@vellumai/assistant 0.12.3-staging.1 → 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/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/desktop-browser-cli.md +45 -4
- 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/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/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- 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/src/gateway-ipc-contracts.ts +20 -0
- 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/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +665 -14
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +10 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- 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__/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__/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__/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-retry-sweep.test.ts +9 -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-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.test.ts +546 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- 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-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 +6 -6
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- 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 +25 -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__/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 +1 -1
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +2 -2
- 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-provider-serializer.test.ts +12 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -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 -0
- 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__/runtime-events-sse-reconnect.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__/secure-keys.test.ts +43 -1
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- 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__/surface-completion-in-flight-snapshot.test.ts +2 -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-metadata-plumbing.test.ts +3 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -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 +99 -41
- package/src/api/events/assistant-turn-start.ts +3 -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/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 +31 -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 +6 -0
- package/src/approvals/AGENTS.md +4 -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 -8
- 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__/notifications.test.ts +35 -10
- package/src/cli/commands/browser.help.ts +4 -5
- 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 +6 -1
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/bundled-marketplace.json +84 -34
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/config/__tests__/default-provider.test.ts +3 -1
- 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/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/profile-text-generation.test.ts +2 -2
- 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 +3 -1
- package/src/config/schemas/mcp.ts +2 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- 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 +1 -11
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- 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 +58 -10
- package/src/daemon/conversation-agent-loop.ts +219 -25
- 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 +8 -3
- package/src/daemon/conversation.ts +143 -41
- 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/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/virtual-desktop-context.ts +21 -0
- 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 +76 -68
- package/src/desktop/desktop-automation-lease.ts +41 -50
- 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-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 +11 -122
- package/src/desktop/desktop-stream-bridge.ts +6 -8
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +52 -2
- 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 +63 -18
- package/src/mcp/__tests__/tool-caps.test.ts +28 -1
- package/src/mcp/manager.ts +3 -0
- package/src/mcp/tool-caps.ts +12 -4
- 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/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 +1 -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 +0 -23
- 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/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/oauth-store.ts +1 -3
- package/src/oauth/provider-serializer.ts +7 -0
- package/src/oauth/seed-providers.ts +30 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +55 -6
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -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/conversations.ts +67 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/steps.ts +17 -0
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +24 -5
- 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/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
- package/src/plugins/defaults/memory/context-search/format.ts +51 -7
- 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/types.ts +1 -11
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
- package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
- 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/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 +1 -1
- package/src/providers/jev/client.test.ts +10 -0
- package/src/providers/jev/client.ts +20 -4
- package/src/providers/model-catalog.ts +4 -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/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 +4 -2
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +1 -1
- 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-reply-router.ts +28 -32
- 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/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
- 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 +1 -1
- 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/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +113 -27
- 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 +4 -6
- 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/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +35 -38
- 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 +38 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -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-providers.ts +7 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/secret-routes.ts +1 -1
- 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/worker-control.ts +15 -5
- package/src/security/secure-keys.ts +53 -103
- 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.ts +6 -4
- package/src/tools/browser/browser-execution.ts +22 -59
- 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 +4 -1
- 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/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +11 -2
- 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 +11 -0
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/terminal/shell.ts +2 -0
- 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/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/provider-error-patterns.ts +3 -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
|
@@ -6,10 +6,10 @@
|
|
|
6
6
|
* has to hold here: `isProcessing()` reads false in the window between a turn
|
|
7
7
|
* releasing and its queued successor being dispatched.
|
|
8
8
|
*
|
|
9
|
-
* In-flight subagents are
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
9
|
+
* In-flight subagents and resident mode-session state are other non-idle
|
|
10
|
+
* cases. Reload marks the conversation stale without discarding that state,
|
|
11
|
+
* then `getOrCreateConversation` rebuilds it once every retained lifecycle is
|
|
12
|
+
* settled.
|
|
13
13
|
*/
|
|
14
14
|
import { beforeEach, describe, expect, mock, test } from "bun:test";
|
|
15
15
|
|
|
@@ -26,7 +26,7 @@ mock.module("../subagent/index.js", () => ({
|
|
|
26
26
|
}),
|
|
27
27
|
}));
|
|
28
28
|
|
|
29
|
-
import
|
|
29
|
+
import { Conversation } from "../daemon/conversation.js";
|
|
30
30
|
import {
|
|
31
31
|
clearConversations,
|
|
32
32
|
conversationIds,
|
|
@@ -45,17 +45,29 @@ interface FakeConversation {
|
|
|
45
45
|
|
|
46
46
|
function register(
|
|
47
47
|
id: string,
|
|
48
|
-
state: {
|
|
48
|
+
state: {
|
|
49
|
+
processing: boolean;
|
|
50
|
+
queued: boolean;
|
|
51
|
+
modeSessionWork?: boolean;
|
|
52
|
+
stale?: boolean;
|
|
53
|
+
},
|
|
49
54
|
): FakeConversation {
|
|
50
55
|
const fake: FakeConversation & Record<string, unknown> = {
|
|
51
56
|
disposed: false,
|
|
52
57
|
markedStale: false,
|
|
53
58
|
conversationId: id,
|
|
59
|
+
liveVoiceResidencyLeases: 0,
|
|
54
60
|
isProcessing: () => state.processing,
|
|
55
61
|
hasQueuedMessages: () => state.queued,
|
|
62
|
+
modeSessions: {
|
|
63
|
+
hasResidentWork: () => state.modeSessionWork === true,
|
|
64
|
+
},
|
|
56
65
|
isStale: () => state.stale === true || fake.markedStale,
|
|
57
|
-
hasInFlightWork
|
|
58
|
-
|
|
66
|
+
hasInFlightWork() {
|
|
67
|
+
return Conversation.prototype.hasInFlightWork.call(
|
|
68
|
+
fake as unknown as Conversation,
|
|
69
|
+
);
|
|
70
|
+
},
|
|
59
71
|
dispose() {
|
|
60
72
|
fake.disposed = true;
|
|
61
73
|
},
|
|
@@ -125,6 +137,43 @@ describe("evictConversationsForReload", () => {
|
|
|
125
137
|
expect(abortedParents).toEqual([]);
|
|
126
138
|
});
|
|
127
139
|
|
|
140
|
+
test("keeps resident mode-session ownership usable across reload eviction", () => {
|
|
141
|
+
const resident = register("reload-mode-active", {
|
|
142
|
+
processing: false,
|
|
143
|
+
queued: false,
|
|
144
|
+
modeSessionWork: true,
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
evictConversationsForReload();
|
|
148
|
+
|
|
149
|
+
expect(resident.disposed).toBe(false);
|
|
150
|
+
expect(resident.markedStale).toBe(true);
|
|
151
|
+
expect(findConversation("reload-mode-active")).toBeDefined();
|
|
152
|
+
expect(abortedParents).toEqual([]);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
test("keeps a Live voice residency lease until the socket releases it", () => {
|
|
156
|
+
const resident = register("reload-live-voice", {
|
|
157
|
+
processing: false,
|
|
158
|
+
queued: false,
|
|
159
|
+
});
|
|
160
|
+
const release = Conversation.prototype.acquireLiveVoiceResidency.call(
|
|
161
|
+
resident as unknown as Conversation,
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
evictConversationsForReload();
|
|
165
|
+
|
|
166
|
+
expect(resident.disposed).toBe(false);
|
|
167
|
+
expect(resident.markedStale).toBe(true);
|
|
168
|
+
expect(findConversation("reload-live-voice")).toBeDefined();
|
|
169
|
+
|
|
170
|
+
release();
|
|
171
|
+
evictConversationsForReload();
|
|
172
|
+
|
|
173
|
+
expect(resident.disposed).toBe(true);
|
|
174
|
+
expect(findConversation("reload-live-voice")).toBeUndefined();
|
|
175
|
+
});
|
|
176
|
+
|
|
128
177
|
test("still evicts other idle conversations when one parent is protected", () => {
|
|
129
178
|
const protectedParent = register("reload-protected", {
|
|
130
179
|
processing: false,
|
|
@@ -73,6 +73,22 @@ describe("sendGuardianExpiryNotices", () => {
|
|
|
73
73
|
expect(deliveredMessages[1].body.chatId).toBe("chat-456");
|
|
74
74
|
});
|
|
75
75
|
|
|
76
|
+
test("opens the guardian's DM for a Discord delivery addressed to their user id", async () => {
|
|
77
|
+
await sendGuardianExpiryNotices(
|
|
78
|
+
[
|
|
79
|
+
makeDelivery({
|
|
80
|
+
destinationChannel: "discord",
|
|
81
|
+
destinationChatId: "111111111111111111",
|
|
82
|
+
}),
|
|
83
|
+
],
|
|
84
|
+
"assistant-1",
|
|
85
|
+
);
|
|
86
|
+
|
|
87
|
+
expect(deliveredMessages).toHaveLength(1);
|
|
88
|
+
expect(deliveredMessages[0].url).toBe("/deliver/discord?dm=1");
|
|
89
|
+
expect(deliveredMessages[0].body.chatId).toBe("111111111111111111");
|
|
90
|
+
});
|
|
91
|
+
|
|
76
92
|
test("skips deliveries that are not sent or pending", async () => {
|
|
77
93
|
await sendGuardianExpiryNotices(
|
|
78
94
|
[
|
|
@@ -158,6 +158,7 @@ describe("guardian-dispatch", () => {
|
|
|
158
158
|
ensureConversation(convId);
|
|
159
159
|
|
|
160
160
|
const session = createCallSession({
|
|
161
|
+
direction: "inbound",
|
|
161
162
|
conversationId: convId,
|
|
162
163
|
provider: "twilio",
|
|
163
164
|
fromNumber: "+15550001111",
|
|
@@ -209,6 +210,7 @@ describe("guardian-dispatch", () => {
|
|
|
209
210
|
ensureConversation(convId);
|
|
210
211
|
|
|
211
212
|
const session = createCallSession({
|
|
213
|
+
direction: "inbound",
|
|
212
214
|
conversationId: convId,
|
|
213
215
|
provider: "twilio",
|
|
214
216
|
fromNumber: "+15550001111",
|
|
@@ -238,6 +240,7 @@ describe("guardian-dispatch", () => {
|
|
|
238
240
|
ensureConversation(convId);
|
|
239
241
|
|
|
240
242
|
const session = createCallSession({
|
|
243
|
+
direction: "inbound",
|
|
241
244
|
conversationId: convId,
|
|
242
245
|
provider: "twilio",
|
|
243
246
|
fromNumber: "+15550001111",
|
|
@@ -282,6 +285,7 @@ describe("guardian-dispatch", () => {
|
|
|
282
285
|
};
|
|
283
286
|
|
|
284
287
|
const session = createCallSession({
|
|
288
|
+
direction: "inbound",
|
|
285
289
|
conversationId: convId,
|
|
286
290
|
provider: "twilio",
|
|
287
291
|
fromNumber: "+15550001111",
|
|
@@ -324,6 +328,7 @@ describe("guardian-dispatch", () => {
|
|
|
324
328
|
};
|
|
325
329
|
|
|
326
330
|
const session = createCallSession({
|
|
331
|
+
direction: "inbound",
|
|
327
332
|
conversationId: convId,
|
|
328
333
|
provider: "twilio",
|
|
329
334
|
fromNumber: "+15550001111",
|
|
@@ -369,6 +374,7 @@ describe("guardian-dispatch", () => {
|
|
|
369
374
|
};
|
|
370
375
|
|
|
371
376
|
const session = createCallSession({
|
|
377
|
+
direction: "inbound",
|
|
372
378
|
conversationId: convId,
|
|
373
379
|
provider: "twilio",
|
|
374
380
|
fromNumber: "+15550001111",
|
|
@@ -396,6 +402,7 @@ describe("guardian-dispatch", () => {
|
|
|
396
402
|
ensureConversation(convId);
|
|
397
403
|
|
|
398
404
|
const session = createCallSession({
|
|
405
|
+
direction: "inbound",
|
|
399
406
|
conversationId: convId,
|
|
400
407
|
provider: "twilio",
|
|
401
408
|
fromNumber: "+15550001111",
|
|
@@ -431,6 +438,7 @@ describe("guardian-dispatch", () => {
|
|
|
431
438
|
ensureConversation(convId);
|
|
432
439
|
|
|
433
440
|
const session = createCallSession({
|
|
441
|
+
direction: "inbound",
|
|
434
442
|
conversationId: convId,
|
|
435
443
|
provider: "twilio",
|
|
436
444
|
fromNumber: "+15550001111",
|
|
@@ -456,6 +464,7 @@ describe("guardian-dispatch", () => {
|
|
|
456
464
|
ensureConversation(convId);
|
|
457
465
|
|
|
458
466
|
const session = createCallSession({
|
|
467
|
+
direction: "inbound",
|
|
459
468
|
conversationId: convId,
|
|
460
469
|
provider: "twilio",
|
|
461
470
|
fromNumber: "+15550001111",
|
|
@@ -488,6 +497,7 @@ describe("guardian-dispatch", () => {
|
|
|
488
497
|
const sharedConversationId = "conv-shared-guardian";
|
|
489
498
|
|
|
490
499
|
const session = createCallSession({
|
|
500
|
+
direction: "inbound",
|
|
491
501
|
conversationId: convId,
|
|
492
502
|
provider: "twilio",
|
|
493
503
|
fromNumber: "+15550001111",
|
|
@@ -576,6 +586,7 @@ describe("guardian-dispatch", () => {
|
|
|
576
586
|
const sharedConversationId = "conv-affinity-guardian";
|
|
577
587
|
|
|
578
588
|
const session = createCallSession({
|
|
589
|
+
direction: "inbound",
|
|
579
590
|
conversationId: convId,
|
|
580
591
|
provider: "twilio",
|
|
581
592
|
fromNumber: "+15550001111",
|
|
@@ -648,6 +659,7 @@ describe("guardian-dispatch", () => {
|
|
|
648
659
|
const sharedConversationId = "conv-affinity-tool-guardian";
|
|
649
660
|
|
|
650
661
|
const session = createCallSession({
|
|
662
|
+
direction: "inbound",
|
|
651
663
|
conversationId: convId,
|
|
652
664
|
provider: "twilio",
|
|
653
665
|
fromNumber: "+15550001111",
|
|
@@ -727,6 +739,7 @@ describe("guardian-dispatch", () => {
|
|
|
727
739
|
const sharedConversationId = "conv-affinity-triple";
|
|
728
740
|
|
|
729
741
|
const session = createCallSession({
|
|
742
|
+
direction: "inbound",
|
|
730
743
|
conversationId: convId,
|
|
731
744
|
provider: "twilio",
|
|
732
745
|
fromNumber: "+15550001111",
|
|
@@ -163,7 +163,7 @@ function resetMockPage() {
|
|
|
163
163
|
*/
|
|
164
164
|
function defaultCdpHandler(
|
|
165
165
|
method: string,
|
|
166
|
-
|
|
166
|
+
params: Record<string, unknown> | undefined,
|
|
167
167
|
): unknown {
|
|
168
168
|
switch (method) {
|
|
169
169
|
case "DOM.getDocument":
|
|
@@ -177,12 +177,28 @@ function defaultCdpHandler(
|
|
|
177
177
|
case "Runtime.evaluate":
|
|
178
178
|
return { result: { value: { w: 800, h: 600 } } };
|
|
179
179
|
case "Runtime.callFunctionOn":
|
|
180
|
+
if (
|
|
181
|
+
params?.returnByValue === true &&
|
|
182
|
+
String(params.functionDeclaration).includes("isConnected")
|
|
183
|
+
) {
|
|
184
|
+
return {
|
|
185
|
+
result: { value: { connected: true, matches: true } },
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
if (
|
|
189
|
+
params?.returnByValue === true &&
|
|
190
|
+
String(params.functionDeclaration).includes("clearFirst")
|
|
191
|
+
) {
|
|
192
|
+
return { result: { value: { needsRefocus: false } } };
|
|
193
|
+
}
|
|
180
194
|
// executeBrowserSelectOption invokes a function that returns
|
|
181
195
|
// a `matched` boolean — default to true so wrapper-contract
|
|
182
196
|
// tests don't need to know the inner select-option matching
|
|
183
197
|
// shape. Tests that exercise the no-match path override the
|
|
184
198
|
// handler explicitly.
|
|
185
199
|
return { result: { value: true } };
|
|
200
|
+
case "Input.insertText":
|
|
201
|
+
return {};
|
|
186
202
|
default:
|
|
187
203
|
return {};
|
|
188
204
|
}
|
|
@@ -485,20 +501,21 @@ describe("executeBrowserType", () => {
|
|
|
485
501
|
expect(result.content).toContain('Typed into element: element_id "e3"');
|
|
486
502
|
expect(result.content).toContain("cleared existing content");
|
|
487
503
|
|
|
488
|
-
//
|
|
489
|
-
//
|
|
490
|
-
// DOM.focus → Input.insertText
|
|
504
|
+
// The editor selection precedes insertion, and a live-node read verifies
|
|
505
|
+
// that the requested text persisted.
|
|
491
506
|
const methods = sendCalls.map((c) => c.method);
|
|
492
507
|
expect(methods).toEqual([
|
|
493
508
|
"DOM.focus",
|
|
494
509
|
"DOM.resolveNode",
|
|
495
510
|
"Runtime.callFunctionOn",
|
|
496
|
-
"DOM.focus",
|
|
497
511
|
"Input.insertText",
|
|
512
|
+
"Runtime.callFunctionOn",
|
|
498
513
|
]);
|
|
499
514
|
const focusCall = sendCalls[0]!;
|
|
500
515
|
expect(focusCall.params).toEqual({ backendNodeId: 555 });
|
|
501
|
-
const insertCall = sendCalls
|
|
516
|
+
const insertCall = sendCalls.find(
|
|
517
|
+
(call) => call.method === "Input.insertText",
|
|
518
|
+
)!;
|
|
502
519
|
expect(insertCall.params).toEqual({ text: "hello" });
|
|
503
520
|
});
|
|
504
521
|
|
|
@@ -524,11 +541,10 @@ describe("executeBrowserType", () => {
|
|
|
524
541
|
);
|
|
525
542
|
expect(result.isError).toBe(false);
|
|
526
543
|
expect(result.content).not.toContain("cleared");
|
|
527
|
-
//
|
|
528
|
-
// and the re-focus call, so we should see focus + insertText only.
|
|
544
|
+
// Append mode collapses the editor selection at the end before insertion.
|
|
529
545
|
const methods = sendCalls.map((c) => c.method);
|
|
530
|
-
expect(methods).
|
|
531
|
-
expect(methods).
|
|
546
|
+
expect(methods).toContain("DOM.resolveNode");
|
|
547
|
+
expect(methods).toContain("Runtime.callFunctionOn");
|
|
532
548
|
const focusCount = methods.filter((m) => m === "DOM.focus").length;
|
|
533
549
|
expect(focusCount).toBe(1);
|
|
534
550
|
expect(methods).toContain("Input.insertText");
|
|
@@ -542,22 +558,22 @@ describe("executeBrowserType", () => {
|
|
|
542
558
|
expect(result.isError).toBe(false);
|
|
543
559
|
expect(result.content).toContain("pressed Enter");
|
|
544
560
|
const methods = sendCalls.map((c) => c.method);
|
|
545
|
-
// Input.insertText must come before the Enter
|
|
561
|
+
// Input.insertText must come before the Enter rawKeyDown/char/keyUp.
|
|
546
562
|
const insertIdx = methods.indexOf("Input.insertText");
|
|
547
563
|
const keyDownIdx = methods.findIndex(
|
|
548
564
|
(m, i) =>
|
|
549
565
|
m === "Input.dispatchKeyEvent" &&
|
|
550
|
-
(sendCalls[i]!.params as { type: string }).type === "
|
|
566
|
+
(sendCalls[i]!.params as { type: string }).type === "rawKeyDown",
|
|
551
567
|
);
|
|
552
568
|
expect(insertIdx).toBeGreaterThanOrEqual(0);
|
|
553
569
|
expect(keyDownIdx).toBeGreaterThan(insertIdx);
|
|
554
|
-
// Enter is text-producing
|
|
570
|
+
// Enter is text-producing, so it emits rawKeyDown + char + keyUp.
|
|
555
571
|
const keyEvents = sendCalls.filter(
|
|
556
572
|
(c) => c.method === "Input.dispatchKeyEvent",
|
|
557
573
|
);
|
|
558
574
|
expect(keyEvents).toHaveLength(3);
|
|
559
575
|
expect((keyEvents[0]!.params as { key: string }).key).toBe("Enter");
|
|
560
|
-
expect((keyEvents[0]!.params as { type: string }).type).toBe("
|
|
576
|
+
expect((keyEvents[0]!.params as { type: string }).type).toBe("rawKeyDown");
|
|
561
577
|
expect((keyEvents[1]!.params as { type: string }).type).toBe("char");
|
|
562
578
|
expect((keyEvents[2]!.params as { type: string }).type).toBe("keyUp");
|
|
563
579
|
});
|
|
@@ -689,7 +705,7 @@ describe("executeBrowserPressKey", () => {
|
|
|
689
705
|
expect(result.content).toContain('Pressed "Enter"');
|
|
690
706
|
// No target => no DOM.focus, no selector resolution. Enter is a
|
|
691
707
|
// text-producing key (text "\r") so dispatchKeyPress emits
|
|
692
|
-
//
|
|
708
|
+
// rawKeyDown + char + keyUp.
|
|
693
709
|
const methods = sendCalls.map((c) => c.method);
|
|
694
710
|
expect(methods).toEqual([
|
|
695
711
|
"Input.dispatchKeyEvent",
|
|
@@ -699,7 +715,7 @@ describe("executeBrowserPressKey", () => {
|
|
|
699
715
|
const keyDown = sendCalls[0]!.params as Record<string, unknown>;
|
|
700
716
|
const charEvt = sendCalls[1]!.params as Record<string, unknown>;
|
|
701
717
|
const keyUp = sendCalls[2]!.params as Record<string, unknown>;
|
|
702
|
-
expect(keyDown.type).toBe("
|
|
718
|
+
expect(keyDown.type).toBe("rawKeyDown");
|
|
703
719
|
expect(keyDown.key).toBe("Enter");
|
|
704
720
|
expect(keyDown.windowsVirtualKeyCode).toBe(13);
|
|
705
721
|
expect(charEvt.type).toBe("char");
|
|
@@ -707,6 +723,36 @@ describe("executeBrowserPressKey", () => {
|
|
|
707
723
|
expect(keyUp.key).toBe("Enter");
|
|
708
724
|
});
|
|
709
725
|
|
|
726
|
+
test("presses modifier chords on the focused element", async () => {
|
|
727
|
+
const result = await executeBrowserPressKey({ key: "Meta+v" }, ctx);
|
|
728
|
+
expect(result.isError).toBe(false);
|
|
729
|
+
expect(result.content).toContain('Pressed "Meta+v"');
|
|
730
|
+
|
|
731
|
+
const keyEvents = sendCalls.filter(
|
|
732
|
+
(call) => call.method === "Input.dispatchKeyEvent",
|
|
733
|
+
);
|
|
734
|
+
expect(keyEvents).toHaveLength(4);
|
|
735
|
+
expect(keyEvents[0]!.params).toMatchObject({
|
|
736
|
+
type: "rawKeyDown",
|
|
737
|
+
key: "Meta",
|
|
738
|
+
modifiers: 4,
|
|
739
|
+
});
|
|
740
|
+
expect(keyEvents[1]!.params).toMatchObject({
|
|
741
|
+
type: "rawKeyDown",
|
|
742
|
+
key: "v",
|
|
743
|
+
modifiers: 4,
|
|
744
|
+
});
|
|
745
|
+
expect(keyEvents[2]!.params).toMatchObject({
|
|
746
|
+
type: "keyUp",
|
|
747
|
+
key: "v",
|
|
748
|
+
modifiers: 4,
|
|
749
|
+
});
|
|
750
|
+
expect(keyEvents[3]!.params).toMatchObject({
|
|
751
|
+
type: "keyUp",
|
|
752
|
+
key: "Meta",
|
|
753
|
+
});
|
|
754
|
+
});
|
|
755
|
+
|
|
710
756
|
test("presses key on targeted element via element_id", async () => {
|
|
711
757
|
snapshotBackendNodeMaps.set("test-conversation", new Map([["e5", 555]]));
|
|
712
758
|
const result = await executeBrowserPressKey(
|
|
@@ -716,14 +762,12 @@ describe("executeBrowserPressKey", () => {
|
|
|
716
762
|
expect(result.isError).toBe(false);
|
|
717
763
|
expect(result.content).toContain('Pressed "Tab" on element');
|
|
718
764
|
expect(result.content).toContain('element_id "e5"');
|
|
719
|
-
// Backend-resolved path: focus
|
|
720
|
-
// text-producing so we also dispatch a char event).
|
|
765
|
+
// Backend-resolved path: focus, then Tab key down and key up.
|
|
721
766
|
const methods = sendCalls.map((c) => c.method);
|
|
722
767
|
expect(methods).toEqual([
|
|
723
768
|
"DOM.focus",
|
|
724
769
|
"Input.dispatchKeyEvent",
|
|
725
770
|
"Input.dispatchKeyEvent",
|
|
726
|
-
"Input.dispatchKeyEvent",
|
|
727
771
|
]);
|
|
728
772
|
expect(sendCalls[0]!.params).toEqual({ backendNodeId: 555 });
|
|
729
773
|
});
|
|
@@ -767,7 +811,7 @@ describe("executeBrowserPressKey", () => {
|
|
|
767
811
|
|
|
768
812
|
test("surfaces CDP failure as a press-key error", async () => {
|
|
769
813
|
sendHandler = () => new Error("Key not recognized");
|
|
770
|
-
const result = await executeBrowserPressKey({ key: "
|
|
814
|
+
const result = await executeBrowserPressKey({ key: "Enter" }, ctx);
|
|
771
815
|
expect(result.isError).toBe(true);
|
|
772
816
|
expect(result.content).toContain("Press key failed");
|
|
773
817
|
expect(result.content).toContain("Key not recognized");
|
|
@@ -334,11 +334,10 @@ const SCAFFOLD_PERSONA = stripCommentLines(GUARDIAN_PERSONA_TEMPLATE).trim();
|
|
|
334
334
|
const { resolveCallSiteConfig } = await import("../config/llm-resolver.js");
|
|
335
335
|
const { LLMSchema } = await import("../config/schemas/llm.js");
|
|
336
336
|
|
|
337
|
-
// Capture broadcastMessage so tests can observe the
|
|
338
|
-
//
|
|
337
|
+
// Capture broadcastMessage so tests can observe the conversation-created
|
|
338
|
+
// events the heartbeat service emits directly.
|
|
339
339
|
type BroadcastedMessage = { type: string; [key: string]: unknown };
|
|
340
340
|
const broadcastedMessages: BroadcastedMessage[] = [];
|
|
341
|
-
let onBroadcast: ((msg: BroadcastedMessage) => void) | null = null;
|
|
342
341
|
|
|
343
342
|
mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
344
343
|
assistantEventHub: {
|
|
@@ -347,7 +346,6 @@ mock.module("../runtime/assistant-event-hub.js", () => ({
|
|
|
347
346
|
},
|
|
348
347
|
broadcastMessage: (msg: BroadcastedMessage) => {
|
|
349
348
|
broadcastedMessages.push(msg);
|
|
350
|
-
onBroadcast?.(msg);
|
|
351
349
|
},
|
|
352
350
|
}));
|
|
353
351
|
|
|
@@ -357,7 +355,6 @@ describe("HeartbeatService", () => {
|
|
|
357
355
|
content: string;
|
|
358
356
|
options?: { callSite?: string };
|
|
359
357
|
}>;
|
|
360
|
-
let alerterCalls: Array<{ type: string; title: string; body: string }>;
|
|
361
358
|
|
|
362
359
|
afterEach(() => {
|
|
363
360
|
// Clean up workspace files between tests so file-existence tests don't leak
|
|
@@ -368,13 +365,7 @@ describe("HeartbeatService", () => {
|
|
|
368
365
|
|
|
369
366
|
beforeEach(() => {
|
|
370
367
|
processMessageCalls = [];
|
|
371
|
-
alerterCalls = [];
|
|
372
368
|
broadcastedMessages.length = 0;
|
|
373
|
-
onBroadcast = (msg) => {
|
|
374
|
-
if (msg.type === "heartbeat_alert") {
|
|
375
|
-
alerterCalls.push(msg as { type: string; title: string; body: string });
|
|
376
|
-
}
|
|
377
|
-
};
|
|
378
369
|
createdConversations.length = 0;
|
|
379
370
|
conversationIdCounter = 0;
|
|
380
371
|
mockStoredMessages.length = 0;
|
|
@@ -693,21 +684,6 @@ describe("HeartbeatService", () => {
|
|
|
693
684
|
expect(processMessageCalls).toHaveLength(1);
|
|
694
685
|
});
|
|
695
686
|
|
|
696
|
-
test("alerts on processMessage failure", async () => {
|
|
697
|
-
const service = createService({
|
|
698
|
-
processMessage: async () => {
|
|
699
|
-
throw new Error("LLM timeout");
|
|
700
|
-
},
|
|
701
|
-
});
|
|
702
|
-
|
|
703
|
-
await service.runOnce();
|
|
704
|
-
|
|
705
|
-
expect(alerterCalls).toHaveLength(1);
|
|
706
|
-
expect(alerterCalls[0].type).toBe("heartbeat_alert");
|
|
707
|
-
expect(alerterCalls[0].title).toBe("Heartbeat Failed");
|
|
708
|
-
expect(alerterCalls[0].body).toBe("LLM timeout");
|
|
709
|
-
});
|
|
710
|
-
|
|
711
687
|
test("successful run updates lastRunAt and nextRunAt", async () => {
|
|
712
688
|
const service = createService();
|
|
713
689
|
expect(service.lastRunAt).toBeNull();
|
|
@@ -724,24 +700,6 @@ describe("HeartbeatService", () => {
|
|
|
724
700
|
);
|
|
725
701
|
});
|
|
726
702
|
|
|
727
|
-
test("alerts on conversation creation failure", async () => {
|
|
728
|
-
// Override createConversation to throw via a fresh import trick:
|
|
729
|
-
// Since createConversation is mocked at module level, we simulate
|
|
730
|
-
// this by having processMessage throw before it's called — but the
|
|
731
|
-
// real fix is that executeRun wraps createConversation in the try/catch.
|
|
732
|
-
// We verify by checking that any error in executeRun triggers the alert.
|
|
733
|
-
const service = createService({
|
|
734
|
-
processMessage: async () => {
|
|
735
|
-
throw new Error("DB locked");
|
|
736
|
-
},
|
|
737
|
-
});
|
|
738
|
-
|
|
739
|
-
await service.runOnce();
|
|
740
|
-
|
|
741
|
-
expect(alerterCalls).toHaveLength(1);
|
|
742
|
-
expect(alerterCalls[0].body).toBe("DB locked");
|
|
743
|
-
});
|
|
744
|
-
|
|
745
703
|
test("resetTimer() pushes nextRunAt forward", () => {
|
|
746
704
|
const service = createService();
|
|
747
705
|
service.start();
|
|
@@ -1467,21 +1425,6 @@ describe("HeartbeatService", () => {
|
|
|
1467
1425
|
});
|
|
1468
1426
|
});
|
|
1469
1427
|
|
|
1470
|
-
test("CAS false suppresses failure alerter and feed event", async () => {
|
|
1471
|
-
mockCompleteHeartbeatRun.mockImplementation(() => false);
|
|
1472
|
-
|
|
1473
|
-
const service = createService({
|
|
1474
|
-
processMessage: async () => {
|
|
1475
|
-
throw new Error("LLM timeout");
|
|
1476
|
-
},
|
|
1477
|
-
});
|
|
1478
|
-
|
|
1479
|
-
await service.runOnce();
|
|
1480
|
-
|
|
1481
|
-
// completeHeartbeatRun returned false, so alerter should NOT be called
|
|
1482
|
-
expect(alerterCalls).toHaveLength(0);
|
|
1483
|
-
});
|
|
1484
|
-
|
|
1485
1428
|
test("active-hours skip calls skipHeartbeatRun", async () => {
|
|
1486
1429
|
setHeartbeatConfig({ activeHoursStart: 9, activeHoursEnd: 17 });
|
|
1487
1430
|
|
|
@@ -18,6 +18,26 @@
|
|
|
18
18
|
import type { Conversation } from "../../daemon/conversation.js";
|
|
19
19
|
import type { ChannelCapabilities } from "../../daemon/conversation-runtime-assembly.js";
|
|
20
20
|
|
|
21
|
+
/** Build a coordinator double representing a turn with no mode owner. */
|
|
22
|
+
export function mockUnownedModeSessions(): Conversation["modeSessions"] {
|
|
23
|
+
return {
|
|
24
|
+
acceptTurn: () => undefined,
|
|
25
|
+
getTurnOwner: () => undefined,
|
|
26
|
+
getTerminalDisposition: () => undefined,
|
|
27
|
+
hasResidentWork: () => false,
|
|
28
|
+
keepsSessionOpenAfterTurn: () => false,
|
|
29
|
+
trackPersistedRow: () => false,
|
|
30
|
+
recordStructuralWait: () => false,
|
|
31
|
+
invalidateStructuralWait: () => false,
|
|
32
|
+
settleStructuralWait: () => false,
|
|
33
|
+
invalidateAllStructuralWaits: () => 0,
|
|
34
|
+
beginDraining: () => false,
|
|
35
|
+
finalizeTurn: () => false,
|
|
36
|
+
releaseTurn: () => {},
|
|
37
|
+
transferTurn: () => undefined,
|
|
38
|
+
} as unknown as Conversation["modeSessions"];
|
|
39
|
+
}
|
|
40
|
+
|
|
21
41
|
/**
|
|
22
42
|
* `TExtra` carries test-only fields a double hangs off the same object
|
|
23
43
|
* (recorded calls, captured messages) through to the return type, so a caller
|
|
@@ -38,6 +58,7 @@ export function asConversation<TExtra extends object = object>(
|
|
|
38
58
|
merged.currentTurnTrustContext ?? merged.trustContext,
|
|
39
59
|
isStale: () => false,
|
|
40
60
|
hasInFlightWork: () => false,
|
|
61
|
+
modeSessions: mockUnownedModeSessions(),
|
|
41
62
|
...mock,
|
|
42
63
|
};
|
|
43
64
|
return merged as unknown as Conversation & TExtra;
|
|
@@ -20,6 +20,7 @@ import type {
|
|
|
20
20
|
EventHandlerState,
|
|
21
21
|
} from "../../daemon/conversation-agent-loop-handlers.js";
|
|
22
22
|
import { dispatchAgentEvent } from "../../daemon/conversation-agent-loop-handlers.js";
|
|
23
|
+
import { mockUnownedModeSessions } from "./mock-conversation.js";
|
|
23
24
|
|
|
24
25
|
/** A `tool_result` `AssistantEvent` emitted by the handler. */
|
|
25
26
|
export type ToolResultEvent = Extract<AssistantEvent, { type: "tool_result" }>;
|
|
@@ -59,6 +60,7 @@ export function createHandlerDeps(reqId = "req-web-search"): HandlerHarness {
|
|
|
59
60
|
emitActivityState: () => {},
|
|
60
61
|
markWorkspaceTopLevelDirty: () => {},
|
|
61
62
|
currentTurnSurfaces: [],
|
|
63
|
+
modeSessions: mockUnownedModeSessions(),
|
|
62
64
|
} as unknown as EventHandlerDeps["ctx"],
|
|
63
65
|
onEvent: (msg: AssistantEvent) => events.push(msg),
|
|
64
66
|
reqId,
|
|
@@ -276,6 +276,11 @@ export function createOutboundSessionGuarded(
|
|
|
276
276
|
}
|
|
277
277
|
source.status = "revoked";
|
|
278
278
|
source.updatedAt = Date.now();
|
|
279
|
+
// Like the gateway, the replacement keeps the claimed session's purpose.
|
|
280
|
+
return createOutboundSession({
|
|
281
|
+
...createParams,
|
|
282
|
+
verificationPurpose: source.verificationPurpose,
|
|
283
|
+
});
|
|
279
284
|
}
|
|
280
285
|
|
|
281
286
|
return createOutboundSession(createParams);
|
|
@@ -464,6 +464,43 @@ describe("HostCuProxy", () => {
|
|
|
464
464
|
const result = await resultPromise;
|
|
465
465
|
expect(result.isError).toBe(false);
|
|
466
466
|
});
|
|
467
|
+
|
|
468
|
+
test("runs the lifecycle callback only for a validated dispatch", async () => {
|
|
469
|
+
setup(0);
|
|
470
|
+
const rejectedCallback = mock(() => {});
|
|
471
|
+
proxy.recordAction("computer_use_click", { element_id: 1 });
|
|
472
|
+
const rejected = await proxy.request(
|
|
473
|
+
"computer_use_click",
|
|
474
|
+
{ element_id: 1 },
|
|
475
|
+
"session-1",
|
|
476
|
+
proxy.stepCount,
|
|
477
|
+
undefined,
|
|
478
|
+
undefined,
|
|
479
|
+
undefined,
|
|
480
|
+
undefined,
|
|
481
|
+
rejectedCallback,
|
|
482
|
+
);
|
|
483
|
+
expect(rejected.isError).toBe(true);
|
|
484
|
+
expect(rejectedCallback).not.toHaveBeenCalled();
|
|
485
|
+
|
|
486
|
+
setup();
|
|
487
|
+
const acceptedCallback = mock(() => {});
|
|
488
|
+
const pending = proxy.request(
|
|
489
|
+
"computer_use_click",
|
|
490
|
+
{ element_id: 1 },
|
|
491
|
+
"session-1",
|
|
492
|
+
1,
|
|
493
|
+
undefined,
|
|
494
|
+
undefined,
|
|
495
|
+
undefined,
|
|
496
|
+
undefined,
|
|
497
|
+
acceptedCallback,
|
|
498
|
+
);
|
|
499
|
+
expect(acceptedCallback).toHaveBeenCalledTimes(1);
|
|
500
|
+
const requestId = (sentMessages[0] as { requestId: string }).requestId;
|
|
501
|
+
proxy.processObservation(requestId, { executionResult: "Clicked" });
|
|
502
|
+
await pending;
|
|
503
|
+
});
|
|
467
504
|
});
|
|
468
505
|
|
|
469
506
|
// -------------------------------------------------------------------------
|
|
@@ -1333,7 +1370,13 @@ describe("HostCuProxy", () => {
|
|
|
1333
1370
|
proxy.processObservation(requestId, { axTree: "Button [1]" });
|
|
1334
1371
|
await resultPromise;
|
|
1335
1372
|
|
|
1336
|
-
proxy.
|
|
1373
|
+
const sourceId = proxy.sourceId;
|
|
1374
|
+
expect(sourceId).not.toBe("");
|
|
1375
|
+
expect(proxy.resetGeneration).toBe(0);
|
|
1376
|
+
|
|
1377
|
+
expect(proxy.endTask("session-1")).toBe(0);
|
|
1378
|
+
expect(proxy.sourceId).toBe(sourceId);
|
|
1379
|
+
expect(proxy.resetGeneration).toBe(1);
|
|
1337
1380
|
const cancels = sentMessages.filter(
|
|
1338
1381
|
(m) => (m as Record<string, unknown>).type === "host_cu_cancel",
|
|
1339
1382
|
) as Array<Record<string, unknown>>;
|
|
@@ -1341,7 +1384,8 @@ describe("HostCuProxy", () => {
|
|
|
1341
1384
|
expect(cancels[0].conversationId).toBe("session-1");
|
|
1342
1385
|
expect(cancels[0].requestId).not.toBe(requestId);
|
|
1343
1386
|
|
|
1344
|
-
proxy.endTask("session-1");
|
|
1387
|
+
expect(proxy.endTask("session-1")).toBe(1);
|
|
1388
|
+
expect(proxy.resetGeneration).toBe(2);
|
|
1345
1389
|
expect(
|
|
1346
1390
|
sentMessages.filter(
|
|
1347
1391
|
(m) => (m as Record<string, unknown>).type === "host_cu_cancel",
|
|
@@ -161,6 +161,7 @@ mock.module("../runtime/trust-context-resolver.js", () => ({
|
|
|
161
161
|
import type { AuthContext } from "../runtime/auth/types.js";
|
|
162
162
|
import { handleSendMessage } from "../runtime/routes/conversation-routes.js";
|
|
163
163
|
import { callHandler } from "./helpers/call-route-handler.js";
|
|
164
|
+
import { mockUnownedModeSessions } from "./helpers/mock-conversation.js";
|
|
164
165
|
|
|
165
166
|
const _testAuthContext: AuthContext = {
|
|
166
167
|
subject: "actor:self:test-actor",
|
|
@@ -194,6 +195,7 @@ function makeConversation(overrides: Record<string, unknown> = {}) {
|
|
|
194
195
|
setHostCuProxy: () => {},
|
|
195
196
|
setHostAppControlProxy: () => {},
|
|
196
197
|
addPreactivatedSkillId: () => {},
|
|
198
|
+
modeSessions: mockUnownedModeSessions(),
|
|
197
199
|
emitConfirmationStateChanged: () => {},
|
|
198
200
|
emitActivityState: () => {},
|
|
199
201
|
setTurnChannelContext: () => {},
|