Documentation
¶
Overview ¶
Package logos provides a reusable stateless agent loop.
Run() executes one agent loop iteration: prompt → LLM → <cmd> blocks → response. The caller provides conversation history, a system prompt, and streaming callbacks. No persistence — the caller receives StepMessages and handles storage.
Library mode: for callers that already have an assistant message in hand and want to run its <cmd> blocks without driving a full agent loop, use ParseCmdBlocks + ExecuteBlocks + FormatResults. NewExecConfig creates an ExecConfig from Config, selecting the appropriate runner (local or sandbox) based on Config.Sandbox.
Plane: shared
Index ¶
- Constants
- func BuildSystemPrompt(data PromptData) (string, error)
- func ContainsBlockedCommand(cmd string) bool
- func ContainsToolCallHallucination(text string) bool
- func FormatResults(results []Result) string
- func ParseCmdBlocks(text string) []string
- func StepsToMessages(steps []StepMessage) []fantasy.Message
- func StripCmdBlocks(text string) string
- type Callbacks
- type CommandDoc
- type Config
- type ExecConfig
- type PromptData
- type Result
- type RunResult
- type StepMessage
- type StepRole
Constants ¶
const CmdBlockClose = "</cmd>"
CmdBlockClose is the closing tag for command blocks: <cmd>...</cmd>.
const CmdBlockOpen = "<cmd>"
CmdBlockOpen is the opening tag for command blocks: <cmd>...</cmd>.
const DefaultMaxSteps = 30
DefaultMaxSteps is the fallback max steps when Config.MaxSteps is 0.
const DefaultMaxTokens = 16384
DefaultMaxTokens is the fallback max output tokens when Config.MaxTokens is 0.
const MaxHallucinationRetries = 3
MaxHallucinationRetries is the maximum number of tool call hallucination retries before Run() returns an error.
Variables ¶
This section is empty.
Functions ¶
func BuildSystemPrompt ¶
func BuildSystemPrompt(data PromptData) (string, error)
BuildSystemPrompt renders the default system prompt with runtime context. The result is the base prompt — consumers append their own instructions after this.
func ContainsBlockedCommand ¶ added in v1.6.0
ContainsBlockedCommand returns true if cmd contains a blocked in-place editing command (sed -i or perl -i).
func ContainsToolCallHallucination ¶ added in v0.8.0
ContainsToolCallHallucination returns true if text contains tool call patterns produced by models that hallucinate structured formats — XML tags (e.g. <tool_call>) or bracket delimiters (e.g. [TOOL_CALL]...[/TOOL_CALL]). Standalone utility — internal detection is handled by streamFilter during streaming.
func FormatResults ¶ added in v1.4.0
FormatResults renders a slice of Results as the single outer <result>...</result> wrap that ExecuteBlocks callers feed back to the model as a user message. Format matches what streamOneTurn produces internally:
<result> <cmd-1-verbatim> <stdout-1> STDERR: ← only if stderr non-empty <stderr-1> (exit code: N) ← only if exit != 0 AND exit != -1 <cmd-2-verbatim> ... </result>
Entries are joined with a single "\n" between them. Empty results slice returns an empty string (no outer wrap).
func ParseCmdBlocks ¶ added in v1.4.0
ParseCmdBlocks extracts the content of each <cmd>...</cmd> block from a complete assistant message. Returns contents in document order with surrounding whitespace trimmed. Nested blocks are not supported — the first </cmd> after a <cmd> closes the block. Unclosed blocks are silently dropped (an unclosed block at the end of the message is ignored with no error — callers who care can detect via strings.Contains themselves).
This is the non-streaming sibling of the internal cmdBlockBuffer used by streamOneTurn. Use this when you have the full text; use cmdBlockBuffer when you have a stream of deltas.
func StepsToMessages ¶ added in v1.7.0
func StepsToMessages(steps []StepMessage) []fantasy.Message
StepsToMessages converts StepMessages back to fantasy.Messages for conversation round-tripping. Assistant steps produce ReasoningPart-first ordering (required by Anthropic). Result steps pass through the pre-formatted <result> envelope as a user message.
Used by fn-agent and lenos to rehydrate a conversation history from persisted StepMessages when resuming an agent session.
func StripCmdBlocks ¶ added in v1.4.0
StripCmdBlocks returns text with all <cmd>...</cmd> blocks (including the tags themselves) removed. Runs of blank lines left behind are collapsed to a single blank line. Unclosed blocks are stripped from their opening tag to the end of the string.
Use this to prepare prose for display when the raw assistant message contains cmd blocks you don't want the human to see (e.g. forwarding to chat without showing the tool calls).
Types ¶
type Callbacks ¶
type Callbacks struct {
// OnDelta is called with each text delta as the LLM streams its response.
OnDelta func(text string)
// OnCommandResult is called after a command executes with the command string,
// raw combined stdout+stderr output (no exit code suffix), and the exit code.
OnCommandResult func(command string, output string, exitCode int)
// OnRetry is called when a tool call hallucination (XML or bracket) is detected
// and an "unprocessed" directive is injected. reason is "tool_call".
OnRetry func(reason string, step int)
}
Callbacks holds optional streaming callbacks for the agent loop. All fields are nil-safe — unset callbacks are simply not called.
type CommandDoc ¶ added in v0.9.0
type CommandDoc struct {
Name string // command name, e.g. "url", "web", "rg"
Summary string // one-line description shown under the heading
Help string // full help text (flags, examples, caveats)
}
CommandDoc describes a command available to the agent. Callers provide these to control which commands appear in the system prompt.
type Config ¶
type Config struct {
Provider fantasy.Provider
Model string
SystemPrompt string
MaxSteps int // 0 means use default (DefaultMaxSteps)
MaxTokens int // 0 means use default (DefaultMaxTokens)
Sandbox bool // true = require temenos sandbox; false = use local exec
SandboxAddr string // temenos socket/address; empty = env fallback chain
SandboxEnv map[string]string // env vars passed to sandbox per-request
// AllowedPaths lists filesystem paths accessible during command execution.
// Path validation (non-empty, absolute) is enforced by the temenos daemon.
// Note: localRunner (Sandbox=false) uses AllowedPaths[0].Path as the working
// directory; additional entries are ignored (no RO enforcement).
AllowedPaths []client.AllowedPath
// contains filtered or unexported fields
}
Config holds everything needed to run one agent loop iteration.
type ExecConfig ¶ added in v1.4.0
type ExecConfig struct {
Env map[string]string
AllowedPaths []client.AllowedPath
TimeoutSec int // maps to RunRequest.Timeout; 0 = daemon default (seconds)
// contains filtered or unexported fields
}
ExecConfig holds the knobs ExecuteBlocks needs to dispatch cmds to a runner. runner is required and set by NewExecConfig. Env, AllowedPaths, TimeoutSec are optional and map directly to temenos client.RunRequest fields.
func NewExecConfig ¶ added in v1.5.0
func NewExecConfig(cfg Config) (ExecConfig, error)
NewExecConfig creates an ExecConfig by resolving the runner from cfg. Uses localRunner if cfg.Sandbox is false; uses temenos client if true. Returns an error only if Sandbox is true but temenos is unreachable.
type PromptData ¶
type PromptData struct {
WorkingDir string
Platform string
Date string
Commands []CommandDoc // caller-provided command documentation
}
PromptData holds the runtime context used to render the default system prompt.
type Result ¶ added in v1.4.0
Result is one command's execution outcome, returned by ExecuteBlocks. Command is the raw bash content that was run (verbatim from the <cmd> block). Stdout/Stderr/ExitCode come from the sandbox runner. Err is non-nil only on runner-level failures (sandbox refusal, daemon unreachable, timeout) — a non-zero exit code from bash is NOT an Err, it's reported via ExitCode. ExitCode == -1 means the runner did not return a normal exit (timeout, sandbox error); Err will be non-nil in that case.
func ExecuteBlocks ¶ added in v1.4.0
func ExecuteBlocks(ctx context.Context, cfg ExecConfig, cmds []string) []Result
ExecuteBlocks runs each cmd concurrently against cfg.runner and returns results in the original order of cmds. Worker pool is capped at 8. Ctx cancellation stops new task submissions; already-submitted tasks run to completion (their Results will contain ctx.Err() on premature exit). Empty cmds returns nil.
ExecuteBlocks panics if cfg.runner is nil.
type RunResult ¶
type RunResult struct {
Response string // final text response (accumulated assistant text)
Steps []StepMessage // all messages generated (for persistence by caller)
}
RunResult contains the agent's output after a loop completes.
type StepMessage ¶
type StepMessage struct {
Role StepRole
Content string
Reasoning string // thinking block text (empty if no reasoning)
ReasoningSignature string // provider signature for round-trip
Timestamp time.Time
}
StepMessage represents one message generated during the agent loop.