AG-UI integration for the Anthropic Claude Agent SDK, with multimodal attachment support (images and documents)
Project description
ag-ui-claude-sdk-fiqros
Implementation of the AG-UI protocol for the Anthropic Claude Agent SDK (Python), with support for user attachments — images and documents sent by the user now reach the model instead of being silently discarded.
This is a fork of
integrations/claude-agent-sdkfrom the AG-UI project (MIT), maintained by the Fiqros team. It tracks upstream and adds the attachment fix described in Attachment support below, contributed by the Fiqros team. The import name is unchanged, so it is a drop-in replacement for the upstream package.
Installation
pip install ag-ui-claude-sdk-fiqros
Or from a checkout:
pip install -e .
Usage
The adapter manages the SDK lifecycle internally — just call adapter.run(input_data):
from ag_ui_claude_sdk import ClaudeAgentAdapter, add_claude_fastapi_endpoint
adapter = ClaudeAgentAdapter(name="my_agent", options={"model": "claude-haiku-4-5"})
add_claude_fastapi_endpoint(app=app, adapter=adapter, path="/my_agent")
Attachment support (fork changes)
Investigated, fixed and documented by the Fiqros team.
Upstream, a user message carrying an attachment never reached the model. Claude would reply "It looks like you forgot to attach the image!" — with no error and nothing in the logs.
Cause. When a user attaches a file, AG-UI sends the message content as a
list of blocks rather than a plain string:
{"role": "user", "content": [
{"type": "text", "text": "what is in this image?"},
{"type": "image", "source": {"type": "data", "value": "<base64>", "mime_type": "image/png"}}
]}
process_messages() walked that list looking for the first block with a .text
attribute, took it, and stopped. Image, document, audio and video blocks have a
.source rather than .text, so they matched nothing and fell out of the loop
unreferenced. Claude was asked about an image it was never shown.
Fix. AG-UI and Anthropic describe attachments with the same structure under different field names, so the fix is a rename, not a conversion — the base64 payload is passed through untouched, with no decode/re-encode:
AG-UI {"type": "data", "value": "<b64>", "mime_type": "image/png"}
Anthropic {"type": "base64", "data": "<b64>", "media_type": "image/png"}
Two changes implement it:
utils.py—convert_content_blocks()renames every block and returns the full list. Messages with no attachment still return a plain string, so the common path is byte-for-byte unchanged.session.py— content blocks requireClaudeSDKClient.query()'s streaming form (AsyncIterable[dict]), since itsstrform cannot carry them. A small async generator wraps the blocks in a user-message envelope.
Also fixed along the way:
- An attachment-only message (no text) previously produced an empty prompt.
- A message split into several text blocks lost everything after the first.
- Unsupported or malformed blocks are now skipped with a warning instead of in silence.
Supported: images and documents, both inline base64 and URL sources. Audio and video blocks are skipped with a warning — Claude does not accept them.
Full analysis, evidence and rejected alternatives: BUG_REPORT_attachments_dropped.md.
Features
- User attachments - Images and documents in user messages are passed through to the model
- Full lifecycle management - Handles client pooling, message extraction, and event translation internally
- Interrupt support - Call
adapter.interrupt()to stop a running query - Dynamic frontend tools - Client-provided tools automatically added as MCP server with auto-granted permissions
- Frontend tool halting - Streams pause after frontend tool calls for client-side execution (human-in-the-loop)
- Streaming tool arguments - Real-time TOOL_CALL_ARGS emission as JSON arguments stream in
- Bidirectional state sync - Shared state management via ag_ui_update_state tool
- Context injection - Context and state injected into prompts for agent awareness
- Event cleanup - Hanging events (tool calls, reasoning blocks) automatically closed on stream end
- Custom tools via MCP - Define custom tools using Claude SDK's @tool decorator
- Forwarded props - Per-run option overrides with security whitelist
Examples
The integration includes 5 example agents:
| Route | Description | Features |
|---|---|---|
/agentic_chat |
Basic conversational assistant | Simple chat |
/backend_tool_rendering |
Weather tool (backend MCP) | Backend tool execution, tool rendering |
/shared_state |
Recipe collaboration | Bidirectional state sync, ag_ui_update_state |
/human_in_the_loop |
Task planning with approval | Frontend tools, step tracking, approval workflow |
/tool_based_generative_ui |
Frontend tool rendering | Dynamic frontend tools, generative UI |
Running the Examples
# Install dependencies
cd integrations/claude-agent-sdk/python
pip install -e .
# Start server (port 8019)
cd examples
ANTHROPIC_API_KEY=sk-ant-xxx python server.py
# Start Dojo (in another terminal)
cd apps/dojo
pnpm dev
Visit http://localhost:3000 and select "Claude Agent SDK (Python)"
Session Persistence
Claude SDK maintains conversation state in the .claude/ directory. For production deployments:
- Development: Sessions persist locally in
.claude/{session_id}/ - Production: Mount
.claude/as a persistent volume in your container - Resumption: Pass
resume=<session_id>via the options dict orforwarded_props
See Claude SDK Hosting Guide for deployment patterns.
Links
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ag_ui_claude_sdk_fiqros-0.1.6.tar.gz.
File metadata
- Download URL: ag_ui_claude_sdk_fiqros-0.1.6.tar.gz
- Upload date:
- Size: 64.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
8037ec37829d84e31c177246ab2933479025c769a2b30a7691bb4514fe4e4c8b
|
|
| MD5 |
30bea781f0bda22798791e8beb699d89
|
|
| BLAKE2b-256 |
cdc7816436816973abe129899fd453c356cf20ddde6599f1671548c31dc81984
|
File details
Details for the file ag_ui_claude_sdk_fiqros-0.1.6-py3-none-any.whl.
File metadata
- Download URL: ag_ui_claude_sdk_fiqros-0.1.6-py3-none-any.whl
- Upload date:
- Size: 36.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.20 {"installer":{"name":"uv","version":"0.11.20","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4923f0d8078f4c3c98a3d5c508e564b5768b90bc4965f4d4f7c655048426aba5
|
|
| MD5 |
5ca7a38ef7720a9abd6d667fa897d33c
|
|
| BLAKE2b-256 |
944716230715e1e116fd98efb2ba3cca69837df68f8732c8b11249b19e88d677
|