@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
|
@@ -13,25 +13,24 @@ import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
|
13
13
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
14
14
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
15
15
|
import { getLogger } from "../util/logger.js";
|
|
16
|
-
import type { ServerMessage } from "./message-protocol.js";
|
|
17
16
|
|
|
18
17
|
const log = getLogger("host-transfer-proxy");
|
|
19
18
|
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
19
|
+
/**
|
|
20
|
+
* Lightweight entry for the transfers map (keyed by transferId).
|
|
21
|
+
* Points back to the requestId so route handlers can correlate
|
|
22
|
+
* content endpoints with the pending interaction.
|
|
23
|
+
*/
|
|
24
|
+
interface TransferEntry {
|
|
24
25
|
requestId: string;
|
|
25
26
|
transferId: string;
|
|
26
|
-
conversationId: string;
|
|
27
27
|
direction: "to_host" | "to_sandbox";
|
|
28
28
|
filePath: string;
|
|
29
29
|
overwrite?: boolean;
|
|
30
30
|
sizeBytes?: number;
|
|
31
31
|
sha256?: string;
|
|
32
32
|
fileBuffer?: Buffer;
|
|
33
|
-
|
|
34
|
-
detachAbort: () => void;
|
|
33
|
+
targetClientId?: string;
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
/**
|
|
@@ -82,10 +81,22 @@ export class HostTransferProxy {
|
|
|
82
81
|
HostTransferProxy._instance = null;
|
|
83
82
|
}
|
|
84
83
|
|
|
85
|
-
/** Pending transfers keyed by requestId (for resolution from client results). */
|
|
86
|
-
private pending = new Map<string, PendingTransfer>();
|
|
87
84
|
/** Pending transfers keyed by transferId (for content endpoint lookups). */
|
|
88
|
-
private transfers = new Map<string,
|
|
85
|
+
private transfers = new Map<string, TransferEntry>();
|
|
86
|
+
/**
|
|
87
|
+
* Briefly retains size/sha256 of a just-consumed transfer so the GET-content
|
|
88
|
+
* route's `resolveResponseHeaders` callback (which the HTTP adapter invokes
|
|
89
|
+
* AFTER the request handler) can still set `Content-Length` and
|
|
90
|
+
* `X-Transfer-SHA256` headers. Without this, the handler's `getTransferContent`
|
|
91
|
+
* call deletes the entry before the header resolver runs, and the resolver
|
|
92
|
+
* silently falls back to default headers — meaning the documented response
|
|
93
|
+
* headers were never actually sent. Entries here self-clear on read; a 30s
|
|
94
|
+
* fallback timer prevents long-term retention if the resolver never runs.
|
|
95
|
+
*/
|
|
96
|
+
private justConsumedMetadata = new Map<
|
|
97
|
+
string,
|
|
98
|
+
{ sizeBytes: number; sha256: string }
|
|
99
|
+
>();
|
|
89
100
|
|
|
90
101
|
/**
|
|
91
102
|
* Whether a client with `host_file` capability is connected.
|
|
@@ -97,10 +108,6 @@ export class HostTransferProxy {
|
|
|
97
108
|
);
|
|
98
109
|
}
|
|
99
110
|
|
|
100
|
-
private send(msg: ServerMessage): void {
|
|
101
|
-
broadcastMessage(msg, undefined, { targetCapability: "host_file" });
|
|
102
|
-
}
|
|
103
|
-
|
|
104
111
|
/**
|
|
105
112
|
* Request a file transfer from the sandbox to the host machine.
|
|
106
113
|
*
|
|
@@ -114,6 +121,7 @@ export class HostTransferProxy {
|
|
|
114
121
|
destPath: string;
|
|
115
122
|
overwrite: boolean;
|
|
116
123
|
conversationId: string;
|
|
124
|
+
targetClientId?: string;
|
|
117
125
|
},
|
|
118
126
|
signal?: AbortSignal,
|
|
119
127
|
): Promise<ToolExecutionResult> {
|
|
@@ -121,13 +129,32 @@ export class HostTransferProxy {
|
|
|
121
129
|
return Promise.resolve({ content: "Aborted", isError: true });
|
|
122
130
|
}
|
|
123
131
|
|
|
132
|
+
let resolvedTargetClientId: string | undefined = input.targetClientId;
|
|
133
|
+
if (resolvedTargetClientId != null) {
|
|
134
|
+
const client = assistantEventHub.getClientById(resolvedTargetClientId);
|
|
135
|
+
if (!client) {
|
|
136
|
+
return Promise.resolve({
|
|
137
|
+
content: `No connected client with id '${resolvedTargetClientId}' supports host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
138
|
+
isError: true,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
if (!client.capabilities.includes("host_file")) {
|
|
142
|
+
return Promise.resolve({
|
|
143
|
+
content: `Client '${resolvedTargetClientId}' does not support host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
144
|
+
isError: true,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
} else {
|
|
148
|
+
const capable = assistantEventHub.listClientsByCapability("host_file");
|
|
149
|
+
if (capable.length === 1) resolvedTargetClientId = capable[0].clientId;
|
|
150
|
+
}
|
|
151
|
+
|
|
124
152
|
const requestId = uuid();
|
|
125
153
|
const transferId = uuid();
|
|
126
154
|
|
|
127
155
|
return new Promise<ToolExecutionResult>((resolve, reject) => {
|
|
128
156
|
readFile(input.sourcePath)
|
|
129
157
|
.then((fileBuffer) => {
|
|
130
|
-
// Check again after async read in case signal fired during I/O.
|
|
131
158
|
if (signal?.aborted) {
|
|
132
159
|
resolve({ content: "Aborted", isError: true });
|
|
133
160
|
return;
|
|
@@ -142,37 +169,40 @@ export class HostTransferProxy {
|
|
|
142
169
|
let detachAbort: () => void = () => {};
|
|
143
170
|
|
|
144
171
|
const timer = setTimeout(() => {
|
|
145
|
-
this.pending.delete(requestId);
|
|
146
172
|
this.transfers.delete(transferId);
|
|
147
|
-
detachAbort();
|
|
148
173
|
pendingInteractions.resolve(requestId);
|
|
149
174
|
log.warn(
|
|
150
175
|
{ requestId, transferId, direction: "to_host" },
|
|
151
176
|
"Host transfer proxy request timed out",
|
|
152
177
|
);
|
|
153
178
|
resolve({
|
|
154
|
-
content:
|
|
155
|
-
|
|
179
|
+
content: resolvedTargetClientId
|
|
180
|
+
? `Host transfer proxy timed out waiting for response from client '${resolvedTargetClientId}'`
|
|
181
|
+
: "Host transfer proxy timed out waiting for client response",
|
|
156
182
|
isError: true,
|
|
157
183
|
});
|
|
158
184
|
}, timeoutMs);
|
|
159
185
|
|
|
160
186
|
if (signal) {
|
|
161
187
|
const onAbort = () => {
|
|
162
|
-
if (
|
|
163
|
-
clearTimeout(timer);
|
|
164
|
-
this.pending.delete(requestId);
|
|
188
|
+
if (pendingInteractions.get(requestId)) {
|
|
165
189
|
this.transfers.delete(transferId);
|
|
166
|
-
detachAbort();
|
|
167
190
|
pendingInteractions.resolve(requestId);
|
|
168
191
|
try {
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
192
|
+
broadcastMessage(
|
|
193
|
+
{
|
|
194
|
+
type: "host_transfer_cancel",
|
|
195
|
+
requestId,
|
|
196
|
+
conversationId: input.conversationId,
|
|
197
|
+
...(resolvedTargetClientId != null
|
|
198
|
+
? { targetClientId: resolvedTargetClientId }
|
|
199
|
+
: {}),
|
|
200
|
+
},
|
|
201
|
+
input.conversationId,
|
|
202
|
+
{ targetClientId: resolvedTargetClientId },
|
|
203
|
+
);
|
|
174
204
|
} catch {
|
|
175
|
-
// Best-effort cancel notification
|
|
205
|
+
// Best-effort cancel notification
|
|
176
206
|
}
|
|
177
207
|
resolve({ content: "Aborted", isError: true });
|
|
178
208
|
}
|
|
@@ -181,40 +211,49 @@ export class HostTransferProxy {
|
|
|
181
211
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
182
212
|
}
|
|
183
213
|
|
|
184
|
-
|
|
185
|
-
resolve,
|
|
186
|
-
reject,
|
|
187
|
-
timer,
|
|
214
|
+
this.transfers.set(transferId, {
|
|
188
215
|
requestId,
|
|
189
216
|
transferId,
|
|
190
|
-
conversationId: input.conversationId,
|
|
191
217
|
direction: "to_host",
|
|
192
218
|
filePath: input.destPath,
|
|
193
219
|
sizeBytes,
|
|
194
220
|
sha256,
|
|
195
221
|
fileBuffer,
|
|
222
|
+
targetClientId: resolvedTargetClientId,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
pendingInteractions.register(requestId, {
|
|
226
|
+
conversationId: input.conversationId,
|
|
227
|
+
kind: "host_transfer",
|
|
228
|
+
targetClientId: resolvedTargetClientId,
|
|
229
|
+
rpcResolve: resolve,
|
|
230
|
+
rpcReject: reject,
|
|
231
|
+
timer,
|
|
196
232
|
detachAbort,
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
this.transfers.set(transferId, entry);
|
|
233
|
+
metadata: { transferId },
|
|
234
|
+
});
|
|
200
235
|
|
|
201
236
|
try {
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
237
|
+
broadcastMessage(
|
|
238
|
+
{
|
|
239
|
+
type: "host_transfer_request",
|
|
240
|
+
requestId,
|
|
241
|
+
conversationId: input.conversationId,
|
|
242
|
+
direction: "to_host",
|
|
243
|
+
transferId,
|
|
244
|
+
destPath: input.destPath,
|
|
245
|
+
sizeBytes,
|
|
246
|
+
sha256,
|
|
247
|
+
overwrite: input.overwrite,
|
|
248
|
+
...(resolvedTargetClientId != null
|
|
249
|
+
? { targetClientId: resolvedTargetClientId }
|
|
250
|
+
: {}),
|
|
251
|
+
},
|
|
252
|
+
input.conversationId,
|
|
253
|
+
{ targetClientId: resolvedTargetClientId },
|
|
254
|
+
);
|
|
213
255
|
} catch (err) {
|
|
214
|
-
clearTimeout(timer);
|
|
215
|
-
this.pending.delete(requestId);
|
|
216
256
|
this.transfers.delete(transferId);
|
|
217
|
-
detachAbort();
|
|
218
257
|
pendingInteractions.resolve(requestId);
|
|
219
258
|
log.warn(
|
|
220
259
|
{ requestId, transferId, err },
|
|
@@ -249,6 +288,7 @@ export class HostTransferProxy {
|
|
|
249
288
|
destPath: string;
|
|
250
289
|
overwrite?: boolean;
|
|
251
290
|
conversationId: string;
|
|
291
|
+
targetClientId?: string;
|
|
252
292
|
},
|
|
253
293
|
signal?: AbortSignal,
|
|
254
294
|
): Promise<ToolExecutionResult> {
|
|
@@ -256,6 +296,26 @@ export class HostTransferProxy {
|
|
|
256
296
|
return Promise.resolve({ content: "Aborted", isError: true });
|
|
257
297
|
}
|
|
258
298
|
|
|
299
|
+
let resolvedTargetClientId: string | undefined = input.targetClientId;
|
|
300
|
+
if (resolvedTargetClientId != null) {
|
|
301
|
+
const client = assistantEventHub.getClientById(resolvedTargetClientId);
|
|
302
|
+
if (!client) {
|
|
303
|
+
return Promise.resolve({
|
|
304
|
+
content: `No connected client with id '${resolvedTargetClientId}' supports host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
305
|
+
isError: true,
|
|
306
|
+
});
|
|
307
|
+
}
|
|
308
|
+
if (!client.capabilities.includes("host_file")) {
|
|
309
|
+
return Promise.resolve({
|
|
310
|
+
content: `Client '${resolvedTargetClientId}' does not support host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
311
|
+
isError: true,
|
|
312
|
+
});
|
|
313
|
+
}
|
|
314
|
+
} else {
|
|
315
|
+
const capable = assistantEventHub.listClientsByCapability("host_file");
|
|
316
|
+
if (capable.length === 1) resolvedTargetClientId = capable[0].clientId;
|
|
317
|
+
}
|
|
318
|
+
|
|
259
319
|
const requestId = uuid();
|
|
260
320
|
const transferId = uuid();
|
|
261
321
|
|
|
@@ -265,36 +325,40 @@ export class HostTransferProxy {
|
|
|
265
325
|
let detachAbort: () => void = () => {};
|
|
266
326
|
|
|
267
327
|
const timer = setTimeout(() => {
|
|
268
|
-
this.pending.delete(requestId);
|
|
269
328
|
this.transfers.delete(transferId);
|
|
270
|
-
detachAbort();
|
|
271
329
|
pendingInteractions.resolve(requestId);
|
|
272
330
|
log.warn(
|
|
273
331
|
{ requestId, transferId, direction: "to_sandbox" },
|
|
274
332
|
"Host transfer proxy request timed out",
|
|
275
333
|
);
|
|
276
334
|
resolve({
|
|
277
|
-
content:
|
|
335
|
+
content: resolvedTargetClientId
|
|
336
|
+
? `Host transfer proxy timed out waiting for response from client '${resolvedTargetClientId}'`
|
|
337
|
+
: "Host transfer proxy timed out waiting for client response",
|
|
278
338
|
isError: true,
|
|
279
339
|
});
|
|
280
340
|
}, timeoutMs);
|
|
281
341
|
|
|
282
342
|
if (signal) {
|
|
283
343
|
const onAbort = () => {
|
|
284
|
-
if (
|
|
285
|
-
clearTimeout(timer);
|
|
286
|
-
this.pending.delete(requestId);
|
|
344
|
+
if (pendingInteractions.get(requestId)) {
|
|
287
345
|
this.transfers.delete(transferId);
|
|
288
|
-
detachAbort();
|
|
289
346
|
pendingInteractions.resolve(requestId);
|
|
290
347
|
try {
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
348
|
+
broadcastMessage(
|
|
349
|
+
{
|
|
350
|
+
type: "host_transfer_cancel",
|
|
351
|
+
requestId,
|
|
352
|
+
conversationId: input.conversationId,
|
|
353
|
+
...(resolvedTargetClientId != null
|
|
354
|
+
? { targetClientId: resolvedTargetClientId }
|
|
355
|
+
: {}),
|
|
356
|
+
},
|
|
357
|
+
input.conversationId,
|
|
358
|
+
{ targetClientId: resolvedTargetClientId },
|
|
359
|
+
);
|
|
296
360
|
} catch {
|
|
297
|
-
// Best-effort cancel notification
|
|
361
|
+
// Best-effort cancel notification
|
|
298
362
|
}
|
|
299
363
|
resolve({ content: "Aborted", isError: true });
|
|
300
364
|
}
|
|
@@ -303,35 +367,44 @@ export class HostTransferProxy {
|
|
|
303
367
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
304
368
|
}
|
|
305
369
|
|
|
306
|
-
|
|
307
|
-
resolve,
|
|
308
|
-
reject,
|
|
309
|
-
timer,
|
|
370
|
+
this.transfers.set(transferId, {
|
|
310
371
|
requestId,
|
|
311
372
|
transferId,
|
|
312
|
-
conversationId: input.conversationId,
|
|
313
373
|
direction: "to_sandbox",
|
|
314
374
|
filePath: input.destPath,
|
|
315
375
|
overwrite: input.overwrite,
|
|
376
|
+
targetClientId: resolvedTargetClientId,
|
|
377
|
+
});
|
|
378
|
+
|
|
379
|
+
pendingInteractions.register(requestId, {
|
|
380
|
+
conversationId: input.conversationId,
|
|
381
|
+
kind: "host_transfer",
|
|
382
|
+
targetClientId: resolvedTargetClientId,
|
|
383
|
+
rpcResolve: resolve,
|
|
384
|
+
rpcReject: reject,
|
|
385
|
+
timer,
|
|
316
386
|
detachAbort,
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
this.transfers.set(transferId, entry);
|
|
387
|
+
metadata: { transferId },
|
|
388
|
+
});
|
|
320
389
|
|
|
321
390
|
try {
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
391
|
+
broadcastMessage(
|
|
392
|
+
{
|
|
393
|
+
type: "host_transfer_request",
|
|
394
|
+
requestId,
|
|
395
|
+
conversationId: input.conversationId,
|
|
396
|
+
direction: "to_sandbox",
|
|
397
|
+
transferId,
|
|
398
|
+
sourcePath: input.sourcePath,
|
|
399
|
+
...(resolvedTargetClientId != null
|
|
400
|
+
? { targetClientId: resolvedTargetClientId }
|
|
401
|
+
: {}),
|
|
402
|
+
},
|
|
403
|
+
input.conversationId,
|
|
404
|
+
{ targetClientId: resolvedTargetClientId },
|
|
405
|
+
);
|
|
330
406
|
} catch (err) {
|
|
331
|
-
clearTimeout(timer);
|
|
332
|
-
this.pending.delete(requestId);
|
|
333
407
|
this.transfers.delete(transferId);
|
|
334
|
-
detachAbort();
|
|
335
408
|
pendingInteractions.resolve(requestId);
|
|
336
409
|
log.warn(
|
|
337
410
|
{ requestId, transferId, err },
|
|
@@ -353,23 +426,21 @@ export class HostTransferProxy {
|
|
|
353
426
|
errorMessage?: string;
|
|
354
427
|
},
|
|
355
428
|
): void {
|
|
356
|
-
const
|
|
357
|
-
if (!
|
|
429
|
+
const interaction = pendingInteractions.resolve(requestId);
|
|
430
|
+
if (!interaction?.rpcResolve) {
|
|
358
431
|
log.warn({ requestId }, "No pending host transfer request for response");
|
|
359
432
|
return;
|
|
360
433
|
}
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
this.pending.delete(requestId);
|
|
364
|
-
this.transfers.delete(entry.transferId);
|
|
434
|
+
const transferId = interaction.metadata?.transferId as string | undefined;
|
|
435
|
+
if (transferId) this.transfers.delete(transferId);
|
|
365
436
|
|
|
366
437
|
if (result.isError) {
|
|
367
|
-
|
|
438
|
+
interaction.rpcResolve({
|
|
368
439
|
content: result.errorMessage ?? "Host transfer failed",
|
|
369
440
|
isError: true,
|
|
370
441
|
});
|
|
371
442
|
} else {
|
|
372
|
-
|
|
443
|
+
interaction.rpcResolve({
|
|
373
444
|
content: `File transferred successfully${result.bytesWritten != null ? ` (${result.bytesWritten} bytes)` : ""}`,
|
|
374
445
|
isError: false,
|
|
375
446
|
});
|
|
@@ -394,8 +465,21 @@ export class HostTransferProxy {
|
|
|
394
465
|
) {
|
|
395
466
|
return null;
|
|
396
467
|
}
|
|
397
|
-
//
|
|
398
|
-
//
|
|
468
|
+
// Stash size/sha256 so the GET-content route's `resolveResponseHeaders`
|
|
469
|
+
// callback can still set `Content-Length` and `X-Transfer-SHA256` on the
|
|
470
|
+
// response. The HTTP adapter invokes the handler (this method) BEFORE the
|
|
471
|
+
// response-header resolver, so without this stash the resolver sees a
|
|
472
|
+
// deleted entry and silently falls back to default headers.
|
|
473
|
+
this.justConsumedMetadata.set(transferId, {
|
|
474
|
+
sizeBytes: entry.sizeBytes,
|
|
475
|
+
sha256: entry.sha256,
|
|
476
|
+
});
|
|
477
|
+
// Fallback cleanup: if the resolver never reads (e.g., handler error after
|
|
478
|
+
// consume, request abort), drop the metadata after a short grace window.
|
|
479
|
+
// `unref()` so the timer never holds the process open.
|
|
480
|
+
setTimeout(() => {
|
|
481
|
+
this.justConsumedMetadata.delete(transferId);
|
|
482
|
+
}, 30_000).unref?.();
|
|
399
483
|
this.transfers.delete(transferId);
|
|
400
484
|
return {
|
|
401
485
|
buffer: entry.fileBuffer,
|
|
@@ -404,6 +488,23 @@ export class HostTransferProxy {
|
|
|
404
488
|
};
|
|
405
489
|
}
|
|
406
490
|
|
|
491
|
+
/**
|
|
492
|
+
* Returns and clears the size/sha256 metadata for a transfer that was just
|
|
493
|
+
* consumed by `getTransferContent`. Intended for use by the GET-content
|
|
494
|
+
* route's `resolveResponseHeaders` callback to populate `Content-Length` and
|
|
495
|
+
* `X-Transfer-SHA256` response headers. Returns null if no metadata is
|
|
496
|
+
* cached (e.g., transfer was never consumed, or already read by a previous
|
|
497
|
+
* resolver call).
|
|
498
|
+
*/
|
|
499
|
+
takeJustConsumedTransferMetadata(
|
|
500
|
+
transferId: string,
|
|
501
|
+
): { sizeBytes: number; sha256: string } | null {
|
|
502
|
+
const meta = this.justConsumedMetadata.get(transferId);
|
|
503
|
+
if (!meta) return null;
|
|
504
|
+
this.justConsumedMetadata.delete(transferId);
|
|
505
|
+
return meta;
|
|
506
|
+
}
|
|
507
|
+
|
|
407
508
|
/**
|
|
408
509
|
* Receive file content from the client for a to_sandbox transfer (the PUT content endpoint).
|
|
409
510
|
*
|
|
@@ -437,29 +538,25 @@ export class HostTransferProxy {
|
|
|
437
538
|
|
|
438
539
|
const { requestId } = entry;
|
|
439
540
|
|
|
440
|
-
// Enforce overwrite policy before writing.
|
|
441
541
|
if (entry.overwrite !== true && existsSync(entry.filePath)) {
|
|
442
542
|
const errorMsg = `Destination file already exists: ${entry.filePath}. Set overwrite to true to replace it.`;
|
|
443
|
-
|
|
444
|
-
entry.detachAbort();
|
|
445
|
-
this.pending.delete(requestId);
|
|
543
|
+
const interaction = pendingInteractions.resolve(requestId);
|
|
446
544
|
this.transfers.delete(transferId);
|
|
447
|
-
|
|
545
|
+
interaction?.rpcResolve?.({ content: errorMsg, isError: true });
|
|
448
546
|
return { accepted: false, error: errorMsg };
|
|
449
547
|
}
|
|
450
548
|
|
|
451
549
|
const cleanup = () => {
|
|
452
|
-
|
|
453
|
-
entry.detachAbort();
|
|
454
|
-
this.pending.delete(requestId);
|
|
550
|
+
pendingInteractions.resolve(requestId);
|
|
455
551
|
this.transfers.delete(transferId);
|
|
456
552
|
};
|
|
457
553
|
|
|
458
554
|
try {
|
|
459
555
|
await mkdir(dirname(entry.filePath), { recursive: true });
|
|
460
556
|
await writeFile(entry.filePath, data);
|
|
557
|
+
const interaction = pendingInteractions.get(requestId);
|
|
461
558
|
cleanup();
|
|
462
|
-
|
|
559
|
+
interaction?.rpcResolve?.({
|
|
463
560
|
content: `File received and written to ${entry.filePath} (${data.length} bytes)`,
|
|
464
561
|
isError: false,
|
|
465
562
|
});
|
|
@@ -470,31 +567,37 @@ export class HostTransferProxy {
|
|
|
470
567
|
{ transferId, filePath: entry.filePath, err },
|
|
471
568
|
"Failed to write received transfer content",
|
|
472
569
|
);
|
|
570
|
+
const interaction = pendingInteractions.get(requestId);
|
|
473
571
|
cleanup();
|
|
474
|
-
|
|
572
|
+
interaction?.rpcResolve?.({ content: errorMsg, isError: true });
|
|
475
573
|
return { accepted: false, error: errorMsg };
|
|
476
574
|
}
|
|
477
575
|
}
|
|
478
576
|
|
|
479
577
|
/** Cancel a pending transfer by requestId. */
|
|
480
578
|
cancel(requestId: string): void {
|
|
481
|
-
const
|
|
482
|
-
if (!
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
this.pending.delete(requestId);
|
|
486
|
-
this.transfers.delete(entry.transferId);
|
|
579
|
+
const interaction = pendingInteractions.get(requestId);
|
|
580
|
+
if (!interaction) return;
|
|
581
|
+
const transferId = interaction.metadata?.transferId as string | undefined;
|
|
582
|
+
if (transferId) this.transfers.delete(transferId);
|
|
487
583
|
pendingInteractions.resolve(requestId);
|
|
488
584
|
try {
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
585
|
+
broadcastMessage(
|
|
586
|
+
{
|
|
587
|
+
type: "host_transfer_cancel",
|
|
588
|
+
requestId,
|
|
589
|
+
conversationId: interaction.conversationId,
|
|
590
|
+
...(interaction.targetClientId != null
|
|
591
|
+
? { targetClientId: interaction.targetClientId }
|
|
592
|
+
: {}),
|
|
593
|
+
},
|
|
594
|
+
interaction.conversationId,
|
|
595
|
+
{ targetClientId: interaction.targetClientId },
|
|
596
|
+
);
|
|
494
597
|
} catch {
|
|
495
|
-
// Best-effort cancel notification
|
|
598
|
+
// Best-effort cancel notification
|
|
496
599
|
}
|
|
497
|
-
|
|
600
|
+
interaction.rpcResolve?.({ content: "Transfer cancelled", isError: true });
|
|
498
601
|
}
|
|
499
602
|
|
|
500
603
|
hasPendingTransfer(transferId: string): boolean {
|
|
@@ -511,28 +614,43 @@ export class HostTransferProxy {
|
|
|
511
614
|
return entry?.requestId ?? null;
|
|
512
615
|
}
|
|
513
616
|
|
|
617
|
+
/**
|
|
618
|
+
* Look up the targetClientId for a given transferId without consuming the entry.
|
|
619
|
+
* Routes call this to verify ownership without affecting the transfer state.
|
|
620
|
+
* Returns null when untargeted (no validation needed).
|
|
621
|
+
*/
|
|
622
|
+
getTargetClientIdForTransfer(transferId: string): string | null {
|
|
623
|
+
return this.transfers.get(transferId)?.targetClientId ?? null;
|
|
624
|
+
}
|
|
625
|
+
|
|
514
626
|
dispose(): void {
|
|
515
|
-
for (const
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
pendingInteractions.resolve(requestId);
|
|
627
|
+
for (const entry of pendingInteractions.getByKind("host_transfer")) {
|
|
628
|
+
const transferId = entry.metadata?.transferId as string | undefined;
|
|
629
|
+
if (transferId) this.transfers.delete(transferId);
|
|
630
|
+
pendingInteractions.resolve(entry.requestId);
|
|
519
631
|
try {
|
|
520
|
-
|
|
632
|
+
broadcastMessage(
|
|
633
|
+
{
|
|
521
634
|
type: "host_transfer_cancel",
|
|
522
|
-
requestId,
|
|
635
|
+
requestId: entry.requestId,
|
|
523
636
|
conversationId: entry.conversationId,
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
637
|
+
...(entry.targetClientId != null
|
|
638
|
+
? { targetClientId: entry.targetClientId }
|
|
639
|
+
: {}),
|
|
640
|
+
},
|
|
641
|
+
entry.conversationId,
|
|
642
|
+
{ targetClientId: entry.targetClientId },
|
|
643
|
+
);
|
|
644
|
+
} catch {
|
|
645
|
+
// Best-effort cancel notification
|
|
646
|
+
}
|
|
647
|
+
entry.rpcReject?.(
|
|
529
648
|
new AssistantError(
|
|
530
649
|
"Host transfer proxy disposed",
|
|
531
650
|
ErrorCode.INTERNAL_ERROR,
|
|
532
651
|
),
|
|
533
652
|
);
|
|
534
653
|
}
|
|
535
|
-
this.pending.clear();
|
|
536
654
|
this.transfers.clear();
|
|
537
655
|
}
|
|
538
656
|
}
|