- Added support for "execute" message type to track tool execution observations within the sandbox environment. - Implemented handling for execute messages in the stream processing, allowing for real-time updates on tool execution status. - Enhanced the stream parser to manage the lifecycle of execute messages, including merging input and output data. - Updated the stream handler to accommodate new message types, improving overall message processing capabilities. - Refactored related tests to ensure coverage for the new execute message functionality, enhancing reliability.
171 lines
4.2 KiB
Go
171 lines
4.2 KiB
Go
package output
|
|
|
|
import (
|
|
"github.com/yaoapp/yao/agent/output/message"
|
|
)
|
|
|
|
// Helper functions for creating built-in message types
|
|
|
|
// NewUserInputMessage creates a user input message (for frontend display)
|
|
// content can be string or []ContentPart for multimodal content
|
|
func NewUserInputMessage(content interface{}, role, name string) *message.Message {
|
|
props := map[string]interface{}{
|
|
"content": content,
|
|
}
|
|
if role != "" {
|
|
props["role"] = role
|
|
}
|
|
if name != "" {
|
|
props["name"] = name
|
|
}
|
|
return &message.Message{
|
|
Type: message.TypeUserInput,
|
|
Props: props,
|
|
}
|
|
}
|
|
|
|
// NewTextMessage creates a text message
|
|
func NewTextMessage(content string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeText,
|
|
Props: map[string]interface{}{
|
|
"content": content,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewThinkingMessage creates a thinking message
|
|
func NewThinkingMessage(content string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeThinking,
|
|
Props: map[string]interface{}{
|
|
"content": content,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewLoadingMessage creates a loading message
|
|
func NewLoadingMessage(msg string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeLoading,
|
|
Props: map[string]interface{}{
|
|
"message": msg,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewToolCallMessage creates a tool call message
|
|
func NewToolCallMessage(id, name, arguments string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeToolCall,
|
|
Props: map[string]interface{}{
|
|
"id": id,
|
|
"name": name,
|
|
"arguments": arguments,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewExecuteMessage creates an execute observation message for sandbox CLI agent actions.
|
|
//
|
|
// tool: the tool name (e.g., "Bash", "Read", "Write")
|
|
// toolID: the agent-side tool call ID
|
|
// input: the tool input (structured, may be nil for status-only updates)
|
|
// status: "running" | "completed" | "error"
|
|
func NewExecuteMessage(tool, toolID string, input interface{}, status string) *message.Message {
|
|
props := map[string]interface{}{
|
|
"tool": tool,
|
|
"tool_id": toolID,
|
|
"status": status,
|
|
}
|
|
if input != nil {
|
|
props["input"] = input
|
|
}
|
|
return &message.Message{
|
|
Type: message.TypeExecute,
|
|
Props: props,
|
|
}
|
|
}
|
|
|
|
// NewErrorMessage creates an error message
|
|
func NewErrorMessage(msg, code string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeError,
|
|
Props: map[string]interface{}{
|
|
"message": msg,
|
|
"code": code,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewActionMessage creates an action message
|
|
func NewActionMessage(name string, payload map[string]interface{}) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeAction,
|
|
Props: map[string]interface{}{
|
|
"name": name,
|
|
"payload": payload,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewEventMessage creates an event message
|
|
func NewEventMessage(event string, msg string, data interface{}) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeEvent,
|
|
Props: map[string]interface{}{
|
|
"event": event,
|
|
"message": msg,
|
|
"data": data,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewImageMessage creates an image message
|
|
func NewImageMessage(url string, alt string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeImage,
|
|
Props: map[string]interface{}{
|
|
"url": url,
|
|
"alt": alt,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewAudioMessage creates an audio message
|
|
func NewAudioMessage(url string, format string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeAudio,
|
|
Props: map[string]interface{}{
|
|
"url": url,
|
|
"format": format,
|
|
},
|
|
}
|
|
}
|
|
|
|
// NewVideoMessage creates a video message
|
|
func NewVideoMessage(url string) *message.Message {
|
|
return &message.Message{
|
|
Type: message.TypeVideo,
|
|
Props: map[string]interface{}{
|
|
"url": url,
|
|
},
|
|
}
|
|
}
|
|
|
|
// IsBuiltinType checks if a message type is a built-in type
|
|
func IsBuiltinType(msgType string) bool {
|
|
switch msgType {
|
|
case message.TypeUserInput, message.TypeText, message.TypeThinking, message.TypeLoading, message.TypeToolCall, message.TypeExecute, message.TypeError, message.TypeImage, message.TypeAudio, message.TypeVideo, message.TypeAction, message.TypeEvent:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// GenerateID generates a unique message ID using nanoid
|
|
// Deprecated: Use message.GenerateMessageID(), message.GenerateChunkID(),
|
|
// message.GenerateBlockID(), or message.GenerateThreadID() instead
|
|
func GenerateID() string {
|
|
return message.GenerateNanoID()
|
|
}
|