@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
|
@@ -1,28 +1,42 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Plugin-facing credential resolution.
|
|
3
3
|
*
|
|
4
|
-
* {@link resolveCredential} returns a stored credential's plaintext value
|
|
5
|
-
* same value `assistant credentials reveal` prints
|
|
6
|
-
* is either a credential UUID or a `"service/field"` string,
|
|
7
|
-
* reveal path does (see
|
|
8
|
-
*
|
|
4
|
+
* {@link resolveCredential} returns a stored credential's plaintext value
|
|
5
|
+
* (the same value `assistant credentials reveal` prints), resolving a
|
|
6
|
+
* reference that is either a credential UUID or a `"service/field"` string,
|
|
7
|
+
* exactly as the reveal path does (see
|
|
8
|
+
* {@link ../tools/credentials/resolve.resolveCredentialRef} and the
|
|
9
|
+
* `credentials/reveal` route).
|
|
9
10
|
*
|
|
10
11
|
* ## Plugin scoping
|
|
11
12
|
*
|
|
12
|
-
* When a plugin is in context
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
16
|
-
*
|
|
17
|
-
*
|
|
18
|
-
*
|
|
19
|
-
*
|
|
13
|
+
* When a plugin is in context, resolution is restricted to credentials
|
|
14
|
+
* whose `service` equals the plugin's runtime install-directory name
|
|
15
|
+
* (`sms/account_sid` for plugin `sms`). Context is:
|
|
16
|
+
*
|
|
17
|
+
* 1. In-process AsyncLocalStorage from `runInPluginContext` (hooks, plugin
|
|
18
|
+
* tools, plugin routes).
|
|
19
|
+
* 2. `VELLUM_PLUGIN_NAME` on a bash or skill-sandbox child.
|
|
20
|
+
* 3. The process entry path, when it sits under
|
|
21
|
+
* `plugins/<service>/skills/<skill>/{scripts,tools}/`.
|
|
22
|
+
*
|
|
23
|
+
* Outside any plugin context the resolver is unscoped and behaves like a
|
|
24
|
+
* direct reveal. A standalone child has an empty in-process metadata
|
|
25
|
+
* cache; when plugin context is set, a cache miss consults the live
|
|
26
|
+
* credential catalog so an empty cache is not reported as "not found".
|
|
20
27
|
*/
|
|
21
28
|
|
|
22
|
-
import {
|
|
29
|
+
import { credentialKey } from "@vellumai/credential-storage";
|
|
30
|
+
|
|
23
31
|
import { getSecureKeyResultAsync } from "../security/secure-keys.js";
|
|
32
|
+
import {
|
|
33
|
+
type CredentialMetadata,
|
|
34
|
+
listCredentialRecordsLive,
|
|
35
|
+
} from "../tools/credentials/metadata-store.js";
|
|
36
|
+
import { parseServiceFieldRef } from "../tools/credentials/ref-parse.js";
|
|
24
37
|
import { resolveCredentialRef } from "../tools/credentials/resolve.js";
|
|
25
38
|
import { credentialInPluginScope } from "./credential-scope.js";
|
|
39
|
+
import { resolveCallingPluginName } from "./plugin-name-env.js";
|
|
26
40
|
|
|
27
41
|
/**
|
|
28
42
|
* Raised when a credential cannot be resolved: the reference does not match a
|
|
@@ -36,6 +50,50 @@ export class CredentialResolutionError extends Error {
|
|
|
36
50
|
}
|
|
37
51
|
}
|
|
38
52
|
|
|
53
|
+
interface ResolvedRef {
|
|
54
|
+
service: string;
|
|
55
|
+
field: string;
|
|
56
|
+
storageKey: string;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
function findLiveRecord(
|
|
60
|
+
records: CredentialMetadata[],
|
|
61
|
+
ref: string,
|
|
62
|
+
): CredentialMetadata | undefined {
|
|
63
|
+
const byId = records.find((record) => record.credentialId === ref);
|
|
64
|
+
if (byId) {
|
|
65
|
+
return byId;
|
|
66
|
+
}
|
|
67
|
+
const parsed = parseServiceFieldRef(ref);
|
|
68
|
+
if (!parsed) {
|
|
69
|
+
return undefined;
|
|
70
|
+
}
|
|
71
|
+
return records.find(
|
|
72
|
+
(record) =>
|
|
73
|
+
record.service === parsed.service && record.field === parsed.field,
|
|
74
|
+
);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async function resolveCredentialRefLive(
|
|
78
|
+
ref: string,
|
|
79
|
+
): Promise<ResolvedRef | undefined> {
|
|
80
|
+
const live = await listCredentialRecordsLive();
|
|
81
|
+
if (live.unreachable) {
|
|
82
|
+
throw new CredentialResolutionError(
|
|
83
|
+
"Credential store is unreachable.",
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
const record = findLiveRecord(live.records, ref);
|
|
87
|
+
if (!record) {
|
|
88
|
+
return undefined;
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
service: record.service,
|
|
92
|
+
field: record.field,
|
|
93
|
+
storageKey: credentialKey(record.service, record.field),
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
|
|
39
97
|
/**
|
|
40
98
|
* Resolve a credential reference to its plaintext value.
|
|
41
99
|
*
|
|
@@ -45,15 +103,16 @@ export class CredentialResolutionError extends Error {
|
|
|
45
103
|
* store is unreachable, or a plugin in context is not scoped to the credential.
|
|
46
104
|
*/
|
|
47
105
|
export async function resolveCredential(ref: string): Promise<string> {
|
|
48
|
-
const
|
|
106
|
+
const pluginName = resolveCallingPluginName();
|
|
107
|
+
|
|
108
|
+
let resolved: ResolvedRef | undefined = resolveCredentialRef(ref);
|
|
109
|
+
if (!resolved && pluginName !== undefined) {
|
|
110
|
+
resolved = await resolveCredentialRefLive(ref);
|
|
111
|
+
}
|
|
49
112
|
if (!resolved) {
|
|
50
113
|
throw new CredentialResolutionError(`Credential not found: ${ref}`);
|
|
51
114
|
}
|
|
52
115
|
|
|
53
|
-
// Scope the resolution to the plugin in context, if any. The ownership gate
|
|
54
|
-
// is enforced before the plaintext is read so an out-of-scope plugin never
|
|
55
|
-
// touches the secure backend.
|
|
56
|
-
const pluginName = getCurrentPluginName();
|
|
57
116
|
if (
|
|
58
117
|
pluginName !== undefined &&
|
|
59
118
|
!credentialInPluginScope(pluginName, resolved.service)
|
|
@@ -70,7 +129,7 @@ export async function resolveCredential(ref: string): Promise<string> {
|
|
|
70
129
|
if (value == null || value.length === 0) {
|
|
71
130
|
if (unreachable) {
|
|
72
131
|
throw new CredentialResolutionError(
|
|
73
|
-
"Credential store is unreachable
|
|
132
|
+
"Credential store is unreachable.",
|
|
74
133
|
);
|
|
75
134
|
}
|
|
76
135
|
throw new CredentialResolutionError(`Credential not found: ${ref}`);
|
|
@@ -397,3 +397,25 @@ describe("doesSupportVision with a bare string", () => {
|
|
|
397
397
|
expect(doesSupportVision("qwen2.5-vl")).toBe(true);
|
|
398
398
|
});
|
|
399
399
|
});
|
|
400
|
+
|
|
401
|
+
describe("doesSupportVision with a resolved target", () => {
|
|
402
|
+
test("profile policy can enable images for a catalog text model", () => {
|
|
403
|
+
expect(
|
|
404
|
+
doesSupportVision({
|
|
405
|
+
provider: "fireworks",
|
|
406
|
+
model: "accounts/fireworks/models/glm-5p2",
|
|
407
|
+
inputModalities: { image: { enabled: true, supported: true } },
|
|
408
|
+
}),
|
|
409
|
+
).toBe(true);
|
|
410
|
+
});
|
|
411
|
+
|
|
412
|
+
test("profile policy can disable images for a catalog vision model", () => {
|
|
413
|
+
expect(
|
|
414
|
+
doesSupportVision({
|
|
415
|
+
provider: "anthropic",
|
|
416
|
+
model: "claude-opus-4-6",
|
|
417
|
+
inputModalities: { image: { enabled: false } },
|
|
418
|
+
}),
|
|
419
|
+
).toBe(false);
|
|
420
|
+
});
|
|
421
|
+
});
|
|
@@ -37,15 +37,24 @@ import {
|
|
|
37
37
|
} from "../providers/model-catalog.js";
|
|
38
38
|
import type { ModelProfileInfo } from "./types.js";
|
|
39
39
|
|
|
40
|
+
/** A fully resolved provider target plus the winning profile's policy. */
|
|
41
|
+
export interface ResolvedVisionTarget {
|
|
42
|
+
readonly provider?: string;
|
|
43
|
+
readonly model: string;
|
|
44
|
+
readonly inputModalities?: InputModalities | null;
|
|
45
|
+
}
|
|
46
|
+
|
|
40
47
|
/**
|
|
41
48
|
* Whether the given model or profile can process image input.
|
|
42
49
|
*
|
|
43
|
-
* `modelOrProfile` may be a concrete model id, a profile key,
|
|
44
|
-
* {@link ModelProfileInfo}
|
|
45
|
-
*
|
|
50
|
+
* `modelOrProfile` may be a concrete model id, a profile key, a
|
|
51
|
+
* {@link ModelProfileInfo}, or a fully resolved target. A resolved target
|
|
52
|
+
* combines the final provider/model with the winning profile's modality
|
|
53
|
+
* policy. A bare string is resolved as a model id first and, failing that, as
|
|
54
|
+
* a profile key. Returns `false` when nothing resolves.
|
|
46
55
|
*/
|
|
47
56
|
export function doesSupportVision(
|
|
48
|
-
modelOrProfile: ModelProfileInfo | string,
|
|
57
|
+
modelOrProfile: ModelProfileInfo | ResolvedVisionTarget | string,
|
|
49
58
|
): boolean {
|
|
50
59
|
if (typeof modelOrProfile === "string") {
|
|
51
60
|
// Concrete catalog model id first, then a profile key, then any profile
|
|
@@ -58,7 +67,10 @@ export function doesSupportVision(
|
|
|
58
67
|
false
|
|
59
68
|
);
|
|
60
69
|
}
|
|
61
|
-
|
|
70
|
+
if ("key" in modelOrProfile) {
|
|
71
|
+
return profileVision(modelOrProfile.key) ?? false;
|
|
72
|
+
}
|
|
73
|
+
return resolveEntryVision(modelOrProfile) ?? false;
|
|
62
74
|
}
|
|
63
75
|
|
|
64
76
|
/**
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { afterEach, describe, expect, spyOn, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import type { SkillSummary } from "../../config/skills.js";
|
|
4
|
+
import * as skills from "../../config/skills.js";
|
|
5
|
+
import type { Conversation } from "../../daemon/conversation.js";
|
|
6
|
+
import * as conversationRegistry from "../../daemon/conversation-registry.js";
|
|
7
|
+
import { PLUGIN_NAME_ENV } from "../../plugin-api/plugin-name-env.js";
|
|
8
|
+
import {
|
|
9
|
+
applyActivePluginName,
|
|
10
|
+
uniqueActivePluginOwner,
|
|
11
|
+
} from "../active-plugin-env.js";
|
|
12
|
+
|
|
13
|
+
function pluginSkill(id: string, pluginId: string): SkillSummary {
|
|
14
|
+
return {
|
|
15
|
+
id,
|
|
16
|
+
name: id,
|
|
17
|
+
displayName: id,
|
|
18
|
+
description: id,
|
|
19
|
+
directoryPath: `/tmp/${id}`,
|
|
20
|
+
skillFilePath: `/tmp/${id}/SKILL.md`,
|
|
21
|
+
source: "plugin",
|
|
22
|
+
owner: { kind: "plugin", id: pluginId },
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function bundledSkill(id: string): SkillSummary {
|
|
27
|
+
return {
|
|
28
|
+
id,
|
|
29
|
+
name: id,
|
|
30
|
+
displayName: id,
|
|
31
|
+
description: id,
|
|
32
|
+
directoryPath: `/tmp/${id}`,
|
|
33
|
+
skillFilePath: `/tmp/${id}/SKILL.md`,
|
|
34
|
+
source: "bundled",
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
function conversationWithSkills(skillIds: string[]): Conversation {
|
|
39
|
+
return {
|
|
40
|
+
skillProjectionState: new Map(skillIds.map((id) => [id, "v1:hash"])),
|
|
41
|
+
} as Conversation;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
describe("uniqueActivePluginOwner", () => {
|
|
45
|
+
let catalogSpy: ReturnType<typeof spyOn>;
|
|
46
|
+
let conversationSpy: ReturnType<typeof spyOn>;
|
|
47
|
+
|
|
48
|
+
afterEach(() => {
|
|
49
|
+
catalogSpy?.mockRestore();
|
|
50
|
+
conversationSpy?.mockRestore();
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
function stub(skillIds: string[], catalog: SkillSummary[]): void {
|
|
54
|
+
conversationSpy = spyOn(
|
|
55
|
+
conversationRegistry,
|
|
56
|
+
"findConversationOrSubagent",
|
|
57
|
+
).mockReturnValue(conversationWithSkills(skillIds));
|
|
58
|
+
catalogSpy = spyOn(skills, "loadSkillCatalog").mockReturnValue(catalog);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
test("returns the owner when exactly one plugin skill is active", () => {
|
|
62
|
+
stub(["sms-setup", "bash"], [
|
|
63
|
+
pluginSkill("sms-setup", "sms"),
|
|
64
|
+
bundledSkill("bash"),
|
|
65
|
+
]);
|
|
66
|
+
expect(uniqueActivePluginOwner("conv-1")).toBe("sms");
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
test("returns undefined when no plugin skill is active", () => {
|
|
70
|
+
stub(["bash"], [bundledSkill("bash")]);
|
|
71
|
+
expect(uniqueActivePluginOwner("conv-1")).toBeUndefined();
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
test("returns undefined when two plugin owners are active", () => {
|
|
75
|
+
stub(
|
|
76
|
+
["sms-setup", "linear-inbox"],
|
|
77
|
+
[
|
|
78
|
+
pluginSkill("sms-setup", "sms"),
|
|
79
|
+
pluginSkill("linear-inbox", "linear"),
|
|
80
|
+
],
|
|
81
|
+
);
|
|
82
|
+
expect(uniqueActivePluginOwner("conv-1")).toBeUndefined();
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
test("treats two skills from the same plugin as a single owner", () => {
|
|
86
|
+
stub(
|
|
87
|
+
["sms-setup", "sms-send"],
|
|
88
|
+
[pluginSkill("sms-setup", "sms"), pluginSkill("sms-send", "sms")],
|
|
89
|
+
);
|
|
90
|
+
expect(uniqueActivePluginOwner("conv-1")).toBe("sms");
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
test("returns undefined without a conversation id", () => {
|
|
94
|
+
expect(uniqueActivePluginOwner(undefined)).toBeUndefined();
|
|
95
|
+
expect(uniqueActivePluginOwner("")).toBeUndefined();
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
describe("applyActivePluginName", () => {
|
|
100
|
+
let catalogSpy: ReturnType<typeof spyOn>;
|
|
101
|
+
let conversationSpy: ReturnType<typeof spyOn>;
|
|
102
|
+
|
|
103
|
+
afterEach(() => {
|
|
104
|
+
catalogSpy?.mockRestore();
|
|
105
|
+
conversationSpy?.mockRestore();
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
test("sets VELLUM_PLUGIN_NAME when a unique plugin owner is active", () => {
|
|
109
|
+
conversationSpy = spyOn(
|
|
110
|
+
conversationRegistry,
|
|
111
|
+
"findConversationOrSubagent",
|
|
112
|
+
).mockReturnValue(conversationWithSkills(["sms-setup"]));
|
|
113
|
+
catalogSpy = spyOn(skills, "loadSkillCatalog").mockReturnValue([
|
|
114
|
+
pluginSkill("sms-setup", "sms"),
|
|
115
|
+
]);
|
|
116
|
+
|
|
117
|
+
const env: NodeJS.ProcessEnv = {};
|
|
118
|
+
applyActivePluginName(env, "conv-1");
|
|
119
|
+
expect(env[PLUGIN_NAME_ENV]).toBe("sms");
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
test("leaves the env unchanged when no unique plugin owner is active", () => {
|
|
123
|
+
conversationSpy = spyOn(
|
|
124
|
+
conversationRegistry,
|
|
125
|
+
"findConversationOrSubagent",
|
|
126
|
+
).mockReturnValue(conversationWithSkills(["sms-setup", "linear-inbox"]));
|
|
127
|
+
catalogSpy = spyOn(skills, "loadSkillCatalog").mockReturnValue([
|
|
128
|
+
pluginSkill("sms-setup", "sms"),
|
|
129
|
+
pluginSkill("linear-inbox", "linear"),
|
|
130
|
+
]);
|
|
131
|
+
|
|
132
|
+
const env: NodeJS.ProcessEnv = {};
|
|
133
|
+
applyActivePluginName(env, "conv-1");
|
|
134
|
+
expect(env[PLUGIN_NAME_ENV]).toBeUndefined();
|
|
135
|
+
});
|
|
136
|
+
});
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Inject the owning plugin name into a sanitized child environment when
|
|
3
|
+
* exactly one plugin-resident skill is active in the conversation.
|
|
4
|
+
*
|
|
5
|
+
* Identity comes from the skill catalog `owner` (install-directory
|
|
6
|
+
* basename), not from the child command or package.json `name`.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { loadSkillCatalog } from "../config/skills.js";
|
|
10
|
+
import { findConversationOrSubagent } from "../daemon/conversation-registry.js";
|
|
11
|
+
import { PLUGIN_NAME_ENV } from "../plugin-api/plugin-name-env.js";
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Unique catalog owner id among plugin-resident skills active in this
|
|
15
|
+
* conversation, or undefined when none or more than one plugin is active.
|
|
16
|
+
*/
|
|
17
|
+
export function uniqueActivePluginOwner(
|
|
18
|
+
conversationId: string | undefined,
|
|
19
|
+
): string | undefined {
|
|
20
|
+
if (conversationId === undefined || conversationId.length === 0) {
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
const conversation = findConversationOrSubagent(conversationId);
|
|
24
|
+
if (!conversation) {
|
|
25
|
+
return undefined;
|
|
26
|
+
}
|
|
27
|
+
const owners = new Set<string>();
|
|
28
|
+
const catalog = loadSkillCatalog();
|
|
29
|
+
for (const skillId of conversation.skillProjectionState.keys()) {
|
|
30
|
+
const skill = catalog.find((entry) => entry.id === skillId);
|
|
31
|
+
if (skill?.owner?.kind === "plugin" && skill.owner.id.length > 0) {
|
|
32
|
+
owners.add(skill.owner.id);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
if (owners.size !== 1) {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
return [...owners][0];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** Set `VELLUM_PLUGIN_NAME` on `env` when a single plugin owner is active. */
|
|
42
|
+
export function applyActivePluginName(
|
|
43
|
+
env: NodeJS.ProcessEnv,
|
|
44
|
+
conversationId: string | undefined,
|
|
45
|
+
): void {
|
|
46
|
+
const owner = uniqueActivePluginOwner(conversationId);
|
|
47
|
+
if (owner === undefined) {
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
env[PLUGIN_NAME_ENV] = owner;
|
|
51
|
+
}
|
|
@@ -78,6 +78,9 @@ import surfaceCompletionNudgePostModelCall from "./surface-completion-nudge/hook
|
|
|
78
78
|
import surfaceCompletionNudgeStop from "./surface-completion-nudge/hooks/stop.js";
|
|
79
79
|
import { resetSurfaceCompletionNudgeStoreForTests } from "./surface-completion-nudge/nudge-state-store.js";
|
|
80
80
|
import surfaceCompletionNudgePkg from "./surface-completion-nudge/package.json" with { type: "json" };
|
|
81
|
+
import taskProgressPostCompact from "./task-progress/hooks/post-compact.js";
|
|
82
|
+
import taskProgressUserPromptSubmit from "./task-progress/hooks/user-prompt-submit.js";
|
|
83
|
+
import taskProgressPkg from "./task-progress/package.json" with { type: "json" };
|
|
81
84
|
import taskProgressNudgePostToolUse, {
|
|
82
85
|
resetTaskProgressNudgeStateForTests,
|
|
83
86
|
} from "./task-progress-nudge/hooks/post-tool-use.js";
|
|
@@ -371,6 +374,26 @@ export const defaultExplorationDriftPlugin: Plugin = {
|
|
|
371
374
|
},
|
|
372
375
|
};
|
|
373
376
|
|
|
377
|
+
/**
|
|
378
|
+
* `task-progress`: a `user-prompt-submit` and `post-compact` hook pair that
|
|
379
|
+
* injects a compact provider-only snapshot of active `task_progress` cards.
|
|
380
|
+
* Reads canonical conversation surface snapshots from the host helper.
|
|
381
|
+
* Owns no durable state. Registered after `empty-response` so memory/runtime
|
|
382
|
+
* injection and refusal quarantine settle first. Built-in history repair
|
|
383
|
+
* still runs after the user-prompt hook chain. The snapshot is small enough
|
|
384
|
+
* to re-apply in minimal injection mode.
|
|
385
|
+
*/
|
|
386
|
+
export const defaultTaskProgressPlugin: Plugin = {
|
|
387
|
+
manifest: {
|
|
388
|
+
name: taskProgressPkg.name,
|
|
389
|
+
version: taskProgressPkg.version,
|
|
390
|
+
},
|
|
391
|
+
hooks: {
|
|
392
|
+
"user-prompt-submit": taskProgressUserPromptSubmit,
|
|
393
|
+
"post-compact": taskProgressPostCompact,
|
|
394
|
+
},
|
|
395
|
+
};
|
|
396
|
+
|
|
374
397
|
/**
|
|
375
398
|
* `task-progress-nudge` — a `post-tool-use` hook that nudges the model to show
|
|
376
399
|
* a `task_progress` card once an interactive turn has accumulated several
|
|
@@ -440,6 +463,7 @@ export function getAllDefaultPlugins(): readonly Plugin[] {
|
|
|
440
463
|
defaultImageFallbackPlugin,
|
|
441
464
|
defaultToolResultTruncatePlugin,
|
|
442
465
|
defaultEmptyResponsePlugin,
|
|
466
|
+
defaultTaskProgressPlugin,
|
|
443
467
|
defaultMaxTokensContinuePlugin,
|
|
444
468
|
defaultToolErrorPlugin,
|
|
445
469
|
defaultExplorationDriftPlugin,
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The daily archive (`memory/archive/`) holds raw buffer entries only. Per-turn
|
|
3
|
+
* injection reads concept pages and never the archive, and text a pass
|
|
4
|
+
* composes or derives on a page is not in it. So nothing the consolidation
|
|
5
|
+
* agent reads may present the archive as making removal safe: that framing
|
|
6
|
+
* licenses deleting filed content that exists nowhere else.
|
|
7
|
+
*
|
|
8
|
+
* The check is sentence-level: no sentence may pair the archive with
|
|
9
|
+
* reassurance that removing content loses nothing. A sentence warning that
|
|
10
|
+
* removed text IS lost stays allowed.
|
|
11
|
+
*/
|
|
12
|
+
import { describe, expect, test } from "bun:test";
|
|
13
|
+
|
|
14
|
+
import { renderConsolidationPrompt } from "../substrate/prompts/consolidation.js";
|
|
15
|
+
import { deleteMemoryPageTool } from "../tools.js";
|
|
16
|
+
|
|
17
|
+
function archiveSafetyClaims(text: string): string[] {
|
|
18
|
+
return text
|
|
19
|
+
.split(/(?<=[.!?])\s+/)
|
|
20
|
+
.filter(
|
|
21
|
+
(sentence) =>
|
|
22
|
+
/archive/i.test(sentence) &&
|
|
23
|
+
/don.t worry|no need to worry|never los|nothing is lost|won.t lose|safe to (?:delete|remove|cut|drop)/i.test(
|
|
24
|
+
sentence,
|
|
25
|
+
),
|
|
26
|
+
);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
describe("the archive is never framed as making removal safe", () => {
|
|
30
|
+
test("neither consolidation article shape makes the claim", () => {
|
|
31
|
+
const v2 = renderConsolidationPrompt("May 1, 12:00 PM", {
|
|
32
|
+
includeCorePagesSection: false,
|
|
33
|
+
articleShape: "v2",
|
|
34
|
+
bufferEntries: "",
|
|
35
|
+
});
|
|
36
|
+
// The over-long-sections step carries the one legitimate archive
|
|
37
|
+
// sentence, so the v3 render includes it.
|
|
38
|
+
const v3 = renderConsolidationPrompt("May 1, 12:00 PM", {
|
|
39
|
+
includeCorePagesSection: true,
|
|
40
|
+
articleShape: "v3",
|
|
41
|
+
bufferEntries: "",
|
|
42
|
+
overlongSections: {
|
|
43
|
+
windowChars: 6000,
|
|
44
|
+
sections: [{ slug: "journal", title: "", chars: 7200 }],
|
|
45
|
+
},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
expect(v3).toContain("the archive is a record");
|
|
49
|
+
expect(archiveSafetyClaims(v2)).toEqual([]);
|
|
50
|
+
expect(archiveSafetyClaims(v3)).toEqual([]);
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
test("a warning that removed text is lost is not the claim", () => {
|
|
54
|
+
expect(
|
|
55
|
+
archiveSafetyClaims(
|
|
56
|
+
"Text you cut from a page is lost to retrieval: the archive does not bring it back.",
|
|
57
|
+
),
|
|
58
|
+
).toEqual([]);
|
|
59
|
+
});
|
|
60
|
+
|
|
61
|
+
test("the delete_memory_page description does not make the claim", () => {
|
|
62
|
+
expect(archiveSafetyClaims(deleteMemoryPageTool.description)).toEqual([]);
|
|
63
|
+
});
|
|
64
|
+
});
|
|
@@ -231,18 +231,26 @@ describe("spawnMemoryWorkerProcess", () => {
|
|
|
231
231
|
}
|
|
232
232
|
});
|
|
233
233
|
|
|
234
|
-
test("
|
|
235
|
-
// A live PID file (this test process) makes the probe report running.
|
|
234
|
+
test("spawns when the PID file names an unrelated live process", async () => {
|
|
236
235
|
writeFileSync(pidPath, String(process.pid));
|
|
237
236
|
let spawned = false;
|
|
238
237
|
const restore = stubBunSpawn(() => {
|
|
239
238
|
spawned = true;
|
|
240
|
-
|
|
239
|
+
writeFileSync(pidPath, "4242");
|
|
240
|
+
return {
|
|
241
|
+
unref: () => {},
|
|
242
|
+
kill: () => {},
|
|
243
|
+
pid: 4242,
|
|
244
|
+
exited: neverExits(),
|
|
245
|
+
};
|
|
241
246
|
});
|
|
242
247
|
try {
|
|
243
|
-
const result = await spawnMemoryWorkerProcess({
|
|
244
|
-
|
|
245
|
-
|
|
248
|
+
const result = await spawnMemoryWorkerProcess({
|
|
249
|
+
pidWaitTimeoutMs: 1_000,
|
|
250
|
+
pidPollIntervalMs: 10,
|
|
251
|
+
});
|
|
252
|
+
expect(result).toEqual({ pid: 4242, alreadyRunning: false });
|
|
253
|
+
expect(spawned).toBe(true);
|
|
246
254
|
} finally {
|
|
247
255
|
restore();
|
|
248
256
|
}
|
|
@@ -250,6 +258,11 @@ describe("spawnMemoryWorkerProcess", () => {
|
|
|
250
258
|
});
|
|
251
259
|
|
|
252
260
|
describe("probeMemoryWorker", () => {
|
|
261
|
+
test("reports not_running when the PID file names a live process that is not this worker", () => {
|
|
262
|
+
writeFileSync(pidPath, String(process.pid));
|
|
263
|
+
expect(probeMemoryWorker()).toEqual({ status: "not_running" });
|
|
264
|
+
});
|
|
265
|
+
|
|
253
266
|
test("reports running (not throws) when the process exists but is not signalable (EPERM)", () => {
|
|
254
267
|
writeFileSync(pidPath, "4321");
|
|
255
268
|
const restore = stubProcessKill(new Set(), new Set([4321]));
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type RecallSource,
|
|
3
|
+
RecallSourceSchema,
|
|
4
|
+
} from "../../../../api/events/tool-result.js";
|
|
1
5
|
import { truncate } from "../host-utils.js";
|
|
2
|
-
import {
|
|
3
|
-
import type { RecallEvidence
|
|
6
|
+
import { normalizeRecallSources } from "./limits.js";
|
|
7
|
+
import type { RecallEvidence } from "./types.js";
|
|
4
8
|
|
|
5
9
|
export type RecallAgentConfidence = "high" | "medium" | "low";
|
|
6
10
|
|
|
@@ -76,7 +80,7 @@ export const SEARCH_SOURCES_TOOL_DEFINITION: RecallAgentToolDefinition = {
|
|
|
76
80
|
sources: {
|
|
77
81
|
type: "array",
|
|
78
82
|
description: "Optional subset of internal sources to search.",
|
|
79
|
-
items: { type: "string", enum: [...
|
|
83
|
+
items: { type: "string", enum: [...RecallSourceSchema.options] },
|
|
80
84
|
uniqueItems: true,
|
|
81
85
|
},
|
|
82
86
|
limit: {
|
|
@@ -176,9 +180,9 @@ export function buildRecallAgentPromptBundle(
|
|
|
176
180
|
): RecallAgentPromptBundle {
|
|
177
181
|
const availableSources = normalizeRecallSources(options.availableSources);
|
|
178
182
|
const maxSearchCalls = options.maxSearchCalls ?? DEFAULT_MAX_SEARCH_CALLS;
|
|
179
|
-
const evidence =
|
|
183
|
+
const evidence = truncateRecallEvidenceToBudget(
|
|
180
184
|
options.evidence,
|
|
181
|
-
options.evidenceBudgetChars,
|
|
185
|
+
options.evidenceBudgetChars ?? DEFAULT_RECALL_AGENT_EVIDENCE_BUDGET_CHARS,
|
|
182
186
|
);
|
|
183
187
|
const citationIds = evidence.map((item) => item.id);
|
|
184
188
|
|
|
@@ -216,13 +220,6 @@ export function buildRecallAgentPromptBundle(
|
|
|
216
220
|
return { prompt, evidence };
|
|
217
221
|
}
|
|
218
222
|
|
|
219
|
-
function prepareRecallAgentPromptEvidence(
|
|
220
|
-
evidence: readonly RecallEvidence[],
|
|
221
|
-
evidenceBudgetChars = DEFAULT_RECALL_AGENT_EVIDENCE_BUDGET_CHARS,
|
|
222
|
-
): RecallEvidence[] {
|
|
223
|
-
return truncateRecallEvidenceToBudget(evidence, evidenceBudgetChars);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
223
|
export function truncateRecallEvidenceToBudget(
|
|
227
224
|
evidence: readonly RecallEvidence[],
|
|
228
225
|
maxTextChars: number,
|