@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 +21 -0
- package/README.md +314 -0
- package/dist/agent-B2EYZvns.d.ts +310 -0
- package/dist/agent-B2EYZvns.d.ts.map +1 -0
- package/dist/agent-Dp45JIaO.d.mts +310 -0
- package/dist/agent-Dp45JIaO.d.mts.map +1 -0
- package/dist/index.d.mts +51 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.d.ts +51 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +2 -0
- package/dist/index.mjs.map +1 -0
- package/dist/server.d.mts +136 -0
- package/dist/server.d.mts.map +1 -0
- package/dist/server.d.ts +136 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +2 -0
- package/dist/server.js.map +1 -0
- package/dist/server.mjs +2 -0
- package/dist/server.mjs.map +1 -0
- package/package.json +85 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["LOG_PREFIX","LOG_PREFIX","StrandsAgentCore","StrandsMessage"],"sources":["../src/config.ts","../src/logger.ts","../src/client-proxy-tool.ts","../src/utils.ts","../src/agent.ts","../src/index.ts"],"sourcesContent":["/** Configuration primitives for customizing Strands agent behavior. */\n\nimport type { RunAgentInput, BaseEvent } from \"@ag-ui/core\";\nimport type { SessionManager } from \"@strands-agents/sdk\";\n\nimport type { Logger } from \"./logger\";\n\nexport type StatePayload = Record<string, unknown>;\n\n/**\n * Free-form key/value map carried on `RunAgentInput.context[]` and\n * `RunAgentInput.forwardedProps`. Exposed on hook contexts so behaviors can\n * react to e.g. per-request auth tokens or locale without re-parsing\n * `inputData`.\n *\n * TypeScript-only: the Python adapter passes `input_data` directly to hooks\n * and callers pull these fields off themselves.\n */\nexport interface ToolCallContextExtras {\n /**\n * `RunAgentInput.context[]` flattened by `description` → `value`.\n * Duplicates: later entries overwrite earlier ones. Keys `__proto__`,\n * `constructor`, and `prototype` are dropped to prevent prototype-pollution\n * surprises in downstream `Object.assign(target, ctx.context)` usage.\n */\n context: Readonly<Record<string, string>>;\n /**\n * `RunAgentInput.forwardedProps` as an opaque record. Shape is defined by\n * the frontend; the adapter does not introspect it.\n */\n forwardedProps: Readonly<Record<string, unknown>>;\n}\n\n/** Context passed to tool call hooks. */\nexport interface ToolCallContext extends ToolCallContextExtras {\n inputData: RunAgentInput;\n toolName: string;\n toolUseId: string;\n toolInput: unknown;\n argsStr: string;\n}\n\n/** Context passed to tool result hooks. */\nexport interface ToolResultContext extends ToolCallContext {\n resultData: unknown;\n messageId: string;\n}\n\nexport type MaybePromise<T> = T | Promise<T>;\n\nexport type ArgsStreamer = (ctx: ToolCallContext) => AsyncIterable<string>;\nexport type StateFromArgs = (\n ctx: ToolCallContext,\n) => MaybePromise<StatePayload | null | undefined>;\nexport type StateFromResult = (\n ctx: ToolResultContext,\n) => MaybePromise<StatePayload | null | undefined>;\nexport type CustomResultHandler = (\n ctx: ToolResultContext,\n) => AsyncIterable<BaseEvent | null | undefined>;\nexport type StateContextBuilder = (\n inputData: RunAgentInput,\n prompt: string,\n /** Convenience view over `inputData.context[]` + `inputData.forwardedProps`. */\n extras?: ToolCallContextExtras,\n) => string;\nexport type SessionManagerProvider = (\n inputData: RunAgentInput,\n) => MaybePromise<SessionManager | null | undefined>;\n\n/** Declarative mapping telling the UI how to predict state from tool args. */\nexport interface PredictStateMapping {\n stateKey: string;\n tool: string;\n toolArgument: string;\n}\n\nexport function predictStateMappingToPayload(m: PredictStateMapping): {\n state_key: string;\n tool: string;\n tool_argument: string;\n} {\n return {\n state_key: m.stateKey,\n tool: m.tool,\n tool_argument: m.toolArgument,\n };\n}\n\n/** Declarative configuration for tool-specific handling. */\nexport interface ToolBehavior {\n /**\n * Suppress the `MessagesSnapshotEvent` that would normally follow this\n * tool's `TOOL_CALL_END` / `TOOL_CALL_RESULT`. Useful when\n * `customResultHandler` emits its own snapshot.\n */\n skipMessagesSnapshot?: boolean;\n /** Keep the stream alive after emitting a frontend tool call. */\n continueAfterFrontendCall?: boolean;\n /** Close text streaming and halt the agent after a tool result arrives. */\n stopStreamingAfterResult?: boolean;\n /** `PredictStateMapping[]` that inform the UI how to project tool args into state. */\n predictState?: PredictStateMapping | Iterable<PredictStateMapping>;\n /** Async generator controlling how tool arguments are streamed to the frontend. */\n argsStreamer?: ArgsStreamer;\n /** Derive a `StateSnapshotEvent` from the tool call arguments. */\n stateFromArgs?: StateFromArgs;\n /** Derive a `StateSnapshotEvent` from the tool result. */\n stateFromResult?: StateFromResult;\n /** Async iterator that can emit arbitrary AG-UI events in response to a result. */\n customResultHandler?: CustomResultHandler;\n}\n\n/** Top-level configuration for the Strands agent adapter. */\nexport interface StrandsAgentConfig {\n /** Per-tool overrides keyed by the Strands tool name. */\n toolBehaviors?: Record<string, ToolBehavior>;\n /** Callable that enriches the outgoing prompt with the current shared state. */\n stateContextBuilder?: StateContextBuilder;\n /**\n * Optional factory for creating per-thread `SessionManager` instances.\n *\n * Called exactly once per `threadId` the first time that thread is seen.\n * Subsequent requests on the same thread reuse the cached agent (and its\n * SessionManager). If the provider depends on per-request data (e.g. auth\n * tokens in `forwardedProps`), only the first request's data is used.\n *\n * If the provider throws, the run yields `RUN_ERROR` and returns early;\n * the thread is NOT cached so the provider will be retried on the next\n * request.\n *\n * If the provider returns `null` or `undefined`, a warning is logged and\n * the agent runs without session persistence; the thread IS cached.\n */\n sessionManagerProvider?: SessionManagerProvider;\n /**\n * Emit `MessagesSnapshotEvent` at lifecycle boundaries (after the initial\n * `STATE_SNAPSHOT`, after each `TOOL_CALL_END` / `TOOL_CALL_RESULT`, and\n * after each terminal `TEXT_MESSAGE_END`).\n *\n * Required for CopilotKit v2 frontends; set to `false` for raw AG-UI\n * consumers that reconstruct messages themselves. Default: `true`.\n */\n emitMessagesSnapshot?: boolean;\n /**\n * When `true` (and the cached Strands agent has no `sessionManager`),\n * reconcile the per-thread `Agent.messages` list with\n * `RunAgentInput.messages` before invoking `stream()`.\n *\n * Prevents the LLM from re-firing frontend tools every turn because\n * Strands' internal history was missing the tool result the frontend\n * produced. Disable only if you manage Strands history yourself.\n * Default: `true`.\n */\n replayHistoryIntoStrands?: boolean;\n /**\n * Emit the self-expanding AG-UI chunk events (`TEXT_MESSAGE_CHUNK`,\n * `TOOL_CALL_CHUNK`, `REASONING_MESSAGE_CHUNK`) instead of the explicit\n * `*_START` / `*_CONTENT` / `*_END` triples. Halves the event count on\n * high-frequency deltas; useful for bandwidth-constrained transports.\n * TypeScript-only. Default: `false`.\n */\n emitChunkEvents?: boolean;\n /**\n * Optional injectable logger. Mirrors the Python adapter's\n * `logging.getLogger(\"ag_ui_strands\")`: the default surfaces `warn` / `error`\n * via the `console` and drops `debug`, matching Python's stdlib default\n * (WARNING-and-up to stderr). Pass `{ debug: console.debug, warn:\n * console.warn, error: console.error }` to enable verbose traces, `{ debug()\n * {}, warn() {}, error() {} }` to silence everything, or wire in pino /\n * winston / bunyan directly — the `Logger` shape matches the `console`\n * methods.\n *\n * Debug messages match the Python adapter's message strings field-for-field\n * (modulo camelCase / snake_case) so cross-SDK log diffs are straightforward.\n */\n logger?: Logger;\n}\n\n// Prototype-pollution guard for keys flattened from `context[]`. Plain\n// `Object.create(null)` maps have no prototype chain, so `__proto__` becomes\n// a regular string key; `constructor` and `prototype` are likewise unfiltered.\nconst UNSAFE_CONTEXT_KEYS = new Set([\"__proto__\", \"constructor\", \"prototype\"]);\n\nfunction isPredictStateMapping(v: unknown): v is PredictStateMapping {\n return (\n typeof v === \"object\" &&\n v !== null &&\n \"stateKey\" in v &&\n \"tool\" in v &&\n \"toolArgument\" in v\n );\n}\n\n/**\n * Flatten `RunAgentInput.context[]` into a plain key/value record and ensure\n * `forwardedProps` is a record. Exported so hook implementations can call it\n * when they have an `inputData` but not a fully-populated hook context.\n */\nexport function buildContextExtras(\n inputData: RunAgentInput,\n): ToolCallContextExtras {\n const context = Object.create(null) as Record<string, string>;\n const rawContext = (inputData as { context?: unknown }).context;\n if (Array.isArray(rawContext)) {\n for (const entry of rawContext) {\n if (!entry || typeof entry !== \"object\") continue;\n const e = entry as { description?: unknown; value?: unknown };\n if (typeof e.description !== \"string\" || e.description.length === 0)\n continue;\n if (UNSAFE_CONTEXT_KEYS.has(e.description)) continue;\n context[e.description] =\n typeof e.value === \"string\" ? e.value : String(e.value ?? \"\");\n }\n }\n const rawForwarded = (inputData as { forwardedProps?: unknown })\n .forwardedProps;\n const forwardedProps: Record<string, unknown> =\n rawForwarded &&\n typeof rawForwarded === \"object\" &&\n !Array.isArray(rawForwarded)\n ? (rawForwarded as Record<string, unknown>)\n : {};\n return { context, forwardedProps };\n}\n\n/** Resolve promise-like values produced by hook callables. */\nexport async function maybeAwait<T>(value: MaybePromise<T>): Promise<T> {\n return await Promise.resolve(value);\n}\n\n/** Normalize predict-state config into a concrete list. */\nexport function normalizePredictState(\n value: PredictStateMapping | Iterable<PredictStateMapping> | undefined,\n): PredictStateMapping[] {\n if (value === undefined) return [];\n if (isPredictStateMapping(value)) return [value];\n return Array.from(value);\n}\n","/**\n * Injectable logger for the AWS Strands adapter.\n *\n * The Python sibling uses `logging.getLogger(__name__)` and emits warnings /\n * errors to stderr at `WARNING` and up, with `DEBUG` opt-in. This module\n * mirrors that behaviour: by default the adapter is silent below `warn`,\n * surfaces warnings via `console.warn`, and lets callers redirect output by\n * passing a `Logger` in `StrandsAgentConfig.logger`.\n *\n * Signature `(message: string, ...args: unknown[])` intentionally matches the\n * `console` method shape so existing `vi.spyOn(console, \"warn\")` test\n * scaffolding keeps working with the default logger in place, and so wiring\n * in pino / winston / bunyan is a one-liner.\n */\nexport interface Logger {\n debug(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\n/**\n * Internal fallback used when `StrandsAgentConfig.logger` is omitted.\n * Mirrors Python's stdlib default: warnings + errors go to the console,\n * debug is dropped. Not exported — callers who want different behaviour\n * inject their own logger.\n */\nexport const DEFAULT_LOGGER: Logger = {\n debug() {},\n warn: (msg, ...args) => console.warn(msg, ...args),\n error: (msg, ...args) => console.error(msg, ...args),\n};\n\n/** Return `provided ?? DEFAULT_LOGGER`. */\nexport function resolveLogger(provided: Logger | undefined): Logger {\n return provided ?? DEFAULT_LOGGER;\n}\n","/** Utilities for forwarding client-defined tools to the Strands agent at runtime. */\n\nimport {\n Agent,\n TextBlock,\n ToolResultBlock,\n type Tool,\n type ToolContext,\n type ToolSpec,\n type ToolStreamGenerator,\n} from \"@strands-agents/sdk\";\nimport type { Tool as AguiTool } from \"@ag-ui/core\";\n\nimport { DEFAULT_LOGGER, type Logger } from \"./logger\";\n\nconst LOG_PREFIX = \"[@ag-ui/aws-strands]\";\n\n/** Derived from `Agent.toolRegistry` because Strands doesn't re-export the type. */\nexport type StrandsToolRegistry = Agent[\"toolRegistry\"];\n\n// Symbol set on proxy tools so we can distinguish them from native tools.\nconst PROXY_MARKER = Symbol.for(\"@ag-ui/aws-strands.proxyTool\");\n\ninterface ProxyTool extends Tool {\n readonly [PROXY_MARKER]: true;\n}\n\n/**\n * Convert an AG-UI `Tool` into a Strands proxy `Tool`.\n *\n * When invoked server-side the proxy returns a placeholder result — the real\n * execution happens on the client. Proxy tools are distinguishable from\n * tools registered at server startup via an internal symbol marker.\n */\nexport function createProxyTool(tool: AguiTool): Tool {\n // Strands' tool registry rejects empty-string descriptions, and Bedrock\n // requires a non-empty description on every tool spec. Frontend tools\n // routed through CopilotKit don't always provide one, so synthesise a\n // minimal placeholder from the tool name when missing.\n const description =\n tool.description && tool.description.length > 0\n ? tool.description\n : `Client-side tool: ${tool.name}`;\n const spec: ToolSpec = {\n name: tool.name,\n description,\n inputSchema: (tool.parameters ?? {\n type: \"object\",\n properties: {},\n }) as ToolSpec[\"inputSchema\"],\n };\n const proxy: ProxyTool = {\n name: spec.name,\n description,\n toolSpec: spec,\n [PROXY_MARKER]: true,\n // `yield` is deliberately omitted — the adapter filters the placeholder\n // result out before it becomes a TOOL_CALL_RESULT on the wire. The\n // generator type keeps the Strands contract happy.\n async *stream(toolContext: ToolContext): ToolStreamGenerator {\n return new ToolResultBlock({\n toolUseId: toolContext.toolUse.toolUseId,\n status: \"success\",\n content: [new TextBlock(\"Forwarded to client\")],\n });\n },\n };\n return proxy;\n}\n\n/** Returns `true` if `tool` was created by `createProxyTool`. */\nexport function isProxyTool(tool: unknown): boolean {\n return (\n typeof tool === \"object\" &&\n tool !== null &&\n (tool as { [PROXY_MARKER]?: boolean })[PROXY_MARKER] === true\n );\n}\n\n/**\n * Synchronise proxy tools in `toolRegistry` with `aguiTools`.\n *\n * - New tools present in `aguiTools` but absent from the registry are\n * registered (unless a native, non-proxy tool with the same name exists).\n * - Stale proxy tools in `trackedNames` but absent from `aguiTools` are\n * removed.\n *\n * Returns the updated set of proxy tool names currently registered.\n */\nexport function syncProxyTools(\n toolRegistry: StrandsToolRegistry,\n aguiTools: AguiTool[],\n trackedNames: Set<string>,\n log: Logger = DEFAULT_LOGGER,\n): Set<string> {\n const desiredNames = new Set<string>();\n for (const t of aguiTools) {\n if (t.name) desiredNames.add(t.name);\n }\n\n // Remove stale proxy tools.\n for (const name of trackedNames) {\n if (desiredNames.has(name)) continue;\n const existing = toolRegistry.get(name);\n if (existing && isProxyTool(existing)) {\n toolRegistry.remove(name);\n log.debug(`${LOG_PREFIX} Removed stale proxy tool: ${name}`);\n }\n }\n\n // Add or refresh proxy tools.\n const current = new Set<string>();\n for (const t of aguiTools) {\n if (!t.name) continue;\n const existing = toolRegistry.get(t.name);\n if (existing && !isProxyTool(existing)) {\n // Native tool shadows client tool — warn so integrators can detect\n // the collision (client's tool will never execute).\n log.warn(\n `${LOG_PREFIX} Native tool \"${t.name}\" shadows client-declared tool with the same name; client tool will not be registered`,\n );\n continue;\n }\n if (existing) {\n // Remove then re-register to pick up any schema changes.\n toolRegistry.remove(t.name);\n }\n toolRegistry.add(createProxyTool(t));\n current.add(t.name);\n log.debug(`${LOG_PREFIX} Registered proxy tool: ${t.name}`);\n }\n\n return current;\n}\n","/** Utility functions for AWS Strands integration. */\n\nimport type {\n InputContent,\n TextInputContent,\n ImageInputContent,\n DocumentInputContent,\n VideoInputContent,\n InputContentSource,\n} from \"@ag-ui/core\";\nimport {\n ImageBlock,\n DocumentBlock,\n VideoBlock,\n TextBlock,\n type ContentBlock,\n type ImageFormat,\n type DocumentFormat,\n type VideoFormat,\n} from \"@strands-agents/sdk\";\nimport { DEFAULT_LOGGER, type Logger } from \"./logger\";\n\nconst LOG_PREFIX = \"[@ag-ui/aws-strands]\";\n\n// Allowed formats per media type for Strands ContentBlock\nconst IMAGE_FORMATS = new Set<string>([\"png\", \"jpeg\", \"gif\", \"webp\"]);\nconst DOCUMENT_FORMATS = new Set<string>([\n \"pdf\",\n \"csv\",\n \"doc\",\n \"docx\",\n \"xls\",\n \"xlsx\",\n \"html\",\n \"txt\",\n \"md\",\n]);\nconst VIDEO_FORMATS = new Set<string>([\n \"flv\",\n \"mkv\",\n \"mov\",\n \"mpeg\",\n \"mpg\",\n \"mp4\",\n \"three_gp\",\n \"webm\",\n \"wmv\",\n]);\n\n/** Parse a MIME type into a short format string; returns null if absent or unsupported. */\nfunction mimeToFormat(\n mimeType: string | undefined,\n allowed: Set<string>,\n log: Logger,\n): string | null {\n if (!mimeType) {\n log.warn(`${LOG_PREFIX} No MIME type provided, cannot determine format`);\n return null;\n }\n const fmt = mimeType.split(\"/\").pop()?.toLowerCase() ?? \"\";\n if (allowed.has(fmt)) {\n return fmt;\n }\n log.warn(\n `${LOG_PREFIX} Unsupported MIME type '${mimeType}' (parsed format '${fmt}' not in ${JSON.stringify([...allowed].sort())})`,\n );\n return null;\n}\n\n/** Fetch raw bytes from a URL using the global fetch (Node 20+). */\nasync function fetchUrlBytes(\n url: string,\n log: Logger,\n): Promise<Uint8Array | null> {\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), 30_000);\n try {\n const res = await fetch(url, { signal: controller.signal });\n if (!res.ok) {\n log.warn(`${LOG_PREFIX} Failed to fetch URL ${url}: HTTP ${res.status}`);\n return null;\n }\n const buf = await res.arrayBuffer();\n return new Uint8Array(buf);\n } catch (e) {\n log.warn(`${LOG_PREFIX} Failed to fetch URL ${url}:`, e);\n return null;\n } finally {\n clearTimeout(timeout);\n }\n}\n\nfunction decodeBase64(value: string, log: Logger): Uint8Array | null {\n try {\n const bin = globalThis.atob(value);\n const out = new Uint8Array(bin.length);\n for (let i = 0; i < bin.length; i++) {\n out[i] = bin.charCodeAt(i);\n }\n return out;\n } catch (e) {\n log.warn(`${LOG_PREFIX} Failed to decode base64 content:`, e);\n return null;\n }\n}\n\n/** Resolve bytes from an AG-UI content source. */\nasync function resolveSourceBytes(\n source: InputContentSource,\n log: Logger,\n): Promise<Uint8Array | null> {\n if (source.type === \"data\") {\n return decodeBase64(source.value, log);\n }\n if (source.type === \"url\") {\n return await fetchUrlBytes(source.value, log);\n }\n log.warn(\n `${LOG_PREFIX} Unknown content source type: ${(source as { type?: string }).type}, cannot resolve bytes`,\n );\n return null;\n}\n\n/**\n * Convert an AG-UI `InputContent` list to Strands `ContentBlock` values.\n *\n * Supported types:\n * - `TextInputContent` -> `TextBlock`\n * - `ImageInputContent` -> `ImageBlock` (png, jpeg, gif, webp)\n * - `DocumentInputContent` -> `DocumentBlock` (pdf, csv, doc, docx, xls, xlsx, html, txt, md)\n * - `VideoInputContent` -> `VideoBlock` (flv, mkv, mov, mpeg, mpg, mp4, three_gp, webm, wmv)\n * - `AudioInputContent` — skipped (Strands has no audio support).\n * - Unresolvable items (bad MIME, fetch failure) — skipped.\n */\nexport async function convertAguiContentToStrands(\n content: InputContent[],\n log: Logger = DEFAULT_LOGGER,\n): Promise<ContentBlock[]> {\n const blocks: ContentBlock[] = [];\n\n for (const item of content) {\n if (item.type === \"text\") {\n blocks.push(new TextBlock((item as TextInputContent).text));\n continue;\n }\n\n if (item.type === \"image\") {\n const imageItem = item as ImageInputContent;\n const bytes = await resolveSourceBytes(imageItem.source, log);\n if (!bytes) continue;\n const fmt = mimeToFormat(imageItem.source.mimeType, IMAGE_FORMATS, log);\n if (!fmt) continue;\n blocks.push(\n new ImageBlock({ format: fmt as ImageFormat, source: { bytes } }),\n );\n continue;\n }\n\n if (item.type === \"document\") {\n const docItem = item as DocumentInputContent;\n const bytes = await resolveSourceBytes(docItem.source, log);\n if (!bytes) continue;\n const fmt = mimeToFormat(docItem.source.mimeType, DOCUMENT_FORMATS, log);\n if (!fmt) continue;\n blocks.push(\n new DocumentBlock({\n format: fmt as DocumentFormat,\n name: \"document\",\n source: { bytes },\n }),\n );\n continue;\n }\n\n if (item.type === \"video\") {\n const vidItem = item as VideoInputContent;\n const bytes = await resolveSourceBytes(vidItem.source, log);\n if (!bytes) continue;\n const fmt = mimeToFormat(vidItem.source.mimeType, VIDEO_FORMATS, log);\n if (!fmt) continue;\n blocks.push(\n new VideoBlock({ format: fmt as VideoFormat, source: { bytes } }),\n );\n continue;\n }\n\n if (item.type === \"audio\") {\n log.warn(\n `${LOG_PREFIX} Skipping audio content: Strands has no audio support`,\n );\n continue;\n }\n\n if (item.type === \"binary\") {\n // Deprecated legacy binary content — try to map to an image block.\n const bin = item as {\n type: \"binary\";\n mimeType: string;\n url?: string;\n data?: string;\n };\n let bytes: Uint8Array | null = null;\n if (bin.data) {\n bytes = decodeBase64(bin.data, log);\n } else if (bin.url) {\n bytes = await fetchUrlBytes(bin.url, log);\n }\n if (!bytes) {\n log.warn(\n `${LOG_PREFIX} Skipping binary content: could not resolve bytes`,\n );\n continue;\n }\n const fmt = mimeToFormat(bin.mimeType, IMAGE_FORMATS, log);\n if (!fmt) {\n log.warn(\n `${LOG_PREFIX} Skipping binary content: unsupported MIME type '${bin.mimeType}'`,\n );\n continue;\n }\n blocks.push(\n new ImageBlock({ format: fmt as ImageFormat, source: { bytes } }),\n );\n continue;\n }\n\n log.warn(\n `${LOG_PREFIX} Skipping unknown content type: ${(item as { type?: string }).type}`,\n );\n }\n\n return blocks;\n}\n\n/** Extract plain text from AG-UI message content or Strands content blocks. */\nexport function flattenContentToText(content: unknown): string {\n if (content === null || content === undefined) {\n return \"\";\n }\n if (typeof content === \"string\") {\n return content;\n }\n if (Array.isArray(content)) {\n const parts: string[] = [];\n for (const item of content) {\n if (!item || typeof item !== \"object\") continue;\n const typed = item as { type?: string; text?: string };\n // AG-UI TextInputContent\n if (typed.type === \"text\" && typeof typed.text === \"string\") {\n parts.push(typed.text);\n }\n // Strands TextBlock\n if (typed.type === \"textBlock\" && typeof typed.text === \"string\") {\n parts.push(typed.text);\n }\n }\n return parts.join(\" \");\n }\n return \"\";\n}\n","/**\n * AWS Strands Agent adapter for AG-UI.\n *\n * Translates Strands streaming events into the AG-UI event protocol.\n */\n\nimport { randomUUID } from \"crypto\";\n\nimport {\n Agent as StrandsAgentCore,\n InterruptResponseContent,\n Message as StrandsMessage,\n SessionManager,\n TextBlock,\n ToolResultBlock,\n ToolUseBlock,\n type AgentConfig,\n type AgentResult as StrandsAgentResult,\n type AgentStreamEvent,\n type ContentBlock,\n type Interrupt as StrandsInterrupt,\n type JSONValue,\n type Plugin,\n} from \"@strands-agents/sdk\";\nimport {\n EventType,\n type AssistantMessage as AguiAssistantMessage,\n type BaseEvent,\n type Interrupt as AguiInterrupt,\n type Message as AguiMessage,\n type ResumeEntry,\n type RunAgentInput,\n type ToolCall as AguiToolCall,\n type ToolMessage as AguiToolMessage,\n type UserMessage as AguiUserMessage,\n} from \"@ag-ui/core\";\n\nimport {\n buildContextExtras,\n maybeAwait,\n normalizePredictState,\n predictStateMappingToPayload,\n type StrandsAgentConfig,\n type ToolCallContext,\n type ToolResultContext,\n} from \"./config\";\nimport { syncProxyTools } from \"./client-proxy-tool\";\nimport { convertAguiContentToStrands, flattenContentToText } from \"./utils\";\nimport type { SeenToolCall } from \"./types\";\nimport { DEFAULT_LOGGER, resolveLogger, type Logger } from \"./logger\";\n\nconst LOG_PREFIX = \"[@ag-ui/aws-strands]\";\n\n// Strands' `randomUUID` return type is branded; normalise to plain string.\nconst uuid = (): string => randomUUID();\n\n/**\n * Structural interface for a Strands multi-agent orchestrator (Graph/Swarm).\n * TypeScript-only: the Python SDK currently has no orchestrator equivalent.\n */\ninterface StrandsOrchestrator {\n readonly id?: string;\n stream(input: string): AsyncGenerator<unknown, unknown, unknown>;\n}\n\n/**\n * Fields cloned from the caller-supplied template Agent into every per-thread\n * Agent. Mirrors Python's `_extract_agent_kwargs`. Deliberately NOT forwarded:\n * - sessionManager: supplied per-thread via sessionManagerProvider.\n * - plugins: supplied explicitly via StrandsAgentOptions.plugins.\n * - conversationManager: bound to template state; sharing across threads\n * would share conversation-window state. Rely on Strands' default.\n * - messages: per-thread agents start empty; AG-UI delivers at runtime.\n * - hooks: Strands' HookRegistry ephemeral state, not forwarded.\n */\ninterface TemplateAgentCloneFields {\n model: AgentConfig[\"model\"];\n tools: StrandsAgentCore[\"tools\"];\n systemPrompt?: AgentConfig[\"systemPrompt\"];\n name?: string;\n description?: string;\n id?: string;\n appState?: Record<string, JSONValue>;\n modelState?: Record<string, JSONValue>;\n traceAttributes?: AgentConfig[\"traceAttributes\"];\n structuredOutputSchema?: AgentConfig[\"structuredOutputSchema\"];\n toolExecutor?: AgentConfig[\"toolExecutor\"];\n}\n\n/**\n * Extract every forwardable field from the template Agent into per-thread\n * clones. Mirrors Python's ``_extract_agent_kwargs``.\n */\nfunction _extractTemplateFields(\n agent: StrandsAgentCore,\n): TemplateAgentCloneFields {\n const model = agent.model;\n // Forward the existing Model instance to per-thread clones so that any\n // provider-specific config the caller set on the template (e.g. Bedrock\n // `additionalRequestFields.thinking`, `temperature`, guardrails) is\n // preserved. Strands also accepts `model: string` and rebuilds a\n // BedrockModel from it, but that path discards every other field — which\n // silently breaks reasoning, guardrails, and per-model tuning.\n const fields: TemplateAgentCloneFields = {\n model,\n tools: agent.tools.slice(),\n };\n if (agent.systemPrompt !== undefined)\n fields.systemPrompt = agent.systemPrompt;\n // Strands defaults `name` to \"Strands Agent\" and `id` to \"agent\" when the\n // caller doesn't set them — forward them unconditionally so the per-thread\n // agent matches the template regardless of whether the default or an\n // override was used.\n if (agent.name !== undefined) fields.name = agent.name;\n if (agent.id !== undefined) fields.id = agent.id;\n if (agent.description !== undefined) fields.description = agent.description;\n // appState / modelState are StateStore instances; serialize to plain dicts.\n const appStateDump = (\n agent.appState as { getAll?: () => Record<string, JSONValue> }\n )?.getAll?.();\n if (appStateDump && Object.keys(appStateDump).length > 0)\n fields.appState = appStateDump;\n const modelStateDump = (\n agent.modelState as { getAll?: () => Record<string, JSONValue> }\n )?.getAll?.();\n if (modelStateDump && Object.keys(modelStateDump).length > 0)\n fields.modelState = modelStateDump;\n // These aren't exposed via the Agent's public accessors in all SDK versions;\n // read them optimistically and forward only when set.\n const extra = agent as unknown as {\n traceAttributes?: AgentConfig[\"traceAttributes\"];\n structuredOutputSchema?: AgentConfig[\"structuredOutputSchema\"];\n toolExecutor?: AgentConfig[\"toolExecutor\"];\n };\n if (extra.traceAttributes !== undefined)\n fields.traceAttributes = extra.traceAttributes;\n if (extra.structuredOutputSchema !== undefined)\n fields.structuredOutputSchema = extra.structuredOutputSchema;\n if (extra.toolExecutor !== undefined)\n fields.toolExecutor = extra.toolExecutor;\n return fields;\n}\n\n/** Best-effort string view of an AG-UI message content field. */\nfunction _coerceText(content: unknown): string {\n if (typeof content === \"string\") return content;\n if (content == null) return \"\";\n if (Array.isArray(content)) return flattenContentToText(content);\n return String(content);\n}\n\n/**\n * Build a Strands `toolResult` content block from an AG-UI tool message body.\n *\n * AG-UI's wire shape requires `ToolMessage.content` to be a string. Frontends\n * (e.g. CopilotKit's `useHumanInTheLoop`) typically JSON-encode structured\n * results before transport, so the string the adapter receives looks like\n * `'{\"accepted\":true,\"steps\":[...]}'`. Forwarding that as a `text` block leaves\n * the LLM with two competing payloads: the original `toolUse.input` (full\n * args) and an opaque-looking JSON string in the result. The model often\n * defaults to the args.\n *\n * Strands' `ToolResultContentData` accepts a `JsonBlock` shape (see\n * `@strands-agents/sdk` `messages.ts`). When the message content parses as a\n * JSON object/array, emit it as `{ json: parsed }` so the LLM sees a real\n * structured result. Fall back to `{ text: ... }` for everything else.\n */\nfunction _buildToolResultContent(\n content: unknown,\n): { text: string } | { json: unknown } {\n const text = _coerceText(content);\n const trimmed = text.trim();\n if (trimmed.length === 0) return { text };\n const first = trimmed[0];\n if (first !== \"{\" && first !== \"[\") return { text };\n try {\n const parsed = JSON.parse(trimmed);\n if (parsed !== null && typeof parsed === \"object\") {\n return { json: parsed };\n }\n } catch {\n // Not valid JSON — fall through to text.\n }\n return { text };\n}\n\n/** Return ``value`` if it is a non-empty string, else a fresh UUID. */\nfunction _coerceId(value: unknown): string {\n return typeof value === \"string\" && value.length > 0 ? value : uuid();\n}\n\n/** Extract a human-readable message from an unknown error. */\nfunction _errorMessage(e: unknown): string {\n return e instanceof Error ? e.message : String(e);\n}\n\n/**\n * Resolve the AG-UI-side tool call id from an incoming Strands tool use.\n *\n * - If we've already seen this Strands tool (by internal id), reuse the\n * existing AG-UI id so every envelope event carries the same id.\n * - Frontend tools get a fresh UUID to avoid cross-request collisions.\n * - Backend tools reuse Strands' own id so result lookup works.\n */\nfunction _resolveToolUseId(\n seen: Map<string, SeenToolCall>,\n strandsToolId: string,\n isFrontendTool: boolean,\n): string {\n for (const [tid, data] of seen) {\n if (data.strandsToolId === strandsToolId) return tid;\n }\n if (isFrontendTool) return uuid();\n return strandsToolId || uuid();\n}\n\n/**\n * Convert ``RunAgentInput.messages`` to AG-UI message objects.\n *\n * Used to seed the running ``MessagesSnapshotEvent`` payload so each snapshot\n * carries the full thread history.\n */\nexport function buildSnapshotMessages(\n input_messages: AguiMessage[],\n): AguiMessage[] {\n const out: AguiMessage[] = [];\n for (const msg of input_messages ?? []) {\n const role = msg.role;\n if (role !== \"user\" && role !== \"assistant\" && role !== \"tool\") continue;\n const msgId = _coerceId((msg as { id?: string }).id);\n if (role === \"user\") {\n out.push({\n id: msgId,\n role: \"user\",\n content: _coerceText(msg.content),\n } as AguiUserMessage);\n } else if (role === \"assistant\") {\n const rawToolCalls = (msg as { toolCalls?: AguiToolCall[] }).toolCalls;\n let toolCalls: AguiToolCall[] | undefined;\n if (rawToolCalls && rawToolCalls.length > 0) {\n toolCalls = rawToolCalls.map((tc) => {\n const fn = tc.function as\n | { name?: string; arguments?: string }\n | undefined;\n return {\n id: _coerceId(tc.id),\n type: \"function\" as const,\n function: {\n name: fn?.name ?? \"unknown\",\n arguments: fn?.arguments ?? \"{}\",\n },\n };\n });\n }\n const assistant: AguiAssistantMessage = {\n id: msgId,\n role: \"assistant\",\n content: _coerceText(msg.content),\n };\n if (toolCalls) assistant.toolCalls = toolCalls;\n out.push(assistant);\n } else {\n const toolCallId = (msg as { toolCallId?: string }).toolCallId ?? \"\";\n out.push({\n id: msgId,\n role: \"tool\",\n content: _coerceText(msg.content),\n toolCallId,\n } as AguiToolMessage);\n }\n }\n return out;\n}\n\n/**\n * Convert ``RunAgentInput.messages`` to Strands native ``Messages``.\n *\n * Strands has only ``user`` and ``assistant`` roles; tool calls and tool\n * results live as ``toolUse`` / ``toolResult`` ContentBlocks. Reconciling\n * the cached agent's ``self.messages`` with this list before invoking\n * ``stream(undefined)`` ensures the LLM sees the real conversation state —\n * including frontend tool results — rather than a fresh prompt that\n * re-fires the same tool every turn.\n *\n * Multimodal content is routed through ``convertAguiContentToStrands`` so\n * image/document/video blocks reach the LLM intact across replay.\n */\nasync function _buildStrandsHistory(\n input_messages: AguiMessage[],\n log: Logger,\n): Promise<Array<{ role: \"user\" | \"assistant\"; content: unknown[] }>> {\n const out: Array<{ role: \"user\" | \"assistant\"; content: unknown[] }> = [];\n for (const msg of input_messages ?? []) {\n const role = msg.role;\n if (role === \"user\") {\n const content: unknown[] = [];\n const raw = msg.content;\n if (Array.isArray(raw)) {\n const hasMedia = raw.some((item: { type?: string }) =>\n [\"image\", \"audio\", \"video\", \"document\"].includes(item.type ?? \"\"),\n );\n if (hasMedia) {\n try {\n const blocks = await convertAguiContentToStrands(raw as never, log);\n for (const b of blocks) {\n if (b instanceof TextBlock) {\n content.push({ text: b.text });\n } else {\n const serialised =\n typeof (b as { toJSON?: () => unknown }).toJSON === \"function\"\n ? (b as { toJSON: () => unknown }).toJSON()\n : b;\n content.push(serialised);\n }\n }\n } catch (e) {\n log.warn(\n `${LOG_PREFIX} history replay multimodal conversion failed; falling back to text`,\n e,\n );\n }\n if (content.length === 0) {\n content.push({ text: flattenContentToText(raw as never) || \"\" });\n }\n } else {\n content.push({ text: flattenContentToText(raw as never) });\n }\n } else {\n content.push({ text: _coerceText(raw) });\n }\n out.push({ role: \"user\", content });\n } else if (role === \"assistant\") {\n const blocks: unknown[] = [];\n const text = _coerceText(msg.content);\n if (text) blocks.push({ text });\n const rawToolCalls =\n (msg as { toolCalls?: AguiToolCall[] }).toolCalls ?? [];\n for (const tc of rawToolCalls) {\n const fn = tc.function as\n | { name?: string; arguments?: string }\n | undefined;\n const name = fn?.name || \"unknown\";\n const rawArgs = fn?.arguments || \"{}\";\n let parsed: unknown;\n try {\n parsed = JSON.parse(rawArgs);\n } catch (e) {\n log.warn(\n `${LOG_PREFIX} history tool args JSON parse failed for ${name}; falling back to {}`,\n e,\n );\n parsed = {};\n }\n if (\n typeof parsed !== \"object\" ||\n parsed === null ||\n Array.isArray(parsed)\n )\n parsed = {};\n blocks.push({\n toolUse: { toolUseId: tc.id, name, input: parsed },\n });\n }\n if (blocks.length === 0) blocks.push({ text: \"\" });\n out.push({ role: \"assistant\", content: blocks });\n } else if (role === \"tool\") {\n const toolCallId = (msg as { toolCallId?: string }).toolCallId || \"\";\n out.push({\n role: \"user\",\n content: [\n {\n toolResult: {\n toolUseId: toolCallId,\n content: [_buildToolResultContent(msg.content)],\n status: \"success\" as const,\n },\n },\n ],\n });\n }\n }\n return out;\n}\n\n/** Options accepted by `StrandsAgent`. */\nexport interface StrandsAgentOptions {\n /**\n * Either an `Agent` (the template — adapter clones it per thread and syncs\n * proxy tools) OR a multi-agent orchestrator (`Graph`, `Swarm`).\n * Orchestrators are stateless per invocation so the same instance serves\n * every thread.\n */\n agent: StrandsAgentCore | StrandsOrchestrator;\n name: string;\n description?: string;\n config?: StrandsAgentConfig;\n /**\n * Plugins forwarded to every per-thread Strands agent created by this\n * adapter (observability, loop caps, policy checks, ...). Mirrors the\n * Python adapter's `hooks=` kwarg. Ignored when `agent` is a multi-agent\n * orchestrator.\n */\n plugins?: Plugin[];\n}\n\n/** AWS Strands Agent wrapper for AG-UI integration. */\nexport class StrandsAgent {\n readonly name: string;\n readonly description: string;\n readonly config: StrandsAgentConfig;\n\n // Template agent configuration for creating fresh per-thread instances.\n private readonly _templateFields: TemplateAgentCloneFields;\n\n /**\n * Hook providers forwarded to each per-thread StrandsAgentCore.\n *\n * Taken directly from the caller rather than read off the template because\n * Strands' `Agent.hooks` is a `HookRegistry` containing only registered\n * callbacks — the original list of provider objects is not retained, and\n * the registry also contains callbacks bound to internal Strands objects\n * that must not be cross-wired into per-thread agents.\n */\n private readonly _plugins: Plugin[];\n\n private readonly _agentsByThread = new Map<string, StrandsAgentCore>();\n private readonly _proxyToolNamesByThread = new Map<string, Set<string>>();\n /**\n * Guards first-time thread initialization. The sessionManagerProvider call\n * introduces an async yield point between the \"is this thread new?\" check\n * and the map assignment, so concurrent requests for the same new threadId\n * could otherwise both create an agent and one would clobber the other.\n */\n private readonly _threadInitLock = new AsyncMutex();\n /**\n * Threads with an in-flight run. Strands `Agent.stream()` throws if a\n * second invocation is started on a busy agent; we detect the collision\n * up front and emit a protocol-shaped RUN_ERROR/THREAD_BUSY instead.\n * TypeScript-only: the Python adapter has no equivalent guard.\n */\n private readonly _activeRunsByThread = new Set<string>();\n /** Outstanding Strands interrupt IDs per thread, used to validate\n * incoming `RunAgentInput.resume[]` (interrupts.mdx rule 4). */\n private readonly _pendingInterruptsByThread = new Map<string, Set<string>>();\n /**\n * When non-null, the adapter bypasses per-thread cloning and invokes\n * the orchestrator directly. See `StrandsAgentOptions.agent`.\n */\n private readonly _orchestrator: StrandsOrchestrator | null;\n /**\n * Injectable logger. Defaults to console `warn`/`error` with `debug`\n * suppressed, matching Python's stdlib `logging.getLogger(__name__)`.\n */\n private readonly _log: Logger;\n\n constructor(options: StrandsAgentOptions) {\n const { agent, name, description = \"\", config = {}, plugins } = options;\n\n // Detect a multi-agent orchestrator. Graph / Swarm expose `nodes` + `edges`\n // (Graph) or `nodes` + invoke semantics (Swarm) and have no `.model`\n // accessor — branching on the presence of `.model` is the cleanest\n // structural check.\n const isOrchestrator =\n typeof (agent as { model?: unknown }).model === \"undefined\" ||\n (agent as { model?: unknown }).model === null;\n\n this.name = name;\n this.description = description;\n this.config = config;\n this._log = resolveLogger(config.logger);\n\n if (isOrchestrator) {\n this._orchestrator = agent as StrandsOrchestrator;\n this._templateFields = { model: undefined as never, tools: [] };\n this._plugins = [];\n return;\n }\n\n this._orchestrator = null;\n const agentCore = agent as StrandsAgentCore;\n this._templateFields = _extractTemplateFields(agentCore);\n this._plugins = plugins ? [...plugins] : [];\n\n // Detect the common pitfall: sessionManager set on the template Agent\n // with no per-thread provider. Forwarding it would make every AG-UI\n // thread share one session_id.\n if (agentCore.sessionManager && !this.config.sessionManagerProvider) {\n this._log.warn(\n `${LOG_PREFIX} sessionManager was set on the template Agent but will ` +\n \"be ignored: forwarding it would cause every AG-UI thread to share the \" +\n \"same session_id. Construct per-thread session managers via \" +\n \"StrandsAgentConfig.sessionManagerProvider instead.\",\n );\n }\n\n // Detect unconnected MCP clients passed directly into `tools: [...]`.\n // Strands resolves a connected `McpClient`'s tools into `agent.tools` at\n // construction time; an unconnected one stays as the bare client and the\n // resolved tool list never appears here. The fix is on the caller's\n // side: `await client.connect()` and spread `await client.listTools()`\n // into the `tools` array.\n for (const tool of this._templateFields.tools ?? []) {\n if (\n tool != null &&\n typeof (tool as { connect?: unknown }).connect === \"function\" &&\n typeof (tool as { name?: unknown }).name !== \"string\"\n ) {\n this._log.warn(\n `${LOG_PREFIX} an entry in the template Agent's \\`tools\\` looks like ` +\n \"an unconnected McpClient — its tools will not be available to the \" +\n \"model. Call `await client.connect()` and spread the resolved tool \" +\n \"list into `tools: [...]` before constructing the Agent.\",\n );\n }\n }\n }\n\n /** Run the Strands agent and yield AG-UI events. */\n async *run(inputData: RunAgentInput): AsyncGenerator<BaseEvent, void, void> {\n const threadId = inputData.threadId || \"default\";\n const hasResume =\n Array.isArray(inputData.resume) && inputData.resume.length > 0;\n\n // interrupts.mdx rule 4: any resume[] entry referencing an unknown\n // interruptId MUST produce RUN_ERROR. Known IDs flow through to\n // `InterruptResponseContent[]`. Gated above `_runRaw` so subclasses\n // that override only `_runRaw` still inherit the check.\n if (hasResume) {\n const pending = this._pendingInterruptsByThread.get(threadId);\n const unknown = inputData\n .resume!.map((entry) => entry.interruptId)\n .filter((id) => !pending?.has(id));\n if (unknown.length > 0) {\n yield _runStarted(inputData);\n yield _runError(\n `This agent did not issue any interrupts to resume: ${unknown\n .slice(0, 4)\n .join(\", \")}. ` +\n \"Resume entries must reference an outstanding interruptId.\",\n \"UNKNOWN_INTERRUPT\",\n );\n return;\n }\n } else {\n // Non-resume run on this thread: any previously recorded interrupt\n // IDs are stale (the client moved on instead of resuming). Drop them\n // so a later replay/race cannot pass the resume[] gate above with a\n // dead interruptId.\n this._pendingInterruptsByThread.delete(threadId);\n }\n const source = this._runRaw(inputData);\n if (this.config.emitChunkEvents) {\n yield* collapseToChunkEvents(source);\n return;\n }\n yield* source;\n }\n\n protected async *_runRaw(\n inputData: RunAgentInput,\n ): AsyncGenerator<BaseEvent, void, void> {\n const threadId = inputData.threadId || \"default\";\n\n // Reject concurrent runs on the same thread up front. Strands cannot\n // multiplex a single Agent across invocations and emits a confusing\n // internal error (\"Agent is already processing an invocation\") if we try.\n if (this._activeRunsByThread.has(threadId)) {\n yield _runStarted(inputData);\n yield _runError(\n `Another run is already in progress on thread \"${threadId}\". Wait for RUN_FINISHED before starting a new run on the same thread.`,\n \"THREAD_BUSY\",\n );\n return;\n }\n this._activeRunsByThread.add(threadId);\n try {\n if (this._orchestrator !== null) {\n yield* this._runOrchestrator(inputData);\n } else {\n yield* this._runSingleAgent(inputData, threadId);\n }\n } finally {\n this._activeRunsByThread.delete(threadId);\n }\n }\n\n private async *_runSingleAgent(\n inputData: RunAgentInput,\n threadId: string,\n ): AsyncGenerator<BaseEvent, void, void> {\n yield _runStarted(inputData);\n\n // Get or create agent instance for this thread. When a\n // sessionManagerProvider is configured, the SessionManager handles\n // conversation persistence; otherwise state is held in-memory per thread.\n let strandsAgent = this._agentsByThread.get(threadId);\n if (!strandsAgent) {\n // Build the message-history seed BEFORE acquiring the global thread\n // init lock. The seed helper may make async fetches for URL-based\n // multimodal attachments; doing that inside the lock would serialise\n // cold-cache initialisations for every OTHER thread behind one slow\n // replay request. Skipped entirely when a SessionManager will own\n // persistence.\n let seedMessages: AgentConfig[\"messages\"] | undefined;\n if (!this.config.sessionManagerProvider) {\n try {\n seedMessages = await buildStrandsSeed(\n inputData.messages ?? [],\n this._log,\n );\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} buildStrandsSeed failed for thread ${threadId}: ${_errorMessage(e)}`,\n e,\n );\n yield _runError(\n \"Failed to build conversation seed: \" + _errorMessage(e),\n \"SEED_BUILD_ERROR\",\n );\n return;\n }\n }\n\n const release = await this._threadInitLock.acquire();\n try {\n // Double-check inside the lock: another coroutine may have completed\n // initialization while we were waiting.\n strandsAgent = this._agentsByThread.get(threadId);\n if (!strandsAgent) {\n let sessionManager: SessionManager | null | undefined;\n if (this.config.sessionManagerProvider) {\n try {\n sessionManager = (await maybeAwait(\n this.config.sessionManagerProvider(inputData),\n )) as SessionManager | null | undefined;\n } catch (e) {\n const msg = _errorMessage(e);\n this._log.error(\n `${LOG_PREFIX} sessionManagerProvider failed: ${msg}`,\n e,\n );\n yield _runError(\n `Failed to initialize session manager: ${msg}`,\n \"SESSION_MANAGER_ERROR\",\n );\n return;\n }\n if (\n sessionManager != null &&\n !(sessionManager instanceof SessionManager)\n ) {\n const actual =\n (sessionManager as object)?.constructor?.name ??\n typeof sessionManager;\n this._log.error(\n `${LOG_PREFIX} sessionManagerProvider returned ${actual}; expected a SessionManager instance.`,\n );\n yield _runError(\n `sessionManagerProvider returned ${actual}; expected a SessionManager instance`,\n \"SESSION_MANAGER_INVALID_TYPE\",\n );\n return;\n }\n if (!sessionManager) {\n this._log.warn(\n `${LOG_PREFIX} sessionManagerProvider returned null/undefined for threadId=${threadId}; ` +\n \"agent will run without session persistence\",\n );\n }\n }\n // If a SessionManager materialised, skip the pre-computed seed —\n // the session owns persistence and seeding on top would duplicate\n // turns.\n const effectiveSeed = sessionManager ? undefined : seedMessages;\n strandsAgent = new StrandsAgentCore(\n this._buildThreadAgentConfig(\n sessionManager ?? undefined,\n effectiveSeed,\n ),\n );\n this._agentsByThread.set(threadId, strandsAgent);\n }\n } finally {\n release();\n }\n }\n\n // Sync proxy tools from client-defined tools.\n if (inputData.tools && inputData.tools.length > 0) {\n const proxyNames = syncProxyTools(\n strandsAgent.toolRegistry,\n inputData.tools,\n this._proxyToolNamesByThread.get(threadId) ?? new Set(),\n this._log,\n );\n this._proxyToolNamesByThread.set(threadId, proxyNames);\n } else {\n const previous = this._proxyToolNamesByThread.get(threadId);\n if (previous && previous.size > 0) {\n syncProxyTools(strandsAgent.toolRegistry, [], previous, this._log);\n this._proxyToolNamesByThread.set(threadId, new Set());\n }\n }\n\n try {\n // Seed the running ``MessagesSnapshotEvent`` payload from the full\n // conversation history so each emitted snapshot carries prior turns\n // plus whatever this turn adds.\n const emitMessagesSnapshot = this.config.emitMessagesSnapshot !== false;\n const snapshotMessages: AguiMessage[] = emitMessagesSnapshot\n ? buildSnapshotMessages(inputData.messages ?? [])\n : [];\n\n // Emit state snapshot if provided. Filter out `messages` from state to\n // avoid \"Unknown message role\" errors — the frontend manages messages\n // separately and doesn't recognize the \"tool\" role.\n if (inputData.state && typeof inputData.state === \"object\") {\n const snapshot: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(\n inputData.state as Record<string, unknown>,\n )) {\n if (k !== \"messages\") snapshot[k] = v;\n }\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n\n // Splice point 1 of 4: emit the initial messages snapshot so the\n // frontend can render the seeded thread before any new content streams.\n if (emitMessagesSnapshot && snapshotMessages.length > 0) {\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n }\n\n const frontendToolNames = new Set<string>();\n for (const t of inputData.tools ?? []) {\n if (t.name) frontendToolNames.add(t.name);\n }\n\n // Collect tool_call_ids that already have results in the message\n // history so we suppress duplicate TOOL_CALL_START events for them.\n const pendingToolResultIds = new Set<string>();\n if (inputData.messages) {\n for (let i = inputData.messages.length - 1; i >= 0; i--) {\n const msg = inputData.messages[i];\n if (!msg) break;\n if (msg.role === \"tool\") {\n const tid = (msg as { toolCallId?: string }).toolCallId;\n if (tid) pendingToolResultIds.add(tid);\n } else {\n break;\n }\n }\n if (pendingToolResultIds.size > 0) {\n this._log.debug(\n `${LOG_PREFIX} Has pending tool results detected: toolCallIds=${JSON.stringify([...pendingToolResultIds])}, threadId=${inputData.threadId}`,\n );\n }\n }\n\n // Lookup of tool_call_id -> tool_name from assistant messages.\n const toolCallIdToName = new Map<string, string>();\n for (const msg of inputData.messages ?? []) {\n if (msg.role !== \"assistant\") continue;\n const calls = (msg as { toolCalls?: AguiToolCall[] }).toolCalls;\n if (!calls) continue;\n for (const tc of calls) {\n const fn = tc.function as { name?: string } | undefined;\n if (tc.id && fn?.name) toolCallIdToName.set(tc.id, fn.name);\n }\n }\n\n // Derive the outgoing user message. For continuation runs (pending\n // tool results in history), synthesise a \"frontend tool executed\"\n // message so the model understands the context.\n let userMessage: string | ContentBlock[] = \"Hello\";\n if (pendingToolResultIds.size > 0 && inputData.messages) {\n for (let i = inputData.messages.length - 1; i >= 0; i--) {\n const msg = inputData.messages[i];\n if (!msg) break;\n if (msg.role === \"tool\") {\n const toolCallId = (msg as { toolCallId?: string }).toolCallId;\n if (toolCallId) {\n const name = toolCallIdToName.get(toolCallId);\n if (name && frontendToolNames.has(name)) {\n userMessage = `${name} executed successfully with no return value.`;\n }\n }\n break;\n }\n }\n } else if (inputData.messages) {\n for (let i = inputData.messages.length - 1; i >= 0; i--) {\n const msg = inputData.messages[i];\n if (!msg) break;\n if (\n (msg.role === \"user\" || msg.role === \"tool\") &&\n msg.content != null\n ) {\n if (Array.isArray(msg.content)) {\n const hasMedia = msg.content.some((item: { type?: string }) =>\n [\"image\", \"audio\", \"video\", \"document\"].includes(\n item.type ?? \"\",\n ),\n );\n if (hasMedia) {\n const blocks = await convertAguiContentToStrands(\n msg.content,\n this._log,\n );\n if (blocks.length > 0) {\n userMessage = blocks;\n } else {\n const textFallback = flattenContentToText(msg.content);\n if (textFallback) {\n userMessage = textFallback;\n this._log.warn(\n `${LOG_PREFIX} all media content blocks failed conversion; falling back to text`,\n );\n } else {\n yield _runError(\n \"All media content blocks failed conversion and no text fallback is available\",\n \"MEDIA_RESOLUTION_FAILED\",\n );\n return;\n }\n }\n } else {\n userMessage = flattenContentToText(msg.content);\n }\n } else {\n userMessage = msg.content as string;\n }\n break;\n }\n }\n }\n\n // Allow configuration to enrich the outgoing user message. Multimodal\n // prompts pass through unchanged so binary payloads reach the model\n // intact.\n if (this.config.stateContextBuilder) {\n try {\n const textForBuilder = Array.isArray(userMessage)\n ? flattenContentToText(userMessage)\n : userMessage;\n const builderResult = this.config.stateContextBuilder(\n inputData,\n textForBuilder,\n buildContextExtras(inputData),\n );\n if (!Array.isArray(userMessage)) {\n userMessage = builderResult;\n }\n } catch (e) {\n this._log.error(`${LOG_PREFIX} stateContextBuilder failed:`, e);\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateContextBuilder\",\n tool: \"__prompt__\",\n error: _errorMessage(e),\n },\n };\n }\n }\n\n // Per-run state.\n let messageId = uuid();\n let messageStarted = false;\n let accumulatedText = \"\";\n const toolCallsSeen = new Map<string, SeenToolCall>();\n const currentState: Record<string, unknown> = {\n ...((inputData.state ?? {}) as object),\n };\n let stopTextStreaming = false;\n let haltEventStream = false;\n let pendingHalt = false;\n\n let reasoningStarted = false;\n let reasoningMessageId: string | undefined;\n\n // Tool currently being streamed via toolUseInputDelta events. Populated\n // by modelContentBlockStartEvent or toolUseInputDelta, flushed on\n // modelContentBlockStopEvent.\n let currentToolUse: {\n name: string;\n toolUseId: string;\n inputChunks: string[];\n } | null = null;\n\n // Reconcile Strands' internal conversation history with\n // ``RunAgentInput.messages`` when no ``sessionManager`` is wired.\n // Without this, frontend tool results never reach the LLM — Strands\n // sees an open ``toolUse`` from the prior turn and the LLM re-fires\n // the same tool every run.\n const replayHistory =\n this.config.replayHistoryIntoStrands !== false &&\n !(strandsAgent as { sessionManager?: unknown }).sessionManager;\n let invokeArgs:\n | string\n | ContentBlock[]\n | InterruptResponseContent[]\n | undefined = userMessage;\n\n // Resume path: convert AG-UI `resume[]` into Strands\n // `InterruptResponseContent[]`. The `run()` gate has already\n // filtered unknown IDs by this point.\n const resumeEntries = resolveResumeEntries(inputData);\n if (resumeEntries.length > 0) {\n invokeArgs = resumeEntries.map(\n (entry) =>\n new InterruptResponseContent({\n interruptId: entry.interruptId,\n response: toResumeResponse(entry) as JSONValue,\n }),\n );\n this._pendingInterruptsByThread.delete(threadId);\n }\n if (replayHistory && resumeEntries.length === 0) {\n const nativeHistory = await _buildStrandsHistory(\n inputData.messages ?? [],\n this._log,\n );\n if (nativeHistory.length > 0) {\n // Apply stateContextBuilder to the last user-text message in the\n // reconciled history rather than to the synthetic `userMessage`\n // string — this is what the LLM actually sees.\n if (this.config.stateContextBuilder) {\n for (let i = nativeHistory.length - 1; i >= 0; i--) {\n const m = nativeHistory[i];\n if (!m || m.role !== \"user\") continue;\n const first = (m.content as Array<{ text?: string }>)[0];\n if (first && typeof first.text === \"string\") {\n try {\n const augmented = this.config.stateContextBuilder(\n inputData,\n first.text,\n buildContextExtras(inputData),\n );\n if (typeof augmented === \"string\") first.text = augmented;\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} stateContextBuilder failed:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateContextBuilder\",\n tool: \"__prompt__\",\n error: _errorMessage(e),\n },\n };\n }\n break;\n }\n }\n }\n // Convert plain-object history into real Message instances —\n // Bedrock's request formatter dispatches on `block.type`, which\n // only the class instances carry.\n (strandsAgent as { messages: unknown[] }).messages =\n nativeHistory.map((m) =>\n StrandsMessage.fromMessageData({\n role: m.role,\n content: m.content as never,\n }),\n );\n // `stream(undefined)` tells Strands to use `this.messages` as-is.\n invokeArgs = undefined;\n }\n }\n\n this._log.debug(\n `${LOG_PREFIX} Starting agent run: threadId=${inputData.threadId}, runId=${inputData.runId}, ` +\n `pendingToolResultIds=${JSON.stringify([...pendingToolResultIds])}, ` +\n `messageCount=${inputData.messages?.length ?? 0}`,\n );\n\n // AbortController wired into Strands's `cancelSignal` so that abandoning\n // the outer generator (HTTP client disconnect) stops the underlying\n // Bedrock streaming call rather than silently burning tokens.\n const runAbort = new AbortController();\n const agentStream = strandsAgent.stream(invokeArgs as never, {\n cancelSignal: runAbort.signal,\n });\n // `agent.stream()` returns the final `AgentResult` on `{ done: true }`.\n // Captured here so the interrupt-variant RUN_FINISHED below can pull\n // `stopReason` and `interrupts[]` off it.\n let finalAgentResult: StrandsAgentResult | undefined;\n\n try {\n while (true) {\n let next: IteratorResult<AgentStreamEvent, unknown>;\n try {\n next = await agentStream.next();\n } catch (streamErr) {\n // Strands throws \"Stream ended without completing a message\" when\n // a frontend tool call halts the agent before the model emits a\n // final assistant message. If we've already decided to halt,\n // swallow the error — it's expected flow.\n if (pendingHalt || haltEventStream) {\n if (\n streamErr instanceof TypeError ||\n streamErr instanceof ReferenceError\n ) {\n throw streamErr;\n }\n haltEventStream = true;\n break;\n }\n throw streamErr;\n }\n if (next.done) {\n finalAgentResult = next.value as StrandsAgentResult | undefined;\n break;\n }\n if (haltEventStream) continue;\n\n // Strands v1 wraps raw model events inside `ModelStreamUpdateEvent`\n // (type: 'modelStreamUpdateEvent', event: ModelStreamEvent) before\n // yielding them from `agent.stream()`. Unwrap once so the dispatch\n // below operates on the inner event shape.\n const event = unwrapStrandsEvent(next.value);\n const kind = getEventKind(event);\n\n // --- Delta events (text, reasoning, tool-use input streaming) ---\n // Maps to Python's top-level \"data\" / \"reasoningText\" /\n // \"current_tool_use\" branches.\n if (kind === \"modelContentBlockDeltaEvent\") {\n const delta = (\n event as unknown as {\n delta:\n | { type: \"textDelta\"; text: string }\n | {\n type: \"reasoningContentDelta\";\n text?: string;\n redactedContent?: Uint8Array;\n }\n | { type: \"toolUseInputDelta\"; input: string };\n }\n ).delta;\n\n // Text data chunks.\n if (delta.type === \"textDelta\" && delta.text) {\n if (stopTextStreaming) continue;\n if (!messageStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId,\n role: \"assistant\",\n };\n messageStarted = true;\n }\n accumulatedText += delta.text;\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId,\n delta: delta.text,\n };\n continue;\n }\n\n // Reasoning/thinking text streaming.\n if (delta.type === \"reasoningContentDelta\") {\n if (delta.text) {\n if (!reasoningStarted) {\n reasoningMessageId = uuid();\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n reasoningStarted = true;\n }\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId!,\n delta: delta.text,\n };\n } else if (delta.redactedContent) {\n if (!reasoningStarted) {\n reasoningMessageId = uuid();\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n reasoningStarted = true;\n }\n yield {\n type: EventType.REASONING_ENCRYPTED_VALUE,\n subtype: \"message\",\n entityId: reasoningMessageId!,\n encryptedValue: Buffer.from(delta.redactedContent).toString(\n \"base64\",\n ),\n };\n }\n continue;\n }\n\n // Tool call input streaming — emits PredictState → TOOL_CALL_START\n // → incremental TOOL_CALL_ARGS deltas. Tools declaring an\n // argsStreamer take the legacy burst-at-contentBlockStop path.\n if (delta.type === \"toolUseInputDelta\" && currentToolUse) {\n currentToolUse.inputChunks.push(delta.input);\n const { name: toolName, toolUseId: strandsToolId } =\n currentToolUse;\n const isFrontendTool = frontendToolNames.has(toolName);\n const toolUseId = _resolveToolUseId(\n toolCallsSeen,\n strandsToolId,\n isFrontendTool,\n );\n\n let entry = toolCallsSeen.get(toolUseId);\n if (!entry) {\n const isPendingNow = pendingToolResultIds.has(toolUseId);\n const behaviorNow = this.config.toolBehaviors?.[toolName];\n this._log.debug(\n `${LOG_PREFIX} Tool call event received: toolName=${toolName}, ` +\n `toolUseId=${toolUseId}, strandsId=${strandsToolId}, ` +\n `isFrontend=${isFrontendTool}, threadId=${inputData.threadId}`,\n );\n // Use streaming (emit ToolCallStart + PredictState now,\n // ToolCallArgs on each growth, ToolCallEnd at\n // contentBlockStop) unless the tool is a continuation or\n // supplies a custom argsStreamer.\n const useStreaming =\n !isPendingNow && !behaviorNow?.argsStreamer;\n entry = {\n name: toolName,\n args: \"\",\n input: {},\n raw: \"\",\n emitted: false,\n startEmitted: false,\n endEmitted: false,\n lastEmittedRawLen: 0,\n isPending: isPendingNow,\n isFrontend: isFrontendTool,\n useStreaming,\n strandsToolId,\n };\n toolCallsSeen.set(toolUseId, entry);\n\n if (useStreaming) {\n // Close any open assistant text turn so the snapshot order\n // matches the wire-event order and message_id can rotate.\n if (messageStarted) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId };\n if (emitMessagesSnapshot && accumulatedText) {\n snapshotMessages.push({\n id: messageId,\n role: \"assistant\",\n content: accumulatedText,\n } as AguiAssistantMessage);\n accumulatedText = \"\";\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n }\n messageStarted = false;\n messageId = uuid();\n }\n\n // PredictState must reach the FE BEFORE any args delta so\n // the FE knows which tool argument feeds which state key\n // while parsing incremental JSON.\n if (behaviorNow) {\n const predict = normalizePredictState(\n behaviorNow.predictState,\n ).map(predictStateMappingToPayload);\n if (predict.length > 0) {\n yield {\n type: EventType.CUSTOM,\n name: \"PredictState\",\n value: predict,\n };\n }\n }\n\n yield {\n type: EventType.TOOL_CALL_START,\n toolCallId: toolUseId,\n toolCallName: toolName,\n parentMessageId: messageId,\n };\n entry.startEmitted = true;\n }\n }\n\n // Rebuild the accumulated raw string and emit the growth as a\n // single TOOL_CALL_ARGS delta. The FE concatenates these into\n // the full args payload and parses incrementally.\n const rawStr = currentToolUse.inputChunks.join(\"\");\n entry.raw = rawStr;\n try {\n entry.input = JSON.parse(rawStr);\n } catch {\n entry.input = rawStr;\n }\n entry.args =\n typeof entry.input === \"string\"\n ? entry.input\n : JSON.stringify(entry.input);\n\n if (entry.startEmitted && entry.useStreaming) {\n const lastLen = entry.lastEmittedRawLen ?? 0;\n if (rawStr.length > lastLen) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: toolUseId,\n delta: rawStr.slice(lastLen),\n };\n entry.lastEmittedRawLen = rawStr.length;\n }\n }\n }\n continue;\n }\n\n // Reasoning signature (verification token) — not exposed to UI.\n if (kind === \"reasoningSignatureEvent\") continue;\n\n // Content block start records tool metadata so toolUseInputDelta\n // can correlate its chunks to a tool. Strands v1 emits\n // `{ start: { type: \"toolUseStart\", name, toolUseId } }` — the\n // field is `.start`, not `.contentBlock`.\n if (kind === \"modelContentBlockStartEvent\") {\n const startWrap = event as unknown as {\n start?: { type?: string; name?: string; toolUseId?: string };\n };\n const s = startWrap.start;\n if (s?.type === \"toolUseStart\" && s.name) {\n currentToolUse = {\n name: s.name,\n toolUseId: s.toolUseId ?? uuid(),\n inputChunks: [],\n };\n }\n continue;\n }\n\n // Content block stop — signals tool input is complete.\n if (kind === \"modelContentBlockStopEvent\") {\n if (reasoningStarted) {\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId!,\n };\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId!,\n };\n reasoningStarted = false;\n reasoningMessageId = undefined;\n }\n\n if (currentToolUse) {\n const {\n name: toolName,\n toolUseId: strandsToolId,\n inputChunks,\n } = currentToolUse;\n currentToolUse = null;\n const rawInput = inputChunks.join(\"\");\n let parsedInput: unknown = {};\n if (rawInput) {\n try {\n parsedInput = JSON.parse(rawInput);\n } catch (e) {\n this._log.warn(\n `${LOG_PREFIX} tool args JSON parse failed for ${toolName}; using raw string`,\n e,\n );\n parsedInput = rawInput;\n }\n }\n const isFrontendTool = frontendToolNames.has(toolName);\n const toolUseId = _resolveToolUseId(\n toolCallsSeen,\n strandsToolId,\n isFrontendTool,\n );\n const argsStr =\n typeof parsedInput === \"string\"\n ? parsedInput\n : JSON.stringify(parsedInput);\n\n if (!toolCallsSeen.has(toolUseId)) {\n toolCallsSeen.set(toolUseId, {\n name: toolName,\n args: argsStr,\n input: parsedInput,\n emitted: false,\n strandsToolId,\n raw: rawInput,\n });\n } else {\n const entry = toolCallsSeen.get(toolUseId)!;\n entry.args = argsStr;\n entry.input = parsedInput;\n entry.raw = rawInput;\n }\n\n const entry = toolCallsSeen.get(toolUseId)!;\n const behavior = this.config.toolBehaviors?.[toolName];\n this._log.debug(\n `${LOG_PREFIX} contentBlockStop close: toolName=${toolName}, ` +\n `toolUseId=${toolUseId}, isFrontendTool=${isFrontendTool}, ` +\n `isPending=${entry.isPending ?? false}, useStreaming=${entry.useStreaming ?? false}, ` +\n `threadId=${inputData.threadId}`,\n );\n\n if (entry.startEmitted && entry.useStreaming) {\n // Streaming path — PredictState + TOOL_CALL_START + per-delta\n // TOOL_CALL_ARGS already went on the wire. Flush any final\n // delta, then close the call.\n const lastLen = entry.lastEmittedRawLen ?? 0;\n if (rawInput.length > lastLen) {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: toolUseId,\n delta: rawInput.slice(lastLen),\n };\n entry.lastEmittedRawLen = rawInput.length;\n }\n\n // stateFromArgs BEFORE TOOL_CALL_END: CopilotKit v2 releases\n // the predict_state buffer at TOOL_CALL_END. Delivering the\n // snapshot first means the FE has authoritative state in\n // hand at the moment prediction is released.\n if (behavior?.stateFromArgs) {\n const callCtx: ToolCallContext = {\n inputData,\n toolName,\n toolUseId,\n toolInput: parsedInput,\n argsStr,\n ...buildContextExtras(inputData),\n };\n try {\n const snapshot = await maybeAwait(\n behavior.stateFromArgs(callCtx),\n );\n if (snapshot) {\n Object.assign(currentState, snapshot);\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} stateFromArgs failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateFromArgs\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n }\n\n yield { type: EventType.TOOL_CALL_END, toolCallId: toolUseId };\n entry.endEmitted = true;\n entry.emitted = true;\n\n // Splice point 2 of 4: append the assistant tool-call entry\n // to the running snapshot, then rotate message_id so the\n // next assistant turn carries a distinct id.\n if (emitMessagesSnapshot && !behavior?.skipMessagesSnapshot) {\n snapshotMessages.push({\n id: messageId,\n role: \"assistant\",\n content: \"\",\n toolCalls: [\n {\n id: toolUseId,\n type: \"function\",\n function: {\n name: toolName || \"unknown\",\n arguments: argsStr || \"{}\",\n },\n },\n ],\n } as AguiAssistantMessage);\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n messageId = uuid();\n }\n\n if (isFrontendTool && !behavior?.continueAfterFrontendCall) {\n this._log.debug(\n `${LOG_PREFIX} Deferring halt after frontend tool call: ` +\n `toolName=${toolName}, toolCallId=${toolUseId}, threadId=${inputData.threadId}`,\n );\n pendingHalt = true;\n }\n } else {\n // Legacy burst path — behavior.argsStreamer is configured,\n // or a continuation turn where the tool is already resolved.\n yield* this._emitToolCall({\n inputData,\n toolUseId,\n isFrontendTool,\n pendingToolResultIds,\n getMessageId: () => messageId,\n setMessageId: (id: string) => {\n messageId = id;\n },\n getMessageStarted: () => messageStarted,\n setMessageStarted: (v: boolean) => {\n messageStarted = v;\n },\n getAccumulatedText: () => accumulatedText,\n setAccumulatedText: (v: string) => {\n accumulatedText = v;\n },\n snapshotMessages,\n emitMessagesSnapshot,\n toolCallsSeen,\n currentState,\n onPendingHalt: () => {\n pendingHalt = true;\n },\n });\n }\n }\n continue;\n }\n\n // ContentBlock yielded post-stream as a completed `ToolUseBlock`.\n // The streaming path above already emitted the envelope via\n // `modelContentBlockStopEvent`; the `emitted` guard inside\n // `_emitToolCall` makes this a no-op when that already happened.\n // This branch also fires when a provider skips delta events\n // entirely (tests, some non-streaming configurations).\n if (kind === \"toolUseBlock\") {\n const block = event as unknown as ToolUseBlock;\n const isFrontendTool = frontendToolNames.has(block.name);\n const toolUseId = _resolveToolUseId(\n toolCallsSeen,\n block.toolUseId,\n isFrontendTool,\n );\n const argsStr =\n typeof block.input === \"string\"\n ? block.input\n : JSON.stringify(block.input);\n if (!toolCallsSeen.has(toolUseId)) {\n toolCallsSeen.set(toolUseId, {\n name: block.name,\n args: argsStr,\n input: block.input,\n emitted: false,\n strandsToolId: block.toolUseId,\n });\n } else {\n const e = toolCallsSeen.get(toolUseId)!;\n e.args = argsStr;\n e.input = block.input;\n }\n yield* this._emitToolCall({\n inputData,\n toolUseId,\n isFrontendTool,\n pendingToolResultIds,\n getMessageId: () => messageId,\n setMessageId: (id: string) => {\n messageId = id;\n },\n getMessageStarted: () => messageStarted,\n setMessageStarted: (v: boolean) => {\n messageStarted = v;\n },\n getAccumulatedText: () => accumulatedText,\n setAccumulatedText: (v: string) => {\n accumulatedText = v;\n },\n snapshotMessages,\n emitMessagesSnapshot,\n toolCallsSeen,\n currentState,\n onPendingHalt: () => {\n pendingHalt = true;\n },\n });\n continue;\n }\n\n // Tool results from Strands (backend tools). Maps to Python's\n // `\"message\" in event and event[\"message\"][\"role\"] == \"user\"` branch.\n if (kind === \"afterToolCallEvent\") {\n if (pendingHalt) {\n // Frontend tool: the proxy \"Forwarded to client\" placeholder has\n // resolved and we don't want to feed it back to the model. Abort\n // the Strands stream so the LLM stops emitting another cycle and\n // we can finalise RUN_FINISHED.\n haltEventStream = true;\n try {\n runAbort.abort();\n } catch {\n // ignore\n }\n break;\n }\n const hookEvent = event as unknown as {\n toolUse: { toolUseId: string; name: string };\n result: ToolResultBlock;\n };\n const resultToolId = hookEvent.toolUse.toolUseId;\n const toolName = hookEvent.toolUse.name;\n\n // Skip placeholder results for proxied frontend tools.\n if (frontendToolNames.has(toolName)) continue;\n\n // Parse the content into a usable value. `result.content` is\n // required by the SDK type but can be missing on errors or\n // malformed tools. A void tool call (returns undefined/null) is\n // legitimate — emit an empty TOOL_CALL_RESULT so the UI still\n // renders a result card.\n let resultData: unknown = null;\n const contentBlocks = hookEvent.result?.content;\n if (Array.isArray(contentBlocks)) {\n for (const cb of contentBlocks) {\n if (cb instanceof TextBlock) {\n try {\n resultData = JSON.parse(cb.text);\n } catch {\n try {\n resultData = JSON.parse(cb.text.replace(/'/g, '\"'));\n } catch (e) {\n this._log.warn(\n `${LOG_PREFIX} tool result JSON parse failed for ${toolName}; using raw text`,\n e,\n );\n resultData = cb.text;\n }\n }\n break;\n }\n const maybeJson = (cb as unknown as { json?: unknown }).json;\n if (maybeJson !== undefined) {\n resultData = maybeJson;\n break;\n }\n }\n }\n\n if (!resultToolId) continue;\n\n const callInfo = toolCallsSeen.get(resultToolId);\n const toolArgs = callInfo?.args;\n const toolInput = callInfo?.input;\n const behavior = this.config.toolBehaviors?.[toolName];\n\n this._log.debug(\n `${LOG_PREFIX} Processing tool result: toolName=${toolName}, ` +\n `resultToolId=${resultToolId}, threadId=${inputData.threadId}`,\n );\n\n // Emit TOOL_CALL_RESULT without a role field so the frontend\n // completes the tool in UI without adding it to the conversation\n // history. A fresh message id ensures CopilotKit creates a\n // standalone ToolMessage and closes the spinner correctly.\n const toolResultMessageId = uuid();\n const toolResultContent =\n resultData == null ? \"\" : JSON.stringify(resultData);\n yield {\n type: EventType.TOOL_CALL_RESULT,\n toolCallId: resultToolId,\n messageId: toolResultMessageId,\n content: toolResultContent,\n };\n\n // Splice point 3 of 4: append the ToolMessage to the running\n // snapshot so the frontend can pair call + result.\n if (emitMessagesSnapshot && !behavior?.skipMessagesSnapshot) {\n snapshotMessages.push({\n id: toolResultMessageId,\n role: \"tool\",\n content: toolResultContent,\n toolCallId: resultToolId,\n } as AguiToolMessage);\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n }\n\n const resultContext: ToolResultContext = {\n inputData,\n toolName,\n toolUseId: resultToolId,\n toolInput,\n argsStr: toolArgs ?? \"{}\",\n resultData,\n messageId,\n ...buildContextExtras(inputData),\n };\n\n if (behavior?.stateFromResult) {\n try {\n const snapshot = await maybeAwait(\n behavior.stateFromResult(resultContext),\n );\n if (snapshot) {\n Object.assign(currentState, snapshot);\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} stateFromResult failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateFromResult\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n }\n\n if (behavior?.customResultHandler) {\n try {\n for await (const customEvent of behavior.customResultHandler(\n resultContext,\n )) {\n if (customEvent) yield customEvent;\n }\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} customResultHandler failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"customResultHandler\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n }\n\n if (behavior?.stopStreamingAfterResult) {\n stopTextStreaming = true;\n if (messageStarted) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId };\n messageStarted = false;\n // Splice point 4 of 4 (early-exit): commit accumulated\n // assistant text into the snapshot.\n if (emitMessagesSnapshot && accumulatedText) {\n snapshotMessages.push({\n id: messageId,\n role: \"assistant\",\n content: accumulatedText,\n } as AguiAssistantMessage);\n accumulatedText = \"\";\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n }\n }\n this._log.debug(\n `${LOG_PREFIX} Breaking event stream: stopStreamingAfterResult behavior triggered ` +\n `(threadId=${inputData.threadId}, toolName=${toolName})`,\n );\n haltEventStream = true;\n break;\n }\n continue;\n }\n\n // Tools can yield state updates mid-execution as toolStreamEvent.\n if (kind === \"toolStreamEvent\") {\n const stream = event as unknown as { data?: unknown };\n const data = stream.data;\n if (data && typeof data === \"object\" && \"state\" in data) {\n yield {\n type: EventType.STATE_SNAPSHOT,\n snapshot: (data as { state: Record<string, unknown> }).state,\n };\n }\n continue;\n }\n\n // Multi-agent events (only fire when `agent` is a Graph/Swarm —\n // also possible when an agent wraps a subgraph).\n const maEvent = event as unknown as {\n type?: string;\n nodeId?: string;\n nodeType?: string;\n source?: string;\n targets?: string[];\n };\n if (maEvent?.type === \"beforeNodeCallEvent\") {\n // stepName must match the paired afterNodeCallEvent below so\n // frontends can pair START/FINISH (events.mdx §StepFinished).\n yield {\n type: EventType.STEP_STARTED,\n stepName: `${maEvent.nodeType ?? \"agent\"}:${maEvent.nodeId ?? \"unknown\"}`,\n };\n continue;\n }\n if (maEvent?.type === \"afterNodeCallEvent\") {\n yield {\n type: EventType.STEP_FINISHED,\n stepName: `${maEvent.nodeType ?? \"agent\"}:${maEvent.nodeId ?? \"unknown\"}`,\n };\n continue;\n }\n if (maEvent?.type === \"multiAgentHandoffEvent\") {\n // Py wire shape: { from_nodes, to_nodes, message }. TS SDK gives\n // `source` + `targets`; wrap source in an array to preserve the\n // Py shape so downstream consumers don't need per-backend branching.\n const handoffMsg = (maEvent as { message?: string }).message;\n yield {\n type: EventType.CUSTOM,\n name: \"MultiAgentHandoff\",\n value: {\n from_nodes: maEvent.source ? [maEvent.source] : [],\n to_nodes: maEvent.targets ?? [],\n message: handoffMsg,\n },\n };\n continue;\n }\n // Ignore events we don't translate (BeforeInvocationEvent,\n // ModelStreamEventHook wrappers, etc.).\n }\n } finally {\n // Consumer bailed (client disconnect, frontend-tool halt, error).\n // Fire the abort signal so Strands stops its Bedrock fetch at the\n // next checkpoint, then drain the generator so cleanup hooks run.\n try {\n runAbort.abort();\n } catch {\n // ignore\n }\n try {\n await agentStream.return(undefined as never);\n } catch {\n // ignore — cancellation typically surfaces as CancelledError\n }\n }\n\n if (reasoningStarted) {\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId!,\n };\n yield { type: EventType.REASONING_END, messageId: reasoningMessageId! };\n }\n\n if (messageStarted) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId };\n // Splice point 4 of 4 (terminal): commit the final assistant text\n // turn into the snapshot.\n if (emitMessagesSnapshot && accumulatedText) {\n snapshotMessages.push({\n id: messageId,\n role: \"assistant\",\n content: accumulatedText,\n } as AguiAssistantMessage);\n accumulatedText = \"\";\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: snapshotMessages.slice(),\n };\n }\n }\n\n // Final state snapshot with `currentState` verbatim. Unlike the initial\n // snapshot this is not filtered — the initial filter exists only to\n // protect frontends that don't recognise the \"tool\" role.\n yield { type: EventType.STATE_SNAPSHOT, snapshot: currentState };\n\n // Interrupt-variant RUN_FINISHED. The STATE_SNAPSHOT +\n // MESSAGES_SNAPSHOT above precede this per interrupts.mdx §\"State at\n // the interrupt boundary\". IDs are recorded on\n // `_pendingInterruptsByThread` for the `run()` resume gate.\n if (finalAgentResult?.stopReason === \"interrupt\") {\n const strandsInterrupts = finalAgentResult.interrupts ?? [];\n if (strandsInterrupts.length > 0) {\n const interruptIds = strandsInterrupts.map((i) => i.id);\n this._pendingInterruptsByThread.set(threadId, new Set(interruptIds));\n yield {\n type: EventType.RUN_FINISHED,\n threadId: inputData.threadId,\n runId: inputData.runId,\n outcome: {\n type: \"interrupt\",\n interrupts: strandsInterrupts.map(strandsInterruptToAgui),\n },\n };\n return;\n }\n }\n\n yield {\n type: EventType.RUN_FINISHED,\n threadId: inputData.threadId,\n runId: inputData.runId,\n };\n } catch (e) {\n const code =\n e instanceof TypeError || e instanceof ReferenceError\n ? \"ADAPTER_BUG\"\n : \"STRANDS_ERROR\";\n this._log.error(`${LOG_PREFIX} _runSingleAgent failed:`, e);\n yield _runError(_errorMessage(e), code);\n }\n }\n\n /**\n * Legacy burst path for tool calls — invoked when the Strands SDK delivers\n * a complete `ToolUseBlock` or when a `ToolBehavior.argsStreamer` takes\n * over args emission at contentBlockStop.\n *\n * The streaming path inside `_runSingleAgent` handles the common case\n * directly; this helper handles continuation turns and custom streamers.\n *\n * Getters/setters surface the caller's local variables because JS closures\n * capture by reference only for `const` / `let` in scope — an object of\n * mutable fields would work but would require threading `state` through\n * `_runSingleAgent`'s long body.\n */\n private async *_emitToolCall(ctx: {\n inputData: RunAgentInput;\n toolUseId: string;\n isFrontendTool: boolean;\n pendingToolResultIds: Set<string>;\n getMessageId: () => string;\n setMessageId: (id: string) => void;\n getMessageStarted: () => boolean;\n setMessageStarted: (v: boolean) => void;\n getAccumulatedText: () => string;\n setAccumulatedText: (v: string) => void;\n snapshotMessages: AguiMessage[];\n emitMessagesSnapshot: boolean;\n toolCallsSeen: Map<string, SeenToolCall>;\n currentState: Record<string, unknown>;\n onPendingHalt: () => void;\n }): AsyncGenerator<BaseEvent, void, void> {\n const entry = ctx.toolCallsSeen.get(ctx.toolUseId);\n if (!entry || entry.emitted) return;\n entry.emitted = true;\n const toolName = entry.name;\n const argsStr = entry.args;\n const toolInput = entry.input;\n const behavior = this.config.toolBehaviors?.[toolName];\n const isPending = ctx.pendingToolResultIds.has(ctx.toolUseId);\n\n const callContext: ToolCallContext = {\n inputData: ctx.inputData,\n toolName,\n toolUseId: ctx.toolUseId,\n toolInput,\n argsStr,\n ...buildContextExtras(ctx.inputData),\n };\n\n // Continuation turn — tool already resolved in conversation history.\n // Don't re-emit wire events, but fire state callbacks so derived state\n // stays consistent.\n if (isPending) {\n if (behavior?.stateFromArgs) {\n try {\n const snapshot = await maybeAwait(\n behavior.stateFromArgs(callContext),\n );\n if (snapshot) {\n Object.assign(ctx.currentState, snapshot);\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} stateFromArgs failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateFromArgs\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n }\n return;\n }\n\n // stateFromArgs BEFORE TOOL_CALL_START seeds the frontend's derived\n // state before the predict_state buffer opens.\n if (behavior?.stateFromArgs) {\n try {\n const snapshot = await maybeAwait(behavior.stateFromArgs(callContext));\n if (snapshot) {\n Object.assign(ctx.currentState, snapshot);\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n } catch (e) {\n this._log.error(\n `${LOG_PREFIX} stateFromArgs failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"stateFromArgs\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n }\n\n if (behavior) {\n const predict = normalizePredictState(behavior.predictState).map(\n predictStateMappingToPayload,\n );\n if (predict.length > 0) {\n yield { type: EventType.CUSTOM, name: \"PredictState\", value: predict };\n }\n }\n\n // Close any open assistant text turn and commit its content to the\n // snapshot before rotating message_id.\n if (ctx.getMessageStarted()) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId: ctx.getMessageId() };\n const acc = ctx.getAccumulatedText();\n if (ctx.emitMessagesSnapshot && acc) {\n ctx.snapshotMessages.push({\n id: ctx.getMessageId(),\n role: \"assistant\",\n content: acc,\n } as AguiAssistantMessage);\n ctx.setAccumulatedText(\"\");\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: ctx.snapshotMessages.slice(),\n };\n }\n ctx.setMessageStarted(false);\n ctx.setMessageId(uuid());\n }\n\n yield {\n type: EventType.TOOL_CALL_START,\n toolCallId: ctx.toolUseId,\n toolCallName: toolName,\n parentMessageId: ctx.getMessageId(),\n };\n\n let streamerFailed = false;\n if (behavior?.argsStreamer) {\n try {\n for await (const chunk of behavior.argsStreamer(callContext)) {\n if (chunk == null) continue;\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: ctx.toolUseId,\n delta: String(chunk),\n };\n }\n } catch (e) {\n streamerFailed = true;\n this._log.error(\n `${LOG_PREFIX} argsStreamer failed for ${toolName}:`,\n e,\n );\n yield {\n type: EventType.CUSTOM,\n name: \"hook_error\",\n value: {\n hook: \"argsStreamer\",\n tool: toolName,\n error: _errorMessage(e),\n },\n };\n }\n } else {\n yield {\n type: EventType.TOOL_CALL_ARGS,\n toolCallId: ctx.toolUseId,\n delta: argsStr,\n };\n }\n\n if (streamerFailed) {\n yield { type: EventType.TOOL_CALL_END, toolCallId: ctx.toolUseId };\n return;\n }\n\n yield { type: EventType.TOOL_CALL_END, toolCallId: ctx.toolUseId };\n\n // Splice point 2 of 4: append the assistant tool-call entry to the\n // snapshot, then rotate message_id.\n if (ctx.emitMessagesSnapshot && !behavior?.skipMessagesSnapshot) {\n ctx.snapshotMessages.push({\n id: ctx.getMessageId(),\n role: \"assistant\",\n content: \"\",\n toolCalls: [\n {\n id: ctx.toolUseId,\n type: \"function\",\n function: {\n name: toolName || \"unknown\",\n arguments: argsStr || \"{}\",\n },\n },\n ],\n } as AguiAssistantMessage);\n yield {\n type: EventType.MESSAGES_SNAPSHOT,\n messages: ctx.snapshotMessages.slice(),\n };\n ctx.setMessageId(uuid());\n }\n\n if (ctx.isFrontendTool && !behavior?.continueAfterFrontendCall) {\n this._log.debug(\n `${LOG_PREFIX} Deferring halt after frontend tool call: ` +\n `toolName=${toolName}, toolCallId=${ctx.toolUseId}, threadId=${ctx.inputData.threadId}`,\n );\n ctx.onPendingHalt();\n }\n }\n\n /**\n * Orchestrator-mode run loop. TypeScript-only: drives a `Graph` or `Swarm`\n * `.stream()` call and translates multi-agent events. Per-thread caching,\n * session managers, and proxy-tool sync don't apply.\n */\n private async *_runOrchestrator(\n inputData: RunAgentInput,\n ): AsyncGenerator<BaseEvent, void, void> {\n yield _runStarted(inputData);\n try {\n if (inputData.state && typeof inputData.state === \"object\") {\n const snapshot: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(\n inputData.state as Record<string, unknown>,\n )) {\n if (k !== \"messages\") snapshot[k] = v;\n }\n yield { type: EventType.STATE_SNAPSHOT, snapshot };\n }\n\n // Orchestrators take string | ContentBlock[] (MultiAgentInput); extract\n // text from the last user/tool turn.\n let prompt = \"Hello\";\n if (inputData.messages) {\n for (let i = inputData.messages.length - 1; i >= 0; i--) {\n const msg = inputData.messages[i];\n if (!msg) break;\n if (\n (msg.role === \"user\" || msg.role === \"tool\") &&\n msg.content != null\n ) {\n prompt =\n typeof msg.content === \"string\"\n ? msg.content\n : flattenContentToText(msg.content);\n break;\n }\n }\n }\n\n let messageId = uuid();\n let messageStarted = false;\n let reasoningStarted = false;\n let reasoningMessageId: string | undefined;\n\n const orchestratorStream = this._orchestrator!.stream(prompt);\n try {\n for await (const rawEvent of orchestratorStream) {\n const event = unwrapStrandsEvent(rawEvent);\n const kind = getEventKind(event);\n\n if (kind === \"beforeNodeCallEvent\") {\n const ev = event as { nodeId?: string; nodeType?: string };\n // stepName must match the paired afterNodeCallEvent below so\n // frontends can pair START/FINISH (events.mdx §StepFinished).\n yield {\n type: EventType.STEP_STARTED,\n stepName: `${ev.nodeType ?? \"agent\"}:${ev.nodeId ?? \"unknown\"}`,\n };\n continue;\n }\n if (kind === \"afterNodeCallEvent\") {\n const ev = event as { nodeId?: string; nodeType?: string };\n if (messageStarted) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId };\n messageStarted = false;\n messageId = uuid();\n }\n if (reasoningStarted) {\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId!,\n };\n yield {\n type: EventType.REASONING_END,\n messageId: reasoningMessageId!,\n };\n reasoningStarted = false;\n reasoningMessageId = undefined;\n }\n yield {\n type: EventType.STEP_FINISHED,\n stepName: `${ev.nodeType ?? \"agent\"}:${ev.nodeId ?? \"unknown\"}`,\n };\n continue;\n }\n if (kind === \"multiAgentHandoffEvent\") {\n const ev = event as {\n source?: string;\n targets?: string[];\n message?: string;\n };\n yield {\n type: EventType.CUSTOM,\n name: \"MultiAgentHandoff\",\n value: {\n from_nodes: ev.source ? [ev.source] : [],\n to_nodes: ev.targets ?? [],\n message: ev.message,\n },\n };\n continue;\n }\n if (kind === \"nodeStreamUpdateEvent\") {\n // Inner event is the agent-level event emitted by the wrapped agent.\n const ev = event as {\n inner?: { source?: string; event?: unknown };\n };\n const inner = ev.inner?.event\n ? unwrapStrandsEvent(ev.inner.event)\n : undefined;\n if (getEventKind(inner) === \"modelContentBlockDeltaEvent\") {\n const delta = (\n inner as { delta?: { type?: string; text?: string } }\n ).delta;\n if (delta?.type === \"textDelta\" && delta.text) {\n if (!messageStarted) {\n yield {\n type: EventType.TEXT_MESSAGE_START,\n messageId,\n role: \"assistant\",\n };\n messageStarted = true;\n }\n yield {\n type: EventType.TEXT_MESSAGE_CONTENT,\n messageId,\n delta: delta.text,\n };\n } else if (delta?.type === \"reasoningContentDelta\" && delta.text) {\n if (!reasoningStarted) {\n reasoningMessageId = uuid();\n yield {\n type: EventType.REASONING_START,\n messageId: reasoningMessageId,\n };\n yield {\n type: EventType.REASONING_MESSAGE_START,\n messageId: reasoningMessageId,\n role: \"reasoning\",\n };\n reasoningStarted = true;\n }\n yield {\n type: EventType.REASONING_MESSAGE_CONTENT,\n messageId: reasoningMessageId!,\n delta: delta.text,\n };\n }\n }\n continue;\n }\n }\n } finally {\n try {\n await orchestratorStream.return(undefined as never);\n } catch {\n // ignore\n }\n }\n\n if (messageStarted) {\n yield { type: EventType.TEXT_MESSAGE_END, messageId };\n }\n if (reasoningStarted) {\n yield {\n type: EventType.REASONING_MESSAGE_END,\n messageId: reasoningMessageId!,\n };\n yield { type: EventType.REASONING_END, messageId: reasoningMessageId! };\n }\n yield { type: EventType.STATE_SNAPSHOT, snapshot: {} };\n yield {\n type: EventType.RUN_FINISHED,\n threadId: inputData.threadId,\n runId: inputData.runId,\n };\n } catch (e) {\n const code =\n e instanceof TypeError || e instanceof ReferenceError\n ? \"ADAPTER_BUG\"\n : \"STRANDS_ERROR\";\n this._log.error(`${LOG_PREFIX} _runOrchestrator failed:`, e);\n yield _runError(_errorMessage(e), code);\n }\n }\n\n private _buildThreadAgentConfig(\n sessionManager?: SessionManager,\n seedMessages?: AgentConfig[\"messages\"],\n ): AgentConfig {\n const t = this._templateFields;\n const cfg: AgentConfig = {\n model: t.model,\n tools: t.tools.slice(),\n printer: false,\n };\n if (t.systemPrompt !== undefined) cfg.systemPrompt = t.systemPrompt;\n if (t.name !== undefined) cfg.name = t.name;\n if (t.description !== undefined) cfg.description = t.description;\n if (t.id !== undefined) cfg.id = t.id;\n if (t.appState !== undefined) cfg.appState = t.appState;\n if (t.modelState !== undefined) cfg.modelState = t.modelState;\n if (t.traceAttributes !== undefined)\n cfg.traceAttributes = t.traceAttributes;\n if (t.structuredOutputSchema !== undefined)\n cfg.structuredOutputSchema = t.structuredOutputSchema;\n if (t.toolExecutor !== undefined) cfg.toolExecutor = t.toolExecutor;\n if (sessionManager) cfg.sessionManager = sessionManager;\n if (seedMessages && seedMessages.length > 0) cfg.messages = seedMessages;\n // Only forward plugins when the caller supplied them explicitly. Passing\n // `plugins: []` risks being interpreted by a future SDK as \"disable\n // default plugins\".\n if (this._plugins.length > 0) cfg.plugins = [...this._plugins];\n return cfg;\n }\n}\n\n// ---------- TypeScript-only helpers (no Python equivalent) ----------\n\n/**\n * Async mutex modelled on Python's `asyncio.Lock`. Serializes first-time\n * thread initialization so concurrent requests for the same new threadId\n * don't both construct a per-thread agent.\n */\nclass AsyncMutex {\n private _tail: Promise<void> = Promise.resolve();\n async acquire(): Promise<() => void> {\n let release!: () => void;\n const next = new Promise<void>((resolve) => {\n release = resolve;\n });\n const previous = this._tail;\n this._tail = next;\n await previous;\n return release;\n }\n}\n\nfunction _runStarted(input: RunAgentInput): BaseEvent {\n return {\n type: EventType.RUN_STARTED,\n threadId: input.threadId,\n runId: input.runId,\n };\n}\n\nfunction _runError(message: string, code: string): BaseEvent {\n return { type: EventType.RUN_ERROR, message, code };\n}\n\n/** Non-empty `resume[]` entries, or `[]` if missing. */\nfunction resolveResumeEntries(input: RunAgentInput): ResumeEntry[] {\n const resume = (input as { resume?: ResumeEntry[] }).resume;\n return Array.isArray(resume) && resume.length > 0 ? resume : [];\n}\n\n/** AG-UI `ResumeEntry` → Strands `InterruptResponseContent.response`. */\nfunction toResumeResponse(entry: ResumeEntry): unknown {\n if (entry.status === \"cancelled\") {\n return { status: \"cancelled\" };\n }\n return entry.payload as unknown;\n}\n\n/** Strands `Interrupt` → AG-UI `Interrupt`. */\nfunction strandsInterruptToAgui(interrupt: StrandsInterrupt): AguiInterrupt {\n const reasonRaw = interrupt.reason;\n const reason =\n typeof reasonRaw === \"string\" && reasonRaw.length > 0\n ? reasonRaw\n : \"confirmation\";\n const out: AguiInterrupt = { id: interrupt.id, reason };\n if (typeof reasonRaw === \"string\" && reasonRaw.length > 0) {\n out.message = reasonRaw;\n } else if (reasonRaw != null) {\n try {\n out.message = JSON.stringify(reasonRaw);\n } catch {\n // non-serializable reason; leave message unset\n }\n }\n out.metadata = { strandsName: interrupt.name };\n return out;\n}\n\nfunction getEventKind(event: unknown): string | undefined {\n if (event && typeof event === \"object\" && \"type\" in event) {\n const t = (event as { type: unknown }).type;\n return typeof t === \"string\" ? t : undefined;\n }\n return undefined;\n}\n\n/**\n * Unwrap wrapper hook events the Strands v1 SDK uses to decorate raw model,\n * content-block, and tool-stream events:\n * `ModelStreamUpdateEvent → .event`\n * `ContentBlockEvent → .contentBlock`\n * `ToolStreamUpdateEvent → .event` (inner `ToolStreamEvent` carries\n * the per-yield payload a tool's async generator produces)\n * Anything else passes through.\n */\nfunction unwrapStrandsEvent(event: unknown): unknown {\n if (!event || typeof event !== \"object\") return event;\n const kind = (event as { type?: unknown }).type;\n if (kind === \"modelStreamUpdateEvent\" && \"event\" in event) {\n return (event as { event: unknown }).event;\n }\n if (kind === \"toolStreamUpdateEvent\" && \"event\" in event) {\n return (event as { event: unknown }).event;\n }\n if (kind === \"contentBlockEvent\" && \"contentBlock\" in event) {\n return (event as { contentBlock: unknown }).contentBlock;\n }\n return event;\n}\n\n/**\n * Transform explicit START/CONTENT/END triples into self-expanding chunk\n * equivalents, driven by `StrandsAgentConfig.emitChunkEvents`.\n *\n * Per `concepts/events.mdx` (TextMessageChunk):\n * - First chunk carries `messageId` (+ optional `role`) — the client\n * transformer auto-emits `TEXT_MESSAGE_START`.\n * - Each chunk with a `delta` auto-emits `TEXT_MESSAGE_CONTENT`.\n * - `TEXT_MESSAGE_END` is auto-emitted by the client transformer when\n * ids change or the stream ends — we drop our explicit END event.\n *\n * Same pattern for `TOOL_CALL_*` and `REASONING_MESSAGE_*`.\n */\nasync function* collapseToChunkEvents(\n source: AsyncGenerator<BaseEvent, void, void>,\n): AsyncGenerator<BaseEvent, void, void> {\n for await (const event of source) {\n switch (event.type) {\n case EventType.TEXT_MESSAGE_START: {\n const e = event as { messageId?: string; role?: string };\n yield {\n type: EventType.TEXT_MESSAGE_CHUNK,\n messageId: e.messageId,\n role: e.role,\n } as BaseEvent;\n break;\n }\n case EventType.TEXT_MESSAGE_CONTENT: {\n const e = event as { messageId?: string; delta?: string };\n yield {\n type: EventType.TEXT_MESSAGE_CHUNK,\n messageId: e.messageId,\n delta: e.delta,\n } as BaseEvent;\n break;\n }\n case EventType.TEXT_MESSAGE_END:\n break;\n case EventType.TOOL_CALL_START: {\n const e = event as {\n toolCallId?: string;\n toolCallName?: string;\n parentMessageId?: string;\n };\n yield {\n type: EventType.TOOL_CALL_CHUNK,\n toolCallId: e.toolCallId,\n toolCallName: e.toolCallName,\n parentMessageId: e.parentMessageId,\n } as BaseEvent;\n break;\n }\n case EventType.TOOL_CALL_ARGS: {\n const e = event as { toolCallId?: string; delta?: string };\n yield {\n type: EventType.TOOL_CALL_CHUNK,\n toolCallId: e.toolCallId,\n delta: e.delta,\n } as BaseEvent;\n break;\n }\n case EventType.TOOL_CALL_END:\n break;\n case EventType.REASONING_MESSAGE_START: {\n const e = event as { messageId?: string };\n yield {\n type: EventType.REASONING_MESSAGE_CHUNK,\n messageId: e.messageId,\n } as BaseEvent;\n break;\n }\n case EventType.REASONING_MESSAGE_CONTENT: {\n const e = event as { messageId?: string; delta?: string };\n yield {\n type: EventType.REASONING_MESSAGE_CHUNK,\n messageId: e.messageId,\n delta: e.delta,\n } as BaseEvent;\n break;\n }\n case EventType.REASONING_MESSAGE_END:\n break;\n default:\n yield event;\n }\n }\n}\n\n/**\n * Build the message-history seed handed to `AgentConfig.messages` on\n * cold-cache agent creation. TypeScript-only: the Python SDK mutates\n * `Agent.messages` in place after construction via\n * `_buildStrandsHistory`, whereas the TS SDK consumes a seed at\n * construction time.\n *\n * - Normal run (tail is a `user` turn): seed everything except the final\n * user turn; the final turn is passed to `agent.stream(...)` as the\n * fresh prompt.\n * - Continuation run (tail is a `tool` message) or orphan tail: seed the\n * entire history so the agent sees its own tool call + result before the\n * synthetic continuation prompt fires.\n *\n * Returns `undefined` when the resulting seed would be empty or would\n * start with an `assistant` turn (Bedrock rejects assistant-first history).\n */\nexport async function buildStrandsSeed(\n messages: AguiMessage[],\n log?: Logger,\n): Promise<AgentConfig[\"messages\"]> {\n if (messages.length === 0) return undefined;\n\n let sliceEnd = messages.length;\n const tail = messages[messages.length - 1];\n if (tail?.role === \"user\") sliceEnd = messages.length - 1;\n if (sliceEnd <= 0) return undefined;\n\n const seed = await convertMessagesForStrandsSeed(\n messages.slice(0, sliceEnd),\n log,\n );\n if (seed.length === 0) return undefined;\n\n // Bedrock requires history to start with `user`; trim any leading\n // assistant turns (rare, e.g. bot-initiated UIs).\n while (seed.length > 0 && seed[0]?.role !== \"user\") seed.shift();\n if (seed.length === 0) return undefined;\n\n return seed as unknown as AgentConfig[\"messages\"];\n}\n\n/**\n * Convert AG-UI messages into the `MessageData` shape `AgentConfig.messages`\n * accepts on cold-cache agent construction. Similar in spirit to\n * `_buildStrandsHistory` but drops orphan tool turns (Bedrock rejects them).\n */\nexport async function convertMessagesForStrandsSeed(\n messages: AguiMessage[],\n log?: Logger,\n): Promise<Array<{ role: \"user\" | \"assistant\"; content: unknown[] }>> {\n const out: Array<{ role: \"user\" | \"assistant\"; content: unknown[] }> = [];\n let pendingToolCalls: Map<string, string> | null = null;\n let pendingToolResults: unknown[] | null = null;\n\n const flushToolResults = (): void => {\n if (pendingToolResults && pendingToolResults.length > 0) {\n out.push({ role: \"user\", content: pendingToolResults });\n }\n pendingToolResults = null;\n pendingToolCalls = null;\n };\n\n for (const msg of messages) {\n const role = msg.role;\n if (role === \"system\" || role === \"developer\") continue;\n\n if (role === \"assistant\") {\n flushToolResults();\n const toolCalls = (\n msg as {\n toolCalls?: {\n id: string;\n function: { name: string; arguments: string };\n }[];\n }\n ).toolCalls;\n const content: unknown[] = [];\n if (typeof msg.content === \"string\" && msg.content.length > 0) {\n content.push({ text: msg.content });\n } else if (Array.isArray(msg.content)) {\n // Assistant-side multimodal history is rare — preserve text only.\n for (const c of msg.content) {\n if (c && typeof c === \"object\" && \"text\" in (c as object)) {\n content.push({ text: (c as { text: string }).text });\n }\n }\n }\n if (toolCalls && toolCalls.length > 0) {\n pendingToolCalls = new Map();\n for (const tc of toolCalls) {\n if (!tc?.id || !tc.function?.name) continue;\n let input: unknown = {};\n try {\n input = tc.function.arguments\n ? JSON.parse(tc.function.arguments)\n : {};\n } catch (e) {\n log?.warn(\n `${LOG_PREFIX} seed tool args JSON parse failed for ${tc.function.name}; using raw string`,\n e,\n );\n input = tc.function.arguments ?? {};\n }\n content.push({\n toolUse: { name: tc.function.name, toolUseId: tc.id, input },\n });\n pendingToolCalls.set(tc.id, tc.function.name);\n }\n }\n if (content.length === 0) continue;\n out.push({ role: \"assistant\", content });\n continue;\n }\n\n if (role === \"tool\") {\n const toolCallId = (msg as { toolCallId?: string }).toolCallId;\n if (!toolCallId || !pendingToolCalls || !pendingToolCalls.has(toolCallId))\n continue;\n const rawContent: unknown = (msg as { content?: unknown }).content;\n const textContent =\n typeof rawContent === \"string\"\n ? rawContent\n : Array.isArray(rawContent)\n ? (rawContent as unknown[])\n .map((c) =>\n c && typeof c === \"object\" && \"text\" in (c as object)\n ? ((c as { text?: string }).text ?? \"\")\n : \"\",\n )\n .join(\"\")\n : \"\";\n pendingToolResults ??= [];\n pendingToolResults.push({\n toolResult: {\n toolUseId: toolCallId,\n status: \"success\" as const,\n content: [{ text: textContent }],\n },\n });\n continue;\n }\n\n // role === \"user\"\n flushToolResults();\n const content: unknown[] = [];\n const rawUserContent = msg.content;\n if (typeof rawUserContent === \"string\") {\n if (rawUserContent.length > 0) content.push({ text: rawUserContent });\n } else if (Array.isArray(rawUserContent)) {\n const hasMedia = rawUserContent.some((c: unknown) => {\n if (!c || typeof c !== \"object\") return false;\n const type = (c as { type?: string }).type;\n return (\n type === \"image\" ||\n type === \"audio\" ||\n type === \"video\" ||\n type === \"document\"\n );\n });\n if (hasMedia) {\n try {\n const blocks = await convertAguiContentToStrands(\n rawUserContent as never,\n log,\n );\n for (const b of blocks) {\n if (b instanceof TextBlock) {\n content.push({ text: b.text });\n } else {\n // Image/Video/Document `toJSON()` emits the wrapped\n // discriminated union the MessageData schema expects.\n const serialised =\n typeof (b as { toJSON?: () => unknown }).toJSON === \"function\"\n ? (b as { toJSON: () => unknown }).toJSON()\n : b;\n content.push(serialised);\n }\n }\n } catch (e) {\n (log ?? DEFAULT_LOGGER).warn(\n `${LOG_PREFIX} seed multimodal conversion failed; dropping attachments for this turn`,\n e,\n );\n const text = flattenContentToText(rawUserContent as never);\n if (text.length > 0) content.push({ text });\n }\n } else {\n for (const c of rawUserContent) {\n if (c && typeof c === \"object\" && \"text\" in (c as object)) {\n content.push({ text: (c as { text: string }).text });\n }\n }\n }\n }\n if (content.length === 0) continue;\n out.push({ role: \"user\", content });\n }\n\n flushToolResults();\n return out;\n}\n","/** AWS Strands integration for AG-UI. */\n\nexport {\n StrandsAgent,\n buildSnapshotMessages,\n buildStrandsSeed,\n convertMessagesForStrandsSeed,\n} from \"./agent\";\nexport type { StrandsAgentOptions } from \"./agent\";\n\nexport {\n createProxyTool,\n syncProxyTools,\n isProxyTool,\n} from \"./client-proxy-tool\";\nexport type { StrandsToolRegistry } from \"./client-proxy-tool\";\n\nexport { convertAguiContentToStrands, flattenContentToText } from \"./utils\";\n\n// Server-side Express transport helpers (`createStrandsApp`,\n// `addStrandsExpressEndpoint`, `addPing`, `addCapabilities`,\n// `capabilitiesFor`, `DEFAULT_CAPABILITIES`, and associated types) live at\n// `@ag-ui/aws-strands/server`. Keeping them off the main entry lets\n// client-side bundlers (Next.js, Vite, etc.) trace this package without\n// pulling Express / cors into the browser graph.\n\nexport type { Logger } from \"./logger\";\n\nexport { buildContextExtras } from \"./config\";\nexport type {\n StrandsAgentConfig,\n ToolBehavior,\n ToolCallContext,\n ToolCallContextExtras,\n ToolResultContext,\n PredictStateMapping,\n SessionManagerProvider,\n StateContextBuilder,\n StateFromArgs,\n StateFromResult,\n CustomResultHandler,\n ArgsStreamer,\n MaybePromise,\n StatePayload,\n} from \"./config\";\n\n// Thin HttpAgent subclass for AG-UI clients pointing at a Strands endpoint.\nimport { HttpAgent } from \"@ag-ui/client\";\nexport class AWSStrandsAgent extends HttpAgent {}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { t as StrandsAgent } from "./agent-Dp45JIaO.mjs";
|
|
2
|
+
import * as express0 from "express";
|
|
3
|
+
import { Express } from "express";
|
|
4
|
+
|
|
5
|
+
//#region src/endpoint.d.ts
|
|
6
|
+
interface AddStrandsEndpointOptions {
|
|
7
|
+
path: string;
|
|
8
|
+
}
|
|
9
|
+
/** Add a Strands agent endpoint to an Express app. */
|
|
10
|
+
declare function addStrandsExpressEndpoint(app: Express, agent: StrandsAgent, options: AddStrandsEndpointOptions): void;
|
|
11
|
+
/** Add a ping endpoint returning `{status: "healthy"}`. */
|
|
12
|
+
declare function addPing(app: Express, path: string): void;
|
|
13
|
+
/**
|
|
14
|
+
* Static description of what this adapter actually supports. Every event
|
|
15
|
+
* family here can be observed on the wire; anything missing is either not
|
|
16
|
+
* emitted by this adapter (e.g. `ACTIVITY_*`, `RAW`) or only emitted in
|
|
17
|
+
* specific configurations (the `*_CHUNK` events, gated by
|
|
18
|
+
* `emitChunkEvents` — use {@link capabilitiesFor} to derive the matrix
|
|
19
|
+
* from a concrete agent and pick those flags up automatically).
|
|
20
|
+
*
|
|
21
|
+
* Exported as a plain object so consumers can fold overrides in — for
|
|
22
|
+
* example, advertising `events.ACTIVITY_SNAPSHOT: true` after wiring a
|
|
23
|
+
* `customResultHandler` that emits those events themselves.
|
|
24
|
+
*/
|
|
25
|
+
interface StrandsAguiCapabilities {
|
|
26
|
+
/** Semver of the AG-UI contract surface this adapter targets. */
|
|
27
|
+
protocol: string;
|
|
28
|
+
/** Content types the HTTP endpoint can stream. */
|
|
29
|
+
transports: {
|
|
30
|
+
sse: boolean;
|
|
31
|
+
protobuf: boolean;
|
|
32
|
+
websocket: boolean;
|
|
33
|
+
};
|
|
34
|
+
/** Event families the adapter emits. Per-event flags, not categories. */
|
|
35
|
+
events: {
|
|
36
|
+
RUN_STARTED: boolean;
|
|
37
|
+
RUN_FINISHED: boolean;
|
|
38
|
+
RUN_ERROR: boolean;
|
|
39
|
+
TEXT_MESSAGE_START: boolean;
|
|
40
|
+
TEXT_MESSAGE_CONTENT: boolean;
|
|
41
|
+
TEXT_MESSAGE_END: boolean;
|
|
42
|
+
TEXT_MESSAGE_CHUNK: boolean;
|
|
43
|
+
TOOL_CALL_START: boolean;
|
|
44
|
+
TOOL_CALL_ARGS: boolean;
|
|
45
|
+
TOOL_CALL_END: boolean;
|
|
46
|
+
TOOL_CALL_RESULT: boolean;
|
|
47
|
+
TOOL_CALL_CHUNK: boolean;
|
|
48
|
+
STATE_SNAPSHOT: boolean;
|
|
49
|
+
STATE_DELTA: boolean;
|
|
50
|
+
MESSAGES_SNAPSHOT: boolean;
|
|
51
|
+
STEP_STARTED: boolean;
|
|
52
|
+
STEP_FINISHED: boolean;
|
|
53
|
+
REASONING_START: boolean;
|
|
54
|
+
REASONING_MESSAGE_START: boolean;
|
|
55
|
+
REASONING_MESSAGE_CONTENT: boolean;
|
|
56
|
+
REASONING_MESSAGE_END: boolean;
|
|
57
|
+
REASONING_MESSAGE_CHUNK: boolean;
|
|
58
|
+
REASONING_ENCRYPTED_VALUE: boolean;
|
|
59
|
+
REASONING_END: boolean;
|
|
60
|
+
CUSTOM: boolean;
|
|
61
|
+
ACTIVITY_SNAPSHOT: boolean;
|
|
62
|
+
ACTIVITY_DELTA: boolean;
|
|
63
|
+
RAW: boolean;
|
|
64
|
+
};
|
|
65
|
+
/** Protocol feature flags advertised to the client. */
|
|
66
|
+
features: {
|
|
67
|
+
/** RunFinished.outcome interrupt + RunAgentInput.resume loop. */interrupts: boolean; /** Tool-call interrupts accept editedArgs in the resume payload. */
|
|
68
|
+
toolCallInterruptEditedArgs: boolean; /** Resumable streams with sequence numbers. Unsupported. */
|
|
69
|
+
resumableStreams: boolean; /** Adapter emits MESSAGES_SNAPSHOT at run lifecycle boundaries (Python parity). */
|
|
70
|
+
messagesSnapshot: boolean; /** State delta via RFC 6902 JSON Patch. Only when a customResultHandler emits them. */
|
|
71
|
+
stateDelta: boolean; /** Binary protobuf content negotiation (explicit Accept header). */
|
|
72
|
+
protobuf: boolean; /** Multiple sequential runs in one HTTP stream. One run per POST. */
|
|
73
|
+
multipleRunsPerStream: boolean;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/** Default capabilities advertised by {@link addCapabilities}. */
|
|
77
|
+
declare const DEFAULT_CAPABILITIES: StrandsAguiCapabilities;
|
|
78
|
+
/** One level of sub-field partiality — shallow `Partial<>` on nested objects. */
|
|
79
|
+
type StrandsAguiCapabilitiesOverrides = {
|
|
80
|
+
protocol?: StrandsAguiCapabilities["protocol"];
|
|
81
|
+
transports?: Partial<StrandsAguiCapabilities["transports"]>;
|
|
82
|
+
events?: Partial<StrandsAguiCapabilities["events"]>;
|
|
83
|
+
features?: Partial<StrandsAguiCapabilities["features"]>;
|
|
84
|
+
};
|
|
85
|
+
/**
|
|
86
|
+
* Derive capabilities from a concrete StrandsAgent instance, flipping the
|
|
87
|
+
* chunk-event flags based on whether the agent is configured to emit chunks.
|
|
88
|
+
* When chunks are on, the explicit triples are suppressed, so the advertised
|
|
89
|
+
* matrix reflects what the client will actually observe.
|
|
90
|
+
*/
|
|
91
|
+
declare function capabilitiesFor(agent: {
|
|
92
|
+
config: {
|
|
93
|
+
emitChunkEvents?: boolean;
|
|
94
|
+
};
|
|
95
|
+
}, overrides?: StrandsAguiCapabilitiesOverrides): StrandsAguiCapabilities;
|
|
96
|
+
/**
|
|
97
|
+
* Add a capabilities-advertisement endpoint.
|
|
98
|
+
*
|
|
99
|
+
* Frontends can GET this path to discover which AG-UI event families and
|
|
100
|
+
* protocol features the adapter supports, without having to probe empirically.
|
|
101
|
+
*
|
|
102
|
+
* Two forms:
|
|
103
|
+
* - `addCapabilities(app, path, overrides?)` — static matrix (back-compat).
|
|
104
|
+
* - `addCapabilities(app, path, { agent })` — derives the matrix from a live
|
|
105
|
+
* `StrandsAgent`, picking up `emitChunkEvents` automatically.
|
|
106
|
+
*/
|
|
107
|
+
declare function addCapabilities(app: Express, path: string, capabilities?: StrandsAguiCapabilitiesOverrides | {
|
|
108
|
+
agent: {
|
|
109
|
+
config: {
|
|
110
|
+
emitChunkEvents?: boolean;
|
|
111
|
+
};
|
|
112
|
+
};
|
|
113
|
+
overrides?: StrandsAguiCapabilitiesOverrides;
|
|
114
|
+
}): void;
|
|
115
|
+
//#endregion
|
|
116
|
+
//#region src/server.d.ts
|
|
117
|
+
interface CreateStrandsAppOptions {
|
|
118
|
+
/** Path for the agent endpoint. Default `/`. */
|
|
119
|
+
path?: string;
|
|
120
|
+
/** Path for the ping endpoint. Pass `null` or `""` to disable. Default `/ping`. */
|
|
121
|
+
pingPath?: string | null;
|
|
122
|
+
/**
|
|
123
|
+
* Path for the capabilities endpoint. Pass `null` or `""` to disable.
|
|
124
|
+
* Default `/capabilities`.
|
|
125
|
+
*/
|
|
126
|
+
capabilitiesPath?: string | null;
|
|
127
|
+
/** Override capabilities advertised at {@link CreateStrandsAppOptions.capabilitiesPath}. */
|
|
128
|
+
capabilities?: StrandsAguiCapabilitiesOverrides;
|
|
129
|
+
/** Override CORS origin. Default `*` (wide-open, matches the Python adapter). */
|
|
130
|
+
corsOrigin?: string | string[] | boolean;
|
|
131
|
+
}
|
|
132
|
+
/** Create an Express app with a single Strands agent endpoint and optional ping endpoint. */
|
|
133
|
+
declare function createStrandsApp(agent: StrandsAgent, options?: CreateStrandsAppOptions): Promise<express0.Express>;
|
|
134
|
+
//#endregion
|
|
135
|
+
export { type AddStrandsEndpointOptions, CreateStrandsAppOptions, DEFAULT_CAPABILITIES, type StrandsAguiCapabilities, type StrandsAguiCapabilitiesOverrides, addCapabilities, addPing, addStrandsExpressEndpoint, capabilitiesFor, createStrandsApp };
|
|
136
|
+
//# sourceMappingURL=server.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.d.mts","names":[],"sources":["../src/endpoint.ts","../src/server.ts"],"mappings":";;;;;UAYiB,yBAAA;EACf,IAAA;AAAA;;iBAwDc,yBAAA,CACd,GAAA,EAAK,OAAA,EACL,KAAA,EAAO,YAAA,EACP,OAAA,EAAS,yBAAA;;iBA+IK,OAAA,CAAQ,GAAA,EAAK,OAAA,EAAS,IAAA;AAlJtC;;;;;;;;;;;;AAAA,UAoKiB,uBAAA;EAjKf;EAmKA,QAAA;EAnKkC;EAqKlC,UAAA;IAAc,GAAA;IAAc,QAAA;IAAmB,SAAA;EAAA;EAtBzB;EAwBtB,MAAA;IACE,WAAA;IACA,YAAA;IACA,SAAA;IACA,kBAAA;IACA,oBAAA;IACA,gBAAA;IACA,kBAAA;IACA,eAAA;IACA,cAAA;IACA,aAAA;IACA,gBAAA;IACA,eAAA;IACA,cAAA;IACA,WAAA;IACA,iBAAA;IACA,YAAA;IACA,aAAA;IACA,eAAA;IACA,uBAAA;IACA,yBAAA;IACA,qBAAA;IACA,uBAAA;IACA,yBAAA;IACA,aAAA;IACA,MAAA;IACA,iBAAA;IACA,cAAA;IACA,GAAA;EAAA;EAVA;EAaF,QAAA;IAXE,iEAaA,UAAA,WAXA;IAaA,2BAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,gBAAA,WAXA;IAaA,UAAA,WARA;IAUA,QAAA,WANA;IAQA,qBAAA;EAAA;AAAA;;cAKS,oBAAA,EAAsB,uBAAA;;KA6CvB,gCAAA;EACV,QAAA,GAAW,uBAAA;EACX,UAAA,GAAa,OAAA,CAAQ,uBAAA;EACrB,MAAA,GAAS,OAAA,CAAQ,uBAAA;EACjB,QAAA,GAAW,OAAA,CAAQ,uBAAA;AAAA;;;;;;;iBAyCL,eAAA,CACd,KAAA;EAAS,MAAA;IAAU,eAAA;EAAA;AAAA,GACnB,SAAA,GAAY,gCAAA,GACX,uBAAA;;;;;;;;;;;;iBA8Ba,eAAA,CACd,GAAA,EAAK,OAAA,EACL,IAAA,UACA,YAAA,GACI,gCAAA;EAEE,KAAA;IAAS,MAAA;MAAU,eAAA;IAAA;EAAA;EACnB,SAAA,GAAY,gCAAA;AAAA;;;UCpYH,uBAAA;EDuCV;ECrCL,IAAA;EDuCS;ECrCT,QAAA;EDqCkC;;;;EChClC,gBAAA;EDgCS;EC9BT,YAAA,GAAe,gCAAA;ED8BmB;EC5BlC,UAAA;AAAA;;iBAIoB,gBAAA,CACpB,KAAA,EAAO,YAAA,EACP,OAAA,GAAS,uBAAA,GACR,OAAA,CADoC,QAAA,CACV,OAAA"}
|