Skip to main content

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-sdk from 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.pyconvert_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 require ClaudeSDKClient.query()'s streaming form (AsyncIterable[dict]), since its str form 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.

Test coverage

44 tests cover the attachment path (suite total: 110 → 154, with every pre-existing test passing unmodified):

Suite Tests Covers
TestConvertContentBlocks 13 Image and document renaming, URL sources, text-only fast path, attachment-only messages, malformed and unknown blocks, base64 passthrough, pydantic models
TestDocumentBlocks 15 MIME passthrough across 6 document types, multiple documents, mixed image+document, large PDFs, missing MIME
TestProcessMessagesWithAttachments 6 Block-list vs plain-string return, camelCase mimeType from TypeScript clients
TestAttachmentReachesTheClient 5 Envelope shape and payload integrity through the real SessionWorker
TestDocumentDelivery 5 Document delivery, 20 KB PDF unmangled, ordering

The delivery suites run the real SessionWorker with only ClaudeSDKClient substituted, so they assert on exactly what would reach the CLI. Both halves of the fix were also mutation-tested — reverting them fails 7 and 17 tests respectively.

uv run --group dev python -m pytest tests/ -q

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 or forwarded_props

See Claude SDK Hosting Guide for deployment patterns.

Links

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

ag_ui_claude_sdk_fiqros-0.1.7.tar.gz (70.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

ag_ui_claude_sdk_fiqros-0.1.7-py3-none-any.whl (36.8 kB view details)

Uploaded Python 3

File details

Details for the file ag_ui_claude_sdk_fiqros-0.1.7.tar.gz.

File metadata

  • Download URL: ag_ui_claude_sdk_fiqros-0.1.7.tar.gz
  • Upload date:
  • Size: 70.3 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

Hashes for ag_ui_claude_sdk_fiqros-0.1.7.tar.gz
Algorithm Hash digest
SHA256 28d23c68b5f5ae78698c98e94c787c05f2829e309686e20e2a685e6548655678
MD5 b0e7d6b8fb35ef4b24572fbe71a58520
BLAKE2b-256 6a308d4135a6e61d0595519a6d4d9941b68a8ec398c9a6a77010db3c6cd32e83

See more details on using hashes here.

File details

Details for the file ag_ui_claude_sdk_fiqros-0.1.7-py3-none-any.whl.

File metadata

  • Download URL: ag_ui_claude_sdk_fiqros-0.1.7-py3-none-any.whl
  • Upload date:
  • Size: 36.8 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

Hashes for ag_ui_claude_sdk_fiqros-0.1.7-py3-none-any.whl
Algorithm Hash digest
SHA256 fb9707377813cb0cbcbeaaa41c4f13ee33c4ec02f79138559306aa7b447880f0
MD5 63a14472876972e4a6c260eb4eed81a3
BLAKE2b-256 250b870eb48480611737e3d7b6a1b844dc99236ee4e962cb02eea2574d724a70

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page