@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
|
@@ -31,6 +31,10 @@ import {
|
|
|
31
31
|
type ConversationCreatedInfo,
|
|
32
32
|
NotificationBroadcaster,
|
|
33
33
|
} from "./broadcaster.js";
|
|
34
|
+
import {
|
|
35
|
+
intersectChannelAllowlist,
|
|
36
|
+
readChannelAllowlist,
|
|
37
|
+
} from "./channel-allowlist.js";
|
|
34
38
|
import { enforceRoutingIntent, evaluateSignal } from "./decision-engine.js";
|
|
35
39
|
import { updateDecision } from "./decisions-store.js";
|
|
36
40
|
import {
|
|
@@ -51,6 +55,7 @@ import type {
|
|
|
51
55
|
import type {
|
|
52
56
|
NotificationChannel,
|
|
53
57
|
NotificationDeliveryResult,
|
|
58
|
+
NotificationReceiptClass,
|
|
54
59
|
} from "./types.js";
|
|
55
60
|
|
|
56
61
|
const log = getLogger("emit-signal");
|
|
@@ -69,20 +74,27 @@ export function getBroadcaster(): NotificationBroadcaster {
|
|
|
69
74
|
new PlatformPushAdapter(),
|
|
70
75
|
]);
|
|
71
76
|
|
|
72
|
-
// Wire the conversation-created callback so the
|
|
73
|
-
//
|
|
74
|
-
//
|
|
77
|
+
// Wire the conversation-created callback so the event goes out as soon
|
|
78
|
+
// as a vellum notification conversation is paired, before slower channel
|
|
79
|
+
// deliveries (e.g. Telegram) run.
|
|
80
|
+
// A guardian-sensitive conversation's title reaches only the guardian's
|
|
81
|
+
// own connections, the same scoping the vellum adapter applies to the
|
|
82
|
+
// notification itself.
|
|
75
83
|
broadcasterInstance.setOnConversationCreated((info) => {
|
|
76
|
-
broadcastMessage(
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
84
|
+
broadcastMessage(
|
|
85
|
+
{
|
|
86
|
+
type: "notification_conversation_created",
|
|
87
|
+
conversationId: info.conversationId,
|
|
88
|
+
title: info.title,
|
|
89
|
+
sourceEventName: info.sourceEventName,
|
|
90
|
+
targetGuardianPrincipalId: info.targetGuardianPrincipalId,
|
|
91
|
+
groupId: info.groupId,
|
|
92
|
+
source: info.source,
|
|
93
|
+
silent: info.silent,
|
|
94
|
+
},
|
|
95
|
+
undefined,
|
|
96
|
+
{ targetActorPrincipalId: info.targetGuardianPrincipalId },
|
|
97
|
+
);
|
|
86
98
|
log.info(
|
|
87
99
|
{
|
|
88
100
|
conversationId: info.conversationId,
|
|
@@ -240,7 +252,9 @@ export interface EmitSignalResult {
|
|
|
240
252
|
deduplicated: boolean;
|
|
241
253
|
dispatched: boolean;
|
|
242
254
|
reason: string;
|
|
255
|
+
selectedChannels: NotificationChannel[];
|
|
243
256
|
deliveryResults: NotificationDeliveryResult[];
|
|
257
|
+
receiptClass: NotificationReceiptClass;
|
|
244
258
|
/**
|
|
245
259
|
* True when the pipeline threw before reaching a verdict. Dispatch, dedupe,
|
|
246
260
|
* suppression, and a blocked deterministic check are all verdicts. Callers
|
|
@@ -250,6 +264,55 @@ export interface EmitSignalResult {
|
|
|
250
264
|
pipelineFailed: boolean;
|
|
251
265
|
}
|
|
252
266
|
|
|
267
|
+
const PROVIDER_RECEIPT_CHANNELS = new Set(["telegram", "slack", "discord"]);
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* Strongest proof the emit path can report from adapter results. A vellum
|
|
271
|
+
* `sent` row means the assistant broadcast a `notification_intent`; it is
|
|
272
|
+
* not a client ACK that the OS posted a banner.
|
|
273
|
+
*/
|
|
274
|
+
export function classifyNotificationReceipt(
|
|
275
|
+
results: readonly NotificationDeliveryResult[],
|
|
276
|
+
): NotificationReceiptClass {
|
|
277
|
+
const accepted = results.filter((result) => {
|
|
278
|
+
return result.status === "sent" || result.status === "pending";
|
|
279
|
+
});
|
|
280
|
+
if (
|
|
281
|
+
accepted.some((result) => {
|
|
282
|
+
return PROVIDER_RECEIPT_CHANNELS.has(result.channel);
|
|
283
|
+
})
|
|
284
|
+
) {
|
|
285
|
+
return "provider_accepted";
|
|
286
|
+
}
|
|
287
|
+
if (
|
|
288
|
+
accepted.some((result) => {
|
|
289
|
+
return result.channel === "platform";
|
|
290
|
+
})
|
|
291
|
+
) {
|
|
292
|
+
return "gateway_accepted";
|
|
293
|
+
}
|
|
294
|
+
return "unknown";
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
function emitOutcome(
|
|
298
|
+
partial: Omit<
|
|
299
|
+
EmitSignalResult,
|
|
300
|
+
"deliveryResults" | "selectedChannels" | "receiptClass"
|
|
301
|
+
> & {
|
|
302
|
+
deliveryResults?: NotificationDeliveryResult[];
|
|
303
|
+
selectedChannels?: NotificationChannel[];
|
|
304
|
+
},
|
|
305
|
+
): EmitSignalResult {
|
|
306
|
+
const deliveryResults = partial.deliveryResults ?? [];
|
|
307
|
+
const selectedChannels = partial.selectedChannels ?? [];
|
|
308
|
+
return {
|
|
309
|
+
...partial,
|
|
310
|
+
selectedChannels,
|
|
311
|
+
deliveryResults,
|
|
312
|
+
receiptClass: classifyNotificationReceipt(deliveryResults),
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
|
|
253
316
|
/**
|
|
254
317
|
* True when at least one channel adapter has already been handed the signal.
|
|
255
318
|
* `sent` is a completed delivery; `pending` is the platform push that passed
|
|
@@ -333,14 +396,13 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
333
396
|
{ signalId, dedupeKey: params.dedupeKey },
|
|
334
397
|
"Signal deduplicated at event store level",
|
|
335
398
|
);
|
|
336
|
-
return {
|
|
399
|
+
return emitOutcome({
|
|
337
400
|
signalId,
|
|
338
401
|
deduplicated: true,
|
|
339
402
|
dispatched: false,
|
|
340
403
|
reason: "Signal deduplicated at event store level",
|
|
341
|
-
deliveryResults: [],
|
|
342
404
|
pipelineFailed: false,
|
|
343
|
-
};
|
|
405
|
+
});
|
|
344
406
|
}
|
|
345
407
|
eventPersisted = true;
|
|
346
408
|
|
|
@@ -357,14 +419,13 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
357
419
|
{ signalId, reason: sourceActiveCheck.reason },
|
|
358
420
|
"Signal suppressed before decision stage (source-active)",
|
|
359
421
|
);
|
|
360
|
-
return {
|
|
422
|
+
return emitOutcome({
|
|
361
423
|
signalId,
|
|
362
424
|
deduplicated: false,
|
|
363
425
|
dispatched: false,
|
|
364
426
|
reason: `Signal suppressed: ${sourceActiveCheck.reason}`,
|
|
365
|
-
deliveryResults: [],
|
|
366
427
|
pipelineFailed: false,
|
|
367
|
-
};
|
|
428
|
+
});
|
|
368
429
|
}
|
|
369
430
|
|
|
370
431
|
// Step 2: Evaluate the signal through the decision engine
|
|
@@ -398,8 +459,31 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
398
459
|
// dispatch rank, so selection order only matters to single_channel
|
|
399
460
|
// enforcement's first-selected fallback (step 2.5b), which must keep
|
|
400
461
|
// the in-app banner rather than a push the server may skip.
|
|
462
|
+
const exclusiveAllowlist = readChannelAllowlist(signal.contextPayload);
|
|
401
463
|
const urgency = signal.attentionHints.urgency;
|
|
402
|
-
if (
|
|
464
|
+
if (exclusiveAllowlist) {
|
|
465
|
+
// Exclusive allowlist wins over the default set, urgent force, and
|
|
466
|
+
// routing-intent expansion. Delivery is the allowlist intersected
|
|
467
|
+
// with connected channels.
|
|
468
|
+
const allowed = intersectChannelAllowlist(
|
|
469
|
+
exclusiveAllowlist,
|
|
470
|
+
connectedChannels,
|
|
471
|
+
);
|
|
472
|
+
const alreadyMatches =
|
|
473
|
+
allowed.length === decision.selectedChannels.length &&
|
|
474
|
+
allowed.every((channel) => {
|
|
475
|
+
return decision.selectedChannels.includes(channel);
|
|
476
|
+
}) &&
|
|
477
|
+
decision.shouldNotify === allowed.length > 0;
|
|
478
|
+
if (!alreadyMatches) {
|
|
479
|
+
decision = {
|
|
480
|
+
...decision,
|
|
481
|
+
selectedChannels: allowed,
|
|
482
|
+
shouldNotify: allowed.length > 0,
|
|
483
|
+
reasoningSummary: `${decision.reasoningSummary} (channelAllowlist: ${allowed.join(", ") || "none available"})`,
|
|
484
|
+
};
|
|
485
|
+
}
|
|
486
|
+
} else if (
|
|
403
487
|
(urgency === "high" || urgency === "critical") &&
|
|
404
488
|
decision.shouldNotify
|
|
405
489
|
) {
|
|
@@ -427,13 +511,16 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
427
511
|
}
|
|
428
512
|
}
|
|
429
513
|
|
|
430
|
-
// Step 2.5b: Enforce routing intent policy (fire-time guard)
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
514
|
+
// Step 2.5b: Enforce routing intent policy (fire-time guard).
|
|
515
|
+
// An exclusive allowlist already closed the channel set.
|
|
516
|
+
if (!exclusiveAllowlist) {
|
|
517
|
+
decision = enforceRoutingIntent(
|
|
518
|
+
decision,
|
|
519
|
+
signal.routingIntent,
|
|
520
|
+
connectedChannels,
|
|
521
|
+
signal.sourceChannel,
|
|
522
|
+
);
|
|
523
|
+
}
|
|
437
524
|
|
|
438
525
|
// Step 2.5c: Access-request signals carry a decisionable canonical
|
|
439
526
|
// guardian request created before this emit, and that row suppresses
|
|
@@ -509,22 +596,21 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
509
596
|
{ signalId, reason: checkResult.reason },
|
|
510
597
|
"Signal blocked by deterministic checks",
|
|
511
598
|
);
|
|
512
|
-
return {
|
|
599
|
+
return emitOutcome({
|
|
513
600
|
signalId,
|
|
514
601
|
deduplicated: false,
|
|
515
602
|
dispatched: false,
|
|
516
603
|
reason: `Signal blocked by deterministic checks: ${checkResult.reason}`,
|
|
517
|
-
deliveryResults: [],
|
|
518
604
|
pipelineFailed: false,
|
|
519
|
-
};
|
|
605
|
+
});
|
|
520
606
|
}
|
|
521
607
|
}
|
|
522
608
|
|
|
523
609
|
// Step 4: Dispatch through the broadcaster
|
|
524
610
|
// Note: notification_conversation_created events are emitted eagerly inside
|
|
525
611
|
// the broadcaster as soon as vellum conversation pairing succeeds, rather
|
|
526
|
-
// than after all channel deliveries complete
|
|
527
|
-
//
|
|
612
|
+
// than after all channel deliveries complete, so a slow Telegram delivery
|
|
613
|
+
// cannot delay it.
|
|
528
614
|
const broadcaster = getBroadcaster();
|
|
529
615
|
const dispatchResult = await dispatchDecision(
|
|
530
616
|
signal,
|
|
@@ -562,14 +648,15 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
562
648
|
},
|
|
563
649
|
"Signal pipeline complete",
|
|
564
650
|
);
|
|
565
|
-
return {
|
|
651
|
+
return emitOutcome({
|
|
566
652
|
signalId,
|
|
567
653
|
deduplicated: false,
|
|
568
654
|
dispatched: dispatchResult.dispatched,
|
|
569
655
|
reason: dispatchResult.reason,
|
|
656
|
+
selectedChannels: decision.selectedChannels,
|
|
570
657
|
deliveryResults: dispatchResult.deliveryResults,
|
|
571
658
|
pipelineFailed: false,
|
|
572
|
-
};
|
|
659
|
+
});
|
|
573
660
|
} catch (err) {
|
|
574
661
|
const errMsg = err instanceof Error ? err.message : String(err);
|
|
575
662
|
log.error(
|
|
@@ -599,13 +686,12 @@ export async function emitNotificationSignal<TEventName extends string>(
|
|
|
599
686
|
if (params.throwOnError) {
|
|
600
687
|
throw err instanceof Error ? err : new Error(errMsg);
|
|
601
688
|
}
|
|
602
|
-
return {
|
|
689
|
+
return emitOutcome({
|
|
603
690
|
signalId,
|
|
604
691
|
deduplicated: false,
|
|
605
692
|
dispatched: false,
|
|
606
693
|
reason: `Signal pipeline failed: ${errMsg}`,
|
|
607
|
-
deliveryResults: [],
|
|
608
694
|
pipelineFailed: true,
|
|
609
|
-
};
|
|
695
|
+
});
|
|
610
696
|
}
|
|
611
697
|
}
|
|
@@ -30,6 +30,7 @@ import {
|
|
|
30
30
|
import { publishConversationMessagesChanged } from "../runtime/sync/resource-sync-events.js";
|
|
31
31
|
import { getLogger } from "../util/logger.js";
|
|
32
32
|
import { normalizeTitle, stripMarkdown } from "../util/short-title.js";
|
|
33
|
+
import { readChannelAllowlist } from "./channel-allowlist.js";
|
|
33
34
|
import { isConversationSeedSane } from "./conversation-seed-composer.js";
|
|
34
35
|
import { deriveTitle } from "./copy-composer.js";
|
|
35
36
|
import {
|
|
@@ -459,12 +460,10 @@ const EVENT_CATEGORY_MAP: Record<string, FeedItemCategory> = {
|
|
|
459
460
|
|
|
460
461
|
/**
|
|
461
462
|
* Map a signal's source event to a feed category, or nothing when the event
|
|
462
|
-
* has no entry. An unmapped event
|
|
463
|
-
*
|
|
464
|
-
*
|
|
465
|
-
* category
|
|
466
|
-
* carries none: readers that filter by category skip it, and nothing has
|
|
467
|
-
* to guess.
|
|
463
|
+
* has no entry. An unmapped event, such as a deliberate assistant
|
|
464
|
+
* notification (`assistant.share`), carries no category rather than a
|
|
465
|
+
* catch-all bucket named for our architecture: readers that filter by
|
|
466
|
+
* category skip it, and nothing has to guess.
|
|
468
467
|
*/
|
|
469
468
|
function deriveCategory(
|
|
470
469
|
signal: NotificationSignal,
|
|
@@ -558,7 +557,10 @@ function resolveHomeFeedMirror(
|
|
|
558
557
|
signal.sourceChannel === "assistant_tool" ||
|
|
559
558
|
signal.sourceEventName === "chat.assistant_reply"
|
|
560
559
|
) {
|
|
561
|
-
|
|
560
|
+
const allowlist = readChannelAllowlist(signal.contextPayload);
|
|
561
|
+
if (!allowlist || allowlist.includes("vellum")) {
|
|
562
|
+
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
563
|
+
}
|
|
562
564
|
}
|
|
563
565
|
if (signal.attentionHints.isAsyncBackground) {
|
|
564
566
|
return { mirror: true, sourceConversationId, sourceScheduleJobId };
|
|
@@ -71,6 +71,25 @@ export function readPayloadObject(
|
|
|
71
71
|
return isPlainObject(value) ? value : undefined;
|
|
72
72
|
}
|
|
73
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Safely read a string-array property from an unknown-typed payload object.
|
|
76
|
+
* Non-string entries are dropped. Returns `undefined` when the payload is
|
|
77
|
+
* not an object or the key does not hold an array.
|
|
78
|
+
*/
|
|
79
|
+
export function readPayloadStringArray(
|
|
80
|
+
payload: unknown,
|
|
81
|
+
key: string,
|
|
82
|
+
): string[] | undefined {
|
|
83
|
+
if (!isPlainObject(payload)) {
|
|
84
|
+
return undefined;
|
|
85
|
+
}
|
|
86
|
+
const value = payload[key];
|
|
87
|
+
if (!Array.isArray(value)) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
return value.filter((entry): entry is string => typeof entry === "string");
|
|
91
|
+
}
|
|
92
|
+
|
|
74
93
|
/** Truncate `text` to `maxLength`, appending "…" when exceeded. */
|
|
75
94
|
export function truncate(text: string, maxLength: number): string {
|
|
76
95
|
if (text.length <= maxLength) {
|
|
@@ -103,12 +103,10 @@ export interface ScheduleResultNotificationParams {
|
|
|
103
103
|
* conversation can come back too and are harmless, because only this run's
|
|
104
104
|
* own call ids are matched.
|
|
105
105
|
*
|
|
106
|
-
* A Slack Web API post through bash is deliberately not a route
|
|
107
|
-
*
|
|
108
|
-
*
|
|
109
|
-
*
|
|
110
|
-
* tool result. A run that posts that way gets the fallback too: at worst a
|
|
111
|
-
* duplicate, never a silence.
|
|
106
|
+
* A Slack Web API post through bash is deliberately not a route. It is off
|
|
107
|
+
* the guided path and unrecorded, and recognizing it would mean reading a
|
|
108
|
+
* shell command for a method name. A run that posts that way gets the
|
|
109
|
+
* fallback too: at worst a duplicate, never a silence.
|
|
112
110
|
*/
|
|
113
111
|
function deliveredThroughMessagingTool(
|
|
114
112
|
conversationId: string,
|
|
@@ -59,8 +59,9 @@ export function isNotificationSourceChannel(
|
|
|
59
59
|
|
|
60
60
|
export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
61
61
|
{
|
|
62
|
-
id: "
|
|
63
|
-
description:
|
|
62
|
+
id: "assistant.share",
|
|
63
|
+
description:
|
|
64
|
+
"Assistant chose to tell the user something (`assistant notifications send`)",
|
|
64
65
|
},
|
|
65
66
|
{
|
|
66
67
|
id: "schedule.notify",
|
|
@@ -113,28 +114,12 @@ export const NOTIFICATION_SOURCE_EVENT_NAMES = [
|
|
|
113
114
|
id: "watcher.notification",
|
|
114
115
|
description: "Watcher detected a notable event",
|
|
115
116
|
},
|
|
116
|
-
{
|
|
117
|
-
id: "watcher.escalation",
|
|
118
|
-
description: "Watcher event requiring immediate attention",
|
|
119
|
-
},
|
|
120
|
-
{
|
|
121
|
-
id: "tool_confirmation.required_action",
|
|
122
|
-
description: "Tool requires user confirmation before executing",
|
|
123
|
-
},
|
|
124
117
|
{ id: "activity.complete", description: "Background activity finished" },
|
|
125
118
|
{
|
|
126
119
|
id: "activity.failed",
|
|
127
120
|
description:
|
|
128
121
|
"Background job execution failed (model_provider, exception, or timeout)",
|
|
129
122
|
},
|
|
130
|
-
{
|
|
131
|
-
id: "quick_chat.response_ready",
|
|
132
|
-
description: "Quick chat response ready for review",
|
|
133
|
-
},
|
|
134
|
-
{
|
|
135
|
-
id: "voice.response_ready",
|
|
136
|
-
description: "Voice response ready for playback",
|
|
137
|
-
},
|
|
138
123
|
{
|
|
139
124
|
id: "credential.health_alert",
|
|
140
125
|
description:
|
|
@@ -251,7 +236,7 @@ export interface NotificationSignal<TEventName extends string = string> {
|
|
|
251
236
|
createdAt: number; // epoch ms
|
|
252
237
|
sourceChannel: NotificationSourceChannel; // see NOTIFICATION_SOURCE_CHANNELS registry
|
|
253
238
|
sourceContextId: string;
|
|
254
|
-
sourceEventName: TEventName; // free-form
|
|
239
|
+
sourceEventName: TEventName; // free-form; see NOTIFICATION_SOURCE_EVENT_NAMES
|
|
255
240
|
contextPayload: NotificationContextPayload<TEventName>;
|
|
256
241
|
attentionHints: AttentionHints;
|
|
257
242
|
/**
|
|
@@ -46,6 +46,21 @@ export type NotificationDeliveryResult = z.infer<
|
|
|
46
46
|
typeof NotificationDeliveryResultSchema
|
|
47
47
|
>;
|
|
48
48
|
|
|
49
|
+
/**
|
|
50
|
+
* Strongest delivery proof the emit path can report. These are receipts,
|
|
51
|
+
* not intents: `client_os_posted` is reserved for a client ACK that the
|
|
52
|
+
* OS banner was posted, which this return path does not observe.
|
|
53
|
+
*/
|
|
54
|
+
export const NotificationReceiptClassSchema = z.enum([
|
|
55
|
+
"provider_accepted",
|
|
56
|
+
"gateway_accepted",
|
|
57
|
+
"client_os_posted",
|
|
58
|
+
"unknown",
|
|
59
|
+
]);
|
|
60
|
+
export type NotificationReceiptClass = z.infer<
|
|
61
|
+
typeof NotificationReceiptClassSchema
|
|
62
|
+
>;
|
|
63
|
+
|
|
49
64
|
// -- Channel adapter data shapes ----------------------------------------------
|
|
50
65
|
|
|
51
66
|
export const DeliveryResultSchema = z.object({
|
package/src/oauth/AGENTS.md
CHANGED
|
@@ -10,6 +10,8 @@ Add an entry to `PROVIDER_SEED_DATA`. Required fields: `provider`, `authorizeUrl
|
|
|
10
10
|
|
|
11
11
|
`injectionTemplates` is also a security boundary, not only an injection rule. `assistant oauth request` and `assistant channels request` accept an absolute URL only when its host matches one of the entry's `hostPattern` values (`assertOAuthRequestUrlAllowed` in `../runtime/routes/oauth-commands-routes.ts`), so that list is the full set of hosts the credential may be sent to. A pattern matches exactly unless it starts with `*.`; reserve the wildcard for per-tenant hosts that cannot be enumerated (`*.salesforce.com`), and name a fixed host the provider documents (`files.slack.com`) by name. The guard sees only the URL the caller passes: the connection follows a redirect itself, and a cross-origin hop carries no `Authorization`, so a redirect target never receives the credential and never needs listing.
|
|
12
12
|
|
|
13
|
+
`responseOkField` declares the boolean a provider's API puts in every response body to report success (Slack: `ok`), and it is read in one place, `providerReportsFailure` in `identity-verifier.ts`. It is not `identityOkField`, which governs only the identity call and stays the documented `--identity-ok-field` contract. Both request doors and `oauth ping` treat an explicit `false` under a 2xx as a failed call, since such a provider hides refusals behind a successful status; a body without the field leaves the status as the verdict. Declare it on every row that calls such an API, the bot row included.
|
|
14
|
+
|
|
13
15
|
If the provider will support managed mode, set `managedServiceConfigKey` to a slug matching the key you will add to `ServicesSchema` (e.g. `"acme-oauth"`).
|
|
14
16
|
|
|
15
17
|
### 2. _(managed only)_ Add a service schema — `../config/schemas/services.ts`
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
|
|
2
2
|
|
|
3
|
-
import {
|
|
3
|
+
import {
|
|
4
|
+
providerReportsFailure,
|
|
5
|
+
verifyIdentity,
|
|
6
|
+
} from "../identity-verifier.js";
|
|
4
7
|
import type { OAuthProviderRow } from "../oauth-store.js";
|
|
5
8
|
|
|
6
9
|
// ---------------------------------------------------------------------------
|
|
@@ -66,6 +69,7 @@ function makeProviderRow(
|
|
|
66
69
|
identityResponsePaths: null,
|
|
67
70
|
identityFormat: null,
|
|
68
71
|
identityOkField: null,
|
|
72
|
+
responseOkField: null,
|
|
69
73
|
featureFlag: null,
|
|
70
74
|
createdAt: now,
|
|
71
75
|
updatedAt: now,
|
|
@@ -469,3 +473,34 @@ describe("verifyIdentity", () => {
|
|
|
469
473
|
});
|
|
470
474
|
});
|
|
471
475
|
});
|
|
476
|
+
|
|
477
|
+
describe("providerReportsFailure", () => {
|
|
478
|
+
test("reads an explicit false in the declared field as failure", () => {
|
|
479
|
+
expect(
|
|
480
|
+
providerReportsFailure(
|
|
481
|
+
{ responseOkField: "ok" },
|
|
482
|
+
{ ok: false, error: "invalid_auth" },
|
|
483
|
+
),
|
|
484
|
+
).toBe(true);
|
|
485
|
+
expect(
|
|
486
|
+
providerReportsFailure({ responseOkField: "ok" }, { ok: true }),
|
|
487
|
+
).toBe(false);
|
|
488
|
+
});
|
|
489
|
+
|
|
490
|
+
test("a body without the field says nothing", () => {
|
|
491
|
+
// A download or an endpoint outside the envelope; the status decides.
|
|
492
|
+
expect(providerReportsFailure({ responseOkField: "ok" }, null)).toBe(false);
|
|
493
|
+
expect(
|
|
494
|
+
providerReportsFailure({ responseOkField: "ok" }, Buffer.from("png")),
|
|
495
|
+
).toBe(false);
|
|
496
|
+
expect(
|
|
497
|
+
providerReportsFailure({ responseOkField: "ok" }, { data: {} }),
|
|
498
|
+
).toBe(false);
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
test("a provider that declares no field never reports failure", () => {
|
|
502
|
+
expect(
|
|
503
|
+
providerReportsFailure({ responseOkField: null }, { ok: false }),
|
|
504
|
+
).toBe(false);
|
|
505
|
+
});
|
|
506
|
+
});
|
|
@@ -467,12 +467,11 @@ async function fetchPlatformConnections(options: {
|
|
|
467
467
|
}
|
|
468
468
|
|
|
469
469
|
const body = (await response.json()) as unknown;
|
|
470
|
-
|
|
470
|
+
return (
|
|
471
471
|
Array.isArray(body)
|
|
472
472
|
? body
|
|
473
473
|
: ((body as Record<string, unknown>).results ?? [])
|
|
474
474
|
) as PlatformConnectionEntry[];
|
|
475
|
-
return connections;
|
|
476
475
|
}
|
|
477
476
|
|
|
478
477
|
/**
|
|
@@ -27,6 +27,30 @@ function getNestedValue(obj: unknown, dotPath: string): unknown {
|
|
|
27
27
|
return current;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
/**
|
|
31
|
+
* Whether a response body says the call failed, read through the ok field the
|
|
32
|
+
* provider declares (`responseOkField`).
|
|
33
|
+
*
|
|
34
|
+
* Some APIs report failure inside a successful HTTP exchange: Slack documents
|
|
35
|
+
* that every Web API response is a JSON object with a top-level boolean `ok`,
|
|
36
|
+
* false on failure, so the status code alone reads a refused call as a
|
|
37
|
+
* success. The provider row is where that envelope is declared, and this is
|
|
38
|
+
* the one reader of it for calls whose endpoint is not known in advance (ping
|
|
39
|
+
* and the authenticated-request doors). Only an explicit `false` counts: a
|
|
40
|
+
* body without the field, such as a file download or an endpoint outside the
|
|
41
|
+
* envelope, says nothing, and the status stays the verdict. The identity
|
|
42
|
+
* verifier reads its own field, `identityOkField`, for the one call it makes.
|
|
43
|
+
*/
|
|
44
|
+
export function providerReportsFailure(
|
|
45
|
+
providerRow: Pick<OAuthProviderRow, "responseOkField">,
|
|
46
|
+
body: unknown,
|
|
47
|
+
): boolean {
|
|
48
|
+
if (!providerRow.responseOkField) {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
return getNestedValue(body, providerRow.responseOkField) === false;
|
|
52
|
+
}
|
|
53
|
+
|
|
30
54
|
/** Safely parse a JSON string, returning a fallback on failure or null/undefined input. */
|
|
31
55
|
function safeJsonParse<T>(value: string | null | undefined, fallback: T): T {
|
|
32
56
|
if (value == null) {
|
package/src/oauth/oauth-store.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type OAuthConnectionRow = typeof oauthConnections.$inferSelect;
|
|
|
59
59
|
* managedServiceConfigKey,
|
|
60
60
|
* loopbackPort, injectionTemplates, appType, setupNotes,
|
|
61
61
|
* identityUrl, identityMethod, identityHeaders, identityBody,
|
|
62
|
-
* identityResponsePaths, identityFormat, identityOkField, featureFlag,
|
|
62
|
+
* identityResponsePaths, identityFormat, identityOkField, responseOkField, featureFlag,
|
|
63
63
|
* scopeSeparator, defaultScopes, availableScopes)
|
|
64
64
|
* and display metadata (displayLabel, description, dashboardUrl,
|
|
65
65
|
* clientIdPlaceholder, logoUrl, requiresClientSecret) propagate to existing
|
|
@@ -111,6 +111,7 @@ export function seedProviders(
|
|
|
111
111
|
identityResponsePaths?: string[];
|
|
112
112
|
identityFormat?: string;
|
|
113
113
|
identityOkField?: string;
|
|
114
|
+
responseOkField?: string;
|
|
114
115
|
featureFlag?: string;
|
|
115
116
|
}>,
|
|
116
117
|
): void {
|
|
@@ -175,6 +176,7 @@ export function seedProviders(
|
|
|
175
176
|
: null;
|
|
176
177
|
const identityFormat = p.identityFormat ?? null;
|
|
177
178
|
const identityOkField = p.identityOkField ?? null;
|
|
179
|
+
const responseOkField = p.responseOkField ?? null;
|
|
178
180
|
const featureFlag = p.featureFlag ?? null;
|
|
179
181
|
|
|
180
182
|
db.insert(oauthProviders)
|
|
@@ -216,6 +218,7 @@ export function seedProviders(
|
|
|
216
218
|
identityResponsePaths,
|
|
217
219
|
identityFormat,
|
|
218
220
|
identityOkField,
|
|
221
|
+
responseOkField,
|
|
219
222
|
featureFlag,
|
|
220
223
|
createdAt: now,
|
|
221
224
|
updatedAt: now,
|
|
@@ -259,6 +262,7 @@ export function seedProviders(
|
|
|
259
262
|
identityResponsePaths,
|
|
260
263
|
identityFormat,
|
|
261
264
|
identityOkField,
|
|
265
|
+
responseOkField,
|
|
262
266
|
featureFlag,
|
|
263
267
|
updatedAt: now,
|
|
264
268
|
},
|
|
@@ -359,6 +363,7 @@ export function registerProvider(params: {
|
|
|
359
363
|
identityResponsePaths?: string[];
|
|
360
364
|
identityFormat?: string;
|
|
361
365
|
identityOkField?: string;
|
|
366
|
+
responseOkField?: string;
|
|
362
367
|
featureFlag?: string;
|
|
363
368
|
}): OAuthProviderRow {
|
|
364
369
|
const db = getDb();
|
|
@@ -425,6 +430,7 @@ export function registerProvider(params: {
|
|
|
425
430
|
: null,
|
|
426
431
|
identityFormat: params.identityFormat ?? null,
|
|
427
432
|
identityOkField: params.identityOkField ?? null,
|
|
433
|
+
responseOkField: params.responseOkField ?? null,
|
|
428
434
|
featureFlag: params.featureFlag ?? null,
|
|
429
435
|
createdAt: now,
|
|
430
436
|
updatedAt: now,
|
|
@@ -486,6 +492,7 @@ export function updateProvider(
|
|
|
486
492
|
identityResponsePaths: string[];
|
|
487
493
|
identityFormat: string;
|
|
488
494
|
identityOkField: string;
|
|
495
|
+
responseOkField: string;
|
|
489
496
|
featureFlag: string;
|
|
490
497
|
managedServiceIsPaid: boolean;
|
|
491
498
|
}>,
|
|
@@ -610,6 +617,9 @@ export function updateProvider(
|
|
|
610
617
|
if (params.identityOkField !== undefined) {
|
|
611
618
|
set.identityOkField = params.identityOkField;
|
|
612
619
|
}
|
|
620
|
+
if (params.responseOkField !== undefined) {
|
|
621
|
+
set.responseOkField = params.responseOkField;
|
|
622
|
+
}
|
|
613
623
|
if (params.featureFlag !== undefined) {
|
|
614
624
|
set.featureFlag = params.featureFlag;
|
|
615
625
|
}
|
|
@@ -668,8 +678,6 @@ export async function upsertApp(
|
|
|
668
678
|
);
|
|
669
679
|
}
|
|
670
680
|
|
|
671
|
-
const defaultCredPath = (appId: string) => oauthAppClientSecretPath(appId);
|
|
672
|
-
|
|
673
681
|
// Verify the credential path points to an existing secret.
|
|
674
682
|
if (clientSecretCredentialPath) {
|
|
675
683
|
const existing = await getSecureKeyAsync(clientSecretCredentialPath);
|
|
@@ -729,7 +737,7 @@ export async function upsertApp(
|
|
|
729
737
|
|
|
730
738
|
const now = Date.now();
|
|
731
739
|
const id = uuid();
|
|
732
|
-
const credPath = clientSecretCredentialPath ??
|
|
740
|
+
const credPath = clientSecretCredentialPath ?? oauthAppClientSecretPath(id);
|
|
733
741
|
|
|
734
742
|
const row = {
|
|
735
743
|
id,
|
|
@@ -19,6 +19,7 @@ export type SerializedProvider = ReturnType<typeof serializeProvider> &
|
|
|
19
19
|
Record<string, unknown>;
|
|
20
20
|
|
|
21
21
|
import { isChannelBotProvider } from "@vellumai/service-contracts/channels";
|
|
22
|
+
import type { IntegrationCategory } from "@vellumai/service-contracts/integration-categories";
|
|
22
23
|
|
|
23
24
|
import { PROVIDER_SEED_DATA } from "./seed-providers.js";
|
|
24
25
|
|
|
@@ -38,6 +39,11 @@ export interface SerializedProviderSummary {
|
|
|
38
39
|
supports_managed_mode: boolean;
|
|
39
40
|
managed_service_is_paid: boolean;
|
|
40
41
|
feature_flag: string | null;
|
|
42
|
+
/**
|
|
43
|
+
* Where the integrations catalog files the provider. `null` for a row with
|
|
44
|
+
* no seed entry, such as a provider a user registered by hand.
|
|
45
|
+
*/
|
|
46
|
+
category: IntegrationCategory | null;
|
|
41
47
|
/**
|
|
42
48
|
* Per-tenant providers only (Shopify): what a client must collect before
|
|
43
49
|
* starting a managed connect, since the provider's OAuth endpoints live on
|
|
@@ -141,6 +147,7 @@ function _serializeProvider(
|
|
|
141
147
|
: null,
|
|
142
148
|
identityFormat: row.identityFormat ?? null,
|
|
143
149
|
identityOkField: row.identityOkField ?? null,
|
|
150
|
+
responseOkField: row.responseOkField ?? null,
|
|
144
151
|
featureFlag: row.featureFlag ?? null,
|
|
145
152
|
redirectUri:
|
|
146
153
|
options?.redirectUri !== undefined ? options.redirectUri : null,
|
|
@@ -172,6 +179,7 @@ export function serializeProviderSummary(
|
|
|
172
179
|
supports_managed_mode: !!row.managedServiceConfigKey,
|
|
173
180
|
managed_service_is_paid: !!row.managedServiceIsPaid,
|
|
174
181
|
feature_flag: row.featureFlag ?? null,
|
|
182
|
+
category: PROVIDER_SEED_DATA[row.provider]?.category ?? null,
|
|
175
183
|
tenant_host: PROVIDER_SEED_DATA[row.provider]?.tenantHost ?? null,
|
|
176
184
|
acts_as: isChannelBotProvider(row.provider) ? "assistant" : "user",
|
|
177
185
|
};
|