@strands-agents/sdk 1.4.0 → 1.6.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 +9 -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.stateful-model.test.js +2 -2
- package/dist/src/agent/__tests__/agent.stateful-model.test.js.map +1 -1
- 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 +135 -2
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +506 -189
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/context-manager/modes/agentic/agentic-context.d.ts +19 -0
- package/dist/src/context-manager/modes/agentic/agentic-context.d.ts.map +1 -0
- package/dist/src/context-manager/modes/agentic/agentic-context.js +245 -0
- package/dist/src/context-manager/modes/agentic/agentic-context.js.map +1 -0
- package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts +2 -0
- package/dist/src/conversation-manager/__tests__/agentic-context.test.d.ts.map +1 -0
- package/dist/src/conversation-manager/__tests__/agentic-context.test.js +332 -0
- package/dist/src/conversation-manager/__tests__/agentic-context.test.js.map +1 -0
- package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts +2 -0
- package/dist/src/conversation-manager/__tests__/context-compression.test.d.ts.map +1 -0
- package/dist/src/conversation-manager/__tests__/context-compression.test.js +176 -0
- package/dist/src/conversation-manager/__tests__/context-compression.test.js.map +1 -0
- 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/__tests__/token-usage-middleware.test.d.ts +2 -0
- package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.d.ts.map +1 -0
- package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js +138 -0
- package/dist/src/conversation-manager/__tests__/token-usage-middleware.test.js.map +1 -0
- package/dist/src/conversation-manager/compression/context-compression.d.ts +39 -0
- package/dist/src/conversation-manager/compression/context-compression.d.ts.map +1 -0
- package/dist/src/conversation-manager/compression/context-compression.js +150 -0
- package/dist/src/conversation-manager/compression/context-compression.js.map +1 -0
- package/dist/src/conversation-manager/compression/pin-message.d.ts +45 -0
- package/dist/src/conversation-manager/compression/pin-message.d.ts.map +1 -0
- package/dist/src/conversation-manager/compression/pin-message.js +106 -0
- package/dist/src/conversation-manager/compression/pin-message.js.map +1 -0
- package/dist/src/conversation-manager/conversation-manager.d.ts +2 -0
- package/dist/src/conversation-manager/conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/conversation-manager.js +2 -2
- package/dist/src/conversation-manager/conversation-manager.js.map +1 -1
- 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 +30 -38
- package/dist/src/conversation-manager/sliding-window-conversation-manager.js.map +1 -1
- package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts +7 -19
- package/dist/src/conversation-manager/summarizing-conversation-manager.d.ts.map +1 -1
- package/dist/src/conversation-manager/summarizing-conversation-manager.js +20 -109
- 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/injection/__tests__/message-injection.test.d.ts +2 -0
- package/dist/src/injection/__tests__/message-injection.test.d.ts.map +1 -0
- package/dist/src/injection/__tests__/message-injection.test.js +200 -0
- package/dist/src/injection/__tests__/message-injection.test.js.map +1 -0
- package/dist/src/injection/index.d.ts +6 -0
- package/dist/src/injection/index.d.ts.map +1 -0
- package/dist/src/injection/index.js +2 -0
- package/dist/src/injection/index.js.map +1 -0
- package/dist/src/injection/message-injection.d.ts +65 -0
- package/dist/src/injection/message-injection.d.ts.map +1 -0
- package/dist/src/injection/message-injection.js +134 -0
- package/dist/src/injection/message-injection.js.map +1 -0
- package/dist/src/injection/types.d.ts +63 -0
- package/dist/src/injection/types.d.ts.map +1 -0
- package/dist/src/injection/types.js +2 -0
- package/dist/src/injection/types.js.map +1 -0
- package/dist/src/injection/xml.d.ts +27 -0
- package/dist/src/injection/xml.d.ts.map +1 -0
- package/dist/src/injection/xml.js +31 -0
- package/dist/src/injection/xml.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 +679 -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 +10 -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 +178 -0
- package/dist/src/memory/memory-manager.d.ts.map +1 -0
- package/dist/src/memory/memory-manager.js +526 -0
- package/dist/src/memory/memory-manager.js.map +1 -0
- package/dist/src/memory/types.d.ts +278 -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 +1206 -0
- package/dist/src/middleware/__tests__/agent-middleware.test.js.map +1 -0
- package/dist/src/middleware/__tests__/copy-on-input.test.d.ts +2 -0
- package/dist/src/middleware/__tests__/copy-on-input.test.d.ts.map +1 -0
- package/dist/src/middleware/__tests__/copy-on-input.test.js +379 -0
- package/dist/src/middleware/__tests__/copy-on-input.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 +145 -0
- package/dist/src/middleware/stages.d.ts.map +1 -0
- package/dist/src/middleware/stages.js +34 -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 +17 -4
- package/dist/src/sandbox/base.d.ts.map +1 -1
- package/dist/src/sandbox/base.js +10 -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 +61 -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 +121 -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 +9 -1
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js +13 -1
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts +2 -0
- package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.d.ts.map +1 -0
- package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js +675 -0
- package/dist/src/vended-interventions/cedar/__tests__/cedar.test.node.js.map +1 -0
- package/dist/src/vended-interventions/cedar/cedar.d.ts +102 -0
- package/dist/src/vended-interventions/cedar/cedar.d.ts.map +1 -0
- package/dist/src/vended-interventions/cedar/cedar.js +228 -0
- package/dist/src/vended-interventions/cedar/cedar.js.map +1 -0
- package/dist/src/vended-interventions/cedar/index.d.ts +3 -0
- package/dist/src/vended-interventions/cedar/index.d.ts.map +1 -0
- package/dist/src/vended-interventions/cedar/index.js +2 -0
- package/dist/src/vended-interventions/cedar/index.js.map +1 -0
- package/dist/src/vended-interventions/cedar/schema-generator.d.ts +10 -0
- package/dist/src/vended-interventions/cedar/schema-generator.d.ts.map +1 -0
- package/dist/src/vended-interventions/cedar/schema-generator.js +33 -0
- package/dist/src/vended-interventions/cedar/schema-generator.js.map +1 -0
- 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-injector/__tests__/plugin.test.d.ts +2 -0
- package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.d.ts.map +1 -0
- package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js +96 -0
- package/dist/src/vended-plugins/context-injector/__tests__/plugin.test.js.map +1 -0
- package/dist/src/vended-plugins/context-injector/index.d.ts +25 -0
- package/dist/src/vended-plugins/context-injector/index.d.ts.map +1 -0
- package/dist/src/vended-plugins/context-injector/index.js +23 -0
- package/dist/src/vended-plugins/context-injector/index.js.map +1 -0
- package/dist/src/vended-plugins/context-injector/plugin.d.ts +55 -0
- package/dist/src/vended-plugins/context-injector/plugin.d.ts.map +1 -0
- package/dist/src/vended-plugins/context-injector/plugin.js +41 -0
- package/dist/src/vended-plugins/context-injector/plugin.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.js +43 -4
- package/dist/src/vended-plugins/context-offloader/__tests__/plugin.test.js.map +1 -1
- 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/__tests__/storage.test.js +68 -0
- package/dist/src/vended-plugins/context-offloader/__tests__/storage.test.js.map +1 -1
- 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 +40 -8
- 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 +58 -6
- package/dist/src/vended-plugins/context-offloader/storage.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/storage.js +136 -14
- 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 +3 -1
- package/dist/src/vended-plugins/index.d.ts.map +1 -1
- package/dist/src/vended-plugins/index.js +3 -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 +59 -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
package/dist/src/agent/agent.js
CHANGED
|
@@ -1,26 +1,33 @@
|
|
|
1
1
|
import { AgentResult, } from '../types/agent.js';
|
|
2
2
|
import { BedrockModel } from '../models/bedrock.js';
|
|
3
3
|
import { contentBlockFromData, Message, TextBlock, ToolResultBlock, ToolUseBlock, } from '../types/messages.js';
|
|
4
|
+
import { deepCopy } from '../types/json.js';
|
|
4
5
|
import { McpClient } from '../mcp.js';
|
|
5
6
|
import { isValidToolName } from '../tools/tool.js';
|
|
6
|
-
import { systemPromptFromData } from '../types/messages.js';
|
|
7
|
+
import { cloneSystemPrompt, systemPromptFromData } from '../types/messages.js';
|
|
7
8
|
import { normalizeError, ConcurrentInvocationError, StructuredOutputError } from '../errors.js';
|
|
8
9
|
import { Model } from '../models/model.js';
|
|
9
10
|
import { ModelPlugin } from '../plugins/model-plugin.js';
|
|
10
11
|
import { isModelStreamEvent } from '../models/streaming.js';
|
|
11
12
|
import { ToolRegistry } from '../registry/tool-registry.js';
|
|
12
13
|
import { StateStore } from '../state-store.js';
|
|
14
|
+
import { serializeStateSerializable, loadStateSerializable } from '../types/serializable.js';
|
|
13
15
|
import { AgentPrinter, getDefaultAppender } from './printer.js';
|
|
14
16
|
import { InterventionRegistry } from '../interventions/registry.js';
|
|
15
17
|
import { PluginRegistry } from '../plugins/registry.js';
|
|
16
18
|
import { SlidingWindowConversationManager } from '../conversation-manager/sliding-window-conversation-manager.js';
|
|
19
|
+
import { SummarizingConversationManager } from '../conversation-manager/summarizing-conversation-manager.js';
|
|
17
20
|
import { NullConversationManager } from '../conversation-manager/null-conversation-manager.js';
|
|
18
21
|
import { ConversationManager } from '../conversation-manager/conversation-manager.js';
|
|
22
|
+
import { ContextOffloader } from '../vended-plugins/context-offloader/plugin.js';
|
|
23
|
+
import { InMemoryStorage } from '../vended-plugins/context-offloader/storage.js';
|
|
19
24
|
import { HookRegistryImplementation } from '../hooks/registry.js';
|
|
25
|
+
import { MiddlewareRegistry, InvokeModelStage, ExecuteToolStage, AgentStreamStage } from '../middleware/index.js';
|
|
20
26
|
import { InitializedEvent, AfterInvocationEvent, AfterModelCallEvent, AfterToolCallEvent, AfterToolsEvent, BeforeInvocationEvent, BeforeModelCallEvent, BeforeToolCallEvent, BeforeToolsEvent, HookableEvent, MessageAddedEvent, ModelStreamUpdateEvent, ContentBlockEvent, ModelMessageEvent, ToolResultEvent, AgentResultEvent, ToolStreamUpdateEvent, InterruptEvent, } from '../hooks/events.js';
|
|
21
27
|
import { StructuredOutputTool, STRUCTURED_OUTPUT_TOOL_NAME } from '../tools/structured-output-tool.js';
|
|
22
28
|
import { AgentAsTool } from './agent-as-tool.js';
|
|
23
29
|
import { ToolCaller } from './tool-caller.js';
|
|
30
|
+
import { MemoryManager } from '../memory/memory-manager.js';
|
|
24
31
|
import { SessionManager } from '../session/session-manager.js';
|
|
25
32
|
import { Tracer } from '../telemetry/tracer.js';
|
|
26
33
|
import { Meter } from '../telemetry/meter.js';
|
|
@@ -28,13 +35,83 @@ import { logger } from '../logging/logger.js';
|
|
|
28
35
|
import { CancelledError } from '../errors.js';
|
|
29
36
|
import { DefaultModelRetryStrategy } from '../retry/default-model-retry-strategy.js';
|
|
30
37
|
import { warnOnDuplicateRetryStrategyTypes } from '../retry/retry-strategy.js';
|
|
31
|
-
import { InterruptError, InterruptState, interruptFromAgent } from '../interrupt.js';
|
|
38
|
+
import { Interrupt, InterruptError, InterruptState, interruptFromAgent } from '../interrupt.js';
|
|
32
39
|
import { isInterruptResponseContent } from '../types/interrupt.js';
|
|
33
40
|
import { takeSnapshot as takeSnapshotInternal, loadSnapshot as loadSnapshotInternal } from './snapshot.js';
|
|
41
|
+
import { defaultSandbox } from '../sandbox/default.js';
|
|
42
|
+
import { summarizeContextTool, truncateContextTool, pinContextTool, createTokenUsageMiddleware, } from '../context-manager/modes/agentic/agentic-context.js';
|
|
43
|
+
/**
|
|
44
|
+
* Supported values for the `contextManager` parameter.
|
|
45
|
+
*/
|
|
46
|
+
export const CONTEXT_MANAGER_STRATEGIES = ['auto', 'agentic'];
|
|
47
|
+
/** Benchmark-validated token threshold for offloading tool results. */
|
|
48
|
+
const CONTEXT_MANAGER_MAX_RESULT_TOKENS = 1_500;
|
|
49
|
+
/** Higher offload threshold for agentic mode — the model manages its own context, so we preserve more inline. */
|
|
50
|
+
const AGENTIC_CONTEXT_MANAGER_MAX_RESULT_TOKENS = 8_000;
|
|
51
|
+
/** Benchmark-validated preview token count for offloaded results. */
|
|
52
|
+
const CONTEXT_MANAGER_PREVIEW_TOKENS = 750;
|
|
53
|
+
/** Benchmark-validated ratio of messages to summarize on overflow. */
|
|
54
|
+
const CONTEXT_MANAGER_SUMMARY_RATIO = 0.3;
|
|
55
|
+
/** Benchmark-validated context window ratio that triggers proactive compression. */
|
|
56
|
+
const CONTEXT_MANAGER_COMPRESSION_THRESHOLD = 0.85;
|
|
57
|
+
/**
|
|
58
|
+
* Resolve the contextManager facade into a concrete ConversationManager.
|
|
59
|
+
*
|
|
60
|
+
* When contextManager is undefined, falls back to the default SlidingWindowConversationManager.
|
|
61
|
+
* When "auto", uses SummarizingConversationManager with proactive compression.
|
|
62
|
+
* When "agentic", uses SummarizingConversationManager without proactive compression
|
|
63
|
+
* (the agent manages its context via tools; the context manager is only a reactive safety net).
|
|
64
|
+
*/
|
|
65
|
+
function resolveConversationManager(contextManager, conversationManager) {
|
|
66
|
+
if (contextManager === 'agentic') {
|
|
67
|
+
return (conversationManager ??
|
|
68
|
+
new SummarizingConversationManager({
|
|
69
|
+
summaryRatio: CONTEXT_MANAGER_SUMMARY_RATIO,
|
|
70
|
+
}));
|
|
71
|
+
}
|
|
72
|
+
if (contextManager === 'auto') {
|
|
73
|
+
return (conversationManager ??
|
|
74
|
+
new SummarizingConversationManager({
|
|
75
|
+
summaryRatio: CONTEXT_MANAGER_SUMMARY_RATIO,
|
|
76
|
+
proactiveCompression: { compressionThreshold: CONTEXT_MANAGER_COMPRESSION_THRESHOLD },
|
|
77
|
+
}));
|
|
78
|
+
}
|
|
79
|
+
if (contextManager !== undefined) {
|
|
80
|
+
throw new Error(`Unsupported contextManager value: "${contextManager}". Supported values: ${CONTEXT_MANAGER_STRATEGIES.map((s) => `"${s}"`).join(', ')}`);
|
|
81
|
+
}
|
|
82
|
+
return conversationManager ?? new SlidingWindowConversationManager({ windowSize: 40 });
|
|
83
|
+
}
|
|
34
84
|
/** Default name assigned to agents when none is provided. */
|
|
35
85
|
const DEFAULT_AGENT_NAME = 'Strands Agent';
|
|
36
86
|
/** Default identifier assigned to agents when none is provided. */
|
|
37
87
|
const DEFAULT_AGENT_ID = 'agent';
|
|
88
|
+
/**
|
|
89
|
+
* Creates a non-mutating interrupt function for middleware contexts.
|
|
90
|
+
* Reads existing responses from state (resume case) but never writes to it.
|
|
91
|
+
* On first run (no response), throws InterruptError with a locally-created Interrupt.
|
|
92
|
+
*
|
|
93
|
+
* @param interruptState - The agent's interrupt state (read-only access)
|
|
94
|
+
* @param idPrefix - Prefix for the interrupt ID (e.g., 'middleware:agentStream')
|
|
95
|
+
*/
|
|
96
|
+
function createMiddlewareInterrupt(interruptState, idPrefix) {
|
|
97
|
+
return (params) => {
|
|
98
|
+
const interruptId = `${idPrefix}:${params.name}`;
|
|
99
|
+
const existing = interruptState.interrupts[interruptId];
|
|
100
|
+
if (existing?.response !== undefined) {
|
|
101
|
+
return { response: existing.response };
|
|
102
|
+
}
|
|
103
|
+
if (params.response !== undefined) {
|
|
104
|
+
return { response: params.response };
|
|
105
|
+
}
|
|
106
|
+
const interrupt = new Interrupt({
|
|
107
|
+
id: interruptId,
|
|
108
|
+
name: params.name,
|
|
109
|
+
...(params.reason !== undefined && { reason: params.reason }),
|
|
110
|
+
source: 'middleware',
|
|
111
|
+
});
|
|
112
|
+
throw new InterruptError(interrupt);
|
|
113
|
+
};
|
|
114
|
+
}
|
|
38
115
|
/**
|
|
39
116
|
* Orchestrates the interaction between a model, a set of tools, and MCP clients.
|
|
40
117
|
* The Agent is responsible for managing the lifecycle of tools and clients
|
|
@@ -81,7 +158,22 @@ export class Agent {
|
|
|
81
158
|
* The session manager for saving and restoring agent sessions, if configured.
|
|
82
159
|
*/
|
|
83
160
|
sessionManager;
|
|
161
|
+
/**
|
|
162
|
+
* The memory manager for cross-session memory retrieval and storage, if configured.
|
|
163
|
+
*/
|
|
164
|
+
memoryManager;
|
|
165
|
+
_sandbox;
|
|
166
|
+
/**
|
|
167
|
+
* Execution environment for running commands, code, and file operations.
|
|
168
|
+
*
|
|
169
|
+
* @throws DefaultNotConfiguredError if no sandbox is configured for this
|
|
170
|
+
* environment (e.g. browsers, where no host default is registered).
|
|
171
|
+
*/
|
|
172
|
+
get sandbox() {
|
|
173
|
+
return this._sandbox || defaultSandbox.get();
|
|
174
|
+
}
|
|
84
175
|
_hooksRegistry;
|
|
176
|
+
_middlewareRegistry;
|
|
85
177
|
_pluginRegistry;
|
|
86
178
|
_interventionRegistry;
|
|
87
179
|
_toolRegistry;
|
|
@@ -116,6 +208,13 @@ export class Agent {
|
|
|
116
208
|
if (config?.description !== undefined)
|
|
117
209
|
this.description = config.description;
|
|
118
210
|
this.sessionManager = config?.sessionManager;
|
|
211
|
+
this.memoryManager =
|
|
212
|
+
config?.memoryManager instanceof MemoryManager
|
|
213
|
+
? config.memoryManager
|
|
214
|
+
: config?.memoryManager
|
|
215
|
+
? new MemoryManager(config.memoryManager)
|
|
216
|
+
: undefined;
|
|
217
|
+
this._sandbox = config?.sandbox;
|
|
119
218
|
if (typeof config?.model === 'string') {
|
|
120
219
|
this.model = new BedrockModel({ modelId: config.model });
|
|
121
220
|
}
|
|
@@ -124,21 +223,28 @@ export class Agent {
|
|
|
124
223
|
}
|
|
125
224
|
// Validate and assign conversation manager
|
|
126
225
|
if (this.model.stateful) {
|
|
127
|
-
if (config?.conversationManager) {
|
|
128
|
-
throw new Error('
|
|
226
|
+
if (config?.conversationManager || config?.contextManager) {
|
|
227
|
+
throw new Error('contextManager and conversationManager cannot be used with a stateful model. The model manages conversation state server-side.');
|
|
129
228
|
}
|
|
130
229
|
this._conversationManager = new NullConversationManager();
|
|
131
230
|
}
|
|
132
231
|
else {
|
|
133
|
-
this._conversationManager =
|
|
134
|
-
config?.conversationManager ?? new SlidingWindowConversationManager({ windowSize: 40 });
|
|
232
|
+
this._conversationManager = resolveConversationManager(config?.contextManager, config?.conversationManager);
|
|
135
233
|
}
|
|
136
234
|
const { tools, mcpClients } = flattenTools(config?.tools ?? []);
|
|
235
|
+
if (config?.contextManager === 'agentic') {
|
|
236
|
+
tools.push(summarizeContextTool, truncateContextTool, pinContextTool);
|
|
237
|
+
}
|
|
137
238
|
this._toolRegistry = new ToolRegistry(tools);
|
|
138
239
|
this._mcpClients = mcpClients;
|
|
139
240
|
// Initialize hooks registry
|
|
140
241
|
this._hooksRegistry = new HookRegistryImplementation();
|
|
141
242
|
this._interventionRegistry = new InterventionRegistry(config?.interventions ?? [], this._hooksRegistry);
|
|
243
|
+
// Initialize middleware registry
|
|
244
|
+
this._middlewareRegistry = new MiddlewareRegistry();
|
|
245
|
+
if (config?.contextManager === 'agentic') {
|
|
246
|
+
this._middlewareRegistry.addInput(InvokeModelStage.Input, createTokenUsageMiddleware(this.model));
|
|
247
|
+
}
|
|
142
248
|
// `undefined` (omitted) → install the default; `null`/`[]` → explicit opt-out.
|
|
143
249
|
const retryStrategies = config?.retryStrategy === null
|
|
144
250
|
? []
|
|
@@ -156,10 +262,23 @@ export class Agent {
|
|
|
156
262
|
// - Retry-strategy ordering is not load-bearing for correctness: `DefaultModelRetryStrategy`
|
|
157
263
|
// guards on `event.retry`, so a user hook that already set it short-circuits
|
|
158
264
|
// the strategy regardless of registration order.
|
|
265
|
+
const hasOffloader = (config?.plugins ?? []).some((p) => p.name === 'strands:context-offloader');
|
|
159
266
|
this._pluginRegistry = new PluginRegistry([
|
|
160
267
|
this._conversationManager,
|
|
161
268
|
...retryStrategies,
|
|
162
269
|
...(config?.plugins ?? []),
|
|
270
|
+
...((config?.contextManager === 'auto' || config?.contextManager === 'agentic') && !hasOffloader
|
|
271
|
+
? [
|
|
272
|
+
new ContextOffloader({
|
|
273
|
+
storage: new InMemoryStorage(),
|
|
274
|
+
maxResultTokens: config?.contextManager === 'agentic'
|
|
275
|
+
? AGENTIC_CONTEXT_MANAGER_MAX_RESULT_TOKENS
|
|
276
|
+
: CONTEXT_MANAGER_MAX_RESULT_TOKENS,
|
|
277
|
+
previewTokens: CONTEXT_MANAGER_PREVIEW_TOKENS,
|
|
278
|
+
}),
|
|
279
|
+
]
|
|
280
|
+
: []),
|
|
281
|
+
...(this.memoryManager ? [this.memoryManager] : []),
|
|
163
282
|
...(config?.sessionManager ? [config.sessionManager] : []),
|
|
164
283
|
new ModelPlugin(this.model),
|
|
165
284
|
]);
|
|
@@ -208,6 +327,33 @@ export class Agent {
|
|
|
208
327
|
addHook(eventType, callback, options) {
|
|
209
328
|
return this._hooksRegistry.addCallback(eventType, callback, options);
|
|
210
329
|
}
|
|
330
|
+
addMiddleware(stageOrPhase, handler) {
|
|
331
|
+
if ('_phase' in stageOrPhase) {
|
|
332
|
+
const phase = stageOrPhase;
|
|
333
|
+
const stage = phase._stage;
|
|
334
|
+
switch (phase._phase) {
|
|
335
|
+
case 'input': {
|
|
336
|
+
const adapted = this._middlewareRegistry.addInput(stageOrPhase, handler);
|
|
337
|
+
return () => this._middlewareRegistry.remove(stage, adapted);
|
|
338
|
+
}
|
|
339
|
+
case 'output': {
|
|
340
|
+
const adapted = this._middlewareRegistry.addOutput(stageOrPhase, handler);
|
|
341
|
+
return () => this._middlewareRegistry.remove(stage, adapted);
|
|
342
|
+
}
|
|
343
|
+
case 'wrap': {
|
|
344
|
+
const wrapHandler = handler;
|
|
345
|
+
this._middlewareRegistry.add(stage, wrapHandler);
|
|
346
|
+
return () => this._middlewareRegistry.remove(stage, wrapHandler);
|
|
347
|
+
}
|
|
348
|
+
default:
|
|
349
|
+
throw new Error(`Unknown middleware phase: ${phase._phase}`);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
const stage = stageOrPhase;
|
|
353
|
+
const wrapHandler = handler;
|
|
354
|
+
this._middlewareRegistry.add(stage, wrapHandler);
|
|
355
|
+
return () => this._middlewareRegistry.remove(stage, wrapHandler);
|
|
356
|
+
}
|
|
211
357
|
async initialize() {
|
|
212
358
|
if (this._initialized) {
|
|
213
359
|
return;
|
|
@@ -221,6 +367,18 @@ export class Agent {
|
|
|
221
367
|
this._toolRegistry.addOrReplace(newTools);
|
|
222
368
|
};
|
|
223
369
|
}));
|
|
370
|
+
// Register tools vended by the sandbox. The host default vends nothing. A tool
|
|
371
|
+
// is skipped if the user already registered one with that name.
|
|
372
|
+
if (this._sandbox) {
|
|
373
|
+
for (const sandboxTool of this._sandbox.getTools()) {
|
|
374
|
+
if (this._toolRegistry.get(sandboxTool.name)) {
|
|
375
|
+
logger.debug(`tool_name=<${sandboxTool.name}> | sandbox-vended tool skipped, user already registered a tool with this name`);
|
|
376
|
+
}
|
|
377
|
+
else {
|
|
378
|
+
this._toolRegistry.add(sandboxTool);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
}
|
|
224
382
|
await this._pluginRegistry.initialize(this);
|
|
225
383
|
for (const handler of this._interventionRegistry.handlers) {
|
|
226
384
|
const observer = handler;
|
|
@@ -454,90 +612,183 @@ export class Agent {
|
|
|
454
612
|
this.acquireLock();
|
|
455
613
|
try {
|
|
456
614
|
await this.initialize();
|
|
615
|
+
// Thread the resolved invocationState so all layers share the same reference.
|
|
616
|
+
const invocationState = options?.invocationState ?? {};
|
|
617
|
+
const resolvedOptions = options?.invocationState ? options : { ...options, invocationState };
|
|
457
618
|
let currentArgs = args;
|
|
458
|
-
// Outer loop: re-enters _stream when a hook sets AfterInvocationEvent.resume.
|
|
459
|
-
// One invocation lock spans the whole resume chain.
|
|
460
619
|
while (true) {
|
|
461
|
-
// Fresh AbortController per
|
|
620
|
+
// Fresh AbortController per iteration, composed with any external signal.
|
|
462
621
|
this._abortController = new AbortController();
|
|
463
|
-
this._abortSignal =
|
|
464
|
-
? AbortSignal.any([this._abortController.signal,
|
|
622
|
+
this._abortSignal = resolvedOptions?.cancelSignal
|
|
623
|
+
? AbortSignal.any([this._abortController.signal, resolvedOptions.cancelSignal])
|
|
465
624
|
: this._abortController.signal;
|
|
466
|
-
|
|
625
|
+
// Process interrupt responses before middleware runs so context.interrupt() can find them
|
|
626
|
+
const interruptResponses = this._extractInterruptResponses(currentArgs);
|
|
627
|
+
if (interruptResponses.length > 0) {
|
|
628
|
+
this._interruptState.resume(interruptResponses);
|
|
629
|
+
}
|
|
630
|
+
// Hooks fire outside middleware — always, even on short-circuit.
|
|
631
|
+
const beforeInvocationEvent = new BeforeInvocationEvent({ agent: this, invocationState });
|
|
632
|
+
yield await this._invokeCallbacks(beforeInvocationEvent);
|
|
633
|
+
if (beforeInvocationEvent.cancel) {
|
|
634
|
+
const cancelText = typeof beforeInvocationEvent.cancel === 'string'
|
|
635
|
+
? beforeInvocationEvent.cancel
|
|
636
|
+
: 'invocation denied by hook';
|
|
637
|
+
const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
|
|
638
|
+
yield this._appendMessage(message, invocationState);
|
|
639
|
+
const afterEvent = new AfterInvocationEvent({ agent: this, invocationState });
|
|
640
|
+
await this._invokeCallbacks(afterEvent);
|
|
641
|
+
yield afterEvent;
|
|
642
|
+
return new AgentResult({
|
|
643
|
+
stopReason: 'endTurn',
|
|
644
|
+
lastMessage: message,
|
|
645
|
+
traces: this._tracer.localTraces,
|
|
646
|
+
metrics: this._meter.metrics,
|
|
647
|
+
invocationState,
|
|
648
|
+
});
|
|
649
|
+
}
|
|
650
|
+
let result;
|
|
467
651
|
let caughtError;
|
|
468
|
-
|
|
469
|
-
let iterationResult;
|
|
652
|
+
const afterInvocationEvent = new AfterInvocationEvent({ agent: this, invocationState });
|
|
470
653
|
try {
|
|
471
|
-
|
|
472
|
-
while (!iterationResult.done) {
|
|
473
|
-
try {
|
|
474
|
-
const processed = await this._invokeCallbacks(iterationResult.value);
|
|
475
|
-
if (processed instanceof AfterInvocationEvent) {
|
|
476
|
-
lastAfterInvocation = processed;
|
|
477
|
-
}
|
|
478
|
-
yield processed;
|
|
479
|
-
iterationResult = await streamGenerator.next();
|
|
480
|
-
}
|
|
481
|
-
catch (error) {
|
|
482
|
-
// Throw interrupt errors back into _stream so executeTools can store the
|
|
483
|
-
// assistant message as pending execution state for resume.
|
|
484
|
-
if (error instanceof InterruptError) {
|
|
485
|
-
iterationResult = await streamGenerator.throw(error);
|
|
486
|
-
}
|
|
487
|
-
else {
|
|
488
|
-
throw error;
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
}
|
|
492
|
-
// Suppress AgentResultEvent for resumed iterations — only the final
|
|
493
|
-
// invocation in a resume chain reports an agent result.
|
|
494
|
-
if (lastAfterInvocation?.resume === undefined) {
|
|
495
|
-
yield await this._invokeCallbacks(new AgentResultEvent({
|
|
496
|
-
agent: this,
|
|
497
|
-
result: iterationResult.value,
|
|
498
|
-
invocationState: iterationResult.value.invocationState,
|
|
499
|
-
}));
|
|
500
|
-
}
|
|
654
|
+
result = yield* this._streamWithMiddleware(currentArgs, resolvedOptions, invocationState);
|
|
501
655
|
}
|
|
502
656
|
catch (error) {
|
|
503
657
|
caughtError = error;
|
|
504
|
-
throw error;
|
|
505
658
|
}
|
|
506
659
|
finally {
|
|
507
|
-
//
|
|
508
|
-
//
|
|
509
|
-
//
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
}
|
|
520
|
-
catch (error) {
|
|
521
|
-
logger.warn(`event_type=<${drainResult.value.type}>, error=<${error}> | error invoking callbacks during cleanup`);
|
|
522
|
-
}
|
|
523
|
-
drainResult = await streamGenerator.next();
|
|
524
|
-
}
|
|
525
|
-
// Reset controller and signal for next iteration / invocation
|
|
526
|
-
this._abortController = new AbortController();
|
|
527
|
-
this._abortSignal = this._abortController.signal;
|
|
660
|
+
// AfterInvocationEvent always fires — even on error or consumer break. Outside middleware.
|
|
661
|
+
// Invoke hooks (so .resume can be set) but don't yield in finally (yields in finally
|
|
662
|
+
// suspend the generator on consumer break instead of completing cleanup).
|
|
663
|
+
await this._invokeCallbacks(afterInvocationEvent);
|
|
664
|
+
}
|
|
665
|
+
// Yield outside finally — in JS, a `yield` inside `finally` suspends the generator
|
|
666
|
+
// mid-cleanup when the consumer breaks, preventing subsequent cleanup code from running.
|
|
667
|
+
// This line is only reached on normal completion or caught error, never on consumer break.
|
|
668
|
+
yield afterInvocationEvent;
|
|
669
|
+
// Re-throw after hooks have fired
|
|
670
|
+
if (caughtError) {
|
|
671
|
+
throw caughtError;
|
|
528
672
|
}
|
|
529
673
|
// Resume only on a clean invocation — errors propagate above.
|
|
530
|
-
if (
|
|
531
|
-
currentArgs =
|
|
674
|
+
if (afterInvocationEvent.resume !== undefined) {
|
|
675
|
+
currentArgs = afterInvocationEvent.resume;
|
|
532
676
|
continue;
|
|
533
677
|
}
|
|
534
|
-
|
|
678
|
+
// Only emit AgentResultEvent on the final iteration (not on resumed ones).
|
|
679
|
+
yield await this._invokeCallbacks(new AgentResultEvent({
|
|
680
|
+
agent: this,
|
|
681
|
+
result: result,
|
|
682
|
+
invocationState,
|
|
683
|
+
}));
|
|
684
|
+
return result;
|
|
535
685
|
}
|
|
536
686
|
}
|
|
537
687
|
finally {
|
|
538
688
|
this._isInvoking = false;
|
|
539
689
|
}
|
|
540
690
|
}
|
|
691
|
+
/**
|
|
692
|
+
* Invokes the AgentStreamStage middleware chain.
|
|
693
|
+
* Hooks fire outside this method (in stream()'s resume loop).
|
|
694
|
+
*/
|
|
695
|
+
async *_streamWithMiddleware(args, options, invocationState) {
|
|
696
|
+
const context = {
|
|
697
|
+
agent: this,
|
|
698
|
+
args,
|
|
699
|
+
...(options !== undefined && { options }),
|
|
700
|
+
interrupt: createMiddlewareInterrupt(this._interruptState, 'middleware:agentStream'),
|
|
701
|
+
};
|
|
702
|
+
// async function* doesn't bind lexical `this`; capture for the terminal callback.
|
|
703
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
704
|
+
const self = this;
|
|
705
|
+
try {
|
|
706
|
+
const { result } = yield* this._middlewareRegistry.invoke(AgentStreamStage, context, async function* (ctx) {
|
|
707
|
+
const result = yield* self._streamCore(ctx.args, ctx.options);
|
|
708
|
+
return { result };
|
|
709
|
+
});
|
|
710
|
+
return result;
|
|
711
|
+
}
|
|
712
|
+
catch (error) {
|
|
713
|
+
if (error instanceof InterruptError) {
|
|
714
|
+
for (const interrupt of error.interrupts) {
|
|
715
|
+
this._interruptState.registerInterrupt(interrupt);
|
|
716
|
+
}
|
|
717
|
+
this._interruptState.activate();
|
|
718
|
+
for (const interrupt of error.interrupts) {
|
|
719
|
+
yield new InterruptEvent({ agent: this, interrupt, invocationState });
|
|
720
|
+
}
|
|
721
|
+
return new AgentResult({
|
|
722
|
+
stopReason: 'interrupt',
|
|
723
|
+
lastMessage: this.messages.length > 0
|
|
724
|
+
? this.messages[this.messages.length - 1]
|
|
725
|
+
: new Message({ role: 'assistant', content: [new TextBlock('Interrupted')] }),
|
|
726
|
+
traces: this._tracer.localTraces,
|
|
727
|
+
metrics: this._meter.metrics,
|
|
728
|
+
interrupts: this._interruptState.getUnansweredInterrupts(),
|
|
729
|
+
invocationState,
|
|
730
|
+
});
|
|
731
|
+
}
|
|
732
|
+
throw error;
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
/**
|
|
736
|
+
* Single-pass stream through _stream() with event processing.
|
|
737
|
+
* No resume loop, no lifecycle events — those are handled by stream()'s resume loop.
|
|
738
|
+
*/
|
|
739
|
+
async *_streamCore(args, options) {
|
|
740
|
+
const streamGenerator = this._stream(args, options);
|
|
741
|
+
let caughtError;
|
|
742
|
+
let iterationResult;
|
|
743
|
+
try {
|
|
744
|
+
iterationResult = await streamGenerator.next();
|
|
745
|
+
while (!iterationResult.done) {
|
|
746
|
+
try {
|
|
747
|
+
const processed = await this._invokeCallbacks(iterationResult.value);
|
|
748
|
+
yield processed;
|
|
749
|
+
iterationResult = await streamGenerator.next();
|
|
750
|
+
}
|
|
751
|
+
catch (error) {
|
|
752
|
+
// Throw interrupt errors back into _stream so executeTools can store the
|
|
753
|
+
// assistant message as pending execution state for resume.
|
|
754
|
+
if (error instanceof InterruptError) {
|
|
755
|
+
iterationResult = await streamGenerator.throw(error);
|
|
756
|
+
}
|
|
757
|
+
else {
|
|
758
|
+
throw error;
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
catch (error) {
|
|
764
|
+
caughtError = error;
|
|
765
|
+
throw error;
|
|
766
|
+
}
|
|
767
|
+
finally {
|
|
768
|
+
// Drain _stream() so cleanup hooks and printer still fire.
|
|
769
|
+
// Yield only on error (consumer may still be iterating); on a consumer
|
|
770
|
+
// break, yielding would suspend the generator and leak the lock.
|
|
771
|
+
let drainResult = await streamGenerator.return(undefined);
|
|
772
|
+
while (!drainResult.done) {
|
|
773
|
+
try {
|
|
774
|
+
if (caughtError) {
|
|
775
|
+
yield await this._invokeCallbacks(drainResult.value);
|
|
776
|
+
}
|
|
777
|
+
else {
|
|
778
|
+
await this._invokeCallbacks(drainResult.value);
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
catch (error) {
|
|
782
|
+
logger.warn(`event_type=<${drainResult.value.type}>, error=<${error}> | error invoking callbacks during cleanup`);
|
|
783
|
+
}
|
|
784
|
+
drainResult = await streamGenerator.next();
|
|
785
|
+
}
|
|
786
|
+
// Reset controller and signal for next iteration / invocation
|
|
787
|
+
this._abortController = new AbortController();
|
|
788
|
+
this._abortSignal = this._abortController.signal;
|
|
789
|
+
}
|
|
790
|
+
return iterationResult.value;
|
|
791
|
+
}
|
|
541
792
|
/**
|
|
542
793
|
* Returns a {@link Tool} that wraps this agent, allowing it to be used
|
|
543
794
|
* as a tool by another agent.
|
|
@@ -661,30 +912,14 @@ export class Agent {
|
|
|
661
912
|
// AgentResult. Mutations by hooks/tools are visible across all recursive
|
|
662
913
|
// agent loop cycles within this invocation.
|
|
663
914
|
const invocationState = options?.invocationState ?? {};
|
|
664
|
-
//
|
|
915
|
+
// Interrupt responses are already consumed in stream() before middleware
|
|
916
|
+
// runs (so middleware-level interrupt() can find them). Re-extract here
|
|
917
|
+
// to gate the "non-interrupt input while interrupted" check below.
|
|
665
918
|
const interruptResponses = this._extractInterruptResponses(args);
|
|
666
|
-
if (interruptResponses.length > 0) {
|
|
667
|
-
this._interruptState.resume(interruptResponses);
|
|
668
|
-
}
|
|
669
919
|
// Reject non-interrupt input while in interrupted state
|
|
670
920
|
if (this._interruptState.activated && interruptResponses.length === 0) {
|
|
671
921
|
throw new TypeError('Agent is in an interrupted state. Resume by invoking with interruptResponse content blocks.');
|
|
672
922
|
}
|
|
673
|
-
const beforeInvocationEvent = new BeforeInvocationEvent({ agent: this, invocationState });
|
|
674
|
-
yield beforeInvocationEvent;
|
|
675
|
-
if (beforeInvocationEvent.cancel) {
|
|
676
|
-
const cancelText = typeof beforeInvocationEvent.cancel === 'string' ? beforeInvocationEvent.cancel : 'invocation denied by hook';
|
|
677
|
-
const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
|
|
678
|
-
yield this._appendMessage(message, invocationState);
|
|
679
|
-
yield new AfterInvocationEvent({ agent: this, invocationState });
|
|
680
|
-
return new AgentResult({
|
|
681
|
-
stopReason: 'endTurn',
|
|
682
|
-
lastMessage: message,
|
|
683
|
-
traces: this._tracer.localTraces,
|
|
684
|
-
metrics: this._meter.metrics,
|
|
685
|
-
invocationState,
|
|
686
|
-
});
|
|
687
|
-
}
|
|
688
923
|
// Normalize input to get the user messages for telemetry
|
|
689
924
|
const inputMessages = this._normalizeInput(args);
|
|
690
925
|
// Start agent trace span
|
|
@@ -884,6 +1119,11 @@ export class Agent {
|
|
|
884
1119
|
return result;
|
|
885
1120
|
}
|
|
886
1121
|
if (error instanceof InterruptError) {
|
|
1122
|
+
// Handles interrupts from tools/hooks that propagated up through the agent loop.
|
|
1123
|
+
// AgentStreamStage middleware interrupts are caught separately in _streamWithMiddleware().
|
|
1124
|
+
for (const interrupt of error.interrupts) {
|
|
1125
|
+
this._interruptState.registerInterrupt(interrupt);
|
|
1126
|
+
}
|
|
887
1127
|
// Fan out one event per interrupt. Each event exposes `interrupt.source` so
|
|
888
1128
|
// consumers can filter by origin (tool callback vs hook callback) without
|
|
889
1129
|
// subscribing to separate event types.
|
|
@@ -917,8 +1157,6 @@ export class Agent {
|
|
|
917
1157
|
if (structuredOutputTool) {
|
|
918
1158
|
this._toolRegistry.remove(STRUCTURED_OUTPUT_TOOL_NAME);
|
|
919
1159
|
}
|
|
920
|
-
// Always emit final event
|
|
921
|
-
yield new AfterInvocationEvent({ agent: this, invocationState });
|
|
922
1160
|
}
|
|
923
1161
|
}
|
|
924
1162
|
/**
|
|
@@ -1095,26 +1333,10 @@ export class Agent {
|
|
|
1095
1333
|
}
|
|
1096
1334
|
return { message, stopReason: 'endTurn' };
|
|
1097
1335
|
}
|
|
1098
|
-
// Start model span within loop span context
|
|
1099
|
-
const modelId = this.model.modelId;
|
|
1100
|
-
const modelSpan = this._tracer.startModelInvokeSpan({
|
|
1101
|
-
messages: this.messages,
|
|
1102
|
-
...(modelId && { modelId }),
|
|
1103
|
-
...(this.systemPrompt !== undefined && { systemPrompt: this.systemPrompt }),
|
|
1104
|
-
});
|
|
1105
1336
|
try {
|
|
1106
|
-
const result = yield* this.
|
|
1337
|
+
const result = yield* this._invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens);
|
|
1107
1338
|
// Accumulate token usage and model latency metrics
|
|
1108
1339
|
this._meter.updateCycle(result.metadata);
|
|
1109
|
-
// End model span with usage
|
|
1110
|
-
const usage = result.metadata?.usage;
|
|
1111
|
-
const metrics = result.metadata?.metrics;
|
|
1112
|
-
this._tracer.endModelInvokeSpan(modelSpan, {
|
|
1113
|
-
output: result.message,
|
|
1114
|
-
stopReason: result.stopReason,
|
|
1115
|
-
...(usage && { usage }),
|
|
1116
|
-
...(metrics && { metrics }),
|
|
1117
|
-
});
|
|
1118
1340
|
yield new ModelMessageEvent({
|
|
1119
1341
|
agent: this,
|
|
1120
1342
|
message: result.message,
|
|
@@ -1146,8 +1368,6 @@ export class Agent {
|
|
|
1146
1368
|
}
|
|
1147
1369
|
catch (error) {
|
|
1148
1370
|
const modelError = normalizeError(error);
|
|
1149
|
-
// End model span with error
|
|
1150
|
-
this._tracer.endModelInvokeSpan(modelSpan, { error: modelError });
|
|
1151
1371
|
// Create error event
|
|
1152
1372
|
const errorEvent = new AfterModelCallEvent({
|
|
1153
1373
|
agent: this,
|
|
@@ -1173,6 +1393,80 @@ export class Agent {
|
|
|
1173
1393
|
}
|
|
1174
1394
|
}
|
|
1175
1395
|
}
|
|
1396
|
+
/**
|
|
1397
|
+
* Invokes the model through the InvokeModelStage middleware chain.
|
|
1398
|
+
* Builds an InvokeModelContext from current agent state and composes the
|
|
1399
|
+
* middleware chain with a terminal function that calls _streamFromModel
|
|
1400
|
+
* using context fields directly (not re-derived from the agent).
|
|
1401
|
+
*
|
|
1402
|
+
* @param invocationState - Per-invocation state shared across hooks and tools
|
|
1403
|
+
* @param toolChoice - Optional tool choice to force specific tool usage
|
|
1404
|
+
* @returns StreamAggregatedResult from the model (or middleware short-circuit)
|
|
1405
|
+
*/
|
|
1406
|
+
async *_invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens) {
|
|
1407
|
+
const context = {
|
|
1408
|
+
agent: this,
|
|
1409
|
+
messages: this.messages.map((msg) => msg.clone()),
|
|
1410
|
+
...(this.systemPrompt !== undefined && { systemPrompt: cloneSystemPrompt(this.systemPrompt) }),
|
|
1411
|
+
toolSpecs: deepCopy(this._toolRegistry.list().map((tool) => tool.toolSpec)),
|
|
1412
|
+
...(toolChoice !== undefined && { toolChoice: deepCopy(toolChoice) }),
|
|
1413
|
+
invocationState,
|
|
1414
|
+
...(projectedInputTokens !== undefined && { projectedInputTokens }),
|
|
1415
|
+
};
|
|
1416
|
+
// Snapshot model state before middleware runs so concurrent mutations don't leak in.
|
|
1417
|
+
// The writeback happens after the entire middleware chain completes, so middleware
|
|
1418
|
+
// cannot affect modelState at any point (before or after next()).
|
|
1419
|
+
const modelStateSnapshot = this.modelState.getAll();
|
|
1420
|
+
let tempModelState;
|
|
1421
|
+
// async function* doesn't bind lexical `this`; capture for the terminal callback.
|
|
1422
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1423
|
+
const self = this;
|
|
1424
|
+
const middlewareResult = yield* this._middlewareRegistry.invoke(InvokeModelStage, context, async function* (ctx) {
|
|
1425
|
+
const modelId = self.model.modelId;
|
|
1426
|
+
const modelSpan = self._tracer.startModelInvokeSpan({
|
|
1427
|
+
messages: ctx.messages,
|
|
1428
|
+
...(modelId && { modelId }),
|
|
1429
|
+
...(ctx.systemPrompt !== undefined && { systemPrompt: ctx.systemPrompt }),
|
|
1430
|
+
});
|
|
1431
|
+
try {
|
|
1432
|
+
// Wrap the snapshot into a StateStore for the model provider, which expects
|
|
1433
|
+
// get/set methods.
|
|
1434
|
+
tempModelState = new StateStore(modelStateSnapshot);
|
|
1435
|
+
const streamOptions = {
|
|
1436
|
+
toolSpecs: ctx.toolSpecs,
|
|
1437
|
+
modelState: tempModelState,
|
|
1438
|
+
...(ctx.systemPrompt !== undefined && { systemPrompt: ctx.systemPrompt }),
|
|
1439
|
+
...(ctx.toolChoice && { toolChoice: ctx.toolChoice }),
|
|
1440
|
+
};
|
|
1441
|
+
const gen = self._streamFromModel(ctx.messages, streamOptions, ctx.invocationState);
|
|
1442
|
+
let iterResult = await gen.next();
|
|
1443
|
+
while (!iterResult.done) {
|
|
1444
|
+
yield iterResult.value;
|
|
1445
|
+
iterResult = await gen.next();
|
|
1446
|
+
}
|
|
1447
|
+
const usage = iterResult.value.metadata?.usage;
|
|
1448
|
+
const metrics = iterResult.value.metadata?.metrics;
|
|
1449
|
+
self._tracer.endModelInvokeSpan(modelSpan, {
|
|
1450
|
+
output: iterResult.value.message,
|
|
1451
|
+
stopReason: iterResult.value.stopReason,
|
|
1452
|
+
...(usage && { usage }),
|
|
1453
|
+
...(metrics && { metrics }),
|
|
1454
|
+
});
|
|
1455
|
+
return { result: iterResult.value };
|
|
1456
|
+
}
|
|
1457
|
+
catch (error) {
|
|
1458
|
+
self._tracer.endModelInvokeSpan(modelSpan, { error: normalizeError(error) });
|
|
1459
|
+
throw error;
|
|
1460
|
+
}
|
|
1461
|
+
});
|
|
1462
|
+
// Sync model state after the entire middleware chain has completed, so no
|
|
1463
|
+
// middleware mutation to agent.modelState (before or after next()) takes effect.
|
|
1464
|
+
// Intentionally skipped on error — partial provider writes should not persist.
|
|
1465
|
+
if (tempModelState) {
|
|
1466
|
+
loadStateSerializable(this.modelState, serializeStateSerializable(tempModelState));
|
|
1467
|
+
}
|
|
1468
|
+
return middlewareResult.result;
|
|
1469
|
+
}
|
|
1176
1470
|
/**
|
|
1177
1471
|
* Streams events from the model and dispatches appropriate events for each.
|
|
1178
1472
|
*
|
|
@@ -1529,86 +1823,9 @@ export class Agent {
|
|
|
1529
1823
|
}
|
|
1530
1824
|
return afterToolCallEvent.result;
|
|
1531
1825
|
}
|
|
1532
|
-
//
|
|
1533
|
-
const
|
|
1534
|
-
|
|
1535
|
-
});
|
|
1536
|
-
// Track tool execution time for metrics
|
|
1537
|
-
const toolStartTime = Date.now();
|
|
1538
|
-
let toolResult;
|
|
1539
|
-
let error;
|
|
1540
|
-
if (!effectiveTool) {
|
|
1541
|
-
// Tool not found
|
|
1542
|
-
toolResult = new ToolResultBlock({
|
|
1543
|
-
toolUseId: toolUse.toolUseId,
|
|
1544
|
-
status: 'error',
|
|
1545
|
-
content: [new TextBlock(`Tool '${toolUse.name}' not found in registry`)],
|
|
1546
|
-
});
|
|
1547
|
-
}
|
|
1548
|
-
else {
|
|
1549
|
-
// Execute tool within the tool span context
|
|
1550
|
-
const toolContext = {
|
|
1551
|
-
toolUse: {
|
|
1552
|
-
name: toolUse.name,
|
|
1553
|
-
toolUseId: toolUse.toolUseId,
|
|
1554
|
-
input: toolUse.input,
|
|
1555
|
-
},
|
|
1556
|
-
agent: this,
|
|
1557
|
-
invocationState,
|
|
1558
|
-
interrupt: (params) => {
|
|
1559
|
-
return interruptFromAgent(this, `tool:${toolUseBlock.toolUseId}:${params.name}`, params, 'tool');
|
|
1560
|
-
},
|
|
1561
|
-
};
|
|
1562
|
-
try {
|
|
1563
|
-
// Manually iterate tool stream to wrap each ToolStreamEvent in ToolStreamUpdateEvent.
|
|
1564
|
-
// This keeps the tool authoring interface unchanged — tools construct ToolStreamEvent
|
|
1565
|
-
// without knowledge of agents or hooks, and we wrap at the boundary.
|
|
1566
|
-
// Tool execution is ran within the tool span's context so that
|
|
1567
|
-
// downstream calls (e.g., MCP clients) can propagate trace context
|
|
1568
|
-
const toolGenerator = this._tracer.withSpanContext(toolSpan, () => effectiveTool.stream(toolContext));
|
|
1569
|
-
let toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
|
|
1570
|
-
while (!toolNext.done) {
|
|
1571
|
-
yield new ToolStreamUpdateEvent({ agent: this, event: toolNext.value, invocationState });
|
|
1572
|
-
toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
|
|
1573
|
-
}
|
|
1574
|
-
const result = toolNext.value;
|
|
1575
|
-
if (!result) {
|
|
1576
|
-
// Tool didn't return a result
|
|
1577
|
-
toolResult = new ToolResultBlock({
|
|
1578
|
-
toolUseId: toolUse.toolUseId,
|
|
1579
|
-
status: 'error',
|
|
1580
|
-
content: [new TextBlock(`Tool '${toolUse.name}' did not return a result`)],
|
|
1581
|
-
});
|
|
1582
|
-
}
|
|
1583
|
-
else {
|
|
1584
|
-
toolResult = result;
|
|
1585
|
-
error = result.error;
|
|
1586
|
-
}
|
|
1587
|
-
}
|
|
1588
|
-
catch (e) {
|
|
1589
|
-
// Re-throw InterruptError to allow interrupt handling
|
|
1590
|
-
if (e instanceof InterruptError) {
|
|
1591
|
-
throw e;
|
|
1592
|
-
}
|
|
1593
|
-
// Tool execution failed with error
|
|
1594
|
-
error = normalizeError(e);
|
|
1595
|
-
toolResult = new ToolResultBlock({
|
|
1596
|
-
toolUseId: toolUse.toolUseId,
|
|
1597
|
-
status: 'error',
|
|
1598
|
-
content: [new TextBlock(error.message)],
|
|
1599
|
-
error,
|
|
1600
|
-
});
|
|
1601
|
-
}
|
|
1602
|
-
}
|
|
1603
|
-
// End tool span with the raw tool result — telemetry reflects what the
|
|
1604
|
-
// tool actually returned, independent of AfterToolCallEvent mutations.
|
|
1605
|
-
this._tracer.endToolCallSpan(toolSpan, { toolResult, ...(error && { error }) });
|
|
1606
|
-
// End tool metrics tracking
|
|
1607
|
-
this._meter.endToolCall({
|
|
1608
|
-
tool: toolUse,
|
|
1609
|
-
duration: Date.now() - toolStartTime,
|
|
1610
|
-
success: toolResult.status === 'success',
|
|
1611
|
-
});
|
|
1826
|
+
// Execute tool core logic through middleware chain
|
|
1827
|
+
const toolResult = yield* this._executeToolWithMiddleware(effectiveTool, toolUse, invocationState);
|
|
1828
|
+
const error = toolResult.error;
|
|
1612
1829
|
// Single point for AfterToolCallEvent
|
|
1613
1830
|
const afterToolCallEvent = new AfterToolCallEvent({
|
|
1614
1831
|
agent: this,
|
|
@@ -1627,6 +1844,106 @@ export class Agent {
|
|
|
1627
1844
|
return afterToolCallEvent.result;
|
|
1628
1845
|
}
|
|
1629
1846
|
}
|
|
1847
|
+
async *_executeToolWithMiddleware(tool, toolUse, invocationState) {
|
|
1848
|
+
const context = {
|
|
1849
|
+
agent: this,
|
|
1850
|
+
tool,
|
|
1851
|
+
toolUse: deepCopy(toolUse),
|
|
1852
|
+
invocationState,
|
|
1853
|
+
interrupt: createMiddlewareInterrupt(this._interruptState, `middleware:executeTool:${toolUse.toolUseId}`),
|
|
1854
|
+
};
|
|
1855
|
+
// async function* doesn't bind lexical `this`; capture for the terminal callback.
|
|
1856
|
+
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1857
|
+
const self = this;
|
|
1858
|
+
const middlewareResult = yield* this._middlewareRegistry.invoke(ExecuteToolStage, context, async function* (ctx) {
|
|
1859
|
+
const result = yield* self._executeToolCore(ctx.tool, ctx.toolUse, ctx.invocationState);
|
|
1860
|
+
return { result };
|
|
1861
|
+
});
|
|
1862
|
+
return middlewareResult.result;
|
|
1863
|
+
}
|
|
1864
|
+
async *_executeToolCore(effectiveTool, toolUse, invocationState) {
|
|
1865
|
+
// Start tool span within loop span context
|
|
1866
|
+
const toolSpan = this._tracer.startToolCallSpan({
|
|
1867
|
+
tool: toolUse,
|
|
1868
|
+
});
|
|
1869
|
+
// Track tool execution time for metrics
|
|
1870
|
+
const toolStartTime = Date.now();
|
|
1871
|
+
let toolResult;
|
|
1872
|
+
let error;
|
|
1873
|
+
if (!effectiveTool) {
|
|
1874
|
+
// Tool not found
|
|
1875
|
+
toolResult = new ToolResultBlock({
|
|
1876
|
+
toolUseId: toolUse.toolUseId,
|
|
1877
|
+
status: 'error',
|
|
1878
|
+
content: [new TextBlock(`Tool '${toolUse.name}' not found in registry`)],
|
|
1879
|
+
});
|
|
1880
|
+
}
|
|
1881
|
+
else {
|
|
1882
|
+
// Execute tool within the tool span context
|
|
1883
|
+
const toolContext = {
|
|
1884
|
+
toolUse: {
|
|
1885
|
+
name: toolUse.name,
|
|
1886
|
+
toolUseId: toolUse.toolUseId,
|
|
1887
|
+
input: toolUse.input,
|
|
1888
|
+
},
|
|
1889
|
+
agent: this,
|
|
1890
|
+
invocationState,
|
|
1891
|
+
interrupt: (params) => {
|
|
1892
|
+
return interruptFromAgent(this, `tool:${toolUse.toolUseId}:${params.name}`, params, 'tool');
|
|
1893
|
+
},
|
|
1894
|
+
};
|
|
1895
|
+
try {
|
|
1896
|
+
// Manually iterate tool stream to wrap each ToolStreamEvent in ToolStreamUpdateEvent.
|
|
1897
|
+
// This keeps the tool authoring interface unchanged — tools construct ToolStreamEvent
|
|
1898
|
+
// without knowledge of agents or hooks, and we wrap at the boundary.
|
|
1899
|
+
// Tool execution is ran within the tool span's context so that
|
|
1900
|
+
// downstream calls (e.g., MCP clients) can propagate trace context
|
|
1901
|
+
const toolGenerator = this._tracer.withSpanContext(toolSpan, () => effectiveTool.stream(toolContext));
|
|
1902
|
+
let toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
|
|
1903
|
+
while (!toolNext.done) {
|
|
1904
|
+
yield new ToolStreamUpdateEvent({ agent: this, event: toolNext.value, invocationState });
|
|
1905
|
+
toolNext = await this._tracer.withSpanContext(toolSpan, () => toolGenerator.next());
|
|
1906
|
+
}
|
|
1907
|
+
const result = toolNext.value;
|
|
1908
|
+
if (!result) {
|
|
1909
|
+
// Tool didn't return a result
|
|
1910
|
+
toolResult = new ToolResultBlock({
|
|
1911
|
+
toolUseId: toolUse.toolUseId,
|
|
1912
|
+
status: 'error',
|
|
1913
|
+
content: [new TextBlock(`Tool '${toolUse.name}' did not return a result`)],
|
|
1914
|
+
});
|
|
1915
|
+
}
|
|
1916
|
+
else {
|
|
1917
|
+
toolResult = result;
|
|
1918
|
+
error = result.error;
|
|
1919
|
+
}
|
|
1920
|
+
}
|
|
1921
|
+
catch (e) {
|
|
1922
|
+
// Re-throw InterruptError to allow interrupt handling
|
|
1923
|
+
if (e instanceof InterruptError) {
|
|
1924
|
+
throw e;
|
|
1925
|
+
}
|
|
1926
|
+
// Tool execution failed with error
|
|
1927
|
+
error = normalizeError(e);
|
|
1928
|
+
toolResult = new ToolResultBlock({
|
|
1929
|
+
toolUseId: toolUse.toolUseId,
|
|
1930
|
+
status: 'error',
|
|
1931
|
+
content: [new TextBlock(error.message)],
|
|
1932
|
+
error,
|
|
1933
|
+
});
|
|
1934
|
+
}
|
|
1935
|
+
}
|
|
1936
|
+
// End tool span with the raw tool result — telemetry reflects what the
|
|
1937
|
+
// tool actually returned, independent of AfterToolCallEvent mutations.
|
|
1938
|
+
this._tracer.endToolCallSpan(toolSpan, { toolResult, ...(error && { error }) });
|
|
1939
|
+
// End tool metrics tracking
|
|
1940
|
+
this._meter.endToolCall({
|
|
1941
|
+
tool: toolUse,
|
|
1942
|
+
duration: Date.now() - toolStartTime,
|
|
1943
|
+
success: toolResult.status === 'success',
|
|
1944
|
+
});
|
|
1945
|
+
return toolResult;
|
|
1946
|
+
}
|
|
1630
1947
|
/**
|
|
1631
1948
|
* Redacts the last message in the conversation history.
|
|
1632
1949
|
* Called when guardrails block user input and redaction is enabled.
|