Spaces:
Paused
Paused
| import { | |
| ensureAgentEntry, | |
| ensureRecord, | |
| getAgentsList, | |
| getRecord, | |
| isRecord, | |
| type LegacyConfigMigration, | |
| mapLegacyAudioTranscription, | |
| mergeMissing, | |
| } from "./legacy.shared.js"; | |
| export const LEGACY_CONFIG_MIGRATIONS_PART_2: LegacyConfigMigration[] = [ | |
| { | |
| id: "agent.model-config-v2", | |
| describe: | |
| "Migrate legacy agent.model/allowedModels/modelAliases/modelFallbacks/imageModelFallbacks to agent.models + model lists", | |
| apply: (raw, changes) => { | |
| const agentRoot = getRecord(raw.agent); | |
| const defaults = getRecord(getRecord(raw.agents)?.defaults); | |
| const agent = agentRoot ?? defaults; | |
| if (!agent) { | |
| return; | |
| } | |
| const label = agentRoot ? "agent" : "agents.defaults"; | |
| const legacyModel = typeof agent.model === "string" ? String(agent.model) : undefined; | |
| const legacyImageModel = | |
| typeof agent.imageModel === "string" ? String(agent.imageModel) : undefined; | |
| const legacyAllowed = Array.isArray(agent.allowedModels) | |
| ? (agent.allowedModels as unknown[]).map(String) | |
| : []; | |
| const legacyModelFallbacks = Array.isArray(agent.modelFallbacks) | |
| ? (agent.modelFallbacks as unknown[]).map(String) | |
| : []; | |
| const legacyImageModelFallbacks = Array.isArray(agent.imageModelFallbacks) | |
| ? (agent.imageModelFallbacks as unknown[]).map(String) | |
| : []; | |
| const legacyAliases = | |
| agent.modelAliases && typeof agent.modelAliases === "object" | |
| ? (agent.modelAliases as Record<string, unknown>) | |
| : {}; | |
| const hasLegacy = | |
| legacyModel || | |
| legacyImageModel || | |
| legacyAllowed.length > 0 || | |
| legacyModelFallbacks.length > 0 || | |
| legacyImageModelFallbacks.length > 0 || | |
| Object.keys(legacyAliases).length > 0; | |
| if (!hasLegacy) { | |
| return; | |
| } | |
| const models = | |
| agent.models && typeof agent.models === "object" | |
| ? (agent.models as Record<string, unknown>) | |
| : {}; | |
| const ensureModel = (rawKey?: string) => { | |
| if (typeof rawKey !== "string") { | |
| return; | |
| } | |
| const key = rawKey.trim(); | |
| if (!key) { | |
| return; | |
| } | |
| if (!models[key]) { | |
| models[key] = {}; | |
| } | |
| }; | |
| ensureModel(legacyModel); | |
| ensureModel(legacyImageModel); | |
| for (const key of legacyAllowed) { | |
| ensureModel(key); | |
| } | |
| for (const key of legacyModelFallbacks) { | |
| ensureModel(key); | |
| } | |
| for (const key of legacyImageModelFallbacks) { | |
| ensureModel(key); | |
| } | |
| for (const target of Object.values(legacyAliases)) { | |
| if (typeof target !== "string") { | |
| continue; | |
| } | |
| ensureModel(target); | |
| } | |
| for (const [alias, targetRaw] of Object.entries(legacyAliases)) { | |
| if (typeof targetRaw !== "string") { | |
| continue; | |
| } | |
| const target = targetRaw.trim(); | |
| if (!target) { | |
| continue; | |
| } | |
| const entry = | |
| models[target] && typeof models[target] === "object" | |
| ? (models[target] as Record<string, unknown>) | |
| : {}; | |
| if (!("alias" in entry)) { | |
| entry.alias = alias; | |
| models[target] = entry; | |
| } | |
| } | |
| const currentModel = | |
| agent.model && typeof agent.model === "object" | |
| ? (agent.model as Record<string, unknown>) | |
| : null; | |
| if (currentModel) { | |
| if (!currentModel.primary && legacyModel) { | |
| currentModel.primary = legacyModel; | |
| } | |
| if ( | |
| legacyModelFallbacks.length > 0 && | |
| (!Array.isArray(currentModel.fallbacks) || currentModel.fallbacks.length === 0) | |
| ) { | |
| currentModel.fallbacks = legacyModelFallbacks; | |
| } | |
| agent.model = currentModel; | |
| } else if (legacyModel || legacyModelFallbacks.length > 0) { | |
| agent.model = { | |
| primary: legacyModel, | |
| fallbacks: legacyModelFallbacks.length ? legacyModelFallbacks : [], | |
| }; | |
| } | |
| const currentImageModel = | |
| agent.imageModel && typeof agent.imageModel === "object" | |
| ? (agent.imageModel as Record<string, unknown>) | |
| : null; | |
| if (currentImageModel) { | |
| if (!currentImageModel.primary && legacyImageModel) { | |
| currentImageModel.primary = legacyImageModel; | |
| } | |
| if ( | |
| legacyImageModelFallbacks.length > 0 && | |
| (!Array.isArray(currentImageModel.fallbacks) || currentImageModel.fallbacks.length === 0) | |
| ) { | |
| currentImageModel.fallbacks = legacyImageModelFallbacks; | |
| } | |
| agent.imageModel = currentImageModel; | |
| } else if (legacyImageModel || legacyImageModelFallbacks.length > 0) { | |
| agent.imageModel = { | |
| primary: legacyImageModel, | |
| fallbacks: legacyImageModelFallbacks.length ? legacyImageModelFallbacks : [], | |
| }; | |
| } | |
| agent.models = models; | |
| if (legacyModel !== undefined) { | |
| changes.push(`Migrated ${label}.model string β ${label}.model.primary.`); | |
| } | |
| if (legacyModelFallbacks.length > 0) { | |
| changes.push(`Migrated ${label}.modelFallbacks β ${label}.model.fallbacks.`); | |
| } | |
| if (legacyImageModel !== undefined) { | |
| changes.push(`Migrated ${label}.imageModel string β ${label}.imageModel.primary.`); | |
| } | |
| if (legacyImageModelFallbacks.length > 0) { | |
| changes.push(`Migrated ${label}.imageModelFallbacks β ${label}.imageModel.fallbacks.`); | |
| } | |
| if (legacyAllowed.length > 0) { | |
| changes.push(`Migrated ${label}.allowedModels β ${label}.models.`); | |
| } | |
| if (Object.keys(legacyAliases).length > 0) { | |
| changes.push(`Migrated ${label}.modelAliases β ${label}.models.*.alias.`); | |
| } | |
| delete agent.allowedModels; | |
| delete agent.modelAliases; | |
| delete agent.modelFallbacks; | |
| delete agent.imageModelFallbacks; | |
| }, | |
| }, | |
| { | |
| id: "routing.agents-v2", | |
| describe: "Move routing.agents/defaultAgentId to agents.list", | |
| apply: (raw, changes) => { | |
| const routing = getRecord(raw.routing); | |
| if (!routing) { | |
| return; | |
| } | |
| const routingAgents = getRecord(routing.agents); | |
| const agents = ensureRecord(raw, "agents"); | |
| const list = getAgentsList(agents); | |
| if (routingAgents) { | |
| for (const [rawId, entryRaw] of Object.entries(routingAgents)) { | |
| const agentId = String(rawId ?? "").trim(); | |
| const entry = getRecord(entryRaw); | |
| if (!agentId || !entry) { | |
| continue; | |
| } | |
| const target = ensureAgentEntry(list, agentId); | |
| const entryCopy: Record<string, unknown> = { ...entry }; | |
| if ("mentionPatterns" in entryCopy) { | |
| const mentionPatterns = entryCopy.mentionPatterns; | |
| const groupChat = ensureRecord(target, "groupChat"); | |
| if (groupChat.mentionPatterns === undefined) { | |
| groupChat.mentionPatterns = mentionPatterns; | |
| changes.push( | |
| `Moved routing.agents.${agentId}.mentionPatterns β agents.list (id "${agentId}").groupChat.mentionPatterns.`, | |
| ); | |
| } else { | |
| changes.push( | |
| `Removed routing.agents.${agentId}.mentionPatterns (agents.list groupChat mentionPatterns already set).`, | |
| ); | |
| } | |
| delete entryCopy.mentionPatterns; | |
| } | |
| const legacyGroupChat = getRecord(entryCopy.groupChat); | |
| if (legacyGroupChat) { | |
| const groupChat = ensureRecord(target, "groupChat"); | |
| mergeMissing(groupChat, legacyGroupChat); | |
| delete entryCopy.groupChat; | |
| } | |
| const legacySandbox = getRecord(entryCopy.sandbox); | |
| if (legacySandbox) { | |
| const sandboxTools = getRecord(legacySandbox.tools); | |
| if (sandboxTools) { | |
| const tools = ensureRecord(target, "tools"); | |
| const sandbox = ensureRecord(tools, "sandbox"); | |
| const toolPolicy = ensureRecord(sandbox, "tools"); | |
| mergeMissing(toolPolicy, sandboxTools); | |
| delete legacySandbox.tools; | |
| changes.push( | |
| `Moved routing.agents.${agentId}.sandbox.tools β agents.list (id "${agentId}").tools.sandbox.tools.`, | |
| ); | |
| } | |
| entryCopy.sandbox = legacySandbox; | |
| } | |
| mergeMissing(target, entryCopy); | |
| } | |
| delete routing.agents; | |
| changes.push("Moved routing.agents β agents.list."); | |
| } | |
| const defaultAgentId = | |
| typeof routing.defaultAgentId === "string" ? routing.defaultAgentId.trim() : ""; | |
| if (defaultAgentId) { | |
| const hasDefault = list.some( | |
| (entry): entry is Record<string, unknown> => isRecord(entry) && entry.default === true, | |
| ); | |
| if (!hasDefault) { | |
| const entry = ensureAgentEntry(list, defaultAgentId); | |
| entry.default = true; | |
| changes.push( | |
| `Moved routing.defaultAgentId β agents.list (id "${defaultAgentId}").default.`, | |
| ); | |
| } else { | |
| changes.push("Removed routing.defaultAgentId (agents.list default already set)."); | |
| } | |
| delete routing.defaultAgentId; | |
| } | |
| if (list.length > 0) { | |
| agents.list = list; | |
| } | |
| if (Object.keys(routing).length === 0) { | |
| delete raw.routing; | |
| } | |
| }, | |
| }, | |
| { | |
| id: "routing.config-v2", | |
| describe: "Move routing bindings/groupChat/queue/agentToAgent/transcribeAudio", | |
| apply: (raw, changes) => { | |
| const routing = getRecord(raw.routing); | |
| if (!routing) { | |
| return; | |
| } | |
| if (routing.bindings !== undefined) { | |
| if (raw.bindings === undefined) { | |
| raw.bindings = routing.bindings; | |
| changes.push("Moved routing.bindings β bindings."); | |
| } else { | |
| changes.push("Removed routing.bindings (bindings already set)."); | |
| } | |
| delete routing.bindings; | |
| } | |
| if (routing.agentToAgent !== undefined) { | |
| const tools = ensureRecord(raw, "tools"); | |
| if (tools.agentToAgent === undefined) { | |
| tools.agentToAgent = routing.agentToAgent; | |
| changes.push("Moved routing.agentToAgent β tools.agentToAgent."); | |
| } else { | |
| changes.push("Removed routing.agentToAgent (tools.agentToAgent already set)."); | |
| } | |
| delete routing.agentToAgent; | |
| } | |
| if (routing.queue !== undefined) { | |
| const messages = ensureRecord(raw, "messages"); | |
| if (messages.queue === undefined) { | |
| messages.queue = routing.queue; | |
| changes.push("Moved routing.queue β messages.queue."); | |
| } else { | |
| changes.push("Removed routing.queue (messages.queue already set)."); | |
| } | |
| delete routing.queue; | |
| } | |
| const groupChat = getRecord(routing.groupChat); | |
| if (groupChat) { | |
| const historyLimit = groupChat.historyLimit; | |
| if (historyLimit !== undefined) { | |
| const messages = ensureRecord(raw, "messages"); | |
| const messagesGroup = ensureRecord(messages, "groupChat"); | |
| if (messagesGroup.historyLimit === undefined) { | |
| messagesGroup.historyLimit = historyLimit; | |
| changes.push("Moved routing.groupChat.historyLimit β messages.groupChat.historyLimit."); | |
| } else { | |
| changes.push( | |
| "Removed routing.groupChat.historyLimit (messages.groupChat.historyLimit already set).", | |
| ); | |
| } | |
| delete groupChat.historyLimit; | |
| } | |
| const mentionPatterns = groupChat.mentionPatterns; | |
| if (mentionPatterns !== undefined) { | |
| const messages = ensureRecord(raw, "messages"); | |
| const messagesGroup = ensureRecord(messages, "groupChat"); | |
| if (messagesGroup.mentionPatterns === undefined) { | |
| messagesGroup.mentionPatterns = mentionPatterns; | |
| changes.push( | |
| "Moved routing.groupChat.mentionPatterns β messages.groupChat.mentionPatterns.", | |
| ); | |
| } else { | |
| changes.push( | |
| "Removed routing.groupChat.mentionPatterns (messages.groupChat.mentionPatterns already set).", | |
| ); | |
| } | |
| delete groupChat.mentionPatterns; | |
| } | |
| if (Object.keys(groupChat).length === 0) { | |
| delete routing.groupChat; | |
| } else { | |
| routing.groupChat = groupChat; | |
| } | |
| } | |
| if (routing.transcribeAudio !== undefined) { | |
| const mapped = mapLegacyAudioTranscription(routing.transcribeAudio); | |
| if (mapped) { | |
| const tools = ensureRecord(raw, "tools"); | |
| const media = ensureRecord(tools, "media"); | |
| const mediaAudio = ensureRecord(media, "audio"); | |
| const models = Array.isArray(mediaAudio.models) ? (mediaAudio.models as unknown[]) : []; | |
| if (models.length === 0) { | |
| mediaAudio.enabled = true; | |
| mediaAudio.models = [mapped]; | |
| changes.push("Moved routing.transcribeAudio β tools.media.audio.models."); | |
| } else { | |
| changes.push("Removed routing.transcribeAudio (tools.media.audio.models already set)."); | |
| } | |
| } else { | |
| changes.push("Removed routing.transcribeAudio (unsupported transcription CLI)."); | |
| } | |
| delete routing.transcribeAudio; | |
| } | |
| const audio = getRecord(raw.audio); | |
| if (audio?.transcription !== undefined) { | |
| const mapped = mapLegacyAudioTranscription(audio.transcription); | |
| if (mapped) { | |
| const tools = ensureRecord(raw, "tools"); | |
| const media = ensureRecord(tools, "media"); | |
| const mediaAudio = ensureRecord(media, "audio"); | |
| const models = Array.isArray(mediaAudio.models) ? (mediaAudio.models as unknown[]) : []; | |
| if (models.length === 0) { | |
| mediaAudio.enabled = true; | |
| mediaAudio.models = [mapped]; | |
| changes.push("Moved audio.transcription β tools.media.audio.models."); | |
| } else { | |
| changes.push("Removed audio.transcription (tools.media.audio.models already set)."); | |
| } | |
| delete audio.transcription; | |
| if (Object.keys(audio).length === 0) { | |
| delete raw.audio; | |
| } else { | |
| raw.audio = audio; | |
| } | |
| } else { | |
| delete audio.transcription; | |
| changes.push("Removed audio.transcription (unsupported transcription CLI)."); | |
| if (Object.keys(audio).length === 0) { | |
| delete raw.audio; | |
| } else { | |
| raw.audio = audio; | |
| } | |
| } | |
| } | |
| if (Object.keys(routing).length === 0) { | |
| delete raw.routing; | |
| } | |
| }, | |
| }, | |
| ]; | |