@strands-agents/sdk 1.4.0 → 1.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/README.md +11 -11
- package/dist/src/__fixtures__/agent-helpers.d.ts.map +1 -1
- package/dist/src/__fixtures__/agent-helpers.js +6 -0
- package/dist/src/__fixtures__/agent-helpers.js.map +1 -1
- package/dist/src/__fixtures__/register-node-defaults.d.ts +2 -0
- package/dist/src/__fixtures__/register-node-defaults.d.ts.map +1 -0
- package/dist/src/__fixtures__/register-node-defaults.js +6 -0
- package/dist/src/__fixtures__/register-node-defaults.js.map +1 -0
- package/dist/src/__fixtures__/test-sandbox.node.d.ts.map +1 -1
- package/dist/src/__fixtures__/test-sandbox.node.js +4 -3
- package/dist/src/__fixtures__/test-sandbox.node.js.map +1 -1
- package/dist/src/__tests__/default-slot.test.d.ts +2 -0
- package/dist/src/__tests__/default-slot.test.d.ts.map +1 -0
- package/dist/src/__tests__/default-slot.test.js +33 -0
- package/dist/src/__tests__/default-slot.test.js.map +1 -0
- package/dist/src/a2a/__tests__/async-lock.test.d.ts +2 -0
- package/dist/src/a2a/__tests__/async-lock.test.d.ts.map +1 -0
- package/dist/src/a2a/__tests__/async-lock.test.js +137 -0
- package/dist/src/a2a/__tests__/async-lock.test.js.map +1 -0
- package/dist/src/a2a/__tests__/executor.test.js +146 -8
- package/dist/src/a2a/__tests__/executor.test.js.map +1 -1
- package/dist/src/a2a/__tests__/server.test.js +20 -0
- package/dist/src/a2a/__tests__/server.test.js.map +1 -1
- package/dist/src/a2a/async-lock.d.ts +22 -0
- package/dist/src/a2a/async-lock.d.ts.map +1 -0
- package/dist/src/a2a/async-lock.js +38 -0
- package/dist/src/a2a/async-lock.js.map +1 -0
- package/dist/src/a2a/executor.d.ts +59 -24
- package/dist/src/a2a/executor.d.ts.map +1 -1
- package/dist/src/a2a/executor.js +209 -32
- package/dist/src/a2a/executor.js.map +1 -1
- package/dist/src/a2a/index.d.ts +1 -1
- package/dist/src/a2a/index.d.ts.map +1 -1
- package/dist/src/a2a/index.js +1 -1
- package/dist/src/a2a/index.js.map +1 -1
- package/dist/src/a2a/server.d.ts +18 -2
- package/dist/src/a2a/server.d.ts.map +1 -1
- package/dist/src/a2a/server.js +13 -2
- package/dist/src/a2a/server.js.map +1 -1
- package/dist/src/agent/__tests__/agent.context-manager.test.d.ts +2 -0
- package/dist/src/agent/__tests__/agent.context-manager.test.d.ts.map +1 -0
- package/dist/src/agent/__tests__/agent.context-manager.test.js +107 -0
- package/dist/src/agent/__tests__/agent.context-manager.test.js.map +1 -0
- package/dist/src/agent/__tests__/agent.tracer.test.node.js +14 -0
- package/dist/src/agent/__tests__/agent.tracer.test.node.js.map +1 -1
- package/dist/src/agent/agent.d.ts +132 -2
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +478 -188
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/conversation-manager/__tests__/pin.test.d.ts +2 -0
- package/dist/src/conversation-manager/__tests__/pin.test.d.ts.map +1 -0
- package/dist/src/conversation-manager/__tests__/pin.test.js +119 -0
- package/dist/src/conversation-manager/__tests__/pin.test.js.map +1 -0
- package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js +49 -0
- package/dist/src/conversation-manager/__tests__/sliding-window-conversation-manager.test.js.map +1 -1
- package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js +58 -0
- package/dist/src/conversation-manager/__tests__/summarizing-conversation-manager.test.js.map +1 -1
- package/dist/src/conversation-manager/pin-message.d.ts +45 -0
- package/dist/src/conversation-manager/pin-message.d.ts.map +1 -0
- package/dist/src/conversation-manager/pin-message.js +106 -0
- package/dist/src/conversation-manager/pin-message.js.map +1 -0
- package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts +7 -0
- package/dist/src/conversation-manager/sliding-window-conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js +27 -4
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
- package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts +7 -0
- package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/summarizing-conversation-manager.js +18 -4
- package/dist/src/conversation-manager/summarizing-conversation-manager.js.map +1 -1
- package/dist/src/default-slot.d.ts +6 -0
- package/dist/src/default-slot.d.ts.map +1 -0
- package/dist/src/default-slot.js +18 -0
- package/dist/src/default-slot.js.map +1 -0
- package/dist/src/errors.d.ts +8 -0
- package/dist/src/errors.d.ts.map +1 -1
- package/dist/src/errors.js +11 -0
- package/dist/src/errors.js.map +1 -1
- package/dist/src/index.d.ts +8 -1
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +7 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/index.node.d.ts +2 -0
- package/dist/src/index.node.d.ts.map +1 -0
- package/dist/src/index.node.js +9 -0
- package/dist/src/index.node.js.map +1 -0
- package/dist/src/interrupt.d.ts +5 -1
- package/dist/src/interrupt.d.ts.map +1 -1
- package/dist/src/interrupt.js +6 -0
- package/dist/src/interrupt.js.map +1 -1
- package/dist/src/memory/__tests__/memory-manager.test.d.ts +2 -0
- package/dist/src/memory/__tests__/memory-manager.test.d.ts.map +1 -0
- package/dist/src/memory/__tests__/memory-manager.test.js +493 -0
- package/dist/src/memory/__tests__/memory-manager.test.js.map +1 -0
- package/dist/src/memory/extraction/__tests__/extraction.test.d.ts +2 -0
- package/dist/src/memory/extraction/__tests__/extraction.test.d.ts.map +1 -0
- package/dist/src/memory/extraction/__tests__/extraction.test.js +637 -0
- package/dist/src/memory/extraction/__tests__/extraction.test.js.map +1 -0
- package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts +2 -0
- package/dist/src/memory/extraction/__tests__/model-extractor.test.d.ts.map +1 -0
- package/dist/src/memory/extraction/__tests__/model-extractor.test.js +68 -0
- package/dist/src/memory/extraction/__tests__/model-extractor.test.js.map +1 -0
- package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts +2 -0
- package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.d.ts.map +1 -0
- package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js +81 -0
- package/dist/src/memory/extraction/__tests__/resolve-extraction-config.test.js.map +1 -0
- package/dist/src/memory/extraction/coordinator.d.ts +128 -0
- package/dist/src/memory/extraction/coordinator.d.ts.map +1 -0
- package/dist/src/memory/extraction/coordinator.js +245 -0
- package/dist/src/memory/extraction/coordinator.js.map +1 -0
- package/dist/src/memory/extraction/model-extractor.d.ts +32 -0
- package/dist/src/memory/extraction/model-extractor.d.ts.map +1 -0
- package/dist/src/memory/extraction/model-extractor.js +118 -0
- package/dist/src/memory/extraction/model-extractor.js.map +1 -0
- package/dist/src/memory/extraction/resolve-extraction-config.d.ts +46 -0
- package/dist/src/memory/extraction/resolve-extraction-config.d.ts.map +1 -0
- package/dist/src/memory/extraction/resolve-extraction-config.js +59 -0
- package/dist/src/memory/extraction/resolve-extraction-config.js.map +1 -0
- package/dist/src/memory/extraction/triggers.d.ts +41 -0
- package/dist/src/memory/extraction/triggers.d.ts.map +1 -0
- package/dist/src/memory/extraction/triggers.js +59 -0
- package/dist/src/memory/extraction/triggers.js.map +1 -0
- package/dist/src/memory/extraction/types.d.ts +133 -0
- package/dist/src/memory/extraction/types.d.ts.map +1 -0
- package/dist/src/memory/extraction/types.js +19 -0
- package/dist/src/memory/extraction/types.js.map +1 -0
- package/dist/src/memory/index.d.ts +9 -0
- package/dist/src/memory/index.d.ts.map +1 -0
- package/dist/src/memory/index.js +5 -0
- package/dist/src/memory/index.js.map +1 -0
- package/dist/src/memory/memory-manager.d.ts +131 -0
- package/dist/src/memory/memory-manager.d.ts.map +1 -0
- package/dist/src/memory/memory-manager.js +404 -0
- package/dist/src/memory/memory-manager.js.map +1 -0
- package/dist/src/memory/types.d.ts +213 -0
- package/dist/src/memory/types.d.ts.map +1 -0
- package/dist/src/memory/types.js +2 -0
- package/dist/src/memory/types.js.map +1 -0
- package/dist/src/middleware/__tests__/agent-middleware.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/agent-middleware.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/agent-middleware.test.js +1207 -0
- package/dist/src/middleware/__tests__/agent-middleware.test.js.map +1 -0
- package/dist/src/middleware/__tests__/custom-stages.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/custom-stages.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/custom-stages.test.js +97 -0
- package/dist/src/middleware/__tests__/custom-stages.test.js.map +1 -0
- package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/middleware-interrupts.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/middleware-interrupts.test.js +267 -0
- package/dist/src/middleware/__tests__/middleware-interrupts.test.js.map +1 -0
- package/dist/src/middleware/__tests__/registry.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/registry.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/registry.test.js +525 -0
- package/dist/src/middleware/__tests__/registry.test.js.map +1 -0
- package/dist/src/middleware/index.d.ts +5 -0
- package/dist/src/middleware/index.d.ts.map +1 -0
- package/dist/src/middleware/index.js +3 -0
- package/dist/src/middleware/index.js.map +1 -0
- package/dist/src/middleware/registry.d.ts +58 -0
- package/dist/src/middleware/registry.d.ts.map +1 -0
- package/dist/src/middleware/registry.js +107 -0
- package/dist/src/middleware/registry.js.map +1 -0
- package/dist/src/middleware/stages.d.ts +138 -0
- package/dist/src/middleware/stages.d.ts.map +1 -0
- package/dist/src/middleware/stages.js +31 -0
- package/dist/src/middleware/stages.js.map +1 -0
- package/dist/src/middleware/types.d.ts +88 -0
- package/dist/src/middleware/types.d.ts.map +1 -0
- package/dist/src/middleware/types.js +2 -0
- package/dist/src/middleware/types.js.map +1 -0
- package/dist/src/models/__tests__/anthropic.test.js +16 -1
- package/dist/src/models/__tests__/anthropic.test.js.map +1 -1
- package/dist/src/models/__tests__/bedrock.test.js +39 -0
- package/dist/src/models/__tests__/bedrock.test.js.map +1 -1
- package/dist/src/models/__tests__/model.test.js +46 -3
- package/dist/src/models/__tests__/model.test.js.map +1 -1
- package/dist/src/models/anthropic.js +2 -2
- package/dist/src/models/anthropic.js.map +1 -1
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +12 -5
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/defaults.d.ts.map +1 -1
- package/dist/src/models/defaults.js +2 -0
- package/dist/src/models/defaults.js.map +1 -1
- package/dist/src/models/model.d.ts.map +1 -1
- package/dist/src/models/model.js +7 -3
- package/dist/src/models/model.js.map +1 -1
- package/dist/src/models/openai/__tests__/responses.test.js +8 -14
- package/dist/src/models/openai/__tests__/responses.test.js.map +1 -1
- package/dist/src/sandbox/__tests__/default.test.browser.d.ts +2 -0
- package/dist/src/sandbox/__tests__/default.test.browser.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/default.test.browser.js +11 -0
- package/dist/src/sandbox/__tests__/default.test.browser.js.map +1 -0
- package/dist/src/sandbox/__tests__/default.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/default.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/default.test.node.js +23 -0
- package/dist/src/sandbox/__tests__/default.test.node.js.map +1 -0
- package/dist/src/sandbox/__tests__/docker.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/docker.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/docker.test.node.js +89 -0
- package/dist/src/sandbox/__tests__/docker.test.node.js.map +1 -0
- package/dist/src/sandbox/__tests__/errors.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/errors.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/errors.test.node.js +33 -0
- package/dist/src/sandbox/__tests__/errors.test.node.js.map +1 -0
- package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js +124 -0
- package/dist/src/sandbox/__tests__/not-a-sandbox-local-environment.test.node.js.map +1 -0
- package/dist/src/sandbox/__tests__/posix-shell.test.node.js +50 -4
- package/dist/src/sandbox/__tests__/posix-shell.test.node.js.map +1 -1
- package/dist/src/sandbox/__tests__/ssh.test.node.d.ts +2 -0
- package/dist/src/sandbox/__tests__/ssh.test.node.d.ts.map +1 -0
- package/dist/src/sandbox/__tests__/ssh.test.node.js +262 -0
- package/dist/src/sandbox/__tests__/ssh.test.node.js.map +1 -0
- package/dist/src/sandbox/base.d.ts +22 -4
- package/dist/src/sandbox/base.d.ts.map +1 -1
- package/dist/src/sandbox/base.js +15 -2
- package/dist/src/sandbox/base.js.map +1 -1
- package/dist/src/sandbox/constants.d.ts +18 -0
- package/dist/src/sandbox/constants.d.ts.map +1 -1
- package/dist/src/sandbox/constants.js +20 -0
- package/dist/src/sandbox/constants.js.map +1 -1
- package/dist/src/sandbox/default.d.ts +3 -0
- package/dist/src/sandbox/default.d.ts.map +1 -0
- package/dist/src/sandbox/default.js +3 -0
- package/dist/src/sandbox/default.js.map +1 -0
- package/dist/src/sandbox/docker.d.ts +38 -0
- package/dist/src/sandbox/docker.d.ts.map +1 -0
- package/dist/src/sandbox/docker.js +59 -0
- package/dist/src/sandbox/docker.js.map +1 -0
- package/dist/src/sandbox/errors.d.ts +26 -0
- package/dist/src/sandbox/errors.d.ts.map +1 -0
- package/dist/src/sandbox/errors.js +35 -0
- package/dist/src/sandbox/errors.js.map +1 -0
- package/dist/src/sandbox/index.d.ts +5 -0
- package/dist/src/sandbox/index.d.ts.map +1 -0
- package/dist/src/sandbox/index.js +4 -0
- package/dist/src/sandbox/index.js.map +1 -0
- package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts +16 -0
- package/dist/src/sandbox/not-a-sandbox-local-environment.d.ts.map +1 -0
- package/dist/src/sandbox/not-a-sandbox-local-environment.js +83 -0
- package/dist/src/sandbox/not-a-sandbox-local-environment.js.map +1 -0
- package/dist/src/sandbox/posix-shell.d.ts +21 -0
- package/dist/src/sandbox/posix-shell.d.ts.map +1 -1
- package/dist/src/sandbox/posix-shell.js +41 -3
- package/dist/src/sandbox/posix-shell.js.map +1 -1
- package/dist/src/sandbox/ssh.d.ts +56 -0
- package/dist/src/sandbox/ssh.d.ts.map +1 -0
- package/dist/src/sandbox/ssh.js +119 -0
- package/dist/src/sandbox/ssh.js.map +1 -0
- package/dist/src/sandbox/stream-process.d.ts.map +1 -1
- package/dist/src/sandbox/stream-process.js +3 -2
- package/dist/src/sandbox/stream-process.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/agent.d.ts +21 -0
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/messages.d.ts +1 -1
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts +2 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.d.ts.map +1 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js +611 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/__tests__/bedrock-knowledge-base-store.test.js.map +1 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts +2 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.d.ts.map +1 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js +2 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/index.js.map +1 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts +230 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts.map +1 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js +370 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js.map +1 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts +2 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.d.ts.map +1 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js +68 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/file-storage-sandbox.test.node.js.map +1 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts +2 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.d.ts.map +1 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js +93 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.node.js.map +1 -0
- package/dist/src/vended-plugins/context-offloader/index.d.ts +1 -1
- package/dist/src/vended-plugins/context-offloader/index.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.d.ts +4 -1
- package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.js +29 -7
- package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -1
- package/dist/src/vended-plugins/context-offloader/search.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/search.js +3 -5
- package/dist/src/vended-plugins/context-offloader/search.js.map +1 -1
- package/dist/src/vended-plugins/context-offloader/storage.d.ts +29 -5
- package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/storage.js +75 -11
- package/dist/src/vended-plugins/context-offloader/storage.js.map +1 -1
- package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts +2 -0
- package/dist/src/vended-plugins/goal/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/src/vended-plugins/goal/__tests__/plugin.test.js +736 -0
- package/dist/src/vended-plugins/goal/__tests__/plugin.test.js.map +1 -0
- package/dist/src/vended-plugins/goal/index.d.ts +21 -0
- package/dist/src/vended-plugins/goal/index.d.ts.map +1 -0
- package/dist/src/vended-plugins/goal/index.js +20 -0
- package/dist/src/vended-plugins/goal/index.js.map +1 -0
- package/dist/src/vended-plugins/goal/judge.d.ts +41 -0
- package/dist/src/vended-plugins/goal/judge.d.ts.map +1 -0
- package/dist/src/vended-plugins/goal/judge.js +92 -0
- package/dist/src/vended-plugins/goal/judge.js.map +1 -0
- package/dist/src/vended-plugins/goal/plugin.d.ts +214 -0
- package/dist/src/vended-plugins/goal/plugin.d.ts.map +1 -0
- package/dist/src/vended-plugins/goal/plugin.js +287 -0
- package/dist/src/vended-plugins/goal/plugin.js.map +1 -0
- package/dist/src/vended-plugins/index.d.ts +2 -1
- package/dist/src/vended-plugins/index.d.ts.map +1 -1
- package/dist/src/vended-plugins/index.js +2 -1
- package/dist/src/vended-plugins/index.js.map +1 -1
- package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js +17 -7
- package/dist/src/vended-plugins/skills/__tests__/agent-skills.test.node.js.map +1 -1
- package/dist/src/vended-plugins/skills/agent-skills.d.ts +21 -7
- package/dist/src/vended-plugins/skills/agent-skills.d.ts.map +1 -1
- package/dist/src/vended-plugins/skills/agent-skills.js +144 -77
- package/dist/src/vended-plugins/skills/agent-skills.js.map +1 -1
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js +44 -4
- package/dist/src/vended-tools/bash/__tests__/bash.test.node.js.map +1 -1
- package/dist/src/vended-tools/bash/bash.d.ts +3 -24
- package/dist/src/vended-tools/bash/bash.d.ts.map +1 -1
- package/dist/src/vended-tools/bash/bash.js +9 -9
- package/dist/src/vended-tools/bash/bash.js.map +1 -1
- package/dist/src/vended-tools/bash/index.d.ts +3 -1
- package/dist/src/vended-tools/bash/index.d.ts.map +1 -1
- package/dist/src/vended-tools/bash/index.js +2 -1
- package/dist/src/vended-tools/bash/index.js.map +1 -1
- package/dist/src/vended-tools/bash/make-bash.d.ts +22 -0
- package/dist/src/vended-tools/bash/make-bash.d.ts.map +1 -0
- package/dist/src/vended-tools/bash/make-bash.js +40 -0
- package/dist/src/vended-tools/bash/make-bash.js.map +1 -0
- package/dist/src/vended-tools/bash/types.d.ts +1 -0
- package/dist/src/vended-tools/bash/types.d.ts.map +1 -1
- package/dist/src/vended-tools/bash/types.js +2 -0
- package/dist/src/vended-tools/bash/types.js.map +1 -1
- package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js +83 -1
- package/dist/src/vended-tools/file-editor/__tests__/file-editor.test.node.js.map +1 -1
- package/dist/src/vended-tools/file-editor/file-editor.d.ts +19 -10
- package/dist/src/vended-tools/file-editor/file-editor.d.ts.map +1 -1
- package/dist/src/vended-tools/file-editor/file-editor.js +188 -218
- package/dist/src/vended-tools/file-editor/file-editor.js.map +1 -1
- package/dist/src/vended-tools/file-editor/index.d.ts +2 -1
- package/dist/src/vended-tools/file-editor/index.d.ts.map +1 -1
- package/dist/src/vended-tools/file-editor/index.js +1 -1
- package/dist/src/vended-tools/file-editor/index.js.map +1 -1
- package/package.json +41 -6
- package/dist/src/utils/shell-quote.d.ts +0 -12
- package/dist/src/utils/shell-quote.d.ts.map +0 -1
- package/dist/src/utils/shell-quote.js +0 -14
- package/dist/src/utils/shell-quote.js.map +0 -1
|
@@ -0,0 +1,611 @@
|
|
|
1
|
+
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
|
+
import { BedrockAgentRuntimeClient } from '@aws-sdk/client-bedrock-agent-runtime';
|
|
3
|
+
import { BedrockAgentClient } from '@aws-sdk/client-bedrock-agent';
|
|
4
|
+
import { BedrockKnowledgeBaseStore } from '../store.js';
|
|
5
|
+
import { MemoryManager } from '../../../memory/index.js';
|
|
6
|
+
import { InvocationTrigger } from '../../../memory/extraction/triggers.js';
|
|
7
|
+
import { Message, TextBlock } from '../../../types/messages.js';
|
|
8
|
+
import { AfterInvocationEvent, MessageAddedEvent } from '../../../hooks/events.js';
|
|
9
|
+
import { createMockAgent } from '../../../__fixtures__/agent-helpers.js';
|
|
10
|
+
import { logger } from '../../../logging/logger.js';
|
|
11
|
+
// Mock the AWS SDK clients. Command classes are stubbed to echo their input as `{ input }`, so a
|
|
12
|
+
// test can assert on `send`'s argument — mirroring src/session/__tests__/s3-storage.test.ts. Client
|
|
13
|
+
// constructors return a stub with a `send` spy; tests that exercise behavior inject their own client
|
|
14
|
+
// instead (the store accepts `config.runtimeClient` / `config.agentClient` / `config.s3.client`).
|
|
15
|
+
vi.mock('@aws-sdk/client-bedrock-agent-runtime', () => ({
|
|
16
|
+
BedrockAgentRuntimeClient: vi.fn().mockImplementation(function () {
|
|
17
|
+
return { send: vi.fn() };
|
|
18
|
+
}),
|
|
19
|
+
RetrieveCommand: vi.fn().mockImplementation(function (input) {
|
|
20
|
+
return { input };
|
|
21
|
+
}),
|
|
22
|
+
}));
|
|
23
|
+
vi.mock('@aws-sdk/client-bedrock-agent', () => ({
|
|
24
|
+
BedrockAgentClient: vi.fn().mockImplementation(function () {
|
|
25
|
+
return { send: vi.fn() };
|
|
26
|
+
}),
|
|
27
|
+
IngestKnowledgeBaseDocumentsCommand: vi.fn().mockImplementation(function (input) {
|
|
28
|
+
return { input };
|
|
29
|
+
}),
|
|
30
|
+
}));
|
|
31
|
+
vi.mock('@aws-sdk/client-s3', () => ({
|
|
32
|
+
S3Client: vi.fn().mockImplementation(function () {
|
|
33
|
+
return { send: vi.fn() };
|
|
34
|
+
}),
|
|
35
|
+
PutObjectCommand: vi.fn().mockImplementation(function (input) {
|
|
36
|
+
return { input };
|
|
37
|
+
}),
|
|
38
|
+
}));
|
|
39
|
+
// uuid v7 backs both the S3 object key and the CUSTOM document id; pin it for deterministic assertions.
|
|
40
|
+
vi.mock('uuid', () => ({
|
|
41
|
+
v7: vi.fn().mockReturnValue('test-uuid-v7'),
|
|
42
|
+
}));
|
|
43
|
+
/** A stub AWS client whose `send` is a spy the test can program and inspect. */
|
|
44
|
+
function mockClient() {
|
|
45
|
+
return { send: vi.fn() };
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Builds a store from a base connection config plus per-store fields. `config` overrides merge onto
|
|
49
|
+
* the shared connection (`knowledgeBaseId: 'kb-1'` + injected runtime/agent clients); `overrides`
|
|
50
|
+
* carry the per-store fields that sit outside `config` (`name`, `scope`, `writable`, ...). The
|
|
51
|
+
* returned `runtime` / `agent` spies are the injected clients, ready to program and inspect.
|
|
52
|
+
*/
|
|
53
|
+
function makeStore(overrides = {}, configOverrides = {}) {
|
|
54
|
+
const runtime = mockClient();
|
|
55
|
+
runtime.send.mockResolvedValue({ retrievalResults: [] });
|
|
56
|
+
const agent = mockClient();
|
|
57
|
+
agent.send.mockResolvedValue({});
|
|
58
|
+
const store = new BedrockKnowledgeBaseStore({
|
|
59
|
+
config: { knowledgeBaseId: 'kb-1', runtimeClient: runtime, agentClient: agent, ...configOverrides },
|
|
60
|
+
name: 'kb',
|
|
61
|
+
...overrides,
|
|
62
|
+
});
|
|
63
|
+
return { store, runtime, agent };
|
|
64
|
+
}
|
|
65
|
+
/** A writable CUSTOM store built via {@link makeStore}, with the data source wired into `config`. */
|
|
66
|
+
function makeCustomStore(overrides = {}, configOverrides = {}) {
|
|
67
|
+
const { store, agent } = makeStore({ writable: true, ...overrides }, { dataSourceType: 'CUSTOM', dataSourceId: 'ds-1', ...configOverrides });
|
|
68
|
+
return { store, agent };
|
|
69
|
+
}
|
|
70
|
+
/** A writable S3 store built via {@link makeStore}, with the data source + bucket wired into `config`. */
|
|
71
|
+
function makeS3Store(overrides = {}, configOverrides = {}) {
|
|
72
|
+
const s3 = mockClient();
|
|
73
|
+
s3.send.mockResolvedValue({});
|
|
74
|
+
const { store, agent } = makeStore({ writable: true, ...overrides }, {
|
|
75
|
+
dataSourceType: 'S3',
|
|
76
|
+
dataSourceId: 'ds-1',
|
|
77
|
+
s3: { bucket: 'my-bucket', client: s3, prefix: 'memories' },
|
|
78
|
+
...configOverrides,
|
|
79
|
+
});
|
|
80
|
+
return { store, agent, s3 };
|
|
81
|
+
}
|
|
82
|
+
/** Reads the filter the most recent RetrieveCommand was sent with. */
|
|
83
|
+
function lastSearchFilter(runtime) {
|
|
84
|
+
const calls = runtime.send.mock.calls;
|
|
85
|
+
return calls[calls.length - 1]?.[0].input.retrievalConfiguration.vectorSearchConfiguration.filter;
|
|
86
|
+
}
|
|
87
|
+
/** Reads the inline attributes the most recent CUSTOM ingestion document carried. */
|
|
88
|
+
function lastInlineAttributes(agent) {
|
|
89
|
+
const calls = agent.send.mock.calls;
|
|
90
|
+
return calls[calls.length - 1]?.[0].input.documents[0].metadata?.inlineAttributes ?? [];
|
|
91
|
+
}
|
|
92
|
+
describe('BedrockKnowledgeBaseStore', () => {
|
|
93
|
+
beforeEach(() => {
|
|
94
|
+
vi.clearAllMocks();
|
|
95
|
+
});
|
|
96
|
+
describe('constructor', () => {
|
|
97
|
+
it('exposes name and defaults writable to false', () => {
|
|
98
|
+
const { store } = makeStore();
|
|
99
|
+
expect(store.name).toBe('kb');
|
|
100
|
+
expect(store.writable).toBe(false);
|
|
101
|
+
expect(store.description).toBeUndefined();
|
|
102
|
+
expect(store.maxSearchResults).toBeUndefined();
|
|
103
|
+
});
|
|
104
|
+
it('keeps name and scope as independent fields', () => {
|
|
105
|
+
const { store } = makeStore({ name: 'explicit', scope: 'user-abc' });
|
|
106
|
+
expect(store.name).toBe('explicit');
|
|
107
|
+
expect(store.scope).toBe('user-abc');
|
|
108
|
+
});
|
|
109
|
+
it('requires name at the type level', () => {
|
|
110
|
+
// @ts-expect-error name is required
|
|
111
|
+
new BedrockKnowledgeBaseStore({ config: { knowledgeBaseId: 'kb-1' }, scope: 'user-abc' });
|
|
112
|
+
});
|
|
113
|
+
it('carries through description and maxSearchResults', () => {
|
|
114
|
+
const { store } = makeStore({ description: 'product docs', maxSearchResults: 7 });
|
|
115
|
+
expect(store.description).toBe('product docs');
|
|
116
|
+
expect(store.maxSearchResults).toBe(7);
|
|
117
|
+
});
|
|
118
|
+
it('throws when writable is true but dataSourceType is omitted', () => {
|
|
119
|
+
expect(() => makeStore({ writable: true })).toThrow("add requires dataSourceType 'CUSTOM' or 'S3'");
|
|
120
|
+
});
|
|
121
|
+
it("throws when writable is true but dataSourceType is 'OTHER'", () => {
|
|
122
|
+
expect(() => makeStore({ writable: true }, { dataSourceType: 'OTHER' })).toThrow("add requires dataSourceType 'CUSTOM' or 'S3'");
|
|
123
|
+
});
|
|
124
|
+
it('throws when maxSearchResults is less than 1', () => {
|
|
125
|
+
expect(() => makeStore({ maxSearchResults: 0 })).toThrow('maxSearchResults must be at least 1');
|
|
126
|
+
expect(() => makeStore({ maxSearchResults: -5 })).toThrow('maxSearchResults must be at least 1');
|
|
127
|
+
});
|
|
128
|
+
it("allows writable with a 'CUSTOM' data source", () => {
|
|
129
|
+
const { store } = makeCustomStore();
|
|
130
|
+
expect(store.writable).toBe(true);
|
|
131
|
+
});
|
|
132
|
+
it("allows writable with an 'S3' data source", () => {
|
|
133
|
+
const { store } = makeS3Store();
|
|
134
|
+
expect(store.writable).toBe(true);
|
|
135
|
+
});
|
|
136
|
+
it('constructs a default runtime client when none is injected', () => {
|
|
137
|
+
new BedrockKnowledgeBaseStore({ config: { knowledgeBaseId: 'kb-1' }, name: 'kb' });
|
|
138
|
+
expect(vi.mocked(BedrockAgentRuntimeClient)).toHaveBeenCalledWith({});
|
|
139
|
+
});
|
|
140
|
+
it('uses the injected runtime client without constructing one', () => {
|
|
141
|
+
makeStore();
|
|
142
|
+
expect(vi.mocked(BedrockAgentRuntimeClient)).not.toHaveBeenCalled();
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
describe('extraction config', () => {
|
|
146
|
+
const extractor = { extract: vi.fn() };
|
|
147
|
+
it('defaults extraction to undefined', () => {
|
|
148
|
+
const { store } = makeStore();
|
|
149
|
+
expect(store.extraction).toBeUndefined();
|
|
150
|
+
});
|
|
151
|
+
it('exposes a configured extraction config verbatim', () => {
|
|
152
|
+
const extraction = { trigger: new InvocationTrigger(), extractor };
|
|
153
|
+
const { store } = makeCustomStore({ extraction });
|
|
154
|
+
expect(store.extraction).toBe(extraction);
|
|
155
|
+
});
|
|
156
|
+
it('exposes the boolean shorthand verbatim', () => {
|
|
157
|
+
// The store passes `extraction` straight through; the MemoryManager resolves the shorthand and
|
|
158
|
+
// (since a KB is add-only, with no addMessages) defaults it to a ModelExtractor.
|
|
159
|
+
const { store } = makeCustomStore({ extraction: true });
|
|
160
|
+
expect(store.extraction).toBe(true);
|
|
161
|
+
});
|
|
162
|
+
});
|
|
163
|
+
describe('search', () => {
|
|
164
|
+
it('issues a RetrieveCommand with the query and a default result limit of 10', async () => {
|
|
165
|
+
const { store, runtime } = makeStore();
|
|
166
|
+
await store.search('how do refunds work');
|
|
167
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
168
|
+
input: {
|
|
169
|
+
knowledgeBaseId: 'kb-1',
|
|
170
|
+
retrievalQuery: { text: 'how do refunds work' },
|
|
171
|
+
retrievalConfiguration: { vectorSearchConfiguration: { numberOfResults: 10 } },
|
|
172
|
+
},
|
|
173
|
+
}));
|
|
174
|
+
});
|
|
175
|
+
it("uses the store's maxSearchResults when the caller omits one", async () => {
|
|
176
|
+
const { store, runtime } = makeStore({ maxSearchResults: 5 });
|
|
177
|
+
await store.search('q');
|
|
178
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
179
|
+
input: expect.objectContaining({
|
|
180
|
+
retrievalConfiguration: { vectorSearchConfiguration: { numberOfResults: 5 } },
|
|
181
|
+
}),
|
|
182
|
+
}));
|
|
183
|
+
});
|
|
184
|
+
it('lets a per-call maxSearchResults override the store default', async () => {
|
|
185
|
+
const { store, runtime } = makeStore({ maxSearchResults: 5 });
|
|
186
|
+
await store.search('q', { maxSearchResults: 2 });
|
|
187
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
188
|
+
input: expect.objectContaining({
|
|
189
|
+
retrievalConfiguration: { vectorSearchConfiguration: { numberOfResults: 2 } },
|
|
190
|
+
}),
|
|
191
|
+
}));
|
|
192
|
+
});
|
|
193
|
+
it('derives a scope filter (default key "namespace") and applies it to retrieval', async () => {
|
|
194
|
+
const { store, runtime } = makeStore({ scope: 'user-123' });
|
|
195
|
+
await store.search('q');
|
|
196
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
197
|
+
input: expect.objectContaining({
|
|
198
|
+
retrievalConfiguration: {
|
|
199
|
+
vectorSearchConfiguration: {
|
|
200
|
+
numberOfResults: 10,
|
|
201
|
+
filter: { equals: { key: 'namespace', value: 'user-123' } },
|
|
202
|
+
},
|
|
203
|
+
},
|
|
204
|
+
}),
|
|
205
|
+
}));
|
|
206
|
+
});
|
|
207
|
+
it('honors a custom scopeMetadataKey when building the scope filter', async () => {
|
|
208
|
+
const { store, runtime } = makeStore({ scope: 'acme' }, { scopeMetadataKey: 'tenant' });
|
|
209
|
+
await store.search('q');
|
|
210
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
211
|
+
input: expect.objectContaining({
|
|
212
|
+
retrievalConfiguration: expect.objectContaining({
|
|
213
|
+
vectorSearchConfiguration: expect.objectContaining({
|
|
214
|
+
filter: { equals: { key: 'tenant', value: 'acme' } },
|
|
215
|
+
}),
|
|
216
|
+
}),
|
|
217
|
+
}),
|
|
218
|
+
}));
|
|
219
|
+
});
|
|
220
|
+
it('prefers an explicit filter over a scope-derived one', async () => {
|
|
221
|
+
const filter = { equals: { key: 'custom', value: 'v' } };
|
|
222
|
+
const { store, runtime } = makeStore({ scope: 'ignored', filter });
|
|
223
|
+
await store.search('q');
|
|
224
|
+
expect(runtime.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
225
|
+
input: expect.objectContaining({
|
|
226
|
+
retrievalConfiguration: expect.objectContaining({
|
|
227
|
+
vectorSearchConfiguration: expect.objectContaining({ filter }),
|
|
228
|
+
}),
|
|
229
|
+
}),
|
|
230
|
+
}));
|
|
231
|
+
});
|
|
232
|
+
it('maps content, metadata, location, and score onto each entry', async () => {
|
|
233
|
+
const { store, runtime } = makeStore();
|
|
234
|
+
runtime.send.mockResolvedValue({
|
|
235
|
+
retrievalResults: [
|
|
236
|
+
{
|
|
237
|
+
content: { text: 'refunds take 5 days' },
|
|
238
|
+
metadata: { source: 'faq' },
|
|
239
|
+
location: { type: 'S3', s3Location: { uri: 's3://b/k' } },
|
|
240
|
+
score: 0.92,
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
});
|
|
244
|
+
const results = await store.search('q');
|
|
245
|
+
expect(results).toStrictEqual([
|
|
246
|
+
{
|
|
247
|
+
content: 'refunds take 5 days',
|
|
248
|
+
metadata: {
|
|
249
|
+
source: 'faq',
|
|
250
|
+
_sourceLocation: { type: 'S3', s3Location: { uri: 's3://b/k' } },
|
|
251
|
+
_relevanceScore: 0.92,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
]);
|
|
255
|
+
});
|
|
256
|
+
it('defaults missing content to an empty string and omits absent metadata', async () => {
|
|
257
|
+
const { store, runtime } = makeStore();
|
|
258
|
+
runtime.send.mockResolvedValue({ retrievalResults: [{}] });
|
|
259
|
+
const results = await store.search('q');
|
|
260
|
+
expect(results).toStrictEqual([{ content: '', metadata: {} }]);
|
|
261
|
+
});
|
|
262
|
+
it('returns an empty array when the knowledge base yields no results', async () => {
|
|
263
|
+
const { store } = makeStore();
|
|
264
|
+
await expect(store.search('q')).resolves.toStrictEqual([]);
|
|
265
|
+
});
|
|
266
|
+
it('returns an empty array when the response omits retrievalResults entirely', async () => {
|
|
267
|
+
const { store, runtime } = makeStore();
|
|
268
|
+
runtime.send.mockResolvedValue({});
|
|
269
|
+
await expect(store.search('q')).resolves.toStrictEqual([]);
|
|
270
|
+
});
|
|
271
|
+
it('logs and rethrows when the retrieve call fails', async () => {
|
|
272
|
+
const errorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
|
|
273
|
+
const { store, runtime } = makeStore();
|
|
274
|
+
runtime.send.mockRejectedValue(new Error('retrieve boom'));
|
|
275
|
+
await expect(store.search('q')).rejects.toThrow('retrieve boom');
|
|
276
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
277
|
+
errorSpy.mockRestore();
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
describe('add — CUSTOM data source', () => {
|
|
281
|
+
it('throws when dataSourceId is missing', () => {
|
|
282
|
+
expect(() => makeStore({ writable: true }, { dataSourceType: 'CUSTOM' })).toThrow('dataSourceId is required');
|
|
283
|
+
});
|
|
284
|
+
it('throws when content is empty or whitespace-only', async () => {
|
|
285
|
+
const { store } = makeCustomStore();
|
|
286
|
+
await expect(store.add('')).rejects.toThrow('content must not be empty');
|
|
287
|
+
await expect(store.add(' ')).rejects.toThrow('content must not be empty');
|
|
288
|
+
});
|
|
289
|
+
it('returns the generated custom document id', async () => {
|
|
290
|
+
const { store } = makeCustomStore();
|
|
291
|
+
await expect(store.add('fact')).resolves.toStrictEqual({ documentId: 'test-uuid-v7' });
|
|
292
|
+
});
|
|
293
|
+
it('uses the same id for the document identifier and the returned documentId', async () => {
|
|
294
|
+
const { store, agent } = makeCustomStore();
|
|
295
|
+
const result = await store.add('fact');
|
|
296
|
+
const document = agent.send.mock.calls[0]?.[0].input.documents[0];
|
|
297
|
+
expect(document.content.custom.customDocumentIdentifier.id).toBe(result.documentId);
|
|
298
|
+
});
|
|
299
|
+
it('ingests an inline CUSTOM document with no metadata field when no scope or metadata', async () => {
|
|
300
|
+
const { store, agent } = makeCustomStore();
|
|
301
|
+
await store.add('remember this');
|
|
302
|
+
expect(agent.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
303
|
+
input: {
|
|
304
|
+
knowledgeBaseId: 'kb-1',
|
|
305
|
+
dataSourceId: 'ds-1',
|
|
306
|
+
documents: [
|
|
307
|
+
{
|
|
308
|
+
content: {
|
|
309
|
+
dataSourceType: 'CUSTOM',
|
|
310
|
+
custom: {
|
|
311
|
+
customDocumentIdentifier: { id: 'test-uuid-v7' },
|
|
312
|
+
sourceType: 'IN_LINE',
|
|
313
|
+
inlineContent: { type: 'TEXT', textContent: { data: 'remember this' } },
|
|
314
|
+
},
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
],
|
|
318
|
+
},
|
|
319
|
+
}));
|
|
320
|
+
});
|
|
321
|
+
it('attaches the scope as a leading inline attribute', async () => {
|
|
322
|
+
const { store, agent } = makeCustomStore({ scope: 'user-123' });
|
|
323
|
+
await store.add('fact');
|
|
324
|
+
const document = agent.send.mock.calls[0]?.[0].input.documents[0];
|
|
325
|
+
expect(document.metadata.inlineAttributes).toStrictEqual([
|
|
326
|
+
{ key: 'namespace', value: { type: 'STRING', stringValue: 'user-123' } },
|
|
327
|
+
]);
|
|
328
|
+
});
|
|
329
|
+
it('drops metadata keys that collide with scopeMetadataKey and preserves scope', async () => {
|
|
330
|
+
const { store, agent } = makeCustomStore({ scope: 'tenant-A' });
|
|
331
|
+
const warnSpy = vi.spyOn(logger, 'warn');
|
|
332
|
+
await store.add('fact', { namespace: 'tenant-EVIL', other: 'ok' });
|
|
333
|
+
const document = agent.send.mock.calls[0]?.[0].input.documents[0];
|
|
334
|
+
const attrs = document.metadata.inlineAttributes;
|
|
335
|
+
expect(attrs.filter((a) => a.key === 'namespace')).toHaveLength(1);
|
|
336
|
+
expect(attrs.find((a) => a.key === 'namespace').value.stringValue).toBe('tenant-A');
|
|
337
|
+
expect(attrs.find((a) => a.key === 'other')).toBeDefined();
|
|
338
|
+
expect(warnSpy).toHaveBeenCalledWith(expect.stringContaining('collides with scopeMetadataKey'));
|
|
339
|
+
warnSpy.mockRestore();
|
|
340
|
+
});
|
|
341
|
+
it('maps supported metadata value types and skips unsupported ones', async () => {
|
|
342
|
+
const { store, agent } = makeCustomStore();
|
|
343
|
+
await store.add('fact', {
|
|
344
|
+
str: 'a',
|
|
345
|
+
num: 1,
|
|
346
|
+
bool: false,
|
|
347
|
+
arr: ['x', 'y'],
|
|
348
|
+
obj: { nested: true },
|
|
349
|
+
nul: null,
|
|
350
|
+
mixedArr: [1, 'a'],
|
|
351
|
+
});
|
|
352
|
+
const document = agent.send.mock.calls[0]?.[0].input.documents[0];
|
|
353
|
+
expect(document.metadata.inlineAttributes).toStrictEqual([
|
|
354
|
+
{ key: 'str', value: { type: 'STRING', stringValue: 'a' } },
|
|
355
|
+
{ key: 'num', value: { type: 'NUMBER', numberValue: 1 } },
|
|
356
|
+
{ key: 'bool', value: { type: 'BOOLEAN', booleanValue: false } },
|
|
357
|
+
{ key: 'arr', value: { type: 'STRING_LIST', stringListValue: ['x', 'y'] } },
|
|
358
|
+
]);
|
|
359
|
+
});
|
|
360
|
+
it('logs and rethrows when ingestion fails', async () => {
|
|
361
|
+
const errorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
|
|
362
|
+
const { store, agent } = makeCustomStore();
|
|
363
|
+
agent.send.mockRejectedValue(new Error('ingest boom'));
|
|
364
|
+
await expect(store.add('fact')).rejects.toThrow('ingest boom');
|
|
365
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
366
|
+
errorSpy.mockRestore();
|
|
367
|
+
});
|
|
368
|
+
it('lazily constructs a default agent client when none is injected', async () => {
|
|
369
|
+
// No injected agentClient, so construct directly rather than via the helper.
|
|
370
|
+
const store = new BedrockKnowledgeBaseStore({
|
|
371
|
+
config: { knowledgeBaseId: 'kb-1', dataSourceType: 'CUSTOM', dataSourceId: 'ds-1' },
|
|
372
|
+
name: 'kb',
|
|
373
|
+
writable: true,
|
|
374
|
+
});
|
|
375
|
+
await store.add('fact');
|
|
376
|
+
expect(vi.mocked(BedrockAgentClient)).toHaveBeenCalledWith({});
|
|
377
|
+
});
|
|
378
|
+
});
|
|
379
|
+
describe('add — S3 data source', () => {
|
|
380
|
+
it('throws when the s3 config is missing', () => {
|
|
381
|
+
expect(() => makeStore({ writable: true }, { dataSourceType: 'S3', dataSourceId: 'ds-1' })).toThrow('s3 config is required');
|
|
382
|
+
});
|
|
383
|
+
it("returns the uploaded content object's s3:// URI as the document id", async () => {
|
|
384
|
+
const { store } = makeS3Store();
|
|
385
|
+
await expect(store.add('content')).resolves.toStrictEqual({
|
|
386
|
+
documentId: 's3://my-bucket/memories/test-uuid-v7.txt',
|
|
387
|
+
});
|
|
388
|
+
});
|
|
389
|
+
it('uploads the content object and ingests an S3 document referencing it (no sidecar)', async () => {
|
|
390
|
+
const { store, agent, s3 } = makeS3Store();
|
|
391
|
+
await store.add('s3 content');
|
|
392
|
+
expect(s3.send).toHaveBeenCalledTimes(1);
|
|
393
|
+
expect(s3.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
394
|
+
input: {
|
|
395
|
+
Bucket: 'my-bucket',
|
|
396
|
+
Key: 'memories/test-uuid-v7.txt',
|
|
397
|
+
Body: 's3 content',
|
|
398
|
+
ContentType: 'text/plain; charset=utf-8',
|
|
399
|
+
},
|
|
400
|
+
}));
|
|
401
|
+
expect(agent.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
402
|
+
input: {
|
|
403
|
+
knowledgeBaseId: 'kb-1',
|
|
404
|
+
dataSourceId: 'ds-1',
|
|
405
|
+
documents: [
|
|
406
|
+
{
|
|
407
|
+
content: {
|
|
408
|
+
dataSourceType: 'S3',
|
|
409
|
+
s3: { s3Location: { uri: 's3://my-bucket/memories/test-uuid-v7.txt' } },
|
|
410
|
+
},
|
|
411
|
+
},
|
|
412
|
+
],
|
|
413
|
+
},
|
|
414
|
+
}));
|
|
415
|
+
});
|
|
416
|
+
it('does not double up the slash when the prefix already ends in one', async () => {
|
|
417
|
+
const client = mockClient();
|
|
418
|
+
client.send.mockResolvedValue({});
|
|
419
|
+
const { store } = makeS3Store({}, { s3: { bucket: 'my-bucket', client: client, prefix: 'memories/' } });
|
|
420
|
+
await store.add('content');
|
|
421
|
+
expect(client.send).toHaveBeenCalledWith(expect.objectContaining({ input: expect.objectContaining({ Key: 'memories/test-uuid-v7.txt' }) }));
|
|
422
|
+
});
|
|
423
|
+
it('writes a sidecar carrying the scope and points the document metadata at it', async () => {
|
|
424
|
+
const { store, agent, s3 } = makeS3Store({ scope: 'team-a' });
|
|
425
|
+
await store.add('content');
|
|
426
|
+
expect(s3.send).toHaveBeenCalledTimes(2);
|
|
427
|
+
expect(s3.send).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
|
428
|
+
input: {
|
|
429
|
+
Bucket: 'my-bucket',
|
|
430
|
+
Key: 'memories/test-uuid-v7.txt.metadata.json',
|
|
431
|
+
Body: JSON.stringify({
|
|
432
|
+
metadataAttributes: {
|
|
433
|
+
namespace: { value: { type: 'STRING', stringValue: 'team-a' }, includeForEmbedding: false },
|
|
434
|
+
},
|
|
435
|
+
}),
|
|
436
|
+
ContentType: 'application/json',
|
|
437
|
+
},
|
|
438
|
+
}));
|
|
439
|
+
const document = agent.send.mock.calls[0]?.[0].input.documents[0];
|
|
440
|
+
expect(document.metadata).toStrictEqual({
|
|
441
|
+
type: 'S3_LOCATION',
|
|
442
|
+
s3Location: { uri: 's3://my-bucket/memories/test-uuid-v7.txt.metadata.json' },
|
|
443
|
+
});
|
|
444
|
+
});
|
|
445
|
+
it('writes a sidecar built from caller metadata', async () => {
|
|
446
|
+
const { store, s3 } = makeS3Store();
|
|
447
|
+
await store.add('content', { priority: 'high' });
|
|
448
|
+
expect(s3.send).toHaveBeenCalledTimes(2);
|
|
449
|
+
expect(s3.send).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
|
450
|
+
input: expect.objectContaining({
|
|
451
|
+
Body: JSON.stringify({
|
|
452
|
+
metadataAttributes: {
|
|
453
|
+
priority: { value: { type: 'STRING', stringValue: 'high' }, includeForEmbedding: false },
|
|
454
|
+
},
|
|
455
|
+
}),
|
|
456
|
+
}),
|
|
457
|
+
}));
|
|
458
|
+
});
|
|
459
|
+
it('omits unsupported metadata values from the sidecar', async () => {
|
|
460
|
+
const { store, s3 } = makeS3Store();
|
|
461
|
+
await store.add('content', { keep: 'yes', drop: { nested: true } });
|
|
462
|
+
expect(s3.send).toHaveBeenNthCalledWith(2, expect.objectContaining({
|
|
463
|
+
input: expect.objectContaining({
|
|
464
|
+
Body: JSON.stringify({
|
|
465
|
+
metadataAttributes: {
|
|
466
|
+
keep: { value: { type: 'STRING', stringValue: 'yes' }, includeForEmbedding: false },
|
|
467
|
+
},
|
|
468
|
+
}),
|
|
469
|
+
}),
|
|
470
|
+
}));
|
|
471
|
+
});
|
|
472
|
+
it('lazily constructs an agent client with no config when neither client nor config is given', async () => {
|
|
473
|
+
const s3 = mockClient();
|
|
474
|
+
s3.send.mockResolvedValue({});
|
|
475
|
+
const store = new BedrockKnowledgeBaseStore({
|
|
476
|
+
config: {
|
|
477
|
+
knowledgeBaseId: 'kb-1',
|
|
478
|
+
dataSourceType: 'S3',
|
|
479
|
+
dataSourceId: 'ds-1',
|
|
480
|
+
s3: { bucket: 'my-bucket', client: s3, prefix: 'memories' },
|
|
481
|
+
},
|
|
482
|
+
name: 'kb',
|
|
483
|
+
writable: true,
|
|
484
|
+
});
|
|
485
|
+
await store.add('content');
|
|
486
|
+
expect(vi.mocked(BedrockAgentClient)).toHaveBeenCalledWith({});
|
|
487
|
+
});
|
|
488
|
+
it('logs and rethrows when the S3 upload fails, before any ingestion', async () => {
|
|
489
|
+
const errorSpy = vi.spyOn(logger, 'error').mockImplementation(() => { });
|
|
490
|
+
const { store, agent, s3 } = makeS3Store();
|
|
491
|
+
s3.send.mockRejectedValue(new Error('upload boom'));
|
|
492
|
+
await expect(store.add('content')).rejects.toThrow('upload boom');
|
|
493
|
+
expect(errorSpy).toHaveBeenCalled();
|
|
494
|
+
expect(agent.send).not.toHaveBeenCalled();
|
|
495
|
+
errorSpy.mockRestore();
|
|
496
|
+
});
|
|
497
|
+
});
|
|
498
|
+
describe('add — non-writable store', () => {
|
|
499
|
+
it('throws when add is called on a non-writable store', async () => {
|
|
500
|
+
const agent = mockClient();
|
|
501
|
+
const store = new BedrockKnowledgeBaseStore({
|
|
502
|
+
config: { knowledgeBaseId: 'kb-1', dataSourceType: 'OTHER', dataSourceId: 'ds-1', agentClient: agent },
|
|
503
|
+
name: 'kb',
|
|
504
|
+
});
|
|
505
|
+
await expect(store.add('fact')).rejects.toThrow('store is not writable');
|
|
506
|
+
expect(agent.send).not.toHaveBeenCalled();
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
describe('config reuse across namespaces', () => {
|
|
510
|
+
it('reuses an injected runtime client across stores built from the same config', async () => {
|
|
511
|
+
const runtime = mockClient();
|
|
512
|
+
runtime.send.mockResolvedValue({ retrievalResults: [] });
|
|
513
|
+
const config = { knowledgeBaseId: 'kb-1', runtimeClient: runtime };
|
|
514
|
+
const personal = new BedrockKnowledgeBaseStore({ config, name: 'personal', scope: 'user-abc' });
|
|
515
|
+
const team = new BedrockKnowledgeBaseStore({ config, name: 'team', scope: 'other' });
|
|
516
|
+
expect(vi.mocked(BedrockAgentRuntimeClient)).not.toHaveBeenCalled();
|
|
517
|
+
await personal.search('q');
|
|
518
|
+
expect(lastSearchFilter(runtime)).toStrictEqual({ equals: { key: 'namespace', value: 'user-abc' } });
|
|
519
|
+
await team.search('q');
|
|
520
|
+
expect(lastSearchFilter(runtime)).toStrictEqual({ equals: { key: 'namespace', value: 'other' } });
|
|
521
|
+
});
|
|
522
|
+
it('constructs a separate default runtime client per store when the config injects none', () => {
|
|
523
|
+
const config = { knowledgeBaseId: 'kb-1' };
|
|
524
|
+
new BedrockKnowledgeBaseStore({ config, name: 'a' });
|
|
525
|
+
new BedrockKnowledgeBaseStore({ config, name: 'b' });
|
|
526
|
+
expect(vi.mocked(BedrockAgentRuntimeClient)).toHaveBeenCalledTimes(2);
|
|
527
|
+
});
|
|
528
|
+
it('inherits the data source from the shared config when writing', async () => {
|
|
529
|
+
const agent = mockClient();
|
|
530
|
+
agent.send.mockResolvedValue({});
|
|
531
|
+
const config = {
|
|
532
|
+
knowledgeBaseId: 'kb-shared',
|
|
533
|
+
dataSourceType: 'CUSTOM',
|
|
534
|
+
dataSourceId: 'ds-shared',
|
|
535
|
+
agentClient: agent,
|
|
536
|
+
};
|
|
537
|
+
const store = new BedrockKnowledgeBaseStore({ config, name: 'personal', scope: 'user-abc', writable: true });
|
|
538
|
+
await store.add('fact');
|
|
539
|
+
expect(agent.send).toHaveBeenCalledWith(expect.objectContaining({
|
|
540
|
+
input: expect.objectContaining({ knowledgeBaseId: 'kb-shared', dataSourceId: 'ds-shared' }),
|
|
541
|
+
}));
|
|
542
|
+
});
|
|
543
|
+
it('registers distinct-name stores together in a MemoryManager', () => {
|
|
544
|
+
const config = { knowledgeBaseId: 'kb-1', runtimeClient: mockClient() };
|
|
545
|
+
const personal = new BedrockKnowledgeBaseStore({ config, name: 'personal', scope: 'user-abc' });
|
|
546
|
+
const team = new BedrockKnowledgeBaseStore({ config, name: 'team', scope: 'other' });
|
|
547
|
+
expect(() => new MemoryManager({ stores: [personal, team] })).not.toThrow();
|
|
548
|
+
});
|
|
549
|
+
it('rejects two stores with the same name in a MemoryManager', () => {
|
|
550
|
+
const config = { knowledgeBaseId: 'kb-1', runtimeClient: mockClient() };
|
|
551
|
+
const a = new BedrockKnowledgeBaseStore({ config, name: 'dupe', scope: 'user-abc' });
|
|
552
|
+
const b = new BedrockKnowledgeBaseStore({ config, name: 'dupe', scope: 'other' });
|
|
553
|
+
expect(() => new MemoryManager({ stores: [a, b] })).toThrow("duplicate store name 'dupe'");
|
|
554
|
+
});
|
|
555
|
+
});
|
|
556
|
+
describe('scope and filter resolution', () => {
|
|
557
|
+
it('applies no filter when the store has no scope', async () => {
|
|
558
|
+
const { store, runtime } = makeStore();
|
|
559
|
+
await store.search('q');
|
|
560
|
+
expect(lastSearchFilter(runtime)).toBeUndefined();
|
|
561
|
+
});
|
|
562
|
+
it('scopes writes by scope even when an explicit search filter is set (search/write asymmetry)', async () => {
|
|
563
|
+
const { store, agent } = makeCustomStore({ scope: 'tenant-a', filter: { equals: { key: 'custom', value: 'v' } } });
|
|
564
|
+
await store.add('fact');
|
|
565
|
+
expect(lastInlineAttributes(agent)).toStrictEqual([
|
|
566
|
+
{ key: 'namespace', value: { type: 'STRING', stringValue: 'tenant-a' } },
|
|
567
|
+
]);
|
|
568
|
+
});
|
|
569
|
+
});
|
|
570
|
+
describe('metadata logging', () => {
|
|
571
|
+
it('logs a debug line when a CUSTOM document drops an unsupported metadata value', async () => {
|
|
572
|
+
const debugSpy = vi.spyOn(logger, 'debug').mockImplementation(() => { });
|
|
573
|
+
const { store } = makeCustomStore();
|
|
574
|
+
await store.add('fact', { good: 'v', bad: { nested: true } });
|
|
575
|
+
expect(debugSpy).toHaveBeenCalledWith(expect.stringContaining('key=<bad>'));
|
|
576
|
+
expect(debugSpy).not.toHaveBeenCalledWith(expect.stringContaining('key=<good>'));
|
|
577
|
+
debugSpy.mockRestore();
|
|
578
|
+
});
|
|
579
|
+
});
|
|
580
|
+
// End-to-end: a writable CUSTOM store carrying an extraction config is picked up by MemoryManager,
|
|
581
|
+
// and on a trigger fire the extracted facts are ingested through the store's own `add` (i.e. via
|
|
582
|
+
// IngestKnowledgeBaseDocuments on the injected agent client). No AWS calls; clients are mocked.
|
|
583
|
+
describe('extraction via MemoryManager', () => {
|
|
584
|
+
it('ingests extracted facts through add when the trigger fires', async () => {
|
|
585
|
+
const extractor = {
|
|
586
|
+
extract: vi.fn().mockResolvedValue([{ content: 'user prefers dark mode' }]),
|
|
587
|
+
};
|
|
588
|
+
const { store, agent: agentClient } = makeCustomStore({
|
|
589
|
+
extraction: { trigger: new InvocationTrigger(), extractor },
|
|
590
|
+
});
|
|
591
|
+
const mm = new MemoryManager({ stores: [store] });
|
|
592
|
+
const agent = createMockAgent();
|
|
593
|
+
mm.initAgent(agent);
|
|
594
|
+
// Buffer a turn, then fire the after-invocation hook and flush the background save.
|
|
595
|
+
const message = new Message({ role: 'user', content: [new TextBlock('I like dark mode')] });
|
|
596
|
+
const added = agent.trackedHooks.filter((h) => h.eventType === MessageAddedEvent);
|
|
597
|
+
for (const hook of added)
|
|
598
|
+
await hook.callback(new MessageAddedEvent({ agent, message, invocationState: {} }));
|
|
599
|
+
const after = agent.trackedHooks.filter((h) => h.eventType === AfterInvocationEvent);
|
|
600
|
+
for (const hook of after)
|
|
601
|
+
await hook.callback(new AfterInvocationEvent({ agent, invocationState: {} }));
|
|
602
|
+
await mm.flush();
|
|
603
|
+
expect(extractor.extract).toHaveBeenCalledTimes(1);
|
|
604
|
+
// The fact was ingested via IngestKnowledgeBaseDocuments with the extracted content.
|
|
605
|
+
expect(agentClient.send).toHaveBeenCalledTimes(1);
|
|
606
|
+
const document = agentClient.send.mock.calls[0]?.[0].input.documents[0];
|
|
607
|
+
expect(document.content.custom.inlineContent.textContent.data).toBe('user prefers dark mode');
|
|
608
|
+
});
|
|
609
|
+
});
|
|
610
|
+
});
|
|
611
|
+
//# sourceMappingURL=bedrock-knowledge-base-store.test.js.map
|