Event is the core communication mechanism between Agent and users in trpc-agent-go. It's like a message envelope that carries Agent response content, tool call results, error information, etc. Through Event, you can understand Agent's working status in real-time, handle streaming responses, implement multi-Agent collaboration, and track tool execution.
Event Overview
Event is the carrier for communication between Agent and users.
Users obtain event streams through the runner.Run() method, then listen to event channels to handle Agent responses.
Event Structure
Event represents an event between Agent and users, with the following structure definition:
typeEventstruct{// Response is the basic response structure of Event, carrying LLM responses.*model.Response// InvocationID is the unique identifier for this invocation.InvocationIDstring`json:"invocationId"`// Author is the initiator of the event.Authorstring`json:"author"`// ID is the unique identifier of the event.IDstring`json:"id"`// Timestamp is the timestamp of the event.Timestamptime.Time`json:"timestamp"`// Branch is a branch identifier for multi-Agent collaboration.Branchstring`json:"branch,omitempty"`// RequiresCompletion indicates whether this event requires a completion signal.RequiresCompletionbool`json:"requiresCompletion,omitempty"`// CompletionID is used for the completion signal of this event.CompletionIDstring`json:"completionId,omitempty"`// LongRunningToolIDs is a set of IDs for long-running function calls.// Agent clients will understand which function calls are long-running from this field.// Only valid for function call events.LongRunningToolIDsmap[string]struct{}`json:"longRunningToolIDs,omitempty"`}
model.Response is the basic response structure of Event, carrying LLM responses, tool calls, and error information, defined as follows:
typeResponsestruct{// Response unique identifier.IDstring`json:"id"`// Object type (such as "chat.completion", "error", etc.), helps clients identify processing methods.Objectstring`json:"object"`// Creation timestamp.Createdint64`json:"created"`// Model name used.Modelstring`json:"model"`// Response options, LLM may generate multiple candidate responses for user selection, default is 1.Choices[]Choice`json:"choices"`// Usage statistics, records token usage.Usage*Usage`json:"usage,omitempty"`// System fingerprint.SystemFingerprint*string`json:"system_fingerprint,omitempty"`// Error information.Error*ResponseError`json:"error,omitempty"`// Timestamp.Timestamptime.Time`json:"timestamp"`// Indicates whether the entire conversation is complete.Donebool`json:"done"`// Whether it's a partial response.IsPartialbool`json:"is_partial"`}typeChoicestruct{// Choice index.Indexint`json:"index"`// Complete message, contains the entire response.MessageMessage`json:"message,omitempty"`// Incremental message, used for streaming responses, only contains new content of current chunk.// For example: complete response "Hello, how can I help you?" in streaming response:// First event: Delta.Content = "Hello"// Second event: Delta.Content = ", how" // Third event: Delta.Content = " can I help you?"DeltaMessage`json:"delta,omitempty"`// Completion reason.FinishReason*string`json:"finish_reason,omitempty"`}typeMessagestruct{// Role of message initiator, such as "system", "user", "assistant", "tool".Rolestring`json:"role"`// Message content.Contentstring`json:"content"`// Content fragments for multimodal messages.ContentParts[]ContentPart`json:"content_parts,omitempty"`// ID of the tool used by tool response.ToolIDstring`json:"tool_id,omitempty"`// Name of the tool used by tool response.ToolNamestring`json:"tool_name,omitempty"`// Optional tool calls.ToolCalls[]ToolCall`json:"tool_calls,omitempty"`}typeUsagestruct{// Number of tokens used in prompts.PromptTokensint`json:"prompt_tokens"`// Number of tokens used in completion.CompletionTokensint`json:"completion_tokens"`// Total number of tokens used in response.TotalTokensint`json:"total_tokens"`}
Event Types
Events are created and sent in the following scenarios:
User Message Events: Automatically created when users send messages
Agent Response Events: Created when Agent generates responses
Streaming Response Events: Created for each response chunk in streaming mode
Tool Call Events: Created when Agent calls tools
Error Events: Created when errors occur
Agent Transfer Events: Created when Agent transfers to other Agents
Completion Events: Created when Agent execution completes
Based on the model.Response.Object field, Events can be divided into the following types:
// processMessage handles single message interaction.func(c*multiTurnChat)processMessage(ctxcontext.Context,userMessagestring)error{message:=model.NewUserMessage(userMessage)// Run agent through runner.eventChan,err:=c.runner.Run(ctx,c.userID,c.sessionID,message)iferr!=nil{returnfmt.Errorf("failed to run agent: %w",err)}// Handle response.returnc.processResponse(eventChan)}// processResponse handles response, including streaming response and tool call visualization.func(c*multiTurnChat)processResponse(eventChan<-chan*event.Event)error{fmt.Print("π€ Assistant: ")var(fullContentstring// Accumulated complete content.toolCallsDetectedbool// Whether tool calls are detected.assistantStartedbool// Whether Assistant has started replying.)forevent:=rangeeventChan{// Handle single event.iferr:=c.handleEvent(event,&toolCallsDetected,&assistantStarted,&fullContent);err!=nil{returnerr}// Check if it's the final event.ifevent.Done&&!c.isToolEvent(event){fmt.Printf("\n")break}}returnnil}// handleEvent handles single event.func(c*multiTurnChat)handleEvent(event*event.Event,toolCallsDetected*bool,assistantStarted*bool,fullContent*string,)error{// 1. Handle error events.ifevent.Error!=nil{fmt.Printf("\nβ Error: %s\n",event.Error.Message)returnnil}// 2. Handle tool calls.ifc.handleToolCalls(event,toolCallsDetected,assistantStarted){returnnil}// 3. Handle tool responses.ifc.handleToolResponses(event){returnnil}// 4. Handle content.c.handleContent(event,toolCallsDetected,assistantStarted,fullContent)returnnil}// handleToolCalls detects and displays tool calls.func(c*multiTurnChat)handleToolCalls(event*event.Event,toolCallsDetected*bool,assistantStarted*bool,)bool{iflen(event.Choices)>0&&len(event.Choices[0].Message.ToolCalls)>0{*toolCallsDetected=trueif*assistantStarted{fmt.Printf("\n")}fmt.Printf("π§ Tool calls initiated:\n")for_,toolCall:=rangeevent.Choices[0].Message.ToolCalls{fmt.Printf(" β’ %s (ID: %s)\n",toolCall.Function.Name,toolCall.ID)iflen(toolCall.Function.Arguments)>0{fmt.Printf(" Args: %s\n",string(toolCall.Function.Arguments))}}fmt.Printf("\nπ Executing tools...\n")returntrue}returnfalse}// handleToolResponses detects and displays tool responses.func(c*multiTurnChat)handleToolResponses(event*event.Event)bool{ifevent.Response!=nil&&len(event.Response.Choices)>0{for_,choice:=rangeevent.Response.Choices{ifchoice.Message.Role==model.RoleTool&&choice.Message.ToolID!=""{fmt.Printf("β Tool response (ID: %s): %s\n",choice.Message.ToolID,strings.TrimSpace(choice.Message.Content))returntrue}}}returnfalse}// handleContent handles and displays content.func(c*multiTurnChat)handleContent(event*event.Event,toolCallsDetected*bool,assistantStarted*bool,fullContent*string,){iflen(event.Choices)>0{choice:=event.Choices[0]content:=c.extractContent(choice)ifcontent!=""{c.displayContent(content,toolCallsDetected,assistantStarted,fullContent)}}}// extractContent extracts content based on streaming mode.func(c*multiTurnChat)extractContent(choicemodel.Choice)string{ifc.streaming{// Streaming mode: use incremental content.returnchoice.Delta.Content}// Non-streaming mode: use complete message content.returnchoice.Message.Content}// displayContent prints content to console.func(c*multiTurnChat)displayContent(contentstring,toolCallsDetected*bool,assistantStarted*bool,fullContent*string,){if!*assistantStarted{if*toolCallsDetected{fmt.Printf("\nπ€ Assistant: ")}*assistantStarted=true}fmt.Print(content)*fullContent+=content}// isToolEvent checks if event is a tool response.func(c*multiTurnChat)isToolEvent(event*event.Event)bool{ifevent.Response==nil{returnfalse}// Check if there are tool calls.iflen(event.Choices)>0&&len(event.Choices[0].Message.ToolCalls)>0{returntrue}// Check if there's a tool ID.iflen(event.Choices)>0&&event.Choices[0].Message.ToolID!=""{returntrue}// Check if it's a tool role.for_,choice:=rangeevent.Response.Choices{ifchoice.Message.Role==model.RoleTool{returntrue}}returnfalse}