@vellumai/assistant 0.4.56 → 0.4.57
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 +185 -173
- 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 +237 -15
- package/src/__tests__/ephemeral-permissions.test.ts +4 -5
- package/src/__tests__/event-bus.test.ts +3 -3
- 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-shell-tool.test.ts +6 -6
- package/src/__tests__/http-user-message-parity.test.ts +2 -2
- 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 +1 -1
- package/src/__tests__/no-domain-routing-in-prompt-guard.test.ts +1 -1
- 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 +547 -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 +139 -274
- 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 +25 -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 +1 -0
- 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 +2 -2
- package/src/notifications/emit-signal.ts +4 -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 +166 -33
- package/src/prompts/templates/IDENTITY.md +8 -23
- 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 +46 -2
- 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 +1 -1
- 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 +63 -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 +9 -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/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 +8 -8
- 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 +263 -78
- package/src/skills/catalog-install.ts +10 -0
- package/src/skills/managed-store.ts +2 -0
- package/src/skills/skill-memory.ts +220 -0
- package/src/subagent/manager.ts +1 -4
- package/src/telemetry/types.ts +10 -1
- package/src/telemetry/usage-telemetry-reporter.test.ts +1 -1
- package/src/telemetry/usage-telemetry-reporter.ts +51 -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 +1 -1
- package/src/tools/filesystem/write.ts +1 -1
- package/src/tools/host-filesystem/edit.ts +2 -1
- package/src/tools/host-filesystem/read.ts +2 -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/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
|
@@ -11,10 +11,11 @@ import type { ToolContext } from "../tools/types.js";
|
|
|
11
11
|
// ---------------------------------------------------------------------------
|
|
12
12
|
|
|
13
13
|
let mockApiKey: string | undefined = "test-gemini-key";
|
|
14
|
+
let mockImageGenMode: "your-own" | "managed" = "your-own";
|
|
14
15
|
let mockGenerateResult = {
|
|
15
16
|
images: [{ mimeType: "image/png", dataBase64: "generated-data" }],
|
|
16
17
|
text: "A beautiful image",
|
|
17
|
-
resolvedModel: "gemini-
|
|
18
|
+
resolvedModel: "gemini-3.1-flash-image-preview",
|
|
18
19
|
};
|
|
19
20
|
let mockGenerateError: Error | null = null;
|
|
20
21
|
let lastGenerateCredentials: unknown = null;
|
|
@@ -29,11 +30,11 @@ mock.module("../config/loader.js", () => ({
|
|
|
29
30
|
model: "claude-opus-4-6",
|
|
30
31
|
},
|
|
31
32
|
"image-generation": {
|
|
32
|
-
mode:
|
|
33
|
+
mode: mockImageGenMode,
|
|
33
34
|
provider: "gemini",
|
|
34
|
-
model: "gemini-
|
|
35
|
+
model: "gemini-3.1-flash-image-preview",
|
|
35
36
|
},
|
|
36
|
-
"web-search": { mode: "your-own", provider: "
|
|
37
|
+
"web-search": { mode: "your-own", provider: "inference-provider-native" },
|
|
37
38
|
},
|
|
38
39
|
}),
|
|
39
40
|
}));
|
|
@@ -43,6 +44,10 @@ mock.module("../security/secure-keys.js", () => ({
|
|
|
43
44
|
if (account === "gemini") return mockApiKey;
|
|
44
45
|
return undefined;
|
|
45
46
|
},
|
|
47
|
+
getProviderKeyAsync: async (provider: string) => {
|
|
48
|
+
if (provider === "gemini") return mockApiKey;
|
|
49
|
+
return undefined;
|
|
50
|
+
},
|
|
46
51
|
}));
|
|
47
52
|
|
|
48
53
|
mock.module("../media/gemini-image-service.js", () => ({
|
|
@@ -171,10 +176,11 @@ const CONFIG_DIR = join(
|
|
|
171
176
|
|
|
172
177
|
beforeEach(() => {
|
|
173
178
|
mockApiKey = "test-gemini-key";
|
|
179
|
+
mockImageGenMode = "your-own";
|
|
174
180
|
mockGenerateResult = {
|
|
175
181
|
images: [{ mimeType: "image/png", dataBase64: "generated-data" }],
|
|
176
182
|
text: "A beautiful image",
|
|
177
|
-
resolvedModel: "gemini-
|
|
183
|
+
resolvedModel: "gemini-3.1-flash-image-preview",
|
|
178
184
|
};
|
|
179
185
|
mockGenerateError = null;
|
|
180
186
|
mockAttachments = [];
|
|
@@ -208,9 +214,9 @@ describe("image-studio skill script wrapper", () => {
|
|
|
208
214
|
expect(result.content).toContain("No Gemini API key");
|
|
209
215
|
});
|
|
210
216
|
|
|
211
|
-
test("
|
|
212
|
-
|
|
213
|
-
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/
|
|
217
|
+
test("managed mode uses managed proxy credentials", async () => {
|
|
218
|
+
mockImageGenMode = "managed";
|
|
219
|
+
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/gemini";
|
|
214
220
|
mockManagedProxyContext = {
|
|
215
221
|
enabled: true,
|
|
216
222
|
platformBaseUrl: "https://platform.example.com",
|
|
@@ -224,13 +230,25 @@ describe("image-studio skill script wrapper", () => {
|
|
|
224
230
|
expect(lastGenerateCredentials).toEqual({
|
|
225
231
|
type: "managed-proxy",
|
|
226
232
|
assistantApiKey: "managed-key-123",
|
|
227
|
-
baseUrl: "https://platform.example.com/v1/runtime-proxy/
|
|
233
|
+
baseUrl: "https://platform.example.com/v1/runtime-proxy/gemini",
|
|
228
234
|
});
|
|
229
235
|
});
|
|
230
236
|
|
|
231
|
-
test("
|
|
237
|
+
test("managed mode returns error when managed proxy is unavailable", async () => {
|
|
238
|
+
mockImageGenMode = "managed";
|
|
239
|
+
mockApiKey = "direct-key"; // should be ignored in managed mode
|
|
240
|
+
mockManagedBaseUrl = undefined;
|
|
241
|
+
|
|
242
|
+
const result = await run({ prompt: "a cat" }, fakeContext);
|
|
243
|
+
|
|
244
|
+
expect(result.isError).toBe(true);
|
|
245
|
+
expect(result.content).toContain("Managed proxy is not available");
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
test("your-own mode uses direct API key", async () => {
|
|
249
|
+
mockImageGenMode = "your-own";
|
|
232
250
|
mockApiKey = "direct-key";
|
|
233
|
-
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/
|
|
251
|
+
mockManagedBaseUrl = "https://platform.example.com/v1/runtime-proxy/gemini";
|
|
234
252
|
mockManagedProxyContext = {
|
|
235
253
|
enabled: true,
|
|
236
254
|
platformBaseUrl: "https://platform.example.com",
|
|
@@ -250,7 +268,7 @@ describe("image-studio skill script wrapper", () => {
|
|
|
250
268
|
|
|
251
269
|
expect(result.isError).toBe(false);
|
|
252
270
|
expect(result.content).toContain("Generated 1 image");
|
|
253
|
-
expect(result.content).toContain("gemini-
|
|
271
|
+
expect(result.content).toContain("gemini-3.1-flash-image-preview");
|
|
254
272
|
expect(result.content).toContain("A beautiful image");
|
|
255
273
|
expect(result.contentBlocks).toHaveLength(1);
|
|
256
274
|
expect(result.contentBlocks![0]).toEqual({
|
|
@@ -270,7 +288,7 @@ describe("image-studio skill script wrapper", () => {
|
|
|
270
288
|
{ mimeType: "image/png", dataBase64: "img2" },
|
|
271
289
|
],
|
|
272
290
|
text: undefined as unknown as string,
|
|
273
|
-
resolvedModel: "gemini-
|
|
291
|
+
resolvedModel: "gemini-3.1-flash-image-preview",
|
|
274
292
|
};
|
|
275
293
|
|
|
276
294
|
const result = await run({ prompt: "test", variants: 2 }, fakeContext);
|
|
@@ -357,8 +375,7 @@ describe("image-studio TOOLS.json manifest", () => {
|
|
|
357
375
|
expect(props.mode.enum).toEqual(["generate", "edit"]);
|
|
358
376
|
expect(props.attachment_ids.type).toBe("array");
|
|
359
377
|
expect(props.model.enum).toEqual([
|
|
360
|
-
"gemini-
|
|
361
|
-
"gemini-3-pro-image",
|
|
378
|
+
"gemini-3.1-flash-image-preview",
|
|
362
379
|
"gemini-3-pro-image-preview",
|
|
363
380
|
]);
|
|
364
381
|
expect(props.variants.type).toBe("number");
|
|
@@ -53,7 +53,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
53
53
|
model: "test",
|
|
54
54
|
provider: "test",
|
|
55
55
|
memory: { enabled: false },
|
|
56
|
-
rateLimit: { maxRequestsPerMinute: 0
|
|
56
|
+
rateLimit: { maxRequestsPerMinute: 0 },
|
|
57
57
|
timeouts: { shellDefaultTimeoutSec: 30, shellMaxTimeoutSec: 60 },
|
|
58
58
|
sandbox: { enabled: false, backend: "native" },
|
|
59
59
|
}),
|
|
@@ -82,6 +82,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
82
82
|
invalidateConfigCache: () => {},
|
|
83
83
|
}));
|
|
84
84
|
|
|
85
|
+
import { stripUserTextBlocksByPrefix } from "../daemon/conversation-runtime-assembly.js";
|
|
85
86
|
import { getDb, initializeDb, resetDb } from "../memory/db.js";
|
|
86
87
|
import {
|
|
87
88
|
resetCleanupScheduleThrottle,
|
|
@@ -89,8 +90,7 @@ import {
|
|
|
89
90
|
} from "../memory/jobs-worker.js";
|
|
90
91
|
import {
|
|
91
92
|
buildMemoryRecall,
|
|
92
|
-
|
|
93
|
-
stripMemoryRecallMessages,
|
|
93
|
+
injectMemoryRecallAsUserBlock,
|
|
94
94
|
} from "../memory/retriever.js";
|
|
95
95
|
import {
|
|
96
96
|
conversations,
|
|
@@ -98,6 +98,7 @@ import {
|
|
|
98
98
|
memoryItemSources,
|
|
99
99
|
messages,
|
|
100
100
|
} from "../memory/schema.js";
|
|
101
|
+
import type { Message } from "../providers/types.js";
|
|
101
102
|
|
|
102
103
|
describe("Memory lifecycle E2E regression", () => {
|
|
103
104
|
beforeAll(() => {
|
|
@@ -322,7 +323,7 @@ describe("Memory lifecycle E2E regression", () => {
|
|
|
322
323
|
totalOutputTokens: 0,
|
|
323
324
|
totalEstimatedCost: 0,
|
|
324
325
|
contextSummary: null,
|
|
325
|
-
contextCompactedMessageCount:
|
|
326
|
+
contextCompactedMessageCount: 1,
|
|
326
327
|
contextCompactedAt: null,
|
|
327
328
|
})
|
|
328
329
|
.run();
|
|
@@ -365,34 +366,39 @@ describe("Memory lifecycle E2E regression", () => {
|
|
|
365
366
|
expect(recall.enabled).toBe(true);
|
|
366
367
|
expect(recall.injectedText.length).toBeGreaterThan(0);
|
|
367
368
|
expect(recall.injectedTokens).toBeGreaterThan(0);
|
|
368
|
-
expect(recall.injectedText).toContain("<memory_context>");
|
|
369
|
+
expect(recall.injectedText).toContain("<memory_context __injected>");
|
|
369
370
|
expect(recall.injectedText).toContain("</memory_context>");
|
|
370
371
|
});
|
|
371
372
|
|
|
372
|
-
test("stripping removes <memory_context>
|
|
373
|
+
test("stripping removes <memory_context> block from injected recall", () => {
|
|
373
374
|
const memoryRecallText =
|
|
374
|
-
"<memory_context>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
375
|
-
const originalMessages = [
|
|
375
|
+
"<memory_context __injected>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
376
|
+
const originalMessages: Message[] = [
|
|
376
377
|
{
|
|
377
|
-
role: "user"
|
|
378
|
-
content: [{ type: "text", text: "Actual user request" }],
|
|
378
|
+
role: "user",
|
|
379
|
+
content: [{ type: "text" as const, text: "Actual user request" }],
|
|
379
380
|
},
|
|
380
381
|
];
|
|
381
|
-
const injected =
|
|
382
|
+
const injected = injectMemoryRecallAsUserBlock(
|
|
382
383
|
originalMessages,
|
|
383
384
|
memoryRecallText,
|
|
384
385
|
);
|
|
385
386
|
|
|
386
|
-
|
|
387
|
+
// Memory context prepended to the last user message as a content block
|
|
388
|
+
expect(injected).toHaveLength(1);
|
|
387
389
|
expect(injected[0].role).toBe("user");
|
|
388
|
-
expect(injected[0].content
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
expect(
|
|
392
|
-
|
|
393
|
-
|
|
390
|
+
expect(injected[0].content).toHaveLength(2);
|
|
391
|
+
const b0 = injected[0].content[0];
|
|
392
|
+
const b1 = injected[0].content[1];
|
|
393
|
+
expect(b0.type === "text" && b0.text).toBe(memoryRecallText);
|
|
394
|
+
expect(b1.type === "text" && b1.text).toBe("Actual user request");
|
|
395
|
+
|
|
396
|
+
// Stripped by prefix-based stripping (same mechanism as workspace/temporal)
|
|
397
|
+
const cleaned = stripUserTextBlocksByPrefix(injected, ["<memory_context __injected>"]);
|
|
394
398
|
expect(cleaned).toHaveLength(1);
|
|
395
|
-
expect(cleaned[0].content
|
|
399
|
+
expect(cleaned[0].content).toHaveLength(1);
|
|
400
|
+
const cb0 = cleaned[0].content[0];
|
|
401
|
+
expect(cb0.type === "text" && cb0.text).toBe("Actual user request");
|
|
396
402
|
});
|
|
397
403
|
|
|
398
404
|
test("empty retrieval returns no injection", async () => {
|
|
@@ -112,6 +112,7 @@ function insertConversation(
|
|
|
112
112
|
db: ReturnType<typeof getDb>,
|
|
113
113
|
id: string,
|
|
114
114
|
createdAt: number,
|
|
115
|
+
contextCompactedMessageCount = 0,
|
|
115
116
|
) {
|
|
116
117
|
db.insert(conversations)
|
|
117
118
|
.values({
|
|
@@ -123,7 +124,7 @@ function insertConversation(
|
|
|
123
124
|
totalOutputTokens: 0,
|
|
124
125
|
totalEstimatedCost: 0,
|
|
125
126
|
contextSummary: null,
|
|
126
|
-
contextCompactedMessageCount
|
|
127
|
+
contextCompactedMessageCount,
|
|
127
128
|
contextCompactedAt: null,
|
|
128
129
|
})
|
|
129
130
|
.run();
|
|
@@ -629,7 +630,7 @@ describe("Memory Recall Quality", () => {
|
|
|
629
630
|
test("invalidated items are excluded from recall", async () => {
|
|
630
631
|
const db = getDb();
|
|
631
632
|
const now = 1_700_000_275_000;
|
|
632
|
-
insertConversation(db, "conv-invalid-status", now);
|
|
633
|
+
insertConversation(db, "conv-invalid-status", now, 1);
|
|
633
634
|
insertMessage(
|
|
634
635
|
db,
|
|
635
636
|
"msg-invalid-status",
|
|
@@ -989,7 +990,7 @@ describe("Memory Recall Quality", () => {
|
|
|
989
990
|
test("precision@k guard verifies pipeline completes with seeded segments", async () => {
|
|
990
991
|
const db = getDb();
|
|
991
992
|
const now = 1_700_000_700_000;
|
|
992
|
-
insertConversation(db, "conv-pk", now);
|
|
993
|
+
insertConversation(db, "conv-pk", now, 3);
|
|
993
994
|
|
|
994
995
|
const prefs = [
|
|
995
996
|
{
|
|
@@ -67,8 +67,8 @@ import { and, eq } from "drizzle-orm";
|
|
|
67
67
|
import { DEFAULT_CONFIG } from "../config/defaults.js";
|
|
68
68
|
import { vectorToBlob } from "../memory/job-utils.js";
|
|
69
69
|
|
|
70
|
-
// Disable LLM extraction in tests to avoid real API calls
|
|
71
|
-
// deterministic pattern-based extraction.
|
|
70
|
+
// Disable LLM extraction and summarization in tests to avoid real API calls
|
|
71
|
+
// and ensure deterministic pattern-based extraction / fallback summaries.
|
|
72
72
|
const TEST_CONFIG = {
|
|
73
73
|
...DEFAULT_CONFIG,
|
|
74
74
|
memory: {
|
|
@@ -77,6 +77,10 @@ const TEST_CONFIG = {
|
|
|
77
77
|
...DEFAULT_CONFIG.memory.extraction,
|
|
78
78
|
useLLM: false,
|
|
79
79
|
},
|
|
80
|
+
summarization: {
|
|
81
|
+
...DEFAULT_CONFIG.memory.summarization,
|
|
82
|
+
useLLM: false,
|
|
83
|
+
},
|
|
80
84
|
},
|
|
81
85
|
};
|
|
82
86
|
|
|
@@ -86,6 +90,7 @@ mock.module("../config/loader.js", () => ({
|
|
|
86
90
|
invalidateConfigCache: () => {},
|
|
87
91
|
}));
|
|
88
92
|
import { estimateTextTokens } from "../context/token-estimator.js";
|
|
93
|
+
import { stripUserTextBlocksByPrefix } from "../daemon/conversation-runtime-assembly.js";
|
|
89
94
|
import {
|
|
90
95
|
getMemorySystemStatus,
|
|
91
96
|
requestMemoryBackfill,
|
|
@@ -120,8 +125,7 @@ import {
|
|
|
120
125
|
escapeXmlTags,
|
|
121
126
|
formatAbsoluteTime,
|
|
122
127
|
formatRelativeTime,
|
|
123
|
-
|
|
124
|
-
stripMemoryRecallMessages,
|
|
128
|
+
injectMemoryRecallAsUserBlock,
|
|
125
129
|
} from "../memory/retriever.js";
|
|
126
130
|
import {
|
|
127
131
|
conversations,
|
|
@@ -133,6 +137,7 @@ import {
|
|
|
133
137
|
messages,
|
|
134
138
|
} from "../memory/schema.js";
|
|
135
139
|
import { buildCoreIdentityContext } from "../prompts/system-prompt.js";
|
|
140
|
+
import type { Message } from "../providers/types.js";
|
|
136
141
|
|
|
137
142
|
describe("Memory regressions", () => {
|
|
138
143
|
beforeAll(() => {
|
|
@@ -308,133 +313,124 @@ describe("Memory regressions", () => {
|
|
|
308
313
|
expect(recall.enabled).toBe(true);
|
|
309
314
|
});
|
|
310
315
|
|
|
311
|
-
test("memory recall injection
|
|
316
|
+
test("memory recall injection as user block and stripped from runtime history", () => {
|
|
312
317
|
const memoryRecallText =
|
|
313
|
-
"<memory_context>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
314
|
-
const originalMessages = [
|
|
318
|
+
"<memory_context __injected>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
319
|
+
const originalMessages: Message[] = [
|
|
315
320
|
{
|
|
316
|
-
role: "user"
|
|
317
|
-
content: [{ type: "text", text: "Actual user request" }],
|
|
321
|
+
role: "user",
|
|
322
|
+
content: [{ type: "text" as const, text: "Actual user request" }],
|
|
318
323
|
},
|
|
319
324
|
];
|
|
320
|
-
const injected =
|
|
325
|
+
const injected = injectMemoryRecallAsUserBlock(
|
|
321
326
|
originalMessages,
|
|
322
327
|
memoryRecallText,
|
|
323
328
|
);
|
|
324
329
|
|
|
325
|
-
|
|
330
|
+
// Memory context prepended to last user message as content block
|
|
331
|
+
expect(injected).toHaveLength(1);
|
|
326
332
|
expect(injected[0].role).toBe("user");
|
|
327
|
-
expect(injected[0].content
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
expect(
|
|
331
|
-
|
|
332
|
-
|
|
333
|
+
expect(injected[0].content).toHaveLength(2);
|
|
334
|
+
const b0 = injected[0].content[0];
|
|
335
|
+
const b1 = injected[0].content[1];
|
|
336
|
+
expect(b0.type === "text" && b0.text).toBe(memoryRecallText);
|
|
337
|
+
expect(b1.type === "text" && b1.text).toBe("Actual user request");
|
|
338
|
+
|
|
339
|
+
// Stripped by prefix-based stripping
|
|
340
|
+
const cleaned = stripUserTextBlocksByPrefix(injected, [
|
|
341
|
+
"<memory_context __injected>",
|
|
342
|
+
]);
|
|
333
343
|
expect(cleaned).toHaveLength(1);
|
|
334
|
-
expect(cleaned[0].content
|
|
344
|
+
expect(cleaned[0].content).toHaveLength(1);
|
|
345
|
+
const cb0 = cleaned[0].content[0];
|
|
346
|
+
expect(cb0.type === "text" && cb0.text).toBe("Actual user request");
|
|
335
347
|
});
|
|
336
348
|
|
|
337
|
-
test("
|
|
349
|
+
test("prefix-based stripping removes all <memory_context> blocks from merged content", () => {
|
|
338
350
|
const memoryRecallText =
|
|
339
|
-
"
|
|
340
|
-
// Simulate deep-repair merging
|
|
341
|
-
//
|
|
342
|
-
const mergedUserMessage = {
|
|
343
|
-
role: "user"
|
|
351
|
+
"<memory_context __injected>\n\n<relevant_context>\nuser prefers concise answers\n</relevant_context>\n\n</memory_context>";
|
|
352
|
+
// Simulate deep-repair merging where multiple memory context blocks exist.
|
|
353
|
+
// Prefix-based stripping removes all blocks starting with <memory_context __injected>.
|
|
354
|
+
const mergedUserMessage: Message = {
|
|
355
|
+
role: "user",
|
|
344
356
|
content: [
|
|
345
|
-
{ type: "text", text: memoryRecallText },
|
|
346
|
-
{ type: "text", text: "Earlier user request" },
|
|
347
|
-
{ type: "text", text: memoryRecallText },
|
|
348
|
-
{ type: "text", text: "Latest user request" },
|
|
357
|
+
{ type: "text" as const, text: memoryRecallText },
|
|
358
|
+
{ type: "text" as const, text: "Earlier user request" },
|
|
359
|
+
{ type: "text" as const, text: memoryRecallText },
|
|
360
|
+
{ type: "text" as const, text: "Latest user request" },
|
|
349
361
|
],
|
|
350
362
|
};
|
|
351
363
|
|
|
352
|
-
const cleaned =
|
|
364
|
+
const cleaned = stripUserTextBlocksByPrefix(
|
|
353
365
|
[mergedUserMessage],
|
|
354
|
-
|
|
366
|
+
["<memory_context __injected>"],
|
|
355
367
|
);
|
|
356
368
|
expect(cleaned).toHaveLength(1);
|
|
357
|
-
// The last (active) recall block should be stripped, the first (leaked) one preserved
|
|
358
369
|
expect(cleaned[0].content).toEqual([
|
|
359
|
-
{ type: "text", text: memoryRecallText },
|
|
360
370
|
{ type: "text", text: "Earlier user request" },
|
|
361
371
|
{ type: "text", text: "Latest user request" },
|
|
362
372
|
]);
|
|
363
373
|
});
|
|
364
374
|
|
|
365
|
-
test("
|
|
366
|
-
const history = [
|
|
367
|
-
{ role: "user"
|
|
368
|
-
{ role: "assistant"
|
|
375
|
+
test("injectMemoryRecallAsUserBlock prepends memory to last user message", () => {
|
|
376
|
+
const history: Message[] = [
|
|
377
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
378
|
+
{ role: "assistant", content: [{ type: "text" as const, text: "Hi!" }] },
|
|
369
379
|
{
|
|
370
|
-
role: "user"
|
|
371
|
-
content: [{ type: "text", text: "Tell me about X" }],
|
|
380
|
+
role: "user",
|
|
381
|
+
content: [{ type: "text" as const, text: "Tell me about X" }],
|
|
372
382
|
},
|
|
373
383
|
];
|
|
374
|
-
const recallText =
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
384
|
+
const recallText =
|
|
385
|
+
"<memory_context __injected>\n\n<relevant_context>\nSome recalled fact\n</relevant_context>\n\n</memory_context>";
|
|
386
|
+
const result = injectMemoryRecallAsUserBlock(history, recallText);
|
|
387
|
+
// Same number of messages — no synthetic pair
|
|
388
|
+
expect(result).toHaveLength(3);
|
|
378
389
|
expect(result[0]).toBe(history[0]);
|
|
379
390
|
expect(result[1]).toBe(history[1]);
|
|
380
|
-
//
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
expect(
|
|
385
|
-
expect(result[3].content).toEqual([
|
|
386
|
-
{ type: "text", text: "[Memory context loaded.]" },
|
|
387
|
-
]);
|
|
388
|
-
// Original user message preserved unchanged
|
|
389
|
-
expect(result[4]).toBe(history[2]);
|
|
391
|
+
// Last user message has memory prepended
|
|
392
|
+
const r0 = result[2].content[0];
|
|
393
|
+
const r1 = result[2].content[1];
|
|
394
|
+
expect(r0.type === "text" && r0.text).toBe(recallText);
|
|
395
|
+
expect(r1.type === "text" && r1.text).toBe("Tell me about X");
|
|
390
396
|
});
|
|
391
397
|
|
|
392
|
-
test("
|
|
393
|
-
const history = [
|
|
394
|
-
{ role: "user"
|
|
398
|
+
test("injectMemoryRecallAsUserBlock with empty text is a no-op", () => {
|
|
399
|
+
const history: Message[] = [
|
|
400
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
395
401
|
];
|
|
396
|
-
const result =
|
|
402
|
+
const result = injectMemoryRecallAsUserBlock(history, " ");
|
|
397
403
|
expect(result).toBe(history);
|
|
398
404
|
});
|
|
399
405
|
|
|
400
|
-
test("
|
|
401
|
-
const recallText =
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
{ role: "
|
|
405
|
-
// Injected context message pair
|
|
406
|
-
{ role: "user" as const, content: [{ type: "text", text: recallText }] },
|
|
406
|
+
test("stripUserTextBlocksByPrefix removes memory_context block from user message", () => {
|
|
407
|
+
const recallText =
|
|
408
|
+
"<memory_context __injected>\n\n<relevant_context>\nSome recalled fact\n</relevant_context>\n\n</memory_context>";
|
|
409
|
+
const msgs: Message[] = [
|
|
410
|
+
{ role: "user", content: [{ type: "text" as const, text: "Hello" }] },
|
|
407
411
|
{
|
|
408
|
-
role: "assistant"
|
|
409
|
-
content: [{ type: "text", text: "
|
|
410
|
-
},
|
|
411
|
-
// Real user message
|
|
412
|
-
{
|
|
413
|
-
role: "user" as const,
|
|
414
|
-
content: [{ type: "text", text: "Tell me about X" }],
|
|
412
|
+
role: "assistant",
|
|
413
|
+
content: [{ type: "text" as const, text: "Hi!" }],
|
|
415
414
|
},
|
|
416
|
-
];
|
|
417
|
-
const cleaned = stripMemoryRecallMessages(messages, recallText);
|
|
418
|
-
expect(cleaned).toHaveLength(3);
|
|
419
|
-
expect(cleaned[0].content[0].text).toBe("Hello");
|
|
420
|
-
expect(cleaned[1].content[0].text).toBe("Hi!");
|
|
421
|
-
expect(cleaned[2].content[0].text).toBe("Tell me about X");
|
|
422
|
-
});
|
|
423
|
-
|
|
424
|
-
test("stripMemoryRecallMessages falls back to prepend_user_block when no separate pair found", () => {
|
|
425
|
-
const recallText = "<memory>Fact</memory>";
|
|
426
|
-
const messages = [
|
|
427
415
|
{
|
|
428
|
-
role: "user"
|
|
416
|
+
role: "user",
|
|
429
417
|
content: [
|
|
430
|
-
{ type: "text", text: recallText },
|
|
431
|
-
{ type: "text", text: "
|
|
418
|
+
{ type: "text" as const, text: recallText },
|
|
419
|
+
{ type: "text" as const, text: "Tell me about X" },
|
|
432
420
|
],
|
|
433
421
|
},
|
|
434
422
|
];
|
|
435
|
-
const cleaned =
|
|
436
|
-
|
|
437
|
-
|
|
423
|
+
const cleaned = stripUserTextBlocksByPrefix(msgs, [
|
|
424
|
+
"<memory_context __injected>",
|
|
425
|
+
]);
|
|
426
|
+
expect(cleaned).toHaveLength(3);
|
|
427
|
+
const c0 = cleaned[0].content[0];
|
|
428
|
+
const c1 = cleaned[1].content[0];
|
|
429
|
+
const c2 = cleaned[2].content[0];
|
|
430
|
+
expect(c0.type === "text" && c0.text).toBe("Hello");
|
|
431
|
+
expect(c1.type === "text" && c1.text).toBe("Hi!");
|
|
432
|
+
expect(cleaned[2].content).toHaveLength(1);
|
|
433
|
+
expect(c2.type === "text" && c2.text).toBe("Tell me about X");
|
|
438
434
|
});
|
|
439
435
|
|
|
440
436
|
test("aborting memory recall embedding returns a non-degraded aborted recall result", async () => {
|
|
@@ -1819,7 +1815,7 @@ describe("Memory regressions", () => {
|
|
|
1819
1815
|
totalOutputTokens: 0,
|
|
1820
1816
|
totalEstimatedCost: 0,
|
|
1821
1817
|
contextSummary: null,
|
|
1822
|
-
contextCompactedMessageCount:
|
|
1818
|
+
contextCompactedMessageCount: 1,
|
|
1823
1819
|
contextCompactedAt: null,
|
|
1824
1820
|
})
|
|
1825
1821
|
.run();
|
|
@@ -2064,7 +2060,7 @@ describe("Memory regressions", () => {
|
|
|
2064
2060
|
totalOutputTokens: 0,
|
|
2065
2061
|
totalEstimatedCost: 0,
|
|
2066
2062
|
contextSummary: null,
|
|
2067
|
-
contextCompactedMessageCount:
|
|
2063
|
+
contextCompactedMessageCount: 1,
|
|
2068
2064
|
contextCompactedAt: null,
|
|
2069
2065
|
})
|
|
2070
2066
|
.run();
|
|
@@ -2138,7 +2134,7 @@ describe("Memory regressions", () => {
|
|
|
2138
2134
|
totalOutputTokens: 0,
|
|
2139
2135
|
totalEstimatedCost: 0,
|
|
2140
2136
|
contextSummary: null,
|
|
2141
|
-
contextCompactedMessageCount:
|
|
2137
|
+
contextCompactedMessageCount: 1,
|
|
2142
2138
|
contextCompactedAt: null,
|
|
2143
2139
|
})
|
|
2144
2140
|
.run();
|