@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
|
@@ -36,6 +36,7 @@ import {
|
|
|
36
36
|
handleVoiceWebhook,
|
|
37
37
|
} from "../calls/twilio-routes.js";
|
|
38
38
|
import { parseChannelId } from "../channels/types.js";
|
|
39
|
+
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
39
40
|
import {
|
|
40
41
|
getGatewayInternalBaseUrl,
|
|
41
42
|
hasUngatedHttpAuthDisabled,
|
|
@@ -53,7 +54,10 @@ import {
|
|
|
53
54
|
type SignalType,
|
|
54
55
|
} from "../memory/conversation-attention-store.js";
|
|
55
56
|
import {
|
|
57
|
+
addMessage,
|
|
56
58
|
type ConversationRow,
|
|
59
|
+
createConversation,
|
|
60
|
+
deleteConversation,
|
|
57
61
|
forkConversation as forkConversationInStore,
|
|
58
62
|
getConversation,
|
|
59
63
|
getDisplayMetaForConversations,
|
|
@@ -62,11 +66,13 @@ import { resolveConversationId } from "../memory/conversation-key-store.js";
|
|
|
62
66
|
import {
|
|
63
67
|
countConversations,
|
|
64
68
|
listConversations,
|
|
69
|
+
listConversationsByTitlePrefix,
|
|
65
70
|
listPinnedConversations,
|
|
66
71
|
} from "../memory/conversation-queries.js";
|
|
67
72
|
import type { ExternalConversationBinding } from "../memory/external-conversation-store.js";
|
|
68
73
|
import * as externalConversationStore from "../memory/external-conversation-store.js";
|
|
69
74
|
import { listGroups } from "../memory/group-crud.js";
|
|
75
|
+
import { enqueueMemoryJob } from "../memory/jobs-store.js";
|
|
70
76
|
import { resolveStreamingTranscriber } from "../providers/speech-to-text/resolve.js";
|
|
71
77
|
import {
|
|
72
78
|
consumeCallback,
|
|
@@ -206,6 +212,7 @@ import {
|
|
|
206
212
|
handlePairingStatus,
|
|
207
213
|
pairingRouteDefinitions,
|
|
208
214
|
} from "./routes/pairing-routes.js";
|
|
215
|
+
import { playgroundRouteDefinitions } from "./routes/playground/index.js";
|
|
209
216
|
import { profilerRouteDefinitions } from "./routes/profiler-routes.js";
|
|
210
217
|
import { recordingRouteDefinitions } from "./routes/recording-routes.js";
|
|
211
218
|
import { scheduleRouteDefinitions } from "./routes/schedule-routes.js";
|
|
@@ -223,7 +230,6 @@ import { ttsRouteDefinitions } from "./routes/tts-routes.js";
|
|
|
223
230
|
import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
|
|
224
231
|
import { usageRouteDefinitions } from "./routes/usage-routes.js";
|
|
225
232
|
import { userRouteDefinitions } from "./routes/user-routes.js";
|
|
226
|
-
import { watchRouteDefinitions } from "./routes/watch-routes.js";
|
|
227
233
|
import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
|
|
228
234
|
import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
|
|
229
235
|
import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
|
|
@@ -356,7 +362,6 @@ export class RuntimeHttpServer {
|
|
|
356
362
|
private getSkillContext?: RuntimeHttpServerOptions["getSkillContext"];
|
|
357
363
|
private conversationManagementDeps?: RuntimeHttpServerOptions["conversationManagementDeps"];
|
|
358
364
|
private getModelSetContext?: RuntimeHttpServerOptions["getModelSetContext"];
|
|
359
|
-
private getWatchDeps?: RuntimeHttpServerOptions["getWatchDeps"];
|
|
360
365
|
private getRecordingDeps?: RuntimeHttpServerOptions["getRecordingDeps"];
|
|
361
366
|
private getCesClient?: RuntimeHttpServerOptions["getCesClient"];
|
|
362
367
|
private onProviderCredentialsChanged?: RuntimeHttpServerOptions["onProviderCredentialsChanged"];
|
|
@@ -381,7 +386,6 @@ export class RuntimeHttpServer {
|
|
|
381
386
|
this.getSkillContext = options.getSkillContext;
|
|
382
387
|
this.conversationManagementDeps = options.conversationManagementDeps;
|
|
383
388
|
this.getModelSetContext = options.getModelSetContext;
|
|
384
|
-
this.getWatchDeps = options.getWatchDeps;
|
|
385
389
|
this.getRecordingDeps = options.getRecordingDeps;
|
|
386
390
|
this.getCesClient = options.getCesClient;
|
|
387
391
|
this.onProviderCredentialsChanged = options.onProviderCredentialsChanged;
|
|
@@ -1995,6 +1999,76 @@ export class RuntimeHttpServer {
|
|
|
1995
1999
|
suggestionInFlight: this.suggestionInFlight,
|
|
1996
2000
|
getHeartbeatService: this.getHeartbeatService,
|
|
1997
2001
|
}),
|
|
2002
|
+
...playgroundRouteDefinitions({
|
|
2003
|
+
getConversationById: async (id) => {
|
|
2004
|
+
// Gate on DB existence first so genuinely-missing IDs return
|
|
2005
|
+
// `undefined` (preserving the route handlers' 404 path) rather
|
|
2006
|
+
// than triggering `getOrCreateConversation`'s create branch and
|
|
2007
|
+
// masking the not-found case. For existing-but-not-loaded rows
|
|
2008
|
+
// (e.g. freshly seeded by `POST /playground/seed-conversation`),
|
|
2009
|
+
// hydrate the in-memory `Conversation` on demand so conv-scoped
|
|
2010
|
+
// playground routes work without first opening the conversation
|
|
2011
|
+
// in the main window.
|
|
2012
|
+
if (!getConversation(id)) return undefined;
|
|
2013
|
+
const sendDeps = this.sendMessageDeps;
|
|
2014
|
+
if (!sendDeps) {
|
|
2015
|
+
// Fall back to the in-memory active map when the daemon hasn't
|
|
2016
|
+
// wired the hydration-capable accessor (e.g. unit tests).
|
|
2017
|
+
const s = this.findConversation?.(id);
|
|
2018
|
+
if (!s || !("abort" in s)) return undefined;
|
|
2019
|
+
return s as import("../daemon/conversation.js").Conversation;
|
|
2020
|
+
}
|
|
2021
|
+
return sendDeps.getOrCreateConversation(id);
|
|
2022
|
+
},
|
|
2023
|
+
isPlaygroundEnabled: () =>
|
|
2024
|
+
isAssistantFeatureFlagEnabled("compaction-playground", getConfig()),
|
|
2025
|
+
listConversationsByTitlePrefix: (prefix) =>
|
|
2026
|
+
listConversationsByTitlePrefix(prefix),
|
|
2027
|
+
deleteConversationById: (id) => {
|
|
2028
|
+
// Existence check first so we can report `false` for missing rows
|
|
2029
|
+
// — `deleteConversation` always returns a result object even when
|
|
2030
|
+
// no row matched.
|
|
2031
|
+
if (!getConversation(id)) return false;
|
|
2032
|
+
// Mirror the canonical DELETE /v1/conversations/:id handler in
|
|
2033
|
+
// conversation-management-routes.ts: tear down the in-memory
|
|
2034
|
+
// Conversation first (so a running agent loop can't write to a
|
|
2035
|
+
// deleted row and trip FK constraints), then drop the DB row,
|
|
2036
|
+
// then enqueue Qdrant vector cleanup for the returned segment
|
|
2037
|
+
// and summary IDs. Without this, seeded-then-deleted playground
|
|
2038
|
+
// conversations leak vectors and zombie Conversation objects.
|
|
2039
|
+
if (this.findConversation?.(id)) {
|
|
2040
|
+
this.conversationManagementDeps?.destroyConversation(id);
|
|
2041
|
+
}
|
|
2042
|
+
const deleted = deleteConversation(id);
|
|
2043
|
+
for (const segId of deleted.segmentIds) {
|
|
2044
|
+
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
2045
|
+
targetType: "segment",
|
|
2046
|
+
targetId: segId,
|
|
2047
|
+
});
|
|
2048
|
+
}
|
|
2049
|
+
for (const summaryId of deleted.deletedSummaryIds) {
|
|
2050
|
+
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
2051
|
+
targetType: "summary",
|
|
2052
|
+
targetId: summaryId,
|
|
2053
|
+
});
|
|
2054
|
+
}
|
|
2055
|
+
return true;
|
|
2056
|
+
},
|
|
2057
|
+
createConversation: async (title) => {
|
|
2058
|
+
const row = createConversation({ title });
|
|
2059
|
+
return { id: row.id };
|
|
2060
|
+
},
|
|
2061
|
+
addMessage: async (conversationId, role, contentJson, options) => {
|
|
2062
|
+
const persisted = await addMessage(
|
|
2063
|
+
conversationId,
|
|
2064
|
+
role,
|
|
2065
|
+
contentJson,
|
|
2066
|
+
undefined,
|
|
2067
|
+
options,
|
|
2068
|
+
);
|
|
2069
|
+
return { id: persisted.id };
|
|
2070
|
+
},
|
|
2071
|
+
}),
|
|
1998
2072
|
...globalSearchRouteDefinitions(),
|
|
1999
2073
|
...approvalRouteDefinitions(),
|
|
2000
2074
|
...hostBashRouteDefinitions(),
|
|
@@ -2032,11 +2106,6 @@ export class RuntimeHttpServer {
|
|
|
2032
2106
|
...oauthAppsRouteDefinitions(),
|
|
2033
2107
|
...attachmentRouteDefinitions(),
|
|
2034
2108
|
|
|
2035
|
-
...(this.getWatchDeps
|
|
2036
|
-
? watchRouteDefinitions({
|
|
2037
|
-
getWatchDeps: this.getWatchDeps,
|
|
2038
|
-
})
|
|
2039
|
-
: []),
|
|
2040
2109
|
...(this.getRecordingDeps
|
|
2041
2110
|
? recordingRouteDefinitions({
|
|
2042
2111
|
getRecordingDeps: this.getRecordingDeps,
|
|
@@ -248,8 +248,6 @@ export interface RuntimeHttpServerOptions {
|
|
|
248
248
|
conversationManagementDeps?: ConversationManagementDeps;
|
|
249
249
|
/** Lazy factory for model config set context (conversation eviction, config reload suppression). */
|
|
250
250
|
getModelSetContext?: () => import("../daemon/handlers/config-model.js").ModelSetContext;
|
|
251
|
-
/** Provider for watch observation dependencies (watch routes). */
|
|
252
|
-
getWatchDeps?: () => import("./routes/watch-routes.js").WatchDeps;
|
|
253
251
|
/** Provider for recording dependencies (recording routes). */
|
|
254
252
|
getRecordingDeps?: () => import("./routes/recording-routes.js").RecordingDeps;
|
|
255
253
|
/** Accessor for the CES client, used to push API key updates to CES after hatch. */
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* A .vbundle is a gzip-compressed tar archive containing:
|
|
5
5
|
* - manifest.json: metadata with schema_version, checksums, and bundle info
|
|
6
6
|
* - workspace/: the entire ~/.vellum/workspace/ directory tree (DB, config,
|
|
7
|
-
* skills,
|
|
7
|
+
* skills, prompts, attachments, etc.) — excluding large/regenerable
|
|
8
8
|
* dirs (embedding-models/, data/qdrant/)
|
|
9
9
|
* - trust/trust.json: trust rules (optional, lives in protected/ outside workspace)
|
|
10
10
|
*/
|
|
@@ -429,15 +429,6 @@ export interface BuildExportVBundleOptions {
|
|
|
429
429
|
description?: string;
|
|
430
430
|
/** Absolute path to trust.json. If provided and the file exists, it is included in the archive. */
|
|
431
431
|
trustPath?: string;
|
|
432
|
-
/**
|
|
433
|
-
* Absolute path to the hooks directory. Previously hooks lived outside the
|
|
434
|
-
* workspace at ~/.vellum/hooks/ and needed explicit inclusion. Now hooks
|
|
435
|
-
* live under workspace (~/.vellum/workspace/hooks/) and are included in
|
|
436
|
-
* the workspace walk. Only pass this for backward-compat scenarios where
|
|
437
|
-
* hooks are still outside the workspace; otherwise omit to avoid double
|
|
438
|
-
* export. Included in the archive under the "hooks/" prefix.
|
|
439
|
-
*/
|
|
440
|
-
hooksDir?: string;
|
|
441
432
|
/**
|
|
442
433
|
* Absolute path to the workspace directory (~/.vellum/workspace/).
|
|
443
434
|
* When provided and exists, the entire directory tree is walked and
|
|
@@ -479,7 +470,6 @@ export function buildExportVBundle(
|
|
|
479
470
|
checkpoint,
|
|
480
471
|
trustPath,
|
|
481
472
|
workspaceDir,
|
|
482
|
-
hooksDir,
|
|
483
473
|
credentials,
|
|
484
474
|
} = options;
|
|
485
475
|
|
|
@@ -515,11 +505,6 @@ export function buildExportVBundle(
|
|
|
515
505
|
configEntry.data = new TextEncoder().encode(sanitized);
|
|
516
506
|
}
|
|
517
507
|
|
|
518
|
-
// Include hooks directory if it exists (lives at ~/.vellum/hooks/, outside workspace).
|
|
519
|
-
if (hooksDir && existsSync(hooksDir) && lstatSync(hooksDir).isDirectory()) {
|
|
520
|
-
files.push(...walkDirectory(hooksDir, "hooks"));
|
|
521
|
-
}
|
|
522
|
-
|
|
523
508
|
// Include trust rules if the file exists (lives in protected/, outside workspace).
|
|
524
509
|
if (trustPath && existsSync(trustPath)) {
|
|
525
510
|
const trustData = new Uint8Array(readFileSync(trustPath));
|
|
@@ -820,7 +805,6 @@ export async function streamExportVBundle(
|
|
|
820
805
|
checkpoint,
|
|
821
806
|
trustPath,
|
|
822
807
|
workspaceDir,
|
|
823
|
-
hooksDir,
|
|
824
808
|
credentials,
|
|
825
809
|
} = options;
|
|
826
810
|
|
|
@@ -845,11 +829,6 @@ export async function streamExportVBundle(
|
|
|
845
829
|
);
|
|
846
830
|
}
|
|
847
831
|
|
|
848
|
-
// Include hooks directory if it exists
|
|
849
|
-
if (hooksDir && existsSync(hooksDir) && lstatSync(hooksDir).isDirectory()) {
|
|
850
|
-
allFileMetadata.push(...walkDirectoryForMetadata(hooksDir, "hooks"));
|
|
851
|
-
}
|
|
852
|
-
|
|
853
832
|
// Include trust rules if the file exists
|
|
854
833
|
if (trustPath && existsSync(trustPath)) {
|
|
855
834
|
const trustStat = lstatSync(trustPath);
|
|
@@ -1,40 +1,52 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Persistent tracker for approval prompt message timestamps.
|
|
3
3
|
*
|
|
4
|
-
* Scopes guardian reaction approvals so only reactions on a known
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
4
|
+
* Scopes guardian reaction approvals so only reactions on a known approval
|
|
5
|
+
* prompt can resolve a pending request. Without this, a stray 👍/✅ on any
|
|
6
|
+
* message in the guardian chat could approve a pending request (since
|
|
7
|
+
* reactions are now admitted from any subscribed channel, not just tracked
|
|
8
|
+
* bot threads).
|
|
9
9
|
*
|
|
10
|
-
* Entries
|
|
11
|
-
*
|
|
12
|
-
* prompt
|
|
13
|
-
*
|
|
10
|
+
* Entries are stored in the `approval_prompt_ts_tracker` table (created by
|
|
11
|
+
* `createApprovalPromptTsTrackerTable`) so that a daemon restart between
|
|
12
|
+
* prompt delivery and guardian reaction does not silently invalidate
|
|
13
|
+
* reactions that are still within the 30-minute guardian approval TTL.
|
|
14
|
+
* Entries expire after `APPROVAL_PROMPT_TS_TTL_MS` (guardian approval TTL
|
|
15
|
+
* plus grace).
|
|
14
16
|
*/
|
|
17
|
+
import { getSqlite } from "../../memory/db-connection.js";
|
|
18
|
+
import { getLogger } from "../../util/logger.js";
|
|
15
19
|
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const tracked = new Map<string, number>();
|
|
20
|
+
const log = getLogger("runtime-http");
|
|
19
21
|
|
|
20
|
-
|
|
21
|
-
return `${channel}\u0000${chatId}\u0000${ts}`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function pruneExpired(now: number): void {
|
|
25
|
-
for (const [k, expiresAt] of tracked) {
|
|
26
|
-
if (expiresAt <= now) tracked.delete(k);
|
|
27
|
-
}
|
|
28
|
-
}
|
|
22
|
+
const APPROVAL_PROMPT_TS_TTL_MS = 35 * 60 * 1000;
|
|
29
23
|
|
|
24
|
+
// Swallow errors: callers run this inside their delivery try/catch, so a
|
|
25
|
+
// tracker throw would be misread as a delivery failure and trigger
|
|
26
|
+
// fallback/retry, double-posting the guardian prompt.
|
|
30
27
|
export function trackApprovalPromptTs(
|
|
31
28
|
channel: string,
|
|
32
29
|
chatId: string,
|
|
33
30
|
ts: string,
|
|
34
31
|
): void {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
32
|
+
try {
|
|
33
|
+
const now = Date.now();
|
|
34
|
+
const expiresAt = now + APPROVAL_PROMPT_TS_TTL_MS;
|
|
35
|
+
const db = getSqlite();
|
|
36
|
+
db.run(
|
|
37
|
+
/*sql*/ `DELETE FROM approval_prompt_ts_tracker WHERE expires_at <= ?`,
|
|
38
|
+
[now],
|
|
39
|
+
);
|
|
40
|
+
db.run(
|
|
41
|
+
/*sql*/ `INSERT OR REPLACE INTO approval_prompt_ts_tracker (channel, chat_id, ts, expires_at) VALUES (?, ?, ?, ?)`,
|
|
42
|
+
[channel, chatId, ts, expiresAt],
|
|
43
|
+
);
|
|
44
|
+
} catch (err) {
|
|
45
|
+
log.error(
|
|
46
|
+
{ err, channel, chatId, ts },
|
|
47
|
+
"Failed to persist approval prompt ts tracker entry; continuing without tracking",
|
|
48
|
+
);
|
|
49
|
+
}
|
|
38
50
|
}
|
|
39
51
|
|
|
40
52
|
export function isTrackedApprovalPromptTs(
|
|
@@ -42,11 +54,19 @@ export function isTrackedApprovalPromptTs(
|
|
|
42
54
|
chatId: string,
|
|
43
55
|
ts: string,
|
|
44
56
|
): boolean {
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
57
|
+
const now = Date.now();
|
|
58
|
+
const db = getSqlite();
|
|
59
|
+
const row = db
|
|
60
|
+
.query(
|
|
61
|
+
/*sql*/ `SELECT expires_at FROM approval_prompt_ts_tracker WHERE channel = ? AND chat_id = ? AND ts = ?`,
|
|
62
|
+
)
|
|
63
|
+
.get(channel, chatId, ts) as { expires_at: number } | null;
|
|
64
|
+
if (!row) return false;
|
|
65
|
+
if (row.expires_at <= now) {
|
|
66
|
+
db.run(
|
|
67
|
+
/*sql*/ `DELETE FROM approval_prompt_ts_tracker WHERE channel = ? AND chat_id = ? AND ts = ?`,
|
|
68
|
+
[channel, chatId, ts],
|
|
69
|
+
);
|
|
50
70
|
return false;
|
|
51
71
|
}
|
|
52
72
|
return true;
|
|
@@ -54,5 +74,5 @@ export function isTrackedApprovalPromptTs(
|
|
|
54
74
|
|
|
55
75
|
/** @internal Test-only — clear all tracked entries. */
|
|
56
76
|
export function _clearApprovalPromptTsTrackerForTesting(): void {
|
|
57
|
-
|
|
77
|
+
getSqlite().run(/*sql*/ `DELETE FROM approval_prompt_ts_tracker`);
|
|
58
78
|
}
|
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
*/
|
|
11
11
|
import { z } from "zod";
|
|
12
12
|
|
|
13
|
+
import { emitFeedEvent } from "../../home/emit-feed-event.js";
|
|
13
14
|
import { getConversationByKey } from "../../memory/conversation-key-store.js";
|
|
14
15
|
import { addRule } from "../../permissions/trust-store.js";
|
|
15
16
|
import type { UserDecision } from "../../permissions/types.js";
|
|
@@ -210,6 +211,22 @@ export async function handleConfirm(
|
|
|
210
211
|
"Confirmation resolved via HTTP",
|
|
211
212
|
);
|
|
212
213
|
|
|
214
|
+
const approved = effectiveDecision === "allow";
|
|
215
|
+
const toolName = interaction.confirmationDetails?.toolName ?? "unknown tool";
|
|
216
|
+
void emitFeedEvent({
|
|
217
|
+
source: "assistant",
|
|
218
|
+
title: `${approved ? "Approved" : "Denied"} use of ${toolName}.`,
|
|
219
|
+
summary: `${approved ? "Approved" : "Denied"} use of ${toolName}.`,
|
|
220
|
+
dedupKey: `tool-approval:${requestId}`,
|
|
221
|
+
urgency: approved ? undefined : "medium",
|
|
222
|
+
conversationId: interaction.conversationId,
|
|
223
|
+
}).catch((err) => {
|
|
224
|
+
log.warn(
|
|
225
|
+
{ err, requestId },
|
|
226
|
+
"Failed to emit tool approval resolution feed event",
|
|
227
|
+
);
|
|
228
|
+
});
|
|
229
|
+
|
|
213
230
|
// ACP permissions: resolve directly without a Conversation object.
|
|
214
231
|
if (interaction.directResolve) {
|
|
215
232
|
interaction.directResolve(effectiveDecision as UserDecision);
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* with 403.
|
|
18
18
|
* - **Browser-origin rejection**: if an `Origin` header is present it
|
|
19
19
|
* must be either empty or explicitly on the
|
|
20
|
-
* `
|
|
20
|
+
* `getAllowedExtensionOrigins()` allowlist. This defends against a
|
|
21
21
|
* malicious web page in another tab issuing a cross-origin POST from
|
|
22
22
|
* the user's browser — such a request would carry the page's origin
|
|
23
23
|
* and would be rejected here even if it somehow reached loopback.
|
|
@@ -194,7 +194,9 @@ function loadAllowedExtensionOrigins(): ReadonlySet<string> {
|
|
|
194
194
|
// 2. Local override. Silently absent is fine; malformed warns but doesn't
|
|
195
195
|
// block other sources.
|
|
196
196
|
try {
|
|
197
|
-
for (const id of readIdsFromFile(LOCAL_OVERRIDE_PATH, {
|
|
197
|
+
for (const id of readIdsFromFile(LOCAL_OVERRIDE_PATH, {
|
|
198
|
+
allowEmpty: true,
|
|
199
|
+
})) {
|
|
198
200
|
merged.add(`chrome-extension://${id}/`);
|
|
199
201
|
}
|
|
200
202
|
} catch (err) {
|
|
@@ -240,10 +242,27 @@ function loadAllowedExtensionOrigins(): ReadonlySet<string> {
|
|
|
240
242
|
* token. Merged from the canonical repo config at
|
|
241
243
|
* `meta/browser-extension/chrome-extension-allowlist.json`, an optional
|
|
242
244
|
* local override at `~/.vellum/chrome-extension-allowlist.local.json`, and
|
|
243
|
-
* the `VELLUM_CHROME_EXTENSION_IDS` env var.
|
|
244
|
-
*
|
|
245
|
+
* the `VELLUM_CHROME_EXTENSION_IDS` env var. Computed lazily on first
|
|
246
|
+
* access so that importing this module (e.g. for `--version`) doesn't
|
|
247
|
+
* trigger filesystem reads. Cached after first call — allowlist edits
|
|
248
|
+
* require a daemon restart to take effect.
|
|
245
249
|
*/
|
|
246
|
-
|
|
250
|
+
let _allowedExtensionOrigins: ReadonlySet<string> | null = null;
|
|
251
|
+
|
|
252
|
+
export function getAllowedExtensionOrigins(): ReadonlySet<string> {
|
|
253
|
+
if (!_allowedExtensionOrigins) {
|
|
254
|
+
_allowedExtensionOrigins = loadAllowedExtensionOrigins();
|
|
255
|
+
}
|
|
256
|
+
return _allowedExtensionOrigins;
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Test helper: clear the cached allowlist so the next call to
|
|
261
|
+
* `getAllowedExtensionOrigins()` re-reads from disk/env.
|
|
262
|
+
*/
|
|
263
|
+
export function __resetAllowedExtensionOriginsForTests(): void {
|
|
264
|
+
_allowedExtensionOrigins = null;
|
|
265
|
+
}
|
|
247
266
|
|
|
248
267
|
/**
|
|
249
268
|
* Reset the dedicated pair-endpoint rate limiter. Exported for tests
|
|
@@ -490,8 +509,8 @@ export async function handleBrowserExtensionPair(
|
|
|
490
509
|
// and the `/`-suffixed form against the allowlist.
|
|
491
510
|
const withSlash = `${originHeader}/`;
|
|
492
511
|
if (
|
|
493
|
-
!
|
|
494
|
-
!
|
|
512
|
+
!getAllowedExtensionOrigins().has(originHeader) &&
|
|
513
|
+
!getAllowedExtensionOrigins().has(withSlash)
|
|
495
514
|
) {
|
|
496
515
|
auditDeny(req, peerIp, "browser_origin_not_allowlisted", {
|
|
497
516
|
originHeader,
|
|
@@ -536,7 +555,7 @@ export async function handleBrowserExtensionPair(
|
|
|
536
555
|
// check catches the failure mode where a compromised extension id
|
|
537
556
|
// that doesn't match a known Vellum build still manages to reach
|
|
538
557
|
// the endpoint.
|
|
539
|
-
if (!
|
|
558
|
+
if (!getAllowedExtensionOrigins().has(extensionOrigin)) {
|
|
540
559
|
auditDeny(req, peerIp, "extension_origin_not_allowlisted", {
|
|
541
560
|
extensionOrigin,
|
|
542
561
|
});
|