@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
|
@@ -9,7 +9,11 @@
|
|
|
9
9
|
* PREVIOUS message as separate queries at a smaller budget
|
|
10
10
|
* (`replyQueryK` per lane), surfacing the threads the assistant is
|
|
11
11
|
* actively developing that the user's message references without
|
|
12
|
-
* naming —
|
|
12
|
+
* naming —
|
|
13
|
+
* - the span-query pass — the dense lane re-run over the current
|
|
14
|
+
* message's clause chunks as separate queries at a small per-chunk
|
|
15
|
+
* budget (`spanQueryK`), rescuing motifs a long multi-topic message's
|
|
16
|
+
* single query vector averages away — and
|
|
13
17
|
* - link-graph edge expansion (`edgeExpand`) over the top
|
|
14
18
|
* user-message needle+dense article seeds, and
|
|
15
19
|
* - learned-edge expansion (`edgeExpand` over the co-selection NPMI
|
|
@@ -61,6 +65,7 @@ import {
|
|
|
61
65
|
} from "../../../../daemon/turn-latency-sub-spans.js";
|
|
62
66
|
import { recordWatchdogEvent } from "../../../../telemetry/watchdog-events-store.js";
|
|
63
67
|
import { getLogger } from "../logging.js";
|
|
68
|
+
import type { DenseHitScored } from "./dense.js";
|
|
64
69
|
import { denseLaneScored } from "./dense.js";
|
|
65
70
|
import type { EdgeGraph } from "./edge.js";
|
|
66
71
|
import { edgeExpand } from "./edge.js";
|
|
@@ -74,6 +79,7 @@ import type {
|
|
|
74
79
|
} from "./pool-select.js";
|
|
75
80
|
import { selectAllPoolCandidates, selectPool } from "./pool-select.js";
|
|
76
81
|
import type { SectionNeedle } from "./section-needle.js";
|
|
82
|
+
import { spanChunksOf } from "./span-query.js";
|
|
77
83
|
import type {
|
|
78
84
|
FinderLane,
|
|
79
85
|
MemoryRoutingTurn,
|
|
@@ -195,6 +201,12 @@ export interface OrchestrateDeps {
|
|
|
195
201
|
* over `turn.previousAssistantMessage` as separate queries). `0` or
|
|
196
202
|
* omitted disables the pass (canonical value: `memory.v3.replyQueryK`). */
|
|
197
203
|
replyQueryK?: number;
|
|
204
|
+
/** Per-chunk article budget for the span-query pass (dense re-run over the
|
|
205
|
+
* current message's clause chunks as separate queries). `0` or omitted
|
|
206
|
+
* disables the pass; it is also inert when the dense lane is disabled or
|
|
207
|
+
* the message yields fewer than two chunks (canonical value:
|
|
208
|
+
* `memory.v3.spanQueryK`). */
|
|
209
|
+
spanQueryK?: number;
|
|
198
210
|
/** Number of top needle+dense seeds expanded. When omitted, the edge lane's
|
|
199
211
|
* own default applies (canonical value: `memory.v3.edge.seedCount`). */
|
|
200
212
|
edgeSeeds?: number;
|
|
@@ -220,9 +232,9 @@ export interface OrchestrateDeps {
|
|
|
220
232
|
/** Whether to run the selector LLM. False passes all pooled candidates
|
|
221
233
|
* straight through as selections, preserving pool-order slug dedup. */
|
|
222
234
|
selectorEnabled?: boolean;
|
|
223
|
-
/** Per-turn injection gate config (`memory.v3.gate` tuning
|
|
224
|
-
*
|
|
225
|
-
*
|
|
235
|
+
/** Per-turn injection gate config (the `memory.v3.gate` tuning, threaded
|
|
236
|
+
* through by observeTurn). Omitted/disabled → the gate never runs and every
|
|
237
|
+
* turn proceeds to selectPool as before. */
|
|
226
238
|
gateConfig?: V3GateConfig;
|
|
227
239
|
/** Real concept-page count at lane build — the same corpus-size signal
|
|
228
240
|
* `resolveV3Tuning` switches the lean/full profile on. Reported with each
|
|
@@ -359,15 +371,23 @@ export async function orchestrate(
|
|
|
359
371
|
// a vector that matches neither) at its own, smaller budget; it runs in the
|
|
360
372
|
// same parallel batch.
|
|
361
373
|
// `denseK = 0` disables dense retrieval for the whole turn, including the
|
|
362
|
-
// reply-query dense
|
|
374
|
+
// reply-query and span-query dense passes.
|
|
363
375
|
const replyK = deps.replyQueryK ?? 0;
|
|
364
376
|
const replyQuery =
|
|
365
377
|
replyK > 0 ? (turn.previousAssistantMessage ?? "").trim() : "";
|
|
366
378
|
const denseEnabled = denseK > 0;
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
379
|
+
// The span-query pass re-runs the dense lane over the current message's
|
|
380
|
+
// clause chunks as SEPARATE queries (a single embedding of a multi-topic
|
|
381
|
+
// message averages its intents into a vector that matches none of them —
|
|
382
|
+
// the within-message form of the averaging the reply pass avoids across
|
|
383
|
+
// speakers). A single-chunk message would just duplicate the full-message
|
|
384
|
+
// dense query, so the pass needs at least two chunks to run.
|
|
385
|
+
const spanK = deps.spanQueryK ?? 0;
|
|
386
|
+
const spanChunks =
|
|
387
|
+
spanK > 0 && denseEnabled ? spanChunksOf(turn.currentMessage) : [];
|
|
388
|
+
const spanQueries = spanChunks.length >= 2 ? spanChunks : [];
|
|
389
|
+
const [needled, densed, replyNeedled, replyDensed, spanDensed] =
|
|
390
|
+
await timeLatencySubSpan("v3_lanes", "Memory search", () =>
|
|
371
391
|
Promise.all([
|
|
372
392
|
Promise.resolve(deps.needle.queryScored(turn.currentMessage, needleK)),
|
|
373
393
|
denseEnabled
|
|
@@ -381,8 +401,13 @@ export async function orchestrate(
|
|
|
381
401
|
replyQuery.length > 0 && denseEnabled
|
|
382
402
|
? denseLaneScored(deps.denseConfig, replyQuery, replyK)
|
|
383
403
|
: Promise.resolve([]),
|
|
404
|
+
Promise.all(
|
|
405
|
+
spanQueries.map((chunk) =>
|
|
406
|
+
denseLaneScored(deps.denseConfig, chunk, spanK),
|
|
407
|
+
),
|
|
408
|
+
),
|
|
384
409
|
]),
|
|
385
|
-
|
|
410
|
+
);
|
|
386
411
|
// Everything from here to the step-3 selection — finder assembly, the
|
|
387
412
|
// entity lane, the injection gate, edge + learned-edge expansion, pool
|
|
388
413
|
// assembly — is synchronous in-memory work, measured as one `v3_expand`
|
|
@@ -437,18 +462,29 @@ export async function orchestrate(
|
|
|
437
462
|
// Step 1b: dense hits — `section` is the matched ORDINAL; resolve it to the
|
|
438
463
|
// concrete `Section` via the section index. Falls back to undefined (blank
|
|
439
464
|
// descriptor) if the ordinal is not in the in-memory index.
|
|
465
|
+
//
|
|
466
|
+
// `denseOwnedSection` tracks the articles whose recorded matched section
|
|
467
|
+
// came from THIS loop (needle records first and wins ties), along with the
|
|
468
|
+
// hit's cosine score — the span pass upgrades those sections when a clause
|
|
469
|
+
// query finds a strictly stronger match under the same metric.
|
|
470
|
+
const denseOwnedSection = new Map<Slug, number>();
|
|
440
471
|
for (const hit of densed) {
|
|
441
472
|
// A deleted page's points can linger in Qdrant; keep only live-index
|
|
442
473
|
// articles. The section index is rebuilt from `getPageIndex` at `initLanes`,
|
|
443
474
|
// so `byArticle` holds exactly the live pages (synthetic capability slugs
|
|
444
475
|
// included) — only truly-deleted pages are dropped here.
|
|
445
|
-
if (!deps.sectionIndex.byArticle.has(hit.article))
|
|
446
|
-
|
|
476
|
+
if (!deps.sectionIndex.byArticle.has(hit.article)) {
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
const section = sectionByOrdinal(
|
|
480
|
+
deps.sectionIndex,
|
|
447
481
|
hit.article,
|
|
448
|
-
|
|
449
|
-
undefined,
|
|
450
|
-
"dense",
|
|
482
|
+
hit.section,
|
|
451
483
|
);
|
|
484
|
+
if (section && !matchedSections.has(hit.article)) {
|
|
485
|
+
denseOwnedSection.set(hit.article, hit.score);
|
|
486
|
+
}
|
|
487
|
+
addFinder(hit.article, section, undefined, "dense");
|
|
452
488
|
}
|
|
453
489
|
|
|
454
490
|
// Step 1b': reply-query hits — candidates the user-message lanes already
|
|
@@ -469,7 +505,53 @@ export async function orchestrate(
|
|
|
469
505
|
);
|
|
470
506
|
}
|
|
471
507
|
|
|
472
|
-
// Step 1b'':
|
|
508
|
+
// Step 1b'': span-query hits — union-additive at the pass's own small
|
|
509
|
+
// budget. Candidates the primary or reply lanes already surfaced keep their
|
|
510
|
+
// attribution (`addFinder`'s first-lane-wins dedupe); only genuinely
|
|
511
|
+
// span-surfaced articles tag `"span"`. Like the reply pass, span hits are
|
|
512
|
+
// excluded from the injection gate (which scores current-message needle +
|
|
513
|
+
// dense only) and from the edge-expansion seeds.
|
|
514
|
+
//
|
|
515
|
+
// An article can be surfaced by SEVERAL chunks; dedupe by best cosine score
|
|
516
|
+
// before `addFinder`, since chunk order would otherwise decide which section
|
|
517
|
+
// gets recorded — letting an earlier chunk's weak match mask the strong
|
|
518
|
+
// buried-clause match the pass exists to recover.
|
|
519
|
+
const bestSpanHits = new Map<Slug, DenseHitScored>();
|
|
520
|
+
for (const hit of spanDensed.flat()) {
|
|
521
|
+
const prev = bestSpanHits.get(hit.article);
|
|
522
|
+
if (!prev || hit.score > prev.score) {
|
|
523
|
+
bestSpanHits.set(hit.article, hit);
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
// For an article a primary lane already surfaced, upgrade its matched
|
|
527
|
+
// section/descriptor ONLY when the existing section was recorded by the
|
|
528
|
+
// full-message dense hit and the span's cosine is strictly higher — same
|
|
529
|
+
// encoder, same collection, so the comparison is evidence, not judgment.
|
|
530
|
+
// Needle- and reply-recorded sections stay (BM25 and cosine scores are not
|
|
531
|
+
// comparable, and the reply pass's own convention is first-wins); lane
|
|
532
|
+
// attribution never changes here.
|
|
533
|
+
for (const hit of bestSpanHits.values()) {
|
|
534
|
+
if (!deps.sectionIndex.byArticle.has(hit.article)) {
|
|
535
|
+
continue;
|
|
536
|
+
}
|
|
537
|
+
const section = sectionByOrdinal(
|
|
538
|
+
deps.sectionIndex,
|
|
539
|
+
hit.article,
|
|
540
|
+
hit.section,
|
|
541
|
+
);
|
|
542
|
+
const denseScore = denseOwnedSection.get(hit.article);
|
|
543
|
+
if (section && denseScore !== undefined && hit.score > denseScore) {
|
|
544
|
+
matchedSections.set(hit.article, section);
|
|
545
|
+
const existing = finder.find((c) => c.slug === hit.article);
|
|
546
|
+
if (existing) {
|
|
547
|
+
existing.descriptor = section.text;
|
|
548
|
+
}
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
addFinder(hit.article, section, undefined, "span");
|
|
552
|
+
}
|
|
553
|
+
|
|
554
|
+
// Step 1b''': entity lane — sections whose `## ` heading NAMES a distinctive
|
|
473
555
|
// entity the message mentions. Additive BM25 buries a single named entity
|
|
474
556
|
// under a long, multi-topic message's bulk theme; this keys on the heading
|
|
475
557
|
// vocabulary so the page the user named surfaces regardless of the bulk
|
|
@@ -501,8 +583,8 @@ export async function orchestrate(
|
|
|
501
583
|
}
|
|
502
584
|
}
|
|
503
585
|
|
|
504
|
-
// Step 1b''': opt-in injection gate. With the CURRENT-message finder lanes in
|
|
505
|
-
// hand (needle + dense — NOT reply/entity/edge, which only add recall), decide
|
|
586
|
+
// Step 1b'''': opt-in injection gate. With the CURRENT-message finder lanes in
|
|
587
|
+
// hand (needle + dense — NOT reply/span/entity/edge, which only add recall), decide
|
|
506
588
|
// whether retrieval is confident enough to spend the selectPool LLM call this
|
|
507
589
|
// turn. Default-off via `?.enabled`; pass-open on any throw (a gate bug must
|
|
508
590
|
// never drop a turn's memory). A closed gate either hard-skips selection
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { getWorkspaceDir } from "../paths.js";
|
|
2
|
+
import { injectedConceptHeader } from "../substrate/injected-block-slugs.js";
|
|
3
|
+
import { readPage, renderPageContent } from "../substrate/page-store.js";
|
|
2
4
|
import { renderCapabilityContent } from "./capabilities.js";
|
|
3
5
|
import { renderCard } from "./card.js";
|
|
4
|
-
import { injectedConceptHeader } from "./substrate/injected-block-slugs.js";
|
|
5
|
-
import { readPage, renderPageContent } from "./substrate/page-store.js";
|
|
6
6
|
import type { Section, Slug } from "./types.js";
|
|
7
7
|
|
|
8
8
|
/**
|
|
@@ -35,12 +35,18 @@ function withConceptHeader(slug: Slug, body: string): string {
|
|
|
35
35
|
*/
|
|
36
36
|
export async function renderV3PageContent(slug: Slug): Promise<string> {
|
|
37
37
|
const capability = renderCapabilityContent(slug);
|
|
38
|
-
if (capability !== null)
|
|
38
|
+
if (capability !== null) {
|
|
39
|
+
return capability;
|
|
40
|
+
}
|
|
39
41
|
try {
|
|
40
42
|
const page = await readPage(getWorkspaceDir(), slug);
|
|
41
|
-
if (!page)
|
|
43
|
+
if (!page) {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
42
46
|
const content = renderPageContent(page).trim();
|
|
43
|
-
if (content.length === 0)
|
|
47
|
+
if (content.length === 0) {
|
|
48
|
+
return "";
|
|
49
|
+
}
|
|
44
50
|
return withConceptHeader(slug, content);
|
|
45
51
|
} catch {
|
|
46
52
|
return "";
|
|
@@ -62,10 +68,14 @@ export async function renderV3PageContent(slug: Slug): Promise<string> {
|
|
|
62
68
|
*/
|
|
63
69
|
export async function renderV3CardContent(slug: Slug): Promise<string> {
|
|
64
70
|
const capability = renderCapabilityContent(slug);
|
|
65
|
-
if (capability !== null)
|
|
71
|
+
if (capability !== null) {
|
|
72
|
+
return capability;
|
|
73
|
+
}
|
|
66
74
|
try {
|
|
67
75
|
const page = await readPage(getWorkspaceDir(), slug);
|
|
68
|
-
if (!page)
|
|
76
|
+
if (!page) {
|
|
77
|
+
return "";
|
|
78
|
+
}
|
|
69
79
|
return renderCard(slug, renderPageContent(page));
|
|
70
80
|
} catch {
|
|
71
81
|
return "";
|
|
@@ -93,10 +103,16 @@ export async function renderV3SectionContent(
|
|
|
93
103
|
section: Section | undefined,
|
|
94
104
|
): Promise<string> {
|
|
95
105
|
const capability = renderCapabilityContent(slug);
|
|
96
|
-
if (capability !== null)
|
|
97
|
-
|
|
106
|
+
if (capability !== null) {
|
|
107
|
+
return capability;
|
|
108
|
+
}
|
|
109
|
+
if (!section) {
|
|
110
|
+
return renderV3PageContent(slug);
|
|
111
|
+
}
|
|
98
112
|
|
|
99
113
|
const text = section.text.trim();
|
|
100
|
-
if (text.length === 0)
|
|
114
|
+
if (text.length === 0) {
|
|
115
|
+
return "";
|
|
116
|
+
}
|
|
101
117
|
return withConceptHeader(slug, text);
|
|
102
118
|
}
|
|
@@ -65,6 +65,10 @@ import { getMemoryConfig } from "../config.js";
|
|
|
65
65
|
import { getLogger } from "../logging.js";
|
|
66
66
|
import { memorySqliteOrNull } from "../memory-db.js";
|
|
67
67
|
import { unwrapMemoryBlock, wrapMemoryBlock } from "../memory-marker.js";
|
|
68
|
+
import {
|
|
69
|
+
INJECTED_CONCEPT_HEADER_REGEX,
|
|
70
|
+
readInjectedBlock,
|
|
71
|
+
} from "../substrate/injected-block-slugs.js";
|
|
68
72
|
import {
|
|
69
73
|
getActiveEntries,
|
|
70
74
|
getPrunedSlugs,
|
|
@@ -72,10 +76,6 @@ import {
|
|
|
72
76
|
MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
|
|
73
77
|
residentBytes,
|
|
74
78
|
} from "./ever-injected-store.js";
|
|
75
|
-
import {
|
|
76
|
-
INJECTED_CONCEPT_HEADER_REGEX,
|
|
77
|
-
readInjectedBlock,
|
|
78
|
-
} from "./substrate/injected-block-slugs.js";
|
|
79
79
|
|
|
80
80
|
const log = getLogger("memory-v3-shadow");
|
|
81
81
|
|
|
@@ -133,7 +133,9 @@ export function parseCardSections(inner: string): {
|
|
|
133
133
|
cardMatches.map((match) => ({ index: match.index!, slug: match[1]! }));
|
|
134
134
|
for (const match of inner.matchAll(TOP_LEVEL_HEADER_REGEX)) {
|
|
135
135
|
const i = match.index!;
|
|
136
|
-
if (cardStarts.has(i))
|
|
136
|
+
if (cardStarts.has(i)) {
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
137
139
|
// Foreign header on a `\n\n` seam → starts its own chunk.
|
|
138
140
|
if (i >= 2 && inner[i - 1] === "\n" && inner[i - 2] === "\n") {
|
|
139
141
|
boundaries.push({ index: i, slug: null });
|
|
@@ -175,16 +177,24 @@ export function filterPrunedCardSections(
|
|
|
175
177
|
prunedSlugs: ReadonlySet<string>,
|
|
176
178
|
): string {
|
|
177
179
|
const { preamble, sections, pieces } = parseCardSections(inner);
|
|
178
|
-
if (sections.length === 0)
|
|
180
|
+
if (sections.length === 0) {
|
|
181
|
+
return inner;
|
|
182
|
+
}
|
|
179
183
|
|
|
180
184
|
const kept = pieces.filter(
|
|
181
185
|
(piece) => piece.kind !== "card" || !prunedSlugs.has(piece.slug),
|
|
182
186
|
);
|
|
183
|
-
if (kept.length === pieces.length)
|
|
184
|
-
|
|
187
|
+
if (kept.length === pieces.length) {
|
|
188
|
+
return inner;
|
|
189
|
+
}
|
|
190
|
+
if (kept.length === 0) {
|
|
191
|
+
return "";
|
|
192
|
+
}
|
|
185
193
|
|
|
186
194
|
const texts = kept.map((piece) => piece.text);
|
|
187
|
-
if (preamble.length > 0)
|
|
195
|
+
if (preamble.length > 0) {
|
|
196
|
+
texts.unshift(preamble);
|
|
197
|
+
}
|
|
188
198
|
return texts.join("\n\n");
|
|
189
199
|
}
|
|
190
200
|
|
|
@@ -226,7 +236,9 @@ export function planPrune(
|
|
|
226
236
|
): PrunePlan | null {
|
|
227
237
|
const activeEntries = getActiveEntries(conversationId);
|
|
228
238
|
const resident = activeEntries.reduce((sum, e) => sum + e.bytes, 0);
|
|
229
|
-
if (resident <= deps.maxResidentBytes)
|
|
239
|
+
if (resident <= deps.maxResidentBytes) {
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
230
242
|
|
|
231
243
|
const memoryRaw = memorySqliteOrNull("planPrune");
|
|
232
244
|
const selectionRows = memoryRaw
|
|
@@ -256,7 +268,9 @@ export function planPrune(
|
|
|
256
268
|
const slugs: string[] = [];
|
|
257
269
|
let bytesFreed = 0;
|
|
258
270
|
for (const candidate of candidates) {
|
|
259
|
-
if (resident - bytesFreed <= deps.targetResidentBytes)
|
|
271
|
+
if (resident - bytesFreed <= deps.targetResidentBytes) {
|
|
272
|
+
break;
|
|
273
|
+
}
|
|
260
274
|
slugs.push(candidate.slug);
|
|
261
275
|
bytesFreed += candidate.bytes;
|
|
262
276
|
}
|
|
@@ -293,7 +307,9 @@ export function collectPersistedV3Cards(conversationId: string): Set<string> {
|
|
|
293
307
|
row.metadata,
|
|
294
308
|
MEMORY_V3_INJECTED_BLOCK_METADATA_KEY,
|
|
295
309
|
);
|
|
296
|
-
if (block === null)
|
|
310
|
+
if (block === null) {
|
|
311
|
+
continue;
|
|
312
|
+
}
|
|
297
313
|
for (const section of parseCardSections(unwrapMemoryBlock(block))
|
|
298
314
|
.sections) {
|
|
299
315
|
sections.add(section.text);
|
|
@@ -321,7 +337,9 @@ export function stripPrunedCardsFromMessages(
|
|
|
321
337
|
): number {
|
|
322
338
|
let strippedBlocks = 0;
|
|
323
339
|
for (const message of messages) {
|
|
324
|
-
if (message.role !== "user")
|
|
340
|
+
if (message.role !== "user") {
|
|
341
|
+
continue;
|
|
342
|
+
}
|
|
325
343
|
let changed = false;
|
|
326
344
|
const nextContent: ContentBlock[] = [];
|
|
327
345
|
for (const block of message.content) {
|
|
@@ -355,7 +373,9 @@ export function stripPrunedCardsFromMessages(
|
|
|
355
373
|
nextContent.push({ type: "text", text: wrapMemoryBlock(filtered) });
|
|
356
374
|
}
|
|
357
375
|
}
|
|
358
|
-
if (changed)
|
|
376
|
+
if (changed) {
|
|
377
|
+
message.content = nextContent;
|
|
378
|
+
}
|
|
359
379
|
}
|
|
360
380
|
return strippedBlocks;
|
|
361
381
|
}
|
|
@@ -400,7 +420,9 @@ export async function runPruneValve(
|
|
|
400
420
|
): Promise<PrunePlan | null> {
|
|
401
421
|
// Defensive read: test configs may omit the prune block entirely.
|
|
402
422
|
const pruneConfig = getMemoryConfig()?.v3?.prune;
|
|
403
|
-
if (!pruneConfig)
|
|
423
|
+
if (!pruneConfig) {
|
|
424
|
+
return null;
|
|
425
|
+
}
|
|
404
426
|
|
|
405
427
|
// Planning needs only the store (cheap); the persisted-metadata scan for
|
|
406
428
|
// the live strip's ownership test runs only once a plan exists — a
|
|
@@ -413,7 +435,9 @@ export async function runPruneValve(
|
|
|
413
435
|
},
|
|
414
436
|
conversationId,
|
|
415
437
|
);
|
|
416
|
-
if (!plan)
|
|
438
|
+
if (!plan) {
|
|
439
|
+
return null;
|
|
440
|
+
}
|
|
417
441
|
|
|
418
442
|
markPruned(conversationId, plan.slugs, options.now ?? Date.now());
|
|
419
443
|
|
|
@@ -22,12 +22,12 @@ import { isMemoryV3Live } from "../../../../config/memory-v3-gate.js";
|
|
|
22
22
|
import { getDb, getSqliteFrom } from "../../../../persistence/db-connection.js";
|
|
23
23
|
import { memorySqliteOrNull } from "../memory-db.js";
|
|
24
24
|
import { getWorkspaceDir } from "../paths.js";
|
|
25
|
+
import { readPage } from "../substrate/page-store.js";
|
|
25
26
|
import { capabilityOrDiskBody } from "./capabilities.js";
|
|
26
27
|
import { sectionByOrdinal } from "./orchestrate.js";
|
|
27
28
|
import { renderV3SectionContent } from "./page-content.js";
|
|
28
29
|
import { renderMemoryBlock } from "./render-injection.js";
|
|
29
30
|
import { buildSectionIndex } from "./sections.js";
|
|
30
|
-
import { readPage } from "./substrate/page-store.js";
|
|
31
31
|
import {
|
|
32
32
|
type Section,
|
|
33
33
|
SELECTION_SOURCES,
|
|
@@ -63,7 +63,9 @@ function rowsForTurn(conversationId: string, turn: number): SelectionRow[] {
|
|
|
63
63
|
}
|
|
64
64
|
|
|
65
65
|
function rowsForMessageIds(messageIds: string[]): SelectionRow[] {
|
|
66
|
-
if (messageIds.length === 0)
|
|
66
|
+
if (messageIds.length === 0) {
|
|
67
|
+
return [];
|
|
68
|
+
}
|
|
67
69
|
const raw = memorySqliteOrNull("rowsForMessageIds");
|
|
68
70
|
if (!raw) {
|
|
69
71
|
return [];
|
|
@@ -87,7 +89,9 @@ const MAX_FORK_HOPS = 64;
|
|
|
87
89
|
* stamps onto every message a fork copies, for the given message ids.
|
|
88
90
|
*/
|
|
89
91
|
function forkSourceIdsOf(messageIds: string[]): string[] {
|
|
90
|
-
if (messageIds.length === 0)
|
|
92
|
+
if (messageIds.length === 0) {
|
|
93
|
+
return [];
|
|
94
|
+
}
|
|
91
95
|
const placeholders = messageIds.map(() => "?").join(", ");
|
|
92
96
|
const rows = getSqliteFrom(getDb())
|
|
93
97
|
.query(
|
|
@@ -117,10 +121,16 @@ function rowsViaForkSource(messageIds: string[]): SelectionRow[] {
|
|
|
117
121
|
const visited = new Set(messageIds);
|
|
118
122
|
for (let hop = 0; hop < MAX_FORK_HOPS; hop++) {
|
|
119
123
|
const sources = forkSourceIdsOf(frontier).filter((id) => !visited.has(id));
|
|
120
|
-
if (sources.length === 0)
|
|
121
|
-
|
|
124
|
+
if (sources.length === 0) {
|
|
125
|
+
return [];
|
|
126
|
+
}
|
|
127
|
+
for (const id of sources) {
|
|
128
|
+
visited.add(id);
|
|
129
|
+
}
|
|
122
130
|
const rows = rowsForMessageIds(sources);
|
|
123
|
-
if (rows.length > 0)
|
|
131
|
+
if (rows.length > 0) {
|
|
132
|
+
return rows;
|
|
133
|
+
}
|
|
124
134
|
frontier = sources;
|
|
125
135
|
}
|
|
126
136
|
return [];
|
|
@@ -140,7 +150,9 @@ async function reconstructMatchedSections(
|
|
|
140
150
|
const sectionSlugs = rows
|
|
141
151
|
.filter((r) => r.section_ordinal != null)
|
|
142
152
|
.map((r) => r.slug);
|
|
143
|
-
if (sectionSlugs.length === 0)
|
|
153
|
+
if (sectionSlugs.length === 0) {
|
|
154
|
+
return new Map();
|
|
155
|
+
}
|
|
144
156
|
|
|
145
157
|
const workspaceDir = getWorkspaceDir();
|
|
146
158
|
const pageBody = (slug: Slug): Promise<string> =>
|
|
@@ -155,9 +167,13 @@ async function reconstructMatchedSections(
|
|
|
155
167
|
|
|
156
168
|
const sectionBySlug = new Map<Slug, Section>();
|
|
157
169
|
for (const row of rows) {
|
|
158
|
-
if (row.section_ordinal == null)
|
|
170
|
+
if (row.section_ordinal == null) {
|
|
171
|
+
continue;
|
|
172
|
+
}
|
|
159
173
|
const section = sectionByOrdinal(index, row.slug, row.section_ordinal);
|
|
160
|
-
if (section)
|
|
174
|
+
if (section) {
|
|
175
|
+
sectionBySlug.set(row.slug, section);
|
|
176
|
+
}
|
|
161
177
|
}
|
|
162
178
|
return sectionBySlug;
|
|
163
179
|
}
|
|
@@ -165,7 +181,9 @@ async function reconstructMatchedSections(
|
|
|
165
181
|
async function buildSelectionLog(
|
|
166
182
|
rows: SelectionRow[],
|
|
167
183
|
): Promise<MemoryV3SelectionLog | null> {
|
|
168
|
-
if (rows.length === 0)
|
|
184
|
+
if (rows.length === 0) {
|
|
185
|
+
return null;
|
|
186
|
+
}
|
|
169
187
|
|
|
170
188
|
const config = getConfig();
|
|
171
189
|
const selections = rows.map((r) => ({
|
|
@@ -226,7 +244,9 @@ export async function getMemoryV3SelectionForInspector(
|
|
|
226
244
|
conversationId: string,
|
|
227
245
|
turn: number | null | undefined,
|
|
228
246
|
): Promise<MemoryV3SelectionLog | null> {
|
|
229
|
-
if (turn == null)
|
|
247
|
+
if (turn == null) {
|
|
248
|
+
return null;
|
|
249
|
+
}
|
|
230
250
|
return buildSelectionLog(rowsForTurn(conversationId, turn));
|
|
231
251
|
}
|
|
232
252
|
|
|
@@ -280,7 +300,9 @@ export function summarizeSelections(conversationId: string): SelectionSummary {
|
|
|
280
300
|
const turns = new Set<number>();
|
|
281
301
|
const slugs = new Set<string>();
|
|
282
302
|
for (const row of rows) {
|
|
283
|
-
if (isSelectionSource(row.source))
|
|
303
|
+
if (isSelectionSource(row.source)) {
|
|
304
|
+
bySource[row.source] += 1;
|
|
305
|
+
}
|
|
284
306
|
turns.add(row.turn);
|
|
285
307
|
slugs.add(row.slug);
|
|
286
308
|
}
|
|
@@ -32,6 +32,7 @@ import {
|
|
|
32
32
|
} from "@vellumai/plugin-api";
|
|
33
33
|
|
|
34
34
|
import { getConfig } from "../../../../config/loader.js";
|
|
35
|
+
import { isMemoryEnabled } from "../../../../config/memory-v3-gate.js";
|
|
35
36
|
import type { AssistantConfig } from "../../../../config/schema.js";
|
|
36
37
|
import {
|
|
37
38
|
recordLatencySubSpan,
|
|
@@ -41,6 +42,8 @@ import { stripCommentLines } from "../host-utils.js";
|
|
|
41
42
|
import { getLogger } from "../logging.js";
|
|
42
43
|
import { memorySqliteOrNull } from "../memory-db.js";
|
|
43
44
|
import { getWorkspaceDir, getWorkspacePromptPath } from "../paths.js";
|
|
45
|
+
import { getPageIndex, invalidatePageIndex } from "../substrate/page-index.js";
|
|
46
|
+
import { readPage, renderPageContent } from "../substrate/page-store.js";
|
|
44
47
|
import {
|
|
45
48
|
capabilityOrDiskBody,
|
|
46
49
|
renderCapabilityContent,
|
|
@@ -53,7 +56,6 @@ import type { EntityIndex } from "./entity-lane.js";
|
|
|
53
56
|
import { buildEntityIndex } from "./entity-lane.js";
|
|
54
57
|
import { getActiveSlugs } from "./ever-injected-store.js";
|
|
55
58
|
import { computeFreshSet } from "./fresh-set.js";
|
|
56
|
-
import { isMemoryV3InjectionGateEnabled } from "./gate-flag.js";
|
|
57
59
|
import { computeHotSet } from "./hot-set.js";
|
|
58
60
|
import { bumpLanesVersion, readLanesVersion } from "./lanes-version-store.js";
|
|
59
61
|
import { computeLearnedEdgeGraph } from "./learned-edges.js";
|
|
@@ -67,8 +69,6 @@ import { ensureSectionCollection } from "./section-dense-store.js";
|
|
|
67
69
|
import type { SectionNeedle } from "./section-needle.js";
|
|
68
70
|
import { buildSectionNeedle } from "./section-needle.js";
|
|
69
71
|
import { buildSectionIndex } from "./sections.js";
|
|
70
|
-
import { getPageIndex, invalidatePageIndex } from "./substrate/page-index.js";
|
|
71
|
-
import { readPage, renderPageContent } from "./substrate/page-store.js";
|
|
72
72
|
import { resolveV3Tuning } from "./tuning-profile.js";
|
|
73
73
|
import {
|
|
74
74
|
type MemoryRoutingTurn,
|
|
@@ -690,7 +690,7 @@ export async function observeTurn(
|
|
|
690
690
|
}
|
|
691
691
|
|
|
692
692
|
const cfg = getConfig();
|
|
693
|
-
if (cfg
|
|
693
|
+
if (!isMemoryEnabled(cfg)) {
|
|
694
694
|
return null;
|
|
695
695
|
}
|
|
696
696
|
// Lane init is module-memoized: the first turn after daemon start pays
|
|
@@ -702,10 +702,6 @@ export async function observeTurn(
|
|
|
702
702
|
() => getLanes(cfg),
|
|
703
703
|
);
|
|
704
704
|
const v3 = cfg.memory.v3;
|
|
705
|
-
// Resolve the effective gate enable once for the turn: the feature flag
|
|
706
|
-
// AND the `memory.v3.gate.enabled` config kill-switch. Tuning lives in
|
|
707
|
-
// `memory.v3.gate`.
|
|
708
|
-
const gateEnabled = isMemoryV3InjectionGateEnabled(cfg);
|
|
709
705
|
// Re-resolve the corpus-adaptive tuning each turn from the CURRENT config
|
|
710
706
|
// (with the lane-build corpus-size signal) so a live config.json edit to a
|
|
711
707
|
// per-turn knob (selectorEnabled, denseK, replyQueryK, edge.*) takes effect
|
|
@@ -733,6 +729,7 @@ export async function observeTurn(
|
|
|
733
729
|
activeSlugs: getActiveSlugs(conversationId),
|
|
734
730
|
entityCap: v3.entity.cap,
|
|
735
731
|
replyQueryK: tuning.replyQueryK,
|
|
732
|
+
spanQueryK: tuning.spanQueryK,
|
|
736
733
|
edgeSeeds: tuning.edgeSeedCount,
|
|
737
734
|
edgePerSeed: tuning.edgePerSeed,
|
|
738
735
|
edgeCap: tuning.edgeCap,
|
|
@@ -744,11 +741,10 @@ export async function observeTurn(
|
|
|
744
741
|
v3.selectorPromptPath,
|
|
745
742
|
getWorkspaceDir(),
|
|
746
743
|
),
|
|
747
|
-
// Per-turn injection gate: the `memory.v3.gate` tuning
|
|
748
|
-
//
|
|
749
|
-
//
|
|
750
|
-
|
|
751
|
-
gateConfig: { ...v3.gate, enabled: gateEnabled },
|
|
744
|
+
// Per-turn injection gate: the `memory.v3.gate` tuning, `enabled`
|
|
745
|
+
// kill-switch included. Read-only downstream, so the config object is
|
|
746
|
+
// passed as-is.
|
|
747
|
+
gateConfig: v3.gate,
|
|
752
748
|
});
|
|
753
749
|
|
|
754
750
|
// A zero-selection turn over a non-trivial pool is unusual enough to be
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { describe, expect, test } from "bun:test";
|
|
2
|
+
|
|
3
|
+
import { MAX_SPAN_CHUNKS, spanChunksOf } from "./span-query.js";
|
|
4
|
+
|
|
5
|
+
describe("spanChunksOf", () => {
|
|
6
|
+
test("short message passes through as its clause spans", () => {
|
|
7
|
+
const chunks = spanChunksOf(
|
|
8
|
+
"the first sentence is here. and a second sentence follows!",
|
|
9
|
+
);
|
|
10
|
+
expect(chunks).toEqual([
|
|
11
|
+
"the first sentence is here.",
|
|
12
|
+
"and a second sentence follows!",
|
|
13
|
+
]);
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
test("newlines split spans like sentence punctuation", () => {
|
|
17
|
+
const chunks = spanChunksOf(
|
|
18
|
+
"a line without terminal punctuation\nanother line of the message",
|
|
19
|
+
);
|
|
20
|
+
expect(chunks).toEqual([
|
|
21
|
+
"a line without terminal punctuation",
|
|
22
|
+
"another line of the message",
|
|
23
|
+
]);
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
test("sub-15-char fragments are dropped", () => {
|
|
27
|
+
const chunks = spanChunksOf("ok. this sentence is long enough to keep.");
|
|
28
|
+
expect(chunks).toEqual(["this sentence is long enough to keep."]);
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
test("empty and whitespace-only messages yield no chunks", () => {
|
|
32
|
+
expect(spanChunksOf("")).toEqual([]);
|
|
33
|
+
expect(spanChunksOf(" \n\n ")).toEqual([]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test("fullwidth CJK terminators split without trailing whitespace", () => {
|
|
37
|
+
const chunks = spanChunksOf(
|
|
38
|
+
"这是消息里的第一句完整的话。这是紧跟着的第二句完整的话!第三句也一样长够十五个字符?",
|
|
39
|
+
);
|
|
40
|
+
expect(chunks).toEqual([
|
|
41
|
+
"这是消息里的第一句完整的话。",
|
|
42
|
+
"这是紧跟着的第二句完整的话!",
|
|
43
|
+
"第三句也一样长够十五个字符?",
|
|
44
|
+
]);
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
test("non-ASCII spaced terminators split like ASCII ones", () => {
|
|
48
|
+
const chunks = spanChunksOf(
|
|
49
|
+
"पहला वाक्य यहाँ लिखा गया है। दूसरा वाक्य भी यहाँ मौजूद है।",
|
|
50
|
+
);
|
|
51
|
+
expect(chunks).toEqual([
|
|
52
|
+
"पहला वाक्य यहाँ लिखा गया है।",
|
|
53
|
+
"दूसरा वाक्य भी यहाँ मौजूद है।",
|
|
54
|
+
]);
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
test("ASCII periods still do not split decimals or dotted numbers", () => {
|
|
58
|
+
expect(spanChunksOf("the value came out to 3.14159 in the final run.")) //
|
|
59
|
+
.toEqual(["the value came out to 3.14159 in the final run."]);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
test("a message at the cap is returned unchanged", () => {
|
|
63
|
+
const sentences = Array.from(
|
|
64
|
+
{ length: MAX_SPAN_CHUNKS },
|
|
65
|
+
(_, i) => `sentence number ${i} padded for length.`,
|
|
66
|
+
);
|
|
67
|
+
expect(spanChunksOf(sentences.join(" "))).toEqual(sentences);
|
|
68
|
+
});
|
|
69
|
+
|
|
70
|
+
test("over-cap messages merge into ≤cap contiguous chunks covering every span", () => {
|
|
71
|
+
const sentences = Array.from(
|
|
72
|
+
{ length: 30 },
|
|
73
|
+
(_, i) => `sentence number ${i} padded for length.`,
|
|
74
|
+
);
|
|
75
|
+
const chunks = spanChunksOf(sentences.join(" "));
|
|
76
|
+
expect(chunks.length).toBe(MAX_SPAN_CHUNKS);
|
|
77
|
+
// Contiguous coverage: rejoining the chunks reproduces every span in order.
|
|
78
|
+
expect(chunks.join(" ")).toBe(sentences.join(" "));
|
|
79
|
+
// Near-equal partition: no chunk hoards spans (30/8 → sizes 3 or 4).
|
|
80
|
+
for (const chunk of chunks) {
|
|
81
|
+
const n = chunk.match(/sentence number/g)?.length ?? 0;
|
|
82
|
+
expect(n).toBeGreaterThanOrEqual(3);
|
|
83
|
+
expect(n).toBeLessThanOrEqual(4);
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
});
|