aiagent

package
v1.2.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2026 License: MIT Imports: 4 Imported by: 0

Documentation

Overview

Package aiagent provides a provider-agnostic, budgeted tool-calling agent loop for the autonomous-pentest engine. It sits one level above internal/aiassist: the ToolCaller interface normalizes the Anthropic Messages format (Anthropic + GLM) and the OpenAI chat-completions format (OpenRouter + OpenAI) into a single {assistant text + tool calls} shape, and Run drives that shape as a hard-budgeted loop against an injected ToolExecutor. All external dependencies (the model caller, the tool executor, and the wall clock) are interfaces so the loop is unit-testable with fakes — no real API calls and no real wall-clock in tests.

Index

Constants

View Source
const (
	StoppedDone   = "done"   // model produced a final tool-less answer
	StoppedBudget = "budget" // a hard budget cap was hit
	StoppedCtx    = "ctx"    // the context was cancelled
	StoppedError  = "error"  // the ToolCaller or ToolExecutor returned an error
)

Stop reasons for a completed run.

Variables

This section is empty.

Functions

This section is empty.

Types

type Budget

type Budget struct {
	MaxSteps     int   // max model turns
	MaxToolCalls int   // max total tool executions across the run
	MaxTokens    int   // advisory token ceiling (0 = unlimited/untracked)
	MaxWallMs    int64 // max wall-clock milliseconds from run start
}

Budget bounds an agent run. A zero/negative value for any field means that dimension is unbounded. MaxTokens is best-effort (advisory): it is only enforced when the ToolCaller reports usage.

type Clock

type Clock interface {
	Now() time.Time
}

Clock is an injected time source so the loop's wall-clock budget is testable without a real clock. Production code passes RealClock; tests pass a fake.

type ErrNoToolSupport

type ErrNoToolSupport struct{ Provider string }

ErrNoToolSupport is returned when the configured provider has no tool-calling path at all (so an agent run cannot proceed).

func (ErrNoToolSupport) Error

func (e ErrNoToolSupport) Error() string

type Message

type Message struct {
	Role       string
	Text       string
	Calls      []ToolCall // assistant messages: tool calls requested this turn
	ToolCallID string     // tool messages: the ToolCall.ID this result answers
}

Message is one entry in the running conversation history. Role is "user", "assistant", or "tool". For an assistant turn that requested tools, Calls holds the requested calls (so the ToolCaller can replay them to the provider in the correct wire format). For a tool-result message, ToolCallID ties the result back to the call that produced it.

type RealClock

type RealClock struct{}

RealClock is the production Clock backed by time.Now.

func (RealClock) Now

func (RealClock) Now() time.Time

Now returns the current time.

type RunResult

type RunResult struct {
	FinalText  string    // the assistant's final text (best available if budget-stopped)
	Steps      int       // model turns taken
	ToolCalls  int       // tool executions performed
	Tokens     int       // total tokens observed (best-effort)
	Transcript []Message // the full message history, including seeded task and tool results
	StoppedBy  string    // done | budget | ctx | error
}

RunResult summarizes a finished run.

func Run

func Run(ctx context.Context, tc ToolCaller, exec ToolExecutor, system, task string, tools []ToolSpec, b Budget, clock Clock) (RunResult, error)

Run drives a budgeted tool-calling loop. It seeds the history with the task, then repeatedly: (1) checks hard budgets and ctx BEFORE each model turn, (2) asks the ToolCaller for one turn, (3) if the turn has no tool calls it is the final answer (StoppedDone), else executes each call via exec, appends the results, and checks budgets again after the batch.

Budget overruns are HARD stops: the loop transitions to StoppedBudget and, if it is cheap and still within remaining budget, does a final tool-less synthesis turn to surface a closing answer (mirroring the in-app agent's final-summary pass). Context cancellation yields StoppedCtx; a caller/executor error yields StoppedError with the error returned. On StoppedError, RunResult still carries the transcript accumulated so far.

type TokenUsage

type TokenUsage struct {
	InputTokens  int
	OutputTokens int
}

TokenUsage is best-effort per-turn token accounting.

func (TokenUsage) Total

func (u TokenUsage) Total() int

Total returns input+output tokens for the turn.

type ToolCall

type ToolCall struct {
	ID   string
	Name string
	Args map[string]any
}

ToolCall is a single tool invocation the model requested.

type ToolCaller

type ToolCaller interface {
	Complete(ctx context.Context, system string, msgs []Message, tools []ToolSpec) (Turn, error)
}

ToolCaller runs one model turn. Complete is given the system prompt, the running message history, and the tools available this turn; it returns the assistant's text plus any tool calls. Implementations translate to/from a provider wire format but expose only this normalized shape.

func NewClientToolCaller

func NewClientToolCaller(c *aiassist.Client) (ToolCaller, error)

NewClientToolCaller wraps an *aiassist.Client as a ToolCaller. It returns ErrNoToolSupport if the client's provider cannot run tool-calling loops.

type ToolExecutor

type ToolExecutor interface {
	Exec(ctx context.Context, call ToolCall) (result string, err error)
}

ToolExecutor runs one tool call and returns its result string. A non-nil error is treated as a hard failure that aborts the run (StoppedBy "error"); tools that want to report a recoverable failure to the model should return it as the result string with a nil error.

type ToolSpec

type ToolSpec struct {
	Name        string
	Description string
	Schema      map[string]any // JSON Schema for the tool's input object
}

ToolSpec describes one tool made available to the model for a turn.

type Turn

type Turn struct {
	Text  string
	Calls []ToolCall
	// Usage is best-effort token accounting reported by the provider (0 when the
	// provider or transport does not surface it). MaxTokens budgeting is advisory
	// and driven off this field.
	Usage TokenUsage
}

Turn is one model turn: the assistant's text plus any tool calls it requested. When Calls is empty the turn is a final answer.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL