ai

package
v1.3.0 Latest Latest
Warning

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

Go to latest
Published: May 6, 2026 License: MIT Imports: 18 Imported by: 0

Documentation

Index

Constants

This section is empty.

Variables

View Source
var ChatPrompt string

ChatPrompt is the system prompt for general follow-up questions.

View Source
var ReviewBatchPrompt string

ReviewBatchPrompt is the system prompt for reviewing a batch of files during multi-pass PR review. Phase 1: RECALL mode — report everything.

View Source
var ReviewFilePrompt string

ReviewFilePrompt is the system prompt used when reviewing a single file's diff.

View Source
var ReviewPRPrompt = ReviewPRSystemPrompt + `

You have access to tools — use them proactively to understand the code:
- git_diff: Get the unified diffs for changed files.
- read_file: Read any file from the PR branch (after changes). Supports pagination.
- read_base_file: Read a file from the base branch (before changes).
- grep: Search for patterns across the codebase (regex). Find callers, usages, related code.
- list_dir: List directory contents to understand the project structure.
- gh_pr_checks: Check CI status for the PR.
- gh_pr_comments: Read existing review comments.

## Workflow

1. Use git_diff to read the diffs for all changed files
2. Use read_file and read_base_file to examine files when you need more context
3. Use grep to find callers, usages, and related code
4. Use gh_pr_checks to check CI status
5. Use gh_pr_comments to read existing review comments

## Output Format

You MUST return ONLY a JSON object matching this exact schema — no prose before or after:

` + "```json" + `
{
  "summary": "one paragraph capturing what the PR does and overall quality",
  "verdict": "approve | request_changes | comment",
  "findings": [
    {
      "severity": "critical | high | medium | low | nit",
      "category": "bug | security | performance | testing | style | architecture | docs",
      "file": "path/to/file.go",
      "line": 42,
      "title": "short title",
      "detail": "what's wrong and why it matters",
      "suggestion": "concrete fix, code snippet preferred",
      "cwe": "CWE-XXX (for security findings only, omit for non-security)"
    }
  ],
  "missing_tests": ["behaviors that should be tested but aren't"],
  "questions_for_author": ["genuine ambiguities, not rhetorical"]
}
` + "```" + `

Guidelines:
- "findings" array MUST be sorted by severity: critical first, nit last
- Every finding MUST include file and line
- "suggestion" may be empty string if no concrete fix is obvious
- "missing_tests" and "questions_for_author" may be empty arrays
- If the PR is clean, return verdict "approve" with an empty findings array
- Return ONLY the JSON — no markdown, no prose, no explanation`

ReviewPRPrompt is the system prompt for single-pass PR review. Combines the embedded review instructions with structured JSON output requirements and tool workflow guidance.

View Source
var ReviewPRSystemPrompt string

ReviewPRSystemPrompt is the high-quality, agent-driven review prompt used as the base for single-pass PR review.

View Source
var ReviewSynthesisPrompt string

ReviewSynthesisPrompt is the system prompt for the final synthesis pass. Phase 2: FILTER mode — verify, deduplicate, prioritize. Output is structured JSON matching ReviewOutput schema.

Functions

func IsToolReadOnly

func IsToolReadOnly(name string) bool

IsToolReadOnly returns true if the named tool is safe for concurrent execution.

func ParseReviewOutput

func ParseReviewOutput(raw string) *state.ReviewOutput

ParseReviewOutput parses a raw AI response into a structured ReviewOutput. It handles common LLM quirks: markdown code fences, leading/trailing prose, and minor JSON formatting issues. Returns nil if parsing fails.

Types

type Agent

type Agent struct {
	// contains filtered or unexported fields
}

Agent wraps a Provider with a tool-calling loop. It implements Client and ToolConfigurer for backward compatibility with the existing UI and review code.

func NewAgent

func NewAgent(provider Provider, toolExec *ToolExecutor, opts ...AgentOption) *Agent

NewAgent creates an Agent that uses the given Provider for API calls and the ToolExecutor for handling tool calls within the iterative loop.

func (*Agent) ChatStream

func (a *Agent) ChatStream(ctx context.Context, systemPrompt string, messages []Message, onToken func(string)) (string, error)

ChatStream implements Client. It runs the iterative tool-calling loop:

  1. Build ChatRequest with system prompt, history, tools (and cache hint).
  2. Call provider.StreamChat, emit text/thinking/tool tokens to the TUI.
  3. Inspect Response.Content for ToolUseBlocks.
  4. If tool calls found: execute (parallel if all read-only), build ToolResultBlock per tool_use (matched by ID, in order), append to history, loop.
  5. If no tool calls: surface final text.
  6. Cap iterations at maxRounds. On hit, surface partial result + "max iterations reached" message.

Quirk tolerance: if the model emits text without any tool_use blocks but the text looks like a preamble ("I'll now use …" pattern without substance), we tolerate this once and continue. On the second occurrence, we terminate.

func (*Agent) ModelName

func (a *Agent) ModelName() string

ModelName returns the model identifier of the underlying LLM provider.

func (*Agent) ProviderName

func (a *Agent) ProviderName() string

ProviderName returns the name of the underlying LLM provider.

func (*Agent) SetBaseRef

func (a *Agent) SetBaseRef(ref string)

SetBaseRef configures the git ref for reading base-branch files.

func (*Agent) SetHeadRef

func (a *Agent) SetHeadRef(ref string)

SetHeadRef configures the git ref used for file reading tools.

func (*Agent) SetRawDiffs

func (a *Agent) SetRawDiffs(diffs map[string]string)

SetRawDiffs provides the raw unified diffs for the git_diff tool.

func (*Agent) SetReviewGetter

func (a *Agent) SetReviewGetter(fn func() string)

SetReviewGetter provides a function that returns the latest PR review summary.

func (*Agent) SwitchModel

func (a *Agent) SwitchModel(modelID string, maxOutputTokens int, temperature float64, thinkingBudget int) error

SwitchModel changes the underlying model at runtime.

type AgentOption

type AgentOption func(*Agent)

AgentOption configures an Agent.

func WithDebugLogger

func WithDebugLogger(w io.Writer) AgentOption

WithDebugLogger enables debug logging to the given writer. All requests, responses, and tool calls are logged (with secrets redacted).

func WithMaxRounds

func WithMaxRounds(n int) AgentOption

WithMaxRounds sets the maximum number of tool-calling loop iterations.

func WithUsageTracker added in v1.3.0

func WithUsageTracker(tracker *UsageTracker) AgentOption

WithUsageTracker attaches a UsageTracker that accumulates token counts across all ChatStream calls. Useful for cost estimation and benchmarking.

type Capabilities

type Capabilities struct {
	PromptCaching     bool // explicit caching API (Anthropic, Gemini)
	StructuredOutput  bool // JSON-schema-constrained output
	ParallelToolCalls bool
	MaxContextTokens  int
}

Capabilities describes what a provider supports.

type ChatEvent

type ChatEvent struct {
	Type     ChatEventType
	Text     string        // EventText, EventThinking
	ToolUse  *ToolUseBlock // EventToolUse
	Response *ChatResponse // EventDone
	Err      error         // EventError
}

ChatEvent is a single streaming event from a provider.

type ChatEventType

type ChatEventType int

ChatEventType categorizes streaming events.

const (
	EventText     ChatEventType = iota // regular text chunk
	EventThinking                      // thinking/reasoning text
	EventToolUse                       // tool call
	EventDone                          // final event with complete response
	EventError                         // error during streaming
)

type ChatRequest

type ChatRequest struct {
	Model           string
	System          string
	Messages        []ProviderMessage
	Tools           []ToolDef
	ToolChoice      ToolChoice
	MaxOutputTokens int
	Temperature     float64
	JSONSchema      *JSONSchema // structured output, optional
	CachePrefix     bool        // hint: cache system + leading messages if supported
}

ChatRequest is the canonical request to a provider.

type ChatResponse

type ChatResponse struct {
	Content    []ContentBlock // mix of TextBlock, ThinkingBlock, ToolUseBlock
	StopReason StopReason
	Usage      TokenUsage
}

ChatResponse is the canonical response from a provider.

type Client

type Client interface {
	// ChatStream sends a conversation to the LLM and streams the response.
	// systemPrompt is prepended as a system instruction.
	// onToken is called for each streamed chunk. Chunks may be:
	//   - plain text (regular model output)
	//   - "\x00THOUGHT:<text>" — model thinking/reasoning
	//   - "\x00TOOL_START:<name>(<args>)" — tool execution starting
	//   - "\x00TOOL_DONE:<name>|<status>|<duration>" — tool execution finished
	// Returns the full assembled response text, or an error.
	ChatStream(ctx context.Context, systemPrompt string, messages []Message, onToken func(string)) (string, error)
}

Client is the interface for LLM providers.

type ContentBlock

type ContentBlock interface {
	// contains filtered or unexported methods
}

ContentBlock is a piece of message content. Implementations: TextBlock, ThinkingBlock, ToolUseBlock, ToolResultBlock.

type GeminiProvider

type GeminiProvider struct {
	APIKey     string
	Model      string
	BaseURL    string       // override for testing; empty uses the real Gemini API
	HTTPClient *http.Client // optional; defaults to a client with no timeout (context-based cancellation)

	// ModelConfig holds per-model tuning (maxOutputTokens, temperature,
	// thinkingBudget). Set by the caller from config.GetModelConfig().
	ModelConfig struct {
		MaxOutputTokens int
		Temperature     float64
		ThinkingBudget  int
	}
}

GeminiProvider implements Provider for the Google Gemini API. It handles single request/response translation; the iterative tool-calling loop lives in Agent.

func (*GeminiProvider) Capabilities

func (g *GeminiProvider) Capabilities() Capabilities

func (*GeminiProvider) Chat

Chat performs a non-streaming request by collecting StreamChat events.

func (*GeminiProvider) ModelID

func (g *GeminiProvider) ModelID() string

func (*GeminiProvider) Name

func (g *GeminiProvider) Name() string

func (*GeminiProvider) StreamChat

func (g *GeminiProvider) StreamChat(ctx context.Context, req ChatRequest) (<-chan ChatEvent, error)

StreamChat makes a single streaming API call and returns a channel of events. It translates ChatRequest to Gemini's native format, streams the SSE response, and emits canonical ChatEvents. The channel is closed when the response ends.

type JSONSchema

type JSONSchema struct {
	Name   string
	Schema json.RawMessage
}

JSONSchema is a simplified JSON Schema for structured output.

type Message

type Message struct {
	Role    string // "user" or "assistant"
	Content string
}

Message represents a chat message.

type ModelInfo

type ModelInfo interface {
	// ProviderName returns the provider name (e.g. "gemini", "anthropic").
	ProviderName() string
	// ModelName returns the model identifier (e.g. "gemini-2.5-pro").
	ModelName() string
}

ModelInfo is optionally implemented by clients that can report their model identity.

type ModelSwitcher

type ModelSwitcher interface {
	// SwitchModel changes the active model to the given ID and applies the
	// provided tuning parameters. Returns an error if the model is invalid.
	SwitchModel(modelID string, maxOutputTokens int, temperature float64, thinkingBudget int) error
}

ModelSwitcher is optionally implemented by clients that support switching the underlying model at runtime (e.g. via a TUI model picker).

type Provider

type Provider interface {
	Name() string
	ModelID() string
	Capabilities() Capabilities
	Chat(ctx context.Context, req ChatRequest) (*ChatResponse, error)
	StreamChat(ctx context.Context, req ChatRequest) (<-chan ChatEvent, error)
}

Provider is the canonical interface for LLM providers. Each supported model (Gemini, Anthropic, OpenAI) plugs in behind this interface.

Chat performs a single non-streaming request. StreamChat performs a single streaming request; the returned channel delivers events until closed. The final event is always EventDone (on success) or EventError (on failure).

type ProviderMessage

type ProviderMessage struct {
	Role    Role
	Content []ContentBlock
}

ProviderMessage is a rich message for the Provider interface. Unlike the simple Message type (used by the Agent's external API), this carries structured content blocks.

type Role

type Role string

Role represents a message participant.

const (
	RoleUser      Role = "user"
	RoleAssistant Role = "assistant"
)

type StopReason

type StopReason string

StopReason indicates why the model stopped generating.

const (
	StopEndTurn   StopReason = "end_turn"
	StopToolUse   StopReason = "tool_use"
	StopMaxTokens StopReason = "max_tokens"
	StopError     StopReason = "error"
)

type TextBlock

type TextBlock struct{ Text string }

TextBlock carries regular text content.

type ThinkingBlock

type ThinkingBlock struct {
	Text      string
	Signature string
}

ThinkingBlock carries model reasoning/thinking text. Signature is an opaque continuity token (Gemini thoughtSignature).

type TokenUsage

type TokenUsage struct {
	InputTokens  int
	OutputTokens int
	CacheHits    int // tokens served from cache (if supported)
}

TokenUsage reports token consumption for a single request.

type ToolChoice

type ToolChoice string

ToolChoice controls how the model selects tools.

const (
	ToolChoiceAuto     ToolChoice = "auto"
	ToolChoiceRequired ToolChoice = "required"
	ToolChoiceNone     ToolChoice = "none"
)

type ToolConfigurer

type ToolConfigurer interface {
	// SetHeadRef configures the git ref used for file reading tools.
	SetHeadRef(ref string)
	// SetBaseRef configures the git ref for reading base-branch files (before changes).
	SetBaseRef(ref string)
	// SetRawDiffs provides the raw unified diffs for the git_diff tool.
	SetRawDiffs(diffs map[string]string)
	// SetReviewGetter provides a function that returns the latest PR review summary.
	SetReviewGetter(fn func() string)
}

ToolConfigurer is optionally implemented by clients that support tools.

type ToolDef

type ToolDef struct {
	Name        string
	Description string
	Parameters  ToolParams
	ReadOnly    bool // true if this tool only reads state (safe for parallel execution)
}

ToolDef defines a tool the model can call. Provider-agnostic; each adapter translates to its native format.

func CanonicalToolDefs

func CanonicalToolDefs() []ToolDef

CanonicalToolDefs returns provider-agnostic tool definitions. Each provider adapter translates these to its native format. Tools are grouped: file/code inspection, git, GitHub (gh CLI), other.

type ToolExecutor

type ToolExecutor struct {
	HeadRef      string            // e.g. "origin/feature-branch" — the PR head ref for git show
	BaseRef      string            // e.g. "origin/main" — the PR base ref for reading pre-change files
	RawDiffs     map[string]string // filePath -> raw unified diff (set by UI after PR load, used by review flow)
	ReviewGetter func() string     // returns the latest PR review summary, or "" if none
	// contains filtered or unexported fields
}

ToolExecutor handles executing tool calls from the LLM.

func (*ToolExecutor) ExecuteTool

func (t *ToolExecutor) ExecuteTool(name string, args map[string]interface{}) (result string, isError bool)

ExecuteTool runs a tool call and returns the result. Results starting with "Error:" are flagged as isError=true so the model can recover gracefully.

type ToolParam

type ToolParam struct {
	Type        string
	Description string
	Enum        []string   // optional enum values
	Items       *ToolParam // for array types
}

ToolParam describes a single parameter.

type ToolParams

type ToolParams struct {
	Type       string // always "object" for function parameters
	Properties map[string]ToolParam
	Required   []string
}

ToolParams describes the parameters object for a tool.

type ToolResultBlock

type ToolResultBlock struct {
	ToolUseID string
	Name      string // tool name (needed by Gemini's functionResponse)
	Content   string
	IsError   bool
}

ToolResultBlock carries the result of executing a tool.

type ToolUseBlock

type ToolUseBlock struct {
	ID        string
	Name      string
	Args      json.RawMessage
	Signature string // opaque thought signature (Gemini); must be echoed back
}

ToolUseBlock represents a tool/function call from the model.

type UsageTracker added in v1.3.0

type UsageTracker struct {
	InputTokens  int
	OutputTokens int
	CacheHits    int
	Calls        int // number of API calls
	// contains filtered or unexported fields
}

UsageTracker accumulates token usage across multiple API calls. It is safe for concurrent use.

func (*UsageTracker) Add added in v1.3.0

func (t *UsageTracker) Add(u TokenUsage)

Add records usage from a single API call.

func (*UsageTracker) Reset added in v1.3.0

func (t *UsageTracker) Reset()

Reset zeroes all counters.

func (*UsageTracker) Snapshot added in v1.3.0

func (t *UsageTracker) Snapshot() UsageTracker

Snapshot returns a copy of the current accumulated usage.

Jump to

Keyboard shortcuts

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