diff --git a/CHANGELOG.md b/CHANGELOG.md index fe336d935..d187613ce 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ All notable changes to this project will be documented in this file. +## [Unreleased] + +## What's New + +- Adds `settings.lean: true` user config option (`~/.config/cagent/config.yaml`) to make the lean TUI the default interface for all interactive runs, without needing to pass `--lean` each time + +### Pull Requests + +- [#3181](https://github.com/docker/docker-agent/pull/3181) - feat(tui): add lean user config setting + ## [v1.83.0] - 2026-06-19 This release adds an opt-in sudo askpass flow for shell commands, a headless embedded chat session API, and several bug fixes for cost accounting, session handling, and custom provider model resolution. diff --git a/docs/guides/go-sdk/index.md b/docs/guides/go-sdk/index.md index 9f3afbf14..6ac81e40b 100644 --- a/docs/guides/go-sdk/index.md +++ b/docs/guides/go-sdk/index.md @@ -31,6 +31,7 @@ docker-agent can be used as a Go library, allowing you to build AI agents direct | `pkg/model/provider/*` | Model provider clients | | `pkg/config/latest` | Configuration types | | `pkg/environment` | Environment and secrets | +| `pkg/embeddedchat` | Headless chat session for embedding the agent runtime in a custom UI | | `pkg/tui/components/toolconfirm` | Tool-confirmation policy: `Decision` enum, `BuildPermissionPattern`, key bindings, and rejection-reason presets. Share this instead of copying the permission-pattern logic. | | `pkg/tui/service` | `StaticSessionState` — a `SessionStateReader` with conservative fixed values, for rendering message/tool views outside the full TUI app. Replaces hand-rolled nine-method stubs. | | `pkg/tui/animation` | `Stopper` / `StopView` — animation lifecycle contract. Call `StopAnimation` on views removed from the UI to prevent leaked tick subscriptions. | @@ -45,6 +46,128 @@ When building custom UIs on top of docker-agent's TUI primitives, four packages - **`pkg/tui/animation`** — implement `animation.Stopper` on any view that owns a tick-based animation. Call `StopAnimation` whenever a view is removed from the UI hierarchy to prevent leaked `time.Tick` subscriptions from firing against a dead view. - **`pkg/tui/components/transcript`** — embed the transcript view for displaying conversation history. Use the `Messages()` method to read the current slice of transcript messages (treat as read-only — mutations desync renders). This is useful for host-side tests asserting on chat history, and for persistence layers that need to snapshot conversation state. +## Headless Embedded Chat (`pkg/embeddedchat`) + +`pkg/embeddedchat` is a thin wrapper around the docker-agent runtime that lets you drive an agent from your own UI instead of running docker-agent's Bubble Tea application. It handles runtime construction, event projection, and conversation state, exposing a simple `Send` / `Confirm` / `Restart` / `Close` API. + +### Creating a session + +```go +import ( + "context" + "fmt" + "strings" + + dagentcfg "github.com/docker/docker-agent/pkg/config" + dagentruntime "github.com/docker/docker-agent/pkg/runtime" + "github.com/docker/docker-agent/pkg/embeddedchat" +) + +chat, err := embeddedchat.New(ctx, embeddedchat.Config{ + // AgentSource can be a file path, raw YAML bytes, or an OCI reference. + AgentSource: dagentcfg.NewBytesSource("agent", []byte(agentYAML)), +}) +if err != nil { + return err +} +defer chat.Close() +``` + +### Sending a message and reading events + +`Send` appends the user message to the conversation and returns a channel of `Event` values. Drain the channel until it closes. + +```go +events, err := chat.Send(ctx, "Hello! What can you do?") +if err != nil { + return err +} + +var response strings.Builder +for ev := range events { + switch { + case ev.Text != "": + response.WriteString(ev.Text) + case ev.Tool != nil && ev.Tool.NeedsConfirmation: + // Approve the pending tool call (use ResumeApproveSession to allow all). + if err := chat.Confirm(ctx, dagentruntime.ResumeApprove()); err != nil { + return err + } + case ev.Tool != nil && ev.Tool.Finished: + fmt.Printf("[tool %s finished]\n", ev.Tool.Def.Name) + case ev.Err != nil: + fmt.Printf("error: %v\n", ev.Err) + case ev.Done: + fmt.Println("\n[turn complete]") + } +} +fmt.Print(response.String()) +``` + +### Restarting the conversation + +To start a fresh conversation without recreating the runtime: + +```go +if err := chat.Restart(); err != nil { + return err +} +``` + +### Event types + +| Field | When set | +| -------------- | ------------------------------------------------------------------------ | +| `Text` | Assistant text delta; accumulate into a string for the full reply. | +| `Tool` | A tool call started, needs confirmation, or finished. | +| `Tool.NeedsConfirmation` | Runtime is blocked until `Confirm` is called. | +| `Tool.Finished` | Tool call completed; `Tool.IsError` is true if it errored. | +| `Err` | A user-facing runtime error; no further content events follow. | +| `Done` | Clean end of turn; no more events. | +| `RuntimeEvent` | The original `runtime.Event` for callers that need the full stream. | + +For advanced use (custom elicitation, raw event inspection), call `chat.Runtime()` to access the underlying `runtime.Runtime` directly. + +## Optional Provider Build Tags + +By default docker-agent includes all four cloud providers (OpenAI, Anthropic, Google, Amazon Bedrock). When embedding docker-agent in your own binary you can compile out unneeded providers — together with their transitive SDK dependencies — to reduce binary size. + +Each provider is gated by a negative build tag prefixed `docker_agent_` to avoid collisions with your own project's tags: + +| Build tag | Provider dropped | Major dependency removed | +| ---------------------------- | ------------------------ | ------------------------------------------------- | +| `docker_agent_no_openai` | OpenAI | `github.com/openai/openai-go` | +| `docker_agent_no_anthropic` | Anthropic | `github.com/anthropics/anthropic-sdk-go` (partial — see note) | +| `docker_agent_no_google` | Google / Vertex AI | `google.golang.org/genai`, Vertex auth stack, and indirectly the Anthropic and OpenAI SDKs via Vertex Model Garden | +| `docker_agent_no_bedrock` | Amazon Bedrock | `github.com/aws/aws-sdk-go-v2` stack (the largest provider dependency tree) | + +To build without Bedrock and OpenAI: + +```bash +go build -tags 'docker_agent_no_bedrock docker_agent_no_openai' ./... +``` + +Requesting a model whose provider was compiled out fails at construction time with a clear `"not compiled into this build"` error. The `dmr` (Docker Model Runner) provider and the rule-based router are always compiled in. + +
The Google provider's Vertex Model Garden support also imports the Anthropic SDK, so the Anthropic dependency is only fully removed when both docker_agent_no_anthropic and docker_agent_no_google are set.
Every string effort value on Anthropic is sent as adaptive thinking (output_config.effort), which only newer Claude models (Opus 4.6+) accept. For older models like Sonnet 4.5, use an integer token budget instead. Conversely, models that only support adaptive thinking (Opus 4.6, 4.7, 4.8) automatically have token budgets coerced to adaptive (a warning is logged).
Every string effort value on Anthropic is sent as adaptive thinking (output_config.effort), which only newer Claude models (Opus 4.6+, Sonnet 4.6) accept. For older models like Sonnet 4.5, use an integer token budget instead. Conversely, models that only support adaptive thinking (Opus 4.6, 4.7, 4.8, Sonnet 4.6) automatically have token budgets coerced to adaptive (a warning is logged).