@vellumai/assistant 0.6.4 → 0.6.5
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/.prettierignore +5 -0
- package/ARCHITECTURE.md +32 -36
- package/Dockerfile +12 -0
- package/README.md +3 -4
- package/bun.lock +8 -3
- package/docs/architecture/integrations.md +1 -20
- package/docs/architecture/security.md +16 -16
- package/docs/error-handling.md +111 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +2 -1
- package/knip.json +9 -2
- package/node_modules/@vellumai/ces-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
- package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
- package/node_modules/@vellumai/credential-storage/package.json +2 -2
- package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
- package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
- package/node_modules/@vellumai/egress-proxy/package.json +2 -2
- package/openapi.yaml +123 -11
- package/package.json +6 -3
- package/scripts/generate-openapi.ts +50 -11
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
- package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
- package/src/__tests__/agent-loop.test.ts +112 -1
- package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
- package/src/__tests__/anthropic-provider.test.ts +171 -2
- package/src/__tests__/approval-cascade.test.ts +31 -10
- package/src/__tests__/approval-routes-http.test.ts +134 -10
- package/src/__tests__/assistant-attachments.test.ts +44 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
- package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
- package/src/__tests__/browser-skill-endstate.test.ts +51 -182
- package/src/__tests__/btw-routes.test.ts +47 -1
- package/src/__tests__/call-controller.test.ts +1 -2
- package/src/__tests__/call-site-routing-provider.test.ts +214 -0
- package/src/__tests__/catalog-cache.test.ts +27 -4
- package/src/__tests__/channel-approval-routes.test.ts +4 -4
- package/src/__tests__/channel-reply-delivery.test.ts +300 -2
- package/src/__tests__/checker.test.ts +428 -501
- package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
- package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
- package/src/__tests__/compaction.benchmark.test.ts +1 -1
- package/src/__tests__/config-analysis.test.ts +11 -28
- package/src/__tests__/config-loader-backfill.test.ts +174 -0
- package/src/__tests__/config-loader-corrupt.test.ts +183 -0
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
- package/src/__tests__/config-schema-cmd.test.ts +11 -5
- package/src/__tests__/config-schema.test.ts +427 -114
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/contact-store-user-file.test.ts +72 -73
- package/src/__tests__/contacts-write.test.ts +4 -4
- package/src/__tests__/context-token-estimator.test.ts +191 -1
- package/src/__tests__/context-window-manager.test.ts +530 -2
- package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
- package/src/__tests__/conversation-agent-loop.test.ts +412 -82
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
- package/src/__tests__/conversation-error.test.ts +37 -6
- package/src/__tests__/conversation-history-web-search.test.ts +6 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
- package/src/__tests__/conversation-lifecycle.test.ts +336 -0
- package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
- package/src/__tests__/conversation-process-callsite.test.ts +306 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
- package/src/__tests__/conversation-queue.test.ts +41 -26
- package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
- package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
- package/src/__tests__/conversation-skill-tools.test.ts +12 -146
- package/src/__tests__/conversation-slash-queue.test.ts +34 -19
- package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
- package/src/__tests__/conversation-speed-override.test.ts +30 -11
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
- package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
- package/src/__tests__/conversation-title-service.test.ts +2 -2
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
- package/src/__tests__/conversation-unread-route.test.ts +2 -2
- package/src/__tests__/conversation-usage.test.ts +3 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
- package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
- package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
- package/src/__tests__/credential-security-invariants.test.ts +3 -0
- package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
- package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
- package/src/__tests__/credential-vault-unit.test.ts +135 -19
- package/src/__tests__/credentials-cli.test.ts +1 -9
- package/src/__tests__/cross-provider-web-search.test.ts +84 -0
- package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
- package/src/__tests__/delete-propagation.test.ts +437 -0
- package/src/__tests__/dm-backfill.test.ts +417 -0
- package/src/__tests__/dm-persistence.test.ts +227 -0
- package/src/__tests__/edit-propagation.test.ts +280 -0
- package/src/__tests__/ephemeral-permissions.test.ts +93 -3
- package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
- package/src/__tests__/estimator-calibration.test.ts +213 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
- package/src/__tests__/file-write-tool.test.ts +151 -1
- package/src/__tests__/filing-service.test.ts +255 -0
- package/src/__tests__/gemini-provider.test.ts +0 -3
- package/src/__tests__/guardian-grant-minting.test.ts +8 -0
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +96 -15
- package/src/__tests__/host-shell-tool.test.ts +124 -18
- package/src/__tests__/http-user-message-parity.test.ts +29 -1
- package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
- package/src/__tests__/intent-routing.test.ts +1 -40
- package/src/__tests__/llm-catalog-parity.test.ts +174 -0
- package/src/__tests__/llm-context-normalization.test.ts +121 -0
- package/src/__tests__/llm-resolver.test.ts +214 -0
- package/src/__tests__/llm-schema.test.ts +223 -0
- package/src/__tests__/managed-proxy-context.test.ts +6 -2
- package/src/__tests__/messaging-skill-split.test.ts +3 -34
- package/src/__tests__/migration-import-from-url.test.ts +684 -0
- package/src/__tests__/model-intents.test.ts +9 -83
- package/src/__tests__/notification-decision-fallback.test.ts +0 -10
- package/src/__tests__/notification-decision-identity.test.ts +0 -9
- package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
- package/src/__tests__/oauth-store.test.ts +10 -7
- package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
- package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
- package/src/__tests__/openai-provider.test.ts +7 -0
- package/src/__tests__/openai-responses-provider.test.ts +396 -0
- package/src/__tests__/openrouter-provider-only.test.ts +135 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
- package/src/__tests__/permission-mode.test.ts +16 -0
- package/src/__tests__/permission-types.test.ts +0 -1
- package/src/__tests__/persona-resolver.test.ts +13 -13
- package/src/__tests__/pkb-autoinject.test.ts +37 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +50 -3
- package/src/__tests__/profiler-routes.test.ts +1 -1
- package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
- package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
- package/src/__tests__/provider-error-scenarios.test.ts +135 -6
- package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
- package/src/__tests__/provider-registry-ollama.test.ts +1 -2
- package/src/__tests__/proxy-approval-callback.test.ts +0 -1
- package/src/__tests__/reaction-persistence.test.ts +560 -0
- package/src/__tests__/relay-server.test.ts +1 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
- package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
- package/src/__tests__/risk-classifier-parity.test.ts +230 -0
- package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
- package/src/__tests__/secret-ingress-http.test.ts +28 -0
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
- package/src/__tests__/secret-scanner-executor.test.ts +1 -1
- package/src/__tests__/send-endpoint-busy.test.ts +29 -1
- package/src/__tests__/server-history-render.test.ts +31 -0
- package/src/__tests__/shell-parser-property.test.ts +13 -13
- package/src/__tests__/skill-cache-store.test.ts +182 -0
- package/src/__tests__/skills.test.ts +19 -33
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
- package/src/__tests__/slack-skill.test.ts +3 -8
- package/src/__tests__/starter-bundle.test.ts +35 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
- package/src/__tests__/suggestion-routes.test.ts +160 -3
- package/src/__tests__/system-prompt.test.ts +22 -35
- package/src/__tests__/task-runner.test.ts +3 -1
- package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
- package/src/__tests__/thread-backfill.test.ts +941 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor.test.ts +60 -94
- package/src/__tests__/trust-store.test.ts +442 -109
- package/src/__tests__/update-bulletin-job.test.ts +389 -0
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
- package/src/__tests__/voice-session-bridge.test.ts +39 -0
- package/src/__tests__/volume-security-guard.test.ts +3 -2
- package/src/__tests__/web-search-history.test.ts +337 -0
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
- package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
- package/src/__tests__/workspace-policy.test.ts +1 -13
- package/src/acp/client-handler.ts +1 -2
- package/src/agent/loop.ts +209 -17
- package/src/avatar/resvg-lazy.test.ts +136 -0
- package/src/avatar/resvg-lazy.ts +82 -9
- package/src/avatar/traits-png-sync.ts +21 -1
- package/src/browser/__tests__/operations.test.ts +163 -0
- package/src/browser/identifiers.ts +51 -0
- package/src/browser/operations.ts +660 -0
- package/src/browser/types.ts +81 -0
- package/src/calls/guardian-question-copy.ts +2 -2
- package/src/calls/telephony-stt-routing.ts +1 -1
- package/src/calls/voice-session-bridge.ts +1 -0
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/commands/__tests__/attachment.test.ts +438 -0
- package/src/cli/commands/__tests__/browser.test.ts +554 -0
- package/src/cli/commands/__tests__/cache.test.ts +623 -0
- package/src/cli/commands/__tests__/email-list.test.ts +6 -0
- package/src/cli/commands/__tests__/email-send.test.ts +93 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
- package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
- package/src/cli/commands/__tests__/task.test.ts +913 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
- package/src/cli/commands/__tests__/ui.test.ts +1215 -0
- package/src/cli/commands/__tests__/watchers.test.ts +716 -0
- package/src/cli/commands/attachment.ts +182 -0
- package/src/cli/commands/browser.ts +350 -0
- package/src/cli/commands/cache.ts +341 -0
- package/src/cli/commands/completions.ts +0 -3
- package/src/cli/commands/config.ts +6 -6
- package/src/cli/commands/conversations-import.ts +347 -0
- package/src/cli/commands/conversations.ts +14 -1
- package/src/cli/commands/email.ts +234 -194
- package/src/cli/commands/image-generation.ts +300 -0
- package/src/cli/commands/inference.ts +200 -0
- package/src/cli/commands/memory.ts +127 -17
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
- package/src/cli/commands/stt.ts +339 -0
- package/src/cli/commands/task.ts +795 -0
- package/src/cli/commands/trust.ts +50 -19
- package/src/cli/commands/tts.ts +273 -0
- package/src/cli/commands/ui.ts +670 -0
- package/src/cli/commands/watchers.ts +509 -0
- package/src/cli/lib/daemon-credential-client.ts +0 -19
- package/src/cli/program.ts +23 -4
- package/src/cli.ts +0 -37
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
- package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +2 -2
- package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-tool-registry.ts +0 -175
- package/src/config/env.ts +7 -2
- package/src/config/feature-flag-registry.json +25 -9
- package/src/config/llm-resolver.ts +128 -0
- package/src/config/loader.ts +194 -10
- package/src/config/raw-config-utils.ts +30 -2
- package/src/config/sanitize-for-transfer.ts +35 -0
- package/src/config/schema.ts +30 -41
- package/src/config/schemas/analysis.ts +3 -22
- package/src/config/schemas/calls.ts +0 -4
- package/src/config/schemas/filing.ts +2 -7
- package/src/config/schemas/heartbeat.ts +0 -5
- package/src/config/schemas/inference.ts +3 -23
- package/src/config/schemas/llm.ts +318 -0
- package/src/config/schemas/memory-processing.ts +1 -9
- package/src/config/schemas/notifications.ts +4 -11
- package/src/config/schemas/platform.ts +3 -9
- package/src/config/schemas/security.ts +33 -0
- package/src/config/schemas/services.ts +9 -4
- package/src/config/schemas/stt.ts +1 -0
- package/src/config/schemas/tts.ts +53 -0
- package/src/config/schemas/updates.ts +1 -1
- package/src/config/schemas/workspace-git.ts +3 -40
- package/src/config/skills.ts +2 -2
- package/src/context/__tests__/compact-prompt.test.ts +45 -0
- package/src/context/__tests__/microcompact.test.ts +805 -0
- package/src/context/estimator-calibration.ts +136 -0
- package/src/context/microcompact.ts +443 -0
- package/src/context/prompts/compact.md +12 -0
- package/src/context/token-estimator.ts +61 -3
- package/src/context/window-manager.ts +229 -25
- package/src/credential-execution/approval-bridge.ts +0 -1
- package/src/credential-execution/executable-discovery.ts +19 -8
- package/src/credential-execution/process-manager.test.ts +109 -0
- package/src/credential-execution/process-manager.ts +65 -2
- package/src/daemon/approval-generators.ts +29 -4
- package/src/daemon/assistant-attachments.ts +24 -13
- package/src/daemon/classifier.ts +2 -2
- package/src/daemon/config-watcher.ts +0 -1
- package/src/daemon/context-overflow-reducer.ts +4 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
- package/src/daemon/conversation-agent-loop.ts +462 -80
- package/src/daemon/conversation-attachments.ts +2 -6
- package/src/daemon/conversation-error.ts +36 -1
- package/src/daemon/conversation-lifecycle.ts +30 -6
- package/src/daemon/conversation-messaging.ts +73 -4
- package/src/daemon/conversation-process.ts +10 -4
- package/src/daemon/conversation-queue-manager.ts +3 -0
- package/src/daemon/conversation-runtime-assembly.ts +760 -29
- package/src/daemon/conversation-slash.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +389 -1
- package/src/daemon/conversation-tool-setup.ts +10 -5
- package/src/daemon/conversation-usage.ts +1 -1
- package/src/daemon/conversation.ts +118 -30
- package/src/daemon/external-skills-bootstrap.ts +41 -0
- package/src/daemon/guardian-action-generators.ts +34 -14
- package/src/daemon/handlers/config-model.test.ts +86 -0
- package/src/daemon/handlers/config-model.ts +54 -12
- package/src/daemon/handlers/conversations.ts +9 -2
- package/src/daemon/handlers/shared.ts +39 -11
- package/src/daemon/handlers/skills.ts +2 -2
- package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
- package/src/daemon/lifecycle.ts +76 -14
- package/src/daemon/message-types/conversations.ts +14 -0
- package/src/daemon/message-types/messages.ts +9 -1
- package/src/daemon/message-types/trust.ts +0 -2
- package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
- package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
- package/src/daemon/pkb-context-tracker.test.ts +169 -0
- package/src/daemon/pkb-context-tracker.ts +125 -0
- package/src/daemon/pkb-reminder-builder.test.ts +70 -0
- package/src/daemon/pkb-reminder-builder.ts +31 -0
- package/src/daemon/providers-setup.ts +6 -0
- package/src/daemon/server.ts +117 -9
- package/src/daemon/tool-side-effects.ts +0 -9
- package/src/daemon/watch-handler.ts +4 -4
- package/src/daemon/web-search-history.ts +126 -0
- package/src/events/domain-events.ts +0 -1
- package/src/filing/filing-service.ts +9 -10
- package/src/heartbeat/heartbeat-service.ts +76 -28
- package/src/home/__tests__/feed-scheduler.test.ts +39 -11
- package/src/home/__tests__/rollup-producer.test.ts +44 -0
- package/src/home/assistant-feed-authoring.ts +4 -0
- package/src/home/emit-feed-event.ts +4 -0
- package/src/home/feed-scheduler.ts +20 -4
- package/src/home/feed-types.ts +56 -2
- package/src/home/relationship-state-writer.ts +2 -2
- package/src/home/rollup-producer.ts +34 -5
- package/src/home/suggested-prompts.ts +101 -0
- package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
- package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
- package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
- package/src/ipc/__tests__/socket-path.test.ts +73 -0
- package/src/ipc/__tests__/task-ipc.test.ts +577 -0
- package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
- package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
- package/src/ipc/cli-client.ts +2 -1
- package/src/ipc/cli-server.ts +26 -8
- package/src/ipc/gateway-client.ts +4 -4
- package/src/ipc/routes/attachment.ts +114 -0
- package/src/ipc/routes/browser-context.ts +61 -0
- package/src/ipc/routes/browser.ts +96 -0
- package/src/ipc/routes/cache.ts +96 -0
- package/src/ipc/routes/index.ts +17 -1
- package/src/ipc/routes/task-queue.ts +226 -0
- package/src/ipc/routes/task.ts +173 -0
- package/src/ipc/routes/ui-request.ts +50 -0
- package/src/ipc/routes/watcher.ts +203 -0
- package/src/ipc/socket-path.ts +100 -0
- package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
- package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
- package/src/memory/admin.ts +18 -0
- package/src/memory/conversation-analyze-job.ts +14 -13
- package/src/memory/conversation-attention-store.ts +13 -6
- package/src/memory/conversation-crud.ts +103 -3
- package/src/memory/conversation-group-migration.ts +38 -6
- package/src/memory/conversation-title-service.ts +7 -4
- package/src/memory/db-init.ts +2 -0
- package/src/memory/embedding-backend.ts +1 -1
- package/src/memory/graph/compaction.ts +299 -0
- package/src/memory/graph/consolidation.ts +4 -4
- package/src/memory/graph/conversation-graph-memory.ts +89 -29
- package/src/memory/graph/extraction.test.ts +272 -2
- package/src/memory/graph/extraction.ts +173 -51
- package/src/memory/graph/graph-search.test.ts +92 -0
- package/src/memory/graph/graph-search.ts +4 -1
- package/src/memory/graph/narrative.ts +2 -2
- package/src/memory/graph/pattern-scan.ts +2 -2
- package/src/memory/graph/retriever.test.ts +459 -0
- package/src/memory/graph/retriever.ts +230 -48
- package/src/memory/graph/store.ts +41 -0
- package/src/memory/graph/tool-handlers.ts +27 -0
- package/src/memory/graph/tools.ts +6 -1
- package/src/memory/indexer.ts +5 -5
- package/src/memory/job-handlers/conversation-starters.ts +23 -20
- package/src/memory/job-handlers/summarization.ts +2 -2
- package/src/memory/job-utils.ts +7 -1
- package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
- package/src/memory/jobs/embed-pkb-file.ts +54 -0
- package/src/memory/jobs-store.ts +44 -3
- package/src/memory/jobs-worker.ts +4 -0
- package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
- package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
- package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
- package/src/memory/migrations/index.ts +1 -0
- package/src/memory/pkb/pkb-index.test.ts +368 -0
- package/src/memory/pkb/pkb-index.ts +255 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
- package/src/memory/pkb/pkb-reconcile.ts +148 -0
- package/src/memory/pkb/pkb-search.test.ts +438 -0
- package/src/memory/pkb/pkb-search.ts +137 -0
- package/src/memory/pkb/types.ts +53 -0
- package/src/memory/qdrant-client.ts +122 -1
- package/src/memory/slack-thread-store.ts +37 -0
- package/src/messaging/providers/gmail/adapter.ts +6 -16
- package/src/messaging/providers/gmail/client.ts +22 -0
- package/src/messaging/providers/gmail/types.ts +7 -0
- package/src/messaging/providers/slack/adapter.ts +14 -2
- package/src/messaging/providers/slack/backfill.test.ts +257 -0
- package/src/messaging/providers/slack/backfill.ts +101 -0
- package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
- package/src/messaging/providers/slack/message-metadata.ts +123 -0
- package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
- package/src/messaging/providers/slack/render-transcript.ts +443 -0
- package/src/messaging/style-analyzer.ts +5 -2
- package/src/notifications/README.md +9 -5
- package/src/notifications/decision-engine.ts +3 -9
- package/src/notifications/preference-extractor.ts +2 -6
- package/src/oauth/oauth-store.ts +1 -0
- package/src/oauth/platform-connection.test.ts +47 -0
- package/src/oauth/platform-connection.ts +15 -5
- package/src/oauth/seed-providers.ts +4 -2
- package/src/permissions/approval-policy.test.ts +948 -0
- package/src/permissions/approval-policy.ts +257 -0
- package/src/permissions/bash-risk-classifier.test.ts +1208 -0
- package/src/permissions/bash-risk-classifier.ts +707 -0
- package/src/permissions/checker.ts +217 -708
- package/src/permissions/command-registry.test.ts +535 -0
- package/src/permissions/command-registry.ts +825 -0
- package/src/permissions/defaults.ts +26 -78
- package/src/permissions/file-risk-classifier.test.ts +535 -0
- package/src/permissions/file-risk-classifier.ts +274 -0
- package/src/permissions/risk-types.ts +205 -0
- package/src/permissions/secret-prompter.ts +53 -2
- package/src/permissions/skill-risk-classifier.test.ts +311 -0
- package/src/permissions/skill-risk-classifier.ts +214 -0
- package/src/permissions/trust-client.ts +52 -25
- package/src/permissions/trust-store-interface.ts +1 -6
- package/src/permissions/trust-store.ts +161 -62
- package/src/permissions/types.ts +23 -14
- package/src/permissions/web-risk-classifier.test.ts +170 -0
- package/src/permissions/web-risk-classifier.ts +89 -0
- package/src/permissions/workspace-policy.ts +1 -16
- package/src/platform/client.ts +19 -1
- package/src/prompts/persona-resolver.ts +3 -3
- package/src/prompts/system-prompt.ts +19 -20
- package/src/prompts/templates/SOUL.md +2 -2
- package/src/prompts/update-bulletin-job.ts +190 -0
- package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
- package/src/providers/__tests__/retry-callsite.test.ts +424 -0
- package/src/providers/anthropic/client.ts +183 -14
- package/src/providers/call-site-routing.ts +71 -0
- package/src/providers/gemini/client.ts +65 -2
- package/src/providers/managed-proxy/constants.ts +2 -1
- package/src/providers/model-catalog.ts +501 -33
- package/src/providers/model-intents.ts +4 -4
- package/src/providers/openai/chat-completions-provider.ts +57 -1
- package/src/providers/openai/responses-provider.ts +86 -9
- package/src/providers/openrouter/client.ts +76 -9
- package/src/providers/provider-env-vars.ts +56 -0
- package/src/providers/provider-send-message.ts +22 -5
- package/src/providers/ratelimit.ts +4 -0
- package/src/providers/registry.ts +19 -8
- package/src/providers/retry.ts +174 -39
- package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
- package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
- package/src/providers/speech-to-text/provider-catalog.ts +17 -0
- package/src/providers/speech-to-text/resolve.ts +7 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
- package/src/providers/speech-to-text/xai-realtime.ts +796 -0
- package/src/providers/speech-to-text/xai.test.ts +155 -0
- package/src/providers/speech-to-text/xai.ts +97 -0
- package/src/providers/types.ts +93 -3
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/__tests__/agent-wake.test.ts +43 -2
- package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
- package/src/runtime/agent-wake.ts +63 -22
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/btw-sidechain.ts +13 -3
- package/src/runtime/channel-reply-delivery.ts +106 -2
- package/src/runtime/decision-token.ts +116 -0
- package/src/runtime/gateway-client.ts +2 -2
- package/src/runtime/http-router.ts +32 -0
- package/src/runtime/http-server.ts +52 -1
- package/src/runtime/http-types.ts +23 -1
- package/src/runtime/interactive-ui.ts +362 -0
- package/src/runtime/invite-instruction-generator.ts +2 -2
- package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
- package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
- package/src/runtime/migrations/gcs-signed-url.ts +162 -0
- package/src/runtime/migrations/vbundle-importer.ts +154 -9
- package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
- package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
- package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
- package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
- package/src/runtime/migrations/vbundle-validator.ts +15 -6
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
- package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
- package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
- package/src/runtime/routes/approval-routes.ts +12 -17
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
- package/src/runtime/routes/avatar-routes.ts +20 -4
- package/src/runtime/routes/btw-routes.ts +1 -4
- package/src/runtime/routes/conversation-management-routes.ts +20 -2
- package/src/runtime/routes/conversation-routes.ts +133 -27
- package/src/runtime/routes/debug-routes.ts +1 -1
- package/src/runtime/routes/diagnostics-routes.ts +6 -4
- package/src/runtime/routes/events-routes.ts +16 -0
- package/src/runtime/routes/guardian-approval-interception.ts +33 -3
- package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
- package/src/runtime/routes/home-feed-routes.ts +120 -2
- package/src/runtime/routes/inbound-message-handler.ts +912 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
- package/src/runtime/routes/integrations/slack/channel.ts +25 -3
- package/src/runtime/routes/llm-context-normalization.ts +23 -1
- package/src/runtime/routes/migration-routes.ts +720 -124
- package/src/runtime/routes/settings-routes.ts +4 -2
- package/src/runtime/routes/trust-rules-routes.ts +30 -14
- package/src/runtime/routes/work-items-routes.test.ts +1 -1
- package/src/runtime/routes/work-items-routes.ts +3 -2
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
- package/src/runtime/services/analyze-conversation.ts +12 -16
- package/src/runtime/skill-route-registry.ts +28 -6
- package/src/schedule/scheduler.ts +8 -0
- package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
- package/src/security/__tests__/untrusted-content.test.ts +109 -0
- package/src/security/oauth2.ts +98 -35
- package/src/security/secure-keys.ts +7 -8
- package/src/security/token-manager.ts +27 -13
- package/src/security/untrusted-content.ts +102 -0
- package/src/skills/catalog-cache.ts +26 -7
- package/src/skills/catalog-install.ts +31 -3
- package/src/skills/skill-cache-store.ts +97 -0
- package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
- package/src/stt/daemon-batch-transcriber.ts +33 -0
- package/src/stt/stt-stream-session.ts +8 -1
- package/src/stt/types.ts +5 -1
- package/src/subagent/manager.ts +41 -13
- package/src/tasks/ephemeral-permissions.ts +9 -4
- package/src/telemetry/usage-telemetry-reporter.ts +27 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
- package/src/tools/browser/browser-execution.ts +65 -38
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
- package/src/tools/credentials/tool-policy.ts +39 -5
- package/src/tools/credentials/vault.ts +9 -4
- package/src/tools/executor.ts +4 -0
- package/src/tools/filesystem/write.ts +52 -0
- package/src/tools/host-terminal/host-shell.ts +45 -5
- package/src/tools/memory/register.test.ts +185 -0
- package/src/tools/memory/register.ts +3 -1
- package/src/tools/network/web-fetch.ts +20 -10
- package/src/tools/network/web-search.ts +19 -4
- package/src/tools/permission-checker.ts +36 -15
- package/src/tools/policy-context.ts +25 -8
- package/src/tools/registry.ts +55 -3
- package/src/tools/side-effects.ts +0 -11
- package/src/tools/skills/execute.ts +2 -2
- package/src/tools/skills/sandbox-runner.ts +5 -2
- package/src/tools/terminal/backends/native.ts +51 -2
- package/src/tools/terminal/safe-env.ts +3 -2
- package/src/tools/terminal/shell.ts +1 -0
- package/src/tools/tool-manifest.ts +6 -21
- package/src/tools/types.ts +12 -3
- package/src/tools/verification-control-plane-policy.ts +1 -1
- package/src/tts/__tests__/provider-adapters.test.ts +240 -13
- package/src/tts/provider-catalog.ts +18 -0
- package/src/tts/providers/index.ts +2 -0
- package/src/tts/providers/xai-provider.ts +224 -0
- package/src/tts/types.ts +46 -0
- package/src/types/tar-stream.d.ts +66 -0
- package/src/util/json.ts +17 -0
- package/src/util/platform.ts +2 -2
- package/src/util/pricing.ts +15 -5
- package/src/watcher/engine.ts +1 -1
- package/src/watcher/providers/google-calendar.ts +134 -8
- package/src/watcher/providers/outlook-calendar.ts +42 -2
- package/src/workspace/git-service.ts +23 -4
- package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
- package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
- package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
- package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
- package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/registry.ts +16 -0
- package/src/workspace/provider-commit-message-generator.ts +19 -38
- package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
- package/src/__tests__/gmail-archive-gate.test.ts +0 -246
- package/src/__tests__/gmail-preferences.test.ts +0 -117
- package/src/__tests__/outlook-attachments.test.ts +0 -301
- package/src/__tests__/outlook-automation-tools.test.ts +0 -425
- package/src/__tests__/outlook-categories.test.ts +0 -212
- package/src/__tests__/outlook-compose-tools.test.ts +0 -325
- package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
- package/src/__tests__/outlook-follow-up.test.ts +0 -196
- package/src/__tests__/outlook-trash.test.ts +0 -77
- package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
- package/src/__tests__/update-bulletin-format.test.ts +0 -181
- package/src/__tests__/update-bulletin-state.test.ts +0 -135
- package/src/__tests__/update-bulletin.test.ts +0 -478
- package/src/__tests__/update-template-contract.test.ts +0 -29
- package/src/cli/commands/doctor.ts +0 -341
- package/src/config/bundled-skills/browser/SKILL.md +0 -88
- package/src/config/bundled-skills/browser/TOOLS.json +0 -516
- package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
- package/src/config/bundled-skills/gmail/SKILL.md +0 -221
- package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
- package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
- package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
- package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
- package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/google-calendar/types.ts +0 -97
- package/src/config/bundled-skills/outlook/SKILL.md +0 -196
- package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
- package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
- package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
- package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
- package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
- package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
- package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
- package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
- package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
- package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
- package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
- package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
- package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
- package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
- package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
- package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
- package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
- package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
- package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
- package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
- package/src/config/bundled-skills/slack/SKILL.md +0 -108
- package/src/config/bundled-skills/tasks/SKILL.md +0 -37
- package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
- package/src/config/bundled-skills/tasks/icon.svg +0 -34
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
- package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
- package/src/config/bundled-skills/watcher/SKILL.md +0 -31
- package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
- package/src/prompts/templates/UPDATES.md +0 -50
- package/src/prompts/update-bulletin-format.ts +0 -85
- package/src/prompts/update-bulletin-state.ts +0 -58
- package/src/prompts/update-bulletin-template-path.ts +0 -13
- package/src/prompts/update-bulletin.ts +0 -139
- package/src/shared/provider-env-vars.ts +0 -19
- package/src/tools/watcher/create.ts +0 -86
- package/src/tools/watcher/delete.ts +0 -36
- package/src/tools/watcher/digest.ts +0 -54
- package/src/tools/watcher/list.ts +0 -83
- package/src/tools/watcher/update.ts +0 -71
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
type LLMCallSite,
|
|
5
|
+
LLMConfigBase,
|
|
6
|
+
type LLMConfigFragment,
|
|
7
|
+
type LLMSchema,
|
|
8
|
+
} from "./schemas/llm.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Resolves a fully-specified `LLMConfigBase` for a given call site by layering
|
|
12
|
+
* the call-site override on top of an optional named profile on top of the
|
|
13
|
+
* required `llm.default`.
|
|
14
|
+
*
|
|
15
|
+
* Resolution order (highest precedence wins):
|
|
16
|
+
* 1. `llm.callSites[callSite]` fields (call-site override)
|
|
17
|
+
* 2. `llm.profiles[site.profile]` fields (named profile)
|
|
18
|
+
* 3. `llm.default` fields (required base)
|
|
19
|
+
*
|
|
20
|
+
* Nested objects (`thinking`, `contextWindow`, and
|
|
21
|
+
* `contextWindow.overflowRecovery`) are deep-merged so partial overrides at
|
|
22
|
+
* any nesting level merge into — rather than replace — the corresponding
|
|
23
|
+
* base value.
|
|
24
|
+
*
|
|
25
|
+
* Pure & synchronous: no I/O, no async work.
|
|
26
|
+
*/
|
|
27
|
+
export function resolveCallSiteConfig(
|
|
28
|
+
callSite: LLMCallSite,
|
|
29
|
+
llm: z.infer<typeof LLMSchema>,
|
|
30
|
+
): z.infer<typeof LLMConfigBase> {
|
|
31
|
+
const site = llm.callSites?.[callSite];
|
|
32
|
+
|
|
33
|
+
// No site-level entry: deep-merge `default` against an empty fragment so
|
|
34
|
+
// every code path goes through the same merge codepath.
|
|
35
|
+
if (site == null) {
|
|
36
|
+
return finalize(deepMerge(llm.default as Mergeable, {} as Mergeable));
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
let profileFragment: LLMConfigFragment | undefined;
|
|
40
|
+
if (site.profile != null) {
|
|
41
|
+
profileFragment = llm.profiles?.[site.profile];
|
|
42
|
+
if (profileFragment == null) {
|
|
43
|
+
// Defensive: `LLMSchema.superRefine` already rejects unknown profile
|
|
44
|
+
// references at config load, so this branch is unreachable for any
|
|
45
|
+
// config that survived schema validation. Throw a clear error in case
|
|
46
|
+
// a hand-crafted (un-parsed) config slips through.
|
|
47
|
+
throw new Error(
|
|
48
|
+
`LLM call site "${callSite}" references undefined profile "${site.profile}"`,
|
|
49
|
+
);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Strip the `profile` discriminator before merging — it isn't a
|
|
54
|
+
// `LLMConfigBase` field.
|
|
55
|
+
const { profile: _profile, ...siteFragment } = site;
|
|
56
|
+
|
|
57
|
+
const merged = deepMerge(
|
|
58
|
+
llm.default as Mergeable,
|
|
59
|
+
(profileFragment ?? {}) as Mergeable,
|
|
60
|
+
siteFragment as Mergeable,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return finalize(merged);
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// ---------------------------------------------------------------------------
|
|
67
|
+
// Internal helpers
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
|
|
70
|
+
type Mergeable = Record<string, unknown>;
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Returns true for objects we should recurse into during deep merge. We
|
|
74
|
+
* deliberately exclude arrays so that array-valued fields (e.g.
|
|
75
|
+
* `pricingOverrides` siblings) get full replacement semantics.
|
|
76
|
+
*/
|
|
77
|
+
function isPlainObject(value: unknown): value is Mergeable {
|
|
78
|
+
return (
|
|
79
|
+
typeof value === "object" &&
|
|
80
|
+
value !== null &&
|
|
81
|
+
!Array.isArray(value) &&
|
|
82
|
+
Object.getPrototypeOf(value) === Object.prototype
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Deep-merges a sequence of fragments where each rightward source overrides
|
|
88
|
+
* the previous. For nested plain objects, recurse so partial overrides merge
|
|
89
|
+
* leaf-by-leaf rather than wholesale-replacing the nested object.
|
|
90
|
+
*
|
|
91
|
+
* `undefined` values in a source are skipped (treated as "no opinion"); this
|
|
92
|
+
* matches Zod fragment semantics where unset optional fields are absent.
|
|
93
|
+
*
|
|
94
|
+
* Plain-object values are always cloned (via recursion) rather than aliased,
|
|
95
|
+
* so the returned config is an isolated snapshot — mutating any nested object
|
|
96
|
+
* on the result cannot affect `llm.default`, named profiles, or other call
|
|
97
|
+
* sites' resolutions. Arrays and primitives are copied by reference; the
|
|
98
|
+
* resolver does not return arrays, and primitives are immutable.
|
|
99
|
+
*/
|
|
100
|
+
function deepMerge(...sources: Mergeable[]): Mergeable {
|
|
101
|
+
const out: Mergeable = {};
|
|
102
|
+
for (const source of sources) {
|
|
103
|
+
for (const [key, value] of Object.entries(source)) {
|
|
104
|
+
if (value === undefined) continue;
|
|
105
|
+
const existing = out[key];
|
|
106
|
+
if (isPlainObject(value)) {
|
|
107
|
+
// Recurse for any plain-object source. Using `existing` as the base
|
|
108
|
+
// when it's also a plain object preserves leaf-by-leaf merge
|
|
109
|
+
// semantics; otherwise we recurse against an empty object so the
|
|
110
|
+
// result is a freshly-allocated clone rather than an alias.
|
|
111
|
+
const base = isPlainObject(existing) ? existing : ({} as Mergeable);
|
|
112
|
+
out[key] = deepMerge(base, value);
|
|
113
|
+
} else {
|
|
114
|
+
out[key] = value;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
return out;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Cast helper that documents the intent: after merging `llm.default` (which
|
|
123
|
+
* is `LLMConfigBase`) with optional fragments, every required field is still
|
|
124
|
+
* present, so the result satisfies `LLMConfigBase`.
|
|
125
|
+
*/
|
|
126
|
+
function finalize(merged: Mergeable): z.infer<typeof LLMConfigBase> {
|
|
127
|
+
return merged as unknown as z.infer<typeof LLMConfigBase>;
|
|
128
|
+
}
|
package/src/config/loader.ts
CHANGED
|
@@ -6,11 +6,14 @@ import {
|
|
|
6
6
|
statSync,
|
|
7
7
|
writeFileSync,
|
|
8
8
|
} from "node:fs";
|
|
9
|
-
import { dirname, join } from "node:path";
|
|
9
|
+
import { basename, dirname, join } from "node:path";
|
|
10
10
|
|
|
11
|
-
import { ConfigError } from "../util/errors.js";
|
|
12
11
|
import { getLogger } from "../util/logger.js";
|
|
13
|
-
import {
|
|
12
|
+
import {
|
|
13
|
+
ensureDataDir,
|
|
14
|
+
getWorkspaceConfigPath,
|
|
15
|
+
getWorkspaceDir,
|
|
16
|
+
} from "../util/platform.js";
|
|
14
17
|
import { isAssistantFeatureFlagEnabled } from "./assistant-feature-flags.js";
|
|
15
18
|
import { AssistantConfigSchema } from "./schema.js";
|
|
16
19
|
import type { AssistantConfig } from "./types.js";
|
|
@@ -47,6 +50,116 @@ function cloneDefaultConfig(): AssistantConfig {
|
|
|
47
50
|
return applyNestedDefaults({});
|
|
48
51
|
}
|
|
49
52
|
|
|
53
|
+
/**
|
|
54
|
+
* Build a filesystem-safe ISO-8601 timestamp for use in quarantine filenames.
|
|
55
|
+
* Replaces `:` (invalid on Windows, confusing on macOS Finder) with `-` so the
|
|
56
|
+
* resulting string is safe on every supported platform.
|
|
57
|
+
*/
|
|
58
|
+
function filesystemSafeTimestamp(date: Date = new Date()): string {
|
|
59
|
+
return date.toISOString().replace(/:/g, "-");
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* Rename a corrupt config file to a quarantine path so the bad content is
|
|
64
|
+
* preserved for debug while the daemon falls through to defaults. Logs at
|
|
65
|
+
* `error` level with a remediation hint. Best-effort: if the rename itself
|
|
66
|
+
* fails (missing permissions, readonly FS, etc.) we still fall through to
|
|
67
|
+
* defaults — startup must never block.
|
|
68
|
+
*
|
|
69
|
+
* The quarantine filename encodes a millisecond-precision timestamp and ends
|
|
70
|
+
* in `.json` so editors syntax-highlight the preserved content:
|
|
71
|
+
* `<path>.corrupt-<ISO-timestamp>.json`
|
|
72
|
+
*
|
|
73
|
+
* On a successful rename, also appends a bulletin to `<workspace>/UPDATES.md`
|
|
74
|
+
* so the background update-bulletin job surfaces the event to the user
|
|
75
|
+
* proactively on their next interaction (log-level errors alone are invisible
|
|
76
|
+
* to users).
|
|
77
|
+
*/
|
|
78
|
+
function quarantineCorruptConfig(configPath: string, err: unknown): string {
|
|
79
|
+
const quarantinePath = `${configPath}.corrupt-${filesystemSafeTimestamp()}.json`;
|
|
80
|
+
try {
|
|
81
|
+
renameSync(configPath, quarantinePath);
|
|
82
|
+
log.error(
|
|
83
|
+
`config file at ${configPath} was corrupt (${String(err)}); ` +
|
|
84
|
+
`quarantined to ${quarantinePath} and loaded defaults. ` +
|
|
85
|
+
`Inspect the quarantined file to recover any hand-edited settings.`,
|
|
86
|
+
);
|
|
87
|
+
appendQuarantineBulletin(configPath, quarantinePath);
|
|
88
|
+
} catch (renameErr) {
|
|
89
|
+
log.error(
|
|
90
|
+
{ renameErr },
|
|
91
|
+
`config file at ${configPath} was corrupt (${String(err)}) but could ` +
|
|
92
|
+
`not be renamed for quarantine; loaded defaults.`,
|
|
93
|
+
);
|
|
94
|
+
}
|
|
95
|
+
return quarantinePath;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/**
|
|
99
|
+
* Append a config-quarantine bulletin to `<workspace>/UPDATES.md`. On the
|
|
100
|
+
* next daemon boot the background update-bulletin job picks up UPDATES.md
|
|
101
|
+
* and processes it inside a background-only conversation (not the user's
|
|
102
|
+
* chat). The agent decides whether and when to surface the event — typical
|
|
103
|
+
* cases are the user asking why their settings changed or noticing missing
|
|
104
|
+
* API keys. The bulletin is agent-visible context, not a push notification.
|
|
105
|
+
*
|
|
106
|
+
* Idempotency: the appended block embeds a marker keyed on the quarantine
|
|
107
|
+
* filename's basename. If that marker is already present in UPDATES.md (a
|
|
108
|
+
* prior append succeeded but the process crashed before control returned, or
|
|
109
|
+
* the file was hand-edited), the function is a no-op. This mirrors the
|
|
110
|
+
* pattern release-notes workspace migrations use — see the "Release Update
|
|
111
|
+
* Hygiene" section in the root `AGENTS.md`.
|
|
112
|
+
*
|
|
113
|
+
* Best-effort: any write failure is logged at `warn` and swallowed. The
|
|
114
|
+
* quarantine path must never block startup, and the error log from
|
|
115
|
+
* `quarantineCorruptConfig` remains the authoritative record.
|
|
116
|
+
*
|
|
117
|
+
* Exported with an underscore-prefixed alias (`_appendQuarantineBulletin`) so
|
|
118
|
+
* tests can exercise the idempotent-skip branch directly with a deterministic
|
|
119
|
+
* quarantine basename. Non-test callers should never import the underscore
|
|
120
|
+
* alias — the wiring into `quarantineCorruptConfig` is the production entry
|
|
121
|
+
* point.
|
|
122
|
+
*/
|
|
123
|
+
function appendQuarantineBulletin(
|
|
124
|
+
originalPath: string,
|
|
125
|
+
quarantinePath: string,
|
|
126
|
+
): void {
|
|
127
|
+
try {
|
|
128
|
+
const updatesPath = join(getWorkspaceDir(), "UPDATES.md");
|
|
129
|
+
const quarantineBasename = basename(quarantinePath);
|
|
130
|
+
const marker = `<!-- config-quarantine:${quarantineBasename} -->`;
|
|
131
|
+
|
|
132
|
+
const existing = existsSync(updatesPath)
|
|
133
|
+
? readFileSync(updatesPath, "utf-8")
|
|
134
|
+
: "";
|
|
135
|
+
if (existing.includes(marker)) return;
|
|
136
|
+
|
|
137
|
+
const timestamp = new Date().toISOString();
|
|
138
|
+
const block =
|
|
139
|
+
`## Config was reset to defaults\n\n` +
|
|
140
|
+
`Your \`config.json\` was unreadable at ${timestamp} and couldn't be parsed ` +
|
|
141
|
+
`as JSON. The assistant preserved the original file at \`${quarantinePath}\` ` +
|
|
142
|
+
`and loaded defaults so the app stays working.\n\n` +
|
|
143
|
+
`If you had custom settings (API keys, model choices, voice preferences), ` +
|
|
144
|
+
`they are still in the quarantined file — \`cat ${quarantinePath}\` to ` +
|
|
145
|
+
`recover them, then re-enter through Settings or the CLI.\n\n` +
|
|
146
|
+
`${marker}\n`;
|
|
147
|
+
|
|
148
|
+
const toWrite = existing.length === 0 ? block : `${existing}\n${block}`;
|
|
149
|
+
writeFileSync(updatesPath, toWrite, "utf-8");
|
|
150
|
+
log.info(
|
|
151
|
+
`Appended config-quarantine bulletin to ${updatesPath} for ${originalPath} ` +
|
|
152
|
+
`(quarantined as ${quarantineBasename}).`,
|
|
153
|
+
);
|
|
154
|
+
} catch (bulletinErr) {
|
|
155
|
+
log.warn(
|
|
156
|
+
{ bulletinErr },
|
|
157
|
+
`Failed to append config-quarantine bulletin to UPDATES.md; ` +
|
|
158
|
+
`the quarantine event is still recorded in the assistant logs.`,
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
|
|
50
163
|
/**
|
|
51
164
|
* Validate a raw config object with Zod. Invalid fields are logged as warnings
|
|
52
165
|
* and replaced with defaults (matching prior behavior of per-field fallback).
|
|
@@ -206,10 +319,53 @@ export function deepMergeMissing(
|
|
|
206
319
|
return changed;
|
|
207
320
|
}
|
|
208
321
|
|
|
322
|
+
/**
|
|
323
|
+
* Recursively strip `null` leaves from a plain-object value, returning a
|
|
324
|
+
* deep clone with all `null`-valued keys removed at every nesting level.
|
|
325
|
+
* Non-object inputs (scalars, arrays, `null` itself) are returned as-is.
|
|
326
|
+
*
|
|
327
|
+
* Used to sanitize `overrides` before assigning whole subtrees in
|
|
328
|
+
* `deepMergeOverwrite`, so deletion-sentinel semantics apply uniformly
|
|
329
|
+
* even when the corresponding `target` key does not yet exist.
|
|
330
|
+
*/
|
|
331
|
+
function stripNullLeaves(value: unknown): unknown {
|
|
332
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) {
|
|
333
|
+
return value;
|
|
334
|
+
}
|
|
335
|
+
const out: Record<string, unknown> = {};
|
|
336
|
+
for (const [k, v] of Object.entries(value as Record<string, unknown>)) {
|
|
337
|
+
if (v === null) continue;
|
|
338
|
+
out[k] = stripNullLeaves(v);
|
|
339
|
+
}
|
|
340
|
+
return out;
|
|
341
|
+
}
|
|
342
|
+
|
|
209
343
|
/**
|
|
210
344
|
* Deep-merge `overrides` into `target`, overwriting leaf values.
|
|
211
345
|
* Recursively merges nested objects; scalars and arrays from `overrides`
|
|
212
346
|
* replace corresponding values in `target`.
|
|
347
|
+
*
|
|
348
|
+
* JSON `null` semantics depend on what the target currently holds at
|
|
349
|
+
* that key:
|
|
350
|
+
*
|
|
351
|
+
* - **Target holds a non-null object** (not array): `null` deletes the
|
|
352
|
+
* key, removing the entire subtree. This supports "clear entry"
|
|
353
|
+
* semantics (e.g. the macOS SettingsStore clearing a call-site
|
|
354
|
+
* override via `{ callSites: { memoryRetrieval: null } }`).
|
|
355
|
+
*
|
|
356
|
+
* - **Target holds a scalar, null, or array**: `null` is assigned as the
|
|
357
|
+
* value, preserving nullable config fields like `activeHoursStart`
|
|
358
|
+
* and `llmRequestLogRetentionMs` where `null` is a valid schema
|
|
359
|
+
* value meaning "disabled / no limit".
|
|
360
|
+
*
|
|
361
|
+
* - **Key absent from target**: no-op. Assigning null to a missing key
|
|
362
|
+
* would create a spurious entry; callers that want to establish a
|
|
363
|
+
* null value should set the key to its default first.
|
|
364
|
+
*
|
|
365
|
+
* When an override assigns a whole object subtree to a key that does
|
|
366
|
+
* not yet exist on `target` (or whose existing value is a scalar/array),
|
|
367
|
+
* `stripNullLeaves` drops any `null` leaves inside that subtree before
|
|
368
|
+
* assignment so no invalid nulls get persisted for non-nullable fields.
|
|
213
369
|
*/
|
|
214
370
|
export function deepMergeOverwrite(
|
|
215
371
|
target: Record<string, unknown>,
|
|
@@ -217,8 +373,20 @@ export function deepMergeOverwrite(
|
|
|
217
373
|
): void {
|
|
218
374
|
for (const key of Object.keys(overrides)) {
|
|
219
375
|
const ov = overrides[key];
|
|
220
|
-
if (
|
|
221
|
-
|
|
376
|
+
if (ov === null) {
|
|
377
|
+
if (!(key in target)) continue;
|
|
378
|
+
const existing = target[key];
|
|
379
|
+
if (
|
|
380
|
+
existing != null &&
|
|
381
|
+
typeof existing === "object" &&
|
|
382
|
+
!Array.isArray(existing)
|
|
383
|
+
) {
|
|
384
|
+
delete target[key];
|
|
385
|
+
} else {
|
|
386
|
+
target[key] = null;
|
|
387
|
+
}
|
|
388
|
+
} else if (
|
|
389
|
+
ov !== undefined &&
|
|
222
390
|
typeof ov === "object" &&
|
|
223
391
|
!Array.isArray(ov) &&
|
|
224
392
|
target[key] != null &&
|
|
@@ -230,7 +398,7 @@ export function deepMergeOverwrite(
|
|
|
230
398
|
ov as Record<string, unknown>,
|
|
231
399
|
);
|
|
232
400
|
} else {
|
|
233
|
-
target[key] = ov;
|
|
401
|
+
target[key] = stripNullLeaves(ov);
|
|
234
402
|
}
|
|
235
403
|
}
|
|
236
404
|
}
|
|
@@ -363,9 +531,14 @@ export function loadConfig(): AssistantConfig {
|
|
|
363
531
|
try {
|
|
364
532
|
fileConfig = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
365
533
|
} catch (err) {
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
534
|
+
// The daemon must never block startup (assistant/CLAUDE.md). A config
|
|
535
|
+
// file that fails JSON.parse — truncated during a mid-write crash, or
|
|
536
|
+
// hand-edited to invalid JSON — is quarantined so the content is
|
|
537
|
+
// preserved for debug, and startup proceeds with the same default-
|
|
538
|
+
// config path used when config.json does not exist.
|
|
539
|
+
quarantineCorruptConfig(configPath, err);
|
|
540
|
+
fileConfig = {};
|
|
541
|
+
configFileExisted = false;
|
|
369
542
|
}
|
|
370
543
|
} else {
|
|
371
544
|
configFileExisted = false;
|
|
@@ -521,7 +694,11 @@ export function loadRawConfig(): Record<string, unknown> {
|
|
|
521
694
|
try {
|
|
522
695
|
raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
523
696
|
} catch (err) {
|
|
524
|
-
|
|
697
|
+
// Mirror loadConfig(): quarantine the corrupt file and return an empty
|
|
698
|
+
// object rather than throwing. This prevents /v1/config from surfacing
|
|
699
|
+
// a 500 when the user's config.json is malformed.
|
|
700
|
+
quarantineCorruptConfig(configPath, err);
|
|
701
|
+
raw = {};
|
|
525
702
|
}
|
|
526
703
|
}
|
|
527
704
|
|
|
@@ -571,3 +748,10 @@ export function setNestedValue(
|
|
|
571
748
|
}
|
|
572
749
|
current[keys[keys.length - 1]] = value;
|
|
573
750
|
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* Test-only alias for `appendQuarantineBulletin`. Exists so the crash-mid-
|
|
754
|
+
* append idempotency branch can be exercised with a deterministic quarantine
|
|
755
|
+
* basename without widening the runtime surface. Not for production use.
|
|
756
|
+
*/
|
|
757
|
+
export const _appendQuarantineBulletin = appendQuarantineBulletin;
|
|
@@ -1,11 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Safely set a nested field on a raw config object's `llm.default` map.
|
|
3
|
+
*
|
|
4
|
+
* Ensures the `llm` and `llm.default` objects exist before writing, so
|
|
5
|
+
* callers don't need to guard against undefined intermediate keys.
|
|
6
|
+
*
|
|
7
|
+
* Example: `setLlmDefaultField(raw, "model", "claude-sonnet-4-6")`
|
|
8
|
+
* produces `raw.llm.default.model = "claude-sonnet-4-6"`.
|
|
9
|
+
*/
|
|
10
|
+
export function setLlmDefaultField(
|
|
11
|
+
raw: Record<string, unknown>,
|
|
12
|
+
field: string,
|
|
13
|
+
value: unknown,
|
|
14
|
+
): void {
|
|
15
|
+
const llm: Record<string, unknown> =
|
|
16
|
+
raw.llm != null && typeof raw.llm === "object" && !Array.isArray(raw.llm)
|
|
17
|
+
? (raw.llm as Record<string, unknown>)
|
|
18
|
+
: {};
|
|
19
|
+
const existing = llm.default;
|
|
20
|
+
const defaultBlock: Record<string, unknown> =
|
|
21
|
+
existing != null && typeof existing === "object" && !Array.isArray(existing)
|
|
22
|
+
? (existing as Record<string, unknown>)
|
|
23
|
+
: {};
|
|
24
|
+
defaultBlock[field] = value;
|
|
25
|
+
llm.default = defaultBlock;
|
|
26
|
+
raw.llm = llm;
|
|
27
|
+
}
|
|
28
|
+
|
|
1
29
|
/**
|
|
2
30
|
* Safely set a nested field on a raw config object's `services` map.
|
|
3
31
|
*
|
|
4
32
|
* Ensures the `services` and service-level objects exist before writing,
|
|
5
33
|
* so callers don't need to guard against undefined intermediate keys.
|
|
6
34
|
*
|
|
7
|
-
* Example: `setServiceField(raw, "inference", "
|
|
8
|
-
* produces `raw.services.inference.
|
|
35
|
+
* Example: `setServiceField(raw, "inference", "mode", "managed")`
|
|
36
|
+
* produces `raw.services.inference.mode = "managed"`.
|
|
9
37
|
*/
|
|
10
38
|
export function setServiceField(
|
|
11
39
|
raw: Record<string, unknown>,
|
|
@@ -7,6 +7,18 @@
|
|
|
7
7
|
* - `ingress.enabled` → deleted
|
|
8
8
|
* - `daemon` → deleted entirely
|
|
9
9
|
* - `skills.load.extraDirs` → set to `[]`
|
|
10
|
+
* - `hostBrowser.cdpInspect.desktopAuto` → deleted **only when the source
|
|
11
|
+
* either relies on the schema default or explicitly sets
|
|
12
|
+
* `enabled: true`**. An explicit `enabled: false` is preserved so a
|
|
13
|
+
* platform→local teleport doesn't silently re-enable auto-attach
|
|
14
|
+
* against the user's opt-out.
|
|
15
|
+
*
|
|
16
|
+
* `logFile.dir` is intentionally *not* stripped: the logger's container
|
|
17
|
+
* fallback (`util/logger.ts#resolveLogDir`) already redirects to the
|
|
18
|
+
* default log dir with a warning when the configured path can't be
|
|
19
|
+
* created, and stripping `dir` would disable rotating file logging
|
|
20
|
+
* entirely because `lifecycle.ts` gates `initLogger` on a truthy
|
|
21
|
+
* `config.logFile.dir`.
|
|
10
22
|
*/
|
|
11
23
|
export function sanitizeConfigForTransfer(configJson: string): string {
|
|
12
24
|
let config: Record<string, unknown>;
|
|
@@ -43,5 +55,28 @@ export function sanitizeConfigForTransfer(configJson: string): string {
|
|
|
43
55
|
}
|
|
44
56
|
}
|
|
45
57
|
|
|
58
|
+
// Strip hostBrowser.cdpInspect.desktopAuto — the auto-attach-to-Chrome
|
|
59
|
+
// behavior is gated on a macOS-originated turn; preserving a
|
|
60
|
+
// source-host-derived `enabled: true` inside a Linux managed pod's
|
|
61
|
+
// config is misleading and brittle. Preserve an explicit
|
|
62
|
+
// `enabled: false` opt-out, though — the schema default is `true`,
|
|
63
|
+
// so unconditionally stripping this subobject would re-enable
|
|
64
|
+
// auto-attach after a platform→local teleport.
|
|
65
|
+
if (config.hostBrowser && typeof config.hostBrowser === "object") {
|
|
66
|
+
const hostBrowser = config.hostBrowser as Record<string, unknown>;
|
|
67
|
+
if (hostBrowser.cdpInspect && typeof hostBrowser.cdpInspect === "object") {
|
|
68
|
+
const cdpInspect = hostBrowser.cdpInspect as Record<string, unknown>;
|
|
69
|
+
const desktopAuto = cdpInspect.desktopAuto;
|
|
70
|
+
const isExplicitOptOut =
|
|
71
|
+
desktopAuto !== null &&
|
|
72
|
+
typeof desktopAuto === "object" &&
|
|
73
|
+
!Array.isArray(desktopAuto) &&
|
|
74
|
+
(desktopAuto as Record<string, unknown>).enabled === false;
|
|
75
|
+
if (!isExplicitOptOut) {
|
|
76
|
+
delete cdpInspect.desktopAuto;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
46
81
|
return JSON.stringify(config, null, 2) + "\n";
|
|
47
82
|
}
|
package/src/config/schema.ts
CHANGED
|
@@ -62,17 +62,13 @@ export {
|
|
|
62
62
|
export type {
|
|
63
63
|
ContextOverflowRecoveryConfig,
|
|
64
64
|
ContextWindowConfig,
|
|
65
|
-
Effort,
|
|
66
65
|
ModelPricingOverride,
|
|
67
|
-
Speed,
|
|
68
66
|
ThinkingConfig,
|
|
69
67
|
} from "./schemas/inference.js";
|
|
70
68
|
export {
|
|
71
69
|
ContextOverflowRecoveryConfigSchema,
|
|
72
70
|
ContextWindowConfigSchema,
|
|
73
|
-
EffortSchema,
|
|
74
71
|
ModelPricingOverrideSchema,
|
|
75
|
-
SpeedSchema,
|
|
76
72
|
ThinkingConfigSchema,
|
|
77
73
|
} from "./schemas/inference.js";
|
|
78
74
|
export type {
|
|
@@ -87,6 +83,14 @@ export {
|
|
|
87
83
|
} from "./schemas/ingress.js";
|
|
88
84
|
export type { JournalConfig } from "./schemas/journal.js";
|
|
89
85
|
export { JournalConfigSchema } from "./schemas/journal.js";
|
|
86
|
+
export type {
|
|
87
|
+
LLMCallSite,
|
|
88
|
+
LLMCallSiteConfig,
|
|
89
|
+
LLMConfig,
|
|
90
|
+
LLMConfigBase,
|
|
91
|
+
LLMConfigFragment,
|
|
92
|
+
} from "./schemas/llm.js";
|
|
93
|
+
export { LLMCallSiteEnum, LLMSchema } from "./schemas/llm.js";
|
|
90
94
|
export type { AuditLogConfig, LogFileConfig } from "./schemas/logging.js";
|
|
91
95
|
export {
|
|
92
96
|
AuditLogConfigSchema,
|
|
@@ -239,15 +243,9 @@ import {
|
|
|
239
243
|
import { FilingConfigSchema } from "./schemas/filing.js";
|
|
240
244
|
import { HeartbeatConfigSchema } from "./schemas/heartbeat.js";
|
|
241
245
|
import { HostBrowserConfigSchema } from "./schemas/host-browser.js";
|
|
242
|
-
import {
|
|
243
|
-
ContextWindowConfigSchema,
|
|
244
|
-
EffortSchema,
|
|
245
|
-
ModelPricingOverrideSchema,
|
|
246
|
-
SpeedSchema,
|
|
247
|
-
ThinkingConfigSchema,
|
|
248
|
-
} from "./schemas/inference.js";
|
|
249
246
|
import { IngressConfigSchema } from "./schemas/ingress.js";
|
|
250
247
|
import { JournalConfigSchema } from "./schemas/journal.js";
|
|
248
|
+
import { LLMSchema } from "./schemas/llm.js";
|
|
251
249
|
import {
|
|
252
250
|
AuditLogConfigSchema,
|
|
253
251
|
LogFileConfigSchema,
|
|
@@ -276,18 +274,6 @@ import { WorkspaceGitConfigSchema } from "./schemas/workspace-git.js";
|
|
|
276
274
|
export const AssistantConfigSchema = z
|
|
277
275
|
.object({
|
|
278
276
|
services: ServicesSchema.default(ServicesSchema.parse({})),
|
|
279
|
-
maxTokens: z
|
|
280
|
-
.number({ error: "maxTokens must be a number" })
|
|
281
|
-
.int("maxTokens must be an integer")
|
|
282
|
-
.positive("maxTokens must be a positive integer")
|
|
283
|
-
.default(64000)
|
|
284
|
-
.describe("Maximum number of output tokens per LLM response"),
|
|
285
|
-
effort: EffortSchema,
|
|
286
|
-
speed: SpeedSchema,
|
|
287
|
-
thinking: ThinkingConfigSchema.default(ThinkingConfigSchema.parse({})),
|
|
288
|
-
contextWindow: ContextWindowConfigSchema.default(
|
|
289
|
-
ContextWindowConfigSchema.parse({}),
|
|
290
|
-
),
|
|
291
277
|
memory: MemoryConfigSchema.default(MemoryConfigSchema.parse({})),
|
|
292
278
|
dataDir: z
|
|
293
279
|
.string({ error: "dataDir must be a string" })
|
|
@@ -305,12 +291,16 @@ export const AssistantConfigSchema = z
|
|
|
305
291
|
logFile: LogFileConfigSchema.default(
|
|
306
292
|
LogFileConfigSchema.parse({ dir: getDataDir() + "/logs" }),
|
|
307
293
|
),
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
294
|
+
// Unified LLM configuration block. The unique source of truth for
|
|
295
|
+
// provider/model/maxTokens/effort/speed/temperature/thinking/contextWindow
|
|
296
|
+
// and pricing overrides for every call site in the assistant.
|
|
297
|
+
//
|
|
298
|
+
// Default values live on each leaf inside `LLMSchema` (see
|
|
299
|
+
// `schemas/llm.ts`), so `LLMSchema.parse({})` returns a fully-populated
|
|
300
|
+
// object. This matches the pattern used by sibling schemas above and
|
|
301
|
+
// ensures the loader's leaf-deletion recovery path can repair a partially
|
|
302
|
+
// invalid `llm` block without falling back to `cloneDefaultConfig()`.
|
|
303
|
+
llm: LLMSchema.default(LLMSchema.parse({})),
|
|
314
304
|
filing: FilingConfigSchema.default(FilingConfigSchema.parse({})),
|
|
315
305
|
heartbeat: HeartbeatConfigSchema.default(HeartbeatConfigSchema.parse({})),
|
|
316
306
|
updates: UpdatesConfigSchema.default(UpdatesConfigSchema.parse({})),
|
|
@@ -364,30 +354,29 @@ export const AssistantConfigSchema = z
|
|
|
364
354
|
),
|
|
365
355
|
})
|
|
366
356
|
.superRefine((config, ctx) => {
|
|
357
|
+
const llmContextWindow = config.llm?.default?.contextWindow;
|
|
367
358
|
if (
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
config.contextWindow.compactThreshold
|
|
359
|
+
llmContextWindow?.targetBudgetRatio != null &&
|
|
360
|
+
llmContextWindow?.compactThreshold != null &&
|
|
361
|
+
llmContextWindow.targetBudgetRatio >= llmContextWindow.compactThreshold
|
|
372
362
|
) {
|
|
373
363
|
ctx.addIssue({
|
|
374
364
|
code: z.ZodIssueCode.custom,
|
|
375
|
-
path: ["contextWindow", "targetBudgetRatio"],
|
|
365
|
+
path: ["llm", "default", "contextWindow", "targetBudgetRatio"],
|
|
376
366
|
message:
|
|
377
|
-
"contextWindow.targetBudgetRatio must be less than contextWindow.compactThreshold",
|
|
367
|
+
"llm.default.contextWindow.targetBudgetRatio must be less than llm.default.contextWindow.compactThreshold",
|
|
378
368
|
});
|
|
379
369
|
}
|
|
380
370
|
if (
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
config.contextWindow.summaryBudgetRatio
|
|
371
|
+
llmContextWindow?.targetBudgetRatio != null &&
|
|
372
|
+
llmContextWindow?.summaryBudgetRatio != null &&
|
|
373
|
+
llmContextWindow.targetBudgetRatio <= llmContextWindow.summaryBudgetRatio
|
|
385
374
|
) {
|
|
386
375
|
ctx.addIssue({
|
|
387
376
|
code: z.ZodIssueCode.custom,
|
|
388
|
-
path: ["contextWindow", "targetBudgetRatio"],
|
|
377
|
+
path: ["llm", "default", "contextWindow", "targetBudgetRatio"],
|
|
389
378
|
message:
|
|
390
|
-
"contextWindow.targetBudgetRatio must be greater than contextWindow.summaryBudgetRatio",
|
|
379
|
+
"llm.default.contextWindow.targetBudgetRatio must be greater than llm.default.contextWindow.summaryBudgetRatio",
|
|
391
380
|
});
|
|
392
381
|
}
|
|
393
382
|
const segmentation = config.memory?.segmentation;
|
|
@@ -24,28 +24,9 @@ export const AnalysisConfigSchema = z
|
|
|
24
24
|
.describe(
|
|
25
25
|
"Milliseconds of idle time after the last message before the debounced analysis job fires",
|
|
26
26
|
),
|
|
27
|
-
|
|
28
|
-
// Optional model intent for the analysis agent loop. When omitted,
|
|
29
|
-
// the analysis agent uses the same model as the main agent.
|
|
30
|
-
// Accepted values match the main agent's model-intent vocabulary.
|
|
31
|
-
modelIntent: z
|
|
32
|
-
.enum(["latency-optimized", "quality-optimized", "vision-optimized"], {
|
|
33
|
-
error: "analysis.modelIntent must be a valid model intent",
|
|
34
|
-
})
|
|
35
|
-
.optional()
|
|
36
|
-
.describe(
|
|
37
|
-
"Model selection strategy for the analysis agent loop — falls back to the main agent's model when omitted",
|
|
38
|
-
),
|
|
39
|
-
|
|
40
|
-
// Optional explicit model override (provider/model string). Takes
|
|
41
|
-
// precedence over modelIntent when both are set.
|
|
42
|
-
modelOverride: z
|
|
43
|
-
.string({ error: "analysis.modelOverride must be a string" })
|
|
44
|
-
.optional()
|
|
45
|
-
.describe(
|
|
46
|
-
"Explicit model override (provider/model string) for the analysis agent loop — takes precedence over modelIntent when both are set",
|
|
47
|
-
),
|
|
48
27
|
})
|
|
49
|
-
.describe(
|
|
28
|
+
.describe(
|
|
29
|
+
"Controls the auto-analyze agent loop triggered by conversation activity. Model selection lives under llm.callSites.analyzeConversation.",
|
|
30
|
+
);
|
|
50
31
|
|
|
51
32
|
export type AnalysisConfig = z.infer<typeof AnalysisConfigSchema>;
|
|
@@ -222,10 +222,6 @@ export const CallsConfigSchema = z
|
|
|
222
222
|
),
|
|
223
223
|
safety: CallsSafetyConfigSchema.default(CallsSafetyConfigSchema.parse({})),
|
|
224
224
|
voice: CallsVoiceConfigSchema.default(CallsVoiceConfigSchema.parse({})),
|
|
225
|
-
model: z
|
|
226
|
-
.string({ error: "calls.model must be a string" })
|
|
227
|
-
.optional()
|
|
228
|
-
.describe("Override the default model for phone call conversations"),
|
|
229
225
|
callerIdentity: CallerIdentityConfigSchema.default(
|
|
230
226
|
CallerIdentityConfigSchema.parse({}),
|
|
231
227
|
),
|