ai

package
v1.8.2 Latest Latest
Warning

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

Go to latest
Published: Sep 26, 2026 License: MIT Imports: 29 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultCompactPercent = 80

DefaultCompactPercent is how full the window gets before the conversation is compacted automatically, when the setting says nothing.

View Source
const ExecuteSystemPrompt = `` /* 266-byte string literal not displayed */

ExecuteSystemPrompt documents execution rules (authoritative copy on Nimbus Cloud).

View Source
const PlanSystemPrompt = `` /* 569-byte string literal not displayed */

PlanSystemPrompt documents the plan JSON contract the CLI expects. The authoritative prompts live on Nimbus Cloud; this is kept for reference and offline tooling.

Variables

View Source
var ErrTurnUnsupported = errors.New("nimbus cloud server does not support agent turns (upgrade the server)")

ErrTurnUnsupported is returned when the cloud server predates the agent turn endpoint; callers fall back to the legacy plan/execute endpoints.

View Source
var SettingDefs = []SettingDef{
	{
		Key: "model", Label: "Model", Kind: SettingChoice,
		Help:    "Which model answers. 'optimal' lets the server choose per request.",
		Choices: []string{"optimal", "fast", "balanced", "deep"},
		// contains filtered or unexported fields
	},
	{
		Key: "auto_compact", Label: "Auto-compact", Kind: SettingBool,
		Help: "Summarise earlier turns automatically as the window fills, instead of failing the turn.",
		// contains filtered or unexported fields
	},
	{
		Key: "context_limit", Label: "Context limit", Kind: SettingInt,
		Help: "Assumed context window, in tokens. Too high fails requests; too low compacts early.",
		Min:  16000, Max: 1000000, Step: 16000, Env: contextLimitEnv,
		// contains filtered or unexported fields
	},
	{
		Key: "compact_threshold_percent", Label: "Compact at", Kind: SettingInt,
		Help: "How full the window gets before compaction runs, as a percentage.",
		Min:  50, Max: 95, Step: 5,
		// contains filtered or unexported fields
	},
	{
		Key: "permission_mode", Label: "Permission mode", Kind: SettingChoice,
		Help:    "auto asks about consequential actions · ask confirms every change · allow runs anything not refused.",
		Choices: []string{string(PermissionAuto), string(PermissionAsk), string(PermissionAllow)},
		// contains filtered or unexported fields
	},
	{
		Key: "verify_builds", Label: "Verify builds", Kind: SettingBool,
		Help: "Build the project after a turn changes code, and hand failures back to be repaired.",
		// contains filtered or unexported fields
	},
	{
		Key: "plan_first", Label: "Plan before executing", Kind: SettingBool,
		Help: "Route every request through plan → approve → execute, rather than answering directly.",
		// contains filtered or unexported fields
	},
	{
		Key: "expand_diffs", Label: "Expand diffs", Kind: SettingBool,
		Help: "Show full diffs in the transcript instead of a change summary. Ctrl+O toggles it per session.",
		// contains filtered or unexported fields
	},
	{
		Key: "show_thinking", Label: "Show thinking", Kind: SettingBool,
		Help: "Report how long each stretch of thinking took.",
		// contains filtered or unexported fields
	},
	{
		Key: "stream_output", Label: "Stream output", Kind: SettingBool,
		Help: "Print the reply as it arrives rather than when it is complete.",
		// contains filtered or unexported fields
	},
	{
		Key: "max_command_output", Label: "Max command output", Kind: SettingInt,
		Help: "Bytes of a command's output fed back to the model before it is truncated.",
		Min:  4096, Max: 262144, Step: 4096,
		// contains filtered or unexported fields
	},
}

SettingDefs is the catalogue, in the order the screen shows it.

Functions

func ContextLimit added in v1.6.0

func ContextLimit() int

ContextLimit returns the assumed context window when no session says otherwise. Settings reach a session through Session.SetLimits.

func EnsureDefaultSkills

func EnsureDefaultSkills() error

EnsureDefaultSkills writes embedded default skills to ~/.nimbus/skills/ if not already present. EnsureDefaultSkills is retained as a no-op.

The Nimbus skill library is Nimbus Cloud intellectual property and now lives on the server, which selects the relevant skill for each turn and folds it into the model's instructions. It used to be embedded in this binary and written to ~/.nimbus/skills on every run, which shipped the whole library to every machine that installed the CLI.

Skills the user writes themselves — in the project or in ~/.nimbus/skills — are unaffected: they stay local and are still discovered by LoadSkills and read by the load_skill tool.

func EstimateTokens added in v1.6.0

func EstimateTokens(messages []Message) int

EstimateTokens approximates the tokens a conversation occupies.

Four characters per token is the usual rule of thumb for English prose and code; tool results skew longer, which the estimate absorbs by counting every character of them too.

func FormatSkillsSummary

func FormatSkillsSummary(skills []Skill) string

FormatSkillsSummary formats the lightweight skill index as a bullet list for the system prompt.

func FormatTokens added in v1.6.0

func FormatTokens(n int) string

FormatTokens renders a token count compactly (1234 -> "1.2k").

func GenerateUnifiedDiff

func GenerateUnifiedDiff(oldContent, newContent, filePath string) string

GenerateUnifiedDiff builds a simple unified line diff.

func ReadSkillContent

func ReadSkillContent(appRoot, skillName string) (string, error)

ReadSkillContent reads the full SKILL.md body for a given skill on demand.

func ReadSkillSection added in v1.5.4

func ReadSkillSection(appRoot, skillName, query string) (string, error)

ReadSkillSection reads only the relevant sections matching a query from a skill document.

func SaveSession

func SaveSession(appRoot string, session *Session) error

SaveSession persists the session JSON under .nimbus/ai-sessions/<id>.json.

func SaveSetting added in v1.6.0

func SaveSetting(appRoot string, scope SettingsScope, key string, value any) error

SaveSetting writes one key to one scope, leaving the rest of the file alone.

Rewriting the whole file from a resolved Settings would be wrong twice over: it would bake every inherited value into the layer as if it had been set there, and it would drop any key this build does not know about.

func ScanForInjection added in v1.6.0

func ScanForInjection(text string) (bool, string)

ScanForInjection reports whether text appears to be addressing the agent, returning the phrase that tripped it.

func SessionListHeader added in v1.6.0

func SessionListHeader() string

SessionListHeader is the column header matching Describe.

func SettingsFileList added in v1.6.0

func SettingsFileList(appRoot string) []string

SettingsFileList reports where each scope's file lives and whether it exists, for the footer of the settings screen.

Types

type AIClient

type AIClient interface {
	Chat(ctx context.Context, prompt, model string, projCtx *ProjectContext) (string, error)
	GeneratePlan(ctx context.Context, prompt string, projCtx *ProjectContext, model string) (*PlanSummary, error)
	RegenerateStep(ctx context.Context, stepIndex int, newDesc string, currentPlan *PlanSummary, projCtx *ProjectContext, model string) (*PlanSummary, error)
	StreamExecute(ctx context.Context, prompt string, plan *PlanSummary, messages []Message, tools []ToolDefinition, projCtx *ProjectContext, onDelta StreamHandler) (*MessageResponse, error)
	// Turn runs a single agentic model turn. Implementations that cannot
	// support it must return ErrTurnUnsupported.
	Turn(ctx context.Context, req *TurnRequest, onDelta StreamHandler) (*MessageResponse, error)
}

AIClient is the interface for communicating with Nimbus Cloud AI backend.

func ResolveClient

func ResolveClient(serverURL, model string) (AIClient, error)

ResolveClient returns the appropriate AIClient. All intelligence is routed through nimbusgo.space.

type Agent

type Agent struct {
	Client    AIClient
	Tools     *ToolExecutor
	Context   *ProjectContext
	Session   *Session
	Model     string
	State     AgentState
	Callbacks AgentCallbacks

	// Verifier runs the project's build/tests after execution and returns
	// (output, ok). Defaults to a Go build when go.mod is present; tests
	// override it. Nil disables verification.
	Verifier func(ctx context.Context) (string, bool)
	// contains filtered or unexported fields
}

Agent manages the explore → plan → execute → verify flow.

func NewAgent

func NewAgent(client AIClient, tools *ToolExecutor, projCtx *ProjectContext, session *Session) *Agent

NewAgent creates a new Nimbus AI Agent.

func (*Agent) ApplySettings added in v1.6.0

func (a *Agent) ApplySettings(s Settings)

ApplySettings wires resolved settings into the agent and the pieces it owns.

One place does this so a setting cannot be half-applied — read by the screen that shows it but never reaching the code that acts on it, which is the usual way a configuration screen becomes a lie.

func (*Agent) Compact added in v1.6.0

func (a *Agent) Compact(ctx context.Context) (*CompactResult, error)

Compact summarises the older part of the conversation in place.

It asks the model for the summary, so it costs one turn; when that fails the conversation is left untouched and the caller decides what to do, rather than silently losing history to a fallback.

func (*Agent) ExecuteApprovedPlan

func (a *Agent) ExecuteApprovedPlan(ctx context.Context, plan *PlanSummary) (string, error)

ExecuteApprovedPlan executes the approved steps using tools, then verifies the result (build) and lets the model repair failures.

func (*Agent) GeneratePlan

func (a *Agent) GeneratePlan(ctx context.Context, userPrompt string) (*PlanSummary, error)

GeneratePlan investigates the codebase for the request, then produces a structured plan grounded in what it found. Conversational requests come back as a plan with zero steps whose Summary holds the answer.

func (*Agent) RegenerateStep

func (a *Agent) RegenerateStep(ctx context.Context, stepIndex int, newDescription string) (*PlanSummary, error)

RegenerateStep regenerates a modified step and any downstream steps.

func (*Agent) Run added in v1.6.0

func (a *Agent) Run(ctx context.Context, userMessage string) (*RunResult, error)

Run handles one user message in the session's ongoing conversation.

It appends the message to the persistent history, then loops: ask the model, run whatever tools it calls, feed the results back, and repeat until the model answers with no further tool calls. Nothing is gated on a plan, and no clarification round-trip is imposed — if the model needs to ask something it simply says so, and the user's reply is the next message in the same conversation.

func (*Agent) Settings added in v1.6.0

func (a *Agent) Settings() Settings

Settings returns the settings currently in force.

type AgentCallbacks

type AgentCallbacks struct {
	OnRequestSent        func()
	OnStreamDelta        func(delta string)
	OnStatus             func(text string)
	OnPlanGenerated      func(plan *PlanSummary)
	OnStepUpdate         func(step *PlanStep)
	OnDiffGenerated      func(filePath, diff string)
	OnToolCall           func(toolName string, args map[string]any)
	OnToolResult         func(toolName string, args map[string]any, output string, err error)
	OnExecutionCompleted func(summary string)
	// OnUsage reports the tokens a turn consumed and the session total.
	OnUsage func(turn *TokenUsage, session SessionUsage)
}

AgentCallbacks defines hooks for the TUI to render real-time progress.

type AgentState

type AgentState string

AgentState represents the state of the agent.

const (
	StateIdle      AgentState = "idle"
	StateExploring AgentState = "exploring"
	StatePlanning  AgentState = "planning"
	StateReviewing AgentState = "reviewing"
	StateExecuting AgentState = "executing"
	StateVerifying AgentState = "verifying"
	StateCompleted AgentState = "completed"
	StateFailed    AgentState = "failed"
)

type Assessment added in v1.6.0

type Assessment struct {
	Risk    CommandRisk
	Reason  string // shown in the approval prompt or the refusal
	Subject string // the command or path the verdict is about
}

Assessment is the verdict on one tool call.

type ClarificationQuestion

type ClarificationQuestion struct {
	ID       string   `json:"id"`
	Question string   `json:"question"`
	Options  []string `json:"options,omitempty"`
	Default  string   `json:"default,omitempty"`
	Selected string   `json:"selected,omitempty"`
}

ClarificationQuestion represents an interactive decision required from the user.

type CommandRisk added in v1.6.0

type CommandRisk int

CommandRisk is the outcome of classifying a command.

const (
	// RiskAllowed is an ordinary workspace command.
	RiskAllowed CommandRisk = iota
	// RiskAsk needs the user's approval before running.
	RiskAsk
	// RiskBlocked is never run.
	RiskBlocked
)

type CommandVerdict added in v1.6.0

type CommandVerdict struct {
	Risk    CommandRisk
	Command string // the offending segment
	Reason  string // human-readable, shown in the approval prompt
}

CommandVerdict explains a classification.

func ClassifyCommand added in v1.6.0

func ClassifyCommand(command string) CommandVerdict

ClassifyCommand decides whether a command may run unattended.

type CompactResult added in v1.6.0

type CompactResult struct {
	BeforeTokens int
	AfterTokens  int
	Summarised   int // messages replaced by the summary
}

CompactResult reports what compaction achieved.

func (CompactResult) Saved added in v1.6.0

func (r CompactResult) Saved() int

Saved is the estimated tokens reclaimed.

type ContentBlock

type ContentBlock struct {
	Type      string         `json:"type"` // "text" | "tool_use" | "tool_result"
	Text      string         `json:"text,omitempty"`
	ID        string         `json:"id,omitempty"`
	Name      string         `json:"name,omitempty"`
	Input     map[string]any `json:"input,omitempty"`
	ToolUseID string         `json:"tool_use_id,omitempty"`
	Content   string         `json:"content,omitempty"`
	IsError   bool           `json:"is_error,omitempty"`
}

ContentBlock represents a text or tool block.

type ContextUsage added in v1.6.0

type ContextUsage struct {
	Tokens int
	Limit  int
	// ThresholdPercent is how full the window gets before compaction runs.
	// Zero means the default, so a usage built by hand still behaves.
	ThresholdPercent int
}

ContextUsage describes how much of the window a conversation occupies.

func (ContextUsage) NeedsCompaction added in v1.6.0

func (u ContextUsage) NeedsCompaction() bool

NeedsCompaction reports whether the conversation has passed the threshold.

The comparison is in integers scaled by 100 rather than in floats: the threshold is a whole percentage from the settings screen, and this way it means exactly what it says at the boundary.

func (ContextUsage) Percent added in v1.6.0

func (u ContextUsage) Percent() int

Percent is how full the window is, 0–100.

func (ContextUsage) Remaining added in v1.6.0

func (u ContextUsage) Remaining() int

Remaining is the estimated room left, never negative.

func (ContextUsage) Threshold added in v1.6.0

func (u ContextUsage) Threshold() int

Threshold is the configured compaction point, as a percentage.

type GeneratedImage added in v1.6.0

type GeneratedImage struct {
	Data  []byte // decoded bytes, ready to write to disk
	Model string // the model that drew it
}

GeneratedImage is one image returned by Nimbus Cloud.

type Message

type Message struct {
	Role    string `json:"role"`    // "user" | "assistant" | "system"
	Content any    `json:"content"` // string or []ContentBlock
}

Message represents a chat message.

type MessageResponse

type MessageResponse struct {
	ID         string         `json:"id"`
	Model      string         `json:"model"`
	Role       string         `json:"role"`
	Content    []ContentBlock `json:"content"`
	StopReason string         `json:"stop_reason"`
	Usage      *TokenUsage    `json:"usage,omitempty"`
}

MessageResponse holds the response from the Nimbus Cloud AI.

func (*MessageResponse) TextContent

func (m *MessageResponse) TextContent() string

func (*MessageResponse) ToolUseBlocks

func (m *MessageResponse) ToolUseBlocks() []ContentBlock

type NimbusCloudClient

type NimbusCloudClient struct {
	ServerURL  string
	Token      string
	HTTPClient *http.Client

	// OnRetry is called before each retry so the UI can explain the pause
	// instead of appearing to hang. See retry.go.
	OnRetry retryNotifier
}

NimbusCloudClient connects the CLI to the intelligence engine hosted at nimbusgo.space.

func NewNimbusCloudClient

func NewNimbusCloudClient(serverURL string) (*NimbusCloudClient, error)

NewNimbusCloudClient initializes client using local authentication credentials.

func (*NimbusCloudClient) Chat

func (c *NimbusCloudClient) Chat(ctx context.Context, prompt, model string, projCtx *ProjectContext) (string, error)

Chat sends a conversational query or question to Nimbus Cloud AI with project context.

func (*NimbusCloudClient) GenerateImage added in v1.6.0

func (c *NimbusCloudClient) GenerateImage(ctx context.Context, prompt, size, model string) (*GeneratedImage, error)

GenerateImage asks Nimbus Cloud for an image.

The provider keys live on the server, so the CLI never talks to an image provider directly: it posts a prompt and receives bytes. Which model draws the picture is server-side configuration, and changing it does not require a new CLI.

func (*NimbusCloudClient) GeneratePlan

func (c *NimbusCloudClient) GeneratePlan(ctx context.Context, prompt string, projCtx *ProjectContext, model string) (*PlanSummary, error)

GeneratePlan calls POST /api/v1/ai/plan on Nimbus Cloud.

func (*NimbusCloudClient) RegenerateStep

func (c *NimbusCloudClient) RegenerateStep(ctx context.Context, stepIndex int, newDesc string, currentPlan *PlanSummary, projCtx *ProjectContext, model string) (*PlanSummary, error)

RegenerateStep calls POST /api/v1/ai/plan/regenerate on Nimbus Cloud.

func (*NimbusCloudClient) SetRetryHook added in v1.6.0

func (c *NimbusCloudClient) SetRetryHook(fn func(attempt int, reason string))

SetRetryHook implements RetryReporter.

func (*NimbusCloudClient) StreamExecute

func (c *NimbusCloudClient) StreamExecute(ctx context.Context, prompt string, plan *PlanSummary, messages []Message, tools []ToolDefinition, projCtx *ProjectContext, onDelta StreamHandler) (*MessageResponse, error)

StreamExecute streams step execution and tool guidance from Nimbus Cloud.

func (*NimbusCloudClient) Turn added in v1.5.4

Turn calls POST /api/v1/ai/turn: one agentic model turn with native tools.

type PermissionMode added in v1.6.0

type PermissionMode string

PermissionMode selects how much is decided without asking.

const (
	// PermissionAuto assesses each call and asks only about consequential ones.
	PermissionAuto PermissionMode = "auto"
	// PermissionAsk confirms anything that changes the workspace.
	PermissionAsk PermissionMode = "ask"
	// PermissionAllow runs whatever the policy does not refuse.
	PermissionAllow PermissionMode = "allow"
)

func ParsePermissionMode added in v1.6.0

func ParsePermissionMode(s string) PermissionMode

ParsePermissionMode reads a mode name, falling back to auto.

type PlanPhase

type PlanPhase struct {
	Name        string   `json:"name"`        // e.g. "Phase 1: Frontend User Interface"
	Description string   `json:"description"` // e.g. "Implement responsive Todo app view"
	Files       []string `json:"files"`       // e.g. ["resources/views/todo.html"]
}

PlanPhase groups architectural steps into logical stages.

type PlanStep

type PlanStep struct {
	ID          int    `json:"id"`
	Phase       string `json:"phase,omitempty"` // e.g. "Phase 1: Frontend UI"
	Action      string `json:"action"`          // "create_file" | "edit_file" | "run_command" | "delete_file" | "clarification_needed"
	Target      string `json:"target"`
	Description string `json:"description"`
	Content     string `json:"content,omitempty"`
	Risk        string `json:"risk"` // "low" | "medium" | "high"
	Approved    bool   `json:"approved"`
	Status      string `json:"status,omitempty"` // "pending" | "running" | "applied" | "failed"
	Error       string `json:"error,omitempty"`
}

PlanStep represents a single reviewable step in the execution plan.

type PlanSummary

type PlanSummary struct {
	Summary            string                  `json:"summary"`
	Overview           string                  `json:"overview,omitempty"`
	NeedsClarification bool                    `json:"needs_clarification,omitempty"`
	Questions          []ClarificationQuestion `json:"questions,omitempty"`
	Phases             []PlanPhase             `json:"phases,omitempty"`
	Steps              []PlanStep              `json:"steps"`
	Details            []string                `json:"details,omitempty"`
}

PlanSummary represents the structured plan generated in Plan Mode.

type ProjectContext

type ProjectContext struct {
	AppRoot        string   `json:"app_root"`
	ProjectName    string   `json:"project_name"`
	GoModName      string   `json:"go_mod_name,omitempty"`
	GoVersion      string   `json:"go_version,omitempty"`
	NimbusModules  []string `json:"nimbus_modules,omitempty"`
	NimbusJSON     string   `json:"nimbus_json,omitempty"`
	DirectoryTree  string   `json:"directory_tree"`
	GitBranch      string   `json:"git_branch,omitempty"`
	GitDiffSummary string   `json:"git_diff_summary,omitempty"`
	RootFiles      []string `json:"root_files,omitempty"`
	Models         []string `json:"models,omitempty"`
	Controllers    []string `json:"controllers,omitempty"`
	Migrations     []string `json:"migrations,omitempty"`
	RoutesSummary  string   `json:"routes_summary,omitempty"`
	Skills         []Skill  `json:"skills,omitempty"`
	// ActiveSkillFrame holds the most recently loaded skill so the server can
	// keep it in the system prompt rather than the message history.
	ActiveSkillFrame string `json:"active_skill_frame,omitempty"`
	// Instructions holds project-level guidance for the agent, read from
	// AGENTS.md / NIMBUS.md / CLAUDE.md / .nimbus/instructions.md. It is the
	// project's persistent memory: conventions, do's and don'ts, commands.
	Instructions string `json:"instructions,omitempty"`
	// InstructionFiles lists which instruction files were found.
	InstructionFiles []string `json:"instruction_files,omitempty"`
	// Stack summarises non-Go tooling detected (package.json, Vite, Tailwind…).
	Stack []string `json:"stack,omitempty"`
	// OS is the host operating system, so shell commands can be phrased correctly.
	OS string `json:"os,omitempty"`
}

ProjectContext contains scanned information about the current Nimbus project.

func ScanProject

func ScanProject(appRoot string) (*ProjectContext, error)

ScanProject scans the given project directory and constructs a ProjectContext.

func (*ProjectContext) FormatSystemContext

func (p *ProjectContext) FormatSystemContext() string

FormatSystemContext formats the ProjectContext into a rich markdown block for AI system prompts.

func (*ProjectContext) Refresh added in v1.5.4

func (p *ProjectContext) Refresh()

Refresh re-reads the cheap, fast-changing parts of the context (git state, directory tree, instructions) so later phases see files created earlier.

type RetryReporter added in v1.6.0

type RetryReporter interface {
	SetRetryHook(func(attempt int, reason string))
}

RetryReporter is implemented by clients that can announce transient retries, so the UI can explain a pause instead of looking frozen.

type RunResult added in v1.6.0

type RunResult struct {
	// Text is the assistant's final message.
	Text string
	// ChangedFiles lists paths written, edited or deleted during the turn.
	ChangedFiles []string
	// ToolCalls counts tool invocations made during the turn.
	ToolCalls int
	// Verified reports whether the project build was run and passed.
	Verified bool
}

RunResult is the outcome of one conversational turn.

type Session

type Session struct {
	ID           string            `json:"id"`
	CreatedAt    time.Time         `json:"created_at"`
	UpdatedAt    time.Time         `json:"updated_at"`
	InitialQuery string            `json:"initial_query"`
	Model        string            `json:"model"`
	Plan         *PlanSummary      `json:"plan,omitempty"`
	ApprovedPlan *PlanSummary      `json:"approved_plan,omitempty"`
	History      []Message         `json:"history"`
	AppliedSteps []int             `json:"applied_steps"`
	LoadedSkills map[string]string `json:"loaded_skills,omitempty"`
	Status       string            `json:"status"` // "planning" | "reviewing" | "executing" | "completed"
	// Findings is the exploration report produced for the current request.
	Findings string `json:"findings,omitempty"`
	// Turns is the conversation memory: one record per completed request,
	// carried into later prompts so follow-ups build on earlier work.
	Turns []TurnRecord `json:"turns,omitempty"`
	// Usage totals every model turn in this session, so a resumed session
	// keeps reporting what it has cost so far.
	Usage SessionUsage `json:"usage"`
	// ContextOverhead is the part of a request that Messages does not
	// account for — the system prompt, the tool schemas and the project
	// context — measured against what the server actually counted. See
	// RecordContextTokens.
	ContextOverhead int `json:"context_overhead,omitempty"`
	// Transcript is what the user saw, kept separately from Messages.
	//
	// Messages is the model's context: compaction rewrites it and pruning
	// drops from it, both of which are right for fitting a context window and
	// wrong for a record of the session. The transcript is append-only, so
	// reopening a session shows the conversation as it happened — including
	// the notices that never went to the model at all.
	Transcript []TranscriptEntry `json:"transcript,omitempty"`
	// Messages is the live conversation: user turns, assistant replies, tool
	// calls and tool results, in order. This is what the model actually sees,
	// and what makes "continue" mean something — it is saved with the session
	// and restored by --resume.
	Messages []Message `json:"messages,omitempty"`
	// contains filtered or unexported fields
}

Session represents an AI session stored on disk.

func LatestSession added in v1.6.0

func LatestSession(appRoot string) (*Session, error)

LatestSession returns the most recently updated session, or nil when the project has none.

func ListSessions

func ListSessions(appRoot string) ([]*Session, error)

ListSessions returns a list of recent sessions sorted newest first.

func LoadSession

func LoadSession(appRoot, sessionID string) (*Session, error)

LoadSession reads an existing session from disk.

func NewSession

func NewSession(model string) *Session

NewSession creates an empty initialized Session.

func (*Session) AppendAssistant added in v1.6.0

func (s *Session) AppendAssistant(content []ContentBlock)

AppendAssistant adds the assistant's reply, keeping its content blocks (text and tool_use) intact so the model sees its own tool calls.

func (*Session) AppendToolResults added in v1.6.0

func (s *Session) AppendToolResults(results []ContentBlock)

AppendToolResults adds the results of the assistant's tool calls. They are sent with the user role, which is how tool results are returned in this protocol.

func (*Session) AppendTranscript added in v1.6.0

func (s *Session) AppendTranscript(e TranscriptEntry)

AppendTranscript records a line of the session as the user saw it.

func (*Session) AppendUser added in v1.6.0

func (s *Session) AppendUser(text string)

AppendUser adds a user message to the conversation.

func (*Session) ContextUsage added in v1.6.0

func (s *Session) ContextUsage() ContextUsage

ContextUsage estimates how much of the window this session occupies.

func (*Session) ConversationSummary added in v1.5.4

func (s *Session) ConversationSummary() string

ConversationSummary renders recent turns for inclusion in prompts, so the model knows what was asked and done earlier in this session.

func (*Session) Describe added in v1.6.0

func (s *Session) Describe(now time.Time) string

Describe renders a session as one line for a picker or a listing: what was asked, how long ago, and how much work is in it.

The prompt is what identifies a session to the person who ran it — an id is only useful once you already know which one you want.

func (*Session) RecordContextTokens added in v1.6.0

func (s *Session) RecordContextTokens(inputTokens int)

RecordContextTokens calibrates the estimate against what the server counted.

EstimateTokens can only see s.Messages, but a request also carries the system prompt, every tool schema and the project context — none of it visible here, and easily thousands of tokens. The gap between the server's input count and the estimate for the messages that produced it is exactly that overhead, so recording it makes every later reading honest.

Keeping the overhead separate rather than caching the absolute count is what makes the number survive compaction: the message estimate drops immediately, the overhead does not, and the gauge is right before the next turn rather than after it.

func (*Session) RecordTurn added in v1.5.4

func (s *Session) RecordTurn(prompt, planSummary, outcome string, files []string)

RecordTurn appends a conversation-memory entry for a finished request.

func (*Session) SetLimits added in v1.6.0

func (s *Session) SetLimits(limitTokens, compactPercent int)

SetLimits applies the configured window and compaction point.

They are held on the session rather than read from a package-level global so that two agents in one process — a test suite, a future subagent — do not have to agree about them.

type SessionUsage added in v1.6.0

type SessionUsage struct {
	InputTokens  int     `json:"input_tokens"`
	OutputTokens int     `json:"output_tokens"`
	Requests     int     `json:"requests"`
	CostUSD      float64 `json:"cost_usd,omitempty"`
}

SessionUsage accumulates token spend across a session.

func (*SessionUsage) Add added in v1.6.0

func (u *SessionUsage) Add(t *TokenUsage)

Add folds one response's usage into the session total. Responses without usage still count as a request, so the request tally stays honest even against a server that does not report tokens.

func (SessionUsage) Reported added in v1.6.0

func (u SessionUsage) Reported() bool

Reported reports whether the server ever sent token counts.

func (SessionUsage) Summary added in v1.6.0

func (u SessionUsage) Summary() string

Summary renders the session's spend for humans, e.g. "18 requests · 42.1k tokens · $0.1240". Returns "" when nothing is known.

func (SessionUsage) Total added in v1.6.0

func (u SessionUsage) Total() int

Total returns all tokens seen in the session.

type SettingDef added in v1.6.0

type SettingDef struct {
	Key     string // the JSON key, and the name used by search
	Label   string // shown in the list
	Help    string // one line, shown for the highlighted row
	Kind    SettingKind
	Choices []string // SettingChoice
	Min     int      // SettingInt
	Max     int      // SettingInt
	Step    int      // SettingInt
	Env     string   // the variable that overrides it, if any
	// contains filtered or unexported fields
}

SettingDef describes one setting for the /settings screen.

The screen is generated from this list rather than written out row by row, so a setting added here appears in the list, in the search, and in the round-trip to disk without touching the view — the same reason the slash commands live in one registry.

func FindSetting added in v1.6.0

func FindSetting(key string) (SettingDef, bool)

FindSetting returns the definition for a key.

func (SettingDef) Display added in v1.6.0

func (d SettingDef) Display(s *Settings) string

Display renders the value the way the screen shows it.

func (SettingDef) Next added in v1.6.0

func (d SettingDef) Next(s *Settings, delta int)

Next advances the value: bools flip, choices cycle, numbers step. Negative delta goes the other way, which is what ←/→ do on a number.

Cycling rather than opening an editor is deliberate — every setting here has few enough sensible values that a list is faster than typing one, and there is no invalid state to validate.

func (SettingDef) Value added in v1.6.0

func (d SettingDef) Value(s *Settings) any

Value reads this setting out of a resolved Settings.

type SettingKind added in v1.6.0

type SettingKind int

SettingKind is how a value is presented and edited.

const (
	// SettingBool toggles between true and false.
	SettingBool SettingKind = iota
	// SettingChoice cycles through a fixed list.
	SettingChoice
	// SettingInt steps between a minimum and a maximum.
	SettingInt
)

type Settings added in v1.6.0

type Settings struct {
	// Model is the default model name, or "optimal" to let the server pick.
	Model string `json:"model"`
	// AutoCompact summarises the conversation automatically as it fills.
	AutoCompact bool `json:"auto_compact"`
	// ContextLimit is the assumed context window in tokens.
	ContextLimit int `json:"context_limit"`
	// CompactThresholdPercent is how full the window gets before compaction.
	CompactThresholdPercent int `json:"compact_threshold_percent"`
	// PermissionMode decides how much runs without being confirmed.
	PermissionMode string `json:"permission_mode"`
	// VerifyBuilds runs the project's build after a turn changes code, and
	// hands failures back to the model to repair.
	VerifyBuilds bool `json:"verify_builds"`
	// ExpandDiffs shows full diffs in the transcript rather than a summary.
	ExpandDiffs bool `json:"expand_diffs"`
	// ShowThinking shows the "Thought for Xs" line between turns.
	ShowThinking bool `json:"show_thinking"`
	// StreamOutput prints the reply as it arrives rather than when complete.
	StreamOutput bool `json:"stream_output"`
	// MaxCommandOutput caps the bytes of a command's output fed back.
	MaxCommandOutput int `json:"max_command_output"`
	// PlanFirst routes every request through plan → approve → execute.
	PlanFirst bool `json:"plan_first"`

	// MCPServers is carried through untouched for the MCP client to read.
	// It is declared here so the raw-JSON round trip keeps it, and is not in
	// the registry: a server list is edited as JSON, not toggled in a list.
	MCPServers map[string]json.RawMessage `json:"mcp_servers,omitempty"`
}

Settings is the resolved configuration for a run.

Every field is also described in the registry below, which is what /settings renders; a field added here without an entry there is invisible to the user.

func DefaultSettings added in v1.6.0

func DefaultSettings() Settings

DefaultSettings is the configuration before any file or variable is read.

func LoadSettings added in v1.6.0

func LoadSettings(appRoot string) Settings

LoadSettings resolves the settings for a project.

Nothing here fails: a malformed or unreadable file is skipped rather than stopping the CLI from starting, because the alternative is a typo in a settings file making the tool unusable.

type SettingsScope added in v1.6.0

type SettingsScope string

SettingsScope is one layer of the settings stack.

const (
	// ScopeUser applies to every project, from ~/.nimbus/settings.json.
	ScopeUser SettingsScope = "user"
	// ScopeProject is committed with the repo.
	ScopeProject SettingsScope = "project"
	// ScopeLocal is this checkout only, and belongs in .gitignore.
	ScopeLocal SettingsScope = "local"
	// ScopeEnv is an environment variable. It cannot be written.
	ScopeEnv SettingsScope = "env"
	// ScopeDefault means nothing has set it.
	ScopeDefault SettingsScope = "default"
)

func SettingSource added in v1.6.0

func SettingSource(appRoot, key string) SettingsScope

SettingSource reports which layer decides a key's value, so the screen can explain why a setting is not what the user thought they set.

This is the question a flat list cannot answer: "I set that to false, why is it true?" is almost always a project file overriding a user file.

type Skill

type Skill struct {
	Name        string `json:"name"`
	Description string `json:"description"`
	Path        string `json:"path"`
	Source      string `json:"source"` // "project" | "global" | "embedded"
}

Skill represents a lightweight index entry for an agent skill.

func LoadSkills

func LoadSkills(appRoot string) ([]Skill, error)

LoadSkills discovers and builds a lightweight index of skills (name + description only).

type StreamHandler

type StreamHandler func(delta string)

StreamHandler receives streaming delta chunks.

type TokenUsage added in v1.6.0

type TokenUsage struct {
	InputTokens  int `json:"input_tokens"`
	OutputTokens int `json:"output_tokens"`
	// CostUSD is what the turn cost, when the server prices it. The CLI does
	// not price locally: the server picks the model behind "optimal", so a
	// client-side guess would put a wrong number against real money.
	CostUSD float64 `json:"cost_usd,omitempty"`
}

TokenUsage reports what a request consumed. It is populated when the server sends a "usage" field (JSON) or a usage SSE event; older servers omit it and the CLI simply reports no usage rather than guessing.

func (*TokenUsage) Total added in v1.6.0

func (u *TokenUsage) Total() int

Total returns all tokens billed for the request.

type ToolDefinition

type ToolDefinition struct {
	Name        string         `json:"name"`
	Description string         `json:"description"`
	InputSchema map[string]any `json:"input_schema"`
}

ToolDefinition describes a tool schema exposed to the AI agent.

type ToolExecutor

type ToolExecutor struct {
	AppRoot string
	// CommandTimeout bounds a single bash invocation.
	CommandTimeout time.Duration

	// ApproveCommand is consulted before running a command the policy flags
	// as consequential (see command_policy.go). Returning false refuses the
	// command; the model reads the refusal and can choose another route.
	//
	// Nil means no one can be asked: interactive callers must set it, and
	// headless callers set AutoApprove instead. Leaving both unset fails
	// closed, so a non-interactive run cannot silently `sudo` its way out of
	// a problem.
	ApproveCommand func(cmd, reason string) bool

	// AutoApprove runs flagged commands without asking (nimbus ai --yes).
	AutoApprove bool

	// MaxCommandOutput caps the bytes of a command's output handed back to
	// the model. Zero means the built-in cap, so a ToolExecutor built without
	// settings is still bounded.
	MaxCommandOutput int

	// GenerateImage draws an image through Nimbus Cloud. The CLI holds no
	// provider keys, so this is injected by the command that owns the cloud
	// client. Nil means the tool is not offered to the model at all, rather
	// than offered and failing when called.
	GenerateImage func(ctx context.Context, prompt, size, model string) ([]byte, string, error)
	// contains filtered or unexported fields
}

ToolExecutor executes agent tool requests.

func NewToolExecutor

func NewToolExecutor(appRoot string) *ToolExecutor

NewToolExecutor creates a tool executor sandboxed to appRoot.

func (*ToolExecutor) AssessToolCall added in v1.6.0

func (t *ToolExecutor) AssessToolCall(name string, args map[string]any) Assessment

AssessToolCall judges one tool call before it runs.

func (*ToolExecutor) Authorize added in v1.6.0

func (t *ToolExecutor) Authorize(name string, args map[string]any) error

Authorize runs the assessment and obtains consent when one is needed.

func (*ToolExecutor) Bash

func (t *ToolExecutor) Bash(ctx context.Context, commandStr string) (string, error)

Bash runs a shell command and returns its combined output. A failing command is not an error at the tool level: the failure text is returned so the model can read and act on it.

func (*ToolExecutor) ClearTaint added in v1.6.0

func (t *ToolExecutor) ClearTaint()

ClearTaint forgets the warning, once the user has decided about it.

func (*ToolExecutor) CreateImage added in v1.6.0

func (t *ToolExecutor) CreateImage(ctx context.Context, prompt, relPath, size string) (string, error)

CreateImage draws an image through Nimbus Cloud and writes it into the workspace, returning a one-line report for the model.

The path goes through the same resolution as any write, so a generated image cannot land outside the project.

func (*ToolExecutor) DeleteFile

func (t *ToolExecutor) DeleteFile(relPath string) (string, string, error)

func (*ToolExecutor) EditFile

func (t *ToolExecutor) EditFile(relPath, target, replacement string) (string, string, error)

EditFile replaces a unique target substring.

func (*ToolExecutor) EditFileAll added in v1.5.4

func (t *ToolExecutor) EditFileAll(relPath, target, replacement string, replaceAll bool) (string, string, error)

EditFileAll replaces the target substring; with replaceAll every occurrence is replaced, otherwise the target must be unique.

func (*ToolExecutor) ExecuteTool

func (t *ToolExecutor) ExecuteTool(ctx context.Context, name string, args map[string]any) (output string, diff string, err error)

func (*ToolExecutor) FetchURL added in v1.6.0

func (t *ToolExecutor) FetchURL(ctx context.Context, rawURL, format string) (string, error)

FetchURL retrieves a page and returns it as readable text, or as raw markup when format is "html".

func (*ToolExecutor) FindFiles added in v1.5.4

func (t *ToolExecutor) FindFiles(pattern, relPath string) (string, error)

FindFiles returns workspace-relative paths matching a glob pattern.

func (*ToolExecutor) GetToolDefinitions

func (t *ToolExecutor) GetToolDefinitions() []ToolDefinition

func (*ToolExecutor) Grep

func (t *ToolExecutor) Grep(pattern, relPath string) (string, error)

Grep searches file contents with a regex (no include filter).

func (*ToolExecutor) GrepFiltered added in v1.5.4

func (t *ToolExecutor) GrepFiltered(pattern, relPath, include string) (string, error)

GrepFiltered searches file contents, optionally restricted to files whose name matches the include glob.

func (*ToolExecutor) ListDir

func (t *ToolExecutor) ListDir(relPath string) (string, error)

ListDir lists a single directory level.

func (*ToolExecutor) ListDirDepth added in v1.5.4

func (t *ToolExecutor) ListDirDepth(relPath string, depth int) (string, error)

ListDirDepth lists a directory up to depth levels deep (1-3).

func (*ToolExecutor) LoadSkill

func (t *ToolExecutor) LoadSkill(skillName string) (string, error)

LoadSkill loads the full content and documentation of a skill by name on demand.

func (*ToolExecutor) PermissionMode added in v1.6.0

func (t *ToolExecutor) PermissionMode() PermissionMode

PermissionMode reports the active mode, defaulting to auto.

func (*ToolExecutor) QuerySkill added in v1.5.4

func (t *ToolExecutor) QuerySkill(skillName, query string) (string, error)

QuerySkill reads specific sections or topics from a skill to keep context lightweight.

func (*ToolExecutor) ReadFile

func (t *ToolExecutor) ReadFile(relPath string) (string, error)

ReadFile reads a whole file (subject to size limits).

A file that has already been read in this conversation, and has not changed since, comes back as a one-line reminder instead of its full contents. An agent investigating a codebase re-reads the same files often — the earlier output is still in the conversation, and sending it again wastes the context it would need to finish the work.

func (*ToolExecutor) ReadFileRange added in v1.5.4

func (t *ToolExecutor) ReadFileRange(relPath string, startLine, endLine int) (string, error)

ReadFileRange reads a file, optionally restricted to a 1-based inclusive line range. Oversized reads are truncated with a hint to use ranges.

func (*ToolExecutor) ReadOnlyToolDefinitions added in v1.5.4

func (t *ToolExecutor) ReadOnlyToolDefinitions() []ToolDefinition

ReadOnlyToolDefinitions returns the tools that inspect the workspace without changing files. Used for the exploration and planning phases.

func (*ToolExecutor) ReadSkill

func (t *ToolExecutor) ReadSkill(name string) (string, error)

ReadSkill is an alias for LoadSkill.

func (*ToolExecutor) RunCommand added in v1.5.4

func (t *ToolExecutor) RunCommand(ctx context.Context, commandStr string) (string, bool)

RunCommand runs a command and reports whether it exited successfully.

func (*ToolExecutor) SetPermissionMode added in v1.6.0

func (t *ToolExecutor) SetPermissionMode(mode PermissionMode)

ExecuteTool runs the requested tool and returns output string and optional diff string. SetPermissionMode selects how much runs without asking.

func (*ToolExecutor) Tainted added in v1.6.0

func (t *ToolExecutor) Tainted() (bool, string, string)

Tainted reports whether untrusted content has tried to give instructions, and what it said.

func (*ToolExecutor) WriteFile

func (t *ToolExecutor) WriteFile(relPath, newContent string) (string, string, error)

type TranscriptEntry added in v1.6.0

type TranscriptEntry struct {
	Role      string            `json:"role"`
	Content   string            `json:"content,omitempty"`
	ToolName  string            `json:"tool_name,omitempty"`
	ToolArgs  map[string]string `json:"tool_args,omitempty"`
	Detail    string            `json:"detail,omitempty"`
	Diff      string            `json:"diff,omitempty"`
	IsError   bool              `json:"is_error,omitempty"`
	ElapsedMS int64             `json:"elapsed_ms,omitempty"`
	At        time.Time         `json:"at"`
}

TranscriptEntry is one line of the session as it was displayed.

type TurnMode added in v1.5.4

type TurnMode string

TurnMode selects the server-side system prompt for an agent turn.

const (
	// TurnModeAgent is the default: one continuous conversation in which the
	// model decides whether to answer, investigate, or change code. The other
	// modes drive the older staged pipeline, still used by --plan-only.
	TurnModeAgent   TurnMode = "agent"
	TurnModeExplore TurnMode = "explore"
	TurnModePlan    TurnMode = "plan"
	TurnModeExecute TurnMode = "execute"
	TurnModeChat    TurnMode = "chat"
)

type TurnRecord added in v1.5.4

type TurnRecord struct {
	At           time.Time `json:"at"`
	Prompt       string    `json:"prompt"`
	PlanSummary  string    `json:"plan_summary,omitempty"`
	Outcome      string    `json:"outcome,omitempty"`
	FilesChanged []string  `json:"files_changed,omitempty"`
}

TurnRecord summarises one completed request/response cycle.

type TurnRequest added in v1.5.4

type TurnRequest struct {
	Mode     TurnMode
	Model    string
	Prompt   string // the user's original request
	Messages []Message
	Tools    []ToolDefinition
	Plan     *PlanSummary
	Context  *ProjectContext
}

TurnRequest is one model turn of the agent loop: the server composes the system prompt for Mode from the project context and returns text and/or tool calls; the CLI executes tools locally and calls again.

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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