@vellumai/assistant 0.8.5 → 0.8.6
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 +33 -1
- package/ARCHITECTURE.md +1 -1
- package/bunfig.toml +6 -1
- package/docs/credential-execution-service.md +6 -6
- package/docs/plugins.md +4 -3
- package/node_modules/@vellumai/skill-host-contracts/src/client.ts +12 -13
- package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +4 -1
- package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +16 -14
- package/openapi.yaml +1900 -166
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +3 -2
- package/src/__tests__/agent-loop-exit-reason.test.ts +102 -9
- package/src/__tests__/agent-loop-override-profile.test.ts +2 -1
- package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +1 -0
- package/src/__tests__/agent-wake-override-profile.test.ts +1 -0
- package/src/__tests__/always-loaded-tools-guard.test.ts +2 -2
- package/src/__tests__/annotate-risk-options.test.ts +1 -0
- package/src/__tests__/approval-cascade.test.ts +1 -0
- package/src/__tests__/approval-routes-http.test.ts +9 -13
- package/src/__tests__/assert-not-live-db.ts +79 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +9 -25
- package/src/__tests__/audit-log-rotation.test.ts +2 -2
- package/src/__tests__/auto-analysis-end-to-end.test.ts +6 -6
- package/src/__tests__/background-workers-disk-pressure.test.ts +5 -8
- package/src/__tests__/browser-skill-endstate.test.ts +3 -3
- package/src/__tests__/btw-routes.test.ts +3 -2
- package/src/__tests__/call-controller.test.ts +3 -2
- package/src/__tests__/channel-approval-routes.test.ts +3 -2
- package/src/__tests__/channel-guardian.test.ts +3 -2
- package/src/__tests__/channel-readiness-slack-remote.test.ts +175 -0
- package/src/__tests__/channel-reply-delivery.test.ts +35 -0
- package/src/__tests__/channel-retry-sweep.test.ts +320 -3
- package/src/__tests__/checker.test.ts +12 -12
- package/src/__tests__/compaction-events.test.ts +1 -0
- package/src/__tests__/compaction-trail-store.test.ts +264 -0
- package/src/__tests__/compactor-call-site-logging.test.ts +1 -0
- package/src/__tests__/compactor-preserved-tail-count.test.ts +1 -0
- package/src/__tests__/computer-use-skill-manifest-regression.test.ts +7 -5
- package/src/__tests__/computer-use-tools.test.ts +12 -14
- package/src/__tests__/config-loader-backfill.test.ts +13 -28
- package/src/__tests__/config-loader-corrupt.test.ts +5 -5
- package/src/__tests__/config-loader-platform-defaults.test.ts +93 -26
- package/src/__tests__/config-loader-quarantine-bulletin.test.ts +3 -3
- package/src/__tests__/config-managed-gemini-defaults.test.ts +3 -4
- package/src/__tests__/config-schema.test.ts +10 -10
- package/src/__tests__/connection-model-compat.test.ts +83 -0
- package/src/__tests__/contacts-tools.test.ts +3 -2
- package/src/__tests__/context-token-estimator.test.ts +22 -0
- package/src/__tests__/conversation-abort-tool-results.test.ts +5 -0
- package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-handlers-max-tokens.test.ts +55 -0
- package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +34 -0
- package/src/__tests__/conversation-agent-loop.test.ts +488 -2
- package/src/__tests__/conversation-analysis-routes.test.ts +1 -0
- package/src/__tests__/conversation-app-control-instantiation.test.ts +29 -19
- package/src/__tests__/conversation-app-control-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-attention-store.test.ts +101 -0
- package/src/__tests__/conversation-attention-telegram.test.ts +3 -2
- package/src/__tests__/conversation-confirmation-signals.test.ts +1 -0
- package/src/__tests__/conversation-error.test.ts +30 -0
- package/src/__tests__/conversation-fork-crud.test.ts +69 -8
- package/src/__tests__/conversation-fork-route.test.ts +3 -2
- package/src/__tests__/conversation-history-web-search.test.ts +1 -0
- package/src/__tests__/conversation-inference-profile-list.test.ts +3 -2
- package/src/__tests__/conversation-inference-profile-route.test.ts +3 -2
- package/src/__tests__/conversation-lifecycle.test.ts +1 -0
- package/src/__tests__/conversation-list-source.test.ts +3 -2
- package/src/__tests__/conversation-load-history-repair.test.ts +2 -1
- package/src/__tests__/conversation-load-history-stripped.test.ts +1 -0
- package/src/__tests__/conversation-pairing.test.ts +53 -0
- package/src/__tests__/conversation-process-app-control-preactivation.test.ts +26 -7
- package/src/__tests__/conversation-process-callsite.test.ts +1 -0
- package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -0
- package/src/__tests__/conversation-queue.test.ts +333 -291
- package/src/__tests__/conversation-routes-disk-view.test.ts +3 -18
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +33 -8
- package/src/__tests__/conversation-routes-slash-commands.test.ts +33 -2
- package/src/__tests__/conversation-runtime-assembly.test.ts +78 -0
- package/src/__tests__/conversation-skill-tools.test.ts +38 -142
- package/src/__tests__/conversation-slash-queue.test.ts +84 -32
- package/src/__tests__/conversation-slash-unknown.test.ts +5 -0
- package/src/__tests__/conversation-speed-override.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-action-delivery.test.ts +46 -0
- package/src/__tests__/conversation-surfaces-data-persist.test.ts +1 -0
- package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-standalone.test.ts +6 -3
- package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -3
- package/src/__tests__/conversation-surfaces-table-action.test.ts +7 -17
- package/src/__tests__/conversation-sync-tags.test.ts +128 -12
- package/src/__tests__/conversation-title-service.test.ts +1 -0
- package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +30 -0
- package/src/__tests__/conversation-usage.test.ts +1 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +1 -0
- package/src/__tests__/conversation-workspace-injection.test.ts +5 -0
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -0
- package/src/__tests__/credential-broker-browser-fill.test.ts +3 -3
- package/src/__tests__/credential-broker-server-use.test.ts +5 -5
- package/src/__tests__/credential-execution-client.test.ts +72 -1
- package/src/__tests__/credential-execution-feature-gates.test.ts +10 -12
- package/src/__tests__/credential-health-service.test.ts +252 -3
- package/src/__tests__/credential-security-invariants.test.ts +5 -5
- package/src/__tests__/credential-vault-unit.test.ts +19 -19
- package/src/__tests__/credential-vault.test.ts +5 -5
- package/src/__tests__/cross-provider-web-search.test.ts +56 -2
- package/src/__tests__/db-connection-isolation.test.ts +7 -6
- package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +8 -10
- package/src/__tests__/db-conversation-inference-profile-migration.test.ts +7 -10
- package/src/__tests__/db-llm-request-log-provider-migration.test.ts +9 -15
- package/src/__tests__/db-test-helpers.ts +58 -0
- package/src/__tests__/disk-pressure-guard.test.ts +58 -41
- package/src/__tests__/disk-pressure-lifecycle.test.ts +13 -10
- package/src/__tests__/disk-pressure-routes.test.ts +0 -33
- package/src/__tests__/disk-pressure-tools.test.ts +0 -4
- package/src/__tests__/dm-persistence.test.ts +26 -40
- package/src/__tests__/document-create-dedupe.test.ts +189 -0
- package/src/__tests__/document-find-replace.test.ts +3 -2
- package/src/__tests__/document-tool-security.test.ts +81 -2
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +5 -4
- package/src/__tests__/encrypted-store-test-helpers.ts +56 -0
- package/src/__tests__/encrypted-store.test.ts +11 -9
- package/src/__tests__/feature-flag-test-helpers.ts +53 -0
- package/src/__tests__/filing-service.test.ts +1 -0
- package/src/__tests__/first-greeting.test.ts +62 -12
- package/src/__tests__/gateway-flag-listener.test.ts +0 -1
- package/src/__tests__/gemini-provider.test.ts +26 -0
- package/src/__tests__/guardian-action-sweep.test.ts +3 -2
- package/src/__tests__/guardian-outbound-http.test.ts +3 -2
- package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +48 -3
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +1 -0
- package/src/__tests__/heartbeat-disk-pressure.test.ts +1 -0
- package/src/__tests__/heartbeat-service.test.ts +1 -0
- package/src/__tests__/helpers/mock-logger.ts +26 -0
- package/src/__tests__/host-bash-routes.test.ts +1 -0
- package/src/__tests__/host-cu-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-file-routes-targeted.test.ts +1 -0
- package/src/__tests__/host-shell-tool.test.ts +5 -4
- package/src/__tests__/host-transfer-routes-targeted.test.ts +1 -0
- package/src/__tests__/http-conversation-lineage.test.ts +3 -2
- package/src/__tests__/http-user-message-parity.test.ts +29 -7
- package/src/__tests__/identity-intro-cache.test.ts +133 -22
- package/src/__tests__/inbound-slack-persistence.test.ts +44 -72
- package/src/__tests__/inference-profile-reaper.test.ts +3 -2
- package/src/__tests__/inference-profile-session-ipc.test.ts +3 -2
- package/src/__tests__/injector-disk-pressure.test.ts +3 -17
- package/src/__tests__/inline-skill-load-permissions.test.ts +4 -4
- package/src/__tests__/list-messages-hidden-metadata.test.ts +80 -0
- package/src/__tests__/llm-context-normalization.test.ts +42 -0
- package/src/__tests__/llm-resolver.test.ts +331 -0
- package/src/__tests__/llm-schema.test.ts +1 -1
- package/src/__tests__/manual-token-reconciliation.test.ts +76 -1
- package/src/__tests__/mcp-abort-signal.test.ts +14 -0
- package/src/__tests__/mcp-client-auth.test.ts +14 -0
- package/src/__tests__/messaging-send-tool.test.ts +1 -0
- package/src/__tests__/migration-import-from-url.test.ts +3 -3
- package/src/__tests__/mock-gateway-ipc.ts +18 -2
- package/src/__tests__/model-intents.test.ts +3 -3
- package/src/__tests__/native-web-search.test.ts +30 -2
- package/src/__tests__/notification-deep-link.test.ts +62 -0
- package/src/__tests__/oauth-commands-routes.test.ts +37 -0
- package/src/__tests__/oauth-provider-visibility.test.ts +8 -8
- package/src/__tests__/oauth-store.test.ts +3 -2
- package/src/__tests__/onboarding-template-contract.test.ts +3 -2
- package/src/__tests__/openai-provider.test.ts +8 -9
- package/src/__tests__/openai-responses-provider.test.ts +70 -10
- package/src/__tests__/openrouter-provider-only.test.ts +27 -5
- package/src/__tests__/outbound-slack-persistence.test.ts +46 -1
- package/src/__tests__/persistence-pipeline.test.ts +139 -1
- package/src/__tests__/persistence-secret-redaction.test.ts +83 -12
- package/src/__tests__/plugin-bootstrap.test.ts +9 -11
- package/src/__tests__/plugin-tool-contribution.test.ts +41 -38
- package/src/__tests__/process-message-background-slack.test.ts +21 -16
- package/src/__tests__/process-message-display-content.test.ts +19 -22
- package/src/__tests__/provider-catalog-visibility.test.ts +9 -9
- package/src/__tests__/provider-platform-proxy-integration.test.ts +216 -4
- package/src/__tests__/provider-registry-ollama.test.ts +45 -22
- package/src/__tests__/recording-handler.test.ts +1 -0
- package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +1 -0
- package/src/__tests__/registry.test.ts +82 -76
- package/src/__tests__/relay-server.test.ts +10 -10
- package/src/__tests__/runtime-attachment-metadata.test.ts +3 -2
- package/src/__tests__/schedule-store.test.ts +16 -1
- package/src/__tests__/scheduler-reuse-conversation.test.ts +48 -3
- package/src/__tests__/secret-ingress-http.test.ts +5 -1
- package/src/__tests__/secure-keys.test.ts +3 -3
- package/src/__tests__/send-endpoint-busy.test.ts +81 -42
- package/src/__tests__/server-history-render.test.ts +4 -1
- package/src/__tests__/skill-feature-flags-integration.test.ts +8 -10
- package/src/__tests__/skill-feature-flags.test.ts +14 -16
- package/src/__tests__/skill-load-feature-flag.test.ts +5 -5
- package/src/__tests__/skill-projection-feature-flag.test.ts +44 -30
- package/src/__tests__/skill-projection.benchmark.test.ts +5 -7
- package/src/__tests__/skill-tool-factory.test.ts +96 -95
- package/src/__tests__/slack-channel-config.test.ts +3 -3
- package/src/__tests__/subagent-call-site-routing.test.ts +11 -3
- package/src/__tests__/subagent-disposal.test.ts +27 -8
- package/src/__tests__/subagent-fork-notifications.test.ts +24 -9
- package/src/__tests__/subagent-fork-spawn.test.ts +13 -4
- package/src/__tests__/subagent-manager-notify.test.ts +20 -8
- package/src/__tests__/subagent-notify-parent.test.ts +5 -4
- package/src/__tests__/subagent-spawn-tool-fork.test.ts +58 -0
- package/src/__tests__/subagent-tools.test.ts +2 -1
- package/src/__tests__/suggestion-routes.test.ts +1 -0
- package/src/__tests__/system-prompt.test.ts +38 -0
- package/src/__tests__/test-preload-verifier.ts +68 -0
- package/src/__tests__/test-preload.ts +32 -39
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +20 -7
- package/src/__tests__/tool-executor.test.ts +55 -10
- package/src/__tests__/tool-preview-lifecycle.test.ts +1 -0
- package/src/__tests__/tool-result-metadata-plumbing.test.ts +1 -0
- package/src/__tests__/twilio-routes.test.ts +3 -2
- package/src/__tests__/validate-input.test.ts +381 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -0
- package/src/__tests__/voice-scoped-grant-consumer.test.ts +2 -1
- package/src/__tests__/voice-session-bridge.test.ts +37 -28
- package/src/__tests__/workspace-migration-090-memory-router-cost-optimized-profile.test.ts +326 -0
- package/src/__tests__/workspace-migration-091-retighten-migration-onboarding-thread.test.ts +166 -0
- package/src/acp/session-manager.ts +5 -6
- package/src/agent/loop.ts +80 -0
- package/src/api/README.md +124 -2
- package/src/api/constants/call-sites.ts +27 -0
- package/src/api/events/assistant-outbound-attachment.ts +51 -0
- package/src/api/events/assistant-text-delta.ts +32 -0
- package/src/api/events/assistant-turn-start.ts +33 -0
- package/src/api/events/document-comment-created.ts +48 -0
- package/src/api/events/document-comment-deleted.ts +24 -0
- package/src/api/events/document-comment-reopened.ts +25 -0
- package/src/api/events/document-comment-resolved.ts +27 -0
- package/src/api/events/generation-cancelled.ts +24 -0
- package/src/api/events/generation-handoff.ts +41 -0
- package/src/api/events/message-complete.ts +42 -0
- package/src/api/events/open-url.ts +30 -0
- package/src/{events → api/events}/relationship-state-updated.ts +3 -3
- package/src/api/events/tool-use-start.ts +32 -0
- package/src/api/index.ts +128 -3
- package/src/api/responses/llm-context-response.ts +39 -0
- package/src/api/responses/llm-request-log-entry.ts +93 -0
- package/src/api/responses/memory-recall-log.ts +65 -0
- package/src/api/responses/memory-v2-activation-log.ts +78 -0
- package/src/background-wake/background-wake-routes.test.ts +687 -52
- package/src/background-wake/platform-client.test.ts +308 -0
- package/src/background-wake/platform-client.ts +167 -0
- package/src/background-wake/publisher.ts +91 -0
- package/src/background-wake/runtime-registry.ts +2 -2
- package/src/background-wake/wake-intent-hooks.test.ts +282 -0
- package/src/calls/guardian-dispatch.ts +1 -0
- package/src/calls/voice-session-bridge.ts +4 -4
- package/src/cli/commands/__tests__/conversations-slack.test.ts +16 -0
- package/src/cli/commands/__tests__/notifications.test.ts +184 -40
- package/src/cli/commands/channels/__tests__/channels.test.ts +143 -0
- package/src/cli/commands/channels/index.ts +229 -0
- package/src/cli/commands/memory-v3-render.ts +147 -0
- package/src/cli/commands/memory-v3.ts +255 -4
- package/src/cli/commands/notifications.ts +365 -55
- package/src/cli/lib/open-browser.ts +7 -2
- package/src/cli/program.ts +2 -0
- package/src/config/assistant-feature-flags.ts +23 -42
- package/src/config/bundled-skills/document-editor/SKILL.md +5 -1
- package/src/config/bundled-skills/schedule/SKILL.md +1 -1
- package/src/config/bundled-skills/schedule/TOOLS.json +2 -2
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -0
- package/src/config/call-site-defaults.ts +1 -1
- package/src/config/feature-flag-cache.ts +86 -0
- package/src/config/feature-flag-registry.json +17 -17
- package/src/config/llm-context-resolution.ts +10 -1
- package/src/config/llm-resolver.ts +121 -15
- package/src/config/loader.ts +4 -5
- package/src/config/schemas/__tests__/memory-v2.test.ts +15 -0
- package/src/config/schemas/heartbeat.ts +1 -1
- package/src/config/schemas/llm.ts +90 -1
- package/src/config/schemas/memory-v2.ts +26 -0
- package/src/config/schemas/services.ts +6 -2
- package/src/config/seed-inference-profiles.ts +36 -16
- package/src/context/token-estimator.ts +10 -5
- package/src/credential-execution/executable-discovery.ts +40 -0
- package/src/credential-execution/process-manager.ts +6 -2
- package/src/credential-health/credential-health-service.ts +125 -40
- package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +3 -6
- package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +13 -15
- package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +1 -2
- package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -0
- package/src/daemon/__tests__/meet-manifest-loader.test.ts +25 -12
- package/src/daemon/__tests__/native-web-search-metadata.test.ts +1 -0
- package/src/daemon/__tests__/switch-inference-profile-tool.test.ts +107 -0
- package/src/daemon/__tests__/web-search-status-text.test.ts +1 -0
- package/src/daemon/conversation-agent-loop-handlers.ts +389 -68
- package/src/daemon/conversation-agent-loop.ts +132 -28
- package/src/daemon/conversation-error.ts +33 -5
- package/src/daemon/conversation-messaging.ts +84 -43
- package/src/daemon/conversation-process.ts +74 -37
- package/src/daemon/conversation-runtime-assembly.ts +29 -9
- package/src/daemon/conversation-skill-tools.ts +14 -30
- package/src/daemon/conversation-surfaces.ts +69 -34
- package/src/daemon/conversation-tool-setup.ts +33 -48
- package/src/daemon/conversation.ts +26 -46
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/daemon-skill-host.ts +9 -2
- package/src/daemon/disk-pressure-guard.ts +27 -29
- package/src/daemon/first-greeting.ts +31 -13
- package/src/daemon/handlers/shared.ts +6 -1
- package/src/daemon/lifecycle.ts +12 -12
- package/src/daemon/mcp-reload-service.ts +1 -1
- package/src/daemon/meet-manifest-loader.ts +10 -17
- package/src/daemon/message-types/conversations.ts +20 -22
- package/src/daemon/message-types/document-comments.ts +8 -44
- package/src/daemon/message-types/home.ts +2 -2
- package/src/daemon/message-types/integrations.ts +2 -7
- package/src/daemon/message-types/messages.ts +23 -38
- package/src/daemon/message-types/subagents.ts +6 -0
- package/src/daemon/process-message.ts +9 -9
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +16 -0
- package/src/daemon/switch-inference-profile-tool.ts +13 -3
- package/src/daemon/tool-setup-types.ts +0 -6
- package/src/daemon/wake-target-adapter.ts +10 -0
- package/src/documents/document-store.ts +38 -0
- package/src/export/__tests__/transcript-formatter.test.ts +1 -0
- package/src/heartbeat/__tests__/heartbeat-service.test.ts +29 -0
- package/src/heartbeat/heartbeat-service.ts +63 -0
- package/src/home/__tests__/feed-writer.test.ts +161 -0
- package/src/home/__tests__/post-connect-feed.test.ts +1 -0
- package/src/home/__tests__/suggested-prompts.test.ts +55 -59
- package/src/home/feed-writer.ts +146 -7
- package/src/home/suggested-prompts.ts +27 -145
- package/src/ipc/__tests__/cli-ipc.test.ts +1 -0
- package/src/ipc/gateway-client.test.ts +4 -1
- package/src/ipc/skill-routes/__tests__/memory.test.ts +1 -0
- package/src/ipc/skill-routes/__tests__/registries.test.ts +36 -7
- package/src/ipc/skill-routes/memory.ts +4 -3
- package/src/ipc/skill-routes/registries.ts +28 -29
- package/src/memory/__tests__/jobs-store-enqueue-gate.test.ts +1 -0
- package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +26 -5
- package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-job.test.ts +1 -0
- package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +1 -0
- package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +31 -0
- package/src/memory/conversation-attention-store.ts +17 -3
- package/src/memory/conversation-crud.ts +352 -112
- package/src/memory/db-connection.ts +29 -19
- package/src/memory/db-init.ts +4 -0
- package/src/memory/db-singleton.ts +77 -0
- package/src/memory/delivery-channels.ts +82 -0
- package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +2 -4
- package/src/memory/graph/retriever.test.ts +3 -3
- package/src/memory/job-handlers/embedding.test.ts +3 -2
- package/src/memory/jobs/__tests__/embed-concept-page.test.ts +5 -2
- package/src/memory/jobs-worker.ts +12 -1
- package/src/memory/llm-request-log-source-clickhouse.ts +80 -0
- package/src/memory/llm-request-log-source-local.ts +24 -0
- package/src/memory/llm-request-log-source.ts +31 -0
- package/src/memory/llm-request-log-store.ts +188 -3
- package/src/memory/memory-v2-activation-log-store.ts +95 -1
- package/src/memory/migrations/265-drop-provider-connection-status.ts +26 -0
- package/src/memory/migrations/266-messages-client-message-id.ts +43 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema/conversations.ts +9 -1
- package/src/memory/schema/inference.ts +0 -1
- package/src/memory/v2/__tests__/backfill-jobs.test.ts +5 -2
- package/src/memory/v2/__tests__/harness-metrics.test.ts +9 -0
- package/src/memory/v2/__tests__/harness-replay-input.test.ts +9 -4
- package/src/memory/v2/__tests__/harness-runner.test.ts +26 -0
- package/src/memory/v2/__tests__/sweep-job.test.ts +6 -3
- package/src/memory/v2/harness/metrics.ts +5 -1
- package/src/memory/v2/harness/replay-input.ts +19 -3
- package/src/memory/v2/harness/runner.ts +6 -0
- package/src/memory/v2/harness/trace.ts +6 -0
- package/src/memory/v3/__tests__/consolidation-job.test.ts +2 -4
- package/src/memory/v3/__tests__/coretrieval-seed.test.ts +270 -0
- package/src/memory/v3/__tests__/edges.test.ts +144 -1
- package/src/memory/v3/__tests__/filter.test.ts +48 -0
- package/src/memory/v3/__tests__/gate.test.ts +96 -33
- package/src/memory/v3/__tests__/index-composition.test.ts +58 -0
- package/src/memory/v3/__tests__/loop.test.ts +250 -5
- package/src/memory/v3/__tests__/scouts.test.ts +49 -0
- package/src/memory/v3/__tests__/shadow-diff.test.ts +225 -0
- package/src/memory/v3/__tests__/shadow-middleware.test.ts +88 -2
- package/src/memory/v3/__tests__/traversal.test.ts +39 -0
- package/src/memory/v3/__tests__/tree-walk.test.ts +77 -0
- package/src/memory/v3/__tests__/validate.test.ts +32 -0
- package/src/memory/v3/coretrieval-seed.ts +240 -0
- package/src/memory/v3/edges.ts +58 -21
- package/src/memory/v3/filter.ts +27 -22
- package/src/memory/v3/gate.ts +51 -36
- package/src/memory/v3/index-composition.ts +18 -5
- package/src/memory/v3/loop.ts +65 -17
- package/src/memory/v3/scouts.ts +15 -4
- package/src/memory/v3/shadow-diff.ts +287 -0
- package/src/memory/v3/shadow-middleware.ts +44 -2
- package/src/memory/v3/traversal.ts +6 -1
- package/src/memory/v3/tree-walk.ts +6 -1
- package/src/memory/v3/validate.ts +56 -33
- package/src/notifications/__tests__/emit-signal-home-feed.test.ts +1 -0
- package/src/notifications/__tests__/home-feed-side-effect.test.ts +1 -0
- package/src/notifications/adapters/slack.ts +45 -11
- package/src/notifications/broadcaster.ts +114 -63
- package/src/notifications/conversation-pairing.ts +23 -3
- package/src/notifications/decisions-store.ts +32 -1
- package/src/notifications/deliveries-store.ts +45 -0
- package/src/notifications/edit-notification.ts +201 -0
- package/src/notifications/emit-signal.ts +11 -1
- package/src/notifications/signal.ts +10 -0
- package/src/notifications/types.ts +37 -0
- package/src/oauth/byo-connection.test.ts +67 -3
- package/src/oauth/byo-connection.ts +32 -5
- package/src/oauth/connect-orchestrator.ts +9 -0
- package/src/oauth/connection-resolver.test.ts +76 -0
- package/src/oauth/connection-resolver.ts +49 -10
- package/src/oauth/manual-token-connection.ts +51 -3
- package/src/oauth/seed-providers.ts +3 -0
- package/src/permissions/approval-policy.test.ts +19 -5
- package/src/permissions/approval-policy.ts +14 -3
- package/src/permissions/checker.ts +21 -8
- package/src/platform/client.test.ts +24 -1
- package/src/platform/client.ts +8 -0
- package/src/platform/feature-gate.ts +15 -0
- package/src/plugins/defaults/injectors.ts +2 -8
- package/src/plugins/defaults/persistence.ts +25 -6
- package/src/plugins/types.ts +57 -13
- package/src/proactive-artifact/job.test.ts +1 -0
- package/src/prompts/__tests__/system-prompt.test.ts +4 -4
- package/src/prompts/system-prompt.ts +38 -40
- package/src/prompts/template-detection.ts +10 -4
- package/src/prompts/templates/BOOTSTRAP.md +7 -11
- package/src/prompts/templates/IDENTITY.md +0 -2
- package/src/providers/__tests__/connection-model-compat.test.ts +3 -4
- package/src/providers/__tests__/registry-native-web-search.test.ts +122 -0
- package/src/providers/call-site-routing.ts +33 -9
- package/src/providers/connection-model-compat.ts +23 -0
- package/src/providers/connection-resolution.ts +39 -20
- package/src/providers/fireworks/client.ts +1 -0
- package/src/providers/gemini/client.ts +24 -3
- package/src/providers/inference/__tests__/adapter-factory-openai-compatible.test.ts +0 -2
- package/src/providers/inference/__tests__/base-url-security.test.ts +2 -3
- package/src/providers/inference/__tests__/{connections-status-label.test.ts → connections-label.test.ts} +12 -111
- package/src/providers/inference/auth.ts +0 -8
- package/src/providers/inference/connections.ts +3 -66
- package/src/providers/inference/resolve-auth.ts +2 -3
- package/src/providers/model-catalog.ts +35 -1
- package/src/providers/model-intents.ts +3 -3
- package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
- package/src/providers/openai/__tests__/chat-completions-provider-reasoning.test.ts +157 -5
- package/src/providers/openai/chat-completions-provider.ts +110 -12
- package/src/providers/openai/codex-models.ts +2 -0
- package/src/providers/openai/responses-provider.ts +53 -53
- package/src/providers/openrouter/client.ts +13 -8
- package/src/providers/provider-send-message.ts +18 -9
- package/src/providers/registry.ts +48 -8
- package/src/providers/retry.ts +16 -4
- package/src/providers/search-provider-catalog.ts +17 -9
- package/src/providers/types.ts +9 -0
- package/src/runtime/__tests__/agent-wake.test.ts +1 -0
- package/src/runtime/__tests__/background-job-runner.test.ts +1 -0
- package/src/runtime/access-request-helper.ts +1 -0
- package/src/runtime/auth/route-policy.ts +10 -0
- package/src/runtime/channel-readiness-service.ts +68 -0
- package/src/runtime/channel-reply-delivery.ts +23 -0
- package/src/runtime/channel-retry-sweep.ts +47 -14
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/migrations/vbundle-builder.ts +3 -2
- package/src/runtime/routes/__tests__/bookmark-routes.test.ts +1 -0
- package/src/runtime/routes/__tests__/conversation-compaction-routes.test.ts +406 -0
- package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
- package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
- package/src/runtime/routes/__tests__/home-feed-routes.test.ts +209 -1
- package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +13 -50
- package/src/runtime/routes/__tests__/memory-v2-simulate-route.test.ts +51 -3
- package/src/runtime/routes/__tests__/memory-v3-simulate-params.test.ts +35 -0
- package/src/runtime/routes/__tests__/slack-channel-routes.test.ts +3 -2
- package/src/runtime/routes/__tests__/surface-content-routes.test.ts +294 -0
- package/src/runtime/routes/__tests__/task-routes.test.ts +48 -3
- package/src/runtime/routes/acp-routes-list.test.ts +3 -0
- package/src/runtime/routes/app-management-routes.ts +111 -4
- package/src/runtime/routes/background-wake-routes.ts +188 -20
- package/src/runtime/routes/btw-routes.ts +4 -4
- package/src/runtime/routes/conversation-analysis-routes.ts +6 -0
- package/src/runtime/routes/conversation-compaction-routes.ts +263 -0
- package/src/runtime/routes/conversation-list-routes.ts +147 -0
- package/src/runtime/routes/conversation-management-routes.ts +39 -14
- package/src/runtime/routes/conversation-query-routes.ts +60 -10
- package/src/runtime/routes/conversation-routes.ts +186 -140
- package/src/runtime/routes/conversations-import-routes.ts +19 -6
- package/src/runtime/routes/documents-routes.ts +10 -1
- package/src/runtime/routes/group-routes.ts +11 -0
- package/src/runtime/routes/home-feed-routes.ts +129 -0
- package/src/runtime/routes/identity-intro-cache.ts +61 -16
- package/src/runtime/routes/identity-routes.ts +30 -9
- package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +530 -6
- package/src/runtime/routes/inbound-stages/background-dispatch.ts +57 -8
- package/src/runtime/routes/index.ts +2 -0
- package/src/runtime/routes/inference-provider-connection-routes.ts +5 -26
- package/src/runtime/routes/integrations/vercel.ts +15 -0
- package/src/runtime/routes/llm-context-normalization.ts +7 -2
- package/src/runtime/routes/memory-v3-routes.ts +160 -2
- package/src/runtime/routes/migration-routes.ts +20 -13
- package/src/runtime/routes/notification-routes.ts +63 -1
- package/src/runtime/routes/oauth-commands-routes.ts +6 -1
- package/src/runtime/routes/surface-action-routes.ts +1 -38
- package/src/runtime/routes/surface-content-routes.ts +12 -5
- package/src/runtime/routes/surface-conversation-resolver.ts +65 -0
- package/src/runtime/routes/wipe-conversation-routes.ts +3 -0
- package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -0
- package/src/runtime/slack-dm-text-delivery.ts +177 -0
- package/src/runtime/sync/resource-sync-events.ts +1 -1
- package/src/runtime/tool-grant-request-helper.ts +1 -0
- package/src/schedule/schedule-store.ts +8 -1
- package/src/schedule/scheduler.ts +111 -15
- package/src/security/__tests__/provider-key-env-fallback.test.ts +3 -3
- package/src/security/encrypted-store.ts +7 -16
- package/src/security/store-path-override.ts +61 -0
- package/src/signals/user-message.ts +5 -8
- package/src/skills/validate-input.ts +177 -0
- package/src/subagent/manager.ts +13 -13
- package/src/subagent/types.ts +6 -0
- package/src/tasks/tool-sanitizer.ts +2 -2
- package/src/tools/apps/definitions.ts +35 -21
- package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +2 -8
- package/src/tools/computer-use/definitions.ts +268 -266
- package/src/tools/document/document-tool.ts +131 -8
- package/src/tools/execution-target.ts +2 -5
- package/src/tools/executor.ts +18 -55
- package/src/tools/host-filesystem/edit.test.ts +1 -0
- package/src/tools/host-filesystem/read.test.ts +1 -0
- package/src/tools/host-filesystem/transfer.test.ts +31 -6
- package/src/tools/host-filesystem/write.test.ts +1 -0
- package/src/tools/mcp/mcp-tool-factory.ts +0 -2
- package/src/tools/network/__tests__/managed-search-proxy.test.ts +282 -0
- package/src/tools/network/__tests__/web-search.test.ts +211 -3
- package/src/tools/network/managed-search-proxy.ts +183 -0
- package/src/tools/network/web-search.ts +199 -44
- package/src/tools/policy-context.ts +3 -1
- package/src/tools/registry.ts +146 -103
- package/src/tools/schedule/create.ts +1 -1
- package/src/tools/skills/skill-tool-factory.ts +17 -36
- package/src/tools/subagent/spawn.ts +3 -0
- package/src/tools/tool-approval-handler.ts +10 -4
- package/src/tools/tool-name-aliases.ts +72 -14
- package/src/tools/types.ts +17 -15
- package/src/tools/ui-surface/definitions.ts +98 -86
- package/src/types/onboarding-context.ts +6 -0
- package/src/usage/attribution.ts +32 -1
- package/src/util/browser.ts +7 -2
- package/src/workspace/migrations/090-memory-router-cost-optimized-profile.ts +109 -0
- package/src/workspace/migrations/091-retighten-migration-onboarding-thread.ts +41 -0
- package/src/workspace/migrations/registry.ts +4 -0
|
@@ -47,7 +47,7 @@ mock.module("openai", () => ({
|
|
|
47
47
|
lastConstructorOptions = opts;
|
|
48
48
|
}
|
|
49
49
|
responses = {
|
|
50
|
-
|
|
50
|
+
create: async (
|
|
51
51
|
params: Record<string, unknown>,
|
|
52
52
|
options?: Record<string, unknown>,
|
|
53
53
|
) => {
|
|
@@ -165,6 +165,26 @@ function completedEvent(
|
|
|
165
165
|
};
|
|
166
166
|
}
|
|
167
167
|
|
|
168
|
+
function incompleteEvent(
|
|
169
|
+
reason: "max_output_tokens" | "content_filter",
|
|
170
|
+
inputTokens: number,
|
|
171
|
+
outputTokens: number,
|
|
172
|
+
): FakeStreamEvent {
|
|
173
|
+
return {
|
|
174
|
+
type: "response.incomplete",
|
|
175
|
+
response: {
|
|
176
|
+
model: "gpt-5.2",
|
|
177
|
+
status: "incomplete",
|
|
178
|
+
incomplete_details: { reason },
|
|
179
|
+
output: [],
|
|
180
|
+
usage: {
|
|
181
|
+
input_tokens: inputTokens,
|
|
182
|
+
output_tokens: outputTokens,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
168
188
|
// ---------------------------------------------------------------------------
|
|
169
189
|
// Tests
|
|
170
190
|
// ---------------------------------------------------------------------------
|
|
@@ -243,6 +263,21 @@ describe("OpenAIResponsesProvider", () => {
|
|
|
243
263
|
expect(result.stopReason).toBe("stop");
|
|
244
264
|
});
|
|
245
265
|
|
|
266
|
+
test("maps response.incomplete max output details to stopReason", async () => {
|
|
267
|
+
fakeStreamEvents = [
|
|
268
|
+
textDeltaEvent("Partial"),
|
|
269
|
+
incompleteEvent("max_output_tokens", 12, 8),
|
|
270
|
+
];
|
|
271
|
+
|
|
272
|
+
const result = await provider.sendMessage([
|
|
273
|
+
{ role: "user", content: [{ type: "text", text: "Hi" }] },
|
|
274
|
+
]);
|
|
275
|
+
|
|
276
|
+
expect(result.content).toEqual([{ type: "text", text: "Partial" }]);
|
|
277
|
+
expect(result.usage).toEqual({ inputTokens: 12, outputTokens: 8 });
|
|
278
|
+
expect(result.stopReason).toBe("max_output_tokens");
|
|
279
|
+
});
|
|
280
|
+
|
|
246
281
|
// -----------------------------------------------------------------------
|
|
247
282
|
// Streaming events
|
|
248
283
|
// -----------------------------------------------------------------------
|
|
@@ -1120,7 +1155,7 @@ describe("OpenAIResponsesProvider", () => {
|
|
|
1120
1155
|
"System prompt",
|
|
1121
1156
|
);
|
|
1122
1157
|
|
|
1123
|
-
// rawRequest should contain the params sent to responses.
|
|
1158
|
+
// rawRequest should contain the params sent to responses.create()
|
|
1124
1159
|
const rawReq = result.rawRequest as Record<string, unknown>;
|
|
1125
1160
|
expect(rawReq.model).toBe("gpt-5.2");
|
|
1126
1161
|
expect(rawReq.instructions).toBe("System prompt");
|
|
@@ -1679,7 +1714,7 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1679
1714
|
expect(lastStreamParams!.max_output_tokens).toBeUndefined();
|
|
1680
1715
|
});
|
|
1681
1716
|
|
|
1682
|
-
test("codexSubscription:
|
|
1717
|
+
test("codexSubscription: forwards reasoning param when effort is set", async () => {
|
|
1683
1718
|
const codexProvider = new OpenAIResponsesProvider("sk-test", "gpt-5.4", {
|
|
1684
1719
|
codexSubscription: true,
|
|
1685
1720
|
});
|
|
@@ -1692,10 +1727,10 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1692
1727
|
{ config: { effort: "high" } },
|
|
1693
1728
|
);
|
|
1694
1729
|
|
|
1695
|
-
expect(lastStreamParams!.reasoning).
|
|
1730
|
+
expect(lastStreamParams!.reasoning).toEqual({ effort: "high" });
|
|
1696
1731
|
});
|
|
1697
1732
|
|
|
1698
|
-
test("codexSubscription:
|
|
1733
|
+
test("codexSubscription: forwards text.verbosity param", async () => {
|
|
1699
1734
|
const codexProvider = new OpenAIResponsesProvider("sk-test", "gpt-5.4", {
|
|
1700
1735
|
codexSubscription: true,
|
|
1701
1736
|
});
|
|
@@ -1708,7 +1743,7 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1708
1743
|
{ config: { verbosity: "low" } },
|
|
1709
1744
|
);
|
|
1710
1745
|
|
|
1711
|
-
expect(lastStreamParams!.text).
|
|
1746
|
+
expect(lastStreamParams!.text).toEqual({ verbosity: "low" });
|
|
1712
1747
|
});
|
|
1713
1748
|
|
|
1714
1749
|
test("codexSubscription: uses Codex baseURL", async () => {
|
|
@@ -1721,7 +1756,7 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1721
1756
|
);
|
|
1722
1757
|
});
|
|
1723
1758
|
|
|
1724
|
-
test("codexSubscription:
|
|
1759
|
+
test("codexSubscription: forwards tools param", async () => {
|
|
1725
1760
|
const codexProvider = new OpenAIResponsesProvider("sk-test", "gpt-5.4", {
|
|
1726
1761
|
codexSubscription: true,
|
|
1727
1762
|
});
|
|
@@ -1737,7 +1772,32 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1737
1772
|
[sampleTool],
|
|
1738
1773
|
);
|
|
1739
1774
|
|
|
1740
|
-
expect(lastStreamParams!.tools).
|
|
1775
|
+
expect(lastStreamParams!.tools).toEqual([
|
|
1776
|
+
{
|
|
1777
|
+
type: "function",
|
|
1778
|
+
name: "test_tool",
|
|
1779
|
+
description: "A test tool",
|
|
1780
|
+
parameters: { type: "object", properties: {} },
|
|
1781
|
+
strict: null,
|
|
1782
|
+
},
|
|
1783
|
+
]);
|
|
1784
|
+
});
|
|
1785
|
+
|
|
1786
|
+
test("codexSubscription: maps web_search to the Codex native web_search tool", async () => {
|
|
1787
|
+
const codexProvider = new OpenAIResponsesProvider("sk-test", "gpt-5.4", {
|
|
1788
|
+
codexSubscription: true,
|
|
1789
|
+
useNativeWebSearch: true,
|
|
1790
|
+
});
|
|
1791
|
+
fakeStreamEvents = [textDeltaEvent("OK"), completedEvent(10, 2)];
|
|
1792
|
+
|
|
1793
|
+
await codexProvider.sendMessage(
|
|
1794
|
+
[{ role: "user", content: [{ type: "text", text: "Search for cats" }] }],
|
|
1795
|
+
[webSearchTool],
|
|
1796
|
+
);
|
|
1797
|
+
|
|
1798
|
+
expect(lastStreamParams!.tools).toEqual([
|
|
1799
|
+
{ type: "web_search", external_web_access: false },
|
|
1800
|
+
]);
|
|
1741
1801
|
});
|
|
1742
1802
|
|
|
1743
1803
|
test("codexSubscription: still sends model, input, and instructions", async () => {
|
|
@@ -1756,7 +1816,7 @@ describe("OpenAIResponsesProvider — Native Web Search", () => {
|
|
|
1756
1816
|
expect(lastStreamParams!.model).toBe("gpt-5.4");
|
|
1757
1817
|
expect(lastStreamParams!.instructions).toBe("You are helpful.");
|
|
1758
1818
|
expect(lastStreamParams!.max_output_tokens).toBeUndefined();
|
|
1759
|
-
expect(lastStreamParams!.reasoning).
|
|
1760
|
-
expect(lastStreamParams!.text).
|
|
1819
|
+
expect(lastStreamParams!.reasoning).toEqual({ effort: "xhigh" });
|
|
1820
|
+
expect(lastStreamParams!.text).toEqual({ verbosity: "high" });
|
|
1761
1821
|
});
|
|
1762
1822
|
});
|
|
@@ -101,19 +101,19 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
101
101
|
config: { openrouter: { only: ["xAI"] } },
|
|
102
102
|
});
|
|
103
103
|
expect(extras).toEqual({
|
|
104
|
-
reasoning: { enabled: false },
|
|
105
104
|
provider: { only: ["xAI"] },
|
|
106
105
|
});
|
|
107
106
|
});
|
|
108
107
|
|
|
109
|
-
test("omits provider when
|
|
108
|
+
test("omits reasoning and provider when config is empty", () => {
|
|
110
109
|
const provider = new ProbeOpenRouterProvider(
|
|
111
110
|
"fake-key",
|
|
112
111
|
"x-ai/grok-4.20-beta",
|
|
113
112
|
);
|
|
114
113
|
const extras = provider.probeExtras({ config: {} });
|
|
115
|
-
expect(extras).toEqual({
|
|
114
|
+
expect(extras).toEqual({});
|
|
116
115
|
expect(extras.provider).toBe(undefined);
|
|
116
|
+
expect(extras.reasoning).toBe(undefined);
|
|
117
117
|
});
|
|
118
118
|
|
|
119
119
|
test("enables thinking with default detailed summary alongside provider.only", () => {
|
|
@@ -133,7 +133,7 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
133
133
|
});
|
|
134
134
|
});
|
|
135
135
|
|
|
136
|
-
test("disabled thinking
|
|
136
|
+
test("disabled thinking omits reasoning entirely", () => {
|
|
137
137
|
const provider = new ProbeOpenRouterProvider(
|
|
138
138
|
"fake-key",
|
|
139
139
|
"x-ai/grok-4.20-beta",
|
|
@@ -145,9 +145,9 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
145
145
|
},
|
|
146
146
|
});
|
|
147
147
|
expect(extras).toEqual({
|
|
148
|
-
reasoning: { enabled: false },
|
|
149
148
|
provider: { only: ["xAI"] },
|
|
150
149
|
});
|
|
150
|
+
expect(extras.reasoning).toBe(undefined);
|
|
151
151
|
});
|
|
152
152
|
|
|
153
153
|
test("nests effort under reasoning and maps `max` to xhigh", () => {
|
|
@@ -182,6 +182,28 @@ describe("OpenRouter provider.only plumbing", () => {
|
|
|
182
182
|
});
|
|
183
183
|
});
|
|
184
184
|
|
|
185
|
+
test("effort without thinking does not emit reasoning", () => {
|
|
186
|
+
const provider = new ProbeOpenRouterProvider(
|
|
187
|
+
"fake-key",
|
|
188
|
+
"x-ai/grok-4.20-beta",
|
|
189
|
+
);
|
|
190
|
+
const extras = provider.probeExtras({
|
|
191
|
+
config: { thinking: { type: "disabled" }, effort: "low" },
|
|
192
|
+
});
|
|
193
|
+
expect(extras.reasoning).toBe(undefined);
|
|
194
|
+
});
|
|
195
|
+
|
|
196
|
+
test("omitting reasoning avoids 400 from reasoning-only models like DeepSeek R1", () => {
|
|
197
|
+
const provider = new ProbeOpenRouterProvider(
|
|
198
|
+
"fake-key",
|
|
199
|
+
"deepseek/deepseek-r1-0528",
|
|
200
|
+
);
|
|
201
|
+
const extras = provider.probeExtras({
|
|
202
|
+
config: { thinking: { type: "disabled" } },
|
|
203
|
+
});
|
|
204
|
+
expect(extras.reasoning).toBe(undefined);
|
|
205
|
+
});
|
|
206
|
+
|
|
185
207
|
test("ignores an invalid summary override and falls back to detailed", () => {
|
|
186
208
|
const provider = new ProbeOpenRouterProvider(
|
|
187
209
|
"fake-key",
|
|
@@ -107,10 +107,47 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
107
107
|
: {};
|
|
108
108
|
row.metadata = JSON.stringify({ ...existing, ...updates });
|
|
109
109
|
},
|
|
110
|
-
updateMessageContent: () => {
|
|
110
|
+
updateMessageContent: (messageId: string, content: string) => {
|
|
111
|
+
// Mirror updateContent into the same capture array so existing
|
|
112
|
+
// `lastAssistantPersisted()` assertions continue to find the row that
|
|
113
|
+
// was reserved at `llm_call_started` time.
|
|
114
|
+
const row = persistedRows.find((candidate) => candidate.id === messageId);
|
|
115
|
+
if (row) row.content = content;
|
|
116
|
+
const call = addMessageCalls.find((c) => c.id === messageId);
|
|
117
|
+
if (call) call.content = content;
|
|
118
|
+
},
|
|
111
119
|
// The handler treats provenance as a flat spread; returning {} keeps the
|
|
112
120
|
// metadata snapshot focused on the fields under test.
|
|
113
121
|
provenanceFromTrustContext: () => ({}),
|
|
122
|
+
reserveMessage: mock(
|
|
123
|
+
async (
|
|
124
|
+
conversationId: string,
|
|
125
|
+
role: string,
|
|
126
|
+
metadata?: Record<string, unknown>,
|
|
127
|
+
) => {
|
|
128
|
+
// B3: production code creates the assistant row at `llm_call_started`
|
|
129
|
+
// via `reserveMessage`, stamping channel metadata at reserve time.
|
|
130
|
+
// Mirror that into the addMessage capture array so existing
|
|
131
|
+
// `lastAssistantPersisted()` assertions keep working.
|
|
132
|
+
const id = `mock-msg-${addMessageCalls.length + 1}-reserve`;
|
|
133
|
+
addMessageCalls.push({
|
|
134
|
+
id,
|
|
135
|
+
conversationId,
|
|
136
|
+
role,
|
|
137
|
+
content: "",
|
|
138
|
+
metadata,
|
|
139
|
+
});
|
|
140
|
+
persistedRows.push({
|
|
141
|
+
id,
|
|
142
|
+
conversationId,
|
|
143
|
+
role,
|
|
144
|
+
content: "",
|
|
145
|
+
createdAt: Date.now(),
|
|
146
|
+
metadata: metadata ? JSON.stringify(metadata) : null,
|
|
147
|
+
});
|
|
148
|
+
return { id };
|
|
149
|
+
},
|
|
150
|
+
),
|
|
114
151
|
}));
|
|
115
152
|
|
|
116
153
|
mock.module("../memory/llm-request-log-store.js", () => ({
|
|
@@ -147,6 +184,7 @@ import type {
|
|
|
147
184
|
} from "../daemon/conversation-agent-loop-handlers.js";
|
|
148
185
|
import {
|
|
149
186
|
createEventHandlerState,
|
|
187
|
+
handleLlmCallStarted,
|
|
150
188
|
handleMessageComplete,
|
|
151
189
|
} from "../daemon/conversation-agent-loop-handlers.js";
|
|
152
190
|
import type { ServerMessage } from "../daemon/message-protocol.js";
|
|
@@ -255,6 +293,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
255
293
|
assistantMessageChannel: "slack",
|
|
256
294
|
requesterChatId: channelId,
|
|
257
295
|
});
|
|
296
|
+
await handleLlmCallStarted(state, deps);
|
|
258
297
|
await handleMessageComplete(state, deps, makeMessageCompleteEvent("hi"));
|
|
259
298
|
|
|
260
299
|
const persisted = lastAssistantPersisted();
|
|
@@ -296,6 +335,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
296
335
|
requesterTimezoneLabel: "ET",
|
|
297
336
|
clientTimezone: "America/Los_Angeles",
|
|
298
337
|
});
|
|
338
|
+
await handleLlmCallStarted(state, deps);
|
|
299
339
|
await handleMessageComplete(
|
|
300
340
|
state,
|
|
301
341
|
deps,
|
|
@@ -324,6 +364,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
324
364
|
requesterChatId: channelId,
|
|
325
365
|
clientTimezone: "America/Los_Angeles",
|
|
326
366
|
});
|
|
367
|
+
await handleLlmCallStarted(state, deps);
|
|
327
368
|
await handleMessageComplete(
|
|
328
369
|
state,
|
|
329
370
|
deps,
|
|
@@ -351,6 +392,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
351
392
|
requesterChatId: channelId,
|
|
352
393
|
requesterTimezoneLabel: "ET",
|
|
353
394
|
});
|
|
395
|
+
await handleLlmCallStarted(state, deps);
|
|
354
396
|
await handleMessageComplete(
|
|
355
397
|
state,
|
|
356
398
|
deps,
|
|
@@ -394,6 +436,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
394
436
|
assistantMessageChannel: "slack",
|
|
395
437
|
requesterChatId: channelId,
|
|
396
438
|
});
|
|
439
|
+
await handleLlmCallStarted(state, deps);
|
|
397
440
|
await handleMessageComplete(state, deps, makeMessageCompleteEvent("hello"));
|
|
398
441
|
|
|
399
442
|
const persisted = lastAssistantPersisted();
|
|
@@ -425,6 +468,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
425
468
|
assistantMessageChannel: "slack",
|
|
426
469
|
requesterChatId: channelId,
|
|
427
470
|
});
|
|
471
|
+
await handleLlmCallStarted(state, deps);
|
|
428
472
|
await handleMessageComplete(
|
|
429
473
|
state,
|
|
430
474
|
deps,
|
|
@@ -446,6 +490,7 @@ describe("outbound assistant Slack metadata persistence", () => {
|
|
|
446
490
|
const deps = makeDeps(conversationId, {
|
|
447
491
|
assistantMessageChannel: "vellum",
|
|
448
492
|
});
|
|
493
|
+
await handleLlmCallStarted(state, deps);
|
|
449
494
|
await handleMessageComplete(
|
|
450
495
|
state,
|
|
451
496
|
deps,
|
|
@@ -25,6 +25,8 @@ import {
|
|
|
25
25
|
createConversation,
|
|
26
26
|
getMessageById,
|
|
27
27
|
getMessages,
|
|
28
|
+
reserveMessage,
|
|
29
|
+
updateMessageContent,
|
|
28
30
|
updateMessageMetadata,
|
|
29
31
|
} from "../memory/conversation-crud.js";
|
|
30
32
|
import { getDb } from "../memory/db-connection.js";
|
|
@@ -44,6 +46,7 @@ import type {
|
|
|
44
46
|
PersistAddResult,
|
|
45
47
|
PersistArgs,
|
|
46
48
|
PersistDeleteResult,
|
|
49
|
+
PersistReserveResult,
|
|
47
50
|
PersistResult,
|
|
48
51
|
Plugin,
|
|
49
52
|
TurnContext,
|
|
@@ -215,6 +218,80 @@ describe("persistence pipeline", () => {
|
|
|
215
218
|
expect(getMessages(conv.id)).toHaveLength(0);
|
|
216
219
|
});
|
|
217
220
|
|
|
221
|
+
test("default plugin: reserve op pre-allocates an empty assistant row", async () => {
|
|
222
|
+
registerPlugin(defaultPersistencePlugin);
|
|
223
|
+
|
|
224
|
+
const conv = createConversation();
|
|
225
|
+
|
|
226
|
+
const result = (await runPipeline<PersistArgs, PersistResult>(
|
|
227
|
+
"persistence",
|
|
228
|
+
getMiddlewaresFor("persistence"),
|
|
229
|
+
defaultPersistenceTerminal,
|
|
230
|
+
{
|
|
231
|
+
op: "reserve",
|
|
232
|
+
conversationId: conv.id,
|
|
233
|
+
role: "assistant",
|
|
234
|
+
metadata: { reservedFor: "anchor" },
|
|
235
|
+
},
|
|
236
|
+
makeCtx({ conversationId: conv.id }),
|
|
237
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
238
|
+
)) as PersistReserveResult;
|
|
239
|
+
|
|
240
|
+
expect(result.op).toBe("reserve");
|
|
241
|
+
expect(result.message.id).toBeTruthy();
|
|
242
|
+
expect(result.message.role).toBe("assistant");
|
|
243
|
+
// Reserve places an empty JSON array so consumers that parse content
|
|
244
|
+
// observe a no-content payload.
|
|
245
|
+
expect(result.message.content).toBe("[]");
|
|
246
|
+
|
|
247
|
+
// Row must exist with the expected shape and live in the conversation.
|
|
248
|
+
const row = getMessageById(result.message.id, conv.id);
|
|
249
|
+
expect(row).not.toBeNull();
|
|
250
|
+
expect(row?.content).toBe("[]");
|
|
251
|
+
expect(JSON.parse(row!.metadata!)).toEqual({ reservedFor: "anchor" });
|
|
252
|
+
expect(getMessages(conv.id).map((m) => m.id)).toContain(result.message.id);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
test("default plugin: updateContent op overwrites an existing row's content", async () => {
|
|
256
|
+
registerPlugin(defaultPersistencePlugin);
|
|
257
|
+
|
|
258
|
+
const conv = createConversation();
|
|
259
|
+
|
|
260
|
+
// Reserve first, then overwrite — exactly the B3 sequence consumers will
|
|
261
|
+
// follow.
|
|
262
|
+
const reserved = await reserveMessage(conv.id, "assistant");
|
|
263
|
+
expect(getMessageById(reserved.id, conv.id)?.content).toBe("[]");
|
|
264
|
+
|
|
265
|
+
const result = await runPipeline<PersistArgs, PersistResult>(
|
|
266
|
+
"persistence",
|
|
267
|
+
getMiddlewaresFor("persistence"),
|
|
268
|
+
defaultPersistenceTerminal,
|
|
269
|
+
{
|
|
270
|
+
op: "updateContent",
|
|
271
|
+
messageId: reserved.id,
|
|
272
|
+
content: JSON.stringify([{ type: "text", text: "Hello" }]),
|
|
273
|
+
},
|
|
274
|
+
makeCtx({ conversationId: conv.id }),
|
|
275
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
276
|
+
);
|
|
277
|
+
expect(result).toEqual({ op: "updateContent" });
|
|
278
|
+
|
|
279
|
+
// Content updated in place; row id unchanged.
|
|
280
|
+
const row = getMessageById(reserved.id, conv.id);
|
|
281
|
+
expect(row).not.toBeNull();
|
|
282
|
+
expect(JSON.parse(row!.content)).toEqual([{ type: "text", text: "Hello" }]);
|
|
283
|
+
|
|
284
|
+
// Direct-call parity: a fresh reserve + direct updateMessageContent
|
|
285
|
+
// should land the same content shape.
|
|
286
|
+
const baselineReserved = await reserveMessage(conv.id, "assistant");
|
|
287
|
+
updateMessageContent(
|
|
288
|
+
baselineReserved.id,
|
|
289
|
+
JSON.stringify([{ type: "text", text: "Hello" }]),
|
|
290
|
+
);
|
|
291
|
+
const baselineRow = getMessageById(baselineReserved.id, conv.id);
|
|
292
|
+
expect(baselineRow?.content).toBe(row?.content);
|
|
293
|
+
});
|
|
294
|
+
|
|
218
295
|
test("custom plugin: short-circuits every op onto a mock in-memory store", async () => {
|
|
219
296
|
type Stored = {
|
|
220
297
|
id: string;
|
|
@@ -249,6 +326,33 @@ describe("persistence pipeline", () => {
|
|
|
249
326
|
},
|
|
250
327
|
};
|
|
251
328
|
}
|
|
329
|
+
case "reserve": {
|
|
330
|
+
const id = `mock-${nextId++}`;
|
|
331
|
+
mockStore.set(id, {
|
|
332
|
+
id,
|
|
333
|
+
conversationId: args.conversationId,
|
|
334
|
+
role: args.role,
|
|
335
|
+
content: "[]",
|
|
336
|
+
metadata: { ...(args.metadata ?? {}) },
|
|
337
|
+
});
|
|
338
|
+
return {
|
|
339
|
+
op: "reserve",
|
|
340
|
+
message: {
|
|
341
|
+
id,
|
|
342
|
+
conversationId: args.conversationId,
|
|
343
|
+
role: args.role,
|
|
344
|
+
content: "[]",
|
|
345
|
+
createdAt: 123,
|
|
346
|
+
},
|
|
347
|
+
};
|
|
348
|
+
}
|
|
349
|
+
case "updateContent": {
|
|
350
|
+
const existing = mockStore.get(args.messageId);
|
|
351
|
+
if (existing) {
|
|
352
|
+
existing.content = args.content;
|
|
353
|
+
}
|
|
354
|
+
return { op: "updateContent" };
|
|
355
|
+
}
|
|
252
356
|
case "update": {
|
|
253
357
|
const existing = mockStore.get(args.messageId);
|
|
254
358
|
if (existing) {
|
|
@@ -298,6 +402,40 @@ describe("persistence pipeline", () => {
|
|
|
298
402
|
expect(addResult.message.id).toBe("mock-1");
|
|
299
403
|
expect(mockStore.size).toBe(1);
|
|
300
404
|
|
|
405
|
+
const reserveResult = (await runPipeline<PersistArgs, PersistResult>(
|
|
406
|
+
"persistence",
|
|
407
|
+
getMiddlewaresFor("persistence"),
|
|
408
|
+
defaultPersistenceTerminal,
|
|
409
|
+
{
|
|
410
|
+
op: "reserve",
|
|
411
|
+
conversationId: conv.id,
|
|
412
|
+
role: "assistant",
|
|
413
|
+
metadata: { reservedFor: "mock-anchor" },
|
|
414
|
+
},
|
|
415
|
+
makeCtx({ conversationId: conv.id }),
|
|
416
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
417
|
+
)) as PersistReserveResult;
|
|
418
|
+
expect(reserveResult.op).toBe("reserve");
|
|
419
|
+
expect(reserveResult.message.id).toBe("mock-2");
|
|
420
|
+
expect(reserveResult.message.content).toBe("[]");
|
|
421
|
+
expect(mockStore.get("mock-2")?.content).toBe("[]");
|
|
422
|
+
|
|
423
|
+
await runPipeline<PersistArgs, PersistResult>(
|
|
424
|
+
"persistence",
|
|
425
|
+
getMiddlewaresFor("persistence"),
|
|
426
|
+
defaultPersistenceTerminal,
|
|
427
|
+
{
|
|
428
|
+
op: "updateContent",
|
|
429
|
+
messageId: "mock-2",
|
|
430
|
+
content: '[{"type":"text","text":"finalized"}]',
|
|
431
|
+
},
|
|
432
|
+
makeCtx({ conversationId: conv.id }),
|
|
433
|
+
DEFAULT_TIMEOUTS.persistence,
|
|
434
|
+
);
|
|
435
|
+
expect(mockStore.get("mock-2")?.content).toBe(
|
|
436
|
+
'[{"type":"text","text":"finalized"}]',
|
|
437
|
+
);
|
|
438
|
+
|
|
301
439
|
await runPipeline<PersistArgs, PersistResult>(
|
|
302
440
|
"persistence",
|
|
303
441
|
getMiddlewaresFor("persistence"),
|
|
@@ -326,7 +464,7 @@ describe("persistence pipeline", () => {
|
|
|
326
464
|
expect(delResult.op).toBe("delete");
|
|
327
465
|
expect(mockStore.has("mock-1")).toBe(false);
|
|
328
466
|
|
|
329
|
-
// The real DB must not have been touched by any of the
|
|
467
|
+
// The real DB must not have been touched by any of the ops.
|
|
330
468
|
expect(getMessages(conv.id)).toHaveLength(dbRowsBefore);
|
|
331
469
|
});
|
|
332
470
|
|
|
@@ -40,6 +40,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
40
40
|
}));
|
|
41
41
|
|
|
42
42
|
interface AddMessageCall {
|
|
43
|
+
id: string;
|
|
43
44
|
conversationId: string;
|
|
44
45
|
role: string;
|
|
45
46
|
content: string;
|
|
@@ -53,13 +54,41 @@ mock.module("../memory/conversation-crud.js", () => ({
|
|
|
53
54
|
content: string,
|
|
54
55
|
metadata?: Record<string, unknown>,
|
|
55
56
|
) => {
|
|
56
|
-
|
|
57
|
-
|
|
57
|
+
const id = `mock-msg-${addMessageCalls.length + 1}`;
|
|
58
|
+
addMessageCalls.push({ id, conversationId, role, content, metadata });
|
|
59
|
+
return { id };
|
|
58
60
|
},
|
|
59
61
|
getConversation: () => null,
|
|
60
62
|
getMessageById: () => null,
|
|
61
|
-
updateMessageContent: () => {
|
|
63
|
+
updateMessageContent: (messageId: string, content: string) => {
|
|
64
|
+
// Mirror updateContent into the same capture array so existing
|
|
65
|
+
// `lastPersisted("assistant")` assertions continue to find the row that
|
|
66
|
+
// was reserved at `llm_call_started` time.
|
|
67
|
+
const call = addMessageCalls.find((c) => c.id === messageId);
|
|
68
|
+
if (call) call.content = content;
|
|
69
|
+
},
|
|
62
70
|
provenanceFromTrustContext: () => ({}),
|
|
71
|
+
reserveMessage: mock(
|
|
72
|
+
async (
|
|
73
|
+
conversationId: string,
|
|
74
|
+
role: string,
|
|
75
|
+
metadata?: Record<string, unknown>,
|
|
76
|
+
) => {
|
|
77
|
+
// B3: production code creates the assistant row at `llm_call_started`
|
|
78
|
+
// via `reserveMessage`, stamping channel metadata at reserve time.
|
|
79
|
+
// Mirror that into the addMessage capture array so existing
|
|
80
|
+
// `lastPersisted("assistant")` assertions keep working.
|
|
81
|
+
const id = `mock-msg-${addMessageCalls.length + 1}-reserve`;
|
|
82
|
+
addMessageCalls.push({
|
|
83
|
+
id,
|
|
84
|
+
conversationId,
|
|
85
|
+
role,
|
|
86
|
+
content: "",
|
|
87
|
+
metadata,
|
|
88
|
+
});
|
|
89
|
+
return { id };
|
|
90
|
+
},
|
|
91
|
+
),
|
|
63
92
|
}));
|
|
64
93
|
|
|
65
94
|
mock.module("../memory/llm-request-log-store.js", () => ({
|
|
@@ -84,6 +113,7 @@ import type {
|
|
|
84
113
|
} from "../daemon/conversation-agent-loop-handlers.js";
|
|
85
114
|
import {
|
|
86
115
|
createEventHandlerState,
|
|
116
|
+
handleLlmCallStarted,
|
|
87
117
|
handleMessageComplete,
|
|
88
118
|
} from "../daemon/conversation-agent-loop-handlers.js";
|
|
89
119
|
|
|
@@ -164,7 +194,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
164
194
|
isError: false,
|
|
165
195
|
});
|
|
166
196
|
|
|
167
|
-
await
|
|
197
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
198
|
+
await handleMessageComplete(
|
|
199
|
+
state,
|
|
200
|
+
makeDeps(),
|
|
201
|
+
makeMessageCompleteEvent("done"),
|
|
202
|
+
);
|
|
168
203
|
|
|
169
204
|
const persisted = lastPersisted("user");
|
|
170
205
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -183,7 +218,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
183
218
|
isError: false,
|
|
184
219
|
});
|
|
185
220
|
|
|
186
|
-
await
|
|
221
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
222
|
+
await handleMessageComplete(
|
|
223
|
+
state,
|
|
224
|
+
makeDeps(),
|
|
225
|
+
makeMessageCompleteEvent("done"),
|
|
226
|
+
);
|
|
187
227
|
|
|
188
228
|
const persisted = lastPersisted("user");
|
|
189
229
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -195,13 +235,19 @@ describe("persistence-layer secret redaction", () => {
|
|
|
195
235
|
});
|
|
196
236
|
|
|
197
237
|
test("does not redact non-secret content (UUID, hex hash) in tool result", async () => {
|
|
198
|
-
const safe =
|
|
238
|
+
const safe =
|
|
239
|
+
"id=550e8400-e29b-41d4-a716-446655440000 sha=a1b2c3d4e5f6a1b2c3d4e5f6a1b2c3d4e5f6a1b2";
|
|
199
240
|
state.pendingToolResults.set("tool-use-3", {
|
|
200
241
|
content: safe,
|
|
201
242
|
isError: false,
|
|
202
243
|
});
|
|
203
244
|
|
|
204
|
-
await
|
|
245
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
246
|
+
await handleMessageComplete(
|
|
247
|
+
state,
|
|
248
|
+
makeDeps(),
|
|
249
|
+
makeMessageCompleteEvent("done"),
|
|
250
|
+
);
|
|
205
251
|
|
|
206
252
|
const persisted = lastPersisted("user");
|
|
207
253
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -224,7 +270,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
224
270
|
// Capture the content before handleMessageComplete clears pendingToolResults
|
|
225
271
|
const contentSnapshot = state.pendingToolResults.get("tool-use-4")!.content;
|
|
226
272
|
|
|
227
|
-
await
|
|
273
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
274
|
+
await handleMessageComplete(
|
|
275
|
+
state,
|
|
276
|
+
makeDeps(),
|
|
277
|
+
makeMessageCompleteEvent("done"),
|
|
278
|
+
);
|
|
228
279
|
|
|
229
280
|
// The snapshot taken from live state before the call must be unmodified
|
|
230
281
|
expect(contentSnapshot).toBe(originalContent);
|
|
@@ -239,7 +290,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
239
290
|
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
240
291
|
const text = `Your API key is \`${secret}\`. Keep it safe.`;
|
|
241
292
|
|
|
242
|
-
await
|
|
293
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
294
|
+
await handleMessageComplete(
|
|
295
|
+
state,
|
|
296
|
+
makeDeps(),
|
|
297
|
+
makeMessageCompleteEvent(text),
|
|
298
|
+
);
|
|
243
299
|
|
|
244
300
|
const persisted = lastPersisted("assistant");
|
|
245
301
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -256,7 +312,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
256
312
|
const secret = "sk-proj-ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrst";
|
|
257
313
|
const text = `I found this key in the config: ${secret}`;
|
|
258
314
|
|
|
259
|
-
await
|
|
315
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
316
|
+
await handleMessageComplete(
|
|
317
|
+
state,
|
|
318
|
+
makeDeps(),
|
|
319
|
+
makeMessageCompleteEvent(text),
|
|
320
|
+
);
|
|
260
321
|
|
|
261
322
|
const persisted = lastPersisted("assistant");
|
|
262
323
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -271,7 +332,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
271
332
|
test("does not redact non-secret text in assistant message", async () => {
|
|
272
333
|
const safe = "Here is the file list: index.ts, util.ts, main.ts";
|
|
273
334
|
|
|
274
|
-
await
|
|
335
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
336
|
+
await handleMessageComplete(
|
|
337
|
+
state,
|
|
338
|
+
makeDeps(),
|
|
339
|
+
makeMessageCompleteEvent(safe),
|
|
340
|
+
);
|
|
275
341
|
|
|
276
342
|
const persisted = lastPersisted("assistant");
|
|
277
343
|
const blocks = JSON.parse(persisted.content) as Array<{
|
|
@@ -286,7 +352,12 @@ describe("persistence-layer secret redaction", () => {
|
|
|
286
352
|
// High-entropy but no known credential prefix — should NOT be redacted
|
|
287
353
|
const text = "checksum: 8f14e45fceea167a5a36dedd4bea2543";
|
|
288
354
|
|
|
289
|
-
await
|
|
355
|
+
await handleLlmCallStarted(state, makeDeps());
|
|
356
|
+
await handleMessageComplete(
|
|
357
|
+
state,
|
|
358
|
+
makeDeps(),
|
|
359
|
+
makeMessageCompleteEvent(text),
|
|
360
|
+
);
|
|
290
361
|
|
|
291
362
|
const persisted = lastPersisted("assistant");
|
|
292
363
|
const blocks = JSON.parse(persisted.content) as Array<{
|