Documentation
¶
Overview ¶
Example ¶
An agent with one tool and a policy, on a session kept in a file.
package main
import (
"context"
"encoding/json"
"fmt"
"log"
"github.com/kirahowe/agentloop"
"github.com/kirahowe/agentloop/anthropic"
)
func main() {
clock := agentloop.Func(agentloop.ToolSpec{
Name: "clock",
Description: "The current time.",
Parameters: json.RawMessage(`{"type":"object","properties":{},"additionalProperties":false}`),
}, func(ctx context.Context, input json.RawMessage) (agentloop.Result, error) {
return agentloop.Result{Content: "09:30"}, nil
})
agent := &agentloop.Agent{
Model: anthropic.New(anthropic.Config{APIKey: "sk-..."}),
ModelID: "claude-opus-5-5",
System: "You answer briefly.",
Tools: []agentloop.Tool{clock},
Policy: agentloop.PolicyFunc(func(ctx context.Context, call agentloop.ToolCall, view agentloop.View) agentloop.Decision {
return agentloop.Decision{Verdict: agentloop.Allow}
}),
Limits: agentloop.Limits{MaxTurns: 20},
}
session, err := agentloop.OpenSession(agentloop.NewFileStore("session.jsonl"))
if err != nil {
log.Fatal(err)
}
outcome, err := agent.Run(context.Background(), session, "What time is it?")
if err != nil {
log.Fatal(err)
}
fmt.Println(outcome.Reason, outcome.Text)
}
Output:
Index ¶
- Constants
- Variables
- func CheckDisplay(d Display) error
- func CheckLabel(l string) error
- func CheckLabels(labels []string) error
- func DisplayID(callID string) string
- func DisplayNote(ref string) string
- func Forbidden(labels, forbid []string) []string
- func UnionLabels(ls ...[]string) []string
- type Agent
- type Call
- type CallInfo
- type CallStartedEntry
- type CallTool
- type Decision
- type DecisionEntry
- type Delta
- type Describer
- type Display
- type Effort
- type Entry
- type EntryType
- type ErrorKind
- type Event
- type FileStore
- type InputChecker
- type InputSchema
- type LabelSource
- type LabelsEntry
- type Limits
- type MemoryStore
- type Message
- type MessageEntry
- type Model
- type ModelError
- type ModelErrorEntry
- type ModelInfo
- type ModelUsage
- type Native
- type Outcome
- type Part
- type PartType
- type PinError
- type PinsEntry
- type Policy
- type PolicyFunc
- type Prices
- type Reason
- type Refusal
- type Request
- type Response
- type Result
- type RetryPolicy
- type Role
- type RunStartedEntry
- type Session
- func (s *Session) AddLabels(labels []string, source string) (*Entry, error)
- func (s *Session) Call(id string) (CallInfo, bool)
- func (s *Session) CheckPins(pins map[string]string) error
- func (s *Session) Entries() []Entry
- func (s *Session) LabelSources() map[string]LabelSource
- func (s *Session) Labels() []string
- func (s *Session) Messages() []Message
- func (s *Session) Pending() []ToolCall
- func (s *Session) Pins() map[string]string
- func (s *Session) Turns() []Turn
- func (s *Session) Usage() Usage
- func (s *Session) View() View
- type Source
- type Stop
- type Store
- type Tool
- type ToolCall
- type ToolResult
- type ToolResultEntry
- type ToolSpec
- type Turn
- type Usage
- type Verdict
- type View
Examples ¶
Constants ¶
const ( LimitTurns = "max_turns" LimitToolCalls = "max_tool_calls" LimitTokens = "max_tokens" )
Names of the limits, as reported in Outcome.Limit.
const ( MaxDisplayTitle = 200 // characters MaxDisplayBody = 200_000 MaxDisplaySources = 50 MaxSourceRef = 2000 )
The bounds on a display.
const ( // LabelSeed: the agent's starting labels. LabelSeed = "seed" // LabelTool: a tool call's decision or result. LabelTool = "tool" )
Where a label can come from, other than a tool call.
const ForbiddenDecision = "This call would give the session a label it may not hold, so it was not run."
ForbiddenDecision is the reason recorded for a call whose decision would have given the session a label it may not hold.
const MaxLabelBytes = 100
MaxLabelBytes is the longest a label may be.
const RefusedResult = "This result was refused: it carries a label this session may not hold."
RefusedResult is what the model is told in place of a tool result that carried a label the session may not hold.
Variables ¶
var DefaultRetry = RetryPolicy{Retries: 3, Backoff: 2 * time.Second, MaxWait: 60 * time.Second}
DefaultRetry is used when an Agent sets no Retry.
Functions ¶
func CheckDisplay ¶
CheckDisplay says what is wrong with a display a tool gave, or returns nil: a title of 1 to MaxDisplayTitle characters, a body of at most MaxDisplayBody bytes, labels that pass CheckLabels, and at most MaxDisplaySources sources, each with a title and a one-line ref.
func CheckLabel ¶
CheckLabel says why l is not a label, or returns nil. Labels are short provenance names such as "private" or "contaminated": 1 to MaxLabelBytes bytes, starting with a lower-case letter or digit and continuing with lower-case letters, digits and the characters _ . : @ / + -. Nothing else is allowed, so case, spacing, invisible, bidi and lookalike variants of a name cannot exist, and a forbid list cannot miss one by a byte.
func CheckLabels ¶
CheckLabels returns the first error CheckLabel gives for labels.
func DisplayID ¶
DisplayID is the name a call's display is kept under: the call id in lower case when that is a short run of letters, digits, _ and -, and otherwise "call-" and the start of the id's sha256. It is a safe path segment either way.
func DisplayNote ¶
DisplayNote is what the model is told in place of a display, after the result's content. It holds nothing of the display, which may carry labels the result does not: only the ref, which the agent made.
func Forbidden ¶
Forbidden is the labels in labels that forbid names, sorted, with no repeats: what a session given labels would hold that it may not. It is empty, never nil, when there are none.
func UnionLabels ¶
UnionLabels is the sorted set of the labels in all of ls.
Types ¶
type Agent ¶
type Agent struct {
Model Model
ModelID string
System string
Tools []Tool
// Labels are added to the session whenever a run starts, before
// anything else happens in it.
Labels []string
// Forbid is the labels the session may never hold. A run on a session
// that holds one, or would from Labels, does not start (ReasonForbidden).
// A tool result carrying one is refused: the model is told only that
// (RefusedResult) and the session does not take the label. An allow
// whose decision would add one is a deny.
Forbid []string
// Policy decides each call after the tool and its input check out. Nil
// allows every call to a tool the agent has.
Policy Policy
Effort Effort
MaxOutputTokens int
Limits Limits
// Retry is how failed model calls are retried. Nil means DefaultRetry.
Retry *RetryPolicy
// ToolTimeout bounds one tool call. Zero means no bound.
ToolTimeout time.Duration
// Pins are digests of tool definitions, by tool name, that the session
// must keep. A run records the ones the session lacks, and a run on a
// session that pinned a different digest for a tool does not start:
// Run returns a *PinError and records nothing. The digests are opaque
// here; the mcp package makes them.
Pins map[string]string
// DisplayRefPrefix, when set, names where a result's display is kept:
// its ref is the prefix and DisplayID of the call, such as
// "shown:2026-10-18/" and "toolu_01abc". The model is told the ref.
DisplayRefPrefix string
// Observe sees every entry as it is appended and every streamed delta.
// It runs on the loop's goroutine; keep it quick.
Observe func(Event)
// Now and Sleep stand in for the clock, so tests can exercise retries
// without waiting. Nil means the real ones. Sleep returns early with
// the context's error if the context ends.
Now func() time.Time
Sleep func(ctx context.Context, d time.Duration) error
}
An Agent is a model, the tools it was given and the rules around them. Its zero value runs nothing: Model is required, and the only tools are the ones in Tools.
func (*Agent) Run ¶
Run carries the session forward until the model is done or something stops it. It first settles the calls an earlier run left open, so it resumes a session from any point. A non-empty prompt is added as a user message once those are settled.
Run returns an error only if the agent is set up wrongly, the store fails, or another Run is already in progress on the session (at most one runs at a time). Anything else is an Outcome.
type Call ¶
type Call struct {
ID string
Input json.RawMessage
// Labels are the session's labels as the call runs, which include
// the labels its decision added.
Labels []string
}
A Call is one call as a CallTool sees it.
type CallInfo ¶
type CallInfo struct {
Call ToolCall
// Decision is the latest decision on the call, nil until it is checked.
Decision *Decision
Started bool
Finished bool
// Result is set once Finished.
Result *ToolResult
}
CallInfo is what the session knows about one tool call.
type CallStartedEntry ¶
type CallStartedEntry struct {
CallID string `json:"call_id"`
}
CallStartedEntry is written immediately before a tool runs. If it is the last word on a call, the call may or may not have taken effect.
type CallTool ¶
A CallTool is a Tool that is told which call it serves and what the session holds. The agent uses CallWith instead of Call.
type Decision ¶
type Decision struct {
Verdict Verdict `json:"verdict"`
// Reason is shown to the model on deny, and recorded always.
Reason string `json:"reason,omitempty"`
// Labels are added to the session when the call is allowed, before
// its result exists.
Labels []string `json:"labels,omitempty"`
}
A Decision is a verdict with the reasons and consequences that go with it.
type DecisionEntry ¶
type DecisionEntry struct {
CallID string `json:"call_id"`
Tool string `json:"tool"`
Verdict Verdict `json:"verdict"`
Reason string `json:"reason,omitempty"`
Labels []string `json:"labels,omitempty"`
}
DecisionEntry records the verdict on one call.
type Describer ¶
A Describer is a Model whose provider can describe a model. It is optional: a Model that does not implement it is described by its id alone.
Describe makes one request, with no retries, and returns a *ModelError for anything the provider refused or could not do.
type Display ¶
type Display struct {
Title string `json:"title"`
Body string `json:"body"`
// Labels are what the display's text carries. The agent adds the
// result's labels and the session's to them, so a display is never
// labelled less than the call that made it.
Labels []string `json:"labels"`
Sources []Source `json:"sources"`
// Ref is where the display is kept, as kind:id, set by the agent
// when it has a DisplayRefPrefix.
Ref string `json:"ref,omitempty"`
}
A Display is what a tool result shows the operator alone: a title, a Markdown body and its sources. The agent keeps it in the tool_result entry and sends it to a client, and never puts any of it in the model's context. The model is told only that the operator was shown something, and under which ref (see DisplayNote).
type Effort ¶
type Effort string
Effort is a provider-neutral reasoning level. An adapter maps it to the nearest level its provider has.
type Entry ¶
type Entry struct {
Seq int `json:"seq"`
Time time.Time `json:"time"`
Type EntryType `json:"type"`
RunStarted *RunStartedEntry `json:"run_started,omitempty"`
Message *MessageEntry `json:"message,omitempty"`
Decision *DecisionEntry `json:"decision,omitempty"`
CallStarted *CallStartedEntry `json:"call_started,omitempty"`
ToolResult *ToolResultEntry `json:"tool_result,omitempty"`
ModelError *ModelErrorEntry `json:"model_error,omitempty"`
RunEnded *Outcome `json:"run_ended,omitempty"`
Labels *LabelsEntry `json:"labels,omitempty"`
Pins *PinsEntry `json:"pins,omitempty"`
}
An Entry is one line of a session's log. Exactly one payload field is set, the one Type names. Entries are never edited or removed.
type EntryType ¶
type EntryType string
EntryType says which payload of an Entry is set.
const ( EntryRunStarted EntryType = "run_started" EntryMessage EntryType = "message" EntryDecision EntryType = "decision" EntryCallStarted EntryType = "call_started" EntryToolResult EntryType = "tool_result" EntryModelError EntryType = "model_error" EntryRunEnded EntryType = "run_ended" EntryLabels EntryType = "labels" EntryPins EntryType = "pins" )
type ErrorKind ¶
type ErrorKind string
ErrorKind sorts what can go wrong with a model call by what to do about it.
const ( // RateLimited: wait until RetryAfter, or ResetsAt for the whole limit. RateLimited ErrorKind = "rate_limited" // Overloaded: the provider failed on its side. Retrying may work. Overloaded ErrorKind = "overloaded" // Unreachable: the request never got an answer. Unreachable ErrorKind = "unreachable" Unauthorized ErrorKind = "unauthorized" // Billing: the account cannot pay. Someone has to act. Billing ErrorKind = "billing" // NotFound: the model or endpoint does not exist. Fix the settings. NotFound ErrorKind = "not_found" // InvalidRequest: the provider rejected the request itself. InvalidRequest ErrorKind = "invalid_request" )
type Event ¶
An Event is one thing a run reports to Observe: either an entry just appended or a streamed delta.
type FileStore ¶
type FileStore struct {
// contains filtered or unexported fields
}
FileStore keeps entries as JSON lines in a file, syncing each append.
func NewFileStore ¶
NewFileStore makes a store on path. The file is created by the first append; its directory must exist.
func (*FileStore) Load ¶
Load reads the file. A final line that is not complete JSON is what a write cut short by a crash leaves, and is ignored. A bad line anywhere else means the log is damaged, and is an error.
The log is agentloop's own, written by encoding/json, so it is read with encoding/json and not the strict reader (relay#58 covers JSON another process wrote). Earlier versions logged tool call inputs and provider data with a repeated name or invalid UTF-8 inside, which the strict reader refuses; such a line is complete, so it must neither stop the session from loading nor be cut off as a torn write.
type InputChecker ¶
type InputChecker interface {
Tool
CheckInput(input json.RawMessage) string
}
An InputChecker is a Tool with a check of its own on input that already matches its schema. The agent runs it before the policy, and a reason it returns denies the call, as a schema mismatch does.
type InputSchema ¶
type InputSchema struct {
// contains filtered or unexported fields
}
An InputSchema is a tool's parameters compiled, to check input as the agent checks a call's input.
func CompileInput ¶
func CompileInput(spec ToolSpec) (*InputSchema, error)
CompileInput compiles a tool's parameters as the agent does: no reference is loaded from anywhere.
func (*InputSchema) Check ¶
func (s *InputSchema) Check(input json.RawMessage) string
Check returns why input is not acceptable, or "".
type LabelSource ¶
type LabelSource struct {
// Kind is LabelSeed or LabelTool.
Kind string `json:"kind"`
// Tool and CallID name the call, for LabelTool.
Tool string `json:"tool,omitempty"`
CallID string `json:"call_id,omitempty"`
// Seq is the entry's sequence number.
Seq int `json:"seq"`
}
A LabelSource is the entry that first gave the session a label, so a client can show why the session holds it.
type LabelsEntry ¶
type LabelsEntry struct {
Labels []string `json:"labels"`
// Source says where they came from: LabelSeed.
Source string `json:"source,omitempty"`
}
LabelsEntry records labels added to the session from outside any call: an agent's starting labels.
type Limits ¶
type Limits struct {
// MaxTurns is the number of model calls in one run.
MaxTurns int `json:"max_turns,omitempty"`
// MaxToolCalls is the number of tool calls run in one run. Calls the
// model makes beyond it are refused and the run ends.
MaxToolCalls int `json:"max_tool_calls,omitempty"`
// MaxTokens is Usage.Total across one run's model calls. It is checked
// before each call, so the last call can overshoot it.
MaxTokens int64 `json:"max_tokens,omitempty"`
}
Limits stop a run that spends too much. A zero field is no limit.
type MemoryStore ¶
type MemoryStore struct {
// contains filtered or unexported fields
}
MemoryStore keeps entries in memory. Entries pass through JSON on the way in and out, so it behaves like a file would, without sharing pointers with the caller.
func NewMemoryStore ¶
func NewMemoryStore(entries ...Entry) *MemoryStore
NewMemoryStore makes a store, optionally holding entries already.
func (*MemoryStore) Append ¶
func (m *MemoryStore) Append(e Entry) error
func (*MemoryStore) Load ¶
func (m *MemoryStore) Load() ([]Entry, error)
type Message ¶
type Message struct {
Role Role `json:"role"`
Parts []Part `json:"parts"`
Native *Native `json:"native,omitempty"`
}
A Message is one turn of a conversation in a form no provider owns.
Parts is the neutral reading of the turn: what policies, logs and other providers see. Native, set only on assistant turns, is the provider's own record of the same turn, kept byte for byte. A provider replays its own turns from Native, so reasoning and anything else the neutral form cannot express goes back to it unchanged; history is never rewritten.
type MessageEntry ¶
type MessageEntry struct {
Message Message `json:"message"`
Stop Stop `json:"stop,omitempty"`
Usage Usage `json:"usage"`
// Model is the model that served the turn.
Model string `json:"model,omitempty"`
Refusal string `json:"refusal,omitempty"`
}
MessageEntry records a message joining the conversation. For an assistant turn it also carries why the turn ended and what it cost.
type Model ¶
type Model interface {
// Provider names the provider, as recorded in Native.Provider.
Provider() string
Generate(ctx context.Context, req *Request, observe func(Delta)) (*Response, error)
}
A Model is one provider's API, adapted. Adapters live in their own packages (anthropic, openai) and are the only code that knows a vendor.
Generate makes exactly one request: no retries, which belong to the Agent so they are visible and bounded. It returns a *ModelError for anything the provider refused or could not do.
type ModelError ¶
type ModelError struct {
Kind ErrorKind `json:"kind"`
Status int `json:"status,omitempty"`
Message string `json:"message"`
// RetryAfter is the earliest time the provider asked to be retried.
RetryAfter time.Time `json:"retry_after,omitzero"`
// ResetsAt is when the exhausted limit fully resets, if the provider
// said, which can be well after RetryAfter.
ResetsAt time.Time `json:"resets_at,omitzero"`
Err error `json:"-"`
}
A ModelError is a model call that failed, sorted by kind.
func AsModelError ¶
func AsModelError(err error) *ModelError
AsModelError finds the ModelError in err, wrapping any other error as Unreachable.
func (*ModelError) Error ¶
func (e *ModelError) Error() string
func (*ModelError) Transient ¶
func (e *ModelError) Transient() bool
Transient reports whether the same request could succeed later.
func (*ModelError) Unwrap ¶
func (e *ModelError) Unwrap() error
type ModelErrorEntry ¶
type ModelErrorEntry struct {
Error ModelError `json:"error"`
// Retry says whether the loop went on to try again, after WaitMillis.
Retry bool `json:"retry"`
WaitMillis int64 `json:"wait_ms,omitempty"`
}
ModelErrorEntry records one failed model call.
type ModelInfo ¶
type ModelInfo struct {
// ID is the model's identifier, as the provider gives it.
ID string
// DisplayName is the provider's name for people. Empty means it gave
// none.
DisplayName string
// ContextWindow is how many input tokens the model takes. Zero means
// the provider did not say.
ContextWindow int64
// Prices is what the model costs. Nil means the provider's adapter
// does not know, and then no cost is reported for it, not zero.
Prices *Prices
}
ModelInfo is what a provider says about one of its models.
type ModelUsage ¶
A ModelUsage is what one model call cost, and the model that served it.
type Native ¶
type Native struct {
Provider string `json:"provider"`
Model string `json:"model"`
Data json.RawMessage `json:"data"`
}
Native is a provider's own record of an assistant turn.
type Outcome ¶
type Outcome struct {
Reason Reason `json:"reason"`
// Text is the last assistant text.
Text string `json:"text,omitempty"`
Error *ModelError `json:"error,omitempty"`
Limit string `json:"limit,omitempty"`
// Forbidden, for forbidden, is the labels the session held or would
// have started with that Agent.Forbid names.
Forbidden []string `json:"forbidden,omitempty"`
// Refused lists the tool results of this run that were refused for
// carrying a forbidden label, whatever the reason the run ended.
Refused []Refusal `json:"refused,omitempty"`
// Turns and Usage count this run only.
Turns int `json:"turns"`
Usage Usage `json:"usage"`
}
An Outcome is how a run ended. Everything but a setup or store failure is one.
type Part ¶
type Part struct {
Type PartType `json:"type"`
// Text is the text of a text part, or the readable summary of a
// reasoning part, which may be empty.
Text string `json:"text,omitempty"`
ToolCall *ToolCall `json:"tool_call,omitempty"`
ToolResult *ToolResult `json:"tool_result,omitempty"`
}
A Part is one piece of a message.
type PinError ¶
type PinError struct {
Tool, Pinned, Got string
}
A PinError says a tool's definition is not the one the session pinned.
type PinsEntry ¶
PinsEntry records the digests of tool definitions the session has pinned (see Agent.Pins), by tool name. A pin is never changed.
type Policy ¶
A Policy decides whether a tool call may run. It is asked only about calls to tools the agent has, whose input already matches the schema.
type PolicyFunc ¶
PolicyFunc makes a Policy from a function.
type Prices ¶
type Prices struct {
Input, Output, CacheWrite, CacheRead float64
}
Prices is what a model charges, in US dollars per million tokens, for each kind of token a call counts.
type Reason ¶
type Reason string
Reason is why a run ended.
const ( // ReasonCompleted: the model finished its turn, or there was nothing to do. ReasonCompleted Reason = "completed" // ReasonMaxTokens: the last response was cut off by its token cap. ReasonMaxTokens Reason = "max_tokens" // ReasonRefused: the model declined to answer. ReasonRefused Reason = "refused" // ReasonLimit: a Limits field was reached; see Outcome.Limit. ReasonLimit Reason = "limit" // ReasonModelError: the model call failed for good; see Outcome.Error. ReasonModelError Reason = "model_error" // ReasonCanceled: the context ended. ReasonCanceled Reason = "canceled" // ReasonForbidden: the session holds, or would start with, a label // Agent.Forbid names, so nothing ran; see Outcome.Forbidden. ReasonForbidden Reason = "forbidden" )
type Refusal ¶
type Refusal struct {
CallID string `json:"call_id"`
Tool string `json:"tool"`
Labels []string `json:"labels"`
}
A Refusal is one tool result the session was not given, because it carried labels the session may not hold.
type Request ¶
type Request struct {
Model string
System string
Messages []Message
Tools []ToolSpec
// Effort is how hard the model should think. Empty means the
// provider's default.
Effort Effort
// MaxOutputTokens caps one response. Zero means the adapter's default.
MaxOutputTokens int
}
A Request is everything one model call is given.
type Response ¶
type Response struct {
// Message is the assistant turn, with Native set.
Message Message
Stop Stop
// Model is the model that served the request, which can differ from
// the one asked for when a provider falls back.
Model string
Usage Usage
// Refusal explains a Stop of StopRefusal, when the provider said why.
Refusal string
}
A Response is one model call's answer.
type Result ¶
type Result struct {
Content string
// IsError marks a result the model should read as a failure.
IsError bool
// Labels are added to the session for good, describing what the
// result brought into it, such as "private" or "contaminated".
Labels []string
// Log is for the operator: it is kept in the session's log and never
// shown to the model.
Log string
// Usage is the model calls the tool made for the run. They count toward the run's usage and its
// MaxTokens limit, and are kept in the tool_result entry even when
// the result is refused.
Usage []ModelUsage
// Display is what the result shows the operator and never the
// model (see Display).
Display *Display
}
A Result is what a tool call produced.
type RetryPolicy ¶
type RetryPolicy struct {
// Retries is the number of further attempts after the first.
Retries int
// Backoff is the first wait for overloaded or unreachable errors. It
// doubles each time.
Backoff time.Duration
// MaxWait is the longest single wait, rate limits included. A longer
// wait ends the run instead. Zero means no cap: any wait is accepted.
MaxWait time.Duration
}
RetryPolicy says how a failed model call is retried.
func (RetryPolicy) Wait ¶
func (p RetryPolicy) Wait(me *ModelError, attempt int, now time.Time) (time.Duration, bool)
Wait says whether to try a model call again after it failed with me on the given attempt (0 for the first), and how long to wait first, as of now.
type RunStartedEntry ¶
type RunStartedEntry struct {
Prompt string `json:"prompt,omitempty"`
}
RunStartedEntry records that Run began.
type Session ¶
type Session struct {
// contains filtered or unexported fields
}
A Session is a conversation and everything decided in it. It is the entries of a Store and nothing else: the conversation, the labels, the usage and the state of every tool call are derived from them, so a session reopened from its store is the session that was closed.
func OpenSession ¶
OpenSession rebuilds a session from the store. An empty store makes a new session.
func (*Session) AddLabels ¶
AddLabels adds labels to the session from outside any call, from source (LabelSeed). It writes an entry only when one of them is new, and returns the entry it wrote, if any.
func (*Session) CheckPins ¶
CheckPins returns a *PinError for the first tool, by name, whose digest in pins differs from the one the session pinned. A tool the session has not pinned passes.
func (*Session) LabelSources ¶
func (s *Session) LabelSources() map[string]LabelSource
LabelSources gives, for each label the session holds, the entry that first added it.
func (*Session) Messages ¶
Messages is the conversation. Results that follow an assistant turn are gathered into one user message, in the order of the calls. While calls are pending the conversation is not yet one a model can take.
func (*Session) Pending ¶
Pending lists the calls of the last assistant turn that have no result yet, in order. A resumed run settles exactly these.
func (*Session) Pins ¶
Pins are the digests of tool definitions the session has pinned, by tool name.
type Source ¶
A Source is one thing a display draws on: a title and a ref, such as web:https://example.org/ or doc:notes/venues.md.
type Store ¶
type Store interface {
// Load returns every entry, in order.
Load() ([]Entry, error)
// Append adds one entry. It is durable when it returns: a crash after
// that cannot lose it.
Append(Entry) error
}
A Store keeps a session's entries. It is the only thing a session needs to be remembered and resumed.
type Tool ¶
type Tool interface {
Spec() ToolSpec
// Call runs the tool on input that has already been checked against
// the spec's schema and allowed by the policy. An error means the
// tool could not run; the model is told so.
Call(ctx context.Context, input json.RawMessage) (Result, error)
}
A Tool is something the model may call. An Agent has no tools but the ones it is given, and runs nothing else.
type ToolCall ¶
type ToolCall struct {
ID string `json:"id"`
Name string `json:"name"`
Input json.RawMessage `json:"input"`
}
A ToolCall is the model asking to run a tool.
type ToolResult ¶
type ToolResult struct {
CallID string `json:"call_id"`
Content string `json:"content"`
IsError bool `json:"is_error,omitempty"`
}
A ToolResult answers one ToolCall.
type ToolResultEntry ¶
type ToolResultEntry struct {
Result ToolResult `json:"result"`
Labels []string `json:"labels,omitempty"`
// Log is what the tool said for the operator alone, such as a
// program's stderr. It is never part of the conversation.
Log string `json:"log,omitempty"`
// Usage is what the model calls the tool made cost (see
// Result.Usage). It counts toward the run's usage and the session's.
Usage []ModelUsage `json:"usage,omitempty"`
// Display is what the operator was shown and the model was not (see
// Display). It is never part of the conversation.
Display *Display `json:"display,omitempty"`
}
ToolResultEntry records how a call ended and what the result added to the session's labels.
type ToolSpec ¶
type ToolSpec struct {
Name string `json:"name"`
Description string `json:"description"`
// Parameters is the JSON Schema of the tool's input, an object.
Parameters json.RawMessage `json:"parameters"`
}
A ToolSpec is what the model is told about a tool.
type Turn ¶
type Turn struct {
// Message is the turn's index in Messages.
Message int
Stop Stop
// Model is the model that served the turn.
Model string
Usage Usage
// Calls lists the ids of the turn's tool calls, in order.
Calls []string
}
A Turn is one assistant message and how it ended.
type Usage ¶
type Usage struct {
InputTokens int64 `json:"input_tokens"`
OutputTokens int64 `json:"output_tokens"`
CacheReadTokens int64 `json:"cache_read_tokens,omitempty"`
CacheWriteTokens int64 `json:"cache_write_tokens,omitempty"`
}
Usage counts tokens.
Source Files
¶
Directories
¶
| Path | Synopsis |
|---|---|
|
Package acpagent serves agentloop sessions over the Agent Client Protocol.
|
Package acpagent serves agentloop sessions over the Agent Client Protocol. |
|
Package anthropic adapts the Anthropic Messages API to agentloop.Model.
|
Package anthropic adapts the Anthropic Messages API to agentloop.Model. |
|
cmd
|
|
|
agentloop
command
Command agentloop runs one agent from a JSON request.
|
Command agentloop runs one agent from a JSON request. |
|
Package command provides an agentloop.Tool that runs a program.
|
Package command provides an agentloop.Tool that runs a program. |
|
Package fake is a scripted agentloop.Model for tests.
|
Package fake is a scripted agentloop.Model for tests. |
|
internal
|
|
|
acpschema
Package acpschema validates JSON against the ACP schema vendored in acp/testdata/schema.json.
|
Package acpschema validates JSON against the ACP schema vendored in acp/testdata/schema.json. |
|
cmd/mcpremote
command
Command mcpremote serves fakeremote, a remote MCP server and its OAuth authorization server, on 127.0.0.1 at a port of its own, for tests.
|
Command mcpremote serves fakeremote, a remote MCP server and its OAuth authorization server, on 127.0.0.1 at a port of its own, for tests. |
|
cmd/mcpserver
command
Command mcpserver is a small MCP stdio server for agentloop's tests.
|
Command mcpserver is a small MCP stdio server for agentloop's tests. |
|
cmd/mockprovider
command
Command mockprovider is a stand-in for Anthropic's Messages and Models APIs, for running agentloop against conformance suites without a key or a network.
|
Command mockprovider is a stand-in for Anthropic's Messages and Models APIs, for running agentloop against conformance suites without a key or a network. |
|
fakeremote
Package fakeremote is a remote MCP server and the OAuth 2.1 authorization server in front of it, for tests: of agentloop's streamable HTTP client, and of relay connect, which runs the whole sign-in against it.
|
Package fakeremote is a remote MCP server and the OAuth 2.1 authorization server in front of it, for tests: of agentloop's streamable HTTP client, and of relay connect, which runs the whole sign-in against it. |
|
httpclient
Package httpclient is the HTTP client agentloop's model adapters use when the caller gives none.
|
Package httpclient is the HTTP client agentloop's model adapters use when the caller gives none. |
|
livetest
Package livetest gates the smoke tests that call the real provider APIs.
|
Package livetest gates the smoke tests that call the real provider APIs. |
|
request
Package request is the JSON document that says what to run, and what it takes to turn that document into an agent: loading, validation, the API key command and agent construction.
|
Package request is the JSON document that says what to run, and what it takes to turn that document into an agent: loading, validation, the API key command and agent construction. |
|
scenario
Package scenario is the harness behind the property tests, for reuse by any package that wants to drive the same generated runs.
|
Package scenario is the harness behind the property tests, for reuse by any package that wants to drive the same generated runs. |
|
sessionfile
Package sessionfile opens a session file for one process at a time.
|
Package sessionfile opens a session file for one process at a time. |
|
strictjson
Package strictjson is how agentloop reads JSON that another process wrote: the ACP client's messages, tool envelopes, MCP traffic and request files.
|
Package strictjson is how agentloop reads JSON that another process wrote: the ACP client's messages, tool envelopes, MCP traffic and request files. |
|
strictjson/stricttest
Package stricttest loads the table of lines that relay, agentloop and relay-tui must read alike (relay#58), from testdata/strict-json/cases.jsonl.
|
Package stricttest loads the table of lines that relay, agentloop and relay-tui must read alike (relay#58), from testdata/strict-json/cases.jsonl. |
|
usage
Package usage is the error for input the operator can fix: an unusable request, command line or session path.
|
Package usage is the error for input the operator can fix: an unusable request, command line or session path. |
|
Package mcp gives an agent the tools of one MCP server as agentloop.Tool values.
|
Package mcp gives an agent the tools of one MCP server as agentloop.Tool values. |
|
Package openai adapts OpenAI's Responses API to agentloop.Model.
|
Package openai adapts OpenAI's Responses API to agentloop.Model. |
|
Package otel turns an agentloop session log into OpenTelemetry traces.
|
Package otel turns an agentloop session log into OpenTelemetry traces. |