event

package
v0.8.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Oct 14, 2026 License: Apache-2.0, MIT Imports: 7 Imported by: 0

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Clear

func Clear()

Clear removes all event handlers from the global event bus

func Emit

func Emit(ctx context.Context, event Event) error

Emit publishes an event to the global event bus

func EmitAndWait

func EmitAndWait(ctx context.Context, event Event) error

EmitAndWait publishes an event to the global event bus and waits for all handlers

func HasHandlers

func HasHandlers(eventType EventType) bool

HasHandlers checks if there are any handlers registered for an event type

func NewEventBusAdapter

func NewEventBusAdapter(bus *EventBus) types.EventBusInterface

NewEventBusAdapter creates a new adapter for EventBus

func Off

func Off(eventType EventType)

Off removes all handlers for a specific event type from the global event bus

func On

func On(eventType EventType, handler EventHandler)

On registers an event handler on the global event bus

func SetGlobalEventBus

func SetGlobalEventBus(bus *EventBus)

SetGlobalEventBus sets the global event bus instance This is useful for testing or custom configurations

Types

type AgentActionData

type AgentActionData struct {
	Iteration  int                    `json:"iteration"`
	ToolName   string                 `json:"tool_name"`
	ToolInput  map[string]interface{} `json:"tool_input"`
	ToolOutput string                 `json:"tool_output"`
	Success    bool                   `json:"success"`
	Error      string                 `json:"error,omitempty"`
	Duration   int64                  `json:"duration_ms"`
}

AgentActionData represents agent tool execution event data

type AgentCompleteData

type AgentCompleteData struct {
	SessionID       string                 `json:"session_id"`
	TotalSteps      int                    `json:"total_steps"`
	FinalAnswer     string                 `json:"final_answer"`
	KnowledgeRefs   []interface{}          `json:"knowledge_refs,omitempty"` // []*types.SearchResult
	AgentSteps      interface{}            `json:"agent_steps,omitempty"`    // []types.AgentStep - detailed execution steps
	Usage           interface{}            `json:"usage,omitempty"`          // *types.TokenUsage - LLM token usage aggregated over the turn
	ModelID         string                 `json:"model_id,omitempty"`       // Chat model whose calls produced Usage
	TotalDurationMs int64                  `json:"total_duration_ms"`
	MessageID       string                 `json:"message_id,omitempty"` // Assistant message ID
	RequestID       string                 `json:"request_id,omitempty"`
	Extra           map[string]interface{} `json:"extra,omitempty"`
}

AgentCompleteData represents agent completion event data

type AgentFinalAnswerData

type AgentFinalAnswerData struct {
	Content    string `json:"content"`
	Done       bool   `json:"done"`
	IsFallback bool   `json:"is_fallback,omitempty"` // True when response is a fallback (no knowledge base match)
	// Truncated marks an answer the provider cut off at the completion-token
	// cap. The text is what the model had produced when the cap hit, not a
	// finished answer, so a client should say so rather than present it as
	// complete. Carried on both the content event and the Done marker,
	// because a live-streamed answer only learns of the cap at the close.
	Truncated bool `json:"truncated,omitempty"`
}

AgentFinalAnswerData represents final answer streaming data

type AgentPlanData

type AgentPlanData struct {
	Query    string   `json:"query"`
	Plan     []string `json:"plan"` // Step descriptions
	Duration int64    `json:"duration_ms,omitempty"`
}

AgentPlanData represents agent planning event data

type AgentQueryData

type AgentQueryData struct {
	SessionID string                 `json:"session_id"`
	Query     string                 `json:"query"`
	RequestID string                 `json:"request_id,omitempty"`
	Extra     map[string]interface{} `json:"extra,omitempty"`
}

AgentQueryData represents agent query event data

type AgentReferencesData

type AgentReferencesData struct {
	References interface{} `json:"references"` // []*types.SearchResult
	Iteration  int         `json:"iteration"`
}

AgentReferencesData represents knowledge references data

type AgentReflectionData

type AgentReflectionData struct {
	ToolCallID string `json:"tool_call_id"` // Tool call ID for tracking
	Content    string `json:"content"`
	Iteration  int    `json:"iteration"`
	Done       bool   `json:"done"` // Whether streaming is complete
}

AgentReflectionData represents agent reflection data

type AgentStepData

type AgentStepData struct {
	Iteration int         `json:"iteration"`
	Thought   string      `json:"thought"`
	ToolCalls interface{} `json:"tool_calls"` // []types.ToolCall
	Duration  int64       `json:"duration_ms"`
}

AgentStepData represents agent step event data

type AgentThoughtData

type AgentThoughtData struct {
	Content   string `json:"content"`
	Iteration int    `json:"iteration"`
	Done      bool   `json:"done"`
}

AgentThoughtData represents agent thought streaming data

type AgentToolCallData

type AgentToolCallData struct {
	ToolCallID string         `json:"tool_call_id"` // Tool call ID for tracking
	ToolName   string         `json:"tool_name"`
	Arguments  map[string]any `json:"arguments,omitempty"`
	Iteration  int            `json:"iteration"`
	Hint       string         `json:"hint,omitempty"` // Human-readable tool hint, e.g. `web_search("query")`
}

AgentToolCallData represents agent tool call notification data

type AgentToolResultData

type AgentToolResultData struct {
	ToolCallID string                 `json:"tool_call_id"` // Tool call ID for tracking
	ToolName   string                 `json:"tool_name"`
	Output     string                 `json:"output"`
	Error      string                 `json:"error,omitempty"`
	Success    bool                   `json:"success"`
	Duration   int64                  `json:"duration_ms,omitempty"`
	Iteration  int                    `json:"iteration"`
	Data       map[string]interface{} `json:"data,omitempty"` // Structured data from tool result (e.g., display_type, formatted results)
}

AgentToolResultData represents agent tool execution result data

type ChatData

type ChatData struct {
	Query       string                 `json:"query"`
	ModelID     string                 `json:"model_id"`
	Response    string                 `json:"response,omitempty"`
	StreamChunk string                 `json:"stream_chunk,omitempty"`
	TokenCount  int                    `json:"token_count,omitempty"`
	Duration    int64                  `json:"duration_ms,omitempty"`
	IsStream    bool                   `json:"is_stream"`
	Extra       map[string]interface{} `json:"extra,omitempty"`
}

ChatData represents chat completion event data

type CommandOutputData

type CommandOutputData struct {
	ToolCallID string    `json:"tool_call_id"`
	Command    string    `json:"command"`
	StartedAt  time.Time `json:"started_at"`
	Output     string    `json:"output"`
	Done       bool      `json:"done"`
}

CommandOutputData is a cumulative tail, so reconnect/replay needs no byte offsets and a missed update does not corrupt the displayed log.

type ContextCompactedData

type ContextCompactedData struct {
	Reason         string `json:"reason"` // threshold | overflow
	Round          int    `json:"round"`
	TokensBefore   int    `json:"tokens_before"`
	TokensAfter    int    `json:"tokens_after"`
	MessagesBefore int    `json:"messages_before"`
	MessagesAfter  int    `json:"messages_after"`
	Summary        string `json:"summary"`
	// Degraded marks a summary that came from the mechanical archive because
	// the summarizer failed.
	Degraded bool `json:"degraded,omitempty"`
	// SplitTurn marks a cut that landed inside a single turn.
	SplitTurn bool `json:"split_turn,omitempty"`
}

ContextCompactedData reports that older conversation was replaced by a summary. Compaction changes what the agent remembers, so it is shown rather than hidden: an answer that forgets an earlier instruction is otherwise indistinguishable from the model ignoring it.

type ErrorData

type ErrorData struct {
	Error     string                 `json:"error"`
	ErrorCode string                 `json:"error_code,omitempty"`
	Stage     string                 `json:"stage"` // 错误发生的阶段
	SessionID string                 `json:"session_id"`
	Query     string                 `json:"query,omitempty"`
	Extra     map[string]interface{} `json:"extra,omitempty"`
}

ErrorData represents error event data

type Event

type Event struct {
	ID        string                 // 事件ID (自动生成UUID,用于流式更新追踪)
	Type      EventType              // 事件类型
	SessionID string                 // 会话ID
	Data      interface{}            // 事件数据
	Metadata  map[string]interface{} // 事件元数据
	RequestID string                 // 请求ID
}

Event represents an event in the system

func NewEvent

func NewEvent(eventType EventType, data interface{}) Event

NewEvent creates a new Event with metadata

func (Event) WithMetadata

func (e Event) WithMetadata(key string, value interface{}) Event

WithMetadata adds metadata to the event

func (Event) WithRequestID

func (e Event) WithRequestID(requestID string) Event

WithRequestID sets the request ID for the event

func (Event) WithSessionID

func (e Event) WithSessionID(sessionID string) Event

WithSessionID sets the session ID for the event

type EventBus

type EventBus struct {
	// contains filtered or unexported fields
}

EventBus manages event publishing and subscription

Example (Basic)

Example: Basic usage of event system

ctx := context.Background()
bus := NewEventBus()

// Register a handler
bus.On(EventQueryReceived, func(ctx context.Context, event Event) error {
	fmt.Printf("Query received: %v\n", event.Data)
	return nil
})

// Emit an event
event := NewEvent(EventQueryReceived, QueryData{
	OriginalQuery: "What is RAG?",
	SessionID:     "session-123",
})

_ = bus.Emit(ctx, event)
Output:
Query received: {What is RAG?  session-123  map[]}
Example (Middleware)

Example: Using middleware

ctx := context.Background()
bus := NewEventBus()

// Create a handler with middleware
handler := func(ctx context.Context, event Event) error {
	data := event.Data.(QueryData)
	fmt.Printf("Processing query: %s\n", data.OriginalQuery)
	return nil
}

// Apply middleware
handlerWithMiddleware := ApplyMiddleware(
	handler,
	WithTiming(),
	WithRecovery(),
)

bus.On(EventQueryReceived, handlerWithMiddleware)

event := NewEvent(EventQueryReceived, QueryData{
	OriginalQuery: "What is RAG?",
})

_ = bus.Emit(ctx, event)
Output:
Processing query: What is RAG?
Example (Pipeline)

Example: Query processing pipeline with events

ctx := context.Background()
bus := NewEventBus()

// Step 1: Query received
bus.On(EventQueryReceived, func(ctx context.Context, event Event) error {
	data := event.Data.(QueryData)
	fmt.Printf("1. Query received: %s\n", data.OriginalQuery)
	return nil
})

// Step 2: Query rewrite
bus.On(EventQueryRewrite, func(ctx context.Context, event Event) error {
	data := event.Data.(QueryData)
	fmt.Printf("2. Rewriting query: %s\n", data.OriginalQuery)
	return nil
})

// Step 3: Retrieval
bus.On(EventRetrievalStart, func(ctx context.Context, event Event) error {
	data := event.Data.(RetrievalData)
	fmt.Printf("3. Starting retrieval for: %s\n", data.Query)
	return nil
})

// Step 4: Rerank
bus.On(EventRerankStart, func(ctx context.Context, event Event) error {
	data := event.Data.(RerankData)
	fmt.Printf("4. Starting rerank for: %s\n", data.Query)
	return nil
})

// Simulate pipeline
sessionID := "session-123"

_ = bus.Emit(ctx, NewEvent(EventQueryReceived, QueryData{
	OriginalQuery: "What is RAG?",
	SessionID:     sessionID,
}))

_ = bus.Emit(ctx, NewEvent(EventQueryRewrite, QueryData{
	OriginalQuery: "What is RAG?",
	SessionID:     sessionID,
}))

_ = bus.Emit(ctx, NewEvent(EventRetrievalStart, RetrievalData{
	Query:           "What is Retrieval Augmented Generation?",
	KnowledgeBaseID: "kb-1",
	TopK:            10,
}))

_ = bus.Emit(ctx, NewEvent(EventRerankStart, RerankData{
	Query:       "What is Retrieval Augmented Generation?",
	InputCount:  10,
	OutputCount: 5,
	ModelID:     "rerank-model-1",
}))
Output:
1. Query received: What is RAG?
2. Rewriting query: What is RAG?
3. Starting retrieval for: What is Retrieval Augmented Generation?
4. Starting rerank for: What is Retrieval Augmented Generation?

func GetGlobalEventBus

func GetGlobalEventBus() *EventBus

GetGlobalEventBus returns the global event bus instance It uses singleton pattern to ensure only one instance exists

func NewAsyncEventBus

func NewAsyncEventBus() *EventBus

NewAsyncEventBus creates a new EventBus with async mode enabled

func NewEventBus

func NewEventBus() *EventBus

NewEventBus creates a new EventBus instance

func (*EventBus) AsEventBusInterface

func (eb *EventBus) AsEventBusInterface() types.EventBusInterface

AsEventBusInterface converts *EventBus to types.EventBusInterface

func (*EventBus) Clear

func (eb *EventBus) Clear()

Clear removes all event handlers

func (*EventBus) Emit

func (eb *EventBus) Emit(ctx context.Context, event Event) error

Emit publishes an event to all registered handlers Returns error if any handler fails (in sync mode) Automatically generates an ID for the event if not provided (from source)

func (*EventBus) EmitAndWait

func (eb *EventBus) EmitAndWait(ctx context.Context, event Event) error

EmitAndWait publishes an event and waits for all handlers to complete This method works in both sync and async mode Automatically generates an ID for the event if not provided (from source)

func (*EventBus) GetHandlerCount

func (eb *EventBus) GetHandlerCount(eventType EventType) int

GetHandlerCount returns the number of handlers for a specific event type

func (*EventBus) HasHandlers

func (eb *EventBus) HasHandlers(eventType EventType) bool

HasHandlers checks if there are any handlers registered for an event type

func (*EventBus) Off

func (eb *EventBus) Off(eventType EventType)

Off removes all handlers for a specific event type

func (*EventBus) On

func (eb *EventBus) On(eventType EventType, handler EventHandler)

On registers an event handler for a specific event type Multiple handlers can be registered for the same event type

type EventBusAdapter

type EventBusAdapter struct {
	// contains filtered or unexported fields
}

EventBusAdapter adapts *EventBus to types.EventBusInterface This allows EventBus to be used through the interface without circular dependencies

func (*EventBusAdapter) Emit

func (a *EventBusAdapter) Emit(ctx context.Context, evt types.Event) error

Emit publishes an event to all registered handlers

func (*EventBusAdapter) On

func (a *EventBusAdapter) On(eventType types.EventType, handler types.EventHandler)

On registers an event handler for a specific event type

type EventHandler

type EventHandler func(ctx context.Context, event Event) error

EventHandler is a function that handles events

func ApplyMiddleware

func ApplyMiddleware(handler EventHandler, middlewares ...Middleware) EventHandler

ApplyMiddleware applies middleware to an event handler

type EventType

type EventType string

EventType represents the type of event in the system

const (
	// Query processing events
	EventQueryReceived   EventType = "query.received"   // 用户查询到达
	EventQueryValidated  EventType = "query.validated"  // 查询验证完成
	EventQueryPreprocess EventType = "query.preprocess" // 查询预处理
	EventQueryRewrite    EventType = "query.rewrite"    // 查询改写
	EventQueryRewritten  EventType = "query.rewritten"  // 查询改写完成

	// Retrieval events
	EventRetrievalStart    EventType = "retrieval.start"    // 检索开始
	EventRetrievalVector   EventType = "retrieval.vector"   // 向量检索
	EventRetrievalKeyword  EventType = "retrieval.keyword"  // 关键词检索
	EventRetrievalEntity   EventType = "retrieval.entity"   // 实体检索
	EventRetrievalComplete EventType = "retrieval.complete" // 检索完成

	// Rerank events
	EventRerankStart    EventType = "rerank.start"    // 排序开始
	EventRerankComplete EventType = "rerank.complete" // 排序完成

	// Merge events
	EventMergeStart    EventType = "merge.start"    // 合并开始
	EventMergeComplete EventType = "merge.complete" // 合并完成

	// Chat completion events
	EventChatStart    EventType = "chat.start"    // 聊天生成开始
	EventChatComplete EventType = "chat.complete" // 聊天生成完成
	EventChatStream   EventType = "chat.stream"   // 聊天流式输出

	// Agent events
	EventAgentQuery    EventType = "agent.query"    // Agent 查询开始
	EventAgentPlan     EventType = "agent.plan"     // Agent 计划生成
	EventAgentStep     EventType = "agent.step"     // Agent 步骤执行
	EventAgentTool     EventType = "agent.tool"     // Agent 工具调用
	EventAgentComplete EventType = "agent.complete" // Agent 完成

	// Agent streaming events (for real-time feedback)
	EventAgentThought       EventType = "thought"        // Agent 思考过程
	EventAgentCommandOutput EventType = "command_output" // bounded command output
	EventAgentToolCall      EventType = "tool_call"      // 工具调用通知
	EventAgentToolResult    EventType = "tool_result"    // 工具结果
	EventAgentReflection    EventType = "reflection"     // Agent 反思
	EventAgentReferences    EventType = "references"     // 知识引用
	EventAgentFinalAnswer   EventType = "final_answer"   // 最终答案

	// MCP tool human approval (issue #1173)
	EventToolApprovalRequired EventType = "tool_approval_required"
	EventToolApprovalResolved EventType = "tool_approval_resolved"

	// MCP OAuth in-conversation authorization prompt: emitted when an
	// OAuth-enabled MCP service is invoked but the current user has not
	// authorized it yet. The agent pauses until the user authorizes (or the
	// wait times out / is canceled).
	EventMCPOAuthRequired EventType = "mcp_oauth_required"
	EventMCPOAuthResolved EventType = "mcp_oauth_resolved"

	// Error events
	EventError EventType = "error" // 错误事件

	// Long-term memory recalled for this turn. Emitted once, before the answer
	// streams, so the UI can show which memories the answer saw.
	EventMemoryRecalled EventType = "memory_recalled"

	// EventContextCompacted is emitted when older conversation was summarized
	// away to fit the context window.
	EventContextCompacted EventType = "context_compacted"

	// EventUserMessageInjected is emitted when a message the user appended
	// while the run was in flight was accepted into the running turn (see
	// agent drainSteerMessages).
	EventUserMessageInjected EventType = "user_message_injected"

	// Session events
	EventSessionTitle EventType = "session_title" // 会话标题更新

	// Control events
	EventStop EventType = "stop" // 停止对话生成
)

type MCPOAuthRequiredData

type MCPOAuthRequiredData struct {
	PendingID          string `json:"pending_id"`
	TenantID           uint64 `json:"tenant_id"`
	SessionID          string `json:"session_id"`
	AssistantMessageID string `json:"assistant_message_id"`
	ServiceID          string `json:"service_id"`
	ServiceName        string `json:"service_name"`
	MCPToolName        string `json:"mcp_tool_name"`
	TimeoutSeconds     int    `json:"timeout_seconds"`
	RequestedAtUnix    int64  `json:"requested_at"`
	ToolCallID         string `json:"tool_call_id"`
	RequestID          string `json:"request_id,omitempty"`
}

MCPOAuthRequiredData is emitted when an OAuth-enabled MCP service is invoked during a conversation but the current user has not authorized it yet. The UI surfaces an "Authorize" card; the agent pauses until the user authorizes.

type MCPOAuthResolvedData

type MCPOAuthResolvedData struct {
	PendingID  string `json:"pending_id"`
	ServiceID  string `json:"service_id"`
	Authorized bool   `json:"authorized"`
	Reason     string `json:"reason,omitempty"`
	TimedOut   bool   `json:"timed_out,omitempty"`
	Canceled   bool   `json:"canceled,omitempty"`
}

MCPOAuthResolvedData confirms the outcome of an in-conversation OAuth prompt (authorized / timeout / cancel).

type MemoryRecalledData

type MemoryRecalledData struct {
	Memories interface{} `json:"memories"`
}

MemoryRecalledData carries the long-term memories injected into this turn. Memories is []types.UsedMemory, kept as interface{} for the same reason AgentReferencesData does: the event package stays free of a types import.

type MergeData

type MergeData struct {
	InputCount  int                    `json:"input_count"`
	OutputCount int                    `json:"output_count"`
	MergeType   string                 `json:"merge_type"` // dedup, fusion, etc.
	Results     interface{}            `json:"results,omitempty"`
	Duration    int64                  `json:"duration_ms,omitempty"`
	Extra       map[string]interface{} `json:"extra,omitempty"`
}

MergeData represents merge event data

type Middleware

type Middleware func(EventHandler) EventHandler

Middleware is a function that wraps an EventHandler

func Chain

func Chain(middlewares ...Middleware) Middleware

Chain combines multiple middlewares into a single middleware

func WithLogging

func WithLogging() Middleware

WithLogging creates a middleware that logs event handling

func WithRecovery

func WithRecovery() Middleware

WithRecovery creates a middleware that recovers from panics

func WithTiming

func WithTiming() Middleware

WithTiming creates a middleware that tracks event handling duration

type PanicError

type PanicError struct {
	Panic interface{}
}

PanicError represents a panic that occurred in an event handler

func (*PanicError) Error

func (e *PanicError) Error() string

type QueryData

type QueryData struct {
	OriginalQuery  string                 `json:"original_query"`
	RewrittenQuery string                 `json:"rewritten_query,omitempty"`
	SessionID      string                 `json:"session_id"`
	UserID         string                 `json:"user_id,omitempty"`
	Extra          map[string]interface{} `json:"extra,omitempty"`
}

QueryData represents query-related event data

type RerankData

type RerankData struct {
	Query       string                 `json:"query"`
	InputCount  int                    `json:"input_count"`  // 输入的候选数量
	OutputCount int                    `json:"output_count"` // 输出的结果数量
	ModelID     string                 `json:"model_id"`
	Threshold   float64                `json:"threshold"`
	Results     interface{}            `json:"results,omitempty"`
	Duration    int64                  `json:"duration_ms,omitempty"` // 排序耗时(毫秒)
	Extra       map[string]interface{} `json:"extra,omitempty"`
}

RerankData represents reranking event data

type RetrievalData

type RetrievalData struct {
	Query           string                 `json:"query"`
	KnowledgeBaseID string                 `json:"knowledge_base_id"`
	TopK            int                    `json:"top_k"`
	Threshold       float64                `json:"threshold"`
	RetrievalType   string                 `json:"retrieval_type"` // vector, keyword, entity
	ResultCount     int                    `json:"result_count"`
	Results         interface{}            `json:"results,omitempty"`
	Duration        int64                  `json:"duration_ms,omitempty"` // 检索耗时(毫秒)
	Extra           map[string]interface{} `json:"extra,omitempty"`
}

RetrievalData represents retrieval event data

type SessionTitleData

type SessionTitleData struct {
	SessionID string `json:"session_id"`
	Title     string `json:"title"`
}

SessionTitleData represents session title update data

type StopData

type StopData struct {
	SessionID string `json:"session_id"`
	MessageID string `json:"message_id"`
	Reason    string `json:"reason,omitempty"` // Optional reason for stopping
}

StopData represents stop generation request data

type ToolApprovalRequiredData

type ToolApprovalRequiredData struct {
	PendingID          string      `json:"pending_id"`
	TenantID           uint64      `json:"tenant_id"`
	SessionID          string      `json:"session_id"`
	AssistantMessageID string      `json:"assistant_message_id"`
	ServiceID          string      `json:"service_id"`
	ServiceName        string      `json:"service_name"`
	MCPToolName        string      `json:"mcp_tool_name"`
	RegisteredToolName string      `json:"registered_tool_name"`
	Description        string      `json:"description"`
	Args               interface{} `json:"args,omitempty"`
	ArgsJSON           string      `json:"args_json,omitempty"`
	TimeoutSeconds     int         `json:"timeout_seconds"`
	RequestedAtUnix    int64       `json:"requested_at"`
	ToolCallID         string      `json:"tool_call_id"`
	RequestID          string      `json:"request_id,omitempty"`
}

ToolApprovalRequiredData is emitted when an MCP tool marked dangerous is about to run.

type ToolApprovalResolvedData

type ToolApprovalResolvedData struct {
	PendingID string `json:"pending_id"`
	Approved  bool   `json:"approved"`
	Reason    string `json:"reason,omitempty"`
	TimedOut  bool   `json:"timed_out,omitempty"`
	Canceled  bool   `json:"canceled,omitempty"`
}

ToolApprovalResolvedData confirms the user decision (or timeout/cancel).

type UserMessageInjectedData

type UserMessageInjectedData struct {
	SteerID       string `json:"steer_id"`   // Correlates with the queued steer event
	Content       string `json:"content"`    // The injected text, as sent to the model
	MessageID     string `json:"message_id"` // Durable assistant message of the run
	UserMessageID string `json:"user_message_id,omitempty"`
}

UserMessageInjectedData reports that a message the user appended while the run was in flight was accepted into the running turn: a user-role row has been persisted under the run's request ID and the text was appended to the agent's message list, so the next LLM call already sees it.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL