ai

package
v0.0.4 Latest Latest
Warning

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

Go to latest
Published: Mar 23, 2026 License: MIT Imports: 21 Imported by: 0

Documentation

Overview

Package ai defines the provider interface and shared types for the AI subsystem. Both structured git-ops (commit messages, conflict resolution) and the conversational chat box consume these types.

Index

Constants

View Source
const (
	ExternalDataStart = "[EXTERNAL_DATA_START]"
	ExternalDataEnd   = "[EXTERNAL_DATA_END]"
)

Boundary markers used to delimit external/untrusted content embedded in LLM prompts. The markers are intentionally distinctive so that the model can recognise where data stops and instructions resume.

View Source
const RedactedPlaceholder = "[REDACTED]"

RedactedPlaceholder is the replacement text for detected secrets.

Variables

This section is empty.

Functions

func QuoteUntrusted

func QuoteUntrusted(s string) string

QuoteUntrusted quotes a single-line value for safe embedding in a prompt. It uses Go's %q verb which escapes control characters and wraps in double quotes, preventing any embedded content from altering prompt structure.

func SanitizeBranchName

func SanitizeBranchName(name string) string

SanitizeBranchName removes control characters from a branch name and validates that it is non-empty. Branch names in prompts are additionally quoted via QuoteUntrusted at the call site.

func SanitizeCommitMessage

func SanitizeCommitMessage(msg string) string

SanitizeCommitMessage removes control characters (except newlines) from a commit message and truncates it if it exceeds maxCommitMessageLen.

func SanitizeExternalContent

func SanitizeExternalContent(content string) string

SanitizeExternalContent wraps untrusted, potentially multi-line content (issue bodies, PR descriptions, file contents, diffs) in boundary markers with a preamble instructing the model to treat it as data.

Any occurrences of the boundary markers within the content itself are neutralised to prevent delimiter injection attacks.

func SanitizeFilePath

func SanitizeFilePath(path string) string

SanitizeFilePath removes control characters from a file path.

Types

type AIProvider

type AIProvider interface {
	// Name returns a human-readable identifier for this provider (e.g. "openai").
	Name() string
	// Available reports whether the provider is configured and reachable.
	Available(ctx context.Context) (bool, error)
	// Complete sends a one-shot completion request and blocks until the full
	// response is ready.
	Complete(ctx context.Context, req CompletionRequest) (CompletionResponse, error)
	// CompleteStream sends a completion request and returns a channel that
	// delivers incremental chunks. The channel is closed when the response is
	// finished or an error occurs.
	CompleteStream(ctx context.Context, req CompletionRequest) (<-chan StreamChunk, error)
	// Close releases any resources held by the provider (HTTP clients, etc.).
	Close() error
}

AIProvider is the interface every AI backend (OpenAI, Anthropic, Ollama, …) must implement. It covers one-shot completions, streaming completions, and lifecycle management.

type AuditEntry

type AuditEntry struct {
	Timestamp  time.Time `json:"timestamp"`
	Operation  string    `json:"operation"` // "conflict_resolve", "commit_message", "chat", etc.
	Provider   string    `json:"provider"`  // "copilot", "claude"
	Result     string    `json:"result"`    // "accepted", "rejected", "modified", "error"
	Error      string    `json:"error,omitempty"`
	FilesSent  []string  `json:"files_sent"` // Paths sent to AI
	Redactions int       `json:"redactions"` // Number of redactions applied
	TokensIn   int       `json:"tokens_in"`
	TokensOut  int       `json:"tokens_out"`
}

AuditEntry captures a single AI operation.

type AuditLogger

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

AuditLogger records every AI operation for transparency and debugging. Entries are appended to a structured log file with automatic rotation.

func NewAuditLogger

func NewAuditLogger(path string) (*AuditLogger, error)

NewAuditLogger creates a logger writing to the given path. If path is empty, uses default: ~/.config/grut/ai-audit.log

func (*AuditLogger) Close

func (a *AuditLogger) Close() error

Close flushes and closes the underlying file.

func (*AuditLogger) Log

func (a *AuditLogger) Log(entry AuditEntry) error

Log appends an entry to the audit log. Thread-safe.

type Builder

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

Builder constructs GitContext objects from repository state, managing token budgets to stay within provider limits.

func NewBuilder

func NewBuilder(client git.GitClient, redactor *Redactor, maxTokens int) *Builder

NewBuilder creates a context builder with the given git client, optional redactor (may be nil to skip redaction), and maximum token budget. A maxTokens of 0 or negative means no limit.

Security: if redactor is nil, a default redactor with built-in secret patterns is created to ensure fail-closed behavior — file contents are never sent to AI providers without redaction (CWE-200).

func (*Builder) ForBisect

func (b *Builder) ForBisect(ctx context.Context, good, bad string) (GitContext, error)

ForBisect builds context for bisect analysis. Includes diff between good/bad and candidate commits.

func (*Builder) ForChangelog

func (b *Builder) ForChangelog(ctx context.Context, fromRef, toRef string) (GitContext, error)

ForChangelog builds context for changelog generation. Includes all commits between two refs.

func (*Builder) ForChat

func (b *Builder) ForChat(ctx context.Context) (GitContext, error)

ForChat builds lightweight context for the chat box. Includes only branch name and working tree status — no diffs or file contents.

func (*Builder) ForCommit

func (b *Builder) ForCommit(ctx context.Context) (GitContext, error)

ForCommit builds context for commit message generation. Includes staged diff, recent commits (for style matching), and branch name.

func (*Builder) ForConflict

func (b *Builder) ForConflict(ctx context.Context, files []string) (GitContext, error)

ForConflict builds context for merge conflict resolution. Includes conflict file contents, branch histories, and surrounding context.

func (*Builder) ForPR

func (b *Builder) ForPR(ctx context.Context, targetBranch string) (GitContext, error)

ForPR builds context for PR description generation. Includes diff vs target branch and all branch commits.

func (*Builder) ForRebase

func (b *Builder) ForRebase(ctx context.Context, onto string) (GitContext, error)

ForRebase builds context for rebase assistance. Includes commits to rebase and their diffs.

func (*Builder) ForReview

func (b *Builder) ForReview(ctx context.Context, opts git.DiffOpts) (GitContext, error)

ForReview builds context for code review. Includes diff, affected file contents, and recent commits.

func (*Builder) ForSplit

func (b *Builder) ForSplit(ctx context.Context, commitHash string) (GitContext, error)

ForSplit builds context for commit splitting. Includes the full diff of a large commit.

type ChatMessage

type ChatMessage struct {
	// Role is one of "user", "assistant", "tool", or "system".
	Role string
	// Content is the textual body of the message.
	Content string
	// ToolID identifies the tool invocation this message responds to. Set
	// when Role is "tool".
	ToolID string
	// ToolCalls is populated when Role is "assistant" and the model invokes
	// one or more tools.
	ToolCalls []ToolCall
}

ChatMessage represents a single turn in a multi-turn conversation.

type ClaudeProvider

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

ClaudeProvider implements AIProvider using the Anthropic Claude API via the anthropic-sdk-go SDK.

func NewClaudeProvider

func NewClaudeProvider(model string, maxTokens int) *ClaudeProvider

NewClaudeProvider creates a ClaudeProvider. model defaults to claude-sonnet-4-20250514 when empty; maxTokens defaults to 8192 when <= 0. The SDK reads ANTHROPIC_API_KEY from the environment automatically.

func (*ClaudeProvider) Available

func (p *ClaudeProvider) Available(_ context.Context) (bool, error)

Available reports true when the ANTHROPIC_API_KEY env var is set.

func (*ClaudeProvider) Close

func (p *ClaudeProvider) Close() error

Close releases resources. The SDK client is stateless, so this is a no-op.

func (*ClaudeProvider) Complete

Complete sends a one-shot completion request and blocks until the full response is ready.

func (*ClaudeProvider) CompleteStream

func (p *ClaudeProvider) CompleteStream(ctx context.Context, req CompletionRequest) (<-chan StreamChunk, error)

CompleteStream sends a completion request and returns a channel that delivers incremental StreamChunks. The channel is closed when the response completes or an error occurs.

func (*ClaudeProvider) Name

func (p *ClaudeProvider) Name() string

Name returns "claude".

type CompletionRequest

type CompletionRequest struct {
	// Operation identifies the high-level task, e.g. "conflict_resolve",
	// "commit_message", or "chat".
	Operation string
	// SystemPrompt is the system-level instruction prepended to the
	// conversation.
	SystemPrompt string
	// GitContext supplies structured repository state for git-ops callers.
	GitContext GitContext
	// Messages carries a multi-turn conversation for the chat box.
	Messages []ChatMessage
	// UserPrompt is a single user turn, used by git-ops callers that don't
	// need multi-turn history.
	UserPrompt string
	// Tools lists function-calling tool definitions available to the model.
	Tools []ToolDefinition
	// MaxTokens caps the number of tokens the model may generate.
	MaxTokens int
	// Temperature controls output randomness (0 = deterministic, 1 = creative).
	Temperature float64
}

CompletionRequest carries everything the provider needs to produce a response. Fields are selectively populated depending on the caller: git-ops fill GitContext; the chat box fills Messages.

type CompletionResponse

type CompletionResponse struct {
	// Metadata holds provider-specific key/value pairs (model name, request
	// ID, etc.).
	Metadata map[string]string
	// Content is the model-generated text.
	Content string
	// FinishReason indicates why generation stopped:
	// "stop", "length", "tool_calls", or "error".
	FinishReason string
	// ToolCalls contains any function calls the model wants to invoke.
	ToolCalls []ToolCall
	// TokensUsed reports input/output token counts for the request.
	TokensUsed TokenUsage
}

CompletionResponse is the provider's reply to a CompletionRequest.

type ConflictFile

type ConflictFile struct {
	// Path is the repository-relative file path.
	Path string
	// OursContent is the full file content from the current branch.
	OursContent string
	// TheirsContent is the full file content from the incoming branch.
	TheirsContent string
	// BaseContent is the full file content from the common ancestor.
	BaseContent string
	// ConflictMarkers lists the individual conflict regions within the file.
	ConflictMarkers []ConflictRegion
}

ConflictFile describes a single file with unresolved merge conflicts.

type ConflictRegion

type ConflictRegion struct {
	// Ours is the text from the current branch within this region.
	Ours string
	// Theirs is the text from the incoming branch within this region.
	Theirs string
	// Base is the text from the common ancestor within this region, if
	// available (diff3 style).
	Base string
	// StartLine is the 1-based line where the conflict begins.
	StartLine int
	// EndLine is the 1-based line where the conflict ends (inclusive).
	EndLine int
}

ConflictRegion marks a single conflict hunk inside a file.

type CopilotProvider

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

--------------------------------------------------------------------------- CopilotProvider --------------------------------------------------------------------------- CopilotProvider implements AIProvider using the official GitHub Copilot SDK (github.com/github/copilot-sdk/go). It manages a Copilot CLI client that is lazily started on first use and creates per-request sessions.

Tool-calling note: The SDK manages tool execution internally via registered handlers. Since the AIProvider interface provides ToolDefinition without execution logic, tool definitions in CompletionRequest.Tools are not forwarded to the SDK. Callers relying on intermediate ToolCalls in the CompletionResponse should be aware this provider does not produce them.

func NewCopilotProvider

func NewCopilotProvider(model string) (*CopilotProvider, error)

NewCopilotProvider creates a CopilotProvider backed by the Copilot SDK. If model is empty the SDK / server selects a default model. Auth is handled by the SDK: if GITHUB_TOKEN is set it is passed directly; otherwise the SDK falls back to gh CLI / stored OAuth tokens.

func (*CopilotProvider) Available

func (p *CopilotProvider) Available(ctx context.Context) (bool, error)

Available reports whether the Copilot SDK can authenticate. It lazily starts the underlying CLI client and queries auth status.

func (*CopilotProvider) Close

func (p *CopilotProvider) Close() error

Close stops the Copilot CLI client if it was started.

func (*CopilotProvider) Complete

Complete sends a one-shot completion request via the Copilot SDK and blocks until the full response is ready.

func (*CopilotProvider) CompleteStream

func (p *CopilotProvider) CompleteStream(ctx context.Context, req CompletionRequest) (<-chan StreamChunk, error)

CompleteStream sends a streaming completion request and returns a channel that delivers incremental chunks. The channel is closed when the response finishes or an error occurs.

func (*CopilotProvider) Name

func (p *CopilotProvider) Name() string

Name returns "copilot".

type GitContext

type GitContext struct {
	// RepoRoot is the absolute path to the repository root.
	RepoRoot string
	// CurrentBranch is the checked-out branch.
	CurrentBranch string
	// TargetBranch is the branch being merged into or compared against.
	TargetBranch string
	// Diffs contains file-level diff information (staged or unstaged).
	Diffs []git.FileDiff
	// Conflicts lists files with unresolved merge conflicts.
	Conflicts []ConflictFile
	// Log holds recent commit history for context.
	Log []git.Commit
	// FileContents maps file paths to their full text, used when the model
	// needs to see entire files rather than just diffs.
	FileContents map[string]string
	// Status lists the working tree and index status of tracked files.
	Status []git.FileStatus
}

GitContext provides structured repository state to AI-powered git operations. Callers populate only the fields relevant to the operation (e.g. Diffs for commit messages, Conflicts for merge resolution).

type Redactor

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

Redactor sanitises content before it reaches AI providers, removing secrets and excluding sensitive files.

func NewRedactor

func NewRedactor(patterns []string) *Redactor

NewRedactor creates a Redactor from the given user-supplied file-exclusion patterns, merged with the built-in patterns that are always active. All secret-matching regexes are compiled once at construction time.

func (*Redactor) RedactContent

func (r *Redactor) RedactContent(content string) (string, int)

RedactContent scans content for secret patterns and replaces each match with [REDACTED]. It returns the sanitised content and the total number of redactions performed.

func (*Redactor) ShouldExcludeFile

func (r *Redactor) ShouldExcludeFile(path string) bool

ShouldExcludeFile reports whether the given file path matches any exclusion pattern and should not be sent to AI. Matching is performed against the base name of the path, so "config/.env.local" is caught by the ".env.*" pattern.

type Registry

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

Registry manages registered AI providers and resolves the active one based on configuration (primary + fallback).

func NewRegistry

func NewRegistry(cfg config.AIConfig) *Registry

NewRegistry creates a registry configured with the given AI settings. It does NOT register any providers — call Register() to add them.

func (*Registry) Close

func (r *Registry) Close() error

Close shuts down all registered providers, collecting any errors.

func (*Registry) Get

func (r *Registry) Get(ctx context.Context) (AIProvider, error)

Get returns the first available provider: tries primary, then fallback. Returns an error if neither is registered or available.

func (*Registry) GetByName

func (r *Registry) GetByName(name string) (AIProvider, bool)

GetByName returns a specific provider by name, or false if not found.

func (*Registry) PrimaryName

func (r *Registry) PrimaryName() string

PrimaryName returns the configured primary provider name.

func (*Registry) Register

func (r *Registry) Register(name string, p AIProvider)

Register adds a provider under the given name. If a provider with that name already exists, it is replaced.

type StreamChunk

type StreamChunk struct {
	// Err carries any error that terminated the stream.
	Err error
	// TokensUsed is set only on the final chunk (Done == true).
	TokensUsed *TokenUsage
	// Delta contains the new text fragment.
	Delta string
	// ToolCalls contains incremental tool-call data, if any.
	ToolCalls []ToolCall
	// Done is true on the final chunk.
	Done bool
}

StreamChunk is a single incremental piece of a streaming response.

type TokenUsage

type TokenUsage struct {
	// InputTokens is the number of prompt tokens sent.
	InputTokens int
	// OutputTokens is the number of tokens the model generated.
	OutputTokens int
}

TokenUsage tracks how many tokens a request consumed.

type ToolCall

type ToolCall struct {
	// Arguments are the parsed function arguments.
	Arguments map[string]any
	// ID is a provider-assigned identifier used to correlate tool results
	// back to the call.
	ID string
	// Name is the function to invoke (must match a ToolDefinition.Name).
	Name string
}

ToolCall represents a single function invocation requested by the model.

type ToolDefinition

type ToolDefinition struct {
	// Parameters is a JSON Schema object describing the function's arguments.
	Parameters map[string]any
	// Name is the function name the model references in a ToolCall.
	Name string
	// Description explains what the tool does, helping the model decide when
	// to call it.
	Description string
}

ToolDefinition describes a function the model may call.

Directories

Path Synopsis
Package middleware provides AIGitClient, a transparent wrapper around git.GitClient that intercepts operations with AI enhancements while delegating all other methods to the inner client.
Package middleware provides AIGitClient, a transparent wrapper around git.GitClient that intercepts operations with AI enhancements while delegating all other methods to the inner client.
Package ops implements AI-powered git operations that compose the core provider and context types from the ai package.
Package ops implements AI-powered git operations that compose the core provider and context types from the ai package.

Jump to

Keyboard shortcuts

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