@vellumai/assistant 0.6.5 → 0.7.0
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/AGENTS.md +29 -1
- package/ARCHITECTURE.md +60 -53
- package/Dockerfile +25 -3
- package/README.md +8 -10
- package/__tests__/permissions/gateway-threshold-reader.test.ts +277 -0
- package/bun.lock +306 -119
- package/docs/architecture/integrations.md +32 -39
- package/docs/architecture/memory.md +26 -120
- package/docs/architecture/security.md +22 -36
- package/docs/browser-use-architecture-phase2.md +63 -20
- package/docs/credential-execution-service.md +7 -5
- package/docs/plugins.md +761 -0
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/README.md +132 -0
- package/examples/plugins/echo/bun.lock +25 -0
- package/examples/plugins/echo/package.json +17 -0
- package/examples/plugins/echo/register.ts +187 -0
- package/knip.json +8 -22
- package/node_modules/@vellumai/ces-client/bun.lock +33 -0
- package/node_modules/@vellumai/ces-client/package.json +25 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/ces-client.test.ts +631 -0
- package/node_modules/@vellumai/ces-client/src/__tests__/package-boundary.test.ts +138 -0
- package/node_modules/@vellumai/ces-client/src/credential-rpc.ts +13 -0
- package/node_modules/@vellumai/ces-client/src/http-credentials.ts +296 -0
- package/node_modules/@vellumai/ces-client/src/http-log-export.ts +111 -0
- package/node_modules/@vellumai/ces-client/src/index.ts +43 -0
- package/node_modules/@vellumai/ces-client/src/rpc-client.ts +445 -0
- package/node_modules/@vellumai/credential-storage/src/__tests__/package-boundary.test.ts +32 -6
- package/node_modules/@vellumai/egress-proxy/src/__tests__/package-boundary.test.ts +32 -1
- package/node_modules/@vellumai/egress-proxy/src/types.ts +19 -0
- package/node_modules/@vellumai/gateway-client/bun.lock +39 -0
- package/node_modules/@vellumai/gateway-client/package.json +23 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/gateway-client.test.ts +343 -0
- package/node_modules/@vellumai/gateway-client/src/__tests__/package-boundary.test.ts +140 -0
- package/node_modules/@vellumai/gateway-client/src/http-delivery.ts +422 -0
- package/node_modules/@vellumai/gateway-client/src/index.ts +35 -0
- package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +331 -0
- package/node_modules/@vellumai/gateway-client/src/types.ts +131 -0
- package/node_modules/@vellumai/gateway-client/tsconfig.json +20 -0
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/bun.lock +1 -1
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/package.json +4 -2
- package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/contracts.test.ts +5 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/package-boundary.test.ts +155 -0
- package/node_modules/@vellumai/service-contracts/src/credential-rpc.ts +23 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +25 -0
- package/node_modules/@vellumai/{ces-contracts/src/index.ts → service-contracts/src/transport.ts} +6 -28
- package/node_modules/@vellumai/service-contracts/src/trust-rules.ts +116 -0
- package/node_modules/@vellumai/service-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +891 -0
- package/node_modules/@vellumai/skill-host-contracts/bun.lock +24 -0
- package/node_modules/@vellumai/skill-host-contracts/package.json +18 -0
- package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +91 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +1348 -0
- package/node_modules/@vellumai/skill-host-contracts/src/index.ts +6 -0
- package/node_modules/@vellumai/skill-host-contracts/src/runtime-mode.ts +11 -0
- package/node_modules/@vellumai/skill-host-contracts/src/server-message.ts +32 -0
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +333 -0
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +444 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/tsconfig.test.json +12 -0
- package/openapi.yaml +3135 -692
- package/package.json +13 -7
- package/scripts/check-circular-deps.ts +80 -0
- package/scripts/generate-openapi.ts +24 -7
- package/{src/memory/graph/inspect.ts → scripts/memory-inspect.ts} +28 -28
- package/src/__tests__/access-request-decision.test.ts +2 -11
- package/src/__tests__/acp-session.test.ts +4 -150
- package/src/__tests__/actor-token-service.test.ts +17 -678
- package/src/__tests__/agent-loop-callsite-precedence.test.ts +2 -6
- package/src/__tests__/agent-loop-override-profile.test.ts +404 -0
- package/src/__tests__/agent-loop-thinking.test.ts +4 -4
- package/src/__tests__/agent-wake-override-profile.test.ts +261 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -1
- package/src/__tests__/anthropic-provider.test.ts +127 -15
- package/src/__tests__/app-compiler.test.ts +57 -0
- package/src/__tests__/app-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +10 -357
- package/src/__tests__/approval-conversation-turn.test.ts +3 -8
- package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
- package/src/__tests__/approval-primitive.test.ts +2 -1
- package/src/__tests__/approval-routes-http.test.ts +34 -451
- package/src/__tests__/assistant-events-sse-hardening.test.ts +73 -80
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -3
- package/src/__tests__/attachment-upload-trusted-source.test.ts +139 -0
- package/src/__tests__/attachments-store.test.ts +46 -1
- package/src/__tests__/audit-log-rotation.test.ts +2 -1
- package/src/__tests__/auto-analysis-end-to-end.test.ts +9 -20
- package/src/__tests__/avatar-generator.test.ts +4 -2
- package/src/__tests__/background-shell-bash.test.ts +227 -0
- package/src/__tests__/background-shell-host-bash.test.ts +474 -0
- package/src/__tests__/background-tool-registry.test.ts +145 -0
- package/src/__tests__/background-tool-routes.test.ts +175 -0
- package/src/__tests__/btw-routes.test.ts +147 -183
- package/src/__tests__/bundled-asset.test.ts +6 -6
- package/src/__tests__/call-controller.test.ts +15 -2
- package/src/__tests__/call-conversation-messages.test.ts +2 -1
- package/src/__tests__/call-domain.test.ts +2 -2
- package/src/__tests__/call-pointer-messages.test.ts +11 -13
- package/src/__tests__/call-recovery.test.ts +2 -1
- package/src/__tests__/call-routes-http.test.ts +3 -14
- package/src/__tests__/call-store.test.ts +2 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +31 -62
- package/src/__tests__/canonical-guardian-store.test.ts +2 -2
- package/src/__tests__/catalog-cache.test.ts +69 -0
- package/src/__tests__/catalog-files.test.ts +0 -26
- package/src/__tests__/ces-rpc-credential-backend.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +79 -49
- package/src/__tests__/channel-approval.test.ts +9 -7
- package/src/__tests__/channel-approvals.test.ts +9 -180
- package/src/__tests__/channel-delivery-store.test.ts +11 -10
- package/src/__tests__/channel-guardian.test.ts +14 -25
- package/src/__tests__/channel-readiness-service.test.ts +8 -6
- package/src/__tests__/channel-reply-delivery.test.ts +3 -19
- package/src/__tests__/channel-retry-sweep.test.ts +2 -5
- package/src/__tests__/checker.test.ts +447 -3806
- package/src/__tests__/circuit-breaker-pipeline.test.ts +406 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +208 -0
- package/src/__tests__/cli.test.ts +1 -38
- package/src/__tests__/compaction-events.test.ts +500 -0
- package/src/__tests__/compaction-pipeline.test.ts +210 -0
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +181 -0
- package/src/__tests__/compaction-timeout-recovery.test.ts +262 -0
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +109 -0
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +25 -203
- package/src/__tests__/config-watcher-cleanup-throttle.test.ts +0 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +4 -25
- package/src/__tests__/contact-store-user-file.test.ts +2 -1
- package/src/__tests__/contacts-tools.test.ts +71 -18
- package/src/__tests__/contacts-write.test.ts +6 -61
- package/src/__tests__/context-overflow-policy.test.ts +7 -7
- package/src/__tests__/context-search-agent-protocol.test.ts +230 -0
- package/src/__tests__/context-search-agent-runner.test.ts +998 -0
- package/src/__tests__/context-search-conversations-source.test.ts +320 -0
- package/src/__tests__/context-search-fanout.test.ts +380 -0
- package/src/__tests__/context-search-memory-source.test.ts +311 -0
- package/src/__tests__/context-search-pkb-source.test.ts +444 -0
- package/src/__tests__/context-search-types.test.ts +95 -0
- package/src/__tests__/context-search-workspace-source.test.ts +545 -0
- package/src/__tests__/context-window-manager.test.ts +380 -4
- package/src/__tests__/conversation-abort-tool-results.test.ts +14 -2
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +631 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +41 -32
- package/src/__tests__/conversation-agent-loop.test.ts +54 -143
- package/src/__tests__/conversation-analysis-routes.test.ts +60 -82
- package/src/__tests__/conversation-attachments.test.ts +9 -20
- package/src/__tests__/conversation-attention-store.test.ts +2 -1
- package/src/__tests__/conversation-attention-telegram.test.ts +4 -2
- package/src/__tests__/conversation-clear-safety.test.ts +53 -95
- package/src/__tests__/conversation-confirmation-signals.test.ts +7 -40
- package/src/__tests__/conversation-crud-inference-profile.test.ts +54 -0
- package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +63 -157
- package/src/__tests__/conversation-disk-view-integration.test.ts +2 -2
- package/src/__tests__/conversation-disk-view.test.ts +5 -4
- package/src/__tests__/conversation-fork-crud.test.ts +26 -55
- package/src/__tests__/conversation-fork-route.test.ts +5 -74
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +128 -0
- package/src/__tests__/conversation-inference-profile-route.test.ts +216 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +4 -95
- package/src/__tests__/conversation-key-store-disk-view.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +0 -1
- package/src/__tests__/conversation-list-source.test.ts +2 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +0 -1
- package/src/__tests__/conversation-pairing.test.ts +174 -11
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -294
- package/src/__tests__/conversation-process-callsite.test.ts +3 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +22 -8
- package/src/__tests__/conversation-queue.test.ts +30 -47
- package/src/__tests__/conversation-routes-disk-view.test.ts +131 -103
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +80 -55
- package/src/__tests__/conversation-routes-slash-commands.test.ts +83 -12
- package/src/__tests__/conversation-runtime-assembly.test.ts +196 -194
- package/src/__tests__/conversation-runtime-workspace.test.ts +23 -38
- package/src/__tests__/conversation-seed-composer.test.ts +2 -2
- package/src/__tests__/conversation-slash-commands.test.ts +6 -43
- package/src/__tests__/conversation-slash-queue.test.ts +7 -3
- package/src/__tests__/conversation-slash-unknown.test.ts +25 -3
- package/src/__tests__/conversation-speed-override.test.ts +6 -2
- package/src/__tests__/conversation-starter-routes.test.ts +177 -55
- package/src/__tests__/conversation-starters-cadence.test.ts +2 -2
- package/src/__tests__/conversation-store.test.ts +2 -375
- package/src/__tests__/conversation-title-service.test.ts +116 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +42 -3
- package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +6 -6
- package/src/__tests__/conversation-unread-route.test.ts +1 -1
- package/src/__tests__/conversation-usage.test.ts +3 -2
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +4 -2
- package/src/__tests__/conversation-workspace-injection.test.ts +3 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -2
- package/src/__tests__/conversations-defer-cli.test.ts +150 -0
- package/src/__tests__/credential-execution-admin-cli.test.ts +1 -1
- package/src/__tests__/credential-execution-api-key-propagation.test.ts +2 -2
- package/src/__tests__/credential-execution-approval-bridge.test.ts +22 -289
- package/src/__tests__/credential-execution-client.test.ts +1 -1
- package/src/__tests__/credential-execution-managed-contract.test.ts +1 -1
- package/src/__tests__/credential-health-service.test.ts +78 -9
- package/src/__tests__/credential-security-invariants.test.ts +16 -2
- package/src/__tests__/credentials-cli.test.ts +45 -21
- package/src/__tests__/daemon-credential-client.test.ts +23 -108
- package/src/__tests__/db-acp-history.test.ts +284 -0
- package/src/__tests__/db-activation-state.test.ts +240 -0
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +2 -1
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +248 -0
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +2 -1
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +116 -0
- package/src/__tests__/db-rename-inference-profile-snake-case-migration.test.ts +132 -0
- package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
- package/src/__tests__/delete-propagation.test.ts +3 -2
- package/src/__tests__/deterministic-verification-control-plane.test.ts +39 -32
- package/src/__tests__/dm-backfill.test.ts +3 -2
- package/src/__tests__/edit-propagation.test.ts +5 -7
- package/src/__tests__/embedding-managed-proxy-selection.test.ts +1 -1
- package/src/__tests__/empty-response-pipeline.test.ts +305 -0
- package/src/__tests__/events-client-registration.test.ts +297 -0
- package/src/__tests__/file-write-tool.test.ts +2 -4
- package/src/__tests__/filing-service.test.ts +144 -17
- package/src/__tests__/first-greeting.test.ts +247 -5
- package/src/__tests__/followup-tools.test.ts +2 -1
- package/src/__tests__/gateway-client-managed-outbound.test.ts +8 -12
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -6
- package/src/__tests__/gateway-only-guard.test.ts +4 -3
- package/src/__tests__/gemini-provider.test.ts +276 -10
- package/src/__tests__/graph-extraction-event-date.test.ts +30 -0
- package/src/__tests__/guardian-action-conversation-turn.test.ts +2 -1
- package/src/__tests__/guardian-action-followup-executor.test.ts +2 -2
- package/src/__tests__/guardian-action-followup-store.test.ts +2 -1
- package/src/__tests__/guardian-action-grant-mint-consume.test.ts +9 -9
- package/src/__tests__/guardian-action-late-reply.test.ts +2 -1
- package/src/__tests__/guardian-action-store.test.ts +2 -1
- package/src/__tests__/guardian-action-sweep.test.ts +9 -8
- package/src/__tests__/guardian-binding-drift-heal.test.ts +2 -1
- package/src/__tests__/guardian-decision-primitive-canonical.test.ts +21 -118
- package/src/__tests__/guardian-dispatch.test.ts +14 -11
- package/src/__tests__/guardian-grant-minting.test.ts +9 -15
- package/src/__tests__/guardian-outbound-http.test.ts +71 -106
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +2 -2
- package/src/__tests__/guardian-routing-invariants.test.ts +34 -90
- package/src/__tests__/guardian-routing-state.test.ts +14 -22
- package/src/__tests__/guardian-verification-voice-binding.test.ts +1 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +253 -0
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +8 -4
- package/src/__tests__/headless-browser-mode.test.ts +57 -0
- package/src/__tests__/heartbeat-service.test.ts +39 -21
- package/src/__tests__/helpers/call-route-handler.ts +72 -0
- package/src/__tests__/helpers/channel-test-adapter.ts +161 -0
- package/src/__tests__/helpers/gateway-classify-mock.ts +67 -0
- package/src/__tests__/helpers/mock-logger.ts +36 -0
- package/src/__tests__/history-repair-pipeline.test.ts +399 -0
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-browser-e2e-cloud.test.ts +309 -1
- package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +12 -2
- package/src/__tests__/host-browser-routes.test.ts +36 -91
- package/src/__tests__/host-browser-ws-events-e2e.test.ts +10 -2
- package/src/__tests__/host-proxy-interface.test.ts +38 -4
- package/src/__tests__/host-shell-tool.test.ts +2 -4
- package/src/__tests__/host-transfer-pending-interactions.test.ts +160 -0
- package/src/__tests__/host-transfer-proxy.test.ts +733 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +20 -11
- package/src/__tests__/image-credentials.test.ts +137 -0
- package/src/__tests__/image-service-dispatcher.test.ts +186 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/injector-chain.test.ts +525 -0
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -206
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- package/src/__tests__/intent-routing.test.ts +0 -26
- package/src/__tests__/invite-redemption-service.test.ts +2 -1
- package/src/__tests__/invite-routes-http.test.ts +80 -12
- package/src/__tests__/jobs-store-qdrant-breaker.test.ts +2 -1
- package/src/__tests__/jobs-store-upsert-debounced.test.ts +2 -1
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +157 -0
- package/src/__tests__/list-messages-attachments.test.ts +52 -55
- package/src/__tests__/list-messages-page-latest.test.ts +283 -0
- package/src/__tests__/list-messages-tool-merge.test.ts +16 -17
- package/src/__tests__/llm-call-pipeline.test.ts +284 -0
- package/src/__tests__/llm-context-normalization.test.ts +69 -4
- package/src/__tests__/llm-context-route-provider.test.ts +39 -113
- package/src/__tests__/llm-request-log-turn-query.test.ts +2 -1
- package/src/__tests__/llm-resolver.test.ts +211 -0
- package/src/__tests__/llm-schema.test.ts +56 -0
- package/src/__tests__/llm-usage-store.test.ts +2 -1
- package/src/__tests__/log-export-workspace.test.ts +28 -17
- package/src/__tests__/mcp-abort-signal.test.ts +2 -3
- package/src/__tests__/mcp-client-auth.test.ts +2 -3
- package/src/__tests__/media-generate-image.test.ts +119 -13
- package/src/__tests__/memory-admin-recall.test.ts +221 -0
- package/src/__tests__/memory-recall-log-store.test.ts +2 -1
- package/src/__tests__/memory-retrieval-pipeline.test.ts +399 -0
- package/src/__tests__/memory-upsert-concurrency.test.ts +3 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +14 -13
- package/src/__tests__/migration-export-http.test.ts +17 -17
- package/src/__tests__/migration-export-to-gcs.test.ts +491 -0
- package/src/__tests__/migration-import-commit-http.test.ts +16 -16
- package/src/__tests__/migration-import-from-gcs.test.ts +533 -0
- package/src/__tests__/migration-import-from-url.test.ts +21 -91
- package/src/__tests__/migration-import-preflight-http.test.ts +13 -13
- package/src/__tests__/migration-jobs-status.test.ts +164 -0
- package/src/__tests__/migration-validate-http.test.ts +48 -83
- package/src/__tests__/mock-gateway-ipc.ts +32 -62
- package/src/__tests__/model-intents.test.ts +16 -1
- package/src/__tests__/nl-approval-parser.test.ts +13 -17
- package/src/__tests__/non-member-access-request.test.ts +13 -5
- package/src/__tests__/notification-broadcaster.test.ts +3 -3
- package/src/__tests__/notification-decision-strategy.test.ts +0 -11
- package/src/__tests__/notification-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +109 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +77 -123
- package/src/__tests__/oauth-cli.test.ts +28 -13
- package/src/__tests__/oauth-connect-orchestrator.test.ts +4 -13
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-serializer.test.ts +6 -4
- package/src/__tests__/oauth-provider-visibility.test.ts +6 -6
- package/src/__tests__/oauth-providers-routes.test.ts +81 -103
- package/src/__tests__/oauth-store.test.ts +44 -77
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- package/src/__tests__/onboarding-template-contract.test.ts +16 -64
- package/src/__tests__/openai-image-service.test.ts +368 -0
- package/src/__tests__/openai-provider.test.ts +105 -6
- package/src/__tests__/openai-responses-provider.test.ts +146 -4
- package/src/__tests__/openrouter-provider-only.test.ts +22 -4
- package/src/__tests__/overflow-reduce-pipeline.test.ts +671 -0
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persist-onboarding-artifacts.test.ts +266 -0
- package/src/__tests__/persistence-pipeline.test.ts +378 -0
- package/src/__tests__/pipeline-runner.test.ts +565 -0
- package/src/__tests__/platform-bash-auto-approve.test.ts +27 -20
- package/src/__tests__/platform.test.ts +10 -59
- package/src/__tests__/playbook-execution.test.ts +2 -1
- package/src/__tests__/playbook-tools.test.ts +2 -1
- package/src/__tests__/plugin-bootstrap.test.ts +529 -0
- package/src/__tests__/plugin-registry.test.ts +303 -0
- package/src/__tests__/plugin-route-contribution.test.ts +294 -0
- package/src/__tests__/plugin-skill-contribution.test.ts +367 -0
- package/src/__tests__/plugin-tool-contribution.test.ts +292 -0
- package/src/__tests__/plugin-types.test.ts +320 -0
- package/src/__tests__/pricing.test.ts +195 -14
- package/src/__tests__/profiler-routes.test.ts +112 -177
- package/src/__tests__/provider-send-message-override-profile.test.ts +223 -0
- package/src/__tests__/proxy-approval-callback.test.ts +6 -493
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +4 -2
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +0 -2
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +1 -2
- package/src/__tests__/relay-server.test.ts +19 -4
- package/src/__tests__/require-fresh-approval.test.ts +19 -168
- package/src/__tests__/resolve-trust-class.test.ts +2 -1
- package/src/__tests__/retry-thinking-tool-choice.test.ts +19 -7
- package/src/__tests__/retry-verbosity-normalization.test.ts +139 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +26 -6
- package/src/__tests__/runtime-events-sse-parity.test.ts +12 -13
- package/src/__tests__/runtime-events-sse.test.ts +13 -21
- package/src/__tests__/schedule-routes.test.ts +304 -77
- package/src/__tests__/schedule-store.test.ts +119 -1
- package/src/__tests__/schedule-tools.test.ts +2 -1
- package/src/__tests__/scheduler-recurrence.test.ts +16 -71
- package/src/__tests__/scheduler-reuse-conversation.test.ts +12 -51
- package/src/__tests__/scheduler-wake.test.ts +356 -0
- package/src/__tests__/scoped-approval-grants.test.ts +2 -1
- package/src/__tests__/scoped-grant-security-matrix.test.ts +2 -1
- package/src/__tests__/secret-detection-handler.test.ts +2 -19
- package/src/__tests__/secret-ingress-http.test.ts +38 -21
- package/src/__tests__/secret-routes-managed-proxy.test.ts +46 -102
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +38 -25
- package/src/__tests__/sequence-store.test.ts +2 -1
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/service-contracts-import-guard.test.ts +185 -0
- package/src/__tests__/set-permission-mode.test.ts +0 -10
- package/src/__tests__/settings-routes.test.ts +35 -68
- package/src/__tests__/skill-boundary-guard.test.ts +105 -0
- package/src/__tests__/skill-load-inline-command.test.ts +2 -2
- package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
- package/src/__tests__/skill-runtime-path.test.ts +64 -0
- package/src/__tests__/skills-file-content-endpoint.test.ts +0 -2
- package/src/__tests__/slack-inbound-verification.test.ts +11 -2
- package/src/__tests__/slack-messaging-token-resolution.test.ts +1 -3
- package/src/__tests__/slack-reaction-approvals.test.ts +4 -4
- package/src/__tests__/slack-share-routes.test.ts +37 -72
- package/src/__tests__/subagent-call-site-routing.test.ts +79 -0
- package/src/__tests__/subagent-fork-spawn.test.ts +20 -28
- package/src/__tests__/subagent-notify-parent.test.ts +6 -29
- package/src/__tests__/subagent-role-registry.test.ts +3 -3
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +52 -104
- package/src/__tests__/subagent-tools.test.ts +0 -1
- package/src/__tests__/suggestion-routes.test.ts +149 -57
- package/src/__tests__/task-compiler.test.ts +2 -1
- package/src/__tests__/task-management-tools.test.ts +2 -1
- package/src/__tests__/task-memory-cleanup.test.ts +3 -1
- package/src/__tests__/task-scheduler.test.ts +5 -16
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +5 -314
- package/src/__tests__/thread-backfill.test.ts +3 -2
- package/src/__tests__/title-generate-pipeline.test.ts +224 -0
- package/src/__tests__/token-estimate-pipeline.test.ts +484 -0
- package/src/__tests__/tool-approval-handler.test.ts +21 -63
- package/src/__tests__/tool-audit-listener.test.ts +3 -3
- package/src/__tests__/tool-domain-event-publisher.test.ts +3 -3
- package/src/__tests__/tool-error-pipeline.test.ts +244 -0
- package/src/__tests__/tool-execute-pipeline.test.ts +429 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +61 -4
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +28 -56
- package/src/__tests__/tool-executor.test.ts +434 -1604
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +356 -0
- package/src/__tests__/tool-result-truncation.test.ts +0 -110
- package/src/__tests__/trust-context-guards.test.ts +1 -1
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +7 -15
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +178 -354
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +3 -2
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -2
- package/src/__tests__/trusted-contact-verification.test.ts +2 -1
- package/src/__tests__/turn-boundary-resolution.test.ts +2 -1
- package/src/__tests__/twilio-routes.test.ts +25 -66
- package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -7
- package/src/__tests__/usage-routes.test.ts +73 -90
- package/src/__tests__/user-plugin-loader.test.ts +233 -0
- package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +2 -2
- package/src/__tests__/verification-control-plane-policy.test.ts +95 -14
- package/src/__tests__/voice-ingress-preflight.test.ts +5 -5
- package/src/__tests__/voice-invite-redemption.test.ts +2 -1
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +3 -3
- package/src/__tests__/voice-session-bridge.test.ts +285 -106
- package/src/__tests__/volume-security-guard.test.ts +0 -2
- package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +3 -1
- package/src/__tests__/workspace-migration-028-recover-conversations-from-disk-view.test.ts +2 -1
- package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +1 -1
- package/src/__tests__/workspace-migration-046-seed-conversation-starters-callsite.test.ts +185 -0
- package/src/__tests__/workspace-migration-049-release-notes-default-sonnet.test.ts +100 -0
- package/src/__tests__/workspace-migration-050-seed-main-agent-opus-callsite.test.ts +171 -0
- package/src/__tests__/workspace-migration-051-seed-conversation-summarization-callsite.test.ts +252 -0
- package/src/__tests__/workspace-migration-052-seed-default-inference-profiles.test.ts +260 -0
- package/src/__tests__/workspace-migration-053-release-notes-acp-codex.test.ts +225 -0
- package/src/__tests__/workspace-migration-054-seed-recall-callsite.test.ts +235 -0
- package/src/__tests__/workspace-migration-055-release-notes-agentic-recall.test.ts +128 -0
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +232 -0
- package/src/__tests__/workspace-migration-acp-sessions-ui.test.ts +144 -0
- package/src/__tests__/workspace-migration-drop-user-md.test.ts +1 -1
- package/src/__tests__/workspace-migration-memory-v2-init.test.ts +274 -0
- package/src/__tests__/workspace-migration-remove-hooks.test.ts +99 -0
- package/src/__tests__/workspace-policy.test.ts +21 -3
- package/src/acp/__tests__/client-handler.test.ts +64 -0
- package/src/acp/__tests__/helpers/acp-config-stub.ts +62 -0
- package/src/acp/__tests__/helpers/which-stub.ts +45 -0
- package/src/acp/__tests__/session-manager-persistence.test.ts +366 -0
- package/src/acp/__tests__/session-manager-startup.test.ts +159 -0
- package/src/acp/__tests__/session-manager.test.ts +83 -0
- package/src/acp/client-handler.ts +23 -139
- package/src/acp/resolve-agent.test.ts +291 -0
- package/src/acp/resolve-agent.ts +176 -0
- package/src/acp/session-manager.ts +166 -7
- package/src/acp/types.ts +2 -50
- package/src/agent/loop.ts +365 -104
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +296 -0
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +109 -103
- package/src/avatar/character-components.ts +6 -6
- package/src/{config/bundled-skills/settings/tools → avatar}/identity-avatar.ts +1 -1
- package/src/backup/__tests__/backup-worker.test.ts +2 -15
- package/src/backup/__tests__/paths.test.ts +3 -2
- package/src/backup/backup-worker.ts +3 -24
- package/src/backup/paths.ts +2 -18
- package/src/backup/restore.ts +7 -11
- package/src/browser/__tests__/operations.test.ts +0 -35
- package/src/browser/operations.ts +1 -47
- package/src/bundler/app-compiler.ts +84 -1
- package/src/bundler/package-resolver.ts +2 -6
- package/src/calls/active-call-lease.ts +1 -1
- package/src/calls/call-constants.ts +1 -1
- package/src/calls/call-controller.ts +1 -5
- package/src/calls/call-domain.ts +14 -14
- package/src/calls/call-pointer-messages.ts +4 -9
- package/src/calls/call-state.ts +2 -2
- package/src/calls/call-store.ts +2 -1
- package/src/calls/guardian-action-sweep.ts +9 -25
- package/src/calls/guardian-dispatch.ts +1 -20
- package/src/calls/media-stream-audio-transcode.ts +2 -41
- package/src/calls/media-stream-server.ts +2 -3
- package/src/calls/media-stream-stt-session.ts +1 -3
- package/src/calls/relay-access-wait.ts +5 -8
- package/src/calls/relay-server.ts +15 -18
- package/src/calls/relay-setup-router.ts +2 -2
- package/src/calls/relay-verification.ts +4 -4
- package/src/calls/twilio-rest.ts +1 -1
- package/src/calls/twilio-routes.ts +160 -78
- package/src/calls/voice-control-protocol.ts +10 -10
- package/src/calls/voice-ingress-preflight.ts +2 -2
- package/src/calls/voice-session-bridge.ts +137 -42
- package/src/channels/__tests__/types.test.ts +28 -6
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +48 -30
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +92 -214
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +4 -15
- package/src/cli/commands/__tests__/browser.test.ts +36 -31
- package/src/cli/commands/__tests__/cache.test.ts +23 -18
- package/src/cli/commands/__tests__/image-generation.test.ts +255 -35
- package/src/cli/commands/__tests__/inference-send.test.ts +12 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +396 -0
- package/src/cli/commands/__tests__/task.test.ts +36 -35
- package/src/cli/commands/__tests__/trust.test.ts +602 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +12 -0
- package/src/cli/commands/__tests__/ui-confirm.test.ts +14 -14
- package/src/cli/commands/__tests__/ui.test.ts +17 -17
- package/src/cli/commands/__tests__/watchers.test.ts +29 -29
- package/src/cli/commands/__tests__/webhooks.test.ts +544 -0
- package/src/cli/commands/attachment.ts +12 -8
- package/src/cli/commands/auth.ts +1 -1
- package/src/cli/commands/avatar.ts +192 -9
- package/src/cli/commands/backup.ts +16 -46
- package/src/cli/commands/browser.ts +52 -4
- package/src/cli/commands/cache.ts +7 -5
- package/src/cli/commands/channel-verification-sessions.ts +6 -6
- package/src/cli/commands/clients.ts +137 -0
- package/src/cli/commands/completions.ts +3 -10
- package/src/cli/commands/contacts.ts +10 -10
- package/src/cli/commands/conversations-defer.ts +364 -0
- package/src/cli/commands/conversations-import.ts +2 -3
- package/src/cli/commands/conversations.ts +115 -57
- package/src/cli/commands/credential-execution.ts +1 -1
- package/src/cli/commands/credentials.ts +139 -5
- package/src/cli/commands/default-action.ts +1 -1
- package/src/cli/commands/domain.ts +2 -2
- package/src/cli/commands/email.ts +7 -7
- package/src/cli/commands/image-generation.ts +33 -34
- package/src/cli/commands/keys.ts +2 -2
- package/src/cli/commands/mcp.ts +1 -1
- package/src/cli/commands/memory-v2.ts +343 -0
- package/src/cli/commands/memory.ts +8 -8
- package/src/cli/commands/notifications.ts +87 -121
- package/src/cli/commands/oauth/__tests__/connect.test.ts +23 -5
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/mode.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +4 -4
- package/src/cli/commands/oauth/providers.ts +176 -8
- package/src/cli/commands/oauth/shared.ts +29 -2
- package/src/cli/commands/oauth/status.ts +46 -36
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -6
- package/src/cli/commands/platform/__tests__/connect.test.ts +23 -11
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +22 -10
- package/src/cli/commands/platform/__tests__/status.test.ts +22 -10
- package/src/cli/commands/platform/connect.ts +3 -3
- package/src/cli/commands/platform/disconnect.ts +4 -6
- package/src/cli/commands/platform/index.ts +12 -10
- package/src/cli/commands/routes.ts +7 -1
- package/src/cli/commands/sequence.ts +7 -7
- package/src/cli/commands/skills.ts +189 -84
- package/src/cli/commands/task.ts +12 -10
- package/src/cli/commands/trust.ts +460 -162
- package/src/cli/commands/ui.ts +3 -3
- package/src/cli/commands/usage.ts +10 -5
- package/src/cli/commands/watchers.ts +8 -8
- package/src/cli/commands/webhooks.ts +270 -0
- package/src/cli/lib/daemon-avatar-client.ts +37 -0
- package/src/cli/lib/daemon-credential-client.ts +27 -189
- package/src/cli/lib/ipc-params.ts +22 -0
- package/src/cli/program.ts +29 -29
- package/src/cli.ts +1 -61
- package/src/config/__tests__/backup-schema.test.ts +7 -2
- package/src/config/acp-defaults.test.ts +57 -0
- package/src/config/acp-defaults.ts +40 -0
- package/src/config/acp-schema.ts +1 -1
- package/src/config/assistant-feature-flags.ts +18 -142
- package/src/config/bundled-skills/acp/SKILL.md +44 -16
- package/src/config/bundled-skills/acp/TOOLS.json +45 -1
- package/src/config/bundled-skills/{screen-watch/tools/start-screen-watch.ts → acp/tools/acp-list-agents.ts} +2 -2
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/references/WIDGETS.md +10 -10
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +66 -87
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +25 -51
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +31 -44
- package/src/config/bundled-skills/image-studio/SKILL.md +2 -1
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -1
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +23 -39
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +6 -6
- package/src/config/bundled-skills/media-processing/services/reduce.ts +0 -13
- package/src/config/bundled-skills/messaging/SKILL.md +3 -3
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +207 -0
- package/src/config/bundled-skills/messaging/tools/gmail-mime-helpers.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +12 -0
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +58 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +1 -1
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +1 -1
- package/src/config/bundled-skills/schedule/SKILL.md +8 -3
- package/src/config/bundled-skills/schedule/TOOLS.json +15 -7
- package/src/config/bundled-skills/schedule/references/SCRIPT_MODE_PATTERNS.md +59 -0
- package/src/config/bundled-skills/settings/SKILL.md +2 -17
- package/src/config/bundled-skills/settings/TOOLS.json +0 -56
- package/src/config/bundled-skills/subagent/SKILL.md +2 -0
- package/src/config/bundled-tool-registry.ts +4 -21
- package/src/config/env.ts +7 -8
- package/src/config/feature-flag-registry.json +25 -17
- package/src/config/llm-resolver.ts +51 -33
- package/src/config/loader.ts +12 -15
- package/src/config/schema.ts +22 -70
- package/src/config/schemas/__tests__/filing.test.ts +58 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +186 -0
- package/src/config/schemas/backup.ts +1 -1
- package/src/config/schemas/conversations.ts +16 -0
- package/src/config/schemas/filing.ts +12 -0
- package/src/config/schemas/host-browser.ts +2 -2
- package/src/config/schemas/inference.ts +0 -2
- package/src/config/schemas/ingress.ts +1 -1
- package/src/config/schemas/llm.ts +51 -10
- package/src/config/schemas/memory-storage.ts +1 -1
- package/src/config/schemas/memory-v2.ts +176 -0
- package/src/config/schemas/memory.ts +2 -0
- package/src/config/schemas/security.ts +0 -60
- package/src/config/schemas/services.ts +46 -7
- package/src/config/schemas/tts.ts +11 -0
- package/src/config/skill-state.ts +6 -2
- package/src/config/skills.ts +95 -6
- package/src/config/types.ts +0 -41
- package/src/contacts/contact-store.ts +2 -2
- package/src/contacts/contacts-write.ts +0 -38
- package/src/contacts/types.ts +8 -10
- package/src/context/__tests__/compact-prompt.test.ts +27 -9
- package/src/context/prompts/compact.md +26 -12
- package/src/context/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +4 -64
- package/src/context/window-manager.ts +191 -17
- package/src/credential-execution/approval-bridge.ts +7 -69
- package/src/credential-execution/client.ts +17 -422
- package/src/credential-execution/feature-gates.ts +1 -2
- package/src/credential-execution/managed-catalog.ts +1 -1
- package/src/credential-health/credential-health-service.ts +20 -7
- package/src/daemon/__tests__/conversation-feed-event.test.ts +304 -0
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +4 -12
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +14 -15
- package/src/daemon/__tests__/daemon-skill-host.test.ts +272 -0
- package/src/daemon/__tests__/meet-host-supervisor.test.ts +587 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +463 -0
- package/src/daemon/approval-generators.ts +2 -14
- package/src/daemon/classifier.ts +0 -106
- package/src/daemon/config-watcher.ts +14 -56
- package/src/daemon/connection-policy.ts +0 -14
- package/src/daemon/context-overflow-policy.ts +4 -13
- package/src/daemon/conversation-agent-loop-handlers.ts +120 -28
- package/src/daemon/conversation-agent-loop.ts +1113 -701
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +11 -20
- package/src/daemon/conversation-launch.ts +1 -1
- package/src/daemon/conversation-lifecycle.ts +37 -19
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-notifiers.ts +3 -111
- package/src/daemon/conversation-process.ts +23 -20
- package/src/daemon/conversation-runtime-assembly.ts +530 -471
- package/src/daemon/conversation-slash.ts +4 -160
- package/src/daemon/conversation-store.ts +368 -0
- package/src/daemon/conversation-surfaces.ts +5 -4
- package/src/daemon/conversation-tool-setup.ts +49 -161
- package/src/daemon/conversation.ts +126 -217
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/daemon-skill-host.ts +262 -0
- package/src/daemon/external-plugins-bootstrap.ts +532 -0
- package/src/daemon/first-greeting.ts +191 -14
- package/src/daemon/handlers/config-channels.ts +2 -2
- package/src/daemon/handlers/config-embeddings.ts +1 -1
- package/src/daemon/handlers/config-ingress.ts +24 -2
- package/src/daemon/handlers/config-model.test.ts +17 -0
- package/src/daemon/handlers/config-model.ts +18 -52
- package/src/daemon/handlers/config-telegram.ts +6 -53
- package/src/daemon/handlers/config-voice.ts +1 -1
- package/src/daemon/handlers/conversations.ts +22 -156
- package/src/daemon/handlers/recording.ts +1 -1
- package/src/daemon/handlers/shared.ts +34 -35
- package/src/daemon/handlers/skills.ts +20 -24
- package/src/daemon/host-transfer-proxy.ts +500 -0
- package/src/daemon/lifecycle.ts +56 -326
- package/src/daemon/meet-host-startup.ts +51 -0
- package/src/daemon/meet-host-supervisor.ts +781 -0
- package/src/daemon/meet-manifest-loader.ts +410 -0
- package/src/daemon/memory-v2-startup.ts +35 -0
- package/src/daemon/message-protocol.ts +4 -7
- package/src/daemon/message-types/acp.ts +1 -0
- package/src/daemon/message-types/computer-use.ts +2 -34
- package/src/daemon/message-types/conversations.ts +65 -2
- package/src/daemon/message-types/host-transfer.ts +41 -0
- package/src/daemon/message-types/integrations.ts +6 -0
- package/src/daemon/message-types/messages.ts +26 -14
- package/src/daemon/message-types/schedules.ts +1 -0
- package/src/daemon/message-types/settings.ts +0 -6
- package/src/daemon/message-types/shared.ts +5 -2
- package/src/daemon/message-types/subagents.ts +2 -1
- package/src/daemon/message-types/workspace.ts +0 -2
- package/src/daemon/pkb-reminder-builder.test.ts +13 -12
- package/src/daemon/pkb-reminder-builder.ts +8 -16
- package/src/daemon/process-message.ts +616 -0
- package/src/daemon/providers-setup.ts +14 -6
- package/src/daemon/server.ts +79 -1272
- package/src/daemon/shutdown-handlers.ts +3 -13
- package/src/daemon/startup-error.ts +1 -1
- package/src/daemon/tool-side-effects.ts +14 -56
- package/src/daemon/trust-context.ts +32 -0
- package/src/daemon/wake-target-adapter.ts +223 -0
- package/src/email/feature-gate.ts +1 -1
- package/src/events/domain-events.ts +1 -8
- package/src/events/tool-audit-listener.ts +2 -8
- package/src/events/tool-metrics-listener.ts +1 -4
- package/src/filing/filing-service.ts +194 -54
- package/src/followups/followup-store.ts +3 -71
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +228 -0
- package/src/heartbeat/heartbeat-service.ts +52 -8
- package/src/home/__tests__/feed-population-integration.test.ts +312 -0
- package/src/home/__tests__/phase5-exit-criteria.test.ts +18 -1
- package/src/home/__tests__/rollup-producer.test.ts +67 -2
- package/src/home/assistant-feed-authoring.ts +8 -1
- package/src/home/emit-feed-event.ts +7 -0
- package/src/home/feed-types.ts +42 -3
- package/src/home/relationship-state-writer.ts +1 -1
- package/src/home/rewrite-command-preview.ts +66 -0
- package/src/home/rewrite-feed-title.ts +58 -0
- package/src/home/rollup-producer.ts +16 -3
- package/src/inbound/platform-callback-registration.ts +1 -17
- package/src/ipc/__tests__/attachment-ipc.test.ts +128 -66
- package/src/ipc/__tests__/browser-ipc.test.ts +75 -51
- package/src/ipc/__tests__/cache-ipc.test.ts +52 -107
- package/src/ipc/__tests__/cli-ipc.test.ts +9 -6
- package/src/ipc/__tests__/skill-server-bidirectional.test.ts +254 -0
- package/src/ipc/__tests__/skill-server.test.ts +182 -0
- package/src/ipc/__tests__/socket-path.test.ts +44 -37
- package/src/ipc/__tests__/ui-request-route.test.ts +241 -216
- package/src/ipc/__tests__/watcher-ipc.test.ts +33 -33
- package/src/ipc/assistant-server.ts +450 -0
- package/src/ipc/cli-client.ts +3 -3
- package/src/ipc/gateway-client.test.ts +131 -0
- package/src/ipc/gateway-client.ts +98 -120
- package/src/ipc/ipc-framing.ts +281 -0
- package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +152 -0
- package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +219 -0
- package/src/ipc/routes/db-proxy.ts +73 -0
- package/src/ipc/routes/route-adapter.ts +32 -0
- package/src/ipc/routes/trust-rules.test.ts +218 -0
- package/src/ipc/skill-ipc-types.ts +13 -0
- package/src/ipc/skill-routes/__tests__/config.test.ts +146 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +402 -0
- package/src/ipc/skill-routes/__tests__/identity.test.ts +81 -0
- package/src/ipc/skill-routes/__tests__/log.test.ts +133 -0
- package/src/ipc/skill-routes/__tests__/memory.test.ts +178 -0
- package/src/ipc/skill-routes/__tests__/platform.test.ts +111 -0
- package/src/ipc/skill-routes/__tests__/providers.test.ts +265 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +361 -0
- package/src/ipc/skill-routes/config.ts +47 -0
- package/src/ipc/skill-routes/events.ts +131 -0
- package/src/ipc/skill-routes/identity.ts +34 -0
- package/src/ipc/skill-routes/index.ts +37 -0
- package/src/ipc/skill-routes/log.ts +40 -0
- package/src/ipc/skill-routes/memory.ts +76 -0
- package/src/ipc/skill-routes/platform.ts +39 -0
- package/src/ipc/skill-routes/providers.ts +163 -0
- package/src/ipc/skill-routes/registries.ts +393 -0
- package/src/ipc/skill-server.ts +771 -0
- package/src/ipc/skill-socket-path.ts +20 -0
- package/src/ipc/socket-cleanup.ts +92 -0
- package/src/ipc/socket-path.ts +55 -48
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +374 -0
- package/src/live-voice/__tests__/live-voice-archive.test.ts +525 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +473 -0
- package/src/live-voice/__tests__/live-voice-integration.test.ts +359 -0
- package/src/live-voice/__tests__/live-voice-metrics.test.ts +179 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +349 -0
- package/src/live-voice/__tests__/live-voice-stt.test.ts +244 -0
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +337 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +337 -0
- package/src/live-voice/__tests__/protocol.test.ts +295 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +421 -0
- package/src/live-voice/live-voice-archive.ts +758 -0
- package/src/live-voice/live-voice-metrics.ts +472 -0
- package/src/live-voice/live-voice-session-manager.ts +222 -0
- package/src/live-voice/live-voice-session.ts +1144 -0
- package/src/live-voice/live-voice-tts.ts +260 -0
- package/src/live-voice/protocol.ts +524 -0
- package/src/mcp/client.ts +2 -2
- package/src/media/app-icon-generator.ts +23 -46
- package/src/media/avatar-router.ts +26 -41
- package/src/media/gemini-image-service.ts +8 -41
- package/src/media/image-credentials.ts +73 -0
- package/src/media/image-service.ts +85 -0
- package/src/media/openai-image-service.ts +131 -0
- package/src/media/types.ts +46 -0
- package/src/memory/__tests__/auto-analysis-enqueue.test.ts +4 -28
- package/src/memory/__tests__/auto-analysis-guard.test.ts +2 -2
- package/src/memory/__tests__/conversation-analyze-job.test.ts +7 -62
- package/src/memory/__tests__/conversation-group-migration.test.ts +2 -2
- package/src/memory/__tests__/find-analysis-conversation.test.ts +2 -1
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +235 -0
- package/src/memory/admin.ts +65 -7
- package/src/memory/app-git-service.ts +0 -14
- package/src/memory/attachments-store.ts +14 -16
- package/src/memory/auto-analysis-enqueue.ts +2 -17
- package/src/memory/canonical-guardian-store.ts +2 -1
- package/src/memory/channel-verification-sessions.ts +1 -1
- package/src/memory/checkpoints.ts +1 -1
- package/src/memory/context-search/agent-protocol.ts +424 -0
- package/src/memory/context-search/agent-runner.ts +1295 -0
- package/src/memory/context-search/format.ts +160 -0
- package/src/memory/context-search/limits.ts +106 -0
- package/src/memory/context-search/search.ts +387 -0
- package/src/memory/context-search/sources/conversations.ts +278 -0
- package/src/memory/context-search/sources/memory.ts +90 -0
- package/src/memory/context-search/sources/pkb.ts +468 -0
- package/src/memory/context-search/sources/workspace.ts +1255 -0
- package/src/memory/context-search/types.ts +49 -0
- package/src/memory/conversation-analyze-job.ts +3 -24
- package/src/memory/conversation-attention-store.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +1 -1
- package/src/memory/conversation-crud.ts +117 -145
- package/src/memory/conversation-directories.ts +1 -11
- package/src/memory/conversation-display-order-migration.ts +11 -2
- package/src/memory/conversation-group-migration.ts +20 -4
- package/src/memory/conversation-key-store.ts +3 -4
- package/src/memory/conversation-queries.ts +69 -29
- package/src/memory/conversation-starter-validation.ts +88 -0
- package/src/memory/conversation-starters-cadence.ts +1 -1
- package/src/memory/conversation-title-service.ts +27 -1
- package/src/memory/db-init.ts +22 -4
- package/src/memory/db-maintenance.ts +1 -1
- package/src/memory/delivery-channels.ts +1 -14
- package/src/memory/delivery-crud.ts +2 -32
- package/src/memory/delivery-status.ts +1 -1
- package/src/memory/embedding-gemini.test.ts +44 -5
- package/src/memory/embedding-gemini.ts +6 -1
- package/src/memory/external-conversation-store.ts +1 -1
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +412 -0
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +225 -0
- package/src/memory/graph/bootstrap.test.ts +277 -0
- package/src/memory/graph/bootstrap.ts +10 -6
- package/src/memory/graph/capability-seed.ts +3 -3
- package/src/memory/graph/compaction.ts +1 -1
- package/src/memory/graph/consolidation.ts +13 -10
- package/src/memory/graph/conversation-graph-memory.ts +151 -1
- package/src/memory/graph/decay.ts +1 -1
- package/src/memory/graph/extraction.ts +63 -23
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +95 -2
- package/src/memory/graph/graph-search.ts +22 -7
- package/src/memory/graph/image-ref-utils.ts +1 -1
- package/src/memory/graph/retriever.test.ts +158 -4
- package/src/memory/graph/retriever.ts +27 -8
- package/src/memory/graph/store.test.ts +2 -1
- package/src/memory/graph/store.ts +1 -1
- package/src/memory/graph/tool-handlers.ts +73 -247
- package/src/memory/graph/tools.ts +35 -53
- package/src/memory/group-crud.ts +1 -2
- package/src/memory/guardian-action-store.ts +2 -1
- package/src/memory/guardian-approvals.ts +1 -1
- package/src/memory/guardian-rate-limits.ts +1 -1
- package/src/memory/indexer.ts +43 -17
- package/src/memory/invite-store.ts +1 -1
- package/src/memory/job-handlers/backfill.ts +1 -1
- package/src/memory/job-handlers/cleanup.ts +2 -1
- package/src/memory/job-handlers/conversation-starters.ts +18 -10
- package/src/memory/job-handlers/embedding.test.ts +2 -1
- package/src/memory/job-handlers/embedding.ts +1 -1
- package/src/memory/job-handlers/index-maintenance.ts +1 -1
- package/src/memory/job-handlers/summarization.ts +3 -3
- package/src/memory/job-utils.ts +3 -3
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +362 -0
- package/src/memory/jobs/embed-concept-page.ts +210 -0
- package/src/memory/jobs/embed-pkb-file.test.ts +2 -1
- package/src/memory/jobs-store.ts +10 -2
- package/src/memory/jobs-worker.ts +58 -5
- package/src/memory/lifecycle-events-store.ts +1 -1
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/llm-usage-store.ts +1 -1
- package/src/memory/media-store.ts +1 -1
- package/src/memory/memory-recall-log-store.ts +1 -1
- package/src/memory/migrations/038-actor-token-records.ts +3 -0
- package/src/memory/migrations/039-actor-refresh-token-records.ts +3 -0
- package/src/memory/migrations/041-approval-prompt-ts-tracker.ts +26 -0
- package/src/memory/migrations/149-oauth-tables.ts +1 -0
- package/src/memory/migrations/223-schedule-script-column.ts +11 -0
- package/src/memory/migrations/224-oauth-providers-managed-service-is-paid.ts +24 -0
- package/src/memory/migrations/225-oauth-providers-available-scopes.ts +13 -0
- package/src/memory/migrations/226-schedule-wake-conversation-id.ts +11 -0
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +18 -0
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +27 -0
- package/src/memory/migrations/229-delete-private-conversations.test.ts +1087 -0
- package/src/memory/migrations/229-delete-private-conversations.ts +210 -0
- package/src/memory/migrations/230-acp-session-history.ts +41 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +128 -0
- package/src/memory/migrations/232-activation-state.ts +38 -0
- package/src/memory/migrations/index.ts +14 -0
- package/src/memory/migrations/registry.ts +7 -0
- package/src/memory/pkb/pkb-index.test.ts +5 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +5 -5
- package/src/memory/pkb/pkb-search.test.ts +148 -7
- package/src/memory/pkb/pkb-search.ts +65 -30
- package/src/memory/published-pages-store.ts +1 -1
- package/src/memory/qdrant-client.test.ts +60 -0
- package/src/memory/qdrant-client.ts +25 -0
- package/src/memory/schema/acp.ts +30 -0
- package/src/memory/schema/conversations.ts +1 -1
- package/src/memory/schema/index.ts +1 -0
- package/src/memory/schema/infrastructure.ts +2 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- package/src/memory/schema/oauth.ts +4 -1
- package/src/memory/scoped-approval-grants.ts +2 -1
- package/src/memory/search/semantic.ts +2 -2
- package/src/memory/shared-app-links-store.ts +2 -1
- package/src/memory/tool-usage-store.ts +1 -1
- package/src/memory/trace-event-store.ts +2 -1
- package/src/memory/turn-events-store.ts +1 -1
- package/src/memory/v2/__tests__/activation-store.test.ts +202 -0
- package/src/memory/v2/__tests__/activation.test.ts +956 -0
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +610 -0
- package/src/memory/v2/__tests__/consolidation-job.test.ts +395 -0
- package/src/memory/v2/__tests__/edges.test.ts +435 -0
- package/src/memory/v2/__tests__/injection.test.ts +792 -0
- package/src/memory/v2/__tests__/migration.test.ts +812 -0
- package/src/memory/v2/__tests__/page-store.test.ts +334 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +438 -0
- package/src/memory/v2/__tests__/sim.test.ts +549 -0
- package/src/memory/v2/__tests__/skill-content.test.ts +85 -0
- package/src/memory/v2/__tests__/skill-qdrant.test.ts +657 -0
- package/src/memory/v2/__tests__/skill-store.test.ts +351 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +441 -0
- package/src/memory/v2/activation-store.ts +109 -0
- package/src/memory/v2/activation.ts +490 -0
- package/src/memory/v2/backfill-jobs.ts +442 -0
- package/src/memory/v2/consolidation-job.ts +304 -0
- package/src/memory/v2/edges.ts +217 -0
- package/src/memory/v2/injection.ts +307 -0
- package/src/memory/v2/migration.ts +654 -0
- package/src/memory/v2/now-text.ts +38 -0
- package/src/memory/v2/page-store.ts +245 -0
- package/src/memory/v2/prompts/consolidation.ts +185 -0
- package/src/memory/v2/prompts/sweep.ts +56 -0
- package/src/memory/v2/qdrant.ts +342 -0
- package/src/memory/v2/sim.ts +206 -0
- package/src/memory/v2/skill-content.ts +42 -0
- package/src/memory/v2/skill-qdrant.ts +395 -0
- package/src/memory/v2/skill-store.ts +128 -0
- package/src/memory/v2/sweep-job.ts +298 -0
- package/src/memory/v2/types.ts +116 -0
- package/src/memory/validation.ts +1 -1
- package/src/messaging/providers/index.ts +262 -0
- package/src/messaging/providers/slack/api.ts +242 -0
- package/src/messaging/providers/slack/message-metadata.ts +1 -1
- package/src/messaging/providers/slack/render-transcript.test.ts +77 -29
- package/src/messaging/providers/slack/render-transcript.ts +58 -0
- package/src/messaging/providers/slack/send.ts +383 -0
- package/src/messaging/providers/telegram-bot/adapter.ts +4 -42
- package/src/messaging/providers/telegram-bot/api.ts +253 -0
- package/src/messaging/providers/telegram-bot/client.ts +17 -58
- package/src/messaging/providers/telegram-bot/send.ts +232 -0
- package/src/messaging/providers/whatsapp/adapter.ts +4 -36
- package/src/messaging/providers/whatsapp/api.ts +319 -0
- package/src/messaging/providers/whatsapp/client.ts +4 -48
- package/src/messaging/providers/whatsapp/send.ts +209 -0
- package/src/notifications/adapters/slack.ts +5 -23
- package/src/notifications/adapters/telegram.ts +8 -29
- package/src/notifications/conversation-candidates.ts +1 -1
- package/src/notifications/conversation-pairing.ts +78 -19
- package/src/notifications/conversation-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -6
- package/src/notifications/decision-engine.ts +1 -1
- package/src/notifications/decisions-store.ts +1 -1
- package/src/notifications/deliveries-store.ts +2 -1
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +1 -1
- package/src/notifications/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +1 -11
- package/src/oauth/AGENTS.md +1 -1
- package/src/oauth/__tests__/identity-verifier.test.ts +2 -1
- package/src/oauth/connect-orchestrator.ts +8 -34
- package/src/oauth/connect-types.ts +6 -10
- package/src/oauth/connection-resolver.ts +11 -2
- package/src/oauth/manual-token-connection.ts +23 -0
- package/src/oauth/oauth-store.ts +32 -15
- package/src/oauth/provider-serializer.ts +6 -1
- package/src/oauth/seed-providers.ts +56 -108
- package/src/outbound-proxy/http-forwarder.ts +9 -0
- package/src/outbound-proxy/index.ts +0 -1
- package/src/permissions/approval-policy.test.ts +398 -106
- package/src/permissions/approval-policy.ts +134 -108
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +280 -345
- package/src/permissions/gateway-threshold-reader.ts +177 -0
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +8 -9
- package/src/permissions/risk-types.ts +24 -153
- package/src/permissions/types.ts +19 -47
- package/src/permissions/workspace-policy.ts +10 -7
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/circuit-breaker.ts +146 -0
- package/src/plugins/defaults/compaction.ts +145 -0
- package/src/plugins/defaults/empty-response.ts +126 -0
- package/src/plugins/defaults/history-repair.ts +85 -0
- package/src/plugins/defaults/index.ts +116 -0
- package/src/plugins/defaults/injectors.ts +488 -0
- package/src/plugins/defaults/llm-call.ts +79 -0
- package/src/plugins/defaults/memory-retrieval.ts +221 -0
- package/src/plugins/defaults/overflow-reduce.ts +185 -0
- package/src/plugins/defaults/persistence.ts +129 -0
- package/src/plugins/defaults/title-generate.ts +95 -0
- package/src/plugins/defaults/token-estimate.ts +103 -0
- package/src/plugins/defaults/tool-error.ts +126 -0
- package/src/plugins/defaults/tool-execute.ts +89 -0
- package/src/plugins/defaults/tool-result-truncate.ts +88 -0
- package/src/plugins/pipeline.ts +316 -0
- package/src/plugins/plugin-skill-contributions.ts +292 -0
- package/src/plugins/registry.ts +301 -0
- package/src/plugins/types.ts +1133 -0
- package/src/plugins/user-loader.ts +203 -0
- package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +197 -0
- package/src/prompts/persona-resolver.ts +2 -4
- package/src/prompts/system-prompt.ts +39 -0
- package/src/prompts/templates/BOOTSTRAP.md +27 -77
- package/src/prompts/templates/SOUL.md +3 -1
- package/src/providers/__tests__/provider-env-vars.test.ts +0 -21
- package/src/providers/__tests__/retry-callsite.test.ts +3 -6
- package/src/providers/anthropic/client.ts +71 -19
- package/src/providers/call-site-routing.ts +7 -3
- package/src/providers/fireworks/client.ts +3 -0
- package/src/providers/gemini/client.ts +96 -22
- package/src/providers/managed-proxy/context.ts +0 -12
- package/src/providers/model-catalog.ts +123 -25
- package/src/providers/model-intents.ts +6 -7
- package/src/providers/openai/chat-completions-provider.ts +37 -7
- package/src/providers/openai/responses-provider.ts +39 -4
- package/src/providers/openrouter/client.ts +9 -6
- package/src/providers/provider-env-vars.ts +4 -12
- package/src/providers/provider-send-message.ts +16 -11
- package/src/providers/registry.ts +1 -1
- package/src/providers/retry.ts +52 -23
- package/src/providers/speech-to-text/deepgram-realtime.test.ts +61 -0
- package/src/providers/speech-to-text/deepgram-realtime.ts +57 -0
- package/src/providers/speech-to-text/openai-whisper-stream.ts +1 -1
- package/src/providers/speech-to-text/openai-whisper.ts +3 -6
- package/src/providers/speech-to-text/provider-catalog.ts +75 -0
- package/src/providers/speech-to-text/xai-realtime.test.ts +72 -4
- package/src/providers/speech-to-text/xai-realtime.ts +39 -14
- package/src/providers/speech-to-text/xai.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +22 -10
- package/src/runtime/AGENTS.md +27 -17
- package/src/runtime/__tests__/agent-wake.test.ts +33 -9
- package/src/runtime/__tests__/client-registry.test.ts +271 -0
- package/src/runtime/__tests__/interactive-ui.test.ts +157 -246
- package/src/runtime/access-request-helper.ts +9 -20
- package/src/runtime/actor-trust-resolver.ts +2 -2
- package/src/runtime/agent-wake.ts +174 -68
- package/src/runtime/approval-conversation-turn.ts +2 -15
- package/src/runtime/approval-message-composer.ts +11 -60
- package/src/runtime/assistant-event.ts +18 -66
- package/src/runtime/auth/__tests__/guard-tests.test.ts +6 -30
- package/src/runtime/auth/__tests__/middleware.test.ts +10 -10
- package/src/runtime/auth/__tests__/route-policy.test.ts +0 -8
- package/src/runtime/auth/context.ts +9 -0
- package/src/runtime/auth/middleware.ts +4 -4
- package/src/runtime/auth/route-policy.ts +195 -4
- package/src/runtime/auth/token-service.ts +1 -100
- package/src/runtime/capability-tokens.ts +89 -313
- package/src/runtime/channel-approval-types.ts +1 -6
- package/src/runtime/channel-approvals.ts +7 -79
- package/src/runtime/channel-readiness-service.ts +2 -2
- package/src/runtime/channel-reply-delivery.ts +2 -8
- package/src/runtime/channel-retry-sweep.ts +20 -17
- package/src/runtime/client-registry.ts +254 -0
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -7
- package/src/runtime/gateway-client.ts +37 -378
- package/src/runtime/guardian-action-grant-minter.ts +2 -3
- package/src/runtime/guardian-action-message-composer.ts +11 -52
- package/src/runtime/guardian-action-service.ts +19 -7
- package/src/runtime/guardian-decision-types.ts +4 -65
- package/src/runtime/guardian-reply-router.ts +10 -19
- package/src/runtime/guardian-vellum-migration.ts +5 -64
- package/src/runtime/http-errors.ts +3 -0
- package/src/runtime/http-router.ts +50 -7
- package/src/runtime/http-server.ts +345 -1041
- package/src/runtime/http-types.ts +15 -100
- package/src/runtime/interactive-ui-types.ts +145 -0
- package/src/runtime/interactive-ui.ts +38 -196
- package/src/runtime/invite-redemption-service.ts +1 -1
- package/src/runtime/invite-redemption-templates.ts +1 -1
- package/src/runtime/local-actor-identity.ts +13 -43
- package/src/runtime/message-composer-types.ts +134 -0
- package/src/runtime/middleware/rate-limiter.ts +1 -1
- package/src/runtime/middleware/request-logger.ts +5 -2
- package/src/runtime/migrations/__tests__/job-registry.test.ts +346 -0
- package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +16 -0
- package/src/runtime/migrations/job-registry.ts +281 -0
- package/src/runtime/migrations/vbundle-builder.ts +4 -26
- package/src/runtime/migrations/vbundle-importer.ts +1 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +0 -13
- package/src/runtime/migrations/vbundle-tar-stream.ts +11 -3
- package/src/runtime/nl-approval-parser.ts +16 -21
- package/src/runtime/pending-interactions.ts +29 -12
- package/src/runtime/routes/__tests__/acp-routes.test.ts +395 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +204 -320
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +72 -4
- package/src/runtime/routes/__tests__/stt-routes.test.ts +182 -223
- package/src/runtime/routes/__tests__/suggest-trust-rule-routes.test.ts +230 -0
- package/src/{ipc/__tests__/task-ipc.test.ts → runtime/routes/__tests__/task-routes.test.ts} +116 -96
- package/src/runtime/routes/__tests__/tts-routes.test.ts +185 -289
- package/src/runtime/routes/access-request-decision.ts +25 -50
- package/src/runtime/routes/acp-routes.test.ts +371 -0
- package/src/runtime/routes/acp-routes.ts +392 -166
- package/src/runtime/routes/app-management-routes.ts +464 -660
- package/src/runtime/routes/app-routes.ts +192 -177
- package/src/runtime/routes/approval-prompt-ts-tracker.ts +51 -31
- package/src/runtime/routes/approval-routes.ts +133 -434
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +24 -84
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +3 -10
- package/src/runtime/routes/attachment-routes.ts +409 -253
- package/src/runtime/routes/audio-routes.ts +51 -18
- package/src/runtime/routes/avatar-routes.ts +82 -75
- package/src/runtime/routes/background-tool-routes.ts +94 -0
- package/src/runtime/routes/backup-routes.ts +154 -336
- package/src/runtime/routes/brain-graph-routes.ts +83 -110
- package/src/runtime/routes/browser-routes.ts +141 -0
- package/src/runtime/routes/btw-routes.ts +62 -106
- package/src/runtime/routes/cache-routes.ts +96 -0
- package/src/runtime/routes/call-routes.ts +208 -247
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +1 -1
- package/src/runtime/routes/channel-delivery-routes.ts +25 -27
- package/src/runtime/routes/channel-readiness-routes.ts +83 -120
- package/src/runtime/routes/channel-route-definitions.ts +62 -0
- package/src/runtime/routes/channel-route-shared.ts +14 -18
- package/src/runtime/routes/channel-verification-routes.ts +207 -187
- package/src/runtime/routes/client-routes.ts +48 -0
- package/src/runtime/routes/contact-routes.ts +533 -407
- package/src/runtime/routes/conversation-analysis-routes.ts +48 -49
- package/src/runtime/routes/conversation-attention-routes.ts +55 -67
- package/src/runtime/routes/conversation-list-routes.ts +265 -0
- package/src/runtime/routes/conversation-management-routes.ts +626 -715
- package/src/runtime/routes/conversation-query-routes.ts +510 -460
- package/src/runtime/routes/conversation-routes.ts +652 -457
- package/src/runtime/routes/conversation-starter-routes.ts +121 -71
- package/src/runtime/routes/credential-prompt-routes.ts +124 -0
- package/src/runtime/routes/debug-routes.ts +34 -39
- package/src/runtime/routes/defer-routes.ts +230 -0
- package/src/runtime/routes/diagnostics-routes.ts +79 -70
- package/src/runtime/routes/documents-routes.ts +117 -106
- package/src/runtime/routes/errors.ts +132 -0
- package/src/runtime/routes/events-routes.ts +97 -58
- package/src/runtime/routes/filing-routes.ts +65 -78
- package/src/runtime/routes/global-search-routes.ts +51 -57
- package/src/runtime/routes/group-routes.ts +199 -181
- package/src/runtime/routes/guardian-action-routes.ts +103 -169
- package/src/runtime/routes/guardian-approval-interception.ts +27 -58
- package/src/runtime/routes/guardian-approval-prompt.ts +10 -21
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +2 -6
- package/src/runtime/routes/guardian-expiry-sweep.ts +19 -36
- package/src/runtime/routes/heartbeat-routes.ts +194 -209
- package/src/runtime/routes/home-feed-routes.ts +85 -187
- package/src/runtime/routes/home-state-routes.ts +27 -24
- package/src/runtime/routes/host-bash-routes.ts +42 -52
- package/src/runtime/routes/host-browser-routes.ts +38 -69
- package/src/runtime/routes/host-cu-routes.ts +74 -70
- package/src/runtime/routes/host-file-routes.ts +50 -60
- package/src/runtime/routes/host-transfer-routes.ts +220 -0
- package/src/runtime/routes/http-adapter.ts +172 -0
- package/src/runtime/routes/identity-routes.ts +83 -79
- package/src/runtime/routes/inbound-conversation.ts +11 -18
- package/src/runtime/routes/inbound-message-handler.ts +162 -123
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +79 -138
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +2 -3
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +54 -90
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +25 -50
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +7 -7
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +5 -5
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +5 -6
- package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +14 -24
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -10
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
- package/src/runtime/routes/inbound-stages/transcribe-audio.ts +3 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +19 -26
- package/src/runtime/routes/index.ts +197 -0
- package/src/runtime/routes/integrations/slack/__tests__/channel.test.ts +25 -32
- package/src/runtime/routes/integrations/slack/__tests__/share.test.ts +22 -31
- package/src/runtime/routes/integrations/slack/channel.ts +69 -66
- package/src/runtime/routes/integrations/slack/share.ts +49 -58
- package/src/runtime/routes/integrations/telegram.ts +91 -74
- package/src/runtime/routes/integrations/twilio.ts +163 -240
- package/src/runtime/routes/integrations/vercel.ts +57 -54
- package/src/runtime/routes/interface-routes.ts +43 -0
- package/src/runtime/routes/internal-oauth-routes.ts +56 -0
- package/src/runtime/routes/internal-twilio-routes.ts +46 -0
- package/src/runtime/routes/llm-context-normalization.ts +4 -2
- package/src/runtime/routes/log-export/workspace-allowlist.ts +1 -1
- package/src/runtime/routes/log-export-routes.ts +90 -100
- package/src/runtime/routes/memory-item-routes.test.ts +153 -175
- package/src/runtime/routes/memory-item-routes.ts +243 -323
- package/src/runtime/routes/memory-v2-routes.ts +193 -0
- package/src/runtime/routes/migration-rollback-routes.ts +167 -212
- package/src/runtime/routes/migration-routes.ts +877 -377
- package/src/runtime/routes/notification-routes.ts +199 -70
- package/src/runtime/routes/oauth-apps.ts +254 -251
- package/src/runtime/routes/oauth-providers.ts +66 -57
- package/src/runtime/routes/playground/__tests__/force-compact.test.ts +224 -0
- package/src/runtime/routes/playground/__tests__/guard.test.ts +60 -0
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +250 -0
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +195 -0
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +159 -0
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +207 -0
- package/src/runtime/routes/playground/__tests__/state.test.ts +175 -0
- package/src/runtime/routes/playground/conversation-not-found.ts +27 -0
- package/src/runtime/routes/playground/force-compact.ts +60 -0
- package/src/runtime/routes/playground/guard.ts +36 -0
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +18 -0
- package/src/runtime/routes/playground/inject-failures.ts +143 -0
- package/src/runtime/routes/playground/reset-circuit.ts +89 -0
- package/src/runtime/routes/playground/seed-conversation.ts +113 -0
- package/src/runtime/routes/playground/seeded-conversations.ts +74 -0
- package/src/runtime/routes/playground/state.ts +77 -0
- package/src/runtime/routes/profiler-routes.ts +132 -167
- package/src/runtime/routes/ps-routes.ts +120 -0
- package/src/runtime/routes/recording-routes.ts +197 -258
- package/src/runtime/routes/rename-conversation-routes.ts +89 -0
- package/src/runtime/routes/schedule-routes.ts +284 -207
- package/src/runtime/routes/secret-routes.ts +219 -265
- package/src/runtime/routes/secrets-deps.ts +24 -0
- package/src/runtime/routes/settings-routes.ts +361 -441
- package/src/runtime/routes/skills-routes.ts +434 -469
- package/src/runtime/routes/stt-routes.ts +196 -206
- package/src/runtime/routes/subagents-routes.ts +125 -141
- package/src/runtime/routes/suggest-trust-rule-routes.ts +244 -0
- package/src/runtime/routes/surface-action-routes.ts +135 -190
- package/src/runtime/routes/surface-content-routes.ts +84 -118
- package/src/runtime/routes/task-routes.ts +354 -0
- package/src/runtime/routes/telemetry-routes.ts +33 -49
- package/src/runtime/routes/trace-event-routes.ts +55 -74
- package/src/runtime/routes/trust-rules-routes.ts +147 -239
- package/src/runtime/routes/tts-routes.ts +187 -169
- package/src/runtime/routes/types.ts +139 -0
- package/src/{ipc/routes/ui-request.ts → runtime/routes/ui-request-routes.ts} +23 -17
- package/src/runtime/routes/upgrade-broadcast-routes.ts +156 -197
- package/src/runtime/routes/usage-routes.ts +143 -169
- package/src/runtime/routes/user-routes.ts +102 -18
- package/src/runtime/routes/wake-conversation-routes.ts +49 -0
- package/src/{ipc/routes/watcher.ts → runtime/routes/watcher-routes.ts} +84 -39
- package/src/runtime/routes/wipe-conversation-routes.ts +89 -0
- package/src/runtime/routes/work-items-routes.test.ts +10 -20
- package/src/runtime/routes/work-items-routes.ts +418 -433
- package/src/runtime/routes/workspace-commit-routes.ts +30 -61
- package/src/runtime/routes/workspace-routes.test.ts +254 -381
- package/src/runtime/routes/workspace-routes.ts +238 -246
- package/src/runtime/runtime-mode.ts +8 -1
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +80 -118
- package/src/runtime/services/analyze-conversation.ts +14 -41
- package/src/runtime/services/conversation-serializer.ts +181 -0
- package/src/runtime/skill-route-registry.ts +75 -15
- package/src/runtime/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +13 -49
- package/src/schedule/run-script.ts +68 -0
- package/src/schedule/schedule-store.ts +70 -2
- package/src/schedule/scheduler.ts +149 -8
- package/src/security/ces-credential-client.ts +32 -169
- package/src/security/ces-rpc-credential-backend.ts +1 -1
- package/src/security/credential-backend.ts +6 -6
- package/src/security/oauth-completion-page.ts +1 -1
- package/src/security/oauth2.ts +3 -6
- package/src/sequence/analytics.ts +1 -1
- package/src/sequence/guardrails.ts +3 -3
- package/src/sequence/store.ts +2 -1
- package/src/signals/bash.ts +1 -1
- package/src/signals/event-stream.ts +1 -1
- package/src/skills/catalog-cache.ts +19 -5
- package/src/skills/catalog-files.ts +0 -5
- package/src/skills/catalog-install.ts +28 -18
- package/src/skills/category-inference.ts +0 -11
- package/src/skills/clawhub.ts +2 -2
- package/src/skills/managed-store.ts +2 -2
- package/src/skills/remote-skill-policy.ts +6 -7
- package/src/subagent/index.ts +2 -6
- package/src/subagent/manager.ts +27 -23
- package/src/subagent/types.ts +9 -0
- package/src/tasks/SPEC.md +2 -2
- package/src/tasks/task-compiler.ts +1 -1
- package/src/tasks/task-runner.ts +2 -22
- package/src/tasks/task-store.ts +1 -1
- package/src/tools/acp/list-agents.test.ts +115 -0
- package/src/tools/acp/list-agents.ts +31 -0
- package/src/tools/acp/spawn.test.ts +379 -0
- package/src/tools/acp/spawn.ts +142 -62
- package/src/tools/acp/steer.test.ts +101 -0
- package/src/tools/acp/steer.ts +38 -0
- package/src/tools/background-tool-registry.ts +98 -0
- package/src/tools/browser/__tests__/browser-status.test.ts +189 -0
- package/src/tools/browser/browser-execution.ts +122 -26
- package/src/tools/browser/browser-manager.ts +1 -8
- package/src/tools/browser/cdp-client/__tests__/extension-cdp-client.test.ts +230 -0
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +146 -3
- package/src/tools/browser/cdp-client/accessibility-snapshot.ts +1 -1
- package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +3 -1
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +54 -3
- package/src/tools/browser/cdp-client/factory.ts +15 -4
- package/src/tools/browser/cdp-client/types.ts +4 -1
- package/src/tools/computer-use/definitions.ts +1 -1
- package/src/tools/credential-execution/make-authenticated-request.ts +2 -2
- package/src/tools/credential-execution/manage-secure-command-tool.ts +1 -1
- package/src/tools/credential-execution/run-authenticated-command.ts +2 -2
- package/src/tools/credentials/broker-types.ts +2 -1
- package/src/tools/document/editor-template.ts +1 -1
- package/src/tools/execution-timeout.ts +1 -1
- package/src/tools/executor.ts +123 -76
- package/src/tools/host-filesystem/transfer.test.ts +268 -0
- package/src/tools/host-filesystem/transfer.ts +234 -0
- package/src/tools/host-terminal/host-shell.ts +189 -11
- package/src/tools/mcp/mcp-tool-factory.ts +1 -1
- package/src/tools/memory/register.test.ts +161 -1
- package/src/tools/memory/register.ts +19 -34
- package/src/tools/network/script-proxy/session-manager.ts +37 -1
- package/src/tools/permission-checker.ts +103 -255
- package/src/tools/policy-context.ts +5 -8
- package/src/tools/registry.ts +156 -4
- package/src/tools/schedule/create.ts +23 -8
- package/src/tools/schedule/update.ts +3 -1
- package/src/tools/secret-detection-handler.ts +13 -154
- package/src/tools/shared/shell-output.ts +4 -1
- package/src/tools/side-effects.ts +2 -2
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/subagent/spawn.ts +35 -11
- package/src/tools/system/avatar-generator.ts +6 -2
- package/src/tools/terminal/safe-env.ts +9 -1
- package/src/tools/terminal/shell.ts +161 -31
- package/src/tools/tool-approval-handler.ts +4 -70
- package/src/tools/tool-input-summary.ts +10 -0
- package/src/tools/types.ts +157 -151
- package/src/tools/ui-surface/definitions.ts +2 -2
- package/src/util/debounce.ts +0 -21
- package/src/util/errors.ts +0 -8
- package/src/util/log-redact.ts +0 -1
- package/src/util/platform.ts +85 -119
- package/src/util/pricing.ts +135 -9
- package/src/watcher/engine.ts +42 -20
- package/src/watcher/watcher-store.ts +2 -1
- package/src/work-items/work-item-store.ts +1 -1
- package/src/workspace/git-service.ts +1 -6
- package/src/workspace/migrations/006-services-config.ts +11 -4
- package/src/workspace/migrations/017-seed-persona-dirs.ts +1 -1
- package/src/workspace/migrations/019-scope-journal-to-guardian.ts +1 -1
- package/src/workspace/migrations/022-move-hooks-to-workspace.ts +2 -3
- package/src/workspace/migrations/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +3 -4
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +108 -0
- package/src/workspace/migrations/047-remove-watch-callsites.ts +54 -0
- package/src/workspace/migrations/048-remove-workspace-hooks.ts +81 -0
- package/src/workspace/migrations/049-release-notes-default-sonnet.ts +80 -0
- package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +86 -0
- package/src/workspace/migrations/051-seed-conversation-summarization-callsite.ts +128 -0
- package/src/workspace/migrations/052-seed-default-inference-profiles.ts +150 -0
- package/src/workspace/migrations/053-release-notes-acp-codex.ts +107 -0
- package/src/workspace/migrations/054-seed-recall-callsite.ts +102 -0
- package/src/workspace/migrations/055-release-notes-agentic-recall.ts +63 -0
- package/src/workspace/migrations/056-release-notes-inference-profile-reordering.ts +65 -0
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +98 -0
- package/src/workspace/migrations/058-release-notes-acp-sessions-ui.ts +71 -0
- package/src/workspace/migrations/059-move-pid-to-workspace.ts +53 -0
- package/src/workspace/migrations/060-memory-v2-init.ts +53 -0
- package/src/workspace/migrations/rebuild-conversation-disk-view.ts +1 -1
- package/src/workspace/migrations/registry.ts +30 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- package/tsconfig.json +1 -1
- package/hook-templates/debug-prompt-logger/hook.json +0 -7
- package/hook-templates/debug-prompt-logger/run.sh +0 -66
- package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +0 -471
- package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +0 -436
- package/src/__tests__/cli-command-risk-guard.test.ts +0 -368
- package/src/__tests__/compaction-circuit-breaker.test.ts +0 -336
- package/src/__tests__/config-watcher-feature-flags.test.ts +0 -211
- package/src/__tests__/context-overflow-approval.test.ts +0 -156
- package/src/__tests__/conversation-approval-overrides.test.ts +0 -207
- package/src/__tests__/conversation-host-access-routes.test.ts +0 -229
- package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +0 -226
- package/src/__tests__/conversation-tool-setup-side-effect-flag.test.ts +0 -167
- package/src/__tests__/ephemeral-permissions.test.ts +0 -474
- package/src/__tests__/extension-id-sync-guard.test.ts +0 -241
- package/src/__tests__/hooks-blocking.test.ts +0 -178
- package/src/__tests__/hooks-cli.test.ts +0 -182
- package/src/__tests__/hooks-config.test.ts +0 -108
- package/src/__tests__/hooks-discovery.test.ts +0 -211
- package/src/__tests__/hooks-integration.test.ts +0 -196
- package/src/__tests__/hooks-manager.test.ts +0 -226
- package/src/__tests__/hooks-runner.test.ts +0 -175
- package/src/__tests__/hooks-settings.test.ts +0 -160
- package/src/__tests__/hooks-templates.test.ts +0 -169
- package/src/__tests__/hooks-ts-runner.test.ts +0 -170
- package/src/__tests__/hooks-watch.test.ts +0 -112
- package/src/__tests__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- package/src/__tests__/notification-schedule-dedup.test.ts +0 -213
- package/src/__tests__/oauth-scope-policy.test.ts +0 -180
- package/src/__tests__/pairing-concurrent.test.ts +0 -84
- package/src/__tests__/pairing-routes.test.ts +0 -181
- package/src/__tests__/parser.test.ts +0 -595
- package/src/__tests__/permission-checker-host-gate.test.ts +0 -512
- package/src/__tests__/permission-controls-v2-flag.test.ts +0 -55
- package/src/__tests__/permission-mode.test.ts +0 -89
- package/src/__tests__/provider-env-vars-scope.test.ts +0 -52
- package/src/__tests__/risk-classifier-parity.test.ts +0 -230
- package/src/__tests__/send-notification-tool.test.ts +0 -83
- package/src/__tests__/shell-identity.test.ts +0 -370
- package/src/__tests__/shell-parser-fuzz.test.ts +0 -629
- package/src/__tests__/shell-parser-property.test.ts +0 -936
- package/src/__tests__/starter-bundle.test.ts +0 -173
- package/src/__tests__/stt-catalog-parity.test.ts +0 -282
- package/src/__tests__/task-runner.test.ts +0 -224
- package/src/__tests__/tool-executor-shell-integration.test.ts +0 -357
- package/src/__tests__/trust-store-pattern-matches.test.ts +0 -29
- package/src/__tests__/trust-store.test.ts +0 -2013
- package/src/__tests__/v2-consent-policy.test.ts +0 -103
- package/src/browser/identifiers.ts +0 -51
- package/src/cli/commands/shotgun.ts +0 -266
- package/src/cli/db.ts +0 -1
- package/src/config/bundled-skills/conversations/SKILL.md +0 -20
- package/src/config/bundled-skills/conversations/TOOLS.json +0 -23
- package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +0 -88
- package/src/config/bundled-skills/heartbeat/SKILL.md +0 -43
- package/src/config/bundled-skills/notifications/SKILL.md +0 -40
- package/src/config/bundled-skills/notifications/TOOLS.json +0 -80
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +0 -152
- package/src/config/bundled-skills/notifications/tools/shared.ts +0 -13
- package/src/config/bundled-skills/screen-watch/SKILL.md +0 -27
- package/src/config/bundled-skills/screen-watch/TOOLS.json +0 -35
- package/src/config/bundled-skills/settings/tools/avatar-get.ts +0 -40
- package/src/config/bundled-skills/settings/tools/avatar-remove.ts +0 -64
- package/src/config/bundled-skills/settings/tools/avatar-update.ts +0 -88
- package/src/config/bundled-skills/skills-catalog/SKILL.md +0 -84
- package/src/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- package/src/daemon/context-overflow-approval.ts +0 -52
- package/src/daemon/external-skills-bootstrap.ts +0 -41
- package/src/daemon/message-types/trust.ts +0 -71
- package/src/daemon/pairing-store.ts +0 -229
- package/src/daemon/watch-handler.ts +0 -399
- package/src/hooks/cli.ts +0 -253
- package/src/hooks/config.ts +0 -100
- package/src/hooks/discovery.ts +0 -135
- package/src/hooks/manager.ts +0 -179
- package/src/hooks/runner.ts +0 -117
- package/src/hooks/templates.ts +0 -77
- package/src/hooks/types.ts +0 -75
- package/src/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -61
- package/src/ipc/routes/browser.ts +0 -96
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/index.ts +0 -21
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/oauth/scope-policy.ts +0 -89
- package/src/permissions/bash-risk-classifier.test.ts +0 -1208
- package/src/permissions/bash-risk-classifier.ts +0 -707
- package/src/permissions/command-registry.test.ts +0 -535
- package/src/permissions/command-registry.ts +0 -825
- package/src/permissions/defaults.ts +0 -313
- package/src/permissions/file-risk-classifier.test.ts +0 -535
- package/src/permissions/file-risk-classifier.ts +0 -274
- package/src/permissions/permission-mode.ts +0 -24
- package/src/permissions/shell-identity.ts +0 -337
- package/src/permissions/skill-risk-classifier.test.ts +0 -311
- package/src/permissions/skill-risk-classifier.ts +0 -214
- package/src/permissions/trust-client.ts +0 -359
- package/src/permissions/trust-store-interface.ts +0 -100
- package/src/permissions/trust-store.ts +0 -1330
- package/src/permissions/v2-consent-policy.ts +0 -87
- package/src/permissions/web-risk-classifier.test.ts +0 -170
- package/src/permissions/web-risk-classifier.ts +0 -89
- package/src/runtime/__tests__/browser-extension-pair-routes.test.ts +0 -715
- package/src/runtime/__tests__/capability-tokens.test.ts +0 -258
- package/src/runtime/actor-refresh-token-store.ts +0 -156
- package/src/runtime/actor-token-store.ts +0 -207
- package/src/runtime/auth/__tests__/credential-service.test.ts +0 -264
- package/src/runtime/auth/credential-service.ts +0 -352
- package/src/runtime/conversation-approval-overrides.ts +0 -86
- package/src/runtime/gateway-internal-client.ts +0 -94
- package/src/runtime/routes/browser-extension-pair-routes.ts +0 -556
- package/src/runtime/routes/channel-routes.ts +0 -112
- package/src/runtime/routes/contact-routes.test.ts +0 -298
- package/src/runtime/routes/guardian-bootstrap-routes.ts +0 -175
- package/src/runtime/routes/guardian-refresh-routes.ts +0 -79
- package/src/runtime/routes/invite-routes.ts +0 -280
- package/src/runtime/routes/pairing-routes.ts +0 -431
- package/src/runtime/routes/watch-routes.ts +0 -156
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/signals/shotgun.ts +0 -203
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/terminal/parser.ts +0 -623
- package/src/tools/watch/screen-watch.ts +0 -144
- package/src/tools/watch/watch-state.ts +0 -142
- package/src/types/qrcode.d.ts +0 -13
- package/src/util/network-info.ts +0 -55
- /package/node_modules/@vellumai/{ces-contracts → ces-client}/tsconfig.json +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/__tests__/grants.test.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/error.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/grants.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/handles.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rendering.ts +0 -0
- /package/node_modules/@vellumai/{ces-contracts → service-contracts}/src/rpc.ts +0 -0
|
@@ -0,0 +1,1348 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `SkillHostClient` — IPC-backed concretion of the neutral `SkillHost`
|
|
3
|
+
* interface. Lets an out-of-process first-party skill consume the daemon's
|
|
4
|
+
* host surface over the Unix domain socket exposed by `SkillIpcServer`.
|
|
5
|
+
*
|
|
6
|
+
* Wire protocol (mirrors `assistant/src/ipc/skill-server.ts`):
|
|
7
|
+
*
|
|
8
|
+
* skill-initiated RPC (one-shot)
|
|
9
|
+
* → { id: "s:<n>", method, params? }
|
|
10
|
+
* ← { id: "s:<n>", result } | { id: "s:<n>", error }
|
|
11
|
+
*
|
|
12
|
+
* daemon-initiated RPC (one-shot, requires registered handler)
|
|
13
|
+
* ← { id: "d:<n>", method, params? }
|
|
14
|
+
* → { id: "d:<n>", result } | { id: "d:<n>", error }
|
|
15
|
+
*
|
|
16
|
+
* streaming RPC (e.g. `host.events.subscribe`, skill-initiated only)
|
|
17
|
+
* → { id: "s:<n>", method, params? }
|
|
18
|
+
* ← { id: "s:<n>", result: { subscribed: true } } (open ack)
|
|
19
|
+
* ← { id: "s:<n>", event: "delivery", payload: <data> } (0..N)
|
|
20
|
+
* ← { id: "s:<n>", error } (terminal)
|
|
21
|
+
* → { id: "s:<n>", method: "host.events.subscribe.close",
|
|
22
|
+
* params: { subscribeId: <original-id> } }
|
|
23
|
+
* ← { id: "s:<n>", result: { closed: true } }
|
|
24
|
+
*
|
|
25
|
+
* The `s:` / `d:` id prefixes namespace the two directions so each side can
|
|
26
|
+
* route inbound responses to its own pending-request map without collision.
|
|
27
|
+
*
|
|
28
|
+
* ### Daemon-initiated dispatch handlers
|
|
29
|
+
*
|
|
30
|
+
* After the skill registers tools / routes / shutdown hooks via
|
|
31
|
+
* `registries.registerTools`, `registries.registerSkillRoute`, and
|
|
32
|
+
* `registries.registerShutdownHook`, the client also installs local
|
|
33
|
+
* handlers for the matching `skill.dispatch_*` methods so the daemon can
|
|
34
|
+
* invoke skill-side closures over the bidirectional RPC. The wire shapes
|
|
35
|
+
* are:
|
|
36
|
+
*
|
|
37
|
+
* skill.dispatch_tool
|
|
38
|
+
* daemon → skill: { name: string, input: Record<string, unknown>,
|
|
39
|
+
* context?: unknown }
|
|
40
|
+
* skill → daemon: { result: unknown }
|
|
41
|
+
* errors: throws "unknown tool: <name>" when the tool name is not in
|
|
42
|
+
* the most recently registered provider's output.
|
|
43
|
+
*
|
|
44
|
+
* skill.dispatch_route
|
|
45
|
+
* daemon → skill: { patternSource: string,
|
|
46
|
+
* request: { method: string, url: string,
|
|
47
|
+
* headers?: Record<string, string>,
|
|
48
|
+
* body?: string } }
|
|
49
|
+
* skill → daemon: { status: number,
|
|
50
|
+
* headers: Record<string, string>,
|
|
51
|
+
* body: string }
|
|
52
|
+
* errors: throws "unknown route: <patternSource>" when no registered
|
|
53
|
+
* route matches the patternSource, or "url did not match
|
|
54
|
+
* pattern: <patternSource>" when the regex fails to match.
|
|
55
|
+
*
|
|
56
|
+
* skill.shutdown
|
|
57
|
+
* daemon → skill: { name?: string, reason?: string }
|
|
58
|
+
* skill → daemon: { ok: true }
|
|
59
|
+
* semantics: when `name` is set, runs only that hook; otherwise runs
|
|
60
|
+
* all registered hooks in reverse-registration order. Per-
|
|
61
|
+
* hook errors are swallowed (logged via the host logger if
|
|
62
|
+
* `connect()` has populated one).
|
|
63
|
+
*
|
|
64
|
+
* ### Sync-method bootstrap
|
|
65
|
+
*
|
|
66
|
+
* The `SkillHost` contract exposes a number of synchronous accessors
|
|
67
|
+
* (`identity.internalAssistantId`, `platform.workspaceDir()`,
|
|
68
|
+
* `platform.runtimeMode()`, etc.) that naturally cannot round-trip an async
|
|
69
|
+
* IPC call on every invocation. `connect()` prefetches the stable subset of
|
|
70
|
+
* these values once, caches them locally, and every subsequent sync accessor
|
|
71
|
+
* reads from the cache. Skill code MUST await `connect()` before any
|
|
72
|
+
* synchronous host accessor fires; calling a sync accessor before connect
|
|
73
|
+
* throws a clear "not connected" error.
|
|
74
|
+
*
|
|
75
|
+
* ### Opaque handle methods
|
|
76
|
+
*
|
|
77
|
+
* Several provider accessors on `SkillHost` (`providers.llm.getConfigured`,
|
|
78
|
+
* `providers.llm.userMessage`, `providers.llm.extractToolUse`,
|
|
79
|
+
* `providers.stt.resolveStreamingTranscriber`, `providers.tts.get`,
|
|
80
|
+
* `speakers.createTracker`) return opaque handles whose concrete types live
|
|
81
|
+
* inside `assistant/`. Across IPC they cannot carry the handle's method
|
|
82
|
+
* closures — the skill treats the return value as a black-box token and
|
|
83
|
+
* threads it into `host.providers.llm.complete` / future dispatch routes.
|
|
84
|
+
* The client implements each as a passthrough that returns a tagged
|
|
85
|
+
* descriptor object; the daemon-side handler that ultimately consumes the
|
|
86
|
+
* token narrows it back to the concrete type at its boundary.
|
|
87
|
+
*
|
|
88
|
+
* ### Reconnect
|
|
89
|
+
*
|
|
90
|
+
* When `autoReconnect` is enabled, a lost socket connection is retried with
|
|
91
|
+
* exponential backoff (capped at `reconnectMaxDelayMs`). In-flight requests
|
|
92
|
+
* are rejected with a clear error because no response correlation survives
|
|
93
|
+
* a socket reset; callers are responsible for retrying at a higher level.
|
|
94
|
+
* Long-lived subscriptions are re-opened on reconnect with the same filter
|
|
95
|
+
* so skill-side callbacks keep firing once the socket is back.
|
|
96
|
+
*/
|
|
97
|
+
|
|
98
|
+
import { randomUUID } from "node:crypto";
|
|
99
|
+
import { connect, type Socket } from "node:net";
|
|
100
|
+
|
|
101
|
+
import type { AssistantEvent } from "./assistant-event.js";
|
|
102
|
+
import type { DaemonRuntimeMode } from "./runtime-mode.js";
|
|
103
|
+
import type { ServerMessage } from "./server-message.js";
|
|
104
|
+
import type {
|
|
105
|
+
AssistantEventCallback,
|
|
106
|
+
ConfigFacet,
|
|
107
|
+
EventsFacet,
|
|
108
|
+
Filter,
|
|
109
|
+
IdentityFacet,
|
|
110
|
+
InsertMessageFn,
|
|
111
|
+
LlmProvidersFacet,
|
|
112
|
+
Logger,
|
|
113
|
+
LoggerFacet,
|
|
114
|
+
MemoryFacet,
|
|
115
|
+
PlatformFacet,
|
|
116
|
+
Provider,
|
|
117
|
+
ProvidersFacet,
|
|
118
|
+
RegistriesFacet,
|
|
119
|
+
SecureKeysFacet,
|
|
120
|
+
SkillHost,
|
|
121
|
+
SkillRoute,
|
|
122
|
+
SkillRouteHandle,
|
|
123
|
+
SpeakersFacet,
|
|
124
|
+
SttProvidersFacet,
|
|
125
|
+
Subscription,
|
|
126
|
+
ToolUse,
|
|
127
|
+
TtsConfig,
|
|
128
|
+
TtsProvider,
|
|
129
|
+
TtsProvidersFacet,
|
|
130
|
+
UserMessage,
|
|
131
|
+
} from "./skill-host.js";
|
|
132
|
+
import type { Tool, ToolContext } from "./tool-types.js";
|
|
133
|
+
|
|
134
|
+
// ---------------------------------------------------------------------------
|
|
135
|
+
// Constants
|
|
136
|
+
// ---------------------------------------------------------------------------
|
|
137
|
+
|
|
138
|
+
const SUBSCRIBE_CLOSE_METHOD = "host.events.subscribe.close" as const;
|
|
139
|
+
const DEFAULT_CALL_TIMEOUT_MS = 30_000;
|
|
140
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 3_000;
|
|
141
|
+
const DEFAULT_RECONNECT_BASE_DELAY_MS = 200;
|
|
142
|
+
const DEFAULT_RECONNECT_MAX_DELAY_MS = 10_000;
|
|
143
|
+
|
|
144
|
+
/** Prefix for ids minted by the daemon (server) side. */
|
|
145
|
+
const DAEMON_ID_PREFIX = "d:" as const;
|
|
146
|
+
/** Prefix for ids minted by the skill (client) side. */
|
|
147
|
+
const SKILL_ID_PREFIX = "s:" as const;
|
|
148
|
+
|
|
149
|
+
// ---------------------------------------------------------------------------
|
|
150
|
+
// Wire-format types
|
|
151
|
+
// ---------------------------------------------------------------------------
|
|
152
|
+
|
|
153
|
+
type IpcRequest = {
|
|
154
|
+
id: string;
|
|
155
|
+
method: string;
|
|
156
|
+
params?: Record<string, unknown>;
|
|
157
|
+
};
|
|
158
|
+
|
|
159
|
+
type IpcResponseFrame = {
|
|
160
|
+
id: string;
|
|
161
|
+
method?: string;
|
|
162
|
+
params?: unknown;
|
|
163
|
+
result?: unknown;
|
|
164
|
+
error?: string;
|
|
165
|
+
event?: "delivery";
|
|
166
|
+
payload?: unknown;
|
|
167
|
+
};
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Handler for a daemon-initiated request. Returning a value (or a Promise)
|
|
171
|
+
* resolves the daemon's `sendRequest` call; throwing rejects it with the
|
|
172
|
+
* thrown error's message. Synchronous returns are wrapped automatically.
|
|
173
|
+
*/
|
|
174
|
+
export type SkillHostRequestHandler = (
|
|
175
|
+
params: unknown,
|
|
176
|
+
) => unknown | Promise<unknown>;
|
|
177
|
+
|
|
178
|
+
// ---------------------------------------------------------------------------
|
|
179
|
+
// Public options
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
|
|
182
|
+
export interface SkillHostClientOptions {
|
|
183
|
+
/** Absolute path to the `assistant-skill.sock` Unix domain socket. */
|
|
184
|
+
socketPath: string;
|
|
185
|
+
/**
|
|
186
|
+
* Identifier for the owning skill. Sent as the default logger-scope name
|
|
187
|
+
* when `logger.get(name)` is not explicitly scoped, and reserved for
|
|
188
|
+
* future per-skill routing at the daemon boundary.
|
|
189
|
+
*/
|
|
190
|
+
skillId: string;
|
|
191
|
+
/**
|
|
192
|
+
* Automatically reconnect the underlying socket when it drops. Existing
|
|
193
|
+
* subscriptions are reopened with the same filter; in-flight one-shot
|
|
194
|
+
* requests are rejected with a "connection lost" error.
|
|
195
|
+
*
|
|
196
|
+
* @default false
|
|
197
|
+
*/
|
|
198
|
+
autoReconnect?: boolean;
|
|
199
|
+
/** Initial retry delay (ms). Exponentially backs off to the max. */
|
|
200
|
+
reconnectBaseDelayMs?: number;
|
|
201
|
+
/** Maximum retry delay (ms). */
|
|
202
|
+
reconnectMaxDelayMs?: number;
|
|
203
|
+
/** Per-call timeout for one-shot RPCs. */
|
|
204
|
+
callTimeoutMs?: number;
|
|
205
|
+
/** Socket `connect()` timeout. */
|
|
206
|
+
connectTimeoutMs?: number;
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
// ---------------------------------------------------------------------------
|
|
210
|
+
// Internal state for pending calls and subscriptions
|
|
211
|
+
// ---------------------------------------------------------------------------
|
|
212
|
+
|
|
213
|
+
interface PendingCall {
|
|
214
|
+
resolve: (value: unknown) => void;
|
|
215
|
+
reject: (err: Error) => void;
|
|
216
|
+
timer: ReturnType<typeof setTimeout>;
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
interface ActiveSubscription {
|
|
220
|
+
id: string;
|
|
221
|
+
filter: Filter;
|
|
222
|
+
callback: AssistantEventCallback;
|
|
223
|
+
disposed: boolean;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ---------------------------------------------------------------------------
|
|
227
|
+
// Helpers
|
|
228
|
+
// ---------------------------------------------------------------------------
|
|
229
|
+
|
|
230
|
+
function notConnected(): Error {
|
|
231
|
+
return new Error(
|
|
232
|
+
"SkillHostClient: not connected. Call `await client.connect()` before using synchronous host accessors.",
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Wraps a sync logger call so a host.log RPC failure never throws at the
|
|
238
|
+
* call site — skills treat logging as side-effectful and don't want a
|
|
239
|
+
* transient socket issue to abort whatever they were doing.
|
|
240
|
+
*/
|
|
241
|
+
function swallow(err: unknown): void {
|
|
242
|
+
// Intentional no-op; logging here would recurse into the same broken
|
|
243
|
+
// logger. The stderr path is a deliberate last-resort sink.
|
|
244
|
+
if (err && process.env.SKILL_HOST_CLIENT_DEBUG) {
|
|
245
|
+
// eslint-disable-next-line no-console
|
|
246
|
+
console.error("[SkillHostClient] log RPC failed:", err);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
/**
|
|
251
|
+
* Stringify an unknown error value for the wire — `Error.message` when
|
|
252
|
+
* available, otherwise `String(err)` so non-Error throws still surface
|
|
253
|
+
* something readable on the daemon side.
|
|
254
|
+
*/
|
|
255
|
+
function errorMessage(err: unknown): string {
|
|
256
|
+
if (err instanceof Error) return err.message;
|
|
257
|
+
return String(err);
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// ---------------------------------------------------------------------------
|
|
261
|
+
// Client implementation
|
|
262
|
+
// ---------------------------------------------------------------------------
|
|
263
|
+
|
|
264
|
+
export class SkillHostClient implements SkillHost {
|
|
265
|
+
// Facets are populated in the constructor so every `SkillHost` method
|
|
266
|
+
// has a concrete target even before `connect()` resolves. Sync methods
|
|
267
|
+
// that depend on prefetched state throw `notConnected()` until then.
|
|
268
|
+
readonly logger: LoggerFacet;
|
|
269
|
+
readonly config: ConfigFacet;
|
|
270
|
+
readonly identity: IdentityFacet;
|
|
271
|
+
readonly platform: PlatformFacet;
|
|
272
|
+
readonly providers: ProvidersFacet;
|
|
273
|
+
readonly memory: MemoryFacet;
|
|
274
|
+
readonly events: EventsFacet;
|
|
275
|
+
readonly registries: RegistriesFacet;
|
|
276
|
+
readonly speakers: SpeakersFacet;
|
|
277
|
+
|
|
278
|
+
private readonly options: Required<
|
|
279
|
+
Pick<
|
|
280
|
+
SkillHostClientOptions,
|
|
281
|
+
| "socketPath"
|
|
282
|
+
| "skillId"
|
|
283
|
+
| "callTimeoutMs"
|
|
284
|
+
| "connectTimeoutMs"
|
|
285
|
+
| "reconnectBaseDelayMs"
|
|
286
|
+
| "reconnectMaxDelayMs"
|
|
287
|
+
>
|
|
288
|
+
> & { autoReconnect: boolean };
|
|
289
|
+
|
|
290
|
+
private socket: Socket | null = null;
|
|
291
|
+
private buffer = "";
|
|
292
|
+
private readonly pending = new Map<string, PendingCall>();
|
|
293
|
+
private readonly subscriptions = new Map<string, ActiveSubscription>();
|
|
294
|
+
private connectingPromise: Promise<void> | null = null;
|
|
295
|
+
private closed = false;
|
|
296
|
+
private reconnectAttempt = 0;
|
|
297
|
+
/**
|
|
298
|
+
* Monotonic counter for skill-initiated request ids, formatted as
|
|
299
|
+
* `s:<n>`. The daemon mints `d:<n>` ids independently, so the two
|
|
300
|
+
* sequences never collide on a shared socket.
|
|
301
|
+
*/
|
|
302
|
+
private nextSkillRequestSeq = 1;
|
|
303
|
+
/**
|
|
304
|
+
* Handlers for daemon-initiated requests, keyed by method name. Populated
|
|
305
|
+
* via `registerHandler(method, handler)`. Daemon→skill request frames
|
|
306
|
+
* (id starts with `d:`) are dispatched through this table.
|
|
307
|
+
*/
|
|
308
|
+
private readonly daemonRequestHandlers = new Map<
|
|
309
|
+
string,
|
|
310
|
+
SkillHostRequestHandler
|
|
311
|
+
>();
|
|
312
|
+
|
|
313
|
+
// Prefetched sync state — populated by `connect()`.
|
|
314
|
+
private cachedInternalAssistantId: string | null = null;
|
|
315
|
+
private cachedAssistantName: string | undefined = undefined;
|
|
316
|
+
private cachedWorkspaceDir: string | null = null;
|
|
317
|
+
private cachedVellumRoot: string | null = null;
|
|
318
|
+
private cachedRuntimeMode: DaemonRuntimeMode | null = null;
|
|
319
|
+
|
|
320
|
+
// ── Local dispatch state ────────────────────────────────────────────────
|
|
321
|
+
// Caches populated by `registries.register*` so the daemon can dispatch
|
|
322
|
+
// skill-owned closures back over the bidirectional RPC. Mirrors what the
|
|
323
|
+
// out-of-process skill installed in-process before the IPC split.
|
|
324
|
+
|
|
325
|
+
/** Most recently registered tool provider (last writer wins, matching the in-process semantics where a single skill module owns one provider). */
|
|
326
|
+
private cachedToolsProvider: (() => Tool[]) | null = null;
|
|
327
|
+
/**
|
|
328
|
+
* Routes keyed by `pattern.source`. Last writer wins on collision so
|
|
329
|
+
* re-registering the same regex source replaces the prior handler — mirrors
|
|
330
|
+
* how an in-process skill would re-`registerSkillRoute` on hot reload.
|
|
331
|
+
*/
|
|
332
|
+
private readonly cachedRoutes = new Map<string, SkillRoute>();
|
|
333
|
+
/**
|
|
334
|
+
* Shutdown hooks ordered by registration time. We use an array (not a Map
|
|
335
|
+
* keyed by name) because the spec requires running hooks in reverse-
|
|
336
|
+
* registration order when no name is provided. Re-registering an existing
|
|
337
|
+
* name replaces the prior entry in place to keep the cache idempotent.
|
|
338
|
+
*/
|
|
339
|
+
private readonly cachedShutdownHooks: Array<{
|
|
340
|
+
name: string;
|
|
341
|
+
hook: (reason: string) => Promise<void>;
|
|
342
|
+
}> = [];
|
|
343
|
+
|
|
344
|
+
constructor(options: SkillHostClientOptions) {
|
|
345
|
+
this.options = {
|
|
346
|
+
socketPath: options.socketPath,
|
|
347
|
+
skillId: options.skillId,
|
|
348
|
+
autoReconnect: options.autoReconnect ?? false,
|
|
349
|
+
callTimeoutMs: options.callTimeoutMs ?? DEFAULT_CALL_TIMEOUT_MS,
|
|
350
|
+
connectTimeoutMs: options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS,
|
|
351
|
+
reconnectBaseDelayMs:
|
|
352
|
+
options.reconnectBaseDelayMs ?? DEFAULT_RECONNECT_BASE_DELAY_MS,
|
|
353
|
+
reconnectMaxDelayMs:
|
|
354
|
+
options.reconnectMaxDelayMs ?? DEFAULT_RECONNECT_MAX_DELAY_MS,
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
this.logger = this.buildLoggerFacet();
|
|
358
|
+
this.config = this.buildConfigFacet();
|
|
359
|
+
this.identity = this.buildIdentityFacet();
|
|
360
|
+
this.platform = this.buildPlatformFacet();
|
|
361
|
+
this.providers = this.buildProvidersFacet();
|
|
362
|
+
this.memory = this.buildMemoryFacet();
|
|
363
|
+
this.events = this.buildEventsFacet();
|
|
364
|
+
this.registries = this.buildRegistriesFacet();
|
|
365
|
+
this.speakers = this.buildSpeakersFacet();
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
// ── Public lifecycle ────────────────────────────────────────────────────
|
|
369
|
+
|
|
370
|
+
/**
|
|
371
|
+
* Connect to the skill IPC socket and prefetch sync-cacheable state
|
|
372
|
+
* (assistant id, workspace dir, vellum root, runtime mode, assistant
|
|
373
|
+
* name). Safe to call multiple times — the first call initiates the
|
|
374
|
+
* connection, concurrent calls await the same promise.
|
|
375
|
+
*/
|
|
376
|
+
async connect(): Promise<void> {
|
|
377
|
+
if (this.closed) {
|
|
378
|
+
throw new Error("SkillHostClient: cannot connect after close()");
|
|
379
|
+
}
|
|
380
|
+
if (this.connectingPromise) return this.connectingPromise;
|
|
381
|
+
// Fully connected: live socket *and* prefetch already populated.
|
|
382
|
+
// If the socket survived but a prior `prefetchSyncState()` rejected,
|
|
383
|
+
// the caches are still null and sync accessors would throw — fall
|
|
384
|
+
// through and re-run prefetch over the existing socket.
|
|
385
|
+
const socketAlive = !!this.socket && !this.socket.destroyed;
|
|
386
|
+
const prefetchDone = this.cachedInternalAssistantId !== null;
|
|
387
|
+
if (socketAlive && prefetchDone) return;
|
|
388
|
+
|
|
389
|
+
const ensureSocket = socketAlive ? Promise.resolve() : this.doConnect();
|
|
390
|
+
this.connectingPromise = ensureSocket
|
|
391
|
+
.then(async () => {
|
|
392
|
+
await this.prefetchSyncState();
|
|
393
|
+
})
|
|
394
|
+
.finally(() => {
|
|
395
|
+
this.connectingPromise = null;
|
|
396
|
+
});
|
|
397
|
+
return this.connectingPromise;
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Close the socket, reject outstanding calls, and dispose all active
|
|
402
|
+
* subscriptions. Safe to call multiple times.
|
|
403
|
+
*/
|
|
404
|
+
close(): void {
|
|
405
|
+
if (this.closed) return;
|
|
406
|
+
this.closed = true;
|
|
407
|
+
// Mark every subscription disposed so stray deliveries during teardown
|
|
408
|
+
// don't fire user callbacks.
|
|
409
|
+
for (const sub of this.subscriptions.values()) {
|
|
410
|
+
sub.disposed = true;
|
|
411
|
+
}
|
|
412
|
+
this.subscriptions.clear();
|
|
413
|
+
// Reject any in-flight calls.
|
|
414
|
+
const closeErr = new Error(
|
|
415
|
+
"SkillHostClient: client closed while request was in flight",
|
|
416
|
+
);
|
|
417
|
+
for (const { reject, timer } of this.pending.values()) {
|
|
418
|
+
clearTimeout(timer);
|
|
419
|
+
reject(closeErr);
|
|
420
|
+
}
|
|
421
|
+
this.pending.clear();
|
|
422
|
+
if (this.socket && !this.socket.destroyed) {
|
|
423
|
+
this.socket.destroy();
|
|
424
|
+
}
|
|
425
|
+
this.socket = null;
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
/**
|
|
429
|
+
* Install a handler for daemon-initiated requests of the given method.
|
|
430
|
+
* The daemon's `SkillIpcServer.sendRequest(connection, method, ...)`
|
|
431
|
+
* resolves with whatever the handler returns (or rejects with the
|
|
432
|
+
* handler's thrown error). Re-registering a method replaces the prior
|
|
433
|
+
* handler — last writer wins.
|
|
434
|
+
*/
|
|
435
|
+
registerHandler(method: string, handler: SkillHostRequestHandler): void {
|
|
436
|
+
this.daemonRequestHandlers.set(method, handler);
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// ── Internal: socket lifecycle ──────────────────────────────────────────
|
|
440
|
+
|
|
441
|
+
private async doConnect(): Promise<void> {
|
|
442
|
+
const { socketPath, connectTimeoutMs } = this.options;
|
|
443
|
+
return new Promise<void>((resolve, reject) => {
|
|
444
|
+
const socket = connect(socketPath);
|
|
445
|
+
let settled = false;
|
|
446
|
+
|
|
447
|
+
const timer = setTimeout(() => {
|
|
448
|
+
if (settled) return;
|
|
449
|
+
settled = true;
|
|
450
|
+
socket.destroy();
|
|
451
|
+
reject(
|
|
452
|
+
new Error(
|
|
453
|
+
`SkillHostClient: connect timed out after ${connectTimeoutMs}ms (${socketPath})`,
|
|
454
|
+
),
|
|
455
|
+
);
|
|
456
|
+
}, connectTimeoutMs);
|
|
457
|
+
|
|
458
|
+
socket.once("connect", () => {
|
|
459
|
+
if (settled) return;
|
|
460
|
+
settled = true;
|
|
461
|
+
clearTimeout(timer);
|
|
462
|
+
// The client may have been `close()`d while `connect()` was
|
|
463
|
+
// still pending. If we attach now we'd reintroduce a live
|
|
464
|
+
// socket on a closed client and leak the server-side connection
|
|
465
|
+
// until process teardown.
|
|
466
|
+
if (this.closed) {
|
|
467
|
+
socket.destroy();
|
|
468
|
+
reject(new Error("SkillHostClient: closed during connect"));
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
this.attachSocket(socket);
|
|
472
|
+
resolve();
|
|
473
|
+
});
|
|
474
|
+
|
|
475
|
+
socket.once("error", (err) => {
|
|
476
|
+
if (settled) return;
|
|
477
|
+
settled = true;
|
|
478
|
+
clearTimeout(timer);
|
|
479
|
+
reject(
|
|
480
|
+
new Error(
|
|
481
|
+
`SkillHostClient: socket error during connect: ${err.message}`,
|
|
482
|
+
),
|
|
483
|
+
);
|
|
484
|
+
});
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
private attachSocket(socket: Socket): void {
|
|
489
|
+
this.socket = socket;
|
|
490
|
+
this.buffer = "";
|
|
491
|
+
this.reconnectAttempt = 0;
|
|
492
|
+
|
|
493
|
+
socket.on("data", (chunk) => {
|
|
494
|
+
this.buffer += chunk.toString();
|
|
495
|
+
let newlineIdx: number;
|
|
496
|
+
while ((newlineIdx = this.buffer.indexOf("\n")) !== -1) {
|
|
497
|
+
const line = this.buffer.slice(0, newlineIdx).trim();
|
|
498
|
+
this.buffer = this.buffer.slice(newlineIdx + 1);
|
|
499
|
+
if (line) this.handleFrame(line);
|
|
500
|
+
}
|
|
501
|
+
});
|
|
502
|
+
|
|
503
|
+
socket.on("close", () => {
|
|
504
|
+
this.socket = null;
|
|
505
|
+
const err = new Error(
|
|
506
|
+
"SkillHostClient: socket closed before response",
|
|
507
|
+
);
|
|
508
|
+
for (const { reject, timer } of this.pending.values()) {
|
|
509
|
+
clearTimeout(timer);
|
|
510
|
+
reject(err);
|
|
511
|
+
}
|
|
512
|
+
this.pending.clear();
|
|
513
|
+
if (!this.closed && this.options.autoReconnect) {
|
|
514
|
+
void this.scheduleReconnect();
|
|
515
|
+
}
|
|
516
|
+
});
|
|
517
|
+
|
|
518
|
+
socket.on("error", (err) => {
|
|
519
|
+
swallow(err);
|
|
520
|
+
});
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
private async scheduleReconnect(): Promise<void> {
|
|
524
|
+
if (this.closed) return;
|
|
525
|
+
this.reconnectAttempt += 1;
|
|
526
|
+
const delay = Math.min(
|
|
527
|
+
this.options.reconnectBaseDelayMs *
|
|
528
|
+
Math.pow(2, this.reconnectAttempt - 1),
|
|
529
|
+
this.options.reconnectMaxDelayMs,
|
|
530
|
+
);
|
|
531
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
532
|
+
if (this.closed) return;
|
|
533
|
+
try {
|
|
534
|
+
await this.doConnect();
|
|
535
|
+
// Re-open every live subscription with a fresh request so the
|
|
536
|
+
// server-side hub installs a new callback.
|
|
537
|
+
const live = [...this.subscriptions.values()].filter((s) => !s.disposed);
|
|
538
|
+
this.subscriptions.clear();
|
|
539
|
+
for (const sub of live) {
|
|
540
|
+
this.reopenSubscription(sub);
|
|
541
|
+
}
|
|
542
|
+
} catch (err) {
|
|
543
|
+
swallow(err);
|
|
544
|
+
if (!this.closed) {
|
|
545
|
+
void this.scheduleReconnect();
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
private reopenSubscription(prev: ActiveSubscription): void {
|
|
551
|
+
// Same id so the application-visible Subscription handle still works.
|
|
552
|
+
const fresh: ActiveSubscription = {
|
|
553
|
+
id: prev.id,
|
|
554
|
+
filter: prev.filter,
|
|
555
|
+
callback: prev.callback,
|
|
556
|
+
disposed: false,
|
|
557
|
+
};
|
|
558
|
+
this.subscriptions.set(fresh.id, fresh);
|
|
559
|
+
// Mirror `openSubscription`: pre-register a pending entry so the
|
|
560
|
+
// server's `{ id, result: { subscribed: true } }` ack frame is
|
|
561
|
+
// matched (otherwise `handleFrame` silently drops it) and so we
|
|
562
|
+
// tear the subscription down on ack timeout instead of leaking it.
|
|
563
|
+
this.registerSubscribeAck(fresh);
|
|
564
|
+
try {
|
|
565
|
+
this.writeFrame({
|
|
566
|
+
id: fresh.id,
|
|
567
|
+
method: "host.events.subscribe",
|
|
568
|
+
params: { filter: fresh.filter },
|
|
569
|
+
});
|
|
570
|
+
} catch (err) {
|
|
571
|
+
this.cancelSubscribeAck(fresh);
|
|
572
|
+
swallow(err);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
private registerSubscribeAck(active: ActiveSubscription): void {
|
|
577
|
+
const ackTimer = setTimeout(() => {
|
|
578
|
+
if (this.pending.delete(active.id)) {
|
|
579
|
+
active.disposed = true;
|
|
580
|
+
this.subscriptions.delete(active.id);
|
|
581
|
+
}
|
|
582
|
+
}, this.options.callTimeoutMs);
|
|
583
|
+
this.pending.set(active.id, {
|
|
584
|
+
resolve: () => {
|
|
585
|
+
clearTimeout(ackTimer);
|
|
586
|
+
},
|
|
587
|
+
reject: (err) => {
|
|
588
|
+
clearTimeout(ackTimer);
|
|
589
|
+
active.disposed = true;
|
|
590
|
+
this.subscriptions.delete(active.id);
|
|
591
|
+
swallow(err);
|
|
592
|
+
},
|
|
593
|
+
timer: ackTimer,
|
|
594
|
+
});
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
private cancelSubscribeAck(active: ActiveSubscription): void {
|
|
598
|
+
const entry = this.pending.get(active.id);
|
|
599
|
+
if (entry) {
|
|
600
|
+
clearTimeout(entry.timer);
|
|
601
|
+
this.pending.delete(active.id);
|
|
602
|
+
}
|
|
603
|
+
active.disposed = true;
|
|
604
|
+
this.subscriptions.delete(active.id);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// ── Internal: frame I/O ─────────────────────────────────────────────────
|
|
608
|
+
|
|
609
|
+
private handleFrame(line: string): void {
|
|
610
|
+
let frame: IpcResponseFrame;
|
|
611
|
+
try {
|
|
612
|
+
frame = JSON.parse(line) as IpcResponseFrame;
|
|
613
|
+
} catch (err) {
|
|
614
|
+
swallow(err);
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (
|
|
619
|
+
!frame ||
|
|
620
|
+
typeof frame !== "object" ||
|
|
621
|
+
Array.isArray(frame) ||
|
|
622
|
+
typeof frame.id !== "string"
|
|
623
|
+
) {
|
|
624
|
+
return;
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
// Delivery frames route into the subscription callback.
|
|
628
|
+
if (frame.event === "delivery") {
|
|
629
|
+
const sub = this.subscriptions.get(frame.id);
|
|
630
|
+
if (sub && !sub.disposed) {
|
|
631
|
+
try {
|
|
632
|
+
const r = sub.callback(frame.payload as AssistantEvent);
|
|
633
|
+
if (r instanceof Promise) r.catch(swallow);
|
|
634
|
+
} catch (err) {
|
|
635
|
+
swallow(err);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
return;
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
// Daemon-initiated request frame — dispatch to a registered handler
|
|
642
|
+
// and write back the response. Identified by the `d:` id prefix and
|
|
643
|
+
// the presence of a `method` field.
|
|
644
|
+
if (
|
|
645
|
+
typeof frame.method === "string" &&
|
|
646
|
+
frame.id.startsWith(DAEMON_ID_PREFIX)
|
|
647
|
+
) {
|
|
648
|
+
this.dispatchDaemonRequest(frame.id, frame.method, frame.params);
|
|
649
|
+
return;
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// Response frame — resolve or reject the pending call.
|
|
653
|
+
const pending = this.pending.get(frame.id);
|
|
654
|
+
if (pending) {
|
|
655
|
+
this.pending.delete(frame.id);
|
|
656
|
+
clearTimeout(pending.timer);
|
|
657
|
+
if (frame.error !== undefined) {
|
|
658
|
+
pending.reject(
|
|
659
|
+
new Error(`SkillHostClient: remote error: ${frame.error}`),
|
|
660
|
+
);
|
|
661
|
+
} else {
|
|
662
|
+
pending.resolve(frame.result);
|
|
663
|
+
}
|
|
664
|
+
return;
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
// No pending entry — could be a terminal error on a subscription.
|
|
668
|
+
if (frame.error !== undefined) {
|
|
669
|
+
const sub = this.subscriptions.get(frame.id);
|
|
670
|
+
if (sub) {
|
|
671
|
+
sub.disposed = true;
|
|
672
|
+
this.subscriptions.delete(frame.id);
|
|
673
|
+
}
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
private dispatchDaemonRequest(
|
|
678
|
+
id: string,
|
|
679
|
+
method: string,
|
|
680
|
+
params: unknown,
|
|
681
|
+
): void {
|
|
682
|
+
const handler = this.daemonRequestHandlers.get(method);
|
|
683
|
+
if (!handler) {
|
|
684
|
+
this.writeResponseFrame({
|
|
685
|
+
id,
|
|
686
|
+
error: `method not found: ${method}`,
|
|
687
|
+
});
|
|
688
|
+
return;
|
|
689
|
+
}
|
|
690
|
+
let result: unknown;
|
|
691
|
+
try {
|
|
692
|
+
result = handler(params);
|
|
693
|
+
} catch (err) {
|
|
694
|
+
this.writeResponseFrame({ id, error: errorMessage(err) });
|
|
695
|
+
return;
|
|
696
|
+
}
|
|
697
|
+
if (result instanceof Promise) {
|
|
698
|
+
result.then(
|
|
699
|
+
(value) => {
|
|
700
|
+
this.writeResponseFrame({ id, result: value });
|
|
701
|
+
},
|
|
702
|
+
(err) => {
|
|
703
|
+
this.writeResponseFrame({ id, error: errorMessage(err) });
|
|
704
|
+
},
|
|
705
|
+
);
|
|
706
|
+
} else {
|
|
707
|
+
this.writeResponseFrame({ id, result });
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private writeResponseFrame(response: {
|
|
712
|
+
id: string;
|
|
713
|
+
result?: unknown;
|
|
714
|
+
error?: string;
|
|
715
|
+
}): void {
|
|
716
|
+
if (!this.socket || this.socket.destroyed) {
|
|
717
|
+
// The peer is gone; silently drop. The daemon-side pending entry
|
|
718
|
+
// will already have been rejected by the connection-close path.
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
this.socket.write(JSON.stringify(response) + "\n");
|
|
722
|
+
}
|
|
723
|
+
|
|
724
|
+
private writeFrame(req: IpcRequest): void {
|
|
725
|
+
if (!this.socket || this.socket.destroyed) {
|
|
726
|
+
throw new Error("SkillHostClient: not connected");
|
|
727
|
+
}
|
|
728
|
+
this.socket.write(JSON.stringify(req) + "\n");
|
|
729
|
+
}
|
|
730
|
+
|
|
731
|
+
/** Allocate the next `s:<n>` id for a skill-initiated request. */
|
|
732
|
+
private nextSkillRequestId(): string {
|
|
733
|
+
return `${SKILL_ID_PREFIX}${this.nextSkillRequestSeq++}`;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
private async call<T>(
|
|
737
|
+
method: string,
|
|
738
|
+
params?: Record<string, unknown>,
|
|
739
|
+
): Promise<T> {
|
|
740
|
+
if (this.closed) {
|
|
741
|
+
throw new Error("SkillHostClient: client is closed");
|
|
742
|
+
}
|
|
743
|
+
if (!this.socket || this.socket.destroyed) {
|
|
744
|
+
throw new Error(
|
|
745
|
+
"SkillHostClient: not connected. Call `await client.connect()` first.",
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
const id = this.nextSkillRequestId();
|
|
749
|
+
return new Promise<T>((resolve, reject) => {
|
|
750
|
+
const timer = setTimeout(() => {
|
|
751
|
+
if (this.pending.delete(id)) {
|
|
752
|
+
reject(
|
|
753
|
+
new Error(
|
|
754
|
+
`SkillHostClient: call '${method}' timed out after ${this.options.callTimeoutMs}ms`,
|
|
755
|
+
),
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
}, this.options.callTimeoutMs);
|
|
759
|
+
this.pending.set(id, {
|
|
760
|
+
resolve: (v) => resolve(v as T),
|
|
761
|
+
reject,
|
|
762
|
+
timer,
|
|
763
|
+
});
|
|
764
|
+
try {
|
|
765
|
+
this.writeFrame({ id, method, params });
|
|
766
|
+
} catch (err) {
|
|
767
|
+
this.pending.delete(id);
|
|
768
|
+
clearTimeout(timer);
|
|
769
|
+
reject(err as Error);
|
|
770
|
+
}
|
|
771
|
+
});
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
// ── Internal: bootstrap cache ───────────────────────────────────────────
|
|
775
|
+
|
|
776
|
+
private async prefetchSyncState(): Promise<void> {
|
|
777
|
+
const [assistantId, workspaceDir, vellumRootValue, runtimeMode, name] =
|
|
778
|
+
await Promise.all([
|
|
779
|
+
this.call<string>("host.identity.getInternalAssistantId"),
|
|
780
|
+
this.call<string>("host.platform.workspaceDir"),
|
|
781
|
+
this.call<string>("host.platform.vellumRoot"),
|
|
782
|
+
this.call<DaemonRuntimeMode>("host.platform.runtimeMode"),
|
|
783
|
+
this.call<string | null>("host.identity.getAssistantName"),
|
|
784
|
+
]);
|
|
785
|
+
this.cachedInternalAssistantId = assistantId;
|
|
786
|
+
this.cachedWorkspaceDir = workspaceDir;
|
|
787
|
+
this.cachedVellumRoot = vellumRootValue;
|
|
788
|
+
this.cachedRuntimeMode = runtimeMode;
|
|
789
|
+
this.cachedAssistantName = name ?? undefined;
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
// ── Facet builders ──────────────────────────────────────────────────────
|
|
793
|
+
|
|
794
|
+
private buildLogger(name: string): Logger {
|
|
795
|
+
const scope = name || this.options.skillId;
|
|
796
|
+
const write = (
|
|
797
|
+
level: "debug" | "info" | "warn" | "error",
|
|
798
|
+
msg: string,
|
|
799
|
+
meta?: unknown,
|
|
800
|
+
) => {
|
|
801
|
+
// Fire-and-forget: skills expect logging to be non-blocking and
|
|
802
|
+
// infallible. If the socket is down we just drop the line.
|
|
803
|
+
this.call("host.log", { level, msg, name: scope, meta }).catch(swallow);
|
|
804
|
+
};
|
|
805
|
+
return {
|
|
806
|
+
debug: (msg, meta) => write("debug", msg, meta),
|
|
807
|
+
info: (msg, meta) => write("info", msg, meta),
|
|
808
|
+
warn: (msg, meta) => write("warn", msg, meta),
|
|
809
|
+
error: (msg, meta) => write("error", msg, meta),
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
private buildLoggerFacet(): LoggerFacet {
|
|
814
|
+
return {
|
|
815
|
+
get: (name) => this.buildLogger(name),
|
|
816
|
+
};
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
private buildConfigFacet(): ConfigFacet {
|
|
820
|
+
return {
|
|
821
|
+
// `isFeatureFlagEnabled` and `getSection` are typed as sync on the
|
|
822
|
+
// contract but require a round-trip to resolve. We cannot block on
|
|
823
|
+
// async I/O inside a sync accessor, so the client surfaces the
|
|
824
|
+
// async semantics by returning a stale-safe value if one has been
|
|
825
|
+
// cached via `prefetchFlag` / `prefetchSection` helpers (future
|
|
826
|
+
// work) — for now, these throw a clear error so skill code that
|
|
827
|
+
// ever reaches them on the client path is audible instead of
|
|
828
|
+
// silently returning a wrong value. Async callers should use the
|
|
829
|
+
// underlying IPC method names directly via `rawCall`.
|
|
830
|
+
isFeatureFlagEnabled: (_key: string): boolean => {
|
|
831
|
+
throw new Error(
|
|
832
|
+
"SkillHostClient.config.isFeatureFlagEnabled: synchronous feature-flag reads are not supported over IPC. Use `client.rawCall('host.config.isFeatureFlagEnabled', { key })` and await the result.",
|
|
833
|
+
);
|
|
834
|
+
},
|
|
835
|
+
getSection: <T>(_path: string): T | undefined => {
|
|
836
|
+
throw new Error(
|
|
837
|
+
"SkillHostClient.config.getSection: synchronous config reads are not supported over IPC. Use `client.rawCall('host.config.getSection', { path })` and await the result.",
|
|
838
|
+
);
|
|
839
|
+
},
|
|
840
|
+
};
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
private buildIdentityFacet(): IdentityFacet {
|
|
844
|
+
const self = this;
|
|
845
|
+
return {
|
|
846
|
+
getAssistantName: () => {
|
|
847
|
+
if (self.cachedInternalAssistantId === null) throw notConnected();
|
|
848
|
+
return self.cachedAssistantName;
|
|
849
|
+
},
|
|
850
|
+
get internalAssistantId(): string {
|
|
851
|
+
if (self.cachedInternalAssistantId === null) throw notConnected();
|
|
852
|
+
return self.cachedInternalAssistantId;
|
|
853
|
+
},
|
|
854
|
+
};
|
|
855
|
+
}
|
|
856
|
+
|
|
857
|
+
private buildPlatformFacet(): PlatformFacet {
|
|
858
|
+
return {
|
|
859
|
+
workspaceDir: () => {
|
|
860
|
+
if (this.cachedWorkspaceDir === null) throw notConnected();
|
|
861
|
+
return this.cachedWorkspaceDir;
|
|
862
|
+
},
|
|
863
|
+
vellumRoot: () => {
|
|
864
|
+
if (this.cachedVellumRoot === null) throw notConnected();
|
|
865
|
+
return this.cachedVellumRoot;
|
|
866
|
+
},
|
|
867
|
+
runtimeMode: () => {
|
|
868
|
+
if (this.cachedRuntimeMode === null) throw notConnected();
|
|
869
|
+
return this.cachedRuntimeMode;
|
|
870
|
+
},
|
|
871
|
+
};
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
private buildLlmProvidersFacet(): LlmProvidersFacet {
|
|
875
|
+
// The provider, user-message, and tool-use values are opaque tokens on
|
|
876
|
+
// the contract; the client synthesizes structurally inert descriptors
|
|
877
|
+
// that round-trip through future dispatch routes.
|
|
878
|
+
return {
|
|
879
|
+
getConfigured: async (callSite: string): Promise<Provider | null> =>
|
|
880
|
+
({
|
|
881
|
+
__vellumSkillHostClientHandle: "llm-provider",
|
|
882
|
+
callSite,
|
|
883
|
+
}) as unknown as Provider,
|
|
884
|
+
userMessage: (text: string): UserMessage =>
|
|
885
|
+
({
|
|
886
|
+
__vellumSkillHostClientHandle: "user-message",
|
|
887
|
+
text,
|
|
888
|
+
}) as unknown as UserMessage,
|
|
889
|
+
extractToolUse: (_response: unknown): ToolUse | null => {
|
|
890
|
+
// The client cannot inspect daemon-shaped completion responses
|
|
891
|
+
// without pulling in the Anthropic SDK types; skills that need
|
|
892
|
+
// typed tool-use extraction should do it via the completion's
|
|
893
|
+
// `content` array directly. Return null as the conservative
|
|
894
|
+
// "no tool_use" answer.
|
|
895
|
+
return null;
|
|
896
|
+
},
|
|
897
|
+
createTimeout: (ms: number) => {
|
|
898
|
+
const controller = new AbortController();
|
|
899
|
+
const timer = setTimeout(() => controller.abort(), ms);
|
|
900
|
+
return {
|
|
901
|
+
signal: controller.signal,
|
|
902
|
+
cleanup: () => clearTimeout(timer),
|
|
903
|
+
};
|
|
904
|
+
},
|
|
905
|
+
};
|
|
906
|
+
}
|
|
907
|
+
|
|
908
|
+
private buildSttProvidersFacet(): SttProvidersFacet {
|
|
909
|
+
// stt sub-facet exposes two pure-data queries and one opaque-handle
|
|
910
|
+
// builder. The data queries would require async fetches; we expose
|
|
911
|
+
// them synchronously via the same "call rawCall" pattern the config
|
|
912
|
+
// facet uses.
|
|
913
|
+
return {
|
|
914
|
+
listProviderIds: (): string[] => {
|
|
915
|
+
throw new Error(
|
|
916
|
+
"SkillHostClient.providers.stt.listProviderIds: use `client.rawCall('host.providers.stt.listProviderIds')` and await the result.",
|
|
917
|
+
);
|
|
918
|
+
},
|
|
919
|
+
supportsBoundary: (_id: string): boolean => {
|
|
920
|
+
throw new Error(
|
|
921
|
+
"SkillHostClient.providers.stt.supportsBoundary: use `client.rawCall('host.providers.stt.supportsBoundary', { id, boundary: 'daemon-streaming' })` and await the result.",
|
|
922
|
+
);
|
|
923
|
+
},
|
|
924
|
+
resolveStreamingTranscriber: async (spec: unknown) =>
|
|
925
|
+
({
|
|
926
|
+
__vellumSkillHostClientHandle: "streaming-transcriber",
|
|
927
|
+
spec,
|
|
928
|
+
}) as unknown,
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
private buildTtsProvidersFacet(): TtsProvidersFacet {
|
|
933
|
+
return {
|
|
934
|
+
get: (id: string): TtsProvider =>
|
|
935
|
+
({
|
|
936
|
+
__vellumSkillHostClientHandle: "tts-provider",
|
|
937
|
+
id,
|
|
938
|
+
}) as unknown as TtsProvider,
|
|
939
|
+
resolveConfig: (): TtsConfig => {
|
|
940
|
+
throw new Error(
|
|
941
|
+
"SkillHostClient.providers.tts.resolveConfig: use `client.rawCall('host.providers.tts.resolveConfig')` and await the result.",
|
|
942
|
+
);
|
|
943
|
+
},
|
|
944
|
+
};
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
private buildSecureKeysFacet(): SecureKeysFacet {
|
|
948
|
+
return {
|
|
949
|
+
getProviderKey: async (id: string): Promise<string | null> =>
|
|
950
|
+
this.call<string | null>("host.providers.secureKeys.getProviderKey", {
|
|
951
|
+
id,
|
|
952
|
+
}),
|
|
953
|
+
};
|
|
954
|
+
}
|
|
955
|
+
|
|
956
|
+
private buildProvidersFacet(): ProvidersFacet {
|
|
957
|
+
return {
|
|
958
|
+
llm: this.buildLlmProvidersFacet(),
|
|
959
|
+
stt: this.buildSttProvidersFacet(),
|
|
960
|
+
tts: this.buildTtsProvidersFacet(),
|
|
961
|
+
secureKeys: this.buildSecureKeysFacet(),
|
|
962
|
+
};
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
private buildMemoryFacet(): MemoryFacet {
|
|
966
|
+
const addMessage: InsertMessageFn = async (
|
|
967
|
+
conversationId,
|
|
968
|
+
role,
|
|
969
|
+
content,
|
|
970
|
+
metadata,
|
|
971
|
+
opts,
|
|
972
|
+
) =>
|
|
973
|
+
this.call("host.memory.addMessage", {
|
|
974
|
+
conversationId,
|
|
975
|
+
role,
|
|
976
|
+
content,
|
|
977
|
+
metadata,
|
|
978
|
+
opts,
|
|
979
|
+
});
|
|
980
|
+
|
|
981
|
+
return {
|
|
982
|
+
addMessage,
|
|
983
|
+
wakeAgentForOpportunity: async (req) => {
|
|
984
|
+
// The contract types `req` as opaque; the daemon route validates
|
|
985
|
+
// the concrete `{ conversationId, hint, source }` shape.
|
|
986
|
+
await this.call("host.memory.wakeAgentForOpportunity", {
|
|
987
|
+
...(req as Record<string, unknown>),
|
|
988
|
+
});
|
|
989
|
+
},
|
|
990
|
+
};
|
|
991
|
+
}
|
|
992
|
+
|
|
993
|
+
private buildEventsFacet(): EventsFacet {
|
|
994
|
+
return {
|
|
995
|
+
publish: async (event) => {
|
|
996
|
+
await this.call("host.events.publish", { event });
|
|
997
|
+
},
|
|
998
|
+
subscribe: (filter, cb) => this.openSubscription(filter, cb),
|
|
999
|
+
buildEvent: (message: ServerMessage, conversationId?: string) => {
|
|
1000
|
+
// `buildEvent` is typed as sync on the contract (the daemon
|
|
1001
|
+
// allocates a uuid + timestamp and returns the envelope). A sync
|
|
1002
|
+
// round-trip isn't possible, so the client produces an envelope
|
|
1003
|
+
// locally using the cached assistant id and the standard uuid /
|
|
1004
|
+
// timestamp sources. This matches the observable shape of the
|
|
1005
|
+
// daemon's `buildAssistantEvent` without the round-trip.
|
|
1006
|
+
if (this.cachedInternalAssistantId === null) throw notConnected();
|
|
1007
|
+
return {
|
|
1008
|
+
id: randomUUID(),
|
|
1009
|
+
assistantId: this.cachedInternalAssistantId,
|
|
1010
|
+
conversationId,
|
|
1011
|
+
emittedAt: new Date().toISOString(),
|
|
1012
|
+
message,
|
|
1013
|
+
};
|
|
1014
|
+
},
|
|
1015
|
+
};
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
private openSubscription(
|
|
1019
|
+
filter: Filter,
|
|
1020
|
+
callback: AssistantEventCallback,
|
|
1021
|
+
): Subscription {
|
|
1022
|
+
const id = this.nextSkillRequestId();
|
|
1023
|
+
const active: ActiveSubscription = {
|
|
1024
|
+
id,
|
|
1025
|
+
filter,
|
|
1026
|
+
callback,
|
|
1027
|
+
disposed: false,
|
|
1028
|
+
};
|
|
1029
|
+
this.subscriptions.set(id, active);
|
|
1030
|
+
// Pre-register a pending call for the open ack. The server writes a
|
|
1031
|
+
// `{ id, result: { subscribed: true } }` frame back; subsequent
|
|
1032
|
+
// `delivery` frames share the same id.
|
|
1033
|
+
this.registerSubscribeAck(active);
|
|
1034
|
+
try {
|
|
1035
|
+
this.writeFrame({
|
|
1036
|
+
id,
|
|
1037
|
+
method: "host.events.subscribe",
|
|
1038
|
+
params: { filter },
|
|
1039
|
+
});
|
|
1040
|
+
} catch (err) {
|
|
1041
|
+
this.cancelSubscribeAck(active);
|
|
1042
|
+
throw err;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
const self = this;
|
|
1046
|
+
return {
|
|
1047
|
+
get active() {
|
|
1048
|
+
return !active.disposed;
|
|
1049
|
+
},
|
|
1050
|
+
dispose: () => {
|
|
1051
|
+
if (active.disposed) return;
|
|
1052
|
+
active.disposed = true;
|
|
1053
|
+
self.subscriptions.delete(id);
|
|
1054
|
+
// Fire-and-forget close RPC — we don't await the ack because the
|
|
1055
|
+
// server also tears down on socket close, which is the fallback.
|
|
1056
|
+
if (self.socket && !self.socket.destroyed) {
|
|
1057
|
+
self
|
|
1058
|
+
.call(SUBSCRIBE_CLOSE_METHOD, { subscribeId: id })
|
|
1059
|
+
.catch(swallow);
|
|
1060
|
+
}
|
|
1061
|
+
},
|
|
1062
|
+
};
|
|
1063
|
+
}
|
|
1064
|
+
|
|
1065
|
+
private buildRegistriesFacet(): RegistriesFacet {
|
|
1066
|
+
return {
|
|
1067
|
+
registerTools: (provider) => {
|
|
1068
|
+
// Invoke the provider synchronously so a failure blows up at the
|
|
1069
|
+
// registration call site (matching the in-process semantics)
|
|
1070
|
+
// rather than silently dropping the tools into the RPC.
|
|
1071
|
+
const tools: Tool[] = provider();
|
|
1072
|
+
const manifests = tools.map((t) => {
|
|
1073
|
+
const def = t.getDefinition();
|
|
1074
|
+
return {
|
|
1075
|
+
name: t.name,
|
|
1076
|
+
description: t.description,
|
|
1077
|
+
input_schema: def.input_schema,
|
|
1078
|
+
defaultRiskLevel: t.defaultRiskLevel,
|
|
1079
|
+
category: t.category,
|
|
1080
|
+
executionTarget: t.executionTarget,
|
|
1081
|
+
executionMode: t.executionMode ?? "proxy",
|
|
1082
|
+
ownerSkillId: t.ownerSkillId ?? this.options.skillId,
|
|
1083
|
+
ownerSkillBundled: t.ownerSkillBundled,
|
|
1084
|
+
ownerSkillVersionHash: t.ownerSkillVersionHash,
|
|
1085
|
+
};
|
|
1086
|
+
});
|
|
1087
|
+
// Cache the provider so `skill.dispatch_tool` can resolve a tool
|
|
1088
|
+
// name back to its `execute` closure. Last writer wins.
|
|
1089
|
+
this.cachedToolsProvider = provider;
|
|
1090
|
+
this.ensureDaemonHandler(
|
|
1091
|
+
"skill.dispatch_tool",
|
|
1092
|
+
this.dispatchTool.bind(this),
|
|
1093
|
+
);
|
|
1094
|
+
// Fire-and-forget; registration failures surface in the daemon log.
|
|
1095
|
+
this.call("host.registries.register_tools", { tools: manifests }).catch(
|
|
1096
|
+
swallow,
|
|
1097
|
+
);
|
|
1098
|
+
},
|
|
1099
|
+
registerSkillRoute: (route: SkillRoute): SkillRouteHandle => {
|
|
1100
|
+
// Cache the route by its regex source — `skill.dispatch_route` uses
|
|
1101
|
+
// the same key to find the handler closure. Re-registering the same
|
|
1102
|
+
// source replaces the prior route, matching in-process hot-reload.
|
|
1103
|
+
this.cachedRoutes.set(route.pattern.source, route);
|
|
1104
|
+
this.ensureDaemonHandler(
|
|
1105
|
+
"skill.dispatch_route",
|
|
1106
|
+
this.dispatchRoute.bind(this),
|
|
1107
|
+
);
|
|
1108
|
+
// The `handler` closure cannot cross IPC; the daemon side installs
|
|
1109
|
+
// a proxy that dispatches back over `skill.dispatch_route` (PR D).
|
|
1110
|
+
// `patternFlags` ships separately so `i/m/g/s/u/y` survive the
|
|
1111
|
+
// RegExp → string round-trip — `new RegExp(source)` alone drops them.
|
|
1112
|
+
this.call("host.registries.register_skill_route", {
|
|
1113
|
+
patternSource: route.pattern.source,
|
|
1114
|
+
patternFlags: route.pattern.flags,
|
|
1115
|
+
methods: route.methods,
|
|
1116
|
+
}).catch(swallow);
|
|
1117
|
+
// The contract models the handle as a branded opaque object — we
|
|
1118
|
+
// return a structurally inert placeholder.
|
|
1119
|
+
return {} as SkillRouteHandle;
|
|
1120
|
+
},
|
|
1121
|
+
registerShutdownHook: (name: string, hook) => {
|
|
1122
|
+
// Cache the hook so `skill.shutdown` can invoke it. If the same
|
|
1123
|
+
// name is re-registered, replace in place to keep the array tidy
|
|
1124
|
+
// without disturbing relative order of unrelated entries.
|
|
1125
|
+
const existingIdx = this.cachedShutdownHooks.findIndex(
|
|
1126
|
+
(h) => h.name === name,
|
|
1127
|
+
);
|
|
1128
|
+
const entry = { name, hook };
|
|
1129
|
+
if (existingIdx >= 0) {
|
|
1130
|
+
this.cachedShutdownHooks[existingIdx] = entry;
|
|
1131
|
+
} else {
|
|
1132
|
+
this.cachedShutdownHooks.push(entry);
|
|
1133
|
+
}
|
|
1134
|
+
this.ensureDaemonHandler(
|
|
1135
|
+
"skill.shutdown",
|
|
1136
|
+
this.dispatchShutdown.bind(this),
|
|
1137
|
+
);
|
|
1138
|
+
// Fire-and-forget; the daemon registers a proxy that fires the
|
|
1139
|
+
// skill.shutdown dispatch at teardown (PR D).
|
|
1140
|
+
this.call("host.registries.register_shutdown_hook", { name }).catch(
|
|
1141
|
+
swallow,
|
|
1142
|
+
);
|
|
1143
|
+
},
|
|
1144
|
+
};
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1147
|
+
// ── Local dispatch helpers ──────────────────────────────────────────────
|
|
1148
|
+
|
|
1149
|
+
/**
|
|
1150
|
+
* Install a daemon-initiated request handler exactly once per method.
|
|
1151
|
+
* Idempotent so repeated `register*` calls don't churn the handler table
|
|
1152
|
+
* — every dispatch is routed through the same bound method anyway.
|
|
1153
|
+
*/
|
|
1154
|
+
private ensureDaemonHandler(
|
|
1155
|
+
method: string,
|
|
1156
|
+
handler: SkillHostRequestHandler,
|
|
1157
|
+
): void {
|
|
1158
|
+
if (!this.daemonRequestHandlers.has(method)) {
|
|
1159
|
+
this.daemonRequestHandlers.set(method, handler);
|
|
1160
|
+
}
|
|
1161
|
+
}
|
|
1162
|
+
|
|
1163
|
+
/**
|
|
1164
|
+
* `skill.dispatch_tool` handler — resolves the tool by name from the
|
|
1165
|
+
* cached provider and invokes its `execute(input, context)`. Returns
|
|
1166
|
+
* `{ result }` so the daemon can distinguish the wrapper from the
|
|
1167
|
+
* tool's own (potentially undefined) return value.
|
|
1168
|
+
*/
|
|
1169
|
+
private async dispatchTool(params: unknown): Promise<{ result: unknown }> {
|
|
1170
|
+
const { name, input, context } = (params ?? {}) as {
|
|
1171
|
+
name?: unknown;
|
|
1172
|
+
input?: unknown;
|
|
1173
|
+
context?: unknown;
|
|
1174
|
+
};
|
|
1175
|
+
if (typeof name !== "string" || !name) {
|
|
1176
|
+
throw new Error(
|
|
1177
|
+
"skill.dispatch_tool: missing or invalid 'name' parameter",
|
|
1178
|
+
);
|
|
1179
|
+
}
|
|
1180
|
+
const provider = this.cachedToolsProvider;
|
|
1181
|
+
if (!provider) {
|
|
1182
|
+
throw new Error(`unknown tool: ${name}`);
|
|
1183
|
+
}
|
|
1184
|
+
// Re-invoke the provider on each dispatch so feature-flag-gated tool
|
|
1185
|
+
// lists stay live — matches the daemon's lazy-manifest semantics in
|
|
1186
|
+
// `assistant/src/tools/registry.ts`.
|
|
1187
|
+
const tools = provider();
|
|
1188
|
+
const tool = tools.find((t) => t.name === name);
|
|
1189
|
+
if (!tool) {
|
|
1190
|
+
throw new Error(`unknown tool: ${name}`);
|
|
1191
|
+
}
|
|
1192
|
+
// The daemon-side `ToolContext` is opaque on the wire; the skill's
|
|
1193
|
+
// `Tool.execute` runtime-validates any field it actually reads, so a
|
|
1194
|
+
// structural cast is sufficient here. Missing required-on-paper fields
|
|
1195
|
+
// are tolerated in practice — meet-host's tools only consult a small
|
|
1196
|
+
// subset that the daemon serializes through.
|
|
1197
|
+
const ctx = (context ?? {}) as ToolContext;
|
|
1198
|
+
const result = await tool.execute(
|
|
1199
|
+
(input ?? {}) as Record<string, unknown>,
|
|
1200
|
+
ctx,
|
|
1201
|
+
);
|
|
1202
|
+
return { result };
|
|
1203
|
+
}
|
|
1204
|
+
|
|
1205
|
+
/**
|
|
1206
|
+
* `skill.dispatch_route` handler — looks up the route by patternSource,
|
|
1207
|
+
* re-runs the regex against the inbound URL to recover match groups,
|
|
1208
|
+
* invokes the handler, and serializes the `Response` to a
|
|
1209
|
+
* JSON-friendly `{ status, headers, body }`.
|
|
1210
|
+
*/
|
|
1211
|
+
private async dispatchRoute(params: unknown): Promise<{
|
|
1212
|
+
status: number;
|
|
1213
|
+
headers: Record<string, string>;
|
|
1214
|
+
body: string;
|
|
1215
|
+
}> {
|
|
1216
|
+
const { patternSource, request } = (params ?? {}) as {
|
|
1217
|
+
patternSource?: unknown;
|
|
1218
|
+
request?: unknown;
|
|
1219
|
+
};
|
|
1220
|
+
if (typeof patternSource !== "string" || !patternSource) {
|
|
1221
|
+
throw new Error(
|
|
1222
|
+
"skill.dispatch_route: missing or invalid 'patternSource' parameter",
|
|
1223
|
+
);
|
|
1224
|
+
}
|
|
1225
|
+
const route = this.cachedRoutes.get(patternSource);
|
|
1226
|
+
if (!route) {
|
|
1227
|
+
throw new Error(`unknown route: ${patternSource}`);
|
|
1228
|
+
}
|
|
1229
|
+
const req = (request ?? {}) as {
|
|
1230
|
+
method?: string;
|
|
1231
|
+
url?: string;
|
|
1232
|
+
headers?: Record<string, string>;
|
|
1233
|
+
body?: string;
|
|
1234
|
+
};
|
|
1235
|
+
if (typeof req.url !== "string" || !req.url) {
|
|
1236
|
+
throw new Error(
|
|
1237
|
+
"skill.dispatch_route: missing or invalid 'request.url' parameter",
|
|
1238
|
+
);
|
|
1239
|
+
}
|
|
1240
|
+
// Resolve against a synthetic base so `new Request` accepts the URL
|
|
1241
|
+
// (it rejects bare paths, but the daemon forwards `pathname + search`)
|
|
1242
|
+
// and so the regex can run against `pathname` alone — keeps query
|
|
1243
|
+
// strings out of anchored patterns like `^/v1/...$`.
|
|
1244
|
+
const parsedUrl = new URL(req.url, "http://skill.local");
|
|
1245
|
+
// Reset lastIndex so a global/sticky regex doesn't carry state across
|
|
1246
|
+
// dispatches — `exec()` mutates lastIndex on g/y flags and the route's
|
|
1247
|
+
// RegExp may be reused across requests.
|
|
1248
|
+
if (route.pattern.global || route.pattern.sticky) {
|
|
1249
|
+
route.pattern.lastIndex = 0;
|
|
1250
|
+
}
|
|
1251
|
+
const match = route.pattern.exec(parsedUrl.pathname);
|
|
1252
|
+
if (!match) {
|
|
1253
|
+
throw new Error(`url did not match pattern: ${patternSource}`);
|
|
1254
|
+
}
|
|
1255
|
+
const init: RequestInit = {
|
|
1256
|
+
method: req.method ?? "GET",
|
|
1257
|
+
headers: req.headers ?? {},
|
|
1258
|
+
};
|
|
1259
|
+
// GET/HEAD requests cannot carry a body in the standard fetch `Request`
|
|
1260
|
+
// constructor; only attach when the verb permits.
|
|
1261
|
+
if (
|
|
1262
|
+
req.body !== undefined &&
|
|
1263
|
+
init.method !== "GET" &&
|
|
1264
|
+
init.method !== "HEAD"
|
|
1265
|
+
) {
|
|
1266
|
+
init.body = req.body;
|
|
1267
|
+
}
|
|
1268
|
+
const response = await route.handler(
|
|
1269
|
+
new Request(parsedUrl.toString(), init),
|
|
1270
|
+
match,
|
|
1271
|
+
);
|
|
1272
|
+
const headers: Record<string, string> = {};
|
|
1273
|
+
response.headers.forEach((value, key) => {
|
|
1274
|
+
headers[key] = value;
|
|
1275
|
+
});
|
|
1276
|
+
const body = await response.text();
|
|
1277
|
+
return { status: response.status, headers, body };
|
|
1278
|
+
}
|
|
1279
|
+
|
|
1280
|
+
/**
|
|
1281
|
+
* `skill.shutdown` handler — runs cached shutdown hooks. With `name`
|
|
1282
|
+
* set, runs only that hook; otherwise runs all hooks in reverse-
|
|
1283
|
+
* registration order. Per-hook errors are logged via the host logger
|
|
1284
|
+
* and otherwise swallowed so one misbehaving hook can't block the
|
|
1285
|
+
* daemon's overall teardown.
|
|
1286
|
+
*/
|
|
1287
|
+
private async dispatchShutdown(params: unknown): Promise<{ ok: true }> {
|
|
1288
|
+
const { name, reason } = (params ?? {}) as {
|
|
1289
|
+
name?: unknown;
|
|
1290
|
+
reason?: unknown;
|
|
1291
|
+
};
|
|
1292
|
+
const reasonStr = typeof reason === "string" ? reason : "shutdown";
|
|
1293
|
+
const log = this.buildLogger(this.options.skillId);
|
|
1294
|
+
const runOne = async (entry: {
|
|
1295
|
+
name: string;
|
|
1296
|
+
hook: (reason: string) => Promise<void>;
|
|
1297
|
+
}): Promise<void> => {
|
|
1298
|
+
try {
|
|
1299
|
+
await entry.hook(reasonStr);
|
|
1300
|
+
} catch (err) {
|
|
1301
|
+
log.warn(`shutdown hook '${entry.name}' threw`, {
|
|
1302
|
+
error: errorMessage(err),
|
|
1303
|
+
});
|
|
1304
|
+
}
|
|
1305
|
+
};
|
|
1306
|
+
if (typeof name === "string" && name) {
|
|
1307
|
+
const entry = this.cachedShutdownHooks.find((h) => h.name === name);
|
|
1308
|
+
if (entry) await runOne(entry);
|
|
1309
|
+
// Silently no-op for unknown names — the daemon may call shutdown
|
|
1310
|
+
// for a hook that was never registered (e.g. a stale registration
|
|
1311
|
+
// leftover from a previous skill load), which shouldn't fail the
|
|
1312
|
+
// overall teardown.
|
|
1313
|
+
return { ok: true };
|
|
1314
|
+
}
|
|
1315
|
+
// Reverse-registration order so later-registered hooks (which often
|
|
1316
|
+
// depend on earlier ones) tear down first.
|
|
1317
|
+
for (let i = this.cachedShutdownHooks.length - 1; i >= 0; i--) {
|
|
1318
|
+
const entry = this.cachedShutdownHooks[i];
|
|
1319
|
+
if (entry) await runOne(entry);
|
|
1320
|
+
}
|
|
1321
|
+
return { ok: true };
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
private buildSpeakersFacet(): SpeakersFacet {
|
|
1325
|
+
return {
|
|
1326
|
+
createTracker: () =>
|
|
1327
|
+
({
|
|
1328
|
+
__vellumSkillHostClientHandle: "speaker-tracker",
|
|
1329
|
+
}) as unknown,
|
|
1330
|
+
};
|
|
1331
|
+
}
|
|
1332
|
+
|
|
1333
|
+
// ── Public escape hatch ─────────────────────────────────────────────────
|
|
1334
|
+
|
|
1335
|
+
/**
|
|
1336
|
+
* Escape hatch for invoking any `host.*` IPC method directly. Callers
|
|
1337
|
+
* that need to bypass the sync-method ergonomic gap (e.g. async reads
|
|
1338
|
+
* of `host.config.*` or `host.providers.stt.listProviderIds`) use this
|
|
1339
|
+
* to await a single RPC round-trip. The return type is unknown because
|
|
1340
|
+
* the method surface is open.
|
|
1341
|
+
*/
|
|
1342
|
+
async rawCall<T = unknown>(
|
|
1343
|
+
method: string,
|
|
1344
|
+
params?: Record<string, unknown>,
|
|
1345
|
+
): Promise<T> {
|
|
1346
|
+
return this.call<T>(method, params);
|
|
1347
|
+
}
|
|
1348
|
+
}
|