@vellumai/assistant 0.6.5 → 0.6.6
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/AGENTS.md +9 -1
- package/ARCHITECTURE.md +15 -17
- package/Dockerfile +6 -4
- package/__tests__/permissions/gateway-threshold-reader.test.ts +283 -0
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +25 -30
- package/docs/architecture/security.md +7 -6
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/plugins.md +761 -0
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/openapi.yaml +212 -68
- package/package.json +1 -1
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/approval-cascade.test.ts +7 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +1 -0
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/checker.test.ts +459 -171
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/compaction-events.test.ts +501 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-model-image-provider.test.ts +110 -0
- package/src/__tests__/config-schema.test.ts +22 -9
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/contacts-tools.test.ts +26 -0
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-window-manager.test.ts +355 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +26 -30
- package/src/__tests__/conversation-agent-loop.test.ts +30 -141
- package/src/__tests__/conversation-confirmation-signals.test.ts +6 -1
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -16
- package/src/__tests__/conversation-pairing.test.ts +174 -10
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -1
- package/src/__tests__/conversation-process-callsite.test.ts +3 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +16 -7
- package/src/__tests__/conversation-queue.test.ts +29 -14
- package/src/__tests__/conversation-routes-disk-view.test.ts +7 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +155 -110
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-queue.test.ts +7 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -2
- package/src/__tests__/conversation-speed-override.test.ts +6 -1
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +41 -2
- package/src/__tests__/conversation-usage.test.ts +1 -1
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +2 -2
- package/src/__tests__/db-schedule-syntax-migration.test.ts +1 -0
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/extension-id-sync-guard.test.ts +3 -3
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +307 -0
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +3 -3
- package/src/__tests__/host-proxy-interface.test.ts +36 -2
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/injector-chain.test.ts +526 -0
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/llm-call-pipeline.test.ts +285 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-retrieval-pipeline.test.ts +401 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +5 -68
- package/src/__tests__/model-intents.test.ts +4 -2
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +108 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -1
- package/src/__tests__/oauth-cli.test.ts +14 -12
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -5
- package/src/__tests__/oauth-providers-routes.test.ts +3 -2
- package/src/__tests__/oauth-store.test.ts +41 -76
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/overflow-reduce-pipeline.test.ts +676 -0
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -24
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +377 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform.test.ts +5 -2
- package/src/__tests__/plugin-bootstrap.test.ts +483 -0
- package/src/__tests__/plugin-registry.test.ts +273 -0
- package/src/__tests__/plugin-route-contribution.test.ts +288 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +286 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +44 -12
- package/src/__tests__/proxy-approval-callback.test.ts +69 -8
- package/src/__tests__/reaction-persistence.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +0 -2
- package/src/__tests__/schedule-routes.test.ts +131 -1
- package/src/__tests__/scheduler-recurrence.test.ts +14 -70
- package/src/__tests__/scheduler-reuse-conversation.test.ts +10 -50
- package/src/__tests__/secret-detection-handler.test.ts +0 -10
- package/src/__tests__/shell-identity.test.ts +0 -134
- package/src/__tests__/suggestion-routes.test.ts +103 -4
- package/src/__tests__/task-memory-cleanup.test.ts +1 -0
- package/src/__tests__/task-scheduler.test.ts +3 -15
- package/src/__tests__/test-preload.ts +11 -0
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +431 -0
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +431 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -6
- package/src/__tests__/tool-executor-shell-integration.test.ts +7 -10
- package/src/__tests__/tool-executor.test.ts +141 -0
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/user-plugin-loader.test.ts +191 -0
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/agent/loop.ts +340 -102
- package/src/approvals/__tests__/guardian-feed-event.test.ts +304 -0
- package/src/approvals/guardian-request-resolvers.ts +80 -0
- package/src/backup/__tests__/backup-worker.test.ts +2 -13
- package/src/backup/backup-worker.ts +3 -15
- package/src/bundler/app-compiler.ts +84 -1
- package/src/calls/call-state.ts +2 -2
- package/src/channels/__tests__/types.test.ts +3 -3
- package/src/channels/types.ts +6 -4
- package/src/cli/__tests__/notifications.test.ts +87 -211
- package/src/cli/commands/__tests__/backup.test.ts +1 -1
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/backup.ts +2 -2
- package/src/cli/commands/clients.ts +138 -0
- package/src/cli/commands/completions.ts +2 -9
- package/src/cli/commands/conversations.ts +55 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/notifications.ts +68 -103
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/skills.ts +3 -4
- package/src/cli/program.ts +25 -29
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +28 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +22 -40
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-tool-registry.ts +0 -15
- package/src/config/feature-flag-registry.json +17 -1
- package/src/config/schema.ts +19 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/llm.ts +2 -3
- package/src/config/schemas/security.ts +6 -6
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +94 -5
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/tool-result-truncation.ts +3 -63
- package/src/context/window-manager.ts +190 -16
- package/src/credential-health/credential-health-service.ts +19 -6
- package/src/daemon/__tests__/conversation-feed-event.test.ts +317 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/config-watcher.ts +0 -2
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +83 -22
- package/src/daemon/conversation-agent-loop.ts +984 -683
- package/src/daemon/conversation-history.ts +10 -19
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-notifiers.ts +2 -110
- package/src/daemon/conversation-process.ts +14 -7
- package/src/daemon/conversation-runtime-assembly.ts +532 -411
- package/src/daemon/conversation-tool-setup.ts +41 -4
- package/src/daemon/conversation.ts +80 -35
- package/src/daemon/external-plugins-bootstrap.ts +478 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-model.ts +11 -0
- package/src/daemon/handlers/skills.ts +5 -1
- package/src/daemon/lifecycle.ts +33 -68
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +49 -0
- package/src/daemon/message-types/messages.ts +12 -0
- package/src/daemon/server.ts +5 -3
- package/src/daemon/shutdown-handlers.ts +2 -12
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +160 -0
- package/src/heartbeat/heartbeat-service.ts +24 -1
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +41 -2
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/ipc/__tests__/socket-path.test.ts +11 -50
- package/src/ipc/cli-client.ts +1 -1
- package/src/ipc/cli-server.ts +3 -3
- package/src/ipc/gateway-client.ts +4 -1
- package/src/ipc/routes/browser-context.ts +2 -0
- package/src/ipc/routes/browser.ts +1 -0
- package/src/ipc/routes/get-contact.ts +16 -0
- package/src/ipc/routes/index.ts +14 -0
- package/src/ipc/routes/list-clients.ts +31 -0
- package/src/ipc/routes/merge-contacts.ts +17 -0
- package/src/ipc/routes/notification.ts +133 -0
- package/src/ipc/routes/rename-conversation.ts +59 -0
- package/src/ipc/routes/search-contacts.ts +19 -0
- package/src/ipc/routes/upsert-contact.ts +25 -0
- package/src/ipc/socket-path.ts +14 -38
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/conversation-crud.ts +48 -18
- package/src/memory/conversation-queries.ts +57 -4
- package/src/memory/conversation-title-service.ts +25 -0
- package/src/memory/db-init.ts +8 -0
- package/src/memory/embedding-gemini.test.ts +41 -2
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/graph/bootstrap.test.ts +282 -0
- package/src/memory/graph/bootstrap.ts +8 -5
- package/src/memory/graph/extraction.ts +10 -2
- package/src/memory/graph/graph-search.test.ts +1 -0
- package/src/memory/graph/inspect.ts +2 -2
- package/src/memory/graph/retriever.ts +10 -3
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/index.ts +4 -0
- package/src/memory/pkb/pkb-index.test.ts +1 -0
- package/src/memory/pkb/pkb-reconcile.test.ts +1 -0
- package/src/memory/pkb/pkb-search.test.ts +65 -4
- package/src/memory/pkb/pkb-search.ts +40 -18
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/infrastructure.ts +1 -0
- package/src/memory/schema/oauth.ts +4 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/copy-composer.ts +0 -5
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/signal.ts +1 -2
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +30 -14
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/permissions/approval-policy.test.ts +293 -18
- package/src/permissions/approval-policy.ts +110 -58
- package/src/permissions/arg-parser.test.ts +161 -0
- package/src/permissions/arg-parser.ts +141 -0
- package/src/permissions/bash-risk-classifier.test.ts +414 -2
- package/src/permissions/bash-risk-classifier.ts +303 -60
- package/src/permissions/checker.ts +157 -29
- package/src/permissions/command-registry.test.ts +239 -0
- package/src/permissions/command-registry.ts +234 -54
- package/src/permissions/defaults.ts +5 -4
- package/src/permissions/gateway-threshold-reader.ts +196 -0
- package/src/permissions/prompter.ts +4 -0
- package/src/permissions/risk-types.ts +61 -4
- package/src/permissions/schedule-risk-classifier.test.ts +129 -0
- package/src/permissions/schedule-risk-classifier.ts +85 -0
- package/src/permissions/shell-identity.ts +2 -42
- package/src/permissions/types.ts +2 -0
- package/src/permissions/workspace-policy.ts +8 -3
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +491 -0
- package/src/plugins/defaults/llm-call.ts +82 -0
- package/src/plugins/defaults/memory-retrieval.ts +226 -0
- package/src/plugins/defaults/overflow-reduce.ts +181 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +104 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +241 -0
- package/src/plugins/types.ts +1134 -0
- package/src/plugins/user-loader.ts +177 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/providers/model-catalog.ts +52 -29
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openrouter/client.ts +5 -1
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/runtime/AGENTS.md +25 -16
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +3 -3
- package/src/runtime/__tests__/client-registry.test.ts +293 -0
- package/src/runtime/client-registry.ts +261 -0
- package/src/runtime/http-server.ts +77 -8
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +1 -22
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +17 -0
- package/src/runtime/routes/browser-extension-pair-routes.ts +27 -8
- package/src/runtime/routes/conversation-routes.ts +223 -116
- package/src/runtime/routes/inbound-message-handler.ts +88 -13
- package/src/runtime/routes/memory-item-routes.test.ts +1 -0
- package/src/runtime/routes/migration-routes.ts +0 -3
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +284 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +80 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +294 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +271 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +202 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +309 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +224 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +29 -0
- package/src/runtime/routes/playground/deps.ts +56 -0
- package/src/runtime/routes/playground/force-compact.ts +73 -0
- package/src/runtime/routes/playground/guard.ts +37 -0
- package/src/runtime/routes/playground/index.ts +28 -0
- package/src/runtime/routes/playground/inject-failures.ts +159 -0
- package/src/runtime/routes/playground/reset-circuit.ts +115 -0
- package/src/runtime/routes/playground/seed-conversation.ts +139 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +78 -0
- package/src/runtime/routes/playground/state.ts +78 -0
- package/src/runtime/routes/schedule-routes.ts +89 -8
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +7 -1
- package/src/schedule/scheduler.ts +48 -8
- package/src/skills/catalog-cache.ts +12 -5
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +88 -19
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/executor.ts +126 -74
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +98 -49
- package/src/tools/policy-context.ts +4 -0
- package/src/tools/registry.ts +140 -3
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +0 -51
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/types.ts +28 -2
- package/src/util/platform.ts +7 -2
- package/src/util/pricing.ts +26 -3
- package/src/workspace/migrations/006-services-config.ts +2 -4
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/registry.ts +12 -0
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/screen-watch/tools/start-screen-watch.ts +0 -12
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/oauth/scope-policy.ts +0 -89
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/signals/shotgun.ts +0 -203
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
|
@@ -3,7 +3,6 @@ import { mkdirSync, renameSync, writeFileSync } from "node:fs";
|
|
|
3
3
|
import { dirname } from "node:path";
|
|
4
4
|
|
|
5
5
|
import { generateAvatar } from "../../media/avatar-router.js";
|
|
6
|
-
import { mapGeminiError } from "../../media/gemini-image-service.js";
|
|
7
6
|
import { getLogger } from "../../util/logger.js";
|
|
8
7
|
import { getAvatarImagePath } from "../../util/platform.js";
|
|
9
8
|
|
|
@@ -69,7 +68,12 @@ export async function generateAndSaveAvatar(
|
|
|
69
68
|
isError: false,
|
|
70
69
|
};
|
|
71
70
|
} catch (error) {
|
|
72
|
-
|
|
71
|
+
// avatar-router already throws with a provider-aware, user-friendly
|
|
72
|
+
// message — just surface error.message directly.
|
|
73
|
+
const message =
|
|
74
|
+
error instanceof Error
|
|
75
|
+
? error.message
|
|
76
|
+
: "An unexpected error occurred during image generation.";
|
|
73
77
|
log.error({ error: message }, "Avatar generation failed");
|
|
74
78
|
return {
|
|
75
79
|
content: `Avatar generation failed: ${message}`,
|
package/src/tools/types.ts
CHANGED
|
@@ -207,6 +207,18 @@ export interface ToolContext {
|
|
|
207
207
|
* to cdp-inspect or local Playwright.
|
|
208
208
|
*/
|
|
209
209
|
transportInterface?: InterfaceId;
|
|
210
|
+
/**
|
|
211
|
+
* True when the host browser proxy's sender was overridden by a
|
|
212
|
+
* registry-routed extension connection (ChromeExtensionRegistry WebSocket).
|
|
213
|
+
* The CDP factory uses this to distinguish between an SSE-backed proxy
|
|
214
|
+
* (macOS, no extension) and an extension-backed proxy: only the latter
|
|
215
|
+
* should suppress desktop-auto cdp-inspect when temporarily unavailable,
|
|
216
|
+
* because the extension transport was explicitly expected and the
|
|
217
|
+
* disconnection is transient. An SSE-backed proxy that reports
|
|
218
|
+
* unavailable (e.g. non-interactive turn) should NOT suppress
|
|
219
|
+
* cdp-inspect — the proxy was never expected to service browser requests.
|
|
220
|
+
*/
|
|
221
|
+
hostBrowserRegistryRouted?: boolean;
|
|
210
222
|
}
|
|
211
223
|
|
|
212
224
|
export interface DiffInfo {
|
|
@@ -242,6 +254,14 @@ export interface ToolExecutionResult {
|
|
|
242
254
|
* the LLM voluntarily end its turn.
|
|
243
255
|
*/
|
|
244
256
|
yieldToUser?: boolean;
|
|
257
|
+
/** Risk level from the classifier (populated during permission check). */
|
|
258
|
+
riskLevel?: string;
|
|
259
|
+
/** Human-readable reason for the risk classification. */
|
|
260
|
+
riskReason?: string;
|
|
261
|
+
/** Whether the daemon is running in a containerized (Docker) environment. */
|
|
262
|
+
isContainerized?: boolean;
|
|
263
|
+
/** Scope options ladder for the rule editor (narrowest to broadest). */
|
|
264
|
+
riskScopeOptions?: Array<{ pattern: string; label: string }>;
|
|
245
265
|
/**
|
|
246
266
|
* When present, indicates that a CES tool returned an `approval_required`
|
|
247
267
|
* response. The executor uses the approval bridge to prompt the guardian,
|
|
@@ -273,6 +293,10 @@ export interface ProxyApprovalRequest {
|
|
|
273
293
|
matchingPatterns?: string[];
|
|
274
294
|
};
|
|
275
295
|
sessionId: string;
|
|
296
|
+
/** HTTP method (plain HTTP only; undefined for HTTPS CONNECT tunnels). */
|
|
297
|
+
method?: string;
|
|
298
|
+
/** Curated non-sensitive headers (plain HTTP only). */
|
|
299
|
+
requestHeaders?: Record<string, string>;
|
|
276
300
|
}
|
|
277
301
|
|
|
278
302
|
/** Callback for proxy policy decisions requiring user confirmation. Returns true if approved. */
|
|
@@ -296,12 +320,14 @@ export interface Tool {
|
|
|
296
320
|
defaultRiskLevel: RiskLevel;
|
|
297
321
|
/** When set to 'proxy', the tool is forwarded to a connected client rather than executed locally. */
|
|
298
322
|
executionMode?: "local" | "proxy";
|
|
299
|
-
/** Whether this tool is a core built-in, provided by a skill, or from an MCP server. */
|
|
300
|
-
origin?: "core" | "skill" | "mcp";
|
|
323
|
+
/** Whether this tool is a core built-in, provided by a skill, contributed by a plugin, or from an MCP server. */
|
|
324
|
+
origin?: "core" | "skill" | "mcp" | "plugin";
|
|
301
325
|
/** If origin is 'skill', the ID of the owning skill. */
|
|
302
326
|
ownerSkillId?: string;
|
|
303
327
|
/** If origin is 'mcp', the ID of the owning MCP server. */
|
|
304
328
|
ownerMcpServerId?: string;
|
|
329
|
+
/** If origin is 'plugin', the name of the owning plugin. */
|
|
330
|
+
ownerPluginId?: string;
|
|
305
331
|
/** Content-hash of the owning skill's source at registration time. */
|
|
306
332
|
ownerSkillVersionHash?: string;
|
|
307
333
|
/** Whether the owning skill is bundled with the daemon (trusted first-party). */
|
package/src/util/platform.ts
CHANGED
|
@@ -59,8 +59,14 @@ export function normalizeAssistantId(assistantId: string): string {
|
|
|
59
59
|
* Docker mode relocates the workspace via `VELLUM_WORKSPACE_DIR` rather
|
|
60
60
|
* than `BASE_DATA_DIR`, so honoring `BASE_DATA_DIR` here does not affect
|
|
61
61
|
* containerized deployments.
|
|
62
|
+
*
|
|
63
|
+
* Exported so other daemon-side consumers (e.g. the meet-join orphan reaper
|
|
64
|
+
* in `skills/meet-join/daemon/docker-runner.ts`) can derive a per-instance
|
|
65
|
+
* identifier from the same canonical root. Do not replace with ad-hoc
|
|
66
|
+
* `process.env.BASE_DATA_DIR` reads — this helper is the single source of
|
|
67
|
+
* truth for per-instance path resolution.
|
|
62
68
|
*/
|
|
63
|
-
function vellumRoot(): string {
|
|
69
|
+
export function vellumRoot(): string {
|
|
64
70
|
const baseDataDir = process.env.BASE_DATA_DIR?.trim();
|
|
65
71
|
if (baseDataDir) return join(baseDataDir, ".vellum");
|
|
66
72
|
return join(homedir(), ".vellum");
|
|
@@ -410,7 +416,6 @@ export function ensureDataDir(): void {
|
|
|
410
416
|
// Workspace dirs
|
|
411
417
|
workspace,
|
|
412
418
|
join(workspace, "signals"),
|
|
413
|
-
join(workspace, "hooks"),
|
|
414
419
|
join(workspace, "skills"),
|
|
415
420
|
join(workspace, "routes"),
|
|
416
421
|
join(workspace, "embedding-models"),
|
package/src/util/pricing.ts
CHANGED
|
@@ -23,9 +23,9 @@ const PROVIDER_PRICING: Record<string, Record<string, ModelPricing>> = {
|
|
|
23
23
|
anthropic: {
|
|
24
24
|
"claude-opus-4-7": { inputPer1M: 5, outputPer1M: 25 },
|
|
25
25
|
"claude-opus-4-6": { inputPer1M: 5, outputPer1M: 25 },
|
|
26
|
-
"claude-opus-4": { inputPer1M:
|
|
26
|
+
"claude-opus-4": { inputPer1M: 5, outputPer1M: 25 },
|
|
27
27
|
"claude-sonnet-4": { inputPer1M: 3, outputPer1M: 15 },
|
|
28
|
-
"claude-haiku-4": { inputPer1M:
|
|
28
|
+
"claude-haiku-4": { inputPer1M: 1, outputPer1M: 5 },
|
|
29
29
|
},
|
|
30
30
|
openai: {
|
|
31
31
|
"gpt-5.4": { inputPer1M: 2.5, outputPer1M: 15 },
|
|
@@ -51,9 +51,32 @@ const PROVIDER_PRICING: Record<string, Record<string, ModelPricing>> = {
|
|
|
51
51
|
fireworks: {
|
|
52
52
|
"accounts/fireworks/models/kimi-k2p5": {
|
|
53
53
|
inputPer1M: 0.6,
|
|
54
|
-
outputPer1M:
|
|
54
|
+
outputPer1M: 2.5,
|
|
55
55
|
},
|
|
56
56
|
},
|
|
57
|
+
// Non-Anthropic OpenRouter models. Anthropic-on-OpenRouter is handled by a
|
|
58
|
+
// dedicated branch in resolvePricingForUsage that routes to the Anthropic
|
|
59
|
+
// catalog (OpenRouter bills those at Anthropic's direct rates). Rates here
|
|
60
|
+
// mirror the catalog metadata in model-catalog.ts so cost tracking has a
|
|
61
|
+
// priced value instead of falling back to 'unpriced'.
|
|
62
|
+
openrouter: {
|
|
63
|
+
"x-ai/grok-4.20-beta": { inputPer1M: 3, outputPer1M: 15 },
|
|
64
|
+
"x-ai/grok-4": { inputPer1M: 3, outputPer1M: 15 },
|
|
65
|
+
"deepseek/deepseek-r1-0528": { inputPer1M: 0.55, outputPer1M: 2.19 },
|
|
66
|
+
"deepseek/deepseek-chat-v3-0324": { inputPer1M: 0.27, outputPer1M: 1.1 },
|
|
67
|
+
"qwen/qwen3.5-plus-02-15": { inputPer1M: 0.8, outputPer1M: 2.4 },
|
|
68
|
+
"qwen/qwen3.5-397b-a17b": { inputPer1M: 0.9, outputPer1M: 2.7 },
|
|
69
|
+
"qwen/qwen3.5-flash-02-23": { inputPer1M: 0.2, outputPer1M: 0.6 },
|
|
70
|
+
"qwen/qwen3-coder-next": { inputPer1M: 0.5, outputPer1M: 1.5 },
|
|
71
|
+
"moonshotai/kimi-k2.6": { inputPer1M: 0.6, outputPer1M: 2.8 },
|
|
72
|
+
"moonshotai/kimi-k2.5": { inputPer1M: 0.6, outputPer1M: 2.5 },
|
|
73
|
+
"mistralai/mistral-medium-3": { inputPer1M: 0.4, outputPer1M: 2.0 },
|
|
74
|
+
"mistralai/mistral-small-2603": { inputPer1M: 0.2, outputPer1M: 0.6 },
|
|
75
|
+
"mistralai/devstral-2512": { inputPer1M: 0.1, outputPer1M: 0.3 },
|
|
76
|
+
"meta-llama/llama-4-maverick": { inputPer1M: 0.27, outputPer1M: 0.85 },
|
|
77
|
+
"meta-llama/llama-4-scout": { inputPer1M: 0.11, outputPer1M: 0.34 },
|
|
78
|
+
"amazon/nova-pro-v1": { inputPer1M: 0.8, outputPer1M: 3.2 },
|
|
79
|
+
},
|
|
57
80
|
};
|
|
58
81
|
|
|
59
82
|
/**
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
2
|
import { join } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { providerForImageModelPrefix } from "../../media/types.js";
|
|
4
5
|
import { credentialKey } from "../../security/credential-key.js";
|
|
5
6
|
import {
|
|
6
7
|
getProviderKeyAsync,
|
|
@@ -110,10 +111,7 @@ export const servicesConfigMigration: WorkspaceMigration = {
|
|
|
110
111
|
services["image-generation"] = {
|
|
111
112
|
...(existingServices["image-generation"] ?? {}),
|
|
112
113
|
mode: "your-own",
|
|
113
|
-
provider:
|
|
114
|
-
imageGenModel.startsWith("dall-e") || imageGenModel.startsWith("gpt")
|
|
115
|
-
? "openai"
|
|
116
|
-
: "gemini",
|
|
114
|
+
provider: providerForImageModelPrefix(imageGenModel),
|
|
117
115
|
model: imageGenModel,
|
|
118
116
|
};
|
|
119
117
|
|
|
@@ -43,9 +43,8 @@ export const moveHooksToWorkspaceMigration: WorkspaceMigration = {
|
|
|
43
43
|
if (!existsSync(oldHooksDir)) return;
|
|
44
44
|
|
|
45
45
|
// Move hook entries from root to workspace. The old (user) entries take
|
|
46
|
-
// precedence over anything already at the destination
|
|
47
|
-
//
|
|
48
|
-
// We remove the destination first so renameSync succeeds atomically.
|
|
46
|
+
// precedence over anything already at the destination. We remove the
|
|
47
|
+
// destination first so renameSync succeeds atomically.
|
|
49
48
|
try {
|
|
50
49
|
const entries = readdirSync(oldHooksDir);
|
|
51
50
|
for (const entry of entries) {
|
|
@@ -7,10 +7,9 @@ const GMAIL_SETTINGS_BASIC_SCOPE =
|
|
|
7
7
|
/**
|
|
8
8
|
* Backfill the `gmail.settings.basic` scope for existing Google provider rows.
|
|
9
9
|
*
|
|
10
|
-
* The scope was added to PROVIDER_SEED_DATA in #25970
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* that already had a `google` provider row never picked up the new scope.
|
|
10
|
+
* The scope was added to PROVIDER_SEED_DATA in #25970. This migration ensures
|
|
11
|
+
* existing workspace rows that were created before the seed update also include
|
|
12
|
+
* the scope.
|
|
14
13
|
*
|
|
15
14
|
* This migration reads the current `defaultScopes` JSON array for the `google`
|
|
16
15
|
* provider and appends the scope if it is not already present.
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Seed a latency-optimized default for the `conversationStarters` LLM
|
|
8
|
+
* call site.
|
|
9
|
+
*
|
|
10
|
+
* `conversationStarters` drives the reply-suggestion chip rendered in the
|
|
11
|
+
* macOS client after every assistant turn. Migration 040 seeded most
|
|
12
|
+
* trivial copy-generation call sites to haiku-4.5 but missed this one, so
|
|
13
|
+
* it falls through to `llm.default` — on workspaces where the default is
|
|
14
|
+
* a high-effort / extended-thinking configured model (e.g. Opus 4.x at
|
|
15
|
+
* `effort: "xhigh"`), every turn completion kicks off an expensive
|
|
16
|
+
* reasoning call that, to add insult to injury, rejects the assistant
|
|
17
|
+
* message prefill the suggestion generator previously relied on with an
|
|
18
|
+
* HTTP 400.
|
|
19
|
+
*
|
|
20
|
+
* Follows the same contract as `040-seed-latency-callsite-defaults`:
|
|
21
|
+
* - Skip entirely when `VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH` is set
|
|
22
|
+
* (platform overlay owns call-site seeds).
|
|
23
|
+
* - Skip when the resolved provider is not Anthropic (the seeded
|
|
24
|
+
* model IDs are Anthropic-shaped, so mixing with another provider
|
|
25
|
+
* would guarantee invalid-model errors).
|
|
26
|
+
* - No-op when `llm.callSites.conversationStarters` is already set.
|
|
27
|
+
*
|
|
28
|
+
* Idempotent, append-only — existing 040 entries are untouched.
|
|
29
|
+
*/
|
|
30
|
+
export const seedConversationStartersCallsiteMigration: WorkspaceMigration = {
|
|
31
|
+
id: "046-seed-conversation-starters-callsite",
|
|
32
|
+
description:
|
|
33
|
+
"Seed latency-optimized default for conversationStarters LLM call site",
|
|
34
|
+
run(workspaceDir: string): void {
|
|
35
|
+
if (process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH) return;
|
|
36
|
+
|
|
37
|
+
const configPath = join(workspaceDir, "config.json");
|
|
38
|
+
const configExisted = existsSync(configPath);
|
|
39
|
+
|
|
40
|
+
let config: Record<string, unknown> = {};
|
|
41
|
+
if (configExisted) {
|
|
42
|
+
try {
|
|
43
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
44
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
45
|
+
config = raw as Record<string, unknown>;
|
|
46
|
+
} catch {
|
|
47
|
+
return;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const llm = readObject(config.llm) ?? {};
|
|
52
|
+
const defaultBlock = readObject(llm.default);
|
|
53
|
+
|
|
54
|
+
const explicitProvider = readString(defaultBlock?.provider);
|
|
55
|
+
if (
|
|
56
|
+
explicitProvider !== undefined &&
|
|
57
|
+
explicitProvider !== "anthropic" &&
|
|
58
|
+
explicitProvider !== "openrouter"
|
|
59
|
+
) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const provider = explicitProvider ?? "anthropic";
|
|
63
|
+
const fastModel = resolveLatencyModel(provider);
|
|
64
|
+
if (fastModel === undefined) return;
|
|
65
|
+
|
|
66
|
+
const callSites = readObject(llm.callSites) ?? {};
|
|
67
|
+
if (readObject(callSites.conversationStarters) !== null) return;
|
|
68
|
+
|
|
69
|
+
callSites.conversationStarters = {
|
|
70
|
+
model: fastModel,
|
|
71
|
+
effort: "low",
|
|
72
|
+
thinking: { enabled: false },
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
llm.callSites = callSites;
|
|
76
|
+
config.llm = llm;
|
|
77
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
78
|
+
},
|
|
79
|
+
down(_workspaceDir: string): void {
|
|
80
|
+
// Forward-only: removing the seeded default would reintroduce the
|
|
81
|
+
// cost/latency regression and the assistant-prefill 400 that this
|
|
82
|
+
// migration fixes.
|
|
83
|
+
},
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
// ---------------------------------------------------------------------------
|
|
87
|
+
// Helpers — self-contained per workspace migrations AGENTS.md
|
|
88
|
+
// ---------------------------------------------------------------------------
|
|
89
|
+
|
|
90
|
+
const PROVIDER_LATENCY_MODELS: Record<string, string> = {
|
|
91
|
+
anthropic: "claude-haiku-4-5-20251001",
|
|
92
|
+
openrouter: "anthropic/claude-haiku-4.5",
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
function resolveLatencyModel(provider: string): string | undefined {
|
|
96
|
+
return PROVIDER_LATENCY_MODELS[provider];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
100
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
return value as Record<string, unknown>;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
function readString(value: unknown): string | undefined {
|
|
107
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
108
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Remove `watchCommentary` and `watchSummary` entries from
|
|
8
|
+
* `llm.callSites` in existing config files. These call-sites were seeded
|
|
9
|
+
* by migration 040 but the screen-watch feature has been removed, so the
|
|
10
|
+
* keys are no longer valid members of the `LLMCallSiteEnum` and would
|
|
11
|
+
* trigger repeated validation warnings if left on disk.
|
|
12
|
+
*/
|
|
13
|
+
export const removeWatchCallsitesMigration: WorkspaceMigration = {
|
|
14
|
+
id: "047-remove-watch-callsites",
|
|
15
|
+
description:
|
|
16
|
+
"Remove watchCommentary and watchSummary from llm.callSites (screen-watch removed)",
|
|
17
|
+
run(workspaceDir: string): void {
|
|
18
|
+
const configPath = join(workspaceDir, "config.json");
|
|
19
|
+
if (!existsSync(configPath)) return;
|
|
20
|
+
|
|
21
|
+
let config: Record<string, unknown>;
|
|
22
|
+
try {
|
|
23
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
24
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
25
|
+
config = raw as Record<string, unknown>;
|
|
26
|
+
} catch {
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const llm = config.llm;
|
|
31
|
+
if (!llm || typeof llm !== "object" || Array.isArray(llm)) return;
|
|
32
|
+
|
|
33
|
+
const callSites = (llm as Record<string, unknown>).callSites;
|
|
34
|
+
if (!callSites || typeof callSites !== "object" || Array.isArray(callSites))
|
|
35
|
+
return;
|
|
36
|
+
|
|
37
|
+
const sites = callSites as Record<string, unknown>;
|
|
38
|
+
let mutated = false;
|
|
39
|
+
|
|
40
|
+
for (const key of ["watchCommentary", "watchSummary"]) {
|
|
41
|
+
if (key in sites) {
|
|
42
|
+
delete sites[key];
|
|
43
|
+
mutated = true;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
if (!mutated) return;
|
|
48
|
+
|
|
49
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
50
|
+
},
|
|
51
|
+
down(_workspaceDir: string): void {
|
|
52
|
+
// no-op — keys are obsolete
|
|
53
|
+
},
|
|
54
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Workspace migration 046: Remove legacy `workspace/hooks/` directory.
|
|
3
|
+
*
|
|
4
|
+
* Migration 022 moved `~/.vellum/hooks/` into `~/.vellum/workspace/hooks/`.
|
|
5
|
+
* With the hook system entirely removed, that directory is dead state — it is
|
|
6
|
+
* no longer read or written by the assistant. This migration deletes the
|
|
7
|
+
* directory (and everything under it) so stale hook manifests, config, and
|
|
8
|
+
* executables do not linger in user workspaces.
|
|
9
|
+
*
|
|
10
|
+
* Idempotent: safe to re-run after interruption. A no-op when the directory
|
|
11
|
+
* is already absent.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import { existsSync, readdirSync, rmSync, statSync } from "node:fs";
|
|
15
|
+
import { join } from "node:path";
|
|
16
|
+
|
|
17
|
+
import { getLogger } from "../../util/logger.js";
|
|
18
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
19
|
+
|
|
20
|
+
const log = getLogger("workspace-migration-048-remove-workspace-hooks");
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Count files under `dir` recursively. Best-effort — returns the count we
|
|
24
|
+
* could successfully stat, and silently skips entries that fail (e.g. a
|
|
25
|
+
* symlink whose target is missing, a file removed concurrently). This is
|
|
26
|
+
* only used for log output, so a slightly stale count is acceptable.
|
|
27
|
+
*/
|
|
28
|
+
function countFilesRecursive(dir: string): number {
|
|
29
|
+
let count = 0;
|
|
30
|
+
let entries: string[];
|
|
31
|
+
try {
|
|
32
|
+
entries = readdirSync(dir);
|
|
33
|
+
} catch {
|
|
34
|
+
return 0;
|
|
35
|
+
}
|
|
36
|
+
for (const entry of entries) {
|
|
37
|
+
const entryPath = join(dir, entry);
|
|
38
|
+
try {
|
|
39
|
+
const s = statSync(entryPath);
|
|
40
|
+
if (s.isDirectory()) {
|
|
41
|
+
count += countFilesRecursive(entryPath);
|
|
42
|
+
} else {
|
|
43
|
+
count += 1;
|
|
44
|
+
}
|
|
45
|
+
} catch {
|
|
46
|
+
// best-effort
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
return count;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
export const removeWorkspaceHooksMigration: WorkspaceMigration = {
|
|
53
|
+
id: "048-remove-workspace-hooks",
|
|
54
|
+
description:
|
|
55
|
+
"Remove legacy workspace/hooks/ directory now that the hook system is gone",
|
|
56
|
+
|
|
57
|
+
run(workspaceDir: string): void {
|
|
58
|
+
const hooksDir = join(workspaceDir, "hooks");
|
|
59
|
+
if (!existsSync(hooksDir)) return;
|
|
60
|
+
|
|
61
|
+
const fileCount = countFilesRecursive(hooksDir);
|
|
62
|
+
try {
|
|
63
|
+
rmSync(hooksDir, { recursive: true, force: true });
|
|
64
|
+
log.info(
|
|
65
|
+
{ path: hooksDir, fileCount },
|
|
66
|
+
"Removed legacy workspace hooks directory",
|
|
67
|
+
);
|
|
68
|
+
} catch (err) {
|
|
69
|
+
log.warn(
|
|
70
|
+
{ err, path: hooksDir },
|
|
71
|
+
"Failed to remove legacy workspace hooks directory; leaving in place",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
down(_workspaceDir: string): void {
|
|
77
|
+
// Forward-only: the hook system is gone and the directory contained no
|
|
78
|
+
// data the assistant still consumes. Restoring an empty directory would
|
|
79
|
+
// just reintroduce dead state.
|
|
80
|
+
},
|
|
81
|
+
};
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import {
|
|
2
|
+
appendFileSync,
|
|
3
|
+
existsSync,
|
|
4
|
+
readFileSync,
|
|
5
|
+
writeFileSync,
|
|
6
|
+
} from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
|
|
9
|
+
import { getLogger } from "../../util/logger.js";
|
|
10
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
11
|
+
|
|
12
|
+
const log = getLogger("workspace-migration-049-release-notes-default-sonnet");
|
|
13
|
+
|
|
14
|
+
const MIGRATION_ID = "049-release-notes-default-sonnet";
|
|
15
|
+
const MARKER = `<!-- release-note-id:${MIGRATION_ID} -->`;
|
|
16
|
+
|
|
17
|
+
const RELEASE_NOTE = `${MARKER}
|
|
18
|
+
## Default LLM is now Claude Sonnet 4.6 (main agent stays on Opus)
|
|
19
|
+
|
|
20
|
+
The schema-level default for \`llm.default.model\` is now
|
|
21
|
+
\`claude-sonnet-4-6\` instead of \`claude-opus-4-7\`, so background call
|
|
22
|
+
sites that fall through to the default now use Sonnet. If you've
|
|
23
|
+
already chosen a model, your persisted config takes precedence.
|
|
24
|
+
|
|
25
|
+
The main agent conversation loop remains on Opus: a companion
|
|
26
|
+
migration seeds \`llm.callSites.mainAgent = { model: "claude-opus-4-7" }\`
|
|
27
|
+
when it's unset, and the \`quality-optimized\` model intent also still
|
|
28
|
+
resolves to Opus.
|
|
29
|
+
|
|
30
|
+
To switch the main agent to Sonnet, clear the call-site override:
|
|
31
|
+
|
|
32
|
+
\`\`\`bash
|
|
33
|
+
assistant config unset llm.callSites.mainAgent
|
|
34
|
+
\`\`\`
|
|
35
|
+
|
|
36
|
+
To switch the overall default back to Opus, run:
|
|
37
|
+
|
|
38
|
+
\`\`\`bash
|
|
39
|
+
assistant config set llm.default.model claude-opus-4-7
|
|
40
|
+
\`\`\`
|
|
41
|
+
`;
|
|
42
|
+
|
|
43
|
+
export const releaseNotesDefaultSonnetMigration: WorkspaceMigration = {
|
|
44
|
+
id: MIGRATION_ID,
|
|
45
|
+
description:
|
|
46
|
+
"Append release notes for default LLM switch to Claude Sonnet 4.6 to UPDATES.md",
|
|
47
|
+
|
|
48
|
+
run(workspaceDir: string): void {
|
|
49
|
+
const updatesPath = join(workspaceDir, "UPDATES.md");
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
if (existsSync(updatesPath)) {
|
|
53
|
+
const existing = readFileSync(updatesPath, "utf-8");
|
|
54
|
+
if (existing.includes(MARKER)) {
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
const needsLeadingNewline = !existing.endsWith("\n\n");
|
|
58
|
+
const prefix = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
59
|
+
appendFileSync(
|
|
60
|
+
updatesPath,
|
|
61
|
+
needsLeadingNewline ? `${prefix}${RELEASE_NOTE}` : RELEASE_NOTE,
|
|
62
|
+
"utf-8",
|
|
63
|
+
);
|
|
64
|
+
} else {
|
|
65
|
+
writeFileSync(updatesPath, RELEASE_NOTE, "utf-8");
|
|
66
|
+
}
|
|
67
|
+
log.info({ path: updatesPath }, "Appended default-Sonnet release note");
|
|
68
|
+
} catch (err) {
|
|
69
|
+
log.warn(
|
|
70
|
+
{ err, path: updatesPath },
|
|
71
|
+
"Failed to append default-Sonnet release note to UPDATES.md",
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
|
|
76
|
+
down(_workspaceDir: string): void {
|
|
77
|
+
// Forward-only: UPDATES.md is a user-facing bulletin the assistant
|
|
78
|
+
// processes and deletes on its own.
|
|
79
|
+
},
|
|
80
|
+
};
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
4
|
+
import type { WorkspaceMigration } from "./types.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Seed `callSites.mainAgent = { model: "claude-opus-4-7" }` so the main
|
|
8
|
+
* agent conversation loop stays on Opus even though the schema-level
|
|
9
|
+
* default dropped to Sonnet. Runs in two modes, mirroring migration 040:
|
|
10
|
+
*
|
|
11
|
+
* 1. **Existing workspace** (config.json present): merge the seed into
|
|
12
|
+
* `llm.callSites` without overwriting a user-defined override.
|
|
13
|
+
* 2. **Fresh install** (config.json absent): write a minimal starter
|
|
14
|
+
* config with just this seed. `loadConfig()` runs after migrations
|
|
15
|
+
* and backfills the remaining schema defaults via `deepMergeMissing`.
|
|
16
|
+
*
|
|
17
|
+
* Applied only when:
|
|
18
|
+
* - the resolved provider is Anthropic (other providers own their
|
|
19
|
+
* own mainAgent model choice), **and**
|
|
20
|
+
* - `llm.default.model` is either unset or equal to the previous
|
|
21
|
+
* schema default `claude-opus-4-7` — a user who explicitly picked
|
|
22
|
+
* a different Anthropic model (e.g. Haiku) kept their own choice,
|
|
23
|
+
* so forcing Opus onto their mainAgent would be surprising.
|
|
24
|
+
*/
|
|
25
|
+
export const seedMainAgentOpusCallsiteMigration: WorkspaceMigration = {
|
|
26
|
+
id: "050-seed-main-agent-opus-callsite",
|
|
27
|
+
description: "Seed callSites.mainAgent to claude-opus-4-7 for Anthropic",
|
|
28
|
+
run(workspaceDir: string): void {
|
|
29
|
+
// Defer to platform-provided overlays.
|
|
30
|
+
if (process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH) return;
|
|
31
|
+
|
|
32
|
+
const configPath = join(workspaceDir, "config.json");
|
|
33
|
+
const configExisted = existsSync(configPath);
|
|
34
|
+
|
|
35
|
+
let config: Record<string, unknown> = {};
|
|
36
|
+
if (configExisted) {
|
|
37
|
+
try {
|
|
38
|
+
const raw = JSON.parse(readFileSync(configPath, "utf-8"));
|
|
39
|
+
if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
|
|
40
|
+
config = raw as Record<string, unknown>;
|
|
41
|
+
} catch {
|
|
42
|
+
return;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
const llm = readObject(config.llm) ?? {};
|
|
47
|
+
const defaultBlock = readObject(llm.default);
|
|
48
|
+
|
|
49
|
+
const explicitProvider = readString(defaultBlock?.provider);
|
|
50
|
+
if (explicitProvider !== undefined && explicitProvider !== "anthropic") {
|
|
51
|
+
return;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const explicitModel = readString(defaultBlock?.model);
|
|
55
|
+
if (explicitModel !== undefined && explicitModel !== "claude-opus-4-7") {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const callSites = readObject(llm.callSites) ?? {};
|
|
60
|
+
|
|
61
|
+
if (readObject(callSites.mainAgent) !== null) return;
|
|
62
|
+
|
|
63
|
+
// maxTokens: 32000 matches Opus's maxOutputTokens (see
|
|
64
|
+
// model-catalog.ts); without it the site would inherit the
|
|
65
|
+
// default's 64000 and overshoot the model capability.
|
|
66
|
+
callSites.mainAgent = { model: "claude-opus-4-7", maxTokens: 32000 };
|
|
67
|
+
llm.callSites = callSites;
|
|
68
|
+
config.llm = llm;
|
|
69
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
|
|
70
|
+
},
|
|
71
|
+
down(_workspaceDir: string): void {
|
|
72
|
+
// Forward-only: removing the seed would silently downgrade the main
|
|
73
|
+
// agent loop to Sonnet on every re-run.
|
|
74
|
+
},
|
|
75
|
+
};
|
|
76
|
+
|
|
77
|
+
function readObject(value: unknown): Record<string, unknown> | null {
|
|
78
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
79
|
+
return null;
|
|
80
|
+
}
|
|
81
|
+
return value as Record<string, unknown>;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function readString(value: unknown): string | undefined {
|
|
85
|
+
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
86
|
+
}
|