@vellumai/assistant 0.12.2 → 0.12.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -0
- package/AGENTS.md +1 -1
- package/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/integrations.md +7 -0
- package/docs/architecture/memory.md +17 -2
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/credential-execution-service.md +1 -1
- package/docs/desktop-browser-cli.md +50 -5
- package/docs/live-voice-task-outcomes.md +100 -0
- package/docs/mode-sessions.md +183 -0
- package/docs/voice-input-diagnostics.md +58 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
- package/node_modules/@vellumai/environments/src/shell.ts +24 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +716 -16
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +11 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- package/scripts/sync-llm-catalog.ts +3 -0
- package/scripts/voice-ttft-spike.ts +2 -2
- package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
- package/src/__tests__/agent-loop.test.ts +259 -0
- package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/answered-question-persistence.test.ts +2 -0
- package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
- package/src/__tests__/anthropic-provider.test.ts +55 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/approval-message-composer.test.ts +1 -118
- package/src/__tests__/approval-routes-http.test.ts +3 -0
- package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
- package/src/__tests__/assistant-event-targeting.test.ts +186 -0
- package/src/__tests__/assistant-stream-state.test.ts +29 -9
- package/src/__tests__/attachments-store.test.ts +22 -3
- package/src/__tests__/browser-fill-credential.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +4 -1
- package/src/__tests__/build-persisted-content.test.ts +1 -1
- package/src/__tests__/call-conversation-messages.test.ts +5 -0
- package/src/__tests__/call-recovery.test.ts +7 -2
- package/src/__tests__/call-routes-http.test.ts +12 -0
- package/src/__tests__/call-store.test.ts +7 -2
- package/src/__tests__/channel-approval.test.ts +9 -14
- package/src/__tests__/channel-reply-delivery.test.ts +56 -0
- package/src/__tests__/channel-retry-sweep.test.ts +9 -0
- package/src/__tests__/chat-credential-redaction.test.ts +23 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
- package/src/__tests__/checker.test.ts +11 -3
- package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
- package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
- package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
- package/src/__tests__/computer-use-tools.test.ts +1 -233
- package/src/__tests__/config-model-image-provider.test.ts +39 -0
- package/src/__tests__/config-schema.test.ts +16 -0
- package/src/__tests__/config-watcher.test.ts +24 -0
- package/src/__tests__/context-search-agent-runner.test.ts +260 -1
- package/src/__tests__/context-search-fanout.test.ts +1 -1
- package/src/__tests__/context-search-types.test.ts +7 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +797 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-attachments.test.ts +106 -0
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- package/src/__tests__/conversation-fork-crud.test.ts +191 -0
- package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
- package/src/__tests__/conversation-retry-route.test.ts +22 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
- package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
- package/src/__tests__/conversation-undo.test.ts +61 -0
- package/src/__tests__/credential-execution-client.test.ts +72 -55
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
- package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
- package/src/__tests__/dm-backfill.test.ts +91 -1
- package/src/__tests__/document-create-route.test.ts +88 -0
- package/src/__tests__/document-sync-tags.test.ts +27 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
- package/src/__tests__/events-tail-route.test.ts +58 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
- package/src/__tests__/guardian-action-sweep.test.ts +16 -0
- package/src/__tests__/guardian-dispatch.test.ts +13 -0
- package/src/__tests__/headless-browser-interactions.test.ts +64 -20
- package/src/__tests__/heartbeat-service.test.ts +2 -59
- package/src/__tests__/helpers/mock-conversation.ts +21 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
- package/src/__tests__/history-repair.test.ts +53 -0
- package/src/__tests__/host-cu-proxy.test.ts +46 -2
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/image-credentials.test.ts +49 -0
- package/src/__tests__/image-service-dispatcher.test.ts +45 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
- package/src/__tests__/llm-catalog-parity.test.ts +27 -4
- package/src/__tests__/media-generate-image.test.ts +49 -1
- package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
- package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
- package/src/__tests__/mode-session-history.test.ts +245 -0
- package/src/__tests__/mode-session-recovery.test.ts +222 -0
- package/src/__tests__/mode-session-wire.test.ts +141 -0
- package/src/__tests__/notification-guardian-path.test.ts +7 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
- package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-commands-routes.test.ts +114 -101
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
- package/src/__tests__/oauth-providers-routes.test.ts +3 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/persist-media-references.test.ts +50 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-api-provider.test.ts +5 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
- package/src/__tests__/process-message-display-content.test.ts +56 -0
- package/src/__tests__/reaction-persistence.test.ts +5 -0
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
- package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +20 -0
- package/src/__tests__/scheduler-result-notification.test.ts +23 -4
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
- package/src/__tests__/secret-routes-scrub.test.ts +22 -27
- package/src/__tests__/secret-scanner.test.ts +20 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
- package/src/__tests__/secure-keys.test.ts +50 -4
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/server-tool-pairing.test.ts +107 -0
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- package/src/__tests__/skills.test.ts +5 -4
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
- package/src/__tests__/subagent-manager-notify.test.ts +1 -2
- package/src/__tests__/subagent-notify-parent.test.ts +146 -39
- package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
- package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/thread-backfill.test.ts +53 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-follow-up.test.ts +99 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -0
- package/src/__tests__/unicode.test.ts +36 -0
- package/src/__tests__/web-search-backend-failure.test.ts +1 -1
- package/src/activation/progress-store.test.ts +12 -7
- package/src/agent/loop.ts +136 -53
- package/src/agent/tool-result-follow-up.ts +70 -0
- package/src/api/attachment-provenance.test.ts +68 -0
- package/src/api/computer-use-tool.test.ts +55 -0
- package/src/api/computer-use-tool.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +3 -0
- package/src/api/events/assistant-turn-start.ts +3 -0
- package/src/api/events/desktop-activity-changed.ts +10 -0
- package/src/api/events/generation-handoff.ts +2 -0
- package/src/api/events/message-complete.ts +2 -0
- package/src/api/events/notification-conversation-created.ts +14 -16
- package/src/api/events/notification-intent.ts +4 -2
- package/src/api/events/question-request.ts +1 -0
- package/src/api/events/tool-result.ts +85 -0
- package/src/api/events/tool-use-start.ts +3 -0
- package/src/api/events/user-message-echo.ts +3 -0
- package/src/api/index.ts +42 -6
- package/src/api/mode-session.test.ts +131 -0
- package/src/api/mode-session.ts +148 -0
- package/src/api/remember-tool.ts +15 -0
- package/src/api/responses/conversation-message.ts +9 -0
- package/src/approvals/AGENTS.md +4 -2
- package/src/approvals/approval-primitive.ts +5 -2
- package/src/approvals/scoped-approval-grants.ts +6 -2
- package/src/browser/__tests__/operations.test.ts +29 -0
- package/src/browser/operation-meta.ts +2 -1
- package/src/browser/operations.ts +29 -0
- package/src/browser/virtual-desktop-target.ts +2 -9
- package/src/bundler/bundle-signer.ts +1 -3
- package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
- package/src/calls/__tests__/call-controller.test.ts +94 -0
- package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
- package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
- package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
- package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
- package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
- package/src/calls/barge-in-guard.ts +5 -0
- package/src/calls/call-controller.ts +196 -1
- package/src/calls/call-domain.ts +4 -0
- package/src/calls/call-store.ts +87 -2
- package/src/calls/guardian-action-sweep.ts +22 -8
- package/src/calls/media-stream-audio-transcode.ts +1 -3
- package/src/calls/typesafe-noul.ts +156 -0
- package/src/calls/voice-control-protocol.ts +6 -0
- package/src/calls/voice-escalation-judge.ts +145 -0
- package/src/calls/voice-escalation-target.ts +10 -0
- package/src/calls/voice-leg-coordinator.ts +121 -3
- package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
- package/src/calls/voice-session-bridge.ts +256 -112
- package/src/calls/voice-triage-escalate.ts +7 -0
- package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
- package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
- package/src/cli/commands/__tests__/notifications.test.ts +35 -10
- package/src/cli/commands/__tests__/plugins.test.ts +20 -1
- package/src/cli/commands/__tests__/schedules.test.ts +14 -0
- package/src/cli/commands/bash.help.ts +4 -3
- package/src/cli/commands/browser.help.ts +9 -6
- package/src/cli/commands/browser.ts +0 -1
- package/src/cli/commands/clients.help.ts +46 -0
- package/src/cli/commands/clients.ts +116 -0
- package/src/cli/commands/credentials.help.ts +9 -4
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/oauth/index.help.ts +10 -0
- package/src/cli/commands/oauth/providers.ts +12 -0
- package/src/cli/commands/oauth/request.test.ts +179 -2
- package/src/cli/commands/oauth/request.ts +41 -10
- package/src/cli/commands/plugins.ts +12 -5
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/commands/schedules.ts +2 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
- package/src/cli/lib/bundled-marketplace.json +906 -1
- package/src/cli/lib/bundled-plugin-packages.json +783 -1
- package/src/cli/lib/inspect-plugin.ts +11 -4
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/cli/lib/upgrade-plugin.ts +19 -11
- package/src/cli/output.ts +18 -4
- package/src/config/__tests__/default-provider.test.ts +6 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
- package/src/config/bundled-skills/schedule/SKILL.md +6 -6
- package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
- package/src/config/call-site-defaults.ts +9 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +9 -17
- package/src/config/platform-identity.ts +8 -8
- package/src/config/profile-text-generation.test.ts +51 -0
- package/src/config/profile-text-generation.ts +51 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
- package/src/config/schemas/__tests__/tools.test.ts +31 -0
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -18
- package/src/config/schemas/llm.ts +9 -2
- package/src/config/schemas/mcp.ts +6 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- package/src/config/schemas/memory-v3.ts +12 -0
- package/src/config/schemas/services.ts +15 -6
- package/src/config/schemas/tools.ts +10 -0
- package/src/config/session-groups-gate.ts +21 -0
- package/src/config/skills.ts +2 -6
- package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
- package/src/conversations/message-consolidation.ts +102 -5
- package/src/credential-execution/ces-connect.test.ts +69 -0
- package/src/credential-execution/ces-connect.ts +115 -0
- package/src/credential-execution/ces-runtime.ts +55 -93
- package/src/credential-execution/executable-discovery.ts +34 -142
- package/src/credential-execution/process-manager.test.ts +20 -24
- package/src/credential-execution/process-manager.ts +24 -19
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
- package/src/daemon/assistant-attachments.ts +20 -12
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- package/src/daemon/chat-credential-redaction.ts +16 -1
- package/src/daemon/computer-use-mode-session.test.ts +210 -0
- package/src/daemon/computer-use-mode-session.ts +105 -0
- package/src/daemon/config-watcher.ts +10 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
- package/src/daemon/conversation-agent-loop.ts +231 -25
- package/src/daemon/conversation-attachments.ts +93 -12
- package/src/daemon/conversation-evictor.ts +5 -24
- package/src/daemon/conversation-history.ts +10 -0
- package/src/daemon/conversation-interrupt-repair.ts +4 -43
- package/src/daemon/conversation-interrupt.ts +7 -11
- package/src/daemon/conversation-messaging.ts +58 -5
- package/src/daemon/conversation-mode-session.test.ts +1667 -0
- package/src/daemon/conversation-mode-session.ts +1008 -0
- package/src/daemon/conversation-process.ts +5 -0
- package/src/daemon/conversation-runtime-assembly.ts +10 -20
- package/src/daemon/conversation-skill-tools.ts +1 -0
- package/src/daemon/conversation-store.ts +4 -4
- package/src/daemon/conversation-surface-snapshots.ts +135 -0
- package/src/daemon/conversation-surfaces.ts +113 -5
- package/src/daemon/conversation-tool-setup.ts +79 -6
- package/src/daemon/conversation-turn-finalize.ts +26 -13
- package/src/daemon/conversation.ts +215 -58
- package/src/daemon/daemon-control.ts +3 -7
- package/src/daemon/handlers/config-model.ts +7 -5
- package/src/daemon/handlers/shared.ts +55 -16
- package/src/daemon/host-cu-proxy.ts +51 -22
- package/src/daemon/lifecycle.ts +30 -13
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/message-types/shared.ts +1 -0
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/orphan-reaper.ts +4 -3
- package/src/daemon/persist-media-references.ts +20 -3
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/tool-setup-types.ts +6 -0
- package/src/daemon/virtual-desktop-context.ts +21 -0
- package/src/daemon/wake-conversation-ops.ts +50 -15
- package/src/desktop/__tests__/fake-desktop.ts +1 -0
- package/src/desktop/desktop-accessibility-script.ts +88 -0
- package/src/desktop/desktop-accessibility.test.ts +160 -0
- package/src/desktop/desktop-accessibility.ts +169 -0
- package/src/desktop/desktop-automation-lease.test.ts +302 -64
- package/src/desktop/desktop-automation-lease.ts +129 -54
- package/src/desktop/desktop-browser-endpoint.ts +4 -0
- package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
- package/src/desktop/desktop-computer-use.test.ts +449 -0
- package/src/desktop/desktop-computer-use.ts +502 -0
- package/src/desktop/desktop-dependencies.ts +47 -293
- package/src/desktop/desktop-display.ts +2 -2
- package/src/desktop/desktop-help.ts +15 -0
- package/src/desktop/desktop-panel-config.test.ts +13 -3
- package/src/desktop/desktop-panel-config.ts +109 -15
- package/src/desktop/desktop-session-manager.test.ts +69 -21
- package/src/desktop/desktop-session-manager.ts +76 -22
- package/src/desktop/desktop-stream-bridge.test.ts +76 -132
- package/src/desktop/desktop-stream-bridge.ts +9 -11
- package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
- package/src/desktop/desktop-wallpaper-worker.ts +17 -0
- package/src/desktop/desktop-wallpaper.test.ts +48 -7
- package/src/desktop/desktop-wallpaper.ts +34 -102
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +53 -3
- package/src/desktop/virtual-desktop-platform.test.ts +5 -9
- package/src/documents/document-store.ts +23 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
- package/src/heartbeat/heartbeat-service.ts +5 -33
- package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
- package/src/ipc/assistant-server.ts +2 -0
- package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
- package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
- package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
- package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
- package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
- package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
- package/src/live-voice/__tests__/session-controls.test.ts +23 -0
- package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
- package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
- package/src/live-voice/camera-mode-session.test.ts +265 -0
- package/src/live-voice/camera-mode-session.ts +277 -0
- package/src/live-voice/continuation-judge.ts +123 -0
- package/src/live-voice/live-activity-reporter.ts +115 -6
- package/src/live-voice/live-voice-manager.ts +36 -1
- package/src/live-voice/live-voice-photo.ts +88 -7
- package/src/live-voice/live-voice-session-manager.ts +15 -0
- package/src/live-voice/live-voice-session.ts +1443 -747
- package/src/live-voice/live-voice-tts.ts +22 -4
- package/src/live-voice/microphone-idle-gate.ts +56 -0
- package/src/live-voice/protocol.ts +171 -4
- package/src/live-voice/session-controls.ts +11 -3
- package/src/live-voice/task-outcomes.ts +131 -0
- package/src/live-voice/voice-input-diagnostics.ts +117 -0
- package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
- package/src/mcp/__tests__/startup.test.ts +30 -7
- package/src/mcp/__tests__/tool-caps.test.ts +134 -0
- package/src/mcp/manager.ts +171 -101
- package/src/mcp/startup.ts +33 -13
- package/src/mcp/tool-caps.ts +184 -0
- package/src/media/__tests__/image-models.test.ts +58 -0
- package/src/media/image-credentials.ts +5 -0
- package/src/media/image-models.ts +52 -0
- package/src/media/image-service.ts +8 -0
- package/src/media/openrouter-image-service.test.ts +133 -0
- package/src/media/openrouter-image-service.ts +153 -0
- package/src/media/types.ts +1 -1
- package/src/messaging/provider-message-metadata.ts +3 -3
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
- package/src/messaging/providers/discord/send.ts +4 -17
- package/src/messaging/providers/discord/transport.ts +2 -2
- package/src/messaging/providers/outlook/client.ts +16 -22
- package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
- package/src/messaging/providers/telegram-bot/send.ts +10 -7
- package/src/messaging/providers/telegram-bot/transport.ts +3 -10
- package/src/messaging/providers/whatsapp/send.test.ts +169 -4
- package/src/monitoring/__tests__/control.test.ts +17 -5
- package/src/monitoring/control.ts +15 -5
- package/src/notifications/AGENTS.md +1 -1
- package/src/notifications/README.md +83 -99
- package/src/notifications/__tests__/broadcaster.test.ts +1 -1
- package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
- package/src/notifications/__tests__/copy-composer.test.ts +71 -1
- package/src/notifications/__tests__/decision-engine.test.ts +79 -2
- package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
- package/src/notifications/__tests__/notification-utils.test.ts +18 -0
- package/src/notifications/adapters/macos.ts +37 -46
- package/src/notifications/broadcaster.ts +5 -6
- package/src/notifications/channel-allowlist.ts +44 -0
- package/src/notifications/copy-composer.ts +11 -26
- package/src/notifications/decision-engine.ts +24 -14
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +123 -37
- package/src/notifications/home-feed-side-effect.ts +9 -7
- package/src/notifications/notification-utils.ts +19 -0
- package/src/notifications/schedule-result-producer.ts +4 -6
- package/src/notifications/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/identity-verifier.ts +24 -0
- package/src/oauth/oauth-store.ts +12 -4
- package/src/oauth/provider-serializer.ts +8 -0
- package/src/oauth/seed-providers.ts +42 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/permissions/confirmation-guardian-request.test.ts +16 -0
- package/src/permissions/confirmation-guardian-request.ts +2 -3
- package/src/permissions/question-prompter.test.ts +31 -0
- package/src/permissions/question-prompter.ts +2 -0
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/attachments-store.ts +84 -44
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +166 -26
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-plugin-facade.ts +30 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/conversation-tool-surface.ts +135 -0
- package/src/persistence/conversation-types.test.ts +32 -0
- package/src/persistence/conversation-types.ts +26 -4
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
- package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
- package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
- package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
- package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
- package/src/persistence/schema/conversations.ts +67 -0
- package/src/persistence/schema/index.ts +1 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/schema/oauth.ts +1 -0
- package/src/persistence/steps.ts +41 -3
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/conversation-turn.ts +31 -7
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +35 -6
- package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
- package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
- package/src/plugin-api/plugin-name-env.ts +125 -0
- package/src/plugin-api/resolve-credential.ts +79 -20
- package/src/plugin-api/vision-support.test.ts +22 -0
- package/src/plugin-api/vision-support.ts +17 -5
- package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
- package/src/plugins/active-plugin-env.ts +51 -0
- package/src/plugins/defaults/index.ts +24 -0
- package/src/plugins/defaults/memory/AGENTS.md +39 -5
- package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
- package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
- package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
- package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/buffer-file.ts +354 -0
- package/src/plugins/defaults/memory/buffer-format.ts +40 -0
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
- package/src/plugins/defaults/memory/context-search/format.ts +53 -8
- package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
- package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
- package/src/plugins/defaults/memory/context-search/search.ts +8 -14
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
- package/src/plugins/defaults/memory/context-search/types.ts +1 -11
- package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/host-utils.ts +0 -10
- package/src/plugins/defaults/memory/injectors.ts +4 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
- package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
- package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
- package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
- package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
- package/src/plugins/defaults/memory/v3/card.ts +2 -1
- package/src/plugins/defaults/memory/v3/injector.ts +212 -178
- package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
- package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
- package/src/plugins/defaults/memory/v3/sections.ts +2 -1
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
- package/src/plugins/defaults/memory/worker-control.ts +15 -5
- package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
- package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
- package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
- package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
- package/src/plugins/defaults/task-progress/package.json +14 -0
- package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
- package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
- package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
- package/src/prompts/delegation-gate.ts +57 -0
- package/src/prompts/system-prompt.ts +14 -32
- package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
- package/src/providers/anthropic/client.ts +10 -1
- package/src/providers/anthropic-gateway-shared.ts +6 -0
- package/src/providers/fetch-provider-catalog.ts +11 -0
- package/src/providers/gemini/client.ts +25 -8
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/jev/client.test.ts +270 -0
- package/src/providers/jev/client.ts +534 -0
- package/src/providers/model-catalog.ts +59 -3
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
- package/src/providers/openai/chat-completions-provider.ts +100 -29
- package/src/providers/openai/google-thought-signature.ts +0 -6
- package/src/providers/openai/responses-provider.ts +23 -1
- package/src/providers/ratelimit.ts +1 -3
- package/src/providers/search-provider-catalog.ts +24 -0
- package/src/providers/server-tool-pairing.ts +16 -7
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
- package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
- package/src/providers/types.ts +5 -0
- package/src/routes/control.ts +7 -5
- package/src/runtime/AGENTS.md +6 -4
- package/src/runtime/__tests__/agent-wake.test.ts +94 -1
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +32 -5
- package/src/runtime/approval-message-composer.ts +3 -69
- package/src/runtime/assistant-event-hub.ts +73 -75
- package/src/runtime/assistant-event-publish-options.ts +7 -0
- package/src/runtime/assistant-event-targeting.ts +79 -0
- package/src/runtime/assistant-stream-state.ts +13 -100
- package/src/runtime/background-job-runner.ts +5 -5
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/guardian-action-message-composer.ts +8 -161
- package/src/runtime/guardian-action-service.ts +2 -17
- package/src/runtime/guardian-reply-router.ts +29 -40
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +6 -0
- package/src/runtime/message-composer-types.ts +3 -61
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
- package/src/runtime/migrations/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
- package/src/runtime/migrations/vbundle-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-validator.ts +1 -0
- package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
- package/src/runtime/pending-interactions.ts +29 -0
- package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
- package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
- package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
- package/src/runtime/routes/browser-context.ts +31 -11
- package/src/runtime/routes/browser-routes.ts +43 -4
- package/src/runtime/routes/btw-routes.ts +9 -4
- package/src/runtime/routes/channel-route-shared.ts +1 -9
- package/src/runtime/routes/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +125 -14
- package/src/runtime/routes/credential-prompt-routes.ts +4 -3
- package/src/runtime/routes/credential-routes.ts +1 -2
- package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
- package/src/runtime/routes/desktop-setup-routes.ts +8 -7
- package/src/runtime/routes/documents-routes.ts +51 -0
- package/src/runtime/routes/email-routes.ts +3 -7
- package/src/runtime/routes/events-routes.ts +75 -54
- package/src/runtime/routes/guardian-approval-interception.ts +24 -0
- package/src/runtime/routes/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +37 -41
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
- package/src/runtime/routes/inference-profiles-routes.ts +9 -0
- package/src/runtime/routes/llm-context-normalization.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +73 -2
- package/src/runtime/routes/notification-routes.ts +10 -0
- package/src/runtime/routes/oauth-commands-routes.ts +57 -54
- package/src/runtime/routes/oauth-providers.ts +11 -0
- package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
- package/src/runtime/routes/oauth-request-hints.ts +149 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/secret-routes.ts +99 -119
- package/src/runtime/routes/settings-routes.ts +10 -4
- package/src/runtime/routes/watcher-routes.ts +1 -3
- package/src/runtime/trust-class.test.ts +7 -6
- package/src/runtime/trust-class.ts +9 -17
- package/src/schedule/__tests__/worker-control.test.ts +36 -5
- package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
- package/src/schedule/run-script.ts +2 -2
- package/src/schedule/scheduler.ts +47 -11
- package/src/schedule/tool-surface-readiness.ts +65 -0
- package/src/schedule/worker-control.ts +15 -5
- package/src/schedule/worker-mcp.ts +85 -0
- package/src/schedule/worker.ts +9 -31
- package/src/security/secure-keys.ts +74 -112
- package/src/skills/clawhub.ts +3 -8
- package/src/skills/managed-store.ts +1 -5
- package/src/stt/types.ts +4 -0
- package/src/subagent/notify.ts +54 -34
- package/src/subagent/parent-notification.ts +6 -0
- package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
- package/src/telemetry/phone-call-funnel.ts +144 -0
- package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
- package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
- package/src/tools/ask-question/ask-question-tool.ts +120 -22
- package/src/tools/browser/browser-execution.ts +29 -60
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
- package/src/tools/client-os.ts +15 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/computer-use/target.ts +42 -0
- package/src/tools/document/document-tool.ts +13 -18
- package/src/tools/execution-target.ts +14 -16
- package/src/tools/host-terminal/host-shell.ts +16 -7
- package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
- package/src/tools/network/__tests__/web-search.test.ts +203 -0
- package/src/tools/network/web-fetch.ts +274 -7
- package/src/tools/network/web-search.ts +468 -6
- package/src/tools/permission-checker.ts +3 -3
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
- package/src/tools/shared/shell-output.test.ts +10 -0
- package/src/tools/shared/shell-output.ts +14 -2
- package/src/tools/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +24 -4
- package/src/tools/skills/scaffold-managed.ts +2 -1
- package/src/tools/skills/skill-script-runner.ts +7 -0
- package/src/tools/skills/skill-tool-factory.ts +15 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
- package/src/tools/terminal/safe-env.ts +39 -24
- package/src/tools/terminal/sanitized-bash.ts +15 -2
- package/src/tools/terminal/shell-launch.test.ts +162 -0
- package/src/tools/terminal/shell.test.ts +29 -0
- package/src/tools/terminal/shell.ts +15 -7
- package/src/tools/tool-approval-handler.ts +5 -1
- package/src/tools/tool-types.ts +3 -3
- package/src/tools/types.ts +8 -2
- package/src/util/__tests__/worker-process-command.test.ts +5 -4
- package/src/util/abort-reasons.ts +18 -26
- package/src/util/browser-human-verification.ts +14 -0
- package/src/util/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/host-process.test.ts +17 -1
- package/src/util/host-process.ts +24 -0
- package/src/util/provider-error-patterns.ts +3 -0
- package/src/util/unicode.ts +29 -0
- package/src/util/worker-process.ts +77 -35
- package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
- package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/computer-use-window-schema.test.ts +0 -24
- package/src/api/events/heartbeat-alert.ts +0 -20
- package/src/daemon/message-types/web-activity.ts +0 -65
- package/src/desktop/desktop-dependencies.test.ts +0 -131
- package/src/tools/computer-use/definitions.ts +0 -607
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One bounded yes/no question to TypeSafe's System One model (Jev), shared by
|
|
3
|
+
* the voice judges. A judge runs only when its call site resolves to the
|
|
4
|
+
* TypeSafe provider; every failure comes back as a non-answer so the caller
|
|
5
|
+
* keeps its default behavior.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
9
|
+
import { type JevJsonValue, noulFromAnswer } from "../providers/jev/client.js";
|
|
10
|
+
import { resolveConfiguredProvider } from "../providers/provider-send-message.js";
|
|
11
|
+
import type { Provider, ProviderResponse } from "../providers/types.js";
|
|
12
|
+
import { getLogger } from "../util/logger.js";
|
|
13
|
+
|
|
14
|
+
const log = getLogger("typesafe-noul");
|
|
15
|
+
|
|
16
|
+
const TYPESAFE_PROVIDER_NAME = "typesafe";
|
|
17
|
+
|
|
18
|
+
export type TypesafeNoulOutcome =
|
|
19
|
+
| "answered"
|
|
20
|
+
| "unavailable"
|
|
21
|
+
| "timeout"
|
|
22
|
+
| "error";
|
|
23
|
+
|
|
24
|
+
export interface TypesafeNoulResult {
|
|
25
|
+
outcome: TypesafeNoulOutcome;
|
|
26
|
+
/** Calibrated P(yes), present when the outcome is "answered". */
|
|
27
|
+
noul?: number;
|
|
28
|
+
latencyMs: number;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** The call site's provider when it resolves to TypeSafe, else null. */
|
|
32
|
+
export async function resolveTypesafeProvider(
|
|
33
|
+
callSite: LLMCallSite,
|
|
34
|
+
): Promise<Provider | null> {
|
|
35
|
+
const resolved = await resolveConfiguredProvider(callSite);
|
|
36
|
+
return resolved?.configuredProviderName === TYPESAFE_PROVIDER_NAME
|
|
37
|
+
? resolved.provider
|
|
38
|
+
: null;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
function answersFrom(
|
|
42
|
+
response: ProviderResponse,
|
|
43
|
+
): Record<string, unknown> | null {
|
|
44
|
+
const raw = response.rawResponse;
|
|
45
|
+
if (
|
|
46
|
+
typeof raw === "object" &&
|
|
47
|
+
raw !== null &&
|
|
48
|
+
"answers" in raw &&
|
|
49
|
+
typeof raw.answers === "object" &&
|
|
50
|
+
raw.answers !== null
|
|
51
|
+
) {
|
|
52
|
+
return raw.answers as Record<string, unknown>;
|
|
53
|
+
}
|
|
54
|
+
const block = response.content.find((b) => b.type === "text");
|
|
55
|
+
if (!block || block.type !== "text") {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
try {
|
|
59
|
+
const parsed: unknown = JSON.parse(block.text);
|
|
60
|
+
return typeof parsed === "object" && parsed !== null
|
|
61
|
+
? (parsed as Record<string, unknown>)
|
|
62
|
+
: null;
|
|
63
|
+
} catch {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Ask one noul question. Never rejects. The timeout is a hard race rather
|
|
70
|
+
* than trust in the provider honoring the abort, because callers hold user
|
|
71
|
+
* audio or background work on the answer.
|
|
72
|
+
*/
|
|
73
|
+
export async function askTypesafeNoul(args: {
|
|
74
|
+
callSite: LLMCallSite;
|
|
75
|
+
conversationId: string;
|
|
76
|
+
state: JevJsonValue;
|
|
77
|
+
instructions: string;
|
|
78
|
+
timeoutMs: number;
|
|
79
|
+
signal?: AbortSignal;
|
|
80
|
+
/** Defaults to {@link resolveTypesafeProvider} for `callSite`. */
|
|
81
|
+
resolveProvider?: () => Promise<Provider | null>;
|
|
82
|
+
}): Promise<TypesafeNoulResult> {
|
|
83
|
+
const startedAt = Date.now();
|
|
84
|
+
const elapsed = () => Date.now() - startedAt;
|
|
85
|
+
const controller = new AbortController();
|
|
86
|
+
const signal = args.signal
|
|
87
|
+
? AbortSignal.any([args.signal, controller.signal])
|
|
88
|
+
: controller.signal;
|
|
89
|
+
|
|
90
|
+
const ask = async (): Promise<TypesafeNoulResult> => {
|
|
91
|
+
try {
|
|
92
|
+
const provider = await (
|
|
93
|
+
args.resolveProvider ?? (() => resolveTypesafeProvider(args.callSite))
|
|
94
|
+
)();
|
|
95
|
+
if (!provider) {
|
|
96
|
+
return { outcome: "unavailable", latencyMs: elapsed() };
|
|
97
|
+
}
|
|
98
|
+
const response = await provider.sendMessage(
|
|
99
|
+
[
|
|
100
|
+
{
|
|
101
|
+
role: "user",
|
|
102
|
+
content: [
|
|
103
|
+
{
|
|
104
|
+
type: "text",
|
|
105
|
+
text: JSON.stringify({
|
|
106
|
+
state: args.state,
|
|
107
|
+
questions: {
|
|
108
|
+
answer: { type: "noul", instructions: args.instructions },
|
|
109
|
+
},
|
|
110
|
+
}),
|
|
111
|
+
},
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
],
|
|
115
|
+
{
|
|
116
|
+
config: {
|
|
117
|
+
callSite: args.callSite,
|
|
118
|
+
conversationId: args.conversationId,
|
|
119
|
+
disableTurnStartCache: true,
|
|
120
|
+
},
|
|
121
|
+
signal,
|
|
122
|
+
},
|
|
123
|
+
);
|
|
124
|
+
const noul = noulFromAnswer(answersFrom(response)?.answer);
|
|
125
|
+
if (noul === undefined) {
|
|
126
|
+
log.warn(
|
|
127
|
+
{ callSite: args.callSite, conversationId: args.conversationId },
|
|
128
|
+
"TypeSafe judge returned no usable answer",
|
|
129
|
+
);
|
|
130
|
+
return { outcome: "error", latencyMs: elapsed() };
|
|
131
|
+
}
|
|
132
|
+
return { outcome: "answered", noul, latencyMs: elapsed() };
|
|
133
|
+
} catch (err) {
|
|
134
|
+
if (!signal.aborted) {
|
|
135
|
+
log.warn(
|
|
136
|
+
{ err, callSite: args.callSite, conversationId: args.conversationId },
|
|
137
|
+
"TypeSafe judge failed",
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
return { outcome: "error", latencyMs: elapsed() };
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
|
|
144
|
+
let timer: ReturnType<typeof setTimeout> | undefined;
|
|
145
|
+
const timedOut = new Promise<TypesafeNoulResult>((resolve) => {
|
|
146
|
+
timer = setTimeout(() => {
|
|
147
|
+
controller.abort();
|
|
148
|
+
resolve({ outcome: "timeout", latencyMs: elapsed() });
|
|
149
|
+
}, args.timeoutMs);
|
|
150
|
+
});
|
|
151
|
+
try {
|
|
152
|
+
return await Promise.race([ask(), timedOut]);
|
|
153
|
+
} finally {
|
|
154
|
+
clearTimeout(timer);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
@@ -14,6 +14,7 @@ export const CALL_OPENING_ACK_MARKER = "[CALL_OPENING_ACK]";
|
|
|
14
14
|
export const CALL_VERIFICATION_COMPLETE_MARKER = "[CALL_VERIFICATION_COMPLETE]";
|
|
15
15
|
export const END_CALL_MARKER = "[END_CALL]";
|
|
16
16
|
export const TASK_STOP_MARKER = "[TASK:STOP]";
|
|
17
|
+
export const TASK_UPDATE_SILENT_MARKER = "[TASK_UPDATE:SILENT]";
|
|
17
18
|
|
|
18
19
|
/**
|
|
19
20
|
* Verdict tokens for the fast "front-door" model (triage-and-escalate voice
|
|
@@ -220,6 +221,7 @@ export function stripInternalSpeechMarkers(text: string): string {
|
|
|
220
221
|
.replace(CALL_OPENING_ACK_MARKER_REGEX, "")
|
|
221
222
|
.replace(END_CALL_MARKER_REGEX, "")
|
|
222
223
|
.replace(TASK_STOP_MARKER_REGEX, "")
|
|
224
|
+
.replaceAll(TASK_UPDATE_SILENT_MARKER, "")
|
|
223
225
|
.replace(HOLD_VERDICT_TOKEN_REGEX, "")
|
|
224
226
|
.replace(ESCALATE_VERDICT_TOKEN_REGEX, "")
|
|
225
227
|
.replace(MINIMIZE_ROOM_MARKER_REGEX, "")
|
|
@@ -249,6 +251,7 @@ const CONTROL_MARKER_STRINGS = [
|
|
|
249
251
|
"[CALL_OPENING_ACK]",
|
|
250
252
|
"[END_CALL]",
|
|
251
253
|
TASK_STOP_MARKER,
|
|
254
|
+
TASK_UPDATE_SILENT_MARKER,
|
|
252
255
|
"[0]",
|
|
253
256
|
"[1]",
|
|
254
257
|
"[-1]",
|
|
@@ -435,6 +438,9 @@ export function parseTerminalSessionControl(
|
|
|
435
438
|
*/
|
|
436
439
|
export function terminalControlMarkerLength(text: string): number {
|
|
437
440
|
const trimmed = text.trimEnd();
|
|
441
|
+
if (trimmed.endsWith(TASK_UPDATE_SILENT_MARKER)) {
|
|
442
|
+
return TASK_UPDATE_SILENT_MARKER.length;
|
|
443
|
+
}
|
|
438
444
|
if (trimmed.endsWith(MINIMIZE_ROOM_MARKER)) {
|
|
439
445
|
return MINIMIZE_ROOM_MARKER.length;
|
|
440
446
|
}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Second opinion on the voice front door's escalate decision.
|
|
3
|
+
*
|
|
4
|
+
* The front-door leg is fast and toolless, and it decides in its leading
|
|
5
|
+
* tokens whether a turn needs the tool-capable escalated leg. Its failure mode
|
|
6
|
+
* is answering a turn it cannot complete ("yeah, I'll send that") so nothing
|
|
7
|
+
* ever happens. This judge asks TypeSafe's System One model one yes/no
|
|
8
|
+
* question about the same turn, in parallel with the front-door leg: does a
|
|
9
|
+
* correct reply need something the front door cannot do from here? A
|
|
10
|
+
* confident yes overrules a front-door answer and hands the turn off.
|
|
11
|
+
*
|
|
12
|
+
* The judge runs only when the `voiceEscalationJudge` call site resolves to
|
|
13
|
+
* the TypeSafe provider. Every other outcome (no such profile, provider
|
|
14
|
+
* error, timeout, unparseable answer) is a "clear" verdict, so the front
|
|
15
|
+
* door's own decision stands exactly as it would without the judge.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import type { Message, Provider } from "../providers/types.js";
|
|
19
|
+
import { safeStringSlice } from "../util/unicode.js";
|
|
20
|
+
import { askTypesafeNoul } from "./typesafe-noul.js";
|
|
21
|
+
|
|
22
|
+
export const VOICE_ESCALATION_JUDGE_CALL_SITE = "voiceEscalationJudge";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Minimum P(yes) that overrules a front-door answer. Calibrated on a labeled
|
|
26
|
+
* set of voice turns: it caught nearly every action request, including bare
|
|
27
|
+
* confirmations of an earlier offer ("yeah, do it"), while clearing ordinary
|
|
28
|
+
* conversation, including follow-ups about work already done.
|
|
29
|
+
*/
|
|
30
|
+
export const ESCALATION_JUDGE_THRESHOLD = 0.7;
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Budget from the front-door dispatch. The judge's measured roundtrip sits
|
|
34
|
+
* well under the front-door model's time to first token, so within this
|
|
35
|
+
* budget the verdict is almost always in hand before the first answer word
|
|
36
|
+
* would have been spoken; past it the front door's decision stands.
|
|
37
|
+
*/
|
|
38
|
+
export const ESCALATION_JUDGE_TIMEOUT_MS = 800;
|
|
39
|
+
|
|
40
|
+
/** Recent turns shown to the judge, oldest first. */
|
|
41
|
+
const HISTORY_TURNS = 6;
|
|
42
|
+
const HISTORY_TURN_MAX_CHARS = 600;
|
|
43
|
+
|
|
44
|
+
export type EscalationJudgeOutcome =
|
|
45
|
+
| "escalate"
|
|
46
|
+
| "clear"
|
|
47
|
+
| "unavailable"
|
|
48
|
+
| "timeout"
|
|
49
|
+
| "error";
|
|
50
|
+
|
|
51
|
+
export interface EscalationJudgement {
|
|
52
|
+
escalate: boolean;
|
|
53
|
+
outcome: EscalationJudgeOutcome;
|
|
54
|
+
/** Calibrated P(yes), when the judge answered. */
|
|
55
|
+
noul?: number;
|
|
56
|
+
latencyMs: number;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const ESCALATION_QUESTION =
|
|
60
|
+
"The voice assistant answering right now has NO tools and no access to the user's accounts, files, messages, calendar, screen, apps, the web, or saved memories. Would a correct reply to what the caller just said require doing something it cannot do from here: taking an action (sending, scheduling, creating, editing, changing, opening, calling), looking up live or current information, or retrieving a personal fact that is not already stated in the recent conversation? Answer yes if the caller is asking for, or agreeing to, any such action, even vaguely or via a short confirmation of an earlier offer. Answer no for conversation, opinions, general knowledge, and questions answerable from the recent conversation.";
|
|
61
|
+
|
|
62
|
+
function textOf(message: Message): string {
|
|
63
|
+
return message.content
|
|
64
|
+
.map((block) => (block.type === "text" ? block.text : ""))
|
|
65
|
+
.filter(
|
|
66
|
+
(text) => text.trim().length > 0 && !text.trimStart().startsWith("<"),
|
|
67
|
+
)
|
|
68
|
+
.join(" ")
|
|
69
|
+
.replace(/\s+/g, " ")
|
|
70
|
+
.trim();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* The judge's view of the conversation: the last few spoken turns as plain
|
|
75
|
+
* text, without injected context blocks, tool traffic, or the caller's
|
|
76
|
+
* current utterance (which the judge receives on its own).
|
|
77
|
+
*/
|
|
78
|
+
export function recentConversationForJudge(
|
|
79
|
+
history: readonly Message[],
|
|
80
|
+
utterance: string,
|
|
81
|
+
): string {
|
|
82
|
+
const lines: string[] = [];
|
|
83
|
+
for (const message of history) {
|
|
84
|
+
const text = textOf(message);
|
|
85
|
+
if (text.length === 0) {
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
const speaker = message.role === "user" ? "caller" : "assistant";
|
|
89
|
+
lines.push(
|
|
90
|
+
`${speaker}: ${safeStringSlice(text, 0, HISTORY_TURN_MAX_CHARS)}`,
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
const current = `caller: ${utterance.replace(/\s+/g, " ").trim()}`;
|
|
94
|
+
if (lines.length > 0 && lines[lines.length - 1] === current) {
|
|
95
|
+
lines.pop();
|
|
96
|
+
}
|
|
97
|
+
return lines.slice(-HISTORY_TURNS).join("\n");
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Judge whether a front-door turn must escalate. Never rejects: every failure
|
|
102
|
+
* is a non-escalating verdict, so the front door's decision stands.
|
|
103
|
+
*/
|
|
104
|
+
export async function judgeEscalation(args: {
|
|
105
|
+
conversationId: string;
|
|
106
|
+
history: readonly Message[];
|
|
107
|
+
utterance: string;
|
|
108
|
+
signal?: AbortSignal;
|
|
109
|
+
timeoutMs?: number;
|
|
110
|
+
/** Provider resolver, injectable for tests. */
|
|
111
|
+
resolveProvider?: () => Promise<Provider | null>;
|
|
112
|
+
}): Promise<EscalationJudgement> {
|
|
113
|
+
const utterance = args.utterance.trim();
|
|
114
|
+
if (utterance.length === 0) {
|
|
115
|
+
return { escalate: false, outcome: "unavailable", latencyMs: 0 };
|
|
116
|
+
}
|
|
117
|
+
const result = await askTypesafeNoul({
|
|
118
|
+
callSite: VOICE_ESCALATION_JUDGE_CALL_SITE,
|
|
119
|
+
conversationId: args.conversationId,
|
|
120
|
+
state: {
|
|
121
|
+
recent_conversation:
|
|
122
|
+
recentConversationForJudge(args.history, utterance) ||
|
|
123
|
+
"(start of conversation)",
|
|
124
|
+
caller_just_said: utterance,
|
|
125
|
+
},
|
|
126
|
+
instructions: ESCALATION_QUESTION,
|
|
127
|
+
timeoutMs: args.timeoutMs ?? ESCALATION_JUDGE_TIMEOUT_MS,
|
|
128
|
+
...(args.signal ? { signal: args.signal } : {}),
|
|
129
|
+
...(args.resolveProvider ? { resolveProvider: args.resolveProvider } : {}),
|
|
130
|
+
});
|
|
131
|
+
if (result.outcome !== "answered" || result.noul === undefined) {
|
|
132
|
+
return {
|
|
133
|
+
escalate: false,
|
|
134
|
+
outcome: result.outcome === "answered" ? "error" : result.outcome,
|
|
135
|
+
latencyMs: result.latencyMs,
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
const escalate = result.noul >= ESCALATION_JUDGE_THRESHOLD;
|
|
139
|
+
return {
|
|
140
|
+
escalate,
|
|
141
|
+
outcome: escalate ? "escalate" : "clear",
|
|
142
|
+
noul: result.noul,
|
|
143
|
+
latencyMs: result.latencyMs,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -12,6 +12,12 @@
|
|
|
12
12
|
* leg, resolve and speak the bridge, mark it as the floor holder, start the
|
|
13
13
|
* escalated leg, re-arm narration. A leg that was cancelled never hands off.
|
|
14
14
|
*
|
|
15
|
+
* An optional escalation judge (see `voice-escalation-judge.ts`) runs beside
|
|
16
|
+
* the leg. While its verdict is pending, an answer is held rather than
|
|
17
|
+
* spoken; a judge that says the turn needs the escalated leg overrules the
|
|
18
|
+
* answer and hands off with the canned bridge. Hold and escalate verdicts
|
|
19
|
+
* from the leg itself never wait on the judge.
|
|
20
|
+
*
|
|
15
21
|
* Everything transport-specific comes in through {@link FrontDoorLegHost}:
|
|
16
22
|
* how answer text and the bridge are spoken, how a leg is started or
|
|
17
23
|
* aborted, and the speculative hold and commit that only live voice has.
|
|
@@ -90,6 +96,13 @@ export interface FrontDoorLegHost {
|
|
|
90
96
|
* bridge cap adds no latency before the escalated leg starts.
|
|
91
97
|
*/
|
|
92
98
|
abortLeg(): void;
|
|
99
|
+
/**
|
|
100
|
+
* Abort a leg whose answer the escalation judge overruled. Its persisted
|
|
101
|
+
* row holds an answer nobody heard, so the driver drops it rather than
|
|
102
|
+
* leaving it in the history the escalated leg reads. Falls back to
|
|
103
|
+
* {@link abortLeg} when absent.
|
|
104
|
+
*/
|
|
105
|
+
overruleLeg?(): void;
|
|
93
106
|
/**
|
|
94
107
|
* Speak the bridge so the strong-model call has no dead air. The model's
|
|
95
108
|
* own bridge is real assistant speech; the canned fallback is audio-only,
|
|
@@ -103,6 +116,21 @@ export interface FrontDoorLegHost {
|
|
|
103
116
|
export interface FrontDoorLegCoordinator {
|
|
104
117
|
/** Whether this leg handed the turn off to the escalated leg. */
|
|
105
118
|
readonly handedOff: boolean;
|
|
119
|
+
/**
|
|
120
|
+
* True while answer text is held for a pending judge verdict. A driver
|
|
121
|
+
* whose leg completes in this state waits on {@link settled} before
|
|
122
|
+
* calling {@link complete}, so the held answer is spoken or overruled
|
|
123
|
+
* before the turn finishes.
|
|
124
|
+
*/
|
|
125
|
+
readonly awaitingJudge: boolean;
|
|
126
|
+
/** Resolves once no answer text is held for the judge. */
|
|
127
|
+
settled(): Promise<void>;
|
|
128
|
+
/**
|
|
129
|
+
* Attach the escalation judge's verdict for this leg. `true` means the
|
|
130
|
+
* turn needs the escalated leg. The promise must never reject, and must
|
|
131
|
+
* settle within a bounded time: a held answer waits on it.
|
|
132
|
+
*/
|
|
133
|
+
attachEscalationJudge(verdict: Promise<boolean>): void;
|
|
106
134
|
/** Feed one raw delta of the front-door leg's stream. */
|
|
107
135
|
push(text: string): void;
|
|
108
136
|
/**
|
|
@@ -125,14 +153,35 @@ export function createFrontDoorLegCoordinator(options: {
|
|
|
125
153
|
const { host } = options;
|
|
126
154
|
const verdict = createFrontDoorVerdictMachine(options.holdEnabled);
|
|
127
155
|
let handedOff = false;
|
|
156
|
+
// "none": no judge attached. "pending": attached, verdict not in yet.
|
|
157
|
+
let judge: "none" | "pending" | "escalate" | "clear" = "none";
|
|
158
|
+
// Answer text released by the verdict machine while the judge is pending.
|
|
159
|
+
// Null until the leg's verdict classified as an answer.
|
|
160
|
+
let heldAnswer: string | null = null;
|
|
161
|
+
let settleWaiters: Array<() => void> = [];
|
|
162
|
+
// Whether any answer text reached the host. A judge attached after that
|
|
163
|
+
// is ignored: speech already started cannot be overruled.
|
|
164
|
+
let answerReleased = false;
|
|
165
|
+
|
|
166
|
+
const releaseAnswer = (text: string): void => {
|
|
167
|
+
answerReleased = true;
|
|
168
|
+
host.onAnswerText(text);
|
|
169
|
+
};
|
|
128
170
|
|
|
129
|
-
const handOff = (
|
|
171
|
+
const handOff = (
|
|
172
|
+
cappedBridge: string,
|
|
173
|
+
opts: { overruled?: boolean } = {},
|
|
174
|
+
): void => {
|
|
130
175
|
if (handedOff || !host.isLive()) {
|
|
131
176
|
return;
|
|
132
177
|
}
|
|
133
178
|
handedOff = true;
|
|
134
179
|
host.progress?.clear();
|
|
135
|
-
host.
|
|
180
|
+
if (opts.overruled === true && host.overruleLeg !== undefined) {
|
|
181
|
+
host.overruleLeg();
|
|
182
|
+
} else {
|
|
183
|
+
host.abortLeg();
|
|
184
|
+
}
|
|
136
185
|
const bridge = resolveSpokenEscalationBridge(cappedBridge, host.language());
|
|
137
186
|
host.speakBridge(bridge);
|
|
138
187
|
// The bridge is the turn's spoken acknowledgement: narration keeps its
|
|
@@ -145,10 +194,79 @@ export function createFrontDoorLegCoordinator(options: {
|
|
|
145
194
|
host.progress?.arm();
|
|
146
195
|
};
|
|
147
196
|
|
|
197
|
+
const releaseSettled = (): void => {
|
|
198
|
+
const waiters = settleWaiters;
|
|
199
|
+
settleWaiters = [];
|
|
200
|
+
for (const resolve of waiters) {
|
|
201
|
+
resolve();
|
|
202
|
+
}
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
// Act on held answer text once the judge has spoken: overrule it, or speak
|
|
206
|
+
// it as the leg would have without a judge.
|
|
207
|
+
const resolveHeldAnswer = (): void => {
|
|
208
|
+
if (heldAnswer === null || judge === "pending") {
|
|
209
|
+
return;
|
|
210
|
+
}
|
|
211
|
+
const text = heldAnswer;
|
|
212
|
+
heldAnswer = null;
|
|
213
|
+
if (judge === "escalate") {
|
|
214
|
+
handOff("", { overruled: true });
|
|
215
|
+
} else if (!handedOff && text.length > 0) {
|
|
216
|
+
releaseAnswer(text);
|
|
217
|
+
}
|
|
218
|
+
releaseSettled();
|
|
219
|
+
};
|
|
220
|
+
|
|
221
|
+
const onAnswer = (text: string): void => {
|
|
222
|
+
if (heldAnswer !== null) {
|
|
223
|
+
heldAnswer += text;
|
|
224
|
+
return;
|
|
225
|
+
}
|
|
226
|
+
if (judge === "pending") {
|
|
227
|
+
heldAnswer = text;
|
|
228
|
+
return;
|
|
229
|
+
}
|
|
230
|
+
if (judge === "escalate") {
|
|
231
|
+
// The verdict landed before the leg's first answer word.
|
|
232
|
+
heldAnswer = text;
|
|
233
|
+
resolveHeldAnswer();
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
releaseAnswer(text);
|
|
237
|
+
};
|
|
238
|
+
|
|
148
239
|
return {
|
|
149
240
|
get handedOff() {
|
|
150
241
|
return handedOff;
|
|
151
242
|
},
|
|
243
|
+
get awaitingJudge() {
|
|
244
|
+
return heldAnswer !== null && judge === "pending";
|
|
245
|
+
},
|
|
246
|
+
settled() {
|
|
247
|
+
if (heldAnswer === null || judge !== "pending") {
|
|
248
|
+
return Promise.resolve();
|
|
249
|
+
}
|
|
250
|
+
return new Promise<void>((resolve) => {
|
|
251
|
+
settleWaiters.push(resolve);
|
|
252
|
+
});
|
|
253
|
+
},
|
|
254
|
+
attachEscalationJudge(verdict) {
|
|
255
|
+
if (judge !== "none" || answerReleased || handedOff) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
judge = "pending";
|
|
259
|
+
void verdict.then(
|
|
260
|
+
(escalate) => {
|
|
261
|
+
judge = escalate ? "escalate" : "clear";
|
|
262
|
+
resolveHeldAnswer();
|
|
263
|
+
},
|
|
264
|
+
() => {
|
|
265
|
+
judge = "clear";
|
|
266
|
+
resolveHeldAnswer();
|
|
267
|
+
},
|
|
268
|
+
);
|
|
269
|
+
},
|
|
152
270
|
push(text) {
|
|
153
271
|
if (handedOff) {
|
|
154
272
|
return;
|
|
@@ -166,7 +284,7 @@ export function createFrontDoorLegCoordinator(options: {
|
|
|
166
284
|
return;
|
|
167
285
|
}
|
|
168
286
|
if (step.kind === "answer") {
|
|
169
|
-
|
|
287
|
+
onAnswer(step.text);
|
|
170
288
|
return;
|
|
171
289
|
}
|
|
172
290
|
if (
|