@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
|
@@ -206,19 +206,26 @@ describe("spawnScheduleWorkerProcess", () => {
|
|
|
206
206
|
}
|
|
207
207
|
});
|
|
208
208
|
|
|
209
|
-
test("
|
|
209
|
+
test("spawns when the PID file names an unrelated live process", async () => {
|
|
210
210
|
writeFileSync(pidPath, String(process.pid));
|
|
211
211
|
let spawned = false;
|
|
212
212
|
const restore = stubBunSpawn(() => {
|
|
213
213
|
spawned = true;
|
|
214
|
-
|
|
214
|
+
writeFileSync(pidPath, "4242");
|
|
215
|
+
return {
|
|
216
|
+
unref: () => {},
|
|
217
|
+
kill: () => {},
|
|
218
|
+
pid: 4242,
|
|
219
|
+
exited: neverExits(),
|
|
220
|
+
};
|
|
215
221
|
});
|
|
216
222
|
try {
|
|
217
223
|
const result = await spawnScheduleWorkerProcess({
|
|
218
|
-
pidWaitTimeoutMs:
|
|
224
|
+
pidWaitTimeoutMs: 1_000,
|
|
225
|
+
pidPollIntervalMs: 10,
|
|
219
226
|
});
|
|
220
|
-
expect(result).toEqual({ pid:
|
|
221
|
-
expect(spawned).toBe(
|
|
227
|
+
expect(result).toEqual({ pid: 4242, alreadyRunning: false });
|
|
228
|
+
expect(spawned).toBe(true);
|
|
222
229
|
} finally {
|
|
223
230
|
restore();
|
|
224
231
|
}
|
|
@@ -240,6 +247,11 @@ describe("probeScheduleWorker", () => {
|
|
|
240
247
|
}
|
|
241
248
|
});
|
|
242
249
|
|
|
250
|
+
test("reports not_running when the PID file names a live process that is not this worker", () => {
|
|
251
|
+
writeFileSync(pidPath, String(process.pid));
|
|
252
|
+
expect(probeScheduleWorker()).toEqual({ status: "not_running" });
|
|
253
|
+
});
|
|
254
|
+
|
|
243
255
|
test("reports running (not throws) when the process exists but is not signalable (EPERM)", () => {
|
|
244
256
|
writeFileSync(pidPath, "4321");
|
|
245
257
|
const restore = stubProcessKill(new Set(), new Set([4321]));
|
|
@@ -256,6 +268,25 @@ describe("stopScheduleWorkerProcess", () => {
|
|
|
256
268
|
expect(stopScheduleWorkerProcess()).toEqual({ status: "not_running" });
|
|
257
269
|
});
|
|
258
270
|
|
|
271
|
+
test("does not signal a recycled PID that is not this worker", () => {
|
|
272
|
+
writeFileSync(pidPath, String(process.pid));
|
|
273
|
+
const signalled: Array<[number, string | number | undefined]> = [];
|
|
274
|
+
const original = process.kill.bind(process);
|
|
275
|
+
process.kill = ((pid: number, signal?: string | number) => {
|
|
276
|
+
if ((signal ?? 0) === 0) {
|
|
277
|
+
return original(pid, signal);
|
|
278
|
+
}
|
|
279
|
+
signalled.push([pid, signal]);
|
|
280
|
+
return true;
|
|
281
|
+
}) as typeof process.kill;
|
|
282
|
+
try {
|
|
283
|
+
expect(stopScheduleWorkerProcess()).toEqual({ status: "not_running" });
|
|
284
|
+
expect(signalled).toEqual([]);
|
|
285
|
+
} finally {
|
|
286
|
+
process.kill = original;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
|
|
259
290
|
test("signals a running worker and reports its prior state", () => {
|
|
260
291
|
writeFileSync(pidPath, "4321");
|
|
261
292
|
const signalled: Array<[number, string | number | undefined]> = [];
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Timing coverage for the schedule-worker MCP bootstrap and reload helpers.
|
|
3
|
+
*
|
|
4
|
+
* The worker entrypoint cannot be imported (it calls process.exit). These
|
|
5
|
+
* tests drive the extracted helpers with a delayed start so a due schedule
|
|
6
|
+
* cannot observe a ready surface before registration settles.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { afterEach, describe, expect, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
import { EMPTY_MCP_STARTUP_SNAPSHOT } from "../../mcp/tool-caps.js";
|
|
12
|
+
import {
|
|
13
|
+
getScheduleToolSurfaceState,
|
|
14
|
+
isScheduleToolSurfaceReady,
|
|
15
|
+
resetScheduleToolSurfaceReadinessForTests,
|
|
16
|
+
} from "../tool-surface-readiness.js";
|
|
17
|
+
import {
|
|
18
|
+
bootstrapScheduleWorkerMcp,
|
|
19
|
+
reloadScheduleWorkerMcp,
|
|
20
|
+
} from "../worker-mcp.js";
|
|
21
|
+
|
|
22
|
+
function deferred<T>(): {
|
|
23
|
+
promise: Promise<T>;
|
|
24
|
+
resolve: (value: T) => void;
|
|
25
|
+
} {
|
|
26
|
+
let resolve!: (value: T) => void;
|
|
27
|
+
const promise = new Promise<T>((res) => {
|
|
28
|
+
resolve = res;
|
|
29
|
+
});
|
|
30
|
+
return { promise, resolve };
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
afterEach(() => {
|
|
34
|
+
resetScheduleToolSurfaceReadinessForTests();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
describe("bootstrapScheduleWorkerMcp", () => {
|
|
38
|
+
test("stays unready past the grace period until start settles", async () => {
|
|
39
|
+
const gate = deferred<typeof EMPTY_MCP_STARTUP_SNAPSHOT>();
|
|
40
|
+
const snapshot = {
|
|
41
|
+
...EMPTY_MCP_STARTUP_SNAPSHOT,
|
|
42
|
+
configuredServerCount: 8,
|
|
43
|
+
connectedServerCount: 8,
|
|
44
|
+
registeredToolCount: 3,
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
const boot = bootstrapScheduleWorkerMcp({
|
|
48
|
+
start: () => gate.promise,
|
|
49
|
+
graceMs: 20,
|
|
50
|
+
});
|
|
51
|
+
await boot;
|
|
52
|
+
|
|
53
|
+
expect(isScheduleToolSurfaceReady()).toBe(false);
|
|
54
|
+
expect(getScheduleToolSurfaceState()).toBe("starting");
|
|
55
|
+
|
|
56
|
+
gate.resolve(snapshot);
|
|
57
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
58
|
+
|
|
59
|
+
expect(isScheduleToolSurfaceReady()).toBe(true);
|
|
60
|
+
expect(getScheduleToolSurfaceState()).toBe("ready");
|
|
61
|
+
});
|
|
62
|
+
|
|
63
|
+
test("marks ready when start finishes before the grace deadline", async () => {
|
|
64
|
+
await bootstrapScheduleWorkerMcp({
|
|
65
|
+
start: async () => ({
|
|
66
|
+
...EMPTY_MCP_STARTUP_SNAPSHOT,
|
|
67
|
+
registeredToolCount: 2,
|
|
68
|
+
}),
|
|
69
|
+
graceMs: 50,
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
expect(isScheduleToolSurfaceReady()).toBe(true);
|
|
73
|
+
});
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
describe("reloadScheduleWorkerMcp", () => {
|
|
77
|
+
test("is not ready while reload is in flight", async () => {
|
|
78
|
+
const gate = deferred<typeof EMPTY_MCP_STARTUP_SNAPSHOT>();
|
|
79
|
+
const reloading = reloadScheduleWorkerMcp({
|
|
80
|
+
restart: () => gate.promise,
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
expect(getScheduleToolSurfaceState()).toBe("reloading");
|
|
84
|
+
expect(isScheduleToolSurfaceReady()).toBe(false);
|
|
85
|
+
|
|
86
|
+
gate.resolve({
|
|
87
|
+
...EMPTY_MCP_STARTUP_SNAPSHOT,
|
|
88
|
+
registeredToolCount: 4,
|
|
89
|
+
});
|
|
90
|
+
await reloading;
|
|
91
|
+
|
|
92
|
+
expect(isScheduleToolSurfaceReady()).toBe(true);
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
test("failed reload does not stay in reloading", async () => {
|
|
96
|
+
await expect(
|
|
97
|
+
reloadScheduleWorkerMcp({
|
|
98
|
+
restart: async () => {
|
|
99
|
+
throw new Error("reconnect failed");
|
|
100
|
+
},
|
|
101
|
+
}),
|
|
102
|
+
).rejects.toThrow("reconnect failed");
|
|
103
|
+
|
|
104
|
+
expect(getScheduleToolSurfaceState()).toBe("ready");
|
|
105
|
+
expect(isScheduleToolSurfaceReady()).toBe(true);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Scheduler gate for tool-backed schedules while the MCP surface is not ready.
|
|
3
|
+
*
|
|
4
|
+
* A due execute schedule must not record success while worker MCP
|
|
5
|
+
* initialization is still incomplete. Once ready, the expected MCP tool
|
|
6
|
+
* has to be present in the registry the turn would use.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { afterEach, describe, expect, mock, test } from "bun:test";
|
|
10
|
+
|
|
11
|
+
import { getDb } from "../../persistence/db-connection.js";
|
|
12
|
+
import { initializeDb } from "../../persistence/db-init.js";
|
|
13
|
+
import { RiskLevel } from "../../tools/tool-types.js";
|
|
14
|
+
import { createSchedule } from "../schedule-store.js";
|
|
15
|
+
import {
|
|
16
|
+
markScheduleToolSurfaceStarting,
|
|
17
|
+
resetScheduleToolSurfaceReadinessForTests,
|
|
18
|
+
} from "../tool-surface-readiness.js";
|
|
19
|
+
|
|
20
|
+
const processedPrompts: string[] = [];
|
|
21
|
+
mock.module("../../runtime/background-job-runner.js", () => ({
|
|
22
|
+
runBackgroundJob: async (opts: { prompt: string }) => {
|
|
23
|
+
const { getMcpToolDefinitions } = await import("../../tools/registry.js");
|
|
24
|
+
capturedMcpTools = getMcpToolDefinitions().map((tool) => tool.name);
|
|
25
|
+
processedPrompts.push(opts.prompt);
|
|
26
|
+
return { conversationId: "conv-xyz", ok: true };
|
|
27
|
+
},
|
|
28
|
+
}));
|
|
29
|
+
|
|
30
|
+
mock.module("../../daemon/process-message.js", () => ({
|
|
31
|
+
processMessage: async () => ({ messageId: "msg-xyz" }),
|
|
32
|
+
processMessageInBackground: async () => {},
|
|
33
|
+
}));
|
|
34
|
+
|
|
35
|
+
mock.module("../../background-wake/publisher.js", () => ({
|
|
36
|
+
refreshBackgroundWakeIntent: () => {},
|
|
37
|
+
}));
|
|
38
|
+
|
|
39
|
+
mock.module("../../daemon/disk-pressure-background-gate.js", () => ({
|
|
40
|
+
checkDiskPressureBackgroundGate: () => ({
|
|
41
|
+
action: "allow",
|
|
42
|
+
status: {
|
|
43
|
+
enabled: false,
|
|
44
|
+
state: "disabled",
|
|
45
|
+
locked: false,
|
|
46
|
+
acknowledged: false,
|
|
47
|
+
overrideActive: false,
|
|
48
|
+
effectivelyLocked: false,
|
|
49
|
+
lockId: null,
|
|
50
|
+
usagePercent: null,
|
|
51
|
+
thresholdPercent: 95,
|
|
52
|
+
path: null,
|
|
53
|
+
lastCheckedAt: null,
|
|
54
|
+
blockedCapabilities: [],
|
|
55
|
+
error: null,
|
|
56
|
+
},
|
|
57
|
+
}),
|
|
58
|
+
diskPressureBackgroundSkipLogFields: () => ({}),
|
|
59
|
+
shouldLogDiskPressureBackgroundSkip: () => false,
|
|
60
|
+
}));
|
|
61
|
+
|
|
62
|
+
const mockEmitNotificationSignal = mock(() => Promise.resolve());
|
|
63
|
+
mock.module("../../notifications/emit-signal.js", () => ({
|
|
64
|
+
emitNotificationSignal: mockEmitNotificationSignal,
|
|
65
|
+
}));
|
|
66
|
+
|
|
67
|
+
const { runDueSchedulesOnce } = await import("../scheduler.js");
|
|
68
|
+
const { __resetRegistryForTesting, getTool, registerMcpTools } =
|
|
69
|
+
await import("../../tools/registry.js");
|
|
70
|
+
|
|
71
|
+
await initializeDb();
|
|
72
|
+
|
|
73
|
+
let capturedMcpTools: string[] = [];
|
|
74
|
+
|
|
75
|
+
function rawDb(): import("bun:sqlite").Database {
|
|
76
|
+
return (getDb() as unknown as { $client: import("bun:sqlite").Database })
|
|
77
|
+
.$client;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
afterEach(() => {
|
|
81
|
+
resetScheduleToolSurfaceReadinessForTests();
|
|
82
|
+
processedPrompts.length = 0;
|
|
83
|
+
capturedMcpTools = [];
|
|
84
|
+
mockEmitNotificationSignal.mockClear();
|
|
85
|
+
__resetRegistryForTesting();
|
|
86
|
+
const db = getDb();
|
|
87
|
+
db.run("DELETE FROM cron_runs");
|
|
88
|
+
db.run("DELETE FROM cron_jobs");
|
|
89
|
+
});
|
|
90
|
+
|
|
91
|
+
describe("automatic schedule MCP readiness", () => {
|
|
92
|
+
test("defers a due execute schedule while MCP is still starting", async () => {
|
|
93
|
+
markScheduleToolSurfaceStarting(8);
|
|
94
|
+
const job = await createSchedule({
|
|
95
|
+
name: "Friday tagging",
|
|
96
|
+
cronExpression: "* * * * *",
|
|
97
|
+
message: "Tag new Reader documents",
|
|
98
|
+
mode: "execute",
|
|
99
|
+
});
|
|
100
|
+
rawDb().run("UPDATE cron_jobs SET next_run_at = ?", [Date.now() - 1000]);
|
|
101
|
+
|
|
102
|
+
const result = await runDueSchedulesOnce();
|
|
103
|
+
|
|
104
|
+
expect(result.claimed).toBe(1);
|
|
105
|
+
expect(result.skipped).toBe(1);
|
|
106
|
+
expect(result.completed).toBe(0);
|
|
107
|
+
expect(processedPrompts).toEqual([]);
|
|
108
|
+
const runs = rawDb()
|
|
109
|
+
.query("SELECT status FROM cron_runs WHERE job_id = ?")
|
|
110
|
+
.all(job.id) as Array<{ status: string }>;
|
|
111
|
+
expect(runs).toEqual([]);
|
|
112
|
+
const row = rawDb()
|
|
113
|
+
.query("SELECT status, enabled FROM cron_jobs WHERE id = ?")
|
|
114
|
+
.get(job.id) as { status: string; enabled: number };
|
|
115
|
+
expect(row.status).toBe("active");
|
|
116
|
+
expect(row.enabled).toBe(1);
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
test("still fires notify and script schedules while MCP is starting", async () => {
|
|
120
|
+
markScheduleToolSurfaceStarting(8);
|
|
121
|
+
await createSchedule({
|
|
122
|
+
name: "Ping",
|
|
123
|
+
cronExpression: "* * * * *",
|
|
124
|
+
message: "ping",
|
|
125
|
+
mode: "notify",
|
|
126
|
+
});
|
|
127
|
+
await createSchedule({
|
|
128
|
+
name: "Script",
|
|
129
|
+
cronExpression: "* * * * *",
|
|
130
|
+
message: "run script",
|
|
131
|
+
mode: "script",
|
|
132
|
+
script: "true",
|
|
133
|
+
});
|
|
134
|
+
rawDb().run("UPDATE cron_jobs SET next_run_at = ?", [Date.now() - 1000]);
|
|
135
|
+
|
|
136
|
+
const result = await runDueSchedulesOnce();
|
|
137
|
+
|
|
138
|
+
expect(result.completed).toBe(2);
|
|
139
|
+
expect(mockEmitNotificationSignal).toHaveBeenCalledTimes(1);
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("an automatic execute run sees the registered MCP tool once ready", async () => {
|
|
143
|
+
registerMcpTools("reader", [
|
|
144
|
+
{
|
|
145
|
+
name: "mcp__reader__list_documents",
|
|
146
|
+
description: "List documents",
|
|
147
|
+
defaultRiskLevel: RiskLevel.Low,
|
|
148
|
+
executionTarget: "sandbox",
|
|
149
|
+
input_schema: { type: "object", properties: {}, required: [] },
|
|
150
|
+
category: "",
|
|
151
|
+
async execute() {
|
|
152
|
+
return { content: "ok", isError: false };
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
]);
|
|
156
|
+
resetScheduleToolSurfaceReadinessForTests();
|
|
157
|
+
|
|
158
|
+
await createSchedule({
|
|
159
|
+
name: "Saturday digest",
|
|
160
|
+
cronExpression: "* * * * *",
|
|
161
|
+
message: "Build the Reader digest",
|
|
162
|
+
mode: "execute",
|
|
163
|
+
});
|
|
164
|
+
rawDb().run("UPDATE cron_jobs SET next_run_at = ?", [Date.now() - 1000]);
|
|
165
|
+
|
|
166
|
+
const result = await runDueSchedulesOnce();
|
|
167
|
+
|
|
168
|
+
expect(result.completed).toBe(1);
|
|
169
|
+
expect(processedPrompts).toEqual(["Build the Reader digest"]);
|
|
170
|
+
expect(capturedMcpTools).toContain("mcp__reader__list_documents");
|
|
171
|
+
expect(getTool("mcp__reader__list_documents")).toBeDefined();
|
|
172
|
+
});
|
|
173
|
+
});
|
|
@@ -1,38 +1,19 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Guard over the schedule worker entrypoint's MCP bootstrap.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
* makes as "Unknown tool", while `assistant tools list` reads the daemon's
|
|
9
|
-
* registry over IPC and reports the same tool as registered. The mismatch is
|
|
10
|
-
* what makes the failure hard to place, so it is worth a guard.
|
|
11
|
-
*
|
|
12
|
-
* The worker is also long-lived, so the set it connects at startup goes stale
|
|
13
|
-
* as soon as the config moves. It watches for the daemon's reload signal to
|
|
14
|
-
* rebuild, which is covered here too.
|
|
15
|
-
*
|
|
16
|
-
* The entrypoint installs signal handlers and calls `process.exit`, so it
|
|
17
|
-
* cannot be imported into a test process; these assertions read its source the
|
|
18
|
-
* way `worker-feature-flags.test.ts` does. The behavior of the steps
|
|
19
|
-
* themselves is covered in `src/mcp/__tests__/startup.test.ts` and
|
|
20
|
-
* `src/mcp/__tests__/reload-signal.test.ts`.
|
|
4
|
+
* Behavioral coverage lives in worker-mcp-readiness.test.ts. This file only
|
|
5
|
+
* asserts the process entrypoint still calls the extracted helpers before
|
|
6
|
+
* the first tick, because the entrypoint installs signal handlers and
|
|
7
|
+
* calls process.exit and cannot be imported into a test process.
|
|
21
8
|
*/
|
|
22
9
|
|
|
23
10
|
import { readFileSync } from "node:fs";
|
|
24
11
|
import { join } from "node:path";
|
|
25
12
|
import { describe, expect, test } from "bun:test";
|
|
26
13
|
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
/** The bounded wait that keeps unreachable servers off the critical path. */
|
|
30
|
-
const MCP_GRACE = "MCP_STARTUP_GRACE_MS";
|
|
31
|
-
|
|
32
|
-
/** The reload watcher that keeps the connected set current. */
|
|
14
|
+
const MCP_BOOTSTRAP = "bootstrapScheduleWorkerMcp(";
|
|
15
|
+
const MCP_RELOAD = "reloadScheduleWorkerMcp(";
|
|
33
16
|
const MCP_WATCH = "watchForMcpReload(";
|
|
34
|
-
|
|
35
|
-
/** The worker's first call that can execute a schedule. */
|
|
36
17
|
const WORK_START = "void tick()";
|
|
37
18
|
|
|
38
19
|
function readWorkerSource(): string {
|
|
@@ -40,37 +21,22 @@ function readWorkerSource(): string {
|
|
|
40
21
|
}
|
|
41
22
|
|
|
42
23
|
describe("schedule worker MCP tools", () => {
|
|
43
|
-
test("
|
|
24
|
+
test("bootstraps its own MCP servers before the first schedule tick", () => {
|
|
44
25
|
const source = readWorkerSource();
|
|
45
|
-
const mcpAt = source.indexOf(
|
|
26
|
+
const mcpAt = source.indexOf(MCP_BOOTSTRAP);
|
|
46
27
|
const workAt = source.indexOf(WORK_START);
|
|
47
28
|
|
|
48
29
|
expect(
|
|
49
30
|
mcpAt,
|
|
50
|
-
`The schedule worker must call \`${
|
|
31
|
+
`The schedule worker must call \`${MCP_BOOTSTRAP})\` at startup. This ` +
|
|
51
32
|
"process hosts execute-mode schedule turns, and its tool registry is " +
|
|
52
33
|
"its own: without the call it has no mcp__* tools at all.",
|
|
53
34
|
).toBeGreaterThanOrEqual(0);
|
|
54
35
|
expect(workAt).toBeGreaterThanOrEqual(0);
|
|
55
36
|
expect(
|
|
56
37
|
mcpAt < workAt,
|
|
57
|
-
"The connect starts and is waited on before the first tick
|
|
58
|
-
"
|
|
59
|
-
"against. The wait is bounded (see below), so a server that never " +
|
|
60
|
-
"answers delays it rather than blocking it.",
|
|
61
|
-
).toBe(true);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test("bounds the startup wait so unrelated schedules still fire", () => {
|
|
65
|
-
const source = readWorkerSource();
|
|
66
|
-
|
|
67
|
-
expect(
|
|
68
|
-
source.includes(MCP_GRACE),
|
|
69
|
-
"`McpServerManager.start()` walks servers one at a time and allows " +
|
|
70
|
-
"each 30s to connect and 30s more to list its tools. An unbounded " +
|
|
71
|
-
"wait lets a few unreachable servers hold every due schedule, " +
|
|
72
|
-
"including the notify and script ones that never touch MCP, while " +
|
|
73
|
-
"the PID file already reports this worker as running.",
|
|
38
|
+
"The connect starts and is waited on before the first tick. Tool-backed " +
|
|
39
|
+
"schedules stay deferred until that surface is marked ready.",
|
|
74
40
|
).toBe(true);
|
|
75
41
|
});
|
|
76
42
|
|
|
@@ -78,11 +44,11 @@ describe("schedule worker MCP tools", () => {
|
|
|
78
44
|
const source = readWorkerSource();
|
|
79
45
|
|
|
80
46
|
expect(
|
|
81
|
-
source.includes(MCP_WATCH),
|
|
47
|
+
source.includes(MCP_WATCH) && source.includes(MCP_RELOAD),
|
|
82
48
|
"This process is long-lived and holds its own connections. Without " +
|
|
83
49
|
"the watcher, a server disabled or removed in the config stays " +
|
|
84
50
|
"registered and callable by background schedules until the worker " +
|
|
85
|
-
"restarts.",
|
|
51
|
+
"restarts. Reload must mark the tool surface unready until it settles.",
|
|
86
52
|
).toBe(true);
|
|
87
53
|
});
|
|
88
54
|
});
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { buildSanitizedEnv } from "../tools/terminal/safe-env.js";
|
|
2
2
|
import {
|
|
3
3
|
buildShellInvocation,
|
|
4
|
+
buildShellSpawnFlags,
|
|
4
5
|
terminateProcessTree,
|
|
5
6
|
} from "../util/host-process.js";
|
|
6
7
|
import { getLogger } from "../util/logger.js";
|
|
@@ -64,10 +65,9 @@ export async function runScript(
|
|
|
64
65
|
const shell = buildShellInvocation(command);
|
|
65
66
|
const proc = Bun.spawn([shell.command, ...shell.args], {
|
|
66
67
|
cwd,
|
|
67
|
-
|
|
68
|
+
...buildShellSpawnFlags(),
|
|
68
69
|
stdout: "pipe",
|
|
69
70
|
stderr: "pipe",
|
|
70
|
-
windowsHide: true,
|
|
71
71
|
env: {
|
|
72
72
|
...buildSanitizedEnv(),
|
|
73
73
|
// __SCHEDULE_ID lets a saved command find its own dir; __SCHEDULE_RUN_ID
|
|
@@ -58,6 +58,13 @@ import {
|
|
|
58
58
|
scheduleRetry,
|
|
59
59
|
setScheduleRunConversationId,
|
|
60
60
|
} from "./schedule-store.js";
|
|
61
|
+
import {
|
|
62
|
+
getScheduleToolSurfaceSnapshot,
|
|
63
|
+
getScheduleToolSurfaceState,
|
|
64
|
+
isScheduleToolSurfaceReady,
|
|
65
|
+
MCP_NOT_READY_DEFER_MS,
|
|
66
|
+
scheduleModeNeedsToolSurface,
|
|
67
|
+
} from "./tool-surface-readiness.js";
|
|
61
68
|
import { buildWakeScheduleOptions } from "./wake-schedule-options.js";
|
|
62
69
|
import {
|
|
63
70
|
isScheduleWorkerAdministrativelyStopped,
|
|
@@ -703,6 +710,32 @@ export async function runDueSchedulesOnce(
|
|
|
703
710
|
continue;
|
|
704
711
|
}
|
|
705
712
|
|
|
713
|
+
if (
|
|
714
|
+
scheduleModeNeedsToolSurface(job.mode) &&
|
|
715
|
+
!isScheduleToolSurfaceReady()
|
|
716
|
+
) {
|
|
717
|
+
log.info(
|
|
718
|
+
{
|
|
719
|
+
jobId: job.id,
|
|
720
|
+
name: job.name,
|
|
721
|
+
mode: job.mode,
|
|
722
|
+
toolSurfaceState: getScheduleToolSurfaceState(),
|
|
723
|
+
...getScheduleToolSurfaceSnapshot(),
|
|
724
|
+
},
|
|
725
|
+
"Deferring tool-backed schedule until the MCP tool surface is ready",
|
|
726
|
+
);
|
|
727
|
+
try {
|
|
728
|
+
await deferClaimedSchedule(job.id, Date.now() + MCP_NOT_READY_DEFER_MS);
|
|
729
|
+
} catch (err) {
|
|
730
|
+
log.warn(
|
|
731
|
+
{ err, jobId: job.id },
|
|
732
|
+
"Failed to defer claimed schedule while MCP tool surface is not ready",
|
|
733
|
+
);
|
|
734
|
+
}
|
|
735
|
+
result.skipped += 1;
|
|
736
|
+
continue;
|
|
737
|
+
}
|
|
738
|
+
|
|
706
739
|
const isOneShot = job.expression == null;
|
|
707
740
|
|
|
708
741
|
// ── Notify mode (one-shot or recurring) ─────────────────────────
|
|
@@ -1149,19 +1182,22 @@ export async function runDueSchedulesOnce(
|
|
|
1149
1182
|
// that before the run is called done and its one result is produced.
|
|
1150
1183
|
await awaitDelegatedWork(conversationId, runStartedAt, log);
|
|
1151
1184
|
await completeScheduleRun(runId, { status: "ok" });
|
|
1152
|
-
//
|
|
1153
|
-
//
|
|
1154
|
-
//
|
|
1185
|
+
// Automatic completion notification for successful execute-mode runs.
|
|
1186
|
+
// Quiet schedules skip this fallback so a clean tick stays silent.
|
|
1187
|
+
// Explicit in-run delivery (e.g. `assistant notifications send`) is
|
|
1188
|
+
// unaffected because it never goes through this producer.
|
|
1155
1189
|
// Awaited rather than fired and forgotten: the schedule worker can exit
|
|
1156
1190
|
// once the tick's loop drains, and a detached emit would race that exit.
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
|
|
1161
|
-
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1191
|
+
if (!job.quiet) {
|
|
1192
|
+
await emitScheduleResultNotification({
|
|
1193
|
+
scheduleId: job.id,
|
|
1194
|
+
scheduleName: job.name,
|
|
1195
|
+
conversationId,
|
|
1196
|
+
runId,
|
|
1197
|
+
runStartedAt,
|
|
1198
|
+
rlog: log,
|
|
1199
|
+
});
|
|
1200
|
+
}
|
|
1165
1201
|
if (isOneShot) {
|
|
1166
1202
|
await completeOneShot(job.id);
|
|
1167
1203
|
}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Process-local readiness of the MCP tool surface this process hosts.
|
|
3
|
+
*
|
|
4
|
+
* MCP tools reach the registry only after every configured server has been
|
|
5
|
+
* attempted. Until that pass settles, an execute/wake/workflow schedule that
|
|
6
|
+
* fires would record success while `mcp__*` calls fail as unknown tools.
|
|
7
|
+
* Notify and script schedules do not use that surface and keep firing.
|
|
8
|
+
*
|
|
9
|
+
* Default is ready so callers that never bootstrap MCP (existing scheduler
|
|
10
|
+
* tests, the daemon's unused tick) are not blocked. The schedule worker
|
|
11
|
+
* marks starting/reloading around its own connect.
|
|
12
|
+
*/
|
|
13
|
+
|
|
14
|
+
import {
|
|
15
|
+
EMPTY_MCP_STARTUP_SNAPSHOT,
|
|
16
|
+
type McpStartupSnapshot,
|
|
17
|
+
} from "../mcp/tool-caps.js";
|
|
18
|
+
import type { ScheduleMode } from "./schedule-store.js";
|
|
19
|
+
|
|
20
|
+
export type ScheduleToolSurfaceState = "ready" | "starting" | "reloading";
|
|
21
|
+
|
|
22
|
+
/** How far a claimed tool-backed schedule is pushed back while MCP is not ready. */
|
|
23
|
+
export const MCP_NOT_READY_DEFER_MS = 5_000;
|
|
24
|
+
|
|
25
|
+
let state: ScheduleToolSurfaceState = "ready";
|
|
26
|
+
let snapshot: McpStartupSnapshot = EMPTY_MCP_STARTUP_SNAPSHOT;
|
|
27
|
+
|
|
28
|
+
export function scheduleModeNeedsToolSurface(mode: ScheduleMode): boolean {
|
|
29
|
+
return mode === "execute" || mode === "wake" || mode === "workflow";
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function isScheduleToolSurfaceReady(): boolean {
|
|
33
|
+
return state === "ready";
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function getScheduleToolSurfaceState(): ScheduleToolSurfaceState {
|
|
37
|
+
return state;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
export function getScheduleToolSurfaceSnapshot(): McpStartupSnapshot {
|
|
41
|
+
return snapshot;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function markScheduleToolSurfaceStarting(
|
|
45
|
+
configuredServerCount = 0,
|
|
46
|
+
): void {
|
|
47
|
+
state = "starting";
|
|
48
|
+
snapshot = { ...EMPTY_MCP_STARTUP_SNAPSHOT, configuredServerCount };
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function markScheduleToolSurfaceReloading(): void {
|
|
52
|
+
state = "reloading";
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export function markScheduleToolSurfaceReady(
|
|
56
|
+
next: McpStartupSnapshot = EMPTY_MCP_STARTUP_SNAPSHOT,
|
|
57
|
+
): void {
|
|
58
|
+
state = "ready";
|
|
59
|
+
snapshot = next;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function resetScheduleToolSurfaceReadinessForTests(): void {
|
|
63
|
+
state = "ready";
|
|
64
|
+
snapshot = EMPTY_MCP_STARTUP_SNAPSHOT;
|
|
65
|
+
}
|
|
@@ -19,6 +19,8 @@ import {
|
|
|
19
19
|
type WorkerProcessStatus,
|
|
20
20
|
} from "../util/worker-process.js";
|
|
21
21
|
|
|
22
|
+
const SCHEDULE_WORKER_ENTRY = new URL("./worker.ts", import.meta.url);
|
|
23
|
+
|
|
22
24
|
const log = getLogger("schedule-worker-control");
|
|
23
25
|
|
|
24
26
|
/**
|
|
@@ -42,11 +44,15 @@ export function setScheduleWorkerAdministrativelyStopped(value: boolean): void {
|
|
|
42
44
|
|
|
43
45
|
/**
|
|
44
46
|
* Inspect the PID file to determine whether the schedule worker process is
|
|
45
|
-
* alive. A stale PID file (pointing at a dead process
|
|
46
|
-
* reported as not_running.
|
|
47
|
+
* alive. A stale PID file (pointing at a dead process, or at a live process
|
|
48
|
+
* that is not this worker) is cleaned up and reported as not_running.
|
|
47
49
|
*/
|
|
48
50
|
export function probeScheduleWorker(): WorkerProcessStatus {
|
|
49
|
-
return probeWorkerPidFile(
|
|
51
|
+
return probeWorkerPidFile(
|
|
52
|
+
getScheduleWorkerPidPath(),
|
|
53
|
+
SCHEDULE_WORKER_ENTRY,
|
|
54
|
+
"schedule",
|
|
55
|
+
);
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
export class ScheduleWorkerSpawnError extends WorkerProcessSpawnError {}
|
|
@@ -95,7 +101,7 @@ async function spawnScheduleWorkerProcessUncoalesced(
|
|
|
95
101
|
try {
|
|
96
102
|
return await spawnWorkerProcess({
|
|
97
103
|
pidPath: getScheduleWorkerPidPath(),
|
|
98
|
-
entry:
|
|
104
|
+
entry: SCHEDULE_WORKER_ENTRY,
|
|
99
105
|
packagedEntry: "schedule",
|
|
100
106
|
workerLabel: "Schedule worker",
|
|
101
107
|
options: opts,
|
|
@@ -114,7 +120,11 @@ async function spawnScheduleWorkerProcessUncoalesced(
|
|
|
114
120
|
* `process.kill` itself fails (e.g. EPERM) — a not-running worker is a no-op.
|
|
115
121
|
*/
|
|
116
122
|
export function stopScheduleWorkerProcess(): WorkerProcessStatus {
|
|
117
|
-
return stopWorkerProcess(
|
|
123
|
+
return stopWorkerProcess(
|
|
124
|
+
getScheduleWorkerPidPath(),
|
|
125
|
+
SCHEDULE_WORKER_ENTRY,
|
|
126
|
+
"schedule",
|
|
127
|
+
);
|
|
118
128
|
}
|
|
119
129
|
|
|
120
130
|
/**
|