text

package
v1.11.3 Latest Latest
Warning

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

Go to latest
Published: Oct 8, 2026 License: MIT Imports: 62 Imported by: 0

Documentation

Index

Constants

View Source
const DefaultHandoverInstructions = "You are approaching the context window limit. Summarize your work and prepare for handover."

DefaultHandoverInstructions is the user message injected into the chat when the token stoploss limit is crossed and no custom message is configured.

Variables

View Source
var Default = Configurations{
	Model:                  "gpt-5.2",
	SystemPrompt:           "You are an assistant for a CLI tool. Answer concisely and informatively. Prefer markdown if possible.",
	Raw:                    false,
	UseTools:               false,
	ToolOutputRuneLimit:    21600,
	SaveReplyAsConv:        true,
	UseLookback:            false,
	SummarizeConversations: true,

	Stoploss: &Stoploss{
		MaxTokens:            0,
		MaxTokensHandoverMsg: DefaultHandoverInstructions,
	},

	CmdModePrompt: "You are an assistant for a CLI tool aiding with cli tool suggestions. Write ONLY the command and nothing else. Disregard any queries asking for anything except a bash command. Do not shell escape single or double quotes.",
}
View Source
var DefaultProfile = Profile{

	Name:            "",
	Model:           Default.Model,
	UseTools:        true,
	UseSkills:       nil,
	Tools:           []string{},
	Prompt:          Default.SystemPrompt,
	SaveReplyAsConv: new(true),
}

Functions

func AppendShellContextIfConfigured

func AppendShellContextIfConfigured(ctx context.Context, configDir, shellContextName, prompt string, r ShellContextRenderer) (string, error)

AppendShellContextIfConfigured inserts the rendered shell context block into prompt.

Insertion rule:

  • if rendered is non-empty: "<shell context>\n" + rendered + "\n</shell context>\n" + <original-prompt-with-leading-whitespace-trimmed>

func ApplyFlagOverrides added in v1.11.0

func ApplyFlagOverrides(tConf *Configurations, tf internal.TextFlags)

ApplyFlagOverrides applies the CLI flag values onto the file-loaded configuration.

The default flags are needed to ensure that the configuration isn't being overwritten by the default flags. Meaning: Only set the value of tConf to the flag, if it's not the default, leave the configuration found in file. If there is no check if the flagSet is default, there may be a case where default > file, which breaks the configuration convention flags > file > default

func ApplyProfileOverrides added in v1.11.0

func ApplyProfileOverrides(tConf *Configurations, tf internal.TextFlags)

ApplyProfileOverrides re-applies the flags that may overrule profile configurations.

func CanonicalModelString added in v1.10.13

func CanonicalModelString(vendor, family, modelVersion string) string

CanonicalModelString is the inverse of vendorType. Given a (vendor, family, modelVersion) triplet — typically parsed from a config filename — it returns the canonical model identifier that can be placed in a profile's "model" field and correctly routed.

func CreateQuerier added in v1.11.0

func CreateQuerier(ctx context.Context, conf Configurations) (models.Querier, error)

CreateQuerier by checking the model for which vendor to use, then initiating a TextQuerier

func MigrateOldChatConfig added in v1.11.0

func MigrateOldChatConfig(configDirPath string) error

MigrateOldChatConfig by first checking if file chatConfig exists, then reading + copying the fields to the new text.Configrations struct. Then write the file as textConfig. For the remaining fields, create vendor specific gpt4TurboPreview struct and write that to gpt4TurboPreview.json.

func QueryCommand added in v1.11.0

func QueryCommand(deps QueryCommandDeps) *internal.Command

QueryCommand builds the query command.

Types

type AgentSettings added in v1.10.23

type AgentSettings struct {
	Logger           *slog.Logger
	Level            slog.Level
	RuneLimit        int
	UsageRecorder    pub_models.CallUsageRecorder
	ToolCallRecorder pub_models.ToolCallRecorder
	// StrictMcpStartup marks the servers in Configurations.McpServers as
	// explicitly requested and load-bearing: a startup failure fails the whole
	// setup with a typed error instead of warn-and-degrade. pkg/agent sets it
	// when WithMcpServers was used; the CLI path never sets it (worklog
	// 2026-09-05-error-propagation, D13).
	StrictMcpStartup bool
}

AgentSettings carries agent-only runtime settings into the querier. It is never serialized to textConfig.json; a nil Logger or recorder disables that channel (worklog 2026-08-15-agent-slog-output, D7).

type CallUsageRecorder added in v1.10.4

type CallUsageRecorder = pub_models.CallUsageRecorder

The recorder types are canonical in pkg/text/models (worklog 26-08-11-clai-prometheus-metrics). The aliases keep internal references unchanged while exposing the seam to embedded consumers through the public package.

type CompletedModelCall added in v1.10.4

type CompletedModelCall = pub_models.CompletedModelCall

The recorder types are canonical in pkg/text/models (worklog 26-08-11-clai-prometheus-metrics). The aliases keep internal references unchanged while exposing the seam to embedded consumers through the public package.

type Configurations

type Configurations struct {
	Model        string `json:"model"`
	SystemPrompt string `json:"system-prompt"`
	Raw          bool   `json:"raw"`
	UseTools     bool   `json:"use-tools"`
	UseSkills    bool   `json:"-"`
	// CmdModePrompt is kept only for backwards compatibility with old config files.
	// It is ignored by clai as the `cmd` command has been removed.
	CmdModePrompt string `json:"cmd-mode-prompt"`
	// ToolOutputRuneLimit limits the amount of runes a tool may return
	// before clai truncates the output. Zero means no limit.
	ToolOutputRuneLimit int    `json:"tool-output-rune-limit"`
	SaveReplyAsConv     bool   `json:"save-reply-as-prompt"`
	ConfigDir           string `json:"-"`
	StdinReplace        string `json:"-"`
	Stream              bool   `json:"-"`
	ReplyMode           bool   `json:"-"`
	// DirReplyMode marks a directory-scoped reply (-dre). Unlike a plain -re (which
	// forks a fresh promoted id and must not record), -dre continues the bound
	// conversation in place, so it DOES upsert the directory history (see finalizer).
	DirReplyMode        bool            `json:"-"`
	Glob                string          `json:"-"`
	InitialChat         pub_models.Chat `json:"-"`
	UseProfile          string          `json:"-"`
	ProfilePath         string          `json:"-"`
	ProfileUseSkillsSet bool            `json:"-"`
	RequestedToolGlobs  []string        `json:"-"`
	// CmdBan is the per-run command ban list for the freetext command tools
	// (cmd, async_cmd; legacy aliases freetext_command, async_cmd_run).
	// Commands matching an entry are
	// refused before spawn (worklog 2026-08-02-cmd-ban-list). The cascade is
	// purely additive: textConfig.json + profile cmd-ban + flag -cmd-ban +
	// agent API; no source removes another source's bans.
	CmdBan []string `json:"cmd-ban"`
	// SummarizeConversations launches the in-flight conversation summarizer
	// on a conversation's first persist (worklog
	// 2026-09-09-conversation-summaries, D12).
	SummarizeConversations bool `json:"summarize-conversations"`
	// SummaryModel is the model the conversation summarizer uses; empty means
	// the resolution ladder (D22). The migrate tag surfaces the empty key in
	// upgraded files, so it must never carry omitempty.
	SummaryModel string `json:"summary-model" migrate:"true"`
	// SummaryJoinTimeout bounds the finalizer's wait for the in-flight
	// summary; zero means defaultSummaryJoinTimeout.
	SummaryJoinTimeout time.Duration `json:"-"`
	// CostWarnf receives the cost manager's and the cost enricher's
	// warnings; nil keeps ancli.Warnf. A querier whose output is discarded
	// routes them to its own trace (worklog
	// 2026-09-09-conversation-summaries, R2-03).
	CostWarnf func(format string, a ...any) `json:"-"`
	// ErrOut replaces the process stderr for the querier's MCP log sink; nil
	// keeps os.Stderr. A querier that may outlive its caller (the abandoned
	// in-flight summarizer) must never read the global stream (R2-09).
	ErrOut io.Writer `json:"-"`
	// TrustInput is the trusted input reader the composition root threads
	// through setup (the same reader skills.TrustPrompter reads from); the
	// authorization phase's printed-URL fallback reads a pasted
	// authorization code from it rather than the process standard input
	// directly (worklog 2026-10-02-mcp-connection-cost, phase 5). Nil
	// disables the paste fallback for the run.
	TrustInput io.Reader `json:"-"`
	// ShellContext is a context definition name for ASC (auto-append shell context).
	// When non-empty, clai will load <configDir>/shellContexts/<name>.json and insert
	// the rendered template block into the system prompt instead of the user prompt.
	ShellContext string `json:"-"`
	// PostProccessedPrompt which has had it\'s strings replaced etc
	PostProccessedPrompt string `json:"-"`

	// These are to allow tools to be injected via public package.
	Tools      []pub_models.LLMTool   `json:"-"`
	McpServers []pub_models.McpServer `json:"-"`
	// SkipAmbientMcpServers skips discovery of <configDir>/mcpServers/*.json;
	// servers passed in McpServers still start and keep their explicit or
	// ambient posture (worklog 2026-09-09-conversation-summaries, D18).
	SkipAmbientMcpServers bool                          `json:"-"`
	BaseTools             map[string]pub_models.LLMTool `json:"-"`
	RegisteredTools       map[string]struct{}           `json:"-"`
	MaxToolCalls          *int                          `json:"max-tool-calls,omitempty"`
	// Stoploss is the token stoploss policy for the run. Nil or
	// MaxTokens <= 0 disables the stoploss (no handover injection).
	Stoploss *Stoploss `json:"stoploss,omitempty"`

	// AgentSettings carries agent-only runtime settings (slog logger, level,
	// rune cap, recorder hooks) from pkg/agent into the querier. json:"-"
	// keeps it out of textConfig.json and the presence-based config merge
	// (worklog 2026-08-15-agent-slog-output, D7).
	AgentSettings *AgentSettings `json:"-"`

	// Out writer. Normally stdout, but may also be a file when invoked as a package
	Out io.Writer `json:"-"`

	// ResponseFormat configures structured output (json_object, json_schema).
	// When nil, no response_format is sent (defaults to text).
	ResponseFormat   *pub_models.ResponseFormat `json:"-"`
	SkillsDescriptor string                     `json:"-"`
	SkillLoader      SkillLoader                `json:"-"`

	// UseLookback gates the opt-in conversation lookback: the recent-conversations
	// descriptor plus the search/inspect/read tools. Resolved as
	// CLI (-lb/-lookback boolean) > profile (use_lookback) > default (false), and is only
	// effectively true when the CWD binding has recorded history.
	UseLookback bool `json:"use_lookback"`
	// LookbackDescriptor is the dir-scoped recent-conversations block injected into
	// the system prompt when the lookback is active.
	LookbackDescriptor string `json:"-"`
	// LookbackCWD is the canonical session working directory captured at setup,
	// used as the default search anchor for search_conversations.
	LookbackCWD string `json:"-"`
	// OutputIsTerminal decides the auth-timeout parameter's
	// terminal-dependent default: a mid-run authorization wait is bounded
	// when the session's output is a terminal, fail-fast otherwise, unless
	// a server's auth_timeout_seconds overrides it either way (worklog
	// 2026-10-02-mcp-connection-cost, phase 6, D22). nil means unset:
	// NewQuerier then derives it from the querier's own terminal check and
	// assigns it, without overwriting a caller-supplied value (R2-09). A
	// caller that cannot observe its own terminal-ness (every pkg/agent SDK
	// consumer, whose writer is always io.Discard) sets this explicitly
	// through pkg/agent.WithOutputIsTerminal instead of relying on the
	// writer-derived default.
	OutputIsTerminal *bool `json:"-"`
}

Configurations used to setup the requirements of text models

func SetupQuerier added in v1.11.0

func SetupQuerier(ctx context.Context, confDir string, tf internal.TextFlags, args []string, trustInput io.Reader) (models.Querier, *Configurations, error)

SetupQuerier composes the full text-querier path: config load, flag and profile cascades, glob/tool/skill/lookback setup, prompt construction and vendor routing. trustInput is the reader for interactive skill-trust prompts (the composition root passes the wizard's input source; text cannot import setup).

func (*Configurations) LoadResponseFormat added in v1.10.9

func (c *Configurations) LoadResponseFormat(path string) error

LoadResponseFormat loads a response_format JSON file from disk and sets it on the configuration. The file must follow the response_format shape. This layer is vendor-agnostic: when a vendor can explain a rejection better it does so through generic.ErrorHandler (see the -rf call site).

func (Configurations) OutputIsTerminalOrDefault added in v1.11.2

func (c Configurations) OutputIsTerminalOrDefault() bool

OutputIsTerminalOrDefault resolves OutputIsTerminal: the explicit value when set, false (the conservative, fail-fast posture) when unset.

func (*Configurations) ProfileOverrides

func (c *Configurations) ProfileOverrides() error

func (*Configurations) SetupInitialChat

func (c *Configurations) SetupInitialChat(args []string) error

SetupInitialChat by doing all sorts of organically grown stuff. Don\'t touch this code too closely. Something will break, most likely.

func (Configurations) UsingProfile

func (c Configurations) UsingProfile() bool

type CostManager added in v1.10.4

type CostManager interface {
	// Start the cost manager. Will return with errors on errCh and close readyCh once there is
	// a token price for the model
	Start(ctx context.Context) (readyCh <-chan struct{}, errCh <-chan error)

	// Enrich the chat with cost for the chat
	Enrich(chat pub_models.Chat) (pub_models.Chat, error)
}

type LoadedSkillRuntime added in v1.10.10

type LoadedSkillRuntime struct {
	Name            string
	SourceClass     string
	RenderedBody    string
	UserVisibleBody string
	Description     string
	Warnings        []string
	EnabledTools    []string
	ActiveTools     map[string]pub_models.LLMTool
	ActivationErr   string
	RawArgs         string
}

type ModelNamer added in v1.10.4

type ModelNamer interface {
	ModelName() string
}

type ModelStepResult added in v1.10.4

type ModelStepResult struct {
	AssistantText string
	ToolCalls     []pub_models.Call
	Usage         *pub_models.Usage
	StopRequested bool
	EndedNormally bool
}

type Profile

type Profile struct {
	Name      string   `json:"name"`
	Model     string   `json:"model"`
	UseTools  bool     `json:"use_tools"`
	UseSkills *bool    `json:"use_skills,omitempty"`
	Tools     []string `json:"tools"`
	// CmdBan merges onto the file base in ProfileOverrides. An omitted or
	// explicitly empty list contributes nothing (purely additive cascade,
	// worklog 2026-08-02-cmd-ban-list R1-04 revision).
	CmdBan          []string                        `json:"cmd-ban,omitempty"`
	Prompt          string                          `json:"prompt"`
	SaveReplyAsConv *bool                           `json:"save-reply-as-conv,omitempty"`
	McpServers      map[string]pub_models.McpServer `json:"mcp_servers,omitempty"`
	ShellContext    string                          `json:"shell_context,omitempty"`
	UseLookback     *bool                           `json:"use_lookback,omitempty"`
}

Profile which allows for specialized ai configurations for specific tasks

type Querier

type Querier[C models.StreamCompleter] struct {
	Raw bool

	Model C
	// contains filtered or unexported fields
}

func NewQuerier

func NewQuerier[C models.StreamCompleter](ctx context.Context, userConf Configurations, dfault C) (Querier[C], error)

func (*Querier[C]) Query

func (q *Querier[C]) Query(ctx context.Context) error

Query using the underlying model to stream completions and then print the output from the model to stdout. Blocking operation.

func (*Querier[C]) SetChatID added in v1.10.6

func (q *Querier[C]) SetChatID(chatID string)

func (*Querier[C]) SetSummarizer added in v1.11.1

func (q *Querier[C]) SetSummarizer(s models.Summarizer)

SetSummarizer attaches the in-flight conversation summarizer.

func (*Querier[C]) SuppressCompletionNotification added in v1.10.19

func (q *Querier[C]) SuppressCompletionNotification() bool

func (*Querier[C]) TextQuery

func (q *Querier[C]) TextQuery(ctx context.Context, chat pub_models.Chat) (pub_models.Chat, error)

type QueryCommandDeps added in v1.11.0

type QueryCommandDeps struct {
	ConfigPrep func() (confDir string, err error)
	TrustInput func() io.Reader
	// ApplyMediaOverrides hands the media-tool flags to the domains owning
	// those tools (internal/audio today), which text must not import.
	ApplyMediaOverrides func(internal.MediaToolFlags) error
	// NewSummarizer builds the in-flight conversation summarizer; nil or a
	// constructor error attaches nothing (worklog
	// 2026-09-09-conversation-summaries, D26).
	NewSummarizer func(confDir string) (models.Summarizer, error)
}

QueryCommandDeps are the composition-root collaborators the query command needs: config prep lives in internal/setup (which imports text, so text cannot call it), and TrustInput hands over the wizard's mutable input reader for skill-trust prompts, read at setup time.

type QuerySession added in v1.10.4

type QuerySession struct {
	Chat               pub_models.Chat
	StartedAt          time.Time
	FinishedAt         time.Time
	PendingText        strings.Builder
	PendingReasoning   strings.Builder
	FinalAssistantText string
	FinalReasoningText string
	FinalUsage         *pub_models.Usage
	CompletedCalls     []CompletedModelCall
	ToolCallsUsed      int
	// PostHandoverToolCallsUsed counts tool calls made after the token
	// stoploss handover fired. It is the phase counter for the
	// max-tool-calls-after-handover wrap-up budget: the handover starts a
	// fresh allowance that pre-handover consumption never eats into.
	PostHandoverToolCallsUsed int
	// HandoverRequested is set once the token stoploss has injected the
	// handover user message. It switches the tool-budget phase: the
	// wrap-up allowance (max-tool-calls-after-handover) replaces the
	// pre-handover max-tool-calls budget.
	HandoverRequested   bool
	ShouldSaveReply     bool
	Raw                 bool
	Finalized           bool
	Failed              bool
	SawAnyText          bool
	SawStopEvent        bool
	LikelyGeminiPreview bool
	Line                string
	LineCount           int
}

func (*QuerySession) AppendPendingText added in v1.10.4

func (s *QuerySession) AppendPendingText(token string)

func (*QuerySession) FlushPendingTextToFinal added in v1.10.4

func (s *QuerySession) FlushPendingTextToFinal()

func (*QuerySession) PendingTextString added in v1.10.4

func (s *QuerySession) PendingTextString() string

func (*QuerySession) ResetPendingText added in v1.10.4

func (s *QuerySession) ResetPendingText()

type ShellContextDefinition

type ShellContextDefinition struct {
	Shell         string            `json:"shell"`
	TimeoutMS     int               `json:"timeout_ms"`
	TimedOutValue string            `json:"timed_out_value"`
	ErrorValue    string            `json:"error_value"`
	Template      string            `json:"template"`
	Vars          map[string]string `json:"vars"`
}

func LoadShellContextDefinition

func LoadShellContextDefinition(configDir, name string) (ShellContextDefinition, error)

LoadShellContextDefinition reads <configDir>/shellContexts/<name>.json.

Templates written by older setup editors carry literal "\n" sequences (architecture/shell-context.md, "Newline encoding"): rehydrate them here so both encodings render identically. Var commands are never rehydrated, since a shell command may legitimately contain literal backslash escapes.

type ShellContextRenderer

type ShellContextRenderer struct {
	RunVar func(ctx context.Context, shell, cmd string, timeout time.Duration) (string, error)
	Warnf  func(format string, args ...any)
}

func (ShellContextRenderer) Render

type SkillLoader added in v1.10.10

type SkillLoader interface {
	LoadSkill(context.Context, string, string, map[string]pub_models.LLMTool) (LoadedSkillRuntime, error)
}

type Stoploss added in v1.10.20

type Stoploss struct {
	MaxTokens                 int    `json:"max-tokens"`
	MaxTokensHandoverMsg      string `json:"max-tokens-handover-instructions"`
	MaxToolCallsAfterHandover int    `json:"max-tool-calls-after-handover" migrate:"true"`
}

Stoploss is the token stoploss policy. MaxTokens <= 0 disables the stoploss. MaxTokensHandoverMsg is the user message injected into the chat when the limit is crossed; empty means the default message (DefaultHandoverInstructions). MaxToolCallsAfterHandover is the wrap-up tool-call budget for the post-handover phase: <= 0 (or absent) means unlimited tool calls after the handover fires. It carries migrate:"true" so the presence-based config migration surfaces it in upgraded files as an explicit 0 (and never omitempty, or the rewrite would drop the zero).

func (*Stoploss) HandoverInstructions added in v1.10.20

func (s *Stoploss) HandoverInstructions() string

HandoverInstructions returns the message to inject when the stoploss limit is crossed: the configured message, or DefaultHandoverInstructions when the configured message is empty.

type ToolCall added in v1.10.22

type ToolCall = pub_models.ToolCall

The recorder types are canonical in pkg/text/models (worklog 26-08-11-clai-prometheus-metrics). The aliases keep internal references unchanged while exposing the seam to embedded consumers through the public package.

type ToolCallRecorder added in v1.10.22

type ToolCallRecorder = pub_models.ToolCallRecorder

The recorder types are canonical in pkg/text/models (worklog 26-08-11-clai-prometheus-metrics). The aliases keep internal references unchanged while exposing the seam to embedded consumers through the public package.

type ToolDecision added in v1.10.4

type ToolDecision struct {
	PatchedCall         pub_models.Call
	SkipExecution       bool
	TreatAsReturnToUser bool
}

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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