@vellumai/assistant 0.8.4 → 0.8.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +2 -2
- package/docs/browser-use-architecture-phase2.md +1 -1
- package/knip.json +2 -1
- package/openapi.yaml +809 -11
- package/package.json +1 -1
- package/src/__tests__/anthropic-provider.test.ts +34 -37
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +293 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +3 -3
- package/src/__tests__/audit-log-rotation.test.ts +70 -16
- package/src/__tests__/background-workers-disk-pressure.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +2 -3
- package/src/__tests__/call-controller.test.ts +0 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +3 -3
- package/src/__tests__/checker.test.ts +6 -15
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +214 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +5 -11
- package/src/__tests__/computer-use-tools.test.ts +2 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +197 -2
- package/src/__tests__/conversation-agent-loop.test.ts +163 -122
- package/src/__tests__/conversation-app-control-instantiation.test.ts +2 -5
- package/src/__tests__/conversation-clear-safety.test.ts +25 -25
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +1 -1
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +31 -0
- package/src/__tests__/conversation-fork-crud.test.ts +178 -15
- package/src/__tests__/conversation-lifecycle.test.ts +52 -11
- package/src/__tests__/{conversation-load-cleaned-at.test.ts → conversation-load-history-stripped.test.ts} +13 -13
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +109 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +35 -0
- package/src/__tests__/conversation-skill-tools.test.ts +2 -5
- package/src/__tests__/conversation-store.test.ts +1 -1
- package/src/__tests__/conversation-sync-tags.test.ts +99 -32
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +9 -7
- package/src/__tests__/credential-execution-tools.test.ts +6 -6
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +2 -2
- package/src/__tests__/dynamic-page-surface.test.ts +2 -2
- package/src/__tests__/email-html-renderer.test.ts +12 -0
- package/src/__tests__/gateway-flag-listener.test.ts +237 -0
- package/src/__tests__/gemini-provider.test.ts +78 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/guardian-outbound-http.test.ts +7 -5
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -1
- package/src/__tests__/heartbeat-disk-pressure.test.ts +4 -0
- package/src/__tests__/heartbeat-service.test.ts +4 -0
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +70 -11
- package/src/__tests__/llm-request-log-call-site.test.ts +136 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +26 -0
- package/src/__tests__/llm-resolver.test.ts +77 -9
- package/src/__tests__/llm-usage-store.test.ts +66 -0
- package/src/__tests__/logger.test.ts +89 -0
- package/src/__tests__/mcp-abort-signal.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +31 -0
- package/src/__tests__/memory-v2-static-injector.test.ts +7 -7
- package/src/__tests__/model-intents.test.ts +2 -4
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/onboarding-template-contract.test.ts +1 -1
- package/src/__tests__/openai-provider.test.ts +46 -0
- package/src/__tests__/openai-responses-provider.test.ts +114 -12
- package/src/__tests__/pending-interactions-resolved-event.test.ts +0 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +2 -2
- package/src/__tests__/platform.test.ts +2 -2
- package/src/__tests__/plugin-api-tool-definition.test.ts +92 -0
- package/src/__tests__/plugin-bootstrap.test.ts +2 -2
- package/src/__tests__/plugin-tool-contribution.test.ts +13 -6
- package/src/__tests__/plugin-types.test.ts +3 -2
- package/src/__tests__/prechat-onboarding-contract.test.ts +131 -98
- package/src/__tests__/pricing.test.ts +12 -0
- package/src/__tests__/prune-jobs-changes-parser.test.ts +61 -0
- package/src/__tests__/registry.test.ts +2 -8
- package/src/__tests__/require-fresh-approval.test.ts +2 -2
- package/src/__tests__/runtime-events-sse-bilingual.test.ts +154 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags.test.ts +2 -2
- package/src/__tests__/skill-projection-feature-flag.test.ts +4 -7
- package/src/__tests__/skill-projection.benchmark.test.ts +2 -6
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/subagent-notify-parent.test.ts +1 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/sync-message-contract.test.ts +59 -0
- package/src/__tests__/system-prompt.test.ts +145 -131
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-approval-handler.test.ts +1 -5
- package/src/__tests__/tool-execute-pipeline.test.ts +2 -2
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -5
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +15 -5
- package/src/__tests__/tool-executor.test.ts +9 -62
- package/src/__tests__/tool-grant-request-escalation.test.ts +1 -6
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +0 -1
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -6
- package/src/__tests__/trusted-contact-multichannel.test.ts +0 -1
- package/src/__tests__/ui-file-upload-surface.test.ts +2 -2
- package/src/__tests__/usage-routes.test.ts +3 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -2
- package/src/__tests__/workspace-git-service.test.ts +6 -5
- package/src/__tests__/workspace-migration-089-move-memory-tree-out-of-v3.test.ts +86 -0
- package/src/acp/__tests__/prepare-agent-env.test.ts +146 -0
- package/src/acp/prepare-agent-env.ts +78 -0
- package/src/acp/session-manager.ts +1 -1
- package/src/agent/loop.ts +8 -0
- package/src/api/README.md +5 -0
- package/src/api/index.ts +4 -0
- package/src/api/package.json +10 -0
- package/src/background-wake/background-wake-routes.test.ts +233 -0
- package/src/background-wake/runtime-registry.ts +24 -0
- package/src/cli/commands/__tests__/browser.test.ts +23 -5
- package/src/cli/commands/__tests__/domain-register.test.ts +110 -0
- package/src/cli/commands/__tests__/domain-status.test.ts +33 -33
- package/src/cli/commands/__tests__/inference-send.test.ts +108 -5
- package/src/cli/commands/__tests__/memory-v2-compare-render.test.ts +98 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +1 -0
- package/src/cli/commands/__tests__/memory-v3-render.test.ts +340 -0
- package/src/cli/commands/browser.ts +247 -0
- package/src/cli/commands/domain.ts +91 -41
- package/src/cli/commands/inference.ts +93 -40
- package/src/cli/commands/memory-v2-compare-render.ts +115 -0
- package/src/cli/commands/memory-v2.ts +176 -1
- package/src/cli/commands/memory-v3-render.ts +344 -0
- package/src/cli/commands/memory-v3.ts +316 -0
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +21 -9
- package/src/config/bundled-skills/document-editor/SKILL.md +11 -2
- package/src/config/bundled-skills/document-editor/TOOLS.json +18 -0
- package/src/config/bundled-skills/document-editor/tools/document-open.ts +12 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +13 -8
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +10 -3
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +16 -14
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +7 -2
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +7 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/call-site-defaults.ts +7 -6
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +213 -1
- package/src/config/schemas/call-site-catalog.ts +21 -7
- package/src/config/schemas/llm.ts +12 -1
- package/src/config/schemas/memory-v2.ts +246 -0
- package/src/config/schemas/memory.ts +2 -1
- package/src/context/compactor.ts +52 -0
- package/src/conversations/__tests__/message-consolidation.test.ts +350 -0
- package/src/conversations/message-consolidation.ts +404 -0
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -1
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +1 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -13
- package/src/daemon/conversation-agent-loop.ts +126 -76
- package/src/daemon/conversation-error.ts +31 -1
- package/src/daemon/conversation-lifecycle.ts +27 -22
- package/src/daemon/conversation-runtime-assembly.ts +10 -9
- package/src/daemon/conversation-tool-setup.ts +63 -3
- package/src/daemon/conversation-usage.ts +2 -0
- package/src/daemon/conversation.ts +14 -29
- package/src/daemon/disk-pressure-guard.ts +14 -2
- package/src/daemon/handlers/config-model.test.ts +1 -0
- package/src/daemon/handlers/conversations.ts +11 -3
- package/src/daemon/host-browser-proxy.ts +5 -5
- package/src/daemon/host-cu-proxy.ts +4 -4
- package/src/daemon/host-file-proxy.ts +4 -4
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/host-transfer-proxy.ts +10 -10
- package/src/daemon/lifecycle.ts +23 -20
- package/src/daemon/meet-manifest-loader.ts +1 -7
- package/src/daemon/message-types/conversations.ts +6 -9
- package/src/daemon/message-types/home.ts +1 -13
- package/src/daemon/message-types/messages.ts +6 -14
- package/src/daemon/message-types/sync.ts +14 -0
- package/src/daemon/shutdown-handlers.ts +24 -5
- package/src/daemon/switch-inference-profile-tool.ts +52 -0
- package/src/daemon/tool-setup-types.ts +13 -0
- package/src/events/relationship-state-updated.ts +25 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +1 -1
- package/src/home/home-greeting.ts +0 -9
- package/src/home/suggested-prompts.ts +0 -9
- package/src/ipc/gateway-flag-listener.ts +123 -0
- package/src/ipc/skill-routes/registries.ts +8 -12
- package/src/memory/__tests__/db-async-query.test.ts +165 -0
- package/src/memory/__tests__/db-maintenance.test.ts +115 -0
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +241 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +28 -1
- package/src/memory/__tests__/memory-retrospective-job.test.ts +7 -0
- package/src/memory/auto-analysis-enqueue.ts +5 -1
- package/src/memory/conversation-crud.ts +71 -70
- package/src/memory/conversation-starters-cadence.ts +3 -1
- package/src/memory/conversation-title-service.ts +19 -3
- package/src/memory/db-async-query.ts +214 -0
- package/src/memory/db-init.ts +10 -0
- package/src/memory/db-maintenance.ts +30 -21
- package/src/memory/graph/bootstrap.ts +8 -1
- package/src/memory/graph/capability-seed.ts +7 -3
- package/src/memory/graph/conversation-graph-memory.ts +100 -17
- package/src/memory/graph/extraction.ts +1 -5
- package/src/memory/graph/graph-search.ts +7 -1
- package/src/memory/indexer.ts +28 -18
- package/src/memory/job-handlers/cleanup.ts +76 -18
- package/src/memory/job-handlers/conversation-starters.ts +1 -4
- package/src/memory/jobs/embed-pkb-file.ts +6 -1
- package/src/memory/jobs-store.ts +14 -0
- package/src/memory/jobs-worker.ts +55 -22
- package/src/memory/llm-request-log-source-clickhouse.ts +42 -2
- package/src/memory/llm-request-log-source-local.ts +7 -0
- package/src/memory/llm-request-log-source.ts +9 -2
- package/src/memory/llm-request-log-store.ts +43 -1
- package/src/memory/llm-usage-store.ts +24 -0
- package/src/memory/memory-retrospective-enqueue.ts +8 -1
- package/src/memory/memory-retrospective-job.ts +5 -0
- package/src/memory/memory-v2-activation-log-store.ts +15 -6
- package/src/memory/migrations/260-rename-cleaned-at.ts +44 -0
- package/src/memory/migrations/261-llm-usage-add-raw-usage.ts +36 -0
- package/src/memory/migrations/262-memory-v3-coactivation.ts +57 -0
- package/src/memory/migrations/263-memory-v3-auto-edges.ts +50 -0
- package/src/memory/migrations/264-llm-request-log-call-site.ts +29 -0
- package/src/memory/migrations/index.ts +17 -0
- package/src/memory/migrations/registry.ts +33 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/infrastructure.ts +21 -0
- package/src/memory/tool-usage-store.ts +36 -8
- package/src/memory/v2/__tests__/consolidation-job.test.ts +1 -0
- package/src/memory/v2/__tests__/harness-compare.test.ts +186 -0
- package/src/memory/v2/__tests__/harness-metrics.test.ts +74 -0
- package/src/memory/v2/__tests__/harness-oracle.test.ts +257 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +225 -0
- package/src/memory/v2/__tests__/harness-runner.test.ts +109 -0
- package/src/memory/v2/__tests__/injection.test.ts +127 -98
- package/src/memory/v2/__tests__/qdrant.test.ts +36 -0
- package/src/memory/v2/__tests__/router.test.ts +171 -3
- package/src/memory/v2/harness/compare.ts +57 -0
- package/src/memory/v2/harness/metrics.ts +124 -0
- package/src/memory/v2/harness/oracle.ts +145 -0
- package/src/memory/v2/harness/replay-input.ts +224 -0
- package/src/memory/v2/harness/retriever.ts +74 -0
- package/src/memory/v2/harness/router-retriever.ts +43 -0
- package/src/memory/v2/harness/runner.ts +106 -0
- package/src/memory/v2/harness/trace.ts +58 -0
- package/src/memory/v2/injection.ts +21 -15
- package/src/memory/v2/prompts/router.ts +26 -1
- package/src/memory/v2/qdrant.ts +14 -2
- package/src/memory/v2/router.ts +171 -18
- package/src/memory/v3/__tests__/coactivation-store.test.ts +422 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +468 -0
- package/src/memory/v3/__tests__/edge-learning-job.test.ts +324 -0
- package/src/memory/v3/__tests__/edges.test.ts +563 -0
- package/src/memory/v3/__tests__/filter.test.ts +512 -0
- package/src/memory/v3/__tests__/gate.test.ts +574 -0
- package/src/memory/v3/__tests__/index-composition.test.ts +233 -0
- package/src/memory/v3/__tests__/loop.test.ts +530 -0
- package/src/memory/v3/__tests__/retriever.test.ts +226 -0
- package/src/memory/v3/__tests__/scouts.test.ts +440 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +312 -0
- package/src/memory/v3/__tests__/system-prompts.test.ts +154 -0
- package/src/memory/v3/__tests__/traversal.test.ts +469 -0
- package/src/memory/v3/__tests__/tree-index.test.ts +280 -0
- package/src/memory/v3/__tests__/tree-store.test.ts +529 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +707 -0
- package/src/memory/v3/__tests__/validate.test.ts +245 -0
- package/src/memory/v3/auto-edges.ts +223 -0
- package/src/memory/v3/coactivation-store.ts +124 -0
- package/src/memory/v3/consolidation-job.ts +323 -0
- package/src/memory/v3/edge-learning-job.ts +160 -0
- package/src/memory/v3/edges.ts +249 -0
- package/src/memory/v3/filter.ts +281 -0
- package/src/memory/v3/gate.ts +334 -0
- package/src/memory/v3/index-composition.ts +113 -0
- package/src/memory/v3/llm-capture.ts +46 -0
- package/src/memory/v3/loop.ts +382 -0
- package/src/memory/v3/maintenance.ts +144 -0
- package/src/memory/v3/prompt-context.ts +33 -0
- package/src/memory/v3/prompts/consolidation.ts +458 -0
- package/src/memory/v3/prompts/system-prompts.ts +196 -0
- package/src/memory/v3/retriever.ts +33 -0
- package/src/memory/v3/scouts.ts +420 -0
- package/src/memory/v3/shadow-middleware.ts +305 -0
- package/src/memory/v3/traversal.ts +206 -0
- package/src/memory/v3/tree-index.ts +237 -0
- package/src/memory/v3/tree-store.ts +394 -0
- package/src/memory/v3/tree-walk.ts +351 -0
- package/src/memory/v3/types.ts +65 -0
- package/src/memory/v3/validate.ts +300 -0
- package/src/notifications/adapters/macos.ts +18 -1
- package/src/notifications/adapters/platform.ts +1 -1
- package/src/notifications/decision-engine.ts +1 -4
- package/src/notifications/emit-signal.ts +29 -49
- package/src/permissions/prompter.ts +3 -3
- package/src/permissions/question-prompter.ts +5 -2
- package/src/permissions/secret-prompter.ts +2 -2
- package/src/plugin-api/index.ts +4 -0
- package/src/plugin-api/types.ts +7 -33
- package/src/plugins/defaults/index.ts +6 -0
- package/src/plugins/defaults/injectors.ts +18 -11
- package/src/plugins/external-plugin-loader.ts +5 -68
- package/src/plugins/types.ts +11 -16
- package/src/proactive-artifact/aux-message-injector.ts +17 -4
- package/src/prompts/__tests__/task-progress-hint-section.test.ts +3 -9
- package/src/prompts/persona-resolver.ts +36 -21
- package/src/prompts/sections.ts +39 -7
- package/src/prompts/system-prompt.ts +50 -185
- package/src/prompts/templates/BOOTSTRAP.md +2 -2
- package/src/prompts/templates/system-sections.ts +230 -8
- package/src/providers/__tests__/connection-model-compat.test.ts +234 -0
- package/src/providers/__tests__/retry-callsite.test.ts +85 -5
- package/src/providers/anthropic/client.ts +32 -66
- package/src/providers/call-site-routing.ts +14 -2
- package/src/providers/connection-model-compat.ts +38 -0
- package/src/providers/connection-resolution.ts +16 -2
- package/src/providers/gemini/client.ts +49 -6
- package/src/providers/inference/adapter-factory.ts +3 -0
- package/src/providers/minimax/client.ts +106 -0
- package/src/providers/model-catalog.ts +43 -0
- package/src/providers/model-intents.ts +1 -1
- package/src/providers/openai/chat-completions-provider.ts +6 -3
- package/src/providers/openai/codex-models.ts +18 -0
- package/src/providers/openai/responses-provider.ts +78 -21
- package/src/providers/provider-send-message.ts +7 -1
- package/src/providers/retry.ts +34 -3
- package/src/providers/thinking-config.ts +26 -1
- package/src/providers/usage-tracking.ts +2 -0
- package/src/runtime/AGENTS.md +2 -2
- package/src/runtime/agent-wake.ts +1 -0
- package/src/runtime/assistant-event-hub.ts +76 -6
- package/src/runtime/auth/route-policy.ts +36 -0
- package/src/runtime/btw-sidechain.ts +0 -6
- package/src/runtime/http-types.ts +0 -2
- package/src/runtime/migrations/vbundle-builder.ts +10 -3
- package/src/runtime/pending-interactions.ts +0 -1
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +106 -0
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +25 -6
- package/src/runtime/routes/__tests__/plugins-routes.test.ts +512 -0
- package/src/runtime/routes/acp-routes.test.ts +255 -6
- package/src/runtime/routes/acp-routes.ts +8 -1
- package/src/runtime/routes/avatar-routes.ts +10 -10
- package/src/runtime/routes/background-wake-routes.ts +188 -0
- package/src/runtime/routes/browser-tabs-routes.ts +200 -0
- package/src/runtime/routes/btw-routes.ts +0 -6
- package/src/runtime/routes/conversation-cli-routes.ts +1 -1
- package/src/runtime/routes/conversation-list-routes.ts +12 -4
- package/src/runtime/routes/conversation-management-routes.ts +77 -20
- package/src/runtime/routes/conversation-query-routes.ts +142 -36
- package/src/runtime/routes/conversation-routes.ts +252 -410
- package/src/runtime/routes/conversation-starter-routes.ts +6 -3
- package/src/runtime/routes/disk-pressure-routes.ts +1 -1
- package/src/runtime/routes/domain-routes.ts +60 -10
- package/src/runtime/routes/email-routes.ts +5 -2
- package/src/runtime/routes/events-routes.ts +54 -10
- package/src/runtime/routes/group-routes.ts +24 -8
- package/src/runtime/routes/host-browser-routes.ts +10 -2
- package/src/runtime/routes/host-cu-routes.ts +2 -2
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +96 -3
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +22 -12
- package/src/runtime/routes/inference-profile-session-routes.ts +7 -1
- package/src/runtime/routes/llm-call-sites-routes.ts +32 -5
- package/src/runtime/routes/memory-item-routes.ts +8 -3
- package/src/runtime/routes/memory-v2-routes.ts +215 -5
- package/src/runtime/routes/memory-v3-routes.ts +316 -0
- package/src/runtime/routes/migration-routes.ts +21 -24
- package/src/runtime/routes/plugins-routes.ts +337 -0
- package/src/runtime/routes/rename-conversation-routes.ts +6 -2
- package/src/runtime/routes/secret-routes.ts +25 -5
- package/src/runtime/routes/settings-routes.ts +12 -11
- package/src/runtime/routes/slack-channel-routes.ts +5 -4
- package/src/runtime/routes/workspace-routes.ts +25 -10
- package/src/runtime/sync/resource-sync-events.ts +106 -38
- package/src/runtime/sync/sync-publisher.test.ts +49 -0
- package/src/runtime/sync/sync-publisher.ts +2 -1
- package/src/runtime/verification-outbound-actions.ts +73 -1
- package/src/telemetry/types.ts +12 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +48 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/acp/spawn.test.ts +119 -0
- package/src/tools/acp/spawn.ts +15 -2
- package/src/tools/apps/definitions.ts +2 -8
- package/src/tools/ask-question/ask-question-tool.test.ts +3 -3
- package/src/tools/ask-question/ask-question-tool.ts +38 -45
- package/src/tools/browser/__tests__/pinned-tabs.test.ts +70 -0
- package/src/tools/browser/browser-execution.ts +16 -3
- package/src/tools/browser/cdp-client/__tests__/browser-tabs-factory.test.ts +402 -0
- package/src/tools/browser/cdp-client/__tests__/types.test.ts +3 -0
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +12 -0
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +27 -1
- package/src/tools/browser/cdp-client/factory.ts +100 -17
- package/src/tools/browser/cdp-client/local-cdp-client.ts +12 -0
- package/src/tools/browser/cdp-client/types.ts +65 -0
- package/src/tools/browser/pinned-tabs.ts +96 -40
- package/src/tools/computer-use/definitions.ts +22 -78
- package/src/tools/credential-execution/make-authenticated-request.ts +3 -9
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -9
- package/src/tools/credential-execution/run-authenticated-command.ts +3 -9
- package/src/tools/credentials/vault.ts +3 -9
- package/src/tools/document/document-tool.ts +59 -0
- package/src/tools/execution-target.ts +21 -23
- package/src/tools/executor.ts +6 -1
- package/src/tools/filesystem/edit.ts +3 -9
- package/src/tools/filesystem/list.ts +3 -9
- package/src/tools/filesystem/read.ts +3 -9
- package/src/tools/filesystem/write.ts +3 -9
- package/src/tools/host-filesystem/edit.ts +3 -9
- package/src/tools/host-filesystem/read.ts +3 -9
- package/src/tools/host-filesystem/transfer.ts +3 -9
- package/src/tools/host-filesystem/write.ts +3 -9
- package/src/tools/host-terminal/host-shell.ts +3 -9
- package/src/tools/mcp/mcp-tool-factory.ts +1 -8
- package/src/tools/memory/register.test.ts +1 -1
- package/src/tools/memory/register.ts +4 -9
- package/src/tools/network/web-fetch.ts +3 -9
- package/src/tools/network/web-search.ts +25 -32
- package/src/tools/registry.ts +7 -23
- package/src/tools/schema-transforms.ts +1 -1
- package/src/tools/skills/execute.ts +3 -9
- package/src/tools/skills/load.ts +3 -9
- package/src/tools/skills/skill-tool-factory.ts +1 -8
- package/src/tools/subagent/notify-parent.ts +3 -9
- package/src/tools/system/request-permission.ts +3 -9
- package/src/tools/terminal/shell.ts +3 -9
- package/src/tools/tool-defaults.ts +94 -0
- package/src/tools/types.ts +27 -98
- package/src/tools/ui-surface/definitions.ts +6 -22
- package/src/usage/pricing.ts +23 -0
- package/src/usage/types.ts +12 -0
- package/src/util/logger.ts +16 -7
- package/src/util/platform.ts +7 -2
- package/src/util/sqlite3-runtime.ts +65 -0
- package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +1 -0
- package/src/workspace/migrations/089-move-memory-tree-out-of-v3.ts +86 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +0 -206
- package/src/__tests__/message-complete-display-id.test.ts +0 -175
- package/src/daemon/query-complexity-router.ts +0 -75
- package/src/prompts/cache-boundary.ts +0 -8
|
@@ -21,7 +21,10 @@ import {
|
|
|
21
21
|
isValidConversationStarterText,
|
|
22
22
|
} from "../../memory/conversation-starter-validation.js";
|
|
23
23
|
import { getDb } from "../../memory/db-connection.js";
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
enqueueMemoryJob,
|
|
26
|
+
isMemoryEnabled,
|
|
27
|
+
} from "../../memory/jobs-store.js";
|
|
25
28
|
import { conversationStarters, memoryJobs } from "../../memory/schema.js";
|
|
26
29
|
import { NotFoundError } from "./errors.js";
|
|
27
30
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
@@ -203,7 +206,7 @@ function handleListConversationStarters({
|
|
|
203
206
|
checkpointAhead ||
|
|
204
207
|
(invalidItemCount > 0 && totalActive > 0 && !withinCooldown);
|
|
205
208
|
|
|
206
|
-
if (shouldRefresh && !hasActiveJob) {
|
|
209
|
+
if (shouldRefresh && !hasActiveJob && isMemoryEnabled()) {
|
|
207
210
|
enqueueMemoryJob("generate_conversation_starters", { scopeId });
|
|
208
211
|
hasActiveJob = true;
|
|
209
212
|
}
|
|
@@ -225,7 +228,7 @@ function handleListConversationStarters({
|
|
|
225
228
|
|
|
226
229
|
const existing = hasActiveConversationStarterJob(db, scopeId);
|
|
227
230
|
|
|
228
|
-
if (!existing) {
|
|
231
|
+
if (!existing && isMemoryEnabled()) {
|
|
229
232
|
enqueueMemoryJob("generate_conversation_starters", { scopeId });
|
|
230
233
|
}
|
|
231
234
|
|
|
@@ -11,7 +11,7 @@ import type { RouteDefinition } from "./types.js";
|
|
|
11
11
|
|
|
12
12
|
const DiskPressureStatusSchema = z.object({
|
|
13
13
|
enabled: z.boolean(),
|
|
14
|
-
state: z.enum(["disabled", "ok", "critical", "unknown"]),
|
|
14
|
+
state: z.enum(["disabled", "ok", "warning", "critical", "unknown"]),
|
|
15
15
|
locked: z.boolean(),
|
|
16
16
|
acknowledged: z.boolean(),
|
|
17
17
|
overrideActive: z.boolean(),
|
|
@@ -35,7 +35,10 @@ async function requireClient(): Promise<VellumPlatformClient> {
|
|
|
35
35
|
// ── Handlers ──────────────────────────────────────────────────────────
|
|
36
36
|
|
|
37
37
|
async function handleDomainRegister({ body = {} }: RouteHandlerArgs) {
|
|
38
|
-
const { subdomain } = body as {
|
|
38
|
+
const { subdomain, email_username } = body as {
|
|
39
|
+
subdomain?: string;
|
|
40
|
+
email_username?: string;
|
|
41
|
+
};
|
|
39
42
|
const client = await requireClient();
|
|
40
43
|
const apexDomain = getApexDomain();
|
|
41
44
|
|
|
@@ -43,6 +46,9 @@ async function handleDomainRegister({ body = {} }: RouteHandlerArgs) {
|
|
|
43
46
|
if (subdomain) {
|
|
44
47
|
reqBody.subdomain = subdomain;
|
|
45
48
|
}
|
|
49
|
+
if (email_username) {
|
|
50
|
+
reqBody.email_username = email_username;
|
|
51
|
+
}
|
|
46
52
|
|
|
47
53
|
const response = await client.fetch(
|
|
48
54
|
`/v1/assistants/${client.platformAssistantId}/domains/`,
|
|
@@ -58,12 +64,18 @@ async function handleDomainRegister({ body = {} }: RouteHandlerArgs) {
|
|
|
58
64
|
string,
|
|
59
65
|
unknown
|
|
60
66
|
>;
|
|
67
|
+
const firstFieldError = ["subdomain", "email_username"].reduce<
|
|
68
|
+
string | undefined
|
|
69
|
+
>(
|
|
70
|
+
(found, field) =>
|
|
71
|
+
found ??
|
|
72
|
+
(Array.isArray(respBody[field])
|
|
73
|
+
? (respBody[field][0] as string)
|
|
74
|
+
: undefined),
|
|
75
|
+
undefined,
|
|
76
|
+
);
|
|
61
77
|
const detail =
|
|
62
|
-
respBody.detail ??
|
|
63
|
-
(Array.isArray(respBody.subdomain)
|
|
64
|
-
? respBody.subdomain[0]
|
|
65
|
-
: undefined) ??
|
|
66
|
-
`HTTP ${response.status}`;
|
|
78
|
+
respBody.detail ?? firstFieldError ?? `HTTP ${response.status}`;
|
|
67
79
|
throw new BadRequestError(String(detail));
|
|
68
80
|
}
|
|
69
81
|
|
|
@@ -71,10 +83,9 @@ async function handleDomainRegister({ body = {} }: RouteHandlerArgs) {
|
|
|
71
83
|
id: string;
|
|
72
84
|
subdomain?: string;
|
|
73
85
|
domain?: string;
|
|
74
|
-
status?: string;
|
|
75
|
-
verified?: boolean;
|
|
76
86
|
created_at?: string;
|
|
77
87
|
created?: string;
|
|
88
|
+
email_error?: { detail: string; code: string };
|
|
78
89
|
};
|
|
79
90
|
|
|
80
91
|
// Persist the subdomain to config so getAssistantDomain() can use it
|
|
@@ -117,8 +128,6 @@ async function handleDomainStatus(_args: RouteHandlerArgs) {
|
|
|
117
128
|
id: string;
|
|
118
129
|
subdomain?: string;
|
|
119
130
|
domain?: string;
|
|
120
|
-
status?: string;
|
|
121
|
-
verified?: boolean;
|
|
122
131
|
created_at?: string;
|
|
123
132
|
created?: string;
|
|
124
133
|
}[];
|
|
@@ -145,6 +154,39 @@ async function handleDomainStatus(_args: RouteHandlerArgs) {
|
|
|
145
154
|
return data;
|
|
146
155
|
}
|
|
147
156
|
|
|
157
|
+
async function handleDomainVerificationStatus({
|
|
158
|
+
body = {},
|
|
159
|
+
}: RouteHandlerArgs) {
|
|
160
|
+
const { domain_id } = body as { domain_id?: string };
|
|
161
|
+
if (!domain_id) {
|
|
162
|
+
throw new BadRequestError("domain_id is required");
|
|
163
|
+
}
|
|
164
|
+
const client = await requireClient();
|
|
165
|
+
|
|
166
|
+
const response = await client.fetch(
|
|
167
|
+
`/v1/assistants/${client.platformAssistantId}/domains/${domain_id}/verification-status/`,
|
|
168
|
+
);
|
|
169
|
+
|
|
170
|
+
if (!response.ok) {
|
|
171
|
+
const respBody = (await response.json().catch(() => ({}))) as Record<
|
|
172
|
+
string,
|
|
173
|
+
unknown
|
|
174
|
+
>;
|
|
175
|
+
const detail = respBody.detail ?? `HTTP ${response.status}`;
|
|
176
|
+
throw new RouteError(
|
|
177
|
+
String(detail),
|
|
178
|
+
"VERIFICATION_STATUS_FAILED",
|
|
179
|
+
response.status,
|
|
180
|
+
);
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
return (await response.json()) as {
|
|
184
|
+
domain: string;
|
|
185
|
+
status: string;
|
|
186
|
+
message: string;
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
|
|
148
190
|
// ── Route definitions ─────────────────────────────────────────────────
|
|
149
191
|
|
|
150
192
|
export const ROUTES: RouteDefinition[] = [
|
|
@@ -164,4 +206,12 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
164
206
|
summary: "Show domain registration and health",
|
|
165
207
|
tags: ["domain"],
|
|
166
208
|
},
|
|
209
|
+
{
|
|
210
|
+
operationId: "domain_verification_status",
|
|
211
|
+
endpoint: "domain/verification-status",
|
|
212
|
+
method: "POST",
|
|
213
|
+
handler: handleDomainVerificationStatus,
|
|
214
|
+
summary: "Get live DNS verification status for a domain",
|
|
215
|
+
tags: ["domain"],
|
|
216
|
+
},
|
|
167
217
|
];
|
|
@@ -277,13 +277,16 @@ async function handleEmailSend({ body = {} }: RouteHandlerArgs) {
|
|
|
277
277
|
|
|
278
278
|
const fromAddress = addresses[0].address;
|
|
279
279
|
|
|
280
|
+
// LLMs often produce literal "\n" escape sequences instead of real newlines.
|
|
281
|
+
const normalizedText = text?.replace(/\\n/g, "\n") ?? "";
|
|
282
|
+
|
|
280
283
|
// Auto-generate HTML from text if not provided
|
|
281
|
-
const resolvedHtml = html ?? markdownToEmailHtml(
|
|
284
|
+
const resolvedHtml = html ?? markdownToEmailHtml(normalizedText);
|
|
282
285
|
|
|
283
286
|
const payload: Record<string, unknown> = {
|
|
284
287
|
to,
|
|
285
288
|
from_address: fromAddress,
|
|
286
|
-
text,
|
|
289
|
+
text: normalizedText,
|
|
287
290
|
};
|
|
288
291
|
if (subject) payload.subject = subject;
|
|
289
292
|
if (resolvedHtml) payload.html = resolvedHtml;
|
|
@@ -26,6 +26,7 @@ import { z } from "zod";
|
|
|
26
26
|
import type { HostProxyCapability } from "../../channels/types.js";
|
|
27
27
|
import { parseInterfaceId, supportsHostProxy } from "../../channels/types.js";
|
|
28
28
|
import { emitContactChange } from "../../contacts/contact-events.js";
|
|
29
|
+
import { getConversation } from "../../memory/conversation-crud.js";
|
|
29
30
|
import { getOrCreateConversation } from "../../memory/conversation-key-store.js";
|
|
30
31
|
import { getLogger } from "../../util/logger.js";
|
|
31
32
|
import { formatSseFrame, formatSseHeartbeat } from "../assistant-event.js";
|
|
@@ -39,7 +40,11 @@ import {
|
|
|
39
40
|
assistantEventHub,
|
|
40
41
|
} from "../assistant-event-hub.js";
|
|
41
42
|
import { resolveActorPrincipalIdForLocalGuardian } from "../local-actor-identity.js";
|
|
42
|
-
import {
|
|
43
|
+
import {
|
|
44
|
+
BadRequestError,
|
|
45
|
+
NotFoundError,
|
|
46
|
+
ServiceUnavailableError,
|
|
47
|
+
} from "./errors.js";
|
|
43
48
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
44
49
|
|
|
45
50
|
const log = getLogger("events-routes");
|
|
@@ -220,9 +225,17 @@ const defaultSseShedReporter: SseShedReporter = (reason, inst) => {
|
|
|
220
225
|
* Stream assistant events as Server-Sent Events.
|
|
221
226
|
*
|
|
222
227
|
* Query params:
|
|
223
|
-
*
|
|
224
|
-
*
|
|
225
|
-
*
|
|
228
|
+
* conversationId -- optional; assistant-minted internal conversation id.
|
|
229
|
+
* When provided, the stream is scoped to that one
|
|
230
|
+
* conversation; the daemon 404s if no such conversation
|
|
231
|
+
* exists (clients must obtain the id from a prior
|
|
232
|
+
* response).
|
|
233
|
+
* conversationKey -- optional; external key (non-vellum channels) or the
|
|
234
|
+
* web idempotency key. Resolved via the conversation
|
|
235
|
+
* keys table; materializes a row on first use.
|
|
236
|
+
* Ignored when `conversationId` is also provided.
|
|
237
|
+
* When both are omitted, the stream delivers events from ALL
|
|
238
|
+
* conversations for this assistant.
|
|
226
239
|
*
|
|
227
240
|
* Headers (optional):
|
|
228
241
|
* X-Vellum-Client-Id -- stable per-install UUID identifying this client.
|
|
@@ -248,8 +261,18 @@ export function handleSubscribeAssistantEvents(
|
|
|
248
261
|
): ReadableStream<Uint8Array> {
|
|
249
262
|
const { queryParams, headers, abortSignal } = args;
|
|
250
263
|
|
|
251
|
-
const
|
|
252
|
-
|
|
264
|
+
const rawConversationId = queryParams?.conversationId;
|
|
265
|
+
const rawConversationKey = queryParams?.conversationKey;
|
|
266
|
+
if (
|
|
267
|
+
"conversationId" in (queryParams ?? {}) &&
|
|
268
|
+
!rawConversationId?.trim()
|
|
269
|
+
) {
|
|
270
|
+
throw new BadRequestError("conversationId must not be empty");
|
|
271
|
+
}
|
|
272
|
+
if (
|
|
273
|
+
"conversationKey" in (queryParams ?? {}) &&
|
|
274
|
+
!rawConversationKey?.trim()
|
|
275
|
+
) {
|
|
253
276
|
throw new BadRequestError("conversationKey must not be empty");
|
|
254
277
|
}
|
|
255
278
|
|
|
@@ -293,10 +316,25 @@ export function handleSubscribeAssistantEvents(
|
|
|
293
316
|
"host_browser",
|
|
294
317
|
];
|
|
295
318
|
|
|
319
|
+
// Resolve the scope. `conversationId` (when supplied) is the
|
|
320
|
+
// assistant-minted internal id — looked up directly; 404 if absent.
|
|
321
|
+
// Otherwise fall through to `conversationKey`, which is treated as an
|
|
322
|
+
// external key and resolved via the conversation_keys table
|
|
323
|
+
// (materialized on first use, preserving the existing subscribe-time
|
|
324
|
+
// create behavior for the web idempotency flow).
|
|
296
325
|
const filter: AssistantEventFilter = {};
|
|
297
|
-
|
|
298
|
-
|
|
326
|
+
let scopeConversationKey: string | null = null;
|
|
327
|
+
if (rawConversationId) {
|
|
328
|
+
const existing = getConversation(rawConversationId);
|
|
329
|
+
if (!existing) {
|
|
330
|
+
throw new NotFoundError(`Conversation ${rawConversationId} not found`);
|
|
331
|
+
}
|
|
332
|
+
filter.conversationId = existing.id;
|
|
333
|
+
scopeConversationKey = existing.id;
|
|
334
|
+
} else if (rawConversationKey) {
|
|
335
|
+
const mapping = getOrCreateConversation(rawConversationKey);
|
|
299
336
|
filter.conversationId = mapping.conversationId;
|
|
337
|
+
scopeConversationKey = rawConversationKey;
|
|
300
338
|
}
|
|
301
339
|
|
|
302
340
|
const encoder = new TextEncoder();
|
|
@@ -316,7 +354,7 @@ export function handleSubscribeAssistantEvents(
|
|
|
316
354
|
heartbeatsSent: 0,
|
|
317
355
|
clientId,
|
|
318
356
|
interfaceId,
|
|
319
|
-
conversationKey:
|
|
357
|
+
conversationKey: scopeConversationKey,
|
|
320
358
|
};
|
|
321
359
|
|
|
322
360
|
ensureEventLoopDelayMonitorStarted();
|
|
@@ -470,9 +508,15 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
470
508
|
description: "Stream assistant events as Server-Sent Events (SSE).",
|
|
471
509
|
tags: ["events"],
|
|
472
510
|
queryParams: [
|
|
511
|
+
{
|
|
512
|
+
name: "conversationId",
|
|
513
|
+
description:
|
|
514
|
+
"Scope to a single conversation by its assistant-minted internal id. 404s if no such conversation exists.",
|
|
515
|
+
},
|
|
473
516
|
{
|
|
474
517
|
name: "conversationKey",
|
|
475
|
-
description:
|
|
518
|
+
description:
|
|
519
|
+
"Scope to a single conversation by an external key (non-vellum channels) or the web idempotency key. Materializes a row on first use. Ignored when conversationId is also provided.",
|
|
476
520
|
},
|
|
477
521
|
],
|
|
478
522
|
responseHeaders: {
|
|
@@ -41,14 +41,17 @@ function handleListGroups() {
|
|
|
41
41
|
return { groups: groups.map(serializeGroup) };
|
|
42
42
|
}
|
|
43
43
|
|
|
44
|
-
function handleCreateGroup({ body = {} }: RouteHandlerArgs) {
|
|
44
|
+
function handleCreateGroup({ body = {}, headers }: RouteHandlerArgs) {
|
|
45
45
|
const name = body.name;
|
|
46
46
|
if (!name || typeof name !== "string") {
|
|
47
47
|
throw new BadRequestError("Missing or invalid name");
|
|
48
48
|
}
|
|
49
49
|
try {
|
|
50
50
|
const group = createGroup(name);
|
|
51
|
-
publishConversationListChanged(
|
|
51
|
+
publishConversationListChanged(
|
|
52
|
+
"created",
|
|
53
|
+
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
54
|
+
);
|
|
52
55
|
return serializeGroup(group);
|
|
53
56
|
} catch (err) {
|
|
54
57
|
if (
|
|
@@ -63,7 +66,11 @@ function handleCreateGroup({ body = {} }: RouteHandlerArgs) {
|
|
|
63
66
|
}
|
|
64
67
|
}
|
|
65
68
|
|
|
66
|
-
function handleUpdateGroup({
|
|
69
|
+
function handleUpdateGroup({
|
|
70
|
+
pathParams = {},
|
|
71
|
+
body = {},
|
|
72
|
+
headers,
|
|
73
|
+
}: RouteHandlerArgs) {
|
|
67
74
|
const groupId = pathParams.groupId;
|
|
68
75
|
const existing = getGroup(groupId);
|
|
69
76
|
if (!existing) {
|
|
@@ -92,11 +99,14 @@ function handleUpdateGroup({ pathParams = {}, body = {} }: RouteHandlerArgs) {
|
|
|
92
99
|
if (!updated) {
|
|
93
100
|
throw new NotFoundError("Group not found");
|
|
94
101
|
}
|
|
95
|
-
publishConversationListChanged(
|
|
102
|
+
publishConversationListChanged(
|
|
103
|
+
"reordered",
|
|
104
|
+
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
105
|
+
);
|
|
96
106
|
return serializeGroup(updated);
|
|
97
107
|
}
|
|
98
108
|
|
|
99
|
-
function handleDeleteGroup({ pathParams = {} }: RouteHandlerArgs) {
|
|
109
|
+
function handleDeleteGroup({ pathParams = {}, headers }: RouteHandlerArgs) {
|
|
100
110
|
const groupId = pathParams.groupId;
|
|
101
111
|
const existing = getGroup(groupId);
|
|
102
112
|
if (!existing) {
|
|
@@ -106,10 +116,13 @@ function handleDeleteGroup({ pathParams = {} }: RouteHandlerArgs) {
|
|
|
106
116
|
throw new ForbiddenError("System groups cannot be deleted");
|
|
107
117
|
}
|
|
108
118
|
deleteGroup(groupId);
|
|
109
|
-
publishConversationListChanged(
|
|
119
|
+
publishConversationListChanged(
|
|
120
|
+
"reordered",
|
|
121
|
+
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
122
|
+
);
|
|
110
123
|
}
|
|
111
124
|
|
|
112
|
-
function handleReorderGroups({ body = {} }: RouteHandlerArgs) {
|
|
125
|
+
function handleReorderGroups({ body = {}, headers }: RouteHandlerArgs) {
|
|
113
126
|
const updates = body.updates as
|
|
114
127
|
| Array<{ groupId: string; sortPosition: number }>
|
|
115
128
|
| undefined;
|
|
@@ -135,7 +148,10 @@ function handleReorderGroups({ body = {} }: RouteHandlerArgs) {
|
|
|
135
148
|
}
|
|
136
149
|
}
|
|
137
150
|
reorderGroups(updates);
|
|
138
|
-
publishConversationListChanged(
|
|
151
|
+
publishConversationListChanged(
|
|
152
|
+
"reordered",
|
|
153
|
+
headers?.["x-vellum-client-id"]?.trim() || undefined,
|
|
154
|
+
);
|
|
139
155
|
return { ok: true };
|
|
140
156
|
}
|
|
141
157
|
|
|
@@ -223,8 +223,9 @@ export type HostBrowserSessionInvalidatedResolution =
|
|
|
223
223
|
export function resolveHostBrowserSessionInvalidated(frame: {
|
|
224
224
|
targetId?: unknown;
|
|
225
225
|
reason?: unknown;
|
|
226
|
+
clientId?: unknown;
|
|
226
227
|
}): HostBrowserSessionInvalidatedResolution {
|
|
227
|
-
const { targetId, reason } = frame;
|
|
228
|
+
const { targetId, reason, clientId } = frame;
|
|
228
229
|
|
|
229
230
|
if (targetId !== undefined && typeof targetId !== "string") {
|
|
230
231
|
return {
|
|
@@ -235,6 +236,9 @@ export function resolveHostBrowserSessionInvalidated(frame: {
|
|
|
235
236
|
};
|
|
236
237
|
}
|
|
237
238
|
|
|
239
|
+
const resolvedClientId =
|
|
240
|
+
typeof clientId === "string" && clientId.length > 0 ? clientId : undefined;
|
|
241
|
+
|
|
238
242
|
if (typeof targetId === "string" && targetId.length > 0) {
|
|
239
243
|
markTargetInvalidated(
|
|
240
244
|
targetId,
|
|
@@ -245,7 +249,7 @@ export function resolveHostBrowserSessionInvalidated(frame: {
|
|
|
245
249
|
// Without this, a user closing the pinned tab manually would see
|
|
246
250
|
// their next browser command fail with a `cdp_session_not_found`
|
|
247
251
|
// until the daemon process restarts.
|
|
248
|
-
clearPinnedTabByTabId(targetId);
|
|
252
|
+
clearPinnedTabByTabId(targetId, resolvedClientId);
|
|
249
253
|
}
|
|
250
254
|
|
|
251
255
|
return { ok: true };
|
|
@@ -387,6 +391,10 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
387
391
|
.optional()
|
|
388
392
|
.describe("CDP target that was detached"),
|
|
389
393
|
reason: z.string().optional().describe("Detach reason"),
|
|
394
|
+
clientId: z
|
|
395
|
+
.string()
|
|
396
|
+
.optional()
|
|
397
|
+
.describe("Extension client ID that reported the invalidation"),
|
|
390
398
|
}),
|
|
391
399
|
responseBody: z.object({
|
|
392
400
|
accepted: z.boolean(),
|
|
@@ -107,12 +107,12 @@ function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
|
107
107
|
|
|
108
108
|
const conversation = findConversation(peeked.conversationId);
|
|
109
109
|
if (!conversation) {
|
|
110
|
-
pendingInteractions.resolve(requestId);
|
|
110
|
+
pendingInteractions.resolve(requestId, "cancelled");
|
|
111
111
|
throw new NotFoundError("Conversation not found for host CU result");
|
|
112
112
|
}
|
|
113
113
|
|
|
114
114
|
if (!conversation.hostCuProxy) {
|
|
115
|
-
pendingInteractions.resolve(requestId);
|
|
115
|
+
pendingInteractions.resolve(requestId, "cancelled");
|
|
116
116
|
throw new NotFoundError("No host CU proxy for conversation");
|
|
117
117
|
}
|
|
118
118
|
|
|
@@ -342,6 +342,49 @@ export async function enforceIngressAcl(
|
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
|
|
345
|
+
// Email: initiate a verification challenge via the guardian notification
|
|
346
|
+
// pipeline. Unlike Slack, we cannot DM the requester directly — the
|
|
347
|
+
// verification code is delivered to the guardian, who decides whether
|
|
348
|
+
// to share it with the email sender out-of-band.
|
|
349
|
+
if (sourceChannel === "email" && (canonicalSenderId ?? rawSenderId)) {
|
|
350
|
+
const emailVerifyResult = initiateEmailVerificationChallenge({
|
|
351
|
+
sourceChannel,
|
|
352
|
+
senderUserId: (canonicalSenderId ?? rawSenderId)!,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
if (emailVerifyResult.initiated) {
|
|
356
|
+
try {
|
|
357
|
+
notifyGuardianOfAccessRequest({
|
|
358
|
+
canonicalAssistantId,
|
|
359
|
+
sourceChannel,
|
|
360
|
+
conversationExternalId,
|
|
361
|
+
actorExternalId: canonicalSenderId ?? rawSenderId,
|
|
362
|
+
actorDisplayName,
|
|
363
|
+
actorUsername,
|
|
364
|
+
messagePreview: truncate(
|
|
365
|
+
trimmedContent,
|
|
366
|
+
MESSAGE_PREVIEW_MAX_LENGTH,
|
|
367
|
+
),
|
|
368
|
+
});
|
|
369
|
+
} catch (err) {
|
|
370
|
+
log.error(
|
|
371
|
+
{ err, sourceChannel, conversationExternalId },
|
|
372
|
+
"Failed to notify guardian of access request (email verification)",
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
return {
|
|
377
|
+
resolvedMember: null,
|
|
378
|
+
earlyResponse: ({
|
|
379
|
+
accepted: true,
|
|
380
|
+
denied: true,
|
|
381
|
+
reason: "verification_challenge_sent",
|
|
382
|
+
verificationSessionId: emailVerifyResult.sessionId,
|
|
383
|
+
}),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
|
|
345
388
|
// Notify the guardian about the access request so they can approve/deny.
|
|
346
389
|
// Uses the shared helper which handles guardian binding lookup,
|
|
347
390
|
// deduplication, canonical request creation, and notification emission.
|
|
@@ -1048,10 +1091,10 @@ async function handleInviteCodeIntercept(params: {
|
|
|
1048
1091
|
}
|
|
1049
1092
|
|
|
1050
1093
|
// ---------------------------------------------------------------------------
|
|
1051
|
-
//
|
|
1094
|
+
// Channel verification challenges
|
|
1052
1095
|
// ---------------------------------------------------------------------------
|
|
1053
1096
|
|
|
1054
|
-
interface
|
|
1097
|
+
interface VerificationChallengeResult {
|
|
1055
1098
|
initiated: boolean;
|
|
1056
1099
|
sessionId?: string;
|
|
1057
1100
|
}
|
|
@@ -1066,7 +1109,7 @@ interface SlackVerificationResult {
|
|
|
1066
1109
|
function initiateSlackVerificationChallenge(params: {
|
|
1067
1110
|
sourceChannel: ChannelId;
|
|
1068
1111
|
senderUserId: string;
|
|
1069
|
-
}):
|
|
1112
|
+
}): VerificationChallengeResult {
|
|
1070
1113
|
const { sourceChannel, senderUserId } = params;
|
|
1071
1114
|
|
|
1072
1115
|
// Skip if there is already a pending challenge or active session for
|
|
@@ -1121,3 +1164,53 @@ function initiateSlackVerificationChallenge(params: {
|
|
|
1121
1164
|
return { initiated: false };
|
|
1122
1165
|
}
|
|
1123
1166
|
}
|
|
1167
|
+
|
|
1168
|
+
// ---------------------------------------------------------------------------
|
|
1169
|
+
// Email verification challenge
|
|
1170
|
+
// ---------------------------------------------------------------------------
|
|
1171
|
+
|
|
1172
|
+
function initiateEmailVerificationChallenge(params: {
|
|
1173
|
+
sourceChannel: ChannelId;
|
|
1174
|
+
senderUserId: string;
|
|
1175
|
+
}): VerificationChallengeResult {
|
|
1176
|
+
const { sourceChannel, senderUserId } = params;
|
|
1177
|
+
|
|
1178
|
+
const existingChallenge = getPendingSession(sourceChannel);
|
|
1179
|
+
const existingSession = findActiveSession(sourceChannel);
|
|
1180
|
+
const senderHasPending =
|
|
1181
|
+
(existingChallenge &&
|
|
1182
|
+
existingChallenge.expectedExternalUserId === senderUserId) ||
|
|
1183
|
+
(existingSession &&
|
|
1184
|
+
existingSession.expectedExternalUserId === senderUserId);
|
|
1185
|
+
if (senderHasPending) {
|
|
1186
|
+
log.debug(
|
|
1187
|
+
{ sourceChannel, senderUserId },
|
|
1188
|
+
"Email verification: skipping — existing challenge/session for this sender",
|
|
1189
|
+
);
|
|
1190
|
+
return { initiated: false };
|
|
1191
|
+
}
|
|
1192
|
+
|
|
1193
|
+
try {
|
|
1194
|
+
const session = createOutboundSession({
|
|
1195
|
+
channel: sourceChannel,
|
|
1196
|
+
expectedExternalUserId: senderUserId,
|
|
1197
|
+
expectedChatId: senderUserId,
|
|
1198
|
+
identityBindingStatus: "bound",
|
|
1199
|
+
destinationAddress: senderUserId,
|
|
1200
|
+
verificationPurpose: "trusted_contact",
|
|
1201
|
+
});
|
|
1202
|
+
|
|
1203
|
+
log.info(
|
|
1204
|
+
{ sourceChannel, senderUserId, sessionId: session.sessionId },
|
|
1205
|
+
"Email verification challenge initiated for unknown contact",
|
|
1206
|
+
);
|
|
1207
|
+
|
|
1208
|
+
return { initiated: true, sessionId: session.sessionId };
|
|
1209
|
+
} catch (err) {
|
|
1210
|
+
log.error(
|
|
1211
|
+
{ err, sourceChannel, senderUserId },
|
|
1212
|
+
"Failed to initiate email verification challenge",
|
|
1213
|
+
);
|
|
1214
|
+
return { initiated: false };
|
|
1215
|
+
}
|
|
1216
|
+
}
|
|
@@ -18,10 +18,12 @@ import { ROUTES as AUDIT_ROUTES } from "./audit-routes.js";
|
|
|
18
18
|
import { ROUTES as AUTH_ROUTES } from "./auth-routes.js";
|
|
19
19
|
import { ROUTES as AVATAR_ROUTES } from "./avatar-routes.js";
|
|
20
20
|
import { ROUTES as BACKGROUND_TOOL_ROUTES } from "./background-tool-routes.js";
|
|
21
|
+
import { ROUTES as BACKGROUND_WAKE_ROUTES } from "./background-wake-routes.js";
|
|
21
22
|
import { ROUTES as BACKUP_ROUTES } from "./backup-routes.js";
|
|
22
23
|
import { ROUTES as BOOKMARK_ROUTES } from "./bookmark-routes.js";
|
|
23
24
|
import { ROUTES as BRAIN_GRAPH_ROUTES } from "./brain-graph-routes.js";
|
|
24
25
|
import { ROUTES as BROWSER_ROUTES } from "./browser-routes.js";
|
|
26
|
+
import { ROUTES as BROWSER_TABS_ROUTES } from "./browser-tabs-routes.js";
|
|
25
27
|
import { ROUTES as BTW_ROUTES } from "./btw-routes.js";
|
|
26
28
|
import { ROUTES as CACHE_ROUTES } from "./cache-routes.js";
|
|
27
29
|
import { ROUTES as CALL_ROUTES } from "./call-routes.js";
|
|
@@ -88,6 +90,7 @@ import { ROUTES as LOG_EXPORT_ROUTES } from "./log-export-routes.js";
|
|
|
88
90
|
import { ROUTES as MCP_AUTH_ROUTES } from "./mcp-auth-routes.js";
|
|
89
91
|
import { ROUTES as MEMORY_ITEM_ROUTES } from "./memory-item-routes.js";
|
|
90
92
|
import { ROUTES as MEMORY_V2_ROUTES } from "./memory-v2-routes.js";
|
|
93
|
+
import { ROUTES as MEMORY_V3_ROUTES } from "./memory-v3-routes.js";
|
|
91
94
|
import { ROUTES as MIGRATION_ROLLBACK_ROUTES } from "./migration-rollback-routes.js";
|
|
92
95
|
import { ROUTES as MIGRATION_ROUTES } from "./migration-routes.js";
|
|
93
96
|
import { ROUTES as NOTIFICATION_ROUTES } from "./notification-routes.js";
|
|
@@ -98,6 +101,7 @@ import { ROUTES as OAUTH_LIFECYCLE_ROUTES } from "./oauth-lifecycle-routes.js";
|
|
|
98
101
|
import { ROUTES as OAUTH_PROVIDERS_ROUTES } from "./oauth-providers.js";
|
|
99
102
|
import { ROUTES as PLATFORM_ROUTES } from "./platform-routes.js";
|
|
100
103
|
import { ROUTES as PLAYGROUND_ROUTES } from "./playground/index.js";
|
|
104
|
+
import { ROUTES as PLUGINS_ROUTES } from "./plugins-routes.js";
|
|
101
105
|
import { ROUTES as PROFILER_ROUTES } from "./profiler-routes.js";
|
|
102
106
|
import { ROUTES as PS_ROUTES } from "./ps-routes.js";
|
|
103
107
|
import { ROUTES as PUBLISH_ROUTES } from "./publish-routes.js";
|
|
@@ -145,6 +149,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
145
149
|
...AUDIT_ROUTES,
|
|
146
150
|
...AUTH_ROUTES,
|
|
147
151
|
...AVATAR_ROUTES,
|
|
152
|
+
...BACKGROUND_WAKE_ROUTES,
|
|
148
153
|
...BACKGROUND_TOOL_ROUTES,
|
|
149
154
|
...BACKUP_ROUTES,
|
|
150
155
|
...BOOKMARK_ROUTES,
|
|
@@ -156,6 +161,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
156
161
|
...CHANNEL_AVAILABILITY_ROUTES,
|
|
157
162
|
...CHANNEL_READINESS_ROUTES,
|
|
158
163
|
...BROWSER_ROUTES,
|
|
164
|
+
...BROWSER_TABS_ROUTES,
|
|
159
165
|
...BTW_ROUTES,
|
|
160
166
|
...BRAIN_GRAPH_ROUTES,
|
|
161
167
|
...CLIENT_ROUTES,
|
|
@@ -211,6 +217,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
211
217
|
...LLM_CALL_SITES_ROUTES,
|
|
212
218
|
...MEMORY_ITEM_ROUTES,
|
|
213
219
|
...MEMORY_V2_ROUTES,
|
|
220
|
+
...MEMORY_V3_ROUTES,
|
|
214
221
|
...MIGRATION_ROLLBACK_ROUTES,
|
|
215
222
|
...MIGRATION_ROUTES,
|
|
216
223
|
...NOTIFICATION_ROUTES,
|
|
@@ -220,6 +227,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
220
227
|
...OAUTH_PROVIDERS_ROUTES,
|
|
221
228
|
...PLATFORM_ROUTES,
|
|
222
229
|
...PLAYGROUND_ROUTES,
|
|
230
|
+
...PLUGINS_ROUTES,
|
|
223
231
|
...PROFILER_ROUTES,
|
|
224
232
|
...PS_ROUTES,
|
|
225
233
|
...PUBLISH_ROUTES,
|
|
@@ -67,11 +67,13 @@ export async function setInferenceProfileSession({
|
|
|
67
67
|
profile,
|
|
68
68
|
ttlSeconds,
|
|
69
69
|
sessionId: callerSessionId,
|
|
70
|
+
originClientId,
|
|
70
71
|
}: {
|
|
71
72
|
conversationId: string;
|
|
72
73
|
profile: string | null;
|
|
73
74
|
ttlSeconds?: number | null;
|
|
74
75
|
sessionId?: string;
|
|
76
|
+
originClientId?: string;
|
|
75
77
|
}): Promise<InferenceProfileSessionResult> {
|
|
76
78
|
const resolvedId = resolveConversationId(conversationId) ?? conversationId;
|
|
77
79
|
const conversation = getConversation(resolvedId);
|
|
@@ -116,12 +118,15 @@ export async function setInferenceProfileSession({
|
|
|
116
118
|
};
|
|
117
119
|
}
|
|
118
120
|
setConversationInferenceProfileSession(resolvedId, null, null, null);
|
|
119
|
-
publishConversationInferenceProfileChanged(
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
121
|
+
publishConversationInferenceProfileChanged(
|
|
122
|
+
{
|
|
123
|
+
conversationId: resolvedId,
|
|
124
|
+
profile: null,
|
|
125
|
+
sessionId: null,
|
|
126
|
+
expiresAt: null,
|
|
127
|
+
},
|
|
128
|
+
originClientId,
|
|
129
|
+
);
|
|
125
130
|
return {
|
|
126
131
|
conversationId: resolvedId,
|
|
127
132
|
profile: null,
|
|
@@ -184,12 +189,15 @@ export async function setInferenceProfileSession({
|
|
|
184
189
|
newExpiresAt ?? null,
|
|
185
190
|
);
|
|
186
191
|
|
|
187
|
-
publishConversationInferenceProfileChanged(
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
192
|
+
publishConversationInferenceProfileChanged(
|
|
193
|
+
{
|
|
194
|
+
conversationId: resolvedId,
|
|
195
|
+
profile,
|
|
196
|
+
sessionId: newSessionId ?? null,
|
|
197
|
+
expiresAt: newExpiresAt ?? null,
|
|
198
|
+
},
|
|
199
|
+
originClientId,
|
|
200
|
+
);
|
|
193
201
|
|
|
194
202
|
return {
|
|
195
203
|
conversationId: resolvedId,
|
|
@@ -218,6 +226,7 @@ export async function setInferenceProfileSession({
|
|
|
218
226
|
*/
|
|
219
227
|
export async function closeInferenceProfileSession(
|
|
220
228
|
conversationId: string,
|
|
229
|
+
originClientId?: string,
|
|
221
230
|
): Promise<{
|
|
222
231
|
conversationId: string;
|
|
223
232
|
closed: { profile: string | null; sessionId: string | null } | null;
|
|
@@ -241,6 +250,7 @@ export async function closeInferenceProfileSession(
|
|
|
241
250
|
const result = await setInferenceProfileSession({
|
|
242
251
|
conversationId: resolvedId,
|
|
243
252
|
profile: null,
|
|
253
|
+
originClientId,
|
|
244
254
|
});
|
|
245
255
|
return {
|
|
246
256
|
conversationId: result.conversationId,
|