Liking cljdoc? Tell your friends :D

Streaming Session Events

Every action the Copilot agent takes — thinking, writing code, running tools — is emitted as a session event you can subscribe to. This guide is a field-level reference for each event type so you know exactly what data to expect without reading the SDK source.

Overview

When streaming: true is set on a session, the SDK emits ephemeral events in real time (deltas, progress updates) alongside persisted events (complete messages, tool results). All events share a common envelope and carry a data payload whose shape depends on the event type.

sequenceDiagram
    participant App as Your App
    participant SDK as SDK Session
    participant Agent as Copilot Agent

    App->>SDK: send({ prompt })
    SDK->>Agent: JSON-RPC

    Agent-->>SDK: assistant.turn_start
    SDK-->>App: event

    loop Streaming response
        Agent-->>SDK: assistant.message_delta (ephemeral)
        SDK-->>App: event
    end

    Agent-->>SDK: assistant.message
    SDK-->>App: event

    loop Tool execution
        Agent-->>SDK: tool.execution_start
        SDK-->>App: event
        Agent-->>SDK: tool.execution_complete
        SDK-->>App: event
    end

    Agent-->>SDK: assistant.turn_end
    SDK-->>App: event

    Agent-->>SDK: session.idle (ephemeral)
    SDK-->>App: event
ConceptDescription
Ephemeral eventTransient; streamed in real time but not persisted to the session log. Not replayed on session resume.
Persisted eventSaved to the session event log on disk. Replayed when resuming a session.
Delta eventAn ephemeral streaming chunk (text or reasoning). Accumulate deltas to build the complete content.
parentId chainEach event's parentId points to the previous event, forming a linked list you can walk.

Event Envelope

Every session event, regardless of type, includes these fields:

FieldTypeDescription
idstring (UUID v4)Unique event identifier
timestampstring (ISO 8601)When the event was created
parentIdstring \| nullID of the previous event in the chain; null for the first event
ephemeralboolean?true for transient events; absent or false for persisted events
typestringEvent type discriminator (see tables below)
dataobjectEvent-specific payload

Subscribing to Events

Node.js / TypeScript
// All events
session.on((event) => {
    console.log(event.type, event.data);
});

// Specific event type — data is narrowed automatically
session.on("assistant.message_delta", (event) => {
    process.stdout.write(event.data.deltaContent);
});
Python
from copilot import CopilotClient
from copilot.generated.session_events import SessionEventType

client = CopilotClient()

session = None  # assume session is created elsewhere

def handle(event):
    if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
        print(event.data.delta_content, end="", flush=True)

# session.on(handle)
from copilot.generated.session_events import SessionEventType

def handle(event):
    if event.type == SessionEventType.ASSISTANT_MESSAGE_DELTA:
        print(event.data.delta_content, end="", flush=True)

session.on(handle)
Go
package main

import (
	"context"
	"fmt"
	copilot "github.com/github/copilot-sdk/go"
)

func main() {
	ctx := context.Background()
	client := copilot.NewClient(nil)

	session, _ := client.CreateSession(ctx, &copilot.SessionConfig{
		Model:     "gpt-4.1",
		Streaming: true,
		OnPermissionRequest: func(req copilot.PermissionRequest, inv copilot.PermissionInvocation) (copilot.PermissionRequestResult, error) {
			return copilot.PermissionRequestResult{Kind: copilot.PermissionRequestResultKindApproved}, nil
		},
	})

	session.On(func(event copilot.SessionEvent) {
		if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
			fmt.Print(d.DeltaContent)
		}
	})
	_ = session
}
session.On(func(event copilot.SessionEvent) {
    if d, ok := event.Data.(*copilot.AssistantMessageDeltaData); ok {
        fmt.Print(d.DeltaContent)
    }
})
.NET
using GitHub.Copilot.SDK;

public static class StreamingEventsExample
{
    public static async Task Example(CopilotSession session)
    {
        session.On(evt =>
        {
            if (evt is AssistantMessageDeltaEvent delta)
            {
                Console.Write(delta.Data.DeltaContent);
            }
        });
    }
}
session.On(evt =>
{
    if (evt is AssistantMessageDeltaEvent delta)
    {
        Console.Write(delta.Data.DeltaContent);
    }
});
Java
// All events
session.on(event -> System.out.println(event.getType()));

// Specific event type — data is narrowed to the matching class
session.on(AssistantMessageDeltaEvent.class, event ->
    System.out.print(event.getData().deltaContent())
);

Tip (Python / Go): These SDKs use a single Data class/struct with all possible fields as optional/nullable. Only the fields listed in the tables below are populated for each event type — the rest will be None / nil.

Tip (.NET): The .NET SDK uses separate, strongly-typed data classes per event (e.g., AssistantMessageDeltaData), so only the relevant fields exist on each type.

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.


Assistant Events

These events track the agent's response lifecycle — from turn start through streaming chunks to the final message.

assistant.turn_start

Emitted when the agent begins processing a turn.

Data FieldTypeRequiredDescription
turnIdstringTurn identifier (typically a stringified turn number)
interactionIdstring CAPI interaction ID for telemetry correlation

assistant.intent

Ephemeral. Short description of what the agent is currently doing, updated as it works.

Data FieldTypeRequiredDescription
intentstringHuman-readable intent (e.g., "Exploring codebase")

assistant.reasoning

Complete extended thinking block from the model. Emitted after reasoning is finished.

Data FieldTypeRequiredDescription
reasoningIdstringUnique identifier for this reasoning block
contentstringThe complete extended thinking text

assistant.reasoning_delta

Ephemeral. Incremental chunk of the model's extended thinking, streamed in real time.

Data FieldTypeRequiredDescription
reasoningIdstringMatches the corresponding assistant.reasoning event
deltaContentstringText chunk to append to reasoning content

assistant.message

The assistant's complete response for this LLM call. May include tool invocation requests.

Data FieldTypeRequiredDescription
messageIdstringUnique identifier for this message
contentstringThe assistant's text response
toolRequestsToolRequest[] Tool calls the assistant wants to make (see below)
reasoningOpaquestring Encrypted extended thinking (Anthropic models); session-bound
reasoningTextstring Readable reasoning text from extended thinking
encryptedContentstring Encrypted reasoning content (OpenAI models); session-bound
phasestring Generation phase (e.g., "thinking" vs "response")
outputTokensnumber Actual output token count from the API response
interactionIdstring CAPI interaction ID for telemetry
parentToolCallIdstring Set when this message originates from a sub-agent

ToolRequest fields:

FieldTypeRequiredDescription
toolCallIdstringUnique ID for this tool call
namestringTool name (e.g., "bash", "edit", "grep")
argumentsobject Parsed arguments for the tool
type"function" \| "custom" Call type; defaults to "function" when absent

assistant.message_delta

Ephemeral. Incremental chunk of the assistant's text response, streamed in real time.

Data FieldTypeRequiredDescription
messageIdstringMatches the corresponding assistant.message event
deltaContentstringText chunk to append to the message
parentToolCallIdstring Set when originating from a sub-agent

assistant.turn_end

Emitted when the agent finishes a turn (all tool executions complete, final response delivered).

Data FieldTypeRequiredDescription
turnIdstringMatches the corresponding assistant.turn_start event

assistant.usage

Ephemeral. Token usage and cost information for an individual API call.

Data FieldTypeRequiredDescription
modelstringModel identifier (e.g., "gpt-4.1")
inputTokensnumber Input tokens consumed
outputTokensnumber Output tokens produced
cacheReadTokensnumber Tokens read from prompt cache
cacheWriteTokensnumber Tokens written to prompt cache
costnumber Model multiplier cost for billing
durationnumber API call duration in milliseconds
initiatorstring What triggered this call (e.g., "sub-agent"); absent for user-initiated
apiCallIdstring Completion ID from the provider (e.g., chatcmpl-abc123)
providerCallIdstring GitHub request tracing ID (x-github-request-id)
parentToolCallIdstring Set when usage originates from a sub-agent
quotaSnapshotsRecord<string, QuotaSnapshot> Per-quota resource usage, keyed by quota identifier
copilotUsageCopilotUsage Itemized token cost breakdown from the API

assistant.streaming_delta

Ephemeral. Low-level network progress indicator — total bytes received from the streaming API response.

Data FieldTypeRequiredDescription
totalResponseSizeBytesnumberCumulative bytes received so far

Tool Execution Events

These events track the full lifecycle of each tool invocation — from the model requesting a tool call through execution to completion.

tool.execution_start

Emitted when a tool begins executing.

Data FieldTypeRequiredDescription
toolCallIdstringUnique identifier for this tool call
toolNamestringName of the tool (e.g., "bash", "edit", "grep")
argumentsobject Parsed arguments passed to the tool
mcpServerNamestring MCP server name, when the tool is provided by an MCP server
mcpToolNamestring Original tool name on the MCP server
parentToolCallIdstring Set when invoked by a sub-agent

tool.execution_partial_result

Ephemeral. Incremental output from a running tool (e.g., streaming bash output).

Data FieldTypeRequiredDescription
toolCallIdstringMatches the corresponding tool.execution_start
partialOutputstringIncremental output chunk

tool.execution_progress

Ephemeral. Human-readable progress status from a running tool (e.g., MCP server progress notifications).

Data FieldTypeRequiredDescription
toolCallIdstringMatches the corresponding tool.execution_start
progressMessagestringProgress status message

tool.execution_complete

Emitted when a tool finishes executing — successfully or with an error.

Data FieldTypeRequiredDescription
toolCallIdstringMatches the corresponding tool.execution_start
successbooleanWhether execution succeeded
modelstring Model that generated this tool call
interactionIdstring CAPI interaction ID
isUserRequestedboolean true when the user explicitly requested this tool call
resultResult Present on success (see below)
error{ message, code? } Present on failure
toolTelemetryobject Tool-specific telemetry (e.g., CodeQL check counts)
parentToolCallIdstring Set when invoked by a sub-agent

Result fields:

FieldTypeRequiredDescription
contentstringConcise result sent to the LLM (may be truncated for token efficiency)
detailedContentstring Full result for display, preserving complete content like diffs
contentsContentBlock[] Structured content blocks (text, terminal, image, audio, resource)

tool.user_requested

Emitted when the user explicitly requests a tool invocation (rather than the model choosing to call one).

Data FieldTypeRequiredDescription
toolCallIdstringUnique identifier for this tool call
toolNamestringName of the tool the user wants to invoke
argumentsobject Arguments for the invocation

Session Lifecycle Events

session.idle

Ephemeral. The agent has finished all processing and is ready for the next message. This is the signal that a turn is fully complete.

Data FieldTypeRequiredDescription
backgroundTasksBackgroundTasks Background agents/shells still running when the agent became idle

session.error

An error occurred during session processing.

Data FieldTypeRequiredDescription
errorTypestringError category (e.g., "authentication", "quota", "rate_limit")
messagestringHuman-readable error message
stackstring Error stack trace
statusCodenumber HTTP status code from the upstream request
providerCallIdstring GitHub request tracing ID for server-side log correlation

session.compaction_start

Context window compaction has begun. Data payload is empty ({}).

session.compaction_complete

Context window compaction finished.

Data FieldTypeRequiredDescription
successbooleanWhether compaction succeeded
errorstring Error message if compaction failed
preCompactionTokensnumber Tokens before compaction
postCompactionTokensnumber Tokens after compaction
preCompactionMessagesLengthnumber Message count before compaction
messagesRemovednumber Messages removed
tokensRemovednumber Tokens removed
summaryContentstring LLM-generated summary of compacted history
checkpointNumbernumber Checkpoint snapshot number created for recovery
checkpointPathstring File path where the checkpoint was stored
compactionTokensUsed{ input, output, cachedInput } Token usage for the compaction LLM call
requestIdstring GitHub request tracing ID for the compaction call

session.title_changed

Ephemeral. The session's auto-generated title was updated.

Data FieldTypeRequiredDescription
titlestringNew session title

session.context_changed

The session's working directory or repository context changed.

Data FieldTypeRequiredDescription
cwdstringCurrent working directory
gitRootstring Git repository root
repositorystring Repository in "owner/name" format
branchstring Current git branch

session.usage_info

Ephemeral. Context window utilization snapshot.

Data FieldTypeRequiredDescription
tokenLimitnumberMaximum tokens for the model's context window
currentTokensnumberCurrent tokens in the context window
messagesLengthnumberCurrent message count in the conversation

session.task_complete

The agent has completed its assigned task.

Data FieldTypeRequiredDescription
summarystring Summary of the completed task

session.shutdown

The session has ended.

Data FieldTypeRequiredDescription
shutdownType"routine" \| "error"Normal shutdown or crash
errorReasonstring Error description when shutdownType is "error"
totalPremiumRequestsnumberTotal premium API requests used
totalApiDurationMsnumberCumulative API call time in milliseconds
sessionStartTimenumberUnix timestamp (ms) when the session started
codeChanges{ linesAdded, linesRemoved, filesModified }Aggregate code change metrics
modelMetricsRecord<string, ModelMetric>Per-model usage breakdown
currentModelstring Model selected at shutdown time

Permission & User Input Events

These events are emitted when the agent needs approval or input from the user before continuing.

permission.requested

Ephemeral. The agent needs permission to perform an action (run a command, write a file, etc.).

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToPermission()
permissionRequestPermissionRequestDetails of the permission being requested

The permissionRequest is a discriminated union on kind:

kindKey FieldsDescription
"shell"fullCommandText, intention, commands[], possiblePaths[]Execute a shell command
"write"fileName, diff, intention, newFileContents?Write/modify a file
"read"path, intentionRead a file or directory
"mcp"serverName, toolName, toolTitle, args?, readOnlyCall an MCP tool
"url"url, intentionFetch a URL
"memory"subject, fact, citationsStore a memory
"custom-tool"toolName, toolDescription, args?Call a custom tool

All kind variants also include an optional toolCallId linking back to the tool call that triggered the request.

permission.completed

Ephemeral. A permission request was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding permission.requested
result.kindstringOne of: "approved", "denied-by-rules", "denied-interactively-by-user", "denied-no-approval-rule-and-could-not-request-from-user", "denied-by-content-exclusion-policy"

user_input.requested

Ephemeral. The agent is asking the user a question.

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToUserInput()
questionstringThe question to present to the user
choicesstring[] Predefined choices for the user
allowFreeformboolean Whether free-form text input is allowed

user_input.completed

Ephemeral. A user input request was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding user_input.requested

elicitation.requested

Ephemeral. The agent needs structured form input from the user (MCP elicitation protocol).

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToElicitation()
messagestringDescription of what information is needed
mode"form" Elicitation mode (currently only "form")
requestedSchema{ type: "object", properties, required? }JSON Schema describing the form fields

elicitation.completed

Ephemeral. An elicitation request was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding elicitation.requested

Sub-Agent & Skill Events

subagent.started

A custom agent was invoked as a sub-agent.

Data FieldTypeRequiredDescription
toolCallIdstringParent tool call that spawned this sub-agent
agentNamestringInternal name of the sub-agent
agentDisplayNamestringHuman-readable display name
agentDescriptionstringDescription of what the sub-agent does

subagent.completed

A sub-agent finished successfully.

Data FieldTypeRequiredDescription
toolCallIdstringMatches the corresponding subagent.started
agentNamestringInternal name
agentDisplayNamestringDisplay name

subagent.failed

A sub-agent encountered an error.

Data FieldTypeRequiredDescription
toolCallIdstringMatches the corresponding subagent.started
agentNamestringInternal name
agentDisplayNamestringDisplay name
errorstringError message

subagent.selected

A custom agent was selected (inferred) to handle the current request.

Data FieldTypeRequiredDescription
agentNamestringInternal name of the selected agent
agentDisplayNamestringDisplay name
toolsstring[] \| nullTool names available to this agent; null for all tools

subagent.deselected

A custom agent was deselected, returning to the default agent. Data payload is empty ({}).

skill.invoked

A skill was activated for the current conversation.

Data FieldTypeRequiredDescription
namestringSkill name
pathstringFile path to the SKILL.md definition
contentstringFull skill content injected into the conversation
allowedToolsstring[] Tools auto-approved while this skill is active
pluginNamestring Plugin the skill originated from
pluginVersionstring Plugin version

Other Events

abort

The current turn was aborted.

Data FieldTypeRequiredDescription
reasonstringWhy the turn was aborted (e.g., "user initiated")

user.message

The user sent a message. Recorded for the session timeline.

Data FieldTypeRequiredDescription
contentstringThe user's message text
transformedContentstring Transformed version after preprocessing
attachmentsAttachment[] File, directory, selection, blob, or GitHub reference attachments
sourcestring Message source identifier
agentModestring Agent mode: "interactive", "plan", "autopilot", or "shell"
interactionIdstring CAPI interaction ID

system.message

A system or developer prompt was injected into the conversation.

Data FieldTypeRequiredDescription
contentstringThe prompt text
role"system" \| "developer"Message role
namestring Source identifier
metadata{ promptVersion?, variables? } Prompt template metadata

external_tool.requested

Ephemeral. The agent wants to invoke an external tool (one provided by the SDK consumer).

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToExternalTool()
sessionIdstringSession this request belongs to
toolCallIdstringTool call ID for this invocation
toolNamestringName of the external tool
argumentsobject Arguments for the tool

external_tool.completed

Ephemeral. An external tool request was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding external_tool.requested

exit_plan_mode.requested

Ephemeral. The agent has created a plan and wants to exit plan mode.

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToExitPlanMode()
summarystringSummary of the plan
planContentstringFull plan file content
actionsstring[]Available user actions (e.g., approve, edit, reject)
recommendedActionstringSuggested action

exit_plan_mode.completed

Ephemeral. An exit plan mode request was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding exit_plan_mode.requested

command.queued

Ephemeral. A slash command was queued for execution.

Data FieldTypeRequiredDescription
requestIdstringUse this to respond via session.respondToQueuedCommand()
commandstringThe slash command text (e.g., /help, /clear)

command.completed

Ephemeral. A queued command was resolved.

Data FieldTypeRequiredDescription
requestIdstringMatches the corresponding command.queued

Quick Reference: Agentic Turn Flow

A typical agentic turn emits events in this order:

assistant.turn_start          → Turn begins
├── assistant.intent          → What the agent plans to do (ephemeral)
├── assistant.reasoning_delta → Streaming thinking chunks (ephemeral, repeated)
├── assistant.reasoning       → Complete thinking block
├── assistant.message_delta   → Streaming response chunks (ephemeral, repeated)
├── assistant.message         → Complete response (may include toolRequests)
├── assistant.usage           → Token usage for this API call (ephemeral)
│
├── [If tools were requested:]
│   ├── permission.requested  → Needs user approval (ephemeral)
│   ├── permission.completed  → Approval result (ephemeral)
│   ├── tool.execution_start  → Tool begins
│   ├── tool.execution_partial_result  → Streaming tool output (ephemeral, repeated)
│   ├── tool.execution_progress        → Progress updates (ephemeral, repeated)
│   ├── tool.execution_complete        → Tool finished
│   │
│   └── [Agent loops: more reasoning → message → tool calls...]
│
assistant.turn_end            → Turn complete
session.idle                  → Ready for next message (ephemeral)

All Event Types at a Glance

Event TypeEphemeralCategoryKey Data Fields
assistant.turn_start AssistantturnId, interactionId?
assistant.intentAssistantintent
assistant.reasoning AssistantreasoningId, content
assistant.reasoning_deltaAssistantreasoningId, deltaContent
assistant.streaming_deltaAssistanttotalResponseSizeBytes
assistant.message AssistantmessageId, content, toolRequests?, outputTokens?, phase?
assistant.message_deltaAssistantmessageId, deltaContent, parentToolCallId?
assistant.turn_end AssistantturnId
assistant.usageAssistantmodel, inputTokens?, outputTokens?, cost?, duration?
tool.user_requested TooltoolCallId, toolName, arguments?
tool.execution_start TooltoolCallId, toolName, arguments?, mcpServerName?
tool.execution_partial_resultTooltoolCallId, partialOutput
tool.execution_progressTooltoolCallId, progressMessage
tool.execution_complete TooltoolCallId, success, result?, error?
session.idleSessionbackgroundTasks?
session.error SessionerrorType, message, statusCode?
session.compaction_start Session(empty)
session.compaction_complete Sessionsuccess, preCompactionTokens?, summaryContent?
session.title_changedSessiontitle
session.context_changed Sessioncwd, gitRoot?, repository?, branch?
session.usage_infoSessiontokenLimit, currentTokens, messagesLength
session.task_complete Sessionsummary?
session.shutdown SessionshutdownType, codeChanges, modelMetrics
permission.requestedPermissionrequestId, permissionRequest
permission.completedPermissionrequestId, result.kind
user_input.requestedUser InputrequestId, question, choices?
user_input.completedUser InputrequestId
elicitation.requestedUser InputrequestId, message, requestedSchema
elicitation.completedUser InputrequestId
subagent.started Sub-AgenttoolCallId, agentName, agentDisplayName
subagent.completed Sub-AgenttoolCallId, agentName, agentDisplayName
subagent.failed Sub-AgenttoolCallId, agentName, error
subagent.selected Sub-AgentagentName, agentDisplayName, tools
subagent.deselected Sub-Agent(empty)
skill.invoked Skillname, path, content, allowedTools?
abort Controlreason
user.message Usercontent, attachments?, agentMode?
system.message Systemcontent, role
external_tool.requestedExternal ToolrequestId, toolName, arguments?
external_tool.completedExternal ToolrequestId
command.queuedCommandrequestId, command
command.completedCommandrequestId
exit_plan_mode.requestedPlan ModerequestId, summary, planContent, actions
exit_plan_mode.completedPlan ModerequestId

Can you improve this documentation? These fine people already did:
Stephen Toub, Bruno Borges, Mackinnon Buck & Patrick Nikoletich
Edit on GitHub

cljdoc builds & hosts documentation for Clojure/Script libraries

Keyboard shortcuts
Ctrl+kJump to recent docs
Move to previous article
Move to next article
Ctrl+/Jump to the search field
× close