@vellumai/assistant 0.7.1 → 0.7.2
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 +32 -49
- package/Dockerfile +1 -0
- package/README.md +1 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
- package/bun.lock +26 -26
- package/docs/architecture/security.md +20 -0
- package/docs/plugins.md +7 -9
- package/knip.json +1 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
- package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
- package/node_modules/@vellumai/service-contracts/package.json +2 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
- package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
- package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
- package/node_modules/@vellumai/twilio-client/package.json +18 -0
- package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
- package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
- package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
- package/openapi.yaml +565 -12
- package/package.json +6 -3
- package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
- package/src/__tests__/app-bundler.test.ts +170 -1
- package/src/__tests__/app-control-flow.test.ts +374 -0
- package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
- package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
- package/src/__tests__/app-executors.test.ts +30 -43
- package/src/__tests__/approval-routes-http.test.ts +23 -6
- package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
- package/src/__tests__/assistant-event-hub.test.ts +109 -2
- package/src/__tests__/assistant-event.test.ts +10 -0
- package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
- package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
- package/src/__tests__/background-shell-host-bash.test.ts +14 -15
- package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
- package/src/__tests__/btw-routes.test.ts +13 -4
- package/src/__tests__/call-controller.test.ts +49 -1
- package/src/__tests__/call-domain.test.ts +0 -2
- package/src/__tests__/call-routes-http.test.ts +0 -2
- package/src/__tests__/channel-readiness-service.test.ts +59 -1
- package/src/__tests__/checker.test.ts +3 -4
- package/src/__tests__/config-loader-backfill.test.ts +90 -155
- package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
- package/src/__tests__/config-schema-cmd.test.ts +0 -1
- package/src/__tests__/config-set-platform-guard.test.ts +48 -4
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
- package/src/__tests__/config-watcher.test.ts +2 -2
- package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
- package/src/__tests__/conversation-lifecycle.test.ts +36 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/conversation-slash-commands.test.ts +0 -4
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
- package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
- package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
- package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
- package/src/__tests__/credentials-cli.test.ts +5 -12
- package/src/__tests__/cu-unified-flow.test.ts +185 -23
- package/src/__tests__/daemon-credential-client.test.ts +101 -19
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
- package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
- package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
- package/src/__tests__/heartbeat-service.test.ts +718 -1
- package/src/__tests__/helpers/call-route-handler.ts +7 -1
- package/src/__tests__/host-app-control-proxy.test.ts +602 -0
- package/src/__tests__/host-app-control-routes.test.ts +263 -0
- package/src/__tests__/host-bash-proxy.test.ts +246 -47
- package/src/__tests__/host-bash-routes.test.ts +294 -0
- package/src/__tests__/host-browser-proxy.test.ts +24 -22
- package/src/__tests__/host-browser-routes.test.ts +39 -13
- package/src/__tests__/host-cu-proxy.test.ts +41 -52
- package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
- package/src/__tests__/host-file-edit-tool.test.ts +47 -1
- package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
- package/src/__tests__/host-file-proxy.test.ts +37 -43
- package/src/__tests__/host-file-read-tool.test.ts +17 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
- package/src/__tests__/host-file-write-tool.test.ts +42 -1
- package/src/__tests__/host-proxy-base.test.ts +312 -0
- package/src/__tests__/host-shell-tool.test.ts +22 -4
- package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
- package/src/__tests__/host-transfer-proxy.test.ts +121 -22
- package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/identity-intro-cache.test.ts +29 -0
- package/src/__tests__/identity-routes.test.ts +103 -1
- package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
- package/src/__tests__/inline-command-runner.test.ts +0 -1
- package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
- package/src/__tests__/integration-status.test.ts +85 -5
- package/src/__tests__/intent-routing.test.ts +0 -1
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
- package/src/__tests__/mcp-auth-routes.test.ts +197 -0
- package/src/__tests__/mcp-cli.test.ts +338 -2
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
- package/src/__tests__/migration-import-commit-http.test.ts +108 -2
- package/src/__tests__/mock-gateway-ipc.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +0 -2
- package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
- package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
- package/src/__tests__/process-message-background-slack.test.ts +2 -0
- package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
- package/src/__tests__/public-ingress-urls.test.ts +97 -0
- package/src/__tests__/require-fresh-approval.test.ts +0 -1
- package/src/__tests__/retry-backoff.test.ts +87 -0
- package/src/__tests__/runtime-events-sse.test.ts +10 -6
- package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
- package/src/__tests__/schedule-retry.test.ts +715 -0
- package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
- package/src/__tests__/secret-ingress-http.test.ts +1 -0
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
- package/src/__tests__/skill-feature-flags.test.ts +43 -41
- package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
- package/src/__tests__/skill-load-inline-command.test.ts +0 -51
- package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
- package/src/__tests__/slack-channel-config.test.ts +9 -14
- package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
- package/src/__tests__/system-prompt.test.ts +0 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/test-preload.ts +8 -0
- package/src/__tests__/tool-approval-handler.test.ts +3 -4
- package/src/__tests__/tool-audit-listener.test.ts +48 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
- package/src/__tests__/tool-executor.test.ts +0 -1
- package/src/__tests__/twilio-config.test.ts +3 -16
- package/src/__tests__/twilio-routes.test.ts +3 -5
- package/src/__tests__/twilio-validation.test.ts +93 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
- package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
- package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
- package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
- package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
- package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
- package/src/backup/__tests__/paths.test.ts +0 -22
- package/src/backup/__tests__/restore.test.ts +51 -151
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +107 -231
- package/src/bundler/app-bundler.ts +51 -3
- package/src/calls/relay-server.ts +4 -44
- package/src/calls/twilio-config.ts +2 -17
- package/src/calls/twilio-rest.ts +33 -105
- package/src/calls/twilio-routes.ts +11 -12
- package/src/channels/types.ts +8 -7
- package/src/cli/commands/__tests__/backup.test.ts +6 -277
- package/src/cli/commands/__tests__/gateway.test.ts +288 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
- package/src/cli/commands/backup.ts +6 -331
- package/src/cli/commands/clients.ts +36 -37
- package/src/cli/commands/contacts.ts +73 -0
- package/src/cli/commands/conversations.ts +2 -5
- package/src/cli/commands/credentials.ts +15 -7
- package/src/cli/commands/domain.ts +66 -15
- package/src/cli/commands/gateway.ts +183 -0
- package/src/cli/commands/keys.ts +9 -6
- package/src/cli/commands/mcp.ts +116 -156
- package/src/cli/commands/memory-v2.ts +296 -1
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
- package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
- package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
- package/src/cli/commands/platform/disconnect.ts +5 -4
- package/src/cli/commands/platform/index.ts +0 -18
- package/src/cli/lib/daemon-credential-client.ts +110 -28
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +67 -10
- package/src/config/bundled-skills/acp/SKILL.md +6 -0
- package/src/config/bundled-skills/acp/TOOLS.json +1 -22
- package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
- package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
- package/src/config/bundled-skills/app-control/SKILL.md +75 -0
- package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
- package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
- package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
- package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
- package/src/config/bundled-skills/document/TOOLS.json +0 -8
- package/src/config/bundled-skills/followups/TOOLS.json +0 -12
- package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
- package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
- package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
- package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
- package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
- package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
- package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
- package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
- package/src/config/bundled-skills/settings/SKILL.md +4 -0
- package/src/config/bundled-skills/settings/TOOLS.json +0 -12
- package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
- package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
- package/src/config/bundled-skills/subagent/SKILL.md +6 -2
- package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
- package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
- package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
- package/src/config/bundled-tool-registry.ts +21 -0
- package/src/config/env-registry.ts +0 -2
- package/src/config/env.ts +19 -12
- package/src/config/feature-flag-registry.json +21 -133
- package/src/config/loader.ts +73 -99
- package/src/config/sanitize-for-transfer.ts +2 -0
- package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
- package/src/config/schemas/calls.ts +0 -9
- package/src/config/schemas/heartbeat.ts +63 -0
- package/src/config/schemas/ingress.ts +10 -6
- package/src/config/schemas/llm.ts +5 -10
- package/src/config/schemas/memory-lifecycle.ts +77 -24
- package/src/config/schemas/memory-v2.ts +48 -4
- package/src/config/schemas/platform.ts +6 -0
- package/src/config/schemas/services.ts +1 -15
- package/src/config/schemas/skills.ts +0 -6
- package/src/config/seed-inference-profiles.ts +1 -1
- package/src/contacts/contact-store.ts +0 -30
- package/src/contacts/contacts-write.ts +0 -27
- package/src/context/window-manager.ts +1 -2
- package/src/credential-execution/feature-gates.ts +10 -10
- package/src/credential-execution/process-manager.ts +12 -41
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
- package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
- package/src/daemon/config-watcher.ts +4 -3
- package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
- package/src/daemon/conversation-agent-loop.ts +32 -28
- package/src/daemon/conversation-lifecycle.ts +8 -1
- package/src/daemon/conversation-process.ts +16 -11
- package/src/daemon/conversation-runtime-assembly.ts +2 -2
- package/src/daemon/conversation-surfaces.ts +125 -4
- package/src/daemon/conversation-tool-setup.ts +16 -55
- package/src/daemon/conversation.ts +21 -2
- package/src/daemon/doordash-steps.ts +1 -1
- package/src/daemon/handlers/shared.ts +4 -1
- package/src/daemon/host-app-control-proxy.ts +293 -0
- package/src/daemon/host-bash-proxy.ts +84 -74
- package/src/daemon/host-browser-proxy.ts +67 -82
- package/src/daemon/host-cu-proxy.ts +81 -86
- package/src/daemon/host-file-proxy.ts +93 -69
- package/src/daemon/host-proxy-base.ts +294 -0
- package/src/daemon/host-proxy-preactivation.ts +82 -0
- package/src/daemon/host-transfer-proxy.ts +247 -129
- package/src/daemon/lifecycle.ts +115 -117
- package/src/daemon/message-protocol.ts +3 -8
- package/src/daemon/message-types/contacts.ts +23 -1
- package/src/daemon/message-types/conversations.ts +11 -8
- package/src/daemon/message-types/host-app-control.ts +150 -0
- package/src/daemon/message-types/host-bash.ts +4 -0
- package/src/daemon/message-types/host-cu.ts +2 -0
- package/src/daemon/message-types/host-file.ts +4 -0
- package/src/daemon/message-types/host-transfer.ts +3 -0
- package/src/daemon/message-types/schedules.ts +8 -3
- package/src/daemon/message-types/skills.ts +2 -2
- package/src/daemon/process-message.ts +18 -1
- package/src/daemon/shutdown-handlers.ts +0 -3
- package/src/daemon/tool-setup-types.ts +51 -0
- package/src/daemon/tool-side-effects.ts +1 -1
- package/src/events/tool-audit-listener.ts +2 -1
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
- package/src/heartbeat/heartbeat-run-store.ts +236 -0
- package/src/heartbeat/heartbeat-service.ts +280 -49
- package/src/home/__tests__/post-connect-feed.test.ts +99 -0
- package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
- package/src/home/__tests__/suggested-prompts.test.ts +89 -0
- package/src/home/post-connect-feed.ts +68 -0
- package/src/home/relationship-state-writer.ts +17 -92
- package/src/home/suggested-prompts.ts +46 -10
- package/src/inbound/public-ingress-urls.ts +32 -34
- package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
- package/src/ipc/assistant-server.ts +14 -1
- package/src/ipc/cli-client.ts +32 -1
- package/src/live-voice/live-voice-metrics.ts +10 -10
- package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
- package/src/mcp/mcp-auth-orchestrator.ts +213 -0
- package/src/mcp/mcp-auth-state.ts +133 -0
- package/src/mcp/mcp-oauth-provider.ts +19 -0
- package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
- package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
- package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
- package/src/memory/anisotropy.test.ts +247 -0
- package/src/memory/anisotropy.ts +443 -0
- package/src/memory/auto-analysis-constants.ts +17 -0
- package/src/memory/auto-analysis-guard.ts +5 -15
- package/src/memory/canonical-guardian-store.ts +7 -7
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
- package/src/memory/context-search/agent-protocol.ts +6 -6
- package/src/memory/context-search/agent-runner.ts +32 -7
- package/src/memory/context-search/sources/memory-v2.ts +17 -5
- package/src/memory/conversation-crud.ts +1 -1
- package/src/memory/conversation-key-store.ts +2 -15
- package/src/memory/db-init.ts +4 -0
- package/src/memory/embedding-backend.ts +9 -21
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
- package/src/memory/graph/conversation-graph-memory.ts +1 -24
- package/src/memory/graph/graph-search.ts +8 -0
- package/src/memory/graph/retriever.ts +28 -0
- package/src/memory/graph/tools.ts +1 -1
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
- package/src/memory/jobs/embed-concept-page.ts +28 -2
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
- package/src/memory/jobs-store.ts +66 -22
- package/src/memory/jobs-worker.ts +112 -63
- package/src/memory/memory-v2-activation-log-store.ts +1 -1
- package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
- package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
- package/src/memory/migrations/index.ts +5 -0
- package/src/memory/migrations/registry.ts +8 -0
- package/src/memory/pkb/pkb-search.ts +7 -0
- package/src/memory/qdrant-client.ts +50 -20
- package/src/memory/schema/infrastructure.ts +15 -0
- package/src/memory/search/semantic.ts +7 -0
- package/src/memory/sparse-tokenize.ts +49 -0
- package/src/memory/v2/__tests__/activation.test.ts +77 -95
- package/src/memory/v2/__tests__/injection.test.ts +43 -21
- package/src/memory/v2/__tests__/sim.test.ts +166 -6
- package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
- package/src/memory/v2/__tests__/static-context.test.ts +0 -1
- package/src/memory/v2/activation.ts +69 -88
- package/src/memory/v2/consolidation-job.ts +3 -5
- package/src/memory/v2/constants.ts +7 -0
- package/src/memory/v2/injection.ts +86 -53
- package/src/memory/v2/prompts/consolidation.ts +312 -91
- package/src/memory/v2/qdrant.ts +99 -1
- package/src/memory/v2/sim.ts +126 -16
- package/src/memory/v2/skill-qdrant.ts +12 -3
- package/src/memory/v2/skill-store.ts +16 -1
- package/src/memory/v2/sparse-bm25.ts +245 -0
- package/src/memory/v2/static-context.ts +6 -5
- package/src/messaging/providers/gmail/types.ts +0 -49
- package/src/messaging/providers/slack/adapter.ts +1 -31
- package/src/messaging/providers/slack/types.ts +0 -32
- package/src/notifications/README.md +10 -10
- package/src/notifications/broadcaster.ts +1 -1
- package/src/notifications/guardian-question-mode.ts +5 -5
- package/src/oauth/connect-orchestrator.ts +4 -0
- package/src/oauth/credential-token-resolver.ts +1 -3
- package/src/oauth/manual-token-connection.ts +0 -4
- package/src/outbound-proxy/index.ts +1 -37
- package/src/outbound-proxy/logging.ts +1 -1
- package/src/outbound-proxy/policy.ts +6 -5
- package/src/outbound-proxy/router.ts +2 -1
- package/src/permissions/approval-policy.test.ts +6 -275
- package/src/permissions/approval-policy.ts +0 -51
- package/src/permissions/checker.test.ts +0 -1
- package/src/permissions/checker.ts +3 -17
- package/src/permissions/gateway-threshold-reader.ts +2 -0
- package/src/permissions/prompter.ts +34 -1
- package/src/permissions/secret-prompter.ts +6 -2
- package/src/prompts/bootstrap-cleanup.ts +27 -0
- package/src/prompts/system-prompt.ts +3 -18
- package/src/prompts/templates/SOUL.md +13 -1
- package/src/providers/speech-to-text/provider-catalog.ts +7 -8
- package/src/runtime/assistant-event-hub.ts +118 -96
- package/src/runtime/assistant-event.ts +1 -0
- package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
- package/src/runtime/auth/middleware.ts +0 -96
- package/src/runtime/auth/route-policy.ts +19 -0
- package/src/runtime/btw-sidechain.ts +2 -3
- package/src/runtime/channel-invite-transport.ts +2 -48
- package/src/runtime/channel-invite-transports/email.ts +1 -1
- package/src/runtime/channel-invite-transports/slack.ts +1 -1
- package/src/runtime/channel-invite-transports/telegram.ts +1 -1
- package/src/runtime/channel-invite-transports/voice.ts +1 -1
- package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
- package/src/runtime/channel-invite-types.ts +54 -0
- package/src/runtime/channel-readiness-service.ts +32 -13
- package/src/runtime/http-server.ts +3 -329
- package/src/runtime/http-types.ts +0 -5
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
- package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
- package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
- package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
- package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
- package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
- package/src/runtime/migrations/migration-transport.ts +7 -7
- package/src/runtime/migrations/vbundle-builder.ts +327 -60
- package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
- package/src/runtime/migrations/vbundle-importer.ts +245 -68
- package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
- package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
- package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
- package/src/runtime/migrations/vbundle-validator.ts +114 -0
- package/src/runtime/pending-interactions.ts +35 -9
- package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
- package/src/runtime/routes/approval-interception-types.ts +13 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
- package/src/runtime/routes/backup-routes.ts +15 -38
- package/src/runtime/routes/btw-routes.ts +14 -37
- package/src/runtime/routes/client-routes.ts +1 -0
- package/src/runtime/routes/contact-prompt-routes.ts +183 -0
- package/src/runtime/routes/conversation-query-routes.ts +36 -1
- package/src/runtime/routes/conversation-routes.ts +30 -13
- package/src/runtime/routes/document-pdf-renderer.ts +165 -0
- package/src/runtime/routes/documents-routes.ts +30 -0
- package/src/runtime/routes/errors.ts +19 -4
- package/src/runtime/routes/events-routes.ts +12 -6
- package/src/runtime/routes/gateway-log-routes.ts +79 -0
- package/src/runtime/routes/guardian-approval-interception.ts +2 -8
- package/src/runtime/routes/heartbeat-routes.ts +103 -38
- package/src/runtime/routes/host-app-control-routes.ts +134 -0
- package/src/runtime/routes/host-bash-routes.ts +36 -6
- package/src/runtime/routes/host-browser-routes.ts +108 -13
- package/src/runtime/routes/host-cu-routes.ts +44 -14
- package/src/runtime/routes/host-file-routes.ts +33 -10
- package/src/runtime/routes/host-transfer-routes.ts +64 -24
- package/src/runtime/routes/http-adapter.ts +1 -0
- package/src/runtime/routes/identity-intro-cache.ts +30 -0
- package/src/runtime/routes/identity-routes.ts +15 -43
- package/src/runtime/routes/inbound-message-handler.ts +1 -9
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
- package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
- package/src/runtime/routes/index.ts +8 -0
- package/src/runtime/routes/mcp-auth-routes.ts +132 -0
- package/src/runtime/routes/memory-item-routes.ts +10 -12
- package/src/runtime/routes/memory-v2-routes.ts +441 -1
- package/src/runtime/routes/migration-routes.ts +96 -0
- package/src/runtime/routes/schedule-routes.ts +7 -0
- package/src/runtime/verification-templates.ts +4 -7
- package/src/schedule/integration-status.ts +66 -2
- package/src/schedule/recurrence-engine.ts +4 -1
- package/src/schedule/retry-backoff.ts +18 -0
- package/src/schedule/retry-policy.ts +82 -0
- package/src/schedule/schedule-recovery.ts +64 -0
- package/src/schedule/schedule-store.ts +106 -2
- package/src/schedule/scheduler-types.ts +25 -0
- package/src/schedule/scheduler.ts +63 -38
- package/src/security/oauth-callback-registry.ts +8 -0
- package/src/sequence/analytics.ts +5 -5
- package/src/sequence/engine.ts +1 -1
- package/src/skills/catalog-files.ts +2 -8
- package/src/skills/include-graph.ts +5 -5
- package/src/skills/remote-skill-policy.ts +5 -5
- package/src/skills/skill-file-provider.ts +1 -1
- package/src/skills/skill-file-types.ts +13 -0
- package/src/skills/skillssh-audit-types.ts +28 -0
- package/src/skills/skillssh-registry.ts +8 -21
- package/src/telemetry/types.ts +2 -0
- package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
- package/src/telemetry/usage-telemetry-reporter.ts +1 -0
- package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
- package/src/tools/apps/executors.ts +56 -69
- package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
- package/src/tools/browser/browser-execution.ts +2 -2
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
- package/src/tools/browser/cdp-client/factory.ts +23 -24
- package/src/tools/browser/cdp-client/index.ts +1 -14
- package/src/tools/computer-use/definitions.ts +42 -20
- package/src/tools/executor.ts +2 -0
- package/src/tools/host-filesystem/edit.ts +26 -0
- package/src/tools/host-filesystem/read.ts +26 -0
- package/src/tools/host-filesystem/transfer.ts +31 -1
- package/src/tools/host-filesystem/write.ts +26 -0
- package/src/tools/host-terminal/host-shell.ts +58 -0
- package/src/tools/schedule/create.ts +6 -0
- package/src/tools/schedule/list.ts +2 -0
- package/src/tools/schedule/update.ts +10 -0
- package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
- package/src/tools/shared/filesystem/path-policy.ts +25 -1
- package/src/tools/skills/load.ts +0 -32
- package/src/tools/tool-approval-handler.ts +1 -5
- package/src/tools/types.ts +4 -0
- package/src/usage/pricing.ts +1 -1
- package/src/workspace/hatched-date.ts +86 -0
- package/src/workspace/migrations/003-seed-device-id.ts +1 -1
- package/src/workspace/migrations/006-services-config.ts +8 -5
- package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
- package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
- package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
- package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
- package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
- package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
- package/src/workspace/migrations/AGENTS.md +1 -1
- package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
- package/src/workspace/migrations/utils.ts +21 -0
- package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
- package/src/__tests__/twilio-rest.test.ts +0 -34
- package/src/backup/__tests__/backup-key.test.ts +0 -152
- package/src/backup/__tests__/backup-worker.test.ts +0 -782
- package/src/backup/__tests__/offsite-writer.test.ts +0 -641
- package/src/backup/__tests__/stream-crypt.test.ts +0 -228
- package/src/backup/backup-key.ts +0 -137
- package/src/backup/backup-worker.ts +0 -472
- package/src/backup/offsite-writer.ts +0 -222
- package/src/backup/stream-crypt.ts +0 -263
- package/src/daemon/message-types/pairing.ts +0 -58
- package/src/outbound-proxy/config.ts +0 -20
- package/src/outbound-proxy/health.ts +0 -18
- package/src/outbound-proxy/types.ts +0 -150
- package/src/runtime/capability-tokens.ts +0 -190
- package/src/signals/mcp-reload.ts +0 -18
|
@@ -1,443 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* E2E smoke test for the cloud-hosted `host_browser_request` round-trip.
|
|
3
|
-
*
|
|
4
|
-
* Boots the runtime HTTP server in-process, opens a mock chrome-extension
|
|
5
|
-
* WebSocket against `/v1/browser-relay`, and drives
|
|
6
|
-
* `HostBrowserProxy.instance.request()` end-to-end:
|
|
7
|
-
*
|
|
8
|
-
* proxy.request()
|
|
9
|
-
* → sendToExtension (routed via assistant event hub)
|
|
10
|
-
* → mock extension WebSocket receives host_browser_request
|
|
11
|
-
* → mock CDP handler (Browser.getVersion fake)
|
|
12
|
-
* → POST /v1/host-browser-result (or WS host_browser_result frame)
|
|
13
|
-
* → resolveHostBrowserResultByRequestId → proxy.resolve()
|
|
14
|
-
* → request() resolves
|
|
15
|
-
*
|
|
16
|
-
* Covers:
|
|
17
|
-
* - Happy path: Browser.getVersion round-trips and returns the fake
|
|
18
|
-
* product string.
|
|
19
|
-
* - Abort: an aborted AbortSignal resolves with "Aborted" and the mock
|
|
20
|
-
* extension receives a host_browser_cancel frame.
|
|
21
|
-
* - Timeout: if the mock extension receives the frame but never
|
|
22
|
-
* POSTs a result, the proxy's setTimeout path fires and surfaces
|
|
23
|
-
* a "timed out waiting for client response" error.
|
|
24
|
-
*
|
|
25
|
-
* The test runs entirely in Bun + loopback WebSocket/fetch — no real
|
|
26
|
-
* Chrome required.
|
|
27
|
-
*/
|
|
28
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
29
|
-
|
|
30
|
-
// ── Module mocks (must be declared before the real imports below) ────
|
|
31
|
-
|
|
32
|
-
mock.module("../util/logger.js", () => ({
|
|
33
|
-
getLogger: () =>
|
|
34
|
-
new Proxy({} as Record<string, unknown>, {
|
|
35
|
-
get: () => () => {},
|
|
36
|
-
}),
|
|
37
|
-
}));
|
|
38
|
-
|
|
39
|
-
mock.module("../config/loader.js", () => ({
|
|
40
|
-
getConfig: () => ({
|
|
41
|
-
ui: {},
|
|
42
|
-
model: "test",
|
|
43
|
-
provider: "test",
|
|
44
|
-
memory: { enabled: false },
|
|
45
|
-
rateLimit: { maxRequestsPerMinute: 0 },
|
|
46
|
-
secretDetection: { enabled: false },
|
|
47
|
-
contextWindow: { maxInputTokens: 200000 },
|
|
48
|
-
services: {
|
|
49
|
-
inference: {
|
|
50
|
-
mode: "your-own",
|
|
51
|
-
provider: "anthropic",
|
|
52
|
-
model: "claude-opus-4-6",
|
|
53
|
-
},
|
|
54
|
-
"image-generation": {
|
|
55
|
-
mode: "your-own",
|
|
56
|
-
provider: "gemini",
|
|
57
|
-
model: "gemini-3.1-flash-image-preview",
|
|
58
|
-
},
|
|
59
|
-
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
60
|
-
},
|
|
61
|
-
}),
|
|
62
|
-
}));
|
|
63
|
-
|
|
64
|
-
// ── Real imports (after mocks) ──────────────────────────────────────
|
|
65
|
-
|
|
66
|
-
import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
|
|
67
|
-
import { getDb } from "../memory/db-connection.js";
|
|
68
|
-
import { initializeDb } from "../memory/db-init.js";
|
|
69
|
-
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
70
|
-
import { mintToken } from "../runtime/auth/token-service.js";
|
|
71
|
-
import { RuntimeHttpServer } from "../runtime/http-server.js";
|
|
72
|
-
|
|
73
|
-
initializeDb();
|
|
74
|
-
|
|
75
|
-
// ── Helpers ─────────────────────────────────────────────────────────
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Mint an actor-bound JWT for the given guardianId. The WebSocket
|
|
79
|
-
* upgrade handler parses `sub=actor:<assistantId>:<actorPrincipalId>`
|
|
80
|
-
* and treats `actorPrincipalId` as the guardianId.
|
|
81
|
-
*/
|
|
82
|
-
function mintActorToken(guardianId: string): string {
|
|
83
|
-
return mintToken({
|
|
84
|
-
aud: "vellum-daemon",
|
|
85
|
-
sub: `actor:self:${guardianId}`,
|
|
86
|
-
scope_profile: "actor_client_v1",
|
|
87
|
-
policy_epoch: 1,
|
|
88
|
-
ttlSeconds: 3600,
|
|
89
|
-
});
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
// ── Tests ───────────────────────────────────────────────────────────
|
|
93
|
-
|
|
94
|
-
describe("host_browser cloud-hosted e2e round-trip", () => {
|
|
95
|
-
let server: RuntimeHttpServer;
|
|
96
|
-
let port: number;
|
|
97
|
-
let runtimeBaseUrl: string;
|
|
98
|
-
|
|
99
|
-
beforeEach(async () => {
|
|
100
|
-
const db = getDb();
|
|
101
|
-
db.run("DELETE FROM contact_channels");
|
|
102
|
-
db.run("DELETE FROM contacts");
|
|
103
|
-
HostBrowserProxy.reset();
|
|
104
|
-
|
|
105
|
-
port = 19800 + Math.floor(Math.random() * 200);
|
|
106
|
-
runtimeBaseUrl = `http://127.0.0.1:${port}`;
|
|
107
|
-
server = new RuntimeHttpServer({ port });
|
|
108
|
-
await server.start();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
afterEach(async () => {
|
|
112
|
-
await server?.stop();
|
|
113
|
-
HostBrowserProxy.reset();
|
|
114
|
-
});
|
|
115
|
-
|
|
116
|
-
test("happy path: Browser.getVersion round-trips through the mock extension", async () => {
|
|
117
|
-
const guardianId = `test-guardian-${crypto.randomUUID()}`;
|
|
118
|
-
const token = mintActorToken(guardianId);
|
|
119
|
-
|
|
120
|
-
const { createMockChromeExtension } =
|
|
121
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
122
|
-
const mockExt = createMockChromeExtension({
|
|
123
|
-
runtimeBaseUrl,
|
|
124
|
-
token,
|
|
125
|
-
});
|
|
126
|
-
await mockExt.start();
|
|
127
|
-
await mockExt.waitForConnection();
|
|
128
|
-
await waitForRegistryEntry(guardianId);
|
|
129
|
-
|
|
130
|
-
const proxy = HostBrowserProxy.instance;
|
|
131
|
-
|
|
132
|
-
const result = await proxy.request(
|
|
133
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
134
|
-
"conv-happy",
|
|
135
|
-
);
|
|
136
|
-
|
|
137
|
-
expect(result.isError).toBe(false);
|
|
138
|
-
expect(result.content).toContain("Chrome/MockTest");
|
|
139
|
-
|
|
140
|
-
const received = mockExt.receivedRequests();
|
|
141
|
-
expect(received).toHaveLength(1);
|
|
142
|
-
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
143
|
-
expect(typeof received[0].requestId).toBe("string");
|
|
144
|
-
expect(received[0].conversationId).toBe("conv-happy");
|
|
145
|
-
|
|
146
|
-
await mockExt.stop();
|
|
147
|
-
});
|
|
148
|
-
|
|
149
|
-
test("happy path (WS result transport): Browser.getVersion round-trips when the extension returns the result over the same WS", async () => {
|
|
150
|
-
const guardianId = `test-guardian-${crypto.randomUUID()}`;
|
|
151
|
-
const token = mintActorToken(guardianId);
|
|
152
|
-
|
|
153
|
-
const { createMockChromeExtension } =
|
|
154
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
155
|
-
const mockExt = createMockChromeExtension({
|
|
156
|
-
runtimeBaseUrl,
|
|
157
|
-
token,
|
|
158
|
-
resultTransport: "ws",
|
|
159
|
-
});
|
|
160
|
-
await mockExt.start();
|
|
161
|
-
await mockExt.waitForConnection();
|
|
162
|
-
await waitForRegistryEntry(guardianId);
|
|
163
|
-
|
|
164
|
-
const proxy = HostBrowserProxy.instance;
|
|
165
|
-
|
|
166
|
-
const result = await proxy.request(
|
|
167
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
168
|
-
"conv-happy-ws",
|
|
169
|
-
);
|
|
170
|
-
|
|
171
|
-
expect(result.isError).toBe(false);
|
|
172
|
-
expect(result.content).toContain("Chrome/MockTest");
|
|
173
|
-
|
|
174
|
-
const received = mockExt.receivedRequests();
|
|
175
|
-
expect(received).toHaveLength(1);
|
|
176
|
-
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
177
|
-
expect(received[0].conversationId).toBe("conv-happy-ws");
|
|
178
|
-
|
|
179
|
-
expect(proxy.hasPendingRequest(received[0].requestId)).toBe(false);
|
|
180
|
-
|
|
181
|
-
await mockExt.stop();
|
|
182
|
-
});
|
|
183
|
-
|
|
184
|
-
test("abort: AbortSignal resolves to 'Aborted' and extension receives host_browser_cancel", async () => {
|
|
185
|
-
const guardianId = `test-guardian-${crypto.randomUUID()}`;
|
|
186
|
-
const token = mintActorToken(guardianId);
|
|
187
|
-
|
|
188
|
-
const { createMockChromeExtension } =
|
|
189
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
190
|
-
const mockExt = createMockChromeExtension({
|
|
191
|
-
runtimeBaseUrl,
|
|
192
|
-
token,
|
|
193
|
-
cdpHandler: () => new Promise(() => {}),
|
|
194
|
-
});
|
|
195
|
-
await mockExt.start();
|
|
196
|
-
await mockExt.waitForConnection();
|
|
197
|
-
await waitForRegistryEntry(guardianId);
|
|
198
|
-
|
|
199
|
-
const proxy = HostBrowserProxy.instance;
|
|
200
|
-
|
|
201
|
-
const controller = new AbortController();
|
|
202
|
-
const resultPromise = proxy.request(
|
|
203
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
204
|
-
"conv-abort",
|
|
205
|
-
controller.signal,
|
|
206
|
-
);
|
|
207
|
-
|
|
208
|
-
await waitFor(() => mockExt.receivedRequests().length === 1);
|
|
209
|
-
|
|
210
|
-
controller.abort();
|
|
211
|
-
const result = await resultPromise;
|
|
212
|
-
|
|
213
|
-
expect(result.content).toBe("Aborted");
|
|
214
|
-
expect(result.isError).toBe(true);
|
|
215
|
-
|
|
216
|
-
await waitFor(() => mockExt.receivedCancels().length === 1);
|
|
217
|
-
const cancels = mockExt.receivedCancels();
|
|
218
|
-
expect(cancels).toHaveLength(1);
|
|
219
|
-
expect(cancels[0].requestId).toBe(mockExt.receivedRequests()[0].requestId);
|
|
220
|
-
|
|
221
|
-
await mockExt.stop();
|
|
222
|
-
});
|
|
223
|
-
|
|
224
|
-
test("abort: late /v1/host-browser-result POST after cancel is ignored (no ghost completion)", async () => {
|
|
225
|
-
const guardianId = `test-guardian-${crypto.randomUUID()}`;
|
|
226
|
-
const token = mintActorToken(guardianId);
|
|
227
|
-
|
|
228
|
-
const { createMockChromeExtension } =
|
|
229
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
230
|
-
const mockExt = createMockChromeExtension({
|
|
231
|
-
runtimeBaseUrl,
|
|
232
|
-
token,
|
|
233
|
-
cdpHandler: () => new Promise(() => {}),
|
|
234
|
-
});
|
|
235
|
-
await mockExt.start();
|
|
236
|
-
await mockExt.waitForConnection();
|
|
237
|
-
await waitForRegistryEntry(guardianId);
|
|
238
|
-
|
|
239
|
-
const proxy = HostBrowserProxy.instance;
|
|
240
|
-
|
|
241
|
-
let resolveCount = 0;
|
|
242
|
-
const controller = new AbortController();
|
|
243
|
-
const resultPromise = proxy
|
|
244
|
-
.request(
|
|
245
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
246
|
-
"conv-abort-late",
|
|
247
|
-
controller.signal,
|
|
248
|
-
)
|
|
249
|
-
.then((r) => {
|
|
250
|
-
resolveCount += 1;
|
|
251
|
-
return r;
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
await waitFor(() => mockExt.receivedRequests().length === 1);
|
|
255
|
-
const pendingRequestId = mockExt.receivedRequests()[0].requestId;
|
|
256
|
-
|
|
257
|
-
controller.abort();
|
|
258
|
-
const result = await resultPromise;
|
|
259
|
-
expect(result.content).toBe("Aborted");
|
|
260
|
-
expect(result.isError).toBe(true);
|
|
261
|
-
expect(resolveCount).toBe(1);
|
|
262
|
-
|
|
263
|
-
// Manually submit a late result for the same requestId —
|
|
264
|
-
// simulating a non-compliant client that failed to honour the
|
|
265
|
-
// cancel envelope. The runtime must accept the POST without error
|
|
266
|
-
// and the proxy must NOT resolve the caller a second time.
|
|
267
|
-
const lateResp = await fetch(`${runtimeBaseUrl}/v1/host-browser-result`, {
|
|
268
|
-
method: "POST",
|
|
269
|
-
headers: {
|
|
270
|
-
"Content-Type": "application/json",
|
|
271
|
-
Authorization: `Bearer ${token}`,
|
|
272
|
-
},
|
|
273
|
-
body: JSON.stringify({
|
|
274
|
-
requestId: pendingRequestId,
|
|
275
|
-
content: JSON.stringify({ product: "Chrome/LateResult" }),
|
|
276
|
-
isError: false,
|
|
277
|
-
}),
|
|
278
|
-
});
|
|
279
|
-
await lateResp.body?.cancel();
|
|
280
|
-
|
|
281
|
-
await new Promise((r) => setTimeout(r, 20));
|
|
282
|
-
expect(resolveCount).toBe(1);
|
|
283
|
-
|
|
284
|
-
await mockExt.stop();
|
|
285
|
-
});
|
|
286
|
-
|
|
287
|
-
test("timeout: proxy.request resolves with timeout error when client never responds", async () => {
|
|
288
|
-
const guardianId = `test-guardian-${crypto.randomUUID()}`;
|
|
289
|
-
const token = mintActorToken(guardianId);
|
|
290
|
-
|
|
291
|
-
const { createMockChromeExtension } =
|
|
292
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
293
|
-
const mockExt = createMockChromeExtension({
|
|
294
|
-
runtimeBaseUrl,
|
|
295
|
-
token,
|
|
296
|
-
cdpHandler: () => new Promise(() => {}),
|
|
297
|
-
});
|
|
298
|
-
await mockExt.start();
|
|
299
|
-
await mockExt.waitForConnection();
|
|
300
|
-
await waitForRegistryEntry(guardianId);
|
|
301
|
-
|
|
302
|
-
const proxy = HostBrowserProxy.instance;
|
|
303
|
-
|
|
304
|
-
const resultPromise = proxy.request(
|
|
305
|
-
{ cdpMethod: "Browser.getVersion", timeout_seconds: 0.5 },
|
|
306
|
-
"conv-timeout",
|
|
307
|
-
);
|
|
308
|
-
|
|
309
|
-
await waitFor(() => mockExt.receivedRequests().length === 1);
|
|
310
|
-
|
|
311
|
-
const result = await resultPromise;
|
|
312
|
-
|
|
313
|
-
expect(result.isError).toBe(true);
|
|
314
|
-
expect(result.content).toContain("timed out");
|
|
315
|
-
|
|
316
|
-
expect(mockExt.receivedRequests()).toHaveLength(1);
|
|
317
|
-
expect(mockExt.receivedRequests()[0].cdpMethod).toBe("Browser.getVersion");
|
|
318
|
-
|
|
319
|
-
await mockExt.stop();
|
|
320
|
-
});
|
|
321
|
-
});
|
|
322
|
-
|
|
323
|
-
// ── macOS message ingress with connected extension ──────────────────
|
|
324
|
-
|
|
325
|
-
describe("macOS message ingress with connected extension", () => {
|
|
326
|
-
let server: RuntimeHttpServer;
|
|
327
|
-
let port: number;
|
|
328
|
-
let runtimeBaseUrl: string;
|
|
329
|
-
|
|
330
|
-
beforeEach(async () => {
|
|
331
|
-
const db = getDb();
|
|
332
|
-
db.run("DELETE FROM contact_channels");
|
|
333
|
-
db.run("DELETE FROM contacts");
|
|
334
|
-
HostBrowserProxy.reset();
|
|
335
|
-
|
|
336
|
-
port = 20000 + Math.floor(Math.random() * 200);
|
|
337
|
-
runtimeBaseUrl = `http://127.0.0.1:${port}`;
|
|
338
|
-
server = new RuntimeHttpServer({ port });
|
|
339
|
-
await server.start();
|
|
340
|
-
});
|
|
341
|
-
|
|
342
|
-
afterEach(async () => {
|
|
343
|
-
await server?.stop();
|
|
344
|
-
HostBrowserProxy.reset();
|
|
345
|
-
});
|
|
346
|
-
|
|
347
|
-
test("macOS turn routes Browser.getVersion through the registry-backed extension", async () => {
|
|
348
|
-
const guardianId = `test-guardian-macos-${crypto.randomUUID()}`;
|
|
349
|
-
const token = mintActorToken(guardianId);
|
|
350
|
-
|
|
351
|
-
const { createMockChromeExtension } =
|
|
352
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
353
|
-
const mockExt = createMockChromeExtension({
|
|
354
|
-
runtimeBaseUrl,
|
|
355
|
-
token,
|
|
356
|
-
});
|
|
357
|
-
await mockExt.start();
|
|
358
|
-
await mockExt.waitForConnection();
|
|
359
|
-
await waitForRegistryEntry(guardianId);
|
|
360
|
-
|
|
361
|
-
const proxy = HostBrowserProxy.instance;
|
|
362
|
-
|
|
363
|
-
const result = await proxy.request(
|
|
364
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
365
|
-
"conv-macos-ext",
|
|
366
|
-
);
|
|
367
|
-
|
|
368
|
-
expect(result.isError).toBe(false);
|
|
369
|
-
expect(result.content).toContain("Chrome/MockTest");
|
|
370
|
-
|
|
371
|
-
const received = mockExt.receivedRequests();
|
|
372
|
-
expect(received).toHaveLength(1);
|
|
373
|
-
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
374
|
-
expect(received[0].conversationId).toBe("conv-macos-ext");
|
|
375
|
-
|
|
376
|
-
await mockExt.stop();
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
test("macOS turn with extension disconnected mid-conversation rejects (proxy detects unavailability)", async () => {
|
|
380
|
-
const guardianId = `test-guardian-macos-disco-${crypto.randomUUID()}`;
|
|
381
|
-
const token = mintActorToken(guardianId);
|
|
382
|
-
|
|
383
|
-
const { createMockChromeExtension } =
|
|
384
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
385
|
-
const mockExt = createMockChromeExtension({
|
|
386
|
-
runtimeBaseUrl,
|
|
387
|
-
token,
|
|
388
|
-
});
|
|
389
|
-
await mockExt.start();
|
|
390
|
-
await mockExt.waitForConnection();
|
|
391
|
-
await waitForRegistryEntry(guardianId);
|
|
392
|
-
|
|
393
|
-
mockExt.forceDisconnect();
|
|
394
|
-
|
|
395
|
-
await waitFor(
|
|
396
|
-
() =>
|
|
397
|
-
assistantEventHub.getMostRecentClientByCapability("host_browser") ==
|
|
398
|
-
null,
|
|
399
|
-
);
|
|
400
|
-
|
|
401
|
-
const proxy = HostBrowserProxy.instance;
|
|
402
|
-
|
|
403
|
-
try {
|
|
404
|
-
await proxy.request(
|
|
405
|
-
{ cdpMethod: "Browser.getVersion", timeout_seconds: 0.5 },
|
|
406
|
-
"conv-macos-disco",
|
|
407
|
-
);
|
|
408
|
-
expect(true).toBe(false); // Should not reach here
|
|
409
|
-
} catch {
|
|
410
|
-
// Expected: the send failed because the extension is disconnected.
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
await mockExt.stop();
|
|
414
|
-
});
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// ── Local wait helpers ──────────────────────────────────────────────
|
|
418
|
-
|
|
419
|
-
async function waitFor(
|
|
420
|
-
predicate: () => boolean,
|
|
421
|
-
timeoutMs = 2000,
|
|
422
|
-
): Promise<void> {
|
|
423
|
-
const deadline = Date.now() + timeoutMs;
|
|
424
|
-
while (!predicate()) {
|
|
425
|
-
if (Date.now() > deadline) {
|
|
426
|
-
throw new Error(
|
|
427
|
-
`waitFor: predicate did not become true within ${timeoutMs}ms`,
|
|
428
|
-
);
|
|
429
|
-
}
|
|
430
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
431
|
-
}
|
|
432
|
-
}
|
|
433
|
-
|
|
434
|
-
async function waitForRegistryEntry(
|
|
435
|
-
_guardianId: string,
|
|
436
|
-
timeoutMs = 2000,
|
|
437
|
-
): Promise<void> {
|
|
438
|
-
await waitFor(
|
|
439
|
-
() =>
|
|
440
|
-
assistantEventHub.getMostRecentClientByCapability("host_browser") != null,
|
|
441
|
-
timeoutMs,
|
|
442
|
-
);
|
|
443
|
-
}
|
|
@@ -1,226 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* End-to-end smoke test for the self-hosted **capability-token**
|
|
3
|
-
* WebSocket round-trip over `/v1/browser-relay`.
|
|
4
|
-
*
|
|
5
|
-
* This file is the Phase 3 complement to `host-browser-e2e-cloud.test.ts`:
|
|
6
|
-
* it exercises the same mock-chrome-extension → runtime → HostBrowserProxy
|
|
7
|
-
* path, but the extension authenticates with a capability token minted
|
|
8
|
-
* by `mintHostBrowserCapability()` instead of a guardian-bound JWT.
|
|
9
|
-
*
|
|
10
|
-
* Invariants covered:
|
|
11
|
-
*
|
|
12
|
-
* 1. `/v1/browser-relay` accepts capability tokens directly.
|
|
13
|
-
* 2. The WS upgrade handler derives the registry-key guardianId from
|
|
14
|
-
* the capability claims so host_browser_request frames route
|
|
15
|
-
* back to the right connection.
|
|
16
|
-
* 3. A full `Browser.getVersion` request round-trips through the
|
|
17
|
-
* mock fixture and resolves on the proxy side.
|
|
18
|
-
*
|
|
19
|
-
* If this test fails, the self-hosted transport cutover is broken.
|
|
20
|
-
*/
|
|
21
|
-
|
|
22
|
-
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
23
|
-
|
|
24
|
-
// ── Module mocks (must be declared before the real imports below) ────
|
|
25
|
-
|
|
26
|
-
mock.module("../util/logger.js", () => ({
|
|
27
|
-
getLogger: () =>
|
|
28
|
-
new Proxy({} as Record<string, unknown>, {
|
|
29
|
-
get: () => () => {},
|
|
30
|
-
}),
|
|
31
|
-
}));
|
|
32
|
-
|
|
33
|
-
mock.module("../config/loader.js", () => ({
|
|
34
|
-
getConfig: () => ({
|
|
35
|
-
ui: {},
|
|
36
|
-
model: "test",
|
|
37
|
-
provider: "test",
|
|
38
|
-
memory: { enabled: false },
|
|
39
|
-
rateLimit: { maxRequestsPerMinute: 0 },
|
|
40
|
-
secretDetection: { enabled: false },
|
|
41
|
-
contextWindow: { maxInputTokens: 200000 },
|
|
42
|
-
services: {
|
|
43
|
-
inference: {
|
|
44
|
-
mode: "your-own",
|
|
45
|
-
provider: "anthropic",
|
|
46
|
-
model: "claude-opus-4-6",
|
|
47
|
-
},
|
|
48
|
-
"image-generation": {
|
|
49
|
-
mode: "your-own",
|
|
50
|
-
provider: "gemini",
|
|
51
|
-
model: "gemini-3.1-flash-image-preview",
|
|
52
|
-
},
|
|
53
|
-
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
54
|
-
},
|
|
55
|
-
}),
|
|
56
|
-
}));
|
|
57
|
-
|
|
58
|
-
// ── Real imports (after mocks) ──────────────────────────────────────
|
|
59
|
-
|
|
60
|
-
import { HostBrowserProxy } from "../daemon/host-browser-proxy.js";
|
|
61
|
-
import { getDb } from "../memory/db-connection.js";
|
|
62
|
-
import { initializeDb } from "../memory/db-init.js";
|
|
63
|
-
import { assistantEventHub } from "../runtime/assistant-event-hub.js";
|
|
64
|
-
import { mintToken } from "../runtime/auth/token-service.js";
|
|
65
|
-
import {
|
|
66
|
-
mintHostBrowserCapability,
|
|
67
|
-
resetCapabilityTokenSecretForTests,
|
|
68
|
-
setCapabilityTokenSecretForTests,
|
|
69
|
-
} from "../runtime/capability-tokens.js";
|
|
70
|
-
import { RuntimeHttpServer } from "../runtime/http-server.js";
|
|
71
|
-
|
|
72
|
-
initializeDb();
|
|
73
|
-
|
|
74
|
-
function mintSseToken(guardianId: string): string {
|
|
75
|
-
return mintToken({
|
|
76
|
-
aud: "vellum-daemon",
|
|
77
|
-
sub: `actor:self:${guardianId}`,
|
|
78
|
-
scope_profile: "actor_client_v1",
|
|
79
|
-
policy_epoch: 1,
|
|
80
|
-
ttlSeconds: 3600,
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
// ── Tests ───────────────────────────────────────────────────────────
|
|
85
|
-
|
|
86
|
-
describe("host_browser self-hosted capability-token e2e round-trip", () => {
|
|
87
|
-
let server: RuntimeHttpServer;
|
|
88
|
-
let port: number;
|
|
89
|
-
let runtimeBaseUrl: string;
|
|
90
|
-
|
|
91
|
-
beforeEach(async () => {
|
|
92
|
-
setCapabilityTokenSecretForTests(Buffer.alloc(32, 0xab));
|
|
93
|
-
|
|
94
|
-
const db = getDb();
|
|
95
|
-
db.run("DELETE FROM contact_channels");
|
|
96
|
-
db.run("DELETE FROM contacts");
|
|
97
|
-
HostBrowserProxy.reset();
|
|
98
|
-
|
|
99
|
-
port = 19600 + Math.floor(Math.random() * 200);
|
|
100
|
-
runtimeBaseUrl = `http://127.0.0.1:${port}`;
|
|
101
|
-
server = new RuntimeHttpServer({ port });
|
|
102
|
-
await server.start();
|
|
103
|
-
});
|
|
104
|
-
|
|
105
|
-
afterEach(async () => {
|
|
106
|
-
await server?.stop();
|
|
107
|
-
HostBrowserProxy.reset();
|
|
108
|
-
resetCapabilityTokenSecretForTests();
|
|
109
|
-
});
|
|
110
|
-
|
|
111
|
-
test("capability token round-trips Browser.getVersion over WS result transport", async () => {
|
|
112
|
-
const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
|
|
113
|
-
const { token } = mintHostBrowserCapability(guardianId);
|
|
114
|
-
|
|
115
|
-
const { createMockChromeExtension } =
|
|
116
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
117
|
-
const mockExt = createMockChromeExtension({
|
|
118
|
-
runtimeBaseUrl,
|
|
119
|
-
token,
|
|
120
|
-
sseToken: mintSseToken(guardianId),
|
|
121
|
-
resultTransport: "ws",
|
|
122
|
-
});
|
|
123
|
-
await mockExt.start();
|
|
124
|
-
await mockExt.waitForConnection();
|
|
125
|
-
await waitForRegistryEntry(guardianId);
|
|
126
|
-
|
|
127
|
-
const proxy = HostBrowserProxy.instance;
|
|
128
|
-
|
|
129
|
-
const result = await proxy.request(
|
|
130
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
131
|
-
"conv-cap-happy-ws",
|
|
132
|
-
);
|
|
133
|
-
|
|
134
|
-
expect(result.isError).toBe(false);
|
|
135
|
-
expect(result.content).toContain("Chrome/MockTest");
|
|
136
|
-
|
|
137
|
-
const received = mockExt.receivedRequests();
|
|
138
|
-
expect(received).toHaveLength(1);
|
|
139
|
-
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
140
|
-
expect(received[0].conversationId).toBe("conv-cap-happy-ws");
|
|
141
|
-
|
|
142
|
-
await mockExt.stop();
|
|
143
|
-
});
|
|
144
|
-
|
|
145
|
-
test("capability token round-trips Browser.getVersion over HTTP POST fallback", async () => {
|
|
146
|
-
const guardianId = `self-hosted-guardian-${crypto.randomUUID()}`;
|
|
147
|
-
const { token } = mintHostBrowserCapability(guardianId);
|
|
148
|
-
|
|
149
|
-
const { createMockChromeExtension } =
|
|
150
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
151
|
-
const mockExt = createMockChromeExtension({
|
|
152
|
-
runtimeBaseUrl,
|
|
153
|
-
token,
|
|
154
|
-
sseToken: mintSseToken(guardianId),
|
|
155
|
-
resultTransport: "http",
|
|
156
|
-
});
|
|
157
|
-
await mockExt.start();
|
|
158
|
-
await mockExt.waitForConnection();
|
|
159
|
-
await waitForRegistryEntry(guardianId);
|
|
160
|
-
|
|
161
|
-
const proxy = HostBrowserProxy.instance;
|
|
162
|
-
|
|
163
|
-
const result = await proxy.request(
|
|
164
|
-
{ cdpMethod: "Browser.getVersion" },
|
|
165
|
-
"conv-cap-happy-http",
|
|
166
|
-
);
|
|
167
|
-
|
|
168
|
-
expect(result.isError).toBe(false);
|
|
169
|
-
expect(result.content).toContain("Chrome/MockTest");
|
|
170
|
-
|
|
171
|
-
const received = mockExt.receivedRequests();
|
|
172
|
-
expect(received).toHaveLength(1);
|
|
173
|
-
expect(received[0].cdpMethod).toBe("Browser.getVersion");
|
|
174
|
-
expect(received[0].conversationId).toBe("conv-cap-happy-http");
|
|
175
|
-
|
|
176
|
-
await mockExt.stop();
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
test("an invalid capability token is rejected with 401", async () => {
|
|
180
|
-
const { createMockChromeExtension } =
|
|
181
|
-
await import("./fixtures/mock-chrome-extension.js");
|
|
182
|
-
const mockExt = createMockChromeExtension({
|
|
183
|
-
runtimeBaseUrl,
|
|
184
|
-
token: "totally-bogus-not-a-real-token",
|
|
185
|
-
});
|
|
186
|
-
let started = false;
|
|
187
|
-
try {
|
|
188
|
-
await mockExt.start();
|
|
189
|
-
started = true;
|
|
190
|
-
await mockExt.waitForConnection(500);
|
|
191
|
-
} catch {
|
|
192
|
-
// expected — SSE or WS auth rejects the bad token
|
|
193
|
-
}
|
|
194
|
-
// The extension must not reach a fully-connected state.
|
|
195
|
-
expect(started).toBe(false);
|
|
196
|
-
await mockExt.stop();
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
|
|
200
|
-
// ── Local wait helpers ──────────────────────────────────────────────
|
|
201
|
-
|
|
202
|
-
async function waitFor(
|
|
203
|
-
predicate: () => boolean,
|
|
204
|
-
timeoutMs = 2000,
|
|
205
|
-
): Promise<void> {
|
|
206
|
-
const deadline = Date.now() + timeoutMs;
|
|
207
|
-
while (!predicate()) {
|
|
208
|
-
if (Date.now() > deadline) {
|
|
209
|
-
throw new Error(
|
|
210
|
-
`waitFor: predicate did not become true within ${timeoutMs}ms`,
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
|
-
await new Promise((r) => setTimeout(r, 10));
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
async function waitForRegistryEntry(
|
|
218
|
-
_guardianId: string,
|
|
219
|
-
timeoutMs = 2000,
|
|
220
|
-
): Promise<void> {
|
|
221
|
-
await waitFor(
|
|
222
|
-
() =>
|
|
223
|
-
assistantEventHub.getMostRecentClientByCapability("host_browser") != null,
|
|
224
|
-
timeoutMs,
|
|
225
|
-
);
|
|
226
|
-
}
|