@mycadet/assistant 0.12.9 → 0.12.10
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/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 +48 -401
- 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 +22 -27
- 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 +59 -287
- 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 +60 -621
- 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,35 +33,24 @@ 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
56
|
routingIdentityModelIssue,
|
|
@@ -100,7 +87,6 @@ import {
|
|
|
100
87
|
log,
|
|
101
88
|
} from "../../daemon/handlers/shared.js";
|
|
102
89
|
import { rescheduleHeartbeatIfTimezoneChanged } from "../../heartbeat/heartbeat-service.js";
|
|
103
|
-
import { overlayWorkspaceMcpForConfigRead } from "../../mcp/workspace-mcp-config.js";
|
|
104
90
|
import {
|
|
105
91
|
getAssistantMessageIdsInTurn,
|
|
106
92
|
getConversation,
|
|
@@ -173,10 +159,7 @@ type LlmContextRouteResult = Omit<LlmContextNormalizationResult, "summary"> & {
|
|
|
173
159
|
import {
|
|
174
160
|
CODE_OWNED_PROFILE_NAMES,
|
|
175
161
|
getEffectiveProfilesForProvider,
|
|
176
|
-
getUserSelectableProfilesForProvider,
|
|
177
|
-
INVARIANT_PROFILE_NAMES,
|
|
178
162
|
MANAGED_PROFILE_NAMES,
|
|
179
|
-
resolveDefaultProfileForProvider,
|
|
180
163
|
} from "../../config/default-profile-catalog.js";
|
|
181
164
|
import { DEFAULT_PROFILE_KEYS } from "../../config/default-profile-names.js";
|
|
182
165
|
import { ACTOR_PRINCIPALS } from "../auth/route-policy.js";
|
|
@@ -523,22 +506,18 @@ async function handleSetEmbeddingConfig({ body }: RouteHandlerArgs) {
|
|
|
523
506
|
}
|
|
524
507
|
|
|
525
508
|
/**
|
|
526
|
-
*
|
|
527
|
-
*
|
|
528
|
-
*
|
|
529
|
-
*
|
|
530
|
-
*
|
|
531
|
-
* normalized slice back onto the caller's object instead of relying on
|
|
532
|
-
* shared references.
|
|
509
|
+
* The `config_set` body. `value` is `z.unknown()` — deliberately wider than
|
|
510
|
+
* an object shape — because the CLI contract writes scalar values and
|
|
511
|
+
* explicit `null`s (`set heartbeat.activeHoursStart null` clears a key), so
|
|
512
|
+
* the value is any JSON at all; only its PRESENCE is required, which zod
|
|
513
|
+
* cannot express on an unknown leaf, so the handler keeps that domain check.
|
|
533
514
|
*/
|
|
534
|
-
const
|
|
535
|
-
const RawProfileEntrySchema = z.record(z.string(), z.unknown());
|
|
536
|
-
const RawLlmWriteSliceSchema = z
|
|
515
|
+
const ConfigSetByKeyBodySchema = z
|
|
537
516
|
.object({
|
|
538
|
-
|
|
539
|
-
|
|
517
|
+
path: z.string().min(1),
|
|
518
|
+
value: z.unknown(),
|
|
540
519
|
})
|
|
541
|
-
.
|
|
520
|
+
.meta({ id: "ConfigSetByKeyRequest" });
|
|
542
521
|
|
|
543
522
|
/**
|
|
544
523
|
* Wire shape of the `memory` section in config responses. Passthrough
|
|
@@ -594,33 +573,28 @@ const CallSiteOverrideDraftSchema = nullablePartial(
|
|
|
594
573
|
* the generated SDK produces literal-union types — no hand-written patch
|
|
595
574
|
* types needed downstream.
|
|
596
575
|
*/
|
|
597
|
-
|
|
576
|
+
export type ConfigPatchRequest = z.infer<typeof ConfigPatchRequestSchema>;
|
|
577
|
+
|
|
578
|
+
export const ConfigPatchRequestSchema = z
|
|
598
579
|
.object({
|
|
599
580
|
...ChatSettingsPatchSchema.shape,
|
|
600
581
|
llm: z
|
|
601
582
|
.object({
|
|
602
|
-
default: nullablePartial(
|
|
603
|
-
LLMConfigFragment.extend({
|
|
604
|
-
provider_connection: z.string().optional(),
|
|
605
|
-
}),
|
|
606
|
-
)
|
|
583
|
+
default: nullablePartial(LLMDefaultConfigSchema)
|
|
607
584
|
.passthrough()
|
|
608
585
|
.nullable()
|
|
609
586
|
.optional(),
|
|
610
587
|
profiles: z
|
|
611
588
|
.record(z.string(), ProfilePatchEntrySchema.nullable())
|
|
589
|
+
.nullable()
|
|
612
590
|
.optional(),
|
|
613
|
-
profileOrder: z.array(z.string()).optional(),
|
|
614
|
-
activeProfile: z.string().nullable().optional(),
|
|
615
|
-
advisorProfile: z.string().nullable().optional(),
|
|
591
|
+
profileOrder: z.array(z.string().min(1)).optional(),
|
|
592
|
+
activeProfile: z.string().min(1).nullable().optional(),
|
|
593
|
+
advisorProfile: z.string().min(1).nullable().optional(),
|
|
616
594
|
callSites: z
|
|
617
595
|
.record(z.string(), CallSiteOverrideDraftSchema.nullable())
|
|
618
596
|
.optional(),
|
|
619
|
-
profileSession:
|
|
620
|
-
.object({
|
|
621
|
-
defaultTtlSeconds: z.number().optional(),
|
|
622
|
-
maxTtlSeconds: z.number().optional(),
|
|
623
|
-
})
|
|
597
|
+
profileSession: nullablePartial(LLMSchema.shape.profileSession.unwrap())
|
|
624
598
|
.nullable()
|
|
625
599
|
.optional(),
|
|
626
600
|
})
|
|
@@ -678,253 +652,6 @@ const ConfigGetResponseSchema = AssistantConfigSchema.pick({
|
|
|
678
652
|
services: true,
|
|
679
653
|
});
|
|
680
654
|
|
|
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
655
|
/**
|
|
929
656
|
* Return the JSON Schema for the assistant config (full or scoped).
|
|
930
657
|
*
|
|
@@ -957,204 +684,6 @@ function handleGetConfigSchema({ queryParams = {} }: RouteHandlerArgs) {
|
|
|
957
684
|
};
|
|
958
685
|
}
|
|
959
686
|
|
|
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
687
|
/**
|
|
1159
688
|
* Reject writes that would store a routing-identity provider with a missing
|
|
1160
689
|
* or unroutable model (see `routingIdentityModelIssue`). saveRawConfig
|
|
@@ -1226,6 +755,17 @@ function assertRoutableIdentityEntries(
|
|
|
1226
755
|
throw new BadRequestError(`${providerIssue} (${label})`);
|
|
1227
756
|
}
|
|
1228
757
|
}
|
|
758
|
+
// A model-less entry under a code-defined default name is the thin
|
|
759
|
+
// managed stub — its content is code-owned, so the routing-identity
|
|
760
|
+
// model check applies only to entries carrying their own body.
|
|
761
|
+
const profileName = label.startsWith("llm.profiles.")
|
|
762
|
+
? label.slice("llm.profiles.".length)
|
|
763
|
+
: undefined;
|
|
764
|
+
const isManagedName =
|
|
765
|
+
profileName != null && MANAGED_PROFILE_NAMES.has(profileName);
|
|
766
|
+
if (entry.model == null && isManagedName) {
|
|
767
|
+
continue;
|
|
768
|
+
}
|
|
1229
769
|
const issue = routingIdentityModelIssue(
|
|
1230
770
|
entry.provider,
|
|
1231
771
|
typeof entry.model === "string" ? entry.model : undefined,
|
|
@@ -1236,67 +776,6 @@ function assertRoutableIdentityEntries(
|
|
|
1236
776
|
}
|
|
1237
777
|
}
|
|
1238
778
|
|
|
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
779
|
export async function commitConfigWrite(
|
|
1301
780
|
raw: Record<string, unknown>,
|
|
1302
781
|
opLabel: string,
|
|
@@ -1313,11 +792,7 @@ export async function commitConfigWrite(
|
|
|
1313
792
|
if (!chatSettings.success) {
|
|
1314
793
|
throw new BadRequestError(chatSettings.error.message);
|
|
1315
794
|
}
|
|
1316
|
-
stampManagedProfileEntries(preWrite, raw);
|
|
1317
|
-
completeChangedCustomProfiles(preWrite, raw);
|
|
1318
|
-
assertInvariantProfilesPreserved(preWrite, raw);
|
|
1319
795
|
assertRoutableIdentityEntries(preWrite, raw);
|
|
1320
|
-
assertCodeOwnedFallbackProfiles(raw);
|
|
1321
796
|
|
|
1322
797
|
// Suppress the file-watcher callback for the duration of the debounce
|
|
1323
798
|
// window. Without this, the ConfigWatcher detects the config.json write
|
|
@@ -1348,7 +823,7 @@ export async function commitConfigWrite(
|
|
|
1348
823
|
invalidateConfigCache();
|
|
1349
824
|
rescheduleHeartbeatIfTimezoneChanged(preWrite, raw);
|
|
1350
825
|
// Reinitialize providers so the live registry reflects the new config.
|
|
1351
|
-
// Suppress disk writes inside
|
|
826
|
+
// Suppress disk writes inside getConfig() — we just wrote the raw config
|
|
1352
827
|
// and the first-launch seed path would overwrite it with full defaults.
|
|
1353
828
|
try {
|
|
1354
829
|
await withSuppressedConfigDiskWrites(async () => {
|
|
@@ -1369,16 +844,24 @@ export async function commitConfigWrite(
|
|
|
1369
844
|
}
|
|
1370
845
|
|
|
1371
846
|
async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
1372
|
-
|
|
1373
|
-
|
|
847
|
+
// First-class body parse — the same schema the route spec declares — so a
|
|
848
|
+
// malformed subtree is rejected with path-qualified messages before any
|
|
849
|
+
// guard or merge runs.
|
|
850
|
+
const patch = ConfigPatchRequestSchema.safeParse(body);
|
|
851
|
+
if (!patch.success) {
|
|
852
|
+
throw new BadRequestError(
|
|
853
|
+
patch.error.issues
|
|
854
|
+
.map((issue) =>
|
|
855
|
+
issue.path.length > 0
|
|
856
|
+
? `${issue.path.join(".")}: ${issue.message}`
|
|
857
|
+
: issue.message,
|
|
858
|
+
)
|
|
859
|
+
.join("; "),
|
|
860
|
+
);
|
|
861
|
+
}
|
|
862
|
+
if (Object.keys(patch.data).length === 0) {
|
|
1374
863
|
throw new BadRequestError("Body must be a non-empty JSON object");
|
|
1375
864
|
}
|
|
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
865
|
// A patch is partial: merge it onto the current config so the schema
|
|
1383
866
|
// parse in `handleSetConfig` always sees a complete config — untouched
|
|
1384
867
|
// values ride, sparse fragments are completed by the merge base.
|
|
@@ -1399,7 +882,7 @@ async function handlePatchConfig({ body }: RouteHandlerArgs) {
|
|
|
1399
882
|
|
|
1400
883
|
await handleSetConfig(merged);
|
|
1401
884
|
|
|
1402
|
-
return
|
|
885
|
+
return getConfig();
|
|
1403
886
|
}
|
|
1404
887
|
|
|
1405
888
|
/**
|
|
@@ -1442,20 +925,18 @@ async function handleSetConfig(merged: AssistantConfig): Promise<void> {
|
|
|
1442
925
|
* {@link handleSetConfig} write.
|
|
1443
926
|
*/
|
|
1444
927
|
async function handleSetConfigByKey({ body }: RouteHandlerArgs) {
|
|
1445
|
-
const parsedBody =
|
|
928
|
+
const parsedBody = ConfigSetByKeyBodySchema.safeParse(body);
|
|
1446
929
|
if (!parsedBody.success) {
|
|
1447
930
|
throw new BadRequestError(
|
|
1448
931
|
"Body must be a JSON object with `path` and `value`",
|
|
1449
932
|
);
|
|
1450
933
|
}
|
|
1451
934
|
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
935
|
// `value` must be present (use explicit `null` to clear a key). Without
|
|
1456
936
|
// this check, `undefined` flows into `setNestedValue` and gets dropped by
|
|
1457
937
|
// `JSON.stringify` at save time, silently removing the key - which is
|
|
1458
|
-
// distinct from the documented "set to null" semantics.
|
|
938
|
+
// distinct from the documented "set to null" semantics. zod cannot express
|
|
939
|
+
// "any value, but the key must exist", so this stays a domain check.
|
|
1459
940
|
if (!Object.hasOwn(parsedBody.data, "value")) {
|
|
1460
941
|
throw new BadRequestError(
|
|
1461
942
|
"`value` is required (use `null` to clear a key)",
|
|
@@ -1469,39 +950,7 @@ async function handleSetConfigByKey({ body }: RouteHandlerArgs) {
|
|
|
1469
950
|
if (path === "ingress.publicBaseUrl") {
|
|
1470
951
|
dropTunnelRecordsForNewUrl(merged.ingress, value);
|
|
1471
952
|
}
|
|
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);
|
|
953
|
+
setNestedValue(merged, path, value);
|
|
1505
954
|
scrubNulledAcpAgentLeaves(merged);
|
|
1506
955
|
|
|
1507
956
|
await handleSetConfig(merged);
|
|
@@ -1568,14 +1017,14 @@ async function handleReplaceInferenceProfile({
|
|
|
1568
1017
|
throw new BadRequestError(`Invalid profile fragment: ${detail}`);
|
|
1569
1018
|
}
|
|
1570
1019
|
// A managed name with no existing entry stays protected so users can't
|
|
1571
|
-
// shadow a seeded cloud profile. An existing entry
|
|
1572
|
-
//
|
|
1020
|
+
// shadow a seeded cloud profile. An existing entry on a non-`cadet`
|
|
1021
|
+
// provider is user-owned and remains fully editable.
|
|
1573
1022
|
const existingProfile = asMutablePlainObject(
|
|
1574
1023
|
getConfig().llm.profiles?.[name],
|
|
1575
1024
|
);
|
|
1576
1025
|
const isCloud =
|
|
1577
1026
|
MANAGED_PROFILE_NAMES.has(name) &&
|
|
1578
|
-
(existingProfile == null || existingProfile.
|
|
1027
|
+
(existingProfile == null || existingProfile.provider === "cadet");
|
|
1579
1028
|
if (CODE_OWNED_PROFILE_NAMES.has(name)) {
|
|
1580
1029
|
// A code-owned profile resolves from the catalog whatever the workspace
|
|
1581
1030
|
// holds, so even a status re-enable would persist a stub that never
|
|
@@ -1603,9 +1052,8 @@ async function handleReplaceInferenceProfile({
|
|
|
1603
1052
|
);
|
|
1604
1053
|
}
|
|
1605
1054
|
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
|
|
1055
|
+
// Cloud profiles are daemon-seeded and read-only — enforce the contract
|
|
1056
|
+
// up front: the only body a cloud PUT accepts
|
|
1609
1057
|
// front: the only body a cloud PUT accepts is a pure status re-enable
|
|
1610
1058
|
// (`{status: "active"}`, or `{status: null}` to clear back to
|
|
1611
1059
|
// active-by-absence). Rejecting here keeps the error message ahead of
|
|
@@ -1633,13 +1081,7 @@ async function handleReplaceInferenceProfile({
|
|
|
1633
1081
|
// here against the live profile set — otherwise an invalid mix would persist
|
|
1634
1082
|
// and break the next full config reparse.
|
|
1635
1083
|
if (parsed.data.mix != null) {
|
|
1636
|
-
const MIX_ALLOWED_KEYS = new Set([
|
|
1637
|
-
"mix",
|
|
1638
|
-
"label",
|
|
1639
|
-
"description",
|
|
1640
|
-
"status",
|
|
1641
|
-
"source",
|
|
1642
|
-
]);
|
|
1084
|
+
const MIX_ALLOWED_KEYS = new Set(["mix", "label", "description", "status"]);
|
|
1643
1085
|
const extraneous = Object.keys(parsed.data).filter(
|
|
1644
1086
|
(k) => !MIX_ALLOWED_KEYS.has(k),
|
|
1645
1087
|
);
|
|
@@ -1826,10 +1268,6 @@ function applyCloudProfileReenable(
|
|
|
1826
1268
|
const nextProfile: Record<string, unknown> = {
|
|
1827
1269
|
...(asMutablePlainObject(profiles[name]) ?? {}),
|
|
1828
1270
|
};
|
|
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
1271
|
if (status === null) {
|
|
1834
1272
|
delete nextProfile.status;
|
|
1835
1273
|
} else {
|
|
@@ -2194,7 +1632,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2194
1632
|
description: "Return the raw settings.json configuration object.",
|
|
2195
1633
|
tags: ["config"],
|
|
2196
1634
|
responseBody: ConfigGetResponseSchema,
|
|
2197
|
-
handler:
|
|
1635
|
+
handler: getConfig,
|
|
2198
1636
|
},
|
|
2199
1637
|
{
|
|
2200
1638
|
operationId: "config_patch",
|
|
@@ -2226,6 +1664,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
2226
1664
|
"(preserves explicit null, replaces object subtrees instead of merging). " +
|
|
2227
1665
|
"Used by the `assistant config set <key> <value>` CLI command.",
|
|
2228
1666
|
tags: ["config"],
|
|
1667
|
+
requestBody: ConfigSetByKeyBodySchema,
|
|
2229
1668
|
handler: handleSetConfigByKey,
|
|
2230
1669
|
},
|
|
2231
1670
|
{
|