From ee53f4ba9d670d0d1420ac6b592fa230fb88b636 Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Mon, 24 Aug 2026 08:37:45 +0000 Subject: [PATCH 1/3] docs: move Docker Agent reference docs upstream Docker Docs mounted 107 low-traffic Docker Agent pages that duplicated the project's own documentation and competed in search and retrieval. Remove the Hugo mount and sync workflow, retain a curated overview and Sandboxes integration, and redirect stale URLs to the upstream documentation. --- .github/workflows/sync-docker-agent-docs.yml | 130 --- .../docker-agent/docs/community/_index.md | 5 - .../docs/community/contributing/index.md | 131 --- .../docs/community/opentelemetry/index.md | 99 -- .../docs/community/telemetry/index.md | 79 -- .../docs/community/troubleshooting/index.md | 342 ------- .../docker-agent/docs/concepts/_index.md | 5 - .../docs/concepts/agents/index.md | 114 --- .../docs/concepts/distribution/index.md | 135 --- .../docs/concepts/models/index.md | 175 ---- .../docs/concepts/multi-agent/index.md | 421 -------- .../docker-agent/docs/concepts/tools/index.md | 78 -- .../docker-agent/docs/configuration/_index.md | 5 - .../docs/configuration/agents/index.md | 618 ------------ .../docs/configuration/agentsignore/index.md | 105 -- .../docs/configuration/budget/index.md | 217 ---- .../docs/configuration/commands/index.md | 218 ---- .../docs/configuration/flavors/index.md | 172 ---- .../docs/configuration/hcl/index.md | 306 ------ .../docs/configuration/hooks/index.md | 952 ------------------ .../docs/configuration/models/index.md | 639 ------------ .../docs/configuration/overview/index.md | 537 ---------- .../docs/configuration/permissions/index.md | 314 ------ .../docs/configuration/routing/index.md | 170 ---- .../docs/configuration/sandbox/index.md | 286 ------ .../configuration/structured-output/index.md | 250 ----- .../docs/configuration/tools/index.md | 518 ---------- .../docs/configuration/user-settings/index.md | 134 --- .../docker/docker-agent/docs/demo.gif | Bin 568044 -> 0 bytes .../docker-agent/docs/features/_index.md | 5 - .../docker-agent/docs/features/a2a/index.md | 106 -- .../docker-agent/docs/features/acp/index.md | 117 --- .../docs/features/api-server/index.md | 394 -------- .../docker-agent/docs/features/board/index.md | 97 -- .../docs/features/chat-server/index.md | 255 ----- .../docker-agent/docs/features/cli/index.md | 840 ---------------- .../docs/features/code-mode/index.md | 66 -- .../docs/features/evaluation/index.md | 311 ------ .../docs/features/harnesses/index.md | 287 ------ .../docs/features/mcp-mode/index.md | 134 --- .../docs/features/remote-mcp/index.md | 308 ------ .../docs/features/sessions/index.md | 135 --- .../docs/features/skills/index.md | 378 ------- .../docs/features/snapshots/index.md | 112 --- .../docker-agent/docs/features/tui/index.md | 591 ----------- .../docs/getting-started/_index.md | 5 - .../getting-started/installation/index.md | 150 --- .../getting-started/introduction/index.md | 74 -- .../docs/getting-started/quickstart/index.md | 156 --- .../getting-started/set-up-a-model/index.md | 276 ----- .../docker/docker-agent/docs/guides/_index.md | 5 - .../docs/guides/compaction/index.md | 149 --- .../docker-agent/docs/guides/go-sdk/index.md | 650 ------------ .../docs/guides/headless/index.md | 225 ----- .../docker-agent/docs/guides/secrets/index.md | 247 ----- .../docs/guides/thinking/index.md | 363 ------- .../docker-agent/docs/guides/tips/index.md | 477 --------- .../docker-agent/docs/providers/_index.md | 5 - .../docs/providers/anthropic/index.md | 241 ----- .../docs/providers/baseten/index.md | 91 -- .../docs/providers/bedrock/index.md | 175 ---- .../docs/providers/cerebras/index.md | 103 -- .../docs/providers/chatgpt/index.md | 128 --- .../providers/cloudflare-ai-gateway/index.md | 115 --- .../providers/cloudflare-workers-ai/index.md | 91 -- .../docs/providers/custom/index.md | 315 ------ .../docs/providers/deepseek/index.md | 96 -- .../docker-agent/docs/providers/dmr/index.md | 253 ----- .../docs/providers/fireworks/index.md | 102 -- .../docs/providers/github-copilot/index.md | 161 --- .../docs/providers/google/index.md | 174 ---- .../docker-agent/docs/providers/groq/index.md | 99 -- .../docs/providers/huggingface/index.md | 101 -- .../docs/providers/local/index.md | 223 ---- .../docs/providers/minimax/index.md | 92 -- .../docs/providers/mistral/index.md | 106 -- .../docs/providers/moonshot/index.md | 97 -- .../docs/providers/nebius/index.md | 90 -- .../docs/providers/nvidia/index.md | 115 --- .../docs/providers/openai/index.md | 138 --- .../docs/providers/opencode-go/index.md | 160 --- .../docs/providers/opencode-zen/index.md | 224 ----- .../docs/providers/openrouter/index.md | 88 -- .../docs/providers/overview/index.md | 104 -- .../docs/providers/ovhcloud/index.md | 108 -- .../docs/providers/together/index.md | 101 -- .../docs/providers/vercel/index.md | 109 -- .../docker-agent/docs/providers/xai/index.md | 99 -- .../docker/docker-agent/docs/tools/_index.md | 5 - .../docker-agent/docs/tools/a2a/index.md | 43 - .../docker-agent/docs/tools/api/index.md | 252 ----- .../docs/tools/background-agents/index.md | 120 --- .../docs/tools/background-jobs/index.md | 89 -- .../docker-agent/docs/tools/fetch/index.md | 173 ---- .../docs/tools/filesystem/index.md | 145 --- .../docker-agent/docs/tools/git/index.md | 100 -- .../docker-agent/docs/tools/handoff/index.md | 63 -- .../docker-agent/docs/tools/lsp/index.md | 227 ----- .../docs/tools/mcp-catalog/index.md | 113 --- .../docker-agent/docs/tools/mcp/index.md | 309 ------ .../docker-agent/docs/tools/memory/index.md | 59 -- .../docs/tools/model-picker/index.md | 73 -- .../docker-agent/docs/tools/open-url/index.md | 95 -- .../docker-agent/docs/tools/openapi/index.md | 83 -- .../docker-agent/docs/tools/plan/index.md | 166 --- .../docker-agent/docs/tools/rag/index.md | 267 ----- .../docs/tools/scheduler/index.md | 96 -- .../docker-agent/docs/tools/script/index.md | 64 -- .../docs/tools/session_context/index.md | 67 -- .../docs/tools/session_plan/index.md | 134 --- .../docker-agent/docs/tools/shell/index.md | 117 --- .../docker-agent/docs/tools/tasks/index.md | 59 -- .../docker-agent/docs/tools/think/index.md | 30 - .../docker-agent/docs/tools/todo/index.md | 54 - .../docs/tools/transfer-task/index.md | 73 -- .../docs/tools/user-prompt/index.md | 186 ---- .../docker-agent/docs/tools/webhook/index.md | 143 --- _vendor/modules.txt | 1 - content/manuals/ai/docker-agent/_index.md | 154 +-- .../ai/sandboxes/agents/docker-agent.md | 2 +- content/manuals/dhi/tools/mcp.md | 2 +- data/docker_agent_redirects.yml | 126 +++ go.mod | 2 - hack/releaser/cloudfront-lambda-redirects.js | 8 +- .../cloudfront-lambda-redirects.test.js | 47 + hack/releaser/redirects-prefixes.json | 5 + hugo.yaml | 35 - layouts/home.redirects.json | 9 + 128 files changed, 208 insertions(+), 21760 deletions(-) delete mode 100644 .github/workflows/sync-docker-agent-docs.yml delete mode 100644 _vendor/github.com/docker/docker-agent/docs/community/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/community/contributing/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/community/opentelemetry/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/community/telemetry/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/community/troubleshooting/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/agents/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/distribution/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/models/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/multi-agent/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/concepts/tools/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/agents/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/agentsignore/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/budget/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/commands/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/flavors/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/hcl/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/hooks/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/models/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/overview/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/permissions/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/routing/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/sandbox/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/structured-output/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/tools/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/configuration/user-settings/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/demo.gif delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/a2a/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/acp/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/api-server/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/board/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/chat-server/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/cli/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/code-mode/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/evaluation/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/harnesses/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/mcp-mode/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/remote-mcp/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/sessions/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/skills/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/snapshots/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/features/tui/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/getting-started/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/getting-started/installation/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/getting-started/introduction/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/getting-started/quickstart/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/getting-started/set-up-a-model/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/compaction/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/go-sdk/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/headless/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/secrets/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/thinking/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/guides/tips/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/anthropic/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/baseten/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/bedrock/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/cerebras/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/chatgpt/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/cloudflare-ai-gateway/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/cloudflare-workers-ai/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/custom/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/deepseek/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/dmr/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/fireworks/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/github-copilot/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/google/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/groq/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/huggingface/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/local/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/minimax/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/mistral/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/moonshot/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/nebius/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/nvidia/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/openai/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/opencode-go/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/opencode-zen/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/openrouter/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/overview/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/ovhcloud/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/together/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/vercel/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/providers/xai/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/_index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/a2a/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/api/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/background-agents/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/background-jobs/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/fetch/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/filesystem/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/git/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/handoff/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/lsp/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/mcp-catalog/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/mcp/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/memory/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/model-picker/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/open-url/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/openapi/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/plan/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/rag/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/scheduler/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/script/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/session_context/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/session_plan/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/shell/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/tasks/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/think/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/todo/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/transfer-task/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/user-prompt/index.md delete mode 100644 _vendor/github.com/docker/docker-agent/docs/tools/webhook/index.md create mode 100644 data/docker_agent_redirects.yml diff --git a/.github/workflows/sync-docker-agent-docs.yml b/.github/workflows/sync-docker-agent-docs.yml deleted file mode 100644 index 3f24f332ca56..000000000000 --- a/.github/workflows/sync-docker-agent-docs.yml +++ /dev/null @@ -1,130 +0,0 @@ -name: sync-docker-agent-docs - -on: - schedule: - # Run daily at 02:30 UTC, offset from sync-cli-docs - - cron: '30 2 * * *' - workflow_dispatch: - inputs: - version: - description: "(optional) docker-agent version - defaults to the latest release tag" - required: false - default: "" - pull_request: - paths: - - '.github/workflows/sync-docker-agent-docs.yml' - -permissions: - contents: write - pull-requests: write - -env: - BRANCH_NAME: "bot/sync-docker-agent-docs" - MODULE_NAME: "github.com/docker/docker-agent" - -jobs: - sync-docker-agent-docs: - runs-on: ubuntu-24.04 - steps: - - - name: Checkout docs repo - uses: actions/checkout@93cb6efe18208431cddfb8368fd83d5badbf9bfd # v5 - with: - fetch-depth: 0 - - - name: Get target version - id: get-version - env: - GH_TOKEN: ${{ github.token }} - run: | - if [ -n "${{ inputs.version }}" ]; then - VERSION="${{ inputs.version }}" - else - VERSION=$(gh release view --repo docker/docker-agent --json tagName --jq .tagName) - fi - CURRENT=$(go list -m -f '{{ .Version }}' "$MODULE_NAME" || true) - - echo "version=$VERSION" >> "$GITHUB_OUTPUT" - echo "current=$CURRENT" >> "$GITHUB_OUTPUT" - echo "docker-agent version: **$VERSION** (currently pinned: **$CURRENT**)" | tee -a "$GITHUB_STEP_SUMMARY" - - - name: Set up Docker Buildx - if: steps.get-version.outputs.version != steps.get-version.outputs.current - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 - - - # go mod edit sets the version before plain make vendor: passing - # VENDOR_MODULE would run hugo mod get, which records docker-agent's - # full transitive graph as indirect requires in go.mod. - name: Update vendor - if: steps.get-version.outputs.version != steps.get-version.outputs.current - run: | - go mod edit -require "${MODULE_NAME}@${{ steps.get-version.outputs.version }}" - make vendor - - - name: Detect changes - id: changes - if: steps.get-version.outputs.version != steps.get-version.outputs.current - run: | - if [ -n "$(git status --porcelain)" ]; then - echo "changes=true" >> "$GITHUB_OUTPUT" - echo "Changes detected - syncing Docker Agent docs" >> "$GITHUB_STEP_SUMMARY" - else - echo "changes=false" >> "$GITHUB_OUTPUT" - echo "No changes to sync - Docker Agent docs are up to date" >> "$GITHUB_STEP_SUMMARY" - fi - - - name: Commit changes - if: steps.changes.outputs.changes == 'true' - env: - BRANCH_NAME: ${{ env.BRANCH_NAME }} - VERSION: ${{ steps.get-version.outputs.version }} - run: | - git checkout -b "$BRANCH_NAME" - git config user.name "github-actions[bot]" - git config user.email "41898282+github-actions[bot]@users.noreply.github.com" - git add -A - git commit -m "docker-agent: sync docs with docker-agent $VERSION" - - - name: Create or update Pull Request - if: steps.changes.outputs.changes == 'true' && github.event_name != 'pull_request' - env: - GH_TOKEN: ${{ github.token }} - BRANCH_NAME: ${{ env.BRANCH_NAME }} - PR_TITLE: "docker-agent: sync docs with docker-agent ${{ steps.get-version.outputs.version }}" - PR_BODY: | - ## Summary - - Automated sync of Docker Agent documentation from the docker/docker-agent repository. - - **docker-agent version:** ${{ steps.get-version.outputs.version }} - - --- - - > [!IMPORTANT] - > **Reviewer:** Please close and reopen this PR to trigger CI checks. - > See: https://docs.github.com/en/actions/how-tos/write-workflows/choose-when-workflows-run/trigger-a-workflow#triggering-a-workflow-from-a-workflow - run: | - # Check for existing open PR from this branch - EXISTING_PR=$(gh pr list --state open --head "$BRANCH_NAME" --json url --jq ".[0].url // empty") - - if [ -n "$EXISTING_PR" ]; then - echo "Updating existing PR: $EXISTING_PR" >> "$GITHUB_STEP_SUMMARY" - git push -u origin "$BRANCH_NAME" --force - gh pr edit "$EXISTING_PR" --title "$PR_TITLE" --body "$PR_BODY" - else - # Check if a closed PR with the same title already exists - CLOSED_PR=$(gh pr list --state closed --search "$PR_TITLE in:title" --json url --jq ".[0].url // empty") - if [ -n "$CLOSED_PR" ]; then - echo "A closed PR already exists for this version: $CLOSED_PR" >> "$GITHUB_STEP_SUMMARY" - echo "Skipping PR creation." - exit 0 - fi - - echo "Creating new PR" >> "$GITHUB_STEP_SUMMARY" - git push -u origin "$BRANCH_NAME" - gh pr create \ - --title "$PR_TITLE" \ - --body "$PR_BODY" \ - --base main \ - --head "$BRANCH_NAME" - fi diff --git a/_vendor/github.com/docker/docker-agent/docs/community/_index.md b/_vendor/github.com/docker/docker-agent/docs/community/_index.md deleted file mode 100644 index 764483d9718c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/community/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Community" -description: "Contributing, troubleshooting, and telemetry." -weight: 80 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/community/contributing/index.md b/_vendor/github.com/docker/docker-agent/docs/community/contributing/index.md deleted file mode 100644 index 302997a137dc..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/community/contributing/index.md +++ /dev/null @@ -1,131 +0,0 @@ ---- -title: "Contributing" -description: "Docker Agent is open source. Here's how to set up your development environment and contribute." -keywords: docker agent, ai agents, community, contributing -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/community/contributing/ ---- - -_Docker Agent is open source. Here's how to set up your development environment and contribute._ - -## Development Setup - -### Prerequisites - -- [Go 1.26](https://go.dev/dl/) or higher -- API key(s) for your chosen AI provider -- [Task](https://taskfile.dev/installation/) -- [golangci-lint](https://golangci-lint.run/docs/welcome/install/local/) - -> [!NOTE] -> **Platform Support** -> -> macOS and Linux are fully supported for development. On Windows, use `task build-local` to build via Docker. - -### Build from Source - -```bash -# Clone and build -git clone https://github.com/docker/docker-agent.git -cd docker-agent -task build - -# Set API keys -export OPENAI_API_KEY=your_key_here -export ANTHROPIC_API_KEY=your_key_here - -# Run an example -./bin/docker-agent run examples/code.yaml -``` - -### Development Commands - -| Command | Description | -| ------------------ | ----------------------------------------------- | -| `task build` | Build the binary to `./bin/docker-agent` | -| `task test` | Run all tests (clears API keys for determinism) | -| `task lint` | Run golangci-lint | -| `task format` | Format code | -| `task dev` | Run lint, test, and build in sequence | -| `task build-local` | Build for local platform via Docker | -| `task cross` | Cross-platform builds (all architectures) | - -## Dogfooding - -Use Docker Agent to work on Docker Agent! The project includes a specialized developer agent: - -```bash -cd docker-agent -docker agent run ./golang_developer.yaml -``` - -This agent is an expert Go developer that understands the Docker Agent codebase. Ask it questions, request fixes, or have it implement features. - -## Core Concepts - -- **Root Agent** — Main entry point that coordinates the system -- **Sub-Agents** — Specialized agents for specific domains -- **Tools** — External capabilities via MCP -- **Models** — AI provider configurations - -## Code Style - -The project uses `golangci-lint` with strict rules. As long as `task lint` passes, the code is stylistically acceptable. - -Key conventions: - -- Use `fmt.Errorf("context: %w", err)` for error wrapping -- Always pass `context.Context` as the first parameter -- Use `slog` for structured logging -- Use functional options pattern for constructors -- In tests: use `t.Context()`, `t.TempDir()`, `t.Setenv()`, and `t.Parallel()` - -## Opening Issues - -File issues on the [GitHub issue tracker](https://github.com/docker/docker-agent/issues). Please: - -> [!NOTE] -> **See also** -> -> [Troubleshooting](../troubleshooting/index.md) — Common issues and debug mode. [Telemetry](../telemetry/index.md) — What data is collected and how to opt out. - -- Use the included issue template -- Search for existing issues before creating new ones -- Only use issues for bugs and feature requests (not support) - -## Submitting Pull Requests - -1. **Fork** the repository and create a branch for your changes -2. **Write** your code following the style and testing guidelines above -3. **Test** your changes: run `task lint` and `task test` -4. **Sign** your commits with `git commit -s` (DCO required) -5. **Open a pull request** against the `main` branch - -> [!TIP] -> Use the dogfooding agent (`docker agent run ./golang_developer.yaml`) to help write and review your changes before submitting. - -## Sign Your Work - -All contributions require a Developer Certificate of Origin (DCO) sign-off: - -```bash -# Sign commits automatically -git config user.name "Your Name" -git config user.email "your.email@example.com" -git commit -s -m "Your commit message" -``` - -## Community - -Find us on [Slack](https://dockercommunity.slack.com/archives/C09DASHHRU4) for questions and discussions. - -## Code of Conduct - -We want to keep the Docker Agent community welcoming, inclusive, and collaborative. Key guidelines: - -- **Be nice** — Be courteous, respectful, and polite. No abuse of any kind will be tolerated. -- **Encourage diversity** — Make everyone feel welcome regardless of background. -- **Keep it legal** — Share only content you own and don't break the law. -- **Stay on topic** — Post to the correct channel and avoid off-topic discussions. - -The governance for this repository is handled by Docker Inc. diff --git a/_vendor/github.com/docker/docker-agent/docs/community/opentelemetry/index.md b/_vendor/github.com/docker/docker-agent/docs/community/opentelemetry/index.md deleted file mode 100644 index ae6b3c9a1304..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/community/opentelemetry/index.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "OpenTelemetry Tracing" -description: "Export Docker Agent traces to any OTLP backend, including Langfuse and LangSmith, for debugging agentic workflows." -keywords: docker agent, ai agents, community, opentelemetry tracing -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/community/opentelemetry/ ---- - -_Docker Agent can export OpenTelemetry traces of an agent run to any OTLP/HTTP backend. This is separate from [product-analytics telemetry](../telemetry/index.md) and is opt-in via the `--otel` flag._ - -When enabled, Docker Agent emits OpenTelemetry GenAI (`gen_ai.*`) and MCP (`mcp.*`) spans following the [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/gen-ai/). Spans cover the agent turn, model calls (with token usage and cost attributes), tool calls, MCP client/server activity, sub-agent hand-offs, and provider fallbacks. W3C `traceparent` context is propagated so the whole run renders as a single connected trace tree. - -## Enabling - -```bash -docker agent run agent.yaml --otel -``` - -Without an exporter endpoint configured, spans are recorded locally as no-ops. To ship them somewhere, set the standard OTLP environment variables described below. - -## Configuration - -Docker Agent reads the standard OTLP environment variables: - -| Variable | Purpose | -| --- | --- | -| `OTEL_EXPORTER_OTLP_ENDPOINT` | Base OTLP/HTTP endpoint. The signal subpath (`/v1/traces`, `/v1/metrics`, `/v1/logs`) is appended automatically. | -| `OTEL_EXPORTER_OTLP_HEADERS` | Comma-separated `key=value` headers sent with every export request (for example, an `Authorization` header). | -| `OTEL_RESOURCE_ATTRIBUTES` | Extra resource attributes merged into every span. | -| `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` | Set to `true` to capture prompt and response message content as span attributes. Off by default. | - -> [!NOTE] -> **Base endpoint, not the full signal URL** -> -> Set `OTEL_EXPORTER_OTLP_ENDPOINT` to the **base** endpoint (for example `https://cloud.langfuse.com/api/public/otel`). Docker Agent appends `/v1/traces` for you, matching the value documented by Langfuse and LangSmith. A bare `host:port` is also accepted and gets `https://` (or `http://` for localhost). - -> [!WARNING] -> **Message content can contain sensitive data** -> -> `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` is off by default because chat history routinely contains PII, secrets, and internal documents. Enable it only for backends and environments where exporting that content is acceptable. - -## Backends - -Protocol support is OTLP over HTTP (`http/protobuf`). gRPC endpoints are not currently supported. - -### Langfuse - -[Langfuse](https://langfuse.com) exposes an OTLP endpoint and authenticates with HTTP Basic auth built from a project's public and secret keys. - -```bash -# Base64 of "public_key:secret_key" -LANGFUSE_AUTH=$(echo -n "pk-lf-...:sk-lf-..." | base64) - -export OTEL_EXPORTER_OTLP_ENDPOINT="https://cloud.langfuse.com/api/public/otel" -export OTEL_EXPORTER_OTLP_HEADERS="Authorization=Basic ${LANGFUSE_AUTH}" - -docker agent run agent.yaml --otel -``` - -Regional and self-hosted hosts use the same `/api/public/otel` base path: - -| Region | Endpoint | -| --- | --- | -| EU | `https://cloud.langfuse.com/api/public/otel` | -| US | `https://us.cloud.langfuse.com/api/public/otel` | -| Self-hosted (>= v3.22.0) | `http://localhost:3000/api/public/otel` | - -### LangSmith - -[LangSmith](https://docs.langchain.com/langsmith/trace-with-opentelemetry) authenticates with an `x-api-key` header (the raw API key, with no `Basic`/`Bearer` prefix). An optional `Langsmith-Project` header routes traces to a named project. - -```bash -export OTEL_EXPORTER_OTLP_ENDPOINT="https://api.smith.langchain.com/otel" -export OTEL_EXPORTER_OTLP_HEADERS="x-api-key=,Langsmith-Project=" - -docker agent run agent.yaml --otel -``` - -### OpenTelemetry Collector - -Any OTLP/HTTP collector (the OpenTelemetry Collector, Grafana Alloy, Jaeger, and so on) works by pointing at its base endpoint: - -```bash -export OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318" -docker agent run agent.yaml --otel -``` - -> [!NOTE] -> **Langfuse and LangSmith ingest traces only** -> -> Both backends accept the traces signal only. Docker Agent also wires metric and log exporters at the same endpoint, so their periodic exports return `404` against trace-only backends. This is harmless to traces but appears in the debug log. Point a full OTLP collector at the endpoint if you also want metrics and logs. - -## Inspecting traces locally - -Use `--debug` to print telemetry activity to the debug log (`~/.cagent/cagent.debug.log` by default) without standing up a backend: - -```bash -docker agent run agent.yaml --otel --debug -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/community/telemetry/index.md b/_vendor/github.com/docker/docker-agent/docs/community/telemetry/index.md deleted file mode 100644 index 54974db155f8..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/community/telemetry/index.md +++ /dev/null @@ -1,79 +0,0 @@ ---- -title: "Telemetry" -description: "Docker Agent collects anonymous usage data to help improve the tool. Telemetry can be disabled at any time." -keywords: docker agent, ai agents, community, telemetry -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/community/telemetry/ ---- - -_Docker Agent collects anonymous usage data to help improve the tool. Telemetry can be disabled at any time._ - -On first startup, Docker Agent displays a notice about telemetry collection so you're always informed. All events are processed synchronously when recorded. - -## Disabling Telemetry - -```bash -# Disable via environment variable -$ TELEMETRY_ENABLED=false docker agent run agent.yaml - -# Or export it in your shell profile -$ export TELEMETRY_ENABLED=false -``` - -> [!NOTE] -> **Default** -> -> Telemetry is **enabled by default**. Set `TELEMETRY_ENABLED=false` to opt out. - -## What's Collected ✅ - -- Command names and success/failure status -- Agent names and model types -- Tool names and whether calls succeed or fail -- Token counts (input/output totals) and estimated costs -- Session metadata (durations, error counts) - -## What's NOT Collected ❌ - -- User input or prompts -- Agent responses or generated content -- File contents -- API keys or credentials -- Personally identifying information (PII) - -> [!TIP] -> **See events locally** -> -> Use `--debug` to see telemetry events printed to the debug log without sending them anywhere additional. - -```bash -docker agent run agent.yaml --debug -``` - -## Event Types - -The telemetry system uses structured, type-safe events: - -| Event Type | What It Tracks | -| ----------- | ------------------------------------------------------------------- | -| **Command** | CLI command execution with success status | -| **Tool** | Agent tool calls with timing and error information | -| **Token** | LLM token usage by model, session, and cost | -| **Session** | Agent session lifecycle with start/end events and aggregate metrics | - -## For Developers - -Telemetry is automatically wrapped around all commands. To record additional events, use the context-based API: - -```bash -// Recommended: context-based telemetry (clean, testable) -if telemetryClient := telemetry.FromContext(ctx); telemetryClient != nil { - telemetryClient.RecordToolCall(ctx, "filesystem", "session-id", "agentName", time.Millisecond*500, nil) - telemetryClient.RecordTokenUsage(ctx, "gpt-4", 100, 50, 0.01) -} - -// Or use direct calls -telemetry.TrackCommand("run", args) -``` - -Events are processed synchronously when `Track()` is called, sending HTTP requests immediately. diff --git a/_vendor/github.com/docker/docker-agent/docs/community/troubleshooting/index.md b/_vendor/github.com/docker/docker-agent/docs/community/troubleshooting/index.md deleted file mode 100644 index 1e73169e067b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/community/troubleshooting/index.md +++ /dev/null @@ -1,342 +0,0 @@ ---- -title: "Troubleshooting" -description: "Common issues and how to resolve them when working with Docker Agent." -keywords: docker agent, ai agents, community, troubleshooting -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/community/troubleshooting/ ---- - -_Common issues and how to resolve them when working with Docker Agent._ - -## Common Errors - -### Context Window Exceeded - -Error message: `context_length_exceeded` or similar. - -- Use `/compact` in the TUI to summarize and reduce conversation history -- Set `num_history_items` in agent config to limit messages sent to the model -- Switch to a model with larger context (Claude Sonnet 4.5 supports 1M tokens, Gemini up to 2M) -- Break large tasks into smaller conversations - -### Max Iterations Reached - -The agent hit its `max_iterations` limit without completing the task. - -- Increase `max_iterations` in agent config (default is unlimited, but many agents set 20-50) -- Check if the agent is stuck in a loop (enable `--debug` to see tool calls) -- Break complex tasks into smaller steps - -### Model Fallback Triggered - -When the primary model fails, Docker Agent automatically switches to fallback models. Look for log messages like `"Switching to fallback model"`. - -- **429 errors:** Rate limited — the cooldown period keeps using the fallback -- **5xx errors:** Server issues — retries with exponential backoff first, then falls back -- **4xx errors:** Client errors — skips directly to next model - -Configure fallback behavior in your agent config: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - fallback: - models: [openai/gpt-5-mini, openai/gpt-4o-mini] - retries: 2 # retries per model for 5xx errors - cooldown: 1m # how long to stick with fallback after 429 -``` - -## Missing credentials or model errors - -When Docker Agent can't find a usable model at startup, it fails fast with an actionable error. The message names the exact next step. `docker agent doctor` is the fastest way to see the full picture — which providers have credentials, whether Docker Model Runner is reachable, and which model `auto` would pick. - -### Required environment variables not set - -An agent (or a tool it uses) depends on environment variables that aren't configured: - -```text -The following environment variables must be set: - - ANTHROPIC_API_KEY - -Provide them using any of these sources: - - Shell environment: export ANTHROPIC_API_KEY= - - Env file: docker agent run --env-from-file ... - - Docker Agent env file: docker agent setup (stores the key in ~/.config/cagent/.env) - -See https://docs.docker.com/ai/docker-agent/guides/secrets/ for details. -``` - -Set the variable through any of the listed [secret sources](../../guides/secrets/index.md). When the missing variable is a model-provider API key, the error also suggests running a local model instead (`docker agent run --model dmr/ai/qwen3 ...`), which needs no API key, and links to the [Set Up a Model](../../getting-started/set-up-a-model/index.md) tutorial. - -### No model available (`auto` selection failed) - -The `auto` model selector found no configured cloud provider and no usable Docker Model Runner model: - -```text -No model is currently available. - -To fix this, you can: - - Pull a Docker Model Runner model, e.g. `docker model pull ai/qwen3` - - Install Docker Model Runner: https://docs.docker.com/ai/model-runner/get-started/ - - Configure an API key for a cloud provider: - - anthropic: ANTHROPIC_API_KEY - - openai: OPENAI_API_KEY - ... -``` - -Either configure a cloud provider API key (see [API keys not set](#api-keys-not-set) below) or pull a local model. The [Set Up a Model](../../getting-started/set-up-a-model/index.md) tutorial walks through both paths. Run `docker agent doctor` to see which providers have credentials and whether Docker Model Runner is reachable. - -### Docker Model Runner model not pulled - -A `dmr/...` model was requested but isn't available locally: - -```text -model ai/qwen3 is not pulled in Docker Model Runner - -To resolve this, you can: - - Pull it first: docker model pull ai/qwen3 - - Or choose a model that is already available (see `docker model ls`). -``` - -If instead you see `cannot query Docker Model Runner at `, Docker Model Runner isn't installed or running — see the [Model Runner get-started guide](https://docs.docker.com/ai/model-runner/get-started/). - -> [!TIP] -> **Diagnose before you run** -> -> Run `docker agent doctor` (or `docker agent doctor ./agent.yaml` to include a file's requirements) to check all three issues in one shot. It exits non-zero when something would block a run, making it useful as a CI preflight. See the [CLI reference](../../features/cli/index.md#docker-agent-doctor). - -## Debug Mode - -The first step for any issue is enabling debug logging. This provides detailed information about what Docker Agent is doing internally. - -```bash -# Enable debug logging (writes to ~/.cagent/cagent.debug.log) -$ docker agent run config.yaml --debug - -# Write debug logs to a custom file -$ docker agent run config.yaml --debug --log-file ./debug.log - -# Enable OpenTelemetry tracing for deeper analysis -$ docker agent run config.yaml --otel -``` - -> [!TIP] -> Always enable `--debug` when reporting issues. The log file contains detailed traces of API calls, tool executions, and agent interactions. - -## Agent Not Responding - -### API keys not set - -Each model provider requires its own API key as an environment variable: - -| Provider | Environment Variable | -| ------------- | --------------------------------------------------- | -| OpenAI | `OPENAI_API_KEY` | -| Anthropic | `ANTHROPIC_API_KEY` | -| Google Gemini | `GOOGLE_API_KEY` or `GEMINI_API_KEY` | -| Mistral | `MISTRAL_API_KEY` | -| xAI | `XAI_API_KEY` | -| Nebius | `NEBIUS_API_KEY` | -| MiniMax | `MINIMAX_API_KEY` | -| Requesty | `REQUESTY_API_KEY` | -| OpenRouter | `OPENROUTER_API_KEY` | -| GitHub Copilot | `GITHUB_TOKEN` (PAT with `copilot` scope) | -| Azure OpenAI | `AZURE_API_KEY` (override with `token_key`) | -| AWS Bedrock | `AWS_BEARER_TOKEN_BEDROCK` or AWS credentials chain | - -```bash -# Verify your keys are set -$ env | grep API_KEY -``` - -### Incorrect model name - -Model names must match the provider's naming exactly. Common mistakes: - -- Using a deprecated model name (e.g. `gpt-4` instead of `gpt-5-mini` or `gpt-4o`) -- Model references are case-sensitive: `openai/gpt-5-mini` ≠ `openai/GPT-5-mini` - -### Network connectivity - -If the agent hangs or times out, check that you can reach the provider's API endpoint. Firewalls, VPNs, or proxy settings may block requests. - -## Tool Execution Failures - -### MCP tools not found or failing - -- Ensure the MCP tool command is installed and on your `PATH` -- Check file permissions — tools need to be executable -- Test MCP tools independently before integrating with Docker Agent -- For Docker-based MCP tools (`ref: docker:*`), ensure Docker Desktop is running - -### Filesystem / shell tool errors - -- Verify the agent has the correct toolset configured (`type: filesystem`, `type: shell`) -- Check that the working directory exists and is accessible -- On macOS, ensure terminal has the necessary permissions (e.g., Full Disk Access) - -### Tool lifecycle issues - -MCP and LSP toolsets are managed by a supervisor that auto-restarts them when they crash or drop their session. The TUI exposes that supervisor through two slash commands: - -- `/tools` — the unified tools dialog. Its top section lists every toolset with its current state (`Stopped`, `Starting`, `Ready`, `Degraded`, `Restarting`, `Failed`), restart count, and last error; the bottom section lists every tool the agent can call. Start here whenever a tool seems missing or stuck. -- `/toolset-restart ` — force a supervisor-driven reconnect of the named toolset. Useful after completing OAuth, when a remote MCP server has been redeployed, or when a language server like `gopls` is unresponsive. - -Remote MCP servers that return `401 invalid_token` (e.g. because the stored OAuth token was revoked or rotated) are now self-healing: Docker Agent silently exchanges the refresh token for a new one when possible, or surfaces an OAuth re-authentication prompt on your next message when refresh is not possible. No more stuck toolsets that require a process restart — but if you want to trigger re-auth immediately, `/toolset-restart ` forces it right away. - -MCP tools using stdio transport must complete the initialization handshake before becoming available. If tools fail silently: - -1. Run `/tools` to see whether the toolset is `Failed` or stuck in `Restarting`, and what the last error was. -2. Enable `--debug` and look for MCP protocol messages in the log -3. Check that the MCP server process starts and responds to `initialize` -4. Verify environment variables required by the tool are set (check `env` and `env_file` in the toolset config) - -> [!NOTE] -> **Startup tool-listing timeout** -> -> At startup, Docker Agent queries each toolset for its tool list. If a toolset does not respond within 10 seconds (e.g. a wedged MCP stdio server that never answers `tools/list`), that toolset is skipped with a warning and the remaining toolsets load normally. The sidebar resolves showing whichever tools did load — no infinite spinner. Enable `--debug` to see the warning message, and use `/toolset-restart ` once the server becomes responsive. - -If a toolset keeps crashing in a tight loop, tune the [`lifecycle`](../../configuration/tools/index.md#toolset-lifecycle) block on the toolset (e.g. raise `backoff.initial`, lower `max_restarts`, or switch to the `best-effort` profile) so a flaky dependency does not amplify into a restart storm. - -## Configuration Errors - -### YAML syntax issues - -Docker Agent validates config at startup and reports errors with line numbers. Common problems: - -- Incorrect indentation (YAML is whitespace-sensitive) -- Missing quotes around values containing special characters (`:`, `#`, `{`, `}`) -- Using tabs instead of spaces - -### Missing references - -- Local agents in `sub_agents` must be defined in the `agents` section (external OCI references like `myorg/agent:tag` are resolved from registries automatically) -- Named model references must exist in the `models` section (or use inline format like `openai/gpt-5`) -- RAG source names referenced by agents must be defined in the `rag` section - -### Toolset validation - -- The `path` field is valid for `memory` and `tasks` toolsets, and for the agent-level `cache` block -- MCP toolsets need either `command` (stdio), `remote` (Streamable HTTP/SSE), or `ref` (Docker) -- Provider names must be one of: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, etc. - -> [!NOTE] -> **Schema Validation** -> -> Use the [JSON schema](https://github.com/docker/docker-agent/blob/main/agent-schema.json) in your editor for real-time config validation and autocompletion. - -## Session & Connectivity Issues - -### Downgrade fails with a newer-database error - -If an older Docker Agent binary cannot open the session database after an upgrade, -the database may contain a schema migration that the older binary does not know. -Restore a database created by the older version, or use a binary that includes the -migration. - -### Port conflicts - -When running Docker Agent as an API server or MCP server, ensure the port is not already in use: - -```bash -# Check if port 8080 is in use -$ lsof -i :8080 - -# Use a different port -$ docker agent serve api config.yaml --listen :9090 -``` - -### MCP endpoint accessibility - -For remote MCP servers, verify the endpoint is reachable: - -```bash -# Test streamable HTTP endpoint -$ curl -v https://mcp-server.example.com/mcp -``` - -### Session isolation - -The API server stores every conversation as a distinct session in the SQLite database (`session.db` by default). Each session is identified by its UUID and only mixes messages when the same session ID is reused. If conversations seem to bleed into each other: - -- Make sure each client creates a fresh session via `POST /api/sessions` (don't reuse session IDs across users). -- Confirm `--session-db` points to the path you expect — a stale database from another run can resurface old sessions. -- Use `GET /api/sessions/:id` to inspect what is actually stored, and `DELETE /api/sessions/:id` to clear sessions you don't want anymore. - -### HTTP 413: request body too large - -Three kinds of process reject an oversized request body with `413 Request Entity Too Large`: `docker agent serve api`, `docker agent serve chat`, and an interactive run's control plane ([`docker agent run --listen`](../../features/api-server/index.md#listen)). They aren't configured the same way: `serve api` and `serve chat` each expose their own `--max-request-size` flag (1 MiB default). A `--listen` control plane has no such flag — it enforces a fixed, non-configurable 1 MiB limit — and no `--auth-token` either. Work through these layers in order: - -1. **Identify which server is involved.** `serve api`, `serve chat`, and an attached run's `--listen` control plane are three separate kinds of process. `serve api` and `serve chat` each have their own `--max-request-size` flag and 1 MiB default — check the flags the process that returned the 413 was actually started with. A `--listen` control plane has no `--max-request-size` flag: its 1 MiB cap is fixed. -2. **Measure the serialized request body, not a source file's size.** JSON string escaping and, for any base64-encoded binary content, base64's ~33% expansion both inflate the wire size well past the original file size — a file just under the limit can still push the encoded request over it. -3. **Rule out an intermediary.** If a reverse proxy, gateway, or load balancer sits in front of Docker Agent, it usually enforces its own, independent body-size limit — often with a differently formatted error — and can reject the request before Docker Agent ever sees it. -4. **Confirm who actually returned the error.** A 413 (or a context-length error) can also come from the model provider itself once the request reaches it; that is a separate limit unrelated to `--max-request-size` — see [Context Window Exceeded](#context-window-exceeded) above. -5. **Resolve it.** Once you've confirmed Docker Agent's own server rejected the request, send less content — split it across turns. On `serve api` or `serve chat` you can also restart the server with a deliberately chosen, larger `--max-request-size` (see [API Server](../../features/api-server/index.md#cli-flags) or [Chat Server](../../features/chat-server/index.md#cli-flags)). A `--listen` control plane has no `--max-request-size` flag to raise — sending less content is the only fix. - -A few things that catch people out: - -- `--max-request-size` is set once at process startup and applies to every request that server handles — it isn't per-request or per-client. Only `serve api` and `serve chat` have it; a `--listen` control plane's 1 MiB cap can't be changed. -- `0` or a negative value falls back to the 1 MiB default; it does not mean "no limit". -- Retrying the same oversized body against the same server won't succeed — the limit doesn't change between requests. -- On all three, the body-size check runs ahead of request authentication, so an oversized request can come back as 413 even without valid credentials. -- Piping stdin into a **local** run (`docker agent run agent.yaml -`) never crosses Docker Agent's own inbound HTTP boundary — Docker Agent may still send that content onward to a model/provider over HTTP, but no request reaches Docker Agent's own server to be measured against a `--max-request-size` cap. Piping stdin into `docker agent run --remote ... -`, however, does cross that boundary: the CLI serializes that stdin text into a native API run request and sends it to whichever Docker Agent server the `--remote` address points at — a `serve api` process or another run's `--listen` control plane, never `serve chat`, which speaks a different protocol — so it's measured against that server's own limit like any other request (a configurable `--max-request-size` for `serve api`, or the fixed 1 MiB cap for a `--listen` control plane). That initial request carries only message text — conversion currently drops any attachment resolved locally (`@path`, `/attach`, `--attach`) for the first message, so it alone can't be the cause of a 413. But a `--remote` run doesn't stay text-only for its whole lifetime: a locally resolved attachment added to a *later* message while the agent is still busy — via the default steer behavior or an explicit follow-up (Alt+Enter) — is forwarded as part of that native API request, counts toward the same limit, and can trigger 413 just like any other oversized request. - -> [!WARNING] -> Raising `--max-request-size` increases how much memory an unauthenticated or malicious client can force the server to buffer per request. Pick a value with your deployment's exposure in mind, and pair any non-loopback listener with `--auth-token` (API server) or `--api-key`/`--api-key-env` (chat server). A `--listen` control plane has neither flag — keep it on loopback, a unix socket, or behind an authenticating reverse proxy if it must be reachable from elsewhere. - -## Performance Issues - -### High memory usage - -- Large context windows (64K+ tokens) consume significant memory — consider reducing `max_tokens` -- Use `num_history_items` in agent config to limit conversation history -- For DMR (local models), tune `runtime_flags` for your hardware (e.g., `--ngl` for GPU layers) - -### Slow responses - -- Check if MCP tools are adding latency (visible in debug logs) -- Use the `/cost` command in TUI to see token usage and identify expensive interactions -- For DMR, consider enabling [speculative decoding](../../providers/dmr/index.md) for faster inference - -### Tool resource leaks - -Monitor for tools that don't clean up properly — check debug logs for MCP server start/stop lifecycle events. Orphaned tool processes can consume system resources. - -## Agent Store Issues - -### Pull / push failures - -```bash -# Test registry connectivity -$ docker pull docker.io/username/agent:latest - -# Verify pulled agent content -$ docker agent share pull docker.io/username/agent:latest -``` - -### Agent content issues - -- Ensure the pushed YAML is valid — run `docker agent run` locally before pushing -- Check that referenced resources (MCP tools, files) are available on the target machine -- For auto-refresh (`--pull-interval`), verify the registry is accessible from the server - -## Log Analysis - -When reviewing debug logs, search for these key patterns: - -| Log Pattern | What It Indicates | -| --------------------------- | ------------------------------------------------------------------------------------------------ | -| `"Starting runtime stream"` | Agent execution beginning | -| `"Tool call"` | A tool is being executed | -| `"Tool call result"` | Tool execution completed | -| `"Stream stopped"` | Agent finished processing | -| `HTTP 429` | Rate limiting — consider adding a [fallback model](../../configuration/agents/index.md) | -| `context canceled` | Operation was interrupted (timeout or user cancel) | -| `[RAG Manager]` | RAG retrieval operations | -| `[Reranker]` | Reranking operations | - -> [!WARNING] -> **Still stuck?** -> -> If these steps don't resolve your issue, file a bug on the [GitHub issue tracker](https://github.com/docker/docker-agent/issues) with your debug log attached, or ask on [Slack](https://dockercommunity.slack.com/archives/C09DASHHRU4). diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/_index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/_index.md deleted file mode 100644 index a4a44d04328a..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Core Concepts" -description: "The core ideas behind Docker Agent: agents, models, tools, and multi-agent teams." -weight: 20 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/agents/index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/agents/index.md deleted file mode 100644 index 092f7af5104c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/agents/index.md +++ /dev/null @@ -1,114 +0,0 @@ ---- -title: "Agents" -description: "Agents are the core building blocks of Docker Agent. Each agent is an AI-powered entity with a model, instructions, tools, and optional sub-agents." -keywords: docker agent, ai agents, concepts, agents -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/concepts/agents/ ---- - -_Agents are the core building blocks of Docker Agent. Each agent is an AI-powered entity with a model, instructions, tools, and optional sub-agents._ - -## What is an Agent? - -An agent in Docker Agent is defined by: - -- **Model** — The AI model powering it (e.g., Claude, GPT-5, Gemini). See [Models](../models/index.md). -- **Description** — A brief summary of what the agent does (used by other agents for delegation) -- **Instruction** — The system prompt that defines the agent's behavior and personality -- **Tools** — Capabilities like filesystem access, shell commands, or external APIs -- **Sub-agents** — Other agents it can delegate tasks to - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Expert software developer - instruction: | - You are an expert developer. Write clean, efficient code - and explain your reasoning step by step. - toolsets: - - type: filesystem - - type: shell - - type: think -``` - -## The Root Agent - -Every Docker Agent configuration has a **root agent** — the entry point that receives user messages. In a single-agent setup, this is the only agent. In a multi-agent setup, the root agent acts as a coordinator, delegating tasks to specialized sub-agents. - -> [!NOTE] -> **Naming** -> -> The first agent defined in your YAML (or the one named `root`) is the root agent by default. You can also specify which agent to start with using `docker agent run config.yaml -a agent_name`. - -## Agent Properties - -| Property | Type | Required | Description | -| ---------------------- | ------- | -------- | -------------------------------------------------------------- | -| `model` | string | ✓ | Model reference (inline like `openai/gpt-5` or a named model) | -| `description` | string | ✓ | What the agent does — used by other agents for delegation | -| `instruction` | string | ✓ | System prompt defining behavior | -| `toolsets` | array | ✗ | List of tool configurations | -| `sub_agents` | array | ✗ | Names of agents this agent can delegate to | -| `fallback` | object | ✗ | Fallback model configuration for resilience | -| `add_date` | boolean | ✗ | Include current date in context | -| `add_environment_info` | boolean | ✗ | Include OS, working directory, git info in context | -| `max_iterations` | int | ✗ | Max tool-calling loops (default: unlimited) | -| `commands` | object | ✗ | Named prompts callable via `/command` | -| `skills` | boolean \| list | ✗ | Enable skill discovery and loading. `true` = `["local"]`; list values may combine `"local"` with remote skill-server URLs. | - -## Model Fallbacks - -Agents can automatically fail over to alternative models when the primary model is unavailable: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - fallback: - models: - - openai/gpt-5 - - google/gemini-3.5-flash - retries: 2 # retries per model for 5xx errors - cooldown: 1m # stick with fallback after 429 -``` - -## Named Commands - -Define reusable prompts that can be invoked as commands: - -```yaml -agents: - root: - model: openai/gpt-5 - instruction: You are a helpful assistant. - commands: - df: "Check how much free space I have on my disk" - greet: "Say hello to ${env.USER}" -``` - -```bash -# Run a named command -$ docker agent run agent.yaml /df -$ docker agent run agent.yaml /greet -``` - -Commands support environment variable interpolation using JavaScript template literal syntax. Undefined variables expand to empty strings. - -## Default Agent - -Running `docker agent run` without a config argument uses `docker-agent.yaml`, `docker-agent.yml`, or `docker-agent.hcl` from the current directory when present. Otherwise, it uses a capable built-in default agent for quick tasks without needing any configuration. - -```bash -# Use the project config or built-in default agent -$ docker agent run - -# Override the default with an alias -$ docker agent alias add default /path/to/my-agent.yaml -$ docker agent run # now runs your custom agent -``` - -> [!TIP] -> **See also** -> -> For reusable task-specific instructions, see [Skills](../../features/skills/index.md). For multi-agent patterns, see [Multi-Agent](../multi-agent/index.md). For full config reference, see [Agent Config](../../configuration/agents/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/distribution/index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/distribution/index.md deleted file mode 100644 index a2ea3aafde5f..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/distribution/index.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: "Agent Distribution" -description: "Package, share, and run agents via OCI-compatible registries — just like container images." -keywords: docker agent, ai agents, concepts, agent distribution -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/concepts/distribution/ -aliases: - - /ai/docker-agent/sharing-agents/ ---- - -_Package, share, and run agents via OCI-compatible registries — just like container images._ - -## Overview - -Docker Agent agents can be pushed to any OCI-compatible registry (Docker Hub, GitHub Container Registry, etc.) and pulled/run anywhere. This makes sharing agents as easy as sharing Docker images. - -> [!TIP] -> For CLI commands related to distribution, see [CLI Reference](../../features/cli/index.md) (`docker agent share push`, `docker agent share pull`, `docker agent alias`). - -## Pushing Agents - -```bash -# Push to Docker Hub -$ docker agent share push ./agent.yaml docker.io/username/my-agent:latest - -# Push to GitHub Container Registry -$ docker agent share push ./agent.yaml ghcr.io/username/my-agent:v1.0 -``` - -## Pulling Agents - -```bash -# Pull an agent -$ docker agent share pull docker.io/username/my-agent:latest - -# Pull from Docker Hub shorthand -$ docker agent share pull myorg/agent:tag -``` - -## Running from a Registry - -Run agents directly from a registry without pulling first: - -```bash -# Run directly from Docker Hub -$ docker agent run docker.io/username/my-agent:latest - -# Docker Hub shorthand (docker.io is implied) -$ docker agent run myorg/agent:tag - -# Run with a specific agent from a multi-agent config -$ docker agent run docker.io/username/dev-team:latest -a developer -``` - -## Using as Sub-Agents - -Registry agents can be used directly as sub-agents in a multi-agent configuration — no need to define them locally: - -```yaml -agents: - root: - model: openai/gpt-5 - description: Coordinator - instruction: Delegate tasks to the right sub-agent. - sub_agents: - - myorg/agent:tag # auto-named "agent" - - my_reviewer:myorg/reviewer # explicitly named "my_reviewer" -``` - -External sub-agents are automatically named after their last path segment. Use the `name:reference` syntax to give them a custom name. - -Tag references are checked against the registry on every `docker agent run`, which adds a network round-trip per sub-agent at startup. Pin them to a digest (`myorg/agent@sha256:…`) to serve them from cache instead. - -See [Pin external sub-agents to a digest](../multi-agent/index.md#pin-external-sub-agents-to-a-digest) and [External Sub-Agents](../multi-agent/index.md#external-sub-agents-from-registries) for details. - -## Using with Aliases - -Combine OCI references with aliases for convenient access: - -```bash -# Create an alias for a registry agent -$ docker agent alias add coder myorg/coder --yolo - -# Now just run -$ docker agent run coder -``` - -## Using with API Server - -The API server supports OCI references with auto-refresh: - -```bash -# Start API from registry, auto-pull every 10 minutes -$ docker agent serve api docker.io/username/agent:latest --pull-interval 10 -``` - -## Private Repositories - -Docker Agent supports pulling from private GitHub repositories and registries that require authentication. Use standard Docker login or GitHub authentication: - -```bash -# Login to a registry -$ docker login docker.io - -# Now push/pull works with private repos -$ docker agent share push ./agent.yaml docker.io/myorg/private-agent:latest -$ docker agent run docker.io/myorg/private-agent:latest -``` - -> [!NOTE] -> **Docker authentication** -> -> When pulling or running an agent from a `docker.com` or `*.docker.com` HTTPS URL (e.g. `desktop.docker.com`), Docker Agent automatically forwards a Docker token for authentication. If Docker Desktop is running and signed in, its token is used; otherwise, Docker Agent exchanges the access token stored by `docker login` for a fresh Docker token. Either way, no explicit login step is required beyond `docker login` (or being signed into Docker Desktop). -> -> Note: `docker.io` (the standard Docker Hub registry domain) is a separate domain and is **not** covered by automatic token forwarding. Agents pulled from `docker.io` or `registry-1.docker.io` still require `docker login docker.io` for private repositories. - -> [!NOTE] -> **Troubleshooting** -> -> Having issues with push/pull? See [Troubleshooting](../../community/troubleshooting/index.md) for common registry issues. - -## Local Development - -For local development and testing, you can run an agent directly from a local HTTP server without a registry: - -```bash -# Serve an agent config locally -$ python3 -m http.server 8080 - -# Run it directly via HTTP -$ docker agent run http://localhost:8080/agent.yaml -$ docker agent run http://127.0.0.1:8080/agent.yaml -``` - -This is useful for iterating on agent configs served from a local dev server before pushing to a registry. Both `localhost` and `127.0.0.1` addresses are supported with plain `http://` URLs. diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/models/index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/models/index.md deleted file mode 100644 index d966769d4562..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/models/index.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -title: "Models" -description: "Models are the AI brains behind your agents. Docker Agent supports multiple providers and flexible configuration." -keywords: docker agent, ai agents, concepts, models -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/concepts/models/ ---- - -_Models are the AI brains behind your agents. Docker Agent supports multiple providers and flexible configuration._ - -## Inline vs. Named Models - -There are two ways to assign a model to an agent: - -### Inline (Quick) - -Use the `provider/model` shorthand directly in the agent definition: - -```yaml -agents: - root: - model: openai/gpt-5 - instruction: You are a helpful assistant. -``` - -### Named (Full Control) - -Define models in a `models` section and reference them by name: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 - temperature: 0.7 - -agents: - root: - model: claude - instruction: You are a helpful assistant. -``` - -Named models let you configure temperature, token limits, thinking budgets, and other parameters. They're also reusable across multiple agents. - -## First Available Models - -A named model can also select the first usable model from a priority list. This -is useful for shared configs that should prefer paid cloud models when their API -keys are present, but still work with a local fallback: - -```yaml -models: - smart: - first_available: - - anthropic/claude-sonnet-4-5 - - openai/gpt-5 - - dmr/ai/qwen3 - -agents: - root: - model: smart - instruction: You are a helpful assistant. -``` - -At load time, Docker Agent selects the first candidate whose credentials are -configured. You only need credentials for one candidate. See -[Model Configuration](../../configuration/models/index.md#first-available-models) -for details. - -## Supported Providers - -| Provider | Key | Example Models | API Key Env Var | -| ------------------- | ---------------- | ------------------------------------ | ----------------------------------- | -| OpenAI | `openai` | gpt-5, gpt-5-mini, gpt-4o | `OPENAI_API_KEY` | -| Anthropic | `anthropic` | claude-sonnet-4-5, claude-opus-5 | `ANTHROPIC_API_KEY` | -| Google | `google` | gemini-3.5-flash, gemini-3-pro | `GOOGLE_API_KEY` / `GEMINI_API_KEY` | -| AWS Bedrock | `amazon-bedrock` | Claude, Nova, Llama models | AWS credentials | -| Docker Model Runner | `dmr` | ai/qwen3, ai/llama3.2 | None (local) | -| Mistral | `mistral` | Mistral models | `MISTRAL_API_KEY` | -| xAI | `xai` | Grok models | `XAI_API_KEY` | -| Nebius | `nebius` | Open-source and specialised models | `NEBIUS_API_KEY` | -| NVIDIA NIM | `nvidia` | Nemotron, Llama, Qwen, DeepSeek (open models) | `NVIDIA_API_KEY` | -| MiniMax | `minimax` | MiniMax models | `MINIMAX_API_KEY` | -| Baseten | `baseten` | DeepSeek, Kimi, GLM, Llama models | `BASETEN_API_KEY` | -| OVHcloud | `ovhcloud` | Qwen, Llama, Mistral, DeepSeek (EU-hosted) | `OVH_AI_ENDPOINTS_ACCESS_TOKEN` | -| Groq | `groq` | Llama, Qwen, GPT-OSS (fast inference) | `GROQ_API_KEY` | -| Fireworks AI | `fireworks` | Kimi, Llama, Qwen, DeepSeek, GLM (open models) | `FIREWORKS_API_KEY` | -| DeepSeek | `deepseek` | DeepSeek-V3 chat and R1 reasoner | `DEEPSEEK_API_KEY` | -| Cerebras | `cerebras` | GPT-OSS, GLM (fast inference) | `CEREBRAS_API_KEY` | -| Together AI | `together` | Llama, Qwen, DeepSeek, Kimi (open models) | `TOGETHER_API_KEY` | -| Hugging Face | `huggingface` | Llama, Qwen, DeepSeek, GLM (open models) | `HF_TOKEN` | -| Cloudflare Workers AI | `cloudflare-workers-ai` | Llama, Mistral, Qwen, Gemma (edge-hosted open models) | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` | -| Moonshot AI | `moonshot` | Kimi K2 chat, reasoning, and coding models | `MOONSHOT_API_KEY` | -| Vercel AI Gateway | `vercel` | Multi-provider gateway | `AI_GATEWAY_API_KEY` | -| Cloudflare AI Gateway | `cloudflare-ai-gateway` | Multi-provider gateway | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_GATEWAY_ID` | -| Requesty | `requesty` | Multi-provider gateway | `REQUESTY_API_KEY` | -| OpenRouter | `openrouter` | Multi-provider gateway | `OPENROUTER_API_KEY` | -| Azure OpenAI | `azure` | gpt-4o, gpt-5 on Azure | `AZURE_API_KEY` + `base_url` | -| [Ollama](../../providers/local/index.md) | `ollama` | Any local Ollama model | None (local; optional `base_url`) | -| GitHub Copilot | `github-copilot` | Copilot-hosted OpenAI/Anthropic | `GITHUB_TOKEN` (PAT with `copilot`) | -| ChatGPT (OpenAI account) | `chatgpt` | gpt-5 family via ChatGPT subscription | None (sign in via `docker agent setup`) | - -See the [Model Providers](../../providers/overview/index.md) section for detailed configuration guides. - -## Model Properties - -| Property | Type | Description | -| ------------------- | ---------- | ------------------------------------------------- | -| `provider` | string | Provider identifier (required) | -| `model` | string | Model name (required) | -| `description` | string | Human-readable summary of the model's purpose | -| `temperature` | float | Randomness: 0.0 (deterministic) to 1.0 (creative) | -| `max_tokens` | int | Maximum response length | -| `top_p` | float | Nucleus sampling: 0.0 to 1.0 | -| `frequency_penalty` | float | Reduce repetition: 0.0 to 2.0 | -| `presence_penalty` | float | Encourage topic diversity: 0.0 to 2.0 | -| `base_url` | string | Custom API endpoint | -| `thinking_budget` | string/int | Reasoning effort configuration | -| `task_budget` | int/object | Total token budget for an agentic task (Anthropic; honored by Opus 4.7 today) | -| `provider_opts` | object | Provider-specific options | - -## Reasoning / Thinking Budget - -Control how much the model "thinks" before responding: - -| Provider | Format | Values | Default | -| ---------- | ---------- | ------------------------------------------------------------------- | -------------------------------- | -| OpenAI | string | `minimal`, `low`, `medium`, `high`, `xhigh`, `max` | `medium` (always-reasoning models only) | -| Anthropic | int or str | 1024–32768 tokens, or `adaptive`, `adaptive/`, effort level | off | -| Gemini 2.5 | int | 0 (off), -1 (dynamic), or token count | -1 (dynamic) | -| Gemini 3 | string | `minimal`, `low`, `medium`, `high` | varies | -| All | string/int | `none` or `0` clears Docker Agent's local config | — | - -`none` and `0` are not universal API-level disable switches. On genuine OpenAI -gpt-5.6+ endpoints (Sol/Terra/Luna), `none` is a real `reasoning_effort` value -that Docker Agent sends as-is and the model does not reason. On older OpenAI -models, `none`/`0` only clear the local `thinking_budget` — omitting the field -has the same effect — and the model falls back to the API's own default effort -(still reasoning internally for always-reasoning models like the o-series). -Providers with a true optional-thinking switch (Gemini 2.5, Claude, local -models) are fully disabled by `none`/`0`. See the -[Thinking / Reasoning guide](../../guides/thinking/index.md#disabling-thinking) -for the full per-provider breakdown. - -```yaml -models: - deep-thinker: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 16384 - - fast-responder: - provider: openai - model: gpt-5.6 - thinking_budget: none # real API-level disable on gpt-5.6+ -``` - -> [!NOTE] -> **Multi-provider teams** -> -> Different agents can use different providers in the same config. See [Multi-Agent](../multi-agent/index.md) for patterns. - -## Alloy Models - -"Alloy models" let you use more than one model in the same conversation — Docker Agent alternates between them to leverage the strengths of each: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5,openai/gpt-5 - instruction: You are a helpful assistant. -``` - -Read more about the alloy model concept at [xbow.com/blog/alloy-agents](https://xbow.com/blog/alloy-agents). diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/multi-agent/index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/multi-agent/index.md deleted file mode 100644 index e9632ff020d5..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/multi-agent/index.md +++ /dev/null @@ -1,421 +0,0 @@ ---- -title: "Multi-Agent Systems" -description: "Build teams of specialized agents that collaborate and delegate tasks to each other." -keywords: docker agent, ai agents, concepts, multi-agent systems -linkTitle: "Multi-Agent" -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/concepts/multi-agent/ ---- - -_Build teams of specialized agents that collaborate and delegate tasks to each other._ - -## Why Multi-Agent? - -Complex tasks benefit from specialization. Instead of one monolithic agent trying to do everything, you can create a **team** of focused agents: - -- A **coordinator** that understands the overall goal and delegates -- A **developer** that writes code with filesystem and shell access -- A **reviewer** that checks code quality -- A **researcher** that searches the web for information - -Each agent has its own model, tools, and instructions — optimized for its specific role. - -## Two Patterns: Delegation vs. Handoffs - -Docker Agent supports two multi-agent patterns: - -| | **Delegation** (`sub_agents`) | **Handoffs** (`handoffs`) | -|---|---|---| -| **Topology** | Hierarchical (parent → child → parent) | Peer-to-peer graph (A → B → C → A) | -| **Session** | Child runs in a **sub-session** | Conversation stays in the **same session** | -| **Context** | Child gets a clean task description | Next agent sees the **full conversation history** | -| **Control flow** | Parent blocks until child finishes, then continues | Active agent switches — previous agent is no longer in the loop | -| **Tool** | `transfer_task` | `handoff` | -| **Best for** | Task delegation to specialists | Pipeline workflows, conversational routing | - -You can combine both patterns in the same configuration — an agent can have both `sub_agents` and `handoffs`. - -> [!TIP] -> **When to use which** -> -> **`sub_agents`** — Use when a coordinator needs to send tasks to specialists and synthesize their results. -> -> **`handoffs`** — Use when agents should take turns processing the same conversation (pipelines, routing). -> -> **`background_agents`** — Use when multiple independent tasks can run simultaneously. - -## Delegation with `sub_agents` - -Agents delegate tasks using the built-in `transfer_task` tool, which is automatically available to any agent with `sub_agents`. The parent agent sends a task to a child agent, waits for the result, and then continues. - -1. **User** sends a message to the root agent -2. **Root agent** analyzes the request and decides which sub-agent should handle it -3. **Root agent** calls `transfer_task` with the target agent, task description, and expected output -4. **Sub-agent** processes the task in its own agentic loop using its tools -5. **Results** flow back to the root agent, which responds to the user - -```bash -# The transfer_task tool call looks like: -transfer_task( - agent="developer", - task="Create a REST API endpoint for user authentication", - expected_output="Working Go code with tests" -) -``` - -> [!NOTE] -> **Auto-Approved** -> -> Unlike other tools, `transfer_task` is always auto-approved — no user confirmation needed. This allows seamless delegation between agents. - -## Handoffs Routing - -Handoffs are a peer-to-peer routing pattern where agents **hand off the entire conversation** to another agent. Unlike delegation, there is no sub-session — the conversation stays in a single session and the active agent simply switches. - -This pattern is ideal for: - -- **Pipeline workflows** — data flows through a chain of specialized agents -- **Conversational routing** — a coordinator routes the user to the right specialist, who can route back when done -- **Graph topologies** — agents can form cycles (A → B → C → A), enabling iterative workflows - -### How It Works - -1. **User** sends a message to the starting agent -2. **Agent A** processes the message, then calls `handoff` to route to **Agent B** -3. **Agent B** becomes the active agent and sees the **full conversation history** -4. **Agent B** can respond, use its own tools, or hand off to another agent -5. This continues until an agent responds directly without handing off - -```bash -# The handoff tool call looks like: -handoff( - agent="summarizer" -) -``` - -> [!NOTE] -> **Scoped Handoff Targets** -> -> Each agent can only hand off to agents listed in its own `handoffs` array. The `handoff` tool is automatically injected — you don't need to add it manually. - -### Example - -A coordinator routes to a researcher, who hands off to a summarizer, who returns to the coordinator: - -```text -Root ──→ Researcher ──→ Summarizer ──→ Root -``` - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Coordinator that routes queries - instruction: | - Route research queries to the researcher. - handoffs: - - researcher - - researcher: - model: openai/gpt-5 - description: Web researcher - instruction: | - Search the web, then hand off to the summarizer. - toolsets: - - type: mcp - ref: docker:duckduckgo - handoffs: - - summarizer - - summarizer: - model: openai/gpt-5 - description: Summarizes findings - instruction: | - Summarize the research results, then hand off - back to root. - handoffs: - - root -``` - -> [!TIP] -> **Full pipeline example** -> -> For a more complex handoff graph with branching and multiple processing stages, see [`examples/handoff.yaml`](https://github.com/docker/docker-agent/blob/main/examples/handoff.yaml). - -### Forced Handoffs - -With `handoffs`, the **model decides** whether to call the `handoff` tool — which means it can forget to, breaking pipelines that depend on a strict order. `force_handoff` removes that uncertainty: whenever the agent produces a final response, the **runtime itself** routes the conversation to the named agent, bypassing the LLM's tool-calling entirely. The full conversation context carries over. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Extracts key facts from the input - instruction: | - Extract the key facts from the user's input as a bullet list. - force_handoff: summarizer - - summarizer: - model: anthropic/claude-sonnet-4-5 - description: Produces the final summary - instruction: | - Summarize the extracted facts for the user. -``` - -Rules enforced at config load time: - -- The target must be an agent defined in the config (or an external reference) -- An agent cannot `force_handoff` to itself -- Chains of `force_handoff` edges must not form a cycle (A → B → A is rejected) - -See [`examples/force_handoff.yaml`](https://github.com/docker/docker-agent/blob/main/examples/force_handoff.yaml) for a runnable example. - -## Parallel Delegation with Background Agents - -`transfer_task` is **sequential** — the coordinator waits for the sub-agent to finish before continuing. When you need to fan out work to multiple agents at the same time, use the `background_agents` toolset instead. - -Add it to your coordinator's toolsets: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Research coordinator - sub_agents: [researcher, analyst, writer] - toolsets: - - type: think - - type: background_agents -``` - -The coordinator can then: - -1. **Dispatch** several tasks at once with `run_background_agent` — each returns a task ID immediately -2. **Monitor** progress with `list_background_agents` or `view_background_agent` -3. **Collect** results once tasks complete -4. **Cancel** tasks that are no longer needed with `stop_background_agent` - -```bash -# Start two tasks in parallel -run_background_agent(agent="researcher", task="Find recent papers on LLM agents") -run_background_agent(agent="analyst", task="Analyze our current architecture") - -# Check on all tasks -list_background_agents() - -# Read results when ready -view_background_agent(task_id="agent_task_abc123") -``` - -## External Sub-Agents from Registries - -Sub-agents don't have to be defined locally — you can reference agents from any OCI-compatible registry directly in your `sub_agents` list. This lets you compose teams using shared agents without duplicating their configuration. - -```yaml -agents: - root: - model: openai/gpt-5 - description: Coordinator that delegates to local and external sub-agents - instruction: | - Delegate tasks to the most appropriate sub-agent. - sub_agents: - - local_helper - - myorg/agent:tag # pulled from registry automatically - - local_helper: - model: openai/gpt-5 - description: A local helper agent for simple tasks - instruction: You are a helpful assistant. -``` - -External sub-agents are automatically named after their last path segment (without the tag) — for example, `myorg/agent:tag` becomes `agent`. You can also give them an explicit name using the `name:reference` syntax: - -```yaml - sub_agents: - - my_agent:myorg/agent:tag # available as "my_agent" - - reviewer:docker.io/myorg/review-agent:latest -``` - -### Pin external sub-agents to a digest - -External references use a tag by default: `myorg/agent` is shorthand for `myorg/agent:latest`. Tag references are re-resolved against the registry on **every** `docker agent run`: each unpinned external sub-agent triggers a digest lookup at startup, even when that sub-agent is never invoked in the session. On a healthy connection this typically adds a second or two per reference (it depends on your network and registry), and it is one of the paths that can stall if the registry or credential helper misbehaves. - -Pinning a reference to an immutable digest (`@sha256:…`) makes the runtime serve it straight from the local cache with no network round-trip, so startup stays fast and your team is fully reproducible: - -```yaml - sub_agents: - - reviewer:docker.io/myorg/review-agent@sha256:44117e73263afa5c861bdf3730dae7925918ffdd146827eee5bcff20bc55e8fa -``` - -Copy the digest from your registry (Docker Hub shows it next to the tag) or read it with a standard OCI tool such as `docker buildx imagetools inspect `. Docker Agent logs a startup warning for any external OCI reference that still uses a tag instead of a digest. - -External references in `handoffs` and `force_handoff` carry the same per-run cost, so pin those to a digest too. - -> [!TIP] -> External sub-agents work with any OCI-compatible registry. See [Agent Distribution](../distribution/index.md) for more on registry references. -> -> See [`examples/sub-agents-from-registry.yaml`](https://github.com/docker/docker-agent/blob/main/examples/sub-agents-from-registry.yaml) for a complete example mixing local and external sub-agents. - -## Harness-Backed Sub-Agents - -Sub-agents can be backed by external coding CLIs — Claude Code, Codex, opencode, or pi — instead of a model API. Add a `harness:` block in place of a `model:` field to create a harness sub-agent: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Orchestrator that plans and delegates - instruction: | - Break down coding tasks and delegate to the coding agents. - sub_agents: - - claude-coder - - codex-coder - - claude-coder: - description: Claude Code specialist - harness: - type: claude-code - effort: high - - codex-coder: - description: Codex specialist - harness: - type: codex -``` - -The orchestrator uses `transfer_task` to send work to a harness sub-agent just like any other sub-agent. Docker Agent handles the orchestration and hooks; the external CLI drives the coding loop. - -> [!TIP] -> **Learn more** -> -> See [Coding Harnesses](../../features/harnesses/index.md) for the full field reference, parallel dispatch patterns, and what does not work inside harness agents. - -## Example: Development Team - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Technical lead coordinating development - instruction: | - You are a technical lead managing a development team. - Analyze requests and delegate to the right specialist. - Ensure quality by reviewing results before responding. - sub_agents: [developer, reviewer, tester] - toolsets: - - type: think - - developer: - model: anthropic/claude-sonnet-4-5 - description: Expert software developer - instruction: | - You are an expert developer. Write clean, efficient code - and follow best practices. - toolsets: - - type: filesystem - - type: shell - - type: think - - reviewer: - model: openai/gpt-5 - description: Code review specialist - instruction: | - You review code for quality, security, and maintainability. - Provide actionable feedback. - toolsets: - - type: filesystem - - tester: - model: openai/gpt-5 - description: Quality assurance engineer - instruction: | - You write tests and ensure software quality. Run tests - and report results. - toolsets: - - type: shell - - type: todo -``` - -## Example: Research Team - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Research coordinator - instruction: | - Coordinate research tasks. Delegate web searches to - the researcher and writing to the writer. - sub_agents: [researcher, writer] - toolsets: - - type: think - - researcher: - model: openai/gpt-5 - description: Web researcher - instruction: Search the web and gather information. - toolsets: - - type: mcp - ref: docker:duckduckgo - - type: memory - path: ./research.db - - writer: - model: anthropic/claude-sonnet-4-5 - description: Content writer - instruction: Write clear, well-structured content. - toolsets: - - type: filesystem -``` - -## Multi-Model Teams - -A key advantage of multi-agent systems is using different models for different roles — picking the best model for each job: - -```yaml -models: - fast: - provider: openai - model: gpt-5-mini - temperature: 0.2 # precise - - creative: - provider: openai - model: gpt-5 - temperature: 0.8 # creative - - local: - provider: dmr - model: ai/qwen3 # runs locally, no API cost - -agents: - analyst: - model: fast # cheap and fast for analysis - writer: - model: creative # creative for content - helper: - model: local # free for simple tasks -``` - -## Shared Tools - -Tools like `todo` can be shared between agents for collaborative task tracking: - -```yaml -toolsets: - - type: todo - shared: true # all agents see the same todo list -``` - -## Best Practices - -- **Keep agents focused** — Each agent should have a clear, narrow role -- **Write clear descriptions** — The coordinator uses descriptions to decide who to delegate to -- **Give minimal tools** — Only give each agent the tools it needs for its specific role -- **Use the think tool when needed** — For models without native reasoning, give coordinators the think tool so they reason about delegation. Models with built-in thinking (e.g., via `thinking_budget`) don't need it -- **Use the right model** — Use capable models for complex reasoning, cheap models for simple tasks -- **Choose the right pattern** — Use `sub_agents` for hierarchical task delegation, `handoffs` for pipeline workflows and conversational routing - -> [!NOTE] -> **Beyond Docker Agent** -> -> For interoperability with other agent frameworks, Docker Agent supports the [A2A protocol](../../features/a2a/index.md) and can expose agents via [MCP Mode](../../features/mcp-mode/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/concepts/tools/index.md b/_vendor/github.com/docker/docker-agent/docs/concepts/tools/index.md deleted file mode 100644 index 149e876d9a7a..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/concepts/tools/index.md +++ /dev/null @@ -1,78 +0,0 @@ ---- -title: "Tools" -description: "Tools give agents the ability to interact with the world — read files, run commands, search the web, query databases, and more." -keywords: docker agent, ai agents, concepts, tools -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/concepts/tools/ ---- - -_Tools give agents the ability to interact with the world — read files, run commands, search the web, query databases, and more._ - -## How Tools Work - -When an agent needs to perform an action, it makes a **tool call**. The Docker Agent runtime executes the tool and returns the result to the agent, which can then use it to continue its work. - -1. Agent receives a user message -2. Agent decides it needs to use a tool (e.g., read a file) -3. Docker Agent executes the tool and returns the result -4. Agent incorporates the result and responds - -> [!NOTE] -> **Tool Confirmation** -> -> By default, Docker Agent asks for user confirmation before executing tools that have side effects (shell commands, file writes). Use `--yolo` to auto-approve all tool calls. - -## Built-in Tools - -Docker Agent ships with several built-in tools that require no external dependencies. Each is enabled by adding its `type` to the agent's `toolsets` list: - -| Tool | Description | -| --- | --- | -| [Filesystem](../../tools/filesystem/index.md) | Read, write, list, search, and navigate files and directories | -| [Shell](../../tools/shell/index.md) | Execute shell commands synchronously | -| [Background Jobs](../../tools/background-jobs/index.md) | Run and manage long-running shell commands | -| [Think](../../tools/think/index.md) | Step-by-step reasoning scratchpad for planning and decision-making | -| [Todo](../../tools/todo/index.md) | Task list management for complex multi-step workflows | -| [Tasks](../../tools/tasks/index.md) | Persistent task database shared across sessions | -| [Memory](../../tools/memory/index.md) | Persistent key-value storage backed by SQLite | -| [Fetch](../../tools/fetch/index.md) | Read content from HTTP/HTTPS URLs (GET only) | -| [Script](../../tools/script/index.md) | Define custom shell scripts as named tools | -| [LSP](../../tools/lsp/index.md) | Connect to Language Server Protocol servers for code intelligence | -| [API](../../tools/api/index.md) | Create custom tools that call HTTP APIs without writing code | -| [OpenAPI](../../tools/openapi/index.md) | Generate tools from an OpenAPI 3.x document | -| [RAG](../../tools/rag/index.md) | Retrieval-augmented generation over indexed sources | -| [Model Picker](../../tools/model-picker/index.md) | Let the agent pick between several models per turn | -| [User Prompt](../../tools/user-prompt/index.md) | Ask users questions and collect interactive input | -| [Open URL](../../tools/open-url/index.md) | Open a fixed URL in the user's default browser | -| [Transfer Task](../../tools/transfer-task/index.md) | Delegate tasks to sub-agents (auto-enabled with `sub_agents`) | -| [Background Agents](../../tools/background-agents/index.md) | Dispatch work to sub-agents concurrently | -| [Handoff](../../tools/handoff/index.md) | Hand the conversation off to another local agent in the same config (auto-enabled with `handoffs:`) | -| [A2A](../../tools/a2a/index.md) | Connect to remote agents via the Agent-to-Agent protocol | -| [MCP Catalog](../../tools/mcp-catalog/index.md) | Discover and activate remote MCP servers from the Docker MCP Catalog on demand | -| [Git](../../tools/git/index.md) | Read-only git repository inspection | -| [Scheduler](../../tools/scheduler/index.md) | Schedule instructions to run at a time or on a recurring interval | -| [Webhook](../../tools/webhook/index.md) | Outbound notifications to Slack, Discord, Telegram, IFTTT, and more | -| [Plan](../../tools/plan/index.md) | Shared persistent scratchpad for multi-agent collaboration | -| [Session Plan](../../tools/session_plan/index.md) | Per-session plan tracker for the draft/review/execute workflow | -| [Session Context](../../tools/session_context/index.md) | Reference a previous session as context | - -## MCP Tools - -Docker Agent supports the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/) for extending agents with external tools. There are three ways to connect MCP tools: - -- **Docker MCP** (recommended) — Run MCP servers in Docker containers via the [MCP Gateway](https://github.com/docker/mcp-gateway). Browse the [Docker MCP Catalog](https://hub.docker.com/search?q=&type=mcp). -- **Local MCP (stdio)** — Run MCP servers as local processes communicating over stdin/stdout. -- **Remote MCP (Streamable HTTP / SSE)** — Connect to MCP servers running on a network. See [Remote MCP Servers](../../features/remote-mcp/index.md). - -```yaml -toolsets: - - type: mcp - ref: docker:duckduckgo -``` - -See [Tool Config](../../configuration/tools/index.md#mcp-tools) for full MCP configuration reference. - -> [!TIP] -> **See also** -> -> For full configuration reference, see [Tool Config](../../configuration/tools/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/_index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/_index.md deleted file mode 100644 index 7b70d5fcfd0f..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Configuration" -description: "Complete reference for configuring agents in YAML or HCL." -weight: 30 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/agents/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/agents/index.md deleted file mode 100644 index 9da240a9cb06..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/agents/index.md +++ /dev/null @@ -1,618 +0,0 @@ ---- -title: "Agent Configuration" -description: "Complete reference for defining agents in your YAML configuration." -keywords: docker agent, ai agents, configuration, yaml, agent configuration -linkTitle: "Agent Config" -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/configuration/agents/ ---- - -_Complete reference for defining agents in your YAML configuration._ - -A configuration must define at least one agent under `agents`. - -## Full Schema - - -```yaml -agents: - agent_name: - model: string # Required: model reference - description: string # Required: what this agent does - instruction: string # Required (unless instruction_file): system prompt - instruction_file: string | [list] # Optional: load the system prompt from one or more files relative to this config (mutually exclusive with instruction) - sub_agents: [list] # Optional: local or external sub-agent references - toolsets: [list] # Optional: tool configurations (use `type: rag` for RAG sources) - fallback: # Optional: fallback config - models: [list] - retries: 2 - cooldown: 1m - add_date: boolean # Optional: add date to context - add_environment_info: boolean # Optional: add env info to context - add_prompt_files: [list] # Optional: include additional prompt files - add_description_parameter: bool # Optional: add description to tool schema - redact_secrets: boolean # Optional: scrub detected secrets out of tool args, outgoing chat messages, and tool output - code_mode_tools: boolean # Optional: let the agent write JavaScript to orchestrate tool calls (see Code Mode) - max_iterations: int # Optional: max tool-calling loops - max_consecutive_tool_calls: int # Optional: max identical consecutive tool calls - max_old_tool_call_tokens: int # Optional: token budget for old tool call content (disabled unless positive) - max_tool_result_tokens: int # Optional: per-tool-result token cap with middle-out truncation (disabled unless positive) - num_history_items: int # Optional: limit conversation history - session_compaction: boolean # Optional: disable automatic session compaction (default: true) - compaction_threshold: float # Optional: context-window fraction that triggers auto-compaction (0–1, default: 0.9) - compaction_model: string # Optional: model used for session-compaction (summary generation) - use_toolsets: [list] # Optional: names of top-level toolsets to merge into this agent - readonly: boolean # Optional: restrict all toolsets to read-only tools only - skills: boolean | [list] # Optional: enable skill discovery (true/false or list of names and/or sources) - use_commands: [list] # Optional: names of top-level commands groups to merge into this agent - use_skills: [list] # Optional: names of top-level skills groups to merge into this agent - commands: # Optional: named prompts - name: "prompt text" # or {instruction: "prompt", agent: "sub_agent_name"} or {url: "https://..."} (TUI only) - welcome_message: string # Optional: message shown at session start - handoffs: [list] # Optional: agent names this agent can hand off to - force_handoff: string # Optional: agent that always receives the conversation when this agent stops - hooks: # Optional: lifecycle hooks - pre_tool_use: [list] - tool_response_transform: [list] - post_tool_use: [list] - session_start: [list] - session_end: [list] - on_user_input: [list] - stop: [list] - notification: [list] - structured_output: # Optional: constrain output format - name: string - schema: object - cache: # Optional: response cache (skip the model on repeat questions) - enabled: boolean - case_sensitive: boolean - trim_spaces: boolean - path: string - harness: # Optional: delegate to an external coding CLI (Claude Code, Codex, opencode, pi) - type: string # Required: claude-code | codex | opencode | pi - model: string # Optional: model override forwarded to the CLI (omit for the CLI's own default) - effort: string # claude-code only: low | medium | high | xhigh | max (omit for the Claude Code default) - agent: string # opencode only: agent profile name - thinking: boolean # opencode only: enable extended thinking -``` - -> [!TIP] -> **See also** -> -> For model parameters, see [Model Config](../models/index.md). For tool details, see [Tool Config](../tools/index.md). For multi-agent patterns, see [Multi-Agent](../../concepts/multi-agent/index.md). - -## Properties Reference - -| Property | Type | Required | Description | -| --------------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `model` | string | ✓ | Model reference. Either inline (`openai/gpt-5`) or a named model from the `models` section. | -| `description` | string | ✓ | Brief description of the agent's purpose. Used by coordinators to decide delegation. | -| `instruction` | string | ✓ | System prompt that defines the agent's behavior, personality, and constraints. Required unless `instruction_file` is set. | -| `instruction_file` | string \| array | ✗ | Path(s) to a file or files (relative to the config file's directory) whose contents become the agent's instruction, loaded at startup. Accepts a single path or a list; multiple files are concatenated in order, separated by a blank line. Mutually exclusive with `instruction`. Each path must be a local relative path inside the config directory (absolute paths and `..` traversal are rejected). Only supported for local file-based configs, not OCI/URL sources. See [External Instruction Files](#external-instruction-files) below. | -| `sub_agents` | array | ✗ | List of agent names or external OCI references this agent can delegate to. Supports local agents, registry references (e.g., `myorg/agent:tag`), and named references (`name:reference`). Automatically enables the `transfer_task` tool. Pin external OCI references to a digest (`name@sha256:…`) to skip the per-run registry lookup that tag references incur. See [External Sub-Agents](../../concepts/multi-agent/index.md#external-sub-agents-from-registries). | -| `toolsets` | array | ✗ | List of tool configurations. See [Tool Config](../tools/index.md). | -| `fallback` | object | ✗ | Automatic model failover configuration. | -| `add_date` | boolean | ✗ | When `true`, injects the current date into the agent's context. | -| `add_environment_info` | boolean | ✗ | When `true`, injects working directory, OS, CPU architecture, and git info into context. | -| `add_prompt_files` | array | ✗ | List of file paths whose contents are appended to the system prompt. Useful for including coding standards, guidelines, or additional context. | -| `add_description_parameter` | boolean | ✗ | When `true`, adds agent descriptions as a parameter in tool schemas. Helps with tool selection in multi-agent scenarios. | -| `redact_secrets` | boolean | ✗ | When `true`, scrubs detected secrets (API keys, tokens, private keys, etc.) out of tool-call arguments, outgoing chat messages, and tool output before they reach a tool, the model, or downstream consumers. See [Redacting Secrets](#redacting-secrets) below. | -| `code_mode_tools` | boolean | ✗ | When `true`, replaces the agent's individual tools with a single tool that runs a JavaScript script calling as many of them as needed in one turn. See [Code Mode](../../features/code-mode/index.md). | -| `max_iterations` | int | ✗ | Maximum number of tool-calling loops. Default: unlimited (0). Set this to prevent infinite loops. | -| `max_consecutive_tool_calls` | int | ✗ | Maximum consecutive identical tool calls before the agent is terminated, preventing degenerate loops. Default: `5`. | -| `max_old_tool_call_tokens` | int | ✗ | Maximum number of tokens to keep from old tool call arguments and results. Older tool calls beyond this budget have their content replaced with a placeholder, saving context space. Tokens are approximated as `len/4`. Truncation is disabled by default; set a positive value to enable it. Set to `-1` to disable truncation (unlimited). | -| `max_tool_result_tokens` | int | ✗ | Maximum number of tokens to keep from each tool result when it is added to the session. Oversized results are truncated middle-out: the head and tail are kept and the removed middle is replaced with a truncation marker. Textual documents attached to the result share the same budget. Tokens are approximated as `len/4`. The cap is disabled by default; set a positive value to enable it. `0` and `-1` both leave tool results unbounded. | -| `num_history_items` | int | ✗ | Limit the number of conversation history messages sent to the model. Useful for managing context window size with long conversations. Default: unlimited (all messages sent). | -| `session_compaction` | boolean | ✗ | When `false`, disables automatic session compaction for this agent: neither the proactive threshold trigger nor the post-overflow auto-recovery runs. The manual `/compact` command remains available. Default: `true`. See the [Context & Compaction guide](../../guides/compaction/index.md). | -| `compaction_threshold` | float | ✗ | Fraction of the model's context window at which proactive auto-compaction triggers. Must be greater than `0` and at most `1`. A `compaction_threshold` set on the agent's model takes precedence. Default: `0.9`. See the [Context & Compaction guide](../../guides/compaction/index.md). | -| `compaction_model` | string | ✗ | Model used for session compaction (summary generation). Can be a named model or an inline `provider/model` string. This agent-level value takes precedence over a `compaction_model` set on the agent's model or provider; when none is set, the agent's own model compacts. See the [Context & Compaction guide](../../guides/compaction/index.md). | -| `skills` | bool/array | ✗ | Enable automatic skill discovery. `true` loads all discovered local skills, `false` disables them. A list can mix skill sources (`local` or `https://…` URLs) and skill names to include — see [Skills](../../features/skills/index.md). | -| `commands` | object | ✗ | Named prompts that can be run with `docker agent run config.yaml /command_name`. Can be simple strings or objects with `instruction` and/or `agent` fields for agent switching, or a `url` field to open a link in the browser (TUI only). See [Named Commands](#named-commands) below. | -| `use_commands` | list of string | ✗ | Names of top-level `commands` groups to merge into this agent. Inline `commands` entries take precedence on name conflicts. Default: `[]`. | -| `use_skills` | list of string | ✗ | Names of top-level `skills` groups to merge into this agent. Inline skills are deduplicated by name against merged entries. Default: `[]`. | -| `use_toolsets` | list of string | ✗ | Names of top-level `toolsets` groups to merge into this agent. See [Reusable Toolsets](../overview/index.md#reusable-toolsets-toolsets). Default: `[]`. | -| `readonly` | boolean | ✗ | When `true`, every toolset on this agent is filtered to expose only read-only tools (those annotated with a read-only hint). Mutating tools are removed at load time and cannot be called even if the model tries. See [Read-Only Agents](#read-only-agents) below. | -| `welcome_message` | string | ✗ | Message displayed to the user when a session starts. Rendered as Markdown in the TUI. **Not sent to the model** — it exists purely for the user's benefit. Useful for telling users what the agent can do and what commands are available. | -| `handoffs` | array | ✗ | List of agent names this agent can hand off the conversation to. Enables the `handoff` tool. See [Handoffs Routing](../../concepts/multi-agent/index.md#handoffs-routing). | -| `force_handoff` | string | ✗ | Name of an agent that unconditionally receives the conversation whenever this agent produces a final response. The runtime performs the switch itself, bypassing the LLM's tool-calling, guaranteeing deterministic pipelines. Must not reference the agent itself, and chains must not form a cycle. See [Forced Handoffs](../../concepts/multi-agent/index.md#forced-handoffs). | -| `hooks` | object | ✗ | Lifecycle hooks for running commands at various points. See [Hooks](../hooks/index.md). | -| `structured_output` | object | ✗ | Constrain agent output to match a JSON schema. See [Structured Output](../structured-output/index.md). | -| `cache` | object | ✗ | Response cache. When the same user question is asked again, the previous answer is replayed verbatim and the model is not called. See [Response Cache](#response-cache) below. | -| `harness` | object | ✗ | Run this agent through an external coding CLI instead of a model. **Note:** Any `toolsets:` defined on the same agent are silently ignored when `harness:` is set — the external CLI brings its own tools. See [Coding Harnesses](../../features/harnesses/index.md). | - -> [!WARNING] -> **max_iterations** -> -> Default is `0` (unlimited). Always set `max_iterations` for agents with powerful tools like `shell` to prevent infinite loops. A value of 20–50 is typical for development agents. - -> [!TIP] -> **Managing long sessions** -> -> `max_old_tool_call_tokens`, `max_tool_result_tokens`, `num_history_items`, `session_compaction`, and `compaction_threshold` all help keep long-running sessions inside the model's context window. See the [Context & Compaction guide](../../guides/compaction/index.md) for how to combine them. - -## External Instruction Files - -Long system prompts can be kept in their own files instead of being inlined in -the YAML, using `instruction_file`. This separates infrastructure configuration -(models, providers, tools) from behavioral content (the prompt), which keeps -version-control diffs focused, reduces merge conflicts on shared configs, and -lets instruction content be edited without risking YAML syntax errors. - -```yaml -agents: - coordinator: - model: openai/gpt-5-mini - description: Routes work between specialist agents - instruction_file: instructions/coordinator.md - sub_agents: - - writer - writer: - model: openai/gpt-5-mini - description: Drafts and edits written content - instruction_file: instructions/writer.md -``` - -The path is resolved relative to the config file's directory and the file's -contents are loaded as the agent's instruction when the config is loaded. Notes: - -- **Mutually exclusive** with `instruction`. Setting both is an error. -- Each path must be a **local relative path inside the config directory**. - Absolute paths and `..` traversal are rejected. -- A **list** of files is also accepted; their contents are concatenated in - order, separated by a blank line. This lets a shared preamble be reused - across agents while each agent appends its own specifics: - - ```yaml - agents: - writer: - model: openai/gpt-5-mini - description: Drafts and edits written content - instruction_file: - - instructions/shared-preamble.md - - instructions/writer.md - ``` - -- Only supported for **local file-based configs**, not agents loaded from OCI - registries or URLs. When an agent is pushed with `docker agent share push`, - the file contents are inlined into the pushed artifact, so the published - agent stays self-contained. - -A runnable example lives in [`examples/instruction_file.yaml`](https://github.com/docker/docker-agent/blob/main/examples/instruction_file.yaml). - -## Prompt Files - -`add_prompt_files` injects the contents of one or more files into the agent's -context at the start of every turn — handy for repo-wide conventions like -`AGENTS.md` or `CLAUDE.md` that should stay available without being pasted -into `instruction`: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: A helpful coding assistant - instruction: You are an expert software developer. - add_prompt_files: - - AGENTS.md -``` - -For each name, the agent loads the closest match found by walking up from the -current working directory, plus (if it's a different file) a copy at that -name directly under the user's home directory — so a personal `~/AGENTS.md` -can layer on top of a repo-local one. Missing files are skipped rather than -erroring. Because resolution and the read happen on every turn, edits to the -file are picked up without restarting the agent. - -Use `--prompt-file` to add files for a single run without editing the -config. It's merged with any `add_prompt_files` already set on the agent, -with duplicates dropped: - -```bash -$ docker agent run agent.yaml --prompt-file CONTRIBUTING.md -``` - -Resolved prompt files show up as their own entries in the `/context` dialog — see [File Attachments](../../features/tui/index.md#file-attachments) in the Terminal UI guide. - -See [Choosing a Large-Input Strategy](../../guides/headless/index.md#choosing-a-large-input-strategy) for how prompt files compare to `@`/`/attach` attachments, the `rag` toolset, and sending content over the API/chat server. - -## Response Cache - -The response cache short-circuits the model when the same user question is asked again. The first time a question is asked, the agent calls the model normally and stores the assistant's reply. Subsequent identical questions skip the model entirely and replay the stored reply verbatim. - -```yaml -agents: - root: - model: openai/gpt-5 - description: Cached assistant - instruction: You are a helpful assistant. - cache: - enabled: true # required to turn the cache on - case_sensitive: false # default: false ("Hello" == "hello") - trim_spaces: true # default: false (" hello " == "hello") - path: ./cache.json # optional: persist to disk; omit for in-memory -``` - -| Property | Type | Default | Description | -| ---------------- | ------- | ------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `enabled` | boolean | `false` | Master switch. When `false` (or when the `cache` section is omitted), no caching is performed. | -| `case_sensitive` | boolean | `false` | When `true`, questions must match exactly (including case) to hit the cache. | -| `trim_spaces` | boolean | `false` | When `true`, leading and trailing whitespace is stripped from the question before it is compared. | -| `path` | string | _empty_ | When set, cache entries are persisted to a JSON file at the given path and reloaded on startup so the cache survives restarts. Relative paths resolve against the agent config directory. When empty, the cache lives in memory only. | - -**How it works** - -- The cache key is the latest user message in the session, normalized according to `case_sensitive` and `trim_spaces`. -- On a hit, the cached reply is added to the session as the assistant message and stop hooks fire normally — the rest of the agent (tools, sub-agents, the model) is bypassed. -- On a miss, the agent runs normally; the final assistant message produced by the first stop of the run is then stored under the question's key. -- Only the response to the original user question of a run is cached; follow-up turns inside the same `RunStream` are not. - -**File-backed storage** - -When `path` is set, every `Store` rewrites the entire cache file. Writes are **atomic**: the new content is written to a sibling temp file, `fsync`'d, and renamed over the destination, so a concurrent reader (or a process that crashes mid-write) will always see either the previous content or the new content in full — never a partially written file. The parent directory is also `fsync`'d after the rename so the rename itself is durable. - -**Cross-process sharing** - -Multiple processes can share the same `path:` cache file safely. Every `Store` takes an exclusive advisory lock on a sibling `.lock` file (POSIX `flock(2)` on Unix, `LockFileEx` on Windows), reloads the current on-disk state under the lock, merges the new entry, and writes back atomically. Two processes that store *different* keys at the same time both see their writes preserved on disk; the lock window is short (one read + one fsync'd write). - -`Lookup` watches the file's modification time and reloads the in-memory map when the file has advanced since its last load, so writes from a sibling process become visible without a restart. The `.lock` sentinel file is created on first write and never deleted: removing it would let two processes lock different inodes and lose mutual exclusion. - -## Redacting Secrets - -The `redact_secrets` flag is a single agent-level switch that scrubs accidentally leaked credentials, tokens, and private keys out of an agent's I/O. It wires up three complementary defenses: - -1. A `pre_tool_use` built-in hook that scrubs detected secrets from the **arguments of every tool call**, before the tool sees them. -2. A `before_llm_call` built-in hook that scrubs the same patterns from **outgoing chat messages** — message content, multi-part text content, prior reasoning content, and the JSON-encoded arguments of any tool call still in the conversation — before they reach the model provider. -3. A `tool_response_transform` built-in hook that scrubs **tool output at the source**, so the secret never reaches event consumers, the persisted session file, the `post_tool_use` hook input, or the next LLM call. - -```yaml -agents: - root: - model: openai/gpt-5 - description: A helpful assistant that scrubs secrets before they leak - instruction: | - You are a helpful assistant. If the user accidentally pastes a token, - do your best work without echoing the secret back. - redact_secrets: true - toolsets: - - type: shell -``` - -Detection uses the [portcullis](https://github.com/docker/portcullis) ruleset, which recognises common secret patterns including: - -- GitHub Personal Access Tokens (`ghp_*`, `gho_*`, `ghu_*`, `ghs_*`, `ghr_*`, fine-grained `github_pat_*`) -- AWS access keys (`AKIA*`, `ASIA*`, …) and secret access keys -- GitLab PATs (`glpat-*`), Hugging Face tokens (`hf_*`) -- Stripe (`sk_live_*`, `pk_test_*`, …), Slack (`xoxb-*`, …), Shopify, Twilio, Discord, Atlassian, Mailchimp, SendGrid, and many more -- JWTs, GCP service-account JSON, Heroku keys, Docker Hub PATs (`dckr_pat_*`) -- PEM-encoded private keys (`-----BEGIN … PRIVATE KEY-----` blocks) - -Each detected span is replaced with the literal string `[REDACTED]`; the surrounding text is preserved so a redacted argument still looks like a legitimate flag (e.g. `--token=[REDACTED]`). Redaction is idempotent — applying it twice yields the same result. - -> [!NOTE] -> **False positives vs. false negatives** -> -> False positives are extremely rare: every rule pairs a regex with a discriminating keyword, so plain English never trips detection. **False negatives are possible** — only patterns the ruleset recognises are scrubbed, so this is a defense-in-depth feature, not a substitute for keeping secrets out of the conversation in the first place. Pair it with a proper [secret manager](../../guides/secrets/index.md) for the credentials your agent actually needs. - -> [!NOTE] -> **Equivalent hook entry** -> -> Setting `redact_secrets: true` on the agent is shorthand for auto-registering all three legs of the feature as hook entries. They share the _same_ built-in name (`type: builtin`, `command: redact_secrets`) on `pre_tool_use`, `before_llm_call`, and `tool_response_transform` respectively — the implementation dispatches on the hook event. You can spell them out by hand to scope a leg to a subset of tools (set `matcher:` to a regex), stack them with other rewriters in a specific order, or enable just one or two legs. See [`examples/redact_secrets_hooks.yaml`](https://github.com/docker/docker-agent/blob/main/examples/redact_secrets_hooks.yaml) for a complete manual wiring and the [Hooks reference](../hooks/index.md#available-built-ins) for the builtin's event coverage. - -## Welcome Message - -Display a message when users start a session: - -```yaml -agents: - assistant: - model: openai/gpt-5 - description: Development assistant - instruction: You are a helpful coding assistant. - welcome_message: | - 👋 Welcome! I'm your development assistant. - - I can help you with: - - Writing and reviewing code - - Running tests and debugging - - Explaining concepts - - What would you like to work on? -``` - -## Deferred Tool Loading - -Toolsets support `defer` to load tools on-demand and speed up agent startup. See [Deferred Tool Loading](../tools/index.md#deferred-tool-loading) for details. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Multi-purpose assistant - instruction: You have access to many tools. - toolsets: - - type: mcp - ref: docker:github-official - defer: true - - type: filesystem -``` - -## Fallback Configuration - -Automatically switch to backup models when the primary fails: - -| Property | Type | Default | Description | -| ---------- | ------ | ------- | ---------------------------------------------------------- | -| `models` | array | `[]` | Fallback models to try in order | -| `retries` | int | `2` | Retries per model for 5xx errors. `-1` to disable. | -| `cooldown` | string | `1m` | How long to stick with a fallback after a rate limit (429) | - -**Error handling:** - -- **Retryable** (same model with backoff): HTTP 5xx, 408, network timeouts -- **Non-retryable** (skip to next model): HTTP 429, 4xx client errors - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - fallback: - models: - - openai/gpt-5 - - google/gemini-3.5-flash - retries: 2 - cooldown: 1m -``` - -## Named Commands - -> [!TIP] -> **Full reference** -> -> This section covers the basics. For URL commands, agent-switching commands, reusable top-level `commands:` groups, and hiding commands with `--disable-commands`, see [Custom Commands](../commands/index.md). - -Define reusable prompt shortcuts that can send prompts to the current agent, switch to a different sub-agent, or open a URL in the browser: - -> **Note:** Named slash commands execute immediately, even while the agent is processing another message. Unlike regular chat messages (which are queued), slash commands interrupt or direct the agent even while it is mid-response. - -```yaml -agents: - root: - model: openai/gpt-5 - instruction: You are a system administrator. - commands: - df: "Check how much free space I have on my disk" - logs: "Show me the last 50 lines of system logs" - greet: "Say hello to ${env.USER}" - deploy: "Deploy ${env.PROJECT_NAME || 'app'} to ${env.ENV || 'staging'}" - - # Advanced format with agent switching - plan: - agent: planner # Switch to the 'planner' agent - instruction: "Create a detailed plan for: ${args.join(\" \")}" # Optional: send this prompt after switching - - # Agent switching without instruction - forwards remaining text as prompt - review: - agent: reviewer # Any text after /review is sent to the reviewer agent - - # URL command - opens a link in the browser instead of messaging the agent - docs: - description: "Open the documentation" - url: https://docs.docker.com/ -``` - -### Command Formats - -Commands support three formats: - -1. **Simple string format**: The string becomes the instruction sent to the current agent - - ```yaml - df: "Check disk space" - ``` - -2. **Advanced object format**: Supports agent switching and optional instructions - - ```yaml - plan: - agent: planner # Required: name of any agent defined in the team - instruction: "Plan: ${args.join(\" \")}" # Optional: prompt to send after switching - description: "Switch to planning mode" # Optional: shown in help text - ``` - -3. **URL format**: Opens a link in the browser instead of messaging the agent - - ```yaml - docs: - url: https://docs.docker.com/ # Required: URL to open - description: "Open the documentation" # Optional: shown in help text - ``` - -When `agent` is set without `instruction`, any text typed after the slash command (e.g., `/plan build a web app`) is forwarded as a prompt to the target agent. The target agent can be **any agent defined in the team configuration** — it does not need to be listed in the current agent's `sub_agents` array. - -**Argument and expansion syntax** - -An `instruction` string can reference the command's arguments and expand tool calls: - -- `${args[0]}`, `${args[1]}`, … — individual positional arguments, in the order the user typed them after the command -- `${args.join(" ")}` — all arguments joined into a single string -- `${tool_name({...})}` — calls a tool and inlines its return value (any tool available to the agent) -- `!tool_name(key=value)` — legacy tool-call form: calls a tool with plain `key=value` arguments and inlines its output - -### Agent-Switching Commands - -Commands with an `agent` field switch the active agent for that command's scope. This is useful for building workflow shortcuts where `/plan`, `/review`, `/deploy` each route the user to the appropriate specialist. - -```yaml -agents: - root: - model: openai/gpt-5 - description: Main assistant - instruction: You are a project coordinator. - sub_agents: [planner, reviewer] - commands: - # Switch to planner with a pre-filled prompt - plan: - agent: planner - instruction: "Create a detailed plan for: ${args.join(\" \")}" - # Switch to reviewer; any text after /review is forwarded - review: - agent: reviewer - # Simple prompt command (no switching) - status: "Summarize what we have accomplished so far" - - planner: - model: openai/gpt-5 - description: Planning specialist - instruction: You create detailed project plans. - - reviewer: - model: anthropic/claude-sonnet-4-5 - description: Code review specialist - instruction: You review code and suggest improvements. -``` - -**Agent-switching vs. `handoff`** - -| | Agent-switching command | `handoff` tool | -| --- | --- | --- | -| **Trigger** | User runs `/command` | Model calls `handoff()` | -| **Session** | Stays in the same session | Stays in the same session | -| **History** | Target agent sees full conversation | Target agent sees full conversation | -| **Return** | User must explicitly switch back | Target agent can chain to another agent | - -**Agent-switching vs. `transfer_task`** - -`transfer_task` launches a **sub-session**: the root agent sends a task, the child runs in isolation, and the result is returned to the root. The root agent stays in control and the child's work is never in the main conversation. Use `transfer_task` (via `sub_agents`) when you want delegation with a clean result; use agent-switching commands when you want to *become* a different agent for the rest of the conversation. - -See [`examples/agent_switching_commands.yaml`](https://github.com/docker/docker-agent/blob/main/examples/agent_switching_commands.yaml) for a complete example. - -```bash -# Run commands from the CLI -$ docker agent run agent.yaml /df -$ docker agent run agent.yaml /greet -$ PROJECT_NAME=myapp ENV=production docker agent run agent.yaml /deploy -``` - -Commands use JavaScript template literal syntax (`${env.VAR}`) for environment variable interpolation. Undefined variables expand to empty strings. - -The same syntax is also expanded in agent and toolset instructions: `agents..instruction` and `toolsets[*].instruction` support `${env.X}` placeholders (with optional `||` defaults and ternary expressions). `agents..description` and `agents..welcome_message` also support it. - -Note that path-like fields (`working_dir`, `path`) primarily use a shell-style syntax (`$VAR`, `${VAR}`, `~`), and also accept `${env.X}` as an alias (though not richer JS expressions). See [Variable Expansion in Config Fields](../overview/index.md#variable-expansion-in-config-fields) for the full table. - -### URL Commands - -A command with a `url` field opens that URL in the user's default browser instead of sending a prompt to the agent. Any URI scheme the OS knows how to dispatch works — both standard web URLs and custom schemes such as `docker-desktop://` for deep links. URL commands are TUI-only — they have no effect when run from the CLI. - -```yaml -agents: - root: - model: openai/gpt-5 - description: An agent with handy URL shortcuts. - instruction: You are a helpful assistant. - commands: - feedback: - description: "Open the feedback site for this session" - url: https://example.com/feedback?session={{session_id}} - docs: - description: "Open the documentation" - url: https://docs.docker.com/ - desktop: - description: "Open this session in Docker Desktop" - url: docker-desktop://dashboard/session/{{session_id}} -``` - -The `{{session_id}}` token is replaced at invocation time with the current session ID (URL-query-escaped so it can't break the URL or inject extra query parameters), letting a command deep-link to something scoped to the conversation. This token deliberately uses `{{...}}` rather than the `${...}` JS-expansion syntax, since the session ID is only known at dispatch time. - -URLs are validated before being handed to the OS opener: a parseable URL with a non-empty scheme is required, and flag-like inputs (those starting with `-`) are rejected to prevent argument injection. - -See [`examples/url_commands.yaml`](https://github.com/docker/docker-agent/blob/main/examples/url_commands.yaml) for a complete example. - -## Read-Only Agents - -Set `readonly: true` on an agent to restrict all of its toolsets to tools that are annotated as read-only. Mutating tools are filtered out at load time — the agent cannot list or call them, even if the model hallucinates a call. - -You can also set `readonly: true` on an individual toolset to restrict only that toolset while leaving others unrestricted. - -```yaml -agents: - # Agent-level readonly: every toolset is restricted to read-only tools. - inspector: - model: anthropic/claude-sonnet-4-5 - description: Read-only inspector that can explore but never modify. - instruction: Explore the project. Do not make changes. - readonly: true - toolsets: - - type: filesystem - - type: shell - - # Toolset-level readonly: only the filesystem toolset is restricted; - # the shell toolset keeps all of its tools. - mixed: - model: anthropic/claude-sonnet-4-5 - description: Read-only file access, full shell access. - instruction: You can read files and run any shell command. - toolsets: - - type: filesystem - readonly: true - - type: shell -``` - -See [`examples/readonly.yaml`](https://github.com/docker/docker-agent/blob/main/examples/readonly.yaml) for a complete example. - -> [!NOTE] -> **Which tools are read-only?** -> -> Whether a tool is read-only is determined by its `ReadOnlyHint` annotation. For built-in tools, read-only operations (list/read/search) carry the hint; mutating operations (write/delete/execute) do not. Custom and MCP tools expose the hint via their own annotations. - -## Complete Example - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 - -agents: - root: - model: claude - description: Technical lead coordinating development - instruction: | - You are a technical lead. Analyze requests and delegate - to the right specialist. Always review work before responding. - welcome_message: "👋 I'm your tech lead. How can I help today?" - sub_agents: [developer, researcher] - add_date: true - add_environment_info: true - fallback: - models: [openai/gpt-5] - toolsets: - - type: think - commands: - review: "Review all recent code changes for issues" - hooks: - session_start: - - type: command - command: "./scripts/setup.sh" - - developer: - model: claude - description: Expert software developer - instruction: Write clean, tested, production-ready code. - max_iterations: 30 - toolsets: - - type: filesystem - - type: shell - - type: think - - type: todo - - researcher: - model: openai/gpt-5 - description: Web researcher with memory - instruction: Search for information and remember findings. - toolsets: - - type: mcp - ref: docker:duckduckgo - - type: memory - path: ./research.db -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/agentsignore/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/agentsignore/index.md deleted file mode 100644 index 67bbcf96ee75..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/agentsignore/index.md +++ /dev/null @@ -1,105 +0,0 @@ ---- -title: "Ignoring files" -description: "Hide files from the agent with a .agentsignore file, using the same syntax as .gitignore." -keywords: docker agent, ai agents, configuration, agentsignore, gitignore, ignore, secrets -weight: 75 -canonical: https://docs.docker.com/ai/docker-agent/configuration/agentsignore/ ---- - -_Hide files from the agent with a `.agentsignore` file, using the same syntax as `.gitignore`._ - -## Overview - -Put a `.agentsignore` file in your project and the agent stops seeing the paths it lists. Matched files are absent from directory listings and searches, and reads, writes and edits targeting them are refused. - -```text -# .agentsignore -secrets.env -*.key -.env.* -build/ -docs/**/*.draft.md -!public.key -``` - -There is nothing to configure. The file's presence is the opt-in, and it is picked up automatically by the [filesystem toolset](../../tools/filesystem/index.md). - -## Syntax - -The syntax is `.gitignore` syntax — parsed with the same library git uses, so patterns behave identically to `.gitignore` and `.dockerignore`: - -| Pattern | Matches | -| --- | --- | -| `secrets.env` | that name at any depth (`secrets.env`, `config/secrets.env`) | -| `/secrets.env` | that name at the project root only | -| `*.key` | any file with the extension | -| `build/` | the directory and everything under it | -| `docs/**/*.draft.md` | nested matches via `**` | -| `!public.key` | re-includes a path an earlier pattern excluded | -| `# comment` | ignored, as are blank lines | - -## Where the file is found - -The nearest `.agentsignore` at or above the working directory is used, so starting a run in a subdirectory still honours the project's file. Patterns are anchored to the directory containing the file, exactly as git anchors to the directory containing `.gitignore`. - -Unlike `.gitignore`, **a git repository is not required** — `.agentsignore` works in any directory. - -## What it affects - -| Behaviour | Effect | -| --- | --- | -| `list_directory`, `directory_tree` | matched entries are omitted | -| `search_files_content` | matched files are skipped | -| `read_file`, `read_multiple_files` | refused | -| `write_file`, `edit_file` | refused, including for files that do not exist yet | -| `create_directory`, `remove_directory` | refused | -| `permissions` | matching deny rules are derived automatically, so `/permissions` shows them | - -Paths are resolved before matching — symlinks, `./` prefixes and `..` segments are all normalised — so an ignored file cannot be reached by spelling it differently. - -The `.agentsignore` file is itself always hidden: it names the very things being kept back, so handing it to the agent would be a map of what to look for. - -> [!NOTE] -> `.agentsignore` is independent of the filesystem toolset's [`ignore_vcs`](../tools/index.md) option. Setting `ignore_vcs: false` turns off `.gitignore` filtering but does **not** un-hide `.agentsignore` entries. - -## Relationship to `.gitignore` - -They are separate, and they do different amounts of work. - -`.gitignore` is respected by default (`ignore_vcs`), but only as a **display filter**: gitignored files are hidden from listings and searches while `read_file` still opens them. That is reasonable for build output, which is noise rather than secret. - -`.agentsignore` is for content the agent should not have at all, so it blocks reads and writes as well. Use `.gitignore` for noise, `.agentsignore` for secrets. - -## Limits - -> [!WARNING] -> `.agentsignore` governs the filesystem toolset. It is **not** a sandbox. -> -> An agent with the [`shell`](../../tools/shell/index.md) toolset can still run `cat secrets.env`, because the shell runs commands the toolset never inspects. The same applies to any toolset that reaches the filesystem on its own, such as [`lsp`](../../tools/lsp/index.md). -> -> Treat `.agentsignore` as a strong default that keeps sensitive files out of the agent's view and context — not as a boundary against an agent actively trying to reach them. When you need a real boundary, combine it with [permissions](../permissions/index.md) that restrict `shell`, or run in [sandbox mode](../sandbox/index.md). - -The derived permission rules are best-effort for the same reason: permission patterns match the argument string as the model wrote it, without resolving it first, so `./secrets.env` can slip past a rule written for `secrets.env`. The filesystem toolset's own check resolves paths first and is the part that actually enforces. - -## Example - -```text -# .agentsignore - -# Secrets -.env -.env.* -secrets.env -*.pem -*.key -!public.key # this one is safe to read - -# Credentials directories -.aws/ -.ssh/ - -# Large build output the agent doesn't need -build/ -dist/ -node_modules/ -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/budget/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/budget/index.md deleted file mode 100644 index 07086c2c5d8e..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/budget/index.md +++ /dev/null @@ -1,217 +0,0 @@ ---- -title: "Budget" -description: "Cap what a single run may spend in money, tokens, or working time." -keywords: docker agent, ai agents, configuration, yaml, budget, cost, limits -weight: 75 -canonical: https://docs.docker.com/ai/docker-agent/configuration/budget/ ---- - -_Cap what a single run may spend in money, tokens, or working time._ - -## Overview - -A budget sets ceilings on a run. When a ceiling is crossed the run stops with a message naming the exact limit that tripped, and the TUI tracks consumption live while the run is still going. - -Every limit is optional and an unset limit is unlimited, so you can cap money, tokens, time, or any combination. Declare no budget at all and runs are unbudgeted, which is the default. - -There are two ways to declare one, and they compose: - -| Block | Scope | -| --- | --- | -| `budget` | One run-wide ceiling, charged for every agent. | -| `budgets` | Named budgets an agent opts into by name. | - -### A run-wide budget - -```yaml -agents: - root: - model: openai/gpt-4o-mini - description: An agent on a short leash. - instruction: You are a helpful assistant. - -budget: - max_cost: 0.50 - max_tokens: 100000 - max_time: 10m -``` - -| Field | Type | Description | -| --- | --- | --- | -| `max_cost` | number | Maximum spend, in USD. | -| `max_tokens` | integer | Maximum cumulative input+output tokens. | -| `max_time` | string | Maximum time the agents spend working, in Go duration format (`10m`, `30s`, `1h30m`). | - -### Named budgets - -Define budgets by name under the top-level `budgets` key, then have each agent opt in by listing names in its own `budgets` field. The fields are the same three. - -```yaml -budgets: - shell-work: - max_cost: 0.03 - max_tokens: 8000 - research: - max_time: 1m - -agents: - root: - model: openai/gpt-4o-mini - description: Does shell work. - instruction: You are a helpful assistant. - budgets: [shell-work] - researcher: - model: openai/gpt-4o-mini - description: Answers questions. - instruction: You answer questions concisely. - budgets: [shell-work, research] -``` - -An agent may list several budgets; all of them apply, and the first to be exhausted stops the run. A run-wide `budget` applies on top of any named budget, so the ceiling that binds is whichever runs out first. - -Referencing a budget name that isn't defined is a config error, caught at parse time rather than silently leaving the agent uncapped. - -## A name is one shared pot - -When several agents reference the same budget name they draw from the **same** ceiling — not a copy each. Above, `root` and `researcher` share `shell-work`: together they cannot spend more than `$0.03`. - -This is deliberate, and it is the whole reason budgets are worth having. If each agent received its own allowance, a run could spend `max_cost` × N simply by fanning out to N sub-agents, and the ceiling would mean nothing for exactly the workloads that most need one. - -Give agents **distinct budget names** when you want independent pots. - -The same applies to the run-wide `budget`: every sub-session inside a run (transferred tasks, sub-agents, skills) spends from that one wallet. - -## Scope: a budget spans the session - -Spend accumulates for the life of the **session**, across every message you send — it does not reset each time you hit enter. A `max_cost: 0.50` you could re-spend on every message would not be a ceiling at all. - -Starting a new session starts a fresh budget. It is a per-session ceiling, not a lifetime quota across sessions. - -> [!NOTE] -> `max_time` measures the time the agents actually spend **working** — the sum of their turn durations — not wall-clock since the session opened. Because a budget spans a session, and a session sits idle while you read and type, wall-clock would let a budget expire during a coffee break: leave the TUI open for ten minutes and your next message would instantly trip a `max_time` of `2m` without the agent having done anything. - -## What stops a run - -Crossing any limit — run-wide or named — stops the run and produces: - -- an assistant message in the transcript naming the limit and the amounts, -- a `budget_exceeded` event carrying `budget`, `limit`, `used`, `max`, `config_path` and, under `stop_message`, the assistant stop message itself (agent name, role, content and timestamp only), -- a `notification` hook at `warning` level, -- a stream end reason of `budget_exceeded`, so a stopped run is distinguishable from a completed one in telemetry. - -The message names the exact YAML path to raise, so there is no ambiguity about which of several budgets tripped: - -```text -Execution stopped after reaching the configured budgets.shell-work.max_cost -limit (used $0.0312 of $0.0300). -``` - -Unlike [`max_iterations`](../agents/index.md), a budget stop is **terminal** — there is no prompt offering to continue. A budget is a ceiling you set deliberately, so raising it means editing the config rather than answering a dialog. - -## Budget stops in evaluation output - -When a budgeted agent is exercised with `docker agent eval`, a budget stop is recorded as a structured termination. It is not an error, and it is distinct from an ordinary stream stop: the run output JSON exposes it as an optional `eval_result.termination` object on the affected session. - -```json -"eval_result": { - "passed": true, - "termination": { - "reason": "budget_exceeded", - "budget": "run", - "limit": "max_cost", - "used": "$0.0312", - "max": "$0.0300", - "config_path": "budget.max_cost", - "message": "Execution stopped after reaching the configured budget.max_cost limit (used $0.0312 of $0.0300)." - } -} -``` - -- `reason` is always `budget_exceeded`. The other fields are optional and are copied from the runtime's `budget_exceeded` event through an allow-list: only `budget`, `limit`, `used`, `max`, `config_path`, and `message` are ever taken, each sanitized (invalid UTF-8 and control characters stripped, bounded length) and omitted when missing or unusable. -- The stored session (SQLite database and sessions JSON) keeps the stop marker at its chronological position, followed exactly once by the assistant stop message rebuilt from the event's embedded `stop_message` (again only agent name, role, content, and timestamp are taken, sanitized the same way). When the event carries no usable `stop_message`, the marker stands alone; nothing is invented from `termination.message`. -- The termination is informational: it does not change `passed`, `failures`, or `error`. A run that completed normally or failed with an error simply has no `termination` field, and older outputs written before the field existed load unchanged. - -## Tracking spend in the TUI - -The sidebar's Token Usage panel lists every active budget by name, with consumption against each ceiling it declares: - -```text -run $0.12/$0.50 · 12.3K/100.0K · 2m14s/10m -shell-work $0.09/$0.10 · 4.3K/20.0K -``` - -Only the ceilings you configured appear. Each reading is colored by the sidebar's shared gauge bands — the same ones a context gauge uses as it nears compaction — so a budget turns amber well before its ceiling and red just short of it, and a run about to be stopped is visible before it stops. - -For a per-agent view of who spent what, set **Sidebar info mode** to `Detailed` in `/settings` → Appearance: the Agents section then reports each agent's cost alongside its effort and context. The budget line deliberately does not repeat that breakdown — the same numbers twice would crowd the sidebar's narrowest column. The per-agent split is still carried on the `budget_usage` event for programmatic consumers, and `/cost` has a **By Agent** section. - -## Limits and caveats - -### Unpriced models do not count towards `max_cost` - -Only responses the runtime can price count towards `max_cost`. A model with no pricing data — an unknown model ID, or a custom endpoint such as a local or private deployment — contributes nothing, because there is no honest number to add. - -Such a run emits a warning and the TUI marks the reading `(unpriced spend)`, rather than silently reading low because the spend is invisible. To make a custom endpoint count, price it explicitly with a model-level [`cost`](../models/index.md#custom-token-pricing) block: - -```yaml -models: - local: - provider: openai - model: my-model - base_url: http://localhost:8000/v1 - cost: - input: 0.15 - output: 0.60 - -agents: - root: - model: local - description: A locally-served agent with real cost accounting. - instruction: You are a helpful assistant. - -budget: - max_cost: 0.50 -``` - -### Limits are checked at turn boundaries - -A run is checked between turns, so it can overshoot by at most the turn already in flight. `max_time` in particular will not interrupt a model call or tool that has already started; the run stops at the first boundary after the limit is reached. - -This is the same granularity [`max_iterations`](../agents/index.md) has, and it keeps the ceiling out of the streaming hot path. Set limits with a little headroom rather than at the exact number you cannot exceed. - -### `max_tokens` here is not the model's `max_tokens` - -The `max_tokens` in a budget is a **cumulative** count of input+output tokens across the whole run. It is unrelated to the provider- or model-level [`max_tokens`](../models/index.md), which caps the output of a single response. - -It is also not the session's context length: compaction resets that, while the budget keeps counting. - -## Examples - -Cap money only, and let the run take as long as it needs: - -```yaml -agents: - root: - model: openai/gpt-4o - description: A cost-capped agent. - instruction: You are a helpful assistant. - -budget: - max_cost: 5.00 -``` - -Cap working time for an unattended job: - -```yaml -agents: - root: - model: openai/gpt-4o-mini - description: A time-boxed agent. - instruction: You are a helpful assistant. - toolsets: - - type: shell - -budget: - max_time: 15m -``` - -See [`examples/budget.yaml`](https://github.com/docker/docker-agent/blob/main/examples/budget.yaml) for a runnable configuration. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/commands/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/commands/index.md deleted file mode 100644 index 1b621b1f1a6e..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/commands/index.md +++ /dev/null @@ -1,218 +0,0 @@ ---- -title: "Custom Commands" -description: "Define slash commands that send prompts, open URLs, or switch agents, and reuse them across agents with top-level command groups." -keywords: docker agent, ai agents, configuration, yaml, custom commands, slash commands -linkTitle: "Custom Commands" -weight: 55 -canonical: https://docs.docker.com/ai/docker-agent/configuration/commands/ ---- - -_Define slash commands that send prompts, open URLs, or switch agents._ - -## What Slash Commands Are - -A slash command is a named shortcut a user types in the TUI (`/df`, `/deploy`, `/plan`) or on the CLI (`docker agent run agent.yaml /df`) instead of typing out a full prompt. Every agent can declare its own commands under `commands:`, and top-level `commands:` groups let multiple agents share the same set without duplicating them. - -Unlike regular chat messages — which are queued while the agent is busy — slash commands (both built-in and named) execute immediately, even mid-response. - -Commands come in three shapes: - -| Shape | What it does | -| --- | --- | -| [Prompt command](#prompt-commands) | Sends a prompt to the current agent | -| [URL command](#url-commands) | Opens a link in the user's browser (full TUI only) | -| [Agent-switching command](#agent-switching-commands) | Switches the active agent, optionally with a prompt (full TUI and CLI) | - -> [!IMPORTANT] -> **Behavior differs by frontend** -> -> `url` and `agent` are only fully honored in the **full TUI**, which checks `url` before `agent` (a URL command opens the browser and stops there; an agent-switching command switches before sending any instruction). The **lean TUI** doesn't special-case either field — it only resolves a command's expanded text and sends it as a chat message, so a URL-only command silently sends whatever trailing text followed the slash (often nothing, opening no browser) and an agent-switching command sends its instruction to the *current* agent instead of the target. The **CLI** (`docker agent run agent.yaml /command`) switches agents like the full TUI, but has no browser to open, so `url` has no effect there. The **HTTP API** (`POST /api/sessions/:id/agent/:agent`) resolves agent-switching commands server-side: if the message content starts with a slash command whose `agent` field is set, the active agent is switched and the message is rewritten before the turn runs. Prompt-only and URL commands are not resolved server-side and pass through to the model unchanged. - -## Prompt Commands - -The simplest form: a string value that becomes the instruction sent to the current agent. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: A system administrator assistant. - instruction: You are a system administrator. - commands: - df: "Check how much free space I have on my disk" - logs: "Show me the last 50 lines of system logs" - greet: "Say hello to ${env.USER}" -``` - -For more control, use the object form with an `instruction:` field, plus an optional `description:` shown in completion dialogs and help text: - -```yaml -commands: - deploy: - description: "Deploy the application to staging" - instruction: "Deploy ${env.PROJECT_NAME || 'app'} to ${env.ENV || 'staging'}" -``` - -Commands support JavaScript template literal syntax (`${env.VAR}`) for environment variable interpolation, with optional `||` defaults and ternary expressions — the same syntax as agent `instruction` and `description`. Undefined variables expand to the empty string. See [Variable Expansion in Config Fields](../overview/index.md#variable-expansion-in-config-fields) for the full picture. - -Prompt commands can also reference the text typed after the slash and call tools, using the same `${...}` expansion engine as `${env.VAR}`: - -- `${args[0]}`, `${args[1]}`, … — individual positional arguments (whitespace-tokenized; quoted substrings keep their spaces together). -- `${args}` or `${args.join(" ")}` — the full argument list. -- `${tool_name({key: value, ...})}` — calls an agent tool and inlines its output. JS expressions are evaluated before tool commands, so tool output is never itself re-evaluated as JS. -- `` !tool_name(key=value) `` — legacy bang syntax for the same tool-call inlining; still supported alongside `${tool_name({...})}`. - -If `instruction` uses none of the `${args...}` placeholders, any text typed after the slash is appended to the resolved instruction automatically. - -```yaml -commands: - fix: - description: "Fix a file, with optional extra options" - instruction: "Fix the file ${args[0]} with options ${args[1]}" - run: - description: "Run a command with all the typed arguments" - instruction: 'Run command with args: ${args.join(" ")}' - lint: - description: "Show the current lint output" - instruction: 'Lint: ${shell({cmd: "task lint"})}' -``` - -```bash -# Run commands from the CLI too -$ docker agent run agent.yaml /df -$ docker agent run agent.yaml /greet -$ docker agent run agent.yaml /fix main.go --verbose -$ PROJECT_NAME=myapp ENV=production docker agent run agent.yaml /deploy -``` - -## URL Commands - -A command with a `url` field opens that URL in the user's default browser instead of sending a prompt to the agent. Any URI scheme the OS knows how to dispatch works — standard web URLs and custom schemes such as `docker-desktop://` for deep links. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: An agent with handy URL shortcuts. - instruction: You are a helpful assistant. - commands: - feedback: - description: "Open the feedback site for this session" - url: https://example.com/feedback?session={{session_id}} - docs: - description: "Open the documentation" - url: https://docs.docker.com/ - desktop: - description: "Open this session in Docker Desktop" - url: docker-desktop://dashboard/session/{{session_id}} -``` - -The `{{session_id}}` token is replaced at invocation time with the current session ID (URL-query-escaped so it can't break the URL or inject extra query parameters), letting a command deep-link to something scoped to the conversation. This token deliberately uses `{{...}}` rather than the `${...}` JS-expansion syntax, since the session ID is only known at dispatch time. - -URLs are validated before being handed to the OS opener: a parseable URL with a non-empty scheme is required, and flag-like inputs (those starting with `-`) are rejected to prevent argument injection. - -> [!NOTE] -> **Full TUI only** -> -> URL commands only open a browser in the full TUI. The CLI and lean TUI don't check the `url` field at all, so `docker agent run agent.yaml /docs` never opens a browser there — but the command is still dispatched: its resolved text (usually empty, for a URL-only command) is sent as a prompt and can trigger a model turn. - -See [`examples/url_commands.yaml`](https://github.com/docker/docker-agent/blob/main/examples/url_commands.yaml) for a complete example. - -## Agent-Switching Commands - -A command with an `agent` field switches the active agent for the rest of the conversation. This is useful for building workflow shortcuts where `/plan`, `/review`, `/deploy` each route the user to the right specialist. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Main assistant - instruction: You are a project coordinator. - sub_agents: [planner, reviewer] - commands: - # Switch to planner with a pre-filled prompt - plan: - agent: planner - instruction: "Create a detailed plan for: ${args.join(' ')}" - # Switch to reviewer; any text after /review is forwarded - review: - agent: reviewer - - planner: - model: anthropic/claude-sonnet-4-5 - description: Planning specialist - instruction: You create detailed project plans. - - reviewer: - model: anthropic/claude-sonnet-4-5 - description: Code review specialist - instruction: You review code and suggest improvements. -``` - -When `agent` is set **without** `instruction`, any text typed after the slash command (e.g. `/review fix the auth bug`) is forwarded as a prompt to the target agent. When both are set, the agent is switched first, then the instruction is sent to the new agent. Either way, the target can be **any agent defined in the team**, not just one of the current agent's own `sub_agents` — `sub_agents` above is shown because `planner` and `reviewer` also happen to be delegation targets, not because `agent:` requires it. - -Agent switching stays in the same session — the target agent sees the full conversation history, and the user must explicitly switch back (there's no automatic return). This is different from the two other ways agents hand off work: - -| | Agent-switching command | `handoff` tool | `transfer_task` | -| --- | --- | --- | --- | -| **Trigger** | User runs `/command` | Model calls `handoff()` | Model calls `transfer_task()` | -| **Session** | Stays in the same session | Stays in the same session | Launches an isolated sub-session | -| **History** | Target agent sees full conversation | Target agent sees full conversation | Child runs in isolation; only the result returns | -| **Control** | User must explicitly switch back | Target agent can chain to another agent | Root agent stays in control | - -Use `transfer_task` (via `sub_agents`) when you want delegation with a clean result; use agent-switching commands when you want to *become* a different agent for the rest of the conversation. - -See [`examples/agent_switching_commands.yaml`](https://github.com/docker/docker-agent/blob/main/examples/agent_switching_commands.yaml) for a complete example. - -## Reusable Command Groups - -Repeated command sets across agents can be hoisted into the top-level `commands:` section and pulled in by name with `use_commands:` — the same reuse pattern as `mcps:` for MCP servers and `toolsets:` for shared toolsets. - -```yaml -commands: - ci: - deploy: "Deploy the application" - test: "Run the test suite" - -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Lead developer - instruction: You are the lead developer. Coordinate the team. - use_commands: [ci] # reuse the "ci" command group - commands: - lint: "Run the linter" # inline command, merged in (wins on conflict) - - docs-writer: - model: anthropic/claude-sonnet-4-5 - description: Documentation writer - instruction: You write and maintain the project documentation. - use_commands: [ci] # same group, reused without duplication -``` - -An agent's own inline `commands:` entries take precedence over merged `use_commands:` entries on name conflicts. See [`examples/shared-commands-skills.yaml`](https://github.com/docker/docker-agent/blob/main/examples/shared-commands-skills.yaml) for a complete example that also covers the equivalent `skills:` / `use_skills:` pattern. - -## Hiding Commands - -Use `--disable-commands` to hide and disable specific slash commands in the TUI — built-in ones (`/cost`, `/eval`, `/model`, …) or your own named ones. Accepts a comma-separated list; the leading slash is optional and matching is case-insensitive. - -```bash -$ docker agent run agent.yaml --disable-commands="/cost,/eval,/model" -``` - -This is useful for shipping a distributed agent with a narrower command surface — for example, hiding `/model` so a published agent always runs its intended model. - -## Built-in Commands - -The TUI ships its own slash commands (`/new`, `/compact`, `/sessions`, `/settings`, …) alongside whatever an agent defines. See [Slash Commands](../../features/tui/index.md#slash-commands) in the TUI reference for the full list. - -## Command Configuration Reference - -| Property | Type | Description | -| --- | --- | --- | -| `description` | string | Shown in completion dialogs and help text. | -| `instruction` | string | The prompt sent to the agent. Supports argument expansion (`${args[0]}`, `${args.join(" ")}`, …), tool calls (`${tool_name({...})}`), and the legacy bang syntax `!tool_name(...)`. | -| `agent` | string | Name of an agent in the team to switch to when this command is invoked — any agent in the team's `agents:` map, not just one of the current agent's `sub_agents`. When set without `instruction`, any text typed after the slash command is forwarded as a prompt to the target agent. | -| `url` | string | URL to open in the user's default browser when this command is invoked, instead of sending a prompt to the agent (full TUI only — see [URL Commands](#url-commands)). The token `{{session_id}}` is replaced at invocation time with the current session ID (URL-query-escaped). | - -`instruction` and `agent` can be combined (the agent is switched first, then the instruction is sent to the new agent). In the full TUI, if `url` is set, it takes precedence over `agent` and `instruction` — the command only opens the browser; the lean TUI and CLI don't check `url` at all, so a URL-only command instead sends its (usually empty) resolved text as a prompt. See [Behavior differs by frontend](#what-slash-commands-are) above. The simple string form is shorthand for `{ instruction: "..." }`. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/flavors/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/flavors/index.md deleted file mode 100644 index 05be0fcf499b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/flavors/index.md +++ /dev/null @@ -1,172 +0,0 @@ ---- -title: "Flavors" -description: "Ship one agent file with named variants, enabled at run time as YAML patches." -keywords: docker agent, ai agents, configuration, yaml, flavors, patch, variants, overrides -weight: 95 -canonical: https://docs.docker.com/ai/docker-agent/configuration/flavors/ ---- - -_Ship one agent file with named variants, enabled at run time as YAML patches._ - -## Overview - -A flavor is a named YAML patch declared in the agent file itself, under the -top-level `flavors` section. Enabling a flavor applies its patch on top of the -rest of the document before the config is parsed, so one file can carry -several variants — a cheaper model for local runs, extra tools for CI, a more -verbose instruction for debugging — without duplicating the whole config. - -```yaml -agents: - root: - model: claude - instruction: You are a helpful assistant. - -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - -flavors: - cheap: - models: - claude: - model: claude-3-5-haiku-latest -``` - -Enable flavors with the repeatable `--flavor` flag: - -```bash -$ docker agent run agent.yaml --flavor cheap -``` - -The flag works on every command that runs an agent — `run`, `chat`, `eval`, -`serve api`, `serve a2a`, `serve mcp` — and order matters: patches apply in -the order the flavors are requested, each on top of the previous result. - -```bash -$ docker agent run agent.yaml --flavor cheap --flavor verbose -``` - -Flavors the file does not define are ignored (with a debug log), so you can -enable the same flavor set across a fleet of agents and each file only reacts -to the names it declares. External sub-agents loaded from OCI or URL -references receive the same enabled flavors. - -## Merge Semantics - -Patches follow [JSON Merge Patch](https://www.rfc-editor.org/rfc/rfc7386) -semantics, with two extensions for arrays: - -| Patch value | Effect | -| --- | --- | -| Object | Merged recursively into the existing object. | -| Scalar or array | Replaces the existing value. | -| `null` | Deletes the key. | -| Key ending in `+` | Appends the items to the existing array. | -| Key ending in `-` | Removes matching entries from an array or object. | - -### Merging and replacing - -An object patch only touches the keys it names — siblings survive: - -```yaml -flavors: - verbose: - agents: - root: - instruction: Explain your reasoning in detail. # model, tools, ... unchanged -``` - -### Deleting a key - -Set it to `null`: - -```yaml -flavors: - no-limit: - models: - claude: - max_tokens: null -``` - -### Appending to an array - -Plain arrays replace wholesale. To add entries instead, suffix the key -with `+`: - -```yaml -agents: - root: - toolsets: - - type: think - -flavors: - with-shell: - agents: - root: - toolsets+: - - type: shell -``` - -With `--flavor with-shell` the root agent gets both `think` and `shell`. - -### Removing entries - -Suffix the key with `-`. Each item in the patch value selects what to remove: - -- From an **array**: a scalar removes equal elements; an object removes every - element it partially matches (all of the matcher's keys must be present - with matching values). -- From an **object**: items are key names to drop. - -```yaml -flavors: - slim: - agents: - root: - toolsets-: - - type: shell # drop every shell toolset, however configured - sub_agents-: - - checker # drop by value - models-: - - spare # drop the named model definition -``` - -> [!NOTE] -> The `+` and `-` suffixes are reserved inside flavor patches: a patch cannot -> set a literal key ending in either character. Base documents are unaffected. - -## Inspecting the Result - -`docker agent debug config` prints the config exactly as the runtime sees it, -flavors applied: - -```bash -$ docker agent debug config agent.yaml --flavor cheap --flavor with-shell -``` - -## HCL - -Flavors work in [HCL configs](../hcl/index.md) too, as labeled blocks. The -append/remove operators need quoted attribute names inside object -expressions: - -```hcl -flavors "with-shell" { - agents = { - root = { - "toolsets+" = [{ type = "shell" }] - } - } -} -``` - -## Notes - -- Flavors require config schema version 13 or later; older versions reject - the `flavors` key with a hint to bump the top-level `version` field. -- Patches apply before validation, so a flavored config is validated exactly - like a hand-written one. -- `docker agent push` publishes the raw document, `flavors` section included, - so consumers of a pushed agent can enable its flavors too. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/hcl/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/hcl/index.md deleted file mode 100644 index 7a465e47a1c0..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/hcl/index.md +++ /dev/null @@ -1,306 +0,0 @@ ---- -title: "HCL Configuration" -description: "Write Docker Agent configs in HCL instead of YAML, using labeled blocks, heredocs, and the same underlying schema." -keywords: docker agent, ai agents, configuration, yaml, hcl configuration -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/configuration/hcl/ ---- - -_Write Docker Agent configs in HCL instead of YAML. It maps to the same Docker Agent schema and validation rules._ - -`docker-agent` supports `.hcl` config files anywhere it supports `.yaml` or `.yml` files. HCL is useful if you prefer labeled blocks, less punctuation, and heredocs for long prompts. - -> [!TIP] -> **Same config model, different syntax** -> -> YAML and HCL are just two syntaxes for the same Docker Agent configuration model. Docker Agent converts HCL to the equivalent YAML structure internally, then runs the normal schema validation and loading pipeline. - -## Minimal Example - -```hcl -#!/usr/bin/env docker agent run - -agent "root" { - model = "openai/gpt-5" - description = "A helpful assistant" - instruction = <<-EOT - You are a helpful assistant. - EOT - - toolset "think" {} -} -``` - -Run it exactly like a YAML config: - -```bash -$ docker agent run agent.hcl -$ docker agent run --exec agent.hcl "Summarize this repository" -$ docker agent serve api ./agents/ # directories may mix .yaml, .yml, and .hcl files -``` - -> [!TIP] -> **See also** -> -> HCL changes the syntax, not the meaning of fields. For what each field does, see [Agent Config](../agents/index.md), [Model Config](../models/index.md), and [Tool Config](../tools/index.md). - -## YAML vs HCL - -These two configs are equivalent: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - -agents: - root: - model: claude - description: Coding assistant - instruction: You help with software development. - toolsets: - - type: filesystem - - type: shell -``` - -```hcl -model "claude" { - provider = "anthropic" - model = "claude-sonnet-4-5" -} - -agent "root" { - model = "claude" - description = "Coding assistant" - instruction = "You help with software development." - - toolset "filesystem" {} - toolset "shell" {} -} -``` - -## Core Conventions - -HCL follows a few simple mapping rules: - -| HCL syntax | YAML shape | -| --- | --- | -| `agent "root" { ... }` | `agents.root` | -| `model "claude" { ... }` | `models.claude` | -| `provider "team" { ... }` | `providers.team` | -| `mcp "github" { ... }` | `mcps.github` | -| `rag "docs" { ... }` | `rag.docs` | -| `command "fix" { ... }` inside an agent | `commands.fix` | -| `toolset "shell" {}` | list item in `toolsets` with `type: shell` | -| `metadata { ... }`, `permissions { ... }` | singleton blocks with the same top-level name | - -### Top-level keyed maps become labeled blocks - -In YAML, several sections are maps keyed by name. In HCL, those become labeled blocks: - -```hcl -model "claude" { - provider = "anthropic" - model = "claude-sonnet-4-5" -} - -agent "root" { - model = "claude" - description = "Primary assistant" - instruction = "You are helpful." -} -``` - -The supported top-level labeled blocks are: - -- `agent` -- `model` -- `provider` -- `mcp` -- `rag` - -The supported top-level singleton blocks are: - -- `metadata` -- `permissions` - -### Toolsets use the block label as `type` - -Instead of writing list entries with `type: ...`, HCL uses a `toolset` block whose label becomes the tool type: - -```hcl -agent "root" { - model = "openai/gpt-5" - description = "Dev assistant" - instruction = "You can inspect and modify code." - - toolset "filesystem" {} - - toolset "mcp" { - ref = "docker:github-official" - } -} -``` - -### Commands use labeled blocks too - -Agent commands are often nicer to write in HCL because each command gets its own block: - -```hcl -agent "root" { - model = "openai/gpt-5" - description = "Build helper" - instruction = "You help with builds." - - command "fix-lint" { - description = "Fix lint issues" - instruction = "Run the linter, then fix any problems." - } -} -``` - -## Strings and Heredocs - -Use quoted strings for short values and heredocs for long prompts, welcome messages, or embedded JSON. - -```hcl -agent "root" { - model = "openai/gpt-5" - description = "Friendly assistant" - - instruction = <<-EOT - You are a helpful assistant. - - Keep answers concise and practical. - EOT -} -``` - -### Escaping literal `${...}` - -HCL treats `${...}` inside strings and heredocs as template interpolation. If you need the literal text `${...}` in your prompt, escape it as `$${...}`. - -This matters for command prompts that intentionally show Docker Agent template snippets: - -```hcl -command "fix-lint" { - instruction = <<-EOT - Run the linter and inspect the result: - - $${shell({cmd: "task lint"})} - EOT -} -``` - -The model will receive the literal `${shell({cmd: "task lint"})}` text. - -## Loading Files with `file()` - -The `file()` function reads a UTF-8 text file and returns its contents as a string. Relative paths are resolved from the HCL config file's directory, and reads are restricted to that directory. - -This keeps long prompts out of the config: - -```hcl -agent "root" { - model = "openai/gpt-5" - description = "Coding assistant" - instruction = file("prompts/coding.md") -} -``` - -With a single argument, the file contents are returned exactly as written — any `${...}` in the file stays literal, so runtime snippets like `${shell({cmd: "..."})}` pass through untouched. - -### Rendering files as templates - -Pass an object as the second argument to render the file as an HCL template. Each key becomes a variable available inside the file: - -```hcl -agent "reviewer" { - model = "openai/gpt-5" - description = "Go reviewer" - instruction = file("prompts/reviewer.md", { - language = "Go" - strictness = "high" - }) -} - -agent "py_reviewer" { - model = "openai/gpt-5" - description = "Python reviewer" - instruction = file("prompts/reviewer.md", { - language = "Python" - strictness = "relaxed" - }) -} -``` - -With `prompts/reviewer.md` containing: - -```markdown -You review ${language} code with ${strictness} strictness. -``` - -Templates support the full HCL template syntax, including `%{ for }` and `%{ if }` directives: - -```markdown -Rules: -%{ for rule in rules ~} -- ${rule} -%{ endfor ~} -``` - -Two things to keep in mind: - -- Referencing a variable that is not in the object is an error. -- No functions are available inside templates, so a template cannot call `file()` again. If the file needs a literal `${...}` while being rendered as a template, escape it as `$${...}` inside the file. - -## Repeated Blocks Become Lists - -Some YAML sections are lists. In HCL, those are written as repeated blocks. - -For example, model routing rules become repeated `routing { ... }` blocks: - -```hcl -model "smart_router" { - provider = "openai" - model = "gpt-5" - - routing { - model = "anthropic/claude-sonnet-4-5" - examples = [ - "Write a detailed technical document", - "Review this code for security issues", - ] - } - - routing { - model = "openai/gpt-5" - examples = [ - "Generate some creative ideas", - "Help me brainstorm", - ] - } -} -``` - -The same idea applies to other list-shaped sections such as RAG `strategy` blocks and hook event entries. - -## Important Differences from Terraform - -Docker Agent uses HCL as a configuration syntax, not as Terraform: - -- There are no modules, `locals`, or `variable` blocks. -- The only function available in expressions is [`file()`](#loading-files-with-file); Terraform's function library (including `templatefile()`, which `file()` with a vars object replaces) is not available. -- Prefer normal literal values: strings, numbers, booleans, lists, objects, and nested blocks. -- After conversion, the result is validated exactly like the equivalent YAML config. - -If you already know Terraform, think of Docker Agent HCL as a thin block-based syntax over the existing config schema. - -## Examples - -See these real configs in the repository: - -- [`examples/pirate.hcl`](https://github.com/docker/docker-agent/blob/main/examples/pirate.hcl) -- [`examples/gopher.hcl`](https://github.com/docker/docker-agent/blob/main/examples/gopher.hcl) -- [`examples/instructions_from_file.hcl`](https://github.com/docker/docker-agent/blob/main/examples/instructions_from_file.hcl) diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/hooks/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/hooks/index.md deleted file mode 100644 index 34efe9d2b8e4..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/hooks/index.md +++ /dev/null @@ -1,952 +0,0 @@ ---- -title: "Hooks" -description: "Run shell commands at various points during agent execution for deterministic control over behavior." -keywords: docker agent, ai agents, configuration, yaml, hooks -weight: 60 -canonical: https://docs.docker.com/ai/docker-agent/configuration/hooks/ ---- - -_Run shell commands at various points during agent execution for deterministic control over behavior._ - -## Overview - -Hooks allow you to execute shell commands or scripts at key points in an agent's lifecycle. They provide deterministic control that works alongside the LLM's behavior, enabling validation, logging, environment setup, and more. - -> [!NOTE] -> **Use Cases** -> -> - Validate or transform tool inputs before execution -> - Log all tool calls to an audit file -> - Block dangerous operations based on custom rules -> - Validate, redact, or enrich user prompts before they reach the model -> - Programmatically approve or deny tool calls without prompting the user -> - Steer or veto context-window compaction -> - Audit sub-agent handoffs in multi-agent setups -> - Set up the environment when a session starts -> - Clean up resources when a session ends -> - Log or validate model responses before returning to the user -> - Send external notifications on agent errors or warnings - -## Hook Types - -Docker Agent dispatches the following hook events: - -| Event | When it fires | Can block? | -| --------------------------- | --------------------------------------------------------------------------------- | ---------- | -| `pre_tool_use` | Before a tool call executes | Yes | -| `tool_response_transform` | Between a tool's execution and the runtime's emission/record of the response | No | -| `post_tool_use` | After a tool completes — fires for both success and failure | Yes | -| `permission_request` | Just before the runtime would prompt the user to approve a tool | Yes | -| `session_start` | When a session begins or resumes | No | -| `user_prompt_submit` | Once per user message, after submission and before the model runs | Yes | -| `user_steering_messages_submit` | Each time queued steering messages are drained (mid-turn, after stop, or while idle) | Yes | -| `user_followup_submit` | Each time a queued follow-up message starts a fresh turn (end-of-turn) | Yes | -| `turn_start` | At the start of every agent turn (each model call) | No | -| `turn_end` | At the end of every agent turn — fires no matter why the turn ended | No | -| `before_llm_call` | Just before every model call (after `turn_start`) | Yes | -| `after_llm_call` | After every successful model call, before the response is recorded | No | -| `session_end` | When a session terminates | No | -| `pre_compact` | Just before the runtime compacts the session transcript | Yes | -| `before_compaction` | Just before a compaction runs — can veto or supply a custom summary | Yes | -| `after_compaction` | After a successful compaction (summary applied to the session) | No | -| `subagent_stop` | When a sub-agent (transferred task / background / skill sub-session) finishes | No | -| `on_user_input` | When the agent is waiting for user input | No | -| `stop` | When the model finishes responding | No | -| `notification` | When the agent emits a notification (error or warning) | No | -| `on_error` | When the runtime hits an error during a turn (fires alongside `notification`) | No | -| `on_max_iterations` | When the runtime reaches its configured `max_iterations` limit | No | -| `on_agent_switch` | When the runtime moves the active agent (transfer_task, handoff, return) | No | -| `on_session_resume` | When the user explicitly approves continuation past `max_iterations` | No | -| `on_tool_approval_decision` | After the runtime's approval chain (permissions / yolo / readonly / ask) resolves | No | -| `worktree_create` | After `docker agent run --worktree` creates a git worktree, before the session | Yes | - -> [!NOTE] -> **Two compaction events** -> -> `pre_compact` and `before_compaction` both fire just before a compaction. `pre_compact` is the original event and is best-suited to _steering_ the LLM-generated summary by appending guidance via `additional_context`. `before_compaction` is the newer, structured event: it carries the input/output token counts, the model's context limit, and a `compaction_reason` so handlers can decide based on real session pressure, and it can _replace_ the LLM-generated summary verbatim via `hook_specific_output.summary`. - -## Configuration - -You can configure hooks directly in an agent YAML file under the agent's `hooks:` block: - -```yaml -agents: - root: - model: openai/gpt-4o - description: An agent with hooks - instruction: You are a helpful assistant. - hooks: - # Run before specific tools - pre_tool_use: - - matcher: "shell|edit_file" - hooks: - - type: command - command: "./scripts/validate-command.sh" - timeout: 30 - - # Run after all tool calls - post_tool_use: - - matcher: "*" - hooks: - - type: command - command: "./scripts/log-tool-call.sh" - - # Run when session starts - session_start: - - type: command - command: "./scripts/setup-env.sh" - - # Run when session ends - session_end: - - type: command - command: "./scripts/cleanup.sh" - - # Run when agent is waiting for user input - on_user_input: - - type: command - command: "./scripts/notify.sh" - - # Run when the model finishes responding - stop: - - type: command - command: "./scripts/log-response.sh" - - # Run on agent errors and warnings - notification: - - type: command - command: "./scripts/alert.sh" -``` - -Each event takes a list of hooks. A single hook can also be written directly -as a mapping, without the list dash: - -```yaml -stop: - type: command - command: "./scripts/log-response.sh" -``` - -## Global (user-level) hooks - -Global hooks let you apply the same hook configuration to every agent you run. Define them in your user config file at `~/.config/cagent/config.yaml` under `settings.hooks`: - -```yaml -# ~/.config/cagent/config.yaml -settings: - hooks: - session_start: - - type: command - command: "~/.config/cagent/hooks/session-start.sh" - pre_compact: - - type: command - command: "~/.config/cagent/hooks/pre-compact.sh" - pre_tool_use: - - matcher: "shell" - hooks: - - type: command - command: "~/.config/cagent/hooks/check-shell.sh" -``` - -Global hooks use the same schema as agent-level hooks and are additive. If an event is configured in multiple places, all matching hooks run in this order: - -1. Agent-config hooks from the agent YAML -2. Global hooks from `settings.hooks` -3. Hook drop-ins from `/hooks.d/` (lexicographic file order) -4. CLI hooks from `--hook-*` flags - -Global hooks cannot be suppressed by an individual agent. Use them for user-wide audit logging, personal guardrails, notifications, and setup/cleanup behavior that should apply everywhere. - -### Hook drop-in files (`hooks.d`) - -External tools that integrate with Docker Agent (terminal emulators, IDEs, audit or observability sidecars) shouldn't have to rewrite your `config.yaml` to install a hook. Instead, Docker Agent also loads every `*.yaml` / `*.yml` file from the `hooks.d` directory next to your user config (default: `~/.config/cagent/hooks.d/`). Each file is a standalone hooks block with the same schema as the content of `settings.hooks`: - -```yaml -# ~/.config/cagent/hooks.d/50-mytool.yaml -session_start: - - type: command - command: mytool notify --event session-start -stop: - - type: command - command: mytool notify --event stop -``` - -- Files are loaded in lexicographic order and merged additively after `settings.hooks` (use numeric prefixes like `10-`, `50-` to control ordering). -- A malformed file is skipped with a logged warning; a broken drop-in never breaks a run. -- Installing an integration means writing one self-contained file; uninstalling means deleting it. No shared-file edits, no conflicts between tools. - -The config directory can be relocated with the `--config-dir` flag or the `DOCKER_AGENT_CONFIG_DIR` (legacy `CAGENT_CONFIG_DIR`) environment variable, which external tools can use to locate `hooks.d` under non-default config dirs. - -## Built-in Hooks - -In addition to shell `command` hooks, Docker Agent ships a small library of **built-in hooks** — in-process Go functions that run without spawning a subprocess. They're invoked with `type: builtin`, where `command` is the builtin's registered name and `args` are passed through as the builtin's parameters. - -```yaml -hooks: - turn_start: - - type: builtin - command: add_date - - type: builtin - command: add_prompt_files - args: - - GUIDELINES.md - - PROJECT.md - session_start: - - type: builtin - command: add_environment_info - before_llm_call: - - type: builtin - command: max_iterations - args: ["50"] -``` - -Built-ins are typically zero-config and faster than equivalent shell hooks because they don't fork a process. They cover the common "inject context into every turn / session" patterns out of the box. - -### Available built-ins - -| Builtin | Event | Args | What it does | -| ----------------------- | ----------------------------------------------------------------------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `add_date` | `turn_start` | _none_ | Prepends `Today's date: YYYY-MM-DD` so the model always knows the current date. | -| `add_environment_info` | `session_start` | _none_ | Adds the working directory, git-repo status, OS, and CPU architecture. | -| `add_prompt_files` | `turn_start` | `[file1, file2, ...]` | Reads each named file from the workdir hierarchy (walking up) and the home directory, and appends their contents. | -| `add_git_status` | `turn_start` | _none_ | Adds the output of `git status --short --branch` (no-op outside a git repo or when git isn't installed). | -| `add_git_diff` | `turn_start` | _none_, or `["full"]` | Adds `git diff --stat` by default. Pass `args: ["full"]` to emit the full unified diff. Output is capped to 4 KB. | -| `add_directory_listing` | `session_start` | _none_ | Adds an alphabetical listing of the cwd's top-level entries (skips dot-files, capped at 100 with a "... and N more"). | -| `add_user_info` | `session_start` | _none_ | Adds the current OS user (username and full name) and the hostname. | -| `add_recent_commits` | `session_start` | _none_, or `[""]` | Adds `git log --oneline -n N`. `N` defaults to 10; pass a positive integer to override. | -| `max_iterations` | `before_llm_call` | `[""]` (required) | Hard-stops the agent after `N` model calls. Stateless: the runtime supplies the iteration counter on every dispatch. | -| `snapshot` | `session_start`, `turn_start`, `turn_end`, `pre_tool_use`, `post_tool_use`, `session_end` | _none_ | Records filesystem snapshots in a shadow git repo under the Docker Agent data directory. No-op outside git repos; respects the source repo's ignore rules and skips newly-added files larger than 2 MiB. | -| `redact_secrets` | `pre_tool_use`, `before_llm_call`, `tool_response_transform` | _none_ | Scrubs detected secrets (API keys, tokens, private keys, …) out of tool call arguments, outgoing chat content, and tool output. The same builtin handles all three events and dispatches on the event name. Auto-registered on all three events by `redact_secrets: true` on the agent — see [`examples/redact_secrets_hooks.yaml`](https://github.com/docker/docker-agent/blob/main/examples/redact_secrets_hooks.yaml) for the manual wiring. | -| `limit_large_tool_results` | `tool_response_transform`, `session_end` | _none_ | **Always-on safety hook** — automatically injected by the runtime, no configuration required. When a tool result from the `filesystem`, `shell`, `mcp`, or `a2a` categories exceeds 2,000 lines or 50 KiB, the full payload is written to a per-session temp file and replaced in the conversation with a notice plus a bounded excerpt (2,000 lines, up to 50 KiB): the tail for most tools, but the head for the built-in filesystem `read_file`, whose notice suggests a follow-up call with `line`/`limit` to continue reading. The `session_end` leg deletes the temp directory. Internal toolsets (`memory`, `plan`, `tasks`, `think`, …) are not affected. | -| `safer_shell` | `pre_tool_use` | _none_ | **Deprecated compatibility shim.** The runtime now classifies every shell command natively (`safe` / `destructive` / `unknown`) and gates it through the session's [safety mode](../permissions/index.md#safety-modes), so this builtin no longer emits verdicts. Pinned entries keep working as pure labellers that attach classification metadata (`safety_label`, `blast_radius`, `category`, `reason`) to the call. Filters by tool name internally (no-op for non-shell calls). | -| `unload` | `on_agent_switch` | _none_ | POSTs `{"model": ""}` to each of the previous agent's DMR model endpoints (`/_unload` by default, overridable per-model via `unload_api`) to free the GPU/RAM the just-departing model was holding. Pure HTTP — reads the model snapshot the runtime ships on `on_agent_switch` and depends on no provider-specific runtime state. Non-DMR providers (OpenAI, Anthropic, …) are silently skipped, so cross-provider chains are safe. Errors are logged and swallowed; agent switching never blocks on a slow or unreachable engine (each call has a 10 s timeout). See [`examples/unload_on_switch.yaml`](https://github.com/docker/docker-agent/blob/main/examples/unload_on_switch.yaml). | - -> [!NOTE] -> **Per-turn vs. per-session** -> -> `turn_start` built-ins recompute every turn and contribute **transient** context that is _not_ persisted to the session — perfect for fast-moving signals like the date or current git state. `session_start` built-ins run once per session and their context **persists** across turns and resumes — pick this for stable context like the OS user or the initial directory listing. - -> [!NOTE] -> **Auto-injected built-ins** -> -> The agent flags `add_date: true`, `add_environment_info: true`, `add_prompt_files: [...]`, and `redact_secrets: true` are shorthands that auto-register the matching built-in hook. You don't need to repeat them under `hooks:` — set the flag _or_ the hook entry(ies), not both. `redact_secrets: true` auto-registers the same builtin on all three of `pre_tool_use`, `before_llm_call`, and `tool_response_transform`; you can also wire any subset of them by hand for finer-grained control (per-tool matchers, ordering with other rewriters, …). -> -> `limit_large_tool_results` is injected unconditionally by the runtime — it is always active and cannot be removed from config. - -A minimal snapshot wiring looks like this: - -```yaml -hooks: - turn_start: - - type: builtin - command: snapshot - turn_end: - - type: builtin - command: snapshot - session_end: - - type: builtin - command: snapshot -``` - -The shadow repository stores tree objects only; it never writes commits or touches the source repository's `.git` directory. The source repository's `.gitignore` and `info/exclude` rules are mirrored before each capture so ignored files do not appear in snapshots. The built-in only records undo checkpoints when files changed, so a final no-op model response does not hide the last changed snapshot. - -You can also enable snapshots globally for every agent with user config: - -```yaml -settings: - snapshot: true -``` - -Omit `snapshot` or set it to `false` to leave automatic snapshots off; manually configured snapshot hooks still run. - -See [`examples/snapshot_hooks.yaml`](https://github.com/docker/docker-agent/blob/main/examples/snapshot_hooks.yaml) for a complete snapshot hook configuration. For an overview of the snapshot feature and the `/undo` / `/snapshots` commands, see [Snapshots](../../features/snapshots/index.md). - -> [!WARNING] -> **Two flavors of `max_iterations`** -> -> The `max_iterations` agent field has its own UX (it pauses and asks the user to resume past the limit). The `max_iterations` built-in hook is a **hard stop with no resume** — when its counter trips, the agent terminates with a block decision. Use the agent field for interactive sessions and the built-in hook to enforce non-negotiable caps in unattended runs. - -## Matcher Patterns - -The `matcher` field uses regex patterns to match tool names: - -| Pattern | Matches | -| ------------------ | ----------------------------- | -| `*` | All tools | -| `shell` | Only the `shell` tool | -| `shell\|edit_file` | Either `shell` or `edit_file` | -| `mcp:.*` | All MCP tools (regex) | - -## Hook Input - -Hooks receive JSON input via stdin with context about the event: - -```json -{ - "session_id": "abc123", - "cwd": "/path/to/project", - "hook_event_name": "pre_tool_use", - "tool_name": "shell", - "tool_use_id": "call_xyz", - "tool_input": { - "cmd": "rm -rf /tmp/cache", - "cwd": "." - } -} -``` - -### Common Fields - -Every hook event carries: - -| Field | Description | -| ----------------- | ------------------------------------- | -| `session_id` | The current session's ID. | -| `cwd` | The runtime's working directory. | -| `hook_event_name` | The event name (e.g. `pre_tool_use`). | - -### Per-Event Extra Fields - -In addition to the common fields, each event ships its own payload: - -| Event | Extra fields | -| --------------------------- | --------------------------------------------------------------------------------------------------------------------- | -| `pre_tool_use` | `agent_name`, `tool_name`, `tool_use_id`, `tool_input` | -| `tool_response_transform` | `tool_name`, `tool_use_id`, `tool_input`, `tool_response` | -| `post_tool_use` | `agent_name`, `tool_name`, `tool_use_id`, `tool_input`, `tool_response`, `tool_error` | -| `permission_request` | `agent_name`, `tool_name`, `tool_use_id`, `tool_input` | -| `session_start` | `source` — one of `startup`, `resume`, `clear`, `compact` | -| `user_prompt_submit` | `prompt` — the text the user just submitted | -| `user_steering_messages_submit` | `steering_messages` — the drained steering messages, in submission order | -| `user_followup_submit` | `prompt` — the text of the dequeued follow-up message | -| `turn_start` | _none_ (just the common fields) | -| `turn_end` | `agent_name`, `reason` — one of `normal`, `continue`, `steered`, `error`, `canceled`, `hook_blocked`, `loop_detected` | -| `before_llm_call` | `iteration` — 1-based run-loop iteration counter (the model call this hook is gating), `model_id` | -| `after_llm_call` | `agent_name`, `stop_response`, `last_user_message`, `model_id`, `usage`, `cost` | -| `session_end` | `reason` — one of `clear`, `logout`, `prompt_input_exit`, `other` | -| `pre_compact` | `source` — one of `manual`, `auto`, `overflow`, `tool_overflow` | -| `before_compaction` | `input_tokens`, `output_tokens`, `context_limit`, `compaction_reason` (one of `threshold`/`overflow`/`manual`) | -| `after_compaction` | `input_tokens`, `output_tokens`, `context_limit`, `compaction_reason`, `summary` | -| `subagent_stop` | `agent_name` (the sub-agent), `parent_session_id`, `stop_response` | -| `on_user_input` | _none_ | -| `stop` | `agent_name`, `stop_response`, `last_user_message` | -| `notification` | `notification_level` (`error` or `warning`), `notification_message` | -| `on_error` | `notification_level` (always `error`), `notification_message` | -| `on_max_iterations` | `notification_level` (always `warning`), `notification_message` | -| `on_agent_switch` | `from_agent`, `to_agent`, `agent_switch_kind` (`transfer_task`, `transfer_task_return`, `handoff`, or `force_handoff`) | -| `on_session_resume` | `previous_max_iterations`, `new_max_iterations` | -| `on_tool_approval_decision` | `tool_name`, `tool_use_id`, `tool_input`, `approval_decision`, `approval_source` | -| `worktree_create` | `worktree_path`, `worktree_branch`, `worktree_source_dir` (`cwd` is also set to the new worktree) | - -Notes: - -- `tool_response` for `post_tool_use` carries the tool's result; `tool_error` is `true` when the tool failed (the failure detail is surfaced inside `tool_response`). -- `agent_name` on `pre_tool_use`, `post_tool_use`, and `permission_request` identifies the agent that issued the tool call — in multi-agent setups this follows the active sub-agent, not always the root agent. -- `prompt` is only populated for `user_prompt_submit`. Sub-sessions (transferred tasks, background agents, skills) do **not** fire this event because their kick-off message is synthesised by the runtime, not authored by the user. -- `steering_messages` is only populated for `user_steering_messages_submit`. It carries the user messages the runtime just drained from the steering queue — messages submitted while the agent was already working (mid-turn, after the model stopped, or while idle before the first model call). -- `prompt` is also populated for `user_followup_submit`, carrying the text of the dequeued follow-up message (a user message queued for end-of-turn processing via the FollowUp API / queue, as opposed to mid-turn steering). -- `stop_response` carries the model's final assistant text for `stop`, `after_llm_call`, and `subagent_stop`. `last_user_message` carries the latest user message at dispatch time. -- `model_id` is populated for `after_llm_call` (and `before_llm_call`) in the canonical `/` form (e.g. `anthropic/claude-sonnet-4-5`). For harness agents, `model_id` is the harness label (e.g. `claude-code`) rather than a canonical model name — see [Coding Harnesses](../../features/harnesses/index.md). -- `usage` and `cost` are populated for `after_llm_call` only. `usage` is the per-call token usage object (`input_tokens`, `output_tokens`, `cached_input_tokens`, `cached_write_tokens`, and `reasoning_tokens` — the last is itself omitted for non-reasoning models); the whole object is absent when the provider reported no usage. `cost` is the USD price of that one model response. For a **native model call** it is the price computed from `usage` and the model's pricing table, and equals the cost the session records for the turn: it is **absent** when the response is unpriced (no pricing data on file, or no usage) and an explicit `0` for a priced call that was free — so a present `cost` is authoritative and an absent one means "unpriced", with no need to cross-check `usage`. Models the catalogue does not price (custom endpoints, local models) can be priced explicitly with the model-level [`cost`](../models/index.md#custom-token-pricing) config. (For harness agents the meaning differs — see the next note.) A cost ledger can therefore record per-call spend from the payload alone, without subscribing to the runtime event channel. -- For [harness agents](../../features/harnesses/index.md), `cost` is the harness's own reported total for the call rather than a computed price, and is present only when the harness reported a non-zero cost (some harnesses, e.g. `codex`, report token counts but no cost — those turns carry `usage` with `cost` absent, even though the recorded message stores `0`). -- `after_llm_call` fires for **every** model call, including calls made inside sub-sessions (transferred tasks, background agents, skills). For those, `session_id` is the sub-session's id. Summing `cost` across `after_llm_call` events therefore captures **all** spend, including sub-sessions (and even sub-sessions that error before their cost is persisted). Do **not** add a separately-queried session cost total on top: the runtime's own total already recurses into and includes completed sub-session spend, so combining the two double-counts. Pick one source — the summed hook costs — as the authoritative ledger. -- `context_limit` is `0` when the model definition is unavailable (treat `0` as "unknown", not as a real limit). -- `approval_decision` is one of `allow`, `deny`, `canceled`. `approval_source` is a stable classifier of which step decided (e.g. `yolo`, `session_permissions_allow`, `session_permissions_deny`, `team_permissions_allow`, `team_permissions_deny`, `pre_tool_use_hook_allow`, `pre_tool_use_hook_deny`, `readonly_hint`, `user_approved`, `user_approved_session`, `user_approved_safe`, `user_approved_tool`, `user_rejected`, `context_canceled`). - -## Hook Output - -Hooks communicate back via JSON output to stdout: - -```json -{ - "continue": true, - "stop_reason": "Optional message when continue=false", - "suppress_output": false, - "system_message": "Warning message to show user", - "decision": "block", - "reason": "Explanation for the decision", - "hook_specific_output": { - "hook_event_name": "pre_tool_use", - "permission_decision": "allow", - "permission_decision_reason": "Command is safe", - "updated_input": { "cmd": "modified command" } - } -} -``` - -All fields are optional. Returning `{}` (or no output at all) means "do nothing, continue normally". - -### Output Fields - -| Field | Type | Description | -| ----------------- | ------- | ----------------------------------------------- | -| `continue` | boolean | Whether to continue execution (default: `true`) | -| `stop_reason` | string | Message to show when `continue=false` | -| `suppress_output` | boolean | Hide stdout from transcript | -| `system_message` | string | Warning message to display to user | -| `decision` | string | For blocking: `block` to prevent operation | -| `reason` | string | Explanation for the decision | - -### Pre-Tool-Use / Permission-Request Specific Output - -The `hook_specific_output` for `pre_tool_use` (and `permission_request`) supports: - -| Field | Type | Description | -| ---------------------------- | ------ | --------------------------------------- | -| `permission_decision` | string | `allow`, `deny`, or `ask` | -| `permission_decision_reason` | string | Explanation for the decision | -| `updated_input` | object | Modified tool input (replaces original) | -| `metadata` | object | (`permission_request` and `pre_tool_use` entries with `preempt_yolo: true` only) string key/value annotations merged onto the tool-call confirmation prompt — see below | - -### Preempting auto-approval from `pre_tool_use` - -`pre_tool_use` entries default to firing AFTER the deterministic approval -pipeline (custom allow rules / safety mode), so an auto-approved call -skips them entirely. For security-critical checks that MUST run on every -call regardless of the safety mode (including `autonomous`, the legacy -`--yolo`), set `preempt_yolo: true` on the matcher entry: - -```yaml -hooks: - pre_tool_use: - - matcher: "*" - preempt_yolo: true - hooks: - - type: command - command: ./security-check.sh -``` - -The entry then fires in a dedicated stage 0 BEFORE `Decide()`: - -- `deny` rejects the call outright; the user is not prompted. -- `ask` forces user confirmation. The default `pre_tool_use` lane and - `permission_request` are skipped on this path so a policy-level - allow there can't override the security verdict. The one exception - is a session-scoped allow grant (the interactive "always allow this - tool" decision) — an informed user opt-in made in response to this - very prompt. -- `allow` is advisory — the pipeline still runs `Decide()` and the - rest of `pre_tool_use`. Same shape as a regular `allow` on the - default lane, just observed earlier. -- No verdict (empty `permission_decision`) falls through. - -Hook crashes on a `preempt_yolo: true` entry fail closed (deny), matching -the default `pre_tool_use` posture. - -Preempting entries can attach structured context via -`hook_specific_output.metadata` (`map[string]string`). The runtime merges -that into the tool-call confirmation event, on top of the metadata it -already derives from its own safety classification (`safety_label`, -`blast_radius`, `category`, `reason`). Key conventions with special -rendering in the TUI confirmation prompt: - -- `safety_label` — the three-value taxonomy: `safe`, `destructive`, or - `unknown`. -- `blast_radius` — one of `safe`, `low`, `medium`, `high`, `unknown`. - Rendered as a colored severity badge (green / yellow / red / muted). -- `category` — taxonomy tag (e.g. `fs-delete`, `dk-volume-del`). - -Plus a free-form `reason` key that the dialog shows as supporting -context. Other keys render as plain text. Last writer wins on key -clashes across hooks, and preempting entries win over the runtime's own -classification. - -### Tool-Response-Transform Specific Output - -The `hook_specific_output` for `tool_response_transform` supports: - -| Field | Type | Description | -| ----------------------- | ------ | --------------------------------------------- | -| `updated_tool_response` | string | Rewritten tool output (replaces the original) | - -This is the symmetric counterpart of `pre_tool_use`'s `updated_input`, applied to tool **results** instead of tool **arguments**. The rewrite reaches every downstream consumer — event subscribers, the persisted session file, the `post_tool_use` hook input, and the next LLM call. Use it to truncate excessive output, scrub PII, or normalise tool dialects. The built-in `redact_secrets` registers itself on this event as the third leg of the redact_secrets feature. - -### Context-Contributing Events - -For `session_start`, `user_prompt_submit`, `user_steering_messages_submit`, `user_followup_submit`, `turn_start`, `post_tool_use`, `pre_compact`, and `stop`, hooks may set `hook_specific_output.additional_context` to inject text into the conversation. `turn_start` context is **transient** (recomputed every turn, never persisted); `session_start` context **persists** for the life of the session. `user_steering_messages_submit` and `user_followup_submit` context is **transient** like `user_prompt_submit` — it is spliced into the steered/follow-up turn only and never persisted. (`worktree_create` also surfaces stdout, but to the CLI user rather than the conversation — the session doesn't exist yet.) - -### Before-Compaction Specific Output - -For `before_compaction`, the `hook_specific_output.summary` field, when non-empty, replaces the LLM-generated compaction summary. The runtime applies the string verbatim and skips the model call. - -```json -{ - "hook_specific_output": { - "hook_event_name": "before_compaction", - "summary": "User asked to refactor pkg/foo. Done in commit abc123." - } -} -``` - -Returning `decision: "block"` (or exit code 2) instead vetoes the compaction entirely. Be cautious about denying when `compaction_reason` is `overflow`: the runtime is recovering from a context-overflow error and a denial there will leave the session unable to make progress. - -### Plain Text Output - -For `session_start`, `user_prompt_submit`, `user_steering_messages_submit`, `user_followup_submit`, `turn_start`, `post_tool_use`, `pre_compact`, and `stop` hooks, plain text written to stdout (i.e., output that is not valid JSON) is captured as additional context for the agent. For `pre_compact` it is appended to the compaction prompt; for the others it is spliced into the conversation as a (transient or persisted) system message depending on the event. - -## Exit Codes - -Hook exit codes have special meaning: - -| Exit Code | Meaning | -| --------- | -------------------------------------- | -| `0` | Success — continue normally | -| `2` | Blocking error — stop the operation | -| Other | Error — logged but execution continues | - -## Per-hook options - -Hooks have a default timeout of 60 seconds. You can also give hooks a name, add environment variables, choose a working directory, and control how non-security hook failures behave: - -```yaml -hooks: - post_tool_use: - - matcher: "shell" - hooks: - - name: "summarize shell output" - type: command - command: "./summarize.sh" - timeout: 120 # 2 minutes - working_dir: ./hooks - env: - PROFILE: dev - on_error: warn # warn | ignore | block -``` - -`pre_tool_use` is fail-closed for safety: a failed pre-tool hook blocks the tool call regardless of `on_error`. - -`working_dir` and `env` apply to `command` and `builtin` hooks. For `builtin` hooks, `working_dir` is resolved with the same logic as `command` hooks (absolute path wins; relative paths join onto the executor directory). `working_dir` accepts `~`, `$VAR`, `${VAR}` and `${env.VAR}`; `env` values expand only the plain `${env.VAR}` form (resolved from the OS process environment), keeping any other `$` literal (see [Variable Expansion in Config Fields](../overview/index.md#variable-expansion-in-config-fields)). A `working_dir` that expands to an empty string (e.g. an unset variable) falls back to the executor's directory with a warning. For `model` hooks, both fields are accepted by the schema but have no effect: model hooks render a prompt template and call the LLM API directly — no subprocess is spawned and no file I/O is performed, so working directory and environment variables have no applicable semantics. - -> [!WARNING] -> **Performance** -> -> Hooks run synchronously and can slow down agent execution. Keep hook scripts fast and efficient. Consider using `suppress_output: true` for logging hooks to reduce noise. - -> [!NOTE] -> **Session End and Cancellation** -> -> `session_end` hooks are designed to run even when the session is interrupted (e.g., Ctrl+C). They are still subject to their configured timeout. - -## Examples - -### Validation Script - -A simple pre-tool-use hook that blocks dangerous shell commands: - -```bash -#!/bin/bash -# scripts/validate-command.sh - -# Read JSON input from stdin -INPUT=$(cat) -TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name') -CMD=$(echo "$INPUT" | jq -r '.tool_input.cmd // empty') - -# Block dangerous commands -if [[ "$TOOL_NAME" == "shell" ]]; then - if [[ "$CMD" =~ ^sudo ]] || [[ "$CMD" =~ rm.*-rf ]]; then - echo '{"decision": "block", "reason": "Dangerous command blocked by policy"}' - exit 2 - fi -fi - -# Allow everything else (returning {} means "do nothing, continue normally") -echo '{}' -exit 0 -``` - -### Audit Logging - -A post-tool-use hook that logs all tool calls: - -```bash -#!/bin/bash -# scripts/log-tool-call.sh - -INPUT=$(cat) -TIMESTAMP=$(date -u +"%Y-%m-%dT%H:%M:%SZ") -TOOL_NAME=$(echo "$INPUT" | jq -r '.tool_name') -SESSION_ID=$(echo "$INPUT" | jq -r '.session_id') - -# Append to audit log -echo "$TIMESTAMP | $SESSION_ID | $TOOL_NAME" >> ./audit.log - -# Don't block execution -echo '{"continue": true}' -exit 0 -``` - -### Session Lifecycle - -Session start and end hooks for environment setup and cleanup: - -```yaml -hooks: - session_start: - - type: command - timeout: 10 - command: | - INPUT=$(cat) - SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"') - echo "Session $SESSION_ID started at $(date)" >> /tmp/agent-session.log - echo '{"hook_specific_output":{"additional_context":"Session initialized."}}' - - session_end: - - type: command - timeout: 10 - command: | - INPUT=$(cat) - SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"') - REASON=$(echo "$INPUT" | jq -r '.reason // "unknown"') - echo "Session $SESSION_ID ended ($REASON) at $(date)" >> /tmp/agent-session.log -``` - -### Response Logging with Stop Hook - -Log every model response for analytics or compliance: - -```yaml -hooks: - stop: - - type: command - timeout: 10 - command: | - INPUT=$(cat) - SESSION_ID=$(echo "$INPUT" | jq -r '.session_id // "unknown"') - RESPONSE_LENGTH=$(echo "$INPUT" | jq -r '.stop_response // ""' | wc -c | tr -d ' ') - echo "[$(date)] Session $SESSION_ID - Response: $RESPONSE_LENGTH chars" >> /tmp/agent-responses.log -``` - -The `stop` hook is useful for: - -- **Response quality checks** — validate that responses meet criteria before returning -- **Analytics** — track response lengths, patterns, or content -- **Compliance logging** — record all agent outputs for audit - -### Error Notifications - -Send alerts when the agent encounters errors: - -```yaml -hooks: - notification: - - type: command - timeout: 10 - command: | - INPUT=$(cat) - LEVEL=$(echo "$INPUT" | jq -r '.notification_level // "unknown"') - MESSAGE=$(echo "$INPUT" | jq -r '.notification_message // "no message"') - echo "[$(date)] [$LEVEL] $MESSAGE" >> /tmp/agent-notifications.log -``` - -The `notification` hook fires when: - -- The model returns an error (all models failed) — also fires `on_error` -- A degenerate tool call loop is detected — also fires `on_error` -- The maximum iteration limit is reached — also fires `on_max_iterations` - -Use `on_error` and `on_max_iterations` instead of `notification` when you want a structured handler for one of these conditions without parsing `notification_level`. - -### Turn-Start: per-turn context - -`turn_start` fires at the start of every agent turn (each model call). Anything you contribute via `additional_context` (or plain stdout) is appended as a **transient** system message for that turn only — it is *not* persisted to the session. Use it for fast-moving signals like the date, current git state, or per-turn prompt files. The built-in hooks `add_date`, `add_prompt_files`, `add_git_status`, and `add_git_diff` all target this event. - -### Turn-End: per-turn finalizer - -`turn_end` is the symmetric counterpart of `turn_start`. It fires once per turn when the iteration finishes — no matter why. The runtime guarantees the dispatch on every exit path (a normal stop, an error, a hook-driven shutdown, the loop detector, even context cancellation), and it uses `context.WithoutCancel` internally so handlers run to completion on Ctrl+C. - -The `reason` field classifies the exit: - -| `reason` | When | -| --------------- | ------------------------------------------------------------ | -| `normal` | Model finished cleanly with no follow-up | -| `continue` | More iterations to come (e.g. tool calls, follow-up message) | -| `steered` | Drained steered messages prompted a re-entry | -| `error` | Model call failed (`handleStreamError` exited the loop) | -| `canceled` | Context was cancelled (e.g. Ctrl+C) | -| `hook_blocked` | `before_llm_call` or `post_tool_use` denied the call | -| `loop_detected` | The consecutive-tool-call loop detector terminated the turn | - -`turn_end` is observational — the result is ignored. Use it to time turns, accumulate per-turn metrics (token usage, tool counts), or notify external observability pipelines symmetrically with `turn_start`. - -### Before/After-LLM-Call: budget guards and model auditing - -`before_llm_call` fires immediately before every model call (after `turn_start` has assembled the messages). It cannot contribute context — use `turn_start` for that — but it can **stop the run** by returning `decision: block` (or exit code 2). The built-in `max_iterations` hook implements a hard cap on top of this event. - -`after_llm_call` fires immediately after each successful model call, before the response is recorded into the session and tool calls are dispatched. The assistant text is in `stop_response`, and the call's `usage` and `cost` carry the per-turn token usage and computed USD spend (see the field notes above). Use it for response auditing, redaction logging, quality metrics, or a sidecar cost ledger that records per-call spend without subscribing to the runtime event channel. Failed model calls fire `on_error` instead. - -### Before/After-Compaction: structured compaction control - -`before_compaction` fires immediately before a compaction. Unlike `pre_compact`, it carries structured token-pressure data: `input_tokens`, `output_tokens`, `context_limit`, and a `compaction_reason` (`threshold`, `overflow`, or `manual`). Hooks can either: - -- veto compaction by returning `decision: block` (the runtime skips compaction entirely), or -- replace the LLM-generated summary by returning `hook_specific_output.summary` (the runtime applies that summary verbatim and skips the model call). - -`after_compaction` fires after a successful compaction. It carries the produced `summary` along with the *pre-compaction* `input_tokens` / `output_tokens` so observability handlers can naturally express "compacted from X to Y". `after_compaction` is purely observational; output is ignored. - -### Agent-Switch and Session-Resume: observability for multi-agent and long runs - -`on_agent_switch` fires whenever the runtime moves the active agent to a new one — `transfer_task`, `handoff`, `force_handoff`, or the return after a transferred task completes. The cause is in `agent_switch_kind`, the source and destination in `from_agent` and `to_agent`. Use it for audit, transcript, and metrics pipelines that track which agent ran which tools. - -The built-in [`unload`](#available-built-ins) hooks into this event to release the resources held by the previous agent's models. It's the canonical way to run two heavy local models on a GPU that can only fit one at a time: - -```yaml -agents: - coder: - model: qwen3-large - handoffs: [reviewer] - hooks: - on_agent_switch: - - type: builtin - command: unload - reviewer: - model: qwen3-coder - handoffs: [coder] - hooks: - on_agent_switch: - - type: builtin - command: unload - -models: - qwen3-large: - provider: dmr - model: ai/qwen3-large - qwen3-coder: - provider: dmr - model: ai/qwen3-coder -``` - -At every transfer the runtime ships a snapshot of the previous agent's model endpoints on the `on_agent_switch` hook input, and the `unload` builtin POSTs `{"model": ""}` to each DMR endpoint's `/_unload` URL over plain HTTP. For cloud providers (OpenAI, Anthropic, …) the hook is a silent no-op since they don't expose an HTTP unload endpoint. Cross-provider chains are safe — only DMR endpoints are touched. See [`examples/unload_on_switch.yaml`](https://github.com/docker/docker-agent/blob/main/examples/unload_on_switch.yaml) for the full file. - -`on_session_resume` fires when the user explicitly approves the runtime to continue past its configured `max_iterations` limit. `previous_max_iterations` carries the cap that was reached and `new_max_iterations` carries the new cap after approval. Useful for alerting on extended-runtime sessions or for billing / quota pipelines that meter resumes. - -### Tool-Approval-Decision: who-approved-what audit trail - -`on_tool_approval_decision` fires after the runtime's tool-approval chain (permissions / yolo / readonly / pre_tool_use hooks / interactive prompt) has resolved a verdict for a tool call. `approval_decision` is `allow`, `deny`, or `canceled`; `approval_source` is a stable classifier of which step produced the verdict. Observational only — it gives audit pipelines a single, structured "who approved what" record without re-implementing the chain. - -### Worktree-Create: prepare an isolated checkout - -`worktree_create` fires once, just after `docker agent run --worktree[=name]` creates a fresh [git worktree](../../features/cli/index.md) and **before** the session starts. Each hook runs **inside** the new worktree — its working directory (and `cwd` in the input) is the fresh checkout — so setup commands operate on the new tree rather than your original one. The worktree path and branch are in `worktree_path` and `worktree_branch`, and `worktree_source_dir` carries the repository root it was branched from. - -Use it to prepare the checkout before the agent begins: copy untracked files git won't carry over (`.env`, local config), install dependencies, or warm caches. Because the worktree lives under the Docker Agent data directory — not next to your checkout — resolve the original files through `worktree_source_dir` rather than a relative path. A hook may **abort the run** by returning `decision: block` / `{"continue": false}` / exit code 2 (for example, when a setup step fails); plain stdout is surfaced as additional context. - -```yaml -hooks: - worktree_create: - # Copy untracked dotfiles git won't bring into the new worktree. - - name: seed local env - type: command - command: | - INPUT=$(cat) - SRC=$(echo "$INPUT" | jq -r '.worktree_source_dir // ""') - [ -n "$SRC" ] && [ -f "$SRC/.env" ] && [ ! -f .env ] && cp "$SRC/.env" .env - echo "Prepared worktree" - # Install dependencies, aborting the run on failure. - - name: install dependencies - type: command - timeout: 600 - command: | - if [ -f package.json ]; then - npm install || { echo '{"continue": false, "system_message": "npm install failed"}'; exit 2; } - fi -``` - -Unlike most events, `worktree_create` is dispatched from the CLI rather than the run loop, because the worktree (and the working directory the runtime, session, tools, and snapshot machinery all capture) must be settled before the runtime and session exist. See [`examples/worktree_create_hook.yaml`](https://github.com/docker/docker-agent/blob/main/examples/worktree_create_hook.yaml) for the full file. - -### Pre-Compact: steer the summary - -`pre_compact` fires just before the runtime compacts the session transcript. Its `source` field tells you why compaction was triggered: - -- `manual` — the user invoked `/compact` -- `auto` — proactive compaction at the configured threshold -- `overflow` — emergency compaction after a context-overflow error -- `tool_overflow` — proactive compaction triggered by tool results pushing the estimated context past the threshold - -Return `additional_context` (or plain stdout) to append guidance to the compaction prompt without modifying the agent's instruction. Block the event (`decision: block` / exit code 2) to cancel compaction — useful when you want to handle truncation yourself. - -### User-Prompt-Submit: gate or enrich every user message - -`user_prompt_submit` fires once per user message, after the prompt is recorded in the session and before the first model call. The submitted text is in `prompt`. Use it to: - -- block prompts that violate policy (`decision: block` / exit code 2), -- inject per-prompt context (`additional_context` is spliced as a transient system message for that turn), -- audit user prompts to a log. - -It does **not** fire for sub-sessions (transferred tasks, background agents, skill sub-sessions) because their kick-off message is synthesised by the runtime. - -### User-Steering-Messages-Submit: gate or enrich mid-flight steering - -`user_steering_messages_submit` is the steering-queue analogue of `user_prompt_submit`. It fires each time the runtime drains the steering queue — messages the user submitted while the agent was already working: mid-turn (after a batch of tool calls), after the model stopped, or while idle before the first model call. The drained messages arrive as a JSON array in `steering_messages`. Use it to: - -- block a run when steering violates policy (`decision: block` / exit code 2), -- inject context in response to the steering (`additional_context` is spliced as a transient system message for the steered turn — never persisted, exactly like `user_prompt_submit`), -- audit steering messages to a log. - -Unlike `turn_end` with `reason: steered`, which only observes the mid-turn and post-stop drains, this event fires on **every** drain — including steering applied while the agent was idle before its first model call. - -```yaml -hooks: - user_steering_messages_submit: - - type: command - timeout: 5 - command: | - INPUT=$(cat) - COUNT=$(echo "$INPUT" | jq -r '.steering_messages | length') - echo "$INPUT" | jq -r '.steering_messages[]' >> /tmp/agent-steering.log - if [ "$COUNT" -gt 0 ]; then - echo '{"hook_specific_output":{"additional_context":"The user sent new instructions while you were working — re-read the latest user messages and adjust course before continuing."}}' - fi -``` - -### User-Followup-Submit: gate or enrich queued follow-ups - -`user_followup_submit` is the follow-up-queue analogue of `user_prompt_submit`. It fires each time the runtime dequeues a follow-up message at the end of a turn and starts a fresh turn for it. Follow-ups are user messages queued for end-of-turn processing (the FollowUp API / queue) — distinct from mid-turn steering: the model sees a follow-up as fresh input, not an interruption, and each follow-up gets a full undivided turn. The follow-up text is in `prompt`. Use it to: - -- block a queued follow-up that violates policy (`decision: block` / exit code 2), -- inject per-follow-up context (`additional_context` is spliced as a transient system message for the follow-up turn — never persisted, exactly like `user_prompt_submit`), -- audit follow-up messages to a log. - -This closes the gap left by `user_prompt_submit`, which fires only for the first interactive prompt and never for queued follow-ups. - -```yaml -hooks: - user_followup_submit: - - type: command - timeout: 5 - command: | - INPUT=$(cat) - echo "$INPUT" | jq -r '.prompt' >> /tmp/agent-followups.log -``` - -### Subagent-Stop: observe handoff completions - -`subagent_stop` fires whenever a sub-agent finishes — `transfer_task` returns, a background agent completes, or a skill sub-session ends. It runs against the *parent* agent's hooks executor, so handlers configured on the orchestrator see every child completion in one place. The sub-agent's name is in `agent_name`, the parent's session ID in `parent_session_id`, and the child's final assistant message in `stop_response`. - -### Permission-Request: programmatic tool approval - -`permission_request` fires just before the runtime would prompt the user to approve a tool call (i.e. when neither the safety mode nor a permissions rule short-circuited the decision). Use the same `hook_specific_output.permission_decision` shape as `pre_tool_use` to auto-approve or auto-deny the call: - -```yaml -hooks: - permission_request: - - matcher: "shell" - hooks: - - type: command - command: | - INPUT=$(cat) - CMD=$(echo "$INPUT" | jq -r '.tool_input.cmd // ""') - if echo "$CMD" | grep -qE '^(ls|pwd|cat) '; then - echo '{"hook_specific_output":{"permission_decision":"allow","permission_decision_reason":"safe read-only command"}}' - fi -``` - -Return nothing to fall through to the usual interactive confirmation. - -When the hook falls through (returns no `permission_decision`), it can still attach key/value `metadata` to the confirmation prompt the runtime shows the user. The runtime merges it onto any static metadata the toolset attached to the tool (hook keys win on a clash) and emits it on the tool-call confirmation message, so clients (TUI, HTTP) can render extra per-call context. Keys from multiple matching hooks are merged; the last hook in config order wins on a clash. - -```yaml -hooks: - permission_request: - - matcher: "shell" - hooks: - - type: command - command: | - INPUT=$(cat) - CMD=$(echo "$INPUT" | jq -r '.tool_input.cmd // ""') - if echo "$CMD" | grep -qE '\brm\b'; then - echo '{"hook_specific_output":{"metadata":{"risk":"high","note":"deletes files"}}}' - fi -``` - -### LLM as a Judge (Auto-Approving Tool Calls) - -The `model` hook type asks an LLM and translates its reply into the -hook's native output — no Go code, no shell glue, no JSON parsing on -your side. Combined with the well-known `pre_tool_use_decision` -schema it gives you a fully-configurable LLM judge that decides -`allow` / `ask` / `deny` per tool call. - -```yaml -hooks: - pre_tool_use: - - matcher: "shell|edit_file|mcp:.*" - hooks: - - type: model - model: openai/gpt-4o-mini - timeout: 15 - schema: pre_tool_use_decision - prompt: | - You are a security judge for an autonomous agent. - Decide whether this tool call is safe to auto-approve. - - Tool: {{ .ToolName }} - Args: {{ .ToolInput | toJSON }} - - Project rules: - - Reads under the working directory are safe. - - Writes to ~/.ssh / ~/.aws / ~/.docker are deny. -``` - -| Field | Required | Description | -| --------- | ---------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `model` | yes | Model spec (`provider/model`, e.g. `openai/gpt-4o-mini`). The judge model — small/cheap is recommended. | -| `prompt` | yes | Go [`text/template`](https://pkg.go.dev/text/template) body. Sees the hook [Input](#hook-input) as data, plus the `toJSON` and `truncate ` helpers. | -| `schema` | no | Well-known response interpretation. `pre_tool_use_decision` produces a `permission_decision` verdict; omit for free-form text injected as `additional_context`. | -| `timeout` | no (default 60s) | Per-call timeout. **Timeouts fail closed (deny) for `pre_tool_use`** regardless of any other setting. Match it to your judge model's typical latency plus a small buffer. | - -The `pre_tool_use_decision` schema constrains the judge to reply with -strict `{decision, reason}` JSON. Providers that honor structured -output (OpenAI, ...) are asked to emit that shape directly; on -providers that ignore it the framework still parses tolerant -JSON-in-text. Anything unparseable propagates as a hook error and the -executor falls closed (deny) on `pre_tool_use`. - -Pair it with deterministic `permissions:` rules so destructive calls -(e.g. `sudo`, `rm -rf`) are blocked even if the judge is misled, and -obvious read-only calls bypass the LLM entirely. See -[`examples/llm_judge.yaml`](https://github.com/docker/docker-agent/blob/main/examples/llm_judge.yaml) -for a complete configuration. - -**Security considerations**: - -- **Sensitive data**: Tool arguments (including file paths, command - arguments, and any other parameters) are sent to the judge LLM. Avoid - using the judge on tools that handle secrets, or ensure your judge - model is self-hosted. -- **Defense in depth**: The judge should not be your only security - layer. Use deterministic `permissions:` rules to block obviously - dangerous operations (e.g., `sudo`, `rm -rf`) before the judge sees - them, as shown in the example configuration. - -## CLI Flags - -You can add hooks from the command line without modifying the agent's YAML file. This is useful for one-off debugging, audit logging, or layering hooks onto an existing agent. - -| Flag | Description | -| ---------------------- | ------------------------------------------------ | -| `--hook-pre-tool-use` | Run a command before every tool call | -| `--hook-post-tool-use` | Run a command after every tool call | -| `--hook-session-start` | Run a command when a session starts | -| `--hook-session-end` | Run a command when a session ends | -| `--hook-on-user-input` | Run a command when waiting for input | -| `--hook-stop` | Run a command when the model finishes responding | - -All flags are repeatable — pass multiple to register multiple hooks. - -```bash -# Add a session-start hook -$ docker agent run agent.yaml --hook-session-start "./scripts/setup-env.sh" - -# Combine multiple hooks -$ docker agent run agent.yaml \ - --hook-pre-tool-use "./scripts/validate.sh" \ - --hook-post-tool-use "./scripts/log.sh" - -# Add hooks to an agent from a registry -$ docker agent run myorg/coder \ - --hook-pre-tool-use "./audit.sh" -``` - -> [!NOTE] -> **Merging behavior** -> -> Agent-config, global, drop-in, and CLI hooks are additive. For each event, hooks run in this order: agent-config hooks first, then global hooks from `settings.hooks`, then [hook drop-ins](#hook-drop-in-files-hooksd) from `hooks.d/`, then CLI hooks. No source replaces another, and individual agents cannot opt out of global hooks. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/models/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/models/index.md deleted file mode 100644 index 0626bd48ef43..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/models/index.md +++ /dev/null @@ -1,639 +0,0 @@ ---- -title: "Model Configuration" -description: "Complete reference for defining models with providers, parameters, and reasoning settings." -keywords: docker agent, ai agents, configuration, yaml, model configuration -linkTitle: "Model Config" -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/configuration/models/ ---- - -_Complete reference for defining models with providers, parameters, and reasoning settings._ - -## Full Schema - - -```yaml -models: - model_name: - first_available: [list] # Optional: candidate model refs, tried in order by available credentials. - # Mutually exclusive with other model settings. - provider: string # Required unless using first_available. One of: openai, anthropic, google, amazon-bedrock, - # dmr, mistral, xai, nebius, nvidia, minimax, baseten, ovhcloud, groq, fireworks, deepseek, cerebras, together, huggingface, moonshot, vercel, cloudflare-workers-ai, cloudflare-ai-gateway, requesty, openrouter, - # azure, ollama, github-copilot, or a named provider defined - # under the top-level `providers:` section. - model: string # Required: model identifier - description: string # Optional: human-readable summary of the model's purpose or strengths - temperature: float # Optional: 0.0–2.0 (provider-dependent; e.g. Anthropic caps at 1.0) - max_tokens: integer # Optional: response length limit - top_p: float # Optional: 0.0–1.0 - frequency_penalty: float # Optional: -2.0–2.0 - presence_penalty: float # Optional: -2.0–2.0 - base_url: string # Optional: custom API endpoint - token_key: string # Optional: env var for API token - thinking_budget: string|int # Optional: reasoning effort - task_budget: int|object # Optional: total task token budget (Anthropic) - parallel_tool_calls: boolean # Optional: allow parallel tool calls - track_usage: boolean # Optional: track token usage - routing: [list] # Optional: rule-based model routing - capabilities: # Optional: override attachment capabilities - image: boolean # Optional: whether the model accepts image attachments - pdf: boolean # Optional: whether the model accepts PDF attachments - cost: # Optional: explicit token pricing (USD per 1M tokens) - input: float # Optional: price per 1M input tokens - output: float # Optional: price per 1M output tokens - cache_read: float # Optional: price per 1M cached input tokens - cache_write: float # Optional: price per 1M cache-write tokens - provider_opts: # Optional: provider-specific options - key: value - title_model: string # Optional: model used for session-title generation - compaction_model: string # Optional: model used for session-compaction (summary generation) - compaction_threshold: float # Optional: context-window fraction that triggers auto-compaction (0–1, default: 0.9) - bypass_models_gateway: boolean # Optional: skip the models gateway for this model (implied by a custom base_url) -``` - -## Properties Reference - -| Property | Type | Required | Description | -| --------------------- | ---------- | -------- | ------------------------------------------------------------------------------------- | -| `first_available` | array | ✗ | Candidate model references tried in order; selects the first whose credentials are configured. Mutually exclusive with other model settings. | -| `provider` | string | ✓/✗ | Required for regular model definitions; omitted for `first_available` selectors. Provider: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, `mistral`, `xai`, `nebius`, `nvidia`, `minimax`, `baseten`, `ovhcloud`, `groq`, `fireworks`, `deepseek`, `cerebras`, `together`, `huggingface`, `moonshot`, `vercel`, `cloudflare-workers-ai`, `cloudflare-ai-gateway`, `requesty`, `openrouter`, `azure`, `ollama`, `github-copilot`, `chatgpt`, or any [named provider](../../providers/custom/index.md). | -| `model` | string | ✓/✗ | Required for regular model definitions; omitted for `first_available` selectors. Model name (e.g., `gpt-4o`, `claude-sonnet-4-5`, `gemini-3.5-flash`) | -| `description` | string | ✗ | Informational, human-readable summary of the model's purpose or strengths (e.g., "fast and cheap, good for summaries"). Not sent to the model. Can be combined with `first_available` (a selector's description is kept when it resolves). | -| `temperature` | float | ✗ | Sampling randomness. Range is provider-dependent — typically `0.0–2.0` (Anthropic caps at `1.0`). `0.0` is deterministic. | -| `max_tokens` | int | ✗ | Maximum response length in tokens | -| `top_p` | float | ✗ | Nucleus sampling threshold (`0.0–1.0`) | -| `frequency_penalty` | float | ✗ | Penalize repeated tokens (`-2.0–2.0`) | -| `presence_penalty` | float | ✗ | Encourage topic diversity (`-2.0–2.0`) | -| `base_url` | string | ✗ | Custom API endpoint URL (for self-hosted or proxied endpoints) | -| `token_key` | string | ✗ | Environment variable name containing the API token (overrides provider default) | -| `thinking_budget` | string/int | ✗ | Reasoning effort control | -| `task_budget` | int/object | ✗ | Total token budget for an agentic task (forwarded to Anthropic; see [Task Budget](#task-budget)). | -| `parallel_tool_calls` | boolean | ✗ | Allow model to call multiple tools at once | -| `track_usage` | boolean | ✗ | Track and report token usage for this model | -| `routing` | array | ✗ | Rule-based routing to different models. See [Model Routing](../routing/index.md). | -| `capabilities` | object | ✗ | Override attachment capabilities for this model. See [Attachment Capability Overrides](#attachment-capability-overrides). | -| `cost` | object | ✗ | Explicit token pricing in USD per 1M tokens, overriding the built-in catalogue. See [Custom Token Pricing](#custom-token-pricing). | -| `provider_opts` | object | ✗ | Provider-specific options (see provider pages) | -| `title_model` | string | ✗ | Model used for session-title generation. Can be a named model from the `models:` section or an inline `provider/model` string. When omitted, the agent's primary model generates titles. Cannot be combined with `first_available`. | -| `compaction_model` | string | ✗ | Model used for session compaction (summary generation). Can be a named model or an inline `provider/model` string. The agent-level `compaction_model` takes precedence over this value, which in turn takes precedence over a provider-level default. When none is set, the primary model compacts. Cannot be combined with `first_available`. See the [Context & Compaction guide](../../guides/compaction/index.md). | -| `compaction_threshold` | float | ✗ | Fraction of the context window at which proactive auto-compaction triggers for agents running this model. Must be greater than `0` and at most `1`. Takes precedence over the agent-level `compaction_threshold`. Cannot be combined with `first_available`. Default: `0.9`. See the [Context & Compaction guide](../../guides/compaction/index.md). | -| `bypass_models_gateway` | boolean | ✗ | When `true`, this model connects directly to its provider even when a models gateway (`--models-gateway` / `DOCKER_AGENT_MODELS_GATEWAY`) is configured. Implied by a custom `base_url`. See [Gateway Bypass](#gateway-bypass). | - -## Attachment Capability Overrides - -For custom OpenAI-compatible providers, local models (Ollama, DMR), and any -model the built-in catalogue does not describe, Docker Agent cannot -auto-detect whether the endpoint accepts image or PDF attachments. When the -model is absent from the catalogue, Docker Agent logs a diagnostic and falls -back to text-only, silently dropping attachments. - -Declare `capabilities` to make the model's attachment support authoritative -and skip the catalogue lookup entirely: - -```yaml -models: - llava-local: - provider: ollama - model: llava - capabilities: - image: true # accepts image attachments - pdf: false # does not accept PDFs - - proxy-vision: - provider: vision-proxy - model: gpt-4o - capabilities: - image: true - pdf: true -``` - -| Field | Type | Description | -| ---------------------- | ------- | ------------------------------------------------- | -| `capabilities.image` | boolean | Whether the model accepts image attachments | -| `capabilities.pdf` | boolean | Whether the model accepts PDF attachments | - -The flags must match what the endpoint actually accepts. Claiming a modality -that the endpoint does not support leads to a provider-side API error. When -`capabilities` is omitted the behaviour is unchanged (catalogue lookup then -conservative text-only fallback). - -See [`examples/capability-overrides.yaml`](https://github.com/docker/docker-agent/blob/main/examples/capability-overrides.yaml) for a complete example. - -## Custom Token Pricing - -Docker Agent prices each model call from the [models.dev](https://models.dev/) -catalogue. Models the catalogue does not know — custom OpenAI-compatible -providers, local models, private deployments — are "unpriced": every call is -recorded at $0 despite consuming tokens, with only a log warning. - -Declare `cost` to price a model explicitly, in **USD per one million tokens**. -When set, it takes precedence over the catalogue and makes an uncatalogued -model priced: - -```yaml -models: - internal-gpt: - provider: internal-llm - model: gpt-4o - cost: - input: 1.25 # USD per 1M input tokens - output: 5.00 # USD per 1M output tokens - cache_read: 0.125 # USD per 1M cached input tokens - cache_write: 1.5625 # USD per 1M cache-write tokens - - # Also works for catalogued models, e.g. a negotiated enterprise discount: - discounted-sonnet: - provider: anthropic - model: claude-sonnet-4-5 - cost: - input: 2.4 - output: 12.0 -``` - -| Field | Type | Description | -| ------------------ | ----- | --------------------------------------- | -| `cost.input` | float | USD price per 1M input tokens | -| `cost.output` | float | USD price per 1M output tokens | -| `cost.cache_read` | float | USD price per 1M cached input tokens | -| `cost.cache_write` | float | USD price per 1M cache-write tokens | - -The declared prices feed per-turn cost computation, session cost tracking, the -`/model` picker, and the [`after_llm_call` hook](../hooks/index.md)'s `cost` -field. Prices must not be negative; omitted fields default to `0`. An all-zero -table means "priced, free" — distinct from omitting `cost` entirely -(unpriced). Cannot be combined with `first_available` (set it on the candidate -models instead). - -See [`examples/custom-pricing.yaml`](https://github.com/docker/docker-agent/blob/main/examples/custom-pricing.yaml) for a complete example. - -## Delegating Session-Title Generation - -The `title_model` field lets a heavyweight primary model hand off the cheap -title-generation call to a smaller, faster model: - -```yaml -model: anthropic/claude-opus-4-7 -title_model: anthropic/claude-haiku-4-5 -``` - -The value can be a named entry from the `models` stanza or an inline -`provider/model` string. When omitted, the agent's primary model generates -titles. - -> [!WARNING] -> **Constraint** -> -> `title_model` cannot be combined with `first_available` model selection — the combination is rejected at validation time. - -## Delegating Session Compaction - -> [!TIP] -> **Full guide** -> -> For a task-oriented walkthrough of automatic vs. on-demand compaction, trimming tool results, and reading the context gauge, see [Managing Context & Compaction](../../guides/compaction/index.md). This section covers the `compaction_model` and `compaction_threshold` fields themselves. - -The `compaction_model` field lets a heavyweight primary model hand off the expensive -compaction (summary generation) call to a smaller, faster model: - -```yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - compaction_model: fast - fast: - provider: anthropic - model: claude-haiku-4-5 -``` - -The value can be a named entry from the `models` stanza or an inline -`provider/model` string. Resolution priority: an agent-level `compaction_model` -wins, then the model-level value, then a provider-level default set in the -`providers` section; when none is set, the primary model compacts. For an -agent listing several models (`model: a,b`), the first listed model that sets -a value (or whose provider sets a default) wins at that level. - -```yaml -providers: - my_anthropic: - provider: anthropic - # Default for every agent whose model uses this provider. - compaction_model: anthropic/claude-haiku-4-5 -``` - -If the compaction model has a **smaller context window** than the primary, -Docker Agent triggers compaction against the smaller window so the summary -call can always ingest the full conversation. Pair the primary with a -compaction model whose window is at least as large to keep the proactive -trigger aligned with the primary's window. - -By default the proactive trigger fires when the estimated token usage crosses -**90%** of the context window. The `compaction_threshold` field tunes that -fraction (greater than `0`, at most `1`): lower values compact earlier and -keep requests smaller, higher values compact later and keep more verbatim -history. It can be set on the model (as above, taking precedence) or on the -agent, and automatic compaction can be disabled entirely per agent with -`session_compaction: false` — see [Agent Config](../agents/index.md#properties-reference). - -```yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - compaction_model: fast - # Compact at 80% of the window instead of the default 90%. - compaction_threshold: 0.8 -``` - -> [!WARNING] -> **Constraint** -> -> `compaction_model` cannot be combined with `first_available` model selection — the combination is rejected at validation time. - -See [`examples/compaction_model.yaml`](https://github.com/docker/docker-agent/blob/main/examples/compaction_model.yaml) -and [`examples/compaction_threshold.yaml`](https://github.com/docker/docker-agent/blob/main/examples/compaction_threshold.yaml) -for complete examples. - -## Gateway Bypass - -When a models gateway (`--models-gateway` / `DOCKER_AGENT_MODELS_GATEWAY`) is configured, -models without a custom `base_url` route through it by default. Set -`bypass_models_gateway: true` on a specific model to make it connect directly -to its provider instead: - -```yaml -models: - gateway-model: - provider: openai - model: gpt-5 - - direct-model: - provider: anthropic - model: claude-sonnet-4-5 - bypass_models_gateway: true # uses ANTHROPIC_API_KEY directly -``` - -The bypassed model authenticates with the provider's own credentials -(`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `token_key`, etc.) rather than the -gateway's short-lived token. The rest of the agent's models continue routing -through the gateway as before. - -Bypass is propagated transparently through router models: a bypass-flagged routing -model passes the flag to all of its routed targets automatically. - -> [!WARNING] -> **Security note** -> -> On an untrusted config, a malicious `base_url` combined with `bypass_models_gateway: true` could route provider credentials to an attacker-controlled endpoint. Only enable this on configs you control. - -> [!WARNING] -> **Constraint** -> -> `bypass_models_gateway: true` cannot be combined with `first_available` — the combination is rejected at validation time. - -See [`examples/bypass_models_gateway.yaml`](https://github.com/docker/docker-agent/blob/main/examples/bypass_models_gateway.yaml) for a complete example. - -## First Available Models - -Use `first_available` when the same agent should work with whichever provider credentials are available in the current environment. Docker Agent checks the candidates in order at load time and replaces the selector with the first candidate whose required environment variables are configured. - -```yaml -models: - smart: - first_available: - - anthropic/claude-sonnet-4-6 - - openai/gpt-5 - - google/gemini-3.5-flash - - dmr/ai/qwen3 # local fallback; no API key required - -agents: - root: - model: smart - instruction: You are a helpful assistant. -``` - -Candidates can be inline `provider/model` references or names from the same `models:` section. Local providers such as `dmr` and `ollama` do not require credentials, so they are useful as final fallbacks. - -If none of the candidates has credentials configured, Docker Agent reports the missing environment variables grouped by candidate. You only need to configure one group of credentials, not every provider in the list. - -A `first_available` model is only a selector. Except for the informational `description`, it cannot be combined with `provider`, `model`, `routing`, `token_key`, budgets, sampling options, or other model settings. Put those settings on named candidate models instead: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-6 - max_tokens: 64000 - - gpt: - provider: openai - model: gpt-5 - thinking_budget: low - - smart: - first_available: - - claude - - gpt - - dmr/ai/qwen3 -``` - -See [`examples/first_available.yaml`](https://github.com/docker/docker-agent/blob/main/examples/first_available.yaml) for a complete example. - -## Thinking Budget - -Control how much reasoning the model does before responding. This varies by provider: - -### OpenAI - -Uses effort levels as strings: - -```yaml -models: - gpt: - provider: openai - model: gpt-5.6 - thinking_budget: low # none | minimal | low | medium | high | xhigh | max (xhigh needs gpt-5.2+; none/max need gpt-5.6+; minimal dropped on gpt-5.6+) -``` - -### Anthropic - -Uses an integer token budget (1024–32768), or — on adaptive-capable models (Opus 4.6+) — `adaptive`, `adaptive/`, or a bare effort level: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 16384 # must be < max_tokens - - opus: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: adaptive # or adaptive/, or low | medium | high | xhigh | max -``` - -### Google Gemini 2.5 - -Uses an integer token budget. `0` disables, `-1` lets the model decide: - -```yaml -models: - gemini: - provider: google - model: gemini-2.5-flash - thinking_budget: -1 # dynamic (default) -``` - -### Google Gemini 3 - -Uses effort levels like OpenAI: - -```yaml -models: - gemini3: - provider: google - model: gemini-3-flash - thinking_budget: medium # minimal | low | medium | high -``` - -### Disabling Thinking - -```yaml -thinking_budget: none # or 0 -``` - -`none` and `0` both clear Docker Agent's local thinking configuration (omitting `thinking_budget` has the same effect); neither is guaranteed to reach the API as a real "off" switch: - -- **OpenAI gpt-5.6+** (Sol/Terra/Luna) is the only case with a genuine API-level `none` reasoning effort: Docker Agent sends it as-is and the model does not reason. -- **Older OpenAI reasoning models** (o-series, gpt-5 through gpt-5.5) have no such switch: `none`/`0` just clear the local config, and the model falls back to the API's own default effort and still reasons internally. Same for other always-reasoning models (Gemini 3). -- Providers with a true optional-thinking switch (Gemini 2.5, Claude, local models) are fully disabled by `none`/`0`. - -```yaml -models: - fast-responder: - provider: openai - model: gpt-5.6 - thinking_budget: none # real API-level disable on gpt-5.6+ -``` - -See the [Thinking / Reasoning guide](../../guides/thinking/index.md) for per-provider details, including AWS Bedrock and Docker Model Runner. - -## Task Budget - -**Anthropic-only.** - -`task_budget` caps the **total** number of tokens the model may spend across a -multi-step agentic task — combining thinking, tool calls, and final output -tokens. It lets long-running agents self-regulate effort without having to -choose a tight per-call `max_tokens`. - -It is forwarded to Anthropic's -[`output_config.task_budget`](https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-7) -request field. Docker Agent automatically attaches the required -`task-budgets-2026-03-13` beta header whenever this field is set. - -You can configure `task_budget` on **any** Claude model — Docker Agent never -gates it by model name. At the time of writing only **Claude Opus 4.7** -actually honors the field; other Claude models will reject requests that -include it. Check the Anthropic release notes linked above for the current -list of supported models. - -### Integer shorthand - -```yaml -models: - opus: - provider: anthropic - model: claude-opus-4-7 - task_budget: 128000 # total tokens for the whole task - thinking_budget: adaptive # works nicely together -``` - -### Object form - -Equivalent, and forward-compatible with future budget types: - -```yaml -models: - opus: - provider: anthropic - model: claude-opus-4-7 - task_budget: - type: tokens # only "tokens" is supported today - total: 128000 -``` - -Setting `task_budget: 0` (or omitting the field) disables the feature — the -model falls back to the provider's default behavior. - -Like other inheritable model settings, `task_budget` can also be declared on a -[provider definition](../../providers/custom/index.md) and is -inherited by every model that references that provider. - -See [`examples/task_budget.yaml`](https://github.com/docker/docker-agent/blob/main/examples/task_budget.yaml) for a complete example. - -## Interleaved Thinking - -For Anthropic and Bedrock Claude models, interleaved thinking allows tool calls during model reasoning. It is auto-enabled whenever a thinking budget is configured: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 8192 - # interleaved_thinking is auto-enabled when thinking_budget is set - provider_opts: - interleaved_thinking: false # disable if needed -``` - -## Thinking Display (Anthropic) - -For Anthropic Claude models, `thinking_display` controls whether thinking blocks are returned in responses when thinking is enabled. Newer Claude models (Opus 4.7+, Fable 5) hide thinking content by default (`omitted`); Docker Agent requests `summarized` thinking by default for adaptive/effort-based budgets so reasoning stays visible. Set this provider option to override: - -```yaml -models: - opus-4-7: - provider: anthropic - model: claude-opus-4-7 - thinking_budget: adaptive - provider_opts: - thinking_display: omitted # "summarized" or "omitted" ("display" on pre-4.6 models only) -``` - -`display` (full thinking blocks) is only accepted by pre-4.6 token-thinking models (e.g. Sonnet 4.5, Haiku 4.5); newer models (Opus/Sonnet 4.6+, Sonnet 5, Fable 5) only accept `summarized` and `omitted`, and Docker Agent rejects the configuration at startup. - -See the [Anthropic provider page](../../providers/anthropic/index.md#thinking-display) for details. - -## Custom HTTP Headers - -For OpenAI-compatible providers (`openai`, `github-copilot`, `mistral`, `xai`, -`nebius`, `nvidia`, `minimax`, `baseten`, `ovhcloud`, `groq`, `fireworks`, `deepseek`, `cerebras`, `together`, `huggingface`, `moonshot`, `vercel`, `cloudflare-workers-ai`, `cloudflare-ai-gateway`, `requesty`, `openrouter`, `ollama`, and any custom provider using the OpenAI API), -`provider_opts.http_headers` adds arbitrary HTTP headers to every outgoing -request: - -```yaml -models: - my_model: - provider: openai - model: gpt-4o - provider_opts: - http_headers: - X-Request-Source: docker-agent - X-Tenant-Id: my-team -``` - -Header names are matched case-insensitively. The `github-copilot` provider -automatically sets `Copilot-Integration-Id: copilot-developer-cli` — see the -[GitHub Copilot provider page](../../providers/github-copilot/index.md) -for details. - -## Examples by Provider - -```yaml -models: - # OpenAI - gpt: - provider: openai - model: gpt-5 - - # Anthropic - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 - - # Google Gemini - gemini: - provider: google - model: gemini-3.5-flash - temperature: 0.5 - - # AWS Bedrock - bedrock: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - provider_opts: - region: us-east-1 - - # OpenRouter - openrouter: - provider: openrouter - model: meta-llama/llama-3.3-70b-instruct - - # Docker Model Runner (local) - local: - provider: dmr - model: ai/qwen3 - max_tokens: 8192 -``` - -For detailed provider setup, see the [Model Providers](../../providers/overview/index.md) section. - -## Custom Endpoints - -Use `base_url` to point to custom or self-hosted endpoints: - -```yaml -models: - # Azure OpenAI - azure_gpt: - provider: openai - model: gpt-4o - base_url: https://my-resource.openai.azure.com/openai/deployments/gpt-4o - token_key: AZURE_OPENAI_API_KEY - - # Self-hosted vLLM - local_llama: - provider: openai # vLLM is OpenAI-compatible - model: meta-llama/Llama-3.2-3B-Instruct - base_url: http://localhost:8000/v1 - - # Proxy or gateway - proxied: - provider: openai - model: gpt-4o - base_url: https://proxy.internal.company.com/openai/v1 - token_key: INTERNAL_API_KEY -``` - -The `model` and `base_url` fields accept `${env.VAR}` (or `${VAR}`) references, which are substituted from the environment when the model is loaded. This keeps the model id or endpoint out of the config when it is supplied by the environment, e.g. a Docker Compose / DMR setup: - -```yaml -models: - nemotron3: - provider: dmr - model: "${env.NEMOTRON3_MODEL}" - base_url: "${env.DMR_BASE_URL}" -``` - -See [Variable Expansion in Config Fields](../overview/index.md#variable-expansion-in-config-fields) for the full set of fields and supported syntaxes. - -See [Local Models](../../providers/local/index.md) for more examples of custom endpoints. - -## Inheriting from Provider Definitions - -Models can reference a named provider to inherit shared defaults. Model-level settings always take precedence: - -```yaml -providers: - my_anthropic: - provider: anthropic - token_key: MY_ANTHROPIC_KEY - max_tokens: 16384 - thinking_budget: 8192 - temperature: 0.5 - -models: - claude: - provider: my_anthropic - model: claude-sonnet-4-5 - # Inherits max_tokens, thinking_budget, temperature from provider - - claude_fast: - provider: my_anthropic - model: claude-haiku-4-5 - thinking_budget: 1024 # Overrides provider default -``` - -See [Provider Definitions](../../providers/custom/index.md) for the full list of inheritable properties. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/overview/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/overview/index.md deleted file mode 100644 index 705a698cf4af..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/overview/index.md +++ /dev/null @@ -1,537 +0,0 @@ ---- -title: "Configuration Overview" -description: "Docker Agent uses YAML or HCL configuration files to define agents, models, tools, and their relationships." -keywords: docker agent, ai agents, configuration, yaml, configuration overview -linkTitle: "Overview" -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/configuration/overview/ -aliases: - - /ai/docker-agent/reference/config/ ---- - -_Docker Agent uses YAML or HCL configuration files to define agents, models, tools, and their relationships._ - -## File Structure - -A Docker Agent config can be written in YAML or HCL. The examples on this page use YAML; see [HCL Configuration](../hcl/index.md) for the block-based HCL syntax. - -A Docker Agent config has these main sections: - -```bash -# 1. Version — configuration schema version (optional but recommended) -version: 15 - -# 2. Metadata — optional agent metadata for distribution -metadata: - author: my-org - description: My helpful agent - version: "1.0.0" - -# 3. Models — define AI models with their parameters -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 - -# 4. Agents — define AI agents with their behavior (at least one is required) -agents: - root: - model: claude - description: A helpful assistant - instruction: You are helpful. - toolsets: - - type: think - -# 5. RAG — define retrieval-augmented generation sources (optional) -rag: - docs: - docs: ["./docs"] - strategies: - - type: chunked-embeddings - embedding_model: openai/text-embedding-3-small - -# 6. MCPs — reusable MCP server definitions (optional) -mcps: - github: - remote: - url: https://api.githubcopilot.com/mcp - transport_type: sse - -# 7. Providers — optional reusable provider definitions -providers: - my_provider: - provider: anthropic # or openai (default), google, amazon-bedrock, etc. - token_key: MY_API_KEY - max_tokens: 16384 - -# 8. Permissions — agent-level tool permission rules (optional) -# For user-wide global permissions, see ~/.config/cagent/config.yaml -permissions: - allow: ["read_*"] - deny: ["shell:cmd=sudo*"] - -# 9. Commands & Skills — reusable, named groups shared across agents (optional) -commands: - ci: - deploy: "Deploy the application" -skills: - base: [local, git] - -# 10. Toolsets — reusable, named toolset definitions shared across agents (optional) -toolsets: - fs: - type: filesystem -``` - -## Minimal Config - -The simplest possible configuration — a single agent with an inline model: - -```yaml -agents: - root: - model: openai/gpt-5 - description: A helpful assistant - instruction: You are a helpful assistant. -``` - -The same config in HCL: - -```hcl -agent "root" { - model = "openai/gpt-5" - description = "A helpful assistant" - instruction = "You are a helpful assistant." -} -``` - -## Inline vs Named Models - -Models can be referenced inline or defined in the `models` section: - -- **Inline** — quick and simple. Use `provider/model` syntax directly: `model: openai/gpt-5` -- **Named** — full control over parameters, reusable across agents: `model: my_claude` - -## Config Sections - -- [**HCL Configuration**](../hcl/index.md) — write the same agent schema in HCL using labeled blocks, heredocs, and block-based tool definitions. -- [**Agent Config**](../agents/index.md) — all agent properties: model, instruction, tools, sub-agents, hooks, and more. -- [**Model Config**](../models/index.md) — provider setup, parameters, thinking budget, and provider-specific options. -- [**Tool Config**](../tools/index.md) — built-in tools, MCP tools, Docker MCP, LSP, API tools, and tool filtering. - -## Advanced Configuration - -- [**Hooks**](../hooks/index.md) — run shell commands at lifecycle events like tool calls and session start/end. -- [**Permissions**](../permissions/index.md) — control which tools auto-approve, require confirmation, or are blocked. -- [**Sandbox Mode**](../sandbox/index.md) — run agents in an isolated Docker container for security. -- [**Structured Output**](../structured-output/index.md) — constrain agent responses to match a specific JSON schema. -- [**Flavors**](../flavors/index.md) — ship one agent file with named variants, enabled at run time as YAML patches. - -## Environment Variables - -API keys and secrets are read from environment variables — never stored in config files. See [Managing Secrets](../../guides/secrets/index.md) for all the ways to provide credentials (env files, Docker Compose secrets, the Docker Agent env file): - -| Variable | Provider | -| -------------------------- | --------------------------------------------------- | -| `OPENAI_API_KEY` | OpenAI | -| `ANTHROPIC_API_KEY` | Anthropic | -| `GOOGLE_API_KEY` / `GEMINI_API_KEY` | Google Gemini | -| `MISTRAL_API_KEY` | Mistral | -| `XAI_API_KEY` | xAI | -| `NEBIUS_API_KEY` | Nebius | -| `MINIMAX_API_KEY` | MiniMax | -| `REQUESTY_API_KEY` | Requesty | -| `OPENROUTER_API_KEY` | OpenRouter | -| `GITHUB_TOKEN` | GitHub Copilot (PAT with `copilot` scope) | -| `AZURE_API_KEY` | Azure OpenAI (override with `token_key`) | -| `AWS_BEARER_TOKEN_BEDROCK` | AWS Bedrock (or the standard AWS credentials chain) | - -**Tool Auto-Installation:** - -| Variable | Description | -| --------------------- | --------------------------------------------------------------- | -| `DOCKER_AGENT_AUTO_INSTALL` | Set to `false` to disable automatic tool installation | -| `DOCKER_AGENT_TOOLS_DIR` | Override the base directory for installed tools (default: `~/.cagent/tools/`) | - -**Runtime overrides:** - -| Variable | Description | -| ----------------------------------- | ---------------------------------------------------------------------------------------------------- | -| `DOCKER_AGENT_DEFAULT_MODEL` | Default model used when none is specified, in `provider/model` form (e.g. `openai/gpt-5`). | -| `DOCKER_AGENT_MODELS_GATEWAY` | Route model traffic through a gateway. Equivalent to the `--models-gateway` flag. | -| `DOCKER_AGENT_HIDE_TELEMETRY_BANNER`| Set to `1` to suppress the first-run telemetry notice. | -| `DOCKER_AGENT_AUTO_UPDATE` | Set to a truthy value (`1`, `true`, `yes`, `on`) to let standalone release binaries self-update before running. See [Optional Self-Updates](../../getting-started/installation/index.md#optional-self-updates). | -| `DOCKER_AGENT_NO_TOKEN_EXCHANGE` | Set to `1` to stop Docker Agent from exchanging the access token stored by `docker login` for a Docker token. See [Docker authentication](../../guides/secrets/index.md#docker-authentication). | -| `DOCKER_AGENT_HUB_LOGIN_URL` | Point the token exchange at a Docker staging environment. Ignored unless it is an HTTPS `docker.com` URL. | - -> [!NOTE] -> **Legacy `CAGENT_*` aliases** -> -> The same variables are also accepted with the legacy `CAGENT_` prefix (e.g. `CAGENT_DEFAULT_MODEL`, `CAGENT_MODELS_GATEWAY`, `CAGENT_HIDE_TELEMETRY_BANNER`) for backward compatibility. Prefer the `DOCKER_AGENT_*` form in new setups. - -> [!IMPORTANT] -> Model references are case-sensitive: `openai/gpt-5` is not the same as `openai/GPT-5`. - -## Variable Expansion in Config Fields - -Docker Agent expands `${env.VAR}` references in many config fields. This is the **canonical syntax everywhere** — prefer it for every field. Two engines back it: a full JavaScript evaluator for prompt/HTTP fields (where you also get defaults, ternaries, and tool calls), and a simpler path expander for filesystem/env fields (which additionally accepts the legacy `$VAR` / `${VAR}` / `~` shell forms). Picking `${env.VAR}` everywhere always works; the one caveat is that the path expander does not evaluate richer JS expressions. Using a shell-style `$VAR` in a JS-templated field is currently a silent no-op, so the literal string is passed through. Tracking issue: [#2615](https://github.com/docker/docker-agent/issues/2615). - -### JavaScript template literals — `${env.VAR}` - -Used wherever the agent prompt or HTTP traffic is templated. Backed by a JS evaluator, so you also get `||` defaults, ternaries, and tool calls (`${tool({...})}`). - -Applies to: - -- `agents..description` -- `agents..welcome_message` -- `agents..instruction` -- `agents..commands.*` (string form and `instruction:` field) -- `toolsets[*].instruction` -- `toolsets[*].headers` and `toolsets[*].remote.headers` (MCP, A2A, OpenAPI, fetch, API) - -For `api` toolsets, `api_config.endpoint` and `api_config.headers` are also rendered through the JS expander (the same syntax applies). - -```yaml -agents: - root: - description: "Assistant for ${env.USER || 'guest'}" - commands: - deploy: "Deploy ${env.PROJECT_NAME || 'app'} to ${env.ENV || 'staging'}" - toolsets: - - type: openapi - url: https://api.example.com - headers: - Authorization: "Bearer ${env.INTERNAL_TOKEN}" -``` - -Undefined variables expand to the empty string. - -### Path & env fields — `${env.VAR}` (canonical), `$VAR` / `${VAR}` / `~` (aliases) - -Used for filesystem paths and process environment values. Backed by `os.ExpandEnv` plus tilde expansion against the current user's home directory. The canonical `${env.VAR}` form is accepted here too, so a single syntax works across every field; the bare `$VAR` / `${VAR}` shell forms remain supported as aliases. - -Applies to: - -- `agents..toolsets[*].working_dir` (MCP, LSP) -- `agents..toolsets[*].path` (memory, tasks) -- `agents..toolsets[*].env` values (MCP, shell, script, LSP) -- `agents..toolsets[*].shell..working_dir` (script tools) -- `agents..hooks.*.working_dir` -- The `~` prefix is also accepted in any path-like field documented as such. - -```yaml -agents: - root: - toolsets: - - type: memory - path: "~/notes/${env.PROJECT}/memory.db" - - type: mcp - command: my-server - working_dir: "${env.HOME}/work" -``` - -Unlike the JS-templated fields above, these accept only a plain variable reference: richer JS expressions (e.g. `${env.VAR || 'default'}`) are **not** evaluated here, and the legacy `$VAR` / `${VAR}` forms keep working for backward compatibility. - -Hook and script-tool `env` values expand only the plain `${env.VAR}` form, resolved against the **OS process environment** (dotenv/secret-provider values are not consulted); a bare `$VAR` or `${VAR}` is passed through **literally**, so values that legitimately contain `$` (passwords, templates) are never mangled: - -```yaml -agents: - root: - hooks: - session_start: - - type: command - command: ./notify.sh - working_dir: "~/scripts" # ~, $VAR, ${VAR}, ${env.VAR} all work - env: - API_TOKEN: "${env.NOTIFY_TOKEN}" # expanded - PASSWORD: "pa$$word" # kept literal -``` - -Model definitions follow the same rule. The `models..model` and `models..base_url` fields are expanded when the provider is built, accepting both `${env.VAR}` and `${VAR}`. This is useful when the model id or endpoint is injected by the environment (for example a Docker Compose / DMR setup that exports the model reference as a variable): - -```yaml -models: - nemotron3: - provider: dmr - model: "${env.NEMOTRON3_MODEL}" # resolved from the environment at load time - base_url: "${DMR_BASE_URL}" # ${VAR} is accepted as well -``` - -`token_key` is **not** expanded: it already names the environment variable that holds the API token, so its value is used as a key rather than substituted. An unset variable in `model` or `base_url` is reported as an error instead of dialing with an empty value. - -### Quick reference - -| Field | `${env.X}` | `$X` / `${X}` | `~` | -| --------------------------------------------- | :--------: | :-----------: | :-: | -| `description`, `welcome_message` | ✓ | ✗ | ✗ | -| `instruction` (agent and toolset) | ✓ | ✗ | ✗ | -| `commands.*` | ✓ | ✗ | ✗ | -| `headers`, `remote.headers`, `api_config.headers` | ✓ | ✗ | ✗ | -| `models.*.model`, `models.*.base_url` | ✓ | ✓ | ✗ | -| `working_dir`, `path` (toolset, script tool, hook) | ✓ | ✓ | ✓ | -| `env` values (toolset) | ✓ | ✓ | ✗ | -| `env` values (hook, script tool) | ✓ | literal | ✗ | - -The `~` prefix is meaningful only in path-like fields (`working_dir`, `path`). In hook and script-tool `env` values, "literal" means a bare `$X` / `${X}` is passed to the process unchanged — only `${env.X}` is substituted there, so values containing `$` survive intact. - -Prefer `${env.X}` everywhere. The bare `$X` / `${X}` and `~` forms are accepted only in path and `env` value fields, where they remain supported for backward compatibility. - -## Validation - -Docker Agent validates your configuration at startup: - -- Local `sub_agents` must reference agents defined in the config (external OCI references like `myorg/agent:tag` are pulled from registries automatically; pin them to a digest with `@sha256:…` to avoid a per-run registry lookup) -- Named model references must exist in the `models` section -- Provider names must be valid (`openai`, `anthropic`, `google`, `dmr`, etc.) -- Required environment variables (API keys) must be set -- Tool-specific fields are validated (e.g., `path` is only valid for `memory`) - -## JSON Schema - -For YAML editor autocompletion and validation, use the [Docker Agent JSON Schema](https://github.com/docker/docker-agent/blob/main/agent-schema.json). Add this to the top of your YAML file: - -```bash -# yaml-language-server: $schema=https://raw.githubusercontent.com/docker/docker-agent/main/agent-schema.json -``` - -## Config Versioning - -Docker Agent configs are versioned. The current version is `15`. Add the version at the top of your config: - -```yaml -version: 15 - -agents: - root: - model: openai/gpt-5 - # ... -``` - -When you load an older config, Docker Agent automatically migrates it to the latest schema. It's recommended to include the version to ensure consistent behavior. - -If you use a config key that requires a newer schema version, Docker Agent will fail with a strict-parse error and include a hint like: - -```text -hint: this key is supported by config version 12; update the top-level 'version' field (currently 11) -``` - -Bump the `version` field as directed to enable the new key. - -## Metadata Section - -Optional metadata for agent distribution via OCI registries: - -```yaml -metadata: - author: my-org - license: Apache-2.0 - description: A helpful coding assistant - readme: | # Displayed in registries - This agent helps with coding tasks. - version: "1.0.0" - tags: [coding, review] -``` - -| Field | Description | -| ------------- | ------------------------------------------ | -| `author` | Author or organization name | -| `license` | License identifier (e.g., Apache-2.0, MIT) | -| `description` | Short description for the agent | -| `readme` | Longer markdown description | -| `version` | Semantic version string | -| `tags` | Tags for categorization and discovery | - -See [Agent Distribution](../../concepts/distribution/index.md) for publishing agents to registries. - -## Reusable MCP Servers (`mcps:`) - -The top-level `mcps:` section defines named MCP server configurations that agents can reference with `toolsets: [{type: mcp, ref: }]`. This avoids repeating the same command / URL / headers across agents and keeps credentials in one place. - -```yaml -mcps: - github: - remote: - url: https://api.githubcopilot.com/mcp - transport_type: sse - playwright: - command: npx - args: ["-y", "@modelcontextprotocol/server-playwright"] - -agents: - root: - model: openai/gpt-5 - toolsets: - - type: mcp - ref: github # reuse the definition above - - type: mcp - ref: playwright -``` - -An `mcps` entry accepts every field a regular `type: mcp` toolset accepts (command/args/env, `remote` with `url`/`transport_type`/`headers`/`oauth`, `tools` filter, `instruction`, `defer`, …) — the `type: mcp` is implicit. See the [Tool Config](../tools/index.md) page for all options and the [Remote MCP Servers](../../features/remote-mcp/index.md) guide for remote setups. - -## Reusable Toolsets (`toolsets:`) - -The top-level `toolsets:` map defines named toolset configurations that agents can reference by name through `use_toolsets:`. This avoids repeating the same toolset definition across multiple agents — the same pattern as `mcps:` for MCP servers and `commands:` / `skills:` for reusable prompt groups. - -Any toolset type is supported, including ones that reference MCP or RAG definitions. Shared toolsets are resolved before the MCP/RAG pass, so they can contain `{type: mcp, ref: }` references. - -```yaml -toolsets: - fs: # a named shared toolset - type: filesystem - docs: - type: fetch - allowed_domains: - - docker.com - -agents: - root: - model: openai/gpt-5 - # Pull in shared toolsets by name; inline toolsets come first. - use_toolsets: [fs, docs] - toolsets: - - type: think - - reviewer: - model: openai/gpt-5 - # Reuse the same filesystem toolset without copying its definition. - use_toolsets: [fs] -``` - -Inline `toolsets:` entries listed directly on the agent take precedence in ordering (they come first) and are always included alongside referenced ones. - -See [`examples/shared-toolsets.yaml`](https://github.com/docker/docker-agent/blob/main/examples/shared-toolsets.yaml) for a complete example. - -## Reusable Commands & Skills (`commands:` / `skills:`) - -The top-level `commands:` and `skills:` sections define named, reusable groups that agents pull in by name through `use_commands:` / `use_skills:`. This avoids repeating the same command set or skill configuration across agents. Each group value uses the exact same format as an agent's own `commands` / `skills` field. - -Referenced groups are merged into the agent during config loading. An agent's own inline `commands` / `skills` entries take precedence on name conflicts. - -```yaml -commands: - ci: # a named command group - deploy: "Deploy the application" - test: "Run the test suite" -skills: - base: [local, git] # a named skill group - -agents: - root: - model: openai/gpt-5 - use_commands: [ci] # reuse the "ci" command group - use_skills: [base] # reuse the "base" skill group - commands: - lint: "Run the linter" # inline command, merged in (wins on conflict) - reviewer: - model: openai/gpt-5 - use_commands: [ci] # same group, reused without duplication -``` - -See [`examples/shared-commands-skills.yaml`](https://github.com/docker/docker-agent/blob/main/examples/shared-commands-skills.yaml) for a complete example. - -## Custom Providers Section - -Define reusable provider configurations with shared defaults. Providers can wrap any provider type — not just OpenAI-compatible endpoints: - -```yaml -providers: - # OpenAI-compatible custom endpoint - azure: - api_type: openai_chatcompletions - base_url: https://my-resource.openai.azure.com/openai/deployments/gpt-4o - token_key: AZURE_OPENAI_API_KEY - - # Anthropic with shared model defaults - team_anthropic: - provider: anthropic - token_key: TEAM_ANTHROPIC_KEY - max_tokens: 32768 - thinking_budget: 16384 - -models: - azure_gpt: - provider: azure - model: gpt-4o - - claude: - provider: team_anthropic - model: claude-sonnet-4-5 - # Inherits max_tokens, thinking_budget from provider - -agents: - root: - model: claude -``` - -| Field | Description | -| --------------------- | ---------------------------------------------------------------------------------------- | -| `provider` | Underlying provider type: `openai` (default), `anthropic`, `google`, `amazon-bedrock`, etc. | -| `api_type` | API schema: `openai_chatcompletions` (default) or `openai_responses`. OpenAI-only. | -| `base_url` | Base URL for the API endpoint. Required for OpenAI-compatible providers. | -| `token_key` | Environment variable name for the API token. | -| `temperature` | Default sampling temperature. | -| `max_tokens` | Default maximum response tokens. | -| `thinking_budget` | Default reasoning effort/budget. | -| `task_budget` | Default total token budget for an agentic task (Anthropic; honored by Claude Opus 4.7 today). | -| `top_p` | Default top-p sampling parameter. | -| `frequency_penalty` | Default frequency penalty. | -| `presence_penalty` | Default presence penalty. | -| `parallel_tool_calls` | Enable parallel tool calls by default. | -| `track_usage` | Track token usage by default. | -| `provider_opts` | Provider-specific options. | - -See [Provider Definitions](../../providers/custom/index.md) for more details. - -## Reusable YAML (anchors & aliases) - -YAML anchors (`&name`), aliases (`*name`) and merge keys (`<<`) are part of the YAML spec, and Docker Agent's config parser supports them. Use them to declare a value once and reuse it elsewhere in the same file, instead of copy-pasting the same block across agents. - -This complements the named-reuse sections above (`mcps:`, `commands:` / `skills:`, `providers:`). Reach for anchors when you want to share something those sections don't cover, such as an instruction string or a block of agent settings. - -Reuse a value verbatim with an anchor and an alias: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Coordinator. - instruction: &house_rules | - You are part of the Acme engineering team. - Cite the files you looked at and keep changes minimal. - reviewer: - model: anthropic/claude-sonnet-4-5 - description: Reviews code changes. - instruction: *house_rules # the same instruction, declared once -``` - -Compose a block with a merge key (`<<`), then override individual fields: - -```yaml -agents: - reviewer: &specialist - model: anthropic/claude-sonnet-4-5 - description: Reviews code changes. - instruction: | - You are a meticulous software professional. - toolsets: - - type: filesystem - documenter: - <<: *specialist # inherit model, instruction, toolsets - description: Writes documentation. # then override one field -``` - -> [!WARNING] -> **Where anchors can live** -> -> An anchor has to sit on a real value inside a known section (for example a real agent, model, or MCP entry, as above). Parking anchors in a separate top-level block such as `defaults:` or `prompts:` fails, because the parser rejects unknown top-level keys. - -> [!WARNING] -> **Overriding merged keys** -> -> Overriding a key that a `<<` merge already set works only in the `agents:` section, as shown above. Every other section (`models:`, `mcps:`, `providers:`, `rag:`) is parsed strictly and reports the override as a duplicate key. There, use `<<` only to add new fields, or use the named-reuse sections above when you need per-entry overrides. - -Anchors are for static reuse within a single file, not dynamic values or cross-file composition. For environment-specific settings, see [Variable Expansion in Config Fields](#variable-expansion-in-config-fields), which substitutes `${env.VAR}` at load time. Templating tags such as `!include` are not acted on: the tag is ignored and its argument is kept as a plain string, so no other file is loaded. Circular aliases are not detected, so keep references acyclic. - -See [`examples/yaml-anchors.yaml`](https://github.com/docker/docker-agent/blob/main/examples/yaml-anchors.yaml) for a complete example. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/permissions/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/permissions/index.md deleted file mode 100644 index c49f5df5501b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/permissions/index.md +++ /dev/null @@ -1,314 +0,0 @@ ---- -title: "Permissions" -description: "Control which tools can execute automatically, require confirmation, or are blocked entirely." -keywords: docker agent, ai agents, configuration, yaml, permissions -weight: 70 -canonical: https://docs.docker.com/ai/docker-agent/configuration/permissions/ ---- - -_Control which tools can execute automatically, require confirmation, or are blocked entirely._ - -## Overview - -Permissions provide fine-grained control over tool execution. You can configure which tools are auto-approved (run without asking), which require user confirmation, and which are completely blocked. - -> [!NOTE] -> **Evaluation Order** -> -> Permissions are evaluated in this order: **Deny → Allow → Ask**. Deny patterns take priority, then allow patterns, and anything else falls through to the session's [safety mode](#safety-modes). - -## Safety Modes - -Every session runs in a **safety mode** that decides what happens when no permission rule matched a tool call. The runtime labels each call `safe` (safe-listed shell command such as `ls` or `git status`, or a read-only-annotated tool), `destructive` (destructive shell command such as `rm -rf`, or a destructive-annotated tool), or `unknown` — and the mode gates on that label: - -| Mode | safe | destructive | unknown | -| ---- | ---- | ----------- | ------- | -| `strict` | ask | ask | ask | -| `balanced` | **allow** | ask | ask | -| `restricted` | **allow** | deny | deny | -| `autonomous` | **allow** | **allow** | **allow** | - -- **`strict`** prompts for every tool call, read-only ones included. Only an `allow:` rule silences a prompt. -- **`balanced`** runs safe calls silently and asks about everything else. -- **`restricted`** is the fail-closed profile for unattended/headless runs: safe calls run silently and everything else is **denied without asking** — the mode's fallback never prompts. Custom rules still win: an `allow:` rule can approve a destructive/unknown call, a `deny:` rule always blocks, and session-scoped `ask:` rules still prompt (as can a `preempt_yolo` hook). Restricted is defense in depth against unwanted tool calls, not a security boundary — for real isolation use [sandbox mode](../sandbox/index.md). -- **`autonomous`** is the legacy `--yolo` behavior: everything runs. Only `deny:` rules, session-scoped `ask:` rules, and `preempt_yolo` hooks still gate. - -Pick a mode with the `--safety` flag (`docker-agent run --safety balanced ...`), the `safety_policy` field on session create (`POST /api/sessions`) or mid-session (`PATCH /api/sessions/:id/safety-policy`), or escalate directly from a confirmation prompt (`B` switches to balanced, `A` to autonomous; the `restricted` fallback never prompts, so the mode is only selected via flag/config/API). Sessions that never choose a mode keep the historical default: read-only tools auto-approve, everything else asks. - -### Declarative Safety Defaults - -Safety modes can also be declared as **defaults** in YAML, at four scopes: - -| Scope | Location | Owner | -| ----- | -------- | ----- | -| Alias | `aliases..safety` in `~/.config/cagent/config.yaml` (or `docker agent alias add ... --safety `) | User | -| Global settings | `settings.safety` in `~/.config/cagent/config.yaml` | User | -| Per-agent | `agents..safety` in the agent YAML | Agent author | -| Config-wide | `runtime.safety` in the agent YAML | Agent author | - -```yaml -# Agent YAML (author-declared defaults) -runtime: - safety: balanced # config-wide default for new sessions - -agents: - root: - safety: strict # overrides runtime.safety for this agent -``` - -All four fields accept only the four canonical modes — `strict`, `balanced`, `restricted`, `autonomous` (yes, an author may declare `autonomous`) — and any other value fails loading with an error naming the field. The legacy spellings remain as aliases for `autonomous`: `settings.YOLO`, the alias `yolo` option, and the `--yolo` flag. When both are set at the same scope, `safety` wins over the legacy `YOLO`/`yolo`. - -For a **new** root session the first source in this order wins: - -1. explicit `--safety` flag -2. explicit `--yolo` flag -3. alias `safety`/`yolo` option -4. `settings.safety`/`settings.YOLO` (user config) -5. selected agent's `agents..safety` -6. `runtime.safety` -7. the historical default (read-only tools auto-approve, everything else asks) - -**Resuming a session never re-applies defaults**: the stored mode is kept unless you pass an explicit `--safety` or `--yolo` flag for that run. Agent switches, handoffs, and delegated sub-agent sessions inherit the active session's mode rather than resetting it. - -Sessions created through the API (`POST /api/sessions`) without a `safety_policy` receive the author-declared defaults (5–6) when their first run starts — the earliest point the agent configuration is loaded. If the server restarts before that first run, the session keeps the historical unset default (7). - -> [!WARNING] -> **Trust: author defaults never outrank you.** `runtime.safety` and `agents..safety` are written by the agent's author — which may be a config you pulled from a URL or an OCI registry. They only fill the gap when you expressed no preference: any user-owned source (CLI flag, alias option, user settings) always takes precedence, and a resumed session keeps its stored mode. Still, an author default of `autonomous` means a fresh session runs every tool call unprompted — review third-party configs before running them, or pin your own floor with `settings.safety` / `--safety`. - -**Custom rules always win over the mode**, with one asymmetry: `ask:` rules written in an agent's YAML (or global config) are agent-author advisories and yield to a user-chosen `balanced`/`restricted`/`autonomous` mode (under `restricted` they resolve to the mode's allow-or-deny verdict rather than introducing a prompt), while `ask:` rules granted at the session level (interactive "always ask" decisions, the session permissions API) always prompt. - -## Permission Levels - -Permissions can be defined at two levels: - -| Level | Location | Scope | -| ----- | -------- | ----- | -| **Agent-level** | Agent YAML config (`permissions:` section) | Applies to that specific agent config | -| **Global (user-level)** | `~/.config/cagent/config.yaml` under `settings.permissions` | Applies to every agent you run | - -Hooks follow the same user-config pattern: agent-level hooks live under `agents..hooks`, and global hooks live under `settings.hooks`. See [Hooks](../hooks/index.md#global-user-level-hooks). - -Both levels use the same `allow`/`ask`/`deny` pattern syntax. When both are present, they are **merged** at startup -- patterns from both sources are combined into a single checker. See [Merging Behavior](#merging-behavior) for details. - -## Agent-Level Configuration - -```yaml -agents: - root: - model: openai/gpt-4o - description: Agent with permission controls - instruction: You are a helpful assistant. - -permissions: - # Auto-approve these tools (no confirmation needed) - allow: - - "read_file" - - "read_*" # Glob patterns - - "shell:cmd=ls*" # With argument matching - - # Always ask before running these tools, even if an allow pattern would match - ask: - - "shell:cmd=git push*" - - "write_file:path=/home/user/important/*" - - # Block these tools entirely - deny: - - "shell:cmd=sudo*" - - "shell:cmd=rm*-rf*" - - "dangerous_tool" -``` - -The three lists are evaluated in order `deny` → `allow` → `ask`, so an `ask:` entry lets you add a confirmation layer on top of an otherwise-allowed tool. - -## Global Permissions - -Global permissions let you enforce rules across **all** agents, regardless of which agent config you run. Define them in your user config file: - -```yaml -# ~/.config/cagent/config.yaml -settings: - permissions: - deny: - - "shell:cmd=sudo*" - - "shell:cmd=rm*-rf*" - allow: - - "read_*" - - "shell:cmd=ls*" - - "shell:cmd=cat*" -``` - -This is useful for setting personal safety guardrails that apply everywhere -- for example, always blocking `sudo` or always auto-approving read-only tools -- without relying on each agent config to include those rules. - -### Merging Behavior - -When both global and agent-level permissions are present, they are merged into a single set of patterns before evaluation. The merge works as follows: - -- **Deny patterns from either source block the tool.** A global deny cannot be overridden by an agent-level allow, and vice versa. -- **Allow patterns from either source auto-approve the tool** (as long as no deny pattern matches). -- **Ask patterns from either source force confirmation** (as long as no deny or allow pattern matches). - -The evaluation order remains the same after merging: **Deny > Allow > Ask > default Ask**. - -> [!TIP] -> **Example: Global deny + agent allow** -> -> If your global config denies `shell:cmd=sudo*` and an agent config allows `shell:cmd=sudo apt update`, the deny wins. Deny patterns always take priority regardless of source. - -## Pattern Syntax - -Permissions support glob-style patterns with optional argument matching: - -### Simple Patterns - -| Pattern | Matches | -| -------------- | ------------------------------ | -| `shell` | Exact match for `shell` tool | -| `read_*` | Any tool starting with `read_` | -| `github_*` | Any GitHub MCP tool | -| `*` | All tools | - -### Argument Matching - -You can match tools based on their argument values using `tool:arg=pattern` syntax: - -```yaml -permissions: - allow: - # Allow shell only when cmd starts with "ls" or "cat" - - "shell:cmd=ls*" - - "shell:cmd=cat*" - - # Allow edit_file only in specific directory - - "edit_file:path=/home/user/safe/*" - - deny: - # Block shell with sudo - - "shell:cmd=sudo*" - - # Block writes to system directories - - "write_file:path=/etc/*" - - "write_file:path=/usr/*" -``` - -> [!NOTE] -> **Colons inside argument values are preserved.** Only the `:key=` token boundaries between -> argument conditions split a pattern — colons that appear inside a value are treated as -> ordinary characters and do not start a new condition. Check a tool’s actual argument names -> (and whether they accept a string or a list) before writing an argument-matching pattern. - -### Multiple Argument Conditions - -Chain multiple argument conditions with colons. All conditions must match: - -```yaml -permissions: - allow: - # Allow shell with ls in current directory - - "shell:cmd=ls*:cwd=." - - deny: - # Block shell with rm -rf anywhere - - "shell:cmd=rm*:cmd=*-rf*" -``` - -## Glob Pattern Rules - -Patterns follow filepath.Match semantics with some extensions: - -- `*` — matches any sequence of characters (including spaces) -- `?` — matches any single character -- `[abc]` — matches any character in the set -- `[a-z]` — matches any character in the range - -Matching is **case-insensitive**. - -> [!TIP] -> **Trailing Wildcards** -> -> Trailing wildcards like `sudo*` match any characters including spaces, so `sudo*` matches `sudo rm -rf /`. - -## Decision Types - -| Decision | Behavior | -| --------- | --------------------------------------------------- | -| **Allow** | Tool executes immediately without user confirmation | -| **Ask** | User must confirm before tool executes (default) | -| **Deny** | Tool is blocked and returns an error to the agent | - -## Examples - -### Read-Only Agent - -Allow all read operations, block all writes: - -```yaml -permissions: - allow: - - "read_file" - - "read_multiple_files" - - "list_directory" - - "directory_tree" - - "search_files_content" - deny: - - "write_file" - - "edit_file" - - "shell" -``` - -### Safe Shell Agent - -Allow specific safe commands, block dangerous ones: - -```yaml -permissions: - allow: - - "shell:cmd=ls*" - - "shell:cmd=cat*" - - "shell:cmd=grep*" - - "shell:cmd=find*" - - "shell:cmd=head*" - - "shell:cmd=tail*" - - "shell:cmd=wc*" - deny: - - "shell:cmd=sudo*" - - "shell:cmd=rm*" - - "shell:cmd=mv*" - - "shell:cmd=chmod*" - - "shell:cmd=chown*" -``` - -### MCP Tool Permissions - -Control MCP tools by their qualified names: - -```yaml -permissions: - allow: - # Allow all GitHub read operations - - "github_get_*" - - "github_list_*" - - "github_search_*" - deny: - # Block destructive GitHub operations - - "github_delete_*" - - "github_close_*" -``` - -## Combining with Hooks - -Permissions work alongside [hooks](../hooks/index.md). The evaluation order is: - -1. Run **`preempt_yolo` pre_tool_use hooks** — security-critical checks that no mode or allow rule can bypass -2. Check **deny** patterns — if matched, tool is blocked -3. Check **allow** patterns — if matched, tool is auto-approved -4. Check **ask** patterns — if matched, the user is prompted directly, skipping the default `pre_tool_use` lane -5. If no rule matched, apply the **[safety mode](#safety-modes)** to the call's safety label — may auto-approve (or, under `restricted`, deny) -6. On a mode "ask", run **pre_tool_use hooks** — hooks can allow, deny, or ask -7. If no decision, **ask user** for confirmation - -Default-lane hooks only see calls the mode routed to "ask"; they cannot override deny decisions or explicit `ask:` rules. - -> [!WARNING] -> **Security Note** -> -> Permissions are enforced client-side. They help prevent accidental operations but should not be relied upon as a security boundary for untrusted agents. For stronger isolation, use [sandbox mode](../sandbox/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/routing/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/routing/index.md deleted file mode 100644 index 54c187bbf63f..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/routing/index.md +++ /dev/null @@ -1,170 +0,0 @@ ---- -title: "Model Routing" -description: "Route requests to different models based on the content of user messages." -keywords: docker agent, ai agents, configuration, yaml, model routing -weight: 100 -canonical: https://docs.docker.com/ai/docker-agent/configuration/routing/ ---- - -_Route requests to different models based on the content of user messages._ - -## Overview - -Model routing lets you define a "router" model that automatically selects the best underlying model based on the user's message. This is useful for cost optimization, specialized handling, or load balancing across models. - -> [!NOTE] -> **How It Works** -> -> Docker Agent uses NLP-based text similarity (via Bleve full-text search) to match user messages against example phrases you define. The route with the best-matching examples wins, and that model handles the request. - -## Configuration - -Add `routing` rules to any model definition. The model's `provider`/`model` fields become the fallback when no route matches: - -```yaml -models: - smart_router: - # Fallback model when no routing rule matches - provider: openai - model: gpt-5-mini - - # Routing rules - routing: - - model: anthropic/claude-sonnet-4-5 - examples: - - "Write a detailed technical document" - - "Help me architect this system" - - "Review this code for security issues" - - "Explain this complex algorithm" - - - model: openai/gpt-5 - examples: - - "Generate some creative ideas" - - "Write a story about" - - "Help me brainstorm" - - "Come up with names for" - - - model: openai/gpt-5-mini - examples: - - "What time is it" - - "Convert this to JSON" - - "Simple math calculation" - - "Translate this word" - -agents: - root: - model: smart_router - description: Assistant with intelligent model routing - instruction: You are a helpful assistant. -``` - -## Routing Rules - -Each routing rule has: - -| Field | Type | Required | Description | -| ---------- | ------ | -------- | ------------------------------------------------------------- | -| `model` | string | ✓ | Target model (inline format or reference to `models` section) | -| `examples` | array | ✓ | Example phrases that should route to this model | - -## Matching Behavior - -The router: - -1. Extracts the last user message from the conversation -2. Searches all examples using full-text search -3. Aggregates match scores by route (best score per route wins) -4. Selects the route with the highest overall score -5. Falls back to the base model if no good match is found - -> [!TIP] -> **Writing Good Examples** -> -> - Use diverse phrasing that captures the intent -> - Include keywords users actually use -> - Add 5-10 examples per route for best results -> - Examples don't need to be exact matches — the router uses semantic similarity - -## Use Cases - -### Cost Optimization - -Route simple queries to cheaper models: - -```yaml -models: - cost_optimizer: - provider: openai - model: gpt-5-mini # Cheap fallback - routing: - - model: anthropic/claude-sonnet-4-5 - examples: - - "Complex analysis" - - "Detailed research" - - "Multi-step reasoning" -``` - -### Specialized Models - -Route coding tasks to code-specialized models: - -```yaml -models: - task_router: - provider: openai - model: gpt-5-mini # General fallback - routing: - - model: anthropic/claude-sonnet-4-5 - examples: - - "Write code" - - "Debug this function" - - "Review my implementation" - - "Fix this bug" - - model: openai/gpt-5 - examples: - - "Write a blog post" - - "Help me with writing" - - "Summarize this document" -``` - -### Load Balancing - -Distribute load across equivalent models from different providers: - -```yaml -models: - load_balancer: - provider: openai - model: gpt-5-mini - routing: - - model: anthropic/claude-sonnet-4-5 - examples: - - "First request pattern" - - "Another request type" - - model: google/gemini-2.5-flash - examples: - - "Different request pattern" - - "Alternative query style" -``` - -## Debugging - -Enable debug logging to see routing decisions: - -```bash -$ docker agent run config.yaml --debug -``` - -Look for log entries like: - -```text -"Rule-based router selected model" router=smart_router selected_model=anthropic/claude-sonnet-4-5 -"Route matched" model=anthropic/claude-sonnet-4-5 score=2.45 -``` - -> [!WARNING] -> **Limitations** -> -> - Routing only considers the last user message, not full conversation context -> - Very short messages may not match well — consider your fallback carefully -> - Each routed model creates a separate provider connection diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/sandbox/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/sandbox/index.md deleted file mode 100644 index ec8cf9540d50..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/sandbox/index.md +++ /dev/null @@ -1,286 +0,0 @@ ---- -title: "Sandbox Mode" -description: "Run agents in an isolated sandbox VM managed by sbx." -keywords: docker agent, sbx, ai agents, configuration, yaml, sandbox mode -weight: 80 -canonical: https://docs.docker.com/ai/docker-agent/configuration/sandbox/ ---- - -_Run agents in an isolated sandbox VM managed by [`sbx`](https://docs.docker.com/ai/sandboxes/)._ - -## Overview - -Sandbox mode is Docker Agent's integration with -[`sbx`](https://docs.docker.com/ai/sandboxes/), Docker's sandbox product. `sbx` -provides the runtime, CLI, and VM; Docker Agent is one of its built-in agents. -The `--sandbox` flag asks `sbx` to create or reuse a VM and launches Docker -Agent inside it. - -All shell, filesystem, and process activity happens inside that VM, so a -misbehaving agent cannot touch files outside the mounted working directory or -reach long-lived host state. Docker Agent does not implement the sandbox or -start a raw `docker run` container; it orchestrates the installed `sbx` CLI. - -> [!NOTE] -> **Requirements** -> -> Install and configure the [`sbx` CLI](https://docs.docker.com/ai/sandboxes/) before -> using `--sandbox`. - -## Usage - -Enable sandbox mode with the `--sandbox` flag on the `docker agent run` command: - -```bash -docker agent run --sandbox agent.yaml -``` - -Docker Agent asks `sbx` to launch or reuse a sandbox VM, mounts the current -working directory, and runs the agent inside it. - -## Flags - -| Flag | Default | Description | -| ------------- | -------------------------------------------- | --------------------------------------------------------------------------------------------------------- | -| `--sandbox` | `false` | Enable sandbox mode. | -| `--template` | `docker/docker-agent-sbx-templates:latest` | OCI image used as the sandbox template. Passed to `sbx create -t`. See [Sandbox templates](#sandbox-templates). | -| `--no-kit` | `false` | Disable the [auto-kit](#auto-kit) — do not stage skills or prompt files into the sandbox. | - -```bash -# Use a custom template image -docker agent run --sandbox --template myorg/custom-agent-template:latest agent.yaml - -# Run without staging skills / prompt files into the sandbox -docker agent run --sandbox --no-kit agent.yaml -``` - -### Always sandbox a given agent - -Add `--sandbox` to an [alias](../../features/cli/index.md#docker-agent-alias) so the -sandbox path is taken automatically whenever that alias is invoked: - -```bash -docker agent alias add safe-coder myorg/coder --sandbox -docker agent run safe-coder -``` - -An explicit `--sandbox=false` on the command line still wins, so you can opt -out of the sandbox for a single run without touching the alias. - -### Bake the default into the agent config - -Agent authors can declare a sandbox default in the YAML itself. Any caller of -the agent then gets the sandbox path automatically, without having to know -(or remember) to pass `--sandbox`: - -```yaml -# agent.yaml -runtime: - sandbox: true - -agents: - root: - model: openai/gpt-4o - description: A helpful assistant - instruction: You are a helpful assistant. - toolsets: - - type: shell -``` - -```bash -docker agent run agent.yaml # runs in a sandbox automatically -``` - -The rule is the same as for aliases: an explicit `--sandbox=false` on the -CLI overrides the config default, so you can debug an agent on the host -without editing its YAML. - -### Declare a network allowlist - -The runner already opens the [tool install hosts](#network-allowlist) and -the [models gateway](#how-it-works) automatically, but agents that talk -to endpoints those resolvers can't infer (custom MCP servers, third-party -APIs, registries not covered by the aqua resolver) would still see a 403 -from the sandbox proxy on first contact. - -Declare those hosts in `runtime.network_allowlist` and they are unioned -with the inferred set, so the agent can reach them on its first request: - -```yaml -# agent.yaml -runtime: - sandbox: true - network_allowlist: - - api.example.com - - registry.npmjs.org -``` - -Each entry is a hostname with an optional `:port` suffix. Commas and -whitespace are rejected to keep a single entry from smuggling several -rules into the policy engine. The runner prints the resulting allowlist -before launch so you can audit exactly which hosts the run opens up. - -### Persist your own allowlist - -For hosts you keep needing across agents (a corporate proxy, a -self-hosted registry, ...) `docker agent sandbox allow` writes the -entry into `~/.config/cagent/config.yaml` once and unions it with the -inferred and agent-declared sets on every subsequent `--sandbox` run: - -```bash -# I just got a `Blocked by network policy` 403 on api.example.com. -docker agent sandbox allow api.example.com - -# See what's currently persisted. -docker agent sandbox list - -# Drop a host you no longer need. -docker agent sandbox deny api.example.com -``` - -When the kit's per-toolset host resolver fails (the `! using fallback -host set` line in the launch summary), the runner now prints a hint -pointing at this command so you can turn the missing host into a -one-line, persistent fix instead of relying on the wider conservative -fallback host set. - -## Sandbox templates - -A sandbox template is the OCI image the sandbox VM boots from. It determines -the base OS and the tools available inside the VM, including whether the -`docker-agent` binary is already there. `--template` (or `-t` on `sbx -create`) selects it. - -### The default template - -`--template` defaults to `docker/docker-agent-sbx-templates:latest`, the -template this repository's own CI builds and publishes from the most recent -`v*` release — see [The repo-published templates](#the-repo-published-templates) -for what it contains and the other available tags. - -### The repo-published templates - -This repository's own CI builds and publishes the sandbox template — from -the `template` stage of the -[`Dockerfile`](https://github.com/docker/docker-agent/blob/main/Dockerfile) — -as `docker/docker-agent-sbx-templates`: - -| Tag | Built from | Use it when | -| --------- | ------------------------------ | ------------------------------------------------------------------- | -| `:latest` | The most recent `v*` release | You want the newest Docker Agent template with release stability (the default). | -| `:edge` | The current `main` branch | You want today's `main` build and can tolerate lower stability. | - -(Each release also publishes a matching version-pinned tag, e.g. -`docker/docker-agent-sbx-templates:1.2.3`.) - -`:latest` is the default. Reach for `:edge` only when you specifically -need an unreleased fix or feature and can tolerate the occasional breakage. -For reproducible runs, pin to a digest instead of a tag, e.g. -`docker/docker-agent-sbx-templates@sha256:...`. - -Select one with `--template`: - -```bash -$ docker agent run --sandbox --template docker/docker-agent-sbx-templates:edge agent.yaml -``` - -Or point the [`sbx`](https://docs.docker.com/ai/sandboxes/) CLI at it -directly, without going through Docker Agent: - -```bash -$ sbx create -t docker/docker-agent-sbx-templates:latest -``` - -> [!TIP] -> The [`sbx` documentation](https://docs.docker.com/ai/sandboxes/) covers the -> sandbox CLI and runtime independently of Docker Agent. - -### What they contain - -The `template` stage in this repository's -[`Dockerfile`](https://github.com/docker/docker-agent/blob/main/Dockerfile) -layers onto `docker/sandbox-templates:shell-docker` and adds: - -- The `docker-agent` binary. -- `vim` and `tmux`, for interactive debugging inside the VM. -- The **`docker-mcp`** Docker CLI plugin, installed at `~/.docker/cli-plugins/docker-mcp`. - -The image carries the label `com.docker.sandboxes.flavor=docker-agent-docker` -so sandbox tooling can identify it. - -## Example - -```yaml -# agent.yaml -agents: - root: - model: openai/gpt-4o - description: Agent with sandboxed shell - instruction: You are a helpful assistant. - toolsets: - - type: shell -``` - -```bash -docker agent run --sandbox agent.yaml -``` - -## How It Works - -1. `--sandbox` tells Docker Agent to invoke the installed `sbx` CLI. -2. A new sandbox VM is created from the image passed via `--template`. -3. The current working directory is mounted into the VM; the agent binary is copied in. -4. The [auto-kit](#auto-kit) is staged on the host and bind-mounted read-only into the VM, so the agent sees its skills and prompt files inside the sandbox. -5. The default-deny network proxy is opened for the configured [models gateway](../../features/cli/index.md#runtime-configuration-flags) and any package hosts the auto-installer needs for the agent's MCP/LSP toolsets. -6. All tools (shell, filesystem, background jobs, etc.) run inside the VM. -7. When the session ends, Docker Agent exits but does not stop or remove the sandbox VM; both the VM and the kit are kept around so subsequent runs from the same workspace can reuse them. A fresh sandbox is created only when the mount set has changed. - -### What the default template includes - -The default template (`docker/docker-agent-sbx-templates:latest`) is built -from this repository's own `Dockerfile` — see -[What they contain](#what-they-contain) for the exact contents, including -the `docker-mcp` CLI plugin. - -## Auto-Kit - -The sandbox VM has its own filesystem and `$HOME` — none of the host's `~/.agents/skills/`, `~/.claude/skills/`, project-level `.agents/skills/`, or prompt files like `AGENTS.md` and `CLAUDE.md` are visible inside it. To bridge that gap, Docker Agent automatically builds a **kit**: a self-contained directory staged on the host before the sandbox starts and bind-mounted read-only into the VM at the same path. - -The kit is built whenever `--sandbox` is used with an agent reference. It is opt-out via `--no-kit`. - -### What gets staged - -For the agent referenced on the command line, the kit collects: - -- **Local [skills](../../features/skills/index.md)** — every `SKILL.md` discovered on the host (global `~/.codex/skills/`, `~/.claude/skills/`, `~/.agents/skills/`, plus project `.claude/skills/`, `.github/skills/` and `.agents/skills/`) is copied under `/skills//`. The in-sandbox skills loader reads from the kit instead of the (non-existent) host `$HOME`. -- **Prompt files** — every file referenced via the agent's `add_prompt_files` (`AGENTS.md`, `CLAUDE.md`, …) is collected. Files that already live under the working directory are left alone (the live workspace mount surfaces them); files outside it (e.g. an `AGENTS.md` in `$HOME`) are copied under `/prompt_files/`. -- **A manifest** — `/manifest.json` records what was staged. The on-disk copy is sanitised so it cannot be used to map the host filesystem from inside the sandbox. - -Before launch, Docker Agent prints a summary of what was staged so you can see exactly which skills and prompt files the agent will have access to inside the sandbox. - -### Secret redaction - -Every text file copied into the kit is run through [portcullis](https://github.com/docker/portcullis), which redacts secrets that match its detection patterns (API keys, tokens, …) in the staged copy. The kit's printed summary marks files as `(redacted)` whenever at least one secret was replaced. Detection is best-effort — portcullis recognises common secret formats but novel or obfuscated tokens may slip through, so the kit is not a substitute for keeping secrets out of skill sources in the first place. - -### Network allowlist - -The sandbox templates ship with a default-deny network proxy that allows the major model providers but blocks `*.docker.com` and every package-registry / source host the auto-installer reaches for. When the agent declares MCP or LSP toolsets that have a `command` and an installable `version`, the kit build resolves each toolset's package against the [aqua](https://aquaproj.github.io/) registry and computes the minimal set of hosts the in-sandbox auto-installer will need (Go module proxy + toolchain bootstrap for `go_install` packages, GitHub release hosts for `github_release` packages, …). Those hosts, `models.dev` (needed so the in-sandbox agent can resolve model metadata such as context limits, pricing, and capabilities — without it the first catalog lookup fails with a `403 Blocked by network policy` error), and the configured [`--models-gateway`](../../features/cli/index.md#runtime-configuration-flags) — are then allow-listed on the sandbox proxy. If a per-toolset registry lookup fails, a conservative fallback union is used so the run can still succeed; the affected toolsets are surfaced in the printed summary. - -### Caching - -Kits are stored under the Docker Agent cache directory (`~/Library/Caches/cagent/sandbox-kits/` on macOS) keyed by a content hash of the agent reference. Reusing the same agent across runs reuses the same kit directory in place; disk usage is bounded by the number of distinct agents you have run. Kits are deliberately kept on disk between runs because the reused sandbox VM holds a hard reference to the kit's bind-mount path — deleting it would leave the sandbox un-startable. - -### Disabling the kit - -Pass `--no-kit` to skip the kit build entirely. The agent then runs without any host-side skills or external prompt files visible inside the sandbox, and the network allowlist falls back to the template defaults. Useful for debugging the sandbox itself, or for agents that don't depend on host skills. - -```bash -docker agent run --sandbox --no-kit agent.yaml -``` - -> [!WARNING] -> **Limitations** -> -> - Sandboxes are reused across runs from the same workspace; if the required mount set changes (e.g. a new kit is staged), the previous sandbox is removed and a fresh one is created. -> - Only the working directory, the agent config directory, and (when staged) the kit directory are mounted; other host files are not visible to the agent. -> - Network egress is constrained by the sandbox backend's default-deny policy plus the per-run allowlist described above. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/structured-output/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/structured-output/index.md deleted file mode 100644 index 9dc4c9e30343..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/structured-output/index.md +++ /dev/null @@ -1,250 +0,0 @@ ---- -title: "Structured Output" -description: "Force the agent to respond with JSON matching a specific schema." -keywords: docker agent, ai agents, configuration, yaml, structured output -weight: 90 -canonical: https://docs.docker.com/ai/docker-agent/configuration/structured-output/ ---- - -_Force the agent to respond with JSON matching a specific schema._ - -## Overview - -Structured output constrains the agent's responses to match a predefined JSON schema. This is useful for building agents that need to produce machine-readable output for downstream processing, API responses, or integration with other systems. - -> [!NOTE] -> **When to Use** -> -> - Building API endpoints that need consistent JSON responses -> - Data extraction and transformation pipelines -> - Agents that feed into other automated systems -> - Ensuring predictable output format for parsing - -## Configuration - -```yaml -agents: - analyzer: - model: openai/gpt-4o - description: Code analyzer that outputs structured results - instruction: | - Analyze the provided code and identify issues. - Return your findings in the structured format. - structured_output: - name: analysis_result - description: Code analysis findings - strict: true - schema: - type: object - properties: - issues: - type: array - items: - type: object - properties: - severity: - type: string - enum: ["error", "warning", "info"] - line: - type: integer - message: - type: string - required: ["severity", "line", "message"] - summary: - type: string - required: ["issues", "summary"] -``` - -## Properties - -| Property | Type | Required | Description | -| ------------- | ------- | -------- | ----------------------------------------------------------------- | -| `name` | string | ✓ | Name identifier for the output schema | -| `description` | string | ✗ | Description of what the output represents | -| `strict` | boolean | ✗ | Enforce strict schema adherence — `native` mode only (default: `false`) | -| `schema` | object | ✓ | JSON Schema defining the output structure | -| `mode` | string | ✗ | Enforcement mode: `native` (default) or `tool` (see [Modes](#modes)) | - -## Modes - -### `native` (default) - -The schema is passed to the provider's native structured-output support (OpenAI JSON mode, Gemini JSON mode, ...). Omitting `mode` keeps this behavior. - -### `tool` - -```yaml -structured_output: - mode: tool - name: analysis_result - schema: - type: object - properties: - summary: - type: string - required: ["summary"] -``` - -In tool mode nothing is sent to the provider's native structured-output API. Instead, the runtime exposes an internal tool named `__structured_output__` whose parameters are exactly the configured schema. The model works normally — including calling other tools — and delivers its final answer by calling that tool, alone, as the only tool call of its response. The runtime validates the arguments against the schema: - -- A valid call ends the turn; the validated (compacted) JSON becomes the final assistant message. -- Invalid JSON gets a detailed tool error so the model can correct itself and retry. -- If the model answers in plain text instead, the runtime injects a transient system reminder and retries (at most 2 reminders), then fails with a `structured_output_failed` error. - -Tool-mode validation applies the full JSON Schema, including `additionalProperties` — unexpected fields are rejected when the schema forbids them. External `$ref` references (`http(s)://`, `file://`, cross-document) are rejected when the schema is compiled; only same-document references starting with `#` (e.g. `#/definitions/item`) are allowed. The `strict` flag has no effect in tool mode. - -Fork-mode skills (`context: fork`) run as exempt sub-sessions: the skill produces its own plain-text answer for the calling agent and is not required to call the output tool. The parent agent still delivers its final answer through the tool. - -Use tool mode when the model must combine tool use with a schema-constrained final answer, or when the provider has no native structured-output support. See [`examples/structured-output-tool-mode.yaml`](https://github.com/docker/docker-agent/blob/main/examples/structured-output-tool-mode.yaml). - -## Schema Format - -The schema follows [JSON Schema](https://json-schema.org/) specification. Common schema types: - -### Simple Object - -```yaml -schema: - type: object - properties: - name: - type: string - count: - type: integer - active: - type: boolean - required: ["name", "count"] -``` - -### Array of Objects - -```yaml -schema: - type: object - properties: - items: - type: array - items: - type: object - properties: - id: - type: string - value: - type: number - required: ["id", "value"] - required: ["items"] -``` - -### Enum Values - -```yaml -schema: - type: object - properties: - status: - type: string - enum: ["pending", "approved", "rejected"] - priority: - type: string - enum: ["low", "medium", "high", "critical"] - required: ["status"] -``` - -## Strict Mode - -`strict` only applies to `native` mode: it is passed to the provider's structured-output API. Tool mode ignores it and always validates against the full schema instead. When `strict: true`, the model is constrained to only produce output that exactly matches the schema. This provides stronger guarantees but may limit the model's flexibility. - -- **`strict: false` (default)** — model aims to match the schema but may include additional fields or slight variations. -- **`strict: true`** — model output is constrained to exactly match the schema. Stronger guarantees. - -## Provider Support - -Structured output support varies by provider: - -| Provider | Support | Notes | -| ------------- | ---------- | --------------------------------------- | -| OpenAI | ✓ Full | Native JSON mode with schema validation | -| Anthropic | ✓ Full | Tool-based structured output | -| Google Gemini | ✓ Full | Native JSON mode | -| AWS Bedrock | ✓ Partial | Depends on underlying model | -| DMR | ⚠️ Limited | Depends on model capabilities | - -## Example: Data Extraction Agent - -```yaml -agents: - extractor: - model: openai/gpt-4o - description: Extract structured data from text - instruction: | - Extract contact information from the provided text. - Return all found contacts in the structured format. - structured_output: - name: contacts - description: Extracted contact information - strict: true - schema: - type: object - properties: - contacts: - type: array - items: - type: object - properties: - name: - type: string - description: Full name of the contact - email: - type: string - description: Email address - phone: - type: string - description: Phone number - company: - type: string - description: Company or organization - required: ["name"] - total_found: - type: integer - description: Total number of contacts found - required: ["contacts", "total_found"] -``` - -## Example: Classification Agent - -```yaml -agents: - classifier: - model: anthropic/claude-sonnet-4-5 - description: Classify support tickets - instruction: | - Classify the support ticket into the appropriate category - and priority level based on its content. - structured_output: - name: ticket_classification - strict: true - schema: - type: object - properties: - category: - type: string - enum: - ["billing", "technical", "account", "feature_request", "other"] - priority: - type: string - enum: ["low", "medium", "high", "urgent"] - confidence: - type: number - minimum: 0 - maximum: 1 - description: Confidence score between 0 and 1 - reasoning: - type: string - description: Brief explanation for the classification - required: ["category", "priority", "confidence"] -``` - -> [!WARNING] -> **Tool Limitations** -> -> When using native structured output, the agent typically cannot use tools since its response format is constrained to the schema. Design your agent workflow accordingly — native structured output agents work best for single-turn analysis or extraction tasks. Use `mode: tool` when the agent needs to call tools before producing its schema-constrained final answer. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/tools/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/tools/index.md deleted file mode 100644 index ff25b1f45ba0..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/tools/index.md +++ /dev/null @@ -1,518 +0,0 @@ ---- -title: "Tool Configuration" -description: "Complete reference for configuring built-in tools, MCP tools, and Docker-based tools." -keywords: docker agent, ai agents, configuration, yaml, tool configuration -linkTitle: "Tool Config" -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/configuration/tools/ -aliases: - - /ai/docker-agent/reference/toolsets/ ---- - -_Complete reference for configuring built-in tools, MCP tools, and Docker-based tools._ - -## Built-in Tools - -Built-in tools are included with Docker Agent and require no external dependencies. Add them to your agent's `toolsets` list by `type`. Each tool's dedicated page covers its full configuration options, available operations, and examples. - -| Type | Description | Page | -| --- | --- | --- | -| `filesystem` | Read, write, list, search, navigate | [Filesystem](../../tools/filesystem/index.md) | -| `git` | Read-only repository inspection (status, log, branches, show, blame) | [Git](../../tools/git/index.md) | -| `shell` | Execute shell commands synchronously | [Shell](../../tools/shell/index.md) | -| `background_jobs` | Run and manage long-running shell commands | [Background Jobs](../../tools/background-jobs/index.md) | -| `scheduler` | Schedule instructions to run at a time or on a recurring interval | [Scheduler](../../tools/scheduler/index.md) | -| `think` | Reasoning scratchpad | [Think](../../tools/think/index.md) | -| `plan` | Shared persistent scratchpad for multi-agent collaboration | [Plan](../../tools/plan/index.md) | -| `session_plan` | Per-session markdown plan for the draft-review-execute workflow | [Session Plan](../../tools/session_plan/index.md) | -| `session_context` | Reference a previous session as context (read-only) | [Session Context](../../tools/session_context/index.md) | -| `todo` | Task list management | [Todo](../../tools/todo/index.md) | -| `memory` | Persistent key-value storage (SQLite) | [Memory](../../tools/memory/index.md) | -| `tasks` | Persistent task database shared across sessions | [Tasks](../../tools/tasks/index.md) | -| `fetch` | HTTP `GET` requests with text/markdown/html output | [Fetch](../../tools/fetch/index.md) | -| `script` | Custom shell scripts as tools | [Script](../../tools/script/index.md) | -| `lsp` | Language Server Protocol integration | [LSP](../../tools/lsp/index.md) | -| `api` | Custom HTTP API tools | [API](../../tools/api/index.md) | -| `openapi` | Import every operation of an OpenAPI 3.x document as tools | [OpenAPI](../../tools/openapi/index.md) | -| `rag` | Retrieval-augmented generation over indexed sources | [RAG](../../tools/rag/index.md) | -| `model_picker` | Let the agent pick between several models per turn | [Model Picker](../../tools/model-picker/index.md) | -| `user_prompt` | Interactive user input | [User Prompt](../../tools/user-prompt/index.md) | -| `open_url` | Open a fixed URL in the user's default browser | [Open URL](../../tools/open-url/index.md) | -| `transfer_task` | Delegate to sub-agents (auto-enabled) | [Transfer Task](../../tools/transfer-task/index.md) | -| `background_agents` | Parallel sub-agent dispatch | [Background Agents](../../tools/background-agents/index.md) | -| `webhook` | Reliable notifications to a configured destination, with retries (Slack, Discord, Telegram, IFTTT, Teams, …) | [Webhook](../../tools/webhook/index.md) | -| `handoff` | Local conversation handoff to another agent in the same config (auto-enabled by `handoffs:`) | [Handoff](../../tools/handoff/index.md) | -| `a2a` | A2A remote agent connection | [A2A](../../tools/a2a/index.md) | -| `mcp_catalog` | Discover and activate remote MCP servers from the Docker MCP Catalog on demand | [MCP Catalog](../../tools/mcp-catalog/index.md) | - -**Example:** - -```yaml -toolsets: - - type: filesystem - - type: shell - - type: background_jobs - - type: think - - type: todo - - type: memory - path: ./dev.db -``` - -## MCP Tools - -Extend agents with external tools via the [Model Context Protocol](https://modelcontextprotocol.io/). For a standalone overview of the `mcp` toolset see the [MCP tool page](../../tools/mcp/index.md). - -> [!TIP] -> **Reusable MCP definitions** -> -> Repeated MCP server definitions can be hoisted into the top-level `mcps:` section and referenced by name with `{type: mcp, ref: }`. See [Reusable MCP Servers](../overview/index.md#reusable-mcp-servers-mcps). - -### Docker MCP (Recommended) - -Run MCP servers as secure Docker containers via the [MCP Gateway](https://github.com/docker/mcp-gateway): - -```yaml -toolsets: - - type: mcp - ref: docker:duckduckgo # web search - - type: mcp - ref: docker:github-official # GitHub integration -``` - -Browse available tools at the [Docker MCP Catalog](https://hub.docker.com/search?q=&type=mcp). - -| Property | Type | Description | -| ------------- | ------ | ---------------------------------------------------------------- | -| `ref` | string | Docker MCP reference (`docker:name`) | -| `tools` | array | Optional: only expose these tools | -| `instruction` | string | Custom instructions injected into the agent's context | -| `config` | any | MCP server-specific configuration (passed during initialization) | -| `working_dir` | string | Working directory for the MCP gateway subprocess. Only applies when the catalog entry runs as a local process (not remote). Relative paths are resolved against the agent's working directory. Supports `${env.VAR}` (canonical), plus `~` and shell-style `$VAR`/`${VAR}` expansion ([details](../overview/index.md#variable-expansion-in-config-fields)). | - -### Local MCP (stdio) - -Run MCP servers as local processes communicating over stdin/stdout: - -```yaml -toolsets: - - type: mcp - command: python - args: ["-m", "mcp_server"] - tools: ["search", "fetch"] - env: - API_KEY: value -``` - -| Property | Type | Description | -| --- | --- | --- | -| `command` | string | Command to execute the MCP server | -| `args` | array | Command arguments | -| `tools` | array | Optional: only expose these tools | -| `env` | object | Environment variables (key-value pairs) | -| `working_dir` | string | Working directory for the MCP server process. Relative paths are resolved against the agent's working directory. Defaults to the agent's working directory when omitted. Supports `${env.VAR}` (canonical), plus `~` and shell-style `$VAR`/`${VAR}` expansion ([details](../overview/index.md#variable-expansion-in-config-fields)). | -| `instruction` | string | Custom instructions injected into the agent's context | -| `version` | string | Package reference for [auto-installing](#auto-installing-tools) the command binary | - -### Remote MCP (Streamable HTTP / SSE) - -Connect to MCP servers over the network: - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp-server.example.com" - transport_type: "streamable" - headers: - Authorization: "Bearer your-token" - # Optional: allow OAuth helper requests to reach private/internal IPs. - allow_private_ips: true - tools: ["search_web", "fetch_url"] -``` - -| Property | Type | Description | -| ----------------------- | ------- | --------------------------------------------------------------------------------------------------------------------- | -| `remote.url` | string | URL of the MCP server. Accepts `https://`, `http://`, and `unix://` (Unix domain socket) schemes. | -| `remote.transport_type` | string | `streamable` or `sse` | -| `remote.headers` | object | HTTP headers sent on every request. Values support `${env.VAR}` and `${headers.NAME}` placeholders, resolved per request. `${env.VAR}` reads an environment variable; `${headers.NAME}` forwards a header from the caller's incoming request (useful when Docker Agent runs as an API server). | -| `allow_private_ips` | boolean | Permit remote MCP OAuth helper requests to dial non-public IP addresses. Use only for trusted internal servers. | - -## Auto-Installing Tools - -When configuring MCP or LSP tools that require a binary command, Docker Agent can **automatically download and install** the command if it's not already available on your system. This uses the [aqua registry](https://github.com/aquaproj/aqua-registry) — a curated index of CLI tool packages. - -### How It Works - -1. When a toolset with a `command` is loaded, Docker Agent checks if the command is available in your `PATH` -2. If not found, it checks the Docker Agent tools directory (`~/.cagent/tools/bin/`) -3. If still not found, it looks up the command in the aqua registry and installs it automatically - -### Explicit Package Reference - -Use the `version` property to specify exactly which package to install: - -```yaml -toolsets: - - type: mcp - command: gopls - version: "golang/tools@v0.21.0" - args: ["mcp"] - - type: lsp - command: rust-analyzer - version: "rust-lang/rust-analyzer@2024-01-01" - file_types: [".rs"] -``` - -The format is `owner/repo` or `owner/repo@version`. When a version is omitted, the latest release is used. - -### Automatic Detection - -If the `version` property is not set, Docker Agent tries to auto-detect the package from the command name by searching the aqua registry: - -```yaml -toolsets: - - type: mcp - command: gopls # auto-detected as golang/tools - args: ["mcp"] -``` - -### Checksum Verification - -Where the aqua registry includes a checksum manifest, downloaded binaries are verified against it before installation. Verification behaviour depends on the checksum type advertised: - -- **Strong checksums (sha256, sha512, etc.)** — verified before the binary is installed. If the downloaded archive does not match, the install is aborted and an error is returned (fails closed). -- **Unsupported or weak checksum types (e.g. md5, sha1)** — skipped with a warning; installation proceeds without verification. -- **No manifest** — if no checksum is advertised in the registry entry, the binary is installed without verification. - -### version_overrides Resolution - -The auto-installer correctly resolves **`version_overrides`** entries in the aqua registry. Many common tools (for example, `fzf`) keep their package configuration — including download URLs and checksums — under `version_overrides` rather than at the top level of their registry entry. These tools previously failed to install silently; they are now handled correctly. - -### Disabling Auto-Install - -**Per toolset** — set `version` to `"false"` or `"off"`: - -```yaml -toolsets: - - type: mcp - command: my-custom-server - version: "false" -``` - -**Globally** — set the `DOCKER_AGENT_AUTO_INSTALL` environment variable: - -```bash -export DOCKER_AGENT_AUTO_INSTALL=false -``` - -### Environment Variables - -| Variable | Default | Description | -| ---------------------------- | ------------------ | ------------------------------------------------ | -| `DOCKER_AGENT_AUTO_INSTALL` | (enabled) | Set to `false` to disable all auto-installation | -| `DOCKER_AGENT_TOOLS_DIR` | `~/.cagent/tools/` | Base directory for installed tools | -| `GITHUB_TOKEN` | — | GitHub token to raise API rate limits (optional) | - -Installed binaries are placed in `~/.cagent/tools/bin/` and cached so they are only downloaded once. - -> [!TIP] -> Auto-install supports both Go packages (via `go install`) and GitHub release binaries (via archive download). The aqua registry metadata determines which method is used. - -## Toolset Lifecycle - -Long-running toolsets — local MCP servers (stdio), remote MCP servers (Streamable HTTP / SSE), and LSP servers — are managed by a single supervisor that can auto-reconnect them when they crash, time out, or drop their session. The `lifecycle` block on the toolset lets you tune that supervisor per toolset. It applies to every `type: mcp` and `type: lsp` toolset. - -The simplest knob is `profile`, which picks a preset: - -| Profile | Auto-restart | Use case | -| --- | --- | --- | -| `resilient` | Yes | Default. Exponential backoff on disconnect; the agent keeps running if the toolset is unavailable. Matches the historical Docker Agent behaviour. | -| `strict` | No | Fail-fast. Marks the toolset as required. Intended for CI / headless runs where a missing dependency should be a hard error. | -| `best-effort` | No | Single attempt, no retries. Good for experimental MCPs whose flakiness should not amplify into a restart loop. | - -```yaml -toolsets: - - type: mcp - ref: docker:duckduckgo - lifecycle: - profile: resilient # default; shown here for clarity - - - type: lsp - command: gopls - file_types: [".go"] - lifecycle: - profile: strict - - - type: mcp - ref: docker:openbnb-airbnb - lifecycle: - profile: best-effort -``` - -### Tuning the defaults - -Any field set on `lifecycle` overrides the profile preset, so you can mix-and-match: pick a profile and only override the knobs you care about. - -```yaml -toolsets: - - type: mcp - command: ["docker", "mcp", "gateway"] - lifecycle: - profile: resilient - max_restarts: 10 # keep trying longer than the default of 5 - backoff: - initial: 500ms - max: 1m - multiplier: 2 - jitter: 0.2 # 20% random offset to avoid thundering-herd retries -``` - -| Property | Type | Description | -| --- | --- | --- | -| `profile` | string | One of `resilient` (default), `strict`, `best-effort`. Picks defaults for every other field. | -| `restart` | string | When the supervisor should reconnect after a disconnect: `never`, `on_failure` (default), or `always`. For **remote** MCP toolsets (Streamable HTTP / SSE), `on_failure` is automatically promoted to `always` so idle-timeout closes reconnect gracefully — `never` is still honored. | -| `max_restarts` | int | Maximum consecutive restart attempts before the toolset is marked `Failed`. `0` uses the profile default (5); `-1` means unlimited. | -| `backoff.initial` | duration | First wait between attempts (Go duration: `500ms`, `1s`, …). Default: `1s`. | -| `backoff.max` | duration | Cap on the wait between attempts. Default: `32s`. | -| `backoff.multiplier` | number | Multiplier applied each attempt. Default: `2`. | -| `backoff.jitter` | number | Fraction (0..1) of the computed delay applied as a uniform random offset. `0` disables jitter (default). | -| `required` | boolean | Marks the toolset as critical. Today this is informational; a future eager-startup phase will refuse to start the agent when a required toolset cannot reach Ready. Defaults to `true` under `strict`, `false` otherwise. | -| `startup_timeout` | duration | Cap on the initial connect+initialize duration. Enforced since v1.94.0: on expiry the toolset stays stopped and the runtime retries on the next turn. | -| `call_timeout` | duration | Cap on an individual tool call, including one reconnect-retry. Enforced: on expiry the call is cancelled and surfaced to the model as a tool error; cancellation is propagated to the server. `0`/unset means no timeout — opt-in only, no profile default. | - -> [!NOTE] -> **`required` is not yet enforced** -> -> The schema validates this field and the supervisor stores it, but no code path acts on it yet. It is documented now so config files written today keep working when the planned eager-startup phase lands. Picking the `strict` profile is forward-compatible — it will start enforcing `required=true` automatically. - -### Inspecting and restarting toolsets at runtime - -The TUI exposes the supervisor through two slash commands: - -- `/tools` — the unified tools dialog. Its top section lists every toolset on the current agent with its lifecycle state (`Stopped`, `Starting`, `Ready`, `Degraded`, `Restarting`, `Failed`), restart count, and last error; its bottom section lists every tool the agent can call, grouped by category. Use this to answer both "what can the agent do?" and "is anything degraded?" with one command. -- `/toolset-restart ` — force the supervisor to reconnect the named toolset. Useful after completing OAuth, when a remote MCP server has been redeployed, or when an LSP like `gopls` is stuck. - -See the [TUI reference](../../features/tui/index.md) for the full list of slash commands. - -See [`examples/lifecycle.yaml`](https://github.com/docker/docker-agent/blob/main/examples/lifecycle.yaml) for a complete lifecycle configuration example. - -## TOON-Encoded Tool Outputs - -Many MCP servers return verbose JSON responses that consume a lot of context budget. The `toon` field on a toolset transparently re-encodes matching tools' JSON output as [TOON](https://github.com/alpkeskin/gotoon) — a compact, model-friendly key/value format — before the result is shown to the model. - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - toon: ".*" # toonify every tool from this MCP server - - type: mcp - command: my-server - toon: "list_.*,get_.*" # only toonify list_/get_ tools -``` - -| Property | Type | Description | -| -------- | ------ | ----------- | -| `toon` | string | Comma-delimited list of regular expressions matching tool names whose JSON output should be re-encoded as TOON. Non-JSON outputs and non-matching tools are passed through untouched. | - -When a tool's output is not valid JSON, it is returned unchanged — TOON encoding is best-effort and never breaks tools that emit plain text. - -> [!NOTE] -> **When to use TOON** -> -> TOON typically yields 30-60% smaller payloads than equivalent JSON for MCP tools that return arrays of records (issue lists, search results, file listings, …). It works best when the schema is regular; one-off responses with deeply nested or heterogeneous shapes may benefit less. - -## Per-Toolset Model Routing - -The `model` field on a toolset overrides which LLM is invoked for the **next turn** after a tool from that toolset returns — letting you process simple tool results (file reads, knowledge-base lookups, shell stdout) with a cheaper or faster model while keeping the agent's primary model for reasoning. - -```yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - fast: - provider: anthropic - model: claude-haiku-4-5 - -agents: - root: - model: primary - toolsets: - - type: filesystem - model: fast # process file reads with the fast model - - type: shell - model: fast # ditto for shell stdout - - type: mcp - ref: docker:github-official - model: openai/gpt-4o-mini # inline provider/model also works -``` - -| Property | Type | Description | -| -------- | ------ | ----------- | -| `model` | string | Model used for the LLM turn that processes tool results from this toolset. Either a name from the `models:` section or an inline `provider/model` (e.g. `openai/gpt-4o-mini`). The override is **one-shot**: subsequent turns return to the agent's primary model. | - -When multiple tool calls in a single turn come from toolsets with different `model` overrides, the runtime picks the override of the **first** tool call that has one set. See [`examples/per_tool_model_routing.yaml`](https://github.com/docker/docker-agent/blob/main/examples/per_tool_model_routing.yaml) for a complete configuration. - -## Tool Filtering - -Toolsets may expose many tools. Use the `tools` property to whitelist only the ones your agent needs. This works for any toolset type — not just MCP: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - tools: ["list_issues", "create_issue", "get_pull_request"] - - type: filesystem - tools: ["read_file", "search_files_content"] - - type: shell - tools: ["shell"] -``` - -> [!TIP] -> Filtering tools improves agent performance — fewer tools means less confusion for the model about which tool to use. - -## Tool Instructions - -Add context-specific instructions that get injected when a toolset is loaded: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - instruction: | - Use these tools to manage GitHub issues. - Always check for existing issues before creating new ones. - Label new issues with 'triage' by default. -``` - -By default, the `instruction:` field **replaces** the toolset's built-in instructions (if any). To keep the built-in guidance and add your own rules on top, include the `{ORIGINAL_INSTRUCTIONS}` placeholder anywhere in your instruction text. At runtime it expands to the toolset's default instructions: - -```yaml -toolsets: - # Enrich: keep built-in instructions, then add your own rules - - type: filesystem - instruction: | - {ORIGINAL_INSTRUCTIONS} - - ## Project-specific rules - - Never modify files outside the `src/` directory. - - Always create a backup before overwriting a file. - - # Enrich: prepend your rules before the built-in instructions - - type: shell - instruction: | - Important: only run commands inside the project root. - {ORIGINAL_INSTRUCTIONS} - - # Replace: omit the placeholder to discard built-in instructions entirely - - type: mcp - ref: docker:github-official - instruction: | - Only read GitHub issues. Never create, edit, or close anything. -``` - -Three patterns at a glance: - -| Pattern | Description | -| --- | --- | -| `{ORIGINAL_INSTRUCTIONS}` then your text | Append your rules after the defaults | -| Your text then `{ORIGINAL_INSTRUCTIONS}` | Prepend your rules before the defaults | -| No placeholder | Replace the defaults entirely | - -See [`examples/toolset_instructions.yaml`](https://github.com/docker/docker-agent/blob/main/examples/toolset_instructions.yaml) for a complete example. - -## Deferred Tool Loading - -Load tools on-demand to speed up agent startup. When a toolset is deferred, its tools are registered lazily — the tool server process is not started until the agent first calls one of its tools. This is useful for large toolsets (e.g., an MCP server with hundreds of tools) where startup time matters. - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - defer: true - - type: mcp - ref: docker:slack - defer: true - - type: filesystem -``` - -Or defer specific tools within a toolset: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - defer: - - "list_issues" - - "search_repos" -``` - -When `defer` is a list of tool names, only those specific tools are deferred; all other tools in the toolset load eagerly. Setting `defer: true` defers the entire toolset. - -### Tool Discovery with `search_tool` - -When an entire toolset is deferred (`defer: true`), the deferred toolset exposes two built-in tools to the agent: - -- **`search_tool`** — Discover available deferred tools by keyword. The search uses **fuzzy matching** against both tool names and descriptions: all characters of the query must appear in the target string in order (but not necessarily adjacently), so a query like `"crfil"` matches `"create_file"`. Returns a list of matching tool names with descriptions. -- **`add_tool`** — Activate a discovered tool by name so it becomes available for use. - -These tools let the agent browse a large toolset on-demand without activating every tool upfront. - -See [`examples/deferred.yaml`](https://github.com/docker/docker-agent/blob/main/examples/deferred.yaml) for a complete example. - -## Combined Example - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Full-featured developer assistant - instruction: You are an expert developer. - toolsets: - # Built-in tools - - type: filesystem - - type: shell - - type: think - - type: todo - - type: memory - path: ./dev.db - - type: user_prompt - # LSP for code intelligence - - type: lsp - command: gopls - file_types: [".go"] - # Custom scripts - - type: script - shell: - run_tests: - description: Run the test suite - cmd: task test - lint: - description: Run the linter - cmd: task lint - # Custom API tool - - type: api - api_config: - name: get_status - method: GET - endpoint: "https://api.example.com/status" - instruction: Check service health - # Docker MCP tools - - type: mcp - ref: docker:github-official - tools: ["list_issues", "create_issue"] - - type: mcp - ref: docker:duckduckgo - # Remote MCP - - type: mcp - remote: - url: "https://internal-api.example.com/mcp" - transport_type: "streamable" - headers: - Authorization: "Bearer ${env.INTERNAL_TOKEN}" -``` - -> [!WARNING] -> **Toolset Order Matters** -> -> If multiple toolsets provide a tool with the same name, the first one wins. Order your toolsets intentionally. diff --git a/_vendor/github.com/docker/docker-agent/docs/configuration/user-settings/index.md b/_vendor/github.com/docker/docker-agent/docs/configuration/user-settings/index.md deleted file mode 100644 index 92a050df6d03..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/configuration/user-settings/index.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: "User Settings" -description: "Full reference for the global settings block in ~/.config/cagent/config.yaml: theme, layout, YOLO, sound, snapshots, permissions, hooks, keybindings, and how they interact with agent config and CLI flags." -keywords: docker agent, ai agents, configuration, yaml, user settings, user config -linkTitle: "User Settings" -weight: 110 -canonical: https://docs.docker.com/ai/docker-agent/configuration/user-settings/ ---- - -_Full reference for the global settings block in your user config file._ - -## Where Settings Live - -Docker Agent reads a single user-level config file, independent of any agent YAML: - -```text -~/.config/cagent/config.yaml -``` - -The `settings:` block inside it holds preferences that apply to every agent you run — appearance, behavior, notifications, and a few global safety defaults. Everything under `settings:` is optional; an unset field falls back to the documented default. - -```yaml -# ~/.config/cagent/config.yaml -settings: - theme: dracula - lean: false - sound: true -``` - -You rarely need to hand-edit this file. Most fields are managed from the TUI's `/settings` dialog (**Appearance**, **Behavior**, **Notifications** tabs) — press Enter there to apply and persist a change. A few fields (`permissions`, `hooks`, `keybindings`) have no dialog UI and are only set by editing the file directly. - -> [!NOTE] -> This page documents `settings:`. The user config file also has top-level sections outside `settings:` — `aliases:`, `providers:`, `board:`, `credential_helper:`, `sandbox_allowlist:` — which are not covered here. - -## Settings Reference - -| Setting | Type | Default | Description | -| --- | --- | --- | --- | -| `hide_tool_results` | boolean | `false` | Hide tool call results in the TUI by default. Mirrors the `--hide-tool-results` flag and the Ctrl+O toggle. | -| `expand_thinking` | boolean | `false` | Start new sessions with thinking/tool blocks expanded instead of collapsed. | -| `split_diff_view` | boolean | `true` | Render file-edit diffs side-by-side instead of unified. | -| `render_images` | boolean | `true` | Render images in the TUI using the Kitty graphics protocol. Applies to both tool-result images and Markdown images in agent responses. Automatically disabled when the terminal does not support Kitty. | -| `theme` | string | `default` | Theme name, loaded from a built-in theme or `~/.cagent/themes/.yaml`. The special value `auto` follows the terminal's light/dark background. See [Theming](../../features/tui/index.md#theming). | -| `theme_dark` | string | `default` | Theme applied when `theme: auto` and the terminal background is dark. | -| `theme_light` | string | `default-light` | Theme applied when `theme: auto` and the terminal background is light. | -| `YOLO` | boolean | `false` | Auto-approve all tool calls globally, across every agent you run. Mirrors the `--yolo` flag and the `/yolo` command. Legacy alias for `safety: autonomous`; when both are set, `safety` wins. | -| `safety` | string | _unset_ | Default [safety mode](../permissions/index.md#safety-modes) for new sessions: `strict`, `balanced`, `restricted`, or `autonomous` (any other value fails config loading). Wins over the legacy `YOLO` flag. Applied when no explicit `--safety`/`--yolo` flag and no alias safety option was given; wins over the agent YAML's `agents..safety` / `runtime.safety` defaults. Never changes the mode of a resumed session. | -| `lean` | boolean | `false` | Make the [lean TUI](../../features/tui/index.md#lean-tui) (simplified, minimal-chrome interface) the default for interactive runs instead of the full TUI. | -| `tab_title_max_length` | int | `20` | Maximum display length for tab titles; longer titles are truncated with an ellipsis. | -| `restore_tabs` | boolean | `false` | Restore previously open tabs when launching the TUI. | -| `sound` | boolean | `false` | Play a notification sound on task success or failure. | -| `sound_threshold` | int | `10` | Minimum duration in seconds a task must run before a success sound plays (failures always play). | -| `snapshot` | boolean | `false` | Enable automatic shadow-git snapshots at turn boundaries globally. See [Snapshots](../../features/snapshots/index.md). | -| `cache_stable_prompts` | boolean | `false` | Keep changing trusted context (date, environment info, dynamic prompt files) out of the frozen system prefix and append chronological updates instead, improving prompt-cache hit rates on long sessions. | -| `warn_on_cache_miss` | boolean | `false` | Warn when a model call after the first one in a session reports no cached input tokens (a prompt-cache miss). Managed from the **Notifications** tab of `/settings`. | -| `busy_send_mode` | string | `steer` | What happens to a message sent while the agent is working: `steer` injects it into the ongoing stream; `queue` holds it until the current turn ends. | -| `interrupt_confirmation` | string | `always` | Controls how the Esc key interrupts a running stream: `always` (default) shows a confirmation dialog; `double-tap` requires pressing Esc twice within 1 second; `none` interrupts immediately without confirmation. Managed from the **Behavior** tab of `/settings`. | -| `permissions` | object | _unset_ | Global tool-permission rules (`allow` / `ask` / `deny`), merged with agent-level and session-level permissions. See [Permissions](../permissions/index.md#global-permissions). | -| `hooks` | object | _unset_ | Global lifecycle hooks applied to every agent, additive with agent-config and CLI hooks. See [Global (user-level) hooks](../hooks/index.md#global-user-level-hooks). | -| `keybindings` | array | _unset_ | Remap TUI keyboard shortcuts. See [Custom Keybindings](../../features/tui/index.md#custom-keybindings) for the full list of actions and syntax. | -| `layout` | object | _unset_ | Sidebar position and section visibility. See [Layout Settings](#layout-settings) below. | - -## Layout Settings - -`layout` customizes the TUI's sidebar. The zero value (an omitted `layout:` block, or any field left out) is the default: sidebar on the right, every section visible, normal spacing. - -| Field | Type | Default | Description | -| --- | --- | --- | --- | -| `sidebar_position` | string | `right` | `right`, `left`, `top`, or `bottom`. Left/right keep a full vertical sidebar; top/bottom render a compact horizontal band. | -| `section_spacing` | string | `normal` | `compact`, `normal`, or `relaxed` — the number of blank lines between sidebar sections. | -| `hide_session_path` | boolean | `false` | Hide the working-directory (session path) line, including its git branch. | -| `hide_usage` | boolean | `false` | Hide the token-usage section. | -| `hide_agents` | boolean | `false` | Hide the Agents section. | -| `active_agents_only` | boolean | `false` | Show only agents active in the current session in the Agents section (and the top/bottom band), instead of the whole configured team. Ignored while the Agents section is hidden. | -| `hide_tools` | boolean | `false` | Hide the Tools section. | -| `hide_todos` | boolean | `false` | Hide the Todos section. | - -```yaml -settings: - layout: - sidebar_position: left - section_spacing: compact - hide_usage: true -``` - -## Complete Example - -```yaml -# ~/.config/cagent/config.yaml -settings: - theme: auto - theme_dark: dracula - theme_light: default-light - lean: false - expand_thinking: false - split_diff_view: true - render_images: true - hide_tool_results: false - sound: true - sound_threshold: 10 - snapshot: true - cache_stable_prompts: true - warn_on_cache_miss: true - busy_send_mode: queue - interrupt_confirmation: double-tap - restore_tabs: true - tab_title_max_length: 24 - layout: - sidebar_position: right - section_spacing: normal - permissions: - deny: - - "shell:cmd=sudo*" - allow: - - "read_*" - hooks: - session_start: - - type: command - command: "~/.config/cagent/hooks/session-start.sh" - keybindings: - - action: "commands" - keys: ["f2", "ctrl+k"] -``` - -## Precedence Rules - -User settings are a **low-priority** source: they establish defaults, and anything more specific wins. - -- **CLI flags over user settings — except plain boolean flags going from `true` to `false`.** Where a `docker agent run` flag mirrors a setting, passing the flag for a specific run takes precedence over the setting for that run only, and the flag never modifies the saved user config file. This holds cleanly for `--lean` / `lean`, `--theme` / `theme`, and the safety flags `--safety` / `--yolo` (see below), which track whether the flag was explicitly passed on the command line. `--hide-tool-results` / `hide_tool_results` doesn't: it's a plain boolean with no "was this explicitly set" tracking, so passing `--hide-tool-results=false` cannot turn a saved `hide_tool_results: true` setting off for that run — the saved `true` wins and is reapplied on top of the flag. Passing the flag to turn it *on* works as expected regardless of the saved setting. -- **Safety has its own, fully-specified chain.** For a **new** session the first source in this order wins: explicit `--safety` flag > explicit `--yolo` flag > alias `safety`/`yolo` option > `settings.safety`/`settings.YOLO` > the agent YAML's `agents..safety` > the agent YAML's `runtime.safety` > the built-in default (read-only tools auto-approve, everything else asks). At each scope the `safety` field wins over the legacy `YOLO`/`yolo` boolean. Your settings therefore beat anything an agent author declared in YAML — an agent config loaded from a file, URL, or OCI registry can never override your `settings.safety`, alias option, or CLI flag. An explicit `--yolo=false` suppresses a saved `YOLO: true` / alias `yolo` for that run (other settings and YAML defaults still apply). **Resumed sessions keep their stored mode**: settings and alias defaults never touch them; only an explicit `--safety` or `--yolo` flag overrides a resume. See [Safety Modes](../permissions/index.md#safety-modes). -- **Aliases sit between CLI flags and user settings.** An [alias](../../features/cli/index.md#docker-agent-alias) (`docker agent alias add ...`) can bundle its own `yolo`, `safety`, `model`, `hide_tool_results`, and `sandbox` defaults; those apply when the corresponding flag was not explicitly passed, the same way user settings do, but are resolved after user settings so an alias's own choices take priority over your global defaults. -- **Permissions are merged, not overridden.** Global `settings.permissions` and an agent's own `permissions:` are combined into a single set of `deny` → `allow` → `ask` patterns before evaluation — a global deny always blocks, regardless of what the agent config allows. See [Merging Behavior](../permissions/index.md#merging-behavior). -- **Hooks are additive, not overridden.** For a given lifecycle event, hooks from the agent config, `settings.hooks`, `hooks.d/` drop-ins, and `--hook-*` CLI flags **all** run, in that order. Global hooks cannot be suppressed by an individual agent. -- **Everything else is a plain default.** Fields with no CLI or agent-config equivalent (`sound`, `sound_threshold`, `restore_tabs`, `tab_title_max_length`, `split_diff_view`, `render_images`, `cache_stable_prompts`, `warn_on_cache_miss`, `busy_send_mode`, `keybindings`, `layout`) only ever come from `settings:` (or the `/settings` dialog that writes it) — there is nothing to override them per run. diff --git a/_vendor/github.com/docker/docker-agent/docs/demo.gif b/_vendor/github.com/docker/docker-agent/docs/demo.gif deleted file mode 100644 index 03d4bfc0ec7ad76b29fb376eba3441c713cee96c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 568044 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 -}bZABV*Fn?2$wmA9SS%-`TB67DY=*RF~sR_i%s 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�W7_|xtpqUN@D;J3g%8fL{ z3Tc-y5klAwWg9+WzgcgAE&H!(-WF7B-bks>Hm9-nJ5pTbohGE&PEdR>M@&ctN{ zMay#}9UNovi07Nk%dt|_1%EU9#eLkc(uD-7(09+Q##j^U;hSYI0F5$RwB6KGsEtKP zkeL`30uMckCU(zhu`AdP0V+v+L`Vg*P_Ee4YLMiyGOLvh=qftS7ZwEP&EjslK6Hvk zuLmyNEY)Zf&~KD8Y|~XO=au{8&}Q=*NHqv@xk!l@Ley4_mxW~d84?-CK|S{NZv~iD znQd1xW}floVcB+k+VLzQn5-rj0HCS})>YtZT+0ECm9v9W$~G;H$hq?#Q{8W0owEN* z?47xb@V=W2t}T#LgmyE&CoEBN2#DAi)Fm~;$vTRNjt{gS^z8@%6F){SLnGb zTDM<4W@H=JEj|Jnp%Zoht0PlR`qX^H+-Kdw?ln!i$M^D1aM@a$UIbTOKU>!vdVG;F z4S8ofrM@o(phOHS`F)L1A;FOH#)(~#>d*8;9u+vuD5j8yVz;SG=i8ni=FWM8EEp|_ zzQf`8I+UI@Zn(MV4bEBwFEbe5yzE@{mlEBgw0T|wf znz14sWyVL?z?7+Zn3^qDvV~M;u@rzAI$CQEgFiP_ient((jNP8v%IU6cTzhbCmD~P zQ$?Ek3Shvwkq-@I`{o%%3UyxIUpvrFnJU{z z>kjK?${+*ch`PV4*xc9tcw>i-=7Bn=ukPi#t>uwFY%@h^v%=xrKOU7VZ44Ug)5y9J zI&}VtbI^E8auG@H2CC3+c+HM>z`OBlYKjw07A#9CJ6BwNha&}W(+*&#^%^X(h@SDV z&~1COR4>b-7dw(%US|Bv=Kh2JjIIwFb}Xdpb0g*Lm{i(Die%IJu$%s4ti)ZDk@czZ zD1+dlq)GR63zt8sdxtK&ocKF=YNaqGIuzND9CQ*tYm4C!3 zUitLfKGNy&u*y4OcJHT$k6-y_T)Z|p9zi)cRBh&bN|&FzZghBPVa!B?&P=6U6SZGC zp6NucQjv2-d4G;ieb!v{Y<-SWy`3ekM8U=aReP$4bkL02>t&g5GjiN8T{bCYX5R0?a@<+Bj04(ocMCb}2P*tkA z%XHjOEL>Fewtb~>MH-l_RCKJs8wdf+M-!PK4;2f(2nunV@i9P9Q>%P79M zWho5UwREUHN;z~pwgi51DPdflx*J1a4fXb zJ&936TqNC?YuNJ?ZlhdLcE`Wh-X3|X1jFN>y?Ua|REv23jT-0;T9@;v%`#;5(J`zaUGYO&m|@Q|WFX8b*@kVx z?pP5fRb;dC(!m?EuV**c>{L>VZM!1?LS-0}p`9Df=4_;6IkG&i6$!=4iD#kW=-3Pj znndA}*x9Rr{A3_Mh($c7@IB~Qa|pQNc6sqAhC|O^E#zSYuvbG~G6kC?M57zeS+G5m zVRRfFtuX}P{dub>`N^Z006_t&Eqfh=UQ5SrprJ_dFnkarUoXgum*lOIaAA8cs+@Oo z?nM$G?N-wsAD_P%K)_0QI_mlHP_|NlONb~h9>SQ%15W_NN-8FdBK8f1Gq;KY?{)^c zAIDvqefW_vLC9sYa?Jeas|jGCRk0}r8!}X;5)a$4^22FJd!gcm%u&M)Fu02e$wc~0 zqcr>hdwM>*Alpue3NPmtHk>n(AM8&rs(KC`irL~g-2A}C zUb$4gf7rDA;5Ju+DRC#P_!5Hg<#|Q`ceOB=MB{SCF=0b+s~#6y&f6%-3o6exYV&^J z2KdKg&HZ6bpsG}YiDbb_$Isyd3gd@z)rU$hSmmVmfJh;w#_NhcD`ypq$*jSc(cva1 zUgrlyd^!47HaaOR50RGVbLqymzzbLon3jn=yMh}%l&ekS8dViwhjLQNd6#?IR}G=D ztelNQ+_|RNC_2|cn2SrxOJbn}R>b*~d<)hEYrVYH1>E;w?z(Bjut~q^(%ZB2HJ+)T zKh#-RV~q?i;EKmFtyWm4p`EA(RP&6OD*zlMx$EMw@qFa|J3jt&tlVr`?SX%x;(ZhE zR_Hgr69eR=LD_cB2$Wk+x{!C`8;QctO%tL6fSgql4DuQ(&7XJd4q`1ItuBFAN-%zI zIRW!f&=3MCMKlaerYzZ;H;M_zA#$Jhtz-c{l03a0mJ1zlVdt+N zLNO&d$#BkzgL4hg3!g~fXedvcrWeY%?H6}@P1@jEXBG3qmogo-NkeeEkQXh(}< zBSWm0HWzy}E=qz-^Pi0s@>o6t>Qu~1 zHrIF$2}KRCW89$d;Z>5{u(z0qrTGpV0CAX$qQhn^te=0`ZINGc15ZixzbHEMcqslq zj?e6UA1v1HV%NFub*3n@M2K=zQADOriMlI_}#vr2@F3q-45ByE@6HKN5~a|owzk`+D@tQ0Wn zLR-pKlMBTjWqHw19tXadh{I@C<2vrbelQ9vLWXsTd1ZN;sh|%oKOREc!f5BTI`c7f zbQwC786P>a(qD$!5(Y1%<#Ae{o9Dktta@{zEPTf6)=_AH1?7t(hd+z<7(5Zv73a4k z0m$j|w)Os6E-zMvh}Wd$E7m@n4F=eWSE~j6o%frOflkp@0N^9Z;N}`IBGgX@MlrzLUv>R# z-J8mUcU7guYlzO*&c`05Mf_n)I(Oh1UA;7Z=|S%NyvHz+20jf0&6tR94~yZa zRuY5e8nu1O(AIop9B#FAM^EV(d?fQ!!PhrN?+SUV%@F4&_ar3u z+PF}YlMgn(@9%vt6`fr@_Wt6;`$Nqg7+m$}rum*zG(xpI$hBy2=-8wC;I*f@pSKV|3A{>8elfHW26v zSe?2}m%+>u;mnUuvzU$A`+Jq9vtOKNzk1Jp3!nX-F#98O_GkX=T-EHa=Gou9v;Pgx z{+XEl`)2mvk69H)3Fs(6GbLi461hZ)icq50DKT4>*a9W)pc3DrB%D*&zYHzDtH7}3i-kM&{GAS~x9NR&ZN6tqmZSyo z{`jBnFZT1ks$K(vzYAVn-{n`DBl-(wCkEp3*UZS`19+cx0~kc zY|i*?3#~iD{_pFHmFAx7zAfJPZOPWnOANmGK5u+cyxA42??gS~wQsY}&u`1H-}U4fLSsuN3LBEpiR@!`BiP3sW}H;Ii=Xq0$cCQ$)0)cqS-5ntW3__@MKT*-1ZMZT!>s7uY8WkG!d6=u19fzc-m_LiyzP$8wAlCC0MB_a9?EhWbE?9PFk#(9g>_)Mts!v*gR`J-5LY zW4Xq(Ph>u7$>f9GeQ;kQ&`cCxeh^1+-AV3)iGarK^UfhTpZX&Hl9yjWO^TNTIVdG= z$t}=|i!_V$Zor^a?ldV`fG`UTkj#O$e56rg*lmYGW}?Jiv8Z8|h_9B6Tpge>QA+}& z#mYsF>V1~@4ns$!fsM*AV6FZh*LKq>{}(eE@$o^+^w~{hd3uzSFihw z_DbN~0HDybmhw?b8_eZGY~w<@SAu6Dc_p+W7&Q}6yj$arXaTD2PKzzo`;X=N?#3c) zn4^hZpSbK8Q^z^$VcfgGt4y}Oe|^?Sd9#&9s1Fn2d%$o>DdpxQG*!?buHpX861^~< z=v;X=JI9lM+C00k{pXjD?|<4VWRls^ zKIPg2)vEm}=SFVadfXn<+R5B8sR!){Id1W;{m=_x`SQ5PKRdp(6{GOA&u>f$edv40 ztClF^e8Cr7A3N5E*2b&eB?jKH$xM5be1i5yf!00Q5>2{x6r+e^pT4-Tj ze#a`K@`A(xx8Gl9?w(#VJFxK2&o3|U9^H6p(ZBzGfBpJ=_NYn(64V+(G%JfM!CUlk zbI1$kq~YdzRn>T-L}iX?QM3})ubPC!1Q?Kb2Qmtk%W>Bi+6~csMS}$>YRVf=1UXTB zjmju22=lW%!=U@0{|guCTN;Chz7iZ&RE^i7dq_IN7li>RvN zR5apHe9bn~n)U7HOlwp7f0@>$kIpwcyyek0vm>;bb7n_({r+Vp6%!Wl>&e>AQ$FS< z^>|Hcs{&%xeh7T6R}-0(i?m3jdGf0G=pw^P<+ukjMR0bCQTxg#IJ_qyhP|N-J`1uM z3X{B2v>yoyOe%Ae@R~Sd-YA1ibGpiNGFGBZOZf;3<1%JUWjH%-KSuXq(s}E%Pq+VP z-8WV2YIE*&%?_LXckSnG&cE;8e;M7Wy}OJOt_C@y@+HWZL ztlSwYxw70fs%w3wyUVo~RAZ>vm%?%^OA2#6QgNrl`Y^K*!|RcubV~!x?qXCaiC@rk z*GQ0{iD&SNHA|D=4j~ZQR}@F6ckxq?T`(_qi=b%y;p)3NpB5=$pZ@ z9>Yj#V;YV(N~!yeBy*+W*Jgiz?$|9yx?fOU(cFFE^ED%PgC{p#Rc_zLm%1d7(PIi!T? zi|7Tr-9*@B)ne4jA4LX^Fy`U75LqI^FEx%azU_;^T~HPYZzw=JpHYf&8qabF-g@7a zM+j*h)avfav)LIVr8E&7`NJNH_l2gM&q#8at*f>@$PFAvJuI5itaQmWTD+f$9RV5W zbU@pWj>3PtWz3k91Xwi`8l)8BYFrGBAFY#+qojm}R-7?~SIpa>z%DsgWQemvk`raP zB|*6m!w#t@@7kCB$B2tG9}#MFZ(~V?V}x~A3?jv(u#rie2Nz+)oHFRI8KjMPqO8@? zPTo>E#*vn5+Q~&RCWV@Q({`PVo47UH97YCLtg`Es;Z|~UnB`*hi6>Bz^<;bfkLe1>s>TC_3Xn1hBQ4fx zU`y_LkfpG1?AZfYemR27XW>7zjhv`BfM8_-wo4_qHu-HhI$Z%T(v+Pi-;iN2e3&AT zW3Xk$BJvo3zJtHDH>2m6{$IY2=gO1E&Lov+{jR>?EtOQ%RBZ6`5c~QNv^DESnhvs$ znJjchXcS64ECcYG0%5_t&;|`pxTSo^QxaC()3$7vMd&e$`)&QHJLmI}dT+||OVyl; z)qgD_FI$8&z3t26%vXkc1Wuf4RcReJGw)b6-Yv#de?7eRqUGwZ?GG+~30t0;*Ae+> z)UPl6R9MxY_pkr49-J<`+PrI*Rh*IK!)w9XR>kPf2wd{Da`m|2(8m-n+w%`c%X@p8 z7g{Ho6CYiP&Fkv8-x;y`@xyy}dV6~>T5q`YZslZB{Mqj4j_~aBkDh3p?HgWblQH#X zm7;mexl139r){l$@-Fyn|HQ=&l3aGw+YFulC%ddOFIztQTz>Y#x?dZ##$BJh@!s0| zW|!^GmzK|8B^|st^ZMhe$CgijeK~vS-`|aE#$Av6SFGLjdy6fs*{MJ~Odk85dSCpY zeFb9ntXz9Qknixs1H5fIsQ>RozNgg-`hmz)6}NY`fcRlb<8U?>zbL;T$g`LSki(d|Y>KpN1WM6(>B04d~^z!iTEGLlSvpNE#D zEzvIQU~RS+ zN+VI0@3F4@a7tpfX)X1=h)5v8L8?b=k z58ORiE7LIEPw=%8g1Qd@Tz^_oD0dJ`hE-0-FI#^~-|A?x1kRtgdWw|Z#RDyr#i*SM zOmJU4&I$mr;V@3*^Fl*SZM-b|8&0sQ*FFO+w$AvB!ZkJ$&nPmjed=?txVk6Wmt2Pb zx=2tdv3iM+OszB~DqUPflzDT;Fqn7S8f2BBIYveO`!pVbblk_rwKp2wjw9W$K&zRJ_LR89i~!8K{(Z# z$7YPZ-xnl$e-IF2Xybc)86dcH?kBhzDqbCBh#{u^xP!EvlRsFBCc6we#*G8Eo7d{T znEZbJwEYLeZ-eCdeM1Bl1!|^q4Yge7=9|aTao8Jg5a`>N!Tz#6zV{k%ZP;Ng8m(~U zkc8nh=Q_3N)G8)|9((Q2#mnI3{E=7U4(Qi z6NAQUlIP1bK12`6g(Mf~Ml^zP&qHTUCO3z??8tt6_?BGAeKkm^Tl4#z&>E7Pa6JgJ zqkop7WSOn_KP=ot^UQI zg+>sj@lz$iKGD;WFL9`Rg6V{Gd=O*N9y*=SX(xd0<6*<8qb>$;>Y#O+yqDKtQw*Gz zgJbc}QH>B5mJv`0b2knHlDVhB&@JPDFGoHwh2*-s5ylM&D>26d!c^y?V3;y3LqPzp z&W8ZYf+aFk9SSFqQmsV6D}ynMA@Urw=*6ml%%%vNr*mU>-T$oB%!F@pJxFm7wr+8f z3xp|zf963+i7+loGipOA$_2u8#{1rjPx6PbSA)>wj=8ZG1}WtnC)1wy!r}y)0vi?x7NXh zRlbvE)s<%1TI9;t5j*dg!I;EVRuQpnZ&SqK*`MC-AnD*?1@rl;rUjCke);+_C`*!j7z9E))Pv-wy zm;bD_zt(*i^D;_X$wce^XM4(=RV#8S%>B;m%NLkeENZLpepjH^R;fK&fzi#@ zXx$fYUb)@8I=ihpzir>@wnLcFgBzxI{hm0~yFRPjJZqb7cE9=I1hd*V(^bOthd;F) z_IOxvtxde1Uvz|dRJ(o4_KBKB2RFxr?|ihbh-J~Z=4wz4FleRyVb(sIg}Y|+iUSD}YGKUrk>0jHk` zuU)7-IzN0F{e8^pHvs`ct%@XnJGvlDIjPmto4n!9Ff9^c0I3k#iU8jznCu8@_Q)ua2TY=2+W?TR9Gi12 zB7BfBnBekMfar6BOOw#MaQ?6F5|~1*(7VU`JBEi7o{7Y!OmSg_7MdhB6iF`VOE^(i z@)W4R5pcaDtU2d>Ey+W7Y?zw0*d&W!jFT)&geXe6=_@PKP}+(Oo#T>bd}O`>M}ipw zO+Spg-=LuX0{Vr6oK^sR1JKtMQ{3dHZm1i@gFFRhDz%H3v8$~SR`n-phR`n1>Smjn6DMYRZQc)@ct33O;ns-{6E+{8o%s01 z=F_JWpMKcP{yQ;?u~kw|Dz$AtBQ_2{JN{+m?G6_)at@knJfKS!hjjwHY2nkp8>d~C zngr${d`{2|7}P^ zc`8wB1-MmRxMU@2Qx|?m*I(x}f{~KonnpY*0FElLw*};NU6>`y#%)fX4~98A5g$1! zi78D&Hioqe5#MW|wbNpPn~WnGWEhJFoW=ATFe2+?PZX8!CXP)33~-X>4}}SgwMk( zeJBb#`vS;vE1+`$O@IvD2aKP{8N1c3>7^x{YwofSrn$3768P)UdrZoSmTN?gy+X5R z`O^fi5;v&imA%bux6My`TUEC$)}JjiKWjPxPRTOhx>NF|$lb7NUL?iE*- z`o}Y!TLLPn>>K6doDPU;DWvuYbsRkmdOXY=J#BkD=Q%ER?^(RW(QA2+SA?VYnjY_U zj!O)BoOf@=b&2`8Pnk`ykqAL_gtbx-# z-B5pvgJ<0DLn~^>V*hBc3WcP_L$osan{F{ZDkS8sQ$Rk1-~+4oKuA6`-UXwW0I1Gj zRopD=m6{L=3vffdzGX1F0TrOD=^*LdNQ}FqFHgpOZ||8{h5EeFY@X?n6S(yi z8Se8ob{98{UujN=^>WhLyzXpN-;BwZmfZ=bGv}RI=hR+0(^8Z9Gk0N9mcy3ZTjsGB zAJ%!i+;{w^kvqS(_pEeuo_PH1`QPg!WNieB?rzWIohMgR&HNOT=T3*Wwo%NPHWroE zt&-hIt=kXg6x55eSCj>~wBKq~M`D@UXg9RaE0}Fd`Fpmw@}0kZR?*kCy>{!j|D0ZZ zI&06}cSR1mc`v4=89z-1vi5#mUpJUl7q-61S@m+Ss;|E0e$}ptM$_rCt-3`8eYr;G zYAt@XWlk2fgzjWBE4Q9&jQ#~r^&L3WT7J5`Y}@=A&zjxtw`(3OtvwmA#bI0BN%JVj zZ8dw6#H(DY_vHB(fviCM4glg>-JV2yPpeg&)cVa@XcEhsGFI*U2L-=|7>`a`T5rKGg%S3 zTXkF;-kI%geo&`c-{YWjEZeo|{MPEfE$1qQS6j6fw5edt3Nc-3*;%{(=`^g%kXwDu z>e&eVN-4$o|6Y~{*cjxV+DBh_n2hd&?TrT!aZuFjx%y zv9|_7M2Q`hQMk_ja<6h+nQVAHOqN2($lwJxVPf40d}~-}K1A+=kUp@l2qtxT7-Y$C zo8e>c`i?A#Xj$i)dv;eY@mFrJMQ(WYHsu=Z!eqhbPX?{42MwQi=rI9m zwTGRRhZ!Ts`~qZXp&s!{{^)obhychfusf075x&Re{yQLcabZ4H&pQ|Qd5zZ|m2pB! zVS2;RZarZVLpS5am13iya{so^Fa0WQqqjRgv^Q2yfaaApn%^&BbI&R3;i|@(-wDYR?0|vHg{z!z9d2KDXX39i?&^_wwh29RA+Ipn{`o1BQi%t_$eU9m z6`YeE3O&yc(yLpIHQYr4N)(4j+v;?lGe*Er1v)s%j|QD zJP&P8w$8=q7mnnT^|Pe)7mlckXD;Y%`!IghKuiiA;T2ik@#*s)OnWH>ODcUk-Q(x&Gk_NmLRTZkVnFZ^u0 z-i+QhIM$-^{?*r^x#^N?x%7-!#v*T9sf|TJY3IE=OYLrk-VK=l@m@%uV>Rf`4QTJoIlq z29G37o}r@MrgOD)|EYYXlr;^4O*zz&C`gQ@H1Sszeeaxz4K|w4zMO2^9Ade5|HZzw z2OSd?*jAQQ7P)!FhKH{Y#+0sjbLex1s3`IYAVhBLu&*4j4x8jIK#NSn`cE*?#V}rS!)HMS4-v(A8QV4&! z_}vhaW*|U#9NT!$^HC$>>4|q?E~imBuf^`zQ=_CxL?UD~26)l(o!vMGvwg z51a_d3tf1xp1#!3?fLZLT+5fZh=jHM|NRmy%JyUY83?bpytB_py&O7C4ff>H{Uz~^ zFLlSK%gBWyNd)~Fb-ulX(a6oC?l&R@7)rbjah^50i z1d7>3ZCcQeZj+U#nw{EKRFb3My0{gFlyzTjTGo5*SE>05&(2kvKZ~zjOP8a2zbqpp zD)K{umaUvK4-iu-q-dwY4Dnx>RKV^XesvxKVYnO+3RZ_Jvbb6$*~#F;$q{} zjSvgPUb6rIe>WDXFP{_o&09wgO@h^K;aovaOfHI>nb~sh^_fNoWL)bp&WtRdpE-8B zIeh4BK>SDVi6VO3??7J|M%lNfKk@oxcd_<#s!Qsg2Y=eXS&Y1zUGgVcRSv9q<@erX zBjOWnpA}!x8}Ylz%UOo;nrz_2`oMu?D>QpraXq{VZrnvwb0aHWMu;*vcNu6p%$dXHi5k%qIAJm*r8m6 zx-qSqhMgeh%^Js`-i?3@FaO)kDu zz@4~x$e-3#jW)=D`e}urhNSv3b*K;Ab=mNpf7f^Sl_Fr_hn3)i8%s49>9|F$e~lOd zgsBDnKRi$XRf1mds{iBq|qNsKIQ52Bsm9|6k zW3?wz?eN}`h-8h;6`1(V0%nVkapcwc3oMpO=q@5=2^#A-A;x3X2~y)yjAI!{ww;VH zvhabK_v9KW)ZorW@Ds%O2kMUUSmnS?e|39M&MpLQUKsS|$gVZZb(`hvZ1ot(&q!f~ zk;Ld`0BDvBKOtnOf)lzYV|1lrJxGYA!Q>YpZPEgy@bpKyAYTm>m|{ynPLG^0X`!~S zX=&d?^?t%;*K^8vtQX4>y?#2Q_3Szx>zVwI*`>5vK|R( z{6Lw$2v;H0E8{Uog$$MjdaR3GR?iw0lX}xAqe6Cm45zsszugk75$V>Yop%<3|AZ** zWY&*gQJ{O}hHqKqN|uz=01~ai*mf)8tu);-A$wR(ln)J7!)wbIK6k6T_OJvU-FJZ&7}rP_JD|nykO9y0cdEpO6vD z#fpTSIxZM1Vm8Qe94h&;kRHjUO zD2Bj-5OG31E)QKzV>c#a8+go22uy;Q4Ll=N3_4%P@teZN%J9`t3E~)t66(F+qGDyZ z8u(}^mpLS)LNc5*MmLiSmMGW>JdBDV!nMZeEWnyx6_a9Nbhnh0IBh@)p$>_0zkHA* zFdmYDNg`%hJtolT8+7X1TnRc-#I3(9T;foZ>+0C-NMfIF!8ITRA zmlPWgXxxj@w%0H$vUADXQ)`-J z8mh^9jiflu7pH+bDTnnL{2}55ipg&vNV{-z+;bm28D&{aIvm-2Jmp*7EluIPGn3mpL?D1hdK97p2P zXO!d(n|0e`a3m=~yLKjf?3PQSLxG&2k*&z2?@NFTJ^7wv_F?$;Fuq zW-3Vg-Xlsxto#^?e<ij7Y(68LaJ}b&4Fq!nTCvjpObK85G5y>>D_`lz6P8 z{*EW(0vKch5J&527zI!t!zv6zzJ(AwQ*;`5SR0vqnK_7>Vyo)l&Bx*pYfzLYjrl9Soo~M1(pGP+z9q z=QuVA>D_?=u8@;|Ci0lv_~unziTK?=OM$Tnn=RKv1yN(+MQ1iM!>@xlp`Nsp(a(!r zny%X{1%?zMRM|I2{8___SWTF0yr1=9HjuigYNV1E|_ zo5|v;(GB%_{htkbmgW{(I#T#-ZG3tyxKj@Fn0;cmv%O=i$UPxhd`}t8Lm`@D_3B5lCs`~ z-HKEo^dU{{Oq_Jy_Eoa&rCn2eDcU$$ceA`^(S-Sdd)m!l7fVeh5tA`8`aLn}$h__Q zU`(zlx-LdXk^no3utOrvu0RH7e789BuhktqMat+K-*NOME>`N}{(X>e!|)H4c3P^w zT0}N*yoZb53}~q`or1hnB>Iw+!xe%A1+E|Te9JUcZh0LJfX0f~V*t2Wq?;{7k`xVhvW7?yeYjqu z0n``{doX=4^r1`Ekua^{7_9xM-;LWSvD?rF6 zjV%Xg04kf;-#Y<(QusD)o2W2a%sX??+V25wTmHW(ato+Uf$Jx$^CqR7Z`{Ln549y0 z#BLF$PC?9o@dLoudzD22zZ--4Hx9>WH$%jv6vCg|xc(SsxD?aB&sR_SJ5G+-tkCI~ zcm0!Vk5MJ<5F;PRbD8H*a4`HXpl>A?`yCwZEYVvn#;M5`-yN`0F{@oP(H@DIu2x5~ zx9)~h&JT*$1G)qCq%;>qQtNYU~HV=(7dUW`=?q$ytRY7(D@3&p>G9Oge2B~#Kqzj zUeHo7@AUaGArPhO-QhO2_zP*bOm+ND<~4pgBm^o)ptUVe}h- z<`aTW08o@MV)jq4S;o$c!G!{hQIJ)t=&~YYqzbRElzxnb&?OMts{Yg}#oE*z*kad< zDj~w{JFVCPzgUc?iMaK0T%n= zzX&50a^RK3N%3kb#3=1$tNMj{xTz&hA9OAd+3mEKBDT6z!q~`G^Il_H$Jj$+vfoBy zRxH}8o--t5kH+W{SK5Snxl=rM$vL+j;Ky$Uv@**+0`a<#>3?o@$R~ryU_CXw z&0RcO-iTgYPiO%-6Cl~9bAEQc{$}AL?bl!@K0c>6UCU&7`?73 z_7F%jmOV)U*{$_#++X##z-p21y?WWD$H<#Y*pm9qdVZjQr{5#Kaz=gYAygX`{nEl^_&Y}tlq7V^FmJKDb8T+JAHWG^%zb! zcd?dWQgtOp^Em`?g!(=g9$j%lWk}7>i&?|5*7qaUB-A7{5 zW}!Z2YQ53UXYVdPyZSo6SwuJjJ@1g>3oVFQ#6|uJT&E1<5yftYNH`uIK{%TvB>+>j zZV^s<39?#>SB{tJ%P>DK5;CPlZiZPUTrx#Y)X-h@tc*;VBF04>7+8n-@f3fnc5}Z6 zCY4KU7U9aKwC2q777wAGe8$(vaL?ZDtvQ2#1JOqSnY(0fzUamNrCF#uL`n?pUw!9C zAB0Obp@zG4O*a82q<)y$z~P!6fXQ>B4>}vMJqjA3o{+6D%wHY-Gl?(<(N)hxxP*Yb ze-CiqU`oR$BmXx_Eg1ELSea3|Iy9ThlW>PtC{cb1}SWcUOw z-t8H#6ZkrC?^)&UUx#-4bS(#^&*@I^vONdX=_m{M;?Z!{0+{>eosa=T>8}Sv7lOpBX9vgve(rE6Pn9RR~ih`RsZG( zj&+F#^U0oS5580^A!DhF{;V5p@X(^uNV%Mkxfd(%hQ~9L$h)#of`8paG zcAh`gwDK6$$?AA}5SVv}{A6IWvzb~)c5#IrKJ-<3E>(T?8{^PAvf$}Qj;G(; ztaIJ*kF=m?dc1LI?V`O4&dl8JTy;L1?ArU`VNdeofxWJ0KRvw=Q5*RAzpX1YdFL?^ zK!=)tF!Ut$XHsrr${vT<32q%r5n$6c9R(<>#b-x zgkM(fEoblS>(bfCu9jY9ucP=S*5~UNCpHw@j3yo{UG%8QZ{hZcbqL(I`87Vh56vD& zV83mFFwL#aE2j7){fm>}Y-kdiswI7PNn3~&n zZZ&weEXV6V>>Z3<;_0PD!-vK^kRh!hg$N5oTVq!Gtv2J9>0ajMv>zZdDqWS*mBWuu zq(vdUyH4XbO-fSDdPtaGdI;pM+IZtHFo+uq80S?W&N_UhbJ zHB4868HLs#rZX~^CI*StBemCz(GceGSk-UL!@RVKl}4RSuzqZz=(B$nt1Q=LrwhC` z4#yn>o>x`IEy!dw&TQH>-HV!-l{>@@h9`q3f8$sTrRV%wW*OtA*Uq*0p9d#?QdeFz zqG>)`R8KVvp>}Old?wsD<(#nd?}?dU>b{h|k#ZGP1`yO9MJrKfLiqeGg_0eXb6)eB zX&0Cka-0LCmb%G~6T3wI+apWy#v+vCJ%v46s{SXWNr;mWF?I|=UkqHtHY$h(V;)*E z5QlD6AQ*`fE^Z2i9~lC@`ABlUlIk&X6~!nNGbfcf#Leh*B5zQSA}=s@0X9<8BsvL! z7_USjiYJxPMq~x+RWb=FC2i2l3R`5rkWhnelwx9`e4`6kP_~#s3wtdLbM-u70n9 zn>06I#KSQz$WRR!B`O2a^Z|hUG&P>`QHG-DtNTA$;2{im@%)~2oY`0xdL|v=@&YVG zmbL7@IfXE-Rw9jLv799?&)o0X?J>@hOC7RglyV4@Dm7GtOC{Tj733tVV9obqo`^-i zbCPym)(%e`$mlQ3OC;+U$-O96iY{AEZ@Ujc$g z;eky3Ef>vpwC{LMd_Fh2b)fqfxY*hAoKfLgX4xFde)4m%yORj_l;-_^!YDRMin#>m zQ~t#O!cHS{-cGN1*)Z_8*aJZtmw{ZhMzCVUuw4z)RO|MaR9rsmOdEC_5ajYkV)Uw^ zHy|)h@q&y&j`t)jFotN$r=}Y#m4p%jYT;yvQ4=4lL6+iET;h=ENwG6mzVJ=x3C>9Y zV0-G+)PuiLwtP%j4}94lY0i!3$e+NSChE-l^lgU<|9vOZ9F>U#V7c4+7qW7^epD-h%B&ZF9)1^h_C` zeJ|AnffTnc`!3LI9n%>ee&F zA%7{`v-6d4%L5#zEYG-AhM7A)Z4opDGdcmgM?o^$1+ci{#*NhO%0k4*Sg9)qNFA^C z!erC;GSh|xRx&3dN;Qm#;~pEMjtsikC+BYXFi1?~d+JUK&>uMv&E)U3NgM9M@4@t# z;>4?##sRo3fQQk^!mk)o8ZO;MSb&_!H`#6#mVPgC{Wva7*WH?sr%3FWgwW_jHH%#d zf=0MuckjNmE2eavm;xwRpSp=eKN=()W2wM99rv0BWDJczCx#u8KS}Kj)DAFDu0VC%E zDT_ET_WI-%kRmcia3EIH zb(v~|tchIRWwilN=E* zL&2NZz80aaGic*?QBTJxFAgr(IF{-RlWvJnxWE*ZU@JjNxT{2N-HLlQh9Zn1r~>3Y zQFL<-qVgrVN(%4-H@4I48G?k`v;|qm0BIK`Lj*W?5ueIXWAV!|T`KWi14H}!9BEb2UMAe*a~Cv66kU+DIHetIxs9L7@B@?n=h_ZgkPfwLVDx6M8q-?iUA?C zPr28fI=u4T;pg}xQ|9w;^>J8;s)-N)FYtOG1fS&OP$hu6gu%)*iVp(lz`YiyKwKcO zX@d5yjYfrz;-mluQ0?_f0PHIOjKE+f2w1d9@8ntl^ZUquIkeC30E|eVI7&B7Tf>cA zh!p{RjK;@907OST@uXieth}%lFdhSNT^6h^@G_S~k*&qS^9;w2YCbwT)YtBEEsntgGf0V+aw8u{y}-XMMV- zhpREPLLpr7v56K_vs~n9Z@Jwpmf&aIpclKqQTxS41`n~ihIXzE!4l{_JO#28q!EFK z)|aN3nN};0CiYmV7qjK4UCXlKwnOc0wZ;5b4}mx44p*mr8)i6lq+#~+U#Z=7nA*65Ze*^zl|>UR9geqFm7i*^V0F0tFKB-UFN zn|7MpWrr{n?eOtCHvQ=M-Ak4?JsPrG2YkBSm(5k=dp-bDJ~Dd?bBtm z6zBp7x98rXc6v^T09%JSx$cgJ5e;b$u*7tvL!cpWz1#YI_tM|TYlRMRU8GB0$aQwu zF#*wf%nS-{u}}a7ft2tOqZM~GOl8X+2`I!io45P@aznJ(F#aw?o=Njh_i%Y}O2ycu z>FAh)e=b6?YtKm2_0uIr@yYsDlH)i1dKnP1TaCh#+12t83=!JIg?vkdzVy9&*ZZ@( z|I0yGHU)^6DOv*YU5J{~BrC3ke}#pbaJoti6pWF>ee@-C&1gDeejw7K_iPzUmmxdZ zyq(@=Z?}Mkgaau(!@f;yZ7X%dPGt8b&Tc>ZSV%Hzb&-*XM<4#Z!1r^Ob%sXcuYN{4 z_~Z_a(WSkbt}A1At5tag0?H-a-YtesFClWP0(ZS@X9c0}IdNdBHqov_cY707XhOt{ zp+ecD;h$Qrf#?tsa?AzMcp0@qhJd-0#cW;AGW0Sj;_EmKDOL544g0bL$Rz@lwV?mM z{TfTk&;ioa=paB%pNwv_E zduy%fz$ApQlEfzrA%t~6NETso_^bm$$T`G*`~Lp#(W7>_?(4eV@AvbC$~X$nVWS;o z=p;qAlOZ&JGNmlN2LpvKn7lTdeZg}-@UD`iJIKx??zZGYltFZJsrAUa>nlh%VrD3q zl?zH#Br4@=<^8I=V#q5FWlLr62eM7i`nsoR2qSS8v;0ShsmyMHyoKH|7_PA zpq_tnPD_YTCZIGeH!#+Jy5F@naKrw64Ti@bK;k6`Pb&(R*OgMvT6yjbjr0I!gfRWN>2 zTKBtbb$PY=Q$fLE#_E3t*wMlTcfMj8HKZX8MgfqWWx#GhXQ2c;$_M5s*En;5*$UDF z#r05xe4dS>bS_;Wxc`3U18GWZ-1FXr_2vUX>-HW2@H|wcnHN@ezxA@AE0Agl2R~;J zQ73S#UIU48%AFr5)uf&Sca;hthsv)$*Eyia!4@_pLI(ILP%m>{%z;twJk}ICU`JW< zeY|M9CDE-(hpl{7jY=s&j_Oxk1t;Y*(x9<_v@c%HMG@E;M+7UAmKu7nH7~Dpi!@|4 zgS2Z>@9+=x*6LyNlfxZ`a}$-=L>Xqe3=NU)iOVqY4E=67>O4SpltGs@B%j|v5SP-z z1)>>wIO@XvnhNYB_BlZAr;ZIMDSF?IRwq(SVotg!P<~wgj0eE{yM2EhF1;)O9IHF& zpMiKTv6njb93ff?01__e-W5tA7lW2sO#Lh@ids!{`v4C2QgT#CTZmYX-!_Il$AFG)IXQJi;!3uv>#}It&>kQS=DM^fjx< zOJ`CTx1x-_mU(>WJ`q%cr&Qm3KO`sKeEe*&!X#es3M0pum9Hif{+hUGx{5I`Urk1kl3sN6&nvN;S~ znm}}KW5E#yrNE^5+)e8ESFFz3_s=zKRFOjfqxl-Lycj4^P?jJD%LT8n?DsO|1;OuE zd8#Mb_pUD~Gib;&a?+jg+QC`NDMQ6T$67S18Z*JgZ~LpaWAiVCCT0GxsfP@6T&4R6 zRGWj-G$x3bp$#aM=Yq@;gv7R)R^}N^2js<;5??YFou_mKAT0LW)LZgJ$Oy=Se! zs_3N|=uTN?ceXK0J`%2{Thdso`~yQu1K&?k+43;mmlp4R4wa4|jqCW-Y<0-{FvMX% z_J^-ZlU6`LZ>wD`d_ArsGB%s{X|#O1MfvUL#~K3BTbm;jxr&DKWr%ri^ZR0%YCvP(}{c(}JY_-7O3= zv|+`}e(AD)yQ!fxpGsLvZnI(y`i3|*Y)@Pr8zHZ&j}3NMn?9fc?OKjC*DP*Z9JU>2 z42Tb`Xp0ZqZ*N_U$kxgtf_JP?nnPFmqUAh1zo#>OXMx~Xm~(y`h%utBRx81ILr*X@ zyg`p~z`B`Wu+!p@a^YF>)jM(|P#UB>L))7D+KjVV_?k)+&iWGV^&p`z#`|f}ml)sC z+QJ3?@7lifR~b&Gna#A|GLJ$IAi_CS+?bN`8Ck;Xx{g{cxG8NA&$tXbpS1oHUmdEA?$&l?!wlIU|OFp$trB%&( zRJ?NAobOXBWkIGteT>|=jFd7umm%IVxDm!#Ey!p&VMXW5!7Ae{C1|xghgT}G=EESS zAZa0pOa2>u4IMYd#A1-;e6gM(<5xS?LXrC4{-CUjLX)ELeNb62mw~m)UdMR7W!;Nm z-2Njks+3sXI*qW3GS#%-#z8$irWHr4<+&|+Sbs4(aB>(&m^7^xH9EhF2C19FnZhmh zHX922=lqy1R0Wy+Q*=M-P!8IVwj_&rgoRK1e5E((c*B;InVc`XKV|X1sdf)3*BS-4 zySNW8eT0ZQlIL5W8Z_}t{rP0^sRP;1W-Yz_?O`HseZ8Hb8d+b4k0x&Fbd)i~Z@=hS zw|(|W{;z0ibkCN}zusNYZl3;Pw&%|C*=w@ScJrExb#=ql*t$8|Bkm=4S04BfXmq6` z)z)J7$bW-Q;{mvBuaJX|^1lI79IAvXwzE$qMEO8p8}5lOK7mOYGU(z7u4GnIDmkY( zi2jPbz%e-WS5fi4(d(1t1(6Nfw+ZTQrbF!3sPr_W19khXKXc0#+LO`8+M8K!!4=^h zX=YcZLfDf0qOgP|Q|FU!^qK5ny2Kwg*ACn`7L#9HJ<>>fU$=MGRga2|9V>1AOohSN zI3L!ao%s*n>j6&oJId|T>1W5ot%-3}tJB9!XKaXw&WPK&r`6u-OL#) zXH4VQAmpZ$W*@mofs5BvPX(#d@Z4SUh!^Q|iGm2I2c zX>f!e;+l1{Jfp3lx`Q>BITS0CBs9%_))IPcLzHM+!shmb%&29*;(mKPkUKnQMK8J? zx&Kwd(K#khyk3XL@BI8#ywx}>wz?$2_sxCjz4~LWck7~>B$V3NBUyY+c5cDL(eWIMcTq?A{f_qSQ7c?GE^ZUmpe+R;MKB2&Bbs9wWz|W0 z_Nl!M+V&mYzsBX*_gS}2^niq9T1L*srP`(n`F^`zrNzlqVmvD~)g|OE_HN74)XiUG zQcRq4n%^!VPRohyOM3Nn1NE*n4(da9&iX6w;tZrpG$XlU6)YFeb{VmVg~N&QY>@#1 zJBCO1%00^i4YC0bM}R|o)P6N|mj~LO>b}WY@?hiN!JS2zY70M$TcMWg;D zADSoWh>{al56_}Pq#}J+femJxf)JAc`KKepm}|e&Xm(yG11W;Cr-B1cV-UoJ{A38# zSOh>uG6c<#38`W;w2@S~!;UR9&eAoD*LmQ@W{{C888R0D%z+E5T+J>Xi@)v|IX^yQ zQ`eWaey^jYcOw(vZCV)R%0fF#$qC-sFxr?0SxR(~Y2&&kIcZWA`JeGkA2yIy!htsa z1{nRZVhkScDhU#G8OkphRVJe-4l)P_q>>}mfir)pN^wm*Ft#N~pMFJRhA_~Me1t@Q zj!XM18_WkcDyci?Lp0LmoL$%V>Z-Yj&V{rXc^p4CJQ(PN@s~2 zuEO5IM^<$kX!%y*`7&FSekH>;X9$yBIAR0`#07MZP;x(9O$o2jr7tv~fNCAH0yn_zMx*8N;5v{yiHsKw{7)g8-hAT%rUPSJJoMzEXAb{oe(v zwVyV)C`3kI?GBsp8VGSa&l0h*1S@6a>&n#u4mu_m+v0;Kgez(GxqwLu<;6ruC;sz( zgb_SU{<|Daq`+lss)V1p+q>oyH&~v}ub5 z#d_NS0dPF50mMyReMf##N=W!?p_{kA_E@W3BNsKN0@5!+f}r-YY>v;;6PMzZ9(SDF z302=V#I}t@lpY!UGu1V3IA5? zAe%7Jyy{L1t_hAVK^&~vG%XJ1!z(3On{ zQ-KZ(7ctq8-K6kxNyvu!uxU<%_q0zGN=OkHqZI)gM4l%auVVPf z?@GYe7{c%nGsJgO4@e3JvF(yYGT{s7qX=}9vazLLI(+xr8;dRh?o>>)3ccI7%#Y<# zQWdec>d?(KK{H^H2VS&A+YU$~gcKfP&4p$NgcV;97Om8d7JB|NKo7sIrvl6XQ4adH z^%O$l0p?thetR#52h2$JnxPR^iaV?Uh@v>-nyt+BpXWVl7h7;g_XN(E6_I=#v}up( z7!>Y(7IoF$%5P1OwJ$Xx{vAQ|1hqeoyMOv!{&a);sPTN05%<>{+)4cYvDW?{{zrV4 zDtw2k9%*gwy((cp8*utsZ}(29cqpffHrc>Tjc~~SswfsTjM4wu z>U>Wb*hjU!&j`7AW+7=!HKBT7fEz2Db(3^A*6R7uuf>3?)X(6$G&~qN6f3ki0^9o^ zysLJrGp=3`Onz|x)Ez2F=HGu%-0FBD&h)On*_E!rXR&N@y!f*PDd7C;twIL@G$a)j|3;1uj;4`&66w&Z!O>MQKXO>igfd z)1eE*@g4^fBA2xs;ZgF&vH7&}Tm%z%Cm8KSyS2m5B)s7(t0{h!d1oq^qXRX=D<+u( z|1(>uXmKw+ZtlZljt_P_+V4d@94KiO86--!y2QP2ANmO<7Ne?IGz?p`R*l9?J)C`; z9_yDlb(<~eeOSRfPs0-{_U=o0S#$04{elw-MKO!k5rwf4Q2tbz4GL< zO0*|KnC>C+@kM7TFy1PZvvQH0@(Hs=93+=-Uj_QXPjx@z0UyE%mi~vCCvil%`a&UG zv>kk~=9bWthw=y)jpA*He4#sneq1f=*7`l3sy+Je+!bG~9M-L(oc!|`t48O;r3cJK zxoS-MRCzwD+=Y$UD9X0TvH42LtoFTr2+mt)|I(!ESg3}45nqno!3BQ|0H!R=2PHOL zg@x7Lrb>exm81X>kE*N#skp^;SOK@3*ItR`i880k=fKF0^v7FRr3JL|Ox0kJ0BPJ= zmL($zSU3*%iJwY>`&-VR#Ky9PtKVbOrC4excEe)*ys0uCtvoLo=L+lIL;dXD1n()F zJYpMPi4`a%E{aNQcx9F@VsUEcqs|8fDoJKCE}G^hk6bbL#pwK+D;EuL0$y@5NM`waAUefb=#nhy zRG81>;lflxE2Vht6oj4!a9H?xERiGabZb78FU4_uk>&!tGgr(UH&0-dJ0SIOQ{|Dz zM42$wvUo3Z63T`#w!R`8U@W&z;xh$?sj2f9>t~M->JI61`637ruS3K(br7E|_4!p+ zFeSE8i8Aq6EJ=m7~wo+&^rUE{W$iV zj>6Tg4v8RU3e1Nwml?6Q4`LJX1Pnu`ey8f{5SLiUTrSQ7@Vr+Et}Y(cA&@38Hl5*a zV^uzv4cHZHGL=~W54y+XMHK(7SFSKlyGm_)8Cll2kIpyC(fv&?c$i{L&J<{<)3kx| zd6{6*AT~Prq9_8{zbna@E94iKjY{3}i_0=+3~ZSKpS?iPf1zW&^*pYWIgDDXgl;BP z(4-Tg!uL*swz#4w2WgJ zsP%QFC^Zm$9z&&JS4)NO=RO#_sz>ArdCAz{x1s!TqTM)lnE>*bgxsm64gmPx5xrIc zU51;Sb|8BE@uU)fVNmAT0uleypb^a3cAd{tb}eX7p2@wlVX$MgWsmG zv9P`cmY6uc9Id6Ij{#W2KKHFFKIN*#YbKbY44jQt zD;x{ob+lKMn=Hu{K#VmB^KWHRRg1b#im_@T4=A6bh+db3EXL;+>eab*TM&MV^e07r)Nj@p03= zAN2UJZ=R>EO%LIcxrkHBe@tF^oP6z6BQ-H}L3b!I=(d zlnPwNEl-t7GP&h}N^>hkneorERZ<)b1E%ng4dE**a*Xx=VBf5tNYWPI{rKgXRBZMX z?&$e_pAp?O@9GlmP6MU5K#Jw7#b|G+7%1yW1qF(-(PVvuzv#Gds{!-xY?>(gxq|=J zI6_Sw*>ipi`Qe*bc3@cxzqe;Ykm-AFDK6BM@;h-sBFd0S>e{qn(&p|yuT?jyG7D$k zJ2-C(M0P4-4K#*sw~aYo#}2vC}&8S zKWB*vME|Mui#+Hxp6K-?`u~CQEcq=L&vl|x7L*sJR5@>8upGILc167 zvjvKhn`H*47fXkO!mEfx@2}Ap6~gP5?iQi^y8N5Ovd7E>`zdgImxFud>}frRsy+wq z65BH-LHv95eh6{Z@M6@wKH+WWvS|e;=3+Hao9n;Bq(N*Hm)uZhmR8pwu`EzGl-r1C zX=Qf4ypSavU&3S1*SZ6D;INox& zX36nmM;rGYKmP9-i-yJgW4juOPA_ZPJ7lZ!aBt-Ss{>2-HVM0D-*wIgQV zjeJ+-R44Cjbv3LUTYhiEX>{AghhuB-y|#Tk^u+gH`bP#EFXwSDo!h7A(wp^6(XAguKiy-rBBXIESw22^Dl8{u zuyUS3--DaM)m6E-#{Uj_#QuIIetL+>N4Cyz=2Ht!I6mzgyk-35+1Y#ZQC4lLAS3dp ze={#yCUCr6a|T0$_NvzO$L9>b>-X25bxu4whbcou@v~zRIH_jK&Ocdw_`vz0HD|5b zuFtfN?tDDw_WQ4x<$4cci0CEf+)tbf`K;>p7*$+i^SZP(f=-M@-}Cb? z_pCg4@zwsq7Z=s5neXL9?>=}Z{_xGo^<29ERS$DE^~D2D9uK<3JQ4GL5Szvuk=h3J z{j4RBlbOAw(p?rgdfqMEp9}SSWZe{xu@4u&Jzja}%J-**+lQahv`r9{9c6X)Pk}&YlgP2Q6DtC6f7D^1os6mH zS`3^E100Wc|s99ZK5H+Wt7rZmO?Y7oq9px2tHIHq_aCQ z?8BfDpL-V9CMTvzL3>4h=UYC5kf!MJ$_zKcp$qF$EACRa!3#X5HQvyyF6#LylwC(C zfnEWW z)qS&e1vD5Kt@~81_?w0wG(JQhG`QI^BY4IL?WUKmm%*69qx^?IjA~|V^E58NoxyAW zWp6ehKh^D_8)?~oMLSGan6R^wDtE{GnUlSXUjh4dS@RvtNO$7`)a9u%cO!tfdXiBS zgTFz&30B)tgWI~UjI0+i_1YSRAs>uR5V@0xJ%Tbcoa)qPO@<#z^SM0q+--g0Pw#tt z!6ICHssFfw1mlB@&I>|GR9;yDsg#t7g!*J3zEzxTtGB-_)W`w`xh*KecwW$Kact@5 z79~*D`^q~;h6J{CTZV>{EQAp&ID8J}njo;w@Y$kuf&c2Z(HMq8hDn}E%+qy(dT+hC z&2K!%=sg#0%8jM0PT``wlX{F_smRL|%1blMKcg(DB6M^ry_12m(AG04cG(&LSckRf zHLI?&C7SGL|#SbrrL>_*6Oh=JxX|HI=WuoX>=S8y@u(M?s*beDnca3`|5uC|Xa#~H zLTM|skw&JzO28?cV|WRy&_l;sX$xVKM@$@gnqhHyDhw=ARNZ;?*;3IWBqs4j?VDEP zIdwle%6TYULZH36xE|Fu3?A+dHx0l8!pGC_ zi?0;X6(cq}Puc~ji!$*UY_U!D^cXqW!MliqU)p-ua4_2I?wZ^$`$q$U?e}$Ap3#)K zvpZ*x94IoaXKY_Ft~6EAIK-miDyx=T_)%^MSjVMA)8rTnb+Atz5Ai9ovzQ(|L|@ zM>$Zw<)@7&xA_I>$SI)8e^=31=!1ImW$gBwPVG+j|Z$-SN6WxsE;QMa@4?U_iaK?;K3U20oQe(#zBNxQoJlscwvMoaMOBN#n8WRGvKWkC*`YW=4n zi?_P|XEkKQwRAwIS|vd?;ebWT0dy1ANg5QonDLV^!Z1u@S`T5vVcU7i7}sr0cb_zR z!Nk55L^0qJP=COj<5wF9ChTX~-@xk9D7=KAjC0xm!Hz8k`3WKdG$#Rcx*Hxi30kU^ z^1HiGQ>jbZlz4mPuHxi5vQ7}$iLDLvp>lRjBR(AvhJjeO1(|xmDDgf$f1z)(i1wsw z^vDB$6Try<2K%<6@C&?Z4zKZjK}|v4WR4ge?>10do3^1Cz1F79b}lJZ_TrU#bGyBYy4jNeT(i>34>2n4cBtA3wFLSV9nvzh#zG6y!#>pF zWe9$3+f<)$#SB=lL+r*ffT)21hDzfTC>uIVn(p$VasXPV7u>zKZ2zojU`GpLM89|0 zYb7c4u>Ge-;=C6pw;EZtl(M)m$O4S&v9Y^_bKpP?+t5X73kJZBRi!NUGkQD928|HZ zBA=AyWOVl~3}6)9?MVY666pRO*wF(U^#FNtfbjL@ibfdKTF0PnWwf9egVHL4z|O=j ze>r$?T(k$HG>#5p_ZjKgb4bQ8Amap_>0R;bNTKE)WgMY20ZeHr{c8mtaUfO!#Na!m zXLm?=m?G`TL^p=LeUc$U>4jr{p1hKP4vsy~M?S-fSrN*z@Asg~Uf>Jt- z*^V=vY6Jar@_!vtD-7~!33P1hc2gia*LD^b#bN~cal5IArMK_6>AG&Crq>I^045#5 zvXbX2gbhu7s2Xx7HP)OL`KC55bJyRh(gQRj?gJhja`4(7A@BN=+C_zj z=F2|)RtmXhunWOq4thz#0qpo%-46`2aceyjpvsJlGz z-Apx-(ouOcwaZxJJO>)f;kTa?SD&c23$ zP%ovKQe*@>N9O=F*2i7@bk_iHE{N8&SNz*OSXRBM3SuE5uK`jI0F{s$L1>T^TelTG0Tb~q54bQi^{=Wro=gXreIW96@K^g`_mQEQMcw)=m@LmeNMCF=@J@L!BGYv5j~ETu@ou3M zfqa#ebmfk!cPhi20gLzL**!ReszNS&S6oG?wFVoamiBE;xp;4I#O1+s>9daQf&nxk zTbVi|=LCDlsoD_r_f@^@_vkQ#RAvtz#VJn-inp(R%hq5({nV$ z4;n+aGTB{G!oA@oWre|+2gerRzoEyv5=OU0U7*7=7^TZ^nbb^>Ml(+IvvP+kK8)Ao zzH!6sdB!ESB5%&*zPt3{ov8QGGiqPeM5s5OaEvtZ_QQwIAIdgWkRv{5a~s|I3Zg#h zN)fiFN;{;T)Kf7u(wzY5m*df|BR`s7kNV(nO7|a?lJdTneEf0A?E<~$;{x}uxp$X8 zJNfM`v2-x9LL zXZEfSAHTnqqTZp=Q3BNEkI*6vMqhzhGl{hvL2nfNwVuRP3Z@I#iB$q%kAV2Epg)z3 zG5Scjpg^BuClp1J^FESB1r$pQ(iZ{g_vBPoCB+>hZu+QgR8Z~m4Z970|78O{`TD0$ z8S0-NY5ho!`ed>)pYjjU_=mgM4}s}^0UGB)+nH}(NHN;-$!MiOi(h%ld}bNxaz6de z=^@!Evs0(7W__faT}QvmxB2a%Vkj&|^GVuIv9N$?S71B8s%jGnA9f1-PrwY^m7k9>`b6#cu0apNVGq{)&*#$5e6A^QJY3+krPuLtuih8;w$}fx3-QjDpR7^0Zm{IIG59X{hQlXTbz^*^IOK@3&QeQH~+2Iw^h6*7}Sq#Cv->)5!V>Kv#%+VJ9THBXSM;q z$6Zi&wo%vqrrcp#p7yR>ku?q2%OM7SNfrroO73E2cg^hOe90~fD?I0!r^KefO!7Uf zG#%wtj&F*rRlJ< z{weL>v-1z-v37bg?as$-S+P_N@97sh^meYe2^;qAqjU&as(UVLzwy_9orFOr7omj; za%};zO#sG4Xs?3YHwl*qAa=eYy(u!f4z!&_wCEJ2NjPN7?J^92aT-ZBx+|-@Q;((8 z4;Ss;4WEiWVo&d!pAH!Jp0^M0#Hi4i9>BJPW7vD%LD#^&@l)rs)2zdV_H)?G8-x4& zLHyK>vqL+#e7i+$D@V)LZQ1i3RDvEV$b*G)V+Bzduo)HQ*6Zz|;h0B=JiLTxo>Din z;x++beU)@lyN3p>J+r`oRP2OCc}xaEUP2E>7la@?W&rloAVU_yprPE#x)6c z_1&glyklRv#r`w)Up@tvPBL&lg$k#DM0?5ty`A<^sUsV54IckAQbyf z;uzqj>Y@k$y%b*qV?b+63u3qcXcy3f58)W=i2|hwwcA<;ipvmexGs^NgF;|yTB&)m zuPXy42XxLylx2Ca0ku?TBv3SvTN{80NAxwt3>8eGfd*_q-`$H#-GG|;4X4*Q_q5VD z#pehYCKm4u79ghdz!}MqY4Dd_qyDq@0}y|MHA9!w3}bx}^SWYdIM7-n^5A#QA4KZj z0T2W7;Da225>H1=pZPVJbT+-_SWk1rgA4Ec76R!n6*5Yf013|f#$3R3qGK^Fnx4#)V>nIK9xrbZ2N3J=CLb>OSmu4g~V^gZcX_NF~mW4QoDJ!1^bP_uG1Mc)knh)+*BDn(0r&f% zilP?>*lI+Zv$}dmfuX}!P6Yr1Q4n_O?ow1ozyr?!v%VHHKhkf9(KFkLa3FI$xRe4H4p;hc!*xgRQnw8_Lgs`CO@r5A6Vyt=%*Bur-LS<0G!w5 zxDKL7Jkvnj0_Z?YZPVf9|m`Z~B*vRrYD93BX~TgBQoY`BzKd z^2a2-b?yP2E3Ml`UT>ieTqA~2)12xDU0q;sIoYLRN*xq!w1eqvI_BYU48Psw-`fm$ z$J0HUKqgeNBiJIX#{-74;px8ZoqiN2Pb8DWQU;EoM zH|1jCn@8t1n&mCOvhnBlZyO(=A>SKL`@(!en-Yo+Fg&jpDp&{4Giz|PL#QoBc0 z249{n))N^^EjBtdzXT=oZ$RcWI!joAiQt=eubODkBk6By9aM5=-rqN8tG|hx@y}2D zZs;*)u!T4qqp|>Y_a~Qx zopWitL1GxF=3(qM^W2UdDuIYjw47hBS@a!C-7eM-{x;~K#;JtTnNn41>3bxl=9a^O zO@_BwN9t>CJ3Y7$L)45*5or8uVE7Qh3$GQT40tsf5gBa@b`jt@28s&zo{2W_(xInR zPijNy7PuI2FtFChuaV=X;`&M6)P_4$`}VV_Izd)HD`MBBf%dT?`nH?HV!QsEG{18- z3Fqh!5m7?E%dUq>%l!-(1+LC1nVTM!a?=}>*F+U`fGl485 z`)gnZHG)-$^1eI~C#S$HX56o;Bj0Bn44r-aSe^Xs>G&wlY_nrg7g82IU-I&~j#CY% z30pUOd%owt&42!wX^;mN;Jx+h<904FkjI@}GVjgPV^M1e9hn0a*O#@S)@-m{_xSR< zTBjG=-<`PdUpIQ5`ODhG<$GW5UiMv^TVeC})`e$36WSM-8Th|C7S-G}_s0>km*8!G zhp6%G>jQzy7N8P**o$8juQ<5x?eP;=E#9@R%0ZTohN=Le!XO-2*tB+&Q>g2rbRxR@ zYfbF&pEWNMp6`if3(JgO9X!W6@#nAQq!MFOKY5;i_3IjoGrfU&&ij%ZzypUHi*D>a zhz+5NBB(!v%%V>t!UJy_>F@J*HEM86MNdL%X|-efZ*;9Xbm03?&b0$CsrFG2UC`rr z({fo2{`rS31qc29Gbp$^$Kj<<;_}zjXf*?yQ?z&UF&Dn|tuZrdx4B z-`8{8axZ?`yMppJ@#%W)>&r2W&cCPDE49J3eEBUQlxt-3wKl^)vh%%T)109ulIfXm zOj$g3zwrlFGDmMYwbZ;v@2VkBoIfriDHR%4Oxr0ml;vM8)$BJ`9EVzhUeJY9=d`g;Fm3HY>61@Sq8%Cm=RR6kh z5@UEj1yj3E7Z?^EHqWpIF|t}%^q8|&cVj~UgsvSs%COl8b`u}cN5>Mqrp7=&jqWTp zEXLL;!38WdaCDCr1+!C8#%dv5SG#uz&)Vow7v%U#gUJH|K_|SN=6#yrAs5Ue^SZ3p zY0%NxBY0zOGx-BUYDZldf6QLYYHuvJX`ck=s7qOlPBD(#_P0H3zxDe z9^zTP9LQca==PSTYzlxetN5?XYMPEkKIwJbvZq*4HccsNk zBt*|k-e;~1w0h8T!}C&S`NDp{BsS))gBJ{$&=KmWBE+Yyfs)?FKvTj4XAkC=qqHpy zKf87%CF_@d7Gu;hjSpZX)T;bvgO*2wIj9acSrELEt_lwvgL#A#achkXl{*Ob3O&Bs zV1=2Y(|OQk3>3iCbNpxTPdK)X%}4dkGnNjB`sM{YV~ zDaET?PJz}ixMVy}?h_zCNr z%%Q$hi=kuz04rBg7v;iZSyQN}>@*@71`8_qrMpkUAW<#$?LiP78cK7~STKh;5-7UC zvaz=fN*}If>OM;g*Z|Zcd!-x90e2^Unm_M-l~;Nyv7C>yr(GGfw0Wv-jP(93ewMv@ zzU7cC8#etqxqY?gk(!8ctk>pGdQ1D5m`mC<|3CJRk!v!Xu4A37WpSQgjY0kK7fd2U zTChoY<3XixR)?iXuLm%{18~S!7!;VM#1F_ry%a+7y{ld56(+%R+9n_Tz8j392$abq zB|;m1w<(Ss_>0s>OrJ*6wpm;za7#hN7T#h1*=et@`0QwD|F_M;A|?Gw@~T1<71$TpcS={0`7J zK?q4S)eDvR8-wK%C;Fs5M%G}JOBRyr8!C;_-R3UELwzkb^GrA0?dnxgFl}tgJVuA* zd0&yqah+gC<7~iD#ajP>#qRsOTw~^XcA_@3$xB(hu|oDmuuk@QmyL$}f!D2L6u0>d zc7Tnnasv{hGIv4)TCxLuyoJjS%tf~O0jFxNf2y!gX!x9JV>|d}_t3v#?64=-Hiuq* z@z2LCHq*aEt4udDo;D9AS-m>Hzu)rku@0_v$wq! z!NLatIp&*%m<9Zi+nT`_A8o9aAWx?XY5)eaxeH6aooXaV`&tBAW-vhXDx92SCetaG zJitXOXlu=VyKd}lYu?+gd&E;zy|a@MSNn+)`Kydd-9K(=K z(7jY&CXayobqLkgwS*@oZkQk#M8r+Ah%sS$XJaid z?6CZirfWw$CrDdA2AT>g9k|H*p$6j&DQf*dt0Hx)Hya~kT5s-L+pG=4Byip=zir+& zOr^@P89JoZNyoWTdo!>)5APM#`a1xoDFI5VwG-u}N&(i(Ek~Hj0?B=rPG?TF`pdE0 z++azIhN=Mb+n{+HhyIGOm#)!k8@ALf-nzLBK@{pkRjVk~BB4Lm9=`Cm!E#+E)*8lT zbT$_oTE755r_X#Aaham}SK}v({8r0ThR$c>obQSBuCO<4x&h>9$n^lK_C$FGK(1Hz zEVtdXjz{^+F=&RN<~(V=hHP4y9?j5ug^+K{NxHJZK6!5jObO=bOAt~O429l9Uxf|0 z9O@Y*Hm(<6{C?ZMFjN8ZKZoEs)(@+P?$ILp^?-hdkT4;5Hi;b4-82s#rv?l4B^vNU z+1>D2(zXU_h3hPd#{HUR(wc$kfej*4sS4yyu(NFFNJ^7H=9cw4yQ|@Rod40C{ue%5 zTJj3BLQ$SuE9H_ow#4tYT}Mnz z@jM=26P|0D8D?V=XZP^t$yswoZRw+{ohYy4jJFnzy>@Iqip7Jb*~2Ec8S_>*rIZAs zZp)3cb!Z|7b0aXNsx*EED_7S#ckhU6Nt9_tZ$B98i+UUp!z0m5miWD zIVSXi^WMbeYj=g58p%+d%WiILsWAS>_TE{J~2h}`E0v!wCN4qeFG;?y%%>ot~iUU+JrMnX+9}P6ZN&$n3bR?C)z&CG$~Tvx*HgxZu>{59e3>dv0~C6ryM- z_)bhpi=+Kvl4zLv6*jp#d`8ggSn+mi-};#q$0au;%kPhG9Q^^lTK`W1|7$XTB_ULj zvBo;dy9#_0U;|wTnl=jw z?KgC)B>e_w#`8CusJt%3G2<;I94;>feet|L?kcIJdnt=xDjd9HvBzpHa_W$Wf7QuE-W%+kBc=go6WJJ zwH}UI!r#m>Pl=qdlOeTHn(j_D(%G6r!_?kTN;9+moRBJ!9KQBwp$*TpF_qTy#JriY zHyQ>RON5 zQo4+Uq?&6Inr>-~J~qRMomBZ@`GF1{bT_+rvn zi?DUqWc_R2>rw$#TB)7rYZwcFO)@&-L$?ElikM7YK!;R_3?_`m^Pok(CKRSdH;*}? zegST7e&Be2Lmbd5mbnzM3rLfd_CU z98&Jl*X9&3QXpE$%)b-_7$^ zA$RZk6&y{4uR)X|n=V^YEzoR-sRY4y1!#DKK^%HQ5Ncj)xR$j!#w4SXQ0_*HS7aLj zdLQ0Xn*eG;+qVj)^GLlmR$o`qaYC0v9QD#jsc|1X6#Tdyu2s|}t)EunS&m7`2s#x2Gq$z_rypBy*?DtRkAQ7IQ=g;{slV6 z7l%;b@klRPqG6%{aP>9**FkvDaU@a&ExAA+Ww<>uyu9l!z!4Y~%3hBS0P&z<{`M>h z&zIJXFJx$BsFuVdwkXrIqEZ8h!ybh1uh{FG&!;uT;0Y=~IJ3h_wxmafod3X}OVkG- zdF--A{{=8sg^zqXYFL9YLJ$ENfbhR#9Ym@Oqsyp&%{Z*fz!=GHl-$8e03#`Aew$}P z=b{#MG{s#3AN)4n^Yj0jFORu#vs%$n$idZtIs_ht$3&jGCb}^rJLoFZde!3}=Fb(x z8!}S4D&@pC;I+&oH`+8K20LYgS;jLcW#ayUVYfg%f=r{oLpvY|#i}$eQvfd&##O%O z&Q09@raJMO*c5SmVGskm$Uv+k>v_Q$3+CxpF!3ZnyUq92(lV>-GOz^H*9CM>GqDK= z%#VZ;A25->wJjSaS^@!tyry^mPI6P|JDNybd9-nm-tSw{Q)%K*X&cVaXkt*RIt(+D zyEcq`*ni8|#(~!CZ~^$gYi~QT#yE}lYKUtV7mrHg7-tB+Kk%h@K0ZJA>}7h4Q3kTt zrXoM8y#FYv!&Y4wdU(?t?}As?VvG**MvwZ^B6--ViLCP(yYU^a`|ZGQj8_HTZ~J2? z6dp~&On+IaA(zn=j6vM`*_@jfvjcD$s@XZqZGRh$E$8SefgTx%j+WK-wt|HUDLaS^7AW6N@_T zFC=IgS>`GaW9NpkLsH-Y&&7C&Lf17HG1jx@B1M49&>+}|9n@tb<+pfGHk#D?nGW=Te$0w~j z-ai|>*7EteLPRuM(%w4rqVKT%hN1SWU*9OJ7oS>U(uO8$+i>9vlZuLrSPGlZi#>W- z*O(V>42^_bU4|)6)2Rgl@$F$Gc7;D@w-9>yw^|4a&u_#)hY*TWD`z|gg|Y5CErgs1k%&spK_wN|R2Ps0%->r56>C{q+uk8nyZTh1S>S-d}A0@$UU4 z1=jw9yjy>3Vwz>HG%?YRfus^+EtSX*KH5kk;(>bN9wKT;p}z8Fl-)d^EmHE6@(EH6%*zrK(8R|0gL zb6?3`Wh3hVLDz_b1|VJL3)P0b&yFrvbyPyZk%eS<$#va3HWMRCo|lGW|{idu|z zd&)-Me%{LX^y`f*$MN@6&C#UaZ|lxb*6rLgE|P3Cs-YITIa^Nqv)(CU3p}q4@S+W0 z1z41`pS#Y$=uPnQ19r8Ht|f8SWhnwRx$C@Wz%h6&%a-}Ia0mKkW4NV(+s&|fEx5)C*sv;4rch=cSM=B7(R5YbsiT*LRLH!FLX zj)3voVZi8}JkYje_~3?iE5A!`@A&KkDcjm74W_wbl=(|IChdjYo=Ofmt%I^gQANL# zc_(4*VLjY{AN?tu?Wk(V(>urkuid{>=_eJQ!l3lzv|yGSRTyt;Zu%}06{K5&S=R@N zZYmjM-Dyc`m}pl&H%E&qM{RoWf~cnT8ar3Dd5+B-%p9mT{n>YG;qRG4*N;8W4JZ=h z{!E$eNeLh*+|Y~v#2VzQXThit8R*;>OG6@Z*83Qso-2=VYPN^PW#-WM48M~|WNKkU z9y9F=xN25xWvSu!SSkZoP_ym20pgLh2mmz;*&)-U2$^6u*Gg1SLcx=p}L z-l9Ezx>YpcPF9SFYN;ZYOJ8E2!Gs7Nq;racF>AIkcHzew^htY|e8b~fi5yf14a+pI z!>ta?h4#Q=+m+R)O*noAH|6Nv8F=G!?2XiBB(iy`)z)9CX&Os+*8v`Pk}z2}E}t?D3Y%M_0yzXLca9Azy8Fo|$w zgN83LfB^vAJR>)e*%SeQh9N(?dCb1+e<&7>p`OGbhyPEmbahjLfvp z+tz`2mSyC~w>VT6wKshkxAuS=05Yc?FxpZm@vOv+EYF@7r2-POVcEKefaZmlFs()f zX!62WMBFjbF3fE#cnUlV(iPFt=3f!TeE@BcDZuKVZKH!1Gg|IE{q!l7AHR1X>bJSA zq;wN%zQ1q!NP@8Qo`cxGKJHtj!ecD=t|8Lk&c;L$ufubsG0IB*T+O#{r5+ZP0%AdSd)#uQ7p#)^h`5QyPPkj>NYlphk%8B4*M1GAEID}dHGO64Z+p+3*deT? za-8HXyRj23z}B3nQ(;+6>XN1^gTbjFuiwL+$G&b`{$F|M<@kHMG7i>?s=?~F(dm&7 zT&tLS-|pxBo`1~x%DI(;@1m}G9x8kGt=4K=Lg<;*Lk-xW^*$Fo)vjK*2Bf`dCzk$w z7i;|AXx|dI^w{vNmh=95T({)H`RtG7PyBkvE)QLas=K~T5wqrTa`XI#o)hsY$Nw9j zTC%h8_TOz8m#@wLENQ;H?di5{yN?g8X126t|M}p3bN6#VvsHnkyxBj}_WbXS=4-F6 zPfO;lnb4e*xl?Q3=3R^bOw#VQ_7&e>ft$xyfUUA>-KE1^$VExp>ma_Gxl=RYqk z4tWf0KKQv*XT|H5=Bq)(v@X3`|l?DLJ~3%{IR!+!04 z_t((-qAxacvYrt?|58@Af2&)1{oMh~?}ugU-kzZ>7+R^>R(}8AkJh_?8}BYm?i(fc+{5HT7+v7|dlEKa|%95CVRz0HJZFj)P= z__@UR^UCD@%5C>ZZjb>B zX)i+Ed|+hB0sUcYsA5S3JHKW&{lpY1o`?O$A`rNX&6S|Gk~AoXm@q`-qF3TUx)RLn zGBQ_y`f;#1z_v<(>F~UZ!O*R`LYmaULIG~gq*O~m(GN|vrPP6@0L^*O_lF=|QAp=P zH|OL%G}tY{@1aKLyo_FYCV0=jDMai|(`wzKJd=9?OuOd1{XIXu#dquL*{rnq&7DEH z1HH=*SQ5lM)cocsT^33#BW&k@Dbe}5tBSlg|DWJkD9+V7|D#kZG6u*>oRl4r|2|#Ed)<% zEKvbG24PbQ_+%D1fX3z{ME#bs506jMZY}eY=i>k<^F^67RP&A0$S$Se8+@uaRC8$x z@ZZ&<6*kC+$buo^n^H0;)2s$SD;UDD2)}vRvd1J_01QYuHOS*n&Z7UlCCr{hCDh7@ zV=@!ZU240rl%|M7qgSg~gwnsX>LPZQ>${XhfUtZT_$kI#Nil0&ATbB$$<;_zi9a2y zSyY~+Q&d(xt!c|Dv;ZI-7TEYU`@g(`H!2j4lWpP&5ml%tJl2p^?kTJEgrl%BS%4C7 zWL5rFlI8=TJr}LRg&0(j!7CR=LE17@pez~-V88LOR3)JMTc)EpO@ZC*vr0F;sTkQ= zJ)lv&&9=IzO*EXh0||45DNObBy+TvadyZhr<*0c)jb!=B#bf6#CM1fk6ji4H7942w zG`RA2c57cgO$y2kSHvvRoRES#EQE>ygKJP1cb!@+H^6f$mm-f|7N}m;dVnE^_OyW} zG97zvMa$KEsuWPRS@L9>i{*OC_!C=pZU2;cVyg8l6PNn~M+n{BN)Rn0|#lk?ud;L_mZCkUG(8sd5CX)IwrDu|~Mu&99Y zt$$U6(;dkhE=rer-q?$8t^no(=j%vIk%o7lksG$0#&k! zu|~@DP9ur=A6kK#$IYnZ94KK6?IGyS%Ys(TT%)y3*y;qxYl-_ zxank5(O?QdE7l`Q0V3l#!il&aYaLVpct)!|6>cPeK|2-)G7g|+K-3~ld#}p9L@+M8 zU!H^;JHGtg1WeekuIP)#-PK?q9t){PyDU)lF~hOF!gq zNj`#J!NM$6VU95HOL(ZtM{NLIF&2otrce_y%`_OZPzqYBP=QqB*G31bP#SQ-%D!X2 zRXD_>qj-YzGlZVJ?08Q3->Ya%MT`M?D6c$}i?%#gR~MpbSOGpG-uMk; z)LiIfebuM>OT~AZeAXtF#){s%)&hJ`KNeN_b)a&*EraIKxM z?7#S@Ke7$t%F)iq>t7ArF@*1!a0e}~3U~3VrKC2#ZS|7fH@=+fF7w<|6edkE%zamX zvBdb$vkyZ%JPsYh-kpqx<{>dgkN)57cXyTux;;UAHWcRxk^wNTO=y&Io(g~l3XpFN zF*&siIQ~(PLPxFyo&pj1?%f2ai@(j5TZ;}?QdPsY+|$@?e4PcgJ#FPC;kT#4w*O#X z`q-bdKhsz zJ?v@hw0zRFy3zrOo|32wthn`7DF^JR`@EXUD|RFp%garWptuVB)??IOcZU-VJ;{Yk zq>w33TfKnJv|QY1b)~#M^?=xI$bD}vv98Cx1B7YnyGs!V5dk}Sf?EHy+dXLtdyFs?f(dJ>0``gHU)aXGm zG__fqKK;1a@5$oDao6-0p3L4;*k^owkbmdt*wEkcQ=-Mikv*oRc|R7>f2P^buZBE|f?t!LPMbXMEyiqpShXS+h-y608Ga)4#85+w zYa6I)aGtmA>ebJ;purxf+^GFR2b6l^Qm3<}oow))AfBvZW0gQ=6G&ND^yTjaNI%(>_Q)Xftj3F2ARZF4Jaq22?TFJi2B+0ZkM4OqCRT*|1-si|hF?PRiA zqgk)%|p-jjO|3@1fxKN)*%ef{w;&_PDN2Air@eu&@qY3c^uQ$Tpi!1LuAFI1%a ze>I;}PN=7E?<@sg39zjOr34wVUlvgs4|p-K zgk7JF7^DssgjWa|FF&7MW*OZ8?u@k}Ue%M#0D+A4V% zB25+M9fP!ih29_|Y)i0O<8w{gusZM*5JFh9#VKE>;row$pSRpybzbmIz2xTi`TMNM zW{}F1+^k&jBI3o{eY3evn<+41l7&{M0QoXX{xrayhca71NK{0u8om@H!(ZYO)>Bt7 zr?JVr2r?JDlZv7!u*rZ%l@h&^L5!lVbuGon0HP4^C-X337J4^86mw}OGx1U?xs&r} zhYVuML4Pj(oQ&{QcP*2P%?F4Ge=7zwdhZ*oNWt%6;rzKT^&SC!Glb*v>b)`0ZZ0-d zu5m4GhKUQi29Pyf-bB2@u{( zska%Et%VSu?Cx&7b#$UzBDdqU($r<1YuRjYtQudr>>TB92(l=5$UnTjZme4jcZ^CeGEm)@J3*VfqsEm;p48Z|8Jnbj?UtMY)*lu-KPv9hf!I7r0_~Vj^wkQioQs zoMpHR=4KyWBwsX`H>2pr6TEci8?L%{E*BT(nBQ0>?9AWNSf04-dmwuC(1`{6u_mj( z@$c1!p9(s$`g_8o3+rx5OxFBJ9J{jZdGCoeKa-wa-}}>T0yxrYX=FO3a4YN)8J>IK z``?)*CD>NoQQmur!)g!b>$F`TOI$gn67l$a&5mf@LF~9WK=|XInOeNjly!%C$ zs*n?35!a-(`5@Mn*KsVNF7>o=YClJIPRnn!A=uQP+aXw2(I9|y{P4b_@T!j9;|@k# zuyS3~Ft$9QcbA1=e-O2}Jf=M_s12&2-7?-Ji?~%vbLD~p+x}m1Ms^*c$UY*kXh*q) z>;VIds|=ivR$vEX;#tM> z4waP!Rm6R;usnn9R$%FyZk#=xk26YvDw0Z5tp^R;7s)izC3!){3B93{Jzi~Zt!ZIr zI6O&Q)v?pPsW-T?;pfe-n%5+&Z(`inrrxq@S-azIp!>S?Td%gaTH45_PQ^uYR0lHL z&idx8d{DGl#HhaDMzfnwxJS+6%K4HI#nRMo(H#ZJksiN8%x;-Z2-eALw~I~ur+-P4PtT^H$Qi$G z747Gy&6??0mep3QD^^ZuIBC=TG)+8jh)k}o<{({b#F+`4%f4JEoN>UhUi`w9NW_&? zti8&Em|ytd(C%v`7JsvLz%7(S$3RZ~4K>SMKFu@7M)VtcFKX(4 zR#V{=T~|r4E_@PW6thpN%Ha$11k)aSLYN|t2g6+}th+m2Q%&|TEb!>EX=|DV7W*>y z{MHJ8jPniOK$PjotDF1PY8(&1u#wgVC5-#9A%*LE2B!!y9LfbTk(CE5=>XWNoeddr z@ab}<9hncK59$}jG;zGi^A0&mQ-OtrFK_|8a%j;EIWSj1+93;KMZrK|Q-fpL^c%T0KMcOj?}!sWsZ4sXnaDL6wa z)k3`q20%@244LiHZ1&NH?Qd5+x@jfsm0L~Na}U|*ixE|Qn>NGG=Ae`)Jq>Y6GGSIg z>sQ_i2Np-4lX4*Zd@l`}Ona08Ra3PuI8+EoeViZ)ve2BtLo%qNzV57so~kr)`pF1i z2&w4^d-=*H*h@ia(tJNksw1*a##_1ckJcLA;8ajdgCI5NyM?h4@7i^(B6&4{AS}whfxSPb%Kt4x(=& z#Lyp|0~`Lx0I5xm4#!54o)(NT&jnq1GxsgBRiKc2*Y)%;IcAgtZP?YtZUU?vp|jws zDIT<13R`Aw)S>Vy=wlNdG^A|CXNAI{VpwlM)Ro}4t{3!OC5sp4qLQpfVYH-yXBGvyT|=!RnK5M3aiOW2m?fA-mIH;OjLA=n0J82e4IuB*Ii69H@9pO!4UqE%>e zeyPbpJ_jGq8xku5P{@TFKTHYC&Ggr0&c^vMBFMKKAL=`Bti7IbY%B_2P#;f{Vv4EO z{3$RyJ0rSShwh8oIB8!z(v)cR=j z3m?7aLcN|5*OeTSfX#c*<#R)3g`0wm60e+N{Hx5frTG$HO(i*=kR5#CcOQMZ2kkap zb$I6QBr%*JWIbwILy{3ELqAYY&k(6oa~EBHNONeCiY>$Z4HSW0 zo})nLr0L|b6U;*7Zn6OB0i!ay(K`zjvHJHJAk4dEEmyrsl0nA_JfWv<(cw@Jj^3*> ze5{u_xMvJv&RhZUI&!dRoeadc0Pp)Pd`g`w!eC6Br)m`($9<0HVi_tD+nG~ zjubH7#-;al07k8fRwNl8!?wU^@H(7iF{Xz-c~rXvejcw=fZl%_0Ro2ul3)nk-KxR8 zKU#692HK32I5~xK-jy?8=mWrAG8ku=yK|a69g>8X3q2q3ADB4!)8hXGd-d_)#!u#m zWDU<%mkKtslFugE-dW!kcLqd#8`jWJaz^(@95DIQ1(>_!n-BkpE15DkT5G2G#2E&9 zJu2z99zOD+9s~v{V3CGOr33K*V_?yd;gikSD0@PyHxGA>v5_)VJWj3Q(4Mk{VBg0h z*j(s3h5>6e%{);Jd4gAhk~VAe;FWH^^vkppbOjqmGZX-ZTKHrI@Y|=LGvv8dT6X@I zBa3W41IC$();agrU%#~zYg5*#8!Hvty;R^=jdr|zbA9ipozMS!j@v(bw^otVH$g1R zeXFTGB+00Y#dvYNibZftS6J3vg$od9#FxJ@BUs7&_9 zo`60oS|9^Vi=B<`mrcAVj!|Ie@W7@1z%~eDEC<)LYMMwL(0$NOYBnubaLO;wkR@>9 zpVgHKY_u>L09u1D95ufW3I47OH65c9najOfyL%HK^lobka(rx%Y=cWhZl74isZqqAFoaUC|aB+-4c}RVYBHgAi3R5sytUgixdQIJP(=`fP?uga$y4@(8pgXIUnI zmZQzI4PDD{E_KvHWuo49l68FoY_4DfHz(Fm!gcn&Ju0|Si2z+iMBe|w!9;3Kl1#Ei zCTCJ5{xSNlnLvJ-gvSNz3J&|b`ZeALOj-lj!yq~{*uxfwux@cG0a9m>5|V!|6W*Yd z*w70f$3n&eNz$x3TPX8#&&%1eRo8Jq|Cwn^=6BGek=i;tCDAkezZoDGMFy~SMcdE6ragy)$bG0a zWjIbu4|1#k@ z4&It8_N75STLrijpr@n>R(dyhc zmMD9kV80E?Q;v2U638sEbaYaE^_dK*(IGlPf@g7UL8MwM{rT zaK&r%Bc9%)7^_FIm;+i|ct0B;HtN=Jkck(Zx>XmsIidQ&kALC9?-gU&3l}{+zJqwp z{hU=?_>DQsjg#gZ9m;emn<_%H0Tlbj++6?$hUe5TNVFoMGe>4qxKGwRLUE%GPUoUh zfTCY@{)=F4)TBPqHrfFf1p;$ta@~zc z7hkLlTF`B|_&Dbjek@xtu7+E9~`bA8v^4iFXNMO}Ul z)iT}jD&2r_?e1mZ^%LVZ!)r6SQvuPBrIG#>Zwh4FQfu$AC(-K=eDNu$D8lxC*`xyQE-8!UTW8sb31`h%$X?;V)(=VNy z#_z!<3beBf{<7furu%k&KZ6NxclmrBL@)ro8VyKrMk2G#~92&2iXhW!XpPiNNoFv2CNnTfnw`EBBI+mjH2A8ef6Y(#kA1-9$>_Jc(_bpD;L_% zf|ieqY0VI)PPldpQsArxELufgnFfcCEH#)Fc(jV>t$>aaY1kajD~n=vsZ8TgoJS#{_vYNt1Y7Bl*=+QcVSvOJdW~+?=EM%+DJHXlb5Cdsqc+2GRU_6Qfb%m$aj)^$=%dGT{xly;ahQ91{8whZzx#I2|+k#~qw zXK~x)i#UBqm{5^Q%}EBtvs@4ra+Vm{b~(!^a+n>k{e5pZ;5;SSJ|#(2O1zK?BN$UY zrcO=^)QPr*N|o@Vv9B{E zm;TGQmg=NrVgeVI8>!q=0bDvPzQ2xF(wlm?`J>638PlILpG0r9b+S>JFs;>ljts^! zgpmyxr!pvbw$ikX=%SRwjecMT2H&IDE=B(40+=^sKqoL#j=$BB=NW9JO6?SQx}78Q%ty-IJhV^`6tA2^WXqFH0-u%@X-@-dWw)f3}gjj*KoF; zpw2&25QPg7Y}}c(X(V;?(cfp!{66>mK>aJ-A{!WZmB5y8k$uUKFMzY7u(B8+7&Rf|HmTA;vd|AeV35lYorR-+wecrF_`ZYiM) zE_dhp=AGV5$lGsE$OS{9i;`4xH!u4?I&8)eT-M1!R*`9{a^yp?t8_|h(gyMsS)Jk{F_!)$z#NM*uef(336tTYqV~V_v}n~BwNm7W8PtVn#rW zOrx+)=euS=;8}ts^NBe1rO2dDa+W55$?YEM)i%Jx1B0#+i(`&cwUCWK{fFVB`K2%X zL|(6E>8gpa5w!rVt*gtPUfKitzB_MOwn2Xdz6sW(yvMkA{b+bCMV)ZVo(p3ppt&XnC`elVM ziXN|zTE;ndqpWrHJ0(Gd$dKVC_)wwwH1P`%qAjaBNJ9IJk4%F|tfW>QHCFT!6)*XLbC~P$v)#pR;E^3|In2RFD%0C81E1152JU=wtS?Klg z%9DLwpRVqRkH2Plev4nq5oyusin(LJZ3A6cyg|F{Pc^}KUUEHXSh~kKCIlh3LalOa zz8tdN5HbyDNk0ff^>e~zU;<@|)n|V*x9XOri#<2nil0P0j`pE0%hRFD8?KkBAZKNl zLwrY00h^hY$QF~`lz=_EY9FVPgQUqd!upt)4uROfblTKU2BsL)3Cz2dMTc6?X zq(?D?`^Xza5 zySe`5x}Le)op)+)U0JbjrvPQc318OMhovZL=0Q%Ny;QN)`^zOXT>(C6!<%TzZWXx7 z)@mZo3tb9BXK$mCrG0d?3P7jTtfjCOgmo(&2~!b}@nM~i{@Nm4S};^;e-xqs?9)KJ zrBRS+WfZmk@tlLh8>X(E=%5x&zKu6yC101 z7&@iIoP4!xdGOR1gUoXjmdatsP`&c!QIl9SYx%FEfs1}ERmkq2v}W^@2BNQM4;~I* z`T)k3G!z;}f7$SF&zyiedJtJR&H06EnDx@O!6S`LwT^pj!#3L8@7~h@##9t8+Cnhy zwM=7~%g^w(x1BzTmDKqj7+hl8W&S*7)6rTR4AJQJa@n5Vih0-VqAs6%cwzgM`j~gt z%gM_P_8aLrPlXi{?wz|k;`8QCqW?+a~bJ3=Ge1)a%lXU|NHfehLg+ek>&W9VAE}*ktjfY_;>3%VLd1P{4cb zL0WN5-WG?%z=F}o_nMoVug^^~!>S*3C33>)vp9_`FX5bfkx+0ZitNT&+qtKby1T54 z;&Sa6b(4U)r?pGddyV1d`4eR4+1vc3t~jC#Hgm}|M0Di|_r*<+{IbKq;Nr4Vr)7?| z+@z$h_0Ru)X}S6DVPP!sGSeB|rSCC|gPy^p=sKW%YT*6CBaw$KRF)^V%&o}^bS5X{ z`kQms@i&g0J6#kTYjmF$Y-s%@0)Hy~l-Uhq>!uhn;V7|Fe4AiARy3*4|Ixwu@&?5l zK44ap7uN>&l002j?)>3ek^5Ll-RDgD`?S?>SrFExG)7hXr{&K2e=cQRdq$r=qk)^W za_Hmif(!=>tcwMRp(={5tIyrG!n4Kh#ndBh-khP#z!#bsyu8#9@sMuxvSp_ne0>hh z;ubOjJi58PnXAKxK6stM7H%&JyVl%c>X&wL+ZYDN+~${?LYu9;7Q3coxWWGKLoVPAn~mW*dU zZX94?-NuA3H2_&Mjmn>WX!Ao~cP4-ZxYdbBcGzba2_xJ3gX)N3C_5184PiFPS~N#F z+Nb4UNUo83j_Oy3?!lDAZP#?b`X8M>=TpQ)(hf9Y0qfMHh-H2Aa6a5td;qM!#=(C? zQ{I83wC5Fn=3;!y1c{i9LbR;I_)czb-IgUxi(G#l9N)h6{>2|xE?@t+@m)M`qB^Hy z?h9O2Subn!0;nMc4WG~UvKpy+WCVJAYIDnpCpch<=VEfo5dVrvG_OC4!Px|OoX+5$ z^55KVr(eH>7m<`QApEkb2z9C--)@FCq(4vTH6A?*yN7KgkTYSO(@e?X5rqfmevfO= zUfmGRKjU+w;1VOkGWt=Jo=<%cGwTW9j1Q-eDFe?U>vkq-n+@eE@IOZ-62b()a5YUy zp|Y~K$U695xmZRB`Cg8GBly`M+osL=#pHm`1v10Sny(;vE84G~0FfIdYZ+vxw^bIp zfQ;Rfi!)<)(fbZLvi(U6SSL+1ZyL$9p{`MROa;oW9dyV=xsHob9HFNSGScmQSu^6l zAfQ7}^+*fy&J}6xdA21+d6(B|Oc%P0cay44_6+w-Ac~{B!#MGvUMt#6(e)sV>oov^ ze#qzh(FZ!&4qb(zfb|2(qTDWfc~9j6#mCwhJU!SW3}rnfm+ocy+;xE?4|?nLd(nPfdm>HP3v$^>_lefrU3y6wWwRyW$aKrkAxyp6`CB> zs0pBx*5&X(f!YMvm2^?Y6bSqo^o~RMz`<65-keU5ZqfE_nB;xWXFB9{c!0egY=e%S z{chxv>x(qeXwf-DOIW{7WU97Nuu zg?g^Yp-#xE^Jjg4Bd=Gj+-DUniQ9G|NKY!zi5BS51Zjp3z?W6}kpl0;+PNHmf=q!l z!8BaWv(tr(ctWrV#^ws$SOTye#Jyg};&geA`$n?S0krWAcohPC5iG}eQnW)Rs%W?e zwHEd=gthiPL$L&dyjAWpKc9cqss@SYfGui+>Ulo(@ya+s{wZ4ce$3J45`2&E5(|Dj*ov8 z>}aS>y=6|yGEp8`fZ#=rAqucW7;nx&B?{SptWz@lZ7mg~DFDyQ{=X^f0B^~w6`0xx zt@-n{OtokNQNK81qRNZ!OZo#b*b2vK0+Ib@=K@$OvunMlucZ-82!SoqP&&GRX&uUe z*J+(7v`X~Tvpnw4SzY;YIqD@*Mej|>C9YiEy}IL;cWDs;abx-Z?(IVBL_hbnJs@@b z0p8N9HD13}bpK_yb?$2Le7Ak;lyxg#r=;6H7qU~GvZ;ew<)BxI@7#M5#)C)U6XXpR2!NcYa~m>AAN*9?^5$M}%r% zbdADM`O2s8K$!O(HbMbg`Zo7rE^qPIp#etJO~};f3U6pEI}yDYngYG>>rt7$TlHa`5`U{OF}4rdHUysX z-rBTU8{@5TGI2OLI$rK}__(=3GfXshAZ**0(7iQBPNL1D@*F?RhK>&g6HwOD8j`mROmdU&nmn6KPI(`I4$m6FCe>?RxE$*b7R^$I?Id z{jaZx0?wxuD=;-2W+MREKwe5;u!Oz;|-^CyJJm_l~+XQy3ZMw4jnrgNTL(a8mH=qQtc2-uk^sX)}aO+Cf~ zT}fGdZ>k^ivT``@kI_WlO(rG8`ToR{tt~t0e1Leqfbt>8wNRvE38%m)Oa7!MuQPvE z?im3?qmS+Dx~L4;@L0o-4x#bu>G3~Pv(KDO-!zzR2zr~}!5V#*bpWug>)boBey3$1 z_(IRjL9~J{oU0~vTtSxh{+wp$#8TmwWl z0V|od9PREytjLZ48$Z{7kg-B&?vRb{23L?IZb|tk_&9$t?R@nHs@}jYosS| zer__n9*TR5>A?xHS0w96@bu!Xd4Y}KQgyeY-b1m}2QbtN3B`@0NLS35 z+Cgj%A@N(W<&)UND~tXsLBWdQ9(bwgH@}&Bek;!yp;iFEE+b3z%gF1R<&UeES&>ER=8$v>Nu)ov-cmK06* zRD+gOGxzOtTDCj6?{II~;p3hb+>*A`J$+?M`Udxm%`F+p?mKt3?A-63nbVS~KIFdZ zXv?ls?pbGAvM#yrZfV(l(|ymamOXdf_l~seeeS;RP0PN|?)!hX>{q+P$hCkbTVT*C zFk=hnvXrh*f+Ufh~@iVX+n z#hs=oWUU1^XZO@+atv4ah3n?*);-wOdhjzlvwrsG+DzTQnR%xUhfKE?nf=OWX_cPQ zwGPd5oqsjQ;%dp#Upwx!9;v^7gEh&XH9I}e>~A}hlOUhBPkT@IbwPu#o`-}&U;{S!-wgz5)x{`fg%qNTg{ zMa;;8aYZ=A7zlk8EHonMIny;1A%Te043SPFc@l>?r6w) z*Lhi))py}GAEE`~c&jdlzD(>N=p2pOde9(6Mdl4rXF+wmAu53)Y|Z5`%`@R4t|AQ| z7MCtl=*A{2MOBvjjXF-bZ(JWITx-H5CU>h&op+7VAy}uV=raOEiilOA5*s3KzSi-5 z0fpTC=!q>>Ek%W$B5z$Z_2mBCE_wT_gNCbn<;n)BvCe8Z=axNmMQ*178>$HyIz|gA z#wYc1o|DaZZu!uMBoJF8+x~O)3!8K3Wa_>~p`9-<8vX) zjpsu=FBth(2eubPcwJr_+JDjRLZna0hWOW0?H8i_%A8V=%Jvu8{*~_M4Yze%j2@R) zJr%3)g_WLz^0Z!mOx(>V_Hj_i7B%hb=~7B3UKg{%dXV(2Aa+e{d8RItJA=oFCRRu` z;e!`3j=`MJ?ks|lTW4_mzW#Gs?wO7|4n+)KwutKQ+;KSSVcEtk?R+;>hP;pejiCF* zM`E7b4IQ|&u_Q6>S!>D8GxoB_z1g?Q3Yau%%4jv2Fvy;e4|B?gP5;KEw4rcCw=VRPfhwU2-~LoJtLSdfnvU?Kel+L zw_qc!J{(p+O32gfGYgkRXQ%qoX~Enzsx!)9n91>tojXg2!h?djQ= z`mvyAv2TY{(XKwjT(srF&jnQbzi~>2{$MsNPhD(*ao4F6S6~#a#gII(uCka-NPQk8 zNx`g{k)+A{2G7T=XGi7WtT)`kZt_Su@#_4)*|SfYa^2hY5^;P1O*sc^@E zr%M-{d3Q_|!_Kx>)&6@+Fi>pR8tRz6P4X*J`9S9PrONZZJKtWva$q*PGW?F+{wrm7 zW>;?2KinyMcl+wKohx@w`$n%^ta6K6ovm_t`>tpr=xyws`Lnw|w7^xNR5Y^?r;X*Y+>VM7fOPIp3W;?di|HeN$@~-hEjH<@K_;OB5CSOA1 zesqj(V2Z`J3u#p3tbB);k>4ZP;%e+j>gQ#q>uKXXgL^)`rDffY znU_mZbEU5FNw>h1%OCUTQSA0h^W4q&n%A zl(nrc{@JIgql}^lTw}@-VHZO!Ai=$I6aEPk)^F^_)i++bLSerTH+sY#*fQFF?pP1L z`mRm1$l-h7~?4TU7gxm zzHaE{{QmCo686PQ)W>r!{>1@>K|U}`E>x|FwDk%|GJ4dV^DxYLqIZmQedD*ceksKT zyMeTt%?LLu{qcfTnx#Lk`{_IfJCM9$U9+uuW!teUxWcJ!1J$4IFe{#d{B8GLC zs-_~7l+S*QF$kL1*xv5;1!^;sX8x}p=QYFE*Jlgmx0L7Y;fA4Y)*GvDr6II?x7yz? ze>zngpj`W~u%S@a9INRg<~lT`X>`#0oigiTSVs_V2}V<=>WSfhh1El`Tw)U>7saOR z%{eZFfxD?UJ>Ni-X1E8|YVMvVw&q@WoT{C`Qt=Tk>ZsBI%0fIET_;go0bHTS4{!Q{ zFW0EZh7fi#FWq3XP>y^C%$e|0>Sf; zN9ekcj&H@;4`}#MZ#|7JI?^yXF-0pDs`2<|hT8GXsVFi;W&CHB`Tmu?zs?r*8k~9_ z9mr3GlPa`glK}7`m>B4~MO9MNz1bkD(1c&1G=)YQGa+bYuvaZ$W|^DI6OM$JL!L2^ zGF#Vr499g5MYZ}=SYH~^c81>Pl-+L?d<%*JbEriU%4Sdu(6lMYNpUYkf#dI7xTq{M zrYm%W=Ba=}wD**B2ws>8*}%QI)8=cr{8g)4y)4xwQW|upn5#3Rt5L)3vks@u%Ja^` zsWT$$O`>(z)`K233T&ITK%(vlC{NL#h?Wach-};O=9X`_n;%n^JHxb&7ac*b0df=h z^8kVebEKsJu*KUhWyp-(&U`2$xPt7{rhUzMs7j^73967v&d62%QI?BiSi^*siG+~ zZ^w<21?ASHlB&v-Ef*I_SP%li+L*Q{Fb#t=7Ak?Wxc@!;q9`D+PJYl4YO*+@hFgPaXTU{RJmu(p$e46gyb)7Q1p znUJ&2*`e6=xhb?^|7_Fciaz4HRGVrM(vsez>4_fqEWCE~{>Q5(aum4rB})P_2Bz}k zEJVKoT+MQIArWVQ5rZFQMt^lbHK6ZiC5{u~y%$NQNu97JLH;A|_{@Vg`NpdD=bE;2!u=aR@O?PMJ zfoZ?8-?!fE_Zfz!%CkfMY@X!8wS~c&Yd%^7jf>Tyu1jTCUxUR3#}~JBPXF5FsIp=F zjnhw`cYn-|!1bA)fp6A=8TZ_NstR5T5J>X>QrOAPnVJ1bK~UhZA=`EJD*OGRS2d^e z&mNxjG)#XjGncaZqYhdP#aRgsA!!Jchj0}-3JY4l1*)XbC0!m!cgtk`Zg5wiCed4bB_(XSEb&p+O6w;0QWDT!ll5^z-=T{7_qg8hPqjcf}uXT z?uRRGK@5?e1d9=&QXq;4IqLR57Uc_)45IzWVEC=?ZWijNPv!I&G7NzGI-^cWP>Di0 zuP|6Jg>+how0V7Pu>VN0Nj}LPKh%$eo<{}Hv3|}lHU;&M@e6B-B*h~gEq(RJD{GC8 z4fg!|>|Qo{Luo{+T)&DBAt57p$fKFiNG^d0QBX=D?1xu!#C)6g^@mhrDcweAzHdEzLF>VE!cJ!Z({ z8qafWt9b3x$p&B@O)ns>U@K$|9q43{%^A?xyNB;Ul``j5UFXs1X;5>KW^VxW1)x&O zg|1@D7Ha`iH7&C0w(YrfY-=G>;j3yag9M`3cS_9a=ZQ>) z8Zl-2@z<^bMLV$MUq@FyHLqOFLazt0kqx*U0PhM8V3q&Mc zNit7B#~u0&)##m9O<-s;A@}w9^fMAbDMgEwf~a1HIYm_)W~ewGoZM0Yaci{pZ_?-* z-%v`|YzkFPWRQsrdn5P0Vu0NHUUfLMS%HND!7yQxTlsXYy`ceg>b5wD#?(BC%q39W z>;okLS!9dLU+JZ5l`>S*8CnVD2sfeKy>iXeP&E+MJCk}9ZQ!Mv4*ei}8yl+8DZ+h@ zcaFWO+{NC#SmQJP*k_!ysqnV^4L$jPRE;K(2F$YXZCaV45`Dj*3MlsICe2IG6~jXdn}!$sp)U=#0yo)*gYc`Uj`IhGf!lR`l?co>ye~DNW7e zBn0q`^=gbqcZyU%j!y!hekpX&Mr<>xd~VqKO20?)skK^@&9Qe^Hb%!I*V4k2sA{F< znzVWQ($6tWIz-B1o#rA8bECi*yomwgDF0`xRJ;xeV1fUAfKO^bWr{UnHDKF1d#e!z zWd41L`P#|;4H`ns2QEp8p}D0zv=ktlmxpIkHNqsH6!^$qF6k#rrL!Ch1jHsQ2OqJS zwXVhj3=)k&R+{h2|BlfR%77-W7M$@ka5cK|@D!XuW`)WTL4qXsLyJYci%+u&SKI&G zazJd~WUOdIjaWtZS)rpV7asOVVP>9Gv*7wROl3->S;~-4WLcoUYIc;9u^+vI3J^** zdo-q_hrd=vOsZNz^UJRA1o7xvgR~d$AUYd{dpAXfi%m)b3pS_?pckrFxMqaIt zIM%Fx%^;F<$wLu9{DyA3AyO}8kSX(!(l43?5@^#WP1E_%75`&P;}AN7%oC|!6se~| z)VmX6P+8vlZm!9R-mP=qaY*r7_t9LP{mF7P-?{$n8Z1OLh>^yBPQ^4_b@DoqLCOnnJ@w;(@_m{#nN&u8r6?50Kqb} zlv2>id~^pxxz_~>vIdKUD*_6{RfsGNRqtGqPJt_OL<4JKRK*x`pd3Sqn_H7e%%r30 z_~bA($eJL!Ca~oEcxT~u2>e6XZ8|Cwkl)Ty(y1brU}8g2haW4JT$(xIl$%?=<9b~% zVMNsc9LOxJ>X2CIrg_x>ioIbL+!%lW=E#c-^;m9;`MhSP5Rw4dcmD%KfeyPg57r_g zR8>`k^C&DA^~vDuc}U5#?Ik{EOO8O=;8}CwjCnL4gjSJF)evMZcoZtJRGC^3ccqk1 zCWiueAtZcWvyNinw*d7HhWw7fqJh>(Ks}WK@jfdzC6W&hR-9qr26x~k47s2KSx-a? zSQZGs6u;&IBnt5~&zbD+Q(1KF`@{vBYHsDR+Uvi3CP{gF-a?2Br8*X>L8AIMAG*n? z(IXsvNP_E_S4Ao*;*}r;bWMIrvj+>M+ov8&EmE#GRg#4Ji!f&;^{x~+D`l~WzE)pC zBF-1Sq-&Wb9oX;&Vj3zuM8Q>ulDCMggW)RDCkjM9LR&ae%D}}+!kVf3uH+hR%g0ZN zKuS6~m<|WYpx-GdG5rgLQL>()bxMTJWT|zCJ|w-CHMXB86mhMOvef$_gyr8v>i}E* z-Yb2}MU#qGMw*jeOeo*9zc&_LtSBgUAIMt#q0`GC)60<;{SSG7jjI$b+im0u5zg5a zdTktSxI~zS+zkXc&GR}P49##mh{9%AFiWsi+2!sPG%u7K{ur*rSDGr<4`{}$F+B+U zLh;JU*S4vk{jwBUL|xn7ngen)a`sERh@5u)AXj@UzP>C}qX2*uvov&V3r46}a^USi zq}~MHRv2? zdn!|j2K$BRK`v>6f(hWKdq%+`g);OEi_|MY1;I_vP>wtqLl@9nGbxw?A^K-2=HXJL zF&B|90U@OZ8^$1qgb%X-IGv9ypb+6AT%r)djW0j788tzd%V&YVhI$A${N;EPVu<+) z;1h-8o6j5c#>`p$)Ok&wIVB;y;-Z5jIu8*6AaJyaOUxF2%H}wnrC?SrgG~YKPYSVs zkEDIFsomW%kdyYoGxyQA6VH!qZ2ddy{}%5_rR}3`+PZK}wbfiWxIvi?S?~_<3cD6z z2vOpjD}XmCi4H)91TIBd120am%YVA@MTVkqJZ~c9O;xfUL~txX>}7FMQJ5ou44(|2 zx?iGeIya)*_)jEzF5d_FX%Si9KJOJ}KXMYi823_{?yaYPqA)w>4W?Y6xuj=VD*1S& ze&g$HIrr*!>duX%xDukix*_ZdoY@>m8j>A=&uv?U{n^46E1sGe+MfDCe;UvFc@uUgbyYMha&j1BwcY69+q_LlOVpBRrqQgnoE? z>cjo3D_u|Ov19M;Zdho&ll^=Ved%hUF6jfIYazH7mCgF3e)`i9F6oyp9Fcp`B>+3N zmaDtqKdb`Y+E?iFY697r)S7(-omFn4Onn`F0xnc7B`tDGQcKqst0f?mk~M z|DnDKx82#*+*Ibl`uB-0gjdNKIO=>v|1i*qte75Nj>&=*=^1>-8N0mHPh`St%M4yU zRXn=&S8&%i)z>d-1s4LtV6I#kQ}}mC@8*f_zwYDz^_l)^=t_L0^Cw334|Nl6&xd<( zWsnNjECtWejCkl390H? zWosE$DMF^3Ds(~$(^4^Mdd~cxy2I1e>Z;!PGqinYO?PEjRXHYwV+lF3HTv=0Vb$5F zbko~vzpU$K>cdBhH|9;(VX$_Thu$#@-RB$>LvQt(&J{ z)X!rWco}t_yEl&Du(^hv8tGfu8tri6AKt!cdA!Q2WYZb@=9R~FyY8JLIJB%jZHjsJ zz~Y{SA@48{khJy8Rof$r#rn+nq;&sEncHqQ)GNqthk`;an}6%sIh4aTM-MBr5ty=m z+1VtT{?7J8bE#wX*MM#9)aQg2I;EOy6JE<+4lL*DzIRphHXu4~lQ(>SF`kTAM_+e_ zu=zYiL>qs_EMpjgYW72p-!gewZD-UjVKnRLgH#Ld_1$?&%`?x?8mq#7&5}{b4CBRE z3dY~zc5@Heg)J`MY3LzNH+Est6~e+}8`6+V$2RmDULt));sTCe&H$T8pAk{|XFVgY z$Re-hL>BMAGZa~J-~lG8v~p;Md(m&t6IZ*z<$1XJJ@51M-2|qX4ke`XpCPeR+%Yqh zwo*3?87^`Q*``cGI38Bx0f^9Y3H|s9=hRVqo;7^}sj4PTC-3}z34oTd_w_=E9_?V6 z53T5p$9mHryP8rY2*+G~u`@K}Vj5U*A_TpiZ>&j~S}^ z6r`bpEro&Be>^lmHM5nNv}&Km9~#s>=Y43%uq@xI)oO){l3%D!(AJkNc!vsMC^o6b zNlwjjK>i>rH4|$d06KF)!&)?Mw}6qU=)C<^I=P6QHVhV7KOM|o_TQHWMf~OF+qhG1 zJF6Vb4(-czZ|3xCiRhJCc-0DqLE)itX|i4lQZvGu`jxQ^ zX&BP7aipiHhAF+GBEpjy(0eAQZBi+@)_)%%9oW=N6-Vm<6-7IJDpJu{P{Y6#_I|pH zaiN9w$~o;9x+v@o?(W~_m~D6du!SwPpX8%9`pStR{pW&3X0W>DeSifJ>`D%WKJ@l3 zAEbEFA#;J$&T%IsydWIT!s_iW*Ywlr|z9$WLFOW7b$;6mnng;Ci`tO&np%< z((yCK?$%TC`4lyw%B(~La|J|d-Y^w?rp|u~0rGmu71-zTL`7OTW^-`2f&;jBUdnU# zqK7HQ8(%%d3CgjP#=$JxTnuRO+3K-;-5uO?ZE8H)iw!X_4E8m0ICfE;PE_Dg(hV}1 zT8bbiuZZIs+WiFjVOzICE*Gv7DdPd!Qw<7*Ojm;NSv~%N&qbpusfsg}5b}(V>gK&XH^z zkZl1Fs?w)4wN(nndWH^ra3q`B%f(l)oV8*u51vjDBG>bKsBF5r+cY0tEOy2x2%$Nw znA-$lP*o=dD>JX7U>bKTcz!w0Z9X)OS3zgFO|K+1uitto`gQ1un#EE}8g)YD0d+Q~F7B$G)D^!VbTSjTcE zvw%SQK9njY2Z@!WU(;YQ4X}@~45s4RCYS=OkPe}xh<{gsSuPJ@^*6~ajq<_aU-uT?w_#5a8r3EE+8D(HJO{^flDdqpFiw0YUH?^17ad&;&llh$%B~dK%-b zup7TfuHlo?0Z88jHz%#|1HhWO75a~wf)X&~P593l8a${oScAEIz3xI8e#zMD*l^$n zd`2=YO&5U4lK=)y4w{Nw6=HIYl?_1`lzmeg{>X2J^}iS;Y?WfC{UM=QDdf=yYYJ|$ zEe$pZ6Wo5HnH+Zc|rYgvgH?3!&j~7f6X3>g4ZSD8Y6X zsUV0op$`hR-1IQ!%Sht_E+Kw~rFieZcq;=E%6nNzQxbzDr5w>ycvcS{jA*h8*{qUD*3R zoJ8nk$lu%y@v|ktoJSc@-P(pO89~a$B})wQya)mHxn8^qr2Nl;sIqQ0)>Z=ib#=pI zX<0}34DNwThzYhA0~4%aSvwPV@W1H2371if{^mY(!8T+PsT&wn52`rQsiNF;88PmF zSFS9_LeKTVF}CTp1yW|f54UZV)m*eOKNq~HVuOXLDosMD3c5!nmMy1~X*pS@tLRZo zNgGszI&4nvF7%D-HY%0^Rpy$h@o#BO&6ki0joG;-A7=D@wxkPDFVN;S41=%IC`{e1 z0aFfFEx9v+fVaE7bn^t2$ zFjy~D`!H>a1V+a&p8LZY0Rn1GFO;|br`&w!7_^#p)&Mr^n0kqOCl*4qsCqJs@kk)y z_4E{N?U7EK9##2ozI0%Xmy%eJ4zr&ikJul7a%Q`$9SA2tfl3bqngJtP682sgp2&Z!s}CP}i^dLD3bi*xEe>I*`) zUjuTqR6P&7Ur6*`H%J5@lXyh!?2iLW^3cyV_7{2;kyQs1z8`ZKOxw7e=42c}6eBK( z5hSUc7M*S|0mO1KZhVND%$V50p{xIJL37Zn98^k!$~tbyRv}dWysF}M>@X9CVQQ^s zz*qR#$-?zY@}}bgoI9|6g~`xoK$N7r$E7f|#KbOYkK^`Zfv@m2l!P#4+q{j}5PLrf$v695`#oj~BAK8Xo; zWdp=XFG=12-18rLXEzY5n=z_%NEVYYLLu&La?@n(SO?%%#HX{Qp`3K> zIX>|Plej>^&L(Ibr4fcD=f?%kW>%hEybz}#c_#^>g$I}!sTlGB0Y&ckpwDRt=CK67 zKp~QJu}c-GMX~lE;PylWpOX?mBjGHQXvaA;=n9pSB9LEz@6%)r@Y_7#nMJ{-vS4vH zFgz9}>@CXiO^PcQQ^LhWa3C5Ic(nR~Dr*#(X>YmQwg zUrNW6(YG8I)08-aiD^nJ5 zm_ke@p=#);-!R=>mWYEK)K*%WF9&rPBz;j($0Hl73ig0$)$s=>X38X5o}#_= zBmfv;)tAHCKBR56MI`+iaBgOHH88fAX;!c^PKkOG%hZxdvWa|vUwq{{tTry<+E)FW z=}@)q8K8ViO{FO$dbUzOsj7MZt=8OIF26mI<EEw4)lrv~LcW(cP|+xzh>mNV+9a10qof^+h~M92%mHp=v+vTs`pC} zGQM;O6us(|W9n6L>l8SEZ&rQ0Zv8&0Uh71?9!O7&X>c)3);ZCjJ9*ITUBg;jqorBn zIuFqDidkElS6fC*TUK6M&aJk*k+w7M+RlLnXtVYUUhRc3?U(b~ zuiR=c8EL=zuDuL&Maj%MD!n?c$8_At>$rKVsHsF zk*@#Vb;)o-h`A8vEkwi$QJ`a~PKX;75>|zBc#*uhNYPuQ94k`I7pd2YG)F~Rt0EnI zH`Tmb&%4_Il&t4>o78oijdokCcCW?vSeo~&^X^$6+p{6R$F8o&VYFxCYL64Xmto%P z;@!JBw%0ws*R!tIOE%i;v)b#2@AEhB+v?r7Ew*oae&3F|zFnhzdsh2G@cp6Y{rkN8 zBVzlb^82If`eR1><5v3*;s@f*2M&7=9Elw`nm=%?Zs5e|z{%Bt)A&JV`^2hpw&;mEniW&4(+!hp)#D-^d@n zSvP!Zboln_@Ll{!z4=I^_egW>NNfH`d)>&r(UJSBBVG7Wk@;wk_h?`2=s^DHP~GUr z=;+w$=p+2txcS(m_t@juu_yUspy}n==-Axq*h~DwdGm*h-Vc{zAHKQP_Om#4OF|MS86%7Jqfmt3-EL)Fj)tEKK~V@PEZ zUCjzUk$T`lb#-U#I^t5BP26#r}%lea=1JqS(8?v@Qoz(lF6V}%KM0#`Al-+GBuF6 zNvUjKxl;cY%Mta+EtYjnDZ!dXm)J9U)xnE?meuJCy4*Wgcvn;LVeVAkLHW0&^B%;T z`bXr$e$HQDx|u9p3?#mK<*b)!sS_4xzTjv7=cnH5LvfvY)lPqB>Nkg;D}DRO!QsH7 zq0_&?>@t*QzM$#|^8FS4bo6hN<+5bxj-~Q!!`kJF(mgp#(LkcEVQya01XB4>gF>ds zK@F8iBif7LV9mJa3+GH^RfCH$>6@NJ-Ac2PSufWKbcdGzpH;?ehb_74r)S4laYo!Y z(&;VRbF<|?N9WBYeb1xhoHE}(d3pM1$L3onnoQf7t<9+p+IL@FiuusKyf^rox6pL@ zx>M`lsBEV?(#V#^z~_ImLl0^9mr*m~azf6{+gOLTF?O1)>3&xIPTE6qU!|7mw#1ZO z{ubnLus?LUXGIllNXG}c&ZI)$y zO4qMRsOF6sTi^ekBsN3JBcl#lX@Ab`RS++#}jzT$o zZ%bO;6c;=G+9r#Ev*wy?AlE$hesFyKix-Kq_di~8QNBA~bUic@OolS4CKK_K(UDhw z#1Egl@~1|_P4makedjhNc6f27)_%0OdbHw;Pn)FX#+~0QRk+s1eYBkiinLmT4|`2! zsxRcNzpiuBfwiZnr*z)T%zsz?13?PpHT;hr@W0%lV7UH=$>=tp ziZk81@M};5woPD38QjQ&vG?)X(`Q64<9Aj<6lrTya{A|i@6q-}SF$nnlYDH4 zG=t_Hh^0|rYBS=@4Q=JbgGD`Bzol6Yt5l-wh_NgA&Sv2bWE z;40q0&?ToAW%2o9jrVoa?L)&s9iIyY`Pa>(JV$oUe!kQ;dVS5&p^?46KVKH&t7%!D zqhT6fiUz%_tu7CZM%sV5BF?Y2zTr8xf9IFtnbB&S)}gTj$G?Le_7=ZvmA)gMjp~!QI z`sD;Z*L~X4@A!i+I-f>su%kc4NeZrTwT3^=WuE>`L3t#s!~B<`ypy#xD;6~7_^^p} zg0$L}t>qXtJy=J=P&96a5SZNHT{{CZYyjGJAG4hsSZ>!%x#f|{G1nGqgAnP>dU`yr ze6ghR(?%iESI|uYpCL89Q;=@zB1Dn|u{Jrho-Ci@yqT@6z@%VYeoiBU`58J%$~SAi zlFU04eIRsy8Gh$<+3$;dc}uo4d01;9F|h4>AOnh?C+Jzz zTZvT+l|v-DGDV16;km&6Vzlx$>DTP$Wh8Bj&(`svx4V(<9zT+j1C|XC1Wu|s(-MZQ zOGMX#DGUv4HG|2XlX0JUJ|zXIM(uK;3*}f4+_zb0CDWucq7Tu#^K0o40m#Q3{QU^U z4poVt*MZN79+5San??sHD*o| zf-`H>)q*2cRNfb)Lfj)b+F5Iy?q*G&OGoK*$ESibYezaGl}H-eFIZsPjRzQUT{K6Q zGwl;B(_u7`=1NUEQUO380V8gNN2+a83O*`(R>gezi?fa3wViw5sM$#_j8&hnwK_#r z<#X3Gm7^?a<&O;MT;+<;j5lZLFb6i+#Yn-R)Q(o+@a{S>K`=SSRY8{!w56wGg%CMk2FmMq1e`oSYkNsBe z6e-YG&b2++I7>UpH~YxNR0NviZ09OU)k2>{V#c|I1O~YI4Q(O(Y&MSN!#tW`Drk>x z>!LZR^50aAIgeCGKIQE8UKUEwDsl-V!4&_3JnWw-guqfJc2$A`g>$WTj&aIhMZ@kg zfQGI~l@|z+F3c1T7zf0&ogri`5fZeK+}u|<07|xHSR2L}!#dzIv1>oR>QrRck)cch3<80TVa z=*h2t!n#^PIyK*5W_i#!cJPA3!rm~j$ecQEHpCU%LR zTf)Z)1bYO0;;UxdiV&&E1tRE#R~eXDfKZ(Q92F3uc6bRuSaWli*=A&k6wAoQR8Ww* zTp&b3U<6~pOlQ#SU@fc=gUXz;3L|;$*Gc( z`~dWO8Ujs+lo?}{#2^43^;v>&ViHRPxIzHaO~HaO8bWyd9u2XBSM1J=Uwat{5)wsH z>;jWeAt97V0E_^$D#czB;FqMhE3#vmbq3fP8bQRu@WIX)j~PqBb})(I{L?b--r4Mv z9-n|hK};5aTVi5d40dUdU|9l850g;C#S{yIF`TeL@DGZK*C~+Z8NdY~F3|9~6#P31 z@)?3POD9YMxH2w2f(GmrU*_?#?^rk!Qph5!j zD8vjV%Z)^MEGXP_jOVR-!8ccd(Z|*a4giCq^eb=_9S9c_Q@MaX2QUW+wUX_ST#C<4 z9FmKj<3SG(!qF7$5*KmpX$lXVK)OS*0?dj4L!sxn86mZ603-?a&~S$Xtr$xO!i0%v z84cD&B5b0c+;fcmp*8AUF!3M(NGrGv2zkQf(0G}F!W!sM%_q_M{YVNJH`0L)@C4aF=-@#SJj6>HejqqolLI)=2qi3lKre?< zAqXjANm4F%v~ZSvP+AD@sDU8C;fI9aB-n$Gk4JDZQ()%G-FBRfySW{Z@j*&IBJsC{ z9H+d82SZ9KdnkScDQt>M2qA5?0eN(M>=F}!kN_nz>0Pu`u7gIncNx|r#aVJ7k%a(} zhWGrw_uBNO^=8-=3R;c=sh|*pSOAiXcn4rm+!Vi#W&_I$>yKSfL$Dr_2pxP}ixjuY z#IkO{!d4=7j$E`m3NYKDMz7)P1gQ}*xY%gi8bLU2e!q7K94&-yGllR;#m8fCQ+$G< zT0<5E_r{cHei{B!fJq#NREPb(e!u%Qy6j1-FF}Y}AmQs`a3HyRue4z86QGz&aN$7aW6H%8oC#}ByqFj-scncT zUt(e#zXJ}q0yzQf1q-MDCW0V<4GM6U6evcDcn_c(?NCcXB$9NM2kcU74ioWlW+bR4 z3EBb5Ev0e|L1MxSDekU} zk9!GV5d5SfUb7slU`=N;LTQ-}R?am;aeXLU$cBs|I*X zV&tzr0S$o%Ioy2Al(1^31U@sAh7ls)(@{Hc4K7S#u>{!k89PbeWA>b&Xun&=b^~D@MBhZF$os(8t#=01bYsI$dZQxA6EsHPHN0IZ`EjV z;uC5lfI0KH%4Jdno&Y*ZjOlHJc}`R^aGgXj1qLkXEec|2@cVNQqeJv0Qu$?21UaS0?=K*k%=0xE_xTDb?47pUArTpK8azVIn07T zgrUQ~Rs-`TO~I_wk50}IL$iVZ?q8QZ0bEIhy8yH;M|?;q`u<8(L5oph;U*;$2CIaY z9RUWN_zvdWPCzb0Ag-kmHgoYJete|T19NGQCBWS52xELhSpEkaXW_&%P)hq_`#tkI zDScT?K!YELz6ovN65M#Tg2Lg^XWf5ufzr*I#u9w3w0d0HzsQ+OVGdq5No%z{!9 zcPNoRa(hcN>^E>U53ffDFu;vmE?~z`wIKoPDf?a6Ll_Rcuef&VcF~#FLlOx(I}$g` zgTq*3*9UfF)}V^8(LI3ZTn(|=Jc`HcdQJTNQslzhic(%?`&P|PRpWo4dJXjqiuOzD8R zBv!MzdzLav{vjuj5Zrn1as|X#4$x+TTBP8nI4H-?(}527Mm~U`1QybWVZ7QRCNWh4 zTFZ)jNUwJpo>V#YQKx+O4n9%D#qentOT;lOCh;K!6(U4UGCL+vb)rmU2?aG{6PW}=thKS~u7t7>;21myTk zAU_lT?*XQQk0#O(?nLzix0i=rkyIS_-l|edc*)1^ z;A1}tQR3k4N8aV)G2{vjA4W$n((uP(gB$?Dl8i}kr>_P{k+H0_gHog~2Y?d@;dFFI zB6vaq+qh5tPNN?3(YP}of4=lRdLKUs5P*4ainWoPb~dK^wq|o^kVcVOyeQiuYBqeV zjkWO7?W_!}rZrEmbBY!B^_G_ZSunPOJYbVI0cZJ(XK>Zz`4;vVal!|q((R| zrMhGbd4`)Gv9}wpzHzpKf(xzv6-~4CXaPmA zF`nqXz5jC#RI{2ECd6P_`yD8##O;H#V+x!>9CU?&y^5eqOHzrRe|*UfyVk4!{d#K_duo%k`P{!j=?M*|KUVjS9{BTSA?DgK ztY_E16X_#mFCYK>c+~0er!Vd=fAG?~e)N4@^Z7&>hDjG5rAlKBDUfey1MMR$XEXR} z*)0!&5H@j8_J8cXYdDmB-}k-GK1*X}j78Ql770lsVk}}TLPAqXk~Aa@sU#t(W*EyX zCWPqF5Rz0wl2wegkSHOdNmfZ3C4|g9$9W#tbzb+gZO^vdZ=N^L^SrU)rLpb%@BjOM zKcDaQ&!#6p{bDnTj9%te8!zj`Vswl0#cgD*dXmGhgaUxeoIoz>V##q~EY&ZG2QWRomMd zzPXvg^ikhpyw}0?O=@O~kH)U*z0M(T((b}eY3?z0IGFJ!{l3j9?Zed$u9a_YJz<{G zIc2=hec(;T^OjS(m#X)9F1^WYfcX-mjU9!R99iu)zB_MKJNg>Fz5SZ$YfxzH0HR$oR6^6q*i0+pp3V7rfp7}ysLH&seJp_cjjrcN#p(D18;MeTTYw* zs@{KX>Fr&?|K2LIsfH3`*qhieXIRQ4C{i1u?lWpXHcpufnd)zA4-&7s_-{`(eie@e88OTP5GV!J*52XEE5 z6dAsIus_=0rO@PXiR-(PBdz|f&uR`o4te+R1pJI!tBGrQ#=Fwfd(ODOt8uNYeD~;l z^cjyylOr_)?;eM?p7H!ubEJOh-IMF^04m(ntx0--6T2tCdsD4jo8drNN_2q0XN&34 zPS=6*%+>(kUA0GhLI$4Rg`cJEF?D~FF;H=T&sqP&weACz1J9mBpA9%=dTe-Lpz?X^ z*>jg_kBu!2Ja2%X3ye1P7?&QbYTt7%=vJ-Al;L3Y>*#aAg{H@6T?cChThE0&t35s+ zGFbZ&em<<#)bmHiVBPed^WpDmJ(ns6Uwn@~A2DfqVs&7!e))fv$^_EkW>ipSh>Nrp z797-35k^CeVljctEoNTmBSTG%huN?l9>Ykf1I-GEvl3EdnEnbGR7RAY-o!%s6*mG~ z?92SbI7~A<1k_AkIAtg7L?8}2KSc=FC0Jx1*9)zeHbo$2OQXGli zdYlZT->W<7E#3u_;5TmaCo;BQ59zc!z=Z`J_I(v{xl=GhM#gpfzRdmI9h^~~voLpb z_xIbc&o5nM!*|oHWQKcVZG-bSy`b3|4fmzQ1Q%@C?dNc0_)TV8aM7+8e$Ju8Z|@>5 z74O;Ye=u{n|Gw>|lEW|jU7ruXdlGZ0^wjP%?t{Yv&)Y6NzVzaZ=koAi10sYIy*t2L zW@M<{Hl+O4ivVAvk@v4-LMjS(pY=a7GCbH8Qu*w~*>j;IBOei=Rjs?v1!azWn6?eA zdH3Q!r82wEhYya7Ew_c%|9Wx$+VaRp0V0eGHxCp<%6#AS4_^gb)+_A?zC^hrL#8$h@ormj#GM;~!+!1@Z`;_^`?7j~r)A>AKRo;f;q+V0BmyZVsI=cC_*&EFp;%|mMjN9RM^uZ;bw53OGw{eB%8 zAzbu?HOY+eW9=fwH#LN{8I3KZ#70bPvAEoMWb8*~d&JbPhRZ#nV?XaAug>hT2!E3~ zws_y}>g?f$@PX%Jzn;WiojYZ5Wq5FG>3RFr`AZE~#+C(R%MHkD{Ai1aahZ=R?RM9G z+-iuJGWz)Yb?mjpLW`@jM?S6&wqIL%*6`o0GOZTZgk9b1({|Ta-!)uYdj9dx_t@*} zlNQ%k2S08sw_o4*)o^`d`J=Gfiwj6`A?jSvfD5(Z!d$p;A1)%8i)0Fy`dpC$F1ms% z+QP;3bFmX#+#**D)`*vC6jyJQFldytX_Rtl+~m_J9o#6xY?KueT?LKue*-R!iv5k7 zCmNL&8R{yaY3_5MYCy3vsr)h?ulme#bygw zix5$@RBy2|XtB0wv2khHv1LE3l_J%8 zK)v;#LF*x#Ru`An!#=I9!L3J_t#0Y9M+;irD_W1Ww0iWn9-nCSTx>l7YokiFd8xN~ z8?>FYY4dSuJLS{n8{Br9*+xrm^DAiculTQ0nTfV@i*4s&?SWG57u4H>4B9W+v_{vMHEJIwA0jEcKxPfV~M(_7@9G-y)jPgV|WL9wXbLg^sh_LKcyyB@; z2Y||QxKlwk`gvO%4>7*y@K~o)qT;D!zkY$9C0T!8#Y7zaf8-J>A#^|&6#q{yf!!E| zlGJw5vr@5?)KL7t&m|~Oh$L{2rKFgA0D14zqE|Vji?bhIKE40?uFReQ>P{aGOY}}; zHk(-BfWeagJC|UYO|uWQX6C>A6k_QV-s1QFavQ|?8lAbH{&OSQDZ{Vz8~c1 zqw)AwS4?8awxK7U%^Oj1VP|aOPRea;>bSMwT@kYN^yt5G2`anDyG`6%8?qF-&-GFb zV9|KAQK?Q<_*5KHE#xdZPsJMri|*936!ym@KyP&#Tap=(Q&HNQEptu>qGPgpkO@kf z$9Vo&tYd(HC3j#ky8g`zPuo>4sd1jDy#Ca=vG_PvhWz#8>jsM%tX?-OGE{yDZ|yHe z<1~xusQ0oi=w&U5q4ik=(5menKjo?dhZu#{FXJ|e8Fp(}iR$2gIBn7zVnvDwB_B9( z1^j~P9hlU%eV1{S!1O15B7{bcw>A%9J_NIx5@EM8XS9fz^J45Y_VA^kK zKW|8ju~~GPM#nxb)DEU*3zabM=i)o!E)=4}PB9WUp$rzfh_!fC&)7np&zN0Z7(tYy zvDkNOi1+H z4^hJ`_D*N5?Ic3N_Ac_p4&Bd+L8JJ5^1W9E61sDb>!R2erUOI!IXUoH$90=mX1TI<{jSj8|{Q@HQYnZhLt#83ZeXe?oQqz)35CnvXTGFzbzk_@qZA>E{NZHef=@?1{#3ClR;Lhf{B{7ho1HB>Aznd!b zlqd?h7b)IkoN0tCkFGJwN|X!L!Cc@%5G}lJ-GN6IUZ79$Az=p=i4`THZV%`bEkLn~ zJUlNDgb+VrH@oF+_O@pjp)b%+2$Sl`nz6W43T~S^6=_JMgJ>T7(g(<)r`y_zAC~Ex zE7%au&{5Erf8$iT=F#G=JX~m%r1?v)%|UoTK`^Wr%d;F;crnaH3+of5WvRGXO>2G@ z8#lfi2}cjX3`2;qVSE+%Fdlve(v$-vqKWj5(sxmPg(`KoFhnXu{M%L}2UVGHAMu zQ7|$3qcIm^Lt^R#l!;zYSA}fP+H8hn05KEyAt&70RS>M`OTh=N*#3+^VfMmYLYi8% zqSY>H8N}Y!8O$G&gB#$Zs5;H@6qqNpxC&_|F+qx;#BQSW;T&Bo6;Fh{N9ht8z83a;oy$r9W30$8n(lkaTW(>uVhZ}HJS`NJQ z>ju(Xi!F_GF3`PZRMYS2oRSY5#Gao6r7LA)RVgd*kPnamFOj!9uPvlFg*BsmRT&`f zNbkwj#rx#HP@ef(F@D8Xphh5hOPyZytpci?lL4?fKMO#U@)FQtI7ggFoEO(hrhKMN ze0~e4K(ZEAC^GzPd+ED6%itQMabCm@kb^K8| zpJ{>$g(3OtjOba}Pav8cO^U$-^3EsGY0qfVCT`HPF8Ps_Rp;%yRAR(+)MT|Z0nqS3 zvNgwLb5KXgK_wQP_9!{jqo%NeCo{Pcjn$D~J7L#VhB5{mior=h(D=wzj7GjK~CIvti z4fzt!MTB{1xBv9xGBX)5#x~ZQ8}aJ73#zfFK7105M(K)z#j%$ zl;3NG?PSEmV4r1>92?^hB0Q|%6Oco*)2iddUnp*tz-B4R@fO}VdZob1HHAg6#QpJF zZkx{+Z%K)D3W$A1fCSNyD)z`U^>r(S(ZCp`1gIq0@v}lBiMi8l?IE&5MgF2DUA96G z2@kg41?vCB$^lJ)j~y!B{%NG}B|TkGXt>7y7~jzE*`LGZ$?GYROtjdb8M1%y>vA zw??Qd-THg?X=|sQH$)DSmo~9Rb>6C*zV9lJ>|EKSDz(Cp^baiDW2z22a5qx?Acr_8 z%RtHZen#0)L1~?~9eWc{#feYB+KQ`MTK19RWW4zT=jzS~2S6je`TV8=`d2%#7c<7z zpqggn<`V8J>&N#bnj|M6IJfvk#e+Gd_jU$vyI)-G)OWfUzymq&@nv_kHL&)n!;+_!kKX&w$=k!zJGARe-R!_^W z*vW}qfN0S%-|(2dJRr-6F}utl&?JS`LAF#_Wd9`^mn>L`W68#+lH$|d;xoeHg)-~xs`xuY@wqGU zY}tf-QbK`SLQz;kaaKY}RYK`d!sC?$j_i$c(v1qY8RNbf>x>3J!gDacZ zL`rONOKb~E?8r*&tV--2O6*xl?3GP=LrUs*OBx7E8p=u6yD4FOQ|jnV>B~1|Z{L)!zNz^Brqb`51i4gI<5cydsT!A4HE*YC zSEuT{Pu2aMN|a06X`E(oG|ljG8cA?F&7?Zb?0uT~?=-Spx|MOd&Czt*%jx#F(;ceQ z9p9%r|4ygK-8yJ|%jM`T*UPuuZr^gRzUA@$mgnzVRJjaq;|!mp8NQb@Xty)`t1|-L zXPo<;5qKG|h6h2}OmkA^MZe5_ahWQBWcY1n@ZL;yy4v;2%!u1AumfQ9?3di*;Z$AOjc5LhnSLI_mp zm5WsGg(yqC?{nvW=kn$5{xH6~c=Ybl<-04l@2*zg zU4MUf=P9k` z5#;k#h0~jRzD9VyW_G@IO}@@>zV2#1QU2aelY0j4_YA}Dk+ScZ)Z8;0zGuFAk1Stc zWl~_{USJzuV4q#!P*dPIT;RM~K#?yzXj16nUg#QL=$2jRUQ_5XTSKN<*sG?e{lxaQG^;YVYuk9hKr$4wqjxIdl>e>{`@c(&&8 z-0aYcS2(B~4!V|u8R6j8 zICzCJ3DYvEV`b7;%4BoOW_ zW6wjb2!(FX!)u>Mj6A=#_MEOz6=_<cPAH6^t*r6VY7aJT8`DVU8(Enx*Jwq7-5W;r4~kf(L6ewwS}DJCZ8odTpV-A z9R30dh=jxE(F!U+l)F6jl3bw*2ash!wy~iDrwhZ5z)b;&DGMg#)h0y>!}{PaSx6BU z@?~Jo%;kdj$6%R(a8xfmlMGXIDR7iVbyu3 zyYG^t(3>49iu>-_r~R7^U=h?^Fn!)}@05)-X|jENEm0~#*C^DL3LzUnds}k6tMbvv z^T5LifeVpMHczaz{f3XlzrvtB1lwKgDS7dK!JUd}JezcJ?gh1dxsKK4lU-T*XFQF; zmRP$)ABw#SIF1sr(CO2A!%WsRl*jvr^$M$Q%LTqhG_n`;y|}_TRa(AZ$Iz>ev~4GP z>Z*TE_ihRIte9zz;flT3;HvvBqpgxd%mfq_l^DsLhkWe`IVaI_dbUAZ3pnFuH@CK` z*a^?z4FUmx(4_9s3g!Y(MaSUb5N}E#1QqP2IsmuUEPttzLsrc|j2tiS*m{xE`xX-s zFmAsk*3G*GT7{h%zd>x%{G4b2MhlHC>L@FlFfS`x^fvVc5#?9V##QHg#adSiadXYjR}1TK0^J zG<RhyXWm%Nv_kX>w$y>}%HA{vSJZi3?q7%vmH7x{fD%~-4B3gr`DUjHv&cZZ~%Y;}(Zj}@3ridtsu?dY*In0+|$~rV2&Xspd zxX2?#b?A&N-1d&YVD1U|@bjJ#Z(wX!Y##`BqW_2yx4`F#$YX~n@k*bK`7H%HhG)LN zSebfwKKO2OSzEEGRlk~?JdF*iu=-iRg}sD8$XQeX!AdbBOK6v{pfzn1Wnxkz5jYm4 z=-OIFz>k-j_e)()pN&zCf(4lyfN;#%68Yp&bz+nnD-PKtcC<7QBA27CVu@wa92=o0 zJRWexLJpSv=yy4C_SZXwoBR}{72#8(1?2SdElpZtAw*Pqs+TSvu5#H6BUTWSwmnFOX{H>w@r%clIk!@;NaP6ZgXf4*k`@7kUW7F%uNf{=VTX`oiP}7s z@iFj%N?LyiX~fKLS%{h`+dRMemD7ICZ%FEt-ypf-{T2|8b* zyy5&P0wxb-XWt}|&1Y&l=An;tG)e!>1|;TTPTM!j5A$P4-NG|?N3)WU4IpFk@q$?U z7FGF$ID5x@iGQ&H3-Of1e5w2Pt=jGj32xo_($70ub;B2KP%-yp+wI$SW-lbt9Pj;$ z4X9a23QWAGIBnle0DIg&Cc38>(VExSo$h_>ZHTiLql~|y@ zb?-|D_aCWQ-31y(FJC%`|43tF3N`Kab{@?Be~=Auyl*o2vL~eG=U@E9`)1R7UxyF> z%w6feZ@&Ce@cP>7&$|Ft2);V>M#?X;QBK8HGM&9KCX0Faq+*+`4t)vki}|vzifxTL z`;x;K?-8&M?Cl)hq-HM`XgWP`IMVqhqb4{e_T?DLiddg1-4Bznr$aX^4`mM<G9HG0XI$7C3)qVsX+recIIAaq0Da$&$}AVLCCzG_eg zg)gp3t)^ zg5jmgs#lNB3D4kTt4q(h*vEmf`#y}zFIROqJr2t3`Y>g(T-}@WIQag)(OLK9nxR*Z zL!Nhy&WA78@~}_B+V_q9$X>3Sae5Ly*fq9Pv;2ae^dw?>-^bPA<@%LZPp&O@ecV`G zZUAr`I?|B`Dy(o(&YVb@ZXUvPr4gUZVQzK&gg&;?B-_J@G3x$=yRyIgU%@ zth8u4mn9tO9+$3NX(c9?C7yQtEI+c+M(Qa`4(T9Vb*3es|bAm#1cS zPiUC_eo09#PrvUtseSBsr&~{X#`Eq;-7CMlsJN$D?T%ABbAETzoS$Y7c261B{uaCn zOn!Q2+Hu-s-%0UpCTd#!6weH_o{tU*^?}t?6nXE4iXztJ4>U zW2ddsb}cG)Cv#zzP?>NcNN>4j|bst$BsOow4 zIP}$5&$ZP-F0PUj>on)Bur}1;Tv?v^YR=bm?R{@@WyO7`Z~n*DhKG78E1$pmcJ9jB z2oLwXs@-WmC}-`%jPvuF!B_JkwQHmNNwPRc%H+3&~g3KNG~NJM5f)q~@$oXbSdM zcOL2akx{!oNldBkKJEN7dt`lz^t!qywC88;+WItEtfn{Cc`;w%&y4;4nm3s}i$$h? zzEDzX`tLjcDmnIN*6nr8!1JD8kFWgsN)@XeYIj~L&-pV)+h038*t1kw`{!F=O6`Yf z=jED_Kl5R)YsZ#*mh0F4e5Z@m@sRshniMwpar^7WWnQnenQknwQtBqQ?*H9+Y~x4P z>$)kU*S~wNZ2V*k&)|0ZSKs7pEEey7F?;0o>Ok$rFHXvfxzqdChDSD*s$RdC4}HBh zwzjd%6|3jR?q45Q5Uh0Uum6$xdVR`N@Vhsqe)0bPKeNXKt3$8rm!7}=Gk-;}#uIB0 zthDdn_>m)67oNda2VZY2)e8RbQySK%_X}1>1RE=_8#b0-3pUn-PhnX)ND_7%(h*^F zR2CgwMaK-$aVvDZEJK3CkaA;4hcSem^YT>;#UX~$3WFdUsY;4ecZ<{ri`2}D)UJxu z8H&_hi6jco;G`%6wSi^Let@S^axnxB|buC!0l zvcCT&Nk7FBVl>C&)H7(~@tQ@&;|V&I|2-`Z&^{-Triwo&n=Q?JP9Y<-CRjGoeiJwC zH6Bc)IvReN_=hBQ^_#rq=KEkW!z1L&WF|F6YwDkAvFO26c0lEqshq$zt?4_#1Ac$s z*gTldjad3JeV2~Vo?$bk{b&A7k|r9?&fH_!YJVw6clG~gTD%i7`{h16MtionAj5z5 zL2*&ZY)NV5?Ce8Mn?U<(X~ls5*MF0wbxX5fpKuY|<~S|VXXgHy77f47J?*vK_N}7d z^~|?tL%t8cRelKh`t3O{X4`z#ze&=fhx0Xam0#y;`EA?2*DVhGds_TnzrOVKdjo*f z;d5a!0sKbP)>3}cziw>sb~+0!Qbz(7T4hg{F0?6z&MmYPVs(CWsAv9rTKv(e^L*|{ z7qMOEXZOEIQqpwk&mOboxu37e$nA^0HZo@y`|P(qT72VZ^rBcq(_nhBOH7@>=s)!E z4imJ=`qcdH=#x^i(wky0vWVBi2(H9sJOnb}cf%|ah9>hm z$5r8vyUre;yY||7?OWCK(HMs|Et*EspMd0XMd5&uLqQ*5|{hJ5z+luiQB6Z*XNz@9*6&WNX0&MYj+qZ&;C_P zb9(4L*f~&H^XpMy(nF7FhrycRUys9HJ@j1e9IRjcB@7FfQjzhS zhkKB_f?t5(V>(LJ4CoGg0qTPcI@uoTixweY^tj3flyy{uhr)};>{t-E4Ov5{*JF0V zBodoQg>7*I6obl`q_^)36lUlsd0vdCf&1%#7dFDQl=njVoQDOCG(&7o%2%bl1!vSs9T zKP`(e`m>5JZ-o*E&sR0iz7BFO)qJZ_v7CmA7{)Q@0+}&#j&4lD8AIBI@;j0QyuExy zJOUIaPy*>zW7%lD!OBSa4ZIN>A{-u0MYMt70rR?zkc=dW&w?Bh@B&#L|GDKpz<)S*V z6M>eVg1D><5%bA+GD)cSBrw$Ucg3L-+6I&u(oqA#fQP9@bw(=E%J&c^A^l*2W|oho zCCYL(PxwRUcuR;vA~#m&l&~BgC11DDX_50mj|pm+v0}8DX6z>DMQ%_#6kGiAlva7z zO}d*?TioYl#Hb&W6mCXM+n4<86wNpG&E&*i7PO0T_p;yJ%7k9t5V^4_$`hG>fG8n# z8s8E8)`@7^EqEt={n93;74$CoY1AdKFM1~SKd;`h?bWV{9`A&^5}lc*9)n7f{(fmx zF{cs1@&g_`?>RuWbflfb=c2^cW7DdoXn{p3BPHxc=zQfZuFSAw+41Awmb%XFBfZ)O zadrYD7`TpfsFT5XdeqA*k&f~ni#{8ulaY^lZxhsz^tnfO7lj-ND=d~wGMshPw>z6( zA(} zUtIz;I_4Y(ud2IkRx3|5nqT?MveW%t=6(|o!oBJXFYnV<=f;@an&Vnwd@z>TBHQkC zHlbA4nS!_C1FTk$f!qkk=i2L#&&=TA>LA9RFNa(ei)}CX5S*8O-X63GO!c|ed zVgh*m*)#rY4EDnjPP`!|%2C{y$iR>e(~=TMt`q#`we9>ty6iifs8`~Xdw~Qa&ly&< z{^u+!h)o~%JYWT!;@TQ{3L8v>GDdGs!kC=HOW$w9g#4>N0}(mL}yTe*jVY^ z8%Zo^;LTID(l1^aqfFMq*P7y@J zF&Mf@Ka4Co&%fd4Xf5Lz$W7KHLXRne*oNL1T}L~RjIow3v5&l$+l=(VoRn=Cf@=ry zD)Aj&vi)vtn;ir5HT3i&IyjARDIpgxl@Gy^qfM?+fF+N;a0I_Vt>{3LxII~FoZ1xB zLcqDH^CU+D+jKPP@qT2ev|%&MG?5?xV6tqoSx^^L0&?R7*&1Kc8>6bu29XAh(!)b= zm71~&y6+Ttl(olTLp;%{V;|Ij9=!#1K+mz8dt8jzq{Gp}SOzzrxn^JqIvhw=M$yTx zPpydaoWGEGRarZsupsyX%Eb{X7Z9kxRb-1EU-+ghWpAZ*M_9s5%}3y}8JZy~qK*?( z4=G{Cu0&p3v=*3jw)EbAy?Qr+St4X!q|G81qJ_$FT1=(;my9E~1Dd31K+GWGzQ{L% z4WyzM=QA^|Fhp-95%qvQEhlA~HDk>NRS+;fLB4qfroldd+pfumV}*S=oC^*vHlML5 z*~ZO23pXwZd`h>9k(;+sRM1D$?*+P=GEJ^A;*Y!iJkts}L5wT|q3S%w#g+DW4wQs)q7mF!NAs{M+;TIGI5fW!rWGh@Zmeyb{`9Sun1k$&cSGB@4y%`zw zR*L}fqL1ow!n$|RTA2e42y2$hK_N^rSJbP*|5?<05SQTZh3s@=N=R_;<6Hd%NMIvo zTP(Ez8j*~_+5?iEkT}rCa&v$i!-(QVKR!1OFg4rpcvGZ^rc09Tics3mj`FW-(h%#g zG^i0r!UF@4Tl2Y)4hn7udpbxgkPOo85y*l?g(rX|M4c@fK)Y$1UPE5V&qEq2=F4}i zSe|uRNII7YRh$IcrIdu02TrquRdSmc+jb0*NQZaP+n@$2$y$VF>9@t8P~}R82ILQY zwhuL~5A=Ud0;Kx@hSG2&Q@Qva2B8UKW7&``nZ5b$@40w4Djk}bBrmWhW7%dfsG{3T z5muB5Z~;KZS#3_>0#83!$y|^%9p!Prun-{W6xB<j?7;6*>O&se3C$YR1+@QM zBz&sVa#u{B?lUZAADU|Y;MIhL@Inj!jRNyCf1Bi$4oa5<+TsNZx?8`v%Z}n>P2~4Y zb4&6S!#kQ}>ez6FJ6rlZ0lMt43KGgBO9^O^(4M$NKRQ`5!If!7)nn2+GVAFbkutRN zqzz`Y?d1bp9abJ>cX|}cRx?(hsK~iND}4;{<2@Dm%TISJd3;j|3bE@Boh~0ScmONh z5PI_gHySi{c_&UI#0m>Ugj3+2e7Kc?uCOBDEd|@#3zL7kYf^}gTS6v}*s#UVR!5z| zQem-dw05LkfsqVc^DOiyVA6~Iamql5>HbJ{J#6&PqNendf>|%}5+1gN3q8pdap3Rx zcu`u73QHj3YRG}-Ik>Q*(~|@gj0Z1#29DB2P(t{Q9y-biJ$o8_M?m`*h|cmbHNx&C zP0xg_qUWsDJ}fBGDE{{cjD6TR4qxW4lOp3>Q6XbpOBJo;1QeBTdToH|r6AnNha$K} z`h_&OAk|+bP_@iQBs}m!HW@N4Wj~S!_V6$xML41Ka1u`wQuvca`yHu(uylKE)7Dhq zv)exbBg;TI0cS&mO$H)ybW9IN4NHW7CZHS-DXR7YO^2}!RM9Ttbrkh)xKo}A;`pMC z-0QVuA>yuUJhe-~PD?;OWW!D%xsS}jMcft=5VY)6C z8_735#@?u*QM?uaPreu~gfLr-E$2Ylr)>CDo5l z{U-xqwvk};7YQ^4F-pevv*7YS#j0qG?QDp(^iFmkV4VRK^ny|>Xa^l*!@Vwq%6$Nt z?F7i1H+&fbN?Ndpk~M%c#piwy>x>M6(fU2*#MI+6jZ=H ziK5@=BG39@qjZcr2RVw5hV$TaJh%>k6VmJroak60&V&bha~tGQ(871!SH7rwAmT02 zgM1r0N+|9bS1=_Y+<3PW=m2nFNa4Kv1Xm)f(F^<=cyFvl-<1nsVV179AD@Qb3DB14?8~9?eJXi@E$KxW(PQkoc@ESJuJP+QL0sU67U6{>m=(X8t zU;6K`L{pQp1RZ*k4~q0cJn%3v;@$OMz)?CT<}0=zKN)>6QipI&f_7c!pYD#)0*nT{=3y=M23PS?t z`v?ug1dLfAq)Q9!I)$}5YUAFeEJK0T3Oy^79icodGw>IZN+6p19mepg{yHPE^mN;|wo1Z->r3yPw`d)Oz1KAg7%;pYvB25?Ign76&yTF#w5 z0Rer&8qz=%?cA$UVfr%N<7Gyvyc!vlB|x;;5E%++9;B$k1+D4uLuAK>aARuc z?!Sb zTI|vxLU(b%3n!)Zh)_2xsOe7V`nrKB1#S_j{NU-$-(^rYB8)%vY!ox;qu2adyzHw`>$xpgt9fCc}g_8UhtA@+SZwH zy78#EQJR-(qL;4k1<11H4qVgLFZmD&K+4L_TJ=ZQR~<-JRSy+87>eC>{+>;0w(gLk z8sLam0JyegJ+7Z6#;x#b7q{$k+Ld?}A`Ls7rUL#{g$M!%C+A)kJ!pjF|^m_u{gt>c)LK zm#%)i@=L7Zw&d= zW(nmNWe~XPq+9N!d;O$G?xyBOd~DyOxA~Nh=alcYDO&E7fBjUz*wnd=sX(RaAoJ;9 z&*_kB(_y*O;q}uIW7F3*rs+yEk>)c@&zYEOGjW34nS}b8#Ic#=jTx5GmsImF>7HLQ zu6@bM{gPe(<<8ib+>I}6rP+M**#ghmqHD9oxw9qpv!!FRk2hvHN?*&(zgBpDt-SWN zD)(zm{nxs&uk{;Wxk__Q=5sBcb8Xk=I&$Ya>*u=1=6W{fdX>JtG5^-@`EB6Zx1ro` z!}Z@jjC~v1_{LM3A2*+$@SLBzHb0X)KU+UPH#R@NG0#`}{=@wHqUZOeYu{ILzpvJR zUmyFvvGE;H=7Sb|*a<%3Iv;hHk8a>&KJsw_K3;i2!eT+{#Deto1=+g`@(l}$9~YDa z3k2mKsun-gPyEoh{zLQb5AB8@Iv;=N3Vslkf9@1m{4_Z6)A0IF(%qjX4L{93{xlc- zBr7jkSuEO|ShT&qXn%Lnp<&VS3$H!luf?rhS zC2xx*pA$>I*OzE_m;4)+0zNLC6D$QPF9%sH2cK9DxxO5BcR9RaIpX8;HNi4nc_q?f zg?VBn=K4z9-IaufmBf!L!rU%P`FE1W%nI zd3QgLWI1tb$M5Wg$p>D$?%mY2)!R|_dh5IG_zDYNgW{Td(%L;ed__v%GYk2?zr;T@ z;j?Tr581rKk~7tE@#mVii+K-?l&@ahp(a}|ufT#@3wr-Z8OZtTLq{z(tXWXgGRXLj zfJ@@g&nb64U9h$0LyaMVA7X+D3z#YK&!#-cDgH^I?9)f#rpk^ctJe~DQ%=lwUBQyk z+N7ebX{M7U{MC-=`MQ@E8ex`_QvP*vsyjbBWNbfP&y+hf<(R$e>{!d~L(|T=yRUA* z6hDD2?MU{3Tka81dp_ zb#W$AQIQGAy*=(t`ZiH8wQS;_pamIm4zZ&;Vg0b9`YcY2$>q=plag1>2%qOotU zeDAleqIlVTS&0ODP|~R*j2!)2QLj60|CoJb{89|Q_!&}@#skq6+v1uKnk4n)>#B3} zknJ`qClPAe#_G{{1NP@MZ8z?C8cC5=T8Nie@iu%3>gUBP8W7?lMGeB(3?%tZNe2S2 zJrjw@EdXrhi~b{Vm?+=3<8Dn4Y%rJRU7;T2a8(9YNQgI5DbS^m3Z0g z6{&|&j`oq59YJg|lVLd2C~8o*@@e0N_ASpnF23Glbo|ob@pIat)TuikQVzm*_7Wye zC}dfsI~XuvsV#}cZ$%unAJ~ZRo4}_PitDl)#my8cpCXlQ7C?rI`GP7#8n$i!^9=gC z1!W1%tb7T3gWKMMM`gX-3B0|I_?|?{4i1CmB-QAXrlwAW9B?du3_BtJKHBtL^>k6~ zx!Uh-BU@jEUtv#ti2ICla*Cs)JT zENhjnzC!qn-`>Gdw{(&cXW}inHNl1Aih)*APJ8w?Blgt=QW5)5eO?Gd={x@KL_KJK zd`T}!yjX{!K;B(M2R=F;;h+A3L5*$Igh>aGyW?-TWO=5O0)`kYJEI|TibEXWg)k?S zePT#WEvv+APTi${UWgA1C3qwC( ze}chDkyszd9*KlSs3Yf-wQe5ptDL}4Rvee4QMl+8cDyP9Em2uJwlB-DRQ{d6q%+6; z_qAR+%;(b%k&ZN_7&242z%tl&8|=x@5TGU3``;3Wp!O@K_7K9%V1vFN&-7wgvx>n2 zOoSyy-B00KSXDAA&AcSt+!#NBo10(#et^jzYQ$3-nL-KzPtdfURV|E$mC~SOclnpX zNa5x?3y_2`Yv`D2_H_a^?;X5IPzmWpi25O7zHfygEz@$g7Mf z7TLU5E+R%^DoSy0Dckde0aj-0sv9e+myLF(S>@G})zEWXw5P1qrc^|glK*+bTXOb$ zTaG^KNI!&Bpm4?FInETC$}L^R$nuI)upMz&37_@T|0Qv7@!$8&yv$|p)4Q8FbQUy@ zrG(|~bym3{F@&>>yXX1|dzTw2fTVKbwS_$%CdDunD=L#D=VwpjxfPVN0GK;kRjLD` zjM78uy-LrlhiQB>_kxL-agiB({2BLyLoi|Oiu(#od>}s$Mxf(ZD+f-*Yj^Lb8K_C% zx5^6`kqGKpWVF*(MWX{1NRkNTjEEzc>;k9wFmgiwOX3i!v89hem|}s>zF#~ScS2Ar z)OckAu-iSW5f{XPDi{!gPuSBDikuzB{8P2Yv`E4@jIBR5O*n;m6xl+F+8jKDsBKJB zGq6OxVVy^36@Sq<7anJ1&qZVbu+rl8nCx!@Hrs@;Z#V=LPj5pJ+!~K{@D24mSvETC z@3Dpg;Rj>FNI7pcYTRs6b?aOoN{S^+zp$9BkzWcQ8#cW75L%Nt< ze>5R(dL}v&DQmguB5IrVdb!~N-fe6#_2?->0?MU@{`6WOQ>`fQzIvT%w1CZ3G}nUy z@!pbWp29R&0>#lET&2=3CQ&JR)Rx_VWGJc;UQU*^Cyh&nYUb{|?IvOuXC-ci7lG$e zzdFQOi9L)LIX$6Iw?O%?iZYJizw*@vGNh31Po}Cpn zCpF=FUp$IPv&1-Y7%-)BhMXe=d%_+R)y1EG??*uFrF)6;|AK7=>b^J^pJ+OY2d^6E zA@ahxm^%Psr{gE&qd%6LI>?CPwa(FhBo0O09~>myBrG!&ccYED^Eisof54+7W-{_4 z?$q8~omNM)2=-T}9ij8rLaQyf^XhrM2rGOjQgKlkSB3wueTPbx?n@&X@Kc&!>dMvw zdlqgin|;`ID7ET)44AcJuCV+w0P`OE7VwY6;i5omr<_Woy=oLFfjUHPJDcx_kH&`-yUc0bI$m_ea`p%2N@%Ct@WGpzUOrf-?X{h zV8d$=#K8tHYZ%Wke2<28qHSV-K^zw8G~_2?D^M=E!pz$-3I!-o zSCmV}aVY7^LTq{QqHaNHj1HQ+G#`@^#nT8^ z$Q3g+r{JvhQMWr5Zf5uZ>(4_ajG2I72FHo6^_WRWUb?I(;qSY z&e(WT&G zBHS*V&9!v08%bM6g)#UXH9oU=Wrp537+4DTAj-L_P?UtJRs&;*d`}(o6~OL`%SG8d zmL^Y5w1>nC;g|%$XQHMR44k5kv~Y-aWH zo}E;H5upja90U(c_5akNVv%okMLaik8)&zSiowF`s8LSt!fhQ;MApA9e z$er0ZIvAag$Xw#8ECTL#rOmH_k(q4c()#%T!j8-|&gX5+2Eu0B~ ziTwh@S?GKKDQJeOJ+i#-x~CSiZw4OU%aUE^-Mpl6I4YR4n+k>HgUK9DA`_kg3t-h} zroQKf2`uc6^VTK7^?8V!EuM+J@Q4wvDGzj@BdS!Z{rSu9tUL}EvpTXs4=GDNZqCDS zB7GnzO2qgM1O=GIRXi+;a~w4J{)~`0Xq`K zQHy)BXe4csJyVV1D<54W0?BLy>d~qxNXH--mab6|GXcv>>j zm)PISBZ4Q&pM1q~bVXhsrEoGajamw_7l$_ofhr<%`EzFsaGerTBZ&~+CkWgJ)D=~z zGUYrJ7(rrrN~;@SF1c%P^O2m44w6S6 z$|Cukc}%7g4<1NN(-4D|&fz#J^DPeatzP)*3f!IyEKXQ4WfM+dG8aB!jY9^$z+X&Q zJwouIyXYKP>C?U^N)_F>jx4&hAoJ_U*&>ol%Lia64^Kna;eV zn!X)K-z4JhN`e{!Fl~FlMv8DDq@ow~DGA}5G}sxVCI%asTEB=gPYmpti)sSN_DsLy z9BeOu=gEI7gdEPojZ|pWa8}8WgzbT54n&R#!V*C>0thb+(U%TMJ%^3HU%agZqJ{88 z3IrM5zLcK6+lN!8cF3QAbkWer@2neGK+#2Ux3#mOqP{sCC?iaz#fjTci`fUQ*%mzR z>Lm7O&qzNWR}BTk_HwF5<+MjZo;^=X-pT|eiD9oSr95fkdE_$vkys{GDt}F%7 zQ!a26hqsWaAqYhASQ<Bx2AhHBKcb|HX6c)EQ8{dx$q<-XjC2{&|z8tY(hr>FUo zk(Tz%c|Jfaf@Amqr7C*7vWDZ7)DeUL(c!G`SeSijTCi9yt^-DLpM;l!*cuFyx*~9d z{e7q0y~mtSOmiJ!--IK`bf9g^8(GGMIM=;A2Oh%G-fNH2QfC4pmjA3X32;GilROYH z35WoqPlPb-a+H!hhB}LH-JcCX6P`s+Eq$GZt(#&+6X44yvJpwp$n*< zci4f(aC;sLMFCM_(4!qLF=nHu(v^i9J$&H4r7Sq%sQh3k&34GiM}EcqdAV^~Ft6jz zm64hgn?VSO1KZ7rAtIs)b{M=+xRnecOBx=&8RP|^+1B?V^j7RW9lrz|bwK!}rWdl)<)AV>f=7^o{{VNvl)1Rm(WnScWEQ-n|cpuU)eYG-z} zGu6Z_11Tu$gMpihK1$|o-JRovG&qba-P~}r{tZ|CDf#oB_seHebkEh;a*64l2@ zreg+nV}{;iMqy*d8^%objG3m7k@LpPE{>Vs9Gl-Zw&2;=!gphfCdVw0;}rFAOVe>H zyK$Md_qa{i_~H%YwtL3y(#P%d#vLw>JKh{$(l+k&Y~13m z_nzyGwk>45W-(yU_ud(~S*86*G z*!OiCzOUc&eM9>9xV-NhFMi*2^ZVwu?^~XIkAL@l>*V)s$jJot$wbr1?RJwpyeD^t zP43z-xqHv#p7hD2yvgK?lY4JY?rWP&c{aKK-Q_({t?M1uHn?pbaHu)^LRux^Kw zRZ5k82IeckZA5^eJ8k`LpV#ve|wn)`x{<0ySPgYpyBF z-ZGU(0Ak+H`fJK-pZvUI;og9p5vk8Kn$9%Y%`|(@w1myv-7wR-XQnNEraf<_D;j0+$-<7*I{#SHq5=*v>cb&Rwu^%&7C2 zd06F^_hZIg`Bocx$~TUiJScM9GdB8u+*B-ZOIKdFX@cByZfTxX{D%p%$EAT61FvlQ zX8yE1^5*tWAHL1+6|QN^UAX!Cg8u4F&nn|TeqT6Hv;AGqmCcijhU)iDj(z$#X(5MC zAypP_nW7BKS~AtGw~kI(zHZMo4Z6Bz+Ujjrq1}$pqtn(S;xpby7sdau`S7?btZM70 zAB#tOD>pp48voPw^FZC6@z0-r+DRo%=_(dmXY9vbcjj4d`#j??G17A}=-Sp<$M2*4 zH+OvbJiBB{I^1^DV%wb4kBJY@s-aKiRZ6`9rPg>HR;ZO$98B zBe^6^YcKgshIt+NY_{VM^0}O)j%MeNNA5MdP_U`a?Bc1tKg>!?G9Aq?oiE&LUUsRh z&iwL~x*z7{6`hXruUzlnJO66!hr0RKZvXf(U)YFQvY_Iw*1iRm9p<+dRNZ&{xuCjx z>5_%lpG59kc%yIAt%WxS_x@a1^D=YEqS`lw`xe!`FT1tq)~C9ki{#f~mss5X*1yl< z&h&>{77epMep-k?1t&@)TrN~^LeH1$*1ej4=njy`|-|_FSmcr zEs-`VxH^5kt9{UEtYdzI)A;=*GN*~|Wv={F}2 zy8L*5xxwYz|BBYXANXivFFDC=#qopmzRuvh`Qw&tk$~9qf^>b*w!Mv){y9>8h z99lJFpwUcjwal%^TJL12^{BLUab-pJ))YgXSL8N_o{Gb}>kakBOWT~sDvlhOF(g9G z+G)y_e6Ev`fy$+JPpitD!zo5ahGreUft9%@>WxgSFLn5DuRK~jV?=g0>kP=PJa)m! z*gWV`XGmq`@vAAu3)Y(5lSTAYp14tOylBUzd(mT+d3R=vDXC^%G0Ii>txhIZM=y1) zv#Kh1kYZwU*6jYqz^cNh^(MAem+r@JuR1w2V`ATI_8>90s_3ngspF$d4|Y{no%)<& z>h#L&VRBDZ@%MUDm+?yv_m5Sbo|`eHLe0f2ty}kOZ-YnV2-Ml9!xB8rkv)R(1vYz9W)#n%OH}hL-{-~g*`hx9kv*kO= z9-SJizUVS*Mo%?=T%vrv)XUjC@MziN^H$d{E#Ge*eAfKQrNHZDp|{OLtID1zaTu`3 zU6`<1M*=oQ%`657VwCBj=Xd5^zib>QitOtQQMM;u-LA%>u9O~8?LAH=O?jhy#Lv!g zsPI*~qXBM002|AIJ5Hq|2-?R8=LDD~Oc6ep4rNmI7RYA}ewYWl@u_1y4Pf8jY75hzieF(bX5moJYT7?#pzMik zoa9?A&0%XY1oF={K^D{mTnlXey(Tzo9Rs=BphWUQ{p+s6Fcpo~nOT-EKJ!aB>19Ks zr56||`y~XEe+egX{zf$hxBxD}$i8WyWBhCe(q)Xw5-5}I75f}@v?&2t5Q0G#m%cRQ z{R(~7Rj2li)n#GDej5#X1hljV*W#iI#e`QFC6u8a(Qnz!^IT08YUxx7$#bwlPh~-{ z*!YPnoT(DkwF5Xzg_)=>J7G^k9@3@q10M=Ig6}LM7yDg3E8$ef!w^drffii=_GYn&4l;$v@Tv@10)pdrj~c z*zq@1;{W0`!K?qNHNhq2XhV;uYP*dV5}z%7RwAV;@#1K-0NoJNAoZTtAPo~3-8N6v z(S!MUQ_p!Z6K!|J=6D@?LCzs9#evPI{OABQ9cCy<2;D_w3Ysy*I6f663pItHWD5dP zsmpba4XPbUlp8RnBHJvJbPkE5F+quvvE4d5g|ycG41OZ@U$`j$ri9TtagekOmYhxc zR|#9C@TpC-j9<=Flw}6QV0}vXYah8YH61hN6SP*)(ve45rWc-@j^Z4$-0>l0gxbha z)!vQKbrjPw@G`b?w3c-rRe5Q_(#3tAj7&mM)pq$40Kx=@Zk#7ezsK|{886*pKmSJg z^RzXuDs_L}_)M)$^6nk{X<-q1C*>iO6Gn{}JNOZY#% z>1uu)Z7A8QdJ?U$Ac0kWHJT+-;}O0BSIgmSDzS%}0|+lqOO;d?$5Em%N@P9@70?*k zgnIm7Hw~#9{5%rl(jt8raV?DxL8-(7Pgh^b7P3$=SB%3puZb6bS~+_4t$OsQ&nGQ5 zkLUi>y0iCwsF3=v8(;sX1ZTCC)^J3>@VI}Kpox(W{md_I@6vM`O)b!DxwbbYTu977 z7zUMLJGwbgj&W#bQ3wAO4~A0}%kj8xT*;WqIVbAhk&pMWJ$dAzP^{S3U$(w)5nwG$153;xgje{X#KU4sAV68vM? z`p$pwEjqSTX}69pr*WrF37@&kIGYYxI-u;qhPo_Jaz|Wt_Rc{OVcYpBDAEEZ4KaU2(z}y%j(!(U80C9lh&~q~kZ7Z$-jHM?_dHQo zc2tXT7$XI(glBf?pp;ggV6D>(UZ8t7J-{y!73beZLu%`AckD7qAT}Y+t;-vC{r5}y z?_lt!iTdwg@IT-O{2dJb4hH{~5E%azg2ARg+pGV*!NAbtpTS^@StIh8mgc!lPkaJ6 zTu?IO&DKfloJEbsn`qsa$L+Tmo%e%H9We) z8N62hzcBm$&ZhsHDJ%zn2ZPNk;NM!iX&RDNB@B9$8;mBSml4qTDWL~evnC`e?DtoH zVErRV!s|*8$b$#mU=*&V``(Sgz5BMTc8mqs*WlUwM!awEp(tPD1$=KSdcu+~DAQeu z^3VLS%~1%=bAqd=Tjv3G6G`L5a|CLKM7WipuS)oLT7I;Sy+MooDCwVJbcpjF=TJC3#ooa;EM>AyvT#C}CPMp?Va=BtFwAsD&0511XjaD*C0%qMnKjrgjd zull$fft<|4^04}=%v22sZcb$K^^e{JORAsGS9f>Jsa22M{s^mfn7Q-pGXhTkEu6o7 zxbpmmqWMU<>kb9s9MMvOtp`YJgz`HZRQvFvm-?@8N38dZ2xE4jx(eJ6i3oKzZYmf4 zfhYJotp3l1Rl$EKte#a1d8fQgUD4@@^KtN!igynyMlbKQF?dR_6HWq3GUjP|uayJt3%F&*ho) z9Kc@pSS>W4s%>YYi`2~zp&%b+h*+IPG06V^K^n!x_iVaWv~i2@D`@8{%0B*om7 z7j0%r9Gi`|_EjZVzB>D=J&&^1)+R@iY2)#`?dQnhr?gEIImk|yaWao8)u_G{l#U^g zftP>u|HYdI%l_#9E4ShAE!f z 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 Q0~t0jaf1#1Cj{yFH [!WARNING] -> **Early support** -> -> A2A support is functional but still evolving. Tool calls, artifacts, and memory features have limited A2A integration. See limitations below. - -## Usage - -```bash -# Start A2A server for an agent -$ docker agent serve a2a ./agent.yaml - -# Specify a custom address -$ docker agent serve a2a ./agent.yaml --listen 127.0.0.1:9000 - -# Use an agent from an OCI registry -$ docker agent serve a2a myorg/agent:tag -``` - -## Flags - -| Flag | Default | Description | -| --------------------------------- | ---------------- | -------------------------------------------------------------------------------------------------------------------- | -| `-l, --listen ` | `127.0.0.1:8082` | Address to listen on. | -| `-a, --agent ` | (first agent) | Name of the agent to expose when the config contains multiple agents. Defaults to the team's first agent. | -| `-s, --session-db ` | `/session.db` | Path to the SQLite session database. | -| `--working-dir ` | current dir | Working directory the agent runs in. | -| `--env-from-file ` | (none) | Load additional environment variables from a `.env` file (repeatable). | -| `--models-gateway ` | (none) | Route all provider traffic through a models gateway URL. | -| `--code-mode-tools` | `false` | Expose tools as a single "code" toolset that accepts a JavaScript snippet to run. | -| `--hook-pre-tool-use ` | (none) | Add a pre-tool-use hook (repeatable). See [Hooks](../../configuration/hooks/index.md). | -| `--hook-post-tool-use ` | (none) | Add a post-tool-use hook (repeatable). | -| `--hook-session-start ` | (none) | Add a session-start hook (repeatable). | -| `--hook-session-end ` | (none) | Add a session-end hook (repeatable). | -| `--hook-on-user-input ` | (none) | Add an on-user-input hook (repeatable). | -| `--hook-stop ` | (none) | Add a stop hook, fired when the model finishes responding (repeatable). | -| `--auth-token ` | (none) | Bearer token required for agent-card and invocation requests. | -| `--cors-origin ` | (none) | Allowed browser origins, comma-separated; empty disables CORS. | -| `--insecure-no-auth` | `false` | Allow an unauthenticated non-loopback listener (unsafe). | -| `--safety ` | `restricted` | Tool safety policy; `autonomous` is permitted only through this explicit CLI flag. | - -## Authentication and network exposure - -Loopback listeners may run without authentication. Non-loopback listeners require -`--auth-token` unless `--insecure-no-auth` explicitly acknowledges the exposure. -Clients must send `Authorization: Bearer ` for both agent-card discovery -and JSON-RPC invocation. Configure browser access with `--cors-origin`; it accepts -comma-separated literal origins or `~`-prefixed regular expressions and permits -credentials only for matching origins. - -```bash -$ docker agent serve a2a ./agent.yaml --auth-token "$A2A_TOKEN" \ - --cors-origin http://localhost:3000 -``` - -## Tool safety and migration - -A2A sessions default to the `restricted` tool safety policy. Precedence is the -`--safety` flag, then agent YAML, then runtime YAML. YAML may select `strict`, -`balanced`, or `restricted`; `safety: autonomous` stops startup and directs the -operator to `--safety autonomous`. That CLI flag is the only deliberate opt-in -to autonomous tool execution. - -Existing deployments should choose an explicit policy before upgrading. Migration -027 labels pre-existing sessions as `run`, so they cannot be resumed through -`/invoke`; clients must start new A2A contexts. An A2A context ID that collides -with another session is rejected without changing that session. - -Downgrading to a binary that predates migration 027 fails because the session -database has a newer schema (`ErrNewerDatabase`). Restore an older database, or -use a binary that includes the migration. Revert changes without removing the -migration catalogue entry. - -## Features - -- **Auto port selection** — Picks an available port if not specified -- **Agent card** — Provides standard A2A agent metadata -- **Full Docker Agent features** — Supports all tools, models, and gateway features -- **Multiple sources** — Load agents from files or OCI registries - -> [!TIP] -> **See also** -> -> For exposing agents via MCP instead, see [MCP Mode](../mcp-mode/index.md). For stdio-based integration, see [ACP](../acp/index.md). For the HTTP API, see [API Server](../api-server/index.md). - -## Current Limitations - -- Tool calls are handled internally, not exposed as separate A2A events -- A2A artifact support not yet integrated -- A2A memory features not yet integrated -- Multi-agent (sub-agent) scenarios need further work diff --git a/_vendor/github.com/docker/docker-agent/docs/features/acp/index.md b/_vendor/github.com/docker/docker-agent/docs/features/acp/index.md deleted file mode 100644 index 52b6dff515ef..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/acp/index.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: "ACP (Agent Client Protocol)" -description: "Expose Docker Agent agents via the Agent Client Protocol for integration with ACP-compatible hosts like VS Code, IDEs, and other developer tools." -keywords: docker agent, ai agents, features, acp (agent client protocol) -linkTitle: "ACP" -weight: 70 -canonical: https://docs.docker.com/ai/docker-agent/features/acp/ -aliases: - - /ai/docker-agent/integrations/acp/ ---- - -_Expose Docker Agent agents via the Agent Client Protocol for integration with ACP-compatible hosts like VS Code, IDEs, and other developer tools._ - -## Overview - -The `docker agent serve acp` command starts an ACP server that communicates over **stdio** (standard input/output). This makes it ideal for integration with editors, IDEs, and other tools that spawn agent processes — the host sends JSON-RPC messages to Docker Agent's stdin and reads responses from stdout. - -ACP is built on the [ACP Go SDK](https://github.com/coder/acp-go-sdk) and provides a standardized way for client applications to interact with AI agents. - -> [!NOTE] -> **ACP vs A2A vs MCP** -> -> **ACP** connects an agent to a *host application* (IDE, CLI tool) via stdio. **A2A** connects *agents to other agents* over HTTP. **MCP** exposes agents as *tools* for other MCP clients. Choose based on your integration target. - -## Usage - -```bash -# Start ACP server on stdio -$ docker agent serve acp ./agent.yaml - -# With a multi-agent team config -$ docker agent serve acp ./team.yaml - -# From an OCI registry -$ docker agent serve acp myorg/agent:tag - -# With a custom session database -$ docker agent serve acp ./agent.yaml --session-db ./my-sessions.db -``` - -## How It Works - -1. The host application spawns `docker agent serve acp agent.yaml` as a child process -2. Communication happens over **stdin/stdout** using the ACP protocol -3. The host sends user messages, Docker Agent processes them through the agent -4. Agent responses, tool calls, and events stream back to the host -5. Sessions are persisted in a SQLite database for continuity - -```bash -# Conceptual flow: -Host Application - └── spawns: docker agent serve acp agent.yaml - ├── stdin ← JSON-RPC requests from host - └── stdout → JSON-RPC responses to host -``` - -## Features - -- **Stdio transport** — No network ports needed; ideal for subprocess integration -- **Session persistence** — SQLite-backed sessions survive process restarts -- **Full agent support** — All Docker Agent features work: tools, multi-agent, model fallbacks -- **Multi-agent configs** — Team configurations with sub-agents work transparently -- **Filesystem operations** — Agents can read/write files relative to the host's working directory - -## CLI Flags - -```bash -docker agent serve acp | [flags] -``` - -| Flag | Default | Description | -| --------------------------------- | ---------------------- | -------------------------------------------------------------------------------------------------------------------- | -| `-s, --session-db ` | `/session.db` | Path to the SQLite session database. | -| `--working-dir ` | current dir | Working directory the agent runs in. | -| `--env-from-file ` | (none) | Load additional environment variables from a `.env` file (repeatable). | -| `--models-gateway ` | (none) | Route all provider traffic through a models gateway URL. | -| `--code-mode-tools` | `false` | Expose tools as a single "code" toolset that accepts a JavaScript snippet to run. | -| `--hook-pre-tool-use ` | (none) | Add a pre-tool-use hook (repeatable). See [Hooks](../../configuration/hooks/index.md). | -| `--hook-post-tool-use ` | (none) | Add a post-tool-use hook (repeatable). | -| `--hook-session-start ` | (none) | Add a session-start hook (repeatable). | -| `--hook-session-end ` | (none) | Add a session-end hook (repeatable). | -| `--hook-on-user-input ` | (none) | Add an on-user-input hook (repeatable). | -| `--hook-stop ` | (none) | Add a stop hook, fired when the model finishes responding (repeatable). | - -## Integration Example - -A host application would spawn Docker Agent as a subprocess and communicate via the ACP protocol: - -```javascript -// Pseudocode for an IDE extension -const child = spawn("docker", ["agent", "serve", "acp", "./agent.yaml"]); - -// Send a message to the agent -child.stdin.write( - JSON.stringify({ - jsonrpc: "2.0", - method: "agent/run", - params: { message: "Explain this code" }, - }), -); - -// Read responses -child.stdout.on("data", (data) => { - const response = JSON.parse(data); - // Handle agent response, tool calls, etc. -}); -``` - -> [!TIP] -> **When to use ACP** -> -> Use ACP when building **IDE integrations**, **editor plugins**, or any tool that wants to embed a Docker Agent agent as a subprocess. For HTTP-based integrations, use the [API Server](../api-server/index.md) instead. - -> [!NOTE] -> **See also** -> -> For HTTP-based agent access, see the [API Server](../api-server/index.md). For agent-to-agent communication, see [A2A Protocol](../a2a/index.md). For exposing agents as MCP tools, see [MCP Mode](../mcp-mode/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/features/api-server/index.md b/_vendor/github.com/docker/docker-agent/docs/features/api-server/index.md deleted file mode 100644 index 2c1bc999702c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/api-server/index.md +++ /dev/null @@ -1,394 +0,0 @@ ---- -title: "API Server" -description: "Expose your agents via an HTTP API for programmatic access, web frontends, and integrations." -keywords: docker agent, ai agents, features, api server -weight: 80 -canonical: https://docs.docker.com/ai/docker-agent/features/api-server/ ---- - -_Expose your agents via an HTTP API for programmatic access, web frontends, and integrations._ - -## Overview - -The `docker agent serve api` command starts an HTTP server that exposes your agents through a REST-style API with Server-Sent Events (SSE) streaming. Use it to build web UIs, integrate with CI/CD pipelines, or connect agents to other services. - -```bash -# Start the API server -$ docker agent serve api agent.yaml - -# Custom listen address -$ docker agent serve api agent.yaml --listen 0.0.0.0:8080 - -# With session persistence -$ docker agent serve api agent.yaml --session-db ./sessions.db - -# Auto-refresh from OCI registry every 10 minutes -$ docker agent serve api myorg/coder --pull-interval 10 -``` - -> [!TIP] -> **When to use API server vs. chat server** -> -> Use the **API server** when you want full control over sessions, agent execution, tool-call confirmations, and streamed runtime events — this is Docker Agent's native protocol. Use the [Chat Server](../chat-server/index.md) when you want to plug Docker Agent into existing OpenAI-compatible tooling (chat UIs, IDE integrations, OpenAI SDK clients) instead. - -## Endpoints - -All endpoints are under the `/api` prefix. - -### Agents - -| Method | Path | Description | -| ------ | ----------------- | --------------------------------- | -| `GET` | `/api/agents` | List all available agents | -| `GET` | `/api/agents/:id` | Get an agent's full configuration | - -Each agent entry in the `GET /api/agents` response contains: - -| Field | Type | Description | -| ------------ | --------------- | --------------------------------------------------------------------------------------------- | -| `name` | string | Agent identifier (config filename without `.yaml`). | -| `description`| string | The root agent's `description` field. | -| `multi` | boolean | `true` when the config defines more than one agent. | -| `commands` | array of string | Sorted list of named command keys defined on the root agent. Omitted when no commands exist. | - -### Sessions - -| Method | Path | Description | -| -------- | ----------------------------------- | ------------------------------------------------------- | -| `GET` | `/api/sessions` | List all sessions | -| `POST` | `/api/sessions` | Create a new session. Accepts an optional `title` field — when set, it is stored and LLM title generation is skipped. | -| `GET` | `/api/sessions/:id` | Get a session by ID (messages, tokens, permissions) | -| `GET` | `/api/sessions/:id/status` | Lightweight runtime state (streaming, title, agent, tokens). Requires an attached runtime. | -| `GET` | `/api/sessions/:id/snapshot` | Full state in one call (stored fields + runtime state + `last_event_seq`) for gapless resync — see [Reconnecting without gaps](#reconnecting-without-gaps). | -| `GET` | `/api/sessions/:id/events` | Live session event stream (SSE) with sequence numbers and replay. Available for a run attached via [`--listen`](#listen), or once a session has raised at least one out-of-band event (e.g. a background job's elicitation, answered via `POST .../elicitation`), which creates a session-scoped event log on demand carrying such out-of-band events — see [Session event stream](#session-event-stream-and-reconnection) for what each kind of log contains. | -| `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/messages` | Append a message directly to a session's history (bypasses the model). Returns `409 Conflict` while the session has an active run (see [Agent Execution](#agent-execution)). | -| `PATCH` | `/api/sessions/:id/messages/:msg_id` | Update an existing message by ID. Returns `409 Conflict` while the session has an active run. | -| `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. Pass the `elicitation_id` from the `elicitation_request` event to target a specific concurrent request; omitted, it resolves the sole pending one. | -| `POST` | `/api/sessions/:id/steer` | Inject messages into a running turn (pre-empts current) | -| `POST` | `/api/sessions/:id/followup` | Enqueue messages to run after the current turn finishes (supports an `Idempotency-Key` — see [Idempotent follow-ups](#idempotent-follow-ups)). | -| `GET` | `/api/sessions/:id/models` | List available models for the session's current agent | - -### Agent Execution - -| Method | Path | Description | -| ------ | ------------------------------------------ | ------------------------------------------------------------------------------------ | -| `POST` | `/api/sessions/:id/agent/:agent` | Run the root agent for a session (SSE stream) | -| `POST` | `/api/sessions/:id/agent/:agent/:name` | Run a specific named agent (SSE stream) | -| `GET` | `/api/agents/:id/:agent_name/tools/count` | Count tools currently available to `:agent_name` (accounts for deferred toolsets). | - -**Path parameters:** - -- **`:agent`** — The agent identifier, which is the **config filename without the `.yaml` extension**. This must match the filename passed to `docker agent serve api`. For example, if you start the server with `docker agent serve api my-assistant.yaml`, the agent identifier is `my-assistant`. When serving a directory of YAML files, each file becomes a separate agent identified by its filename without the extension. -- **`:name`** _(optional)_ — The name of a specific sub-agent defined in a multi-agent configuration. If omitted, the request targets the `root` agent. For example, in a config that defines agents named `root`, `coder`, and `reviewer`, use `/api/sessions/:id/agent/my-config/coder` to run the `coder` sub-agent directly. - -**Examples:** - -```bash -# Single-agent config: my-assistant.yaml -# Start: docker agent serve api my-assistant.yaml -# Run the root agent: -curl -N -X POST http://localhost:8080/api/sessions/$SID/agent/my-assistant \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role": "user", "content": "Hello!"}]}' - -# Multi-agent config: team.yaml (defines agents: root, coder, reviewer) -# Start: docker agent serve api team.yaml -# Run the root agent: -curl -N -X POST http://localhost:8080/api/sessions/$SID/agent/team \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role": "user", "content": "Review this PR"}]}' - -# Run a specific sub-agent (reviewer): -curl -N -X POST http://localhost:8080/api/sessions/$SID/agent/team/reviewer \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role": "user", "content": "Review this PR"}]}' -``` - -### Health - -| Method | Path | Description | -| ------ | ----------- | ----------------------------------------- | -| `GET` | `/api/ping` | Health check — returns `{"status": "ok"}` | - -### OAuth - -| Method | Path | Description | -| ------ | ------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `POST` | `/api/mcp-oauth/callback` | Deliver an OAuth deeplink callback to a pending unmanaged OAuth flow. Success path: `?state=&code=`; authorization-server error path: `?state=&error=&error_description=`. Returns 400 if `state` is missing or neither `code` nor `error` is provided; 404 if no flow is awaiting that `state`. See [Remote MCP OAuth](../remote-mcp/index.md) for details. | - -## Streaming Responses - -The agent execution endpoints (`POST /api/sessions/:id/agent/:agent`) return **Server-Sent Events (SSE)**. The request body is a JSON object with a `messages` array and an optional `model` field. Setting `model` applies a persistent per-agent override on the session before the turn starts (subsequent turns reuse it). An empty or omitted `model` leaves the existing override untouched. (Each event is a JSON object representing a runtime event — remember that `:agent` is the config filename without the `.yaml` extension.): - -```bash -# Send a message and stream the response -# (assuming the server was started with: docker agent serve api my-agent.yaml) -$ curl -N -X POST http://localhost:8080/api/sessions/$SID/agent/my-agent \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role": "user", "content": "Hello!"}]}' - -# Same call, but switch the agent's model for this turn (and persist it): -$ curl -N -X POST http://localhost:8080/api/sessions/$SID/agent/my-agent \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role":"user","content":"Hello!"}],"model":"openai/gpt-4o"}' - -# Response (SSE stream): -data: {"type":"stream_started","session_id":"...","agent":"root"} -data: {"type":"agent_choice","content":"Hello! How","agent":"root"} -data: {"type":"agent_choice","content":" can I help","agent":"root"} -data: {"type":"agent_choice","content":" you today?","agent":"root"} -data: {"type":"stream_stopped","session_id":"...","agent":"root"} -``` - -Event types include: - -- `stream_started` / `stream_stopped` — Agent execution lifecycle -- `agent_choice` — Streamed text content (partial responses) -- `tool_call` — Agent requesting tool execution -- `tool_call_confirmation` — Tool call waiting for user approval -- `tool_call_response` — Tool execution result -- `plan_changed` — A shared plan was created, updated, or deleted through the plan toolset. The payload carries the plan's `scope`, `name`, `action`, and `version` — never its content. Shared plans are deliberately process-global: every active stream served by the same process subscribes to the same shared plan notifier and receives the event regardless of which session performed the mutation, and the payload does not identify the mutating session (read the plan's `author` metadata for collaborative attribution). -- `error` — Error during execution - -## Typical Workflow - -1. **List agents** — `GET /api/agents` to discover available agents -2. **Create session** — `POST /api/sessions` to start a conversation -3. **Send message** — `POST /api/sessions/:id/agent/:agent` with user messages -4. **Stream response** — Read SSE events as the agent processes -5. **Handle confirmations** — If a tool call needs approval, `POST /api/sessions/:id/resume` -6. **Continue** — Send follow-up messages to the same session - -```bash -# 1. List available agents -$ curl http://localhost:8080/api/agents -[{"name":"my-agent","multi":false,"description":"A helpful assistant","commands":["deploy","review"]}] - -# 2. Create a session -$ curl -X POST http://localhost:8080/api/sessions \ - -H "Content-Type: application/json" -d '{}' -{"id":"abc-123","title":"","created_at":"..."} - -# Create a session with a pre-supplied title (skips LLM title generation) -$ curl -X POST http://localhost:8080/api/sessions \ - -H "Content-Type: application/json" -d '{"title":"deploy check"}' -{"id":"def-456","title":"deploy check","created_at":"..."} -# title preserved; LLM title generation skipped - -# 3. Run the agent with a message -$ curl -N -X POST http://localhost:8080/api/sessions/abc-123/agent/my-agent \ - -H "Content-Type: application/json" \ - -d '{"messages":[{"role":"user","content":"What files are in the current directory?"}]}' -``` - -## CLI Flags - -```bash -docker agent serve api | [flags] -``` - -| Flag | Default | Description | -| ------------------ | ---------------- | ------------------------------------------------ | -| `-l, --listen` | `127.0.0.1:8080` | Address to listen on | -| `--auth-token` | (none) | Bearer token required for all API requests. Leave empty to disable authentication (safe when listening on loopback interfaces only). Recommended when `--listen` binds to a network-reachable interface. | -| `--max-request-size ` | `1048576` (1 MiB) | Maximum request body size in bytes. Requests whose body exceeds this limit are rejected with HTTP 413 (Request Entity Too Large) — see [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large) if you hit this. | -| `--session-workingdir-root` | (none — unrestricted) | Confine the `working_dir` accepted by `POST /api/sessions` to this directory: after resolving symlinks, the requested directory must be the root or one of its descendants. By default any clean host directory is accepted — the intended behaviour for local single-user daemons that open arbitrary workspaces — but raw values containing `..` are always rejected. Set a root whenever the API serves callers that must not reach arbitrary host paths (multi-user or network-exposed deployments). | -| `-s, --session-db` | `session.db` | Path to the SQLite session database | -| `--pull-interval` | `0` (disabled) | Auto-pull OCI reference every N minutes | -| `--fake` | (none) | Replay AI responses from cassette file (testing) | -| `--record` | (none) | Record AI API interactions to cassette file. Routes through `--models-gateway` when one is configured. | -| `--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](../remote-mcp/index.md) for details. | - -> [!NOTE] -> **What `--max-request-size` does and doesn't cover** -> -> This is a finite, process-wide cap on one serialized inbound HTTP request body — it isn't a model context-window limit, and raising it doesn't increase what a provider/model accepts or how large a local attachment/prompt file can be. A larger cap also means the server buffers more memory per request from an unauthenticated or malicious client, so weigh that against your deployment's exposure. If a reverse proxy or gateway sits in front of this server, it may enforce its own, lower cap regardless of this flag. See [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large) for full diagnosis. - -> [!TIP] -> **Live profiling (advanced)** -> -> For production diagnostics, set the `CAGENT_PPROF_ADDR` environment variable (or the hidden `--pprof-addr` flag) to a TCP address such as `127.0.0.1:6060`. Docker Agent will start a Go pprof HTTP server at `/debug/pprof/`, which you can query with `go tool pprof`. Use a loopback address — a non-loopback binding logs a security warning. This flag is intentionally hidden from `--help`. - -> [!TIP] -> **Multi-agent configs** -> -> You can point `docker agent serve api` at a directory containing multiple agent YAML files. Each becomes a separate agent accessible via `/api/agents`. Combine with `--pull-interval` to auto-refresh agents from an OCI registry. - -## Session Persistence - -Sessions are stored in a SQLite database (default: `session.db` in the current directory). This means: - -- Sessions survive server restarts -- Multiple server instances can share a database -- Use `--session-db` to specify a custom path - -## Tool Call Approval - -By default, tool calls require approval. In the API workflow: - -1. Agent makes a tool call → server emits a `tool_call_confirmation` event -2. Client reviews and sends `POST /api/sessions/:id/resume` with the decision -3. Execution continues based on approval/denial - -Toggle auto-approve with `POST /api/sessions/:id/tools/toggle` for automated workflows. - -## Driving a running TUI with `--listen` {#listen} - -The same session API can be exposed by an **interactive run** so an external -process can drive it — send follow-up prompts, observe progress, read the -title — without scraping the terminal. Start a normal run and add `--listen`: - -```bash -# Expose this run's control plane on a TCP port... -$ docker agent run agent.yaml --listen 127.0.0.1:8080 - -# ...or on a unix socket (no port to allocate; access is gated by file -# permissions). npipe:// (Windows) and fd:// are also accepted. -$ docker agent run agent.yaml --listen unix:///tmp/my-run.sock -``` - -The run keeps its interactive TUI; the control plane runs alongside it. A -follow-up delivered over HTTP is processed exactly as if it had been typed -into the TUI: it starts a turn even when the agent is idle, generates the -session title on the first turn, and streams the resulting events to both the -terminal and every connected API client. - -```bash -# Send a follow-up to the attached run (SID is the --session id): -$ curl -X POST http://127.0.0.1:8080/api/sessions/$SID/followup \ - -H 'Content-Type: application/json' \ - -d '{"messages":[{"content":"Now add tests"}]}' -``` - -> [!NOTE] -> **Discovering a run** -> -> Each run started with `--listen` writes a discovery record to `/runs/.json` containing its address and session id, so a supervising process can find a live run by session id, pid, or address. - -> [!WARNING] -> **This control plane has a fixed 1 MiB request-body cap and no built-in authentication** -> -> Unlike the standalone `docker agent serve api` process above, an attached run's `--listen` control plane exposes neither `--max-request-size` nor `--auth-token`: every request is capped at a fixed, non-configurable 1 MiB body (returning HTTP 413 above it — see [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large)), and there is no bearer token to require. If you need a configurable cap, built-in bearer auth, or a network-reachable listener, run a standalone `docker agent serve api` deployment instead. Otherwise, keep `--listen` on loopback, a unix socket, or behind an authenticating reverse proxy. - -## Session event stream and reconnection - -`GET /api/sessions/:id/events` is a **Server-Sent Events** stream of the -session's runtime events — `stream_started`, `agent_choice`, `tool_call`, -`session_title`, `token_usage`, `stream_stopped`, and so on. Unlike the -per-request stream returned by the agent-execution endpoint, it is -session-scoped and survives across turns, so a client can watch a session for -its whole lifetime. It is available for a run attached via -[`--listen`](#listen), and — since a session-scoped event log is created on -demand the first time a session raises an out-of-band event, such as an -`elicitation_request` from a background job — for any API-created session -that has produced at least one (see the -[Sessions endpoint table](#sessions) above). The two kinds of log differ in -coverage: a `--listen` run feeds its full runtime event stream into the log, -while an on-demand log for an API-created session carries the session's -out-of-band events — not necessarily all ordinary turn events, which flow on -the per-request SSE stream of the [agent-execution](#agent-execution) -request that runs the turn. - -Each event carries a monotonic **sequence number** in the SSE `id:` field, and -the server buffers recent events. This makes the stream resumable: - -- **Resume after a drop** — reconnect with the standard `Last-Event-ID` header - (sent automatically by browser `EventSource` clients) or a `?since=` - query parameter. Buffered events newer than that point are replayed before - live tailing resumes, so nothing is missed. -- **Gap signal** — if the resume point has already fallen out of the buffer, the - server sends a single `{"type":"gap"}` event (with no id) before the replay. - The client should re-fetch the snapshot to resync, then continue tailing. -- **End of session** — when the session is ended server-side (for example via - `DELETE /api/sessions/:id`) the server sends a terminal - `{"type":"session_exited"}` event and closes the stream; a client that - receives it should stop. A stream that closes **without** `session_exited` is - a dropped connection — including the run process itself exiting — so reconnect - with the last id; if the run is gone the reconnection simply fails. - -### Reconnecting without gaps - -`GET /api/sessions/:id/snapshot` returns the session's full state in one -response — stored fields (messages, tokens, permissions), live runtime state -(`streaming`, current `agent`), and `last_event_seq`: the sequence number of -the most recent event. Pair it with the event stream for an exact, gapless -resync: - -```bash -# 1. Read the full state and the stream position it corresponds to. -$ SEQ=$(curl -s http://127.0.0.1:8080/api/sessions/$SID/snapshot | jq .last_event_seq) - -# 2. Tail everything that happens after that point (replaying anything that -# occurred between the two calls). -$ curl -N "http://127.0.0.1:8080/api/sessions/$SID/events?since=$SEQ" -``` - -This snapshot-then-tail pattern lets a client (or a client that just -restarted) rebuild a session's state and keep it correct without polling. - -### Waiting for readiness - -`GET /api/sessions/:id/status` reports a session's runtime state. Add -`?wait=` (e.g. `?wait=10s`) to block until that specific session's -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 -{ "user_message_index": 1 } -``` - -`user_message_index` is a **0-based ordinal** that counts only user-role messages in the parent's flat, user-visible message list. The targeted user message is **excluded** from the fork so clients can prefill it into their chat input for the user to edit and resubmit. - -**Example:** - -```bash -# Fork a session before the second user message (ordinal 1) -$ curl -X POST http://localhost:8080/api/sessions/$SID/fork \ - -H 'Content-Type: application/json' \ - -d '{"user_message_index": 1}' -# Returns: api.SessionResponse for the new forked session -# New session title: " (fork 1)", "(fork 2)", etc. -``` - -**Validation:** - -- Out-of-range ordinals (negative, or at/past the user-message count) return `400 Bad Request`. -- An ordinal that resolves to a user message 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` -header, making the request safe to retry after a network timeout. A repeat -with a key already seen for the session is acknowledged without delivering the -follow-up again: - -```bash -$ curl -X POST http://127.0.0.1:8080/api/sessions/$SID/followup \ - -H 'Content-Type: application/json' \ - -H 'Idempotency-Key: 7f3a-...' \ - -d '{"messages":[{"content":"Ship it"}]}' -# => {"status":"queued_streaming","duplicate":false} -# A retry with the same key => {"status":"duplicate","duplicate":true} -``` - -The response `status` is `queued_streaming` (a turn is running or starting), -`queued_idle` (delivered to an idle headless session, runs on the next turn), -or `duplicate`. - -> [!NOTE] -> **See also** -> -> For interactive use, see the [Terminal UI](../tui/index.md). For agent-to-agent communication, see [A2A Protocol](../a2a/index.md) and [ACP](../acp/index.md). For MCP integration, see [MCP Mode](../mcp-mode/index.md). For an OpenAI-compatible chat-completions API, see the [Chat Server](../chat-server/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/features/board/index.md b/_vendor/github.com/docker/docker-agent/docs/features/board/index.md deleted file mode 100644 index 176966a7e59c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/board/index.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: "Kanban Board" -description: "Orchestrate multiple agents from a Kanban TUI: each card runs an agent in a tmux session on an isolated git worktree." -keywords: docker agent, ai agents, features, board, kanban, orchestration -linkTitle: "Kanban Board" -weight: 15 -canonical: https://docs.docker.com/ai/docker-agent/features/board/ ---- - -_Board is a Kanban TUI for orchestrating agents. Each card launches an agent -in a tmux session on an isolated git worktree, and moving a card forward -through the pipeline sends the destination column's prompt to its agent._ - -## Launching the board - -```bash -$ docker agent board -``` - -Requirements: `tmux` and `git` must be installed. - -## How it works - -- **Cards run agents.** Creating a card (`n`) launches `docker agent run` in - a dedicated tmux session, working in a fresh git worktree branched from the - project's upstream default branch. The card's title, running/idle status, - and failures are mirrored live from the agent's control plane. -- **Startup phases.** While an agent is coming up its card moves through three - intermediate statuses before reaching **running**: `starting` (tmux session - created, process booting, no worktree yet) → `loading` (worktree present; - agent loading config, models, and tools) → `attaching` (control-plane socket - bound; board waiting for the first snapshot). -- **Columns are a pipeline.** The default pipeline is - Dev → Review → Push → Done, and it's fully customizable: manage columns - from the board (`c`) or in the config file. Moving a card forward (`]`) - sends the destination column's prompt to the card's agent; moving it back - (`[`) sends nothing. -- **Attach anytime.** Press `enter` (or double-click a card) to attach your - terminal to the agent's session and interact with it directly; `ctrl+q` - detaches and returns to the board. -- **Everything is recoverable.** Quitting the board leaves agents running in - tmux; restarting it reattaches to them. If an agent process dies, the board - relaunches it and resumes the same conversation and worktree. An agent that - keeps crashing at startup turns its card red instead of relaunching - forever: attach to it (`enter`) to read the error output, then move the - card forward to relaunch it, or delete it. - -## Key bindings - -| Key | Action | -| ------------- | --------------------------------------------------- | -| `n` | Create a card (project + prompt) | -| `enter` | Attach to the card's agent (`ctrl+q` detaches) | -| `d` | View the card's worktree diff | -| `o` | Open the card's worktree in `$DOCKER_AGENT_BOARD_EDITOR` (`code`) | -| `s` | Open an interactive shell in the card's worktree | -| `[` / `]` | Move the card back / forward | -| `1`-`9` | Move the card to column N | -| `x` | Delete the card, its session, worktree, and branch | -| `p` | Manage projects (add, edit, reorder, remove) | -| `c` | Manage columns (add, edit, reorder, remove) | -| `e` | Edit the selected column's prompt | -| `←↓↑→` `hjkl` | Navigate | -| mouse | Click selects, double-click attaches, drag moves, wheel scrolls | -| `?` | Help | -| `q` | Quit (agents keep running) | - -## Configuration - -Everything is configured in the global config file -(`~/.config/cagent/config.yaml`) or through the TUI itself (`p` for projects, -`c` for columns, `e` for column prompts): - -```yaml -board: - projects: - - name: my-app - path: /Users/me/src/my-app - agent: coder # any agent ref; defaults to the built-in agent - columns: - - id: dev - name: Dev - emoji: 🔨 - - id: review - name: Review - emoji: 🔍 - prompt: Review the local changes and fix any issues you find. - - id: done - name: Done - emoji: ✅ -``` - -Omitting `columns` keeps the default pipeline. Column `id`s identify a -column across renames (cards remember the column they are in by id); when -omitted, the id is derived from the column's name. When a card enters a -column with a `prompt`, that prompt is delivered to the card's agent as its -next message. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/chat-server/index.md b/_vendor/github.com/docker/docker-agent/docs/features/chat-server/index.md deleted file mode 100644 index 6b9957568064..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/chat-server/index.md +++ /dev/null @@ -1,255 +0,0 @@ ---- -title: "Chat Server" -description: "Expose your agents through an OpenAI-compatible Chat Completions API so any tool that already speaks OpenAI can drive a Docker Agent agent." -keywords: docker agent, ai agents, features, chat server -weight: 90 -canonical: https://docs.docker.com/ai/docker-agent/features/chat-server/ ---- - -_Expose your agents through an OpenAI-compatible Chat Completions API so any tool that already speaks OpenAI can drive a Docker Agent agent._ - -## Overview - -The `docker agent serve chat` command starts an HTTP server that exposes one or -more agents through an **OpenAI-compatible Chat Completions API** at -`/v1/chat/completions` and `/v1/models`. Any client that already speaks the -OpenAI protocol — for example -[Open WebUI](https://github.com/open-webui/open-webui), `curl`, the OpenAI -Python SDK, or LangChain — can drive a Docker Agent agent without any custom -integration. - -```bash -# Single agent — exposed as the model `root` -$ docker agent serve chat agent.yaml - -# Multi-agent config — every agent in the team becomes a model -$ docker agent serve chat ./team.yaml - -# Pick a specific agent from a multi-agent config -$ docker agent serve chat ./team.yaml --agent reviewer - -# Run an agent straight from the registry -$ docker agent serve chat myorg/agent:tag --listen 127.0.0.1:9090 - -# Require a Bearer token, sourced from an env var -$ docker agent serve chat agent.yaml --api-key-env CHAT_BEARER_TOKEN -``` - -> [!TIP] -> **When to use chat server vs. API server** -> -> Use the **chat server** when you want to plug Docker Agent into existing OpenAI-compatible tooling (chat UIs, IDE integrations, OpenAI SDK clients). Use the [API server](../api-server/index.md) when you want full control over sessions, agent execution, tool-call confirmations, and streamed runtime events. - -## Endpoints - -The OpenAI-compatible endpoints live under the `/v1` prefix to match the -OpenAI API surface. The OpenAPI specification is served at the top level so it -can be discovered without authentication. - -| Method | Path | Description | -| ------ | ---------------------- | ---------------------------------------------------------------------- | -| `GET` | `/v1/models` | List the agents that this server exposes as models | -| `POST` | `/v1/chat/completions` | Send messages and receive a completion (regular or streaming) | -| `GET` | `/openapi.json` | OpenAPI specification for the chat server | - -The model identifier in `POST /v1/chat/completions` is the **agent name**. -For a single-agent config that's typically `root`; for a multi-agent config, -each named agent becomes its own selectable model. - -## Quick Start - -```bash -# 1. Start the server -$ docker agent serve chat agent.yaml -Listening on 127.0.0.1:8083 -OpenAI-compatible chat completions endpoint: http://127.0.0.1:8083/v1/chat/completions - -# 2. List exposed agents (models) -$ curl http://127.0.0.1:8083/v1/models -{"object":"list","data":[{"id":"root","object":"model","owned_by":"docker-agent"}]} - -# 3. Send a chat request -$ curl http://127.0.0.1:8083/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -d '{ - "model": "root", - "messages": [{"role": "user", "content": "Hello!"}] - }' -``` - -### Streaming - -Set `"stream": true` in the request body to receive a Server-Sent Events -(SSE) stream of OpenAI-format `chat.completion.chunk` deltas: - -```bash -$ curl -N http://127.0.0.1:8083/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -d '{ - "model": "root", - "stream": true, - "messages": [{"role": "user", "content": "Stream a poem"}] - }' -``` - -### Drive it from the OpenAI Python SDK - -Because the wire format is OpenAI-compatible, point any OpenAI client at the -chat server's `base_url` and use the agent name as the model: - -```python -from openai import OpenAI - -client = OpenAI( - base_url="http://127.0.0.1:8083/v1", - api_key="not-needed-when-no-api-key-flag", # required by the SDK, ignored if no auth -) - -resp = client.chat.completions.create( - model="root", - messages=[{"role": "user", "content": "Hello!"}], -) -print(resp.choices[0].message.content) -``` - -## Server-side Conversation Caching - -By default the server is **stateless**: every request must contain the full -message history, exactly like OpenAI's API. Enable server-side caching by -setting `--conversations-max` to a positive value, then send a stable -`X-Conversation-Id` header on each request: - -```bash -$ docker agent serve chat agent.yaml --conversations-max 100 --conversation-ttl 30m -``` - -```bash -$ curl http://127.0.0.1:8083/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -H 'X-Conversation-Id: my-thread-1' \ - -d '{ - "model": "root", - "messages": [{"role": "user", "content": "Remember my name is Alice"}] - }' - -$ curl http://127.0.0.1:8083/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -H 'X-Conversation-Id: my-thread-1' \ - -d '{ - "model": "root", - "messages": [{"role": "user", "content": "What is my name?"}] - }' -``` - -Cached conversations are evicted after `--conversation-ttl` of inactivity, or -when the cache hits `--conversations-max` items (oldest entries are evicted -first). - -### Failure-safe caching - -When a request fails — for example because the model returns an error or the `--request-timeout` expires — the conversation cache is **not updated**. The server clones the cached session before processing each request and only commits the updated session when the turn completes successfully. This means: - -- A failed turn leaves the conversation in the same state it was before the request. -- Clients can safely retry with the same `X-Conversation-Id` after a failure. -- Transient errors do not corrupt the conversation history. - -## Authentication - -The chat server defaults to loopback binding. A non-loopback `--listen` address requires `--api-key`, `--api-key-env`, or the explicit `--insecure-no-auth` override. An environment variable selected by `--api-key-env` must be set and non-empty. - -To require a Bearer -token, pass `--api-key` (literal value) or `--api-key-env` (name of an -environment variable that holds the value): - -```bash -$ docker agent serve chat agent.yaml --api-key-env CHAT_BEARER_TOKEN -``` - -Clients must then send an `Authorization: Bearer ` header on every -request to `/v1/*`. Both `/v1/models` and `/v1/chat/completions` are -protected once a key is set. - -> [!WARNING] -> **Public exposure** -> -> The default listen address is `127.0.0.1:8083`. Non-loopback binding is rejected unless `--api-key`, `--api-key-env`, or `--insecure-no-auth` is supplied. Use the insecure override only behind a trusted authentication boundary. - -## Tool safety - -The chat server resolves its safety policy in this order: `--safety`, agent configuration, runtime configuration, then `restricted`. Cached conversations retain the more restrictive of their prior policy and the server policy, so a continuation cannot regain permissions after the server policy becomes stricter. - -## CORS - -CORS is **disabled by default**. To allow a browser-based client to call the -server, set `--cors-origin` to the exact origin (scheme + host + port) that -should be allowed: - -```bash -$ docker agent serve chat agent.yaml --cors-origin https://my-ui.example.com -``` - -## CLI Flags - -```bash -docker agent serve chat | [flags] -``` - -| Flag | Default | Description | -| ----------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- | -| `-a, --agent ` | (all agents) | Name of the agent to expose. If omitted, every agent in the config is exposed as a separate model. | -| `-l, --listen ` | `127.0.0.1:8083` | Address to listen on. | -| `--cors-origin ` | (none) | Allowed CORS origin (e.g. `https://example.com`). Empty disables CORS. | -| `--api-key ` | (none) | Required Bearer token clients must present (`Authorization: Bearer `). Empty disables auth. | -| `--api-key-env ` | (none) | Read the required API key from this non-empty environment variable. | -| `--insecure-no-auth` | `false` | Permit unauthenticated non-loopback binding. Use only behind a trusted authentication boundary. | -| `--safety ` | `restricted` | Tool safety policy. CLI value overrides agent/runtime configuration. | -| `--max-request-size ` | `1048576` (1 MiB) | Maximum request body size in bytes. Requests whose body exceeds this limit are rejected with HTTP 413 (Request Entity Too Large) — see [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large) if you hit this. | -| `--request-timeout ` | `5m` | Per-request timeout (covers model + tool calls + streaming). | -| `--conversations-max ` | `0` | Cache up to N conversations server-side, keyed by `X-Conversation-Id`. `0` disables — clients must resend history. | -| `--conversation-ttl ` | `30m` | Idle TTL after which a cached conversation is evicted. | -| `--max-idle-runtimes ` | `4` | Maximum number of idle runtimes pooled per agent. `0` disables pooling. | - -All [runtime configuration flags](../cli/index.md#runtime-configuration-flags) -(`--working-dir`, `--env-from-file`, `--models-gateway`, `--hook-*`, …) are -also accepted. - -> [!NOTE] -> **What `--max-request-size` does and doesn't cover** -> -> This is a finite, process-wide cap on one serialized inbound HTTP request body — it isn't a model context-window limit, and raising it doesn't increase what a provider/model accepts or how large a local attachment/prompt file can be. A larger cap also means the server buffers more memory per request from an unauthenticated or malicious client, so weigh that against your deployment's exposure. If a reverse proxy or gateway sits in front of this server, it may enforce its own, lower cap regardless of this flag. See [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large) for full diagnosis. - -## Image Inputs - -Messages can include OpenAI-style `image_url` content parts alongside `text`: - -```json -{"type": "image_url", "image_url": {"url": "data:image/png;base64,..."}} -``` - -A `data:` URL embeds the image bytes directly in the JSON body, so its base64-encoded size counts toward `--max-request-size` above like any other request content. A remote `http(s)://` URL is passed through to the selected model provider rather than fetched by the chat server itself — whether it works depends on that provider and model: some accept a remote URL directly, others only accept `data:` URLs, and a provider/model without image support drops the part. Don't assume a remote image URL will be fetched or rendered universally; verify against the specific provider/model you've configured. - -## Open WebUI Integration - -Open WebUI can talk to any OpenAI-compatible endpoint. To plug Docker Agent -in: - -1. Start the chat server, optionally with auth: - - ```bash - $ docker agent serve chat agent.yaml \ - --listen 127.0.0.1:8083 \ - --cors-origin http://localhost:3000 \ - --api-key-env OPEN_WEBUI_TOKEN - ``` - -2. In Open WebUI, add an OpenAI-compatible connection: - - - **API Base URL:** `http://127.0.0.1:8083/v1` - - **API Key:** the value of `OPEN_WEBUI_TOKEN` - -3. Each agent in your config appears as a selectable model. - -> [!NOTE] -> **See also** -> -> For the Docker Agent–native HTTP API (sessions, tool-call confirmation, runtime events), see the [API Server](../api-server/index.md). For full CLI flag documentation, see the [CLI Reference](../cli/index.md#docker-agent-serve-chat). diff --git a/_vendor/github.com/docker/docker-agent/docs/features/cli/index.md b/_vendor/github.com/docker/docker-agent/docs/features/cli/index.md deleted file mode 100644 index 41db671d409d..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/cli/index.md +++ /dev/null @@ -1,840 +0,0 @@ ---- -title: "CLI Reference" -description: "Complete reference for all Docker Agent command-line commands and flags." -keywords: docker agent, ai agents, features, cli reference -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/features/cli/ -aliases: - - /ai/docker-agent/reference/cli/ ---- - -_Complete reference for all Docker Agent command-line commands and flags._ - -> [!TIP] -> **No config needed** -> -> Running `docker agent run` without a config argument uses `docker-agent.yaml`, `docker-agent.yml`, or `docker-agent.hcl` from the current directory when present. Otherwise, it uses a built-in default agent that is perfect for quick experimentation. - -## Commands - -### `docker agent run` - -Launch the interactive TUI with an agent configuration (`.yaml`, `.yml`, or `.hcl`). - -```bash -$ docker agent run [config] [message...] [flags] -``` - -| Flag | Description | -| --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -| `-a, --agent ` | Run a specific agent from the config | -| `--yolo` | Auto-approve tool calls (unless explicitly denied). Legacy alias for `--safety autonomous`. | -| `--safety ` | Safety mode for tool approval: `strict` (ask for everything), `balanced` (auto-approve safe calls), `restricted` (auto-approve safe calls, deny the rest — fail-closed for unattended runs), or `autonomous` (approve everything). Wins over `--yolo` when both are given. Without the flag, the mode falls back to alias/user-config defaults, then the agent YAML's `agents..safety` / `runtime.safety`; a resumed session keeps its stored mode unless `--safety`/`--yolo` is passed explicitly. See [Safety Modes](../../configuration/permissions/index.md#safety-modes). | -| `--model ` | Override model(s). Use `provider/model` for all agents, or `agent=provider/model` for specific agents. Comma-separate multiple overrides. | -| `--session ` | Resume a previous session. Supports relative refs (`-1` = newest by creation time, `-2` = second-newest, … — creation order, not last-used). An explicit ID that does not exist yet is created with that ID, so a supervisor can own the session ID upfront and reuse it across runs. | -| `-s, --session-db ` | Path to the SQLite session database (default: `/session.db`, so `~/.cagent/session.db` unless `--data-dir` is set) | -| `--session-read-only` | Open the TUI in read-only mode: conversation history is displayed but no new messages can be sent to the LLM. Cannot be used with `--exec`. | -| `--prompt-file ` | Include file contents as additional system context (repeatable) | -| `--attach ` | Attach an image file to the initial message | -| `--dry-run` | Initialize the agent without executing anything (useful for validating a config) | -| `--remote ` | Use a remote runtime at the given address instead of running the agent locally. Mutually exclusive with `--sandbox`, `--worktree`, `--worktree-pr`, `--worktree-base`, `--session`, `--session-db`, `--record`, and `--fake` — a remote runtime owns its own session storage and execution environment, so these local-only concerns don't apply. | -| `--listen ` | Expose this run's control plane over HTTP so an external process can drive the running TUI (send follow-ups, stream events, read the title). Accepts `host:port` or `unix://`, `npipe://`, `fd://`. Hidden from `docker agent run --help` — like `debug`, it's a stable but advanced/automation-oriented flag rather than a day-to-day one. See the [API Server](../api-server/index.md#listen) guide for the full walkthrough. | -| `--session-workingdir-root ` | Confine the `working_dir` of sessions created through the `--listen` control plane to this directory and its descendants (default: no restriction — any clean host directory is accepted, though raw values containing `..` are rejected). Recommended when the control plane is reachable by other users. Hidden from `--help`, like `--listen`. | -| `--lean` | Use a simplified, non-alternate-screen TUI. Unlike the default full-screen TUI, this renders inline in the normal terminal buffer — useful in environments where an alternate screen is unwanted (e.g. inside tmux panes, CI with a tty, or log-friendly pipelines). Like the full TUI, displays an ASCII art banner on startup when the chat is empty. | -| `--app-name ` | Override the application name label shown in the TUI (status bar, window title, "/exit" notifications). | -| `--sidebar` | Control sidebar visibility. Set to `--sidebar=false` to hide the sidebar and disable the Ctrl+B toggle (default: `true`). | -| `--disable-commands ` | Hide and disable specific slash commands in the TUI. Accepts a comma-separated list of command names (leading slash optional, case-insensitive). E.g. `--disable-commands="/cost,/eval,/model"`. | -| `--theme ` | Preselect a TUI theme by name, or `auto` to follow the terminal's light/dark background (overrides the theme from user config; ignored outside the interactive TUI) | -| `--on-event =` | Run a shell command when an event of the given type fires (`*=` matches any event). Repeatable. | -| `--json` | Output results as newline-delimited JSON (use with `--exec`) | -| `--hide-tool-calls` | Hide tool calls in the output | -| `--hide-tool-results` | Hide tool call results in the output | -| `--sandbox` | Run the agent in sandbox mode using `sbx` (see [Sandbox](../../configuration/sandbox/index.md)) | -| `--template ` | Template image for the sandbox (default: `docker/docker-agent-sbx-templates:latest`) | -| `--no-kit` | Disable the [auto-kit](../../configuration/sandbox/index.md#auto-kit): do not stage skills or prompt files into the sandbox | -| `--agent-picker [refs]` | Show a full-screen interactive picker before launching, letting you browse and select an agent. Accepts an optional comma-separated list of agent references to show (defaults to the built-in `default` and `coder` agents plus any agent configs found in `~/.agents`). Arrow keys navigate; `?` toggles the YAML preview panel; `l` (or mouse-click) toggles the **Lean Mode** checkbox to launch in the lean TUI; `b` (or clicking **[ Open Board ]**) opens the Kanban board (`docker agent board`) instead of running an agent; Enter confirms. Not available in `--exec` or non-TTY modes. | -| `-w, --worktree [name]` | Run the agent in a fresh git worktree of the working directory, isolating its changes from your checkout. Optionally name it (`--worktree=my-feature`); otherwise a name is generated. Requires the working directory to be inside a git repository. Every tool (the shell included) runs inside the worktree. Combine with `--working-dir` to branch from another repository, and with `--session` to resume into the same worktree later. Cannot be combined with `--remote` or `--sandbox`. When the session ends, a clean worktree is removed automatically; one with work prompts to keep or remove (never in `--exec`). | -| `--worktree-base ` | Branch the `--worktree` from `` (a branch, tag, commit, or remote-tracking ref like `origin/main`) instead of the current `HEAD`. A remote-tracking ref is fetched first so the worktree starts from the latest remote state. Requires `--worktree`; cannot be combined with `--worktree-pr`, `--remote`, or `--sandbox`. | -| `--worktree-pr ` | Run the agent in a git worktree checked out on an existing GitHub pull request (PR number, `#123`, or PR URL). Continues the PR's branch so commits push back to it. Requires the [GitHub CLI](https://cli.github.com/) (`gh`). Cannot be combined with `--worktree`, `--remote`, or `--sandbox`. | -| `--working-dir ` | Set the working directory for the session (applies to tools and relative paths) | -| `--env-from-file ` | Load environment variables from file (repeatable) | -| `--flavor ` | Enable a config flavor, a YAML patch defined under the config's `flavors` section (repeatable, applied in order). See [Flavors](../../configuration/flavors/index.md). | -| `--code-mode-tools` | Provide a single tool to call other tools via JavaScript (forces code-mode tools globally) | -| `--models-gateway ` | Route model traffic through a gateway. Also reads `DOCKER_AGENT_MODELS_GATEWAY` (legacy `CAGENT_MODELS_GATEWAY`) env var. | -| `--hook-pre-tool-use ` | Add a pre-tool-use hook command (repeatable). See [Hooks](../../configuration/hooks/index.md). | -| `--hook-post-tool-use ` | Add a post-tool-use hook command (repeatable) | -| `--hook-session-start ` | Add a session-start hook command (repeatable) | -| `--hook-session-end ` | Add a session-end hook command (repeatable) | -| `--hook-on-user-input ` | Add an on-user-input hook command (repeatable) | -| `--hook-stop ` | Add a stop hook command, fired when the model finishes responding (repeatable) | -| `--fake ` | Replay AI responses from a cassette file (for testing). Mutually exclusive with `--record`. | -| `--fake-stream [ms]` | When replaying with `--fake`, simulate streaming with a delay between chunks (defaults to 15ms when given without a value). | -| `--record [path]` | Record AI API interactions to a cassette file and generate a TUI e2e test from the session (auto-generates filename if no path given). Routes through `--models-gateway` when one is configured. | -| `-d, --debug` | Enable debug logging | -| `--log-file ` | Custom debug log location | -| `-o, --otel` | Enable OpenTelemetry observability: traces, metrics, and logs. Requires `OTEL_EXPORTER_OTLP_ENDPOINT` to export to a collector. | - -```bash -# Examples -$ docker agent run agent.yaml -$ docker agent run agent.yaml "Fix the bug in auth.go" -$ docker agent run agent.yaml -a developer --yolo -$ docker agent run agent.yaml --model anthropic/claude-sonnet-4-5 -$ docker agent run agent.yaml --model "dev=openai/gpt-4o,reviewer=anthropic/claude-sonnet-4-5" -$ docker agent run agent.yaml --session -1 # resume last session -$ docker agent run agent.yaml --session -1 --session-read-only # review last session without sending messages -$ docker agent run agent.yaml --prompt-file ./context.md # include file as context - -# Add hooks from the command line -$ docker agent run agent.yaml --hook-session-start "./scripts/setup-env.sh" -$ docker agent run agent.yaml --hook-pre-tool-use "./scripts/validate.sh" --hook-post-tool-use "./scripts/log.sh" - -# Queue multiple messages (processed in sequence) -$ docker agent run agent.yaml "question 1" "question 2" "question 3" - -# Customize TUI display -$ docker agent run agent.yaml --app-name "My Project" -$ docker agent run agent.yaml --sidebar=false -$ docker agent run agent.yaml --disable-commands="/cost,/eval,/model" - -# Browse and pick an agent interactively -$ docker agent run --agent-picker -$ docker agent run --agent-picker=myorg/coder,myorg/researcher -``` - -> [!TIP] -> **Lean, inline TUI** -> -> Pass `--lean` to get a lightweight TUI that renders inline in your terminal (no alternate screen). Like the full TUI, it displays an ASCII art banner on startup when the chat is empty, and supports the same slash commands and streaming output, making it handy inside tmux, scripts, or any context where a full-screen takeover is unwanted. - -> [!TIP] -> **Isolate a run in a git worktree** -> -> When the working directory is inside a git repository, `--worktree` creates a fresh [git worktree](https://git-scm.com/docs/git-worktree) and points the session at it, so the agent's edits land on a separate branch and never touch your checkout. Every tool — the shell included — runs inside the worktree. The worktree is stored under `/worktrees/` on a branch named `worktree-`. - -```bash -# Run in an isolated worktree with a generated name (e.g. "focused_turing") -$ docker agent run agent.yaml --worktree -$ docker agent run agent.yaml -w "Refactor the auth package" - -# Give the worktree (and its branch) an explicit name -$ docker agent run agent.yaml --worktree=auth-refactor - -# Branch the worktree from another ref instead of the current HEAD. -# A remote-tracking ref is fetched first, so the worktree starts from the -# latest remote state. -$ docker agent run agent.yaml --worktree=auth-refactor --worktree-base origin/main - -# Resume a worktree run later: the session remembers its worktree, so you -# don't pass --worktree again (which would fail — the worktree already exists). -$ docker agent run agent.yaml --worktree=auth-refactor # first run, creates it -$ docker agent run agent.yaml --session -1 # resumes into the same worktree - -# Check out an existing GitHub pull request to continue it (requires gh) -$ docker agent run agent.yaml --worktree-pr 123 -$ docker agent run agent.yaml --worktree-pr https://github.com/owner/repo/pull/123 -``` - -With `--worktree-pr`, the PR's head branch is checked out tracking its remote (via the [GitHub CLI](https://cli.github.com/)), so commits made during the run push straight back to the pull request. The worktree is stored under `/worktrees/pr-`. - -When the interactive session ends, the worktree is cleaned up based on its state: - -- **Clean** (no uncommitted changes, untracked files, or new commits): the worktree and its branch are removed automatically. -- **Has work** (uncommitted changes, untracked files, or new commits): you're prompted to keep or remove it. Keeping preserves the directory and branch so you can return later; removing discards the worktree, its branch, and all that work. -- **Non-interactive runs** (`--exec`): the worktree is never cleaned up — it's left in place for inspection. - -A worktree is only ever removed if `--worktree` created it for this run; a pre-existing worktree is never touched. - -A kept worktree can be resumed: pass `--session` (a relative ref like `-1`, or the session id) and the run reattaches to the same worktree directory and branch automatically. Don't re-pass `--worktree` on resume — that would try to create a new worktree and fail because it already exists. - -### `docker agent run --exec` - -Run an agent in non-interactive (headless) mode. No TUI — output goes to stdout. - -```bash -$ docker agent run --exec [config] [message...] [flags] -``` - -```bash -# One-shot task -$ docker agent run --exec agent.yaml "Create a Dockerfile for a Python Flask app" - -# With auto-approve -$ docker agent run --exec agent.yaml --yolo "Set up CI/CD pipeline" - -# Multi-turn conversation -$ docker agent run --exec agent.yaml "question 1" "question 2" "question 3" -``` - -### `docker agent new` - -Interactively generate a new agent configuration file. - -```bash -$ docker agent new [flags] - -# Examples -$ docker agent new -$ docker agent new --model openai/gpt-5 -$ docker agent new --model dmr/ai/gemma3-qat:12B --max-iterations 15 -``` - -### `docker agent getting-started` - -Run a short (about 2 minutes), skippable interactive tour inside the chat UI: sending messages, approving tool calls, the command palette (Ctrl+K), slash commands, and how agents are configured. Aliased as `docker agent tour`. Requires an interactive terminal. - -```bash -$ docker agent getting-started -``` - -Replay it anytime with this command, or with the `/getting-started` slash command inside a running TUI session. - -### `docker agent models` - -List models available for use with `--model`. By default only shows models for providers you have credentials for. Aliases: `docker agent models list`, `docker agent models ls`. - -```bash -$ docker agent models [flags] -``` - -| Flag | Default | Description | -| ---------------------- | ------- | ---------------------------------------------------------------------------------- | -| `-p, --provider ` | (none) | Filter models by provider name (e.g. `openai`, `anthropic`, `dmr`, `ollama`, …). | -| `--format ` | `table` | Output format: `table` or `json`. | -| `-a, --all` | `false` | Include models from all providers, not just those you have credentials for. | - -```bash -# Examples -$ docker agent models # only providers you can use -$ docker agent models --all # every provider the catalog knows about -$ docker agent models --provider openai -$ docker agent models --format json | jq -``` - -When a models gateway is configured (`--models-gateway`, `DOCKER_AGENT_MODELS_GATEWAY`, or the user config), the command first queries the gateway's `/v1/models` endpoint. A non-empty response is authoritative for the models routed through the gateway: the listing shows the models the gateway serves (`--provider` filters within it), alongside any custom providers you have configured, which serve their models from their own endpoints rather than through the gateway. If the gateway cannot be queried or serves no usable model (endpoint not implemented, empty list, invalid response, timeout, missing authentication), the command falls back to the providers you have configured directly — provider API keys, provider aliases, and custom providers — plus the model catalog; a failure of one source never prevents the others from being listed. The Docker Desktop token is only sent (and required) when the gateway targets a trusted Docker URL. - -### `docker agent toolsets` - -List the built-in toolset types available for use in an agent configuration. Each type can be referenced under `toolsets:` in an agent YAML file. Use this to discover what's available without leaving the terminal. - -```bash -$ docker agent toolsets [flags] -``` - -| Flag | Default | Description | -| ---------------- | ------- | --------------------------------- | -| `--format ` | `table` | Output format: `table` or `json`. | - -```bash -# Examples -$ docker agent toolsets # human-readable table -$ docker agent toolsets --format json | jq # machine-readable (type, summary, docs URL) -``` - -### `docker agent setup` - -Set up a model interactively. Four paths: - -- **Built-in cloud provider**: pick a provider Docker Agent already knows (Anthropic, OpenAI, Google, Groq, Hugging Face, ...) and connect it. Credentials vary by provider: most take an API key or token, stored in the Docker Agent env file `~/.config/cagent/.env`, while `chatgpt` signs in with your ChatGPT account in the browser. -- **Local model**: check Docker Model Runner and pull a model. No API key needed. -- **Custom OpenAI-compatible endpoint**: register an endpoint that is not built in (vLLM, LiteLLM, a corporate gateway, ...) with its base URL, API format, and API key variable, saved to your [user configuration](../../providers/custom/index.md#global-providers-user-configuration) so its models work everywhere via `--model /`. -- **Claude Code harness**: use a Claude subscription through the official `claude` CLI. The wizard checks that the CLI is installed and logged in, offers to run `claude auth login --claudeai` (only after you confirm), and writes a ready-to-run `claude-code-agent.yaml`. See [Coding Harnesses](../harnesses/index.md). - -Ends with the exact command to start chatting. Secret values are never printed, and Docker Agent never reads or copies the Claude CLI's credentials. - -The wizard is also offered automatically when an interactive run finds no usable model (decline-able; set `DOCKER_AGENT_NO_SETUP=1` to suppress the offer). - -```bash -$ docker agent setup -``` - -### `docker agent doctor` - -Diagnose the model and credential setup. Reports which model providers have credentials and where each credential comes from (shell environment, env file, Docker Desktop, …), whether Docker Model Runner is reachable and which models are pulled, and which model the `auto` selection would pick. Secret values are never printed. Exits with a non-zero status when an issue would prevent an agent from running, which makes it usable in scripts and CI. - -```bash -$ docker agent doctor [agent-file|registry-ref] [flags] -``` - -With an agent file, also lists the environment variables that file requires (model credentials and tool secrets such as `GITHUB_PERSONAL_ACCESS_TOKEN`), whether each one is set, and from which source. When the file declares a [`claude-code` harness](../harnesses/index.md) agent, the doctor additionally checks that the official `claude` CLI is installed and logged in, reporting its version and safe login metadata (auth method, API provider, subscription type — never your email, organization, or tokens); a missing or logged-out CLI is reported as an issue with the `claude auth login --claudeai` remediation. - -| Flag | Default | Description | -| ------------------------ | ------- | -------------------------------------------------------------- | -| `--json` | `false` | Output the full report in JSON format (for scripting). | -| `--env-from-file ` | (none) | Also check variables supplied by an env file. | -| `--models-gateway ` | (none) | Diagnose against a models gateway (credentials come from it). | - -```bash -# Examples -$ docker agent doctor # credential, DMR, and auto-selection state -$ docker agent doctor ./agent.yaml # also check that file's requirements -$ docker agent doctor --json | jq .issues -``` - -### `docker agent serve api` - -Start the HTTP API server for programmatic access. The argument can be a single agent file, a registry reference, or a directory — when given a directory, every `.yaml`/`.yml`/`.hcl` file in it is exposed as a separate entry under `/api/agents`. - -```bash -$ docker agent serve api || [flags] -``` - -| Flag | Default | Description | -| -------------------------- | ------------------ | ---------------------------------------------------------------------------------------------------------- | -| `-l, --listen ` | `127.0.0.1:8080` | Address to listen on. | -| `--auth-token ` | (none) | Bearer token required for all API requests. When set, every request must include `Authorization: Bearer `. Leave empty to disable authentication (safe when listening on loopback interfaces only). | -| `--max-request-size ` | `1048576` (1 MiB) | Maximum request body size. Requests exceeding this limit are rejected with HTTP 413 — see [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large). | -| `--session-workingdir-root ` | (none) | Confine the `working_dir` of sessions created via `POST /api/sessions` to this directory and its descendants (symlinks are resolved before the check). Unrestricted by default — any clean host directory is accepted (raw values containing `..` are rejected), as local single-user daemons rely on. Recommended for multi-user or network-exposed deployments. | -| `-s, --session-db ` | `session.db` | Path to the SQLite session database (relative paths resolve against the working directory). | -| `--pull-interval `| `0` | Periodically re-pull OCI/URL references and refresh the agent definition. `0` disables auto-pull. | -| `--fake ` | (none) | Replay AI responses from a cassette file (for testing). Mutually exclusive with `--record`. | -| `--record [path]` | (none) | Record AI API interactions to a cassette file. Routes through `--models-gateway` when one is configured. | -| `--mcp-oauth-redirect-uri ` | (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](../remote-mcp/index.md) 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 -# Examples -$ docker agent serve api agent.yaml -$ docker agent serve api agent.yaml --listen :8080 -$ docker agent serve api ./agents/ # directory of agent YAML/HCL configs -$ docker agent serve api ociReference --pull-interval 10 # auto-refresh -``` - -See [API Server](../api-server/index.md) for the full HTTP API reference. - -### `docker agent serve mcp` - -Expose agents as MCP tools for use in Claude Desktop, Claude Code, or other MCP clients. Defaults to stdio transport; use `--http` to start a streaming HTTP server instead. - -```bash -$ docker agent serve mcp [flags] -``` - -| Flag | Default | Description | -| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------- | -| `-a, --agent ` | (all agents) | Name of the agent to expose. If omitted, every agent in the config is exposed as a separate tool. | -| `--tool-name ` | (agent name) | Override the MCP tool identifier clients call; only valid when exposing a single agent. | -| `--http` | `false` | Use streaming HTTP transport instead of stdio. | -| `--safety ` | `restricted` | HTTP MCP safety policy; no effect on stdio or `--attach`. | -| `--auth-token ` | (none) | Required Bearer token for HTTP MCP requests. | -| `--insecure-no-auth` | `false` | Permit unauthenticated non-loopback HTTP MCP binding. | -| `-l, --listen ` | `127.0.0.1:8081` | Address to listen on (only used with `--http`). | -| `--mcp-keepalive `| `0` (disabled) | Interval between MCP keep-alive pings (e.g. `30s`). | -| `--attach [target]` | (none) | Attach to a running TUI run by pid, address, or session id; given without a value, selects the most recent run. | - -All [runtime configuration flags](#runtime-configuration-flags) are also accepted. - -```bash -# Examples -$ docker agent serve mcp agent.yaml # stdio transport -$ docker agent serve mcp agent.yaml --http --listen 127.0.0.1:9090 # streaming HTTP -$ docker agent serve mcp agent.yaml --working-dir /path/to/project -$ docker agent serve mcp myorg/coder -``` - -See [MCP Mode](../mcp-mode/index.md) for detailed setup. - -### `docker agent serve a2a` - -Start an A2A (Agent-to-Agent) protocol server. - -```bash -$ docker agent serve a2a [flags] -``` - -| Flag | Default | Description | -| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------ | -| `-a, --agent ` | (team default) | Name of the agent to run. Defaults to the team's first agent if not specified. | -| `-l, --listen ` | `127.0.0.1:8082` | Address to listen on. | -| `-s, --session-db ` | `/session.db` | Path to the SQLite session database. | - -All [runtime configuration flags](#runtime-configuration-flags) are also accepted. - -```bash -# Examples -$ docker agent serve a2a agent.yaml -$ docker agent serve a2a agent.yaml --listen 127.0.0.1:9000 -$ docker agent serve a2a myorg/agent:tag -``` - -### `docker agent serve acp` - -Start an ACP (Agent Client Protocol) server over stdio. This allows external clients to interact with your agents using the ACP protocol. - -```bash -$ docker agent serve acp [flags] -``` - -| Flag | Default | Description | -| ------------------------- | --------------------------- | ------------------------------------------------- | -| `-s, --session-db ` | `/session.db` | Path to the SQLite session database. | - -All [runtime configuration flags](#runtime-configuration-flags) are also accepted. - -```bash -# Examples -$ docker agent serve acp agent.yaml -$ docker agent serve acp ./team.yaml -$ docker agent serve acp myorg/agent:tag -``` - -See [ACP](../acp/index.md) for details on the Agent Client Protocol. - -### `docker agent serve chat` - -Start an HTTP server that exposes one or more agents through an **OpenAI-compatible Chat Completions API** at `/v1/chat/completions` and `/v1/models`. This lets any tool that already speaks the OpenAI protocol — for example [Open WebUI](https://github.com/open-webui/open-webui), `curl`, the OpenAI Python SDK, or LangChain — drive a Docker Agent agent without any custom integration. - -```bash -$ docker agent serve chat [flags] -``` - -| Flag | Default | Description | -| ----------------------------- | ------------------ | ----------------------------------------------------------------------------------------------------------------- | -| `-a, --agent ` | (all agents) | Name of the agent to expose. If omitted, every agent in the config is exposed as a separate model. | -| `-l, --listen ` | `127.0.0.1:8083` | Address to listen on. | -| `--cors-origin ` | (none) | Allowed CORS origin (e.g. `https://example.com`). Empty disables CORS. | -| `--api-key ` | (none) | Required Bearer token clients must present (`Authorization: Bearer `). Empty disables auth. | -| `--api-key-env ` | (none) | Read the required API key from this non-empty environment variable. | -| `--insecure-no-auth` | `false` | Permit unauthenticated non-loopback binding. | -| `--safety ` | `restricted` | Tool safety policy; CLI value overrides agent/runtime configuration. | -| `--max-request-size ` | `1048576` (1 MiB) | Maximum request body size. Requests exceeding this limit are rejected with HTTP 413 — see [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large). | -| `--request-timeout ` | `5m` | Per-request timeout (covers model + tool calls + streaming). | -| `--conversations-max ` | `0` | Cache up to N conversations server-side, keyed by `X-Conversation-Id`. `0` disables — clients must resend history. | -| `--conversation-ttl ` | `30m` | Idle TTL after which a cached conversation is evicted. | -| `--max-idle-runtimes ` | `4` | Maximum number of idle runtimes pooled per agent. `0` disables pooling. | - -```bash -# Examples -$ docker agent serve chat agent.yaml -$ docker agent serve chat ./team.yaml --agent reviewer -$ docker agent serve chat myorg/agent:tag --listen 127.0.0.1:9090 -$ docker agent serve chat agent.yaml --api-key-env CHAT_BEARER_TOKEN - -# Drive it from any OpenAI-compatible client -$ curl http://127.0.0.1:8083/v1/chat/completions \ - -H 'Content-Type: application/json' \ - -d '{"model": "root", "messages": [{"role": "user", "content": "hello"}]}' -``` - -See [Chat Server](../chat-server/index.md) for the full feature reference. - -### `docker agent board` - -Launch a full-screen Kanban TUI for orchestrating multiple agents at once. Each card runs an agent in its own tmux session on an isolated git worktree; moving a card forward through the pipeline (Dev → Review → Push → Done) delivers the destination column's prompt to that card's agent. Projects and column prompts are stored in the global config file (`~/.config/cagent/config.yaml`) and can be managed from the TUI. - -```bash -$ docker agent board -``` - -Takes no arguments or flags. Requires `tmux` and `git` to be installed. - -See [Kanban Board](../board/index.md) for key bindings, configuration, and workflow details. - -### `docker agent share push` / `docker agent share pull` - -Share agents via OCI registries. - -```bash -# Push an agent -$ docker agent share push ./agent.yaml docker.io/username/my-agent:latest - -# Pull an agent -$ docker agent share pull docker.io/username/my-agent:latest - -# Force pull, overwriting the local copy -$ docker agent share pull docker.io/username/my-agent:latest --force -``` - -| Flag | Applies to | Description | -| ---------- | ---------- | ---------------------------------------------------------- | -| `--force` | `pull` | Force pull even if the configuration already exists locally | - -See [Agent Distribution](../../concepts/distribution/index.md) for full registry workflow details. - -### `docker agent sessions diff` - -Compare two recorded sessions and report the first point where the agent behaved -differently — the triage answer when a task that worked yesterday does not work -today. - -```bash -$ docker agent sessions diff [flags] -``` - -```console -$ docker agent sessions diff -1 -2 -Comparing a1b2c3d4 (7 turns) against e5f6a7b8 (9 turns) - -❌ First divergence at turn 3 (after 3 matching turn(s)). - a1b2c3d4 called: - read_file({"path":"pkg/cache/cache.go"}) - e5f6a7b8 called: - search_files_content({"query":"persistToDisk","path":"."}) - -Everything after this point is downstream of the divergence and is not compared. -``` - -Session references accept a full ID, a unique ID prefix, or a relative form such -as `-1` for the most recent run. - -| Flag | Default | Description | -| ----------------------- | ----------------------- | ------------------------------------------------ | -| `-s, --session-db` | `/session.db` | Path to the session database | -| `--json` | `false` | Emit the comparison as JSON | -| `--fail-on-divergence` | `false` | Exit non-zero when the two sessions diverge | - -Comparison is over the sequence of tool calls, not the assistant's prose: model -output is nondeterministic, so two runs of the same task almost always word -things differently while doing the same work. Turns taken by delegated -sub-agents are included in sequence. Reporting stops at the first divergence — -everything after it is downstream of that difference. - -This locates *where* two runs diverged, not *why*. Re-running a session against -a different model while holding the environment fixed is a separate, unbuilt -feature. - -### `docker agent eval` - -Run agent evaluations against a directory of recorded sessions. - -```bash -$ docker agent eval | [|./evals] [flags] -``` - -| Flag | Default | Description | -| ------------------- | ------------------------------------ | -------------------------------------------------------------------------- | -| `-c, --concurrency` | num CPUs | Number of concurrent evaluation runs | -| `--judge-model` | `anthropic/claude-opus-5` | Model for LLM-as-a-judge relevance scoring (format: `provider/model`) | -| `--output ` | `/results` | Directory for results, logs, and session databases | -| `--only ` | (all) | Only run evals with file names matching these patterns (repeatable) | -| `--base-image` | (default) | Custom base image for eval containers | -| `--container-runtime` | `docker` | Container runtime executable for building and running evaluations (e.g. `podman`) | -| `--keep-containers` | `false` | Keep containers after evaluation (don't remove with `--rm`) | -| `-e, --env` | (none) | Environment variables to pass to container (`KEY` or `KEY=VALUE`, repeatable) | -| `--repeat ` | `1` | Number of times to repeat each evaluation (useful for computing baselines) | -| `--baseline ` | (none) | Compare against a previously saved run JSON (`/.json`) and exit non-zero on regression | -| `--regression-tolerance ` | `0` | How far an aggregate quality rate may fall before `--baseline` reports a regression (0–1) | - -All [runtime configuration flags](#runtime-configuration-flags) are also accepted. - -```bash -# Examples -$ docker agent eval agent.yaml # use ./evals -$ docker agent eval agent.yaml ./my-evals # custom directory -$ docker agent eval agent.yaml -c 8 # 8 concurrent evaluations -$ docker agent eval agent.yaml --keep-containers # keep containers for debugging -$ docker agent eval agent.yaml --only "auth*" # only run matching evals -$ docker agent eval agent.yaml --repeat 5 # repeat each eval 5 times -$ docker agent eval agent.yaml --container-runtime podman # use a Docker-compatible runtime such as Podman -``` - -See [Evaluation](../evaluation/index.md) for details on creating eval sessions and interpreting results. - -### `docker agent version` - -Print the version and commit hash for your `docker-agent` install. - -```bash -$ docker agent version -docker agent version v1.54.0 -Commit: 1737035c -``` - -### `docker agent alias` - -Manage agent aliases for quick access. - -```bash -# List aliases -$ docker agent alias ls - -# List aliases as JSON -$ docker agent alias list --json - -# Add an alias -$ docker agent alias add pirate /path/to/pirate.yaml -$ docker agent alias add other ociReference - -# Add an alias with runtime options -$ docker agent alias add yolo-coder myorg/coder --yolo -$ docker agent alias add careful-coder myorg/coder --safety balanced -$ docker agent alias add fast-coder myorg/coder --model openai/gpt-4o-mini -$ docker agent alias add safe-coder myorg/coder --sandbox -$ docker agent alias add turbo myorg/coder --yolo --model anthropic/claude-sonnet-4-5 - -# Use an alias -$ docker agent run pirate -$ docker agent run yolo-coder -``` - -**Alias Options:** Aliases can include runtime options that apply automatically when used: - -- `--yolo` — Auto-approve tool calls (unless explicitly denied) when running the alias. Legacy alias for `--safety autonomous`. -- `--safety ` — Default [safety mode](../../configuration/permissions/index.md#safety-modes) (`strict`, `balanced`, `restricted`, or `autonomous`) when running the alias. Wins over the alias's `yolo` option; both are stored declaratively in the user config (`aliases..safety` / `aliases..yolo`), so you can also edit them there by hand. -- `--model ` — Override the model for the alias -- `--hide-tool-results` — Hide tool call results in the TUI when running the alias -- `--sandbox` — Always run the alias inside a [Docker sandbox](../../configuration/sandbox/index.md) - -Alias safety options are defaults for new sessions: an explicit `--safety`/`--yolo` on the command line wins over them, they win over `settings.safety`/`settings.YOLO` and over anything declared in the agent YAML, and they never change the mode of a resumed session. - -When listing aliases, options are shown in brackets: - -```bash -$ docker agent alias ls -Registered aliases (3): - - fast-coder → myorg/coder [model=openai/gpt-4o-mini] - turbo → myorg/coder [yolo, model=anthropic/claude-sonnet-4-5] - yolo-coder → myorg/coder [yolo] - -Run an alias with: docker agent run -``` - -Pass `--json` to output aliases as a JSON array instead of the formatted table. Each entry includes the alias `name` and its options: - -```bash -$ docker agent alias list --json -[ - { - "name": "fast-coder", - "path": "myorg/coder", - "model": "openai/gpt-4o-mini" - }, - { - "name": "turbo", - "path": "myorg/coder", - "yolo": true, - "model": "anthropic/claude-sonnet-4-5" - }, - { - "name": "yolo-coder", - "path": "myorg/coder", - "yolo": true - } -] -``` - -JSON output is sorted by name and omits false/zero-valued fields. This is useful for scripting and automation. - -> [!TIP] -> **Override alias options** -> -> Command-line flags override alias options. For example, `docker agent run yolo-coder --yolo=false` disables yolo mode even though the alias has it enabled. - -> [!TIP] -> **Set a default agent** -> -> Create a `default` alias to customize what `docker agent` starts with no arguments: -> -> ```console -> $ docker agent alias add default /my/default/agent.yaml -> ``` -> -> Then simply run `docker agent` — it will launch that agent automatically. - -### `docker agent sandbox` - -Manage settings shared by every [`--sandbox`](../../configuration/sandbox/index.md) run — today, the persistent network allowlist that turns a `Blocked by network policy` 403 into a one-line, durable fix: - -```bash -# Allow a host on every subsequent --sandbox run. -$ docker agent sandbox allow api.example.com - -# Or several at once. -$ docker agent sandbox allow api.example.com registry.npmjs.org:443 - -# See what's persisted in ~/.config/cagent/config.yaml. -$ docker agent sandbox list - -# Drop a host you no longer need. -$ docker agent sandbox deny api.example.com -``` - -Entries are unioned with the gateway, the kit-resolved tool install hosts, and any `runtime.network_allowlist` declared by the agent. The launch summary lists every source separately so you can see which holes were punched by which layer. - -### `docker agent plans` - -Manage the plans agents collaborate on, from the host — without starting a session. Two plan systems are covered: - -- **Shared plans** — the named, versioned documents of the [plan toolset](../../tools/plan/index.md). Fully manageable: create, update, set status, export, delete. -- **Session plans** — the single per-session plan of the "draft, review, execute" workflow. Read-only here (`list`, `get`, `export`); they belong to their session and are changed from within it. A mutation aimed at a session plan fails with an `unsupported` error explaining what to do instead. - -```bash -$ docker agent plans [flags] -``` - -| Subcommand | Description | -| ---------- | ----------- | -| `list [--session ]` | List shared plans with scope, name, status, version, updated time, and title. With `--session`, that session's plan is listed first when it exists. Plans that exist but cannot be read are reported as warnings on stderr (in the `warnings` field with `--json`), so they are never mistaken for missing. | -| `get ` | Print a plan. Content goes to stdout and a concise metadata line goes to stderr, so `> file` captures the content alone (use `export` for a byte-exact copy). `get --session ` prints a session's plan; the name is then omitted (`--scope shared\|session` disambiguates explicitly, and `--session` alone implies session scope). | -| `create --file ` | Create a new shared plan with content from `--file` (required — the CLI never prompts; `--file -` reads stdin). Create-only: an existing name fails with a version conflict instead of overwriting. `--title`, `--author`, and `--status` set metadata. | -| `update --file ` | Replace the content of an existing shared plan (never creates). Omitted `--title`/`--author`/`--status` flags preserve the current values; passing them (even empty) overwrites. | -| `status ` | Set a shared plan's free-form status without touching its body (bumps the version). | -| `export --output ` | Write a plan's content, byte-exact, to a file (parents created, atomic write). An existing destination is refused (`invalid_argument`) and left untouched; add `--force` to replace an existing regular file atomically. Works for both scopes: `export --session --output `. | -| `delete ` | Delete a shared plan. A `--force` delete also recovers a corrupt plan. | - -Plan content passed via `--file` (a regular file, or stdin with `--file -`) is capped at 10 MiB — the same limit the plan storage itself enforces — and a directory or non-regular file (device, named pipe) is rejected up front; violations fail with an `invalid_argument` error. - -**Concurrency guard:** every mutation (`update`, `status`, `delete`) requires exactly one of two mutually exclusive flags — the CLI is headless and never prompts: - -- `--expected-version ` — the version you last read (from `get` or `list`; must be ≥ 1). When the plan changed in the meantime the command fails with a version conflict, reports the current version, leaves the plan untouched, and exits with code **3** (all other failures exit with 1). -- `--force` — deliberately write without the optimistic-lock guard (last writer wins). - -`create` takes no guard: it is inherently create-only and conflicts (exit code 3) when the name already exists. - -**JSON output:** every subcommand accepts `--json`. Success documents go to stdout with a top-level `"schema_version": "1"` marker and stable service-model keys (`plans`, `plan`, `export`, `deleted`) whose fields are snake_case (`updated_at`, `session_id`, `bytes_written`; a zero/unknown `updated_at` is omitted); empty plan lists encode as `[]`, and no prose or ANSI is mixed in. Failures print a single JSON object to stderr: - -```json -{"schema_version":"1","error":{"code":"conflict","message":"...","scope":"shared","name":"p","expected_version":1,"current_version":2}} -``` - -with `code` one of `conflict` (including `expected_version` and `current_version`), `not_found`, `invalid_argument`, `unsupported`, `corrupt`, `storage`, or `error`; `scope`, `name`, and `op` are included where the failure carries them. Validation performed before a subcommand runs is covered too: a missing required flag, a violated `--expected-version`/`--force` group rule, and wrong positional arguments are reported as the same JSON object (code `invalid_argument`) whenever `--json` is present. One residual: flags are parsed left-to-right and parsing stops at the first unknown flag or invalid flag value, so such an error is reported as JSON only when `--json` appears before it on the command line; errors raised before a `plans` subcommand is resolved at all (e.g. an unknown subcommand) also remain plain text. - -```bash -# Examples -$ docker agent plans list -$ docker agent plans list --json | jq '.plans[].name' -$ docker agent plans create release --file ./plan.md --title "Release plan" --status draft -$ cat plan.md | docker agent plans create release --file - -$ docker agent plans get release > plan.md # content only; metadata on stderr -$ docker agent plans update release --file ./plan.md --expected-version 1 -$ docker agent plans status release done --expected-version 2 -$ docker agent plans export release --output ./plan.md -$ docker agent plans export release --output ./plan.md --force # replace an existing file -$ docker agent plans delete release --expected-version 3 -$ docker agent plans delete scratch --force -$ docker agent plans get --session # a session's plan -$ docker agent plans export --session --output ./session-plan.md -``` - -Plans live under the data directory (`~/.cagent/plans/` and `~/.cagent/session_plans/` by default), so `--data-dir` selects which store the commands operate on. - -### `docker agent debug` - -Troubleshooting subcommands for inspecting how an agent config resolves and generating diagnostic output — useful when a config isn't behaving the way you expect. `debug` doesn't appear in `docker agent --help` (it's a diagnostic surface, not a day-to-day command), but every subcommand below is stable and fully supported. - -```bash -$ docker agent debug [flags] -``` - -| Subcommand | Description | -| ---------- | ----------- | -| `config ` | Print the fully-resolved, canonical form of an agent's configuration (defaults applied, references resolved). | -| `toolsets ` | List every toolset each agent in the config exposes, with each tool's name and description. | -| `skills ` | List the skills discovered for each agent, marking forked skills. | -| `title ` | Generate a session title for `` using the same title-generation path the TUI uses (including any configured `title_model`), without starting a session. See [Session Titles](../sessions/index.md#session-titles). | -| `auth` | Print parsed Docker authentication info from the token in use (source, subject, issuer, expiry, username/email). Add `--json` for machine-readable output. | -| `oauth list` | List stored MCP OAuth tokens (resource, scope, expiry, redacted access token). Add `--json` for machine-readable output. | -| `oauth remove ` | Remove a stored MCP OAuth token. | -| `oauth login ` | Perform an interactive OAuth login for a remote MCP server declared in the config, by its name or URL. See [Remote MCP Servers](../remote-mcp/index.md). | - -```bash -# Examples -$ docker agent debug config agent.yaml -$ docker agent debug toolsets agent.yaml -$ docker agent debug skills agent.yaml -$ docker agent debug title agent.yaml "How do I configure a fallback model?" -$ docker agent debug auth --json -$ docker agent debug oauth list -$ docker agent debug oauth login agent.yaml github -``` - -> [!WARNING] -> **`debug auth --json` prints the full bearer token** -> -> The text output of `debug auth` truncates the token to a short preview, but `--json` includes the complete, unredacted JWT in its `token` field. Never paste `debug auth --json` output into logs, issue trackers, or bug reports — anyone with that token can act as you against Docker. Use the plain-text output (or redact the `token` field yourself) when sharing diagnostic output. - -The `Source` field says where the token came from: `docker desktop`, or `minted from the stored access token` when it was obtained by exchanging the access token `docker login` stored. See [Docker authentication](../../guides/secrets/index.md#docker-authentication). - -The `config`, `toolsets`, `skills`, and `title` subcommands also accept [runtime configuration flags](#runtime-configuration-flags) (`--working-dir`, `--models-gateway`, …); `title` additionally accepts `--model` to override the model used to resolve the config before generating the title. - -### `docker agent completion` - -Generate a shell completion script for `bash`, `zsh`, `fish`, or `powershell`. - -```bash -$ docker agent completion - -# Examples -# Bash: load for the current session -$ source <(docker agent completion bash) - -# Zsh: install permanently (adjust the path for your $fpath) -$ docker agent completion zsh > "${fpath[1]}/_docker-agent" -``` - -Run `docker agent completion --help` for shell-specific installation instructions. - -### Self-update - -When installed from a standalone GitHub release binary, Docker Agent can opt in to updating itself. It's disabled by default; set `DOCKER_AGENT_AUTO_UPDATE` to a truthy value (`1`, `true`, `yes`, `on`) to enable it for a command or a shell session: - -```bash -$ DOCKER_AGENT_AUTO_UPDATE=1 docker agent run -``` - -When enabled, every command checks the latest GitHub release before running. If a newer release exists, an interactive session asks whether to install it; a non-interactive session (CI, piped input) proceeds automatically. On yes, Docker Agent downloads the asset for your OS/architecture, verifies its checksum, replaces the current binary, and re-executes with the same arguments. The whole mechanism is fail-safe: any failure at any step falls back to running the current binary. Self-update never triggers for `version`, `help`, `--help`/`-h` (including per-subcommand help), `completion`, or the Docker CLI plugin metadata handshake. - -See [Optional Self-Updates](../../getting-started/installation/index.md#optional-self-updates) for the full walkthrough. Docker Desktop and Homebrew installs already manage updates and don't need this. - -## Global Flags - -These flags are available on every `docker agent` command: - -| Flag | Description | -| ------------------------- | -------------------------------------------------------------------------------------- | -| `-d, --debug` | Enable debug logging (default location: `~/.cagent/cagent.debug.log`) | -| `--log-file ` | Custom debug log location (only used with `--debug`) | -| `-o, --otel` | Enable OpenTelemetry observability: traces, metrics, and logs. Requires `OTEL_EXPORTER_OTLP_ENDPOINT` to export to a collector. | -| `--cache-dir ` | Override the cache directory (default: `~/Library/Caches/cagent` on macOS) | -| `--config-dir ` | Override the config directory (default: `~/.config/cagent`). Also reads `DOCKER_AGENT_CONFIG_DIR` (legacy `CAGENT_CONFIG_DIR`) env var. | -| `--data-dir ` | Override the data directory (default: `~/.cagent`; holds `session.db`, worktrees, plans, …) | -| `--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. | - -## 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. - -| Flag | Description | -| ------------------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| `--working-dir ` | Set the working directory for the session (applies to tools and relative paths). | -| `--env-from-file ` | Load environment variables from file (repeatable). | -| `--flavor ` | Enable a config flavor, a YAML patch defined under the config's `flavors` section (repeatable, applied in order). See [Flavors](../../configuration/flavors/index.md). | -| `--code-mode-tools` | Provide a single tool to call other tools via JavaScript (forces code-mode tools globally). | -| `--models-gateway ` | Route model traffic through a gateway. Reads `DOCKER_AGENT_MODELS_GATEWAY` (legacy `CAGENT_MODELS_GATEWAY`) env var. | -| `--hook-pre-tool-use ` | Add a pre-tool-use hook command (repeatable). See [Hooks](../../configuration/hooks/index.md). | -| `--hook-post-tool-use ` | Add a post-tool-use hook command (repeatable). | -| `--hook-session-start ` | Add a session-start hook command (repeatable). | -| `--hook-session-end ` | Add a session-end hook command (repeatable). | -| `--hook-on-user-input ` | Add an on-user-input hook command (repeatable). | -| `--hook-stop ` | Add a stop hook command, fired when the model finishes responding (repeatable). | -| `--mcp-oauth-redirect-uri ` | Public HTTPS URL to advertise as the OAuth `redirect_uri` for MCP servers running in unmanaged OAuth mode. When set, docker-agent drives PKCE and the code exchange in-process instead of expecting the client to. See [Remote MCP](../remote-mcp/index.md) for details. | - -## Agent References - -Commands that accept a config support multiple reference types: - -| Type | Example | -| ------------- | ------------------------------------------- | -| Local file | `./agent.yaml` | -| OCI registry | `docker.io/username/agent:latest` | -| Hub shorthand | `myorg/agent:tag` | -| Alias | `pirate` (after `docker agent alias add`) | -| Default | (no argument) — uses project config or built-in default agent | - -> [!NOTE] -> **Debugging** -> -> Having issues? See [Troubleshooting](../../community/troubleshooting/index.md) for debug mode, log analysis, and common solutions. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/code-mode/index.md b/_vendor/github.com/docker/docker-agent/docs/features/code-mode/index.md deleted file mode 100644 index 80a55978a991..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/code-mode/index.md +++ /dev/null @@ -1,66 +0,0 @@ ---- -title: "Code Mode" -description: "Let an agent write JavaScript that orchestrates several tool calls in one turn instead of calling tools one at a time." -keywords: docker agent, ai agents, features, code mode -weight: 115 -canonical: https://docs.docker.com/ai/docker-agent/features/code-mode/ ---- - -_Let an agent write JavaScript that orchestrates several tool calls in one turn instead of calling tools one at a time._ - -## What Code Mode Is - -By default, a model calls one tool at a time: it emits a tool call, waits for the result, then decides what to call next. For a task that chains many tool calls together — "list every open issue, then for each one fetch its comments, then summarize" — that means one model round-trip per step. - -**Code Mode** replaces the agent's individual tools with a single tool, `run_tools_with_javascript`, that runs a JavaScript script. Every tool the agent would otherwise call directly is exposed to that script as a plain JavaScript function (synchronous — no `await`/`async` needed). The model writes a script that calls as many of them as it needs, combines and filters the results, and returns a single string — all in one tool call. - -## Enabling Code Mode - -Set `code_mode_tools: true` on an agent: - -```yaml -# examples/code_mode.yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Demonstrates the use of Code Mode with tools - instruction: Use your tool to help the user with their github requests. - code_mode_tools: true - commands: - demo: How many issues in docker/docker-agent have a number that is prime? - toolsets: - - type: mcp - ref: docker:github-official -``` - -Every toolset configured on the agent (the GitHub MCP server here) is wrapped: the model no longer sees the individual GitHub tools, only `run_tools_with_javascript`, with each wrapped tool documented as TypeScript interfaces, type aliases, and function declarations inside its description. - -To force Code Mode for every agent in a run regardless of their individual config, use the `--code-mode-tools` CLI flag (or the equivalent `--code-mode-tools` [runtime configuration flag](../cli/index.md#runtime-configuration-flags), accepted by `run`, `run --exec`, `serve api`, `serve mcp`, and the other commands that load an agent): - -```bash -$ docker agent run agent.yaml --code-mode-tools -``` - -## When It Helps - -Code Mode is worth enabling when an agent's task typically needs **many tool calls chained together**, especially with conditional logic or filtering in between — for example, paging through a large result set, cross-referencing several API calls, or reducing a large payload down to the few fields the model actually needs before it ever sees them. Each of those becomes one model turn instead of many, which cuts both latency and token spend on tool-call/response round-trips. - -It is not a general-purpose replacement for direct tool calls: for an agent that mostly makes one or two independent tool calls per turn, Code Mode adds the overhead of writing and reasoning about a script for no real benefit. - -## Limits & Security Notes - -- **One string result.** The script must return a string; use `console.*` inside the script to print debug information if something doesn't behave as expected — it comes back as `stdout`/`stderr` alongside the result. -- **Failures are diagnosable.** If the script throws or returns unexpectedly, the response includes the tool calls it made before failing (name, arguments, and result or error), so the model can see what happened and adjust the script on the next attempt. -- **Not every tool is wrapped.** Tools in the `todo` category are excluded from the script environment and stay directly callable as ordinary tools — Code Mode does not replace them. -- **The script runs in an embedded, sandboxed JS engine** ([goja](https://github.com/dop251/goja)), not Node.js or a browser: there is no filesystem, network, or process access beyond the tool functions injected into it. - -## Interaction With Permissions and Tool Approval - -[Permissions](../../configuration/permissions/index.md) and interactive tool-call approval are enforced when the **runtime dispatches a tool call requested by the model** — which, with Code Mode enabled, is only `run_tools_with_javascript` itself. The individual tool calls a script makes from inside that JavaScript are invoked directly and do **not** go through a second round of permission checks or approval prompts. - -In practice this means enabling `code_mode_tools` collapses the approval granularity from "one prompt per tool call" down to "one prompt for the whole script". Treat that single approval as authorizing everything the script's toolset could do: - -> [!WARNING] -> **Coarser approval granularity** -> -> Approving a `run_tools_with_javascript` call approves every tool it might invoke internally, including ones that would otherwise need a separate `ask` or be blocked by a `deny` pattern under [Permissions](../../configuration/permissions/index.md). If an agent's toolset includes anything destructive, consider whether Code Mode's coarser granularity is acceptable for that agent before enabling it. Delegating to a separate, non-Code-Mode agent isn't a way out either: [handoff](../../tools/handoff/index.md) and [transfer_task](../../tools/transfer-task/index.md) are themselves wrapped like any other tool once `code_mode_tools` is on, but they have no code-mode-compatible handler — the model's script gets `tool "handoff" is not available in code mode` if it tries to call them. This only rules out the model *choosing* to delegate from inside the script: a configured `force_handoff` target on the agent still runs deterministically after the agent's turn naturally stops, regardless of Code Mode, since it's applied by the runtime outside the tool-call dispatch path Code Mode replaces. Keep `code_mode_tools` off any agent whose model needs to hand off or transfer to one that holds a destructive toolset. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/evaluation/index.md b/_vendor/github.com/docker/docker-agent/docs/features/evaluation/index.md deleted file mode 100644 index c90701dec2e4..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/evaluation/index.md +++ /dev/null @@ -1,311 +0,0 @@ ---- -title: "Evaluation" -description: "Measure agent quality with automated evaluations — tool call accuracy, response relevance, output size, and more." -keywords: docker agent, ai agents, features, evaluation -weight: 100 -canonical: https://docs.docker.com/ai/docker-agent/features/evaluation/ -aliases: - - /ai/docker-agent/evals/ ---- - -_Measure agent quality with automated evaluations — tool call accuracy, response relevance, output size, and more._ - -## Overview - -The `docker agent eval` command runs your agent against a set of recorded sessions and scores the results. Each eval session captures a user question, the expected tool calls, and criteria the response must satisfy. Docker Agent replays the question, compares the agent's behavior to expectations, and produces a report. - -> [!NOTE] -> **Container runtime required** -> -> Evaluations run inside containers for isolation. Each eval gets a clean environment with optional setup scripts. A running Docker-compatible container CLI/runtime is required: Docker Desktop or Docker Engine by default, or another Docker-compatible runtime such as Podman selected with `--container-runtime`. - -## Quick Start - -```bash -# Run evaluations for an agent -$ docker agent eval agent.yaml - -# Specify a custom evals directory -$ docker agent eval agent.yaml ./my-evals - -# Run with 8 concurrent evaluations -$ docker agent eval agent.yaml -c 8 - -# Only run evals matching a pattern -$ docker agent eval agent.yaml --only "auth*" - -# Repeat each eval 5 times to compute a baseline -$ docker agent eval agent.yaml --repeat 5 - -# Repeat a specific eval 5 times -$ docker agent eval agent.yaml --only "auth*" --repeat 5 - -# Use a Docker-compatible runtime such as Podman -$ docker agent eval agent.yaml --container-runtime podman -``` - -## Eval Directory Structure - -By default, Docker Agent looks for eval sessions in an `evals/` directory next to your agent config: - -```bash -my-agent/ -├── agent.yaml -└── evals/ - ├── 41b179a2-....json # Eval session 1 - ├── 5d83e247-....json # Eval session 2 - └── results/ # Output (auto-created) - ├── adjective-noun-1234.json - ├── adjective-noun-1234.log - ├── adjective-noun-1234.db - └── adjective-noun-1234-sessions.json -``` - -## Eval Session Format - -Each eval file is a JSON session that captures a complete conversation. The key fields for evaluation are the user message, the expected tool calls (recorded from a real session), and optional eval criteria: - -```json -{ - "id": "41b179a2-ed19-4ae2-a45d-95775aaa90f7", - "title": "Counting Files in Local Folder", - "messages": [ - { - "message": { - "message": { - "role": "user", - "content": "How many files in the local folder?" - } - } - }, - { - "message": { - "agent_name": "root", - "message": { - "role": "assistant", - "tool_calls": [ - { - "id": "call_abc123", - "type": "function", - "function": { - "name": "list_directory", - "arguments": "{\"path\":\"./\"}" - } - } - ] - } - } - }, - { - "message": { - "agent_name": "root", - "message": { - "role": "assistant", - "content": "There are 2 files in the local folder..." - } - } - } - ], - "evals": { - "relevance": [ - "The response mentions exactly 2 files", - "The response lists README.md and agent.yaml" - ], - "size": "S", - "working_dir": "my-project", - "setup": "echo 'hello' > test.txt" - } -} -``` - -## Eval Criteria - -The `evals` object inside each session controls what gets scored: - -| Field | Type | Description | -| ------------- | -------- | ----------------------------------------------------------------------------------------- | -| `relevance` | string[] | Statements that must be true about the agent's response. Scored by an LLM judge. | -| `size` | string | Expected response size: `S`, `M`, `L`, or `XL`. Compared against actual output length. | -| `working_dir` | string | Subdirectory under `evals/working_dirs/` to mount as the container's working directory. | -| `setup` | string | Shell script to run in the container before the agent executes (e.g., create test files). | - -## Scoring Metrics - -Docker Agent evaluates agents across three dimensions: - -| Metric | How It's Measured | -| ------------------- | ------------------------------------------------------------------------------------------------------------------------- | -| **Tool Calls (F1)** | F1 score between the expected tool call sequence (from the recorded session) and the actual tool calls made by the agent. | -| **Relevance** | An LLM judge (configurable via `--judge-model`) evaluates whether each relevance statement is satisfied by the response. | -| **Size** | Whether the response length matches the expected size category (S/M/L/XL). | - -## Serve-safety verification and rollback - -When changing an agent served over MCP HTTP, chat, or A2A, add an evaluation that attempts an approval-requiring tool call and verifies the resolved safety policy and authentication behavior. Run the evaluation with the same explicit `--safety` setting used in deployment. If a rollout must be reversed, stop the affected listener, restore the prior agent configuration and explicit safety flag, then restart only after confirming non-loopback listeners still require authentication. Do not restore an unauthenticated network listener as a rollback shortcut. - -## Creating Eval Sessions - -The easiest way to create eval sessions is from real conversations: - -1. Run your agent interactively: `docker agent run agent.yaml` -2. Have a conversation that tests the behavior you care about -3. Use the `/eval` slash command in the TUI to save the session as an eval file -4. Edit the generated JSON to add `evals` criteria (relevance, size, etc.) - -> [!TIP] -> Start with tool call scoring (automatic from recorded sessions), then add relevance criteria for the responses you care most about. - -## CLI Flags - -```bash -$ docker agent eval | [|./evals] -``` - -| Flag | Default | Description | -| ------------------- | --------------------------- | ----------------------------------------------------------------- | -| `-c, --concurrency` | num CPUs | Number of concurrent evaluation runs | -| `--judge-model` | `anthropic/claude-opus-5` | Model for LLM-as-a-judge relevance scoring | -| `--output` | `/results` | Directory for results, logs, and session databases | -| `--only` | (all) | Only run evals with file names matching these patterns | -| `--base-image` | (default) | Custom base image for eval containers (see [Custom Base Images](#custom-base-images)) | -| `--container-runtime` | `docker` | Container runtime executable for building and running evaluations (e.g. `podman`) | -| `--keep-containers` | `false` | Keep containers after evaluation (don't remove with `--rm`) | -| `-e, --env` | (none) | Environment variables to pass to container (`KEY` or `KEY=VALUE`) | -| `--repeat` | `1` | Number of times to repeat each evaluation (useful for computing baselines) | -| `--baseline` | (none) | Compare against a previously saved run JSON and exit non-zero on regression (see [Regression gate](#regression-gate)) | -| `--regression-tolerance` | `0` | How far an aggregate quality rate may fall before `--baseline` reports a regression (0–1) | - -### Regression gate - -`--baseline` compares the run against a previous one and exits non-zero when -quality regressed, so an eval suite can gate CI: - -```console -$ docker agent eval ./agent.yaml --baseline results/2026-08-01-run.json -``` - -The baseline is the run JSON written by a previous invocation — -`/.json` — so there is no separate artifact to produce. - -Four rules decide the verdict, and they are worth knowing before wiring this -into CI: - -- **The tolerance governs aggregate rates only.** An LLM judge does not return - the same score twice, so without a tolerance the gate flaps. `--regression-tolerance 0.05` - lets an aggregate rate fall five points before it counts. -- **An evaluation that passed and now fails always gates**, regardless of the - tolerance. That transition is the signal the gate exists to catch, so it is - never absorbed. -- **Cost is reported but never gates.** A provider price change is not a quality - regression. -- **An added *failing* evaluation gates** via the aggregate rate, even though no - existing evaluation regressed. A suite that got worse should say so — but it - means committing a known-failing eval needs a tolerance bump or a fix. - -A baseline that carries no evaluations, or a run that produced none (an -`--only` pattern that matched nothing), is rejected rather than reported as -passing: a gate that cannot fail is worse than no gate. - -### Provider Credentials - -Eval containers are isolated from your host environment. Dedicated model -provider API keys (for example `ANTHROPIC_API_KEY` or `OPENAI_API_KEY`) are -forwarded into eval containers automatically, so most provider setups work -without extra flags. - -> [!WARNING] -> **`GITHUB_TOKEN` and `GH_TOKEN` are not forwarded automatically** -> -> GitHub tokens are broad credentials (git, `gh`, CI, packages), not dedicated -> model API keys, so for security reasons Docker Agent does not forward them -> into eval containers — even when they are set in your shell or in -> `~/.config/cagent/.env`. If your agent uses the `github-copilot` provider, -> pass the token explicitly by name: -> -> ```bash -> docker agent eval agent.yaml ./evals -e GITHUB_TOKEN -> ``` -> -> When using a custom env file, both flags are required: -> -> ```bash -> docker agent eval agent.yaml ./evals \ -> --env-from-file /path/to/secrets.env \ -> -e GITHUB_TOKEN -> ``` - -Note that the LLM judge runs on the host, not inside the eval container. If -the token is not forwarded, judge validation can succeed while every -evaluated agent run fails to authenticate. - -### Custom Base Images - -When `--base-image` is set, the eval harness builds a derived image on top of your base image at evaluation time. Two things happen automatically: - -1. **The docker-agent binary is injected** — it is copied from `docker/docker-agent:edge` into the derived image at build time, so you don't need to include it in your base image. -2. **The entrypoint is overridden** — Docker Agent replaces your base image's entrypoint with its own `/run.sh` wrapper. - -Your base image therefore only needs to provide the runtime environment: language runtimes, installed dependencies, test fixtures, the appropriate working directory, and so on. Any `ENTRYPOINT` or `CMD` defined in your base image is ignored. - -## Output - -After a run completes, Docker Agent produces: - -- **Console summary** — Pass/fail status per eval with metric breakdowns -- **JSON results** — Full structured results for programmatic analysis -- **SQLite database** — Complete sessions for detailed investigation and debugging -- **Sessions JSON** — Exported session data for analysis -- **Log file** — Debug-level log of the entire evaluation run - -> [!TIP] -> **Debugging Failed Evals** -> -> Use `--keep-containers` to preserve containers after evaluation. You can then inspect them with your selected runtime's `exec` command (`docker exec` by default, `podman exec` with `--container-runtime podman`) to understand why an eval failed. The session database (`.db` file) contains the full conversation history for each eval. - -```bash -$ docker agent eval demo.yaml ./evals - - ✓ Counting Files in Local Folder - ✓ tool calls ✓ relevance 2/2 - ✓ Checking the Content of README.md File - ✓ tool calls ✓ relevance 1/1 - -✅ Tool Calls: 100.0% avg F1 (2 evals) -✅ Relevance: 3/3 passed (100.0%) - -Total Cost: $0.012345 -Total Time: 12s - -Sessions DB: ./evals/results/happy-panda-1234.db -Sessions JSON: ./evals/results/happy-panda-1234-sessions.json -Log: ./evals/results/happy-panda-1234.log -``` - -## Example - -Here's a minimal evaluation setup: - -```yaml -# agent.yaml -agents: - root: - model: openai/gpt-4o - description: Test agent - instruction: You know how to read/write and list files. - toolsets: - - type: filesystem -``` - -```bash -# Create evals from interactive sessions -$ docker agent run agent.yaml -# ... have conversations, then use /eval to save them - -# Run the evaluations -$ docker agent eval agent.yaml ./evals -``` - -> [!NOTE] -> **See also** -> -> Use `/eval` in the [TUI](../tui/index.md) to create eval sessions from conversations. See the [CLI Reference](../cli/index.md) for all `docker agent eval` flags. Example eval configs are in [examples/eval](https://github.com/docker/docker-agent/tree/main/examples/eval) on GitHub. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/harnesses/index.md b/_vendor/github.com/docker/docker-agent/docs/features/harnesses/index.md deleted file mode 100644 index b091bfea3ec9..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/harnesses/index.md +++ /dev/null @@ -1,287 +0,0 @@ ---- -title: "Coding Harnesses" -description: "Delegate coding tasks to external AI coding CLIs (Claude Code, Codex, opencode) as sub-agents." -keywords: docker agent, ai agents, features, coding harnesses -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/features/harnesses/ ---- - -_Delegate coding tasks to external AI coding CLIs (Claude Code, Codex, opencode) as sub-agents._ - -## Overview - -A **harness** agent delegates its work to an external coding CLI — `claude` (Claude Code), `codex` (OpenAI Codex), `opencode`, or `pi` — instead of calling a model API directly. The external CLI drives the coding loop while Docker Agent provides orchestration, hooks, permissions, and distribution. - -This pattern gives you the best of both worlds: - -- **External CLI strengths** — deep IDE integration, specialized coding workflows, CLI-native tool access -- **Docker Agent strengths** — multi-agent coordination, hook-based auditing and policy enforcement, permission controls, OCI distribution, and the full agent config schema - -> [!NOTE] -> **When to use harnesses** -> -> Use a harness when you want a Claude Code / Codex / opencode session to act as a sub-agent inside a larger Docker Agent workflow — for example, an orchestrator that plans work and delegates coding tasks to specialized harness agents. - -## Prerequisites - -The external CLI must be installed and available on `PATH` before starting Docker Agent: - -| Harness type | Required binary | Install | -| --- | --- | --- | -| `claude-code` | `claude` | [docs.anthropic.com/en/docs/claude-code](https://docs.anthropic.com/en/docs/claude-code) | -| `codex` | `codex` | [github.com/openai/codex](https://github.com/openai/codex) | -| `opencode` | `opencode` | [opencode.ai](https://opencode.ai) | -| `pi` | `pi` | Refer to the `pi` CLI documentation for installation instructions. | - -Docker Agent will report an error at session start if the required binary is not found. The `claude-code` harness additionally needs the CLI to be logged in — see [Authentication](#authentication-claude-subscription-no-api-key) below. - -## Configuration - -Add a `harness:` block to any agent definition to make it harness-backed: - -```yaml -agents: - coder: - description: A Claude Code harness agent - harness: - type: claude-code -``` - -Harness agents do **not** need a `model:` field — the external CLI manages its own model selection. - -### Field Reference - -| Field | Applies to | Type | Description | -| --- | --- | --- | --- | -| `type` | all | string | **Required.** One of `claude-code`, `codex`, `opencode`, `pi` | -| `model` | all | string | Optional model override forwarded to the CLI. When omitted, the CLI uses its own default model. | -| `effort` | `claude-code` | string | Reasoning effort: `low` \| `medium` \| `high` \| `xhigh` \| `max` — forwarded as `--effort`. When omitted, Claude Code uses its own default. | -| `agent` | `opencode` | string | opencode agent profile name | -| `thinking` | `opencode` | boolean | Enable extended thinking — forwarded as `--thinking` | - -### Claude Code - -```yaml -agents: - coder: - description: Claude Code coding agent - harness: - type: claude-code - model: claude-sonnet-4-5 # optional: alias (sonnet, opus, haiku) or full model ID - effort: high # low | medium | high | xhigh | max -``` - -- `model` accepts whatever the `claude` CLI accepts for `--model`: an alias - like `sonnet`, `opus`, or `haiku`, or a full model ID like - `claude-sonnet-4-5`. Omit it to use Claude Code's own default model. This is - **not** a Docker Agent `provider/model` reference — the harness model never - goes through Docker Agent's model providers or routing. -- `effort` is forwarded as `--effort` and must be one of `low`, `medium`, - `high`, `xhigh`, or `max`. Omit it to use Claude Code's own default. - -#### Authentication (Claude subscription, no API key) - -The `claude-code` harness runs the official CLI with the CLI's **own login**. -A Claude (claude.ai) subscription sign-in is all it needs — no -`ANTHROPIC_API_KEY` and no Docker Agent model credential are required for the -harness agent itself. Log in once: - -```bash -$ claude auth login --claudeai # interactive, opens a browser -$ claude auth status --text # verify the login -``` - -The login is stored per OS user by the CLI (in its own configuration and, on -macOS, the keychain) and is found via `HOME` and the process environment. Run -the login **as the same OS user and environment that run `docker agent`** — a -login made under another user, container, or `sudo` context is invisible to -the harness. Docker Agent never reads, copies, or stores the CLI's tokens; it -only launches `claude`, which authenticates itself. - -If the CLI is not logged in when a harness agent runs, the `claude` subprocess -fails at session start and the agent reports a harness error — Docker Agent -never opens a browser or starts a login on its own. Diagnose and fix with: - -```bash -$ docker agent doctor ./agent.yaml # checks install + login for claude-code harness files -$ docker agent setup # pick "Claude Code harness" to be walked through it -``` - -`docker agent doctor ` probes the CLI only when the file declares a -`claude-code` harness, and reports installation, version, and safe login -metadata (auth method, API provider, subscription type — never your email, -organization, or tokens). `docker agent setup` offers to run the official -`claude auth login --claudeai` for you (only after you confirm) and writes a -ready-to-run `claude-code-agent.yaml`. - -> [!WARNING] -> **The harness bypasses Claude Code's permission prompts** -> -> Docker Agent runs the CLI non-interactively with its own tools and passes -> `--dangerously-skip-permissions`: Claude Code edits files and runs commands -> without asking. Only point a harness agent at a repository you trust, and -> prefer isolation — `docker agent run --worktree` runs it on an isolated git -> worktree, keeping its changes off your checkout (a worktree with work, or -> from a non-interactive run, is kept for inspection per the normal cleanup -> rules). `docker agent run --sandbox` does not automatically carry the -> `claude` CLI or its login into the sandbox, so it cannot isolate the -> harness unless the sandbox image is separately provisioned and -> authenticated. - -### Codex - -```yaml -agents: - coder: - description: Codex coding agent - harness: - type: codex - model: o4-mini # optional model override -``` - -### opencode - -```yaml -agents: - coder: - description: opencode coding agent - harness: - type: opencode - agent: my-profile # optional agent profile - thinking: true # enable extended thinking -``` - -## What Does NOT Work - -Harness agents bypass the Docker Agent model pipeline entirely. As a result: - -- **Docker Agent toolsets are inactive.** The external CLI provides its own tools — filesystem, shell, etc. Any `toolsets:` defined on a harness agent are silently ignored. -- **`model:` routing is unavailable.** The harness CLI manages model selection; Docker Agent's `models:` configuration and routing rules do not apply to harness agents. -- **Token usage tracking depends on the external CLI.** Docker Agent records usage when the CLI reports it (Claude Code and Codex both report usage data). If the CLI does not emit usage data, the session will show zero token usage. - -> [!WARNING] -> **No Docker Agent toolsets inside a harness** -> -> Do not configure `toolsets:` on a harness agent — they are silently ignored. If you need Docker Agent toolsets alongside external coding capabilities, use a standard sub-agent with `transfer_task` rather than a harness. - -## Hook Behavior - -Hooks work normally on harness agents, including `before_llm_call` and `after_llm_call`. `before_llm_call` runs before the prompt is forwarded to the external CLI and can block or rewrite the run; `after_llm_call` fires after the CLI returns its final response. - -The `model_id` field in hook payloads is set to the harness label (e.g. `claude-code`) rather than a canonical `provider/model` string. This applies to `before_llm_call`, `after_llm_call`, and any other event that carries `model_id`. - -See [Hooks](../../configuration/hooks/index.md) for the full hook reference. - -## Recipe: Root Harness Agent - -The simplest setup: a single root agent that hands everything to Claude Code. -No `models:` section, no API key — the CLI's subscription login does the work. -This is exactly the file `docker agent setup` generates for the Claude Code -harness path (as `claude-code-agent.yaml`). - -```yaml -# claude-code-agent.yaml -agents: - root: - description: Claude Code running on your Claude subscription - harness: - type: claude-code - effort: medium # low | medium | high | xhigh | max; omit for the Claude Code default - # model: claude-sonnet-4-5 # optional; omit for the Claude Code default -``` - -```bash -$ docker agent run claude-code-agent.yaml -$ docker agent doctor claude-code-agent.yaml # verify the CLI is installed and logged in -``` - -## Recipe: Orchestrator + Harness Sub-Agents (Sequential) - -An orchestrator plans the work and delegates to specialized harness agents one at a time. Each coding agent runs in its own sub-session and reports results back. - -```yaml -# examples/coding_harnesses.yaml - -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - -agents: - root: - model: claude - description: Orchestrator that plans and delegates coding tasks - instruction: | - You are a project orchestrator. Break down coding requests into - focused tasks and delegate each task to the most appropriate - coding agent. Collect results and synthesize a final summary. - sub_agents: - - claude-coder - - codex-coder - - claude-coder: - description: Claude Code specialist for complex refactors - harness: - type: claude-code - model: claude-sonnet-4-5 - effort: xhigh - - codex-coder: - description: Codex specialist for code generation - harness: - type: codex -``` - -Only the orchestrator's `model: claude` needs an Anthropic API key — the -`claude-coder` harness agent authenticates through the CLI's own subscription -login. - -The root agent calls `transfer_task` to send work to a harness sub-agent, waits for the result, and continues. See the [full example on GitHub](https://github.com/docker/docker-agent/blob/main/examples/coding_harnesses.yaml). - -## Recipe: Parallel Harness Dispatch - -Combine the `background_agents` toolset with harness sub-agents to dispatch multiple coding tasks simultaneously: - -```yaml -# examples/coding_harness_background_agents.yaml - -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - -agents: - root: - model: claude - description: Orchestrator that fans out coding tasks in parallel - instruction: | - Use background agents to run multiple coding tasks at once. - Dispatch all tasks, then collect results when each finishes. - sub_agents: - - claude-coder - - codex-coder - toolsets: - - type: background_agents - - claude-coder: - description: Frontend specialist (Claude Code) - harness: - type: claude-code - effort: medium - - codex-coder: - description: Backend specialist (Codex) - harness: - type: codex -``` - -The orchestrator calls `run_background_agent` for each task, monitors progress with `list_background_agents`, and collects results with `view_background_agent`. See the [full example on GitHub](https://github.com/docker/docker-agent/blob/main/examples/coding_harness_background_agents.yaml). - -For the general background agents reference, see [Background Agents](../../tools/background-agents/index.md). - -## See Also - -- [Multi-Agent Systems](../../concepts/multi-agent/index.md) — orchestration patterns -- [Background Agents](../../tools/background-agents/index.md) — parallel task dispatch -- [Hooks](../../configuration/hooks/index.md) — auditing and policy enforcement -- [Agent Configuration](../../configuration/agents/index.md) — full agent schema reference diff --git a/_vendor/github.com/docker/docker-agent/docs/features/mcp-mode/index.md b/_vendor/github.com/docker/docker-agent/docs/features/mcp-mode/index.md deleted file mode 100644 index 9e3ae0bf69eb..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/mcp-mode/index.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: "MCP Mode" -description: "Expose your Docker Agent agents as MCP tools for use in Claude Desktop, Claude Code, and other MCP-compatible applications." -keywords: docker agent, ai agents, features, mcp mode -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/features/mcp-mode/ ---- - -_Expose your Docker Agent agents as MCP tools for use in Claude Desktop, Claude Code, and other MCP-compatible applications._ - -## Why MCP Mode? - -The `docker agent serve mcp` command makes your agents available to any application that supports the [Model Context Protocol](https://modelcontextprotocol.io/). This means you can: - -- Use custom agents directly within **Claude Desktop** or **Claude Code** -- Share specialized agents across different applications -- Build reusable agent teams consumable from any MCP client -- Integrate domain-specific agents into existing workflows - -> [!NOTE] -> **What is MCP?** -> -> The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI tools. See also [Remote MCP Servers](../remote-mcp/index.md) for connecting to cloud services. - -## Basic Usage - -```bash -# Expose a local config (stdio transport, the default) -$ docker agent serve mcp ./agent.yaml - -# Expose from a registry -$ docker agent serve mcp myorg/agent:tag - -# Set the working directory -$ docker agent serve mcp ./agent.yaml --working-dir /path/to/project -``` - -## Transports - -By default, `serve mcp` uses the stdio transport — ideal for clients that spawn the server as a subprocess (Claude Desktop, Claude Code, Cursor, …). - -To expose the MCP server over streaming HTTP instead, pass `--http`: - -```bash -# Streaming HTTP transport on the default 127.0.0.1:8081 -$ docker agent serve mcp ./agent.yaml --http - -# Override the listen address / port; non-loopback HTTP requires authentication -$ docker agent serve mcp ./agent.yaml --http --listen 0.0.0.0:9090 --auth-token "$MCP_BEARER_TOKEN" -``` - -| Flag | Default | Description | -| ---------------------- | ------------------ | ------------------------------------------------------------------------------------------------------------ | -| `--http` | `false` | Use streaming HTTP transport instead of stdio. | -| `-l`, `--listen` | `127.0.0.1:8081` | Address to listen on when `--http` is enabled. | -| `-a`, `--agent` | all agents | Expose a single named agent instead of every agent in the config. | -| `--tool-name` | (none) | Override the MCP tool identifier clients call (defaults to agent name); only valid when exposing one agent. | -| `--auth-token` | (none) | Require this Bearer token for HTTP requests. Required for non-loopback HTTP unless explicitly overridden. | -| `--insecure-no-auth` | `false` | Permit unauthenticated non-loopback HTTP. Use only behind a trusted authentication boundary. | -| `--safety` | `restricted` | Tool safety policy for HTTP requests. CLI value overrides agent/runtime configuration. | -| `--mcp-keepalive` | `0` | Interval between MCP keep-alive pings (e.g. `30s`); `0` disables keep-alive. | - -Runtime configuration flags such as `--working-dir`, `--env-from-file`, `--models-gateway`, and hook flags are also available — see the [CLI reference](../cli/index.md). - -## HTTP security - -HTTP MCP defaults to loopback binding. A non-loopback `--listen` address requires `--auth-token`; use `--insecure-no-auth` only when a trusted reverse proxy or network boundary authenticates clients. The safety policy is resolved in this order: `--safety`, agent configuration, runtime configuration, then `restricted`. These HTTP-only flags do not affect stdio or `--attach` operation. - -## Using with Claude Desktop - -Add a configuration to your Claude Desktop MCP settings file: - -- **macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json` -- **Windows:** `%APPDATA%\Claude\claude_desktop_config.json` - -```json -{ - "mcpServers": { - "myagent": { - "command": "/usr/local/bin/docker", - "args": [ - "agent", - "serve", - "mcp", - "myorg/coder", - "--working-dir", - "/home/user/projects" - ], - "env": { - "ANTHROPIC_API_KEY": "your_key_here", - "OPENAI_API_KEY": "your_key_here" - } - } - } -} -``` - -Restart Claude Desktop after updating the configuration. - -## Using with Claude Code - -```bash -$ claude mcp add --transport stdio myagent \ - --env OPENAI_API_KEY=$OPENAI_API_KEY \ - --env ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY \ - -- docker agent serve mcp myorg/agent:tag --working-dir $(pwd) -``` - -## Multi-Agent in MCP Mode - -When you expose a multi-agent configuration via MCP, each agent becomes a separate tool in the MCP client: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Main coordinator - sub_agents: [designer, engineer] - designer: - model: openai/gpt-5-mini - description: UI/UX design specialist - engineer: - model: anthropic/claude-sonnet-4-5 - description: Software engineer -``` - -All three agents (`root`, `designer`, `engineer`) appear as separate tools in Claude Desktop or Claude Code. - -## Troubleshooting - -- **Agents not appearing:** Verify the `docker-agent` binary path and restart the MCP client -- **Permission errors:** Ensure `docker-agent` has execute permissions (`chmod +x`) -- **Missing API keys:** Pass all required keys in the `env` section -- **Working directory issues:** Verify the `--working-dir` path exists and is accessible diff --git a/_vendor/github.com/docker/docker-agent/docs/features/remote-mcp/index.md b/_vendor/github.com/docker/docker-agent/docs/features/remote-mcp/index.md deleted file mode 100644 index 564233bd57c7..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/remote-mcp/index.md +++ /dev/null @@ -1,308 +0,0 @@ ---- -title: "Remote MCP Servers" -description: "Connect Docker Agent to cloud services via remote MCP servers with built-in OAuth authentication." -keywords: docker agent, ai agents, features, remote mcp servers -weight: 120 -canonical: https://docs.docker.com/ai/docker-agent/features/remote-mcp/ ---- - -_Connect Docker Agent to cloud services via remote MCP servers with built-in OAuth authentication._ - -## Overview - -Docker Agent supports connecting to remote MCP servers over **Streamable HTTP**, **SSE** (Server-Sent Events), and **Unix domain sockets**. Streamable HTTP is the current recommended transport for most hosted MCP servers. Many popular services offer MCP endpoints with OAuth — Docker Agent handles the authentication flow automatically. - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp.linear.app/mcp" - transport_type: "streamable" -``` - -## Unix Domain Sockets - -Use a `unix://` URL to connect to an MCP server listening on a local Unix socket. This is useful when running Docker Agent inside a container and exposing an MCP server from the host via a bind-mounted socket: - -```yaml -toolsets: - - type: mcp - remote: - url: "unix:///tmp/mcp-notify.sock" - transport_type: "streamable" -``` - -The path after `unix://` is the absolute path to the socket file. Configured `headers` are forwarded over the socket connection. OAuth discovery is not supported for Unix socket URLs. - -> [!TIP] -> **OAuth flow** -> -> When you connect to a remote MCP server that requires OAuth, Docker Agent opens your browser automatically for authentication. Tokens are cached for subsequent sessions. - -> [!TIP] -> **Cancelling the authorization dialog** -> -> If you dismiss the OAuth authorization dialog, the request is cancelled cleanly — no repeated prompts appear. The agent will report that authorization was declined. To try again, simply re-enable the server or repeat the request that triggered the flow. - -## Configuration - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp.example.com/mcp" - transport_type: "streamable" # or "sse" for legacy servers - headers: - Authorization: "Bearer ${env.MY_TOKEN}" # resolved per request - # Optional: use only for trusted internal/private MCP or OAuth endpoints. - allow_private_ips: true -``` - -For full configuration details, see the [Tool Config](../../configuration/tools/index.md) page. - -Set `allow_private_ips: true` on a remote MCP toolset only when the MCP server or its OAuth registration/token endpoints intentionally resolve to private, loopback, or link-local addresses. The default blocks those OAuth helper requests to reduce SSRF risk. - -> [!NOTE] -> **Headers forwarded during OAuth discovery** -> -> Configured `headers` are forwarded to OAuth protected-resource-metadata discovery requests directed at the MCP server's own host — not to third-party authorization servers. This allows services like Grafana Cloud that require a routing header (e.g. `X-Grafana-URL`) on the discovery request to scope the OAuth flow correctly. Headers are never sent to a different host than the one in `remote.url`. - -> [!NOTE] -> **Per-request header template expansion** -> -> Header values in `remote.headers` support `${env.VAR}` and `${headers.NAME}` placeholders. Both are resolved on every outbound HTTP request (not just once at initialization), so short-lived credentials and forwarded caller headers always reflect the latest values: -> -> - `${env.VAR}` — reads the named environment variable. Useful for credentials stored in a secret manager that rotates them in-process. -> - `${headers.NAME}` — forwards the named header from the caller's incoming HTTP request. Only meaningful when Docker Agent is running as an API server (`docker agent serve api`) and a client passes authentication headers that the upstream MCP server also accepts. - -> [!NOTE] -> **Automatic reconnection after idle timeouts** -> -> Remote MCP connections (Streamable HTTP / SSE) automatically reconnect after the server closes an idle connection — no configuration needed. Services like Notion and Linear close idle connections periodically; Docker Agent detects the clean close and reconnects with exponential backoff. To tune reconnect behaviour or disable reconnection entirely, use the [`lifecycle` block](../../configuration/tools/index.md#toolset-lifecycle). - -> [!NOTE] -> **Automatic recovery from revoked or rotated OAuth tokens** -> -> If a remote MCP server rejects the cached token with a `401 invalid_token` error (for example, because the token was revoked or rotated server-side), Docker Agent handles the failure automatically: -> -> - **Silent refresh:** when a refresh token is available, Docker Agent silently exchanges it for a new access token and replays the request — no user interaction required. -> - **Re-authentication prompt:** when the refresh token is absent or has also expired, the toolset transitions to a "needs re-auth" state and surfaces an OAuth prompt on your next message (exactly like the first-time flow). -> -> Either way, the agent never burns 5 reconnect attempts on an auth failure — it fails fast and either refreshes silently or defers to interactive re-auth. If you want to trigger re-auth immediately without waiting for the next message, run `/toolset-restart ` from the TUI. - -### OAuth for servers without Dynamic Client Registration - -Most remote MCP servers that require OAuth support [Dynamic Client Registration (RFC 7591)](https://datatracker.ietf.org/doc/html/rfc7591) — no configuration is needed, Docker Agent handles the flow for you. - -For servers that do **not** support DCR, Docker Agent falls back automatically: - -1. **Interactive credential prompt**: Docker Agent presents a dialog asking for your `client_id` (required) and optionally a `client_secret`. This covers servers that require pre-registered app credentials but don't advertise them via DCR. -2. **Explicit `oauth:` block** (recommended when you know the credentials in advance): add the block described below to skip the interactive prompt and supply credentials directly in config. - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp.example.com/mcp" - transport_type: "streamable" - oauth: - clientId: "my-app-client-id" - clientSecret: "my-app-client-secret" # optional (public clients may omit) - callbackPort: 8765 # optional; picks a free port otherwise - scopes: # optional; server-specific - - read - - write -``` - -| Field | Type | Required | Description | -| -------------- | --------------- | -------- | ------------------------------------------------------------------------------------------------ | -| `clientId` | string | ✗ | OAuth client ID registered with the remote MCP server. When omitted, Docker Agent uses Dynamic Client Registration or prompts interactively. | -| `clientSecret` | string | ✗ | OAuth client secret. Requires `clientId`. Omit for public clients using PKCE. | -| `callbackPort` | integer | ✗ | Local port to receive the OAuth redirect. If omitted, Docker Agent picks a random free port. | -| `scopes` | array[string] | ✗ | Scopes to request during the authorization step. Values are server-specific. | -| `callbackRedirectURL` | string | ✗ | Custom OAuth redirect URI. Useful when the auth server requires HTTPS or a pre-registered URL. The literal placeholder `${callbackPort}` is replaced with the actual local callback port. See below. | - -Secrets should be stored in a credential helper or environment variable rather than committed — see [Secrets](../../guides/secrets/index.md) for interpolation patterns. - -> [!TIP] -> The `oauth:` block also works **without** `clientId`. Use it to pin the callback port, request specific scopes, or set a custom redirect URL while still letting Docker Agent obtain the client ID via Dynamic Client Registration (or the interactive prompt). - -### Custom redirect URI (`callbackRedirectURL`) - -Some authorization servers require the OAuth `redirect_uri` to be HTTPS or to match a URL that was pre-registered during app creation — neither of which plays nicely with a locally-bound loopback address such as `http://127.0.0.1:8765/callback`. - -To work around this, set `callbackRedirectURL` to a public URL that redirects back to the local callback server. The literal placeholder `${callbackPort}` is substituted with the actual port the local callback server is listening on (either `callbackPort` when set, or the randomly-assigned port otherwise). - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp.example.com/mcp" - transport_type: "streamable" - oauth: - clientId: "my-app-client-id" - callbackPort: 8765 - # Advertise this URL to the authorization server. The external - # service at redirect.example.com is expected to 302-redirect the - # browser to http://127.0.0.1:8765/callback preserving the query - # string (code, state, …). - callbackRedirectURL: "https://redirect.example.com/cb?port=${callbackPort}" -``` - -The local callback server still listens on the loopback interface on `callbackPort`; only the `redirect_uri` advertised to the authorization server changes. - -**Validation rules:** - -- The URL must be absolute (scheme + host) once `${callbackPort}` has been substituted. -- Only `http` and `https` schemes are accepted. -- `http` is only allowed when the host is a loopback address (`127.0.0.1`, `::1`, `localhost`); any other host must use `https` to avoid exposing the authorization `code` on the wire (RFC 8252 §7.3). - -### Unmanaged OAuth flow (server mode) - -When running `docker agent serve api` (no local browser, no callback server), the runtime delegates the OAuth dance to the connected client via an MCP elicitation. There are two sub-behaviors, selected by the `--mcp-oauth-redirect-uri` flag: - -- **`--mcp-oauth-redirect-uri=` set** (recommended for hosts like Docker Desktop): the runtime generates `state` + PKCE + (optional) Dynamic Client Registration in-process, builds the full authorize URL, and emits an elicitation whose `Meta` includes: - - | Key | Value | - | ---------------------------- | ---------------------------------------------------------------- | - | `docker-agent/type` | `"oauth_flow"` | - | `docker-agent/server_url` | The MCP server URL (for display / favicon) | - | `docker-agent/authorize_url` | The full URL the client should open in the user's browser | - | `docker-agent/state` | The `state` value the client must echo back when replying | - | `auth_server` | Issuer of the authorization server | - | `auth_server_metadata` | RFC 8414 authorization-server metadata document | - | `resource_metadata` | RFC 9728 protected-resource metadata document | - - The client opens the browser at the URL provided in the `docker-agent/authorize_url` meta field, receives the OAuth callback at whatever endpoint the configured `redirect_uri` resolves to (typically a host-controlled bouncer that 302s into a deeplink), and replies to the elicitation with `accept` and `Content = {"code": "...", "state": "..."}`. The runtime verifies the `state`, exchanges the `code` at the token endpoint (using the same `redirect_uri` for RFC 6749 §4.1.3 binding), stores the token, and replays the original MCP request with `Authorization: Bearer ...`. - -- **Flag not set** (client-driven): the runtime emits the elicitation meta below and expects the client to drive the OAuth flow itself (PKCE, DCR, token exchange) and reply with `Content = {"access_token": "...", "refresh_token": "...", ...}`: - - | Key | Value | - | ---------------------------- | ---------------------------------------------------------------- | - | `docker-agent/type` | `"oauth_flow"` | - | `docker-agent/server_url` | The MCP server URL (for display / favicon) | - | `auth_server` | Issuer of the authorization server | - | `auth_server_metadata` | RFC 8414 authorization-server metadata document | - | `resource_metadata` | RFC 9728 protected-resource metadata document | - -The client-driven `{access_token, ...}` reply shape is still accepted on the `--mcp-oauth-redirect-uri` path too: a client that prefers to do the exchange itself can ignore the `docker-agent/authorize_url`/`docker-agent/state` keys. - -A per-toolset `callbackRedirectURL` (in the YAML) overrides the runtime-wide `--mcp-oauth-redirect-uri` for that toolset. - -> [!WARNING] -> **Security note** -> -> The `POST /api/mcp-oauth/callback` route is open by default (no auth required) when `--auth-token` is unset. State values are 128-bit opaque tokens, so brute-force is infeasible, but a state value that leaks (e.g. via debug logs or a compromised host) could be exploited by an attacker to inject a code. Set `--auth-token` when `docker agent serve api` listens on a network-reachable interface. When set, `--auth-token` enforces Bearer-token authentication on all API routes including this callback endpoint. - -## Project Management & Collaboration - -| Service | URL | Transport | Description | -| ---------- | ---------------------------------- | --------- | ------------------------------------- | -| Asana | `https://mcp.asana.com/sse` | sse | Task and project management | -| Atlassian | `https://mcp.atlassian.com/v1/mcp/authv2` | streamable | Jira, Confluence integration | -| Linear | `https://mcp.linear.app/mcp` | streamable | Issue tracking and project management | -| Monday.com | `https://mcp.monday.com/sse` | sse | Work management platform | -| Intercom | `https://mcp.intercom.com/sse` | sse | Customer communication platform | - -## Development & Infrastructure - -| Service | URL | Transport | Description | -| ------------------------ | ---------------------------------------------- | ---------- | --------------------------------- | -| GitHub | `https://api.githubcopilot.com/mcp` | sse | Version control and collaboration | -| Buildkite | `https://mcp.buildkite.com/mcp` | streamable | CI/CD platform | -| Netlify | `https://netlify-mcp.netlify.app/mcp` | streamable | Web hosting and deployment | -| Vercel | `https://mcp.vercel.com/` | sse | Web deployment platform | -| Cloudflare Bindings | `https://bindings.mcp.cloudflare.com/sse` | sse | Edge computing resources | -| Cloudflare Observability | `https://observability.mcp.cloudflare.com/sse` | sse | Monitoring and analytics | -| Grafbase | `https://api.grafbase.com/mcp` | streamable | GraphQL backend platform | -| Neon | `https://mcp.neon.tech/sse` | sse | Serverless Postgres database | -| Prisma | `https://mcp.prisma.io/mcp` | streamable | Database ORM and toolkit | -| Sentry | `https://mcp.sentry.dev/sse` | sse | Error tracking and monitoring | - -## Content & Media - -| 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 | -| Wix | `https://mcp.wix.com/sse` | sse | Website builder platform | -| Notion | `https://mcp.notion.com/mcp` | streamable | Documentation and knowledge base | - -## Communication & Voice - -| Service | URL | Transport | Description | -| ----------- | ----------------------------------- | ---------- | --------------------------- | -| Fireflies | `https://api.fireflies.ai/mcp` | streamable | Meeting transcription | -| Listenetic | `https://mcp.listenetic.com/v1/mcp` | streamable | Audio intelligence platform | -| Carbonvoice | `https://mcp.carbonvoice.app` | sse | Voice communication tools | -| Telnyx | `https://api.telnyx.com/v2/mcp` | streamable | Communications platform | -| Dialer | `https://getdialer.app/sse` | sse | Phone communication tools | - -## Storage & File Management - -| Service | URL | Transport | Description | -| ------- | ----------------------------------- | --------- | ------------------------ | -| Box | `https://mcp.box.com` | sse | Cloud content management | -| Egnyte | `https://mcp-server.egnyte.com/sse` | sse | Enterprise file sharing | - -## Business & Finance - -| Service | URL | Transport | Description | -| ------------- | ----------------------------------------- | ---------- | -------------------------- | -| PayPal | `https://mcp.paypal.com/sse` | sse | Payment processing | -| Plaid | `https://api.dashboard.plaid.com/mcp/sse` | sse | Financial data integration | -| Square | `https://mcp.squareup.com/sse` | sse | Payment processing | -| Close | `https://mcp.close.com/mcp` | streamable | CRM platform | -| Dodo Payments | `https://mcp.dodopayments.com/sse` | sse | Payment processing | - -## Analytics & Data - -| Service | URL | Transport | Description | -| ----------- | --------------------------------------- | ---------- | ------------------------------ | -| ThoughtSpot | `https://agent.thoughtspot.app/mcp` | streamable | Analytics and BI platform | -| Meta Ads | `https://mcp.pipeboard.co/meta-ads-mcp` | streamable | Facebook advertising analytics | - -## Utilities & Tools - -| Service | URL | Transport | Description | -| ------------- | ---------------------------------- | ---------- | ------------------------------- | -| Apify | `https://mcp.apify.com` | sse | Web scraping and automation | -| SimpleScraper | `https://mcp.simplescraper.io/mcp` | streamable | Web scraping tool | -| GlobalPing | `https://mcp.globalping.dev/sse` | sse | Network diagnostics | -| Jam | `https://mcp.jam.dev/mcp` | streamable | Bug reporting and collaboration | - -## Example: Multi-Service Agent - -Combine multiple remote MCP servers in a single agent: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - instruction: | - You help manage projects and deployments. - toolsets: - - type: mcp - remote: - url: "https://mcp.linear.app/mcp" - transport_type: "streamable" - instruction: Use Linear for issue tracking. - - type: mcp - remote: - url: "https://api.githubcopilot.com/mcp" - transport_type: "sse" - instruction: Use GitHub for code and PRs. - - type: mcp - remote: - url: "https://mcp.vercel.com/" - transport_type: "sse" - instruction: Use Vercel for deployments. -``` - -> [!NOTE] -> **Growing list** -> -> This list is updated as more services add MCP support. If a service you use isn't listed, check their documentation — many providers are adding MCP endpoints regularly. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/sessions/index.md b/_vendor/github.com/docker/docker-agent/docs/features/sessions/index.md deleted file mode 100644 index dd264814b476..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/sessions/index.md +++ /dev/null @@ -1,135 +0,0 @@ ---- -title: "Sessions" -description: "How Docker Agent stores conversations, resumes them across runs, and tracks their token cost." -keywords: docker agent, ai agents, features, sessions -weight: 25 -canonical: https://docs.docker.com/ai/docker-agent/features/sessions/ ---- - -_How Docker Agent stores conversations, resumes them across runs, and tracks their token cost._ - -## What a Session Is - -Every `docker agent run` creates or resumes a **session**: the record of a conversation, including every message, tool call, sub-agent run, and cost. Sessions are what makes `/undo`, `/sessions`, `--session `, and cost tracking possible — the agent itself is stateless between runs, but the session is not. - -A session is only persisted to disk once it has content (the first message added), so a run you cancel before sending anything never leaves an empty session behind. - -## Where Sessions Are Stored - -Sessions live in a SQLite database, `session.db`, under the [data directory](../cli/index.md#global-flags) (`~/.cagent` by default): - -```bash -$ ls ~/.cagent/session.db -``` - -Override the location with `-s`/`--session-db`, or by overriding the data directory itself with `--data-dir`: - -```bash -# Use a project-local session database instead of the global one -$ docker agent run agent.yaml --session-db ./sessions.db -``` - -## Resuming a Session - -Pass `--session ` to continue a previous conversation instead of starting a new one: - -```bash -# Resume by explicit session ID -$ docker agent run agent.yaml --session 3f9c1e2a-... - -# Resume the most recently created session -$ docker agent run agent.yaml --session -1 - -# Resume the session created before that one -$ docker agent run agent.yaml --session -2 -``` - -`--session` accepts two kinds of reference: - -- **A relative offset** (`-1`, `-2`, …): sessions are ordered by **creation time**, newest first — `-1` is the most recently *created* session, `-2` the one created before it, and so on. This is creation order, not last-used order: resuming an older session with `--session ` does not make it the new `-1`; the next `-1` still resolves to whichever session was created most recently. A relative offset that has no matching session (for example `-1` with an empty database) is an error. -- **An explicit ID**: if a session with that ID already exists, it is resumed. If it doesn't exist yet, docker agent **creates it with that ID** instead of failing. This lets a supervisor (for example a board or a script) choose a session ID up front and reuse it across runs — the first run creates the session, later runs resume it. - -## Read-Only Sessions - -Add `--session-read-only` to open a session for viewing without sending new messages — useful for reviewing a past conversation without accidentally continuing it: - -```bash -$ docker agent run agent.yaml --session -1 --session-read-only -``` - -`--session-read-only` requires the TUI: it cannot be combined with `--exec`, since there would be nothing to display without one. - -## Browsing Sessions in the TUI - -Press `/sessions` to open the session browser: search and filter past conversations, see which ones were started in the current working directory ("This workspace") versus elsewhere ("Other locations"), and restore one with Enter. Restoring a session reopens it in its original working directory. See [Session Management](../tui/index.md#session-management) in the Terminal UI docs for the full set of session-browser and session-title features (starring, branching by editing a past message, and so on). - -### Tabs - -Ctrl+T opens a new tab running an additional agent session alongside the current one; Ctrl+N/Ctrl+P cycle between tabs and Ctrl+W closes the current one. By default, tabs are not restored the next time you launch the TUI. Set `restore_tabs: true` in your user config to reopen the same tabs (and their sessions) on the next launch: - -```yaml -# ~/.config/cagent/config.yaml -settings: - restore_tabs: true -``` - -## Session Titles - -Docker Agent auto-generates a short title for each session from your first message, using a one-shot call to the agent's own model. Point that call at a smaller, cheaper model instead with `title_model` on a model definition: - -```yaml -# examples/title_model.yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - # Generate session titles with the cheaper Haiku model instead of Sonnet. - title_model: fast - fast: - provider: anthropic - model: claude-haiku-4-5 - -agents: - root: - model: primary - description: An assistant that generates session titles with a cheaper model. - instruction: You are a helpful assistant. -``` - -When `title_model` is omitted, title generation reuses the agent's own model. Set or regenerate a title from inside the TUI with `/title` (see [Session Title Editing](../tui/index.md#session-title-editing)) — regenerating sends every user message in the session so far, not just the first — or generate one from the command line without starting a session at all: - -```bash -$ docker agent debug title agent.yaml "How do I configure a fallback model?" -``` - -See [`docker agent debug title`](../cli/index.md#docker-agent-debug) for details. - -## Usage & Cost Tracking - -Every tracked model call — the main conversation turns and compaction calls — updates the session's cumulative input/output token counts and cost. Check them at any time with `/cost` in the TUI, or disable tracking per-model with `track_usage: false` if you don't want a model's calls counted (for example, a free local model). Auxiliary one-shot calls the runtime makes on your behalf, such as automatic session-title generation, call the model directly and are not folded into this total. - -Cost is computed from the [models.dev](https://models.dev/) pricing catalogue by default. For a custom endpoint, a private deployment, or a negotiated enterprise rate the catalogue doesn't know about, declare pricing explicitly with a model's `cost:` block: - -```yaml -# examples/custom-pricing.yaml -models: - internal-gpt: - provider: internal-llm - model: gpt-4o - cost: - input: 1.25 # USD per 1M input tokens - output: 5.00 # USD per 1M output tokens - cache_read: 0.125 # USD per 1M cached input tokens - cache_write: 1.5625 # USD per 1M cache-write tokens -``` - -An all-zero `cost:` table means "priced, free" — distinct from a model with no `cost:` at all, which falls back to the catalogue (and bills $0 for models the catalogue doesn't know). - -> [!NOTE] -> **Cost never decreases** -> -> A session's cumulative cost is a running total updated after every *tracked* model call — the same main conversation turns and compaction calls described above. Compacting the conversation (manually with `/compact`, or automatically — see the agent's `session_compaction`/`compaction_threshold` fields in the [Agent Config reference](../../configuration/agents/index.md)) reshapes the message history sent back to the model, but never touches this running total. Auxiliary one-shot calls such as automatic session-title generation are not tracked and are not reflected in this total: `/cost` covers everything the session's tracked calls have spent, not literally every model call the runtime makes on your behalf. - -## Resuming Into a Worktree - -A session created during a `--worktree` run remembers which worktree it used. Resuming it with `--session` reattaches to the same worktree directory and branch automatically — you don't need to pass `--worktree` again. See [`--worktree`](../cli/index.md#docker-agent-run) in the CLI reference for the full worktree lifecycle. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/skills/index.md b/_vendor/github.com/docker/docker-agent/docs/features/skills/index.md deleted file mode 100644 index bba760387a0a..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/skills/index.md +++ /dev/null @@ -1,378 +0,0 @@ ---- -title: "Skills" -description: "Skills provide specialized instructions that agents can load on demand when a task matches a skill's description." -keywords: docker agent, ai agents, features, skills -weight: 110 -canonical: https://docs.docker.com/ai/docker-agent/features/skills/ ---- - -_Skills provide specialized instructions that agents can load on demand when a task matches a skill's description._ - -## How Skills Work - -1. Docker Agent scans standard directories for `SKILL.md` files -2. Skill metadata (name, description) is injected into the agent's system prompt -3. When a user request matches a skill, the agent reads the full instructions -4. The agent follows the skill's detailed instructions to complete the task - -## Enabling Skills - -```yaml -agents: - root: - model: openai/gpt-4o - instruction: You are a helpful assistant. - skills: true - toolsets: - - type: filesystem # required for reading skill files -``` - -> [!TIP] -> Skills are perfect for encoding team-specific workflows (PR review, deployment, coding standards) that apply across projects. - -## Filtering Skills - -The `skills` field also accepts a list, letting you restrict the agent to a specific subset of skills instead of exposing every discovered one. List items are classified automatically: - -- `"local"` or any `http://` / `https://` URL → a **source** to load skills from -- any other string → the **name** of a skill to include - -When only names are given, local sources are used by default. - -```yaml -agents: - # Load every discovered local skill (same as `skills: true`). - full: - skills: true - - # Load local skills, but only expose "commit" and "poem". - scoped: - skills: - - commit - - poem - - # Combine an explicit source with a name filter. - remote_filtered: - skills: - - https://skills.example.com - - commit - - # Disable skills entirely. - none: - skills: false -``` - -A name that doesn't match any discovered skill is logged as a warning at startup but is otherwise ignored. - -## Inline Skills - -Instead of (or alongside) loading skills from files and URLs, you can define skills directly in the agent config. An inline skill is a mapping item in the `skills` list, freely mixed with the string items above: - -```yaml -agents: - root: - model: openai/gpt-4o - instruction: You are a helpful assistant. - skills: - - name: changelog - description: Write a concise changelog entry from a diff or description. - instructions: | - Produce a single changelog entry in Keep a Changelog style. - Pick the right category (Added, Changed, Fixed, Removed) and write - one imperative sentence summarising the user-visible change. - - # A fork-mode inline skill runs in an isolated sub-agent. - - name: triage - description: Triage a bug report in an isolated context. - context: fork - instructions: | - Restate the problem, list likely root causes most-probable-first, - and propose the smallest reproduction and next concrete action. - - # Inline skills mix freely with sources and name filters. - - local - toolsets: - - type: filesystem -``` - -Inline skills carry their body in the config itself, so they need no `SKILL.md` file and require no filesystem source. They are **always exposed** — the name filter only applies to file- and URL-based skills. Because inline skills travel inside the agent YAML, they also work in `--sandbox` mode without any kit staging, and they can be shared with the agent via `share push`. - -### Inline Skill Fields - -| Field | Required | Description | -| --------------- | -------- | -------------------------------------------------------------------------- | -| `name` | Yes | Skill identifier used by `read_skill` / `run_skill` and the `/` command | -| `description` | Yes | Short description shown to the agent for skill matching | -| `instructions` | Yes | The skill body (what a `SKILL.md` would contain below its frontmatter) | -| `context` | No | Set to `fork` to run the skill as an isolated sub-agent | -| `model` | No | Override the model used while running a fork-mode skill | -| `allowed_tools` | No | For a fork-mode skill, restricts the sub-session to the parent tools whose names match an entry (glob or exact). See [Scoping a fork skill's tools](#scoping-a-fork-skills-tools). | -| `toolsets` | No | For a fork-mode skill, names of top-level [`toolsets`](../../configuration/overview/index.md#reusable-toolsets-toolsets) to expose in the sub-session on top of the inherited tools. | - -> [!NOTE] -> **Inline vs. file-based skills** -> -> Inline skills support the subset of the SKILL.md format that fits in YAML. They cannot bundle supporting files (no `read_skill_file`) or use `` !`command` `` expansion. For skills that need bundled resources or executable helpers, use a `SKILL.md` directory instead. - -## SKILL.md Format - - -```yaml ---- -name: create-dockerfile -description: Create optimized Dockerfiles for applications -license: Apache-2.0 -metadata: - author: my-org - version: "1.0" ---- - -# Creating Dockerfiles - -When asked to create a Dockerfile: - -1. Analyze the application type and language -2. Use multi-stage builds for compiled languages -3. Minimize image size by using slim base images -4. Follow security best practices (non-root user, etc.) -``` - -### Frontmatter Fields - -| Field | Required | Description | -| ---------------- | -------- | --------------------------------------------------------------------------- | -| `name` | Yes | Unique skill identifier | -| `description` | Yes | Short description shown to the agent for skill matching | -| `context` | No | Set to `fork` to run the skill as an isolated sub-agent (see below) | -| `model` | No | Override the model used while running the skill as a sub-agent (fork only) | -| `allowed-tools` | No | For a fork-mode skill, restricts the sub-session to the parent tools whose names match an entry (YAML list or comma-separated string). See [Scoping a fork skill's tools](#scoping-a-fork-skills-tools). | -| `toolsets` | No | For a fork-mode skill, names of top-level [`toolsets`](../../configuration/overview/index.md#reusable-toolsets-toolsets) to expose in the sub-session (YAML list or comma-separated string). | -| `license` | No | License identifier (e.g. `Apache-2.0`) | -| `compatibility` | No | Free-text compatibility notes | -| `metadata` | No | Arbitrary key-value pairs (e.g. `author`, `version`) | - -## Running a Skill as a Sub-Agent - -By default, when an agent invokes a skill it reads the instructions inline into its own conversation. For complex, multi-step skills this can consume a large portion of the agent's context window and pollute the parent conversation with intermediate tool calls. - -Adding `context: fork` to the SKILL.md frontmatter tells the agent to run the skill in an **isolated sub-agent** instead: - - -```yaml ---- -name: bump-go-dependencies -description: Update Go module dependencies one by one -context: fork ---- - -# Bump Dependencies - -1. List outdated deps -2. Update each one, run tests, commit or revert -3. Produce a summary table -``` - -When the agent encounters a task that matches a `context: fork` skill, it uses the `run_skill` tool instead of `read_skill`. This: - -- **Spawns a child session** with the skill content as the system prompt and the caller's task as the user message -- **Isolates the context window** — the sub-agent has its own conversation history, so lengthy tool-call chains don't eat into the parent's token budget -- **Folds the result** — only the sub-agent's final answer is returned to the parent as the tool result -- **Inherits the parent's model and tools** — the sub-agent can use all tools available to the parent agent (scope this with `allowed_tools` / `toolsets`, see [Scoping a fork skill's tools](#scoping-a-fork-skills-tools)) - -> [!TIP] -> **When to use context: fork** -> -> Use `context: fork` for skills that involve many steps, heavy tool usage, or that should not clutter the main conversation — for example dependency bumping, large refactors, or code generation pipelines. - -### Overriding the model for a fork skill - -Fork skills can declare a `model` field in their frontmatter to use a -different model than the parent agent for the duration of the sub-session. -This is useful when a skill is best handled by a faster, cheaper, or more -specialised model — for example a powerful reasoning model for refactors, -or a fast model for routine bookkeeping work. The override only applies -while the skill is running; the parent agent keeps its own model. - -The `model` value accepts either a named model from the agent config or -an inline `provider/model` reference (and the same comma-separated alloy -syntax as the rest of the agent config): - - -```yaml ---- -name: bump-go-dependencies -description: Update Go module dependencies one by one -context: fork -model: openai/gpt-4o-mini ---- - -# Bump Dependencies - -1. ... -``` - -If the model reference cannot be resolved (unknown name, missing -credentials, runtime not configured for model switching, …) the skill -falls back to the agent's currently-active model (its configured -default, or any override the user previously set via the model picker) -and a warning is logged. - -When the skill completes, the agent's previous model is restored — but -only if no one else changed the model in the meantime. If the user -switches the model via the TUI model picker while the fork skill is -running, their choice is preserved (the deferred restore becomes a -no-op). - -### Scoping a fork skill's tools - -By default a fork skill inherits the parent agent's entire tool set. Two -optional fields let you scope what the sub-session can use. Both apply -**only to fork-mode skills** and work the same whether the skill is -inline or loaded from a `SKILL.md` file. - -`allowed_tools` (frontmatter: `allowed-tools`) is an **allow-list** over -the inherited tools: only tools whose names match an entry are kept, -everything else is hidden from the sub-session. Entries support glob -patterns (e.g. `read_*`) and otherwise match exactly. This is the -Claude-Code-compatible `allowed-tools` field, now enforced for fork -skills rather than merely recorded. - -`toolsets` references reusable [top-level toolsets](../../configuration/overview/index.md#reusable-toolsets-toolsets) -by name. The referenced toolsets are exposed in the sub-session **in -addition to** the inherited tools, and they bypass the `allowed_tools` -filter (the skill explicitly asked for them). - -```yaml -toolsets: - web: - type: fetch - -agents: - root: - model: openai/gpt-4o - instruction: You are a helpful assistant. - toolsets: - - type: filesystem - - type: shell - skills: - # Inherits the parent tools but is restricted to read-only filesystem - # access while it runs — shell and write tools are hidden. - - name: audit - description: Review the repository layout without modifying anything. - context: fork - allowed_tools: - - read_file - - list_directory - - directory_tree - instructions: Inspect the repository structure and summarise it. - - # Brings in the top-level `web` toolset on top of the parent's tools. - - name: research - description: Research a topic using web fetches in an isolated context. - context: fork - toolsets: - - web - instructions: Research the requested topic and summarise with links. -``` - -The equivalent in a `SKILL.md` file uses frontmatter lists: - - -```yaml ---- -name: research -description: Research a topic using web fetches -context: fork -allowed-tools: - - fetch -toolsets: - - web ---- -``` - -> [!NOTE] -> **Fork only** -> -> Both fields are rejected by config validation when set on a non-fork skill, and a `toolsets` entry that doesn't resolve to a top-level toolset is a load-time error. - -## Search Paths - -Skills are discovered from these locations (later overrides earlier): - -### Global - -| Path | Search Type | -| ------------------- | --------------------------------------- | -| `~/.codex/skills/` | Recursive (searches all subdirectories) | -| `~/.claude/skills/` | Flat (immediate children only) | -| `~/.agents/skills/` | Recursive (searches all subdirectories) | - -### Project (from git root to current directory) - -| Path | Search Type | -| ----------------- | ------------------------------------------ | -| `.claude/skills/` | Flat (cwd only) | -| `.github/skills/` | Flat (each directory from git root to cwd) | -| `.agents/skills/` | Flat (each directory from git root to cwd) | - -## Invoking Skills - -Skills can be invoked in multiple ways: - -- **Automatic:** The agent detects when your request matches a skill's description and loads it automatically -- **Explicit:** Reference the skill name in your prompt: "Use the create-dockerfile skill to..." -- **Slash command:** Use `/{skill-name}` to invoke a skill directly - -```bash -# In the TUI, invoke skill directly: -/create-dockerfile - -# Or mention it in your message: -"Create a dockerfile for my Python app (use the create-dockerfile skill)" -``` - -## Precedence - -When multiple skills share the same name: - -1. Global skills load first -2. Project skills load next, from git root toward current directory -3. Skills closer to the current directory override those further away -4. At the same directory level, `.agents/skills/` overrides `.github/skills/` - -## Skills in Sandbox Mode - -When you run an agent with [`--sandbox`](../../configuration/sandbox/index.md), the sandbox VM has its own filesystem with no access to your host's skill directories. Docker Agent handles this transparently via the [auto-kit](../../configuration/sandbox/index.md#auto-kit): every discovered local skill is staged into a per-agent kit on the host, run through best-effort secret redaction (see the [auto-kit](../../configuration/sandbox/index.md#secret-redaction) docs), and bind-mounted read-only into the sandbox so the agent sees the same skills inside the VM as on the host. No configuration is required — use `--no-kit` only if you explicitly want to run the sandbox without any host skills. - -## Creating a Skill - -```bash -# Create the skill directory -$ mkdir -p ~/.agents/skills/create-dockerfile - -# Write the SKILL.md file -$ cat > ~/.agents/skills/create-dockerfile/SKILL.md << 'EOF' ---- -name: create-dockerfile -description: Create optimized Dockerfiles for applications ---- - -# Creating Dockerfiles - -When asked to create a Dockerfile: - -1. Analyze the application type and language -2. Use multi-stage builds for compiled languages -3. Use slim base images to minimize size -4. Run as non-root user for security -EOF -``` - -The skill will automatically be available to any agent with skills enabled (`skills: true`, or a list that targets its name — see [Filtering Skills](#filtering-skills)). - -> [!NOTE] -> **See also** -> -> Skills are enabled in the [Agent Config](../../configuration/agents/index.md) with the `skills` property (boolean or list). For tool-based capabilities, see [Tools](../../concepts/tools/index.md). -> -> Example configs: [`examples/skills_inline.yaml`](https://github.com/docker/docker-agent/blob/main/examples/skills_inline.yaml) (inline skill definition), [`examples/skills_fork_toolsets.yaml`](https://github.com/docker/docker-agent/blob/main/examples/skills_fork_toolsets.yaml) (scoping a fork skill's tools), [`examples/skills_filter.yaml`](https://github.com/docker/docker-agent/blob/main/examples/skills_filter.yaml) (filtering which skills load). diff --git a/_vendor/github.com/docker/docker-agent/docs/features/snapshots/index.md b/_vendor/github.com/docker/docker-agent/docs/features/snapshots/index.md deleted file mode 100644 index bc624bf89123..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/snapshots/index.md +++ /dev/null @@ -1,112 +0,0 @@ ---- -title: "Snapshots" -description: "Shadow-git snapshots capture your workspace at turn boundaries so you can review what an agent changed and undo it without touching your real git history." -keywords: docker agent, ai agents, features, snapshots -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/features/snapshots/ ---- - -_Shadow-git snapshots capture your workspace at turn boundaries so you can review what an agent changed and undo it without touching your real git history._ - -## Overview - -When snapshots are enabled, Docker Agent records the state of your working -directory as the agent runs. Each checkpoint is stored in a **shadow git -repository** kept under the Docker Agent data directory — completely separate -from your project's own `.git`. This lets you: - -- **Review** exactly which files an agent touched on a given turn. -- **Undo** the most recent change with `/undo`. -- **Reset** the workspace back to any earlier checkpoint — or all the way to - its pre-agent state. - -Snapshots only ever touch files on disk. They never write commits to your -repository, never move your `HEAD`, and never appear in `git log` or -`git status`. - -> [!NOTE] -> **Git repositories only** -> -> The snapshot machinery is a no-op outside a git worktree. It needs a git -> repository to scope which files belong to your project and to mirror the -> repository's ignore rules. - -## Enabling Snapshots - -The simplest way is to enable snapshots globally for every agent in your user -config: - -```yaml -# ~/.config/cagent/config.yaml -settings: - snapshot: true -``` - -Omit `snapshot` or set it to `false` to leave automatic snapshots off. - -You can also wire the [`snapshot` built-in hook](../../configuration/hooks/index.md#available-built-ins) -into a single agent instead of enabling it globally: - -```yaml -hooks: - turn_start: - - type: builtin - command: snapshot - turn_end: - - type: builtin - command: snapshot - session_end: - - type: builtin - command: snapshot -``` - -Manually configured snapshot hooks always run, even when `settings.snapshot` -is unset. See [`examples/snapshot_hooks.yaml`](https://github.com/docker/docker-agent/blob/main/examples/snapshot_hooks.yaml) -for a complete configuration. - -## Using Snapshots in the TUI - -When snapshots are enabled, the [TUI](../tui/index.md) -exposes two slash commands: - -- **`/undo`** restores files from the most recent snapshot (one step back). -- **`/snapshots`** opens a dialog listing every captured snapshot and the - number of files in each. Use / (or - j/k) to highlight an entry, then press r to - reset the workspace to that point. Pick `` to revert every snapshot - and bring the workspace back to its pre-agent state. Esc closes the - dialog without changing anything. - -Neither command removes messages from the session transcript — they only touch -files on disk. Both commands (and their command-palette entries) are hidden -when snapshots are turned off. - -## How It Works - -- **Shadow repository.** The first time a snapshot is taken for a worktree, - Docker Agent initializes a separate shadow git directory under the data - directory (`~/.cagent/snapshot/...` by default), keyed by a hash of the - worktree path. The shadow repo stores tree objects only — it never writes - commits and never touches your source repository's `.git`. -- **Ignore rules are mirrored.** Before each capture, the source repository's - `.gitignore` and `info/exclude` rules are mirrored into the shadow repo so - ignored files never appear in snapshots. -- **Large files are skipped.** Newly-added files larger than 2 MiB are excluded - from snapshots to keep the shadow repo small. -- **Checkpoints only on change.** A checkpoint is recorded only when files - actually changed, so a final no-op model response does not hide the last - meaningful snapshot. -- **Scoped to the working directory.** Snapshot operations are scoped to the - agent's working directory within the worktree, so a sub-directory agent only - captures and restores files under that directory. -- **Garbage collection.** Wiring `snapshot` into `session_end` (or enabling it - globally) runs `git gc` against the shadow repo so old, unreferenced objects - are pruned over time. - -## See Also - -- [Hooks](../../configuration/hooks/index.md) — the `snapshot` - built-in and the events it can run on. -- [Terminal UI](../tui/index.md) — the `/undo` and - `/snapshots` commands. -- [`examples/snapshot_hooks.yaml`](https://github.com/docker/docker-agent/blob/main/examples/snapshot_hooks.yaml) — a complete snapshot hook configuration. diff --git a/_vendor/github.com/docker/docker-agent/docs/features/tui/index.md b/_vendor/github.com/docker/docker-agent/docs/features/tui/index.md deleted file mode 100644 index 5a06b6ebbc88..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/features/tui/index.md +++ /dev/null @@ -1,591 +0,0 @@ ---- -title: "Terminal UI (TUI)" -description: "Docker Agent's default interface is a rich, interactive terminal UI with file attachments, themes, session management, and more." -keywords: docker agent, ai agents, features, terminal ui (tui) -linkTitle: "Terminal UI" -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/features/tui/ ---- - -_Docker Agent's default interface is a rich, interactive terminal UI with file attachments, themes, session management, and more._ - -![Docker Agent TUI in action showing an interactive agent session](../../demo.gif) - -## Launching the TUI - -Both the full TUI and the lean TUI display a centered ASCII art Docker Agent banner on startup when the chat is empty. The banner is automatically hidden once the agent starts responding or when a custom welcome message is configured. - -```bash -# Launch with a config -$ docker agent run agent.yaml - -# Start with an initial message -$ docker agent run agent.yaml "Help me refactor this code" - -# Auto-approve all tool calls -$ docker agent run agent.yaml --yolo - -# Enable debug logging -$ docker agent run agent.yaml --debug - -# Override the application name shown in the status bar and window title -$ docker agent run agent.yaml --app-name "My Project" - -# Preselect a color theme -$ docker agent run agent.yaml --theme dracula - -# Hide the sidebar (cannot be re-enabled via Ctrl+B) -$ docker agent run agent.yaml --sidebar=false - -# Disable specific slash commands -$ docker agent run agent.yaml --disable-commands="/cost,/eval,/model" - -# Open in read-only mode to review a past session without sending new messages -$ docker agent run agent.yaml --session -1 --session-read-only - -# Use the lean TUI for this run -$ docker agent run agent.yaml --lean -``` - -### Lean TUI - -The lean TUI uses a simplified terminal interface with minimal chrome. To make it the default for interactive runs, set `lean` in your user config: - -```yaml -# ~/.config/cagent/config.yaml -settings: - lean: true -``` - -Omit `lean` or set it to `false` to keep the full TUI as the default. You can still use `--lean` for a single run, or `--lean=false` to use the full TUI when `settings.lean` is enabled. See [User Settings](../../configuration/user-settings/index.md) for the full precedence rules between flags and user config. - -The lean TUI supports **steering** and **follow-ups** while the agent is running. Press Enter to steer the active turn, or Alt+Enter to queue the message as a separate turn after the current one finishes. Pending messages appear with muted styling at the end of the live stream. - -The lean TUI supports a focused set of slash commands: `/new`, `/compact`, `/model`, `/effort`, `/clear`, `/help`, `/exit` (alias: `/quit`), plus any agent-defined commands. Type `/model` (or `/model `) to switch the active model inline — the command opens a fuzzy-searchable list of available models. - -## Slash Commands - -Type `/` during a session to see available commands, or press Ctrl+K for the command palette: - -| Command | Description | -| ------------------ | ------------------------------------------------------------------------------------ | -| `/new` | Start a new conversation | -| `/clear` | Clear the current conversation (keep session, drop messages) | -| `/compact` | Summarize and compact the conversation history | -| `/fork` | Fork the current session into a new branch | -| `/copy` | Copy the entire conversation to clipboard | -| `/copy-last` | Copy only the last assistant message to clipboard | -| `/undo` | Restore file changes from the latest snapshot (only when snapshots are enabled) | -| `/snapshots` | List captured snapshots (only when snapshots are enabled) | -| `/export` | Export the session as HTML | -| `/sessions` | Browse and load past sessions | -| `/plans` | Browse and manage plans: every [shared plan](../../tools/plan/index.md) plus the current session's [session plan](../../tools/session_plan/index.md). Filter, open a detail view, refresh, export to a file, and — for shared plans — set status, edit/create in `$VISUAL`/`$EDITOR`, and delete, all guarded against concurrent edits. Not available in the lean TUI | -| `/model` | Change the model for the current agent | -| `/effort` | Set the current model's reasoning-effort level (`/effort `, or `/effort` alone to pick from the supported levels; reasoning models only). Press Tab after `/effort` and a space to complete a level the current model supports | -| `/settings` | Manage appearance, behavior, and notification preferences | -| `/yolo` | Toggle automatic tool call approval | -| `/title` | Set or regenerate session title | -| `/attach` | Attach a file to your message | -| `/shell` | Open a shell | -| `/star` | Star/unstar the current session | -| `/context` | Show a context-window breakdown: estimated tokens per category (system prompt, tool definitions, prompt files, messages, tool results, compaction summary), a team-level **Live sessions** view (the current session plus every running sub-agent session with its agent, short session ID, and context budget), plus a per-file inventory of attached files and prompt files. When a compaction has occurred, the dialog also displays the verbatim text of the most recent compaction summary. When a dedicated `compaction_model` caps the effective limit below the primary model's own window, a second line reads "compaction cap: `` • `` tokens" — Live-sessions rows are silent on the cap, and the sidebar shows a minimal ⚠ capped marker without repeating the model or the figure (the `/context` header is the authoritative source of the model + number). Use the arrow keys to select a row: press Enter on a live session to explicitly compact it, or d on an attached file to drop it | -| `/drop` | Remove an attached file from the session context (`/drop `, or `/drop` alone to review and drop from the `/context` dialog). Press Tab after `/drop` and a space to complete an attached file's path | -| `/cost` | Show cost breakdown for this session. Includes a **By Agent** section (alongside **By Model**) showing cumulative cost per agent; unattributed usage and compaction spend appear in their own buckets. | -| `/eval` | Create an evaluation report | -| `/pause` | Pause/resume the runtime loop. While the agent is mid-request, the resize handle shows "Pausing…" until the in-flight request completes; once the loop is blocked the indicator changes to "⏸ Paused". Run `/pause` again to resume. | -| `/tools` | Show every toolset (with lifecycle state) and the tools they expose | -| `/skills` | List skills available to the current agent | -| `/toolset-restart` | Force a supervisor-driven reconnect of the named toolset (`/toolset-restart `). Press Tab after `/toolset-restart` and a space to complete a toolset name; non-restartable toolsets are shown dimmed and cannot be selected. | -| `/permissions` | Inspect and edit tool permission rules | -| `/speak` | Voice input via system speech-to-text (macOS only) | -| `/exit` | Exit the application (aliases: `/quit`, `/q`) | - -Slash commands (both built-in and named) execute immediately when entered. Regular chat messages sent while the agent is working are steered into the ongoing stream by default: the agent picks them up mid-turn (they appear in the transcript at the point the agent sees them) without breaking the stream. Prefer the previous end-of-turn behavior? Switch **While agent is working** to `Queue` on the **Behavior** tab of `/settings`; queued messages are processed in order once the stream stops. - -Agent-defined commands (prompts, URL links, agent-switching shortcuts) are configured under `commands:` in the agent YAML — see [Custom Commands](../../configuration/commands/index.md) for the full reference, including how to hide commands with `--disable-commands`. - -### Agents Panel - -The sidebar's **Agents** section lists every agent in the team and has two display modes selectable via **Sidebar info mode** in `/settings`: - -- **Compact** (default) — The current agent is shown as a focus **card** (rendered in place at its position in the list) with its name, a wrapped description, its full `provider/model`, and a thinking line. Every other agent is shown as a compact **two-line row** — line 1 is the shortcut/spinner, the agent name (in its accent color), and a right-aligned thinking **gauge**; line 2 is the indented full `provider/model` and, once the agent has run, its latest **context usage** as a right-aligned percentage of its context window. -- **Detailed** — Each agent is shown as a responsive card with labeled **Effort**, **Context**, and **Cost** metrics on a single line (or split across lines at narrow sidebar widths), making cumulative per-agent cost visible at a glance across the team. - -Agents are separated by a blank line so rows stay visually distinct. The effort **gauge** is the only visual language for thinking; the focus card and the Agent Inspector spell out the exact level alongside it. Left-click any agent to switch to it. - -On large teams the roster can be trimmed to the agents that matter right now: enable **Active agents only** (nested under **Agents** in `/settings` → Appearance → Sidebar sections, off by default) to list only agents active in the current session — the selected or working agent, participants of an in-flight transfer, and any agent with recorded participation (usage or attributed cost, including agents restored with a reloaded session). The filter also applies to the top/bottom band, is purely presentational — Ctrl+number shortcuts keep their original team positions and agent cycling still walks the whole team — and is unavailable while the Agents section itself is hidden. - -#### Agent inspector - -Open a read-only **Agent Inspector** to inspect any agent's full configuration combined with its live state. The instruction/system prompt is deliberately omitted; everything else the agent declares is shown: - -- **Right-click any agent** (card or row) to open the inspector without switching to it. -- **Ctrl+left-click any agent** does the same — a fallback for terminals that don't forward right-clicks. -- **Left-click** always switches to the agent. - -The title is rendered in the agent's accent color. Sections appear in this order, and any empty section is omitted: - -- **Description** — the agent's wrapped description. -- **Live state** — a `● current agent` line when the inspected agent is the one currently running. -- **Model / Fallback / Thinking** — the `provider/model`, any fallback models, and the gauge + value thinking line (omitted for models with no selectable thinking, e.g. harness-backed agents). -- **Context** — the agent's latest known context usage, e.g. `Context: 12.8K of 128.0K tokens (10%)` (a bare token count when the context limit is unknown; omitted until the agent has run). Sub-agent and background-agent runs are accounted for. When a dedicated `compaction_model` caps the effective limit below the primary model's own window, the token-usage line also shows a short "⚠ capped" marker (see `/context` for the model and figure). -- **Cost** — the agent's cumulative cost across all runs in the session tree. Repeated session snapshots are not double-counted. Omitted until the agent has run. -- **Sub-agents (N) / Handoffs (N) / Skills (N)** — compact, inline, comma-separated lists wrapped to the dialog width. -- **Limits** — the configured per-agent limits that are set, e.g. `Limits: max-iter 50 · history 40 · max-tool-calls 5`. -- **Options** — the enabled option flags, e.g. `Options: add-date · add-environment-info · redact-secrets`. -- **Toolsets (N)** — one line per toolset with a status marker, its name, kind, and tool count, followed by the indented tool names. -- **Commands (N)** — the slash commands the agent defines, each with its description. - -Each toolset carries a single-width status marker reflecting its **live** lifecycle: `●` started (serving), `○` stopped (not yet started), or `⚠` error. The tools listed under a toolset are the **live** tool names when it has started; for a toolset that has not started, the inspector instead shows its declared `tools:` allow-list prefixed with `declared:` (and shows nothing when the toolset declares no allow-list and therefore serves every tool). This lets you see both what an agent is configured with and what is actually running, even before the agent has been used. - -The dialog scrolls when the content is long; press Esc to close it. Remote runtimes (which hold no local team config) degrade gracefully — the config-derived sections are simply omitted. - -Model identifiers on line 2 are truncated **from the left** (e.g. `…claude-sonnet-4-6`) only when they overflow, so the informative tail (variant/version) is preserved. As the sidebar narrows the model keeps its own line, and near the minimum width line 1's gauge collapses to a single cell to keep the name readable. - -The thinking state of each model is shown with a gauge + value on the card and a gauge or badge on the row (no `✻` glyph): - -| Model state | Card line | Row badge | -| ---------------------- | ------------------------------ | ---------------------- | -| Effort level | `thinking ▰▰▰▰▱▱ high` | `▰▰▰▰▱▱` (effort gauge) | -| Adaptive budget | `thinking auto adaptive` | `auto` | -| Token budget | `thinking ◉ 8.2K tokens` | `◉ 8.2K` | -| Disabled (capable) | `thinking ▱▱▱▱▱▱ off` (dimmed) | `▱▱▱▱▱▱` (empty gauge) | -| Not reasoning-capable | _(omitted)_ | _(omitted)_ | - -The **effort gauge** is a fixed-width six-cell indicator (`▰` filled, `▱` empty) so the badge column stays aligned. It maps the six selectable levels one-to-one onto filled-cell counts — `minimal` → `▰▱▱▱▱▱`, `low` → `▰▰▱▱▱▱`, `medium` → `▰▰▰▱▱▱`, `high` → `▰▰▰▰▱▱`, `xhigh` → `▰▰▰▰▰▱`, `max` → `▰▰▰▰▰▰` — so the cell count alone is lossless, with a low→high color ramp as a secondary cue. A capable-but-disabled model shows a dim empty gauge (`▱▱▱▱▱▱` `off`), adaptive budgets show `auto`, and token budgets keep `◉ `. The same gauge + value renders on the focus card, the Agent Inspector, and the row. - -Harness-backed agents (e.g. `claude-code`) show the harness type as their model and no thinking gauge. Press **Shift+Tab** to cycle the current model's thinking-effort level; a `✻ Thinking: ` toast confirms the change (useful when the sidebar is hidden). - -### Agent Delegation Feedback - -When a parent agent calls `transfer_task` to delegate work to a sub-agent, the TUI provides live visual feedback in both the sidebar and the chat. - -**Sidebar — Transfer box:** As soon as the delegation starts, an animated **Transfer** box appears below the agent roster, showing the direction of the handoff with a traveling dot: - -```text -╭─ Transfer ─────────────────╮ -│ parent ●──────► child │ -╰────────────────────────────╯ -``` - -The box stays visible for at least 1.5 seconds. Once the sub-agent produces its first message, reasoning, or tool output, the box hides (still honoring the minimum window) to keep the sidebar focused on the active agent. If the sub-agent is slow or silent, the box hides after a 3-second maximum cutoff. The header shows a `↔` marker while any delegation is still in flight, even after the box hides. - -**Sidebar — Return box:** When the sub-agent finishes and control returns to the parent, a brief **Return** box animates the reverse direction for up to 1.5 seconds, then disappears: - -```text -╭─ Return ───────────────────╮ -│ child ●──────► parent │ -╰────────────────────────────╯ -``` - -**Chat — return transition:** Alongside the sidebar Return animation, the chat shows a one-line static transition between the two agent badges: - -```text -[child] returned control to [parent] -``` - -This transition is not persisted — it does not reappear when you reload the session. - -### Context-Usage Gauge - -The context percentage shown in the sidebar token-usage section, and the fill bar in the lean TUI status line, both color-escalate as the active session approaches the auto-compaction threshold: - -| State | Color | Trigger | -| ------- | ------ | ------- | -| Normal | (default) | Usage below 75% of the compaction threshold | -| Warning | Orange | Usage at or above 75% of the compaction threshold | -| Critical | Red | Usage at or above 95% of the compaction threshold | - -While a compaction is running the percentage is replaced by a **"compacting…"** indicator; token counts remain visible in the lean TUI status line. - -The thresholds are proportional to the agent's configured `compaction_threshold` (default `0.9`), so a custom value keeps a predictable visual runway. See [Compaction Threshold](../../configuration/models/index.md#delegating-session-compaction) for configuration details. - -Clicking the token/context part of the sidebar's usage reading (the glyph, token count, context percentage — or the "compacting…" marker — and the `⚠ capped` marker) opens the `/context` dialog with the full breakdown. Clicking the cost part (the `$` figure and the sub-session count) opens the `/cost` dialog instead. The "Token Usage" section title itself is not clickable. - -### Thinking and Tool Details - -Reasoning/thinking blocks are collapsed by default and carry a `Thinking` header badge. When collapsed, the TUI shows a short preview and compact tool summaries. Expand a block to see the full thinking content and the real tool renderers, including detailed tool output such as file edit diffs. - -To start new sessions with thinking/tool blocks expanded by default, set `expand_thinking` in your user config: - -```yaml -# ~/.config/cagent/config.yaml -settings: - expand_thinking: true -``` - -Set it to `false` or omit it to keep the default collapsed behavior. See [User Settings](../../configuration/user-settings/index.md) for the full settings reference. - -### Mermaid Diagrams - -The TUI renders Mermaid diagram blocks inline rather than displaying raw syntax. When an assistant message contains a fenced code block tagged ` ```mermaid `, the TUI parses the diagram and draws an ASCII representation directly in the conversation: - -| Diagram type | Support | -| ---------------------------------------------- | ------------------------------------------------- | -| `graph` / `flowchart` | ✅ Rendered inline | -| `sequenceDiagram` | ✅ Rendered inline | -| `stateDiagram` / `stateDiagram-v2` | ✅ Rendered inline (supports `direction TD/TB/BT/LR/RL`) | -| Other types (`classDiagram`, `erDiagram`, …) | Falls back to a syntax-highlighted code block | - -Mermaid rendering works in both the full TUI and the lean TUI. Unsupported or syntactically invalid diagram blocks are displayed as ordinary fenced code blocks — no configuration is required and there is no way to disable it. - -### LaTeX Math Rendering - -The TUI renders LaTeX math expressions as terminal-friendly Unicode text. When an assistant message contains inline math (delimited by `$…$`) or display math (delimited by `$$…$$`), the TUI converts supported LaTeX commands to their Unicode equivalents and displays them directly in the conversation. - -Supported features include: - -- Greek letters (`\alpha`, `\beta`, `\gamma`, …) -- Mathematical operators (`\times`, `\div`, `\pm`, `\oplus`, …) -- Relations (`\le`, `\ge`, `\approx`, `\equiv`, …) -- Set operators (`\cap`, `\cup`, `\subset`, `\in`, …) -- Calculus symbols (`\int`, `\sum`, `\prod`, `\partial`, `\nabla`, …) -- Arrows and logic (`\to`, `\implies`, `\forall`, `\exists`, …) -- Superscripts and subscripts (e.g., `x^2`, `a_i`) -- Fractions (`\frac{a}{b}`), square roots (`\sqrt{x}`), and matrices -- Common functions (`\sin`, `\cos`, `\log`, `\lim`, …) - -Unsupported or syntactically invalid LaTeX expressions fall back to displaying the raw source. LaTeX rendering works in both the full TUI and the lean TUI, requires no configuration, and cannot be disabled. - -### Markdown Images - -The TUI fetches and renders images referenced in agent responses using the Kitty graphics protocol. When an assistant message contains a standard Markdown image reference, the TUI downloads the image in the background and displays it inline at the point of the reference. While the image is loading a placeholder is shown; once loaded, the message re-renders with the image in place. - -Only `http://`, `https://`, and `data:image/…;base64,…` URIs are resolved. `file://`, `sandbox://`, and any other URI scheme are rejected as a security measure against prompt-injection attacks that could otherwise read local files. Bare relative paths (e.g. `./output.png`, used for agent-generated images) are read via the local filesystem. Images that fail to load are silently dropped — the surrounding message text is unaffected. Image rendering requires a terminal that supports the Kitty graphics protocol; it is automatically disabled when the terminal does not support it. You can also disable it explicitly via `render_images: false` in `~/.config/cagent/config.yaml` or the **Render images** toggle in `/settings`. - -### Snapshots, `/undo`, and `/snapshots` - -Enable shadow-git snapshots globally in `~/.config/cagent/config.yaml`: - -```yaml -settings: - snapshot: true -``` - -When enabled, Docker Agent records filesystem snapshots at turn boundaries. The TUI exposes two slash commands that operate on those snapshots: - -- **`/undo`** restores files from the most recent snapshot (one step back). -- **`/snapshots`** opens a dialog showing how many snapshots have been captured and the number of files in each one. Use / (or j/k) to highlight an entry, then press r to reset the workspace to that point. Pick `` to revert every snapshot and bring the workspace back to its pre-agent state. Esc closes the dialog without changing anything. - -Neither command removes messages from the session transcript — they only touch files on disk. Both commands (and the matching command-palette entries) are hidden when snapshots are turned off. Omit `snapshot` or set it to `false` to leave automatic snapshots off; agents can still configure snapshot hooks manually. - -See [Snapshots](../snapshots/index.md) for how the shadow-git machinery works and how to wire it per-agent. - -## File Attachments - -Attach file contents to your messages using the `@` trigger: - -1. Type `@` to open the file completion menu -2. Start typing to filter files (respects `.gitignore`) -3. Select a file to insert the reference - -```bash -# In the chat input: -Explain what the code in @pkg/agent/agent.go does -``` - -The agent receives the full file contents in a structured `` block, while the UI shows just the reference. - -For large or frequently-reused documents, or for getting content to an agent over the API or chat server instead of the TUI, see [Choosing a Large-Input Strategy](../../guides/headless/index.md#choosing-a-large-input-strategy). - -Attached files are also recorded on the session so sub-agents spawned by task transfer can read them. To review what is attached, open `/context`: the dialog lists every attached file (and resolved prompt file) with a per-file token estimate and, when a compaction has occurred, displays the verbatim text of the most recent compaction summary. Use / to select an attached file and press d (or x/Del) to drop it, or run `/drop ` directly — press Tab after `/drop` and a space to complete the path from the currently attached files. Dropping stops sharing the file with sub-agents and skills; content already inlined in earlier messages stays in the conversation until compaction, and the file can always be re-attached with `@` or `/attach`. - -### Team Context Budgets and Targeted Compaction - -The `/context` dialog also shows a **Live sessions** section: the current session plus every currently running sub-agent session (foreground children spawned by task transfer and long-running `run_background_agent` tasks). Each row shows the agent name, a short session ID (so two concurrent runs of the same agent stay distinguishable), and that session's context budget: used tokens, context limit, and percentage, or an explicit "limit unknown" reading when the model's window cannot be resolved. Live-sessions rows do not repeat the compaction-cap wording themselves — the dialog's header line is the sole authority on which model, if any, caps the effective limit. - -When a compaction has occurred, the dialog displays the verbatim text of the most recent compaction summary below the file inventory, under a "Latest compaction summary" section. This shows exactly what was summarized, preserving hard newlines and soft-wrapping long lines to the dialog width. - -Select a live session with / and press Enter to explicitly compact it. Cross-agent compaction happens only on this explicit request: no idle-triggered automatic compaction is added, and the existing automatic threshold and overflow-recovery compaction of sub-agent sessions is unchanged. The request is queued onto the target session's own run loop and executes at the next safe point between model turns, so it cannot corrupt an in-flight turn. The dialog closes and a notification confirms the request; a second notification reports the outcome (compacted, skipped, or failed) with the agent's name. Selecting the main row runs the same compaction as `/compact`. `/compact` itself keeps compacting the current root session. Remote runtimes do not expose live-session tracking, so the section is omitted there. - -## Runtime Model Switching - -Change the AI model during a session with `/model` or Ctrl+M. Model switching works in both the full TUI and the lean TUI. - -1. Press Ctrl+M (full TUI) or type `/model` (both TUIs) -2. Select from config models or type a custom `provider/model` -3. The model switch is saved with the session and restored on reload - -When a models gateway is configured (`--models-gateway`) and it exposes an OpenAI-style `/v1/models` endpoint, the picker lists the models actually served by the gateway (merged with the models defined in the agent config). When the gateway doesn't expose `/v1/models`, the picker falls back to the regular catalog. - -The picker's catalog entries come from [models.dev](https://models.dev) and are cached locally for a day. Press Ctrl+R in the picker to force model discovery to run again, including a refetch of the models.dev catalog. - -> [!TIP] -> Use model switching to try a more capable model for complex tasks, or a cheaper one for simple queries — without modifying your YAML config. - -## Editable Messages - -Edit any previous user message to branch the conversation. Hover a past user message and click **✎ edit** (or select it with the keyboard and press e) to modify it — the agent will re-process from that point, while the original session history is preserved. This is great for exploring alternative approaches without losing your work. - -Hovering a user or assistant message also reveals a **⎘ copy** button that copies the message text to the clipboard (c when a message is selected). - -## Error Recovery - -When an agent turn fails (fatal model error, hook block, loop detection, tool-setup failure), the TUI displays the error in the message stream and persists it to the session store. Errors survive a reload and are shown exactly where they occurred, making them visible in shared or remote sessions. - -Each error message includes a clickable **↻ retry** button. Clicking it resumes the conversation from the point of failure — without retyping your last message. This lets you recover from transient failures (rate limits, network blips, model API errors) in one click. - -## Session Management - -Docker Agent automatically saves your sessions. Use `/sessions` to browse past conversations: - -- **Browse** past sessions with search and filtering. The search matches against session **titles** and **session IDs** (full UUIDs, dash-less variants, and partial fragments all resolve correctly — useful when jumping back to a session from a copied ID or log). -- **Workspace grouping**: sessions are grouped by **git repository root** (worktree-aware) — sessions from any subdirectory or linked worktree of the same repository are grouped together under "This workspace", and the header shows the repository root path. Sessions outside the current repository appear under "Other locations" with their originating directory. Press Ctrl+G in the browser to cycle between all, current-workspace only, and other-directory views. Restoring a session reopens it in its original directory, so the label always matches where a restore will land. -- **Star** important sessions with `/star` -- **Branch** conversations by editing any previous user message — preserving the original session history -- **Resume** sessions with `docker agent run config.yaml --session ` -- **Relative refs**: `--session -1` for the last session, `-2` for the one before - -### Session Title Editing - -Customize session titles to make them more meaningful and easier to find. By default, Docker Agent auto-generates titles based on your first message, but you can override or regenerate them at any time. - -**Using the `/title` command:** - -```bash -/title # Regenerate title using AI (based on recent messages) -/title My Custom Title # Set a specific title -``` - -**Using the sidebar:** - -1. Click the pencil icon (✎) next to the session title in the sidebar -2. Type your new title -3. Press Enter to save, or Escape to cancel - -> [!NOTE] -> Manually set titles are preserved and won’t be overwritten by auto-generation. Title changes are persisted immediately to the session. - -## Keyboard Shortcuts - -| Shortcut | Action | -| ---------- | ----------------------------------------------- | -| Ctrl+K | Open command palette | -| Ctrl+M | Switch model | -| Ctrl+R | Reverse history search (search previous inputs) | -| Ctrl+G | Cancel reverse history search | -| Ctrl+S | Cycle to next agent in the team | -| Shift+Tab | Cycle the current model's thinking-effort level (shows a `✻ Thinking: ` toast) | -| Ctrl+1 – 9 | Switch directly to agent _N_ in the team list | -| Ctrl+T | Open a new tab (additional agent session) | -| Ctrl+W | Close the current tab | -| Ctrl+N | Next tab | -| Ctrl+P | Previous tab | -| Ctrl+B | Toggle the sidebar (full-UI mode only; disabled when --sidebar=false) | -| Ctrl+Y | Toggle YOLO mode (auto-approve tool calls) | -| Ctrl+O | Toggle hide tool results | -| Ctrl+Z | Suspend TUI to background (resume with `fg`) | -| Ctrl+X | Clear queued messages | -| Escape | Cancel current operation | -| Enter | Send message (or steer while the agent is running) | -| Alt+Enter | Queue a follow-up turn while the agent is running | -| Shift+Enter | Insert a newline | -| Up/Down | Navigate message history | - -Press Ctrl+H to view the complete list of all available keyboard shortcuts. - -### Custom Keybindings - -You can remap the shortcuts above by adding a `keybindings` list to the `settings` block of your `~/.config/cagent/config.yaml` (see [User Settings](../../configuration/user-settings/index.md#settings-reference) for the field reference). Each entry maps an action to one or more key combinations in [Bubbles key format](https://github.com/charmbracelet/bubbles) (for example `ctrl+q`, `alt+enter`, `f2`). Unlisted actions keep their defaults. - -This is the recommended way to replace the `Ctrl+J` newline fallback, which conflicts with common editor/terminal shortcuts (for example inside VS Code). - -```yaml -settings: - keybindings: - # Insert a newline with Alt+Enter instead of Ctrl+J. Shift+Enter still - # works automatically on terminals that report it. - - action: "editor_newline" - keys: ["alt+enter"] - # Allow several keys for one action. - - action: "commands" - keys: ["f2", "ctrl+k"] - - action: "quit" - keys: ["ctrl+q"] -``` - -**Valid actions:** - -| Action | Default | Description | -| -------------------------- | ------------ | -------------------------------------- | -| `editor_send` | `enter` | Send the current message | -| `editor_newline` | `ctrl+j` | Insert a newline in the input | -| `quit` | `ctrl+c` | Quit (opens the exit confirmation) | -| `switch_focus` | `tab` | Switch focus between panels | -| `commands` | `ctrl+k` | Open the command palette | -| `help` | `ctrl+h` | Show the help dialog | -| `toggle_yolo` | `ctrl+y` | Toggle YOLO mode | -| `toggle_hide_tool_results` | `ctrl+o` | Toggle hiding tool results | -| `cycle_agent` | `ctrl+s` | Cycle to the next agent | -| `model_picker` | `ctrl+m` | Open the model picker | -| `clear_queue` | `ctrl+x` | Clear queued messages | -| `suspend` | `ctrl+z` | Suspend the TUI | -| `toggle_sidebar` | `ctrl+b` | Toggle the sidebar | -| `edit_external` | `ctrl+g` | Edit input in an external editor | -| `history_search` | `ctrl+r` | Incremental history search | - -`Shift+Enter` for newline is detected from your terminal's capabilities and is always available where supported, independent of `editor_newline`. - -Invalid entries are ignored with a warning (visible with `--debug`) so a bad config never breaks the TUI: unknown actions, empty or malformed keys, and keys that would collide with another action are dropped while every other binding keeps working. - -## History Search - -Press Ctrl+R to enter incremental history search mode. Start typing to filter through your previous inputs. Press Enter to select a match, or Escape to cancel. - -## Settings - -Run `/settings` to open the settings dialog. Use Tab to switch between **Appearance**, **Behavior**, and **Notifications**. - -> [!TIP] -> **Full settings reference** -> -> This section covers the `/settings` dialog. For the complete list of `settings:` fields (including ones with no dialog UI, like `permissions`, `hooks`, and `keybindings`) and how they interact with CLI flags and aliases, see [User Settings](../../configuration/user-settings/index.md). - -The **Appearance** tab selects the theme and customizes the layout. Layout changes show a live schematic preview and apply immediately to the UI behind the dialog: - -- **Sidebar position**: `Right` (default), `Left`, `Top`, or `Bottom`. Left/right keep the full vertical sidebar next to the chat; top/bottom render it as a compact horizontal band above or below the chat (session title, working directory, token usage, plus a one-line summary of the current agent and its model; in multi-agent configurations all team agents are listed by name after the current agent). -- **Sidebar info mode**: `Compact` (default) or `Detailed`. Controls how the Agents panel renders agent rows — see [Agents Panel](#agents-panel) for details. Persisted as `settings.layout.sidebar_info_mode: detailed`; compact is the default and omitted from the config. -- **Section spacing**: `Compact`, `Normal` (default), or `Relaxed`, the number of blank lines between the sidebar sections (1, 2, or 3). -- **Sidebar sections**: toggle the visibility of the **Session path** (the working directory line, including its git branch) and the **Token usage**, **Agents**, **Tools**, and **Todos** sections. The session title is always shown. - -Appearance also controls split-diff rendering, expanded thinking, and whether tool results are hidden by default. Select **Theme** to open the theme picker. - -The **Behavior** tab controls busy-message handling, the auto-approve default, tab restoration, automatic snapshots, lean UI, and the maximum tab-title length. Restore-tabs and lean-UI changes take effect on the next launch. Enabling auto-approve requires confirmation. - -The **Notifications** tab enables completion sounds and sets the minimum task duration before a sound plays. - -Press Enter to apply and persist, or Escape to cancel and restore the previous layout. The settings are saved globally in `~/.config/cagent/config.yaml`: - -```yaml -# ~/.config/cagent/config.yaml -settings: - busy_send_mode: queue # steer (default), queue - layout: - sidebar_position: left # right (default), left, top, bottom - sidebar_info_mode: detailed # compact (default, omitted), detailed - section_spacing: compact # normal (default), compact, relaxed - hide_session_path: false - hide_usage: true - hide_agents: false - active_agents_only: false # true to filter to session-active agents - hide_tools: false - hide_todos: false -``` - -## Theming - -Customize the TUI appearance with built-in or custom themes: - -```bash -# Open Settings and select Theme under Appearance -/settings -``` - -### Built-in Themes - -`default`, `default-light`, `catppuccin-latte`, `catppuccin-mocha`, `dracula`, `gruvbox-dark`, `gruvbox-light`, `nord`, `one-dark`, `solarized-dark`, `tokyo-night` - -### Auto Theme (match the terminal) - -The special theme `auto` follows the terminal's light/dark background instead of naming a fixed theme. Select **Auto (match terminal)** from **Settings → Appearance → Theme**, pass `--theme auto`, or set it in your user config: - -```yaml -settings: - theme: auto - theme_dark: default # optional, theme used on dark backgrounds (default: default) - theme_light: default-light # optional, theme used on light backgrounds (default: default-light) -``` - -At startup the terminal background is queried (OSC 11) to pick the dark or light theme of the pair; non-interactive runs (pipes, CI) fall back to the dark theme. In terminals that report appearance changes (DEC mode 2031 — Ghostty, kitty, contour, …), flipping the OS or terminal appearance while Docker Agent is running switches the theme live. Terminals without that mode re-sync when the window regains focus. - -### Custom Themes - -Create theme files in `~/.cagent/themes/` as YAML. Theme files are **partial overrides** — you only need to specify the colors you want to change. Any omitted keys fall back to the built-in default theme values. - -```yaml -# ~/.cagent/themes/my-theme.yaml -name: "My Custom Theme" - -colors: - # Backgrounds - background: "#1a1a2e" - background_alt: "#16213e" - - # Text colors - text_bright: "#ffffff" - text_primary: "#e8e8e8" - text_secondary: "#b0b0b0" - text_muted: "#707070" - - # Accent colors - accent: "#4fc3f7" - brand: "#1d96f3" - - # Status colors - success: "#4caf50" - error: "#f44336" - warning: "#ff9800" - info: "#00bcd4" - -# Optional: Customize syntax highlighting colors -chroma: - comment: "#6a9955" - keyword: "#569cd6" - literal_string: "#ce9178" - -# Optional: Customize markdown rendering colors -markdown: - heading: "#4fc3f7" - link: "#569cd6" - code: "#ce9178" -``` - -### Applying Themes - -**In user config** (`~/.config/cagent/config.yaml`, see [User Settings](../../configuration/user-settings/index.md) for the full reference): - -```yaml -settings: - theme: my-theme # References ~/.cagent/themes/my-theme.yaml -``` - -**At launch:** Pass `--theme ` to `docker agent run` to preselect a theme for that session. This overrides `settings.theme` in your config but is not saved. Invalid theme names print an error at startup listing the available options. Has no effect in `--exec` mode. `--theme auto` enables the [auto theme](#auto-theme-match-the-terminal) for the session. - -**At runtime:** Open `/settings`, select **Theme** on the Appearance tab, and choose from the available themes. Your selection is saved globally in `~/.config/cagent/config.yaml` under `settings.theme` and persists across sessions. - -> [!TIP] -> **Hot Reload** -> -> Custom themes auto-reload when you save changes to the file — no restart needed. This makes it easy to tweak colors in real-time. - -> [!WARNING] -> **Partial overrides** -> -> All user themes are applied on top of the `default` theme. If you want to customize a built-in theme (e.g., `dracula`), copy its full YAML from the [built-in themes on GitHub](https://github.com/docker/docker-agent/tree/main/pkg/tui/styles/themes) into `~/.cagent/themes/` and edit the copy. Otherwise, omitted values will use `default` colors, not the original theme's colors. - -## Tool Permissions - -When an agent calls a tool, Docker Agent shows a confirmation dialog by default. You can: - -- **Approve once** — Allow this specific call -- **Always allow** — Permanently approve this tool/command for the session -- **Deny** — Reject the tool call - -**Granular permissions:** The permission system supports pattern-based matching. When you “Always allow” a specific tool command, only that exact pattern is auto-approved — other commands from the same tool still require confirmation. This lets you auto-approve safe, read-only operations while maintaining control over destructive ones. - -> [!TIP] -> **YOLO mode** -> -> Use `--yolo` or the `/yolo` command to auto-approve all tool calls. You can also toggle this mid-session. For aliases, set `--yolo` when creating the alias: `docker agent alias add fast myorg/coder --yolo`. - -## Notifications - -The TUI displays transient notification banners for agent warnings, errors, and other runtime events. Notifications auto-dismiss after a short delay unless the mouse is hovering over them — hovering pauses the timer so you have time to read the message. - -| Interaction | Behaviour | -| ----------- | --------- | -| Hover | Pauses auto-dismiss; the notification stays visible until the mouse moves away | -| Click | Copies the notification text to the clipboard | -| × (close) | Dismisses immediately; the glyph turns red when hovered | - -Hint text in the top-left corner of the notification border shows the available actions at a glance. diff --git a/_vendor/github.com/docker/docker-agent/docs/getting-started/_index.md b/_vendor/github.com/docker/docker-agent/docs/getting-started/_index.md deleted file mode 100644 index 46eeae898947..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/getting-started/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Getting Started" -description: "Install Docker Agent and build your first agent." -weight: 10 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/getting-started/installation/index.md b/_vendor/github.com/docker/docker-agent/docs/getting-started/installation/index.md deleted file mode 100644 index 43e52344c5b8..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/getting-started/installation/index.md +++ /dev/null @@ -1,150 +0,0 @@ ---- -title: "Installation" -description: "Get Docker Agent running on your system in minutes." -keywords: docker agent, ai agents, getting started, installation -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/getting-started/installation/ ---- - -_Get Docker Agent running on your system in minutes._ - -## Prerequisites - -- An API key for at least one AI provider (OpenAI, Anthropic, Google, etc.) -- **Optional:** [Docker Desktop](https://www.docker.com/products/docker-desktop/) — for running containerized MCP tools and Docker Model Runner - -## Docker Desktop (Pre-installed) - -Starting with [Docker Desktop 4.63](https://docs.docker.com/desktop/release-notes/#4630), **Docker Agent is already available**. No separate installation needed — just open a terminal and run: - -```bash -$ docker agent version -``` - -> [!TIP] -> Docker Desktop bundles Docker Agent and keeps it up to date. This is the easiest way to get started, especially if you want to use Docker MCP tools and Docker Model Runner. - -## Homebrew (macOS / Linux) - -Install Docker Agent using [Homebrew](https://brew.sh/): - -```bash -# Install -$ brew install docker-agent - -# Verify -$ docker-agent version -``` - -You can also install Docker Agent as a docker CLI plugin, by copying the `docker-agent` binary in `~/.docker/cli-plugins`. You can then run `docker agent version`. - -## Download Binary Releases - -Download [prebuilt binary releases](https://github.com/docker/docker-agent/releases) for Windows, macOS, and Linux from the GitHub Releases page. - -### macOS / Linux - -```bash -# Download the latest release -OS=$(uname -s | tr '[:upper:]' '[:lower:]') -ARCH=$(uname -m); case "$ARCH" in x86_64) ARCH=amd64;; aarch64) ARCH=arm64;; esac -curl -L "https://github.com/docker/docker-agent/releases/latest/download/docker-agent-${OS}-${ARCH}" -o docker-agent -chmod +x docker-agent -sudo mv docker-agent /usr/local/bin/ -docker-agent version - -# or alternatively, instead of moving to /usr/local/bin: -mkdir -p ~/.docker/cli-plugins -sudo mv docker-agent ~/.docker/cli-plugins -docker agent version -``` - -### Windows - -Download `docker-agent-windows-amd64.exe` from the [releases page](https://github.com/docker/docker-agent/releases), rename it to `docker-agent.exe` and add it to your PATH. Alternatively you can move it to `~/.docker/cli-plugins` - -## Optional Self-Updates - -When Docker Agent is installed from a standalone GitHub release binary, you can opt in to automatic self-updates by setting `DOCKER_AGENT_AUTO_UPDATE` to a truthy value (`1`, `true`, `yes`, or `on`): - -```bash -# Enable for one command -DOCKER_AGENT_AUTO_UPDATE=1 docker agent run - -# Or enable for the current shell session -export DOCKER_AGENT_AUTO_UPDATE=1 -docker agent run -``` - -With self-updates enabled, Docker Agent checks the latest GitHub release before normal commands run. If a newer release exists and your session is interactive, Docker Agent asks whether you want to install it or keep running your current version. When the answer is yes (or the session is non-interactive, such as CI or piped input, in which case the update proceeds automatically), it downloads the asset for your OS and architecture, verifies the release-provided SHA-256 digest/checksum, replaces the current binary, and restarts the command with the same arguments. - -Self-updates are fail-safe: if checking, downloading, verifying, installing, or restarting fails, Docker Agent keeps running the current binary. Version/help/completion commands and Docker CLI plugin metadata handshakes do not trigger self-updates. - -> [!NOTE] -> **Package-manager installs** -> -> Docker Desktop and Homebrew already manage Docker Agent updates. Prefer those update mechanisms when you installed Docker Agent that way. Self-updates are mainly intended for standalone release binaries. - -## Build from Source - -For the latest features, or to contribute, build from source: - -### Prerequisites - -- [Go 1.26](https://go.dev/dl/) or higher -- [Task](https://taskfile.dev/installation/) (build tool) -- [golangci-lint](https://golangci-lint.run/docs/welcome/install/local/) (for linting) - -```bash -# Clone the repository -git clone https://github.com/docker/docker-agent.git -cd docker-agent - -# Build the binary -task build - -# The binary is at ./bin/docker-agent -./bin/docker-agent --help -``` - -> [!TIP] -> **Building on Windows** -> -> On Windows, use `task build-local` instead of `task build`. This builds the binary inside a Docker container using Docker Buildx, which avoids issues with Windows-specific toolchain setup and CGo cross-compilation. The output goes to the `./dist` directory. - -## Set Up API Keys - -Docker Agent needs API keys for the model providers you want to use. Set them as environment variables: - -```bash -# Pick one (or more) depending on your provider -export OPENAI_API_KEY="sk-..." # OpenAI -export ANTHROPIC_API_KEY="sk-ant-..." # Anthropic -export GOOGLE_API_KEY="AI..." # Google Gemini (or GEMINI_API_KEY) -export GITHUB_TOKEN="ghp-..." # GitHub Copilot (PAT with copilot scope) -export MISTRAL_API_KEY="..." # Mistral -export OPENROUTER_API_KEY="..." # OpenRouter -``` - -See [Configuration Overview](../../configuration/overview/index.md#environment-variables) for the full list of supported providers and environment variables. - -> [!NOTE] -> You only need the key(s) for the provider(s) you configure in your agent YAML. If you use Docker Model Runner (DMR), no API key is needed — models run locally. - -## Verify Installation - -```bash -# Check the version -$ docker agent version - -# Run the default agent -$ docker agent run - -# Or run an agent from an OCI registry -$ docker agent run myorg/agent:tag -``` - -## What's Next? - -- [**Quick Start**](../quickstart/index.md) — create and run your first agent in under 5 minutes. -- [**Troubleshooting**](../../community/troubleshooting/index.md) — something not working? Debug mode, common issues, and solutions. diff --git a/_vendor/github.com/docker/docker-agent/docs/getting-started/introduction/index.md b/_vendor/github.com/docker/docker-agent/docs/getting-started/introduction/index.md deleted file mode 100644 index 0ade379b873c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/getting-started/introduction/index.md +++ /dev/null @@ -1,74 +0,0 @@ ---- -title: "Introduction" -description: "Docker Agent is a multi-agent runtime that lets you build, run, and share AI agents with a YAML or HCL config — no glue code required." -keywords: docker agent, ai agents, getting started, introduction -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/getting-started/introduction/ ---- - -_Docker Agent is a multi-agent runtime that lets you build, run, and share AI agents with a YAML or HCL config — no glue code required._ - -## What is Docker Agent? - -Docker Agent is an open-source tool from Docker that orchestrates AI -agents with specialized capabilities and tools. Instead of writing -code to wire up LLMs, tools, and workflows, you **declare** your -agents in YAML or HCL — their model, personality, tools, and how they -collaborate — and Docker Agent handles the rest. - -- **Multi-Agent Architecture** — build hierarchical teams of agents that specialize in different tasks and delegate work to each other. -- **Rich Tool Ecosystem** — built-in tools for files, shell, memory, and todos. Extend with any MCP server from [Docker's MCP catalog](https://hub.docker.com/u/mcp). -- **Multi-Model Support** — OpenAI, Anthropic, Google Gemini, AWS Bedrock, Docker Model Runner, and reusable provider definitions with shared defaults. -- **Package & Share** — push agents to OCI registries and pull them anywhere, just like Docker images. -- **Multiple Interfaces** — interactive TUI, headless CLI, HTTP API server, MCP mode, and A2A protocol support. -- **Security-First Design** — tool confirmation prompts, containerized MCP tools via Docker, client isolation, and resource scoping. - -## Why Docker Agent? - -After spending years building AI agents using various frameworks, the -Docker team kept asking the same questions: - -- **How do we make building agents less of a hassle?** — Most agents - use the same building blocks. Docker Agent provides them out of the - box. -- **Can we reuse those building blocks?** — Declarative YAML or HCL - configs mean you can mix and match agents, models, and tools without - rewriting code. -- **How can we share agents easily?** — Push agents to any OCI - registry and run them anywhere with a single command. - -Docker Agent is built in the open so the community can make use of -this work and contribute to its future. - -## How it works - -At its core, Docker Agent follows a simple loop: - -1. **You define agents** in YAML or HCL — their model, instructions, tools, and sub-agents. -2. **You run an agent** via the TUI, CLI, or API. -3. **The agent processes your request** — calling tools, delegating to sub-agents, and reasoning step by step. -4. **Results stream back in real-time** via an event-driven architecture. - -```yaml -# A minimal agent definition -agents: - root: - model: openai/gpt-5 - description: A helpful assistant - instruction: You are a helpful assistant. - toolsets: - - type: think -``` - -```bash -# Run it -$ docker agent run agent.yaml -``` - -> [!TIP] -> Jump straight to the [Quick Start](../quickstart/index.md) if you want to build your first agent right away. - -## What's next? - -- [**Installation**](../installation/index.md) — install Docker Agent on macOS, Linux, or Windows. -- [**Quick Start**](../quickstart/index.md) — build your first agent in under 5 minutes. diff --git a/_vendor/github.com/docker/docker-agent/docs/getting-started/quickstart/index.md b/_vendor/github.com/docker/docker-agent/docs/getting-started/quickstart/index.md deleted file mode 100644 index f3f9056a829d..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/getting-started/quickstart/index.md +++ /dev/null @@ -1,156 +0,0 @@ ---- -title: "Quick Start" -description: "Get up and running with Docker Agent in under 5 minutes. Pick whichever path suits you best." -keywords: docker agent, ai agents, getting started, quick start -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/getting-started/quickstart/ -aliases: - - /ai/docker-agent/tutorial/ ---- - -_Get up and running with Docker Agent in under 5 minutes. Pick whichever path suits you best._ - -## Option A: Run the Default Agent - -The fastest way to try Docker Agent — no config file needed: - -```bash -# Launch the default agent with the interactive TUI -$ docker agent run -``` - -This starts a general-purpose assistant with sensible defaults. Just start chatting. - -> [!NOTE] -> This needs a model: a cloud provider API key, or a local model pulled through Docker Model Runner. [Set Up a Model](../set-up-a-model/index.md) walks through both paths. - -## Option B: Run an Agent from a Registry - -Run an agent shared through any OCI-compatible registry — no local YAML needed: - -```bash -$ docker agent run myorg/agent:tag -``` - -## Option C: Generate a Config Interactively - -Use the `docker agent new` command to scaffold a config file through prompts: - -```bash -# Interactive wizard -$ docker agent new - -# Or specify options directly -$ docker agent new --model openai/gpt-5 - -# Override iteration limits -$ docker agent new --model dmr/ai/gemma3-qat:12B --max-iterations 15 -``` - -This generates an `agent.yaml` in the current directory. Then run it: - -```bash -$ docker agent run agent.yaml -``` - -## Option D: Write Your Own Config - -Create an `agent.yaml` by hand for full control. Here's a minimal example: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: A helpful coding assistant - instruction: | - You are an expert software developer. Help users write - clean, efficient code. Explain your reasoning. - toolsets: - - type: filesystem - - type: shell - - type: think -``` - -This gives your agent: - -- **Claude Sonnet 4.5** as the underlying model -- **Filesystem access** to read and write files -- **Shell access** to run commands -- **Think tool** for step-by-step reasoning - -This config needs `ANTHROPIC_API_KEY` set. See [Set Up a Model](../set-up-a-model/index.md) for where to put it, or use a local `dmr/...` model that needs no key. - -```bash -# Launch the interactive terminal UI -$ docker agent run agent.yaml -``` - -> [!TIP] -> **Prefer HCL?** -> -> You can write the same config as `agent.hcl` using labeled blocks and heredocs. See [HCL Configuration](../../configuration/hcl/index.md). - -## Try It Out - -Once your agent is running, try asking it to: - -- _"List the files in the current directory"_ -- _"Create a Python script that fetches weather data"_ -- _"Explain what the code in main.go does"_ - -> [!TIP] -> Add `--yolo` to auto-approve all tool calls: `docker agent run agent.yaml --yolo` - -## Take the Interactive Tour - -Prefer to learn by doing? Run: - -```bash -$ docker agent getting-started -``` - -This launches a short, scripted tour inside the chat UI: sending messages, approving tool calls, the command palette, and slash commands. It's skippable at any point with Esc, and you can replay it later with the same command or the `/getting-started` slash command. - -## Non-Interactive Mode - -Use `docker agent run --exec` for one-shot tasks: - -```bash -# Ask a single question -$ docker agent run --exec agent.yaml "Create a Dockerfile for a Node.js app" - -# Pipe input -$ cat error.log | docker agent run --exec agent.yaml "What's wrong in this log?" -``` - -## Add More Power - -Give your agent persistent memory and web search: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Research assistant with memory - instruction: | - You are a research assistant. Search the web for information, - remember important findings, and provide thorough analysis. - toolsets: - - type: think - - type: memory - path: ./research.db - - type: mcp - ref: docker:duckduckgo -``` - -> [!NOTE] -> **Docker MCP Tools** -> -> The `ref: docker:duckduckgo` syntax runs the DuckDuckGo MCP server in a Docker container. This is the recommended way to use MCP tools — secure, isolated, and easy to configure. Requires Docker Desktop. - -## What's Next? - -- [**Understand Agents**](../../concepts/agents/index.md) — learn how agents work and what you can configure. -- [**Multi-Agent Systems**](../../concepts/multi-agent/index.md) — build teams of collaborating agents. -- [**Configuration Reference**](../../configuration/overview/index.md) — full reference for all YAML and HCL options. -- [**Troubleshooting**](../../community/troubleshooting/index.md) — something not working? Debug tips and common fixes. diff --git a/_vendor/github.com/docker/docker-agent/docs/getting-started/set-up-a-model/index.md b/_vendor/github.com/docker/docker-agent/docs/getting-started/set-up-a-model/index.md deleted file mode 100644 index bff584def8d3..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/getting-started/set-up-a-model/index.md +++ /dev/null @@ -1,276 +0,0 @@ ---- -title: "Set Up a Model" -description: "Make a model available to Docker Agent: connect a cloud provider, run a local model with Docker Model Runner, or register a custom OpenAI-compatible endpoint." -keywords: docker agent, ai agents, getting started, set up a model, api key, local model, docker model runner, custom endpoint -weight: 25 -canonical: https://docs.docker.com/ai/docker-agent/getting-started/set-up-a-model/ ---- - -_Most agents need a model to think with: connect a built-in cloud provider, run a model locally with Docker Model Runner, or register a custom OpenAI-compatible endpoint. This page walks through each path end to end — plus the exception: agents that delegate to the Claude Code CLI on a Claude subscription, which need no model at all._ - -## Pick a Path - -| | Built-in cloud provider (Path A) | Local model (Path B) | -| ------------- | ------------------------------------------------ | ---------------------------------------- | -| You need | An account and a credential (usually an API key) | Docker Desktop with Model Runner enabled | -| Cost | Pay per token | Free once the model is downloaded | -| Your data | Sent to the provider | Never leaves your machine | -| Model quality | Frontier models (Claude, GPT-5, Gemini) | Open models sized to your hardware | - -You can set up both. When you don't name a model, Docker Agent's `auto` selection picks the first cloud provider with a configured credential and falls back to a locally pulled Docker Model Runner model. - -Two more paths cover the remaining cases: if your models sit behind your own OpenAI-compatible endpoint (vLLM, LiteLLM, a corporate gateway), register it with its base URL as a [custom endpoint](#path-c-custom-openai-compatible-endpoint) (Path C); and if you have a **Claude subscription**, the [Claude Code harness](#path-d-claude-code-harness-claude-subscription) (Path D) runs the official `claude` CLI as the agent, with no API key and no local model required. - -> [!TIP] -> **Prefer a wizard?** -> -> `docker agent setup` walks through the same choices interactively: pick a built-in provider and store its credential, check Docker Model Runner and pull a local model, register a custom OpenAI-compatible endpoint, or set up the Claude Code harness. This page is the manual version. See the [CLI reference](../../features/cli/index.md#docker-agent-setup). - -## Path A: Built-in Cloud Provider - -Docker Agent ships built-in support for many cloud providers: Anthropic, OpenAI, Google Gemini, Groq, Hugging Face, AWS Bedrock, GitHub Copilot, and more. You pick these by name instead of registering a custom provider. The providers `docker agent setup` lists — Groq and Hugging Face among them — come with a predefined endpoint, so setting the provider's credential is enough; some other built-in aliases need manual configuration, such as Azure OpenAI with your resource endpoint as `base_url`. The credential is usually an API key, but not always: Hugging Face uses the `HF_TOKEN` token, GitHub Copilot a `GITHUB_TOKEN`, AWS Bedrock your AWS credentials, and `chatgpt` signs in with your ChatGPT account in the browser via `docker agent setup`, with no key to paste. The steps below show the API-key flow that most providers follow. - -### 1. Get an API key - -Create a key in your provider's console: - -| Provider | Environment variable | Get a key at | -| ------------- | -------------------- | ------------------------------------------------------------------- | -| Anthropic | `ANTHROPIC_API_KEY` | [console.anthropic.com](https://console.anthropic.com/settings/keys) | -| OpenAI | `OPENAI_API_KEY` | [platform.openai.com](https://platform.openai.com/api-keys) | -| Google Gemini | `GOOGLE_API_KEY` | [aistudio.google.com](https://aistudio.google.com/apikey) | - -Every other provider with an API key works the same way. See [Model Providers](../../providers/overview/index.md) for the full list, each provider's credential variable, and the exceptions noted above. - -### 2. Store the key - -The fastest option is an environment variable in your shell: - -```bash -$ export ANTHROPIC_API_KEY=sk-ant-... -``` - -That lasts for the current shell session. To set a key up once, use any other built-in secret source: - -```bash -# Env file, passed at run time -$ echo 'ANTHROPIC_API_KEY=sk-ant-...' > .env -$ docker agent run --env-from-file .env - -# Docker Agent env file, read automatically on every run -# (`docker agent setup` writes it for you with owner-only permissions) -$ echo 'ANTHROPIC_API_KEY=sk-ant-...' >> ~/.config/cagent/.env -$ chmod 600 ~/.config/cagent/.env -``` - -The entry name must match the environment variable the provider expects. [Managing Secrets](../../guides/secrets/index.md) covers every source (Docker Compose secrets, credential helpers, 1Password references) and the order they are checked in. - -> [!IMPORTANT] -> Keys never go in `agent.yaml`. If you use an env file, add it to `.gitignore`. - -### 3. Verify - -`docker agent doctor` shows whether the key is visible and where it comes from: - -```bash -$ docker agent doctor -``` - -```text -User configuration - ~/.config/cagent/config.yaml: ok - -Model provider credentials - PROVIDER STATUS CREDENTIAL SOURCE - anthropic found ANTHROPIC_API_KEY environment - openai not set OPENAI_API_KEY - - ... - -Docker Model Runner - Status: not installed (https://docs.docker.com/ai/model-runner/get-started/) - -Model auto-selection - auto -> anthropic/claude-sonnet-4-6 - -No issues found. -``` - -### 4. Run - -```bash -$ docker agent run -``` - -With no config file, the default agent picks the provider you configured. To name a model explicitly, use `--model` or the `model` field in your config: - -```bash -$ docker agent run --model anthropic/claude-sonnet-4-5 -``` - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: A helpful coding assistant - instruction: You are an expert software developer. -``` - -## Path B: Local Model (Docker Model Runner) - -Docker Model Runner (DMR) runs open models on your own machine: no API key, no per-token cost, and prompts never leave your computer. - -### 1. Install Docker Model Runner - -Model Runner ships with [Docker Desktop](https://www.docker.com/products/docker-desktop/) (enable it under **Settings > AI**) and is also available for Docker Engine. Check that it responds: - -```bash -$ docker model status -``` - -If the command is missing or fails, follow the [Model Runner get-started guide](https://docs.docker.com/ai/model-runner/get-started/). - -### 2. Pull a model - -```bash -$ docker model pull ai/qwen3 -``` - -`ai/qwen3` is the model Docker Agent reaches for by default, but any model from the [Docker Hub `ai` catalog](https://hub.docker.com/u/ai) works. Pick one sized for your machine's memory. List what you have locally: - -```bash -$ docker model ls -``` - -### 3. Verify - -```bash -$ docker agent doctor -``` - -```text -User configuration - ~/.config/cagent/config.yaml: ok - -Model provider credentials - PROVIDER STATUS CREDENTIAL SOURCE - anthropic not set ANTHROPIC_API_KEY - - ... - -Docker Model Runner - Status: reachable, 1 model(s) pulled: - - ai/qwen3:latest - -Model auto-selection - auto -> dmr/ai/qwen3:latest - -No issues found. -``` - -### 4. Run - -```bash -$ docker agent run --model dmr/ai/qwen3 -``` - -Or in your config: - -```yaml -agents: - root: - model: dmr/ai/qwen3 - description: A local assistant - instruction: You are a helpful assistant. -``` - -When no cloud key is configured, bare `docker agent run` auto-selects a pulled local model, so after `docker model pull` you can run with no flags at all. The [Docker Model Runner provider page](../../providers/dmr/index.md) covers context size, runtime flags, and other tuning options. - -## Path C: Custom OpenAI-compatible Endpoint - -If your models are served from your own endpoint (vLLM, LiteLLM, a corporate gateway, an API proxy), register it as a custom provider: you supply its base URL, the API format, and the environment variable holding its API key, if it needs one. Built-in providers such as Groq or Hugging Face don't need this; use [Path A](#path-a-built-in-cloud-provider) and set their credential instead. - -The interactive wizard is the quickest way: - -```bash -$ docker agent setup # pick "Custom OpenAI-compatible endpoint" -``` - -Or define the provider once in your user configuration (`~/.config/cagent/config.yaml`): - -```yaml -providers: - myprovider: - base_url: https://llm.corp.example.com/v1 - api_type: openai_chatcompletions - token_key: MYPROVIDER_API_KEY -``` - -Its models then work with every command: - -```bash -$ docker agent models --provider myprovider -$ docker agent run --model myprovider/ -``` - -See [Provider Definitions](../../providers/custom/index.md#global-providers-user-configuration) for the full reference, including per-agent-file providers and gateway behavior. - -## Path D: Claude Code Harness (Claude Subscription) - -If you already pay for a Claude subscription, an agent can delegate its work to -the official Claude Code CLI instead of calling a model API. This is an -**external CLI, not provider API access**: Docker Agent launches `claude`, -which authenticates with its own subscription login — no `ANTHROPIC_API_KEY`, -no Docker Model Runner, and no token ever passes through Docker Agent. - -### 1. Install and log in - -Install [Claude Code](https://docs.anthropic.com/en/docs/claude-code), then -log in **as the same OS user and environment that run `docker agent`**: - -```bash -$ claude auth login --claudeai # interactive, opens a browser -$ claude auth status --text # verify -``` - -### 2. Create a harness agent - -`docker agent setup` (pick "Claude Code harness") generates this file for you, -or write it yourself: - -```yaml -# claude-code-agent.yaml -agents: - root: - description: Claude Code running on your Claude subscription - harness: - type: claude-code - effort: medium # low | medium | high | xhigh | max; omit for the Claude Code default -``` - -### 3. Verify and run - -```bash -$ docker agent doctor claude-code-agent.yaml # checks the CLI is installed and logged in -$ docker agent run claude-code-agent.yaml -``` - -The harness runs the CLI non-interactively and bypasses Claude Code's -permission prompts, so use it in a repository you trust — see the security -notes and full field reference in [Coding Harnesses](../../features/harnesses/index.md). - -## Check Your Setup Anytime - -`docker agent doctor` reports which providers have credentials (and from which source), whether Docker Model Runner is reachable and which models are pulled, and which model `auto` would pick. Secret values are never printed. - -```bash -$ docker agent doctor # credential, DMR, and auto-selection state -$ docker agent doctor ./agent.yaml # also check that file's requirements -``` - -It exits non-zero when something would block a run, which makes it usable as a CI preflight. See the [CLI reference](../../features/cli/index.md#docker-agent-doctor). - -## What's Next? - -- [**Quick Start**](../quickstart/index.md) — run your first agent now that a model is available. -- [**Models**](../../concepts/models/index.md) — inline vs. named models, fallbacks, and `auto` selection. -- [**Managing Secrets**](../../guides/secrets/index.md) — every way to store credentials, compared. -- [**Troubleshooting**](../../community/troubleshooting/index.md#missing-credentials-or-model-errors) — decode "no model available" and credential errors. diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/_index.md b/_vendor/github.com/docker/docker-agent/docs/guides/_index.md deleted file mode 100644 index 3e7b3780ad13..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Guides" -description: "Practical guides for building and running agents." -weight: 70 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/compaction/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/compaction/index.md deleted file mode 100644 index 67027ff65c03..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/compaction/index.md +++ /dev/null @@ -1,149 +0,0 @@ ---- -title: "Managing Context & Compaction" -description: "How to keep long Docker Agent sessions from filling the model's context window: automatic and on-demand compaction, trimming tool results, and reading the context gauge." -keywords: docker agent, ai agents, guides, context window, compaction, session compaction -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/guides/compaction/ ---- - -_How to keep long-running sessions from filling the model's context window._ - -## Why long sessions fill the context window - -Every model has a fixed context window — a maximum number of tokens it can read per request. As a session grows, the system prompt, tool definitions, prompt files, and the full message history (including every tool call and its result) all count against that budget. A long-running agent — one that reads many files, runs many commands, or just keeps chatting for a while — eventually approaches the limit. Once a request no longer fits, the model provider rejects it and the session stalls. - -Docker Agent addresses this with **compaction**: replacing older parts of the conversation with a compact AI-generated summary, freeing up room for the session to keep going. This guide covers the levers you have — automatic compaction, on-demand compaction, and trimming individual tool results — and how to read the context gauge so you know where a session stands. - -## Let Docker Agent compact automatically - -By default, every agent proactively compacts its own session once estimated token usage crosses **90%** of the model's context window: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: A long-running research assistant - instruction: You are a helpful assistant. -``` - -No configuration is required to get this behavior — it's on by default. Three fields let you tune it: - -| Field | Where | Description | -| --- | --- | --- | -| `session_compaction` | agent | Set to `false` to disable automatic compaction entirely for this agent (both the proactive threshold trigger and the post-overflow auto-recovery). The manual `/compact` command still works. Default: `true`. | -| `compaction_threshold` | agent or model | Fraction of the context window (greater than `0`, at most `1`) at which proactive compaction fires. A value set on the model takes precedence over the agent-level value. Default: `0.9`. | -| `compaction_model` | agent, model, or provider | Delegate the compaction (summary-generation) call to a different, usually cheaper and faster, model. The agent-level value wins, then the model-level value, then the provider-level default. | - -Lower the threshold to compact earlier and keep individual requests smaller and cheaper; raise it to keep more verbatim history in context before the first summary happens: - -```yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - # Compact at 80% of the window instead of the default 90%. - compaction_threshold: 0.8 -``` - -Compaction itself is a model call — feeding the full conversation to a model and asking for a summary — and it's the most expensive call in a session simply because it's the one that runs when the context is largest. There's rarely a reason to spend your primary reasoning model on it. Point `compaction_model` at something smaller instead; every other call still runs on the primary model: - -```yaml -models: - primary: - provider: anthropic - model: claude-sonnet-4-5 - compaction_model: fast - fast: - provider: anthropic - model: claude-haiku-4-5 -``` - -> [!IMPORTANT] -> **Context window mismatch** -> -> If `compaction_model` has a **smaller** context window than the primary model, Docker Agent triggers compaction against the smaller window so the summary call can always ingest the full conversation. Pair the primary model with a compaction model whose window is at least as large to keep the proactive trigger aligned with the primary model's window. -> -> The `/context` header and the sidebar's context gauge surface this cap when it applies: the `/context` header shows a second line reading "compaction cap: `` • `` tokens", and the sidebar shows a short "⚠ capped" marker. Live-sessions rows do not carry cap wording; the sidebar marker deliberately doesn't repeat the model name or figure — the `/context` header is the sole authority on why the reported limit is smaller than the primary model's own window. - -Disable compaction only when you specifically want a session to keep full, unabridged history and are willing to risk hitting the context limit: - -```yaml -agents: - archivist: - model: anthropic/claude-sonnet-4-5 - description: An assistant that never auto-compacts its sessions. - instruction: You keep full conversation history and never lose context. - session_compaction: false -``` - -See [`examples/compaction_model.yaml`](https://github.com/docker/docker-agent/blob/main/examples/compaction_model.yaml) and [`examples/compaction_threshold.yaml`](https://github.com/docker/docker-agent/blob/main/examples/compaction_threshold.yaml) for complete configurations, and [Delegating Session Compaction](../../configuration/models/index.md#delegating-session-compaction) in the Model Config reference for the full field-level details. - -## Compact on demand - -You don't have to wait for the automatic threshold. Two TUI commands give you direct control: - -- **`/compact`** — summarize and compact the current session's history right now, regardless of how full the context window is. Useful before starting a new phase of work that doesn't need the earlier detail. -- **`/context`** — open a context-window breakdown: estimated tokens per category (system prompt, tool definitions, prompt files, messages, tool results, compaction summary), a **Live sessions** view listing the current session plus every running sub-agent session with its own context budget, and a per-file inventory of attachments and prompt files. When a compaction has occurred, the dialog also displays the verbatim text of the most recent compaction summary, preserving hard newlines and soft-wrapping long lines to the dialog width. - -From `/context`, select any live session with the arrow keys and press Enter to explicitly compact it — including a sub-agent's session, not just the main one. This is the only way cross-agent compaction happens: there's no idle-triggered automatic compaction of sub-agent sessions, so a long-running background agent stays under your control. The request is queued onto the target session's own run loop and applied at the next safe point between model turns, so it never corrupts an in-flight turn. - -```bash -$ docker agent run agent.yaml -# ... work for a while ... -# Type /context to see the current breakdown, or /compact to summarize now -``` - -## Trim tool results to save room - -Compaction deals with the whole conversation at once. For sessions dominated by a few oversized tool results — a full build log, a large file dump — three agent-level fields let you cap the damage before it ever reaches compaction: - -| Field | What it bounds | Behavior | -| --- | --- | --- | -| `max_tool_result_tokens` | Each tool result, as it's added to the session | Oversized results are truncated **middle-out**: the head and tail are kept (usually the most informative parts) and the removed middle is replaced with a truncation marker. | -| `max_old_tool_call_tokens` | The total budget for **old** tool call arguments and results | Once older tool calls exceed the budget, their content is replaced wholesale with a placeholder — freeing context space without touching recent, still-relevant calls. | -| `num_history_items` | The number of non-system conversation messages kept in history | A message-**count** limit, not a token budget. The oldest non-protected messages are dropped first once the count is exceeded; **system and user messages are always protected** and are never counted against or removed by this limit, so the assembled history can exceed `num_history_items` and every user message survives even a long single-turn agentic loop. | - -`max_tool_result_tokens` and `max_old_tool_call_tokens` are approximated as `len/4` tokens (the industry rule-of-thumb of ~4 characters per token); `num_history_items` counts messages, not tokens. All three are disabled by default (`0`). Set a positive value to enable them: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: An assistant whose tool results are capped at ~2000 tokens each. - instruction: | - You are a helpful assistant with shell access. Very large command - outputs are truncated in the middle — the beginning and end are - always preserved, and a marker shows where content was removed. - max_tool_result_tokens: 2000 - toolsets: - - type: shell -``` - -> [!TIP] -> **Use both together** -> -> `max_tool_result_tokens` bounds each result the moment it's recorded; `max_old_tool_call_tokens` reclaims space from calls that are no longer fresh. Combine them on tool-heavy agents (shell, filesystem) to keep the session lean well before it approaches the compaction threshold. - -See [`examples/max_tool_result_tokens.yaml`](https://github.com/docker/docker-agent/blob/main/examples/max_tool_result_tokens.yaml) for a complete example, and [Agent Config](../../configuration/agents/index.md#properties-reference) for the full field reference. - -## Read the context gauge - -The TUI's sidebar token-usage section (and the fill bar in the [lean TUI](../../features/tui/index.md#lean-tui) status line) color-escalates as a session approaches its compaction threshold, so you can see trouble coming before a request fails: - -| State | Color | Trigger | -| --- | --- | --- | -| Normal | (default) | Usage below 75% of the compaction threshold | -| Warning | Orange | Usage at or above 75% of the compaction threshold | -| Critical | Red | Usage at or above 95% of the compaction threshold | - -While a compaction is running, the percentage is replaced by a **"compacting…"** indicator; token counts remain visible in the lean TUI status line. The thresholds scale with the agent's configured `compaction_threshold` (default `0.9`), so a custom value keeps a predictable visual runway — for example, a `compaction_threshold: 0.8` session turns orange at 60% usage (75% of 0.8) instead of 67.5%. - -Open `/context` at any time for the full per-category breakdown behind that percentage. - -## What happens to cost across compaction - -Compaction summarizes history, but it never resets what a session has actually cost you. Session cost tracking is **monotonic across compaction**: the running total only ever goes up, even though the summarized conversation itself is now smaller. Check `/cost` to see the current breakdown at any point, before or after a compaction has run. - -## Related: deferred tool loading - -Compaction and result trimming manage context that's already in the session. If large toolsets are inflating your **starting** context instead — many MCP servers, hundreds of tools — look at [deferred tool loading](../../configuration/tools/index.md#deferred-tool-loading), which registers a toolset's tools lazily instead of eagerly at startup. diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/go-sdk/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/go-sdk/index.md deleted file mode 100644 index 909729e16f3c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/go-sdk/index.md +++ /dev/null @@ -1,650 +0,0 @@ ---- -title: "Go SDK" -description: "Use Docker Agent as a Go library to embed AI agents in your applications." -keywords: docker agent, ai agents, guides, go sdk -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/guides/go-sdk/ ---- - -_Use Docker Agent as a Go library to embed AI agents in your applications._ - -## Overview - -Docker Agent can be used as a Go library, allowing you to build AI agents directly into your Go applications. This gives you full programmatic control over agent creation, tool integration, and execution. - -> [!NOTE] -> **Import Path** -> -> ```go -> import "github.com/docker/docker-agent/pkg/..." -> ``` - -## Core Packages - -| Package | Purpose | -| ---------------------- | ---------------------------------------- | -| `pkg/agent` | Agent creation and configuration | -| `pkg/runtime` | Agent execution and event streaming | -| `pkg/session` | Conversation state management | -| `pkg/team` | Multi-agent team composition | -| `pkg/tools` | Tool interface and utilities | -| `pkg/tools/builtin` | Built-in tools (shell, filesystem, etc.) | -| `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. | -| `pkg/tui/components/transcript` | Embedded transcript view with read-only `Messages()` accessor for observing conversation structure in host tests and persistence layers. | - -## Embedding TUI Components - -When building custom UIs on top of Docker Agent's TUI primitives, four packages define the contracts that keep the runtime and the UI in sync: - -- **`pkg/tui/components/toolconfirm`** — import this package for the permission-decision policy rather than copying the pattern-building logic. The `Decision` enum, `BuildPermissionPattern` helper, and rejection-reason presets are the canonical source of truth: whatever pattern is shown to the user in the confirmation dialog is exactly the pattern granted to the runtime. -- **`pkg/tui/service`** — use `StaticSessionState` as a stub `SessionStateReader` when rendering individual message or tool views outside the full TUI app. It returns conservative fixed values for all nine interface methods, eliminating the need for hand-rolled stubs. -- **`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. - -> [!WARNING] -> **Breaking change: `Runtime.ResumeElicitation` (#3584)** -> -> `Runtime.ResumeElicitation` gained an `elicitationID` parameter so responses can -> be correlated with a specific concurrent elicitation request (needed once -> multiple background jobs can be eliciting input at the same time). It is -> declared **variadic** (`elicitationID ...string`) specifically so existing -> *callers* of the 3-argument form keep compiling unchanged — `rt.ResumeElicitation(ctx, action, content)` -> still works and falls back to resolving the sole pending request. -> -> If you implement your own `runtime.Runtime` (rather than embedding -> `runtime.LocalRuntime`/`runtime.RemoteRuntime`), you do need to update your -> method's signature to match, and also add an `OnElicitationRequest(handler -> func(runtime.Event))` method (a no-op is fine if your runtime never raises -> elicitations) — both are required interface methods, matching the existing -> no-op-able pattern already used by `OnToolsChanged`/`OnBackgroundEvent`. - -## 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. - -> [!WARNING] -> **Anthropic + Google dependency** -> -> 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. - -## RAG Toolset (opt-out) - -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`). - -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/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() -delete(creators, "rag") -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/.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 -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. - -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 -} -``` - -> [!WARNING] -> **Call order matters** -> -> If `keyringstore.Register()` 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 `teamloader.Load()`. Always call `keyringstore.Register()` before calling `teamloader.Load()` on a config that includes remote MCP toolsets. - -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. - -## JavaScript Command Expressions (opt-in) - -Slash-command instructions can embed `${...}` JavaScript expressions (`${args[0]}`, `${args.join(" ")}`, `${tool({...})}`). Evaluating them requires the goja JavaScript engine, which is deliberately kept out of `pkg/runtime`'s import graph so code-built embedders don't link it by default. - -The CLI, `teamloader.Load()`, `pkg/cli.Run()` and `embeddedchat/defaults` enable it automatically. If you build teams in code, call `runtime.ResolveCommand` (or `cli.PrepareUserMessage`) directly **and** use `${...}` expressions in commands, register the evaluator yourself: - -```go -import "github.com/docker/docker-agent/pkg/runtime/jscommands" - -func main() { - jscommands.Register() - // ... rest of your startup code -} -``` - -Without the registration, `${...}` expressions are left unexpanded and a warning naming the fix is logged; everything else about command resolution (including the legacy `!tool(...)` syntax) works as usual. - -## Basic Example - -Create a simple agent and run it: - -```go -package main - -import ( - "context" - "fmt" - "log" - "os/signal" - "syscall" - - "github.com/docker/docker-agent/pkg/agent" - "github.com/docker/docker-agent/pkg/config/latest" - "github.com/docker/docker-agent/pkg/environment" - "github.com/docker/docker-agent/pkg/model/provider/openai" - "github.com/docker/docker-agent/pkg/runtime" - "github.com/docker/docker-agent/pkg/session" - "github.com/docker/docker-agent/pkg/team" -) - -func main() { - ctx, cancel := signal.NotifyContext(context.Background(), - syscall.SIGINT, syscall.SIGTERM) - defer cancel() - - if err := run(ctx); err != nil { - log.Fatal(err) - } -} - -func run(ctx context.Context) error { - // Create model provider - llm, err := openai.NewClient( - ctx, - &latest.ModelConfig{ - Provider: "openai", - Model: "gpt-4o", - }, - environment.NewDefaultProvider(), - ) - if err != nil { - return err - } - - // Create agent - assistant := agent.New( - "root", - "You are a helpful assistant.", - agent.WithModel(llm), - agent.WithDescription("A helpful assistant"), - ) - - // Create team and runtime - t := team.New(team.WithAgents(assistant)) - rt, err := runtime.New(t) - if err != nil { - return err - } - - // Run with a user message - sess := session.New( - session.WithUserMessage("What is 2 + 2?"), - ) - - messages, err := rt.Run(ctx, sess) - if err != nil { - return err - } - - // Print the response - fmt.Println(messages[len(messages)-1].Message.Content) - return nil -} -``` - -## Custom Tools - -Define custom tools for your agent: - -```go -package main - -import ( - "context" - "encoding/json" - "fmt" - - "github.com/docker/docker-agent/pkg/tools" -) - -// Define the tool's input schema -type AddNumbersArgs struct { - A int `json:"a"` - B int `json:"b"` -} - -// Implement the tool handler -func addNumbers(_ context.Context, toolCall tools.ToolCall) (*tools.ToolCallResult, error) { - var args AddNumbersArgs - if err := json.Unmarshal([]byte(toolCall.Function.Arguments), &args); err != nil { - return nil, err - } - - result := args.A + args.B - return tools.ResultSuccess(fmt.Sprintf("%d", result)), nil -} - -func main() { - // Create the tool definition - addTool := tools.Tool{ - Name: "add", - Category: "math", - Description: "Add two numbers together", - Parameters: tools.MustSchemaFor[AddNumbersArgs](), - Handler: addNumbers, - } - - // Use with an agent - calculator := agent.New( - "root", - "You are a calculator. Use the add tool for arithmetic.", - agent.WithModel(llm), - agent.WithTools(addTool), - ) - // ... -} -``` - -## Streaming Responses - -Process events as they happen: - -```go -func runStreaming(ctx context.Context, rt runtime.Runtime, sess *session.Session) error { - events := rt.RunStream(ctx, sess) - - for event := range events { - switch e := event.(type) { - case *runtime.StreamStartedEvent: - fmt.Println("Stream started") - - case *runtime.AgentChoiceEvent: - // Print response chunks as they arrive - fmt.Print(e.Content) - - case *runtime.ToolCallEvent: - fmt.Printf("\n[Tool call: %s]\n", e.ToolCall.Function.Name) - - case *runtime.ToolCallConfirmationEvent: - // Auto-approve tool calls - rt.Resume(ctx, runtime.ResumeRequest{ - Type: runtime.ResumeTypeApproveSession, - }) - - case *runtime.ToolCallResponseEvent: - fmt.Printf("[Tool response: %s]\n", e.Response) - - case *runtime.StreamStoppedEvent: - fmt.Println("\nStream stopped") - - case *runtime.ErrorEvent: - return fmt.Errorf("error: %s", e.Error) - } - } - - return nil -} -``` - -## Multi-Agent Teams - -Create agents that delegate to sub-agents: - -```go -package main - -import ( - "github.com/docker/docker-agent/pkg/agent" - "github.com/docker/docker-agent/pkg/team" - "github.com/docker/docker-agent/pkg/tools/builtin" -) - -func createTeam(llm provider.Provider) *team.Team { - // Create a child agent - researcher := agent.New( - "researcher", - "You research topics thoroughly.", - agent.WithModel(llm), - agent.WithDescription("Research specialist"), - ) - - // Create root agent with sub-agents - coordinator := agent.New( - "root", - "You coordinate research tasks.", - agent.WithModel(llm), - agent.WithDescription("Team coordinator"), - agent.WithSubAgents(researcher), - agent.WithToolSets(builtin.NewTransferTaskTool()), - ) - - return team.New(team.WithAgents(coordinator, researcher)) -} -``` - -## Built-in Tools - -Use Docker Agent's built-in tools: - -```go -import ( - "github.com/docker/docker-agent/pkg/config" - "github.com/docker/docker-agent/pkg/tools/builtin" -) - -func createAgentWithBuiltinTools(llm provider.Provider) *agent.Agent { - // Runtime config for tools that need it - rtConfig := &config.RuntimeConfig{ - Config: config.Config{ - WorkingDir: "/path/to/workdir", - }, - } - - return agent.New( - "root", - "You are a developer assistant.", - agent.WithModel(llm), - agent.WithToolSets( - // Shell tool for running commands - builtin.NewShellTool(os.Environ(), rtConfig), - // Filesystem tools - builtin.NewFilesystemTool(rtConfig.Config.WorkingDir), - // Think tool for reasoning - builtin.NewThinkTool(), - // Todo tool for task tracking - builtin.NewTodoTool(), - ), - ) -} -``` - -## HTTP Middleware / Transport Wrappers - -Use `options.WithHTTPTransportWrapper` to inject HTTP middleware into the transport chain of all provider clients built by Docker Agent. This is useful for request tracing, injecting custom headers, collecting metrics, or any other cross-cutting concern at the HTTP layer. - -```go -import ( - "net/http" - - "github.com/docker/docker-agent/pkg/model/provider/options" -) - -type headerTransport struct { - base http.RoundTripper -} - -func (t *headerTransport) RoundTrip(req *http.Request) (*http.Response, error) { - req = req.Clone(req.Context()) - req.Header.Set("X-Request-Source", "my-app") - return t.base.RoundTrip(req) -} - -// Example: add a custom header to every outbound LLM request -wrapper := options.WithHTTPTransportWrapper( - func(base http.RoundTripper) http.RoundTripper { - return &headerTransport{base: base} - }, -) - -client, err := openai.NewClient(ctx, &latest.ModelConfig{ - Provider: "openai", - Model: "gpt-4o", -}, env, wrapper) -``` - -The wrapper receives the already-instrumented transport (OpenTelemetry, SSE decompression, Desktop proxy support) as its `base` argument, so wrapping it preserves all built-in behaviour. - -**Supported providers:** Anthropic, OpenAI, Gemini (GeminiAPI backend), Bedrock. Works in both direct and gateway/proxy mode. - -> [!WARNING] -> **Vertex AI not supported** -> -> Vertex AI uses an ADC-managed HTTP client that Docker Agent cannot intercept. When a transport wrapper is set, Docker Agent falls back to the GeminiAPI backend instead of Vertex AI — a debug message is logged. - -In **gateway mode** the wrapper is called on every LLM request because gateway clients are rebuilt each call for short-lived auth tokens. In **direct mode** it is called once at client construction. Rate-limit responses (HTTP 429) are classified as non-retryable by the runtime and cause the model chain to skip to the next fallback, so wrappers that track per-request outcomes will observe these as failures rather than retried calls. - -Returning `nil` from your wrapper function is not allowed; Docker Agent logs a warning and keeps the original transport instead. - -## Using Different Providers - -```go -import ( - "github.com/docker/docker-agent/pkg/model/provider/anthropic" - "github.com/docker/docker-agent/pkg/model/provider/gemini" - "github.com/docker/docker-agent/pkg/model/provider/openai" -) - -// OpenAI -openaiClient, _ := openai.NewClient(ctx, &latest.ModelConfig{ - Provider: "openai", - Model: "gpt-4o", -}, env) - -// Anthropic -anthropicClient, _ := anthropic.NewClient(ctx, &latest.ModelConfig{ - Provider: "anthropic", - Model: "claude-sonnet-4-5", -}, env) - -// Google Gemini -geminiClient, _ := gemini.NewClient(ctx, &latest.ModelConfig{ - Provider: "google", - Model: "gemini-3.5-flash", -}, env) -``` - -## Session Options - -```go -import "github.com/docker/docker-agent/pkg/session" - -sess := session.New( - // Set a title for the session - session.WithTitle("Code Review Task"), - - // Add user message - session.WithUserMessage("Review this code for bugs"), - - // Limit iterations - session.WithMaxIterations(20), -) -``` - -## Error Handling - -```go -messages, err := rt.Run(ctx, sess) -if err != nil { - if errors.Is(err, context.Canceled) { - // User cancelled - log.Println("Operation cancelled") - return nil - } - if errors.Is(err, context.DeadlineExceeded) { - // Timeout - log.Println("Operation timed out") - return nil - } - // Other error - return fmt.Errorf("runtime error: %w", err) -} - -// Check for errors in the event stream -for event := range rt.RunStream(ctx, sess) { - if errEvent, ok := event.(*runtime.ErrorEvent); ok { - return fmt.Errorf("stream error: %s", errEvent.Error) - } -} -``` - -## Complete Example - -See the [examples/golibrary](https://github.com/docker/docker-agent/tree/main/examples/golibrary) directory for complete working examples: - -- `simple/` — Basic agent with no tools -- `tool/` — Custom tool implementation -- `stream/` — Streaming event handling -- `multi/` — Multi-agent with sub-agents -- `builtintool/` — Using built-in tools diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/headless/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/headless/index.md deleted file mode 100644 index 76a87bd4d505..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/headless/index.md +++ /dev/null @@ -1,225 +0,0 @@ ---- -title: "Running Agents Headless & in CI" -description: "Run Docker Agent without a TUI: structured JSON output, event hooks, sandboxed CI isolation, and a GitHub Actions example." -keywords: docker agent, ai agents, guides, headless, ci, github actions, sandbox -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/guides/headless/ ---- - -_Run Docker Agent without a TUI: structured JSON output, event hooks, sandboxed CI isolation, and a GitHub Actions example._ - -## `--exec` Mode Basics - -`--exec` runs an agent without the interactive TUI: output goes to stdout and the process exits when the conversation is done. It's the mode to use in scripts, CI, and any context without a terminal. - -```bash -# One-shot task, message as an argument -$ docker agent run --exec agent.yaml "Summarize the open issues in this repo" - -# Pipe the message via stdin instead -$ echo "Summarize the open issues in this repo" | docker agent run --exec agent.yaml - - -# Multiple messages are processed as a multi-turn conversation, in order -$ docker agent run --exec agent.yaml "question 1" "question 2" "question 3" -``` - -See [`docker agent run --exec`](../../features/cli/index.md#docker-agent-run---exec) for the full flag reference. - -## Choosing a Large-Input Strategy - -Docker Agent has several unrelated mechanisms for getting a large document, file, or dataset in front of an agent. Which one fits depends on whether the content is local to the machine running Docker Agent, how often it needs to be revisited, and whether you're driving the agent through the CLI/TUI or over one of the HTTP servers: - -| You have… | Use… | Notes | -| --- | --- | --- | -| A file on disk, for one interactive turn | `@path` or `/attach` in the TUI (see [File Attachments](../../features/tui/index.md#file-attachments)), `--attach` at startup (seeds an interactive TUI run just as readily as `--exec`), or `/attach` under `--exec` | Read from the local filesystem and inlined into the message once it clears a local admission check. That never crosses Docker Agent's own inbound HTTP boundary for a local (non-`--remote`) run or for the *first* message of a `--remote` run — but a locally resolved attachment added to a *later* message on a remote run does cross it; see the remote-runtime row below. The admission check itself, and how a rejection is reported, differ by entry point; see the read-time limits below. | -| Instructions/context every agent turn should see | `add_prompt_files` in the agent config, or `--prompt-file` on the CLI (see [Prompt Files](../../configuration/agents/index.md#prompt-files)) | Re-read from disk **in full** on every turn and injected as instruction context; local, not an HTTP upload, and not subject to the attachment inlining checks above — memory and the model's context window are the practical ceilings. | -| A one-off piece of text for a **local** headless run | stdin, without `--remote` (see [`--exec` Mode Basics](#--exec-mode-basics) above) | The piped text becomes the message directly; it never crosses Docker Agent's own inbound HTTP boundary and has no size cap of its own, though Docker Agent may still send it onward to a model/provider over HTTP. | -| A one-off piece of text driving a **remote** runtime | stdin with `docker agent run --remote ... -` | The CLI serializes that stdin text into a native API run request sent to whichever Docker Agent server the `--remote` address points at — a `serve api` process or another run's [`--listen`](../../features/api-server/index.md#listen) control plane, never `serve chat` — so it's measured against that server's own limit: `serve api`'s configurable `--max-request-size`, or a `--listen` control plane's fixed, non-configurable 1 MiB cap. See the HTTP body limit below. That *initial* request carries only message text: conversion currently drops any attachment resolved locally (`@path`/`/attach`, `--attach`) for the first message before it's sent. A *later* message to the same remote run — sent while the agent is still busy, via the default steer behavior or an explicit follow-up (Alt+Enter) — does forward a locally resolved attachment as part of that native API request, so it counts toward the same limit and can 413 like any other oversized request. Client-side `--prompt-file` values are **not** forwarded to a remote runtime either way; prompt files configured on the agent itself (`add_prompt_files`) still resolve, but on the server's filesystem. | -| A document collection you'll query repeatedly, or one too large to inline at all | The [`rag` toolset](../../tools/rag/index.md) | Indexed once in the background; each query retrieves only the relevant chunks into context, instead of the whole collection. | -| An OpenAI-compatible client driving Docker Agent over HTTP | [Chat Server](../../features/chat-server/index.md) | Accepts OpenAI-style `text` and [`image_url`](../../features/chat-server/index.md#image-inputs) content parts. The whole request travels as a single HTTP body capped by that server's `--max-request-size`; a data URL's bytes count toward it, while a remote `http(s)://` image URL is passed to the provider rather than fetched by the chat server, and works only if that provider/model supports it. | -| A native integration driving Docker Agent's own session/control protocol | [API Server](../../features/api-server/index.md) | Supports the documented session, run, and event-streaming flows over a single capped HTTP body; see the note below on the upload contract this does *not* provide. | -| A supervisor process driving an already-running interactive session | An attached run's [`--listen`](../../features/api-server/index.md#listen) control plane | Exposes the same session/follow-up/event-streaming API as the API server, but with a fixed, non-configurable 1 MiB request-body cap and no `--auth-token` — there's no `--max-request-size` or `--auth-token` flag for this surface. Keep it on loopback, a unix socket, or behind an authenticating reverse proxy if it must be reachable from elsewhere. | - -Three independent ceilings apply, and hitting one says nothing about the others: - -1. **The HTTP body limit** — applies to any request reaching one of Docker Agent's three inbound HTTP surfaces: `docker agent serve api`, `docker agent serve chat`, or an interactive run's [`--listen`](../../features/api-server/index.md#listen) control plane. `docker agent run --remote ... -` builds a native run request from stdin and sends it to whichever of `serve api` or a `--listen` control plane the remote address points at — never `serve chat`, which speaks a different protocol. `serve api` and `serve chat` each enforce their own `--max-request-size` (1 MiB default, configurable) and return `413 Request Entity Too Large` above it; a `--listen` control plane enforces the same 1 MiB default but exposes no `--max-request-size` flag (or `--auth-token`) to change it — it's fixed, and reducing the request is the only remedy. See [Troubleshooting: HTTP 413](../../community/troubleshooting/index.md#http-413-request-body-too-large) for how to diagnose and resolve it. Local (non-`--remote`) stdin and prompt files never cross this boundary; a locally resolved `@path`/`/attach`/`--attach` attachment doesn't either for a remote run's initial message, but one added to a later steer or follow-up message on that same remote run does — see the remote-runtime row above. -2. **Local read-time limits, which differ by path** — the TUI and non-TUI (CLI/`--exec`) message assembly don't share one text/binary rule. The TUI (both `/attach` and a typed `@path` reference) runs every file reference through one flat size ceiling *before* it looks at the file's type; non-TUI assembly — the CLI's `--attach` flag and `--exec`'s own `/attach` parsing — inlines text up to its own ceiling and hands supported binary files (images, PDFs) to a separate path with a higher cap, so a binary file that's fine for `--attach`/`--exec` can still be too big for the TUI's flatter, lower ceiling. Either way an oversized file is rejected rather than silently truncated or allowed to exhaust memory, but whether you're actually told about it depends on the surface: only the interactive TUI's `/attach` command shows a visible error notification (with a file-picker fallback), while a bare `@path` reference is only checked speculatively as you type — a rejection there is logged at debug level only, and the reference is left as plain text in your message with no on-screen notice. Outside the interactive TUI, neither the CLI's `--attach` flag nor `--exec`'s `/attach` (which reuses the same non-TUI assembly and rejection path as `--attach`, not the TUI's notification flow) prints anything about a rejected attachment in normal run output — the message just falls back to text-only, and the reason is visible only in the debug log when `--debug` is enabled. Prompt files (`add_prompt_files`/`--prompt-file`) have no equivalent guard — they're read in full on every turn regardless of size, so memory and the model's context window are what actually bound them. -3. **Model/provider context and media limits** — even content that clears the first two layers still has to fit the model's token/context window, and binary attachments (images, PDF, audio, video) only work if the model declares support for that media type (see [Attachment Capability Overrides](../../configuration/models/index.md#attachment-capability-overrides)). Exceeding the context window is a separate failure from either limit above — see [Context Window Exceeded](../../community/troubleshooting/index.md#context-window-exceeded). - -> [!NOTE] -> **No file-upload endpoint** -> -> None of Docker Agent's three inbound HTTP surfaces — the API server, the chat server, or an attached run's `--listen` control plane — exposes a multipart file-upload endpoint, and none of them fetches a remote URL on your behalf — the chat server's `image_url` support only ever passes a remote URL through to the provider (see the table above). Content reaches an agent either locally (`@path`/`/attach`, prompt files, `rag`) or embedded directly in the HTTP message body those servers already document; there is no separate attachment channel over any of them. - -## Structured Output for Machines - -Two independent things make an `--exec` run's output easy to parse: how the transcript is emitted, and what shape the model's own answer takes. - -**`--json`** switches the transcript itself from human-readable text to newline-delimited JSON: one JSON object per runtime event (messages, tool calls, tool results, errors, …), instead of formatted text interleaved with tool-call boxes. Pipe it into `jq` or any NDJSON-aware log processor: - -```bash -$ docker agent run --exec agent.yaml --json "List the 5 largest files in this repo" | jq -c 'select(.type == "agent_choice")' -``` - -**`structured_output`** constrains the *model's own response* to a JSON schema you define on the agent, independent of `--json`. Use it when downstream code needs the model's answer in a predictable shape (a list of findings, a classification, …) rather than free-form prose. See [Structured Output](../../configuration/structured-output/index.md) for the full field reference — combine it with `--json` in `--exec` to get both a parseable transcript and a schema-validated final answer. - -## Reacting to Events - -`--on-event =` runs a shell command whenever an event of the given type fires, with the event's JSON payload piped to the command's stdin. Use `*=` to match every event type. The flag is repeatable. - -> [!WARNING] -> **`--on-event` does nothing under `--exec`** -> -> Event hooks are installed on the interactive App's event bus. A `docker agent run --exec` run returns before that wiring happens, so `--on-event` is silently a no-op there — no error, no hook ever runs. Use `--on-event` with a normal interactive run or `--lean` (which still installs hooks; it just skips the alternate screen). For a headless `--exec` run, get the same effect by parsing the `--json` NDJSON stream yourself and shelling out on the events you care about — for example `stream_stopped`, which fires when a turn ends normally. - -```bash -# Post a Slack notification when the agent finishes a turn (interactive or --lean only) -$ docker agent run agent.yaml --lean --on-event stream_stopped="./notify-slack.sh" "Fix the failing test" - -# Log every event to a file for later inspection -$ docker agent run agent.yaml --lean --on-event "*=cat >> events.ndjson" "Fix the failing test" - -# Headless equivalent: capture the --json NDJSON stream, then react to it yourself -$ docker agent run --exec agent.yaml --json "Fix the failing test" | tee events.ndjson -$ jq -e 'select(.type == "stream_stopped")' events.ndjson >/dev/null && ./notify-slack.sh -``` - -Hooks run asynchronously and are never waited on: each is spawned detached from the run's own context, and the process exits (`os.Exit`) as soon as the run finishes without waiting for, or signaling, any hook subprocess still in flight. A hook's own failure is logged but never fails the run — and, independent of that, its fate at process exit is unspecified: it may keep running as an orphaned process, or it may be torn down by whatever supervises the job (a CI runner tearing down its container, a shell killing its process group, …), depending on your environment rather than on anything docker-agent guarantees. Don't rely on `--on-event` for anything that must demonstrably finish before the process exits; have the hook script itself detach (e.g. `nohup`/`disown`) and/or write its own completion marker if you need proof it ran. - -## Running Unattended in CI - -Interactively, the TUI prompts for confirmation before a tool call runs unless it's covered by an `allow` permission pattern. There's no one to answer that prompt in CI, so an unattended `--exec` run needs an explicit policy for what may run without asking — otherwise every tool call the model attempts is rejected outright (there's no stdin to prompt, so `--exec` without one just answers "no" on your behalf; see [`--json`'s auto-reject behavior](#structured-output-for-machines) above). - -Two different questions come up here, and it's worth keeping them separate: - -- **What is allowed to run without asking?** — the safety mode (`--safety strict|balanced|restricted|autonomous`, with `--yolo` as the legacy spelling of `autonomous`) and permission allow-lists answer this. -- **What happens if the model runs something it shouldn't have?** — only `--sandbox` answers that one. The rest of this section explains why, and treats that distinction as the whole point. - -### `--sandbox`: the isolation boundary - -For an untrusted or autonomous agent — anything acting without a human watching approvals — **`--sandbox` is the isolation boundary to reach for**, not a cleverer allow-list. It runs the entire agent, shell calls included, inside a VM managed by [`sbx`](https://docs.docker.com/ai/sandboxes/): a misbehaving or successfully-prompt-injected agent can't touch anything outside the mounted working directory or reach other host/CI state, regardless of which command it runs. That VM isn't disposable or ephemeral — a sandbox matching the current workspace and mount set is retained and reused across subsequent runs rather than torn down when the session ends (see [How It Works](../../configuration/sandbox/index.md#how-it-works)). See [Sandbox Mode](../../configuration/sandbox/index.md) for the full flag reference, `sbx` requirement, network allowlist, and kit staging behavior. - -```bash -$ docker agent run --sandbox --exec agent.yaml --json "Fix the failing test" -``` - -Because the blast radius is contained by the VM boundary, `--sandbox` also makes unattended operation reasonable in CI — and it defaults to exactly that: unless you already passed a `--yolo` or `--safety` flag of your own, `--sandbox` injects `--yolo` for the agent process it runs inside the VM, so the command above already runs unattended with no confirmation prompts. Passing `--yolo` explicitly (`--sandbox --yolo --exec ...`) is equivalent and can make the intent clearer in a script, but it's optional. To keep confirmation prompts even inside the sandbox, select a stricter mode (`--sandbox --safety strict`) or opt out of the legacy default with `--yolo=false` — `--sandbox` only fills in `--yolo` when neither safety flag was set. - -If your CI provider already runs each job in its own disposable VM or container — many hosted runners do — and nothing on the runner matters once the job ends, that may already give you an isolation boundary on its own. `--sandbox` still gives you the same guarantee independent of the CI provider, and starts to matter as soon as the agent runs on a persistent self-hosted runner, a long-lived container, or your own workstation. - -### Defense in depth, not a boundary: permissions and shell command matching - -Permission allow-lists (`permissions.allow` on the agent, or `settings.permissions.allow` globally — see [Permissions](../../configuration/permissions/index.md)) and the balanced safety mode's shell classifier (see [Safety modes](../../configuration/permissions/index.md#safety-modes)) narrow what runs without asking. Used well, they cut down how often you're prompted and catch obviously destructive calls before they run. They are **not** a security boundary: - -- Both work by matching the shell command **string** (or, for `permissions`, the tool's arguments). The classifier's safe-list refuses to vouch for any command carrying shell metacharacters (`;`, `&`, `|`, `<`, `>`, backticks, `$(`, newlines — spaced or not), so `ls && rm -rf ~`, `grep foo|rm -rf /`, and `grep x > /etc/passwd` all fall through to a confirmation instead of inheriting a safe verdict. But string matching still can't reason about what a command actually *does* — see the next point. -- Command-string and argument matching in general can't reason about what a command actually does; a dynamically built string, an unusual quoting form, or a wrapper script can slip past any fixed set of patterns. - -For unattended runs, the `restricted` safety mode packages this stance as a fail-closed default: classifier-safe calls run, every other unmatched call is **denied outright** instead of falling through to a confirmation prompt nobody will answer. Pair it with an allow-list scoped to what the job actually needs — explicit `allow` rules still win over the mode, so the job's known-good commands run even when the classifier can't vouch for them: - -```yaml -# agent.yaml — the allow-list overrides restricted's deny for these calls -permissions: - allow: - - "shell:cmd=go test*" - - "shell:cmd=go build*" -``` - -```bash -# Safe and allow-listed calls run; every other call is denied without prompting -$ docker agent run --exec --safety restricted agent.yaml --json "Fix the failing test" -``` - -Like the allow-list itself, `restricted` is defense in depth, not a security boundary: it narrows what runs unattended, but only `--sandbox` contains what a misbehaving agent can do with the calls that are allowed. - -Treat permissions and the balanced/restricted modes as a way to reduce prompt fatigue and catch the obvious cases, paired with least-privilege CI credentials — never as the reason a CI job is safe to run unattended. For that, use `--sandbox`. - -> [!WARNING] -> **`--yolo` without `--sandbox` runs untrusted, unattended code with no boundary** -> -> A CI job is exactly the environment where a runaway or misled agent does the most damage before anyone notices — no one is at the keyboard to catch a bad `shell` call before it runs, and, per above, a permission allow-list or the shell classifier can't be trusted to catch everything either. If you can't add `--sandbox`, prefer `--safety restricted` with a permission allow-list scoped to what the job actually needs over blanket `--yolo`, and budget for the credentials and blast radius of the agent's toolsets as if the job itself were compromised — see [`examples/permissions.yaml`](https://github.com/docker/docker-agent/blob/main/examples/permissions.yaml) for a worked allow/deny list. - -> [!NOTE] -> **A worktree is not a security boundary either** -> -> [`--worktree`](../../features/cli/index.md#docker-agent-run) isolates *which branch and checkout* the agent modifies — it gives the agent its own working directory and branch so your primary checkout stays untouched — but the shell toolset still runs as a native process on the host, and the worktree shares the repository's underlying object store with the rest of your checkouts. It's checkout isolation, not a security boundary. Only `--sandbox` provides that. - -## Providing Secrets in CI - -Never put provider API keys or MCP tokens in the agent config file. Inject them as environment variables from your CI provider's secret store, or via `--env-from-file` with a file materialized at job start. See [Managing Secrets](../secrets/index.md) for every supported method, including Docker Compose secrets and 1Password references — both of which map cleanly onto CI secret stores. - -## Disabling Telemetry - -Docker Agent's anonymous usage telemetry is enabled by default. In CI you may want it off: - -```bash -$ TELEMETRY_ENABLED=false docker agent run --exec agent.yaml "..." -``` - -See [Telemetry](../../community/telemetry/index.md) for exactly what is (and isn't) collected. - -## Example: GitHub Actions - -A bare OCI registry reference (`myorg/coder`) has no local config you control, so a security-sensitive CI job should check in a small agent config instead. This example runs a checked-in review agent non-interactively against the repository being built: - -```yaml -# .github/agents/review-agent.yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Reviews the changes in a pull request for bugs and security issues - instruction: Review the changes in this PR for bugs and security issues. - toolsets: - - type: shell -``` - -```yaml -# .github/workflows/agent-review.yml -name: Agent code review -on: - pull_request: - -permissions: - contents: read - -jobs: - review: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - with: - persist-credentials: false - - - name: Install docker-agent - run: | - curl -L "https://github.com/docker/docker-agent/releases/latest/download/docker-agent-linux-amd64" -o docker-agent - chmod +x docker-agent - sudo mv docker-agent /usr/local/bin/ - - - name: Run the review agent - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - TELEMETRY_ENABLED: "false" - run: | - docker-agent run --exec --yolo .github/agents/review-agent.yaml --json \ - "Review the changes in this PR for bugs and security issues" \ - | tee agent-events.ndjson - - - name: Upload transcript - if: always() - uses: actions/upload-artifact@v4 - with: - name: agent-events - path: agent-events.ndjson -``` - -This job auto-approves every shell call the review agent makes (`--yolo`) rather than trying to allow-list every `git`/`grep`/`cat` invocation a code review might need — the read surface for "review this diff" is open-ended, and a fixed pattern list is exactly the kind of shell-matching boundary the [previous section](#defense-in-depth-not-a-boundary-permissions-and-shell-command-matching) says not to rely on. If your CI environment has `sbx` installed and configured (GitHub-hosted `ubuntu-latest` does not ship it out of the box), add `--sandbox` and get a real isolation boundary around that `--yolo`: - -```bash -$ docker-agent run --sandbox --exec --yolo .github/agents/review-agent.yaml --json "..." -``` - -Without `--sandbox`, this workflow's safety instead rests on least-privilege secrets (only `ANTHROPIC_API_KEY` is injected — no repo-write token), the top-level `permissions: contents: read` block and `persist-credentials: false` on the checkout step (which together mean the job never holds a write-capable `GITHUB_TOKEN` and never persists one to disk for `git` to pick up), and the job running on a GitHub-hosted, ephemeral runner that's discarded after the job. - -This example omits the GitHub MCP toolset (`docker:github-official`) shown in earlier revisions of this guide: that server requires a `GITHUB_PERSONAL_ACCESS_TOKEN` this workflow doesn't provide, and — because the toolset above has no `name:` field — its tools would be exposed under their raw MCP names (`get_file_contents`, `search_code`, …) rather than a `github_*`-style qualified name, so permission patterns written against that prefix wouldn't match anything anyway. If your review agent needs GitHub API access, add the toolset back with an explicit `name: github`, wire `GITHUB_PERSONAL_ACCESS_TOKEN` through `env:` from a repository secret, and write any `permissions` patterns against the tool names it actually exposes (`github_get_*` only works once the toolset carries that `name:`). - -Swap the model, toolsets, and provider secret for your own — the shape (checkout, install the binary, run `--exec` with `--json` against a checked-in config, upload the transcript) generalizes to any CI provider that can run a shell step. diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/secrets/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/secrets/index.md deleted file mode 100644 index 26fe93547132..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/secrets/index.md +++ /dev/null @@ -1,247 +0,0 @@ ---- -title: "Managing Secrets" -description: "How to securely provide API keys and credentials to Docker Agent using environment variables, env files, Docker Compose secrets, and 1Password references." -keywords: docker agent, ai agents, guides, managing secrets -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/guides/secrets/ ---- - -_How to securely provide API keys and credentials to Docker Agent._ - -## Overview - -Docker Agent needs API keys to talk to model providers (OpenAI, Anthropic, etc.) and MCP tool servers (GitHub, Slack, etc.). These keys are **never stored in config files**. Instead, Docker Agent resolves them at runtime through a chain of secret providers, checked in order (see `pkg/environment/default.go`): - -| Priority | Provider | Description | -| --- | --- | --- | -| 1 | [Environment variables](#environment-variables) | `export OPENAI_API_KEY=sk-...` | -| 2 | [Docker Compose secrets](#docker-compose-secrets) | Files in `/run/secrets/` | -| 3 | [Docker Agent env file](#docker-agent-env-file) | `~/.config/cagent/.env`, written by `docker agent setup` | -| 4 | [Credential helper](#credential-helper) | Custom command declared in `~/.config/cagent/config.yaml` under `credential_helper:` | -| 5 | [Docker Desktop](#docker-desktop) | Secrets stored by the Docker Desktop backend (no setup on a Desktop install) | - -The first provider that has a value wins. You can mix and match — for example, use environment variables for one key and the Docker Agent env file for another. - -> [!NOTE] -> Older Docker Agent versions could also read secrets from the macOS Keychain and the `pass` password manager. These sources are no longer consulted: migrate any keys stored there to one of the sources above, e.g. by re-running `docker agent setup`. - -Whatever provider returns the value, if that value looks like a [1Password secret reference](#1password-references) (it starts with `op://`), Docker Agent resolves it through the `op` CLI before handing it to a model provider or tool. - -When Docker Agent runs an agent with `--sandbox` and a Docker AI gateway is configured, the sandbox proxy authenticates gateway requests itself: it injects your Docker login token into HTTPS requests to the gateway host (docker.com domains only). The token never enters the sandbox — inside it, `DOCKER_TOKEN` is a proxy-managed placeholder. - -## Environment Variables - -The simplest approach. Set variables in your shell before running Docker Agent: - -```bash -export OPENAI_API_KEY=sk-... -export ANTHROPIC_API_KEY=sk-ant-... -docker agent run agent.yaml -``` - -Common variables: - -| Variable | Provider | -| --- | --- | -| `OPENAI_API_KEY` | OpenAI | -| `ANTHROPIC_API_KEY` | Anthropic | -| `GOOGLE_API_KEY` | Google Gemini | -| `MISTRAL_API_KEY` | Mistral | -| `OPENROUTER_API_KEY` | OpenRouter | -| `XAI_API_KEY` | xAI | -| `NEBIUS_API_KEY` | Nebius | - -MCP tools may require additional variables. For example, the GitHub MCP server needs `GITHUB_PERSONAL_ACCESS_TOKEN`. These are passed to tools via the `env` field in your config: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - env: - GITHUB_PERSONAL_ACCESS_TOKEN: $GITHUB_PERSONAL_ACCESS_TOKEN -``` - -## Env Files - -For convenience, you can store secrets in a `.env` file and pass it to Docker Agent with `--env-from-file`: - -```bash -# .env -OPENAI_API_KEY=sk-... -ANTHROPIC_API_KEY=sk-ant-... -GITHUB_PERSONAL_ACCESS_TOKEN=ghp_... -``` - -```bash -docker agent run agent.yaml --env-from-file .env -``` - -The file format supports: - -- `KEY=VALUE` pairs, one per line -- Comments starting with `#` -- Quoted values: `KEY="value with spaces"` -- Blank lines are ignored - -> [!IMPORTANT] -> Add `.env` to your `.gitignore` to avoid committing secrets to version control. - -## Docker Agent env file - -A `.env` file (same format as above) at `~/.config/cagent/.env` is read automatically on every run — no `--env-from-file` flag needed. It is where [`docker agent setup`](../../features/cli/index.md#docker-agent-setup) stores API keys when you choose the env-file location, and you can edit it by hand: - -```bash -# ~/.config/cagent/.env -OPENAI_API_KEY=sk-... -``` - -The file is created with owner-only permissions (`0600`), but the values are stored in plain text. - -## Docker Compose Secrets - -When running Docker Agent in a container with Docker Compose, you can use [Compose secrets](https://docs.docker.com/compose/how-tos/use-secrets/) to inject credentials securely. Compose mounts secrets as files under `/run/secrets/`, and Docker Agent reads from this location automatically. - -### From a file - -Store each secret in its own file, then reference it in `compose.yaml`: - -```bash -echo -n "sk-ant-your-key-here" > .anthropic_api_key -``` - -```yaml -# compose.yaml -services: - agent: - image: docker/docker-agent - command: run --exec /app/agent.yaml "Hello!" - secrets: - - ANTHROPIC_API_KEY - volumes: - - ./agent.yaml:/app/agent.yaml:ro - -secrets: - ANTHROPIC_API_KEY: - file: ./.anthropic_api_key -``` - -Docker Compose mounts the file as `/run/secrets/ANTHROPIC_API_KEY`. Docker Agent picks it up with no extra configuration. - -### From a host environment variable - -In CI/CD pipelines, secrets are often injected as environment variables. Compose can forward these to `/run/secrets/`: - -```yaml -secrets: - ANTHROPIC_API_KEY: - environment: "ANTHROPIC_API_KEY" -``` - -### Multiple secrets - -```yaml -services: - agent: - image: docker/docker-agent - command: run --exec /app/agent.yaml "Summarize my GitHub issues" - secrets: - - ANTHROPIC_API_KEY - - GITHUB_PERSONAL_ACCESS_TOKEN - volumes: - - ./agent.yaml:/app/agent.yaml:ro - -secrets: - ANTHROPIC_API_KEY: - file: ./.anthropic_api_key - GITHUB_PERSONAL_ACCESS_TOKEN: - file: ./.github_token -``` - -### Why use Compose secrets over environment variables? - -| Aspect | Environment Variables | Compose Secrets | -| --- | --- | --- | -| Storage | In memory, visible via `docker inspect` | Mounted as tmpfs files under `/run/secrets/` | -| Visibility | Shown in process list and inspect output | Not exposed in `docker inspect` | -| Best for | Development | Production and CI/CD | - -## Credential Helper - -Docker Agent can shell out to an external credential helper you define in your user config. This is useful when your organisation already has a secrets daemon you want to reuse (HashiCorp Vault, 1Password CLI, `bitwarden-cli`, etc.). - -Declare the helper in `~/.config/cagent/config.yaml`: - -```yaml -# ~/.config/cagent/config.yaml -credential_helper: - command: op - args: ["read", "op://Personal/docker-agent"] -``` - -The command is invoked with the variable name appended as the final argument, and must print the secret value to stdout. - -## Docker Desktop - -On machines where Docker Desktop is installed, Docker Agent queries Docker Desktop's backend for secrets stored against your signed-in Docker account. This is transparent — no extra configuration — and it is how signed-in Docker users get provider API keys without setting any environment variables. - -## Docker Authentication - -Routing model traffic through the [Docker models gateway](../../configuration/models/index.md) needs a Docker token. Docker Desktop hands out one that is valid for 15 minutes and cannot be renewed by Docker Agent, so when Desktop has nothing usable to offer — it is signed out, not running, or its own refresh is stuck — Docker Agent exchanges the long-lived access token that `docker login` left in your credential store for a fresh Docker token, the same exchange `docker login` itself performs. Signing in with `docker login` is therefore enough; Docker Desktop is not required. - -Only Docker access tokens are exchanged — the `dckr_…` secrets `docker login` stores — never an account password, and the exchange goes to Docker Hub over HTTPS. The resulting bearer token is cached in a private file under Docker Agent's cache directory so sibling processes reuse it instead of minting their own, and it stops being used within seconds of a `docker logout` or an account switch. Run `docker agent debug auth` to see which token is in use and where it came from. - -Set `DOCKER_AGENT_NO_TOKEN_EXCHANGE=1` to opt out: Docker Agent then relies on Docker Desktop alone. - -## 1Password References - -Any secret value resolved through the chain above can be a **1Password secret reference** instead of the literal secret. If the value starts with `op://`, Docker Agent resolves it by invoking the [1Password CLI](https://developer.1password.com/docs/cli/) (`op read `) and uses the result. - -This works with every provider — most commonly an environment variable or env file: - -```bash -export OPENAI_API_KEY="op://Personal/OpenAI/api-key" -docker agent run agent.yaml -``` - -References follow the `op:////` format. Make sure the `op` CLI is installed and you are signed in (`op signin`) so that non-interactive reads succeed. - -> [!WARNING] -> **Behaviour when resolution fails** -> -> If the value starts with `op://` but the `op` CLI is not installed, or the reference cannot be read (not signed in, wrong path, locked vault), Docker Agent logs a warning and uses an **empty value** — it never forwards the raw `op://` reference to a model provider or tool. Resolved references (and deterministic failures) are cached for the lifetime of the run; transient failures such as a cancelled lookup are not cached, so a later attempt can retry. - -## Choosing a Method - -| Method | Best for | Setup effort | -| --- | --- | --- | -| Environment variables | Quick local development, scripts | Low | -| Env files | Team projects, multiple keys | Low | -| Docker Agent env file | Keys used across all projects, written by `docker agent setup` | Low | -| Docker Compose secrets | Containerized deployments, CI/CD | Medium | -| Credential helper | Reusing an existing secrets daemon (Vault, 1Password CLI, ...) | Medium | -| 1Password references (`op://`) | Teams already using 1Password | Low | - -You can combine methods. For example, store long-lived provider keys in the Docker Agent env file and pass project-specific MCP tokens via env files. - -## Preventing Secret Leaks - -Provider keys live in the secret store and are passed to Docker Agent through the chain above — the agent itself never receives them as input. But the **content of a conversation** can still leak credentials: a user pasting a token, a tool returning a config file with embedded keys, a transcript dumped into a prompt. - -For that defense-in-depth case, set `redact_secrets: true` on an agent. It scrubs detected secrets out of: - -- the arguments of every outgoing tool call (before the tool sees them), -- every outgoing chat message (before the model provider sees them), and -- every tool's output (before it reaches event consumers, the persisted session file, the `post_tool_use` hook input, or the next LLM call). - -```yaml -agents: - root: - model: openai/gpt-5 - description: A helpful assistant - instruction: You are a helpful assistant. - redact_secrets: true - toolsets: - - type: shell -``` - -The ruleset covers GitHub PATs, AWS / GCP / Azure credentials, Stripe / Slack / GitLab / Hugging Face tokens, JWTs, PEM-encoded private keys, Docker Hub PATs, and many others. Each detected span is replaced with the literal `[REDACTED]`. See the [Redacting Secrets](../../configuration/agents/index.md#redacting-secrets) section in the agent configuration reference for the full picture and important caveats about false negatives. diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/thinking/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/thinking/index.md deleted file mode 100644 index fbdef06dee3b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/thinking/index.md +++ /dev/null @@ -1,363 +0,0 @@ ---- -title: "Thinking / Reasoning" -description: "Control how much a model reasons before responding. Works across OpenAI, Anthropic, Google Gemini, AWS Bedrock, and Docker Model Runner." -keywords: docker agent, ai agents, guides, thinking / reasoning -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/guides/thinking/ ---- - -_Control how much a model reasons before responding. Works across OpenAI, Anthropic, Google Gemini, AWS Bedrock, and Docker Model Runner._ - -## What Is Thinking? - -Several modern models support an extended reasoning phase that happens before they produce visible output. During this phase the model plans, evaluates options, and works through the problem — internally, not shown in the response by default. This typically improves accuracy on complex tasks like coding, math, and multi-step planning, at the cost of higher token usage and latency. - -Docker Agent exposes this through a single `thinking_budget` field on any named model. The value format differs slightly by provider, but the semantics are the same: higher effort means more thorough reasoning. - -> [!NOTE] -> **Think tool vs. thinking budget** -> -> The [think tool](../../tools/think/index.md) is a scratchpad for models that lack native reasoning. If your model supports `thinking_budget`, you do not need the think tool. - -## Quick Reference - -| Provider | Format | Values | Default | -| ------------------- | ---------- | --------------------------------------------------------------------------------------- | ------------------ | -| OpenAI | string | `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`; `xhigh` on gpt-5.2+, `none`/`max` on gpt-5.6+ only, `minimal` dropped on gpt-5.6+ | `medium` (API default) | -| Anthropic | int or str | 1024–32768 tokens, or `minimal`–`max`, `adaptive`, `adaptive/`, `none` | off | -| Gemini 2.5 | int | `0` (off), `-1` (dynamic), or token count (max 24576 / 32768) | `-1` (dynamic) | -| Gemini 3 | string | `minimal`, `low`, `medium`, `high` | API default (model-dependent) | -| AWS Bedrock | int or str | 1024–32768 tokens (`minimal`–`max` mapped to tokens); `adaptive`, `adaptive/` for Opus 4.6+ (rejected by older Claude models) | off | -| Docker Model Runner | int or str | token count, `minimal`–`max` (mapped to tokens), `adaptive` (unlimited), `none` | engine default | - -String values are case-insensitive. The full set of accepted strings is `none`, `minimal`, `low`, `medium`, `high`, `xhigh`, `max`, `adaptive`, and `adaptive/` — but each provider only honors the subset listed above. Unsupported values either fail at request time (OpenAI) or are mapped/ignored as described per provider below. - -> `thinking_budget` is only applied by the providers listed above. Other OpenAI-compatible providers (xAI, Mistral, Ollama, …) currently ignore it — see [xAI and Mistral](#xai-grok-and-mistral). - -## OpenAI - -OpenAI reasoning models (o-series, gpt-5, gpt-5-mini, gpt-5.6 family) use a string effort level that maps to their `reasoning_effort` API parameter. The `xhigh` level requires gpt-5.2+; `none` and `max` require gpt-5.6+ (Sol/Terra/Luna); `minimal` is dropped on gpt-5.6+. - -```yaml -models: - gpt-thinker: - provider: openai - model: gpt-5.6 - thinking_budget: high # none | minimal | low | medium | high | xhigh | max -``` - -**Effort levels:** - -| Level | Description | -| --------- | -------------------------------------------------------- | -| `none` | No reasoning. Sent as-is on gpt-5.6+ (a real API value); on older models it just disables the local `thinking_budget` (the API's own default still applies). | -| `minimal` | Fastest; lightest reasoning pass. Not accepted on gpt-5.6+ (dropped from the API). | -| `low` | Quick reasoning for straightforward tasks. | -| `medium` | Balanced default. | -| `high` | More thorough; recommended for complex tasks. | -| `xhigh` | Near-maximum effort; slower but most accurate. Requires gpt-5.2+. | -| `max` | Maximum effort. Requires gpt-5.6+. | - -Token counts, `adaptive`, and `adaptive/` are rejected with a configuration error at request time. `xhigh` is only supported by gpt-5.2 and later minor versions (e.g. gpt-5.2, gpt-5.4-mini); `none` and `max` are only supported by gpt-5.6 and later (Sol/Terra/Luna); `minimal` is not accepted on gpt-5.6+. Older models (o1, o3-mini) only accept `low`/`medium`/`high` — sending an unsupported level returns an API error. - -> [!WARNING] -> **Tokens and max_tokens** -> -> Older OpenAI reasoning models always reason internally — even with `thinking_budget: none` there are hidden reasoning tokens that count against `max_tokens`. On gpt-5.6+ (Sol/Terra/Luna), `none` is a real API value that genuinely disables reasoning. Docker Agent automatically raises the output-token floor for its internal low-effort calls (e.g. title generation) so hidden reasoning cannot starve visible text output. - -## Anthropic - -Anthropic Claude supports two thinking modes: a **token budget** (older models) and **adaptive / effort-based** thinking (newer models). - -### Token budget (Claude 4 and earlier) - -Set an explicit number of thinking tokens (1024–32768). This must be less than `max_tokens`: - -```yaml -models: - claude-thinker: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 16384 # tokens reserved for internal reasoning -``` - -Docker Agent auto-adjusts `max_tokens` when you set a thinking budget but leave `max_tokens` at its default. If you set `max_tokens` explicitly, it must be greater than `thinking_budget`. - -### Adaptive thinking (Opus 4.6+ and Sonnet 4.6) - -Newer Claude models support adaptive thinking, where the model decides how much to think. **Claude Opus 4.6, 4.7, 4.8, and Sonnet 4.6 only support adaptive thinking** — they reject token-based budgets. Use `adaptive`, `adaptive/`, or a bare effort level — on Anthropic, a bare effort level like `high` is shorthand for adaptive thinking at that effort: - -```yaml -models: - claude-adaptive: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: adaptive # model decides effort (defaults to high) - - claude-adaptive-low: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: low # same as adaptive/low - - claude-adaptive-max: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: adaptive/max # adaptive/low | adaptive/medium | adaptive/high | adaptive/xhigh | adaptive/max -``` - -**Adaptive effort levels and per-model support:** - -| Level | Opus 4.5 | Sonnet 4.5 / Haiku | Sonnet 4.6 | Opus 4.6 | Opus 4.7 / 4.8 | Fable 5 | Mythos 5 | Mythos preview | -| --------- | :------: | :----------------: | :--------: | :------: | :------------: | :-----: | :------: | :------------: | -| `low` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| `medium` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| `high` | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | -| `xhigh` | — | — | — | — | ✓ | ✓ | ✓ | — | -| `max` | — | — | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | - -`minimal` is treated as `low` (bare form only). `high` is the default when `adaptive` is used without an effort level. - -> [!WARNING] -> **Effort strings require adaptive-capable models** -> -> 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). - -### Disabling thinking - -```yaml -thinking_budget: none # or 0 -``` - -### Interleaved thinking - -Interleaved thinking lets the model reason between tool calls — useful for complex agentic tasks. Docker Agent auto-enables it whenever a thinking budget is configured on a Claude model, so you only need to set it explicitly to turn it off: - -```yaml -models: - claude-interleaved: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 16384 - # interleaved_thinking is auto-enabled; disable it explicitly if needed: - provider_opts: - interleaved_thinking: false -``` - -> [!NOTE] -> **Temperature and top_p** -> -> When extended thinking is enabled, Anthropic requires `temperature=1.0`. Docker Agent automatically suppresses any `temperature` or `top_p` settings you have configured — they are silently ignored while thinking is active. - -### Thinking display - -Newer Claude models (Opus 4.7+, Fable 5) hide thinking content by default at the API level. To keep reasoning visible, Docker Agent requests `summarized` thinking whenever adaptive/effort-based thinking is used without an explicit `thinking_display`. Use `thinking_display` in `provider_opts` to override: - -```yaml -models: - opus-47: - provider: anthropic - model: claude-opus-4-7 - thinking_budget: adaptive - provider_opts: - thinking_display: omitted # summarized | omitted (display: pre-4.6 models only) -``` - -| Value | Behavior | -| ------------ | ------------------------------------------------------------------------------------- | -| `summarized` | Thinking blocks returned with a text summary (Docker Agent default for adaptive thinking). | -| `display` | Full thinking blocks returned for display. Pre-4.6 token-thinking models only — rejected by Opus/Sonnet 4.6+, Sonnet 5, and Fable 5 (Docker Agent fails fast with a configuration error). | -| `omitted` | Thinking blocks hidden — only the signature is returned. | - -Full thinking tokens are billed regardless of `thinking_display`. - -### Task budget (Anthropic) - -`task_budget` caps total tokens across an entire multi-step agentic task (thinking + tool calls + output combined): - -```yaml -models: - opus-bounded: - provider: anthropic - model: claude-opus-4-7 - thinking_budget: adaptive - task_budget: 128000 # total token ceiling for the whole task -``` - -See the [Anthropic provider page](../../providers/anthropic/index.md#task-budget) for details. - -## Google Gemini - -Gemini 2.5 and Gemini 3 use different formats. - -### Gemini 2.5 (token budget) - -```yaml -models: - gemini-off: - provider: google - model: gemini-2.5-flash - thinking_budget: 0 # disable thinking - - gemini-dynamic: - provider: google - model: gemini-2.5-flash - thinking_budget: -1 # let the model decide (default) - - gemini-fixed: - provider: google - model: gemini-2.5-flash - thinking_budget: 8192 # fixed token budget (max 24576 for Flash, 32768 for Pro) -``` - -### Gemini 3 (level-based) - -```yaml -models: - gemini3-flash: - provider: google - model: gemini-3-flash - thinking_budget: medium # minimal | low | medium | high - - gemini3-pro: - provider: google - model: gemini-3-pro - thinking_budget: high # low | high (Pro supports fewer levels) -``` - -## AWS Bedrock (Claude) - -Bedrock Claude uses a token budget like Anthropic. String effort levels (`minimal`–`max`) are mapped automatically: - -| Effort level | Token budget | -| ------------ | ------------ | -| `minimal` | 1,024 | -| `low` | 2,048 | -| `medium` | 8,192 | -| `high` | 16,384 | -| `xhigh`/`max`| 32,768 | - -```yaml -models: - bedrock-claude-thinker: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - thinking_budget: 8192 # or use an effort level: medium - provider_opts: - region: us-east-1 - - bedrock-claude-interleaved: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - thinking_budget: high - provider_opts: - region: us-east-1 - # interleaved_thinking is auto-enabled when thinking_budget is set -``` - -**Claude Opus 4.6+ on Bedrock requires adaptive thinking** — these models reject `thinking.type=enabled` (token budgets). Configure them with `adaptive` or `adaptive/`; Docker Agent auto-coerces token budgets and effort levels on these models with a warning: - -```yaml -models: - bedrock-opus-adaptive: - provider: amazon-bedrock - model: global.anthropic.claude-opus-4-8 - thinking_budget: adaptive/high - provider_opts: - region: us-east-1 -``` - -> [!WARNING] -> **Bedrock thinking requirements** -> -> Bedrock Claude requires token-based `thinking_budget` values to be ≥ 1024 and less than `max_tokens`. Docker Agent logs a warning and ignores the budget if either condition is violated. Interleaved thinking requires the `interleaved-thinking-2025-05-14` beta header, which Docker Agent adds automatically; it is auto-enabled whenever a token thinking budget is set on a Bedrock-hosted Claude model (adaptive thinking interleaves on its own). - -## Docker Model Runner (local models) - -For local models, `thinking_budget` is forwarded to the inference engine. Both token counts and effort strings work; effort strings map to the same token scale as Bedrock (`minimal`=1024 … `xhigh`/`max`=32768), and `adaptive` means unlimited: - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - thinking_budget: medium # llama.cpp: reasoning-budget=8192; vLLM: thinking_token_budget=8192 -``` - -- **llama.cpp**: sent as `reasoning-budget` at model-configure time. -- **vLLM**: sent as `thinking_token_budget` on each request. -- **MLX / SGLang**: no reasoning-budget knob; the value is silently ignored. - -See the [Docker Model Runner provider page](../../providers/dmr/index.md) for details. - -## xAI (Grok) and Mistral - -xAI and Mistral run through Docker Agent's OpenAI-compatible client, but the `reasoning_effort` parameter is only sent for OpenAI reasoning model names (o-series, gpt-5). **Setting `thinking_budget` on Grok or Mistral models currently has no effect** — the value is accepted by config validation but never sent to the API. - -Grok and Mistral reasoning models (e.g. `grok-3-mini`, `magistral`) manage reasoning on their own; for non-reasoning models, consider the [think tool](../../tools/think/index.md) instead. - -## Disabling Thinking - -Use `none` or `0` to disable thinking on any provider: - -```yaml -models: - fast-model: - provider: openai - model: gpt-5-mini - thinking_budget: none - - gemini-no-think: - provider: google - model: gemini-2.5-flash - thinking_budget: 0 -``` - -`none` and `0` clear Docker Agent's thinking configuration — no thinking parameter is sent. Models that always reason (OpenAI o-series, gpt-5 through gpt-5.5, Gemini 3) then fall back to the API's default behavior and still reason internally; gpt-5.6+ (Sol/Terra/Luna) sends `none` as a real API value that genuinely disables reasoning. Models with optional thinking (Gemini 2.5, Claude, local models) are also fully disabled. - -## Choosing an Effort Level - -| Task complexity | Recommended level | -| -------------------------------- | ----------------------- | -| Simple factual Q&A | `none` / `minimal` | -| General-purpose chat | `low` / `medium` | -| Coding, debugging, analysis | `medium` / `high` | -| Complex reasoning, planning | `high` / `xhigh` | -| Research, difficult math/logic | `xhigh` / `max` | -| Long agentic tasks (Anthropic) | `adaptive` | - -## Changing Thinking Level at Runtime - -While running in the TUI, press **Shift+Tab** to cycle the thinking effort level for the current model without editing your YAML config, or type `/effort ` to jump straight to a specific level (e.g. `/effort high`). Running `/effort` without an argument opens a picker listing the levels the current model supports: - -- The level steps through the model's supported range (model-specific), wrapping around — for example `none → minimal → low → medium → high → none` on OpenAI gpt-5/o-series, `none → minimal → low → medium → high → xhigh → none` on gpt-5.2+, `none → low → medium → high → xhigh → max → none` on gpt-5.6+ (no `minimal`), `none → low → medium → high → max → none` on Anthropic Opus 4.6 and Sonnet 4.6, and `none → low → medium → high → xhigh → max → none` on Anthropic Opus 4.7+, Fable 5, and Mythos 5. For older Anthropic models (e.g. Sonnet 4.5) that only accept token budgets, effort-string cycling has no effect — use an integer `thinking_budget` in your YAML config instead. -- The current level is shown in the sidebar next to the model name (e.g. `openai/gpt-5 • high`). -- This applies as a session override — it is **not** saved to the config file. The next session starts from the level defined in your YAML. -- For models that don't support reasoning, and for remote runtimes, Shift+Tab is a no-op and an informational message is displayed. -- `/effort` only accepts levels the current model supports; requesting an unsupported level shows the model's supported list. Like Shift+Tab, it is unavailable for non-reasoning models and remote runtimes. -- Press Tab after `/effort` and a space to complete a level from the current model's supported range; it lists the same levels the picker shows (and, like the picker, offers no candidates for non-reasoning models or remote runtimes). - -## Sharing Thinking Config Across Models - -Define a provider with a default `thinking_budget` and all models that reference it inherit it: - -```yaml -providers: - deep-anthropic: - provider: anthropic - thinking_budget: adaptive/high - max_tokens: 32768 - -models: - claude-smart: - provider: deep-anthropic - model: claude-opus-4-6 # inherits thinking_budget: adaptive/high - - claude-faster: - provider: deep-anthropic - model: claude-opus-4-6 - thinking_budget: low # overrides to adaptive/low -``` - -## Full Example - -See [`examples/thinking_budget.yaml`](https://github.com/docker/docker-agent/blob/main/examples/thinking_budget.yaml) for a runnable config covering all providers. diff --git a/_vendor/github.com/docker/docker-agent/docs/guides/tips/index.md b/_vendor/github.com/docker/docker-agent/docs/guides/tips/index.md deleted file mode 100644 index bde25ee34a7c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/guides/tips/index.md +++ /dev/null @@ -1,477 +0,0 @@ ---- -title: "Tips & Best Practices" -description: "Expert guidance for building effective, efficient, and secure agents." -keywords: docker agent, ai agents, guides, tips & best practices -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/guides/tips/ -aliases: - - /ai/docker-agent/best-practices/ ---- - -_Expert guidance for building effective, efficient, and secure agents._ - -## Configuration Tips - -### Auto Mode for Quick Start - -Don't have a config file? Docker Agent can automatically detect your available API keys and use an appropriate model: - -```bash -# Automatically uses the best available provider -$ docker agent run - -# Provider priority: Anthropic → OpenAI → Google → Mistral → Amazon Bedrock → DMR -``` - -The special `auto` model value also works in configs: - -```yaml -agents: - root: - model: auto # Uses best available provider - description: Adaptive assistant - instruction: You are a helpful assistant. -``` - -### Environment Variable Interpolation - -Commands support JavaScript template literal syntax for environment variables: - -```yaml -agents: - root: - model: openai/gpt-4o - description: Deployment assistant - instruction: You help with deployments. - commands: - # Simple variable - greet: "Hello ${env.USER}!" - - # With default value - deploy: "Deploy to ${env.ENV || 'staging'}" - - # Multiple variables - release: "Release ${env.PROJECT} v${env.VERSION || '1.0.0'}" -``` - -### Model Aliases Are Auto-Pinned - -Docker Agent automatically resolves model aliases to their latest pinned versions. This ensures reproducible behavior: - -```yaml -# You write: -model: anthropic/claude-sonnet-4-5 - -# docker-agent resolves to: -# anthropic/claude-sonnet-4-5-20250929 (or latest available) -``` - -To use a specific version, specify it explicitly in your config. - -## Performance Tips - -### Defer Tools for Faster Startup - -Large MCP toolsets can slow down agent startup. Use `defer` to load tools on-demand: - -```yaml -agents: - root: - model: openai/gpt-4o - description: Multi-tool assistant - instruction: You have many tools available. - toolsets: - - type: mcp - ref: docker:github-official - defer: true - - type: mcp - ref: docker:slack - defer: true - - type: mcp - ref: docker:linear - defer: true -``` - -Or defer specific tools within a toolset: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - defer: - - "list_issues" - - "search_repos" - - type: mcp - ref: docker:slack - defer: - - "list_channels" -``` - -### Filter MCP Tools - -Many MCP servers expose dozens of tools. Filter to only what you need: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - # Only expose these specific tools - tools: - - list_issues - - create_issue - - get_pull_request - - create_pull_request -``` - -Fewer tools means faster tool selection and less confusion for the model. - -### Set max_iterations - -Always set `max_iterations` for agents with powerful tools to prevent infinite loops: - -```yaml -agents: - developer: - model: anthropic/claude-sonnet-4-5 - description: Development assistant - instruction: You are a developer. - max_iterations: 30 # Reasonable limit for development tasks - toolsets: - - type: filesystem - - type: shell -``` - -Typical values: 20-30 for development agents, 10-15 for simple tasks. - -## Reliability Tips - -### Use Fallback Models - -Configure fallback models for resilience against provider outages or rate limits: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Reliable assistant - instruction: You are a helpful assistant. - fallback: - models: - # Different provider for resilience - - openai/gpt-4o - # Cheaper model as last resort - - openai/gpt-4o-mini - retries: 2 # Retry 5xx errors twice - cooldown: 1m # Stick with fallback for 1 min after rate limit -``` - -**Best practices for fallback chains:** - -- Use different providers for true redundancy -- Order by preference (best first) -- Include a cheaper/faster model as last resort - -### Use Think Tool for Non-Reasoning Models - -The `think` tool provides a reasoning scratchpad for models that lack built-in thinking capabilities: - -```yaml -toolsets: - - type: think # Useful for models without native reasoning -``` - -The agent uses it as a scratchpad for planning and decision-making. If your model already supports a [thinking budget](../../configuration/models/index.md#thinking-budget) (e.g., Claude with extended thinking, OpenAI o-series, Gemini with thinking enabled), you don't need this tool — the model can reason internally. - -## Security Tips - -### Use --yolo Mode Carefully - -The `--yolo` flag auto-approves all tool calls without confirmation: - -```bash -# Auto-approve everything (use with caution!) -$ docker agent run agent.yaml --yolo -``` - -**When it's appropriate:** - -- CI/CD pipelines with controlled inputs -- Automated testing -- Agents with only safe, read-only tools - -**When to avoid:** - -- Interactive sessions with untested prompts -- Agents with shell or filesystem write access -- Any situation where unreviewed actions could cause harm - -### Combine Permissions with Sandbox - -For defense in depth, use both permissions and [sandbox mode](../../configuration/sandbox/index.md): - -```yaml -agents: - secure_dev: - model: anthropic/claude-sonnet-4-5 - description: Secure development assistant - instruction: You are a secure coding assistant. - toolsets: - - type: filesystem - - type: shell - -permissions: - allow: - - "read_*" - - "shell:cmd=go*" - - "shell:cmd=npm*" - deny: - - "shell:cmd=sudo*" - - "shell:cmd=rm*-rf*" -``` - -```bash -# Run with sandbox enabled -docker-agent run --sandbox agent.yaml -``` - -### Set Global Permission Guardrails - -Use [global permissions](../../configuration/permissions/index.md#global-permissions) in your user config to enforce safety rules across every agent: - -```yaml -# ~/.config/cagent/config.yaml -settings: - permissions: - deny: - - "shell:cmd=sudo*" - - "shell:cmd=rm*-rf*" - - "shell:cmd=git push --force*" - allow: - - "read_*" - - "shell:cmd=ls*" - - "shell:cmd=cat*" -``` - -These rules merge with any agent-level permissions. Deny patterns from your global config cannot be overridden by agent configs, so you can trust that dangerous commands stay blocked regardless of which agent you run. - -### Use Hooks for Audit Logging - -Log all tool calls for compliance or debugging: - -```yaml -agents: - audited: - model: openai/gpt-4o - description: Audited assistant - instruction: You are a helpful assistant. - hooks: - post_tool_use: - - matcher: "*" - hooks: - - type: command - command: "./scripts/audit-log.sh" -``` - -## Multi-Agent Tips - -### Handoffs vs Sub-Agents - -Understand the difference between `sub_agents` and `handoffs`: - -- **`sub_agents` (transfer_task)** — delegates a task to a child in a sub-session, waits for the result, then continues. Hierarchical: the parent remains in control. - - ```yaml - sub_agents: [researcher, writer] - ``` - -- **`handoffs` (peer-to-peer)** — hands off the entire conversation to another agent in the same session. The active agent switches and sees the full history. Agents can form cycles. - - ```yaml - handoffs: - - specialist - - summarizer - ``` - -See [Multi-Agent Systems](../../concepts/multi-agent/index.md) for a detailed comparison. - -### Give Sub-Agents Clear Descriptions - -The root agent uses descriptions to decide which sub-agent to delegate to: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Technical lead - instruction: Delegate to specialists based on the task. - sub_agents: [frontend, backend, devops] - - frontend: - model: openai/gpt-4o - # Good: specific and actionable - description: | - Frontend specialist. Handles React, TypeScript, CSS, - UI components, and browser-related issues. - - backend: - model: openai/gpt-4o - # Good: clear domain boundaries - description: | - Backend specialist. Handles APIs, databases, - server logic, and Go/Python code. - - devops: - model: openai/gpt-4o - description: | - DevOps specialist. Handles CI/CD, Docker, Kubernetes, - infrastructure, and deployment pipelines. -``` - -## Debugging Tips - -### Enable Debug Logging - -Use the `--debug` flag to see detailed execution logs: - -```bash -# Default log location: ~/.cagent/cagent.debug.log -$ docker agent run agent.yaml --debug - -# Custom log location -$ docker agent run agent.yaml --debug --log-file ./debug.log -``` - -### Check Token Usage - -Use the `/cost` command during a session to see token consumption: - -```text -/cost - -Token Usage: - Input: 12,456 tokens - Output: 3,789 tokens - Total: 16,245 tokens -``` - -### Compact Long Sessions - -If a session gets too long, use `/compact` to summarize and reduce context: - -```text -/compact - -Session compacted. Summary generated and history trimmed. -``` - -## More Tips - -### User-Defined Default Model - -Set your preferred default model in `~/.config/cagent/config.yaml`: - -```yaml -settings: - default_model: anthropic/claude-sonnet-4-5 -``` - -This model is used by the built-in default agent when you run `docker agent run` without a config argument and no project-level `docker-agent.yaml`, `docker-agent.yml`, or `docker-agent.hcl` exists. - -### Get Desktop Notifications with Hooks - -Long-running agents shouldn't require staring at the terminal. Add [global hooks](../../configuration/hooks/index.md#global-user-level-hooks) to your user config so every agent notifies you when it needs attention or finishes: - -```yaml -# ~/.config/cagent/config.yaml -settings: - hooks: - # Agent is waiting for your input (question, approval prompt, ...) - on_user_input: - - type: command - command: osascript -e 'display notification "Agent needs your input" with title "docker-agent"' - - # Agent finished responding - stop: - - type: command - command: osascript -e 'display notification "Task finished" with title "docker-agent"' -``` - -On Linux, replace `osascript` with `notify-send`: - -```yaml -command: notify-send "docker-agent" "Agent needs your input" -``` - -Hooks inherit Docker Agent's environment, so this works as-is from a desktop terminal. In detached contexts (SSH, tmux started outside your desktop session, containers), `notify-send` needs the session's `DISPLAY` and `DBUS_SESSION_BUS_ADDRESS` to reach the notification daemon, and fails silently without them. Pass them with the per-hook `env` option: - -```yaml -on_user_input: - - type: command - command: notify-send "docker-agent" "Agent needs your input" - env: - DISPLAY: ":0" - DBUS_SESSION_BUS_ADDRESS: "unix:path=/run/user/1000/bus" -``` - -To also get alerted on errors and warnings, hook the `notification` event and read the message from the JSON payload on stdin: - -```yaml -settings: - hooks: - notification: - - type: command - timeout: 10 - command: | - MESSAGE=$(cat | jq -r '.notification_message // "Agent error"') - osascript -e "display notification \"$MESSAGE\" with title \"docker-agent\"" -``` - -If a sound is enough, set `settings: { sound: true }` instead — Docker Agent plays a failure sound when a task errors, and a success sound when a task that ran longer than `sound_threshold` seconds (default 10) completes. - -See the [Hooks documentation](../../configuration/hooks/index.md) for the full list of events, their payloads, and per-hook options (`env`, `working_dir`, `timeout`). - -### GitHub PR Reviewer Example - -Use Docker Agent as a GitHub Actions PR reviewer: - -```yaml -# .github/workflows/pr-review.yml -name: PR Review -on: - pull_request: - types: [opened, synchronize] - -jobs: - review: - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - name: Run docker-agent review - env: - ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }} - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - # Install docker-agent - curl -fsSL https://get.docker-agent.dev | sh - - # Run the review - docker agent run --exec reviewer.yaml --yolo \ - "Review PR #${{ github.event.pull_request.number }}" -``` - -With a simple reviewer agent: - -```yaml -# reviewer.yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: PR reviewer - instruction: | - Review pull requests for code quality, bugs, and security issues. - Be constructive and specific in your feedback. - toolsets: - - type: mcp - ref: docker:github-official - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/_index.md b/_vendor/github.com/docker/docker-agent/docs/providers/_index.md deleted file mode 100644 index 22c440cfe7a5..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Model Providers" -description: "Model providers supported by Docker Agent." -weight: 60 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/anthropic/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/anthropic/index.md deleted file mode 100644 index 69c8041f1d35..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/anthropic/index.md +++ /dev/null @@ -1,241 +0,0 @@ ---- -title: "Anthropic" -description: "Use Claude Sonnet 4, Claude Sonnet 4.5, and other Anthropic models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, anthropic -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/providers/anthropic/ ---- - -_Use Claude Sonnet 4, Claude Sonnet 4.5, and other Anthropic models with Docker Agent._ - -## Setup - -```bash -# Set your API key -export ANTHROPIC_API_KEY="sk-ant-..." -``` - -### Workload Identity Federation (no API key) - -Authenticate with short-lived tokens minted from your own OIDC identity -provider instead of a long-lived API key. See Anthropic's -[Workload Identity Federation guide](https://platform.claude.com/docs/en/build-with-claude/workload-identity-federation) -to provision a Federation Rule, then configure Docker Agent with a typed -`auth:` block: - -```yaml -providers: - anthropic-wif: - provider: anthropic - auth: - type: workload_identity_federation - workload_identity_federation: - federation_rule_id: fdrl_REPLACE_ME - organization_id: 00000000-0000-0000-0000-000000000000 - # Optional: only required for target_type=SERVICE_ACCOUNT rules. - service_account_id: svac_REPLACE_ME - identity_token: - # Pick exactly one of: file, env, command, url - file: /var/run/secrets/anthropic.com/token - -models: - claude: - provider: anthropic-wif - model: claude-sonnet-4-5 -``` - -`identity_token` accepts four mutually exclusive sources: - -| Source | When to use | -| --------- | ------------------------------------------------------------------------------------------------------------------------ | -| `file` | Kubernetes projected service-account tokens, SPIFFE/SPIRE helpers, Vault sidecars — anything that rotates a file on disk | -| `env` | The token is already exported in an environment variable | -| `command` | Shell out to a CLI on every refresh (`gcloud auth print-identity-token`, `az account get-access-token`, ...) | -| `url` | Fetch from an HTTP(S) endpoint (cloud metadata servers, GitHub Actions OIDC token URL, ...) | - -For `url`, both the URL and any header values support `${env.VAR}` expansion -against the runtime environment (the legacy `${VAR}` form is also accepted), -which lets you wire the GitHub Actions OIDC -token endpoint without putting secrets in YAML: - -```yaml -identity_token: - url: ${env.ACTIONS_ID_TOKEN_REQUEST_URL}&audience=https://api.anthropic.com - headers: - Authorization: bearer ${env.ACTIONS_ID_TOKEN_REQUEST_TOKEN} - response_field: value -``` - -`auth:` is mutually exclusive with `--gateway`. Token-refresh failures are -surfaced through the normal error path with a clear `anthropic workload -identity federation: failed to refresh identity token from source -(federation_rule=fdrl_…): ...` message in the TUI. - -A complete walkthrough of all four sources lives in -[`examples/anthropic_wif.yaml`](https://github.com/docker/docker-agent/blob/main/examples/anthropic_wif.yaml). - -## Configuration - -### Inline - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 -``` - -### Named Model - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 -``` - -## Available Models - -| Model ID | Description | -| ------------------- | --------------------------------------------------- | -| `claude-opus-5` | Highest-capability Opus model; full effort ladder (low–max) | -| `claude-opus-4-7` | Previous Opus flagship; supports task budget | -| `claude-sonnet-4-5` | Most capable Sonnet; supports extended thinking | -| `claude-sonnet-4-0` | Previous Sonnet generation, still supported | -| `claude-haiku-4-5` | Fast and inexpensive, good for tight loops | - -## Thinking Budget - -Anthropic accepts either an integer token budget or a string effort value. Thinking is off unless you set `thinking_budget`; when set, interleaved thinking is auto-enabled. - -**Token budget** (1024–32768; works on all extended-thinking Claude models): - -```yaml -models: - claude-deep: - provider: anthropic - model: claude-sonnet-4-5 - thinking_budget: 16384 # must be < max_tokens -``` - -**Adaptive / effort-based** (Claude Opus 4.6+, Sonnet 4.6 — every string value is sent as adaptive thinking via `output_config.effort`): - -```yaml -models: - opus-adaptive: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: adaptive # model decides effort (defaults to high) - - opus-effort: - provider: anthropic - model: claude-opus-4-6 - thinking_budget: high # low | medium | high | xhigh | max (same as adaptive/) -``` - -On models that reject token-based thinking (Opus 4.6, 4.7, 4.8, Sonnet 4.6), an integer budget is automatically coerced to `adaptive` with a logged warning. See the [Thinking / Reasoning guide](../../guides/thinking/index.md) for the full cross-provider reference. - -## Interleaved Thinking - -Auto-enabled whenever a thinking budget is configured on a Claude model. Allows tool calls during model reasoning for more integrated problem-solving: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - provider_opts: - interleaved_thinking: false # disable if needed -``` - -## Task Budget - -`task_budget` caps the **total** number of tokens the model may spend across a -multi-step agentic task — combined thinking, tool calls, and final output. It -is forwarded as -[`output_config.task_budget`](https://platform.claude.com/docs/en/about-claude/models/whats-new-claude-4-7) -and is ideal for letting long-running agents self-regulate effort without -tightening `max_tokens` on every call. - -Docker Agent automatically attaches the required `task-budgets-2026-03-13` -beta header whenever this field is set. You can configure `task_budget` on -**any** Claude model — Docker Agent never gates it by model name. At the time -of writing, only **Claude Opus 4.7** actually honors the field; other Claude -models (Sonnet 4.5, Opus 4.5 / 4.6, etc.) are expected to reject requests -that include it. Check the Anthropic release notes linked above for the -current list of supported models. - -```yaml -models: - opus: - provider: anthropic - model: claude-opus-4-7 - task_budget: 128000 # integer shorthand → { type: tokens, total: 128000 } - thinking_budget: adaptive -``` - -Object form (forward-compatible with future budget types): - -```yaml - opus: - provider: anthropic - model: claude-opus-4-7 - task_budget: - type: tokens - total: 128000 -``` - -See the full schema on the [Model Configuration](../../configuration/models/index.md#task-budget) page. - -## Server-Side Fallbacks - -When the primary model refuses a request (e.g. Claude Fable 5's safety -classifiers ending the turn with stop reason `refusal`), Anthropic can retry -the request with backup models in a single round trip. Set `fallbacks` in -`provider_opts` to a list of model IDs, in priority order: - -```yaml -models: - fable: - provider: anthropic - model: claude-fable-5 - provider_opts: - fallbacks: - - claude-opus-4-8 - - claude-sonnet-4-6 -``` - -Docker Agent automatically attaches the required -`server-side-fallback-2026-06-01` beta header and forwards the option as -`fallbacks: [{"model": "..."}]`. The response's `model` field reports which -model actually served the request. - -Fallback models receive the exact same request as the primary model -(thinking configuration, task budget, beta features, ...), so list only -models that accept the same request shape. Not available on Bedrock, Vertex -AI, or the Message Batches API. - -## Thinking Display - -Controls whether thinking blocks are returned in responses when thinking is enabled. Newer Claude models (Opus 4.7+, Fable 5) hide thinking content by default (`omitted`); Docker Agent counters this by requesting `summarized` thinking whenever an adaptive/effort-based budget is used without an explicit `thinking_display`, so reasoning stays visible in the UI. Set `thinking_display` in `provider_opts` to override: - -```yaml -models: - claude-opus-4-7: - provider: anthropic - model: claude-opus-4-7 - thinking_budget: adaptive - provider_opts: - thinking_display: omitted # "summarized" or "omitted" ("display" on pre-4.6 models only) -``` - -Valid values: - -- `summarized`: thinking blocks are returned with summarized thinking text (Docker Agent's default for adaptive/effort-based budgets). -- `display`: thinking blocks are returned for display. Only accepted by pre-4.6 token-thinking models (e.g. Sonnet 4.5, Haiku 4.5); models from the adaptive-thinking generation onward (Opus/Sonnet 4.6+, Sonnet 5, Fable 5) reject it, and Docker Agent fails fast with a configuration error instead of sending a request the API would refuse. -- `omitted`: thinking blocks are returned with an empty thinking field; the signature is still returned for multi-turn continuity. Useful to reduce time-to-first-text-token when streaming. - -Note: `thinking_display` applies to both `thinking_budget` with token counts and adaptive/effort-based budgets. For token-count budgets no default is applied (the API already defaults to `summarized`). Full thinking tokens are billed regardless of the `thinking_display` value. - -> [!NOTE] -> Anthropic thinking budget values below 1024 or greater than or equal to `max_tokens` are ignored (a warning is logged). diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/baseten/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/baseten/index.md deleted file mode 100644 index f36428484838..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/baseten/index.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: "Baseten" -description: "Use Baseten AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, baseten -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/providers/baseten/ ---- - -_Use Baseten AI models with Docker Agent._ - -## Overview - -Baseten provides AI models through an OpenAI-compatible API. Docker Agent includes built-in support for Baseten as an alias provider. - -## Setup - -1. Get an API key from [Baseten](https://www.baseten.co/) -2. Set the environment variable: - - ```bash - export BASETEN_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Baseten: - -```yaml -agents: - root: - model: baseten/deepseek-ai/DeepSeek-V3.1 - description: Assistant using Baseten - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - baseten_model: - provider: baseten - model: deepseek-ai/DeepSeek-V3.1 - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: baseten_model - description: Assistant using Baseten - instruction: You are a helpful assistant. -``` - -## Available Models - -Baseten hosts various open models through its Model APIs. Check the [Baseten documentation](https://docs.baseten.co/) for the current model catalog. - -| Model | Description | -| ------------------------------ | ------------------------------ | -| `deepseek-ai/DeepSeek-V3.1` | DeepSeek V3.1 model | -| `moonshotai/Kimi-K2.5` | Moonshot Kimi K2.5 model | -| `openai/gpt-oss-120b` | GPT-OSS 120B model | -| `zai-org/GLM-5` | GLM-5 model | - -## How It Works - -Baseten is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://inference.baseten.co/v1` -- **Token Variable:** `BASETEN_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: baseten/deepseek-ai/DeepSeek-V3.1 - description: Code assistant using DeepSeek - instruction: | - You are an expert programmer using DeepSeek V3.1. - Write clean, well-documented code. - Follow best practices for the language being used. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/bedrock/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/bedrock/index.md deleted file mode 100644 index f7e190a08602..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/bedrock/index.md +++ /dev/null @@ -1,175 +0,0 @@ ---- -title: "AWS Bedrock" -description: "Access Claude, Nova, Llama, and more through AWS infrastructure with enterprise-grade security and compliance." -keywords: docker agent, ai agents, model providers, llm, aws bedrock -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/providers/bedrock/ ---- - -_Access Claude, Nova, Llama, and more through AWS infrastructure with enterprise-grade security and compliance._ - -## Prerequisites - -- AWS account with Bedrock enabled in your region -- Model access granted in the [Bedrock Console](https://console.aws.amazon.com/bedrock/) (some models require approval) -- AWS credentials configured (see authentication below) - -## Configuration - -```yaml -models: - bedrock-claude: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - max_tokens: 64000 - provider_opts: - region: us-east-1 -``` - -## Authentication - -### Option 1: Bedrock API Key (Simplest) - -```bash -export AWS_BEARER_TOKEN_BEDROCK="your-key" -``` - -```yaml -models: - bedrock: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - token_key: AWS_BEARER_TOKEN_BEDROCK # env var name - provider_opts: - region: us-east-1 -``` - -### Option 2: AWS Credentials (Default) - -Uses the standard AWS SDK credential chain: env vars → shared credentials → config → IAM roles. - -```yaml -models: - bedrock: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - provider_opts: - profile: my-aws-profile - region: us-east-1 -``` - -### With IAM Role Assumption - -```yaml -models: - bedrock: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - provider_opts: - role_arn: "arn:aws:iam::123456789012:role/BedrockAccessRole" - external_id: "my-external-id" -``` - -## Provider Options - -| Option | Type | Default | Description | -| ------------------------ | ------ | ---------------------- | ------------------------------------ | -| `region` | string | us-east-1 | AWS region | -| `profile` | string | — | AWS profile name | -| `role_arn` | string | — | IAM role ARN for assume role | -| `role_session_name` | string | docker-agent-bedrock-session | Session name for assumed role | -| `external_id` | string | — | External ID for role assumption | -| `endpoint_url` | string | — | Custom endpoint (VPC/testing) | -| `interleaved_thinking` | bool | auto | Allow reasoning between tool calls (Claude); auto-enabled when a thinking budget is set on a Claude model; adds the required beta header automatically | -| `disable_prompt_caching` | bool | false | Disable automatic prompt caching | - -## Inference Profiles - -Use inference profile prefixes for optimal routing: - -| Prefix | Routes To | -| --------- | ---------------------------------------- | -| `global.` | All commercial AWS regions (recommended) | -| `us.` | US regions only | -| `eu.` | EU regions only (GDPR compliance) | -| `apac.` | Asia Pacific regions only | - -> [!TIP] -> **Inference profiles** -> -> Use `global.` prefix on model IDs for automatic cross-region routing. Use `eu.` prefix for GDPR compliance. - -## Thinking Budget (Claude on Bedrock) - -Bedrock Claude models support extended thinking — an internal reasoning phase before the model produces its response. Set `thinking_budget` to a token count (1024–32768) or an effort level string that maps automatically: - -| Effort level | Token budget | -| ------------ | ------------ | -| `minimal` | 1,024 | -| `low` | 2,048 | -| `medium` | 8,192 | -| `high` | 16,384 | -| `xhigh`/`max`| 32,768 | - -```yaml -models: - bedrock-claude-thinking: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - thinking_budget: 8192 # tokens, or use an effort string like "medium" - max_tokens: 16384 # must be > thinking_budget - provider_opts: - region: us-east-1 -``` - -`thinking_budget` must be ≥ 1024 and less than `max_tokens`. Values outside this range are logged as a warning and ignored. - -### Adaptive thinking (Opus 4.6+) - -Newer Claude Opus models (4.6, 4.7, 4.8) **reject token-based thinking** — Bedrock returns a `ValidationException` asking for `thinking.type=adaptive`. For these models, use adaptive thinking: - -```yaml -models: - bedrock-opus-adaptive: - provider: amazon-bedrock - model: global.anthropic.claude-opus-4-8 - thinking_budget: adaptive/high # adaptive | adaptive/low | adaptive/medium | adaptive/high | adaptive/xhigh | adaptive/max - provider_opts: - region: us-east-1 -``` - -Docker Agent recognizes these models (including Bedrock-style IDs) and transparently coerces a configured token budget or effort level to adaptive thinking, logging a warning — so `thinking_budget: 32768` on Opus 4.8 won't fail, but `adaptive` or `adaptive/` is the recommended configuration. On older models that still use token-based thinking (e.g. Sonnet 4.5), `adaptive` is forwarded as-is and rejected by Bedrock — use a token count or effort level there instead. - -> [!NOTE] -> **Temperature and top_p** -> -> Bedrock Claude suppresses `temperature` and `top_p` while extended thinking is active — Anthropic requires `temperature=1.0` internally. - -## Interleaved Thinking (Claude on Bedrock) - -Interleaved thinking lets the model reason between tool calls, not just at the start. This is useful for complex agentic tasks. Enable it alongside a thinking budget: - -```yaml -models: - bedrock-claude-interleaved: - provider: amazon-bedrock - model: global.anthropic.claude-sonnet-4-5-20250929-v1:0 - thinking_budget: high - provider_opts: - region: us-east-1 - # interleaved_thinking is auto-enabled when thinking_budget is set -``` - -Docker Agent auto-enables `interleaved_thinking` whenever a thinking budget is configured on a Bedrock-hosted Claude model and automatically adds the `interleaved-thinking-2025-05-14` beta header. If you set `interleaved_thinking: false` while a thinking budget is active, a warning is logged because the budget may be ignored by Bedrock without the beta header. - -See the [Thinking / Reasoning guide](../../guides/thinking/index.md) for a full cross-provider overview. - -## Prompt Caching - -Automatically enabled for supported models to reduce latency and costs. System prompts, tool definitions, and recent messages are cached with a 5-minute TTL. - -```bash -# Disable if needed -provider_opts: - disable_prompt_caching: true -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/cerebras/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/cerebras/index.md deleted file mode 100644 index bf0dba14c912..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/cerebras/index.md +++ /dev/null @@ -1,103 +0,0 @@ ---- -title: "Cerebras" -description: "Use Cerebras models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, cerebras -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/providers/cerebras/ ---- - -_Use Cerebras models with Docker Agent._ - -## Overview - -[Cerebras](https://www.cerebras.ai/) serves open-weight models such as GPT-OSS -and GLM through an OpenAI-compatible API on its wafer-scale hardware, delivering -some of the highest tokens/sec available. That speed makes it a strong fit for -latency-sensitive coding workflows. Docker Agent includes built-in support for -Cerebras as an alias provider. - -## Setup - -1. Create an API key from the [Cerebras Cloud console](https://cloud.cerebras.ai/). -2. Set the environment variable: - - ```bash - export CEREBRAS_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Cerebras: - -```yaml -agents: - root: - model: cerebras/gpt-oss-120b - description: Assistant using Cerebras - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - cerebras_model: - provider: cerebras - model: gpt-oss-120b - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: cerebras_model - description: Assistant using Cerebras - instruction: You are a helpful assistant. -``` - -## Available Models - -Cerebras hosts a curated set of open-weight models. Check the -[Cerebras models documentation](https://inference-docs.cerebras.ai/models/overview) -for current model IDs, context limits, and pricing. - -| Model | Description | -| --- | --- | -| `gpt-oss-120b` | Open-weight GPT-OSS reasoning model with tool calling | -| `zai-glm-4.7` | Z.AI GLM-4.7 reasoning model with tool calling | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. Cerebras may serve additional models not in the built-in catalog; those -> still work but resolve to default capability metadata locally. - -## How It Works - -Cerebras is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.cerebras.ai/v1` -- **Token Variable:** `CEREBRAS_API_KEY` - -Because Cerebras fronts open-weight models whose chat templates may only accept -a single leading system message, Docker Agent coalesces its per-source system -messages (agent instruction plus each toolset's instructions) into one before -sending the request. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: cerebras/gpt-oss-120b - description: Fast code assistant using Cerebras - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/chatgpt/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/chatgpt/index.md deleted file mode 100644 index ed50250056b5..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/chatgpt/index.md +++ /dev/null @@ -1,128 +0,0 @@ ---- -title: "ChatGPT (OpenAI account)" -description: "Use your ChatGPT Plus/Pro/Business subscription with Docker Agent by signing in with your OpenAI account, no API key needed." -keywords: docker agent, ai agents, model providers, llm, chatgpt, openai, codex, subscription -weight: 55 -canonical: https://docs.docker.com/ai/docker-agent/providers/chatgpt/ ---- - -_Use your ChatGPT subscription with Docker Agent by signing in with your OpenAI account. No API key needed._ - -## Overview - -The `chatgpt` provider authenticates with a ChatGPT account (the same -"Sign in with ChatGPT" flow used by OpenAI's Codex CLI) instead of an -`OPENAI_API_KEY`. Usage is billed against your ChatGPT Plus, Pro, or -Business plan rather than pay-per-token API credits. - -Under the hood, Docker Agent talks to the ChatGPT Codex backend -(`https://chatgpt.com/backend-api/codex`), which serves the `gpt-5` model -family over the OpenAI Responses API. GPT-5.6 (Sol/Terra/Luna) is served -there too; GPT-5.2 and GPT-5.3-Codex are deprecated for ChatGPT sign-in. - -## Prerequisites - -- A paid **ChatGPT** subscription (Plus, Pro, or Business). -- A browser on the machine running the sign-in (the OAuth flow uses a - fixed `localhost:1455` callback). - -## Sign In - -```bash -docker agent setup -``` - -Pick **chatgpt** in the provider list: instead of asking for an API key, the -wizard opens your browser on the ChatGPT sign-in page and stores the -resulting OAuth credential in the Docker Agent config directory -(`~/.config/cagent/chatgpt-auth.json`, owner-only permissions). The access -token is refreshed automatically; you only need to sign in again if the -refresh token is revoked. - -Related commands: - -```bash -docker agent doctor # the chatgpt row shows the credential state -rm ~/.config/cagent/chatgpt-auth.json # sign out (remove the stored sign-in) -``` - -## Configuration - -### Inline - -```yaml -agents: - root: - model: chatgpt/gpt-5.6 - instruction: You are a helpful assistant. -``` - -### Named model - -```yaml -models: - gpt: - provider: chatgpt - model: gpt-5.6 - thinking_budget: medium - -agents: - root: - model: gpt -``` - -## Available Models - -The Codex backend serves the models available to your ChatGPT plan, -typically: - -| Model | Best For | -| -------------------- | -------------------------------------- | -| `gpt-5.6` | Alias for `gpt-5.6-sol`; general purpose, strong reasoning | -| `gpt-5.6-sol` | Frontier model, most capable | -| `gpt-5.6-terra` | Everyday workhorse | -| `gpt-5.6-luna` | High-volume, cost-efficient | -| `gpt-5.2` | Deprecated for ChatGPT sign-in | -| `gpt-5.2-codex` | Deprecated for ChatGPT sign-in | - -The effort picker exposes Low/Medium/High/XHigh/Max on the GPT-5.6 family -(no Minimal). - -## How It Works - -- **Auth:** the `docker agent setup` sign-in runs an OAuth 2.0 - authorization-code + PKCE flow against `auth.openai.com`. The stored login - is exposed to credential checks (doctor, `first_available`, auto model - selection) as the virtual `CHATGPT_OAUTH_TOKEN` variable. -- **API:** requests go to the Responses API only; the backend has no Chat - Completions endpoint, so `api_type` is pinned automatically. -- **Request shape:** the backend requires stateless requests (`store: false`) - and a top-level `instructions` field, so Docker Agent moves system messages - there. Client-side sampling parameters (`temperature`, `top_p`, - `max_tokens`) are not supported by the backend and are dropped. - -## Setting the Token Explicitly - -`CHATGPT_OAUTH_TOKEN` can also be set like any other credential (shell -environment, `--env-from-file`, ...). An explicitly set value takes -precedence over the stored sign-in. This is useful for short-lived CI runs -with a pre-minted access token, but note that such a token expires and is not -refreshed. - -## ChatGPT Subscription vs. OpenAI API Key - -| | `chatgpt` | `openai` | -| --- | --- | --- | -| Credential | ChatGPT account sign-in | `OPENAI_API_KEY` | -| Billing | Included in the ChatGPT plan (rate-limited) | Pay per token | -| Models | `gpt-5` family served by the Codex backend | Full OpenAI API catalog | -| Sampling controls (`temperature`, ...) | Not supported | Supported | -| Embeddings / reranking | Not supported | Supported | - -When both credentials are configured, automatic model selection prefers -`openai`; pin `--model chatgpt/gpt-5.6` (or use a named model) to use the -subscription. - -> [!NOTE] -> Use of the Codex backend is governed by OpenAI's terms for ChatGPT and -> Codex. Sign-in is per user; do not share the stored credential. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-ai-gateway/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-ai-gateway/index.md deleted file mode 100644 index 558d8c6e03b0..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-ai-gateway/index.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: "Cloudflare AI Gateway" -description: "Use Cloudflare AI Gateway models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, cloudflare ai gateway -weight: 60 -canonical: https://docs.docker.com/ai/docker-agent/providers/cloudflare-ai-gateway/ ---- - -_Use Cloudflare AI Gateway models with Docker Agent._ - -## Overview - -[Cloudflare AI Gateway](https://developers.cloudflare.com/ai-gateway/) is a -single OpenAI-compatible endpoint that routes to models from OpenAI, Anthropic, -Workers AI and more, with caching, rate limiting and observability. Docker Agent -includes built-in support for AI Gateway as an alias provider. - -The alias sends your token in the standard `Authorization: Bearer` header, so it -works out of the box with a gateway that has **authentication disabled** (the -default), typically to route to your own Workers AI models through a gateway you -own. See [Authentication](#authentication) below for the unified-billing / -authenticated-gateway caveat. - -## Setup - -The gateway endpoint is account- and gateway-scoped, so its base URL is resolved -from your account ID and gateway ID. Three environment variables are required: - -```bash -export CLOUDFLARE_ACCOUNT_ID=your-account-id -export CLOUDFLARE_GATEWAY_ID=your-gateway-id -export CLOUDFLARE_API_TOKEN=your-api-token -``` - -Create a gateway from the -[AI Gateway dashboard](https://dash.cloudflare.com/?to=/:account/ai/ai-gateway) -and an API token with the appropriate permissions. - -## Usage - -AI Gateway model IDs use the gateway's `provider/model` form (for example -`workers-ai/@cf/meta/llama-3.1-8b-instruct` or `openai/gpt-4o`); the gateway -routes each request to the underlying provider. - -### Inline Syntax - -```yaml -agents: - root: - model: cloudflare-ai-gateway/workers-ai/@cf/meta/llama-3.1-8b-instruct - description: Assistant using Cloudflare AI Gateway - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - cloudflare_model: - provider: cloudflare-ai-gateway - model: "workers-ai/@cf/meta/llama-3.1-8b-instruct" - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: cloudflare_model - description: Assistant using Cloudflare AI Gateway - instruction: You are a helpful assistant. -``` - -## Available Models - -AI Gateway exposes models from many providers behind one endpoint. Check the -[AI Gateway documentation](https://developers.cloudflare.com/ai-gateway/) for -the current provider list, model IDs, and how billing works. - -> Model IDs are case-sensitive and must be passed exactly as the gateway lists -> them, including the `provider/` prefix. - -## How It Works - -Cloudflare AI Gateway is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://gateway.ai.cloudflare.com/v1/${CLOUDFLARE_ACCOUNT_ID}/${CLOUDFLARE_GATEWAY_ID}/compat` -- **Token Variable:** `CLOUDFLARE_API_TOKEN` - -The base URL is templated: `${CLOUDFLARE_ACCOUNT_ID}` and -`${CLOUDFLARE_GATEWAY_ID}` are substituted from the environment when the provider -is built, so both must be set in addition to `CLOUDFLARE_API_TOKEN`. Because the -gateway can route to open-weight models with strict chat templates, Docker Agent -coalesces consecutive system messages into a single leading one for this -provider. - -## Authentication - -Docker Agent authenticates by sending `CLOUDFLARE_API_TOKEN` in the standard -`Authorization: Bearer` header. On the `.../compat` endpoint that header is -treated as the **provider** key, so this alias works when: - -- the gateway has **authentication disabled** (the default), and -- the routed models accept that token as their provider key, which is the case - for **Workers AI** models (`workers-ai/@cf/...`). - -A gateway with **authentication enabled** (required for -[unified billing](https://developers.cloudflare.com/ai-gateway/features/unified-billing/)) -instead expects the token in Cloudflare's `cf-aig-authorization` header. The -alias does not send that header, and custom `provider_opts.http_headers` values -are not environment-expanded, so an authenticated gateway is **not supported out -of the box** today. For that setup, use an unauthenticated gateway, or configure -a [custom provider](../custom/index.md) against the -Cloudflare AI Gateway REST API. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-workers-ai/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-workers-ai/index.md deleted file mode 100644 index 68477296aee6..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/cloudflare-workers-ai/index.md +++ /dev/null @@ -1,91 +0,0 @@ ---- -title: "Cloudflare Workers AI" -description: "Use Cloudflare Workers AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, cloudflare workers ai -weight: 70 -canonical: https://docs.docker.com/ai/docker-agent/providers/cloudflare-workers-ai/ ---- - -_Use Cloudflare Workers AI models with Docker Agent._ - -## Overview - -[Cloudflare Workers AI](https://developers.cloudflare.com/workers-ai/) runs -open-weight models (Llama, Mistral, Qwen, Gemma, and more) on Cloudflare's -global edge network through an OpenAI-compatible endpoint. No separate provider -accounts are needed for the supported models. Docker Agent includes built-in -support for Workers AI as an alias provider. - -## Setup - -Workers AI is account-scoped, so its base URL is resolved from your account ID. -Two environment variables are required: - -```bash -export CLOUDFLARE_ACCOUNT_ID=your-account-id -export CLOUDFLARE_API_TOKEN=your-api-token -``` - -Create an API token with the `Workers AI` permission from the -[Cloudflare dashboard](https://dash.cloudflare.com/profile/api-tokens). Your -account ID is shown on the Workers AI page. - -## Usage - -Workers AI model IDs use the `@cf/...` form (for example -`@cf/meta/llama-3.1-8b-instruct`). - -### Inline Syntax - -```yaml -agents: - root: - model: cloudflare-workers-ai/@cf/meta/llama-3.1-8b-instruct - description: Assistant using Cloudflare Workers AI - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - cloudflare_model: - provider: cloudflare-workers-ai - model: "@cf/meta/llama-3.1-8b-instruct" - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: cloudflare_model - description: Assistant using Cloudflare Workers AI - instruction: You are a helpful assistant. -``` - -## Available Models - -Check the -[Workers AI models catalog](https://developers.cloudflare.com/workers-ai/models/) -for the current list, IDs, and pricing. - -| Model | Description | -| --- | --- | -| `@cf/meta/llama-3.1-8b-instruct` | Meta Llama 3.1 8B Instruct | -| `@cf/mistralai/mistral-small-3.1-24b-instruct` | Mistral Small 3.1 24B Instruct | -| `@cf/qwen/qwen2.5-coder-32b-instruct` | Qwen 2.5 Coder 32B Instruct | - -## How It Works - -Cloudflare Workers AI is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.cloudflare.com/client/v4/accounts/${CLOUDFLARE_ACCOUNT_ID}/ai/v1` -- **Token Variable:** `CLOUDFLARE_API_TOKEN` - -The base URL is templated: `${CLOUDFLARE_ACCOUNT_ID}` is substituted from the -environment when the provider is built, so `CLOUDFLARE_ACCOUNT_ID` must be set in -addition to `CLOUDFLARE_API_TOKEN`. Because Workers AI serves open-weight models -with strict chat templates, Docker Agent coalesces consecutive system messages -into a single leading one for this provider. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/custom/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/custom/index.md deleted file mode 100644 index 427585502d7b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/custom/index.md +++ /dev/null @@ -1,315 +0,0 @@ ---- -title: "Provider Definitions" -description: "Define reusable provider configurations with shared defaults for any provider type — OpenAI, Anthropic, Google, Bedrock, and more." -keywords: docker agent, ai agents, model providers, llm, provider definitions -weight: 280 -canonical: https://docs.docker.com/ai/docker-agent/providers/custom/ ---- - -_Define reusable provider configurations with shared defaults for any provider type — OpenAI, Anthropic, Google, Bedrock, and more._ - -## Overview - -The `providers` section in your agent YAML lets you define named provider configurations that models can reference. This is useful for: - -- **Grouping shared defaults** — Set temperature, max_tokens, thinking_budget once and share across models -- **Custom endpoints** — Connect to self-hosted models, API proxies, or gateways -- **Centralizing credentials** — Define token_key once for all models using a provider -- **Any provider type** — Works with OpenAI, Anthropic, Google, Bedrock, and any OpenAI-compatible API - -> [!NOTE] -> **Works with any provider** -> -> The `providers` section supports all provider types: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, and any built-in alias. When the `provider` field is not set, it defaults to `openai` for backward compatibility. - -## Configuration - -### OpenAI-compatible endpoint - -```yaml -providers: - my_gateway: - base_url: https://api.example.com/v1 - token_key: MY_API_KEY - -models: - my_model: - provider: my_gateway - model: gpt-4o - -agents: - root: - model: my_model - instruction: You are a helpful assistant. -``` - -### Anthropic with shared defaults - -```yaml -providers: - my_anthropic: - provider: anthropic - token_key: MY_ANTHROPIC_KEY - max_tokens: 16384 - thinking_budget: 8192 - -models: - claude_smart: - provider: my_anthropic - model: claude-sonnet-4-5 - # Inherits max_tokens: 16384, thinking_budget: 8192 - - claude_fast: - provider: my_anthropic - model: claude-haiku-4-5 - thinking_budget: 1024 # Overrides provider default - -agents: - root: - model: claude_smart - instruction: You are a helpful assistant. -``` - -### Google with shared temperature - -```yaml -providers: - my_google: - provider: google - temperature: 0.3 - -models: - gemini: - provider: my_google - model: gemini-2.5-flash - # Inherits temperature: 0.3 - -agents: - root: - model: gemini - instruction: You are a helpful assistant. -``` - -## Provider Properties - -| Property | Type | Description | Default | -| --------------------- | ---------- | ------------------------------------------------------------------------------------- | ------------------------ | -| `provider` | string | Underlying provider type: `openai`, `anthropic`, `google`, `amazon-bedrock`, `dmr`, etc. | `openai` | -| `api_type` | string | API schema: `openai_chatcompletions` or `openai_responses`. Only for OpenAI-compatible providers. When omitted, the API type is selected automatically based on the model name: newer models (gpt-4.1, o-series, gpt-5, Codex) default to `openai_responses`; all others default to `openai_chatcompletions`. | `auto (model-dependent)` | -| `base_url` | string | Base URL for the API endpoint. Required for OpenAI-compatible providers, optional for native providers. | — | -| `token_key` | string | Environment variable name containing the API token. | — | -| `unload_api` | string | Optional path (or absolute URL) to the provider's model-unload endpoint. Used by the [`unload`](../../configuration/hooks/index.md#available-built-ins) built-in hook to release model resources between agent switches. Relative paths resolve against `base_url`'s scheme + host; absolute URLs are used verbatim. Today only Docker Model Runner ships a provider that calls this endpoint; cloud providers don't implement the underlying interface and the hook silently skips them. | — | -| `temperature` | float | Default sampling temperature (0.0–2.0). | — | -| `max_tokens` | int | Default maximum response tokens. | — | -| `top_p` | float | Default nucleus sampling threshold (0.0–1.0). | — | -| `frequency_penalty` | float | Default frequency penalty (-2.0–2.0). | — | -| `presence_penalty` | float | Default presence penalty (-2.0–2.0). | — | -| `parallel_tool_calls` | boolean | Whether to enable parallel tool calls by default. | — | -| `track_usage` | boolean | Whether to track token usage by default. | — | -| `thinking_budget` | string/int | Default reasoning effort/budget. | — | -| `task_budget` | int/object | Default total token budget for an agentic task (forwarded to Anthropic; honored by Claude Opus 4.7 today). Integer shorthand or `{type: tokens, total: N}`. | — | -| `compaction_model` | string | Default model used for session compaction (summary generation) by agents whose model uses this provider. Named model or inline `provider/model` string. Agent-level and model-level `compaction_model` take precedence. | — | -| `provider_opts` | object | Provider-specific options passed through to the client. | — | - -## Default Inheritance - -Models referencing a provider inherit all its defaults. Model-level settings always take precedence: - -```yaml -providers: - my_anthropic: - provider: anthropic - token_key: MY_ANTHROPIC_KEY - max_tokens: 16384 - temperature: 0.7 - thinking_budget: high - -models: - # Inherits everything from provider - claude_default: - provider: my_anthropic - model: claude-sonnet-4-5 - - # Overrides temperature and thinking_budget, inherits the rest - claude_custom: - provider: my_anthropic - model: claude-sonnet-4-5 - temperature: 0.2 - thinking_budget: low -``` - -`compaction_model` works slightly differently: it is not merged into the model -but resolved per agent, with the agent-level `compaction_model` winning over -the model-level one, which wins over the provider-level default. - -## Shorthand Syntax - -Once a provider is defined, you can use the shorthand `provider_name/model` syntax: - -```yaml -agents: - root: - model: my_gateway/gpt-4o-mini # uses the provider's defaults - researcher: - model: my_anthropic/claude-sonnet-4-5 # uses anthropic provider defaults -``` - -## API Types - -Only applicable for OpenAI-compatible providers (when `provider` is `openai` or unset): - -- **`openai_chatcompletions`** — Standard OpenAI Chat Completions API. Works with most OpenAI-compatible endpoints. -- **`openai_responses`** — OpenAI Responses API. For newer models that require the Responses API format. - -> If `api_type` is not set, Docker Agent automatically selects the API type based on the model name. You only need to set `api_type` explicitly to override the detected default. - -## Examples - -### vLLM / Ollama - -```yaml -providers: - local_llm: - base_url: http://localhost:8000/v1 - -agents: - root: - model: local_llm/llama-3.1-8b -``` - -> [!NOTE] -> **Reasoning tokens from OpenAI-compatible providers** -> -> Models that stream reasoning under `delta.reasoning` (e.g. Qwen3 served via OVHcloud AI Endpoints, OpenRouter, or a self-hosted vLLM / SGLang deployment) are fully supported. Docker Agent reads both the `delta.reasoning_content` and `delta.reasoning` fields from the stream, so thinking blocks are captured and shown in the TUI regardless of which field the server uses. - -### API Router (Requesty, LiteLLM) - -```yaml -providers: - router: - base_url: https://router.requesty.ai/v1 - token_key: REQUESTY_API_KEY - -agents: - root: - model: router/anthropic/claude-sonnet-4-5 -``` - -### Azure OpenAI - -```yaml -models: - azure_model: - provider: azure - model: gpt-4o - base_url: https://your-llm.openai.azure.com - provider_opts: - api_version: 2024-12-01-preview -``` - -### Anthropic Team Setup - -```yaml -providers: - team_anthropic: - provider: anthropic - token_key: TEAM_ANTHROPIC_KEY - max_tokens: 32768 - thinking_budget: high - temperature: 0.5 - -models: - architect: - provider: team_anthropic - model: claude-sonnet-4-5 - - reviewer: - provider: team_anthropic - model: claude-haiku-4-5 - thinking_budget: low # faster reviews - -agents: - root: - model: architect - sub_agents: [code_reviewer] - code_reviewer: - model: reviewer -``` - -### Multi-Provider with Shared Defaults - -```yaml -providers: - fast_openai: - base_url: https://api.openai.com/v1 - token_key: OPENAI_API_KEY - temperature: 0.3 - max_tokens: 8192 - - smart_anthropic: - provider: anthropic - token_key: ANTHROPIC_API_KEY - max_tokens: 64000 - thinking_budget: high - -agents: - root: - model: smart_anthropic/claude-sonnet-4-5 - sub_agents: [helper] - helper: - model: fast_openai/gpt-4o-mini -``` - -## Global Providers (User Configuration) - -Providers defined in an agent file only apply to that file. To make a custom -provider available to every command (`docker agent run`, `new`, `models`, ...), -define it once in your user configuration (`~/.config/cagent/config.yaml`) -under the same `providers` key: - -```yaml -# ~/.config/cagent/config.yaml -providers: - myprovider: - base_url: https://llm.corp.example.com/v1 - api_type: openai_chatcompletions - token_key: MYPROVIDER_API_KEY -``` - -The easiest way to register one is the interactive wizard: - -```bash -docker agent setup -# pick "3. Custom OpenAI-compatible endpoint", then enter the base URL, -# API format, and the environment variable holding the API key -``` - -Once registered, the provider works everywhere: - -```bash -docker agent models --provider myprovider # list the endpoint's models -docker agent new --model myprovider/mymodel # build agents with it -docker agent run --model myprovider/mymodel # chat with it -``` - -Global providers are merged into every loaded agent configuration; when an -agent file defines a provider with the same name, the agent file wins. Note -that automatic model selection (`model: auto`) never picks a custom provider, -so reference its models explicitly with `--model /` or -`default_model`. - -## How It Works - -When you reference a provider: - -1. The provider's `provider` field determines which API client to use (defaults to `openai`) -2. The provider's `base_url` and `token_key` are applied to the model (if not already set on the model) -3. All model-level defaults (temperature, max_tokens, thinking_budget, etc.) are inherited (model settings take precedence) -4. For OpenAI-compatible providers, the `api_type` is stored in `provider_opts.api_type` -5. The model is used with the appropriate API client - -A provider with a `base_url` implies `bypass_models_gateway: true` for every -model that references it: user-chosen endpoints are never routed through a -configured models gateway, and such models authenticate with the provider's -own credentials (`token_key`). See -[Gateway Bypass](../../configuration/models/index.md#gateway-bypass). diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/deepseek/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/deepseek/index.md deleted file mode 100644 index e62710a4f413..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/deepseek/index.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: "DeepSeek" -description: "Use DeepSeek models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, deepseek -weight: 80 -canonical: https://docs.docker.com/ai/docker-agent/providers/deepseek/ ---- - -_Use DeepSeek models with Docker Agent._ - -## Overview - -[DeepSeek](https://www.deepseek.com/) serves its frontier chat and reasoning -models through an OpenAI-compatible API, with strong price/performance on coding -and reasoning tasks. Docker Agent includes built-in support for DeepSeek as an -alias provider. - -## Setup - -1. Create an API key from the [DeepSeek Platform](https://platform.deepseek.com/api_keys). -2. Set the environment variable: - - ```bash - export DEEPSEEK_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use DeepSeek: - -```yaml -agents: - root: - model: deepseek/deepseek-chat - description: Assistant using DeepSeek - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - deepseek_model: - provider: deepseek - model: deepseek-chat - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: deepseek_model - description: Assistant using DeepSeek - instruction: You are a helpful assistant. -``` - -## Available Models - -DeepSeek exposes a small, vendor-controlled model lineup. Check the -[DeepSeek models documentation](https://api-docs.deepseek.com/quick_start/pricing) -for current model IDs, context limits, and pricing. - -| Model | Description | -| --- | --- | -| `deepseek-chat` | DeepSeek-V3, general-purpose chat and tool calling | -| `deepseek-reasoner` | DeepSeek-R1, extended-reasoning model | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -DeepSeek is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.deepseek.com/v1` -- **Token Variable:** `DEEPSEEK_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: deepseek/deepseek-chat - description: Code assistant using DeepSeek-V3 - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/dmr/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/dmr/index.md deleted file mode 100644 index 65b0528bec80..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/dmr/index.md +++ /dev/null @@ -1,253 +0,0 @@ ---- -title: "Docker Model Runner" -description: "Run AI models locally with Docker — no API keys, no costs, full data privacy." -keywords: docker agent, ai agents, model providers, llm, docker model runner -weight: 90 -canonical: https://docs.docker.com/ai/docker-agent/providers/dmr/ ---- - -_Run AI models locally with Docker — no API keys, no costs, full data privacy._ - -## Overview - -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. - -> [!TIP] -> **No API key needed** -> -> DMR runs models locally — your data never leaves your machine. Great for development, sensitive data, or offline use. - -## Prerequisites - -- [Docker Desktop](https://www.docker.com/products/docker-desktop/) with the Model Runner feature enabled -- Verify with: `docker model status --json` - -## Configuration - -### Inline - -```yaml -agents: - root: - model: dmr/ai/qwen3 -``` - -### Named Model - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - max_tokens: 8192 -``` - -## Available Models - -Any model available through Docker Model Runner can be used. Common options: - -| Model | Description | -| ------------- | ----------------------------------------------------- | -| `ai/qwen3` | Qwen 3 — versatile, good for coding and general tasks | -| `ai/llama3.2` | Llama 3.2 — Meta's open-source model | - -## Runtime Flags - -Pass flags to the underlying inference runtime (e.g., llama.cpp) using `provider_opts.runtime_flags`: - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - max_tokens: 8192 - provider_opts: - runtime_flags: ["--threads", "8"] -``` - -Runtime flags also accept a single string: - -```yaml -provider_opts: - runtime_flags: "--threads 8" -``` - -Use only flags your Model Runner backend allows (see `docker model configure --help` and backend docs). **Do not** put sampling parameters (`temperature`, `top_p`, penalties) in `runtime_flags` — set them on the model (`temperature`, `top_p`, etc.); they are sent **per request** via the OpenAI-compatible chat API. - -## Context size - -`max_tokens` controls the **maximum output tokens** per chat completion request. To set the engine's **total context window**, use `provider_opts.context_size`: - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - max_tokens: 4096 # max output tokens (per-request) - provider_opts: - context_size: 32768 # total context window (sent via _configure) -``` - -If `context_size` is omitted, Model Runner uses its default. `max_tokens` is **not** used as the context window. - -Docker Agent's auto-compaction scales its summary and keep-tail token budgets proportionally to `context_size`. This ensures compaction works correctly even for small context windows — for example, an 8k-token local model will not have its session history wiped during compaction. - -## Thinking / reasoning budget - -When using the **llama.cpp** backend, `thinking_budget` is sent as structured `llamacpp.reasoning-budget` on `_configure` (maps to `--reasoning-budget`). String efforts use the same token mapping as other providers; `adaptive` maps to unlimited (`-1`). - -When using the **vLLM** backend, `thinking_budget` is sent as `thinking_token_budget` in each chat completion request. Effort levels map to token counts using the same scale as other providers; `adaptive` maps to unlimited (`-1`). - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - thinking_budget: medium # llama.cpp: reasoning-budget=8192; vLLM: thinking_token_budget=8192 -``` - -On **MLX** and **SGLang** backends, `thinking_budget` is silently ignored — those engines do not currently expose a per-request reasoning token budget knob. - -## vLLM-specific configuration - -When running a model on the **vLLM** backend, additional engine-level settings can be passed via `provider_opts` and are forwarded to model-runner's `_configure` endpoint: - -- `gpu_memory_utilization` — fraction of GPU memory (0.0–1.0) vLLM may use. Values outside this range are rejected. -- `hf_overrides` — map of Hugging Face config overrides applied when vLLM loads the model. - -```yaml -models: - vllm-local: - provider: dmr - model: ai/some-model-safetensors - provider_opts: - gpu_memory_utilization: 0.9 - hf_overrides: - max_model_len: 8192 - dtype: bfloat16 -``` - -`hf_overrides` keys (including nested ones) must match `^[a-zA-Z_][a-zA-Z0-9_]*$` — the same rule model-runner enforces server-side to block injection via flags. Invalid keys are rejected at client creation time so you fail fast instead of after a round-trip. - -These options are ignored on non-vLLM backends. - -## Keeping models resident in memory (`keep_alive`) - -By default model-runner unloads idle models after a few minutes. Override the idle timeout via `provider_opts.keep_alive`: - -```yaml -models: - sticky: - provider: dmr - model: ai/qwen3 - provider_opts: - keep_alive: "30m" # duration string - # keep_alive: "0" # unload immediately after each request - # keep_alive: "-1" # keep loaded forever -``` - -Accepted values: any Go duration string (`"30s"`, `"5m"`, `"1h"`, `"2h30m"`), `"0"` (immediate unload), or `"-1"` (never unload). Invalid values are rejected before the configure request is sent. - -## Unloading models on agent switch - -In multi-agent setups where two DMR models can't fit in GPU memory simultaneously, wire the [`unload`](../../configuration/hooks/index.md#available-built-ins) built-in hook into each agent's `on_agent_switch` chain. Every time the active agent transfers control, the runtime POSTs to the engine's `_unload` endpoint to free the previous model's resources before the next one is loaded: - -```yaml -agents: - coder: - model: qwen3-large - handoffs: [reviewer] - hooks: - on_agent_switch: - - type: builtin - command: unload - reviewer: - model: qwen3-coder - handoffs: [coder] - hooks: - on_agent_switch: - - type: builtin - command: unload -``` - -The unload URL is derived from `base_url` by replacing the trailing `/v1` segment (e.g. `http://127.0.0.1:12434/engines/llama.cpp/v1/` → `http://127.0.0.1:12434/engines/llama.cpp/_unload`). Override it explicitly via the provider-level `unload_api` field when running against a non-standard model-runner deployment: - -```yaml -providers: - my_dmr: - provider: dmr - base_url: http://model-runner.docker.internal/engines/v1 - unload_api: /engines/_unload # default; absolute URLs also work - -models: - big: - provider: my_dmr - model: ai/qwen3 -``` - -Unload errors are logged and swallowed — a stuck or unreachable engine never blocks an agent transfer (each call is bounded to 10 s). Pair this with [`keep_alive`](#keeping-models-resident-in-memory-keep_alive) only when you want the model to *also* survive idle periods within a single agent's run; the hook controls **between-agent** unloads independently. - -> [!WARNING] -> **Single-tenant assumption** -> -> The `_unload` endpoint is engine-level: it evicts the model from DMR's memory regardless of who is using it. If two concurrent sessions on the same runtime (e.g. an API server serving multiple users) hit the same agent, switching away in session A will yank the model out from under session B's in-flight request, which then has to wait for a reload. Wire `unload` only when the agents using these models are not run concurrently — typically a single TUI/CLI session. - -See [`examples/unload_on_switch.yaml`](https://github.com/docker/docker-agent/blob/main/examples/unload_on_switch.yaml) for the full example. - -## Operating mode (`mode`) - -Model-runner normally infers the backend mode from the request path. You can pin it explicitly via `provider_opts.mode`: - -```yaml -provider_opts: - mode: embedding # one of: completion, embedding, reranking, image-generation -``` - -Most agents don't need this — leave it unset unless you know you need it. - -## Raw runtime flags (`raw_runtime_flags`) - -`runtime_flags` (a list) is the preferred way to pass flags. If you have a pre-built command-line string you'd rather ship verbatim, use `raw_runtime_flags` instead: - -```yaml -provider_opts: - raw_runtime_flags: "--threads 8 --batch-size 512" -``` - -Model-runner parses the string with shell-style word splitting. `runtime_flags` and `raw_runtime_flags` are mutually exclusive — setting both is an error. - -## Speculative Decoding - -Use a smaller draft model to predict tokens ahead for faster inference: - -```yaml -models: - fast-local: - provider: dmr - model: ai/qwen3:14B - max_tokens: 8192 - provider_opts: - speculative_draft_model: ai/qwen3:0.6B-F16 - speculative_num_tokens: 16 - speculative_acceptance_rate: 0.8 -``` - -## Custom Endpoint - -If `base_url` is omitted, Docker Agent auto-discovers the DMR endpoint. To set manually: - -```yaml -models: - local: - provider: dmr - model: ai/qwen3 - base_url: http://127.0.0.1:12434/engines/llama.cpp/v1 -``` - -## Troubleshooting - -- **Plugin not found:** Ensure Docker Model Runner is enabled in Docker Desktop. Docker Agent will fall back to the default URL. -- **Endpoint empty:** Verify the Model Runner is running with `docker model status --json`. -- **Performance:** Use `runtime_flags` to tune GPU layers (`--ngl`) and thread count (`--threads`). diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/fireworks/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/fireworks/index.md deleted file mode 100644 index 9644653071f8..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/fireworks/index.md +++ /dev/null @@ -1,102 +0,0 @@ ---- -title: "Fireworks AI" -description: "Use Fireworks AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, fireworks ai -weight: 100 -canonical: https://docs.docker.com/ai/docker-agent/providers/fireworks/ ---- - -_Use Fireworks AI models with Docker Agent._ - -## Overview - -[Fireworks AI](https://fireworks.ai/) is a fast inference host for open-weight -models, serving Kimi K2, Llama, Qwen, DeepSeek, GLM and others through an -OpenAI-compatible API. Docker Agent includes built-in support for Fireworks AI -as an alias provider. - -## Setup - -1. Create an API key from the [Fireworks dashboard](https://fireworks.ai/account/api-keys). -2. Set the environment variable: - - ```bash - export FIREWORKS_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Fireworks AI: - -```yaml -agents: - root: - model: fireworks/accounts/fireworks/models/kimi-k2-instruct - description: Assistant using Fireworks AI - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - fireworks_model: - provider: fireworks - model: accounts/fireworks/models/kimi-k2-instruct - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: fireworks_model - description: Assistant using Fireworks AI - instruction: You are a helpful assistant. -``` - -## Available Models - -Fireworks serves a broad, changing catalog of open-weight models. Model IDs use -the `accounts/fireworks/models/` form. Check the -[Fireworks model library](https://fireworks.ai/models) for current IDs, context -limits, and pricing. - -| Model | Description | -| --- | --- | -| `accounts/fireworks/models/kimi-k2-instruct` | Kimi K2, large open MoE chat and tool-calling model | -| `accounts/fireworks/models/llama-v3p3-70b-instruct` | Llama 3.3 70B instruct | -| `accounts/fireworks/models/qwen3-235b-a22b` | Qwen 3 235B MoE | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -Fireworks AI is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.fireworks.ai/inference/v1` -- **Token Variable:** `FIREWORKS_API_KEY` - -Because Fireworks fronts open-weight models whose chat templates may reject more -than one leading system message, Docker Agent coalesces its per-source system -messages into a single one for this provider. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: fireworks/accounts/fireworks/models/kimi-k2-instruct - description: Code assistant using Kimi K2 on Fireworks AI - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/github-copilot/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/github-copilot/index.md deleted file mode 100644 index 3e4e7c3cd3e5..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/github-copilot/index.md +++ /dev/null @@ -1,161 +0,0 @@ ---- -title: "GitHub Copilot" -description: "Use GitHub Copilot's hosted models (GPT-4o, Claude, Gemini, and more) with Docker Agent through your GitHub subscription." -keywords: docker agent, ai agents, model providers, llm, github copilot -weight: 110 -canonical: https://docs.docker.com/ai/docker-agent/providers/github-copilot/ ---- - -_Use GitHub Copilot's hosted models with Docker Agent through your existing GitHub subscription._ - -## Overview - -GitHub Copilot exposes an OpenAI-compatible Chat Completions API at -`https://api.githubcopilot.com`. Docker Agent ships with built-in support for -it as the `github-copilot` provider, so any user with a paid GitHub Copilot -subscription can reuse their entitlement from Docker Agent. - -## Prerequisites - -- An active **GitHub Copilot** subscription (Individual, Business, or Enterprise). -- A **personal access token** with the `copilot` scope, exported as `GITHUB_TOKEN`. - -```bash -export GITHUB_TOKEN="ghp_..." -``` - -## Running Evals - -Eval cases (`docker agent eval`) run in isolated containers. Unlike dedicated -provider API keys, `GITHUB_TOKEN` and `GH_TOKEN` are **not** forwarded into -eval containers automatically, because a GitHub token grants far broader -access than a model API key. Pass the token explicitly: - -```bash -docker agent eval agent.yaml ./evals -e GITHUB_TOKEN -``` - -See [Evaluation](../../features/evaluation/index.md#provider-credentials) -for details, including behavior with `--env-from-file`. - -## Configuration - -### Inline - -```yaml -agents: - root: - model: github-copilot/gpt-4o - instruction: You are a helpful assistant. -``` - -### Named model - -```yaml -models: - copilot: - provider: github-copilot - model: gpt-4o - temperature: 0.7 - max_tokens: 4000 - -agents: - root: - model: copilot -``` - -## Available Models - -The exact set of models you can call depends on your Copilot plan. The most -commonly available ones today are: - -| Model | Best For | -| ------------------------ | ----------------------------------- | -| `gpt-4o` | Multimodal, balanced performance | -| `gpt-4o-mini` | Fast and cheap | -| `claude-sonnet-4` | Strong coding and analysis | -| `gemini-2.5-pro` | Google's flagship, large context | -| `o3-mini` | Reasoning-focused | - -Check the -[GitHub Copilot documentation](https://docs.github.com/en/copilot) -for the current model list. - -## `Copilot-Integration-Id` Header - -GitHub's Copilot API rejects requests that don't carry a -`Copilot-Integration-Id` header with a `Bad Request` error. Docker Agent -automatically sends `copilot-developer-cli` for the `github-copilot` -provider, so PAT-based usage works out of the box. - -We specifically chose `copilot-developer-cli` (instead of, say, -`vscode-chat`) because it is the integration id accepted by the Copilot -API for **both** OAuth tokens and Personal Access Tokens. Most -Docker Agent users authenticate with a PAT exported as `GITHUB_TOKEN`, -and `vscode-chat` is rejected for those tokens. - -If you need to send a different integration id — for example if your -organization allows-lists a specific value — you can override it via -`provider_opts.http_headers`: - -```yaml -models: - copilot: - provider: github-copilot - model: gpt-4o - provider_opts: - http_headers: - Copilot-Integration-Id: my-custom-integration -``` - -Header names are matched case-insensitively, so `copilot-integration-id` -works too. - -## Chat Completions vs. Responses API - -GitHub Copilot proxies OpenAI models behind two endpoints: the legacy -`/chat/completions` and the newer `/responses`. Newer models (the `gpt-5` -family, Codex variants, etc.) are only served via `/responses` and reject -`/chat/completions` with a `400 Bad Request`. Docker Agent auto-selects the -right endpoint per model, so no configuration is needed in the common case. - -If you ever need to force one or the other, set `api_type` explicitly: - -```yaml -models: - copilot: - provider: github-copilot - model: gpt-5 - provider_opts: - api_type: openai_responses # or openai_chatcompletions -``` - -## Custom HTTP Headers - -`provider_opts.http_headers` is a generic escape hatch that works for any -OpenAI-compatible provider, not just GitHub Copilot. Every key/value pair -is added to every outgoing request: - -```yaml -models: - my_model: - provider: openai - model: gpt-4o - provider_opts: - http_headers: - X-Request-Source: docker-agent - X-Tenant-Id: my-team -``` - -## How It Works - -GitHub Copilot is implemented as a built-in alias in Docker Agent: - -- **API type:** OpenAI-compatible (Chat Completions) -- **Base URL:** `https://api.githubcopilot.com` -- **Token variable:** `GITHUB_TOKEN` -- **Default headers:** `Copilot-Integration-Id: copilot-developer-cli` - -This means the same client as OpenAI is used, so every OpenAI feature -supported by Docker Agent (tool calling, structured output, multimodal -inputs, etc.) is available when the underlying model supports it. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/google/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/google/index.md deleted file mode 100644 index efbb27817169..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/google/index.md +++ /dev/null @@ -1,174 +0,0 @@ ---- -title: "Google Gemini" -description: "Use Gemini 2.5 Flash, Gemini 3 Pro, and other Google models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, google gemini -weight: 120 -canonical: https://docs.docker.com/ai/docker-agent/providers/google/ ---- - -_Use Gemini 2.5 Flash, Gemini 3 Pro, and other Google models with Docker Agent._ - -## Setup - -Docker Agent reads the first credential it finds from these environment variables (see `pkg/model/provider/gemini/client.go`): - -| Variable | Purpose | -| --------------------------- | ----------------------------------------------------------------------------------- | -| `GOOGLE_API_KEY` | Primary Gemini API key. | -| `GEMINI_API_KEY` | Alternative name for the Gemini API key (also used by the official Google SDK). | -| `GOOGLE_GENAI_USE_VERTEXAI` | When set (any value), routes through Vertex AI instead of the Gemini Developer API. | -| `GOOGLE_CLOUD_PROJECT` | GCP project used when `GOOGLE_GENAI_USE_VERTEXAI` is set or for Vertex AI Model Garden. | -| `GOOGLE_CLOUD_LOCATION` | GCP region for Vertex AI (defaults to the SDK default). | - -```bash -# Gemini Developer API -export GOOGLE_API_KEY="AI..." # or GEMINI_API_KEY - -# Vertex AI (no API key; uses Application Default Credentials) -gcloud auth application-default login -export GOOGLE_GENAI_USE_VERTEXAI=1 -export GOOGLE_CLOUD_PROJECT="my-gcp-project" -export GOOGLE_CLOUD_LOCATION="us-central1" -``` - -## Configuration - -### Inline - -```yaml -agents: - root: - model: google/gemini-3.5-flash -``` - -### Named Model - -```yaml -models: - gemini: - provider: google - model: gemini-3.5-flash - temperature: 0.5 -``` - -## Available Models - -| Model | Best For | -| ------------------ | ------------------------------- | -| `gemini-3-pro` | Most capable Gemini model | -| `gemini-3-flash` | Fast, efficient, good balance | -| `gemini-2.5-flash` | Fast inference, cost-effective | -| `gemini-2.5-pro` | Strong reasoning, large context | - -## Thinking Budget - -Gemini supports two approaches depending on the model version: - -> [!WARNING] -> **Different thinking formats** -> -> Gemini 2.5 uses **token-based** budgets (integers). Gemini 3 uses **level-based** budgets (strings like `low`, `high`). Make sure you use the right format for your model version. - -### Gemini 2.5 (Token-based) - -```yaml -models: - gemini-no-thinking: - provider: google - model: gemini-2.5-flash - thinking_budget: 0 # disable thinking - - gemini-dynamic: - provider: google - model: gemini-2.5-flash - thinking_budget: -1 # dynamic (model decides) — default - - gemini-fixed: - provider: google - model: gemini-2.5-flash - thinking_budget: 8192 # fixed token budget -``` - -### Gemini 3 (Level-based) - -```yaml -models: - gemini-3-pro: - provider: google - model: gemini-3-pro - thinking_budget: high # default for Pro: low | high - - gemini-3-flash: - provider: google - model: gemini-3-flash - thinking_budget: medium # default for Flash: minimal | low | medium | high -``` - -## Built-in Tools (Grounding) - -Gemini models support built-in tools that let the model access Google Search and Google Maps -directly during generation. Enable them via `provider_opts`: - -```yaml -models: - gemini-grounded: - provider: google - model: gemini-2.5-flash - provider_opts: - google_search: true - google_maps: true - code_execution: true -``` - -| Option | Description | -| ---------------- | ---------------------------------------------------- | -| `google_search` | Enables Google Search grounding for up-to-date info | -| `google_maps` | Enables Google Maps grounding for location queries | -| `code_execution` | Enables server-side code execution for computations | - -## Vertex AI Model Garden - -You can use non-Gemini models (e.g. Claude, Llama) hosted on Google Cloud's -[Vertex AI Model Garden](https://cloud.google.com/vertex-ai/generative-ai/docs/partner-models/use-partner-models) -through the `google` provider. When a `publisher` is specified in `provider_opts`, -requests are routed through the appropriate Vertex AI endpoint instead of the -Gemini SDK: - -- **Anthropic Claude** (`publisher: anthropic`) uses the Anthropic-native - `:rawPredict` / `:streamRawPredict` endpoints. Claude models on Vertex AI do - not support the OpenAI `/chat/completions` path. -- **Other publishers** (e.g. `meta`, `mistral`) use Vertex AI's - OpenAI-compatible `/chat/completions` endpoint. - -### Authentication - -Vertex AI uses Google Cloud Application Default Credentials (ADC). Make sure you -are authenticated: - -```bash -gcloud auth application-default login -``` - -### Configuration - -```yaml -models: - claude-on-vertex: - provider: google - model: claude-sonnet-4-20250514 - provider_opts: - project: my-gcp-project # GCP project ID (or set GOOGLE_CLOUD_PROJECT) - location: us-east5 # GCP region (or set GOOGLE_CLOUD_LOCATION) - publisher: anthropic # Model publisher (anthropic, meta, etc.) -``` - -| Option | Description | -| ----------- | ------------------------------------------------------------------------------------ | -| `project` | GCP project ID. Falls back to `GOOGLE_CLOUD_PROJECT` env var | -| `location` | GCP region (e.g. `us-east5`, `us-central1`). Falls back to `GOOGLE_CLOUD_LOCATION` | -| `publisher` | Model publisher (e.g. `anthropic`, `meta`, `mistral`). Must not be `google` | - -> [!NOTE] -> **Gemini models on Vertex AI** -> -> Setting `publisher: google` (or omitting `publisher`) uses the native Gemini SDK path. The Model Garden endpoint is only used for non-Google publishers. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/groq/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/groq/index.md deleted file mode 100644 index 4c7d3945581c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/groq/index.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "Groq" -description: "Use Groq fast-inference models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, groq -weight: 130 -canonical: https://docs.docker.com/ai/docker-agent/providers/groq/ ---- - -_Use Groq models with Docker Agent._ - -## Overview - -[Groq](https://groq.com/) serves open-weight models on its LPU inference engine -through an OpenAI-compatible API, with a focus on very low latency. Docker Agent -includes built-in support for Groq as an alias provider. - -## Setup - -1. Create an API key from the [Groq Console](https://console.groq.com/keys). -2. Set the environment variable: - - ```bash - export GROQ_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Groq: - -```yaml -agents: - root: - model: groq/llama-3.3-70b-versatile - description: Assistant using Groq - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - groq_model: - provider: groq - model: llama-3.3-70b-versatile - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: groq_model - description: Assistant using Groq - instruction: You are a helpful assistant. -``` - -## Available Models - -Groq hosts a rotating catalogue of open-weight models. Check the -[Groq models documentation](https://console.groq.com/docs/models) for current -model IDs, context limits, and rate limits. - -| Model | Description | -| --- | --- | -| `llama-3.3-70b-versatile` | Llama 3.3 70B, reliable general-purpose chat and tool calling | -| `llama-3.1-8b-instant` | Llama 3.1 8B, fastest and cheapest | -| `openai/gpt-oss-120b` | GPT-OSS 120B, strong reasoning and tool calling | -| `openai/gpt-oss-20b` | GPT-OSS 20B, compact reasoning model | -| `qwen/qwen3-32b` | Qwen3 32B, reasoning and tool calling | -| `meta-llama/llama-4-scout-17b-16e-instruct` | Llama 4 Scout MoE | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -Groq is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.groq.com/openai/v1` -- **Token Variable:** `GROQ_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: groq/llama-3.3-70b-versatile - description: Code assistant using Llama 3.3 - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/huggingface/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/huggingface/index.md deleted file mode 100644 index 8b5860100a71..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/huggingface/index.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: "Hugging Face" -description: "Use Hugging Face Inference Providers with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, hugging face -weight: 140 -canonical: https://docs.docker.com/ai/docker-agent/providers/huggingface/ ---- - -_Use Hugging Face Inference Providers with Docker Agent._ - -## Overview - -[Hugging Face Inference Providers](https://huggingface.co/docs/inference-providers/index) -routes requests to open models (Llama, Qwen, DeepSeek, Kimi, GLM and others) -across many backends through a single OpenAI-compatible endpoint. Docker Agent -includes built-in support for Hugging Face as an alias provider. - -## Setup - -1. Create a token from the [Hugging Face token settings](https://huggingface.co/settings/tokens). -2. Set the environment variable: - - ```bash - export HF_TOKEN=your-token - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Hugging Face: - -```yaml -agents: - root: - model: huggingface/meta-llama/Llama-3.3-70B-Instruct - description: Assistant using Hugging Face Inference Providers - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - huggingface_model: - provider: huggingface - model: meta-llama/Llama-3.3-70B-Instruct - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: huggingface_model - description: Assistant using Hugging Face Inference Providers - instruction: You are a helpful assistant. -``` - -## Available Models - -Hugging Face routes to a broad, changing catalog of open-weight models. Check the -[Hugging Face models page](https://huggingface.co/models?inference_provider=all) -for current model IDs, context limits, and pricing. - -| Model | Description | -| --- | --- | -| `meta-llama/Llama-3.3-70B-Instruct` | Llama 3.3 70B, general-purpose chat and tool calling | -| `Qwen/Qwen3-235B-A22B` | Qwen3 235B mixture-of-experts instruct model | -| `deepseek-ai/DeepSeek-V3.2` | DeepSeek, strong coding and reasoning | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -Hugging Face is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://router.huggingface.co/v1` -- **Token Variable:** `HF_TOKEN` - -Because Hugging Face fronts open-weight models whose chat templates may reject -more than one leading system message, Docker Agent coalesces its per-source -system messages into a single one for this provider. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: huggingface/Qwen/Qwen3-Coder-480B-A35B-Instruct - description: Code assistant using Qwen3 Coder on Hugging Face - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/local/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/local/index.md deleted file mode 100644 index c4122a108cdd..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/local/index.md +++ /dev/null @@ -1,223 +0,0 @@ ---- -title: "Local Models (Ollama, vLLM, LocalAI)" -description: "Run Docker Agent with locally hosted models for privacy, offline use, or cost savings." -keywords: docker agent, ai agents, model providers, llm, local models, ollama, vllm, localai, offline models -linkTitle: "Local Models" -weight: 150 -canonical: https://docs.docker.com/ai/docker-agent/providers/local/ -aliases: - - /ai/docker-agent/local-models/ - - /ai/docker-agent/providers/ollama/ ---- - -_Run Docker Agent with locally hosted models for privacy, offline use, or cost savings._ - -## Overview - -Docker Agent can connect to any OpenAI-compatible local model server. This guide covers the most popular options: - -- **Ollama** — Easy-to-use local model runner -- **vLLM** — High-performance inference server -- **LocalAI** — OpenAI-compatible API for various backends - -> [!TIP] -> **Docker Model Runner** -> -> For the easiest local model experience, consider [Docker Model Runner](../dmr/index.md) which is built into Docker Desktop and requires no additional setup. - -## Ollama - -Ollama is a popular tool for running LLMs locally. Docker Agent includes a built-in `ollama` alias for easy configuration. - -### Setup - -1. Install Ollama from [ollama.ai](https://ollama.ai/) -2. Pull a model: - - ```bash - ollama pull llama3.2 - ollama pull qwen2.5-coder - ``` - -3. Start the Ollama server (usually runs automatically): - - ```bash - ollama serve - ``` - -### Configuration - -Use the built-in `ollama` alias: - -```yaml -agents: - root: - model: ollama/llama3.2 - description: Local assistant - instruction: You are a helpful assistant. -``` - -The `ollama` alias automatically uses: - -- **Base URL:** `http://localhost:11434/v1` -- **API Type:** OpenAI-compatible -- **No API key required** - -### Custom Port or Host - -If Ollama runs on a different host or port: - -```yaml -models: - my_ollama: - provider: ollama - model: llama3.2 - base_url: http://192.168.1.100:11434/v1 - -agents: - root: - model: my_ollama - description: Remote Ollama assistant - instruction: You are a helpful assistant. -``` - -### Popular Ollama Models - -| Model | Size | Best For | -| ---------------- | ---- | --------------------- | -| `llama3.2` | 3B | General purpose, fast | -| `llama3.1` | 8B | Better reasoning | -| `qwen2.5-coder` | 7B | Code generation | -| `mistral` | 7B | General purpose | -| `codellama` | 7B | Code tasks | -| `deepseek-coder` | 6.7B | Code generation | - -## vLLM - -vLLM is a high-performance inference server optimized for throughput. - -### Setup - -```bash -# Install vLLM -pip install vllm - -# Start the server -python -m vllm.entrypoints.openai.api_server \ - --model meta-llama/Llama-3.2-3B-Instruct \ - --port 8000 -``` - -### Configuration - -```yaml -providers: - vllm: - api_type: openai_chatcompletions - base_url: http://localhost:8000/v1 - -agents: - root: - model: vllm/meta-llama/Llama-3.2-3B-Instruct - description: vLLM-powered assistant - instruction: You are a helpful assistant. -``` - -## LocalAI - -LocalAI provides an OpenAI-compatible API that works with various backends. - -### Setup - -```bash -# Run with Docker -docker run -p 8080:8080 --name local-ai \ - -v ./models:/models \ - localai/localai:latest-cpu -``` - -### Configuration - -```yaml -providers: - localai: - api_type: openai_chatcompletions - base_url: http://localhost:8080/v1 - -agents: - root: - model: localai/gpt4all-j - description: LocalAI assistant - instruction: You are a helpful assistant. -``` - -## Generic Custom Provider - -For any OpenAI-compatible server: - -```yaml -providers: - my_server: - api_type: openai_chatcompletions - base_url: http://localhost:8000/v1 - # token_key: MY_API_KEY # if auth required - -agents: - root: - model: my_server/model-name - description: Custom server assistant - instruction: You are a helpful assistant. -``` - -## Performance Tips - -> [!NOTE] -> **Local Model Considerations** -> -> - **Memory:** Larger models need more RAM/VRAM. A 7B model typically needs 8-16GB RAM. -> - **GPU:** GPU acceleration dramatically improves speed. Check your server's GPU support. -> - **Context length:** Local models often have smaller context windows than cloud models. -> - **Tool calling:** Not all local models support function/tool calling. Test your model's capabilities. - -## Example: Offline Development Agent - -```yaml -agents: - developer: - model: ollama/qwen2.5-coder - description: Offline code assistant - instruction: | - You are a software developer working offline. - Focus on code quality and clear explanations. - max_iterations: 20 - toolsets: - - type: filesystem - - type: shell - - type: think - - type: todo -``` - -## Troubleshooting - -### Connection Refused - -Ensure your model server is running and accessible: - -```bash -curl http://localhost:11434/v1/models # Ollama -curl http://localhost:8000/v1/models # vLLM -``` - -### Model Not Found - -Verify the model is downloaded/available: - -```bash -ollama list # List available Ollama models -``` - -### Slow Responses - -- Check if GPU acceleration is enabled -- Try a smaller model -- Reduce `max_tokens` in your config diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/minimax/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/minimax/index.md deleted file mode 100644 index e6eeac606e38..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/minimax/index.md +++ /dev/null @@ -1,92 +0,0 @@ ---- -title: "MiniMax" -description: "Use MiniMax AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, minimax -weight: 160 -canonical: https://docs.docker.com/ai/docker-agent/providers/minimax/ ---- - -_Use MiniMax AI models with Docker Agent._ - -## Overview - -MiniMax provides AI models through an OpenAI-compatible API. Docker Agent includes built-in support for MiniMax as an alias provider. - -## Setup - -1. Get an API key from [MiniMax](https://www.minimaxi.com/) -2. Set the environment variable: - - ```bash - export MINIMAX_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use MiniMax: - -```yaml -agents: - root: - model: minimax/MiniMax-M2.5 - description: Assistant using MiniMax - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - minimax_model: - provider: minimax - model: MiniMax-M2.5 - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: minimax_model - description: Assistant using MiniMax - instruction: You are a helpful assistant. -``` - -## Available Models - -Check the [MiniMax documentation](https://www.minimaxi.com/document/introduction) for the current model catalog. - -| Model | Description | -| ------------------------ | ----------------------------------------------- | -| `MiniMax-M2.5` | Peak performance, 204K context | -| `MiniMax-M2.5-highspeed` | Same as M2.5 but faster (~100 tps) | -| `MiniMax-M2.1` | Multi-language programming capabilities | -| `MiniMax-M2.1-highspeed` | Faster variant of M2.1 (~100 tps) | -| `MiniMax-M2` | Agentic capabilities, advanced reasoning | - -## How It Works - -MiniMax is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai`) -- **Base URL:** `https://api.minimax.io/v1` -- **Token Variable:** `MINIMAX_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: minimax/MiniMax-M2.5 - description: Code assistant using MiniMax - instruction: | - You are an expert programmer using MiniMax M2.5. - Write clean, well-documented code. - Follow best practices for the language being used. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/mistral/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/mistral/index.md deleted file mode 100644 index 7e40916d53c6..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/mistral/index.md +++ /dev/null @@ -1,106 +0,0 @@ ---- -title: "Mistral" -description: "Use Mistral AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, mistral -weight: 170 -canonical: https://docs.docker.com/ai/docker-agent/providers/mistral/ ---- - -_Use Mistral AI models with Docker Agent._ - -## Overview - -Mistral AI provides powerful language models through an OpenAI-compatible API. Docker Agent includes built-in support for Mistral as an alias provider. - -## Setup - -1. Get an API key from [Mistral Console](https://console.mistral.ai/) -2. Set the environment variable: - - ```bash - export MISTRAL_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Mistral: - -```yaml -agents: - root: - model: mistral/mistral-large-latest - description: Assistant using Mistral - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - mistral: - provider: mistral - model: mistral-large-latest - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: mistral - description: Assistant using Mistral - instruction: You are a helpful assistant. -``` - -## Available Models - -| Model | Description | Context | -| ----------------------- | --------------------------------- | ------- | -| `mistral-large-latest` | Most capable Mistral model | 128K | -| `mistral-medium-latest` | Balanced performance and cost | 128K | -| `mistral-small-latest` | Fast and cost-effective (default) | 128K | -| `codestral-latest` | Optimized for code generation | 32K | -| `open-mistral-nemo` | Open-weight model | 128K | -| `ministral-8b-latest` | Compact 8B parameter model | 128K | -| `ministral-3b-latest` | Smallest Mistral model | 128K | - -Check the [Mistral Models documentation](https://docs.mistral.ai/getting-started/models/) for the latest available models. - -## Auto-Detection - -When you run `docker agent run` without specifying a config and no project-level `docker-agent.yaml`, `docker-agent.yml`, or `docker-agent.hcl` exists, Docker Agent automatically detects available providers. If `MISTRAL_API_KEY` is set and higher-priority providers (OpenAI, Anthropic, Google) are not available, Mistral will be used with `mistral-small-latest` as the default model. - -## Extended Thinking - -Docker Agent's `thinking_budget` field is **not applied** to Mistral models: the underlying OpenAI-compatible client only sends `reasoning_effort` for OpenAI reasoning model names (o-series, gpt-5). Setting `thinking_budget` on a Mistral model passes config validation but has no effect on the request. - -Mistral reasoning models (e.g. `magistral`) reason on their own without configuration. For non-reasoning models, use the [think tool](../../tools/think/index.md) instead. - -## How It Works - -Mistral is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.mistral.ai/v1` -- **Token Variable:** `MISTRAL_API_KEY` - -This means Mistral uses the same client as OpenAI, making it fully compatible with all OpenAI features supported by Docker Agent. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: mistral/codestral-latest - description: Expert code assistant - instruction: | - You are an expert programmer using Codestral. - Write clean, efficient, well-documented code. - Explain your reasoning when helpful. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/moonshot/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/moonshot/index.md deleted file mode 100644 index f370592b492d..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/moonshot/index.md +++ /dev/null @@ -1,97 +0,0 @@ ---- -title: "Moonshot AI" -description: "Use Moonshot AI (Kimi) models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, moonshot ai -weight: 180 -canonical: https://docs.docker.com/ai/docker-agent/providers/moonshot/ ---- - -_Use Moonshot AI (Kimi) models with Docker Agent._ - -## Overview - -[Moonshot AI](https://www.moonshot.ai/) serves its Kimi model family through an -OpenAI-compatible API. The Kimi K2 models have strong momentum for coding and -agentic tasks. Docker Agent includes built-in support for Moonshot AI as an -alias provider. - -## Setup - -1. Create an API key from the [Moonshot AI console](https://platform.moonshot.ai/console/api-keys). -2. Set the environment variable: - - ```bash - export MOONSHOT_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Moonshot AI: - -```yaml -agents: - root: - model: moonshot/kimi-k2-0905-preview - description: Assistant using Moonshot AI - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - moonshot_model: - provider: moonshot - model: kimi-k2-0905-preview - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: moonshot_model - description: Assistant using Moonshot AI - instruction: You are a helpful assistant. -``` - -## Available Models - -Moonshot AI exposes a vendor-controlled Kimi model lineup. Check the -[Moonshot API documentation](https://platform.moonshot.ai/docs/api) for current -model IDs, context limits, and pricing. - -| Model | Description | -| --- | --- | -| `kimi-k2-0905-preview` | Kimi K2, general-purpose chat, coding, and tool calling | -| `kimi-k2-turbo-preview` | Kimi K2 optimized for higher throughput | -| `kimi-k2-thinking` | Kimi K2 extended-reasoning model | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -Moonshot AI is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.moonshot.ai/v1` -- **Token Variable:** `MOONSHOT_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: moonshot/kimi-k2-0905-preview - description: Code assistant using Kimi K2 - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/nebius/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/nebius/index.md deleted file mode 100644 index deadbaaea4b3..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/nebius/index.md +++ /dev/null @@ -1,90 +0,0 @@ ---- -title: "Nebius" -description: "Use Nebius AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, nebius -weight: 190 -canonical: https://docs.docker.com/ai/docker-agent/providers/nebius/ ---- - -_Use Nebius AI models with Docker Agent._ - -## Overview - -Nebius provides AI models through an OpenAI-compatible API. Docker Agent includes built-in support for Nebius as an alias provider. - -## Setup - -1. Get an API key from [Nebius AI](https://nebius.ai/) -2. Set the environment variable: - - ```bash - export NEBIUS_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Nebius: - -```yaml -agents: - root: - model: nebius/deepseek-ai/DeepSeek-V3 - description: Assistant using Nebius - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - nebius_model: - provider: nebius - model: deepseek-ai/DeepSeek-V3 - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: nebius_model - description: Assistant using Nebius - instruction: You are a helpful assistant. -``` - -## Available Models - -Nebius hosts various open models. Check the [Nebius documentation](https://nebius.ai/docs) for the current model catalog. - -| Model | Description | -| ----------------------------------- | ------------------------------- | -| `deepseek-ai/DeepSeek-V3` | DeepSeek V3 model | -| `Qwen/Qwen2.5-72B-Instruct` | Qwen 2.5 72B instruction-tuned | -| `meta-llama/Llama-3.3-70B-Instruct` | Llama 3.3 70B instruction-tuned | - -## How It Works - -Nebius is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.studio.nebius.com/v1` -- **Token Variable:** `NEBIUS_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: nebius/deepseek-ai/DeepSeek-V3 - description: Code assistant using DeepSeek - instruction: | - You are an expert programmer using DeepSeek V3. - Write clean, well-documented code. - Follow best practices for the language being used. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/nvidia/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/nvidia/index.md deleted file mode 100644 index 330dad99f0bd..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/nvidia/index.md +++ /dev/null @@ -1,115 +0,0 @@ ---- -title: "NVIDIA NIM" -description: "Use NVIDIA NIM models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, nvidia, nim, nemotron -weight: 290 -canonical: https://docs.docker.com/ai/docker-agent/providers/nvidia/ ---- - -_Use NVIDIA NIM models with Docker Agent._ - -## Overview - -NVIDIA provides access to Nemotron and many other open-weight models through -[build.nvidia.com](https://build.nvidia.com/) (with a free tier) via an -OpenAI-compatible API. Docker Agent includes built-in support for NVIDIA as an -alias provider. The same alias also works against a self-hosted -[NVIDIA NIM](https://docs.nvidia.com/nim/) deployment by overriding `base_url`. - -## Setup - -1. Get an API key from [build.nvidia.com](https://build.nvidia.com/) -2. Set the environment variable: - - ```bash - export NVIDIA_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use NVIDIA NIM: - -```yaml -agents: - root: - model: nvidia/nvidia/nemotron-3-super-120b-a12b - description: Assistant using NVIDIA NIM - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - nemotron: - provider: nvidia - model: nvidia/nemotron-3-super-120b-a12b - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: nemotron - description: Assistant using NVIDIA NIM - instruction: You are a helpful assistant. -``` - -## Available Models - -NVIDIA NIM hosts Nemotron alongside many other open models (Llama, Qwen, -DeepSeek, Mistral, ...). Check the [NVIDIA API catalog](https://build.nvidia.com/) -for the current model list. - -| Model | Description | -| -------------------------------------------- | ---------------------------------- | -| `nvidia/nemotron-3-super-120b-a12b` | Nemotron 3 Super, reasoning + tool calling | -| `nvidia/nemotron-3-nano-30b-a3b` | Nemotron 3 Nano, smaller/faster | -| `meta/llama-3.3-70b-instruct` | Llama 3.3 70B instruction-tuned | -| `qwen/qwen3-coder-480b-a35b-instruct` | Qwen3 Coder, code-focused | - -## On-Prem / Self-Hosted NIM - -For self-hosted NIM deployments, point `base_url` at your own endpoint instead -of the hosted `integrate.api.nvidia.com` API: - -```yaml -models: - local_nim: - provider: nvidia - model: meta/llama-3.3-70b-instruct - base_url: http://localhost:8000/v1 -``` - -## How It Works - -NVIDIA is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://integrate.api.nvidia.com/v1` -- **Token Variable:** `NVIDIA_API_KEY` - -Because NIM fronts open-weight models whose chat templates often only accept -a single system message, Docker Agent coalesces the agent instruction and any -toolset instructions into one leading system message before sending the -request. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: nvidia/nvidia/nemotron-3-super-120b-a12b - description: Code assistant using Nemotron - instruction: | - You are an expert programmer using NVIDIA Nemotron. - Write clean, well-documented code. - Follow best practices for the language being used. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/openai/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/openai/index.md deleted file mode 100644 index abd11c54fbe8..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/openai/index.md +++ /dev/null @@ -1,138 +0,0 @@ ---- -title: "OpenAI" -description: "Use GPT-5.6, GPT-4o, GPT-5, GPT-5-mini, and other OpenAI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, openai -weight: 200 -canonical: https://docs.docker.com/ai/docker-agent/providers/openai/ ---- - -_Use GPT-5.6, GPT-4o, GPT-5, GPT-5-mini, and other OpenAI models with Docker Agent._ - -## Setup - -```bash -# Set your API key -export OPENAI_API_KEY="sk-..." -``` - -> [!TIP] -> No API key? A ChatGPT Plus/Pro/Business subscription can be used instead -> through the [`chatgpt` provider](../chatgpt/index.md): sign in once with -> `docker agent setup` (pick chatgpt). - -## Configuration - -### Inline - -```yaml -agents: - root: - model: openai/gpt-5.6 -``` - -### Named Model - -```yaml -models: - gpt: - provider: openai - model: gpt-5.6 - max_tokens: 4000 -``` - -## Available Models - -| Model | Best For | -| ---------------- | ----------------------------------------------------- | -| `gpt-5.6` | Alias for `gpt-5.6-sol`; tracks the flagship model | -| `gpt-5.6-sol` | Frontier model, most capable, complex reasoning | -| `gpt-5.6-terra` | Everyday workhorse; successor to the `-mini` tier | -| `gpt-5.6-luna` | High-volume, cost-efficient; successor to `-nano` tier | -| `gpt-5` | Previous-generation flagship | -| `gpt-5-mini` | Previous-generation fast, cost-effective model | -| `gpt-4o` | Multimodal, balanced performance | -| `gpt-4o-mini` | Cheapest, fast for simple tasks | - -Starting with GPT-5.6, OpenAI renamed the `-mini`/`-nano` size tiers to `-terra`/`-luna` (with `-sol` denoting the frontier tier previously left unsuffixed). - -Find more model names at [modelnames.ai](https://modelnames.ai/) or in the [official OpenAI docs](https://platform.openai.com/docs/models). - -## Thinking Budget - -OpenAI reasoning models (o-series, gpt-5, gpt-5-mini, gpt-5.6 family) support extended thinking through the `reasoning_effort` API parameter. Set `thinking_budget` to control the effort level: - -```yaml -models: - gpt-thinker: - provider: openai - model: gpt-5.6 - thinking_budget: high # none | minimal | low | medium | high | xhigh | max -``` - -**Effort levels:** - -| Level | Description | -| --------- | -------------------------------------------------------- | -| `none` | No reasoning. On `gpt-5.6`+ this is a real API value that is sent as-is; on older models it just disables the local `thinking_budget` (the API's own default still applies). | -| `minimal` | Fastest; lightest reasoning pass. Not accepted on `gpt-5.6`+ (dropped from the API). | -| `low` | Quick reasoning for straightforward tasks. | -| `medium` | Balanced default. | -| `high` | More thorough; recommended for complex tasks. | -| `xhigh` | Near-maximum effort; slower but most accurate. Requires `gpt-5.2`+. | -| `max` | Maximum effort. Requires `gpt-5.6`+ (Sol/Terra/Luna). | - -Token counts, `adaptive`, and `adaptive/` are rejected with a configuration error at request time. Older models (o1, o3-mini) only accept `low`/`medium`/`high`; `xhigh` requires `gpt-5.2`+; `none` and `max` require `gpt-5.6`+; `minimal` is not accepted on `gpt-5.6`+. - -> [!WARNING] -> **Hidden reasoning tokens** -> -> OpenAI reasoning models always produce hidden reasoning tokens that count against `max_tokens` — even with `thinking_budget: none` on older models. Docker Agent automatically raises the output-token floor for its internal low-effort calls so reasoning cannot starve visible text output. - -See the [Thinking / Reasoning guide](../../guides/thinking/index.md) for a cross-provider overview. - -> [!TIP] -> **Custom endpoints** -> -> Use `base_url` for proxies and OpenAI-compatible services. See [Custom Providers](../custom/index.md) for full setup. - -## Custom Endpoint - -Use `base_url` to connect to OpenAI-compatible APIs: - -```yaml -models: - custom: - provider: openai - model: gpt-5-mini - base_url: https://your-proxy.example.com/v1 -``` - -## WebSocket Transport - -For OpenAI Responses API models (gpt-4.1+, o-series, gpt-5), you can use WebSocket streaming instead of the default SSE (Server-Sent Events): - -```yaml -models: - fast-gpt: - provider: openai - model: gpt-4.1 - provider_opts: - transport: websocket # Use WebSocket instead of SSE -``` - -### Benefits - -- **~40% faster** for workflows with 20+ tool calls -- **Persistent connection** reduces per-turn overhead -- **Server-side caching** of connection state -- **Automatic fallback** to SSE if WebSocket fails - -### Requirements - -- Only works with Responses API models: `gpt-4.1+`, `o1`, `o3`, `o4`, `gpt-5` -- NOT compatible with the `--models-gateway` flag (automatically falls back to SSE when a gateway is configured) -- Requires `OPENAI_API_KEY` environment variable - -### Example - -See [`examples/websocket_transport.yaml`](https://github.com/docker/docker-agent/blob/main/examples/websocket_transport.yaml) for a complete example. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/opencode-go/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/opencode-go/index.md deleted file mode 100644 index 69199c31f557..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/opencode-go/index.md +++ /dev/null @@ -1,160 +0,0 @@ ---- -title: "OpenCode Go" -description: "Use OpenCode Go models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, opencode go -weight: 210 -canonical: https://docs.docker.com/ai/docker-agent/providers/opencode-go/ ---- - -_Use OpenCode Go models with Docker Agent._ - -## Overview - -[OpenCode Go](https://opencode.ai/docs/go) is a low-cost subscription service ($5 first month, then $10/month) that provides reliable access to popular open-source coding models. It serves models through both OpenAI-compatible and Anthropic-compatible APIs from globally distributed endpoints. - -Docker Agent includes built-in support for OpenCode Go as an alias provider. - -## Setup - -1. Subscribe to OpenCode Go at [opencode.ai/auth](https://opencode.ai/auth) -2. Copy your API key from the console -3. Set the environment variable: - - ```bash - export OPENCODE_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use OpenCode Go: - -```yaml -agents: - root: - model: opencode-go/deepseek-v4-flash - description: Assistant using OpenCode Go - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - my_model: - provider: opencode-go - model: deepseek-v4-pro - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: my_model - description: Assistant using OpenCode Go - instruction: You are a helpful assistant. -``` - -## Available Models - -You can retrieve the full, up-to-date model list at any time: - -```bash -curl https://opencode.ai/zen/go/v1/models -``` - -### OpenAI-Compatible - -These models use the `/v1/chat/completions` endpoint and work directly with the `opencode-go` alias: - -| Model | Description | -| ------------------- | ------------------------------------- | -| `deepseek-v4-flash` | Fast and cost-effective DeepSeek model | -| `deepseek-v4-pro` | Most capable DeepSeek model | -| `kimi-k2.7-code` | Kimi K2.7 optimized for code | -| `kimi-k2.6` | Kimi K2.6 model | -| `kimi-k2.5` | Kimi K2.5 model | -| `glm-5.2` | GLM 5.2 flagship model | -| `glm-5.1` | GLM 5.1 model | -| `glm-5` | GLM 5 model | -| `mimo-v2.5` | MiMo V2.5 efficient model | -| `mimo-v2.5-pro` | MiMo V2.5 Pro model | -| `mimo-v2-pro` | MiMo V2 Pro model | -| `mimo-v2-omni` | MiMo V2 Omni model | -| `hy3-preview` | HY3 preview model | - -### Anthropic-Compatible - -These models use the `/v1/messages` endpoint and require a [custom provider definition](../custom/index.md): - -| Model | Description | -| ----------------- | ------------------------ | -| `minimax-m3` | MiniMax M3 model | -| `minimax-m2.7` | MiniMax M2.7 model | -| `minimax-m2.5` | MiniMax M2.5 model | -| `qwen3.7-max` | Qwen 3.7 Max model | -| `qwen3.7-plus` | Qwen 3.7 Plus model | -| `qwen3.6-plus` | Qwen 3.6 Plus model | -| `qwen3.5-plus` | Qwen 3.5 Plus model | - -To use an Anthropic-compatible model, define a custom provider: - -```yaml -providers: - opengo-ant: - provider: anthropic - base_url: https://opencode.ai/zen/go - token_key: OPENCODE_API_KEY - -models: - qwen: - provider: opengo-ant - model: qwen3.7-max - -agents: - root: - model: qwen - description: Assistant using Qwen through OpenCode Go - instruction: You are a helpful assistant. -``` - -## How It Works - -OpenCode Go is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://opencode.ai/zen/go/v1` -- **Token Variable:** `OPENCODE_API_KEY` - -This means OpenCode Go uses the same client as OpenAI, making it fully compatible with all OpenAI features supported by Docker Agent. - -For Anthropic-compatible models (MiniMax, Qwen), Docker Agent uses a custom provider pointing to the Anthropic client at `https://opencode.ai/zen/go` with the same token. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: opencode-go/deepseek-v4-flash - description: Expert code assistant - instruction: | - You are an expert programmer using DeepSeek V4 Flash. - Write clean, efficient, well-documented code. - Explain your reasoning when helpful. - toolsets: - - type: filesystem - - type: shell - - type: think -``` - -## Usage Limits - -OpenCode Go subscriptions include the following limits: - -- **5-hour rolling limit** — $12 of usage -- **Weekly limit** — $30 of usage -- **Monthly limit** — $60 of usage - -Limits are defined as dollar values. More expensive models allow fewer requests per limit period. You can also [add Zen balance](https://opencode.ai/auth) to continue usage beyond the limits. diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/opencode-zen/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/opencode-zen/index.md deleted file mode 100644 index dc765cfd43f1..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/opencode-zen/index.md +++ /dev/null @@ -1,224 +0,0 @@ ---- -title: "OpenCode Zen" -description: "Use OpenCode Zen models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, opencode zen -weight: 220 -canonical: https://docs.docker.com/ai/docker-agent/providers/opencode-zen/ ---- - -_Use OpenCode Zen models with Docker Agent._ - -## Overview - -[OpenCode Zen](https://opencode.ai/docs/zen) is a curated gateway of tested and verified AI models provided by the OpenCode team. It offers pay-per-use access to a wide range of models — from GPT and Claude to open-source models — all through a single API key. Several free models are also available. - -Docker Agent includes built-in support for OpenCode Zen as an alias provider for OpenAI-compatible models. Anthropic and Google models are supported via custom provider definitions. - -## Setup - -1. Sign in to [OpenCode Zen](https://opencode.ai/auth), add billing information, and copy your API key -2. Set the environment variable: - - ```bash - export OPENCODE_API_KEY=your-api-key - ``` - -3. Verify available models: - - ```bash - curl https://opencode.ai/zen/v1/models - ``` - -## Usage - -### Inline Syntax - -The simplest way to use OpenCode Zen with a free model: - -```yaml -agents: - root: - model: opencode-zen/deepseek-v4-flash-free - description: Assistant using OpenCode Zen (free) - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - zen_model: - provider: opencode-zen - model: gpt-5.5 - temperature: 0.7 - max_tokens: 16384 - -agents: - root: - model: zen_model - description: Assistant using OpenCode Zen - instruction: You are a helpful assistant. -``` - -## Available Models - -### Free Models - -These models are available at no cost: - -| Model | Description | -| ------------------------- | ---------------------------------- | -| `deepseek-v4-flash-free` | Free DeepSeek V4 Flash | -| `mimo-v2.5-free` | Free MiMo V2.5 model | -| `qwen3.6-plus-free` | Free Qwen 3.6 Plus model | -| `minimax-m3-free` | Free MiniMax M3 model | -| `nemotron-3-ultra-free` | Free Nemotron 3 Ultra model | -| `north-mini-code-free` | Free North Mini Code model | -| `big-pickle` | Free stealth model | - -### OpenAI-Compatible (Chat Completions) - -These models use the `/v1/chat/completions` endpoint and work directly with the `opencode-zen` alias: - -| Model | Description | -| --------------------- | ---------------------------------- | -| `deepseek-v4-pro` | DeepSeek V4 Pro model | -| `deepseek-v4-flash` | Fast DeepSeek V4 model | -| `glm-5.2` | GLM 5.2 model | -| `glm-5.1` | GLM 5.1 model | -| `glm-5` | GLM 5 model | -| `kimi-k2.6` | Kimi K2.6 model | -| `kimi-k2.5` | Kimi K2.5 model | -| `minimax-m2.7` | MiniMax M2.7 model | -| `minimax-m2.5` | MiniMax M2.5 model | -| `grok-build-0.1` | Grok Build 0.1 model | - -### OpenAI-Compatible (Responses API) - -These models use the `/v1/responses` endpoint and are auto-detected by Docker Agent based on the model name: - -| Model | Description | -| ---------------------- | --------------------------------- | -| `gpt-5.5` | Latest GPT model | -| `gpt-5.5-pro` | GPT 5.5 Pro, highest capability | -| `gpt-5.4` | GPT 5.4 model | -| `gpt-5.4-pro` | GPT 5.4 Pro model | -| `gpt-5.4-mini` | GPT 5.4 Mini model | -| `gpt-5.4-nano` | GPT 5.4 Nano, fastest | -| `gpt-5.3-codex` | GPT 5.3 Codex for coding | -| `gpt-5.3-codex-spark` | GPT 5.3 Codex Spark | -| `gpt-5.2` | GPT 5.2 model | -| `gpt-5.2-codex` | GPT 5.2 Codex | -| `gpt-5.1` | GPT 5.1 model | -| `gpt-5.1-codex` | GPT 5.1 Codex | -| `gpt-5.1-codex-max` | GPT 5.1 Codex Max | -| `gpt-5.1-codex-mini` | GPT 5.1 Codex Mini | -| `gpt-5` | GPT 5 model | -| `gpt-5-codex` | GPT 5 Codex | -| `gpt-5-nano` | GPT 5 Nano | - -### Anthropic-Compatible (Messages API) - -These models use the `/v1/messages` endpoint and require a [custom provider definition](../custom/index.md): - -| Model | Description | -| ----------------------- | ----------------------------- | -| `claude-fable-5` | Claude Fable 5 model | -| `claude-opus-4-8` | Claude Opus 4.8 model | -| `claude-opus-4-7` | Claude Opus 4.7 model | -| `claude-opus-4-6` | Claude Opus 4.6 model | -| `claude-opus-4-5` | Claude Opus 4.5 model | -| `claude-opus-4-1` | Claude Opus 4.1 model | -| `claude-sonnet-4-6` | Claude Sonnet 4.6 model | -| `claude-sonnet-4-5` | Claude Sonnet 4.5 model | -| `claude-sonnet-4` | Claude Sonnet 4 model | -| `claude-haiku-4-5` | Claude Haiku 4.5 model | -| `qwen3.7-max` | Qwen 3.7 Max model | -| `qwen3.7-plus` | Qwen 3.7 Plus model | -| `qwen3.6-plus` | Qwen 3.6 Plus model | -| `qwen3.5-plus` | Qwen 3.5 Plus model | - -To use an Anthropic-compatible model: - -```yaml -providers: - opencode-zen-claude: - provider: anthropic - base_url: https://opencode.ai/zen - token_key: OPENCODE_API_KEY - -models: - claude: - provider: opencode-zen-claude - model: claude-sonnet-4-5 - -agents: - root: - model: claude - description: Assistant using Claude through OpenCode Zen - instruction: You are a helpful assistant. -``` - -### Google-Compatible - -These models require a [custom provider definition](../custom/index.md) with a Google-compatible client: - -| Model | Description | -| ------------------- | ------------------------ | -| `gemini-3.5-flash` | Gemini 3.5 Flash model | -| `gemini-3.1-pro` | Gemini 3.1 Pro model | -| `gemini-3-flash` | Gemini 3 Flash model | - -To use a Google model: - -```yaml -providers: - opencode-zen-gemini: - provider: google - base_url: https://opencode.ai/zen - token_key: OPENCODE_API_KEY - -models: - gemini: - provider: opencode-zen-gemini - model: gemini-3.5-flash - -agents: - root: - model: gemini - description: Assistant using Gemini through OpenCode Zen - instruction: You are a helpful assistant. -``` - -## How It Works - -OpenCode Zen is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (auto-detects Responses API for GPT models, Chat Completions for others) -- **Base URL:** `https://opencode.ai/zen/v1` -- **Token Variable:** `OPENCODE_API_KEY` - -The same API key works for both OpenCode Go and OpenCode Zen — they are part of the same platform. Zen uses a pay-per-use billing model, while Go uses a fixed subscription. - -For Anthropic-compatible models, Docker Agent uses a custom provider pointing to the Anthropic client at `https://opencode.ai/zen` with the same token. For Google models, a custom provider points to the Google client at `https://opencode.ai/zen` (the Google SDK appends its own `/v1beta/models/...` path segment). - -### Differences from OpenCode Go - -| Aspect | OpenCode Zen | OpenCode Go | -|--------|-------------|-------------| -| Billing | Pay-per-use | $10/month subscription | -| Models | GPT-5.x, Claude, Gemini, open-source | Open-source only | -| Free models | Yes (7 models) | No | -| Base URL | `https://opencode.ai/zen/v1` | `https://opencode.ai/zen/go/v1` | - -## Usage Limits and Pricing - -OpenCode Zen uses a pay-per-use model. See the [OpenCode Zen documentation](https://opencode.ai/docs/zen) for current pricing. Automatic top-up and monthly usage limits are available from the console. - -You can retrieve the full model catalog at any time: - -```bash -curl https://opencode.ai/zen/v1/models -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/openrouter/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/openrouter/index.md deleted file mode 100644 index b01d40211ef8..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/openrouter/index.md +++ /dev/null @@ -1,88 +0,0 @@ ---- -title: "OpenRouter" -description: "Use OpenRouter models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, openrouter -weight: 230 -canonical: https://docs.docker.com/ai/docker-agent/providers/openrouter/ ---- - -_Use OpenRouter models with Docker Agent._ - -## Overview - -OpenRouter provides access to models from many providers through an OpenAI-compatible API. Docker Agent includes built-in support for OpenRouter as an alias provider. - -## Setup - -1. Get an API key from [OpenRouter](https://openrouter.ai/settings/keys) -2. Set the environment variable: - - ```bash - export OPENROUTER_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use OpenRouter: - -```yaml -agents: - root: - model: openrouter/meta-llama/llama-3.3-70b-instruct - description: Assistant using OpenRouter - instruction: You are a helpful assistant. -``` - -OpenRouter model IDs usually include the upstream provider name, such as `anthropic/claude-sonnet-4-5` or `meta-llama/llama-3.3-70b-instruct`. Docker Agent splits only the first slash, so the full upstream model ID is preserved. - -### Named Model - -For more control over parameters: - -```yaml -models: - openrouter_llama: - provider: openrouter - model: meta-llama/llama-3.3-70b-instruct - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: openrouter_llama - description: Assistant using OpenRouter - instruction: You are a helpful assistant. -``` - -## Pricing and Model Metadata - -Docker Agent fetches OpenRouter model metadata from [models.dev](https://models.dev/), including pricing per 1M input/output tokens, cache pricing when available, context limits, output limits, and modalities. This powers cost tracking and the model picker in the same way as other first-class providers. - -If models.dev is unavailable, Docker Agent falls back to its embedded catalog snapshot. - -## How It Works - -OpenRouter is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai`) -- **Base URL:** `https://openrouter.ai/api/v1` -- **Token Variable:** `OPENROUTER_API_KEY` - -## Example: Code Assistant - -```yaml -agents: - coder: - model: openrouter/meta-llama/llama-3.3-70b-instruct - description: Code assistant using OpenRouter - instruction: | - You are an expert programmer. - Write clean, maintainable code. - Explain trade-offs when helpful. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/overview/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/overview/index.md deleted file mode 100644 index 662ca2a43043..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/overview/index.md +++ /dev/null @@ -1,104 +0,0 @@ ---- -title: "Model Providers" -description: "Docker Agent supports multiple AI model providers. Choose the right one for your use case, or use multiple providers in the same configuration." -keywords: docker agent, ai agents, model providers, llm -linkTitle: "Overview" -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/providers/overview/ -aliases: - - /ai/docker-agent/model-providers/ ---- - -_Docker Agent supports multiple AI model providers. Choose the right one for your use case, or use multiple providers in the same configuration._ - -## Supported Providers - -- [**OpenAI**](../openai/index.md) — GPT-5, GPT-5-mini, GPT-4o. The most widely used AI models. -- [**Anthropic**](../anthropic/index.md) — Claude Sonnet 4.5, Claude Opus 4.7. Excellent for coding and analysis. -- [**Google Gemini**](../google/index.md) — Gemini 2.5 Flash, Gemini 3 Pro. Fast and cost-effective. -- [**AWS Bedrock**](../bedrock/index.md) — access Claude, Nova, Llama, and more through AWS infrastructure. -- [**Docker Model Runner**](../dmr/index.md) — run models locally with Docker. No API keys, no costs. -- [**Local Models**](../local/index.md) — run Ollama, vLLM, or LocalAI locally. No API key required. -- [**Provider Definitions**](../custom/index.md) — define reusable provider configurations with shared defaults for any provider type. - -## Quick Comparison - -| Provider | Key | Local? | Strengths | -| ------------------- | ---------------- | ------ | ----------------------------------------------------- | -| OpenAI | `openai` | No | Broad model selection, tool calling, multimodal | -| Anthropic | `anthropic` | No | Strong coding, extended thinking, large context | -| Google | `google` | No | Fast inference, competitive pricing, multimodal | -| AWS Bedrock | `amazon-bedrock` | No | Enterprise features, multiple models, AWS integration | -| Docker Model Runner | `dmr` | Yes | No API costs, data privacy, offline capable | -| Local Models (Ollama / vLLM) | `ollama` / custom | Yes | No API costs, full data privacy, any OpenAI-compatible server | - -## Additional Built-in Providers - -Docker Agent also includes built-in aliases for these providers: - -| Provider | Alias | API Key / Env Variable | -| -------------- | ---------------- | ----------------------------------- | -| ChatGPT (OpenAI account) | [`chatgpt`](../chatgpt/index.md) | None (sign in via `docker agent setup`) | -| OpenCode Zen | `opencode-zen` | `OPENCODE_API_KEY` | -| OpenCode Go | `opencode-go` | `OPENCODE_API_KEY` | -| Mistral | `mistral` | `MISTRAL_API_KEY` | -| xAI (Grok) | `xai` | `XAI_API_KEY` | -| Nebius | `nebius` | `NEBIUS_API_KEY` | -| NVIDIA NIM | `nvidia` | `NVIDIA_API_KEY` | -| MiniMax | `minimax` | `MINIMAX_API_KEY` | -| Baseten | `baseten` | `BASETEN_API_KEY` | -| OVHcloud | `ovhcloud` | `OVH_AI_ENDPOINTS_ACCESS_TOKEN` | -| Groq | `groq` | `GROQ_API_KEY` | -| Fireworks AI | `fireworks` | `FIREWORKS_API_KEY` | -| DeepSeek | `deepseek` | `DEEPSEEK_API_KEY` | -| Cerebras | `cerebras` | `CEREBRAS_API_KEY` | -| Together AI | `together` | `TOGETHER_API_KEY` | -| Hugging Face | `huggingface` | `HF_TOKEN` | -| Cloudflare Workers AI | `cloudflare-workers-ai` | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` | -| Moonshot AI | `moonshot` | `MOONSHOT_API_KEY` | -| Vercel AI Gateway | `vercel` | `AI_GATEWAY_API_KEY` | -| Cloudflare AI Gateway | `cloudflare-ai-gateway` | `CLOUDFLARE_API_TOKEN` + `CLOUDFLARE_ACCOUNT_ID` + `CLOUDFLARE_GATEWAY_ID` | -| Requesty | `requesty` | `REQUESTY_API_KEY` | -| OpenRouter | `openrouter` | `OPENROUTER_API_KEY` | -| Azure OpenAI | `azure` | `AZURE_API_KEY` + `base_url` | -| [Ollama](../local/index.md) | `ollama` | None (local; optional `base_url`) | -| GitHub Copilot | `github-copilot` | `GITHUB_TOKEN` (PAT with `copilot` scope) | - -```bash -# Use built-in providers inline -agents: - root: - model: mistral/mistral-large-latest -``` - -> [!TIP] -> **Multi-provider teams** -> -> Use expensive models for complex reasoning and cheaper/local models for routine tasks. See the example below. - -## Using Multiple Providers - -Different agents can use different providers in the same configuration: - -```yaml -models: - claude: - provider: anthropic - model: claude-sonnet-4-5 - max_tokens: 64000 - gpt: - provider: openai - model: gpt-5 - local: - provider: dmr - model: ai/qwen3 - -agents: - root: - model: claude # coordinator uses Claude - sub_agents: [coder, helper] - coder: - model: gpt # coder uses GPT-5 - helper: - model: local # helper runs locally for free -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/ovhcloud/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/ovhcloud/index.md deleted file mode 100644 index 53298c8d57ac..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/ovhcloud/index.md +++ /dev/null @@ -1,108 +0,0 @@ ---- -title: "OVHcloud" -description: "Use OVHcloud AI Endpoints models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, ovhcloud -weight: 240 -canonical: https://docs.docker.com/ai/docker-agent/providers/ovhcloud/ ---- - -_Use OVHcloud AI Endpoints models with Docker Agent._ - -## Overview - -[OVHcloud AI Endpoints](https://endpoints.ai.cloud.ovh.net/) serves open-weight -models through an OpenAI-compatible API, hosted in the EU. Docker Agent includes -built-in support for OVHcloud as an alias provider. - -## Setup - -1. Create an access token from the - [OVHcloud AI Endpoints portal](https://endpoints.ai.cloud.ovh.net/). -2. Set the environment variable: - - ```bash - export OVH_AI_ENDPOINTS_ACCESS_TOKEN=your-access-token - ``` - -## Usage - -### Inline Syntax - -```yaml -agents: - root: - model: ovhcloud/Qwen3.5-397B-A17B - description: Assistant using OVHcloud - instruction: You are a helpful assistant. -``` - -### Named Model - -```yaml -models: - ovhcloud_model: - provider: ovhcloud - model: Qwen3.5-397B-A17B - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: ovhcloud_model - description: Assistant using OVHcloud - instruction: You are a helpful assistant. -``` - -## Available Models - -OVHcloud hosts a rotating catalogue of open-weight models. Check the -[AI Endpoints catalogue](https://endpoints.ai.cloud.ovh.net/) for current model -IDs, context limits, and free-tier availability. - -| Model | Description | -| --- | --- | -| `Qwen3.5-397B-A17B` | Large Qwen3.5 MoE — strong general, coding, and reasoning | -| `Qwen3-32B` | Mid-size Qwen3 — fast, tool-calling, reasoning | -| `Qwen3.6-27B` | Compact Qwen3.6 — fast and efficient | -| `Qwen3.5-9B` | Small Qwen3.5 — lightweight, free-tier friendly | -| `Qwen3-Coder-30B-A3B-Instruct` | Qwen3 Coder MoE — optimised for code generation | -| `Meta-Llama-3_3-70B-Instruct` | Llama 3.3 70B — reliable general-purpose chat | -| `Mistral-Small-3.2-24B-Instruct-2506` | Compact, fast, tool-calling | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -OVHcloud is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://oai.endpoints.kepler.ai.cloud.ovh.net/v1` -- **Token Variable:** `OVH_AI_ENDPOINTS_ACCESS_TOKEN` - -Docker Agent automatically coalesces consecutive system messages into one for -OVHcloud, because some OVHcloud models return an empty stream when a request -carries more than one system message. - -## Free tier - -OVHcloud offers rate-limited free access to several models. Under heavy -rate-limiting the endpoint may return an empty response; Docker Agent surfaces -this as a warning rather than failing. For sustained use, an access token with a -paid plan avoids the free-tier request-rate cap. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: ovhcloud/Qwen3.5-397B-A17B - description: Code assistant using Qwen3.5 - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/together/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/together/index.md deleted file mode 100644 index 8dda71006171..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/together/index.md +++ /dev/null @@ -1,101 +0,0 @@ ---- -title: "Together AI" -description: "Use Together AI models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, together ai -weight: 250 -canonical: https://docs.docker.com/ai/docker-agent/providers/together/ ---- - -_Use Together AI models with Docker Agent._ - -## Overview - -[Together AI](https://www.together.ai/) is one of the largest hosts of open -models, serving Llama, Qwen, DeepSeek, Kimi, GLM and others through an -OpenAI-compatible API. Docker Agent includes built-in support for Together AI as -an alias provider. - -## Setup - -1. Create an API key from the [Together AI settings](https://api.together.ai/settings/api-keys). -2. Set the environment variable: - - ```bash - export TOGETHER_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use Together AI: - -```yaml -agents: - root: - model: together/meta-llama/Llama-3.3-70B-Instruct-Turbo - description: Assistant using Together AI - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - together_model: - provider: together - model: meta-llama/Llama-3.3-70B-Instruct-Turbo - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: together_model - description: Assistant using Together AI - instruction: You are a helpful assistant. -``` - -## Available Models - -Together AI serves a broad, changing catalog of open-weight models. Check the -[Together AI model library](https://docs.together.ai/docs/serverless-models) for -current model IDs, context limits, and pricing. - -| Model | Description | -| --- | --- | -| `meta-llama/Llama-3.3-70B-Instruct-Turbo` | Llama 3.3 70B, general-purpose chat and tool calling | -| `Qwen/Qwen3-235B-A22B-Instruct-2507-tput` | Qwen3 235B mixture-of-experts instruct model | -| `deepseek-ai/DeepSeek-V3` | DeepSeek-V3, strong coding and reasoning | - -> Model IDs are case-sensitive and must be passed exactly as the catalogue lists -> them. - -## How It Works - -Together AI is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.together.xyz/v1` -- **Token Variable:** `TOGETHER_API_KEY` - -Because Together AI fronts open-weight models whose chat templates may reject -more than one leading system message, Docker Agent coalesces its per-source -system messages into a single one for this provider. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: together/Qwen/Qwen3-235B-A22B-Instruct-2507-tput - description: Code assistant using Qwen3 on Together AI - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/vercel/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/vercel/index.md deleted file mode 100644 index f2278690bb23..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/vercel/index.md +++ /dev/null @@ -1,109 +0,0 @@ ---- -title: "Vercel AI Gateway" -description: "Use Vercel AI Gateway models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, vercel ai gateway -weight: 260 -canonical: https://docs.docker.com/ai/docker-agent/providers/vercel/ ---- - -_Use Vercel AI Gateway models with Docker Agent._ - -## Overview - -[Vercel AI Gateway](https://vercel.com/docs/ai-gateway) is a single, unified -OpenAI-compatible endpoint that routes to models from OpenAI, Anthropic, Google, -xAI and more at list price with no markup, plus provider routing and failover. -It lets you reach many providers with one API key. Docker Agent includes -built-in support for Vercel AI Gateway as an alias provider. - -## Setup - -1. Create an API key from the [Vercel AI Gateway dashboard](https://vercel.com/docs/ai-gateway). -2. Set the environment variable: - - ```bash - export AI_GATEWAY_API_KEY=your-api-key - ``` - -## Usage - -Vercel AI Gateway model IDs use a `creator/model` form (for example -`openai/gpt-5.6-sol` or `anthropic/claude-sonnet-4.5`); the gateway routes each -request to the underlying provider. The gateway lists explicit variant slugs -only (`openai/gpt-5.6-sol`, `-terra`, `-luna`) — there is no unsuffixed -`openai/gpt-5.6` alias on the gateway. - -### Inline Syntax - -The simplest way to use Vercel AI Gateway: - -```yaml -agents: - root: - model: vercel/openai/gpt-5.6-sol - description: Assistant using Vercel AI Gateway - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - vercel_model: - provider: vercel - model: openai/gpt-5.6-sol - max_tokens: 8192 - -agents: - root: - model: vercel_model - description: Assistant using Vercel AI Gateway - instruction: You are a helpful assistant. -``` - -## Available Models - -Vercel AI Gateway exposes models from many providers behind one endpoint. Check -the [Vercel AI Gateway documentation](https://vercel.com/docs/ai-gateway) for -the current model list, IDs, and pricing. - -| Model | Description | -| --- | --- | -| `openai/gpt-5.6-sol` | OpenAI GPT-5.6 Sol (frontier) routed through the gateway | -| `openai/gpt-5.6-terra` | OpenAI GPT-5.6 Terra (workhorse) routed through the gateway | -| `openai/gpt-5.6-luna` | OpenAI GPT-5.6 Luna (high-volume) routed through the gateway | -| `anthropic/claude-sonnet-4.5` | Anthropic Claude Sonnet routed through the gateway | -| `google/gemini-2.5-flash` | Google Gemini routed through the gateway | - -> Model IDs are case-sensitive and must be passed exactly as the gateway lists -> them, including the `creator/` prefix. - -## How It Works - -Vercel AI Gateway is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://ai-gateway.vercel.sh/v1` -- **Token Variable:** `AI_GATEWAY_API_KEY` - -Because the gateway can route to open-weight models with strict chat templates, -Docker Agent coalesces consecutive system messages into a single leading one for -this provider. - -## Example: Code Assistant - -```yaml -agents: - coder: - model: vercel/anthropic/claude-sonnet-4.5 - description: Code assistant via Vercel AI Gateway - instruction: | - You are an expert programmer. - Write clean, well-documented code and follow language best practices. - toolsets: - - type: filesystem - - type: shell - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/providers/xai/index.md b/_vendor/github.com/docker/docker-agent/docs/providers/xai/index.md deleted file mode 100644 index 638e5018826b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/providers/xai/index.md +++ /dev/null @@ -1,99 +0,0 @@ ---- -title: "xAI (Grok)" -description: "Use xAI's Grok models with Docker Agent." -keywords: docker agent, ai agents, model providers, llm, xai (grok) -weight: 270 -canonical: https://docs.docker.com/ai/docker-agent/providers/xai/ ---- - -_Use xAI's Grok models with Docker Agent._ - -## Overview - -xAI provides the Grok family of models through an OpenAI-compatible API. Docker Agent includes built-in support for xAI as an alias provider. - -## Setup - -1. Get an API key from [xAI Console](https://console.x.ai/) -2. Set the environment variable: - - ```bash - export XAI_API_KEY=your-api-key - ``` - -## Usage - -### Inline Syntax - -The simplest way to use xAI: - -```yaml -agents: - root: - model: xai/grok-3 - description: Assistant using Grok - instruction: You are a helpful assistant. -``` - -### Named Model - -For more control over parameters: - -```yaml -models: - grok: - provider: xai - model: grok-3 - temperature: 0.7 - max_tokens: 8192 - -agents: - root: - model: grok - description: Assistant using Grok - instruction: You are a helpful assistant. -``` - -## Available Models - -| Model | Description | Context | -| ------------------ | ---------------------------------- | ------- | -| `grok-3` | Latest and most capable Grok model | 131K | -| `grok-3-fast` | Faster variant with lower latency | 131K | -| `grok-3-mini` | Compact model for simpler tasks | 131K | -| `grok-3-mini-fast` | Fast variant of the mini model | 131K | -| `grok-2` | Previous generation model | 128K | -| `grok-vision` | Vision-capable model | 32K | - -Check the [xAI documentation](https://docs.x.ai/docs) for the latest available models. - -## Extended Thinking - -Docker Agent's `thinking_budget` field is **not applied** to xAI models: the underlying OpenAI-compatible client only sends `reasoning_effort` for OpenAI reasoning model names (o-series, gpt-5). Setting `thinking_budget` on a Grok model passes config validation but has no effect on the request. - -Grok reasoning models (e.g. `grok-3-mini`) reason on their own without configuration. For non-reasoning models, use the [think tool](../../tools/think/index.md) instead. - -## How It Works - -xAI is implemented as a built-in alias in Docker Agent: - -- **API Type:** OpenAI-compatible (`openai_chatcompletions`) -- **Base URL:** `https://api.x.ai/v1` -- **Token Variable:** `XAI_API_KEY` - -## Example: Research Assistant - -```yaml -agents: - researcher: - model: xai/grok-3 - description: Research assistant with real-time knowledge - instruction: | - You are a research assistant using Grok. - Provide well-researched, factual responses. - Cite sources when available. - toolsets: - - type: mcp - ref: docker:duckduckgo - - type: think -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/_index.md b/_vendor/github.com/docker/docker-agent/docs/tools/_index.md deleted file mode 100644 index ca9847f9a25d..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/_index.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -title: "Built-in Tools" -description: "Built-in toolsets agents can use out of the box." -weight: 40 ---- diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/a2a/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/a2a/index.md deleted file mode 100644 index f07a9fe62435..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/a2a/index.md +++ /dev/null @@ -1,43 +0,0 @@ ---- -title: "A2A Tool" -description: "Connect to remote agents via the Agent-to-Agent protocol." -keywords: docker agent, ai agents, tools, toolsets, a2a tool -linkTitle: "A2A" -weight: 60 -canonical: https://docs.docker.com/ai/docker-agent/tools/a2a/ ---- - -_Connect to remote agents via the Agent-to-Agent protocol._ - -## Overview - -The A2A tool connects to a remote agent exposed over the A2A (Agent-to-Agent) protocol. Unlike [`handoff`](../handoff/index.md), which only targets local agents declared in the same config, `a2a` reaches out to an agent running on the network. - -## Configuration - -```yaml -toolsets: - - type: a2a - url: "http://localhost:8080/a2a" - # Optional: custom tool name (defaults to a sanitized form of the URL / agent card name) - name: research_agent - # Optional: custom HTTP headers (typically for auth) - headers: - Authorization: "Bearer ${env.A2A_TOKEN}" - X-Tenant: "acme" -``` - -The `Authorization` header shown above authenticates to endpoints served with `docker agent serve a2a --auth-token`. - -## Properties - -| Property | Type | Required | Description | -| ---------- | ---------------- | -------- | -------------------------------------------------------------------------------------------------------- | -| `url` | string | ✓ | A2A server endpoint URL (must include scheme). | -| `name` | string | ✗ | Tool name registered for the remote agent. Defaults to a name derived from the server's agent card. | -| `headers` | map\[string\]string | ✗ | Extra HTTP headers sent with every request (useful for `Authorization`, tenant selection, tracing, \u2026). | - -> [!TIP] -> **See also** -> -> For full details on the A2A protocol and serving agents as A2A endpoints, see [A2A Protocol](../../features/a2a/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/api/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/api/index.md deleted file mode 100644 index 73e802bd5b89..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/api/index.md +++ /dev/null @@ -1,252 +0,0 @@ ---- -title: "API Tool" -description: "Create custom tools that call HTTP APIs." -keywords: docker agent, ai agents, tools, toolsets, api tool -linkTitle: "API" -weight: 240 -canonical: https://docs.docker.com/ai/docker-agent/tools/api/ ---- - -_Create custom tools that call HTTP APIs._ - -## Overview - -The API tool type lets you define custom tools that make HTTP requests to external APIs. This is useful for integrating agents with REST APIs, webhooks, or any HTTP-based service without writing code. - -> [!NOTE] -> **When to Use** -> -> - Integrating with REST APIs that don't have an MCP server -> - Simple HTTP operations (GET, POST) -> - Quick prototyping before building a full MCP server - -## Configuration - -```yaml -agents: - assistant: - model: openai/gpt-4o - description: Assistant with API access - instruction: You can look up weather information. - toolsets: - - type: api - api_config: - name: get_weather - method: GET - endpoint: "https://api.weather.example/v1/current?city=${city}" - instruction: Get current weather for a city - args: - city: - type: string - description: City name to get weather for - required: ["city"] - headers: - Authorization: "Bearer ${env.WEATHER_API_KEY}" -``` - -## Properties - -The `api` toolset accepts the following toolset-level fields in addition to the `api_config` block: - -| Property | Type | Required | Description | -| ------------------- | ------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `api_config` | object | ✓ | The HTTP tool definition. See the table below. | -| `timeout` | int | ✗ | HTTP client timeout in seconds (default: `30`). Applies to every call the generated tool makes. | -| `allow_private_ips` | boolean | ✗ | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast and the unspecified address). Set to `true` only when the configured endpoint legitimately targets internal services. See [Reaching internal services](#reaching-internal-services). | - -### `api_config` - -| Property | Type | Required | Description | -| --------------- | ------ | -------- | ------------------------------------------------ | -| `name` | string | ✓ | Tool name (how the agent references it) | -| `method` | string | ✓ | HTTP method: `GET` or `POST` | -| `endpoint` | string | ✓ | URL endpoint (supports `${param}` interpolation) | -| `instruction` | string | ✗ | Description shown to the agent | -| `args` | object | ✗ | Parameter definitions (JSON Schema properties) | -| `required` | array | ✗ | List of required parameter names | -| `headers` | object | ✗ | HTTP headers to include. Values support `${env.VAR}` and `${headers.NAME}` placeholders (the latter forwards a header from the caller's incoming request, useful when docker agent is itself exposed as an HTTP server). | -| `output_schema` | object | ✗ | JSON Schema for the response. Used by MCP / Code Mode consumers; tool responses are still returned to the model as raw strings. | - -## HTTP Methods - -### GET Requests - -For GET requests, parameters are interpolated into the URL: - -```yaml -toolsets: - - type: api - api_config: - name: search_users - method: GET - endpoint: "https://api.example.com/users?q=${query}&limit=${limit}" - instruction: Search for users by name - args: - query: - type: string - description: Search query - limit: - type: integer - description: Maximum results (default 10) - required: ["query"] -``` - -### POST Requests - -For POST requests, parameters are sent as JSON in the request body: - -```yaml -toolsets: - - type: api - api_config: - name: create_task - method: POST - endpoint: "https://api.example.com/tasks" - instruction: Create a new task - args: - title: - type: string - description: Task title - description: - type: string - description: Task description - priority: - type: string - enum: ["low", "medium", "high"] - description: Task priority - required: ["title"] - headers: - Content-Type: "application/json" - Authorization: "Bearer ${env.API_TOKEN}" -``` - -## URL Interpolation - -Use `${param}` syntax to insert parameter values into URLs: - -```yaml -endpoint: "https://api.example.com/users/${user_id}/posts/${post_id}" -``` - -Parameter values are inserted as strings by the template expansion. Add URL encoding in the template when needed (for example, `${encodeURIComponent(city)}`). - -## Headers - -Headers can include environment variables: - -```yaml -headers: - Authorization: "Bearer ${env.API_KEY}" - X-Custom-Header: "static-value" - Content-Type: "application/json" -``` - -## Output Schema - -Optionally document the expected response format: - -```yaml -toolsets: - - type: api - api_config: - name: get_user - method: GET - endpoint: "https://api.example.com/users/${id}" - instruction: Get user details by ID - args: - id: - type: string - description: User ID - required: ["id"] - output_schema: - type: object - properties: - id: - type: string - name: - type: string - email: - type: string - created_at: - type: string -``` - -## Example: GitHub API - -```yaml -agents: - github_assistant: - model: openai/gpt-4o - description: Assistant that can query GitHub - instruction: You can look up GitHub repositories and users. - toolsets: - - type: api - api_config: - name: get_repo - method: GET - endpoint: "https://api.github.com/repos/${owner}/${repo}" - instruction: Get information about a GitHub repository - args: - owner: - type: string - description: Repository owner (user or org) - repo: - type: string - description: Repository name - required: ["owner", "repo"] - headers: - Accept: "application/vnd.github.v3+json" - Authorization: "Bearer ${env.GITHUB_TOKEN}" - - - type: api - api_config: - name: get_user - method: GET - endpoint: "https://api.github.com/users/${username}" - instruction: Get information about a GitHub user - args: - username: - type: string - description: GitHub username - required: ["username"] - headers: - Accept: "application/vnd.github.v3+json" -``` - -## Limitations - -- Only supports GET and POST methods -- Response body is limited to 1MB -- Default 30-second timeout per request (override with the `timeout` field) -- Only HTTP and HTTPS URLs are supported -- No support for file uploads or multipart forms -- By default, requests to non-public IP ranges (loopback, RFC1918, link-local, the cloud-metadata endpoint, multicast, the unspecified address) are refused at dial time — even when DNS for an otherwise-public host resolves there. Set `allow_private_ips: true` to disable that check. - -## Reaching internal services - -```yaml -toolsets: - - type: api - timeout: 60 - allow_private_ips: true - api_config: - name: get_local_status - method: GET - endpoint: "http://localhost:8080/health" - instruction: Check the local service health -``` - -> [!WARNING] -> **SSRF** -> -> Setting `allow_private_ips: true` re-exposes the SSRF surface for this tool. Only enable it when the configured `endpoint` is a trusted internal service — a prompt-injected agent cannot redirect the call elsewhere because the endpoint is fixed in config, but redirects from the configured host can still reach unexpected places. - -> [!TIP] -> **For Complex APIs** -> -> For APIs that need authentication flows, pagination, or complex request/response handling, consider using an MCP server instead. The API tool is best for simple, stateless HTTP operations. - -> [!WARNING] -> **Security** -> -> API keys and tokens in headers are visible in debug logs. Use environment variables (`${env.VAR}`) rather than hardcoding secrets in configuration files. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/background-agents/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/background-agents/index.md deleted file mode 100644 index 0c6afbfaaed9..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/background-agents/index.md +++ /dev/null @@ -1,120 +0,0 @@ ---- -title: "Background Agents Tool" -description: "Dispatch work to sub-agents concurrently and collect results asynchronously." -keywords: docker agent, ai agents, tools, toolsets, background agents tool -linkTitle: "Background Agents" -weight: 90 -canonical: https://docs.docker.com/ai/docker-agent/tools/background-agents/ ---- - -_Dispatch work to sub-agents concurrently and collect results asynchronously._ - -## Overview - -The background agents tool lets an orchestrator dispatch work to sub-agents concurrently and collect results asynchronously. Unlike [transfer_task](../transfer-task/index.md) (which blocks until the sub-agent finishes), background agent tasks run in parallel — the orchestrator can start several tasks, do other work, and check on them later. - -## Available Tools - -| Tool | Description | -| ------------------------ | --------------------------------------------------------------- | -| `run_background_agent` | Start a sub-agent task in the background; returns a task ID | -| `list_background_agents` | List all background tasks with their status and runtime | -| `view_background_agent` | View live output or final result of a task by ID | -| `stop_background_agent` | Cancel a running task by ID | - -### `run_background_agent` parameters - -| Parameter | Type | Required | Description | -| ----------------- | ------ | -------- | --------------------------------------------------------------------------- | -| `agent` | string | ✓ | Name of the sub-agent to run. Must be listed under the caller's `sub_agents`. | -| `task` | string | ✓ | Clear, concise description of the task the sub-agent should achieve. | -| `expected_output` | string | ✗ | Optional description of the result format the caller expects. | - -`run_background_agent` returns a **task ID** string. Tools run by the sub-agent inherit the parent session's permissions. Because background tasks run non-interactively, any tool call that would normally prompt the user for approval will be automatically denied. To allow background agents to run mutating tools, you must explicitly approve them in the parent session (e.g. via YOLO mode or explicit allow rules). - -Background delegation shares the same runtime guards as `transfer_task`: delegation cycles are rejected and chains are capped at 10 nested delegations. See [Delegation Limits](../transfer-task/index.md#delegation-limits). - -### `view_background_agent` and `stop_background_agent` parameters - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | -------------------------------------------------------------- | -| `task_id` | string | ✓ | Task ID returned by `run_background_agent` or `list_background_agents`. | - -`list_background_agents` takes no parameters. - -## Configuration - -```yaml -toolsets: - - type: background_agents -``` - -No configuration options. Requires the agent to have `sub_agents` configured so the background tasks have agents to dispatch to. - -## Example - -```yaml -agents: - coordinator: - model: openai/gpt-4o - description: Orchestrates parallel research - instruction: Fan out research tasks and synthesize results. - sub_agents: [researcher] - toolsets: - - type: background_agents - - type: think - - researcher: - model: openai/gpt-4o - description: Web researcher - instruction: Research topics thoroughly. - toolsets: - - type: mcp - ref: docker:duckduckgo -``` - -> [!TIP] -> **When to Use** -> -> Use `background_agents` when your orchestrator needs to fan out work to multiple specialists in parallel — for example, researching several topics simultaneously or running independent code analyses side by side. - -In the TUI, each background task's token usage is accounted for live: the sidebar's Agents panel shows the sub-agent's context usage percentage on its roster row, the Agent Inspector shows its exact token counts, and the task's cost joins the session total. - -## Using Harness Sub-Agents - -Background agents work equally well with [harness-backed sub-agents](../../features/harnesses/index.md) — sub-agents driven by external coding CLIs such as Claude Code or Codex. This lets you dispatch multiple independent coding tasks in parallel: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Orchestrator that fans out coding tasks - instruction: | - Dispatch the frontend and backend tasks in parallel, - then collect results and produce a summary. - sub_agents: - - claude-coder - - codex-coder - toolsets: - - type: background_agents - - claude-coder: - description: Frontend specialist (Claude Code) - harness: - type: claude-code - effort: medium - - codex-coder: - description: Backend specialist (Codex) - harness: - type: codex -``` - -The orchestrator calls `run_background_agent` for each coding task, then uses `list_background_agents` and `view_background_agent` to collect results when they finish. - -> [!NOTE] -> **Harness toolsets are ignored** -> -> Harness agents use the external CLI's own tools — any `toolsets:` configured on the harness agent are silently ignored. See [Coding Harnesses](../../features/harnesses/index.md) for details and caveats. - -See [`examples/coding_harness_background_agents.yaml`](https://github.com/docker/docker-agent/blob/main/examples/coding_harness_background_agents.yaml) for a complete configuration. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/background-jobs/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/background-jobs/index.md deleted file mode 100644 index 8a7a3915e678..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/background-jobs/index.md +++ /dev/null @@ -1,89 +0,0 @@ ---- -title: "Background Jobs Tool" -description: "Run and manage long-running shell commands." -keywords: docker agent, ai agents, tools, toolsets, background jobs, shell -linkTitle: "Background Jobs" -weight: 21 -canonical: https://docs.docker.com/ai/docker-agent/tools/background-jobs/ ---- - -_Run and manage long-running shell commands._ - -## Overview - -The `background_jobs` toolset starts shell commands that should keep running while the agent continues with other work, such as local servers, file watchers, long builds, or test suites. It returns a job ID immediately, captures combined stdout/stderr up to 10 MB per job, and terminates all running jobs when the agent session ends. - -Use the [`shell`](../shell/index.md) toolset for short synchronous commands. Add both toolsets when an agent needs both synchronous commands and long-running processes. - -## Configuration - -```yaml -toolsets: - - type: shell - - type: background_jobs -``` - -### Options - -| Property | Type | Description | -| -------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `env` | object | Environment variables to set for all background job commands. | -| `recall` | boolean | Let `run_background_job` expose a `recall` parameter so jobs can steer the agent when they finish (see [Background job recall](#background-job-recall)). Default `false`. | - -### Custom Environment Variables - -```yaml -toolsets: - - type: background_jobs - env: - MY_VAR: "value" - PATH: "${env.PATH}:/custom/bin" -``` - -### Background job recall - -Set `recall: true` to let the `run_background_job` tool expose a `recall` boolean parameter: - -```yaml -toolsets: - - type: background_jobs - recall: true -``` - -When the agent starts a background job with `recall: true`, Docker Agent sends a steering message back into the running agent loop after the job finishes. The message contains a short completion sentence and the job output, so the agent can react without polling `view_background_job`. - -Use recall for finite background work where completion matters (for example, a long build or test suite). Avoid it for servers and watchers that are expected to run until stopped. See [`examples/shell_recall.yaml`](https://github.com/docker/docker-agent/blob/main/examples/shell_recall.yaml) for a complete configuration. - -## Available Tools - -The background jobs toolset exposes five tools: - -| Tool Name | Description | -| ---------------------- | ---------------------------------------------------------------------------------------------- | -| `run_background_job` | Start a command asynchronously and return a job ID immediately. Use for servers/watchers/etc. | -| `list_background_jobs` | List all background jobs with their status, runtime, and metadata. | -| `view_background_job` | View the buffered output and status of a specific background job by ID. | -| `stop_background_job` | Stop a running background job. Child processes are terminated too. | -| `wait_background_job` | Block until a job finishes and return its exit code and output. Safe on already-finished jobs. | - -### `run_background_job` parameters - -| Parameter | Type | Required | Description | -| --------- | ------- | -------- | ------------------------------------------------------------------------------------------------------------------------------------------- | -| `cmd` | string | ✓ | The shell command to execute in the background. | -| `cwd` | string | ✗ | Working directory to run the command in (default: `.`). | -| `recall` | boolean | ✗ | Only available when the `background_jobs` toolset has `recall: true`. When true, send a steering message with the job output when it finishes. | - -`view_background_job` and `stop_background_job` each take a single required `job_id` string returned by `run_background_job` or `list_background_jobs`. - -### `wait_background_job` parameters - -| Parameter | Type | Required | Description | -| --------- | ------- | -------- | -------------------------------------------------------------------------------------------------------------- | -| `job_id` | string | ✓ | Job ID returned by `run_background_job` or `list_background_jobs`. | -| `timeout` | integer | ✗ | Maximum seconds to wait (default: `60`). If the job is still running when the limit fires, the tool returns the current output with a notice and the job continues in the background. | - -> [!WARNING] -> **Safety** -> -> Background jobs run shell commands with the same access as the agent process. Stop servers and watchers when they are no longer needed, and use [Sandbox Mode](../../configuration/sandbox/index.md) for additional isolation. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/fetch/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/fetch/index.md deleted file mode 100644 index fa793a54ac07..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/fetch/index.md +++ /dev/null @@ -1,173 +0,0 @@ ---- -title: "Fetch Tool" -description: "Read content from HTTP/HTTPS URLs." -keywords: docker agent, ai agents, tools, toolsets, fetch tool -linkTitle: "Fetch" -weight: 50 -canonical: https://docs.docker.com/ai/docker-agent/tools/fetch/ ---- - -_Read content from HTTP/HTTPS URLs._ - -## Overview - -The fetch tool lets agents retrieve content from one or more HTTP/HTTPS URLs. It is **read-only** — only `GET` requests are supported. The tool respects `robots.txt`, limits response size (1 MB per URL), and can return content as plain text, Markdown (converted from HTML), or raw HTML. - -> [!NOTE] -> **GET only** -> -> The fetch tool does **not** support `POST`, `PUT`, `DELETE` or other methods, and does not expose request bodies or per-call custom headers (the toolset can still attach static [credential headers](#custom-headers) to every request). To call REST endpoints with other verbs, use the [API tool](../api/index.md) or an [OpenAPI toolset](../openapi/index.md). - -## Configuration - -```yaml -toolsets: - - type: fetch -``` - -### Options - -| Property | Type | Default | Description | -| ------------------- | ------------- | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `timeout` | int | `30` | Default request timeout in seconds (overridable per tool call). | -| `allowed_domains` | array[string] | _none_ | Allow-list of hosts the tool may fetch. When set, every URL whose host is **not** in the list is rejected before any network call is made. Mutually exclusive with `blocked_domains`. | -| `blocked_domains` | array[string] | _none_ | Deny-list of hosts the tool must not fetch. URLs whose host matches one of these patterns are rejected before any network call (including `robots.txt`) is made. Mutually exclusive with `allowed_domains`. | -| `allow_private_ips` | boolean | `false` | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast, and the unspecified address). Required to reach `localhost` / internal services. See [SSRF protection](#ssrf-protection-and-reaching-localhost) below. | -| `headers` | map[string]string | _none_ | Static HTTP headers attached to **every** request the toolset issues (including `robots.txt`). Values support `${env.VAR}` for secrets. Caller-supplied entries override the default `User-Agent` and the format-driven `Accept` header. Headers are stripped on cross-host redirects so credentials never leak to a third-party host. See [Custom headers](#custom-headers) below. | - -### Domain matching - -Domain patterns in `allowed_domains` and `blocked_domains` use the following rules (case-insensitive): - -- **Bare domain** — `example.com` matches the host `example.com` _and_ any subdomain such as `docs.example.com`. It does **not** match unrelated hosts that share a suffix (e.g. `badexample.com`). -- **Leading dot** — `.example.com` matches **only** strict subdomains (`docs.example.com`, `a.b.example.com`), not the apex `example.com`. -- **Wildcard glob** — `*.example.com` is an alias for the leading-dot form; the apex is excluded. The `*` is only valid as a leading `*.` token (entries like `foo.*`, `*.*.example.com`, or a bare `*` are rejected at config-load time). -- **IP literal** — IP addresses are matched exactly (`169.254.169.254`). -- **CIDR range** — `169.254.0.0/16`, `10.0.0.0/8`, `::1/128`, `fc00::/7`. Matches when the URL's host parses as an IP inside the network. Hostname hosts never match a CIDR pattern. Malformed CIDRs are rejected at config-load time. -- **Trailing dots** in FQDN-form URLs (`http://example.com./`) are stripped before matching, so they cannot bypass a deny-list entry. - -The lists are mutually exclusive: a single fetch toolset may set either `allowed_domains` or `blocked_domains`, but not both. - -When a list is configured, every redirect target is re-checked against the same list. A request to an allowed origin that redirects to a forbidden host is rejected before any data is read from the redirect. - -> [!WARNING] -> **Limitations** -> -> Matching is purely string-based on the URL host. It does **not** perform DNS resolution and does **not** normalise alternative IP encodings (decimal `2852039166`, hex `0xa9.0xfe.0xa9.0xfe`, octal, etc. IPv4-mapped IPv6 addresses ARE normalized to their IPv4 form). If you need to deny access to a specific IP, also list its alternative encodings, or block at the network layer. - -### Custom Timeout - -```yaml -toolsets: - - type: fetch - timeout: 60 -``` - -### Custom headers - -Attach static headers — typically credentials — to every request. Values support `${env.VAR}` interpolation so secrets stay out of YAML, and headers are dropped on cross-host redirects so a redirect chain cannot leak them to a third-party host: - -```yaml -toolsets: - - type: fetch - allowed_domains: - - docs.internal.example.com - headers: - Authorization: "Bearer ${env.INTERNAL_DOCS_TOKEN}" - X-Internal-Client: "docker-agent" -``` - -> [!WARNING] -> **Pair credential headers with an allow-list** -> -> When `headers` carries credentials (e.g. `Authorization`), set `allowed_domains` to the specific hosts that should receive them. Stdlib already strips a small allow-list (`Authorization`, `Cookie`, `WWW-Authenticate`) on cross-domain redirects, and the fetch tool additionally strips every operator-supplied header on cross-host redirects — but an allow-list is the strongest guarantee against accidental exfiltration. - -### Restrict to specific domains - -```yaml -toolsets: - - type: fetch - allowed_domains: - - docker.com # docker.com and *.docker.com - - github.com # github.com and *.github.com - - .githubusercontent.com # only subdomains, e.g. raw.githubusercontent.com -``` - -### Block sensitive hosts - -```yaml -toolsets: - - type: fetch - blocked_domains: - - 169.254.169.254 # cloud metadata endpoint (literal IP) - - 169.254.0.0/16 # entire link-local range (CIDR) - - 10.0.0.0/8 # RFC1918 private range - - "*.internal.example.com" # any subdomain (wildcard) - - internal.example.com # internal corporate hostname -``` - -> [!NOTE] -> **Already blocked by default** -> -> You do **not** need to add loopback, RFC1918, link-local (incl. `169.254.169.254`), multicast or the unspecified address to `blocked_domains` to be safe — the fetch tool already refuses connections to those ranges at dial time, after DNS resolution. The example above is only useful if you also want to reject those hosts _before_ any network call (and to surface a clearer error message to the agent), or if you have set `allow_private_ips: true` and want to deny a specific subset. - -### SSRF protection and reaching localhost - -By default, the fetch tool refuses connections to **non-public IP addresses** — even when DNS for an otherwise-public host resolves to one of them (so DNS rebinding is also blocked). The check happens at dial time, after DNS resolution, and rejects: - -- **Loopback** — `127.0.0.0/8`, `::1` (this is what blocks `http://localhost/...` and `http://127.0.0.1/...`) -- **RFC1918 private ranges** — `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16` -- **Link-local** — `169.254.0.0/16` (IPv4, including the cloud-metadata endpoint `169.254.169.254`) and `fe80::/10` (IPv6) -- **Multicast** and the **unspecified** address (`0.0.0.0`, `::`) -- **IPv4-mapped IPv6** — addresses like `::ffff:127.0.0.1` or `::ffff:169.254.169.254` are normalized to their IPv4 form and blocked accordingly - -This is the default because LLM-driven fetches are a classic Server-Side Request Forgery (SSRF) vector: a prompt-injected URL can otherwise reach internal services, cloud metadata, or admin interfaces on the host running the agent. - -If an agent legitimately needs to call **localhost** or an **internal service**, opt in with `allow_private_ips: true`: - -```yaml -toolsets: - - type: fetch - allow_private_ips: true - allowed_domains: - - localhost - - 127.0.0.1 - - 10.0.0.0/8 # internal corporate range -``` - -> [!WARNING] -> **Pair with an allow-list** -> -> Setting `allow_private_ips: true` alone re-exposes the SSRF surface. We strongly recommend combining it with an `allowed_domains` entry that restricts the tool to the specific internal hosts or CIDRs the agent actually needs (e.g. `localhost`, `127.0.0.1`, or your internal CIDR). -> -> **Note:** `allowed_domains` is checked _before_ DNS resolution (string-based on hostname), while the SSRF check happens _after_ DNS resolution (on the resolved IP). This means `allowed_domains` and `blocked_domains` are evaluated independently of `allow_private_ips` and continue to apply. A public hostname in `allowed_domains` that resolves to a private IP will still be blocked unless `allow_private_ips: true` is set. - -## Tool Interface - -The toolset exposes a single tool, `fetch`, with the following parameters: - -| Parameter | Type | Required | Description | -| --------- | -------------- | -------- | ----------------------------------------------------------------------------------------------------------- | -| `urls` | array[string] | ✓ | One or more HTTP/HTTPS URLs to fetch (all via `GET`). | -| `format` | string | ✓ | Output format: `text`, `markdown`, or `html`. HTML responses are converted to text/markdown when requested. | -| `timeout` | integer | ✗ | Per-call request timeout in seconds. Overrides the toolset default. Valid range: `1`–`300`. | - -Responses are capped at **1 MB** per URL. Hosts that disallow the agent's user-agent via `robots.txt` are skipped with a clear error. - -> [!TIP] -> **Fetch vs. API Tool** -> -> Use `fetch` when the agent needs to read arbitrary public URLs at runtime. Use the [API tool](../api/index.md) to expose specific, structured HTTP endpoints (including non-`GET` verbs) as named tools. - -## Domain Filtering - -The `allowed_domains`, `blocked_domains`, and `allow_private_ips` options let you control which hosts the fetch tool may reach. The complete reference is in the [Options](#options) table and [Domain matching](#domain-matching) section above. - -**Key points:** - -- `allowed_domains` — allow-list; only listed hosts (and their subdomains for bare-domain entries) are reachable -- `blocked_domains` — deny-list; mutually exclusive with `allowed_domains` (a config error is thrown if both are set) -- `allow_private_ips` — defaults to `false`; set to `true` to reach loopback / RFC-1918 / link-local addresses -- The same `allow_private_ips` flag is also supported on `api`, `openapi`, `a2a`, and remote `mcp` toolsets - -See [`examples/fetch_domain_filtering.yaml`](https://github.com/docker/docker-agent/blob/main/examples/fetch_domain_filtering.yaml) for a complete filtering example, and [`examples/remote_mcp_allow_private_ips.yaml`](https://github.com/docker/docker-agent/blob/main/examples/remote_mcp_allow_private_ips.yaml) for the equivalent pattern on remote MCP toolsets. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/filesystem/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/filesystem/index.md deleted file mode 100644 index 19b0be53e1c2..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/filesystem/index.md +++ /dev/null @@ -1,145 +0,0 @@ ---- -title: "Filesystem Tool" -description: "Read, write, list, search, and navigate files and directories." -keywords: docker agent, ai agents, tools, toolsets, filesystem tool -linkTitle: "Filesystem" -weight: 10 -canonical: https://docs.docker.com/ai/docker-agent/tools/filesystem/ ---- - -_Read, write, list, search, and navigate files and directories._ - -## Overview - -The filesystem tool gives agents the ability to explore codebases, read and edit files, create new files, search across files, and navigate directory structures. - -### Path resolution - -Paths are resolved relative to the **working directory** (the directory where the agent session started, or the directory specified with `--workdir`): - -- **Relative paths** (e.g., `src/main.go`, `../README.md`) are joined with the working directory. -- **Absolute paths** must match the host operating system: - - Unix/Linux/macOS: `/home/user/project/file.txt` - - Windows: `C:\Users\user\project\file.txt` or `C:/Users/user/project/file.txt` -- **Home directory expansion**: paths starting with `~` or `~/` expand to the user's home directory. - -When a file is not found, error messages include the resolved absolute path to help diagnose incorrect base directories or path formats. - -> [!IMPORTANT] -> Agents must use paths appropriate for the host OS. A Windows absolute path like `C:\file.txt` on a Unix system (or vice versa) is rejected with a clear error message. - -### Empty directory detection - -When `list_directory` encounters an empty directory or a directory where all entries are hidden by ignore patterns (e.g., only a `.git` folder when `ignore_vcs: true`), it explicitly reports the state: - -- **Empty directory**: "Directory is empty: /path/to/dir" -- **All entries ignored**: "Directory has no visible entries (N hidden by ignore patterns): /path/to/dir" - -This helps agents distinguish between an empty directory and a tool failure, avoiding unnecessary retries with shell commands. - -## Available Tools - -| Tool | Description | -| ---------------------- | ------------------------------------------------------------------------- | -| `read_file` | Read the contents of a file (whole file, or a line range of a text file) | -| `read_multiple_files` | Read several files in one call (more efficient than multiple `read_file`) | -| `write_file` | Create or overwrite a file with new content | -| `edit_file` | Make line-based edits (find-and-replace) in an existing file. Each edit must specify a non-empty `oldText` to match and replace; empty `oldText` values are rejected with an error. | -| `list_directory` | List files and directories at a given path (explicitly reports empty directories) | -| `directory_tree` | Recursive tree view of a directory | -| `create_directory` | Create a new directory (creates parent directories as needed) | -| `remove_directory` | Remove an empty directory | -| `search_files_content` | Search for text or regex patterns across files | - -## edit_file Validation - -The `edit_file` tool applies a sequence of find-and-replace edits to a file in memory, then writes the result back atomically. Each edit must provide a non-empty `oldText` value: - -- **Valid**: `{"oldText": "line one", "newText": "LINE ONE"}` -- **Invalid**: `{"oldText": "", "newText": "INJECTED"}` — rejected with error - -An empty `oldText` is never a meaningful edit: Go's `strings.Contains(s, "")` is always `true`, and `strings.Replace(s, "", new, 1)` silently inserts at offset 0. Without validation, this would prepend content to the file while still reporting success. The tool now returns an explicit error ("oldText must not be empty") when an edit has an empty `oldText`, and no changes are written to disk. - -When a sequence contains multiple edits and a later one is rejected, the entire operation fails and the file is left untouched — edits are applied in memory and only written once at the end, so partial application is not possible. - -## Configuration - -```yaml -toolsets: - - type: filesystem -``` - -### Options - -| Property | Type | Default | Description | -| --- | --- | --- | --- | -| `ignore_vcs` | boolean | `true` | When `true` (default), `.git` directories and `.gitignore` patterns are excluded from listings and searches. Set to `false` to include them. | -| `post_edit` | array | `[]` | Commands to run after editing files matching a path pattern | -| `post_edit[].path` | string | — | Glob pattern for files (e.g., `*.go`, `src/*/*.ts`) | -| `post_edit[].cmd` | string | — | Command to run (use `${file}` for the edited file path) | -| `allow_list` | array | `[]` | Directories the tools may access. Empty = unrestricted (default). | -| `deny_list` | array | `[]` | Directories the tools must not access. Takes precedence over `allow_list`. | - -### Path access control - -By default the filesystem tools are unrestricted: relative paths resolve -from the working directory, but absolute paths and `..` traversals can -reach anywhere the agent process can. Configure `allow_list` and/or -`deny_list` to sandbox the toolset. - -Entries in either list are expanded as follows: - -- `"."` — the agent's working directory -- `"~"` or `"~/..."` — the user's home directory -- `"$VAR"` / `"${VAR}"` / `"${env.VAR}"` — environment variable expansion -- absolute paths — used as-is -- relative paths — anchored at the working directory - -Symlinks are resolved before the containment check, so a symlink inside an -allowed root cannot be used to escape it. When an `allow_list` is set, -each entry is opened as a Go [`*os.Root`](https://pkg.go.dev/os#Root) so -that the kernel's rooted-lookup semantics also reject `..` and symlink -escapes at I/O time, not just at resolve time. - -```yaml -toolsets: - - type: filesystem - # Restrict every operation to the working directory and the user's - # home folder, then carve credentials out of the home folder. - allow_list: - - "." - - "~" - deny_list: - - "~/.ssh" - - "~/.aws" -``` - -When the path supplied by the agent is rejected, the tool returns a -structured error rather than performing any filesystem I/O. This makes the -restriction visible to the model so it can adjust its plan. - -### Post-Edit Hooks - -Automatically run formatting, linting, or other commands after the agent edits a file. The command fires once per file after each edit operation (`write_file` and `edit_file`). Use `${file}` as a placeholder for the absolute path of the edited file. - -```yaml -toolsets: - - type: filesystem - ignore_vcs: false - post_edit: - - path: "*.go" - cmd: "gofmt -w ${file}" - - path: "*.ts" - cmd: "prettier --write ${file}" - - path: "src/*/*.py" - cmd: "black ${file}" -``` - -| Property | Type | Description | -| --- | --- | --- | -| `path` | string | Glob pattern matched against the file path. `*.go` matches any `.go` file; `src/*/*.ts` matches `.ts` files inside `src/`. | -| `cmd` | string | Shell command to run. `${file}` expands to the absolute path of the just-edited file. | - -Post-edit commands run with the same working directory as the agent. If a command exits non-zero, the error is logged and surfaced to the model as a warning, but the edit is not rolled back. - -See [`examples/post_edit.yaml`](https://github.com/docker/docker-agent/blob/main/examples/post_edit.yaml) for a complete example. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/git/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/git/index.md deleted file mode 100644 index 9568b7508dfa..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/git/index.md +++ /dev/null @@ -1,100 +0,0 @@ ---- -title: "Git Tool" -description: "Read-only inspection of the working git repository." -keywords: docker agent, ai agents, tools, toolsets, git tool -linkTitle: "Git" -weight: 125 -canonical: https://docs.docker.com/ai/docker-agent/tools/git/ ---- - -_Read-only inspection of the working git repository._ - -## Overview - -The git toolset gives an agent structured, **read-only** access to the working repository — status, history, branches, a commit's changes, and line-level authorship. It is implemented with go-git, so it needs **no `git` binary**. - -Compared with running `git` through the `shell` tool, the git toolset returns clean, structured output the model can read reliably, is **safe by construction** (no command can modify the repository), and works even when `shell` is disabled or no `git` binary is installed. - -> [!NOTE] -> The git toolset is read-only. To stage, commit, or check out, use the [`shell`](../shell/index.md) tool. - -## Configuration - -```yaml -toolsets: - - type: git -``` - -No configuration options. The repository is opened at the agent's working directory; a subdirectory still resolves to the repository root. - -> [!WARNING] -> **The repository is discovered by walking up parent directories.** If the working -> directory is not itself a repository but an ancestor is (for example a -> home directory tracked as dotfiles), the toolset resolves to that ancestor and -> `git_show` / `git_blame` can expose its full history and file contents. The -> filesystem toolset's allow/deny lists do **not** apply here. Only enable this -> toolset where the surrounding repository is safe to read. - -> [!NOTE] -> **Performance.** go-git is pure Go, which costs speed on large repositories: -> `git_status` rehashes the whole worktree, and `git_blame` scales with history -> depth times file size — its 400-line output cap is applied *after* the full -> computation, so it does not make blaming a large file cheaper. - -## Tools - -| Tool | Description | -| --- | --- | -| `git_status` | Current branch and changed files (staged / unstaged / untracked). | -| `git_log` | Recent commits (hash, date, author, subject). | -| `git_branches` | Local branches, current one marked with `*`. | -| `git_show` | A commit's metadata, message, and changed files with +/- counts. | -| `git_blame` | Line-by-line authorship for a file. | - -### `git_log` - -| Parameter | Required | Description | -| --- | --- | --- | -| `limit` | No | Maximum number of commits to return (default 20). | -| `path` | No | Only show commits that touch this path. | - -### `git_show` - -| Parameter | Required | Description | -| --- | --- | --- | -| `ref` | No | Commit hash or revision to show (default HEAD). | - -### `git_blame` - -| Parameter | Required | Description | -| --- | --- | --- | -| `path` | Yes | File path to blame, relative to the repository root. | -| `rev` | No | Commit or revision to blame at (default HEAD). | - -## Example - -```yaml -agents: - root: - model: openai/gpt-5-mini - description: A code review assistant - instruction: | - Review the working changes: check git_status, then git_show the latest - commit, and summarize what changed. - toolsets: - - type: git - - type: filesystem -``` - -Example `git_status` output: - -```text -On branch master -1 changed file(s) [XY = staged/worktree; M=modified A=added D=deleted R=renamed ?=untracked]: - M main.go -``` - -> [!TIP] -> **When to use** -> -> Use the git toolset whenever the agent needs repository context — before editing, to review recent history, or to find who last touched a line — without exposing the writable `shell` surface. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/handoff/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/handoff/index.md deleted file mode 100644 index 4375be03daac..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/handoff/index.md +++ /dev/null @@ -1,63 +0,0 @@ ---- -title: "Handoff Tool" -description: "Hand off the active conversation to another local agent defined in the same config." -keywords: docker agent, ai agents, tools, toolsets, handoff tool -linkTitle: "Handoff" -weight: 70 -canonical: https://docs.docker.com/ai/docker-agent/tools/handoff/ ---- - -_Hand off the active conversation to another local agent defined in the same config._ - -## Overview - -The `handoff` tool lets an agent transfer control of the **current conversation** to another agent in the **same config file**. Unlike [`transfer_task`](../transfer-task/index.md), which delegates a sub-task and collects the result, `handoff` rewires the session so the receiving agent continues the conversation directly with the user. - -This is the core mechanism for **handoffs routing** — a pattern where a router agent classifies the user's request and hands it off to a specialist, which then owns the rest of the session. - -> [!NOTE] -> **Local only** -> -> The `handoff` tool only targets agents declared in the **same** config file by their local name. It does **not** open network connections. To delegate to a remote agent over the network, use the [A2A toolset](../a2a/index.md) instead. - -## Configuration - -The tool is enabled implicitly when an agent declares a non-empty `handoffs:` list. You do **not** add `- type: handoff` under `toolsets:` — it is not a toolset type. - -```yaml -agents: - router: - model: openai/gpt-4o - description: Routes questions to the right specialist - instruction: | - Classify the user's question and hand off to the most appropriate - specialist. If unsure, ask a clarifying question first. - handoffs: [billing, support] - - billing: - model: openai/gpt-4o - description: Billing specialist - instruction: Answer billing questions. - - support: - model: openai/gpt-4o - description: Technical support specialist - instruction: Help with technical issues. -``` - -The router agent automatically gets a `handoff` tool it can call to switch the conversation to `billing` or `support`. - -## Tool Interface - -The `handoff` tool takes a single parameter: - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | ----------------------------------------------------------------- | -| `agent` | string | ✓ | The local name of the agent to hand off the conversation to. | - -Only names listed in the current agent's `handoffs:` field are valid targets. - -> [!TIP] -> **See also** -> -> For sub-task delegation (caller stays in control, waits for the result), see [Transfer Task](../transfer-task/index.md). For remote agent connections over the network, see the [A2A toolset](../a2a/index.md). For the broader pattern, see [Handoffs Routing](../../concepts/multi-agent/index.md#handoffs-routing). diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/lsp/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/lsp/index.md deleted file mode 100644 index b2d97b7227b6..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/lsp/index.md +++ /dev/null @@ -1,227 +0,0 @@ ---- -title: "LSP Tool" -description: "Connect to Language Server Protocol servers for code intelligence." -keywords: docker agent, ai agents, tools, toolsets, lsp tool -linkTitle: "LSP" -weight: 220 -canonical: https://docs.docker.com/ai/docker-agent/tools/lsp/ ---- - -_Connect to Language Server Protocol servers for code intelligence._ - -## Overview - -The LSP tool connects your agent to any Language Server Protocol (LSP) server, providing comprehensive code intelligence capabilities like go-to-definition, find references, diagnostics, and more. - -> [!NOTE] -> **What is LSP?** -> -> The [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) is a standard for providing language features like autocomplete, go-to-definition, and diagnostics. Most programming languages have LSP servers available. - -## Available Tools - -The LSP toolset provides these tools to the agent: - -| Tool | Description | Read-Only | -| ----------------------- | --------------------------------------------- | --------- | -| `lsp_workspace` | Get workspace info and available capabilities | ✓ | -| `lsp_hover` | Get type info and documentation for a symbol | ✓ | -| `lsp_definition` | Find where a symbol is defined | ✓ | -| `lsp_references` | Find all references to a symbol | ✓ | -| `lsp_document_symbols` | List all symbols in a file | ✓ | -| `lsp_workspace_symbols` | Search symbols across the workspace | ✓ | -| `lsp_diagnostics` | Get errors and warnings for a file | ✓ | -| `lsp_code_actions` | Get available quick fixes and refactorings | ✓ | -| `lsp_rename` | Rename a symbol across the workspace | ✗ | -| `lsp_format` | Format a file | ✗ | -| `lsp_call_hierarchy` | Find incoming/outgoing calls | ✓ | -| `lsp_type_hierarchy` | Find supertypes/subtypes | ✓ | -| `lsp_implementations` | Find interface implementations | ✓ | -| `lsp_signature_help` | Get function signature at call site | ✓ | -| `lsp_inlay_hints` | Get type annotations and parameter names | ✓ | - -## Configuration - -```yaml -agents: - developer: - model: anthropic/claude-sonnet-4-5 - description: Code developer with LSP support - instruction: You are a software developer. - toolsets: - - type: lsp - command: gopls - args: [] - file_types: [".go"] - - type: filesystem - - type: shell -``` - -## Properties - -| Property | Type | Required | Description | -| ------------- | ------ | -------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `command` | string | ✓ | LSP server executable command | -| `args` | array | ✗ | Command-line arguments for the LSP server | -| `env` | object | ✗ | Environment variables for the LSP process | -| `file_types` | array | ✗ | File extensions this LSP handles (e.g., `[".go", ".mod"]`) | -| `working_dir` | string | ✗ | Working directory for the LSP server process. Relative paths are resolved against the agent's working directory. Defaults to the agent's working directory when omitted. | -| `version` | string | ✗ | Package reference for [auto-installing](../../configuration/tools/index.md#auto-installing-tools) the command binary | - -## Common LSP Servers - -Here are configurations for popular languages: - -### Go (gopls) - -```yaml -toolsets: - - type: lsp - command: gopls - version: "golang/tools@v0.21.0" # optional: auto-install if not in PATH - file_types: [".go"] -``` - -If your Go module lives in a subdirectory (e.g. a monorepo where `go.mod` is under `./backend`), set `working_dir` so `gopls` is started from the module root: - -```yaml -toolsets: - - type: lsp - command: gopls - file_types: [".go"] - working_dir: ./backend # gopls must be started from the module root -``` - -### TypeScript/JavaScript (typescript-language-server) - -```yaml -toolsets: - - type: lsp - command: typescript-language-server - args: ["--stdio"] - file_types: [".ts", ".tsx", ".js", ".jsx"] -``` - -### Python (pylsp) - -```yaml -toolsets: - - type: lsp - command: pylsp - file_types: [".py"] -``` - -### Rust (rust-analyzer) - -```yaml -toolsets: - - type: lsp - command: rust-analyzer - file_types: [".rs"] -``` - -### C/C++ (clangd) - -```yaml -toolsets: - - type: lsp - command: clangd - file_types: [".c", ".cpp", ".h", ".hpp"] -``` - -## Multiple LSP Servers - -You can configure multiple LSP servers for different file types: - -```yaml -agents: - polyglot: - model: anthropic/claude-sonnet-4-5 - description: Multi-language developer - instruction: You are a full-stack developer. - toolsets: - - type: lsp - command: gopls - file_types: [".go"] - - type: lsp - command: typescript-language-server - args: ["--stdio"] - file_types: [".ts", ".tsx", ".js", ".jsx"] - - type: lsp - command: pylsp - file_types: [".py"] - - type: filesystem - - type: shell -``` - -## Workflow Instructions - -The LSP tool includes built-in instructions that guide the agent on how to use it effectively. The agent learns to: - -1. Start with `lsp_workspace` to understand available capabilities -2. Use `lsp_workspace_symbols` to find relevant code -3. Use `lsp_references` before modifying any symbol -4. Check `lsp_diagnostics` after every code change -5. Apply `lsp_format` after edits are complete - -> [!TIP] -> **Best Practice** -> -> Always include the `filesystem` tool alongside LSP. The agent needs filesystem access to read and write code files, while LSP provides intelligence about the code. - -## Capability Detection - -Not all LSP servers support all features. During the `initialize` handshake, Docker Agent reads the server's `ServerCapabilities` and **filters out the `lsp_*` tools the server does not advertise**. The model never sees, for example, `lsp_inlay_hints` against a server that doesn't support it, so it can't waste a turn calling a tool that would only fail. - -The agent uses `lsp_workspace` to discover what's available: - -```text -Workspace Information: -- Root: /path/to/project -- Server: gopls v0.14.0 -- File types: .go - -Available Capabilities: -- Hover: Yes -- Go to Definition: Yes -- Find References: Yes -- Rename: Yes -- Code Actions: Yes -- Formatting: Yes -- Call Hierarchy: Yes -- Type Hierarchy: Yes -... -``` - -## Auto-Restart and Lifecycle - -LSP toolsets are managed by the same supervisor as MCP toolsets, so a crashed `gopls` (or any other language server) is reconnected automatically with exponential backoff. Use the [`lifecycle`](../../configuration/tools/index.md#toolset-lifecycle) block to tune the policy per toolset — for example, mark `gopls` as `strict` if your CI flow requires it to be available, or use `/toolset-restart gopls` from the TUI to force a reconnect when the server gets stuck. - -```yaml -toolsets: - - type: lsp - command: gopls - file_types: [".go"] - lifecycle: - profile: resilient # default: auto-restart on crash with exponential backoff -``` - -## Position Format - -All LSP tools use **1-based** line and character positions: - -- Line 1 is the first line of the file -- Character 1 is the first character on a line - -```json -{ - "file": "/path/to/file.go", - "line": 42, - "character": 15 -} -``` - -> [!TIP] -> **Auto-Installation** -> -> Docker Agent can automatically download and install LSP servers if they are not found in your PATH. Use the `version` property to specify a package, or let Docker Agent auto-detect it from the command name. See [Auto-Installing Tools](../../configuration/tools/index.md#auto-installing-tools) for details. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/mcp-catalog/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/mcp-catalog/index.md deleted file mode 100644 index d395a3ef6de7..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/mcp-catalog/index.md +++ /dev/null @@ -1,113 +0,0 @@ ---- -title: "MCP Catalog Tool" -description: "Let the agent discover and activate remote MCP servers from the Docker MCP Catalog on demand." -keywords: docker agent, ai agents, tools, toolsets, mcp catalog tool -linkTitle: "MCP Catalog" -weight: 120 -canonical: https://docs.docker.com/ai/docker-agent/tools/mcp-catalog/ ---- - -_Let the agent discover and activate remote MCP servers from the Docker MCP Catalog on demand._ - -## Overview - -The `mcp_catalog` toolset gives an agent access to a curated subset of the [Docker MCP Catalog](https://hub.docker.com/search?q=&type=mcp) — every server in this subset is reachable over the **streamable-http** transport, so Docker Agent can talk to it directly without the MCP gateway or a local subprocess. - -Servers are **not** active by default. Instead, the toolset exposes a small set of meta-tools the agent uses to search, enable, and disable servers as a turn unfolds. Tools from un-enabled servers stay hidden, so the prompt is not flooded with hundreds of tool definitions the agent will never use. - -> [!NOTE] -> **When to use it** -> -> Use `mcp_catalog` when you want the agent to _decide at runtime_ which third-party services it needs (Notion, Stripe, Brave Search, …) instead of pinning that decision in YAML up front. For a fixed set of servers, declare each one with [`type: mcp`](../../configuration/tools/index.md#mcp-tools) directly — the catalog adds an extra layer of meta-tools that pure `type: mcp` entries do not need. - -## Configuration - -```yaml -toolsets: - - type: mcp_catalog -``` - -The catalog is embedded in the `docker-agent` binary and refreshed with each release. By default every server in the embedded subset is offered. - -### Restricting the offered servers - -Two optional lists narrow what the toolset offers, so an agent sees a focused, predictable menu instead of the full catalog: - -- **`allowed_servers`** — when non-empty, **only** these catalog server ids are searchable and enableable; every other entry is hidden. -- **`blocked_servers`** — removes individual ids from the offered set. It is applied **after** `allowed_servers`, so a server listed in both is blocked (block wins over allow). - -Both take server ids (the `id` field returned by `search_remote_mcp_servers`). An empty or omitted list disables that filter. - -```yaml -toolsets: - - type: mcp_catalog - allowed_servers: - - docker-docs - - microsoft-learn - - hugging-face - blocked_servers: - - gitmcp -``` - -## Meta-Tools - -Up to five tools are exposed to the model. The disable / reset-auth pair only appears once at least one server is enabled, so the meta-tool surface stays minimal until the agent activates something. - -| Tool | When visible | Description | -| ------------------------------- | ----------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- | -| `search_remote_mcp_servers` | Always | Case-insensitive fuzzy search over id, title, description, category and tags. Returns id, auth requirements (`oauth` / `none`) and URL. | -| `enable_remote_mcp_server` | Always | Activate a server by id. **Blocks** until the connection (and any required OAuth handshake) completes; on success the server's tools are immediately live and the model continues with the user's original request in the same turn. | -| `list_remote_mcp_servers` | Always | Show currently enabled servers and their connection state. | -| `disable_remote_mcp_server` | After first enable | Stop a server and remove its tools from the active set. | -| `reset_remote_mcp_server_auth` | After first enable | Drop persisted OAuth credentials so the next enable triggers a fresh authorization flow. No-op for `none` servers. | - -### Workflow - -1. The agent calls `search_remote_mcp_servers` with a keyword matching the user's intent (`"notion"`, `"stripe"`, `"docs"`, `"browser"`, `"grafana"`, …). -2. It picks a matching server id and calls `enable_remote_mcp_server`. **`enable` blocks** until the MCP handshake (and any required OAuth flow) completes: - - on success the server's tools are available **in the same turn** — the agent goes straight to the user's original request, no re-ask required; - - on failure (user dismissed the authorization dialog, server refused) the tool returns an error result naming the specific reason so the agent can recover instead of pretending the server is connected. -3. It uses the newly activated tools as it would any other. -4. When done, it calls `disable_remote_mcp_server` to remove the server from the active set. - -## Authentication - -The catalog only includes servers Docker Agent can authenticate itself, so there are two auth flavours: - -- **`oauth`** — `enable_remote_mcp_server` surfaces an authorization URL through the elicitation pipeline (the same one used by YAML-declared remote MCP toolsets) and blocks until the user either authorizes or cancels. Once the user authorizes, tokens are persisted in the OS keyring and re-used on subsequent runs. Use `reset_remote_mcp_server_auth` to wipe them. If the user dismisses the dialog, `enable` returns an error result naming the decline so the agent can ask whether to retry. -- **`none`** — No authentication. The server is reachable as soon as it is enabled. - -Servers that require a caller-provided API key are intentionally excluded from the catalog. To use one, declare it explicitly with [`type: mcp`](../../configuration/tools/index.md#mcp-tools) and supply the key via an environment variable. - -## Example - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Agent that can on-demand connect to remote MCP servers from the Docker MCP Catalog. - instruction: | - You can discover and activate remote MCP servers on demand. - Use search_remote_mcp_servers to find a server matching the - user's intent, then enable_remote_mcp_server to activate it. - Be conservative: enable only the servers you actually need for - the task at hand. Disable a server with disable_remote_mcp_server - once you are done with it. - toolsets: - - type: mcp_catalog -``` - -A complete, runnable configuration lives in [`examples/mcp_catalog.yaml`](https://github.com/docker/docker-agent/blob/main/examples/mcp_catalog.yaml). A curated, allow/block-listed variant lives in [`examples/mcp_catalog_filtered.yaml`](https://github.com/docker/docker-agent/blob/main/examples/mcp_catalog_filtered.yaml). - -## Notes and Limitations - -- **Streamable-http only.** The catalog deliberately excludes servers that require a local subprocess or the MCP gateway — declare those with [`type: mcp`](../../configuration/tools/index.md#mcp-tools) instead. -- **Catalog membership changes between releases.** The set of available servers is updated with each Docker Agent release as integrations are added or removed. Servers present in one release may not appear in the next. -- **Blocking enable.** DNS, TCP, MCP handshake and any OAuth flow happen synchronously inside `enable_remote_mcp_server` so the agent gets a deterministic result in the same turn. On startup, however, the runtime probes tools non-interactively (`mcp.WithoutInteractivePrompts`); OAuth-pending servers fail fast there and are silently deferred to the next interactive turn — including the sidebar-only tool-count pass, where a dialog would be impossible. -- **No prompt discovery.** MCP prompt lookups (`/prompts`) walk YAML-declared `mcp` toolsets directly; prompts exposed by servers activated through the catalog are not surfaced. Tools — the primary interface — work fine. -- **Frozen at build time.** The list of servers is embedded in the binary. New entries land with each Docker Agent release. - -> [!TIP] -> **Pair with permissions** -> -> Because the agent decides which third-party services to talk to, this toolset works best with explicit [permissions](../../configuration/permissions/index.md) on the surrounding tools (filesystem writes, shell commands) so a misrouted server cannot exfiltrate data unnoticed. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/mcp/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/mcp/index.md deleted file mode 100644 index b1acb0cca7ea..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/mcp/index.md +++ /dev/null @@ -1,309 +0,0 @@ ---- -title: "MCP Tool" -description: "Extend agents with external tools via the Model Context Protocol." -keywords: docker agent, ai agents, tools, toolsets, mcp tool -linkTitle: "MCP" -weight: 130 -canonical: https://docs.docker.com/ai/docker-agent/tools/mcp/ -aliases: - - /ai/docker-agent/integrations/mcp/ ---- - -_Extend agents with external tools via the Model Context Protocol (MCP)._ - -## Overview - -The `mcp` toolset connects your agent to any MCP server — a process or remote service that exposes tools, resources, and prompts over the [Model Context Protocol](https://modelcontextprotocol.io/). Three flavours are supported: - -| Flavour | Transport | Best for | -| --- | --- | --- | -| **Docker MCP** | Container via the [MCP Gateway](https://github.com/docker/mcp-gateway) | Curated, sandboxed servers from the [Docker MCP Catalog](https://hub.docker.com/u/mcp) | -| **Local stdio** | Subprocess over stdin/stdout | Custom or community MCP servers run from a binary or `npx`/`pip` package | -| **Remote** | Streamable HTTP or SSE | Cloud services with hosted MCP endpoints (Linear, Notion, Atlassian, …) | - -> [!NOTE] -> **What is MCP?** -> -> The [Model Context Protocol](https://modelcontextprotocol.io/) is an open standard for connecting AI tools. Docker Agent can both _use_ MCP servers (this page) and _expose_ agents as MCP servers — see [MCP Mode](../../features/mcp-mode/index.md). - -## Docker MCP (Recommended) - -Run MCP servers as secure Docker containers via the MCP Gateway. The `ref: docker:` syntax pulls a curated definition from the Docker MCP Catalog: - -```yaml -toolsets: - - type: mcp - ref: docker:duckduckgo # web search - - type: mcp - ref: docker:github-official # GitHub integration - tools: ["list_issues", "create_issue"] -``` - -Browse available servers at the [Docker MCP Catalog](https://hub.docker.com/u/mcp). - -| Property | Type | Description | -| ------------- | ------ | ---------------------------------------------------------------- | -| `ref` | string | Docker MCP reference (`docker:name`) or a name from the [reusable `mcps:`](../../configuration/overview/index.md#reusable-mcp-servers-mcps) block. | -| `tools` | array | Optional whitelist — only expose these tools to the model. | -| `instruction` | string | Custom instructions injected into the agent's context. | -| `config` | any | MCP server-specific configuration passed during initialization. | -| `working_dir` | string | Working directory for the MCP gateway subprocess. Only applies when the catalog entry runs as a local process (not remote). Relative paths are resolved against the agent's working directory. Supports `${env.VAR}` (canonical), plus `~` and shell-style `$VAR`/`${VAR}` expansion ([details](../../configuration/overview/index.md#variable-expansion-in-config-fields)). | - -## Local MCP (stdio) - -Run MCP servers as local processes communicating over stdin/stdout: - -```yaml -toolsets: - - type: mcp - command: python - args: ["-m", "mcp_server"] - tools: ["search", "fetch"] - env: - API_KEY: value -``` - -| Property | Type | Description | -| ------------- | ------ | ----------- | -| `command` | string | Command to execute the MCP server. | -| `args` | array | Command arguments. | -| `tools` | array | Optional whitelist — only expose these tools. | -| `env` | object | Environment variables (key-value pairs). | -| `working_dir` | string | Working directory for the MCP server process. Relative paths are resolved against the agent's working directory. Defaults to the agent's working directory when omitted. Supports `${env.VAR}` (canonical), plus `~` and shell-style `$VAR`/`${VAR}` expansion ([details](../../configuration/overview/index.md#variable-expansion-in-config-fields)). | -| `instruction` | string | Custom instructions injected into the agent's context. | -| `version` | string | Package reference for [auto-installing](../../configuration/tools/index.md#auto-installing-tools) the command binary. | - -> [!TIP] -> **Auto-installation** -> -> If the `command` is not in your `PATH`, Docker Agent looks it up in the [aqua registry](https://github.com/aquaproj/aqua-registry) and installs it for you. Use `version: "false"` to opt out, or set `DOCKER_AGENT_AUTO_INSTALL=false` globally. See [Auto-Installing Tools](../../configuration/tools/index.md#auto-installing-tools). - -## Remote MCP (Streamable HTTP / SSE) - -Connect to MCP servers over the network. OAuth flows (including [Dynamic Client Registration](https://datatracker.ietf.org/doc/html/rfc7591)) are handled automatically — Docker Agent opens your browser when authentication is required and caches tokens for subsequent sessions. Tokens are refreshed silently when they expire or are revoked server-side; if a silent refresh is not possible, the OAuth prompt reappears on the next message. - -```yaml -toolsets: - - type: mcp - remote: - url: "https://mcp.linear.app/mcp" - transport_type: "streamable" # or "sse" for legacy servers - headers: - Authorization: "Bearer ${env.LINEAR_TOKEN}" - # Optional: allow OAuth helper requests to reach private/internal IPs. - allow_private_ips: false - tools: ["search_issues", "create_issue"] -``` - -| Property | Type | Description | -| ----------------------- | ------- | ----------- | -| `remote.url` | string | Base URL of the MCP server. | -| `remote.transport_type` | string | `streamable` or `sse`. | -| `remote.headers` | object | HTTP headers sent on every request. Values support `${env.VAR}` and `${headers.NAME}` placeholders, resolved per request. See [Remote MCP Servers](../../features/remote-mcp/index.md#per-request-header-template-expansion) for details. | -| `remote.oauth` | object | Explicit OAuth client credentials for servers that don't support DCR. See [Remote MCP Servers](../../features/remote-mcp/index.md#oauth-for-servers-without-dynamic-client-registration). | -| `allow_private_ips` | boolean | Permit remote MCP OAuth helper requests to dial non-public IP addresses. Use only for trusted internal servers. | - -For a curated list of public remote MCP endpoints (Linear, GitHub, Vercel, Notion, …) and full OAuth configuration details, see [Remote MCP Servers](../../features/remote-mcp/index.md). - -## MCP Prompts - -MCP servers can expose **prompts** — named, parameterized templates that the server provides via the `/prompts` endpoint. Docker Agent discovers these at toolset startup and registers them as **slash commands** in the TUI, so you can invoke them directly from the input box. - -```text -# Type / to see available prompts alongside built-in commands -/review # invoke an MCP prompt named "review" -/summarize My text here # invoke with the first argument filled in -``` - -**How it works:** - -- Each MCP prompt appears in the command palette (accessible via Ctrl+K) under the **MCP Prompts** category. -- Typing `/` in the input box invokes the prompt immediately. -- If the prompt declares arguments and you provide text after the slash command, that text is mapped to the first declared argument. -- If a required argument is missing, Docker Agent opens the argument input dialog before running the prompt. -- When no argument is needed or all required arguments are supplied, the prompt runs immediately. - -> [!NOTE] -> MCP prompt discovery requires a YAML-declared `mcp` toolset. Prompts from servers activated through the [Docker MCP Catalog](../../tools/mcp-catalog/index.md) (`ref: docker:`) are not currently surfaced. - -## Embedded Resources - -MCP tool results can include embedded resources — images, PDFs, and text files returned directly in the tool response. Docker Agent preserves these as attachments and forwards them to the model as native content blocks: - -- **Anthropic** — images become `image` blocks in the `tool_result`; PDFs and other documents become `document` blocks. -- **OpenAI** — images are forwarded as `input_image` data URIs; PDFs as `input_file` data URIs in the tool result content. -- **Bedrock** and **Gemini** — receive equivalent provider-native representations. - -No configuration is required. When an MCP server returns an embedded resource alongside its text output, the resource is automatically attached and sent to the model on the next turn. This is useful for MCP servers that generate charts, export PDFs, or return binary data as part of their responses. - -## Reusable Definitions (`mcps:`) - -Repeated MCP server configurations can be hoisted into the top-level `mcps:` section and referenced by name with `{type: mcp, ref: }`: - -```yaml -mcps: - github: - remote: - url: https://api.githubcopilot.com/mcp - transport_type: sse - playwright: - command: npx - args: ["-y", "@modelcontextprotocol/server-playwright"] - -agents: - root: - model: openai/gpt-5 - toolsets: - - type: mcp - ref: github - - type: mcp - ref: playwright -``` - -See [Reusable MCP Servers](../../configuration/overview/index.md#reusable-mcp-servers-mcps) for the full reference. - -## Common Options - -These properties apply to every MCP toolset regardless of flavour: - -### Tool filtering - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - tools: ["list_issues", "create_issue", "get_pull_request"] -``` - -Whitelisting tools improves model accuracy — fewer choices means less confusion. - -### Deferred loading - -Skip the toolset's startup cost until its tools are actually called: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - defer: true - # Or defer specific tools within a toolset: - - type: mcp - ref: docker:slack - defer: ["list_channels", "search_messages"] -``` - -### Custom instructions - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - instruction: | - Use these tools to manage GitHub issues. - Always check for existing issues before creating new ones. - Label new issues with 'triage' by default. -``` - -### TOON-encoded outputs - -Re-encode verbose JSON outputs as the compact [TOON](https://github.com/alpkeskin/gotoon) format to save context budget. Typically yields 30–60% smaller payloads on list/search tools. - -`toon` is a regex string that is matched against tool names. Any tool whose name matches the pattern has its JSON output transparently re-encoded as TOON before it is shown to the model. The re-encoding reduces schema verbosity, which is especially useful when a model struggles with large or repetitive tool output. - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - toon: ".*" # toonify every tool from this server - - type: mcp - command: my-server - toon: "list_.*,get_.*" # only toonify list_/get_ tools -``` - -The value is a comma-separated list of regexes (or a single regex). A tool name must match at least one pattern to be re-encoded. Setting `toon: ".*"` re-encodes all tools from that toolset. - -See [`examples/github-toon.yaml`](https://github.com/docker/docker-agent/blob/main/examples/github-toon.yaml) for a practical example using the GitHub MCP server. - -### Per-toolset model routing - -Process tool results from this toolset with a different (typically cheaper / faster) model. The override is one-shot — subsequent turns return to the agent's primary model: - -```yaml -toolsets: - - type: mcp - ref: docker:github-official - model: openai/gpt-4o-mini -``` - -See [Per-Toolset Model Routing](../../configuration/tools/index.md#per-toolset-model-routing). - -### Lifecycle (auto-restart, profiles) - -Local stdio and remote MCP servers are supervised: crashed servers reconnect automatically with exponential backoff. **Remote** MCP servers (Streamable HTTP / SSE) also reconnect after idle/clean connection closes — services like Notion and Linear periodically close idle connections, and Docker Agent reconnects transparently. Tune the policy with the `lifecycle` block: - -```yaml -toolsets: - - type: mcp - ref: docker:duckduckgo - lifecycle: - profile: resilient # default; auto-restart with backoff - - type: mcp - command: docker - args: ["mcp", "gateway"] - lifecycle: - profile: strict # fail-fast: required, no retries -``` - -See [Toolset Lifecycle](../../configuration/tools/index.md#toolset-lifecycle) for all profiles and tuning knobs, and [`/toolset-restart`](../../features/tui/index.md) to force a reconnect from the TUI. - -## Combined Example - -```yaml -mcps: - github: - remote: - url: https://api.githubcopilot.com/mcp - transport_type: sse - -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Full-featured developer assistant - instruction: You are an expert developer. - toolsets: - # Docker MCP catalog entry - - type: mcp - ref: docker:duckduckgo - - # Reusable definition from the top-level mcps: block - - type: mcp - ref: github - tools: ["list_issues", "create_issue"] - toon: "list_.*" - - # Local stdio server with auto-install - - type: mcp - command: gopls - version: "golang/tools@v0.21.0" - args: ["mcp"] - - # Remote MCP with OAuth (handled automatically) - - type: mcp - remote: - url: "https://mcp.linear.app/mcp" - transport_type: "streamable" - instruction: Use Linear for issue tracking. -``` - -> [!WARNING] -> **Toolset order matters** -> -> If multiple toolsets provide a tool with the same name, the first one wins: the duplicate from the later toolset is ignored and a warning identifies both toolsets. Order your toolsets intentionally. To keep both tools callable, give the MCP toolset a unique `name:` (its tools are then exposed as `_`) or restrict the overlapping toolset with its `tools:` filter. - -## See Also - -- [Tool Configuration](../../configuration/tools/index.md) — full reference for every toolset type, plus shared options (lifecycle, TOON, model routing, …). -- [Reusable MCP Servers](../../configuration/overview/index.md#reusable-mcp-servers-mcps) — the top-level `mcps:` block. -- [Remote MCP Servers](../../features/remote-mcp/index.md) — catalog of public remote MCP endpoints + OAuth recipes. -- [MCP Mode](../../features/mcp-mode/index.md) — expose your own agents as MCP tools to Claude Desktop, Claude Code, etc. -- [Auto-Installing Tools](../../configuration/tools/index.md#auto-installing-tools) — automatic installation of MCP server binaries. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/memory/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/memory/index.md deleted file mode 100644 index 1e5671a304ea..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/memory/index.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: "Memory Tool" -description: "Persistent key-value storage backed by SQLite for cross-session recall." -keywords: docker agent, ai agents, tools, toolsets, memory tool -linkTitle: "Memory" -weight: 100 -canonical: https://docs.docker.com/ai/docker-agent/tools/memory/ ---- - -_Persistent key-value storage backed by SQLite for cross-session recall._ - -## Overview - -The memory tool provides persistent key-value storage backed by SQLite. Data survives across sessions, allowing agents to remember facts, user preferences, project context, and past decisions. Memories can be organized with categories and searched by keyword. - -By default, the database is stored at `~/.cagent/memory//memory.db`, where `` is derived from the loaded configuration (typically the YAML file name) and falls back to `default` when unavailable. When the agent is loaded from an OCI reference (e.g. `docker/my-agent:latest`), characters that are reserved in filesystem paths (such as `:`) are sanitised in the `` segment — the agent's display name elsewhere is unchanged. Agents declared in the same configuration share this database by default; set an explicit `path` per toolset to isolate them. - -## Available Tools - -| Tool | Description | -| ----------------- | -------------------------------------------------------------------------------- | -| `add_memory` | Store a new memory with optional category | -| `get_memories` | Retrieve all stored memories | -| `delete_memory` | Delete a specific memory by ID | -| `search_memories` | Search memories by keywords and/or category (more efficient than `get_memories`) | -| `update_memory` | Update an existing memory's content and/or category by ID | - -## Configuration - -```yaml -toolsets: - - type: memory -``` - -### Options - -| Property | Type | Default | Description | -| -------- | ------ | ----------------------------------------- | -------------------------------- | -| `path` | string | `~/.cagent/memory//memory.db` | Path to the SQLite database file | - -### Custom Database Path - -```yaml -toolsets: - - type: memory - path: ./agent_memory.db -``` - -## Categories - -Memories support an optional `category` field for organization and filtering. Common categories include: - -- `preference` — User preferences and settings -- `fact` — Factual information about the project or user -- `project` — Project-specific context -- `decision` — Past decisions and their rationale - -> [!TIP] -> Memory is especially useful for long-running assistants that need to recall information across conversations — like coding preferences, project conventions, or context discovered during previous sessions. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/model-picker/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/model-picker/index.md deleted file mode 100644 index 0c0d4613021c..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/model-picker/index.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: "Model Picker Tool" -description: "Let the agent pick between several models per turn." -keywords: docker agent, ai agents, tools, toolsets, model picker tool -linkTitle: "Model Picker" -weight: 200 -canonical: https://docs.docker.com/ai/docker-agent/tools/model-picker/ ---- - -_Let the agent pick between several models per turn._ - -## Overview - -The model picker tool gives an agent the ability to dynamically choose which model to use for each turn of the conversation. This is useful when you want the agent to route different types of requests to different models — for example, using a fast, inexpensive model for simple queries and a more capable model for complex reasoning tasks. - -## Configuration - -```yaml -toolsets: - - type: model_picker - models: - - openai/gpt-5-mini - - anthropic/claude-sonnet-4-5 - - openai/gpt-5 -``` - -### Options - -| Property | Type | Required | Description | -| -------- | -------------- | -------- | ------------------------------------------------------------ | -| `models` | array[string] | ✓ | List of model references the agent can choose from. Use `provider/model` format. | - -## How It Works - -When the model picker toolset is enabled, the agent gets two tools: `change_model` to switch to one of the configured models, and `revert_model` to return to its default model. The agent decides which model to use based on the complexity of the task, cost considerations, or other factors you describe in its instruction. - -## Example - -```yaml -agents: - root: - model: openai/gpt-5-mini # Default model - instruction: | - You are a helpful assistant. For simple questions, use gpt-5-mini. - For complex reasoning or coding tasks, switch to claude-sonnet-4-5 or gpt-5. - toolsets: - - type: model_picker - models: - - openai/gpt-5-mini - - anthropic/claude-sonnet-4-5 - - openai/gpt-5 -``` - -> [!TIP] -> **Cost optimization** -> -> The model picker tool is particularly useful for cost optimization: let the agent use a cheap model by default and only escalate to expensive models when necessary. - -## Tool Interface - -The toolset exposes two tools: - -### `change_model` - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | --------------------------------------------------------------------------- | -| `model` | string | ✓ | The model to switch to. Must be one of the configured models. | - -### `revert_model` - -Takes no parameters. Reverts the agent to its original/default model. - -The switch takes effect immediately: the next inference call — including the remainder of the current agentic loop — uses the new model. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/open-url/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/open-url/index.md deleted file mode 100644 index b2a97dd44b36..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/open-url/index.md +++ /dev/null @@ -1,95 +0,0 @@ ---- -title: "Open URL Tool" -description: "Open a fixed URL in the user's default browser." -keywords: docker agent, ai agents, tools, toolsets, open url tool -linkTitle: "Open URL" -weight: 40 -canonical: https://docs.docker.com/ai/docker-agent/tools/open-url/ ---- - -_Open a fixed URL in the user's default browser._ - -## Overview - -The `open_url` toolset exposes a single, argument-less tool that opens a URL -baked into the toolset definition in the user's default browser. The model -never supplies the URL — it just calls the tool by name. Launching the browser -is cross-platform: Docker Agent uses `open` on macOS, `xdg-open` on Linux, and -`rundll32` on Windows. - -> [!NOTE] -> **When to Use** -> -> - Letting an agent open a dashboard, documentation page, or deep link on demand -> - Deep-linking into a desktop app via a custom URI scheme (e.g. `docker-desktop://`) -> - Any "take me there" action where the destination is fixed and known up front - -## Configuration - -```yaml -agents: - assistant: - model: openai/gpt-4o - description: Assistant that can open the dashboard - instruction: When the user asks to see the dashboard, call open_dashboard. - toolsets: - - type: open_url - name: open_dashboard - url: https://example.com/dashboard -``` - -## Properties - -| Property | Type | Required | Description | -| -------- | ------ | -------- | ---------------------------------------------------------------------------------------------------- | -| `url` | string | ✓ | URL to open. Supports `${env.VAR}` interpolation. Any scheme the OS can dispatch is allowed. | -| `name` | string | ✗ | Tool name the agent references. Defaults to `open_url`. Use a descriptive name when configuring several. | - -## Multiple URLs - -Add one toolset entry per destination, each with its own `name`: - -```yaml -toolsets: - - type: open_url - name: open_dashboard - url: https://example.com/dashboard - - type: open_url - name: open_docs - url: https://docs.example.com/${env.DOCS_VERSION} -``` - -## URL Interpolation - -The `url` field supports `${env.VAR}` placeholders, expanded at call time -against the runtime environment: - -```yaml -toolsets: - - type: open_url - name: open_docs - url: https://docs.example.com/${env.DOCS_VERSION} -``` - -## Custom URI Schemes - -Any scheme the operating system knows how to dispatch works, including deep -links into desktop applications: - -```yaml -toolsets: - - type: open_url - name: open_in_docker_desktop - url: docker-desktop://dashboard/apps -``` - -## Limitations - -- The URL must include a scheme (e.g. `https://`); bare paths are rejected. -- URLs that look like a command-line flag (starting with `-`) are refused to - prevent argument injection into the platform `open` helper. -- The tool opens the URL on the **host** running Docker Agent; in headless or - remote environments where no browser/launcher is available, the call fails - gracefully and reports the error to the agent. - -See [`examples/open_url.yaml`](https://github.com/docker/docker-agent/blob/main/examples/open_url.yaml) for a complete configuration. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/openapi/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/openapi/index.md deleted file mode 100644 index 56c0c30561cc..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/openapi/index.md +++ /dev/null @@ -1,83 +0,0 @@ ---- -title: "OpenAPI Tool" -description: "Automatically generate tools from an OpenAPI specification." -keywords: docker agent, ai agents, tools, toolsets, openapi tool -linkTitle: "OpenAPI" -weight: 230 -canonical: https://docs.docker.com/ai/docker-agent/tools/openapi/ ---- - -_Automatically generate tools from an OpenAPI specification._ - -## Overview - -The OpenAPI tool fetches an OpenAPI 3.x specification from a URL and creates one tool per API operation. Each endpoint's parameters, request body, and description are translated into a callable tool that the agent can invoke directly. - -## Configuration - -```yaml -toolsets: - - type: openapi - url: "https://petstore3.swagger.io/api/v3/openapi.json" -``` - -### With custom headers - -Pass custom headers to every HTTP request made by the generated tools (for example, for authentication): - -```yaml -toolsets: - - type: openapi - url: "https://api.example.com/openapi.json" - headers: - Authorization: "Bearer ${env.API_TOKEN}" - X-Custom-Header: "my-value" -``` - -### Custom timeout - -Override the default 30-second HTTP timeout (applies both to fetching the spec and to the generated tool calls): - -```yaml -toolsets: - - type: openapi - url: "https://api.example.com/openapi.json" - timeout: 60 -``` - -### Reaching internal services - -By default the OpenAPI tool refuses connections to non-public IP addresses, blocking SSRF attempts even when DNS resolves an otherwise-public host to an internal range. Opt in with `allow_private_ips` when the spec or its `servers` entries legitimately target localhost or your internal network: - -```yaml -toolsets: - - type: openapi - url: "http://localhost:8080/openapi.json" - allow_private_ips: true -``` - -## Properties - -| Property | Type | Required | Description | -| ------------------- | ----------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| `url` | string | ✓ | URL of the OpenAPI specification (JSON format). Supports `${env.VAR}` interpolation. | -| `headers` | map[string]string | ✗ | Custom HTTP headers sent with every request — both the spec fetch and every generated tool call. Values support `${env.VAR}` and `${headers.NAME}` placeholders (the latter forwards a header from the caller's incoming request when docker agent is exposed as a server). | -| `timeout` | int | ✗ | HTTP client timeout in seconds (default: `30`). Applies to both the spec fetch and the generated tools' requests. | -| `allow_private_ips` | boolean | ✗ | Opt in to dialling **non-public** IP addresses (loopback, RFC1918, link-local — including the cloud-metadata endpoint at `169.254.169.254` — multicast and the unspecified address). Set to `true` only when the spec or its servers legitimately target internal services. By default such addresses are refused at dial time, after DNS resolution, so DNS rebinding cannot bypass the check. | - -## How it works - -1. The spec is fetched from the configured `url` at startup. -2. Each operation (GET, POST, PUT, …) becomes a separate tool named after its `operationId` (or `method_path` when no `operationId` is set). -3. Path and query parameters are exposed as tool parameters. Request body properties are prefixed with `body_`. -4. Read-only operations (GET, HEAD, OPTIONS) are annotated accordingly. -5. Responses are returned as text; errors include the HTTP status code. - -## Limits - -- The OpenAPI spec must be **10 MB or less**. -- Individual API responses are truncated at **1 MB**. - -## Example - -See the full [Pet Store example](https://github.com/docker/docker-agent/blob/main/examples/openapi-petstore.yaml) for a working agent configuration. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/plan/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/plan/index.md deleted file mode 100644 index 3f27b0198939..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/plan/index.md +++ /dev/null @@ -1,166 +0,0 @@ ---- -title: "Plan Tool" -description: "Shared persistent scratchpad for multi-agent collaboration." -keywords: docker agent, ai agents, tools, toolsets, plan tool -linkTitle: "Plan" -weight: 150 -canonical: https://docs.docker.com/ai/docker-agent/tools/plan/ ---- - -_Shared persistent scratchpad for multi-agent collaboration._ - -## Overview - -The plan tool gives agents a shared, persistent scratchpad of named documents. Any agent in a multi-agent config that loads the `plan` toolset can read and write the same plans, and those plans survive across sessions. This makes it straightforward to wire a planner agent that sketches work and one or more executor agents that consume it without any custom tool wiring. - -Plans are stored as JSON files in the Docker Agent data directory (`~/.cagent/plans/` by default). Agents that share a process serialize on a single mutex, and every write or delete additionally holds an advisory lock on a sentinel file in the plans directory, so writers in *separate* Docker Agent processes are serialized too: concurrent edits can never silently overwrite each other, and a stale revision always fails with a deterministic version conflict. Writes are atomic (temp file + rename), so a reader never observes partial content. - -## Configuration - -```yaml -toolsets: - - type: plan -``` - -No additional options are required. All agents that include `type: plan` in their toolsets share the same plans. - -## Available Tools - -| Tool | Description | -| ----------------------- | ------------------------------------------------------------------------------------------------- | -| `write_plan` | Create or update a shared plan by name. Replaces the entire plan content — read it first to preserve what you want to keep. Each write bumps the revision number. | -| `read_plan` | Read a shared plan by name, including its title, content, author, status, revision number, and last-updated timestamp. | -| `list_plans` | List all shared plans with their name, title, author, status, revision, and last-updated timestamp. | -| `delete_plan` | Delete a shared plan by name. | -| `update_plan_from_file` | Create or update a plan, taking the new content from a file on disk instead of inline. Use it with `export_plan_to_file` to edit a large plan without re-sending its whole body. | -| `export_plan_to_file` | Write a plan's content to a file. The content goes to disk and is **not** returned as tool output, so materialising a plan costs no tokens. | -| `set_plan_status` | Set a plan's free-form status without rewriting its body. The plan must already exist. | -| `get_plan_status` | Read a plan's status and current revision without fetching its body. | - -### Cheap edits with file-based revisions - -Re-sending a whole plan on every revision is expensive. The file-based tools let -an agent edit a plan without paying input-token cost for its body: - -1. `export_plan_to_file` writes the current plan content to a path. The content - is written to disk and is **not** returned. -2. The agent edits that file in place with its filesystem tools. -3. `update_plan_from_file` commits the file's new contents as the next revision. - -### Free-form status - -Each plan carries a free-form `status` string. There is no fixed vocabulary: -define your own in the system prompt (e.g. `idle`, `in-progress`, `blocked`, -`done`, `canceled`). Read and write it independently of the body with -`get_plan_status` and `set_plan_status`, or pass `status` to `write_plan` and -`update_plan_from_file`. The TUI surfaces the status next to the plan title. - -### Optimistic locking - -When several sessions edit the same plan, concurrent writes could silently -overwrite each other. Every read returns a `revision` number; pass the value you -last read as `last_known_revision` to `write_plan`, `update_plan_from_file`, -`set_plan_status`, or `delete_plan`. If the plan changed since (its current -revision no longer matches), the write is rejected with a version-conflict -error and the caller should re-read the plan and retry. The revision check and -the write happen under the storage's cross-process file lock, so the conflict -is detected reliably even when the competing writer runs in a different Docker -Agent process. Omit `last_known_revision` to write unconditionally (last -writer wins). - -### Plan Names - -Plan names must match the pattern `[a-z0-9][a-z0-9_-]*` (lowercase letters, digits, `-`, `_`). This is enforced structurally so two different inputs can never collapse onto the same file and path-traversal is impossible by construction. - -### Plan Fields - -Each plan document contains: - -| Field | Description | -| ---------- | --------------------------------------------------------- | -| `name` | The plan's unique slug name | -| `title` | A short human-readable title (optional) | -| `content` | The full Markdown or free-form plan text | -| `author` | Free-form label identifying who last wrote the plan | -| `status` | Free-form lifecycle label (optional), e.g. `in-progress` | -| `revision` | Monotonically increasing version counter, bumped on every write | -| `updatedAt`| ISO 8601 timestamp of the last write | - -## Example - -Two agents collaborate on a shared plan — the architect drafts it and the builder refines it: - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Coordinator - instruction: | - Route work between the architect and the builder. - handoffs: [architect, builder] - - architect: - model: anthropic/claude-sonnet-4-5 - description: Drafts high-level plans - instruction: | - Use list_plans and read_plan to inspect existing plans, then write_plan - to create or revise one. Always read before writing. When done, hand off - to the builder. - toolsets: - - type: plan - handoffs: [builder] - - builder: - model: openai/gpt-4o - description: Adds implementation steps to plans - instruction: | - Read the architect's plan with read_plan, then use write_plan to append - concrete implementation steps. Always read before writing. When done, - hand off back to root. - toolsets: - - type: plan - handoffs: [root] -``` - -See [`examples/shared_plan.yaml`](https://github.com/docker/docker-agent/blob/main/examples/shared_plan.yaml) for a complete working example. - -## Error Handling - -- `read_plan` returns a distinct "not found" error when a plan does not exist, as opposed to any other I/O error, so callers can tell "plan missing" from "plan unreadable." -- `list_plans` skips corrupt entries but reports them in a `warnings` field so an agent can detect and recover from a bad state (e.g., by calling `delete_plan`). -- `delete_plan` can remove a corrupt plan to recover from a bad state. - -## Managing plans from the host - -Shared plans can also be inspected and managed outside a session with the [`docker agent plans`](../../features/cli/index.md#docker-agent-plans) command group: list, get, create, update, set status, export, and delete — with the same optimistic-locking semantics as the tools (`--expected-version` guards a write and a stale version fails with exit code 3; `--force` writes unconditionally). Session plans (the per-session "draft, review, execute" plan) can be listed, read, and exported through the same commands but stay owned by their session and cannot be mutated from the host. - -```bash -$ docker agent plans list -$ docker agent plans get release > plan.md -$ docker agent plans update release --file ./plan.md --expected-version 1 -``` - -### The `/plans` browser in the TUI - -Inside the full-screen TUI, the `/plans` slash command (also in the Ctrl+K command palette) opens a plan browser over the same store the agents use, so changes made by agents mid-session appear immediately. The list shows every shared plan plus the current session's [session plan](../session_plan/index.md), with each plan's scope, identity (name, or session ID for the session plan), status, version (`-` for the unversioned session plan), last update time, and title. - -Keybindings: - -| Key | Action | -| --- | ------ | -| /, mouse | Navigate; Enter or double-click opens a detail view with the full metadata and scrollable markdown content | -| / | Filter by name, title, status, or scope (Esc leaves filter mode) | -| r | Refresh from storage | -| x | Export the selected plan to `.md` (shared) or `session-plan-.md` (session) in the session's working directory. An existing file is never overwritten — the export fails with a notification instead | -| s | Set a shared plan's free-form status via a small input dialog | -| e | Edit a shared plan's content in `$VISUAL`/`$EDITOR` | -| n | Create a new shared plan: pick a name, then draft the content in `$VISUAL`/`$EDITOR` (an empty draft aborts) | -| d | Delete a shared plan after a confirmation that names the plan and its version | -| Esc | Close the detail view / the browser | - -Every mutation is guarded by the version shown on screen (the same optimistic locking as `last_known_revision`): if an agent changed the plan in the meantime, the write is rejected, a notification reports the current version, the newer content is left intact and re-read into the browser, and an edit draft is kept in a temp file so nothing is lost. Session plans are read-only here — status, edit, and delete report why instead of attempting the write. The browser also refreshes live when agents in the same process write, re-status, or delete plans (and when this session's agent updates its session plan); in the lean TUI, which has no overlays, `/plans` is unavailable. - -> [!TIP] -> **Plan vs. Todo vs. Tasks** -> -> Use **plan** for shared, free-form documents that multiple agents collaborate on (design docs, requirements, work items). Use [todo](../todo/index.md) for lightweight in-session task lists. Use [tasks](../tasks/index.md) for a structured, persistent task database with priorities and dependencies. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/rag/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/rag/index.md deleted file mode 100644 index 0aa77a99350f..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/rag/index.md +++ /dev/null @@ -1,267 +0,0 @@ ---- -title: "RAG Tool" -description: "Give your agents access to document knowledge bases with background indexing, multiple retrieval strategies, and hybrid search." -keywords: docker agent, ai agents, tools, toolsets, rag tool -linkTitle: "RAG" -weight: 110 -canonical: https://docs.docker.com/ai/docker-agent/tools/rag/ -aliases: - - /ai/docker-agent/rag/ ---- - -_Give your agents access to document knowledge bases with background indexing, multiple retrieval strategies, and hybrid search._ - -## Overview - -The `rag` toolset lets agents search through your documents to find relevant information before responding. Knowledge bases are declared once at the top of the config under `rag:` and then referenced from any agent via `type: rag, ref: `. Docker Agent supports: - -- **Background indexing** — Files are indexed automatically and re-indexed on change -- **Multiple strategies** — Semantic embeddings, BM25 keyword search, and LLM-enhanced search -- **Hybrid search** — Combine strategies with result fusion for best results -- **Reranking** — Re-score results with specialized models for improved relevance - -RAG is the strategy to reach for when a document collection is too large to inline directly, or gets queried repeatedly across turns/sessions — see [Choosing a Large-Input Strategy](../../guides/headless/index.md#choosing-a-large-input-strategy) for how it compares to `@`/`/attach` attachments and prompt files. - -## Quick Start - -```yaml -rag: - my_docs: - tool: - description: "Technical documentation" - docs: [./documents, ./some-doc.md] - strategies: - - type: chunked-embeddings - embedding_model: openai/text-embedding-3-small - database: ./docs.db - vector_dimensions: 1536 - -agents: - root: - model: openai/gpt-4o - instruction: | - You have access to a knowledge base. Use it to answer questions. - toolsets: - - type: rag - ref: my_docs -``` - -## Retrieval Strategies - -### Chunked Embeddings (Semantic Search) - -Uses embedding models to find semantically similar content. Best for understanding intent, synonyms, and paraphrasing. - -```yaml -strategies: - - type: chunked-embeddings - embedding_model: openai/text-embedding-3-small - database: ./vector.db - vector_dimensions: 1536 - similarity_metric: cosine_similarity - threshold: 0.5 - limit: 10 - embedding_batch_size: 50 - chunking: - size: 1000 - overlap: 100 -``` - -### Semantic Embeddings (LLM-Enhanced) - -Uses an LLM to generate semantic summaries of each chunk before embedding, capturing meaning and intent. Best for code search and understanding implementations. - -```yaml -strategies: - - type: semantic-embeddings - embedding_model: openai/text-embedding-3-small - vector_dimensions: 1536 - chat_model: openai/gpt-4o-mini - database: ./semantic.db - ast_context: true # include AST metadata - chunking: - size: 1000 - code_aware: true # AST-aware chunking -``` - -> [!NOTE] -> **Trade-offs** -> -> Semantic embeddings provide higher quality retrieval but slower indexing (LLM call per chunk) and additional API costs. - -### BM25 (Keyword Search) - -Traditional keyword matching using the BM25 algorithm. Best for exact terms, technical jargon, and code identifiers. - -```yaml -strategies: - - type: bm25 - database: ./bm25.db - k1: 1.5 # term frequency saturation - b: 0.75 # length normalization - threshold: 0.3 - limit: 10 - chunking: - size: 1000 - overlap: 100 -``` - -## Hybrid Search - -Combine multiple strategies for best results. Strategies run in parallel and results are fused together: - -```yaml -rag: - hybrid: - docs: [./docs] - strategies: - - type: chunked-embeddings - embedding_model: openai/text-embedding-3-small - database: ./vector.db - vector_dimensions: 1536 - limit: 20 - chunking: { size: 1000, overlap: 100 } - - type: bm25 - database: ./bm25.db - limit: 15 - chunking: { size: 1000, overlap: 100 } - results: - fusion: - strategy: rrf # Reciprocal Rank Fusion - k: 60 - deduplicate: true - limit: 5 -``` - -## Fusion Strategies - -| Strategy | Best For | Description | -| ---------- | --------------------------------- | ------------------------------------------------------------------ | -| `rrf` | General use (recommended) | Reciprocal Rank Fusion — rank-based, no score normalization needed | -| `weighted` | Known performance characteristics | Weight strategies differently (e.g., embeddings: 0.7, BM25: 0.3) | -| `max` | Same scoring scale | Takes the maximum score from any strategy | - -## Reranking - -Re-score retrieved documents with a specialized model to improve relevance: - -```yaml -results: - reranking: - model: openai/gpt-4o-mini - top_k: 10 # only rerank top 10 - threshold: 0.3 # minimum score after reranking - criteria: | - Prioritize official documentation over blog posts. - Prefer recent information and practical examples. - limit: 5 -``` - -Supported reranking providers: **DMR** (native `/rerank` endpoint), **OpenAI**, **Anthropic**, **Gemini**. - -## Code-Aware Chunking - -For source code, enable AST-based chunking to keep functions and methods intact: - -```yaml -chunking: - size: 2000 - code_aware: true # Uses tree-sitter for AST-based chunking -``` - -> [!NOTE] -> **Language Support** -> -> Currently supports Go (`.go`) files. More languages will be added. Falls back to plain text chunking for unsupported file types. - -## Debugging RAG - -Enable debug logging to see retrieval details: - -```bash -$ docker agent run config.yaml --debug --log-file debug.log -``` - -Look for log tags: `[RAG Manager]`, `[Chunked-Embeddings Strategy]`, `[BM25 Strategy]`, `[RRF Fusion]`, `[Reranker]`. - -**Permanent model errors abort early.** If the embedding model, semantic-LLM model, or reranking model returns a permanent error (HTTP 400, 401, 404, or 429 — invalid config, bad auth, unknown model, or rate limit), Docker Agent treats the model configuration as invalid and stops immediately rather than retrying doomed requests: - -- **Indexing** — the entire indexing run is aborted after the first permanent failure (including 429). The error is surfaced in the logs so you know immediately if a model name or API key is wrong, rather than silently producing incomplete results. -- **Reranking** — a permanent error (including 429) permanently disables the reranker for the lifetime of the manager. Subsequent queries fall back to un-reranked results. Only transient errors (5xx, timeouts) fall back and retry on the next query. - -> [!TIP] -> **Examples** -> -> See the [RAG examples](https://github.com/docker/docker-agent/tree/main/examples/rag) in the GitHub repo for complete, runnable configurations. - -## Configuration Reference - -### Top-Level RAG Fields - -| Field | Type | Default | Description | -| ------------- | -------- | ------- | -------------------------------------------------------------- | -| `docs` | []string | — | Document paths/directories (shared across strategies) | -| `description` | string | — | Human-readable description of this RAG source | -| `respect_vcs` | boolean | `true` | Respect `.gitignore` files when indexing documents | -| `strategies` | []object | — | Array of retrieval strategy configurations | -| `results` | object | — | Post-processing: fusion, reranking, deduplication, final limit | - -### Chunked-Embeddings Strategy - -| Field | Type | Default | Description | -| --------------------------- | ------ | ------------------- | ------------------------------------------------------------ | -| `embedding_model` | string | — | **Required.** Embedding model reference | -| `database` | string | — | Path to local SQLite database | -| `vector_dimensions` | int | — | Embedding dimensions (e.g., 1536 for text-embedding-3-small) | -| `similarity_metric` | string | `cosine_similarity` | Similarity metric | -| `threshold` | float | `0.5` | Minimum similarity score (0–1) | -| `limit` | int | `5` | Max results from this strategy | -| `embedding_batch_size` | int | `50` | Chunks per embedding request | -| `max_embedding_concurrency` | int | `3` | Max concurrent embedding requests | -| `chunking.size` | int | `1500` | Chunk size in characters (`4000` when `code_aware` is set) | -| `chunking.overlap` | int | `75` | Overlap between chunks in characters | -| `chunking.code_aware` | bool | `false` | AST-based chunking (Go files only) | - -### Semantic-Embeddings Strategy - -| Field | Type | Default | Description | -| -------------------------- | ------ | ---------- | ------------------------------------------------------------------ | -| `embedding_model` | string | — | **Required.** Embedding model reference | -| `chat_model` | string | — | **Required.** LLM for generating semantic summaries | -| `vector_dimensions` | int | — | **Required.** Embedding dimensions | -| `database` | string | — | Path to local SQLite database | -| `semantic_prompt` | string | (built-in) | Custom prompt template (`${path}`, `${content}`, `${ast_context}`) | -| `ast_context` | bool | `false` | Include tree-sitter AST metadata in prompts | -| `threshold` | float | `0.5` | Minimum similarity score (0–1) | -| `limit` | int | `5` | Max results | -| `max_indexing_concurrency` | int | `3` | Max concurrent file indexing | -| `chunking.size` | int | `1500` | Chunk size in characters (`4000` when `code_aware` is set) | -| `chunking.overlap` | int | `75` | Overlap between chunks | -| `chunking.code_aware` | bool | `false` | AST-based chunking | - -### BM25 Strategy - -| Field | Type | Default | Description | -| ------------------ | ------ | ------- | ----------------------------------------------- | -| `database` | string | — | Path to local SQLite database | -| `k1` | float | `1.5` | Term frequency saturation (1.2–2.0 recommended) | -| `b` | float | `0.75` | Length normalization (0–1) | -| `threshold` | float | `0.0` | Minimum BM25 score | -| `limit` | int | `5` | Max results | -| `chunking.size` | int | `1500` | Chunk size in characters | -| `chunking.overlap` | int | `75` | Overlap between chunks | - -### Results (Post-Processing) - -| Field | Type | Default | Description | -| --------------------- | ------ | ------- | ----------------------------------------------------------- | -| `fusion.strategy` | string | `rrf` | Fusion method: `rrf`, `weighted`, or `max` | -| `fusion.k` | int | `60` | RRF rank constant | -| `deduplicate` | bool | `true` | Remove duplicate results | -| `limit` | int | `15` | Final number of results | -| `include_score` | bool | `false` | Include relevance scores in results | -| `return_full_content` | bool | `false` | Return full document content instead of just matched chunks | -| `reranking.model` | string | — | Reranking model reference | -| `reranking.top_k` | int | (`limit`) | Only rerank top K results. Defaults to the results `limit` when set. | -| `reranking.threshold` | float | `0.5` | Minimum relevance score after reranking | -| `reranking.criteria` | string | — | Custom relevance guidance for the reranking model | diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/scheduler/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/scheduler/index.md deleted file mode 100644 index 16635f7f77f2..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/scheduler/index.md +++ /dev/null @@ -1,96 +0,0 @@ ---- -title: "Scheduler Tool" -description: "Schedule instructions to run at a time or on a recurring interval." -keywords: docker agent, ai agents, tools, toolsets, scheduler tool, cron -linkTitle: "Scheduler" -weight: 135 -canonical: https://docs.docker.com/ai/docker-agent/tools/scheduler/ ---- - -_Schedule instructions to run at a time or on a recurring interval._ - -## Overview - -The scheduler toolset lets an agent make something happen at a chosen time or on a repeating cadence during a session. You give it an instruction and a schedule; when the schedule is due, the instruction is delivered back to the agent, which then carries out the action with its normal tools (`shell`, `api`, `fetch`, and so on). - -The scheduler does not run shell or API calls itself. When a schedule fires it injects the instruction into the agent loop via the runtime's recall mechanism — the same primitive [`background_jobs`](../background-jobs/index.md) uses to report completed work — and the agent decides how to act. This keeps every action under the agent's normal tools and permissions rather than adding a second, unattended -command runner. - -> [!NOTE] -> Schedules only fire while the session is running (interactive TUI or a server mode) and are not persisted across restarts. Scheduling requires a host that supports recall; if it does not, `create_schedule` returns an error. - -## Configuration - -```yaml -toolsets: - - type: scheduler -``` - -No configuration options. - -## Tools - -| Tool | Description | -| --- | --- | -| `create_schedule` | Register an instruction to run at a time or interval. | -| `list_schedules` | List active schedules with their id, spec, and next fire time. | -| `cancel_schedule` | Remove a schedule by id. | - -### `create_schedule` - -| Parameter | Required | Description | -| --- | --- | --- | -| `prompt` | Yes | The instruction to deliver to the agent when the schedule fires. | -| `when` | Yes | When to fire (see [Schedule specs](#schedule-specs)). | -| `name` | No | Optional human-readable label. | - -Returns the new schedule's id and its next fire time. - -### `cancel_schedule` - -| Parameter | Required | Description | -| --- | --- | --- | -| `id` | Yes | The id of the schedule to cancel (from `create_schedule` or `list_schedules`). | - -## Schedule specs - -The `when` argument accepts: - -| Form | Meaning | Example | -| --- | --- | --- | -| `in:` | One-shot, after a delay | `in:10m` | -| `at:` | One-shot, at an absolute future time | `at:2026-07-14T09:00:00Z` | -| `every:` | Recurring, at a fixed interval | `every:1h` | -| `minutely` / `hourly` / `daily` / `weekly` | Recurring preset intervals | `hourly` | - -Durations use Go's duration syntax (`30s`, `15m`, `2h`). Preset and `every:` intervals are measured from the schedule's creation time (for example `hourly` fires every hour after it is created), not aligned to wall-clock slots. - -> [!IMPORTANT] -> **Recurring schedules have a one-minute minimum.** Every fire injects a message into the agent loop and typically costs an LLM turn, so `every:` values below `1m` are rejected — a typo such as `every:1s` in place of `every:1h` would otherwise become a runaway token burn. One-shot schedules (`in:` / `at:`) are not restricted, since they fire once. - -## Example - -```yaml -agents: - root: - model: openai/gpt-5-mini - description: A monitoring assistant - instruction: | - Every 15 minutes, run `git fetch` and tell me if origin/main moved. - toolsets: - - type: scheduler - - type: shell -``` - -The agent calls: - -```text -create_schedule(prompt="Run git fetch and report if origin/main moved", when="every:15m") -``` - -Every 15 minutes it is reminded, runs the command with the `shell` tool, and reports back. - -> [!TIP] -> **When to use** -> -> Use the scheduler for recurring monitoring, timed one-shots, and unattended housekeeping loops during a long-running session. For work that should run immediately and be awaited, use [`background_jobs`](../background-jobs/index.md) instead. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/script/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/script/index.md deleted file mode 100644 index b4f912705517..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/script/index.md +++ /dev/null @@ -1,64 +0,0 @@ ---- -title: "Script Tool" -description: "Define custom shell scripts as named tools with typed parameters." -keywords: docker agent, ai agents, tools, toolsets, script tool -linkTitle: "Script" -weight: 30 -canonical: https://docs.docker.com/ai/docker-agent/tools/script/ ---- - -_Define custom shell scripts as named tools with typed parameters._ - -## Overview - -The script tool lets you define custom shell scripts as named tools. Unlike the generic [shell tool](../shell/index.md) where the agent writes the command, script tools execute predefined commands — ideal for exposing safe, well-scoped operations with descriptive names. - -## Configuration - -### Simple Scripts - -```yaml -toolsets: - - type: script - shell: - run_tests: - cmd: task test - description: Run the project test suite - lint: - cmd: task lint - description: Run the linter -``` - -### Scripts with Parameters - -Use `${param}` interpolation and JSON Schema to define typed arguments: - -```yaml -toolsets: - - type: script - shell: - deploy: - cmd: ./scripts/deploy.sh ${env} - description: Deploy to an environment - args: - env: - type: string - enum: [staging, production] - required: [env] -``` - -## Properties - -| Property | Type | Description | -| --------------------------------- | ------ | ---------------------------------------------------------- | -| `shell..cmd` | string | Shell command to execute (supports `${arg}` interpolation) | -| `shell..description` | string | Description shown to the model | -| `shell..args` | object | Parameter definitions (JSON Schema properties) | -| `shell..required` | array | Required parameter names | -| `shell..env` | object | Environment variables for this script | -| `shell..working_dir` | string | Working directory for script execution | - -> [!TIP] -> **Script vs. Shell** -> -> Use the [shell tool](../shell/index.md) when the agent needs to run arbitrary commands. Use the script tool when you want to expose specific, predefined operations with clear names and typed parameters — giving the agent less freedom but more safety. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/session_context/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/session_context/index.md deleted file mode 100644 index 9f241bb551db..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/session_context/index.md +++ /dev/null @@ -1,67 +0,0 @@ ---- -title: "Session Context Tool" -description: "Reference a previous session as context in the current one." -keywords: docker agent, ai agents, tools, toolsets, session context tool -linkTitle: "Session Context" -weight: 210 -canonical: https://docs.docker.com/ai/docker-agent/tools/session_context/ ---- - -_Reference a previous session as context, without manual export/import._ - -## Overview - -The `session_context` toolset lets an agent discover earlier sessions and pull one in as context for the current session. It removes the manual workaround of exporting a conversation to HTML and re-attaching it with an `@` mention. - -The tool surface is two read-only tools: - -| Tool | Description | -| --------------- | ------------------------------------------------------------------------------------------------------------ | -| `list_sessions` | List previous sessions (most recent first) with id, title, creation time and message count. | -| `read_session` | Return the transcript of a previous session, by id or by a relative reference like `-1`. | - -The session the agent is currently running in is never listed by `list_sessions` and cannot be read by `read_session` (a circular reference returns an error). - -## Configuration - -```yaml -toolsets: - - type: session_context -``` - -No configuration options. Both tools are read-only and operate against the same session store the runtime already uses for persistence. - -Restrict the toolset to a subset of tools the standard way: - -```yaml -# An agent that may browse but never pull a full transcript into context. -toolsets: - - type: session_context - tools: - - list_sessions -``` - -## Selecting a session - -`read_session` accepts either form: - -- A concrete id returned by `list_sessions`, e.g. `read_session("a1b2c3...")`. -- A relative reference: `-1` is the most recent session, `-2` the second most recent, and so on. Relative references resolve against the same ordering `list_sessions` uses (most recent first), excluding sub-sessions. - -## Transcript size - -A long session could overflow the current context window, so `read_session` caps the rendered transcript. When a transcript is larger than the budget, the oldest messages are dropped (the most recent are usually the most useful for continuing work) and a note records how many were omitted: - -```text -[12 earlier message(s) omitted to fit the context budget; showing the most recent 8] -``` - -## Notes - -- `list_sessions` defaults to 20 sessions and is capped at 100; pass `limit` to request fewer. -- `read_session` returns an error when the session is not found, when the reference cannot be resolved, or when it points at the current session. -- Both tools are read-only: they never modify, branch, or delete sessions. - -## Example - -See [`examples/session_context.yaml`](https://github.com/docker/docker-agent/blob/main/examples/session_context.yaml) for a complete working example. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/session_plan/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/session_plan/index.md deleted file mode 100644 index ea4c8e4970f0..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/session_plan/index.md +++ /dev/null @@ -1,134 +0,0 @@ ---- -title: "Session Plan Tool" -description: "Per-session plan tracker for the draft, review, execute workflow." -keywords: docker agent, ai agents, tools, toolsets, session plan tool -linkTitle: "Session Plan" -weight: 160 -canonical: https://docs.docker.com/ai/docker-agent/tools/session_plan/ ---- - -_Per-session plan tracker for the "draft, review, execute" workflow._ - -## Overview - -The `session_plan` toolset gives one agent a place to write a plan for the current session, signal that the plan is ready, and let the host route the next turn to an executing agent. - -Different from the [`plan` toolset](../plan/index.md) — `plan` is for shared, named plans multiple agents collaborate on over many sessions. `session_plan` is for one ephemeral plan per session, scoped to that session by ID. - -Plans live as Markdown files under: - -```text -~/.cagent/session_plans/.md -``` - -The tool surface is three tools: - -| Tool | Description | -| -------------------- | ---------------------------------------------------------------------------------------------------- | -| `write_session_plan` | Create or replace this session's plan as markdown. There's exactly one plan per session. | -| `read_session_plan` | Read the plan written for the current session and return it as markdown. | -| `exit_plan_mode` | Signal that the plan is ready for review. Does not switch agents on its own. | - -## Configuration - -```yaml -toolsets: - - type: session_plan -``` - -No configuration options. The plan path is derived from the session ID; the agent does not name plans. - -Restrict the toolset to a subset of tools the standard way: - -```yaml -# An agent that consumes a plan but should not be able to (re)write or finalize one. -toolsets: - - type: session_plan - tools: - - read_session_plan -``` - -## When to call exit_plan_mode - -Call `exit_plan_mode` once the plan is complete and you do not intend to change it on the next turn. It validates that a plan exists for the session and returns a "ready for review" tool result. It does **not** switch agents or solicit user approval on its own — the host application owns the next-turn routing (for example, by reading the tool result, by a UI affordance the user toggles, or by a `handoff` declared on the agent). - -This separation keeps the tool reusable across UIs: a CLI that prints tool results inline, a chat UI with a plan-mode toggle, and a server that auto-routes the next turn through a `handoff` can all consume the same signal without one stepping on another. - -## Storage and cleanup - -- Plans are markdown files written atomically (temp + rename), so concurrent readers — in this process or another — never observe a partial write. -- A best-effort sweep on first use of the toolset removes plan files older than 30 days under the plans directory. Stranded plans for long-gone sessions do not accumulate. -- The session ID identifies the file directly. There is no in-process mutex or revision counter, because two sessions cannot map to the same path. - -## Events - -A `session_plan_updated` event is emitted whenever `write_session_plan` succeeds: - -```json -{ - "type": "session_plan_updated", - "session_id": "...", - "path": "/Users/.../.cagent/session_plans/.md", - "content": "# my plan\n...", - "agent_name": "planner" -} -``` - -Embedders that render the plan inline can subscribe and update without re-reading the file. - -## Managing session plans from the host - -A session plan belongs to its session: hosts can read and export it, never change it. - -- **CLI** — the [`docker agent plans`](../../features/cli/index.md#docker-agent-plans) command group lists, reads (`get --session `), and exports session plans alongside shared plans. Mutations (`update`, `status`, `delete`) are refused with an `unsupported` error explaining the ownership rule. -- **TUI** — the `/plans` browser (see the [plan toolset docs](../plan/index.md#the-plans-browser-in-the-tui) for the full keybinding table) includes the **current session's** plan as the `session` scope row; plans of other sessions are never enumerated. Its identity is the session ID and its version column shows `-` — session plans have no versions. Enter opens the detail view (scope, session ID, update time, scrollable markdown) and x exports to `session-plan-.md` in the working directory (refusing to overwrite an existing file). e opens the plan body in your external editor (`$VISUAL` or `$EDITOR`) for editing — the write is unguarded and last-write-wins by design. Status and delete visibly report that session plans don't support them (session plans belong to their session and carry no shared-plan metadata). The browser refreshes live on the `session_plan_updated` event, so a plan the agent just wrote appears without reopening. - -## Example - -A two-agent workflow: `root` executes, `planner` plans. `/plan` hands off to the planner; `exit_plan_mode` signals "ready", and the host decides what happens next. - -```yaml -agents: - root: - model: anthropic/claude-sonnet-4-5 - description: Executes approved plans - instruction: | - You execute plans the planner has handed off. When you see a message - that a plan has been approved, read it with read_session_plan and work - through its steps in order. - toolsets: - - type: session_plan - tools: - - read_session_plan - - type: filesystem - - type: shell - commands: - plan: - description: "Switch to the planner" - agent: planner - - planner: - model: anthropic/claude-sonnet-4-5 - description: Investigates and writes plans for review - instruction: | - Investigate the user's request, then write the plan with - write_session_plan. Iterate with the user until the plan is complete, - then call exit_plan_mode to mark it ready for review. - toolsets: - - type: session_plan - - type: filesystem - readonly: true - - type: user_prompt -``` - -See [`examples/session_plan.yaml`](https://github.com/docker/docker-agent/blob/main/examples/session_plan.yaml) for a complete working example. - -## Error Handling - -- `read_session_plan` and `exit_plan_mode` return a "no plan written yet" error when called before `write_session_plan`. -- `write_session_plan` validates the session ID and refuses to write anything that could escape the plans directory; in practice the runtime generates UUIDs so this only triggers if an embedder supplies a hand-crafted ID. - -> [!TIP] -> **session_plan vs. plan vs. todo vs. tasks** -> -> Use **session_plan** when one agent drafts an approach for the user to review before another agent executes it (ephemeral, one per session). Use [plan](../plan/index.md) for shared, named plans multiple agents collaborate on over many sessions. Use [todo](../todo/index.md) for lightweight in-session task lists. Use [tasks](../tasks/index.md) for a structured, persistent task database with priorities and dependencies. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/shell/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/shell/index.md deleted file mode 100644 index 5da9fc8f8233..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/shell/index.md +++ /dev/null @@ -1,117 +0,0 @@ ---- -title: "Shell Tool" -description: "Execute arbitrary shell commands in the user's environment." -keywords: docker agent, ai agents, tools, toolsets, shell tool -linkTitle: "Shell" -weight: 20 -canonical: https://docs.docker.com/ai/docker-agent/tools/shell/ ---- - -_Execute arbitrary shell commands in the user's environment._ - -## Overview - -The shell tool allows agents to execute arbitrary shell commands synchronously. This is one of the most powerful tools — it lets agents run builds, install dependencies, query APIs, and interact with the system. Each call runs in a fresh, isolated shell session — no state persists between calls. - -Commands have a default 30-second timeout and require user confirmation unless `--yolo` is used. For servers, watchers, and other long-running commands, add the [`background_jobs`](../background-jobs/index.md) toolset alongside `shell`. - -### Shell interpreter detection - -The shell tool automatically detects and names the resolved shell interpreter (e.g., `bash`, `zsh`, `powershell`, `pwsh`, `cmd`) in its description to the model, along with the operating system (Linux, macOS, Windows). This helps models use the correct shell syntax for the host environment. - -For example: - -- On Linux with bash: "Executes the given shell command with bash on Linux." -- On Windows with PowerShell: "Executes the given shell command with powershell on Windows. Use Windows PowerShell 5.1 syntax: chain commands with ";" (not "&&"), and avoid POSIX commands/flags like "ls -la"." - -This reduces wasted turns where models assume POSIX syntax on Windows or vice versa. - -## Configuration - -```yaml -toolsets: - - type: shell -``` - -### Options - -| Property | Type | Description | -| -------------- | ------- | --------------------------------------------------------------------------------------------------- | -| `env` | object | Environment variables to set for all shell commands | -| `safer` | boolean | Deprecated and ignored — shell commands are always classified now (see [Command classification](#command-classification)). Kept so existing YAMLs still parse. | -| `sudo_askpass` | boolean | Opt in to prompting for a `sudo` password (see [Sudo support](#sudo-support)). Default `false`. | - -### Custom Environment Variables - -```yaml -toolsets: - - type: shell - env: - MY_VAR: "value" - PATH: "${env.PATH}:/custom/bin" -``` - -### Command classification - -Every shell command is classified against an embedded taxonomy before the approval decision — no opt-in required: - -- **Destructive matches** (`rm -rf `, `docker volume rm`, `mkfs`, `dd if=… of=/dev/`, …) are labelled `destructive` with a `blast_radius` (`low` / `medium` / `high`) and a `category` tag. The TUI confirmation dialog renders the blast radius with a color badge. -- **Known-safe reads** (`ls`, `cat`, `git status`, `git diff`, `docker ps`, `docker logs`, `kubectl get`, …) are labelled `safe`. -- **Everything else** is labelled `unknown`. - -The session's [safety mode](../../configuration/permissions/index.md#safety-modes) decides what each label means: `strict` asks about everything, `balanced` auto-runs safe commands and asks about destructive/unknown ones, `restricted` auto-runs safe commands and denies destructive/unknown ones without asking (fail-closed for unattended runs), `autonomous` runs everything. Custom permission rules always win over the mode. - -Compound shell (`a && b`, `a; b`, `a | b`) is never matched against the safe allowlist; any destructive segment falls through to ask. The full taxonomy lives in [`pkg/safety/safety_patterns.json`](https://github.com/docker/docker-agent/blob/main/pkg/safety/safety_patterns.json). - -See [`examples/safety_modes.yaml`](https://github.com/docker/docker-agent/blob/main/examples/safety_modes.yaml) for a full example. The legacy `safer: true` toolset flag is deprecated and ignored. - -### Sudo support - -By default a shell command has no controlling terminal, so a `sudo` command that needs a password hangs until it times out (the agent usually gives up and falls back to printing manual instructions). - -Set `sudo_askpass: true` to enable a sudo privilege escalation flow: - -```yaml -toolsets: - - type: shell - sudo_askpass: true -``` - -When enabled, `sudo` commands prompt you for your password through the host UI (the input is masked). The password is handed to `sudo` over a private, per-session socket via the standard `SUDO_ASKPASS` mechanism — it is never written to the command line, the logs, or stored by the agent. - -The bridge environment variables (`SUDO_ASKPASS`, `CAGENT_ASKPASS_SOCKET`, `CAGENT_ASKPASS_TOKEN`) are added only to commands that invoke `sudo`, but within such a command they are visible to every child process, not just `sudo`. They carry a socket path and a session token, not the password; the socket lives in a `0700` directory, so only your own user can reach it. - -Notes and limitations: - -- Unix only. The flag has no effect on Windows. -- Interactive UI only. In headless / non-interactive runs the prompt is declined automatically and `sudo` fails as before. -- Only a bare `sudo ...` invocation in a POSIX shell (`sh`, `bash`, `zsh`, ...) is handled. `sudo` called by absolute path (`/usr/bin/sudo`), via `env sudo`, from inside a nested script, or under a non-POSIX shell (e.g. `fish`) is not intercepted and behaves as before. -- Caching is `sudo`'s own. Because each shell tool call runs in a fresh shell with no controlling terminal, `sudo`'s credential cache does not persist across separate tool calls: you are prompted once per shell command that uses `sudo`. Within a single command, multiple `sudo` calls (e.g. `sudo a && sudo b`) usually share one prompt, subject to `sudo`'s own timestamp configuration. -- The prompt must be answered within the command's timeout; raise the `timeout` parameter for `sudo` commands that may wait on input. -- Prompts are serialized: if a single command runs two `sudo` calls in parallel (e.g. `sudo a & sudo b`), the second waits for the first prompt to be answered rather than opening two dialogs at once. - -## Available Tools - -The shell toolset exposes one tool: - -| Tool Name | Description | -| --------- | ---------------------------------------------------------------------------- | -| `shell` | Run a command synchronously and return its combined output when it finishes. | - -### `shell` parameters - -| Parameter | Type | Required | Description | -| --------- | ------- | -------- | ------------------------------------------------------------------------- | -| `cmd` | string | ✓ | The shell command to execute. | -| `cwd` | string | ✗ | Working directory to run the command in (default: `.`). | -| `timeout` | integer | ✗ | Per-call execution timeout in seconds (default: `30`). | - -> [!WARNING] -> **Safety** -> -> The shell tool gives agents full access to the system shell. Always set `max_iterations` on agents that use the shell tool to prevent infinite loops. A value of 20–50 is typical for development agents. Use [Sandbox Mode](../../configuration/sandbox/index.md) for additional isolation. - -> [!NOTE] -> **Tool Confirmation** -> -> By default, Docker Agent asks for user confirmation before executing shell commands. Use `--yolo` to auto-approve all tool calls. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/tasks/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/tasks/index.md deleted file mode 100644 index 9d399f96958b..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/tasks/index.md +++ /dev/null @@ -1,59 +0,0 @@ ---- -title: "Tasks Tool" -description: "Persistent task database with priorities and dependencies, shared across sessions." -keywords: docker agent, ai agents, tools, toolsets, tasks tool -linkTitle: "Tasks" -weight: 180 -canonical: https://docs.docker.com/ai/docker-agent/tools/tasks/ ---- - -_Persistent task database with priorities and dependencies, shared across sessions._ - -## Overview - -The tasks tool provides a persistent task database that survives across agent sessions. Unlike the [Todo tool](../todo/index.md), which maintains an in-memory task list for the current session only, the tasks tool stores tasks in a JSON file on disk so they can be accessed and updated across multiple sessions. Tasks support priorities and dependencies — a task is _blocked_ until every task it depends on is `done`. - -## Configuration - -```yaml -toolsets: - - type: tasks - path: ./tasks.json # Optional: custom database path -``` - -### Options - -| Property | Type | Default | Description | -| -------- | ------ | ------------- | ---------------------------------------------------------------------------------------------------------------------------- | -| `path` | string | `tasks.json` | Path to the JSON task database. Relative paths resolve against the agent config directory (or `--working-dir` when set). | - -## Available Tools - -The tasks toolset exposes these tools: - -| Tool Name | Description | -| ------------------- | ------------------------------------------------------------------------------------------------------------------------ | -| `create_task` | Create a new task with a title, description (or markdown file path), optional priority, and optional dependencies. | -| `get_task` | Get full details of a single task by ID, including its effective status (`blocked` if any dependency is not `done`). | -| `update_task` | Update a task's title, description, priority, status, or dependency list. | -| `delete_task` | Delete a task by ID. Also removes it from other tasks' dependency lists. | -| `list_tasks` | List tasks sorted by priority (critical first) with blocked tasks last. Optionally filter by status or priority. | -| `next_task` | Return the highest-priority actionable task — one that is not blocked and not done. Great for "what should I work on?". | -| `add_dependency` | Add a dependency: a task is blocked until the task it depends on is `done`. | -| `remove_dependency` | Remove a dependency from a task. | - -## Example - -```yaml -agents: - root: - model: openai/gpt-4o - toolsets: - - type: tasks - path: ./project-tasks.json -``` - -> [!TIP] -> **Tasks vs. Todo** -> -> Use the **tasks** tool when you need persistence across sessions, priorities, or dependencies (e.g., long-running projects, recurring work). Use the [todo tool](../todo/index.md) for ephemeral, session-scoped task lists. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/think/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/think/index.md deleted file mode 100644 index 24873fcacfe3..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/think/index.md +++ /dev/null @@ -1,30 +0,0 @@ ---- -title: "Think Tool" -description: "Step-by-step reasoning scratchpad for planning and decision-making." -keywords: docker agent, ai agents, tools, toolsets, think tool -linkTitle: "Think" -weight: 140 -canonical: https://docs.docker.com/ai/docker-agent/tools/think/ ---- - -_Step-by-step reasoning scratchpad for planning and decision-making._ - -## Overview - -The think tool is a reasoning scratchpad that lets agents think step-by-step before acting. The agent can write its thoughts without producing visible output to the user — ideal for planning complex tasks, breaking down problems, and reasoning through multi-step solutions. - -This is a lightweight tool with no side effects. It is most useful for models that lack built-in reasoning or thinking capabilities (e.g., smaller or older models). For models that already support native thinking — such as Claude with extended thinking, OpenAI o-series, or Gemini with a thinking budget — this tool is unnecessary since the model can reason internally. - -## Configuration - -```yaml -toolsets: - - type: think -``` - -No configuration options. - -> [!TIP] -> **When to use** -> -> Use the think tool with models that don't have native reasoning capabilities. If your model already supports a [thinking budget](../../configuration/models/index.md#thinking-budget), you likely don't need this tool. diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/todo/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/todo/index.md deleted file mode 100644 index 7f2154379cce..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/todo/index.md +++ /dev/null @@ -1,54 +0,0 @@ ---- -title: "Todo Tool" -description: "Task list management for complex multi-step workflows." -keywords: docker agent, ai agents, tools, toolsets, todo tool -linkTitle: "Todo" -weight: 170 -canonical: https://docs.docker.com/ai/docker-agent/tools/todo/ ---- - -_Task list management for complex multi-step workflows._ - -## Overview - -The todo tool provides task list management. Agents can create, update, list, and track progress on tasks with status tracking (pending, in-progress, completed). Useful for complex multi-step workflows where the agent needs to stay organized and ensure all steps are completed. - -## Available Tools - -| Tool | Description | -| -------------- | ---------------------------------------- | -| `create_todo` | Create a new task | -| `create_todos` | Create multiple tasks at once | -| `update_todos` | Update status of one or more tasks | -| `list_todos` | List all current tasks with their status | - -### Task Statuses - -| Status | Description | -| ------------- | ---------------------------- | -| `pending` | Task has not been started | -| `in-progress` | Task is currently being done | -| `completed` | Task is finished | - -## Configuration - -```yaml -toolsets: - - type: todo -``` - -### Options - -| Property | Type | Default | Description | -| -------- | ------- | ------- | ----------------------------------------------------------------------- | -| `shared` | boolean | `false` | When `true`, todos are shared across all agents in a multi-agent config | - -### Shared Todos - -In multi-agent setups, enable shared todos so all agents can see and update the same task list: - -```yaml -toolsets: - - type: todo - shared: true -``` diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/transfer-task/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/transfer-task/index.md deleted file mode 100644 index 9d3bc2a03a07..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/transfer-task/index.md +++ /dev/null @@ -1,73 +0,0 @@ ---- -title: "Transfer Task Tool" -description: "Delegate tasks to sub-agents in multi-agent setups." -keywords: docker agent, ai agents, tools, toolsets, transfer task tool -linkTitle: "Transfer Task" -weight: 80 -canonical: https://docs.docker.com/ai/docker-agent/tools/transfer-task/ ---- - -_Delegate tasks to sub-agents in multi-agent setups._ - -## Overview - -The `transfer_task` tool allows an agent to delegate tasks to specialized sub-agents and receive their results. This is the core mechanism for multi-agent orchestration. - -**You don't need to add it manually** — it's automatically available when an agent has `sub_agents` configured. - -## Configuration - -The tool is enabled implicitly when `sub_agents` is set: - -```yaml -agents: - coordinator: - model: openai/gpt-4o - description: Coordinates work across specialists - instruction: Analyze requests and delegate to the right specialist. - sub_agents: [developer, researcher] - - developer: - model: anthropic/claude-sonnet-4-5 - description: Expert software developer - instruction: Write clean, production-ready code. - toolsets: - - type: filesystem - - type: shell - - researcher: - model: openai/gpt-4o - description: Web researcher - instruction: Search for information online. - toolsets: - - type: mcp - ref: docker:duckduckgo -``` - -The coordinator agent automatically gets a `transfer_task` tool that can delegate to `developer` or `researcher`. - -## Tool Interface - -The `transfer_task` tool takes three parameters: - -| Parameter | Type | Required | Description | -| ----------------- | ------ | -------- | ------------------------------------------------------------------------------------------- | -| `agent` | string | ✓ | Name of the sub-agent to delegate to. Must be listed under the caller's `sub_agents`. | -| `task` | string | ✓ | Clear, concise description of the task the sub-agent should achieve. | -| `expected_output` | string | ✓ | Description of the result/format the caller expects back. | - -The call blocks until the sub-agent returns its result, which becomes the tool's response. For non-blocking parallel delegation, use [`background_agents`](../background-agents/index.md) instead. - -## Delegation Limits - -Sub-agents can have `sub_agents` of their own, so multi-level delegation chains are supported. Two runtime guards keep chains sane, applied to both `transfer_task` and `run_background_agent`: - -- **Cycles are rejected.** A delegation targeting an agent that is already part of the active delegation chain (for example `a -> b -> a`) fails with an error naming the cycle. -- **Depth is capped at 10 nested delegations.** The root agent delegating to its first sub-agent counts as depth 1; a call that would exceed the cap fails with an error stating the attempted depth. - -A rejected delegation returns a tool error to the calling agent and never starts the sub-agent. - -> [!TIP] -> **See also** -> -> For parallel task delegation, see [Background Agents](../background-agents/index.md). For multi-agent patterns, see [Multi-Agent](../../concepts/multi-agent/index.md). diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/user-prompt/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/user-prompt/index.md deleted file mode 100644 index 739892c93750..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/user-prompt/index.md +++ /dev/null @@ -1,186 +0,0 @@ ---- -title: "User Prompt Tool" -description: "Ask the user questions and collect interactive input during agent execution." -keywords: docker agent, ai agents, tools, toolsets, user prompt tool -linkTitle: "User Prompt" -weight: 190 -canonical: https://docs.docker.com/ai/docker-agent/tools/user-prompt/ ---- - -_Ask the user questions and collect interactive input during agent execution._ - -## Overview - -The user prompt tool allows agents to ask questions and collect input from users during execution. This enables interactive workflows where the agent needs clarification, confirmation, or additional information before proceeding. - -> [!NOTE] -> **When to Use** -> -> - When the agent needs clarification before proceeding -> - Collecting credentials or configuration values -> - Presenting choices and getting user decisions -> - Confirming destructive or important actions - -## Configuration - -```yaml -agents: - assistant: - model: openai/gpt-4o - description: Interactive assistant - instruction: | - You are a helpful assistant. When you need information - from the user, use the user_prompt tool to ask them. - toolsets: - - type: user_prompt - - type: filesystem - - type: shell -``` - -## Tool Interface - -The `user_prompt` tool takes these parameters: - -| Parameter | Type | Required | Description | -| --------- | ------ | -------- | -------------------------------------------------------------------------------------------------- | -| `message` | string | ✓ | The question or prompt to display. | -| `title` | string | ✗ | Optional title for the dialog window in the TUI. Defaults to `"Question"` when not provided. | -| `schema` | object | ✗ | JSON Schema defining the expected response structure (object or primitive). | - -## Response Format - -The tool returns a JSON response: - -```json -{ - "action": "accept", - "content": { - "field1": "user value", - "field2": true - } -} -``` - -### Action Values - -| Action | Meaning | -| --------- | ------------------------------------------ | -| `accept` | User provided a response (check `content`) | -| `decline` | User declined to answer | -| `cancel` | User cancelled the prompt | - -## Schema Examples - -### Simple String Input - -```json -{ - "type": "string", - "title": "API Key", - "description": "Enter your API key" -} -``` - -### Multiple Choice - -```json -{ - "type": "string", - "enum": ["development", "staging", "production"], - "title": "Environment", - "description": "Select the target environment" -} -``` - -### Boolean Confirmation - -```json -{ - "type": "boolean", - "title": "Confirm", - "description": "Are you sure you want to proceed?" -} -``` - -### Object with Multiple Fields - -```json -{ - "type": "object", - "properties": { - "username": { - "type": "string", - "description": "Your username" - }, - "password": { - "type": "string", - "description": "Your password" - }, - "remember": { - "type": "boolean", - "description": "Remember credentials" - } - }, - "required": ["username", "password"] -} -``` - -### Number Input - -```json -{ - "type": "integer", - "title": "Port Number", - "description": "Enter the port number (1024-65535)", - "minimum": 1024, - "maximum": 65535 -} -``` - -## Example Usage - -Here's how an agent might use the user prompt tool: - -```text -Agent: I need to deploy this application. Let me ask which environment to target. - -[Calls user_prompt with message: "Which environment should I deploy to?" - and schema with enum: ["development", "staging", "production"]] - -User selects: "staging" - -Agent: Great, I'll deploy to staging. Let me confirm this action. - -[Calls user_prompt with message: "Deploy to staging? This will replace the current version." - and schema with type: "boolean"] - -User confirms: true - -Agent: Deploying to staging... -``` - -## UI Presentation - -How the prompt appears depends on the interface: - -- **TUI**: Displays an interactive dialog with appropriate input controls -- **CLI (exec mode)**: Prints the prompt and reads from stdin -- **API/MCP**: Returns an elicitation request to the client - -> [!TIP] -> **Best Practice** -> -> Provide clear, concise messages. Include context about why you're asking and what the information will be used for. Use schemas with descriptions to guide users on expected input format. - -## Handling Responses - -The agent should handle all possible actions: - -- **accept**: Process the `content` and continue -- **decline**: Acknowledge and try an alternative approach or explain what's needed -- **cancel**: Stop the current operation gracefully - -> [!WARNING] -> **Context Requirement** -> -> The user prompt tool requires an elicitation handler to be configured. It works in the TUI and CLI modes but may not be available in all contexts (e.g., some MCP client configurations). diff --git a/_vendor/github.com/docker/docker-agent/docs/tools/webhook/index.md b/_vendor/github.com/docker/docker-agent/docs/tools/webhook/index.md deleted file mode 100644 index ded710754192..000000000000 --- a/_vendor/github.com/docker/docker-agent/docs/tools/webhook/index.md +++ /dev/null @@ -1,143 +0,0 @@ ---- -title: "Webhook Tool" -description: "Reliable outbound notifications to Slack, Discord, Telegram, IFTTT, and more." -keywords: docker agent, ai agents, tools, toolsets, webhook, slack, discord, telegram, ifttt, notifications -linkTitle: "Webhook" -weight: 145 -canonical: https://docs.docker.com/ai/docker-agent/tools/webhook/ ---- - -_Reliable outbound notifications to Slack, Discord, Telegram, IFTTT, and more._ - -## Overview - -The webhook toolset delivers a notification to a destination **you configure**. The -agent supplies only the message text: it never sees or chooses the URL, because a -webhook URL is itself a credential (Slack and Mattermost embed a secret path, -Discord a token, IFTTT a key, Telegram a bot token). - -This is not a general HTTP client — that is the [`api`](../api/index.md) toolset. -The webhook toolset owns *delivery*: - -- **At-least-once delivery.** Transient failures (`429`, `5xx`, network errors) are - retried with exponential backoff, honouring the server's `Retry-After`. A `4xx` - is permanent and fails immediately without wasting retries. -- **Non-blocking.** The call returns as soon as the notification is queued, so a - slow or retrying endpoint never stalls the agent's turn. The agent is messaged - back **only if delivery ultimately fails**. -- **Storm protection.** An identical message to the same destination inside a short - window is suppressed, and notifications are rate limited, so a looping agent - cannot flood a channel. -- **Provider-shaped payloads.** Each service's wire format is applied for you. - -## Configuration - -The destination lives in `webhook_config`. Use `${env.VAR}` for anything secret — -values are expanded at call time and never stored in the config file. - -```yaml -toolsets: - - type: webhook - webhook_config: - provider: slack - url: ${env.SLACK_WEBHOOK_URL} -``` - -| Field | Required | Description | -| --- | --- | --- | -| `url` | Yes | Webhook endpoint. Usually embeds a secret — prefer `${env.VAR}`. | -| `provider` | No | Payload shape (default `generic`). | -| `headers` | No | Extra headers, for endpoints authenticating with a token. | -| `chat_id` | No | Destination chat — required for `provider: telegram`. | - -`timeout` on the toolset (seconds) overrides the per-request HTTP timeout. - -## Providers - -| Provider | Payload sent | Where the secret lives | -| --- | --- | --- | -| `slack`, `mattermost`, `rocketchat`, `googlechat`, `teams`, `generic` | `{"text": message}` | secret webhook URL | -| `discord` | `{"content": message}` | token in the webhook URL | -| `ifttt` | `{"value1": message, "value2": …, "value3": …}` | key in the webhook URL | -| `telegram` | `{"chat_id": …, "text": message}` | bot token in the URL, plus `chat_id` | - -Aliases are accepted: `msteams`/`microsoft_teams` → `teams`, `google_chat`/`gchat` -→ `googlechat`, `rocket.chat` → `rocketchat`. - -### Per-service examples - -```yaml -# Slack / Mattermost / Rocket.Chat — the URL is the credential -toolsets: - - type: webhook - webhook_config: - provider: slack - url: ${env.SLACK_WEBHOOK_URL} -``` - -```yaml -# Discord — the token is part of the webhook URL -toolsets: - - type: webhook - webhook_config: - provider: discord - url: ${env.DISCORD_WEBHOOK_URL} -``` - -```yaml -# Telegram — bot token in the URL, chat_id selects the destination chat -toolsets: - - type: webhook - webhook_config: - provider: telegram - url: https://api.telegram.org/bot${env.TELEGRAM_BOT_TOKEN}/sendMessage - chat_id: "123456789" -``` - -```yaml -# IFTTT — the key is part of the trigger URL -toolsets: - - type: webhook - webhook_config: - provider: ifttt - url: https://maker.ifttt.com/trigger/build_failed/with/key/${env.IFTTT_KEY} -``` - -```yaml -# Generic endpoint authenticating with a bearer token -toolsets: - - type: webhook - webhook_config: - provider: generic - url: https://alerts.example.com/notify - headers: - Authorization: Bearer ${env.ALERTS_TOKEN} -``` - -## `send_webhook` - -| Parameter | Required | Description | -| --- | --- | --- | -| `message` | Yes | The message text to deliver. | -| `value2`, `value3` | No | Extra IFTTT data fields (`provider: ifttt`). | - -Returns immediately once queued. On success nothing further happens; if delivery -ultimately fails, the agent receives a message saying so. - -## Example - -```yaml -agents: - root: - model: openai/gpt-5-mini - instruction: If a check fails, notify the team with send_webhook. - toolsets: - - type: webhook - webhook_config: - provider: slack - url: ${env.SLACK_WEBHOOK_URL} -``` - -> [!NOTE] -> Requests to non-public addresses are refused (the SSRF-safe HTTP client), and the -> configured URL is never echoed back to the model or into error messages. diff --git a/_vendor/modules.txt b/_vendor/modules.txt index 1ac92137fbbf..e4b9aa04a639 100644 --- a/_vendor/modules.txt +++ b/_vendor/modules.txt @@ -4,4 +4,3 @@ # github.com/docker/cli v29.7.2+incompatible # github.com/docker/compose/v5 v5.5.0 # github.com/docker/model-runner v1.1.36 -# github.com/docker/docker-agent v1.126.0 diff --git a/content/manuals/ai/docker-agent/_index.md b/content/manuals/ai/docker-agent/_index.md index bb69c0115df8..44a19a48224e 100644 --- a/content/manuals/ai/docker-agent/_index.md +++ b/content/manuals/ai/docker-agent/_index.md @@ -14,153 +14,23 @@ params: keywords: [ai, agent, docker agent, cagent] --- -[Docker Agent](https://github.com/docker/docker-agent) is an open-source framework -for building teams of specialized AI agents. Instead of prompting one -generalist model, you define agents with specific roles and instructions that -collaborate to solve problems. Run these agent teams from your terminal using -any LLM provider. +[Docker Agent](https://github.com/docker/docker-agent) is an open source runtime +for building, running, and sharing AI agents. Define agents and multi-agent +teams in YAML, choose an LLM provider, and run them from the terminal. > [!NOTE] > Docker Agent is a framework for building and running custom agent teams. > For Docker's built-in AI assistant, see [Gordon](/ai/gordon/) (`docker ai`). -## Why agent teams +## Learn Docker Agent -One agent handling complex work means constant context-switching. Split the work -across focused agents instead - each handles what it's best at. Docker Agent manages -the coordination. +The Docker Agent project maintains its technical documentation separately: -Here's a two-agent team that debugs problems: +- [Get started](https://docker.github.io/docker-agent/getting-started/quickstart/) +- [Configure agents](https://docker.github.io/docker-agent/configuration/overview/) +- [Browse providers](https://docker.github.io/docker-agent/providers/overview/) +- [Explore tools](https://docker.github.io/docker-agent/tools/) +- [Read all Docker Agent documentation](https://docker.github.io/docker-agent/) -```yaml -agents: - root: - model: openai/gpt-5-mini # Change to the model that you want to use - description: Bug investigator - instruction: | - Analyze error messages, stack traces, and code to find bug root causes. - Explain what's wrong and why it's happening. - Delegate fix implementation to the fixer agent. - sub_agents: [fixer] - toolsets: - - type: filesystem - - type: mcp - ref: docker:duckduckgo - - fixer: - model: anthropic/claude-sonnet-4-5 # Change to the model that you want to use - description: Fix implementer - instruction: | - Write fixes for bugs diagnosed by the investigator. - Make minimal, targeted changes and add tests to prevent regression. - toolsets: - - type: filesystem - - type: shell -``` - -The root agent investigates and explains the problem. When it understands the -issue, it hands off to `fixer` for implementation. Each agent stays focused on -its specialty. - -## Installation - -Docker Agent is included in Docker Desktop 4.63 and later. In Docker Desktop versions 4.49 through 4.62, this feature was called cagent. - -For Docker Engine users or custom installations: - -- **Homebrew**: `brew install docker-agent` -- **Winget**: `winget install Docker.Agent` -- **Pre-built binaries**: [GitHub - releases](https://github.com/docker/docker-agent/releases) -- **From source**: See the [Docker Agent - repository](https://github.com/docker/docker-agent?tab=readme-ov-file#build-from-source) - -The `docker-agent` binary should be copied to `~/.docker/cli-plugins` and then can be used with the `docker agent` command. Alternatively, it can be used as a standalone binary. - -## Get started - -Try the bug analyzer team: - -1. Set your API key for the model provider you want to use: - - ```console - $ export ANTHROPIC_API_KEY= # For Claude models - $ export OPENAI_API_KEY= # For OpenAI models - $ export GOOGLE_API_KEY= # For Gemini models - ``` - -2. Save the [example configuration](#why-agent-teams) as `debugger.yaml`. - -3. Run your agent team: - - ```console - $ docker agent run debugger.yaml - ``` - -You'll see a prompt where you can describe bugs or paste error messages. The -investigator analyzes the problem, then hands off to the fixer for -implementation. - -## How it works - -You interact with the _root agent_, which can delegate work to sub-agents you -define. Each agent: - -- Uses its own model and parameters -- Has its own context (agents don't share knowledge) -- Can access built-in tools like todo lists, memory, and task delegation -- Can use external tools via [MCP - servers](/manuals/ai/mcp-catalog-and-toolkit/mcp-gateway.md) - -The root agent delegates tasks to agents listed under `sub_agents`. Sub-agents -can have their own sub-agents for deeper hierarchies. - -## Configuration options - -Agent configurations are YAML files. A basic structure looks like this: - -```yaml -agents: - root: - model: claude-sonnet-4-0 - description: Brief role summary - instruction: | - Detailed instructions for this agent... - sub_agents: [helper] - - helper: - model: gpt-5-mini - description: Specialist agent role - instruction: | - Instructions for the helper agent... -``` - -You can also configure model settings (like context limits), tools (including -MCP servers), and more. See the [configuration -reference](./configuration/overview/index.md) -for complete details. - -## Share agent teams - -Agent configurations are packaged as OCI artifacts. Push and pull them like -container images: - -```console -$ docker agent share push ./debugger.yaml myusername/debugger -$ docker agent share pull myusername/debugger -``` - -Use Docker Hub or any OCI-compatible registry. Pushing creates the repository if -it doesn't exist yet. - -## What's next - -- Follow the [quickstart](./getting-started/quickstart/index.md) to build your first agent -- Learn [best practices](./guides/tips/index.md) for building effective agents -- Integrate Docker Agent with your [editor](./features/acp/index.md) or use agents as - [tools in MCP clients](./tools/mcp/index.md) -- Browse example agent configurations in the [Docker Agent - repository](https://github.com/docker/docker-agent/tree/main/examples) -- Connect agents to external tools via the [Docker MCP - Gateway](/manuals/ai/mcp-catalog-and-toolkit/mcp-gateway.md) -- Read the full [configuration reference](./configuration/overview/index.md) +To run Docker Agent inside an isolated environment, see +[Docker Agent in Docker Sandboxes](/manuals/ai/sandboxes/agents/docker-agent.md). diff --git a/content/manuals/ai/sandboxes/agents/docker-agent.md b/content/manuals/ai/sandboxes/agents/docker-agent.md index 0839f7cb1477..c332c3d9ad13 100644 --- a/content/manuals/ai/sandboxes/agents/docker-agent.md +++ b/content/manuals/ai/sandboxes/agents/docker-agent.md @@ -7,7 +7,7 @@ description: | keywords: docker sandboxes, docker agent, openai, anthropic, sbx --- -Official documentation: [Docker Agent](/manuals/ai/docker-agent/_index.md) +Full documentation: [Docker Agent](https://docker.github.io/docker-agent/) ## Quick start diff --git a/content/manuals/dhi/tools/mcp.md b/content/manuals/dhi/tools/mcp.md index bc71dae76de6..b9c8ff74ced2 100644 --- a/content/manuals/dhi/tools/mcp.md +++ b/content/manuals/dhi/tools/mcp.md @@ -89,7 +89,7 @@ Or add it manually to `.claude/mcp.json` in your project: {{< /tab >}} {{< tab name="Docker Agent" >}} -In your [Docker Agent](/manuals/ai/docker-agent/_index.md) YAML configuration, add the +In your [Docker Agent](https://docker.github.io/docker-agent/) YAML configuration, add the DHI MCP server as a remote toolset: ```yaml diff --git a/data/docker_agent_redirects.yml b/data/docker_agent_redirects.yml new file mode 100644 index 000000000000..67724d4d7aee --- /dev/null +++ b/data/docker_agent_redirects.yml @@ -0,0 +1,126 @@ +# Exact redirects for Docker Agent pages formerly mounted on docs.docker.com. +# Keep this inventory when removing the Hugo module so stale HTML and Markdown +# URLs continue to resolve to their corresponding upstream documentation. +paths: + - community/contributing + - community/opentelemetry + - community/telemetry + - community/troubleshooting + - concepts/agents + - concepts/distribution + - concepts/models + - concepts/multi-agent + - concepts/tools + - configuration/agents + - configuration/agentsignore + - configuration/budget + - configuration/commands + - configuration/flavors + - configuration/hcl + - configuration/hooks + - configuration/models + - configuration/overview + - configuration/permissions + - configuration/routing + - configuration/sandbox + - configuration/structured-output + - configuration/tools + - configuration/user-settings + - features/a2a + - features/acp + - features/api-server + - features/board + - features/chat-server + - features/cli + - features/code-mode + - features/evaluation + - features/harnesses + - features/mcp-mode + - features/remote-mcp + - features/sessions + - features/skills + - features/snapshots + - features/tui + - getting-started/installation + - getting-started/introduction + - getting-started/quickstart + - getting-started/set-up-a-model + - guides/compaction + - guides/go-sdk + - guides/headless + - guides/secrets + - guides/thinking + - guides/tips + - providers/anthropic + - providers/baseten + - providers/bedrock + - providers/cerebras + - providers/chatgpt + - providers/cloudflare-ai-gateway + - providers/cloudflare-workers-ai + - providers/custom + - providers/deepseek + - providers/dmr + - providers/fireworks + - providers/github-copilot + - providers/google + - providers/groq + - providers/huggingface + - providers/local + - providers/minimax + - providers/mistral + - providers/moonshot + - providers/nebius + - providers/nvidia + - providers/openai + - providers/opencode-go + - providers/opencode-zen + - providers/openrouter + - providers/overview + - providers/ovhcloud + - providers/together + - providers/vercel + - providers/xai + - tools/a2a + - tools/api + - tools/background-agents + - tools/background-jobs + - tools/fetch + - tools/filesystem + - tools/git + - tools/handoff + - tools/lsp + - tools/mcp-catalog + - tools/mcp + - tools/memory + - tools/model-picker + - tools/open-url + - tools/openapi + - tools/plan + - tools/rag + - tools/scheduler + - tools/script + - tools/session_context + - tools/session_plan + - tools/shell + - tools/tasks + - tools/think + - tools/todo + - tools/transfer-task + - tools/user-prompt + - tools/webhook +aliases: + /ai/docker-agent/best-practices/: guides/tips + /ai/docker-agent/evals/: features/evaluation + /ai/docker-agent/integrations/a2a/: features/a2a + /ai/docker-agent/integrations/acp/: features/acp + /ai/docker-agent/integrations/mcp/: tools/mcp + /ai/docker-agent/local-models/: providers/local + /ai/docker-agent/model-providers/: providers/overview + /ai/docker-agent/providers/ollama/: providers/local + /ai/docker-agent/rag/: tools/rag + /ai/docker-agent/reference/cli/: features/cli + /ai/docker-agent/reference/config/: configuration/overview + /ai/docker-agent/reference/toolsets/: configuration/tools + /ai/docker-agent/sharing-agents/: concepts/distribution + /ai/docker-agent/tutorial/: getting-started/quickstart diff --git a/go.mod b/go.mod index eb4897444a12..aa611347cfa6 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,6 @@ require ( github.com/docker/buildx v0.36.1 github.com/docker/cli v29.7.2+incompatible github.com/docker/compose/v5 v5.5.0 - github.com/docker/docker-agent v1.126.0 github.com/docker/model-runner v1.1.36 github.com/moby/buildkit v0.32.2 github.com/moby/moby/api v1.55.0 @@ -21,7 +20,6 @@ tool ( github.com/docker/buildx github.com/docker/cli github.com/docker/compose/v5 - github.com/docker/docker-agent github.com/docker/model-runner github.com/docker/scout-cli github.com/moby/buildkit diff --git a/hack/releaser/cloudfront-lambda-redirects.js b/hack/releaser/cloudfront-lambda-redirects.js index 7d3d4cfe1992..26abe82e9979 100644 --- a/hack/releaser/cloudfront-lambda-redirects.js +++ b/hack/releaser/cloudfront-lambda-redirects.js @@ -53,8 +53,14 @@ exports.handler = (event, context, callback) => { if (!request.uri.startsWith(`/${rp["prefix"]}`)) { continue; } + const prefixRoot = `/${rp["prefix"]}`.replace(/\/$/, ""); + if (rp["excludeRoot"] && requestUrl === prefixRoot) { + continue; + } let newlocation = "/"; - if (rp["strip"]) { + if (rp["target"]) { + newlocation = rp["target"]; + } else if (rp["strip"]) { let re = new RegExp(`(^/${rp["prefix"]})`, "gi"); newlocation = request.uri.replace(re, "/"); } diff --git a/hack/releaser/cloudfront-lambda-redirects.test.js b/hack/releaser/cloudfront-lambda-redirects.test.js index 915e33b10d68..3c232b392416 100644 --- a/hack/releaser/cloudfront-lambda-redirects.test.js +++ b/hack/releaser/cloudfront-lambda-redirects.test.js @@ -22,11 +22,20 @@ const REDIRECTS = { "/target-with-query/": "/dest/?ref=docs", "/target-with-fragment/": "/dest/?ref=docs#install", "/external-target/": "https://www.docker.com/example?ref=docs#install", + "/ai/docker-agent/getting-started/quickstart/": + "https://docker.github.io/docker-agent/getting-started/quickstart/", + "/ai/docker-agent/getting-started/quickstart.md": + "https://docker.github.io/docker-agent/getting-started/quickstart/", }; const REDIRECTS_PREFIXES = [ { prefix: "keep/", strip: false }, { prefix: "strip/", strip: true }, + { + prefix: "ai/docker-agent/", + target: "https://docker.github.io/docker-agent/", + excludeRoot: true, + }, ]; // Render the template the same way getLambdaFunctionZip in aws.go does, then @@ -141,6 +150,44 @@ test("prefix redirect (no strip) preserves the query string", async () => { assert.equal(locationOf(result), "/?utm_source=x"); }); +test("external prefix redirect preserves the query string", async () => { + const { result } = await invoke({ + uri: "/ai/docker-agent/removed-page/", + querystring: "utm_source=x", + }); + assert.equal(result.status, "301"); + assert.equal( + locationOf(result), + "https://docker.github.io/docker-agent/?utm_source=x", + ); +}); + +test("exact redirect takes precedence over an external prefix", async () => { + const { result } = await invoke({ + uri: "/ai/docker-agent/getting-started/quickstart/", + }); + assert.equal( + locationOf(result), + "https://docker.github.io/docker-agent/getting-started/quickstart/", + ); +}); + +test("markdown exact redirect takes precedence over an external prefix", async () => { + const { result } = await invoke({ + uri: "/ai/docker-agent/getting-started/quickstart.md", + }); + assert.equal( + locationOf(result), + "https://docker.github.io/docker-agent/getting-started/quickstart/", + ); +}); + +test("external prefix redirect excludes the retained root page", async () => { + const { result, request } = await invoke({ uri: "/ai/docker-agent/" }); + assert.equal(result, request); + assert.equal(request.uri, "/ai/docker-agent/index.html"); +}); + test("directory rewrite passes the request through with query string intact", async () => { const { result, request } = await invoke({ uri: "/some/page", diff --git a/hack/releaser/redirects-prefixes.json b/hack/releaser/redirects-prefixes.json index 8894e5130a88..c08bd71b8a1c 100644 --- a/hack/releaser/redirects-prefixes.json +++ b/hack/releaser/redirects-prefixes.json @@ -1,4 +1,9 @@ [ + { + "prefix": "ai/docker-agent/", + "target": "https://docker.github.io/docker-agent/", + "excludeRoot": true + }, { "prefix": "compliance/", "strip": false diff --git a/hugo.yaml b/hugo.yaml index f7e9ab291035..9277576e7dae 100644 --- a/hugo.yaml +++ b/hugo.yaml @@ -32,15 +32,6 @@ cascade: - target: path: /reference/cli/sbx/** layout: sbx-cli - # Docker Agent section indexes are mounted navigation stubs; skip - # rendering them so they don't produce empty pages (same pattern as - # gordon/concepts and other render:never section indexes) - - target: - path: /manuals/ai/docker-agent/** - kind: section - build: - render: never - # Remove the /manuals prefix for content in the manuals section permalinks: page: @@ -393,29 +384,3 @@ module: - source: cmd/cli/docs/reference target: data/cli/model files: ["*.yaml"] - - # Docker Agent - # Single-sources https://docker.github.io/docker-agent/ content; - # bumped on each docker-agent release by sync-docker-agent-docs.yml. - # Sections are mounted individually so hugo mod vendor does not - # vendor the upstream Jekyll site files that also live in docs/. - - path: github.com/docker/docker-agent - mounts: - - source: docs/getting-started - target: content/manuals/ai/docker-agent/getting-started - - source: docs/concepts - target: content/manuals/ai/docker-agent/concepts - - source: docs/configuration - target: content/manuals/ai/docker-agent/configuration - - source: docs/tools - target: content/manuals/ai/docker-agent/tools - - source: docs/providers - target: content/manuals/ai/docker-agent/providers - - source: docs/features - target: content/manuals/ai/docker-agent/features - - source: docs/guides - target: content/manuals/ai/docker-agent/guides - - source: docs/community - target: content/manuals/ai/docker-agent/community - - source: docs/demo.gif - target: content/manuals/ai/docker-agent/demo.gif diff --git a/layouts/home.redirects.json b/layouts/home.redirects.json index 9d7ed82c9f05..11fe4e98a0e9 100644 --- a/layouts/home.redirects.json +++ b/layouts/home.redirects.json @@ -41,5 +41,14 @@ {{- $redirects.SetInMap "paths" . $target -}} {{- end -}} {{- end -}} +{{- range hugo.Data.docker_agent_redirects.paths -}} + {{- $target := printf "https://docker.github.io/docker-agent/%s/" . -}} + {{- $redirects.SetInMap "paths" (printf "/ai/docker-agent/%s/" .) $target -}} + {{- $redirects.SetInMap "paths" (printf "/ai/docker-agent/%s.md" .) $target -}} +{{- end -}} +{{- range $source, $targetPath := hugo.Data.docker_agent_redirects.aliases -}} + {{- $target := printf "https://docker.github.io/docker-agent/%s/" $targetPath -}} + {{- $redirects.SetInMap "paths" $source $target -}} +{{- end -}} {{- $opts := dict "noHTMLEscape" true }} {{- $redirects.Get "paths" | jsonify $opts }} From d13ec3f41c201969d22a06db20ebbca8f0e38adf Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Mon, 24 Aug 2026 08:48:31 +0000 Subject: [PATCH 2/3] docs: make Docker Agent overview a leaf page The retained Docker Agent overview was still represented as a section index after its child documentation moved upstream. Convert it to a leaf page, pin its existing public URL, and update source cross-references so Docker Docs no longer presents it as a documentation subtree. --- content/guides/agentic-ai.md | 2 +- content/manuals/ai/{docker-agent/_index.md => docker-agent.md} | 1 + content/manuals/desktop/release-notes.md | 2 +- 3 files changed, 3 insertions(+), 2 deletions(-) rename content/manuals/ai/{docker-agent/_index.md => docker-agent.md} (98%) diff --git a/content/guides/agentic-ai.md b/content/guides/agentic-ai.md index 26141201e775..869dfe51a5bc 100644 --- a/content/guides/agentic-ai.md +++ b/content/guides/agentic-ai.md @@ -13,7 +13,7 @@ params: > > This guide uses the familiar Docker Compose workflow to orchestrate agentic AI > applications. For a smoother development experience, check out -> [Docker Agent](../manuals/ai/docker-agent/_index.md), a purpose-built agent runtime that +> [Docker Agent](../manuals/ai/docker-agent.md), a purpose-built agent runtime that > simplifies running and managing AI agents. ## Introduction diff --git a/content/manuals/ai/docker-agent/_index.md b/content/manuals/ai/docker-agent.md similarity index 98% rename from content/manuals/ai/docker-agent/_index.md rename to content/manuals/ai/docker-agent.md index 44a19a48224e..b11da728387d 100644 --- a/content/manuals/ai/docker-agent/_index.md +++ b/content/manuals/ai/docker-agent.md @@ -2,6 +2,7 @@ title: Docker Agent description: Docker Agent lets you build, orchestrate, and share AI agents that work together as a team. weight: 60 +url: /ai/docker-agent/ aliases: - /ai/cagent/ - /manuals/ai/cagent/ diff --git a/content/manuals/desktop/release-notes.md b/content/manuals/desktop/release-notes.md index a7a80e016f79..10b487cbdddd 100644 --- a/content/manuals/desktop/release-notes.md +++ b/content/manuals/desktop/release-notes.md @@ -1489,7 +1489,7 @@ For more frequently asked questions, see the [FAQs](/manuals/desktop/troubleshoo ### New -- [Docker Agent](/manuals/ai/docker-agent/_index.md) is now available through Docker Desktop. +- [Docker Agent](/manuals/ai/docker-agent.md) is now available through Docker Desktop. - [Docker Debug](/reference/cli/docker/debug/) is now free for all users. ### Upgrades From 6e47cb23dae3a1b5610073bd15b995ae8ce6d16e Mon Sep 17 00:00:00 2001 From: David Karlsson <35727626+dvdksn@users.noreply.github.com> Date: Mon, 24 Aug 2026 08:53:19 +0000 Subject: [PATCH 3/3] docs: simplify Docker Agent redirects The initial removal added a Docker Agent-specific manifest for every former page and historical alias. Replace it with a generic fixed-target prefix redirect so all child paths under the retired section go to the upstream documentation homepage while the local overview remains available. --- data/docker_agent_redirects.yml | 126 ------------------ hack/releaser/cloudfront-lambda-redirects.js | 3 +- .../cloudfront-lambda-redirects.test.js | 44 ++---- hack/releaser/redirects-prefixes.json | 3 +- layouts/home.redirects.json | 9 -- 5 files changed, 10 insertions(+), 175 deletions(-) delete mode 100644 data/docker_agent_redirects.yml diff --git a/data/docker_agent_redirects.yml b/data/docker_agent_redirects.yml deleted file mode 100644 index 67724d4d7aee..000000000000 --- a/data/docker_agent_redirects.yml +++ /dev/null @@ -1,126 +0,0 @@ -# Exact redirects for Docker Agent pages formerly mounted on docs.docker.com. -# Keep this inventory when removing the Hugo module so stale HTML and Markdown -# URLs continue to resolve to their corresponding upstream documentation. -paths: - - community/contributing - - community/opentelemetry - - community/telemetry - - community/troubleshooting - - concepts/agents - - concepts/distribution - - concepts/models - - concepts/multi-agent - - concepts/tools - - configuration/agents - - configuration/agentsignore - - configuration/budget - - configuration/commands - - configuration/flavors - - configuration/hcl - - configuration/hooks - - configuration/models - - configuration/overview - - configuration/permissions - - configuration/routing - - configuration/sandbox - - configuration/structured-output - - configuration/tools - - configuration/user-settings - - features/a2a - - features/acp - - features/api-server - - features/board - - features/chat-server - - features/cli - - features/code-mode - - features/evaluation - - features/harnesses - - features/mcp-mode - - features/remote-mcp - - features/sessions - - features/skills - - features/snapshots - - features/tui - - getting-started/installation - - getting-started/introduction - - getting-started/quickstart - - getting-started/set-up-a-model - - guides/compaction - - guides/go-sdk - - guides/headless - - guides/secrets - - guides/thinking - - guides/tips - - providers/anthropic - - providers/baseten - - providers/bedrock - - providers/cerebras - - providers/chatgpt - - providers/cloudflare-ai-gateway - - providers/cloudflare-workers-ai - - providers/custom - - providers/deepseek - - providers/dmr - - providers/fireworks - - providers/github-copilot - - providers/google - - providers/groq - - providers/huggingface - - providers/local - - providers/minimax - - providers/mistral - - providers/moonshot - - providers/nebius - - providers/nvidia - - providers/openai - - providers/opencode-go - - providers/opencode-zen - - providers/openrouter - - providers/overview - - providers/ovhcloud - - providers/together - - providers/vercel - - providers/xai - - tools/a2a - - tools/api - - tools/background-agents - - tools/background-jobs - - tools/fetch - - tools/filesystem - - tools/git - - tools/handoff - - tools/lsp - - tools/mcp-catalog - - tools/mcp - - tools/memory - - tools/model-picker - - tools/open-url - - tools/openapi - - tools/plan - - tools/rag - - tools/scheduler - - tools/script - - tools/session_context - - tools/session_plan - - tools/shell - - tools/tasks - - tools/think - - tools/todo - - tools/transfer-task - - tools/user-prompt - - tools/webhook -aliases: - /ai/docker-agent/best-practices/: guides/tips - /ai/docker-agent/evals/: features/evaluation - /ai/docker-agent/integrations/a2a/: features/a2a - /ai/docker-agent/integrations/acp/: features/acp - /ai/docker-agent/integrations/mcp/: tools/mcp - /ai/docker-agent/local-models/: providers/local - /ai/docker-agent/model-providers/: providers/overview - /ai/docker-agent/providers/ollama/: providers/local - /ai/docker-agent/rag/: tools/rag - /ai/docker-agent/reference/cli/: features/cli - /ai/docker-agent/reference/config/: configuration/overview - /ai/docker-agent/reference/toolsets/: configuration/tools - /ai/docker-agent/sharing-agents/: concepts/distribution - /ai/docker-agent/tutorial/: getting-started/quickstart diff --git a/hack/releaser/cloudfront-lambda-redirects.js b/hack/releaser/cloudfront-lambda-redirects.js index 26abe82e9979..d7ab30b62896 100644 --- a/hack/releaser/cloudfront-lambda-redirects.js +++ b/hack/releaser/cloudfront-lambda-redirects.js @@ -53,8 +53,7 @@ exports.handler = (event, context, callback) => { if (!request.uri.startsWith(`/${rp["prefix"]}`)) { continue; } - const prefixRoot = `/${rp["prefix"]}`.replace(/\/$/, ""); - if (rp["excludeRoot"] && requestUrl === prefixRoot) { + if (rp["target"] && requestUrl === `/${rp["prefix"]}`.replace(/\/$/, "")) { continue; } let newlocation = "/"; diff --git a/hack/releaser/cloudfront-lambda-redirects.test.js b/hack/releaser/cloudfront-lambda-redirects.test.js index 3c232b392416..dcaab5920faf 100644 --- a/hack/releaser/cloudfront-lambda-redirects.test.js +++ b/hack/releaser/cloudfront-lambda-redirects.test.js @@ -22,19 +22,14 @@ const REDIRECTS = { "/target-with-query/": "/dest/?ref=docs", "/target-with-fragment/": "/dest/?ref=docs#install", "/external-target/": "https://www.docker.com/example?ref=docs#install", - "/ai/docker-agent/getting-started/quickstart/": - "https://docker.github.io/docker-agent/getting-started/quickstart/", - "/ai/docker-agent/getting-started/quickstart.md": - "https://docker.github.io/docker-agent/getting-started/quickstart/", }; const REDIRECTS_PREFIXES = [ { prefix: "keep/", strip: false }, { prefix: "strip/", strip: true }, { - prefix: "ai/docker-agent/", - target: "https://docker.github.io/docker-agent/", - excludeRoot: true, + prefix: "external/", + target: "https://example.com/docs/", }, ]; @@ -150,42 +145,19 @@ test("prefix redirect (no strip) preserves the query string", async () => { assert.equal(locationOf(result), "/?utm_source=x"); }); -test("external prefix redirect preserves the query string", async () => { +test("fixed-target prefix redirect preserves the query string", async () => { const { result } = await invoke({ - uri: "/ai/docker-agent/removed-page/", + uri: "/external/removed-page/", querystring: "utm_source=x", }); assert.equal(result.status, "301"); - assert.equal( - locationOf(result), - "https://docker.github.io/docker-agent/?utm_source=x", - ); -}); - -test("exact redirect takes precedence over an external prefix", async () => { - const { result } = await invoke({ - uri: "/ai/docker-agent/getting-started/quickstart/", - }); - assert.equal( - locationOf(result), - "https://docker.github.io/docker-agent/getting-started/quickstart/", - ); -}); - -test("markdown exact redirect takes precedence over an external prefix", async () => { - const { result } = await invoke({ - uri: "/ai/docker-agent/getting-started/quickstart.md", - }); - assert.equal( - locationOf(result), - "https://docker.github.io/docker-agent/getting-started/quickstart/", - ); + assert.equal(locationOf(result), "https://example.com/docs/?utm_source=x"); }); -test("external prefix redirect excludes the retained root page", async () => { - const { result, request } = await invoke({ uri: "/ai/docker-agent/" }); +test("fixed-target prefix redirect leaves the prefix root unchanged", async () => { + const { result, request } = await invoke({ uri: "/external/" }); assert.equal(result, request); - assert.equal(request.uri, "/ai/docker-agent/index.html"); + assert.equal(request.uri, "/external/index.html"); }); test("directory rewrite passes the request through with query string intact", async () => { diff --git a/hack/releaser/redirects-prefixes.json b/hack/releaser/redirects-prefixes.json index c08bd71b8a1c..07442442dbaa 100644 --- a/hack/releaser/redirects-prefixes.json +++ b/hack/releaser/redirects-prefixes.json @@ -1,8 +1,7 @@ [ { "prefix": "ai/docker-agent/", - "target": "https://docker.github.io/docker-agent/", - "excludeRoot": true + "target": "https://docker.github.io/docker-agent/" }, { "prefix": "compliance/", diff --git a/layouts/home.redirects.json b/layouts/home.redirects.json index 11fe4e98a0e9..9d7ed82c9f05 100644 --- a/layouts/home.redirects.json +++ b/layouts/home.redirects.json @@ -41,14 +41,5 @@ {{- $redirects.SetInMap "paths" . $target -}} {{- end -}} {{- end -}} -{{- range hugo.Data.docker_agent_redirects.paths -}} - {{- $target := printf "https://docker.github.io/docker-agent/%s/" . -}} - {{- $redirects.SetInMap "paths" (printf "/ai/docker-agent/%s/" .) $target -}} - {{- $redirects.SetInMap "paths" (printf "/ai/docker-agent/%s.md" .) $target -}} -{{- end -}} -{{- range $source, $targetPath := hugo.Data.docker_agent_redirects.aliases -}} - {{- $target := printf "https://docker.github.io/docker-agent/%s/" $targetPath -}} - {{- $redirects.SetInMap "paths" $source $target -}} -{{- end -}} {{- $opts := dict "noHTMLEscape" true }} {{- $redirects.Get "paths" | jsonify $opts }}