@mycadet/assistant 0.12.9 → 0.12.11
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/Dockerfile +0 -8
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +1 -1
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/ces-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/ces-client/src/http-credentials.ts +18 -1
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/gateway-client/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/node_modules/@mycadet/service-contracts/src/__tests__/ingress.test.ts +8 -8
- package/node_modules/@mycadet/service-contracts/src/ingress.ts +1 -1
- package/openapi.yaml +62 -910
- package/package.json +3 -7
- package/scripts/build-test-fixtures.ts +1 -1
- package/scripts/generate-openapi.ts +22 -6
- package/scripts/postinstall.ts +4 -10
- package/scripts/run-tests.ts +0 -21
- package/src/__tests__/adaptive-thinking-repair.test.ts +19 -57
- package/src/__tests__/agent-loop.test.ts +0 -76
- package/src/__tests__/anthropic-provider.test.ts +6 -6
- package/src/__tests__/assert-not-live-db.ts +1 -1
- package/src/__tests__/assistant-id-boundary-guard.test.ts +3 -3
- package/src/__tests__/attachments-store-heic-normalize.test.ts +1 -1
- package/src/__tests__/attachments-store.test.ts +1 -1
- package/src/__tests__/audit-log-rotation.test.ts +1 -1
- package/src/__tests__/btw-routes.test.ts +1 -1
- package/src/__tests__/byok-default-profile-ensure.test.ts +21 -27
- package/src/__tests__/call-conversation-messages.test.ts +0 -5
- package/src/__tests__/call-recovery.test.ts +2 -7
- package/src/__tests__/call-routes-http.test.ts +0 -12
- package/src/__tests__/call-store.test.ts +2 -7
- package/src/__tests__/catalog-files.test.ts +7 -5
- package/src/__tests__/checker.test.ts +1 -1
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +4 -4
- package/src/__tests__/cloud-client-verify-credential.test.ts +0 -4
- package/src/__tests__/cloud-credential-catalog-cli.test.ts +14 -14
- package/src/__tests__/cloud-profile-guard.test.ts +87 -404
- package/src/__tests__/compaction-events.test.ts +2 -2
- package/src/__tests__/config-loader-backfill.test.ts +74 -163
- package/src/__tests__/config-loader-cloud-defaults.test.ts +11 -11
- package/src/__tests__/config-loader-corrupt.test.ts +10 -10
- package/src/__tests__/config-loader-quarantine-notice.test.ts +7 -7
- package/src/__tests__/config-loader-validation-reset-notice.test.ts +11 -11
- package/src/__tests__/config-schema.test.ts +26 -27
- package/src/__tests__/config-set-route.test.ts +2 -6
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +28 -300
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +39 -246
- package/src/__tests__/conversation-agent-loop.test.ts +2 -58
- package/src/__tests__/conversation-clear-safety.test.ts +0 -30
- package/src/__tests__/conversation-inference-profile-route.test.ts +1 -1
- package/src/__tests__/conversation-queue.test.ts +1 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +1 -1
- package/src/__tests__/conversation-skill-tools.test.ts +4 -444
- package/src/__tests__/conversation-slash-commands.test.ts +1 -1
- package/src/__tests__/conversation-store.test.ts +1 -84
- package/src/__tests__/conversation-surface-state.test.ts +0 -16
- package/src/__tests__/credential-health-service.test.ts +14 -1
- package/src/__tests__/credential-record-retire.test.ts +1 -1
- package/src/__tests__/credential-record-write-through.test.ts +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +0 -145
- package/src/__tests__/custom-profile-ensure.test.ts +1 -1
- package/src/__tests__/default-profile-catalog-fallback.test.ts +5 -15
- package/src/__tests__/deterministic-verification-control-plane.test.ts +0 -2
- package/src/__tests__/dictation-profile-store.test.ts +6 -6
- package/src/__tests__/disk-usage.test.ts +28 -164
- package/src/__tests__/docker-signing-key-bootstrap.test.ts +1 -1
- package/src/__tests__/embedding-cloud-proxy-selection.test.ts +1 -1
- package/src/__tests__/emit-event-signal.test.ts +1 -1
- package/src/__tests__/gateway-client-cloud-outbound.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +1 -1
- package/src/__tests__/guardian-dispatch.test.ts +0 -13
- package/src/__tests__/helpers/seed-app.ts +1 -1
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/identity-routes.test.ts +1 -1
- package/src/__tests__/inference-profile-session-handler.test.ts +1 -1
- package/src/__tests__/inference-profile-session-ipc.test.ts +1 -1
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-config-quarantine-notice.test.ts +1 -1
- package/src/__tests__/injector-config-validation-reset-notice.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +1 -1
- package/src/__tests__/{platform.test.ts → layout.test.ts} +1 -1
- package/src/__tests__/list-all-apps.test.ts +1 -1
- package/src/__tests__/live-workspace-guard.test.ts +2 -2
- package/src/__tests__/llm-resolver-override-or-default.test.ts +5 -6
- package/src/__tests__/llm-resolver.test.ts +7 -7
- package/src/__tests__/llm-schema-fallback-profile.test.ts +9 -10
- package/src/__tests__/llm-usage-store.test.ts +0 -495
- package/src/__tests__/log-export-routes.test.ts +1 -1
- package/src/__tests__/mcp-config-secret-boundary.test.ts +12 -53
- package/src/__tests__/mcp-list-plugin-servers.test.ts +1 -1
- package/src/__tests__/memory-config-file-parity.test.ts +1 -1
- package/src/__tests__/memory-v2-static-injector.test.ts +1 -1
- package/src/__tests__/messages-read-boundary-guard.test.ts +0 -2
- package/src/__tests__/notification-guardian-path.test.ts +0 -7
- package/src/__tests__/onboarding-persona-write.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +8 -8
- package/src/__tests__/path-policy.test.ts +1 -1
- package/src/__tests__/persona-resolver.test.ts +1 -1
- package/src/__tests__/plugin-app-serve-routes.test.ts +1 -1
- package/src/__tests__/plugin-effective-enabled-set.test.ts +1 -1
- package/src/__tests__/plugin-import-boundary-guard.test.ts +4 -6
- package/src/__tests__/plugin-import-boundary-reverse-guard.test.ts +0 -3
- package/src/__tests__/provider-cloud-proxy-integration.test.ts +1 -5
- package/src/__tests__/provider-connections-backfill.test.ts +10 -10
- package/src/__tests__/prune-old-conversations-job.test.ts +6 -31
- package/src/__tests__/resolve-app.test.ts +1 -1
- package/src/__tests__/run-due-schedules.test.ts +1 -1
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +0 -53
- package/src/__tests__/schedule-routes.test.ts +1 -1
- package/src/__tests__/schedule-store.test.ts +1 -1
- package/src/__tests__/secret-routes-cloud-proxy.test.ts +1 -1
- package/src/__tests__/skill-load-plugin-scope.test.ts +1 -1
- package/src/__tests__/surface-completion-compaction-boundary.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -1
- package/src/__tests__/tool-audit.test.ts +5 -235
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +54 -114
- package/src/__tests__/tools-get-route.test.ts +1 -1
- package/src/__tests__/turn-outcome-read.test.ts +1 -1
- package/src/__tests__/twilio-routes.test.ts +0 -1
- package/src/__tests__/usage-attribution.test.ts +0 -31
- package/src/__tests__/verification-control-plane-policy.test.ts +3 -10
- package/src/__tests__/visible-app-context.test.ts +1 -1
- package/src/__tests__/voice-ingress-preflight.test.ts +1 -1
- package/src/__tests__/workspace-git-service.test.ts +1 -1
- package/src/__tests__/workspace-greetings.test.ts +1 -1
- package/src/acp/__tests__/helpers/acp-config-stub.ts +1 -1
- package/src/activation/progress-store.ts +1 -1
- package/src/activation/turn-hooks.ts +1 -1
- package/src/agent/loop.ts +0 -51
- package/src/apps/app-store.ts +1 -1
- package/src/avatar/__tests__/avatar-store.test.ts +2 -172
- package/src/avatar/accent-backfill.ts +1 -1
- package/src/avatar/avatar-manifest.ts +1 -1
- package/src/avatar/avatar-store.ts +10 -69
- package/src/avatar/ensure-raster.ts +1 -1
- package/src/avatar/identity-avatar.ts +1 -1
- package/src/avatar/sync-avatar.ts +1 -1
- package/src/avatar/traits-png-sync.ts +1 -1
- package/src/bundler/compiler-tools.ts +1 -1
- package/src/bundler/package-resolver.ts +1 -1
- package/src/calls/__tests__/call-controller.test.ts +25 -27
- package/src/calls/active-call-lease.ts +1 -1
- package/src/calls/call-controller.ts +3 -3
- package/src/calls/call-domain.ts +4 -8
- package/src/calls/call-store.ts +2 -76
- package/src/calls/resolve-call-tts-provider.ts +3 -3
- package/src/calls/twilio-config.ts +3 -3
- package/src/calls/twilio-rest.ts +2 -2
- package/src/calls/voice-ingress-preflight.ts +2 -2
- package/src/cli/bundled-modules.ts +0 -2
- package/src/cli/commands/__tests__/apps.test.ts +1 -1
- package/src/cli/commands/__tests__/plugins.test.ts +9 -66
- package/src/cli/commands/__tests__/ps.test.ts +67 -0
- package/src/cli/commands/auth.help.ts +2 -2
- package/src/cli/commands/avatar.ts +1 -1
- package/src/cli/commands/changelog.ts +1 -1
- package/src/cli/commands/cloud/__tests__/subscription.test.ts +2 -2
- package/src/cli/commands/cloud/index.help.ts +1 -1
- package/src/cli/commands/cloud/index.ts +2 -2
- package/src/cli/commands/db/refresh.ts +1 -1
- package/src/cli/commands/db/repair-step-conversation-backfill.ts +1 -1
- package/src/cli/commands/db/repair.ts +1 -1
- package/src/cli/commands/db/status.ts +1 -1
- package/src/cli/commands/inference-profiles.ts +1 -12
- package/src/cli/commands/memory/__tests__/memory-v3.test.ts +1 -116
- package/src/cli/commands/memory/index.help.ts +1 -43
- package/src/cli/commands/memory/memory-v3.ts +0 -64
- package/src/cli/commands/plugins.ts +54 -205
- package/src/cli/commands/ps.ts +5 -2
- package/src/cli/commands/status.ts +1 -1
- package/src/cli/index.help.ts +0 -2
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +36 -66
- package/src/cli/lib/__tests__/install-from-cloud.test.ts +1 -1
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -117
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +2 -185
- package/src/cli/lib/__tests__/plugin-catalog-resolve.test.ts +36 -66
- package/src/cli/lib/__tests__/plugin-catalog-visibility.test.ts +4 -6
- package/src/cli/lib/__tests__/plugin-details.test.ts +113 -96
- package/src/cli/lib/__tests__/search-plugins.test.ts +9 -16
- package/src/cli/lib/__tests__/uninstall-plugin.test.ts +1 -1
- package/src/cli/lib/__tests__/upgrade-plugin.test.ts +38 -15
- package/src/cli/lib/diff-plugin.ts +1 -1
- package/src/cli/lib/inspect-plugin.ts +13 -97
- package/src/cli/lib/install-from-cloud.ts +1 -1
- package/src/cli/lib/install-from-github.ts +75 -154
- package/src/cli/lib/install-plugin-dependencies.ts +1 -1
- package/src/cli/lib/list-installed-plugins.ts +1 -1
- package/src/cli/lib/open-browser.ts +1 -1
- package/src/cli/lib/plugin-catalog-cache.ts +8 -51
- package/src/cli/lib/plugin-catalog-resolve.ts +3 -22
- package/src/cli/lib/plugin-details.ts +5 -27
- package/src/cli/lib/plugin-marketplace.ts +18 -266
- package/src/cli/lib/search-plugins.ts +23 -43
- package/src/cli/lib/toggle-plugin.ts +1 -1
- package/src/cli/lib/uninstall-plugin.ts +1 -1
- package/src/cli/lib/upgrade-plugin.ts +3 -49
- package/src/cli/program.ts +1 -3
- package/src/cli.ts +1 -1
- package/src/cloud/client.ts +0 -6
- package/src/cloud/consent-cache.test.ts +22 -201
- package/src/cloud/consent-cache.ts +16 -111
- package/src/cloud/sync-identity.ts +1 -1
- package/src/config/__tests__/chat-settings.test.ts +1 -1
- package/src/config/__tests__/cloud-identity.test.ts +15 -2
- package/src/config/__tests__/default-plugin-skill-discovery.test.ts +1 -1
- package/src/config/__tests__/default-profile-catalog.test.ts +12 -51
- package/src/config/__tests__/deployment-context-defaults.test.ts +13 -13
- package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +4 -4
- package/src/config/__tests__/loader-last-known-good.test.ts +9 -9
- package/src/config/__tests__/loader-sparse-array-cleanup.test.ts +7 -7
- package/src/config/__tests__/plugin-resident-skill-discovery.test.ts +1 -1
- package/src/config/__tests__/profile-materialization.test.ts +2 -4
- package/src/config/__tests__/sync-gated-profiles.test.ts +1 -106
- package/src/config/acp-agent-write.ts +1 -1
- package/src/config/bundled-skills/settings/tools/open-system-settings.test.ts +1 -1
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/call-site-defaults.ts +0 -6
- package/src/config/cloud-identity.ts +12 -5
- package/src/config/composer-preferences.ts +1 -1
- package/src/config/default-profile-catalog.ts +8 -75
- package/src/config/default-profile-names.ts +2 -25
- package/src/config/env-registry.ts +1 -14
- package/src/config/env.ts +8 -6
- package/src/config/llm-resolver.ts +1 -2
- package/src/config/loader.ts +13 -17
- package/src/config/profile-materialization.ts +1 -1
- package/src/config/schema.ts +1 -7
- package/src/config/schemas/call-site-catalog.ts +0 -7
- package/src/config/schemas/llm.ts +25 -32
- package/src/config/seed-inference-profiles.ts +16 -17
- package/src/config/skills.ts +2 -2
- package/src/config/sync-gated-profiles.ts +6 -24
- package/src/credential-health/credential-health-service.ts +10 -3
- package/src/daemon/approval-generators.ts +3 -3
- package/src/daemon/config-watcher.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +0 -18
- package/src/daemon/conversation-agent-loop.ts +6 -97
- package/src/daemon/conversation-process.ts +1 -1
- package/src/daemon/conversation-skill-tools.ts +4 -72
- package/src/daemon/conversation-store.ts +1 -1
- package/src/daemon/conversation-surface-state.ts +0 -33
- package/src/daemon/conversation-surfaces.ts +1 -86
- package/src/daemon/conversation-tool-setup.test.ts +1 -1
- package/src/daemon/conversation-tool-setup.ts +0 -23
- package/src/daemon/conversation.ts +3 -5
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/dictation-profile-store.ts +3 -3
- package/src/daemon/event-loop-watchdog.test.ts +2 -198
- package/src/daemon/event-loop-watchdog.ts +0 -185
- package/src/daemon/external-plugins-bootstrap.ts +1 -1
- package/src/daemon/first-greeting.ts +1 -1
- package/src/daemon/handlers/skills.ts +1 -1
- package/src/daemon/host-app-control-proxy.ts +1 -1
- package/src/daemon/host-cu-proxy.ts +2 -2
- package/src/daemon/identity-helpers.ts +1 -1
- package/src/daemon/lifecycle.ts +11 -15
- package/src/daemon/main.ts +1 -1
- package/src/daemon/now-scratchpad.ts +1 -1
- package/src/daemon/process-message.ts +4 -4
- package/src/daemon/profiler-run-store.ts +2 -2
- package/src/daemon/providers-setup.ts +2 -2
- package/src/daemon/shutdown-handlers.ts +0 -10
- package/src/daemon/sqlite-corruption-watchdog.test.ts +2 -142
- package/src/daemon/sqlite-corruption-watchdog.ts +17 -81
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/desktop/desktop-session-manager.ts +1 -1
- package/src/desktop/desktop-wallpaper-renderer.ts +1 -1
- package/src/heartbeat/heartbeat-service.ts +1 -1
- package/src/home/feed-writer.ts +1 -1
- package/src/home/home-greeting-cache.ts +1 -1
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/hooks/__tests__/hook-live-reload.test.ts +1 -1
- package/src/hooks/hook-loader.ts +2 -2
- package/src/inbound/__tests__/oauth-callback-url.test.ts +2 -2
- package/src/inbound/oauth-callback-url.ts +3 -3
- package/src/ipc/__tests__/attachment-ipc.test.ts +1 -1
- package/src/ipc/socket-path.ts +1 -1
- package/src/live-voice/__tests__/live-voice-archive.test.ts +1 -1
- package/src/live-voice/__tests__/live-voice-vad.test.ts +1 -1
- package/src/live-voice/live-voice-session.ts +3 -66
- package/src/mcp/__tests__/effective-config.test.ts +1 -1
- package/src/mcp/__tests__/mcp-oauth-client-registration.test.ts +2 -2
- package/src/mcp/__tests__/mcp-oauth-provider.test.ts +2 -3
- package/src/mcp/__tests__/reload-signal-emission.test.ts +1 -1
- package/src/mcp/__tests__/reload-signal.test.ts +1 -1
- package/src/mcp/__tests__/workspace-mcp-config.test.ts +19 -21
- package/src/mcp/reload-signal.ts +1 -1
- package/src/mcp/workspace-mcp-config.ts +1 -23
- package/src/messaging/draft-store.ts +1 -1
- package/src/monitoring/__tests__/active-conversations.test.ts +1 -1
- package/src/monitoring/__tests__/page-cache.test.ts +1 -1
- package/src/monitoring/__tests__/stall-capture.test.ts +1 -1
- package/src/monitoring/__tests__/workspace-git-heartbeat.test.ts +1 -1
- package/src/monitoring/active-conversations.ts +1 -1
- package/src/monitoring/control.ts +1 -1
- package/src/monitoring/daemon-boot-time.ts +1 -1
- package/src/monitoring/daemon-heartbeat.ts +1 -1
- package/src/monitoring/page-cache.ts +1 -1
- package/src/monitoring/plugin-auto-update.ts +1 -7
- package/src/monitoring/plugin-source-watch.ts +1 -1
- package/src/monitoring/recovery/db.ts +1 -1
- package/src/monitoring/recovery/inflight-content.ts +1 -1
- package/src/monitoring/resource-sampler.ts +3 -14
- package/src/monitoring/stall-capture.ts +1 -1
- package/src/monitoring/worker.ts +9 -76
- package/src/monitoring/workspace-git-heartbeat.ts +1 -1
- package/src/oauth/connect-orchestrator.ts +4 -4
- package/src/permissions/checker.ts +1 -1
- package/src/permissions/workspace-policy.ts +1 -1
- package/src/persistence/__tests__/main-db-readonly-probe.ts +27 -52
- package/src/persistence/__tests__/message-content-file.test.ts +1 -1
- package/src/persistence/__tests__/slow-sync-log.test.ts +0 -2
- package/src/persistence/attachments-store.ts +1 -1
- package/src/persistence/conversation-crud.ts +1 -38
- package/src/persistence/conversation-directories.ts +1 -1
- package/src/persistence/conversation-types.ts +0 -8
- package/src/persistence/db-async-query.ts +1 -1
- package/src/persistence/db-connection.ts +11 -1
- package/src/persistence/db-init.ts +1 -1
- package/src/persistence/db-maintenance.ts +1 -1
- package/src/persistence/embeddings/__tests__/embedding-local-lifecycle.test.ts +1 -1
- package/src/persistence/embeddings/embedding-local.ts +4 -4
- package/src/persistence/embeddings/embedding-runtime-manager.ts +1 -1
- package/src/persistence/embeddings/qdrant-client.ts +1 -1
- package/src/persistence/embeddings/qdrant-manager.ts +1 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-backfill.test.ts +1 -1
- package/src/persistence/job-handlers/__tests__/message-lexical-enqueue.test.ts +1 -1
- package/src/persistence/job-handlers/cleanup.ts +8 -17
- package/src/persistence/llm-usage-store.ts +2 -229
- package/src/persistence/message-content-file.ts +1 -1
- package/src/persistence/migrations/209-strip-thinking-from-consolidated.ts +1 -1
- package/src/persistence/migrations/222-strip-placeholder-sentinels-from-messages.ts +1 -1
- package/src/persistence/migrations/296-rewrite-balanced-economy-profile-pins.test.ts +1 -1
- package/src/persistence/migrations/306-rewrite-frontier-profile-pins.test.ts +1 -1
- package/src/persistence/migrations/329-move-onboarding-events-to-telemetry-db.test.ts +13 -0
- package/src/persistence/migrations/330-move-auth-fallback-events-to-telemetry-db.test.ts +13 -0
- package/src/persistence/migrations/331-move-lifecycle-events-to-telemetry-db.test.ts +13 -0
- package/src/persistence/migrations/332-move-skill-loaded-events-to-telemetry-db.test.ts +13 -0
- package/src/persistence/migrations/333-create-telemetry-events-table.test.ts +7 -4
- package/src/persistence/migrations/334-backfill-telemetry-events-outbox.test.ts +13 -0
- package/src/persistence/migrations/387-drop-telemetry-tables.ts +51 -0
- package/src/persistence/migrations/__tests__/327-create-flush-checkpoints.test.ts +9 -1
- package/src/persistence/migrations/__tests__/387-drop-telemetry-tables.test.ts +79 -0
- package/src/persistence/migrations/helpers/relocation.ts +1 -1
- package/src/persistence/migrations/run-migrations.ts +1 -1
- package/src/persistence/migrations/validate-migration-state.ts +1 -1
- package/src/persistence/raw-query.ts +1 -29
- package/src/persistence/slow-sync-log.ts +0 -23
- package/src/persistence/steps.ts +2 -0
- package/src/{telemetry → persistence}/tool-audit.ts +6 -121
- package/src/plugin-api/index.ts +1 -1
- package/src/plugin-api/plugin-name-env.ts +1 -1
- package/src/plugins/__tests__/installed-plugin-dirs.test.ts +1 -1
- package/src/plugins/collect-source-versions.ts +1 -1
- package/src/plugins/defaults/channel/package.json +1 -1
- package/src/plugins/defaults/cloud-hosted/package.json +1 -1
- package/src/plugins/defaults/compaction/package.json +1 -1
- package/src/plugins/defaults/documents/package.json +1 -1
- package/src/plugins/defaults/empty-response/package.json +1 -1
- package/src/plugins/defaults/exploration-drift/package.json +1 -1
- package/src/plugins/defaults/image-fallback/package.json +1 -1
- package/src/plugins/defaults/image-recovery/package.json +1 -1
- package/src/plugins/defaults/max-tokens-continue/package.json +1 -1
- package/src/plugins/defaults/memory/__tests__/db-async-query.test.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/db-maintenance.test.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +0 -82
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-skill-card.test.ts +0 -41
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +0 -2
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +3 -52
- package/src/plugins/defaults/memory/memory-retrospective-skill-card.ts +0 -18
- package/src/plugins/defaults/memory/package.json +1 -1
- package/src/plugins/defaults/memory/paths.ts +4 -4
- package/src/plugins/defaults/memory/src/__tests__/memory-worker-routes.test.ts +1 -1
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +5 -5
- package/src/plugins/defaults/memory/src/memory-v3-routes.ts +0 -207
- package/src/plugins/defaults/memory/src/memory-worker-routes.ts +1 -1
- package/src/plugins/defaults/memory/startup.ts +1 -22
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +2 -253
- package/src/plugins/defaults/memory/v3/orchestrate.ts +5 -129
- package/src/plugins/defaults/memory/worker-control.ts +1 -1
- package/src/plugins/defaults/memory/worker.ts +2 -2
- package/src/plugins/defaults/session/package.json +1 -1
- package/src/plugins/defaults/surface-completion-nudge/package.json +1 -1
- package/src/plugins/defaults/task-progress/package.json +1 -1
- package/src/plugins/defaults/task-progress-nudge/package.json +1 -1
- package/src/plugins/defaults/title-generate/package.json +1 -1
- package/src/plugins/defaults/tool-error/package.json +1 -1
- package/src/plugins/defaults/tool-result-truncate/package.json +1 -1
- package/src/plugins/defaults/turn-context/package.json +1 -1
- package/src/plugins/defaults/workspace/injectors.ts +1 -1
- package/src/plugins/defaults/workspace/package.json +1 -1
- package/src/plugins/disabled-state.ts +1 -1
- package/src/plugins/ensure-plugin-api-shim.ts +1 -1
- package/src/plugins/ensure-shared-dep-links.ts +1 -1
- package/src/plugins/installed-plugin-dirs.ts +1 -1
- package/src/plugins/mcp-servers.ts +7 -9
- package/src/plugins/mtime-cache.ts +2 -2
- package/src/plugins/source-versions.ts +1 -1
- package/src/prompts/bootstrap-cleanup.ts +1 -1
- package/src/prompts/persona-resolver.ts +1 -1
- package/src/prompts/sections.ts +2 -2
- package/src/prompts/system-prompt.ts +10 -42
- package/src/prompts/templates/BOOTSTRAP-ACTIVATION-RAIL.md +0 -37
- package/src/providers/__tests__/cadet-connection-routing.test.ts +2 -2
- package/src/providers/cadet/client.ts +1 -1
- package/src/providers/inference/__tests__/base-url-route-validation.test.ts +1 -1
- package/src/providers/inference/adapter-factory.ts +1 -1
- package/src/providers/inference/backfill.ts +3 -10
- package/src/providers/inference/profile-probe.ts +1 -1
- package/src/providers/retry.ts +0 -2
- package/src/providers/types.ts +0 -7
- package/src/providers/usage-tracking.ts +1 -1
- package/src/routes/__tests__/route-host.test.ts +1 -1
- package/src/routes/control.ts +1 -1
- package/src/routes/route-host-client.ts +1 -1
- package/src/routes/worker.ts +2 -2
- package/src/runtime/agent-wake.ts +1 -1
- package/src/runtime/assistant-stream-state.ts +1 -1
- package/src/runtime/auth/token-service.ts +1 -1
- package/src/runtime/background-job-runner.ts +1 -1
- package/src/runtime/middleware/twilio-validation.ts +2 -2
- package/src/runtime/routes/__tests__/app-pin-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/apps-refresh-route.test.ts +1 -1
- package/src/runtime/routes/__tests__/avatar-state-routes.test.ts +3 -33
- package/src/runtime/routes/__tests__/cloud-credits-routes.test.ts +5 -4
- package/src/runtime/routes/__tests__/cloud-invoice-routes.test.ts +4 -3
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +72 -298
- package/src/runtime/routes/__tests__/default-plugin-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/deprecated-route-context.test.ts +15 -62
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +105 -12
- package/src/runtime/routes/__tests__/ingress-status-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/monitoring-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +47 -211
- package/src/runtime/routes/__tests__/route-host-worker-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/schedule-routes-disarm-reason.test.ts +1 -1
- package/src/runtime/routes/__tests__/schedule-worker-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher-host.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-routes-cli.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-routes-notices.test.ts +1 -1
- package/src/runtime/routes/__tests__/user-routes-request.test.ts +1 -1
- package/src/runtime/routes/app-management-routes.ts +1 -1
- package/src/runtime/routes/attachment-routes.ts +1 -1
- package/src/runtime/routes/audit-routes.ts +1 -1
- package/src/runtime/routes/avatar-routes.ts +3 -10
- package/src/runtime/routes/cloud-routes.ts +3 -3
- package/src/runtime/routes/content-source-routes.ts +1 -1
- package/src/runtime/routes/conversation-query-routes.ts +49 -706
- package/src/runtime/routes/conversation-routes.ts +1 -38
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/deprecated-route-context.ts +5 -61
- package/src/runtime/routes/heartbeat-routes.ts +1 -1
- package/src/runtime/routes/identity-routes.ts +1 -1
- package/src/runtime/routes/index.ts +0 -6
- package/src/runtime/routes/inference-profile-session-handler.ts +3 -3
- package/src/runtime/routes/inference-profiles-routes.ts +48 -21
- package/src/runtime/routes/inference-provider-connection-routes.ts +0 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +3 -3
- package/src/runtime/routes/log-export/__tests__/installed-inventory.test.ts +1 -1
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist-error-contract.test.ts +1 -1
- package/src/runtime/routes/log-export/__tests__/workspace-allowlist.test.ts +1 -1
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +17 -15
- package/src/runtime/routes/migration-rollback-routes.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +2 -3
- package/src/runtime/routes/monitoring-routes.ts +2 -2
- package/src/runtime/routes/oauth-providers.ts +5 -5
- package/src/runtime/routes/plugins-routes.ts +38 -163
- package/src/runtime/routes/profiler-routes.ts +1 -1
- package/src/runtime/routes/route-host-worker-routes.ts +1 -1
- package/src/runtime/routes/sanity-routes.ts +1 -1
- package/src/runtime/routes/schedule-routes.ts +1 -1
- package/src/runtime/routes/schedule-worker-routes.ts +1 -1
- package/src/runtime/routes/settings-routes.ts +1 -1
- package/src/runtime/routes/sounds-config-routes.ts +1 -1
- package/src/runtime/routes/surface-conversation-resolver.ts +1 -7
- package/src/runtime/routes/user-route-dispatcher.ts +1 -3
- package/src/runtime/routes/user-route-import.ts +1 -1
- package/src/runtime/routes/user-route-resolution.ts +1 -1
- package/src/runtime/routes/user-routes-cli.ts +1 -1
- package/src/runtime/routes/workspace-commit-routes.ts +1 -1
- package/src/runtime/routes/workspace-greetings.ts +1 -1
- package/src/runtime/routes/workspace-routes.ts +1 -1
- package/src/runtime/routes/workspace-utils.ts +1 -1
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/schedule/__tests__/plugin-schedule-declarations.test.ts +1 -1
- package/src/schedule/__tests__/plugin-schedule-reconciler.test.ts +1 -1
- package/src/schedule/plugin-schedule-availability.ts +1 -1
- package/src/schedule/plugin-schedule-declarations.ts +1 -1
- package/src/schedule/run-script.ts +1 -1
- package/src/schedule/scheduler.ts +1 -11
- package/src/schedule/worker-control.ts +1 -1
- package/src/schedule/worker.ts +3 -3
- package/src/security/oauth2.ts +2 -2
- package/src/security/secret-allowlist.ts +1 -1
- package/src/signals/cancel.ts +1 -1
- package/src/signals/conversation-undo.ts +1 -1
- package/src/signals/emit-event.ts +1 -1
- package/src/signals/event-stream.ts +1 -1
- package/src/signals/user-message.ts +1 -1
- package/src/skills/catalog-install.ts +2 -1
- package/src/skills/clawhub.ts +1 -1
- package/src/skills/cloud-store.ts +1 -1
- package/src/skills/path-classifier.ts +1 -1
- package/src/skills/skill-history.ts +1 -1
- package/src/skills/skillssh-registry.ts +1 -1
- package/src/skills/uninstall.ts +1 -1
- package/src/skills/workspace-skill-md-signature.ts +1 -1
- package/src/subagent/manager.ts +1 -1
- package/src/theme/workspace-theme.ts +1 -1
- package/src/tools/browser/auth-cache.ts +1 -1
- package/src/tools/browser/browser-manager.ts +1 -1
- package/src/tools/browser/runtime-check.ts +1 -1
- package/src/tools/executor.ts +4 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/permission-checker.ts +2 -51
- package/src/tools/run-standalone.ts +1 -1
- package/src/tools/skills/format-input-schema.ts +1 -1
- package/src/tools/skills/load.ts +1 -1
- package/src/tools/skills/scaffold-cloud.ts +0 -32
- package/src/tools/terminal/safe-env.ts +1 -2
- package/src/tools/terminal/sanitized-bash.ts +1 -1
- package/src/tools/terminal/shell.ts +1 -1
- package/src/tools/tool-approval-handler.ts +4 -1
- package/src/tools/workflows/manage-workflows.ts +2 -2
- package/src/tools/workflows/run-workflow.test.ts +1 -1
- package/src/tools/workspace-tools/loader.ts +1 -1
- package/src/tts/synthesis-stream.ts +2 -2
- package/src/usage/attribution.ts +1 -11
- package/src/util/browser.ts +1 -1
- package/src/util/bun-runtime.ts +2 -1
- package/src/util/device-id.ts +1 -1
- package/src/util/disk-usage.ts +4 -139
- package/src/util/layout.ts +3 -3
- package/src/util/logger.ts +1 -1
- package/src/util/logs-db-path.ts +1 -1
- package/src/util/memory-db-path.ts +1 -1
- package/src/util/{platform.ts → os.ts} +5 -30
- package/src/util/process-tree.ts +19 -0
- package/src/util/sqlite3-runtime.ts +1 -1
- package/src/util/telemetry-db-path.ts +1 -1
- package/src/watcher/__tests__/engine.test.ts +0 -23
- package/src/watcher/engine.ts +0 -7
- package/src/windows-compiled-cli.ts +0 -4
- package/src/windows-compiled-worker-entry.ts +0 -6
- package/src/workflows/leaf-runner.test.ts +1 -1
- package/src/workflows/leaf-runner.ts +1 -1
- package/src/workflows/library.ts +1 -1
- package/src/workspace/adaptive-thinking-repair.ts +5 -24
- package/src/workspace/byok-default-profile-ensure.ts +24 -26
- package/src/workspace/custom-profile-ensure.ts +2 -2
- package/src/workspace/git-service.ts +1 -1
- package/src/workspace/hatched-date.ts +1 -1
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +2 -2
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +1 -1
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +1 -1
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +1 -1
- package/src/workspace/migrations/registry.ts +0 -4
- package/src/workspace/turn-commit.ts +1 -1
- package/docs/activation-funnel-telemetry.md +0 -324
- package/scripts/bundled-plugin-packages.ts +0 -154
- package/scripts/generate-bundled-plugin-packages.ts +0 -29
- package/src/__tests__/activation-early-marking.test.ts +0 -114
- package/src/__tests__/auth-fallback-events-store.test.ts +0 -99
- package/src/__tests__/config-get-vision-flag.test.ts +0 -139
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +0 -400
- package/src/__tests__/internal-telemetry-routes.test.ts +0 -213
- package/src/__tests__/telemetry-routes.test.ts +0 -182
- package/src/__tests__/turn-events-store.test.ts +0 -376
- package/src/__tests__/ui-channel-variants.test.ts +0 -53
- package/src/avatar/__tests__/avatar-changed-telemetry.test.ts +0 -217
- package/src/avatar/avatar-changed-telemetry.ts +0 -128
- package/src/calls/__tests__/call-funnel-telemetry.test.ts +0 -204
- package/src/cli/commands/telemetry.help.ts +0 -27
- package/src/cli/commands/telemetry.ts +0 -83
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +0 -251
- package/src/cli/lib/__tests__/plugin-catalog-local.test.ts +0 -113
- package/src/cli/lib/__tests__/plugin-marketplace.test.ts +0 -384
- package/src/cli/lib/__tests__/plugin-pin-history.test.ts +0 -164
- package/src/cli/lib/__tests__/plugins-install-offline.test.ts +0 -228
- package/src/cli/lib/bundled-marketplace.json +0 -1575
- package/src/cli/lib/bundled-plugin-packages.json +0 -827
- package/src/cli/lib/bundled-plugin-packages.ts +0 -87
- package/src/cli/lib/plugin-catalog-local.ts +0 -94
- package/src/cli/lib/plugin-pin-history.ts +0 -276
- package/src/cloud/feature-gate.ts +0 -8
- package/src/config/__tests__/cloud-rehydration.test.ts +0 -180
- package/src/config/cloud-rehydration.ts +0 -35
- package/src/daemon/__tests__/auto-profile-router.test.ts +0 -380
- package/src/daemon/auto-profile-router.ts +0 -428
- package/src/live-voice/__tests__/live-voice-session-telemetry.test.ts +0 -391
- package/src/monitoring/__tests__/db-integrity-sample.test.ts +0 -113
- package/src/monitoring/__tests__/oom-kill-reporter.test.ts +0 -374
- package/src/monitoring/db-integrity-check.ts +0 -163
- package/src/monitoring/db-integrity-sample.ts +0 -176
- package/src/monitoring/oom-kill-reporter.ts +0 -469
- package/src/onboarding/__tests__/onboarding-events-store.test.ts +0 -158
- package/src/onboarding/onboarding-events-store.ts +0 -296
- package/src/persistence/__tests__/raw-query-telemetry.test.ts +0 -76
- package/src/persistence/lifecycle-events-store.test.ts +0 -134
- package/src/persistence/lifecycle-events-store.ts +0 -110
- package/src/plugins/defaults/memory/__tests__/activation-session-store.test.ts +0 -76
- package/src/plugins/defaults/memory/activation-session-store.ts +0 -50
- package/src/plugins/defaults/memory/src/__tests__/memory-v3-gate-stats.test.ts +0 -281
- package/src/runtime/routes/auto-profile-routes.ts +0 -83
- package/src/runtime/routes/internal-telemetry-routes.ts +0 -142
- package/src/runtime/routes/telemetry-routes.ts +0 -274
- package/src/security/auth-fallback-events-store.ts +0 -57
- package/src/telemetry/__tests__/activation-funnel.test.ts +0 -95
- package/src/telemetry/__tests__/config-setting-events-store.test.ts +0 -63
- package/src/telemetry/__tests__/config-setting-snapshot.test.ts +0 -143
- package/src/telemetry/__tests__/flush-checkpoints.test.ts +0 -56
- package/src/telemetry/__tests__/live-voice-funnel.test.ts +0 -174
- package/src/telemetry/__tests__/outbox-test-harness.ts +0 -85
- package/src/telemetry/__tests__/phone-call-funnel.test.ts +0 -72
- package/src/telemetry/__tests__/telemetry-event-fixtures.ts +0 -282
- package/src/telemetry/__tests__/watchdog-events-store.test.ts +0 -71
- package/src/telemetry/activation-funnel.ts +0 -172
- package/src/telemetry/config-setting-events-store.ts +0 -40
- package/src/telemetry/config-setting-snapshot.ts +0 -170
- package/src/telemetry/flush-checkpoints.ts +0 -70
- package/src/telemetry/live-voice-funnel.ts +0 -185
- package/src/telemetry/memory-corpus-size.test.ts +0 -120
- package/src/telemetry/memory-corpus-size.ts +0 -184
- package/src/telemetry/memory-tier-reporter.test.ts +0 -195
- package/src/telemetry/memory-tier-reporter.ts +0 -130
- package/src/telemetry/phone-call-funnel.ts +0 -144
- package/src/telemetry/skill-loaded-events-store.test.ts +0 -93
- package/src/telemetry/skill-loaded-events-store.ts +0 -39
- package/src/telemetry/telemetry-event-sources.test.ts +0 -223
- package/src/telemetry/telemetry-event-sources.ts +0 -597
- package/src/telemetry/telemetry-events-outbox.test.ts +0 -375
- package/src/telemetry/telemetry-events-outbox.ts +0 -237
- package/src/telemetry/telemetry-main-db.ts +0 -48
- package/src/telemetry/telemetry-wire-source.json +0 -4
- package/src/telemetry/telemetry-wire-validation.test.ts +0 -157
- package/src/telemetry/telemetry-wire-validation.ts +0 -162
- package/src/telemetry/telemetry-wire.generated.ts +0 -483
- package/src/telemetry/tool-executed-events-store.test.ts +0 -210
- package/src/telemetry/tool-executed-events-store.ts +0 -102
- package/src/telemetry/trace-collection-policy.test.ts +0 -28
- package/src/telemetry/trace-collection-policy.ts +0 -30
- package/src/telemetry/turn-events-store.ts +0 -216
- package/src/telemetry/turn-trace-store.test.ts +0 -884
- package/src/telemetry/turn-trace-store.ts +0 -399
- package/src/telemetry/types.test.ts +0 -38
- package/src/telemetry/types.ts +0 -780
- package/src/telemetry/usage-telemetry-reporter.test.ts +0 -3445
- package/src/telemetry/usage-telemetry-reporter.ts +0 -566
- package/src/telemetry/watchdog-direct-emit.test.ts +0 -112
- package/src/telemetry/watchdog-direct-emit.ts +0 -104
- package/src/telemetry/watchdog-events-store.ts +0 -31
- package/src/tools/ui-surface/channel-variants.ts +0 -52
- package/src/watcher/__tests__/telemetry.test.ts +0 -178
- package/src/watcher/telemetry.ts +0 -93
- package/src/workspace/migrations/097-enable-adaptive-thinking-managed-profiles.ts +0 -165
- package/src/workspace/migrations/104-recheck-adaptive-thinking-model-implied-anthropic.ts +0 -151
- /package/src/{telemetry → persistence}/tool-usage-store.ts +0 -0
- /package/src/{telemetry → persistence}/turn-outcome.ts +0 -0
|
@@ -19,8 +19,6 @@
|
|
|
19
19
|
* POST /v1/messages/queued/:id/steer — steer to a queued message
|
|
20
20
|
*/
|
|
21
21
|
|
|
22
|
-
import { isDeepStrictEqual } from "node:util";
|
|
23
|
-
|
|
24
22
|
import { z } from "zod";
|
|
25
23
|
|
|
26
24
|
import { LlmContextResponseSchema } from "../../api/responses/llm-context-response.js";
|
|
@@ -35,39 +33,26 @@ import {
|
|
|
35
33
|
scrubNulledChatSettings,
|
|
36
34
|
validateChatSettingsWrite,
|
|
37
35
|
} from "../../config/chat-settings.js";
|
|
38
|
-
import {
|
|
39
|
-
catalogEntryFor,
|
|
40
|
-
modalitiesOf,
|
|
41
|
-
resolveModalityOverride,
|
|
42
|
-
} from "../../config/input-modalities.js";
|
|
43
36
|
import {
|
|
44
37
|
deepMergeOverwrite,
|
|
45
38
|
getConfig,
|
|
46
39
|
invalidateConfigCache,
|
|
47
|
-
loadConfig,
|
|
48
40
|
loadRawConfig,
|
|
49
41
|
saveRawConfig,
|
|
50
42
|
setNestedValue,
|
|
51
43
|
withSuppressedConfigDiskWrites,
|
|
52
44
|
withSuppressedConfigDiskWritesSync,
|
|
53
45
|
} from "../../config/loader.js";
|
|
54
|
-
import {
|
|
55
|
-
completeCustomProfile,
|
|
56
|
-
mergePreservingUnknownKeys,
|
|
57
|
-
} from "../../config/profile-materialization.js";
|
|
58
46
|
import {
|
|
59
47
|
type AssistantConfig,
|
|
60
48
|
AssistantConfigSchema,
|
|
61
49
|
} from "../../config/schema.js";
|
|
62
50
|
import { getSchemaAtPath } from "../../config/schema-utils.js";
|
|
63
51
|
import {
|
|
64
|
-
collectFallbackProfileIssues,
|
|
65
|
-
LLMConfigBase,
|
|
66
52
|
LLMConfigFragment,
|
|
53
|
+
LLMDefaultConfigSchema,
|
|
67
54
|
LLMSchema,
|
|
68
55
|
ProfileEntry,
|
|
69
|
-
routingIdentityModelIssue,
|
|
70
|
-
unknownLlmProviderIssue,
|
|
71
56
|
} from "../../config/schemas/llm.js";
|
|
72
57
|
import { VALID_MEMORY_EMBEDDING_PROVIDERS } from "../../config/schemas/memory-storage.js";
|
|
73
58
|
import { ServiceModeSchema } from "../../config/schemas/services.js";
|
|
@@ -100,7 +85,6 @@ import {
|
|
|
100
85
|
log,
|
|
101
86
|
} from "../../daemon/handlers/shared.js";
|
|
102
87
|
import { rescheduleHeartbeatIfTimezoneChanged } from "../../heartbeat/heartbeat-service.js";
|
|
103
|
-
import { overlayWorkspaceMcpForConfigRead } from "../../mcp/workspace-mcp-config.js";
|
|
104
88
|
import {
|
|
105
89
|
getAssistantMessageIdsInTurn,
|
|
106
90
|
getConversation,
|
|
@@ -120,7 +104,6 @@ import { getMemoryRecallLogByMessageIds } from "../../plugins/defaults/memory/me
|
|
|
120
104
|
import { getMemoryV2ActivationLogByMessageIds } from "../../plugins/defaults/memory/v2/activation-log-store.js";
|
|
121
105
|
import { getMemoryV3SelectionForInspectorByMessageIds } from "../../plugins/defaults/memory/v3/selection-log-store.js";
|
|
122
106
|
import { CLOUD_ROUTABLE_PROVIDERS } from "../../providers/cadet-model-routing.js";
|
|
123
|
-
import { writableProfileProviderIssue } from "../../providers/connection-resolution.js";
|
|
124
107
|
import { ROUTING_IDENTITY_PROVIDERS } from "../../providers/inference/auth.js";
|
|
125
108
|
import { PROVIDERS_REQUIRING_BASE_URL_AND_MODELS } from "../../providers/inference/auth.js";
|
|
126
109
|
import {
|
|
@@ -173,10 +156,7 @@ type LlmContextRouteResult = Omit<LlmContextNormalizationResult, "summary"> & {
|
|
|
173
156
|
import {
|
|
174
157
|
CODE_OWNED_PROFILE_NAMES,
|
|
175
158
|
getEffectiveProfilesForProvider,
|
|
176
|
-
getUserSelectableProfilesForProvider,
|
|
177
|
-
INVARIANT_PROFILE_NAMES,
|
|
178
159
|
MANAGED_PROFILE_NAMES,
|
|
179
|
-
resolveDefaultProfileForProvider,
|
|
180
160
|
} from "../../config/default-profile-catalog.js";
|
|
181
161
|
import { DEFAULT_PROFILE_KEYS } from "../../config/default-profile-names.js";
|
|
182
162
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
@@ -523,22 +503,18 @@ async function handleSetEmbeddingConfig({ body }: RouteHandlerArgs) {
|
|
|
523
503
|
}
|
|
524
504
|
|
|
525
505
|
/**
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
* normalized slice back onto the caller's object instead of relying on
|
|
532
|
-
* shared references.
|
|
506
|
+
* The `config_set` body. `value` is `z.unknown()` — deliberately wider than
|
|
507
|
+
* an object shape — because the CLI contract writes scalar values and
|
|
508
|
+
* explicit `null`s (`set heartbeat.activeHoursStart null` clears a key), so
|
|
509
|
+
* the value is any JSON at all; only its PRESENCE is required, which zod
|
|
510
|
+
* cannot express on an unknown leaf, so the handler keeps that domain check.
|
|
533
511
|
*/
|
|
534
|
-
const
|
|
535
|
-
const RawProfileEntrySchema = z.record(z.string(), z.unknown());
|
|
536
|
-
const RawLlmWriteSliceSchema = z
|
|
512
|
+
const ConfigSetByKeyBodySchema = z
|
|
537
513
|
.object({
|
|
538
|
-
|
|
539
|
-
|
|
514
|
+
path: z.string().min(1),
|
|
515
|
+
value: z.unknown(),
|
|
540
516
|
})
|
|
541
|
-
.
|
|
517
|
+
.meta({ id: "ConfigSetByKeyRequest" });
|
|
542
518
|
|
|
543
519
|
/**
|
|
544
520
|
* Wire shape of the `memory` section in config responses. Passthrough
|
|
@@ -594,33 +570,28 @@ const CallSiteOverrideDraftSchema = nullablePartial(
|
|
|
594
570
|
* the generated SDK produces literal-union types — no hand-written patch
|
|
595
571
|
* types needed downstream.
|
|
596
572
|
*/
|
|
597
|
-
|
|
573
|
+
export type ConfigPatchRequest = z.infer<typeof ConfigPatchRequestSchema>;
|
|
574
|
+
|
|
575
|
+
export const ConfigPatchRequestSchema = z
|
|
598
576
|
.object({
|
|
599
577
|
...ChatSettingsPatchSchema.shape,
|
|
600
578
|
llm: z
|
|
601
579
|
.object({
|
|
602
|
-
default: nullablePartial(
|
|
603
|
-
LLMConfigFragment.extend({
|
|
604
|
-
provider_connection: z.string().optional(),
|
|
605
|
-
}),
|
|
606
|
-
)
|
|
580
|
+
default: nullablePartial(LLMDefaultConfigSchema)
|
|
607
581
|
.passthrough()
|
|
608
582
|
.nullable()
|
|
609
583
|
.optional(),
|
|
610
584
|
profiles: z
|
|
611
585
|
.record(z.string(), ProfilePatchEntrySchema.nullable())
|
|
586
|
+
.nullable()
|
|
612
587
|
.optional(),
|
|
613
|
-
profileOrder: z.array(z.string()).optional(),
|
|
614
|
-
activeProfile: z.string().nullable().optional(),
|
|
615
|
-
advisorProfile: z.string().nullable().optional(),
|
|
588
|
+
profileOrder: z.array(z.string().min(1)).optional(),
|
|
589
|
+
activeProfile: z.string().min(1).nullable().optional(),
|
|
590
|
+
advisorProfile: z.string().min(1).nullable().optional(),
|
|
616
591
|
callSites: z
|
|
617
592
|
.record(z.string(), CallSiteOverrideDraftSchema.nullable())
|
|
618
593
|
.optional(),
|
|
619
|
-
profileSession:
|
|
620
|
-
.object({
|
|
621
|
-
defaultTtlSeconds: z.number().optional(),
|
|
622
|
-
maxTtlSeconds: z.number().optional(),
|
|
623
|
-
})
|
|
594
|
+
profileSession: nullablePartial(LLMSchema.shape.profileSession.unwrap())
|
|
624
595
|
.nullable()
|
|
625
596
|
.optional(),
|
|
626
597
|
})
|
|
@@ -678,253 +649,6 @@ const ConfigGetResponseSchema = AssistantConfigSchema.pick({
|
|
|
678
649
|
services: true,
|
|
679
650
|
});
|
|
680
651
|
|
|
681
|
-
function handleGetConfig() {
|
|
682
|
-
try {
|
|
683
|
-
// The overlays stamp wire-only state (catalog bodies, effective chat
|
|
684
|
-
// settings, capability flags) onto the returned object. Clone first so
|
|
685
|
-
// the loader's cached config — and every other `getConfig()` reader,
|
|
686
|
-
// including the config-write merge base — never sees the wire view.
|
|
687
|
-
const config = structuredClone(loadConfig());
|
|
688
|
-
overlayWorkspaceMcpForConfigRead(config);
|
|
689
|
-
overlayEffectiveProfilesForWire(config);
|
|
690
|
-
enrichProfilesForWire(config);
|
|
691
|
-
overlayChatSettingsForWire(config);
|
|
692
|
-
return config;
|
|
693
|
-
} catch (err) {
|
|
694
|
-
const message = err instanceof Error ? err.message : String(err);
|
|
695
|
-
throw new InternalError(`Failed to read config: ${message}`);
|
|
696
|
-
}
|
|
697
|
-
}
|
|
698
|
-
function overlayChatSettingsForWire(config: AssistantConfig): void {
|
|
699
|
-
const effective = getConfig();
|
|
700
|
-
config.conversations = {
|
|
701
|
-
...config.conversations,
|
|
702
|
-
autoArchive: {
|
|
703
|
-
...config.conversations?.autoArchive,
|
|
704
|
-
...effective.conversations.autoArchive,
|
|
705
|
-
},
|
|
706
|
-
};
|
|
707
|
-
config.notifications = {
|
|
708
|
-
...config.notifications,
|
|
709
|
-
newMessageEnabled: effective.notifications.newMessageEnabled,
|
|
710
|
-
};
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
/**
|
|
714
|
-
* Replace `llm.profiles` in an outgoing config response with the effective
|
|
715
|
-
* profile view (code-catalog default bodies + workspace overlays). Default
|
|
716
|
-
* profile CONTENT is code-owned and the workspace holds at most a thin stub,
|
|
717
|
-
* but clients (settings UI, sticky-profile pickers) need the full bodies to
|
|
718
|
-
* render labels/models — so the wire view materializes them, resolved through
|
|
719
|
-
* `llm.default`'s column of the intent × provider matrix so a BYO
|
|
720
|
-
* install sees the provider/model that actually dispatches. Wire-only:
|
|
721
|
-
* `normalizeCloudProfileWrites` reduces echoed bodies back to the
|
|
722
|
-
* workspace-owned fields on the write paths, so a `config get` →
|
|
723
|
-
* `config set` round-trip never persists catalog content — the two must
|
|
724
|
-
* resolve through the same column or honest round-trips are rejected.
|
|
725
|
-
*
|
|
726
|
-
* The profiles come from one schema parse of the `llm` block being served
|
|
727
|
-
* through the real `LLMSchema`, whose `isDefaultProviderChoice` clamp
|
|
728
|
-
* shields the matrix lookup from a persisted value the matrix cannot
|
|
729
|
-
* implement, which a raw read would feed straight into resolution.
|
|
730
|
-
*/
|
|
731
|
-
function overlayEffectiveProfilesForWire(config: AssistantConfig): void {
|
|
732
|
-
const parsedLlm = LLMSchema.safeParse(config.llm);
|
|
733
|
-
config.llm.profiles = getUserSelectableProfilesForProvider(
|
|
734
|
-
parsedLlm.success ? parsedLlm.data : undefined,
|
|
735
|
-
);
|
|
736
|
-
}
|
|
737
|
-
|
|
738
|
-
/**
|
|
739
|
-
* Normalize managed default-profile entries in a config-write fragment, in
|
|
740
|
-
* place, so a `config get` → write round-trip of the enriched wire view is a
|
|
741
|
-
* no-op while genuine edit attempts still reach the invariant guard's
|
|
742
|
-
* precise rejections:
|
|
743
|
-
*
|
|
744
|
-
* - A default name backed by a user-source on-disk entry is a legacy shadow
|
|
745
|
-
* and stays fully editable — left untouched here.
|
|
746
|
-
* - Echo-stripping: any field whose incoming value equals the current
|
|
747
|
-
* effective (wire) value is deleted from the fragment — it is catalog
|
|
748
|
-
* content the client read from us, not user input. Values that DIFFER stay
|
|
749
|
-
* in the fragment for {@link assertInvariantProfilesPreserved} to reject
|
|
750
|
-
* (or, for `status`, to judge as the one legal transition).
|
|
751
|
-
* - A default name with NO on-disk entry is catalog-owned: after
|
|
752
|
-
* echo-stripping, any remaining content field, a `disabled` status, or a
|
|
753
|
-
* non-managed `source` is rejected — default names cannot be newly
|
|
754
|
-
* shadowed or given content. A clean echo reduces to a no-op
|
|
755
|
-
* `{source: "managed"}` stub.
|
|
756
|
-
*
|
|
757
|
-
* The llm slice is parsed through {@link RawLlmWriteSliceSchema} and the
|
|
758
|
-
* normalized slice written back — a zod parse copies, so the write-back (not
|
|
759
|
-
* shared references) is what carries the normalization to the caller's patch.
|
|
760
|
-
* `handleSetConfig` reads the written-back shape for entry-level SETs.
|
|
761
|
-
*/
|
|
762
|
-
export function normalizeCloudProfileWrites(
|
|
763
|
-
patch: Record<string, unknown>,
|
|
764
|
-
): void {
|
|
765
|
-
const llm = RawLlmWriteSliceSchema.safeParse(patch.llm);
|
|
766
|
-
if (!llm.success || !llm.data.profiles) {
|
|
767
|
-
return;
|
|
768
|
-
}
|
|
769
|
-
const profiles = llm.data.profiles;
|
|
770
|
-
|
|
771
|
-
const currentLlm = RawLlmWriteSliceSchema.safeParse(loadRawConfig().llm);
|
|
772
|
-
const typedCurrent = currentLlm.success
|
|
773
|
-
? LLMSchema.shape.profiles.safeParse(currentLlm.data.profiles)
|
|
774
|
-
: undefined;
|
|
775
|
-
const currentProfiles: Record<string, unknown> | undefined =
|
|
776
|
-
typedCurrent?.success ? typedCurrent.data : undefined;
|
|
777
|
-
|
|
778
|
-
for (const name of Object.keys(profiles)) {
|
|
779
|
-
if (!MANAGED_PROFILE_NAMES.has(name)) {
|
|
780
|
-
continue;
|
|
781
|
-
}
|
|
782
|
-
const entry = RawProfileEntrySchema.safeParse(profiles[name]);
|
|
783
|
-
if (!entry.success) {
|
|
784
|
-
continue;
|
|
785
|
-
}
|
|
786
|
-
|
|
787
|
-
const current = RawProfileEntrySchema.safeParse(currentProfiles?.[name]);
|
|
788
|
-
|
|
789
|
-
if (current.success && current.data.source !== "managed") {
|
|
790
|
-
// Legacy user-owned shadow: fully editable, normal custom-profile rules.
|
|
791
|
-
continue;
|
|
792
|
-
}
|
|
793
|
-
|
|
794
|
-
// Must resolve through the same provider column as
|
|
795
|
-
// `overlayEffectiveProfilesForWire`, or an echo of the wire view would
|
|
796
|
-
// not match `effective` and an honest round-trip would be rejected.
|
|
797
|
-
const resolved = resolveDefaultProfileForProvider(
|
|
798
|
-
typedCurrent?.success ? typedCurrent.data : undefined,
|
|
799
|
-
name,
|
|
800
|
-
getConfig().llm.default,
|
|
801
|
-
);
|
|
802
|
-
const effective: Record<string, unknown> | undefined = resolved
|
|
803
|
-
? { ...resolved }
|
|
804
|
-
: undefined;
|
|
805
|
-
for (const key of Object.keys(entry.data)) {
|
|
806
|
-
if (key === "source" || key === "status") {
|
|
807
|
-
continue;
|
|
808
|
-
}
|
|
809
|
-
const matchesEffective =
|
|
810
|
-
effective != null &&
|
|
811
|
-
key in effective &&
|
|
812
|
-
isDeepStrictEqual(entry.data[key], effective[key]);
|
|
813
|
-
if (!current.success || !(key in current.data)) {
|
|
814
|
-
// Not on disk: a value matching the wire view is a client echo of
|
|
815
|
-
// catalog content — drop it. Anything else stays for the guard.
|
|
816
|
-
if (matchesEffective) {
|
|
817
|
-
delete entry.data[key];
|
|
818
|
-
}
|
|
819
|
-
continue;
|
|
820
|
-
}
|
|
821
|
-
// The key exists on disk (a frozen overlay field, or stale content an
|
|
822
|
-
// overlay persisted). Deleting it would read as a key removal on a
|
|
823
|
-
// full-entry SET, so instead: an echo of the wire value that differs
|
|
824
|
-
// from disk is pinned back to the on-disk value (no change for the
|
|
825
|
-
// guard to reject); everything else is left for the guard's
|
|
826
|
-
// frozen-field comparison.
|
|
827
|
-
if (
|
|
828
|
-
matchesEffective &&
|
|
829
|
-
!isDeepStrictEqual(entry.data[key], current.data[key])
|
|
830
|
-
) {
|
|
831
|
-
entry.data[key] = current.data[key];
|
|
832
|
-
}
|
|
833
|
-
}
|
|
834
|
-
|
|
835
|
-
if (current.success) {
|
|
836
|
-
// Existing stub: the guard compares the merged result against it and
|
|
837
|
-
// rejects everything but the status re-enable.
|
|
838
|
-
if (entry.data.source === undefined) {
|
|
839
|
-
entry.data.source = "managed";
|
|
840
|
-
}
|
|
841
|
-
profiles[name] = entry.data;
|
|
842
|
-
continue;
|
|
843
|
-
}
|
|
844
|
-
|
|
845
|
-
// No on-disk entry: the name is catalog-owned. Nothing but a clean echo
|
|
846
|
-
// (which reduced to source/status above) may pass. The wire-only flags
|
|
847
|
-
// ride echoes too — the write path's schema parse strips them before
|
|
848
|
-
// anything persists.
|
|
849
|
-
if ("source" in entry.data && entry.data.source !== "managed") {
|
|
850
|
-
throw new BadRequestError(
|
|
851
|
-
`Cannot create profile "${name}" — the name is reserved for a code-defined default profile.`,
|
|
852
|
-
);
|
|
853
|
-
}
|
|
854
|
-
if (
|
|
855
|
-
"status" in entry.data &&
|
|
856
|
-
entry.data.status != null &&
|
|
857
|
-
entry.data.status !== "active"
|
|
858
|
-
) {
|
|
859
|
-
throw new BadRequestError(`Cannot disable cloud profile "${name}".`);
|
|
860
|
-
}
|
|
861
|
-
const residual = Object.keys(entry.data).filter(
|
|
862
|
-
(key) =>
|
|
863
|
-
key !== "source" &&
|
|
864
|
-
key !== "status" &&
|
|
865
|
-
key !== "invariant" &&
|
|
866
|
-
key !== "supportsVision",
|
|
867
|
-
);
|
|
868
|
-
if (residual.length > 0) {
|
|
869
|
-
throw new BadRequestError(
|
|
870
|
-
`Cannot edit cloud profile "${name}" fields [${residual.join(", ")}]. ` +
|
|
871
|
-
`Cloud profiles are read-only; duplicate to a custom profile to customize.`,
|
|
872
|
-
);
|
|
873
|
-
}
|
|
874
|
-
entry.data.source = "managed";
|
|
875
|
-
profiles[name] = entry.data;
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
patch.llm = llm.data;
|
|
879
|
-
}
|
|
880
|
-
|
|
881
|
-
/**
|
|
882
|
-
* The enriched profile shape clients consume: {@link ProfileEntry} plus the
|
|
883
|
-
* wire-only flags `enrichProfilesForWire` stamps onto config-read responses.
|
|
884
|
-
* The flags are deliberately absent from `ProfileEntry` — the persisted
|
|
885
|
-
* schema — so a config write's schema parse strips echoed copies instead of
|
|
886
|
-
* persisting them.
|
|
887
|
-
*/
|
|
888
|
-
type WireProfileEntry = ProfileEntry & {
|
|
889
|
-
invariant?: boolean;
|
|
890
|
-
supportsVision?: boolean;
|
|
891
|
-
};
|
|
892
|
-
|
|
893
|
-
/**
|
|
894
|
-
* Annotate each profile in `config.llm.profiles` with wire-only flags —
|
|
895
|
-
* never persisted to disk:
|
|
896
|
-
*
|
|
897
|
-
* - `supportsVision`: resolved from the model catalog, with a profile
|
|
898
|
-
* `inputModalities.image` override winning when set. Unknown (provider,
|
|
899
|
-
* model) pairs with no override default to `true` (fail-open) so image
|
|
900
|
-
* upload remains available for custom / unlisted models.
|
|
901
|
-
* - `invariant`: `true` for managed-source entries of the cloud profile
|
|
902
|
-
* names (`INVARIANT_PROFILE_NAMES`); absent otherwise. Source-gated to
|
|
903
|
-
* match `assertInvariantProfilesPreserved` — a user-owned profile sharing
|
|
904
|
-
* a cloud name is fully editable, so it must render as a normal custom
|
|
905
|
-
* profile.
|
|
906
|
-
*/
|
|
907
|
-
function enrichProfilesForWire(config: AssistantConfig): void {
|
|
908
|
-
const profiles: Record<string, WireProfileEntry> = config.llm.profiles;
|
|
909
|
-
for (const [name, entry] of Object.entries(profiles)) {
|
|
910
|
-
if (INVARIANT_PROFILE_NAMES.has(name) && entry.source === "managed") {
|
|
911
|
-
entry.invariant = true;
|
|
912
|
-
}
|
|
913
|
-
|
|
914
|
-
if (entry.provider == null || entry.model == null) {
|
|
915
|
-
continue;
|
|
916
|
-
}
|
|
917
|
-
|
|
918
|
-
const catalogModel = catalogEntryFor(entry.provider, entry.model);
|
|
919
|
-
const catalogVision = catalogModel?.supportsVision;
|
|
920
|
-
const imageOverride = modalitiesOf({
|
|
921
|
-
inputModalities: entry.inputModalities,
|
|
922
|
-
})?.image;
|
|
923
|
-
entry.supportsVision =
|
|
924
|
-
resolveModalityOverride(imageOverride, catalogVision) ?? true;
|
|
925
|
-
}
|
|
926
|
-
}
|
|
927
|
-
|
|
928
652
|
/**
|
|
929
653
|
* Return the JSON Schema for the assistant config (full or scoped).
|
|
930
654
|
*
|
|
@@ -957,346 +681,6 @@ function handleGetConfigSchema({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
957
681
|
};
|
|
958
682
|
}
|
|
959
683
|
|
|
960
|
-
export function rejectCloudProfileDeletion(
|
|
961
|
-
body: Record<string, unknown>,
|
|
962
|
-
): void {
|
|
963
|
-
const llm = RawLlmWriteSliceSchema.safeParse(body.llm);
|
|
964
|
-
if (!llm.success) {
|
|
965
|
-
return;
|
|
966
|
-
}
|
|
967
|
-
if (llm.data.profiles === null) {
|
|
968
|
-
throw new BadRequestError(
|
|
969
|
-
"Cannot null llm.profiles — cloud profiles would be deleted.",
|
|
970
|
-
);
|
|
971
|
-
}
|
|
972
|
-
const profiles = llm.data.profiles;
|
|
973
|
-
if (!profiles) {
|
|
974
|
-
return;
|
|
975
|
-
}
|
|
976
|
-
const existingLlm = RawLlmWriteSliceSchema.safeParse(getConfig().llm);
|
|
977
|
-
const existingProfiles = existingLlm.success
|
|
978
|
-
? (existingLlm.data.profiles ?? {})
|
|
979
|
-
: {};
|
|
980
|
-
for (const name of Object.keys(profiles)) {
|
|
981
|
-
if (profiles[name] !== null || !MANAGED_PROFILE_NAMES.has(name)) {
|
|
982
|
-
continue;
|
|
983
|
-
}
|
|
984
|
-
// Only block deletion when the on-disk entry is Cadet Cloud. A
|
|
985
|
-
// user-owned profile sharing a cloud name carries a non-managed `source`
|
|
986
|
-
// and is freely deletable.
|
|
987
|
-
const existing = RawProfileEntrySchema.safeParse(existingProfiles[name]);
|
|
988
|
-
if (existing.success && existing.data.source === "managed") {
|
|
989
|
-
throw new BadRequestError(`Cannot delete cloud profile "${name}".`);
|
|
990
|
-
}
|
|
991
|
-
}
|
|
992
|
-
}
|
|
993
|
-
|
|
994
|
-
/**
|
|
995
|
-
* Enforce the cloud-profile invariants at the config-write choke point.
|
|
996
|
-
*
|
|
997
|
-
* Protects the thin managed stubs (`INVARIANT_PROFILE_NAMES`) that live in
|
|
998
|
-
* workspace config. Default profile CONTENT is code-owned and only exists on
|
|
999
|
-
* the wire, so the guard's job is the stub itself: it checks entries present
|
|
1000
|
-
* in the OLD config, and `normalizeCloudProfileWrites` reduces incoming
|
|
1001
|
-
* managed entries to the workspace-owned fields before this comparison runs.
|
|
1002
|
-
*
|
|
1003
|
-
* Invariance is gated on managed ownership: a name is enforced only when the
|
|
1004
|
-
* OLD entry's `source` is `"managed"`. A user-owned profile sharing a
|
|
1005
|
-
* managed name stays fully editable and deletable — for os-beta that state
|
|
1006
|
-
* is real and supported, because the flag-gated reconcile refuses to
|
|
1007
|
-
* overwrite a same-named user profile.
|
|
1008
|
-
*
|
|
1009
|
-
* For each invariant name where the OLD raw config carries a cloud-source
|
|
1010
|
-
* plain-object entry at `llm.profiles[name]`:
|
|
1011
|
-
*
|
|
1012
|
-
* - The NEW raw config must still carry a plain-object entry at the same
|
|
1013
|
-
* path — deletion, non-object overwrite, and subtree replacement are all
|
|
1014
|
-
* rejected by this single check, regardless of route.
|
|
1015
|
-
* - `status` is one-directional: effective status is
|
|
1016
|
-
* `entry.status !== "disabled"` (absence/null = active). An active managed
|
|
1017
|
-
* profile can never be disabled; a changed `status` must be `"active"`,
|
|
1018
|
-
* `null`, or absent — re-enabling a disabled profile. Any other value is
|
|
1019
|
-
* rejected.
|
|
1020
|
-
* - The wire-only flags (`invariant`, `supportsVision`) are ignored on both
|
|
1021
|
-
* sides: the write path's schema parse strips them from incoming writes,
|
|
1022
|
-
* but configs persisted before that was true may still carry them on
|
|
1023
|
-
* disk, and treating that stale key as a removed field would reject every
|
|
1024
|
-
* round-trip write until reboot reseeds the profile.
|
|
1025
|
-
* - Every other field is frozen: any changed, added, or removed key across
|
|
1026
|
-
* the union of both entries' keys (except `status` and the wire-only keys)
|
|
1027
|
-
* is rejected. A pre-existing on-disk override (e.g. `topP`) is preserved
|
|
1028
|
-
* but frozen — it passes the guard only while it doesn't change.
|
|
1029
|
-
*/
|
|
1030
|
-
function assertInvariantProfilesPreserved(
|
|
1031
|
-
oldRaw: Record<string, unknown>,
|
|
1032
|
-
newRaw: Record<string, unknown>,
|
|
1033
|
-
): void {
|
|
1034
|
-
const oldProfiles = asMutablePlainObject(
|
|
1035
|
-
asMutablePlainObject(oldRaw.llm)?.profiles,
|
|
1036
|
-
);
|
|
1037
|
-
if (!oldProfiles) {
|
|
1038
|
-
return;
|
|
1039
|
-
}
|
|
1040
|
-
const newProfiles = asMutablePlainObject(
|
|
1041
|
-
asMutablePlainObject(newRaw.llm)?.profiles,
|
|
1042
|
-
);
|
|
1043
|
-
|
|
1044
|
-
for (const name of INVARIANT_PROFILE_NAMES) {
|
|
1045
|
-
const oldEntry = asMutablePlainObject(oldProfiles[name]);
|
|
1046
|
-
if (!oldEntry) {
|
|
1047
|
-
continue;
|
|
1048
|
-
}
|
|
1049
|
-
if (oldEntry.source !== "managed") {
|
|
1050
|
-
continue;
|
|
1051
|
-
}
|
|
1052
|
-
|
|
1053
|
-
const newEntry = newProfiles
|
|
1054
|
-
? asMutablePlainObject(newProfiles[name])
|
|
1055
|
-
: null;
|
|
1056
|
-
if (!newEntry) {
|
|
1057
|
-
throw new BadRequestError(
|
|
1058
|
-
`Cannot delete or replace cloud profile "${name}". Cloud profiles are read-only.`,
|
|
1059
|
-
);
|
|
1060
|
-
}
|
|
1061
|
-
|
|
1062
|
-
if (!isDeepStrictEqual(oldEntry.status, newEntry.status)) {
|
|
1063
|
-
if (newEntry.status === "disabled") {
|
|
1064
|
-
throw new BadRequestError(`Cannot disable cloud profile "${name}".`);
|
|
1065
|
-
}
|
|
1066
|
-
if (newEntry.status !== "active" && newEntry.status != null) {
|
|
1067
|
-
throw new BadRequestError(
|
|
1068
|
-
`Cannot set status ${JSON.stringify(newEntry.status)} on cloud profile "${name}". ` +
|
|
1069
|
-
`Only re-enabling (status "active") is allowed.`,
|
|
1070
|
-
);
|
|
1071
|
-
}
|
|
1072
|
-
}
|
|
1073
|
-
|
|
1074
|
-
const changedKeys = [
|
|
1075
|
-
...new Set([...Object.keys(oldEntry), ...Object.keys(newEntry)]),
|
|
1076
|
-
].filter(
|
|
1077
|
-
(key) =>
|
|
1078
|
-
key !== "status" &&
|
|
1079
|
-
key !== "invariant" &&
|
|
1080
|
-
key !== "supportsVision" &&
|
|
1081
|
-
!isDeepStrictEqual(oldEntry[key], newEntry[key]),
|
|
1082
|
-
);
|
|
1083
|
-
if (changedKeys.length > 0) {
|
|
1084
|
-
throw new BadRequestError(
|
|
1085
|
-
`Cannot edit cloud profile "${name}" fields [${changedKeys.join(", ")}]. ` +
|
|
1086
|
-
`Cloud profiles are read-only; duplicate to a custom profile to customize.`,
|
|
1087
|
-
);
|
|
1088
|
-
}
|
|
1089
|
-
}
|
|
1090
|
-
}
|
|
1091
|
-
|
|
1092
|
-
/**
|
|
1093
|
-
* Custom profiles persist as complete overrides: any user-source, non-mix
|
|
1094
|
-
* profile entry this write creates or changes is completed against the
|
|
1095
|
-
* workspace default base (`completeCustomProfile`) before it lands on disk, so no
|
|
1096
|
-
* write path can persist a new partial profile. Entries the write did not
|
|
1097
|
-
* touch are left byte-identical — an unrelated config write must not rewrite
|
|
1098
|
-
* profile entries. Entries that do not parse as a `ProfileEntry` are also
|
|
1099
|
-
* left untouched; full-config parsing owns their rejection/recovery.
|
|
1100
|
-
*/
|
|
1101
|
-
function completeChangedCustomProfiles(
|
|
1102
|
-
preWrite: Record<string, unknown>,
|
|
1103
|
-
raw: Record<string, unknown>,
|
|
1104
|
-
): void {
|
|
1105
|
-
const llm = RawLlmWriteSliceSchema.safeParse(raw.llm);
|
|
1106
|
-
if (!llm.success || !llm.data.profiles) {
|
|
1107
|
-
return;
|
|
1108
|
-
}
|
|
1109
|
-
const profiles = llm.data.profiles;
|
|
1110
|
-
const parsedDefault = LLMConfigBase.safeParse(llm.data.default ?? {});
|
|
1111
|
-
if (!parsedDefault.success) {
|
|
1112
|
-
return;
|
|
1113
|
-
}
|
|
1114
|
-
const priorLlm = RawLlmWriteSliceSchema.safeParse(preWrite.llm);
|
|
1115
|
-
const prior = priorLlm.success ? (priorLlm.data.profiles ?? {}) : {};
|
|
1116
|
-
for (const [name, entry] of Object.entries(profiles)) {
|
|
1117
|
-
if (isDeepStrictEqual(entry, prior[name])) {
|
|
1118
|
-
continue;
|
|
1119
|
-
}
|
|
1120
|
-
const parsedEntry = ProfileEntry.safeParse(entry);
|
|
1121
|
-
if (!parsedEntry.success) {
|
|
1122
|
-
continue;
|
|
1123
|
-
}
|
|
1124
|
-
// `source: "managed"` is only meaningful on catalog-owned names. On any
|
|
1125
|
-
// other name it would skip completion (and read as a locked entry), so a
|
|
1126
|
-
// body claiming it is normalized to user-owned before completing.
|
|
1127
|
-
const entryData =
|
|
1128
|
-
parsedEntry.data.source === "managed" && !MANAGED_PROFILE_NAMES.has(name)
|
|
1129
|
-
? { ...parsedEntry.data, source: "user" as const }
|
|
1130
|
-
: parsedEntry.data;
|
|
1131
|
-
// Merge the completed known fields over the original raw entry at every
|
|
1132
|
-
// depth: `safeParse` strips keys the schema doesn't know (top-level and
|
|
1133
|
-
// inside nested objects like `contextWindow`), and dropping them here
|
|
1134
|
-
// would delete forward-compatible fields whenever the entry is edited.
|
|
1135
|
-
const entryRecord = RawProfileEntrySchema.safeParse(entry);
|
|
1136
|
-
if (!entryRecord.success) {
|
|
1137
|
-
continue;
|
|
1138
|
-
}
|
|
1139
|
-
profiles[name] = mergePreservingUnknownKeys(
|
|
1140
|
-
entryRecord.data,
|
|
1141
|
-
completeCustomProfile(parsedDefault.data, entryData) as Record<
|
|
1142
|
-
string,
|
|
1143
|
-
unknown
|
|
1144
|
-
>,
|
|
1145
|
-
);
|
|
1146
|
-
}
|
|
1147
|
-
// A zod parse copies — write the completed slice back so `raw` carries it.
|
|
1148
|
-
raw.llm = llm.data;
|
|
1149
|
-
}
|
|
1150
|
-
|
|
1151
|
-
/**
|
|
1152
|
-
* Persist a mutated raw config object to disk and synchronize the running
|
|
1153
|
-
* daemon (file-watcher, embedding cache, provider registry).
|
|
1154
|
-
*
|
|
1155
|
-
* Shared by `handlePatchConfig` and `handleSetConfig` so both write paths get
|
|
1156
|
-
* identical post-write side effects.
|
|
1157
|
-
*/
|
|
1158
|
-
/**
|
|
1159
|
-
* Reject writes that would store a routing-identity provider with a missing
|
|
1160
|
-
* or unroutable model (see `routingIdentityModelIssue`). saveRawConfig
|
|
1161
|
-
* persists without schema validation, so the parse-time rejection alone
|
|
1162
|
-
* would let the pair reach disk and be stripped on the next read — a silent
|
|
1163
|
-
* no-op where the user expects a saved override.
|
|
1164
|
-
*/
|
|
1165
|
-
function collectProviderEntries(
|
|
1166
|
-
raw: Record<string, unknown>,
|
|
1167
|
-
): [string, { provider?: unknown; model?: unknown }][] {
|
|
1168
|
-
const llm = raw.llm as
|
|
1169
|
-
| {
|
|
1170
|
-
default?: { provider?: unknown; model?: unknown } | null;
|
|
1171
|
-
profiles?: Record<
|
|
1172
|
-
string,
|
|
1173
|
-
{ provider?: unknown; model?: unknown } | null | undefined
|
|
1174
|
-
>;
|
|
1175
|
-
callSites?: Record<
|
|
1176
|
-
string,
|
|
1177
|
-
{ provider?: unknown; model?: unknown } | null | undefined
|
|
1178
|
-
>;
|
|
1179
|
-
}
|
|
1180
|
-
| undefined;
|
|
1181
|
-
const entries: [string, { provider?: unknown; model?: unknown }][] = [];
|
|
1182
|
-
// llm.default is a raw compatibility field outside the parsed schema;
|
|
1183
|
-
// profile materialization uses the on-disk blob as its fill base, so it is
|
|
1184
|
-
// checked like the schema-carried sections.
|
|
1185
|
-
if (llm?.default) {
|
|
1186
|
-
entries.push(["llm.default", llm.default]);
|
|
1187
|
-
}
|
|
1188
|
-
for (const section of ["profiles", "callSites"] as const) {
|
|
1189
|
-
for (const [name, entry] of Object.entries(llm?.[section] ?? {})) {
|
|
1190
|
-
if (entry) {
|
|
1191
|
-
entries.push([`llm.${section}.${name}`, entry]);
|
|
1192
|
-
}
|
|
1193
|
-
}
|
|
1194
|
-
}
|
|
1195
|
-
return entries;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
function assertRoutableIdentityEntries(
|
|
1199
|
-
preWrite: Record<string, unknown>,
|
|
1200
|
-
raw: Record<string, unknown>,
|
|
1201
|
-
): void {
|
|
1202
|
-
const entries = collectProviderEntries(raw);
|
|
1203
|
-
const priorProviders = new Map(
|
|
1204
|
-
collectProviderEntries(preWrite).flatMap(([label, entry]) =>
|
|
1205
|
-
typeof entry.provider === "string" ? [[label, entry.provider]] : [],
|
|
1206
|
-
),
|
|
1207
|
-
);
|
|
1208
|
-
for (const [label, entry] of entries) {
|
|
1209
|
-
if (typeof entry.provider !== "string") {
|
|
1210
|
-
continue;
|
|
1211
|
-
}
|
|
1212
|
-
// The provider schema is an open string (a stored value outside the
|
|
1213
|
-
// known set parses instead of stripping its profile), so write-time
|
|
1214
|
-
// membership is enforced here and at the profiles route. Scoped to
|
|
1215
|
-
// providers this write introduces or changes: a stored value outside
|
|
1216
|
-
// the known set is readable and dispatchable by design, and
|
|
1217
|
-
// re-validating it on every write would make all later settings saves
|
|
1218
|
-
// fail with no in-product repair path. Profiles accept entry names;
|
|
1219
|
-
// call-site fragments and the legacy default blob stay vendor-only
|
|
1220
|
-
// (overrides become model-only with the entries demolition).
|
|
1221
|
-
if (entry.provider !== priorProviders.get(label)) {
|
|
1222
|
-
const providerIssue = label.startsWith("llm.profiles.")
|
|
1223
|
-
? writableProfileProviderIssue(entry.provider)
|
|
1224
|
-
: unknownLlmProviderIssue(entry.provider);
|
|
1225
|
-
if (providerIssue) {
|
|
1226
|
-
throw new BadRequestError(`${providerIssue} (${label})`);
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
const issue = routingIdentityModelIssue(
|
|
1230
|
-
entry.provider,
|
|
1231
|
-
typeof entry.model === "string" ? entry.model : undefined,
|
|
1232
|
-
);
|
|
1233
|
-
if (issue) {
|
|
1234
|
-
throw new BadRequestError(`${issue} (${label})`);
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
}
|
|
1238
|
-
|
|
1239
|
-
/**
|
|
1240
|
-
* Reject writes that would persist unsupported `fallbackProfile` metadata.
|
|
1241
|
-
* Automatic fallbacks are code-owned for managed default profiles. The write
|
|
1242
|
-
* paths save raw config without a full-schema parse, so this check keeps a
|
|
1243
|
-
* custom pointer from reaching disk. It runs unconditionally so an existing
|
|
1244
|
-
* hand-edited pointer blocks unrelated rewrites until the user clears it with
|
|
1245
|
-
* `null`.
|
|
1246
|
-
*/
|
|
1247
|
-
function assertCodeOwnedFallbackProfiles(raw: Record<string, unknown>): void {
|
|
1248
|
-
const llm = RawLlmWriteSliceSchema.safeParse(raw.llm);
|
|
1249
|
-
if (!llm.success) {
|
|
1250
|
-
return;
|
|
1251
|
-
}
|
|
1252
|
-
// The sibling `llm.default` decides whether the cloud backups are valid
|
|
1253
|
-
// fallback targets: they resolve on the cloud column alone.
|
|
1254
|
-
const issues = collectFallbackProfileIssues(
|
|
1255
|
-
llm.data.profiles ?? undefined,
|
|
1256
|
-
llm.data.default,
|
|
1257
|
-
);
|
|
1258
|
-
if (issues.length > 0) {
|
|
1259
|
-
throw new BadRequestError(issues.map((issue) => issue.message).join(" "));
|
|
1260
|
-
}
|
|
1261
|
-
}
|
|
1262
|
-
|
|
1263
|
-
/**
|
|
1264
|
-
* Stamp the managed marker onto `llm.profiles` entries of catalog-owned
|
|
1265
|
-
* names that a write created without a `source` — a source-less entry reads
|
|
1266
|
-
* as a user shadow that blocks the catalog body. A user-owned entry sharing
|
|
1267
|
-
* the name (a legacy shadow) keeps its source, so its edits stay fully
|
|
1268
|
-
* user-owned.
|
|
1269
|
-
*/
|
|
1270
|
-
function stampManagedProfileEntries(
|
|
1271
|
-
preWrite: Record<string, unknown>,
|
|
1272
|
-
raw: Record<string, unknown>,
|
|
1273
|
-
): void {
|
|
1274
|
-
const newLlm = RawLlmWriteSliceSchema.safeParse(raw.llm);
|
|
1275
|
-
if (!newLlm.success || !newLlm.data.profiles) {
|
|
1276
|
-
return;
|
|
1277
|
-
}
|
|
1278
|
-
const oldLlm = RawLlmWriteSliceSchema.safeParse(preWrite.llm);
|
|
1279
|
-
let stamped = false;
|
|
1280
|
-
for (const name of MANAGED_PROFILE_NAMES) {
|
|
1281
|
-
const written = RawProfileEntrySchema.safeParse(newLlm.data.profiles[name]);
|
|
1282
|
-
if (!written.success || written.data.source !== undefined) {
|
|
1283
|
-
continue;
|
|
1284
|
-
}
|
|
1285
|
-
const prior = RawProfileEntrySchema.safeParse(
|
|
1286
|
-
oldLlm.success ? oldLlm.data.profiles?.[name] : undefined,
|
|
1287
|
-
);
|
|
1288
|
-
if (prior.success && prior.data.source !== "managed") {
|
|
1289
|
-
continue;
|
|
1290
|
-
}
|
|
1291
|
-
written.data.source = "managed";
|
|
1292
|
-
newLlm.data.profiles[name] = written.data;
|
|
1293
|
-
stamped = true;
|
|
1294
|
-
}
|
|
1295
|
-
if (stamped) {
|
|
1296
|
-
raw.llm = newLlm.data;
|
|
1297
|
-
}
|
|
1298
|
-
}
|
|
1299
|
-
|
|
1300
684
|
export async function commitConfigWrite(
|
|
1301
685
|
raw: Record<string, unknown>,
|
|
1302
686
|
opLabel: string,
|
|
@@ -1313,11 +697,6 @@ export async function commitConfigWrite(
|
|
|
1313
697
|
if (!chatSettings.success) {
|
|
1314
698
|
throw new BadRequestError(chatSettings.error.message);
|
|
1315
699
|
}
|
|
1316
|
-
stampManagedProfileEntries(preWrite, raw);
|
|
1317
|
-
completeChangedCustomProfiles(preWrite, raw);
|
|
1318
|
-
assertInvariantProfilesPreserved(preWrite, raw);
|
|
1319
|
-
assertRoutableIdentityEntries(preWrite, raw);
|
|
1320
|
-
assertCodeOwnedFallbackProfiles(raw);
|
|
1321
700
|
|
|
1322
701
|
// Suppress the file-watcher callback for the duration of the debounce
|
|
1323
702
|
// window. Without this, the ConfigWatcher detects the config.json write
|
|
@@ -1348,7 +727,7 @@ export async function commitConfigWrite(
|
|
|
1348
727
|
invalidateConfigCache();
|
|
1349
728
|
rescheduleHeartbeatIfTimezoneChanged(preWrite, raw);
|
|
1350
729
|
// Reinitialize providers so the live registry reflects the new config.
|
|
1351
|
-
// Suppress disk writes inside
|
|
730
|
+
// Suppress disk writes inside getConfig() — we just wrote the raw config
|
|
1352
731
|
// and the first-launch seed path would overwrite it with full defaults.
|
|
1353
732
|
try {
|
|
1354
733
|
await withSuppressedConfigDiskWrites(async () => {
|
|
@@ -1369,16 +748,24 @@ export async function commitConfigWrite(
|
|
|
1369
748
|
}
|
|
1370
749
|
|
|
1371
750
|
async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
1372
|
-
|
|
1373
|
-
|
|
751
|
+
// First-class body parse — the same schema the route spec declares — so a
|
|
752
|
+
// malformed subtree is rejected with path-qualified messages before any
|
|
753
|
+
// guard or merge runs.
|
|
754
|
+
const patch = ConfigPatchRequestSchema.safeParse(body);
|
|
755
|
+
if (!patch.success) {
|
|
756
|
+
throw new BadRequestError(
|
|
757
|
+
patch.error.issues
|
|
758
|
+
.map((issue) =>
|
|
759
|
+
issue.path.length > 0
|
|
760
|
+
? `${issue.path.join(".")}: ${issue.message}`
|
|
761
|
+
: issue.message,
|
|
762
|
+
)
|
|
763
|
+
.join("; "),
|
|
764
|
+
);
|
|
765
|
+
}
|
|
766
|
+
if (Object.keys(patch.data).length === 0) {
|
|
1374
767
|
throw new BadRequestError("Body must be a non-empty JSON object");
|
|
1375
768
|
}
|
|
1376
|
-
// Managed-profile normalization runs on the fragment before it merges:
|
|
1377
|
-
// an honest `config get` → PATCH round-trip reduces to a no-op, and a
|
|
1378
|
-
// genuine edit reaches the invariant guard's precise rejections.
|
|
1379
|
-
normalizeCloudProfileWrites(patch.data);
|
|
1380
|
-
rejectCloudProfileDeletion(patch.data);
|
|
1381
|
-
|
|
1382
769
|
// A patch is partial: merge it onto the current config so the schema
|
|
1383
770
|
// parse in `handleSetConfig` always sees a complete config — untouched
|
|
1384
771
|
// values ride, sparse fragments are completed by the merge base.
|
|
@@ -1399,7 +786,7 @@ async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
|
1399
786
|
|
|
1400
787
|
await handleSetConfig(merged);
|
|
1401
788
|
|
|
1402
|
-
return
|
|
789
|
+
return getConfig();
|
|
1403
790
|
}
|
|
1404
791
|
|
|
1405
792
|
/**
|
|
@@ -1442,20 +829,18 @@ async function handleSetConfig(merged: AssistantConfig): Promise<void> {
|
|
|
1442
829
|
* {@link handleSetConfig} write.
|
|
1443
830
|
*/
|
|
1444
831
|
async function handleSetConfigByKey({ body }: RouteHandlerArgs) {
|
|
1445
|
-
const parsedBody =
|
|
832
|
+
const parsedBody = ConfigSetByKeyBodySchema.safeParse(body);
|
|
1446
833
|
if (!parsedBody.success) {
|
|
1447
834
|
throw new BadRequestError(
|
|
1448
835
|
"Body must be a JSON object with `path` and `value`",
|
|
1449
836
|
);
|
|
1450
837
|
}
|
|
1451
838
|
const path = parsedBody.data.path;
|
|
1452
|
-
if (typeof path !== "string" || path.length === 0) {
|
|
1453
|
-
throw new BadRequestError("`path` must be a non-empty string");
|
|
1454
|
-
}
|
|
1455
839
|
// `value` must be present (use explicit `null` to clear a key). Without
|
|
1456
840
|
// this check, `undefined` flows into `setNestedValue` and gets dropped by
|
|
1457
841
|
// `JSON.stringify` at save time, silently removing the key - which is
|
|
1458
|
-
// distinct from the documented "set to null" semantics.
|
|
842
|
+
// distinct from the documented "set to null" semantics. zod cannot express
|
|
843
|
+
// "any value, but the key must exist", so this stays a domain check.
|
|
1459
844
|
if (!Object.hasOwn(parsedBody.data, "value")) {
|
|
1460
845
|
throw new BadRequestError(
|
|
1461
846
|
"`value` is required (use `null` to clear a key)",
|
|
@@ -1469,39 +854,7 @@ async function handleSetConfigByKey({ body }: RouteHandlerArgs) {
|
|
|
1469
854
|
if (path === "ingress.publicBaseUrl") {
|
|
1470
855
|
dropTunnelRecordsForNewUrl(merged.ingress, value);
|
|
1471
856
|
}
|
|
1472
|
-
|
|
1473
|
-
// use: `normalizeCloudProfileWrites` reduces an echo of the wire view to
|
|
1474
|
-
// the workspace-owned stub and rejects genuine edits to managed entries.
|
|
1475
|
-
// Its normalization lives in the parsed llm slice (a zod parse copies), so
|
|
1476
|
-
// the written value below is the normalized slice/entry — and a leaf write
|
|
1477
|
-
// below the entry level rides raw; the ladder stamps the managed marker
|
|
1478
|
-
// onto an entry the write creates.
|
|
1479
|
-
const pathSegments = path.split(".");
|
|
1480
|
-
let writtenValue: unknown = value;
|
|
1481
|
-
if (pathSegments[0] === "llm") {
|
|
1482
|
-
const patchShape: Record<string, unknown> = {};
|
|
1483
|
-
setNestedValue(patchShape, path, value);
|
|
1484
|
-
normalizeCloudProfileWrites(patchShape);
|
|
1485
|
-
rejectCloudProfileDeletion(patchShape);
|
|
1486
|
-
const patchLlm = RawLlmWriteSliceSchema.safeParse(patchShape.llm);
|
|
1487
|
-
if (patchLlm.success) {
|
|
1488
|
-
if (pathSegments.length === 1) {
|
|
1489
|
-
writtenValue = patchLlm.data;
|
|
1490
|
-
} else if (pathSegments[1] === "profiles") {
|
|
1491
|
-
if (pathSegments.length === 2) {
|
|
1492
|
-
if (patchLlm.data.profiles) {
|
|
1493
|
-
writtenValue = patchLlm.data.profiles;
|
|
1494
|
-
}
|
|
1495
|
-
} else if (pathSegments.length === 3) {
|
|
1496
|
-
const normalized = patchLlm.data.profiles?.[pathSegments[2]!];
|
|
1497
|
-
if (normalized !== undefined) {
|
|
1498
|
-
writtenValue = normalized;
|
|
1499
|
-
}
|
|
1500
|
-
}
|
|
1501
|
-
}
|
|
1502
|
-
}
|
|
1503
|
-
}
|
|
1504
|
-
setNestedValue(merged, path, writtenValue);
|
|
857
|
+
setNestedValue(merged, path, value);
|
|
1505
858
|
scrubNulledAcpAgentLeaves(merged);
|
|
1506
859
|
|
|
1507
860
|
await handleSetConfig(merged);
|
|
@@ -1568,14 +921,14 @@ async function handleReplaceInferenceProfile({
|
|
|
1568
921
|
throw new BadRequestError(`Invalid profile fragment: ${detail}`);
|
|
1569
922
|
}
|
|
1570
923
|
// A managed name with no existing entry stays protected so users can't
|
|
1571
|
-
// shadow a seeded cloud profile. An existing entry
|
|
1572
|
-
//
|
|
924
|
+
// shadow a seeded cloud profile. An existing entry on a non-`cadet`
|
|
925
|
+
// provider is user-owned and remains fully editable.
|
|
1573
926
|
const existingProfile = asMutablePlainObject(
|
|
1574
927
|
getConfig().llm.profiles?.[name],
|
|
1575
928
|
);
|
|
1576
929
|
const isCloud =
|
|
1577
930
|
MANAGED_PROFILE_NAMES.has(name) &&
|
|
1578
|
-
(existingProfile == null || existingProfile.
|
|
931
|
+
(existingProfile == null || existingProfile.provider === "cadet");
|
|
1579
932
|
if (CODE_OWNED_PROFILE_NAMES.has(name)) {
|
|
1580
933
|
// A code-owned profile resolves from the catalog whatever the workspace
|
|
1581
934
|
// holds, so even a status re-enable would persist a stub that never
|
|
@@ -1603,9 +956,8 @@ async function handleReplaceInferenceProfile({
|
|
|
1603
956
|
);
|
|
1604
957
|
}
|
|
1605
958
|
if (isCloud) {
|
|
1606
|
-
// Cloud profiles are daemon-seeded and read-only — the
|
|
1607
|
-
//
|
|
1608
|
-
// except re-enabling a disabled profile. Enforce the same contract up
|
|
959
|
+
// Cloud profiles are daemon-seeded and read-only — enforce the contract
|
|
960
|
+
// up front: the only body a cloud PUT accepts
|
|
1609
961
|
// front: the only body a cloud PUT accepts is a pure status re-enable
|
|
1610
962
|
// (`{status: "active"}`, or `{status: null}` to clear back to
|
|
1611
963
|
// active-by-absence). Rejecting here keeps the error message ahead of
|
|
@@ -1633,13 +985,7 @@ async function handleReplaceInferenceProfile({
|
|
|
1633
985
|
// here against the live profile set — otherwise an invalid mix would persist
|
|
1634
986
|
// and break the next full config reparse.
|
|
1635
987
|
if (parsed.data.mix != null) {
|
|
1636
|
-
const MIX_ALLOWED_KEYS = new Set([
|
|
1637
|
-
"mix",
|
|
1638
|
-
"label",
|
|
1639
|
-
"description",
|
|
1640
|
-
"status",
|
|
1641
|
-
"source",
|
|
1642
|
-
]);
|
|
988
|
+
const MIX_ALLOWED_KEYS = new Set(["mix", "label", "description", "status"]);
|
|
1643
989
|
const extraneous = Object.keys(parsed.data).filter(
|
|
1644
990
|
(k) => !MIX_ALLOWED_KEYS.has(k),
|
|
1645
991
|
);
|
|
@@ -1826,10 +1172,6 @@ function applyCloudProfileReenable(
|
|
|
1826
1172
|
const nextProfile: Record<string, unknown> = {
|
|
1827
1173
|
...(asMutablePlainObject(profiles[name]) ?? {}),
|
|
1828
1174
|
};
|
|
1829
|
-
// Only reached for managed-owned names (the route's managed gate), so a
|
|
1830
|
-
// freshly created stub must carry the cloud marker the effective view
|
|
1831
|
-
// and write guards key on.
|
|
1832
|
-
nextProfile.source = "managed";
|
|
1833
1175
|
if (status === null) {
|
|
1834
1176
|
delete nextProfile.status;
|
|
1835
1177
|
} else {
|
|
@@ -2194,7 +1536,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2194
1536
|
description: "Return the raw settings.json configuration object.",
|
|
2195
1537
|
tags: ["config"],
|
|
2196
1538
|
responseBody: ConfigGetResponseSchema,
|
|
2197
|
-
handler:
|
|
1539
|
+
handler: getConfig,
|
|
2198
1540
|
},
|
|
2199
1541
|
{
|
|
2200
1542
|
operationId: "config_patch",
|
|
@@ -2226,6 +1568,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2226
1568
|
"(preserves explicit null, replaces object subtrees instead of merging). " +
|
|
2227
1569
|
"Used by the `assistant config set <key> <value>` CLI command.",
|
|
2228
1570
|
tags: ["config"],
|
|
1571
|
+
requestBody: ConfigSetByKeyBodySchema,
|
|
2229
1572
|
handler: handleSetConfigByKey,
|
|
2230
1573
|
},
|
|
2231
1574
|
{
|