


























@@ -420,21 +420,49 @@ function buildOllamaModelsConfig(
420420});
421421}
422422423+function getOllamaLatestDedupeKey(name: string): string {
424+const normalized = normalizeLowercaseStringOrEmpty(name);
425+return normalized.endsWith(":latest") ? normalized.slice(0, -":latest".length) : normalized;
426+}
427+428+function isExplicitLatestOllamaModel(name: string): boolean {
429+return normalizeLowercaseStringOrEmpty(name).endsWith(":latest");
430+}
431+432+function shouldReplaceOllamaModelName(existing: string, candidate: string): boolean {
433+return !isExplicitLatestOllamaModel(existing) && isExplicitLatestOllamaModel(candidate);
434+}
435+423436function mergeUniqueModelNames(...groups: string[][]): string[] {
424-const seen = new Set<string>();
437+const indexByKey = new Map<string, number>();
425438const merged: string[] = [];
426439for (const group of groups) {
427440for (const name of group) {
428-if (seen.has(name)) {
441+const key = getOllamaLatestDedupeKey(name);
442+const existingIndex = indexByKey.get(key);
443+if (existingIndex !== undefined) {
444+if (shouldReplaceOllamaModelName(merged[existingIndex], name)) {
445+merged[existingIndex] = name;
446+}
429447continue;
430448}
431-seen.add(name);
449+indexByKey.set(key, merged.length);
432450merged.push(name);
433451}
434452}
435453return merged;
436454}
437455456+function findAvailableOllamaModelName(modelName: string, availableModelNames: Iterable<string>) {
457+const wantedKey = getOllamaLatestDedupeKey(modelName);
458+for (const available of availableModelNames) {
459+if (getOllamaLatestDedupeKey(available) === wantedKey) {
460+return available;
461+}
462+}
463+return undefined;
464+}
465+438466function applyOllamaProviderConfig(
439467cfg: OpenClawConfig,
440468baseUrl: string,
@@ -632,19 +660,20 @@ export async function configureOllamaNonInteractive(params: {
632660);
633661const discoveredModelsByName = new Map(enrichedModels.map((model) => [model.name, model]));
634662const modelNames = models.map((model) => model.name);
635-const orderedModelNames = [
636- ...OLLAMA_SUGGESTED_MODELS_LOCAL,
637- ...modelNames.filter((name) => !OLLAMA_SUGGESTED_MODELS_LOCAL.includes(name)),
638-];
663+const orderedModelNames = mergeUniqueModelNames(OLLAMA_SUGGESTED_MODELS_LOCAL, modelNames);
639664640665const requestedDefaultModelId = explicitModel ?? OLLAMA_SUGGESTED_MODELS_LOCAL[0];
641666const availableModelNames = new Set(modelNames);
667+const availableDefaultModelId = findAvailableOllamaModelName(
668+requestedDefaultModelId,
669+availableModelNames,
670+);
642671const requestedCloudModel = isOllamaCloudModel(requestedDefaultModelId);
643672let pulledRequestedModel = false;
644673645674if (requestedCloudModel) {
646675availableModelNames.add(requestedDefaultModelId);
647-} else if (!modelNames.includes(requestedDefaultModelId)) {
676+} else if (!availableDefaultModelId) {
648677pulledRequestedModel = await pullOllamaModelNonInteractive(
649678baseUrl,
650679requestedDefaultModelId,
@@ -656,15 +685,15 @@ export async function configureOllamaNonInteractive(params: {
656685}
657686658687let allModelNames = orderedModelNames;
659-let defaultModelId = requestedDefaultModelId;
688+let defaultModelId = availableDefaultModelId ?? requestedDefaultModelId;
660689if (
661690(pulledRequestedModel || requestedCloudModel) &&
662691!allModelNames.includes(requestedDefaultModelId)
663692) {
664693allModelNames = [...allModelNames, requestedDefaultModelId];
665694}
666695667-if (!availableModelNames.has(requestedDefaultModelId)) {
696+if (!findAvailableOllamaModelName(defaultModelId, availableModelNames)) {
668697if (availableModelNames.size === 0) {
669698params.runtime.error(
670699[
@@ -677,7 +706,7 @@ export async function configureOllamaNonInteractive(params: {
677706}
678707679708defaultModelId =
680-allModelNames.find((name) => availableModelNames.has(name)) ??
709+allModelNames.find((name) => findAvailableOllamaModelName(name, availableModelNames)) ??
681710Array.from(availableModelNames)[0];
682711params.runtime.log(
683712`Ollama model ${requestedDefaultModelId} was not available; using ${defaultModelId} instead.`,
@@ -709,7 +738,12 @@ export async function ensureOllamaModelPulled(params: {
709738return;
710739}
711740const { models } = await fetchOllamaModels(baseUrl);
712-if (models.some((model) => model.name === modelName)) {
741+if (
742+findAvailableOllamaModelName(
743+modelName,
744+models.map((model) => model.name),
745+)
746+) {
713747return;
714748}
715749if (!(await pullOllamaModel(baseUrl, modelName, params.prompter))) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。