@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
|
@@ -107,10 +107,10 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
107
107
|
});
|
|
108
108
|
|
|
109
109
|
test("fails when body is the raw source event name", async () => {
|
|
110
|
-
const signal = makeSignal({ sourceEventName: "
|
|
110
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
111
111
|
const decision = makeDecision({
|
|
112
112
|
renderedCopy: {
|
|
113
|
-
vellum: { title: "Reminder", body: "
|
|
113
|
+
vellum: { title: "Reminder", body: "assistant.share" },
|
|
114
114
|
},
|
|
115
115
|
});
|
|
116
116
|
const result = await runDeterministicChecks(signal, decision, context);
|
|
@@ -119,10 +119,10 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
119
119
|
});
|
|
120
120
|
|
|
121
121
|
test("fails when body matches the normalized source event name", async () => {
|
|
122
|
-
const signal = makeSignal({ sourceEventName: "
|
|
122
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
123
123
|
const decision = makeDecision({
|
|
124
124
|
renderedCopy: {
|
|
125
|
-
vellum: { title: "Reminder", body: "
|
|
125
|
+
vellum: { title: "Reminder", body: "assistant share" },
|
|
126
126
|
},
|
|
127
127
|
});
|
|
128
128
|
const result = await runDeterministicChecks(signal, decision, context);
|
|
@@ -174,11 +174,11 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
174
174
|
test("still validates body quality for channels with rendered copy", async () => {
|
|
175
175
|
// Even when some channels lack copy (broadcaster fallback territory),
|
|
176
176
|
// channels that DO have copy must still pass the empty/event-name checks.
|
|
177
|
-
const signal = makeSignal({ sourceEventName: "
|
|
177
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
178
178
|
const decision = makeDecision({
|
|
179
179
|
selectedChannels: ["vellum", "telegram"],
|
|
180
180
|
renderedCopy: {
|
|
181
|
-
telegram: { title: "Reminder", body: "
|
|
181
|
+
telegram: { title: "Reminder", body: "assistant.share" },
|
|
182
182
|
},
|
|
183
183
|
});
|
|
184
184
|
const result = await runDeterministicChecks(signal, decision, {
|
|
@@ -194,7 +194,7 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
194
194
|
// a usable body (no template for sourceEventName → buildGenericCopy
|
|
195
195
|
// returns body=""), the gate must fail-closed rather than letting
|
|
196
196
|
// dispatchDecision report 0/N sent.
|
|
197
|
-
const signal = makeSignal({ sourceEventName: "
|
|
197
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
198
198
|
const decision = makeDecision({
|
|
199
199
|
selectedChannels: ["vellum"],
|
|
200
200
|
renderedCopy: {},
|
|
@@ -218,7 +218,7 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
218
218
|
});
|
|
219
219
|
|
|
220
220
|
test("passes when shouldNotify is false regardless of copy contents", async () => {
|
|
221
|
-
const signal = makeSignal({ sourceEventName: "
|
|
221
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
222
222
|
const decision = makeDecision({
|
|
223
223
|
shouldNotify: false,
|
|
224
224
|
// Empty body + event-name body would both fail the copy check if
|
|
@@ -286,11 +286,11 @@ describe("checkRenderedCopyQuality (via runDeterministicChecks)", () => {
|
|
|
286
286
|
test("still fails non-pass-through decision when body matches event name", async () => {
|
|
287
287
|
// Regression guard: the pass-through short-circuit must not weaken
|
|
288
288
|
// the check for LLM/fallback paths.
|
|
289
|
-
const signal = makeSignal({ sourceEventName: "
|
|
289
|
+
const signal = makeSignal({ sourceEventName: "assistant.share" });
|
|
290
290
|
const decision = makeDecision({
|
|
291
291
|
reasoningSummary: "llm classification",
|
|
292
292
|
renderedCopy: {
|
|
293
|
-
vellum: { title: "Reminder", body: "
|
|
293
|
+
vellum: { title: "Reminder", body: "assistant.share" },
|
|
294
294
|
},
|
|
295
295
|
});
|
|
296
296
|
const result = await runDeterministicChecks(signal, decision, context);
|
|
@@ -281,7 +281,9 @@ describe("writeHomeFeedItemForSignal", () => {
|
|
|
281
281
|
"The deployment completed successfully.",
|
|
282
282
|
);
|
|
283
283
|
expect(appendCalls[0]!.conversationId).toBe("conv-source-1");
|
|
284
|
-
expect(
|
|
284
|
+
expect(
|
|
285
|
+
appendCalls[0]!.metadata?.notificationConversationMessageId,
|
|
286
|
+
).toBeUndefined();
|
|
285
287
|
expect(messageAppends).toEqual([]);
|
|
286
288
|
expect(messagesInvalidated).toEqual([]);
|
|
287
289
|
expect(conversationLookups).toEqual(["conv-source-1", "conv-source-1"]);
|
|
@@ -352,6 +354,93 @@ describe("writeHomeFeedItemForSignal", () => {
|
|
|
352
354
|
expect(conversationLookups).toEqual(["cli-12345"]);
|
|
353
355
|
});
|
|
354
356
|
|
|
357
|
+
test("assistant_tool source skips the automatic Home mirror when channelAllowlist omits vellum", async () => {
|
|
358
|
+
conversationRow = null;
|
|
359
|
+
const signal = makeSignal({
|
|
360
|
+
sourceChannel: "assistant_tool",
|
|
361
|
+
sourceEventName: "assistant.share",
|
|
362
|
+
sourceContextId: "cli-12345",
|
|
363
|
+
contextPayload: {
|
|
364
|
+
title: "Telegram only",
|
|
365
|
+
channelAllowlist: ["telegram"],
|
|
366
|
+
},
|
|
367
|
+
attentionHints: {
|
|
368
|
+
requiresAction: false,
|
|
369
|
+
urgency: "critical",
|
|
370
|
+
isAsyncBackground: false,
|
|
371
|
+
visibleInSourceNow: false,
|
|
372
|
+
},
|
|
373
|
+
});
|
|
374
|
+
const decision = makeDecision({
|
|
375
|
+
selectedChannels: ["telegram"],
|
|
376
|
+
renderedCopy: {
|
|
377
|
+
telegram: { title: "Telegram only", body: "Alarm body" },
|
|
378
|
+
},
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
const item = await writeHomeFeedItemForSignal(signal, decision);
|
|
382
|
+
|
|
383
|
+
expect(item).toBeNull();
|
|
384
|
+
expect(appendCalls).toHaveLength(0);
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
test("assistant_tool source still mirrors when channelAllowlist includes vellum", async () => {
|
|
388
|
+
conversationRow = null;
|
|
389
|
+
const signal = makeSignal({
|
|
390
|
+
sourceChannel: "assistant_tool",
|
|
391
|
+
sourceEventName: "assistant.share",
|
|
392
|
+
sourceContextId: "cli-12345",
|
|
393
|
+
contextPayload: {
|
|
394
|
+
title: "Inbox and telegram",
|
|
395
|
+
channelAllowlist: ["vellum", "telegram"],
|
|
396
|
+
},
|
|
397
|
+
});
|
|
398
|
+
const decision = makeDecision({
|
|
399
|
+
selectedChannels: ["vellum", "telegram"],
|
|
400
|
+
renderedCopy: {
|
|
401
|
+
vellum: { title: "Inbox and telegram", body: "Shared body" },
|
|
402
|
+
},
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
const item = await writeHomeFeedItemForSignal(signal, decision);
|
|
406
|
+
|
|
407
|
+
expect(item).not.toBeNull();
|
|
408
|
+
expect(appendCalls).toHaveLength(1);
|
|
409
|
+
});
|
|
410
|
+
|
|
411
|
+
test("assistant_tool exclusive allowlist still mirrors when isAsyncBackground is set", async () => {
|
|
412
|
+
conversationRow = null;
|
|
413
|
+
const signal = makeSignal({
|
|
414
|
+
sourceChannel: "assistant_tool",
|
|
415
|
+
sourceEventName: "assistant.share",
|
|
416
|
+
sourceContextId: "cli-12345",
|
|
417
|
+
contextPayload: {
|
|
418
|
+
title: "Background telegram",
|
|
419
|
+
channelAllowlist: ["telegram"],
|
|
420
|
+
},
|
|
421
|
+
attentionHints: {
|
|
422
|
+
requiresAction: false,
|
|
423
|
+
urgency: "low",
|
|
424
|
+
isAsyncBackground: true,
|
|
425
|
+
visibleInSourceNow: false,
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
const decision = makeDecision({
|
|
429
|
+
selectedChannels: ["telegram"],
|
|
430
|
+
renderedCopy: {
|
|
431
|
+
telegram: { title: "Background telegram", body: "Still a feed item" },
|
|
432
|
+
},
|
|
433
|
+
});
|
|
434
|
+
|
|
435
|
+
const item = await writeHomeFeedItemForSignal(signal, decision);
|
|
436
|
+
|
|
437
|
+
expect(item).not.toBeNull();
|
|
438
|
+
expect(appendCalls).toHaveLength(1);
|
|
439
|
+
expect(appendCalls[0]!.noteworthy).toBe(true);
|
|
440
|
+
expect(appendCalls[0]!.conversationId).toBeUndefined();
|
|
441
|
+
expect(conversationLookups).toEqual(["cli-12345"]);
|
|
442
|
+
});
|
|
443
|
+
|
|
355
444
|
test("source conversation id does not propagate when the lookup misses", async () => {
|
|
356
445
|
// When `sourceContextId` does not resolve to a real conversation row
|
|
357
446
|
// (e.g. scheduler job id, watcher event id), the item is still mirrored
|
|
@@ -956,7 +1045,7 @@ describe("writeHomeFeedItemForSignal", () => {
|
|
|
956
1045
|
conversationRow = { conversationType: "background" };
|
|
957
1046
|
const signal = makeSignal({
|
|
958
1047
|
sourceChannel: "assistant_tool",
|
|
959
|
-
sourceEventName: "
|
|
1048
|
+
sourceEventName: "assistant.share",
|
|
960
1049
|
contextPayload: { title: "Tool share", body: "Body" },
|
|
961
1050
|
});
|
|
962
1051
|
|
|
@@ -970,7 +1059,7 @@ describe("writeHomeFeedItemForSignal", () => {
|
|
|
970
1059
|
conversationRow = { conversationType: "background" };
|
|
971
1060
|
const signal = makeSignal({
|
|
972
1061
|
sourceChannel: "assistant_tool",
|
|
973
|
-
sourceEventName: "
|
|
1062
|
+
sourceEventName: "assistant.share",
|
|
974
1063
|
contextPayload: { title: "Tool share", body: "Body" },
|
|
975
1064
|
});
|
|
976
1065
|
|
|
@@ -1126,7 +1215,7 @@ describe("writeHomeFeedItemForSignal", () => {
|
|
|
1126
1215
|
conversationRow = { conversationType: "background" };
|
|
1127
1216
|
const signal = makeSignal({
|
|
1128
1217
|
sourceChannel: "assistant_tool",
|
|
1129
|
-
sourceEventName: "
|
|
1218
|
+
sourceEventName: "assistant.share",
|
|
1130
1219
|
contextPayload: { title: "Tool share", body: "Body" },
|
|
1131
1220
|
});
|
|
1132
1221
|
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
decodeLiteralLineBreaks,
|
|
6
6
|
describeMedia,
|
|
7
7
|
mediaEmbeds,
|
|
8
|
+
readPayloadStringArray,
|
|
8
9
|
sanitizeMultilineMessagePreview,
|
|
9
10
|
stripMarkdownForPreview,
|
|
10
11
|
} from "../notification-utils.js";
|
|
@@ -280,6 +281,23 @@ describe("describeMedia", () => {
|
|
|
280
281
|
});
|
|
281
282
|
});
|
|
282
283
|
|
|
284
|
+
describe("readPayloadStringArray", () => {
|
|
285
|
+
test("returns string entries and drops non-strings", () => {
|
|
286
|
+
expect(
|
|
287
|
+
readPayloadStringArray(
|
|
288
|
+
{ channelAllowlist: ["telegram", 1, "slack"] },
|
|
289
|
+
"channelAllowlist",
|
|
290
|
+
),
|
|
291
|
+
).toEqual(["telegram", "slack"]);
|
|
292
|
+
});
|
|
293
|
+
|
|
294
|
+
test("returns undefined when the key is missing or not an array", () => {
|
|
295
|
+
expect(readPayloadStringArray({ channelAllowlist: "telegram" }, "channelAllowlist")).toBeUndefined();
|
|
296
|
+
expect(readPayloadStringArray({}, "channelAllowlist")).toBeUndefined();
|
|
297
|
+
expect(readPayloadStringArray(null, "channelAllowlist")).toBeUndefined();
|
|
298
|
+
});
|
|
299
|
+
});
|
|
300
|
+
|
|
283
301
|
describe("decodeLiteralLineBreaks", () => {
|
|
284
302
|
test("turns literal newline escapes into real line breaks", () => {
|
|
285
303
|
expect(decodeLiteralLineBreaks("Line one\\n\\nLine two")).toBe(
|
|
@@ -2,26 +2,26 @@
|
|
|
2
2
|
* Vellum channel adapter — delivers notifications to connected desktop
|
|
3
3
|
* and mobile clients via the daemon's event broadcast mechanism.
|
|
4
4
|
*
|
|
5
|
-
* The adapter broadcasts a `notification_intent` message that the
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
5
|
+
* The adapter broadcasts a `notification_intent` message that the client
|
|
6
|
+
* turns into an OS notification (`use-notification-intent-sync.ts` in the
|
|
7
|
+
* web client, which every first-party app runs). The `silent` flag is true
|
|
8
|
+
* for non-urgent (`low`/`medium`) signals, and the client posts nothing for
|
|
9
|
+
* those: they reach their conversation (and the home feed, for background
|
|
10
|
+
* work) without a banner.
|
|
11
|
+
* Urgent signals (`high`/`critical`) broadcast with `silent: false` and
|
|
12
|
+
* banner.
|
|
13
13
|
*
|
|
14
14
|
* Guardian-sensitive notifications (approval requests, access requests)
|
|
15
|
-
* are
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
15
|
+
* are delivered only to connections authenticated as the guardian: the hub
|
|
16
|
+
* matches `targetActorPrincipalId` against each connection's verified
|
|
17
|
+
* principal, so no other connection ever receives the title and body. The
|
|
18
|
+
* payload's `targetGuardianPrincipalId` records that scoping for clients.
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
21
|
import type { AssistantEvent } from "../../api/index.js";
|
|
22
|
-
import type { InterfaceId } from "../../channels/types.js";
|
|
23
22
|
import { getAssistantName } from "../../daemon/identity-helpers.js";
|
|
24
23
|
import { updateMessageContent } from "../../persistence/conversation-crud.js";
|
|
24
|
+
import type { BroadcastMessageOptions } from "../../runtime/assistant-event-hub.js";
|
|
25
25
|
import { publishConversationMessagesChanged } from "../../runtime/sync/resource-sync-events.js";
|
|
26
26
|
import { getLogger } from "../../util/logger.js";
|
|
27
27
|
import type {
|
|
@@ -36,28 +36,16 @@ import type {
|
|
|
36
36
|
|
|
37
37
|
const log = getLogger("notif-adapter-vellum");
|
|
38
38
|
|
|
39
|
-
/**
|
|
40
|
-
* Optional targeting/filtering applied at the hub when a broadcast is
|
|
41
|
-
* emitted. Mirrors the third argument of
|
|
42
|
-
* `broadcastMessage()` in `runtime/assistant-event-hub.ts`. Callers can
|
|
43
|
-
* use `targetInterfaceId` to scope a legacy message to a single client
|
|
44
|
-
* surface (e.g. macOS) during a migration window.
|
|
45
|
-
*/
|
|
46
|
-
export interface BroadcastFnOptions {
|
|
47
|
-
targetClientId?: string;
|
|
48
|
-
targetInterfaceId?: InterfaceId;
|
|
49
|
-
}
|
|
50
|
-
|
|
51
39
|
export type BroadcastFn = (
|
|
52
40
|
msg: AssistantEvent,
|
|
53
41
|
conversationId?: string,
|
|
54
|
-
options?:
|
|
42
|
+
options?: BroadcastMessageOptions,
|
|
55
43
|
) => void;
|
|
56
44
|
|
|
57
45
|
/**
|
|
58
46
|
* Event name prefixes that carry guardian-sensitive content (approval
|
|
59
|
-
* requests, access requests). Notifications for these events
|
|
60
|
-
*
|
|
47
|
+
* requests, access requests). Notifications for these events reach only
|
|
48
|
+
* the guardian's own connections.
|
|
61
49
|
*/
|
|
62
50
|
const GUARDIAN_SENSITIVE_EVENT_PREFIXES = [
|
|
63
51
|
"guardian.question",
|
|
@@ -86,10 +74,9 @@ export class VellumAdapter implements ChannelAdapter {
|
|
|
86
74
|
destination: ChannelDestination,
|
|
87
75
|
): Promise<DeliveryResult> {
|
|
88
76
|
try {
|
|
89
|
-
// For guardian-sensitive events,
|
|
90
|
-
//
|
|
91
|
-
//
|
|
92
|
-
// the destination resolver.
|
|
77
|
+
// For guardian-sensitive events, deliver only to the guardian's own
|
|
78
|
+
// connections. The guardianPrincipalId comes from the vellum binding
|
|
79
|
+
// resolved by the destination resolver.
|
|
93
80
|
const guardianPrincipalId =
|
|
94
81
|
typeof destination.metadata?.guardianPrincipalId === "string"
|
|
95
82
|
? destination.metadata.guardianPrincipalId
|
|
@@ -104,20 +91,24 @@ export class VellumAdapter implements ChannelAdapter {
|
|
|
104
91
|
payload.urgency !== "high" && payload.urgency !== "critical";
|
|
105
92
|
const assistantName = getAssistantName()?.trim() || undefined;
|
|
106
93
|
|
|
107
|
-
this.broadcast(
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
94
|
+
this.broadcast(
|
|
95
|
+
{
|
|
96
|
+
type: "notification_intent",
|
|
97
|
+
deliveryId: payload.deliveryId,
|
|
98
|
+
correlationId: payload.correlationId,
|
|
99
|
+
sourceEventName: payload.sourceEventName,
|
|
100
|
+
...(assistantName ? { assistantName } : {}),
|
|
101
|
+
title: payload.copy.title,
|
|
102
|
+
body: payload.copy.body,
|
|
103
|
+
deepLinkMetadata: payload.deepLinkTarget,
|
|
104
|
+
targetGuardianPrincipalId,
|
|
105
|
+
silent,
|
|
106
|
+
remotePushDispatched: payload.remotePushDispatched,
|
|
107
|
+
remotePushPlatforms: payload.remotePushPlatforms,
|
|
108
|
+
},
|
|
109
|
+
undefined,
|
|
110
|
+
{ targetActorPrincipalId: targetGuardianPrincipalId },
|
|
111
|
+
);
|
|
121
112
|
|
|
122
113
|
log.info(
|
|
123
114
|
{
|
|
@@ -241,8 +241,8 @@ export interface ConversationCreatedInfo {
|
|
|
241
241
|
/** Semantic source from the signal producer (e.g. "schedule", "reminder"). */
|
|
242
242
|
source?: string;
|
|
243
243
|
/**
|
|
244
|
-
* Mirrors the vellum adapter's `silent` flag
|
|
245
|
-
*
|
|
244
|
+
* Mirrors the vellum adapter's `silent` flag (true for low- and
|
|
245
|
+
* medium-urgency signals).
|
|
246
246
|
*/
|
|
247
247
|
silent: boolean;
|
|
248
248
|
}
|
|
@@ -354,10 +354,9 @@ export class NotificationBroadcaster {
|
|
|
354
354
|
|
|
355
355
|
// Ensure vellum is processed first so the notification_conversation_created
|
|
356
356
|
// event fires immediately, before slower channel sends (e.g. Telegram 30s
|
|
357
|
-
// timeout) can delay it
|
|
358
|
-
//
|
|
359
|
-
//
|
|
360
|
-
// instead of waiting behind slower channels.
|
|
357
|
+
// timeout) can delay it. Platform sorts second: the vellum intent carries
|
|
358
|
+
// remotePushDispatched, so its deferred send (below) flushes right after
|
|
359
|
+
// the platform outcome is known instead of waiting behind slower channels.
|
|
361
360
|
const dispatchRank = (channel: NotificationChannel): number => {
|
|
362
361
|
if (channel === "vellum") {
|
|
363
362
|
return 0;
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Exclusive channel allowlist carried on a signal's `contextPayload`.
|
|
3
|
+
*
|
|
4
|
+
* When `channelAllowlist` is a non-empty string array, delivery is restricted
|
|
5
|
+
* to that set intersected with connected channels. Urgent force and
|
|
6
|
+
* routing-intent expansion do not add channels outside the allowlist.
|
|
7
|
+
* `preferredChannels` stays additive and is ignored when an allowlist is
|
|
8
|
+
* present.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { readPayloadStringArray } from "./notification-utils.js";
|
|
12
|
+
import type { NotificationChannel } from "./types.js";
|
|
13
|
+
|
|
14
|
+
export function readChannelAllowlist(payload: unknown): string[] | undefined {
|
|
15
|
+
const raw = readPayloadStringArray(payload, "channelAllowlist");
|
|
16
|
+
if (!raw) {
|
|
17
|
+
return undefined;
|
|
18
|
+
}
|
|
19
|
+
const channels = raw.map((entry) => entry.trim()).filter((entry) => {
|
|
20
|
+
return entry.length > 0;
|
|
21
|
+
});
|
|
22
|
+
return channels.length > 0 ? channels : undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export function hasExclusiveChannelAllowlist(payload: unknown): boolean {
|
|
26
|
+
return readChannelAllowlist(payload) !== undefined;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
export function intersectChannelAllowlist(
|
|
30
|
+
allowlist: readonly string[],
|
|
31
|
+
available: readonly NotificationChannel[],
|
|
32
|
+
): NotificationChannel[] {
|
|
33
|
+
const availableSet = new Set<string>(available);
|
|
34
|
+
const seen = new Set<string>();
|
|
35
|
+
const selected: NotificationChannel[] = [];
|
|
36
|
+
for (const channel of allowlist) {
|
|
37
|
+
if (!availableSet.has(channel) || seen.has(channel)) {
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
seen.add(channel);
|
|
41
|
+
selected.push(channel as NotificationChannel);
|
|
42
|
+
}
|
|
43
|
+
return selected;
|
|
44
|
+
}
|
|
@@ -331,29 +331,24 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
331
331
|
body: str(payload.body, "A watcher event occurred"),
|
|
332
332
|
}),
|
|
333
333
|
|
|
334
|
-
"watcher.escalation": (payload) => ({
|
|
335
|
-
title: str(payload.title, "Watcher Escalation"),
|
|
336
|
-
body: str(payload.body, "A watcher event requires your attention"),
|
|
337
|
-
}),
|
|
338
|
-
|
|
339
|
-
"tool_confirmation.required_action": (payload) => {
|
|
340
|
-
const toolName = str(payload.toolName, "A tool");
|
|
341
|
-
return {
|
|
342
|
-
title: `${toolName} needs your confirmation`,
|
|
343
|
-
body: `${toolName} requires your confirmation`,
|
|
344
|
-
};
|
|
345
|
-
},
|
|
346
|
-
|
|
347
334
|
// Titled by what was done rather than by the kind of event: the summary's
|
|
348
335
|
// first sentence is the outcome ("Finished the fuel-system diagnostic app"),
|
|
349
|
-
// which is what a reader scanning the bell wants to see. A
|
|
350
|
-
//
|
|
336
|
+
// which is what a reader scanning the bell wants to see. A producer that
|
|
337
|
+
// names its subject in the payload keeps that name here, read in the same
|
|
338
|
+
// order the home feed reads it, so the headline is the same whether or not
|
|
339
|
+
// the classifier ran. A summary with neither still gets a title that says
|
|
340
|
+
// something happened.
|
|
351
341
|
"activity.complete": (payload) => {
|
|
352
342
|
const summary = nonEmpty(
|
|
353
343
|
typeof payload.summary === "string" ? payload.summary : undefined,
|
|
354
344
|
);
|
|
345
|
+
const authored = normalizeTitle(
|
|
346
|
+
readPayloadString(payload, "title") ??
|
|
347
|
+
readPayloadString(payload, "requestedTitle") ??
|
|
348
|
+
"",
|
|
349
|
+
);
|
|
355
350
|
return {
|
|
356
|
-
title: summary ? deriveTitle(summary) : "Activity complete",
|
|
351
|
+
title: authored || (summary ? deriveTitle(summary) : "Activity complete"),
|
|
357
352
|
body: summary ?? "An activity has completed",
|
|
358
353
|
};
|
|
359
354
|
},
|
|
@@ -377,16 +372,6 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
377
372
|
body: summary !== "" ? summary : describeUnclassifiedFailure(payload),
|
|
378
373
|
};
|
|
379
374
|
},
|
|
380
|
-
|
|
381
|
-
"quick_chat.response_ready": (payload) => ({
|
|
382
|
-
title: "Quick chat reply ready",
|
|
383
|
-
body: str(payload.preview, "Your quick chat response is ready"),
|
|
384
|
-
}),
|
|
385
|
-
|
|
386
|
-
"voice.response_ready": (payload) => ({
|
|
387
|
-
title: "Voice reply ready",
|
|
388
|
-
body: str(payload.preview, "A voice response is ready"),
|
|
389
|
-
}),
|
|
390
375
|
};
|
|
391
376
|
|
|
392
377
|
/**
|
|
@@ -35,6 +35,10 @@ import {
|
|
|
35
35
|
buildAccessRequestSeedContentBlocks,
|
|
36
36
|
buildToolApprovalSeedContentBlocks,
|
|
37
37
|
} from "./approval-card-data.js";
|
|
38
|
+
import {
|
|
39
|
+
intersectChannelAllowlist,
|
|
40
|
+
readChannelAllowlist,
|
|
41
|
+
} from "./channel-allowlist.js";
|
|
38
42
|
import {
|
|
39
43
|
buildConversationCandidates,
|
|
40
44
|
type ConversationCandidateSet,
|
|
@@ -52,6 +56,7 @@ import {
|
|
|
52
56
|
nonEmpty,
|
|
53
57
|
readPayloadObject,
|
|
54
58
|
readPayloadString,
|
|
59
|
+
readPayloadStringArray,
|
|
55
60
|
} from "./notification-utils.js";
|
|
56
61
|
import { getPreferenceSummary } from "./preference-summary.js";
|
|
57
62
|
import type { NotificationSignal, RoutingIntent } from "./signal.js";
|
|
@@ -887,22 +892,27 @@ export async function evaluateSignal(
|
|
|
887
892
|
signal.attentionHints.urgency,
|
|
888
893
|
availableChannels,
|
|
889
894
|
);
|
|
890
|
-
//
|
|
891
|
-
//
|
|
892
|
-
//
|
|
893
|
-
//
|
|
894
|
-
//
|
|
895
|
-
const
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
|
|
895
|
+
// `channelAllowlist` is exclusive: only those available channels are
|
|
896
|
+
// selected. `preferredChannels` is additive on top of the default set
|
|
897
|
+
// (vellum stays the canonical inbox) and is ignored when an allowlist
|
|
898
|
+
// is present. Disconnected names are dropped so we never deliver on
|
|
899
|
+
// something unavailable.
|
|
900
|
+
const exclusiveAllowlist = readChannelAllowlist(payload);
|
|
901
|
+
const preferredChannelsRaw = readPayloadStringArray(
|
|
902
|
+
payload,
|
|
903
|
+
"preferredChannels",
|
|
904
|
+
);
|
|
900
905
|
let selectedChannels = defaultChannels;
|
|
901
|
-
if (
|
|
906
|
+
if (exclusiveAllowlist) {
|
|
907
|
+
selectedChannels = intersectChannelAllowlist(
|
|
908
|
+
exclusiveAllowlist,
|
|
909
|
+
availableChannels,
|
|
910
|
+
);
|
|
911
|
+
} else if (preferredChannelsRaw && preferredChannelsRaw.length > 0) {
|
|
902
912
|
const availableSet = new Set<string>(availableChannels);
|
|
903
|
-
const preferredAvailable = preferredChannelsRaw.filter((c) =>
|
|
904
|
-
availableSet.has(c)
|
|
905
|
-
) as NotificationChannel[];
|
|
913
|
+
const preferredAvailable = preferredChannelsRaw.filter((c) => {
|
|
914
|
+
return availableSet.has(c);
|
|
915
|
+
}) as NotificationChannel[];
|
|
906
916
|
if (preferredAvailable.length > 0) {
|
|
907
917
|
selectedChannels = Array.from(
|
|
908
918
|
new Set<NotificationChannel>([
|
|
@@ -254,7 +254,7 @@ function checkDedupe(
|
|
|
254
254
|
/**
|
|
255
255
|
* Fail-closed check that the rendered copy is real text and not an
|
|
256
256
|
* accidental fallback leak (empty body, or body that is just the raw
|
|
257
|
-
* source event name like "
|
|
257
|
+
* source event name like "assistant.share").
|
|
258
258
|
*
|
|
259
259
|
* Only validates channels that the decision engine actually emitted
|
|
260
260
|
* copy for. Channels appended after the decision (urgency-forced
|