API reference
Every public item of every package, generated from the interfaces the compiler writes. 435 public items across 13 packages.
#The facade moonbitstack/moonkoog
What importing the module root gives you: the agent, the built-in middleware, the planner, the team builder and the shipped tools, all re-exported from the package that owns them.
Values
pub fn answer_only(name? : String) -> @agent.Strategy
pub fn calculator() -> @agent.ToolSpec
pub fn chat() -> @agent.Strategy
pub fn create_agent(&@moonmuse.Provider, @agent.AgentConfig, saver? : &@moonstate.Saver, store? : &@moonstate.Store, executor? : &@moonstate.Executor) -> @agent.Agent raise @moonstate.Refused
pub let default_limits : @agent.Limits
pub let default_options : @agent.Options
pub fn describe(@agent.AgentError) -> String
pub fn handoff_tool(Array[String]) -> @agent.ToolSpec
pub fn plan_and_execute(@agent.AgentConfig, limit? : Int32, replan? : Bool) -> @agent.AgentConfig
pub fn react(reasoning_prompt? : String, interval? : Int32) -> @agent.Strategy
pub fn[S : Eq + Hash] search(Array[@plan.GoapAction[S]], S, @plan.GoapGoal[S]) -> Array[String]?
pub fn single_run() -> @agent.Strategy
pub fn supervisor(@agent.AgentConfig, Array[@agent.Agent], instruction? : String, max_turns? : Int32) -> @agent.AgentConfig
pub fn swarm(@agent.AgentConfig, Array[@agent.Agent]) -> @agent.AgentConfig
Type aliases
pub using @agent {type Agent}
pub using @agent {type AgentConfig}
pub using @agent {type AgentError}
pub using @agent {type AgentState}
pub using @middleware {type ContextEditing}
pub using @middleware {type EditingStrategy}
pub using @agent {type Event}
pub using @agent {type EventHandler}
pub using @middleware {type FileSearch}
pub using @plan {type GoapAction}
pub using @plan {type GoapGoal}
pub using @middleware {type HumanInTheLoop}
pub using @agent {type Limits}
pub using @middleware {type ModelCallLimit}
pub using @middleware {type ModelFallback}
pub using @agent {type ModelOutcome}
pub using @middleware {type ModelRetry}
pub using @agent {type NodeKind}
pub using @agent {type Options}
pub using @middleware {type Pii}
pub using @middleware {type PiiRule}
pub using @agent {type RequestMode}
pub using @agent {type RunContext}
pub using @middleware {type ShellTool}
pub using @agent {type Strategy}
pub using @middleware {type Summarization}
pub using @middleware {type TodoList}
pub using @middleware {type ToolCallLimit}
pub using @agent {type ToolOutcome}
pub using @middleware {type ToolRetry}
pub using @middleware {type ToolSelection}
pub using @agent {type ToolSpec}
pub using @agent {type Tools}
pub using @agent {type Update}
pub using @agent {trait Middleware}
#The agent moonbitstack/moonkoog/agent
The run itself: the state a graph checkpoints, the strategy that decides which node runs, the middleware chain around each model and tool call, and the events a run reports.
Values
pub async fn after_agent_hooks(Runtime, RunContext, AgentState) -> Array[Update]
pub let agent_node : String
The node an agent run starts from: it seeds the system message, runs the middleware's run-start hooks, and hands over to the model node.
pub fn answer_only(name? : String) -> Strategy
A strategy with a single model call: no tools, one answer. Useful as a judge, a classifier or the planner half of a plan-and-execute run.
pub async fn before_agent_hooks(Runtime, RunContext) -> Array[Update]
pub fn chat() -> Strategy
The chat loop: the model must call a tool rather than answer in prose, and the run ends when it calls the exit tool. `exit_tool` is what the run watches for.
pub async fn compress(Runtime, RunContext, Array[@moonmuse.Message], HistoryPolicy) -> Compressed
pub fn create_agent(&@moonmuse.Provider, AgentConfig, saver? : &@moonstate.Saver, store? : &@moonstate.Store, executor? : &@moonstate.Executor) -> Agent raise @moonstate.Refused
Build an agent. The strategy defaults to [`single_run`]; tools from the config are installed first, then whatever the middleware contributes, so a middleware can replace a default tool of the same name.
pub let default_limits : Limits
The default caps.
pub let default_options : Options
Nothing pinned: the provider's defaults, tools left to the model's judgement, no stop sequences.
pub fn describe(AgentError) -> String
A failure as a line of text, for hooks that only report.
pub let error_key : String
The storage key a run records its own failure under. The graph cannot raise a library error from a node, so the node records what went wrong and the walk ends; the agent turns that record back into the error a caller expects.
pub fn error_text(Error) -> String
The text of an error, without the type path a `suberror`'s `to_string` prepends.
pub let finish_node : String
The node a run ends on.
pub let handoff_key : String
The storage key a tool writes to ask the run to hand over to another agent. The value is the node name of the agent to continue with.
pub fn install_tools(Runtime) -> Unit
Let every middleware add its tools. Done once, when the agent is built.
pub fn merge(AgentState, Update) -> AgentState
Apply one update.
pub fn message_from_json(@json.Json, @json.JsonPath) -> @moonmuse.Message raise @json.JsonDecodeError
A message from its JSON form; the error names the field that did not read.
pub fn message_to_json(@moonmuse.Message) -> @json.Json
A message as JSON. The conversation is part of a checkpoint, so it has to survive a round trip through the saver: `role`, then one entry per part, each tagged with the part's kind.
pub let model_node : String
The node that makes one model call.
pub async fn node_agent(Runtime, String, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_compress(Runtime, HistoryPolicy, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_custom(Runtime, String, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_execute(Runtime, ExecuteMode, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_finish(Runtime, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_request(Runtime, RequestMode, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_request_to(Runtime, RequestMode, String, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
pub async fn node_think(Runtime, AgentState, @moonstate.Run, prompt~ : String, every~ : Int32) -> Array[@moonstate.Step[AgentState, Update]]
pub fn part_from_json(@json.Json, @json.JsonPath) -> @moonmuse.Part raise @json.JsonDecodeError
One part from its JSON form.
pub fn part_to_json(@moonmuse.Part) -> @json.Json
One part as JSON, tagged with its kind.
pub async fn pipeline_model(Runtime, RunContext, ModelCall, RequestMode) -> ModelOutcome
pub async fn pipeline_tool(Runtime, RunContext, ToolCall) -> ToolOutcome
pub fn react(reasoning_prompt? : String, interval? : Int32) -> Strategy
Reason-and-act: after each round of tools the model is asked to think about what it learned, without tools in reach, before it acts again. `interval` spaces the thinking out, so a long loop does not pay for a reasoning call on every round.
pub fn role_code(@moonmuse.Role) -> String
The wire name of a role, the same spelling the providers use.
pub fn role_of(String) -> @moonmuse.Role?
A role from its wire name.
pub fn single_run() -> Strategy
The one-run loop: ask, run whatever was asked for, ask again until the model answers in prose. This is the strategy an agent gets when nothing else is asked for.
pub fn[T : @json.ToJson] store(String, T) -> Update
pub let tools_node : String
The node that executes the calls a reply asked for.
Errors
pub(all) suberror AgentError {
A run that went wrong, or one that was interrupted and can be resumed. `Engine` carries the graph engine's own error unchanged so that an interrupt, a step limit and a backend failure stay distinguishable to the caller.
Types and methods
pub struct Agent {
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub fn Agent::graph(Self) -> @moonstate.Graph[AgentState, Update]
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub async fn Agent::history(Self, String) -> Array[@moonstate.Snapshot[AgentState]] raise AgentError
pub fn Agent::model(Self) -> String
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub fn Agent::name(Self) -> String
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub async fn Agent::resume_from(Self, String, @json.Json) -> String raise AgentError
pub async fn Agent::run(Self, String, thread? : String) -> String raise AgentError
pub fn Agent::runtime(Self) -> Runtime
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub async fn Agent::state(Self, String) -> @moonstate.Snapshot[AgentState]? raise AgentError
pub fn Agent::strategy_name(Self) -> String
An agent: a runtime, the graph its strategy compiled to, and the operations a caller runs. The graph is the same engine a plain state machine uses — an agent is a graph whose nodes happen to talk to a model, which is what keeps checkpoints, interrupts, resumption and multi-agent composition available without a second mechanism.
pub async fn Agent::stream(Self, String, (Event) -> Unit, thread? : String) -> String raise AgentError
pub(all) struct AgentConfig {
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::chat(String, name? : String) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::exit_tool_spec() -> ToolSpec
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::new(String, name? : String) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::react(String, name? : String, reasoning_prompt? : String, interval? : Int32) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_events(Self, EventHandler) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_instructions(Self, String) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_limits(Self, Limits) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_middleware(Self, &Middleware) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_node(Self, String, async (Runtime, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_options(Self, Options) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_strategy(Self, Strategy) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_structured(Self, Structured) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub fn AgentConfig::with_tools(Self, Array[ToolSpec]) -> Self
Everything an agent is configured with, short of the provider and the checkpoint stores. A config is data plus a strategy: copying it and changing one field is how a second agent is made, and the presets are the three shapes a run usually takes.
pub(all) struct AgentState {
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::from_json(@json.Json, @json.JsonPath) -> Self raise @json.JsonDecodeError
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn[T : @json.FromJson] AgentState::get(Self, String) -> T?
pub fn AgentState::messages(Self) -> Array[@moonmuse.Message]
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::new() -> Self
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::raw(Self, String) -> @json.Json?
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::text(Self) -> String
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::to_json(Self) -> @json.Json
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub fn AgentState::with_messages(Self, Array[@moonmuse.Message]) -> Self
What a run carries between nodes: the conversation, the run's own scratch space, how many model and tool calls it has spent, and the answer once one is set. The whole value is the graph's state, so it round-trips through JSON for the saver — a checkpoint restores the conversation and the counters, which is what lets a run resume with the budgets it had already spent.
pub impl @json.FromJson for AgentState
pub impl @json.ToJson for AgentState
pub(all) enum Compressed {
The result of compressing a conversation: the messages to carry on with, or why the summary could not be written.
pub(all) enum Event {
What a run broadcasts: one variant per boundary worth observing. The stream is data so it can be rendered as log lines, counted in tests, or translated into OpenTelemetry spans without the observer reaching into the graph.
pub struct EventHandler {
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::intercept_llm_call_completed(Self, (@moonmuse.Reply) -> @moonmuse.Reply) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::intercept_llm_call_starting(Self, (@moonmuse.Request) -> @moonmuse.Request) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::intercept_tool_call_completed(Self, (String, String) -> String) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::intercept_tool_call_starting(Self, (String, @json.Json) -> @json.Json) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::new() -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::observe(Self, (Event) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_agent_completed(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_agent_execution_failed(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_agent_starting(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_llm_call_completed(Self, (@moonmuse.Reply) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_llm_call_starting(Self, (@moonmuse.Request) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_llm_streaming_completed(Self, (@moonmuse.Reply) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_llm_streaming_frame(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_llm_streaming_starting(Self, (@moonmuse.Request) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_node_execution_completed(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_node_execution_failed(Self, (String, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_node_execution_starting(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_strategy_completed(Self, (String, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_strategy_starting(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_subgraph_execution_completed(Self, (String, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_subgraph_execution_starting(Self, (String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_tool_call_completed(Self, (String, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_tool_call_failed(Self, (String, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_tool_call_starting(Self, (String, @json.Json) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::on_tool_validation_failed(Self, (String, @json.Json, String) -> Unit) -> Self
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub fn EventHandler::report(Self, Event) -> Unit
Hooks over an agent run: observers that watch, and interceptors that rewrite the value in flight. Every registration chains after what was registered before, so several handlers fire and several interceptors compose left to right. The interceptors are the only way to change what is sent, what comes back and what a tool receives, which keeps a run's conversation and a hook's edits in one place. Hooks are synchronous; anything that has to await belongs in middleware, whose hooks are async.
pub(all) enum ExecuteMode {
Which calls an execution node runs.
pub struct FirstChoice {
Take the first candidate.
pub async fn FirstChoice::choose(Self, Array[@moonmuse.Reply]) -> @moonmuse.Reply
pub fn FirstChoice::new() -> Self
Take the first candidate.
pub impl Chooser for FirstChoice
pub(all) enum HistoryPolicy {
Which part of the conversation a compression node folds into a summary.
pub(all) struct Limits {
What a run may spend. `iterations` counts model calls, `tool_calls` counts executions, and `steps` bounds the graph walk itself so a strategy that loops on its own still terminates. The numbers follow the agent frameworks this one is built for: 50 model calls is the cap their default agent uses, and a thousand node visits is the walk limit a compiled graph gets. Raise them for a run that legitimately needs more, lower them in a test.
pub fn Limits::new() -> Self
What a run may spend. `iterations` counts model calls, `tool_calls` counts executions, and `steps` bounds the graph walk itself so a strategy that loops on its own still terminates. The numbers follow the agent frameworks this one is built for: 50 model calls is the cap their default agent uses, and a thousand node visits is the walk limit a compiled graph gets. Raise them for a run that legitimately needs more, lower them in a test.
pub fn Limits::with_iterations(Self, Int32) -> Self
What a run may spend. `iterations` counts model calls, `tool_calls` counts executions, and `steps` bounds the graph walk itself so a strategy that loops on its own still terminates. The numbers follow the agent frameworks this one is built for: 50 model calls is the cap their default agent uses, and a thousand node visits is the walk limit a compiled graph gets. Raise them for a run that legitimately needs more, lower them in a test.
pub fn Limits::with_steps(Self, Int32) -> Self
What a run may spend. `iterations` counts model calls, `tool_calls` counts executions, and `steps` bounds the graph walk itself so a strategy that loops on its own still terminates. The numbers follow the agent frameworks this one is built for: 50 model calls is the cap their default agent uses, and a thousand node visits is the walk limit a compiled graph gets. Raise them for a run that legitimately needs more, lower them in a test.
pub fn Limits::with_tool_calls(Self, Int32) -> Self
What a run may spend. `iterations` counts model calls, `tool_calls` counts executions, and `steps` bounds the graph walk itself so a strategy that loops on its own still terminates. The numbers follow the agent frameworks this one is built for: 50 model calls is the cap their default agent uses, and a thousand node visits is the walk limit a compiled graph gets. Raise them for a run that legitimately needs more, lower them in a test.
pub(all) struct ModelCall {
One model call about to be made.
pub struct ModelChoice {
Ask a model which candidate answers best, and keep that one.
pub async fn ModelChoice::choose(Self, Array[@moonmuse.Reply]) -> @moonmuse.Reply
pub fn ModelChoice::new(&@moonmuse.Provider, String) -> Self
Ask a model which candidate answers best, and keep that one.
pub impl Chooser for ModelChoice
pub(all) enum ModelOutcome {
What a model call came to. `Halted` is a middleware refusing to spend the call, carrying the text the run ends with — the shape a call limit takes.
pub(all) enum NodeKind {
One position in a strategy graph. Four kinds cover the twenty-six node functions the graph DSL of the framework this one is designed after exposes: every request variant is one `Request` mode, every tool-result variant folds into the request that follows it, tool execution is one node, history compression and the exit are one each. The moderation nodes are a middleware here, because what they do — inspect or rewrite messages on the way through — is a pipeline concern.
pub(all) struct Options {
The request settings every call from this agent carries. The provider's own defaults apply to anything left unset, so an empty record means "let the model decide".
pub struct Passthrough {
A middleware that changes nothing, for a caller that wants one hook and no others.
pub async fn Passthrough::after_agent(Self, RunContext, AgentState) -> Array[Update]
pub async fn Passthrough::before_agent(Self, RunContext) -> Array[Update]
pub fn Passthrough::install(Self, Tools) -> Unit
A middleware that changes nothing, for a caller that wants one hook and no others.
pub fn Passthrough::name(Self) -> String
A middleware that changes nothing, for a caller that wants one hook and no others.
pub fn Passthrough::new(String) -> Self
A middleware that changes nothing, for a caller that wants one hook and no others.
pub async fn Passthrough::wrap_model(Self, RunContext, ModelCall, async (ModelCall) -> ModelOutcome) -> ModelOutcome
pub async fn Passthrough::wrap_tool(Self, RunContext, ToolCall, async (ToolCall) -> ToolOutcome) -> ToolOutcome
pub impl Middleware for Passthrough
pub(all) enum RequestMode {
Which way a request node asks the model. This is the whole of the request side: the many request nodes a Kotlin-style DSL spells out separately differ only in what they put in the request — the tools, the choice, the number of candidates, whether the answer is streamed or shaped by a schema.
pub(all) struct RunContext {
What a middleware is handed about the run it is taking part in: the agent's identity, the thread it belongs to, the step it is on, and the state as of this node. The state is a snapshot — a middleware that wants to change it returns updates, so every change goes through the graph and lands in the checkpoint like a node's own write.
pub struct Runtime {
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::context(Self, @moonstate.Run, AgentState) -> RunContext
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::has_node(Self, String) -> Bool
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::provider(Self) -> &@moonmuse.Provider
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::request_for(Self, RequestMode, AgentState) -> @moonmuse.Request
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::tool(Self, String) -> ToolSpec?
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub fn Runtime::tool_specs(Self) -> Array[@moonmuse.Tool]
The request this node sends: the conversation so far, the tools the mode allows, and the agent's options.
pub(all) struct Strategy {
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub fn Strategy::compile(Self, Runtime, saver? : &@moonstate.Saver, store? : &@moonstate.Store, executor? : &@moonstate.Executor) -> @moonstate.Graph[AgentState, Update] raise @moonstate.Refused
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub fn Strategy::edge(Self, String, String) -> Self
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub fn Strategy::new(String, limit? : Int32) -> Self
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub fn Strategy::node(Self, String, NodeKind) -> Self
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub fn Strategy::node_names(Self) -> Array[String]
A strategy as data: named positions, what each one does, and the edges between them. Keeping it data means a strategy can be inspected, compared and documented without a provider in hand, and compiled against whichever runtime an agent was built with. A node that decides where to go next does so by returning a `Goto`, so edges only describe the fixed part of the flow.
pub(all) struct Structured {
Ask the model for an object that matches `schema`, in a call that advertises a single tool of that shape. The model's answer is the tool call's arguments, which is how a provider without a `response_format` field can still be held to a schema.
pub fn Structured::new(String, @json.Json) -> Self
Ask the model for an object that matches `schema`, in a call that advertises a single tool of that shape. The model's answer is the tool call's arguments, which is how a provider without a `response_format` field can still be held to a schema.
pub(all) struct ToolCall {
One tool call about to be made.
pub(all) enum ToolOutcome {
What a tool call came to. `Failed` records the reason as an error result, which is what the model reads and what a retry policy looks at.
pub(all) struct ToolSpec {
A tool the model may call and the function behind it. The descriptor is what the model sees; the function is handed the arguments object and the run it belongs to, and returns the text the model reads back. The run context is what makes a stateful tool possible — a todo list remembers itself, a retrieval tool can see what the run already looked at — without a second tool interface.
pub fn ToolSpec::new(name~ : String, description~ : String, run~ : async (@json.Json, RunContext) -> String, schema? : @json.Json) -> Self
A tool the model may call and the function behind it. The descriptor is what the model sees; the function is handed the arguments object and the run it belongs to, and returns the text the model reads back. The run context is what makes a stateful tool possible — a todo list remembers itself, a retrieval tool can see what the run already looked at — without a second tool interface.
pub fn ToolSpec::of(@moonmuse.Tool, async (@json.Json, RunContext) -> String) -> Self
A tool the model may call and the function behind it. The descriptor is what the model sees; the function is handed the arguments object and the run it belongs to, and returns the text the model reads back. The run context is what makes a stateful tool possible — a todo list remembers itself, a retrieval tool can see what the run already looked at — without a second tool interface.
pub struct Tools {
The tools being collected for an agent: what the config brings, and what each middleware adds when the agent is built.
pub fn Tools::add(Self, ToolSpec) -> Unit
The tools being collected for an agent: what the config brings, and what each middleware adds when the agent is built.
pub fn Tools::new() -> Self
The tools being collected for an agent: what the config brings, and what each middleware adds when the agent is built.
pub fn Tools::register(Self, name~ : String, description~ : String, run~ : async (@json.Json, RunContext) -> String, schema? : @json.Json) -> Unit
The tools being collected for an agent: what the config brings, and what each middleware adds when the agent is built.
pub fn Tools::specs(Self) -> Array[ToolSpec]
The tools being collected for an agent: what the config brings, and what each middleware adds when the agent is built.
pub(all) enum Update {
One change a node makes to the state. A node returns these as `Step::Write`, and the graph applies them in order through [`merge`]; they are also what a checkpoint's pending writes replay.
pub fn Update::from_json(@json.Json, @json.JsonPath) -> Self raise @json.JsonDecodeError
One change a node makes to the state. A node returns these as `Step::Write`, and the graph applies them in order through [`merge`]; they are also what a checkpoint's pending writes replay.
pub fn Update::to_json(Self) -> @json.Json
One change a node makes to the state. A node returns these as `Step::Write`, and the graph applies them in order through [`merge`]; they are also what a checkpoint's pending writes replay.
pub impl @json.FromJson for Update
pub impl @json.ToJson for Update
Type aliases
pub type Listener = (Event) -> Unit
The subscriber a run reports to. Every run has one; the default drops what it is told.
pub type NodeFn = async (Runtime, AgentState, @moonstate.Run) -> Array[@moonstate.Step[AgentState, Update]]
A node body: what a custom position in a strategy does.
Traits
pub(open) trait Chooser {
Picks one reply out of several candidates for the same request. Asking more than once and choosing is how a run buys diversity without asking the provider for `n` completions it may not support: every candidate is a normal call, so middleware, limits and retries apply to each of them.
pub(open) trait Middleware {
A hook into a run, between the graph and the provider. Four places to act: before the run starts, around each model call, around each tool call, and after the run ends. The around-hooks take the next step as a function, so a middleware can retry it, replace it, or skip it — and the pipeline nesting is the composition order, first registered outermost. A middleware may also install tools, which is how a feature that is best expressed as something the model calls (a todo list, a shell, a file search) joins a run.
#Middleware moonbitstack/moonkoog/middleware
The built-in pipeline. Each one wraps the model call, the tool call, or both.
Values
pub let cleared : String
What stands in for a cleared tool result.
pub fn format_todos(Array[@json.Json]) -> String
The list as the model reads it back: one line per item, with its status.
pub let os_shell : Array[String]
No process and no file system on this target: the tools that need one say so instead of pretending to run. The functions stay asynchronous so their callers are written once, and the yield keeps the signature honest rather than nominal.
pub let read_tool : String
pub let search_tool : String
The tools the middleware installs.
pub let shell_tool : String
The tool the middleware installs.
pub let todo_key : String
The storage key the list lives under.
pub let todo_note : String
What the model is told about the list, once, at the start of the run.
pub let todo_tool : String
The tool the middleware installs.
pub fn todos(@agent.AgentState) -> Array[@json.Json]
The list a run recorded, when it has one.
pub fn tool_count(@agent.AgentState, String) -> Int32
How many times a tool has run in this thread so far. The tool node records it after each round, which is why the count survives a checkpoint.
Types and methods
pub struct ContextEditing {
Trim a conversation without asking the model to summarise it. Cheap and lossless in structure: nothing is invented, so nothing can be wrong. It is the right policy when the older turns are scaffolding — tool results the model has already used — rather than decisions worth keeping.
pub async fn ContextEditing::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ContextEditing::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ContextEditing::install(Self, @agent.Tools) -> Unit
Trim a conversation without asking the model to summarise it. Cheap and lossless in structure: nothing is invented, so nothing can be wrong. It is the right policy when the older turns are scaffolding — tool results the model has already used — rather than decisions worth keeping.
pub fn ContextEditing::name(Self) -> String
Trim a conversation without asking the model to summarise it. Cheap and lossless in structure: nothing is invented, so nothing can be wrong. It is the right policy when the older turns are scaffolding — tool results the model has already used — rather than decisions worth keeping.
pub fn ContextEditing::new(EditingStrategy) -> Self
Trim a conversation without asking the model to summarise it. Cheap and lossless in structure: nothing is invented, so nothing can be wrong. It is the right policy when the older turns are scaffolding — tool results the model has already used — rather than decisions worth keeping.
pub async fn ContextEditing::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ContextEditing::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ContextEditing
pub(all) enum EditingStrategy {
How a conversation is trimmed when it is too long.
pub(all) struct Fallback {
One alternative to fall back to: another provider, another model, or both.
pub fn Fallback::new(&@moonmuse.Provider, String) -> Self
One alternative to fall back to: another provider, another model, or both.
pub struct FileSearch {
Give the model a way to look around a directory tree. Two tools, both read-only: `search_files` expands a glob under the root, and `read_file` opens one file. The root is the whole of the permission model — a path that leaves it is refused before anything is opened, which is what keeps a prompt-injected instruction from reading the host's files.
pub async fn FileSearch::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn FileSearch::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn FileSearch::install(Self, @agent.Tools) -> Unit
Give the model a way to look around a directory tree. Two tools, both read-only: `search_files` expands a glob under the root, and `read_file` opens one file. The root is the whole of the permission model — a path that leaves it is refused before anything is opened, which is what keeps a prompt-injected instruction from reading the host's files.
pub fn FileSearch::name(Self) -> String
Give the model a way to look around a directory tree. Two tools, both read-only: `search_files` expands a glob under the root, and `read_file` opens one file. The root is the whole of the permission model — a path that leaves it is refused before anything is opened, which is what keeps a prompt-injected instruction from reading the host's files.
pub fn FileSearch::new(String, limit? : Int32, read_limit? : Int32) -> Self
Give the model a way to look around a directory tree. Two tools, both read-only: `search_files` expands a glob under the root, and `read_file` opens one file. The root is the whole of the permission model — a path that leaves it is refused before anything is opened, which is what keeps a prompt-injected instruction from reading the host's files.
pub async fn FileSearch::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn FileSearch::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for FileSearch
pub struct HumanInTheLoop {
Ask the host whether a tool may run, by stopping the run on a question. The run stops at the tool call; the host answers with `true` or `false` when it resumes. An approval is remembered for the rest of the thread, so a tool called five times asks once. A denial comes back to the model as a failed call, which lets it choose another way instead of ending the run.
pub async fn HumanInTheLoop::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn HumanInTheLoop::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn HumanInTheLoop::install(Self, @agent.Tools) -> Unit
Ask the host whether a tool may run, by stopping the run on a question. The run stops at the tool call; the host answers with `true` or `false` when it resumes. An approval is remembered for the rest of the thread, so a tool called five times asks once. A denial comes back to the model as a failed call, which lets it choose another way instead of ending the run.
pub fn HumanInTheLoop::name(Self) -> String
Ask the host whether a tool may run, by stopping the run on a question. The run stops at the tool call; the host answers with `true` or `false` when it resumes. An approval is remembered for the rest of the thread, so a tool called five times asks once. A denial comes back to the model as a failed call, which lets it choose another way instead of ending the run.
pub fn HumanInTheLoop::new(Array[String], reason? : String) -> Self
Ask the host whether a tool may run, by stopping the run on a question. The run stops at the tool call; the host answers with `true` or `false` when it resumes. An approval is remembered for the rest of the thread, so a tool called five times asks once. A denial comes back to the model as a failed call, which lets it choose another way instead of ending the run.
pub async fn HumanInTheLoop::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn HumanInTheLoop::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for HumanInTheLoop
pub struct ModelCallLimit {
Stop a run before it makes more model calls than the budget allows. The cap is checked against what the run has already spent, which the state carries, so a resumed run does not get a fresh budget. Reaching it ends the run with a line of text saying so rather than failing: a caller that wanted an error can look at the answer.
pub async fn ModelCallLimit::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ModelCallLimit::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ModelCallLimit::install(Self, @agent.Tools) -> Unit
Stop a run before it makes more model calls than the budget allows. The cap is checked against what the run has already spent, which the state carries, so a resumed run does not get a fresh budget. Reaching it ends the run with a line of text saying so rather than failing: a caller that wanted an error can look at the answer.
pub fn ModelCallLimit::name(Self) -> String
Stop a run before it makes more model calls than the budget allows. The cap is checked against what the run has already spent, which the state carries, so a resumed run does not get a fresh budget. Reaching it ends the run with a line of text saying so rather than failing: a caller that wanted an error can look at the answer.
pub fn ModelCallLimit::new(limit? : Int32) -> Self
Stop a run before it makes more model calls than the budget allows. The cap is checked against what the run has already spent, which the state carries, so a resumed run does not get a fresh budget. Reaching it ends the run with a line of text saying so rather than failing: a caller that wanted an error can look at the answer.
pub async fn ModelCallLimit::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ModelCallLimit::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ModelCallLimit
pub struct ModelFallback {
Try the alternatives in order when the primary model call fails. The order is the point: a smaller local model first, a larger one second, and the primaries' own retry policy already applied inside. Fallbacks call their provider directly — a fallback is a different endpoint, not the same one with different arguments — so the middleware inside them is skipped deliberately.
pub async fn ModelFallback::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ModelFallback::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ModelFallback::install(Self, @agent.Tools) -> Unit
Try the alternatives in order when the primary model call fails. The order is the point: a smaller local model first, a larger one second, and the primaries' own retry policy already applied inside. Fallbacks call their provider directly — a fallback is a different endpoint, not the same one with different arguments — so the middleware inside them is skipped deliberately.
pub fn ModelFallback::name(Self) -> String
Try the alternatives in order when the primary model call fails. The order is the point: a smaller local model first, a larger one second, and the primaries' own retry policy already applied inside. Fallbacks call their provider directly — a fallback is a different endpoint, not the same one with different arguments — so the middleware inside them is skipped deliberately.
pub fn ModelFallback::new(Array[Fallback]) -> Self
Try the alternatives in order when the primary model call fails. The order is the point: a smaller local model first, a larger one second, and the primaries' own retry policy already applied inside. Fallbacks call their provider directly — a fallback is a different endpoint, not the same one with different arguments — so the middleware inside them is skipped deliberately.
pub async fn ModelFallback::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ModelFallback::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ModelFallback
pub struct ModelRetry {
Retry a model call that failed in a way the provider itself calls retryable: a rate limit, a gateway error, a timeout. A rejected request is not retried, because the same request would be rejected again.
pub async fn ModelRetry::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ModelRetry::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ModelRetry::install(Self, @agent.Tools) -> Unit
Retry a model call that failed in a way the provider itself calls retryable: a rate limit, a gateway error, a timeout. A rejected request is not retried, because the same request would be rejected again.
pub fn ModelRetry::name(Self) -> String
Retry a model call that failed in a way the provider itself calls retryable: a rate limit, a gateway error, a timeout. A rejected request is not retried, because the same request would be rejected again.
pub fn ModelRetry::new(attempts? : Int32, base_ms? : Int32, factor? : Double, cap_ms? : Int32) -> Self
Retry a model call that failed in a way the provider itself calls retryable: a rate limit, a gateway error, a timeout. A rejected request is not retried, because the same request would be rejected again.
pub async fn ModelRetry::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ModelRetry::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ModelRetry
pub struct Pii {
Scrub personal data out of what the model is about to read. The rules run over the request as it is being sent, so the conversation the run keeps is untouched: a later step still has the real value if the host put it there, while the provider never sees it. Rules are regular expressions, which is what makes them auditable — the policy is data a reviewer can read.
pub async fn Pii::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn Pii::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn Pii::install(Self, @agent.Tools) -> Unit
Scrub personal data out of what the model is about to read. The rules run over the request as it is being sent, so the conversation the run keeps is untouched: a later step still has the real value if the host put it there, while the provider never sees it. Rules are regular expressions, which is what makes them auditable — the policy is data a reviewer can read.
pub fn Pii::name(Self) -> String
Scrub personal data out of what the model is about to read. The rules run over the request as it is being sent, so the conversation the run keeps is untouched: a later step still has the real value if the host put it there, while the provider never sees it. Rules are regular expressions, which is what makes them auditable — the policy is data a reviewer can read.
pub fn Pii::new(Array[PiiRule], action? : PiiAction) -> Self
Scrub personal data out of what the model is about to read. The rules run over the request as it is being sent, so the conversation the run keeps is untouched: a later step still has the real value if the host put it there, while the provider never sees it. Rules are regular expressions, which is what makes them auditable — the policy is data a reviewer can read.
pub fn Pii::standard() -> Self
Scrub personal data out of what the model is about to read. The rules run over the request as it is being sent, so the conversation the run keeps is untouched: a later step still has the real value if the host put it there, while the provider never sees it. Rules are regular expressions, which is what makes them auditable — the policy is data a reviewer can read.
pub async fn Pii::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn Pii::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for Pii
pub(all) enum PiiAction {
What to do with a value a policy recognises as personal data.
pub(all) struct PiiRule {
One recogniser: a regular expression and the label that stands in for what it matches.
pub fn PiiRule::new(String, String) -> Self
One recogniser: a regular expression and the label that stands in for what it matches.
pub fn PiiRule::standard() -> Array[Self]
One recogniser: a regular expression and the label that stands in for what it matches.
pub struct ShellTool {
Give the model a shell. A shell is the broadest capability a run can have, so the tool is explicit about where it runs: the middleware carries the working directory it is allowed in, the shell it hands the line to, and the wall-clock limit after which the process is stopped. Output is cut so one command cannot flood the conversation.
pub async fn ShellTool::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ShellTool::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ShellTool::install(Self, @agent.Tools) -> Unit
Give the model a shell. A shell is the broadest capability a run can have, so the tool is explicit about where it runs: the middleware carries the working directory it is allowed in, the shell it hands the line to, and the wall-clock limit after which the process is stopped. Output is cut so one command cannot flood the conversation.
pub fn ShellTool::name(Self) -> String
Give the model a shell. A shell is the broadest capability a run can have, so the tool is explicit about where it runs: the middleware carries the working directory it is allowed in, the shell it hands the line to, and the wall-clock limit after which the process is stopped. Output is cut so one command cannot flood the conversation.
pub fn ShellTool::new(prefix? : Array[String], cwd? : String, timeout_ms? : Int32) -> Self
Give the model a shell. A shell is the broadest capability a run can have, so the tool is explicit about where it runs: the middleware carries the working directory it is allowed in, the shell it hands the line to, and the wall-clock limit after which the process is stopped. Output is cut so one command cannot flood the conversation.
pub async fn ShellTool::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ShellTool::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ShellTool
pub struct Summarization {
Fold a conversation that has grown past a limit into a summary before sending it. The budget is counted in messages rather than tokens: a message count is exact on every provider, needs no tokenizer, and is what a caller can reason about. The newest messages are kept word for word, because that is what the next step depends on.
pub async fn Summarization::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn Summarization::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn Summarization::install(Self, @agent.Tools) -> Unit
Fold a conversation that has grown past a limit into a summary before sending it. The budget is counted in messages rather than tokens: a message count is exact on every provider, needs no tokenizer, and is what a caller can reason about. The newest messages are kept word for word, because that is what the next step depends on.
pub fn Summarization::name(Self) -> String
Fold a conversation that has grown past a limit into a summary before sending it. The budget is counted in messages rather than tokens: a message count is exact on every provider, needs no tokenizer, and is what a caller can reason about. The newest messages are kept word for word, because that is what the next step depends on.
pub fn Summarization::new(max_messages? : Int32, keep? : Int32) -> Self
Fold a conversation that has grown past a limit into a summary before sending it. The budget is counted in messages rather than tokens: a message count is exact on every provider, needs no tokenizer, and is what a caller can reason about. The newest messages are kept word for word, because that is what the next step depends on.
pub async fn Summarization::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn Summarization::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for Summarization
pub struct TodoList {
Give the model a todo list it can write to. A long task goes better when the model states its plan and updates it: the list is in the conversation, so the next step sees it, and in the state, so a resumed run sees it too. The middleware contributes both the tool and the note that tells the model to use it.
pub async fn TodoList::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn TodoList::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn TodoList::install(Self, @agent.Tools) -> Unit
Give the model a todo list it can write to. A long task goes better when the model states its plan and updates it: the list is in the conversation, so the next step sees it, and in the state, so a resumed run sees it too. The middleware contributes both the tool and the note that tells the model to use it.
pub fn TodoList::name(Self) -> String
Give the model a todo list it can write to. A long task goes better when the model states its plan and updates it: the list is in the conversation, so the next step sees it, and in the state, so a resumed run sees it too. The middleware contributes both the tool and the note that tells the model to use it.
pub fn TodoList::new() -> Self
Give the model a todo list it can write to. A long task goes better when the model states its plan and updates it: the list is in the conversation, so the next step sees it, and in the state, so a resumed run sees it too. The middleware contributes both the tool and the note that tells the model to use it.
pub async fn TodoList::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn TodoList::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for TodoList
pub struct ToolCallLimit {
Stop a run from executing more tool calls than the budget allows, in total or for one tool. A refused call comes back to the model as a failure rather than ending the run: the model can then answer with what it has, which is usually better than ending mid-task.
pub async fn ToolCallLimit::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ToolCallLimit::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ToolCallLimit::install(Self, @agent.Tools) -> Unit
Stop a run from executing more tool calls than the budget allows, in total or for one tool. A refused call comes back to the model as a failure rather than ending the run: the model can then answer with what it has, which is usually better than ending mid-task.
pub fn ToolCallLimit::name(Self) -> String
Stop a run from executing more tool calls than the budget allows, in total or for one tool. A refused call comes back to the model as a failure rather than ending the run: the model can then answer with what it has, which is usually better than ending mid-task.
pub fn ToolCallLimit::new(limit? : Int32, tool? : String) -> Self
Stop a run from executing more tool calls than the budget allows, in total or for one tool. A refused call comes back to the model as a failure rather than ending the run: the model can then answer with what it has, which is usually better than ending mid-task.
pub async fn ToolCallLimit::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ToolCallLimit::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ToolCallLimit
pub struct ToolRetry {
Retry a tool call that failed. Whether a failure is worth another attempt is the tool's business — a network read is, a rejected argument is not — so the policy looks at the reason the tool gave and retries everything unless told otherwise.
pub async fn ToolRetry::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ToolRetry::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ToolRetry::install(Self, @agent.Tools) -> Unit
Retry a tool call that failed. Whether a failure is worth another attempt is the tool's business — a network read is, a rejected argument is not — so the policy looks at the reason the tool gave and retries everything unless told otherwise.
pub fn ToolRetry::name(Self) -> String
Retry a tool call that failed. Whether a failure is worth another attempt is the tool's business — a network read is, a rejected argument is not — so the policy looks at the reason the tool gave and retries everything unless told otherwise.
pub fn ToolRetry::new(attempts? : Int32, base_ms? : Int32, factor? : Double, cap_ms? : Int32) -> Self
Retry a tool call that failed. Whether a failure is worth another attempt is the tool's business — a network read is, a rejected argument is not — so the policy looks at the reason the tool gave and retries everything unless told otherwise.
pub async fn ToolRetry::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ToolRetry::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ToolRetry
pub struct ToolSelection {
Pick the tools worth advertising for the next call. A large toolbox costs tokens on every request and confuses a small model. This middleware asks the model, once per call, which of the named tools it needs for what the user just asked, and advertises only those — always keeping the ones a policy pins.
pub async fn ToolSelection::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn ToolSelection::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn ToolSelection::install(Self, @agent.Tools) -> Unit
Pick the tools worth advertising for the next call. A large toolbox costs tokens on every request and confuses a small model. This middleware asks the model, once per call, which of the named tools it needs for what the user just asked, and advertises only those — always keeping the ones a policy pins.
pub fn ToolSelection::name(Self) -> String
Pick the tools worth advertising for the next call. A large toolbox costs tokens on every request and confuses a small model. This middleware asks the model, once per call, which of the named tools it needs for what the user just asked, and advertises only those — always keeping the ones a policy pins.
pub fn ToolSelection::new(max_tools? : Int32, always? : Array[String]) -> Self
Pick the tools worth advertising for the next call. A large toolbox costs tokens on every request and confuses a small model. This middleware asks the model, once per call, which of the named tools it needs for what the user just asked, and advertises only those — always keeping the ones a policy pins.
pub async fn ToolSelection::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn ToolSelection::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for ToolSelection
#Planning moonbitstack/moonkoog/plan
Goal-oriented search over world states, and the plan-and-execute strategy.
Values
pub fn advance(@agent.Runtime, @agent.AgentState, @moonstate.Run, replan~ : Bool) -> Array[@moonstate.Step[@agent.AgentState, @agent.Update]]
The advance node: mark the step done, and plan again when it failed.
pub let advance_node : String
The node that records a step as done, and decides whether to plan again.
pub fn done(@agent.AgentState) -> Int32
How many steps the state has finished.
pub let index_key : String
How many steps are done.
pub fn parse_steps(String, Int32) -> Array[String]
Read a list of steps out of a model reply: the JSON array when there is one, otherwise the lines that look like steps. A model that answers with a numbered list instead of JSON is common enough that refusing it would make the feature unusable.
pub fn plan_and_execute(@agent.AgentConfig, limit? : Int32, replan? : Bool) -> @agent.AgentConfig
Turn the config into a plan-and-execute agent: a planner writes the steps, the model works through them with its tools, and a failed step sends the run back to the planner. The loop lives in the graph, so a run that stops — for approval, for a checkpoint, for a cap — resumes at the step it was on with the plan it had.
pub let plan_key : String
The steps a run is working through, in order.
pub async fn planner(@agent.Runtime, @agent.AgentState, @moonstate.Run, limit~ : Int32) -> Array[@moonstate.Step[@agent.AgentState, @agent.Update]]
pub let planner_node : String
The names of the nodes a plan-and-execute run adds to a graph.
pub fn planning_prompt(String, Int32) -> String
The prompt that turns a task into steps.
pub fn[S : Eq + Hash] search(Array[GoapAction[S]], S, GoapGoal[S]) -> Array[String]?
pub fn step(@agent.Runtime, @agent.AgentState, @moonstate.Run) -> Array[@moonstate.Step[@agent.AgentState, @agent.Update]]
The step node: put the next step in front of the model, or finish when the plan is done.
pub let step_node : String
The node that hands the next step to the model.
pub fn steps(@agent.AgentState) -> Array[String]
The plan a state holds.
Types and methods
pub(all) struct GoapAction[S] {
One action of a goal-oriented plan: when it applies, what it changes, and what it costs. A GOAP plan is searched over world states, so an action has to be a pure function of the state it runs in — that is what lets the search try it without side effects.
pub fn[S] GoapAction::new(name~ : String, applies~ : (S) -> Bool, effect~ : (S) -> S, cost? : (S) -> Double) -> Self[S]
pub(all) struct GoapGoal[S] {
What a plan is for: a test for "done", and an estimate of how far away that is.
pub fn[S] GoapGoal::new(reached~ : (S) -> Bool, estimate? : (S) -> Double) -> Self[S]
#Teams moonbitstack/moonkoog/multi
Agents as nodes of one graph: handovers, a swarm that follows them, and a supervisor that chooses.
Values
pub fn handoff_tool(Array[String]) -> @agent.ToolSpec
A tool that hands the conversation to another peer of the team. The tool records the destination in the run's state rather than jumping: the peer's own graph has no node for an agent outside it, so it ends its turn and the team's router reads the marker. That is what makes a handover work across a graph boundary, and it is why a peer does not need to know how the team is wired.
pub let handoff_tool_name : String
The tool a peer calls to pass the conversation to another peer.
pub let route_node : String
The node a team's router lives on.
pub fn supervisor(@agent.AgentConfig, Array[@agent.Agent], instruction? : String, max_turns? : Int32) -> @agent.AgentConfig
A team with a lead that decides which peer acts next. The router asks the model — the agent's own model, with the conversation in hand — which peer should act, and stops when it answers `FINISH`. A supervisor costs one model call per turn and buys a plan nobody has to write; a swarm costs nothing and only goes where the members send it.
pub fn swarm(@agent.AgentConfig, Array[@agent.Agent]) -> @agent.AgentConfig
A team whose members hand the conversation to each other through the handoff tool. Each peer runs as a nested graph over the same conversation, so a peer sees what the ones before it said. The run starts with the first peer and ends when a peer answers without handing over. Nothing decides the order but the members themselves, which is what makes a swarm different from a supervisor.
#Observability moonbitstack/moonkoog/otel
A run as GenAI spans.
Values
pub fn agent_span_name(String) -> String
The span name for an agent run. The GenAI conventions put the operation first and the subject after it.
pub fn tool_span_name(String) -> String
The span name for a tool call.
Types and methods
pub struct Otel {
Translate an agent's run into OpenTelemetry spans. Two signals are all a GenAI trace needs: an `invoke_agent` span around the run, with the agent's name and the tokens it spent, and an `execute_tool` span around each tool call. Both take their attribute names from the semantic conventions, so a collector that understands GenAI — Langfuse, Phoenix, Grafana — reads the trace without a mapping table. The library never reads a clock of its own: `now` supplies the nanosecond timestamps, so a replay can be traced on a timeline the caller chose.
pub fn Otel::install(Self, @agent.EventHandler) -> @agent.EventHandler
Translate an agent's run into OpenTelemetry spans. Two signals are all a GenAI trace needs: an `invoke_agent` span around the run, with the agent's name and the tokens it spent, and an `execute_tool` span around each tool call. Both take their attribute names from the semantic conventions, so a collector that understands GenAI — Langfuse, Phoenix, Grafana — reads the trace without a mapping table. The library never reads a clock of its own: `now` supplies the nanosecond timestamps, so a replay can be traced on a timeline the caller chose.
pub fn Otel::new(tracer~ : @trace.Tracer, now~ : () -> Int64) -> Self
Translate an agent's run into OpenTelemetry spans. Two signals are all a GenAI trace needs: an `invoke_agent` span around the run, with the agent's name and the tokens it spent, and an `execute_tool` span around each tool call. Both take their attribute names from the semantic conventions, so a collector that understands GenAI — Langfuse, Phoenix, Grafana — reads the trace without a mapping table. The library never reads a clock of its own: `now` supplies the nanosecond timestamps, so a replay can be traced on a timeline the caller chose.
#Tools moonbitstack/moonkoog/tools
The tools this module ships.
Values
pub fn all() -> Array[@agent.ToolSpec]
The tools this package ships.
pub fn calculator() -> @agent.ToolSpec
A tool that does arithmetic on two numbers. Models are unreliable at arithmetic and good at deciding that arithmetic is needed, which is exactly the division of labour a tool exists for. Division by zero is refused rather than answered with infinity: a wrong number that looks like a number is worse than an error.
#MCP moonbitstack/moonkoog/mcp
An agent as an MCP server, and another server's tools as this agent's tools.
Values
pub let chat_tool : String
The tool a served agent answers on.
pub fn serve(@agent.Agent, name? : String, version? : String) -> @server.Server raise @exceptions.FastMCPError
Expose an agent as an MCP server: one tool, `chat`, that takes a message and returns the agent's answer. A server is the right shape for an agent other programs drive — an editor, a desktop app, an orchestrator that speaks MCP already — because it needs no HTTP surface of its own and can run over stdio.
pub fn text_of(@types.CallToolResult) -> String
The text of a tool result: every text block, in order. A result with no text — an image, say — is reported as such rather than silently becoming an empty string.
pub async fn tools(@client.Client, prefix? : String) -> Array[@agent.ToolSpec]
#A2A moonbitstack/moonkoog/a2a
An agent behind A2A, and a remote agent as a tool.
Values
pub fn executor(@agent.Agent) -> @moona2a.CallableExecutor
An agent's answer to one A2A message. The executor is the whole bridge: a request arrives as a message, the agent runs on its text, and the answer goes back as a reply part. Everything else — discovery, task storage, push notifications — belongs to the protocol's own server, which this adapter does not duplicate.
pub fn remote_tool(&@moona2a.Transport, name~ : String, description~ : String) -> @agent.ToolSpec
A remote agent as a tool: the model calls another agent the way it calls any tool. This is the direction that makes a fleet of agents useful — one agent delegates to another over the network — and it costs a single tool rather than a second orchestration layer.
#ACP moonbitstack/moonkoog/acp
An agent behind ACP.
Values
pub fn message_update(String) -> @moonacp.SessionUpdate
One agent message as a session update.
pub fn prompt_text(@moonacp.Prompt) -> String
The text of a prompt: every text block, in order.
pub fn updates(@agent.Event) -> Array[@moonacp.SessionUpdate]
A session update for each agent event worth reporting: the tool a run starts, the tool it finishes, and the answer it settles on. The translation is the whole of the ACP bridge on the streaming side: the protocol sends `session/update` notifications, the agent already reports events, so an adapter is a mapping and not a second event system.
Types and methods
pub struct Acp {
An agent exported over ACP. The protocol part is small: one initialize, one session per conversation, one prompt per turn. The interest is in the translation — the run's events become `session/update` notifications, and the protocol's own client renders them. A session update is sent once the turn has settled rather than as it happens, because this runtime's hooks are synchronous while the protocol's writes are not; the order of the notifications is the order the run produced them.
pub async fn Acp::authenticate(Self, @moonacp.Authenticate) -> Unit raise @moonacp.Refused
pub async fn Acp::cancel(Self, String) -> Unit
pub async fn Acp::close_session(Self, @moonacp.CloseSession) -> Unit raise @moonacp.Refused
pub async fn Acp::delete_session(Self, @moonacp.DeleteSession) -> Unit raise @moonacp.Refused
pub async fn Acp::initialize(Self, @moonacp.Initialize) -> @moonacp.Initialized raise @moonacp.Refused
pub async fn Acp::list_sessions(Self, @moonacp.ListSessions) -> @moonacp.SessionList raise @moonacp.Refused
pub async fn Acp::load_session(Self, @moonacp.LoadSession, @moonacp.Session) -> @moonacp.SessionStarted raise @moonacp.Refused
pub async fn Acp::logout(Self) -> Unit raise @moonacp.Refused
pub fn Acp::new(@agent.Agent) -> Self
An agent exported over ACP. The protocol part is small: one initialize, one session per conversation, one prompt per turn. The interest is in the translation — the run's events become `session/update` notifications, and the protocol's own client renders them. A session update is sent once the turn has settled rather than as it happens, because this runtime's hooks are synchronous while the protocol's writes are not; the order of the notifications is the order the run produced them.
pub async fn Acp::new_session(Self, @moonacp.NewSession) -> @moonacp.SessionStarted raise @moonacp.Refused
pub async fn Acp::prompt(Self, @moonacp.Prompt, @moonacp.Session) -> @moonacp.StopReason raise @moonacp.Refused
pub async fn Acp::resume_session(Self, @moonacp.ResumeSession, @moonacp.Session) -> @moonacp.SessionStarted raise @moonacp.Refused
pub async fn Acp::set_config_option(Self, @moonacp.SetConfigOption) -> Array[@moonacp.ConfigOption] raise @moonacp.Refused
pub async fn Acp::set_mode(Self, @moonacp.SetMode) -> Unit raise @moonacp.Refused
pub impl @moonacp.Agent for Acp
#Retrieval moonbitstack/moonkoog/rag
Retrieval as a tool, and retrieval as middleware.
Values
pub fn passage(Int32, @moonrag.Scored) -> String
How a retrieved passage is written into the conversation.
pub fn passages(Array[@moonrag.Scored]) -> String
The passages from `hits`, numbered, for a prompt or a tool result.
pub fn retrieval_tool(&@moonrag.Retriever, limit? : Int32, name? : String) -> @agent.ToolSpec
Retrieval as a tool: the model decides when to look, and reads what came back. The alternative — retrieving before every call — buys recall at the cost of tokens and can drown a question that did not need a document. Handing retrieval to the model keeps the decision where the question is.
pub let search_tool : String
The tool a retrieval provider exposes to the model.
Types and methods
pub struct Rag {
Retrieval as middleware: look up what the user just asked, and put the passages in front of the model. One retrieval per model call, on the last user message. That is the shape a knowledge assistant wants — the answer is grounded whether or not the model thought to search — and it is why the two forms both exist rather than one replacing the other.
pub async fn Rag::after_agent(Self, @agent.RunContext, @agent.AgentState) -> Array[@agent.Update]
pub async fn Rag::before_agent(Self, @agent.RunContext) -> Array[@agent.Update]
pub fn Rag::install(Self, @agent.Tools) -> Unit
Retrieval as middleware: look up what the user just asked, and put the passages in front of the model. One retrieval per model call, on the last user message. That is the shape a knowledge assistant wants — the answer is grounded whether or not the model thought to search — and it is why the two forms both exist rather than one replacing the other.
pub fn Rag::name(Self) -> String
Retrieval as middleware: look up what the user just asked, and put the passages in front of the model. One retrieval per model call, on the last user message. That is the shape a knowledge assistant wants — the answer is grounded whether or not the model thought to search — and it is why the two forms both exist rather than one replacing the other.
pub fn Rag::new(&@moonrag.Retriever, limit? : Int32, label? : String) -> Self
Retrieval as middleware: look up what the user just asked, and put the passages in front of the model. One retrieval per model call, on the last user message. That is the shape a knowledge assistant wants — the answer is grounded whether or not the model thought to search — and it is why the two forms both exist rather than one replacing the other.
pub async fn Rag::wrap_model(Self, @agent.RunContext, @agent.ModelCall, async (@agent.ModelCall) -> @agent.ModelOutcome) -> @agent.ModelOutcome
pub async fn Rag::wrap_tool(Self, @agent.RunContext, @agent.ToolCall, async (@agent.ToolCall) -> @agent.ToolOutcome) -> @agent.ToolOutcome
pub impl @agent.Middleware for Rag
#Skills moonbitstack/moonkoog/skills
Progressive loading of skill documents.
Values
pub fn catalog(Array[@moonskill.Skill]) -> String
The listing an agent carries: one line per skill, name then description, which is what the model needs to decide whether a skill is worth loading.
pub fn enable(@agent.AgentConfig, Array[@moonskill.Skill]) -> @agent.AgentConfig
Turn the config into a skill-enabled agent: the listing goes in the instructions, the loading tool goes in the toolbox.
pub let load_tool : String
The tool a skill-enabled agent uses to read a skill's body.
pub fn load_tool_spec(Array[@moonskill.Skill]) -> @agent.ToolSpec
The tool that reads one skill's body. Progressive loading is the whole point: the listing costs a line per skill, the body costs what it costs, and only the skills the run actually reaches are paid for.
#Agent Protocol moonbitstack/moonkoog/serve
The Agent Protocol's threads and runs over moonapi.
Values
pub fn app(Server) -> @moonapi.App
The routes an Agent Protocol client expects: create a thread, read it, run on it, read the run. The handlers are the protocol; serving them is `moonapi`'s job, and which server it is — moonapi's own, mooncat, a cloud runtime — is a deployment decision this package does not make.
Types and methods
pub(all) struct Run {
One execution of an agent on a thread.
pub fn Run::to_json(Self) -> @json.Json
One execution of an agent on a thread.
pub struct Server {
The Agent Protocol's two resources: threads and the runs that use them. The store is in memory and per server; a deployment that needs runs to outlive the process passes a saver to the agent instead, because the conversation is checkpointed there and the protocol's records are a view of it.
pub async fn Server::create_run(Self, String, String) -> Run raise @agent.AgentError
pub fn Server::create_thread(Self, @json.Json) -> Thread
The Agent Protocol's two resources: threads and the runs that use them. The store is in memory and per server; a deployment that needs runs to outlive the process passes a saver to the agent instead, because the conversation is checkpointed there and the protocol's records are a view of it.
pub fn Server::new(@agent.Agent) -> Self
The Agent Protocol's two resources: threads and the runs that use them. The store is in memory and per server; a deployment that needs runs to outlive the process passes a saver to the agent instead, because the conversation is checkpointed there and the protocol's records are a view of it.
pub fn Server::run(Self, String) -> Run?
The Agent Protocol's two resources: threads and the runs that use them. The store is in memory and per server; a deployment that needs runs to outlive the process passes a saver to the agent instead, because the conversation is checkpointed there and the protocol's records are a view of it.
pub fn Server::thread(Self, String) -> Thread?
The Agent Protocol's two resources: threads and the runs that use them. The store is in memory and per server; a deployment that needs runs to outlive the process passes a saver to the agent instead, because the conversation is checkpointed there and the protocol's records are a view of it.
pub(all) struct Thread {
A conversation the protocol keeps: an identifier, when it started, and whatever the client wants remembered about it.
pub fn Thread::to_json(Self) -> @json.Json
A conversation the protocol keeps: an identifier, when it started, and whatever the client wants remembered about it.