@vellumai/assistant 0.6.6 → 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 +20 -0
- package/ARCHITECTURE.md +45 -36
- package/Dockerfile +26 -6
- package/README.md +8 -10
- package/__tests__/permissions/gateway-threshold-reader.test.ts +14 -20
- package/bun.lock +306 -119
- package/docs/architecture/memory.md +1 -90
- package/docs/architecture/security.md +15 -30
- package/docs/credential-execution-service.md +7 -5
- package/docs/skills.md +10 -10
- package/docs/stt-provider-onboarding.md +17 -45
- package/examples/plugins/echo/bun.lock +25 -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/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 +2855 -556
- 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} +27 -27
- 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-routes-csp.test.ts +106 -55
- package/src/__tests__/approval-cascade.test.ts +3 -355
- 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 +8 -20
- 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__/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-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 +274 -3921
- package/src/__tests__/circuit-breaker-pipeline.test.ts +1 -1
- 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 +0 -1
- package/src/__tests__/compaction-pipeline.test.ts +1 -1
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +2 -2
- package/src/__tests__/compaction-timeout-recovery.test.ts +1 -1
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -7
- package/src/__tests__/config-model-image-provider.test.ts +0 -1
- package/src/__tests__/config-schema-cmd.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +30 -221
- 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 +56 -29
- package/src/__tests__/contacts-write.test.ts +6 -61
- 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 +25 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +10 -1
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +631 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +15 -2
- package/src/__tests__/conversation-agent-loop.test.ts +24 -2
- 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 +1 -39
- 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-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 -81
- 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 +0 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +137 -297
- package/src/__tests__/conversation-process-callsite.test.ts +0 -1
- package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -1
- package/src/__tests__/conversation-queue.test.ts +1 -33
- package/src/__tests__/conversation-routes-disk-view.test.ts +124 -97
- 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 +41 -84
- package/src/__tests__/conversation-slash-commands.test.ts +6 -43
- package/src/__tests__/conversation-slash-queue.test.ts +0 -1
- package/src/__tests__/conversation-slash-unknown.test.ts +0 -1
- package/src/__tests__/conversation-speed-override.test.ts +0 -1
- 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-tool-setup-app-refresh.test.ts +1 -1
- 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 +2 -1
- package/src/__tests__/conversation-wipe.test.ts +2 -103
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -1
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -1
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -1
- 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-security-invariants.test.ts +14 -0
- 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 +1 -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 +1 -1
- 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__/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__/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 +1 -1
- package/src/__tests__/home-state-routes.test.ts +10 -31
- package/src/__tests__/host-browser-e2e-cloud.test.ts +2 -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 +3 -3
- 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__/inbound-invite-redemption.test.ts +3 -2
- package/src/__tests__/injector-chain.test.ts +16 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +41 -206
- package/src/__tests__/install-skill-routing.test.ts +1 -1
- 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 +7 -8
- 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 +57 -1
- 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__/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 +6 -8
- package/src/__tests__/memory-upsert-concurrency.test.ts +2 -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 +16 -23
- 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 +15 -2
- 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-guardian-path.test.ts +15 -8
- package/src/__tests__/notification-schedule-notify-dedup.test.ts +2 -1
- package/src/__tests__/notification-telegram-adapter.test.ts +57 -55
- package/src/__tests__/oauth-apps-routes.test.ts +76 -122
- package/src/__tests__/oauth-cli.test.ts +14 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-provider-visibility.test.ts +3 -1
- package/src/__tests__/oauth-providers-routes.test.ts +78 -101
- package/src/__tests__/oauth-store.test.ts +3 -1
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -3
- 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 +4 -9
- package/src/__tests__/permission-types.test.ts +3 -18
- package/src/__tests__/persistence-pipeline.test.ts +3 -2
- package/src/__tests__/pipeline-runner.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +27 -20
- package/src/__tests__/platform.test.ts +11 -63
- 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 +51 -5
- package/src/__tests__/plugin-registry.test.ts +30 -0
- package/src/__tests__/plugin-route-contribution.test.ts +17 -11
- package/src/__tests__/plugin-skill-contribution.test.ts +3 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +10 -4
- package/src/__tests__/plugin-types.test.ts +1 -1
- package/src/__tests__/pricing.test.ts +151 -2
- 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 -554
- package/src/__tests__/qdrant-collection-migration.test.ts +7 -7
- package/src/__tests__/reaction-persistence.test.ts +3 -2
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +0 -2
- package/src/__tests__/registry.test.ts +1 -0
- 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 +226 -129
- 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 +2 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +2 -1
- 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 -9
- 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 +55 -62
- 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 +2 -1
- package/src/__tests__/task-scheduler.test.ts +2 -1
- package/src/__tests__/telegram-config.test.ts +0 -1
- package/src/__tests__/terminal-tools.test.ts +5 -314
- package/src/__tests__/test-preload.ts +0 -11
- package/src/__tests__/thread-backfill.test.ts +3 -2
- package/src/__tests__/token-estimate-pipeline.test.ts +68 -15
- 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 +6 -6
- package/src/__tests__/tool-execute-pipeline.test.ts +6 -8
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +64 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +28 -56
- package/src/__tests__/tool-executor.test.ts +322 -1633
- package/src/__tests__/tool-grant-request-escalation.test.ts +90 -311
- package/src/__tests__/tool-result-truncate-pipeline.test.ts +1 -1
- 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 +54 -12
- 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-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/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 +37 -14
- package/src/agent/message-types.ts +0 -2
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/__tests__/guardian-feed-event.test.ts +1 -9
- package/src/approvals/approval-primitive.ts +3 -20
- package/src/approvals/guardian-decision-primitive.ts +37 -68
- package/src/approvals/guardian-request-resolvers.ts +29 -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 +0 -2
- package/src/backup/__tests__/paths.test.ts +3 -2
- package/src/backup/backup-worker.ts +1 -10
- 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/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-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 +25 -3
- package/src/channels/permission-profiles.ts +2 -72
- package/src/channels/types.ts +42 -26
- package/src/cli/AGENTS.md +1 -0
- package/src/cli/__tests__/notifications.test.ts +12 -10
- package/src/cli/commands/__tests__/attachment.test.ts +14 -8
- package/src/cli/commands/__tests__/backup.test.ts +3 -14
- 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__/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__/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 +14 -44
- 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 +11 -12
- package/src/cli/commands/completions.ts +1 -1
- 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 +63 -53
- 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 +1 -1
- 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 +21 -20
- 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__/status.test.ts +1 -1
- package/src/cli/commands/oauth/__tests__/token.test.ts +1 -1
- package/src/cli/commands/oauth/connect.ts +2 -2
- package/src/cli/commands/oauth/shared.ts +29 -2
- 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 +188 -82
- 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 +4 -0
- package/src/cli.ts +1 -61
- 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/acp/tools/acp-list-agents.ts +12 -0
- package/src/config/bundled-skills/acp/tools/acp-steer.ts +12 -0
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +14 -14
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +1 -4
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +11 -6
- 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/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/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/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 -6
- package/src/config/env.ts +7 -8
- package/src/config/feature-flag-registry.json +16 -24
- package/src/config/llm-resolver.ts +51 -33
- package/src/config/loader.ts +12 -15
- package/src/config/schema.ts +5 -72
- 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/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 -9
- 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/skills.ts +1 -1
- 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/token-estimator.ts +1 -1
- package/src/context/tool-result-truncation.ts +1 -1
- package/src/context/window-manager.ts +1 -1
- 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 +1 -1
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -13
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +1 -1
- 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 -54
- package/src/daemon/connection-policy.ts +0 -14
- package/src/daemon/conversation-agent-loop-handlers.ts +37 -6
- package/src/daemon/conversation-agent-loop.ts +164 -53
- package/src/daemon/conversation-attachments.ts +5 -81
- package/src/daemon/conversation-error.ts +9 -5
- package/src/daemon/conversation-history.ts +1 -1
- package/src/daemon/conversation-launch.ts +1 -1
- package/src/daemon/conversation-messaging.ts +1 -1
- package/src/daemon/conversation-notifiers.ts +1 -1
- package/src/daemon/conversation-process.ts +9 -13
- package/src/daemon/conversation-runtime-assembly.ts +26 -88
- 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 +23 -172
- package/src/daemon/conversation.ts +46 -182
- package/src/daemon/daemon-control.ts +3 -3
- package/src/daemon/daemon-skill-host.ts +262 -0
- package/src/daemon/external-plugins-bootstrap.ts +67 -13
- 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 +7 -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 +15 -23
- package/src/daemon/host-transfer-proxy.ts +500 -0
- package/src/daemon/lifecycle.ts +23 -258
- 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/conversations.ts +16 -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 +14 -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 -1274
- package/src/daemon/shutdown-handlers.ts +1 -1
- package/src/daemon/startup-error.ts +1 -1
- 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 +89 -21
- package/src/heartbeat/heartbeat-service.ts +32 -11
- 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/feed-types.ts +1 -1
- package/src/home/relationship-state-writer.ts +1 -1
- 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 +69 -23
- 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 -123
- 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 +63 -32
- 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/types.ts +4 -4
- 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 +69 -127
- 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 +13 -26
- 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 +2 -1
- package/src/memory/db-init.ts +14 -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 +4 -4
- 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 +2 -7
- package/src/memory/graph/bootstrap.ts +2 -1
- 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 +53 -21
- package/src/memory/graph/graph-memory-state-store.ts +1 -1
- package/src/memory/graph/graph-search.test.ts +94 -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 +17 -5
- 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/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 +10 -0
- package/src/memory/migrations/registry.ts +7 -0
- package/src/memory/pkb/pkb-index.test.ts +4 -5
- package/src/memory/pkb/pkb-reconcile.test.ts +4 -5
- package/src/memory/pkb/pkb-search.test.ts +83 -3
- package/src/memory/pkb/pkb-search.ts +27 -14
- package/src/memory/published-pages-store.ts +1 -1
- 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 +1 -32
- package/src/memory/schema/memory-graph.ts +36 -14
- 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/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-seed-composer.ts +12 -6
- package/src/notifications/copy-composer.ts +1 -1
- 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/events-store.ts +1 -13
- package/src/notifications/preferences-store.ts +1 -1
- package/src/notifications/signal.ts +0 -9
- package/src/oauth/connection-resolver.ts +11 -2
- package/src/oauth/oauth-store.ts +2 -1
- package/src/outbound-proxy/index.ts +0 -1
- package/src/permissions/approval-policy.test.ts +149 -132
- package/src/permissions/approval-policy.ts +65 -91
- package/src/permissions/checker.test.ts +632 -0
- package/src/permissions/checker.ts +266 -459
- package/src/permissions/gateway-threshold-reader.ts +28 -47
- package/src/permissions/ipc-risk-types.ts +95 -0
- package/src/permissions/prompter.ts +4 -9
- package/src/permissions/risk-types.ts +24 -210
- package/src/permissions/types.ts +17 -47
- package/src/permissions/workspace-policy.ts +2 -4
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/plugins/defaults/index.ts +1 -1
- package/src/plugins/defaults/injectors.ts +18 -21
- package/src/plugins/defaults/llm-call.ts +6 -9
- package/src/plugins/defaults/memory-retrieval.ts +1 -6
- package/src/plugins/defaults/overflow-reduce.ts +9 -5
- package/src/plugins/defaults/token-estimate.ts +2 -3
- package/src/plugins/registry.ts +61 -1
- package/src/plugins/types.ts +6 -7
- package/src/plugins/user-loader.ts +36 -10
- 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/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 +83 -8
- package/src/providers/model-intents.ts +7 -8
- 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 +4 -5
- 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/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.ts +5 -5
- package/src/providers/thinking-config.ts +34 -0
- package/src/providers/types.ts +22 -10
- package/src/runtime/AGENTS.md +10 -9
- package/src/runtime/__tests__/agent-wake.test.ts +33 -9
- package/src/runtime/__tests__/client-registry.test.ts +5 -27
- 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 +21 -28
- 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 -1110
- package/src/runtime/http-types.ts +15 -98
- 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 +3 -4
- 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-routes.ts +116 -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 +456 -368
- 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 +74 -110
- 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 +152 -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 -374
- 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 +60 -120
- package/src/runtime/routes/playground/__tests__/guard.test.ts +34 -54
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +107 -151
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +41 -117
- package/src/runtime/routes/playground/__tests__/seed-conversation.test.ts +95 -138
- package/src/runtime/routes/playground/__tests__/seeded-conversations.test.ts +115 -217
- package/src/runtime/routes/playground/__tests__/state.test.ts +41 -90
- package/src/runtime/routes/playground/conversation-not-found.ts +9 -11
- package/src/runtime/routes/playground/force-compact.ts +41 -54
- package/src/runtime/routes/playground/guard.ts +18 -19
- package/src/runtime/routes/playground/helpers.ts +103 -0
- package/src/runtime/routes/playground/index.ts +15 -25
- package/src/runtime/routes/playground/inject-failures.ts +48 -64
- package/src/runtime/routes/playground/reset-circuit.ts +31 -57
- package/src/runtime/routes/playground/seed-conversation.ts +66 -92
- package/src/runtime/routes/playground/seeded-conversations.ts +60 -64
- package/src/runtime/routes/playground/state.ts +23 -24
- 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 +238 -242
- 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/trust-context-resolver.ts +3 -2
- package/src/runtime/verification-outbound-actions.ts +13 -49
- package/src/schedule/schedule-store.ts +64 -2
- package/src/schedule/scheduler.ts +101 -0
- 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 +7 -0
- 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/browser-execution.ts +34 -7
- package/src/tools/browser/browser-manager.ts +1 -8
- 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/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 +10 -15
- 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/permission-checker.ts +18 -219
- package/src/tools/policy-context.ts +1 -8
- package/src/tools/registry.ts +16 -1
- package/src/tools/secret-detection-handler.ts +13 -103
- 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/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 +143 -163
- 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 -124
- package/src/util/pricing.ts +109 -6
- 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 +10 -1
- 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/028-recover-conversations-from-disk-view.ts +1 -1
- package/src/workspace/migrations/031-drop-user-md.ts +1 -1
- package/src/workspace/migrations/045-release-notes-meet-avatar.ts +3 -4
- 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 +18 -0
- package/src/workspace/migrations/runner.ts +2 -2
- package/src/workspace/provider-commit-message-generator.ts +1 -1
- 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__/config-watcher-feature-flags.test.ts +0 -211
- 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__/host-browser-e2e-self-hosted.test.ts +0 -374
- package/src/__tests__/native-host-marker-sync-guard.test.ts +0 -157
- 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 -488
- 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__/shell-identity.test.ts +0 -236
- 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 -354
- 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/db.ts +0 -1
- 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/daemon/__tests__/lifecycle-startup-ordering.test.ts +0 -127
- package/src/daemon/approved-devices-store.ts +0 -110
- 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/ipc/cli-server.ts +0 -252
- package/src/ipc/routes/attachment.ts +0 -114
- package/src/ipc/routes/browser-context.ts +0 -63
- package/src/ipc/routes/browser.ts +0 -97
- package/src/ipc/routes/cache.ts +0 -96
- package/src/ipc/routes/get-contact.ts +0 -16
- package/src/ipc/routes/index.ts +0 -35
- package/src/ipc/routes/list-clients.ts +0 -31
- package/src/ipc/routes/merge-contacts.ts +0 -17
- package/src/ipc/routes/notification.ts +0 -133
- package/src/ipc/routes/rename-conversation.ts +0 -59
- package/src/ipc/routes/search-contacts.ts +0 -19
- package/src/ipc/routes/task-queue.ts +0 -226
- package/src/ipc/routes/task.ts +0 -173
- package/src/ipc/routes/upsert-contact.ts +0 -25
- package/src/ipc/routes/wake-conversation.ts +0 -19
- package/src/memory/db.ts +0 -23
- package/src/permissions/arg-parser.test.ts +0 -161
- package/src/permissions/arg-parser.ts +0 -141
- package/src/permissions/bash-risk-classifier.test.ts +0 -1620
- package/src/permissions/bash-risk-classifier.ts +0 -950
- package/src/permissions/command-registry.test.ts +0 -774
- package/src/permissions/command-registry.ts +0 -1005
- package/src/permissions/defaults.ts +0 -314
- 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/schedule-risk-classifier.test.ts +0 -129
- package/src/permissions/schedule-risk-classifier.ts +0 -85
- package/src/permissions/shell-identity.ts +0 -297
- 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/routes/browser-extension-pair-routes.ts +0 -575
- 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/playground/deps.ts +0 -56
- package/src/runtime/services/__tests__/analyze-deps-singleton.test.ts +0 -67
- package/src/runtime/services/analyze-deps-singleton.ts +0 -32
- package/src/tasks/ephemeral-permissions.ts +0 -55
- package/src/tools/terminal/parser.ts +0 -623
- 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
|
@@ -5,15 +5,6 @@
|
|
|
5
5
|
* configured port (default: 7821).
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import {
|
|
9
|
-
existsSync,
|
|
10
|
-
mkdirSync,
|
|
11
|
-
readFileSync,
|
|
12
|
-
renameSync,
|
|
13
|
-
unlinkSync,
|
|
14
|
-
writeFileSync,
|
|
15
|
-
} from "node:fs";
|
|
16
|
-
import { dirname, resolve } from "node:path";
|
|
17
8
|
|
|
18
9
|
import type { ServerWebSocket } from "bun";
|
|
19
10
|
|
|
@@ -35,75 +26,40 @@ import {
|
|
|
35
26
|
handleStatusCallback,
|
|
36
27
|
handleVoiceWebhook,
|
|
37
28
|
} from "../calls/twilio-routes.js";
|
|
38
|
-
import { parseChannelId } from "../channels/types.js";
|
|
39
|
-
import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
|
|
40
29
|
import {
|
|
41
|
-
getGatewayInternalBaseUrl,
|
|
42
30
|
hasUngatedHttpAuthDisabled,
|
|
43
31
|
isHttpAuthDisabled,
|
|
44
32
|
} from "../config/env.js";
|
|
45
33
|
import { getConfig } from "../config/loader.js";
|
|
46
|
-
import
|
|
47
|
-
import {
|
|
48
|
-
import {
|
|
49
|
-
type AttentionState,
|
|
50
|
-
type Confidence,
|
|
51
|
-
getAttentionStateByConversationIds,
|
|
52
|
-
markConversationUnread,
|
|
53
|
-
recordConversationSeenSignal,
|
|
54
|
-
type SignalType,
|
|
55
|
-
} from "../memory/conversation-attention-store.js";
|
|
56
|
-
import {
|
|
57
|
-
addMessage,
|
|
58
|
-
type ConversationRow,
|
|
59
|
-
createConversation,
|
|
60
|
-
deleteConversation,
|
|
61
|
-
forkConversation as forkConversationInStore,
|
|
62
|
-
getConversation,
|
|
63
|
-
getDisplayMetaForConversations,
|
|
64
|
-
} from "../memory/conversation-crud.js";
|
|
65
|
-
import { resolveConversationId } from "../memory/conversation-key-store.js";
|
|
34
|
+
import { processMessage } from "../daemon/process-message.js";
|
|
35
|
+
import { createLiveVoiceSession } from "../live-voice/live-voice-session.js";
|
|
36
|
+
import { LiveVoiceSessionManager } from "../live-voice/live-voice-session-manager.js";
|
|
66
37
|
import {
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
import { listGroups } from "../memory/group-crud.js";
|
|
75
|
-
import { enqueueMemoryJob } from "../memory/jobs-store.js";
|
|
38
|
+
type LiveVoiceClientFrame,
|
|
39
|
+
type LiveVoiceProtocolError,
|
|
40
|
+
LiveVoiceProtocolErrorCode,
|
|
41
|
+
type LiveVoiceServerFrame,
|
|
42
|
+
parseLiveVoiceBinaryAudioFrame,
|
|
43
|
+
parseLiveVoiceClientTextFrame,
|
|
44
|
+
} from "../live-voice/protocol.js";
|
|
76
45
|
import { resolveStreamingTranscriber } from "../providers/speech-to-text/resolve.js";
|
|
77
|
-
import {
|
|
78
|
-
consumeCallback,
|
|
79
|
-
consumeCallbackError,
|
|
80
|
-
} from "../security/oauth-callback-registry.js";
|
|
81
46
|
import {
|
|
82
47
|
activeSttStreamSessions,
|
|
83
48
|
SttStreamSession,
|
|
84
49
|
} from "../stt/stt-stream-session.js";
|
|
85
|
-
import { UserError } from "../util/errors.js";
|
|
86
50
|
import { getLogger } from "../util/logger.js";
|
|
87
|
-
import { getRuntimePortFilePath } from "../util/platform.js";
|
|
88
|
-
import { buildAssistantEvent } from "./assistant-event.js";
|
|
89
|
-
import { assistantEventHub } from "./assistant-event-hub.js";
|
|
90
|
-
import { DAEMON_INTERNAL_ASSISTANT_ID } from "./assistant-scope.js";
|
|
91
51
|
// Auth
|
|
92
52
|
import {
|
|
93
53
|
authenticateHostBrowserResultRequest,
|
|
94
54
|
authenticateRequest,
|
|
95
55
|
} from "./auth/middleware.js";
|
|
96
56
|
import { parseSub } from "./auth/subject.js";
|
|
97
|
-
import {
|
|
98
|
-
mintDaemonDeliveryToken,
|
|
99
|
-
mintUiPageToken,
|
|
100
|
-
verifyToken,
|
|
101
|
-
} from "./auth/token-service.js";
|
|
57
|
+
import { verifyToken } from "./auth/token-service.js";
|
|
102
58
|
import { verifyHostBrowserCapability } from "./capability-tokens.js";
|
|
103
59
|
import { sweepFailedEvents } from "./channel-retry-sweep.js";
|
|
104
60
|
import { getChromeExtensionRegistry } from "./chrome-extension-registry.js";
|
|
105
|
-
import { httpError } from "./http-errors.js";
|
|
106
|
-
import type {
|
|
61
|
+
import { httpError, type HttpErrorCode } from "./http-errors.js";
|
|
62
|
+
import type { HTTPRouteDefinition } from "./http-router.js";
|
|
107
63
|
import { HttpRouter } from "./http-router.js";
|
|
108
64
|
// Middleware
|
|
109
65
|
import {
|
|
@@ -129,111 +85,25 @@ import {
|
|
|
129
85
|
TWILIO_WEBHOOK_RE,
|
|
130
86
|
validateTwilioWebhook,
|
|
131
87
|
} from "./middleware/twilio-validation.js";
|
|
132
|
-
import {
|
|
133
|
-
import {
|
|
134
|
-
import { handleServePage } from "./routes/app-routes.js";
|
|
135
|
-
import { appRouteDefinitions } from "./routes/app-routes.js";
|
|
136
|
-
import { approvalRouteDefinitions } from "./routes/approval-routes.js";
|
|
137
|
-
import { attachmentRouteDefinitions } from "./routes/attachment-routes.js";
|
|
138
|
-
import { handleGetAudio } from "./routes/audio-routes.js";
|
|
139
|
-
import { avatarRouteDefinitions } from "./routes/avatar-routes.js";
|
|
140
|
-
import { backupRouteDefinitions } from "./routes/backup-routes.js";
|
|
141
|
-
import { brainGraphRouteDefinitions } from "./routes/brain-graph-routes.js";
|
|
142
|
-
import { handleBrowserExtensionPair } from "./routes/browser-extension-pair-routes.js";
|
|
143
|
-
import { btwRouteDefinitions } from "./routes/btw-routes.js";
|
|
144
|
-
import { callRouteDefinitions } from "./routes/call-routes.js";
|
|
88
|
+
import { ROUTES as APP_ROUTES } from "./routes/app-routes.js";
|
|
89
|
+
import { ROUTES as AUDIO_ROUTES } from "./routes/audio-routes.js";
|
|
145
90
|
import {
|
|
146
91
|
startCanonicalGuardianExpirySweep,
|
|
147
92
|
stopCanonicalGuardianExpirySweep,
|
|
148
93
|
} from "./routes/canonical-guardian-expiry-sweep.js";
|
|
149
|
-
import { channelReadinessRouteDefinitions } from "./routes/channel-readiness-routes.js";
|
|
150
94
|
import {
|
|
151
|
-
channelRouteDefinitions,
|
|
152
95
|
startGuardianExpirySweep,
|
|
153
96
|
stopGuardianExpirySweep,
|
|
154
|
-
} from "./routes/channel-routes.js";
|
|
155
|
-
import {
|
|
97
|
+
} from "./routes/channel-guardian-routes.js";
|
|
98
|
+
import { RouteError } from "./routes/errors.js";
|
|
156
99
|
import {
|
|
157
|
-
contactCatchAllRouteDefinitions,
|
|
158
|
-
contactRouteDefinitions,
|
|
159
|
-
} from "./routes/contact-routes.js";
|
|
160
|
-
import { conversationAnalysisRouteDefinitions } from "./routes/conversation-analysis-routes.js";
|
|
161
|
-
import { conversationAttentionRouteDefinitions } from "./routes/conversation-attention-routes.js";
|
|
162
|
-
import {
|
|
163
|
-
type ConversationManagementDeps,
|
|
164
|
-
conversationManagementRouteDefinitions,
|
|
165
|
-
} from "./routes/conversation-management-routes.js";
|
|
166
|
-
import { conversationQueryRouteDefinitions } from "./routes/conversation-query-routes.js";
|
|
167
|
-
import { conversationRouteDefinitions } from "./routes/conversation-routes.js";
|
|
168
|
-
import { conversationStarterRouteDefinitions } from "./routes/conversation-starter-routes.js";
|
|
169
|
-
import { debugRouteDefinitions } from "./routes/debug-routes.js";
|
|
170
|
-
import { diagnosticsRouteDefinitions } from "./routes/diagnostics-routes.js";
|
|
171
|
-
import { documentRouteDefinitions } from "./routes/documents-routes.js";
|
|
172
|
-
import { eventsRouteDefinitions } from "./routes/events-routes.js";
|
|
173
|
-
import { filingRouteDefinitions } from "./routes/filing-routes.js";
|
|
174
|
-
import { globalSearchRouteDefinitions } from "./routes/global-search-routes.js";
|
|
175
|
-
import { groupRouteDefinitions } from "./routes/group-routes.js";
|
|
176
|
-
import { guardianActionRouteDefinitions } from "./routes/guardian-action-routes.js";
|
|
177
|
-
import { handleGuardianBootstrap } from "./routes/guardian-bootstrap-routes.js";
|
|
178
|
-
import { handleGuardianRefresh } from "./routes/guardian-refresh-routes.js";
|
|
179
|
-
import { heartbeatRouteDefinitions } from "./routes/heartbeat-routes.js";
|
|
180
|
-
import { homeFeedRouteDefinitions } from "./routes/home-feed-routes.js";
|
|
181
|
-
import { homeStateRouteDefinitions } from "./routes/home-state-routes.js";
|
|
182
|
-
import { hostBashRouteDefinitions } from "./routes/host-bash-routes.js";
|
|
183
|
-
import {
|
|
184
|
-
hostBrowserRouteDefinitions,
|
|
185
100
|
resolveHostBrowserEvent,
|
|
186
101
|
resolveHostBrowserResultByRequestId,
|
|
187
102
|
resolveHostBrowserSessionInvalidated,
|
|
188
103
|
} from "./routes/host-browser-routes.js";
|
|
189
|
-
import {
|
|
190
|
-
import {
|
|
191
|
-
import {
|
|
192
|
-
handleHealth,
|
|
193
|
-
handleReadyz,
|
|
194
|
-
identityRouteDefinitions,
|
|
195
|
-
} from "./routes/identity-routes.js";
|
|
196
|
-
import { slackChannelRouteDefinitions } from "./routes/integrations/slack/channel.js";
|
|
197
|
-
import { slackShareRouteDefinitions } from "./routes/integrations/slack/share.js";
|
|
198
|
-
import { telegramRouteDefinitions } from "./routes/integrations/telegram.js";
|
|
199
|
-
import { twilioRouteDefinitions } from "./routes/integrations/twilio.js";
|
|
200
|
-
import { vercelRouteDefinitions } from "./routes/integrations/vercel.js";
|
|
201
|
-
import { inviteRouteDefinitions } from "./routes/invite-routes.js";
|
|
202
|
-
import { logExportRouteDefinitions } from "./routes/log-export-routes.js";
|
|
203
|
-
import { memoryItemRouteDefinitions } from "./routes/memory-item-routes.js";
|
|
204
|
-
import { migrationRollbackRouteDefinitions } from "./routes/migration-rollback-routes.js";
|
|
205
|
-
import { migrationRouteDefinitions } from "./routes/migration-routes.js";
|
|
206
|
-
import { notificationRouteDefinitions } from "./routes/notification-routes.js";
|
|
207
|
-
import { oauthAppsRouteDefinitions } from "./routes/oauth-apps.js";
|
|
208
|
-
import { oauthProvidersRouteDefinitions } from "./routes/oauth-providers.js";
|
|
209
|
-
import type { PairingHandlerContext } from "./routes/pairing-routes.js";
|
|
210
|
-
import {
|
|
211
|
-
handlePairingRequest,
|
|
212
|
-
handlePairingStatus,
|
|
213
|
-
pairingRouteDefinitions,
|
|
214
|
-
} from "./routes/pairing-routes.js";
|
|
215
|
-
import { playgroundRouteDefinitions } from "./routes/playground/index.js";
|
|
216
|
-
import { profilerRouteDefinitions } from "./routes/profiler-routes.js";
|
|
217
|
-
import { recordingRouteDefinitions } from "./routes/recording-routes.js";
|
|
218
|
-
import { scheduleRouteDefinitions } from "./routes/schedule-routes.js";
|
|
219
|
-
import { secretRouteDefinitions } from "./routes/secret-routes.js";
|
|
220
|
-
import { settingsRouteDefinitions } from "./routes/settings-routes.js";
|
|
221
|
-
import { skillRouteDefinitions } from "./routes/skills-routes.js";
|
|
222
|
-
import { sttRouteDefinitions } from "./routes/stt-routes.js";
|
|
223
|
-
import { subagentRouteDefinitions } from "./routes/subagents-routes.js";
|
|
224
|
-
import { surfaceActionRouteDefinitions } from "./routes/surface-action-routes.js";
|
|
225
|
-
import { surfaceContentRouteDefinitions } from "./routes/surface-content-routes.js";
|
|
226
|
-
import { telemetryRouteDefinitions } from "./routes/telemetry-routes.js";
|
|
227
|
-
import { traceEventRouteDefinitions } from "./routes/trace-event-routes.js";
|
|
228
|
-
import { trustRulesRouteDefinitions } from "./routes/trust-rules-routes.js";
|
|
229
|
-
import { ttsRouteDefinitions } from "./routes/tts-routes.js";
|
|
230
|
-
import { upgradeBroadcastRouteDefinitions } from "./routes/upgrade-broadcast-routes.js";
|
|
231
|
-
import { usageRouteDefinitions } from "./routes/usage-routes.js";
|
|
232
|
-
import { userRouteDefinitions } from "./routes/user-routes.js";
|
|
233
|
-
import { workItemRouteDefinitions } from "./routes/work-items-routes.js";
|
|
234
|
-
import { workspaceCommitRouteDefinitions } from "./routes/workspace-commit-routes.js";
|
|
235
|
-
import { workspaceRouteDefinitions } from "./routes/workspace-routes.js";
|
|
236
|
-
import { setAnalysisDeps } from "./services/analyze-deps-singleton.js";
|
|
104
|
+
import { routeDefinitionsToHTTPRoutes } from "./routes/http-adapter.js";
|
|
105
|
+
import { handleHealth, handleReadyz } from "./routes/identity-routes.js";
|
|
106
|
+
import { ROUTES } from "./routes/index.js";
|
|
237
107
|
import { matchSkillRoute } from "./skill-route-registry.js";
|
|
238
108
|
|
|
239
109
|
// Re-export for consumers
|
|
@@ -249,7 +119,6 @@ export type {
|
|
|
249
119
|
RuntimeAttachmentMetadata,
|
|
250
120
|
RuntimeHttpServerOptions,
|
|
251
121
|
RuntimeMessageConversationOptions,
|
|
252
|
-
SendMessageDeps,
|
|
253
122
|
} from "./http-types.js";
|
|
254
123
|
|
|
255
124
|
import type {
|
|
@@ -257,9 +126,7 @@ import type {
|
|
|
257
126
|
ApprovalCopyGenerator,
|
|
258
127
|
GuardianActionCopyGenerator,
|
|
259
128
|
GuardianFollowUpConversationGenerator,
|
|
260
|
-
MessageProcessor,
|
|
261
129
|
RuntimeHttpServerOptions,
|
|
262
|
-
SendMessageDeps,
|
|
263
130
|
} from "./http-types.js";
|
|
264
131
|
|
|
265
132
|
const log = getLogger("runtime-http");
|
|
@@ -338,59 +205,44 @@ interface SttStreamWebSocketData {
|
|
|
338
205
|
session?: SttStreamSession;
|
|
339
206
|
}
|
|
340
207
|
|
|
208
|
+
/**
|
|
209
|
+
* WebSocket data attached to `/v1/live-voice` connections. The `wsType`
|
|
210
|
+
* discriminator routes frames to the live voice protocol shell instead of
|
|
211
|
+
* the other WebSocket handlers.
|
|
212
|
+
*/
|
|
213
|
+
interface LiveVoiceWebSocketData {
|
|
214
|
+
wsType: "live-voice";
|
|
215
|
+
sessionId?: string;
|
|
216
|
+
lastSeq: number;
|
|
217
|
+
}
|
|
218
|
+
|
|
341
219
|
export class RuntimeHttpServer {
|
|
342
220
|
private server: ReturnType<typeof Bun.serve> | null = null;
|
|
343
221
|
private port: number;
|
|
344
222
|
private hostname: string;
|
|
345
|
-
|
|
346
|
-
private bearerToken: string | undefined;
|
|
347
|
-
private processMessage?: MessageProcessor;
|
|
223
|
+
|
|
348
224
|
private approvalCopyGenerator?: ApprovalCopyGenerator;
|
|
349
225
|
private approvalConversationGenerator?: ApprovalConversationGenerator;
|
|
350
226
|
private guardianActionCopyGenerator?: GuardianActionCopyGenerator;
|
|
351
227
|
private guardianFollowUpConversationGenerator?: GuardianFollowUpConversationGenerator;
|
|
352
|
-
private interfacesDir: string | null;
|
|
353
|
-
private suggestionCache = new Map<string, string>();
|
|
354
|
-
private suggestionInFlight = new Map<string, Promise<string | null>>();
|
|
355
228
|
private retrySweepTimer: ReturnType<typeof setInterval> | null = null;
|
|
356
229
|
private sweepInProgress = false;
|
|
357
|
-
|
|
358
|
-
private
|
|
359
|
-
private sendMessageDeps?: SendMessageDeps;
|
|
360
|
-
private findConversation?: RuntimeHttpServerOptions["findConversation"];
|
|
361
|
-
private findConversationBySurfaceId?: RuntimeHttpServerOptions["findConversationBySurfaceId"];
|
|
362
|
-
private getSkillContext?: RuntimeHttpServerOptions["getSkillContext"];
|
|
363
|
-
private conversationManagementDeps?: RuntimeHttpServerOptions["conversationManagementDeps"];
|
|
364
|
-
private getModelSetContext?: RuntimeHttpServerOptions["getModelSetContext"];
|
|
365
|
-
private getRecordingDeps?: RuntimeHttpServerOptions["getRecordingDeps"];
|
|
366
|
-
private getCesClient?: RuntimeHttpServerOptions["getCesClient"];
|
|
367
|
-
private onProviderCredentialsChanged?: RuntimeHttpServerOptions["onProviderCredentialsChanged"];
|
|
368
|
-
private getHeartbeatService?: RuntimeHttpServerOptions["getHeartbeatService"];
|
|
369
|
-
private getFilingService?: RuntimeHttpServerOptions["getFilingService"];
|
|
230
|
+
|
|
231
|
+
private readonly liveVoiceSessionManager: LiveVoiceSessionManager;
|
|
370
232
|
private router: HttpRouter;
|
|
371
233
|
|
|
372
234
|
constructor(options: RuntimeHttpServerOptions = {}) {
|
|
373
235
|
this.port = options.port ?? DEFAULT_PORT;
|
|
374
236
|
this.hostname = options.hostname ?? DEFAULT_HOSTNAME;
|
|
375
|
-
|
|
376
|
-
this.processMessage = options.processMessage;
|
|
237
|
+
|
|
377
238
|
this.approvalCopyGenerator = options.approvalCopyGenerator;
|
|
378
239
|
this.approvalConversationGenerator = options.approvalConversationGenerator;
|
|
379
240
|
this.guardianActionCopyGenerator = options.guardianActionCopyGenerator;
|
|
380
241
|
this.guardianFollowUpConversationGenerator =
|
|
381
242
|
options.guardianFollowUpConversationGenerator;
|
|
382
|
-
this.
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
this.findConversationBySurfaceId = options.findConversationBySurfaceId;
|
|
386
|
-
this.getSkillContext = options.getSkillContext;
|
|
387
|
-
this.conversationManagementDeps = options.conversationManagementDeps;
|
|
388
|
-
this.getModelSetContext = options.getModelSetContext;
|
|
389
|
-
this.getRecordingDeps = options.getRecordingDeps;
|
|
390
|
-
this.getCesClient = options.getCesClient;
|
|
391
|
-
this.onProviderCredentialsChanged = options.onProviderCredentialsChanged;
|
|
392
|
-
this.getHeartbeatService = options.getHeartbeatService;
|
|
393
|
-
this.getFilingService = options.getFilingService;
|
|
243
|
+
this.liveVoiceSessionManager = new LiveVoiceSessionManager({
|
|
244
|
+
createSession: (context) => createLiveVoiceSession(context),
|
|
245
|
+
});
|
|
394
246
|
this.router = new HttpRouter(this.buildRouteTable());
|
|
395
247
|
}
|
|
396
248
|
|
|
@@ -399,40 +251,13 @@ export class RuntimeHttpServer {
|
|
|
399
251
|
return this.server?.port ?? this.port;
|
|
400
252
|
}
|
|
401
253
|
|
|
402
|
-
/** Expose the pairing store so the daemon server can wire HTTP handlers. */
|
|
403
|
-
getPairingStore(): PairingStore {
|
|
404
|
-
return this.pairingStore;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/** Set a callback for broadcasting server messages (wired by daemon server). */
|
|
408
|
-
setPairingBroadcast(fn: (msg: ServerMessage) => void): void {
|
|
409
|
-
this.pairingBroadcast = fn;
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
private get pairingContext(): PairingHandlerContext {
|
|
413
|
-
const broadcast = this.pairingBroadcast;
|
|
414
|
-
return {
|
|
415
|
-
pairingStore: this.pairingStore,
|
|
416
|
-
bearerToken: this.bearerToken,
|
|
417
|
-
pairingBroadcast: broadcast
|
|
418
|
-
? (msg) => {
|
|
419
|
-
// Broadcast to all clients via the event hub so HTTP/SSE clients
|
|
420
|
-
// (e.g. macOS app) receive pairing approval requests.
|
|
421
|
-
broadcast(msg);
|
|
422
|
-
void assistantEventHub.publish(
|
|
423
|
-
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, msg),
|
|
424
|
-
);
|
|
425
|
-
}
|
|
426
|
-
: undefined,
|
|
427
|
-
};
|
|
428
|
-
}
|
|
429
|
-
|
|
430
254
|
async start(): Promise<void> {
|
|
431
255
|
type AllWebSocketData =
|
|
432
256
|
| RelayWebSocketData
|
|
433
257
|
| BrowserRelayWebSocketData
|
|
434
258
|
| MediaStreamWebSocketData
|
|
435
|
-
| SttStreamWebSocketData
|
|
259
|
+
| SttStreamWebSocketData
|
|
260
|
+
| LiveVoiceWebSocketData;
|
|
436
261
|
this.server = Bun.serve<AllWebSocketData>({
|
|
437
262
|
port: this.port,
|
|
438
263
|
hostname: this.hostname,
|
|
@@ -440,7 +265,7 @@ export class RuntimeHttpServer {
|
|
|
440
265
|
maxRequestBodySize: MAX_REQUEST_BODY_BYTES,
|
|
441
266
|
fetch: (req, server) => this.handleRequest(req, server),
|
|
442
267
|
websocket: {
|
|
443
|
-
open(ws) {
|
|
268
|
+
open: (ws) => {
|
|
444
269
|
const data = ws.data as AllWebSocketData;
|
|
445
270
|
if ("wsType" in data && data.wsType === "browser-relay") {
|
|
446
271
|
// When the JWT sub resolved to a guardian principal at upgrade
|
|
@@ -547,6 +372,10 @@ export class RuntimeHttpServer {
|
|
|
547
372
|
);
|
|
548
373
|
return;
|
|
549
374
|
}
|
|
375
|
+
if ("wsType" in data && data.wsType === "live-voice") {
|
|
376
|
+
log.info("Live voice WebSocket opened");
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
550
379
|
const callSessionId = (data as RelayWebSocketData).callSessionId;
|
|
551
380
|
log.info({ callSessionId }, "ConversationRelay WebSocket opened");
|
|
552
381
|
if (callSessionId) {
|
|
@@ -557,7 +386,7 @@ export class RuntimeHttpServer {
|
|
|
557
386
|
activeRelayConnections.set(callSessionId, connection);
|
|
558
387
|
}
|
|
559
388
|
},
|
|
560
|
-
message(ws, message) {
|
|
389
|
+
message: (ws, message) => {
|
|
561
390
|
const data = ws.data as AllWebSocketData;
|
|
562
391
|
const raw =
|
|
563
392
|
typeof message === "string"
|
|
@@ -708,13 +537,32 @@ export class RuntimeHttpServer {
|
|
|
708
537
|
}
|
|
709
538
|
return;
|
|
710
539
|
}
|
|
540
|
+
if ("wsType" in data && data.wsType === "live-voice") {
|
|
541
|
+
void this.handleLiveVoiceMessage(
|
|
542
|
+
ws as ServerWebSocket<LiveVoiceWebSocketData>,
|
|
543
|
+
message,
|
|
544
|
+
).catch((err) => {
|
|
545
|
+
log.warn(
|
|
546
|
+
{ error: err instanceof Error ? err.message : String(err) },
|
|
547
|
+
"Live voice WebSocket message handler failed",
|
|
548
|
+
);
|
|
549
|
+
this.sendLiveVoiceError(
|
|
550
|
+
ws as ServerWebSocket<LiveVoiceWebSocketData>,
|
|
551
|
+
{
|
|
552
|
+
code: LiveVoiceProtocolErrorCode.InvalidFrame,
|
|
553
|
+
message: "Live voice frame handling failed",
|
|
554
|
+
},
|
|
555
|
+
);
|
|
556
|
+
});
|
|
557
|
+
return;
|
|
558
|
+
}
|
|
711
559
|
const callSessionId = (data as RelayWebSocketData).callSessionId;
|
|
712
560
|
if (callSessionId) {
|
|
713
561
|
const connection = activeRelayConnections.get(callSessionId);
|
|
714
562
|
connection?.handleMessage(raw);
|
|
715
563
|
}
|
|
716
564
|
},
|
|
717
|
-
close(ws, code, reason) {
|
|
565
|
+
close: (ws, code, reason) => {
|
|
718
566
|
const data = ws.data as AllWebSocketData;
|
|
719
567
|
if ("wsType" in data && data.wsType === "browser-relay") {
|
|
720
568
|
// Always attempt to unregister — the registry uses connectionId
|
|
@@ -775,6 +623,18 @@ export class RuntimeHttpServer {
|
|
|
775
623
|
}
|
|
776
624
|
return;
|
|
777
625
|
}
|
|
626
|
+
if ("wsType" in data && data.wsType === "live-voice") {
|
|
627
|
+
log.info(
|
|
628
|
+
{
|
|
629
|
+
sessionId: data.sessionId,
|
|
630
|
+
code,
|
|
631
|
+
reason: reason?.toString(),
|
|
632
|
+
},
|
|
633
|
+
"Live voice WebSocket closed",
|
|
634
|
+
);
|
|
635
|
+
this.releaseLiveVoiceSession(data, "websocket_close");
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
778
638
|
const callSessionId = (data as RelayWebSocketData).callSessionId;
|
|
779
639
|
log.info(
|
|
780
640
|
{ callSessionId, code, reason: reason?.toString() },
|
|
@@ -801,8 +661,6 @@ export class RuntimeHttpServer {
|
|
|
801
661
|
);
|
|
802
662
|
}
|
|
803
663
|
|
|
804
|
-
this.pairingStore.start();
|
|
805
|
-
|
|
806
664
|
if (hasUngatedHttpAuthDisabled()) {
|
|
807
665
|
log.warn(
|
|
808
666
|
"DISABLE_HTTP_AUTH is set but VELLUM_UNSAFE_AUTH_BYPASS=1 is not — auth bypass is IGNORED and HTTP authentication remains enabled. Set VELLUM_UNSAFE_AUTH_BYPASS=1 to confirm the bypass.",
|
|
@@ -817,15 +675,9 @@ export class RuntimeHttpServer {
|
|
|
817
675
|
{
|
|
818
676
|
port: this.actualPort,
|
|
819
677
|
hostname: this.hostname,
|
|
820
|
-
auth: !!this.bearerToken,
|
|
821
678
|
},
|
|
822
679
|
"Runtime HTTP server listening",
|
|
823
680
|
);
|
|
824
|
-
|
|
825
|
-
// Advertise the actual port to thin helpers that need to reach the
|
|
826
|
-
// runtime without inheriting the daemon's environment (e.g. the
|
|
827
|
-
// chrome-extension native messaging helper, spawned by Chrome).
|
|
828
|
-
this.writeRuntimePortFile(this.actualPort);
|
|
829
681
|
}
|
|
830
682
|
|
|
831
683
|
/**
|
|
@@ -834,108 +686,27 @@ export class RuntimeHttpServer {
|
|
|
834
686
|
* Extracted from start() to allow future callers to defer sweep startup.
|
|
835
687
|
*/
|
|
836
688
|
private startBackgroundSweeps(): void {
|
|
837
|
-
if (
|
|
838
|
-
const pm = this.processMessage;
|
|
839
|
-
const mintBt = () => mintDaemonDeliveryToken();
|
|
689
|
+
if (!this.retrySweepTimer) {
|
|
840
690
|
this.retrySweepTimer = setInterval(() => {
|
|
841
691
|
if (this.sweepInProgress) return;
|
|
842
692
|
this.sweepInProgress = true;
|
|
843
|
-
sweepFailedEvents(
|
|
693
|
+
sweepFailedEvents(processMessage).finally(() => {
|
|
844
694
|
this.sweepInProgress = false;
|
|
845
695
|
});
|
|
846
696
|
}, 30_000);
|
|
847
697
|
}
|
|
848
698
|
|
|
849
|
-
startGuardianExpirySweep(
|
|
850
|
-
getGatewayInternalBaseUrl(),
|
|
851
|
-
() => mintDaemonDeliveryToken(),
|
|
852
|
-
this.approvalCopyGenerator,
|
|
853
|
-
);
|
|
699
|
+
startGuardianExpirySweep(this.approvalCopyGenerator);
|
|
854
700
|
log.info("Guardian approval expiry sweep started");
|
|
855
701
|
|
|
856
|
-
startGuardianActionSweep(
|
|
857
|
-
getGatewayInternalBaseUrl(),
|
|
858
|
-
() => mintDaemonDeliveryToken(),
|
|
859
|
-
this.guardianActionCopyGenerator,
|
|
860
|
-
);
|
|
702
|
+
startGuardianActionSweep(this.guardianActionCopyGenerator);
|
|
861
703
|
log.info("Guardian action expiry sweep started");
|
|
862
704
|
|
|
863
705
|
startCanonicalGuardianExpirySweep();
|
|
864
706
|
log.info("Canonical guardian request expiry sweep started");
|
|
865
707
|
}
|
|
866
708
|
|
|
867
|
-
/**
|
|
868
|
-
* Atomically publish the runtime HTTP port to ~/.vellum/runtime-port so
|
|
869
|
-
* external helpers can locate a non-default `RUNTIME_HTTP_PORT` without
|
|
870
|
-
* any manifest changes. Best-effort — write failures never block
|
|
871
|
-
* daemon startup (see assistant/AGENTS.md "Daemon startup philosophy").
|
|
872
|
-
*/
|
|
873
|
-
private writeRuntimePortFile(actualPort: number): void {
|
|
874
|
-
try {
|
|
875
|
-
const portFile = getRuntimePortFilePath();
|
|
876
|
-
const dir = dirname(portFile);
|
|
877
|
-
if (!existsSync(dir)) {
|
|
878
|
-
mkdirSync(dir, { recursive: true });
|
|
879
|
-
}
|
|
880
|
-
const tmpPath = `${portFile}.tmp.${process.pid}`;
|
|
881
|
-
writeFileSync(tmpPath, String(actualPort), { mode: 0o644 });
|
|
882
|
-
renameSync(tmpPath, portFile);
|
|
883
|
-
log.info({ portFile, actualPort }, "Wrote runtime port file");
|
|
884
|
-
} catch (err) {
|
|
885
|
-
log.warn(
|
|
886
|
-
{ err },
|
|
887
|
-
"Failed to write runtime port file; non-default assistant ports may require --assistant-port on thin helpers",
|
|
888
|
-
);
|
|
889
|
-
}
|
|
890
|
-
}
|
|
891
|
-
|
|
892
|
-
/**
|
|
893
|
-
* Remove the runtime port file written by `writeRuntimePortFile`.
|
|
894
|
-
* Called from `stop()` on clean shutdown so a stale file does not
|
|
895
|
-
* point thin helpers (e.g. the chrome-extension native messaging
|
|
896
|
-
* helper) at a dead port until the next daemon start overwrites it.
|
|
897
|
-
* Best-effort — unlink failures never block shutdown.
|
|
898
|
-
*
|
|
899
|
-
* The unlink is conditional: we only remove the file if its current
|
|
900
|
-
* contents still match this server's port. The runtime-port file
|
|
901
|
-
* lives at the user-home level (`~/.vellum/runtime-port`) and is
|
|
902
|
-
* therefore shared across multiple daemon instances running on
|
|
903
|
-
* different `RUNTIME_HTTP_PORT`s. If a sibling instance has already
|
|
904
|
-
* rewritten the file with its own port, deleting it would strand
|
|
905
|
-
* thin helpers on the default port `7821` and break their ability
|
|
906
|
-
* to reach the still-running sibling.
|
|
907
|
-
*
|
|
908
|
-
* Note: this only runs on graceful shutdown. A crash leaves the
|
|
909
|
-
* file in place; the next successful startup overwrites it.
|
|
910
|
-
*/
|
|
911
|
-
private removeRuntimePortFile(): void {
|
|
912
|
-
try {
|
|
913
|
-
const portFile = getRuntimePortFilePath();
|
|
914
|
-
if (!existsSync(portFile)) return;
|
|
915
|
-
// Read-then-compare-then-unlink. Race-safe enough: the worst case
|
|
916
|
-
// is that another instance writes the file between our read and
|
|
917
|
-
// our unlink, in which case we erroneously delete its mapping.
|
|
918
|
-
// That window is short (a few microseconds) and a sibling startup
|
|
919
|
-
// will rewrite the file on its next port-publish call. The much
|
|
920
|
-
// more common multi-instance race — sibling already overwrote
|
|
921
|
-
// before our stop() runs — is correctly handled here as a no-op.
|
|
922
|
-
const current = readFileSync(portFile, "utf-8").trim();
|
|
923
|
-
if (current !== String(this.actualPort)) {
|
|
924
|
-
log.info(
|
|
925
|
-
{ portFile, current, actualPort: this.actualPort },
|
|
926
|
-
"Leaving runtime port file alone — owned by another instance",
|
|
927
|
-
);
|
|
928
|
-
return;
|
|
929
|
-
}
|
|
930
|
-
unlinkSync(portFile);
|
|
931
|
-
log.info({ portFile }, "Removed runtime port file");
|
|
932
|
-
} catch (err) {
|
|
933
|
-
log.warn({ err }, "Failed to remove runtime port file");
|
|
934
|
-
}
|
|
935
|
-
}
|
|
936
|
-
|
|
937
709
|
async stop(): Promise<void> {
|
|
938
|
-
this.pairingStore.stop();
|
|
939
710
|
stopGuardianExpirySweep();
|
|
940
711
|
stopGuardianActionSweep();
|
|
941
712
|
stopCanonicalGuardianExpirySweep();
|
|
@@ -952,12 +723,19 @@ export class RuntimeHttpServer {
|
|
|
952
723
|
activeSttStreamSessions.delete(sessionId);
|
|
953
724
|
}
|
|
954
725
|
|
|
726
|
+
const liveVoiceSessionId = this.liveVoiceSessionManager.activeSessionId;
|
|
727
|
+
if (liveVoiceSessionId) {
|
|
728
|
+
await this.liveVoiceSessionManager.releaseSession(
|
|
729
|
+
liveVoiceSessionId,
|
|
730
|
+
"manager_shutdown",
|
|
731
|
+
);
|
|
732
|
+
}
|
|
733
|
+
|
|
955
734
|
if (this.server) {
|
|
956
735
|
this.server.stop(true);
|
|
957
736
|
this.server = null;
|
|
958
737
|
log.info("Runtime HTTP server stopped");
|
|
959
738
|
}
|
|
960
|
-
this.removeRuntimePortFile();
|
|
961
739
|
}
|
|
962
740
|
|
|
963
741
|
private async handleRequest(
|
|
@@ -1026,43 +804,48 @@ export class RuntimeHttpServer {
|
|
|
1026
804
|
return this.handleSttStreamUpgrade(req, server);
|
|
1027
805
|
}
|
|
1028
806
|
|
|
807
|
+
// WebSocket upgrade for live voice — same private-network restrictions
|
|
808
|
+
// and gateway-service token verification as STT streaming.
|
|
809
|
+
if (
|
|
810
|
+
path === "/v1/live-voice" &&
|
|
811
|
+
req.headers.get("upgrade")?.toLowerCase() === "websocket"
|
|
812
|
+
) {
|
|
813
|
+
return this.handleLiveVoiceUpgrade(req, server);
|
|
814
|
+
}
|
|
815
|
+
|
|
1029
816
|
// Twilio webhook endpoints — before auth check because Twilio
|
|
1030
817
|
// webhook POSTs don't include bearer tokens.
|
|
1031
818
|
const twilioResponse = await this.handleTwilioWebhook(req, path);
|
|
1032
819
|
if (twilioResponse) return twilioResponse;
|
|
1033
820
|
|
|
1034
821
|
// Audio serving endpoint — before auth check because Twilio
|
|
1035
|
-
// fetches these URLs directly
|
|
822
|
+
// fetches these URLs directly (isPublic route, ATL-314).
|
|
1036
823
|
const audioMatch = path.match(/^\/v1\/audio\/([^/]+)$/);
|
|
1037
824
|
if (audioMatch && req.method === "GET") {
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
|
|
1052
|
-
|
|
1053
|
-
|
|
1054
|
-
|
|
1055
|
-
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return await handleGuardianBootstrap(req, server);
|
|
1063
|
-
}
|
|
1064
|
-
if (path === "/v1/guardian/refresh" && req.method === "POST") {
|
|
1065
|
-
return await handleGuardianRefresh(req);
|
|
825
|
+
const audioDef = AUDIO_ROUTES.find((r) => r.operationId === "audio_get")!;
|
|
826
|
+
const args = { pathParams: { audioId: audioMatch[1] } };
|
|
827
|
+
try {
|
|
828
|
+
const result = await audioDef.handler(args);
|
|
829
|
+
const headers =
|
|
830
|
+
typeof audioDef.responseHeaders === "function"
|
|
831
|
+
? audioDef.responseHeaders(args)
|
|
832
|
+
: audioDef.responseHeaders;
|
|
833
|
+
if (result instanceof ReadableStream) {
|
|
834
|
+
return new Response(result as ReadableStream<Uint8Array>, {
|
|
835
|
+
headers,
|
|
836
|
+
});
|
|
837
|
+
}
|
|
838
|
+
return new Response(result as BodyInit, { headers });
|
|
839
|
+
} catch (err) {
|
|
840
|
+
if (err instanceof RouteError) {
|
|
841
|
+
return httpError(
|
|
842
|
+
err.code as HttpErrorCode,
|
|
843
|
+
err.message,
|
|
844
|
+
err.statusCode,
|
|
845
|
+
);
|
|
846
|
+
}
|
|
847
|
+
throw err;
|
|
848
|
+
}
|
|
1066
849
|
}
|
|
1067
850
|
|
|
1068
851
|
// Skill-registered routes (e.g. meet-bot event ingress). Handled before
|
|
@@ -1092,7 +875,7 @@ export class RuntimeHttpServer {
|
|
|
1092
875
|
const normalizedPath = path.endsWith("/") ? path.slice(0, -1) : path;
|
|
1093
876
|
const authResult =
|
|
1094
877
|
normalizedPath === "/v1/host-browser-result" && req.method === "POST"
|
|
1095
|
-
? authenticateHostBrowserResultRequest(req)
|
|
878
|
+
? await authenticateHostBrowserResultRequest(req)
|
|
1096
879
|
: authenticateRequest(req);
|
|
1097
880
|
if (!authResult.ok) {
|
|
1098
881
|
return authResult.response;
|
|
@@ -1102,9 +885,18 @@ export class RuntimeHttpServer {
|
|
|
1102
885
|
// Serve shareable app pages (outside /v1/ namespace, no rate limiting)
|
|
1103
886
|
const pagesMatch = path.match(/^\/pages\/([^/]+)$/);
|
|
1104
887
|
if (pagesMatch && req.method === "GET") {
|
|
1105
|
-
return withErrorHandling("pages", async () =>
|
|
1106
|
-
|
|
1107
|
-
|
|
888
|
+
return withErrorHandling("pages", async () => {
|
|
889
|
+
const pageDef = APP_ROUTES.find(
|
|
890
|
+
(r) => r.operationId === "pages_serve",
|
|
891
|
+
)!;
|
|
892
|
+
const args = { pathParams: { appId: pagesMatch[1] } };
|
|
893
|
+
const body = pageDef.handler(args) as string;
|
|
894
|
+
const headers =
|
|
895
|
+
typeof pageDef.responseHeaders === "function"
|
|
896
|
+
? pageDef.responseHeaders(args)
|
|
897
|
+
: pageDef.responseHeaders;
|
|
898
|
+
return new Response(body, { headers });
|
|
899
|
+
});
|
|
1108
900
|
}
|
|
1109
901
|
|
|
1110
902
|
// Per-client-IP rate limiting for /v1/* endpoints. Authenticated requests
|
|
@@ -1166,10 +958,10 @@ export class RuntimeHttpServer {
|
|
|
1166
958
|
return routerResponse ?? httpError("NOT_FOUND", "Not found", 404);
|
|
1167
959
|
}
|
|
1168
960
|
|
|
1169
|
-
private handleBrowserRelayUpgrade(
|
|
961
|
+
private async handleBrowserRelayUpgrade(
|
|
1170
962
|
req: Request,
|
|
1171
963
|
server: ReturnType<typeof Bun.serve>,
|
|
1172
|
-
): Response {
|
|
964
|
+
): Promise<Response> {
|
|
1173
965
|
if (
|
|
1174
966
|
!isLoopbackHost(new URL(req.url).hostname) &&
|
|
1175
967
|
!isPrivateNetworkPeer(server, req)
|
|
@@ -1185,8 +977,8 @@ export class RuntimeHttpServer {
|
|
|
1185
977
|
// `/v1/browser-relay` handshake:
|
|
1186
978
|
//
|
|
1187
979
|
// 1. **Capability token** — a signed `host_browser_command`
|
|
1188
|
-
// capability minted by
|
|
1189
|
-
//
|
|
980
|
+
// capability minted by the gateway and handed to the chrome
|
|
981
|
+
// extension by the native-messaging pair flow
|
|
1190
982
|
// (`/v1/browser-extension-pair`). This is the preferred,
|
|
1191
983
|
// self-hosted default: the extension never has to touch a
|
|
1192
984
|
// gateway JWT.
|
|
@@ -1235,7 +1027,7 @@ export class RuntimeHttpServer {
|
|
|
1235
1027
|
// messaging pair flow. We derive `guardianId` from the
|
|
1236
1028
|
// capability claims directly — the claims are HMAC-signed by
|
|
1237
1029
|
// the same daemon so there is no cross-tenant risk.
|
|
1238
|
-
const capabilityClaims = verifyHostBrowserCapability(token);
|
|
1030
|
+
const capabilityClaims = await verifyHostBrowserCapability(token);
|
|
1239
1031
|
if (capabilityClaims) {
|
|
1240
1032
|
guardianId = capabilityClaims.guardianId;
|
|
1241
1033
|
} else {
|
|
@@ -1304,6 +1096,28 @@ export class RuntimeHttpServer {
|
|
|
1304
1096
|
return undefined!;
|
|
1305
1097
|
}
|
|
1306
1098
|
|
|
1099
|
+
private verifyGatewayServiceToken(req: Request): Response | null {
|
|
1100
|
+
if (isHttpAuthDisabled()) return null;
|
|
1101
|
+
|
|
1102
|
+
const wsUrl = new URL(req.url);
|
|
1103
|
+
const token = wsUrl.searchParams.get("token");
|
|
1104
|
+
if (!token) {
|
|
1105
|
+
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
const jwtResult = verifyToken(token, "vellum-daemon");
|
|
1109
|
+
if (!jwtResult.ok) {
|
|
1110
|
+
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
const subResult = parseSub(jwtResult.claims.sub);
|
|
1114
|
+
if (!subResult.ok || subResult.principalType !== "svc_gateway") {
|
|
1115
|
+
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return null;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
1307
1121
|
private handleRelayUpgrade(
|
|
1308
1122
|
req: Request,
|
|
1309
1123
|
server: ReturnType<typeof Bun.serve>,
|
|
@@ -1316,6 +1130,10 @@ export class RuntimeHttpServer {
|
|
|
1316
1130
|
);
|
|
1317
1131
|
}
|
|
1318
1132
|
|
|
1133
|
+
// Verify the gateway service token before accepting the upgrade.
|
|
1134
|
+
const tokenError = this.verifyGatewayServiceToken(req);
|
|
1135
|
+
if (tokenError) return tokenError;
|
|
1136
|
+
|
|
1319
1137
|
const wsUrl = new URL(req.url);
|
|
1320
1138
|
const callSessionId = wsUrl.searchParams.get("callSessionId");
|
|
1321
1139
|
if (!callSessionId) {
|
|
@@ -1341,6 +1159,10 @@ export class RuntimeHttpServer {
|
|
|
1341
1159
|
);
|
|
1342
1160
|
}
|
|
1343
1161
|
|
|
1162
|
+
// Verify the gateway service token before accepting the upgrade.
|
|
1163
|
+
const tokenError = this.verifyGatewayServiceToken(req);
|
|
1164
|
+
if (tokenError) return tokenError;
|
|
1165
|
+
|
|
1344
1166
|
const wsUrl = new URL(req.url);
|
|
1345
1167
|
const callSessionId = wsUrl.searchParams.get("callSessionId");
|
|
1346
1168
|
if (!callSessionId) {
|
|
@@ -1382,23 +1204,8 @@ export class RuntimeHttpServer {
|
|
|
1382
1204
|
}
|
|
1383
1205
|
|
|
1384
1206
|
// Verify the gateway service token before accepting the upgrade.
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
const token = wsUrl.searchParams.get("token");
|
|
1388
|
-
if (!token) {
|
|
1389
|
-
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1390
|
-
}
|
|
1391
|
-
const jwtResult = verifyToken(token, "vellum-daemon");
|
|
1392
|
-
if (!jwtResult.ok) {
|
|
1393
|
-
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1394
|
-
}
|
|
1395
|
-
// Accept gateway service tokens (svc:gateway:*) — these are the
|
|
1396
|
-
// only tokens the gateway mints for upstream connections.
|
|
1397
|
-
const subResult = parseSub(jwtResult.claims.sub);
|
|
1398
|
-
if (!subResult.ok || subResult.principalType !== "svc_gateway") {
|
|
1399
|
-
return httpError("UNAUTHORIZED", "Unauthorized", 401);
|
|
1400
|
-
}
|
|
1401
|
-
}
|
|
1207
|
+
const tokenError = this.verifyGatewayServiceToken(req);
|
|
1208
|
+
if (tokenError) return tokenError;
|
|
1402
1209
|
|
|
1403
1210
|
const wsUrl = new URL(req.url);
|
|
1404
1211
|
// provider is optional compatibility metadata — the runtime resolves
|
|
@@ -1431,6 +1238,175 @@ export class RuntimeHttpServer {
|
|
|
1431
1238
|
return undefined!;
|
|
1432
1239
|
}
|
|
1433
1240
|
|
|
1241
|
+
/**
|
|
1242
|
+
* Handle WebSocket upgrade for `/v1/live-voice`.
|
|
1243
|
+
*
|
|
1244
|
+
* The gateway owns downstream client auth and forwards this upstream with
|
|
1245
|
+
* a short-lived gateway service token. The runtime accepts only private
|
|
1246
|
+
* network peers/origins so the shell is not publicly reachable.
|
|
1247
|
+
*/
|
|
1248
|
+
private handleLiveVoiceUpgrade(
|
|
1249
|
+
req: Request,
|
|
1250
|
+
server: ReturnType<typeof Bun.serve>,
|
|
1251
|
+
): Response {
|
|
1252
|
+
if (!isPrivateNetworkPeer(server, req) || !isPrivateNetworkOrigin(req)) {
|
|
1253
|
+
return httpError(
|
|
1254
|
+
"FORBIDDEN",
|
|
1255
|
+
"Direct live voice access disabled — only private network peers allowed",
|
|
1256
|
+
403,
|
|
1257
|
+
);
|
|
1258
|
+
}
|
|
1259
|
+
|
|
1260
|
+
const tokenError = this.verifyGatewayServiceToken(req);
|
|
1261
|
+
if (tokenError) return tokenError;
|
|
1262
|
+
|
|
1263
|
+
const upgraded = server.upgrade(req, {
|
|
1264
|
+
data: {
|
|
1265
|
+
wsType: "live-voice",
|
|
1266
|
+
lastSeq: 0,
|
|
1267
|
+
} satisfies LiveVoiceWebSocketData,
|
|
1268
|
+
});
|
|
1269
|
+
if (!upgraded) {
|
|
1270
|
+
return new Response("WebSocket upgrade failed", { status: 500 });
|
|
1271
|
+
}
|
|
1272
|
+
return undefined!;
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
private async handleLiveVoiceMessage(
|
|
1276
|
+
ws: ServerWebSocket<LiveVoiceWebSocketData>,
|
|
1277
|
+
message: string | ArrayBuffer | ArrayBufferView,
|
|
1278
|
+
): Promise<void> {
|
|
1279
|
+
if (typeof message === "string") {
|
|
1280
|
+
const result = parseLiveVoiceClientTextFrame(message);
|
|
1281
|
+
if (!result.ok) {
|
|
1282
|
+
this.sendLiveVoiceError(ws, result.error);
|
|
1283
|
+
return;
|
|
1284
|
+
}
|
|
1285
|
+
await this.dispatchLiveVoiceClientFrame(ws, result.frame);
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
|
|
1289
|
+
const result = parseLiveVoiceBinaryAudioFrame(message);
|
|
1290
|
+
if (!result.ok) {
|
|
1291
|
+
this.sendLiveVoiceError(ws, result.error);
|
|
1292
|
+
return;
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
const sessionId = ws.data.sessionId;
|
|
1296
|
+
if (!sessionId) {
|
|
1297
|
+
this.sendLiveVoiceStateError(
|
|
1298
|
+
ws,
|
|
1299
|
+
"Live voice binary audio received before start",
|
|
1300
|
+
);
|
|
1301
|
+
return;
|
|
1302
|
+
}
|
|
1303
|
+
|
|
1304
|
+
const handled = await this.liveVoiceSessionManager.handleBinaryAudio(
|
|
1305
|
+
sessionId,
|
|
1306
|
+
result.frame.data,
|
|
1307
|
+
);
|
|
1308
|
+
if (handled.status === "not_found") {
|
|
1309
|
+
ws.data.sessionId = undefined;
|
|
1310
|
+
this.sendLiveVoiceStateError(ws, "Live voice session is not active");
|
|
1311
|
+
}
|
|
1312
|
+
}
|
|
1313
|
+
|
|
1314
|
+
private async dispatchLiveVoiceClientFrame(
|
|
1315
|
+
ws: ServerWebSocket<LiveVoiceWebSocketData>,
|
|
1316
|
+
frame: LiveVoiceClientFrame,
|
|
1317
|
+
): Promise<void> {
|
|
1318
|
+
if (frame.type === "start") {
|
|
1319
|
+
if (ws.data.sessionId) {
|
|
1320
|
+
this.sendLiveVoiceStateError(ws, "Live voice session already started");
|
|
1321
|
+
return;
|
|
1322
|
+
}
|
|
1323
|
+
|
|
1324
|
+
const result = await this.liveVoiceSessionManager.startSession(frame, {
|
|
1325
|
+
sendFrame: async (serverFrame) => {
|
|
1326
|
+
this.sendLiveVoiceFrame(ws, serverFrame);
|
|
1327
|
+
},
|
|
1328
|
+
});
|
|
1329
|
+
if (result.status === "accepted") {
|
|
1330
|
+
ws.data.sessionId = result.sessionId;
|
|
1331
|
+
}
|
|
1332
|
+
return;
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
const sessionId = ws.data.sessionId;
|
|
1336
|
+
if (!sessionId) {
|
|
1337
|
+
this.sendLiveVoiceStateError(
|
|
1338
|
+
ws,
|
|
1339
|
+
`Live voice ${frame.type} frame received before start`,
|
|
1340
|
+
);
|
|
1341
|
+
return;
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
const handled = await this.liveVoiceSessionManager.handleClientFrame(
|
|
1345
|
+
sessionId,
|
|
1346
|
+
frame,
|
|
1347
|
+
);
|
|
1348
|
+
if (handled.status === "not_found") {
|
|
1349
|
+
ws.data.sessionId = undefined;
|
|
1350
|
+
this.sendLiveVoiceStateError(ws, "Live voice session is not active");
|
|
1351
|
+
return;
|
|
1352
|
+
}
|
|
1353
|
+
|
|
1354
|
+
if (frame.type === "end") {
|
|
1355
|
+
ws.data.sessionId = undefined;
|
|
1356
|
+
}
|
|
1357
|
+
}
|
|
1358
|
+
|
|
1359
|
+
private sendLiveVoiceStateError(
|
|
1360
|
+
ws: ServerWebSocket<LiveVoiceWebSocketData>,
|
|
1361
|
+
message: string,
|
|
1362
|
+
): void {
|
|
1363
|
+
this.sendLiveVoiceError(ws, {
|
|
1364
|
+
code: LiveVoiceProtocolErrorCode.InvalidFrame,
|
|
1365
|
+
message,
|
|
1366
|
+
});
|
|
1367
|
+
}
|
|
1368
|
+
|
|
1369
|
+
private sendLiveVoiceError(
|
|
1370
|
+
ws: ServerWebSocket<LiveVoiceWebSocketData>,
|
|
1371
|
+
error: Pick<LiveVoiceProtocolError, "code" | "message">,
|
|
1372
|
+
): void {
|
|
1373
|
+
this.sendLiveVoiceFrame(ws, {
|
|
1374
|
+
type: "error",
|
|
1375
|
+
seq: ws.data.lastSeq + 1,
|
|
1376
|
+
code: error.code,
|
|
1377
|
+
message: error.message,
|
|
1378
|
+
});
|
|
1379
|
+
}
|
|
1380
|
+
|
|
1381
|
+
private sendLiveVoiceFrame(
|
|
1382
|
+
ws: ServerWebSocket<LiveVoiceWebSocketData>,
|
|
1383
|
+
frame: LiveVoiceServerFrame,
|
|
1384
|
+
): void {
|
|
1385
|
+
ws.data.lastSeq = Math.max(ws.data.lastSeq, frame.seq);
|
|
1386
|
+
ws.send(JSON.stringify(frame));
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
private releaseLiveVoiceSession(
|
|
1390
|
+
data: LiveVoiceWebSocketData,
|
|
1391
|
+
reason: "websocket_close",
|
|
1392
|
+
): void {
|
|
1393
|
+
const sessionId = data.sessionId;
|
|
1394
|
+
data.sessionId = undefined;
|
|
1395
|
+
if (!sessionId) return;
|
|
1396
|
+
|
|
1397
|
+
void this.liveVoiceSessionManager
|
|
1398
|
+
.releaseSession(sessionId, reason)
|
|
1399
|
+
.catch((err) => {
|
|
1400
|
+
log.warn(
|
|
1401
|
+
{
|
|
1402
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1403
|
+
sessionId,
|
|
1404
|
+
},
|
|
1405
|
+
"Failed to release live voice session",
|
|
1406
|
+
);
|
|
1407
|
+
});
|
|
1408
|
+
}
|
|
1409
|
+
|
|
1434
1410
|
private async handleTwilioWebhook(
|
|
1435
1411
|
req: Request,
|
|
1436
1412
|
path: string,
|
|
@@ -1471,202 +1447,6 @@ export class RuntimeHttpServer {
|
|
|
1471
1447
|
return null;
|
|
1472
1448
|
}
|
|
1473
1449
|
|
|
1474
|
-
private handleGetInterface(interfacePath: string): Response {
|
|
1475
|
-
if (!this.interfacesDir) {
|
|
1476
|
-
return httpError("NOT_FOUND", "Interface not found", 404);
|
|
1477
|
-
}
|
|
1478
|
-
const fullPath = resolve(this.interfacesDir, interfacePath);
|
|
1479
|
-
if (
|
|
1480
|
-
(fullPath !== this.interfacesDir &&
|
|
1481
|
-
!fullPath.startsWith(this.interfacesDir + "/")) ||
|
|
1482
|
-
!existsSync(fullPath)
|
|
1483
|
-
) {
|
|
1484
|
-
return httpError("NOT_FOUND", "Interface not found", 404);
|
|
1485
|
-
}
|
|
1486
|
-
const source = readFileSync(fullPath, "utf-8");
|
|
1487
|
-
return new Response(source, {
|
|
1488
|
-
headers: { "Content-Type": "text/plain; charset=utf-8" },
|
|
1489
|
-
});
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
private buildAssistantAttention(attentionState: AttentionState | undefined):
|
|
1493
|
-
| {
|
|
1494
|
-
hasUnseenLatestAssistantMessage: boolean;
|
|
1495
|
-
latestAssistantMessageAt?: number;
|
|
1496
|
-
lastSeenAssistantMessageAt?: number;
|
|
1497
|
-
lastSeenConfidence?: Confidence;
|
|
1498
|
-
lastSeenSignalType?: SignalType;
|
|
1499
|
-
}
|
|
1500
|
-
| undefined {
|
|
1501
|
-
if (!attentionState) return undefined;
|
|
1502
|
-
|
|
1503
|
-
return {
|
|
1504
|
-
hasUnseenLatestAssistantMessage:
|
|
1505
|
-
attentionState.latestAssistantMessageAt != null &&
|
|
1506
|
-
(attentionState.lastSeenAssistantMessageAt == null ||
|
|
1507
|
-
attentionState.lastSeenAssistantMessageAt <
|
|
1508
|
-
attentionState.latestAssistantMessageAt),
|
|
1509
|
-
...(attentionState.latestAssistantMessageAt != null
|
|
1510
|
-
? {
|
|
1511
|
-
latestAssistantMessageAt: attentionState.latestAssistantMessageAt,
|
|
1512
|
-
}
|
|
1513
|
-
: {}),
|
|
1514
|
-
...(attentionState.lastSeenAssistantMessageAt != null
|
|
1515
|
-
? {
|
|
1516
|
-
lastSeenAssistantMessageAt:
|
|
1517
|
-
attentionState.lastSeenAssistantMessageAt,
|
|
1518
|
-
}
|
|
1519
|
-
: {}),
|
|
1520
|
-
...(attentionState.lastSeenConfidence != null
|
|
1521
|
-
? { lastSeenConfidence: attentionState.lastSeenConfidence }
|
|
1522
|
-
: {}),
|
|
1523
|
-
...(attentionState.lastSeenSignalType != null
|
|
1524
|
-
? { lastSeenSignalType: attentionState.lastSeenSignalType }
|
|
1525
|
-
: {}),
|
|
1526
|
-
};
|
|
1527
|
-
}
|
|
1528
|
-
|
|
1529
|
-
private buildForkParent(
|
|
1530
|
-
conversation: ConversationRow,
|
|
1531
|
-
parentCache: Map<string, ConversationRow | null>,
|
|
1532
|
-
): { conversationId: string; messageId: string; title: string } | undefined {
|
|
1533
|
-
const parentConversationId = conversation.forkParentConversationId;
|
|
1534
|
-
const parentMessageId = conversation.forkParentMessageId;
|
|
1535
|
-
if (!parentConversationId || !parentMessageId) return undefined;
|
|
1536
|
-
|
|
1537
|
-
let parentConversation: ConversationRow | null | undefined =
|
|
1538
|
-
parentCache.get(parentConversationId);
|
|
1539
|
-
if (parentConversation === undefined) {
|
|
1540
|
-
parentConversation = getConversation(parentConversationId);
|
|
1541
|
-
parentCache.set(parentConversationId, parentConversation);
|
|
1542
|
-
}
|
|
1543
|
-
if (
|
|
1544
|
-
!parentConversation ||
|
|
1545
|
-
parentConversation.conversationType === "private"
|
|
1546
|
-
) {
|
|
1547
|
-
return undefined;
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
return {
|
|
1551
|
-
conversationId: parentConversationId,
|
|
1552
|
-
messageId: parentMessageId,
|
|
1553
|
-
title: parentConversation.title ?? "Untitled",
|
|
1554
|
-
};
|
|
1555
|
-
}
|
|
1556
|
-
|
|
1557
|
-
private serializeConversationSummary(params: {
|
|
1558
|
-
conversation: ConversationRow;
|
|
1559
|
-
binding?: ExternalConversationBinding | null;
|
|
1560
|
-
attentionState?: AttentionState;
|
|
1561
|
-
displayMeta?: {
|
|
1562
|
-
displayOrder: number | null;
|
|
1563
|
-
isPinned: boolean;
|
|
1564
|
-
groupId: string | null;
|
|
1565
|
-
};
|
|
1566
|
-
parentCache: Map<string, ConversationRow | null>;
|
|
1567
|
-
}) {
|
|
1568
|
-
const { conversation, binding, attentionState, displayMeta, parentCache } =
|
|
1569
|
-
params;
|
|
1570
|
-
const originChannel = parseChannelId(conversation.originChannel);
|
|
1571
|
-
const assistantAttention = this.buildAssistantAttention(attentionState);
|
|
1572
|
-
const forkParent = this.buildForkParent(conversation, parentCache);
|
|
1573
|
-
|
|
1574
|
-
return {
|
|
1575
|
-
id: conversation.id,
|
|
1576
|
-
title: conversation.title ?? "Untitled",
|
|
1577
|
-
createdAt: conversation.createdAt,
|
|
1578
|
-
updatedAt: conversation.updatedAt,
|
|
1579
|
-
lastMessageAt: conversation.lastMessageAt,
|
|
1580
|
-
conversationType: conversation.conversationType ?? "standard",
|
|
1581
|
-
source: conversation.source ?? "user",
|
|
1582
|
-
hostAccess: conversation.hostAccess === 1,
|
|
1583
|
-
...(conversation.scheduleJobId
|
|
1584
|
-
? { scheduleJobId: conversation.scheduleJobId }
|
|
1585
|
-
: {}),
|
|
1586
|
-
...(binding
|
|
1587
|
-
? {
|
|
1588
|
-
channelBinding: {
|
|
1589
|
-
sourceChannel: binding.sourceChannel,
|
|
1590
|
-
externalChatId: binding.externalChatId,
|
|
1591
|
-
externalUserId: binding.externalUserId,
|
|
1592
|
-
displayName: binding.displayName,
|
|
1593
|
-
username: binding.username,
|
|
1594
|
-
},
|
|
1595
|
-
}
|
|
1596
|
-
: {}),
|
|
1597
|
-
...(originChannel ? { conversationOriginChannel: originChannel } : {}),
|
|
1598
|
-
...(assistantAttention ? { assistantAttention } : {}),
|
|
1599
|
-
...(displayMeta?.isPinned
|
|
1600
|
-
? {
|
|
1601
|
-
isPinned: true as const,
|
|
1602
|
-
displayOrder: displayMeta.displayOrder,
|
|
1603
|
-
}
|
|
1604
|
-
: displayMeta?.displayOrder != null
|
|
1605
|
-
? {
|
|
1606
|
-
displayOrder: displayMeta.displayOrder,
|
|
1607
|
-
}
|
|
1608
|
-
: {}),
|
|
1609
|
-
groupId: displayMeta?.groupId ?? null,
|
|
1610
|
-
...(forkParent ? { forkParent } : {}),
|
|
1611
|
-
...(conversation.archivedAt != null
|
|
1612
|
-
? { archivedAt: conversation.archivedAt }
|
|
1613
|
-
: {}),
|
|
1614
|
-
};
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
private buildConversationDetailResponse(conversationId: string) {
|
|
1618
|
-
const conversation = getConversation(conversationId);
|
|
1619
|
-
if (!conversation) {
|
|
1620
|
-
return null;
|
|
1621
|
-
}
|
|
1622
|
-
|
|
1623
|
-
const bindings = externalConversationStore.getBindingsForConversations([
|
|
1624
|
-
conversation.id,
|
|
1625
|
-
]);
|
|
1626
|
-
const attentionStates = getAttentionStateByConversationIds([
|
|
1627
|
-
conversation.id,
|
|
1628
|
-
]);
|
|
1629
|
-
const displayMeta = getDisplayMetaForConversations([conversation.id]);
|
|
1630
|
-
const parentCache = new Map<string, ConversationRow | null>();
|
|
1631
|
-
|
|
1632
|
-
return {
|
|
1633
|
-
conversation: this.serializeConversationSummary({
|
|
1634
|
-
conversation,
|
|
1635
|
-
binding: bindings.get(conversation.id),
|
|
1636
|
-
attentionState: attentionStates.get(conversation.id),
|
|
1637
|
-
displayMeta: displayMeta.get(conversation.id),
|
|
1638
|
-
parentCache,
|
|
1639
|
-
}),
|
|
1640
|
-
};
|
|
1641
|
-
}
|
|
1642
|
-
|
|
1643
|
-
private getConversationManagementRouteDeps(): ConversationManagementDeps | null {
|
|
1644
|
-
if (!this.conversationManagementDeps) {
|
|
1645
|
-
return null;
|
|
1646
|
-
}
|
|
1647
|
-
|
|
1648
|
-
return {
|
|
1649
|
-
...this.conversationManagementDeps,
|
|
1650
|
-
forkConversation:
|
|
1651
|
-
this.conversationManagementDeps.forkConversation ??
|
|
1652
|
-
(async ({ conversationId, throughMessageId }) => {
|
|
1653
|
-
const forkedConversation = forkConversationInStore({
|
|
1654
|
-
conversationId,
|
|
1655
|
-
throughMessageId,
|
|
1656
|
-
});
|
|
1657
|
-
const detail = this.buildConversationDetailResponse(
|
|
1658
|
-
forkedConversation.id,
|
|
1659
|
-
);
|
|
1660
|
-
if (!detail) {
|
|
1661
|
-
throw new Error(
|
|
1662
|
-
`Forked conversation ${forkedConversation.id} could not be loaded`,
|
|
1663
|
-
);
|
|
1664
|
-
}
|
|
1665
|
-
return detail.conversation;
|
|
1666
|
-
}),
|
|
1667
|
-
};
|
|
1668
|
-
}
|
|
1669
|
-
|
|
1670
1450
|
// ---------------------------------------------------------------------------
|
|
1671
1451
|
// Declarative route table
|
|
1672
1452
|
// ---------------------------------------------------------------------------
|
|
@@ -1680,552 +1460,7 @@ export class RuntimeHttpServer {
|
|
|
1680
1460
|
* `./routes/` and composed here via spread. The composition order
|
|
1681
1461
|
* preserves the original top-to-bottom matching semantics.
|
|
1682
1462
|
*/
|
|
1683
|
-
private buildRouteTable():
|
|
1684
|
-
|
|
1685
|
-
const conversationManagementDeps =
|
|
1686
|
-
this.getConversationManagementRouteDeps();
|
|
1687
|
-
|
|
1688
|
-
return [
|
|
1689
|
-
...pairingRouteDefinitions({
|
|
1690
|
-
getPairingContext: () => this.pairingContext,
|
|
1691
|
-
}),
|
|
1692
|
-
...appRouteDefinitions(),
|
|
1693
|
-
...appManagementRouteDefinitions(),
|
|
1694
|
-
...secretRouteDefinitions({
|
|
1695
|
-
getCesClient: this.getCesClient,
|
|
1696
|
-
onProviderCredentialsChanged: this.onProviderCredentialsChanged,
|
|
1697
|
-
}),
|
|
1698
|
-
...identityRouteDefinitions(),
|
|
1699
|
-
...upgradeBroadcastRouteDefinitions(),
|
|
1700
|
-
...workspaceCommitRouteDefinitions(),
|
|
1701
|
-
...migrationRollbackRouteDefinitions(),
|
|
1702
|
-
...debugRouteDefinitions(),
|
|
1703
|
-
...usageRouteDefinitions(),
|
|
1704
|
-
...telemetryRouteDefinitions(),
|
|
1705
|
-
...workspaceRouteDefinitions(),
|
|
1706
|
-
...memoryItemRouteDefinitions(),
|
|
1707
|
-
...conversationStarterRouteDefinitions(),
|
|
1708
|
-
...settingsRouteDefinitions(),
|
|
1709
|
-
...avatarRouteDefinitions(),
|
|
1710
|
-
...scheduleRouteDefinitions({
|
|
1711
|
-
sendMessageDeps: this.sendMessageDeps,
|
|
1712
|
-
}),
|
|
1713
|
-
...heartbeatRouteDefinitions({
|
|
1714
|
-
getHeartbeatService: this.getHeartbeatService,
|
|
1715
|
-
}),
|
|
1716
|
-
...filingRouteDefinitions({
|
|
1717
|
-
getFilingService: this.getFilingService,
|
|
1718
|
-
}),
|
|
1719
|
-
...homeStateRouteDefinitions(),
|
|
1720
|
-
...homeFeedRouteDefinitions(),
|
|
1721
|
-
...notificationRouteDefinitions(),
|
|
1722
|
-
...diagnosticsRouteDefinitions(),
|
|
1723
|
-
...logExportRouteDefinitions(),
|
|
1724
|
-
...profilerRouteDefinitions(),
|
|
1725
|
-
...documentRouteDefinitions(),
|
|
1726
|
-
...workItemRouteDefinitions(
|
|
1727
|
-
this.sendMessageDeps
|
|
1728
|
-
? {
|
|
1729
|
-
getOrCreateConversation: (conversationId) =>
|
|
1730
|
-
this.sendMessageDeps!.getOrCreateConversation(conversationId),
|
|
1731
|
-
findConversation: this.findConversation
|
|
1732
|
-
? (conversationId) => {
|
|
1733
|
-
const s = this.findConversation!(conversationId);
|
|
1734
|
-
if (!s || !("abort" in s)) return undefined;
|
|
1735
|
-
return s as import("../daemon/conversation.js").Conversation;
|
|
1736
|
-
}
|
|
1737
|
-
: undefined,
|
|
1738
|
-
}
|
|
1739
|
-
: undefined,
|
|
1740
|
-
),
|
|
1741
|
-
...acpRouteDefinitions(),
|
|
1742
|
-
...subagentRouteDefinitions(),
|
|
1743
|
-
...conversationQueryRouteDefinitions({
|
|
1744
|
-
getModelSetContext: this.getModelSetContext,
|
|
1745
|
-
findConversationForQueue: this.findConversation
|
|
1746
|
-
? (id) => {
|
|
1747
|
-
const s = this.findConversation!(id);
|
|
1748
|
-
if (!s?.removeQueuedMessage) return undefined;
|
|
1749
|
-
return { removeQueuedMessage: s.removeQueuedMessage.bind(s) };
|
|
1750
|
-
}
|
|
1751
|
-
: undefined,
|
|
1752
|
-
}),
|
|
1753
|
-
...ttsRouteDefinitions(),
|
|
1754
|
-
...sttRouteDefinitions(),
|
|
1755
|
-
|
|
1756
|
-
// Conversation list and seen signal — kept inline because they
|
|
1757
|
-
// depend on multiple cross-cutting stores that aren't grouped
|
|
1758
|
-
// into a single domain module.
|
|
1759
|
-
{
|
|
1760
|
-
endpoint: "conversations",
|
|
1761
|
-
method: "GET",
|
|
1762
|
-
handler: ({ url }) => {
|
|
1763
|
-
const limit = Number(url.searchParams.get("limit") ?? 50);
|
|
1764
|
-
const offset = Number(url.searchParams.get("offset") ?? 0);
|
|
1765
|
-
const backgroundOnly =
|
|
1766
|
-
url.searchParams.get("conversationType") === "background";
|
|
1767
|
-
let rows = listConversations(limit, backgroundOnly, offset);
|
|
1768
|
-
const totalCount = countConversations(backgroundOnly);
|
|
1769
|
-
// On the first page, ensure all pinned conversations are included
|
|
1770
|
-
// even if they fall outside the paginated window.
|
|
1771
|
-
if (offset === 0 && !backgroundOnly) {
|
|
1772
|
-
const pinned = listPinnedConversations();
|
|
1773
|
-
const seen = new Set(rows.map((c) => c.id));
|
|
1774
|
-
const missing = pinned.filter((c) => !seen.has(c.id));
|
|
1775
|
-
if (missing.length > 0) {
|
|
1776
|
-
rows = [...rows, ...missing];
|
|
1777
|
-
}
|
|
1778
|
-
}
|
|
1779
|
-
const conversationIds = rows.map((c) => c.id);
|
|
1780
|
-
const displayMeta = getDisplayMetaForConversations(conversationIds);
|
|
1781
|
-
const bindings =
|
|
1782
|
-
externalConversationStore.getBindingsForConversations(
|
|
1783
|
-
conversationIds,
|
|
1784
|
-
);
|
|
1785
|
-
const attentionStates =
|
|
1786
|
-
getAttentionStateByConversationIds(conversationIds);
|
|
1787
|
-
const parentCache = new Map<string, ConversationRow | null>();
|
|
1788
|
-
const nextOffset = offset + limit;
|
|
1789
|
-
const response: Record<string, unknown> = {
|
|
1790
|
-
conversations: rows.map((conversation) =>
|
|
1791
|
-
this.serializeConversationSummary({
|
|
1792
|
-
conversation,
|
|
1793
|
-
binding: bindings.get(conversation.id),
|
|
1794
|
-
attentionState: attentionStates.get(conversation.id),
|
|
1795
|
-
displayMeta: displayMeta.get(conversation.id),
|
|
1796
|
-
parentCache,
|
|
1797
|
-
}),
|
|
1798
|
-
),
|
|
1799
|
-
nextOffset,
|
|
1800
|
-
hasMore: nextOffset < totalCount,
|
|
1801
|
-
};
|
|
1802
|
-
// Include groups array on first page only
|
|
1803
|
-
if (offset === 0) {
|
|
1804
|
-
const groups = listGroups();
|
|
1805
|
-
response.groups = groups.map((g) => ({
|
|
1806
|
-
id: g.id,
|
|
1807
|
-
name: g.name,
|
|
1808
|
-
sortPosition: g.sortPosition,
|
|
1809
|
-
isSystemGroup: g.isSystemGroup,
|
|
1810
|
-
}));
|
|
1811
|
-
}
|
|
1812
|
-
return Response.json(response);
|
|
1813
|
-
},
|
|
1814
|
-
},
|
|
1815
|
-
...conversationAttentionRouteDefinitions(),
|
|
1816
|
-
|
|
1817
|
-
...(conversationManagementDeps
|
|
1818
|
-
? conversationManagementRouteDefinitions(conversationManagementDeps)
|
|
1819
|
-
: []),
|
|
1820
|
-
|
|
1821
|
-
...((): RouteDefinition[] => {
|
|
1822
|
-
const sendMessageDeps = this.sendMessageDeps;
|
|
1823
|
-
if (!sendMessageDeps) return [];
|
|
1824
|
-
const analysisDeps = {
|
|
1825
|
-
sendMessageDeps,
|
|
1826
|
-
buildConversationDetailResponse: (id: string) =>
|
|
1827
|
-
this.buildConversationDetailResponse(id),
|
|
1828
|
-
};
|
|
1829
|
-
// Also expose via the module singleton so background callers
|
|
1830
|
-
// (e.g. job handlers) can invoke analyzeConversation() without
|
|
1831
|
-
// HTTP-layer wiring. Daemon startup must never block, so failures
|
|
1832
|
-
// to register the singleton are logged and swallowed.
|
|
1833
|
-
try {
|
|
1834
|
-
setAnalysisDeps(analysisDeps);
|
|
1835
|
-
} catch (err) {
|
|
1836
|
-
log.warn(
|
|
1837
|
-
{ err },
|
|
1838
|
-
"Failed to register analysis deps singleton; background analysis jobs will be skipped",
|
|
1839
|
-
);
|
|
1840
|
-
}
|
|
1841
|
-
return conversationAnalysisRouteDefinitions(analysisDeps);
|
|
1842
|
-
})(),
|
|
1843
|
-
|
|
1844
|
-
...groupRouteDefinitions(),
|
|
1845
|
-
|
|
1846
|
-
{
|
|
1847
|
-
endpoint: "conversations/seen",
|
|
1848
|
-
method: "POST",
|
|
1849
|
-
handler: async ({ req }) => {
|
|
1850
|
-
const body = (await req.json()) as Record<string, unknown>;
|
|
1851
|
-
const rawConversationId = body.conversationId as string | undefined;
|
|
1852
|
-
if (!rawConversationId)
|
|
1853
|
-
return httpError("BAD_REQUEST", "Missing conversationId", 400);
|
|
1854
|
-
// The client may send a conversation key rather than the internal
|
|
1855
|
-
// conversation ID. Resolve to the internal ID to satisfy FK constraints.
|
|
1856
|
-
const conversationId = resolveConversationId(rawConversationId);
|
|
1857
|
-
if (!conversationId)
|
|
1858
|
-
return httpError(
|
|
1859
|
-
"NOT_FOUND",
|
|
1860
|
-
`Unknown conversation: ${rawConversationId}`,
|
|
1861
|
-
404,
|
|
1862
|
-
);
|
|
1863
|
-
try {
|
|
1864
|
-
// Snapshot current state to detect whether the seen cursor
|
|
1865
|
-
// actually advances (avoids emitting on no-op signals).
|
|
1866
|
-
// Only consider a conversation "unseen" when a latest assistant
|
|
1867
|
-
// message exists and the seen cursor is behind it — matching
|
|
1868
|
-
// the hasUnseenLatestAssistantMessage logic in buildAssistantAttention.
|
|
1869
|
-
const priorState = getAttentionStateByConversationIds([
|
|
1870
|
-
conversationId,
|
|
1871
|
-
]).get(conversationId);
|
|
1872
|
-
const wasUnseen =
|
|
1873
|
-
priorState != null &&
|
|
1874
|
-
priorState.latestAssistantMessageAt != null &&
|
|
1875
|
-
(priorState.lastSeenAssistantMessageAt == null ||
|
|
1876
|
-
priorState.lastSeenAssistantMessageAt <
|
|
1877
|
-
priorState.latestAssistantMessageAt);
|
|
1878
|
-
|
|
1879
|
-
recordConversationSeenSignal({
|
|
1880
|
-
conversationId,
|
|
1881
|
-
sourceChannel: (body.sourceChannel as string) ?? "vellum",
|
|
1882
|
-
signalType: ((body.signalType as string) ??
|
|
1883
|
-
"macos_conversation_opened") as SignalType,
|
|
1884
|
-
confidence: ((body.confidence as string) ??
|
|
1885
|
-
"explicit") as Confidence,
|
|
1886
|
-
source: (body.source as string) ?? "http-api",
|
|
1887
|
-
evidenceText: body.evidenceText as string | undefined,
|
|
1888
|
-
metadata: body.metadata as Record<string, unknown> | undefined,
|
|
1889
|
-
observedAt: body.observedAt as number | undefined,
|
|
1890
|
-
});
|
|
1891
|
-
if (wasUnseen) {
|
|
1892
|
-
assistantEventHub
|
|
1893
|
-
.publish(
|
|
1894
|
-
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
1895
|
-
type: "conversation_list_invalidated",
|
|
1896
|
-
reason: "seen_changed",
|
|
1897
|
-
}),
|
|
1898
|
-
)
|
|
1899
|
-
.catch((err) => {
|
|
1900
|
-
log.warn(
|
|
1901
|
-
{ err },
|
|
1902
|
-
"Failed to publish conversation_list_invalidated (seen_changed)",
|
|
1903
|
-
);
|
|
1904
|
-
});
|
|
1905
|
-
}
|
|
1906
|
-
return Response.json({ ok: true });
|
|
1907
|
-
} catch (err) {
|
|
1908
|
-
log.error(
|
|
1909
|
-
{ err, conversationId },
|
|
1910
|
-
"POST /v1/conversations/seen: failed",
|
|
1911
|
-
);
|
|
1912
|
-
return httpError(
|
|
1913
|
-
"INTERNAL_ERROR",
|
|
1914
|
-
"Failed to record seen signal",
|
|
1915
|
-
500,
|
|
1916
|
-
);
|
|
1917
|
-
}
|
|
1918
|
-
},
|
|
1919
|
-
},
|
|
1920
|
-
|
|
1921
|
-
{
|
|
1922
|
-
endpoint: "conversations/unread",
|
|
1923
|
-
method: "POST",
|
|
1924
|
-
handler: async ({ req }) => {
|
|
1925
|
-
const body = (await req.json()) as Record<string, unknown>;
|
|
1926
|
-
const rawConversationId = body.conversationId as string | undefined;
|
|
1927
|
-
if (!rawConversationId)
|
|
1928
|
-
return httpError("BAD_REQUEST", "Missing conversationId", 400);
|
|
1929
|
-
const conversationId = resolveConversationId(rawConversationId);
|
|
1930
|
-
if (!conversationId)
|
|
1931
|
-
return httpError(
|
|
1932
|
-
"NOT_FOUND",
|
|
1933
|
-
`Unknown conversation: ${rawConversationId}`,
|
|
1934
|
-
404,
|
|
1935
|
-
);
|
|
1936
|
-
try {
|
|
1937
|
-
const changed = markConversationUnread(conversationId);
|
|
1938
|
-
if (changed) {
|
|
1939
|
-
assistantEventHub
|
|
1940
|
-
.publish(
|
|
1941
|
-
buildAssistantEvent(DAEMON_INTERNAL_ASSISTANT_ID, {
|
|
1942
|
-
type: "conversation_list_invalidated",
|
|
1943
|
-
reason: "seen_changed",
|
|
1944
|
-
}),
|
|
1945
|
-
)
|
|
1946
|
-
.catch((err) => {
|
|
1947
|
-
log.warn(
|
|
1948
|
-
{ err },
|
|
1949
|
-
"Failed to publish conversation_list_invalidated (seen_changed)",
|
|
1950
|
-
);
|
|
1951
|
-
});
|
|
1952
|
-
}
|
|
1953
|
-
return Response.json({ ok: true });
|
|
1954
|
-
} catch (err) {
|
|
1955
|
-
if (err instanceof UserError) {
|
|
1956
|
-
return httpError("UNPROCESSABLE_ENTITY", err.message, 422);
|
|
1957
|
-
}
|
|
1958
|
-
log.error(
|
|
1959
|
-
{ err, conversationId },
|
|
1960
|
-
"POST /v1/conversations/unread: failed",
|
|
1961
|
-
);
|
|
1962
|
-
return httpError(
|
|
1963
|
-
"INTERNAL_ERROR",
|
|
1964
|
-
"Failed to mark conversation unread",
|
|
1965
|
-
500,
|
|
1966
|
-
);
|
|
1967
|
-
}
|
|
1968
|
-
},
|
|
1969
|
-
},
|
|
1970
|
-
|
|
1971
|
-
// conversations/:id must be registered AFTER all literal conversations/<word>
|
|
1972
|
-
// routes above (attention, seen, unread) so the parameterized :id does not
|
|
1973
|
-
// shadow them.
|
|
1974
|
-
{
|
|
1975
|
-
endpoint: "conversations/:id",
|
|
1976
|
-
method: "GET",
|
|
1977
|
-
handler: ({ params }) => {
|
|
1978
|
-
const detail = this.buildConversationDetailResponse(params.id);
|
|
1979
|
-
if (!detail) {
|
|
1980
|
-
return httpError(
|
|
1981
|
-
"NOT_FOUND",
|
|
1982
|
-
`Conversation ${params.id} not found`,
|
|
1983
|
-
404,
|
|
1984
|
-
);
|
|
1985
|
-
}
|
|
1986
|
-
return Response.json(detail);
|
|
1987
|
-
},
|
|
1988
|
-
},
|
|
1989
|
-
|
|
1990
|
-
...btwRouteDefinitions({
|
|
1991
|
-
sendMessageDeps: this.sendMessageDeps,
|
|
1992
|
-
}),
|
|
1993
|
-
|
|
1994
|
-
...conversationRouteDefinitions({
|
|
1995
|
-
interfacesDir: this.interfacesDir,
|
|
1996
|
-
sendMessageDeps: this.sendMessageDeps,
|
|
1997
|
-
approvalConversationGenerator: this.approvalConversationGenerator,
|
|
1998
|
-
suggestionCache: this.suggestionCache,
|
|
1999
|
-
suggestionInFlight: this.suggestionInFlight,
|
|
2000
|
-
getHeartbeatService: this.getHeartbeatService,
|
|
2001
|
-
}),
|
|
2002
|
-
...playgroundRouteDefinitions({
|
|
2003
|
-
getConversationById: async (id) => {
|
|
2004
|
-
// Gate on DB existence first so genuinely-missing IDs return
|
|
2005
|
-
// `undefined` (preserving the route handlers' 404 path) rather
|
|
2006
|
-
// than triggering `getOrCreateConversation`'s create branch and
|
|
2007
|
-
// masking the not-found case. For existing-but-not-loaded rows
|
|
2008
|
-
// (e.g. freshly seeded by `POST /playground/seed-conversation`),
|
|
2009
|
-
// hydrate the in-memory `Conversation` on demand so conv-scoped
|
|
2010
|
-
// playground routes work without first opening the conversation
|
|
2011
|
-
// in the main window.
|
|
2012
|
-
if (!getConversation(id)) return undefined;
|
|
2013
|
-
const sendDeps = this.sendMessageDeps;
|
|
2014
|
-
if (!sendDeps) {
|
|
2015
|
-
// Fall back to the in-memory active map when the daemon hasn't
|
|
2016
|
-
// wired the hydration-capable accessor (e.g. unit tests).
|
|
2017
|
-
const s = this.findConversation?.(id);
|
|
2018
|
-
if (!s || !("abort" in s)) return undefined;
|
|
2019
|
-
return s as import("../daemon/conversation.js").Conversation;
|
|
2020
|
-
}
|
|
2021
|
-
return sendDeps.getOrCreateConversation(id);
|
|
2022
|
-
},
|
|
2023
|
-
isPlaygroundEnabled: () =>
|
|
2024
|
-
isAssistantFeatureFlagEnabled("compaction-playground", getConfig()),
|
|
2025
|
-
listConversationsByTitlePrefix: (prefix) =>
|
|
2026
|
-
listConversationsByTitlePrefix(prefix),
|
|
2027
|
-
deleteConversationById: (id) => {
|
|
2028
|
-
// Existence check first so we can report `false` for missing rows
|
|
2029
|
-
// — `deleteConversation` always returns a result object even when
|
|
2030
|
-
// no row matched.
|
|
2031
|
-
if (!getConversation(id)) return false;
|
|
2032
|
-
// Mirror the canonical DELETE /v1/conversations/:id handler in
|
|
2033
|
-
// conversation-management-routes.ts: tear down the in-memory
|
|
2034
|
-
// Conversation first (so a running agent loop can't write to a
|
|
2035
|
-
// deleted row and trip FK constraints), then drop the DB row,
|
|
2036
|
-
// then enqueue Qdrant vector cleanup for the returned segment
|
|
2037
|
-
// and summary IDs. Without this, seeded-then-deleted playground
|
|
2038
|
-
// conversations leak vectors and zombie Conversation objects.
|
|
2039
|
-
if (this.findConversation?.(id)) {
|
|
2040
|
-
this.conversationManagementDeps?.destroyConversation(id);
|
|
2041
|
-
}
|
|
2042
|
-
const deleted = deleteConversation(id);
|
|
2043
|
-
for (const segId of deleted.segmentIds) {
|
|
2044
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
2045
|
-
targetType: "segment",
|
|
2046
|
-
targetId: segId,
|
|
2047
|
-
});
|
|
2048
|
-
}
|
|
2049
|
-
for (const summaryId of deleted.deletedSummaryIds) {
|
|
2050
|
-
enqueueMemoryJob("delete_qdrant_vectors", {
|
|
2051
|
-
targetType: "summary",
|
|
2052
|
-
targetId: summaryId,
|
|
2053
|
-
});
|
|
2054
|
-
}
|
|
2055
|
-
return true;
|
|
2056
|
-
},
|
|
2057
|
-
createConversation: async (title) => {
|
|
2058
|
-
const row = createConversation({ title });
|
|
2059
|
-
return { id: row.id };
|
|
2060
|
-
},
|
|
2061
|
-
addMessage: async (conversationId, role, contentJson, options) => {
|
|
2062
|
-
const persisted = await addMessage(
|
|
2063
|
-
conversationId,
|
|
2064
|
-
role,
|
|
2065
|
-
contentJson,
|
|
2066
|
-
undefined,
|
|
2067
|
-
options,
|
|
2068
|
-
);
|
|
2069
|
-
return { id: persisted.id };
|
|
2070
|
-
},
|
|
2071
|
-
}),
|
|
2072
|
-
...globalSearchRouteDefinitions(),
|
|
2073
|
-
...approvalRouteDefinitions(),
|
|
2074
|
-
...hostBashRouteDefinitions(),
|
|
2075
|
-
...hostBrowserRouteDefinitions(),
|
|
2076
|
-
...hostCuRouteDefinitions(),
|
|
2077
|
-
...hostFileRouteDefinitions(),
|
|
2078
|
-
...(this.getSkillContext
|
|
2079
|
-
? skillRouteDefinitions({
|
|
2080
|
-
getSkillContext: this.getSkillContext,
|
|
2081
|
-
})
|
|
2082
|
-
: []),
|
|
2083
|
-
...trustRulesRouteDefinitions(),
|
|
2084
|
-
...surfaceActionRouteDefinitions({
|
|
2085
|
-
findConversation: this.findConversation,
|
|
2086
|
-
findConversationBySurfaceId: this.findConversationBySurfaceId,
|
|
2087
|
-
}),
|
|
2088
|
-
...surfaceContentRouteDefinitions({
|
|
2089
|
-
findConversation: this.findConversation,
|
|
2090
|
-
}),
|
|
2091
|
-
...guardianActionRouteDefinitions(),
|
|
2092
|
-
|
|
2093
|
-
...contactRouteDefinitions(),
|
|
2094
|
-
...inviteRouteDefinitions(),
|
|
2095
|
-
// contacts/:id catch-all must follow invite routes to avoid shadowing
|
|
2096
|
-
...contactCatchAllRouteDefinitions(),
|
|
2097
|
-
|
|
2098
|
-
...telegramRouteDefinitions(),
|
|
2099
|
-
...channelVerificationRouteDefinitions(),
|
|
2100
|
-
...slackChannelRouteDefinitions(),
|
|
2101
|
-
...slackShareRouteDefinitions(),
|
|
2102
|
-
...twilioRouteDefinitions(),
|
|
2103
|
-
...vercelRouteDefinitions(),
|
|
2104
|
-
...channelReadinessRouteDefinitions(),
|
|
2105
|
-
...oauthProvidersRouteDefinitions(),
|
|
2106
|
-
...oauthAppsRouteDefinitions(),
|
|
2107
|
-
...attachmentRouteDefinitions(),
|
|
2108
|
-
|
|
2109
|
-
...(this.getRecordingDeps
|
|
2110
|
-
? recordingRouteDefinitions({
|
|
2111
|
-
getRecordingDeps: this.getRecordingDeps,
|
|
2112
|
-
})
|
|
2113
|
-
: []),
|
|
2114
|
-
|
|
2115
|
-
{
|
|
2116
|
-
endpoint: "interfaces/:path*",
|
|
2117
|
-
method: "GET",
|
|
2118
|
-
policyKey: "interfaces",
|
|
2119
|
-
handler: ({ params }) => this.handleGetInterface(params.path),
|
|
2120
|
-
},
|
|
2121
|
-
|
|
2122
|
-
...channelRouteDefinitions({
|
|
2123
|
-
assistantId,
|
|
2124
|
-
processMessage: this.processMessage,
|
|
2125
|
-
approvalCopyGenerator: this.approvalCopyGenerator,
|
|
2126
|
-
approvalConversationGenerator: this.approvalConversationGenerator,
|
|
2127
|
-
guardianActionCopyGenerator: this.guardianActionCopyGenerator,
|
|
2128
|
-
guardianFollowUpConversationGenerator:
|
|
2129
|
-
this.guardianFollowUpConversationGenerator,
|
|
2130
|
-
getHeartbeatService: this.getHeartbeatService,
|
|
2131
|
-
}),
|
|
2132
|
-
...callRouteDefinitions({ assistantId }),
|
|
2133
|
-
|
|
2134
|
-
// Internal Twilio forwarding (gateway -> runtime) — kept inline
|
|
2135
|
-
// because these reconstruct fake form-encoded requests from JSON,
|
|
2136
|
-
// a pattern specific to the gateway-to-daemon bridge.
|
|
2137
|
-
{
|
|
2138
|
-
endpoint: "internal/twilio/voice-webhook",
|
|
2139
|
-
method: "POST",
|
|
2140
|
-
handler: async ({ req }) => {
|
|
2141
|
-
const json = (await req.json()) as {
|
|
2142
|
-
params: Record<string, string>;
|
|
2143
|
-
originalUrl?: string;
|
|
2144
|
-
};
|
|
2145
|
-
const formBody = new URLSearchParams(json.params).toString();
|
|
2146
|
-
const reconstructedUrl = json.originalUrl ?? req.url;
|
|
2147
|
-
const fakeReq = new Request(reconstructedUrl, {
|
|
2148
|
-
method: "POST",
|
|
2149
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2150
|
-
body: formBody,
|
|
2151
|
-
});
|
|
2152
|
-
return handleVoiceWebhook(fakeReq);
|
|
2153
|
-
},
|
|
2154
|
-
},
|
|
2155
|
-
{
|
|
2156
|
-
endpoint: "internal/twilio/status",
|
|
2157
|
-
method: "POST",
|
|
2158
|
-
handler: async ({ req }) => {
|
|
2159
|
-
const json = (await req.json()) as {
|
|
2160
|
-
params: Record<string, string>;
|
|
2161
|
-
};
|
|
2162
|
-
const formBody = new URLSearchParams(json.params).toString();
|
|
2163
|
-
const fakeReq = new Request(req.url, {
|
|
2164
|
-
method: "POST",
|
|
2165
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2166
|
-
body: formBody,
|
|
2167
|
-
});
|
|
2168
|
-
return handleStatusCallback(fakeReq);
|
|
2169
|
-
},
|
|
2170
|
-
},
|
|
2171
|
-
{
|
|
2172
|
-
endpoint: "internal/twilio/connect-action",
|
|
2173
|
-
method: "POST",
|
|
2174
|
-
handler: async ({ req }) => {
|
|
2175
|
-
const json = (await req.json()) as {
|
|
2176
|
-
params: Record<string, string>;
|
|
2177
|
-
};
|
|
2178
|
-
const formBody = new URLSearchParams(json.params).toString();
|
|
2179
|
-
const fakeReq = new Request(req.url, {
|
|
2180
|
-
method: "POST",
|
|
2181
|
-
headers: { "Content-Type": "application/x-www-form-urlencoded" },
|
|
2182
|
-
body: formBody,
|
|
2183
|
-
});
|
|
2184
|
-
return handleConnectAction(fakeReq);
|
|
2185
|
-
},
|
|
2186
|
-
},
|
|
2187
|
-
|
|
2188
|
-
...brainGraphRouteDefinitions({ mintUiPageToken }),
|
|
2189
|
-
...eventsRouteDefinitions(),
|
|
2190
|
-
...traceEventRouteDefinitions(),
|
|
2191
|
-
...migrationRouteDefinitions(),
|
|
2192
|
-
...backupRouteDefinitions(),
|
|
2193
|
-
|
|
2194
|
-
// User-defined routes under /x/* — must be LAST so built-in routes
|
|
2195
|
-
// always take priority.
|
|
2196
|
-
...userRouteDefinitions(),
|
|
2197
|
-
|
|
2198
|
-
// Internal OAuth callback (gateway -> runtime)
|
|
2199
|
-
{
|
|
2200
|
-
endpoint: "internal/oauth/callback",
|
|
2201
|
-
method: "POST",
|
|
2202
|
-
handler: async ({ req }) => {
|
|
2203
|
-
const json = (await req.json()) as {
|
|
2204
|
-
state: string;
|
|
2205
|
-
code?: string;
|
|
2206
|
-
error?: string;
|
|
2207
|
-
};
|
|
2208
|
-
if (!json.state)
|
|
2209
|
-
return httpError("BAD_REQUEST", "Missing state parameter", 400);
|
|
2210
|
-
if (json.error) {
|
|
2211
|
-
const consumed = consumeCallbackError(json.state, json.error);
|
|
2212
|
-
return consumed
|
|
2213
|
-
? Response.json({ ok: true })
|
|
2214
|
-
: httpError("NOT_FOUND", "Unknown state", 404);
|
|
2215
|
-
}
|
|
2216
|
-
if (json.code) {
|
|
2217
|
-
const consumed = consumeCallback(json.state, json.code);
|
|
2218
|
-
return consumed
|
|
2219
|
-
? Response.json({ ok: true })
|
|
2220
|
-
: httpError("NOT_FOUND", "Unknown state", 404);
|
|
2221
|
-
}
|
|
2222
|
-
return httpError(
|
|
2223
|
-
"BAD_REQUEST",
|
|
2224
|
-
"Missing code or error parameter",
|
|
2225
|
-
400,
|
|
2226
|
-
);
|
|
2227
|
-
},
|
|
2228
|
-
},
|
|
2229
|
-
];
|
|
1463
|
+
private buildRouteTable(): HTTPRouteDefinition[] {
|
|
1464
|
+
return [...routeDefinitionsToHTTPRoutes(ROUTES)];
|
|
2230
1465
|
}
|
|
2231
1466
|
}
|