@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
|
@@ -9,6 +9,9 @@
|
|
|
9
9
|
* Unlike HostBashProxy/HostFileProxy/HostTransferProxy, this is NOT a
|
|
10
10
|
* singleton — each conversation gets its own instance because CU state
|
|
11
11
|
* (step count, AX tree history, loop detection) is per-conversation.
|
|
12
|
+
*
|
|
13
|
+
* RPC lifecycle (resolve/reject/timer/detachAbort) is stored in
|
|
14
|
+
* pendingInteractions alongside routing metadata.
|
|
12
15
|
*/
|
|
13
16
|
|
|
14
17
|
import { v4 as uuid } from "uuid";
|
|
@@ -24,7 +27,6 @@ import * as pendingInteractions from "../runtime/pending-interactions.js";
|
|
|
24
27
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
25
28
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
26
29
|
import { getLogger } from "../util/logger.js";
|
|
27
|
-
import type { ServerMessage } from "./message-protocol.js";
|
|
28
30
|
|
|
29
31
|
const log = getLogger("host-cu-proxy");
|
|
30
32
|
|
|
@@ -62,28 +64,19 @@ export interface ActionRecord {
|
|
|
62
64
|
reasoning?: string;
|
|
63
65
|
}
|
|
64
66
|
|
|
65
|
-
interface PendingRequest {
|
|
66
|
-
resolve: (result: ToolExecutionResult) => void;
|
|
67
|
-
reject: (err: Error) => void;
|
|
68
|
-
timer: ReturnType<typeof setTimeout>;
|
|
69
|
-
conversationId: string;
|
|
70
|
-
/** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
|
|
71
|
-
detachAbort: () => void;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
67
|
// ---------------------------------------------------------------------------
|
|
75
68
|
// HostCuProxy
|
|
76
69
|
// ---------------------------------------------------------------------------
|
|
77
70
|
|
|
78
71
|
export class HostCuProxy {
|
|
79
|
-
private pending = new Map<string, PendingRequest>();
|
|
80
|
-
|
|
81
72
|
// CU state tracking (per-conversation)
|
|
82
73
|
private _stepCount = 0;
|
|
83
74
|
private _maxSteps: number;
|
|
84
75
|
private _previousAXTree: string | undefined;
|
|
85
76
|
private _consecutiveUnchangedSteps = 0;
|
|
86
77
|
private _actionHistory: ActionRecord[] = [];
|
|
78
|
+
/** Request IDs owned by this instance — used to scope dispose(). */
|
|
79
|
+
private _ownedRequests = new Set<string>();
|
|
87
80
|
|
|
88
81
|
constructor(maxSteps = loadConfig().maxStepsPerSession) {
|
|
89
82
|
this._maxSteps = maxSteps;
|
|
@@ -121,17 +114,7 @@ export class HostCuProxy {
|
|
|
121
114
|
* Whether a client with `host_cu` capability is connected.
|
|
122
115
|
*/
|
|
123
116
|
isAvailable(): boolean {
|
|
124
|
-
return (
|
|
125
|
-
assistantEventHub.getMostRecentClientByCapability("host_cu") != null
|
|
126
|
-
);
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
// ---------------------------------------------------------------------------
|
|
130
|
-
// Send helper
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
|
|
133
|
-
private send(msg: ServerMessage): void {
|
|
134
|
-
broadcastMessage(msg, undefined, { targetCapability: "host_cu" });
|
|
117
|
+
return assistantEventHub.getMostRecentClientByCapability("host_cu") != null;
|
|
135
118
|
}
|
|
136
119
|
|
|
137
120
|
// ---------------------------------------------------------------------------
|
|
@@ -145,6 +128,7 @@ export class HostCuProxy {
|
|
|
145
128
|
stepNumber: number,
|
|
146
129
|
reasoning?: string,
|
|
147
130
|
signal?: AbortSignal,
|
|
131
|
+
targetClientId?: string,
|
|
148
132
|
): Promise<ToolExecutionResult> {
|
|
149
133
|
if (signal?.aborted) {
|
|
150
134
|
return Promise.resolve({
|
|
@@ -153,7 +137,6 @@ export class HostCuProxy {
|
|
|
153
137
|
});
|
|
154
138
|
}
|
|
155
139
|
|
|
156
|
-
// Enforce step limit before sending to client
|
|
157
140
|
if (this._stepCount > this._maxSteps) {
|
|
158
141
|
return Promise.resolve({
|
|
159
142
|
content: `Step limit (${this._maxSteps}) exceeded. Call computer_use_done to finish.`,
|
|
@@ -167,8 +150,7 @@ export class HostCuProxy {
|
|
|
167
150
|
let detachAbort: () => void = () => {};
|
|
168
151
|
|
|
169
152
|
const timer = setTimeout(() => {
|
|
170
|
-
this.
|
|
171
|
-
detachAbort();
|
|
153
|
+
this._ownedRequests.delete(requestId);
|
|
172
154
|
pendingInteractions.resolve(requestId);
|
|
173
155
|
log.warn({ requestId, toolName }, "Host CU proxy request timed out");
|
|
174
156
|
resolve({
|
|
@@ -179,19 +161,24 @@ export class HostCuProxy {
|
|
|
179
161
|
|
|
180
162
|
if (signal) {
|
|
181
163
|
const onAbort = () => {
|
|
182
|
-
if (
|
|
183
|
-
|
|
184
|
-
this.pending.delete(requestId);
|
|
185
|
-
detachAbort();
|
|
164
|
+
if (pendingInteractions.get(requestId)) {
|
|
165
|
+
this._ownedRequests.delete(requestId);
|
|
186
166
|
pendingInteractions.resolve(requestId);
|
|
187
167
|
try {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
168
|
+
broadcastMessage(
|
|
169
|
+
{
|
|
170
|
+
type: "host_cu_cancel",
|
|
171
|
+
requestId,
|
|
172
|
+
conversationId,
|
|
173
|
+
...(targetClientId != null
|
|
174
|
+
? { targetClientId }
|
|
175
|
+
: {}),
|
|
176
|
+
},
|
|
191
177
|
conversationId,
|
|
192
|
-
|
|
178
|
+
{ targetClientId },
|
|
179
|
+
);
|
|
193
180
|
} catch {
|
|
194
|
-
// Best-effort cancel notification
|
|
181
|
+
// Best-effort cancel notification
|
|
195
182
|
}
|
|
196
183
|
resolve({ content: "Aborted", isError: true });
|
|
197
184
|
}
|
|
@@ -200,22 +187,36 @@ export class HostCuProxy {
|
|
|
200
187
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
201
188
|
}
|
|
202
189
|
|
|
203
|
-
this.
|
|
190
|
+
this._ownedRequests.add(requestId);
|
|
191
|
+
|
|
192
|
+
pendingInteractions.register(requestId, {
|
|
193
|
+
conversationId,
|
|
194
|
+
kind: "host_cu",
|
|
195
|
+
targetClientId,
|
|
196
|
+
rpcResolve: resolve,
|
|
197
|
+
rpcReject: reject,
|
|
198
|
+
timer,
|
|
199
|
+
detachAbort,
|
|
200
|
+
});
|
|
204
201
|
|
|
205
202
|
try {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
203
|
+
broadcastMessage(
|
|
204
|
+
{
|
|
205
|
+
type: "host_cu_request",
|
|
206
|
+
requestId,
|
|
207
|
+
conversationId,
|
|
208
|
+
toolName,
|
|
209
|
+
input,
|
|
210
|
+
stepNumber,
|
|
211
|
+
reasoning,
|
|
212
|
+
// Include in body so receiving client can verify targeted endpoint.
|
|
213
|
+
...(targetClientId != null ? { targetClientId } : {}),
|
|
214
|
+
},
|
|
209
215
|
conversationId,
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
stepNumber,
|
|
213
|
-
reasoning,
|
|
214
|
-
});
|
|
216
|
+
{ targetClientId },
|
|
217
|
+
);
|
|
215
218
|
} catch (err) {
|
|
216
|
-
|
|
217
|
-
this.pending.delete(requestId);
|
|
218
|
-
detachAbort();
|
|
219
|
+
this._ownedRequests.delete(requestId);
|
|
219
220
|
pendingInteractions.resolve(requestId);
|
|
220
221
|
log.warn({ requestId, toolName, err }, "Host CU proxy send failed");
|
|
221
222
|
reject(err instanceof Error ? err : new Error(String(err)));
|
|
@@ -223,28 +224,27 @@ export class HostCuProxy {
|
|
|
223
224
|
});
|
|
224
225
|
}
|
|
225
226
|
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
227
|
+
/**
|
|
228
|
+
* Process a CU observation from the client and resolve the RPC.
|
|
229
|
+
* Updates CU state (step tracking, AX tree history) and formats
|
|
230
|
+
* the observation into a ToolExecutionResult.
|
|
231
|
+
*/
|
|
232
|
+
processObservation(
|
|
233
|
+
requestId: string,
|
|
234
|
+
observation: CuObservationResult,
|
|
235
|
+
): ToolExecutionResult | undefined {
|
|
236
|
+
this._ownedRequests.delete(requestId);
|
|
237
|
+
const interaction = pendingInteractions.resolve(requestId);
|
|
238
|
+
if (!interaction?.rpcResolve) {
|
|
229
239
|
log.warn({ requestId }, "No pending host CU request for response");
|
|
230
|
-
return;
|
|
240
|
+
return undefined;
|
|
231
241
|
}
|
|
232
|
-
clearTimeout(entry.timer);
|
|
233
|
-
entry.detachAbort();
|
|
234
|
-
this.pending.delete(requestId);
|
|
235
242
|
|
|
236
|
-
// Capture pre-update state so formatObservation sees the correct previous AX tree
|
|
237
243
|
const prevAXTree = this._previousAXTree;
|
|
238
|
-
|
|
239
|
-
// Update CU state from observation
|
|
240
244
|
this.updateStateFromObservation(observation);
|
|
241
|
-
|
|
242
245
|
const result = this.formatObservation(observation, prevAXTree);
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
hasPendingRequest(requestId: string): boolean {
|
|
247
|
-
return this.pending.has(requestId);
|
|
246
|
+
interaction.rpcResolve(result);
|
|
247
|
+
return result;
|
|
248
248
|
}
|
|
249
249
|
|
|
250
250
|
// ---------------------------------------------------------------------------
|
|
@@ -267,7 +267,6 @@ export class HostCuProxy {
|
|
|
267
267
|
input,
|
|
268
268
|
reasoning,
|
|
269
269
|
});
|
|
270
|
-
// Keep history bounded
|
|
271
270
|
if (this._actionHistory.length > MAX_HISTORY_ENTRIES) {
|
|
272
271
|
this._actionHistory = this._actionHistory.slice(-MAX_HISTORY_ENTRIES);
|
|
273
272
|
}
|
|
@@ -297,7 +296,6 @@ export class HostCuProxy {
|
|
|
297
296
|
const prevTree = previousAXTree;
|
|
298
297
|
const parts: string[] = [];
|
|
299
298
|
|
|
300
|
-
// Surface user guidance prominently so the model sees it first
|
|
301
299
|
if (obs.userGuidance) {
|
|
302
300
|
parts.push(`USER GUIDANCE: ${obs.userGuidance}`);
|
|
303
301
|
parts.push("");
|
|
@@ -308,12 +306,10 @@ export class HostCuProxy {
|
|
|
308
306
|
parts.push("");
|
|
309
307
|
}
|
|
310
308
|
|
|
311
|
-
// AX tree diff / unchanged warning
|
|
312
309
|
if (obs.axDiff) {
|
|
313
310
|
parts.push(obs.axDiff);
|
|
314
311
|
parts.push("");
|
|
315
312
|
} else if (prevTree != null && obs.axTree != null) {
|
|
316
|
-
// Skip unchanged warning after wait actions — they intentionally yield no immediate change
|
|
317
313
|
const lastAction =
|
|
318
314
|
this._actionHistory.length > 0
|
|
319
315
|
? this._actionHistory[this._actionHistory.length - 1]
|
|
@@ -321,7 +317,6 @@ export class HostCuProxy {
|
|
|
321
317
|
const isWaitAction = lastAction?.toolName === "computer_use_wait";
|
|
322
318
|
|
|
323
319
|
if (!isWaitAction) {
|
|
324
|
-
// No diff means the screen didn't change
|
|
325
320
|
if (
|
|
326
321
|
this._consecutiveUnchangedSteps >=
|
|
327
322
|
CONSECUTIVE_UNCHANGED_WARNING_THRESHOLD
|
|
@@ -338,7 +333,6 @@ export class HostCuProxy {
|
|
|
338
333
|
}
|
|
339
334
|
}
|
|
340
335
|
|
|
341
|
-
// Loop detection: identical actions repeated
|
|
342
336
|
if (this._actionHistory.length >= LOOP_DETECTION_WINDOW) {
|
|
343
337
|
const recent = this._actionHistory.slice(-LOOP_DETECTION_WINDOW);
|
|
344
338
|
const allIdentical = recent.every(
|
|
@@ -354,7 +348,6 @@ export class HostCuProxy {
|
|
|
354
348
|
}
|
|
355
349
|
}
|
|
356
350
|
|
|
357
|
-
// Current screen state wrapped in markers for history compaction
|
|
358
351
|
if (obs.axTree) {
|
|
359
352
|
parts.push("<ax-tree>");
|
|
360
353
|
parts.push("CURRENT SCREEN STATE:");
|
|
@@ -362,7 +355,6 @@ export class HostCuProxy {
|
|
|
362
355
|
parts.push("</ax-tree>");
|
|
363
356
|
}
|
|
364
357
|
|
|
365
|
-
// Secondary windows for cross-app awareness
|
|
366
358
|
if (obs.secondaryWindows) {
|
|
367
359
|
parts.push("");
|
|
368
360
|
parts.push(obs.secondaryWindows);
|
|
@@ -372,7 +364,6 @@ export class HostCuProxy {
|
|
|
372
364
|
);
|
|
373
365
|
}
|
|
374
366
|
|
|
375
|
-
// Screenshot metadata
|
|
376
367
|
const screenshotMeta = this.formatScreenshotMetadata(obs);
|
|
377
368
|
if (screenshotMeta.length > 0) {
|
|
378
369
|
parts.push("");
|
|
@@ -381,7 +372,6 @@ export class HostCuProxy {
|
|
|
381
372
|
|
|
382
373
|
const content = parts.join("\n").trim() || "Action executed";
|
|
383
374
|
|
|
384
|
-
// Build content blocks for screenshot
|
|
385
375
|
const contentBlocks: ContentBlock[] = [];
|
|
386
376
|
if (obs.screenshot) {
|
|
387
377
|
contentBlocks.push({
|
|
@@ -410,31 +400,36 @@ export class HostCuProxy {
|
|
|
410
400
|
// ---------------------------------------------------------------------------
|
|
411
401
|
|
|
412
402
|
dispose(): void {
|
|
413
|
-
for (const
|
|
414
|
-
|
|
415
|
-
entry
|
|
416
|
-
pendingInteractions.resolve(requestId);
|
|
403
|
+
for (const requestId of this._ownedRequests) {
|
|
404
|
+
const entry = pendingInteractions.resolve(requestId);
|
|
405
|
+
if (!entry) continue;
|
|
417
406
|
try {
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
407
|
+
broadcastMessage(
|
|
408
|
+
{
|
|
409
|
+
type: "host_cu_cancel",
|
|
410
|
+
requestId,
|
|
411
|
+
conversationId: entry.conversationId,
|
|
412
|
+
...(entry.targetClientId != null
|
|
413
|
+
? { targetClientId: entry.targetClientId }
|
|
414
|
+
: {}),
|
|
415
|
+
},
|
|
416
|
+
entry.conversationId,
|
|
417
|
+
{ targetClientId: entry.targetClientId as string | undefined },
|
|
418
|
+
);
|
|
423
419
|
} catch {
|
|
424
|
-
// Best-effort cancel notification
|
|
420
|
+
// Best-effort cancel notification
|
|
425
421
|
}
|
|
426
|
-
entry.
|
|
422
|
+
entry.rpcReject?.(
|
|
427
423
|
new AssistantError("Host CU proxy disposed", ErrorCode.INTERNAL_ERROR),
|
|
428
424
|
);
|
|
429
425
|
}
|
|
430
|
-
this.
|
|
426
|
+
this._ownedRequests.clear();
|
|
431
427
|
}
|
|
432
428
|
|
|
433
429
|
// ---------------------------------------------------------------------------
|
|
434
430
|
// Private helpers
|
|
435
431
|
// ---------------------------------------------------------------------------
|
|
436
432
|
|
|
437
|
-
/** Update consecutive-unchanged tracking from an incoming observation. */
|
|
438
433
|
private updateStateFromObservation(obs: CuObservationResult): void {
|
|
439
434
|
if (this._stepCount > 0) {
|
|
440
435
|
if (
|
|
@@ -9,7 +9,6 @@ import { readImageBase64 } from "../tools/shared/filesystem/image-read.js";
|
|
|
9
9
|
import type { ToolExecutionResult } from "../tools/types.js";
|
|
10
10
|
import { AssistantError, ErrorCode } from "../util/errors.js";
|
|
11
11
|
import { getLogger } from "../util/logger.js";
|
|
12
|
-
import type { ServerMessage } from "./message-protocol.js";
|
|
13
12
|
import type { HostFileRequest } from "./message-types/host-file.js";
|
|
14
13
|
|
|
15
14
|
/** Distributive omit that preserves union variant fields. */
|
|
@@ -25,17 +24,6 @@ export type HostFileInput = DistributiveOmit<
|
|
|
25
24
|
|
|
26
25
|
const log = getLogger("host-file-proxy");
|
|
27
26
|
|
|
28
|
-
interface PendingRequest {
|
|
29
|
-
resolve: (result: ToolExecutionResult) => void;
|
|
30
|
-
reject: (err: Error) => void;
|
|
31
|
-
timer: ReturnType<typeof setTimeout>;
|
|
32
|
-
operation: HostFileInput["operation"];
|
|
33
|
-
path: string;
|
|
34
|
-
conversationId: string;
|
|
35
|
-
/** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
|
|
36
|
-
detachAbort: () => void;
|
|
37
|
-
}
|
|
38
|
-
|
|
39
27
|
export class HostFileProxy {
|
|
40
28
|
private static _instance: HostFileProxy | null = null;
|
|
41
29
|
|
|
@@ -65,8 +53,6 @@ export class HostFileProxy {
|
|
|
65
53
|
HostFileProxy._instance = null;
|
|
66
54
|
}
|
|
67
55
|
|
|
68
|
-
private pending = new Map<string, PendingRequest>();
|
|
69
|
-
|
|
70
56
|
/**
|
|
71
57
|
* Whether a client with `host_file` capability is connected.
|
|
72
58
|
* Note: host_file covers both file operations and transfers.
|
|
@@ -77,56 +63,81 @@ export class HostFileProxy {
|
|
|
77
63
|
);
|
|
78
64
|
}
|
|
79
65
|
|
|
80
|
-
private send(msg: ServerMessage): void {
|
|
81
|
-
broadcastMessage(msg, undefined, { targetCapability: "host_file" });
|
|
82
|
-
}
|
|
83
|
-
|
|
84
66
|
request(
|
|
85
67
|
input: HostFileInput,
|
|
86
68
|
conversationId: string,
|
|
87
69
|
signal?: AbortSignal,
|
|
70
|
+
targetClientId?: string,
|
|
88
71
|
): Promise<ToolExecutionResult> {
|
|
89
72
|
if (signal?.aborted) {
|
|
90
73
|
return Promise.resolve({ content: "Aborted", isError: true });
|
|
91
74
|
}
|
|
92
75
|
|
|
76
|
+
// Resolve targetClientId: explicit → validate; single capable client → auto-resolve.
|
|
77
|
+
// Callers may embed targetClientId in the input object (tool handlers) or pass it as
|
|
78
|
+
// the 4th parameter (legacy). Prefer the explicit param; fall back to input field.
|
|
79
|
+
let resolvedTargetClientId: string | undefined = targetClientId ?? input.targetClientId;
|
|
80
|
+
if (resolvedTargetClientId != null) {
|
|
81
|
+
const client = assistantEventHub.getClientById(resolvedTargetClientId);
|
|
82
|
+
if (!client) {
|
|
83
|
+
return Promise.resolve({
|
|
84
|
+
content: `No connected client with id '${resolvedTargetClientId}' supports host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
85
|
+
isError: true,
|
|
86
|
+
});
|
|
87
|
+
}
|
|
88
|
+
if (!client.capabilities.includes("host_file")) {
|
|
89
|
+
return Promise.resolve({
|
|
90
|
+
content: `Client '${resolvedTargetClientId}' does not support host_file. Run \`assistant clients list --capability host_file\` to see available clients.`,
|
|
91
|
+
isError: true,
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
} else {
|
|
95
|
+
const capable = assistantEventHub.listClientsByCapability("host_file");
|
|
96
|
+
if (capable.length === 1) {
|
|
97
|
+
resolvedTargetClientId = capable[0].clientId;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
|
|
93
101
|
const requestId = uuid();
|
|
94
102
|
|
|
95
103
|
return new Promise<ToolExecutionResult>((resolve, reject) => {
|
|
96
|
-
// File operations should be fast — 30 second timeout.
|
|
97
104
|
const timeoutSec = 30;
|
|
98
105
|
|
|
99
106
|
let detachAbort: () => void = () => {};
|
|
100
107
|
|
|
101
108
|
const timer = setTimeout(() => {
|
|
102
|
-
this.pending.delete(requestId);
|
|
103
|
-
detachAbort();
|
|
104
109
|
pendingInteractions.resolve(requestId);
|
|
105
110
|
log.warn(
|
|
106
111
|
{ requestId, operation: input.operation },
|
|
107
112
|
"Host file proxy request timed out",
|
|
108
113
|
);
|
|
109
114
|
resolve({
|
|
110
|
-
content:
|
|
115
|
+
content: resolvedTargetClientId
|
|
116
|
+
? `Host file proxy timed out waiting for response from client '${resolvedTargetClientId}'`
|
|
117
|
+
: "Host file proxy timed out waiting for client response",
|
|
111
118
|
isError: true,
|
|
112
119
|
});
|
|
113
120
|
}, timeoutSec * 1000);
|
|
114
121
|
|
|
115
122
|
if (signal) {
|
|
116
123
|
const onAbort = () => {
|
|
117
|
-
if (
|
|
118
|
-
clearTimeout(timer);
|
|
119
|
-
this.pending.delete(requestId);
|
|
120
|
-
detachAbort();
|
|
124
|
+
if (pendingInteractions.get(requestId)) {
|
|
121
125
|
pendingInteractions.resolve(requestId);
|
|
122
126
|
try {
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
127
|
+
broadcastMessage(
|
|
128
|
+
{
|
|
129
|
+
type: "host_file_cancel",
|
|
130
|
+
requestId,
|
|
131
|
+
conversationId,
|
|
132
|
+
...(resolvedTargetClientId != null
|
|
133
|
+
? { targetClientId: resolvedTargetClientId }
|
|
134
|
+
: {}),
|
|
135
|
+
},
|
|
126
136
|
conversationId,
|
|
127
|
-
|
|
137
|
+
{ targetClientId: resolvedTargetClientId },
|
|
138
|
+
);
|
|
128
139
|
} catch {
|
|
129
|
-
// Best-effort cancel notification
|
|
140
|
+
// Best-effort cancel notification
|
|
130
141
|
}
|
|
131
142
|
resolve({ content: "Aborted", isError: true });
|
|
132
143
|
}
|
|
@@ -135,27 +146,34 @@ export class HostFileProxy {
|
|
|
135
146
|
detachAbort = () => signal.removeEventListener("abort", onAbort);
|
|
136
147
|
}
|
|
137
148
|
|
|
138
|
-
|
|
139
|
-
resolve,
|
|
140
|
-
reject,
|
|
141
|
-
timer,
|
|
142
|
-
operation: input.operation,
|
|
143
|
-
path: input.path,
|
|
149
|
+
pendingInteractions.register(requestId, {
|
|
144
150
|
conversationId,
|
|
151
|
+
kind: "host_file",
|
|
152
|
+
targetClientId: resolvedTargetClientId,
|
|
153
|
+
rpcResolve: resolve,
|
|
154
|
+
rpcReject: reject,
|
|
155
|
+
timer,
|
|
145
156
|
detachAbort,
|
|
157
|
+
metadata: { operation: input.operation, path: input.path },
|
|
146
158
|
});
|
|
147
159
|
|
|
148
160
|
try {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
161
|
+
broadcastMessage(
|
|
162
|
+
{
|
|
163
|
+
...input,
|
|
164
|
+
type: "host_file_request",
|
|
165
|
+
requestId,
|
|
166
|
+
conversationId,
|
|
167
|
+
// Always include in message body so the receiving client can verify
|
|
168
|
+
// which endpoint was targeted (even when auto-resolved).
|
|
169
|
+
...(resolvedTargetClientId != null
|
|
170
|
+
? { targetClientId: resolvedTargetClientId }
|
|
171
|
+
: {}),
|
|
172
|
+
},
|
|
153
173
|
conversationId,
|
|
154
|
-
|
|
174
|
+
{ targetClientId: resolvedTargetClientId },
|
|
175
|
+
);
|
|
155
176
|
} catch (err) {
|
|
156
|
-
clearTimeout(timer);
|
|
157
|
-
this.pending.delete(requestId);
|
|
158
|
-
detachAbort();
|
|
159
177
|
pendingInteractions.resolve(requestId);
|
|
160
178
|
log.warn(
|
|
161
179
|
{ requestId, operation: input.operation, err },
|
|
@@ -166,55 +184,61 @@ export class HostFileProxy {
|
|
|
166
184
|
});
|
|
167
185
|
}
|
|
168
186
|
|
|
187
|
+
/**
|
|
188
|
+
* Process a client result and resolve the RPC. Called by route handlers.
|
|
189
|
+
*/
|
|
169
190
|
resolve(
|
|
170
191
|
requestId: string,
|
|
171
192
|
response: { content: string; isError: boolean; imageData?: string },
|
|
172
193
|
): void {
|
|
173
|
-
const
|
|
174
|
-
if (!
|
|
194
|
+
const interaction = pendingInteractions.resolve(requestId);
|
|
195
|
+
if (!interaction?.rpcResolve) {
|
|
175
196
|
log.warn({ requestId }, "No pending host file request for response");
|
|
176
197
|
return;
|
|
177
198
|
}
|
|
178
|
-
|
|
179
|
-
entry.detachAbort();
|
|
180
|
-
this.pending.delete(requestId);
|
|
199
|
+
const meta = interaction.metadata ?? {};
|
|
181
200
|
if (
|
|
182
|
-
|
|
201
|
+
meta.operation === "read" &&
|
|
183
202
|
!response.isError &&
|
|
184
203
|
typeof response.imageData === "string" &&
|
|
185
204
|
response.imageData.length > 0
|
|
186
205
|
) {
|
|
187
|
-
|
|
206
|
+
interaction.rpcResolve(
|
|
207
|
+
readImageBase64(response.imageData, meta.path as string),
|
|
208
|
+
);
|
|
188
209
|
return;
|
|
189
210
|
}
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
return this.pending.has(requestId);
|
|
211
|
+
interaction.rpcResolve({
|
|
212
|
+
content: response.content,
|
|
213
|
+
isError: response.isError,
|
|
214
|
+
});
|
|
195
215
|
}
|
|
196
216
|
|
|
197
217
|
dispose(): void {
|
|
198
|
-
for (const
|
|
199
|
-
|
|
200
|
-
entry.detachAbort();
|
|
201
|
-
pendingInteractions.resolve(requestId);
|
|
218
|
+
for (const entry of pendingInteractions.getByKind("host_file")) {
|
|
219
|
+
pendingInteractions.resolve(entry.requestId);
|
|
202
220
|
try {
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
221
|
+
broadcastMessage(
|
|
222
|
+
{
|
|
223
|
+
type: "host_file_cancel",
|
|
224
|
+
requestId: entry.requestId,
|
|
225
|
+
conversationId: entry.conversationId,
|
|
226
|
+
...(entry.targetClientId != null
|
|
227
|
+
? { targetClientId: entry.targetClientId }
|
|
228
|
+
: {}),
|
|
229
|
+
},
|
|
230
|
+
entry.conversationId,
|
|
231
|
+
{ targetClientId: entry.targetClientId as string | undefined },
|
|
232
|
+
);
|
|
208
233
|
} catch {
|
|
209
|
-
// Best-effort cancel notification
|
|
234
|
+
// Best-effort cancel notification
|
|
210
235
|
}
|
|
211
|
-
entry.
|
|
236
|
+
entry.rpcReject?.(
|
|
212
237
|
new AssistantError(
|
|
213
238
|
"Host file proxy disposed",
|
|
214
239
|
ErrorCode.INTERNAL_ERROR,
|
|
215
240
|
),
|
|
216
241
|
);
|
|
217
242
|
}
|
|
218
|
-
this.pending.clear();
|
|
219
243
|
}
|
|
220
244
|
}
|