@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
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
ModeSessionSchema,
|
|
5
|
+
ModeSessionStatusSchema,
|
|
6
|
+
ModeSessionSummarySchema,
|
|
7
|
+
} from "./mode-session.js";
|
|
8
|
+
|
|
9
|
+
describe("mode session API schemas", () => {
|
|
10
|
+
test("accepts canonical membership", () => {
|
|
11
|
+
expect(
|
|
12
|
+
ModeSessionSchema.parse({ id: "session-123", mode: "browser" }),
|
|
13
|
+
).toEqual({ id: "session-123", mode: "browser" });
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("keeps persisted status to the three lifecycle states", () => {
|
|
17
|
+
expect(ModeSessionStatusSchema.options).toEqual([
|
|
18
|
+
"active",
|
|
19
|
+
"completed",
|
|
20
|
+
"interrupted",
|
|
21
|
+
]);
|
|
22
|
+
expect(ModeSessionStatusSchema.safeParse("waiting").success).toBe(false);
|
|
23
|
+
expect(ModeSessionStatusSchema.safeParse("draining").success).toBe(false);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("accepts an interrupted summary with unknown end time", () => {
|
|
27
|
+
const summary = ModeSessionSummarySchema.parse({
|
|
28
|
+
id: "session-123",
|
|
29
|
+
conversationId: "conv-123",
|
|
30
|
+
mode: "computer_use",
|
|
31
|
+
status: "interrupted",
|
|
32
|
+
sourceStartedAt: 100,
|
|
33
|
+
firstIncludedAt: 110,
|
|
34
|
+
firstIncludedMessageId: "message-123",
|
|
35
|
+
lastActivityAt: 125,
|
|
36
|
+
lastOwnedMessageId: "message-456",
|
|
37
|
+
endedAt: null,
|
|
38
|
+
endReason: "assistant_restarted",
|
|
39
|
+
revision: 4,
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
expect(summary.endedAt).toBeNull();
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("rejects unknown historic modes and invalid revisions", () => {
|
|
46
|
+
const base = {
|
|
47
|
+
id: "session-123",
|
|
48
|
+
conversationId: "conv-123",
|
|
49
|
+
status: "active",
|
|
50
|
+
sourceStartedAt: 100,
|
|
51
|
+
firstIncludedAt: null,
|
|
52
|
+
firstIncludedMessageId: null,
|
|
53
|
+
lastActivityAt: 100,
|
|
54
|
+
lastOwnedMessageId: null,
|
|
55
|
+
endedAt: null,
|
|
56
|
+
endReason: null,
|
|
57
|
+
};
|
|
58
|
+
expect(
|
|
59
|
+
ModeSessionSummarySchema.safeParse({
|
|
60
|
+
...base,
|
|
61
|
+
mode: "unknown_mode",
|
|
62
|
+
revision: 1,
|
|
63
|
+
}).success,
|
|
64
|
+
).toBe(false);
|
|
65
|
+
expect(
|
|
66
|
+
ModeSessionSummarySchema.safeParse({
|
|
67
|
+
...base,
|
|
68
|
+
mode: "ambient",
|
|
69
|
+
revision: 0,
|
|
70
|
+
}).success,
|
|
71
|
+
).toBe(false);
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("enforces status-specific terminal timing", () => {
|
|
75
|
+
const base = {
|
|
76
|
+
id: "session-123",
|
|
77
|
+
conversationId: "conv-123",
|
|
78
|
+
mode: "browser",
|
|
79
|
+
sourceStartedAt: 100,
|
|
80
|
+
firstIncludedAt: null,
|
|
81
|
+
firstIncludedMessageId: null,
|
|
82
|
+
lastActivityAt: 125,
|
|
83
|
+
lastOwnedMessageId: null,
|
|
84
|
+
revision: 1,
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
expect(
|
|
88
|
+
ModeSessionSummarySchema.safeParse({
|
|
89
|
+
...base,
|
|
90
|
+
status: "active",
|
|
91
|
+
endedAt: 150,
|
|
92
|
+
endReason: "settled",
|
|
93
|
+
}).success,
|
|
94
|
+
).toBe(false);
|
|
95
|
+
expect(
|
|
96
|
+
ModeSessionSummarySchema.safeParse({
|
|
97
|
+
...base,
|
|
98
|
+
status: "completed",
|
|
99
|
+
endedAt: null,
|
|
100
|
+
endReason: "settled",
|
|
101
|
+
}).success,
|
|
102
|
+
).toBe(false);
|
|
103
|
+
expect(
|
|
104
|
+
ModeSessionSummarySchema.safeParse({
|
|
105
|
+
...base,
|
|
106
|
+
status: "completed",
|
|
107
|
+
endedAt: 120,
|
|
108
|
+
endReason: "settled",
|
|
109
|
+
}).success,
|
|
110
|
+
).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
test("keeps display boundary fields paired", () => {
|
|
114
|
+
expect(
|
|
115
|
+
ModeSessionSummarySchema.safeParse({
|
|
116
|
+
id: "session-123",
|
|
117
|
+
conversationId: "conv-123",
|
|
118
|
+
mode: "ambient",
|
|
119
|
+
status: "active",
|
|
120
|
+
sourceStartedAt: 100,
|
|
121
|
+
firstIncludedAt: 110,
|
|
122
|
+
firstIncludedMessageId: null,
|
|
123
|
+
lastActivityAt: 125,
|
|
124
|
+
lastOwnedMessageId: null,
|
|
125
|
+
endedAt: null,
|
|
126
|
+
endReason: null,
|
|
127
|
+
revision: 1,
|
|
128
|
+
}).success,
|
|
129
|
+
).toBe(false);
|
|
130
|
+
});
|
|
131
|
+
});
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
export const ModeSessionModeSchema = z.enum([
|
|
4
|
+
"computer_use",
|
|
5
|
+
"browser",
|
|
6
|
+
"live_vision",
|
|
7
|
+
"ambient",
|
|
8
|
+
]);
|
|
9
|
+
export type ModeSessionMode = z.infer<typeof ModeSessionModeSchema>;
|
|
10
|
+
|
|
11
|
+
/** Whether a stamped row may start the user-visible span for this mode. */
|
|
12
|
+
export function modeSessionRowStartsDisplay(
|
|
13
|
+
mode: ModeSessionMode,
|
|
14
|
+
startsDisplayBoundary: boolean,
|
|
15
|
+
): boolean {
|
|
16
|
+
return mode === "live_vision" || startsDisplayBoundary;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export const ModeSessionStatusSchema = z.enum([
|
|
20
|
+
"active",
|
|
21
|
+
"completed",
|
|
22
|
+
"interrupted",
|
|
23
|
+
]);
|
|
24
|
+
export type ModeSessionStatus = z.infer<typeof ModeSessionStatusSchema>;
|
|
25
|
+
|
|
26
|
+
/** Immutable ownership stamped onto transcript message metadata. */
|
|
27
|
+
export const ModeSessionSchema = z.object({
|
|
28
|
+
mode: ModeSessionModeSchema,
|
|
29
|
+
id: z.string().min(1),
|
|
30
|
+
});
|
|
31
|
+
export type ModeSession = z.infer<typeof ModeSessionSchema>;
|
|
32
|
+
|
|
33
|
+
export function parseModeSession(value: unknown): ModeSession | undefined {
|
|
34
|
+
const parsed = ModeSessionSchema.safeParse(value);
|
|
35
|
+
return parsed.success ? parsed.data : undefined;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/** Historic or caller-authored invalid stamps behave like an absent stamp. */
|
|
39
|
+
export const TolerantModeSessionSchema = z.preprocess(
|
|
40
|
+
parseModeSession,
|
|
41
|
+
ModeSessionSchema.optional(),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const MAX_DATE_MS = 8_640_000_000_000_000;
|
|
45
|
+
|
|
46
|
+
export const ModeSessionActivitySchema = z
|
|
47
|
+
.object({
|
|
48
|
+
firstAt: z.number().int().nonnegative().max(MAX_DATE_MS),
|
|
49
|
+
lastAt: z.number().int().nonnegative().max(MAX_DATE_MS),
|
|
50
|
+
})
|
|
51
|
+
.refine((activity) => activity.lastAt >= activity.firstAt, {
|
|
52
|
+
message: "Mode session activity cannot end before it starts",
|
|
53
|
+
path: ["lastAt"],
|
|
54
|
+
});
|
|
55
|
+
export type ModeSessionActivity = z.infer<typeof ModeSessionActivitySchema>;
|
|
56
|
+
|
|
57
|
+
const ModeSessionSummaryBaseSchema = z.object({
|
|
58
|
+
id: z.string().min(1),
|
|
59
|
+
conversationId: z.string().min(1),
|
|
60
|
+
mode: ModeSessionModeSchema,
|
|
61
|
+
sourceStartedAt: z.number().int().nonnegative(),
|
|
62
|
+
firstIncludedAt: z.number().int().nonnegative().nullable(),
|
|
63
|
+
firstIncludedMessageId: z.string().min(1).nullable(),
|
|
64
|
+
lastActivityAt: z.number().int().nonnegative(),
|
|
65
|
+
lastOwnedMessageId: z.string().min(1).nullable(),
|
|
66
|
+
revision: z.number().int().positive(),
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
/** Durable lifecycle summary for one conversation-owned presentation run. */
|
|
70
|
+
export const ModeSessionSummarySchema = z
|
|
71
|
+
.discriminatedUnion("status", [
|
|
72
|
+
ModeSessionSummaryBaseSchema.extend({
|
|
73
|
+
status: z.literal("active"),
|
|
74
|
+
endedAt: z.null(),
|
|
75
|
+
endReason: z.null(),
|
|
76
|
+
}),
|
|
77
|
+
ModeSessionSummaryBaseSchema.extend({
|
|
78
|
+
status: z.literal("completed"),
|
|
79
|
+
endedAt: z.number().int().nonnegative(),
|
|
80
|
+
endReason: z.string().min(1),
|
|
81
|
+
}),
|
|
82
|
+
ModeSessionSummaryBaseSchema.extend({
|
|
83
|
+
status: z.literal("interrupted"),
|
|
84
|
+
endedAt: z.number().int().nonnegative().nullable(),
|
|
85
|
+
endReason: z.string().min(1),
|
|
86
|
+
}),
|
|
87
|
+
])
|
|
88
|
+
.superRefine((summary, ctx) => {
|
|
89
|
+
if (
|
|
90
|
+
(summary.firstIncludedAt === null) !==
|
|
91
|
+
(summary.firstIncludedMessageId === null)
|
|
92
|
+
) {
|
|
93
|
+
ctx.addIssue({
|
|
94
|
+
code: "custom",
|
|
95
|
+
message: "First included time and message ID must be set together",
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (summary.endedAt !== null && summary.endedAt < summary.lastActivityAt) {
|
|
99
|
+
ctx.addIssue({
|
|
100
|
+
code: "custom",
|
|
101
|
+
message: "Mode session end cannot precede its last activity",
|
|
102
|
+
path: ["endedAt"],
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
if (summary.lastActivityAt < summary.sourceStartedAt) {
|
|
106
|
+
ctx.addIssue({
|
|
107
|
+
code: "custom",
|
|
108
|
+
message: "Last activity cannot precede source start",
|
|
109
|
+
path: ["lastActivityAt"],
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
if (
|
|
113
|
+
summary.firstIncludedAt !== null &&
|
|
114
|
+
summary.firstIncludedAt > summary.lastActivityAt
|
|
115
|
+
) {
|
|
116
|
+
ctx.addIssue({
|
|
117
|
+
code: "custom",
|
|
118
|
+
message: "First included time cannot follow last activity",
|
|
119
|
+
path: ["firstIncludedAt"],
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
export type ModeSessionSummary = z.infer<typeof ModeSessionSummarySchema>;
|
|
124
|
+
|
|
125
|
+
export const ModeSessionRuntimeStateSchema = z.enum(["waiting", "finishing"]);
|
|
126
|
+
export type ModeSessionRuntimeState = z.infer<
|
|
127
|
+
typeof ModeSessionRuntimeStateSchema
|
|
128
|
+
>;
|
|
129
|
+
|
|
130
|
+
/** Durable lifecycle truth plus optional process-local presentation state. */
|
|
131
|
+
export const ModeSessionDescriptorSchema = z
|
|
132
|
+
.object({
|
|
133
|
+
summary: ModeSessionSummarySchema,
|
|
134
|
+
runtimeState: ModeSessionRuntimeStateSchema.optional(),
|
|
135
|
+
})
|
|
136
|
+
.superRefine((descriptor, ctx) => {
|
|
137
|
+
if (
|
|
138
|
+
descriptor.runtimeState !== undefined &&
|
|
139
|
+
descriptor.summary.status !== "active"
|
|
140
|
+
) {
|
|
141
|
+
ctx.addIssue({
|
|
142
|
+
code: "custom",
|
|
143
|
+
message: "Only active mode sessions can expose runtime state",
|
|
144
|
+
path: ["runtimeState"],
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
export type ModeSessionDescriptor = z.infer<typeof ModeSessionDescriptorSchema>;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* The `remember` tool's input: what the daemon parses a call with, and what a
|
|
5
|
+
* client reads a recorded call's input with. `content` is one fact or a list
|
|
6
|
+
* of them. `finish_turn` yields the turn only when it is `true`; any other
|
|
7
|
+
* value reads as absent. Unknown keys, such as the injected `activity`, pass
|
|
8
|
+
* through.
|
|
9
|
+
*/
|
|
10
|
+
export const RememberInputSchema = z.looseObject({
|
|
11
|
+
content: z.union([z.string(), z.array(z.string()).min(1)]),
|
|
12
|
+
finish_turn: z.boolean().optional().catch(undefined),
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
export type RememberInput = z.infer<typeof RememberInputSchema>;
|
|
@@ -33,6 +33,10 @@ import {
|
|
|
33
33
|
import { AnsweredQuestionSchema } from "../events/question-answered.js";
|
|
34
34
|
import { QuestionEntrySchema } from "../events/question-request.js";
|
|
35
35
|
import { ToolActivityMetadataSchema } from "../events/tool-result.js";
|
|
36
|
+
import {
|
|
37
|
+
ModeSessionActivitySchema,
|
|
38
|
+
ModeSessionSchema,
|
|
39
|
+
} from "../mode-session.js";
|
|
36
40
|
|
|
37
41
|
// ---------------------------------------------------------------------------
|
|
38
42
|
// Attachment metadata
|
|
@@ -492,6 +496,8 @@ export type ConversationContentBlock = z.infer<
|
|
|
492
496
|
*/
|
|
493
497
|
export const ConversationMessageSchema = z.object({
|
|
494
498
|
id: z.string(),
|
|
499
|
+
modeSession: ModeSessionSchema.optional(),
|
|
500
|
+
modeSessionActivity: ModeSessionActivitySchema.optional(),
|
|
495
501
|
/**
|
|
496
502
|
* Server message ids folded into this display row when consecutive
|
|
497
503
|
* assistant messages were consolidated for history rendering.
|
package/src/approvals/AGENTS.md
CHANGED
|
@@ -11,7 +11,9 @@ The end-to-end lifecycle of interactive guardian requests (approvals, questions)
|
|
|
11
11
|
|
|
12
12
|
## Single-Guardian Invariant
|
|
13
13
|
|
|
14
|
-
Each assistant instance serves exactly one guardian. Multi-guardian is not supported and will never be.
|
|
14
|
+
Each assistant instance serves exactly one guardian. Multi-guardian is not supported and will never be. Only that guardian's principal decides guardian requests: `applyGuardianDecision()` requires it exactly. Do not introduce guardian-keyed maps, per-guardian routing logic, or multi-guardian multiplexing; they add complexity without a real use case and create the false impression that cross-guardian isolation is required.
|
|
15
|
+
|
|
16
|
+
One guardian does not mean one person connected. The event stream (`GET /v1/events`) admits any actor principal with `chat.read`, so a non-guardian actor can hold a valid connection. Routes that must be guardian-only set `requireGuardian: true`, which `routes/http-adapter.ts` enforces with `requireBoundGuardian` (`runtime/auth/require-bound-guardian.ts`). Content meant only for the guardian is scoped to the guardian's principal at delivery (`targetActorPrincipalId` on the event hub), never assumed safe because it reached a connection.
|
|
15
17
|
|
|
16
18
|
## Guardian Verification Invariant
|
|
17
19
|
|
|
@@ -21,7 +23,7 @@ Conversational guardian verification control-plane invocation is guardian-only.
|
|
|
21
23
|
|
|
22
24
|
## Memory Provenance Invariant
|
|
23
25
|
|
|
24
|
-
|
|
26
|
+
Memory access follows the acting actor's capabilities: `resolveCapabilities(trustClass).canAccessMemory`, which only `guardian` holds. An actor without it neither reads nor writes the guardian's memory. The memory plugin's `injectors.ts` admits personal-memory content only for a turn whose trust context passes `isPersonalMemoryAllowed`; the `recall`, `remember`, and `delete_memory_page` tools refuse such a turn (`plugins/defaults/memory/tools.ts`); and extraction from conversation messages runs only for guardian-provenance rows, or legacy rows with none (`plugins/defaults/memory/indexer.ts`).
|
|
25
27
|
|
|
26
28
|
## Guardian Privilege Isolation Invariant
|
|
27
29
|
|
|
@@ -2,6 +2,7 @@ import { describe, expect, test } from "bun:test";
|
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
4
|
BROWSER_OPERATION_META,
|
|
5
|
+
browserOperationLifecycle,
|
|
5
6
|
executeBrowserOperation,
|
|
6
7
|
} from "../operations.js";
|
|
7
8
|
import { BROWSER_OPERATIONS, type BrowserOperation } from "../types.js";
|
|
@@ -19,6 +20,34 @@ describe("browser operations contract", () => {
|
|
|
19
20
|
expect(BROWSER_OPERATION_META).toHaveLength(BROWSER_OPERATIONS.length);
|
|
20
21
|
});
|
|
21
22
|
|
|
23
|
+
test("classifies every typed operation for session lifecycle", () => {
|
|
24
|
+
const classifications = Object.fromEntries(
|
|
25
|
+
BROWSER_OPERATIONS.map((operation) => [
|
|
26
|
+
operation,
|
|
27
|
+
browserOperationLifecycle(operation),
|
|
28
|
+
]),
|
|
29
|
+
);
|
|
30
|
+
expect(classifications).toEqual({
|
|
31
|
+
navigate: "action",
|
|
32
|
+
snapshot: "action",
|
|
33
|
+
screenshot: "action",
|
|
34
|
+
close: "terminal",
|
|
35
|
+
attach: "action",
|
|
36
|
+
detach: "terminal",
|
|
37
|
+
click: "action",
|
|
38
|
+
type: "action",
|
|
39
|
+
press_key: "action",
|
|
40
|
+
scroll: "action",
|
|
41
|
+
select_option: "action",
|
|
42
|
+
hover: "action",
|
|
43
|
+
wait_for: "action",
|
|
44
|
+
extract: "action",
|
|
45
|
+
wait_for_download: "action",
|
|
46
|
+
fill_credential: "action",
|
|
47
|
+
status: "status",
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
|
|
22
51
|
// ── Every operation has a dispatch handler ─────────────────────────
|
|
23
52
|
|
|
24
53
|
test("every operation has a dispatch handler (rejects unknown)", async () => {
|
|
@@ -216,7 +216,7 @@ Examples:
|
|
|
216
216
|
name: "key",
|
|
217
217
|
type: "string",
|
|
218
218
|
description:
|
|
219
|
-
'The key to press (e.g. "Enter", "
|
|
219
|
+
'The key or modifier chord to press (e.g. "Enter", "Meta+v", "Control+a").',
|
|
220
220
|
required: true,
|
|
221
221
|
},
|
|
222
222
|
{
|
|
@@ -238,6 +238,7 @@ the key is dispatched to that element; otherwise to the focused element.
|
|
|
238
238
|
Examples:
|
|
239
239
|
$ assistant browser press-key --key Enter
|
|
240
240
|
$ assistant browser press-key --key Tab --element-id e5
|
|
241
|
+
$ assistant browser press-key --key "Meta+v"
|
|
241
242
|
$ assistant browser press-key --key Escape`,
|
|
242
243
|
},
|
|
243
244
|
{
|
|
@@ -36,6 +36,35 @@ import type { ToolExecutionResult } from "../tools/types.js";
|
|
|
36
36
|
import type { BrowserOperationContext as ToolContext } from "./types.js";
|
|
37
37
|
import type { BrowserOperation } from "./types.js";
|
|
38
38
|
|
|
39
|
+
export type BrowserOperationLifecycle = "action" | "terminal" | "status";
|
|
40
|
+
|
|
41
|
+
const OPERATION_LIFECYCLE: Record<BrowserOperation, BrowserOperationLifecycle> =
|
|
42
|
+
{
|
|
43
|
+
navigate: "action",
|
|
44
|
+
snapshot: "action",
|
|
45
|
+
screenshot: "action",
|
|
46
|
+
close: "terminal",
|
|
47
|
+
attach: "action",
|
|
48
|
+
detach: "terminal",
|
|
49
|
+
click: "action",
|
|
50
|
+
type: "action",
|
|
51
|
+
press_key: "action",
|
|
52
|
+
scroll: "action",
|
|
53
|
+
select_option: "action",
|
|
54
|
+
hover: "action",
|
|
55
|
+
wait_for: "action",
|
|
56
|
+
extract: "action",
|
|
57
|
+
wait_for_download: "action",
|
|
58
|
+
fill_credential: "action",
|
|
59
|
+
status: "status",
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
export function browserOperationLifecycle(
|
|
63
|
+
operation: BrowserOperation,
|
|
64
|
+
): BrowserOperationLifecycle {
|
|
65
|
+
return OPERATION_LIFECYCLE[operation];
|
|
66
|
+
}
|
|
67
|
+
|
|
39
68
|
// ── Dispatch handlers ────────────────────────────────────────────────
|
|
40
69
|
|
|
41
70
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { shouldUseVirtualDesktop } from "../desktop/virtual-desktop-feature.js";
|
|
2
2
|
import { browserManager } from "../tools/browser/browser-manager.js";
|
|
3
3
|
import { normalizeBrowserMode } from "../tools/browser/browser-mode.js";
|
|
4
4
|
import { getPinnedTab } from "../tools/browser/pinned-tabs.js";
|
|
@@ -18,16 +18,10 @@ export function shouldUseVirtualDesktopBrowser(
|
|
|
18
18
|
mode.mode !== "auto" ||
|
|
19
19
|
input.target_client_id ||
|
|
20
20
|
input.use_active_tab ||
|
|
21
|
-
context.transportInterface !== "web" ||
|
|
22
|
-
context.clientOs === "macos" ||
|
|
23
|
-
context.clientOs === "windows" ||
|
|
24
|
-
context.clientOs === "linux" ||
|
|
25
|
-
context.trustClass !== "guardian" ||
|
|
26
|
-
!context.sourceActorPrincipalId ||
|
|
27
21
|
browserManager.getPreferredBackendKind(context.conversationId) !== null ||
|
|
28
22
|
getPinnedTab(context.conversationId)
|
|
29
23
|
) {
|
|
30
24
|
return false;
|
|
31
25
|
}
|
|
32
|
-
return
|
|
26
|
+
return shouldUseVirtualDesktop(context);
|
|
33
27
|
}
|
|
@@ -115,7 +115,7 @@ export async function signBundle(
|
|
|
115
115
|
const { signature, keyId } = await requestSignature(canonicalPayload);
|
|
116
116
|
|
|
117
117
|
// 5. Build SignatureJson
|
|
118
|
-
|
|
118
|
+
return {
|
|
119
119
|
algorithm: "ed25519",
|
|
120
120
|
signer: {
|
|
121
121
|
key_id: keyId,
|
|
@@ -124,6 +124,4 @@ export async function signBundle(
|
|
|
124
124
|
content_hashes: contentHashes,
|
|
125
125
|
signature,
|
|
126
126
|
};
|
|
127
|
-
|
|
128
|
-
return signatureJson;
|
|
129
127
|
}
|
|
@@ -12,13 +12,16 @@ describe("createBargeInGuard", () => {
|
|
|
12
12
|
expect(guard.track("speech", 100)).toBe("pending");
|
|
13
13
|
expect(guard.track("speech", 100)).toBe("pending");
|
|
14
14
|
expect(guard.speechMs).toBe(200);
|
|
15
|
+
expect(guard.fired).toBe(false);
|
|
15
16
|
});
|
|
16
17
|
|
|
17
18
|
test("sustained speech reaching the threshold fires once and stays fired", () => {
|
|
18
19
|
const guard = createBargeInGuard(250);
|
|
19
20
|
guard.track("speech", 200);
|
|
20
21
|
expect(guard.track("speech", 50)).toBe("fired");
|
|
22
|
+
expect(guard.fired).toBe(true);
|
|
21
23
|
expect(guard.track("silence", 1_000)).toBe("fired");
|
|
24
|
+
expect(guard.fired).toBe(true);
|
|
22
25
|
});
|
|
23
26
|
|
|
24
27
|
test("a brief sub-threshold gap does not reset the run", () => {
|
|
@@ -421,6 +421,7 @@ function setupController(
|
|
|
421
421
|
) {
|
|
422
422
|
ensureConversation("conv-ctrl-test");
|
|
423
423
|
const session = createCallSession({
|
|
424
|
+
direction: "inbound",
|
|
424
425
|
conversationId: "conv-ctrl-test",
|
|
425
426
|
provider: "twilio",
|
|
426
427
|
fromNumber: "+15551111111",
|
|
@@ -471,6 +472,7 @@ function setupControllerWithOrigin(task?: string) {
|
|
|
471
472
|
ensureConversation("conv-ctrl-voice");
|
|
472
473
|
ensureConversation("conv-ctrl-origin");
|
|
473
474
|
const session = createCallSession({
|
|
475
|
+
direction: "inbound",
|
|
474
476
|
conversationId: "conv-ctrl-voice",
|
|
475
477
|
provider: "twilio",
|
|
476
478
|
fromNumber: "+15551111111",
|
|
@@ -5028,4 +5030,96 @@ describe("call-controller", () => {
|
|
|
5028
5030
|
await turnPromise.catch(() => {});
|
|
5029
5031
|
});
|
|
5030
5032
|
});
|
|
5033
|
+
describe("turn metrics", () => {
|
|
5034
|
+
test("a caller turn records the marks the latency numbers are built from", async () => {
|
|
5035
|
+
const { controller } = setupController();
|
|
5036
|
+
|
|
5037
|
+
await controller.handleCallerUtterance("What is the weather?");
|
|
5038
|
+
|
|
5039
|
+
const snapshot = controller.getMetricsSnapshot();
|
|
5040
|
+
expect(snapshot.recentTurns.length).toBe(1);
|
|
5041
|
+
const turn = snapshot.recentTurns[0];
|
|
5042
|
+
expect(turn.status).toBe("completed");
|
|
5043
|
+
// The transcript mark is seeded from when the caller stopped talking,
|
|
5044
|
+
// the dispatch mark from when the leg went out, and the delta mark from
|
|
5045
|
+
// the first token back: the three anchors every phone latency number is
|
|
5046
|
+
// subtracted from.
|
|
5047
|
+
expect(turn.timestamps.finalTranscriptAtMs).not.toBeNull();
|
|
5048
|
+
expect(turn.timestamps.assistantDispatchAtMs).not.toBeNull();
|
|
5049
|
+
expect(turn.timestamps.firstAssistantDeltaAtMs).not.toBeNull();
|
|
5050
|
+
expect(turn.durations.dispatchToFirstAssistantDeltaMs).not.toBeNull();
|
|
5051
|
+
expect(turn.durations.totalTurnDurationMs).not.toBeNull();
|
|
5052
|
+
// The provider's final doubles as the speech-end anchor, so the turn's
|
|
5053
|
+
// round trip is measurable on phone as it is in live voice.
|
|
5054
|
+
expect(turn.timestamps.utteranceEndAtMs).not.toBeNull();
|
|
5055
|
+
expect(turn.durations.roundTripMs).not.toBeNull();
|
|
5056
|
+
|
|
5057
|
+
controller.destroy();
|
|
5058
|
+
});
|
|
5059
|
+
|
|
5060
|
+
test("the transcript mark predates the dispatch it triggered", async () => {
|
|
5061
|
+
// Seeding backdates the turn to the caller's own boundary; a turn that
|
|
5062
|
+
// opened at dispatch time would report a felt latency that starts after
|
|
5063
|
+
// the caller already finished speaking.
|
|
5064
|
+
const { controller } = setupController();
|
|
5065
|
+
|
|
5066
|
+
await controller.handleCallerUtterance("Hello there");
|
|
5067
|
+
|
|
5068
|
+
const turn = controller.getMetricsSnapshot().recentTurns[0];
|
|
5069
|
+
const finalTranscriptAtMs = turn.timestamps.finalTranscriptAtMs;
|
|
5070
|
+
const assistantDispatchAtMs = turn.timestamps.assistantDispatchAtMs;
|
|
5071
|
+
expect(finalTranscriptAtMs).not.toBeNull();
|
|
5072
|
+
expect(assistantDispatchAtMs).not.toBeNull();
|
|
5073
|
+
expect(finalTranscriptAtMs!).toBeLessThanOrEqual(assistantDispatchAtMs!);
|
|
5074
|
+
expect(turn.timestamps.startedAtMs).toBeLessThanOrEqual(
|
|
5075
|
+
finalTranscriptAtMs!,
|
|
5076
|
+
);
|
|
5077
|
+
|
|
5078
|
+
controller.destroy();
|
|
5079
|
+
});
|
|
5080
|
+
|
|
5081
|
+
test("a barge-in ends the turn once, as cancelled", async () => {
|
|
5082
|
+
// One interruption is one cancelled turn: the count downstream reads as
|
|
5083
|
+
// "turns the caller cut off", so a second settle would double it.
|
|
5084
|
+
// A turn that never emits or completes holds the controller in the
|
|
5085
|
+
// pre-speech phase, which a sustained barge-in can still cut off.
|
|
5086
|
+
mockStartVoiceTurn.mockImplementation(
|
|
5087
|
+
async (opts: { onComplete: () => void }) => ({
|
|
5088
|
+
turnId: "run-metrics-slow",
|
|
5089
|
+
abort: () => opts.onComplete(),
|
|
5090
|
+
}),
|
|
5091
|
+
);
|
|
5092
|
+
const { controller } = setupController();
|
|
5093
|
+
const turnPromise = controller.handleCallerUtterance("Tell me a story");
|
|
5094
|
+
for (let i = 0; i < 5; i++) {
|
|
5095
|
+
await Promise.resolve();
|
|
5096
|
+
}
|
|
5097
|
+
expect(controller.getState()).toBe("processing");
|
|
5098
|
+
|
|
5099
|
+
expect(controller.handleBargeIn()).toBe(true);
|
|
5100
|
+
await turnPromise.catch(() => {});
|
|
5101
|
+
controller.destroy();
|
|
5102
|
+
|
|
5103
|
+
const turns = controller.getMetricsSnapshot().recentTurns;
|
|
5104
|
+
expect(turns.length).toBe(1);
|
|
5105
|
+
expect(turns[0].status).toBe("cancelled");
|
|
5106
|
+
expect(turns[0].cancellationReason).toBe("interrupted");
|
|
5107
|
+
expect(turns[0].timestamps.bargeInAtMs).not.toBeNull();
|
|
5108
|
+
});
|
|
5109
|
+
|
|
5110
|
+
test("no turn is invented between turns", async () => {
|
|
5111
|
+
// Every mark opens a turn when none is active, so a barge-in on an idle
|
|
5112
|
+
// controller must leave the collector empty rather than start a turn
|
|
5113
|
+
// that never settles.
|
|
5114
|
+
const { controller } = setupController();
|
|
5115
|
+
|
|
5116
|
+
expect(controller.handleBargeIn()).toBe(false);
|
|
5117
|
+
|
|
5118
|
+
const snapshot = controller.getMetricsSnapshot();
|
|
5119
|
+
expect(snapshot.recentTurns.length).toBe(0);
|
|
5120
|
+
expect(snapshot.activeTurn).toBeNull();
|
|
5121
|
+
|
|
5122
|
+
controller.destroy();
|
|
5123
|
+
});
|
|
5124
|
+
});
|
|
5031
5125
|
});
|