@vellumai/assistant 0.4.56 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +10 -10
- package/Dockerfile +3 -0
- package/README.md +11 -11
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/memory.md +3 -4
- package/docs/credential-execution-service.md +13 -20
- package/node_modules/@vellumai/ces-contracts/src/error.ts +5 -4
- package/package.json +1 -1
- package/src/__tests__/actor-token-service.test.ts +7 -7
- package/src/__tests__/anthropic-provider.test.ts +172 -0
- package/src/__tests__/app-builder-tool-scripts.test.ts +15 -1
- package/src/__tests__/approval-cascade.test.ts +2 -2
- package/src/__tests__/approval-routes-http.test.ts +3 -4
- package/src/__tests__/asset-materialize-tool.test.ts +5 -5
- package/src/__tests__/asset-search-tool.test.ts +1 -1
- package/src/__tests__/assistant-attachments.test.ts +5 -5
- package/src/__tests__/assistant-events-sse-hardening.test.ts +1 -1
- package/src/__tests__/assistant-feature-flags-integration.test.ts +50 -38
- package/src/__tests__/attachments-store.test.ts +2 -2
- package/src/__tests__/avatar-e2e.test.ts +5 -3
- package/src/__tests__/browser-skill-endstate.test.ts +0 -1
- package/src/__tests__/call-routes-http.test.ts +2 -2
- package/src/__tests__/callback-handoff-copy.test.ts +1 -1
- package/src/__tests__/cancel-resolves-conversation-key.test.ts +158 -0
- package/src/__tests__/channel-readiness-routes.test.ts +0 -1
- package/src/__tests__/channel-readiness-service.test.ts +0 -1
- package/src/__tests__/checker.test.ts +31 -32
- package/src/__tests__/chrome-cdp.test.ts +47 -18
- package/src/__tests__/claude-code-skill-regression.test.ts +2 -2
- package/src/__tests__/config-schema-cmd.test.ts +2 -2
- package/src/__tests__/config-schema.test.ts +9 -18
- package/src/__tests__/confirmation-request-guardian-bridge.test.ts +1 -1
- package/src/__tests__/conversation-abort-tool-results.test.ts +4 -4
- package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -2
- package/src/__tests__/conversation-agent-loop.test.ts +11 -4
- package/src/__tests__/conversation-attachments.test.ts +1 -1
- package/src/__tests__/conversation-confirmation-signals.test.ts +2 -2
- package/src/__tests__/conversation-error.test.ts +33 -0
- package/src/__tests__/conversation-init.benchmark.test.ts +0 -1
- package/src/__tests__/conversation-load-history-repair.test.ts +1 -1
- package/src/__tests__/conversation-pairing.test.ts +1 -1
- package/src/__tests__/conversation-pre-run-repair.test.ts +4 -4
- package/src/__tests__/conversation-provider-retry-repair.test.ts +4 -4
- package/src/__tests__/conversation-queue.test.ts +23 -14
- package/src/__tests__/conversation-routes-slash-commands.test.ts +3 -3
- package/src/__tests__/conversation-runtime-assembly.test.ts +204 -185
- package/src/__tests__/conversation-seed-composer.test.ts +1 -1
- package/src/__tests__/conversation-slash-queue.test.ts +4 -4
- package/src/__tests__/conversation-slash-unknown.test.ts +4 -4
- package/src/__tests__/conversation-starter-routes.test.ts +291 -0
- package/src/__tests__/conversation-wipe.test.ts +438 -0
- package/src/__tests__/conversation-workspace-cache-state.test.ts +2 -3
- package/src/__tests__/conversation-workspace-injection.test.ts +4 -5
- package/src/__tests__/conversation-workspace-tool-tracking.test.ts +4 -5
- package/src/__tests__/credential-security-e2e.test.ts +20 -0
- package/src/__tests__/credential-security-invariants.test.ts +1 -0
- package/src/__tests__/credential-vault-unit.test.ts +227 -0
- package/src/__tests__/credentials-cli.test.ts +3 -0
- package/src/__tests__/date-context.test.ts +59 -377
- package/src/__tests__/drop-capability-card-state-migration.test.ts +169 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +11 -45
- package/src/__tests__/emit-signal-routing-intent.test.ts +3 -3
- package/src/__tests__/encrypted-store.test.ts +249 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- package/src/__tests__/file-read-tool.test.ts +40 -0
- package/src/__tests__/gateway-only-enforcement.test.ts +2 -2
- package/src/__tests__/gateway-only-guard.test.ts +1 -0
- package/src/__tests__/gemini-image-service.test.ts +4 -4
- package/src/__tests__/gemini-provider.test.ts +6 -9
- package/src/__tests__/guardian-binding-drift-heal.test.ts +128 -0
- package/src/__tests__/guardian-dispatch.test.ts +0 -1
- package/src/__tests__/host-file-read-tool.test.ts +87 -0
- package/src/__tests__/host-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- package/src/__tests__/identity-intro-cache.test.ts +209 -0
- package/src/__tests__/intent-routing.test.ts +51 -99
- package/src/__tests__/invite-routes-http.test.ts +5 -0
- package/src/__tests__/list-messages-attachments.test.ts +1 -1
- package/src/__tests__/managed-proxy-context.test.ts +2 -5
- package/src/__tests__/managed-skill-lifecycle.test.ts +8 -8
- package/src/__tests__/media-generate-image.test.ts +32 -15
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +1 -1
- package/src/__tests__/memory-lifecycle-e2e.test.ts +24 -18
- package/src/__tests__/memory-recall-quality.test.ts +4 -3
- package/src/__tests__/memory-regressions.test.ts +86 -90
- package/src/__tests__/migration-cross-version-compatibility.test.ts +32 -32
- package/src/__tests__/migration-export-http.test.ts +26 -27
- package/src/__tests__/migration-import-commit-http.test.ts +165 -37
- package/src/__tests__/migration-import-preflight-http.test.ts +81 -20
- package/src/__tests__/migration-validate-http.test.ts +16 -16
- package/src/__tests__/model-intents.test.ts +2 -2
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- package/src/__tests__/non-member-access-request.test.ts +3 -3
- package/src/__tests__/notification-broadcaster.test.ts +1 -1
- package/src/__tests__/notification-decision-fallback.test.ts +2 -2
- package/src/__tests__/notification-decision-identity.test.ts +8 -9
- package/src/__tests__/notification-decision-strategy.test.ts +1 -1
- package/src/__tests__/notification-deep-link.test.ts +1 -1
- package/src/__tests__/notification-guardian-path.test.ts +0 -1
- package/src/__tests__/notification-schedule-dedup.test.ts +7 -7
- package/src/__tests__/oauth-store.test.ts +1 -3
- package/src/__tests__/oauth2-gateway-transport.test.ts +6 -1
- package/src/__tests__/onboarding-template-contract.test.ts +23 -59
- package/src/__tests__/provider-error-scenarios.test.ts +154 -0
- package/src/__tests__/provider-fail-open-selection.test.ts +2 -2
- package/src/__tests__/provider-managed-proxy-integration.test.ts +8 -9
- package/src/__tests__/provider-registry-ollama.test.ts +5 -2
- package/src/__tests__/qdrant-manager.test.ts +7 -7
- package/src/__tests__/ratelimit.test.ts +0 -74
- package/src/__tests__/recording-handler.test.ts +0 -1
- package/src/__tests__/require-fresh-approval.test.ts +1 -1
- package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
- package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
- package/src/__tests__/runtime-events-sse.test.ts +1 -1
- package/src/__tests__/scheduler-recurrence.test.ts +46 -2
- package/src/__tests__/schema-transforms.test.ts +114 -54
- package/src/__tests__/secret-onetime-send.test.ts +20 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -2
- package/src/__tests__/secret-scanner-executor.test.ts +1 -2
- package/src/__tests__/send-endpoint-busy.test.ts +63 -4
- package/src/__tests__/send-notification-tool.test.ts +2 -2
- package/src/__tests__/shell-credential-ref.test.ts +0 -1
- package/src/__tests__/shell-tool-proxy-mode.test.ts +1 -2
- package/src/__tests__/skill-memory.test.ts +549 -0
- package/src/__tests__/skill-script-runner-sandbox.test.ts +1 -2
- package/src/__tests__/slack-app-setup-skill-regression.test.ts +37 -0
- package/src/__tests__/slack-channel-config.test.ts +109 -94
- package/src/__tests__/swarm-conversation-integration.test.ts +2 -2
- package/src/__tests__/swarm-recursion.test.ts +2 -2
- package/src/__tests__/swarm-tool.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +19 -66
- package/src/__tests__/telegram-config.test.ts +121 -0
- package/src/__tests__/terminal-tools.test.ts +1 -1
- package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -2
- package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
- package/src/__tests__/tool-executor-shell-integration.test.ts +1 -1
- package/src/__tests__/tool-executor.test.ts +1 -1
- package/src/__tests__/trace-emitter.test.ts +8 -1
- package/src/__tests__/trust-store.test.ts +7 -8
- package/src/__tests__/twilio-routes.test.ts +1 -18
- package/src/__tests__/user-reference.test.ts +82 -2
- package/src/__tests__/vbundle-pax-and-symlink.test.ts +196 -0
- package/src/__tests__/verification-control-plane-policy.test.ts +1 -1
- package/src/approvals/guardian-request-resolvers.ts +3 -3
- package/src/avatar/ascii-renderer.ts +2 -2
- package/src/avatar/png-renderer.ts +2 -2
- package/src/avatar/resvg-lazy.ts +21 -0
- package/src/calls/guardian-dispatch.ts +1 -1
- package/src/calls/relay-access-wait.ts +2 -2
- package/src/calls/twilio-rest.ts +0 -248
- package/src/cli/AGENTS.md +5 -8
- package/src/cli/__tests__/notifications.test.ts +5 -5
- package/src/cli/commands/avatar.ts +64 -2
- package/src/cli/commands/conversations.ts +131 -1
- package/src/cli/commands/credentials.ts +2 -0
- package/src/cli/commands/notifications.ts +3 -3
- package/src/cli.ts +10 -0
- package/src/config/bundled-skills/acp/SKILL.md +5 -5
- package/src/config/bundled-skills/acp/TOOLS.json +6 -6
- package/src/config/bundled-skills/app-builder/SKILL.md +42 -42
- package/src/config/bundled-skills/app-builder/TOOLS.json +10 -10
- package/src/config/bundled-skills/browser/SKILL.md +15 -15
- package/src/config/bundled-skills/browser/TOOLS.json +14 -14
- package/src/config/bundled-skills/chatgpt-import/SKILL.md +2 -2
- package/src/config/bundled-skills/chatgpt-import/TOOLS.json +1 -1
- package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
- package/src/config/bundled-skills/claude-code/SKILL.md +5 -5
- package/src/config/bundled-skills/computer-use/SKILL.md +2 -2
- package/src/config/bundled-skills/computer-use/TOOLS.json +15 -15
- package/src/config/bundled-skills/contacts/SKILL.md +3 -3
- package/src/config/bundled-skills/contacts/TOOLS.json +4 -4
- package/src/config/bundled-skills/document/SKILL.md +4 -4
- package/src/config/bundled-skills/document/TOOLS.json +2 -2
- package/src/config/bundled-skills/followups/TOOLS.json +3 -3
- package/src/config/bundled-skills/gmail/SKILL.md +32 -32
- package/src/config/bundled-skills/gmail/TOOLS.json +16 -16
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +1 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
- package/src/config/bundled-skills/google-calendar/SKILL.md +1 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +5 -5
- package/src/config/bundled-skills/google-calendar/types.ts +1 -1
- package/src/config/bundled-skills/heartbeat/SKILL.md +43 -0
- package/src/config/bundled-skills/image-studio/SKILL.md +3 -3
- package/src/config/bundled-skills/image-studio/TOOLS.json +2 -3
- package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +16 -12
- package/src/config/bundled-skills/media-processing/SKILL.md +40 -40
- package/src/config/bundled-skills/media-processing/TOOLS.json +8 -8
- package/src/config/bundled-skills/media-processing/__tests__/concurrency-pool.test.ts +2 -2
- package/src/config/bundled-skills/media-processing/__tests__/preprocess.test.ts +1 -1
- package/src/config/bundled-skills/media-processing/services/gemini-map.ts +5 -5
- package/src/config/bundled-skills/media-processing/services/gemini-video.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/preprocess.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/processing-pipeline.ts +2 -2
- package/src/config/bundled-skills/media-processing/services/reduce.ts +3 -3
- package/src/config/bundled-skills/media-processing/tools/generate-clip.ts +2 -2
- package/src/config/bundled-skills/media-processing/tools/query-media-events.ts +1 -1
- package/src/config/bundled-skills/messaging/SKILL.md +29 -25
- package/src/config/bundled-skills/messaging/TOOLS.json +11 -11
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +1 -1
- package/src/config/bundled-skills/messaging/tools/shared.ts +1 -1
- package/src/config/bundled-skills/notifications/SKILL.md +3 -3
- package/src/config/bundled-skills/notifications/TOOLS.json +2 -2
- package/src/config/bundled-skills/notifications/tools/send-notification.ts +3 -3
- package/src/config/bundled-skills/orchestration/SKILL.md +1 -1
- package/src/config/bundled-skills/orchestration/TOOLS.json +1 -1
- package/src/config/bundled-skills/phone-calls/SKILL.md +18 -14
- package/src/config/bundled-skills/phone-calls/TOOLS.json +3 -3
- package/src/config/bundled-skills/phone-calls/references/CONFIG.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +2 -2
- package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +1 -1
- package/src/config/bundled-skills/playbooks/TOOLS.json +4 -4
- package/src/config/bundled-skills/schedule/SKILL.md +26 -26
- package/src/config/bundled-skills/schedule/TOOLS.json +5 -5
- package/src/config/bundled-skills/screen-watch/SKILL.md +3 -3
- package/src/config/bundled-skills/screen-watch/TOOLS.json +1 -1
- package/src/config/bundled-skills/sequences/SKILL.md +2 -2
- package/src/config/bundled-skills/sequences/TOOLS.json +10 -10
- package/src/config/bundled-skills/sequences/tools/sequence-analytics.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enroll.ts +2 -2
- package/src/config/bundled-skills/sequences/tools/sequence-enrollment-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-get.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-import.ts +3 -3
- package/src/config/bundled-skills/sequences/tools/sequence-list.ts +1 -1
- package/src/config/bundled-skills/sequences/tools/sequence-update.ts +1 -1
- package/src/config/bundled-skills/settings/TOOLS.json +3 -3
- package/src/config/bundled-skills/settings/tools/open-system-settings.ts +1 -1
- package/src/config/bundled-skills/skill-management/TOOLS.json +5 -5
- package/src/config/bundled-skills/skills-catalog/SKILL.md +84 -0
- package/src/config/bundled-skills/slack/SKILL.md +2 -2
- package/src/config/bundled-skills/slack/TOOLS.json +8 -8
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +3 -3
- package/src/config/bundled-skills/subagent/TOOLS.json +5 -5
- package/src/config/bundled-skills/tasks/SKILL.md +1 -1
- package/src/config/bundled-skills/tasks/TOOLS.json +9 -9
- package/src/config/bundled-skills/transcribe/SKILL.md +5 -5
- package/src/config/bundled-skills/transcribe/TOOLS.json +1 -1
- package/src/config/bundled-skills/transcribe/tools/transcribe-media.ts +10 -10
- package/src/config/bundled-skills/watcher/SKILL.md +4 -4
- package/src/config/bundled-skills/watcher/TOOLS.json +5 -5
- package/src/config/feature-flag-registry.json +33 -17
- package/src/config/schemas/sandbox.ts +1 -1
- package/src/config/schemas/services.ts +13 -3
- package/src/config/schemas/timeouts.ts +0 -10
- package/src/contacts/contact-store.ts +63 -0
- package/src/contacts/contacts-write.ts +1 -1
- package/src/daemon/assistant-attachments.ts +2 -2
- package/src/daemon/conversation-agent-loop-handlers.ts +2 -2
- package/src/daemon/conversation-agent-loop.ts +7 -30
- package/src/daemon/conversation-error.ts +24 -0
- package/src/daemon/conversation-memory.ts +8 -7
- package/src/daemon/conversation-runtime-assembly.ts +141 -275
- package/src/daemon/conversation-slash.ts +7 -26
- package/src/daemon/conversation-surfaces.ts +14 -0
- package/src/daemon/conversation-tool-setup.ts +9 -8
- package/src/daemon/conversation.ts +2 -0
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +10 -83
- package/src/daemon/handlers/config-channels.ts +12 -2
- package/src/daemon/handlers/config-slack-channel.ts +7 -1
- package/src/daemon/handlers/config-telegram.ts +6 -1
- package/src/daemon/handlers/conversations.ts +2 -2
- package/src/daemon/handlers/skills.ts +4 -0
- package/src/daemon/lifecycle.ts +28 -4
- package/src/daemon/providers-setup.ts +1 -1
- package/src/daemon/server.ts +1 -5
- package/src/daemon/shutdown-handlers.ts +9 -3
- package/src/daemon/tool-side-effects.ts +40 -0
- package/src/daemon/trace-emitter.ts +26 -2
- package/src/events/domain-events.ts +1 -1
- package/src/events/tool-permission-telemetry-listener.ts +46 -0
- package/src/inbound/platform-callback-registration.ts +0 -18
- package/src/media/app-icon-generator.ts +15 -8
- package/src/media/avatar-router.ts +15 -8
- package/src/media/gemini-image-service.ts +125 -21
- package/src/memory/attachments-store.ts +3 -3
- package/src/memory/channel-verification-sessions.ts +6 -6
- package/src/memory/conversation-crud.ts +196 -1
- package/src/memory/{thread-starters-cadence.ts → conversation-starters-cadence.ts} +9 -42
- package/src/memory/conversation-title-service.ts +2 -3
- package/src/memory/db-init.ts +25 -1
- package/src/memory/invite-store.ts +4 -4
- package/src/memory/items-extractor.ts +4 -4
- package/src/memory/job-handlers/{thread-starters.ts → conversation-starters.ts} +123 -38
- package/src/memory/jobs-store.ts +3 -2
- package/src/memory/jobs-worker.ts +7 -5
- package/src/memory/lifecycle-events-store.ts +63 -0
- package/src/memory/migrations/172-rename-created-by-session-id.ts +27 -0
- package/src/memory/migrations/173-rename-source-session-id.ts +16 -0
- package/src/memory/migrations/174-rename-thread-starters-table.ts +52 -0
- package/src/memory/migrations/175-create-lifecycle-events.ts +15 -0
- package/src/memory/migrations/176-drop-capability-card-state.ts +36 -0
- package/src/memory/migrations/177-create-trace-events-table.ts +40 -0
- package/src/memory/migrations/index.ts +6 -0
- package/src/memory/migrations/registry.ts +13 -0
- package/src/memory/retriever.test.ts +223 -96
- package/src/memory/retriever.ts +115 -138
- package/src/memory/schema/calls.ts +1 -1
- package/src/memory/schema/contacts.ts +1 -1
- package/src/memory/schema/infrastructure.ts +29 -0
- package/src/memory/schema/memory-core.ts +7 -17
- package/src/memory/schema/notifications.ts +1 -1
- package/src/memory/search/formatting.ts +23 -6
- package/src/memory/search/lexical.ts +2 -0
- package/src/memory/search/semantic.ts +2 -0
- package/src/memory/search/staleness.ts +5 -1
- package/src/memory/search/types.ts +4 -0
- package/src/memory/task-memory-cleanup.ts +96 -6
- package/src/memory/trace-event-store.ts +148 -0
- package/src/notifications/README.md +1 -1
- package/src/notifications/decision-engine.ts +45 -4
- package/src/notifications/emit-signal.ts +5 -4
- package/src/notifications/events-store.ts +4 -4
- package/src/notifications/signal.ts +1 -1
- package/src/oauth/manual-token-connection.ts +49 -25
- package/src/permissions/checker.ts +6 -5
- package/src/permissions/defaults.ts +4 -4
- package/src/prompts/__tests__/build-cli-reference-section.test.ts +9 -90
- package/src/prompts/cache-boundary.ts +8 -0
- package/src/prompts/system-prompt.ts +105 -634
- package/src/prompts/templates/BOOTSTRAP.md +172 -33
- package/src/prompts/templates/IDENTITY.md +8 -24
- package/src/prompts/templates/SOUL.md +20 -41
- package/src/prompts/templates/USER.md +3 -19
- package/src/prompts/user-reference.ts +14 -16
- package/src/providers/anthropic/client.ts +51 -19
- package/src/providers/gemini/client.ts +6 -9
- package/src/providers/managed-proxy/constants.ts +1 -7
- package/src/providers/managed-proxy/context.ts +0 -1
- package/src/providers/model-intents.ts +5 -5
- package/src/providers/openai/client.ts +10 -1
- package/src/providers/openrouter/client.ts +1 -0
- package/src/providers/ratelimit.ts +0 -35
- package/src/providers/registry.ts +3 -5
- package/src/providers/retry.ts +18 -1
- package/src/runtime/access-request-helper.ts +16 -2
- package/src/runtime/auth/route-policy.ts +7 -0
- package/src/runtime/channel-verification-service.ts +1 -1
- package/src/runtime/confirmation-request-guardian-bridge.ts +1 -1
- package/src/runtime/guardian-vellum-migration.ts +61 -1
- package/src/runtime/http-server.ts +8 -4
- package/src/runtime/migrations/vbundle-builder.ts +212 -32
- package/src/runtime/migrations/vbundle-import-analyzer.ts +74 -8
- package/src/runtime/migrations/vbundle-importer.ts +66 -1
- package/src/runtime/migrations/vbundle-validator.ts +17 -3
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +4 -4
- package/src/runtime/routes/attachment-routes.ts +2 -2
- package/src/runtime/routes/btw-routes.ts +93 -0
- package/src/runtime/routes/channel-verification-routes.ts +19 -2
- package/src/runtime/routes/conversation-management-routes.ts +55 -1
- package/src/runtime/routes/conversation-query-routes.ts +1 -1
- package/src/runtime/routes/conversation-routes.ts +49 -5
- package/src/runtime/routes/conversation-starter-routes.ts +207 -0
- package/src/runtime/routes/guardian-bootstrap-routes.ts +13 -9
- package/src/runtime/routes/identity-intro-cache.ts +105 -0
- package/src/runtime/routes/identity-routes.ts +51 -0
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +1 -1
- package/src/runtime/routes/migration-routes.ts +25 -13
- package/src/runtime/routes/secret-routes.ts +18 -0
- package/src/runtime/routes/settings-routes.ts +9 -9
- package/src/runtime/routes/telemetry-routes.ts +53 -0
- package/src/runtime/routes/trace-event-routes.ts +62 -0
- package/src/runtime/tool-grant-request-helper.ts +1 -1
- package/src/runtime/verification-outbound-actions.ts +47 -31
- package/src/security/encrypted-store.ts +262 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +222 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +7 -2
- package/src/telemetry/usage-telemetry-reporter.ts +53 -4
- package/src/tools/AGENTS.md +11 -11
- package/src/tools/acp/spawn.ts +1 -1
- package/src/tools/apps/executors.ts +8 -8
- package/src/tools/apps/registry.ts +1 -1
- package/src/tools/assets/materialize.ts +6 -6
- package/src/tools/assets/search.ts +10 -10
- package/src/tools/browser/__tests__/auth-cache.test.ts +2 -2
- package/src/tools/browser/__tests__/auth-detector.test.ts +4 -4
- package/src/tools/browser/auth-detector.ts +6 -6
- package/src/tools/browser/browser-execution.ts +13 -13
- package/src/tools/browser/browser-manager.ts +3 -3
- package/src/tools/browser/chrome-cdp.ts +5 -5
- package/src/tools/browser/jit-auth.ts +2 -2
- package/src/tools/browser/network-recorder.test.ts +2 -2
- package/src/tools/browser/network-recorder.ts +3 -3
- package/src/tools/browser/runtime-check.ts +3 -3
- package/src/tools/claude-code/claude-code.ts +2 -2
- package/src/tools/computer-use/definitions.ts +18 -18
- package/src/tools/credential-execution/make-authenticated-request.ts +4 -4
- package/src/tools/credential-execution/manage-secure-command-tool.ts +3 -3
- package/src/tools/credential-execution/run-authenticated-command.ts +4 -4
- package/src/tools/credentials/broker-types.ts +5 -5
- package/src/tools/credentials/broker.ts +15 -15
- package/src/tools/credentials/metadata-store.ts +2 -2
- package/src/tools/credentials/resolve.ts +1 -1
- package/src/tools/credentials/selection.ts +1 -1
- package/src/tools/credentials/tool-policy.ts +1 -1
- package/src/tools/credentials/vault.ts +115 -25
- package/src/tools/execution-target.ts +2 -2
- package/src/tools/executor.ts +7 -7
- package/src/tools/filesystem/edit.ts +2 -2
- package/src/tools/filesystem/read.ts +15 -4
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +18 -1
- package/src/tools/host-filesystem/write.ts +1 -1
- package/src/tools/host-terminal/host-shell.ts +9 -8
- package/src/tools/mcp/mcp-tool-factory.ts +7 -6
- package/src/tools/memory/definitions.ts +6 -5
- package/src/tools/memory/handlers.test.ts +1 -1
- package/src/tools/network/__tests__/web-search.test.ts +3 -3
- package/src/tools/network/domain-normalize.ts +2 -2
- package/src/tools/network/script-proxy/session-manager.ts +10 -10
- package/src/tools/network/web-fetch.ts +1 -1
- package/src/tools/network/web-search.ts +3 -3
- package/src/tools/permission-checker.ts +8 -8
- package/src/tools/registry.ts +7 -7
- package/src/tools/schedule/list.ts +2 -2
- package/src/tools/schema-transforms.ts +31 -21
- package/src/tools/secret-detection-handler.ts +1 -1
- package/src/tools/sensitive-output-placeholders.ts +1 -1
- package/src/tools/shared/filesystem/edit-engine.ts +1 -1
- package/src/tools/shared/filesystem/file-ops-service.ts +3 -3
- package/src/tools/shared/filesystem/image-read.ts +25 -5
- package/src/tools/shared/filesystem/path-policy.ts +2 -2
- package/src/tools/shared/shell-output.ts +1 -1
- package/src/tools/side-effects.ts +1 -1
- package/src/tools/skills/execute.ts +1 -1
- package/src/tools/skills/load.ts +3 -3
- package/src/tools/skills/sandbox-runner.ts +3 -3
- package/src/tools/subagent/read.ts +1 -1
- package/src/tools/subagent/spawn.ts +2 -2
- package/src/tools/swarm/delegate.ts +3 -3
- package/src/tools/system/request-permission.ts +5 -4
- package/src/tools/terminal/backends/native.ts +4 -4
- package/src/tools/terminal/parser.ts +6 -6
- package/src/tools/terminal/sandbox-diagnostics.ts +1 -1
- package/src/tools/terminal/shell.ts +16 -16
- package/src/tools/tool-approval-handler.ts +21 -12
- package/src/tools/tool-manifest.ts +4 -4
- package/src/tools/types.ts +3 -3
- package/src/tools/ui-surface/definitions.ts +9 -37
- package/src/tools/watcher/list.ts +1 -1
- package/src/util/logger.ts +7 -2
- package/src/util/pricing.ts +4 -0
- package/src/util/retry.ts +29 -1
- package/src/workspace/migrations/007-web-search-provider-rename.ts +37 -0
- package/src/workspace/migrations/registry.ts +2 -0
- package/src/__tests__/cli-help-reference-sync.test.ts +0 -26
- package/src/__tests__/onboarding-starter-tasks.test.ts +0 -190
- package/src/cli/reference.ts +0 -38
- package/src/memory/job-handlers/capability-cards.ts +0 -420
- package/src/runtime/routes/thread-starter-routes.ts +0 -294
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { type DrizzleDb, getSqliteFrom } from "../db-connection.js";
|
|
2
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Rename `thread_starters` table to `conversation_starters` and recreate
|
|
6
|
+
* indexes with new names, aligning with the thread → conversation
|
|
7
|
+
* terminology unification.
|
|
8
|
+
*/
|
|
9
|
+
export function migrateRenameThreadStartersTable(database: DrizzleDb): void {
|
|
10
|
+
withCrashRecovery(
|
|
11
|
+
database,
|
|
12
|
+
"migration_rename_thread_starters_table_v1",
|
|
13
|
+
() => {
|
|
14
|
+
const raw = getSqliteFrom(database);
|
|
15
|
+
|
|
16
|
+
// Check the old table exists before attempting anything
|
|
17
|
+
const oldTableExists = raw
|
|
18
|
+
.query(
|
|
19
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'thread_starters'`,
|
|
20
|
+
)
|
|
21
|
+
.get();
|
|
22
|
+
if (!oldTableExists) return;
|
|
23
|
+
|
|
24
|
+
// Rename the physical table
|
|
25
|
+
raw.exec(
|
|
26
|
+
/*sql*/ `ALTER TABLE thread_starters RENAME TO conversation_starters`,
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
// Drop old indexes and recreate with new names.
|
|
30
|
+
// SQLite automatically updates index table references on RENAME, but the
|
|
31
|
+
// index names still reference the old naming convention — drop and recreate
|
|
32
|
+
// with consistent names pointing at the new table.
|
|
33
|
+
|
|
34
|
+
raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_thread_starters_batch`);
|
|
35
|
+
raw.exec(
|
|
36
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversation_starters_batch ON conversation_starters(generation_batch, created_at)`,
|
|
37
|
+
);
|
|
38
|
+
|
|
39
|
+
raw.exec(/*sql*/ `DROP INDEX IF EXISTS idx_thread_starters_card_type`);
|
|
40
|
+
raw.exec(
|
|
41
|
+
/*sql*/ `CREATE INDEX IF NOT EXISTS idx_conversation_starters_card_type ON conversation_starters(card_type, scope_id)`,
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
// Migrate checkpoint keys from old thread_starters: prefix to
|
|
45
|
+
// conversation_starters: so existing checkpoint data is found by
|
|
46
|
+
// the renamed code paths and unnecessary re-generation is avoided.
|
|
47
|
+
raw.exec(
|
|
48
|
+
/*sql*/ `UPDATE memory_checkpoints SET key = replace(key, 'thread_starters:', 'conversation_starters:') WHERE key LIKE 'thread_starters:%'`,
|
|
49
|
+
);
|
|
50
|
+
},
|
|
51
|
+
);
|
|
52
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Create the lifecycle_events table for tracking app lifecycle telemetry
|
|
5
|
+
* (app_open, hatch, etc.).
|
|
6
|
+
*/
|
|
7
|
+
export function createLifecycleEventsTable(database: DrizzleDb): void {
|
|
8
|
+
database.run(/*sql*/ `
|
|
9
|
+
CREATE TABLE IF NOT EXISTS lifecycle_events (
|
|
10
|
+
id TEXT PRIMARY KEY,
|
|
11
|
+
event_name TEXT NOT NULL,
|
|
12
|
+
created_at INTEGER NOT NULL
|
|
13
|
+
)
|
|
14
|
+
`);
|
|
15
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_drop_capability_card_state_v1";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Remove persisted capability-card state after the card feed was deleted.
|
|
9
|
+
*
|
|
10
|
+
* Conversation starters remain in place, but card rows, category relevance
|
|
11
|
+
* state, and queued generation jobs are dead data and should not survive.
|
|
12
|
+
*/
|
|
13
|
+
export function migrateDropCapabilityCardState(database: DrizzleDb): void {
|
|
14
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
15
|
+
const raw = getSqliteFrom(database);
|
|
16
|
+
|
|
17
|
+
const conversationStartersExists = raw
|
|
18
|
+
.query(
|
|
19
|
+
`SELECT 1 FROM sqlite_master WHERE type = 'table' AND name = 'conversation_starters'`,
|
|
20
|
+
)
|
|
21
|
+
.get();
|
|
22
|
+
if (conversationStartersExists) {
|
|
23
|
+
raw.exec(
|
|
24
|
+
/*sql*/ `DELETE FROM conversation_starters WHERE card_type = 'card'`,
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
raw.exec(
|
|
29
|
+
/*sql*/ `DELETE FROM memory_jobs WHERE type = 'generate_capability_cards'`,
|
|
30
|
+
);
|
|
31
|
+
raw.exec(
|
|
32
|
+
/*sql*/ `DELETE FROM memory_checkpoints WHERE key LIKE 'capability_cards:%'`,
|
|
33
|
+
);
|
|
34
|
+
raw.exec(/*sql*/ `DROP TABLE IF EXISTS capability_card_categories`);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { DrizzleDb } from "../db-connection.js";
|
|
2
|
+
import { getSqliteFrom } from "../db-connection.js";
|
|
3
|
+
import { withCrashRecovery } from "./validate-migration-state.js";
|
|
4
|
+
|
|
5
|
+
const CHECKPOINT_KEY = "migration_create_trace_events_table_v1";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Create the trace_events table for persisting trace/activity events
|
|
9
|
+
* so the Logs panel has data across sessions.
|
|
10
|
+
*/
|
|
11
|
+
export function migrateCreateTraceEventsTable(database: DrizzleDb): void {
|
|
12
|
+
withCrashRecovery(database, CHECKPOINT_KEY, () => {
|
|
13
|
+
const raw = getSqliteFrom(database);
|
|
14
|
+
|
|
15
|
+
raw.exec(/*sql*/ `
|
|
16
|
+
CREATE TABLE IF NOT EXISTS trace_events (
|
|
17
|
+
event_id TEXT PRIMARY KEY,
|
|
18
|
+
conversation_id TEXT NOT NULL,
|
|
19
|
+
request_id TEXT,
|
|
20
|
+
timestamp_ms INTEGER NOT NULL,
|
|
21
|
+
sequence INTEGER NOT NULL,
|
|
22
|
+
kind TEXT NOT NULL,
|
|
23
|
+
status TEXT,
|
|
24
|
+
summary TEXT NOT NULL,
|
|
25
|
+
attributes_json TEXT,
|
|
26
|
+
created_at INTEGER NOT NULL
|
|
27
|
+
)
|
|
28
|
+
`);
|
|
29
|
+
|
|
30
|
+
raw.exec(/*sql*/ `
|
|
31
|
+
CREATE INDEX IF NOT EXISTS idx_trace_events_conversation_id
|
|
32
|
+
ON trace_events (conversation_id)
|
|
33
|
+
`);
|
|
34
|
+
|
|
35
|
+
raw.exec(/*sql*/ `
|
|
36
|
+
CREATE INDEX IF NOT EXISTS idx_trace_events_conversation_timestamp
|
|
37
|
+
ON trace_events (conversation_id, timestamp_ms)
|
|
38
|
+
`);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
@@ -113,6 +113,12 @@ export { migrateRenameSequenceStepsReplyKey } from "./168-rename-sequence-steps-
|
|
|
113
113
|
export { migrateRenameGmailProviderKeyToGoogle } from "./169-rename-gmail-provider-key-to-google.js";
|
|
114
114
|
export { migrateCreateThreadStartersTable } from "./170-thread-starters-table.js";
|
|
115
115
|
export { migrateCapabilityCardColumns } from "./171-capability-card-columns.js";
|
|
116
|
+
export { migrateRenameCreatedBySessionIdColumns } from "./172-rename-created-by-session-id.js";
|
|
117
|
+
export { migrateRenameSourceSessionIdColumn } from "./173-rename-source-session-id.js";
|
|
118
|
+
export { migrateRenameThreadStartersTable } from "./174-rename-thread-starters-table.js";
|
|
119
|
+
export { createLifecycleEventsTable } from "./175-create-lifecycle-events.js";
|
|
120
|
+
export { migrateDropCapabilityCardState } from "./176-drop-capability-card-state.js";
|
|
121
|
+
export { migrateCreateTraceEventsTable } from "./177-create-trace-events-table.js";
|
|
116
122
|
export {
|
|
117
123
|
MIGRATION_REGISTRY,
|
|
118
124
|
type MigrationRegistryEntry,
|
|
@@ -215,6 +215,19 @@ export const MIGRATION_REGISTRY: MigrationRegistryEntry[] = [
|
|
|
215
215
|
description:
|
|
216
216
|
"Rename integration:gmail provider key to integration:google across oauth_providers, oauth_apps, and oauth_connections",
|
|
217
217
|
},
|
|
218
|
+
{
|
|
219
|
+
key: "migration_rename_thread_starters_table_v1",
|
|
220
|
+
version: 32,
|
|
221
|
+
description:
|
|
222
|
+
"Rename thread_starters table to conversation_starters and recreate indexes with new names",
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
key: "migration_drop_capability_card_state_v1",
|
|
226
|
+
version: 33,
|
|
227
|
+
dependsOn: ["migration_rename_thread_starters_table_v1"],
|
|
228
|
+
description:
|
|
229
|
+
"Remove deleted capability-card rows, jobs, checkpoints, and category state",
|
|
230
|
+
},
|
|
218
231
|
];
|
|
219
232
|
|
|
220
233
|
export interface MigrationValidationResult {
|
|
@@ -95,8 +95,7 @@ import {
|
|
|
95
95
|
} from "../memory/qdrant-circuit-breaker.js";
|
|
96
96
|
import {
|
|
97
97
|
buildMemoryRecall,
|
|
98
|
-
|
|
99
|
-
stripMemoryRecallMessages,
|
|
98
|
+
injectMemoryRecallAsUserBlock,
|
|
100
99
|
} from "../memory/retriever.js";
|
|
101
100
|
import {
|
|
102
101
|
conversations,
|
|
@@ -104,15 +103,24 @@ import {
|
|
|
104
103
|
memoryItemSources,
|
|
105
104
|
messages,
|
|
106
105
|
} from "../memory/schema.js";
|
|
106
|
+
import type { ContentBlock, Message } from "../providers/types.js";
|
|
107
107
|
|
|
108
108
|
// ---------------------------------------------------------------------------
|
|
109
109
|
// Helpers
|
|
110
110
|
// ---------------------------------------------------------------------------
|
|
111
111
|
|
|
112
|
+
/** Extract text from a content block, asserting it is a text block. */
|
|
113
|
+
function textOf(block: ContentBlock): string {
|
|
114
|
+
if (block.type !== "text")
|
|
115
|
+
throw new Error(`Expected text block, got ${block.type}`);
|
|
116
|
+
return block.text;
|
|
117
|
+
}
|
|
118
|
+
|
|
112
119
|
function insertConversation(
|
|
113
120
|
db: ReturnType<typeof getDb>,
|
|
114
121
|
id: string,
|
|
115
122
|
createdAt: number,
|
|
123
|
+
opts?: { contextCompactedMessageCount?: number },
|
|
116
124
|
) {
|
|
117
125
|
db.insert(conversations)
|
|
118
126
|
.values({
|
|
@@ -124,7 +132,7 @@ function insertConversation(
|
|
|
124
132
|
totalOutputTokens: 0,
|
|
125
133
|
totalEstimatedCost: 0,
|
|
126
134
|
contextSummary: null,
|
|
127
|
-
contextCompactedMessageCount: 0,
|
|
135
|
+
contextCompactedMessageCount: opts?.contextCompactedMessageCount ?? 0,
|
|
128
136
|
contextCompactedAt: null,
|
|
129
137
|
})
|
|
130
138
|
.run();
|
|
@@ -318,8 +326,178 @@ describe("Memory Retriever Pipeline", () => {
|
|
|
318
326
|
expect(result.tier1Count).toBeDefined();
|
|
319
327
|
expect(result.tier2Count).toBeDefined();
|
|
320
328
|
expect(result.hybridSearchMs).toBeDefined();
|
|
321
|
-
// Recency search finds candidates
|
|
329
|
+
// Recency search finds raw candidates from this conversation…
|
|
330
|
+
expect(result.recencyHits).toBeGreaterThan(0);
|
|
331
|
+
// …but they are filtered out because they belong to the active
|
|
332
|
+
// conversation and are already present in the conversation history.
|
|
333
|
+
expect(result.mergedCount).toBe(0);
|
|
334
|
+
});
|
|
335
|
+
|
|
336
|
+
// -----------------------------------------------------------------------
|
|
337
|
+
// Current-conversation segment filtering
|
|
338
|
+
// -----------------------------------------------------------------------
|
|
339
|
+
|
|
340
|
+
test("current-conversation segments are filtered from recency results", async () => {
|
|
341
|
+
const db = getDb();
|
|
342
|
+
const now = Date.now();
|
|
343
|
+
const activeConv = "conv-active";
|
|
344
|
+
const otherConv = "conv-other";
|
|
345
|
+
|
|
346
|
+
insertConversation(db, activeConv, now - 60_000);
|
|
347
|
+
insertConversation(db, otherConv, now - 120_000);
|
|
348
|
+
|
|
349
|
+
// Messages and segments in the active conversation (should be filtered)
|
|
350
|
+
insertMessage(
|
|
351
|
+
db,
|
|
352
|
+
"msg-a1",
|
|
353
|
+
activeConv,
|
|
354
|
+
"user",
|
|
355
|
+
"hello world",
|
|
356
|
+
now - 50_000,
|
|
357
|
+
);
|
|
358
|
+
insertSegment(
|
|
359
|
+
db,
|
|
360
|
+
"seg-a1",
|
|
361
|
+
"msg-a1",
|
|
362
|
+
activeConv,
|
|
363
|
+
"user",
|
|
364
|
+
"hello world",
|
|
365
|
+
now - 50_000,
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
// Messages and segments in a different conversation (should be kept)
|
|
369
|
+
insertMessage(
|
|
370
|
+
db,
|
|
371
|
+
"msg-o1",
|
|
372
|
+
otherConv,
|
|
373
|
+
"user",
|
|
374
|
+
"hello world from other",
|
|
375
|
+
now - 100_000,
|
|
376
|
+
);
|
|
377
|
+
insertSegment(
|
|
378
|
+
db,
|
|
379
|
+
"seg-o1",
|
|
380
|
+
"msg-o1",
|
|
381
|
+
otherConv,
|
|
382
|
+
"user",
|
|
383
|
+
"hello world from other",
|
|
384
|
+
now - 100_000,
|
|
385
|
+
);
|
|
386
|
+
|
|
387
|
+
// Query from the active conversation
|
|
388
|
+
const result = await buildMemoryRecall(
|
|
389
|
+
"hello world",
|
|
390
|
+
activeConv,
|
|
391
|
+
TEST_CONFIG,
|
|
392
|
+
);
|
|
393
|
+
|
|
394
|
+
expect(result.enabled).toBe(true);
|
|
395
|
+
// Recency search finds segments from the active conversation
|
|
396
|
+
expect(result.recencyHits).toBeGreaterThan(0);
|
|
397
|
+
// But they are filtered out of merged results; only other-conversation
|
|
398
|
+
// segments would survive (none in this case since recency is scoped to
|
|
399
|
+
// the active conversation).
|
|
400
|
+
expect(result.mergedCount).toBe(0);
|
|
401
|
+
});
|
|
402
|
+
|
|
403
|
+
test("compacted segments from current conversation are preserved in memory", async () => {
|
|
404
|
+
const db = getDb();
|
|
405
|
+
const now = Date.now();
|
|
406
|
+
const convId = "conv-compacted";
|
|
407
|
+
|
|
408
|
+
// Create a conversation where 2 messages have been compacted away
|
|
409
|
+
insertConversation(db, convId, now - 120_000, {
|
|
410
|
+
contextCompactedMessageCount: 2,
|
|
411
|
+
});
|
|
412
|
+
|
|
413
|
+
// Older messages (compacted out of context window) — their segments
|
|
414
|
+
// should NOT be filtered because the model can no longer see them
|
|
415
|
+
insertMessage(
|
|
416
|
+
db,
|
|
417
|
+
"msg-old-1",
|
|
418
|
+
convId,
|
|
419
|
+
"user",
|
|
420
|
+
"old discussion topic",
|
|
421
|
+
now - 100_000,
|
|
422
|
+
);
|
|
423
|
+
insertMessage(
|
|
424
|
+
db,
|
|
425
|
+
"msg-old-2",
|
|
426
|
+
convId,
|
|
427
|
+
"assistant",
|
|
428
|
+
"old response",
|
|
429
|
+
now - 90_000,
|
|
430
|
+
);
|
|
431
|
+
|
|
432
|
+
// Newer messages (still in context window) — their segments should
|
|
433
|
+
// be filtered since the model can still see them
|
|
434
|
+
insertMessage(
|
|
435
|
+
db,
|
|
436
|
+
"msg-new-1",
|
|
437
|
+
convId,
|
|
438
|
+
"user",
|
|
439
|
+
"recent discussion",
|
|
440
|
+
now - 50_000,
|
|
441
|
+
);
|
|
442
|
+
insertMessage(
|
|
443
|
+
db,
|
|
444
|
+
"msg-new-2",
|
|
445
|
+
convId,
|
|
446
|
+
"assistant",
|
|
447
|
+
"recent response",
|
|
448
|
+
now - 40_000,
|
|
449
|
+
);
|
|
450
|
+
|
|
451
|
+
// Segments from compacted messages (should survive filtering)
|
|
452
|
+
insertSegment(
|
|
453
|
+
db,
|
|
454
|
+
"seg-old-1",
|
|
455
|
+
"msg-old-1",
|
|
456
|
+
convId,
|
|
457
|
+
"user",
|
|
458
|
+
"old discussion topic details",
|
|
459
|
+
now - 100_000,
|
|
460
|
+
);
|
|
461
|
+
insertSegment(
|
|
462
|
+
db,
|
|
463
|
+
"seg-old-2",
|
|
464
|
+
"msg-old-2",
|
|
465
|
+
convId,
|
|
466
|
+
"assistant",
|
|
467
|
+
"old response details",
|
|
468
|
+
now - 90_000,
|
|
469
|
+
);
|
|
470
|
+
|
|
471
|
+
// Segments from in-context messages (should be filtered)
|
|
472
|
+
insertSegment(
|
|
473
|
+
db,
|
|
474
|
+
"seg-new-1",
|
|
475
|
+
"msg-new-1",
|
|
476
|
+
convId,
|
|
477
|
+
"user",
|
|
478
|
+
"recent discussion details",
|
|
479
|
+
now - 50_000,
|
|
480
|
+
);
|
|
481
|
+
insertSegment(
|
|
482
|
+
db,
|
|
483
|
+
"seg-new-2",
|
|
484
|
+
"msg-new-2",
|
|
485
|
+
convId,
|
|
486
|
+
"assistant",
|
|
487
|
+
"recent response details",
|
|
488
|
+
now - 40_000,
|
|
489
|
+
);
|
|
490
|
+
|
|
491
|
+
const result = await buildMemoryRecall(
|
|
492
|
+
"discussion topic",
|
|
493
|
+
convId,
|
|
494
|
+
TEST_CONFIG,
|
|
495
|
+
);
|
|
496
|
+
|
|
497
|
+
expect(result.enabled).toBe(true);
|
|
498
|
+
// Recency search finds segments from this conversation
|
|
322
499
|
expect(result.recencyHits).toBeGreaterThan(0);
|
|
500
|
+
// Compacted segments survive filtering — they are no longer in context
|
|
323
501
|
expect(result.mergedCount).toBeGreaterThan(0);
|
|
324
502
|
});
|
|
325
503
|
|
|
@@ -527,10 +705,10 @@ describe("Memory Retriever Pipeline", () => {
|
|
|
527
705
|
expect(result.enabled).toBe(true);
|
|
528
706
|
// Semantic/hybrid search should be skipped
|
|
529
707
|
expect(result.semanticHits).toBe(0);
|
|
530
|
-
// Recency search finds candidates
|
|
531
|
-
// since recency-only candidates have no semantic score component)
|
|
708
|
+
// Recency search finds raw candidates…
|
|
532
709
|
expect(result.recencyHits).toBeGreaterThan(0);
|
|
533
|
-
|
|
710
|
+
// …but current-conversation segments are filtered out
|
|
711
|
+
expect(result.mergedCount).toBe(0);
|
|
534
712
|
});
|
|
535
713
|
|
|
536
714
|
// -----------------------------------------------------------------------
|
|
@@ -588,115 +766,62 @@ describe("Memory Retriever Pipeline", () => {
|
|
|
588
766
|
});
|
|
589
767
|
|
|
590
768
|
// -----------------------------------------------------------------------
|
|
591
|
-
//
|
|
769
|
+
// injectMemoryRecallAsUserBlock
|
|
592
770
|
// -----------------------------------------------------------------------
|
|
593
771
|
|
|
594
|
-
test("
|
|
595
|
-
|
|
596
|
-
role: "user" | "assistant";
|
|
597
|
-
content: Array<{ type: string; text?: string }>;
|
|
598
|
-
};
|
|
599
|
-
const recallText =
|
|
600
|
-
"<memory_context>\n\n<relevant_context>\nsome context\n</relevant_context>\n\n</memory_context>";
|
|
601
|
-
|
|
602
|
-
const msgs: Msg[] = [
|
|
603
|
-
{
|
|
604
|
-
role: "user",
|
|
605
|
-
content: [{ type: "text", text: recallText }],
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
role: "assistant",
|
|
609
|
-
content: [{ type: "text", text: "[Memory context loaded.]" }],
|
|
610
|
-
},
|
|
772
|
+
test("injectMemoryRecallAsUserBlock: prepends memory context to last user message", () => {
|
|
773
|
+
const msgs: Message[] = [
|
|
611
774
|
{
|
|
612
775
|
role: "user",
|
|
613
|
-
content: [{ type: "text", text: "Hello
|
|
776
|
+
content: [{ type: "text", text: "Hello" }],
|
|
614
777
|
},
|
|
615
778
|
];
|
|
616
779
|
|
|
617
|
-
const
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
expect(cleaned[0].content[0].text).toBe(
|
|
621
|
-
"Hello, what do you know about me?",
|
|
622
|
-
);
|
|
623
|
-
});
|
|
780
|
+
const recallText =
|
|
781
|
+
"<memory_context __injected>\n\n<relevant_context>\ntest\n</relevant_context>\n\n</memory_context>";
|
|
782
|
+
const result = injectMemoryRecallAsUserBlock(msgs, recallText);
|
|
624
783
|
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
784
|
+
// Same number of messages — no synthetic pair added
|
|
785
|
+
expect(result).toHaveLength(1);
|
|
786
|
+
expect(result[0].role).toBe("user");
|
|
787
|
+
// Memory context prepended as first content block
|
|
788
|
+
expect(result[0].content).toHaveLength(2);
|
|
789
|
+
expect(textOf(result[0].content[0])).toBe(recallText);
|
|
790
|
+
// Original user text preserved as second block
|
|
791
|
+
expect(textOf(result[0].content[1])).toBe("Hello");
|
|
792
|
+
});
|
|
634
793
|
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
role: "user",
|
|
638
|
-
content: [{ type: "text", text: actualRecall }],
|
|
639
|
-
},
|
|
640
|
-
{
|
|
641
|
-
role: "assistant",
|
|
642
|
-
content: [{ type: "text", text: "[Memory context loaded.]" }],
|
|
643
|
-
},
|
|
794
|
+
test("injectMemoryRecallAsUserBlock: no-op for empty text", () => {
|
|
795
|
+
const msgs: Message[] = [
|
|
644
796
|
{
|
|
645
797
|
role: "user",
|
|
646
|
-
content: [{ type: "text", text: "
|
|
798
|
+
content: [{ type: "text", text: "Hello" }],
|
|
647
799
|
},
|
|
648
800
|
];
|
|
649
801
|
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
expect(
|
|
653
|
-
expect(cleaned[0].content[0].text).toBe("follow-up question");
|
|
802
|
+
const result = injectMemoryRecallAsUserBlock(msgs, "");
|
|
803
|
+
expect(result).toHaveLength(1);
|
|
804
|
+
expect(textOf(result[0].content[0])).toBe("Hello");
|
|
654
805
|
});
|
|
655
806
|
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
type Msg = {
|
|
662
|
-
role: "user" | "assistant";
|
|
663
|
-
content: Array<{ type: string; text?: string }>;
|
|
664
|
-
};
|
|
665
|
-
const msgs: Msg[] = [
|
|
666
|
-
{
|
|
667
|
-
role: "user",
|
|
668
|
-
content: [{ type: "text", text: "Hello" }],
|
|
669
|
-
},
|
|
807
|
+
test("injectMemoryRecallAsUserBlock: preserves history before last user message", () => {
|
|
808
|
+
const msgs: Message[] = [
|
|
809
|
+
{ role: "user", content: [{ type: "text", text: "First" }] },
|
|
810
|
+
{ role: "assistant", content: [{ type: "text", text: "Response" }] },
|
|
811
|
+
{ role: "user", content: [{ type: "text", text: "Second" }] },
|
|
670
812
|
];
|
|
671
813
|
|
|
672
814
|
const recallText =
|
|
673
|
-
"<memory_context>\n\n<relevant_context>\
|
|
674
|
-
const result =
|
|
815
|
+
"<memory_context __injected>\n\n<relevant_context>\nfact\n</relevant_context>\n\n</memory_context>";
|
|
816
|
+
const result = injectMemoryRecallAsUserBlock(msgs, recallText);
|
|
675
817
|
|
|
676
818
|
expect(result).toHaveLength(3);
|
|
677
|
-
|
|
678
|
-
expect(result[0].
|
|
679
|
-
expect(result[1]
|
|
680
|
-
|
|
681
|
-
expect(result[2].
|
|
682
|
-
expect(result[2].content[
|
|
683
|
-
});
|
|
684
|
-
|
|
685
|
-
test("injectMemoryRecallAsSeparateMessage: no-op for empty text", () => {
|
|
686
|
-
type Msg = {
|
|
687
|
-
role: "user" | "assistant";
|
|
688
|
-
content: Array<{ type: string; text?: string }>;
|
|
689
|
-
};
|
|
690
|
-
const msgs: Msg[] = [
|
|
691
|
-
{
|
|
692
|
-
role: "user",
|
|
693
|
-
content: [{ type: "text", text: "Hello" }],
|
|
694
|
-
},
|
|
695
|
-
];
|
|
696
|
-
|
|
697
|
-
const result = injectMemoryRecallAsSeparateMessage(msgs, "");
|
|
698
|
-
expect(result).toHaveLength(1);
|
|
699
|
-
expect(result[0].content[0].text).toBe("Hello");
|
|
819
|
+
// Earlier messages unchanged
|
|
820
|
+
expect(result[0]).toBe(msgs[0]);
|
|
821
|
+
expect(result[1]).toBe(msgs[1]);
|
|
822
|
+
// Last user message has memory prepended
|
|
823
|
+
expect(textOf(result[2].content[0])).toBe(recallText);
|
|
824
|
+
expect(textOf(result[2].content[1])).toBe("Second");
|
|
700
825
|
});
|
|
701
826
|
|
|
702
827
|
// -----------------------------------------------------------------------
|
|
@@ -728,7 +853,9 @@ describe("Memory Retriever Pipeline", () => {
|
|
|
728
853
|
// pipeline proceeds non-degraded end-to-end.
|
|
729
854
|
expect(result.enabled).toBe(true);
|
|
730
855
|
expect(result.degraded).toBe(false);
|
|
731
|
-
// Recency search finds candidates; hybrid search returns empty from mock
|
|
856
|
+
// Recency search finds raw candidates; hybrid search returns empty from mock
|
|
732
857
|
expect(result.recencyHits).toBeGreaterThan(0);
|
|
858
|
+
// Current-conversation segments are filtered out of merged results
|
|
859
|
+
expect(result.mergedCount).toBe(0);
|
|
733
860
|
});
|
|
734
861
|
});
|