@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
|
@@ -12,11 +12,14 @@ import { v4 as uuid } from "uuid";
|
|
|
12
12
|
|
|
13
13
|
import { cleanupBootstrapFiles } from "../prompts/bootstrap-cleanup.js";
|
|
14
14
|
import { getCurrentSeq } from "../runtime/assistant-stream-state.js";
|
|
15
|
+
import { getLogger } from "../util/logger.js";
|
|
15
16
|
import { initConversationDir } from "./conversation-disk-view.js";
|
|
16
17
|
import { GENERATING_TITLE } from "./conversation-title-service.js";
|
|
17
18
|
import { getDb } from "./db-connection.js";
|
|
18
19
|
import { conversationKeys, conversations } from "./schema/index.js";
|
|
19
20
|
|
|
21
|
+
const log = getLogger("conversation-key-store");
|
|
22
|
+
|
|
20
23
|
/** Set after the first conversation is created so BOOTSTRAP.md is deleted on the second. */
|
|
21
24
|
let firstConversationSeen = false;
|
|
22
25
|
|
|
@@ -267,6 +270,23 @@ export function getOrCreateConversation(
|
|
|
267
270
|
|
|
268
271
|
if (result.created) {
|
|
269
272
|
initConversationDir({ ...result.conversation, originChannel: null });
|
|
273
|
+
// Attribution for every key-materialized conversation: this is the single
|
|
274
|
+
// choke point through which all unseen-key creations flow, and the key
|
|
275
|
+
// shape + caller frames identify the entry point from the log alone. The
|
|
276
|
+
// raw key is never logged — channel-backed keys embed external chat ids
|
|
277
|
+
// (phone numbers, Slack/Telegram ids), and assistant logs travel in
|
|
278
|
+
// support bundles. Emitted only on the creation branch, never on hot
|
|
279
|
+
// read/write paths.
|
|
280
|
+
log.info(
|
|
281
|
+
{
|
|
282
|
+
conversationKeyShape: classifyConversationKey(conversationKey),
|
|
283
|
+
conversationId: result.conversationId,
|
|
284
|
+
conversationType,
|
|
285
|
+
hasCustomTitle: Boolean(opts?.title?.trim()),
|
|
286
|
+
caller: captureCallerFrames(),
|
|
287
|
+
},
|
|
288
|
+
"Materialized conversation for unseen conversation key",
|
|
289
|
+
);
|
|
270
290
|
}
|
|
271
291
|
|
|
272
292
|
return {
|
|
@@ -275,3 +295,46 @@ export function getOrCreateConversation(
|
|
|
275
295
|
created: result.created,
|
|
276
296
|
};
|
|
277
297
|
}
|
|
298
|
+
|
|
299
|
+
const UUID_SHAPE_RE =
|
|
300
|
+
/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
301
|
+
|
|
302
|
+
/**
|
|
303
|
+
* PII-free shape label for a conversation key. Channel-backed keys embed
|
|
304
|
+
* external chat/user ids, so only the structural prefix is kept (e.g.
|
|
305
|
+
* `asst:<id>:slack:<chat>:thread:<ts>` → "asst-scoped:slack:threaded");
|
|
306
|
+
* free-form keys collapse to a coarse class.
|
|
307
|
+
*/
|
|
308
|
+
function classifyConversationKey(conversationKey: string): string {
|
|
309
|
+
if (conversationKey.startsWith("asst:")) {
|
|
310
|
+
const parts = conversationKey.split(":");
|
|
311
|
+
const channel = parts[2] ?? "unknown";
|
|
312
|
+
const threaded = parts.includes("thread") ? ":threaded" : "";
|
|
313
|
+
return `asst-scoped:${channel}${threaded}`;
|
|
314
|
+
}
|
|
315
|
+
const prefixed = conversationKey.match(/^([a-z-]+)[:-]/i);
|
|
316
|
+
if (prefixed) {
|
|
317
|
+
return `prefixed:${prefixed[1].toLowerCase()}`;
|
|
318
|
+
}
|
|
319
|
+
if (UUID_SHAPE_RE.test(conversationKey)) {
|
|
320
|
+
return "uuid";
|
|
321
|
+
}
|
|
322
|
+
return "opaque";
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
/**
|
|
326
|
+
* Compact caller summary for creation attribution: the first few stack
|
|
327
|
+
* frames above this module, joined into one log-friendly line.
|
|
328
|
+
*/
|
|
329
|
+
function captureCallerFrames(): string {
|
|
330
|
+
const stack = new Error().stack?.split("\n") ?? [];
|
|
331
|
+
return stack
|
|
332
|
+
.slice(1)
|
|
333
|
+
.map((line) => line.trim())
|
|
334
|
+
.filter(
|
|
335
|
+
(line) =>
|
|
336
|
+
line.startsWith("at ") && !line.includes("conversation-key-store"),
|
|
337
|
+
)
|
|
338
|
+
.slice(0, 4)
|
|
339
|
+
.join(" | ");
|
|
340
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { eq } from "drizzle-orm";
|
|
2
|
+
|
|
3
|
+
import { getDb } from "./db-connection.js";
|
|
4
|
+
import { conversations } from "./schema/index.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* The durable spawn parent of a conversation: the `parent_conversation_id`
|
|
8
|
+
* column stamped at subagent bootstrap. Returns `undefined` for a conversation
|
|
9
|
+
* with no recorded parent or no row at all.
|
|
10
|
+
*
|
|
11
|
+
* Unlike the in-memory conversation registry — which drops a subagent entry as
|
|
12
|
+
* soon as its run goes terminal and evicts idle top-level conversations — this
|
|
13
|
+
* survives for the life of the row, so an ancestry walk still resolves long
|
|
14
|
+
* after the run that created the chain has finished.
|
|
15
|
+
*
|
|
16
|
+
* A single-row primary-key lookup.
|
|
17
|
+
*/
|
|
18
|
+
export function getPersistedParentConversationId(
|
|
19
|
+
conversationId: string,
|
|
20
|
+
): string | undefined {
|
|
21
|
+
const row = getDb()
|
|
22
|
+
.select({ parentConversationId: conversations.parentConversationId })
|
|
23
|
+
.from(conversations)
|
|
24
|
+
.where(eq(conversations.id, conversationId))
|
|
25
|
+
.get();
|
|
26
|
+
return row?.parentConversationId ?? undefined;
|
|
27
|
+
}
|
|
@@ -228,7 +228,7 @@ async function runViaCli(
|
|
|
228
228
|
// corrupt) — the durability posture every daemon write already has, so
|
|
229
229
|
// FULL here buys no end-to-end guarantee. Prepended to the piped SQL so
|
|
230
230
|
// both take effect before the statement runs.
|
|
231
|
-
const sqlWithPragma = `PRAGMA busy_timeout=${SQLITE_BUSY_TIMEOUT_MS};\nPRAGMA synchronous=NORMAL;\n${sql}`;
|
|
231
|
+
const sqlWithPragma = `PRAGMA busy_timeout=${SQLITE_BUSY_TIMEOUT_MS};\nPRAGMA synchronous=NORMAL;\nPRAGMA journal_mode=WAL;\n${sql}`;
|
|
232
232
|
|
|
233
233
|
// Write the SQL and close stdin so sqlite3 sees EOF and exits.
|
|
234
234
|
proc.stdin.write(sqlWithPragma + "\n");
|
|
@@ -17,10 +17,10 @@
|
|
|
17
17
|
*
|
|
18
18
|
* State is held on `globalThis.vellumAssistant.dbSingletons` so test
|
|
19
19
|
* helpers in `__tests__/` can read/write it WITHOUT importing this
|
|
20
|
-
* module
|
|
21
|
-
*
|
|
22
|
-
*
|
|
23
|
-
*
|
|
20
|
+
* module. Both sides reference the shared ambient `VellumDbSlots` type
|
|
21
|
+
* (declared in `src/vellum-assistant-namespace.d.ts`), which types the
|
|
22
|
+
* slot without adding a runtime import between them. See
|
|
23
|
+
* `__tests__/db-test-helpers.ts` for the test-side reader.
|
|
24
24
|
*
|
|
25
25
|
* The stored value is typed as `unknown` so this file never has to import
|
|
26
26
|
* Drizzle types. Callers in `db-connection.ts` narrow via the type
|
|
@@ -33,32 +33,19 @@
|
|
|
33
33
|
* - `__tests__/db-test-helpers.ts` (per-test reset, via globalThis)
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
-
/**
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
| "telemetry";
|
|
43
|
-
|
|
44
|
-
type DbSlot = {
|
|
45
|
-
db: unknown;
|
|
46
|
-
closer: (() => void) | null;
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
type DbSlots = Record<DbSlotKey, DbSlot>;
|
|
50
|
-
|
|
51
|
-
type VellumAssistantNamespace = {
|
|
52
|
-
dbSingletons?: DbSlots;
|
|
53
|
-
};
|
|
36
|
+
/**
|
|
37
|
+
* Which connection a slot holds. The canonical union is the ambient
|
|
38
|
+
* `VellumDbSlotKey` (see `src/vellum-assistant-namespace.d.ts`); this
|
|
39
|
+
* re-export is the DB layer's public name for it.
|
|
40
|
+
*/
|
|
41
|
+
export type DbSlotKey = VellumDbSlotKey;
|
|
54
42
|
|
|
55
|
-
function emptySlot():
|
|
43
|
+
function emptySlot(): VellumDbSlot {
|
|
56
44
|
return { db: null, closer: null };
|
|
57
45
|
}
|
|
58
46
|
|
|
59
|
-
function slots():
|
|
60
|
-
const
|
|
61
|
-
const ns = (g.vellumAssistant ??= {});
|
|
47
|
+
function slots(): VellumDbSlots {
|
|
48
|
+
const ns = (globalThis.vellumAssistant ??= {});
|
|
62
49
|
return (ns.dbSingletons ??= {
|
|
63
50
|
main: emptySlot(),
|
|
64
51
|
"main-readonly": emptySlot(),
|
|
@@ -68,7 +55,7 @@ function slots(): DbSlots {
|
|
|
68
55
|
});
|
|
69
56
|
}
|
|
70
57
|
|
|
71
|
-
function slot(key: DbSlotKey):
|
|
58
|
+
function slot(key: DbSlotKey): VellumDbSlot {
|
|
72
59
|
return slots()[key];
|
|
73
60
|
}
|
|
74
61
|
|
|
@@ -188,6 +188,51 @@ function resolveInboundConversation(
|
|
|
188
188
|
return getOrCreateConversation(threadedKey);
|
|
189
189
|
}
|
|
190
190
|
|
|
191
|
+
/**
|
|
192
|
+
* Resolve the internal conversation already bound to an inbound
|
|
193
|
+
* (channel, chat, thread) address, or `null` when none exists. Mirrors
|
|
194
|
+
* {@link resolveInboundConversation}'s lookup order — threaded key first,
|
|
195
|
+
* then the Slack flat-key alias when thread evidence exists — but is
|
|
196
|
+
* strictly read-only: deny lanes use it to attach the in-app
|
|
197
|
+
* access-request card to the originating conversation, and a denied
|
|
198
|
+
* inbound must never mint a conversation as a side effect.
|
|
199
|
+
*/
|
|
200
|
+
export function findInboundConversationId(
|
|
201
|
+
sourceChannel: string,
|
|
202
|
+
externalChatId: string,
|
|
203
|
+
sourceThreadId?: string | null,
|
|
204
|
+
): string | null {
|
|
205
|
+
const threadedKey = buildScopedConversationKey(
|
|
206
|
+
sourceChannel,
|
|
207
|
+
externalChatId,
|
|
208
|
+
sourceThreadId,
|
|
209
|
+
);
|
|
210
|
+
const threadedMapping = getConversationByKey(threadedKey);
|
|
211
|
+
if (threadedMapping) {
|
|
212
|
+
return threadedMapping.conversationId;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const threadId = sourceThreadId?.trim();
|
|
216
|
+
if (sourceChannel !== "slack" || !threadId) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const legacyKey = buildScopedConversationKey(sourceChannel, externalChatId);
|
|
221
|
+
const legacyMapping = getConversationByKey(legacyKey);
|
|
222
|
+
if (
|
|
223
|
+
legacyMapping &&
|
|
224
|
+
legacySlackConversationHasThreadEvidence(
|
|
225
|
+
legacyMapping.conversationId,
|
|
226
|
+
externalChatId,
|
|
227
|
+
threadId,
|
|
228
|
+
)
|
|
229
|
+
) {
|
|
230
|
+
return legacyMapping.conversationId;
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
return null;
|
|
234
|
+
}
|
|
235
|
+
|
|
191
236
|
/**
|
|
192
237
|
* Record an inbound channel event. Returns `duplicate: true` if this
|
|
193
238
|
* exact (channel, chat, message) combination was already seen.
|
|
@@ -2,6 +2,7 @@ import { createHash } from "node:crypto";
|
|
|
2
2
|
|
|
3
3
|
import { getOllamaBaseUrlEnv } from "../../config/env.js";
|
|
4
4
|
import { resolveCallSiteConfig } from "../../config/llm-resolver.js";
|
|
5
|
+
import { isMemoryEnabled } from "../../config/memory-v3-gate.js";
|
|
5
6
|
import type { AssistantConfig } from "../../config/types.js";
|
|
6
7
|
import { PLATFORM_PROVIDER_META } from "../../providers/platform-proxy/constants.js";
|
|
7
8
|
import { resolveManagedProxyContext } from "../../providers/platform-proxy/context.js";
|
|
@@ -507,7 +508,7 @@ export async function getMemoryBackendStatus(config: AssistantConfig): Promise<{
|
|
|
507
508
|
model: string | null;
|
|
508
509
|
reason: string | null;
|
|
509
510
|
}> {
|
|
510
|
-
if (config
|
|
511
|
+
if (!isMemoryEnabled(config)) {
|
|
511
512
|
return {
|
|
512
513
|
enabled: false,
|
|
513
514
|
degraded: false,
|
|
@@ -12,9 +12,13 @@ import { resolveQdrantUrl } from "./qdrant-client.js";
|
|
|
12
12
|
|
|
13
13
|
const log = getLogger("embedding-identity");
|
|
14
14
|
|
|
15
|
-
//
|
|
16
|
-
//
|
|
17
|
-
//
|
|
15
|
+
// FROZEN: `memory_v2_concept_pages` is a Qdrant collection name on disk, and it
|
|
16
|
+
// belongs to the concept-page SUBSTRATE (which outlives the v2 engine) despite
|
|
17
|
+
// the `v2` spelling — see `plugins/defaults/memory/AGENTS.md`. Inlined rather
|
|
18
|
+
// than imported from `memory/substrate/qdrant.ts`'s `MEMORY_V2_COLLECTION`: the
|
|
19
|
+
// persistence layer must not import from the memory feature layer (enforced by
|
|
20
|
+
// persistence-layering-guard). The dependency direction is memory →
|
|
21
|
+
// persistence. This copy and the substrate's must change together or never.
|
|
18
22
|
const MEMORY_V2_COLLECTION = "memory_v2_concept_pages";
|
|
19
23
|
|
|
20
24
|
export interface BackendDimensionProbe {
|
|
@@ -230,8 +230,39 @@ export async function embedAndUpsert(
|
|
|
230
230
|
? generateSparseEmbedding(normalized.text)
|
|
231
231
|
: undefined;
|
|
232
232
|
|
|
233
|
-
// Persist embedding in SQLite for cross-restart cache
|
|
234
233
|
const now = Date.now();
|
|
234
|
+
const qdrant = requireQdrantClient();
|
|
235
|
+
|
|
236
|
+
try {
|
|
237
|
+
const modality = normalized.type;
|
|
238
|
+
await withQdrantBreaker(() =>
|
|
239
|
+
qdrant.upsert(
|
|
240
|
+
targetType,
|
|
241
|
+
targetId,
|
|
242
|
+
vector,
|
|
243
|
+
{
|
|
244
|
+
text: payloadText,
|
|
245
|
+
modality,
|
|
246
|
+
created_at: (extraPayload?.created_at as number) ?? now,
|
|
247
|
+
...(extraPayload as Record<string, unknown> | undefined),
|
|
248
|
+
},
|
|
249
|
+
sparseVector,
|
|
250
|
+
),
|
|
251
|
+
);
|
|
252
|
+
} catch (err) {
|
|
253
|
+
log.warn(
|
|
254
|
+
{ err, targetType, targetId },
|
|
255
|
+
"Failed to upsert embedding to Qdrant",
|
|
256
|
+
);
|
|
257
|
+
throw err;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Persist the embedding in SQLite for the cross-restart cache, after the
|
|
261
|
+
// point is live in Qdrant. Consumers read a row as "this target is indexed"
|
|
262
|
+
// — the graph-node orphan sweep does — so a row written ahead of the upsert
|
|
263
|
+
// would mark a missing point as embedded and suppress the re-embed that
|
|
264
|
+
// would restore it. Best-effort in the other direction: a write failure logs
|
|
265
|
+
// and leaves the point in place, and the next run re-embeds.
|
|
235
266
|
try {
|
|
236
267
|
const blobValue = vectorToBlob(vector);
|
|
237
268
|
db.insert(memoryEmbeddings)
|
|
@@ -267,30 +298,4 @@ export async function embedAndUpsert(
|
|
|
267
298
|
} catch (err) {
|
|
268
299
|
log.warn({ err, targetType, targetId }, "Failed to write embedding cache");
|
|
269
300
|
}
|
|
270
|
-
|
|
271
|
-
const qdrant = requireQdrantClient();
|
|
272
|
-
|
|
273
|
-
try {
|
|
274
|
-
const modality = normalized.type;
|
|
275
|
-
await withQdrantBreaker(() =>
|
|
276
|
-
qdrant.upsert(
|
|
277
|
-
targetType,
|
|
278
|
-
targetId,
|
|
279
|
-
vector,
|
|
280
|
-
{
|
|
281
|
-
text: payloadText,
|
|
282
|
-
modality,
|
|
283
|
-
created_at: (extraPayload?.created_at as number) ?? now,
|
|
284
|
-
...(extraPayload as Record<string, unknown> | undefined),
|
|
285
|
-
},
|
|
286
|
-
sparseVector,
|
|
287
|
-
),
|
|
288
|
-
);
|
|
289
|
-
} catch (err) {
|
|
290
|
-
log.warn(
|
|
291
|
-
{ err, targetType, targetId },
|
|
292
|
-
"Failed to upsert embedding to Qdrant",
|
|
293
|
-
);
|
|
294
|
-
throw err;
|
|
295
|
-
}
|
|
296
301
|
}
|
|
@@ -2,6 +2,7 @@ import { and, asc, eq, inArray, lte, notInArray, sql } from "drizzle-orm";
|
|
|
2
2
|
import { v4 as uuid } from "uuid";
|
|
3
3
|
|
|
4
4
|
import { getConfig } from "../config/loader.js";
|
|
5
|
+
import { isMemoryEnabled as isMemoryEnabledForConfig } from "../config/memory-v3-gate.js";
|
|
5
6
|
import { getLogger } from "../util/logger.js";
|
|
6
7
|
import { truncate } from "../util/truncate.js";
|
|
7
8
|
import { type DrizzleDb, getMemoryDb } from "./db-connection.js";
|
|
@@ -13,6 +14,7 @@ import {
|
|
|
13
14
|
isQdrantBreakerOpen,
|
|
14
15
|
shouldAllowQdrantProbe,
|
|
15
16
|
} from "./embeddings/qdrant-circuit-breaker.js";
|
|
17
|
+
import { isLifecycleQuiesced } from "./lifecycle-quiesce.js";
|
|
16
18
|
import { rawMemoryAll, rawMemoryChanges } from "./raw-query.js";
|
|
17
19
|
import { memoryJobs } from "./schema/index.js";
|
|
18
20
|
|
|
@@ -55,6 +57,8 @@ export type MemoryJobType =
|
|
|
55
57
|
| "graph_trigger_embed"
|
|
56
58
|
| "graph_bootstrap"
|
|
57
59
|
| "embed_concept_page"
|
|
60
|
+
// FROZEN: `memory_v2_*` job type values are persisted in job rows — never
|
|
61
|
+
// rename them.
|
|
58
62
|
| "memory_v2_sweep"
|
|
59
63
|
| "memory_v2_consolidate"
|
|
60
64
|
| "memory_v2_migrate"
|
|
@@ -68,12 +72,12 @@ export type MemoryJobType =
|
|
|
68
72
|
| "delete_message_lexical"
|
|
69
73
|
| "backfill_lexical_index"
|
|
70
74
|
| "skill_card_insert"
|
|
75
|
+
| "memory_retrospective"
|
|
71
76
|
| "memory_retrospective_sweep"
|
|
72
77
|
// Retired/legacy — no live handler; persisted rows drop via LEGACY_JOB_TYPES.
|
|
73
78
|
| "memory_v3_consolidate"
|
|
74
79
|
| "memory_v3_index_maintenance"
|
|
75
80
|
| "memory_v3_edge_learning"
|
|
76
|
-
| "memory_retrospective"
|
|
77
81
|
| "conversation_analyze";
|
|
78
82
|
|
|
79
83
|
export const EMBED_JOB_TYPES: MemoryJobType[] = [
|
|
@@ -127,10 +131,11 @@ export const MEMORY_V2_CONSOLIDATION_JOB_TRIGGERS = {
|
|
|
127
131
|
remember: "remember",
|
|
128
132
|
} as const;
|
|
129
133
|
|
|
130
|
-
/**
|
|
134
|
+
/** Config-singleton wrapper over the canonical gate predicate in
|
|
135
|
+
* `config/memory-v3-gate.ts`; defaults to `true` on config load errors. */
|
|
131
136
|
export function isMemoryEnabled(): boolean {
|
|
132
137
|
try {
|
|
133
|
-
return getConfig()
|
|
138
|
+
return isMemoryEnabledForConfig(getConfig());
|
|
134
139
|
} catch {
|
|
135
140
|
return true;
|
|
136
141
|
}
|
|
@@ -374,6 +379,33 @@ function mergeSkillCardEntries(
|
|
|
374
379
|
return merged;
|
|
375
380
|
}
|
|
376
381
|
|
|
382
|
+
/**
|
|
383
|
+
* Source-conversation ids of every PENDING `memory_retrospective` job. The
|
|
384
|
+
* retrospective sweep skips these up front: a pending row already covers the
|
|
385
|
+
* source's unprocessed span, and a coalescing upsert against it must not
|
|
386
|
+
* consume the sweep's per-pass enqueue cap. Deliberately excludes `running`
|
|
387
|
+
* rows — a running job's fork and cursor are pre-run snapshots, so messages
|
|
388
|
+
* arriving mid-run need a follow-up row behind it, and the sweep must be able
|
|
389
|
+
* to create that follow-up. Mirrors `upsertMemoryRetrospectiveJob`'s
|
|
390
|
+
* pending-only coalescing.
|
|
391
|
+
*/
|
|
392
|
+
export function listPendingMemoryRetrospectiveSourceConversationIds(): string[] {
|
|
393
|
+
return memoryDb()
|
|
394
|
+
.select({
|
|
395
|
+
conversationId: sql<string>`json_extract(${memoryJobs.payload}, '$.conversationId')`,
|
|
396
|
+
})
|
|
397
|
+
.from(memoryJobs)
|
|
398
|
+
.where(
|
|
399
|
+
and(
|
|
400
|
+
eq(memoryJobs.type, "memory_retrospective"),
|
|
401
|
+
eq(memoryJobs.status, "pending"),
|
|
402
|
+
),
|
|
403
|
+
)
|
|
404
|
+
.all()
|
|
405
|
+
.map((row) => row.conversationId)
|
|
406
|
+
.filter((id): id is string => typeof id === "string" && id.length > 0);
|
|
407
|
+
}
|
|
408
|
+
|
|
377
409
|
/**
|
|
378
410
|
* Check whether a pending or running job of the given type already exists.
|
|
379
411
|
* Used to prevent duplicate enqueues for long-running maintenance jobs.
|
|
@@ -453,6 +485,36 @@ export function upsertEmbedConceptPageJob(payload: { slug: string }): string {
|
|
|
453
485
|
return enqueueMemoryJob("embed_concept_page", { slug: payload.slug });
|
|
454
486
|
}
|
|
455
487
|
|
|
488
|
+
/**
|
|
489
|
+
* Enqueue an `embed_graph_node` job, coalescing with an existing pending row
|
|
490
|
+
* for the same node id. The payload carries only the node id — the handler
|
|
491
|
+
* reads the node's content at execution time — so a pending row is exactly
|
|
492
|
+
* equivalent to a fresh enqueue and a duplicate would only redo identical
|
|
493
|
+
* embedding work and Qdrant upserts. A running row never matches: it may have
|
|
494
|
+
* embedded a pre-write snapshot of the node, so the new enqueue must survive
|
|
495
|
+
* it. Same synchronous check-then-insert rationale as
|
|
496
|
+
* {@link upsertEmbedConceptPageJob}. Returns the id of the pending row,
|
|
497
|
+
* existing or newly inserted.
|
|
498
|
+
*/
|
|
499
|
+
export function upsertEmbedGraphNodeJob(payload: { nodeId: string }): string {
|
|
500
|
+
const db = memoryDb();
|
|
501
|
+
const existing = db
|
|
502
|
+
.select({ id: memoryJobs.id })
|
|
503
|
+
.from(memoryJobs)
|
|
504
|
+
.where(
|
|
505
|
+
and(
|
|
506
|
+
eq(memoryJobs.type, "embed_graph_node"),
|
|
507
|
+
eq(memoryJobs.status, "pending"),
|
|
508
|
+
sql`json_extract(${memoryJobs.payload}, '$.nodeId') = ${payload.nodeId}`,
|
|
509
|
+
),
|
|
510
|
+
)
|
|
511
|
+
.get();
|
|
512
|
+
if (existing) {
|
|
513
|
+
return existing.id;
|
|
514
|
+
}
|
|
515
|
+
return enqueueMemoryJob("embed_graph_node", { nodeId: payload.nodeId });
|
|
516
|
+
}
|
|
517
|
+
|
|
456
518
|
export function enqueuePruneOldLlmRequestLogsJob(retentionMs?: number): string {
|
|
457
519
|
const db = memoryDb();
|
|
458
520
|
const existing = db
|
|
@@ -618,6 +680,13 @@ export function claimMemoryJobs(
|
|
|
618
680
|
return [];
|
|
619
681
|
}
|
|
620
682
|
|
|
683
|
+
// Drain gate: while a quiesce lease is active, claim nothing so in-flight
|
|
684
|
+
// jobs finish and the queue drains to a stop. Enqueues are unaffected;
|
|
685
|
+
// claims resume when the lease expires. Fail-open via the lease read.
|
|
686
|
+
if (isLifecycleQuiesced()) {
|
|
687
|
+
return [];
|
|
688
|
+
}
|
|
689
|
+
|
|
621
690
|
const db = memoryDb();
|
|
622
691
|
const now = Date.now();
|
|
623
692
|
const restrictFilter = restrictToTypes
|
|
@@ -868,6 +937,26 @@ export function resetRunningJobsToPending(): number {
|
|
|
868
937
|
return rawMemoryChanges();
|
|
869
938
|
}
|
|
870
939
|
|
|
940
|
+
/** Currently-running memory jobs, oldest first — the drain-status view. */
|
|
941
|
+
export function listRunningMemoryJobs(): Array<{
|
|
942
|
+
id: string;
|
|
943
|
+
type: string;
|
|
944
|
+
startedAt: number | null;
|
|
945
|
+
}> {
|
|
946
|
+
const db = memoryDb();
|
|
947
|
+
return db
|
|
948
|
+
.select({
|
|
949
|
+
id: memoryJobs.id,
|
|
950
|
+
type: memoryJobs.type,
|
|
951
|
+
startedAt: memoryJobs.startedAt,
|
|
952
|
+
})
|
|
953
|
+
.from(memoryJobs)
|
|
954
|
+
.where(eq(memoryJobs.status, "running"))
|
|
955
|
+
.orderBy(asc(memoryJobs.startedAt))
|
|
956
|
+
.limit(20)
|
|
957
|
+
.all();
|
|
958
|
+
}
|
|
959
|
+
|
|
871
960
|
/**
|
|
872
961
|
* Fail running jobs whose `startedAt` is older than `timeoutMs` ago.
|
|
873
962
|
* Returns the number of jobs that were timed out.
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cross-process quiesce lease for graceful drains.
|
|
3
|
+
*
|
|
4
|
+
* `vellum sleep --wait` sets a short-TTL lease before stopping the assistant;
|
|
5
|
+
* every background-work claim/fire site (heartbeat, the daemon's
|
|
6
|
+
* watcher/sequence tick, the schedule worker's claim tick, the memory jobs
|
|
7
|
+
* worker) checks it and stops STARTING new work while it is active. Enqueue
|
|
8
|
+
* paths are unaffected — queued work runs after the restart.
|
|
9
|
+
*
|
|
10
|
+
* The lease is a single `memory_checkpoints` row on the main database so the
|
|
11
|
+
* daemon and both worker processes read the same value. The value is an
|
|
12
|
+
* epoch-ms deadline, refreshed by the waiting client, so a dead client can
|
|
13
|
+
* never silence background work for longer than one TTL. Readers fail OPEN —
|
|
14
|
+
* a missing, malformed, or unreadable lease means "not quiesced".
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
import {
|
|
18
|
+
deleteMemoryCheckpoint,
|
|
19
|
+
getMemoryCheckpoint,
|
|
20
|
+
setMemoryCheckpoint,
|
|
21
|
+
} from "./checkpoints.js";
|
|
22
|
+
|
|
23
|
+
const QUIESCE_UNTIL_KEY = "lifecycle:quiesce_until";
|
|
24
|
+
|
|
25
|
+
export const MIN_QUIESCE_TTL_MS = 5_000;
|
|
26
|
+
export const MAX_QUIESCE_TTL_MS = 10 * 60_000;
|
|
27
|
+
export const DEFAULT_QUIESCE_TTL_MS = 60_000;
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Arm (or refresh) the quiesce lease. Returns the lease deadline (epoch ms).
|
|
31
|
+
*
|
|
32
|
+
* Throws when the lease cannot be persisted — callers that promise a drain
|
|
33
|
+
* must surface the failure rather than pretend background work is paused.
|
|
34
|
+
*/
|
|
35
|
+
export function setLifecycleQuiesce(
|
|
36
|
+
ttlMs: number = DEFAULT_QUIESCE_TTL_MS,
|
|
37
|
+
): number {
|
|
38
|
+
const clamped = Math.min(
|
|
39
|
+
Math.max(Math.floor(ttlMs), MIN_QUIESCE_TTL_MS),
|
|
40
|
+
MAX_QUIESCE_TTL_MS,
|
|
41
|
+
);
|
|
42
|
+
const quiescedUntil = Date.now() + clamped;
|
|
43
|
+
setMemoryCheckpoint(QUIESCE_UNTIL_KEY, String(quiescedUntil));
|
|
44
|
+
return quiescedUntil;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* The active lease deadline, or null when no unexpired lease exists.
|
|
49
|
+
* Fail-open: any read or parse failure reads as "no lease".
|
|
50
|
+
*/
|
|
51
|
+
export function getLifecycleQuiesceUntil(): number | null {
|
|
52
|
+
let raw: string | null;
|
|
53
|
+
try {
|
|
54
|
+
raw = getMemoryCheckpoint(QUIESCE_UNTIL_KEY);
|
|
55
|
+
} catch {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
if (raw == null) {
|
|
59
|
+
return null;
|
|
60
|
+
}
|
|
61
|
+
const until = Number.parseInt(raw, 10);
|
|
62
|
+
if (!Number.isFinite(until) || until <= Date.now()) {
|
|
63
|
+
return null;
|
|
64
|
+
}
|
|
65
|
+
return until;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** True while an unexpired quiesce lease is active. Fail-open. */
|
|
69
|
+
export function isLifecycleQuiesced(): boolean {
|
|
70
|
+
return getLifecycleQuiesceUntil() != null;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/** Drop the lease. Best-effort — a failure leaves the TTL to expire it. */
|
|
74
|
+
export function clearLifecycleQuiesce(): void {
|
|
75
|
+
try {
|
|
76
|
+
deleteMemoryCheckpoint(QUIESCE_UNTIL_KEY);
|
|
77
|
+
} catch {
|
|
78
|
+
// Fail-soft: the lease self-expires.
|
|
79
|
+
}
|
|
80
|
+
}
|
|
@@ -42,6 +42,30 @@ import {
|
|
|
42
42
|
// Write
|
|
43
43
|
// ---------------------------------------------------------------------------
|
|
44
44
|
|
|
45
|
+
/**
|
|
46
|
+
* Resolve the parent conversation's `conversation_type` at record time.
|
|
47
|
+
* Usage rows outlive conversation rows (retrospective forks are GC'd,
|
|
48
|
+
* users delete conversations), so the type must be captured while the
|
|
49
|
+
* conversation still exists — the telemetry flush can run after the
|
|
50
|
+
* parent row is gone. Best-effort: a lookup failure degrades to null
|
|
51
|
+
* (same as the pre-column behavior) rather than dropping the usage row.
|
|
52
|
+
*/
|
|
53
|
+
function lookupConversationType(conversationId: string | null): string | null {
|
|
54
|
+
if (conversationId === null) {
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
const row = getDb()
|
|
59
|
+
.select({ conversationType: conversations.conversationType })
|
|
60
|
+
.from(conversations)
|
|
61
|
+
.where(eq(conversations.id, conversationId))
|
|
62
|
+
.get();
|
|
63
|
+
return row?.conversationType ?? null;
|
|
64
|
+
} catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
45
69
|
export function recordUsageEvent(
|
|
46
70
|
input: UsageEventInput,
|
|
47
71
|
pricing: PricingResult,
|
|
@@ -88,6 +112,10 @@ export function recordUsageEvent(
|
|
|
88
112
|
// the assistant happens to be running on at upload time. See
|
|
89
113
|
// migration 267 + `TelemetryEventBase.assistant_version` (wire).
|
|
90
114
|
assistantVersion: event.assistantVersion,
|
|
115
|
+
// Capture the parent conversation's type at RECORD time for the
|
|
116
|
+
// same reason: the conversation row may be deleted before the
|
|
117
|
+
// telemetry flush joins against it. See migration 353.
|
|
118
|
+
conversationType: lookupConversationType(event.conversationId),
|
|
91
119
|
})
|
|
92
120
|
.run();
|
|
93
121
|
return event;
|
|
@@ -192,9 +220,11 @@ export function listUsageEvents(options?: { limit?: number }): UsageEvent[] {
|
|
|
192
220
|
export interface UnreportedUsageEvent extends UsageEvent {
|
|
193
221
|
/**
|
|
194
222
|
* Type of the parent conversation (`"standard"` / `"background"` /
|
|
195
|
-
* `"scheduled"`).
|
|
196
|
-
* (
|
|
197
|
-
* `conversations`
|
|
223
|
+
* `"scheduled"`). Sourced from the value captured at record time
|
|
224
|
+
* (survives deletion of the parent conversation before flush), with a
|
|
225
|
+
* JOIN to `conversations` as the fallback for rows persisted before
|
|
226
|
+
* migration 353. Null when the LLM call has no `conversationId`
|
|
227
|
+
* (memory consolidation, background embedding work, etc.).
|
|
198
228
|
*/
|
|
199
229
|
conversationType: string | null;
|
|
200
230
|
/**
|
|
@@ -263,10 +293,13 @@ export function queryUnreportedUsageEvents(
|
|
|
263
293
|
${conversations.createdAt}
|
|
264
294
|
)
|
|
265
295
|
END`;
|
|
266
|
-
//
|
|
267
|
-
//
|
|
268
|
-
//
|
|
269
|
-
//
|
|
296
|
+
// `conversationType` prefers the value stamped on the row at record
|
|
297
|
+
// time (migration 353) — the parent conversation may have been deleted
|
|
298
|
+
// before this flush (retrospective fork GC, user deletion) — and falls
|
|
299
|
+
// back to a LEFT JOIN against `conversations` for pre-353 rows. LEFT
|
|
300
|
+
// JOIN because `llm_usage_events.conversationId` is nullable — calls
|
|
301
|
+
// that aren't tied to a conversation (memory consolidation, etc.)
|
|
302
|
+
// still need to flush through telemetry.
|
|
270
303
|
//
|
|
271
304
|
// `turnIndex` is a correlated subquery counting real user turns in
|
|
272
305
|
// the same conversation up to and including this LLM call's
|
|
@@ -297,7 +330,11 @@ export function queryUnreportedUsageEvents(
|
|
|
297
330
|
pricingStatus: llmUsageEvents.pricingStatus,
|
|
298
331
|
assistantVersion: llmUsageEvents.assistantVersion,
|
|
299
332
|
llmCallCount: llmUsageEvents.llmCallCount,
|
|
300
|
-
conversationType:
|
|
333
|
+
conversationType: sql<
|
|
334
|
+
string | null
|
|
335
|
+
>`COALESCE(${llmUsageEvents.conversationType}, ${conversations.conversationType})`.as(
|
|
336
|
+
"resolved_conversation_type",
|
|
337
|
+
),
|
|
301
338
|
// Null when conversationId is null (no parent conversation).
|
|
302
339
|
// Otherwise the count of eligible user turns up to and including
|
|
303
340
|
// this LLM call's createdAt. The COALESCE guard returns null
|