@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
|
@@ -5,13 +5,16 @@ import { z } from "zod";
|
|
|
5
5
|
import type { BackgroundToolCompletedEvent } from "../../api/events/background-tool-completed.js";
|
|
6
6
|
import { getConfig } from "../../config/loader.js";
|
|
7
7
|
import { RiskLevel } from "../../permissions/types.js";
|
|
8
|
+
import { applyActivePluginName } from "../../plugins/active-plugin-env.js";
|
|
8
9
|
import { wakeAgentForOpportunity } from "../../runtime/agent-wake.js";
|
|
9
10
|
import { broadcastMessage } from "../../runtime/assistant-event-hub.js";
|
|
10
11
|
import { conversationRevealNonce } from "../../runtime/reveal-nonce.js";
|
|
11
12
|
import { redactSecrets } from "../../security/secret-scanner.js";
|
|
12
13
|
import {
|
|
13
14
|
buildShellInvocation,
|
|
15
|
+
buildShellSpawnFlags,
|
|
14
16
|
terminateProcessTree,
|
|
17
|
+
watchShellProcessStart,
|
|
15
18
|
} from "../../util/host-process.js";
|
|
16
19
|
import { getLogger } from "../../util/logger.js";
|
|
17
20
|
import { getDataDir } from "../../util/platform.js";
|
|
@@ -288,6 +291,7 @@ export const shellTool = {
|
|
|
288
291
|
|
|
289
292
|
const env = buildSanitizedEnv();
|
|
290
293
|
env.__CONVERSATION_ID = context.conversationId;
|
|
294
|
+
applyActivePluginName(env, context.conversationId);
|
|
291
295
|
// Secret binding for reveal-derived chat authority — see reveal-nonce.ts.
|
|
292
296
|
env.__REVEAL_NONCE = conversationRevealNonce(context.conversationId);
|
|
293
297
|
// Surface the resolving model to assistant CLI commands so they can tailor
|
|
@@ -324,9 +328,9 @@ export const shellTool = {
|
|
|
324
328
|
cwd: context.workingDir,
|
|
325
329
|
env,
|
|
326
330
|
stdio: ["ignore", "pipe", "pipe"],
|
|
327
|
-
|
|
328
|
-
windowsHide: true,
|
|
331
|
+
...buildShellSpawnFlags(),
|
|
329
332
|
});
|
|
333
|
+
const launch = watchShellProcessStart(child);
|
|
330
334
|
const collector = attachBoundedStdio(child);
|
|
331
335
|
|
|
332
336
|
const killTree = buildKillTree(child, {
|
|
@@ -367,11 +371,13 @@ export const shellTool = {
|
|
|
367
371
|
timedOut,
|
|
368
372
|
});
|
|
369
373
|
|
|
370
|
-
const fmtResult = collector.format(code, timedOut, timeoutSec
|
|
374
|
+
const fmtResult = collector.format(code, timedOut, timeoutSec, {
|
|
375
|
+
started: launch.didStart(),
|
|
376
|
+
});
|
|
371
377
|
|
|
372
378
|
const status: BackgroundToolCompletedEvent["status"] = aborted
|
|
373
379
|
? "cancelled"
|
|
374
|
-
: timedOut
|
|
380
|
+
: timedOut || fmtResult.isError
|
|
375
381
|
? "failed"
|
|
376
382
|
: code === 0
|
|
377
383
|
? "completed"
|
|
@@ -529,9 +535,9 @@ export const shellTool = {
|
|
|
529
535
|
cwd: context.workingDir,
|
|
530
536
|
env,
|
|
531
537
|
stdio: ["ignore", "pipe", "pipe"],
|
|
532
|
-
|
|
533
|
-
windowsHide: true,
|
|
538
|
+
...buildShellSpawnFlags(),
|
|
534
539
|
});
|
|
540
|
+
const launch = watchShellProcessStart(child);
|
|
535
541
|
const collector = attachBoundedStdio(child, {
|
|
536
542
|
onOutput: context.onOutput,
|
|
537
543
|
});
|
|
@@ -573,7 +579,9 @@ export const shellTool = {
|
|
|
573
579
|
timedOut,
|
|
574
580
|
});
|
|
575
581
|
|
|
576
|
-
const fmtResult = collector.format(code, timedOut, timeoutSec
|
|
582
|
+
const fmtResult = collector.format(code, timedOut, timeoutSec, {
|
|
583
|
+
started: launch.didStart(),
|
|
584
|
+
});
|
|
577
585
|
|
|
578
586
|
resolve({
|
|
579
587
|
content: fmtResult.content,
|
|
@@ -837,7 +837,11 @@ export class ToolApprovalHandler {
|
|
|
837
837
|
// sandbox/host routing reflects the tool actually registered under this
|
|
838
838
|
// name at execution time.
|
|
839
839
|
const tool = getTool(name);
|
|
840
|
-
const executionTarget = resolveExecutionTarget(
|
|
840
|
+
const executionTarget = resolveExecutionTarget(
|
|
841
|
+
tool ?? { name },
|
|
842
|
+
input,
|
|
843
|
+
context,
|
|
844
|
+
);
|
|
841
845
|
|
|
842
846
|
// Determine whether this invocation requires a scoped grant. Capture
|
|
843
847
|
// the consume params now but defer the actual atomic consumption until
|
package/src/tools/tool-types.ts
CHANGED
|
@@ -279,9 +279,9 @@ export interface ToolContext {
|
|
|
279
279
|
principal?: string;
|
|
280
280
|
/**
|
|
281
281
|
* Trust classification of the actor who initiated this tool invocation.
|
|
282
|
-
* Broadened to `string` here; the assistant narrows this back to
|
|
283
|
-
*
|
|
284
|
-
*
|
|
282
|
+
* Broadened to `string` here; the assistant narrows this back to
|
|
283
|
+
* `TrustClass` (declared in `@vellumai/gateway-client`) in
|
|
284
|
+
* `assistant/src/tools/types.ts`.
|
|
285
285
|
*/
|
|
286
286
|
trustClass: string;
|
|
287
287
|
/** Channel through which the tool invocation originates (e.g. 'telegram', 'phone'). Used for scoped grant consumption. */
|
package/src/tools/types.ts
CHANGED
|
@@ -6,6 +6,7 @@ import type {
|
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
|
|
8
8
|
import type { AnsweredQuestion } from "../api/events/question-answered.js";
|
|
9
|
+
import type { ToolActivityMetadata } from "../api/events/tool-result.js";
|
|
9
10
|
import {
|
|
10
11
|
CLIENT_OS_VALUES,
|
|
11
12
|
type ClientOs,
|
|
@@ -13,7 +14,6 @@ import {
|
|
|
13
14
|
} from "../channels/types.js";
|
|
14
15
|
import type { LLMCallSite } from "../config/schemas/llm.js";
|
|
15
16
|
import { SEND_USER_MESSAGE_TOOL_NAME } from "../config/send-user-message-constants.js";
|
|
16
|
-
import type { ToolActivityMetadata } from "../daemon/message-types/web-activity.js";
|
|
17
17
|
import type { SecretPromptResult } from "../permissions/secret-prompt-types.js";
|
|
18
18
|
import type { ContentBlock } from "../providers/types.js";
|
|
19
19
|
import type { TrustClass } from "../runtime/trust-class.js";
|
|
@@ -605,7 +605,13 @@ export type ToolDefinition = z.infer<typeof ToolDefinitionSchema>;
|
|
|
605
605
|
export type Tool = Required<
|
|
606
606
|
Omit<ToolDefinition, "exclusive" | "supportedClientOs">
|
|
607
607
|
> &
|
|
608
|
-
Pick<ToolDefinition, "exclusive" | "supportedClientOs"
|
|
608
|
+
Pick<ToolDefinition, "exclusive" | "supportedClientOs"> & {
|
|
609
|
+
/** Invocation-specific boundary for trusted tool implementations. */
|
|
610
|
+
getExecutionTarget?: (
|
|
611
|
+
input: Record<string, unknown>,
|
|
612
|
+
context?: ToolContext,
|
|
613
|
+
) => "sandbox" | "host";
|
|
614
|
+
};
|
|
609
615
|
|
|
610
616
|
/**
|
|
611
617
|
* The kind of entity that owns a tool. `"default"` is the built-in tool set
|
|
@@ -205,11 +205,12 @@ describe("decideWorkerSlot", () => {
|
|
|
205
205
|
).toEqual({ action: "adopt", pid: WORKER });
|
|
206
206
|
});
|
|
207
207
|
|
|
208
|
-
// The cases below
|
|
208
|
+
// The cases below must never reach a kill. Unmatched command lines spawn
|
|
209
|
+
// a new worker without signalling the stranger holding the recycled PID.
|
|
209
210
|
test("never signals an unrelated process on a recycled PID", () => {
|
|
210
211
|
expect(
|
|
211
212
|
decide({ pid: WORKER, ppid: 1, command: "/usr/bin/postgres -D /data" }),
|
|
212
|
-
).toEqual({ action: "
|
|
213
|
+
).toEqual({ action: "spawn" });
|
|
213
214
|
});
|
|
214
215
|
|
|
215
216
|
test("never signals another project's worker.ts on a recycled PID", () => {
|
|
@@ -219,7 +220,7 @@ describe("decideWorkerSlot", () => {
|
|
|
219
220
|
ppid: 1,
|
|
220
221
|
command: "bun run /home/dev/side-project/worker.ts",
|
|
221
222
|
}),
|
|
222
|
-
).toEqual({ action: "
|
|
223
|
+
).toEqual({ action: "spawn" });
|
|
223
224
|
});
|
|
224
225
|
|
|
225
226
|
test("never signals a different worker kind holding this slot", () => {
|
|
@@ -229,7 +230,7 @@ describe("decideWorkerSlot", () => {
|
|
|
229
230
|
ppid: 1,
|
|
230
231
|
command: "bun --smol run /app/runtime/0.10.11/src/monitoring/worker.ts",
|
|
231
232
|
}),
|
|
232
|
-
).toEqual({ action: "
|
|
233
|
+
).toEqual({ action: "spawn" });
|
|
233
234
|
});
|
|
234
235
|
|
|
235
236
|
test("never signals when the process table could not be read", () => {
|
|
@@ -78,49 +78,41 @@ export function isUserInterruptAbort(reason: AbortReason | undefined): boolean {
|
|
|
78
78
|
*/
|
|
79
79
|
export const CANCELLED_TOOL_RESULT_TEXT = "Cancelled by user";
|
|
80
80
|
|
|
81
|
-
/**
|
|
82
|
-
* The instruction both interrupt annotations end on: answer the message that
|
|
83
|
-
* interrupted, then decide what happens to the work it cut off.
|
|
84
|
-
*
|
|
85
|
-
* Shared so the two annotations cannot drift. Resuming the work inline is the
|
|
86
|
-
* trap the last clause closes: the reply the user is waiting for arrives only
|
|
87
|
-
* once the resumed work finishes, so an interrupt that was meant to get their
|
|
88
|
-
* question answered first buys nothing. A subagent carries the work in
|
|
89
|
-
* parallel and leaves the conversation free.
|
|
90
|
-
*/
|
|
91
|
-
const INTERRUPT_PRIORITY_INSTRUCTION =
|
|
92
|
-
"reply to it first, then decide whether to resume or abandon the work that was in progress, and if it is still wanted and too big to finish inline, hand it to a subagent so it continues in parallel instead of holding up the conversation. This is the normal way a conversation flows, not a problem: do not apologize, do not mention that anything was stopped or interrupted, and do not ask the user to wait.";
|
|
93
|
-
|
|
94
81
|
/**
|
|
95
82
|
* Synthetic `tool_result` text for a tool call a newly arrived user message
|
|
96
83
|
* cut off.
|
|
97
84
|
*
|
|
85
|
+
* States the fact about this one call and nothing else. What the model should
|
|
86
|
+
* do about the interruption belongs on the interrupting message
|
|
87
|
+
* ({@link INTERRUPTED_TURN_NOTE_TEXT}), which is read once no matter how many
|
|
88
|
+
* calls the abort stopped and which sits after the user's words rather than
|
|
89
|
+
* before them.
|
|
90
|
+
*
|
|
98
91
|
* Distinct from {@link CANCELLED_TOOL_RESULT_TEXT} because the model's next
|
|
99
92
|
* decision is different. A plain cancel ends the work; a preemption means a
|
|
100
|
-
* message is waiting, the abandoned call may well have taken effect on the
|
|
101
|
-
* outside world before the abort landed
|
|
102
|
-
* message before it decides what to do about the work it was doing.
|
|
93
|
+
* message is waiting, and the abandoned call may well have taken effect on the
|
|
94
|
+
* outside world before the abort landed.
|
|
103
95
|
*/
|
|
104
|
-
export const PREEMPTED_TOOL_RESULT_TEXT =
|
|
96
|
+
export const PREEMPTED_TOOL_RESULT_TEXT =
|
|
97
|
+
"Stopped early because the user sent a new message. This call may have completed anyway; check before repeating it.";
|
|
105
98
|
|
|
106
99
|
/**
|
|
107
100
|
* Annotation appended to the LLM-facing content of the user message that
|
|
108
|
-
* interrupted a turn
|
|
109
|
-
* flight.
|
|
101
|
+
* interrupted a turn.
|
|
110
102
|
*
|
|
111
|
-
*
|
|
112
|
-
*
|
|
113
|
-
*
|
|
114
|
-
*
|
|
115
|
-
*
|
|
116
|
-
* the new message and drops the work it had just committed to.
|
|
103
|
+
* The one place the behavior after an interrupt is spelled out, and it rides
|
|
104
|
+
* on every interrupt, whether or not a tool call was stopped. Leading with the
|
|
105
|
+
* short reply is the point: the user is waiting to learn they were heard, and
|
|
106
|
+
* a turn that opens with more reasoning or another tool call leaves them
|
|
107
|
+
* staring at silence.
|
|
117
108
|
*
|
|
118
109
|
* Tagged rather than written as prose so it reads as a system annotation on
|
|
119
110
|
* the message instead of something the user typed. It rides on the LLM-facing
|
|
120
111
|
* content only: the persisted row stays exactly what the user sent, so no
|
|
121
112
|
* client renders it.
|
|
122
113
|
*/
|
|
123
|
-
export const INTERRUPTED_TURN_NOTE_TEXT =
|
|
114
|
+
export const INTERRUPTED_TURN_NOTE_TEXT =
|
|
115
|
+
"<interrupted_turn>The user sent this while you were still working, so that work stopped. Reply right away, in a line or two, before any more thinking or tool calls, so the user knows you heard them. Then pick the earlier work back up only if it is still wanted. Never apologize for or mention the interruption.</interrupted_turn>";
|
|
124
116
|
|
|
125
117
|
/**
|
|
126
118
|
* The synthetic `tool_result` text that matches why the turn was aborted.
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
export const HUMAN_VERIFICATION_GUIDANCE =
|
|
2
|
+
"CAPTCHAs and bot-detection challenges must be completed by the user. " +
|
|
3
|
+
"This includes drag-to-verify sliders, press-and-hold checks, verification checkboxes and image puzzles. " +
|
|
4
|
+
"Stop before attempting the challenge, even when its controls look easy to automate. " +
|
|
5
|
+
"Do not click, drag, hold, script or retry the verification yourself.";
|
|
6
|
+
|
|
7
|
+
export const DESKTOP_HELP_GUIDANCE =
|
|
8
|
+
HUMAN_VERIFICATION_GUIDANCE +
|
|
9
|
+
" In the virtual desktop, immediately call ask_question with " +
|
|
10
|
+
"desktopHelp: { message, doneLabel, skipLabel } in the user's language. " +
|
|
11
|
+
"Keep message to one short sentence explaining the needed human action. " +
|
|
12
|
+
"This shows an inline preview with Step In, Done and Skip. Wait for the response. " +
|
|
13
|
+
"After Done, inspect a fresh snapshot. If verification remains, request help again. " +
|
|
14
|
+
"Skip leaves the challenge unresolved. Use the same desktopHelp request for other steps that require direct user interaction.";
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { inboundIdentitiesMatch } from "./canonicalize-identity.js";
|
|
4
|
+
|
|
5
|
+
describe("inboundIdentitiesMatch", () => {
|
|
6
|
+
test("matches ids that canonicalize to the same sender", () => {
|
|
7
|
+
expect(inboundIdentitiesMatch("slack", " U123 ", "U123")).toBe(true);
|
|
8
|
+
expect(
|
|
9
|
+
inboundIdentitiesMatch("email", "USER@example.com", "user@example.com"),
|
|
10
|
+
).toBe(true);
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
test("distinct senders do not match", () => {
|
|
14
|
+
expect(inboundIdentitiesMatch("slack", "U123", "U456")).toBe(false);
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test("an empty identifier matches nothing, not even another empty one", () => {
|
|
18
|
+
expect(inboundIdentitiesMatch("slack", "", "")).toBe(false);
|
|
19
|
+
expect(inboundIdentitiesMatch("slack", " ", "U123")).toBe(false);
|
|
20
|
+
});
|
|
21
|
+
});
|
|
@@ -55,3 +55,19 @@ export function canonicalizeInboundIdentity(
|
|
|
55
55
|
|
|
56
56
|
return trimmed;
|
|
57
57
|
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Whether two raw identifiers name the same sender on `channel`. An empty
|
|
61
|
+
* identifier matches nothing.
|
|
62
|
+
*/
|
|
63
|
+
export function inboundIdentitiesMatch(
|
|
64
|
+
channel: ChannelId,
|
|
65
|
+
left: string,
|
|
66
|
+
right: string,
|
|
67
|
+
): boolean {
|
|
68
|
+
const canonicalLeft = canonicalizeInboundIdentity(channel, left);
|
|
69
|
+
return (
|
|
70
|
+
canonicalLeft !== null &&
|
|
71
|
+
canonicalLeft === canonicalizeInboundIdentity(channel, right)
|
|
72
|
+
);
|
|
73
|
+
}
|
package/src/util/errors.ts
CHANGED
|
@@ -151,11 +151,19 @@ export class ProviderError extends AssistantError {
|
|
|
151
151
|
public readonly apiErrorParam?: string;
|
|
152
152
|
public readonly requestId?: string;
|
|
153
153
|
/**
|
|
154
|
-
* Verbatim upstream non-2xx body (possibly truncated).
|
|
155
|
-
*
|
|
156
|
-
*
|
|
154
|
+
* Verbatim upstream non-2xx response body (possibly truncated). This is
|
|
155
|
+
* what the provider returned after rejecting the call, not the request
|
|
156
|
+
* we sent. The inspector's Raw tab uses it when a 4xx/5xx body carries
|
|
157
|
+
* detail the extracted `apiError*` fields drop.
|
|
157
158
|
*/
|
|
158
159
|
public readonly rawBody?: string;
|
|
160
|
+
/**
|
|
161
|
+
* Inspectable SDK/wire request payload for the call that failed. This is
|
|
162
|
+
* the outbound request, not the error response (`rawBody`). Provider
|
|
163
|
+
* `sendMessage` throws attach it so inspector rows show the same request
|
|
164
|
+
* shape as a successful `usage` row.
|
|
165
|
+
*/
|
|
166
|
+
public readonly rawRequest?: unknown;
|
|
159
167
|
/**
|
|
160
168
|
* Tagged daemon-owned abort reason carried over from the AbortSignal that
|
|
161
169
|
* triggered this error. Untyped here to avoid a daemon→util import cycle;
|
|
@@ -181,6 +189,7 @@ export class ProviderError extends AssistantError {
|
|
|
181
189
|
apiErrorParam?: string;
|
|
182
190
|
requestId?: string;
|
|
183
191
|
rawBody?: string;
|
|
192
|
+
rawRequest?: unknown;
|
|
184
193
|
reason?: ProviderErrorReason;
|
|
185
194
|
},
|
|
186
195
|
) {
|
|
@@ -192,6 +201,7 @@ export class ProviderError extends AssistantError {
|
|
|
192
201
|
this.apiErrorParam = options?.apiErrorParam;
|
|
193
202
|
this.requestId = options?.requestId;
|
|
194
203
|
this.rawBody = options?.rawBody;
|
|
204
|
+
this.rawRequest = options?.rawRequest;
|
|
195
205
|
this.abortReason = options?.abortReason;
|
|
196
206
|
this.reason = options?.reason;
|
|
197
207
|
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { EventEmitter } from "node:events";
|
|
1
2
|
import { expect, mock, test } from "bun:test";
|
|
2
3
|
|
|
3
|
-
import { terminateProcessTree } from "./host-process.js";
|
|
4
|
+
import { terminateProcessTree, watchShellProcessStart } from "./host-process.js";
|
|
4
5
|
|
|
5
6
|
test("Windows process trees use taskkill and fall back to the direct child", () => {
|
|
6
7
|
const kill = mock(() => true);
|
|
@@ -15,3 +16,18 @@ test("Windows process trees use taskkill and fall back to the direct child", ()
|
|
|
15
16
|
expect(kill).toHaveBeenCalledTimes(1);
|
|
16
17
|
expect(kill).toHaveBeenCalledWith();
|
|
17
18
|
});
|
|
19
|
+
|
|
20
|
+
test("watchShellProcessStart is false until spawn or a pid appears", () => {
|
|
21
|
+
const child = new EventEmitter() as EventEmitter & { pid?: number };
|
|
22
|
+
const launch = watchShellProcessStart(child);
|
|
23
|
+
expect(launch.didStart()).toBe(false);
|
|
24
|
+
|
|
25
|
+
child.emit("spawn");
|
|
26
|
+
expect(launch.didStart()).toBe(true);
|
|
27
|
+
});
|
|
28
|
+
|
|
29
|
+
test("watchShellProcessStart treats a pid assigned at construction as started", () => {
|
|
30
|
+
const child = new EventEmitter() as EventEmitter & { pid?: number };
|
|
31
|
+
child.pid = 4242;
|
|
32
|
+
expect(watchShellProcessStart(child).didStart()).toBe(true);
|
|
33
|
+
});
|
package/src/util/host-process.ts
CHANGED
|
@@ -2,10 +2,34 @@ import { spawn } from "node:child_process";
|
|
|
2
2
|
|
|
3
3
|
export {
|
|
4
4
|
buildShellInvocation,
|
|
5
|
+
buildShellSpawnFlags,
|
|
5
6
|
pathListDelimiter,
|
|
6
7
|
prependUniquePathEntries,
|
|
7
8
|
} from "@vellumai/environments/shell";
|
|
8
9
|
|
|
10
|
+
export interface ShellProcessStartWatch {
|
|
11
|
+
didStart(): boolean;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Record whether a spawned child actually started. A `close` with exit 0 and
|
|
16
|
+
* empty stdio is not proof of execution: Windows can emit that when the
|
|
17
|
+
* process was never created. Callers must treat `didStart() === false` as a
|
|
18
|
+
* launch failure.
|
|
19
|
+
*/
|
|
20
|
+
export function watchShellProcessStart(child: {
|
|
21
|
+
pid?: number;
|
|
22
|
+
once(event: "spawn", listener: () => void): unknown;
|
|
23
|
+
}): ShellProcessStartWatch {
|
|
24
|
+
let spawnSeen = child.pid != null;
|
|
25
|
+
child.once("spawn", () => {
|
|
26
|
+
spawnSeen = true;
|
|
27
|
+
});
|
|
28
|
+
return {
|
|
29
|
+
didStart: () => spawnSeen || child.pid != null,
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
|
|
9
33
|
export interface KillableProcess {
|
|
10
34
|
pid?: number;
|
|
11
35
|
kill: unknown;
|
|
@@ -33,6 +33,9 @@ export function isVisionNotSupportedError(message: string): boolean {
|
|
|
33
33
|
export const CHAT_TEMPLATE_FAILURE_PATTERNS = [
|
|
34
34
|
/appl\w* (?:the )?chat[ _-]?template/i,
|
|
35
35
|
/chat[ _-]?template (?:error|render)/i,
|
|
36
|
+
// Fireworks surfaces the renderer's raw Python str.join TypeError without
|
|
37
|
+
// naming the template: "sequence item 0: expected str instance, list found".
|
|
38
|
+
/sequence item \d+: expected str instance, list found/i,
|
|
36
39
|
];
|
|
37
40
|
|
|
38
41
|
/**
|
package/src/util/unicode.ts
CHANGED
|
@@ -67,6 +67,35 @@ export function safeStringSlice(
|
|
|
67
67
|
return str.slice(safeStart, safeEnd);
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
+
/**
|
|
71
|
+
* A `[start, end)` character window of at most `maxChars` code units that
|
|
72
|
+
* never splits a surrogate pair, for paging through text by offset. A split
|
|
73
|
+
* leaves a lone half at each edge, and each encodes to U+FFFD, so the
|
|
74
|
+
* character is lost from both this window and the next one paged in after
|
|
75
|
+
* it. `charCodeAt` reads the underlying text so a caller need not hold it as
|
|
76
|
+
* one string.
|
|
77
|
+
*/
|
|
78
|
+
export function surrogateSafeWindow(
|
|
79
|
+
total: number,
|
|
80
|
+
charCodeAt: (index: number) => number,
|
|
81
|
+
requestedStart: number,
|
|
82
|
+
maxChars: number,
|
|
83
|
+
): { start: number; end: number } {
|
|
84
|
+
let start = Math.max(0, Math.min(requestedStart, total));
|
|
85
|
+
if (start > 0 && start < total && isLowSurrogate(charCodeAt(start))) {
|
|
86
|
+
start -= 1;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let end = Math.min(total, start + maxChars);
|
|
90
|
+
if (end > start && end < total && isHighSurrogate(charCodeAt(end - 1))) {
|
|
91
|
+
// Backing off would empty a one-character window, which stalls paging on
|
|
92
|
+
// the same offset, so take the whole pair instead.
|
|
93
|
+
end = end - 1 > start ? end - 1 : Math.min(total, end + 1);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return { start, end };
|
|
97
|
+
}
|
|
98
|
+
|
|
70
99
|
/**
|
|
71
100
|
* Replace every orphaned UTF-16 surrogate in `str` with U+FFFD
|
|
72
101
|
* (REPLACEMENT CHARACTER).
|
|
@@ -50,13 +50,11 @@ function isEsrchError(err: unknown): boolean {
|
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
/**
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
*/
|
|
59
|
-
export function probeWorkerPidFile(path: string): WorkerProcessStatus {
|
|
53
|
+
/** Kill-0 plus command-line identity for a PID file. */
|
|
54
|
+
function probePidFile(
|
|
55
|
+
path: string,
|
|
56
|
+
signature: readonly string[],
|
|
57
|
+
): WorkerProcessStatus {
|
|
60
58
|
if (!existsSync(path)) {
|
|
61
59
|
return { status: "not_running" };
|
|
62
60
|
}
|
|
@@ -69,22 +67,49 @@ export function probeWorkerPidFile(path: string): WorkerProcessStatus {
|
|
|
69
67
|
|
|
70
68
|
try {
|
|
71
69
|
process.kill(pid, 0);
|
|
72
|
-
return { status: "running", pid };
|
|
73
70
|
} catch (err: unknown) {
|
|
74
71
|
if (isEsrchError(err)) {
|
|
75
|
-
|
|
76
|
-
try {
|
|
77
|
-
unlinkSync(path);
|
|
78
|
-
} catch {
|
|
79
|
-
// best-effort
|
|
80
|
-
}
|
|
72
|
+
unlinkPidFileIfNames(path, pid);
|
|
81
73
|
return { status: "not_running" };
|
|
82
74
|
}
|
|
83
75
|
// Any other error (e.g. EPERM: the process exists but this caller may not
|
|
84
|
-
// signal it) means the process is alive.
|
|
85
|
-
// letting the error escape a status probe.
|
|
86
|
-
|
|
76
|
+
// signal it) means the process is alive. Fall through to the identity
|
|
77
|
+
// check rather than letting the error escape a status probe.
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const fate = classifyOrphanAfterWait(
|
|
81
|
+
true,
|
|
82
|
+
readRawProcessCommand(pid),
|
|
83
|
+
signature,
|
|
84
|
+
);
|
|
85
|
+
if (fate === "gone") {
|
|
86
|
+
log.info(
|
|
87
|
+
{ pid, pidPath: path },
|
|
88
|
+
"Worker PID file names a live process this runtime does not recognise as its worker; releasing the slot rather than treating it as running",
|
|
89
|
+
);
|
|
90
|
+
unlinkPidFileIfNames(path, pid);
|
|
91
|
+
return { status: "not_running" };
|
|
87
92
|
}
|
|
93
|
+
return { status: "running", pid };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Read a PID file and report whether this worker is actually running there.
|
|
98
|
+
*
|
|
99
|
+
* Identity comes from the same `entry` / `packagedEntry` spawn uses. A missing
|
|
100
|
+
* or malformed file reports not_running. A file pointing at a dead process, or
|
|
101
|
+
* at a live process whose command line is not this worker (a recycled PID
|
|
102
|
+
* after a container restart), is cleaned up and reported as not_running. A
|
|
103
|
+
* live PID whose command line cannot be read is reported running: uncertainty
|
|
104
|
+
* must not start a second worker next to a maybe-live one, and must not be
|
|
105
|
+
* treated as a license to signal a stranger.
|
|
106
|
+
*/
|
|
107
|
+
export function probeWorkerPidFile(
|
|
108
|
+
pidPath: string,
|
|
109
|
+
entry: URL,
|
|
110
|
+
packagedEntry?: PackagedWorkerEntry,
|
|
111
|
+
): WorkerProcessStatus {
|
|
112
|
+
return probePidFile(pidPath, workerKindSignature(entry, packagedEntry));
|
|
88
113
|
}
|
|
89
114
|
|
|
90
115
|
/** Thrown when a worker process fails to come up within the wait window. */
|
|
@@ -394,11 +419,13 @@ async function stopOrphanedWorker(
|
|
|
394
419
|
/**
|
|
395
420
|
* What to do about the process a worker's PID file currently names.
|
|
396
421
|
*
|
|
397
|
-
* - `adopt`: reuse it.
|
|
398
|
-
*
|
|
399
|
-
*
|
|
422
|
+
* - `adopt`: reuse it. It is this process's own worker, it belongs to
|
|
423
|
+
* another live owner, or its identity could not be read so a second
|
|
424
|
+
* worker must not be started next to a maybe-live one.
|
|
400
425
|
* - `reclaim`: an orphan left by an owner that is gone. Stop it, then spawn.
|
|
401
|
-
* - `spawn`: nothing is holding the slot
|
|
426
|
+
* - `spawn`: nothing is holding the slot, including a live PID whose
|
|
427
|
+
* command line is not this worker (a recycled PID). Never signal that
|
|
428
|
+
* process.
|
|
402
429
|
*/
|
|
403
430
|
export type WorkerSlotDecision =
|
|
404
431
|
| { action: "adopt"; pid: number }
|
|
@@ -410,9 +437,12 @@ export type WorkerSlotDecision =
|
|
|
410
437
|
*
|
|
411
438
|
* `reclaim` is the only outcome that signals a process, and it requires two
|
|
412
439
|
* independent things to agree: the command line marks the process as this
|
|
413
|
-
* worker, and parentage says no daemon owns it. A missing row
|
|
414
|
-
* command line
|
|
415
|
-
*
|
|
440
|
+
* worker, and parentage says no daemon owns it. A missing row and an
|
|
441
|
+
* unreadable command line fall back to `adopt`, so an uncertain answer never
|
|
442
|
+
* costs a process its life and never starts a duplicate. A command line that
|
|
443
|
+
* does not match is `spawn` without a signal: the PID file is stale, and
|
|
444
|
+
* treating that PID as the worker would leave the slot occupied by a
|
|
445
|
+
* stranger forever.
|
|
416
446
|
*
|
|
417
447
|
* `isOwnerAlive` is the caller's definition of a legitimate owner. These
|
|
418
448
|
* workers have exactly one, the daemon, so passing a plain liveness probe
|
|
@@ -435,7 +465,7 @@ export function decideWorkerSlot(
|
|
|
435
465
|
return { action: "adopt", pid: status.pid };
|
|
436
466
|
}
|
|
437
467
|
if (!matchesSignature(row.command, signature)) {
|
|
438
|
-
return { action: "
|
|
468
|
+
return { action: "spawn" };
|
|
439
469
|
}
|
|
440
470
|
const ownership = classifyWorkerOwnership(
|
|
441
471
|
row,
|
|
@@ -458,7 +488,7 @@ function inspectWorkerSlot(
|
|
|
458
488
|
pidPath: string,
|
|
459
489
|
signature: readonly string[],
|
|
460
490
|
): WorkerSlotDecision {
|
|
461
|
-
const status =
|
|
491
|
+
const status = probePidFile(pidPath, signature);
|
|
462
492
|
if (status.status !== "running" || status.pid == null) {
|
|
463
493
|
return { action: "spawn" };
|
|
464
494
|
}
|
|
@@ -479,11 +509,11 @@ function inspectWorkerSlot(
|
|
|
479
509
|
if (row && !matchesSignature(row.command, signature)) {
|
|
480
510
|
log.info(
|
|
481
511
|
{ pid: row.pid, pidPath },
|
|
482
|
-
"Worker PID file names a live process this runtime does not recognise as its worker;
|
|
512
|
+
"Worker PID file names a live process this runtime does not recognise as its worker; releasing the slot rather than treating it as running",
|
|
483
513
|
);
|
|
484
514
|
}
|
|
485
515
|
|
|
486
|
-
|
|
516
|
+
const decision = decideWorkerSlot(
|
|
487
517
|
status,
|
|
488
518
|
row,
|
|
489
519
|
signature,
|
|
@@ -491,6 +521,12 @@ function inspectWorkerSlot(
|
|
|
491
521
|
(pid) => isDaemonCommand(commandOf(pid)),
|
|
492
522
|
pid1OwnsWorkers(commandOf(1)),
|
|
493
523
|
);
|
|
524
|
+
// A spawn decision while the PID file still names a live stranger would
|
|
525
|
+
// make waitForWorkerPidFile treat that stale file as readiness.
|
|
526
|
+
if (decision.action === "spawn") {
|
|
527
|
+
unlinkPidFileIfNames(pidPath, status.pid);
|
|
528
|
+
}
|
|
529
|
+
return decision;
|
|
494
530
|
}
|
|
495
531
|
|
|
496
532
|
/**
|
|
@@ -508,7 +544,7 @@ async function reclaimWorkerSlot(
|
|
|
508
544
|
// Still running and beyond our reach. One stale worker beats two live ones.
|
|
509
545
|
return pid;
|
|
510
546
|
}
|
|
511
|
-
const replacement =
|
|
547
|
+
const replacement = probePidFile(pidPath, signature);
|
|
512
548
|
return replacement.status === "running" && replacement.pid != null
|
|
513
549
|
? replacement.pid
|
|
514
550
|
: null;
|
|
@@ -519,7 +555,8 @@ async function reclaimWorkerSlot(
|
|
|
519
555
|
* process, and wait for it to report readiness by writing its PID file. The
|
|
520
556
|
* child is `unref`'d, so the spawning process never blocks on it.
|
|
521
557
|
*
|
|
522
|
-
* If a worker is already running (
|
|
558
|
+
* If a worker is already running (the PID file names a live process whose
|
|
559
|
+
* command line matches this worker), returns its PID with
|
|
523
560
|
* `alreadyRunning: true` rather than spawning a second one. Throws
|
|
524
561
|
* {@link WorkerProcessSpawnError} if the child crashes during startup or
|
|
525
562
|
* never writes its PID file within the wait window.
|
|
@@ -633,14 +670,19 @@ export async function spawnWorkerProcess(args: {
|
|
|
633
670
|
|
|
634
671
|
/**
|
|
635
672
|
* Send SIGTERM to the worker process behind `pidPath` if it is actually
|
|
636
|
-
*
|
|
673
|
+
* this worker.
|
|
637
674
|
*
|
|
638
675
|
* Returns the status observed before signalling, so callers can report
|
|
639
|
-
* whether anything was stopped.
|
|
640
|
-
*
|
|
676
|
+
* whether anything was stopped. A PID file that names a dead process or a
|
|
677
|
+
* live process that is not this worker is a no-op. Only throws if
|
|
678
|
+
* `process.kill` itself fails (e.g. EPERM).
|
|
641
679
|
*/
|
|
642
|
-
export function stopWorkerProcess(
|
|
643
|
-
|
|
680
|
+
export function stopWorkerProcess(
|
|
681
|
+
pidPath: string,
|
|
682
|
+
entry: URL,
|
|
683
|
+
packagedEntry?: PackagedWorkerEntry,
|
|
684
|
+
): WorkerProcessStatus {
|
|
685
|
+
const current = probeWorkerPidFile(pidPath, entry, packagedEntry);
|
|
644
686
|
if (current.status === "running" && current.pid != null) {
|
|
645
687
|
process.kill(current.pid, "SIGTERM");
|
|
646
688
|
}
|