@strands-agents/sdk 1.13.0 → 1.15.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/dist/src/agent/agent-as-tool.d.ts.map +1 -1
- package/dist/src/agent/agent-as-tool.js +8 -2
- package/dist/src/agent/agent-as-tool.js.map +1 -1
- package/dist/src/agent/agent-delegation.d.ts +9 -30
- package/dist/src/agent/agent-delegation.d.ts.map +1 -1
- package/dist/src/agent/agent-delegation.js +26 -98
- package/dist/src/agent/agent-delegation.js.map +1 -1
- package/dist/src/agent/agent.d.ts +49 -15
- package/dist/src/agent/agent.d.ts.map +1 -1
- package/dist/src/agent/agent.js +193 -60
- package/dist/src/agent/agent.js.map +1 -1
- package/dist/src/agent/continuation.d.ts +77 -0
- package/dist/src/agent/continuation.d.ts.map +1 -0
- package/dist/src/agent/continuation.js +167 -0
- package/dist/src/agent/continuation.js.map +1 -0
- package/dist/src/agent/tool-caller.d.ts.map +1 -1
- package/dist/src/agent/tool-caller.js +1 -0
- package/dist/src/agent/tool-caller.js.map +1 -1
- package/dist/src/background-tasks/errors.d.ts +8 -0
- package/dist/src/background-tasks/errors.d.ts.map +1 -0
- package/dist/src/background-tasks/errors.js +11 -0
- package/dist/src/background-tasks/errors.js.map +1 -0
- package/dist/src/background-tasks/in-process/engine.d.ts +96 -0
- package/dist/src/background-tasks/in-process/engine.d.ts.map +1 -0
- package/dist/src/background-tasks/in-process/engine.js +322 -0
- package/dist/src/background-tasks/in-process/engine.js.map +1 -0
- package/dist/src/background-tasks/in-process/types.d.ts +76 -0
- package/dist/src/background-tasks/in-process/types.d.ts.map +1 -0
- package/dist/src/background-tasks/in-process/types.js +2 -0
- package/dist/src/background-tasks/in-process/types.js.map +1 -0
- package/dist/src/context-manager/context-manager.d.ts +30 -0
- package/dist/src/context-manager/context-manager.d.ts.map +1 -0
- package/dist/src/context-manager/context-manager.js +89 -0
- package/dist/src/context-manager/context-manager.js.map +1 -0
- package/dist/src/context-manager/methods/summarize.d.ts +41 -0
- package/dist/src/context-manager/methods/summarize.d.ts.map +1 -0
- package/dist/src/context-manager/methods/summarize.js +108 -0
- package/dist/src/context-manager/methods/summarize.js.map +1 -0
- package/dist/src/context-manager/methods/truncate.d.ts +36 -0
- package/dist/src/context-manager/methods/truncate.d.ts.map +1 -0
- package/dist/src/context-manager/methods/truncate.js +86 -0
- package/dist/src/context-manager/methods/truncate.js.map +1 -0
- package/dist/src/context-manager/modes/agentic/agentic-context.d.ts +1 -2
- package/dist/src/context-manager/modes/agentic/agentic-context.d.ts.map +1 -1
- package/dist/src/context-manager/modes/agentic/agentic-context.js +6 -3
- package/dist/src/context-manager/modes/agentic/agentic-context.js.map +1 -1
- package/dist/src/context-manager/strategies/offload/base.d.ts +140 -0
- package/dist/src/context-manager/strategies/offload/base.d.ts.map +1 -0
- package/dist/src/context-manager/strategies/offload/base.js +376 -0
- package/dist/src/context-manager/strategies/offload/base.js.map +1 -0
- package/dist/src/context-manager/strategies/offload/drop.d.ts +19 -0
- package/dist/src/context-manager/strategies/offload/drop.d.ts.map +1 -0
- package/dist/src/context-manager/strategies/offload/drop.js +31 -0
- package/dist/src/context-manager/strategies/offload/drop.js.map +1 -0
- package/dist/src/context-manager/strategies/offload/index.d.ts +43 -0
- package/dist/src/context-manager/strategies/offload/index.d.ts.map +1 -0
- package/dist/src/context-manager/strategies/offload/index.js +37 -0
- package/dist/src/context-manager/strategies/offload/index.js.map +1 -0
- package/dist/src/context-manager/strategies/offload/summarize.d.ts +22 -0
- package/dist/src/context-manager/strategies/offload/summarize.d.ts.map +1 -0
- package/dist/src/context-manager/strategies/offload/summarize.js +104 -0
- package/dist/src/context-manager/strategies/offload/summarize.js.map +1 -0
- package/dist/src/context-manager/strategies/offload/truncate.d.ts +21 -0
- package/dist/src/context-manager/strategies/offload/truncate.d.ts.map +1 -0
- package/dist/src/context-manager/strategies/offload/truncate.js +66 -0
- package/dist/src/context-manager/strategies/offload/truncate.js.map +1 -0
- package/dist/src/context-manager/types.d.ts +50 -0
- package/dist/src/context-manager/types.d.ts.map +1 -0
- package/dist/src/context-manager/types.js +5 -0
- package/dist/src/context-manager/types.js.map +1 -0
- package/dist/src/hooks/events.d.ts +6 -5
- package/dist/src/hooks/events.d.ts.map +1 -1
- package/dist/src/hooks/events.js +5 -4
- package/dist/src/hooks/events.js.map +1 -1
- package/dist/src/hooks/types.d.ts +1 -0
- package/dist/src/hooks/types.d.ts.map +1 -1
- package/dist/src/hooks/types.js +1 -0
- package/dist/src/hooks/types.js.map +1 -1
- package/dist/src/index.d.ts +4 -2
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +3 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/injection/message-injection.d.ts +12 -9
- package/dist/src/injection/message-injection.d.ts.map +1 -1
- package/dist/src/injection/message-injection.js +17 -16
- package/dist/src/injection/message-injection.js.map +1 -1
- package/dist/src/mcp/client.d.ts.map +1 -1
- package/dist/src/mcp/client.js +9 -0
- package/dist/src/mcp/client.js.map +1 -1
- package/dist/src/middleware/stages.d.ts +15 -2
- package/dist/src/middleware/stages.d.ts.map +1 -1
- package/dist/src/middleware/stages.js.map +1 -1
- package/dist/src/mime.d.ts +1 -0
- package/dist/src/mime.d.ts.map +1 -1
- package/dist/src/mime.js.map +1 -1
- package/dist/src/models/anthropic.d.ts +26 -1
- package/dist/src/models/anthropic.d.ts.map +1 -1
- package/dist/src/models/anthropic.js +178 -54
- package/dist/src/models/anthropic.js.map +1 -1
- package/dist/src/models/bedrock.d.ts +36 -17
- package/dist/src/models/bedrock.d.ts.map +1 -1
- package/dist/src/models/bedrock.js +166 -34
- package/dist/src/models/bedrock.js.map +1 -1
- package/dist/src/models/google/adapters.d.ts.map +1 -1
- package/dist/src/models/google/adapters.js +18 -4
- package/dist/src/models/google/adapters.js.map +1 -1
- package/dist/src/models/google/model.d.ts.map +1 -1
- package/dist/src/models/google/model.js +9 -7
- package/dist/src/models/google/model.js.map +1 -1
- package/dist/src/models/google/types.d.ts +2 -0
- package/dist/src/models/google/types.d.ts.map +1 -1
- package/dist/src/models/model.d.ts +72 -5
- package/dist/src/models/model.d.ts.map +1 -1
- package/dist/src/models/model.js +15 -0
- package/dist/src/models/model.js.map +1 -1
- package/dist/src/models/openai/cache.d.ts +31 -0
- package/dist/src/models/openai/cache.d.ts.map +1 -0
- package/dist/src/models/openai/cache.js +56 -0
- package/dist/src/models/openai/cache.js.map +1 -0
- package/dist/src/models/openai/chat-adapter.d.ts.map +1 -1
- package/dist/src/models/openai/chat-adapter.js +2 -0
- package/dist/src/models/openai/chat-adapter.js.map +1 -1
- package/dist/src/models/openai/model.d.ts.map +1 -1
- package/dist/src/models/openai/model.js +14 -3
- package/dist/src/models/openai/model.js.map +1 -1
- package/dist/src/models/openai/responses-adapter.d.ts.map +1 -1
- package/dist/src/models/openai/responses-adapter.js +3 -1
- package/dist/src/models/openai/responses-adapter.js.map +1 -1
- package/dist/src/models/openai/types.d.ts +5 -1
- package/dist/src/models/openai/types.d.ts.map +1 -1
- package/dist/src/models/routing/fallback-strategy.d.ts +13 -0
- package/dist/src/models/routing/fallback-strategy.d.ts.map +1 -0
- package/dist/src/models/routing/fallback-strategy.js +33 -0
- package/dist/src/models/routing/fallback-strategy.js.map +1 -0
- package/dist/src/models/routing/index.d.ts +11 -0
- package/dist/src/models/routing/index.d.ts.map +1 -0
- package/dist/src/models/routing/index.js +9 -0
- package/dist/src/models/routing/index.js.map +1 -0
- package/dist/src/models/routing/router.d.ts +161 -0
- package/dist/src/models/routing/router.d.ts.map +1 -0
- package/dist/src/models/routing/router.js +474 -0
- package/dist/src/models/routing/router.js.map +1 -0
- package/dist/src/models/routing/strategy.d.ts +53 -0
- package/dist/src/models/routing/strategy.d.ts.map +1 -0
- package/dist/src/models/routing/strategy.js +2 -0
- package/dist/src/models/routing/strategy.js.map +1 -0
- package/dist/src/models/streaming.d.ts +12 -0
- package/dist/src/models/streaming.d.ts.map +1 -1
- package/dist/src/models/streaming.js +17 -0
- package/dist/src/models/streaming.js.map +1 -1
- package/dist/src/multiagent/plugins.d.ts +3 -1
- package/dist/src/multiagent/plugins.d.ts.map +1 -1
- package/dist/src/multiagent/plugins.js +6 -1
- package/dist/src/multiagent/plugins.js.map +1 -1
- package/dist/src/plugins/registry.d.ts +3 -1
- package/dist/src/plugins/registry.d.ts.map +1 -1
- package/dist/src/plugins/registry.js +6 -1
- package/dist/src/plugins/registry.js.map +1 -1
- package/dist/src/retry/default-model-retry-strategy.d.ts +3 -8
- package/dist/src/retry/default-model-retry-strategy.d.ts.map +1 -1
- package/dist/src/retry/default-model-retry-strategy.js +3 -8
- package/dist/src/retry/default-model-retry-strategy.js.map +1 -1
- package/dist/src/retry/model-retry-strategy.d.ts +6 -9
- package/dist/src/retry/model-retry-strategy.d.ts.map +1 -1
- package/dist/src/retry/model-retry-strategy.js +8 -12
- package/dist/src/retry/model-retry-strategy.js.map +1 -1
- package/dist/src/session/session-manager.d.ts +4 -0
- package/dist/src/session/session-manager.d.ts.map +1 -1
- package/dist/src/session/session-manager.js +6 -0
- package/dist/src/session/session-manager.js.map +1 -1
- package/dist/src/storage/in-memory-storage.d.ts +8 -1
- package/dist/src/storage/in-memory-storage.d.ts.map +1 -1
- package/dist/src/storage/in-memory-storage.js +10 -0
- package/dist/src/storage/in-memory-storage.js.map +1 -1
- package/dist/src/storage/local-file-storage.d.ts +8 -1
- package/dist/src/storage/local-file-storage.d.ts.map +1 -1
- package/dist/src/storage/local-file-storage.js +10 -0
- package/dist/src/storage/local-file-storage.js.map +1 -1
- package/dist/src/storage/s3-storage.d.ts +8 -1
- package/dist/src/storage/s3-storage.d.ts.map +1 -1
- package/dist/src/storage/s3-storage.js +10 -0
- package/dist/src/storage/s3-storage.js.map +1 -1
- package/dist/src/storage/search/index.d.ts +13 -0
- package/dist/src/storage/search/index.d.ts.map +1 -0
- package/dist/src/storage/search/index.js +11 -0
- package/dist/src/storage/search/index.js.map +1 -0
- package/dist/src/storage/search/keyword.d.ts +23 -0
- package/dist/src/storage/search/keyword.d.ts.map +1 -0
- package/dist/src/storage/search/keyword.js +53 -0
- package/dist/src/storage/search/keyword.js.map +1 -0
- package/dist/src/storage/search/types.d.ts +24 -0
- package/dist/src/storage/search/types.d.ts.map +1 -0
- package/dist/src/storage/search/types.js +2 -0
- package/dist/src/storage/search/types.js.map +1 -0
- package/dist/src/storage/storage.d.ts +46 -1
- package/dist/src/storage/storage.d.ts.map +1 -1
- package/dist/src/storage/storage.js +22 -0
- package/dist/src/storage/storage.js.map +1 -1
- package/dist/src/telemetry/meter.d.ts +8 -6
- package/dist/src/telemetry/meter.d.ts.map +1 -1
- package/dist/src/telemetry/meter.js +8 -7
- package/dist/src/telemetry/meter.js.map +1 -1
- package/dist/src/telemetry/tracer.d.ts.map +1 -1
- package/dist/src/telemetry/tracer.js +9 -2
- package/dist/src/telemetry/tracer.js.map +1 -1
- package/dist/src/tools/executors/executor.d.ts +2 -0
- package/dist/src/tools/executors/executor.d.ts.map +1 -1
- package/dist/src/tools/executors/executor.js +6 -4
- package/dist/src/tools/executors/executor.js.map +1 -1
- package/dist/src/tools/executors/sequential.d.ts +1 -1
- package/dist/src/tools/executors/sequential.js +2 -2
- package/dist/src/tools/executors/sequential.js.map +1 -1
- package/dist/src/tools/mcp-tool.d.ts +2 -1
- package/dist/src/tools/mcp-tool.d.ts.map +1 -1
- package/dist/src/tools/mcp-tool.js +2 -1
- package/dist/src/tools/mcp-tool.js.map +1 -1
- package/dist/src/tools/tool.d.ts +2 -0
- package/dist/src/tools/tool.d.ts.map +1 -1
- package/dist/src/tools/tool.js.map +1 -1
- package/dist/src/tools/types.d.ts +8 -0
- package/dist/src/tools/types.d.ts.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/types/agent.d.ts +14 -4
- package/dist/src/types/agent.d.ts.map +1 -1
- package/dist/src/types/agent.js +3 -2
- package/dist/src/types/agent.js.map +1 -1
- package/dist/src/types/media.d.ts +65 -3
- package/dist/src/types/media.d.ts.map +1 -1
- package/dist/src/types/media.js +68 -1
- package/dist/src/types/media.js.map +1 -1
- package/dist/src/types/messages.d.ts +6 -4
- package/dist/src/types/messages.d.ts.map +1 -1
- package/dist/src/types/messages.js +4 -1
- package/dist/src/types/messages.js.map +1 -1
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts +11 -0
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.d.ts.map +1 -1
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js +53 -3
- package/dist/src/vended-memory-stores/bedrock-knowledge-base/store.js.map +1 -1
- package/dist/src/vended-memory-stores/file-memory-store/index.d.ts +3 -0
- package/dist/src/vended-memory-stores/file-memory-store/index.d.ts.map +1 -0
- package/dist/src/vended-memory-stores/file-memory-store/index.js +2 -0
- package/dist/src/vended-memory-stores/file-memory-store/index.js.map +1 -0
- package/dist/src/vended-memory-stores/file-memory-store/store.d.ts +104 -0
- package/dist/src/vended-memory-stores/file-memory-store/store.d.ts.map +1 -0
- package/dist/src/vended-memory-stores/file-memory-store/store.js +237 -0
- package/dist/src/vended-memory-stores/file-memory-store/store.js.map +1 -0
- package/dist/src/vended-memory-stores/test-memory-store/store.d.ts.map +1 -1
- package/dist/src/vended-memory-stores/test-memory-store/store.js +2 -25
- package/dist/src/vended-memory-stores/test-memory-store/store.js.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.d.ts.map +1 -1
- package/dist/src/vended-plugins/context-offloader/plugin.js +2 -8
- package/dist/src/vended-plugins/context-offloader/plugin.js.map +1 -1
- package/dist/src/vended-tools/http-request/http-request.d.ts +1 -1
- package/dist/src/vended-tools/http-request/http-request.js +2 -2
- package/dist/src/vended-tools/http-request/http-request.js.map +1 -1
- package/dist/src/vended-tools/sleep/make-sleep.d.ts +4 -6
- package/dist/src/vended-tools/sleep/make-sleep.d.ts.map +1 -1
- package/dist/src/vended-tools/sleep/make-sleep.js +5 -7
- package/dist/src/vended-tools/sleep/make-sleep.js.map +1 -1
- package/package.json +16 -4
package/dist/src/agent/agent.js
CHANGED
|
@@ -7,8 +7,9 @@ import { isValidToolName } from '../tools/tool.js';
|
|
|
7
7
|
import { cloneSystemPrompt, systemPromptFromData } from '../types/messages.js';
|
|
8
8
|
import { normalizeError, ConcurrentInvocationError, StructuredOutputError } from '../errors.js';
|
|
9
9
|
import { Model } from '../models/model.js';
|
|
10
|
+
import { ModelRouter } from '../models/routing/router.js';
|
|
10
11
|
import { ModelPlugin } from '../plugins/model-plugin.js';
|
|
11
|
-
import { isModelStreamEvent } from '../models/streaming.js';
|
|
12
|
+
import { totalPromptTokens, isModelStreamEvent } from '../models/streaming.js';
|
|
12
13
|
import { ToolRegistry } from '../registry/tool-registry.js';
|
|
13
14
|
import { StateStore } from '../state-store.js';
|
|
14
15
|
import { serializeStateSerializable, loadStateSerializable } from '../types/serializable.js';
|
|
@@ -30,6 +31,7 @@ import { ConcurrentToolExecutor } from '../tools/executors/concurrent.js';
|
|
|
30
31
|
import { SequentialToolExecutor } from '../tools/executors/sequential.js';
|
|
31
32
|
import { AgentAsTool } from './agent-as-tool.js';
|
|
32
33
|
import { ToolCaller } from './tool-caller.js';
|
|
34
|
+
import { continuations } from './continuation.js';
|
|
33
35
|
import { MemoryManager } from '../memory/memory-manager.js';
|
|
34
36
|
import { SessionManager } from '../session/session-manager.js';
|
|
35
37
|
import { Tracer } from '../telemetry/tracer.js';
|
|
@@ -44,8 +46,9 @@ import { isInterruptResponseContent } from '../types/interrupt.js';
|
|
|
44
46
|
import { takeSnapshot as takeSnapshotInternal, loadSnapshot as loadSnapshotInternal } from './snapshot.js';
|
|
45
47
|
import { defaultSandbox } from '../sandbox/default.js';
|
|
46
48
|
import { summarizeContextTool, truncateContextTool, pinContextTool, createTokenUsageMiddleware, } from '../context-manager/modes/agentic/agentic-context.js';
|
|
49
|
+
import { ContextManager } from '../context-manager/context-manager.js';
|
|
47
50
|
/**
|
|
48
|
-
* Supported
|
|
51
|
+
* Supported string presets for the `contextManager` parameter.
|
|
49
52
|
*/
|
|
50
53
|
export const CONTEXT_MANAGER_STRATEGIES = ['auto', 'agentic'];
|
|
51
54
|
/** Benchmark-validated token threshold for offloading tool results. */
|
|
@@ -65,8 +68,16 @@ const CONTEXT_MANAGER_COMPRESSION_THRESHOLD = 0.85;
|
|
|
65
68
|
* When "auto", uses SummarizingConversationManager with proactive compression.
|
|
66
69
|
* When "agentic", uses SummarizingConversationManager without proactive compression
|
|
67
70
|
* (the agent manages its context via tools; the context manager is only a reactive safety net).
|
|
71
|
+
* When a ContextManager instance, uses NullConversationManager — the ContextManager owns
|
|
72
|
+
* overflow recovery via apply().
|
|
68
73
|
*/
|
|
69
74
|
function resolveConversationManager(contextManager, conversationManager) {
|
|
75
|
+
if (contextManager === false) {
|
|
76
|
+
return conversationManager ?? new NullConversationManager();
|
|
77
|
+
}
|
|
78
|
+
if (contextManager instanceof ContextManager) {
|
|
79
|
+
return new NullConversationManager();
|
|
80
|
+
}
|
|
70
81
|
if (contextManager === 'agentic') {
|
|
71
82
|
return (conversationManager ??
|
|
72
83
|
new SummarizingConversationManager({
|
|
@@ -132,6 +143,7 @@ export class Agent {
|
|
|
132
143
|
* The model provider used by the agent for inference.
|
|
133
144
|
*/
|
|
134
145
|
model;
|
|
146
|
+
_modelRouter;
|
|
135
147
|
/**
|
|
136
148
|
* The system prompt to pass to the model provider.
|
|
137
149
|
*/
|
|
@@ -148,10 +160,15 @@ export class Agent {
|
|
|
148
160
|
* Optional description of what the agent does.
|
|
149
161
|
*/
|
|
150
162
|
description;
|
|
163
|
+
/**
|
|
164
|
+
* The context manager for strategy-driven offloading, if configured.
|
|
165
|
+
*/
|
|
166
|
+
contextManager;
|
|
151
167
|
/**
|
|
152
168
|
* The session manager for saving and restoring agent sessions, if configured.
|
|
153
169
|
*/
|
|
154
170
|
sessionManager;
|
|
171
|
+
_sessionId;
|
|
155
172
|
/**
|
|
156
173
|
* The memory manager for cross-session memory retrieval and storage, if configured.
|
|
157
174
|
*/
|
|
@@ -170,6 +187,20 @@ export class Agent {
|
|
|
170
187
|
get sandbox() {
|
|
171
188
|
return this._sandbox || defaultSandbox.get();
|
|
172
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* A stable, unique identifier for the current conversation session.
|
|
192
|
+
*
|
|
193
|
+
* If a SessionManager is attached, delegates to its sessionId.
|
|
194
|
+
* Otherwise, lazily generates and caches a random 8-character hex string.
|
|
195
|
+
*/
|
|
196
|
+
get sessionId() {
|
|
197
|
+
if (this.sessionManager)
|
|
198
|
+
return this.sessionManager.sessionId;
|
|
199
|
+
if (!this._sessionId) {
|
|
200
|
+
this._sessionId = globalThis.crypto.randomUUID().slice(0, 8);
|
|
201
|
+
}
|
|
202
|
+
return this._sessionId;
|
|
203
|
+
}
|
|
173
204
|
_hooksRegistry;
|
|
174
205
|
_middlewareRegistry;
|
|
175
206
|
_pluginRegistry;
|
|
@@ -207,6 +238,7 @@ export class Agent {
|
|
|
207
238
|
this.id = config?.id ?? DEFAULT_AGENT_ID;
|
|
208
239
|
if (config?.description !== undefined)
|
|
209
240
|
this.description = config.description;
|
|
241
|
+
this.contextManager = config?.contextManager instanceof ContextManager ? config.contextManager : undefined;
|
|
210
242
|
this.sessionManager = config?.sessionManager;
|
|
211
243
|
this.storage = config?.storage;
|
|
212
244
|
this.memoryManager =
|
|
@@ -216,11 +248,19 @@ export class Agent {
|
|
|
216
248
|
? new MemoryManager(config.memoryManager)
|
|
217
249
|
: undefined;
|
|
218
250
|
this._sandbox = config?.sandbox;
|
|
219
|
-
|
|
220
|
-
|
|
251
|
+
const configuredModel = config?.model;
|
|
252
|
+
if (typeof configuredModel === 'string') {
|
|
253
|
+
this.model = new BedrockModel({ modelId: configuredModel });
|
|
254
|
+
}
|
|
255
|
+
else if (configuredModel instanceof ModelRouter) {
|
|
256
|
+
this._modelRouter = configuredModel;
|
|
257
|
+
this.model = configuredModel.defaultModel;
|
|
221
258
|
}
|
|
222
259
|
else {
|
|
223
|
-
this.model =
|
|
260
|
+
this.model = configuredModel ?? new BedrockModel();
|
|
261
|
+
}
|
|
262
|
+
if (config?.plugins?.some((plugin) => plugin instanceof ModelRouter)) {
|
|
263
|
+
throw new Error('ModelRouter must be passed through Agent({ model }), not plugins');
|
|
224
264
|
}
|
|
225
265
|
// Validate and assign conversation manager
|
|
226
266
|
if (this.model.stateful) {
|
|
@@ -243,8 +283,9 @@ export class Agent {
|
|
|
243
283
|
this._interventionRegistry = new InterventionRegistry(config?.interventions ?? [], this._hooksRegistry);
|
|
244
284
|
// Initialize middleware registry
|
|
245
285
|
this._middlewareRegistry = new MiddlewareRegistry();
|
|
286
|
+
this._modelRouter?.attachToAgent(this);
|
|
246
287
|
if (config?.contextManager === 'agentic') {
|
|
247
|
-
this._middlewareRegistry.addInput(InvokeModelStage.Input, createTokenUsageMiddleware(
|
|
288
|
+
this._middlewareRegistry.addInput(InvokeModelStage.Input, createTokenUsageMiddleware());
|
|
248
289
|
}
|
|
249
290
|
// `undefined` (omitted) → install the default; `null`/`[]` → explicit opt-out.
|
|
250
291
|
const retryStrategies = config?.retryStrategy === null
|
|
@@ -268,7 +309,9 @@ export class Agent {
|
|
|
268
309
|
// when a delegate tool is added (construction, plugin getTools, MCP, runtime).
|
|
269
310
|
// The plugin is a no-op when no delegation tools fire.
|
|
270
311
|
const hasAgentDelegation = (config?.plugins ?? []).some((p) => p.name === 'strands:agent-delegation');
|
|
312
|
+
const contextManagerPlugin = config?.contextManager instanceof ContextManager ? config.contextManager : undefined;
|
|
271
313
|
this._pluginRegistry = new PluginRegistry([
|
|
314
|
+
...(this._modelRouter ? [this._modelRouter] : []),
|
|
272
315
|
this._conversationManager,
|
|
273
316
|
...retryStrategies,
|
|
274
317
|
...(config?.plugins ?? []),
|
|
@@ -284,6 +327,7 @@ export class Agent {
|
|
|
284
327
|
]
|
|
285
328
|
: []),
|
|
286
329
|
...(this.memoryManager ? [this.memoryManager] : []),
|
|
330
|
+
...(contextManagerPlugin ? [contextManagerPlugin] : []),
|
|
287
331
|
...(config?.sessionManager ? [config.sessionManager] : []),
|
|
288
332
|
new ModelPlugin(this.model),
|
|
289
333
|
]);
|
|
@@ -533,7 +577,7 @@ export class Agent {
|
|
|
533
577
|
/**
|
|
534
578
|
* The cancellation signal for the current invocation.
|
|
535
579
|
*
|
|
536
|
-
*
|
|
580
|
+
* SDK-managed tool contexts receive this as `context.cancelSignal` for cancellable operations.
|
|
537
581
|
* Hooks can check `event.agent.cancelSignal.aborted` to detect cancellation.
|
|
538
582
|
*/
|
|
539
583
|
get cancelSignal() {
|
|
@@ -549,7 +593,7 @@ export class Agent {
|
|
|
549
593
|
* - At the top of each agent loop cycle
|
|
550
594
|
*
|
|
551
595
|
* If a tool is already executing, it will run to completion unless
|
|
552
|
-
* the tool checks
|
|
596
|
+
* the tool checks `context.cancelSignal` internally.
|
|
553
597
|
*
|
|
554
598
|
* Hook callbacks can check `event.agent.cancelSignal.aborted` to detect
|
|
555
599
|
* cancellation and adjust their behavior accordingly.
|
|
@@ -637,6 +681,7 @@ export class Agent {
|
|
|
637
681
|
*/
|
|
638
682
|
async *stream(args, options) {
|
|
639
683
|
this.acquireLock();
|
|
684
|
+
let continuationEvent;
|
|
640
685
|
try {
|
|
641
686
|
await this.initialize();
|
|
642
687
|
// Thread the resolved invocationState so all layers share the same reference.
|
|
@@ -664,6 +709,8 @@ export class Agent {
|
|
|
664
709
|
const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
|
|
665
710
|
yield this._appendMessage(message, invocationState);
|
|
666
711
|
const afterEvent = new AfterInvocationEvent({ agent: this, invocationState });
|
|
712
|
+
await continuations.abandon(continuationEvent, new Error('Continuation was not incorporated into agent history'));
|
|
713
|
+
continuationEvent = afterEvent;
|
|
667
714
|
await this._invokeCallbacks(afterEvent);
|
|
668
715
|
yield afterEvent;
|
|
669
716
|
return new AgentResult({
|
|
@@ -678,7 +725,7 @@ export class Agent {
|
|
|
678
725
|
let caughtError;
|
|
679
726
|
const afterInvocationEvent = new AfterInvocationEvent({ agent: this, invocationState });
|
|
680
727
|
try {
|
|
681
|
-
result = yield* this._streamWithMiddleware(currentArgs, resolvedOptions, invocationState);
|
|
728
|
+
result = yield* this._streamWithMiddleware(currentArgs, resolvedOptions, invocationState, continuationEvent);
|
|
682
729
|
}
|
|
683
730
|
catch (error) {
|
|
684
731
|
caughtError = error;
|
|
@@ -687,6 +734,8 @@ export class Agent {
|
|
|
687
734
|
// AfterInvocationEvent always fires — even on error or consumer break. Outside middleware.
|
|
688
735
|
// Invoke hooks (so .resume can be set) but don't yield in finally (yields in finally
|
|
689
736
|
// suspend the generator on consumer break instead of completing cleanup).
|
|
737
|
+
await continuations.abandon(continuationEvent, new Error('Continuation was not incorporated into agent history'));
|
|
738
|
+
continuationEvent = afterInvocationEvent;
|
|
690
739
|
await this._invokeCallbacks(afterInvocationEvent);
|
|
691
740
|
}
|
|
692
741
|
// Yield outside finally — in JS, a `yield` inside `finally` suspends the generator
|
|
@@ -697,9 +746,15 @@ export class Agent {
|
|
|
697
746
|
if (caughtError) {
|
|
698
747
|
throw caughtError;
|
|
699
748
|
}
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
749
|
+
const stopReason = result.stopReason;
|
|
750
|
+
const allowsContinuation = stopReason === 'endTurn' || stopReason === 'stopSequence';
|
|
751
|
+
if (!allowsContinuation && stopReason !== 'interrupt') {
|
|
752
|
+
await continuations.abandon(afterInvocationEvent, new Error(`Continuation abandoned after ${stopReason}`));
|
|
753
|
+
}
|
|
754
|
+
const hasContinuation = (await continuations.prepare(afterInvocationEvent, (continuationArgs) => this._normalizeInput(continuationArgs), stopReason)) !== undefined;
|
|
755
|
+
continuationEvent = hasContinuation ? afterInvocationEvent : undefined;
|
|
756
|
+
if (hasContinuation || afterInvocationEvent.resume !== undefined) {
|
|
757
|
+
currentArgs = afterInvocationEvent.resume ?? [];
|
|
703
758
|
continue;
|
|
704
759
|
}
|
|
705
760
|
// Only emit AgentResultEvent on the final iteration (not on resumed ones).
|
|
@@ -712,6 +767,7 @@ export class Agent {
|
|
|
712
767
|
}
|
|
713
768
|
}
|
|
714
769
|
finally {
|
|
770
|
+
await continuations.abandon(continuationEvent, new Error('Agent stream closed before continuation input was incorporated into agent history'));
|
|
715
771
|
this._isInvoking = false;
|
|
716
772
|
}
|
|
717
773
|
}
|
|
@@ -719,7 +775,7 @@ export class Agent {
|
|
|
719
775
|
* Invokes the AgentStreamStage middleware chain.
|
|
720
776
|
* Hooks fire outside this method (in stream()'s resume loop).
|
|
721
777
|
*/
|
|
722
|
-
async *_streamWithMiddleware(args, options, invocationState) {
|
|
778
|
+
async *_streamWithMiddleware(args, options, invocationState, continuationEvent) {
|
|
723
779
|
// Snapshot so a gate that re-reads its response after next() still resolves even if a tool cycle called deactivate().
|
|
724
780
|
const interruptsSnapshot = { ...this._interruptState.interrupts };
|
|
725
781
|
const context = {
|
|
@@ -733,7 +789,8 @@ export class Agent {
|
|
|
733
789
|
const self = this;
|
|
734
790
|
try {
|
|
735
791
|
const { result } = yield* this._middlewareRegistry.invoke(AgentStreamStage, context, async function* (ctx) {
|
|
736
|
-
const
|
|
792
|
+
const streamArgs = continuations.combine(continuationEvent, ctx.args, (continuationArgs) => self._normalizeInput(continuationArgs));
|
|
793
|
+
const result = yield* self._streamCore(streamArgs, ctx.options, streamArgs === ctx.args ? undefined : continuationEvent);
|
|
737
794
|
return { result };
|
|
738
795
|
});
|
|
739
796
|
if (this._interruptState.activated &&
|
|
@@ -770,8 +827,8 @@ export class Agent {
|
|
|
770
827
|
* Single-pass stream through _stream() with event processing.
|
|
771
828
|
* No resume loop, no lifecycle events — those are handled by stream()'s resume loop.
|
|
772
829
|
*/
|
|
773
|
-
async *_streamCore(args, options) {
|
|
774
|
-
const streamGenerator = this._stream(args, options);
|
|
830
|
+
async *_streamCore(args, options, continuationEvent) {
|
|
831
|
+
const streamGenerator = this._stream(args, options, continuationEvent);
|
|
775
832
|
let caughtError;
|
|
776
833
|
let iterationResult;
|
|
777
834
|
try {
|
|
@@ -933,7 +990,7 @@ export class Agent {
|
|
|
933
990
|
* @param options - Optional per-invocation options
|
|
934
991
|
* @returns Async generator that yields AgentStreamEvent objects and returns AgentResult
|
|
935
992
|
*/
|
|
936
|
-
async *_stream(args, options) {
|
|
993
|
+
async *_stream(args, options, continuationEvent) {
|
|
937
994
|
let currentArgs = args;
|
|
938
995
|
let result;
|
|
939
996
|
this._validateLimits(options);
|
|
@@ -1016,8 +1073,13 @@ export class Agent {
|
|
|
1016
1073
|
// Normalize input and append user messages on first invocation only
|
|
1017
1074
|
if (currentArgs !== undefined) {
|
|
1018
1075
|
const messagesToAppend = this._normalizeInput(currentArgs);
|
|
1019
|
-
|
|
1020
|
-
yield this.
|
|
1076
|
+
if (continuationEvent) {
|
|
1077
|
+
yield* await this._appendContinuationMessages(messagesToAppend, continuationEvent, invocationState);
|
|
1078
|
+
}
|
|
1079
|
+
else {
|
|
1080
|
+
for (const message of messagesToAppend) {
|
|
1081
|
+
yield this._appendMessage(message, invocationState);
|
|
1082
|
+
}
|
|
1021
1083
|
}
|
|
1022
1084
|
currentArgs = undefined;
|
|
1023
1085
|
}
|
|
@@ -1140,13 +1202,16 @@ export class Agent {
|
|
|
1140
1202
|
}
|
|
1141
1203
|
this._meter.endCycle(cycleStartTime);
|
|
1142
1204
|
this._tracer.endAgentLoopSpan(cycleSpan);
|
|
1143
|
-
// Hook requested halt: exit without calling the model again
|
|
1205
|
+
// Hook requested halt with content: exit without calling the model again.
|
|
1144
1206
|
const { afterToolsEvent } = toolsResult;
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1207
|
+
const endTurnValue = afterToolsEvent.endTurn;
|
|
1208
|
+
if (endTurnValue === true || (endTurnValue !== false && endTurnValue.length > 0)) {
|
|
1209
|
+
const endTurnContent = Array.isArray(endTurnValue)
|
|
1210
|
+
? [...endTurnValue]
|
|
1211
|
+
: [
|
|
1212
|
+
new TextBlock(typeof endTurnValue === 'string' ? endTurnValue : 'Turn ended early by hook after tool execution'),
|
|
1213
|
+
];
|
|
1214
|
+
const lastMessage = new Message({ role: 'assistant', content: endTurnContent });
|
|
1150
1215
|
yield this._appendMessage(lastMessage, invocationState);
|
|
1151
1216
|
result = new AgentResult({
|
|
1152
1217
|
stopReason: 'endTurn',
|
|
@@ -1203,7 +1268,9 @@ export class Agent {
|
|
|
1203
1268
|
role: 'assistant',
|
|
1204
1269
|
content: [new TextBlock('Cancelled by user')],
|
|
1205
1270
|
});
|
|
1206
|
-
|
|
1271
|
+
if (this._hasOpenUserTurn()) {
|
|
1272
|
+
yield this._appendMessage(cancelMessage, invocationState);
|
|
1273
|
+
}
|
|
1207
1274
|
result = new AgentResult({
|
|
1208
1275
|
stopReason: 'cancelled',
|
|
1209
1276
|
lastMessage: cancelMessage,
|
|
@@ -1233,14 +1300,16 @@ export class Agent {
|
|
|
1233
1300
|
}
|
|
1234
1301
|
finally {
|
|
1235
1302
|
// If cancelled but the catch block was bypassed (generator terminated
|
|
1236
|
-
// via .return() when the consumer breaks out of for-await),
|
|
1237
|
-
//
|
|
1303
|
+
// via .return() when the consumer breaks out of for-await), close an
|
|
1304
|
+
// existing user turn so the agent can be reinvoked.
|
|
1238
1305
|
if (!caughtError && !result && this.isCancelled) {
|
|
1239
1306
|
const cancelMessage = new Message({
|
|
1240
1307
|
role: 'assistant',
|
|
1241
1308
|
content: [new TextBlock('Cancelled by user')],
|
|
1242
1309
|
});
|
|
1243
|
-
|
|
1310
|
+
if (this._hasOpenUserTurn()) {
|
|
1311
|
+
yield this._appendMessage(cancelMessage, invocationState);
|
|
1312
|
+
}
|
|
1244
1313
|
}
|
|
1245
1314
|
this._tracer.endAgentSpan(agentSpan, {
|
|
1246
1315
|
...(caughtError && { error: caughtError }),
|
|
@@ -1412,48 +1481,70 @@ export class Agent {
|
|
|
1412
1481
|
if (this.systemPrompt !== undefined) {
|
|
1413
1482
|
streamOptions.systemPrompt = this.systemPrompt;
|
|
1414
1483
|
}
|
|
1415
|
-
// Add tool choice if provided
|
|
1416
1484
|
if (toolChoice) {
|
|
1417
1485
|
streamOptions.toolChoice = toolChoice;
|
|
1418
1486
|
}
|
|
1419
1487
|
let attemptCount = 1;
|
|
1420
1488
|
while (true) {
|
|
1421
|
-
|
|
1489
|
+
const selectedModel = this._modelForAttempt(invocationState);
|
|
1422
1490
|
let projectedInputTokens;
|
|
1423
1491
|
try {
|
|
1492
|
+
// Context management continues to size against the agent's default model.
|
|
1424
1493
|
projectedInputTokens = await this._estimateInputTokens(streamOptions);
|
|
1425
1494
|
}
|
|
1426
|
-
catch (
|
|
1427
|
-
logger.debug(`error=<${
|
|
1495
|
+
catch (error) {
|
|
1496
|
+
logger.debug(`error=<${error}> | token estimation failed, proceeding without estimate`);
|
|
1428
1497
|
}
|
|
1429
1498
|
const beforeModelCallEvent = new BeforeModelCallEvent({
|
|
1430
1499
|
agent: this,
|
|
1431
|
-
model:
|
|
1500
|
+
model: selectedModel,
|
|
1432
1501
|
invocationState,
|
|
1433
1502
|
...(projectedInputTokens !== undefined && { projectedInputTokens }),
|
|
1434
1503
|
});
|
|
1435
|
-
|
|
1504
|
+
let modelContinuation;
|
|
1505
|
+
try {
|
|
1506
|
+
yield beforeModelCallEvent;
|
|
1507
|
+
modelContinuation = await continuations.prepare(beforeModelCallEvent, (continuationArgs) => this._normalizeInput(continuationArgs));
|
|
1508
|
+
}
|
|
1509
|
+
finally {
|
|
1510
|
+
if (modelContinuation === undefined) {
|
|
1511
|
+
await continuations.abandon(beforeModelCallEvent, new Error('Agent stream closed before continuation input was incorporated into agent history'));
|
|
1512
|
+
}
|
|
1513
|
+
}
|
|
1436
1514
|
if (beforeModelCallEvent.cancel) {
|
|
1515
|
+
await continuations.abandon(beforeModelCallEvent, new Error('Continuation abandoned by BeforeModelCallEvent'));
|
|
1437
1516
|
const cancelText = typeof beforeModelCallEvent.cancel === 'string' ? beforeModelCallEvent.cancel : 'model call denied by hook';
|
|
1438
1517
|
const message = new Message({ role: 'assistant', content: [new TextBlock(cancelText)] });
|
|
1439
1518
|
const stopData = { message, stopReason: 'endTurn' };
|
|
1440
1519
|
const afterModelCallEvent = new AfterModelCallEvent({
|
|
1441
1520
|
agent: this,
|
|
1442
|
-
model:
|
|
1521
|
+
model: selectedModel,
|
|
1443
1522
|
attemptCount,
|
|
1444
1523
|
stopData,
|
|
1445
1524
|
invocationState,
|
|
1446
1525
|
});
|
|
1447
1526
|
yield afterModelCallEvent;
|
|
1448
1527
|
if (afterModelCallEvent.retry) {
|
|
1449
|
-
attemptCount
|
|
1528
|
+
attemptCount = this._nextAttemptCount(selectedModel, invocationState, attemptCount);
|
|
1450
1529
|
continue;
|
|
1451
1530
|
}
|
|
1452
1531
|
return { message, stopReason: 'endTurn' };
|
|
1453
1532
|
}
|
|
1533
|
+
yield* await this._appendContinuationMessages(modelContinuation ?? [], beforeModelCallEvent, invocationState);
|
|
1534
|
+
if (modelContinuation !== undefined) {
|
|
1535
|
+
try {
|
|
1536
|
+
projectedInputTokens = await this._estimateInputTokens(streamOptions);
|
|
1537
|
+
}
|
|
1538
|
+
catch (error) {
|
|
1539
|
+
projectedInputTokens = undefined;
|
|
1540
|
+
logger.debug(`error=<${error}> | token estimation failed after continuation input, proceeding without estimate`);
|
|
1541
|
+
}
|
|
1542
|
+
}
|
|
1543
|
+
const invokedModelRef = {};
|
|
1454
1544
|
try {
|
|
1455
|
-
const result = yield* this._invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens);
|
|
1456
|
-
|
|
1545
|
+
const result = yield* this._invokeModelWithMiddleware(invocationState, selectedModel, invokedModelRef, toolChoice, projectedInputTokens);
|
|
1546
|
+
const routedModel = this._modelRouter?.getRoutedModel(this, invocationState) ?? selectedModel;
|
|
1547
|
+
const model = invokedModelRef.model ?? selectedModel;
|
|
1457
1548
|
this._meter.updateCycle(result.metadata);
|
|
1458
1549
|
yield new ModelMessageEvent({
|
|
1459
1550
|
agent: this,
|
|
@@ -1461,7 +1552,6 @@ export class Agent {
|
|
|
1461
1552
|
stopReason: result.stopReason,
|
|
1462
1553
|
invocationState,
|
|
1463
1554
|
});
|
|
1464
|
-
// Handle user content redaction if guardrails blocked input
|
|
1465
1555
|
if (result.redaction?.userMessage) {
|
|
1466
1556
|
this._redactLastMessage(result.redaction.userMessage);
|
|
1467
1557
|
}
|
|
@@ -1472,45 +1562,50 @@ export class Agent {
|
|
|
1472
1562
|
};
|
|
1473
1563
|
const afterModelCallEvent = new AfterModelCallEvent({
|
|
1474
1564
|
agent: this,
|
|
1475
|
-
model
|
|
1565
|
+
model,
|
|
1476
1566
|
attemptCount,
|
|
1477
1567
|
stopData,
|
|
1478
1568
|
invocationState,
|
|
1479
1569
|
});
|
|
1480
1570
|
yield afterModelCallEvent;
|
|
1481
1571
|
if (afterModelCallEvent.retry) {
|
|
1482
|
-
attemptCount
|
|
1572
|
+
attemptCount = this._nextAttemptCount(routedModel, invocationState, attemptCount);
|
|
1483
1573
|
continue;
|
|
1484
1574
|
}
|
|
1485
1575
|
return result;
|
|
1486
1576
|
}
|
|
1487
1577
|
catch (error) {
|
|
1578
|
+
const routedModel = this._modelRouter?.getRoutedModel(this, invocationState) ?? selectedModel;
|
|
1579
|
+
// A failure before the terminal ran (e.g. in input middleware) is attributed to the routed model.
|
|
1580
|
+
const failedModel = invokedModelRef.model ?? routedModel;
|
|
1488
1581
|
const modelError = normalizeError(error);
|
|
1489
|
-
// Create error event
|
|
1490
1582
|
const errorEvent = new AfterModelCallEvent({
|
|
1491
1583
|
agent: this,
|
|
1492
|
-
model:
|
|
1584
|
+
model: failedModel,
|
|
1493
1585
|
attemptCount,
|
|
1494
1586
|
error: modelError,
|
|
1495
1587
|
invocationState,
|
|
1496
1588
|
});
|
|
1497
|
-
// Yield error event - stream will invoke hooks
|
|
1498
1589
|
yield errorEvent;
|
|
1499
|
-
//
|
|
1500
|
-
// (we emit the AfterModelCall because we already emitted Before and we guarentee the pair)
|
|
1590
|
+
// Preserve the Before/After event pair, but never retry cancellation.
|
|
1501
1591
|
if (error instanceof CancelledError) {
|
|
1502
1592
|
throw error;
|
|
1503
1593
|
}
|
|
1504
|
-
// After yielding, hooks have been invoked and may have set retry
|
|
1505
1594
|
if (errorEvent.retry) {
|
|
1506
|
-
attemptCount
|
|
1595
|
+
attemptCount = this._nextAttemptCount(routedModel, invocationState, attemptCount);
|
|
1507
1596
|
continue;
|
|
1508
1597
|
}
|
|
1509
|
-
// Re-throw error
|
|
1510
1598
|
throw error;
|
|
1511
1599
|
}
|
|
1512
1600
|
}
|
|
1513
1601
|
}
|
|
1602
|
+
_modelForAttempt(invocationState) {
|
|
1603
|
+
return this._modelRouter?.getRoutedModel(this, invocationState) ?? this.model;
|
|
1604
|
+
}
|
|
1605
|
+
_nextAttemptCount(model, invocationState, attemptCount) {
|
|
1606
|
+
const nextModel = this._modelRouter?.getRoutedModel(this, invocationState);
|
|
1607
|
+
return nextModel !== undefined && nextModel !== model ? 1 : attemptCount + 1;
|
|
1608
|
+
}
|
|
1514
1609
|
/**
|
|
1515
1610
|
* Invokes the model through the InvokeModelStage middleware chain.
|
|
1516
1611
|
* Builds an InvokeModelContext from current agent state and composes the
|
|
@@ -1518,12 +1613,15 @@ export class Agent {
|
|
|
1518
1613
|
* using context fields directly (not re-derived from the agent).
|
|
1519
1614
|
*
|
|
1520
1615
|
* @param invocationState - Per-invocation state shared across hooks and tools
|
|
1616
|
+
* @param selectedModel - Model the chain starts with; middleware may replace it
|
|
1617
|
+
* @param invokedModelRef - Slot filled with the model the terminal actually invoked
|
|
1521
1618
|
* @param toolChoice - Optional tool choice to force specific tool usage
|
|
1522
1619
|
* @returns StreamAggregatedResult from the model (or middleware short-circuit)
|
|
1523
1620
|
*/
|
|
1524
|
-
async *_invokeModelWithMiddleware(invocationState, toolChoice, projectedInputTokens) {
|
|
1621
|
+
async *_invokeModelWithMiddleware(invocationState, selectedModel, invokedModelRef, toolChoice, projectedInputTokens) {
|
|
1525
1622
|
const context = {
|
|
1526
1623
|
agent: this,
|
|
1624
|
+
model: selectedModel,
|
|
1527
1625
|
messages: this.messages.map((msg) => msg.clone()),
|
|
1528
1626
|
...(this.systemPrompt !== undefined && { systemPrompt: cloneSystemPrompt(this.systemPrompt) }),
|
|
1529
1627
|
toolSpecs: deepCopy(this._toolRegistry.list().map((tool) => tool.toolSpec)),
|
|
@@ -1540,7 +1638,8 @@ export class Agent {
|
|
|
1540
1638
|
// eslint-disable-next-line @typescript-eslint/no-this-alias
|
|
1541
1639
|
const self = this;
|
|
1542
1640
|
const middlewareResult = yield* this._middlewareRegistry.invoke(InvokeModelStage, context, async function* (ctx) {
|
|
1543
|
-
|
|
1641
|
+
invokedModelRef.model = ctx.model;
|
|
1642
|
+
const modelId = ctx.model.modelId;
|
|
1544
1643
|
const modelSpan = self._tracer.startModelInvokeSpan({
|
|
1545
1644
|
messages: ctx.messages,
|
|
1546
1645
|
...(modelId && { modelId }),
|
|
@@ -1556,8 +1655,10 @@ export class Agent {
|
|
|
1556
1655
|
modelState: tempModelState,
|
|
1557
1656
|
...(ctx.systemPrompt !== undefined && { systemPrompt: ctx.systemPrompt }),
|
|
1558
1657
|
...(ctx.toolChoice && { toolChoice: ctx.toolChoice }),
|
|
1658
|
+
// Omitted when zero, so an ordinary call's options are unchanged.
|
|
1659
|
+
...(ctx.dynamicTrailingBlocks ? { dynamicTrailingBlocks: ctx.dynamicTrailingBlocks } : {}),
|
|
1559
1660
|
};
|
|
1560
|
-
const gen = self._streamFromModel(ctx.messages, streamOptions, ctx.invocationState);
|
|
1661
|
+
const gen = self._streamFromModel(ctx.model, ctx.messages, streamOptions, ctx.invocationState);
|
|
1561
1662
|
let iterResult = await gen.next();
|
|
1562
1663
|
while (!iterResult.done) {
|
|
1563
1664
|
yield iterResult.value;
|
|
@@ -1598,13 +1699,14 @@ export class Agent {
|
|
|
1598
1699
|
* These are separate event classes because they represent different granularities
|
|
1599
1700
|
* (partial deltas vs finished blocks). Both are yielded in the stream and hookable.
|
|
1600
1701
|
*
|
|
1702
|
+
* @param model - Model selected for this call
|
|
1601
1703
|
* @param messages - Messages to send to the model
|
|
1602
1704
|
* @param streamOptions - Options for streaming
|
|
1603
1705
|
* @returns StreamAggregatedResult containing message, stop reason, and optional redaction message
|
|
1604
1706
|
*/
|
|
1605
|
-
async *_streamFromModel(messages, streamOptions, invocationState) {
|
|
1707
|
+
async *_streamFromModel(model, messages, streamOptions, invocationState) {
|
|
1606
1708
|
messages = normalizeToolUseNames(messages);
|
|
1607
|
-
const streamGenerator =
|
|
1709
|
+
const streamGenerator = model.streamAggregated(messages, streamOptions);
|
|
1608
1710
|
try {
|
|
1609
1711
|
let result = await streamGenerator.next();
|
|
1610
1712
|
while (!result.done) {
|
|
@@ -1685,6 +1787,7 @@ export class Agent {
|
|
|
1685
1787
|
middlewareRegistry: this._middlewareRegistry,
|
|
1686
1788
|
tracer: this._tracer,
|
|
1687
1789
|
meter: this._meter,
|
|
1790
|
+
cancelSignal: this._abortSignal,
|
|
1688
1791
|
}, {
|
|
1689
1792
|
toolUseBlocks,
|
|
1690
1793
|
toolResultBlocks,
|
|
@@ -1762,10 +1865,10 @@ export class Agent {
|
|
|
1762
1865
|
/**
|
|
1763
1866
|
* Estimate the input token count for the next model call.
|
|
1764
1867
|
*
|
|
1765
|
-
* Uses the token counting strategy: reads
|
|
1766
|
-
* from the last assistant message's metadata as a known baseline, then
|
|
1767
|
-
* only new messages added after it. Falls back to full estimation when no metadata
|
|
1768
|
-
*
|
|
1868
|
+
* Uses the token counting strategy: reads the total prompt the model processed (including cached
|
|
1869
|
+
* tokens) plus outputTokens from the last assistant message's metadata as a known baseline, then
|
|
1870
|
+
* estimates only new messages added after it. Falls back to full estimation when no metadata is
|
|
1871
|
+
* available (cold start or first call).
|
|
1769
1872
|
*
|
|
1770
1873
|
* @param streamOptions - The stream options containing system prompt and tool specs
|
|
1771
1874
|
* @returns Estimated input token count
|
|
@@ -1782,7 +1885,7 @@ export class Agent {
|
|
|
1782
1885
|
let estimate;
|
|
1783
1886
|
if (lastAssistantIdx >= 0) {
|
|
1784
1887
|
const usage = this.messages[lastAssistantIdx].metadata.usage;
|
|
1785
|
-
const knownBaseline = usage
|
|
1888
|
+
const knownBaseline = totalPromptTokens(usage) + usage.outputTokens;
|
|
1786
1889
|
const newMessages = this.messages.slice(lastAssistantIdx + 1);
|
|
1787
1890
|
if (newMessages.length === 0) {
|
|
1788
1891
|
estimate = knownBaseline;
|
|
@@ -1821,6 +1924,36 @@ export class Agent {
|
|
|
1821
1924
|
this.messages.push(message);
|
|
1822
1925
|
return new MessageAddedEvent({ agent: this, message, invocationState });
|
|
1823
1926
|
}
|
|
1927
|
+
async _appendContinuationMessages(messages, continuationEvent, invocationState) {
|
|
1928
|
+
const events = [];
|
|
1929
|
+
for (const message of messages) {
|
|
1930
|
+
const lastMessage = this.messages.at(-1);
|
|
1931
|
+
if (lastMessage?.role !== message.role) {
|
|
1932
|
+
events.push(this._appendMessage(message, invocationState));
|
|
1933
|
+
continue;
|
|
1934
|
+
}
|
|
1935
|
+
const appendedMessage = new Message({
|
|
1936
|
+
role: message.role,
|
|
1937
|
+
content: [...lastMessage.content, ...message.content],
|
|
1938
|
+
trackingId: lastMessage.trackingId,
|
|
1939
|
+
...(lastMessage.metadata !== undefined && { metadata: lastMessage.metadata }),
|
|
1940
|
+
});
|
|
1941
|
+
this.messages[this.messages.length - 1] = appendedMessage;
|
|
1942
|
+
const messageEvent = new MessageAddedEvent({ agent: this, message: appendedMessage, invocationState });
|
|
1943
|
+
if (events.at(-1)?.message === lastMessage) {
|
|
1944
|
+
events[events.length - 1] = messageEvent;
|
|
1945
|
+
}
|
|
1946
|
+
else {
|
|
1947
|
+
events.push(messageEvent);
|
|
1948
|
+
}
|
|
1949
|
+
}
|
|
1950
|
+
await continuations.markAppended(continuationEvent);
|
|
1951
|
+
return events;
|
|
1952
|
+
}
|
|
1953
|
+
_hasOpenUserTurn() {
|
|
1954
|
+
const lastMessage = this.messages[this.messages.length - 1];
|
|
1955
|
+
return lastMessage?.role === 'user';
|
|
1956
|
+
}
|
|
1824
1957
|
}
|
|
1825
1958
|
const INVALID_TOOL_NAME_PLACEHOLDER = 'INVALID_TOOL_NAME';
|
|
1826
1959
|
/**
|