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
2 changes: 2 additions & 0 deletions docs/features/custom-agents.md
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,8 @@ By default, all custom agents are available for automatic selection (`infer: tru

When a sub-agent runs, the parent session emits lifecycle events. Subscribe to these events to build UIs that visualize agent activity.

Sub-agent-originated session events share the parent session stream and include envelope-level `agentId`. Root/main agent events and session-level events omit `agentId`, so renderers can keep the parent response separate from sub-agent traces by checking the event envelope.

### Event types

| Event | Emitted when | Data |
Expand Down
46 changes: 40 additions & 6 deletions docs/features/streaming-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ Every session event, regardless of type, includes these fields:
| `id` | `string` (UUID v4) | Unique event identifier |
| `timestamp` | `string` (ISO 8601) | When the event was created |
| `parentId` | `string \| null` | ID of the previous event in the chain; `null` for the first event |
| `agentId` | `string?` | Sub-agent instance ID for sub-agent-originated events; absent for root/main agent and session-level events |
| `ephemeral` | `boolean?` | `true` for transient events; absent or `false` for persisted events |
| `type` | `string` | Event type discriminator (see tables below) |
| `data` | `object` | Event-specific payload |
Expand Down Expand Up @@ -217,6 +218,37 @@ session.on(AssistantMessageDeltaEvent.class, event ->
> [!TIP]
> **(TypeScript)** The TypeScript SDK uses a discriminated union—when you match on `event.type`, the `data` payload is automatically narrowed to the correct shape.

## Render only the parent agent response

Sub-agent events share the parent session stream and include envelope-level `agentId`. Root/main agent events and session-level events omit `agentId`, so main-chat renderers can ignore assistant events where `agentId` is set and route those events to traces or progress UI instead.

<details open>
<summary><strong>TypeScript</strong></summary>

```typescript
session.on("assistant.message_delta", (event) => {
if (!event.agentId) process.stdout.write(event.data.deltaContent);
});
```

</details>
<details>
<summary><strong>Python</strong></summary>

```python
from copilot import CopilotSession
from copilot.session_events import SessionEventType

def subscribe_parent_response(session: CopilotSession):
def handle(event):
if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA and event.agent_id is None:
print(event.data.delta_content, end="", flush=True)

session.on(handle)
```

</details>

## Assistant events

These events track the agent's response lifecycle—from turn start through streaming chunks to the final message.
Expand Down Expand Up @@ -271,7 +303,7 @@ The assistant's complete response for this LLM call. May include tool invocation
| `phase` | `string` | | Generation phase (e.g., `"thinking"` vs `"response"`) |
| `outputTokens` | `number` | | Actual output token count from the API response |
| `interactionId` | `string` | | CAPI interaction ID for telemetry |
| `parentToolCallId` | `string` | | Set when this message originates from a sub-agent |
| `parentToolCallId` | `string` | | Deprecated. Use envelope-level `agentId` for sub-agent attribution |

**`ToolRequest` fields:**

Expand All @@ -290,7 +322,7 @@ Ephemeral. Incremental chunk of the assistant's text response, streamed in real
|------------|------|----------|-------------|
| `messageId` | `string` | ✅ | Matches the corresponding `assistant.message` event |
| `deltaContent` | `string` | ✅ | Text chunk to append to the message |
| `parentToolCallId` | `string` | | Set when originating from a sub-agent |
| `parentToolCallId` | `string` | | Deprecated. Use envelope-level `agentId` for sub-agent attribution |

### `assistant.turn_end`

Expand All @@ -317,7 +349,7 @@ Ephemeral. Token usage and cost information for an individual API call.
| `apiCallId` | `string` | | Completion ID from the provider (e.g., `chatcmpl-abc123`) |
| `apiEndpoint` | `"/chat/completions" \| "/v1/messages" \| "/responses" \| "ws:/responses"` | | API endpoint used for the model call; useful for observability and cost attribution. `ws:/responses` is the websocket variant of the responses API |
| `providerCallId` | `string` | | GitHub request tracing ID (`x-github-request-id`) |
| `parentToolCallId` | `string` | | Set when usage originates from a sub-agent |
| `parentToolCallId` | `string` | | Deprecated. Use envelope-level `agentId` for sub-agent attribution |
| `quotaSnapshots` | `Record<string, QuotaSnapshot>` | | Per-quota resource usage, keyed by quota identifier |
| `copilotUsage` | `CopilotUsage` | | Itemized token cost breakdown from the API |

Expand All @@ -344,7 +376,7 @@ Emitted when a tool begins executing.
| `arguments` | `object` | | Parsed arguments passed to the tool |
| `mcpServerName` | `string` | | MCP server name, when the tool is provided by an MCP server |
| `mcpToolName` | `string` | | Original tool name on the MCP server |
| `parentToolCallId` | `string` | | Set when invoked by a sub-agent |
| `parentToolCallId` | `string` | | Deprecated. Use envelope-level `agentId` for sub-agent attribution |

### `tool.execution_partial_result`

Expand Down Expand Up @@ -378,7 +410,7 @@ Emitted when a tool finishes executing—successfully or with an error.
| `result` | `Result` | | Present on success (see below) |
| `error` | `{ message, code? }` | | Present on failure |
| `toolTelemetry` | `object` | | Tool-specific telemetry (e.g., CodeQL check counts) |
| `parentToolCallId` | `string` | | Set when invoked by a sub-agent |
| `parentToolCallId` | `string` | | Deprecated. Use envelope-level `agentId` for sub-agent attribution |

**`Result` fields:**

Expand Down Expand Up @@ -789,6 +821,8 @@ session.idle → Ready for next message (ephemeral)

## All event types at a glance

This table lists key `data` payload fields. Common envelope fields are documented above.

| Event Type | Ephemeral | Category | Key Data Fields |
|------------|-----------|----------|-----------------|
| `assistant.turn_start` | | Assistant | `turnId`, `interactionId?` |
Expand All @@ -797,7 +831,7 @@ session.idle → Ready for next message (ephemeral)
| `assistant.reasoning_delta` | ✅ | Assistant | `reasoningId`, `deltaContent` |
| `assistant.streaming_delta` | ✅ | Assistant | `totalResponseSizeBytes` |
| `assistant.message` | | Assistant | `messageId`, `content`, `toolRequests?`, `outputTokens?`, `phase?` |
| `assistant.message_delta` | ✅ | Assistant | `messageId`, `deltaContent`, `parentToolCallId?` |
| `assistant.message_delta` | ✅ | Assistant | `messageId`, `deltaContent` |
| `assistant.turn_end` | | Assistant | `turnId` |
| `assistant.usage` | ✅ | Assistant | `model`, `apiEndpoint?`, `inputTokens?`, `outputTokens?`, `cost?`, `duration?` |
| `tool.user_requested` | | Tool | `toolCallId`, `toolName`, `arguments?` |
Expand Down
Loading