@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
|
@@ -106,7 +106,10 @@ import { markProcessed } from "../../persistence/delivery-status.js";
|
|
|
106
106
|
import { upsertBinding } from "../../persistence/external-conversation-store.js";
|
|
107
107
|
import type { ContentBlock } from "../../providers/types.js";
|
|
108
108
|
import { checkIngressForSecrets } from "../../security/secret-ingress.js";
|
|
109
|
-
import {
|
|
109
|
+
import {
|
|
110
|
+
canonicalizeInboundIdentity,
|
|
111
|
+
inboundIdentitiesMatch,
|
|
112
|
+
} from "../../util/canonicalize-identity.js";
|
|
110
113
|
import { safeParseRecord } from "../../util/json.js";
|
|
111
114
|
import { getLogger } from "../../util/logger.js";
|
|
112
115
|
import { truncate } from "../../util/truncate.js";
|
|
@@ -126,6 +129,11 @@ import {
|
|
|
126
129
|
enforceIngressAcl,
|
|
127
130
|
} from "./inbound-stages/acl-enforcement.js";
|
|
128
131
|
import { enforceAdmissionPolicy } from "./inbound-stages/admission-policy.js";
|
|
132
|
+
import {
|
|
133
|
+
type BackfilledSenderProvenance,
|
|
134
|
+
type BackfilledSenderProvenanceResolver,
|
|
135
|
+
createBackfilledSenderProvenanceResolver,
|
|
136
|
+
} from "./inbound-stages/backfill-sender-provenance.js";
|
|
129
137
|
import { processChannelMessageInBackground } from "./inbound-stages/background-dispatch.js";
|
|
130
138
|
import { handleBootstrapIntercept } from "./inbound-stages/bootstrap-intercept.js";
|
|
131
139
|
import { handleEditIntercept } from "./inbound-stages/edit-intercept.js";
|
|
@@ -1531,8 +1539,7 @@ export async function handleChannelInbound({
|
|
|
1531
1539
|
sourceMetadata.account.length > 0
|
|
1532
1540
|
? sourceMetadata.account
|
|
1533
1541
|
: undefined;
|
|
1534
|
-
const
|
|
1535
|
-
sourceChannel === "slack" && sourceMetadata?.slackBotMentioned === true;
|
|
1542
|
+
const botMentioned = sourceMetadata?.botMentioned === true;
|
|
1536
1543
|
|
|
1537
1544
|
// ── DM cold-start backfill ──
|
|
1538
1545
|
// First time a Slack DM without thread_ts lands in a conversation that
|
|
@@ -1625,7 +1632,7 @@ export async function handleChannelInbound({
|
|
|
1625
1632
|
approvalCopyGenerator,
|
|
1626
1633
|
chatType: sourceChatType,
|
|
1627
1634
|
clientTimezone: inboundClientTimezone,
|
|
1628
|
-
|
|
1635
|
+
botMentioned,
|
|
1629
1636
|
slackInbound,
|
|
1630
1637
|
channelInbound,
|
|
1631
1638
|
});
|
|
@@ -1836,6 +1843,7 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1836
1843
|
message: ProviderMessage;
|
|
1837
1844
|
account?: string;
|
|
1838
1845
|
guardianExternalUserId?: string;
|
|
1846
|
+
resolveSenderProvenance: BackfilledSenderProvenanceResolver;
|
|
1839
1847
|
}): Promise<boolean> {
|
|
1840
1848
|
const { message } = params;
|
|
1841
1849
|
|
|
@@ -1873,10 +1881,19 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1873
1881
|
message.metadata,
|
|
1874
1882
|
"actorTimezoneLabel",
|
|
1875
1883
|
);
|
|
1876
|
-
const
|
|
1884
|
+
const role = (await isBackfilledSlackAssistantMessage(
|
|
1877
1885
|
message,
|
|
1878
|
-
params.
|
|
1879
|
-
)
|
|
1886
|
+
params.account,
|
|
1887
|
+
))
|
|
1888
|
+
? "assistant"
|
|
1889
|
+
: "user";
|
|
1890
|
+
// The assistant's own posts are replayed as assistant history, not as any
|
|
1891
|
+
// person's words, so only a person's row asks who its sender is.
|
|
1892
|
+
const provenance: BackfilledSenderProvenance =
|
|
1893
|
+
role === "user"
|
|
1894
|
+
? await params.resolveSenderProvenance(actorExternalUserId)
|
|
1895
|
+
: { provenanceTrustClass: "unknown" };
|
|
1896
|
+
const isGuardian = provenance.provenanceTrustClass === "guardian";
|
|
1880
1897
|
const slackTranscriptTimestampTimezone =
|
|
1881
1898
|
resolveSlackTranscriptTimestampTimezone();
|
|
1882
1899
|
const slackTimezoneFields = buildSlackTimezoneMetadata({
|
|
@@ -1900,13 +1917,6 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1900
1917
|
...(slackFiles.length > 0 ? { slackFiles } : {}),
|
|
1901
1918
|
};
|
|
1902
1919
|
|
|
1903
|
-
const role = (await isBackfilledSlackAssistantMessage(
|
|
1904
|
-
message,
|
|
1905
|
-
params.account,
|
|
1906
|
-
))
|
|
1907
|
-
? "assistant"
|
|
1908
|
-
: "user";
|
|
1909
|
-
|
|
1910
1920
|
const rawText = message.text ?? "";
|
|
1911
1921
|
|
|
1912
1922
|
// `sentAt` is when the message was sent; the row's `createdAt` is when the
|
|
@@ -1945,7 +1955,7 @@ async function persistBackfilledSlackMessage(params: {
|
|
|
1945
1955
|
metadata: {
|
|
1946
1956
|
...envelope,
|
|
1947
1957
|
...(sentAt !== undefined ? { sentAt } : {}),
|
|
1948
|
-
|
|
1958
|
+
...provenance,
|
|
1949
1959
|
provenanceSourceChannel: "slack",
|
|
1950
1960
|
...(params.guardianExternalUserId
|
|
1951
1961
|
? { provenanceGuardianExternalUserId: params.guardianExternalUserId }
|
|
@@ -2064,22 +2074,6 @@ async function buildBackfilledSlackContentBlocks(
|
|
|
2064
2074
|
return blocks;
|
|
2065
2075
|
}
|
|
2066
2076
|
|
|
2067
|
-
function isBackfilledSlackGuardianMessage(
|
|
2068
|
-
message: ProviderMessage,
|
|
2069
|
-
guardianExternalUserId: string | undefined,
|
|
2070
|
-
): boolean {
|
|
2071
|
-
const rawSenderId = message.sender?.id?.trim();
|
|
2072
|
-
if (!rawSenderId || !guardianExternalUserId) {
|
|
2073
|
-
return false;
|
|
2074
|
-
}
|
|
2075
|
-
const normalizedSender =
|
|
2076
|
-
canonicalizeInboundIdentity("slack", rawSenderId) ?? rawSenderId;
|
|
2077
|
-
const normalizedGuardian =
|
|
2078
|
-
canonicalizeInboundIdentity("slack", guardianExternalUserId) ??
|
|
2079
|
-
guardianExternalUserId.trim();
|
|
2080
|
-
return normalizedSender === normalizedGuardian;
|
|
2081
|
-
}
|
|
2082
|
-
|
|
2083
2077
|
const SLACK_ASSISTANT_THREAD_PLACEHOLDER_TEXT = "New Assistant Thread";
|
|
2084
2078
|
|
|
2085
2079
|
async function isSlackAssistantThreadPlaceholder(
|
|
@@ -2116,7 +2110,7 @@ async function isBackfilledSlackAssistantMessage(
|
|
|
2116
2110
|
return false;
|
|
2117
2111
|
}
|
|
2118
2112
|
|
|
2119
|
-
if (rawSenderId &&
|
|
2113
|
+
if (rawSenderId && inboundIdentitiesMatch("slack", rawSenderId, botUserId)) {
|
|
2120
2114
|
return true;
|
|
2121
2115
|
}
|
|
2122
2116
|
|
|
@@ -2132,7 +2126,7 @@ async function isBackfilledSlackAssistantMessage(
|
|
|
2132
2126
|
const resolvedBotUserId = await resolveSlackBotUserId(account, rawBotId);
|
|
2133
2127
|
return (
|
|
2134
2128
|
typeof resolvedBotUserId === "string" &&
|
|
2135
|
-
|
|
2129
|
+
inboundIdentitiesMatch("slack", resolvedBotUserId, botUserId)
|
|
2136
2130
|
);
|
|
2137
2131
|
} catch (err) {
|
|
2138
2132
|
log.warn(
|
|
@@ -2143,14 +2137,6 @@ async function isBackfilledSlackAssistantMessage(
|
|
|
2143
2137
|
}
|
|
2144
2138
|
}
|
|
2145
2139
|
|
|
2146
|
-
function slackIdentityMatches(left: string, right: string): boolean {
|
|
2147
|
-
const canonicalSender =
|
|
2148
|
-
canonicalizeInboundIdentity("slack", left) ?? left.trim();
|
|
2149
|
-
const canonicalBot =
|
|
2150
|
-
canonicalizeInboundIdentity("slack", right) ?? right.trim();
|
|
2151
|
-
return canonicalSender === canonicalBot;
|
|
2152
|
-
}
|
|
2153
|
-
|
|
2154
2140
|
/**
|
|
2155
2141
|
* Transient view of `slackFiles` that preserves the download URLs added by
|
|
2156
2142
|
* `mapSlackFiles` on the in-flight `ProviderMessage`. These URLs never reach
|
|
@@ -2291,6 +2277,10 @@ async function runBackfillSlackDmIfCold(params: {
|
|
|
2291
2277
|
// and a transcript that reads correctly when the renderer joins on
|
|
2292
2278
|
// monotonic createdAt.
|
|
2293
2279
|
const ordered = [...fetched].reverse();
|
|
2280
|
+
const resolveSenderProvenance = createBackfilledSenderProvenanceResolver(
|
|
2281
|
+
params.guardianExternalUserId,
|
|
2282
|
+
ordered,
|
|
2283
|
+
);
|
|
2294
2284
|
for (const message of ordered) {
|
|
2295
2285
|
if (seen.has(message.id)) {
|
|
2296
2286
|
continue;
|
|
@@ -2310,6 +2300,7 @@ async function runBackfillSlackDmIfCold(params: {
|
|
|
2310
2300
|
...(params.guardianExternalUserId
|
|
2311
2301
|
? { guardianExternalUserId: params.guardianExternalUserId }
|
|
2312
2302
|
: {}),
|
|
2303
|
+
resolveSenderProvenance,
|
|
2313
2304
|
});
|
|
2314
2305
|
seen.add(message.id);
|
|
2315
2306
|
if (stored) {
|
|
@@ -2891,6 +2882,10 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
|
|
|
2891
2882
|
}
|
|
2892
2883
|
|
|
2893
2884
|
let persisted = 0;
|
|
2885
|
+
const resolveSenderProvenance = createBackfilledSenderProvenanceResolver(
|
|
2886
|
+
guardianExternalUserId,
|
|
2887
|
+
fetched,
|
|
2888
|
+
);
|
|
2894
2889
|
for (const message of fetched) {
|
|
2895
2890
|
if (!message.id) {
|
|
2896
2891
|
continue;
|
|
@@ -2908,6 +2903,7 @@ export async function triggerSlackThreadBackfillIfNeeded(params: {
|
|
|
2908
2903
|
message,
|
|
2909
2904
|
...(account ? { account } : {}),
|
|
2910
2905
|
...(guardianExternalUserId ? { guardianExternalUserId } : {}),
|
|
2906
|
+
resolveSenderProvenance,
|
|
2911
2907
|
});
|
|
2912
2908
|
threadState.storedChannelTs.add(message.id);
|
|
2913
2909
|
if (stored) {
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
import { afterAll, beforeEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { TrustVerdict } from "@vellumai/gateway-client";
|
|
4
|
+
|
|
5
|
+
import type { InboundTrustReadResult } from "../../../calls/inbound-trust-reader.js";
|
|
6
|
+
import * as inboundTrustReader from "../../../calls/inbound-trust-reader.js";
|
|
7
|
+
import type { Message as ProviderMessage } from "../../../messaging/provider-types.js";
|
|
8
|
+
import { createBackfilledSenderProvenanceResolver } from "./backfill-sender-provenance.js";
|
|
9
|
+
|
|
10
|
+
const readsBySender = new Map<string, InboundTrustReadResult>();
|
|
11
|
+
const readInboundTrustMock = spyOn(
|
|
12
|
+
inboundTrustReader,
|
|
13
|
+
"readInboundTrust",
|
|
14
|
+
).mockImplementation(
|
|
15
|
+
async (input) =>
|
|
16
|
+
readsBySender.get(input.actorExternalId ?? "") ?? { ok: false },
|
|
17
|
+
);
|
|
18
|
+
|
|
19
|
+
afterAll(() => {
|
|
20
|
+
readInboundTrustMock.mockRestore();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const GUARDIAN_ID = "U_GUARDIAN";
|
|
24
|
+
|
|
25
|
+
function memberVerdict(
|
|
26
|
+
trustClass: TrustVerdict["trustClass"],
|
|
27
|
+
contactId: string,
|
|
28
|
+
status: string,
|
|
29
|
+
): TrustVerdict {
|
|
30
|
+
return {
|
|
31
|
+
trustClass,
|
|
32
|
+
canonicalSenderId: `U_${contactId}`,
|
|
33
|
+
contactId,
|
|
34
|
+
channelId: `ch-${contactId}`,
|
|
35
|
+
status,
|
|
36
|
+
policy: "allow",
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function readOf(verdict: TrustVerdict): InboundTrustReadResult {
|
|
41
|
+
return { ok: true, verdict, admissionPolicy: null };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
beforeEach(() => {
|
|
45
|
+
readsBySender.clear();
|
|
46
|
+
readInboundTrustMock.mockClear();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
describe("createBackfilledSenderProvenanceResolver", () => {
|
|
50
|
+
test("stamps the gateway verdict's trust class and contact id", async () => {
|
|
51
|
+
readsBySender.set(
|
|
52
|
+
"U_ALICE",
|
|
53
|
+
readOf(memberVerdict("trusted_contact", "c-alice", "active")),
|
|
54
|
+
);
|
|
55
|
+
readsBySender.set(
|
|
56
|
+
"U_BOB",
|
|
57
|
+
readOf(memberVerdict("unverified_contact", "c-bob", "unverified")),
|
|
58
|
+
);
|
|
59
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
60
|
+
|
|
61
|
+
expect(await resolve("U_ALICE")).toEqual({
|
|
62
|
+
provenanceTrustClass: "trusted_contact",
|
|
63
|
+
provenanceContactId: "c-alice",
|
|
64
|
+
});
|
|
65
|
+
expect(await resolve("U_BOB")).toEqual({
|
|
66
|
+
provenanceTrustClass: "unverified_contact",
|
|
67
|
+
provenanceContactId: "c-bob",
|
|
68
|
+
});
|
|
69
|
+
expect(readInboundTrustMock).toHaveBeenCalledWith({
|
|
70
|
+
channelType: "slack",
|
|
71
|
+
actorExternalId: "U_ALICE",
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
test("a stranger verdict carries no contact id and no lookup-failed marker", async () => {
|
|
76
|
+
readsBySender.set(
|
|
77
|
+
"U_STRANGER",
|
|
78
|
+
readOf({ trustClass: "unknown", canonicalSenderId: "U_STRANGER" }),
|
|
79
|
+
);
|
|
80
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
81
|
+
|
|
82
|
+
expect(await resolve("U_STRANGER")).toEqual({
|
|
83
|
+
provenanceTrustClass: "unknown",
|
|
84
|
+
});
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
test("an unreadable verdict falls back to the guardian address comparison and marks the failed lookup", async () => {
|
|
88
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
89
|
+
|
|
90
|
+
expect(await resolve(GUARDIAN_ID)).toEqual({
|
|
91
|
+
provenanceTrustClass: "guardian",
|
|
92
|
+
provenanceLookupFailed: true,
|
|
93
|
+
});
|
|
94
|
+
expect(await resolve("U_ALICE")).toEqual({
|
|
95
|
+
provenanceTrustClass: "unknown",
|
|
96
|
+
provenanceLookupFailed: true,
|
|
97
|
+
});
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
test("a resolver-failure verdict is not trusted for class or contact id", async () => {
|
|
101
|
+
readsBySender.set(
|
|
102
|
+
"U_ALICE",
|
|
103
|
+
readOf({
|
|
104
|
+
...memberVerdict("trusted_contact", "c-alice", "active"),
|
|
105
|
+
resolutionFailed: true,
|
|
106
|
+
}),
|
|
107
|
+
);
|
|
108
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
109
|
+
|
|
110
|
+
expect(await resolve("U_ALICE")).toEqual({
|
|
111
|
+
provenanceTrustClass: "unknown",
|
|
112
|
+
provenanceLookupFailed: true,
|
|
113
|
+
});
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
test("reads the gateway once per distinct sender", async () => {
|
|
117
|
+
readsBySender.set(
|
|
118
|
+
"U_ALICE",
|
|
119
|
+
readOf(memberVerdict("trusted_contact", "c-alice", "active")),
|
|
120
|
+
);
|
|
121
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
122
|
+
|
|
123
|
+
await Promise.all([
|
|
124
|
+
resolve("U_ALICE"),
|
|
125
|
+
resolve(" U_ALICE "),
|
|
126
|
+
resolve("U_BOB"),
|
|
127
|
+
]);
|
|
128
|
+
await resolve("U_ALICE");
|
|
129
|
+
|
|
130
|
+
expect(readInboundTrustMock).toHaveBeenCalledTimes(2);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test("a row with no sender id is unknown without a gateway read or a lookup-failed marker", async () => {
|
|
134
|
+
const resolve = createBackfilledSenderProvenanceResolver(GUARDIAN_ID, []);
|
|
135
|
+
|
|
136
|
+
expect(await resolve(undefined)).toEqual({
|
|
137
|
+
provenanceTrustClass: "unknown",
|
|
138
|
+
});
|
|
139
|
+
expect(readInboundTrustMock).not.toHaveBeenCalled();
|
|
140
|
+
});
|
|
141
|
+
|
|
142
|
+
test("starts every sender's read up front and together, bots included", () => {
|
|
143
|
+
const message = (id: string, senderId: string, isBot = false) =>
|
|
144
|
+
({
|
|
145
|
+
id,
|
|
146
|
+
conversationId: "C1",
|
|
147
|
+
sender: { id: senderId, name: senderId },
|
|
148
|
+
text: "hi",
|
|
149
|
+
timestamp: 0,
|
|
150
|
+
platform: "slack",
|
|
151
|
+
...(isBot ? { metadata: { isBot: true } } : {}),
|
|
152
|
+
}) satisfies ProviderMessage;
|
|
153
|
+
|
|
154
|
+
createBackfilledSenderProvenanceResolver(GUARDIAN_ID, [
|
|
155
|
+
message("1", "U_ALICE"),
|
|
156
|
+
message("2", "B_THIRD_PARTY", true),
|
|
157
|
+
message("3", "U_ALICE"),
|
|
158
|
+
message("4", "U_BOB"),
|
|
159
|
+
]);
|
|
160
|
+
|
|
161
|
+
// Every read is in flight before any of them has settled.
|
|
162
|
+
expect(readInboundTrustMock.mock.calls.map(([input]) => input)).toEqual([
|
|
163
|
+
{ channelType: "slack", actorExternalId: "U_ALICE" },
|
|
164
|
+
{ channelType: "slack", actorExternalId: "B_THIRD_PARTY" },
|
|
165
|
+
{ channelType: "slack", actorExternalId: "U_BOB" },
|
|
166
|
+
]);
|
|
167
|
+
});
|
|
168
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provenance for backfilled Slack rows, resolved per sender.
|
|
3
|
+
*
|
|
4
|
+
* A backfilled row was written by someone other than the live inbound actor,
|
|
5
|
+
* so the live turn's trust context says nothing about it. Each sender is
|
|
6
|
+
* classified by the same gateway verdict live ingress uses
|
|
7
|
+
* (`resolve_inbound_trust`), so a backfilled row and a live row from the same
|
|
8
|
+
* person carry the same trust class and contact id. The verdict answers for
|
|
9
|
+
* the contact list at import time, which is when the row is written.
|
|
10
|
+
*
|
|
11
|
+
* When the verdict is unreadable or unusable, the row falls back to the
|
|
12
|
+
* guardian-address comparison, carries no contact id, and is marked
|
|
13
|
+
* `provenanceLookupFailed` so it stays distinguishable from a stranger.
|
|
14
|
+
*
|
|
15
|
+
* A read goes through `readInboundTrust`, so it also refreshes the
|
|
16
|
+
* member-verdict cache for that sender, as a live inbound read does.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { readInboundTrust } from "../../../calls/inbound-trust-reader.js";
|
|
20
|
+
import type { ActorAuthorProvenance } from "../../../daemon/message-provenance.js";
|
|
21
|
+
import type { Message as ProviderMessage } from "../../../messaging/provider-types.js";
|
|
22
|
+
import { inboundIdentitiesMatch } from "../../../util/canonicalize-identity.js";
|
|
23
|
+
import type { TrustClass } from "../../trust-class.js";
|
|
24
|
+
import {
|
|
25
|
+
verdictMemberFromVerdict,
|
|
26
|
+
verdictUsability,
|
|
27
|
+
} from "../../trust-verdict-consumer.js";
|
|
28
|
+
|
|
29
|
+
export interface BackfilledSenderProvenance extends ActorAuthorProvenance {
|
|
30
|
+
provenanceTrustClass: TrustClass;
|
|
31
|
+
/** The lookup ran and returned no usable verdict; see `messageMetadataSchema`. */
|
|
32
|
+
provenanceLookupFailed?: true;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Resolves a backfilled message's sender provenance. One resolver serves one
|
|
37
|
+
* backfill pass and reads the gateway at most once per distinct sender.
|
|
38
|
+
*/
|
|
39
|
+
export type BackfilledSenderProvenanceResolver = (
|
|
40
|
+
senderId: string | undefined,
|
|
41
|
+
) => Promise<BackfilledSenderProvenance>;
|
|
42
|
+
|
|
43
|
+
export function createBackfilledSenderProvenanceResolver(
|
|
44
|
+
guardianExternalUserId: string | undefined,
|
|
45
|
+
messages: readonly ProviderMessage[],
|
|
46
|
+
): BackfilledSenderProvenanceResolver {
|
|
47
|
+
const bySender = new Map<string, Promise<BackfilledSenderProvenance>>();
|
|
48
|
+
const resolve: BackfilledSenderProvenanceResolver = (senderId) => {
|
|
49
|
+
const trimmed = senderId?.trim();
|
|
50
|
+
if (!trimmed) {
|
|
51
|
+
return Promise.resolve({ provenanceTrustClass: "unknown" });
|
|
52
|
+
}
|
|
53
|
+
let pending = bySender.get(trimmed);
|
|
54
|
+
if (!pending) {
|
|
55
|
+
pending = resolveSenderProvenance(trimmed, guardianExternalUserId);
|
|
56
|
+
bySender.set(trimmed, pending);
|
|
57
|
+
}
|
|
58
|
+
return pending;
|
|
59
|
+
};
|
|
60
|
+
// Every sender's read starts now, so the pass waits on the slowest read
|
|
61
|
+
// rather than their sum. Bots included: a third-party bot's post is a user
|
|
62
|
+
// row, and singling out this assistant's own posts needs an async lookup.
|
|
63
|
+
// A read reports failure as a result, never a rejection.
|
|
64
|
+
for (const message of messages) {
|
|
65
|
+
void resolve(message.sender?.id);
|
|
66
|
+
}
|
|
67
|
+
return resolve;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async function resolveSenderProvenance(
|
|
71
|
+
senderId: string,
|
|
72
|
+
guardianExternalUserId: string | undefined,
|
|
73
|
+
): Promise<BackfilledSenderProvenance> {
|
|
74
|
+
const read = await readInboundTrust({
|
|
75
|
+
channelType: "slack",
|
|
76
|
+
actorExternalId: senderId,
|
|
77
|
+
});
|
|
78
|
+
if (read.ok) {
|
|
79
|
+
const usability = verdictUsability(read.verdict);
|
|
80
|
+
if (usability.usable) {
|
|
81
|
+
const member = verdictMemberFromVerdict(usability.verdict);
|
|
82
|
+
return {
|
|
83
|
+
provenanceTrustClass: usability.verdict.trustClass,
|
|
84
|
+
...(member ? { provenanceContactId: member.contactId } : {}),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
provenanceTrustClass:
|
|
90
|
+
guardianExternalUserId !== undefined &&
|
|
91
|
+
inboundIdentitiesMatch("slack", senderId, guardianExternalUserId)
|
|
92
|
+
? "guardian"
|
|
93
|
+
: "unknown",
|
|
94
|
+
provenanceLookupFailed: true,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
@@ -173,10 +173,10 @@ import {
|
|
|
173
173
|
} from "../../../daemon/conversation-registry.js";
|
|
174
174
|
import type { TrustContext } from "../../../daemon/trust-context-types.js";
|
|
175
175
|
import type { MessageProcessor } from "../../http-types.js";
|
|
176
|
+
import { hasDeliverableAssistantText } from "../../no-response.js";
|
|
176
177
|
import {
|
|
177
178
|
isBoundGuardianActor,
|
|
178
179
|
processChannelMessageInBackground,
|
|
179
|
-
shouldShowActivityForText,
|
|
180
180
|
shouldShowActivityImmediately,
|
|
181
181
|
} from "./background-dispatch.js";
|
|
182
182
|
import { __resetChannelTurnAdmissionForTests } from "./channel-turn-admission.js";
|
|
@@ -260,6 +260,35 @@ describe("processChannelMessageInBackground — reply delivery", () => {
|
|
|
260
260
|
const flush = (): Promise<void> =>
|
|
261
261
|
new Promise((resolve) => setTimeout(resolve, 10));
|
|
262
262
|
|
|
263
|
+
test("names the inbound sender as the persisted message's author", async () => {
|
|
264
|
+
let capturedAuthor: TrustContext | undefined;
|
|
265
|
+
const processMessage: MessageProcessor = async (
|
|
266
|
+
_conversationId,
|
|
267
|
+
_content,
|
|
268
|
+
options,
|
|
269
|
+
) => {
|
|
270
|
+
capturedAuthor = options?.author;
|
|
271
|
+
return { messageId: "user-msg-author" };
|
|
272
|
+
};
|
|
273
|
+
|
|
274
|
+
processChannelMessageInBackground({
|
|
275
|
+
processMessage,
|
|
276
|
+
conversationId: "conv-author",
|
|
277
|
+
eventId: "evt-author",
|
|
278
|
+
content: "the export endpoint needs a scoped token",
|
|
279
|
+
sourceChannel: "slack",
|
|
280
|
+
sourceInterface: "slack",
|
|
281
|
+
externalChatId: "C-AUTHOR",
|
|
282
|
+
trustCtx,
|
|
283
|
+
metadataHints: [],
|
|
284
|
+
replyCallbackUrl: "https://example.test/deliver/slack?channel=C-AUTHOR",
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
await flush();
|
|
288
|
+
|
|
289
|
+
expect(capturedAuthor).toBe(trustCtx);
|
|
290
|
+
});
|
|
291
|
+
|
|
263
292
|
test("records callback delivery failures without failing processing", async () => {
|
|
264
293
|
const conversationId = "conv-delivery-failure";
|
|
265
294
|
const channelId = "C-DELIVERY-FAILURE";
|
|
@@ -1070,14 +1099,14 @@ describe("channel activity timing", () => {
|
|
|
1070
1099
|
});
|
|
1071
1100
|
|
|
1072
1101
|
test("recognizes only deliverable text as a reason to show activity", () => {
|
|
1073
|
-
expect(
|
|
1074
|
-
expect(
|
|
1075
|
-
expect(
|
|
1076
|
-
expect(
|
|
1077
|
-
expect(
|
|
1078
|
-
expect(
|
|
1079
|
-
expect(
|
|
1080
|
-
expect(
|
|
1102
|
+
expect(hasDeliverableAssistantText("")).toBe(false);
|
|
1103
|
+
expect(hasDeliverableAssistantText(" ")).toBe(false);
|
|
1104
|
+
expect(hasDeliverableAssistantText("<")).toBe(false);
|
|
1105
|
+
expect(hasDeliverableAssistantText("<no_response")).toBe(false);
|
|
1106
|
+
expect(hasDeliverableAssistantText("<no_response/>")).toBe(false);
|
|
1107
|
+
expect(hasDeliverableAssistantText(" <no_response /> ")).toBe(false);
|
|
1108
|
+
expect(hasDeliverableAssistantText("Real response.")).toBe(true);
|
|
1109
|
+
expect(hasDeliverableAssistantText("<no_response/>\nReal response.")).toBe(
|
|
1081
1110
|
true,
|
|
1082
1111
|
);
|
|
1083
1112
|
});
|
|
@@ -1169,7 +1198,7 @@ describe("channel activity timing", () => {
|
|
|
1169
1198
|
externalChatId: channelId,
|
|
1170
1199
|
trustCtx,
|
|
1171
1200
|
metadataHints: [],
|
|
1172
|
-
|
|
1201
|
+
botMentioned: true,
|
|
1173
1202
|
replyCallbackUrl: `https://example.test/deliver/slack?channel=${channelId}&threadTs=${threadTs}`,
|
|
1174
1203
|
});
|
|
1175
1204
|
|
|
@@ -105,8 +105,11 @@ export interface BackgroundProcessingParams {
|
|
|
105
105
|
chatType?: string;
|
|
106
106
|
/** IANA timezone reported by the active client for the current turn. */
|
|
107
107
|
clientTimezone?: string;
|
|
108
|
-
/**
|
|
109
|
-
|
|
108
|
+
/**
|
|
109
|
+
* The message addresses the assistant by name, as stated by the channel
|
|
110
|
+
* (`sourceMetadata.botMentioned`). Absent means not established.
|
|
111
|
+
*/
|
|
112
|
+
botMentioned?: boolean;
|
|
110
113
|
/**
|
|
111
114
|
* Slack-specific inbound metadata extracted at the HTTP boundary. Threaded
|
|
112
115
|
* through to `persistUserMessage` so the row can be tagged with a
|
|
@@ -166,7 +169,7 @@ export function processChannelMessageInBackground(
|
|
|
166
169
|
sourceLanguageCode,
|
|
167
170
|
chatType,
|
|
168
171
|
clientTimezone,
|
|
169
|
-
|
|
172
|
+
botMentioned,
|
|
170
173
|
slackInbound,
|
|
171
174
|
channelInbound,
|
|
172
175
|
slackReactionRowMeta,
|
|
@@ -204,7 +207,7 @@ export function processChannelMessageInBackground(
|
|
|
204
207
|
initiatorUserId: slackInbound?.actorExternalUserId,
|
|
205
208
|
startImmediately: shouldShowActivityImmediately({
|
|
206
209
|
chatType,
|
|
207
|
-
botMentioned
|
|
210
|
+
botMentioned,
|
|
208
211
|
}),
|
|
209
212
|
});
|
|
210
213
|
const stopApprovalWatcher = replyCallbackUrl
|
|
@@ -283,6 +286,7 @@ export function processChannelMessageInBackground(
|
|
|
283
286
|
},
|
|
284
287
|
assistantId,
|
|
285
288
|
trustContext: trustCtx,
|
|
289
|
+
author: trustCtx,
|
|
286
290
|
isInteractive: resolveRoutingState(trustCtx).promptWaitingAllowed,
|
|
287
291
|
...(displayContent !== undefined ? { displayContent } : {}),
|
|
288
292
|
...(cmdIntent ? { commandIntent: cmdIntent } : {}),
|
|
@@ -449,10 +453,6 @@ type ChannelActivityController = {
|
|
|
449
453
|
stop: () => void;
|
|
450
454
|
};
|
|
451
455
|
|
|
452
|
-
export function shouldShowActivityForText(text: string): boolean {
|
|
453
|
-
return hasDeliverableAssistantText(text);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
456
|
/**
|
|
457
457
|
* Room shapes with one other participant, in each channel's own word for it.
|
|
458
458
|
*
|
|
@@ -610,7 +610,7 @@ function startChannelActivity(params: {
|
|
|
610
610
|
return;
|
|
611
611
|
}
|
|
612
612
|
observedAssistantText += msg.text;
|
|
613
|
-
if (
|
|
613
|
+
if (hasDeliverableAssistantText(observedAssistantText)) {
|
|
614
614
|
show();
|
|
615
615
|
}
|
|
616
616
|
},
|
|
@@ -35,6 +35,7 @@ import { createApprovalCopyGenerator } from "../../../daemon/approval-generators
|
|
|
35
35
|
import { findConversation } from "../../../daemon/conversation-registry.js";
|
|
36
36
|
import { getDiskPressureStatus } from "../../../daemon/disk-pressure-guard.js";
|
|
37
37
|
import { classifyDiskPressureTurnPolicy } from "../../../daemon/disk-pressure-policy.js";
|
|
38
|
+
import { actorAuthorProvenance } from "../../../daemon/message-provenance.js";
|
|
38
39
|
import { processMessage } from "../../../daemon/process-message.js";
|
|
39
40
|
import { renderReactionHistoryText } from "../../../daemon/reaction-history-render.js";
|
|
40
41
|
import type { TrustContext } from "../../../daemon/trust-context-types.js";
|
|
@@ -544,6 +545,7 @@ async function persistReactionAsMessage(params: {
|
|
|
544
545
|
{
|
|
545
546
|
metadata: {
|
|
546
547
|
...provenanceFromTrustContext(params.trustCtx),
|
|
548
|
+
...actorAuthorProvenance(params.trustCtx),
|
|
547
549
|
...buildReactionRowEnvelope(facts),
|
|
548
550
|
},
|
|
549
551
|
skipIndexing: true,
|
|
@@ -16,6 +16,10 @@ import { randomUUID } from "node:crypto";
|
|
|
16
16
|
|
|
17
17
|
import { getUserSelectableProfilesForProvider } from "../../config/default-profile-catalog.js";
|
|
18
18
|
import { loadConfig } from "../../config/loader.js";
|
|
19
|
+
import {
|
|
20
|
+
nonTextConversationProfileMessage,
|
|
21
|
+
profileSupportsTextGeneration,
|
|
22
|
+
} from "../../config/profile-text-generation.js";
|
|
19
23
|
import { findConversation } from "../../daemon/conversation-registry.js";
|
|
20
24
|
import {
|
|
21
25
|
getConversation,
|
|
@@ -163,10 +167,16 @@ export async function setInferenceProfileSession({
|
|
|
163
167
|
);
|
|
164
168
|
}
|
|
165
169
|
|
|
170
|
+
const selectable = profiles as Record<string, unknown>;
|
|
171
|
+
const selected = selectable[profile] as Record<string, unknown>;
|
|
172
|
+
if (!profileSupportsTextGeneration(selected, selectable)) {
|
|
173
|
+
throw new BadRequestError(nonTextConversationProfileMessage(profile));
|
|
174
|
+
}
|
|
175
|
+
|
|
166
176
|
// Pinning a profile that provably cannot dispatch turns the next turn in
|
|
167
177
|
// this conversation into a hard failure, so refuse the pin the same way the
|
|
168
178
|
// active-profile setter does.
|
|
169
|
-
const entry =
|
|
179
|
+
const entry = selected;
|
|
170
180
|
const availability = await computeProfileAvailability(entry);
|
|
171
181
|
if (isUnavailable(availability)) {
|
|
172
182
|
throw new BadRequestError(
|
|
@@ -29,6 +29,10 @@ import {
|
|
|
29
29
|
getConfigReadOnly,
|
|
30
30
|
loadRawConfig,
|
|
31
31
|
} from "../../config/loader.js";
|
|
32
|
+
import {
|
|
33
|
+
nonTextConversationProfileMessage,
|
|
34
|
+
profileSupportsTextGeneration,
|
|
35
|
+
} from "../../config/profile-text-generation.js";
|
|
32
36
|
import {
|
|
33
37
|
ProfileEntry,
|
|
34
38
|
routingIdentityModelIssue,
|
|
@@ -891,6 +895,11 @@ async function handleSetActiveProfile({ body = {} }: RouteHandlerArgs) {
|
|
|
891
895
|
`Profile "${name}" is disabled and cannot be set as the active profile. Enable it first, or pick another.`,
|
|
892
896
|
);
|
|
893
897
|
}
|
|
898
|
+
if (
|
|
899
|
+
!profileSupportsTextGeneration(entry, effective as Record<string, unknown>)
|
|
900
|
+
) {
|
|
901
|
+
throw new BadRequestError(nonTextConversationProfileMessage(name));
|
|
902
|
+
}
|
|
894
903
|
// No escape hatch here: an active profile that cannot dispatch locks the
|
|
895
904
|
// user out of chat entirely, and nothing about the write signals that.
|
|
896
905
|
await guardProfileAvailability({
|
|
@@ -1025,7 +1025,7 @@ function anthropicMessageSections(
|
|
|
1025
1025
|
toolName: asString(block.name) ?? asString(block.tool_use_id),
|
|
1026
1026
|
data:
|
|
1027
1027
|
type === "web_search_tool_result"
|
|
1028
|
-
?
|
|
1028
|
+
? sanitizeAnthropicStructuredValue(block)
|
|
1029
1029
|
: undefined,
|
|
1030
1030
|
text: collectAnthropicToolResultText(block),
|
|
1031
1031
|
});
|
|
@@ -1397,12 +1397,6 @@ function collectAnthropicToolResultText(
|
|
|
1397
1397
|
return collectAnthropicText(block.content);
|
|
1398
1398
|
}
|
|
1399
1399
|
|
|
1400
|
-
function sanitizeAnthropicWebSearchToolResultData(
|
|
1401
|
-
block: Record<string, unknown>,
|
|
1402
|
-
): unknown {
|
|
1403
|
-
return sanitizeAnthropicStructuredValue(block);
|
|
1404
|
-
}
|
|
1405
|
-
|
|
1406
1400
|
function sanitizeAnthropicStructuredValue(value: unknown): unknown {
|
|
1407
1401
|
if (Array.isArray(value)) {
|
|
1408
1402
|
return value.map((entry) => sanitizeAnthropicStructuredValue(entry));
|