module type export agent, sommelier, companion, virtualcustomer, agentContext using Dates, UUIDs, DataStructures, JSON, NATS using GeneralUtils # ---------------------------------------------- 100 --------------------------------------------- # # ============================================================================ # Message types # ============================================================================ abstract type agentMessage end # Base type for all agent messages struct userMessage <: agentMessage # Message from the user role::String # Always "user" content::Vector{messageContent} # Text and/or image content timestamp::Timestamp # When the message was sent end struct assistantMessage <: agentMessage # Message from the AI assistant role::String # Always "assistant" content::Vector{messageContent} # Text and/or image content api::String # API name used (e.g., "openai") provider::String # Provider name (e.g., "anthropic") model::String # Model identifier usage::Usage # Token usage for this message stopReason::String # Why generation stopped (e.g., "end_turn") errorMessage::Union{String, Nothing} # Error if generation failed timestamp::Timestamp # When the message was received end struct toolResultMessage <: agentMessage # Result returned from a tool execution role::String # Always "tool" toolCallId::String # ID matching the tool call toolName::String # Name of the executed tool content::Vector{messageContent} # Tool output content details::Any # Additional tool-specific details usage::Union{Usage, Nothing} # Token usage if applicable addedToolNames::Union{Vector{String}, Nothing} # Tools added during execution isError::Bool # Whether the tool call resulted in an error timestamp::Timestamp # When the result was recorded end # ============================================================================ # Message content types # ============================================================================ abstract type messageContent end # Base type for message content struct textContent <: messageContent # Plain text message content text::String # The text content end struct imageContent <: messageContent # Image message content data::String # Base64-encoded image data mimeType::String # MIME type (e.g., "image/png") end # ============================================================================ # Tool types # ============================================================================ struct agentTool{TParameters, TDetails} # A tool available to the agent name::String # Tool identifier label::String # Human-readable tool name description::String # What the tool does parameters::TParameters # Tool parameters schema (JSON schema) execute::Function # Tool execution function prepareArguments::Union{Function, Nothing} # Optional argument preparation callback executionMode::Union{toolExecutionMode, Nothing} # Override: run tool calls sequentially or in parallel end # ============================================================================ # Agent context # ============================================================================ struct agentContext # Snapshot of the agent's conversation context systemPrompt::String # System prompt for the agent messages::Vector{agentMessage} # Conversation messages tools::Union{Vector{agentTool}, Nothing} # Available tools end # ============================================================================ # Agent state # ============================================================================ mutable struct agentState # Mutable runtime state of an agent systemPrompt::String # System prompt text model::llmModel # LLM model to use tools::Vector{agentTool} # Available tools messages::Vector{agentMessage} # Conversation messages pendingToolCalls::Vector{String} # Tool call IDs waiting for results errorMessage::Union{String, Nothing} # Last error message end function agentState( systemPrompt::String="", model::llmModel=llmModel{String}("", "", "unknown", "unknown", "", false, String[], modelCost(0.0, 0.0, 0.0, 0.0), 0, 0), tools::Vector{agentTool}=agentTool[], messages::Vector{agentMessage}=agentMessage[], ) agentState( systemPrompt, model, deepcopy(tools), deepcopy(messages), Vector{String}(), nothing, ) end # ============================================================================ # Tool call types # ============================================================================ struct toolCall # A tool invocation from the LLM type::String # Always "function" id::String # Unique tool call identifier name::String # Tool name arguments::Dict{String, Any} # Parsed tool arguments end # ============================================================================ # Next turn context # ============================================================================ struct nextTurnContext # Context for preparing the next conversation turn message::assistantMessage # The assistant's message that just completed toolResults::Vector{toolResultMessage} # Tool results from this turn context::agentContext # Current conversation context newMessages::Vector{agentMessage} # Messages to append to the context end # ============================================================================ # llmModel types # ============================================================================ struct modelCost # Model pricing per 1M tokens input::Float64 # Price per 1M input tokens output::Float64 # Price per 1M output tokens cache_read::Float64 # Price per 1M cached read tokens cache_write::Float64 # Price per 1M cache write tokens end struct llmModel{Api} # LLM model configuration id::String # Unique model identifier name::String # Human-readable model name api::Api # API type (parametric type) provider::String # Provider name (e.g., "anthropic", "openai") baseUrl::String # API endpoint base URL reasoning::Bool # Whether the model supports chain-of-thought input::Vector{String} # Supported input modalities (e.g., "text", "image") cost::modelCost # Pricing information contextWindow::Int64 # Maximum context length in tokens maxTokens::Int64 # Maximum output tokens per completion end # ============================================================================ # Agent struct # ============================================================================ mutable struct yiemAgent # High-level agent wrapper _state::agentState # Current state (prompt, model, messages, tools, etc.) input_ch::Channel # user sends prompt message to agent. # if agent is idle, it process user message right away. # if agent is running, it process user message after # the current tool call finished. followUpQueue::Channel # Messages queued via followUp() during agent is # running. After the agent loop process all input_ch # and the agent isn't use tool call. it then process # followUp message output_ch::Channel # agent respond message to user after it process all # user message in input_ch and all followUp message. formatMsgForLLM::Function # Convert agent messages to LLM message format preprocessMessages ::Union{Function, Nothing} # Preprocess/transform messages before sending to LLM beforeToolCall::Union{Function, Nothing} # Callback invoked before executing a tool call afterToolCall::Union{Function, Nothing} # Callback invoked after executing a tool call prepareNextTurn::Union{Function, Nothing} # Callback to prepare the next conversation turn prepareNextTurnWithContext::Union{Function, Nothing} # Same but receives context activeRun::Union{Bool, Nothing} # tracks the currently executing agent run state sessionId::Union{String, Nothing} # Optional session identifier maxRetryDelayMs::Union{Int64, Nothing} # Maximum delay between retries (ms) toolExecution::toolExecutionMode # Default: run tool calls sequentially or in parallel end # Outer constructor — clean keyword API function yiemAgent( ; systemPrompt::String="", model::llmModel=llmModel{String}("", "", "unknown", "unknown", "", false, String[], modelCost(0.0, 0.0, 0.0, 0.0), 0, 0), tools::Vector{agentTool}=agentTool[], messages::Vector{agentMessage}=agentMessage[], formatMsgForLLM::Function=defaultformatMsgForLLM, preprocessMessages ::Union{Function, Nothing}=nothing, beforeToolCall::Union{Function, Nothing}=nothing, afterToolCall::Union{Function, Nothing}=nothing, prepareNextTurn::Union{Function, Nothing}=nothing, prepareNextTurnWithContext::Union{Function, Nothing}=nothing, sessionId::Union{String, Nothing}=nothing, maxRetryDelayMs::Union{Int64, Nothing}=nothing, toolExecution::toolExecutionMode=EXECUTION_PARALLEL, ) new( agentState(systemPrompt, model, tools, messages), Channel(16), formatMsgForLLM, preprocessMessages, onPayload, onResponse, beforeToolCall, afterToolCall, prepareNextTurn, prepareNextTurnWithContext, sessionId, maxRetryDelayMs, toolExecution, ) end end # module type