Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 37 additions & 0 deletions docs/features/api-server/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ All endpoints are under the `/api` prefix.
| `DELETE` | `/api/sessions/:id` | Delete a session |
| `PATCH` | `/api/sessions/:id/title` | Update session title |
| `PATCH` | `/api/sessions/:id/permissions` | Update session permissions |
| `POST` | `/api/sessions/:id/fork` | Fork a session at a user message — creates a new session with messages `[0, message_index)` of the parent (see [Session Forking](#session-forking)) |
| `POST` | `/api/sessions/:id/resume` | Resume a paused session (after tool confirmation) |
| `POST` | `/api/sessions/:id/tools/toggle` | Toggle auto-approve (YOLO) mode |
| `POST` | `/api/sessions/:id/elicitation` | Respond to an MCP tool elicitation request |
Expand Down Expand Up @@ -179,6 +180,13 @@ docker agent serve api <agent-file>|<agents-dir> [flags]
| `--record` | (none) | Record AI API interactions to cassette file |
| `--mcp-oauth-redirect-uri` | (none) | Public HTTPS URL advertised as the OAuth `redirect_uri` for unmanaged MCP OAuth flows. When set, docker-agent drives PKCE and code exchange in-process and sends the full authorize URL to the client via elicitation. See [Remote MCP]({{ '/features/remote-mcp/' | relative_url }}) for details. |

<div class="callout callout-tip" markdown="1">
<div class="callout-title">Live profiling (advanced)
</div>
<p>For production diagnostics, set the <code>CAGENT_PPROF_ADDR</code> environment variable (or the hidden <code>--pprof-addr</code> flag) to a TCP address such as <code>127.0.0.1:6060</code>. docker-agent will start a Go pprof HTTP server at <code>/debug/pprof/</code>, which you can query with <code>go tool pprof</code>. Use a loopback address — a non-loopback binding logs a security warning. This flag is intentionally hidden from <code>--help</code>.</p>

</div>

<div class="callout callout-tip" markdown="1">
<div class="callout-title">Multi-agent configs
</div>
Expand Down Expand Up @@ -293,6 +301,35 @@ runtime is attached and ready to accept follow-ups, then return its status, or
`503` on timeout. This is session-scoped, unlike `GET /api/ready`, which fires
as soon as any session is ready.

## Session Forking

`POST /api/sessions/:id/fork` creates a new session whose history is a copy of the parent up to (but **excluding**) a specified user message. This lets a client "branch" a conversation — e.g. rewind to an earlier question and try a different prompt — without losing the shared history that came before.

**Request body:**

```json
{ "message_index": 2 }
```

`message_index` is a **0-based index** into the flat, user-visible message list (the same shape `GET /api/sessions/:id` returns in `messages`). The fork includes messages `[0, message_index)` — the message at `message_index` is **excluded**, so clients can prefill it into their chat input for the user to edit and resubmit.

**Example:**

```bash
# Fork a session before message index 4 (the user message the user wants to rewrite)
$ curl -X POST http://localhost:8080/api/sessions/$SID/fork \
-H 'Content-Type: application/json' \
-d '{"message_index": 4}'
# Returns: api.SessionResponse for the new forked session
# New session title: "<parent title> (fork 1)", "(fork 2)", etc.
```

**Validation:**

- `message_index` must point to a **user-role message**; pointing at an assistant turn returns `400 Bad Request`.
- Out-of-range indices return `400 Bad Request`.
- An index that falls inside a sub-session returns `400 Bad Request`. A sub-session is a nested session created when a multi-agent config delegates work to a child agent; its messages are embedded within the parent session's message list and cannot be used as a fork boundary.

## Idempotent follow-ups

`POST /api/sessions/:id/followup` accepts an optional `Idempotency-Key`
Expand Down
2 changes: 2 additions & 0 deletions docs/features/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -219,6 +219,8 @@ $ docker agent serve api <agent-file>|<agents-dir>|<registry-ref> [flags]
| `--record [path]` | (none) | Record AI API interactions to a cassette file. |
| `--mcp-oauth-redirect-uri <url>` | (none) | OAuth redirect URI for the unmanaged MCP OAuth flow in server mode. When set, the runtime drives PKCE and code exchange in-process and sends the full authorize URL to the client via elicitation. See [Remote MCP]({{ '/features/remote-mcp/' | relative_url }}) for details. |

> **Diagnostics:** Set `CAGENT_PPROF_ADDR=127.0.0.1:6060` (or `--pprof-addr`, a hidden flag) to start a live Go pprof server at `/debug/pprof/`. Use a loopback address; a non-loopback binding logs a security warning.

All [runtime configuration flags](#runtime-configuration-flags) (`--working-dir`, `--env-from-file`, `--models-gateway`, `--hook-*`, …) are also accepted.

```bash
Expand Down
40 changes: 40 additions & 0 deletions docs/guides/go-sdk/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,46 @@ registry := teamloader.NewToolsetRegistry(creators)

Pass the custom registry via `teamloader.WithToolsetRegistry(registry)` when calling `teamloader.Load`. Note that `teamloader.Load()` does not return an error for unknown toolset types — the failure is recorded as a load-time warning and can be retrieved with `agent.DrainWarnings()`; it is also surfaced via logging and TUI notifications.

## Registering Custom Built-in Themes

When embedding docker-agent, you can contribute your own built-in themes via `styles.RegisterBuiltinThemes`. Registered themes integrate seamlessly with the existing theme picker, `/theme` command, and `settings.theme` config key — they behave exactly like docker-agent's own bundled themes.

```go
import (
"embed"

"github.com/docker/docker-agent/pkg/tui/styles"
)

//go:embed themes/*.yaml
var brandThemes embed.FS

// Call at startup, before applying any persisted theme:
if err := styles.RegisterBuiltinThemes(brandThemes); err != nil {
return err
}
```

Each theme file lives at `themes/<name>.yaml` inside the embedded filesystem and is a **partial override** — only the colors you want to change are required; everything else falls back to `DefaultTheme()`.

```yaml
# themes/brand.yaml
name: Brand

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[LOW] Theme YAML example omits name field and undocumented fallback behavior

The themes/brand.yaml snippet (line 203–206) shows only colors.accent and colors.background — the name: key is absent. While the code silently falls back to the filename stem (i.e. "brand") when name: is missing, this behaviour is not mentioned anywhere in the new section.

Suggested addition after the YAML block:

If name: is omitted, docker-agent uses the filename stem (e.g. brand from themes/brand.yaml) as the display name in the theme picker.

Without this note, embedders who rely on an exact human-readable label in the picker may be surprised.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in dc53ff1. Added a sentence after the YAML block: "If name: is omitted, docker-agent uses the filename stem as the display name in the theme picker (e.g. brand from themes/brand.yaml)."

colors:
accent: "#FF6A00"
background: "#1A0F0A"
```

If `name:` is omitted, docker-agent uses the filename stem as the display name in the theme picker (e.g. `brand` from `themes/brand.yaml`).

To replace docker-agent's default theme entirely, ship the file as `themes/default.yaml` — it masks the bundled default while inheriting any colors you don't set.

**Semantics:**

- Registered sources take precedence over bundled themes; a registered ref overrides a bundled theme of the same name.
- Among multiple registered sources, last-registered wins on a collision.
- `RegisterBuiltinThemes` validates eagerly (nil fs, missing `themes/` dir) so errors surface at registration time, not at picker time.

## MCP OAuth Token Persistence

By default, MCP OAuth tokens are stored in-memory only and are not persisted across process restarts. The CLI registers a keyring-backed store automatically at startup; when embedding docker-agent as a library you must do this yourself if you want tokens to survive restarts.
Expand Down
2 changes: 2 additions & 0 deletions docs/providers/dmr/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ _Run AI models locally with Docker — no API keys, no costs, full data privacy.

Docker Model Runner (DMR) lets you run open-source AI models directly on your machine. Models run in Docker, so there's no API key needed and no data leaves your computer.

docker-agent automatically discovers models you have already pulled from DMR. When no model is explicitly configured, auto-selection prefers a locally-installed model (choosing the model specified via the `model:` key in the agent YAML if it is already pulled locally, or otherwise the first available non-embedding model) rather than always defaulting to `ai/qwen3:latest` and triggering a pull prompt.

<div class="callout callout-tip" markdown="1">
<div class="callout-title">No API key needed
</div>
Expand Down
Loading