README

#Agent Package

The agent package provides the core AI agent functionality that manages conversations, executes tools, and handles the conversation loop.

#Core Structs

#Agent

The main agent struct that encapsulates all state and behavior for an AI assistant.

///|
pub(all) struct Agent {
uuid : @uuid.Generator
cwd : String
model : @model.Model
logger : @pino.Logger
event_target : @broadcast.Broadcast[@event.Event]
mut web_search : Bool
// private fields: tools, history, input_queue, etc.
}

Key Fields:
  • uuid: Generator for unique identifiers
  • cwd: Current working directory for tool operations
  • model: AI model configuration
  • event_target: Broadcast channel for lifecycle events

#QueuedMessage

Represents a message waiting to be processed.

///|
pub struct QueuedMessage {
id : @uuid.Uuid
message : @ai.Message
web_search : Bool
}

#Key APIs

#Creating an Agent

pub async fn new(
name? : String,
model : @model.Model,
uuid? : @uuid.Generator,
logger? : @pino.Logger,
system_message? : String,
user_message? : String,
home? : StringView,
cwd~ : StringView,
web_search? : Bool = false,
external_events? : @event.ExternalEventQueue,
history? : @conversation.Conversation,
) -> Agent

#Loading an Existing Agent

pub async fn load(
model : @model.Model,
history : @conversation.Conversation,
// ... other optional parameters
) -> Agent

#Managing Messages

// Queue a message for processing
pub fn Agent::queue_message(
agent : Agent,
message : @ai.Message,
web_search? : Bool = agent.web_search,
) -> @uuid.Uuid

// Get all queued messages
pub fn Agent::queued_messages(self : Agent) -> Array[QueuedMessage]

// Clear all pending inputs
pub fn Agent::clear_inputs(self : Agent) -> Array[QueuedMessage]

#Tool Management

// Add a single tool
pub fn[Output : ToJson + Show] Agent::add_tool(
self : Agent,
tool : @tool.Tool[Output],
enabled? : Bool
) -> Unit

// Add multiple tools
pub fn Agent::add_tools(Self, Array[@tool.AgentTool]) -> Unit

// Set which tools are enabled
pub fn Agent::set_enabled_tools(Self, @set.Set[String]) -> Unit

#Starting the Conversation

pub async fn Agent::start(agent : Agent) -> Unit

#Conversation Loop Algorithm

Agent::start() │ ├─► Spawn event_target in background │ └─► Loop: │ ├─► poll_external_events() │ │ │ ├─► Handle Cancelled → break │ └─► Handle UserMessage → inject into queue │ ├─► Pop from pending_queue → input_queue │ ├─► If input_queue empty → break │ ├─► prepare_messages_for_request() │ │ │ ├─► Calculate pruning │ ├─► Emit Pruned events │ └─► Apply prompt caching │ ├─► @openai.chat() → Get response │ ├─► Emit AssistantMessage event │ ├─► Calibrate token counter │ └─► Execute tool calls → Queue results

#Event System

The agent emits events throughout its lifecycle:

EventWhen
ModelLoadedAgent initialized with model
PreConversationConversation starts
MessageQueuedMessage added to pending queue
MessageUnqueuedMessage moved to input queue
TokenCountedTokens counted before request
ContextPrunedContext trimmed to fit budget
AssistantMessageResponse received from model
PreToolCallBefore tool execution
PostToolCallAfter tool execution
UserMessageUser/Tool message injected
PostConversationConversation ends
CancelledAgent cancelled

#Usage Example

// Create and configure agent
let agent = @agent.new(
model=model_config,
cwd="/project/path",
system_message="You are a helpful coding assistant.",
)

// Add event listener
agent.add_listener(fn(event) {
match event.desc {
AssistantMessage(content, ..) => println(content)
_ => ()
}
})

// Add tools
agent.add_tools([
@execute_command.new(job_manager).to_agent_tool(),
@read_file.new(file_manager).to_agent_tool(),
])

// Queue initial message
agent.queue_message(@ai.user_message(content="Help me debug this code"))

// Start processing
agent.start()

#Dependencies

  • model: Model configuration
  • ai: Message types
  • event: Event definitions
  • tool: Tool types
  • conversation: Conversation history
  • openai: API client
  • context_pruner: Token management
  • broadcast: Event distribution

#
Agent

pub(all) struct Agent {
uuid :
Generator

cwd : String
model :
Model

logger :
Logger

event_target :
Broadcast
[
Event
]
web_search : Bool
request_timeout_ms : Int?
// private fields
}

Represents an AI agent that interacts with language models and executes tools.

The Agent struct encapsulates the complete state and behavior of an AI agent, including conversation history, available tools, model configuration, and event handling. It manages the conversation loop, token counting, context pruning, and tool execution.

#
Agent::add_listener

fn Agent::add_listener(agent : Agent, f : async (
Event
) -> Unit) -> Unit

Registers an event listener for the specified event type on the agent.

Parameters:

  • agent : The agent to add the event listener to.
  • f : The asynchronous callback function to execute when the event is triggered. The function receives an Event containing relevant event data.

#
Agent::add_tool

fn[Output : ToJson] Agent::add_tool(agent : Agent, tool :
Tool
[Output], enabled? : Bool) -> Unit

Adds a tool to the agent's available tools collection.

Parameters:

  • agent : The agent instance to add the tool to.
  • tool : The tool to be added, which will be indexed by its name for future tool calls.

#
Agent::add_tools

fn Agent::add_tools(agent : Agent, tools : Array[
AgentTool
]) -> Unit

Adds multiple tools to the agent's available tools collection.

This is a convenience function for adding multiple AgentTool instances at once. Each tool is added individually and triggers a ToolAdded event.

Parameters:

  • agent : The agent instance to add the tools to.
  • tools : An array of AgentTool instances to be registered with the agent.

#
Agent::clear_inputs

fn Agent::clear_inputs(self : Agent) -> Array[QueuedMessage]

#
Agent::close

fn Agent::close(_ : Agent) -> Unit

Closes the agent and performs any necessary cleanup.

This function is currently a placeholder for future cleanup operations such as closing connections, flushing logs, or releasing resources.

Parameters:

  • agent : The agent instance to close (currently unused).

#
Agent::external_events

Returns the external events queue for this agent.

The environment can use this queue to send events to the agent:
  • Cancelled - to cancel the current operation
  • UserMessage - to send an immediate message that interrupts the flow
  • Diagnostics - to provide IDE diagnostic information

Example:
let queue = agent.external_events()
queue.send(UserMessage("Please stop and focus on this instead"))

#
Agent::id

Gets the unique identifier of the agent.

Parameters:

  • agent : The agent instance to get the identifier for.

Returns the UUID that uniquely identifies this agent instance.

#
Agent::queue_message

fn Agent::queue_message(agent : Agent, message :
Message
, web_search? : Bool) ->
Uuid

Queues a message to be sent to the AI model in the next round of conversation.

#
Agent::queued_messages

fn Agent::queued_messages(self : Agent) -> Array[QueuedMessage]

#
Agent::set_enabled_tools

fn Agent::set_enabled_tools(agent : Agent, tool_names :
Set
[String]) -> Unit

Enables or disables tools based on the provided set of tool names.

Parameters:

  • agent : The agent instance whose tools will be enabled or disabled.
  • tool_names : A set containing the names of tools that should be enabled. Tools not in this set will be disabled.

#
Agent::set_system_prompt

fn Agent::set_system_prompt(agent : Agent, prompt : String?) -> Unit

Sets the system prompt for the agent's conversation history and emits an event notification.

Parameters:

  • agent : The agent instance whose system prompt will be set.
  • prompt : The system prompt text to be set for the agent's conversation.

#
Agent::start

async fn Agent::start(agent : Agent) -> Unit

Starts the agent's conversation loop and executes tool calls until completion.

This function implements the main agent execution loop:
  1. Spawns the event target in the background to handle event processing
  2. Emits a PreConversation event to signal the start
  3. Repeatedly calls the AI model and executes any requested tool calls
  4. Continues until the model returns a response with no tool calls
  5. Emits a PostConversation event when complete

The conversation loop automatically handles:
  • Sending queued messages to the API
  • Processing tool call requests from the model
  • Executing tools and returning results
  • Managing conversation history

Parameters:

  • agent : The agent instance to start.

The function runs within an async task group to manage concurrent operations.

#
Agent::system_prompt

fn Agent::system_prompt(agent : Agent) -> String?

Retrieves the current system prompt from the agent's conversation history.

#
Agent::tools

fn Agent::tools(self : Agent) -> Map[String, Tool]

#
Tool

type Tool

#
Tool::enabled

fn Tool::enabled(self : Tool) -> Bool

#
load

async fn load(model :
Model
, history :
Conversation
, uuid? :
Generator
, logger? :
Logger
, home? : StringView, user_message? : String, web_search? : Bool, external_events? :
ExternalEventQueue
, request_timeout_ms? : Int?) -> Agent

Loads an existing agent from a conversation history with the specified configuration.

Parameters:

  • model : The AI model to use for generating responses and handling tool calls.
  • history : The existing conversation history to load into the agent.
  • uuid : Optional UUID generator for creating unique identifiers. If not provided, uses ChaCha8.
  • logger : Optional logger instance for recording agent activities. Defaults to the MoonClaw product-home log.
  • home : Optional MoonSuite root path. If not provided, uses the OS home as the standalone suite root.
  • user_message : Optional initial user message to send immediately after loading.
  • web_search : Whether to enable web search functionality. Defaults to false.
  • external_events : Optional external event queue for receiving events from the environment.

Returns a new Agent instance initialized with the provided conversation history and configuration.

#
new

async fn new(name? : String, model :
Model
, uuid? :
Generator
, logger? :
Logger
, system_message? : String, user_message? : String, home? : StringView, cwd~ : StringView, web_search? : Bool, external_events? :
ExternalEventQueue
, history? :
Conversation
, request_timeout_ms? : Int?) -> Agent

Creates a new agent instance with the specified AI model and working directory.

This function initializes a complete agent with all necessary components:
  • Random number generator and UUID generator (or uses provided ones)
  • Logger for recording agent activities (defaults to file logging)
  • Conversation history manager
  • Token counter for tracking API usage
  • Context pruner for managing message history within token budgets
  • Empty tool collection and message queue
  • Event target for handling lifecycle events

Parameters:

  • model : The AI model to use for generating responses and handling tool calls.
  • rand : Optional random number generator. If not provided, uses ChaCha8.
  • uuid : Optional UUID generator. If not provided, creates one using the random generator.
  • logger : Optional logger instance. Defaults to the MoonClaw product-home log.
  • cwd : The current working directory that will be used as the base path for tool operations.
  • system_message : Optional system prompt to set at initialization.
  • user_message : Optional initial user message to send immediately after initialization.
  • home : Optional MoonSuite root path. If not provided, uses the OS home as the standalone suite root.
  • web_search : Whether to enable web search functionality. Defaults to false.
  • external_events : Optional external event queue for receiving events from the environment.
  • history : Optional existing conversation history to load into the agent.

Returns a new Agent instance initialized with empty conversation history, no tools, and a fresh event target for handling agent lifecycle events.

The agent's context pruner is configured with the model's safe_zone_tokens setting to automatically manage conversation history size.