@vellumai/assistant 0.12.2 → 0.12.3-staging.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.env.example +2 -0
- package/AGENTS.md +1 -1
- package/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/integrations.md +7 -0
- package/docs/architecture/memory.md +17 -2
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/credential-execution-service.md +1 -1
- package/docs/desktop-browser-cli.md +50 -5
- package/docs/live-voice-task-outcomes.md +100 -0
- package/docs/mode-sessions.md +183 -0
- package/docs/voice-input-diagnostics.md +58 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/environments/src/shell.test.ts +21 -0
- package/node_modules/@vellumai/environments/src/shell.ts +24 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +20 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +8 -2
- package/node_modules/@vellumai/gateway-client/src/index.ts +4 -1
- package/node_modules/@vellumai/gateway-client/src/outbound-contract.ts +38 -7
- package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +5 -6
- package/node_modules/@vellumai/service-contracts/package.json +2 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +4 -1
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +716 -16
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +11 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- package/scripts/sync-llm-catalog.ts +3 -0
- package/scripts/voice-ttft-spike.ts +2 -2
- package/src/__tests__/agent-loop-output-hooks.test.ts +150 -1
- package/src/__tests__/agent-loop-provider-error-recording.test.ts +87 -19
- package/src/__tests__/agent-loop.test.ts +259 -0
- package/src/__tests__/agent-wake-delegation-prompt.test.ts +64 -2
- package/src/__tests__/annotate-activity-metadata.test.ts +3 -1
- package/src/__tests__/annotate-risk-options.test.ts +2 -0
- package/src/__tests__/answered-question-persistence.test.ts +2 -0
- package/src/__tests__/anthropic-gateway-shared.test.ts +22 -0
- package/src/__tests__/anthropic-provider.test.ts +55 -0
- package/src/__tests__/approval-interception-trust-gates.test.ts +40 -0
- package/src/__tests__/approval-message-composer.test.ts +1 -118
- package/src/__tests__/approval-routes-http.test.ts +3 -0
- package/src/__tests__/assistant-event-hub-connection-history.test.ts +111 -0
- package/src/__tests__/assistant-event-hub-targeted.test.ts +50 -0
- package/src/__tests__/assistant-event-targeting.test.ts +186 -0
- package/src/__tests__/assistant-stream-state.test.ts +29 -9
- package/src/__tests__/attachments-store.test.ts +22 -3
- package/src/__tests__/browser-fill-credential.test.ts +11 -22
- package/src/__tests__/btw-routes.test.ts +4 -1
- package/src/__tests__/build-persisted-content.test.ts +1 -1
- package/src/__tests__/call-conversation-messages.test.ts +5 -0
- package/src/__tests__/call-recovery.test.ts +7 -2
- package/src/__tests__/call-routes-http.test.ts +12 -0
- package/src/__tests__/call-store.test.ts +7 -2
- package/src/__tests__/channel-approval.test.ts +9 -14
- package/src/__tests__/channel-reply-delivery.test.ts +56 -0
- package/src/__tests__/channel-retry-sweep.test.ts +9 -0
- package/src/__tests__/chat-credential-redaction.test.ts +23 -0
- package/src/__tests__/chat-reveal-guard-priming.test.ts +2 -0
- package/src/__tests__/checker.test.ts +11 -3
- package/src/__tests__/client-os-metadata-persistence.test.ts +35 -1
- package/src/__tests__/computer-use-screenshot-attachments.test.ts +411 -0
- package/src/__tests__/computer-use-screenshot-selection.test.ts +50 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +0 -25
- package/src/__tests__/computer-use-tools.test.ts +1 -233
- package/src/__tests__/config-model-image-provider.test.ts +39 -0
- package/src/__tests__/config-schema.test.ts +16 -0
- package/src/__tests__/config-watcher.test.ts +24 -0
- package/src/__tests__/context-search-agent-runner.test.ts +260 -1
- package/src/__tests__/context-search-fanout.test.ts +1 -1
- package/src/__tests__/context-search-types.test.ts +7 -7
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +8 -2
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -0
- package/src/__tests__/conversation-agent-loop.test.ts +797 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-attachments.test.ts +106 -0
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- package/src/__tests__/conversation-fork-crud.test.ts +191 -0
- package/src/__tests__/conversation-history-boundary-repair-failure.test.ts +174 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +2 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +2 -0
- package/src/__tests__/conversation-rendered-delegation-state.test.ts +276 -0
- package/src/__tests__/conversation-retry-route.test.ts +22 -0
- package/src/__tests__/conversation-routes-disk-view.test.ts +2 -0
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +2 -0
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +10 -0
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +2 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +2 -0
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -0
- package/src/__tests__/conversation-surface-snapshots.test.ts +543 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +151 -0
- package/src/__tests__/conversation-surfaces-point-at-budget.test.ts +63 -1
- package/src/__tests__/conversation-tool-setup-attribution.test.ts +23 -0
- package/src/__tests__/conversation-undo.test.ts +61 -0
- package/src/__tests__/credential-execution-client.test.ts +72 -55
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- package/src/__tests__/db-conversation-tool-surface.test.ts +221 -0
- package/src/__tests__/db-mode-sessions-migration.test.ts +175 -0
- package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -0
- package/src/__tests__/dm-backfill.test.ts +91 -1
- package/src/__tests__/document-create-route.test.ts +88 -0
- package/src/__tests__/document-sync-tags.test.ts +27 -0
- package/src/__tests__/emit-signal-routing-intent.test.ts +142 -2
- package/src/__tests__/events-tail-route.test.ts +58 -0
- package/src/__tests__/evict-conversations-for-reload.test.ts +57 -8
- package/src/__tests__/guardian-action-sweep.test.ts +16 -0
- package/src/__tests__/guardian-dispatch.test.ts +13 -0
- package/src/__tests__/headless-browser-interactions.test.ts +64 -20
- package/src/__tests__/heartbeat-service.test.ts +2 -59
- package/src/__tests__/helpers/mock-conversation.ts +21 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +2 -0
- package/src/__tests__/helpers/verification-sessions-ipc-sim.ts +5 -0
- package/src/__tests__/history-repair.test.ts +53 -0
- package/src/__tests__/host-cu-proxy.test.ts +46 -2
- package/src/__tests__/http-user-message-parity.test.ts +2 -0
- package/src/__tests__/image-credentials.test.ts +49 -0
- package/src/__tests__/image-service-dispatcher.test.ts +45 -0
- package/src/__tests__/inference-profile-session-handler.test.ts +26 -0
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/list-messages-tool-merge.test.ts +85 -1
- package/src/__tests__/llm-catalog-parity.test.ts +27 -4
- package/src/__tests__/media-generate-image.test.ts +49 -1
- package/src/__tests__/message-provenance-contact-id.test.ts +69 -0
- package/src/__tests__/migration-export-to-gcs.test.ts +142 -0
- package/src/__tests__/mode-session-history.test.ts +245 -0
- package/src/__tests__/mode-session-recovery.test.ts +222 -0
- package/src/__tests__/mode-session-wire.test.ts +141 -0
- package/src/__tests__/notification-guardian-path.test.ts +7 -0
- package/src/__tests__/notification-telegram-adapter.test.ts +2 -2
- package/src/__tests__/notification-vellum-adapter.test.ts +34 -0
- package/src/__tests__/oauth-apps-routes.test.ts +1 -0
- package/src/__tests__/oauth-commands-routes.test.ts +114 -101
- package/src/__tests__/oauth-connect-orchestrator.test.ts +2 -0
- package/src/__tests__/oauth-provider-serializer.test.ts +13 -0
- package/src/__tests__/oauth-providers-routes.test.ts +3 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -0
- package/src/__tests__/persist-media-references.test.ts +50 -0
- package/src/__tests__/persistence-secret-redaction.test.ts +2 -0
- package/src/__tests__/plugin-api-provider.test.ts +5 -0
- package/src/__tests__/plugin-api-resolve-credential.test.ts +97 -0
- package/src/__tests__/plugin-import-boundary-guard.test.ts +9 -1
- package/src/__tests__/process-message-display-content.test.ts +56 -0
- package/src/__tests__/reaction-persistence.test.ts +5 -0
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +25 -9
- package/src/__tests__/run-conversation-turn-persistence.test.ts +138 -1
- package/src/__tests__/runtime-events-sse-reconnect.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +20 -0
- package/src/__tests__/scheduler-result-notification.test.ts +23 -4
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/scripted-turn-metadata-persistence.test.ts +73 -0
- package/src/__tests__/secret-ingress-http.test.ts +2 -0
- package/src/__tests__/secret-routes-platform-proxy.test.ts +86 -31
- package/src/__tests__/secret-routes-scrub.test.ts +22 -27
- package/src/__tests__/secret-scanner.test.ts +20 -0
- package/src/__tests__/secure-keys-managed-failover.test.ts +8 -0
- package/src/__tests__/secure-keys.test.ts +50 -4
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/server-tool-pairing.test.ts +107 -0
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- package/src/__tests__/skills.test.ts +5 -4
- package/src/__tests__/subagent-fork-notifications.test.ts +1 -2
- package/src/__tests__/subagent-manager-notify.test.ts +1 -2
- package/src/__tests__/subagent-notify-parent.test.ts +146 -39
- package/src/__tests__/subagent-notify-stale-rebuild.test.ts +2 -4
- package/src/__tests__/subagent-tool-gate-mode.test.ts +226 -0
- package/src/__tests__/surface-completion-in-flight-snapshot.test.ts +2 -0
- package/src/__tests__/terminal-tools.test.ts +8 -0
- package/src/__tests__/thread-backfill.test.ts +53 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +2 -0
- package/src/__tests__/tool-result-follow-up.test.ts +99 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +66 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -0
- package/src/__tests__/unicode.test.ts +36 -0
- package/src/__tests__/web-search-backend-failure.test.ts +1 -1
- package/src/activation/progress-store.test.ts +12 -7
- package/src/agent/loop.ts +136 -53
- package/src/agent/tool-result-follow-up.ts +70 -0
- package/src/api/attachment-provenance.test.ts +68 -0
- package/src/api/computer-use-tool.test.ts +55 -0
- package/src/api/computer-use-tool.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +3 -0
- package/src/api/events/assistant-turn-start.ts +3 -0
- package/src/api/events/desktop-activity-changed.ts +10 -0
- package/src/api/events/generation-handoff.ts +2 -0
- package/src/api/events/message-complete.ts +2 -0
- package/src/api/events/notification-conversation-created.ts +14 -16
- package/src/api/events/notification-intent.ts +4 -2
- package/src/api/events/question-request.ts +1 -0
- package/src/api/events/tool-result.ts +85 -0
- package/src/api/events/tool-use-start.ts +3 -0
- package/src/api/events/user-message-echo.ts +3 -0
- package/src/api/index.ts +42 -6
- package/src/api/mode-session.test.ts +131 -0
- package/src/api/mode-session.ts +148 -0
- package/src/api/remember-tool.ts +15 -0
- package/src/api/responses/conversation-message.ts +9 -0
- package/src/approvals/AGENTS.md +4 -2
- package/src/approvals/approval-primitive.ts +5 -2
- package/src/approvals/scoped-approval-grants.ts +6 -2
- package/src/browser/__tests__/operations.test.ts +29 -0
- package/src/browser/operation-meta.ts +2 -1
- package/src/browser/operations.ts +29 -0
- package/src/browser/virtual-desktop-target.ts +2 -9
- package/src/bundler/bundle-signer.ts +1 -3
- package/src/calls/__tests__/barge-in-guard.test.ts +3 -0
- package/src/calls/__tests__/call-controller.test.ts +94 -0
- package/src/calls/__tests__/call-funnel-telemetry.test.ts +204 -0
- package/src/calls/__tests__/voice-control-protocol.test.ts +15 -0
- package/src/calls/__tests__/voice-escalation-judge.test.ts +209 -0
- package/src/calls/__tests__/voice-leg-coordinator.test.ts +168 -0
- package/src/{live-voice/__tests__/live-voice-metrics.test.ts → calls/__tests__/voice-metrics.test.ts} +32 -38
- package/src/calls/__tests__/voice-session-bridge.test.ts +576 -122
- package/src/calls/barge-in-guard.ts +5 -0
- package/src/calls/call-controller.ts +196 -1
- package/src/calls/call-domain.ts +4 -0
- package/src/calls/call-store.ts +87 -2
- package/src/calls/guardian-action-sweep.ts +22 -8
- package/src/calls/media-stream-audio-transcode.ts +1 -3
- package/src/calls/typesafe-noul.ts +156 -0
- package/src/calls/voice-control-protocol.ts +6 -0
- package/src/calls/voice-escalation-judge.ts +145 -0
- package/src/calls/voice-escalation-target.ts +10 -0
- package/src/calls/voice-leg-coordinator.ts +121 -3
- package/src/{live-voice/live-voice-metrics.ts → calls/voice-metrics.ts} +94 -87
- package/src/calls/voice-session-bridge.ts +256 -112
- package/src/calls/voice-triage-escalate.ts +7 -0
- package/src/cli/__tests__/roadmap-cli.test.ts +4 -41
- package/src/cli/commands/__tests__/cli-test-harness.ts +21 -3
- package/src/cli/commands/__tests__/notifications.test.ts +35 -10
- package/src/cli/commands/__tests__/plugins.test.ts +20 -1
- package/src/cli/commands/__tests__/schedules.test.ts +14 -0
- package/src/cli/commands/bash.help.ts +4 -3
- package/src/cli/commands/browser.help.ts +9 -6
- package/src/cli/commands/browser.ts +0 -1
- package/src/cli/commands/clients.help.ts +46 -0
- package/src/cli/commands/clients.ts +116 -0
- package/src/cli/commands/credentials.help.ts +9 -4
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/oauth/index.help.ts +10 -0
- package/src/cli/commands/oauth/providers.ts +12 -0
- package/src/cli/commands/oauth/request.test.ts +179 -2
- package/src/cli/commands/oauth/request.ts +41 -10
- package/src/cli/commands/plugins.ts +12 -5
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/commands/schedules.ts +2 -0
- package/src/cli/lib/__tests__/inspect-plugin.test.ts +54 -0
- package/src/cli/lib/__tests__/install-from-github.test.ts +41 -0
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/__tests__/local-plugin-upgrade.test.ts +133 -51
- package/src/cli/lib/__tests__/plugin-catalog-cache.test.ts +8 -2
- package/src/cli/lib/bundled-marketplace.json +906 -1
- package/src/cli/lib/bundled-plugin-packages.json +783 -1
- package/src/cli/lib/inspect-plugin.ts +11 -4
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/cli/lib/upgrade-plugin.ts +19 -11
- package/src/cli/output.ts +18 -4
- package/src/config/__tests__/default-provider.test.ts +6 -0
- package/src/config/__tests__/memory-retrospective-schema.test.ts +14 -1
- package/src/config/bundled-skills/computer-use/SKILL.md +1 -1
- package/src/config/bundled-skills/computer-use/TOOLS.json +89 -1
- package/src/config/bundled-skills/image-studio/SKILL.md +17 -2
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +7 -11
- package/src/config/bundled-skills/schedule/SKILL.md +6 -6
- package/src/config/bundled-skills/sequences/TOOLS.json +1 -5
- package/src/config/call-site-defaults.ts +9 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +9 -17
- package/src/config/platform-identity.ts +8 -8
- package/src/config/profile-text-generation.test.ts +51 -0
- package/src/config/profile-text-generation.ts +51 -0
- package/src/config/schemas/__tests__/memory-v3.test.ts +12 -0
- package/src/config/schemas/__tests__/tools.test.ts +31 -0
- package/src/config/schemas/call-site-catalog.ts +14 -0
- package/src/config/schemas/channels.ts +0 -18
- package/src/config/schemas/llm.ts +9 -2
- package/src/config/schemas/mcp.ts +6 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- package/src/config/schemas/memory-v3.ts +12 -0
- package/src/config/schemas/services.ts +15 -6
- package/src/config/schemas/tools.ts +10 -0
- package/src/config/session-groups-gate.ts +21 -0
- package/src/config/skills.ts +2 -6
- package/src/conversations/__tests__/message-consolidation.test.ts +149 -0
- package/src/conversations/message-consolidation.ts +102 -5
- package/src/credential-execution/ces-connect.test.ts +69 -0
- package/src/credential-execution/ces-connect.ts +115 -0
- package/src/credential-execution/ces-runtime.ts +55 -93
- package/src/credential-execution/executable-discovery.ts +34 -142
- package/src/credential-execution/process-manager.test.ts +20 -24
- package/src/credential-execution/process-manager.ts +24 -19
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/conversation-tool-setup.test.ts +43 -0
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/__tests__/turn-tail-deleted-conversation.test.ts +36 -0
- package/src/daemon/assistant-attachments.ts +20 -12
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- package/src/daemon/chat-credential-redaction.ts +16 -1
- package/src/daemon/computer-use-mode-session.test.ts +210 -0
- package/src/daemon/computer-use-mode-session.ts +105 -0
- package/src/daemon/config-watcher.ts +10 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +132 -13
- package/src/daemon/conversation-agent-loop.ts +231 -25
- package/src/daemon/conversation-attachments.ts +93 -12
- package/src/daemon/conversation-evictor.ts +5 -24
- package/src/daemon/conversation-history.ts +10 -0
- package/src/daemon/conversation-interrupt-repair.ts +4 -43
- package/src/daemon/conversation-interrupt.ts +7 -11
- package/src/daemon/conversation-messaging.ts +58 -5
- package/src/daemon/conversation-mode-session.test.ts +1667 -0
- package/src/daemon/conversation-mode-session.ts +1008 -0
- package/src/daemon/conversation-process.ts +5 -0
- package/src/daemon/conversation-runtime-assembly.ts +10 -20
- package/src/daemon/conversation-skill-tools.ts +1 -0
- package/src/daemon/conversation-store.ts +4 -4
- package/src/daemon/conversation-surface-snapshots.ts +135 -0
- package/src/daemon/conversation-surfaces.ts +113 -5
- package/src/daemon/conversation-tool-setup.ts +79 -6
- package/src/daemon/conversation-turn-finalize.ts +26 -13
- package/src/daemon/conversation.ts +215 -58
- package/src/daemon/daemon-control.ts +3 -7
- package/src/daemon/handlers/config-model.ts +7 -5
- package/src/daemon/handlers/shared.ts +55 -16
- package/src/daemon/host-cu-proxy.ts +51 -22
- package/src/daemon/lifecycle.ts +30 -13
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/message-types/shared.ts +1 -0
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/orphan-reaper.ts +4 -3
- package/src/daemon/persist-media-references.ts +20 -3
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/tool-setup-types.ts +6 -0
- package/src/daemon/virtual-desktop-context.ts +21 -0
- package/src/daemon/wake-conversation-ops.ts +50 -15
- package/src/desktop/__tests__/fake-desktop.ts +1 -0
- package/src/desktop/desktop-accessibility-script.ts +88 -0
- package/src/desktop/desktop-accessibility.test.ts +160 -0
- package/src/desktop/desktop-accessibility.ts +169 -0
- package/src/desktop/desktop-automation-lease.test.ts +302 -64
- package/src/desktop/desktop-automation-lease.ts +129 -54
- package/src/desktop/desktop-browser-endpoint.ts +4 -0
- package/src/desktop/desktop-computer-use-routing.test.ts +330 -0
- package/src/desktop/desktop-computer-use.test.ts +449 -0
- package/src/desktop/desktop-computer-use.ts +502 -0
- package/src/desktop/desktop-dependencies.ts +47 -293
- package/src/desktop/desktop-display.ts +2 -2
- package/src/desktop/desktop-help.ts +15 -0
- package/src/desktop/desktop-panel-config.test.ts +13 -3
- package/src/desktop/desktop-panel-config.ts +109 -15
- package/src/desktop/desktop-session-manager.test.ts +69 -21
- package/src/desktop/desktop-session-manager.ts +76 -22
- package/src/desktop/desktop-stream-bridge.test.ts +76 -132
- package/src/desktop/desktop-stream-bridge.ts +9 -11
- package/src/desktop/desktop-wallpaper-renderer.ts +132 -0
- package/src/desktop/desktop-wallpaper-worker.ts +17 -0
- package/src/desktop/desktop-wallpaper.test.ts +48 -7
- package/src/desktop/desktop-wallpaper.ts +34 -102
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +53 -3
- package/src/desktop/virtual-desktop-platform.test.ts +5 -9
- package/src/documents/document-store.ts +23 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +22 -26
- package/src/heartbeat/heartbeat-service.ts +5 -33
- package/src/ipc/__tests__/browser-ipc.test.ts +215 -6
- package/src/ipc/assistant-server.ts +2 -0
- package/src/ipc/routes/__tests__/channel-reply-ipc-routes.test.ts +111 -0
- package/src/ipc/routes/channel-reply-ipc-routes.ts +73 -0
- package/src/live-voice/__tests__/continuation-judge.test.ts +151 -0
- package/src/live-voice/__tests__/live-activity-reporter.test.ts +154 -15
- package/src/live-voice/__tests__/live-voice-flux-turn-end.test.ts +743 -31
- package/src/live-voice/__tests__/live-voice-look-follow-up.test.ts +191 -10
- package/src/live-voice/__tests__/live-voice-session-groups-gate.test.ts +87 -0
- package/src/live-voice/__tests__/live-voice-session-manager.test.ts +5 -1
- package/src/live-voice/__tests__/live-voice-sight-frame-echo.test.ts +41 -0
- package/src/live-voice/__tests__/live-voice-sight-frame.test.ts +1017 -9
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +224 -1
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +101 -0
- package/src/live-voice/__tests__/live-voice-tts.test.ts +44 -0
- package/src/live-voice/__tests__/live-voice-vad.test.ts +939 -75
- package/src/live-voice/__tests__/microphone-idle-gate.test.ts +87 -0
- package/src/live-voice/__tests__/session-controls.test.ts +23 -0
- package/src/live-voice/__tests__/task-outcomes.test.ts +117 -0
- package/src/live-voice/__tests__/voice-input-diagnostics.test.ts +117 -0
- package/src/live-voice/camera-mode-session.test.ts +265 -0
- package/src/live-voice/camera-mode-session.ts +277 -0
- package/src/live-voice/continuation-judge.ts +123 -0
- package/src/live-voice/live-activity-reporter.ts +115 -6
- package/src/live-voice/live-voice-manager.ts +36 -1
- package/src/live-voice/live-voice-photo.ts +88 -7
- package/src/live-voice/live-voice-session-manager.ts +15 -0
- package/src/live-voice/live-voice-session.ts +1443 -747
- package/src/live-voice/live-voice-tts.ts +22 -4
- package/src/live-voice/microphone-idle-gate.ts +56 -0
- package/src/live-voice/protocol.ts +171 -4
- package/src/live-voice/session-controls.ts +11 -3
- package/src/live-voice/task-outcomes.ts +131 -0
- package/src/live-voice/voice-input-diagnostics.ts +117 -0
- package/src/mcp/__tests__/manager-tool-caps.test.ts +156 -0
- package/src/mcp/__tests__/startup.test.ts +30 -7
- package/src/mcp/__tests__/tool-caps.test.ts +134 -0
- package/src/mcp/manager.ts +171 -101
- package/src/mcp/startup.ts +33 -13
- package/src/mcp/tool-caps.ts +184 -0
- package/src/media/__tests__/image-models.test.ts +58 -0
- package/src/media/image-credentials.ts +5 -0
- package/src/media/image-models.ts +52 -0
- package/src/media/image-service.ts +8 -0
- package/src/media/openrouter-image-service.test.ts +133 -0
- package/src/media/openrouter-image-service.ts +153 -0
- package/src/media/types.ts +1 -1
- package/src/messaging/provider-message-metadata.ts +3 -3
- package/src/messaging/providers/__tests__/transport-dispatch.test.ts +65 -11
- package/src/messaging/providers/discord/send.ts +4 -17
- package/src/messaging/providers/discord/transport.ts +2 -2
- package/src/messaging/providers/outlook/client.ts +16 -22
- package/src/messaging/providers/telegram-bot/send.test.ts +236 -1
- package/src/messaging/providers/telegram-bot/send.ts +10 -7
- package/src/messaging/providers/telegram-bot/transport.ts +3 -10
- package/src/messaging/providers/whatsapp/send.test.ts +169 -4
- package/src/monitoring/__tests__/control.test.ts +17 -5
- package/src/monitoring/control.ts +15 -5
- package/src/notifications/AGENTS.md +1 -1
- package/src/notifications/README.md +83 -99
- package/src/notifications/__tests__/broadcaster.test.ts +1 -1
- package/src/notifications/__tests__/channel-allowlist.test.ts +39 -0
- package/src/notifications/__tests__/copy-composer.test.ts +71 -1
- package/src/notifications/__tests__/decision-engine.test.ts +79 -2
- package/src/notifications/__tests__/deterministic-checks.test.ts +10 -10
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +93 -4
- package/src/notifications/__tests__/notification-utils.test.ts +18 -0
- package/src/notifications/adapters/macos.ts +37 -46
- package/src/notifications/broadcaster.ts +5 -6
- package/src/notifications/channel-allowlist.ts +44 -0
- package/src/notifications/copy-composer.ts +11 -26
- package/src/notifications/decision-engine.ts +24 -14
- package/src/notifications/deterministic-checks.ts +1 -1
- package/src/notifications/emit-signal.ts +123 -37
- package/src/notifications/home-feed-side-effect.ts +9 -7
- package/src/notifications/notification-utils.ts +19 -0
- package/src/notifications/schedule-result-producer.ts +4 -6
- package/src/notifications/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/AGENTS.md +2 -0
- package/src/oauth/__tests__/identity-verifier.test.ts +36 -1
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/identity-verifier.ts +24 -0
- package/src/oauth/oauth-store.ts +12 -4
- package/src/oauth/provider-serializer.ts +8 -0
- package/src/oauth/seed-providers.ts +42 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/permissions/confirmation-guardian-request.test.ts +16 -0
- package/src/permissions/confirmation-guardian-request.ts +2 -3
- package/src/permissions/question-prompter.test.ts +31 -0
- package/src/permissions/question-prompter.ts +2 -0
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/attachments-store.ts +84 -44
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +166 -26
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-plugin-facade.ts +30 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/conversation-tool-surface.ts +135 -0
- package/src/persistence/conversation-types.test.ts +32 -0
- package/src/persistence/conversation-types.ts +26 -4
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.test.ts +78 -0
- package/src/persistence/migrations/378-create-conversation-tool-surfaces.ts +29 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.test.ts +92 -0
- package/src/persistence/migrations/379-oauth-providers-response-ok-field.ts +32 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts +90 -0
- package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts +34 -0
- package/src/persistence/migrations/381-create-conversation-mode-sessions.ts +41 -0
- package/src/persistence/migrations/382-create-client-connection-events.ts +40 -0
- package/src/persistence/migrations/__tests__/382-create-client-connection-events.test.ts +56 -0
- package/src/persistence/schema/conversation-tool-surfaces.ts +32 -0
- package/src/persistence/schema/conversations.ts +67 -0
- package/src/persistence/schema/index.ts +1 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/schema/oauth.ts +1 -0
- package/src/persistence/steps.ts +41 -3
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/conversation-turn.ts +31 -7
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +35 -6
- package/src/plugin-api/plugin-channel-turn-trust.test.ts +133 -0
- package/src/plugin-api/plugin-channel-turn-trust.ts +71 -0
- package/src/plugin-api/plugin-name-env.ts +125 -0
- package/src/plugin-api/resolve-credential.ts +79 -20
- package/src/plugin-api/vision-support.test.ts +22 -0
- package/src/plugin-api/vision-support.ts +17 -5
- package/src/plugins/__tests__/active-plugin-env.test.ts +136 -0
- package/src/plugins/active-plugin-env.ts +51 -0
- package/src/plugins/defaults/index.ts +24 -0
- package/src/plugins/defaults/memory/AGENTS.md +39 -5
- package/src/plugins/defaults/memory/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/buffer-file.test.ts +365 -0
- package/src/plugins/defaults/memory/__tests__/buffer-format.test.ts +43 -0
- package/src/plugins/defaults/memory/__tests__/conversation-memory-purge.test.ts +1 -0
- package/src/plugins/defaults/memory/__tests__/db-memory-attach.test.ts +2 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/buffer-appender.ts +17 -0
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +74 -0
- package/src/plugins/defaults/memory/__tests__/memory-run-evidence.test.ts +161 -0
- package/src/plugins/defaults/memory/__tests__/relocated-memory-test-rows.ts +10 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/buffer-file.ts +354 -0
- package/src/plugins/defaults/memory/buffer-format.ts +40 -0
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +77 -22
- package/src/plugins/defaults/memory/context-search/format.ts +53 -8
- package/src/plugins/defaults/memory/context-search/limits.ts +10 -12
- package/src/plugins/defaults/memory/context-search/recall-input.ts +38 -0
- package/src/plugins/defaults/memory/context-search/search.ts +8 -14
- package/src/plugins/defaults/memory/context-search/sources/conversations.ts +1 -0
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +2 -1
- package/src/plugins/defaults/memory/context-search/sources/workspace.ts +2 -1
- package/src/plugins/defaults/memory/context-search/types.ts +1 -11
- package/src/plugins/defaults/memory/conversation-memory-purge.ts +4 -0
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/capability-seed.ts +1 -2
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +13 -63
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/host-utils.ts +0 -10
- package/src/plugins/defaults/memory/injectors.ts +4 -3
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +72 -183
- package/src/plugins/defaults/memory/memory-run-evidence.ts +213 -0
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +6 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-job.test.ts +407 -99
- package/src/plugins/defaults/memory/substrate/__tests__/consolidation-prompt-flag-gating-guard.test.ts +10 -0
- package/src/plugins/defaults/memory/substrate/__tests__/prompts-consolidation.test.ts +107 -7
- package/src/plugins/defaults/memory/substrate/consolidation-job.ts +307 -86
- package/src/plugins/defaults/memory/substrate/consolidation-tool-surface.ts +34 -0
- package/src/plugins/defaults/memory/substrate/page-index.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +91 -51
- package/src/plugins/defaults/memory/substrate/sweep-job.ts +1 -1
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v1/graph/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/v1/graph/extraction.ts +2 -1
- package/src/plugins/defaults/memory/v1/graph/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/migration.test.ts +5 -0
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +5 -2
- package/src/plugins/defaults/memory/v2/reranker.ts +2 -1
- package/src/plugins/defaults/memory/v3/__tests__/injection.test.ts +81 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +87 -0
- package/src/plugins/defaults/memory/v3/__tests__/plugin-schema.test.ts +12 -0
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +332 -15
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +148 -28
- package/src/plugins/defaults/memory/v3/card.ts +2 -1
- package/src/plugins/defaults/memory/v3/injector.ts +212 -178
- package/src/plugins/defaults/memory/v3/orchestrate.ts +159 -32
- package/src/plugins/defaults/memory/v3/plugin-schema.ts +54 -4
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +275 -37
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +47 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +710 -59
- package/src/plugins/defaults/memory/v3/sections.ts +2 -1
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +41 -14
- package/src/plugins/defaults/memory/worker-control.ts +15 -5
- package/src/plugins/defaults/task-progress/__tests__/registration.test.ts +70 -0
- package/src/plugins/defaults/task-progress/__tests__/task-progress-context.test.ts +380 -0
- package/src/plugins/defaults/task-progress/hooks/post-compact.ts +19 -0
- package/src/plugins/defaults/task-progress/hooks/user-prompt-submit.ts +24 -0
- package/src/plugins/defaults/task-progress/package.json +14 -0
- package/src/plugins/defaults/task-progress/src/apply-task-progress-context.ts +93 -0
- package/src/plugins/defaults/task-progress/src/format-task-progress-context.ts +67 -0
- package/src/plugins/defaults/tool-error/hooks/post-tool-use.ts +4 -1
- package/src/plugins/defaults/tool-result-truncate/terminal.ts +1 -46
- package/src/prompts/__tests__/parallel-tasks-section.test.ts +25 -0
- package/src/prompts/delegation-gate.ts +57 -0
- package/src/prompts/system-prompt.ts +14 -32
- package/src/providers/__tests__/context-overflow-error.test.ts +10 -0
- package/src/providers/__tests__/search-provider-catalog.test.ts +18 -0
- package/src/providers/anthropic/client.ts +10 -1
- package/src/providers/anthropic-gateway-shared.ts +6 -0
- package/src/providers/fetch-provider-catalog.ts +11 -0
- package/src/providers/gemini/client.ts +25 -8
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/jev/client.test.ts +270 -0
- package/src/providers/jev/client.ts +534 -0
- package/src/providers/model-catalog.ts +59 -3
- package/src/providers/openai/__tests__/chat-completions-extra-body.test.ts +94 -1
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +106 -1
- package/src/providers/openai/__tests__/chat-template-flatten.test.ts +24 -0
- package/src/providers/openai/__tests__/google-thought-signature.test.ts +1 -2
- package/src/providers/openai/chat-completions-provider.ts +100 -29
- package/src/providers/openai/google-thought-signature.ts +0 -6
- package/src/providers/openai/responses-provider.ts +23 -1
- package/src/providers/ratelimit.ts +1 -3
- package/src/providers/search-provider-catalog.ts +24 -0
- package/src/providers/server-tool-pairing.ts +16 -7
- package/src/providers/speech-to-text/__tests__/deepgram-flux-frames.test.ts +24 -0
- package/src/providers/speech-to-text/__tests__/deepgram-flux-realtime.test.ts +7 -1
- package/src/providers/speech-to-text/__tests__/vellum-managed-realtime.test.ts +50 -1
- package/src/providers/speech-to-text/deepgram-flux-frames.ts +11 -0
- package/src/providers/speech-to-text/vellum-managed-flux-realtime.ts +13 -0
- package/src/providers/types.ts +5 -0
- package/src/routes/control.ts +7 -5
- package/src/runtime/AGENTS.md +6 -4
- package/src/runtime/__tests__/agent-wake.test.ts +94 -1
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +32 -5
- package/src/runtime/approval-message-composer.ts +3 -69
- package/src/runtime/assistant-event-hub.ts +73 -75
- package/src/runtime/assistant-event-publish-options.ts +7 -0
- package/src/runtime/assistant-event-targeting.ts +79 -0
- package/src/runtime/assistant-stream-state.ts +13 -100
- package/src/runtime/background-job-runner.ts +5 -5
- package/src/runtime/channel-retry-sweep.ts +1 -0
- package/src/runtime/guardian-action-message-composer.ts +8 -161
- package/src/runtime/guardian-action-service.ts +2 -17
- package/src/runtime/guardian-reply-router.ts +29 -40
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +6 -0
- package/src/runtime/message-composer-types.ts +3 -61
- package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +67 -1
- package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +89 -0
- package/src/runtime/migrations/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +43 -11
- package/src/runtime/migrations/vbundle-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-streaming-importer.ts +4 -1
- package/src/runtime/migrations/vbundle-validator.ts +1 -0
- package/src/runtime/pending-interactions-mode-session.test.ts +62 -0
- package/src/runtime/pending-interactions.ts +29 -0
- package/src/runtime/routes/__tests__/client-history-routes.test.ts +104 -0
- package/src/runtime/routes/__tests__/image-generation-routes.test.ts +97 -0
- package/src/runtime/routes/__tests__/inference-profiles-routes.test.ts +24 -2
- package/src/runtime/routes/__tests__/roadmap-routes.test.ts +29 -6
- package/src/runtime/routes/browser-context.ts +31 -11
- package/src/runtime/routes/browser-routes.ts +43 -4
- package/src/runtime/routes/btw-routes.ts +9 -4
- package/src/runtime/routes/channel-route-shared.ts +1 -9
- package/src/runtime/routes/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +125 -14
- package/src/runtime/routes/credential-prompt-routes.ts +4 -3
- package/src/runtime/routes/credential-routes.ts +1 -2
- package/src/runtime/routes/desktop-setup-routes.test.ts +9 -18
- package/src/runtime/routes/desktop-setup-routes.ts +8 -7
- package/src/runtime/routes/documents-routes.ts +51 -0
- package/src/runtime/routes/email-routes.ts +3 -7
- package/src/runtime/routes/events-routes.ts +75 -54
- package/src/runtime/routes/guardian-approval-interception.ts +24 -0
- package/src/runtime/routes/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +37 -41
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.test.ts +168 -0
- package/src/runtime/routes/inbound-stages/backfill-sender-provenance.ts +96 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +39 -10
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +9 -9
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -0
- package/src/runtime/routes/inference-profile-session-handler.ts +11 -1
- package/src/runtime/routes/inference-profiles-routes.ts +9 -0
- package/src/runtime/routes/llm-context-normalization.ts +1 -7
- package/src/runtime/routes/migration-routes.ts +73 -2
- package/src/runtime/routes/notification-routes.ts +10 -0
- package/src/runtime/routes/oauth-commands-routes.ts +57 -54
- package/src/runtime/routes/oauth-providers.ts +11 -0
- package/src/runtime/routes/oauth-request-hints.test.ts +246 -0
- package/src/runtime/routes/oauth-request-hints.ts +149 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/schedule-routes.ts +2 -0
- package/src/runtime/routes/secret-routes.ts +99 -119
- package/src/runtime/routes/settings-routes.ts +10 -4
- package/src/runtime/routes/watcher-routes.ts +1 -3
- package/src/runtime/trust-class.test.ts +7 -6
- package/src/runtime/trust-class.ts +9 -17
- package/src/schedule/__tests__/worker-control.test.ts +36 -5
- package/src/schedule/__tests__/worker-mcp-bootstrap.test.ts +107 -0
- package/src/schedule/__tests__/worker-mcp-readiness.test.ts +173 -0
- package/src/schedule/__tests__/worker-mcp-tools.test.ts +13 -47
- package/src/schedule/run-script.ts +2 -2
- package/src/schedule/scheduler.ts +47 -11
- package/src/schedule/tool-surface-readiness.ts +65 -0
- package/src/schedule/worker-control.ts +15 -5
- package/src/schedule/worker-mcp.ts +85 -0
- package/src/schedule/worker.ts +9 -31
- package/src/security/secure-keys.ts +74 -112
- package/src/skills/clawhub.ts +3 -8
- package/src/skills/managed-store.ts +1 -5
- package/src/stt/types.ts +4 -0
- package/src/subagent/notify.ts +54 -34
- package/src/subagent/parent-notification.ts +6 -0
- package/src/telemetry/__tests__/phone-call-funnel.test.ts +72 -0
- package/src/telemetry/phone-call-funnel.ts +144 -0
- package/src/tools/__tests__/tool-schema-root-combinator-guard.test.ts +81 -0
- package/src/tools/ask-question/ask-question-tool.test.ts +167 -5
- package/src/tools/ask-question/ask-question-tool.ts +120 -22
- package/src/tools/browser/browser-execution.ts +29 -60
- package/src/tools/browser/cdp-client/__tests__/cdp-dom-helpers.test.ts +561 -39
- package/src/tools/browser/cdp-client/cdp-dom-helpers.ts +435 -39
- package/src/tools/browser/cdp-client/cdp-inspect-client.ts +1 -8
- package/src/tools/client-os.ts +15 -0
- package/src/tools/computer-use/skill-proxy-bridge.ts +1 -1
- package/src/tools/computer-use/target.ts +42 -0
- package/src/tools/document/document-tool.ts +13 -18
- package/src/tools/execution-target.ts +14 -16
- package/src/tools/host-terminal/host-shell.ts +16 -7
- package/src/tools/network/__tests__/web-fetch-tinyfish.test.ts +250 -0
- package/src/tools/network/__tests__/web-search.test.ts +203 -0
- package/src/tools/network/web-fetch.ts +274 -7
- package/src/tools/network/web-search.ts +468 -6
- package/src/tools/permission-checker.ts +3 -3
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +1 -31
- package/src/tools/shared/shell-output.test.ts +10 -0
- package/src/tools/shared/shell-output.ts +14 -2
- package/src/tools/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +24 -4
- package/src/tools/skills/scaffold-managed.ts +2 -1
- package/src/tools/skills/skill-script-runner.ts +7 -0
- package/src/tools/skills/skill-tool-factory.ts +15 -1
- package/src/tools/terminal/__tests__/safe-env.test.ts +44 -4
- package/src/tools/terminal/__tests__/sanitized-bash.test.ts +0 -14
- package/src/tools/terminal/safe-env.ts +39 -24
- package/src/tools/terminal/sanitized-bash.ts +15 -2
- package/src/tools/terminal/shell-launch.test.ts +162 -0
- package/src/tools/terminal/shell.test.ts +29 -0
- package/src/tools/terminal/shell.ts +15 -7
- package/src/tools/tool-approval-handler.ts +5 -1
- package/src/tools/tool-types.ts +3 -3
- package/src/tools/types.ts +8 -2
- package/src/util/__tests__/worker-process-command.test.ts +5 -4
- package/src/util/abort-reasons.ts +18 -26
- package/src/util/browser-human-verification.ts +14 -0
- package/src/util/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/host-process.test.ts +17 -1
- package/src/util/host-process.ts +24 -0
- package/src/util/provider-error-patterns.ts +3 -0
- package/src/util/unicode.ts +29 -0
- package/src/util/worker-process.ts +77 -35
- package/src/workspace/migrations/157-add-desktop-files-launcher.ts +94 -0
- package/src/workspace/migrations/__tests__/156-extract-workspace-mcp-json.test.ts +4 -10
- package/src/workspace/migrations/__tests__/157-add-desktop-files-launcher.test.ts +113 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/computer-use-window-schema.test.ts +0 -24
- package/src/api/events/heartbeat-alert.ts +0 -20
- package/src/daemon/message-types/web-activity.ts +0 -65
- package/src/desktop/desktop-dependencies.test.ts +0 -131
- package/src/tools/computer-use/definitions.ts +0 -607
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import {
|
|
4
|
+
COMPUTER_USE_SCREENSHOT_ATTACHMENT_IDS_KEY,
|
|
5
|
+
computerUseScreenshotAttachmentIdsFromMetadata,
|
|
6
|
+
} from "./conversation-types.js";
|
|
7
|
+
|
|
8
|
+
describe("computerUseScreenshotAttachmentIdsFromMetadata", () => {
|
|
9
|
+
test("returns valid nonempty attachment ids", () => {
|
|
10
|
+
expect(
|
|
11
|
+
computerUseScreenshotAttachmentIdsFromMetadata({
|
|
12
|
+
[COMPUTER_USE_SCREENSHOT_ATTACHMENT_IDS_KEY]: [
|
|
13
|
+
"attachment-1",
|
|
14
|
+
"",
|
|
15
|
+
42,
|
|
16
|
+
"attachment-2",
|
|
17
|
+
],
|
|
18
|
+
}),
|
|
19
|
+
).toEqual(["attachment-1", "attachment-2"]);
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
test("treats absent and malformed metadata as legacy", () => {
|
|
23
|
+
expect(computerUseScreenshotAttachmentIdsFromMetadata(undefined)).toEqual(
|
|
24
|
+
[],
|
|
25
|
+
);
|
|
26
|
+
expect(
|
|
27
|
+
computerUseScreenshotAttachmentIdsFromMetadata({
|
|
28
|
+
[COMPUTER_USE_SCREENSHOT_ATTACHMENT_IDS_KEY]: "attachment-1",
|
|
29
|
+
}),
|
|
30
|
+
).toEqual([]);
|
|
31
|
+
});
|
|
32
|
+
});
|
|
@@ -82,7 +82,10 @@ export function isBackgroundConversationType(
|
|
|
82
82
|
* columns into one label.
|
|
83
83
|
*/
|
|
84
84
|
export type ConversationKind =
|
|
85
|
-
|
|
85
|
+
| "user"
|
|
86
|
+
| "background"
|
|
87
|
+
| "background_memory_consolidation"
|
|
88
|
+
| "scheduled";
|
|
86
89
|
|
|
87
90
|
/**
|
|
88
91
|
* Single classifier shared by the LLM-context routes and the notification
|
|
@@ -270,6 +273,10 @@ export function isVoiceSessionUserMessage(
|
|
|
270
273
|
*/
|
|
271
274
|
export const SIGHT_FRAME_ATTACHMENT_IDS_KEY = "sightFrameAttachmentIds";
|
|
272
275
|
|
|
276
|
+
/** Metadata key naming computer-use screenshots automatically linked to a reply. */
|
|
277
|
+
export const COMPUTER_USE_SCREENSHOT_ATTACHMENT_IDS_KEY =
|
|
278
|
+
"computerUseScreenshotAttachmentIds";
|
|
279
|
+
|
|
273
280
|
/**
|
|
274
281
|
* The row's attachments that arrived as ambient camera frames, by attachment
|
|
275
282
|
* id. A user attachment carries no metadata of its own, so the marking lives on
|
|
@@ -291,6 +298,23 @@ export function sightFrameAttachmentIdsFromMetadata(
|
|
|
291
298
|
);
|
|
292
299
|
}
|
|
293
300
|
|
|
301
|
+
/**
|
|
302
|
+
* Attachment ids whose placement on this row was automatic computer-use
|
|
303
|
+
* screenshot promotion. Malformed and legacy metadata conservatively yields
|
|
304
|
+
* no marked attachments.
|
|
305
|
+
*/
|
|
306
|
+
export function computerUseScreenshotAttachmentIdsFromMetadata(
|
|
307
|
+
metadata: Record<string, unknown> | null | undefined,
|
|
308
|
+
): string[] {
|
|
309
|
+
const ids = metadata?.[COMPUTER_USE_SCREENSHOT_ATTACHMENT_IDS_KEY];
|
|
310
|
+
if (!Array.isArray(ids)) {
|
|
311
|
+
return [];
|
|
312
|
+
}
|
|
313
|
+
return ids.filter(
|
|
314
|
+
(id): id is string => typeof id === "string" && id.length > 0,
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
|
|
294
318
|
/**
|
|
295
319
|
* True when a stored `messages.metadata` column belongs to a standalone
|
|
296
320
|
* ambient camera keep: a row the call's own gate sampled, which no one spoke.
|
|
@@ -360,9 +384,7 @@ export function isDesktopOriginatedUserMessage(
|
|
|
360
384
|
return false;
|
|
361
385
|
}
|
|
362
386
|
const clientOs = parseClientOs((client as Record<string, unknown>).os);
|
|
363
|
-
return
|
|
364
|
-
clientOs === "macos" || clientOs === "windows" || clientOs === "linux"
|
|
365
|
-
);
|
|
387
|
+
return clientOs === "macos" || clientOs === "windows" || clientOs === "linux";
|
|
366
388
|
}
|
|
367
389
|
|
|
368
390
|
/**
|
|
@@ -515,19 +515,13 @@ interface GroupRow {
|
|
|
515
515
|
|
|
516
516
|
type UsageQueryParam = ScheduleAttributionSqlParam;
|
|
517
517
|
|
|
518
|
-
function normalizeUsageAggregationFilter(
|
|
519
|
-
filter?: UsageAggregationFilter,
|
|
520
|
-
): UsageAggregationFilter {
|
|
521
|
-
return normalizeScheduleAttributionFilter(filter);
|
|
522
|
-
}
|
|
523
|
-
|
|
524
518
|
function buildUsageAggregationWhere(
|
|
525
519
|
range: UsageTimeRange,
|
|
526
520
|
filter?: UsageAggregationFilter,
|
|
527
521
|
eventAlias?: string,
|
|
528
522
|
now: number = Date.now(),
|
|
529
523
|
): { sql: string; params: UsageQueryParam[] } {
|
|
530
|
-
const normalized =
|
|
524
|
+
const normalized = normalizeScheduleAttributionFilter(filter);
|
|
531
525
|
const eventTable = eventAlias ?? "llm_usage_events";
|
|
532
526
|
const createdAt = `${eventTable}.created_at`;
|
|
533
527
|
const clauses = [`${createdAt} >= ? AND ${createdAt} <= ?`];
|
|
@@ -852,7 +846,7 @@ export function getUsageGroupBreakdown(
|
|
|
852
846
|
// Runtime allowlist — defense-in-depth against SQL injection via type assertions.
|
|
853
847
|
assertGroupByDimension(groupBy);
|
|
854
848
|
|
|
855
|
-
const normalizedFilter =
|
|
849
|
+
const normalizedFilter = normalizeScheduleAttributionFilter(filter);
|
|
856
850
|
|
|
857
851
|
// Conversation grouping requires a JOIN with conversations to resolve titles.
|
|
858
852
|
if (groupBy === "conversation") {
|
|
@@ -984,7 +978,7 @@ export function getUsageGroupedSeries(
|
|
|
984
978
|
throw new Error("Grouped usage series does not support conversation");
|
|
985
979
|
}
|
|
986
980
|
|
|
987
|
-
const normalizedFilter =
|
|
981
|
+
const normalizedFilter = normalizeScheduleAttributionFilter(filter);
|
|
988
982
|
let rows: UsageGroupedBucketRow[];
|
|
989
983
|
|
|
990
984
|
if (groupBy === "schedule") {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ModeSession, parseModeSession } from "../api/mode-session.js";
|
|
1
2
|
import { safeParseRecord } from "../util/json.js";
|
|
2
3
|
|
|
3
4
|
/**
|
|
@@ -18,3 +19,27 @@ export function mergeMessageMetadata(
|
|
|
18
19
|
...updates,
|
|
19
20
|
});
|
|
20
21
|
}
|
|
22
|
+
|
|
23
|
+
export function readModeSessionMetadata(
|
|
24
|
+
metadata: string | null | undefined,
|
|
25
|
+
): ModeSession | undefined {
|
|
26
|
+
if (!metadata) {
|
|
27
|
+
return undefined;
|
|
28
|
+
}
|
|
29
|
+
return parseModeSession(safeParseRecord(metadata).modeSession);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function readMessageSentAt(
|
|
33
|
+
metadata: string | null | undefined,
|
|
34
|
+
): number | undefined {
|
|
35
|
+
if (!metadata) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
const sentAt = safeParseRecord(metadata).sentAt;
|
|
39
|
+
return typeof sentAt === "number" &&
|
|
40
|
+
Number.isInteger(sentAt) &&
|
|
41
|
+
sentAt >= 0 &&
|
|
42
|
+
Number.isFinite(new Date(sentAt).getTime())
|
|
43
|
+
? sentAt
|
|
44
|
+
: undefined;
|
|
45
|
+
}
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import * as schema from "../schema.js";
|
|
7
|
+
import { migrateCreateConversationToolSurfaces } from "./378-create-conversation-tool-surfaces.js";
|
|
8
|
+
|
|
9
|
+
function createTestDb() {
|
|
10
|
+
const sqlite = new Database(":memory:");
|
|
11
|
+
sqlite.run("PRAGMA foreign_keys = ON");
|
|
12
|
+
// Only the parent table the FK points at.
|
|
13
|
+
sqlite.run(/*sql*/ `CREATE TABLE conversations (id TEXT PRIMARY KEY)`);
|
|
14
|
+
return { sqlite, db: drizzle(sqlite, { schema }) };
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
function tableDdl(sqlite: Database): string | undefined {
|
|
18
|
+
const row = sqlite
|
|
19
|
+
.query(
|
|
20
|
+
`SELECT sql FROM sqlite_master WHERE type='table' AND name='conversation_tool_surfaces'`,
|
|
21
|
+
)
|
|
22
|
+
.get() as { sql: string } | null;
|
|
23
|
+
return row?.sql;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function insertSurface(sqlite: Database, conversationId: string): void {
|
|
27
|
+
sqlite
|
|
28
|
+
.query(
|
|
29
|
+
/*sql*/ `INSERT INTO conversation_tool_surfaces (conversation_id, tools_json, tools_hash, updated_at) VALUES (?, ?, ?, ?)`,
|
|
30
|
+
)
|
|
31
|
+
.run(conversationId, "[]", "hash", 1);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function surfaceCount(sqlite: Database): number {
|
|
35
|
+
const row = sqlite
|
|
36
|
+
.query(`SELECT COUNT(*) AS n FROM conversation_tool_surfaces`)
|
|
37
|
+
.get() as { n: number };
|
|
38
|
+
return row.n;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
describe("migration 378: conversation_tool_surfaces", () => {
|
|
42
|
+
test("creates the table keyed by conversation with a cascading FK", () => {
|
|
43
|
+
const { sqlite, db } = createTestDb();
|
|
44
|
+
expect(tableDdl(sqlite)).toBeUndefined();
|
|
45
|
+
|
|
46
|
+
migrateCreateConversationToolSurfaces(db);
|
|
47
|
+
|
|
48
|
+
const ddl = tableDdl(sqlite);
|
|
49
|
+
expect(ddl).toContain("conversation_id TEXT PRIMARY KEY");
|
|
50
|
+
expect(ddl).toContain("REFERENCES conversations(id) ON DELETE CASCADE");
|
|
51
|
+
expect(ddl).toContain("tools_json TEXT NOT NULL");
|
|
52
|
+
expect(ddl).toContain("tools_hash TEXT NOT NULL");
|
|
53
|
+
expect(ddl).toContain("updated_at INTEGER NOT NULL");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test("deleting a conversation cascades to its surface row", () => {
|
|
57
|
+
const { sqlite, db } = createTestDb();
|
|
58
|
+
migrateCreateConversationToolSurfaces(db);
|
|
59
|
+
sqlite.query(`INSERT INTO conversations (id) VALUES (?)`).run("conv-1");
|
|
60
|
+
insertSurface(sqlite, "conv-1");
|
|
61
|
+
expect(surfaceCount(sqlite)).toBe(1);
|
|
62
|
+
|
|
63
|
+
sqlite.query(`DELETE FROM conversations WHERE id = ?`).run("conv-1");
|
|
64
|
+
|
|
65
|
+
expect(surfaceCount(sqlite)).toBe(0);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
test("is idempotent: a second run keeps the table and its rows", () => {
|
|
69
|
+
const { sqlite, db } = createTestDb();
|
|
70
|
+
migrateCreateConversationToolSurfaces(db);
|
|
71
|
+
sqlite.query(`INSERT INTO conversations (id) VALUES (?)`).run("conv-1");
|
|
72
|
+
insertSurface(sqlite, "conv-1");
|
|
73
|
+
|
|
74
|
+
expect(() => migrateCreateConversationToolSurfaces(db)).not.toThrow();
|
|
75
|
+
|
|
76
|
+
expect(surfaceCount(sqlite)).toBe(1);
|
|
77
|
+
});
|
|
78
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
const TABLE = "conversation_tool_surfaces";
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Create `conversation_tool_surfaces`: one row per conversation holding the
|
|
7
|
+
* tool definitions its most recent live turn sent to the provider, keyed by
|
|
8
|
+
* conversation with a content hash so an unchanged surface is never rewritten.
|
|
9
|
+
*
|
|
10
|
+
* Its own table rather than a column on `conversations` because the payload
|
|
11
|
+
* is a JSON array of every tool definition (tens of kilobytes) that only fork
|
|
12
|
+
* wakes read, while `conversations` rows are read whole on every hot path.
|
|
13
|
+
* The row cascades with its conversation, so a deleted conversation leaves
|
|
14
|
+
* no surface behind.
|
|
15
|
+
*
|
|
16
|
+
* Idempotent via IF NOT EXISTS.
|
|
17
|
+
*/
|
|
18
|
+
export function migrateCreateConversationToolSurfaces(
|
|
19
|
+
database: DrizzleDb,
|
|
20
|
+
): void {
|
|
21
|
+
database.run(
|
|
22
|
+
`CREATE TABLE IF NOT EXISTS ${TABLE} (
|
|
23
|
+
conversation_id TEXT PRIMARY KEY REFERENCES conversations(id) ON DELETE CASCADE,
|
|
24
|
+
tools_json TEXT NOT NULL,
|
|
25
|
+
tools_hash TEXT NOT NULL,
|
|
26
|
+
updated_at INTEGER NOT NULL
|
|
27
|
+
)`,
|
|
28
|
+
);
|
|
29
|
+
}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import * as schema from "../schema.js";
|
|
7
|
+
import { migrateOAuthProvidersResponseOkField } from "./379-oauth-providers-response-ok-field.js";
|
|
8
|
+
|
|
9
|
+
function createTestDb(options: { withTable?: boolean } = {}) {
|
|
10
|
+
const sqlite = new Database(":memory:");
|
|
11
|
+
if (options.withTable !== false) {
|
|
12
|
+
// Pre-379 shape: only the columns the migration and tests touch.
|
|
13
|
+
sqlite.exec(/*sql*/ `
|
|
14
|
+
CREATE TABLE oauth_providers (
|
|
15
|
+
provider_key TEXT PRIMARY KEY,
|
|
16
|
+
identity_ok_field TEXT,
|
|
17
|
+
created_at INTEGER NOT NULL,
|
|
18
|
+
updated_at INTEGER NOT NULL
|
|
19
|
+
);
|
|
20
|
+
`);
|
|
21
|
+
}
|
|
22
|
+
return { sqlite, db: drizzle(sqlite, { schema }) };
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function columnNames(sqlite: Database): string[] {
|
|
26
|
+
return (
|
|
27
|
+
sqlite.query("PRAGMA table_info(oauth_providers)").all() as Array<{
|
|
28
|
+
name: string;
|
|
29
|
+
}>
|
|
30
|
+
).map((c) => c.name);
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe("migration 379: oauth_providers.response_ok_field", () => {
|
|
34
|
+
test("adds the nullable column beside the identity one", () => {
|
|
35
|
+
const { sqlite, db } = createTestDb();
|
|
36
|
+
expect(columnNames(sqlite)).not.toContain("response_ok_field");
|
|
37
|
+
|
|
38
|
+
migrateOAuthProvidersResponseOkField(db);
|
|
39
|
+
|
|
40
|
+
const column = (
|
|
41
|
+
sqlite.query("PRAGMA table_info(oauth_providers)").all() as Array<{
|
|
42
|
+
name: string;
|
|
43
|
+
notnull: number;
|
|
44
|
+
}>
|
|
45
|
+
).find((c) => c.name === "response_ok_field");
|
|
46
|
+
expect(column).toBeDefined();
|
|
47
|
+
expect(column?.notnull).toBe(0);
|
|
48
|
+
expect(columnNames(sqlite)).toContain("identity_ok_field");
|
|
49
|
+
});
|
|
50
|
+
|
|
51
|
+
test("rows written before the column existed read back null", () => {
|
|
52
|
+
// A provider that declared nothing is judged by status alone, which is
|
|
53
|
+
// what it was before the column existed.
|
|
54
|
+
const { sqlite, db } = createTestDb();
|
|
55
|
+
sqlite.exec(/*sql*/ `
|
|
56
|
+
INSERT INTO oauth_providers (provider_key, identity_ok_field, created_at, updated_at)
|
|
57
|
+
VALUES ('slack', 'ok', 1000, 1000)
|
|
58
|
+
`);
|
|
59
|
+
|
|
60
|
+
migrateOAuthProvidersResponseOkField(db);
|
|
61
|
+
|
|
62
|
+
const row = sqlite
|
|
63
|
+
.query(
|
|
64
|
+
"SELECT response_ok_field FROM oauth_providers WHERE provider_key = 'slack'",
|
|
65
|
+
)
|
|
66
|
+
.get() as { response_ok_field: unknown };
|
|
67
|
+
expect(row.response_ok_field).toBeNull();
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("is idempotent: re-run is a no-op", () => {
|
|
71
|
+
const { sqlite, db } = createTestDb();
|
|
72
|
+
|
|
73
|
+
migrateOAuthProvidersResponseOkField(db);
|
|
74
|
+
expect(() => migrateOAuthProvidersResponseOkField(db)).not.toThrow();
|
|
75
|
+
|
|
76
|
+
expect(
|
|
77
|
+
columnNames(sqlite).filter((n) => n === "response_ok_field"),
|
|
78
|
+
).toHaveLength(1);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
test("a missing table is a failure, never a silent success", () => {
|
|
82
|
+
// The runner checkpoints a throwing step as failed and retries it, and
|
|
83
|
+
// the registry defers this step behind the table's own. Swallowing the
|
|
84
|
+
// error here would checkpoint the step as done against no table, and the
|
|
85
|
+
// column would never be added.
|
|
86
|
+
// The driver wraps SQLite's "no such table" in its own message, so the
|
|
87
|
+
// assertion is that the step throws at all.
|
|
88
|
+
const { db } = createTestDb({ withTable: false });
|
|
89
|
+
|
|
90
|
+
expect(() => migrateOAuthProvidersResponseOkField(db)).toThrow();
|
|
91
|
+
});
|
|
92
|
+
});
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { tableHasColumn } from "./schema-introspection.js";
|
|
3
|
+
|
|
4
|
+
const TABLE_NAME = "oauth_providers";
|
|
5
|
+
const COLUMN_NAME = "response_ok_field";
|
|
6
|
+
const COLUMN_DEFINITION = "response_ok_field TEXT";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add `response_ok_field` to `oauth_providers` (migration 149): the dot path
|
|
10
|
+
* of the boolean a provider's API puts in every response body to report
|
|
11
|
+
* success (Slack: `ok`). Its own column, distinct from `identity_ok_field`,
|
|
12
|
+
* because the two declare different facts: the identity field governs the
|
|
13
|
+
* one call the provider row names, this one governs any request made with
|
|
14
|
+
* the credential.
|
|
15
|
+
*
|
|
16
|
+
* Nullable with no backfill: seeding upserts the value for the built-in rows
|
|
17
|
+
* on the next start, and a custom provider that declares nothing is judged by
|
|
18
|
+
* status alone, which is what it was before the column existed.
|
|
19
|
+
*
|
|
20
|
+
* Idempotent: guarded with `tableHasColumn` so a crash between the `ALTER
|
|
21
|
+
* TABLE` and the checkpoint write doesn't cause a duplicate-column error on
|
|
22
|
+
* the next boot. A missing table is not swallowed: the registry declares the
|
|
23
|
+
* dependency on the table's own step, so this one is deferred rather than
|
|
24
|
+
* checkpointed as done against no table.
|
|
25
|
+
*/
|
|
26
|
+
export function migrateOAuthProvidersResponseOkField(
|
|
27
|
+
database: DrizzleDb,
|
|
28
|
+
): void {
|
|
29
|
+
if (!tableHasColumn(database, TABLE_NAME, COLUMN_NAME)) {
|
|
30
|
+
database.run(`ALTER TABLE ${TABLE_NAME} ADD COLUMN ${COLUMN_DEFINITION}`);
|
|
31
|
+
}
|
|
32
|
+
}
|
package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.test.ts
ADDED
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { Database } from "bun:sqlite";
|
|
2
|
+
import { describe, expect, test } from "bun:test";
|
|
3
|
+
|
|
4
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
5
|
+
|
|
6
|
+
import * as schema from "../schema.js";
|
|
7
|
+
import { migrateCreateConversationToolSurfaces } from "./378-create-conversation-tool-surfaces.js";
|
|
8
|
+
import { migrateConversationToolSurfacesDelegateIndependentTasks } from "./380-conversation-tool-surfaces-delegate-independent-tasks.js";
|
|
9
|
+
|
|
10
|
+
function createTestDb(options: { withTable?: boolean } = {}) {
|
|
11
|
+
const sqlite = new Database(":memory:");
|
|
12
|
+
sqlite.run("PRAGMA foreign_keys = ON");
|
|
13
|
+
// Only the parent table the FK points at.
|
|
14
|
+
sqlite.run(/*sql*/ `CREATE TABLE conversations (id TEXT PRIMARY KEY)`);
|
|
15
|
+
const db = drizzle(sqlite, { schema });
|
|
16
|
+
if (options.withTable !== false) {
|
|
17
|
+
// Pre-380 shape: the table as migration 378 creates it.
|
|
18
|
+
migrateCreateConversationToolSurfaces(db);
|
|
19
|
+
}
|
|
20
|
+
return { sqlite, db };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function columns(sqlite: Database): Array<{ name: string; notnull: number }> {
|
|
24
|
+
return sqlite
|
|
25
|
+
.query("PRAGMA table_info(conversation_tool_surfaces)")
|
|
26
|
+
.all() as Array<{ name: string; notnull: number }>;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("migration 380: conversation_tool_surfaces.delegate_independent_tasks", () => {
|
|
30
|
+
test("adds the nullable column", () => {
|
|
31
|
+
const { sqlite, db } = createTestDb();
|
|
32
|
+
expect(columns(sqlite).map((c) => c.name)).not.toContain(
|
|
33
|
+
"delegate_independent_tasks",
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
migrateConversationToolSurfacesDelegateIndependentTasks(db);
|
|
37
|
+
|
|
38
|
+
const column = columns(sqlite).find(
|
|
39
|
+
(c) => c.name === "delegate_independent_tasks",
|
|
40
|
+
);
|
|
41
|
+
expect(column).toBeDefined();
|
|
42
|
+
expect(column?.notnull).toBe(0);
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
test("rows written before the column existed read back null", () => {
|
|
46
|
+
// A fork replaying such a row derives the section for itself, which is
|
|
47
|
+
// what it did before the column existed.
|
|
48
|
+
const { sqlite, db } = createTestDb();
|
|
49
|
+
sqlite.query(`INSERT INTO conversations (id) VALUES (?)`).run("conv-1");
|
|
50
|
+
sqlite
|
|
51
|
+
.query(
|
|
52
|
+
/*sql*/ `INSERT INTO conversation_tool_surfaces (conversation_id, tools_json, tools_hash, updated_at) VALUES (?, ?, ?, ?)`,
|
|
53
|
+
)
|
|
54
|
+
.run("conv-1", "[]", "hash", 1);
|
|
55
|
+
|
|
56
|
+
migrateConversationToolSurfacesDelegateIndependentTasks(db);
|
|
57
|
+
|
|
58
|
+
const row = sqlite
|
|
59
|
+
.query(
|
|
60
|
+
"SELECT delegate_independent_tasks FROM conversation_tool_surfaces WHERE conversation_id = 'conv-1'",
|
|
61
|
+
)
|
|
62
|
+
.get() as { delegate_independent_tasks: unknown };
|
|
63
|
+
expect(row.delegate_independent_tasks).toBeNull();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
test("is idempotent: re-run is a no-op", () => {
|
|
67
|
+
const { sqlite, db } = createTestDb();
|
|
68
|
+
|
|
69
|
+
migrateConversationToolSurfacesDelegateIndependentTasks(db);
|
|
70
|
+
expect(() =>
|
|
71
|
+
migrateConversationToolSurfacesDelegateIndependentTasks(db),
|
|
72
|
+
).not.toThrow();
|
|
73
|
+
|
|
74
|
+
expect(
|
|
75
|
+
columns(sqlite).filter((c) => c.name === "delegate_independent_tasks"),
|
|
76
|
+
).toHaveLength(1);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
test("a missing table is a failure, never a silent success", () => {
|
|
80
|
+
// The runner checkpoints a throwing step as failed and retries it, and
|
|
81
|
+
// the registry defers this step behind the table's own. Swallowing the
|
|
82
|
+
// error here would checkpoint the step as done against no table, and the
|
|
83
|
+
// column would never be added.
|
|
84
|
+
const { db } = createTestDb({ withTable: false });
|
|
85
|
+
|
|
86
|
+
expect(() =>
|
|
87
|
+
migrateConversationToolSurfacesDelegateIndependentTasks(db),
|
|
88
|
+
).toThrow();
|
|
89
|
+
});
|
|
90
|
+
});
|
package/src/persistence/migrations/380-conversation-tool-surfaces-delegate-independent-tasks.ts
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { tableHasColumn } from "./schema-introspection.js";
|
|
3
|
+
|
|
4
|
+
const TABLE_NAME = "conversation_tool_surfaces";
|
|
5
|
+
const COLUMN_NAME = "delegate_independent_tasks";
|
|
6
|
+
const COLUMN_DEFINITION = "delegate_independent_tasks INTEGER";
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Add `delegate_independent_tasks` to `conversation_tool_surfaces`: whether
|
|
10
|
+
* the system prompt of the turn that recorded the surface rendered the
|
|
11
|
+
* parallel-delegation section (`01-parallel-tasks`). The prompt derives that
|
|
12
|
+
* section from the same resolved tool surface, so a fork wake replaying the
|
|
13
|
+
* surface needs the rendered state too: the section sits in the system
|
|
14
|
+
* prompt, the second tier of the provider cache prefix, and a fork that
|
|
15
|
+
* derives it from its own restricted scope renders it off where the source
|
|
16
|
+
* rendered it on, missing the source's cached prefix from that byte on.
|
|
17
|
+
*
|
|
18
|
+
* Nullable with no backfill: a row written before the column existed reads
|
|
19
|
+
* null and the fork derives the section for itself, exactly as it did before
|
|
20
|
+
* the column; the next live turn records the state.
|
|
21
|
+
*
|
|
22
|
+
* Idempotent: guarded with `tableHasColumn` so a crash between the `ALTER
|
|
23
|
+
* TABLE` and the checkpoint write doesn't cause a duplicate-column error on
|
|
24
|
+
* the next boot. A missing table is not swallowed: the registry declares the
|
|
25
|
+
* dependency on the table's own step, so this one is deferred rather than
|
|
26
|
+
* checkpointed as done against no table.
|
|
27
|
+
*/
|
|
28
|
+
export function migrateConversationToolSurfacesDelegateIndependentTasks(
|
|
29
|
+
database: DrizzleDb,
|
|
30
|
+
): void {
|
|
31
|
+
if (!tableHasColumn(database, TABLE_NAME, COLUMN_NAME)) {
|
|
32
|
+
database.run(`ALTER TABLE ${TABLE_NAME} ADD COLUMN ${COLUMN_DEFINITION}`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
const TABLE = "conversation_mode_sessions";
|
|
5
|
+
|
|
6
|
+
export function migrateCreateConversationModeSessions(
|
|
7
|
+
database: DrizzleDb,
|
|
8
|
+
): void {
|
|
9
|
+
const sqlite = getSqliteFrom(database);
|
|
10
|
+
sqlite.exec(/* sql */ `
|
|
11
|
+
CREATE TABLE IF NOT EXISTS ${TABLE} (
|
|
12
|
+
id TEXT PRIMARY KEY,
|
|
13
|
+
conversation_id TEXT NOT NULL REFERENCES conversations(id) ON DELETE CASCADE,
|
|
14
|
+
mode TEXT NOT NULL CHECK (mode IN ('computer_use', 'browser', 'live_vision', 'ambient')),
|
|
15
|
+
status TEXT NOT NULL CHECK (status IN ('active', 'completed', 'interrupted')),
|
|
16
|
+
source_started_at INTEGER NOT NULL,
|
|
17
|
+
first_included_at INTEGER,
|
|
18
|
+
first_included_message_id TEXT,
|
|
19
|
+
last_activity_at INTEGER NOT NULL,
|
|
20
|
+
last_owned_message_id TEXT,
|
|
21
|
+
ended_at INTEGER,
|
|
22
|
+
end_reason TEXT,
|
|
23
|
+
revision INTEGER NOT NULL DEFAULT 1 CHECK (revision > 0),
|
|
24
|
+
CHECK ((first_included_at IS NULL) = (first_included_message_id IS NULL)),
|
|
25
|
+
CHECK (
|
|
26
|
+
(status = 'active' AND ended_at IS NULL AND end_reason IS NULL)
|
|
27
|
+
OR (status = 'completed' AND ended_at IS NOT NULL AND end_reason IS NOT NULL AND length(end_reason) > 0)
|
|
28
|
+
OR (status = 'interrupted' AND end_reason IS NOT NULL AND length(end_reason) > 0)
|
|
29
|
+
),
|
|
30
|
+
CHECK (ended_at IS NULL OR ended_at >= last_activity_at),
|
|
31
|
+
CHECK (last_activity_at >= source_started_at),
|
|
32
|
+
CHECK (first_included_at IS NULL OR first_included_at <= last_activity_at)
|
|
33
|
+
);
|
|
34
|
+
CREATE INDEX IF NOT EXISTS idx_conversation_mode_sessions_conversation_status
|
|
35
|
+
ON ${TABLE} (conversation_id, status);
|
|
36
|
+
`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function downCreateConversationModeSessions(database: DrizzleDb): void {
|
|
40
|
+
getSqliteFrom(database).exec(`DROP TABLE IF EXISTS ${TABLE}`);
|
|
41
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
|
|
4
|
+
const TABLE = "client_connection_events";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create `client_connection_events`: the durable hub subscribe/dispose
|
|
8
|
+
* ledger used by `assistant clients history`.
|
|
9
|
+
*
|
|
10
|
+
* One row per client-subscriber lifecycle event. Reconnects shorter than
|
|
11
|
+
* the flap window are coalesced at read time, not at write time, so the
|
|
12
|
+
* raw event stream stays a complete audit.
|
|
13
|
+
*
|
|
14
|
+
* Idempotent via IF NOT EXISTS.
|
|
15
|
+
*/
|
|
16
|
+
export function migrateCreateClientConnectionEvents(database: DrizzleDb): void {
|
|
17
|
+
const sqlite = getSqliteFrom(database);
|
|
18
|
+
sqlite.exec(
|
|
19
|
+
`CREATE TABLE IF NOT EXISTS ${TABLE} (
|
|
20
|
+
id TEXT PRIMARY KEY,
|
|
21
|
+
client_id TEXT NOT NULL,
|
|
22
|
+
interface_id TEXT NOT NULL,
|
|
23
|
+
connection_id TEXT NOT NULL,
|
|
24
|
+
reason TEXT NOT NULL,
|
|
25
|
+
occurred_at INTEGER NOT NULL,
|
|
26
|
+
actor_principal_id TEXT,
|
|
27
|
+
client_version TEXT,
|
|
28
|
+
sse_watchdog INTEGER,
|
|
29
|
+
machine_name TEXT
|
|
30
|
+
)`,
|
|
31
|
+
);
|
|
32
|
+
sqlite.exec(
|
|
33
|
+
`CREATE INDEX IF NOT EXISTS idx_client_connection_events_client_occurred
|
|
34
|
+
ON ${TABLE} (client_id, occurred_at)`,
|
|
35
|
+
);
|
|
36
|
+
sqlite.exec(
|
|
37
|
+
`CREATE INDEX IF NOT EXISTS idx_client_connection_events_occurred
|
|
38
|
+
ON ${TABLE} (occurred_at)`,
|
|
39
|
+
);
|
|
40
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Migration 382 creates `client_connection_events`, the durable hub
|
|
3
|
+
* subscribe/dispose ledger used by `assistant clients history`.
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import { Database } from "bun:sqlite";
|
|
7
|
+
import { describe, expect, test } from "bun:test";
|
|
8
|
+
|
|
9
|
+
import { drizzle } from "drizzle-orm/bun-sqlite";
|
|
10
|
+
|
|
11
|
+
import { getSqliteFrom } from "../../db-connection.js";
|
|
12
|
+
import * as schema from "../../schema.js";
|
|
13
|
+
import { migrateCreateClientConnectionEvents } from "../382-create-client-connection-events.js";
|
|
14
|
+
|
|
15
|
+
function createTestDb() {
|
|
16
|
+
const sqlite = new Database(":memory:");
|
|
17
|
+
sqlite.exec("PRAGMA journal_mode=WAL");
|
|
18
|
+
return drizzle(sqlite, { schema });
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function tableNames(db: ReturnType<typeof createTestDb>): string[] {
|
|
22
|
+
const rows = getSqliteFrom(db)
|
|
23
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'table'")
|
|
24
|
+
.all() as { name: string }[];
|
|
25
|
+
return rows.map((row) => row.name);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function indexNames(db: ReturnType<typeof createTestDb>): string[] {
|
|
29
|
+
const rows = getSqliteFrom(db)
|
|
30
|
+
.prepare("SELECT name FROM sqlite_master WHERE type = 'index'")
|
|
31
|
+
.all() as { name: string }[];
|
|
32
|
+
return rows.map((row) => row.name);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
describe("migrateCreateClientConnectionEvents", () => {
|
|
36
|
+
test("creates the table and its lookup indexes", () => {
|
|
37
|
+
const db = createTestDb();
|
|
38
|
+
|
|
39
|
+
migrateCreateClientConnectionEvents(db);
|
|
40
|
+
|
|
41
|
+
expect(tableNames(db)).toContain("client_connection_events");
|
|
42
|
+
expect(indexNames(db)).toContain(
|
|
43
|
+
"idx_client_connection_events_client_occurred",
|
|
44
|
+
);
|
|
45
|
+
expect(indexNames(db)).toContain("idx_client_connection_events_occurred");
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
test("re-running is a no-op", () => {
|
|
49
|
+
const db = createTestDb();
|
|
50
|
+
|
|
51
|
+
migrateCreateClientConnectionEvents(db);
|
|
52
|
+
migrateCreateClientConnectionEvents(db);
|
|
53
|
+
|
|
54
|
+
expect(tableNames(db)).toContain("client_connection_events");
|
|
55
|
+
});
|
|
56
|
+
});
|