@vellumai/assistant 0.4.26 → 0.4.30
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/.env.example +2 -2
- package/AGENTS.md +5 -0
- package/ARCHITECTURE.md +207 -105
- package/Dockerfile +1 -1
- package/README.md +111 -113
- package/bun.lock +0 -3
- package/docs/architecture/integrations.md +0 -1
- package/docs/architecture/memory.md +100 -63
- package/docs/error-handling.md +71 -0
- package/docs/runbook-trusted-contacts.md +89 -52
- package/docs/trusted-contact-access.md +48 -46
- package/package.json +3 -3
- package/scripts/compare-benchmarks.sh +12 -5
- package/scripts/ipc/check-swift-decoder-drift.ts +5 -3
- package/scripts/test.sh +89 -5
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +50 -37
- package/src/__tests__/access-request-decision.test.ts +0 -1
- package/src/__tests__/account-registry.test.ts +1 -1
- package/src/__tests__/actor-token-service.test.ts +40 -26
- package/src/__tests__/agent-loop-thinking.test.ts +29 -13
- package/src/__tests__/agent-loop.test.ts +2 -1
- package/src/__tests__/app-builder-tool-scripts.test.ts +1 -1
- package/src/__tests__/app-executors.test.ts +7 -17
- package/src/__tests__/approval-routes-http.test.ts +2 -2
- package/src/__tests__/asset-materialize-tool.test.ts +7 -7
- package/src/__tests__/asset-search-tool.test.ts +7 -7
- package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -10
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/browser-skill-endstate.test.ts +10 -1
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +218 -0
- package/src/__tests__/call-controller.test.ts +99 -69
- package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
- package/src/__tests__/channel-approval-routes.test.ts +157 -114
- package/src/__tests__/channel-approval.test.ts +8 -0
- package/src/__tests__/channel-approvals.test.ts +39 -1
- package/src/__tests__/channel-guardian.test.ts +176 -275
- package/src/__tests__/channel-readiness-service.test.ts +6 -2
- package/src/__tests__/channel-reply-delivery.test.ts +33 -2
- package/src/__tests__/channel-retry-sweep.test.ts +14 -14
- package/src/__tests__/checker.test.ts +12 -31
- package/src/__tests__/claude-code-tool-profiles.test.ts +1 -1
- package/src/__tests__/commit-message-enrichment-service.test.ts +71 -59
- package/src/__tests__/compaction.benchmark.test.ts +6 -2
- package/src/__tests__/computer-use-tools.test.ts +1 -1
- package/src/__tests__/config-schema.test.ts +66 -7
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -29
- package/src/__tests__/contacts-tools.test.ts +63 -2
- package/src/__tests__/context-overflow-approval.test.ts +141 -0
- package/src/__tests__/context-overflow-policy.test.ts +171 -0
- package/src/__tests__/context-overflow-reducer.test.ts +533 -0
- package/src/__tests__/context-window-manager.test.ts +97 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +38 -46
- package/src/__tests__/conversation-pairing.test.ts +2 -2
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +214 -10
- package/src/__tests__/conversation-routes.test.ts +4 -7
- package/src/__tests__/credential-broker-browser-fill.test.ts +13 -2
- package/src/__tests__/credential-security-e2e.test.ts +1 -1
- package/src/__tests__/credential-security-invariants.test.ts +1 -1
- package/src/__tests__/credential-vault-unit.test.ts +1 -1
- package/src/__tests__/credential-vault.test.ts +11 -8
- package/src/__tests__/daemon-lifecycle.test.ts +2 -2
- package/src/__tests__/daemon-server-session-init.test.ts +6 -6
- package/src/__tests__/delete-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +9 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +4 -0
- package/src/__tests__/encrypted-store.test.ts +10 -7
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/file-edit-tool.test.ts +1 -1
- package/src/__tests__/file-read-tool.test.ts +1 -1
- package/src/__tests__/file-write-tool.test.ts +1 -1
- package/src/__tests__/fixtures/credential-security-fixtures.ts +87 -64
- package/src/__tests__/fixtures/media-reuse-fixtures.ts +37 -31
- package/src/__tests__/fixtures/mock-signup-server.ts +171 -115
- package/src/__tests__/fixtures/proxy-fixtures.ts +39 -39
- package/src/__tests__/followup-tools.test.ts +1 -1
- package/src/__tests__/gateway-only-guard.test.ts +4 -0
- package/src/__tests__/gemini-image-service.test.ts +2 -2
- package/src/__tests__/guardian-actions-endpoint.test.ts +543 -1
- package/src/__tests__/guardian-control-plane-policy.test.ts +15 -15
- package/src/__tests__/guardian-dispatch.test.ts +79 -1
- package/src/__tests__/guardian-grant-minting.test.ts +20 -20
- package/src/__tests__/guardian-outbound-http.test.ts +1 -2
- package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -41
- package/src/__tests__/guardian-routing-invariants.test.ts +36 -16
- package/src/__tests__/guardian-routing-state.test.ts +36 -52
- package/src/__tests__/guardian-verification-intent-routing.test.ts +4 -6
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +6 -8
- package/src/__tests__/handle-user-message-secret-resume.test.ts +39 -1
- package/src/__tests__/handlers-cu-observation-blob.test.ts +21 -10
- package/src/__tests__/handlers-telegram-config.test.ts +14 -14
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +23 -2
- package/src/__tests__/headless-browser-interactions.test.ts +1 -1
- package/src/__tests__/headless-browser-navigate.test.ts +1 -1
- package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
- package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
- package/src/__tests__/heartbeat-service.test.ts +45 -2
- package/src/__tests__/host-file-edit-tool.test.ts +1 -1
- package/src/__tests__/host-file-read-tool.test.ts +1 -1
- package/src/__tests__/host-file-write-tool.test.ts +1 -1
- package/src/__tests__/host-shell-tool.test.ts +1 -1
- package/src/__tests__/inbound-invite-redemption.test.ts +17 -19
- package/src/__tests__/ingress-reconcile.test.ts +2 -2
- package/src/__tests__/integrations-cli.test.ts +232 -0
- package/src/__tests__/intent-routing.test.ts +7 -5
- package/src/__tests__/invite-redemption-service.test.ts +5 -4
- package/src/__tests__/{ingress-routes-http.test.ts → invite-routes-http.test.ts} +42 -321
- package/src/__tests__/ipc-snapshot.test.ts +32 -31
- package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
- package/src/__tests__/mcp-cli.test.ts +136 -57
- package/src/__tests__/mcp-client-auth.test.ts +95 -0
- package/src/__tests__/media-generate-image.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +8 -8
- package/src/__tests__/memory-regressions.test.ts +6 -6
- package/src/__tests__/messaging-send-tool.test.ts +1 -1
- package/src/__tests__/migration-cross-version-compatibility.test.ts +1855 -0
- package/src/__tests__/migration-export-http.test.ts +540 -0
- package/src/__tests__/migration-import-commit-http.test.ts +823 -0
- package/src/__tests__/migration-import-preflight-http.test.ts +755 -0
- package/src/__tests__/migration-parity-persistence.test.ts +1854 -0
- package/src/__tests__/migration-transport.test.ts +904 -0
- package/src/__tests__/migration-validate-http.test.ts +698 -0
- package/src/__tests__/migration-wizard.test.ts +1289 -0
- package/src/__tests__/nl-approval-parser.test.ts +305 -0
- package/src/__tests__/non-member-access-request.test.ts +17 -17
- package/src/__tests__/notification-decision-strategy.test.ts +110 -2
- package/src/__tests__/notification-deep-link.test.ts +18 -0
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/oauth-provider-profiles.test.ts +34 -0
- package/src/__tests__/oauth2-gateway-transport.test.ts +1 -1
- package/src/__tests__/playbook-execution.test.ts +1 -1
- package/src/__tests__/playbook-tools.test.ts +1 -1
- package/src/__tests__/provider-error-scenarios.test.ts +68 -0
- package/src/__tests__/provider-streaming.benchmark.test.ts +3 -1
- package/src/__tests__/proxy-approval-callback.test.ts +1 -1
- package/src/__tests__/qdrant-manager.test.ts +40 -11
- package/src/__tests__/rebind-secrets-screen.test.ts +839 -0
- package/src/__tests__/recording-handler.test.ts +2 -2
- package/src/__tests__/recording-intent-handler.test.ts +3 -3
- package/src/__tests__/recording-state-machine.test.ts +2 -2
- package/src/__tests__/relay-server.test.ts +507 -228
- package/src/__tests__/reminder-store.test.ts +8 -0
- package/src/__tests__/reminder.test.ts +8 -0
- package/src/__tests__/{resolve-guardian-trust-class.test.ts → resolve-trust-class.test.ts} +11 -17
- package/src/__tests__/retry-after-extraction.test.ts +111 -0
- package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
- package/src/__tests__/schedule-tools.test.ts +1 -1
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/script-proxy-connect-tunnel.test.ts +2 -3
- package/src/__tests__/script-proxy-decision-trace.test.ts +2 -2
- package/src/__tests__/script-proxy-http-forwarder.test.ts +1 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +5 -5
- package/src/__tests__/script-proxy-mitm-handler.test.ts +4 -4
- package/src/__tests__/script-proxy-policy-runtime.test.ts +2 -2
- package/src/__tests__/script-proxy-policy.test.ts +2 -2
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +127 -0
- package/src/__tests__/script-proxy-session-manager.test.ts +4 -7
- package/src/__tests__/script-proxy-session-runtime.test.ts +1 -6
- package/src/__tests__/secret-onetime-send.test.ts +4 -4
- package/src/__tests__/secret-scanner-executor.test.ts +2 -2
- package/src/__tests__/send-endpoint-busy.test.ts +11 -9
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +17 -2
- package/src/__tests__/session-agent-loop.test.ts +456 -35
- package/src/__tests__/session-confirmation-signals.test.ts +3 -2
- package/src/__tests__/session-conflict-gate.test.ts +20 -3
- package/src/__tests__/session-init.benchmark.test.ts +2 -2
- package/src/__tests__/session-load-history-repair.test.ts +7 -7
- package/src/__tests__/session-media-retry.test.ts +147 -0
- package/src/__tests__/session-pre-run-repair.test.ts +17 -2
- package/src/__tests__/session-profile-injection.test.ts +20 -3
- package/src/__tests__/session-provider-retry-repair.test.ts +86 -6
- package/src/__tests__/session-queue.test.ts +33 -18
- package/src/__tests__/session-runtime-assembly.test.ts +147 -1
- package/src/__tests__/session-runtime-workspace.test.ts +40 -0
- package/src/__tests__/session-slash-known.test.ts +21 -3
- package/src/__tests__/session-slash-queue.test.ts +17 -2
- package/src/__tests__/session-slash-unknown.test.ts +17 -2
- package/src/__tests__/session-surfaces-deselection.test.ts +208 -0
- package/src/__tests__/session-workspace-cache-state.test.ts +2 -2
- package/src/__tests__/session-workspace-injection.test.ts +17 -2
- package/src/__tests__/session-workspace-tool-tracking.test.ts +17 -2
- package/src/__tests__/shell-credential-ref.test.ts +1 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +9 -5
- package/src/__tests__/skill-feature-flags.test.ts +18 -12
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -4
- package/src/__tests__/skill-load-tool.test.ts +1 -1
- package/src/__tests__/skill-script-runner-host.test.ts +1 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -1
- package/src/__tests__/skill-script-runner.test.ts +1 -1
- package/src/__tests__/skill-tool-factory.test.ts +1 -1
- package/src/__tests__/slack-block-formatting.test.ts +100 -0
- package/src/__tests__/slack-inbound-verification.test.ts +346 -0
- package/src/__tests__/slack-reaction-approvals.test.ts +77 -0
- package/src/__tests__/slack-skill.test.ts +4 -2
- package/src/__tests__/starter-task-flow.test.ts +0 -1
- package/src/__tests__/subagent-tools.test.ts +3 -3
- package/src/__tests__/swarm-recursion.test.ts +1 -1
- package/src/__tests__/swarm-session-integration.test.ts +1 -1
- package/src/__tests__/swarm-tool.test.ts +1 -1
- package/src/__tests__/task-management-tools.test.ts +1 -1
- package/src/__tests__/task-tools.test.ts +1 -1
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/test-support/browser-skill-harness.ts +39 -27
- package/src/__tests__/test-support/computer-use-skill-harness.ts +14 -14
- package/src/__tests__/tool-approval-handler.test.ts +15 -15
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +23 -182
- package/src/__tests__/tool-grant-request-escalation.test.ts +11 -11
- package/src/__tests__/tool-permission-simulate-handler.test.ts +4 -4
- package/src/__tests__/transfer-progress-screen.test.ts +1180 -0
- package/src/__tests__/trust-context-guards.test.ts +25 -29
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +23 -21
- package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +37 -40
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +29 -25
- package/src/__tests__/trusted-contact-multichannel.test.ts +25 -24
- package/src/__tests__/trusted-contact-verification.test.ts +64 -76
- package/src/__tests__/turn-commit.test.ts +18 -18
- package/src/__tests__/twilio-provider.test.ts +7 -7
- package/src/__tests__/validation-results-screen.test.ts +1107 -0
- package/src/__tests__/view-image-tool.test.ts +1 -1
- package/src/__tests__/voice-invite-redemption.test.ts +4 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +12 -12
- package/src/__tests__/voice-session-bridge.test.ts +24 -24
- package/src/agent/attachments.ts +3 -1
- package/src/agent/loop.ts +13 -13
- package/src/agent/message-types.ts +13 -7
- package/src/amazon/cart.ts +59 -32
- package/src/amazon/checkout.ts +25 -14
- package/src/amazon/client.ts +61 -58
- package/src/amazon/product-details.ts +3 -3
- package/src/amazon/request-extractor.ts +46 -31
- package/src/amazon/search.ts +6 -4
- package/src/amazon/session.ts +33 -24
- package/src/approvals/AGENTS.md +26 -0
- package/src/approvals/approval-primitive.ts +87 -64
- package/src/approvals/guardian-decision-primitive.ts +172 -81
- package/src/approvals/guardian-request-resolvers.ts +262 -155
- package/src/autonomy/autonomy-resolver.ts +7 -5
- package/src/autonomy/autonomy-store.ts +34 -19
- package/src/autonomy/disposition-mapper.ts +5 -5
- package/src/autonomy/index.ts +6 -6
- package/src/autonomy/types.ts +7 -3
- package/src/browser-extension-relay/client.ts +50 -19
- package/src/browser-extension-relay/protocol.ts +11 -11
- package/src/browser-extension-relay/server.ts +45 -20
- package/src/bundler/app-bundler.ts +75 -50
- package/src/bundler/bundle-scanner.ts +145 -41
- package/src/bundler/bundle-signer.ts +16 -14
- package/src/bundler/signature-verifier.ts +36 -33
- package/src/calls/call-constants.ts +10 -3
- package/src/calls/call-controller.ts +473 -214
- package/src/calls/call-conversation-messages.ts +25 -15
- package/src/calls/call-domain.ts +401 -148
- package/src/calls/call-pointer-message-composer.ts +26 -21
- package/src/calls/call-pointer-messages.ts +52 -28
- package/src/calls/call-recovery.ts +53 -37
- package/src/calls/call-state-machine.ts +37 -7
- package/src/calls/call-state.ts +35 -13
- package/src/calls/call-store.ts +165 -77
- package/src/calls/elevenlabs-client.ts +39 -20
- package/src/calls/guardian-action-sweep.ts +42 -24
- package/src/calls/guardian-dispatch.ts +79 -56
- package/src/calls/guardian-question-copy.ts +28 -23
- package/src/calls/relay-server.ts +1149 -532
- package/src/calls/speaker-identification.ts +21 -15
- package/src/calls/twilio-config.ts +34 -17
- package/src/calls/twilio-provider.ts +108 -55
- package/src/calls/twilio-rest.ts +212 -100
- package/src/calls/twilio-routes.ts +165 -92
- package/src/calls/types.ts +55 -7
- package/src/calls/voice-quality.ts +6 -4
- package/src/calls/voice-session-bridge.ts +181 -133
- package/src/channels/config.ts +18 -14
- package/src/channels/types.ts +38 -10
- package/src/cli/amazon.ts +333 -227
- package/src/cli/config-commands.ts +236 -146
- package/src/cli/core-commands.ts +403 -329
- package/src/cli/email-guardrails.ts +38 -19
- package/src/cli/email.ts +207 -153
- package/src/cli/influencer.ts +58 -56
- package/src/cli/integrations.ts +306 -0
- package/src/cli/ipc-client.ts +24 -19
- package/src/cli/map.ts +176 -129
- package/src/cli/mcp.ts +260 -152
- package/src/cli/sequence.ts +165 -107
- package/src/cli/twitter.ts +302 -218
- package/src/cli.ts +418 -279
- package/src/commands/cc-command-registry.ts +52 -27
- package/src/config/agent-schema.ts +217 -134
- package/src/config/assistant-feature-flags.ts +23 -18
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +19 -0
- package/src/config/bundled-skills/app-builder/SKILL.md +193 -1500
- package/src/config/bundled-skills/app-builder/TOOLS.json +70 -18
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-delete.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-edit.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-file-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-read.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-file-write.ts +7 -4
- package/src/config/bundled-skills/app-builder/tools/app-list.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-query.ts +6 -3
- package/src/config/bundled-skills/app-builder/tools/app-update.ts +6 -3
- package/src/config/bundled-skills/browser/TOOLS.json +59 -2
- package/src/config/bundled-skills/browser/tools/browser-click.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-close.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-extract.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-hover.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-navigate.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-press-key.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-scroll.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-select-option.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-type.ts +5 -2
- package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +13 -6
- package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +5 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +4 -0
- package/src/config/bundled-skills/claude-code/TOOLS.json +4 -0
- package/src/config/bundled-skills/claude-code/tools/claude-code.ts +5 -2
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +50 -2
- package/src/config/bundled-skills/computer-use/tools/computer-use-click.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-done.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-double-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-drag.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-key.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-open-app.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-request-control.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-respond.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-right-click.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-run-applescript.ts +10 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-scroll.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-type-text.ts +6 -3
- package/src/config/bundled-skills/computer-use/tools/computer-use-wait.ts +6 -3
- package/src/config/bundled-skills/configure-settings/SKILL.md +28 -14
- package/src/config/bundled-skills/contacts/SKILL.md +453 -15
- package/src/config/bundled-skills/contacts/TOOLS.json +22 -2
- package/src/config/bundled-skills/contacts/tools/contact-merge.ts +79 -20
- package/src/config/bundled-skills/contacts/tools/contact-search.ts +55 -18
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +64 -19
- package/src/config/bundled-skills/document/TOOLS.json +8 -0
- package/src/config/bundled-skills/document/tools/document-create.ts +5 -2
- package/src/config/bundled-skills/document/tools/document-update.ts +5 -2
- package/src/config/bundled-skills/doordash/doordash-cli.ts +17 -7
- package/src/config/bundled-skills/email-setup/SKILL.md +12 -9
- package/src/config/bundled-skills/followups/TOOLS.json +12 -0
- package/src/config/bundled-skills/followups/tools/followup-create.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-list.ts +5 -2
- package/src/config/bundled-skills/followups/tools/followup-resolve.ts +5 -2
- package/src/config/bundled-skills/google-calendar/TOOLS.json +124 -26
- package/src/config/bundled-skills/google-calendar/calendar-client.ts +44 -32
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +11 -5
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +13 -7
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +28 -12
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +6 -4
- package/src/config/bundled-skills/google-calendar/types.ts +3 -3
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +88 -33
- package/src/config/bundled-skills/image-studio/TOOLS.json +12 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +48 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +13 -3
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +60 -35
- package/src/config/bundled-skills/mcp-setup/SKILL.md +75 -0
- package/src/config/bundled-skills/media-processing/SKILL.md +55 -15
- package/src/config/bundled-skills/media-processing/TOOLS.json +48 -2
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +12 -10
- package/src/config/bundled-skills/media-processing/__tests__/cost-tracker.test.ts +34 -19
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +82 -66
- package/src/config/bundled-skills/media-processing/services/audio-transcribe.ts +148 -0
- package/src/config/bundled-skills/media-processing/services/concurrency-pool.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/cost-tracker.ts +8 -3
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +117 -53
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +273 -0
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +185 -97
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +32 -27
- package/src/config/bundled-skills/media-processing/services/reduce.ts +101 -24
- package/src/config/bundled-skills/media-processing/tools/analyze-keyframes.ts +121 -55
- package/src/config/bundled-skills/media-processing/tools/extract-keyframes.ts +58 -24
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +198 -92
- package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +98 -70
- package/src/config/bundled-skills/media-processing/tools/media-diagnostics.ts +59 -19
- package/src/config/bundled-skills/media-processing/tools/media-status.ts +26 -10
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +29 -14
- package/src/config/bundled-skills/messaging/SKILL.md +7 -5
- package/src/config/bundled-skills/messaging/TOOLS.json +232 -186
- package/src/config/bundled-skills/messaging/tools/gmail-archive-by-query.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/gmail-archive.ts +16 -10
- package/src/config/bundled-skills/messaging/tools/gmail-batch-label.ts +18 -9
- package/src/config/bundled-skills/messaging/tools/gmail-download-attachment.ts +23 -16
- package/src/config/bundled-skills/messaging/tools/gmail-draft.ts +28 -12
- package/src/config/bundled-skills/messaging/tools/gmail-filters.ts +41 -21
- package/src/config/bundled-skills/messaging/tools/gmail-follow-up.ts +44 -23
- package/src/config/bundled-skills/messaging/tools/gmail-forward.ts +73 -33
- package/src/config/bundled-skills/messaging/tools/gmail-label.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-list-attachments.ts +22 -14
- package/src/config/bundled-skills/messaging/tools/gmail-outreach-scan.ts +99 -50
- package/src/config/bundled-skills/messaging/tools/gmail-send-draft.ts +14 -8
- package/src/config/bundled-skills/messaging/tools/gmail-send-with-attachments.ts +63 -44
- package/src/config/bundled-skills/messaging/tools/gmail-sender-digest.ts +90 -46
- package/src/config/bundled-skills/messaging/tools/gmail-summarize-thread.ts +43 -22
- package/src/config/bundled-skills/messaging/tools/gmail-trash.ts +15 -9
- package/src/config/bundled-skills/messaging/tools/gmail-triage.ts +51 -22
- package/src/config/bundled-skills/messaging/tools/gmail-unsubscribe.ts +62 -26
- package/src/config/bundled-skills/messaging/tools/gmail-vacation.ts +34 -19
- package/src/config/bundled-skills/messaging/tools/google-contacts.ts +32 -16
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-activity.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +91 -47
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +21 -9
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +9 -3
- package/src/config/bundled-skills/messaging/tools/messaging-draft.ts +30 -17
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +16 -5
- package/src/config/bundled-skills/messaging/tools/messaging-reply.ts +63 -36
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +10 -4
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +30 -12
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +48 -29
- package/src/config/bundled-skills/messaging/tools/scan-result-store.ts +20 -6
- package/src/config/bundled-skills/messaging/tools/send-notification.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/sequence-analytics.ts +59 -22
- package/src/config/bundled-skills/messaging/tools/sequence-cancel.ts +13 -7
- package/src/config/bundled-skills/messaging/tools/sequence-create.ts +27 -12
- package/src/config/bundled-skills/messaging/tools/sequence-delete.ts +14 -6
- package/src/config/bundled-skills/messaging/tools/sequence-enroll.ts +30 -11
- package/src/config/bundled-skills/messaging/tools/sequence-enrollment-list.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-get.ts +31 -13
- package/src/config/bundled-skills/messaging/tools/sequence-import.ts +38 -22
- package/src/config/bundled-skills/messaging/tools/sequence-list.ts +16 -7
- package/src/config/bundled-skills/messaging/tools/sequence-pause.ts +29 -10
- package/src/config/bundled-skills/messaging/tools/sequence-resume.ts +16 -8
- package/src/config/bundled-skills/messaging/tools/sequence-update.ts +35 -16
- package/src/config/bundled-skills/messaging/tools/shared.ts +26 -12
- package/src/config/bundled-skills/notifications/SKILL.md +3 -2
- package/src/config/bundled-skills/notifications/TOOLS.json +7 -13
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +69 -34
- package/src/config/bundled-skills/notifications/tools/shared.ts +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +46 -48
- package/src/config/bundled-skills/phone-calls/TOOLS.json +13 -1
- package/src/config/bundled-skills/phone-calls/tools/call-end.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-start.ts +1 -1
- package/src/config/bundled-skills/phone-calls/tools/call-status.ts +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +16 -0
- package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +91 -51
- package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +30 -16
- package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +66 -27
- package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +89 -42
- package/src/config/bundled-skills/public-ingress/SKILL.md +26 -19
- package/src/config/bundled-skills/reminder/TOOLS.json +15 -2
- package/src/config/bundled-skills/reminder/tools/reminder-cancel.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-create.ts +5 -2
- package/src/config/bundled-skills/reminder/tools/reminder-list.ts +5 -2
- package/src/config/bundled-skills/schedule/SKILL.md +33 -15
- package/src/config/bundled-skills/schedule/TOOLS.json +17 -1
- package/src/config/bundled-skills/schedule/tools/schedule-create.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-delete.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-list.ts +5 -2
- package/src/config/bundled-skills/schedule/tools/schedule-update.ts +5 -2
- package/src/config/bundled-skills/screen-recording/SKILL.md +11 -3
- package/src/config/bundled-skills/self-upgrade/SKILL.md +9 -8
- package/src/config/bundled-skills/slack/SKILL.md +30 -1
- package/src/config/bundled-skills/slack/TOOLS.json +122 -17
- package/src/config/bundled-skills/slack/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +146 -0
- package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +46 -16
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +11 -5
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +28 -0
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +12 -6
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +120 -0
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +200 -0
- package/src/config/bundled-skills/sms-setup/SKILL.md +5 -8
- package/src/config/bundled-skills/subagent/TOOLS.json +22 -2
- package/src/config/bundled-skills/subagent/tools/subagent-abort.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-message.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-read.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-spawn.ts +5 -2
- package/src/config/bundled-skills/subagent/tools/subagent-status.ts +5 -2
- package/src/config/bundled-skills/tasks/TOOLS.json +86 -14
- package/src/config/bundled-skills/tasks/tools/task-delete.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-add.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-show.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list-update.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-list.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-run.ts +5 -2
- package/src/config/bundled-skills/tasks/tools/task-save.ts +5 -2
- package/src/config/bundled-skills/telegram-setup/SKILL.md +7 -8
- package/src/config/bundled-skills/transcribe/TOOLS.json +4 -0
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +232 -127
- package/src/config/bundled-skills/twilio-setup/SKILL.md +7 -12
- package/src/config/bundled-skills/twitter/SKILL.md +19 -2
- package/src/config/bundled-skills/voice-setup/SKILL.md +5 -5
- package/src/config/bundled-skills/watcher/TOOLS.json +20 -0
- package/src/config/bundled-skills/watcher/tools/watcher-create.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-list.ts +5 -2
- package/src/config/bundled-skills/watcher/tools/watcher-update.ts +5 -2
- package/src/config/bundled-skills/weather/TOOLS.json +4 -0
- package/src/config/bundled-skills/weather/tools/get-weather.ts +5 -2
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/calls-schema.ts +108 -63
- package/src/config/channel-permission-profiles.ts +155 -0
- package/src/config/computer-use-prompt.ts +7 -7
- package/src/config/core-schema.ts +239 -155
- package/src/config/defaults.ts +2 -2
- package/src/config/elevenlabs-schema.ts +15 -15
- package/src/config/env-registry.ts +33 -33
- package/src/config/env.ts +4 -1
- package/src/config/feature-flag-registry.json +31 -7
- package/src/config/loader.ts +118 -58
- package/src/config/mcp-schema.ts +29 -15
- package/src/config/memory-schema.ts +434 -229
- package/src/config/notifications-schema.ts +4 -4
- package/src/config/sandbox-schema.ts +2 -2
- package/src/config/schema.ts +12 -2
- package/src/config/skill-state.ts +27 -15
- package/src/config/skills-schema.ts +72 -23
- package/src/config/skills.ts +303 -143
- package/src/config/system-prompt.ts +25 -6
- package/src/config/types.ts +1 -1
- package/src/config/update-bulletin-format.ts +3 -3
- package/src/config/update-bulletin-state.ts +15 -6
- package/src/config/update-bulletin-template-path.ts +8 -4
- package/src/config/update-bulletin.ts +33 -14
- package/src/config/user-reference.ts +8 -8
- package/src/contacts/contact-events.ts +21 -0
- package/src/contacts/contact-store.ts +813 -100
- package/src/contacts/contacts-write.ts +287 -0
- package/src/contacts/index.ts +13 -4
- package/src/contacts/startup-migration.ts +21 -0
- package/src/contacts/types.ts +73 -2
- package/src/context/token-estimator.ts +54 -31
- package/src/context/tool-result-truncation.ts +41 -7
- package/src/context/window-manager.ts +225 -120
- package/src/daemon/approval-generators.ts +83 -55
- package/src/daemon/approved-devices-store.ts +33 -20
- package/src/daemon/assistant-attachments.ts +157 -101
- package/src/daemon/auth-manager.ts +17 -15
- package/src/daemon/classifier.ts +117 -46
- package/src/daemon/computer-use-session.ts +316 -187
- package/src/daemon/config-watcher.ts +91 -44
- package/src/daemon/connection-policy.ts +18 -10
- package/src/daemon/context-overflow-approval.ts +48 -0
- package/src/daemon/context-overflow-policy.ts +50 -0
- package/src/daemon/context-overflow-reducer.ts +300 -0
- package/src/daemon/daemon-control.ts +79 -51
- package/src/daemon/date-context.ts +119 -69
- package/src/daemon/dictation-profile-store.ts +94 -48
- package/src/daemon/dictation-text-processing.ts +33 -12
- package/src/daemon/doordash-steps.ts +92 -49
- package/src/daemon/guardian-action-generators.ts +62 -46
- package/src/daemon/guardian-verification-intent.ts +35 -19
- package/src/daemon/handlers/apps.ts +258 -113
- package/src/daemon/handlers/avatar.ts +20 -15
- package/src/daemon/handlers/computer-use.ts +82 -39
- package/src/daemon/handlers/config-channels.ts +146 -69
- package/src/daemon/handlers/config-heartbeat.ts +114 -59
- package/src/daemon/handlers/config-inbox.ts +213 -160
- package/src/daemon/handlers/config-ingress.ts +127 -55
- package/src/daemon/handlers/config-integrations.ts +145 -88
- package/src/daemon/handlers/config-model.ts +58 -22
- package/src/daemon/handlers/config-platform.ts +40 -16
- package/src/daemon/handlers/config-scheduling.ts +109 -48
- package/src/daemon/handlers/config-slack-channel.ts +67 -35
- package/src/daemon/handlers/config-slack.ts +21 -20
- package/src/daemon/handlers/config-telegram.ts +100 -70
- package/src/daemon/handlers/config-tools.ts +103 -55
- package/src/daemon/handlers/config-trust.ts +50 -20
- package/src/daemon/handlers/config.ts +72 -24
- package/src/daemon/handlers/contacts.ts +163 -0
- package/src/daemon/handlers/diagnostics.ts +90 -48
- package/src/daemon/handlers/documents.ts +74 -46
- package/src/daemon/handlers/guardian-actions.ts +57 -77
- package/src/daemon/handlers/home-base.ts +19 -16
- package/src/daemon/handlers/identity.ts +65 -45
- package/src/daemon/handlers/index.ts +78 -54
- package/src/daemon/handlers/misc.ts +664 -234
- package/src/daemon/handlers/navigate-settings.ts +14 -11
- package/src/daemon/handlers/oauth-connect.ts +48 -35
- package/src/daemon/handlers/open-bundle-handler.ts +31 -24
- package/src/daemon/handlers/pairing.ts +51 -25
- package/src/daemon/handlers/publish.ts +55 -33
- package/src/daemon/handlers/recording.ts +378 -162
- package/src/daemon/handlers/sessions.ts +922 -423
- package/src/daemon/handlers/shared.ts +202 -117
- package/src/daemon/handlers/signing.ts +25 -6
- package/src/daemon/handlers/subagents.ts +117 -56
- package/src/daemon/handlers/twitter-auth.ts +70 -49
- package/src/daemon/handlers/work-items.ts +264 -112
- package/src/daemon/handlers/workspace-files.ts +27 -20
- package/src/daemon/handlers.ts +2 -2
- package/src/daemon/history-repair.ts +16 -15
- package/src/daemon/identity-helpers.ts +4 -4
- package/src/daemon/install-cli-launchers.ts +33 -22
- package/src/daemon/ipc-blob-store.ts +38 -24
- package/src/daemon/ipc-contract/apps.ts +61 -50
- package/src/daemon/ipc-contract/computer-use.ts +47 -37
- package/src/daemon/ipc-contract/contacts.ts +69 -0
- package/src/daemon/ipc-contract/diagnostics.ts +14 -14
- package/src/daemon/ipc-contract/documents.ts +8 -8
- package/src/daemon/ipc-contract/guardian-actions.ts +4 -4
- package/src/daemon/ipc-contract/inbox.ts +12 -71
- package/src/daemon/ipc-contract/integrations.ts +57 -44
- package/src/daemon/ipc-contract/memory.ts +3 -5
- package/src/daemon/ipc-contract/messages.ts +95 -69
- package/src/daemon/ipc-contract/notifications.ts +10 -6
- package/src/daemon/ipc-contract/pairing.ts +8 -8
- package/src/daemon/ipc-contract/schedules.ts +20 -20
- package/src/daemon/ipc-contract/sessions.ts +89 -57
- package/src/daemon/ipc-contract/settings.ts +12 -7
- package/src/daemon/ipc-contract/shared.ts +9 -7
- package/src/daemon/ipc-contract/skills.ts +46 -26
- package/src/daemon/ipc-contract/subagents.ts +9 -9
- package/src/daemon/ipc-contract/surfaces.ts +0 -1
- package/src/daemon/ipc-contract/trust.ts +11 -11
- package/src/daemon/ipc-contract/work-items.ts +33 -28
- package/src/daemon/ipc-contract/workspace.ts +28 -21
- package/src/daemon/ipc-contract-inventory.json +10 -4
- package/src/daemon/ipc-contract-inventory.ts +29 -26
- package/src/daemon/ipc-contract.ts +111 -44
- package/src/daemon/ipc-handler.ts +27 -19
- package/src/daemon/ipc-protocol.ts +22 -12
- package/src/daemon/ipc-validate.ts +91 -46
- package/src/daemon/lifecycle.ts +39 -3
- package/src/daemon/main.ts +10 -8
- package/src/daemon/media-visibility-policy.ts +3 -1
- package/src/daemon/pairing-store.ts +72 -40
- package/src/daemon/providers-setup.ts +35 -25
- package/src/daemon/recording-executor.ts +37 -30
- package/src/daemon/recording-intent-fallback.ts +58 -28
- package/src/daemon/recording-intent.ts +71 -61
- package/src/daemon/ride-shotgun-handler.ts +201 -121
- package/src/daemon/seed-files.ts +28 -17
- package/src/daemon/server.ts +23 -14
- package/src/daemon/session-agent-loop-handlers.ts +270 -135
- package/src/daemon/session-agent-loop.ts +796 -253
- package/src/daemon/session-attachments.ts +109 -40
- package/src/daemon/session-conflict-gate.ts +72 -28
- package/src/daemon/session-dynamic-profile.ts +36 -22
- package/src/daemon/session-error.ts +68 -45
- package/src/daemon/session-evictor.ts +17 -10
- package/src/daemon/session-history.ts +201 -89
- package/src/daemon/session-lifecycle.ts +80 -44
- package/src/daemon/session-media-retry.ts +104 -42
- package/src/daemon/session-memory.ts +77 -55
- package/src/daemon/session-messaging.ts +261 -111
- package/src/daemon/session-notifiers.ts +57 -45
- package/src/daemon/session-process.ts +370 -154
- package/src/daemon/session-queue-manager.ts +30 -13
- package/src/daemon/session-runtime-assembly.ts +61 -15
- package/src/daemon/session-skill-tools.ts +84 -36
- package/src/daemon/session-slash.ts +178 -113
- package/src/daemon/session-surfaces.ts +498 -212
- package/src/daemon/session-tool-setup.ts +24 -16
- package/src/daemon/session-usage.ts +26 -13
- package/src/daemon/session-workspace.ts +7 -4
- package/src/daemon/session.ts +18 -19
- package/src/daemon/shutdown-handlers.ts +36 -33
- package/src/daemon/tls-certs.ts +90 -57
- package/src/daemon/tool-side-effects.ts +97 -65
- package/src/daemon/trace-emitter.ts +8 -7
- package/src/daemon/video-thumbnail.ts +55 -25
- package/src/daemon/watch-handler.ts +164 -86
- package/src/email/provider.ts +1 -1
- package/src/email/providers/agentmail.ts +87 -45
- package/src/email/providers/index.ts +19 -14
- package/src/email/service.ts +52 -24
- package/src/email/types.ts +2 -2
- package/src/errors.ts +1 -1
- package/src/events/bus.ts +30 -10
- package/src/events/domain-events.ts +20 -13
- package/src/events/index.ts +6 -6
- package/src/events/tool-audit-listener.ts +34 -20
- package/src/events/tool-domain-event-publisher.ts +22 -20
- package/src/events/tool-metrics-listener.ts +26 -21
- package/src/events/tool-notification-listener.ts +5 -5
- package/src/events/tool-profiling-listener.ts +33 -23
- package/src/events/tool-trace-listener.ts +70 -46
- package/src/export/formatter.ts +38 -32
- package/src/followups/followup-store.ts +43 -36
- package/src/followups/index.ts +2 -2
- package/src/followups/types.ts +1 -1
- package/src/gallery/default-gallery.ts +37 -34
- package/src/gallery/gallery-manifest.ts +9 -9
- package/src/heartbeat/heartbeat-service.ts +59 -37
- package/src/home-base/app-link-store.ts +14 -12
- package/src/home-base/bootstrap.ts +14 -8
- package/src/home-base/prebuilt/seed.ts +34 -26
- package/src/home-base/prebuilt-home-base-updater.ts +14 -8
- package/src/hooks/cli.ts +56 -43
- package/src/hooks/config.ts +27 -14
- package/src/hooks/discovery.ts +53 -33
- package/src/hooks/manager.ts +50 -26
- package/src/hooks/runner.ts +35 -29
- package/src/hooks/templates.ts +38 -15
- package/src/hooks/types.ts +13 -13
- package/src/inbound/platform-callback-registration.ts +21 -15
- package/src/inbound/public-ingress-urls.ts +9 -6
- package/src/index.ts +20 -19
- package/src/influencer/client.ts +261 -117
- package/src/instrument.ts +3 -1
- package/src/logfire.ts +64 -39
- package/src/mcp/client.ts +107 -55
- package/src/mcp/manager.ts +45 -18
- package/src/mcp/mcp-oauth-provider.ts +114 -62
- package/src/media/gemini-image-service.ts +75 -23
- package/src/memory/account-store.ts +16 -9
- package/src/memory/admin.ts +87 -57
- package/src/memory/app-git-service.ts +77 -47
- package/src/memory/app-store.ts +148 -78
- package/src/memory/attachments-store.ts +123 -53
- package/src/memory/canonical-guardian-store.ts +190 -48
- package/src/memory/channel-delivery-store.ts +5 -5
- package/src/memory/channel-guardian-store.ts +31 -16
- package/src/memory/checkpoints.ts +14 -7
- package/src/memory/clarification-resolver.ts +219 -104
- package/src/memory/conflict-intent.ts +74 -23
- package/src/memory/conflict-policy.ts +20 -7
- package/src/memory/conflict-store.ts +144 -94
- package/src/memory/contradiction-checker.ts +257 -132
- package/src/memory/conversation-attention-store.ts +74 -32
- package/src/memory/conversation-bootstrap.ts +28 -0
- package/src/memory/conversation-crud.ts +12 -5
- package/src/memory/conversation-display-order-migration.ts +7 -7
- package/src/memory/conversation-key-store.ts +18 -13
- package/src/memory/conversation-queries.ts +130 -52
- package/src/memory/conversation-store.ts +43 -26
- package/src/memory/conversation-title-service.ts +89 -66
- package/src/memory/db-init.ts +94 -2
- package/src/memory/db.ts +10 -3
- package/src/memory/delivery-channels.ts +12 -6
- package/src/memory/delivery-crud.ts +26 -12
- package/src/memory/delivery-status.ts +19 -16
- package/src/memory/embedding-backend.ts +205 -77
- package/src/memory/embedding-gemini.ts +23 -10
- package/src/memory/embedding-local.ts +89 -44
- package/src/memory/embedding-ollama.ts +25 -13
- package/src/memory/embedding-openai.ts +20 -11
- package/src/memory/embedding-runtime-manager.ts +163 -90
- package/src/memory/entity-extractor.ts +185 -123
- package/src/memory/external-conversation-store.ts +30 -12
- package/src/memory/fingerprint.ts +2 -2
- package/src/memory/fts-reconciler.ts +57 -28
- package/src/memory/guardian-action-store.ts +162 -100
- package/src/memory/guardian-approvals.ts +63 -129
- package/src/memory/guardian-rate-limits.ts +20 -9
- package/src/memory/guardian-verification.ts +82 -35
- package/src/memory/indexer.ts +96 -55
- package/src/memory/{ingress-invite-store.ts → invite-store.ts} +28 -169
- package/src/memory/items-extractor.ts +313 -157
- package/src/memory/job-handlers/backfill.ts +116 -63
- package/src/memory/job-handlers/cleanup.ts +64 -41
- package/src/memory/job-handlers/conflict.ts +90 -49
- package/src/memory/job-handlers/embedding.ts +32 -17
- package/src/memory/job-handlers/extraction.ts +58 -33
- package/src/memory/job-handlers/index-maintenance.ts +31 -17
- package/src/memory/job-handlers/media-processing.ts +65 -24
- package/src/memory/job-handlers/summarization.ts +186 -128
- package/src/memory/job-utils.ts +100 -57
- package/src/memory/jobs-store.ts +235 -142
- package/src/memory/jobs-worker.ts +167 -83
- package/src/memory/llm-request-log-store.ts +13 -11
- package/src/memory/llm-usage-store.ts +35 -26
- package/src/memory/media-store.ts +151 -44
- package/src/memory/message-content.ts +28 -18
- package/src/memory/migrations/001-job-deferrals.ts +11 -5
- package/src/memory/migrations/002-tool-invocations-fk.ts +14 -6
- package/src/memory/migrations/003-memory-fts-backfill.ts +11 -5
- package/src/memory/migrations/004-entity-relation-dedup.ts +17 -11
- package/src/memory/migrations/005-fingerprint-scope-unique.ts +36 -21
- package/src/memory/migrations/006-scope-salted-fingerprints.ts +35 -20
- package/src/memory/migrations/007-assistant-id-to-self.ts +40 -27
- package/src/memory/migrations/008-remove-assistant-id-columns.ts +58 -36
- package/src/memory/migrations/009-llm-usage-events-drop-assistant-id.ts +36 -22
- package/src/memory/migrations/010-ext-conv-bindings-channel-chat-unique.ts +21 -11
- package/src/memory/migrations/011-call-sessions-provider-sid-dedup.ts +30 -15
- package/src/memory/migrations/012-call-sessions-add-initiated-from.ts +4 -2
- package/src/memory/migrations/013-guardian-action-tables.ts +29 -11
- package/src/memory/migrations/014-backfill-inbox-thread-state.ts +35 -21
- package/src/memory/migrations/015-drop-active-search-index.ts +17 -11
- package/src/memory/migrations/016-memory-segments-indexes.ts +7 -3
- package/src/memory/migrations/017-memory-items-indexes.ts +4 -2
- package/src/memory/migrations/018-remaining-table-indexes.ts +13 -5
- package/src/memory/migrations/019-notification-tables-schema-migration.ts +34 -20
- package/src/memory/migrations/020-rename-macos-ios-channel-to-vellum.ts +87 -53
- package/src/memory/migrations/021-conversation-status-indexes.ts +7 -3
- package/src/memory/migrations/022-add-origin-interface.ts +4 -2
- package/src/memory/migrations/023-memory-item-sources-indexes.ts +4 -2
- package/src/memory/migrations/024-embedding-vector-blob.ts +34 -18
- package/src/memory/migrations/025-messages-fts-backfill.ts +11 -5
- package/src/memory/migrations/026-guardian-verification-sessions.ts +80 -14
- package/src/memory/migrations/026a-embeddings-nullable-vector-json.ts +42 -26
- package/src/memory/migrations/027-notification-delivery-pairing-columns.ts +22 -8
- package/src/memory/migrations/027a-guardian-bootstrap-token.ts +11 -3
- package/src/memory/migrations/028-call-session-mode.ts +13 -3
- package/src/memory/migrations/028-notification-delivery-client-ack.ts +22 -8
- package/src/memory/migrations/029-channel-inbound-delivered-segments.ts +7 -3
- package/src/memory/migrations/030-guardian-action-followup.ts +46 -8
- package/src/memory/migrations/030-guardian-verification-purpose.ts +4 -2
- package/src/memory/migrations/031-conversations-thread-type-index.ts +4 -2
- package/src/memory/migrations/032-guardian-delivery-conversation-index.ts +4 -2
- package/src/memory/migrations/032-notification-delivery-thread-decision.ts +22 -8
- package/src/memory/migrations/033-scoped-approval-grants.ts +1 -1
- package/src/memory/migrations/034-guardian-action-tool-metadata.ts +15 -3
- package/src/memory/migrations/035-guardian-action-supersession.ts +15 -3
- package/src/memory/migrations/036-normalize-phone-identities.ts +101 -87
- package/src/memory/migrations/037-voice-invite-columns.ts +22 -4
- package/src/memory/migrations/038-actor-token-records.ts +5 -9
- package/src/memory/migrations/039-actor-refresh-token-records.ts +7 -13
- package/src/memory/migrations/100-core-tables.ts +1 -1
- package/src/memory/migrations/101-watchers-and-logs.ts +1 -1
- package/src/memory/migrations/103-complex-migrations.ts +9 -9
- package/src/memory/migrations/104-core-indexes.ts +188 -64
- package/src/memory/migrations/105-contacts-and-triage.ts +28 -10
- package/src/memory/migrations/106-call-sessions.ts +58 -16
- package/src/memory/migrations/107-followups.ts +16 -6
- package/src/memory/migrations/108-tasks-and-work-items.ts +43 -11
- package/src/memory/migrations/109-external-conversation-bindings.ts +11 -5
- package/src/memory/migrations/110-channel-guardian.ts +48 -10
- package/src/memory/migrations/111-media-assets.ts +52 -18
- package/src/memory/migrations/112-assistant-inbox.ts +32 -12
- package/src/memory/migrations/113-late-migrations.ts +12 -12
- package/src/memory/migrations/114-notifications.ts +28 -12
- package/src/memory/migrations/115-sequences.ts +10 -4
- package/src/memory/migrations/116-messages-fts.ts +1 -1
- package/src/memory/migrations/117-conversation-attention.ts +16 -6
- package/src/memory/migrations/118-reminder-routing-intent.ts +7 -3
- package/src/memory/migrations/119-schema-indexes-and-columns.ts +35 -15
- package/src/memory/migrations/120-fk-cascade-rebuilds.ts +36 -17
- package/src/memory/migrations/121-canonical-guardian-requests.ts +25 -9
- package/src/memory/migrations/122-canonical-guardian-requester-chat-id.ts +11 -3
- package/src/memory/migrations/123-canonical-guardian-deliveries-destination-index.ts +4 -2
- package/src/memory/migrations/124-voice-invite-display-metadata.ts +15 -3
- package/src/memory/migrations/125-guardian-principal-id-columns.ts +22 -4
- package/src/memory/migrations/126-backfill-guardian-principal-id.ts +174 -126
- package/src/memory/migrations/127-guardian-principal-id-not-null.ts +58 -42
- package/src/memory/migrations/128-contacts-role-principal.ts +26 -0
- package/src/memory/migrations/129-contact-channels-access-fields.ts +105 -0
- package/src/memory/migrations/130-contact-channels-type-ext-chat-id-index.ts +15 -0
- package/src/memory/migrations/131-drop-legacy-member-guardian-tables.ts +134 -0
- package/src/memory/migrations/132-contacts-assistant-id.ts +21 -0
- package/src/memory/migrations/133-assistant-contact-metadata.ts +21 -0
- package/src/memory/migrations/index.ts +83 -73
- package/src/memory/migrations/registry.ts +53 -37
- package/src/memory/migrations/validate-migration-state.ts +73 -46
- package/src/memory/profile-compiler.ts +58 -24
- package/src/memory/published-pages-store.ts +12 -16
- package/src/memory/qdrant-circuit-breaker.ts +28 -20
- package/src/memory/qdrant-client.ts +99 -63
- package/src/memory/qdrant-manager.ts +89 -57
- package/src/memory/query-builder.ts +9 -7
- package/src/memory/raw-query.ts +63 -14
- package/src/memory/recall-cache.ts +15 -8
- package/src/memory/retrieval-budget.ts +0 -1
- package/src/memory/retriever.ts +385 -192
- package/src/memory/schema-migration.ts +1 -1
- package/src/memory/schema.ts +56 -56
- package/src/memory/scoped-approval-grants.ts +99 -45
- package/src/memory/search/entity.ts +102 -40
- package/src/memory/search/formatting.ts +70 -52
- package/src/memory/search/lexical.ts +82 -43
- package/src/memory/search/ranking.ts +103 -39
- package/src/memory/search/semantic.ts +59 -35
- package/src/memory/search/types.ts +8 -8
- package/src/memory/segmenter.ts +20 -12
- package/src/memory/shared-app-links-store.ts +21 -16
- package/src/memory/slack-thread-store.ts +187 -0
- package/src/memory/task-memory-cleanup.ts +18 -8
- package/src/memory/tool-usage-store.ts +27 -19
- package/src/memory/validation.ts +4 -2
- package/src/messaging/activity-analyzer.ts +7 -7
- package/src/messaging/draft-store.ts +13 -10
- package/src/messaging/email-classifier.ts +73 -37
- package/src/messaging/index.ts +3 -3
- package/src/messaging/outreach-classifier.ts +76 -38
- package/src/messaging/provider-types.ts +2 -4
- package/src/messaging/provider.ts +37 -8
- package/src/messaging/providers/gmail/adapter.ts +183 -66
- package/src/messaging/providers/gmail/client.ts +3 -1
- package/src/messaging/providers/gmail/mime-builder.ts +21 -19
- package/src/messaging/providers/gmail/people-client.ts +22 -9
- package/src/messaging/providers/gmail/types.ts +6 -6
- package/src/messaging/providers/slack/adapter.ts +93 -43
- package/src/messaging/providers/slack/client.ts +165 -48
- package/src/messaging/providers/slack/types.ts +10 -0
- package/src/messaging/providers/sms/adapter.ts +76 -40
- package/src/messaging/providers/sms/client.ts +4 -4
- package/src/messaging/providers/telegram-bot/adapter.ts +52 -30
- package/src/messaging/providers/telegram-bot/client.ts +7 -7
- package/src/messaging/providers/whatsapp/adapter.ts +58 -31
- package/src/messaging/providers/whatsapp/client.ts +4 -4
- package/src/messaging/registry.ts +9 -5
- package/src/messaging/style-analyzer.ts +69 -39
- package/src/messaging/thread-summarizer.ts +101 -53
- package/src/messaging/triage-engine.ts +111 -82
- package/src/messaging/types.ts +10 -10
- package/src/migrations/config-merge.ts +18 -10
- package/src/migrations/data-layout.ts +35 -22
- package/src/migrations/data-merge.ts +17 -7
- package/src/migrations/hooks-merge.ts +43 -16
- package/src/migrations/index.ts +6 -6
- package/src/migrations/log.ts +9 -5
- package/src/migrations/skills-merge.ts +17 -7
- package/src/migrations/workspace-layout.ts +39 -25
- package/src/notifications/AGENTS.md +5 -0
- package/src/notifications/adapters/macos.ts +21 -14
- package/src/notifications/adapters/slack.ts +90 -0
- package/src/notifications/adapters/sms.ts +28 -15
- package/src/notifications/adapters/telegram.ts +24 -15
- package/src/notifications/broadcaster.ts +108 -52
- package/src/notifications/conversation-pairing.ts +64 -29
- package/src/notifications/copy-composer.ts +165 -95
- package/src/notifications/decision-engine.ts +353 -147
- package/src/notifications/decisions-store.ts +26 -10
- package/src/notifications/deliveries-store.ts +23 -13
- package/src/notifications/destination-resolver.ts +83 -24
- package/src/notifications/deterministic-checks.ts +78 -27
- package/src/notifications/emit-signal.ts +95 -41
- package/src/notifications/events-store.ts +13 -7
- package/src/notifications/guardian-question-mode.ts +125 -75
- package/src/notifications/preference-extractor.ts +85 -53
- package/src/notifications/preference-summary.ts +31 -18
- package/src/notifications/preferences-store.ts +29 -18
- package/src/notifications/runtime-dispatch.ts +22 -12
- package/src/notifications/signal.ts +4 -4
- package/src/notifications/thread-candidates.ts +59 -23
- package/src/notifications/thread-seed-composer.ts +45 -27
- package/src/notifications/types.ts +19 -10
- package/src/oauth/connect-orchestrator.ts +105 -54
- package/src/oauth/connect-types.ts +3 -3
- package/src/oauth/provider-profiles.ts +102 -59
- package/src/oauth/scope-policy.ts +5 -2
- package/src/oauth/token-persistence.ts +58 -24
- package/src/outbound-proxy/certs.ts +284 -0
- package/src/outbound-proxy/config.ts +94 -0
- package/src/outbound-proxy/connect-tunnel.ts +84 -0
- package/src/outbound-proxy/health.ts +62 -0
- package/src/outbound-proxy/host-pattern-match.ts +67 -0
- package/src/outbound-proxy/http-forwarder.ts +162 -0
- package/src/outbound-proxy/index.ts +80 -0
- package/src/outbound-proxy/logging.ts +193 -0
- package/src/outbound-proxy/mitm-handler.ts +292 -0
- package/src/outbound-proxy/policy.ts +172 -0
- package/src/outbound-proxy/router.ts +64 -0
- package/src/outbound-proxy/server.ts +145 -0
- package/src/outbound-proxy/types.ts +150 -0
- package/src/permissions/checker.ts +481 -189
- package/src/permissions/defaults.ts +135 -108
- package/src/permissions/prompter.ts +53 -27
- package/src/permissions/secret-prompter.ts +21 -15
- package/src/permissions/shell-identity.ts +47 -16
- package/src/permissions/trust-store.ts +185 -73
- package/src/permissions/types.ts +22 -12
- package/src/permissions/workspace-policy.ts +47 -38
- package/src/playbooks/index.ts +10 -2
- package/src/playbooks/playbook-compiler.ts +30 -24
- package/src/playbooks/types.ts +11 -8
- package/src/providers/anthropic/client.ts +328 -168
- package/src/providers/failover.ts +57 -22
- package/src/providers/fireworks/client.ts +9 -5
- package/src/providers/gemini/client.ts +61 -39
- package/src/providers/model-intents.ts +40 -33
- package/src/providers/ollama/client.ts +7 -7
- package/src/providers/openai/client.ts +109 -68
- package/src/providers/openrouter/client.ts +9 -5
- package/src/providers/provider-send-message.ts +59 -27
- package/src/providers/ratelimit.ts +25 -8
- package/src/providers/registry.ts +86 -38
- package/src/providers/retry.ts +93 -37
- package/src/providers/stream-timeout.ts +5 -3
- package/src/providers/types.ts +7 -6
- package/src/runtime/AGENTS.md +42 -0
- package/src/runtime/access-request-helper.ts +118 -68
- package/src/runtime/actor-refresh-token-store.ts +21 -16
- package/src/runtime/actor-token-store.ts +25 -18
- package/src/runtime/actor-trust-resolver.ts +191 -80
- package/src/runtime/approval-conversation-turn.ts +39 -26
- package/src/runtime/approval-message-composer.ts +116 -84
- package/src/runtime/assistant-event-hub.ts +25 -6
- package/src/runtime/assistant-event.ts +4 -4
- package/src/runtime/assistant-scope.ts +1 -1
- package/src/runtime/auth/__tests__/guard-tests.test.ts +36 -14
- package/src/runtime/auth/context.ts +8 -7
- package/src/runtime/auth/credential-service.ts +60 -38
- package/src/runtime/auth/external-assistant-id.ts +16 -8
- package/src/runtime/auth/index.ts +23 -16
- package/src/runtime/auth/require-bound-guardian.ts +44 -0
- package/src/runtime/auth/route-policy.ts +166 -104
- package/src/runtime/auth/scopes.ts +22 -29
- package/src/runtime/auth/subject.ts +19 -13
- package/src/runtime/auth/token-service.ts +3 -3
- package/src/runtime/auth/types.ts +23 -23
- package/src/runtime/channel-approval-parser.ts +37 -14
- package/src/runtime/channel-approval-types.ts +30 -4
- package/src/runtime/channel-approvals.ts +49 -23
- package/src/runtime/channel-guardian-service.ts +144 -103
- package/src/runtime/channel-invite-transport.ts +5 -3
- package/src/runtime/channel-invite-transports/telegram.ts +16 -10
- package/src/runtime/channel-invite-transports/voice.ts +7 -7
- package/src/runtime/channel-readiness-service.ts +139 -90
- package/src/runtime/channel-readiness-types.ts +4 -2
- package/src/runtime/channel-reply-delivery.ts +83 -14
- package/src/runtime/channel-retry-sweep.ts +111 -62
- package/src/runtime/confirmation-request-guardian-bridge.ts +73 -54
- package/src/runtime/gateway-client.ts +122 -55
- package/src/runtime/gateway-internal-client.ts +86 -0
- package/src/runtime/guardian-action-conversation-turn.ts +34 -18
- package/src/runtime/guardian-action-followup-executor.ts +115 -45
- package/src/runtime/guardian-action-grant-minter.ts +40 -24
- package/src/runtime/guardian-action-message-composer.ts +105 -84
- package/src/runtime/guardian-action-service.ts +127 -0
- package/src/runtime/guardian-decision-types.ts +28 -13
- package/src/runtime/guardian-outbound-actions.ts +9 -0
- package/src/runtime/guardian-reply-router.ts +274 -145
- package/src/runtime/guardian-vellum-migration.ts +38 -24
- package/src/runtime/guardian-verification-templates.ts +24 -12
- package/src/runtime/http-router.ts +175 -0
- package/src/runtime/http-server.ts +913 -680
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/invite-redemption-service.ts +211 -134
- package/src/runtime/invite-redemption-templates.ts +18 -11
- package/src/runtime/{ingress-service.ts → invite-service.ts} +92 -151
- package/src/runtime/local-actor-identity.ts +73 -55
- package/src/runtime/middleware/auth.ts +25 -14
- package/src/runtime/middleware/error-handler.ts +15 -11
- package/src/runtime/middleware/rate-limiter.ts +23 -17
- package/src/runtime/middleware/request-logger.ts +4 -4
- package/src/runtime/middleware/twilio-validation.ts +29 -20
- package/src/runtime/migrations/migration-transport.ts +575 -0
- package/src/runtime/migrations/migration-wizard.ts +715 -0
- package/src/runtime/migrations/rebind-secrets-screen.ts +351 -0
- package/src/runtime/migrations/transfer-progress-screen.ts +321 -0
- package/src/runtime/migrations/validation-results-screen.ts +467 -0
- package/src/runtime/migrations/vbundle-builder.ts +295 -0
- package/src/runtime/migrations/vbundle-import-analyzer.ts +212 -0
- package/src/runtime/migrations/vbundle-importer.ts +339 -0
- package/src/runtime/migrations/vbundle-validator.ts +356 -0
- package/src/runtime/nl-approval-parser.ts +138 -0
- package/src/runtime/pending-interactions.ts +16 -7
- package/src/runtime/routes/access-request-decision.ts +73 -52
- package/src/runtime/routes/app-routes.ts +56 -38
- package/src/runtime/routes/approval-routes.ts +144 -92
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +930 -0
- package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +82 -0
- package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +151 -0
- package/src/runtime/routes/attachment-routes.ts +59 -48
- package/src/runtime/routes/brain-graph-routes.ts +85 -69
- package/src/runtime/routes/call-routes.ts +79 -38
- package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +10 -10
- package/src/runtime/routes/channel-delivery-routes.ts +19 -14
- package/src/runtime/routes/channel-guardian-routes.ts +3 -3
- package/src/runtime/routes/channel-inbound-routes.ts +2 -2
- package/src/runtime/routes/channel-readiness-routes.ts +12 -6
- package/src/runtime/routes/channel-route-shared.ts +67 -25
- package/src/runtime/routes/channel-routes.ts +4 -6
- package/src/runtime/routes/contact-routes.ts +374 -17
- package/src/runtime/routes/conversation-attention-routes.ts +57 -28
- package/src/runtime/routes/conversation-routes.ts +321 -174
- package/src/runtime/routes/debug-routes.ts +14 -10
- package/src/runtime/routes/events-routes.ts +90 -57
- package/src/runtime/routes/global-search-routes.ts +266 -0
- package/src/runtime/routes/guardian-action-routes.ts +112 -113
- package/src/runtime/routes/guardian-approval-interception.ts +325 -874
- package/src/runtime/routes/guardian-approval-prompt.ts +40 -24
- package/src/runtime/routes/guardian-approval-reply-helpers.ts +135 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +55 -36
- package/src/runtime/routes/guardian-expiry-sweep.ts +63 -37
- package/src/runtime/routes/guardian-refresh-routes.ts +40 -19
- package/src/runtime/routes/identity-routes.ts +71 -42
- package/src/runtime/routes/inbound-conversation.ts +17 -11
- package/src/runtime/routes/inbound-message-handler.ts +305 -1459
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +880 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +600 -0
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +214 -0
- package/src/runtime/routes/inbound-stages/edit-intercept.ts +116 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +167 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +185 -0
- package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +132 -0
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +340 -0
- package/src/runtime/routes/integration-routes.ts +60 -21
- package/src/runtime/routes/invite-routes.ts +140 -0
- package/src/runtime/routes/migration-routes.ts +434 -0
- package/src/runtime/routes/pairing-routes.ts +157 -79
- package/src/runtime/routes/secret-routes.ts +6 -2
- package/src/runtime/routes/twilio-routes.ts +443 -249
- package/src/runtime/slack-block-formatting.ts +176 -0
- package/src/runtime/tool-grant-request-helper.ts +36 -27
- package/src/runtime/{guardian-context-resolver.ts → trust-context-resolver.ts} +29 -41
- package/src/schedule/integration-status.ts +44 -9
- package/src/schedule/recurrence-engine.ts +47 -24
- package/src/schedule/recurrence-types.ts +12 -7
- package/src/schedule/schedule-store.ts +166 -83
- package/src/schedule/scheduler.ts +37 -24
- package/src/security/encrypted-store.ts +68 -38
- package/src/security/keychain.ts +183 -120
- package/src/security/oauth-callback-registry.ts +3 -3
- package/src/security/oauth2.ts +226 -138
- package/src/security/redaction.ts +24 -24
- package/src/security/secret-allowlist.ts +46 -21
- package/src/security/secret-ingress.ts +15 -7
- package/src/security/secret-scanner.ts +193 -104
- package/src/security/secure-keys.ts +9 -3
- package/src/security/token-manager.ts +99 -40
- package/src/security/tool-approval-digest.ts +3 -3
- package/src/sequence/analytics.ts +52 -27
- package/src/sequence/engine.ts +135 -72
- package/src/sequence/guardrails.ts +32 -20
- package/src/sequence/importer.ts +75 -37
- package/src/sequence/reply-matcher.ts +36 -18
- package/src/sequence/store.ts +137 -75
- package/src/sequence/types.ts +30 -16
- package/src/services/published-app-updater.ts +26 -16
- package/src/services/vercel-deploy.ts +19 -15
- package/src/skills/active-skill-tools.ts +3 -3
- package/src/skills/clawhub.ts +178 -90
- package/src/skills/include-graph.ts +24 -17
- package/src/skills/managed-store.ts +89 -42
- package/src/skills/path-classifier.ts +10 -10
- package/src/skills/remote-skill-policy.ts +31 -22
- package/src/skills/slash-commands.ts +36 -30
- package/src/skills/tool-manifest.ts +60 -31
- package/src/skills/version-hash.ts +25 -15
- package/src/slack/slack-webhook.ts +19 -15
- package/src/subagent/index.ts +4 -8
- package/src/subagent/manager.ts +119 -69
- package/src/subagent/types.ts +9 -12
- package/src/swarm/backend-claude-code.ts +124 -45
- package/src/swarm/checkpoint.ts +36 -16
- package/src/swarm/graph-utils.ts +1 -3
- package/src/swarm/index.ts +38 -19
- package/src/swarm/limits.ts +13 -4
- package/src/swarm/orchestrator.ts +108 -57
- package/src/swarm/plan-validator.ts +23 -17
- package/src/swarm/router-planner.ts +51 -22
- package/src/swarm/router-prompts.ts +4 -1
- package/src/swarm/synthesizer.ts +26 -18
- package/src/swarm/types.ts +14 -4
- package/src/swarm/worker-backend.ts +36 -26
- package/src/swarm/worker-prompts.ts +13 -9
- package/src/swarm/worker-runner.ts +40 -34
- package/src/tasks/candidate-store.ts +14 -6
- package/src/tasks/ephemeral-permissions.ts +9 -5
- package/src/tasks/task-compiler.ts +41 -38
- package/src/tasks/task-runner.ts +54 -26
- package/src/tasks/task-scheduler.ts +1 -1
- package/src/tasks/task-store.ts +20 -7
- package/src/tasks/tool-sanitizer.ts +3 -3
- package/src/tools/apps/definitions.ts +23 -15
- package/src/tools/apps/executors.ts +122 -40
- package/src/tools/apps/open-proxy.ts +5 -5
- package/src/tools/apps/registry.ts +2 -2
- package/src/tools/assets/materialize.ts +59 -41
- package/src/tools/assets/search.ts +86 -48
- package/src/tools/browser/api-map.ts +52 -36
- package/src/tools/browser/auth-cache.ts +21 -18
- package/src/tools/browser/auth-detector.ts +43 -28
- package/src/tools/browser/auto-navigate.ts +149 -68
- package/src/tools/browser/browser-execution.ts +9 -3
- package/src/tools/browser/headless-browser.ts +287 -150
- package/src/tools/browser/jit-auth.ts +37 -21
- package/src/tools/browser/network-recorder.ts +138 -56
- package/src/tools/browser/recording-store.ts +22 -15
- package/src/tools/browser/runtime-check.ts +8 -5
- package/src/tools/browser/x-auto-navigate.ts +88 -47
- package/src/tools/calls/call-end.ts +10 -7
- package/src/tools/calls/call-start.ts +30 -20
- package/src/tools/calls/call-status.ts +8 -5
- package/src/tools/claude-code/claude-code.ts +301 -165
- package/src/tools/computer-use/definitions.ts +175 -130
- package/src/tools/computer-use/registry.ts +2 -2
- package/src/tools/computer-use/request-computer-control.ts +21 -13
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/credentials/account-registry.ts +52 -35
- package/src/tools/credentials/broker-types.ts +1 -1
- package/src/tools/credentials/broker.ts +97 -55
- package/src/tools/credentials/domain-policy.ts +5 -2
- package/src/tools/credentials/host-pattern-match.ts +15 -8
- package/src/tools/credentials/metadata-store.ts +93 -43
- package/src/tools/credentials/policy-types.ts +5 -2
- package/src/tools/credentials/policy-validate.ts +21 -14
- package/src/tools/credentials/post-connect-hooks.ts +18 -7
- package/src/tools/credentials/resolve.ts +11 -10
- package/src/tools/credentials/selection.ts +30 -25
- package/src/tools/credentials/tool-policy.ts +5 -2
- package/src/tools/credentials/vault.ts +538 -185
- package/src/tools/document/document-tool.ts +23 -17
- package/src/tools/document/editor-template.ts +12 -7
- package/src/tools/execution-target.ts +13 -10
- package/src/tools/execution-timeout.ts +6 -5
- package/src/tools/executor.ts +141 -74
- package/src/tools/filesystem/edit.ts +82 -45
- package/src/tools/filesystem/fuzzy-match.ts +70 -32
- package/src/tools/filesystem/read.ts +46 -28
- package/src/tools/filesystem/view-image.ts +86 -42
- package/src/tools/filesystem/write.ts +53 -32
- package/src/tools/followups/followup_create.ts +43 -17
- package/src/tools/followups/followup_list.ts +28 -13
- package/src/tools/followups/followup_resolve.ts +9 -6
- package/src/tools/guardian-control-plane-policy.ts +15 -14
- package/src/tools/host-filesystem/edit.ts +77 -42
- package/src/tools/host-filesystem/read.ts +52 -33
- package/src/tools/host-filesystem/write.ts +50 -29
- package/src/tools/host-terminal/host-shell.ts +97 -61
- package/src/tools/mcp/mcp-tool-factory.ts +21 -14
- package/src/tools/memory/definitions.ts +60 -28
- package/src/tools/memory/handlers.ts +149 -77
- package/src/tools/memory/register.ts +39 -16
- package/src/tools/network/__tests__/web-search.test.ts +236 -177
- package/src/tools/network/domain-normalize.ts +13 -9
- package/src/tools/network/script-proxy/__tests__/logging.test.ts +193 -123
- package/src/tools/network/script-proxy/__tests__/policy.test.ts +225 -127
- package/src/tools/network/script-proxy/index.ts +1 -17
- package/src/tools/network/script-proxy/session-manager.ts +178 -86
- package/src/tools/network/url-safety.ts +56 -34
- package/src/tools/network/web-fetch.ts +273 -155
- package/src/tools/network/web-search.ts +166 -81
- package/src/tools/permission-checker.ts +24 -25
- package/src/tools/policy-context.ts +8 -5
- package/src/tools/registry.ts +73 -46
- package/src/tools/reminder/reminder-store.ts +65 -44
- package/src/tools/reminder/reminder.ts +76 -35
- package/src/tools/schedule/create.ts +44 -21
- package/src/tools/schedule/delete.ts +8 -5
- package/src/tools/schedule/list.ts +39 -19
- package/src/tools/schedule/update.ts +49 -26
- package/src/tools/secret-detection-handler.ts +130 -49
- package/src/tools/sensitive-output-placeholders.ts +15 -8
- package/src/tools/shared/filesystem/edit-engine.ts +45 -14
- package/src/tools/shared/filesystem/errors.ts +18 -18
- package/src/tools/shared/filesystem/file-ops-service.ts +59 -32
- package/src/tools/shared/filesystem/format-diff.ts +21 -11
- package/src/tools/shared/filesystem/path-policy.ts +17 -13
- package/src/tools/shared/filesystem/size-guard.ts +8 -4
- package/src/tools/shared/filesystem/types.ts +2 -2
- package/src/tools/shared/shell-output.ts +4 -3
- package/src/tools/side-effects.ts +36 -28
- package/src/tools/skills/delete-managed.ts +30 -17
- package/src/tools/skills/load.ts +88 -46
- package/src/tools/skills/sandbox-runner.ts +62 -46
- package/src/tools/skills/scaffold-managed.ts +98 -48
- package/src/tools/skills/script-contract.ts +5 -2
- package/src/tools/skills/skill-script-runner.ts +29 -13
- package/src/tools/skills/skill-tool-factory.ts +20 -10
- package/src/tools/subagent/abort.ts +10 -4
- package/src/tools/subagent/message.ts +14 -8
- package/src/tools/subagent/read.ts +20 -11
- package/src/tools/subagent/spawn.ts +14 -6
- package/src/tools/subagent/status.ts +7 -4
- package/src/tools/swarm/delegate.ts +75 -49
- package/src/tools/system/avatar-generator.ts +46 -33
- package/src/tools/system/navigate-settings.ts +29 -19
- package/src/tools/system/open-system-settings.ts +30 -20
- package/src/tools/system/request-permission.ts +59 -44
- package/src/tools/system/version.ts +27 -16
- package/src/tools/system/voice-config.ts +116 -53
- package/src/tools/tasks/index.ts +8 -8
- package/src/tools/tasks/task-delete.ts +61 -22
- package/src/tools/tasks/task-list.ts +23 -11
- package/src/tools/tasks/task-run.ts +41 -16
- package/src/tools/tasks/task-save.ts +27 -10
- package/src/tools/tasks/work-item-enqueue.ts +114 -48
- package/src/tools/tasks/work-item-list.ts +20 -10
- package/src/tools/tasks/work-item-remove.ts +49 -15
- package/src/tools/tasks/work-item-run.ts +34 -13
- package/src/tools/tasks/work-item-update.ts +84 -31
- package/src/tools/terminal/backends/native.ts +64 -35
- package/src/tools/terminal/backends/types.ts +6 -2
- package/src/tools/terminal/parser.ts +200 -125
- package/src/tools/terminal/safe-env.ts +27 -21
- package/src/tools/terminal/sandbox-diagnostics.ts +31 -13
- package/src/tools/terminal/sandbox.ts +10 -6
- package/src/tools/terminal/shell.ts +134 -68
- package/src/tools/tool-approval-handler.ts +239 -140
- package/src/tools/types.ts +79 -22
- package/src/tools/ui-surface/definitions.ts +124 -89
- package/src/tools/ui-surface/registry.ts +2 -2
- package/src/tools/watch/screen-watch.ts +50 -32
- package/src/tools/watch/watch-state.ts +41 -15
- package/src/tools/watcher/create.ts +37 -15
- package/src/tools/watcher/delete.ts +9 -6
- package/src/tools/watcher/digest.ts +10 -6
- package/src/tools/watcher/list.ts +37 -14
- package/src/tools/watcher/update.ts +33 -18
- package/src/tools/weather/service.ts +331 -174
- package/src/twitter/client.ts +261 -138
- package/src/twitter/oauth-client.ts +17 -13
- package/src/twitter/router.ts +51 -23
- package/src/twitter/session.ts +27 -18
- package/src/types/qrcode.d.ts +6 -3
- package/src/usage/actors.ts +16 -16
- package/src/usage/types.ts +3 -3
- package/src/util/bundled-asset.ts +10 -6
- package/src/util/canonicalize-identity.ts +11 -4
- package/src/util/clipboard.ts +7 -7
- package/src/util/content-id.ts +3 -3
- package/src/util/debounce.ts +3 -2
- package/src/util/diff.ts +55 -33
- package/src/util/errors.ts +31 -27
- package/src/util/fs.ts +8 -2
- package/src/util/log-redact.ts +12 -12
- package/src/util/logger.ts +112 -51
- package/src/util/network-info.ts +13 -5
- package/src/util/object.ts +4 -2
- package/src/util/phone.ts +4 -4
- package/src/util/platform.ts +80 -58
- package/src/util/pricing.ts +49 -31
- package/src/util/retry.ts +39 -7
- package/src/util/row-mapper.ts +7 -4
- package/src/util/silently.ts +7 -4
- package/src/util/spawn.ts +48 -0
- package/src/util/spinner.ts +9 -7
- package/src/util/time.ts +16 -3
- package/src/util/truncate.ts +1 -1
- package/src/util/voice-code.ts +6 -4
- package/src/util/xml.ts +5 -1
- package/src/version.ts +12 -8
- package/src/watcher/engine.ts +71 -44
- package/src/watcher/provider-registry.ts +1 -1
- package/src/watcher/providers/github.ts +40 -23
- package/src/watcher/providers/gmail.ts +59 -38
- package/src/watcher/providers/google-calendar.ts +62 -48
- package/src/watcher/providers/linear.ts +219 -150
- package/src/watcher/providers/slack.ts +125 -29
- package/src/watcher/watcher-store.ts +75 -55
- package/src/work-items/work-item-runner.ts +62 -29
- package/src/work-items/work-item-store.ts +137 -47
- package/src/workspace/commit-message-enrichment-service.ts +65 -25
- package/src/workspace/commit-message-provider.ts +14 -12
- package/src/workspace/git-service.ts +355 -239
- package/src/workspace/heartbeat-service.ts +74 -37
- package/src/workspace/provider-commit-message-generator.ts +95 -70
- package/src/workspace/top-level-renderer.ts +10 -8
- package/src/workspace/top-level-scanner.ts +9 -3
- package/src/workspace/turn-commit.ts +63 -36
- package/src/__tests__/ingress-member-store.test.ts +0 -294
- package/src/__tests__/script-proxy-router.test.ts +0 -215
- package/src/config/bundled-skills/trusted-contacts/SKILL.md +0 -372
- package/src/memory/guardian-bindings.ts +0 -158
- package/src/memory/ingress-member-store.ts +0 -352
- package/src/runtime/routes/ingress-routes.ts +0 -229
- package/src/tools/network/script-proxy/__tests__/router.test.ts +0 -77
- package/src/tools/network/script-proxy/certs.ts +0 -7
- package/src/tools/network/script-proxy/connect-tunnel.ts +0 -1
- package/src/tools/network/script-proxy/http-forwarder.ts +0 -2
- package/src/tools/network/script-proxy/logging.ts +0 -12
- package/src/tools/network/script-proxy/mitm-handler.ts +0 -2
- package/src/tools/network/script-proxy/policy.ts +0 -4
- package/src/tools/network/script-proxy/router.ts +0 -2
- package/src/tools/network/script-proxy/server.ts +0 -5
- package/src/tools/network/script-proxy/types.ts +0 -19
|
@@ -8,40 +8,53 @@
|
|
|
8
8
|
* barge-in, state machine, guardian verification).
|
|
9
9
|
*/
|
|
10
10
|
|
|
11
|
-
import { getGatewayInternalBaseUrl } from
|
|
12
|
-
import type { ServerMessage } from
|
|
13
|
-
import type {
|
|
11
|
+
import { getGatewayInternalBaseUrl } from "../config/env.js";
|
|
12
|
+
import type { ServerMessage } from "../daemon/ipc-contract.js";
|
|
13
|
+
import type { TrustContext } from "../daemon/session-runtime-assembly.js";
|
|
14
14
|
import {
|
|
15
15
|
expireCanonicalGuardianRequest,
|
|
16
16
|
getCanonicalRequestByPendingQuestionId,
|
|
17
17
|
getPendingCanonicalRequestByCallSessionId,
|
|
18
18
|
listCanonicalGuardianDeliveries,
|
|
19
|
-
} from
|
|
20
|
-
import { revokeScopedApprovalGrantsForContext } from
|
|
21
|
-
import { DAEMON_INTERNAL_ASSISTANT_ID } from
|
|
22
|
-
import { mintDaemonDeliveryToken } from
|
|
23
|
-
import { computeToolApprovalDigest } from
|
|
24
|
-
import { getLogger } from
|
|
25
|
-
import {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
19
|
+
} from "../memory/canonical-guardian-store.js";
|
|
20
|
+
import { revokeScopedApprovalGrantsForContext } from "../memory/scoped-approval-grants.js";
|
|
21
|
+
import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
|
|
22
|
+
import { mintDaemonDeliveryToken } from "../runtime/auth/token-service.js";
|
|
23
|
+
import { computeToolApprovalDigest } from "../security/tool-approval-digest.js";
|
|
24
|
+
import { getLogger } from "../util/logger.js";
|
|
25
|
+
import {
|
|
26
|
+
getMaxCallDurationMs,
|
|
27
|
+
getSilenceTimeoutMs,
|
|
28
|
+
getUserConsultationTimeoutMs,
|
|
29
|
+
} from "./call-constants.js";
|
|
30
|
+
import { persistCallCompletionMessage } from "./call-conversation-messages.js";
|
|
31
|
+
import { addPointerMessage, formatDuration } from "./call-pointer-messages.js";
|
|
32
|
+
import {
|
|
33
|
+
fireCallCompletionNotifier,
|
|
34
|
+
fireCallQuestionNotifier,
|
|
35
|
+
fireCallTranscriptNotifier,
|
|
36
|
+
registerCallController,
|
|
37
|
+
unregisterCallController,
|
|
38
|
+
} from "./call-state.js";
|
|
29
39
|
import {
|
|
30
40
|
createPendingQuestion,
|
|
31
41
|
expirePendingQuestions,
|
|
32
42
|
getCallSession,
|
|
33
43
|
recordCallEvent,
|
|
34
44
|
updateCallSession,
|
|
35
|
-
} from
|
|
36
|
-
import { sendGuardianExpiryNotices } from
|
|
37
|
-
import { dispatchGuardianQuestion } from
|
|
38
|
-
import type { RelayConnection } from
|
|
39
|
-
import type { PromptSpeakerContext } from
|
|
40
|
-
import {
|
|
45
|
+
} from "./call-store.js";
|
|
46
|
+
import { sendGuardianExpiryNotices } from "./guardian-action-sweep.js";
|
|
47
|
+
import { dispatchGuardianQuestion } from "./guardian-dispatch.js";
|
|
48
|
+
import type { RelayConnection } from "./relay-server.js";
|
|
49
|
+
import type { PromptSpeakerContext } from "./speaker-identification.js";
|
|
50
|
+
import {
|
|
51
|
+
startVoiceTurn,
|
|
52
|
+
type VoiceTurnHandle,
|
|
53
|
+
} from "./voice-session-bridge.js";
|
|
41
54
|
|
|
42
|
-
const log = getLogger(
|
|
55
|
+
const log = getLogger("call-controller");
|
|
43
56
|
|
|
44
|
-
type ControllerState =
|
|
57
|
+
type ControllerState = "idle" | "processing" | "speaking";
|
|
45
58
|
|
|
46
59
|
/**
|
|
47
60
|
* Tracks a pending guardian input request independently of the controller's
|
|
@@ -86,7 +99,7 @@ function extractBalancedJson(
|
|
|
86
99
|
|
|
87
100
|
const prefixIdx = prefixMatch.index;
|
|
88
101
|
const jsonStart = prefixIdx + prefixMatch[0].length;
|
|
89
|
-
if (jsonStart >= text.length || text[jsonStart] !==
|
|
102
|
+
if (jsonStart >= text.length || text[jsonStart] !== "{") return null;
|
|
90
103
|
|
|
91
104
|
let depth = 0;
|
|
92
105
|
let inString = false;
|
|
@@ -100,7 +113,7 @@ function extractBalancedJson(
|
|
|
100
113
|
continue;
|
|
101
114
|
}
|
|
102
115
|
|
|
103
|
-
if (ch ===
|
|
116
|
+
if (ch === "\\" && inString) {
|
|
104
117
|
escape = true;
|
|
105
118
|
continue;
|
|
106
119
|
}
|
|
@@ -112,9 +125,9 @@ function extractBalancedJson(
|
|
|
112
125
|
|
|
113
126
|
if (inString) continue;
|
|
114
127
|
|
|
115
|
-
if (ch ===
|
|
128
|
+
if (ch === "{") {
|
|
116
129
|
depth++;
|
|
117
|
-
} else if (ch ===
|
|
130
|
+
} else if (ch === "}") {
|
|
118
131
|
depth--;
|
|
119
132
|
if (depth === 0) {
|
|
120
133
|
const jsonEnd = i + 1;
|
|
@@ -129,7 +142,7 @@ function extractBalancedJson(
|
|
|
129
142
|
// Require the closing ']' to be present before considering this
|
|
130
143
|
// a complete match. If it hasn't arrived yet (streaming), return
|
|
131
144
|
// null so the caller keeps buffering.
|
|
132
|
-
if (bracketIdx >= text.length || text[bracketIdx] !==
|
|
145
|
+
if (bracketIdx >= text.length || text[bracketIdx] !== "]") {
|
|
133
146
|
return null;
|
|
134
147
|
}
|
|
135
148
|
const fullMatchEnd = bracketIdx + 1;
|
|
@@ -152,7 +165,9 @@ function stripGuardianApprovalMarkers(text: string): string {
|
|
|
152
165
|
for (;;) {
|
|
153
166
|
const match = extractBalancedJson(result);
|
|
154
167
|
if (!match) break;
|
|
155
|
-
result =
|
|
168
|
+
result =
|
|
169
|
+
result.slice(0, match.startIndex) +
|
|
170
|
+
result.slice(match.startIndex + match.fullMatch.length);
|
|
156
171
|
}
|
|
157
172
|
return result;
|
|
158
173
|
}
|
|
@@ -164,31 +179,32 @@ const CALL_OPENING_ACK_MARKER_REGEX = /\[CALL_OPENING_ACK\]/g;
|
|
|
164
179
|
const END_CALL_MARKER_REGEX = /\[END_CALL\]/g;
|
|
165
180
|
const GUARDIAN_TIMEOUT_MARKER_REGEX = /\[GUARDIAN_TIMEOUT\]/g;
|
|
166
181
|
const GUARDIAN_UNAVAILABLE_MARKER_REGEX = /\[GUARDIAN_UNAVAILABLE\]/g;
|
|
167
|
-
const CALL_OPENING_MARKER =
|
|
168
|
-
const CALL_OPENING_ACK_MARKER =
|
|
169
|
-
const END_CALL_MARKER =
|
|
182
|
+
const CALL_OPENING_MARKER = "[CALL_OPENING]";
|
|
183
|
+
const CALL_OPENING_ACK_MARKER = "[CALL_OPENING_ACK]";
|
|
184
|
+
const END_CALL_MARKER = "[END_CALL]";
|
|
170
185
|
|
|
171
186
|
function stripInternalSpeechMarkers(text: string): string {
|
|
172
187
|
let result = stripGuardianApprovalMarkers(text);
|
|
173
188
|
result = result
|
|
174
|
-
.replace(ASK_GUARDIAN_MARKER_REGEX,
|
|
175
|
-
.replace(USER_ANSWERED_MARKER_REGEX,
|
|
176
|
-
.replace(USER_INSTRUCTION_MARKER_REGEX,
|
|
177
|
-
.replace(CALL_OPENING_MARKER_REGEX,
|
|
178
|
-
.replace(CALL_OPENING_ACK_MARKER_REGEX,
|
|
179
|
-
.replace(END_CALL_MARKER_REGEX,
|
|
180
|
-
.replace(GUARDIAN_TIMEOUT_MARKER_REGEX,
|
|
181
|
-
.replace(GUARDIAN_UNAVAILABLE_MARKER_REGEX,
|
|
189
|
+
.replace(ASK_GUARDIAN_MARKER_REGEX, "")
|
|
190
|
+
.replace(USER_ANSWERED_MARKER_REGEX, "")
|
|
191
|
+
.replace(USER_INSTRUCTION_MARKER_REGEX, "")
|
|
192
|
+
.replace(CALL_OPENING_MARKER_REGEX, "")
|
|
193
|
+
.replace(CALL_OPENING_ACK_MARKER_REGEX, "")
|
|
194
|
+
.replace(END_CALL_MARKER_REGEX, "")
|
|
195
|
+
.replace(GUARDIAN_TIMEOUT_MARKER_REGEX, "")
|
|
196
|
+
.replace(GUARDIAN_UNAVAILABLE_MARKER_REGEX, "");
|
|
182
197
|
return result;
|
|
183
198
|
}
|
|
184
199
|
|
|
185
200
|
export class CallController {
|
|
186
201
|
private callSessionId: string;
|
|
187
202
|
private relay: RelayConnection;
|
|
188
|
-
private state: ControllerState =
|
|
203
|
+
private state: ControllerState = "idle";
|
|
189
204
|
private abortController: AbortController = new AbortController();
|
|
190
205
|
private currentTurnHandle: VoiceTurnHandle | null = null;
|
|
191
206
|
private currentTurnPromise: Promise<void> | null = null;
|
|
207
|
+
private destroyed = false;
|
|
192
208
|
private silenceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
193
209
|
private durationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
194
210
|
private durationWarningTimer: ReturnType<typeof setTimeout> | null = null;
|
|
@@ -216,7 +232,7 @@ export class CallController {
|
|
|
216
232
|
/** Assistant identity for scoping guardian bindings. */
|
|
217
233
|
private assistantId: string;
|
|
218
234
|
/** Guardian trust context for the current caller, when available. */
|
|
219
|
-
private
|
|
235
|
+
private trustContext: TrustContext | null;
|
|
220
236
|
/** Conversation ID for the voice session. */
|
|
221
237
|
private conversationId: string;
|
|
222
238
|
/**
|
|
@@ -241,7 +257,7 @@ export class CallController {
|
|
|
241
257
|
opts?: {
|
|
242
258
|
broadcast?: (msg: ServerMessage) => void;
|
|
243
259
|
assistantId?: string;
|
|
244
|
-
|
|
260
|
+
trustContext?: TrustContext;
|
|
245
261
|
},
|
|
246
262
|
) {
|
|
247
263
|
this.callSessionId = callSessionId;
|
|
@@ -250,7 +266,7 @@ export class CallController {
|
|
|
250
266
|
this.isInbound = !task;
|
|
251
267
|
this.broadcast = opts?.broadcast;
|
|
252
268
|
this.assistantId = opts?.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID;
|
|
253
|
-
this.
|
|
269
|
+
this.trustContext = opts?.trustContext ?? null;
|
|
254
270
|
|
|
255
271
|
// Resolve the conversation ID from the call session
|
|
256
272
|
const session = getCallSession(callSessionId);
|
|
@@ -280,8 +296,8 @@ export class CallController {
|
|
|
280
296
|
/**
|
|
281
297
|
* Update guardian trust context for subsequent LLM turns.
|
|
282
298
|
*/
|
|
283
|
-
|
|
284
|
-
this.
|
|
299
|
+
setTrustContext(ctx: TrustContext | null): void {
|
|
300
|
+
this.trustContext = ctx;
|
|
285
301
|
}
|
|
286
302
|
|
|
287
303
|
/**
|
|
@@ -304,7 +320,7 @@ export class CallController {
|
|
|
304
320
|
*/
|
|
305
321
|
async startInitialGreeting(): Promise<void> {
|
|
306
322
|
if (this.initialGreetingStarted) return;
|
|
307
|
-
if (this.state !==
|
|
323
|
+
if (this.state !== "idle") return;
|
|
308
324
|
|
|
309
325
|
this.initialGreetingStarted = true;
|
|
310
326
|
this.resetSilenceTimer();
|
|
@@ -317,12 +333,16 @@ export class CallController {
|
|
|
317
333
|
* Caller utterances always trigger normal turns, even when a guardian
|
|
318
334
|
* consultation is pending — the consultation is tracked separately.
|
|
319
335
|
*/
|
|
320
|
-
async handleCallerUtterance(
|
|
321
|
-
|
|
336
|
+
async handleCallerUtterance(
|
|
337
|
+
transcript: string,
|
|
338
|
+
speaker?: PromptSpeakerContext,
|
|
339
|
+
): Promise<void> {
|
|
340
|
+
const interruptedInFlight =
|
|
341
|
+
this.state === "processing" || this.state === "speaking";
|
|
322
342
|
// If we're already processing or speaking, abort the in-flight generation
|
|
323
343
|
if (interruptedInFlight) {
|
|
324
344
|
this.abortCurrentTurn();
|
|
325
|
-
this.llmRunVersion++;
|
|
345
|
+
this.llmRunVersion++; // Invalidate stale turn before awaiting teardown
|
|
326
346
|
}
|
|
327
347
|
|
|
328
348
|
// Always await any lingering turn promise, even if handleInterrupt() already ran
|
|
@@ -331,11 +351,11 @@ export class CallController {
|
|
|
331
351
|
this.currentTurnPromise = null;
|
|
332
352
|
await Promise.race([
|
|
333
353
|
teardownPromise.catch(() => {}),
|
|
334
|
-
new Promise<void>(resolve => setTimeout(resolve, 2000)),
|
|
354
|
+
new Promise<void>((resolve) => setTimeout(resolve, 2000)),
|
|
335
355
|
]);
|
|
336
356
|
}
|
|
337
357
|
|
|
338
|
-
this.state =
|
|
358
|
+
this.state = "processing";
|
|
339
359
|
this.resetSilenceTimer();
|
|
340
360
|
const callerContent = this.formatCallerUtterance(transcript, speaker);
|
|
341
361
|
const shouldMarkOpeningAck = this.awaitingOpeningAck;
|
|
@@ -363,7 +383,7 @@ export class CallController {
|
|
|
363
383
|
if (!this.pendingGuardianInput) {
|
|
364
384
|
log.warn(
|
|
365
385
|
{ callSessionId: this.callSessionId, state: this.state },
|
|
366
|
-
|
|
386
|
+
"handleUserAnswer called but no pending consultation exists",
|
|
367
387
|
);
|
|
368
388
|
return false;
|
|
369
389
|
}
|
|
@@ -372,7 +392,7 @@ export class CallController {
|
|
|
372
392
|
clearTimeout(this.pendingGuardianInput.timer);
|
|
373
393
|
this.pendingGuardianInput = null;
|
|
374
394
|
|
|
375
|
-
updateCallSession(this.callSessionId, { status:
|
|
395
|
+
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
376
396
|
|
|
377
397
|
// Inject the answer as a queued instruction so it merges into the
|
|
378
398
|
// next turn naturally, respecting role-alternation. If the controller
|
|
@@ -382,7 +402,7 @@ export class CallController {
|
|
|
382
402
|
// If the controller is idle, flush instructions immediately to
|
|
383
403
|
// deliver the answer. If processing/speaking, the answer will be
|
|
384
404
|
// delivered when the current turn completes via flushPendingInstructions.
|
|
385
|
-
if (this.state ===
|
|
405
|
+
if (this.state === "idle") {
|
|
386
406
|
this.flushPendingInstructions();
|
|
387
407
|
}
|
|
388
408
|
|
|
@@ -399,10 +419,12 @@ export class CallController {
|
|
|
399
419
|
* position once the current turn completes.
|
|
400
420
|
*/
|
|
401
421
|
async handleUserInstruction(instructionText: string): Promise<void> {
|
|
402
|
-
recordCallEvent(this.callSessionId,
|
|
422
|
+
recordCallEvent(this.callSessionId, "user_instruction_relayed", {
|
|
423
|
+
instruction: instructionText,
|
|
424
|
+
});
|
|
403
425
|
|
|
404
426
|
// Queue the instruction when it cannot be safely appended right now
|
|
405
|
-
if (this.state ===
|
|
427
|
+
if (this.state === "processing" || this.state === "speaking") {
|
|
406
428
|
this.pendingInstructions.push(`[USER_INSTRUCTION: ${instructionText}]`);
|
|
407
429
|
return;
|
|
408
430
|
}
|
|
@@ -418,15 +440,15 @@ export class CallController {
|
|
|
418
440
|
* Handle caller interrupting the assistant's speech.
|
|
419
441
|
*/
|
|
420
442
|
handleInterrupt(): void {
|
|
421
|
-
const wasSpeaking = this.state ===
|
|
443
|
+
const wasSpeaking = this.state === "speaking";
|
|
422
444
|
this.abortCurrentTurn();
|
|
423
445
|
this.llmRunVersion++;
|
|
424
446
|
// Explicitly terminate the in-progress TTS turn so the relay can
|
|
425
447
|
// immediately hand control back to the caller after barge-in.
|
|
426
448
|
if (wasSpeaking) {
|
|
427
|
-
this.relay.sendTextToken(
|
|
449
|
+
this.relay.sendTextToken("", true);
|
|
428
450
|
}
|
|
429
|
-
this.state =
|
|
451
|
+
this.state = "idle";
|
|
430
452
|
// Restart silence detection so a barge-in that never yields a
|
|
431
453
|
// follow-up utterance doesn't leave the call without a watchdog.
|
|
432
454
|
this.resetSilenceTimer();
|
|
@@ -436,11 +458,19 @@ export class CallController {
|
|
|
436
458
|
* Tear down all timers and abort any in-flight work.
|
|
437
459
|
*/
|
|
438
460
|
destroy(): void {
|
|
461
|
+
this.destroyed = true;
|
|
439
462
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
440
463
|
if (this.durationTimer) clearTimeout(this.durationTimer);
|
|
441
464
|
if (this.durationWarningTimer) clearTimeout(this.durationWarningTimer);
|
|
442
|
-
if (this.pendingGuardianInput) {
|
|
443
|
-
|
|
465
|
+
if (this.pendingGuardianInput) {
|
|
466
|
+
clearTimeout(this.pendingGuardianInput.timer);
|
|
467
|
+
this.pendingGuardianInput = null;
|
|
468
|
+
}
|
|
469
|
+
if (this.durationEndTimer) {
|
|
470
|
+
clearTimeout(this.durationEndTimer);
|
|
471
|
+
this.durationEndTimer = null;
|
|
472
|
+
}
|
|
473
|
+
this.pendingInstructions = [];
|
|
444
474
|
this.llmRunVersion++;
|
|
445
475
|
this.abortCurrentTurn();
|
|
446
476
|
this.currentTurnPromise = null;
|
|
@@ -451,16 +481,30 @@ export class CallController {
|
|
|
451
481
|
// guardian-approval-interception minting path sets callSessionId: null
|
|
452
482
|
// but always sets conversationId.
|
|
453
483
|
try {
|
|
454
|
-
let revoked = revokeScopedApprovalGrantsForContext({
|
|
455
|
-
|
|
484
|
+
let revoked = revokeScopedApprovalGrantsForContext({
|
|
485
|
+
callSessionId: this.callSessionId,
|
|
486
|
+
});
|
|
487
|
+
revoked += revokeScopedApprovalGrantsForContext({
|
|
488
|
+
conversationId: this.conversationId,
|
|
489
|
+
});
|
|
456
490
|
if (revoked > 0) {
|
|
457
|
-
log.info(
|
|
491
|
+
log.info(
|
|
492
|
+
{
|
|
493
|
+
callSessionId: this.callSessionId,
|
|
494
|
+
conversationId: this.conversationId,
|
|
495
|
+
revokedCount: revoked,
|
|
496
|
+
},
|
|
497
|
+
"Revoked scoped grants on call end",
|
|
498
|
+
);
|
|
458
499
|
}
|
|
459
500
|
} catch (err) {
|
|
460
|
-
log.warn(
|
|
501
|
+
log.warn(
|
|
502
|
+
{ err, callSessionId: this.callSessionId },
|
|
503
|
+
"Failed to revoke scoped grants on call end",
|
|
504
|
+
);
|
|
461
505
|
}
|
|
462
506
|
|
|
463
|
-
log.info({ callSessionId: this.callSessionId },
|
|
507
|
+
log.info({ callSessionId: this.callSessionId }, "CallController destroyed");
|
|
464
508
|
}
|
|
465
509
|
|
|
466
510
|
// ── Private ──────────────────────────────────────────────────────
|
|
@@ -478,11 +522,17 @@ export class CallController {
|
|
|
478
522
|
this.abortController = new AbortController();
|
|
479
523
|
}
|
|
480
524
|
|
|
481
|
-
private formatCallerUtterance(
|
|
525
|
+
private formatCallerUtterance(
|
|
526
|
+
transcript: string,
|
|
527
|
+
speaker?: PromptSpeakerContext,
|
|
528
|
+
): string {
|
|
482
529
|
if (!speaker) return transcript;
|
|
483
|
-
const safeId = speaker.speakerId.replaceAll('"', '
|
|
484
|
-
const safeLabel = speaker.speakerLabel.replaceAll('"', '
|
|
485
|
-
const confidencePart =
|
|
530
|
+
const safeId = speaker.speakerId.replaceAll('"', "'");
|
|
531
|
+
const safeLabel = speaker.speakerLabel.replaceAll('"', "'");
|
|
532
|
+
const confidencePart =
|
|
533
|
+
speaker.speakerConfidence != null
|
|
534
|
+
? ` confidence="${speaker.speakerConfidence.toFixed(2)}"`
|
|
535
|
+
: "";
|
|
486
536
|
return `[SPEAKER id="${safeId}" label="${safeLabel}" source="${speaker.source}"${confidencePart}] ${transcript}`;
|
|
487
537
|
}
|
|
488
538
|
|
|
@@ -497,6 +547,7 @@ export class CallController {
|
|
|
497
547
|
}
|
|
498
548
|
|
|
499
549
|
private async runTurnInner(content: string): Promise<void> {
|
|
550
|
+
if (this.destroyed) return;
|
|
500
551
|
const runVersion = ++this.llmRunVersion;
|
|
501
552
|
const runSignal = this.abortController.signal;
|
|
502
553
|
|
|
@@ -509,23 +560,23 @@ export class CallController {
|
|
|
509
560
|
}
|
|
510
561
|
|
|
511
562
|
try {
|
|
512
|
-
this.state =
|
|
563
|
+
this.state = "speaking";
|
|
513
564
|
|
|
514
565
|
// Buffer incoming tokens so we can strip control markers ([ASK_GUARDIAN:...], [END_CALL])
|
|
515
566
|
// before they reach TTS. We hold text whenever an unmatched '[' appears, since it
|
|
516
567
|
// could be the start of a control marker.
|
|
517
|
-
let ttsBuffer =
|
|
568
|
+
let ttsBuffer = "";
|
|
518
569
|
// Accumulate the full response text for post-turn marker detection
|
|
519
|
-
let fullResponseText =
|
|
570
|
+
let fullResponseText = "";
|
|
520
571
|
|
|
521
572
|
const flushSafeText = (): void => {
|
|
522
573
|
if (!this.isCurrentRun(runVersion)) return;
|
|
523
574
|
if (ttsBuffer.length === 0) return;
|
|
524
|
-
const bracketIdx = ttsBuffer.indexOf(
|
|
575
|
+
const bracketIdx = ttsBuffer.indexOf("[");
|
|
525
576
|
if (bracketIdx === -1) {
|
|
526
577
|
// No bracket at all — safe to flush everything
|
|
527
578
|
this.relay.sendTextToken(ttsBuffer, false);
|
|
528
|
-
ttsBuffer =
|
|
579
|
+
ttsBuffer = "";
|
|
529
580
|
} else {
|
|
530
581
|
// Flush everything before the bracket
|
|
531
582
|
if (bracketIdx > 0) {
|
|
@@ -538,36 +589,36 @@ export class CallController {
|
|
|
538
589
|
// bracketed text (e.g. "[A]", "[note]") doesn't stall TTS.
|
|
539
590
|
const afterBracket = ttsBuffer;
|
|
540
591
|
const couldBeControl =
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
afterBracket.startsWith(
|
|
551
|
-
afterBracket.startsWith(
|
|
552
|
-
afterBracket.startsWith(
|
|
553
|
-
afterBracket.startsWith(
|
|
554
|
-
afterBracket ===
|
|
555
|
-
afterBracket.startsWith(
|
|
556
|
-
afterBracket ===
|
|
557
|
-
afterBracket.startsWith(
|
|
558
|
-
afterBracket ===
|
|
559
|
-
afterBracket.startsWith(
|
|
560
|
-
afterBracket ===
|
|
561
|
-
afterBracket.startsWith(
|
|
562
|
-
afterBracket ===
|
|
563
|
-
afterBracket.startsWith(
|
|
592
|
+
"[ASK_GUARDIAN_APPROVAL:".startsWith(afterBracket) ||
|
|
593
|
+
"[ASK_GUARDIAN:".startsWith(afterBracket) ||
|
|
594
|
+
"[USER_ANSWERED:".startsWith(afterBracket) ||
|
|
595
|
+
"[USER_INSTRUCTION:".startsWith(afterBracket) ||
|
|
596
|
+
"[CALL_OPENING]".startsWith(afterBracket) ||
|
|
597
|
+
"[CALL_OPENING_ACK]".startsWith(afterBracket) ||
|
|
598
|
+
"[END_CALL]".startsWith(afterBracket) ||
|
|
599
|
+
"[GUARDIAN_TIMEOUT]".startsWith(afterBracket) ||
|
|
600
|
+
"[GUARDIAN_UNAVAILABLE]".startsWith(afterBracket) ||
|
|
601
|
+
afterBracket.startsWith("[ASK_GUARDIAN_APPROVAL:") ||
|
|
602
|
+
afterBracket.startsWith("[ASK_GUARDIAN:") ||
|
|
603
|
+
afterBracket.startsWith("[USER_ANSWERED:") ||
|
|
604
|
+
afterBracket.startsWith("[USER_INSTRUCTION:") ||
|
|
605
|
+
afterBracket === "[CALL_OPENING" ||
|
|
606
|
+
afterBracket.startsWith("[CALL_OPENING]") ||
|
|
607
|
+
afterBracket === "[CALL_OPENING_ACK" ||
|
|
608
|
+
afterBracket.startsWith("[CALL_OPENING_ACK]") ||
|
|
609
|
+
afterBracket === "[END_CALL" ||
|
|
610
|
+
afterBracket.startsWith("[END_CALL]") ||
|
|
611
|
+
afterBracket === "[GUARDIAN_TIMEOUT" ||
|
|
612
|
+
afterBracket.startsWith("[GUARDIAN_TIMEOUT]") ||
|
|
613
|
+
afterBracket === "[GUARDIAN_UNAVAILABLE" ||
|
|
614
|
+
afterBracket.startsWith("[GUARDIAN_UNAVAILABLE]");
|
|
564
615
|
|
|
565
616
|
if (!couldBeControl) {
|
|
566
617
|
// Not a control marker prefix — flush up to the next '[' (if any)
|
|
567
|
-
const nextBracket = ttsBuffer.indexOf(
|
|
618
|
+
const nextBracket = ttsBuffer.indexOf("[", 1);
|
|
568
619
|
if (nextBracket === -1) {
|
|
569
620
|
this.relay.sendTextToken(ttsBuffer, false);
|
|
570
|
-
ttsBuffer =
|
|
621
|
+
ttsBuffer = "";
|
|
571
622
|
} else {
|
|
572
623
|
this.relay.sendTextToken(ttsBuffer.slice(0, nextBracket), false);
|
|
573
624
|
ttsBuffer = ttsBuffer.slice(nextBracket);
|
|
@@ -601,30 +652,43 @@ export class CallController {
|
|
|
601
652
|
callSessionId: this.callSessionId,
|
|
602
653
|
content,
|
|
603
654
|
assistantId: this.assistantId,
|
|
604
|
-
|
|
655
|
+
trustContext: this.trustContext ?? undefined,
|
|
605
656
|
isInbound: this.isInbound,
|
|
606
657
|
task: this.task,
|
|
607
658
|
onTextDelta,
|
|
608
659
|
onComplete,
|
|
609
660
|
onError,
|
|
610
661
|
signal: runSignal,
|
|
611
|
-
})
|
|
612
|
-
|
|
613
|
-
this.
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
662
|
+
})
|
|
663
|
+
.then((handle) => {
|
|
664
|
+
if (this.isCurrentRun(runVersion)) {
|
|
665
|
+
this.currentTurnHandle = handle;
|
|
666
|
+
} else {
|
|
667
|
+
// Turn was superseded before handle arrived; abort immediately
|
|
668
|
+
handle.abort();
|
|
669
|
+
}
|
|
670
|
+
})
|
|
671
|
+
.catch((err) => {
|
|
672
|
+
reject(err);
|
|
673
|
+
});
|
|
621
674
|
|
|
622
675
|
// Defensive: if the turn is aborted (e.g. barge-in) and the event
|
|
623
676
|
// sink callbacks are never invoked, resolve the promise so it
|
|
624
677
|
// doesn't hang forever.
|
|
625
|
-
runSignal.addEventListener(
|
|
678
|
+
runSignal.addEventListener(
|
|
679
|
+
"abort",
|
|
680
|
+
() => {
|
|
681
|
+
resolve();
|
|
682
|
+
},
|
|
683
|
+
{ once: true },
|
|
684
|
+
);
|
|
626
685
|
});
|
|
627
686
|
|
|
687
|
+
// Eagerly mark the rejection as handled so runtimes (e.g. bun) don't
|
|
688
|
+
// flag it as an unhandled rejection when onError fires synchronously
|
|
689
|
+
// inside the Promise constructor before this await adds its handler.
|
|
690
|
+
// The await below still re-throws, caught by the outer try-catch.
|
|
691
|
+
turnComplete.catch(() => {});
|
|
628
692
|
await turnComplete;
|
|
629
693
|
if (!this.isCurrentRun(runVersion)) return;
|
|
630
694
|
|
|
@@ -635,7 +699,7 @@ export class CallController {
|
|
|
635
699
|
}
|
|
636
700
|
|
|
637
701
|
// Signal end of this turn's speech
|
|
638
|
-
this.relay.sendTextToken(
|
|
702
|
+
this.relay.sendTextToken("", true);
|
|
639
703
|
|
|
640
704
|
// Mark the greeting's first response as awaiting ack
|
|
641
705
|
if (this.lastSentWasOpener && fullResponseText.length > 0) {
|
|
@@ -646,12 +710,19 @@ export class CallController {
|
|
|
646
710
|
const responseText = fullResponseText;
|
|
647
711
|
|
|
648
712
|
// Record the assistant response event
|
|
649
|
-
recordCallEvent(this.callSessionId,
|
|
713
|
+
recordCallEvent(this.callSessionId, "assistant_spoke", {
|
|
714
|
+
text: responseText,
|
|
715
|
+
});
|
|
650
716
|
const spokenText = stripInternalSpeechMarkers(responseText).trim();
|
|
651
717
|
if (spokenText.length > 0) {
|
|
652
718
|
const session = getCallSession(this.callSessionId);
|
|
653
719
|
if (session) {
|
|
654
|
-
fireCallTranscriptNotifier(
|
|
720
|
+
fireCallTranscriptNotifier(
|
|
721
|
+
session.conversationId,
|
|
722
|
+
this.callSessionId,
|
|
723
|
+
"assistant",
|
|
724
|
+
spokenText,
|
|
725
|
+
);
|
|
655
726
|
}
|
|
656
727
|
}
|
|
657
728
|
|
|
@@ -660,16 +731,34 @@ export class CallController {
|
|
|
660
731
|
// `}]` inside JSON string values does not truncate the payload or
|
|
661
732
|
// leak partial JSON into TTS output.
|
|
662
733
|
const approvalMatch = extractBalancedJson(responseText);
|
|
663
|
-
let toolApprovalMeta: {
|
|
734
|
+
let toolApprovalMeta: {
|
|
735
|
+
question: string;
|
|
736
|
+
toolName: string;
|
|
737
|
+
inputDigest: string;
|
|
738
|
+
} | null = null;
|
|
664
739
|
if (approvalMatch) {
|
|
665
740
|
try {
|
|
666
|
-
const parsed = JSON.parse(approvalMatch.json) as {
|
|
741
|
+
const parsed = JSON.parse(approvalMatch.json) as {
|
|
742
|
+
question?: string;
|
|
743
|
+
toolName?: string;
|
|
744
|
+
input?: Record<string, unknown>;
|
|
745
|
+
};
|
|
667
746
|
if (parsed.question && parsed.toolName && parsed.input) {
|
|
668
|
-
const digest = computeToolApprovalDigest(
|
|
669
|
-
|
|
747
|
+
const digest = computeToolApprovalDigest(
|
|
748
|
+
parsed.toolName,
|
|
749
|
+
parsed.input,
|
|
750
|
+
);
|
|
751
|
+
toolApprovalMeta = {
|
|
752
|
+
question: parsed.question,
|
|
753
|
+
toolName: parsed.toolName,
|
|
754
|
+
inputDigest: digest,
|
|
755
|
+
};
|
|
670
756
|
}
|
|
671
757
|
} catch {
|
|
672
|
-
log.warn(
|
|
758
|
+
log.warn(
|
|
759
|
+
{ callSessionId: this.callSessionId },
|
|
760
|
+
"Failed to parse ASK_GUARDIAN_APPROVAL JSON payload",
|
|
761
|
+
);
|
|
673
762
|
}
|
|
674
763
|
}
|
|
675
764
|
|
|
@@ -677,29 +766,44 @@ export class CallController {
|
|
|
677
766
|
? null // structured approval takes precedence
|
|
678
767
|
: responseText.match(ASK_GUARDIAN_CAPTURE_REGEX);
|
|
679
768
|
|
|
680
|
-
const questionText =
|
|
769
|
+
const questionText =
|
|
770
|
+
toolApprovalMeta?.question ?? (askMatch ? askMatch[1] : null);
|
|
681
771
|
|
|
682
772
|
if (questionText) {
|
|
683
773
|
if (this.isCallerGuardian()) {
|
|
684
774
|
// Caller IS the guardian — don't dispatch cross-channel.
|
|
685
775
|
// Queue an instruction so the next turn asks them directly.
|
|
686
|
-
log.info(
|
|
687
|
-
|
|
776
|
+
log.info(
|
|
777
|
+
{ callSessionId: this.callSessionId },
|
|
778
|
+
"Caller is guardian — skipping ASK_GUARDIAN dispatch, asking directly",
|
|
779
|
+
);
|
|
780
|
+
this.pendingInstructions.push(
|
|
781
|
+
`You just tried to use [ASK_GUARDIAN] but the person on the phone IS your guardian. Ask them directly: "${questionText}"`,
|
|
782
|
+
);
|
|
688
783
|
// Fall through to normal turn completion (idle + flushPendingInstructions)
|
|
689
784
|
} else if (this.guardianUnavailableForCall) {
|
|
690
785
|
// Guardian already timed out earlier in this call — skip the full
|
|
691
786
|
// consultation wait and immediately tell the model to proceed
|
|
692
787
|
// without guardian input.
|
|
693
|
-
log.info(
|
|
694
|
-
|
|
788
|
+
log.info(
|
|
789
|
+
{ callSessionId: this.callSessionId },
|
|
790
|
+
"Guardian unavailable for call — skipping ASK_GUARDIAN wait",
|
|
791
|
+
);
|
|
792
|
+
recordCallEvent(this.callSessionId, "guardian_unavailable_skipped", {
|
|
793
|
+
question: questionText,
|
|
794
|
+
});
|
|
695
795
|
this.pendingInstructions.push(
|
|
696
|
-
`[GUARDIAN_UNAVAILABLE] You tried to consult your guardian again, but they were already unreachable earlier in this call. `
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
796
|
+
`[GUARDIAN_UNAVAILABLE] You tried to consult your guardian again, but they were already unreachable earlier in this call. ` +
|
|
797
|
+
`Do NOT use [ASK_GUARDIAN] again. Instead, let the caller know you cannot reach the guardian right now, ` +
|
|
798
|
+
`and continue the conversation by asking if there is anything else you can help with or if they would like a callback. ` +
|
|
799
|
+
`The unanswered question was: "${questionText}"`,
|
|
700
800
|
);
|
|
701
801
|
// Fall through to normal turn completion (idle + flushPendingInstructions)
|
|
702
|
-
} else if (
|
|
802
|
+
} else if (
|
|
803
|
+
this.pendingInstructions.some((instr) =>
|
|
804
|
+
instr.startsWith("[USER_ANSWERED:"),
|
|
805
|
+
)
|
|
806
|
+
) {
|
|
703
807
|
// A guardian answer arrived mid-turn and is queued in
|
|
704
808
|
// pendingInstructions but hasn't been flushed yet. The in-flight
|
|
705
809
|
// LLM response was generated without knowledge of this answer, so
|
|
@@ -707,16 +811,24 @@ export class CallController {
|
|
|
707
811
|
// desynchronize the flow. Skip this consultation — the answer will
|
|
708
812
|
// be flushed on the next turn, and if the model still needs to
|
|
709
813
|
// consult a guardian, it will emit another ASK_GUARDIAN then.
|
|
710
|
-
log.info(
|
|
711
|
-
|
|
814
|
+
log.info(
|
|
815
|
+
{ callSessionId: this.callSessionId },
|
|
816
|
+
"Deferring ASK_GUARDIAN — queued USER_ANSWERED pending",
|
|
817
|
+
);
|
|
818
|
+
recordCallEvent(this.callSessionId, "guardian_consult_deferred", {
|
|
819
|
+
question: questionText,
|
|
820
|
+
});
|
|
712
821
|
// Fall through to normal turn completion (idle + flushPendingInstructions)
|
|
713
822
|
} else {
|
|
714
823
|
// Determine the effective tool metadata for this ask. If the new
|
|
715
824
|
// ask has structured tool metadata, use it; otherwise inherit from
|
|
716
825
|
// the prior pending consultation (preserves tool scope on re-asks).
|
|
717
826
|
const effectiveToolMeta = toolApprovalMeta
|
|
718
|
-
? {
|
|
719
|
-
|
|
827
|
+
? {
|
|
828
|
+
toolName: toolApprovalMeta.toolName,
|
|
829
|
+
inputDigest: toolApprovalMeta.inputDigest,
|
|
830
|
+
}
|
|
831
|
+
: (this.pendingGuardianInput?.toolApprovalMeta ?? null);
|
|
720
832
|
|
|
721
833
|
// Coalesce repeated identical asks: if a consultation is already
|
|
722
834
|
// pending for the same tool/action (or same informational question),
|
|
@@ -724,18 +836,28 @@ export class CallController {
|
|
|
724
836
|
if (this.pendingGuardianInput) {
|
|
725
837
|
const isSameToolAction =
|
|
726
838
|
effectiveToolMeta && this.pendingGuardianInput.toolApprovalMeta
|
|
727
|
-
? effectiveToolMeta.toolName ===
|
|
728
|
-
|
|
729
|
-
|
|
839
|
+
? effectiveToolMeta.toolName ===
|
|
840
|
+
this.pendingGuardianInput.toolApprovalMeta.toolName &&
|
|
841
|
+
effectiveToolMeta.inputDigest ===
|
|
842
|
+
this.pendingGuardianInput.toolApprovalMeta.inputDigest
|
|
843
|
+
: !effectiveToolMeta &&
|
|
844
|
+
!this.pendingGuardianInput.toolApprovalMeta;
|
|
730
845
|
|
|
731
846
|
if (isSameToolAction) {
|
|
732
847
|
// Same tool/action — coalesce. Keep the existing consultation
|
|
733
848
|
// alive and skip creating a new request.
|
|
734
849
|
log.info(
|
|
735
|
-
{
|
|
736
|
-
|
|
850
|
+
{
|
|
851
|
+
callSessionId: this.callSessionId,
|
|
852
|
+
questionId: this.pendingGuardianInput.questionId,
|
|
853
|
+
},
|
|
854
|
+
"Coalescing repeated ASK_GUARDIAN — same tool/action already pending",
|
|
855
|
+
);
|
|
856
|
+
recordCallEvent(
|
|
857
|
+
this.callSessionId,
|
|
858
|
+
"guardian_consult_coalesced",
|
|
859
|
+
{ question: questionText },
|
|
737
860
|
);
|
|
738
|
-
recordCallEvent(this.callSessionId, 'guardian_consult_coalesced', { question: questionText });
|
|
739
861
|
// Fall through to normal turn completion (idle + flushPendingInstructions)
|
|
740
862
|
} else {
|
|
741
863
|
// Materially different intent — supersede the old consultation.
|
|
@@ -744,14 +866,19 @@ export class CallController {
|
|
|
744
866
|
// Expire the previous consultation's storage records so stale
|
|
745
867
|
// guardian answers cannot match the old request.
|
|
746
868
|
expirePendingQuestions(this.callSessionId);
|
|
747
|
-
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
869
|
+
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
870
|
+
this.callSessionId,
|
|
871
|
+
);
|
|
748
872
|
if (previousRequest) {
|
|
749
873
|
// Immediately expire with 'superseded' reason to prevent
|
|
750
874
|
// stale answers from resolving the old request.
|
|
751
875
|
expireCanonicalGuardianRequest(previousRequest.id);
|
|
752
876
|
log.info(
|
|
753
|
-
{
|
|
754
|
-
|
|
877
|
+
{
|
|
878
|
+
callSessionId: this.callSessionId,
|
|
879
|
+
requestId: previousRequest.id,
|
|
880
|
+
},
|
|
881
|
+
"Superseded guardian action request (materially different intent)",
|
|
755
882
|
);
|
|
756
883
|
}
|
|
757
884
|
|
|
@@ -761,7 +888,11 @@ export class CallController {
|
|
|
761
888
|
// The previous request ID is passed through so the dispatch
|
|
762
889
|
// can backfill supersession chain metadata (superseded_by_request_id)
|
|
763
890
|
// once the new request has been created.
|
|
764
|
-
this.dispatchNewConsultation(
|
|
891
|
+
this.dispatchNewConsultation(
|
|
892
|
+
questionText,
|
|
893
|
+
effectiveToolMeta,
|
|
894
|
+
previousRequest?.id ?? null,
|
|
895
|
+
);
|
|
765
896
|
}
|
|
766
897
|
} else {
|
|
767
898
|
// No prior consultation — dispatch fresh
|
|
@@ -785,7 +916,9 @@ export class CallController {
|
|
|
785
916
|
// a completed call with a dangling pendingQuestion, and guardian
|
|
786
917
|
// replies are cleanly rejected instead of hitting answerCall failures.
|
|
787
918
|
expirePendingQuestions(this.callSessionId);
|
|
788
|
-
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
919
|
+
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
920
|
+
this.callSessionId,
|
|
921
|
+
);
|
|
789
922
|
if (previousRequest) {
|
|
790
923
|
expireCanonicalGuardianRequest(previousRequest.id);
|
|
791
924
|
}
|
|
@@ -795,37 +928,70 @@ export class CallController {
|
|
|
795
928
|
|
|
796
929
|
const currentSession = getCallSession(this.callSessionId);
|
|
797
930
|
const shouldNotifyCompletion = currentSession
|
|
798
|
-
? currentSession.status !==
|
|
931
|
+
? currentSession.status !== "completed" &&
|
|
932
|
+
currentSession.status !== "failed" &&
|
|
933
|
+
currentSession.status !== "cancelled"
|
|
799
934
|
: false;
|
|
800
935
|
|
|
801
|
-
this.relay.endSession(
|
|
802
|
-
updateCallSession(this.callSessionId, {
|
|
803
|
-
|
|
936
|
+
this.relay.endSession("Call completed");
|
|
937
|
+
updateCallSession(this.callSessionId, {
|
|
938
|
+
status: "completed",
|
|
939
|
+
endedAt: Date.now(),
|
|
940
|
+
});
|
|
941
|
+
recordCallEvent(this.callSessionId, "call_ended", {
|
|
942
|
+
reason: "completed",
|
|
943
|
+
});
|
|
804
944
|
|
|
805
945
|
// Notify the voice conversation
|
|
806
946
|
if (shouldNotifyCompletion && currentSession) {
|
|
807
|
-
persistCallCompletionMessage(
|
|
808
|
-
|
|
947
|
+
persistCallCompletionMessage(
|
|
948
|
+
currentSession.conversationId,
|
|
949
|
+
this.callSessionId,
|
|
950
|
+
).catch((err) => {
|
|
951
|
+
log.error(
|
|
952
|
+
{
|
|
953
|
+
err,
|
|
954
|
+
conversationId: currentSession.conversationId,
|
|
955
|
+
callSessionId: this.callSessionId,
|
|
956
|
+
},
|
|
957
|
+
"Failed to persist call completion message",
|
|
958
|
+
);
|
|
809
959
|
});
|
|
810
|
-
fireCallCompletionNotifier(
|
|
960
|
+
fireCallCompletionNotifier(
|
|
961
|
+
currentSession.conversationId,
|
|
962
|
+
this.callSessionId,
|
|
963
|
+
);
|
|
811
964
|
}
|
|
812
965
|
|
|
813
966
|
// Post a pointer message in the initiating conversation
|
|
814
967
|
if (currentSession?.initiatedFromConversationId) {
|
|
815
|
-
const durationMs = currentSession.startedAt
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
968
|
+
const durationMs = currentSession.startedAt
|
|
969
|
+
? Date.now() - currentSession.startedAt
|
|
970
|
+
: 0;
|
|
971
|
+
addPointerMessage(
|
|
972
|
+
currentSession.initiatedFromConversationId,
|
|
973
|
+
"completed",
|
|
974
|
+
currentSession.toNumber,
|
|
975
|
+
{
|
|
976
|
+
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
977
|
+
},
|
|
978
|
+
).catch((err) => {
|
|
979
|
+
log.warn(
|
|
980
|
+
{
|
|
981
|
+
conversationId: currentSession.initiatedFromConversationId,
|
|
982
|
+
err,
|
|
983
|
+
},
|
|
984
|
+
"Skipping pointer write — origin conversation may no longer exist",
|
|
985
|
+
);
|
|
820
986
|
});
|
|
821
987
|
}
|
|
822
|
-
this.state =
|
|
988
|
+
this.state = "idle";
|
|
823
989
|
return;
|
|
824
990
|
}
|
|
825
991
|
|
|
826
992
|
// Normal turn complete — restart silence detection and flush any
|
|
827
993
|
// instructions that arrived while the LLM was active.
|
|
828
|
-
this.state =
|
|
994
|
+
this.state = "idle";
|
|
829
995
|
this.currentTurnHandle = null;
|
|
830
996
|
this.resetSilenceTimer();
|
|
831
997
|
this.flushPendingInstructions();
|
|
@@ -839,24 +1005,30 @@ export class CallController {
|
|
|
839
1005
|
errName: err instanceof Error ? err.name : typeof err,
|
|
840
1006
|
stale: !this.isCurrentRun(runVersion),
|
|
841
1007
|
},
|
|
842
|
-
|
|
1008
|
+
"Voice turn aborted",
|
|
843
1009
|
);
|
|
844
1010
|
if (this.isCurrentRun(runVersion)) {
|
|
845
|
-
this.state =
|
|
1011
|
+
this.state = "idle";
|
|
846
1012
|
this.resetSilenceTimer();
|
|
847
1013
|
}
|
|
848
1014
|
return;
|
|
849
1015
|
}
|
|
850
1016
|
if (!this.isCurrentRun(runVersion)) {
|
|
851
1017
|
log.debug(
|
|
852
|
-
{
|
|
853
|
-
|
|
1018
|
+
{
|
|
1019
|
+
callSessionId: this.callSessionId,
|
|
1020
|
+
errName: err instanceof Error ? err.name : typeof err,
|
|
1021
|
+
},
|
|
1022
|
+
"Ignoring stale voice turn error from superseded turn",
|
|
854
1023
|
);
|
|
855
1024
|
return;
|
|
856
1025
|
}
|
|
857
|
-
log.error({ err, callSessionId: this.callSessionId },
|
|
858
|
-
this.relay.sendTextToken(
|
|
859
|
-
|
|
1026
|
+
log.error({ err, callSessionId: this.callSessionId }, "Voice turn error");
|
|
1027
|
+
this.relay.sendTextToken(
|
|
1028
|
+
"I'm sorry, I encountered a technical issue. Could you repeat that?",
|
|
1029
|
+
true,
|
|
1030
|
+
);
|
|
1031
|
+
this.state = "idle";
|
|
860
1032
|
this.resetSilenceTimer();
|
|
861
1033
|
this.flushPendingInstructions();
|
|
862
1034
|
}
|
|
@@ -864,8 +1036,7 @@ export class CallController {
|
|
|
864
1036
|
|
|
865
1037
|
private isExpectedAbortError(err: unknown): boolean {
|
|
866
1038
|
if (!(err instanceof Error)) return false;
|
|
867
|
-
return err.name ===
|
|
868
|
-
|| err.name === 'APIUserAbortError';
|
|
1039
|
+
return err.name === "AbortError" || err.name === "APIUserAbortError";
|
|
869
1040
|
}
|
|
870
1041
|
|
|
871
1042
|
private isCurrentRun(runVersion: number): boolean {
|
|
@@ -873,7 +1044,7 @@ export class CallController {
|
|
|
873
1044
|
}
|
|
874
1045
|
|
|
875
1046
|
private isCallerGuardian(): boolean {
|
|
876
|
-
return this.
|
|
1047
|
+
return this.trustContext?.trustClass === "guardian";
|
|
877
1048
|
}
|
|
878
1049
|
|
|
879
1050
|
/**
|
|
@@ -888,14 +1059,23 @@ export class CallController {
|
|
|
888
1059
|
effectiveToolMeta: { toolName: string; inputDigest: string } | null,
|
|
889
1060
|
supersededRequestId: string | null,
|
|
890
1061
|
): void {
|
|
891
|
-
const pendingQuestion = createPendingQuestion(
|
|
892
|
-
|
|
893
|
-
|
|
1062
|
+
const pendingQuestion = createPendingQuestion(
|
|
1063
|
+
this.callSessionId,
|
|
1064
|
+
questionText,
|
|
1065
|
+
);
|
|
1066
|
+
updateCallSession(this.callSessionId, { status: "waiting_on_user" });
|
|
1067
|
+
recordCallEvent(this.callSessionId, "user_question_asked", {
|
|
1068
|
+
question: questionText,
|
|
1069
|
+
});
|
|
894
1070
|
|
|
895
1071
|
// Notify the conversation that a question was asked
|
|
896
1072
|
const session = getCallSession(this.callSessionId);
|
|
897
1073
|
if (session) {
|
|
898
|
-
fireCallQuestionNotifier(
|
|
1074
|
+
fireCallQuestionNotifier(
|
|
1075
|
+
session.conversationId,
|
|
1076
|
+
this.callSessionId,
|
|
1077
|
+
questionText,
|
|
1078
|
+
);
|
|
899
1079
|
|
|
900
1080
|
// Dispatch guardian action request to all configured channels
|
|
901
1081
|
// Capture the pending question ID in a closure for stable lookup
|
|
@@ -914,13 +1094,19 @@ export class CallController {
|
|
|
914
1094
|
// Backfill supersession chain: now that the new request exists in
|
|
915
1095
|
// the store, link the old request to the new one.
|
|
916
1096
|
if (supersededRequestId) {
|
|
917
|
-
const newRequest = getCanonicalRequestByPendingQuestionId(
|
|
1097
|
+
const newRequest = getCanonicalRequestByPendingQuestionId(
|
|
1098
|
+
stablePendingQuestionId,
|
|
1099
|
+
);
|
|
918
1100
|
if (newRequest) {
|
|
919
1101
|
// Canonical store does not track supersession metadata;
|
|
920
1102
|
// the old request was already expired above.
|
|
921
1103
|
log.info(
|
|
922
|
-
{
|
|
923
|
-
|
|
1104
|
+
{
|
|
1105
|
+
callSessionId: this.callSessionId,
|
|
1106
|
+
oldRequestId: supersededRequestId,
|
|
1107
|
+
newRequestId: newRequest.id,
|
|
1108
|
+
},
|
|
1109
|
+
"Supersession chain: new canonical request created",
|
|
924
1110
|
);
|
|
925
1111
|
}
|
|
926
1112
|
}
|
|
@@ -931,22 +1117,36 @@ export class CallController {
|
|
|
931
1117
|
// record, not the global controller state.
|
|
932
1118
|
const consultationTimer = setTimeout(() => {
|
|
933
1119
|
// Only fire if this consultation is still the active one
|
|
934
|
-
if (
|
|
1120
|
+
if (
|
|
1121
|
+
!this.pendingGuardianInput ||
|
|
1122
|
+
this.pendingGuardianInput.questionId !== pendingQuestion.id
|
|
1123
|
+
)
|
|
1124
|
+
return;
|
|
935
1125
|
|
|
936
|
-
log.info(
|
|
1126
|
+
log.info(
|
|
1127
|
+
{ callSessionId: this.callSessionId },
|
|
1128
|
+
"Guardian consultation timed out",
|
|
1129
|
+
);
|
|
937
1130
|
|
|
938
1131
|
// Mark the linked guardian action request as timed out and
|
|
939
1132
|
// send expiry notices to guardian destinations. Deliveries
|
|
940
1133
|
// must be captured before markTimedOutWithReason changes
|
|
941
1134
|
// their status.
|
|
942
|
-
const pendingActionRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1135
|
+
const pendingActionRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1136
|
+
this.callSessionId,
|
|
1137
|
+
);
|
|
943
1138
|
if (pendingActionRequest) {
|
|
944
|
-
const canonicalDeliveries = listCanonicalGuardianDeliveries(
|
|
1139
|
+
const canonicalDeliveries = listCanonicalGuardianDeliveries(
|
|
1140
|
+
pendingActionRequest.id,
|
|
1141
|
+
);
|
|
945
1142
|
// Expire the canonical request and its deliveries
|
|
946
1143
|
expireCanonicalGuardianRequest(pendingActionRequest.id);
|
|
947
1144
|
log.info(
|
|
948
|
-
{
|
|
949
|
-
|
|
1145
|
+
{
|
|
1146
|
+
callSessionId: this.callSessionId,
|
|
1147
|
+
requestId: pendingActionRequest.id,
|
|
1148
|
+
},
|
|
1149
|
+
"Marked canonical guardian request as timed out",
|
|
950
1150
|
);
|
|
951
1151
|
void sendGuardianExpiryNotices(
|
|
952
1152
|
canonicalDeliveries,
|
|
@@ -955,8 +1155,12 @@ export class CallController {
|
|
|
955
1155
|
() => mintDaemonDeliveryToken(),
|
|
956
1156
|
).catch((err) => {
|
|
957
1157
|
log.error(
|
|
958
|
-
{
|
|
959
|
-
|
|
1158
|
+
{
|
|
1159
|
+
err,
|
|
1160
|
+
callSessionId: this.callSessionId,
|
|
1161
|
+
requestId: pendingActionRequest.id,
|
|
1162
|
+
},
|
|
1163
|
+
"Failed to send guardian action expiry notices after call timeout",
|
|
960
1164
|
);
|
|
961
1165
|
});
|
|
962
1166
|
}
|
|
@@ -964,22 +1168,24 @@ export class CallController {
|
|
|
964
1168
|
// Expire pending questions and update call state
|
|
965
1169
|
expirePendingQuestions(this.callSessionId);
|
|
966
1170
|
this.pendingGuardianInput = null;
|
|
967
|
-
updateCallSession(this.callSessionId, { status:
|
|
1171
|
+
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
968
1172
|
this.guardianUnavailableForCall = true;
|
|
969
|
-
recordCallEvent(this.callSessionId,
|
|
1173
|
+
recordCallEvent(this.callSessionId, "guardian_consultation_timed_out", {
|
|
1174
|
+
question: questionText,
|
|
1175
|
+
});
|
|
970
1176
|
|
|
971
1177
|
// Inject timeout instruction so the model addresses it on the
|
|
972
1178
|
// next turn. If idle, flush immediately; otherwise it merges
|
|
973
1179
|
// into the next turn completion.
|
|
974
1180
|
const timeoutInstruction =
|
|
975
|
-
`[GUARDIAN_TIMEOUT] Your guardian did not respond in time to your question: "${questionText}". `
|
|
976
|
-
|
|
977
|
-
|
|
978
|
-
|
|
1181
|
+
`[GUARDIAN_TIMEOUT] Your guardian did not respond in time to your question: "${questionText}". ` +
|
|
1182
|
+
`Apologize to the caller for the delay, let them know you were unable to reach your guardian, ` +
|
|
1183
|
+
`ask if they would like to leave a message or receive a callback, ` +
|
|
1184
|
+
`and ask if there are any other questions you can help with right now.`;
|
|
979
1185
|
|
|
980
1186
|
this.pendingInstructions.push(timeoutInstruction);
|
|
981
1187
|
|
|
982
|
-
if (this.state ===
|
|
1188
|
+
if (this.state === "idle") {
|
|
983
1189
|
this.resetSilenceTimer();
|
|
984
1190
|
this.flushPendingInstructions();
|
|
985
1191
|
}
|
|
@@ -997,20 +1203,24 @@ export class CallController {
|
|
|
997
1203
|
* Drain any instructions that were queued while the LLM was active.
|
|
998
1204
|
*/
|
|
999
1205
|
private flushPendingInstructions(): void {
|
|
1206
|
+
if (this.destroyed) return;
|
|
1000
1207
|
if (this.pendingInstructions.length === 0) return;
|
|
1001
1208
|
|
|
1002
|
-
const parts = this.pendingInstructions.map(
|
|
1003
|
-
|
|
1209
|
+
const parts = this.pendingInstructions.map((instr) =>
|
|
1210
|
+
instr.startsWith("[") ? instr : `[USER_INSTRUCTION: ${instr}]`,
|
|
1004
1211
|
);
|
|
1005
1212
|
this.pendingInstructions = [];
|
|
1006
1213
|
|
|
1007
|
-
const content = parts.join(
|
|
1214
|
+
const content = parts.join("\n");
|
|
1008
1215
|
|
|
1009
1216
|
this.resetSilenceTimer();
|
|
1010
1217
|
|
|
1011
1218
|
// Fire-and-forget so we don't block the current turn's cleanup.
|
|
1012
1219
|
this.runTurn(content).catch((err) =>
|
|
1013
|
-
log.error(
|
|
1220
|
+
log.error(
|
|
1221
|
+
{ err, callSessionId: this.callSessionId },
|
|
1222
|
+
"runTurn failed after flushing queued instructions",
|
|
1223
|
+
),
|
|
1014
1224
|
);
|
|
1015
1225
|
}
|
|
1016
1226
|
|
|
@@ -1020,44 +1230,83 @@ export class CallController {
|
|
|
1020
1230
|
|
|
1021
1231
|
if (warningMs > 0) {
|
|
1022
1232
|
this.durationWarningTimer = setTimeout(() => {
|
|
1023
|
-
log.info(
|
|
1233
|
+
log.info(
|
|
1234
|
+
{ callSessionId: this.callSessionId },
|
|
1235
|
+
"Call duration warning",
|
|
1236
|
+
);
|
|
1024
1237
|
this.relay.sendTextToken(
|
|
1025
|
-
|
|
1238
|
+
"Just to let you know, we're running low on time for this call.",
|
|
1026
1239
|
true,
|
|
1027
1240
|
);
|
|
1028
1241
|
}, warningMs);
|
|
1029
1242
|
}
|
|
1030
1243
|
|
|
1031
1244
|
this.durationTimer = setTimeout(() => {
|
|
1032
|
-
log.info(
|
|
1245
|
+
log.info(
|
|
1246
|
+
{ callSessionId: this.callSessionId },
|
|
1247
|
+
"Call duration limit reached",
|
|
1248
|
+
);
|
|
1033
1249
|
this.relay.sendTextToken(
|
|
1034
|
-
|
|
1250
|
+
"I'm sorry, but we've reached the maximum time for this call. Thank you for your time. Goodbye!",
|
|
1035
1251
|
true,
|
|
1036
1252
|
);
|
|
1037
1253
|
// Give TTS a moment to play, then end
|
|
1038
1254
|
this.durationEndTimer = setTimeout(() => {
|
|
1039
1255
|
const currentSession = getCallSession(this.callSessionId);
|
|
1040
1256
|
const shouldNotifyCompletion = currentSession
|
|
1041
|
-
? currentSession.status !==
|
|
1257
|
+
? currentSession.status !== "completed" &&
|
|
1258
|
+
currentSession.status !== "failed" &&
|
|
1259
|
+
currentSession.status !== "cancelled"
|
|
1042
1260
|
: false;
|
|
1043
1261
|
|
|
1044
|
-
this.relay.endSession(
|
|
1045
|
-
updateCallSession(this.callSessionId, {
|
|
1046
|
-
|
|
1262
|
+
this.relay.endSession("Maximum call duration reached");
|
|
1263
|
+
updateCallSession(this.callSessionId, {
|
|
1264
|
+
status: "completed",
|
|
1265
|
+
endedAt: Date.now(),
|
|
1266
|
+
});
|
|
1267
|
+
recordCallEvent(this.callSessionId, "call_ended", {
|
|
1268
|
+
reason: "max_duration",
|
|
1269
|
+
});
|
|
1047
1270
|
if (shouldNotifyCompletion && currentSession) {
|
|
1048
|
-
persistCallCompletionMessage(
|
|
1049
|
-
|
|
1271
|
+
persistCallCompletionMessage(
|
|
1272
|
+
currentSession.conversationId,
|
|
1273
|
+
this.callSessionId,
|
|
1274
|
+
).catch((err) => {
|
|
1275
|
+
log.error(
|
|
1276
|
+
{
|
|
1277
|
+
err,
|
|
1278
|
+
conversationId: currentSession.conversationId,
|
|
1279
|
+
callSessionId: this.callSessionId,
|
|
1280
|
+
},
|
|
1281
|
+
"Failed to persist call completion message",
|
|
1282
|
+
);
|
|
1050
1283
|
});
|
|
1051
|
-
fireCallCompletionNotifier(
|
|
1284
|
+
fireCallCompletionNotifier(
|
|
1285
|
+
currentSession.conversationId,
|
|
1286
|
+
this.callSessionId,
|
|
1287
|
+
);
|
|
1052
1288
|
}
|
|
1053
1289
|
|
|
1054
1290
|
// Post a pointer message in the initiating conversation
|
|
1055
1291
|
if (currentSession?.initiatedFromConversationId) {
|
|
1056
|
-
const durationMs = currentSession.startedAt
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1292
|
+
const durationMs = currentSession.startedAt
|
|
1293
|
+
? Date.now() - currentSession.startedAt
|
|
1294
|
+
: 0;
|
|
1295
|
+
addPointerMessage(
|
|
1296
|
+
currentSession.initiatedFromConversationId,
|
|
1297
|
+
"completed",
|
|
1298
|
+
currentSession.toNumber,
|
|
1299
|
+
{
|
|
1300
|
+
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1301
|
+
},
|
|
1302
|
+
).catch((err) => {
|
|
1303
|
+
log.warn(
|
|
1304
|
+
{
|
|
1305
|
+
conversationId: currentSession.initiatedFromConversationId,
|
|
1306
|
+
err,
|
|
1307
|
+
},
|
|
1308
|
+
"Skipping pointer write — origin conversation may no longer exist",
|
|
1309
|
+
);
|
|
1061
1310
|
});
|
|
1062
1311
|
}
|
|
1063
1312
|
}, 3000);
|
|
@@ -1066,18 +1315,28 @@ export class CallController {
|
|
|
1066
1315
|
|
|
1067
1316
|
private resetSilenceTimer(): void {
|
|
1068
1317
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
1318
|
+
if (this.destroyed) return;
|
|
1069
1319
|
this.silenceTimer = setTimeout(() => {
|
|
1070
1320
|
// During guardian wait states, the relay heartbeat timer handles
|
|
1071
1321
|
// periodic updates — suppress the generic "Are you still there?"
|
|
1072
1322
|
// which is confusing when the caller is waiting on a decision.
|
|
1073
1323
|
// Two paths: in-call consultation (pendingGuardianInput) and
|
|
1074
1324
|
// inbound access-request wait (relay state).
|
|
1075
|
-
if (
|
|
1076
|
-
|
|
1325
|
+
if (
|
|
1326
|
+
this.pendingGuardianInput ||
|
|
1327
|
+
this.relay.getConnectionState() === "awaiting_guardian_decision"
|
|
1328
|
+
) {
|
|
1329
|
+
log.debug(
|
|
1330
|
+
{ callSessionId: this.callSessionId },
|
|
1331
|
+
"Silence timeout suppressed during guardian wait",
|
|
1332
|
+
);
|
|
1077
1333
|
return;
|
|
1078
1334
|
}
|
|
1079
|
-
log.info(
|
|
1080
|
-
|
|
1335
|
+
log.info(
|
|
1336
|
+
{ callSessionId: this.callSessionId },
|
|
1337
|
+
"Silence timeout triggered",
|
|
1338
|
+
);
|
|
1339
|
+
this.relay.sendTextToken("Are you still there?", true);
|
|
1081
1340
|
}, getSilenceTimeoutMs());
|
|
1082
1341
|
}
|
|
1083
1342
|
}
|