@vellumai/assistant 0.10.12 → 0.11.0-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/AGENTS.md +1 -1
- package/ARCHITECTURE.md +4 -5
- package/README.md +1 -1
- package/docs/architecture/memory.md +60 -23
- package/docs/error-handling.md +3 -3
- package/docs/guardian-request-flow.md +112 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/ces-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts +28 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/app.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts +2 -2
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/index.js.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts +2 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/dist/events/message.d.ts.map +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@slack/types/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/gateway-client/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/node_modules/@vellumai/gateway-client/package.json +1 -1
- package/node_modules/@vellumai/gateway-client/src/admission-policy-contract.ts +6 -0
- package/node_modules/@vellumai/gateway-client/src/inbound-contract.ts +34 -0
- package/node_modules/@vellumai/service-contracts/package.json +1 -0
- package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +9 -1
- package/node_modules/@vellumai/service-contracts/src/__tests__/secret-detection.test.ts +449 -0
- package/node_modules/@vellumai/service-contracts/src/channels.ts +1 -0
- package/node_modules/@vellumai/service-contracts/src/secret-detection.ts +468 -0
- package/openapi.yaml +264 -14
- package/package.json +2 -2
- package/src/__tests__/acp-session.test.ts +3 -3
- package/src/__tests__/agent-loop-mutable-latest-user-message.test.ts +3 -0
- package/src/__tests__/anthropic-provider.test.ts +40 -0
- package/src/__tests__/app-conversation-ids-backfill.test.ts +33 -2
- package/src/__tests__/app-conversation-ids.test.ts +204 -0
- package/src/__tests__/approval-cascade.test.ts +5 -5
- package/src/__tests__/approval-routes-http.test.ts +3 -3
- package/src/__tests__/ask-question-resolver.test.ts +207 -0
- package/src/__tests__/assistant-event-hub-self-exclusion.test.ts +16 -16
- package/src/__tests__/assistant-event-hub-targeted.test.ts +13 -11
- package/src/__tests__/assistant-event-hub.test.ts +13 -11
- package/src/__tests__/assistant-event.test.ts +12 -9
- package/src/__tests__/assistant-feature-flag-guard.test.ts +3 -3
- package/src/__tests__/assistant-feature-flag-guardrails.test.ts +1 -1
- package/src/__tests__/assistant-id-boundary-guard.test.ts +0 -58
- package/src/__tests__/assistant-stream-state.test.ts +17 -7
- package/src/__tests__/avatar-identity-sync.test.ts +3 -3
- package/src/__tests__/background-workers-disk-pressure.test.ts +1 -0
- package/src/__tests__/call-conversation-messages.test.ts +134 -18
- package/src/__tests__/call-start-guardian-guard.test.ts +27 -0
- package/src/__tests__/channel-approvals.test.ts +0 -27
- package/src/__tests__/channel-guardian.test.ts +85 -512
- package/src/__tests__/channel-readiness-slack-remote.test.ts +151 -3
- package/src/__tests__/channel-retry-sweep.test.ts +88 -1
- package/src/__tests__/channel-setup-panel-ack.test.ts +12 -9
- package/src/__tests__/chat-reveal-guard-priming.test.ts +31 -34
- package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +2 -2
- package/src/__tests__/compaction-events.test.ts +8 -8
- package/src/__tests__/config-loader-platform-defaults.test.ts +54 -28
- package/src/__tests__/config-model-image-provider.test.ts +20 -0
- package/src/__tests__/config-schema-memory-substrate.test.ts +306 -0
- package/src/__tests__/config-schema.test.ts +14 -2
- package/src/__tests__/config-set-platform-guard.test.ts +11 -12
- package/src/__tests__/config-sounds-sync.test.ts +4 -4
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +5 -0
- package/src/__tests__/context-search-memory-source.test.ts +1 -1
- package/src/__tests__/context-search-memory-v2-source.test.ts +6 -6
- package/src/__tests__/context-token-estimator.test.ts +54 -1
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +12 -3
- package/src/__tests__/conversation-agent-loop-fatal-cleanup.test.ts +13 -4
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +10 -1
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +22 -13
- package/src/__tests__/conversation-agent-loop.test.ts +39 -30
- package/src/__tests__/conversation-confirmation-signals.test.ts +14 -14
- package/src/__tests__/conversation-evictor.test.ts +49 -0
- package/src/__tests__/conversation-fork-crud.test.ts +1 -1
- package/src/__tests__/conversation-group-tools.test.ts +279 -0
- package/src/__tests__/conversation-history-web-search.test.ts +1 -1
- package/src/__tests__/conversation-key-store-disk-view.test.ts +5 -5
- package/src/__tests__/conversation-lineage.test.ts +235 -0
- package/src/__tests__/conversation-loop-db-lock-resilience.test.ts +5 -5
- package/src/__tests__/conversation-message-sync-tags.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +81 -81
- package/src/__tests__/conversation-routes-enabled-plugins.test.ts +8 -1
- package/src/__tests__/conversation-routes-hidden-queue.test.ts +8 -1
- package/src/__tests__/conversation-routes-slash-commands.test.ts +10 -1
- package/src/__tests__/conversation-runtime-assembly.test.ts +29 -2
- package/src/__tests__/conversation-slash-queue.test.ts +11 -11
- package/src/__tests__/conversation-slash-unknown.test.ts +2 -2
- package/src/__tests__/conversation-speed-override.test.ts +2 -2
- package/src/__tests__/conversation-summarize-route.test.ts +9 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +18 -16
- package/src/__tests__/conversation-surfaces-activation-emit.test.ts +17 -17
- package/src/__tests__/conversation-surfaces-app-open.test.ts +7 -4
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +7 -7
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +9 -9
- package/src/__tests__/conversation-surfaces-standalone.test.ts +12 -12
- package/src/__tests__/conversation-surfaces-state-update.test.ts +8 -5
- package/src/__tests__/conversation-surfaces-table-action.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-task-progress.test.ts +46 -46
- package/src/__tests__/conversation-sync-tags.test.ts +5 -5
- package/src/__tests__/conversation-wait-for-idle.test.ts +2 -2
- package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
- package/src/__tests__/conversation-workspace-injection.test.ts +0 -3
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -3
- package/src/__tests__/copy-composer-tc-templates.test.ts +3 -131
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/daemon-assistant-events.test.ts +14 -15
- package/src/__tests__/db-test-helpers.ts +13 -27
- package/src/__tests__/disk-pressure-routes.test.ts +12 -3
- package/src/__tests__/document-tool-security.test.ts +95 -0
- package/src/__tests__/drain-kick-guard.test.ts +232 -0
- package/src/__tests__/dynamic-skill-background-guard.test.ts +19 -6
- package/src/__tests__/emit-event-signal.test.ts +5 -6
- package/src/__tests__/encrypted-store-test-helpers.ts +10 -20
- package/src/__tests__/events-tail-route.test.ts +6 -4
- package/src/__tests__/feature-flag-test-helpers.ts +10 -20
- package/src/__tests__/file-edit-tool.test.ts +24 -4
- package/src/__tests__/file-list-tool.test.ts +2 -1
- package/src/__tests__/file-read-tool.test.ts +62 -10
- package/src/__tests__/file-write-tool.test.ts +24 -5
- package/src/__tests__/followup-tools.test.ts +58 -0
- package/src/__tests__/gateway-threshold-reader-mock.ts +99 -0
- package/src/__tests__/graph-extraction-event-date.test.ts +1 -1
- package/src/__tests__/guardian-question-mode.test.ts +42 -3
- package/src/__tests__/guardian-reply-router-answer-mode.test.ts +283 -0
- package/src/__tests__/guardian-vellum-destination-pinning.test.ts +221 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/native-web-search-harness.ts +10 -10
- package/src/__tests__/host-browser-proxy.test.ts +1 -1
- package/src/__tests__/host-file-edit-tool.test.ts +3 -3
- package/src/__tests__/host-file-read-tool.test.ts +2 -2
- package/src/__tests__/host-file-write-tool.test.ts +7 -3
- package/src/__tests__/host-shell-tool.test.ts +17 -5
- package/src/__tests__/host-transfer-pending-interactions.test.ts +8 -8
- package/src/__tests__/image-credentials.test.ts +65 -8
- package/src/__tests__/injection-block.test.ts +4 -4
- package/src/__tests__/injector-chain.test.ts +1 -1
- package/src/__tests__/injector-pkb-v2-silenced.test.ts +2 -2
- package/src/__tests__/injector-registry-order-guard.test.ts +4 -9
- package/src/__tests__/injector-v3-suppression.test.ts +6 -4
- package/src/__tests__/lifecycle-memory-v2-seed.test.ts +27 -28
- package/src/__tests__/list-messages-page-latest.test.ts +2 -2
- package/src/__tests__/llm-usage-store.test.ts +67 -4
- package/src/__tests__/log-redact.test.ts +18 -0
- package/src/__tests__/managed-profile-guard.test.ts +27 -0
- package/src/__tests__/managed-skill-lifecycle.test.ts +2 -2
- package/src/__tests__/media-generate-image.test.ts +62 -11
- package/src/__tests__/memory-identity-context-parity.test.ts +1 -1
- package/src/__tests__/memory-jobs-worker-lanes.test.ts +9 -1
- package/src/__tests__/memory-retrieval-hook.test.ts +4 -4
- package/src/__tests__/notification-decision-strategy.test.ts +115 -11
- package/src/__tests__/notification-deep-link.test.ts +12 -12
- package/src/__tests__/notification-vellum-adapter.test.ts +8 -8
- package/src/__tests__/outbound-slack-persistence.test.ts +8 -8
- package/src/__tests__/path-policy.test.ts +315 -0
- package/src/__tests__/pending-interactions-resolved-event.test.ts +6 -6
- package/src/__tests__/persistence-layering-guard.test.ts +2 -2
- package/src/__tests__/pkb-autoinject.test.ts +1 -1
- package/src/__tests__/platform-bash-auto-approve.test.ts +1 -0
- package/src/__tests__/platform-callback-registration.test.ts +10 -10
- package/src/__tests__/plugin-event-hub-facade.test.ts +22 -15
- package/src/__tests__/plugin-import-boundary-guard.test.ts +15 -15
- package/src/__tests__/processing-flag-persist-failure.test.ts +0 -4
- package/src/__tests__/provider-platform-proxy-integration.test.ts +0 -1
- package/src/__tests__/rebuild-index-graph-nodes.test.ts +1 -1
- package/src/__tests__/request-secret-standalone-channel-gate.test.ts +5 -5
- package/src/__tests__/require-fresh-approval.test.ts +38 -38
- package/src/__tests__/resolve-app-id.test.ts +32 -0
- package/src/__tests__/run-due-schedules.test.ts +72 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +11 -10
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/schedule-routes.test.ts +44 -5
- package/src/__tests__/schedule-store.test.ts +3 -3
- package/src/__tests__/schedule-tools.test.ts +176 -0
- package/src/__tests__/secret-prompt-log-hygiene.test.ts +3 -3
- package/src/__tests__/secret-prompter-channel-fallback.test.ts +3 -3
- package/src/__tests__/secret-response-routing.test.ts +3 -3
- package/src/__tests__/secret-routes-platform-proxy.test.ts +4 -7
- package/src/__tests__/secret-scanner.test.ts +36 -0
- package/src/__tests__/send-endpoint-busy.test.ts +7 -7
- package/src/__tests__/slack-required-scopes-mirror.test.ts +81 -0
- package/src/__tests__/starter-task-flow.test.ts +26 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +2 -2
- package/src/__tests__/subagent-disposal.test.ts +40 -11
- package/src/__tests__/subagent-fork-notifications.test.ts +4 -4
- package/src/__tests__/subagent-fork-prompt-role.test.ts +3 -3
- package/src/__tests__/subagent-fork-spawn.test.ts +4 -4
- package/src/__tests__/subagent-manager-notify.test.ts +73 -14
- package/src/__tests__/subagent-notify-parent.test.ts +48 -4
- package/src/__tests__/subagent-spawn-and-await.test.ts +62 -14
- package/src/__tests__/subagent-tools.test.ts +64 -0
- package/src/__tests__/sync-message-contract.test.ts +3 -3
- package/src/__tests__/terminal-tools.test.ts +12 -3
- package/src/__tests__/test-preload.ts +9 -0
- package/src/__tests__/tool-approval-handler.test.ts +587 -43
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +7 -4
- package/src/__tests__/tool-executor.test.ts +116 -0
- package/src/__tests__/tool-grant-request-escalation.test.ts +5 -0
- package/src/__tests__/tool-preview-lifecycle.test.ts +32 -29
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +5 -5
- package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
- package/src/__tests__/tool-start-timestamp.test.ts +4 -4
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +9 -22
- package/src/__tests__/ui-choice-copy-surfaces.test.ts +13 -13
- package/src/__tests__/ui-work-result-surface.test.ts +3 -3
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +6 -6
- package/src/__tests__/voice-session-bridge.test.ts +44 -44
- package/src/__tests__/workspace-migration-134-image-generation-mode-to-provider.test.ts +284 -0
- package/src/__tests__/workspace-policy.test.ts +482 -2
- package/src/acp/__tests__/client-handler.test.ts +3 -3
- package/src/acp/__tests__/session-manager-persistence.test.ts +10 -10
- package/src/acp/__tests__/session-manager-resume.test.ts +7 -7
- package/src/acp/client-handler.ts +3 -3
- package/src/acp/session-manager.ts +8 -8
- package/src/api/events/subagent-event.ts +2 -2
- package/src/api/responses/memory-v2-activation-log.ts +2 -2
- package/src/api/responses/subagent-detail.ts +13 -0
- package/src/approvals/AGENTS.md +2 -0
- package/src/approvals/guardian-request-resolvers.ts +118 -24
- package/src/apps/app-store.ts +95 -4
- package/src/calls/__tests__/voice-control-protocol.test.ts +57 -0
- package/src/calls/__tests__/voice-session-bridge.test.ts +229 -7
- package/src/calls/__tests__/voice-triage-escalate.test.ts +3 -4
- package/src/calls/call-controller.ts +27 -27
- package/src/calls/call-conversation-messages.ts +58 -18
- package/src/calls/voice-control-protocol.ts +56 -0
- package/src/calls/voice-session-bridge.ts +178 -65
- package/src/calls/voice-triage-escalate.ts +2 -3
- package/src/channels/config.ts +8 -0
- package/src/channels/types.ts +1 -0
- package/src/cli/commands/config.ts +49 -13
- package/src/cli/commands/memory/index.help.ts +4 -2
- package/src/cli/commands/memory/memory-retrospective.ts +5 -0
- package/src/cli/commands/webhooks.help.ts +9 -4
- package/src/cli/lib/bundled-marketplace.json +12 -0
- package/src/cli.ts +2 -109
- package/src/config/__tests__/deployment-context-defaults.test.ts +9 -0
- package/src/config/__tests__/substrate-twin-shadowing.test.ts +191 -0
- package/src/config/assistant-feature-flags.ts +1 -1
- package/src/config/bundled-skills/conversation-groups/SKILL.md +29 -0
- package/src/config/bundled-skills/conversation-groups/TOOLS.json +58 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-create.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/group-list.ts +12 -0
- package/src/config/bundled-skills/conversation-groups/tools/move-to-group.ts +12 -0
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +13 -7
- package/src/config/bundled-skills/schedule/SKILL.md +2 -0
- package/src/config/feature-flag-cache.ts +6 -16
- package/src/config/feature-flag-registry.json +14 -38
- package/src/config/loader.ts +7 -1
- package/src/config/memory-tier.ts +15 -10
- package/src/config/memory-v3-gate.test.ts +278 -1
- package/src/config/memory-v3-gate.ts +88 -26
- package/src/config/raw-config-utils.ts +1 -1
- package/src/config/schemas/__tests__/live-voice.test.ts +27 -16
- package/src/config/schemas/__tests__/memory-v3.test.ts +1 -0
- package/src/config/schemas/live-voice.ts +33 -7
- package/src/config/schemas/llm.ts +1 -0
- package/src/config/schemas/memory-retrospective.ts +13 -0
- package/src/config/schemas/memory-substrate.ts +183 -0
- package/src/config/schemas/memory-v2.ts +3 -2
- package/src/config/schemas/memory-v3.ts +11 -4
- package/src/config/schemas/memory.ts +35 -1
- package/src/config/schemas/services.ts +10 -2
- package/src/config/substrate-twin-shadowing.ts +195 -0
- package/src/config/webhook-routing.ts +67 -0
- package/src/context/compactor.ts +10 -3
- package/src/context/token-estimator.ts +21 -0
- package/src/daemon/__tests__/channel-ui-capability.test.ts +85 -0
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +3 -3
- package/src/daemon/__tests__/embedding-reconcile.test.ts +3 -3
- package/src/daemon/__tests__/inference-profile-notification.test.ts +3 -6
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +5 -5
- package/src/daemon/__tests__/web-search-status-text.test.ts +2 -2
- package/src/daemon/channel-ui-capability.ts +70 -1
- package/src/daemon/conversation-agent-loop-handlers.ts +4 -4
- package/src/daemon/conversation-agent-loop.ts +12 -5
- package/src/daemon/conversation-evictor.ts +26 -4
- package/src/daemon/conversation-launch.ts +11 -14
- package/src/daemon/conversation-lineage.ts +76 -0
- package/src/daemon/conversation-messaging.ts +14 -14
- package/src/daemon/conversation-notifiers.ts +2 -2
- package/src/daemon/conversation-process.ts +133 -21
- package/src/daemon/conversation-queue-manager.ts +7 -7
- package/src/daemon/conversation-runtime-assembly.ts +16 -0
- package/src/daemon/conversation-store.ts +11 -3
- package/src/daemon/conversation-surfaces.ts +8 -14
- package/src/daemon/conversation-tool-setup.ts +13 -7
- package/src/daemon/conversation-usage.ts +12 -11
- package/src/daemon/conversation.ts +38 -15
- package/src/daemon/disk-pressure-guard.ts +5 -12
- package/src/daemon/embedding-reconcile.ts +14 -9
- package/src/daemon/handlers/config-channels.ts +40 -134
- package/src/daemon/handlers/config-model.ts +15 -7
- package/src/daemon/handlers/conversations.ts +4 -2
- package/src/daemon/handlers/shared.ts +29 -0
- package/src/daemon/host-proxy-base.ts +4 -4
- package/src/daemon/lifecycle.ts +13 -0
- package/src/daemon/message-protocol.ts +8 -144
- package/src/daemon/message-types/computer-use.ts +0 -12
- package/src/daemon/message-types/conversations.ts +9 -345
- package/src/daemon/message-types/host-app-control.ts +0 -9
- package/src/daemon/message-types/host-browser.ts +0 -7
- package/src/daemon/message-types/host-ui-snapshot.ts +0 -7
- package/src/daemon/message-types/messages.ts +0 -48
- package/src/daemon/message-types/notifications.ts +0 -7
- package/src/daemon/message-types/skills.ts +0 -5
- package/src/daemon/message-types/surfaces.ts +0 -9
- package/src/daemon/message-types/sync.ts +0 -2
- package/src/daemon/process-message.ts +5 -5
- package/src/daemon/skill-memory-refresh.ts +5 -5
- package/src/daemon/tool-side-effects.ts +32 -16
- package/src/daemon/trust-context.ts +1 -1
- package/src/daemon/wake-conversation-ops.ts +4 -4
- package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +100 -7
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +67 -0
- package/src/heartbeat/heartbeat-run-store.ts +81 -4
- package/src/heartbeat/heartbeat-service.ts +32 -1
- package/src/home/__tests__/feed-writer.test.ts +7 -7
- package/src/home/__tests__/home-content-refresh.test.ts +3 -0
- package/src/home/__tests__/suggested-prompts.test.ts +1 -0
- package/src/home/feed-writer.ts +6 -13
- package/src/home/home-content-refresh.ts +6 -9
- package/src/home/relationship-state-writer.ts +5 -12
- package/src/home/suggested-prompts-cache.ts +6 -19
- package/src/ipc/__tests__/events-publish-client.test.ts +67 -0
- package/src/ipc/events-publish-client.ts +44 -0
- package/src/ipc/routes/__tests__/conversation-sync-ipc-routes.test.ts +2 -2
- package/src/ipc/routes/__tests__/events-ipc-routes.test.ts +38 -9
- package/src/ipc/routes/events-ipc-routes.ts +11 -31
- package/src/live-voice/__tests__/front-decision.test.ts +4 -176
- package/src/live-voice/__tests__/live-voice-agent-turn.test.ts +276 -68
- package/src/live-voice/__tests__/live-voice-continuation-fork-hydration.test.ts +286 -0
- package/src/live-voice/__tests__/live-voice-events.test.ts +6 -3
- package/src/live-voice/__tests__/live-voice-progress.test.ts +185 -46
- package/src/live-voice/__tests__/live-voice-triage-escalate.test.ts +24 -59
- package/src/live-voice/__tests__/live-voice-tts-session.test.ts +38 -54
- package/src/live-voice/__tests__/live-voice-vad.test.ts +1154 -636
- package/src/live-voice/front-decision.ts +5 -155
- package/src/live-voice/live-voice-metrics.ts +4 -1
- package/src/live-voice/live-voice-session.ts +1288 -439
- package/src/live-voice/progress-phrases.ts +17 -0
- package/src/live-voice/protocol.ts +15 -0
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +9 -5
- package/src/media/image-credentials.ts +42 -10
- package/src/media/image-service.ts +1 -13
- package/src/media/types.ts +26 -3
- package/src/notifications/AGENTS.md +2 -0
- package/src/notifications/__tests__/broadcaster.test.ts +95 -0
- package/src/notifications/adapters/macos.ts +3 -3
- package/src/notifications/broadcaster.ts +57 -0
- package/src/notifications/copy-composer.ts +0 -15
- package/src/notifications/decision-engine.ts +21 -22
- package/src/notifications/guardian-question-mode.ts +57 -2
- package/src/notifications/home-feed-side-effect.ts +4 -0
- package/src/notifications/signal.ts +6 -4
- package/src/notifications/trusted-contact-payloads.ts +3 -4
- package/src/notifications/vellum-card-affinity.ts +39 -0
- package/src/oauth/AGENTS.md +1 -1
- package/src/permissions/channel-permission-query.test.ts +69 -0
- package/src/permissions/channel-permission-query.ts +73 -1
- package/src/permissions/checker.test.ts +298 -15
- package/src/permissions/checker.ts +102 -36
- package/src/permissions/confirmation-guardian-request.test.ts +2 -2
- package/src/permissions/confirmation-guardian-request.ts +2 -2
- package/src/permissions/gateway-threshold-reader.test.ts +224 -17
- package/src/permissions/gateway-threshold-reader.ts +82 -10
- package/src/permissions/ipc-risk-types.ts +8 -0
- package/src/permissions/prompter.ts +5 -5
- package/src/permissions/question-guardian-request.test.ts +222 -0
- package/src/permissions/question-guardian-request.ts +179 -0
- package/src/permissions/question-prompter.test.ts +8 -8
- package/src/permissions/question-prompter.ts +18 -0
- package/src/permissions/secret-prompter.ts +2 -4
- package/src/permissions/workspace-policy.ts +269 -34
- package/src/persistence/__tests__/lifecycle-quiesce.test.ts +82 -0
- package/src/persistence/__tests__/message-content-file.test.ts +58 -3
- package/src/persistence/conversation-crud.ts +93 -0
- package/src/persistence/conversation-key-store.ts +63 -0
- package/src/persistence/conversation-parent.ts +27 -0
- package/src/persistence/db-async-query.ts +1 -1
- package/src/persistence/db-singleton.ts +14 -27
- package/src/persistence/delivery-crud.ts +45 -0
- package/src/persistence/embeddings/embedding-backend.ts +2 -1
- package/src/persistence/embeddings/embedding-identity.ts +7 -3
- package/src/persistence/job-utils.ts +32 -27
- package/src/persistence/jobs-store.ts +92 -3
- package/src/persistence/lifecycle-quiesce.ts +80 -0
- package/src/persistence/llm-usage-store.ts +45 -8
- package/src/persistence/message-content-file.ts +4 -4
- package/src/persistence/migrations/336-move-memory-v2-activation-logs-to-memory-db.ts +1 -1
- package/src/persistence/migrations/351-schedule-skill-script-handoff.ts +39 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.test.ts +83 -0
- package/src/persistence/migrations/352-drop-schedule-skill-script-handoff.ts +36 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.test.ts +110 -0
- package/src/persistence/migrations/353-add-llm-usage-conversation-type.ts +49 -0
- package/src/persistence/migrations/354-backfill-app-conversation-lineage.ts +41 -0
- package/src/persistence/schema/infrastructure.ts +11 -0
- package/src/persistence/steps.ts +9 -1
- package/src/plugin-api/__tests__/publish-event-forwarding.test.ts +113 -0
- package/src/plugin-api/__tests__/publish-event.test.ts +57 -0
- package/src/plugin-api/conversation-turn.ts +4 -4
- package/src/plugin-api/event-hub-facade.ts +15 -6
- package/src/plugin-api/index.ts +10 -4
- package/src/plugin-api/publish-event.ts +36 -0
- package/src/plugins/AGENTS.md +2 -0
- package/src/plugins/defaults/compaction/window-manager.ts +9 -0
- package/src/plugins/defaults/index.ts +9 -13
- package/src/plugins/defaults/memory/AGENTS.md +775 -0
- package/src/plugins/defaults/memory/__tests__/capability-seed-embed-gate.test.ts +186 -0
- package/src/plugins/defaults/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/indexer-tier-dispatch.test.ts +129 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-quiesce-gate.test.ts +91 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v1-graph-substrate-noop.test.ts +342 -0
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-schedule.test.ts +36 -1
- package/src/plugins/defaults/memory/__tests__/jobs-worker-v2-sweep-defer.test.ts +9 -1
- package/src/plugins/defaults/memory/__tests__/memory-log-stores-degraded.test.ts +2 -2
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-job.test.ts +44 -10
- package/src/plugins/defaults/memory/__tests__/memory-retrospective-sweep.test.ts +151 -10
- package/src/plugins/defaults/memory/__tests__/memory-tier-boundary-guard.test.ts +1155 -0
- package/src/plugins/defaults/memory/__tests__/memory-v2-activation-log-store.test.ts +1 -1
- package/src/plugins/defaults/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -3
- package/src/plugins/defaults/memory/__tests__/tools-delete-memory-page.test.ts +1 -1
- package/src/plugins/defaults/memory/context-search/sources/memory-v2.ts +71 -35
- package/src/plugins/defaults/memory/context-search/sources/memory.ts +5 -1
- package/src/plugins/defaults/memory/fork-conversation-memory.ts +4 -4
- package/src/plugins/defaults/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +80 -10
- package/src/plugins/defaults/memory/graph/__tests__/handle-remember-v2.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/capability-seed.ts +24 -10
- package/src/plugins/defaults/memory/graph/conversation-graph-memory.ts +123 -49
- package/src/plugins/defaults/memory/graph/graph-search.ts +6 -118
- package/src/plugins/defaults/memory/graph/in-context-tracker.test.ts +173 -0
- package/src/plugins/defaults/memory/graph/in-context-tracker.ts +109 -0
- package/src/plugins/defaults/memory/graph/store.ts +1 -0
- package/src/plugins/defaults/memory/graph/tool-handlers.test.ts +1 -1
- package/src/plugins/defaults/memory/graph/tool-handlers.ts +5 -2
- package/src/plugins/defaults/memory/graph-topology/__tests__/build-memory-graph.test.ts +1 -1
- package/src/plugins/defaults/memory/graph-topology/build-memory-graph.ts +6 -9
- package/src/plugins/defaults/memory/hooks/__tests__/user-prompt-submit.test.ts +30 -16
- package/src/plugins/defaults/memory/hooks/user-prompt-submit.ts +18 -14
- package/src/plugins/defaults/memory/indexer.ts +146 -89
- package/src/plugins/defaults/memory/injectors.ts +86 -41
- package/src/plugins/defaults/memory/job-handlers.ts +130 -39
- package/src/plugins/defaults/memory/jobs/__tests__/embed-concept-page.test.ts +2 -2
- package/src/plugins/defaults/memory/jobs/embed-concept-page.ts +22 -10
- package/src/plugins/defaults/memory/jobs-worker.ts +279 -208
- package/src/plugins/defaults/memory/memory-retrospective-enqueue.ts +4 -2
- package/src/plugins/defaults/memory/memory-retrospective-job.ts +40 -3
- package/src/plugins/defaults/memory/memory-retrospective-sweep.ts +99 -11
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-routes.test.ts +5 -3
- package/src/plugins/defaults/memory/src/__tests__/memory-v2-simulate-route.test.ts +3 -4
- package/src/plugins/defaults/memory/src/memory-graph-routes.ts +2 -1
- package/src/plugins/defaults/memory/src/memory-item-routes.test.ts +7 -5
- package/src/plugins/defaults/memory/src/memory-item-routes.ts +51 -19
- package/src/plugins/defaults/memory/src/memory-v2-routes.ts +31 -20
- package/src/plugins/defaults/memory/startup.ts +58 -21
- package/src/plugins/defaults/memory/substrate/__tests__/boot-maintenance.test.ts +335 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/cli-command-store.test.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-job.test.ts +51 -21
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/edge-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/frontmatter-sweep.test.ts +3 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-index.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/page-store.test.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/prompts-consolidation.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/qdrant.test.ts +23 -14
- package/src/plugins/defaults/memory/substrate/__tests__/reembed-job.test.ts +262 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sim.test.ts +9 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-content.test.ts +2 -2
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/skill-store.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sparse-bm25.test.ts +12 -5
- package/src/plugins/defaults/memory/substrate/__tests__/spread.test.ts +276 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/static-context.test.ts +17 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/sweep-job.test.ts +9 -9
- package/src/plugins/defaults/memory/{v3/substrate/memory-v2-startup.ts → substrate/boot-maintenance.ts} +43 -24
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/consolidation-job.ts +51 -27
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/constants.ts +1 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/edge-index.ts +28 -9
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/frontmatter-sweep.ts +14 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/injected-block-slugs.ts +9 -3
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-index.ts +29 -10
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/page-store.ts +35 -12
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/consolidation.ts +14 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/prompts/sweep.ts +4 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/qdrant.ts +96 -36
- package/src/plugins/defaults/memory/substrate/reembed-job.ts +54 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sim.ts +26 -15
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-content.ts +1 -1
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/skill-store.ts +13 -8
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sparse-bm25.ts +27 -10
- package/src/plugins/defaults/memory/substrate/spread.ts +165 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/static-context.ts +12 -7
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/sweep-job.ts +20 -15
- package/src/plugins/defaults/memory/substrate/tuning.ts +93 -0
- package/src/plugins/defaults/memory/{v3/substrate → substrate}/types.ts +7 -4
- package/src/plugins/defaults/memory/tools.test.ts +1 -1
- package/src/plugins/defaults/memory/tools.ts +1 -1
- package/src/plugins/defaults/memory/v1/README.md +5 -0
- package/src/plugins/defaults/memory/{__tests__ → v1/__tests__}/filing-jobs.test.ts +4 -4
- package/src/plugins/defaults/memory/{filing-jobs.ts → v1/filing-jobs.ts} +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.test.ts +68 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/bootstrap.ts +40 -21
- package/src/plugins/defaults/memory/{graph → v1/graph}/consolidation.ts +14 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/decay.ts +3 -3
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction-job.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/extraction.ts +20 -14
- package/src/plugins/defaults/memory/{graph → v1/graph}/graph-search.test.ts +3 -3
- package/src/plugins/defaults/memory/v1/graph/graph-search.ts +123 -0
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.test.ts +1 -118
- package/src/plugins/defaults/memory/{graph → v1/graph}/injection.ts +9 -111
- package/src/plugins/defaults/memory/{graph → v1/graph}/narrative.ts +6 -6
- package/src/plugins/defaults/memory/{graph → v1/graph}/pattern-scan.ts +5 -5
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.test.ts +135 -42
- package/src/plugins/defaults/memory/{graph → v1/graph}/retriever.ts +40 -22
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/scoring.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/serendipity.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.test.ts +1 -1
- package/src/plugins/defaults/memory/{graph → v1/graph}/triggers.ts +1 -1
- package/src/plugins/defaults/memory/{identity-context.ts → v1/identity-context.ts} +4 -4
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/backfill.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.test.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/embedding.ts +6 -6
- package/src/plugins/defaults/memory/{job-handlers → v1/job-handlers}/index-maintenance.ts +8 -8
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.test.ts +7 -7
- package/src/plugins/defaults/memory/{jobs → v1/jobs}/embed-pkb-file.ts +5 -5
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/autoinject.ts +1 -1
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/context.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-index.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-reconcile.ts +2 -2
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.test.ts +3 -3
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/pkb-search.ts +6 -6
- package/src/plugins/defaults/memory/{pkb → v1/pkb}/types.ts +3 -5
- package/src/plugins/defaults/memory/{pkb-schedule.ts → v1/pkb-schedule.ts} +2 -2
- package/src/plugins/defaults/memory/{search/semantic.ts → v1/semantic-search.ts} +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation-store.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/activation.test.ts +11 -274
- package/src/plugins/defaults/memory/v2/__tests__/backfill-jobs.test.ts +9 -131
- package/src/plugins/defaults/memory/v2/__tests__/harness-compare.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-oracle.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/harness-replay-input.test.ts +1 -1
- package/src/plugins/defaults/memory/v2/__tests__/injection.test.ts +14 -10
- package/src/plugins/defaults/memory/v2/__tests__/reranker.test.ts +7 -5
- package/src/plugins/defaults/memory/v2/__tests__/router.test.ts +12 -6
- package/src/plugins/defaults/memory/{memory-v2-activation-log-store.ts → v2/activation-log-store.ts} +2 -2
- package/src/plugins/defaults/memory/v2/activation-store.ts +22 -8
- package/src/plugins/defaults/memory/v2/activation.ts +30 -163
- package/src/plugins/defaults/memory/v2/backfill-jobs.ts +7 -54
- package/src/plugins/defaults/memory/{memory-v2-concept-frequency.ts → v2/concept-frequency.ts} +3 -3
- package/src/plugins/defaults/memory/v2/harness/oracle.ts +1 -1
- package/src/plugins/defaults/memory/v2/harness/replay-input.ts +2 -2
- package/src/plugins/defaults/memory/v2/harness/retriever.ts +1 -1
- package/src/plugins/defaults/memory/v2/injection.ts +36 -26
- package/src/plugins/defaults/memory/v2/migration.ts +2 -2
- package/src/plugins/defaults/memory/{rerank-local.ts → v2/rerank-local.ts} +44 -18
- package/src/plugins/defaults/memory/v2/reranker.ts +29 -11
- package/src/plugins/defaults/memory/v2/router.ts +38 -15
- package/src/plugins/defaults/memory/v3/__tests__/candidate-match.test.ts +5 -3
- package/src/plugins/defaults/memory/v3/__tests__/carry-integration.test.ts +21 -8
- package/src/plugins/defaults/memory/v3/__tests__/edge.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/live-integration.test.ts +1 -1
- package/src/plugins/defaults/memory/v3/__tests__/maintain-job.test.ts +4 -1
- package/src/plugins/defaults/memory/v3/__tests__/orchestrate.test.ts +181 -3
- package/src/plugins/defaults/memory/v3/__tests__/selection-log-store.test.ts +3 -0
- package/src/plugins/defaults/memory/v3/__tests__/shadow-integration.test.ts +14 -5
- package/src/plugins/defaults/memory/v3/__tests__/shadow-plugin.test.ts +40 -50
- package/src/plugins/defaults/memory/v3/__tests__/tuning-profile.test.ts +1 -0
- package/src/plugins/defaults/memory/v3/candidate-match.ts +2 -2
- package/src/plugins/defaults/memory/v3/capabilities.ts +6 -4
- package/src/plugins/defaults/memory/v3/card.ts +25 -9
- package/src/plugins/defaults/memory/v3/edge.ts +52 -18
- package/src/plugins/defaults/memory/v3/gate.ts +4 -4
- package/src/plugins/defaults/memory/v3/injector.ts +10 -3
- package/src/plugins/defaults/memory/v3/maintain-job.ts +3 -3
- package/src/plugins/defaults/memory/v3/orchestrate.ts +100 -18
- package/src/plugins/defaults/memory/v3/page-content.ts +26 -10
- package/src/plugins/defaults/memory/v3/prune.ts +40 -16
- package/src/plugins/defaults/memory/v3/selection-log-store.ts +34 -12
- package/src/plugins/defaults/memory/v3/shadow-plugin.ts +9 -13
- package/src/plugins/defaults/memory/v3/span-query.test.ts +86 -0
- package/src/plugins/defaults/memory/v3/span-query.ts +71 -0
- package/src/plugins/defaults/memory/v3/tuning-profile.ts +3 -0
- package/src/plugins/defaults/memory/v3/types.ts +4 -1
- package/src/plugins/defaults/memory/v3-eval/eval-packets.ts +2 -2
- package/src/plugins/defaults/memory/validation.ts +1 -1
- package/src/plugins/defaults/memory/worker.ts +2 -1
- package/src/plugins/defaults/platform-hosted/__tests__/reengage.test.ts +104 -12
- package/src/plugins/defaults/platform-hosted/routes/reengage.ts +104 -12
- package/src/plugins/types.ts +2 -2
- package/src/prompts/sections.ts +4 -16
- package/src/providers/__tests__/registry-native-web-search.test.ts +47 -2
- package/src/providers/anthropic/client.ts +15 -6
- package/src/providers/content-block-schema.ts +26 -0
- package/src/providers/inference/__tests__/connections-credential-normalize.test.ts +87 -0
- package/src/providers/inference/adapter-factory.ts +6 -0
- package/src/providers/inference/connections.ts +30 -14
- package/src/providers/model-catalog.ts +77 -0
- package/src/providers/openai/__tests__/chat-completions-input-audio.test.ts +260 -0
- package/src/providers/openai/chat-completions-provider.ts +65 -17
- package/src/providers/openai/input-audio.ts +76 -0
- package/src/providers/openrouter/client.ts +0 -2
- package/src/providers/platform-proxy/constants.ts +4 -0
- package/src/providers/poolside/client.ts +42 -0
- package/src/providers/registry.ts +40 -8
- package/src/providers/retry.ts +2 -0
- package/src/providers/types.ts +39 -1
- package/src/providers/vercel-ai-gateway/client.ts +0 -2
- package/src/runtime/AGENTS.md +7 -5
- package/src/runtime/__tests__/question-request-guardian-bridge.test.ts +173 -0
- package/src/runtime/__tests__/question-resolution.test.ts +111 -0
- package/src/runtime/access-request-helper.ts +7 -15
- package/src/runtime/assistant-event-hub.ts +43 -31
- package/src/runtime/assistant-event-publish-options.ts +31 -0
- package/src/runtime/assistant-event.ts +19 -30
- package/src/runtime/assistant-stream-state.ts +4 -4
- package/src/runtime/channel-approvals.ts +0 -25
- package/src/runtime/channel-readiness-service.ts +99 -40
- package/src/runtime/channel-retry-sweep.ts +38 -15
- package/src/runtime/confirmation-request-guardian-bridge.ts +4 -0
- package/src/runtime/guardian-reply-router.ts +108 -0
- package/src/runtime/http-server.ts +8 -0
- package/src/runtime/http-types.ts +2 -2
- package/src/runtime/process-role.ts +42 -0
- package/src/runtime/question-request-guardian-bridge.ts +184 -0
- package/src/runtime/question-resolution.ts +153 -0
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +6 -2
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/subagents-routes.test.ts +250 -0
- package/src/runtime/routes/__tests__/webhook-routes.test.ts +201 -0
- package/src/runtime/routes/acp-routes.ts +2 -2
- package/src/runtime/routes/bookmark-routes.ts +3 -15
- package/src/runtime/routes/canned-message-complete.ts +2 -2
- package/src/runtime/routes/consolidation-routes.ts +8 -2
- package/src/runtime/routes/conversation-list-routes.ts +3 -19
- package/src/runtime/routes/conversation-management-routes.ts +1 -5
- package/src/runtime/routes/conversation-query-routes.ts +52 -8
- package/src/runtime/routes/conversation-routes.ts +36 -22
- package/src/runtime/routes/credential-request-routes.ts +0 -1
- package/src/runtime/routes/filing-routes.ts +7 -7
- package/src/runtime/routes/global-search-routes.ts +1 -1
- package/src/runtime/routes/guardian-approval-prompt.ts +2 -2
- package/src/runtime/routes/image-generation-routes.ts +12 -9
- package/src/runtime/routes/inbound-message-handler.ts +17 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +50 -0
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +19 -0
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -4
- package/src/runtime/routes/inbound-stages/inbound-content-prep.test.ts +129 -0
- package/src/runtime/routes/inbound-stages/inbound-content-prep.ts +141 -9
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/lifecycle-routes.ts +199 -0
- package/src/runtime/routes/platform-routes.ts +3 -8
- package/src/runtime/routes/playground/__tests__/inject-failures.test.ts +7 -7
- package/src/runtime/routes/playground/__tests__/reset-circuit.test.ts +5 -5
- package/src/runtime/routes/question-routes.ts +34 -87
- package/src/runtime/routes/secret-routes.ts +11 -1
- package/src/runtime/routes/settings-routes.ts +8 -18
- package/src/runtime/routes/subagents-routes.ts +35 -8
- package/src/runtime/routes/upgrade-broadcast-routes.ts +4 -5
- package/src/runtime/routes/webhook-routes.ts +89 -30
- package/src/runtime/routes/workspace-routes.test.ts +7 -4
- package/src/runtime/slack-reply-session.test.ts +12 -12
- package/src/runtime/slack-reply-session.ts +17 -17
- package/src/runtime/sync/sync-publisher.test.ts +7 -5
- package/src/runtime/tool-grant-request-helper.ts +4 -0
- package/src/schedule/schedule-store.ts +70 -0
- package/src/schedule/scheduler.ts +27 -0
- package/src/security/AGENTS.md +1 -1
- package/src/security/credential-key.ts +17 -0
- package/src/security/secret-ingress.ts +14 -105
- package/src/security/secret-patterns.ts +8 -139
- package/src/security/secret-scanner.ts +8 -3
- package/src/security/store-path-override.ts +6 -16
- package/src/sequence/store.ts +8 -0
- package/src/signals/emit-event.ts +5 -10
- package/src/signals/event-stream.ts +20 -10
- package/src/subagent/manager.ts +76 -25
- package/src/subagent/notify.ts +8 -0
- package/src/subagent/types.ts +13 -3
- package/src/telegram/__tests__/webhook-health.test.ts +442 -0
- package/src/telegram/webhook-health.ts +478 -0
- package/src/telemetry/AGENTS.md +6 -0
- package/src/telemetry/memory-corpus-size.test.ts +129 -0
- package/src/telemetry/memory-corpus-size.ts +184 -0
- package/src/telemetry/memory-tier-reporter.test.ts +67 -2
- package/src/telemetry/memory-tier-reporter.ts +30 -3
- package/src/tools/__tests__/conversation-group-tool-input-schemas.test.ts +61 -0
- package/src/tools/__tests__/document-tool-input-schemas.test.ts +103 -0
- package/src/tools/__tests__/followup-call-acp-tool-input-schemas.test.ts +125 -0
- package/src/tools/__tests__/schedule-tool-input-schemas.test.ts +83 -0
- package/src/tools/__tests__/subagent-workflow-tool-input-schemas.test.ts +116 -0
- package/src/tools/__tests__/tool-input-schemas.test.ts +192 -0
- package/src/tools/__tests__/tool-schema-drift-harness.ts +142 -0
- package/src/tools/acp/abort.ts +21 -1
- package/src/tools/acp/context.ts +5 -5
- package/src/tools/acp/spawn.test.ts +15 -5
- package/src/tools/acp/spawn.ts +26 -3
- package/src/tools/acp/status.ts +20 -1
- package/src/tools/acp/steer.test.ts +20 -0
- package/src/tools/acp/steer.ts +23 -2
- package/src/tools/apps/resolve-app-id.ts +15 -3
- package/src/tools/ask-question/ask-question-tool.test.ts +65 -0
- package/src/tools/ask-question/ask-question-tool.ts +68 -92
- package/src/tools/browser/browser-screencast.ts +6 -6
- package/src/tools/calls/call-end.ts +24 -3
- package/src/tools/calls/call-start.ts +35 -11
- package/src/tools/calls/call-status.ts +20 -1
- package/src/tools/conversation-groups/group_create.ts +63 -0
- package/src/tools/conversation-groups/group_list.ts +20 -0
- package/src/tools/conversation-groups/group_shared.ts +52 -0
- package/src/tools/conversation-groups/move_to_group.ts +106 -0
- package/src/tools/document/document-comment-tool.test.ts +49 -0
- package/src/tools/document/document-comment-tool.ts +45 -6
- package/src/tools/document/document-tool.ts +142 -24
- package/src/tools/executor.ts +27 -13
- package/src/tools/filesystem/edit.ts +62 -60
- package/src/tools/filesystem/list.ts +36 -29
- package/src/tools/filesystem/read.ts +56 -39
- package/src/tools/filesystem/write.ts +44 -38
- package/src/tools/followups/followup_create.ts +41 -12
- package/src/tools/followups/followup_list.ts +34 -6
- package/src/tools/followups/followup_resolve.ts +26 -4
- package/src/tools/host-filesystem/edit.ts +50 -60
- package/src/tools/host-filesystem/read.ts +45 -39
- package/src/tools/host-filesystem/write.ts +31 -36
- package/src/tools/host-terminal/host-shell.ts +76 -62
- package/src/tools/policy-context.ts +27 -10
- package/src/tools/schedule/create.ts +76 -33
- package/src/tools/schedule/delete.ts +21 -2
- package/src/tools/schedule/list.ts +25 -3
- package/src/tools/schedule/update.ts +105 -48
- package/src/tools/shared/filesystem/path-policy.ts +246 -40
- package/src/tools/shared/zod-tool-schema.ts +117 -0
- package/src/tools/subagent/abort.ts +12 -4
- package/src/tools/subagent/consult-deadline.ts +9 -3
- package/src/tools/subagent/message.ts +21 -5
- package/src/tools/subagent/notify-parent.ts +44 -23
- package/src/tools/subagent/read.ts +15 -4
- package/src/tools/subagent/resolve.ts +26 -4
- package/src/tools/subagent/spawn.ts +37 -13
- package/src/tools/subagent/status.ts +12 -4
- package/src/tools/system/request-permission.ts +35 -26
- package/src/tools/terminal/shell.ts +68 -55
- package/src/tools/tool-approval-handler.ts +327 -53
- package/src/tools/tool-input-schemas.ts +85 -0
- package/src/tools/tool-types.ts +7 -0
- package/src/tools/types.ts +8 -0
- package/src/tools/workflows/manage-workflows.ts +30 -2
- package/src/tools/workflows/run-workflow.test.ts +54 -2
- package/src/tools/workflows/run-workflow.ts +32 -4
- package/src/util/fs-symlinks.ts +30 -0
- package/src/util/log-redact.ts +7 -3
- package/src/util/platform.ts +15 -0
- package/src/vellum-assistant-namespace.d.ts +80 -0
- package/src/watcher/watcher-store.ts +8 -0
- package/src/workflows/leaf-runner.test.ts +104 -2
- package/src/workflows/leaf-runner.ts +31 -6
- package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +2 -2
- package/src/workspace/migrations/134-image-generation-mode-to-provider.ts +128 -0
- package/src/workspace/migrations/135-copy-substrate-tunables.ts +248 -0
- package/src/workspace/migrations/__tests__/135-copy-substrate-tunables.test.ts +446 -0
- package/src/workspace/migrations/__tests__/backfill-v3-leaves.test.ts +2 -2
- package/src/workspace/migrations/registry.ts +4 -0
- package/tsconfig.plugin-api.json +1 -1
- package/src/__tests__/memory-retrieval-budget.test.ts +0 -49
- package/src/__tests__/secret-patterns.test.ts +0 -27
- package/src/config/__tests__/proc-to-skills.test.ts +0 -21
- package/src/config/memory-tier.test.ts +0 -44
- package/src/daemon/message-types/acp.ts +0 -20
- package/src/daemon/message-types/apps.ts +0 -11
- package/src/daemon/message-types/background-tools.ts +0 -14
- package/src/daemon/message-types/bookmarks.ts +0 -13
- package/src/daemon/message-types/contacts.ts +0 -13
- package/src/daemon/message-types/document-comments.ts +0 -14
- package/src/daemon/message-types/documents.ts +0 -13
- package/src/daemon/message-types/home.ts +0 -15
- package/src/daemon/message-types/host-bash.ts +0 -12
- package/src/daemon/message-types/host-cu.ts +0 -10
- package/src/daemon/message-types/host-file.ts +0 -12
- package/src/daemon/message-types/host-transfer.ts +0 -12
- package/src/daemon/message-types/integrations.ts +0 -90
- package/src/daemon/message-types/memory.ts +0 -10
- package/src/daemon/message-types/schedules.ts +0 -14
- package/src/daemon/message-types/settings.ts +0 -17
- package/src/daemon/message-types/subagents.ts +0 -63
- package/src/daemon/message-types/upgrades.ts +0 -14
- package/src/daemon/message-types/workflows.ts +0 -25
- package/src/daemon/message-types/workspace.ts +0 -137
- package/src/live-voice/ack-phrases.ts +0 -58
- package/src/plugins/defaults/memory/retrieval-budget.ts +0 -29
- package/src/plugins/defaults/memory/v3/__tests__/gate-flag.test.ts +0 -69
- package/src/plugins/defaults/memory/v3/gate-flag.ts +0 -20
- package/src/plugins/defaults/memory/v3/substrate/__tests__/memory-v2-startup.test.ts +0 -86
- package/src/plugins/defaults/memory/v3/substrate/memory-v2-startup.test.ts +0 -205
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/concept-page-frontmatter-schema.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/consolidation-prompt-flag-gating-guard.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/__tests__/injected-block-slugs.test.ts +0 -0
- /package/src/plugins/defaults/memory/{v3/substrate → substrate}/cli-command-content.ts +0 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory v3 — deterministic clause chunking for the span-query dense pass.
|
|
3
|
+
*
|
|
4
|
+
* A single embedding of a long, multi-topic message averages its distinct
|
|
5
|
+
* retrieval intents into one vector that matches none of them — the
|
|
6
|
+
* within-message form of the cross-speaker averaging the reply-query pass
|
|
7
|
+
* exists to avoid. The span pass re-runs the dense lane over the message's
|
|
8
|
+
* clause spans as separate queries so a motif buried in one clause retrieves
|
|
9
|
+
* at full strength.
|
|
10
|
+
*
|
|
11
|
+
* Chunking is pure text processing: split at newlines and sentence
|
|
12
|
+
* punctuation, drop fragments below {@link MIN_SPAN_WEIGHT}. A message yielding
|
|
13
|
+
* more than {@link MAX_SPAN_CHUNKS} spans is NOT truncated to its head — all
|
|
14
|
+
* spans are partitioned into {@link MAX_SPAN_CHUNKS} contiguous near-equal
|
|
15
|
+
* groups, so the whole message stays covered and long messages are simply
|
|
16
|
+
* queried at paragraph grain instead of clause grain.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
/** Hard cap on span chunks per message — bounds the pass at
|
|
20
|
+
* `MAX_SPAN_CHUNKS × spanQueryK` extra candidates and as many embed calls. */
|
|
21
|
+
export const MAX_SPAN_CHUNKS = 8;
|
|
22
|
+
|
|
23
|
+
/** Spans weighing less than this carry no retrieval signal ("ok.", bare emoji
|
|
24
|
+
* lines) and are dropped before chunking. Weight, not raw length — see
|
|
25
|
+
* {@link spanWeight}. */
|
|
26
|
+
const MIN_SPAN_WEIGHT = 15;
|
|
27
|
+
|
|
28
|
+
/** Dense CJK scripts pack roughly a clause into the character budget English
|
|
29
|
+
* needs for a few words, so a raw char floor tuned for spaced scripts would
|
|
30
|
+
* drop nearly every realistic Chinese/Japanese/Korean sentence. Weigh those
|
|
31
|
+
* chars at 3× so the floor measures comparable information content. */
|
|
32
|
+
const DENSE_SCRIPT = /[\p{sc=Han}\p{sc=Hiragana}\p{sc=Katakana}\p{sc=Hangul}]/u;
|
|
33
|
+
|
|
34
|
+
function spanWeight(span: string): number {
|
|
35
|
+
let weight = 0;
|
|
36
|
+
for (const ch of span) {
|
|
37
|
+
weight += DENSE_SCRIPT.test(ch) ? 3 : 1;
|
|
38
|
+
}
|
|
39
|
+
return weight;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Split `message` into at most {@link MAX_SPAN_CHUNKS} contiguous clause
|
|
44
|
+
* chunks. Messages with that many spans or fewer return them unchanged;
|
|
45
|
+
* longer messages merge adjacent spans into near-equal groups covering the
|
|
46
|
+
* whole message. Deterministic; returns `[]` for empty/whitespace input.
|
|
47
|
+
*/
|
|
48
|
+
export function spanChunksOf(message: string): string[] {
|
|
49
|
+
// Boundaries: newlines; any Unicode sentence terminator (`\p{STerm}` covers
|
|
50
|
+
// ASCII `.!?` plus CJK `。!?`, Arabic `؟`, Devanagari `।`, …) or ellipsis
|
|
51
|
+
// followed by whitespace; and a zero-width split after fullwidth CJK
|
|
52
|
+
// terminators, which conventionally have NO trailing space. The whitespace
|
|
53
|
+
// requirement on the general arm keeps ASCII `.` from splitting decimals
|
|
54
|
+
// and dotted abbreviations; fullwidth terminators never appear there.
|
|
55
|
+
const spans = message
|
|
56
|
+
.split(/\n+|(?<=[\p{STerm}…])\s+|(?<=[。!?。])/u)
|
|
57
|
+
.map((s) => s.trim())
|
|
58
|
+
.filter((s) => spanWeight(s) >= MIN_SPAN_WEIGHT);
|
|
59
|
+
if (spans.length <= MAX_SPAN_CHUNKS) {
|
|
60
|
+
return spans;
|
|
61
|
+
}
|
|
62
|
+
const chunks: string[] = [];
|
|
63
|
+
for (let i = 0; i < MAX_SPAN_CHUNKS; i++) {
|
|
64
|
+
const lo = Math.floor((i * spans.length) / MAX_SPAN_CHUNKS);
|
|
65
|
+
const hi = Math.floor(((i + 1) * spans.length) / MAX_SPAN_CHUNKS);
|
|
66
|
+
if (hi > lo) {
|
|
67
|
+
chunks.push(spans.slice(lo, hi).join(" "));
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
return chunks;
|
|
71
|
+
}
|
|
@@ -28,6 +28,7 @@ export interface ResolvedV3Tuning {
|
|
|
28
28
|
needleK: number;
|
|
29
29
|
denseK: number;
|
|
30
30
|
replyQueryK: number;
|
|
31
|
+
spanQueryK: number;
|
|
31
32
|
selectorEnabled: boolean;
|
|
32
33
|
learnedEdgesCap: number;
|
|
33
34
|
edgeSeedCount: number;
|
|
@@ -55,6 +56,7 @@ export const MEMORY_V3_NEW_USER_TUNING: ResolvedV3Tuning = {
|
|
|
55
56
|
needleK: 12,
|
|
56
57
|
denseK: 0,
|
|
57
58
|
replyQueryK: 0,
|
|
59
|
+
spanQueryK: 0,
|
|
58
60
|
selectorEnabled: false,
|
|
59
61
|
learnedEdgesCap: 0,
|
|
60
62
|
edgeSeedCount: 6,
|
|
@@ -82,6 +84,7 @@ export function resolveV3Tuning(
|
|
|
82
84
|
needleK: v3.needleK,
|
|
83
85
|
denseK: v3.denseK,
|
|
84
86
|
replyQueryK: v3.replyQueryK,
|
|
87
|
+
spanQueryK: v3.spanQueryK,
|
|
85
88
|
selectorEnabled: v3.selectorEnabled,
|
|
86
89
|
learnedEdgesCap: v3.learnedEdges.cap,
|
|
87
90
|
edgeSeedCount: v3.edge.seedCount,
|
|
@@ -96,7 +96,9 @@ export interface MemoryRoutingTurn {
|
|
|
96
96
|
* frecency hot set, modification-recency fresh set); `needle` / `dense` /
|
|
97
97
|
* `edge` are the per-turn finder lanes over the user's message; `reply` marks
|
|
98
98
|
* finder candidates first surfaced by the reply-query pass (needle + dense
|
|
99
|
-
* re-run over the assistant's previous message); `
|
|
99
|
+
* re-run over the assistant's previous message); `span` marks candidates first
|
|
100
|
+
* surfaced by the span-query pass (dense re-run over the current message's
|
|
101
|
+
* clause chunks as separate queries); `learned` marks candidates
|
|
100
102
|
* surfaced by the co-selection NPMI association graph; `entity` marks
|
|
101
103
|
* candidates surfaced because the message named an entity that titles a section
|
|
102
104
|
* heading (the heading-anchored entity lane).
|
|
@@ -114,6 +116,7 @@ export const SELECTION_SOURCES = [
|
|
|
114
116
|
"dense",
|
|
115
117
|
"edge",
|
|
116
118
|
"reply",
|
|
119
|
+
"span",
|
|
117
120
|
"learned",
|
|
118
121
|
"entity",
|
|
119
122
|
] as const;
|
|
@@ -36,11 +36,11 @@ import {
|
|
|
36
36
|
messages,
|
|
37
37
|
} from "../../../../persistence/schema/index.js";
|
|
38
38
|
import { FRONTMATTER_REGEX, parseFrontmatterFields } from "../frontmatter.js";
|
|
39
|
+
import { injectedConceptHeader } from "../substrate/injected-block-slugs.js";
|
|
40
|
+
import { slugFromConceptPath } from "../substrate/page-store.js";
|
|
39
41
|
import { renderCard } from "../v3/card.js";
|
|
40
42
|
import { buildSectionNeedle } from "../v3/section-needle.js";
|
|
41
43
|
import { buildSectionIndex } from "../v3/sections.js";
|
|
42
|
-
import { injectedConceptHeader } from "../v3/substrate/injected-block-slugs.js";
|
|
43
|
-
import { slugFromConceptPath } from "../v3/substrate/page-store.js";
|
|
44
44
|
import type { SectionIndex, Slug } from "../v3/types.js";
|
|
45
45
|
|
|
46
46
|
type DrizzleDb = ReturnType<typeof getDb>;
|
|
@@ -14,7 +14,7 @@ export function clampUnitInterval(value: number): number {
|
|
|
14
14
|
* `(x + 1) / 2`, then clamp. Single-channel display normalization for the
|
|
15
15
|
* legacy v1 semantic-search path; do **not** use before hybrid fusion —
|
|
16
16
|
* the affine rescale halves pairwise dense differences and shifts ranking
|
|
17
|
-
* toward sparse. Hybrid fusion (`
|
|
17
|
+
* toward sparse. Hybrid fusion (`substrate/sim.ts`) instead clamps negative
|
|
18
18
|
* cosines to 0 with `Math.max(0, x)` and lets positive cosines pass
|
|
19
19
|
* through unchanged.
|
|
20
20
|
*/
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
import { writeFileSync } from "node:fs";
|
|
14
14
|
|
|
15
15
|
import { getConfig } from "../../../config/loader.js";
|
|
16
|
+
import { isMemoryEnabled } from "../../../config/memory-v3-gate.js";
|
|
16
17
|
import { rehydratePlatformCredentials } from "../../../config/platform-rehydration.js";
|
|
17
18
|
import { resetDb } from "../../../persistence/db-connection.js";
|
|
18
19
|
import { disableStreamSeqStamping } from "../../../runtime/assistant-stream-state.js";
|
|
@@ -34,7 +35,7 @@ async function main(): Promise<void> {
|
|
|
34
35
|
const config = getConfig();
|
|
35
36
|
const pidPath = getMemoryWorkerPidPath();
|
|
36
37
|
|
|
37
|
-
if (config
|
|
38
|
+
if (!isMemoryEnabled(config)) {
|
|
38
39
|
log.info("Memory is disabled in config; worker process exiting");
|
|
39
40
|
process.exit(0);
|
|
40
41
|
}
|
|
@@ -12,6 +12,8 @@
|
|
|
12
12
|
* Covers:
|
|
13
13
|
* - Happy path: model writes valid JSON → structured subject/body, file cleaned up
|
|
14
14
|
* - Runs in a fresh background conversation
|
|
15
|
+
* - Offers standard conversations as candidates; returns the assistant's chosen
|
|
16
|
+
* id, drops hallucinated ids, excludes surfaced background rows
|
|
15
17
|
* - Fenced JSON in the file → still parsed
|
|
16
18
|
* - Model writes nothing → 502
|
|
17
19
|
* - Model writes JSON missing a field → 502
|
|
@@ -32,12 +34,30 @@ import type { RunConversationTurnOptions } from "@vellumai/plugin-api";
|
|
|
32
34
|
// prompt).
|
|
33
35
|
// ---------------------------------------------------------------------------
|
|
34
36
|
|
|
37
|
+
interface ConversationRowStub {
|
|
38
|
+
id: string;
|
|
39
|
+
title: string | null;
|
|
40
|
+
conversationType: string;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** JSON the assistant "writes", including its chosen conversation id. */
|
|
44
|
+
function draftJson(conversation: string | null): string {
|
|
45
|
+
return JSON.stringify({
|
|
46
|
+
subject: "Ready when you are",
|
|
47
|
+
body: "Just picking up where we left off.",
|
|
48
|
+
conversation,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
35
52
|
let workspaceDir = mkdtempSync(join(tmpdir(), "reengage-test-"));
|
|
36
|
-
let fileContents: string | null =
|
|
37
|
-
subject: "Ready when you are",
|
|
38
|
-
body: "Just picking up where we left off.",
|
|
39
|
-
});
|
|
53
|
+
let fileContents: string | null = draftJson("conv-42");
|
|
40
54
|
let lastOptions: RunConversationTurnOptions | undefined;
|
|
55
|
+
// Rows the mocked `listConversations` returns, newest-first — the route filters
|
|
56
|
+
// these to genuine `standard` rows and offers them as link candidates.
|
|
57
|
+
let conversationRows: ConversationRowStub[] = [
|
|
58
|
+
{ id: "conv-42", title: "Roadmap planning", conversationType: "standard" },
|
|
59
|
+
];
|
|
60
|
+
let lastListArgs: unknown[] | undefined;
|
|
41
61
|
|
|
42
62
|
function extractInjectedPath(prompt: string): string {
|
|
43
63
|
const match = prompt.match(/`([^`]+)`/);
|
|
@@ -57,6 +77,10 @@ mock.module("@vellumai/plugin-api", () => ({
|
|
|
57
77
|
}
|
|
58
78
|
return { content: [], userMessageId: "msg-1", conversationId: "conv-1" };
|
|
59
79
|
},
|
|
80
|
+
listConversations: async (...args: unknown[]) => {
|
|
81
|
+
lastListArgs = args;
|
|
82
|
+
return conversationRows;
|
|
83
|
+
},
|
|
60
84
|
}));
|
|
61
85
|
|
|
62
86
|
const { POST } = await import("../routes/reengage.js");
|
|
@@ -72,23 +96,34 @@ describe("platform-hosted /reengage POST", () => {
|
|
|
72
96
|
beforeEach(() => {
|
|
73
97
|
workspaceDir = mkdtempSync(join(tmpdir(), "reengage-test-"));
|
|
74
98
|
lastOptions = undefined;
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
99
|
+
lastListArgs = undefined;
|
|
100
|
+
conversationRows = [
|
|
101
|
+
{
|
|
102
|
+
id: "conv-42",
|
|
103
|
+
title: "Roadmap planning",
|
|
104
|
+
conversationType: "standard",
|
|
105
|
+
},
|
|
106
|
+
];
|
|
107
|
+
fileContents = draftJson("conv-42");
|
|
79
108
|
});
|
|
80
109
|
|
|
110
|
+
function promptText(): string {
|
|
111
|
+
return (lastOptions?.content[0] as { text: string }).text;
|
|
112
|
+
}
|
|
113
|
+
|
|
81
114
|
test("returns the structured subject/body the model wrote, and cleans up", async () => {
|
|
82
115
|
const response = await POST(postRequest());
|
|
83
116
|
expect(response.status).toBe(200);
|
|
84
|
-
const json = (await response.json()) as {
|
|
117
|
+
const json = (await response.json()) as {
|
|
118
|
+
subject: string;
|
|
119
|
+
body: string;
|
|
120
|
+
conversation: string | null;
|
|
121
|
+
};
|
|
85
122
|
expect(json.subject).toBe("Ready when you are");
|
|
86
123
|
expect(json.body).toBe("Just picking up where we left off.");
|
|
87
124
|
|
|
88
125
|
// The injected file is removed after the handler returns.
|
|
89
|
-
const injectedPath = extractInjectedPath(
|
|
90
|
-
(lastOptions?.content[0] as { text: string }).text,
|
|
91
|
-
);
|
|
126
|
+
const injectedPath = extractInjectedPath(promptText());
|
|
92
127
|
expect(existsSync(injectedPath)).toBe(false);
|
|
93
128
|
});
|
|
94
129
|
|
|
@@ -103,6 +138,63 @@ describe("platform-hosted /reengage POST", () => {
|
|
|
103
138
|
expect(lastOptions?.callSite).toBe("inference");
|
|
104
139
|
});
|
|
105
140
|
|
|
141
|
+
test("offers the standard conversations as candidates and returns the chosen id", async () => {
|
|
142
|
+
conversationRows = [
|
|
143
|
+
{
|
|
144
|
+
id: "conv-42",
|
|
145
|
+
title: "Roadmap planning",
|
|
146
|
+
conversationType: "standard",
|
|
147
|
+
},
|
|
148
|
+
{ id: "older", title: "Trip notes", conversationType: "standard" },
|
|
149
|
+
];
|
|
150
|
+
fileContents = draftJson("conv-42");
|
|
151
|
+
const response = await POST(postRequest());
|
|
152
|
+
const json = (await response.json()) as { conversation: string | null };
|
|
153
|
+
|
|
154
|
+
expect(json.conversation).toBe("conv-42");
|
|
155
|
+
// The candidates are offered to the model in the prompt (id + title).
|
|
156
|
+
expect(promptText()).toContain("conv-42: Roadmap planning");
|
|
157
|
+
expect(promptText()).toContain("older: Trip notes");
|
|
158
|
+
// The standard bucket is queried (subagent/background excluded there).
|
|
159
|
+
expect(lastListArgs).toEqual([20, "standard"]);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test("drops a chosen id that isn't among the offered candidates", async () => {
|
|
163
|
+
// A hallucinated / stale id the assistant made up is never trusted.
|
|
164
|
+
fileContents = draftJson("made-up-id");
|
|
165
|
+
const response = await POST(postRequest());
|
|
166
|
+
const json = (await response.json()) as { conversation: string | null };
|
|
167
|
+
expect(json.conversation).toBeNull();
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
test("null conversation is returned when the assistant declines to pick", async () => {
|
|
171
|
+
fileContents = draftJson(null);
|
|
172
|
+
const response = await POST(postRequest());
|
|
173
|
+
const json = (await response.json()) as { conversation: string | null };
|
|
174
|
+
expect(json.conversation).toBeNull();
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
test("excludes surfaced background/scheduled rows from the candidates", async () => {
|
|
178
|
+
// `listConversations(…, "standard")` can surface promoted background rows;
|
|
179
|
+
// they are not real chats to re-open, so they are filtered out — never
|
|
180
|
+
// offered, and rejected even if the model somehow names one.
|
|
181
|
+
conversationRows = [
|
|
182
|
+
{ id: "surfaced-bg", title: "Heartbeat", conversationType: "background" },
|
|
183
|
+
{
|
|
184
|
+
id: "conv-42",
|
|
185
|
+
title: "Roadmap planning",
|
|
186
|
+
conversationType: "standard",
|
|
187
|
+
},
|
|
188
|
+
];
|
|
189
|
+
fileContents = draftJson("surfaced-bg");
|
|
190
|
+
const response = await POST(postRequest());
|
|
191
|
+
const json = (await response.json()) as { conversation: string | null };
|
|
192
|
+
|
|
193
|
+
expect(json.conversation).toBeNull();
|
|
194
|
+
expect(promptText()).not.toContain("surfaced-bg");
|
|
195
|
+
expect(promptText()).toContain("conv-42: Roadmap planning");
|
|
196
|
+
});
|
|
197
|
+
|
|
106
198
|
test("tolerates JSON wrapped in a code fence", async () => {
|
|
107
199
|
fileContents =
|
|
108
200
|
'```json\n{"subject": "A quick nudge", "body": "Let me know."}\n```';
|
|
@@ -14,12 +14,22 @@
|
|
|
14
14
|
* from structured JSON rather than parsed out of the chat reply. The turn runs
|
|
15
15
|
* in a fresh `background` conversation, so it stays out of the user's visible
|
|
16
16
|
* chats.
|
|
17
|
+
*
|
|
18
|
+
* The response also carries `conversation` — the id of the conversation the
|
|
19
|
+
* email's "jump back in" link should re-open, or `null`. The assistant chooses
|
|
20
|
+
* it: the prompt offers a list of the owner's recent conversations and asks it
|
|
21
|
+
* to name the one its email is about, and the route returns that id only after
|
|
22
|
+
* validating it against the offered set. See {@link conversationCandidates}.
|
|
17
23
|
*/
|
|
18
24
|
|
|
19
25
|
import { mkdir, readFile, rm } from "node:fs/promises";
|
|
20
26
|
import { join } from "node:path";
|
|
21
27
|
|
|
22
|
-
import {
|
|
28
|
+
import {
|
|
29
|
+
getWorkspaceDir,
|
|
30
|
+
listConversations,
|
|
31
|
+
runConversationTurn,
|
|
32
|
+
} from "@vellumai/plugin-api";
|
|
23
33
|
|
|
24
34
|
// ---------------------------------------------------------------------------
|
|
25
35
|
// Output location — the plugin's own data directory
|
|
@@ -34,7 +44,15 @@ function pluginDataDir(): string {
|
|
|
34
44
|
// Prompt
|
|
35
45
|
// ---------------------------------------------------------------------------
|
|
36
46
|
|
|
37
|
-
function buildPrompt(
|
|
47
|
+
function buildPrompt(
|
|
48
|
+
outputPath: string,
|
|
49
|
+
candidates: ConversationCandidate[],
|
|
50
|
+
): string {
|
|
51
|
+
const conversationList =
|
|
52
|
+
candidates.length > 0
|
|
53
|
+
? candidates.map((c) => `- ${c.id}: ${c.title}`).join("\n")
|
|
54
|
+
: "(you have no recent conversations)";
|
|
55
|
+
|
|
38
56
|
return `Compose a short re-engagement email to me, in your own voice as my assistant, to gently draw me back into our work together.
|
|
39
57
|
|
|
40
58
|
Draw on what you know about me and our recent conversations to make it personal and specific — reference something concrete we have been working on, or a next step that is waiting on me, rather than a generic "just checking in." Keep it warm, brief, and low-pressure: a few sentences at most, with no pushy or salesy language.
|
|
@@ -43,22 +61,38 @@ When the email is ready, use your file-writing tool to write it to exactly this
|
|
|
43
61
|
|
|
44
62
|
\`${outputPath}\`
|
|
45
63
|
|
|
46
|
-
Write ONLY a raw JSON object to that file — no markdown, no code fence, no surrounding prose — with exactly these
|
|
47
|
-
{"subject": "<the subject line>", "body": "<the plain-text email body>"}
|
|
64
|
+
Write ONLY a raw JSON object to that file — no markdown, no code fence, no surrounding prose — with exactly these fields:
|
|
65
|
+
{"subject": "<the subject line>", "body": "<the plain-text email body>", "conversation": "<id or null>"}
|
|
66
|
+
|
|
67
|
+
The subject should be short and specific. The body is the email itself, written as if you are speaking directly to me.
|
|
48
68
|
|
|
49
|
-
|
|
69
|
+
For "conversation", choose the one conversation below that your email is about — the thread I should re-open to pick up where we left off — and use its id exactly as written. If none of them fit what your email references, use null. Never invent an id; only use one from this list:
|
|
70
|
+
${conversationList}
|
|
71
|
+
|
|
72
|
+
The file is the deliverable; do not include the email in your chat reply.`;
|
|
50
73
|
}
|
|
51
74
|
|
|
52
75
|
// ---------------------------------------------------------------------------
|
|
53
76
|
// Parsing
|
|
54
77
|
// ---------------------------------------------------------------------------
|
|
55
78
|
|
|
79
|
+
interface ParsedEmail {
|
|
80
|
+
subject: string;
|
|
81
|
+
body: string;
|
|
82
|
+
/** The conversation id the assistant chose, or `null` for none. */
|
|
83
|
+
conversation: string | null;
|
|
84
|
+
}
|
|
85
|
+
|
|
56
86
|
/**
|
|
57
|
-
* Read `{ subject, body }` out of the JSON the assistant wrote.
|
|
58
|
-
* asks for a bare object, but tolerate a stray code fence or
|
|
59
|
-
* by falling back to the first brace-delimited span.
|
|
87
|
+
* Read `{ subject, body, conversation }` out of the JSON the assistant wrote.
|
|
88
|
+
* The instruction asks for a bare object, but tolerate a stray code fence or
|
|
89
|
+
* surrounding prose by falling back to the first brace-delimited span.
|
|
90
|
+
*
|
|
91
|
+
* `conversation` is optional and the id it names is not trusted here — the
|
|
92
|
+
* handler validates it against the offered candidates. A missing value, JSON
|
|
93
|
+
* `null`, or the literal string `"null"` all normalize to `null`.
|
|
60
94
|
*/
|
|
61
|
-
function parseEmail(raw: string):
|
|
95
|
+
function parseEmail(raw: string): ParsedEmail | null {
|
|
62
96
|
const candidates = [raw.trim()];
|
|
63
97
|
const brace = raw.match(/\{[\s\S]*\}/);
|
|
64
98
|
if (brace?.[0]) {
|
|
@@ -73,7 +107,12 @@ function parseEmail(raw: string): { subject: string; body: string } | null {
|
|
|
73
107
|
typeof record.subject === "string" ? record.subject.trim() : "";
|
|
74
108
|
const body = typeof record.body === "string" ? record.body.trim() : "";
|
|
75
109
|
if (subject && body) {
|
|
76
|
-
|
|
110
|
+
const raw =
|
|
111
|
+
typeof record.conversation === "string"
|
|
112
|
+
? record.conversation.trim()
|
|
113
|
+
: "";
|
|
114
|
+
const conversation = raw && raw !== "null" ? raw : null;
|
|
115
|
+
return { subject, body, conversation };
|
|
77
116
|
}
|
|
78
117
|
}
|
|
79
118
|
} catch {
|
|
@@ -87,6 +126,42 @@ function jsonError(message: string, status: number): Response {
|
|
|
87
126
|
return Response.json({ error: { message } }, { status });
|
|
88
127
|
}
|
|
89
128
|
|
|
129
|
+
// ---------------------------------------------------------------------------
|
|
130
|
+
// Conversation candidates for the "jump back in" link
|
|
131
|
+
// ---------------------------------------------------------------------------
|
|
132
|
+
|
|
133
|
+
/** A conversation the assistant may choose to link the email back to. */
|
|
134
|
+
interface ConversationCandidate {
|
|
135
|
+
id: string;
|
|
136
|
+
title: string;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** How many recent conversations to offer the assistant to choose from. */
|
|
140
|
+
const CANDIDATE_LIMIT = 10;
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Recent, genuinely-standard conversations the assistant can pick from for the
|
|
144
|
+
* email's "jump back in" link.
|
|
145
|
+
*
|
|
146
|
+
* The assistant chooses which conversation the email is about (see
|
|
147
|
+
* {@link buildPrompt}), but it has no reliable handle on raw conversation ids —
|
|
148
|
+
* there is no list/search-conversations tool and ids are not in its context —
|
|
149
|
+
* so we hand it real candidates to choose among and validate its pick against
|
|
150
|
+
* this set, rather than trusting a free-formed (hallucinatable) id.
|
|
151
|
+
*
|
|
152
|
+
* `listConversations(…, "standard")` also surfaces background/scheduled rows
|
|
153
|
+
* that were promoted via `surfaced_at`, which are not real chats to re-open, so
|
|
154
|
+
* the result is filtered to rows whose type is actually `"standard"`. That also
|
|
155
|
+
* excludes the drafting turn's own background conversation.
|
|
156
|
+
*/
|
|
157
|
+
async function conversationCandidates(): Promise<ConversationCandidate[]> {
|
|
158
|
+
const rows = await listConversations(CANDIDATE_LIMIT * 2, "standard");
|
|
159
|
+
return rows
|
|
160
|
+
.filter((row) => row.conversationType === "standard")
|
|
161
|
+
.slice(0, CANDIDATE_LIMIT)
|
|
162
|
+
.map((row) => ({ id: row.id, title: row.title?.trim() || "Untitled" }));
|
|
163
|
+
}
|
|
164
|
+
|
|
90
165
|
// ---------------------------------------------------------------------------
|
|
91
166
|
// Handler
|
|
92
167
|
// ---------------------------------------------------------------------------
|
|
@@ -96,9 +171,13 @@ export const POST = async (request: Request): Promise<Response> => {
|
|
|
96
171
|
await mkdir(dir, { recursive: true });
|
|
97
172
|
const outputPath = join(dir, `reengage-${crypto.randomUUID()}.json`);
|
|
98
173
|
|
|
174
|
+
// Offer the assistant real conversations to choose the "jump back in" link
|
|
175
|
+
// from, so the id it writes can be validated against actual chats.
|
|
176
|
+
const candidates = await conversationCandidates();
|
|
177
|
+
|
|
99
178
|
try {
|
|
100
179
|
await runConversationTurn({
|
|
101
|
-
content: [{ type: "text", text: buildPrompt(outputPath) }],
|
|
180
|
+
content: [{ type: "text", text: buildPrompt(outputPath, candidates) }],
|
|
102
181
|
conversationType: "background",
|
|
103
182
|
// Drafting a short email is latency-bound, not depth-bound, so run it on
|
|
104
183
|
// the fast model rather than the balanced main-agent default. `inference`
|
|
@@ -127,7 +206,20 @@ export const POST = async (request: Request): Promise<Response> => {
|
|
|
127
206
|
);
|
|
128
207
|
}
|
|
129
208
|
|
|
130
|
-
|
|
209
|
+
// Trust the assistant's choice only if it names one of the conversations we
|
|
210
|
+
// offered — never a free-formed id. The platform wraps `body` in a template
|
|
211
|
+
// whose CTA deep-links to this conversation when present, else the
|
|
212
|
+
// assistant root.
|
|
213
|
+
const candidateIds = new Set(candidates.map((c) => c.id));
|
|
214
|
+
const conversation =
|
|
215
|
+
email.conversation && candidateIds.has(email.conversation)
|
|
216
|
+
? email.conversation
|
|
217
|
+
: null;
|
|
218
|
+
return Response.json({
|
|
219
|
+
subject: email.subject,
|
|
220
|
+
body: email.body,
|
|
221
|
+
conversation,
|
|
222
|
+
});
|
|
131
223
|
} finally {
|
|
132
224
|
await rm(outputPath, { force: true });
|
|
133
225
|
}
|
package/src/plugins/types.ts
CHANGED
|
@@ -91,8 +91,8 @@ export type {
|
|
|
91
91
|
/**
|
|
92
92
|
* The complete set of compaction circuit-breaker transition events:
|
|
93
93
|
* `compaction_circuit_open` when the breaker trips and `compaction_circuit_closed`
|
|
94
|
-
* on the open→closed transition. Both are a subset of `
|
|
95
|
-
* existing `
|
|
94
|
+
* on the open→closed transition. Both are a subset of `AssistantEvent`, so any
|
|
95
|
+
* existing `AssistantEvent` sink remains assignable to a
|
|
96
96
|
* `(msg: CompactionCircuitEvent) => void` parameter.
|
|
97
97
|
*/
|
|
98
98
|
export type CompactionCircuitEvent =
|
package/src/prompts/sections.ts
CHANGED
|
@@ -3,7 +3,10 @@ import { join } from "node:path";
|
|
|
3
3
|
|
|
4
4
|
import { parseFrontmatterFields } from "../skills/frontmatter.js";
|
|
5
5
|
import { getLogger } from "../util/logger.js";
|
|
6
|
-
import {
|
|
6
|
+
import {
|
|
7
|
+
getWorkspacePromptPath,
|
|
8
|
+
getWorkspaceSystemPromptDir,
|
|
9
|
+
} from "../util/platform.js";
|
|
7
10
|
import { stripCommentLines } from "../util/strip-comment-lines.js";
|
|
8
11
|
import {
|
|
9
12
|
BUNDLED_SYSTEM_SECTIONS,
|
|
@@ -25,21 +28,6 @@ const log = getLogger("system-prompt-sections");
|
|
|
25
28
|
*/
|
|
26
29
|
export type SectionRenderContext = Record<string, unknown>;
|
|
27
30
|
|
|
28
|
-
/**
|
|
29
|
-
* Workspace override location for user-authored system prompt sections.
|
|
30
|
-
* Layout: `<workspace>/prompts/system/<NN-name>.md`.
|
|
31
|
-
*
|
|
32
|
-
* The bundled section registry (`templates/system-sections.ts`) is the
|
|
33
|
-
* source of default truth; this directory is an optional override layer.
|
|
34
|
-
* Drop a file with the same id as a bundled section to replace its body,
|
|
35
|
-
* or drop a file with a brand-new `<NN-name>` to add a workspace-only
|
|
36
|
-
* section. Either path is opt-in — the directory may not exist on a
|
|
37
|
-
* fresh install, and the renderer will simply use bundled defaults.
|
|
38
|
-
*/
|
|
39
|
-
export function getWorkspaceSystemPromptDir(): string {
|
|
40
|
-
return join(getWorkspaceDir(), "prompts", "system");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
31
|
/**
|
|
44
32
|
* Render static sections in id-sort order, then dynamic sections in id-sort
|
|
45
33
|
* order, returning the trimmed bodies of enabled sections grouped into
|
|
@@ -1,4 +1,12 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
afterEach,
|
|
3
|
+
beforeEach,
|
|
4
|
+
describe,
|
|
5
|
+
expect,
|
|
6
|
+
mock,
|
|
7
|
+
setSystemTime,
|
|
8
|
+
test,
|
|
9
|
+
} from "bun:test";
|
|
2
10
|
|
|
3
11
|
import { LLMSchema } from "../../config/schemas/llm.js";
|
|
4
12
|
import type { ProviderConnection } from "../inference/auth.js";
|
|
@@ -52,7 +60,6 @@ function makeConfig(): ProvidersConfig {
|
|
|
52
60
|
services: {
|
|
53
61
|
inference: {},
|
|
54
62
|
"image-generation": {
|
|
55
|
-
mode: "your-own",
|
|
56
63
|
provider: "gemini",
|
|
57
64
|
model: "gemini-3.1-flash-image-preview",
|
|
58
65
|
},
|
|
@@ -115,6 +122,44 @@ describe("resolveProviderFromConnection native web search selection", () => {
|
|
|
115
122
|
});
|
|
116
123
|
});
|
|
117
124
|
|
|
125
|
+
describe("resolveProviderFromConnection connection cache TTL", () => {
|
|
126
|
+
beforeEach(() => {
|
|
127
|
+
adapterCalls.length = 0;
|
|
128
|
+
clearConnectionProviderCache();
|
|
129
|
+
setSystemTime(new Date("2026-01-01T00:00:00Z"));
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
afterEach(() => {
|
|
133
|
+
// Restore the real clock so later suites are not frozen.
|
|
134
|
+
setSystemTime();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
test("serves a cached provider within the TTL, re-resolves after it expires", async () => {
|
|
138
|
+
// First resolution: a cache miss builds an adapter.
|
|
139
|
+
await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
|
|
140
|
+
model: "anthropic/claude-opus-4-7",
|
|
141
|
+
});
|
|
142
|
+
expect(adapterCalls).toHaveLength(1);
|
|
143
|
+
|
|
144
|
+
// A second resolution 59s later is a cache hit — no new adapter, so the
|
|
145
|
+
// baked-in credential is reused.
|
|
146
|
+
setSystemTime(new Date("2026-01-01T00:00:59Z"));
|
|
147
|
+
await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
|
|
148
|
+
model: "anthropic/claude-opus-4-7",
|
|
149
|
+
});
|
|
150
|
+
expect(adapterCalls).toHaveLength(1);
|
|
151
|
+
|
|
152
|
+
// Past the 60s TTL the entry is stale: the next resolution re-reads the
|
|
153
|
+
// credential and rebuilds the adapter, so a key rotated out-of-band is
|
|
154
|
+
// picked up without any explicit cache invalidation.
|
|
155
|
+
setSystemTime(new Date("2026-01-01T00:01:01Z"));
|
|
156
|
+
await resolveProviderFromConnection(openRouterConnection, makeConfig(), {
|
|
157
|
+
model: "anthropic/claude-opus-4-7",
|
|
158
|
+
});
|
|
159
|
+
expect(adapterCalls).toHaveLength(2);
|
|
160
|
+
});
|
|
161
|
+
});
|
|
162
|
+
|
|
118
163
|
describe("isNativeWebSearchCapableProvider gateway anthropic routing", () => {
|
|
119
164
|
test("vercel-ai-gateway anthropic/* models are capable", () => {
|
|
120
165
|
expect(
|
|
@@ -1790,8 +1790,8 @@ export class AnthropicProvider implements Provider {
|
|
|
1790
1790
|
),
|
|
1791
1791
|
);
|
|
1792
1792
|
|
|
1793
|
-
// Preserve assistant turns that would otherwise become empty after
|
|
1794
|
-
// unknown block types
|
|
1793
|
+
// Preserve assistant turns that would otherwise become empty after
|
|
1794
|
+
// filtering unknown block types. Dropping these messages can violate
|
|
1795
1795
|
// Anthropic's role alternation requirement.
|
|
1796
1796
|
if (
|
|
1797
1797
|
content.length === 0 &&
|
|
@@ -1940,10 +1940,13 @@ export class AnthropicProvider implements Provider {
|
|
|
1940
1940
|
}
|
|
1941
1941
|
|
|
1942
1942
|
/**
|
|
1943
|
-
* Convert a content block to Anthropic format, returning null for
|
|
1944
|
-
*
|
|
1945
|
-
*
|
|
1946
|
-
*
|
|
1943
|
+
* Convert a content block to Anthropic format, returning null for blocks the
|
|
1944
|
+
* Messages API cannot carry instead of throwing, so they don't prevent the
|
|
1945
|
+
* request from being sent or break tool_use/tool_result pairing.
|
|
1946
|
+
*
|
|
1947
|
+
* Two distinct null cases: `ui_surface` is a known client-rendering block
|
|
1948
|
+
* dropped by design, while a block reaching `default` is genuinely
|
|
1949
|
+
* unrecognised and warns so the gap is visible.
|
|
1947
1950
|
*/
|
|
1948
1951
|
private toAnthropicBlockSafe(
|
|
1949
1952
|
block: ContentBlock,
|
|
@@ -2086,6 +2089,12 @@ export class AnthropicProvider implements Provider {
|
|
|
2086
2089
|
tool_use_id: block.tool_use_id,
|
|
2087
2090
|
content: block.content,
|
|
2088
2091
|
} as unknown as Anthropic.ContentBlockParam;
|
|
2092
|
+
case "ui_surface":
|
|
2093
|
+
// A client rendering instruction, not model context. Dropped by
|
|
2094
|
+
// design: the producer's sibling `_surfaceFallback` text block is what
|
|
2095
|
+
// the model reads. `buildSentMessages` projects the surface to text
|
|
2096
|
+
// for legacy rows that have no fallback sibling.
|
|
2097
|
+
return null;
|
|
2089
2098
|
default: {
|
|
2090
2099
|
log.warn(
|
|
2091
2100
|
{ blockType: (block as { type: string }).type },
|