chat

package
v0.2.0-rc.3 Latest Latest
Warning

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

Go to latest
Published: Nov 13, 2026 License: MIT Imports: 33 Imported by: 0

Documentation

Overview

Package chat answers a reviewer's questions about a pull request with the agent that wrote its review. A conversation belongs to one saved review version and keeps one agent session: its first turn forks the session the review was generated in, so the agent starts with everything it read, and every later turn resumes the conversation's own session in the same working directory. When the review's session is gone, the conversation starts a new session in a seeded run directory (the checkout at the review's head, the saved review and the earlier turns) and says so.

Only a review by a local Claude Code (User profile) or Codex (Local profile) keeps a session, so only those chat. The agent is read-only, as it was for the review. Answers are checked (schema, cited files and lines), masked for secrets and stored with the conversation in the clone's review store (internal/store).

Index

Constants

View Source
const (
	MaxQuestionRunes = 4000
	MaxAnswerBytes   = 20000
	MaxCitations     = 20
	MaxAnchors       = 20
)

Limits of what a question and its answer may hold.

View Source
const NoSessionNote = "The agent kept no session for this answer, so the next question starts without this conversation's context."

NoSessionNote is the note on a turn whose agent reported no session: the next question starts from the saved review and the earlier turns.

View Source
const SeededNote = "Started without the review's own context: "

SeededNote starts the note on a turn whose conversation had to start a new session without the review agent's own context.

Variables

View Source
var (
	ErrRepositoryNotFound = errors.New("the repository is not registered")
	ErrNeedsClone         = errors.New("a local clone of the repository is required")
	ErrNoReview           = errors.New("there is no saved review of this pull request at that version")
	ErrUnsupportedBackend = errors.New("only a review written by Claude Code or Codex on this computer can be asked about")
	ErrBusy               = store.ErrConversationBusy
	ErrNotFound           = store.ErrConversationNotFound
	ErrInvalid            = errors.New("invalid question")
)

Errors a question is refused with before it is queued. The API answers each with its own code.

View Source
var Schema = []byte(`{
  "type": "object",
  "additionalProperties": false,
  "required": ["answer_markdown", "citations", "suggests_fix"],
  "properties": {
    "answer_markdown": {"type": "string", "minLength": 1, "maxLength": 20000},
    "citations": {
      "type": "array",
      "maxItems": 20,
      "items": {
        "type": "object",
        "additionalProperties": false,
        "required": ["path", "start_line", "end_line"],
        "properties": {
          "path": {"type": "string", "minLength": 1, "maxLength": 1024},
          "start_line": {"type": "integer", "minimum": 1},
          "end_line": {"type": "integer", "minimum": 1}
        }
      }
    },
    "suggests_fix": {
      "anyOf": [
        {
          "type": "object",
          "additionalProperties": false,
          "required": ["summary"],
          "properties": {"summary": {"type": "string", "minLength": 1, "maxLength": 2000}}
        },
        {"type": "null"}
      ]
    }
  }
}`)

Schema is the JSON Schema of an answer. It keeps to what strict structured outputs accept (codex.StrictSchema): objects with every property required and no others, arrays, strings and integers, and null only through anyOf.

Functions

func Budgets

func Budgets(cfg config.Config) agent.Budgets

Budgets are a turn's: the time limit of an agent run that is not a review (run_timeout) and, when a review's calls and tokens are bounded, half of each.

func PassTimeout

func PassTimeout(cfg config.Config) time.Duration

PassTimeout lets an agent call use the turn's full time limit. A backend call may contain its entire tool loop, so a shorter pass deadline would defeat the run time limit chosen in Settings.

func Supported

func Supported(backend string) bool

Supported reports whether a review by backend can be chatted with: only a local Claude Code or Codex session can be resumed.

Types

type Anchor

type Anchor struct {
	Path      string `json:"path"`
	StartLine int    `json:"start_line,omitempty"`
	EndLine   int    `json:"end_line,omitempty"`
}

Anchor is a file, or lines of it, the focused part of the review points at.

type Answer

type Answer struct {
	Markdown    string      `json:"answer_markdown"`
	Citations   []Citation  `json:"citations"`
	SuggestsFix *Suggestion `json:"suggests_fix"`
}

Answer is the agent's answer to one question.

type Ask

type Ask struct {
	Clone        string
	PR           int
	Version      int
	Conversation string
	Question     string
	Focus        *Focus
}

Ask is a question to queue: on a new conversation about the review version Version, or the next turn of Conversation.

type Begun

type Begun struct {
	Ref
	Repository     string
	Version        int
	Backend, Model string
}

Begun is a question stored as a queued turn.

type Citation

type Citation struct {
	Path      string `json:"path"`
	StartLine int    `json:"start_line"`
	EndLine   int    `json:"end_line"`
}

Citation is lines of a file at the pull request's head, by its repository-relative path.

type Focus

type Focus struct {
	// Kind is "section", "stop" or "overview".
	Kind    string   `json:"kind"`
	ID      string   `json:"id,omitempty"`
	Title   string   `json:"title,omitempty"`
	Anchors []Anchor `json:"anchors,omitempty"`
}

Focus is the part of the review a question is about, as the app sends it. It is untrusted data in the prompt.

func (Focus) Validate

func (f Focus) Validate() error

Validate checks the focus's kind and bounds.

type Ref

type Ref struct {
	Clone        string `json:"clone"`
	PR           int    `json:"pr"`
	Conversation string `json:"conversation"`
	Turn         int    `json:"turn"`
}

Ref names one turn: the clone, pull request, conversation and turn number. A chat job carries it.

type Report

type Report struct {
	Phase                  string
	Accounting             *agent.Accounting
	Calls, Tokens, Repairs int
	CostUSD                *float64
	CostReason             string
}

Report is what a turn has spent so far, as the job shows it.

type RunOptions

type RunOptions struct {
	// Transcript receives the agent's steps as the job's transcript; nil
	// keeps none.
	Transcript func(agent.TranscriptEntry)
	// Progress receives the phase and what was spent; nil discards it.
	Progress func(Report)
}

RunOptions are where a turn's progress goes.

type Service

type Service struct {
	Registry *repos.Registry
	Config   config.Config
	// Backends builds the agents; the zero value builds the default ones for
	// the resolved configuration.
	Backends generate.Backends
	// Root holds the run directories of seeded sessions; empty is
	// reviewruns.DefaultRoot. The review's kept directories are there too.
	Root string
	// Log receives sizes and outcomes, never questions or answers; nil logs
	// nothing.
	Log *slog.Logger
	// Now defaults to time.Now.
	Now func() time.Time
	// RetryDelay is the wait before a provider retry (agent.Generator);
	// nil is the loop's default.
	RetryDelay func(attempt int) time.Duration
}

Service stores conversations and runs their turns.

func (*Service) Begin

func (s *Service) Begin(ctx context.Context, a Ask, jobID string, ended store.Ended) (Begun, error)

Begin stores a question as a queued turn of job jobID: the first turn of a new conversation about the review version, or the next turn of an existing one. ended reports how the job of a turn still pending ended, so a turn a stopped daemon left pending does not keep the conversation busy.

func (*Service) Conversations

func (s *Service) Conversations(ctx context.Context, clone string, pr int, ended store.Ended) ([]store.Conversation, error)

Conversations lists the pull request's conversations, newest first. A turn still pending whose job ended reads as ended reports it: the turn is settled a moment after its job, and a stopped daemon leaves it pending.

func (*Service) Run

func (s *Service) Run(ctx context.Context, ref Ref, o RunOptions) (report Report, err error)

Run answers the turn ref names. It marks the turn running, runs the agent in the conversation's session (forking the review's on the first turn, or seeding a new one when that is gone), checks and masks the answer, and stores it with what it cost. A failure leaves the turn running for the queue to settle with the job's reason; the error is a *generate.Error whose category is the reason, or ErrNeedsClone.

func (*Service) Settle

func (s *Service) Settle(ctx context.Context, ref Ref, state, reason string, cost *float64, costReason string) error

Settle ends a turn that is still pending, for a job that failed, was cancelled or was interrupted: a completed turn keeps its answer.

type Suggestion

type Suggestion struct {
	Summary string `json:"summary"`
}

Suggestion is a concrete change the answer says should be made.

Directories

Path Synopsis
Package chattest builds a registered clone with a saved review whose agent session was kept, and a scripted agent, for tests of chats.
Package chattest builds a registered clone with a saved review whose agent session was kept, and a scripted agent, for tests of chats.

Jump to

Keyboard shortcuts

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