LLM Agent framework with hexagonal (ports-and-adapters) architecture. Defines extension ports + Agent loop.
API docs: https://mooncakes.io/docs/colmugx/posoco · 中文 README: README-zh.mbt.mdWARNING: Posoco is experimental (0.x). The public API is subject to change.
moon add colmugx/posoco@0.23.3| Port | Purpose |
|---|---|
| ModelPort | Model chat + context compaction (chat, compact, provider_config) |
| DecisionPort | Provider-neutral structured semantic judgement |
| ToolProvider | Tool discovery and execution |
| LogPort | Structured application logging with caller-selected durability |
| SessionPort | Load / save conversation session |
| Observer | Read-only turn-event observation |
| Hook | Pipeline interception with default methods: rewrite messages or abort before model (before_model), approve / defer / reject before tool (before_tool), read-only after each effect (on_post_event) |
| MemoryPort | Long-term memory storage and retrieval |
| Lifecycle | Async resource cleanup on shutdown |
| CommandPort | User-side slash-command enumeration and dispatch |
| UiPort | Structured UI intents + interaction requests (Status / Notice / Widget / Input / Confirm / Select) |
| SystemPromptContributor | Declare system-prompt sections (assembled and injected before the model call) |
| Extension | Self-report protocol: extension_id + manifest declaring which ports an extension contributes |
| ProviderConfig | Model-side provider config (companion type, not a runtime port) |
// 1. Implement the port trait(s) your extension contributes.
// (ToolProvider shown here; the body is omitted for brevity.)
///|
pub impl @posoco.Extension for ReadTools with fn extension_id(_self) -> String {
"posoco_ext_read"
}
///|
/// 2. Declare which ports ReadTools contributes. The same `self` goes under
/// every slot whose trait ReadTools implements; omitted slots default to [].
pub impl @posoco.Extension for ReadTools with fn manifest(self) -> @posoco.ExtensionManifest {
@posoco.ExtensionManifest::make(id="posoco_ext_read", tools=[self])
}
///|
/// 3. Expose Extension methods for dot-syntax callers and so `&ReadTools`
/// coerces to `&@posoco.Extension` inside `Array[&@posoco.Extension]`.
pub extend ReadTools with @posoco.Extension::{extension_id, manifest}
///|
/// 4. Optional factory for hosts that construct from defaults.
pub fn read_extension() -> ReadTools {
ReadTools::ReadTools()
}let agent = @posoco.Agent(
exts=[
model_ext, // an extension contributing ModelPort
read_ext, // the ReadTools extension built above, contributing ToolProvider
],
config={
max_tool_rounds: Some(10),
temperature: None,
max_output_tokens: None,
model_context_window: None,
},
)
let input : @posoco.Message = @posoco.UserMessage(content=[
@posoco.Content::Text("hello"),
])
let result = agent.run_turn(input, "session_1")| # | Chapter | Status |
|---|---|---|
| 01 | Agent Loop principles: how to write your own | ✅ |
| 02 | Your first agent with Posoco (10 lines) | ✅ |
moon check --output-json
moon test --output-json
moon fmt
moon infoToolCallPending (entered the pipeline, awaiting hook chain)
├─ ToolCallApproved (chain finalized executable; consent audit)
│ └─ ToolCallStarted (wave launched)
│ ├─ ToolCallSucceeded / ToolCallFailed
├─ ToolCallRejected (a decision resolved the call: hook reject,
│ validation reject; run continues)
└─ ToolCallAbandoned (no outcome exists: cancelled mid-wave,
terminal hook failure, run ended)pub struct Agent {
// private fields
}fn Agent::Agent(exts~ : Array[&Extension], config~ : AgentConfig, ui_projection? : Bool) -> Agent raise CompositionErrorasync fn Agent::compact_session(self : Agent, session_id : String) -> CompactOutcome raise AgentErrorasync fn Agent::resume_turn(self : Agent, session_id : String, continuation? : String) -> TurnResult raise AgentErrorasync fn Agent::run_turn(self : Agent, input : Message, session_id : String) -> TurnResult raise AgentErrorfn Agent::with_runtime(exts~ : Array[&Extension], config~ : AgentConfig, runtime~ : &Runtime, ui_projection? : Bool) -> Agent raise CompositionErrorpub struct AgentConfig {
max_tool_rounds : Int?
max_tool_calls : Int?
max_tool_depth : Int?
temperature : Double?
max_output_tokens : Int?
model_context_window : Int?
compact_threshold : Double?
system_prompt : String?
memory_inbound_timeout_ms : Int?
}pub struct AgentControl {
// private fields
}pub(all) struct NoopCommandPort {
}impl CommandPort for NoopCommandPortasync fn invoke(_self : NoopCommandPort, id : String, _args : Json) -> CommandOutcome raise CommandErrorasync fn NoopCommandPort::invoke(_self : NoopCommandPort, id : String, _args : Json) -> CommandOutcome raise CommandErrorlet MEMORY_INBOUND_LEAD : Stringlet SESSION_TITLE_METADATA_KEY : Stringfn agent_config(max_tool_rounds? : Int?, max_tool_calls? : Int?, max_tool_depth? : Int?, temperature? : Double?, max_output_tokens? : Int?, model_context_window? : Int?, compact_threshold? : Double?, system_prompt? : String?, memory_inbound_timeout_ms? : Int?) -> AgentConfigInstall
Download zipLLM Agent framework with hexagonal (ports-and-adapters) architecture. Defines extension ports + Agent loop.