@vellumai/assistant 0.7.3 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +11 -0
- package/ARCHITECTURE.md +29 -28
- package/Dockerfile +6 -4
- package/README.md +2 -2
- package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
- package/bun.lock +3 -0
- package/docker-entrypoint.sh +16 -0
- package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
- package/eslint-rules/cli-no-daemon-internals.js +283 -0
- package/eslint.config.mjs +12 -0
- package/knip.json +3 -1
- package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
- package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
- package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
- package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
- package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
- package/openapi.yaml +4126 -959
- package/package.json +5 -1
- package/scripts/generate-openapi.ts +52 -4
- package/scripts/sync-llm-catalog.ts +165 -0
- package/scripts/sync-web-search-catalog.ts +107 -0
- package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
- package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
- package/src/__tests__/annotate-risk-options.test.ts +291 -0
- package/src/__tests__/anthropic-provider.test.ts +92 -2
- package/src/__tests__/app-control-flow.test.ts +7 -0
- package/src/__tests__/approval-cascade.test.ts +8 -16
- package/src/__tests__/approval-routes-http.test.ts +6 -0
- package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
- package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
- package/src/__tests__/avatar-identity-sync.test.ts +87 -0
- package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +1 -0
- package/src/__tests__/call-constants.test.ts +10 -1
- package/src/__tests__/call-controller.test.ts +127 -0
- package/src/__tests__/call-site-routing-provider.test.ts +172 -45
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
- package/src/__tests__/channel-policy.test.ts +12 -0
- package/src/__tests__/checker.test.ts +89 -0
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
- package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
- package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
- package/src/__tests__/config-loader-backfill.test.ts +526 -102
- package/src/__tests__/config-loader-corrupt.test.ts +68 -0
- package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
- package/src/__tests__/config-schema-cmd.test.ts +63 -29
- package/src/__tests__/config-schema.test.ts +14 -3
- package/src/__tests__/config-set-platform-guard.test.ts +75 -152
- package/src/__tests__/config-set-route.test.ts +198 -0
- package/src/__tests__/config-watcher.test.ts +6 -0
- package/src/__tests__/contacts-tools.test.ts +51 -199
- package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
- package/src/__tests__/context-search-agent-runner.test.ts +22 -138
- package/src/__tests__/context-search-conversations-source.test.ts +42 -16
- package/src/__tests__/context-search-fanout.test.ts +20 -157
- package/src/__tests__/context-search-memory-source.test.ts +3 -26
- package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
- package/src/__tests__/context-search-types.test.ts +7 -2
- package/src/__tests__/context-window-manager.test.ts +389 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
- package/src/__tests__/conversation-agent-loop.test.ts +3 -3
- package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
- package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
- package/src/__tests__/conversation-error.test.ts +38 -0
- package/src/__tests__/conversation-fork-crud.test.ts +241 -1
- package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
- package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
- package/src/__tests__/conversation-lifecycle.test.ts +124 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
- package/src/__tests__/conversation-process-callsite.test.ts +22 -7
- package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
- package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
- package/src/__tests__/conversation-slash-commands.test.ts +194 -2
- package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
- package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
- package/src/__tests__/credential-security-invariants.test.ts +5 -6
- package/src/__tests__/daemon-credential-client.test.ts +56 -1
- package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
- package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
- package/src/__tests__/db-proxy-transaction.test.ts +206 -0
- package/src/__tests__/external-plugin-loader.test.ts +458 -0
- package/src/__tests__/filing-service.test.ts +25 -22
- package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
- package/src/__tests__/gateway-only-guard.test.ts +0 -1
- package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
- package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
- package/src/__tests__/heartbeat-service.test.ts +50 -233
- package/src/__tests__/history-repair.test.ts +89 -0
- package/src/__tests__/host-app-control-proxy.test.ts +109 -1
- package/src/__tests__/host-app-control-routes.test.ts +247 -1
- package/src/__tests__/host-browser-proxy.test.ts +416 -20
- package/src/__tests__/host-browser-routes.test.ts +325 -33
- package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
- package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
- package/src/__tests__/inference-profile-reaper.test.ts +154 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
- package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
- package/src/__tests__/injector-chain.test.ts +24 -16
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
- package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
- package/src/__tests__/install-skill-routing.test.ts +2 -2
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
- package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
- package/src/__tests__/llm-catalog-parity.test.ts +146 -0
- package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
- package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
- package/src/__tests__/llm-resolver.test.ts +46 -0
- package/src/__tests__/managed-profile-guard.test.ts +131 -2
- package/src/__tests__/mcp-auth-routes.test.ts +1 -0
- package/src/__tests__/mcp-cli.test.ts +182 -220
- package/src/__tests__/mcp-health-check.test.ts +56 -27
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
- package/src/__tests__/message-complete-display-id.test.ts +175 -0
- package/src/__tests__/notification-decision-fallback.test.ts +91 -0
- package/src/__tests__/notification-decision-strategy.test.ts +22 -0
- package/src/__tests__/notification-platform-adapter.test.ts +229 -0
- package/src/__tests__/oauth-cli.test.ts +38 -1888
- package/src/__tests__/oauth-commands-routes.test.ts +711 -0
- package/src/__tests__/oauth-connect-routes.test.ts +174 -11
- package/src/__tests__/oauth-providers-routes.test.ts +14 -10
- package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
- package/src/__tests__/openai-responses-provider.test.ts +17 -0
- package/src/__tests__/plugin-bootstrap.test.ts +31 -2
- package/src/__tests__/plugin-route-contribution.test.ts +31 -3
- package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
- package/src/__tests__/plugin-types.test.ts +13 -11
- package/src/__tests__/process-message-background-slack.test.ts +46 -0
- package/src/__tests__/profile-entry-status.test.ts +43 -0
- package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
- package/src/__tests__/provider-registry-ollama.test.ts +12 -4
- package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
- package/src/__tests__/relay-server.test.ts +164 -2
- package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
- package/src/__tests__/schedule-retry.test.ts +56 -4
- package/src/__tests__/schedule-routes.test.ts +104 -0
- package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
- package/src/__tests__/scheduler-recurrence.test.ts +87 -34
- package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
- package/src/__tests__/scheduler-wake.test.ts +0 -63
- package/src/__tests__/secret-allowlist.test.ts +1 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
- package/src/__tests__/secret-response-routing.test.ts +7 -5
- package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
- package/src/__tests__/server-history-render.test.ts +82 -0
- package/src/__tests__/shell-credential-ref.test.ts +95 -3
- package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
- package/src/__tests__/skill-include-graph.test.ts +31 -0
- package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
- package/src/__tests__/skill-load-tool.test.ts +42 -16
- package/src/__tests__/skills.test.ts +39 -0
- package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
- package/src/__tests__/suggestion-routes.test.ts +3 -3
- package/src/__tests__/sync-message-contract.test.ts +63 -0
- package/src/__tests__/task-scheduler.test.ts +88 -23
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
- package/src/__tests__/tool-executor.test.ts +155 -0
- package/src/__tests__/update-bulletin-job.test.ts +96 -193
- package/src/__tests__/usage-cli.test.ts +11 -73
- package/src/__tests__/user-plugin-loader.test.ts +145 -0
- package/src/__tests__/vercel-config.test.ts +168 -0
- package/src/__tests__/voice-session-bridge.test.ts +3 -0
- package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
- package/src/__tests__/web-search.test.ts +303 -2
- package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
- package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
- package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
- package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
- package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
- package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
- package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
- package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
- package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
- package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
- package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
- package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
- package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
- package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
- package/src/acp/__tests__/helpers/which-stub.ts +4 -2
- package/src/acp/resolve-agent.test.ts +25 -0
- package/src/acp/resolve-agent.ts +13 -2
- package/src/acp/session-manager.ts +14 -0
- package/src/agent/loop.ts +11 -0
- package/src/approvals/guardian-decision-primitive.ts +0 -13
- package/src/approvals/guardian-request-resolvers.ts +19 -102
- package/src/calls/call-constants.ts +5 -8
- package/src/calls/call-controller.ts +130 -67
- package/src/calls/relay-server.ts +42 -1
- package/src/calls/relay-setup-router.ts +36 -0
- package/src/calls/types.ts +1 -0
- package/src/calls/voice-session-bridge.ts +24 -5
- package/src/channels/config.ts +14 -1
- package/src/channels/types.ts +1 -0
- package/src/cli/AGENTS.md +164 -4
- package/src/cli/__tests__/notifications.test.ts +54 -0
- package/src/cli/commands/__tests__/avatar.test.ts +540 -0
- package/src/cli/commands/__tests__/backup.test.ts +236 -776
- package/src/cli/commands/__tests__/cache.test.ts +1 -1
- package/src/cli/commands/__tests__/changelog.test.ts +593 -0
- package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
- package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
- package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
- package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
- package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
- package/src/cli/commands/__tests__/email-core.test.ts +579 -0
- package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
- package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
- package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
- package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
- package/src/cli/commands/__tests__/skills.test.ts +563 -0
- package/src/cli/commands/__tests__/status.test.ts +249 -0
- package/src/cli/commands/__tests__/stt.test.ts +320 -0
- package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
- package/src/cli/commands/__tests__/tts.test.ts +321 -0
- package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
- package/src/cli/commands/attachment.ts +8 -3
- package/src/cli/commands/audit.ts +95 -64
- package/src/cli/commands/auth.ts +61 -58
- package/src/cli/commands/avatar.ts +276 -390
- package/src/cli/commands/backup.ts +409 -505
- package/src/cli/commands/bash.ts +9 -5
- package/src/cli/commands/browser.ts +28 -9
- package/src/cli/commands/cache.ts +9 -4
- package/src/cli/commands/changelog.ts +414 -0
- package/src/cli/commands/channel-verification-sessions.ts +238 -317
- package/src/cli/commands/clients.ts +8 -3
- package/src/cli/commands/completions.ts +9 -9
- package/src/cli/commands/config.ts +102 -72
- package/src/cli/commands/contacts.ts +575 -696
- package/src/cli/commands/conversations-defer.ts +17 -69
- package/src/cli/commands/conversations-import.ts +90 -253
- package/src/cli/commands/conversations.ts +346 -436
- package/src/cli/commands/credential-execution.ts +9 -6
- package/src/cli/commands/credentials.ts +456 -736
- package/src/cli/commands/domain.ts +128 -206
- package/src/cli/commands/email.ts +606 -794
- package/src/cli/commands/gateway.ts +8 -1
- package/src/cli/commands/image-generation.ts +157 -205
- package/src/cli/commands/inference-providers.ts +352 -0
- package/src/cli/commands/inference-session.ts +415 -0
- package/src/cli/commands/inference.ts +87 -65
- package/src/cli/commands/keys.ts +8 -3
- package/src/cli/commands/mcp.ts +103 -287
- package/src/cli/commands/memory-v2.ts +163 -517
- package/src/cli/commands/notifications.ts +33 -7
- package/src/cli/commands/oauth/apps.ts +292 -261
- package/src/cli/commands/oauth/connect.ts +182 -345
- package/src/cli/commands/oauth/disconnect.ts +16 -215
- package/src/cli/commands/oauth/index.ts +49 -45
- package/src/cli/commands/oauth/mode.ts +43 -199
- package/src/cli/commands/oauth/ping.ts +17 -125
- package/src/cli/commands/oauth/providers.ts +732 -921
- package/src/cli/commands/oauth/request.ts +60 -350
- package/src/cli/commands/oauth/shared.ts +11 -121
- package/src/cli/commands/oauth/status.ts +31 -121
- package/src/cli/commands/oauth/token.ts +13 -55
- package/src/cli/commands/pending.ts +19 -10
- package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
- package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
- package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
- package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
- package/src/cli/commands/platform/connect.ts +16 -80
- package/src/cli/commands/platform/disconnect.ts +14 -112
- package/src/cli/commands/platform/index.ts +177 -246
- package/src/cli/commands/routes.ts +153 -336
- package/src/cli/commands/sequence.ts +316 -360
- package/src/cli/commands/skills.ts +449 -671
- package/src/cli/commands/status.ts +58 -37
- package/src/cli/commands/stt.ts +94 -262
- package/src/cli/commands/task.ts +14 -40
- package/src/cli/commands/trust.ts +8 -3
- package/src/cli/commands/tts.ts +162 -167
- package/src/cli/commands/ui.ts +35 -42
- package/src/cli/commands/usage.ts +188 -126
- package/src/cli/commands/watchers.ts +8 -3
- package/src/cli/commands/webhooks.ts +99 -193
- package/src/cli/lib/__tests__/register-command.test.ts +85 -0
- package/src/cli/lib/daemon-credential-client.ts +4 -5
- package/src/cli/lib/nested-value.ts +44 -0
- package/src/cli/lib/open-browser.ts +36 -0
- package/src/cli/lib/register-command.ts +19 -0
- package/src/cli/lib/time-ago.ts +34 -0
- package/src/cli/program.ts +2 -4
- package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
- package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
- package/src/cli/utils/conversation-id.ts +30 -0
- package/src/cli/utils/parse-duration.ts +41 -0
- package/src/config/acp-defaults.test.ts +5 -1
- package/src/config/acp-defaults.ts +11 -4
- package/src/config/bundled-skills/acp/TOOLS.json +2 -2
- package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
- package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
- package/src/config/bundled-skills/contacts/SKILL.md +12 -45
- package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
- package/src/config/bundled-tool-registry.ts +0 -2
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-resolver.ts +16 -1
- package/src/config/loader.ts +148 -33
- package/src/config/raw-config-utils.ts +2 -30
- package/src/config/schema.ts +4 -0
- package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
- package/src/config/schemas/call-site-catalog.ts +29 -7
- package/src/config/schemas/llm-request-logs.ts +57 -0
- package/src/config/schemas/llm.ts +52 -2
- package/src/config/schemas/memory-retrospective.ts +48 -0
- package/src/config/schemas/memory-v2.ts +33 -2
- package/src/config/schemas/memory.ts +4 -0
- package/src/config/schemas/services.ts +15 -12
- package/src/config/seed-inference-profiles.ts +195 -134
- package/src/contacts/contact-store.ts +0 -61
- package/src/context/window-manager.ts +191 -5
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
- package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
- package/src/daemon/approval-generators.ts +23 -29
- package/src/daemon/config-watcher.ts +2 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
- package/src/daemon/conversation-agent-loop.ts +140 -107
- package/src/daemon/conversation-error.ts +21 -0
- package/src/daemon/conversation-lifecycle.ts +68 -13
- package/src/daemon/conversation-process.ts +36 -19
- package/src/daemon/conversation-runtime-assembly.ts +14 -5
- package/src/daemon/conversation-slash.ts +175 -23
- package/src/daemon/conversation-store.ts +17 -10
- package/src/daemon/conversation-surfaces.ts +92 -26
- package/src/daemon/conversation-tool-setup.ts +33 -19
- package/src/daemon/conversation.ts +49 -10
- package/src/daemon/external-plugins-bootstrap.ts +18 -8
- package/src/daemon/guardian-action-generators.ts +7 -22
- package/src/daemon/handlers/config-model.ts +8 -126
- package/src/daemon/handlers/config-slack-channel.ts +10 -7
- package/src/daemon/handlers/config-vercel.ts +3 -1
- package/src/daemon/handlers/shared.ts +26 -0
- package/src/daemon/handlers/skills.ts +84 -5
- package/src/daemon/history-repair.ts +33 -6
- package/src/daemon/host-app-control-proxy.ts +44 -19
- package/src/daemon/host-bash-proxy.ts +85 -158
- package/src/daemon/host-browser-proxy.ts +97 -36
- package/src/daemon/host-cu-proxy.ts +1 -1
- package/src/daemon/host-file-proxy.ts +1 -1
- package/src/daemon/host-proxy-base.ts +13 -1
- package/src/daemon/host-proxy-preactivation.ts +25 -1
- package/src/daemon/host-transfer-proxy.ts +2 -2
- package/src/daemon/identity-helpers.ts +19 -0
- package/src/daemon/lifecycle.ts +128 -114
- package/src/daemon/meet-host-supervisor.ts +15 -15
- package/src/daemon/memory-v2-startup.ts +62 -14
- package/src/daemon/message-protocol.ts +6 -0
- package/src/daemon/message-types/bookmarks.ts +18 -0
- package/src/daemon/message-types/conversations.ts +12 -9
- package/src/daemon/message-types/messages.ts +28 -2
- package/src/daemon/message-types/sync.ts +60 -0
- package/src/daemon/pkb-reminder-builder.test.ts +54 -13
- package/src/daemon/pkb-reminder-builder.ts +21 -7
- package/src/daemon/process-message.ts +56 -23
- package/src/daemon/server.ts +23 -18
- package/src/daemon/shutdown-handlers.ts +0 -2
- package/src/daemon/tool-setup-types.ts +9 -0
- package/src/daemon/tool-side-effects.ts +6 -4
- package/src/daemon/wake-target-adapter.ts +11 -0
- package/src/documents/document-store.ts +35 -1
- package/src/export/transcript-formatter.ts +61 -2
- package/src/filing/filing-service.ts +42 -56
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
- package/src/heartbeat/heartbeat-run-store.ts +2 -1
- package/src/heartbeat/heartbeat-service.ts +149 -128
- package/src/home/__tests__/feed-types.test.ts +63 -131
- package/src/home/__tests__/feed-writer.test.ts +77 -278
- package/src/home/__tests__/post-connect-feed.test.ts +9 -12
- package/src/home/feed-types.ts +19 -73
- package/src/home/feed-writer.ts +25 -156
- package/src/home/post-connect-feed.ts +1 -3
- package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
- package/src/ipc/__tests__/email-ipc.test.ts +506 -0
- package/src/ipc/__tests__/exit-helper.test.ts +104 -0
- package/src/ipc/__tests__/streaming-client.test.ts +237 -0
- package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
- package/src/ipc/assistant-server.ts +148 -42
- package/src/ipc/cli-client.ts +370 -50
- package/src/ipc/routes/db-proxy-transaction.ts +151 -0
- package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
- package/src/ipc/skill-routes/events.ts +30 -3
- package/src/ipc/skill-server.ts +99 -42
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
- package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
- package/src/live-voice/live-voice-session-manager.ts +11 -4
- package/src/live-voice/live-voice-session.ts +14 -6
- package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
- package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
- package/src/memory/__tests__/conversation-types.test.ts +36 -0
- package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
- package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
- package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
- package/src/memory/bookmark-crud.ts +179 -0
- package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
- package/src/memory/context-search/agent-protocol.ts +5 -1
- package/src/memory/context-search/agent-runner.ts +60 -85
- package/src/memory/context-search/limits.ts +1 -4
- package/src/memory/context-search/search.ts +23 -113
- package/src/memory/context-search/sources/conversations.ts +18 -6
- package/src/memory/context-search/sources/memory-v2.ts +40 -31
- package/src/memory/context-search/sources/memory.ts +9 -2
- package/src/memory/context-search/sources/workspace.ts +13 -10
- package/src/memory/context-search/types.ts +1 -1
- package/src/memory/conversation-bootstrap.ts +11 -0
- package/src/memory/conversation-crud.ts +312 -10
- package/src/memory/conversation-queries.ts +9 -5
- package/src/memory/conversation-title-service.ts +1 -0
- package/src/memory/conversation-types.ts +16 -0
- package/src/memory/db-init.ts +14 -0
- package/src/memory/embedding-backend.ts +2 -1
- package/src/memory/embedding-runtime-manager.ts +1 -2
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
- package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
- package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
- package/src/memory/graph/conversation-graph-memory.ts +108 -14
- package/src/memory/graph/extraction.ts +4 -0
- package/src/memory/graph/graph-memory-state-store.ts +16 -3
- package/src/memory/graph/graph-search.test.ts +6 -5
- package/src/memory/graph/graph-search.ts +3 -4
- package/src/memory/graph/retriever.test.ts +12 -7
- package/src/memory/graph/retriever.ts +4 -5
- package/src/memory/graph/tool-handlers.ts +20 -11
- package/src/memory/graph/tools.ts +48 -9
- package/src/memory/indexer.ts +18 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
- package/src/memory/jobs/embed-concept-page.ts +261 -89
- package/src/memory/jobs-store.ts +51 -1
- package/src/memory/jobs-worker.ts +60 -7
- package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
- package/src/memory/llm-request-log-source-local.ts +26 -0
- package/src/memory/llm-request-log-source.ts +97 -0
- package/src/memory/llm-request-log-store.ts +1 -1
- package/src/memory/memory-retrospective-constants.ts +13 -0
- package/src/memory/memory-retrospective-enqueue.ts +114 -0
- package/src/memory/memory-retrospective-job.ts +351 -0
- package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
- package/src/memory/memory-retrospective-state.ts +162 -0
- package/src/memory/memory-retrospective-trigger-check.ts +91 -0
- package/src/memory/memory-v2-activation-log-store.ts +49 -5
- package/src/memory/memory-v2-concept-frequency.ts +4 -0
- package/src/memory/message-content.ts +38 -1
- package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
- package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
- package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
- package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
- package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
- package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
- package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
- package/src/memory/migrations/242-message-bookmarks.ts +38 -0
- package/src/memory/migrations/243-provider-connections.ts +68 -0
- package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
- package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
- package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
- package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
- package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
- package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
- package/src/memory/migrations/index.ts +7 -0
- package/src/memory/pkb/pkb-search.test.ts +6 -5
- package/src/memory/pkb/pkb-search.ts +4 -5
- package/src/memory/published-pages-store.ts +16 -0
- package/src/memory/qdrant-client.ts +3 -0
- package/src/memory/schema/bookmarks.ts +38 -0
- package/src/memory/schema/conversations.ts +2 -0
- package/src/memory/schema/index.ts +2 -0
- package/src/memory/schema/inference.ts +29 -0
- package/src/memory/schema/memory-core.ts +9 -0
- package/src/memory/search/semantic.ts +5 -9
- package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
- package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
- package/src/memory/v2/__tests__/activation.test.ts +46 -9
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
- package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
- package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
- package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
- package/src/memory/v2/__tests__/injection.test.ts +768 -33
- package/src/memory/v2/__tests__/migration.test.ts +7 -3
- package/src/memory/v2/__tests__/page-index.test.ts +277 -0
- package/src/memory/v2/__tests__/page-store.test.ts +14 -1
- package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
- package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
- package/src/memory/v2/__tests__/reranker.test.ts +4 -4
- package/src/memory/v2/__tests__/router.test.ts +516 -0
- package/src/memory/v2/__tests__/sim.test.ts +163 -8
- package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
- package/src/memory/v2/__tests__/static-context.test.ts +8 -35
- package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
- package/src/memory/v2/activation-store.ts +34 -5
- package/src/memory/v2/activation.ts +40 -27
- package/src/memory/v2/backfill-jobs.ts +17 -84
- package/src/memory/v2/consolidation-job.ts +92 -86
- package/src/memory/v2/frontmatter-sweep.ts +91 -0
- package/src/memory/v2/injection.ts +466 -115
- package/src/memory/v2/migration.ts +117 -20
- package/src/memory/v2/page-index.ts +191 -0
- package/src/memory/v2/page-store.ts +42 -0
- package/src/memory/v2/prompts/consolidation.ts +14 -7
- package/src/memory/v2/prompts/router.ts +192 -0
- package/src/memory/v2/qdrant.ts +307 -133
- package/src/memory/v2/reranker.ts +14 -7
- package/src/memory/v2/router.ts +322 -0
- package/src/memory/v2/sim.ts +88 -34
- package/src/memory/v2/skill-store.ts +118 -29
- package/src/memory/v2/static-context.ts +20 -17
- package/src/memory/v2/sweep-job.ts +127 -102
- package/src/memory/v2/types.ts +16 -5
- package/src/memory/validation.ts +13 -0
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
- package/src/notifications/__tests__/signal-registry.test.ts +17 -0
- package/src/notifications/adapters/platform.ts +171 -0
- package/src/notifications/conversation-pairing.ts +2 -2
- package/src/notifications/copy-composer.ts +61 -12
- package/src/notifications/decision-engine.ts +46 -0
- package/src/notifications/destination-resolver.ts +21 -0
- package/src/notifications/emit-signal.ts +28 -1
- package/src/notifications/home-feed-side-effect.ts +111 -0
- package/src/notifications/signal.ts +5 -0
- package/src/permissions/checker.ts +12 -0
- package/src/permissions/gateway-threshold-reader.ts +116 -8
- package/src/permissions/ipc-risk-types.ts +2 -0
- package/src/permissions/prompter.ts +86 -96
- package/src/permissions/secret-prompter.ts +31 -31
- package/src/plugin-api/index.ts +13 -0
- package/src/plugin-api/package.json +12 -0
- package/src/plugin-api/types.ts +62 -0
- package/src/plugins/defaults/injectors.ts +20 -5
- package/src/plugins/external-plugin-loader.ts +294 -0
- package/src/plugins/types.ts +46 -30
- package/src/plugins/user-loader.ts +64 -41
- package/src/proactive-artifact/job.test.ts +63 -8
- package/src/proactive-artifact/job.ts +20 -2
- package/src/proactive-artifact/message-copy.ts +18 -1
- package/src/proactive-artifact/trigger-state.test.ts +9 -0
- package/src/proactive-artifact/trigger-state.ts +4 -0
- package/src/prompts/__tests__/system-prompt.test.ts +105 -0
- package/src/prompts/system-prompt.ts +22 -1
- package/src/prompts/templates/SOUL.md +13 -28
- package/src/prompts/update-bulletin-job.ts +61 -73
- package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
- package/src/providers/__tests__/inference.test.ts +288 -0
- package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
- package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
- package/src/providers/__tests__/retry-callsite.test.ts +14 -32
- package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
- package/src/providers/anthropic/client.ts +95 -26
- package/src/providers/call-site-routing.ts +94 -16
- package/src/providers/connection-resolution.ts +163 -0
- package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
- package/src/providers/inference/adapter-factory.ts +173 -0
- package/src/providers/inference/auth.ts +112 -0
- package/src/providers/inference/backfill.ts +196 -0
- package/src/providers/inference/connections.ts +356 -0
- package/src/providers/inference/resolve-auth.ts +65 -0
- package/src/providers/model-catalog.ts +104 -6
- package/src/providers/openai/responses-provider.ts +4 -2
- package/src/providers/provider-env-vars.ts +17 -7
- package/src/providers/provider-secret-catalog.ts +49 -30
- package/src/providers/provider-send-message.ts +41 -20
- package/src/providers/registry.ts +143 -159
- package/src/providers/retry.ts +18 -10
- package/src/providers/search-provider-catalog.ts +121 -0
- package/src/runtime/AGENTS.md +18 -5
- package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
- package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
- package/src/runtime/actor-trust-resolver.ts +32 -10
- package/src/runtime/agent-wake.ts +35 -6
- package/src/runtime/assistant-event-hub.ts +3 -85
- package/src/runtime/auth/route-policy.ts +304 -8
- package/src/runtime/auth/same-actor.ts +2 -0
- package/src/runtime/background-job-runner.ts +339 -0
- package/src/runtime/btw-sidechain.ts +1 -0
- package/src/runtime/channel-approvals.ts +3 -2
- package/src/runtime/guardian-reply-router.ts +0 -10
- package/src/runtime/http-router.ts +36 -1
- package/src/runtime/http-server.ts +31 -5
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
- package/src/runtime/middleware/request-logger.ts +62 -1
- package/src/runtime/pending-interactions.ts +19 -15
- package/src/runtime/pre-first-message-gate.ts +83 -0
- package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
- package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
- package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
- package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
- package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
- package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
- package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
- package/src/runtime/routes/acp-routes.ts +10 -8
- package/src/runtime/routes/app-management-routes.ts +228 -3
- package/src/runtime/routes/approval-routes.ts +7 -21
- package/src/runtime/routes/audit-routes.ts +43 -0
- package/src/runtime/routes/auth-routes.ts +72 -0
- package/src/runtime/routes/avatar-routes.ts +273 -20
- package/src/runtime/routes/backup-routes.ts +406 -2
- package/src/runtime/routes/bookmark-routes.ts +154 -0
- package/src/runtime/routes/channel-verification-routes.ts +2 -1
- package/src/runtime/routes/consolidation-routes.ts +8 -9
- package/src/runtime/routes/contact-routes.ts +0 -160
- package/src/runtime/routes/conversation-cli-routes.ts +192 -0
- package/src/runtime/routes/conversation-management-routes.ts +30 -43
- package/src/runtime/routes/conversation-query-routes.ts +373 -82
- package/src/runtime/routes/conversation-routes.ts +31 -10
- package/src/runtime/routes/conversations-import-routes.ts +229 -0
- package/src/runtime/routes/credential-routes.ts +540 -0
- package/src/runtime/routes/debug-bash-routes.ts +2 -0
- package/src/runtime/routes/debug-routes.ts +2 -2
- package/src/runtime/routes/document-pdf-renderer.ts +5 -1
- package/src/runtime/routes/domain-routes.ts +167 -0
- package/src/runtime/routes/email-routes.ts +603 -0
- package/src/runtime/routes/errors.ts +2 -2
- package/src/runtime/routes/events-routes.ts +192 -0
- package/src/runtime/routes/filing-routes.ts +2 -3
- package/src/runtime/routes/home-feed-routes.ts +6 -78
- package/src/runtime/routes/host-app-control-routes.ts +44 -2
- package/src/runtime/routes/host-browser-routes.ts +103 -22
- package/src/runtime/routes/http-adapter.ts +2 -0
- package/src/runtime/routes/identity-routes.ts +5 -0
- package/src/runtime/routes/image-generation-routes.ts +99 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
- package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
- package/src/runtime/routes/index.ts +36 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
- package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
- package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
- package/src/runtime/routes/inference-send-routes.ts +115 -0
- package/src/runtime/routes/integrations/twilio.ts +1 -0
- package/src/runtime/routes/mcp-auth-routes.ts +283 -9
- package/src/runtime/routes/memory-item-routes.test.ts +3 -9
- package/src/runtime/routes/memory-item-routes.ts +5 -6
- package/src/runtime/routes/memory-v2-routes.ts +105 -404
- package/src/runtime/routes/notification-routes.ts +2 -0
- package/src/runtime/routes/oauth-apps.ts +112 -7
- package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
- package/src/runtime/routes/oauth-connect-routes.ts +67 -5
- package/src/runtime/routes/oauth-providers.ts +298 -8
- package/src/runtime/routes/platform-routes.ts +336 -0
- package/src/runtime/routes/playground/inject-failures.ts +2 -1
- package/src/runtime/routes/playground/reset-circuit.ts +2 -1
- package/src/runtime/routes/playground/state.ts +2 -1
- package/src/runtime/routes/publish-routes.ts +221 -0
- package/src/runtime/routes/schedule-routes.ts +82 -0
- package/src/runtime/routes/sequence-routes.ts +291 -0
- package/src/runtime/routes/settings-routes.ts +2 -10
- package/src/runtime/routes/skills-routes.ts +31 -1
- package/src/runtime/routes/stt-routes.ts +240 -3
- package/src/runtime/routes/surface-action-routes.ts +43 -7
- package/src/runtime/routes/tts-routes.ts +67 -0
- package/src/runtime/routes/types.ts +32 -0
- package/src/runtime/routes/user-routes-cli.ts +243 -0
- package/src/runtime/routes/webhook-routes.ts +165 -0
- package/src/runtime/sync/resource-sync-events.ts +25 -0
- package/src/runtime/sync/sync-publisher.test.ts +105 -0
- package/src/runtime/sync/sync-publisher.ts +21 -0
- package/src/schedule/scheduler.ts +200 -123
- package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
- package/src/security/secret-patterns.ts +3 -0
- package/src/sequence/engine.ts +38 -40
- package/src/skills/include-graph.ts +35 -13
- package/src/subagent/manager.ts +20 -15
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
- package/src/tools/browser/browser-execution.ts +15 -4
- package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
- package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
- package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
- package/src/tools/browser/cdp-client/factory.ts +66 -5
- package/src/tools/browser/runtime-check.ts +77 -0
- package/src/tools/document/document-tool.ts +20 -0
- package/src/tools/executor.ts +18 -2
- package/src/tools/memory/register.test.ts +10 -8
- package/src/tools/memory/register.ts +9 -1
- package/src/tools/network/__tests__/web-search.test.ts +156 -0
- package/src/tools/network/web-search.ts +280 -37
- package/src/tools/permission-checker.ts +28 -5
- package/src/tools/skills/load.ts +24 -20
- package/src/tools/subagent/spawn.ts +3 -3
- package/src/tools/terminal/shell.ts +44 -0
- package/src/tools/tool-name-aliases.ts +19 -0
- package/src/tools/types.ts +19 -1
- package/src/usage/attribution.ts +3 -2
- package/src/util/pricing.ts +86 -160
- package/src/watcher/__tests__/engine.test.ts +301 -0
- package/src/watcher/constants.ts +7 -0
- package/src/watcher/engine.ts +90 -90
- package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
- package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
- package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
- package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
- package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
- package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
- package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
- package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
- package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
- package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
- package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
- package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
- package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
- package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
- package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
- package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
- package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
- package/src/workspace/migrations/registry.ts +28 -0
- package/src/workspace/migrations/runner.ts +13 -2
- package/src/workspace/migrations/types.ts +13 -3
- package/src/workspace/provider-commit-message-generator.ts +3 -2
- package/src/__tests__/context-search-pkb-source.test.ts +0 -492
- package/src/__tests__/credentials-cli.test.ts +0 -1225
- package/src/__tests__/memory-admin-recall.test.ts +0 -213
- package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
- package/src/cli/commands/__tests__/email-download.test.ts +0 -260
- package/src/cli/commands/__tests__/email-list.test.ts +0 -216
- package/src/cli/commands/__tests__/email-register.test.ts +0 -186
- package/src/cli/commands/__tests__/email-send.test.ts +0 -416
- package/src/cli/commands/__tests__/email-status.test.ts +0 -185
- package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
- package/src/cli/commands/__tests__/routes.test.ts +0 -562
- package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
- package/src/cli/commands/autonomy.ts +0 -365
- package/src/cli/commands/memory.ts +0 -424
- package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
- package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
- package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
- package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
- package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
- package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
- package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
- package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
- package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
- package/src/cli/lib/daemon-avatar-client.ts +0 -37
- package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
- package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
- package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
- package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
- package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
- package/src/home/__tests__/emit-feed-event.test.ts +0 -169
- package/src/home/__tests__/feed-population-integration.test.ts +0 -312
- package/src/home/__tests__/feed-scheduler.test.ts +0 -222
- package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
- package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
- package/src/home/__tests__/rollup-producer.test.ts +0 -507
- package/src/home/assistant-feed-authoring.ts +0 -135
- package/src/home/emit-feed-event.ts +0 -169
- package/src/home/feed-scheduler.ts +0 -281
- package/src/home/platform-gmail-digest.ts +0 -163
- package/src/home/rewrite-command-preview.ts +0 -66
- package/src/home/rewrite-feed-title.ts +0 -58
- package/src/home/rollup-producer.ts +0 -426
- package/src/memory/admin.ts +0 -326
- package/src/memory/context-search/sources/pkb.ts +0 -477
- package/src/memory/graph/compaction.ts +0 -299
- /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
|
@@ -13,8 +13,8 @@
|
|
|
13
13
|
|
|
14
14
|
import { answerCall } from "../calls/call-domain.js";
|
|
15
15
|
import { findContactChannel } from "../contacts/contact-store.js";
|
|
16
|
+
import { upsertContactChannel } from "../contacts/contacts-write.js";
|
|
16
17
|
import { findConversation } from "../daemon/conversation-store.js";
|
|
17
|
-
import { emitFeedEvent } from "../home/emit-feed-event.js";
|
|
18
18
|
import {
|
|
19
19
|
type CanonicalGuardianRequest,
|
|
20
20
|
getCanonicalGuardianRequest,
|
|
@@ -192,28 +192,15 @@ const pendingInteractionResolver: GuardianRequestResolver = {
|
|
|
192
192
|
return { ok: false, reason: "pending_interaction_not_found" };
|
|
193
193
|
}
|
|
194
194
|
|
|
195
|
-
// Resolve the interaction: remove from tracker and get the session.
|
|
196
|
-
const resolved = pendingInteractions.resolve(request.id);
|
|
197
|
-
if (!resolved) {
|
|
198
|
-
// Race condition: interaction was consumed between get() and resolve().
|
|
199
|
-
log.warn(
|
|
200
|
-
{
|
|
201
|
-
event: "resolver_tool_approval_resolve_race",
|
|
202
|
-
requestId: request.id,
|
|
203
|
-
},
|
|
204
|
-
"Tool approval resolver: pending interaction consumed between lookup and resolve",
|
|
205
|
-
);
|
|
206
|
-
return { ok: false, reason: "pending_interaction_race" };
|
|
207
|
-
}
|
|
208
|
-
|
|
209
195
|
// Map action to the permission system's UserDecision type and notify session.
|
|
196
|
+
// resolveConfirmation() owns pendingInteractions deregistration.
|
|
210
197
|
const userDecision: UserDecision =
|
|
211
198
|
decision.action === "reject" ? "deny" : "allow";
|
|
212
|
-
const conversation = findConversation(
|
|
199
|
+
const conversation = findConversation(interaction.conversationId);
|
|
213
200
|
if (!conversation) {
|
|
214
201
|
return {
|
|
215
202
|
ok: false,
|
|
216
|
-
reason: `conversation_not_found: ${
|
|
203
|
+
reason: `conversation_not_found: ${interaction.conversationId}`,
|
|
217
204
|
};
|
|
218
205
|
}
|
|
219
206
|
conversation.handleConfirmationResponse(
|
|
@@ -225,21 +212,6 @@ const pendingInteractionResolver: GuardianRequestResolver = {
|
|
|
225
212
|
ctx.emissionContext,
|
|
226
213
|
);
|
|
227
214
|
|
|
228
|
-
const approved = decision.action !== "reject";
|
|
229
|
-
void emitFeedEvent({
|
|
230
|
-
source: "assistant",
|
|
231
|
-
title: approved ? "Tool Request Approved" : "Tool Request Denied",
|
|
232
|
-
summary: `${approved ? "Approved" : "Denied"} access to ${request.toolName ?? "unknown tool"}.`,
|
|
233
|
-
dedupKey: `guardian-approval:${request.id}`,
|
|
234
|
-
urgency: approved ? undefined : "medium",
|
|
235
|
-
detailPanel: { kind: "toolPermission" },
|
|
236
|
-
}).catch((err) => {
|
|
237
|
-
log.warn(
|
|
238
|
-
{ err, requestId: request.id },
|
|
239
|
-
"Failed to emit guardian approval feed event",
|
|
240
|
-
);
|
|
241
|
-
});
|
|
242
|
-
|
|
243
215
|
log.info(
|
|
244
216
|
{
|
|
245
217
|
event: "resolver_tool_approval_applied",
|
|
@@ -486,20 +458,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
486
458
|
}
|
|
487
459
|
}
|
|
488
460
|
|
|
489
|
-
void emitFeedEvent({
|
|
490
|
-
source: "assistant",
|
|
491
|
-
title: "Access Request Denied",
|
|
492
|
-
summary: `Denied access request.`,
|
|
493
|
-
dedupKey: `guardian-access:${request.id}`,
|
|
494
|
-
urgency: "medium",
|
|
495
|
-
detailPanel: { kind: "permissionChat" },
|
|
496
|
-
}).catch((err) => {
|
|
497
|
-
log.warn(
|
|
498
|
-
{ err, requestId: request.id },
|
|
499
|
-
"Failed to emit access request feed event",
|
|
500
|
-
);
|
|
501
|
-
});
|
|
502
|
-
|
|
503
461
|
return {
|
|
504
462
|
ok: true,
|
|
505
463
|
applied: true,
|
|
@@ -515,6 +473,21 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
515
473
|
// a verification session. The caller is already on the line and the
|
|
516
474
|
// relay server's in-call wait loop will detect the approved status.
|
|
517
475
|
if (channel === "phone") {
|
|
476
|
+
try {
|
|
477
|
+
upsertContactChannel({
|
|
478
|
+
sourceChannel: "phone",
|
|
479
|
+
externalUserId: requesterExternalUserId,
|
|
480
|
+
externalChatId: requesterChatId,
|
|
481
|
+
status: "active",
|
|
482
|
+
policy: "allow",
|
|
483
|
+
});
|
|
484
|
+
} catch (err) {
|
|
485
|
+
log.error(
|
|
486
|
+
{ err, requesterExternalUserId },
|
|
487
|
+
"Access request resolver: failed to activate voice caller as trusted contact",
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
|
|
518
491
|
log.info(
|
|
519
492
|
{
|
|
520
493
|
event: "resolver_access_request_voice_approved",
|
|
@@ -525,20 +498,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
525
498
|
"Access request resolver: voice approval — direct trusted-contact activation (no verification session)",
|
|
526
499
|
);
|
|
527
500
|
|
|
528
|
-
void emitFeedEvent({
|
|
529
|
-
source: "assistant",
|
|
530
|
-
title: "Access Request Approved",
|
|
531
|
-
summary: `Granted access request.`,
|
|
532
|
-
dedupKey: `guardian-access:${request.id}`,
|
|
533
|
-
urgency: undefined,
|
|
534
|
-
detailPanel: { kind: "permissionChat" },
|
|
535
|
-
}).catch((err) => {
|
|
536
|
-
log.warn(
|
|
537
|
-
{ err, requestId: request.id },
|
|
538
|
-
"Failed to emit access request feed event",
|
|
539
|
-
);
|
|
540
|
-
});
|
|
541
|
-
|
|
542
501
|
return {
|
|
543
502
|
ok: true,
|
|
544
503
|
applied: true,
|
|
@@ -766,20 +725,6 @@ const accessRequestResolver: GuardianRequestResolver = {
|
|
|
766
725
|
? `Access approved for ${requesterLabel}. Give them this verification code: \`${session.secret}\`. The code expires in 10 minutes.`
|
|
767
726
|
: `Access approved for ${requesterLabel}. Give them this verification code: \`${session.secret}\`. The code expires in 10 minutes. I could not notify them automatically, so please tell them to send the code manually.`;
|
|
768
727
|
|
|
769
|
-
void emitFeedEvent({
|
|
770
|
-
source: "assistant",
|
|
771
|
-
title: "Access Request Approved",
|
|
772
|
-
summary: `Granted access request.`,
|
|
773
|
-
dedupKey: `guardian-access:${request.id}`,
|
|
774
|
-
urgency: undefined,
|
|
775
|
-
detailPanel: { kind: "permissionChat" },
|
|
776
|
-
}).catch((err) => {
|
|
777
|
-
log.warn(
|
|
778
|
-
{ err, requestId: request.id },
|
|
779
|
-
"Failed to emit access request feed event",
|
|
780
|
-
);
|
|
781
|
-
});
|
|
782
|
-
|
|
783
728
|
return {
|
|
784
729
|
ok: true,
|
|
785
730
|
applied: true,
|
|
@@ -853,20 +798,6 @@ const toolGrantRequestResolver: GuardianRequestResolver = {
|
|
|
853
798
|
}
|
|
854
799
|
}
|
|
855
800
|
|
|
856
|
-
void emitFeedEvent({
|
|
857
|
-
source: "assistant",
|
|
858
|
-
title: "Tool Grant Denied",
|
|
859
|
-
summary: `Denied grant request for ${request.toolName ?? "unknown tool"}.`,
|
|
860
|
-
dedupKey: `guardian-grant:${request.id}`,
|
|
861
|
-
urgency: "medium",
|
|
862
|
-
detailPanel: { kind: "toolPermission" },
|
|
863
|
-
}).catch((err) => {
|
|
864
|
-
log.warn(
|
|
865
|
-
{ err, requestId: request.id },
|
|
866
|
-
"Failed to emit tool grant denial feed event",
|
|
867
|
-
);
|
|
868
|
-
});
|
|
869
|
-
|
|
870
801
|
return { ok: true, applied: true };
|
|
871
802
|
}
|
|
872
803
|
|
|
@@ -964,20 +895,6 @@ const toolGrantRequestResolver: GuardianRequestResolver = {
|
|
|
964
895
|
}
|
|
965
896
|
}
|
|
966
897
|
|
|
967
|
-
void emitFeedEvent({
|
|
968
|
-
source: "assistant",
|
|
969
|
-
title: "Tool Grant Approved",
|
|
970
|
-
summary: `Approved grant request for ${request.toolName ?? "unknown tool"}.`,
|
|
971
|
-
dedupKey: `guardian-grant:${request.id}`,
|
|
972
|
-
urgency: undefined,
|
|
973
|
-
detailPanel: { kind: "toolPermission" },
|
|
974
|
-
}).catch((err) => {
|
|
975
|
-
log.warn(
|
|
976
|
-
{ err, requestId: request.id },
|
|
977
|
-
"Failed to emit tool grant approval feed event",
|
|
978
|
-
);
|
|
979
|
-
});
|
|
980
|
-
|
|
981
898
|
return { ok: true, applied: true, grantMinted: false };
|
|
982
899
|
},
|
|
983
900
|
};
|
|
@@ -1,14 +1,7 @@
|
|
|
1
1
|
import { getConfig } from "../config/loader.js";
|
|
2
2
|
|
|
3
3
|
// Emergency/high-risk numbers that should never be called
|
|
4
|
-
const DENIED_NUMBERS = new Set([
|
|
5
|
-
"911",
|
|
6
|
-
"112",
|
|
7
|
-
"999",
|
|
8
|
-
"000",
|
|
9
|
-
"110",
|
|
10
|
-
"119",
|
|
11
|
-
]);
|
|
4
|
+
const DENIED_NUMBERS = new Set(["911", "112", "999", "000", "110", "119"]);
|
|
12
5
|
|
|
13
6
|
/**
|
|
14
7
|
* Check whether a phone number is a denied emergency number.
|
|
@@ -75,3 +68,7 @@ export function getGuardianWaitUpdateSteadyMaxIntervalMs(): number {
|
|
|
75
68
|
export function getSilenceTimeoutMs(): number {
|
|
76
69
|
return 30 * 1000; // 30 seconds
|
|
77
70
|
}
|
|
71
|
+
|
|
72
|
+
export function getEndCallListenWindowMs(): number {
|
|
73
|
+
return 15 * 1000;
|
|
74
|
+
}
|
|
@@ -26,6 +26,7 @@ import type { TtsProvider, TtsProviderId } from "../tts/types.js";
|
|
|
26
26
|
import { getLogger } from "../util/logger.js";
|
|
27
27
|
import { createStreamingEntry } from "./audio-store.js";
|
|
28
28
|
import {
|
|
29
|
+
getEndCallListenWindowMs,
|
|
29
30
|
getMaxCallDurationMs,
|
|
30
31
|
getSilenceTimeoutMs,
|
|
31
32
|
getUserConsultationTimeoutMs,
|
|
@@ -37,6 +38,7 @@ import {
|
|
|
37
38
|
registerCallController,
|
|
38
39
|
unregisterCallController,
|
|
39
40
|
} from "./call-state.js";
|
|
41
|
+
import { isTerminalState } from "./call-state-machine.js";
|
|
40
42
|
import {
|
|
41
43
|
createPendingQuestion,
|
|
42
44
|
expirePendingQuestions,
|
|
@@ -93,6 +95,7 @@ export class CallController {
|
|
|
93
95
|
private currentTurnPromise: Promise<void> | null = null;
|
|
94
96
|
private destroyed = false;
|
|
95
97
|
private silenceTimer: ReturnType<typeof setTimeout> | null = null;
|
|
98
|
+
private endCallListenTimer: ReturnType<typeof setTimeout> | null = null;
|
|
96
99
|
private durationTimer: ReturnType<typeof setTimeout> | null = null;
|
|
97
100
|
private durationWarningTimer: ReturnType<typeof setTimeout> | null = null;
|
|
98
101
|
/**
|
|
@@ -244,6 +247,8 @@ export class CallController {
|
|
|
244
247
|
transcript: string,
|
|
245
248
|
speaker?: PromptSpeakerContext,
|
|
246
249
|
): Promise<void> {
|
|
250
|
+
this.cancelPendingEndCall();
|
|
251
|
+
|
|
247
252
|
const interruptedInFlight =
|
|
248
253
|
this.state === "processing" || this.state === "speaking";
|
|
249
254
|
// If we're already processing or speaking, abort the in-flight generation
|
|
@@ -295,6 +300,8 @@ export class CallController {
|
|
|
295
300
|
return false;
|
|
296
301
|
}
|
|
297
302
|
|
|
303
|
+
this.cancelPendingEndCall();
|
|
304
|
+
|
|
298
305
|
// Clear the consultation timeout and record
|
|
299
306
|
clearTimeout(this.pendingGuardianInput.timer);
|
|
300
307
|
this.pendingGuardianInput = null;
|
|
@@ -326,6 +333,8 @@ export class CallController {
|
|
|
326
333
|
* position once the current turn completes.
|
|
327
334
|
*/
|
|
328
335
|
async handleUserInstruction(instructionText: string): Promise<void> {
|
|
336
|
+
this.cancelPendingEndCall();
|
|
337
|
+
|
|
329
338
|
recordCallEvent(this.callSessionId, "user_instruction_relayed", {
|
|
330
339
|
instruction: instructionText,
|
|
331
340
|
});
|
|
@@ -408,6 +417,7 @@ export class CallController {
|
|
|
408
417
|
destroy(): void {
|
|
409
418
|
this.destroyed = true;
|
|
410
419
|
if (this.silenceTimer) clearTimeout(this.silenceTimer);
|
|
420
|
+
if (this.endCallListenTimer) clearTimeout(this.endCallListenTimer);
|
|
411
421
|
if (this.durationTimer) clearTimeout(this.durationTimer);
|
|
412
422
|
if (this.durationWarningTimer) clearTimeout(this.durationWarningTimer);
|
|
413
423
|
if (this.pendingGuardianInput) {
|
|
@@ -419,6 +429,7 @@ export class CallController {
|
|
|
419
429
|
this.durationEndTimer = null;
|
|
420
430
|
}
|
|
421
431
|
this.pendingInstructions = [];
|
|
432
|
+
this.endCallListenTimer = null;
|
|
422
433
|
this.llmRunVersion++;
|
|
423
434
|
this.abortCurrentTurn();
|
|
424
435
|
if (this.activeSynthesisAbort) {
|
|
@@ -1075,73 +1086,7 @@ export class CallController {
|
|
|
1075
1086
|
|
|
1076
1087
|
// Check for END_CALL marker
|
|
1077
1088
|
if (responseText.includes(END_CALL_MARKER)) {
|
|
1078
|
-
|
|
1079
|
-
// Without this, the consultation timeout can fire on an already-ended
|
|
1080
|
-
// call, overwriting 'completed' status back to 'in_progress' and
|
|
1081
|
-
// starting a new LLM turn on a dead conversation. Similarly, a late
|
|
1082
|
-
// handleUserAnswer could be accepted since pendingGuardianInput is
|
|
1083
|
-
// still non-null.
|
|
1084
|
-
if (this.pendingGuardianInput) {
|
|
1085
|
-
clearTimeout(this.pendingGuardianInput.timer);
|
|
1086
|
-
|
|
1087
|
-
// Expire store-side consultation records so clients don't observe
|
|
1088
|
-
// a completed call with a dangling pendingQuestion, and guardian
|
|
1089
|
-
// replies are cleanly rejected instead of hitting answerCall failures.
|
|
1090
|
-
expirePendingQuestions(this.callSessionId);
|
|
1091
|
-
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1092
|
-
this.callSessionId,
|
|
1093
|
-
);
|
|
1094
|
-
if (previousRequest) {
|
|
1095
|
-
expireCanonicalGuardianRequest(previousRequest.id);
|
|
1096
|
-
}
|
|
1097
|
-
|
|
1098
|
-
this.pendingGuardianInput = null;
|
|
1099
|
-
}
|
|
1100
|
-
|
|
1101
|
-
const currentSession = getCallSession(this.callSessionId);
|
|
1102
|
-
const shouldNotifyCompletion = currentSession
|
|
1103
|
-
? currentSession.status !== "completed" &&
|
|
1104
|
-
currentSession.status !== "failed" &&
|
|
1105
|
-
currentSession.status !== "cancelled"
|
|
1106
|
-
: false;
|
|
1107
|
-
|
|
1108
|
-
this.transport.endSession("Call completed");
|
|
1109
|
-
updateCallSession(this.callSessionId, {
|
|
1110
|
-
status: "completed",
|
|
1111
|
-
endedAt: Date.now(),
|
|
1112
|
-
});
|
|
1113
|
-
recordCallEvent(this.callSessionId, "call_ended", {
|
|
1114
|
-
reason: "completed",
|
|
1115
|
-
});
|
|
1116
|
-
|
|
1117
|
-
// Notify the voice conversation
|
|
1118
|
-
if (shouldNotifyCompletion && currentSession) {
|
|
1119
|
-
finalizeCall(this.callSessionId, currentSession.conversationId);
|
|
1120
|
-
}
|
|
1121
|
-
|
|
1122
|
-
// Post a pointer message in the initiating conversation
|
|
1123
|
-
if (currentSession?.initiatedFromConversationId) {
|
|
1124
|
-
const durationMs = currentSession.startedAt
|
|
1125
|
-
? Date.now() - currentSession.startedAt
|
|
1126
|
-
: 0;
|
|
1127
|
-
addPointerMessage(
|
|
1128
|
-
currentSession.initiatedFromConversationId,
|
|
1129
|
-
"completed",
|
|
1130
|
-
currentSession.toNumber,
|
|
1131
|
-
{
|
|
1132
|
-
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1133
|
-
},
|
|
1134
|
-
).catch((err) => {
|
|
1135
|
-
log.warn(
|
|
1136
|
-
{
|
|
1137
|
-
conversationId: currentSession.initiatedFromConversationId,
|
|
1138
|
-
err,
|
|
1139
|
-
},
|
|
1140
|
-
"Skipping pointer write — origin conversation may no longer exist",
|
|
1141
|
-
);
|
|
1142
|
-
});
|
|
1143
|
-
}
|
|
1144
|
-
this.state = "idle";
|
|
1089
|
+
this.scheduleEndCallAfterListenWindow();
|
|
1145
1090
|
return;
|
|
1146
1091
|
}
|
|
1147
1092
|
|
|
@@ -1153,6 +1098,124 @@ export class CallController {
|
|
|
1153
1098
|
this.flushPendingInstructions();
|
|
1154
1099
|
}
|
|
1155
1100
|
|
|
1101
|
+
private scheduleEndCallAfterListenWindow(): void {
|
|
1102
|
+
const currentSession = getCallSession(this.callSessionId);
|
|
1103
|
+
if (currentSession && isTerminalState(currentSession.status)) {
|
|
1104
|
+
this.state = "idle";
|
|
1105
|
+
this.currentTurnHandle = null;
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
|
|
1109
|
+
const clearedPendingGuardianInput =
|
|
1110
|
+
this.clearPendingGuardianInputForCallEnd();
|
|
1111
|
+
this.state = "idle";
|
|
1112
|
+
this.currentTurnHandle = null;
|
|
1113
|
+
|
|
1114
|
+
if (this.endCallListenTimer) {
|
|
1115
|
+
clearTimeout(this.endCallListenTimer);
|
|
1116
|
+
this.endCallListenTimer = null;
|
|
1117
|
+
}
|
|
1118
|
+
|
|
1119
|
+
const listenWindowMs = getEndCallListenWindowMs();
|
|
1120
|
+
const callContinues =
|
|
1121
|
+
this.pendingInstructions.length > 0 || listenWindowMs > 0;
|
|
1122
|
+
if (clearedPendingGuardianInput && callContinues) {
|
|
1123
|
+
updateCallSession(this.callSessionId, { status: "in_progress" });
|
|
1124
|
+
}
|
|
1125
|
+
|
|
1126
|
+
if (this.pendingInstructions.length > 0) {
|
|
1127
|
+
this.flushPendingInstructions();
|
|
1128
|
+
return;
|
|
1129
|
+
}
|
|
1130
|
+
|
|
1131
|
+
if (listenWindowMs <= 0) {
|
|
1132
|
+
this.completeCallFromEndMarker();
|
|
1133
|
+
return;
|
|
1134
|
+
}
|
|
1135
|
+
|
|
1136
|
+
this.resetSilenceTimer();
|
|
1137
|
+
this.endCallListenTimer = setTimeout(() => {
|
|
1138
|
+
this.endCallListenTimer = null;
|
|
1139
|
+
this.completeCallFromEndMarker();
|
|
1140
|
+
}, listenWindowMs);
|
|
1141
|
+
}
|
|
1142
|
+
|
|
1143
|
+
private cancelPendingEndCall(): void {
|
|
1144
|
+
if (!this.endCallListenTimer) return;
|
|
1145
|
+
clearTimeout(this.endCallListenTimer);
|
|
1146
|
+
this.endCallListenTimer = null;
|
|
1147
|
+
}
|
|
1148
|
+
|
|
1149
|
+
private clearPendingGuardianInputForCallEnd(): boolean {
|
|
1150
|
+
if (!this.pendingGuardianInput) return false;
|
|
1151
|
+
|
|
1152
|
+
clearTimeout(this.pendingGuardianInput.timer);
|
|
1153
|
+
|
|
1154
|
+
// Expire store-side consultation records so clients don't observe
|
|
1155
|
+
// a completed call with a dangling pendingQuestion, and guardian
|
|
1156
|
+
// replies are cleanly rejected instead of hitting answerCall failures.
|
|
1157
|
+
expirePendingQuestions(this.callSessionId);
|
|
1158
|
+
const previousRequest = getPendingCanonicalRequestByCallSessionId(
|
|
1159
|
+
this.callSessionId,
|
|
1160
|
+
);
|
|
1161
|
+
if (previousRequest) {
|
|
1162
|
+
expireCanonicalGuardianRequest(previousRequest.id);
|
|
1163
|
+
}
|
|
1164
|
+
|
|
1165
|
+
this.pendingGuardianInput = null;
|
|
1166
|
+
return true;
|
|
1167
|
+
}
|
|
1168
|
+
|
|
1169
|
+
private completeCallFromEndMarker(): void {
|
|
1170
|
+
if (this.destroyed) return;
|
|
1171
|
+
|
|
1172
|
+
const currentSession = getCallSession(this.callSessionId);
|
|
1173
|
+
if (currentSession && isTerminalState(currentSession.status)) {
|
|
1174
|
+
this.state = "idle";
|
|
1175
|
+
return;
|
|
1176
|
+
}
|
|
1177
|
+
|
|
1178
|
+
const shouldNotifyCompletion = !!currentSession;
|
|
1179
|
+
|
|
1180
|
+
this.transport.endSession("Call completed");
|
|
1181
|
+
updateCallSession(this.callSessionId, {
|
|
1182
|
+
status: "completed",
|
|
1183
|
+
endedAt: Date.now(),
|
|
1184
|
+
});
|
|
1185
|
+
recordCallEvent(this.callSessionId, "call_ended", {
|
|
1186
|
+
reason: "completed",
|
|
1187
|
+
});
|
|
1188
|
+
|
|
1189
|
+
// Notify the voice conversation
|
|
1190
|
+
if (shouldNotifyCompletion && currentSession) {
|
|
1191
|
+
finalizeCall(this.callSessionId, currentSession.conversationId);
|
|
1192
|
+
}
|
|
1193
|
+
|
|
1194
|
+
// Post a pointer message in the initiating conversation
|
|
1195
|
+
if (currentSession?.initiatedFromConversationId) {
|
|
1196
|
+
const durationMs = currentSession.startedAt
|
|
1197
|
+
? Date.now() - currentSession.startedAt
|
|
1198
|
+
: 0;
|
|
1199
|
+
addPointerMessage(
|
|
1200
|
+
currentSession.initiatedFromConversationId,
|
|
1201
|
+
"completed",
|
|
1202
|
+
currentSession.toNumber,
|
|
1203
|
+
{
|
|
1204
|
+
duration: durationMs > 0 ? formatDuration(durationMs) : undefined,
|
|
1205
|
+
},
|
|
1206
|
+
).catch((err) => {
|
|
1207
|
+
log.warn(
|
|
1208
|
+
{
|
|
1209
|
+
conversationId: currentSession.initiatedFromConversationId,
|
|
1210
|
+
err,
|
|
1211
|
+
},
|
|
1212
|
+
"Skipping pointer write — origin conversation may no longer exist",
|
|
1213
|
+
);
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
this.state = "idle";
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1156
1219
|
private isExpectedAbortError(err: unknown): boolean {
|
|
1157
1220
|
if (!(err instanceof Error)) return false;
|
|
1158
1221
|
return err.name === "AbortError" || err.name === "APIUserAbortError";
|
|
@@ -66,6 +66,8 @@ import {
|
|
|
66
66
|
} from "./speaker-identification.js";
|
|
67
67
|
|
|
68
68
|
const log = getLogger("relay-server");
|
|
69
|
+
const UUID_SHAPED_NAME =
|
|
70
|
+
/^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/;
|
|
69
71
|
|
|
70
72
|
// ── ConversationRelay message types ──────────────────────────────────
|
|
71
73
|
|
|
@@ -610,6 +612,12 @@ export class RelayConnection {
|
|
|
610
612
|
);
|
|
611
613
|
this.startNameCapture(outcome.assistantId, outcome.fromNumber);
|
|
612
614
|
return;
|
|
615
|
+
case "unverified_caller":
|
|
616
|
+
await this.handleUnverifiedCaller(
|
|
617
|
+
outcome.displayName,
|
|
618
|
+
outcome.isGuardian,
|
|
619
|
+
);
|
|
620
|
+
return;
|
|
613
621
|
case "verification":
|
|
614
622
|
if (this.controller && resolved.actorTrust.trustClass !== "unknown") {
|
|
615
623
|
this.controller.setTrustContext(
|
|
@@ -667,6 +675,35 @@ export class RelayConnection {
|
|
|
667
675
|
});
|
|
668
676
|
}
|
|
669
677
|
|
|
678
|
+
/** Speak verification guidance to a known-but-unverified caller, then disconnect. */
|
|
679
|
+
private async handleUnverifiedCaller(
|
|
680
|
+
displayName: string,
|
|
681
|
+
isGuardian: boolean,
|
|
682
|
+
): Promise<void> {
|
|
683
|
+
recordCallEvent(this.callSessionId, "inbound_acl_unverified_caller", {
|
|
684
|
+
callSessionId: this.callSessionId,
|
|
685
|
+
isGuardian,
|
|
686
|
+
});
|
|
687
|
+
this.connectionState = "disconnecting";
|
|
688
|
+
updateCallSession(this.callSessionId, {
|
|
689
|
+
status: "failed",
|
|
690
|
+
endedAt: Date.now(),
|
|
691
|
+
lastError: "Inbound voice ACL: caller channel unverified",
|
|
692
|
+
});
|
|
693
|
+
const action = isGuardian
|
|
694
|
+
? `To verify, open your assistant's contacts page, click Verify next to the phone channel, ` +
|
|
695
|
+
`and follow the prompts. Then call back once the verification session is active.`
|
|
696
|
+
: `Please reach out to the account guardian to start a new verification session, ` +
|
|
697
|
+
`then call back once the verification session is active.`;
|
|
698
|
+
const message =
|
|
699
|
+
`This number is registered as ${displayName}'s phone but has not been verified yet. ` +
|
|
700
|
+
action;
|
|
701
|
+
await speakSystemPrompt(this, message);
|
|
702
|
+
setTimeout(() => {
|
|
703
|
+
this.endSession("Inbound voice ACL: caller channel unverified");
|
|
704
|
+
}, getTtsPlaybackDelayMs());
|
|
705
|
+
}
|
|
706
|
+
|
|
670
707
|
/** Deny an inbound call with a TTS message and schedule disconnect. */
|
|
671
708
|
private async denyInboundCall(
|
|
672
709
|
from: string,
|
|
@@ -1615,7 +1652,11 @@ export class RelayConnection {
|
|
|
1615
1652
|
private resolveAssistantLabel(): string | null {
|
|
1616
1653
|
try {
|
|
1617
1654
|
const name = getAssistantName();
|
|
1618
|
-
|
|
1655
|
+
const trimmedName = name?.trim();
|
|
1656
|
+
if (!trimmedName || UUID_SHAPED_NAME.test(trimmedName)) {
|
|
1657
|
+
return null;
|
|
1658
|
+
}
|
|
1659
|
+
return trimmedName;
|
|
1619
1660
|
} catch {
|
|
1620
1661
|
return null;
|
|
1621
1662
|
}
|
|
@@ -56,6 +56,13 @@ type SetupOutcome =
|
|
|
56
56
|
guardianName: string | null;
|
|
57
57
|
}
|
|
58
58
|
| { action: "name_capture"; assistantId: string; fromNumber: string }
|
|
59
|
+
| {
|
|
60
|
+
action: "unverified_caller";
|
|
61
|
+
assistantId: string;
|
|
62
|
+
fromNumber: string;
|
|
63
|
+
displayName: string;
|
|
64
|
+
isGuardian: boolean;
|
|
65
|
+
}
|
|
59
66
|
| { action: "deny"; message: string; logReason: string };
|
|
60
67
|
|
|
61
68
|
// ── Resolved context produced alongside the outcome ──────────────────
|
|
@@ -234,6 +241,35 @@ export function routeSetup(ctx: SetupContext): {
|
|
|
234
241
|
};
|
|
235
242
|
}
|
|
236
243
|
|
|
244
|
+
// Known caller whose channel hasn't passed verification yet —
|
|
245
|
+
// mirrors the gateway's pre-intercept (twilio-voice-webhook.ts) so
|
|
246
|
+
// calls slipping past it (e.g. canonicalization mismatch between
|
|
247
|
+
// gateway and assistant DBs) still get useful guidance instead of
|
|
248
|
+
// the "I don't recognize this number" name-capture script.
|
|
249
|
+
const unverifiedStatuses = new Set(["unverified", "pending"]);
|
|
250
|
+
const memberChannel = actorTrust.memberRecord?.channel;
|
|
251
|
+
if (memberChannel && unverifiedStatuses.has(memberChannel.status)) {
|
|
252
|
+
log.info(
|
|
253
|
+
{
|
|
254
|
+
callSessionId: ctx.callSessionId,
|
|
255
|
+
from: ctx.from,
|
|
256
|
+
channelId: memberChannel.id,
|
|
257
|
+
channelStatus: memberChannel.status,
|
|
258
|
+
},
|
|
259
|
+
"Inbound voice ACL: known but unverified caller — returning verification guidance",
|
|
260
|
+
);
|
|
261
|
+
return {
|
|
262
|
+
outcome: {
|
|
263
|
+
action: "unverified_caller",
|
|
264
|
+
assistantId,
|
|
265
|
+
fromNumber: ctx.from,
|
|
266
|
+
displayName: actorTrust.memberRecord!.contact.displayName,
|
|
267
|
+
isGuardian: actorTrust.memberRecord!.contact.role === "guardian",
|
|
268
|
+
},
|
|
269
|
+
resolved,
|
|
270
|
+
};
|
|
271
|
+
}
|
|
272
|
+
|
|
237
273
|
// Unknown caller — name capture flow
|
|
238
274
|
log.info(
|
|
239
275
|
{
|
package/src/calls/types.ts
CHANGED
|
@@ -33,6 +33,7 @@ export type CallEventType =
|
|
|
33
33
|
| "inbound_acl_name_capture_started"
|
|
34
34
|
| "inbound_acl_name_captured"
|
|
35
35
|
| "inbound_acl_name_capture_timeout"
|
|
36
|
+
| "inbound_acl_unverified_caller"
|
|
36
37
|
| "inbound_acl_access_approved"
|
|
37
38
|
| "inbound_acl_access_denied"
|
|
38
39
|
| "inbound_acl_access_timeout"
|
|
@@ -233,7 +233,7 @@ function buildVoiceCallControlPrompt(opts: {
|
|
|
233
233
|
);
|
|
234
234
|
} else {
|
|
235
235
|
lines.push(
|
|
236
|
-
'7. If the latest user turn is "(call connected — deliver opening greeting)", this is an inbound call you are answering (not a call you initiated). Greet the caller warmly and ask how you can help. Introduce yourself once at the start using your assistant name if you know it (for example: "Hey there, this is Ava, Sam\'s assistant. How can I help?"). If your assistant name is not known, skip the name and just identify yourself as the guardian\'s assistant. Do NOT say "I\'m calling" or "I\'m calling on behalf of". Vary the wording; do not use a fixed template.',
|
|
236
|
+
'7. If the latest user turn is "(call connected — deliver opening greeting)", this is an inbound call you are answering (not a call you initiated). Greet the caller warmly and ask how you can help. Introduce yourself once at the start using your assistant name if you know it (for example: "Hey there, this is Ava, Sam\'s assistant. How can I help?"). If your assistant name is not known, skip the name and just identify yourself as the guardian\'s assistant. Never use a UUID-shaped internal assistant ID as your spoken name. Do NOT say "I\'m calling" or "I\'m calling on behalf of". Vary the wording; do not use a fixed template.',
|
|
237
237
|
);
|
|
238
238
|
}
|
|
239
239
|
lines.push(
|
|
@@ -293,7 +293,11 @@ export async function startVoiceTurn(
|
|
|
293
293
|
onMessageComplete: (msg) => {
|
|
294
294
|
opts.onComplete?.();
|
|
295
295
|
opts.callbacks?.message_complete?.(msg);
|
|
296
|
-
if (
|
|
296
|
+
if (
|
|
297
|
+
msg.type === "message_complete" &&
|
|
298
|
+
msg.messageId &&
|
|
299
|
+
msg.source !== "aux"
|
|
300
|
+
) {
|
|
297
301
|
try {
|
|
298
302
|
opts.callbacks?.persisted_assistant_message_id?.(msg.messageId);
|
|
299
303
|
} catch (err) {
|
|
@@ -314,7 +318,8 @@ export async function startVoiceTurn(
|
|
|
314
318
|
|
|
315
319
|
// Phone voice has no interactive permission/secret UI, so apply explicit
|
|
316
320
|
// per-role policies by default. Local live voice opts into the normal
|
|
317
|
-
// client approval path instead.
|
|
321
|
+
// client approval path instead. Side-effect double-defense is wired
|
|
322
|
+
// below at the conversation-configure point.
|
|
318
323
|
const trustClass = opts.trustContext?.trustClass;
|
|
319
324
|
const isGuardian = trustClass === "guardian";
|
|
320
325
|
const approvalMode = opts.approvalMode ?? "phone-call";
|
|
@@ -386,7 +391,13 @@ export async function startVoiceTurn(
|
|
|
386
391
|
}
|
|
387
392
|
}
|
|
388
393
|
|
|
389
|
-
//
|
|
394
|
+
// Non-guardian phone voice forces side-effect tools to prompt so the
|
|
395
|
+
// auto-deny handler below reliably sees a confirmation_request. Without
|
|
396
|
+
// this, a broad allow trust rule (e.g. wildcard bash) would let
|
|
397
|
+
// side-effect tools execute without ever emitting an event for the
|
|
398
|
+
// auto-deny / scoped-grant handler to intercept.
|
|
399
|
+
conversation.forcePromptSideEffects =
|
|
400
|
+
!isGuardian && !usesLocalInteractiveApprovals;
|
|
390
401
|
conversation.setAssistantId(opts.assistantId ?? DAEMON_INTERNAL_ASSISTANT_ID);
|
|
391
402
|
conversation.callSessionId = voiceSessionId;
|
|
392
403
|
conversation.setTrustContext(opts.trustContext ?? null);
|
|
@@ -528,7 +539,14 @@ export async function startVoiceTurn(
|
|
|
528
539
|
return;
|
|
529
540
|
}
|
|
530
541
|
} else if (msg.type === "secret_request") {
|
|
531
|
-
|
|
542
|
+
if (usesLocalInteractiveApprovals) {
|
|
543
|
+
// Local live voice runs alongside the desktop client, which has a
|
|
544
|
+
// secret-entry UI (SecretPromptManager). Forward the broadcast and
|
|
545
|
+
// let the prompter's existing registration handle the response.
|
|
546
|
+
broadcastMessage(msg);
|
|
547
|
+
return;
|
|
548
|
+
}
|
|
549
|
+
// Phone voice has no secret-entry UI, so resolve immediately.
|
|
532
550
|
log.info(
|
|
533
551
|
{ turnId, service: msg.service, field: msg.field },
|
|
534
552
|
"Auto-resolving secret request for voice turn (no secret-entry UI)",
|
|
@@ -549,6 +567,7 @@ export async function startVoiceTurn(
|
|
|
549
567
|
conversation.setAssistantId("self");
|
|
550
568
|
conversation.setVoiceCallControlPrompt(null);
|
|
551
569
|
conversation.callSessionId = undefined;
|
|
570
|
+
conversation.forcePromptSideEffects = false;
|
|
552
571
|
// Reset the conversation's client callback to a no-op so the stale
|
|
553
572
|
// closure doesn't intercept events from future turns on the same conversation.
|
|
554
573
|
conversation.updateClient(() => {}, true);
|