-
Notifications
You must be signed in to change notification settings - Fork 140
Feat/agui strands pattern #62
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
1a194ce
fix: restructure existing agent patterns and fix bugs
razkenari b0806f8
feat: add AG-UI agent patterns and frontend support
razkenari d59b600
Merge branch 'main' into feat/agui-strands-pattern
kaleko cde75f4
Update AGUI_INTEGRATION.md
kaleko File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,128 @@ | ||
| # AG-UI Protocol Integration | ||
|
|
||
| Guide for using the AG-UI (Agent-User Interaction) protocol patterns in FAST. | ||
|
|
||
| --- | ||
|
|
||
| ## Overview | ||
|
|
||
| [AG-UI](https://docs.ag-ui.com/concepts/overview) is an open protocol that defines a standard SSE event format for agent-to-frontend communication. Instead of each framework emitting its own event schema (Strands events, LangChain message chunks, etc.), AG-UI provides a unified event vocabulary: `TEXT_MESSAGE_CONTENT`, `TOOL_CALL_START`, `TOOL_CALL_ARGS`, `TOOL_CALL_RESULT`, `RUN_FINISHED`, and so on. | ||
|
|
||
| FAST includes two AG-UI agent patterns: | ||
|
|
||
| | Pattern | Framework | Location | | ||
| |---------|-----------|----------| | ||
| | `agui-strands-agent` | Strands + `ag-ui-strands` | `agent_patterns/agui-strands-agent/` | | ||
| | `agui-langgraph-agent` | LangGraph + `copilotkit` | `agent_patterns/agui-langgraph-agent/` | | ||
|
|
||
| Both patterns use `BedrockAgentCoreApp` as the entrypoint (same as the HTTP patterns), which means AgentCore Runtime headers (WorkloadAccessToken, Authorization, Session-Id) are available for Gateway auth, Memory, and secure user identity extraction. | ||
|
|
||
| --- | ||
|
|
||
| ## How It Works | ||
|
|
||
| ### Architecture | ||
|
|
||
| ``` | ||
| Frontend (Amplify) | ||
| │ | ||
| │ POST /invocations (AG-UI RunAgentInput payload) | ||
| ▼ | ||
| AgentCore Runtime | ||
| │ | ||
| │ Proxies request to container port 8080 | ||
| │ Injects: WorkloadAccessToken, Authorization, Session-Id headers | ||
| ▼ | ||
| Agent Container | ||
| │ | ||
| │ BedrockAgentCoreApp reads headers → sets ContextVars | ||
| │ @entrypoint handler creates agent, runs it | ||
| ▼ | ||
| AG-UI Wrapper (StrandsAgent / LangGraphAGUIAgent) | ||
| │ | ||
| │ Translates framework events → AG-UI SSE events | ||
| ▼ | ||
| Frontend Parser (parsers/agui.ts) | ||
| │ | ||
| │ Maps AG-UI events → StreamEvent types | ||
| ▼ | ||
| ChatInterface.tsx renders messages | ||
| ``` | ||
|
|
||
| ### Request Flow | ||
|
|
||
| 1. The frontend sends an AG-UI `RunAgentInput` payload (with `threadId`, `messages`, `runId`) | ||
| 2. AgentCore Runtime proxies the request, injecting auth headers | ||
| 3. `BedrockAgentCoreApp` reads headers and populates `BedrockAgentCoreContext` (ContextVars) | ||
| 4. The `@entrypoint` handler extracts user identity from the JWT, creates the agent with Memory and Gateway tools | ||
| 5. The AG-UI wrapper translates framework streaming events into AG-UI SSE events | ||
| 6. The frontend `parseAguiChunk` parser maps AG-UI events to the shared `StreamEvent` types | ||
|
|
||
| ### AG-UI vs HTTP Protocol on AgentCore Runtime | ||
|
|
||
| AgentCore Runtime supports both `HTTP` and `AGUI` server protocols. The difference is minimal: with `AGUI`, platform-level errors are returned as AG-UI-compliant `RUN_ERROR` events in the SSE stream (HTTP 200) instead of HTTP error codes. Everything else — auth, session headers, payload passthrough — is identical. | ||
|
|
||
| The AG-UI patterns in FAST deploy with `HTTP` protocol, which works correctly because the agent container handles AG-UI event formatting internally. | ||
|
|
||
| --- | ||
|
|
||
| ## Agent Patterns | ||
|
|
||
| ### AG-UI Strands (`agui-strands-agent`) | ||
|
|
||
| **Location**: `agent_patterns/agui-strands-agent/` | ||
|
|
||
| Uses `ag-ui-strands` (`StrandsAgent`) to wrap a Strands `Agent`. The agent is created per-request inside the `@entrypoint` handler, ensuring each request gets a fresh `Agent` with the correct `session_manager` and fresh MCP client connections. | ||
|
|
||
| **Includes**: AgentCore Memory, Gateway MCP tools, Code Interpreter, AG-UI SSE streaming. | ||
|
|
||
| ### AG-UI LangGraph (`agui-langgraph-agent`) | ||
|
|
||
| **Location**: `agent_patterns/agui-langgraph-agent/` | ||
|
|
||
| Uses the `copilotkit` python library (`LangGraphAGUIAgent`) to wrap a LangGraph compiled graph. Uses `ActorAwareLangGraphAgent`, a subclass that rebuilds the graph per-request to ensure fresh Gateway MCP tool connections with valid tokens. | ||
|
|
||
| **Includes**: AgentCore Memory (checkpointer), Gateway MCP tools, Code Interpreter, CopilotKit middleware, AG-UI SSE streaming. | ||
|
|
||
| --- | ||
|
|
||
| ## Frontend | ||
|
|
||
| ### Parser Auto-Selection | ||
|
|
||
| The AG-UI parser is automatically selected based on the pattern name prefix. Any pattern starting with `agui-` uses the AG-UI parser (`parsers/agui.ts`). Unlike the HTTP patterns — which each require a framework-specific parser (Strands, LangGraph, Claude) to handle their different streaming formats — all AG-UI patterns share a single parser. This is one of the key benefits of the AG-UI protocol: the backend framework is abstracted away behind a standard event vocabulary, so the frontend doesn't need to know whether the agent uses Strands or LangGraph. | ||
|
|
||
| See `frontend/src/lib/agentcore-client/client.ts` for the parser selection logic and `infra-cdk/config.yaml` comments for the full prefix-to-parser mapping. | ||
|
|
||
| ### AG-UI Payload Format | ||
|
|
||
| The frontend automatically sends the correct payload format based on the pattern prefix. AG-UI patterns receive a `RunAgentInput` payload (with `threadId`, `messages`, `runId`), while HTTP patterns receive the standard `{ prompt, runtimeSessionId }` format. This is handled by `AgentCoreClient.invoke()`. | ||
|
|
||
| --- | ||
|
|
||
| ## Deployment | ||
|
|
||
| Set the pattern in `infra-cdk/config.yaml`: | ||
|
|
||
| ```yaml | ||
| backend: | ||
| pattern: agui-strands-agent # or agui-langgraph-agent | ||
| deployment_type: docker | ||
| ``` | ||
|
|
||
| No CDK changes are required. The AG-UI patterns deploy as standard HTTP containers on AgentCore Runtime. | ||
|
|
||
| --- | ||
|
|
||
| ## CopilotKit Integration | ||
|
|
||
| [CopilotKit](https://www.copilotkit.ai/) is a React UI library that natively understands the AG-UI protocol. While FAST's built-in frontend includes a lightweight AG-UI parser for basic chat streaming, CopilotKit provides a richer set of capabilities for building agent-powered applications. Fullstack FAST applications with deeper CopilotKit integration can be found in the FAST samples repository (coming soon). | ||
|
|
||
| --- | ||
|
|
||
| ## Additional Resources | ||
|
|
||
| - [AG-UI Protocol Documentation](https://docs.ag-ui.com/concepts/overview) | ||
| - [ag-ui-strands on PyPI](https://pypi.org/project/ag-ui-strands/) | ||
| - [CopilotKit Documentation](https://docs.copilotkit.ai/) | ||
| - [Strands AG-UI Integration Guide](https://strandsagents.com/docs/community/integrations/ag-ui/) | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Oops, something went wrong.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,81 @@ | ||
| // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. | ||
| // SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| import type { ChunkParser } from "../types" | ||
|
|
||
| /** | ||
| * Parses SSE chunks from AG-UI (ag-ui-strands) agents. | ||
| * | ||
| * AG-UI events arrive as `data: <JSON>` where each JSON object has a `type` field: | ||
| * RUN_STARTED, STATE_SNAPSHOT, TEXT_MESSAGE_START, TEXT_MESSAGE_CONTENT, | ||
| * TEXT_MESSAGE_END, TOOL_CALL_START, TOOL_CALL_ARGS, TOOL_CALL_END, | ||
| * TOOL_CALL_RESULT, RUN_FINISHED | ||
| */ | ||
| export const parseAguiChunk: ChunkParser = (line, callback) => { | ||
| if (!line.startsWith("data: ")) return | ||
|
|
||
| const data = line.substring(6).trim() | ||
| if (!data) return | ||
|
|
||
| try { | ||
| const json = JSON.parse(data) | ||
| const eventType: string = json.type | ||
|
|
||
| switch (eventType) { | ||
| case "TEXT_MESSAGE_CONTENT": | ||
| callback({ type: "text", content: json.delta ?? "" }) | ||
| break | ||
|
|
||
| case "TOOL_CALL_START": | ||
| callback({ | ||
| type: "tool_use_start", | ||
| toolUseId: json.toolCallId, | ||
| name: json.toolCallName, | ||
| }) | ||
| break | ||
|
|
||
| case "TOOL_CALL_ARGS": | ||
| callback({ | ||
| type: "tool_use_delta", | ||
| toolUseId: json.toolCallId, | ||
| input: json.delta ?? "", | ||
| }) | ||
| break | ||
|
|
||
| case "TOOL_CALL_RESULT": | ||
| callback({ | ||
| type: "tool_result", | ||
| toolUseId: json.toolCallId, | ||
| result: json.content ?? "", | ||
| }) | ||
| break | ||
|
|
||
| case "RUN_FINISHED": | ||
| callback({ type: "result", stopReason: "end_turn" }) | ||
| callback({ type: "lifecycle", event: "run_finished" }) | ||
| break | ||
|
|
||
| case "RUN_STARTED": | ||
| callback({ type: "lifecycle", event: "run_started" }) | ||
| break | ||
|
|
||
| case "TEXT_MESSAGE_START": | ||
| callback({ type: "lifecycle", event: "message_start" }) | ||
| break | ||
|
|
||
| case "TEXT_MESSAGE_END": | ||
| callback({ type: "lifecycle", event: "message_end" }) | ||
| break | ||
|
|
||
| case "STATE_SNAPSHOT": | ||
| case "TOOL_CALL_END": | ||
| // Informational — no action needed | ||
| break | ||
|
|
||
| default: | ||
| console.debug("Unhandled AG-UI event type:", eventType) | ||
| } | ||
| } catch { | ||
| console.debug("Failed to parse AG-UI event:", data) | ||
| } | ||
| } |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.