@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
|
@@ -11,7 +11,8 @@ import {
|
|
|
11
11
|
publishCdpEvent,
|
|
12
12
|
} from "../../browser-session/events.js";
|
|
13
13
|
import { HostBrowserProxy } from "../../daemon/host-browser-proxy.js";
|
|
14
|
-
import
|
|
14
|
+
import * as pendingInteractions from "../pending-interactions.js";
|
|
15
|
+
import { BadRequestError, ConflictError, NotFoundError } from "./errors.js";
|
|
15
16
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
16
17
|
|
|
17
18
|
/**
|
|
@@ -29,21 +30,26 @@ export type HostBrowserResultResolution =
|
|
|
29
30
|
| { ok: true }
|
|
30
31
|
| {
|
|
31
32
|
ok: false;
|
|
32
|
-
code: "BAD_REQUEST" | "NOT_FOUND";
|
|
33
|
-
status: 400 | 404;
|
|
33
|
+
code: "BAD_REQUEST" | "NOT_FOUND" | "CONFLICT";
|
|
34
|
+
status: 400 | 404 | 409;
|
|
34
35
|
message: string;
|
|
35
36
|
};
|
|
36
37
|
|
|
37
38
|
/**
|
|
38
|
-
*
|
|
39
|
-
*
|
|
40
|
-
*
|
|
41
|
-
*
|
|
39
|
+
* Resolver for the `POST /v1/host-browser-result` HTTP route. Looks up
|
|
40
|
+
* the pending interaction by requestId, validates its kind is
|
|
41
|
+
* `host_browser`, and forwards the response to the owning conversation.
|
|
42
|
+
*
|
|
43
|
+
* NOTE: The WebSocket `host_browser_result` frame path does NOT go
|
|
44
|
+
* through this function — it is handled by `HostBrowserProxy.resolveResult`
|
|
45
|
+
* directly, which only consults `pendingInteractions` and does not
|
|
46
|
+
* currently perform a kind check. That asymmetry is pre-existing; if
|
|
47
|
+
* the WS path is ever opened to less-trusted clients, it should adopt
|
|
48
|
+
* the same kind-check guard added here.
|
|
42
49
|
*
|
|
43
50
|
* This function does NOT perform auth — callers are expected to have
|
|
44
51
|
* already authenticated the caller (the HTTP route uses
|
|
45
|
-
* `requireBoundGuardian
|
|
46
|
-
* at WebSocket upgrade time).
|
|
52
|
+
* `requireBoundGuardian`).
|
|
47
53
|
*/
|
|
48
54
|
export function resolveHostBrowserResultByRequestId(frame: {
|
|
49
55
|
requestId?: unknown;
|
|
@@ -61,20 +67,30 @@ export function resolveHostBrowserResultByRequestId(frame: {
|
|
|
61
67
|
};
|
|
62
68
|
}
|
|
63
69
|
|
|
64
|
-
const
|
|
65
|
-
if (!
|
|
70
|
+
const peeked = pendingInteractions.get(requestId);
|
|
71
|
+
if (!peeked) {
|
|
66
72
|
return {
|
|
67
73
|
ok: false,
|
|
68
74
|
code: "NOT_FOUND",
|
|
69
75
|
status: 404,
|
|
70
|
-
message: "No pending
|
|
76
|
+
message: "No pending browser request for this requestId",
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (peeked.kind !== "host_browser") {
|
|
81
|
+
return {
|
|
82
|
+
ok: false,
|
|
83
|
+
code: "CONFLICT",
|
|
84
|
+
status: 409,
|
|
85
|
+
message: `Pending interaction is of kind "${peeked.kind}", expected "host_browser"`,
|
|
71
86
|
};
|
|
72
87
|
}
|
|
73
88
|
|
|
74
89
|
const normalizedContent = typeof content === "string" ? content : "";
|
|
75
90
|
const normalizedIsError = typeof isError === "boolean" ? isError : false;
|
|
76
91
|
|
|
77
|
-
proxy.
|
|
92
|
+
const proxy = HostBrowserProxy.instance;
|
|
93
|
+
proxy.resolveResult(requestId, {
|
|
78
94
|
content: normalizedContent,
|
|
79
95
|
isError: normalizedIsError,
|
|
80
96
|
});
|
|
@@ -181,6 +197,42 @@ function handleHostBrowserResult({ body }: RouteHandlerArgs) {
|
|
|
181
197
|
if (!resolution.ok) {
|
|
182
198
|
if (resolution.code === "NOT_FOUND")
|
|
183
199
|
throw new NotFoundError(resolution.message);
|
|
200
|
+
if (resolution.code === "CONFLICT")
|
|
201
|
+
throw new ConflictError(resolution.message);
|
|
202
|
+
throw new BadRequestError(resolution.message);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
return { accepted: true };
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
// ---------------------------------------------------------------------------
|
|
209
|
+
// POST /v1/host-browser-event
|
|
210
|
+
// ---------------------------------------------------------------------------
|
|
211
|
+
|
|
212
|
+
function handleHostBrowserEvent({ body }: RouteHandlerArgs) {
|
|
213
|
+
if (!body || typeof body !== "object") {
|
|
214
|
+
throw new BadRequestError("Request body is required");
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
const resolution = resolveHostBrowserEvent(body);
|
|
218
|
+
if (!resolution.ok) {
|
|
219
|
+
throw new BadRequestError(resolution.message);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
return { accepted: true };
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
// ---------------------------------------------------------------------------
|
|
226
|
+
// POST /v1/host-browser-session-invalidated
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
|
|
229
|
+
function handleHostBrowserSessionInvalidated({ body }: RouteHandlerArgs) {
|
|
230
|
+
if (!body || typeof body !== "object") {
|
|
231
|
+
throw new BadRequestError("Request body is required");
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
const resolution = resolveHostBrowserSessionInvalidated(body);
|
|
235
|
+
if (!resolution.ok) {
|
|
184
236
|
throw new BadRequestError(resolution.message);
|
|
185
237
|
}
|
|
186
238
|
|
|
@@ -210,4 +262,47 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
210
262
|
}),
|
|
211
263
|
handler: handleHostBrowserResult,
|
|
212
264
|
},
|
|
265
|
+
{
|
|
266
|
+
operationId: "host_browser_event",
|
|
267
|
+
endpoint: "host-browser-event",
|
|
268
|
+
method: "POST",
|
|
269
|
+
requireGuardian: true,
|
|
270
|
+
summary: "Forward a CDP event from the browser extension",
|
|
271
|
+
description:
|
|
272
|
+
"Publishes a chrome.debugger.onEvent firing into the runtime-side browser-session event bus.",
|
|
273
|
+
tags: ["host"],
|
|
274
|
+
requestBody: z.object({
|
|
275
|
+
method: z.string().describe("CDP event method name"),
|
|
276
|
+
params: z.unknown().optional().describe("CDP event parameters"),
|
|
277
|
+
cdpSessionId: z
|
|
278
|
+
.string()
|
|
279
|
+
.optional()
|
|
280
|
+
.describe("CDP session ID (if target-scoped)"),
|
|
281
|
+
}),
|
|
282
|
+
responseBody: z.object({
|
|
283
|
+
accepted: z.boolean(),
|
|
284
|
+
}),
|
|
285
|
+
handler: handleHostBrowserEvent,
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
operationId: "host_browser_session_invalidated",
|
|
289
|
+
endpoint: "host-browser-session-invalidated",
|
|
290
|
+
method: "POST",
|
|
291
|
+
requireGuardian: true,
|
|
292
|
+
summary: "Notify runtime that a CDP session was invalidated",
|
|
293
|
+
description:
|
|
294
|
+
"Marks the target as invalidated in the runtime-side browser session registry.",
|
|
295
|
+
tags: ["host"],
|
|
296
|
+
requestBody: z.object({
|
|
297
|
+
targetId: z
|
|
298
|
+
.string()
|
|
299
|
+
.optional()
|
|
300
|
+
.describe("CDP target that was detached"),
|
|
301
|
+
reason: z.string().optional().describe("Detach reason"),
|
|
302
|
+
}),
|
|
303
|
+
responseBody: z.object({
|
|
304
|
+
accepted: z.boolean(),
|
|
305
|
+
}),
|
|
306
|
+
handler: handleHostBrowserSessionInvalidated,
|
|
307
|
+
},
|
|
213
308
|
];
|
|
@@ -8,18 +8,14 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import { findConversation } from "../../daemon/conversation-store.js";
|
|
10
10
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
11
|
-
import {
|
|
12
|
-
BadRequestError,
|
|
13
|
-
ConflictError,
|
|
14
|
-
NotFoundError,
|
|
15
|
-
} from "./errors.js";
|
|
11
|
+
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from "./errors.js";
|
|
16
12
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
17
13
|
|
|
18
14
|
// ---------------------------------------------------------------------------
|
|
19
15
|
// POST /v1/host-cu-result
|
|
20
16
|
// ---------------------------------------------------------------------------
|
|
21
17
|
|
|
22
|
-
function handleHostCuResult({ body }: RouteHandlerArgs) {
|
|
18
|
+
function handleHostCuResult({ body, headers }: RouteHandlerArgs) {
|
|
23
19
|
if (!body || typeof body !== "object") {
|
|
24
20
|
throw new BadRequestError("Request body is required");
|
|
25
21
|
}
|
|
@@ -58,9 +54,7 @@ function handleHostCuResult({ body }: RouteHandlerArgs) {
|
|
|
58
54
|
|
|
59
55
|
const peeked = pendingInteractions.get(requestId);
|
|
60
56
|
if (!peeked) {
|
|
61
|
-
throw new NotFoundError(
|
|
62
|
-
"No pending interaction found for this requestId",
|
|
63
|
-
);
|
|
57
|
+
throw new NotFoundError("No pending interaction found for this requestId");
|
|
64
58
|
}
|
|
65
59
|
|
|
66
60
|
if (peeked.kind !== "host_cu") {
|
|
@@ -69,13 +63,32 @@ function handleHostCuResult({ body }: RouteHandlerArgs) {
|
|
|
69
63
|
);
|
|
70
64
|
}
|
|
71
65
|
|
|
72
|
-
|
|
73
|
-
|
|
66
|
+
// Validate submitting client matches the targeted client (if any).
|
|
67
|
+
if (peeked.targetClientId != null) {
|
|
68
|
+
const rawClientId = (headers as Record<string, string | undefined>)?.["x-vellum-client-id"];
|
|
69
|
+
const submittingClientId = rawClientId?.trim() || undefined;
|
|
70
|
+
if (!submittingClientId) {
|
|
71
|
+
throw new BadRequestError("x-vellum-client-id header is missing for a targeted host CU request.");
|
|
72
|
+
}
|
|
73
|
+
if (submittingClientId !== peeked.targetClientId) {
|
|
74
|
+
throw new ForbiddenError(
|
|
75
|
+
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const conversation = findConversation(peeked.conversationId);
|
|
74
81
|
if (!conversation) {
|
|
82
|
+
pendingInteractions.resolve(requestId);
|
|
75
83
|
throw new NotFoundError("Conversation not found for host CU result");
|
|
76
84
|
}
|
|
77
85
|
|
|
78
|
-
conversation.hostCuProxy
|
|
86
|
+
if (!conversation.hostCuProxy) {
|
|
87
|
+
pendingInteractions.resolve(requestId);
|
|
88
|
+
throw new NotFoundError("No host CU proxy for conversation");
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
conversation.hostCuProxy.processObservation(requestId, {
|
|
79
92
|
axTree,
|
|
80
93
|
axDiff,
|
|
81
94
|
screenshot,
|
|
@@ -103,8 +116,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
103
116
|
method: "POST",
|
|
104
117
|
requireGuardian: true,
|
|
105
118
|
summary: "Submit host CU result",
|
|
106
|
-
description:
|
|
107
|
-
"Resolve a pending host computer-use request by requestId.",
|
|
119
|
+
description: "Resolve a pending host computer-use request by requestId.",
|
|
108
120
|
tags: ["host"],
|
|
109
121
|
requestBody: z.object({
|
|
110
122
|
requestId: z.string().describe("Pending CU request ID"),
|
|
@@ -123,6 +135,24 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
123
135
|
responseBody: z.object({
|
|
124
136
|
accepted: z.boolean(),
|
|
125
137
|
}),
|
|
138
|
+
additionalResponses: {
|
|
139
|
+
"400": {
|
|
140
|
+
description:
|
|
141
|
+
"x-vellum-client-id header is missing for a targeted host CU request.",
|
|
142
|
+
},
|
|
143
|
+
"403": {
|
|
144
|
+
description:
|
|
145
|
+
"Submitting client does not match the targeted client for this request.",
|
|
146
|
+
},
|
|
147
|
+
"404": {
|
|
148
|
+
description:
|
|
149
|
+
"No pending interaction found for the given requestId, or the conversation/proxy no longer exists.",
|
|
150
|
+
},
|
|
151
|
+
"409": {
|
|
152
|
+
description:
|
|
153
|
+
"Pending interaction exists but is of a different kind (e.g. host_bash, host_file).",
|
|
154
|
+
},
|
|
155
|
+
},
|
|
126
156
|
handler: handleHostCuResult,
|
|
127
157
|
},
|
|
128
158
|
];
|
|
@@ -8,18 +8,14 @@ import { z } from "zod";
|
|
|
8
8
|
|
|
9
9
|
import { HostFileProxy } from "../../daemon/host-file-proxy.js";
|
|
10
10
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
11
|
-
import {
|
|
12
|
-
BadRequestError,
|
|
13
|
-
ConflictError,
|
|
14
|
-
NotFoundError,
|
|
15
|
-
} from "./errors.js";
|
|
11
|
+
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from "./errors.js";
|
|
16
12
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
17
13
|
|
|
18
14
|
// ---------------------------------------------------------------------------
|
|
19
15
|
// POST /v1/host-file-result
|
|
20
16
|
// ---------------------------------------------------------------------------
|
|
21
17
|
|
|
22
|
-
function handleHostFileResult({ body }: RouteHandlerArgs) {
|
|
18
|
+
function handleHostFileResult({ body, headers }: RouteHandlerArgs) {
|
|
23
19
|
if (!body || typeof body !== "object") {
|
|
24
20
|
throw new BadRequestError("Request body is required");
|
|
25
21
|
}
|
|
@@ -37,9 +33,7 @@ function handleHostFileResult({ body }: RouteHandlerArgs) {
|
|
|
37
33
|
|
|
38
34
|
const peeked = pendingInteractions.get(requestId);
|
|
39
35
|
if (!peeked) {
|
|
40
|
-
throw new NotFoundError(
|
|
41
|
-
"No pending interaction found for this requestId",
|
|
42
|
-
);
|
|
36
|
+
throw new NotFoundError("No pending interaction found for this requestId");
|
|
43
37
|
}
|
|
44
38
|
|
|
45
39
|
if (peeked.kind !== "host_file") {
|
|
@@ -48,7 +42,19 @@ function handleHostFileResult({ body }: RouteHandlerArgs) {
|
|
|
48
42
|
);
|
|
49
43
|
}
|
|
50
44
|
|
|
51
|
-
|
|
45
|
+
// Validate submitting client matches the targeted client (if any).
|
|
46
|
+
if (peeked.targetClientId != null) {
|
|
47
|
+
const rawClientId = (headers as Record<string, string | undefined>)?.["x-vellum-client-id"];
|
|
48
|
+
const submittingClientId = rawClientId?.trim() || undefined;
|
|
49
|
+
if (!submittingClientId) {
|
|
50
|
+
throw new BadRequestError("x-vellum-client-id header is missing for a targeted host file request.");
|
|
51
|
+
}
|
|
52
|
+
if (submittingClientId !== peeked.targetClientId) {
|
|
53
|
+
throw new ForbiddenError(
|
|
54
|
+
`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}"). The targeted client must submit the result.`,
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
52
58
|
|
|
53
59
|
HostFileProxy.instance.resolve(requestId, {
|
|
54
60
|
content: content ?? "",
|
|
@@ -90,6 +96,23 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
90
96
|
responseBody: z.object({
|
|
91
97
|
accepted: z.boolean(),
|
|
92
98
|
}),
|
|
99
|
+
additionalResponses: {
|
|
100
|
+
"400": {
|
|
101
|
+
description:
|
|
102
|
+
"x-vellum-client-id header is missing for a targeted host file request.",
|
|
103
|
+
},
|
|
104
|
+
"403": {
|
|
105
|
+
description:
|
|
106
|
+
"Submitting client does not match the targeted client for this request.",
|
|
107
|
+
},
|
|
108
|
+
"404": {
|
|
109
|
+
description: "No pending interaction found for the given requestId.",
|
|
110
|
+
},
|
|
111
|
+
"409": {
|
|
112
|
+
description:
|
|
113
|
+
"Pending interaction exists but is of a different kind (e.g. host_bash, host_cu).",
|
|
114
|
+
},
|
|
115
|
+
},
|
|
93
116
|
handler: handleHostFileResult,
|
|
94
117
|
},
|
|
95
118
|
];
|
|
@@ -9,11 +9,7 @@ import { z } from "zod";
|
|
|
9
9
|
|
|
10
10
|
import { HostTransferProxy } from "../../daemon/host-transfer-proxy.js";
|
|
11
11
|
import * as pendingInteractions from "../pending-interactions.js";
|
|
12
|
-
import {
|
|
13
|
-
BadRequestError,
|
|
14
|
-
ConflictError,
|
|
15
|
-
NotFoundError,
|
|
16
|
-
} from "./errors.js";
|
|
12
|
+
import { BadRequestError, ConflictError, ForbiddenError, NotFoundError } from "./errors.js";
|
|
17
13
|
import type { RouteDefinition, RouteHandlerArgs } from "./types.js";
|
|
18
14
|
|
|
19
15
|
/**
|
|
@@ -34,6 +30,7 @@ function findProxyByTransferId(transferId: string) {
|
|
|
34
30
|
|
|
35
31
|
function handleTransferContentGet({
|
|
36
32
|
pathParams = {},
|
|
33
|
+
headers = {},
|
|
37
34
|
}: RouteHandlerArgs): Uint8Array {
|
|
38
35
|
const transferId = pathParams.transferId;
|
|
39
36
|
if (!transferId) {
|
|
@@ -45,6 +42,13 @@ function handleTransferContentGet({
|
|
|
45
42
|
throw new NotFoundError("Unknown or consumed transfer");
|
|
46
43
|
}
|
|
47
44
|
|
|
45
|
+
const targetClientId = match.proxy.getTargetClientIdForTransfer(transferId);
|
|
46
|
+
if (targetClientId != null) {
|
|
47
|
+
const submittingClientId = (headers as Record<string, string>)["x-vellum-client-id"]?.trim() || undefined;
|
|
48
|
+
if (!submittingClientId) throw new BadRequestError("x-vellum-client-id header required for targeted transfer");
|
|
49
|
+
if (submittingClientId !== targetClientId) throw new ForbiddenError(`Client "${submittingClientId}" is not the owner of this transfer`);
|
|
50
|
+
}
|
|
51
|
+
|
|
48
52
|
const content = match.proxy.getTransferContent(transferId);
|
|
49
53
|
if (!content) {
|
|
50
54
|
throw new NotFoundError("Unknown or consumed transfer");
|
|
@@ -55,8 +59,11 @@ function handleTransferContentGet({
|
|
|
55
59
|
|
|
56
60
|
/**
|
|
57
61
|
* Resolve Content-Length and X-Transfer-SHA256 response headers for the
|
|
58
|
-
* GET transfer content endpoint. Called by the HTTP adapter
|
|
59
|
-
*
|
|
62
|
+
* GET transfer content endpoint. Called by the HTTP adapter AFTER the handler
|
|
63
|
+
* runs (`http-adapter.ts:107-125`), so the entry has already been consumed by
|
|
64
|
+
* `getTransferContent`. We read the size/sha256 from
|
|
65
|
+
* `takeJustConsumedTransferMetadata`, which the proxy populates synchronously
|
|
66
|
+
* during the handler's `getTransferContent` call.
|
|
60
67
|
*/
|
|
61
68
|
function resolveTransferContentGetHeaders({
|
|
62
69
|
pathParams = {},
|
|
@@ -66,16 +73,14 @@ function resolveTransferContentGetHeaders({
|
|
|
66
73
|
const transferId = pathParams?.transferId;
|
|
67
74
|
if (!transferId) return { "Content-Type": "application/octet-stream" };
|
|
68
75
|
|
|
69
|
-
const
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
const content = match.proxy.getTransferContent(transferId);
|
|
73
|
-
if (!content) return { "Content-Type": "application/octet-stream" };
|
|
76
|
+
const meta =
|
|
77
|
+
HostTransferProxy.instance.takeJustConsumedTransferMetadata(transferId);
|
|
78
|
+
if (!meta) return { "Content-Type": "application/octet-stream" };
|
|
74
79
|
|
|
75
80
|
return {
|
|
76
81
|
"Content-Type": "application/octet-stream",
|
|
77
|
-
"Content-Length":
|
|
78
|
-
"X-Transfer-SHA256":
|
|
82
|
+
"Content-Length": meta.sizeBytes.toString(),
|
|
83
|
+
"X-Transfer-SHA256": meta.sha256,
|
|
79
84
|
};
|
|
80
85
|
}
|
|
81
86
|
|
|
@@ -98,6 +103,13 @@ async function handleTransferContentPut({
|
|
|
98
103
|
throw new NotFoundError("Unknown or consumed transfer");
|
|
99
104
|
}
|
|
100
105
|
|
|
106
|
+
const targetClientId = match.proxy.getTargetClientIdForTransfer(transferId);
|
|
107
|
+
if (targetClientId != null) {
|
|
108
|
+
const submittingClientId = (headers as Record<string, string>)["x-vellum-client-id"]?.trim() || undefined;
|
|
109
|
+
if (!submittingClientId) throw new BadRequestError("x-vellum-client-id header required for targeted transfer");
|
|
110
|
+
if (submittingClientId !== targetClientId) throw new ForbiddenError(`Client "${submittingClientId}" is not the owner of this transfer`);
|
|
111
|
+
}
|
|
112
|
+
|
|
101
113
|
const data = rawBody ? Buffer.from(rawBody) : Buffer.alloc(0);
|
|
102
114
|
const sha256 = headers["x-transfer-sha256"] ?? "";
|
|
103
115
|
|
|
@@ -107,11 +119,6 @@ async function handleTransferContentPut({
|
|
|
107
119
|
sha256,
|
|
108
120
|
);
|
|
109
121
|
|
|
110
|
-
// For to_sandbox transfers there is no separate /v1/host-transfer-result
|
|
111
|
-
// callback — the PUT handler is the terminal event. Always clean up the
|
|
112
|
-
// pending interaction so it doesn't leak.
|
|
113
|
-
pendingInteractions.resolve(match.requestId);
|
|
114
|
-
|
|
115
122
|
if (!result.accepted) {
|
|
116
123
|
throw new BadRequestError(result.error ?? "Transfer content rejected");
|
|
117
124
|
}
|
|
@@ -123,7 +130,7 @@ async function handleTransferContentPut({
|
|
|
123
130
|
// POST /v1/host-transfer-result
|
|
124
131
|
// ---------------------------------------------------------------------------
|
|
125
132
|
|
|
126
|
-
function handleTransferResult({ body }: RouteHandlerArgs) {
|
|
133
|
+
function handleTransferResult({ body, headers }: RouteHandlerArgs) {
|
|
127
134
|
if (!body || typeof body !== "object") {
|
|
128
135
|
throw new BadRequestError("Request body is required");
|
|
129
136
|
}
|
|
@@ -141,9 +148,7 @@ function handleTransferResult({ body }: RouteHandlerArgs) {
|
|
|
141
148
|
|
|
142
149
|
const peeked = pendingInteractions.get(requestId);
|
|
143
150
|
if (!peeked) {
|
|
144
|
-
throw new NotFoundError(
|
|
145
|
-
"No pending interaction found for this requestId",
|
|
146
|
-
);
|
|
151
|
+
throw new NotFoundError("No pending interaction found for this requestId");
|
|
147
152
|
}
|
|
148
153
|
|
|
149
154
|
if (peeked.kind !== "host_transfer") {
|
|
@@ -152,7 +157,12 @@ function handleTransferResult({ body }: RouteHandlerArgs) {
|
|
|
152
157
|
);
|
|
153
158
|
}
|
|
154
159
|
|
|
155
|
-
|
|
160
|
+
if (peeked.targetClientId != null) {
|
|
161
|
+
const rawClientId = (headers as Record<string, string | undefined>)?.["x-vellum-client-id"];
|
|
162
|
+
const submittingClientId = rawClientId?.trim() || undefined;
|
|
163
|
+
if (!submittingClientId) throw new BadRequestError("x-vellum-client-id header is missing for a targeted host transfer request.");
|
|
164
|
+
if (submittingClientId !== peeked.targetClientId) throw new ForbiddenError(`Client "${submittingClientId}" is not the target for this request (expected "${peeked.targetClientId}").`);
|
|
165
|
+
}
|
|
156
166
|
|
|
157
167
|
HostTransferProxy.instance.resolveTransferResult(requestId, {
|
|
158
168
|
isError: isError ?? false,
|
|
@@ -179,6 +189,16 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
179
189
|
"Serve raw file bytes for a to_host transfer. Single-use: returns 404 after first consumption.",
|
|
180
190
|
tags: ["host-transfer"],
|
|
181
191
|
responseHeaders: resolveTransferContentGetHeaders,
|
|
192
|
+
additionalResponses: {
|
|
193
|
+
"400": {
|
|
194
|
+
description:
|
|
195
|
+
"x-vellum-client-id header is missing for a targeted transfer.",
|
|
196
|
+
},
|
|
197
|
+
"403": {
|
|
198
|
+
description:
|
|
199
|
+
"Submitting client does not match the targeted client for this transfer.",
|
|
200
|
+
},
|
|
201
|
+
},
|
|
182
202
|
handler: handleTransferContentGet,
|
|
183
203
|
},
|
|
184
204
|
{
|
|
@@ -191,6 +211,16 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
191
211
|
description:
|
|
192
212
|
"Receive raw file bytes for a to_sandbox transfer. Verifies SHA-256 integrity via the X-Transfer-SHA256 header.",
|
|
193
213
|
tags: ["host-transfer"],
|
|
214
|
+
additionalResponses: {
|
|
215
|
+
"400": {
|
|
216
|
+
description:
|
|
217
|
+
"x-vellum-client-id header is missing for a targeted transfer.",
|
|
218
|
+
},
|
|
219
|
+
"403": {
|
|
220
|
+
description:
|
|
221
|
+
"Submitting client does not match the targeted client for this transfer.",
|
|
222
|
+
},
|
|
223
|
+
},
|
|
194
224
|
handler: handleTransferContentPut,
|
|
195
225
|
},
|
|
196
226
|
{
|
|
@@ -211,6 +241,16 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
211
241
|
responseBody: z.object({
|
|
212
242
|
accepted: z.boolean(),
|
|
213
243
|
}),
|
|
244
|
+
additionalResponses: {
|
|
245
|
+
"400": {
|
|
246
|
+
description:
|
|
247
|
+
"x-vellum-client-id header is missing for a targeted host transfer request.",
|
|
248
|
+
},
|
|
249
|
+
"403": {
|
|
250
|
+
description:
|
|
251
|
+
"Submitting client does not match the targeted client for this transfer.",
|
|
252
|
+
},
|
|
253
|
+
},
|
|
214
254
|
handler: handleTransferResult,
|
|
215
255
|
},
|
|
216
256
|
];
|
|
@@ -48,6 +48,36 @@ function readWorkspaceFile(name: string): string {
|
|
|
48
48
|
}
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
function parseIdentityIntroSection(content: string): string | null {
|
|
52
|
+
let inSection = false;
|
|
53
|
+
|
|
54
|
+
for (const line of content.split("\n")) {
|
|
55
|
+
const trimmed = line.trim();
|
|
56
|
+
if (/^#+\s/.test(trimmed)) {
|
|
57
|
+
inSection = trimmed.toLowerCase().includes("identity intro");
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
if (inSection && trimmed.length > 0) {
|
|
61
|
+
return trimmed;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Read the explicit `## Identity Intro` section from workspace prompt files.
|
|
70
|
+
*
|
|
71
|
+
* BOOTSTRAP.md instructs the assistant to write this section in IDENTITY.md.
|
|
72
|
+
* SOUL.md remains a fallback for older workspaces that stored the intro there.
|
|
73
|
+
*/
|
|
74
|
+
export function readWorkspaceIdentityIntro(): string | null {
|
|
75
|
+
return (
|
|
76
|
+
parseIdentityIntroSection(readWorkspaceFile("IDENTITY.md")) ??
|
|
77
|
+
parseIdentityIntroSection(readWorkspaceFile("SOUL.md"))
|
|
78
|
+
);
|
|
79
|
+
}
|
|
80
|
+
|
|
51
81
|
/** Compute a SHA-256 hex hash of the concatenated identity file contents. */
|
|
52
82
|
export function computeIdentityContentHash(): string {
|
|
53
83
|
const staticFiles = IDENTITY_FILES.map(readWorkspaceFile).join("\n---\n");
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
import { spawnSync } from "node:child_process";
|
|
6
|
-
import { existsSync, readFileSync, statfsSync
|
|
6
|
+
import { existsSync, readFileSync, statfsSync } from "node:fs";
|
|
7
7
|
import { availableParallelism, cpus, totalmem } from "node:os";
|
|
8
8
|
|
|
9
9
|
import { z } from "zod";
|
|
@@ -21,6 +21,7 @@ import {
|
|
|
21
21
|
getWorkspacePromptPath,
|
|
22
22
|
} from "../../util/platform.js";
|
|
23
23
|
import { APP_VERSION } from "../../version.js";
|
|
24
|
+
import { resolveHatchedAtReadOnly } from "../../workspace/hatched-date.js";
|
|
24
25
|
import { WORKSPACE_MIGRATIONS } from "../../workspace/migrations/registry.js";
|
|
25
26
|
import { getLastWorkspaceMigrationId } from "../../workspace/migrations/runner.js";
|
|
26
27
|
import { NotFoundError } from "./errors.js";
|
|
@@ -488,13 +489,7 @@ function getIdentity() {
|
|
|
488
489
|
|
|
489
490
|
const version = APP_VERSION;
|
|
490
491
|
|
|
491
|
-
|
|
492
|
-
try {
|
|
493
|
-
const stats = statSync(identityPath);
|
|
494
|
-
createdAt = stats.birthtime.toISOString();
|
|
495
|
-
} catch {
|
|
496
|
-
// ignore
|
|
497
|
-
}
|
|
492
|
+
const createdAt = resolveIdentityCreatedAt(identityPath);
|
|
498
493
|
|
|
499
494
|
return {
|
|
500
495
|
name: fields.name ?? "",
|
|
@@ -507,10 +502,18 @@ function getIdentity() {
|
|
|
507
502
|
};
|
|
508
503
|
}
|
|
509
504
|
|
|
505
|
+
function resolveIdentityCreatedAt(identityPath: string): string | undefined {
|
|
506
|
+
return resolveHatchedAtReadOnly(identityPath);
|
|
507
|
+
}
|
|
508
|
+
|
|
510
509
|
function getIdentityIntro() {
|
|
511
|
-
const
|
|
512
|
-
if (
|
|
513
|
-
|
|
510
|
+
const identityPath = getWorkspacePromptPath("IDENTITY.md");
|
|
511
|
+
if (existsSync(identityPath)) {
|
|
512
|
+
const content = readFileSync(identityPath, "utf-8");
|
|
513
|
+
const fields = parseIdentityFields(content);
|
|
514
|
+
if (fields.name) {
|
|
515
|
+
return { text: `Hi, I'm ${fields.name}!` };
|
|
516
|
+
}
|
|
514
517
|
}
|
|
515
518
|
|
|
516
519
|
const cached = getCachedIntro();
|
|
@@ -520,37 +523,6 @@ function getIdentityIntro() {
|
|
|
520
523
|
return { text: cached.text };
|
|
521
524
|
}
|
|
522
525
|
|
|
523
|
-
// ---------------------------------------------------------------------------
|
|
524
|
-
// Identity intro cache
|
|
525
|
-
// ---------------------------------------------------------------------------
|
|
526
|
-
|
|
527
|
-
/**
|
|
528
|
-
* Parse the `## Identity Intro` section from SOUL.md.
|
|
529
|
-
* Returns the first non-empty line under that heading, or null.
|
|
530
|
-
*/
|
|
531
|
-
function readSoulIdentityIntro(): string | null {
|
|
532
|
-
try {
|
|
533
|
-
const soulPath = getWorkspacePromptPath("SOUL.md");
|
|
534
|
-
if (!existsSync(soulPath)) return null;
|
|
535
|
-
const content = readFileSync(soulPath, "utf-8");
|
|
536
|
-
|
|
537
|
-
let inSection = false;
|
|
538
|
-
for (const line of content.split("\n")) {
|
|
539
|
-
const trimmed = line.trim();
|
|
540
|
-
if (/^#+\s/.test(trimmed)) {
|
|
541
|
-
inSection = trimmed.toLowerCase().includes("identity intro");
|
|
542
|
-
continue;
|
|
543
|
-
}
|
|
544
|
-
if (inSection && trimmed.length > 0) {
|
|
545
|
-
return trimmed;
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
} catch {
|
|
549
|
-
// Fall through to cache/fallback
|
|
550
|
-
}
|
|
551
|
-
return null;
|
|
552
|
-
}
|
|
553
|
-
|
|
554
526
|
// ---------------------------------------------------------------------------
|
|
555
527
|
// Zod schemas for profiler health metadata
|
|
556
528
|
// ---------------------------------------------------------------------------
|
|
@@ -647,7 +619,7 @@ export const ROUTES: RouteDefinition[] = [
|
|
|
647
619
|
handler: getIdentityIntro,
|
|
648
620
|
summary: "Get identity intro text",
|
|
649
621
|
description:
|
|
650
|
-
"Returns
|
|
622
|
+
"Returns a deterministic greeting derived from the assistant name in IDENTITY.md, falling back to LLM-generated cache.",
|
|
651
623
|
tags: ["identity"],
|
|
652
624
|
responseBody: z.object({
|
|
653
625
|
text: z.string(),
|