@ag-ui/aws-strands 0.1.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,314 @@
1
+ # AWS Strands Integration for AG-UI (TypeScript)
2
+
3
+ This package exposes a lightweight wrapper that lets any `@strands-agents/sdk` `Agent` speak the AG-UI protocol. It mirrors the developer experience of the other integrations: give us a Strands agent instance, plug it into `StrandsAgent`, and wire it to Express via `createStrandsApp` (or `addStrandsExpressEndpoint`).
4
+
5
+ ## Prerequisites
6
+
7
+ - Node.js 18+
8
+ - `pnpm` (recommended) or `npm`
9
+ - A Strands-compatible model key (e.g., AWS credentials for Bedrock, `OPENAI_API_KEY` for OpenAI)
10
+
11
+ ## Quick Start
12
+
13
+ The `examples/` package ships a "dojo" server that mounts every demo on a
14
+ single port, plus seven standalone servers — one per feature — that you can
15
+ run independently.
16
+
17
+ ```bash
18
+ # from the repo root
19
+ pnpm install
20
+ pnpm --filter @ag-ui/aws-strands build
21
+
22
+ cd integrations/aws-strands/typescript/examples
23
+ pnpm dojo # all examples at http://localhost:8022
24
+ ```
25
+
26
+ Or run any single example on its own port (default `8000`):
27
+
28
+ ```bash
29
+ pnpm agentic-chat
30
+ pnpm agentic-chat-reasoning
31
+ pnpm agentic-chat-multimodal
32
+ pnpm backend-tool-rendering
33
+ pnpm shared-state
34
+ pnpm agentic-generative-ui
35
+ pnpm human-in-the-loop
36
+ ```
37
+
38
+ The dojo exposes:
39
+
40
+ | Route | Description |
41
+ | -------------------------- | ------------------------------------------------------------------------ |
42
+ | `/agentic-chat` | Baseline chat; frontend tools auto-registered from `RunAgentInput.tools` |
43
+ | `/agentic-chat-reasoning` | Reasoning / thinking event streaming |
44
+ | `/agentic-chat-multimodal` | Multimodal image / document analysis |
45
+ | `/backend-tool-rendering` | Backend-executed tools (`get_weather`, `render_chart`) |
46
+ | `/shared-state` | Shared recipe state (`stateFromArgs`) |
47
+ | `/agentic-generative-ui` | Async-generator tool streams `STATE_SNAPSHOT`s + `PredictState` |
48
+ | `/human-in-the-loop` | Frontend proxy tool with halt-after-call |
49
+
50
+ Each standalone file under `examples/server/api/*.ts` follows the same pattern: build a Strands `Agent`, wrap it in a `StrandsAgent`, hand it to `createStrandsApp`, listen.
51
+
52
+ ## Architecture Overview
53
+
54
+ The integration has three main layers:
55
+
56
+ - **StrandsAgent** – wraps `Agent.stream()` from `@strands-agents/sdk`. It translates Strands streaming events into AG-UI events (text chunks, tool calls, PredictState, snapshots, reasoning/thinking, multi-agent steps, etc.).
57
+ - **Configuration** – `StrandsAgentConfig` + `ToolBehavior` + `PredictStateMapping` let you describe tool-specific quirks declaratively (skip message snapshots, emit state, stream args, etc.).
58
+ - **Transport helpers** – `createStrandsApp` and `addStrandsExpressEndpoint` expose the agent via SSE. They are thin shells over the shared `@ag-ui/encoder` `EventEncoder`. Imported from `@ag-ui/aws-strands/server` — kept off the main entry so client-side bundlers (Next.js, Vite) don't pull Express into the browser graph.
59
+
60
+ See [../ARCHITECTURE.md](../ARCHITECTURE.md) for diagrams and a deeper dive.
61
+
62
+ ## Key Files
63
+
64
+ | File | Description |
65
+ | -------------------------- | ------------------------------------------------------------------------------- |
66
+ | `src/agent.ts` | Core wrapper translating Strands streams into AG-UI events |
67
+ | `src/config.ts` | Config primitives (`StrandsAgentConfig`, `ToolBehavior`, `PredictStateMapping`) |
68
+ | `src/server.ts` | `createStrandsApp` + Express transport (subpath: `@ag-ui/aws-strands/server`) |
69
+ | `src/endpoint.ts` | Express endpoint helpers (used by `server.ts`) |
70
+ | `src/utils.ts` | Multimodal content conversion |
71
+ | `src/client-proxy-tool.ts` | Dynamic frontend tool registration/deregistration |
72
+ | `examples/server/api/*.ts` | Ready-to-run demo apps |
73
+
74
+ ## Amazon Bedrock AgentCore Considerations
75
+
76
+ If you are planning to deploy your agent into Amazon Bedrock AgentCore (AC), please note that AC expects the following:
77
+
78
+ - The server is running on port 8080.
79
+ - The path `/invocations - POST` is implemented and can be used for interacting with the agent.
80
+ - The path `/ping - GET` is implemented and can be used for verifying that the agent is operational and ready to handle requests.
81
+
82
+ To implement the paths mentioned above, you can use the helper function `createStrandsApp` and pass the agent interaction path and the ping path as shown below:
83
+
84
+ ```ts
85
+ const app = await createStrandsApp(aguiAgent, {
86
+ path: "/invocations",
87
+ pingPath: "/ping",
88
+ });
89
+ app.listen(8080);
90
+ ```
91
+
92
+ You can also use the helper functions `addStrandsExpressEndpoint` and `addPing` for adding the mentioned paths to an Express app that you are creating separately:
93
+
94
+ ```ts
95
+ import express from "express";
96
+ import cors from "cors";
97
+ import { addStrandsExpressEndpoint, addPing } from "@ag-ui/aws-strands/server";
98
+
99
+ const app = express();
100
+ app.use(cors());
101
+ app.use(express.json({ limit: "50mb" }));
102
+ addStrandsExpressEndpoint(app, aguiAgent, { path: "/invocations" });
103
+ addPing(app, "/ping");
104
+ app.listen(8080);
105
+ ```
106
+
107
+ Requests to the AC endpoint must be authenticated. You can configure your agent runtime to accept JWT bearer tokens (via Amazon Cognito) or use SigV4. See [Set up authentication](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-agui.html) in the AgentCore documentation.
108
+
109
+ For details on how AgentCore handles AG-UI requests, event streaming, and error formatting, see the [AG-UI protocol contract](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-agui-protocol-contract.html).
110
+
111
+ To deploy, use the [AgentCore Starter Toolkit](https://github.com/awslabs/bedrock-agentcore-starter-toolkit):
112
+
113
+ ```bash
114
+ pip install bedrock-agentcore-starter-toolkit
115
+ agentcore configure -e my_agui_server.ts --protocol AGUI
116
+ agentcore deploy
117
+ ```
118
+
119
+ For the complete deployment walkthrough, see [Deploy AG-UI servers in AgentCore Runtime](https://docs.aws.amazon.com/bedrock-agentcore/latest/devguide/runtime-agui.html).
120
+
121
+ ## Supported AG-UI Events
122
+
123
+ The integration supports the following AG-UI event families:
124
+
125
+ - **Lifecycle**: `RUN_STARTED`, `RUN_FINISHED`, `RUN_ERROR`
126
+ - **Text streaming**: `TEXT_MESSAGE_START`, `TEXT_MESSAGE_CONTENT`, `TEXT_MESSAGE_END` (optionally collapsed into `TEXT_MESSAGE_CHUNK` via `StrandsAgentConfig.emitChunkEvents`)
127
+ - **Reasoning**: `REASONING_*` events for models with extended thinking (`REASONING_MESSAGE_CHUNK` when `emitChunkEvents` is on)
128
+ - **Tool calls**: `TOOL_CALL_START`, `TOOL_CALL_ARGS`, `TOOL_CALL_END`, `TOOL_CALL_RESULT` (or `TOOL_CALL_CHUNK` with `emitChunkEvents`)
129
+ - **State management**: `STATE_SNAPSHOT`
130
+ - **Multi-agent**: `STEP_STARTED`, `STEP_FINISHED`, and `MultiAgentHandoff` custom events
131
+ - **Generative UI**: `PredictState` custom events for optimistic UI updates
132
+ - **Multimodal**: Image, document, and video content in user messages (converted to Strands ContentBlock format)
133
+
134
+ The adapter advertises its full event / feature matrix at GET
135
+ `/capabilities` (enabled by default; override via `createStrandsApp({ capabilitiesPath, capabilities })` or mount manually with `addCapabilities(app, path, overrides)`).
136
+
137
+ ## Passing tools to the Agent
138
+
139
+ The adapter clones the template `Agent`'s `tools` array onto every per-thread
140
+ clone. That means whatever the Strands SDK has resolved into `agent.tools` at
141
+ construction time is what the model sees — including for `McpClient`
142
+ instances. If you pass an **unconnected** `McpClient` directly, its tools
143
+ won't be in the resolved list and the model can't call them.
144
+
145
+ Connect MCP clients first and spread the resolved tools into `tools`:
146
+
147
+ ```ts
148
+ import { Agent } from "@strands-agents/sdk";
149
+ import { McpClient } from "@strands-agents/sdk/mcp";
150
+
151
+ const spellbook = new McpClient({
152
+ /* transport config */
153
+ });
154
+ await spellbook.connect();
155
+ const mcpTools = await spellbook.listTools();
156
+
157
+ const agent = new Agent({
158
+ model: "anthropic.claude-sonnet-4-5-20250929-v1:0",
159
+ tools: [...mcpTools, myLocalTool],
160
+ });
161
+
162
+ const aguiAgent = new StrandsAgent({ agent });
163
+ ```
164
+
165
+ The adapter logs a warning at construction time if it spots an entry in
166
+ `tools` that looks like an unconnected client (has a `.connect()` method but
167
+ no `.name`).
168
+
169
+ ## Human-in-the-loop interrupts
170
+
171
+ Two complementary patterns are supported:
172
+
173
+ - **Frontend tools.** The `/human-in-the-loop` example declares
174
+ `generate_task_steps` on the frontend via `useHumanInTheLoop` — the adapter
175
+ auto-registers it as a proxy tool, halts the run after the proxy resolves,
176
+ and hands control back to the UI for approval.
177
+ - **Native Strands interrupts (SDK 1.1.0+).** Backend hooks and tools can call
178
+ `event.interrupt(...)` / `context.interrupt(...)` to raise a
179
+ `stopReason: 'interrupt'`. The adapter forwards the outstanding interrupts
180
+ on `RUN_FINISHED`:
181
+
182
+ ```json
183
+ {
184
+ "type": "RUN_FINISHED",
185
+ "outcome": {
186
+ "type": "interrupt",
187
+ "interrupts": [
188
+ { "id": "...", "reason": "...", "metadata": { "strandsName": "..." } }
189
+ ]
190
+ }
191
+ }
192
+ ```
193
+
194
+ The next `RunAgentInput` carries `resume[]` entries keyed by those `id`s.
195
+ The adapter converts each entry into a Strands `InterruptResponseContent`
196
+ (forwarding `payload` for `resolved` and `{ status: "cancelled" }` for
197
+ `cancelled`) and hands them straight to `agent.stream(...)`. Unknown
198
+ `interruptId`s still short-circuit with
199
+ `RUN_ERROR { code: "UNKNOWN_INTERRUPT" }` per
200
+ [interrupts.mdx rule 4](https://docs.ag-ui.com/concepts/interrupts).
201
+
202
+ ## Reasoning / extended thinking
203
+
204
+ The `/agentic-chat-reasoning` demo only emits `REASONING_*` events when the
205
+ underlying Strands model is configured with thinking / reasoning params. The
206
+ default `BedrockModel(...)` without `additional_request_fields` returns plain
207
+ text; for Claude extended thinking, configure the model like so:
208
+
209
+ ```ts
210
+ import { BedrockModel } from "@strands-agents/sdk/models/bedrock";
211
+
212
+ const model = new BedrockModel({
213
+ modelId: "global.anthropic.claude-sonnet-4-6",
214
+ additionalRequestFields: {
215
+ thinking: { type: "enabled", budget_tokens: 5000 },
216
+ },
217
+ });
218
+ ```
219
+
220
+ ## Install
221
+
222
+ ```bash
223
+ pnpm add @ag-ui/aws-strands @strands-agents/sdk @ag-ui/core @ag-ui/encoder
224
+ # Server-side helpers (createStrandsApp / addStrandsExpressEndpoint) require express + cors:
225
+ pnpm add express cors
226
+ pnpm add -D @types/express @types/cors
227
+ # @modelcontextprotocol/sdk is loaded unconditionally by @strands-agents/sdk
228
+ # — required at runtime even for agents that don't use MCP:
229
+ pnpm add @modelcontextprotocol/sdk
230
+ ```
231
+
232
+ ## Server: Expose a Strands Agent via AG-UI
233
+
234
+ ```ts
235
+ import { Agent } from "@strands-agents/sdk";
236
+ import { StrandsAgent } from "@ag-ui/aws-strands";
237
+ import { createStrandsApp } from "@ag-ui/aws-strands/server";
238
+
239
+ // `model` accepts either a Bedrock model ID string or a constructed
240
+ // Model instance (e.g. BedrockModel / AnthropicModel / OpenAIResponsesModel).
241
+ // Omitting it uses Strands' current Bedrock default.
242
+ const strandsAgent = new Agent({
243
+ systemPrompt: "You are a helpful assistant.",
244
+ tools: [],
245
+ });
246
+
247
+ const aguiAgent = new StrandsAgent({
248
+ agent: strandsAgent,
249
+ name: "MyAgent",
250
+ description: "A Strands agent exposed via AG-UI",
251
+ });
252
+
253
+ const app = await createStrandsApp(aguiAgent, { path: "/invocations" });
254
+ app.listen(8000);
255
+ ```
256
+
257
+ ## Configuration
258
+
259
+ ```ts
260
+ import {
261
+ StrandsAgent,
262
+ type StrandsAgentConfig,
263
+ type ToolBehavior,
264
+ } from "@ag-ui/aws-strands";
265
+
266
+ const config: StrandsAgentConfig = {
267
+ toolBehaviors: {
268
+ set_recipe: {
269
+ stateFromArgs: async (ctx) => ({ recipe: ctx.toolInput }),
270
+ predictState: [
271
+ { stateKey: "recipe", tool: "set_recipe", toolArgument: "data" },
272
+ ],
273
+ },
274
+ render_chart: {
275
+ stopStreamingAfterResult: true,
276
+ },
277
+ },
278
+ sessionManagerProvider: async (input) => {
279
+ // Optional: vend a SessionManager per-thread from your own state store.
280
+ return undefined;
281
+ },
282
+ stateContextBuilder: (input, prompt) => {
283
+ // Optional: decorate the outgoing prompt with any server-side state.
284
+ return prompt;
285
+ },
286
+ };
287
+
288
+ const agent = new StrandsAgent({ agent: strandsAgent, name: "x", config });
289
+ ```
290
+
291
+ ## Low-Level Transport
292
+
293
+ If you have an existing Express app, mount the endpoint directly instead of
294
+ using `createStrandsApp`:
295
+
296
+ ```ts
297
+ import express from "express";
298
+ import cors from "cors";
299
+ import { addStrandsExpressEndpoint, addPing } from "@ag-ui/aws-strands/server";
300
+
301
+ const app = express();
302
+ app.use(cors());
303
+ app.use(express.json({ limit: "50mb" }));
304
+ addStrandsExpressEndpoint(app, aguiAgent, { path: "/invocations" });
305
+ addPing(app, "/ping");
306
+ ```
307
+
308
+ ## Development
309
+
310
+ ```bash
311
+ pnpm install
312
+ pnpm build
313
+ pnpm test
314
+ ```
@@ -0,0 +1,310 @@
1
+ import { Agent, AgentConfig, Plugin, SessionManager } from "@strands-agents/sdk";
2
+ import { BaseEvent, Message, RunAgentInput } from "@ag-ui/core";
3
+
4
+ //#region src/logger.d.ts
5
+ /**
6
+ * Injectable logger for the AWS Strands adapter.
7
+ *
8
+ * The Python sibling uses `logging.getLogger(__name__)` and emits warnings /
9
+ * errors to stderr at `WARNING` and up, with `DEBUG` opt-in. This module
10
+ * mirrors that behaviour: by default the adapter is silent below `warn`,
11
+ * surfaces warnings via `console.warn`, and lets callers redirect output by
12
+ * passing a `Logger` in `StrandsAgentConfig.logger`.
13
+ *
14
+ * Signature `(message: string, ...args: unknown[])` intentionally matches the
15
+ * `console` method shape so existing `vi.spyOn(console, "warn")` test
16
+ * scaffolding keeps working with the default logger in place, and so wiring
17
+ * in pino / winston / bunyan is a one-liner.
18
+ */
19
+ interface Logger {
20
+ debug(message: string, ...args: unknown[]): void;
21
+ warn(message: string, ...args: unknown[]): void;
22
+ error(message: string, ...args: unknown[]): void;
23
+ }
24
+ //#endregion
25
+ //#region src/config.d.ts
26
+ type StatePayload = Record<string, unknown>;
27
+ /**
28
+ * Free-form key/value map carried on `RunAgentInput.context[]` and
29
+ * `RunAgentInput.forwardedProps`. Exposed on hook contexts so behaviors can
30
+ * react to e.g. per-request auth tokens or locale without re-parsing
31
+ * `inputData`.
32
+ *
33
+ * TypeScript-only: the Python adapter passes `input_data` directly to hooks
34
+ * and callers pull these fields off themselves.
35
+ */
36
+ interface ToolCallContextExtras {
37
+ /**
38
+ * `RunAgentInput.context[]` flattened by `description` → `value`.
39
+ * Duplicates: later entries overwrite earlier ones. Keys `__proto__`,
40
+ * `constructor`, and `prototype` are dropped to prevent prototype-pollution
41
+ * surprises in downstream `Object.assign(target, ctx.context)` usage.
42
+ */
43
+ context: Readonly<Record<string, string>>;
44
+ /**
45
+ * `RunAgentInput.forwardedProps` as an opaque record. Shape is defined by
46
+ * the frontend; the adapter does not introspect it.
47
+ */
48
+ forwardedProps: Readonly<Record<string, unknown>>;
49
+ }
50
+ /** Context passed to tool call hooks. */
51
+ interface ToolCallContext extends ToolCallContextExtras {
52
+ inputData: RunAgentInput;
53
+ toolName: string;
54
+ toolUseId: string;
55
+ toolInput: unknown;
56
+ argsStr: string;
57
+ }
58
+ /** Context passed to tool result hooks. */
59
+ interface ToolResultContext extends ToolCallContext {
60
+ resultData: unknown;
61
+ messageId: string;
62
+ }
63
+ type MaybePromise<T> = T | Promise<T>;
64
+ type ArgsStreamer = (ctx: ToolCallContext) => AsyncIterable<string>;
65
+ type StateFromArgs = (ctx: ToolCallContext) => MaybePromise<StatePayload | null | undefined>;
66
+ type StateFromResult = (ctx: ToolResultContext) => MaybePromise<StatePayload | null | undefined>;
67
+ type CustomResultHandler = (ctx: ToolResultContext) => AsyncIterable<BaseEvent | null | undefined>;
68
+ type StateContextBuilder = (inputData: RunAgentInput, prompt: string, /** Convenience view over `inputData.context[]` + `inputData.forwardedProps`. */
69
+
70
+ extras?: ToolCallContextExtras) => string;
71
+ type SessionManagerProvider = (inputData: RunAgentInput) => MaybePromise<SessionManager | null | undefined>;
72
+ /** Declarative mapping telling the UI how to predict state from tool args. */
73
+ interface PredictStateMapping {
74
+ stateKey: string;
75
+ tool: string;
76
+ toolArgument: string;
77
+ }
78
+ /** Declarative configuration for tool-specific handling. */
79
+ interface ToolBehavior {
80
+ /**
81
+ * Suppress the `MessagesSnapshotEvent` that would normally follow this
82
+ * tool's `TOOL_CALL_END` / `TOOL_CALL_RESULT`. Useful when
83
+ * `customResultHandler` emits its own snapshot.
84
+ */
85
+ skipMessagesSnapshot?: boolean;
86
+ /** Keep the stream alive after emitting a frontend tool call. */
87
+ continueAfterFrontendCall?: boolean;
88
+ /** Close text streaming and halt the agent after a tool result arrives. */
89
+ stopStreamingAfterResult?: boolean;
90
+ /** `PredictStateMapping[]` that inform the UI how to project tool args into state. */
91
+ predictState?: PredictStateMapping | Iterable<PredictStateMapping>;
92
+ /** Async generator controlling how tool arguments are streamed to the frontend. */
93
+ argsStreamer?: ArgsStreamer;
94
+ /** Derive a `StateSnapshotEvent` from the tool call arguments. */
95
+ stateFromArgs?: StateFromArgs;
96
+ /** Derive a `StateSnapshotEvent` from the tool result. */
97
+ stateFromResult?: StateFromResult;
98
+ /** Async iterator that can emit arbitrary AG-UI events in response to a result. */
99
+ customResultHandler?: CustomResultHandler;
100
+ }
101
+ /** Top-level configuration for the Strands agent adapter. */
102
+ interface StrandsAgentConfig {
103
+ /** Per-tool overrides keyed by the Strands tool name. */
104
+ toolBehaviors?: Record<string, ToolBehavior>;
105
+ /** Callable that enriches the outgoing prompt with the current shared state. */
106
+ stateContextBuilder?: StateContextBuilder;
107
+ /**
108
+ * Optional factory for creating per-thread `SessionManager` instances.
109
+ *
110
+ * Called exactly once per `threadId` the first time that thread is seen.
111
+ * Subsequent requests on the same thread reuse the cached agent (and its
112
+ * SessionManager). If the provider depends on per-request data (e.g. auth
113
+ * tokens in `forwardedProps`), only the first request's data is used.
114
+ *
115
+ * If the provider throws, the run yields `RUN_ERROR` and returns early;
116
+ * the thread is NOT cached so the provider will be retried on the next
117
+ * request.
118
+ *
119
+ * If the provider returns `null` or `undefined`, a warning is logged and
120
+ * the agent runs without session persistence; the thread IS cached.
121
+ */
122
+ sessionManagerProvider?: SessionManagerProvider;
123
+ /**
124
+ * Emit `MessagesSnapshotEvent` at lifecycle boundaries (after the initial
125
+ * `STATE_SNAPSHOT`, after each `TOOL_CALL_END` / `TOOL_CALL_RESULT`, and
126
+ * after each terminal `TEXT_MESSAGE_END`).
127
+ *
128
+ * Required for CopilotKit v2 frontends; set to `false` for raw AG-UI
129
+ * consumers that reconstruct messages themselves. Default: `true`.
130
+ */
131
+ emitMessagesSnapshot?: boolean;
132
+ /**
133
+ * When `true` (and the cached Strands agent has no `sessionManager`),
134
+ * reconcile the per-thread `Agent.messages` list with
135
+ * `RunAgentInput.messages` before invoking `stream()`.
136
+ *
137
+ * Prevents the LLM from re-firing frontend tools every turn because
138
+ * Strands' internal history was missing the tool result the frontend
139
+ * produced. Disable only if you manage Strands history yourself.
140
+ * Default: `true`.
141
+ */
142
+ replayHistoryIntoStrands?: boolean;
143
+ /**
144
+ * Emit the self-expanding AG-UI chunk events (`TEXT_MESSAGE_CHUNK`,
145
+ * `TOOL_CALL_CHUNK`, `REASONING_MESSAGE_CHUNK`) instead of the explicit
146
+ * `*_START` / `*_CONTENT` / `*_END` triples. Halves the event count on
147
+ * high-frequency deltas; useful for bandwidth-constrained transports.
148
+ * TypeScript-only. Default: `false`.
149
+ */
150
+ emitChunkEvents?: boolean;
151
+ /**
152
+ * Optional injectable logger. Mirrors the Python adapter's
153
+ * `logging.getLogger("ag_ui_strands")`: the default surfaces `warn` / `error`
154
+ * via the `console` and drops `debug`, matching Python's stdlib default
155
+ * (WARNING-and-up to stderr). Pass `{ debug: console.debug, warn:
156
+ * console.warn, error: console.error }` to enable verbose traces, `{ debug()
157
+ * {}, warn() {}, error() {} }` to silence everything, or wire in pino /
158
+ * winston / bunyan directly — the `Logger` shape matches the `console`
159
+ * methods.
160
+ *
161
+ * Debug messages match the Python adapter's message strings field-for-field
162
+ * (modulo camelCase / snake_case) so cross-SDK log diffs are straightforward.
163
+ */
164
+ logger?: Logger;
165
+ }
166
+ /**
167
+ * Flatten `RunAgentInput.context[]` into a plain key/value record and ensure
168
+ * `forwardedProps` is a record. Exported so hook implementations can call it
169
+ * when they have an `inputData` but not a fully-populated hook context.
170
+ */
171
+ declare function buildContextExtras(inputData: RunAgentInput): ToolCallContextExtras;
172
+ //#endregion
173
+ //#region src/agent.d.ts
174
+ /**
175
+ * Structural interface for a Strands multi-agent orchestrator (Graph/Swarm).
176
+ * TypeScript-only: the Python SDK currently has no orchestrator equivalent.
177
+ */
178
+ interface StrandsOrchestrator {
179
+ readonly id?: string;
180
+ stream(input: string): AsyncGenerator<unknown, unknown, unknown>;
181
+ }
182
+ /**
183
+ * Convert ``RunAgentInput.messages`` to AG-UI message objects.
184
+ *
185
+ * Used to seed the running ``MessagesSnapshotEvent`` payload so each snapshot
186
+ * carries the full thread history.
187
+ */
188
+ declare function buildSnapshotMessages(input_messages: Message[]): Message[];
189
+ /** Options accepted by `StrandsAgent`. */
190
+ interface StrandsAgentOptions {
191
+ /**
192
+ * Either an `Agent` (the template — adapter clones it per thread and syncs
193
+ * proxy tools) OR a multi-agent orchestrator (`Graph`, `Swarm`).
194
+ * Orchestrators are stateless per invocation so the same instance serves
195
+ * every thread.
196
+ */
197
+ agent: Agent | StrandsOrchestrator;
198
+ name: string;
199
+ description?: string;
200
+ config?: StrandsAgentConfig;
201
+ /**
202
+ * Plugins forwarded to every per-thread Strands agent created by this
203
+ * adapter (observability, loop caps, policy checks, ...). Mirrors the
204
+ * Python adapter's `hooks=` kwarg. Ignored when `agent` is a multi-agent
205
+ * orchestrator.
206
+ */
207
+ plugins?: Plugin[];
208
+ }
209
+ /** AWS Strands Agent wrapper for AG-UI integration. */
210
+ declare class StrandsAgent {
211
+ readonly name: string;
212
+ readonly description: string;
213
+ readonly config: StrandsAgentConfig;
214
+ private readonly _templateFields;
215
+ /**
216
+ * Hook providers forwarded to each per-thread StrandsAgentCore.
217
+ *
218
+ * Taken directly from the caller rather than read off the template because
219
+ * Strands' `Agent.hooks` is a `HookRegistry` containing only registered
220
+ * callbacks — the original list of provider objects is not retained, and
221
+ * the registry also contains callbacks bound to internal Strands objects
222
+ * that must not be cross-wired into per-thread agents.
223
+ */
224
+ private readonly _plugins;
225
+ private readonly _agentsByThread;
226
+ private readonly _proxyToolNamesByThread;
227
+ /**
228
+ * Guards first-time thread initialization. The sessionManagerProvider call
229
+ * introduces an async yield point between the "is this thread new?" check
230
+ * and the map assignment, so concurrent requests for the same new threadId
231
+ * could otherwise both create an agent and one would clobber the other.
232
+ */
233
+ private readonly _threadInitLock;
234
+ /**
235
+ * Threads with an in-flight run. Strands `Agent.stream()` throws if a
236
+ * second invocation is started on a busy agent; we detect the collision
237
+ * up front and emit a protocol-shaped RUN_ERROR/THREAD_BUSY instead.
238
+ * TypeScript-only: the Python adapter has no equivalent guard.
239
+ */
240
+ private readonly _activeRunsByThread;
241
+ /** Outstanding Strands interrupt IDs per thread, used to validate
242
+ * incoming `RunAgentInput.resume[]` (interrupts.mdx rule 4). */
243
+ private readonly _pendingInterruptsByThread;
244
+ /**
245
+ * When non-null, the adapter bypasses per-thread cloning and invokes
246
+ * the orchestrator directly. See `StrandsAgentOptions.agent`.
247
+ */
248
+ private readonly _orchestrator;
249
+ /**
250
+ * Injectable logger. Defaults to console `warn`/`error` with `debug`
251
+ * suppressed, matching Python's stdlib `logging.getLogger(__name__)`.
252
+ */
253
+ private readonly _log;
254
+ constructor(options: StrandsAgentOptions);
255
+ /** Run the Strands agent and yield AG-UI events. */
256
+ run(inputData: RunAgentInput): AsyncGenerator<BaseEvent, void, void>;
257
+ protected _runRaw(inputData: RunAgentInput): AsyncGenerator<BaseEvent, void, void>;
258
+ private _runSingleAgent;
259
+ /**
260
+ * Legacy burst path for tool calls — invoked when the Strands SDK delivers
261
+ * a complete `ToolUseBlock` or when a `ToolBehavior.argsStreamer` takes
262
+ * over args emission at contentBlockStop.
263
+ *
264
+ * The streaming path inside `_runSingleAgent` handles the common case
265
+ * directly; this helper handles continuation turns and custom streamers.
266
+ *
267
+ * Getters/setters surface the caller's local variables because JS closures
268
+ * capture by reference only for `const` / `let` in scope — an object of
269
+ * mutable fields would work but would require threading `state` through
270
+ * `_runSingleAgent`'s long body.
271
+ */
272
+ private _emitToolCall;
273
+ /**
274
+ * Orchestrator-mode run loop. TypeScript-only: drives a `Graph` or `Swarm`
275
+ * `.stream()` call and translates multi-agent events. Per-thread caching,
276
+ * session managers, and proxy-tool sync don't apply.
277
+ */
278
+ private _runOrchestrator;
279
+ private _buildThreadAgentConfig;
280
+ }
281
+ /**
282
+ * Build the message-history seed handed to `AgentConfig.messages` on
283
+ * cold-cache agent creation. TypeScript-only: the Python SDK mutates
284
+ * `Agent.messages` in place after construction via
285
+ * `_buildStrandsHistory`, whereas the TS SDK consumes a seed at
286
+ * construction time.
287
+ *
288
+ * - Normal run (tail is a `user` turn): seed everything except the final
289
+ * user turn; the final turn is passed to `agent.stream(...)` as the
290
+ * fresh prompt.
291
+ * - Continuation run (tail is a `tool` message) or orphan tail: seed the
292
+ * entire history so the agent sees its own tool call + result before the
293
+ * synthetic continuation prompt fires.
294
+ *
295
+ * Returns `undefined` when the resulting seed would be empty or would
296
+ * start with an `assistant` turn (Bedrock rejects assistant-first history).
297
+ */
298
+ declare function buildStrandsSeed(messages: Message[], log?: Logger): Promise<AgentConfig["messages"]>;
299
+ /**
300
+ * Convert AG-UI messages into the `MessageData` shape `AgentConfig.messages`
301
+ * accepts on cold-cache agent construction. Similar in spirit to
302
+ * `_buildStrandsHistory` but drops orphan tool turns (Bedrock rejects them).
303
+ */
304
+ declare function convertMessagesForStrandsSeed(messages: Message[], log?: Logger): Promise<Array<{
305
+ role: "user" | "assistant";
306
+ content: unknown[];
307
+ }>>;
308
+ //#endregion
309
+ export { ToolCallContext as _, convertMessagesForStrandsSeed as a, buildContextExtras as b, MaybePromise as c, StateContextBuilder as d, StateFromArgs as f, ToolBehavior as g, StrandsAgentConfig as h, buildStrandsSeed as i, PredictStateMapping as l, StatePayload as m, StrandsAgentOptions as n, ArgsStreamer as o, StateFromResult as p, buildSnapshotMessages as r, CustomResultHandler as s, StrandsAgent as t, SessionManagerProvider as u, ToolCallContextExtras as v, Logger as x, ToolResultContext as y };
310
+ //# sourceMappingURL=agent-B2EYZvns.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent-B2EYZvns.d.ts","names":[],"sources":["../src/logger.ts","../src/config.ts","../src/agent.ts"],"mappings":"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"}