@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,8 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Managed CES contract and wiring tests.
|
|
3
3
|
*
|
|
4
|
-
* Validates the contract surface
|
|
5
|
-
*
|
|
4
|
+
* Validates the contract surface and behavioral invariants for the managed
|
|
5
|
+
* (three-container pod) CES sidecar integration:
|
|
6
6
|
*
|
|
7
7
|
* 1. Pod creation contract: well-known path constants match the
|
|
8
8
|
* stateful_template.yaml K8s spec (read-only mount + private PVC).
|
|
@@ -18,25 +18,11 @@
|
|
|
18
18
|
* (UpdateManagedCredential, MakeAuthenticatedRequest) validate expected
|
|
19
19
|
* payloads and reject malformed ones at the contract level.
|
|
20
20
|
*
|
|
21
|
-
* 5. Feature-flag rollback: when the `ces-managed-sidecar` flag is off,
|
|
22
|
-
* the process manager falls back to local discovery and never attempts
|
|
23
|
-
* the managed sidecar path.
|
|
24
|
-
*
|
|
25
21
|
* All tests use contract schemas and handle parsers to verify behavioral
|
|
26
22
|
* contracts — no real CES process or socket dependencies are needed.
|
|
27
23
|
*/
|
|
28
24
|
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
|
|
32
|
-
|
|
33
|
-
beforeEach(() => {
|
|
34
|
-
_setOverridesForTesting({});
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
afterEach(() => {
|
|
38
|
-
_setOverridesForTesting({});
|
|
39
|
-
});
|
|
25
|
+
import { describe, expect, test } from "bun:test";
|
|
40
26
|
|
|
41
27
|
import {
|
|
42
28
|
CES_PROTOCOL_VERSION,
|
|
@@ -53,26 +39,11 @@ import {
|
|
|
53
39
|
UpdateManagedCredentialSchema,
|
|
54
40
|
} from "@vellumai/service-contracts/credential-rpc";
|
|
55
41
|
|
|
56
|
-
import type { AssistantConfig } from "../config/schema.js";
|
|
57
|
-
import {
|
|
58
|
-
isCesManagedSidecarEnabled,
|
|
59
|
-
isCesToolsEnabled,
|
|
60
|
-
} from "../credential-execution/feature-gates.js";
|
|
61
42
|
import {
|
|
62
43
|
CES_ASSISTANT_DATA_READONLY_MOUNT,
|
|
63
44
|
CES_PRIVATE_DATA_DIR,
|
|
64
|
-
type CesProcessManagerConfig,
|
|
65
45
|
} from "../credential-execution/process-manager.js";
|
|
66
46
|
|
|
67
|
-
// ---------------------------------------------------------------------------
|
|
68
|
-
// Helpers
|
|
69
|
-
// ---------------------------------------------------------------------------
|
|
70
|
-
|
|
71
|
-
/** Create a minimal AssistantConfig (flag overrides are now set via _setOverridesForTesting). */
|
|
72
|
-
function makeConfig(): AssistantConfig {
|
|
73
|
-
return {} as AssistantConfig;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
47
|
// ---------------------------------------------------------------------------
|
|
77
48
|
// Well-known paths contract
|
|
78
49
|
// ---------------------------------------------------------------------------
|
|
@@ -440,102 +411,3 @@ describe("managed OAuth materialization through CES sidecar", () => {
|
|
|
440
411
|
}
|
|
441
412
|
});
|
|
442
413
|
});
|
|
443
|
-
|
|
444
|
-
// ---------------------------------------------------------------------------
|
|
445
|
-
// Feature-flag rollback safety
|
|
446
|
-
// ---------------------------------------------------------------------------
|
|
447
|
-
|
|
448
|
-
describe("feature-flag rollback safety", () => {
|
|
449
|
-
test("managed sidecar flag defaults to true (enabled by default)", () => {
|
|
450
|
-
const config = makeConfig();
|
|
451
|
-
expect(isCesManagedSidecarEnabled(config)).toBe(true);
|
|
452
|
-
});
|
|
453
|
-
|
|
454
|
-
test("managed sidecar flag can be explicitly enabled", () => {
|
|
455
|
-
_setOverridesForTesting({
|
|
456
|
-
"ces-managed-sidecar": true,
|
|
457
|
-
});
|
|
458
|
-
const config = makeConfig();
|
|
459
|
-
expect(isCesManagedSidecarEnabled(config)).toBe(true);
|
|
460
|
-
});
|
|
461
|
-
|
|
462
|
-
test("managed sidecar flag can be explicitly disabled", () => {
|
|
463
|
-
_setOverridesForTesting({
|
|
464
|
-
"ces-managed-sidecar": false,
|
|
465
|
-
});
|
|
466
|
-
const config = makeConfig();
|
|
467
|
-
expect(isCesManagedSidecarEnabled(config)).toBe(false);
|
|
468
|
-
});
|
|
469
|
-
|
|
470
|
-
test("enabling managed sidecar does not enable CES tools", () => {
|
|
471
|
-
_setOverridesForTesting({
|
|
472
|
-
"ces-managed-sidecar": true,
|
|
473
|
-
});
|
|
474
|
-
const config = makeConfig();
|
|
475
|
-
// CES tools flag should remain independently controlled
|
|
476
|
-
expect(isCesToolsEnabled(config)).toBe(false);
|
|
477
|
-
});
|
|
478
|
-
|
|
479
|
-
test("disabling managed sidecar does not affect other CES flags", () => {
|
|
480
|
-
_setOverridesForTesting({
|
|
481
|
-
"ces-managed-sidecar": false,
|
|
482
|
-
"ces-tools": true,
|
|
483
|
-
});
|
|
484
|
-
const config = makeConfig();
|
|
485
|
-
expect(isCesToolsEnabled(config)).toBe(true);
|
|
486
|
-
});
|
|
487
|
-
});
|
|
488
|
-
|
|
489
|
-
// ---------------------------------------------------------------------------
|
|
490
|
-
// Process manager config wiring
|
|
491
|
-
// ---------------------------------------------------------------------------
|
|
492
|
-
|
|
493
|
-
describe("process manager config wiring", () => {
|
|
494
|
-
test("CesProcessManagerConfig accepts assistantConfig for flag gating", () => {
|
|
495
|
-
_setOverridesForTesting({
|
|
496
|
-
"ces-managed-sidecar": true,
|
|
497
|
-
});
|
|
498
|
-
const config: CesProcessManagerConfig = {
|
|
499
|
-
assistantConfig: makeConfig(),
|
|
500
|
-
};
|
|
501
|
-
expect(config.assistantConfig).toBeDefined();
|
|
502
|
-
expect(isCesManagedSidecarEnabled(config.assistantConfig!)).toBe(true);
|
|
503
|
-
});
|
|
504
|
-
|
|
505
|
-
test("CesProcessManagerConfig requires assistantConfig for feature-flag gate", () => {
|
|
506
|
-
const config: CesProcessManagerConfig = {
|
|
507
|
-
assistantConfig: makeConfig(),
|
|
508
|
-
};
|
|
509
|
-
expect(config.assistantConfig).toBeDefined();
|
|
510
|
-
});
|
|
511
|
-
|
|
512
|
-
test("when flag is off, managed discovery is skipped", () => {
|
|
513
|
-
_setOverridesForTesting({
|
|
514
|
-
"ces-managed-sidecar": false,
|
|
515
|
-
});
|
|
516
|
-
const config: CesProcessManagerConfig = {
|
|
517
|
-
assistantConfig: makeConfig(),
|
|
518
|
-
};
|
|
519
|
-
// The managed path should be gated
|
|
520
|
-
expect(isCesManagedSidecarEnabled(config.assistantConfig!)).toBe(false);
|
|
521
|
-
});
|
|
522
|
-
});
|
|
523
|
-
|
|
524
|
-
// ---------------------------------------------------------------------------
|
|
525
|
-
// Non-CES internal consumers intact
|
|
526
|
-
// ---------------------------------------------------------------------------
|
|
527
|
-
|
|
528
|
-
describe("non-CES internal consumers intact when flag is off", () => {
|
|
529
|
-
test("existing non-agent flows are unaffected by managed sidecar flag", () => {
|
|
530
|
-
_setOverridesForTesting({
|
|
531
|
-
"ces-managed-sidecar": false,
|
|
532
|
-
});
|
|
533
|
-
const config = makeConfig();
|
|
534
|
-
expect(isCesManagedSidecarEnabled(config)).toBe(false);
|
|
535
|
-
});
|
|
536
|
-
|
|
537
|
-
test("process manager without config allows managed mode (backward compat)", () => {
|
|
538
|
-
const config: CesProcessManagerConfig = {};
|
|
539
|
-
expect(config.assistantConfig).toBeUndefined();
|
|
540
|
-
});
|
|
541
|
-
});
|
|
@@ -57,24 +57,17 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
57
57
|
}));
|
|
58
58
|
|
|
59
59
|
mock.module("../cli/lib/daemon-credential-client.js", () => ({
|
|
60
|
-
setSecureKeyViaDaemon: async (
|
|
61
|
-
type: string,
|
|
62
|
-
name: string,
|
|
63
|
-
value: string,
|
|
64
|
-
): Promise<boolean> => {
|
|
60
|
+
setSecureKeyViaDaemon: async (type: string, name: string, value: string) => {
|
|
65
61
|
secureKeyStore.set(normalizeCredentialAccount(type, name), value);
|
|
66
|
-
return true;
|
|
62
|
+
return { ok: true };
|
|
67
63
|
},
|
|
68
|
-
deleteSecureKeyViaDaemon: async (
|
|
69
|
-
type: string,
|
|
70
|
-
name: string,
|
|
71
|
-
): Promise<"deleted" | "not-found" | "error"> => {
|
|
64
|
+
deleteSecureKeyViaDaemon: async (type: string, name: string) => {
|
|
72
65
|
const key = normalizeCredentialAccount(type, name);
|
|
73
66
|
if (secureKeyStore.has(key)) {
|
|
74
67
|
secureKeyStore.delete(key);
|
|
75
|
-
return "deleted";
|
|
68
|
+
return { result: "deleted" as const };
|
|
76
69
|
}
|
|
77
|
-
return "not-found";
|
|
70
|
+
return { result: "not-found" as const };
|
|
78
71
|
},
|
|
79
72
|
}));
|
|
80
73
|
|
|
@@ -9,28 +9,27 @@ import { afterEach, describe, expect, mock, test } from "bun:test";
|
|
|
9
9
|
|
|
10
10
|
const sentMessages: unknown[] = [];
|
|
11
11
|
let mockHasClient = true; // Default to true for CU unified flow tests
|
|
12
|
+
let mockCuClients: Array<{ clientId: string; capabilities: string[] }> = [
|
|
13
|
+
{ clientId: "mock-client-1", capabilities: ["host_cu"] },
|
|
14
|
+
];
|
|
12
15
|
|
|
13
16
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
14
17
|
broadcastMessage: (msg: unknown) => sentMessages.push(msg),
|
|
15
18
|
assistantEventHub: {
|
|
16
19
|
getMostRecentClientByCapability: (cap: string) =>
|
|
17
20
|
cap === "host_cu" && mockHasClient ? { id: "mock-client" } : null,
|
|
21
|
+
listClientsByCapability: (cap: string) =>
|
|
22
|
+
cap === "host_cu" ? mockCuClients : [],
|
|
23
|
+
getClientById: (id: string) =>
|
|
24
|
+
mockCuClients.find((c) => c.clientId === id) ?? null,
|
|
18
25
|
},
|
|
19
26
|
}));
|
|
20
27
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
get: () => undefined,
|
|
24
|
-
getByKind: () => [],
|
|
25
|
-
getByConversation: () => [],
|
|
26
|
-
removeByConversation: () => {},
|
|
27
|
-
}));
|
|
28
|
-
|
|
29
|
-
const { surfaceProxyResolver } = await import(
|
|
30
|
-
"../daemon/conversation-surfaces.js"
|
|
31
|
-
);
|
|
28
|
+
const { surfaceProxyResolver } =
|
|
29
|
+
await import("../daemon/conversation-surfaces.js");
|
|
32
30
|
const { HostCuProxy } = await import("../daemon/host-cu-proxy.js");
|
|
33
|
-
type SurfaceConversationContext =
|
|
31
|
+
type SurfaceConversationContext =
|
|
32
|
+
import("../daemon/conversation-surfaces.js").SurfaceConversationContext;
|
|
34
33
|
|
|
35
34
|
// ---------------------------------------------------------------------------
|
|
36
35
|
// Test helpers
|
|
@@ -73,6 +72,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
73
72
|
function setupProxy(maxSteps?: number): SurfaceConversationContext {
|
|
74
73
|
sentMessages.length = 0;
|
|
75
74
|
mockHasClient = true;
|
|
75
|
+
mockCuClients = [{ clientId: "mock-client-1", capabilities: ["host_cu"] }];
|
|
76
76
|
proxy = new HostCuProxy(maxSteps);
|
|
77
77
|
return buildMockContext(proxy);
|
|
78
78
|
}
|
|
@@ -239,7 +239,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
239
239
|
|
|
240
240
|
// Simulate client resolving with observation
|
|
241
241
|
const requestId = sent.requestId as string;
|
|
242
|
-
proxy.
|
|
242
|
+
proxy.processObservation(requestId, {
|
|
243
243
|
axTree: "SubmitButton [1]\nTextField [2]",
|
|
244
244
|
executionResult: "Clicked element 42",
|
|
245
245
|
});
|
|
@@ -265,7 +265,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
265
265
|
expect(sent.type).toBe("host_cu_request");
|
|
266
266
|
expect(sent.toolName).toBe("computer_use_screenshot");
|
|
267
267
|
|
|
268
|
-
proxy.
|
|
268
|
+
proxy.processObservation(sent.requestId as string, {
|
|
269
269
|
axTree: "Window [1]",
|
|
270
270
|
screenshot: "base64screenshot",
|
|
271
271
|
screenshotWidthPx: 1920,
|
|
@@ -302,7 +302,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
302
302
|
reasoning: "Type into search box",
|
|
303
303
|
});
|
|
304
304
|
|
|
305
|
-
proxy.
|
|
305
|
+
proxy.processObservation(sent.requestId as string, {
|
|
306
306
|
axTree: "SearchBox [1] value='Hello world'",
|
|
307
307
|
executionResult: "Typed text",
|
|
308
308
|
});
|
|
@@ -326,7 +326,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
326
326
|
reasoning: "Check what's on screen",
|
|
327
327
|
});
|
|
328
328
|
const sent1 = sentMessages[0] as Record<string, unknown>;
|
|
329
|
-
proxy.
|
|
329
|
+
proxy.processObservation(sent1.requestId as string, {
|
|
330
330
|
axTree: "LoginButton [1]\nUsernameField [2]",
|
|
331
331
|
});
|
|
332
332
|
const r1 = await p1;
|
|
@@ -340,7 +340,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
340
340
|
reasoning: "Click login button",
|
|
341
341
|
});
|
|
342
342
|
const sent2 = sentMessages[1] as Record<string, unknown>;
|
|
343
|
-
proxy.
|
|
343
|
+
proxy.processObservation(sent2.requestId as string, {
|
|
344
344
|
axTree: "PasswordField [1]\nSubmitButton [2]",
|
|
345
345
|
axDiff: "+ PasswordField [1]\n+ SubmitButton [2]\n- LoginButton [1]",
|
|
346
346
|
executionResult: "Clicked element 1",
|
|
@@ -370,6 +370,168 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
370
370
|
// Step limit enforced through resolver
|
|
371
371
|
// -------------------------------------------------------------------------
|
|
372
372
|
|
|
373
|
+
// -------------------------------------------------------------------------
|
|
374
|
+
// Multi-client ambiguity guard
|
|
375
|
+
// -------------------------------------------------------------------------
|
|
376
|
+
|
|
377
|
+
describe("multi-client ambiguity guard", () => {
|
|
378
|
+
test("returns error when multiple CU clients connected and no target_client_id given", async () => {
|
|
379
|
+
const ctx = setupProxy();
|
|
380
|
+
mockCuClients = [
|
|
381
|
+
{ clientId: "client-a", capabilities: ["host_cu"] },
|
|
382
|
+
{ clientId: "client-b", capabilities: ["host_cu"] },
|
|
383
|
+
];
|
|
384
|
+
|
|
385
|
+
const result = await surfaceProxyResolver(ctx, "computer_use_click", {
|
|
386
|
+
element_id: 1,
|
|
387
|
+
reasoning: "click",
|
|
388
|
+
});
|
|
389
|
+
|
|
390
|
+
expect(result.isError).toBe(true);
|
|
391
|
+
expect(result.content).toContain("multiple clients support host_cu");
|
|
392
|
+
expect(result.content).toContain("target_client_id");
|
|
393
|
+
// No message should have been dispatched
|
|
394
|
+
expect(sentMessages).toHaveLength(0);
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
test("proceeds when multiple clients connected and target_client_id is given", async () => {
|
|
398
|
+
const ctx = setupProxy();
|
|
399
|
+
mockCuClients = [
|
|
400
|
+
{ clientId: "client-a", capabilities: ["host_cu"] },
|
|
401
|
+
{ clientId: "client-b", capabilities: ["host_cu"] },
|
|
402
|
+
];
|
|
403
|
+
|
|
404
|
+
const resultPromise = surfaceProxyResolver(ctx, "computer_use_click", {
|
|
405
|
+
element_id: 1,
|
|
406
|
+
reasoning: "click",
|
|
407
|
+
target_client_id: "client-a",
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
// Should have dispatched the request
|
|
411
|
+
expect(sentMessages).toHaveLength(1);
|
|
412
|
+
const sent = sentMessages[0] as Record<string, unknown>;
|
|
413
|
+
expect(sent.type).toBe("host_cu_request");
|
|
414
|
+
expect(sent.targetClientId).toBe("client-a");
|
|
415
|
+
|
|
416
|
+
proxy.processObservation(sent.requestId as string, { axTree: "ok" });
|
|
417
|
+
const result = await resultPromise;
|
|
418
|
+
expect(result.isError).toBe(false);
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
test("proceeds normally when exactly one CU client is connected", async () => {
|
|
422
|
+
const ctx = setupProxy();
|
|
423
|
+
// mockCuClients already has 1 entry from setupProxy
|
|
424
|
+
|
|
425
|
+
const resultPromise = surfaceProxyResolver(ctx, "computer_use_click", {
|
|
426
|
+
element_id: 2,
|
|
427
|
+
reasoning: "safe click",
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
expect(sentMessages).toHaveLength(1);
|
|
431
|
+
const sent = sentMessages[0] as Record<string, unknown>;
|
|
432
|
+
expect(sent.type).toBe("host_cu_request");
|
|
433
|
+
|
|
434
|
+
proxy.processObservation(sent.requestId as string, { axTree: "ok" });
|
|
435
|
+
const result = await resultPromise;
|
|
436
|
+
expect(result.isError).toBe(false);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
test("multi-client guard does not apply to terminal tools (computer_use_done)", async () => {
|
|
440
|
+
const ctx = setupProxy();
|
|
441
|
+
mockCuClients = [
|
|
442
|
+
{ clientId: "client-a", capabilities: ["host_cu"] },
|
|
443
|
+
{ clientId: "client-b", capabilities: ["host_cu"] },
|
|
444
|
+
];
|
|
445
|
+
|
|
446
|
+
// Terminal tools short-circuit before the ambiguity check
|
|
447
|
+
const result = await surfaceProxyResolver(ctx, "computer_use_done", {
|
|
448
|
+
summary: "all done",
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
expect(result.isError).toBe(false);
|
|
452
|
+
expect(result.content).toBe("all done");
|
|
453
|
+
expect(sentMessages).toHaveLength(0);
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
|
|
457
|
+
// -------------------------------------------------------------------------
|
|
458
|
+
// targetClientId validation (lives at resolver layer so step count and
|
|
459
|
+
// action history are not mutated when validation rejects the request).
|
|
460
|
+
// -------------------------------------------------------------------------
|
|
461
|
+
|
|
462
|
+
describe("targetClientId validation", () => {
|
|
463
|
+
test("returns fast error when targetClientId does not match any connected client", async () => {
|
|
464
|
+
const ctx = setupProxy();
|
|
465
|
+
mockCuClients = [{ clientId: "real-client", capabilities: ["host_cu"] }];
|
|
466
|
+
const stepCountBefore = proxy.stepCount;
|
|
467
|
+
|
|
468
|
+
const result = await surfaceProxyResolver(ctx, "computer_use_click", {
|
|
469
|
+
element_id: 1,
|
|
470
|
+
reasoning: "click",
|
|
471
|
+
target_client_id: "nonexistent-client",
|
|
472
|
+
});
|
|
473
|
+
|
|
474
|
+
expect(result.isError).toBe(true);
|
|
475
|
+
expect(result.content).toContain("nonexistent-client");
|
|
476
|
+
expect(result.content).toContain("host_cu");
|
|
477
|
+
// Critical: validation must run BEFORE recordAction. stepCount and
|
|
478
|
+
// actionHistory must be unchanged when rejection fires — otherwise
|
|
479
|
+
// every invalid target_client_id burns a step and leaves a ghost
|
|
480
|
+
// entry the LLM can reason about.
|
|
481
|
+
expect(proxy.stepCount).toBe(stepCountBefore);
|
|
482
|
+
expect(proxy.actionHistory).toHaveLength(0);
|
|
483
|
+
expect(sentMessages).toHaveLength(0);
|
|
484
|
+
});
|
|
485
|
+
|
|
486
|
+
test("returns fast error when targetClientId points to a client without host_cu capability", async () => {
|
|
487
|
+
const ctx = setupProxy();
|
|
488
|
+
mockCuClients = [
|
|
489
|
+
{ clientId: "no-cu-client", capabilities: ["host_bash"] }, // bash, not cu
|
|
490
|
+
];
|
|
491
|
+
const stepCountBefore = proxy.stepCount;
|
|
492
|
+
|
|
493
|
+
const result = await surfaceProxyResolver(ctx, "computer_use_click", {
|
|
494
|
+
element_id: 1,
|
|
495
|
+
reasoning: "click",
|
|
496
|
+
target_client_id: "no-cu-client",
|
|
497
|
+
});
|
|
498
|
+
|
|
499
|
+
expect(result.isError).toBe(true);
|
|
500
|
+
expect(result.content).toContain("no-cu-client");
|
|
501
|
+
expect(result.content).toContain("host_cu");
|
|
502
|
+
// No step burned, no ghost in history.
|
|
503
|
+
expect(proxy.stepCount).toBe(stepCountBefore);
|
|
504
|
+
expect(proxy.actionHistory).toHaveLength(0);
|
|
505
|
+
expect(sentMessages).toHaveLength(0);
|
|
506
|
+
});
|
|
507
|
+
|
|
508
|
+
test("dispatches and records action when targetClientId is valid", async () => {
|
|
509
|
+
const ctx = setupProxy();
|
|
510
|
+
mockCuClients = [
|
|
511
|
+
{ clientId: "cu-client", capabilities: ["host_cu"] },
|
|
512
|
+
{ clientId: "client-b", capabilities: ["host_cu"] }, // would otherwise trip ambiguity guard
|
|
513
|
+
];
|
|
514
|
+
|
|
515
|
+
const resultPromise = surfaceProxyResolver(ctx, "computer_use_click", {
|
|
516
|
+
element_id: 5,
|
|
517
|
+
reasoning: "click",
|
|
518
|
+
target_client_id: "cu-client",
|
|
519
|
+
});
|
|
520
|
+
|
|
521
|
+
expect(sentMessages).toHaveLength(1);
|
|
522
|
+
const sent = sentMessages[0] as Record<string, unknown>;
|
|
523
|
+
expect(sent.type).toBe("host_cu_request");
|
|
524
|
+
expect(sent.targetClientId).toBe("cu-client");
|
|
525
|
+
// recordAction did fire on the success path.
|
|
526
|
+
expect(proxy.stepCount).toBe(1);
|
|
527
|
+
expect(proxy.actionHistory).toHaveLength(1);
|
|
528
|
+
|
|
529
|
+
proxy.processObservation(sent.requestId as string, { axTree: "ok" });
|
|
530
|
+
const result = await resultPromise;
|
|
531
|
+
expect(result.isError).toBe(false);
|
|
532
|
+
});
|
|
533
|
+
});
|
|
534
|
+
|
|
373
535
|
describe("step limit enforcement through resolver", () => {
|
|
374
536
|
test("rejects action tools when step limit exceeded", async () => {
|
|
375
537
|
const ctx = setupProxy(2); // maxSteps = 2
|
|
@@ -423,7 +585,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
423
585
|
});
|
|
424
586
|
|
|
425
587
|
const sent = sentMessages[0] as Record<string, unknown>;
|
|
426
|
-
proxy.
|
|
588
|
+
proxy.processObservation(sent.requestId as string, {
|
|
427
589
|
executionError: "Element 999 not found in AX tree",
|
|
428
590
|
axTree: "Window [1]",
|
|
429
591
|
});
|
|
@@ -452,7 +614,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
452
614
|
expect(sent.reasoning).toBe("Submit the form");
|
|
453
615
|
|
|
454
616
|
// Resolve to avoid unhandled rejection on dispose
|
|
455
|
-
proxy.
|
|
617
|
+
proxy.processObservation(sent.requestId as string, { axTree: "..." });
|
|
456
618
|
await resultPromise;
|
|
457
619
|
});
|
|
458
620
|
|
|
@@ -469,7 +631,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
469
631
|
|
|
470
632
|
// Resolve to avoid hanging
|
|
471
633
|
const sent = sentMessages[0] as Record<string, unknown>;
|
|
472
|
-
proxy.
|
|
634
|
+
proxy.processObservation(sent.requestId as string, { axTree: "..." });
|
|
473
635
|
});
|
|
474
636
|
});
|
|
475
637
|
|
|
@@ -515,7 +677,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
515
677
|
reasoning: "first",
|
|
516
678
|
});
|
|
517
679
|
const s1 = sentMessages[0] as Record<string, unknown>;
|
|
518
|
-
proxy.
|
|
680
|
+
proxy.processObservation(s1.requestId as string, { axTree: "A" });
|
|
519
681
|
await p1;
|
|
520
682
|
expect(proxy.stepCount).toBe(1);
|
|
521
683
|
|
|
@@ -525,7 +687,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
525
687
|
reasoning: "second",
|
|
526
688
|
});
|
|
527
689
|
const s2 = sentMessages[1] as Record<string, unknown>;
|
|
528
|
-
proxy.
|
|
690
|
+
proxy.processObservation(s2.requestId as string, { axTree: "B" });
|
|
529
691
|
await p2;
|
|
530
692
|
expect(proxy.stepCount).toBe(2);
|
|
531
693
|
|
|
@@ -536,7 +698,7 @@ describe("surfaceProxyResolver — CU tool routing", () => {
|
|
|
536
698
|
reasoning: "third",
|
|
537
699
|
});
|
|
538
700
|
const s3 = sentMessages[2] as Record<string, unknown>;
|
|
539
|
-
proxy.
|
|
701
|
+
proxy.processObservation(s3.requestId as string, { axTree: "C" });
|
|
540
702
|
await p3;
|
|
541
703
|
expect(proxy.stepCount).toBe(3);
|
|
542
704
|
|
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import { describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* Mock
|
|
4
|
+
* Mock the IPC client and logger. The IPC mock returns configurable
|
|
5
|
+
* responses so we can test success, failure, and unreachable paths.
|
|
6
|
+
*
|
|
5
7
|
* Do NOT mock secure-keys.js — daemon-credential-client falls back to it
|
|
6
8
|
* for writes/deletes when the daemon is unreachable.
|
|
7
9
|
*/
|
|
8
10
|
|
|
11
|
+
let _ipcResponse: { ok: boolean; result?: unknown; error?: string } = {
|
|
12
|
+
ok: false,
|
|
13
|
+
error: "Could not connect to assistant daemon. Is it running?",
|
|
14
|
+
};
|
|
15
|
+
|
|
9
16
|
mock.module("../ipc/cli-client.js", () => ({
|
|
10
|
-
cliIpcCall: async () =>
|
|
11
|
-
ok: false,
|
|
12
|
-
error: "Could not connect to assistant daemon. Is it running?",
|
|
13
|
-
}),
|
|
17
|
+
cliIpcCall: async () => _ipcResponse,
|
|
14
18
|
}));
|
|
15
19
|
|
|
16
20
|
mock.module("../util/logger.js", () => ({
|
|
@@ -20,22 +24,100 @@ mock.module("../util/logger.js", () => ({
|
|
|
20
24
|
}),
|
|
21
25
|
}));
|
|
22
26
|
|
|
23
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
deleteSecureKeyViaDaemon,
|
|
29
|
+
setSecureKeyViaDaemon,
|
|
30
|
+
} from "../cli/lib/daemon-credential-client.js";
|
|
24
31
|
import { credentialKey } from "../security/credential-key.js";
|
|
25
32
|
import { getSecureKeyAsync } from "../security/secure-keys.js";
|
|
26
33
|
|
|
27
|
-
describe("daemon credential
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
describe("daemon credential client", () => {
|
|
35
|
+
describe("set — daemon unreachable", () => {
|
|
36
|
+
test("falls back to direct write when daemon is not running", async () => {
|
|
37
|
+
_ipcResponse = {
|
|
38
|
+
ok: false,
|
|
39
|
+
error: "Could not connect to assistant daemon. Is it running?",
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
const result = await setSecureKeyViaDaemon(
|
|
43
|
+
"api_key",
|
|
44
|
+
"test-provider",
|
|
45
|
+
"test-value",
|
|
46
|
+
);
|
|
47
|
+
expect(result.ok).toBe(true);
|
|
48
|
+
|
|
49
|
+
const readBack = await getSecureKeyAsync(
|
|
50
|
+
credentialKey("test-provider", "api_key"),
|
|
51
|
+
);
|
|
52
|
+
expect(readBack).toBe("test-value");
|
|
53
|
+
});
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
describe("set — daemon error", () => {
|
|
57
|
+
test("surfaces daemon error message on IPC failure", async () => {
|
|
58
|
+
_ipcResponse = {
|
|
59
|
+
ok: false,
|
|
60
|
+
error:
|
|
61
|
+
"Failed to store credential in secure storage (backend: ces-rpc)",
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
const result = await setSecureKeyViaDaemon(
|
|
65
|
+
"credential",
|
|
66
|
+
"vellum:webhook_secret",
|
|
67
|
+
"some-value",
|
|
68
|
+
);
|
|
69
|
+
expect(result.ok).toBe(false);
|
|
70
|
+
expect(result.error).toBe(
|
|
71
|
+
"Failed to store credential in secure storage (backend: ces-rpc)",
|
|
72
|
+
);
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("surfaces validation error from daemon result", async () => {
|
|
76
|
+
_ipcResponse = {
|
|
77
|
+
ok: true,
|
|
78
|
+
result: {
|
|
79
|
+
success: false,
|
|
80
|
+
error: "API key validation failed: invalid format",
|
|
81
|
+
},
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const result = await setSecureKeyViaDaemon(
|
|
85
|
+
"api_key",
|
|
86
|
+
"anthropic",
|
|
87
|
+
"bad-key",
|
|
88
|
+
);
|
|
89
|
+
expect(result.ok).toBe(false);
|
|
90
|
+
expect(result.error).toBe("API key validation failed: invalid format");
|
|
91
|
+
});
|
|
92
|
+
});
|
|
93
|
+
|
|
94
|
+
describe("delete — daemon error", () => {
|
|
95
|
+
test("surfaces daemon error message", async () => {
|
|
96
|
+
_ipcResponse = {
|
|
97
|
+
ok: false,
|
|
98
|
+
error: "Credential store is unreachable",
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
const result = await deleteSecureKeyViaDaemon(
|
|
102
|
+
"credential",
|
|
103
|
+
"vellum:temp_cred",
|
|
104
|
+
);
|
|
105
|
+
expect(result.result).toBe("error");
|
|
106
|
+
expect(result.error).toBe("Credential store is unreachable");
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
test("returns not-found for 404 errors", async () => {
|
|
110
|
+
_ipcResponse = {
|
|
111
|
+
ok: false,
|
|
112
|
+
error: "Credential not found (404)",
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
const result = await deleteSecureKeyViaDaemon(
|
|
116
|
+
"credential",
|
|
117
|
+
"vellum:missing",
|
|
118
|
+
);
|
|
119
|
+
expect(result.result).toBe("not-found");
|
|
120
|
+
expect(result.error).toBeUndefined();
|
|
121
|
+
});
|
|
40
122
|
});
|
|
41
123
|
});
|
|
@@ -36,6 +36,8 @@ describe("schedule_syntax column migration", () => {
|
|
|
36
36
|
last_run_at INTEGER,
|
|
37
37
|
last_status TEXT,
|
|
38
38
|
retry_count INTEGER NOT NULL DEFAULT 0,
|
|
39
|
+
max_retries INTEGER NOT NULL DEFAULT 3,
|
|
40
|
+
retry_backoff_ms INTEGER NOT NULL DEFAULT 60000,
|
|
39
41
|
created_by TEXT NOT NULL,
|
|
40
42
|
mode TEXT NOT NULL DEFAULT 'execute',
|
|
41
43
|
routing_intent TEXT NOT NULL DEFAULT 'all_channels',
|