@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,72 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
PHONE_CALL_STEPS,
|
|
5
|
+
phoneCallEndScreen,
|
|
6
|
+
phoneCallSilenceReason,
|
|
7
|
+
phoneCallStartScreen,
|
|
8
|
+
} from "../phone-call-funnel.js";
|
|
9
|
+
|
|
10
|
+
describe("phoneCallStartScreen", () => {
|
|
11
|
+
it("stamps the direction and the call mode", () => {
|
|
12
|
+
expect(phoneCallStartScreen("inbound", "normal")).toBe(
|
|
13
|
+
"started_inbound:normal",
|
|
14
|
+
);
|
|
15
|
+
expect(phoneCallStartScreen("outbound", "verification")).toBe(
|
|
16
|
+
"started_outbound:verification",
|
|
17
|
+
);
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
it("reads an unwritten mode as the ordinary call it is", () => {
|
|
21
|
+
// Only verification and invite calls write a mode, so a null there is a
|
|
22
|
+
// normal conversation rather than a dimension nobody filled in.
|
|
23
|
+
expect(phoneCallStartScreen("inbound", null)).toBe(
|
|
24
|
+
"started_inbound:normal",
|
|
25
|
+
);
|
|
26
|
+
expect(phoneCallStartScreen("inbound")).toBe("started_inbound:normal");
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
it("keeps the longest stamp inside the wire field's 64-char bound", () => {
|
|
30
|
+
const longest = phoneCallStartScreen("outbound", "verification");
|
|
31
|
+
expect(longest.length).toBeLessThanOrEqual(64);
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
describe("phoneCallSilenceReason", () => {
|
|
36
|
+
it("blames the connection when the call never reached the caller", () => {
|
|
37
|
+
// Nothing that happens on a live call can be held against one that never
|
|
38
|
+
// connected: nobody was there to speak.
|
|
39
|
+
expect(phoneCallSilenceReason({ connected: false })).toBe("no_connect");
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
it("reports a connected call that took no turn as silence on the line", () => {
|
|
43
|
+
expect(phoneCallSilenceReason({ connected: true })).toBe("no_turn");
|
|
44
|
+
});
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
describe("phoneCallEndScreen", () => {
|
|
48
|
+
it("stamps the terminal status on a call that took a turn", () => {
|
|
49
|
+
expect(phoneCallEndScreen("completed")).toBe("ended_completed");
|
|
50
|
+
expect(phoneCallEndScreen("failed", null)).toBe("ended_failed");
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it("carries the silence classification when no turn was taken", () => {
|
|
54
|
+
expect(phoneCallEndScreen("failed", "no_connect")).toBe(
|
|
55
|
+
"ended_failed:silent_no_connect",
|
|
56
|
+
);
|
|
57
|
+
expect(phoneCallEndScreen("completed", "no_turn")).toBe(
|
|
58
|
+
"ended_completed:silent_no_turn",
|
|
59
|
+
);
|
|
60
|
+
});
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
describe("PHONE_CALL_STEPS", () => {
|
|
64
|
+
it("orders the pair the warehouse subtracts", () => {
|
|
65
|
+
// Duration is the gap between these two rows, so their order is part of
|
|
66
|
+
// the contract rather than a label.
|
|
67
|
+
expect(PHONE_CALL_STEPS.callStarted.stepIndex).toBe(0);
|
|
68
|
+
expect(PHONE_CALL_STEPS.callEnded.stepIndex).toBe(1);
|
|
69
|
+
expect(PHONE_CALL_STEPS.callStarted.stepName).toBe("phone_call_started");
|
|
70
|
+
expect(PHONE_CALL_STEPS.callEnded.stepName).toBe("phone_call_ended");
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phone-call telemetry vocabulary: the single source of truth for the step
|
|
3
|
+
* names, funnel version, and dimension values the call store's emitter uses.
|
|
4
|
+
*
|
|
5
|
+
* The phone half of the live-voice funnel, and deliberately its mirror image:
|
|
6
|
+
* same onboarding substrate (`type: "onboarding"`), same open-string
|
|
7
|
+
* `step_name` / `funnel_version`, same reason for both. See
|
|
8
|
+
* `live-voice-funnel.ts` for the full argument; the short version is that the
|
|
9
|
+
* backend stores those two as open strings, so a new funnel needs no platform
|
|
10
|
+
* serializer and no wire-contract change.
|
|
11
|
+
*
|
|
12
|
+
* **Duration is not a field**, for the same reason it is not one on live
|
|
13
|
+
* voice: the onboarding event shape has no numeric slot. The two events below
|
|
14
|
+
* are keyed by the call session id in `session_id` and the warehouse subtracts
|
|
15
|
+
* their `recorded_at` stamps.
|
|
16
|
+
*
|
|
17
|
+
* **Turn count is not a field either.** Phone turns already carry the call
|
|
18
|
+
* session id in their `client` bag (`voiceTelemetry` at the bridge call site),
|
|
19
|
+
* so a turn count is a count of those rows.
|
|
20
|
+
*
|
|
21
|
+
* A call that starts and never ends is **censored, not infinite**: a daemon
|
|
22
|
+
* crash between the two writes emits no end event, so duration math must drop
|
|
23
|
+
* unmatched `started` rows rather than treat the call as still running.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { CallMode, CallStatus } from "../calls/types.js";
|
|
27
|
+
|
|
28
|
+
/** Funnel version stamped on every phone-call event. */
|
|
29
|
+
export const PHONE_CALL_FUNNEL_VERSION = "phone_call_v1_2026_09";
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Phone-call funnel steps. `stepName` is the wire value; `stepIndex` is the
|
|
33
|
+
* ordinal position.
|
|
34
|
+
*
|
|
35
|
+
* `callStarted` fires when the call session row is created, before the
|
|
36
|
+
* provider has dialled: a call that never connects is exactly the one worth
|
|
37
|
+
* counting, so the start event precedes no-answer, busy, provider failure and
|
|
38
|
+
* the inbound credential preflight (an inbound session exists before that
|
|
39
|
+
* preflight runs and records against it).
|
|
40
|
+
*
|
|
41
|
+
* It does **not** cover an outbound attempt rejected before a session exists:
|
|
42
|
+
* `startCall`, `startVerificationCall` and `startInviteCall` all return on a
|
|
43
|
+
* failed `preflightVoiceIngress()` without creating a row, and this funnel is
|
|
44
|
+
* keyed by the session id it would have had. Counting those needs a key that
|
|
45
|
+
* does not depend on a session row, which is its own piece of work.
|
|
46
|
+
*/
|
|
47
|
+
export const PHONE_CALL_STEPS = {
|
|
48
|
+
callStarted: { stepName: "phone_call_started", stepIndex: 0 },
|
|
49
|
+
callEnded: { stepName: "phone_call_ended", stepIndex: 1 },
|
|
50
|
+
} as const;
|
|
51
|
+
|
|
52
|
+
export type PhoneCallStepName =
|
|
53
|
+
(typeof PHONE_CALL_STEPS)[keyof typeof PHONE_CALL_STEPS]["stepName"];
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Which way the call was placed. Inbound is someone dialling the assistant's
|
|
57
|
+
* number; outbound is the assistant dialling out on a task.
|
|
58
|
+
*/
|
|
59
|
+
export type PhoneCallDirection = "inbound" | "outbound";
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* How a call ended, stamped as `outcome`.
|
|
63
|
+
*
|
|
64
|
+
* `failed` means the call died on an error: no answer, a provider or
|
|
65
|
+
* credential failure, a dropped media stream. A call the caller or the
|
|
66
|
+
* assistant hung up, including one cancelled before it connected, is
|
|
67
|
+
* `completed`: it ran its course and the close reason on `screen` says how.
|
|
68
|
+
*/
|
|
69
|
+
export type PhoneCallOutcome = "completed" | "failed";
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* How far a call that produced NO caller turn actually got.
|
|
73
|
+
*
|
|
74
|
+
* The phone analogue of the live-voice silence taxonomy, and the closest thing
|
|
75
|
+
* call telemetry has to a "the phone path didn't work" rate. A bare
|
|
76
|
+
* started/ended pair cannot separate a call that never connected from one that
|
|
77
|
+
* connected to silence, and those have completely different fixes.
|
|
78
|
+
*
|
|
79
|
+
* - `no_connect` the call never reached `in_progress`: it failed, was
|
|
80
|
+
* cancelled, or was never answered, so nobody could have
|
|
81
|
+
* spoken.
|
|
82
|
+
* - `no_turn` the call connected and then no caller utterance was ever
|
|
83
|
+
* transcribed: a silent line, a failed STT leg, or a caller who
|
|
84
|
+
* hung up on the disclosure.
|
|
85
|
+
*/
|
|
86
|
+
export type PhoneCallSilenceReason = "no_connect" | "no_turn";
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Classify a call that produced no caller turn. Call only when the call really
|
|
90
|
+
* produced none: the second branch asserts silence, so a call that did take a
|
|
91
|
+
* turn would be mislabelled by it.
|
|
92
|
+
*/
|
|
93
|
+
export function phoneCallSilenceReason(signals: {
|
|
94
|
+
connected: boolean;
|
|
95
|
+
}): PhoneCallSilenceReason {
|
|
96
|
+
return signals.connected ? "no_turn" : "no_connect";
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* The mode an ordinary call carries. Only the verification and invite flows
|
|
101
|
+
* write a mode on the session row, so a null there is not a missing dimension
|
|
102
|
+
* but the ordinary conversation every other path creates.
|
|
103
|
+
*/
|
|
104
|
+
const PHONE_CALL_DEFAULT_MODE: CallMode = "normal";
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* The `screen` dimension for a started call: which way it was placed and what
|
|
108
|
+
* kind of call it is, as `started_<direction>:<mode>`.
|
|
109
|
+
*
|
|
110
|
+
* The mode separates the three things a phone call can be (a normal
|
|
111
|
+
* conversation, a callee verification, an invite redemption) because they have
|
|
112
|
+
* completely different shapes and success criteria, and a funnel that mixed
|
|
113
|
+
* them would report the verification flow's brevity as a conversation problem.
|
|
114
|
+
*/
|
|
115
|
+
export function phoneCallStartScreen(
|
|
116
|
+
direction: PhoneCallDirection,
|
|
117
|
+
mode?: CallMode | null,
|
|
118
|
+
): string {
|
|
119
|
+
return `started_${direction}:${mode ?? PHONE_CALL_DEFAULT_MODE}`;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* The `screen` dimension for an ended call: the terminal status it reached,
|
|
124
|
+
* plus a detail half carrying the silence classification when the call took no
|
|
125
|
+
* caller turn at all.
|
|
126
|
+
*
|
|
127
|
+
* The status is the daemon's own `CallStatus` verbatim rather than a mapping,
|
|
128
|
+
* so a rename surfaces here as a compile error instead of a silently-empty
|
|
129
|
+
* dashboard facet.
|
|
130
|
+
*
|
|
131
|
+
* The silence value carries a `silent_` prefix to match the live-voice stamp,
|
|
132
|
+
* which shares its detail slot with failure codes and renders in an admin
|
|
133
|
+
* column labelled "failure code". Reading the two funnels side by side is
|
|
134
|
+
* worth more than a shorter string here.
|
|
135
|
+
*/
|
|
136
|
+
export function phoneCallEndScreen(
|
|
137
|
+
status: CallStatus,
|
|
138
|
+
silenceReason?: PhoneCallSilenceReason | null,
|
|
139
|
+
): string {
|
|
140
|
+
if (silenceReason) {
|
|
141
|
+
return `ended_${status}:silent_${silenceReason}`;
|
|
142
|
+
}
|
|
143
|
+
return `ended_${status}`;
|
|
144
|
+
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { dirname, join, resolve } from "node:path";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { describe, expect, test } from "bun:test";
|
|
4
|
+
|
|
5
|
+
import { parseToolManifestFile } from "../../skills/tool-manifest.js";
|
|
6
|
+
import { explicitTools } from "../tool-manifest.js";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Tool input schemas must be plain objects at the root.
|
|
10
|
+
*
|
|
11
|
+
* Anthropic's Messages API rejects a tool whose `input_schema` carries
|
|
12
|
+
* `oneOf`, `anyOf`, or `allOf` at the top level ("input_schema does not
|
|
13
|
+
* support oneOf, allOf, or anyOf at the top level"). The rejection is a 400
|
|
14
|
+
* for the whole request, so one offending definition takes down every call
|
|
15
|
+
* that advertises it. Other hosts accept the same schema, which lets the
|
|
16
|
+
* mistake hide until a request routes to Anthropic directly. Either/or rules
|
|
17
|
+
* between fields belong in the tool description and the tool's own input
|
|
18
|
+
* validation instead.
|
|
19
|
+
*
|
|
20
|
+
* Covers the core manifest and every bundled skill's `TOOLS.json`.
|
|
21
|
+
* Combinators nested under `properties` are accepted by Anthropic and stay
|
|
22
|
+
* out of scope.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
const ROOT_COMBINATORS = ["oneOf", "anyOf", "allOf"] as const;
|
|
26
|
+
|
|
27
|
+
const BUNDLED_SKILLS_DIR = resolve(
|
|
28
|
+
dirname(fileURLToPath(import.meta.url)),
|
|
29
|
+
"../../config/bundled-skills",
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
interface SchemaCase {
|
|
33
|
+
/** Tool name, prefixed with the skill directory for bundled skill tools. */
|
|
34
|
+
label: string;
|
|
35
|
+
schema: Record<string, unknown>;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function bundledSkillSchemas(): SchemaCase[] {
|
|
39
|
+
const cases: SchemaCase[] = [];
|
|
40
|
+
for (const relative of new Bun.Glob("*/TOOLS.json").scanSync({
|
|
41
|
+
cwd: BUNDLED_SKILLS_DIR,
|
|
42
|
+
})) {
|
|
43
|
+
const manifest = parseToolManifestFile(join(BUNDLED_SKILLS_DIR, relative));
|
|
44
|
+
for (const tool of manifest.tools) {
|
|
45
|
+
cases.push({
|
|
46
|
+
label: `${dirname(relative)}/${tool.name}`,
|
|
47
|
+
schema: tool.input_schema,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return cases;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function coreSchemas(): SchemaCase[] {
|
|
55
|
+
return explicitTools.map((tool) => {
|
|
56
|
+
if (!tool.name) {
|
|
57
|
+
throw new Error("core manifest entries carry explicit names");
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
label: tool.name,
|
|
61
|
+
schema: tool.input_schema as Record<string, unknown>,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const CASES: SchemaCase[] = [...coreSchemas(), ...bundledSkillSchemas()];
|
|
67
|
+
|
|
68
|
+
describe("tool input schema root", () => {
|
|
69
|
+
test("covers the core manifest and the bundled skills", () => {
|
|
70
|
+
expect(CASES.length).toBeGreaterThan(explicitTools.length);
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
for (const { label, schema } of CASES) {
|
|
74
|
+
test(`${label} keeps combinators out of the schema root`, () => {
|
|
75
|
+
for (const keyword of ROOT_COMBINATORS) {
|
|
76
|
+
expect(schema).not.toHaveProperty(keyword);
|
|
77
|
+
}
|
|
78
|
+
expect(schema.type).toBe("object");
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
});
|
|
@@ -15,6 +15,13 @@ import type { ToolContext } from "../types.js";
|
|
|
15
15
|
// `mock.module` is hoisted by bun before any static import of the tool
|
|
16
16
|
// runs, so the import below sees the stubbed prompter even though
|
|
17
17
|
// `askQuestionTool` captures the symbol at module-eval time.
|
|
18
|
+
const finishDesktopHelp = mock(async (_resume: boolean) => {});
|
|
19
|
+
const prepareDesktopHelp = mock(
|
|
20
|
+
async (_context: ToolContext) => finishDesktopHelp,
|
|
21
|
+
);
|
|
22
|
+
let promptError: Error | undefined;
|
|
23
|
+
mock.module("../../desktop/desktop-help.js", () => ({ prepareDesktopHelp }));
|
|
24
|
+
|
|
18
25
|
const calls: QuestionPromptParams[] = [];
|
|
19
26
|
let nextResult: QuestionPromptResult = {
|
|
20
27
|
entries: [{ questionId: "q1", decision: "skipped" }],
|
|
@@ -28,6 +35,9 @@ mock.module("../../permissions/question-prompter.js", () => ({
|
|
|
28
35
|
QuestionPrompter: class {
|
|
29
36
|
async prompt(params: QuestionPromptParams): Promise<QuestionPromptOutcome> {
|
|
30
37
|
calls.push(params);
|
|
38
|
+
if (promptError) {
|
|
39
|
+
throw promptError;
|
|
40
|
+
}
|
|
31
41
|
// Mirror the real prompter: it mints the request id and assigns the
|
|
32
42
|
// per-question `q1..qN` ids, then returns them alongside the resolution.
|
|
33
43
|
return {
|
|
@@ -61,6 +71,9 @@ function makeContext(overrides: Partial<ToolContext> = {}): ToolContext {
|
|
|
61
71
|
// `setNextResult()` before invoking `askQuestionTool.execute(...)`.
|
|
62
72
|
beforeEach(() => {
|
|
63
73
|
calls.length = 0;
|
|
74
|
+
prepareDesktopHelp.mockClear();
|
|
75
|
+
finishDesktopHelp.mockClear();
|
|
76
|
+
promptError = undefined;
|
|
64
77
|
nextResult = {
|
|
65
78
|
entries: [{ questionId: "q1", decision: "skipped" }],
|
|
66
79
|
overall: "completed",
|
|
@@ -100,7 +113,7 @@ describe("askQuestionTool definition", () => {
|
|
|
100
113
|
expect(def.description).toContain("up to 5");
|
|
101
114
|
expect(def.description).toContain("Skip button");
|
|
102
115
|
|
|
103
|
-
const schema = def.input_schema as {
|
|
116
|
+
const schema = def.input_schema as unknown as {
|
|
104
117
|
properties: Record<
|
|
105
118
|
string,
|
|
106
119
|
{
|
|
@@ -670,7 +683,7 @@ describe("AskQuestionTool batched input", () => {
|
|
|
670
683
|
});
|
|
671
684
|
|
|
672
685
|
describe("askQuestionTool definition (batched schema)", () => {
|
|
673
|
-
test("exposes
|
|
686
|
+
test("exposes batched questions and a desktop help alternative", () => {
|
|
674
687
|
const def = askQuestionTool;
|
|
675
688
|
const schema = def.input_schema as unknown as {
|
|
676
689
|
properties: Record<
|
|
@@ -708,9 +721,7 @@ describe("askQuestionTool definition (batched schema)", () => {
|
|
|
708
721
|
|
|
709
722
|
expect(questions?.items?.required).toEqual(["question", "options"]);
|
|
710
723
|
|
|
711
|
-
|
|
712
|
-
expect(schema.required).toEqual(["questions"]);
|
|
713
|
-
expect(Object.keys(schema.properties)).toEqual(["questions"]);
|
|
724
|
+
expect(schema.properties.desktopHelp?.type).toBe("object");
|
|
714
725
|
|
|
715
726
|
// The legacy flat fields are gone.
|
|
716
727
|
expect(schema.properties.question).toBeUndefined();
|
|
@@ -825,3 +836,154 @@ describe("answered-question record", () => {
|
|
|
825
836
|
).toBeUndefined();
|
|
826
837
|
});
|
|
827
838
|
});
|
|
839
|
+
|
|
840
|
+
describe("virtual desktop help", () => {
|
|
841
|
+
test("reserves the desktop before waiting and resumes control after Done", async () => {
|
|
842
|
+
setNextResult(singleCompleted({ decision: "option", optionId: "done" }));
|
|
843
|
+
const result = await askQuestionTool.execute(
|
|
844
|
+
{
|
|
845
|
+
desktopHelp: {
|
|
846
|
+
message: "Please complete the CAPTCHA.",
|
|
847
|
+
doneLabel: "Done",
|
|
848
|
+
skipLabel: "Skip",
|
|
849
|
+
},
|
|
850
|
+
},
|
|
851
|
+
makeContext(),
|
|
852
|
+
);
|
|
853
|
+
expect(prepareDesktopHelp).toHaveBeenCalledTimes(1);
|
|
854
|
+
expect(finishDesktopHelp).toHaveBeenCalledWith(true);
|
|
855
|
+
expect(calls[0]?.questions[0]?.presentation).toBe("virtual_desktop");
|
|
856
|
+
expect(result.content).toContain("fresh browser snapshot");
|
|
857
|
+
expect(result.answeredQuestion?.responses[0]).toEqual({
|
|
858
|
+
questionId: "q1",
|
|
859
|
+
decision: "option",
|
|
860
|
+
optionId: "done",
|
|
861
|
+
});
|
|
862
|
+
});
|
|
863
|
+
|
|
864
|
+
test.each([
|
|
865
|
+
{ decision: "skipped" as const },
|
|
866
|
+
{ decision: "option" as const, optionId: "skip" },
|
|
867
|
+
])("does not claim the obstacle was solved after Skip: %j", async (entry) => {
|
|
868
|
+
setNextResult(singleCompleted(entry));
|
|
869
|
+
const result = await askQuestionTool.execute(
|
|
870
|
+
{
|
|
871
|
+
desktopHelp: {
|
|
872
|
+
message: "Please complete the CAPTCHA.",
|
|
873
|
+
doneLabel: "Done",
|
|
874
|
+
skipLabel: "Skip",
|
|
875
|
+
},
|
|
876
|
+
},
|
|
877
|
+
makeContext(),
|
|
878
|
+
);
|
|
879
|
+
expect(finishDesktopHelp).toHaveBeenCalledWith(false);
|
|
880
|
+
expect(result.content).toContain("obstacle may still be present");
|
|
881
|
+
expect(result.isError).toBe(false);
|
|
882
|
+
});
|
|
883
|
+
|
|
884
|
+
test("does not wait for a user in a background turn", async () => {
|
|
885
|
+
await askQuestionTool.execute(
|
|
886
|
+
{
|
|
887
|
+
desktopHelp: {
|
|
888
|
+
message: "Please complete the CAPTCHA.",
|
|
889
|
+
doneLabel: "Done",
|
|
890
|
+
skipLabel: "Skip",
|
|
891
|
+
},
|
|
892
|
+
},
|
|
893
|
+
makeContext({ isInteractive: false }),
|
|
894
|
+
);
|
|
895
|
+
expect(prepareDesktopHelp).not.toHaveBeenCalled();
|
|
896
|
+
expect(calls).toHaveLength(0);
|
|
897
|
+
});
|
|
898
|
+
|
|
899
|
+
test("rejects mixing desktop help with a question batch", async () => {
|
|
900
|
+
const result = await askQuestionTool.execute(
|
|
901
|
+
{
|
|
902
|
+
...validInput,
|
|
903
|
+
desktopHelp: {
|
|
904
|
+
message: "Please complete the CAPTCHA.",
|
|
905
|
+
doneLabel: "Done",
|
|
906
|
+
skipLabel: "Skip",
|
|
907
|
+
},
|
|
908
|
+
},
|
|
909
|
+
makeContext(),
|
|
910
|
+
);
|
|
911
|
+
expect(result.isError).toBe(true);
|
|
912
|
+
expect(calls).toHaveLength(0);
|
|
913
|
+
});
|
|
914
|
+
});
|
|
915
|
+
|
|
916
|
+
test("desktop help preserves model-localized fallback labels in history", async () => {
|
|
917
|
+
setNextResult(singleCompleted({ decision: "option", optionId: "done" }));
|
|
918
|
+
const result = await askQuestionTool.execute(
|
|
919
|
+
{
|
|
920
|
+
desktopHelp: {
|
|
921
|
+
message: "Completa la verificación.",
|
|
922
|
+
doneLabel: "Listo",
|
|
923
|
+
skipLabel: "Omitir",
|
|
924
|
+
},
|
|
925
|
+
},
|
|
926
|
+
makeContext(),
|
|
927
|
+
);
|
|
928
|
+
expect(calls[0]?.questions[0]?.options).toEqual([
|
|
929
|
+
{ id: "done", label: "Listo" },
|
|
930
|
+
{ id: "skip", label: "Omitir" },
|
|
931
|
+
]);
|
|
932
|
+
expect(result.answeredQuestion?.questions[0]?.options).toEqual(
|
|
933
|
+
calls[0]?.questions[0]?.options,
|
|
934
|
+
);
|
|
935
|
+
});
|
|
936
|
+
|
|
937
|
+
test("desktop help does not park on a guardian channel without desktop controls", async () => {
|
|
938
|
+
const result = await askQuestionTool.execute(
|
|
939
|
+
{
|
|
940
|
+
desktopHelp: {
|
|
941
|
+
message: "Please sign in.",
|
|
942
|
+
doneLabel: "Done",
|
|
943
|
+
skipLabel: "Skip",
|
|
944
|
+
},
|
|
945
|
+
},
|
|
946
|
+
makeContext({
|
|
947
|
+
supportsDynamicUi: false,
|
|
948
|
+
supportsGuardianQuestionCards: true,
|
|
949
|
+
}),
|
|
950
|
+
);
|
|
951
|
+
expect(result.isError).toBe(true);
|
|
952
|
+
expect(result.content).toContain("continue in the Vellum app");
|
|
953
|
+
expect(prepareDesktopHelp).not.toHaveBeenCalled();
|
|
954
|
+
expect(calls).toHaveLength(0);
|
|
955
|
+
});
|
|
956
|
+
|
|
957
|
+
for (const overall of ["closed", "timed_out", "aborted"] as const) {
|
|
958
|
+
test(`desktop reservation ends when the question is ${overall}`, async () => {
|
|
959
|
+
setNextResult({ overall, entries: [] });
|
|
960
|
+
await askQuestionTool.execute(
|
|
961
|
+
{
|
|
962
|
+
desktopHelp: {
|
|
963
|
+
message: "Complete verification.",
|
|
964
|
+
doneLabel: "Done",
|
|
965
|
+
skipLabel: "Skip",
|
|
966
|
+
},
|
|
967
|
+
},
|
|
968
|
+
makeContext(),
|
|
969
|
+
);
|
|
970
|
+
expect(finishDesktopHelp).toHaveBeenCalledWith(false);
|
|
971
|
+
});
|
|
972
|
+
}
|
|
973
|
+
|
|
974
|
+
test("desktop reservation ends when presenting the question throws", async () => {
|
|
975
|
+
promptError = new Error("delivery failed");
|
|
976
|
+
await expect(
|
|
977
|
+
askQuestionTool.execute(
|
|
978
|
+
{
|
|
979
|
+
desktopHelp: {
|
|
980
|
+
message: "Complete verification.",
|
|
981
|
+
doneLabel: "Done",
|
|
982
|
+
skipLabel: "Skip",
|
|
983
|
+
},
|
|
984
|
+
},
|
|
985
|
+
makeContext(),
|
|
986
|
+
),
|
|
987
|
+
).rejects.toThrow("delivery failed");
|
|
988
|
+
expect(finishDesktopHelp).toHaveBeenCalledWith(false);
|
|
989
|
+
});
|