Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions docs/concepts/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,12 @@ elements such as progress indicators or loading states. It also provides crucial
identifiers that can be used to associate subsequent events with this specific
run.

| Property | Description |
| ---------- | ----------------------------- |
| `threadId` | ID of the conversation thread |
| `runId` | ID of the agent run |
| Property | Description |
| -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `threadId` | ID of the conversation thread |
| `runId` | ID of the agent run |
| `parentRunId` | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread, creating a git-like append-only log |
| `input` | (Optional) The exact agent input payload that was sent to the agent for this run. May omit messages already present in history; compactEvents() will normalize |

### RunFinished

Expand Down
22 changes: 21 additions & 1 deletion docs/concepts/messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,31 @@ Messages from the end user to the agent:
interface UserMessage {
id: string
role: "user"
content: string // Text input from the user
content: string | InputContent[] // Text or multimodal input from the user
name?: string // Optional user identifier
}

type InputContent = TextInputContent | BinaryInputContent

interface TextInputContent {
type: "text"
text: string
}

interface BinaryInputContent {
type: "binary"
mimeType: string
id?: string
url?: string
data?: string
filename?: string
}
```

> For `BinaryInputContent`, provide at least one of `id`, `url`, or `data` to reference the payload.

This structure keeps traditional plain-text inputs working while enabling richer payloads such as images, audio clips, or uploaded files in the same message.

### Assistant Messages

Messages from the AI assistant to the user:
Expand Down
2 changes: 1 addition & 1 deletion docs/drafts/multimodal-messages.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ apps. Inputs may include text, images, audio, and files.

## Status

- **Status**: Draft
- **Status**: Implemented — October 16, 2025
- **Author(s)**: Markus Ecker (mail@mme.xyz)

## Detailed Specification
Expand Down
40 changes: 40 additions & 0 deletions docs/sdk/js/client/abstract-agent.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -111,13 +111,42 @@ Creates a deep copy of the agent instance.
clone(): AbstractAgent
```

### connectAgent()

Establishes a persistent connection with an agent that implements the
`connect()` method.

```typescript
connectAgent(parameters?: RunAgentParameters, subscriber?: AgentSubscriber): Promise<RunAgentResult>
```

Similar to `runAgent()` but uses the `connect()` method internally. The agent
must implement `connect()` or this functionality must be provided by a framework
like [CopilotKit](https://copilotkit.ai).

## Observable Properties

### events$

An observable stream of all events emitted during agent execution.

```typescript
events$: Observable<BaseEvent>
```

This property provides direct access to the agent's event stream. Events are
stored using a `ReplaySubject`, allowing late subscribers will receive all
historical events.

## Properties

- `agentId`: Unique identifier for the agent instance
- `description`: Human-readable description
- `threadId`: Conversation thread identifier
- `messages`: Array of conversation messages
- `state`: Current agent state object
- `events$`: Observable stream of all `BaseEvent` objects emitted during agent
execution (replayed for late subscribers)

## Protected Methods

Expand All @@ -131,6 +160,17 @@ Executes the agent and returns an observable event stream.
protected abstract run(input: RunAgentInput): RunAgent
```

### connect()

Establishes a persistent connection and returns an observable event stream.

```typescript
protected connect(input: RunAgentInput): RunAgent
```

Override this method to implement persistent connections. Default implementation
throws `ConnectNotImplementedError`.

### apply()

Processes events from the run and updates the agent state.
Expand Down
12 changes: 8 additions & 4 deletions docs/sdk/js/core/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -68,13 +68,17 @@ type RunStartedEvent = BaseEvent & {
type: EventType.RUN_STARTED
threadId: string
runId: string
parentRunId?: string
input?: RunAgentInput
}
```

| Property | Type | Description |
| ---------- | -------- | ----------------------------- |
| `threadId` | `string` | ID of the conversation thread |
| `runId` | `string` | ID of the agent run |
| Property | Type | Description |
| -------------- | ----------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `threadId` | `string` | ID of the conversation thread |
| `runId` | `string` | ID of the agent run |
| `parentRunId` | `string` (optional) | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread |
| `input` | `RunAgentInput` (optional) | (Optional) The exact agent input payload sent to the agent for this run. May omit messages already in history |

### RunFinishedEvent

Expand Down
48 changes: 41 additions & 7 deletions docs/sdk/js/core/types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ Input parameters for running an agent. In the HTTP API, this is the body of the
type RunAgentInput = {
threadId: string
runId: string
parentRunId?: string
state: any
messages: Message[]
tools: Tool[]
Expand All @@ -32,6 +33,7 @@ type RunAgentInput = {
| ---------------- | ----------- | ---------------------------------------------- |
| `threadId` | `string` | ID of the conversation thread |
| `runId` | `string` | ID of the current run |
| `parentRunId` | `string (optional)` | ID of the run that spawned this run |
| `state` | `any` | Current state of the agent |
| `messages` | `Message[]` | Array of messages in the conversation |
| `tools` | `Tool[]` | Array of tools available to the agent |
Expand Down Expand Up @@ -121,17 +123,49 @@ Represents a message from a user.
type UserMessage = {
id: string
role: "user"
content: string
content: string | InputContent[]
name?: string
}
```

| Property | Type | Description |
| --------- | -------- | ------------------------------------------- |
| `id` | `string` | Unique identifier for the message |
| `role` | `"user"` | Role of the message sender, fixed as "user" |
| `content` | `string` | Text content of the message (required) |
| `name` | `string` | Optional name of the sender |
| Property | Type | Description |
| --------- | --------------------------- | --------------------------------------------------------------------- |
| `id` | `string` | Unique identifier for the message |
| `role` | `"user"` | Role of the message sender, fixed as "user" |
| `content` | `string \| InputContent[]` | Either plain text or an ordered array of multimodal content fragments |
| `name` | `string` | Optional name of the sender |

### InputContent

Union of supported multimodal fragments.

```typescript
type InputContent = TextInputContent | BinaryInputContent
```

### TextInputContent

```typescript
type TextInputContent = {
type: "text"
text: string
}
```

### BinaryInputContent

```typescript
type BinaryInputContent = {
type: "binary"
mimeType: string
id?: string
url?: string
data?: string
filename?: string
}
```

> At least one of `id`, `url`, or `data` must be provided.

### ToolMessage

Expand Down
12 changes: 8 additions & 4 deletions docs/sdk/python/core/events.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -73,12 +73,16 @@ class RunStartedEvent(BaseEvent):
type: Literal[EventType.RUN_STARTED]
thread_id: str
run_id: str
parent_run_id: Optional[str] = None
input: Optional[RunAgentInput] = None
```

| Property | Type | Description |
| ----------- | ----- | ----------------------------- |
| `thread_id` | `str` | ID of the conversation thread |
| `run_id` | `str` | ID of the agent run |
| Property | Type | Description |
| ---------------- | -------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------- |
| `thread_id` | `str` | ID of the conversation thread |
| `run_id` | `str` | ID of the agent run |
| `parent_run_id` | `Optional[str]` | (Optional) Lineage pointer for branching/time travel. If present, refers to a prior run within the same thread |
| `input` | `Optional[RunAgentInput]` | (Optional) The exact agent input payload sent to the agent for this run. May omit messages already in history |

### RunFinishedEvent

Expand Down
56 changes: 49 additions & 7 deletions docs/sdk/python/core/types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Input parameters for running an agent. In the HTTP API, this is the body of the
class RunAgentInput(ConfiguredBaseModel):
thread_id: str
run_id: str
parent_run_id: Optional[str] = None
state: Any
messages: List[Message]
tools: List[Tool]
Expand All @@ -33,6 +34,7 @@ class RunAgentInput(ConfiguredBaseModel):
| ----------------- | --------------- | --------------------------------------------- |
| `thread_id` | `str` | ID of the conversation thread |
| `run_id` | `str` | ID of the current run |
| `parent_run_id` | `Optional[str]` | (Optional) ID of the run that spawned this run|
| `state` | `Any` | Current state of the agent |
| `messages` | `List[Message]` | List of messages in the conversation |
| `tools` | `List[Tool]` | List of tools available to the agent |
Expand Down Expand Up @@ -122,15 +124,55 @@ Represents a message from a user.
```python
class UserMessage(BaseMessage):
role: Literal["user"]
content: str
content: Union[str, List["InputContent"]]
```

| Property | Type | Description |
| --------- | ---------------------------------- | --------------------------------------------------------------------- |
| `id` | `str` | Unique identifier for the message |
| `role` | `Literal["user"]` | Role of the message sender, fixed as "user" |
| `content` | `Union[str, List["InputContent"]]` | Either a plain text string or an ordered list of multimodal fragments |
| `name` | `Optional[str]` | Optional name of the sender |

### TextInputContent

Represents a text fragment inside a multimodal user message.

```python
class TextInputContent(ConfiguredBaseModel):
type: Literal["text"]
text: str
```

| Property | Type | Description |
| --------- | ----------------- | ------------------------------------------- |
| `id` | `str` | Unique identifier for the message |
| `role` | `Literal["user"]` | Role of the message sender, fixed as "user" |
| `content` | `str` | Text content of the message (required) |
| `name` | `Optional[str]` | Optional name of the sender |
| Property | Type | Description |
| -------- | --------------- | ---------------------------- |
| `type` | `Literal["text"]` | Identifies the fragment type |
| `text` | `str` | Text content |

### BinaryInputContent

Represents binary data such as images, audio, or files.

```python
class BinaryInputContent(ConfiguredBaseModel):
type: Literal["binary"]
mime_type: str
id: Optional[str] = None
url: Optional[str] = None
data: Optional[str] = None
filename: Optional[str] = None
```

| Property | Type | Description |
| ---------- | ----------------- | ------------------------------------------------------------- |
| `type` | `Literal["binary"]` | Identifies the fragment type |
| `mime_type`| `str` | MIME type, for example `"image/png"` |
| `id` | `Optional[str]` | Reference to previously uploaded content |
| `url` | `Optional[str]` | Remote URL where the content can be retrieved |
| `data` | `Optional[str]` | Base64 encoded content |
| `filename` | `Optional[str]` | Optional filename hint |

> **Validation:** At least one of `id`, `url`, or `data` must be provided.

### ToolMessage

Expand Down
17 changes: 17 additions & 0 deletions python-sdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,23 @@ sse_data = encoder.encode(event)
# Output: data: {"type":"TEXT_MESSAGE_CONTENT","messageId":"msg_123","delta":"Hello from Python!"}\n\n
```

### Multimodal user message

```python
from ag_ui.core import UserMessage, TextInputContent, BinaryInputContent

message = UserMessage(
id="user-123",
content=[
TextInputContent(text="Please describe this image"),
BinaryInputContent(mime_type="image/png", url="https://example.com/cat.png"),
],
)

payload = message.model_dump(by_alias=True)
# {"id": "user-123", "role": "user", "content": [...]}
```

## Packages

- **`ag_ui.core`** – Types, events, and data models for AG-UI protocol
Expand Down
10 changes: 8 additions & 2 deletions python-sdk/ag_ui/core/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
Context,
Tool,
RunAgentInput,
State
State,
TextInputContent,
BinaryInputContent,
InputContent,
)

__all__ = [
Expand Down Expand Up @@ -92,5 +95,8 @@
"Context",
"Tool",
"RunAgentInput",
"State"
"State",
"TextInputContent",
"BinaryInputContent",
"InputContent",
]
4 changes: 3 additions & 1 deletion python-sdk/ag_ui/core/events.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

from pydantic import Field

from .types import ConfiguredBaseModel, Message, State, Role
from .types import ConfiguredBaseModel, Message, State, Role, RunAgentInput

# Text messages can have any role except "tool"
TextMessageRole = Literal["developer", "system", "assistant", "user"]
Expand Down Expand Up @@ -213,6 +213,8 @@ class RunStartedEvent(BaseEvent):
type: Literal[EventType.RUN_STARTED] = EventType.RUN_STARTED # pyright: ignore[reportIncompatibleVariableOverride]
thread_id: str
run_id: str
parent_run_id: Optional[str] = None
input: Optional[RunAgentInput] = None


class RunFinishedEvent(BaseEvent):
Expand Down
Loading