ai

package
v0.9.0 Latest Latest
Warning

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

Go to latest
Published: May 5, 2026 License: MIT Imports: 11 Imported by: 0

Documentation

Overview

Package ai implements an autonomous LLM-driven browser agent that drives the existing ghostchrome agent ops. It is provider-agnostic (Anthropic, OpenAI) and goes through a Runner adapter so cmd/ai.go can inject the real session without exposing internal types.

Index

Constants

View Source
const SystemPrompt = `` /* 769-byte string literal not displayed */

SystemPrompt is the role-priming message prepended to every conversation. Keep it tight — verbose system prompts hurt latency and cost.

Variables

View Source
var ErrFakeExhausted = errors.New("fake provider: scripted steps exhausted")

ErrFakeExhausted is returned when the script is consumed.

Functions

This section is empty.

Types

type AnthropicProvider

type AnthropicProvider struct {
	APIKey      string
	Model       string
	MaxTokens   int
	Temperature float64
	Endpoint    string // override for self-hosted gateways
	Timeout     time.Duration
}

AnthropicProvider talks directly to the Messages API. Stays HTTP-native to avoid a heavyweight SDK dependency and the version drift that comes with it.

func (*AnthropicProvider) Name

func (p *AnthropicProvider) Name() string

func (*AnthropicProvider) Step

func (p *AnthropicProvider) Step(ctx context.Context, history []Message, tools []ToolSpec) (Step, error)

type FakeCall

type FakeCall struct {
	History []Message
	Tools   []ToolSpec
}

FakeCall is a record of one Provider.Step invocation.

type FakeProvider

type FakeProvider struct {
	Steps []Step

	// CalledWith is appended on every Step invocation; useful for asserts.
	CalledWith []FakeCall
	// contains filtered or unexported fields
}

FakeProvider replays a scripted sequence of Steps without ever calling a real LLM. Used by loop_test.go and as a way for downstream callers to integration-test pipelines without burning tokens.

One Step is consumed per Provider.Step call. When the queue is empty, Step returns ErrFakeExhausted.

func (*FakeProvider) Name

func (p *FakeProvider) Name() string

func (*FakeProvider) Step

func (p *FakeProvider) Step(_ context.Context, history []Message, tools []ToolSpec) (Step, error)

type FakeRunner

type FakeRunner struct {
	URL     string
	Results map[string]any                        // op → result
	OnOp    func(op string, args json.RawMessage) // optional spy
}

FakeRunner is a deterministic Runner that returns a canned result for each op. Use to drive Run end-to-end without a real browser.

func (*FakeRunner) CurrentURL

func (r *FakeRunner) CurrentURL() string

func (*FakeRunner) RunOp

func (r *FakeRunner) RunOp(op string, args json.RawMessage) (any, *engine.Observation, error)

type LoopOpts

type LoopOpts struct {
	Goal     string
	MaxSteps int  // hard cap (default 15)
	Verbose  bool // emit one stderr trace line per tool call
	OnStep   func(StepRecord)
}

LoopOpts configures one Run call.

type Message

type Message struct {
	Role    string        `json:"role"` // "system" | "user" | "assistant" | "tool"
	Content string        `json:"content,omitempty"`
	Tool    *ToolMessage  `json:"-"` // present when Role=="tool"
	Calls   []ToolCallReq `json:"-"` // present on assistant messages with tool calls
}

Message is the cross-provider chat message shape used by the loop.

type OpenAIProvider

type OpenAIProvider struct {
	APIKey      string
	Model       string
	Temperature float64
	Endpoint    string
	Timeout     time.Duration
}

OpenAIProvider hits the Chat Completions endpoint with function-style tool calls. Same HTTP-native rationale as AnthropicProvider.

func (*OpenAIProvider) Name

func (p *OpenAIProvider) Name() string

func (*OpenAIProvider) Step

func (p *OpenAIProvider) Step(ctx context.Context, history []Message, tools []ToolSpec) (Step, error)

type Provider

type Provider interface {
	Name() string
	Step(ctx context.Context, history []Message, tools []ToolSpec) (Step, error)
}

Provider is the LLM backend abstraction. Implementations are stateless; the loop accumulates the conversation and replays it on every Step call.

type Result

type Result struct {
	Success     bool         `json:"success"`
	Goal        string       `json:"goal"`
	Provider    string       `json:"provider"`
	Model       string       `json:"model"`
	Steps       []StepRecord `json:"steps"`
	StepsTaken  int          `json:"steps_taken"`
	FinalURL    string       `json:"final_url,omitempty"`
	FinalAnswer string       `json:"final_answer,omitempty"`
	Error       string       `json:"error,omitempty"`
}

Result is the JSON envelope emitted by `ghostchrome ai`.

func Run

func Run(ctx context.Context, runner Runner, provider Provider, opts LoopOpts) (*Result, error)

Run drives the observe→think→act loop until the model emits the `done` tool, MaxSteps is hit, or the runner returns a fatal error.

type Runner

type Runner interface {
	RunOp(op string, args json.RawMessage) (result any, obs *engine.Observation, err error)
	CurrentURL() string
}

Runner is the adapter the loop uses to actually execute tools against the browser. cmd/ai.go provides an implementation that wraps an agentSession.

type Step

type Step struct {
	Text        string        // assistant prose (kept for trace)
	ToolCalls   []ToolCallReq // 0+ tool calls to execute (often 1)
	StopReason  string        // "end_turn" | "tool_use" | "max_tokens" | …
	FinalAnswer string        // populated when the model emits the `done` tool
}

Step is the LLM's decision for one iteration.

type StepRecord

type StepRecord struct {
	Index       int                 `json:"index"`
	Op          string              `json:"op,omitempty"`
	Args        json.RawMessage     `json:"args,omitempty"`
	OK          bool                `json:"ok"`
	Error       string              `json:"error,omitempty"`
	Observation *engine.Observation `json:"observation,omitempty"`
	Text        string              `json:"text,omitempty"` // assistant prose for this step
}

StepRecord is appended to Result.Steps for each iteration. Compact by design — never embed raw DOM/HTML payloads here.

type ToolCallReq

type ToolCallReq struct {
	ID    string
	Name  string
	Input json.RawMessage
}

ToolCallReq is a tool call requested by the assistant.

type ToolMessage

type ToolMessage struct {
	CallID string
	Name   string
	Result string // serialised JSON result (or error)
	IsErr  bool
}

ToolMessage carries the result of a tool execution back to the LLM.

type ToolSpec

type ToolSpec struct {
	Name        string
	Description string
	InputSchema map[string]any // JSON Schema object
}

ToolSpec is the JSON-Schema-shaped tool definition shared with the LLM.

func ToolSpecs

func ToolSpecs() []ToolSpec

ToolSpecs returns the tool catalog exposed to the LLM. The names match the JSONL ops dispatched by cmd/agent.go's agentSession.dispatch — this is intentional: the LLM can read CLAUDE.md / agent docs and pick the same op names a human operator would.

Schemas are deliberately minimal — overspec'd schemas hurt model recall (extra fields the model has to reason about) without buying us safety beyond what the agent ops already enforce at runtime.

Jump to

Keyboard shortcuts

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