@vellumai/assistant 0.12.3-staging.1 → 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/ARCHITECTURE.md +43 -29
- package/Dockerfile +63 -0
- package/docs/architecture/security.md +10 -5
- package/docs/architecture/turn-actor.md +2 -0
- package/docs/desktop-browser-cli.md +45 -4
- 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/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/gateway-client/node_modules/@vellumai/service-contracts/package.json +2 -1
- 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/src/gateway-ipc-contracts.ts +20 -0
- 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/index.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/integration-categories.ts +36 -0
- package/node_modules/@vellumai/slack-text/src/index.ts +4 -8
- package/openapi.yaml +665 -14
- package/package.json +1 -1
- package/scripts/smoke-desktop-browser-cli.ts +10 -26
- package/scripts/smoke-desktop-window-theme.ts +2 -3
- 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__/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__/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__/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-retry-sweep.test.ts +9 -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-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.test.ts +546 -16
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +53 -1
- package/src/__tests__/conversation-evictor.test.ts +62 -37
- 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-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 +6 -6
- package/src/__tests__/credential-prompt-route.test.ts +35 -3
- package/src/__tests__/cu-unified-flow.test.ts +82 -1
- 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 +25 -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__/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 +1 -1
- package/src/__tests__/interrupt-on-send.test.ts +57 -43
- package/src/__tests__/interrupt-turn-note.test.ts +5 -6
- package/src/__tests__/llm-catalog-parity.test.ts +2 -2
- 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-provider-serializer.test.ts +12 -0
- package/src/__tests__/oauth-providers-routes.test.ts +1 -0
- package/src/__tests__/outbound-slack-persistence.test.ts +2 -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 -0
- 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__/runtime-events-sse-reconnect.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__/secure-keys.test.ts +43 -1
- package/src/__tests__/send-endpoint-busy.test.ts +163 -1
- package/src/__tests__/server-history-render.test.ts +91 -1
- package/src/__tests__/settings-routes.test.ts +50 -1
- package/src/__tests__/skill-script-runner-sandbox.test.ts +32 -0
- 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__/surface-completion-in-flight-snapshot.test.ts +2 -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-metadata-plumbing.test.ts +3 -1
- package/src/__tests__/tool-start-timestamp.test.ts +2 -0
- package/src/__tests__/twilio-routes.test.ts +1 -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 +99 -41
- package/src/api/events/assistant-turn-start.ts +3 -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/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 +31 -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 +6 -0
- package/src/approvals/AGENTS.md +4 -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 -8
- 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__/notifications.test.ts +35 -10
- package/src/cli/commands/browser.help.ts +4 -5
- 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 +6 -1
- package/src/cli/commands/notifications.help.ts +16 -2
- package/src/cli/commands/notifications.ts +30 -8
- package/src/cli/commands/roadmap.help.ts +18 -21
- package/src/cli/commands/roadmap.ts +4 -21
- package/src/cli/lib/__tests__/list-installed-plugins.test.ts +5 -2
- package/src/cli/lib/bundled-marketplace.json +84 -34
- package/src/cli/lib/plugin-marketplace.ts +8 -0
- package/src/cli/lib/publish-plugin.ts +1 -2
- package/src/config/__tests__/default-provider.test.ts +3 -1
- 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/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/profile-text-generation.test.ts +2 -2
- 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 +3 -1
- package/src/config/schemas/mcp.ts +2 -1
- package/src/config/schemas/memory-retrospective.ts +11 -2
- 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 +1 -11
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +10 -1
- package/src/daemon/__tests__/inference-profile-notification.test.ts +2 -0
- package/src/daemon/browser-mode-session.test.ts +402 -0
- package/src/daemon/browser-mode-session.ts +186 -0
- 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 +58 -10
- package/src/daemon/conversation-agent-loop.ts +219 -25
- 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 +8 -3
- package/src/daemon/conversation.ts +143 -41
- 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/message-protocol.ts +0 -1
- package/src/daemon/message-provenance.ts +28 -4
- package/src/daemon/mode-session-startup-recovery.ts +23 -0
- package/src/daemon/mode-session-tracking.ts +54 -0
- package/src/daemon/process-message.ts +13 -4
- package/src/daemon/virtual-desktop-context.ts +21 -0
- 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 +76 -68
- package/src/desktop/desktop-automation-lease.ts +41 -50
- 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-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 +11 -122
- package/src/desktop/desktop-stream-bridge.ts +6 -8
- package/src/desktop/desktop-window-theme.ts +5 -25
- package/src/desktop/virtual-desktop-feature.ts +52 -2
- 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 +63 -18
- package/src/mcp/__tests__/tool-caps.test.ts +28 -1
- package/src/mcp/manager.ts +3 -0
- package/src/mcp/tool-caps.ts +12 -4
- 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/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 +1 -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 +0 -23
- 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/signal.ts +4 -19
- package/src/notifications/types.ts +15 -0
- package/src/oauth/connection-resolver.ts +1 -2
- package/src/oauth/oauth-store.ts +1 -3
- package/src/oauth/provider-serializer.ts +7 -0
- package/src/oauth/seed-providers.ts +30 -0
- package/src/onboarding/onboarding-events-store.ts +99 -12
- package/src/persistence/__tests__/client-connection-events-store.test.ts +322 -0
- package/src/persistence/client-connection-events-store.ts +377 -0
- package/src/persistence/conversation-crud.ts +55 -6
- package/src/persistence/conversation-mode-sessions.test.ts +424 -0
- package/src/persistence/conversation-mode-sessions.ts +460 -0
- package/src/persistence/conversation-queries.ts +6 -19
- package/src/persistence/llm-usage-store.ts +3 -9
- package/src/persistence/message-metadata.ts +25 -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/conversations.ts +67 -0
- package/src/persistence/schema/infrastructure.ts +29 -0
- package/src/persistence/steps.ts +17 -0
- package/src/plugin-api/__tests__/plugin-name-env.test.ts +249 -0
- package/src/plugin-api/effective-context-window.ts +33 -0
- package/src/plugin-api/index.ts +24 -5
- 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/__tests__/archive-removal-framing.test.ts +64 -0
- package/src/plugins/defaults/memory/__tests__/worker-control.test.ts +19 -6
- package/src/plugins/defaults/memory/context-search/agent-protocol.ts +9 -12
- package/src/plugins/defaults/memory/context-search/agent-runner.ts +78 -22
- package/src/plugins/defaults/memory/context-search/format.ts +51 -7
- 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/types.ts +1 -11
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +11 -4
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +12 -21
- package/src/plugins/defaults/memory/graph/tools.ts +35 -64
- package/src/plugins/defaults/memory/src/memory-eval-routes.ts +2 -3
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +5 -0
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +2 -1
- package/src/plugins/defaults/memory/substrate/prompts/consolidation.ts +2 -2
- package/src/plugins/defaults/memory/tools.test.ts +124 -9
- package/src/plugins/defaults/memory/tools.ts +38 -11
- package/src/plugins/defaults/memory/v3/__tests__/pool-log-store.test.ts +165 -27
- package/src/plugins/defaults/memory/v3/__tests__/pool-select.test.ts +626 -27
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +46 -27
- package/src/plugins/defaults/memory/v3/orchestrate.ts +78 -38
- package/src/plugins/defaults/memory/v3/pool-log-store.ts +65 -79
- package/src/plugins/defaults/memory/v3/pool-select.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/pool-select.ts +683 -44
- 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/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 +1 -1
- package/src/providers/jev/client.test.ts +10 -0
- package/src/providers/jev/client.ts +20 -4
- package/src/providers/model-catalog.ts +4 -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/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 +4 -2
- package/src/runtime/actor-trust-resolver.ts +3 -3
- package/src/runtime/agent-wake.ts +1 -1
- 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-reply-router.ts +28 -32
- 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/vbundle-builder.ts +24 -1
- package/src/runtime/migrations/vbundle-import-analyzer.ts +13 -4
- package/src/runtime/migrations/vbundle-import-policy.ts +10 -0
- 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 +1 -1
- 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/client-routes.ts +108 -0
- package/src/runtime/routes/conversation-management-routes.ts +4 -1
- package/src/runtime/routes/conversation-routes.ts +113 -27
- 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 +4 -6
- 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/identity-routes.ts +1 -5
- package/src/runtime/routes/image-generation-routes.ts +8 -14
- package/src/runtime/routes/inbound-message-handler.ts +35 -38
- 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 +38 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +2 -5
- package/src/runtime/routes/inbound-stages/reaction-intercept.ts +2 -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-providers.ts +7 -0
- package/src/runtime/routes/plugins-routes.ts +6 -0
- package/src/runtime/routes/roadmap-routes.ts +47 -8
- package/src/runtime/routes/secret-routes.ts +1 -1
- 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/worker-control.ts +15 -5
- package/src/security/secure-keys.ts +53 -103
- 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.ts +6 -4
- package/src/tools/browser/browser-execution.ts +22 -59
- 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 +4 -1
- 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/skills/load.ts +2 -1
- package/src/tools/skills/sandbox-runner.ts +11 -2
- 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 +11 -0
- package/src/tools/terminal/safe-env.ts +4 -0
- package/src/tools/terminal/shell.ts +2 -0
- 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/canonicalize-identity.test.ts +21 -0
- package/src/util/canonicalize-identity.ts +16 -0
- package/src/util/errors.ts +13 -3
- package/src/util/provider-error-patterns.ts +3 -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
|
@@ -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,19 +331,6 @@ 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
336
|
// which is what a reader scanning the bell wants to see. A producer that
|
|
@@ -385,16 +372,6 @@ const TEMPLATES: Partial<Record<NotificationSourceEventName, CopyTemplate>> = {
|
|
|
385
372
|
body: summary !== "" ? summary : describeUnclassifiedFailure(payload),
|
|
386
373
|
};
|
|
387
374
|
},
|
|
388
|
-
|
|
389
|
-
"quick_chat.response_ready": (payload) => ({
|
|
390
|
-
title: "Quick chat reply ready",
|
|
391
|
-
body: str(payload.preview, "Your quick chat response is ready"),
|
|
392
|
-
}),
|
|
393
|
-
|
|
394
|
-
"voice.response_ready": (payload) => ({
|
|
395
|
-
title: "Voice reply ready",
|
|
396
|
-
body: str(payload.preview, "A voice response is ready"),
|
|
397
|
-
}),
|
|
398
375
|
};
|
|
399
376
|
|
|
400
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
|