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
13 changes: 11 additions & 2 deletions docs/features/cli/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ $ docker agent run [config] [message...] [flags]
| `--record [path]` | Record AI API interactions to a cassette file (auto-generates filename if no path given) |
| `-d, --debug` | Enable debug logging |
| `--log-file <path>` | Custom debug log location |
| `-o, --otel` | Enable OpenTelemetry tracing |
| `-o, --otel` | Enable OpenTelemetry observability: traces, metrics, and logs. Requires `OTEL_EXPORTER_OTLP_ENDPOINT` to export to a collector. |

```bash
# Examples
Expand Down Expand Up @@ -521,12 +521,21 @@ These flags are available on every `docker agent` command:
| ------------------------- | -------------------------------------------------------------------------------------- |
| `-d, --debug` | Enable debug logging (default location: `~/.cagent/cagent.debug.log`) |
| `--log-file <path>` | Custom debug log location (only used with `--debug`) |
| `-o, --otel` | Enable OpenTelemetry tracing |
| `-o, --otel` | Enable OpenTelemetry observability: traces, metrics, and logs. Requires `OTEL_EXPORTER_OTLP_ENDPOINT` to export to a collector. |
| `--cache-dir <path>` | Override the cache directory (default: `~/Library/Caches/cagent` on macOS) |
| `--config-dir <path>` | Override the config directory (default: `~/.config/cagent`) |
| `--data-dir <path>` | Override the data directory (default: `~/.cagent`) |
| `--help` | Show help for any command |

### OpenTelemetry environment variables

When `--otel` is enabled, the standard [OTel SDK env vars](https://opentelemetry.io/docs/specs/otel/configuration/sdk-environment-variables/) are honored (`OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_RESOURCE_ATTRIBUTES`, etc.). Two additional docker-agent-specific variables control GenAI instrumentation:

| Variable | Default | Description |
| -------- | ------- | ----------- |
| `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` | `false` | Set to `true` to capture prompt text, model responses, tool arguments, and tool results as span attributes. Off by default because these fields may contain PII. |
| `OTEL_SEMCONV_STABILITY_OPT_IN` | (dual-emit) | Set to `gen_ai_latest_experimental` to emit only the spec-defined `gen_ai.*` keys from the [GenAI semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/). The default dual-emit mode emits both `gen_ai.*` and legacy keys so existing dashboards continue working. |

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.

[HIGH] Incorrect OTEL_SEMCONV_STABILITY_OPT_IN value: gen_ai_latest_experimental is not a recognized OTel opt-in token

The documented value gen_ai_latest_experimental does not appear in the OpenTelemetry specification or the go.opentelemetry.io/contrib instrumentation libraries. The recognized values for OTEL_SEMCONV_STABILITY_OPT_IN in the GenAI semconv ecosystem are:

  • gen_ai — emit only the stable, spec-defined gen_ai.* keys (opt into the new semconv exclusively)
  • gen_ai_experimental — used in some pre-stable contrib packages for experimental attributes

If a user follows this documentation and sets OTEL_SEMCONV_STABILITY_OPT_IN=gen_ai_latest_experimental, the SDK will treat it as an unrecognized value and silently remain in dual-emit mode — the opposite of the documented behavior. Users trying to reduce cardinality or migrate away from legacy keys will be misled.

Suggested fix: Change gen_ai_latest_experimental to gen_ai (or gen_ai_experimental if this refers to pre-stable attributes). If this project's OTel instrumentation layer defines a custom value, add a note explaining that.


## Runtime Configuration Flags

These flags are accepted by every command that loads an agent (`run`, `run --exec`, `new`, `eval`, `serve api`, `serve mcp`, `serve a2a`, `serve acp`, `serve chat`). They are listed once here to avoid repetition in the per-command tables above.
Expand Down
1 change: 1 addition & 0 deletions docs/features/remote-mcp/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,7 @@ A per-toolset `callbackRedirectURL` (in the YAML) overrides the runtime-wide `--
| Service | URL | Transport | Description |
| ---------- | ------------------------------------------------- | ---------- | --------------------------------- |
| Canva | `https://mcp.canva.com/mcp` | streamable | Design and graphics platform |
| Miro | `https://mcp.miro.com/` | streamable | Collaborative whiteboard platform (Enterprise plan required; see [official docs](https://developers.miro.com/docs/miro-mcp)) |
| Cloudinary | `https://asset-management.mcp.cloudinary.com/sse` | sse | Media management and optimization |
| InVideo | `https://mcp.invideo.io/sse` | sse | Video creation platform |
| Webflow | `https://mcp.webflow.com/sse` | sse | Website builder and CMS |
Expand Down
43 changes: 38 additions & 5 deletions docs/guides/go-sdk/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -154,19 +154,52 @@ Requesting a model whose provider was compiled out fails at construction time wi
<p>The Google provider's Vertex Model Garden support also imports the Anthropic SDK, so the Anthropic dependency is only fully removed when <em>both</em> <code>docker_agent_no_anthropic</code> and <code>docker_agent_no_google</code> are set.</p>
</div>

## RAG Toolset (cgo-free builds)
## RAG Toolset (opt-out)

The RAG toolset (`type: rag`) uses a tree-sitter code parser that requires cgo. When building without cgo — or when you want to drop the cgo dependency entirely — do not import the `pkg/rag` package in your binary.
The RAG toolset (`type: rag`) is included in `NewDefaultToolsetRegistry()` (from `pkg/teamloader/toolsets`) and `loaderdefaults.Opts()` (from `pkg/teamloader/defaults`, using the conventional import alias `loaderdefaults`).

By default the RAG toolset is **opt-in**: it is only linked when you blank-import its package:
The underlying tree-sitter code parser uses cgo, but build-tag guards in `pkg/rag/treesitter` mean importing the package is safe regardless of `CGO_ENABLED`: with `CGO_ENABLED=0` the parser stub compiles in and returns a runtime error on first use rather than failing at compile time.

If you want to exclude the RAG toolset from your binary entirely — surfacing a load-time warning on the agent rather than a deferred runtime error from the `!cgo` stub — remove it from the registry before passing it to `teamloader.Load`:

```go
import (
_ "github.com/docker/docker-agent/pkg/tools/builtin/rag" // register RAG toolset
"github.com/docker/docker-agent/pkg/teamloader"
loadertoolsets "github.com/docker/docker-agent/pkg/teamloader/toolsets"
)

// Opt out of the RAG toolset; a config that declares type: rag attaches
// a load-time warning to the agent instead of failing at document processing.
creators := loadertoolsets.DefaultToolsetCreators()

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.

[MEDIUM] Go code snippet uses := outside a function body — invalid Go syntax

The snippet shows:

import (
    "github.com/docker/docker-agent/pkg/teamloader"
    loadertoolsets "github.com/docker/docker-agent/pkg/teamloader/toolsets"
)

creators := loadertoolsets.DefaultToolsetCreators()
delete(creators, "rag")
registry := teamloader.NewToolsetRegistry(creators)

In Go, short variable declarations (:=) are only valid inside function bodies. At package scope only var declarations are allowed. As written, this snippet will not compile if copied into a Go source file.

This is inconsistent with the keyringstore.Register() snippet immediately below it in the same file, which is correctly wrapped in func main() { ... }.

Suggested fix: Wrap the statements in a function scope, e.g.:

import (
    "github.com/docker/docker-agent/pkg/teamloader"
    loadertoolsets "github.com/docker/docker-agent/pkg/teamloader/toolsets"
)

func main() {
    creators := loadertoolsets.DefaultToolsetCreators()
    delete(creators, "rag")
    registry := teamloader.NewToolsetRegistry(creators)
    // Pass to teamloader.Load via teamloader.WithToolsetRegistry(registry)
}

delete(creators, "rag")
registry := teamloader.NewToolsetRegistry(creators)
```

Without this import, a config that declares `type: rag` fails with a "toolset type not registered" error at startup. If your application does not use RAG, simply omit the blank import; the rest of docker-agent works without cgo.
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.

## 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.

Call `keyringstore.Register()` **before** any MCP toolset is initialised to enable the OS keyring-backed token store:

```go
import "github.com/docker/docker-agent/pkg/tools/mcp/keyringstore"

func main() {
// Must be called before teamloader.Load() on configs with remote MCP
// toolsets; calling it after the store is created panics.
keyringstore.Register()
// ... rest of your startup code
}
```

<div class="callout callout-warning" markdown="1">
<div class="callout-title">Call order matters</div>
<p>If <code>keyringstore.Register()</code> is called after the default token store has already been lazily initialised, docker-agent panics. The store is initialised when any remote MCP toolset is constructed — which happens inside <code>teamloader.Load()</code>. Always call <code>keyringstore.Register()</code> before calling <code>teamloader.Load()</code> on a config that includes remote MCP toolsets.</p>
</div>

If you do not need persistent OAuth tokens (for example, in short-lived batch jobs or tests), omit the call and tokens will be kept in-memory for the process lifetime.

## Basic Example

Expand Down
Loading