@vellumai/assistant 0.11.3 → 0.11.4-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +11 -6
- package/docs/architecture/memory.md +11 -0
- package/docs/architecture/turn-actor.md +70 -0
- package/docs/flux-turn-detection-spike.md +243 -0
- package/docs/stt-provider-onboarding.md +3 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +34 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +2 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +11 -0
- package/openapi.yaml +139 -37
- package/package.json +1 -1
- package/scripts/voice-ttft-spike.ts +3 -3
- package/src/__tests__/app-compiler.test.ts +38 -3
- package/src/__tests__/attachments-store.test.ts +21 -12
- package/src/__tests__/byok-default-profile-ensure.test.ts +17 -0
- package/src/__tests__/call-setup-flow-name-capture.test.ts +0 -1
- package/src/__tests__/call-site-routing-provider.test.ts +1 -1
- package/src/__tests__/channel-availability-routes.test.ts +14 -1
- package/src/__tests__/channel-capabilities-dedupe.test.ts +214 -0
- package/src/__tests__/channel-delivery-store.test.ts +14 -14
- package/src/__tests__/config-loader-backfill.test.ts +3 -3
- package/src/__tests__/config-schema.test.ts +25 -10
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +8 -11
- package/src/__tests__/conversation-agent-loop.test.ts +28 -20
- package/src/__tests__/conversation-attention-store.test.ts +63 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -4
- package/src/__tests__/conversation-fork-crud.test.ts +69 -0
- package/src/__tests__/conversation-fork-referential.test.ts +67 -0
- package/src/__tests__/conversation-fork-retrospective.test.ts +24 -0
- package/src/__tests__/conversation-notifiers-provenance.test.ts +59 -0
- package/src/__tests__/conversation-queue.test.ts +177 -4
- package/src/__tests__/conversation-runtime-assembly.test.ts +134 -102
- package/src/__tests__/conversation-runtime-workspace.test.ts +14 -10
- package/src/__tests__/credential-prompt-route.test.ts +7 -10
- package/src/__tests__/custom-profile-ensure.test.ts +5 -1
- package/src/__tests__/discord-access-request-privacy.test.ts +5 -1
- package/src/__tests__/discord-requester-notice-privacy.test.ts +3 -3
- package/src/__tests__/document-append-idempotency.test.ts +233 -0
- package/src/__tests__/edit-propagation.test.ts +0 -7
- package/src/__tests__/helpers/mock-actor-context.ts +49 -0
- package/src/__tests__/helpers/mock-conversation.ts +13 -1
- package/src/__tests__/injector-chain.test.ts +63 -41
- package/src/__tests__/injector-disk-pressure.test.ts +11 -23
- package/src/__tests__/llm-context-resolution.test.ts +73 -1
- package/src/__tests__/llm-schema.test.ts +5 -2
- package/src/__tests__/mcp-list-plugin-servers.test.ts +250 -0
- package/src/__tests__/memory-retrieval-hook.test.ts +6 -5
- package/src/__tests__/messages-read-boundary-guard.test.ts +134 -0
- package/src/__tests__/mtime-cache.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +0 -20
- package/src/__tests__/outbound-slack-persistence.test.ts +40 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +5 -0
- package/src/__tests__/plugin-secret-pattern-contribution.test.ts +1 -1
- package/src/__tests__/post-compaction-reinjection-idempotency.test.ts +14 -7
- package/src/__tests__/provider-commit-message-generator.test.ts +20 -0
- package/src/__tests__/run-conversation-turn-persistence.test.ts +434 -105
- package/src/__tests__/scoped-approval-grants.test.ts +11 -6
- package/src/__tests__/secret-ingress-channel.test.ts +0 -1
- package/src/__tests__/skills.test.ts +32 -0
- package/src/__tests__/slack-edit-ordering-characterization.test.ts +0 -1
- package/src/__tests__/subagent-call-site-routing.test.ts +31 -19
- package/src/__tests__/subagent-spawn-and-await.test.ts +14 -10
- package/src/__tests__/turn-events-store.test.ts +43 -0
- package/src/__tests__/ui-shape-teaching.test.ts +33 -0
- package/src/__tests__/ui-voice-picker-surface.test.ts +128 -0
- package/src/__tests__/user-plugin-loader.test.ts +1 -1
- package/src/__tests__/visible-app-context.test.ts +16 -9
- package/src/__tests__/voice-config-update.test.ts +40 -0
- package/src/__tests__/worker-entrypoint-guards.test.ts +54 -0
- package/src/__tests__/worker-plugin-surface.test.ts +77 -0
- package/src/__tests__/workspace-migration-142-consolidate-voice-front-door.test.ts +158 -0
- package/src/__tests__/workspace-migration-143-repair-deprecated-codex-model-id.test.ts +133 -0
- package/src/__tests__/workspace-migration-144-convert-stranded-subscription-openai-profiles.test.ts +316 -0
- package/src/__tests__/workspace-migration-145-collapse-profile-bindings-to-entries.test.ts +325 -0
- package/src/__tests__/workspace-migration-146-repair-retired-fireworks-deepseek-flash-model-id.test.ts +235 -0
- package/src/acp/__tests__/acp-claude-oauth.test.ts +10 -2
- package/src/acp/__tests__/auth-required.test.ts +161 -0
- package/src/acp/acp-claude-oauth.ts +19 -2
- package/src/acp/agent-process.test.ts +100 -0
- package/src/acp/agent-process.ts +29 -26
- package/src/acp/auth-required.ts +102 -0
- package/src/acp/session-manager.test.ts +119 -0
- package/src/acp/session-manager.ts +68 -2
- package/src/api/events/acp-auth-required.ts +55 -0
- package/src/api/index.ts +7 -0
- package/src/api/surfaces.ts +7 -3
- package/src/apps/app-store.ts +3 -0
- package/src/bundler/package-resolver.ts +2 -30
- package/src/calls/__tests__/voice-session-bridge.test.ts +173 -1
- package/src/calls/__tests__/voice-triage-escalate.test.ts +94 -0
- package/src/calls/call-controller.ts +19 -3
- package/src/calls/call-setup-flow.ts +0 -1
- package/src/calls/media-stream-stt-session.ts +15 -0
- package/src/calls/voice-session-bridge.ts +71 -16
- package/src/calls/voice-triage-escalate.ts +104 -2
- package/src/channels/__tests__/plugin-channel-declarations.test.ts +161 -0
- package/src/channels/config.ts +13 -0
- package/src/channels/plugin-channel-declarations.ts +108 -0
- package/src/channels/types.ts +30 -0
- package/src/cli/AGENTS.md +5 -2
- package/src/cli/commands/credentials.help.ts +2 -2
- package/src/cli/commands/inference-providers.ts +1 -1
- package/src/cli/commands/mcp.help.ts +13 -4
- package/src/cli/commands/mcp.ts +9 -0
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +128 -5
- package/src/cli/commands/memory/index.help.ts +43 -1
- package/src/cli/commands/memory/memory-v3.ts +64 -0
- package/src/cli/commands/stt.help.ts +27 -2
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +39 -0
- package/src/cli/lib/bundled-marketplace.json +13 -0
- package/src/cli/lib/upgrade-plugin.ts +42 -0
- package/src/config/__tests__/default-profile-catalog.test.ts +34 -2
- package/src/config/__tests__/default-provider.test.ts +6 -1
- package/src/config/__tests__/profile-materialization.test.ts +75 -19
- package/src/config/bundled-skills/acp/SKILL.md +6 -7
- package/src/config/bundled-skills/document-editor/SKILL.md +2 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +14 -4
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.test.ts +65 -0
- package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +7 -1
- package/src/config/bundled-skills/settings/tools/shared.ts +16 -0
- package/src/config/bundled-skills/settings/tools/voice-config-update.ts +19 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.test.ts +22 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +9 -2
- package/src/config/call-site-defaults.ts +4 -5
- package/src/config/default-profile-catalog.ts +83 -12
- package/src/config/default-profile-names.ts +4 -1
- package/src/config/default-provider-resolution.ts +4 -0
- package/src/config/llm-context-resolution.ts +11 -3
- package/src/config/llm-resolver.ts +28 -1
- package/src/config/profile-materialization.ts +70 -22
- package/src/config/schemas/__tests__/live-voice.test.ts +107 -4
- package/src/config/schemas/call-site-catalog.ts +4 -4
- package/src/config/schemas/live-voice.ts +57 -23
- package/src/config/schemas/llm.ts +59 -32
- package/src/config/schemas/mcp.ts +23 -0
- package/src/config/schemas/plugin-updates.ts +6 -2
- package/src/config/schemas/stt.ts +1 -0
- package/src/context/outbound-sanitize.ts +96 -1
- package/src/daemon/__tests__/plugin-mcp-reconcile.test.ts +82 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +15 -10
- package/src/daemon/conversation-agent-loop.ts +17 -6
- package/src/daemon/conversation-messaging.ts +5 -1
- package/src/daemon/conversation-notifiers.ts +9 -1
- package/src/daemon/conversation-process.ts +36 -6
- package/src/daemon/conversation-runtime-assembly.ts +3 -4
- package/src/daemon/conversation-surfaces.ts +27 -5
- package/src/daemon/conversation-tool-setup.ts +1 -2
- package/src/daemon/conversation.ts +48 -0
- package/src/daemon/interactive-turn-sender.ts +59 -0
- package/src/daemon/mcp-reload-service.ts +36 -6
- package/src/daemon/process-message.ts +24 -24
- package/src/daemon/providers-setup.ts +6 -3
- package/src/daemon/trust-context-types.ts +29 -0
- package/src/daemon/wake-conversation-ops.ts +3 -2
- package/src/documents/document-store.ts +138 -5
- package/src/hooks/hook-loader.ts +3 -3
- package/src/hooks/registry.ts +50 -6
- package/src/inbound/__tests__/oauth-callback-url.test.ts +83 -0
- package/src/inbound/oauth-callback-url.ts +61 -0
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +1 -104
- package/src/live-voice/__tests__/live-voice-events.test.ts +7 -8
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +932 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +115 -8
- package/src/live-voice/__tests__/live-voice-photo.test.ts +100 -0
- package/src/live-voice/__tests__/live-voice-progress.test.ts +60 -194
- package/src/live-voice/__tests__/live-voice-stt.test.ts +14 -0
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +29 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +0 -483
- package/src/live-voice/__tests__/live-voice-vad.test.ts +0 -16
- package/src/live-voice/__tests__/progress-narration.test.ts +214 -0
- package/src/live-voice/live-voice-archive.ts +2 -0
- package/src/live-voice/live-voice-metrics.ts +57 -32
- package/src/live-voice/live-voice-photo.ts +1 -2
- package/src/live-voice/live-voice-session.ts +535 -314
- package/src/live-voice/progress-narration.ts +277 -0
- package/src/live-voice/protocol.ts +21 -1
- package/src/mcp/__tests__/effective-config.test.ts +238 -0
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +200 -0
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +9 -9
- package/src/mcp/__tests__/plugin-server-credential-isolation.test.ts +95 -0
- package/src/mcp/client.ts +16 -11
- package/src/mcp/effective-config.ts +113 -0
- package/src/mcp/manager.ts +11 -6
- package/src/mcp/mcp-auth-orchestrator.ts +13 -22
- package/src/mcp/mcp-oauth-provider.ts +205 -240
- package/src/monitoring/__tests__/plugin-auto-update.test.ts +166 -3
- package/src/monitoring/plugin-auto-update.ts +128 -24
- package/src/notifications/signal.ts +1 -0
- package/src/permissions/confirmation-guardian-request.test.ts +15 -11
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/question-guardian-request.test.ts +14 -6
- package/src/permissions/question-guardian-request.ts +1 -2
- package/src/persistence/attachments-store.ts +8 -1
- package/src/persistence/bookmark-crud.ts +3 -7
- package/src/persistence/conversation-attention-store.ts +16 -45
- package/src/persistence/conversation-crud.ts +33 -4
- package/src/persistence/conversation-lineage.ts +9 -0
- package/src/persistence/conversation-queries.ts +108 -41
- package/src/persistence/delivery-crud.ts +38 -29
- package/src/persistence/external-conversation-store.ts +32 -4
- package/src/persistence/llm-request-log-store.ts +4 -10
- package/src/persistence/llm-usage-store.ts +8 -3
- package/src/persistence/message-reads.test.ts +197 -0
- package/src/persistence/message-reads.ts +211 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.test.ts +120 -0
- package/src/persistence/migrations/366-chatgpt-subscription-row-identity.ts +62 -0
- package/src/persistence/real-user-turn-filter.ts +27 -3
- package/src/persistence/steps.ts +9 -0
- package/src/plugin-api/__tests__/oauth-callback-url-export.test.ts +29 -0
- package/src/plugin-api/conversation-turn.ts +168 -5
- package/src/plugin-api/index.ts +21 -5
- package/src/plugin-api/vision-support.test.ts +1 -1
- package/src/plugins/__tests__/mcp-servers.test.ts +371 -0
- package/src/plugins/defaults/memory/AGENTS.md +4 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +204 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-accounting.test.ts +72 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +4 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-provider-path.test.ts +4 -1
- package/src/plugins/defaults/memory/buffer-format.ts +165 -0
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +6 -0
- package/src/plugins/defaults/memory/graph/image-ref-utils.ts +3 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +1 -30
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.test.ts +34 -0
- package/src/plugins/defaults/memory/graph-topology/pending-buffer.ts +8 -12
- package/src/plugins/defaults/memory/hooks/post-compact.ts +1 -4
- package/src/plugins/defaults/memory/indexer.ts +3 -1
- package/src/plugins/defaults/memory/memory-retrospective-accounting.ts +19 -7
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +281 -0
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +207 -0
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +33 -0
- package/src/plugins/defaults/memory/substrate/__tests__/static-context.test.ts +199 -2
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +25 -18
- package/src/plugins/defaults/memory/substrate/skill-content.ts +8 -1
- package/src/plugins/defaults/memory/substrate/static-context.ts +160 -4
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +2 -4
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +3 -1
- package/src/plugins/defaults/memory/v3/prune.ts +2 -0
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +2 -0
- package/src/plugins/defaults/memory/worker.ts +6 -3
- package/src/plugins/external-plugin-loader.ts +47 -0
- package/src/plugins/mcp-servers.ts +361 -0
- package/src/plugins/mtime-cache.ts +23 -49
- package/src/plugins/worker-plugin-surface.ts +33 -0
- package/src/providers/__tests__/connection-model-compat.test.ts +1 -1
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +214 -2
- package/src/providers/__tests__/preflight-resolved-config.test.ts +57 -0
- package/src/providers/__tests__/retry-callsite.test.ts +5 -2
- package/src/providers/call-site-routing.ts +30 -3
- package/src/providers/connection-resolution.ts +194 -11
- package/src/providers/inference/auth.ts +6 -0
- package/src/providers/inference/connection-availability.ts +24 -2
- package/src/providers/inference/connections.ts +2 -0
- package/src/providers/model-catalog.ts +3 -3
- package/src/providers/model-intents.ts +28 -8
- package/src/providers/openai/chat-completions-provider.ts +5 -6
- package/src/providers/openai/codex-models.ts +2 -1
- package/src/providers/provider-send-message.ts +32 -3
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +433 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +620 -0
- package/src/providers/speech-to-text/__tests__/provider-catalog.test.ts +34 -0
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +285 -6
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +395 -0
- package/src/providers/speech-to-text/deepgram-flux-realtime.ts +719 -0
- package/src/providers/speech-to-text/provider-catalog.ts +99 -8
- package/src/providers/speech-to-text/resolve.ts +25 -2
- package/src/routes/worker.ts +17 -5
- package/src/runtime/access-request-helper.ts +9 -12
- package/src/runtime/agent-wake.ts +3 -3
- package/src/runtime/pre-first-message-gate.ts +4 -0
- package/src/runtime/routes/__tests__/acp-claude-auth-routes.test.ts +12 -4
- package/src/runtime/routes/__tests__/conversation-list-routes.test.ts +219 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +52 -0
- package/src/runtime/routes/__tests__/default-provider-routes.test.ts +61 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +102 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +44 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +25 -0
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +62 -1
- package/src/runtime/routes/channel-availability-routes.ts +32 -14
- package/src/runtime/routes/channel-route-shared.ts +0 -6
- package/src/runtime/routes/chatgpt-subscription-auth-routes.ts +6 -6
- package/src/runtime/routes/conversation-list-routes.ts +112 -1
- package/src/runtime/routes/conversation-query-routes.ts +40 -27
- package/src/runtime/routes/credential-prompt-routes.ts +4 -7
- package/src/runtime/routes/default-provider-routes.ts +15 -0
- package/src/runtime/routes/inbound-message-handler.ts +17 -41
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -9
- package/src/runtime/routes/inbound-stages/admission-policy.ts +1 -17
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +2 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +1 -3
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -4
- package/src/runtime/routes/inbound-stages/reaction-intercept.test.ts +0 -1
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +11 -20
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +2 -3
- package/src/runtime/routes/inference-profiles-routes.ts +20 -11
- package/src/runtime/routes/inference-provider-connection-routes.ts +77 -15
- package/src/runtime/routes/log-export-routes.ts +3 -0
- package/src/runtime/routes/mcp-auth-routes.ts +148 -57
- package/src/runtime/routes/plugins-routes.ts +21 -3
- package/src/runtime/routes/stt-routes.ts +31 -25
- package/src/runtime/routes/surface-conversation-resolver.ts +3 -0
- package/src/runtime/routes/user-route-dispatcher.ts +39 -14
- package/src/runtime/routes/user-route-import.ts +108 -0
- package/src/schedule/worker.ts +6 -0
- package/src/security/oauth2.ts +6 -22
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +22 -0
- package/src/stt/__tests__/types.test.ts +94 -0
- package/src/stt/daemon-batch-transcriber.ts +10 -0
- package/src/stt/stt-stream-session.ts +8 -4
- package/src/stt/types.ts +103 -0
- package/src/subagent/manager.ts +1 -3
- package/src/subagent/types.ts +7 -6
- package/src/tools/acp/spawn.test.ts +97 -0
- package/src/tools/acp/spawn.ts +32 -0
- package/src/tools/document/document-tool.ts +12 -3
- package/src/tools/registry.ts +2 -1
- package/src/tools/ui-surface/surface-shape-docs.ts +11 -0
- package/src/tools/workflows/run-workflow.ts +1 -2
- package/src/tts/__tests__/reasoning-tag-filter.test.ts +78 -0
- package/src/tts/reasoning-tag-filter.ts +89 -0
- package/src/util/think-tag-stream.ts +95 -0
- package/src/workspace/byok-default-profile-ensure.ts +76 -24
- package/src/workspace/custom-profile-ensure.ts +4 -24
- package/src/workspace/migrations/142-consolidate-voice-front-door.ts +70 -0
- package/src/workspace/migrations/143-repair-deprecated-codex-model-id.ts +134 -0
- package/src/workspace/migrations/144-convert-stranded-subscription-openai-profiles.ts +265 -0
- package/src/workspace/migrations/145-collapse-profile-bindings-to-entries.ts +328 -0
- package/src/workspace/migrations/146-repair-retired-fireworks-deepseek-flash-model-id.ts +195 -0
- package/src/workspace/migrations/__tests__/141-stt-english-default-to-multilingual.test.ts +0 -10
- package/src/workspace/migrations/registry.ts +10 -0
- package/src/workspace/provider-commit-message-generator.ts +7 -5
- package/src/live-voice/__tests__/front-decision.test.ts +0 -645
- package/src/live-voice/front-decision.ts +0 -476
|
@@ -18,6 +18,7 @@ import {
|
|
|
18
18
|
type LLMProvider,
|
|
19
19
|
type ProfileEntry,
|
|
20
20
|
} from "../config/schemas/llm.js";
|
|
21
|
+
import { ROUTING_IDENTITY_PROVIDERS } from "../providers/inference/auth.js";
|
|
21
22
|
import { getLogger } from "../util/logger.js";
|
|
22
23
|
import { completedProfileBody } from "./custom-profile-ensure.js";
|
|
23
24
|
|
|
@@ -135,10 +136,26 @@ const ERA_COPY_LABEL_SUFFIX = " (Custom Provider)";
|
|
|
135
136
|
/**
|
|
136
137
|
* Comparison ignores `label` and `status` (user overlay state, preserved via
|
|
137
138
|
* `userOverlayState`) and `model` (checked separately against the current
|
|
138
|
-
* intent resolution and `HISTORICAL_INTENT_MODELS`).
|
|
139
|
+
* intent resolution and `HISTORICAL_INTENT_MODELS`). The CONVENTIONAL
|
|
140
|
+
* `<vendor>-personal` binding is normalized away before comparison (it was
|
|
141
|
+
* machinery-written across several eras); a non-conventional binding is a
|
|
142
|
+
* user selection and keeps blocking conversion.
|
|
139
143
|
*/
|
|
140
144
|
const IGNORED_COMPARISON_KEYS = new Set(["label", "status", "model"]);
|
|
141
145
|
|
|
146
|
+
/**
|
|
147
|
+
* Fold the conventional personal entry name back to its vendor. The entries
|
|
148
|
+
* collapse (migration 145) rewrites a hatch copy's binding into its
|
|
149
|
+
* provider as `<vendor>-personal`; the matcher folds that shape so every
|
|
150
|
+
* era of stored copy keeps converting (the same discipline as
|
|
151
|
+
* `HISTORICAL_INTENT_MODELS`).
|
|
152
|
+
*/
|
|
153
|
+
function foldPersonalEntryName(provider: string): string {
|
|
154
|
+
return provider.endsWith("-personal")
|
|
155
|
+
? provider.slice(0, -"-personal".length)
|
|
156
|
+
: provider;
|
|
157
|
+
}
|
|
158
|
+
|
|
142
159
|
/**
|
|
143
160
|
* Per-provider model ids that earlier intent eras pinned onto `custom-*`
|
|
144
161
|
* copies, verified against `providers/model-intents.ts` git history. Hatch
|
|
@@ -146,9 +163,10 @@ const IGNORED_COMPARISON_KEYS = new Set(["label", "status", "model"]);
|
|
|
146
163
|
* 2026-05-05, #29755), and the profile-model migrations (100, 103, 109, 113,
|
|
147
164
|
* 123) deliberately rewrite only the managed default entries (`custom-*` is
|
|
148
165
|
* the user's to manage), so an untouched copy still carries whichever value
|
|
149
|
-
* its hatch-era intent resolved to.
|
|
150
|
-
*
|
|
151
|
-
* place
|
|
166
|
+
* its hatch-era intent resolved to. Migrations 136 and 146 are the
|
|
167
|
+
* exceptions: they rewrite stale Fireworks pins (`custom-*` included) in
|
|
168
|
+
* place, so their targets are machinery-authored values too. A model listed
|
|
169
|
+
* here counts as unedited only when every non-model
|
|
152
170
|
* field still matches the template.
|
|
153
171
|
*/
|
|
154
172
|
const HISTORICAL_INTENT_MODELS: Record<
|
|
@@ -156,6 +174,10 @@ const HISTORICAL_INTENT_MODELS: Record<
|
|
|
156
174
|
Partial<Record<string, readonly string[]>>
|
|
157
175
|
> = {
|
|
158
176
|
balanced: {
|
|
177
|
+
openai: [
|
|
178
|
+
// balanced intent 2026-05-05 (#29755) to the 2026-08-10 gpt-5.6 repoint.
|
|
179
|
+
"gpt-5.4-mini",
|
|
180
|
+
],
|
|
159
181
|
fireworks: [
|
|
160
182
|
// balanced intent 2026-05-05 (#29755) to 2026-05-19 (#31068).
|
|
161
183
|
"accounts/fireworks/models/kimi-k2p5",
|
|
@@ -163,9 +185,15 @@ const HISTORICAL_INTENT_MODELS: Record<
|
|
|
163
185
|
"accounts/fireworks/models/kimi-k2p6",
|
|
164
186
|
// migration 136's in-place rewrite of a kimi-k2p5 pin.
|
|
165
187
|
"accounts/fireworks/models/deepseek-v4-flash",
|
|
188
|
+
// the ID migration 146 writes over stale deepseek-v4-flash pins.
|
|
189
|
+
"accounts/fireworks/models/deepseek-v4-flash-0731",
|
|
166
190
|
],
|
|
167
191
|
},
|
|
168
192
|
"quality-optimized": {
|
|
193
|
+
openai: [
|
|
194
|
+
// quality intent 2026-05-05 (#29755) to the 2026-08-10 gpt-5.6 repoint.
|
|
195
|
+
"gpt-5.4",
|
|
196
|
+
],
|
|
169
197
|
anthropic: [
|
|
170
198
|
// quality intent 2026-05-05 (#29755) to 2026-06-11 (#34498).
|
|
171
199
|
"claude-opus-4-7",
|
|
@@ -183,6 +211,8 @@ const HISTORICAL_INTENT_MODELS: Record<
|
|
|
183
211
|
"accounts/fireworks/models/kimi-k2p5",
|
|
184
212
|
// migration 136's in-place rewrite of a kimi-k2p5 pin.
|
|
185
213
|
"accounts/fireworks/models/deepseek-v4-flash",
|
|
214
|
+
// the ID migration 146 writes over stale deepseek-v4-flash pins.
|
|
215
|
+
"accounts/fireworks/models/deepseek-v4-flash-0731",
|
|
186
216
|
],
|
|
187
217
|
},
|
|
188
218
|
"cost-optimized": {
|
|
@@ -196,10 +226,14 @@ const HISTORICAL_INTENT_MODELS: Record<
|
|
|
196
226
|
],
|
|
197
227
|
fireworks: [
|
|
198
228
|
// latency intent 2026-05-05 (#29755) to 2026-07-28 (#39446). On live
|
|
199
|
-
// configs migration 136
|
|
200
|
-
//
|
|
201
|
-
// backups.
|
|
229
|
+
// configs migration 136 rewrites it to deepseek-v4-flash, so this
|
|
230
|
+
// survives only in configs restored from pre-136 backups.
|
|
202
231
|
"accounts/fireworks/models/kimi-k2p5",
|
|
232
|
+
// latency intent 2026-07-28 (#39446) to the 2026-08-17 dated-ID
|
|
233
|
+
// repoint; also the ID migration 136 writes. On live configs migration
|
|
234
|
+
// 146 rewrites it to the dated ID, so this survives only in pre-146
|
|
235
|
+
// backups.
|
|
236
|
+
"accounts/fireworks/models/deepseek-v4-flash",
|
|
203
237
|
],
|
|
204
238
|
},
|
|
205
239
|
};
|
|
@@ -259,11 +293,13 @@ export function ensureByokDefaultProfiles(workspaceDir: string): void {
|
|
|
259
293
|
const completionBase = LLMConfigBase.safeParse(llm.default ?? {}).data;
|
|
260
294
|
|
|
261
295
|
// The default provider on a BYOK default, or the uniform hatch provider
|
|
262
|
-
// across the complete copy set on a
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
296
|
+
// across the complete copy set on a routing-identity default (vellum,
|
|
297
|
+
// chatgpt); null converts nothing.
|
|
298
|
+
const candidateProvider = ROUTING_IDENTITY_PROVIDERS.has(
|
|
299
|
+
parsedDefault.data.provider,
|
|
300
|
+
)
|
|
301
|
+
? uniformCopyProvider(profiles)
|
|
302
|
+
: parsedDefault.data.provider;
|
|
267
303
|
const convertibleProvider =
|
|
268
304
|
candidateProvider !== null && isByokDefaultProviderChoice(candidateProvider)
|
|
269
305
|
? candidateProvider
|
|
@@ -339,7 +375,11 @@ function isKnownUneditedBody(
|
|
|
339
375
|
// (hatch materialized it once; the default provider may have changed
|
|
340
376
|
// since); equality with the corroborated provider rules out a user
|
|
341
377
|
// re-provision.
|
|
342
|
-
if (
|
|
378
|
+
if (
|
|
379
|
+
convertibleProvider === null ||
|
|
380
|
+
typeof entry.provider !== "string" ||
|
|
381
|
+
foldPersonalEntryName(entry.provider) !== convertibleProvider
|
|
382
|
+
) {
|
|
343
383
|
return false;
|
|
344
384
|
}
|
|
345
385
|
const copyProvider = convertibleProvider;
|
|
@@ -347,11 +387,13 @@ function isKnownUneditedBody(
|
|
|
347
387
|
if (template === undefined) {
|
|
348
388
|
return false;
|
|
349
389
|
}
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
390
|
+
// No connection binding: the bare provider means the default entry of
|
|
391
|
+
// that kind, and a stamped binding would re-introduce the collapsed
|
|
392
|
+
// field on disk.
|
|
393
|
+
const materialized = materializeProfile(template, copyProvider) as Record<
|
|
394
|
+
string,
|
|
395
|
+
unknown
|
|
396
|
+
>;
|
|
355
397
|
if (
|
|
356
398
|
entry.model !== materialized.model &&
|
|
357
399
|
!(HISTORICAL_INTENT_MODELS[key][copyProvider] ?? []).includes(entry.model)
|
|
@@ -361,11 +403,20 @@ function isKnownUneditedBody(
|
|
|
361
403
|
// Completion skips managed-source bodies, so a copy from the era whose
|
|
362
404
|
// templates wrote `source: "managed"` (#29755 to #29768, 2026-05-05) is
|
|
363
405
|
// compared as if user-source to keep both sides normalized identically.
|
|
406
|
+
const normalizedEntry: Record<string, unknown> = {
|
|
407
|
+
...entry,
|
|
408
|
+
provider: copyProvider,
|
|
409
|
+
...(entry.source === "managed" ? { source: "user" } : {}),
|
|
410
|
+
};
|
|
411
|
+
// The conventional personal binding is machinery-written (hatch stamps,
|
|
412
|
+
// completion re-stamps); normalize it away. Any other binding is user
|
|
413
|
+
// state and stays in the comparison, where the unbound template side
|
|
414
|
+
// makes it block conversion.
|
|
415
|
+
if (normalizedEntry.provider_connection === `${copyProvider}-personal`) {
|
|
416
|
+
delete normalizedEntry.provider_connection;
|
|
417
|
+
}
|
|
364
418
|
const body = comparableBody(
|
|
365
|
-
withCompletionBaked(
|
|
366
|
-
entry.source === "managed" ? { ...entry, source: "user" } : entry,
|
|
367
|
-
completionBase,
|
|
368
|
-
),
|
|
419
|
+
withCompletionBaked(normalizedEntry, completionBase),
|
|
369
420
|
);
|
|
370
421
|
const known = comparableBody(
|
|
371
422
|
withCompletionBaked(materialized, completionBase),
|
|
@@ -392,9 +443,10 @@ function uniformCopyProvider(profiles: Record<string, unknown>): string | null {
|
|
|
392
443
|
if (typeof entry.provider !== "string") {
|
|
393
444
|
return null;
|
|
394
445
|
}
|
|
446
|
+
const entryProvider = foldPersonalEntryName(entry.provider);
|
|
395
447
|
if (provider === null) {
|
|
396
|
-
provider =
|
|
397
|
-
} else if (provider !==
|
|
448
|
+
provider = entryProvider;
|
|
449
|
+
} else if (provider !== entryProvider) {
|
|
398
450
|
return null;
|
|
399
451
|
}
|
|
400
452
|
}
|
|
@@ -3,7 +3,10 @@ import { join } from "node:path";
|
|
|
3
3
|
import { isDeepStrictEqual } from "node:util";
|
|
4
4
|
|
|
5
5
|
import { invalidateConfigCache } from "../config/loader.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
completeCustomProfile,
|
|
8
|
+
mergePreservingUnknownKeys,
|
|
9
|
+
} from "../config/profile-materialization.js";
|
|
7
10
|
import { LLMConfigBase, ProfileEntry } from "../config/schemas/llm.js";
|
|
8
11
|
import { getLogger } from "../util/logger.js";
|
|
9
12
|
|
|
@@ -113,29 +116,6 @@ export function completedProfileBody(
|
|
|
113
116
|
);
|
|
114
117
|
}
|
|
115
118
|
|
|
116
|
-
/**
|
|
117
|
-
* `{...raw, ...completed}` recursively: completed (schema-known) values win,
|
|
118
|
-
* raw keys the schema stripped survive at every depth. (Duplicated in the
|
|
119
|
-
* write-path normalization in conversation-query-routes.ts — the two land in
|
|
120
|
-
* independent PRs; consolidate when either next changes.)
|
|
121
|
-
*/
|
|
122
|
-
function mergePreservingUnknownKeys(
|
|
123
|
-
raw: Record<string, unknown>,
|
|
124
|
-
completed: Record<string, unknown>,
|
|
125
|
-
): Record<string, unknown> {
|
|
126
|
-
const out: Record<string, unknown> = { ...raw, ...completed };
|
|
127
|
-
for (const [key, value] of Object.entries(completed)) {
|
|
128
|
-
const rawValue = raw[key];
|
|
129
|
-
if (readObject(value) !== null && readObject(rawValue) !== null) {
|
|
130
|
-
out[key] = mergePreservingUnknownKeys(
|
|
131
|
-
rawValue as Record<string, unknown>,
|
|
132
|
-
value as Record<string, unknown>,
|
|
133
|
-
);
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
return out;
|
|
137
|
-
}
|
|
138
|
-
|
|
139
119
|
function readObject(value: unknown): Record<string, unknown> | null {
|
|
140
120
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
141
121
|
return null;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
const OLD_CALLSITE = "voiceFrontDecision";
|
|
7
|
+
const PROGRESS_CALLSITE = "voiceProgressNarration";
|
|
8
|
+
const RETIRED_ACK_KEYS = [
|
|
9
|
+
"ackFirstDeltaTimeoutMs",
|
|
10
|
+
"ackGenerationTimeoutMs",
|
|
11
|
+
] as const;
|
|
12
|
+
|
|
13
|
+
export const consolidateVoiceFrontDoorMigration: WorkspaceMigration = {
|
|
14
|
+
id: "142-consolidate-voice-front-door",
|
|
15
|
+
description:
|
|
16
|
+
"Rename the progress narration callsite and remove retired generated-ack tuning",
|
|
17
|
+
run(workspaceDir: string): void {
|
|
18
|
+
const configPath = join(workspaceDir, "config.json");
|
|
19
|
+
if (!existsSync(configPath)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
let config: Record<string, unknown>;
|
|
24
|
+
try {
|
|
25
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
26
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
config = raw as Record<string, unknown>;
|
|
30
|
+
} catch {
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
let changed = false;
|
|
35
|
+
const llm = readObject(config.llm);
|
|
36
|
+
const callSites = readObject(llm?.callSites);
|
|
37
|
+
if (callSites && Object.hasOwn(callSites, OLD_CALLSITE)) {
|
|
38
|
+
if (!Object.hasOwn(callSites, PROGRESS_CALLSITE)) {
|
|
39
|
+
callSites[PROGRESS_CALLSITE] = callSites[OLD_CALLSITE];
|
|
40
|
+
}
|
|
41
|
+
delete callSites[OLD_CALLSITE];
|
|
42
|
+
changed = true;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const liveVoice = readObject(config.liveVoice);
|
|
46
|
+
const frontModel = readObject(liveVoice?.frontModel);
|
|
47
|
+
if (frontModel) {
|
|
48
|
+
for (const key of RETIRED_ACK_KEYS) {
|
|
49
|
+
if (Object.hasOwn(frontModel, key)) {
|
|
50
|
+
delete frontModel[key];
|
|
51
|
+
changed = true;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
if (changed) {
|
|
57
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
down(_workspaceDir: string): void {
|
|
61
|
+
// Forward-only.
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
66
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
67
|
+
return null;
|
|
68
|
+
}
|
|
69
|
+
return value as Record<string, unknown>;
|
|
70
|
+
}
|
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Repair the deprecated `gpt-5.3-codex` model ID on ChatGPT-subscription
|
|
8
|
+
* config fragments.
|
|
9
|
+
*
|
|
10
|
+
* OpenAI deprecated `gpt-5.3-codex` under ChatGPT sign-in (the Codex
|
|
11
|
+
* endpoint rejects it with HTTP 400), so it is being removed from
|
|
12
|
+
* `CODEX_SUBSCRIPTION_MODEL_IDS`. A workspace can still pin it on
|
|
13
|
+
* `provider: "chatgpt"` fragments (migration 133 wrote exactly that shape
|
|
14
|
+
* for `chatgpt-subscription` entries), and once the ID leaves the allowlist,
|
|
15
|
+
* `LLMSchema.superRefine` rejects such a fragment. The loader's leaf
|
|
16
|
+
* recovery then deletes the fragment's `model`, which still fails ("chatgpt"
|
|
17
|
+
* requires an explicit model), and per-section salvage resets the whole
|
|
18
|
+
* `llm` section, discarding the user's other LLM settings.
|
|
19
|
+
*
|
|
20
|
+
* Repair rewrites the model to `gpt-5.6-terra` (OpenAI's recommended
|
|
21
|
+
* everyday Codex model) on an exact `provider: "chatgpt"` + model match in
|
|
22
|
+
* `llm.default`, `llm.callSites.*`, and `llm.profiles.*`. A call-site
|
|
23
|
+
* fragment is also repaired when it pins the model with no provider of its
|
|
24
|
+
* own: at resolve time such a fragment overlays the winning profile, so the
|
|
25
|
+
* stale pin rides whatever provider and connection the winner supplies
|
|
26
|
+
* (including the subscription connection, which routes it to the Codex
|
|
27
|
+
* endpoint). Fragments with any other explicit provider are left untouched:
|
|
28
|
+
* the allowlist only gates the "chatgpt" routing identity, and a provider
|
|
29
|
+
* like `openai-compatible` may legitimately serve this id.
|
|
30
|
+
*/
|
|
31
|
+
export const repairDeprecatedCodexModelIdMigration: WorkspaceMigration = {
|
|
32
|
+
id: "143-repair-deprecated-codex-model-id",
|
|
33
|
+
description:
|
|
34
|
+
'Repair deprecated gpt-5.3-codex model ID on provider "chatgpt" fragments in workspace LLM config',
|
|
35
|
+
run(workspaceDir: string): void {
|
|
36
|
+
const configPath = join(workspaceDir, "config.json");
|
|
37
|
+
if (!existsSync(configPath)) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
// Read outside the parse catch: a transient filesystem error (EIO,
|
|
42
|
+
// EACCES) must reach the runner so the migration retries, while
|
|
43
|
+
// malformed JSON is a permanent state this migration cannot repair.
|
|
44
|
+
const rawText = readFileSync(configPath, "utf-8");
|
|
45
|
+
|
|
46
|
+
let config: Record<string, unknown>;
|
|
47
|
+
try {
|
|
48
|
+
const raw = JSON.parse(rawText);
|
|
49
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
config = raw as Record<string, unknown>;
|
|
53
|
+
} catch {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
const llm = readObject(config.llm);
|
|
58
|
+
if (llm === null) {
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
let changed = false;
|
|
63
|
+
|
|
64
|
+
changed = repairFragment(readObject(llm.default)) || changed;
|
|
65
|
+
|
|
66
|
+
const callSites = readObject(llm.callSites);
|
|
67
|
+
if (callSites !== null) {
|
|
68
|
+
for (const rawConfig of Object.values(callSites)) {
|
|
69
|
+
changed =
|
|
70
|
+
repairFragment(readObject(rawConfig), {
|
|
71
|
+
repairMissingProvider: true,
|
|
72
|
+
}) || changed;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const profiles = readObject(llm.profiles);
|
|
77
|
+
if (profiles !== null) {
|
|
78
|
+
for (const rawProfile of Object.values(profiles)) {
|
|
79
|
+
changed = repairFragment(readObject(rawProfile)) || changed;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
if (!changed) {
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
// Write-then-rename so an interrupted write cannot leave config.json
|
|
88
|
+
// truncated: a torn in-place write would parse as invalid JSON on the
|
|
89
|
+
// retry, which the catch above treats as "nothing to do", letting the
|
|
90
|
+
// runner checkpoint the migration as completed against a corrupt file.
|
|
91
|
+
const tmpPath = `${configPath}.migration-143.tmp`;
|
|
92
|
+
writeFileSync(tmpPath, JSON.stringify(config, null, 2) + "\n");
|
|
93
|
+
renameSync(tmpPath, configPath);
|
|
94
|
+
},
|
|
95
|
+
// The exact-match rewrite is idempotent, so a transient failure (full
|
|
96
|
+
// disk, I/O error) is safe to retry on later startups.
|
|
97
|
+
retryFailedCheckpoint: true,
|
|
98
|
+
down(_workspaceDir: string): void {
|
|
99
|
+
// Forward-only: reintroducing the deprecated model ID would fail schema
|
|
100
|
+
// validation once the allowlist no longer carries it.
|
|
101
|
+
},
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
// ---------------------------------------------------------------------------
|
|
105
|
+
// Helpers: self-contained per workspace migrations AGENTS.md
|
|
106
|
+
// ---------------------------------------------------------------------------
|
|
107
|
+
|
|
108
|
+
const DEPRECATED_MODEL_ID = "gpt-5.3-codex";
|
|
109
|
+
const REPLACEMENT_MODEL_ID = "gpt-5.6-terra";
|
|
110
|
+
|
|
111
|
+
function repairFragment(
|
|
112
|
+
fragment: Record<string, unknown> | null,
|
|
113
|
+
options?: { repairMissingProvider?: boolean },
|
|
114
|
+
): boolean {
|
|
115
|
+
if (fragment === null || fragment.model !== DEPRECATED_MODEL_ID) {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
const providerRepairable =
|
|
119
|
+
fragment.provider === "chatgpt" ||
|
|
120
|
+
(options?.repairMissingProvider === true &&
|
|
121
|
+
fragment.provider === undefined);
|
|
122
|
+
if (!providerRepairable) {
|
|
123
|
+
return false;
|
|
124
|
+
}
|
|
125
|
+
fragment.model = REPLACEMENT_MODEL_ID;
|
|
126
|
+
return true;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
130
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
131
|
+
return null;
|
|
132
|
+
}
|
|
133
|
+
return value as Record<string, unknown>;
|
|
134
|
+
}
|