From 33571d335b5ca868b1eae86b5ba09302bc526492 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 16:33:53 -0500 Subject: [PATCH 1/8] init Signed-off-by: Rachael Graham --- .../content/kagent/1.x/about/core-concepts.md | 4 +- .../kagent/1.x/about/what-is-kagent.md | 2 +- .../kagent/1.x/agents/agent-harness.md | 268 +++++++++++++----- .../kagent/1.x/agents/bring-your-own-agent.md | 10 +- .../kagent/1.x/agents/structured-output.md | 2 +- .../operations/operational-considerations.md | 2 +- .../kagent/1.x/operations/upgrade-from-0x.md | 12 +- .../model-providers/about-model-providers.md | 12 +- 8 files changed, 219 insertions(+), 93 deletions(-) diff --git a/docs-site/content/kagent/1.x/about/core-concepts.md b/docs-site/content/kagent/1.x/about/core-concepts.md index 408b6052..6a8a0a64 100644 --- a/docs-site/content/kagent/1.x/about/core-concepts.md +++ b/docs-site/content/kagent/1.x/about/core-concepts.md @@ -63,12 +63,12 @@ Examples include [Claude Code](https://code.claude.com/docs/en/how-claude-code-w A **Harness** in kagent is a Kubernetes custom resource that applies that idea to a cluster. It defines _how an agent is allowed to run_, and specifies: -- **Runtime**: The engine that executes the agent. A Harness selects exactly one of `kagent`, `codex`, `claude`, or `byo`, and kagent compiles all four. `kagent` runs kagent's own agent engine, `codex` and `claude` run those coding agents, and `byo` runs any image that implements kagent's A2A contract. +- **Runtime**: The engine that executes the agent. A Harness selects exactly one of `kagent`, `codex`, `claude`, or `byo`. `kagent` runs kagent's own agent engine, `codex` runs Codex, `claude` runs Claude, and `byo` runs any image that implements kagent's A2A contract. The four runtimes accept different model providers and different AgentTemplate features. - **Workload**: The container image, command, and arguments that the runtime runs as. - **Environment**: Literal environment values for the runtime, set in `spec.env`. - **Substrate policy**: The capacity that the agent runs on, and where its state is kept when it goes idle. The Harness names a [WorkerPool]({{< link path="about/architecture/agent-substrate#workers-and-workerpools" >}}) to schedule onto and the storage location that snapshots write to. -A Harness names no AgentTemplate, and an AgentTemplate names no Harness. An [Agent](#agent) pairs the two, and nothing pairs them implicitly. Applying a Harness runs nothing on its own. It registers a runtime and policy that an Agent can select. +A Harness and an AgentTemplate do not reference each other. An [Agent](#agent) references both, and nothing pairs them implicitly. Applying a Harness runs nothing on its own. It registers a runtime and policy that an Agent can select. Each runtime accepts a different subset of configuration, and an Agent that asks for something its runtime cannot do reports a compatibility condition rather than running. For the per-runtime restrictions and the complete Harness schema, see the [API reference]({{< link path="reference/api-ref#harness" >}}). diff --git a/docs-site/content/kagent/1.x/about/what-is-kagent.md b/docs-site/content/kagent/1.x/about/what-is-kagent.md index 5fb8428d..be92a62e 100644 --- a/docs-site/content/kagent/1.x/about/what-is-kagent.md +++ b/docs-site/content/kagent/1.x/about/what-is-kagent.md @@ -33,7 +33,7 @@ kagent 1.0 separates an agent's capabilities from its runtime, then runs the two {{< feature-card title="Sandboxed by default" desc="Every Session runs on a Substrate Actor, isolated from the host kernel by a gVisor sandbox. Run untrusted, model-directed code safely." >}} {{< feature-card title="Suspend and resume" desc="Idle Sessions suspend and free their compute, then resume on demand. Run far more agents than you have capacity for at any one moment." >}} {{< feature-card title="Checkpoints" desc="Pin a snapshot of a conversation at a turn boundary so that Agent Substrate keeps the state for inspection and retention." >}} -{{< feature-card title="Pluggable agent runtimes" desc="A Harness selects the engine behind an agent: kagent's own Go and Python engines, the Codex or Claude coding agents, or any image of your own that speaks kagent's A2A contract." >}} +{{< feature-card title="Pluggable agent runtimes" desc="A Harness selects the engine behind an agent: kagent's own Go engine, Codex, Claude, or any image of your own that speaks kagent's A2A contract." >}} {{< feature-card title="Tools over MCP" desc="Bind an agent to any Model Context Protocol (MCP) server with a RemoteMCPServer resource. An installation registers two servers already, including 124 tools for Kubernetes, Helm, Istio, and Argo Rollouts." >}} {{< feature-card title="Agent tools" desc="Bind another AgentTemplate as a tool, so an agent can hand work to a specialist. A Shared binding nests that agent inside its parent's Actor, one level deep." >}} {{< feature-card title="Long-term memory" desc="Persistent, vector-backed memory across sessions. Agents remember context, not just the last prompt." >}} diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index 30106f52..b63b867b 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -5,11 +5,13 @@ weight: 10 author: kagent.dev --- -Review configuration guidelines and reference for the `Harness` resource: every field it takes, the four runtimes it can select, and what each runtime supports. To understand a Harness and why an Agent, rather than the Harness itself, names the AgentTemplate that runs on it, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). +A Harness defines how an agent is allowed to run. It selects the runtime that executes the agent, the container image that runtime starts from, and the Agent Substrate capacity and snapshot storage that the agent runs on. A Harness runs nothing by itself. To run an agent, create an Agent that references a Harness and an AgentTemplate, which supplies the system prompt, the model, and the tools. + +This page covers the Harness schema, the four runtimes it can select, and what each runtime supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). ## Configure a Harness -The following configuration is for a complete Harness resource. Only `workload`, `substrate`, and one runtime block are required. +The following configuration shows a complete Harness. Only `workload`, `substrate`, and one runtime block are required. ```yaml kubectl apply -f - <}}). Note that the kagent installation's settings, such as the runtime log level, come from the Helm chart's `config.runtimeDefaults` block rather than from this setting. | +| `env` | No | Environment variables for the runtime, up to 100 entries. Each entry sets a literal `value`, which is required and can be an empty string. The schema defines no secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials on a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Some names are reserved. For more information, see [Reserved environment variables](#reserved-environment-variables). | | `substrate.workerPoolRef.name` | Yes | The {{< gloss "WorkerPool" >}}WorkerPool{{< /gloss >}} that this Harness's Actors are scheduled onto. An operator must provision one before any agent can run. | | `substrate.snapshotPolicy.location` | Yes | The object storage location for Actor {{< gloss "Snapshot" >}}snapshots{{< /gloss >}}. | -A Harness names no AgentTemplate. An {{< gloss "Agent" >}}Agent{{< /gloss >}} pairs the two through `spec.harnessRef`, so whoever writes the Agent decides which template runs on which Harness. `spec.harnessRef` takes a reference only, so a Harness must exist before an Agent can name it. For more information about the pairing, see [Core concepts]({{< link path="about/core-concepts#agent" >}}). +> [!NOTE] +> Although the schema accepts up to 100 `env` entries, Agent Substrate accepts at most 32 environment variables on an Actor. The controller adds its own variables to every revision, such as the agent configuration and the certificate trust settings, and those count toward the limit. A revision that exceeds 32 reports `runtime revision has environment variables; Substrate supports at most 32`. + +A Harness and an AgentTemplate do not reference each other. An {{< gloss "Agent" >}}Agent{{< /gloss >}} references both, through `spec.harnessRef` and `spec.template.ref`, so whoever writes the Agent decides which template runs on which Harness. Both fields take a reference only, so the Harness must exist before an Agent can name it. For more information about the pairing, see [Core concepts]({{< link path="about/core-concepts#agent" >}}). -A command or argument override belongs to the revision that kagent prepares. Changing one prepares a new revision rather than altering a running agent. A {{< gloss "Session" >}}Session{{< /gloss >}} pinned to an earlier revision keeps the command it was prepared with until it moves to the new one. +The image, command, arguments, environment, and resolved AgentTemplate together form a {{< gloss "Revision" >}}revision{{< /gloss >}}, which kagent identifies by a digest of that content. Editing any of them produces a new revision at the next reconcile. A {{< gloss "Session" >}}Session{{< /gloss >}} runs the revision that it was created from until that Session ends, so only Sessions that start after the edit use the new revision. ## Choose a runtime @@ -56,18 +61,20 @@ A Harness names exactly one of the following four runtimes, and that choice deci | Runtime | What it runs | When to use it | | ------- | ------------ | ----------- | -| `kagent` | kagent's own Go and Python engines | You want the full feature set: every model provider, agent-as-tool composition, skills, plugins, and long-term memory. | -| `codex` | The Codex coding agent | You want Codex to do the work, and your model is OpenAI or an OpenAI-compatible Bedrock deployment. | -| `claude` | The Claude coding agent | You want Claude to do the work, with Anthropic, Bedrock, or Anthropic on Vertex AI as the model. | -| `byo` | Any container image of your own that implements kagent's A2A contract | You have an agent framework kagent does not adapt, and you would rather bring the image than the integration. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | +| `kagent` | kagent's built-in Go engine | You want to define the agentic loop through configuration, with a system prompt, skills, plugins, and MCP servers, rather than by writing an agent. This runtime also supports the widest set of features. | +| `codex` | Codex | You want Codex to do the work, and your model is OpenAI or an OpenAI-compatible Bedrock deployment. | +| `claude` | Claude | You want Claude to do the work, with Anthropic or Bedrock as the model. | +| `byo` | A container image of your own that implements kagent's A2A contract | You already have an agent that is built with an agent framework, and you want to run that agent in kagent. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | -The `kagent` and `byo` runtimes compile through the same path, so they accept the same model providers and the same AgentTemplate features, except [structured output]({{< link path="agents/structured-output" >}}), which only the `kagent` runtime supports. The `codex` and `claude` runtimes are purpose-built adapters, and each accepts a narrower slice. +The runtimes differ in two ways that decide what an agent on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. -The agent chat in the kagent UI allows file attachments only on the `kagent` runtime, so an agent on a `byo`, `codex`, or `claude` Harness has no attachment option in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). +The agent chat in the kagent UI offers file attachments only on the `kagent` runtime. An agent on a `byo`, `codex`, or `claude` Harness has no option to attach files in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). -### Runtime-specific settings +### kagent runtime -`spec.kagent` is the only runtime block that takes settings of its own. The rest are empty. +The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins instead of writing one. Three features are available on this runtime alone: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. + +`spec.kagent` is the only runtime block that takes settings of its own. The other three runtimes take their configuration from the AgentTemplate and the ModelConfig, so their blocks are empty. ```yaml spec: @@ -76,24 +83,86 @@ spec: modelConfigRef: name: embedding-model-config ttlDays: 30 + compaction: + tokenThreshold: 120000 + eventRetentionSize: 20 ``` +The settings fall into two groups. Memory persists facts across conversations, and compaction keeps a single conversation's prompt bounded as the conversation grows. + | Field | Description | | ----- | ----------- | -| `memory.modelConfigRef.name` | The ModelConfig supplying the embedding model, in the Harness's namespace. Required when `memory` is set. | +| `memory.modelConfigRef.name` | The ModelConfig supplying the embedding model, in the Harness's namespace. Required when `memory` is set. Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). | | `memory.ttlDays` | How many days a stored memory entry stays valid. Minimum 1. When omitted, the server applies a default of 15 days. | +| `compaction.tokenThreshold` | The prompt token count at which kagent summarizes the history before the next model call. Set it with `compaction.eventRetentionSize`. | +| `compaction.eventRetentionSize` | The number of most recent events that stay uncompacted. Set it with `compaction.tokenThreshold`. | +| `compaction.compactionInterval` | The number of new user-initiated invocations that triggers a sliding-window compaction of those invocations. An alternative to the two tail-retention settings, and `compaction` requires one strategy or the other. | +| `compaction.overlapSize` | The number of already-compacted invocations pulled back into the next window, so that consecutive summaries overlap. Requires `compaction.compactionInterval`. | +| `compaction.summarizer` | The ModelConfig and prompt template that write the summaries. When omitted, kagent summarizes with the agent's own model and the runtime's default prompt. | -Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). +For the two compaction strategies and the rules that the API server enforces on them, see [Context management]({{< link path="agents/context-management" >}}). + +The following example applies a complete `kagent` agent, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. + +```yaml +kubectl apply -f - <}} + substrate: + workerPoolRef: + name: kagent-default + snapshotPolicy: + location: s3://ate-snapshots/kagent/ +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: AgentTemplate +metadata: + name: kagent-template + namespace: kagent +spec: + modelConfig: + name: kagent-model-config + systemPrompt: You are a concise, helpful assistant. +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: Agent +metadata: + name: my-agent + namespace: kagent +spec: + template: + ref: + name: kagent-template + harnessRef: + name: kagent-harness +EOF +``` -Setting `compaction` summarizes older session events so an agent's prompt stays bounded as a conversation grows. For the two strategies and the rules the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). +### Codex runtime -### Codex and Claude examples +The `codex` runtime runs Codex against an OpenAI or Bedrock model. The runtime block takes no settings. Codex accepts a narrower set of AgentTemplate features than the built-in runtime, and the restrictions are in [Tool and skill support](#tool-and-skill-support). -A `codex` or `claude` Harness has the same shape as a `kagent` one, and differs in the runtime block, the image, and the ModelConfigs that it accepts. For the providers and settings that each runtime accepts, see [Model provider support](#model-provider-support), and for the limits each one places on an AgentTemplate, see [Tool and skill support](#tool-and-skill-support). +The ModelConfig must set `openAI.apiFormat: responses`, and the API key must be entitled to the model that you name. A key without access to that model fails the turn with `Codex execution failed`. The ModelConfig in the following example reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. -{{< tabs >}} -{{% tab name="Codex" %}} -The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. The key must be entitled to the model that you name. A key without access to it fails the turn with `Codex execution failed`. ```yaml kubectl apply -f - <}}) guide creates. + +### Claude runtime + +The `claude` runtime runs Claude against an Anthropic or Bedrock model. The runtime block takes no settings. Claude accepts a narrower set of AgentTemplate features than the built-in runtime, and the restrictions are in [Tool and skill support](#tool-and-skill-support). + +The ModelConfig in the following example reads its API key from the `kagent-anthropic` Secret that the [Anthropic]({{< link path="setup/model-providers/anthropic#create-the-modelconfig" >}}) guide creates. + ```yaml kubectl apply -f - <}} + +### BYO runtime + +The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent rather than rebuild it. The runtime block takes no settings, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. + +A `byo` revision is compiled the same way as a `kagent` one, so a BYO image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, and the `kagent` runtime alone supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the A2A contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). + +```yaml +kubectl apply -f - </my-agent@sha256: + command: ["/my-agent"] + substrate: + workerPoolRef: + name: kagent-default + snapshotPolicy: + location: s3://ate-snapshots/kagent/ +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: AgentTemplate +metadata: + name: byo-template + namespace: kagent +spec: + description: An agent that runs from my own image. +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: Agent +metadata: + name: byo-agent + namespace: kagent +spec: + template: + ref: + name: byo-template + harnessRef: + name: byo-harness +EOF +``` ## Model provider support -The runtime that a Harness selects decides which ModelConfig an Agent that runs on it can use. This table covers every value that the ModelConfig `provider` field accepts, including the four that kagent 1.0 rejects on every runtime. +The runtime that a Harness selects decides which ModelConfig an Agent that runs on it can use. The following table covers every value that the ModelConfig `provider` field accepts, including the three that no runtime accepts with a credential Secret. | Provider | `kagent` | `byo` | `codex` | `claude` | | -------- | :------: | :---: | :-----: | :------: | | `OpenAI` | ✅ | ✅ | ✅ | ❌ | | `Anthropic` | ✅ | ✅ | ❌ | ✅ | | `Bedrock` | ✅ | ✅ | ✅ | ✅ | -| `AnthropicVertexAI` | ❌ | ❌ | ❌ | ❌ | -| `GeminiVertexAI` | ❌ | ❌ | ❌ | ❌ | | `AzureOpenAI` | ✅ | ✅ | ❌ | ❌ | | `Gemini` | ✅ | ✅ | ❌ | ❌ | +| `Mistral` | ✅ | ✅ | ❌ | ❌ | | `Ollama` | ✅ | ✅ | ❌ | ❌ | -| `SAPAICore` | ❌ | ❌ | ❌ | ❌ | | `Foundry` | ✅ | ✅ | ❌ | ❌ | -| `Mistral` | ❌ | ❌ | ❌ | ❌ | +| `AnthropicVertexAI` | ❌ | ❌ | ❌ | ❌ | +| `GeminiVertexAI` | ❌ | ❌ | ❌ | ❌ | +| `SAPAICore` | ❌ | ❌ | ❌ | ❌ | -kagent rejects `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore` on every runtime, because each authenticates with a credential that the egress gateway cannot place in an HTTP header. No agent can use these providers. For the alternatives, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). +kagent reaches a model provider through the egress gateway, which holds the credential and adds it to each request as an HTTP header. The three rejected providers authenticate in a way that this design cannot serve, and they fail in two different ways. -kagent rejects `Mistral` for a different reason. The controller does not resolve the provider at all, so a Mistral ModelConfig reports `unsupported model provider: Mistral`. +* `AnthropicVertexAI` and `GeminiVertexAI` authenticate with a Google service account key, which kagent would have to mount as a file. An Actor takes no volumes, so a ModelConfig that names a credential Secret is rejected with `ModelConfig requires volume mounts unsupported by Substrate ActorTemplate`. +* `SAPAICore` authenticates with an OAuth client ID and secret, which the runtime exchanges for a token itself. A ModelConfig that names a credential Secret is rejected with `environment credential "" cannot use gateway header injection`. Some supported combinations still carry restrictions. | Combination | Restriction | | ----------- | ----------- | -| `codex` with `OpenAI` | Requires `openAI.apiFormat: responses`, and does not accept any other `openAI` setting beyond `baseUrl`. | +| `codex` with `OpenAI` | Requires `openAI.apiFormat: responses`, and accepts no other `openAI` setting beyond `baseUrl`. | | `codex` with `Bedrock` | Accepts only OpenAI `gpt-*` model IDs, and no `bedrock` settings beyond `region`. | | `claude` with `Anthropic` | Accepts no `anthropic` settings beyond `baseUrl`. | | `claude` with `Bedrock` | Accepts no `bedrock` settings beyond `region`. | -| `Bedrock` on any runtime | The Secret must hold an `AWS_BEARER_TOKEN_BEDROCK` key. A Secret of IAM access keys is rejected, because IAM signs each request locally. | - -> [!IMPORTANT] -> Neither `codex` nor `claude` accepts a ModelConfig that sets `defaultHeaders`, `tls`, or `apiKeyPassthrough`. Separately, every runtime rejects a credential that the egress gateway cannot place in an HTTP header, such as an IAM key pair or a Google service account key. For more information about that limitation, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). +| `Bedrock` on any runtime | The Secret must hold an `AWS_BEARER_TOKEN_BEDROCK` key. A Secret of IAM access keys is rejected with `cannot use gateway header injection`, because IAM signs each request locally rather than sending a static header. | +| `codex` and `claude` with any provider | Neither runtime accepts a ModelConfig that sets `defaultHeaders`, `tls`, or `apiKeyPassthrough`. | ## Tool and skill support -The coding-agent runtimes also constrain what an AgentTemplate can ask for. +The `kagent` runtime accepts every AgentTemplate feature. Codex and Claude run agentic loops of their own, so each constrains what an AgentTemplate can ask for. The `byo` runtime takes the same set as the built-in runtime, apart from structured output. | Constraint | Applies to | | ---------- | ---------- | | A subagent binding cannot itself carry tools, skills, plugins, or nested agents, and must use the same provider and credentials as the agent that binds it. | `codex`, `claude` | -| An {{< gloss "MCP" >}}MCP{{< /gloss >}} server is bound whole. Claude does not support partial tool selection, so the agent sees every tool the server offers rather than only the ones a binding names. The compiler warns rather than failing. | `claude` | -| A `RemoteMCPServer` must use the `STREAMABLE_HTTP` protocol. `SSE` is rejected. | `codex` | +| An {{< gloss "MCP" >}}MCP{{< /gloss >}} server is bound whole. Claude does not support partial tool selection, so the agent sees every tool that the server offers rather than only the ones that a binding names. The Agent still reconciles, and reports the decision in `status.warnings` as `Claude RemoteMCPServer "" does not support partial tool selection`. | `claude` | +| A RemoteMCPServer must use the `STREAMABLE_HTTP` protocol. `SSE` is rejected. | `codex` | +| Structured output is rejected, with `Harness runtime "" does not support structured output`. | `codex`, `claude`, `byo` | -The `kagent` and `byo` runtimes take the full set. For more information about what an AgentTemplate can bind, see [About tools]({{< link path="skills-and-mcp/about-tools" >}}). +For more information about what an AgentTemplate can bind, see [About tools]({{< link path="skills-and-mcp/about-tools" >}}). ## Telemetry content settings -Tracing carries the prompts and replies that an agent exchanges with a model, and so does log export on the `claude` runtime. Two settings in the kagent Helm chart decide whether that content leaves the runtime, and each one reaches a different set of runtimes. Both default to `false`, and both take effect only where tracing or log export is already enabled. +Enabling content capture puts the prompts and replies that an agent exchanges with a model into your telemetry backend, where anyone with access to that backend can read them. Both settings that do this default to `false`, and both take effect only where tracing or log export is already enabled. Set them in the kagent Helm chart. ```yaml config: @@ -265,48 +382,50 @@ config: maxCaptureBytes: 16384 ``` +The two capture settings differ in how much they return and which runtimes read them. The third setting bounds the size of what either one captures. + | Setting | What it includes | Applies to | | ------- | ---------------- | ---------- | -| `config.runtimeDefaults.telemetry.captureContent` | Prompts and assistant replies in the runtime's telemetry. On the `kagent` runtime, the content appears in the span for each model call. That runtime records a tool call's arguments and reply on the span for the tool call instead, regardless of this setting. On the `claude` runtime, tool results require tracing, and assistant replies require log export through `config.runtimeDefaults.telemetry.logs`. | `kagent`, `codex`, `claude` | +| `config.runtimeDefaults.telemetry.captureContent` | Prompts and assistant replies. On the `kagent` runtime, the content appears in the span for each model call. That runtime records a tool call's arguments and reply on the span for the tool call instead, whatever this setting is. On the `claude` runtime, tool results need tracing, and assistant replies need log export through `config.runtimeDefaults.telemetry.logs`. | `kagent`, `codex`, `claude` | | `config.runtimeDefaults.telemetry.captureRawApiBodies` | The complete provider API request and response bodies. This setting returns more than `captureContent` does, and it takes effect only when you set the logs endpoint. | `claude` | | `config.runtimeDefaults.telemetry.maxCaptureBytes` | The budget for each captured prompt or reply, in bytes. Defaults to `16384`, with a maximum of `65536`. | `codex`, `claude` | -The controller sets `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` in every compiled runtime from `config.runtimeDefaults.telemetry.captureContent`, so a Harness cannot change the capture decision for itself. Naming that variable in the Harness `spec.env` field fails the `claude` and `codex` runtimes outright, and is discarded on the `kagent` runtime. For the rest of the variables that behave this way, see [Controller-owned telemetry variables](#controller-owned-telemetry-variables). +These settings are the installation's default. To change the capture decision for one Harness, set `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` in that Harness's `spec.env` field. The `kagent`, `codex`, and `claude` runtimes all read the variable and apply it in place of the installation default. Set `SPAN_ONLY` to put prompts and replies on spans, or `NO_CONTENT` to turn capture off. -The controller compiles the telemetry environment into the `byo` runtime as well whenever any signal is enabled, so `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` reaches a `byo` image. The `byo` runtime is the exception to the ownership rule. The controller applies the Harness `spec.env` field after the telemetry environment, so a `spec.env` entry wins where the two name the same variable, and an image that exports to its own backend keeps doing so. Whether the image acts on either setting depends on its own instrumentation. For more information, see [Tracing]({{< link path="observability/tracing#about-trace-coverage" >}}). +A `byo` image receives the same variable whenever any signal is enabled, but whether the image acts on it depends on its own instrumentation. An image that exports to its own backend keeps doing so. For more information, see [Tracing]({{< link path="observability/tracing#about-trace-coverage" >}}). -## Controller-owned telemetry variables +## Reserved environment variables -The controller compiles an installation's telemetry decisions into every runtime revision, so a Harness cannot override them through its `spec.env` field. The controller owns the following variables. +An installation's telemetry settings reach a runtime as defaults rather than as fixed values. Where a Harness `spec.env` entry names the same variable, the Harness value wins, which is how one Harness tunes exporter behavior for the agents that run on it. Two sets of names are reserved instead, and a Harness that names one of them is rejected. -* `OTEL_SDK_DISABLED` and `OTEL_SERVICE_NAME` -* `OTEL_EXPORTER_OTLP_ENDPOINT`, `OTEL_EXPORTER_OTLP_PROTOCOL`, and `OTEL_EXPORTER_OTLP_TIMEOUT` -* `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER`, and `OTEL_LOGS_EXPORTER` -* `OTEL_EXPORTER_OTLP__ENDPOINT` and `OTEL_EXPORTER_OTLP__PROTOCOL`, where `` is `TRACES`, `METRICS`, or `LOGS` -* `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` +Every runtime reserves the certificate trust variables, because the egress gateway intercepts HTTPS and each runtime must trust the gateway's certificate authority to reach a model at all. -A runtime that meets one of these names in `spec.env` either refuses the Harness or discards the entry, as described in the following table. +* `SSL_CERT_FILE` and `SSL_CERT_DIR` +* `REQUESTS_CA_BUNDLE`, `AWS_CA_BUNDLE`, and `CURL_CA_BUNDLE` +* `NODE_EXTRA_CA_CERTS` +* `GIT_SSL_CAINFO` -| Runtime | Result of naming a controller-owned variable in `spec.env` | -| ------- | ---------------------------------------------------------- | -| `claude` | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Claude-owned runtime configuration`. | -| `codex` | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Codex's compiled configuration`. | -| `kagent` | The entry is dropped and the controller's own value is compiled in its place. No error is reported. | +A Harness that names one of these variables reports `runtime environment "" conflicts with gateway trust`. -Two further variables fall outside that table: +The `codex` and `claude` runtimes each reserve a second set, which covers the credentials and runtime state that their adapters write. The `kagent` and `byo` runtimes reserve nothing beyond the trust variables. -* `OTEL_RESOURCE_ATTRIBUTES` is merged rather than refused. The value in `spec.env` is kept, and the agent identity attributes that the controller adds win where the two name the same attribute. -* `OTEL_EXPORTER_OTLP_HEADERS` is neither owned nor rendered. No Helm setting produces it, so the controller never adds it to a runtime, but a value in the Harness `spec.env` field reaches every runtime unchanged. To attach headers without holding them in an Actor environment, export to an in-cluster collector that adds them. +| Runtime | Also reserved | Result | +| ------- | ------------- | ------ | +| `claude` | The Anthropic, AWS, and Vertex AI credential variables, `CLAUDE_CONFIG_DIR`, `DISABLE_UPDATES`, `IS_SANDBOX`, `CLAUDE_CODE_ENABLE_TELEMETRY`, `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA`, `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, Claude's `OTEL_LOG_*` capture flags, `TRACEPARENT`, `TRACESTATE`, and the Prometheus exporter host and port | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Claude-owned runtime configuration`. | +| `codex` | `CODEX_HOME`, `OPENAI_API_KEY`, `AWS_REGION`, `AWS_BEARER_TOKEN_BEDROCK`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Codex's compiled configuration`. | -Every other `OTEL_*` variable, such as the `OTEL_BSP_*` batch span processor settings, stays available for per-Harness tuning. +Two variables take a value from a Harness without replacing the controller's. + +* `OTEL_RESOURCE_ATTRIBUTES` is merged rather than replaced. The value in `spec.env` is kept, and the agent identity attributes that the controller adds win where the two name the same attribute. +* `OTEL_EXPORTER_OTLP_HEADERS` has no controller value to replace. No Helm setting produces it and the controller never adds it, but a value in `spec.env` reaches every runtime unchanged. To attach headers without holding them in an Actor environment, export to an in-cluster collector that adds them. ### Baggage propagation Baggage is a W3C header that travels with a request alongside its trace context. Each entry in that header is a member, which pairs a name with a string value. Every service that the request reaches can read the members that it carries. -When the environment leaves `OTEL_PROPAGATORS` unset, kagent runtimes set it to `tracecontext`. A caller's baggage does not reach the tools that an agent calls or the agent's model provider, but trace context still propagates. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value only from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the kagent controller. +By default, a kagent runtime sets `OTEL_PROPAGATORS` to `tracecontext`, which carries trace context and drops baggage. A caller's baggage therefore does not reach the tools that an agent calls or the agent's model provider. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the controller. -`OTEL_PROPAGATORS` is a list of wire formats that apply to both incoming and outgoing requests. If an incoming request has a format that is not in the list, the format is not read. Similarly, the runtime does not write an omitted format to an outgoing one. When the list omits `baggage`, the runtime's own members are dropped too. +`OTEL_PROPAGATORS` is a list of wire formats that apply to both incoming and outgoing requests. If an incoming request has a format that is not in the list, the format is not read. Similarly, the runtime does not write an omitted format to an outgoing request. When the list omits `baggage`, the runtime's own members are dropped too. When `baggage` is listed, the `kagent` runtime adds the request's identity to the baggage of each model call and each MCP tool call. @@ -323,21 +442,28 @@ These members serve as identifiers only, and the runtime can replace a caller's > **Enabling baggage sends the caller's own members to your model provider.** A caller baggage member that kagent does not replace is forwarded unchanged in the `baggage` header of each model API request and each MCP request. This means that a caller controls what reaches those external services in the header. Enable baggage only where you trust what your callers attach. Review and plan for the following considerations. -* The `claude` and `codex` runtimes receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The Python runtime does not add any either, so the four members reach the `kagent` runtime alone. +* The `claude` and `codex` runtimes receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The four members reach the `kagent` runtime alone. * kagent never copies a baggage member onto a span. To make these values searchable, add a baggage-to-attributes span processor to the service that receives the request or to its OpenTelemetry Collector. When an agent requires an MCP server, the first tool listing or tool call opens a session with the MCP server, and every later request to that server shares it. The session makes three requests: the event stream, the replies to server requests, and the close. These requests do not carry trace context or baggage, because these name a request that has already ended. -## Check that a Harness is ready +## Check that an agent can run + +A Harness reports no status of its own. The `READY` column in `kubectl get harness` output is always empty, and `kubectl describe harness` shows no conditions, because nothing writes them. + +The Agent reports for all three resources instead, because an AgentTemplate reports no status of its own either. -The `READY` column reports whether a Harness's dependencies resolved. ```bash -kubectl get harness -n kagent +kubectl get agent -n kagent ``` -A Harness that is not `Ready` most often names a WorkerPool that does not exist yet. For the specific reason, read its conditions with `kubectl describe harness -n kagent`. +An Agent that is not `Ready` carries the reason in its conditions. `ResolvedRefs` reports whether the resources that the Agent depends on exist, which covers the Harness, the AgentTemplate, and the ModelConfig, and also the WorkerPool that the Harness names. A missing pool is the most common cause, and it reports the reason `WorkerPoolNotFound`. `Compatible` reports whether the resolved configuration is one that the Harness's runtime accepts, which is where a rejected provider, a reserved environment variable, or an unsupported AgentTemplate feature appears. `Ready` reports whether Agent Substrate finished preparing the agent's capacity. + +```bash +kubectl describe agent -n kagent +``` -`Ready` covers the Harness's own dependencies, not whether a given agent runs on it. Whether a template compiles against this Harness is reported on the Agent that pairs the two, because an AgentTemplate does not report status of its own. For that check and the conditions it reports, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). +An Agent can also reconcile and still report a non-blocking decision in `status.warnings`, such as Claude binding an MCP server whole. For the conditions in full, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). ## Next steps diff --git a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md index 4b30bbfb..122bc7a8 100644 --- a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md +++ b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md @@ -5,7 +5,7 @@ weight: 20 author: kagent.dev --- -The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still compiles the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} into a {{< gloss "Revision" >}}revision{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this runtime when you have an agent framework that kagent does not adapt, and you would rather bring the image than the integration. +The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still compiles the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} into a {{< gloss "Revision" >}}revision{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent rather than rebuild it. ## What kagent runs and what your image runs @@ -43,12 +43,12 @@ A `byo` image must meet four requirements to run as an agent. kagent enforces on ## Opaque and configured agents -kagent compiles an AgentTemplate for a `byo` Harness in the same way as for the `kagent` runtime, then hands the result to the container. The two ways of using this runtime differ only in whether the image reads it. +kagent resolves an AgentTemplate for a `byo` Harness in the same way as for the `kagent` runtime, then hands the result to the container. The two ways of using this runtime differ only in whether the image reads it. - **An opaque agent ignores the compiled configuration.** The AgentTemplate exists to give the agent an identity and a description, and the image decides everything else, including which model to call and which tools to offer. Every field on an opaque AgentTemplate is optional, `modelConfig` included. - **A configured agent reads the compiled configuration.** The image honors the AgentTemplate's system prompt, ModelConfig, tool bindings, skills, and plugins, so an operator changes the agent's behavior by editing the AgentTemplate rather than by rebuilding the image. -The `kagent` and `byo` runtimes compile through the same path, so a configured BYO agent accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). +kagent builds a revision for the `byo` runtime the same way as for the `kagent` runtime, so a configured BYO agent accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). Both kinds of agent receive the same inputs. Agent Substrate delivers the two JSON payloads as private environment variables, and the kagent helpers write them to files before the agent starts. An image in another language either reads the files that `MaterializeFromEnv` writes or parses the variables itself. @@ -56,7 +56,7 @@ Both kinds of agent receive the same inputs. Agent Substrate delivers the two JS | ----- | -------- | | `KAGENT_CONFIG_JSON`, which the helpers write to `/config/config.json` | The compiled agent configuration, including the resolved system prompt, the model and its settings, every tool, skill, and plugin that the AgentTemplate binds, and a `runtime` object that sets the process settings. | | `KAGENT_AGENT_CARD_JSON`, which the helpers write to `/config/agent-card.json` | The agent card that kagent advertises for this agent, rendered as JSON. | -| Anything in `spec.env` | Literal values and `credentialRef` lookups from the Harness, resolved before the Actor starts. Agent Substrate accepts at most 32 environment variables on an Actor, and the compiled configuration counts toward that limit. A revision that exceeds it fails to compile rather than starting and misbehaving. | +| Anything in `spec.env` | The literal values that the Harness sets. The field takes no secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected rather than starting and misbehaving. | The `runtime` object is the root of the configuration document, and subagents inherit it. The object includes the settings that a process needs before it serves a request. @@ -226,7 +226,7 @@ The kagent helpers read `KAGENT_CONFIG_JSON` and materialize its contents into ` - **The A2A interface is fixed.** kagent advertises `http://127.0.0.1:80` over gRPC, and `spec.byo` does not take a field that changes the address, the port, or the protocol. An image that serves A2A over HTTP JSON-RPC alone cannot run on this runtime. - **The `kagent-langgraph` and `kagent-crewai` adapters do not qualify yet.** Both build a FastAPI application with A2A JSON-RPC routes and no gRPC server, so neither satisfies the contract as shipped. Running LangGraph or CrewAI under `byo` currently means serving A2A over gRPC yourself. -- **Long-term memory is unavailable.** Memory is configured under `spec.kagent.memory` and wired only by the `kagent` runtime's compiler. A `byo` Harness has no equivalent setting. For what a BYO image would need to replace, see [Agent memory]({{< link path="agents/agent-memory" >}}). +- **Long-term memory is unavailable.** Memory is configured under `spec.kagent.memory`, and only the `kagent` runtime wires it up. A `byo` Harness has no equivalent setting. For what a BYO image would need to replace, see [Agent memory]({{< link path="agents/agent-memory" >}}). - **A broken port mapping presents as a healthy agent.** For the failure and what avoids it, see [The A2A contract](#the-a2a-contract). ## Next steps diff --git a/docs-site/content/kagent/1.x/agents/structured-output.md b/docs-site/content/kagent/1.x/agents/structured-output.md index 98170e6c..1fabd7b1 100644 --- a/docs-site/content/kagent/1.x/agents/structured-output.md +++ b/docs-site/content/kagent/1.x/agents/structured-output.md @@ -19,7 +19,7 @@ The schema goes in one of two AgentTemplate fields, `spec.outputSchema` or `spec 1. [Create your first agent]({{< link path="get-started/your-first-agent" >}}), so that you have the `my-first-harness` Harness and the `default-model-config` {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} that the AgentTemplates in this guide use. That guide also has you install the kagent CLI and `jq`. - Structured output needs a Harness that uses the `kagent` runtime with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` runtime block and the same `workload.image` as `my-first-harness`. With the `codex`, `claude`, or `byo` runtime, an Agent whose template sets a schema fails to compile. With the `kagent` runtime and an image of kagent's Python engine, the AgentTemplate compiles, but the agent ignores the schema. For the differences between runtimes, see [Agent harness]({{< link path="agents/agent-harness#choose-a-runtime" >}}). + Structured output needs a Harness that uses the `kagent` runtime with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` runtime block and the same `workload.image` as `my-first-harness`. With the `codex`, `claude`, or `byo` runtime, an Agent whose template sets a schema is rejected with `Harness runtime "" does not support structured output`. For the differences between runtimes, see [Agent harness]({{< link path="agents/agent-harness#choose-a-runtime" >}}). 2. Check your kagent CLI version. The steps on this page need the {{< reuse "kagent-docs/versions/kagent.md" >}} CLI. A CLI from another release can fail with `unknown command`. ```bash diff --git a/docs-site/content/kagent/1.x/operations/operational-considerations.md b/docs-site/content/kagent/1.x/operations/operational-considerations.md index 411363a2..3ca4930a 100644 --- a/docs-site/content/kagent/1.x/operations/operational-considerations.md +++ b/docs-site/content/kagent/1.x/operations/operational-considerations.md @@ -57,7 +57,7 @@ After you change these values, you can verify their validity by checking the con The only section of settings that the controller does not apply to itself is `config.runtimeDefaults`. The controller compiles those settings into each agent runtime that it starts. If you want a setting to apply to both the controller and the agents, such as the log level, the telemetry endpoints, or the content capture decision, you must configure that setting in both `config` and `config.runtimeDefaults`. -The controller compiles each `config.runtimeDefaults` setting into the runtime's configuration document rather than passing it as an environment variable, so a Harness cannot override one of these settings through its `spec.env` field. A Harness tunes only the standard `OTEL_*` variables that the controller does not own, such as the `OTEL_BSP_*` batch span processor settings. For the variables that the controller does own, see [Controller-owned telemetry variables]({{< link path="agents/agent-harness#controller-owned-telemetry-variables" >}}). +A `config.runtimeDefaults` setting is the installation's default rather than a fixed value. A Harness can replace most of them for the agents that run on it, by naming the equivalent variable in its `spec.env` field. A small set of names is reserved instead, such as the certificate trust variables that let a runtime reach the egress gateway. For the reserved names and the per-runtime differences, see [Reserved environment variables]({{< link path="agents/agent-harness#reserved-environment-variables" >}}). ## Choose a database diff --git a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md index ee3d0d93..fc1de1f4 100644 --- a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md +++ b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md @@ -136,19 +136,19 @@ Four resource kinds are removed rather than replaced, so plan for each one befor ## Verify the new installation -Confirm that the resources resolved before you retire anything, because a Harness that is missing a dependency reports the reason on itself. +Confirm that the resources resolved before you retire anything. Neither a Harness nor an AgentTemplate reports status of its own, so the Agent that references both is where every problem surfaces. -1. Check that each Harness is ready. A Harness that is not ready most often names a WorkerPool that does not exist. +1. Check that each Agent is ready. ```bash - kubectl get harness -n kagent + kagent agent list ``` -2. Check that each Agent compiled. An AgentTemplate does not report status, so the Agent that pairs it with a Harness is where readiness is reported. +2. Read the conditions on any Agent that is not ready. `ResolvedRefs` reports a missing reference, and a Harness that names a WorkerPool that does not exist is the most common cause. ```bash - kagent agent list + kubectl describe agent -n kagent ``` -3. Create a Session against a migrated Agent and send it a message. A reply confirms the whole path, from the compiled revision to the model credentials. +3. Create a Session against a migrated Agent and send it a message. A reply confirms the whole path, from the revision to the model credentials. ```bash kagent agent session create --agent ``` diff --git a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md index 15702813..62b45e66 100644 --- a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md +++ b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md @@ -5,7 +5,7 @@ weight: 10 author: kagent.dev --- -A `ModelConfig` is a Kubernetes custom resource that names one model at one provider, along with the credentials to reach it. An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} references a {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} by name in its `spec.modelConfig.name` field, and every agent compiled from that template calls the model that the ModelConfig names. +A `ModelConfig` is a Kubernetes custom resource that names one model at one provider, along with the credentials to reach it. An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} references a {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} by name in its `spec.modelConfig.name` field, and every agent that runs from that template calls the model that the ModelConfig names. The kagent installation creates a `default-model-config` ModelConfig from the provider API key that you supply at install time, so a first agent does not need extra setup. To use a different provider, a different model, or a different set of credentials, create additional ModelConfigs. @@ -15,7 +15,7 @@ Every ModelConfig shares the same three parts, regardless of the provider that i | Field | Description | | ----- | ----------- | -| `provider` | The provider to use. Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`. Defaults to `OpenAI`. The API accepts `Mistral`, but the controller does not resolve it, so the controller rejects a Mistral ModelConfig and reports `unsupported model provider: Mistral`. | +| `provider` | The provider to use. Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`. Defaults to `OpenAI`. Three of these values are rejected on every runtime. For more information, see [Credentials that kagent rejects](#credentials-that-do-not-compile). | | `model` | The model name, as the provider spells it. | | `stream` | Whether the agent streams its model calls. Defaults to `true`. Set `false` for an endpoint that rejects streaming, which otherwise fails every turn. | | Provider block | A block named after the provider, such as `openAI` or `bedrock`, holding the settings that only that provider takes. An empty block is valid when the provider does not take extra settings. | @@ -51,11 +51,11 @@ spec: The setting belongs to the root agent's ModelConfig, and the root runner applies it to its subagents as well. Turning streaming off does not stop a caller from streaming the conversation: A2A task events remain streamable either way. The `codex` and `claude` harnesses do not read this setting. -Changing `stream` compiles a new {{< gloss "Revision" >}}revision{{< /gloss >}}, so create a new {{< gloss "Session" >}}Session{{< /gloss >}} to use the change. +Changing `stream` produces a new {{< gloss "Revision" >}}revision{{< /gloss >}}, so create a new {{< gloss "Session" >}}Session{{< /gloss >}} to use the change. ## How a credential reaches the provider -A credential never enters the agent. kagent compiles the Secret that a ModelConfig names into a destination-scoped binding, and the {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}} egress gateway fetches the Secret and writes the value into an outgoing HTTP header. Where an SDK requires an API key, the runtime receives the inert placeholder `kagent-credential-injected`. A compiled {{< gloss "Revision" >}}revision{{< /gloss >}} therefore records the Secret name, key, destination, and header, and never the credential itself. +A credential never enters the agent. kagent records the Secret that a ModelConfig names as a destination-scoped binding, and the {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}} egress gateway fetches the Secret and writes the value into an outgoing HTTP header. Where an SDK requires an API key, the runtime receives the inert placeholder `kagent-credential-injected`. A {{< gloss "Revision" >}}revision{{< /gloss >}} therefore records the Secret name, key, destination, and header, and never the credential itself. To rotate a credential, update the Secret. The revision records the Secret name and key rather than the value, so a rotation does not require a recompile. The gateway caches what it fetches, so allow a short delay before the new value is in use. @@ -95,7 +95,7 @@ The `Ollama` provider is unaffected when it points at a local daemon, which auth The runtime that a {{< gloss "Harness" >}}Harness{{< /gloss >}} selects constrains which providers an agent can use, because each runtime integrates a different set. -- The **`kagent`** runtime integrates every provider, and the **`byo`** runtime integrates the same set, because both compile through the same path. +- The **`kagent`** runtime integrates every provider, and the **`byo`** runtime integrates the same set, because kagent builds a revision for both runtimes the same way. - The **`codex`** runtime integrates only `OpenAI` and `Bedrock`. - The **`claude`** runtime integrates only `Anthropic` and `Bedrock`. @@ -121,4 +121,4 @@ spec: systemPrompt: You are a concise, helpful assistant. ``` -Editing a ModelConfig produces a new compiled {{< gloss "Revision" >}}revision{{< /gloss >}} for every {{< gloss "Agent" >}}Agent{{< /gloss >}} whose template references it. A {{< gloss "Session" >}}Session{{< /gloss >}} keeps running the revision that it was created from, so create a new Session to pick up a changed model. +Editing a ModelConfig produces a new {{< gloss "Revision" >}}revision{{< /gloss >}} for every {{< gloss "Agent" >}}Agent{{< /gloss >}} whose template references it. A {{< gloss "Session" >}}Session{{< /gloss >}} keeps running the revision that it was created from, so create a new Session to pick up a changed model. From c0c7c8e8907f712a64cf54158e846c5cb5ad3f02 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 16:53:15 -0500 Subject: [PATCH 2/8] conventions Signed-off-by: Rachael Graham --- .../kagent/1.x/agents/agent-harness.md | 28 ++++++++++++------- .../kagent/1.x/agents/bring-your-own-agent.md | 6 ++-- .../operations/operational-considerations.md | 2 +- .../kagent/1.x/operations/upgrade-from-0x.md | 2 +- .../model-providers/about-model-providers.md | 4 +-- 5 files changed, 25 insertions(+), 17 deletions(-) diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index b63b867b..343993da 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -61,7 +61,7 @@ A Harness names exactly one of the following four runtimes, and that choice deci | Runtime | What it runs | When to use it | | ------- | ------------ | ----------- | -| `kagent` | kagent's built-in Go engine | You want to define the agentic loop through configuration, with a system prompt, skills, plugins, and MCP servers, rather than by writing an agent. This runtime also supports the widest set of features. | +| `kagent` | kagent's built-in Go engine | You want to define the agentic loop through configuration, with a system prompt, skills, plugins, and MCP servers. This runtime also supports the widest set of features. | | `codex` | Codex | You want Codex to do the work, and your model is OpenAI or an OpenAI-compatible Bedrock deployment. | | `claude` | Claude | You want Claude to do the work, with Anthropic or Bedrock as the model. | | `byo` | A container image of your own that implements kagent's A2A contract | You already have an agent that is built with an agent framework, and you want to run that agent in kagent. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | @@ -72,7 +72,7 @@ The agent chat in the kagent UI offers file attachments only on the `kagent` run ### kagent runtime -The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins instead of writing one. Three features are available on this runtime alone: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. +The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins. Three features are available on this runtime alone: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. `spec.kagent` is the only runtime block that takes settings of its own. The other three runtimes take their configuration from the AgentTemplate and the ModelConfig, so their blocks are empty. @@ -278,9 +278,9 @@ EOF ### BYO runtime -The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent rather than rebuild it. The runtime block takes no settings, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. +The `byo` runtime runs an agent that you built with an agent framework of your own, packaged as a container image. The runtime block takes no settings, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. -A `byo` revision is compiled the same way as a `kagent` one, so a BYO image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, and the `kagent` runtime alone supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the A2A contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). +kagent builds a `byo` revision the same way as a `kagent` one, so an image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, and the `kagent` runtime alone supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). ```yaml kubectl apply -f - <}}MCP{{< /gloss >}} server is bound whole. Claude does not support partial tool selection, so the agent sees every tool that the server offers rather than only the ones that a binding names. The Agent still reconciles, and reports the decision in `status.warnings` as `Claude RemoteMCPServer "" does not support partial tool selection`. | `claude` | +| An {{< gloss "MCP" >}}MCP{{< /gloss >}} server is bound whole. Claude does not support partial tool selection, so the agent sees every tool that the server offers. The Agent still reconciles, and reports the decision in `status.warnings` as `Claude RemoteMCPServer "" does not support partial tool selection`. | `claude` | | A RemoteMCPServer must use the `STREAMABLE_HTTP` protocol. `SSE` is rejected. | `codex` | | Structured output is rejected, with `Harness runtime "" does not support structured output`. | `codex`, `claude`, `byo` | @@ -396,7 +396,7 @@ A `byo` image receives the same variable whenever any signal is enabled, but whe ## Reserved environment variables -An installation's telemetry settings reach a runtime as defaults rather than as fixed values. Where a Harness `spec.env` entry names the same variable, the Harness value wins, which is how one Harness tunes exporter behavior for the agents that run on it. Two sets of names are reserved instead, and a Harness that names one of them is rejected. +An installation's telemetry settings reach a runtime as defaults. Where a Harness `spec.env` entry names the same variable, the Harness value wins. One Harness can therefore tune exporter behavior for the agents that run on it, without changing the installation. Two sets of names are reserved instead, and a Harness that names one of them is rejected. Every runtime reserves the certificate trust variables, because the egress gateway intercepts HTTPS and each runtime must trust the gateway's certificate authority to reach a model at all. @@ -416,14 +416,14 @@ The `codex` and `claude` runtimes each reserve a second set, which covers the cr Two variables take a value from a Harness without replacing the controller's. -* `OTEL_RESOURCE_ATTRIBUTES` is merged rather than replaced. The value in `spec.env` is kept, and the agent identity attributes that the controller adds win where the two name the same attribute. +* `OTEL_RESOURCE_ATTRIBUTES` is merged. The value in `spec.env` is kept, and the agent identity attributes that the controller adds win where the two name the same attribute. * `OTEL_EXPORTER_OTLP_HEADERS` has no controller value to replace. No Helm setting produces it and the controller never adds it, but a value in `spec.env` reaches every runtime unchanged. To attach headers without holding them in an Actor environment, export to an in-cluster collector that adds them. ### Baggage propagation Baggage is a W3C header that travels with a request alongside its trace context. Each entry in that header is a member, which pairs a name with a string value. Every service that the request reaches can read the members that it carries. -By default, a kagent runtime sets `OTEL_PROPAGATORS` to `tracecontext`, which carries trace context and drops baggage. A caller's baggage therefore does not reach the tools that an agent calls or the agent's model provider. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the controller. +By default, a kagent runtime sets `OTEL_PROPAGATORS` to `tracecontext`. That value propagates trace context and drops baggage. A caller's baggage therefore does not reach the tools that an agent calls or the agent's model provider. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the controller. `OTEL_PROPAGATORS` is a list of wire formats that apply to both incoming and outgoing requests. If an incoming request has a format that is not in the list, the format is not read. Similarly, the runtime does not write an omitted format to an outgoing request. When the list omits `baggage`, the runtime's own members are dropped too. @@ -457,12 +457,20 @@ The Agent reports for all three resources instead, because an AgentTemplate repo kubectl get agent -n kagent ``` -An Agent that is not `Ready` carries the reason in its conditions. `ResolvedRefs` reports whether the resources that the Agent depends on exist, which covers the Harness, the AgentTemplate, and the ModelConfig, and also the WorkerPool that the Harness names. A missing pool is the most common cause, and it reports the reason `WorkerPoolNotFound`. `Compatible` reports whether the resolved configuration is one that the Harness's runtime accepts, which is where a rejected provider, a reserved environment variable, or an unsupported AgentTemplate feature appears. `Ready` reports whether Agent Substrate finished preparing the agent's capacity. +An Agent that is not `Ready` states the reason in its conditions. ```bash kubectl describe agent -n kagent ``` +The following conditions report the three stages that an Agent passes through. + +| Condition | Report | +| --------- | ------ | +| `ResolvedRefs` | Whether the resources that the Agent depends on exist. The controller resolves the Harness, the AgentTemplate, and the ModelConfig, and also the WorkerPool that the Harness references. A missing WorkerPool is the most common failure, and the Agent then reports the reason as `WorkerPoolNotFound`. | +| `Compatible` | Whether the Harness's runtime accepts the resolved configuration. A rejected model provider, a reserved environment variable, and an unsupported AgentTemplate feature all fail here. | +| `Ready` | Whether Agent Substrate finished preparing the agent's capacity. | + An Agent can also reconcile and still report a non-blocking decision in `status.warnings`, such as Claude binding an MCP server whole. For the conditions in full, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). ## Next steps diff --git a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md index 122bc7a8..2267c198 100644 --- a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md +++ b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md @@ -5,7 +5,7 @@ weight: 20 author: kagent.dev --- -The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still compiles the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} into a {{< gloss "Revision" >}}revision{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent rather than rebuild it. +The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still compiles the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} into a {{< gloss "Revision" >}}revision{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent. ## What kagent runs and what your image runs @@ -48,7 +48,7 @@ kagent resolves an AgentTemplate for a `byo` Harness in the same way as for the - **An opaque agent ignores the compiled configuration.** The AgentTemplate exists to give the agent an identity and a description, and the image decides everything else, including which model to call and which tools to offer. Every field on an opaque AgentTemplate is optional, `modelConfig` included. - **A configured agent reads the compiled configuration.** The image honors the AgentTemplate's system prompt, ModelConfig, tool bindings, skills, and plugins, so an operator changes the agent's behavior by editing the AgentTemplate rather than by rebuilding the image. -kagent builds a revision for the `byo` runtime the same way as for the `kagent` runtime, so a configured BYO agent accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). +kagent builds a revision for the `byo` runtime in the same way that it does for the `kagent` runtime, so a configured BYO agent accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). Both kinds of agent receive the same inputs. Agent Substrate delivers the two JSON payloads as private environment variables, and the kagent helpers write them to files before the agent starts. An image in another language either reads the files that `MaterializeFromEnv` writes or parses the variables itself. @@ -56,7 +56,7 @@ Both kinds of agent receive the same inputs. Agent Substrate delivers the two JS | ----- | -------- | | `KAGENT_CONFIG_JSON`, which the helpers write to `/config/config.json` | The compiled agent configuration, including the resolved system prompt, the model and its settings, every tool, skill, and plugin that the AgentTemplate binds, and a `runtime` object that sets the process settings. | | `KAGENT_AGENT_CARD_JSON`, which the helpers write to `/config/agent-card.json` | The agent card that kagent advertises for this agent, rendered as JSON. | -| Anything in `spec.env` | The literal values that the Harness sets. The field takes no secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected rather than starting and misbehaving. | +| Anything in `spec.env` | The literal values that the Harness sets. The field takes no secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected. | The `runtime` object is the root of the configuration document, and subagents inherit it. The object includes the settings that a process needs before it serves a request. diff --git a/docs-site/content/kagent/1.x/operations/operational-considerations.md b/docs-site/content/kagent/1.x/operations/operational-considerations.md index 3ca4930a..b07ccf66 100644 --- a/docs-site/content/kagent/1.x/operations/operational-considerations.md +++ b/docs-site/content/kagent/1.x/operations/operational-considerations.md @@ -57,7 +57,7 @@ After you change these values, you can verify their validity by checking the con The only section of settings that the controller does not apply to itself is `config.runtimeDefaults`. The controller compiles those settings into each agent runtime that it starts. If you want a setting to apply to both the controller and the agents, such as the log level, the telemetry endpoints, or the content capture decision, you must configure that setting in both `config` and `config.runtimeDefaults`. -A `config.runtimeDefaults` setting is the installation's default rather than a fixed value. A Harness can replace most of them for the agents that run on it, by naming the equivalent variable in its `spec.env` field. A small set of names is reserved instead, such as the certificate trust variables that let a runtime reach the egress gateway. For the reserved names and the per-runtime differences, see [Reserved environment variables]({{< link path="agents/agent-harness#reserved-environment-variables" >}}). +Each `config.runtimeDefaults` setting is the installation's default. A Harness can replace most of these settings for the agents that run on it by naming the equivalent variable in its `spec.env` field. A small set of names is reserved instead, such as the certificate trust variables that let a runtime reach the egress gateway. For the reserved names and the per-runtime differences, see [Reserved environment variables]({{< link path="agents/agent-harness#reserved-environment-variables" >}}). ## Choose a database diff --git a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md index fc1de1f4..98373be1 100644 --- a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md +++ b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md @@ -136,7 +136,7 @@ Four resource kinds are removed rather than replaced, so plan for each one befor ## Verify the new installation -Confirm that the resources resolved before you retire anything. Neither a Harness nor an AgentTemplate reports status of its own, so the Agent that references both is where every problem surfaces. +Confirm that the resources resolved before you retire anything. Harness and AgentTemplate resources do not report their own statuses, so check for issues in the Agent that references them both. 1. Check that each Agent is ready. ```bash diff --git a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md index 62b45e66..807b8679 100644 --- a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md +++ b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md @@ -15,7 +15,7 @@ Every ModelConfig shares the same three parts, regardless of the provider that i | Field | Description | | ----- | ----------- | -| `provider` | The provider to use. Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`. Defaults to `OpenAI`. Three of these values are rejected on every runtime. For more information, see [Credentials that kagent rejects](#credentials-that-do-not-compile). | +| `provider` | The provider to use.
  • Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`.
  • Defaults to `OpenAI`.
  • `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore` are rejected on every runtime.
For more information, see [Credentials that kagent rejects](#credentials-that-do-not-compile). | | `model` | The model name, as the provider spells it. | | `stream` | Whether the agent streams its model calls. Defaults to `true`. Set `false` for an endpoint that rejects streaming, which otherwise fails every turn. | | Provider block | A block named after the provider, such as `openAI` or `bedrock`, holding the settings that only that provider takes. An empty block is valid when the provider does not take extra settings. | @@ -95,7 +95,7 @@ The `Ollama` provider is unaffected when it points at a local daemon, which auth The runtime that a {{< gloss "Harness" >}}Harness{{< /gloss >}} selects constrains which providers an agent can use, because each runtime integrates a different set. -- The **`kagent`** runtime integrates every provider, and the **`byo`** runtime integrates the same set, because kagent builds a revision for both runtimes the same way. +- The **`kagent`** runtime integrates every provider, and the **`byo`** runtime integrates the same set, because kagent builds a revision for both runtimes in the same way. - The **`codex`** runtime integrates only `OpenAI` and `Bedrock`. - The **`claude`** runtime integrates only `Anthropic` and `Bedrock`. From 039c085f3d3a55e990d8dda73878b1cfd6e0fada Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 17:35:47 -0500 Subject: [PATCH 3/8] preview review Signed-off-by: Rachael Graham --- .../kagent/1.x/agents/agent-harness.md | 79 ++++++++----------- .../kagent/1.x/agents/bring-your-own-agent.md | 2 +- 2 files changed, 35 insertions(+), 46 deletions(-) diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index 343993da..a2ccb0eb 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -41,16 +41,13 @@ EOF | Field | Required | Description | | ----- | -------- | ----------- | | One of `kagent`, `codex`, `claude`, `byo` | Yes | The runtime that executes the agent. Naming none, or more than one, is rejected. For the available runtimes, see [Choose a runtime](#choose-a-runtime). | -| `workload.image` | Yes | The runtime image, pinned by `sha256` digest. A tag alone is rejected, because a revision must be reproducible. | +| `workload.image` | Yes | The runtime image, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. | | `workload.command` | For `byo` | Overrides the image entrypoint, up to 32 entries. Required for the `byo` runtime, optional otherwise. Every runtime honors an explicit value, the `kagent` runtime included, regardless of the language its image is written in. | | `workload.args` | No | Overrides the image arguments, up to 64 entries. An override that you omit stays unset rather than taking a default. | -| `env` | No | Environment variables for the runtime, up to 100 entries. Each entry sets a literal `value`, which is required and can be an empty string. The schema defines no secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials on a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Some names are reserved. For more information, see [Reserved environment variables](#reserved-environment-variables). | +| `env` | No | Environment variables for the runtime. Each entry sets a literal `value`, which is required and can be an empty string. The schema accepts up to 100 entries, but Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that the controller adds to every revision count toward that limit. A revision that exceeds 32 reports `runtime revision has environment variables; Substrate supports at most 32`. The schema does not define a secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials on a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Some names are reserved. For more information, see [Reserved environment variables](#reserved-environment-variables). | | `substrate.workerPoolRef.name` | Yes | The {{< gloss "WorkerPool" >}}WorkerPool{{< /gloss >}} that this Harness's Actors are scheduled onto. An operator must provision one before any agent can run. | | `substrate.snapshotPolicy.location` | Yes | The object storage location for Actor {{< gloss "Snapshot" >}}snapshots{{< /gloss >}}. | -> [!NOTE] -> Although the schema accepts up to 100 `env` entries, Agent Substrate accepts at most 32 environment variables on an Actor. The controller adds its own variables to every revision, such as the agent configuration and the certificate trust settings, and those count toward the limit. A revision that exceeds 32 reports `runtime revision has environment variables; Substrate supports at most 32`. - A Harness and an AgentTemplate do not reference each other. An {{< gloss "Agent" >}}Agent{{< /gloss >}} references both, through `spec.harnessRef` and `spec.template.ref`, so whoever writes the Agent decides which template runs on which Harness. Both fields take a reference only, so the Harness must exist before an Agent can name it. For more information about the pairing, see [Core concepts]({{< link path="about/core-concepts#agent" >}}). The image, command, arguments, environment, and resolved AgentTemplate together form a {{< gloss "Revision" >}}revision{{< /gloss >}}, which kagent identifies by a digest of that content. Editing any of them produces a new revision at the next reconcile. A {{< gloss "Session" >}}Session{{< /gloss >}} runs the revision that it was created from until that Session ends, so only Sessions that start after the edit use the new revision. @@ -66,15 +63,15 @@ A Harness names exactly one of the following four runtimes, and that choice deci | `claude` | Claude | You want Claude to do the work, with Anthropic or Bedrock as the model. | | `byo` | A container image of your own that implements kagent's A2A contract | You already have an agent that is built with an agent framework, and you want to run that agent in kagent. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | -The runtimes differ in two ways that decide what an agent on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. +The runtimes differ in two ways that decide what an agent running on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. The agent chat in the kagent UI offers file attachments only on the `kagent` runtime. An agent on a `byo`, `codex`, or `claude` Harness has no option to attach files in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). ### kagent runtime -The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins. Three features are available on this runtime alone: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. +The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins. Three features are available only on the kagent runtime: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. -`spec.kagent` is the only runtime block that takes settings of its own. The other three runtimes take their configuration from the AgentTemplate and the ModelConfig, so their blocks are empty. +Add runtime settings in the `spec.kagent` section of the Harness resource. ```yaml spec: @@ -88,19 +85,17 @@ spec: eventRetentionSize: 20 ``` -The settings fall into two groups. Memory persists facts across conversations, and compaction keeps a single conversation's prompt bounded as the conversation grows. +Memory settings persist facts across conversations. Compaction settings keep a single conversation's prompt bounded as the conversation grows, and kagent offers two strategies for that. Tail retention summarizes the older history once the prompt passes a token count. A sliding window summarizes each group of completed invocations as the conversation goes. Setting `compaction` requires at least one of the two strategies, and setting both is valid. For the rules that the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). | Field | Description | | ----- | ----------- | -| `memory.modelConfigRef.name` | The ModelConfig supplying the embedding model, in the Harness's namespace. Required when `memory` is set. Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). | +| `memory.modelConfigRef.name` | The ModelConfig that supplies the embedding model, in the Harness's namespace. Required when `memory` is set. Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). | | `memory.ttlDays` | How many days a stored memory entry stays valid. Minimum 1. When omitted, the server applies a default of 15 days. | -| `compaction.tokenThreshold` | The prompt token count at which kagent summarizes the history before the next model call. Set it with `compaction.eventRetentionSize`. | -| `compaction.eventRetentionSize` | The number of most recent events that stay uncompacted. Set it with `compaction.tokenThreshold`. | -| `compaction.compactionInterval` | The number of new user-initiated invocations that triggers a sliding-window compaction of those invocations. An alternative to the two tail-retention settings, and `compaction` requires one strategy or the other. | -| `compaction.overlapSize` | The number of already-compacted invocations pulled back into the next window, so that consecutive summaries overlap. Requires `compaction.compactionInterval`. | -| `compaction.summarizer` | The ModelConfig and prompt template that write the summaries. When omitted, kagent summarizes with the agent's own model and the runtime's default prompt. | - -For the two compaction strategies and the rules that the API server enforces on them, see [Context management]({{< link path="agents/context-management" >}}). +| `compaction.tokenThreshold` | Tail retention. The prompt token count that triggers a summary. Once the prompt passes this count, kagent summarizes the older history before the next model call. Requires `compaction.eventRetentionSize`. | +| `compaction.eventRetentionSize` | Tail retention. The number of most recent events that kagent leaves out of that summary, so the latest exchanges reach the model in full. Requires `compaction.tokenThreshold`. | +| `compaction.compactionInterval` | Sliding window. The number of new user-initiated invocations that triggers a summary of those invocations. Set `5` to summarize each group of five. | +| `compaction.overlapSize` | Sliding window. The number of already-summarized invocations that kagent includes in the next summary, so that consecutive summaries overlap and carry context forward. Requires `compaction.compactionInterval`. | +| `compaction.summarizer` | Both strategies. The ModelConfig and prompt template that write the summaries. When omitted, kagent summarizes with the agent's own model and the runtime's default prompt. | The following example applies a complete `kagent` agent, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. @@ -159,7 +154,7 @@ EOF ### Codex runtime -The `codex` runtime runs Codex against an OpenAI or Bedrock model. The runtime block takes no settings. Codex accepts a narrower set of AgentTemplate features than the built-in runtime, and the restrictions are in [Tool and skill support](#tool-and-skill-support). +The `codex` runtime runs Codex against an OpenAI or Bedrock model. The runtime block is empty. Codex accepts a narrower set of AgentTemplate features than the built-in runtime. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). The ModelConfig must set `openAI.apiFormat: responses`, and the API key must be entitled to the model that you name. A key without access to that model fails the turn with `Codex execution failed`. The ModelConfig in the following example reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. @@ -219,7 +214,7 @@ EOF ### Claude runtime -The `claude` runtime runs Claude against an Anthropic or Bedrock model. The runtime block takes no settings. Claude accepts a narrower set of AgentTemplate features than the built-in runtime, and the restrictions are in [Tool and skill support](#tool-and-skill-support). +The `claude` runtime runs Claude against an Anthropic or Bedrock model. The runtime block is empty. Claude accepts a narrower set of AgentTemplate features than the built-in runtime. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). The ModelConfig in the following example reads its API key from the `kagent-anthropic` Secret that the [Anthropic]({{< link path="setup/model-providers/anthropic#create-the-modelconfig" >}}) guide creates. @@ -278,9 +273,9 @@ EOF ### BYO runtime -The `byo` runtime runs an agent that you built with an agent framework of your own, packaged as a container image. The runtime block takes no settings, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. +The `byo` runtime runs an agent that you built with an agent framework of your own, packaged as a container image. The runtime block is empty, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. -kagent builds a `byo` revision the same way as a `kagent` one, so an image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, and the `kagent` runtime alone supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). +kagent builds a `byo` revision in the same way that it builds a `kagent` one, so an image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, because only the `kagent` runtime supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). ```yaml kubectl apply -f - <" cannot use gateway header injection`. Some supported combinations still carry restrictions. | Combination | Restriction | | ----------- | ----------- | -| `codex` with `OpenAI` | Requires `openAI.apiFormat: responses`, and accepts no other `openAI` setting beyond `baseUrl`. | -| `codex` with `Bedrock` | Accepts only OpenAI `gpt-*` model IDs, and no `bedrock` settings beyond `region`. | -| `claude` with `Anthropic` | Accepts no `anthropic` settings beyond `baseUrl`. | -| `claude` with `Bedrock` | Accepts no `bedrock` settings beyond `region`. | +| `codex` with `OpenAI` | Requires `openAI.apiFormat: responses`, and does not accept any other `openAI` setting beyond `baseUrl`. | +| `codex` with `Bedrock` | Accepts only OpenAI `gpt-*` model IDs, and does not accept any `bedrock` setting beyond `region`. | +| `claude` with `Anthropic` | Does not accept any `anthropic` setting beyond `baseUrl`. | +| `claude` with `Bedrock` | Does not accept any `bedrock` setting beyond `region`. | | `Bedrock` on any runtime | The Secret must hold an `AWS_BEARER_TOKEN_BEDROCK` key. A Secret of IAM access keys is rejected with `cannot use gateway header injection`, because IAM signs each request locally. | | `codex` and `claude` with any provider | Neither runtime accepts a ModelConfig that sets `defaultHeaders`, `tls`, or `apiKeyPassthrough`. | @@ -371,7 +366,7 @@ For more information about what an AgentTemplate can bind, see [About tools]({{< ## Telemetry content settings -Enabling content capture puts the prompts and replies that an agent exchanges with a model into your telemetry backend, where anyone with access to that backend can read them. Both settings that do this default to `false`, and both take effect only where tracing or log export is already enabled. Set them in the kagent Helm chart. +By default, kagent's telemetry records that a model call happened, without the prompt or the reply. Two settings in the kagent Helm chart add that content, and both default to `false`. `captureContent` adds the prompts and assistant replies. `captureRawApiBodies` adds the complete provider request and response bodies. Neither takes effect until you enable tracing or log export, and anyone who can read your telemetry backend can read whatever you capture. ```yaml config: @@ -382,35 +377,35 @@ config: maxCaptureBytes: 16384 ``` -The two capture settings differ in how much they return and which runtimes read them. The third setting bounds the size of what either one captures. +Each setting reaches a different set of runtimes, and `maxCaptureBytes` bounds the size of what either capture setting records. | Setting | What it includes | Applies to | | ------- | ---------------- | ---------- | -| `config.runtimeDefaults.telemetry.captureContent` | Prompts and assistant replies. On the `kagent` runtime, the content appears in the span for each model call. That runtime records a tool call's arguments and reply on the span for the tool call instead, whatever this setting is. On the `claude` runtime, tool results need tracing, and assistant replies need log export through `config.runtimeDefaults.telemetry.logs`. | `kagent`, `codex`, `claude` | +| `config.runtimeDefaults.telemetry.captureContent` | Prompts and assistant replies. On the `kagent` runtime, the content appears in the span for each model call. That runtime records a tool call's arguments and reply on the span for the tool call instead, regardless of this setting. On the `claude` runtime, tool results require tracing, and assistant replies require log export through `config.runtimeDefaults.telemetry.logs`. | `kagent`, `codex`, `claude` | | `config.runtimeDefaults.telemetry.captureRawApiBodies` | The complete provider API request and response bodies. This setting returns more than `captureContent` does, and it takes effect only when you set the logs endpoint. | `claude` | | `config.runtimeDefaults.telemetry.maxCaptureBytes` | The budget for each captured prompt or reply, in bytes. Defaults to `16384`, with a maximum of `65536`. | `codex`, `claude` | These settings are the installation's default. To change the capture decision for one Harness, set `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` in that Harness's `spec.env` field. The `kagent`, `codex`, and `claude` runtimes all read the variable and apply it in place of the installation default. Set `SPAN_ONLY` to put prompts and replies on spans, or `NO_CONTENT` to turn capture off. -A `byo` image receives the same variable whenever any signal is enabled, but whether the image acts on it depends on its own instrumentation. An image that exports to its own backend keeps doing so. For more information, see [Tracing]({{< link path="observability/tracing#about-trace-coverage" >}}). +A `byo` image receives the same variable whenever any signal is enabled, but whether the image acts on it depends on its own instrumentation. An image that exports to its own backend continues to do so. For more information, see [Tracing]({{< link path="observability/tracing#about-trace-coverage" >}}). ## Reserved environment variables -An installation's telemetry settings reach a runtime as defaults. Where a Harness `spec.env` entry names the same variable, the Harness value wins. One Harness can therefore tune exporter behavior for the agents that run on it, without changing the installation. Two sets of names are reserved instead, and a Harness that names one of them is rejected. +A Harness tunes telemetry for its own agents by setting `OTEL_*` variables in its `spec.env` field. Each runtime reads its environment first and falls back to the installation's telemetry settings, so a value in `spec.env` wins for that Harness only and leaves every other Harness unchanged. Some variable names are reserved, and a Harness that sets one is rejected. -Every runtime reserves the certificate trust variables, because the egress gateway intercepts HTTPS and each runtime must trust the gateway's certificate authority to reach a model at all. +Every runtime reserves the following certificate trust variables. The egress gateway intercepts HTTPS, so a runtime that does not trust the gateway's certificate authority cannot reach a model. * `SSL_CERT_FILE` and `SSL_CERT_DIR` * `REQUESTS_CA_BUNDLE`, `AWS_CA_BUNDLE`, and `CURL_CA_BUNDLE` * `NODE_EXTRA_CA_CERTS` * `GIT_SSL_CAINFO` -A Harness that names one of these variables reports `runtime environment "" conflicts with gateway trust`. +A Harness that sets one of these variables reports `runtime environment "" conflicts with gateway trust`. -The `codex` and `claude` runtimes each reserve a second set, which covers the credentials and runtime state that their adapters write. The `kagent` and `byo` runtimes reserve nothing beyond the trust variables. +The `codex` and `claude` runtimes each reserve a second set of variables, which describe the credentials and runtime state that their adapters write. -| Runtime | Also reserved | Result | -| ------- | ------------- | ------ | +| Runtime | Additional reserved variables | Effect if set by a Harness | +| ------- | ----------------------------- | -------------------------- | | `claude` | The Anthropic, AWS, and Vertex AI credential variables, `CLAUDE_CONFIG_DIR`, `DISABLE_UPDATES`, `IS_SANDBOX`, `CLAUDE_CODE_ENABLE_TELEMETRY`, `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA`, `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, Claude's `OTEL_LOG_*` capture flags, `TRACEPARENT`, `TRACESTATE`, and the Prometheus exporter host and port | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Claude-owned runtime configuration`. | | `codex` | `CODEX_HOME`, `OPENAI_API_KEY`, `AWS_REGION`, `AWS_BEARER_TOKEN_BEDROCK`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Codex's compiled configuration`. | @@ -442,20 +437,14 @@ These members serve as identifiers only, and the runtime can replace a caller's > **Enabling baggage sends the caller's own members to your model provider.** A caller baggage member that kagent does not replace is forwarded unchanged in the `baggage` header of each model API request and each MCP request. This means that a caller controls what reaches those external services in the header. Enable baggage only where you trust what your callers attach. Review and plan for the following considerations. -* The `claude` and `codex` runtimes receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The four members reach the `kagent` runtime alone. +* The `claude` and `codex` runtimes receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The four members reach only the `kagent` runtime. * kagent never copies a baggage member onto a span. To make these values searchable, add a baggage-to-attributes span processor to the service that receives the request or to its OpenTelemetry Collector. When an agent requires an MCP server, the first tool listing or tool call opens a session with the MCP server, and every later request to that server shares it. The session makes three requests: the event stream, the replies to server requests, and the close. These requests do not carry trace context or baggage, because these name a request that has already ended. ## Check that an agent can run -A Harness reports no status of its own. The `READY` column in `kubectl get harness` output is always empty, and `kubectl describe harness` shows no conditions, because nothing writes them. - -The Agent reports for all three resources instead, because an AgentTemplate reports no status of its own either. - -```bash -kubectl get agent -n kagent -``` +To check the status of a Harness, AgentTemplate, or Agent, check the status of only the Agent. It reports for all three resources, because neither a Harness nor an AgentTemplate reports a status of its own. For example, the `READY` column in `kubectl get harness` output is always empty. An Agent that is not `Ready` states the reason in its conditions. diff --git a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md index 2267c198..9119819f 100644 --- a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md +++ b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md @@ -56,7 +56,7 @@ Both kinds of agent receive the same inputs. Agent Substrate delivers the two JS | ----- | -------- | | `KAGENT_CONFIG_JSON`, which the helpers write to `/config/config.json` | The compiled agent configuration, including the resolved system prompt, the model and its settings, every tool, skill, and plugin that the AgentTemplate binds, and a `runtime` object that sets the process settings. | | `KAGENT_AGENT_CARD_JSON`, which the helpers write to `/config/agent-card.json` | The agent card that kagent advertises for this agent, rendered as JSON. | -| Anything in `spec.env` | The literal values that the Harness sets. The field takes no secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected. | +| Anything in `spec.env` | The literal values that the Harness sets. The field does not take a secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected. | The `runtime` object is the root of the configuration document, and subagents inherit it. The object includes the settings that a process needs before it serves a request. From 0163783e9f966077d4c2ebfd9a6d884331231c28 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 18:00:51 -0500 Subject: [PATCH 4/8] final pass Signed-off-by: Rachael Graham --- docs-site/content/kagent/1.x/agents/agent-harness.md | 6 +++--- docs-site/content/kagent/1.x/agents/bring-your-own-agent.md | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index a2ccb0eb..4912bc80 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -7,7 +7,7 @@ author: kagent.dev A Harness defines how an agent is allowed to run. It selects the runtime that executes the agent, the container image that runtime starts from, and the Agent Substrate capacity and snapshot storage that the agent runs on. A Harness runs nothing by itself. To run an agent, create an Agent that references a Harness and an AgentTemplate, which supplies the system prompt, the model, and the tools. -This page covers the Harness schema, the four runtimes it can select, and what each runtime supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). +This page covers the Harness schema, the four runtimes that a Harness can select, and what each runtime supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). ## Configure a Harness @@ -85,7 +85,7 @@ spec: eventRetentionSize: 20 ``` -Memory settings persist facts across conversations. Compaction settings keep a single conversation's prompt bounded as the conversation grows, and kagent offers two strategies for that. Tail retention summarizes the older history once the prompt passes a token count. A sliding window summarizes each group of completed invocations as the conversation goes. Setting `compaction` requires at least one of the two strategies, and setting both is valid. For the rules that the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). +Memory settings persist facts across conversations. Compaction settings keep a single conversation's prompt bounded as the conversation grows, through either of two strategies. Tail retention summarizes the older history once the prompt passes a token count. A sliding window summarizes each group of completed invocations as the conversation goes. Setting `compaction` requires at least one of the two strategies, and setting both is valid. For the rules that the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). | Field | Description | | ----- | ----------- | @@ -275,7 +275,7 @@ EOF The `byo` runtime runs an agent that you built with an agent framework of your own, packaged as a container image. The runtime block is empty, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. -kagent builds a `byo` revision in the same way that it builds a `kagent` one, so an image that reads the agent configuration accepts the same model providers and the same AgentTemplate features as the built-in runtime. Structured output is the one exception, because only the `kagent` runtime supports it. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). +An image that reads the agent configuration accepts the same model providers and AgentTemplate features as the built-in runtime, except for structured output. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). ```yaml kubectl apply -f - <}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). +kagent builds a revision for the `byo` runtime in the same way that it does for the `kagent` runtime. A configured BYO agent therefore accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). Both kinds of agent receive the same inputs. Agent Substrate delivers the two JSON payloads as private environment variables, and the kagent helpers write them to files before the agent starts. An image in another language either reads the files that `MaterializeFromEnv` writes or parses the variables itself. From 574a259e547068b0d472c9fb02455bc73fbfbc37 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 20:57:49 -0500 Subject: [PATCH 5/8] Clarify harness and BYO agent docs Align 1.x documentation with the harness model and clarify BYO agent responsibilities, runtime requirements, Actor environment limits, and pgvector setup for agent memory. Signed-off-by: Rachael Graham --- .../content/kagent/1.x/about/core-concepts.md | 12 +- docs-site/content/kagent/1.x/agents/_index.md | 2 +- .../kagent/1.x/agents/agent-harness.md | 168 +++++------------- .../content/kagent/1.x/agents/agent-memory.md | 38 ++-- .../kagent/1.x/agents/bring-your-own-agent.md | 121 +++++++------ .../kagent/1.x/agents/context-management.md | 22 ++- .../kagent/1.x/agents/structured-output.md | 12 +- .../kagent/1.x/agents/system-prompts.md | 10 +- .../kagent/1.x/operations/upgrade-from-0x.md | 2 +- .../model-providers/about-model-providers.md | 2 +- docs-site/data/glossary.yaml | 6 +- 11 files changed, 176 insertions(+), 219 deletions(-) diff --git a/docs-site/content/kagent/1.x/about/core-concepts.md b/docs-site/content/kagent/1.x/about/core-concepts.md index 6a8a0a64..82258744 100644 --- a/docs-site/content/kagent/1.x/about/core-concepts.md +++ b/docs-site/content/kagent/1.x/about/core-concepts.md @@ -14,7 +14,7 @@ author: kagent.dev The new model separates what an agent can do from how it is allowed to run, and then names the pairing explicitly: -- A [**Harness**](#harness) defines how an agent is allowed to run. It picks a runtime and the infrastructure policy around it. +- A [**Harness**](#harness) defines how an agent is allowed to run. It picks a harness and the infrastructure policy around it. - An [**AgentTemplate**](#agenttemplate) defines what an agent can do: its model, prompt, and tools. - An [**Agent**](#agent) pairs one AgentTemplate with one Harness. Callers address the Agent, and the controller compiles it. - A [**Session**](#session) is a running conversation with an Agent. @@ -63,14 +63,14 @@ Examples include [Claude Code](https://code.claude.com/docs/en/how-claude-code-w A **Harness** in kagent is a Kubernetes custom resource that applies that idea to a cluster. It defines _how an agent is allowed to run_, and specifies: -- **Runtime**: The engine that executes the agent. A Harness selects exactly one of `kagent`, `codex`, `claude`, or `byo`. `kagent` runs kagent's own agent engine, `codex` runs Codex, `claude` runs Claude, and `byo` runs any image that implements kagent's A2A contract. The four runtimes accept different model providers and different AgentTemplate features. -- **Workload**: The container image, command, and arguments that the runtime runs as. -- **Environment**: Literal environment values for the runtime, set in `spec.env`. +- **Execution**: What runs the agent. A Harness selects exactly one of `kagent`, `codex`, `claude`, or `byo`. `kagent` runs kagent's own agent engine, `codex` runs Codex, `claude` runs Claude, and `byo` runs any image that exposes kagent's A2A contract. Each accepts different model providers and different AgentTemplate features. +- **Workload**: The container image, command, and arguments that the harness runs as. +- **Environment**: Literal environment values for the agent process, set in `spec.env`. - **Substrate policy**: The capacity that the agent runs on, and where its state is kept when it goes idle. The Harness names a [WorkerPool]({{< link path="about/architecture/agent-substrate#workers-and-workerpools" >}}) to schedule onto and the storage location that snapshots write to. A Harness and an AgentTemplate do not reference each other. An [Agent](#agent) references both, and nothing pairs them implicitly. Applying a Harness runs nothing on its own. It registers a runtime and policy that an Agent can select. -Each runtime accepts a different subset of configuration, and an Agent that asks for something its runtime cannot do reports a compatibility condition rather than running. For the per-runtime restrictions and the complete Harness schema, see the [API reference]({{< link path="reference/api-ref#harness" >}}). +Each harness accepts a different subset of configuration, and an Agent that asks for something its harness cannot do reports a compatibility condition rather than running. For the per-harness restrictions and the complete Harness schema, see the [API reference]({{< link path="reference/api-ref#harness" >}}). > [!IMPORTANT] > This `Harness` is unrelated to 0.x's `AgentHarness` resource, which provisions OpenClaw or Hermes coding-agent sandboxes. `Harness` is a different resource that covers how any agent is allowed to run, not a renamed or expanded version of `AgentHarness`. @@ -110,7 +110,7 @@ spec: name: kagent ``` -The Agent owns readiness. Its status reports the desired revision, the latest revision that compiled and prepared successfully, any non-blocking compatibility warnings, and the `Accepted`, `ResolvedRefs`, `Compatible`, and `Ready` conditions. An AgentTemplate and a Harness are shared configuration and do not report runtime status of their own. +The Agent owns readiness. Its status reports the desired revision, the latest revision that was built and prepared successfully, any non-blocking compatibility warnings, and the `Accepted`, `ResolvedRefs`, `Compatible`, and `Ready` conditions. An AgentTemplate and a Harness are shared configuration and do not report runtime status of their own. Deleting an Agent retires its definition. Existing Sessions keep the revisions that they pinned. Recreating an Agent under the same name creates a new identity, which cannot inherit the deleted Agent's last successful revision. diff --git a/docs-site/content/kagent/1.x/agents/_index.md b/docs-site/content/kagent/1.x/agents/_index.md index e07add1a..f37a52a6 100644 --- a/docs-site/content/kagent/1.x/agents/_index.md +++ b/docs-site/content/kagent/1.x/agents/_index.md @@ -1,6 +1,6 @@ --- title: Agents -description: Configure how an agent runs and what it knows, from the runtime behind it to its prompt and memory. +description: Configure how an agent runs and what it knows, from the harness behind it to its prompt and memory. weight: 40 author: kagent.dev --- diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index 4912bc80..ae366c5d 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -1,17 +1,17 @@ --- title: Agent harness -description: Configure a Harness, the resource that defines which runtime executes an agent and what infrastructure it runs on. +description: Configure a Harness, the resource that defines what executes an agent and what infrastructure the agent runs on. weight: 10 author: kagent.dev --- -A Harness defines how an agent is allowed to run. It selects the runtime that executes the agent, the container image that runtime starts from, and the Agent Substrate capacity and snapshot storage that the agent runs on. A Harness runs nothing by itself. To run an agent, create an Agent that references a Harness and an AgentTemplate, which supplies the system prompt, the model, and the tools. +A Harness defines how an agent is allowed to run. It names what executes the agent, the container image to start from, and the Agent Substrate capacity and snapshot storage that the agent runs on. A Harness runs nothing by itself. To run an agent, create an Agent that references a Harness and an AgentTemplate, which supplies the system prompt, the model, and the tools. -This page covers the Harness schema, the four runtimes that a Harness can select, and what each runtime supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). +This page covers the Harness schema, the four options that a Harness can select, and what each one supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). ## Configure a Harness -The following configuration shows a complete Harness. Only `workload`, `substrate`, and one runtime block are required. +The following configuration shows a complete Harness. Only `workload`, `substrate`, and one harness block are required. ```yaml kubectl apply -f - <}} @@ -40,121 +40,40 @@ EOF | Field | Required | Description | | ----- | -------- | ----------- | -| One of `kagent`, `codex`, `claude`, `byo` | Yes | The runtime that executes the agent. Naming none, or more than one, is rejected. For the available runtimes, see [Choose a runtime](#choose-a-runtime). | -| `workload.image` | Yes | The runtime image, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. | -| `workload.command` | For `byo` | Overrides the image entrypoint, up to 32 entries. Required for the `byo` runtime, optional otherwise. Every runtime honors an explicit value, the `kagent` runtime included, regardless of the language its image is written in. | +| One of `kagent`, `codex`, `claude`, `byo` | Yes | The harness that executes the agent. Naming none, or more than one, is rejected. For the four available, see [Choose a harness](#choose-a-harness). | +| `workload.image` | Yes | The container image to run, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. | +| `workload.command` | For `byo` | Overrides the image entrypoint, up to 32 entries. Required for the `byo` harness, optional otherwise. Every harness honors an explicit value, the `kagent` harness included, regardless of the language its image is written in. | | `workload.args` | No | Overrides the image arguments, up to 64 entries. An override that you omit stays unset rather than taking a default. | -| `env` | No | Environment variables for the runtime. Each entry sets a literal `value`, which is required and can be an empty string. The schema accepts up to 100 entries, but Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that the controller adds to every revision count toward that limit. A revision that exceeds 32 reports `runtime revision has environment variables; Substrate supports at most 32`. The schema does not define a secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials on a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Some names are reserved. For more information, see [Reserved environment variables](#reserved-environment-variables). | +| `env` | No | Environment variables for the agent process. Each entry sets a literal `value`, which is required and can be an empty string. The schema does not define a secret-backed source, so the API server rejects a `credentialRef` entry as an unknown field. Put credentials in a ModelConfig or a RemoteMCPServer instead. For more information, see [About model providers]({{< link path="setup/model-providers/about-model-providers#credentials-that-do-not-compile" >}}). Limits and reserved names both apply. For more information, see [Environment variables on an Actor](#environment-variables-on-an-actor). | | `substrate.workerPoolRef.name` | Yes | The {{< gloss "WorkerPool" >}}WorkerPool{{< /gloss >}} that this Harness's Actors are scheduled onto. An operator must provision one before any agent can run. | | `substrate.snapshotPolicy.location` | Yes | The object storage location for Actor {{< gloss "Snapshot" >}}snapshots{{< /gloss >}}. | -A Harness and an AgentTemplate do not reference each other. An {{< gloss "Agent" >}}Agent{{< /gloss >}} references both, through `spec.harnessRef` and `spec.template.ref`, so whoever writes the Agent decides which template runs on which Harness. Both fields take a reference only, so the Harness must exist before an Agent can name it. For more information about the pairing, see [Core concepts]({{< link path="about/core-concepts#agent" >}}). +A Harness and an AgentTemplate do not reference each other. An {{< gloss "Agent" >}}Agent{{< /gloss >}} references both, through `spec.harnessRef` and `spec.template.ref`, so whoever writes the Agent decides which template runs on which Harness. Both fields take a reference only. The Harness must therefore exist before an Agent can name it. For more information about the pairing, see [Core concepts]({{< link path="about/core-concepts#agent" >}}). The image, command, arguments, environment, and resolved AgentTemplate together form a {{< gloss "Revision" >}}revision{{< /gloss >}}, which kagent identifies by a digest of that content. Editing any of them produces a new revision at the next reconcile. A {{< gloss "Session" >}}Session{{< /gloss >}} runs the revision that it was created from until that Session ends, so only Sessions that start after the edit use the new revision. -## Choose a runtime +## Choose a harness -A Harness names exactly one of the following four runtimes, and that choice decides what executes an agent and how much of kagent's feature set the agent can use. +A Harness names exactly one of the following four options, and that choice decides what executes an agent and how much of kagent's feature set the agent can use. -| Runtime | What it runs | When to use it | +| Harness | What it runs | When to use it | | ------- | ------------ | ----------- | -| `kagent` | kagent's built-in Go engine | You want to define the agentic loop through configuration, with a system prompt, skills, plugins, and MCP servers. This runtime also supports the widest set of features. | +| `kagent` | kagent's built-in Go engine | You want to define the agentic loop through configuration, with a system prompt, skills, plugins, and MCP servers. This harness also supports the widest set of features. For more information, see [Declarative agents]({{< link path="agents/declarative-agents" >}}). | | `codex` | Codex | You want Codex to do the work, and your model is OpenAI or an OpenAI-compatible Bedrock deployment. | | `claude` | Claude | You want Claude to do the work, with Anthropic or Bedrock as the model. | | `byo` | A container image of your own that implements kagent's A2A contract | You already have an agent that is built with an agent framework, and you want to run that agent in kagent. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | -The runtimes differ in two ways that decide what an agent running on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. +The harnesses differ in two ways that decide what an agent running on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. -The agent chat in the kagent UI offers file attachments only on the `kagent` runtime. An agent on a `byo`, `codex`, or `claude` Harness has no option to attach files in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). +The agent chat in the kagent UI offers file attachments only on the `kagent` harness. An agent on a `byo`, `codex`, or `claude` Harness cannot attach files in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). -### kagent runtime +### kagent harness -The `kagent` runtime runs kagent's built-in Go engine, which reads the compiled agent configuration and runs the agentic loop from it. Choose this runtime to build an agent from a system prompt, tools, skills, and plugins. Three features are available only on the kagent runtime: [structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and file attachments in the UI chat. +The `kagent` harness runs kagent's built-in Go engine, which reads the agent configuration and runs the agentic loop from it. Choose the `kagent` harness to build an agent from a system prompt, tools, skills, and plugins. Its own settings live in `spec.kagent`, which takes a long-term memory block and a context compaction block. For those settings, a complete example, and how this route compares with a BYO image, see [Declarative agents]({{< link path="agents/declarative-agents" >}}). -Add runtime settings in the `spec.kagent` section of the Harness resource. +### Codex harness -```yaml -spec: - kagent: - memory: - modelConfigRef: - name: embedding-model-config - ttlDays: 30 - compaction: - tokenThreshold: 120000 - eventRetentionSize: 20 -``` - -Memory settings persist facts across conversations. Compaction settings keep a single conversation's prompt bounded as the conversation grows, through either of two strategies. Tail retention summarizes the older history once the prompt passes a token count. A sliding window summarizes each group of completed invocations as the conversation goes. Setting `compaction` requires at least one of the two strategies, and setting both is valid. For the rules that the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). - -| Field | Description | -| ----- | ----------- | -| `memory.modelConfigRef.name` | The ModelConfig that supplies the embedding model, in the Harness's namespace. Required when `memory` is set. Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). | -| `memory.ttlDays` | How many days a stored memory entry stays valid. Minimum 1. When omitted, the server applies a default of 15 days. | -| `compaction.tokenThreshold` | Tail retention. The prompt token count that triggers a summary. Once the prompt passes this count, kagent summarizes the older history before the next model call. Requires `compaction.eventRetentionSize`. | -| `compaction.eventRetentionSize` | Tail retention. The number of most recent events that kagent leaves out of that summary, so the latest exchanges reach the model in full. Requires `compaction.tokenThreshold`. | -| `compaction.compactionInterval` | Sliding window. The number of new user-initiated invocations that triggers a summary of those invocations. Set `5` to summarize each group of five. | -| `compaction.overlapSize` | Sliding window. The number of already-summarized invocations that kagent includes in the next summary, so that consecutive summaries overlap and carry context forward. Requires `compaction.compactionInterval`. | -| `compaction.summarizer` | Both strategies. The ModelConfig and prompt template that write the summaries. When omitted, kagent summarizes with the agent's own model and the runtime's default prompt. | - -The following example applies a complete `kagent` agent, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. - -```yaml -kubectl apply -f - <}} - substrate: - workerPoolRef: - name: kagent-default - snapshotPolicy: - location: s3://ate-snapshots/kagent/ ---- -apiVersion: api.kagent.dev/v1alpha3 -kind: AgentTemplate -metadata: - name: kagent-template - namespace: kagent -spec: - modelConfig: - name: kagent-model-config - systemPrompt: You are a concise, helpful assistant. ---- -apiVersion: api.kagent.dev/v1alpha3 -kind: Agent -metadata: - name: my-agent - namespace: kagent -spec: - template: - ref: - name: kagent-template - harnessRef: - name: kagent-harness -EOF -``` - -### Codex runtime - -The `codex` runtime runs Codex against an OpenAI or Bedrock model. The runtime block is empty. Codex accepts a narrower set of AgentTemplate features than the built-in runtime. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). +The `codex` harness runs Codex against an OpenAI or Bedrock model. The harness block is empty. Codex accepts a narrower set of AgentTemplate features than the built-in engine. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). The ModelConfig must set `openAI.apiFormat: responses`, and the API key must be entitled to the model that you name. A key without access to that model fails the turn with `Codex execution failed`. The ModelConfig in the following example reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. @@ -212,9 +131,9 @@ spec: EOF ``` -### Claude runtime +### Claude harness -The `claude` runtime runs Claude against an Anthropic or Bedrock model. The runtime block is empty. Claude accepts a narrower set of AgentTemplate features than the built-in runtime. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). +The `claude` harness runs Claude against an Anthropic or Bedrock model. The harness block is empty. Claude accepts a narrower set of AgentTemplate features than the built-in engine. To understand the restrictions, see [Tool and skill support](#tool-and-skill-support). The ModelConfig in the following example reads its API key from the `kagent-anthropic` Secret that the [Anthropic]({{< link path="setup/model-providers/anthropic#create-the-modelconfig" >}}) guide creates. @@ -271,11 +190,11 @@ spec: EOF ``` -### BYO runtime +### BYO harness -The `byo` runtime runs an agent that you built with an agent framework of your own, packaged as a container image. The runtime block is empty, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. +The `byo` harness runs an agent that you built with an agent framework of your own, packaged as a container image. The harness block is empty, and `workload.command` is required, because kagent cannot infer the entrypoint of an image that it does not build. -An image that reads the agent configuration accepts the same model providers and AgentTemplate features as the built-in runtime, except for structured output. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). +An image that reads the agent configuration accepts the same model providers as the `kagent` harness, and kagent rejects structured output on a `byo` Harness. An image that ignores the configuration decides everything itself, and its AgentTemplate needs only a name. For the contract that the image must implement, how to read the configuration, and the known limitations, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). ```yaml kubectl apply -f - <}}). -## Reserved environment variables +## Environment variables on an Actor + +kagent adds variables of its own to every revision, alongside the Harness `spec.env` entries: the agent configuration and the agent card as JSON payloads, a certificate-authority setting for each TLS client that must trust the egress gateway, and `OTEL_RESOURCE_ATTRIBUTES`, which records the revision's service version. Enabling a telemetry signal adds more. All added variables count toward the limits that Agent Substrate enforces, so a Harness cannot spend the whole allowance on `spec.env`. + +Two limits bound the result, and kagent checks both when it builds the Actor template. A Harness that breaks one is admitted, and then reports the failure on its Agents. + +* Agent Substrate accepts at most 32 environment variables on an Actor. A revision that exceeds that count reports `runtime revision has environment variables; Substrate supports at most 32`. +* A single value is capped at 32768 characters. A revision that exceeds that length reports `environment variable "" is characters; Substrate supports at most 32768`. The agent configuration is one of those values, so a long system prompt or a large tool list counts against it. -A Harness tunes telemetry for its own agents by setting `OTEL_*` variables in its `spec.env` field. Each runtime reads its environment first and falls back to the installation's telemetry settings, so a value in `spec.env` wins for that Harness only and leaves every other Harness unchanged. Some variable names are reserved, and a Harness that sets one is rejected. +A Harness tunes telemetry for its own agents by setting `OTEL_*` variables in its `spec.env` field. Each harness reads its environment first and falls back to the installation's telemetry settings, so a value in `spec.env` wins for that Harness only and leaves every other Harness unchanged. Some variable names are reserved, and a Harness that sets one is rejected. -Every runtime reserves the following certificate trust variables. The egress gateway intercepts HTTPS, so a runtime that does not trust the gateway's certificate authority cannot reach a model. +Every harness reserves the following certificate trust variables. The egress gateway intercepts HTTPS, so an agent that does not trust the gateway's certificate authority cannot reach a model. * `SSL_CERT_FILE` and `SSL_CERT_DIR` * `REQUESTS_CA_BUNDLE`, `AWS_CA_BUNDLE`, and `CURL_CA_BUNDLE` @@ -402,9 +328,9 @@ Every runtime reserves the following certificate trust variables. The egress gat A Harness that sets one of these variables reports `runtime environment "" conflicts with gateway trust`. -The `codex` and `claude` runtimes each reserve a second set of variables, which describe the credentials and runtime state that their adapters write. +The `codex` and `claude` harnesses each reserve a second set of variables, which describe the credentials and runtime state that their adapters write. -| Runtime | Additional reserved variables | Effect if set by a Harness | +| Harness | Additional reserved variables | Effect if set by a Harness | | ------- | ----------------------------- | -------------------------- | | `claude` | The Anthropic, AWS, and Vertex AI credential variables, `CLAUDE_CONFIG_DIR`, `DISABLE_UPDATES`, `IS_SANDBOX`, `CLAUDE_CODE_ENABLE_TELEMETRY`, `CLAUDE_CODE_ENHANCED_TELEMETRY_BETA`, `OTEL_TRACES_EXPORTER`, `OTEL_METRICS_EXPORTER`, `OTEL_LOGS_EXPORTER`, Claude's `OTEL_LOG_*` capture flags, `TRACEPARENT`, `TRACESTATE`, and the Prometheus exporter host and port | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Claude-owned runtime configuration`. | | `codex` | `CODEX_HOME`, `OPENAI_API_KEY`, `AWS_REGION`, `AWS_BEARER_TOKEN_BEDROCK`, `AWS_ACCESS_KEY_ID`, `AWS_SECRET_ACCESS_KEY`, and `AWS_SESSION_TOKEN` | Every Agent on the Harness reports `Compatible` as `False`, and the controller reports `Harness env "" conflicts with Codex's compiled configuration`. | @@ -412,17 +338,17 @@ The `codex` and `claude` runtimes each reserve a second set of variables, which Two variables take a value from a Harness without replacing the controller's. * `OTEL_RESOURCE_ATTRIBUTES` is merged. The value in `spec.env` is kept, and the agent identity attributes that the controller adds win where the two name the same attribute. -* `OTEL_EXPORTER_OTLP_HEADERS` has no controller value to replace. No Helm setting produces it and the controller never adds it, but a value in `spec.env` reaches every runtime unchanged. To attach headers without holding them in an Actor environment, export to an in-cluster collector that adds them. +* `OTEL_EXPORTER_OTLP_HEADERS` has no controller value to replace. No Helm setting produces it and the controller never adds it, but a value in `spec.env` reaches every harness unchanged. To attach headers without holding them in an Actor environment, export to an in-cluster collector that adds them. ### Baggage propagation Baggage is a W3C header that travels with a request alongside its trace context. Each entry in that header is a member, which pairs a name with a string value. Every service that the request reaches can read the members that it carries. -By default, a kagent runtime sets `OTEL_PROPAGATORS` to `tracecontext`. That value propagates trace context and drops baggage. A caller's baggage therefore does not reach the tools that an agent calls or the agent's model provider. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the controller. +By default, kagent sets `OTEL_PROPAGATORS` to `tracecontext` on every harness. That value propagates trace context and drops baggage. A caller's baggage therefore does not reach the tools that an agent calls or the agent's model provider. To carry baggage as well, set `OTEL_PROPAGATORS` to `tracecontext,baggage` in the Harness `spec.env` field. The kagent controller reads its own value from the `controller.env` Helm value, so enabling baggage on a runtime does not enable it on the controller. `OTEL_PROPAGATORS` is a list of wire formats that apply to both incoming and outgoing requests. If an incoming request has a format that is not in the list, the format is not read. Similarly, the runtime does not write an omitted format to an outgoing request. When the list omits `baggage`, the runtime's own members are dropped too. -When `baggage` is listed, the `kagent` runtime adds the request's identity to the baggage of each model call and each MCP tool call. +When `baggage` is listed, the `kagent` harness adds the request's identity to the baggage of each model call and each MCP tool call. | Member | Model calls | MCP tool calls | | ------ | ----------- | -------------- | @@ -437,7 +363,7 @@ These members serve as identifiers only, and the runtime can replace a caller's > **Enabling baggage sends the caller's own members to your model provider.** A caller baggage member that kagent does not replace is forwarded unchanged in the `baggage` header of each model API request and each MCP request. This means that a caller controls what reaches those external services in the header. Enable baggage only where you trust what your callers attach. Review and plan for the following considerations. -* The `claude` and `codex` runtimes receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The four members reach only the `kagent` runtime. +* The `claude` and `codex` harnesses receive `OTEL_PROPAGATORS`, but kagent does not add identity to their model and tool calls. The four members reach only the `kagent` harness. * kagent never copies a baggage member onto a span. To make these values searchable, add a baggage-to-attributes span processor to the service that receives the request or to its OpenTelemetry Collector. When an agent requires an MCP server, the first tool listing or tool call opens a session with the MCP server, and every later request to that server shares it. The session makes three requests: the event stream, the replies to server requests, and the close. These requests do not carry trace context or baggage, because these name a request that has already ended. @@ -457,7 +383,7 @@ The following conditions report the three stages that an Agent passes through. | Condition | Report | | --------- | ------ | | `ResolvedRefs` | Whether the resources that the Agent depends on exist. The controller resolves the Harness, the AgentTemplate, and the ModelConfig, and also the WorkerPool that the Harness references. A missing WorkerPool is the most common failure, and the Agent then reports the reason as `WorkerPoolNotFound`. | -| `Compatible` | Whether the Harness's runtime accepts the resolved configuration. A rejected model provider, a reserved environment variable, and an unsupported AgentTemplate feature all fail here. | +| `Compatible` | Whether the harness accepts the resolved configuration. A rejected model provider, a reserved environment variable, and an unsupported AgentTemplate feature all fail here. | | `Ready` | Whether Agent Substrate finished preparing the agent's capacity. | An Agent can also reconcile and still report a non-blocking decision in `status.warnings`, such as Claude binding an MCP server whole. For the conditions in full, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). diff --git a/docs-site/content/kagent/1.x/agents/agent-memory.md b/docs-site/content/kagent/1.x/agents/agent-memory.md index 02774e30..8459827b 100644 --- a/docs-site/content/kagent/1.x/agents/agent-memory.md +++ b/docs-site/content/kagent/1.x/agents/agent-memory.md @@ -1,7 +1,7 @@ --- title: Agent memory description: Give agents long-term memory that persists across conversations, backed by vector similarity search. -weight: 40 +weight: 45 author: kagent.dev --- @@ -25,16 +25,24 @@ Memories are scoped to the agent and to the user who created them, and carry the ## Before you begin -> [!IMPORTANT] -> Memory requires an **external** PostgreSQL database with the [pgvector](https://github.com/pgvector/pgvector) extension installed. The development database that `kagent install` creates uses the stock `postgres` image, which does not ship pgvector, so the database cannot store memories. Point kagent at your own database first. +Agent memory requires your own PostgreSQL database with the [pgvector](https://github.com/pgvector/pgvector) extension installed. The default database that `kagent install` deploys runs the stock `postgres` image, which omits pgvector, so that database cannot store memories. -1. Store the connection string for your database in a Kubernetes Secret, in the same namespace as the kagent controller. +1. Install the pgvector extension in your database, in the schema that kagent reads it from. The `config.database.vectorSchema` value names this schema and defaults to `extensions`. Grant `USAGE` on the schema to the role that kagent assumes after it connects, which the `config.database.role` value names. When you leave `config.database.role` empty, grant `USAGE` to the login user. + ```sql + CREATE SCHEMA IF NOT EXISTS extensions; + CREATE EXTENSION IF NOT EXISTS vector SCHEMA extensions; + GRANT USAGE ON SCHEMA extensions TO ; + ``` + + The kagent migrations create the memory tables, and they never create the extension. Be sure to install it yourself before you enable memory. + +2. Store the connection string for your database in a Kubernetes Secret in the same namespace as the kagent controller. ```bash kubectl create secret generic my-postgres-url-secret -n kagent \ --from-literal=connectionString='postgres://:@:5432/?sslmode=require' ``` -2. Save the following values, which point kagent at your database and run the migration that creates the pgvector extension. +3. Save the following Helm values to point kagent at your database and run the migration that creates the memory tables. ```yaml cat > kagent-memory-values.yaml <}}/{{< reuse "kagent-docs/snippets/helm-kagent.md" >}} \ @@ -61,14 +71,14 @@ Memories are scoped to the agent and to the user who created them, and carry the -f kagent-memory-values.yaml ``` -4. Wait for the controller to roll out with the new configuration. +5. Wait for the controller to roll out with the new configuration. ```bash kubectl rollout status deployment/kagent-controller -n kagent --timeout=300s ``` ## Choose an embedding model -Any provider that the `kagent` runtime supports can serve the embedding model, so the choice typically depends on whichever provider already holds your credentials. The embedding ModelConfig is resolved in the same way that a chat ModelConfig is, which means that the same [provider limitations]({{< link path="setup/model-providers/about-model-providers" >}}) apply to it. +Any provider that the `kagent` harness supports can serve the embedding model, so the choice typically depends on whichever provider already holds your credentials. The embedding ModelConfig is resolved in the same way that a chat ModelConfig is, which means that the same [provider limitations]({{< link path="setup/model-providers/about-model-providers" >}}) apply to it. kagent stores every memory as a **768-dimensional** vector. Models that produce wider vectors are truncated and re-normalized to that width, so no dimension setting is needed and models of different widths can coexist. @@ -120,7 +130,7 @@ Add memory to a Harness that already exists. The examples in these steps use `my | `memory.modelConfigRef.name` | The ModelConfig supplying the embedding model, in the Harness's namespace. Required when `memory` is set. | | `memory.ttlDays` | How many days a stored memory stays valid. Minimum 1. When omitted, the server applies a default of 15 days. | -3. Create a new Session against an {{< gloss "Agent" >}}Agent{{< /gloss >}} that uses this Harness. Editing the Harness compiles a new {{< gloss "Revision" >}}revision{{< /gloss >}}, and an existing Session keeps running the revision it was created from. An agent that was already running does not gain memory until you start a new Session. +3. Create a new Session against an {{< gloss "Agent" >}}Agent{{< /gloss >}} that uses this Harness. Editing the Harness builds a new {{< gloss "Revision" >}}revision{{< /gloss >}}, and an existing Session keeps running the revision it was created from. An agent that was already running does not gain memory until you start a new Session. ```bash kagent agent session create --agent my-first-agent ``` @@ -135,7 +145,7 @@ Add memory to a Harness that already exists. The examples in these steps use `my ``` > [!NOTE] -> Only the `kagent` runtime supports memory. The `memory` block exists only under `spec.kagent`, so a Harness that selects `codex`, `claude`, or `byo` has no settings to configure memory. +> Only the `kagent` harness supports memory. The `memory` block exists only under `spec.kagent`, so a Harness that selects `codex`, `claude`, or `byo` does not take memory settings. ## Verify that memory works @@ -196,7 +206,7 @@ Each memory is one row in the `memory` table, which the vector migration created The SQL query only reads the table. To list or clear memories, call the `MemoryService` that the kagent controller serves over gRPC. -No CLI command wraps the service yet, so these examples call it with [grpcurl](https://github.com/fullstorydev/grpcurl), and both calls take the `agent_name` exactly as the memory table stores it. Be sure to copy the value out of the table rather than assembling it by hand, because an incorrect name fails silently. +No CLI command manages memories, so these examples call the service with [grpcurl](https://github.com/fullstorydev/grpcurl). Both calls take the `agent_name` exactly as the memory table stores it. Be sure to copy the value out of the table rather than assembling it by hand, because an incorrect name fails silently. 1. Port-forward the controller's gRPC port, and confirm that your kagent installation sets `config.server.grpcReflection=true`. ```bash @@ -227,7 +237,7 @@ The memory service also exposes `Search`, `AddSession`, and `AddSessionBatch`. E A memory expires `ttlDays` after it is written, which defaults to 15 days. Expiry is per memory rather than per session, so an old preference ages out while a recent one survives. -Changing `ttlDays` on the Harness applies to memories written by Sessions created after the change, because the value is compiled into the revision. +Changing `ttlDays` on the Harness applies to memories written by Sessions created after the change, because the value is built into the revision. ## Known limitations @@ -238,6 +248,6 @@ Changing `ttlDays` on the Harness applies to memories written by Sessions create ## Next steps {{< cards >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Configure the rest of the Harness that memory is enabled on." >}} + {{< card link=`{{< link path="agents/declarative-agents" >}}` title="Declarative agents" subtitle="Configure the rest of the kagent harness that memory is enabled on." >}} {{< card link=`{{< link path="setup/model-providers/about-model-providers" >}}` title="About model providers" subtitle="Understand how a ModelConfig reaches a running agent." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md index 17cc7781..b45f264c 100644 --- a/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md +++ b/docs-site/content/kagent/1.x/agents/bring-your-own-agent.md @@ -1,62 +1,66 @@ --- title: Bring your own agent -description: Run a container image of your own as a kagent agent by implementing the A2A service that the byo runtime expects. +description: Run a container image of your own as a kagent agent by exposing the A2A service that the byo harness expects. weight: 20 author: kagent.dev --- -The `byo` runtime runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still compiles the {{< gloss "Harness" >}}Harness{{< /gloss >}} and {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} into a {{< gloss "Revision" >}}revision{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this runtime when you already have an agent that is built with an agent framework, and you want to run that agent in kagent. +The `byo` harness runs a container image that you build, and treats what is inside it as opaque. {{< reuse "kagent-docs/snippets/name-product.md" >}} still builds a {{< gloss "Revision" >}}revision{{< /gloss >}} from the {{< gloss "Harness" >}}Harness{{< /gloss >}} and the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}, schedules that revision onto {{< gloss "Agent Substrate" >}}Agent Substrate{{< /gloss >}}, and routes conversations to it. What the image does with a message is yours to decide. Choose this harness when you already have an agent that is built with an agent framework, and you want to run that agent in kagent. -## What kagent runs and what your image runs +## Responsibilities on each side of the A2A boundary -The `byo` runtime divides the work at the {{< gloss "A2A" >}}A2A{{< /gloss >}} (Agent-to-Agent) boundary. Everything on kagent's side of that boundary behaves in the same way as for the built-in runtimes, so a BYO agent is sandboxed, snapshotted, and addressed identically to one that kagent executes itself. +{{< gloss "A2A" >}}A2A{{< /gloss >}} (Agent-to-Agent) is the contract between kagent and a BYO agent. -kagent owns the lifecycle, the isolation, and the routing: +Your image owns one side of the A2A contract by: -- Compiles an {{< gloss "Agent" >}}Agent{{< /gloss >}} into an immutable revision, and creates a {{< gloss "Session" >}}Session{{< /gloss >}} from it. -- Wraps the {{< gloss "Actor" >}}Actor{{< /gloss >}} that the image runs in with a [gVisor sandbox]({{< link path="about/substrate-runtime/sandboxing#sandbox-classes" >}}). -- [Suspends and resumes]({{< link path="about/substrate-runtime/suspend-and-resume#suspension-between-turns" >}}) the Actor between turns, including its in-memory state. -- Routes every conversation through the A2A gateway, so callers address the Agent rather than the Actor behind it. -- Delivers the compiled agent configuration and agent card to the container, which the kagent helpers write to `/config/config.json` and `/config/agent-card.json` at startup. +- Exposing an A2A service that accepts a message and returns a reply. +- Exposing a readiness endpoint that reports when the service can take traffic. +- Deciding what the agent actually does, including model calls, tool calls, and conversation state. -Your image owns the agent's behavior and the two endpoints that expose it: +kagent runs a BYO agent exactly as it runs one on a managed harness, and owns the other side of the A2A contract by: -- An A2A service that accepts a message and returns a reply. -- A readiness endpoint that reports when the service can take traffic. -- Whatever the agent actually does: model calls, tool calls, and conversation state. +- Building an immutable revision from the {{< gloss "Harness" >}}Harness{{< /gloss >}} and the AgentTemplate, and creating a {{< gloss "Session" >}}Session{{< /gloss >}} from it. +- Running the {{< gloss "Actor" >}}Actor{{< /gloss >}} that hosts your image inside a sandbox. The {{< gloss "WorkerPool" >}}WorkerPool{{< /gloss >}} that the Harness references sets the class: `gvisor`, which every installation provides, or `microvm`, which needs its own Agent Substrate provisioning. For more information, see [Sandbox classes]({{< link path="about/substrate-runtime/sandboxing#sandbox-classes" >}}). +- [Suspending and resuming]({{< link path="about/substrate-runtime/suspend-and-resume#suspension-between-turns" >}}) the Actor between turns, including its in-memory state. +- Routing every conversation through the A2A gateway, so callers address the {{< gloss "Agent" >}}Agent{{< /gloss >}} rather than the Actor behind it. +- Delivering the agent configuration and agent card to the container, which the kagent helpers write to `/config/config.json` and `/config/agent-card.json` at startup. Because Agent Substrate snapshots the whole Actor, an image that keeps conversation state in memory keeps it across a suspend. Your image does not need to persist anything to survive the gap between turns. ## The A2A contract -A `byo` image must meet four requirements to run as an agent. kagent enforces only `spec.workload.command` at apply time, and the rest surface as a failed invoke rather than as a validation error. The steps in the [Configure a byo Harness](#configure-a-byo-harness) and [Build the image](#build-the-image) sections later in this page show how to satisfy each requirement. +Both the Harness and the image must meet the following requirements, and kagent enforces them at different moments. Nothing checks the A2A service until a caller invokes the agent, so a misconfigured image reaches a healthy-looking state first. For examples of how to satisfy each requirement, see the steps in [Configure a BYO Harness](#configure-a-byo-harness) and [Build the image](#build-the-image). -| Requirement | Detail | -| ----------- | ------ | -| `spec.workload.command` is set on the Harness | A `byo` Harness must override the image entrypoint, because kagent does not infer it. | -| The container serves gRPC on port 80 | kagent builds the agent card with a single interface, `http://127.0.0.1:80` bound to gRPC, and that address is not configurable. The service is `lf.a2a.v1.A2AService`. | -| The container answers `GET /readyz` on port 8081 | Agent Substrate probes this path to decide when the Actor is ready, with a 30-second timeout. The probe is on a different port from the A2A service on purpose, so serve it independently. | -| The A2A service speaks gRPC, not JSON-RPC | The agent card fixes the protocol binding to gRPC. An image that serves A2A over JSON-RPC alone is never reached, regardless of the port it listens on. | +| Requirement | Checked | Detail | +| ----------- | ------- | ------ | +| `spec.workload.command` is set on the Harness | When you apply the Harness | You must set the entrypoint override on a `byo` Harness. A manifest that omits it is rejected with `BYO harnesses must specify workload.command`. | +| `spec.workload.image` is pinned by digest | When you apply the Harness | A `byo` Harness must name an image, and every Harness must pin it by `sha256` digest. A manifest that omits the image is rejected with `BYO harnesses must specify workload.image`, and a tag alone fails the field's pattern. | +| The container serves gRPC on port 80 | When a caller invokes the agent | kagent builds the agent card with a single interface, `http://127.0.0.1:80` bound to gRPC, and that address is not configurable. The service is `lf.a2a.v1.A2AService`. | +| The container answers `GET /readyz` on port 8081 | When Agent Substrate starts the Actor | Agent Substrate probes this path to decide when the Actor is ready, with a 30-second timeout. The probe is on a different port from the A2A service on purpose, so serve it independently. | +| The A2A service speaks gRPC, not JSON-RPC | When a caller invokes the agent | The agent card fixes the protocol binding to gRPC. An image that serves A2A over only JSON-RPC is never reached, regardless of the port it listens on. | > [!WARNING] -> **An image that listens on another port still reports `READY`.** Readiness is probed on port 8081, which succeeds no matter what the A2A service does, so nothing surfaces the mismatch until an invoke fails with `Connect: tunnel failed`. The compiled configuration sets port `80` in its `runtime.port` field, so an image that reads the configuration binds the right port. An image that ignores the configuration must pin port 80 itself. This gap is tracked as [kagent#2758](https://github.com/kagent-dev/kagent/issues/2758). +> **An image that serves A2A on another port still reports `READY`.** Agent Substrate probes readiness on port 8081. That probe succeeds whether or not the A2A service on port 80 works, so the mismatch stays hidden until the first invoke. The invoke then fails in the gateway with `Connect: tunnel failed`. That message reports only that the gateway could not open a connection to the agent. It does not name a port. To bind the right port, read the `runtime.port` field of the configuration that kagent delivers. An image that ignores the configuration must bind port 80 itself. -## Opaque and configured agents +## Compare BYO and declarative agents -kagent resolves an AgentTemplate for a `byo` Harness in the same way as for the `kagent` runtime, then hands the result to the container. The two ways of using this runtime differ only in whether the image reads it. +kagent resolves the AgentTemplate in the same way for a BYO agent as for a [declarative agent]({{< link path="agents/declarative-agents" >}}), then delivers the result to the container as a JSON document in an environment variable. Both harnesses resolve a ModelConfig through the same code, so the same model providers work and the same ones are rejected. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). -- **An opaque agent ignores the compiled configuration.** The AgentTemplate exists to give the agent an identity and a description, and the image decides everything else, including which model to call and which tools to offer. Every field on an opaque AgentTemplate is optional, `modelConfig` included. -- **A configured agent reads the compiled configuration.** The image honors the AgentTemplate's system prompt, ModelConfig, tool bindings, skills, and plugins, so an operator changes the agent's behavior by editing the AgentTemplate rather than by rebuilding the image. +The kagent harness reads that document and assembles the agent from it. A BYO image decides whether to read it: -kagent builds a revision for the `byo` runtime in the same way that it does for the `kagent` runtime. A configured BYO agent therefore accepts the same model providers and the same AgentTemplate features as the built-in runtime. For the provider matrix, see [Model provider support]({{< link path="agents/agent-harness#model-provider-support" >}}). For what an AgentTemplate can bind, see [Tool and skill support]({{< link path="agents/agent-harness#tool-and-skill-support" >}}). +- **An opaque agent ignores the document.** The AgentTemplate exists to give the agent an identity and a description, and the image decides everything else, including which model to call and which tools to offer. Every field on an opaque AgentTemplate is optional, `modelConfig` included. +- **A configured agent reads the document.** The image applies the AgentTemplate's system prompt, ModelConfig, tool bindings, skills, and plugins itself. Editing the AgentTemplate changes what the agent does without a rebuild. -Both kinds of agent receive the same inputs. Agent Substrate delivers the two JSON payloads as private environment variables, and the kagent helpers write them to files before the agent starts. An image in another language either reads the files that `MaterializeFromEnv` writes or parses the variables itself. +Two AgentTemplate features continue to apply regardless of this choice. First, a `byo` Harness rejects structured output, with `Harness runtime "byo" does not support structured output`. Second, the agent card that kagent advertises for a `byo` Agent leaves out the AgentTemplate's skills and declares no extension, so a client cannot discover human-in-the-loop support the way it can for a declarative agent. -| Input | Contents | -| ----- | -------- | -| `KAGENT_CONFIG_JSON`, which the helpers write to `/config/config.json` | The compiled agent configuration, including the resolved system prompt, the model and its settings, every tool, skill, and plugin that the AgentTemplate binds, and a `runtime` object that sets the process settings. | +Both kinds of BYO agent receive the same environment variables. Agent Substrate delivers the two JSON payloads as private variables, and the kagent helpers write them to files before the agent starts. An image in another language either reads the files that `MaterializeFromEnv` writes or parses the variables itself. + +| Environment variable | Contents | +| -------------------- | -------- | +| `KAGENT_CONFIG_JSON`, which the helpers write to `/config/config.json` | The agent configuration, including the resolved system prompt, the model and its settings, every tool, skill, and plugin that the AgentTemplate binds, and a `runtime` object that sets the process settings. | | `KAGENT_AGENT_CARD_JSON`, which the helpers write to `/config/agent-card.json` | The agent card that kagent advertises for this agent, rendered as JSON. | -| Anything in `spec.env` | The literal values that the Harness sets. The field does not take a secret-backed source, so put credentials on a ModelConfig or a RemoteMCPServer instead. Agent Substrate accepts at most 32 environment variables on an Actor, and the variables that kagent adds count toward that limit. A revision that exceeds 32 is rejected. | +| Anything in `spec.env` | The literal values that the Harness sets. | +| Certificate-authority variables and `SSL_CERT_DIR` | The egress gateway's trust bundle, which every Actor receives. For the list and the limit on how many variables an Actor takes, see [Environment variables on an Actor]({{< link path="agents/agent-harness#environment-variables-on-an-actor" >}}). | The `runtime` object is the root of the configuration document, and subagents inherit it. The object includes the settings that a process needs before it serves a request. @@ -79,16 +83,13 @@ The `runtime` object is the root of the configuration document, and subagents in | `control_plane_url` | The kagent API that the agent reports task state to. Required by the Go and Python helpers. | | `gateway_url` | The A2A gateway that the agent reaches other agents and MCP servers through. | | `name` and `namespace` | The Agent's name and the AgentTemplate's namespace, which kagent's helpers use to scope sessions. | -| `port` | The port to serve A2A on. The controller sets `80` for every runtime, and the agent card advertises that same port. | +| `port` | The port to serve A2A on. The controller sets `80` for every harness, and the agent card advertises that same port. | | `log_level` | `debug`, `info`, `warn`, or `error`, from the `config.runtimeDefaults.logging.level` Helm value. | | `max_content_length` | The largest A2A request body to accept, in bytes. Zero means unlimited, and an absent field keeps the helper's own default. | -> [!IMPORTANT] -> The process settings moved into the configuration document in {{< reuse "kagent-docs/versions/kagent.md" >}}. An image that reads `KAGENT_PORT`, `KAGENT_NAME`, `KAGENT_NAMESPACE`, `KAGENT_API_URL`, or `KAGENT_A2A_GRPC_ADDRESS` reads them as unset, and naming one of these variables in `spec.env` sets a variable that nothing reads. Read the `runtime` object instead. - ## Configure a BYO Harness -A `byo` Harness takes the same fields as any other, minus the runtime settings block. `spec.byo` is an empty object, because the runtime has nothing to configure. The image holds the behavior. +A `byo` Harness takes the same fields as any other Harness. Its own block, `spec.byo`, is an empty object, because the image defines the behavior that the other harnesses take settings for. ```yaml kubectl apply -f - <}}). +The A2A contract is a gRPC service and a readiness endpoint, so any language with a gRPC server can satisfy it. kagent ships helpers for Go and Python. To build and run a minimal image end to end before writing your own, see [Run your own agent image]({{< link path="examples/a2a-byo" >}}). > [!TIP] > The Go helper produces smaller images, faster startup, and lower memory use than the Python one. Where both suit the agent that you are building, prefer Go. @@ -159,6 +160,20 @@ The A2A contract is a gRPC service and a readiness endpoint, so any language wit `github.com/kagent-dev/kagent/go/adk/pkg/app` serves the A2A gRPC service, the readiness endpoint on 8081, and the agent card, given any type that implements `a2asrv.AgentExecutor`. The helper is framework-agnostic, so the executor is the only part that you write. `config.MaterializeFromEnv` writes the payloads that Agent Substrate delivers to `/config`, and `config.LoadAgentConfig` reads the document back. ```go +import ( + "cmp" + "context" + "fmt" + "iter" + "os" + + a2atype "github.com/a2aproject/a2a-go/v2/a2a" + "github.com/a2aproject/a2a-go/v2/a2asrv" + "github.com/kagent-dev/kagent/go/adk/pkg/app" + "github.com/kagent-dev/kagent/go/adk/pkg/config" + "github.com/kagent-dev/kagent/go/pkg/logging" +) + if err := config.MaterializeFromEnv("/config"); err != nil { return err } @@ -186,12 +201,16 @@ if err != nil { return application.Run() ``` -Because the helper reports task state to the kagent API, you must set either `ControlPlaneURL` or your own `ControllerClient` in `app.AppConfig`. When `runtime.port` is omitted or unset, `cmp.Or` supplies `80`. Without that fallback, the helper listens on its own `8080` by default, which kagent never dials. +`app.New` takes an application configuration and an executor, and returns an application that serves the A2A gRPC service and the agent card on the port that the configuration names. These settings in `app.AppConfig` decide whether kagent can reach the result: + +- `Port` is the port the A2A listener binds. `app.AppConfig` defaults it to `8080`, which kagent never dials. Pass `cmp.Or(runtime.Port, "80")` instead to take the port from the configuration and fall back to `80` when the configuration omits it. +- `ControlPlaneURL`, or a `ControllerClient` of your own, is required because the helper reports task state to the kagent API. +- `AppName` scopes sessions. The `runtime.Name` value is the Agent's name. For a complete executor, see [`go/core/test/byoa2a/main.go`](https://github.com/kagent-dev/kagent/blob/main/go/core/test/byoa2a/main.go) in the kagent repository. {{% /tab %}} {{% tab name="Python" %}} -The `kagent-adk` package serves A2A over gRPC and its readiness endpoint on 8081. `KAgentConfig.from_file` materializes the payloads that Agent Substrate delivers and reads the `runtime` object back. The listener defaults to `[::]:80`, which matches what kagent dials. +The `kagent-adk` package provides helpers for agents that are built with the Google Agent Development Kit (ADK). `KAgentApp` wraps an ADK agent rather than an arbitrary framework, serves A2A over gRPC, and answers the readiness endpoint on 8081. `KAgentConfig.from_file` materializes the payloads that Agent Substrate delivers and reads the `runtime` object back. The listener defaults to `[::]:80`, which matches what kagent dials. ```python from kagent.adk import KAgentApp @@ -207,7 +226,7 @@ app = KAgentApp( ).build() ``` -`from_file` raises `ValueError` when the document omits `control_plane_url`, `gateway_url`, `name`, or `namespace`, so a standalone process that runs outside Agent Substrate must supply its own `/config/config.json`. `KAgentApp` wraps a Google Agent Development Kit (ADK) agent rather than an arbitrary framework. +`from_file` raises `ValueError` when the document omits `control_plane_url`, `gateway_url`, `name`, or `namespace`, so a standalone process that runs outside Agent Substrate must supply its own `/config/config.json`. To bind the address that the configuration names rather than the default, pass the parsed document as the `agent_config` argument. The `a2a_grpc_address` argument overrides both. {{% /tab %}} @@ -216,7 +235,7 @@ Implement the contract directly: 1. Serve `lf.a2a.v1.A2AService` over gRPC on port 80. Generate the stubs from the [A2A protocol](https://a2a-protocol.org) definitions. 2. Serve `GET /readyz` over HTTP on port 8081, returning `200`. -3. To honor the AgentTemplate, read the compiled configuration from the `KAGENT_CONFIG_JSON` environment variable. An agent that ignores the variable runs as an opaque agent. +3. To honor the AgentTemplate, read the agent configuration from the `KAGENT_CONFIG_JSON` environment variable. An agent that ignores the variable runs as an opaque agent. The kagent helpers read `KAGENT_CONFIG_JSON` and materialize its contents into `/config/config.json`. An image without those helpers parses the variable directly. {{% /tab %}} @@ -224,16 +243,16 @@ The kagent helpers read `KAGENT_CONFIG_JSON` and materialize its contents into ` ## Known limitations -- **The A2A interface is fixed.** kagent advertises `http://127.0.0.1:80` over gRPC, and `spec.byo` does not take a field that changes the address, the port, or the protocol. An image that serves A2A over HTTP JSON-RPC alone cannot run on this runtime. -- **The `kagent-langgraph` and `kagent-crewai` adapters do not qualify yet.** Both build a FastAPI application with A2A JSON-RPC routes and no gRPC server, so neither satisfies the contract as shipped. Running LangGraph or CrewAI under `byo` currently means serving A2A over gRPC yourself. -- **Long-term memory is unavailable.** Memory is configured under `spec.kagent.memory`, and only the `kagent` runtime wires it up. A `byo` Harness has no equivalent setting. For what a BYO image would need to replace, see [Agent memory]({{< link path="agents/agent-memory" >}}). -- **A broken port mapping presents as a healthy agent.** For the failure and what avoids it, see [The A2A contract](#the-a2a-contract). +- **The A2A interface is fixed.** kagent advertises `http://127.0.0.1:80` over gRPC, and `spec.byo` does not take a field that changes the address, the port, or the protocol. An image that serves A2A over only HTTP JSON-RPC cannot run on this harness. +- **The LangGraph, CrewAI, and OpenAI adapters do not satisfy the contract.** The `kagent-langgraph`, `kagent-crewai`, and `kagent-openai` packages each build a FastAPI application with A2A JSON-RPC routes, without a gRPC server. Running LangGraph, CrewAI, or the OpenAI Agents SDK under `byo` means serving A2A over gRPC yourself, as the **Any other language** tab in [Build the image](#build-the-image) describes. +- **Long-term memory is unavailable.** Memory is configured under `spec.kagent.memory`, and only the `kagent` harness wires it up. A `byo` Harness does not take an equivalent setting. For what a BYO image would need to replace, see [Agent memory]({{< link path="agents/agent-memory" >}}). +- **A broken port mapping looks like a healthy agent.** For the failure and what avoids it, see [The A2A contract](#the-a2a-contract). ## Next steps {{< cards >}} {{< card link=`{{< link path="examples/a2a-byo" >}}` title="Run your own agent image" subtitle="Build the minimal BYO agent, run it on a byo Harness, and invoke it." >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the byo runtime against the three that kagent executes itself." >}} + {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the byo harness against the ones that kagent executes itself." >}} {{< card link=`{{< link path="examples/a2a-agents" >}}` title="Call an agent over A2A" subtitle="Send messages to an Agent with the same protocol that a BYO image serves." >}} {{< card link=`{{< link path="about/substrate-runtime/suspend-and-resume" >}}` title="Suspend and resume" subtitle="Understand what Agent Substrate snapshots while your image is idle." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/context-management.md b/docs-site/content/kagent/1.x/agents/context-management.md index 6002a0a3..a89fe4f6 100644 --- a/docs-site/content/kagent/1.x/agents/context-management.md +++ b/docs-site/content/kagent/1.x/agents/context-management.md @@ -1,15 +1,15 @@ --- title: Context management description: Summarize older session events so an agent's prompt stays bounded as a conversation grows, with two strategies configured on the Harness. -weight: 35 +weight: 40 author: kagent.dev --- An agent's prompt grows with the conversation: every message, tool call, and tool result accumulates, and long sessions eventually exceed the model's context window or degrade answer quality. Context compaction solves that by summarizing older session events so the prompt stays bounded while the agent keeps enough recent context to stay coherent. -Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. It is a property of the runner that drives the root agent, so it is runtime policy rather than portable agent behavior. This is the same Harness-versus-AgentTemplate split that [agent memory]({{< link path="agents/agent-memory" >}}) follows. An AgentTemplate cannot enable, disable, or tune compaction on its own. +This page applies to [declarative agents]({{< link path="agents/declarative-agents" >}}), which run on the `kagent` harness. Compaction is a `spec.kagent` setting, so a Harness that selects `codex`, `claude`, or `byo` does not take compaction settings. Omitting the `compaction` block leaves the history uncompacted. -Compaction is a `spec.kagent` setting, so it applies to the **kagent runtime only**. A Harness that selects `codex`, `claude`, or `byo` has no compaction settings. Omitting the `compaction` block leaves the history uncompacted. +Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The setting belongs to the runner that drives the root agent, which makes compaction harness policy rather than portable agent behavior. This is the same Harness-versus-AgentTemplate split that [agent memory]({{< link path="agents/agent-memory" >}}) follows. An AgentTemplate cannot enable, disable, or tune compaction on its own. Two strategies ship, and both are configured on the same field: @@ -18,7 +18,7 @@ Two strategies ship, and both are configured on the same field: ## Configure compaction -The following manifest enables both strategies on a Harness that already selects the kagent runtime. The `compaction` block is the only change; the rest of the Harness is unchanged. +The following manifest enables both strategies on a Harness that already selects the `kagent` harness. The `compaction` block is the only change. The rest of the Harness is unchanged. ```yaml apiVersion: api.kagent.dev/v1alpha3 @@ -57,7 +57,7 @@ spec: location: s3://ate-snapshots/kagent/ ``` -`Harness.spec.kagent.compaction` is the only field this page owns. The field-by-field schema — types, defaults, and validation rules — lives in the generated [API reference]({{< link path="reference/api-ref#kagentharnesscompaction" >}}); the complete Harness schema, including `workload`, `substrate`, and the runtime selection, lives on [Agent harness]({{< link path="agents/agent-harness" >}}). +`Harness.spec.kagent.compaction` is the only field this page owns. The generated [API reference]({{< link path="reference/api-ref#kagentharnesscompaction" >}}) carries the field-by-field schema, with types, defaults, and validation rules. [Agent harness]({{< link path="agents/agent-harness" >}}) carries the complete Harness schema, including `workload`, `substrate`, and the harness selection. The table below lists the compaction fields and their requirements: @@ -81,21 +81,19 @@ These are CEL validations on the CRD, so a manifest that breaks one is rejected ## Summarizer model and revisions -The summarizer model resolves the same way the agent's own model does: its config lands in the compiled revision, its credentials and egress join the revision, and it joins the provenance. Changing the summarizer model therefore compiles a new revision for every {{< gloss "Agent" >}}Agent{{< /gloss >}} that uses the Harness. +The summarizer model resolves in the same way as the agent's own model: its config lands in the revision, its credentials and egress join the revision, and it joins the provenance. Changing the summarizer model therefore builds a new revision for every {{< gloss "Agent" >}}Agent{{< /gloss >}} that uses the Harness. A {{< gloss "Session" >}}Session{{< /gloss >}} that is already running keeps summarizing with the model that it started with. -Naming an AgentTemplate's own model in `summarizer.modelConfigRef` is semantically a no-op for that AgentTemplate, because the runtime already summarizes with that model by default. The setting applies to every Agent that uses the Harness, so templates that use a different model summarize with the named one instead. It is not free, though. Revision IDs are not content hashes, so any change to the spec recompiles the revision, semantically identical or not, and setting this field carries that revision cost. - -These are the same {{< gloss "Revision" >}}revision{{< /gloss >}} mechanics the rest of the Harness configuration follows — the value is compiled in, not read at request time. +Naming an AgentTemplate's own model in `summarizer.modelConfigRef` is semantically a no-op for that AgentTemplate, because the runtime already summarizes by using that model by default. The setting applies to every Agent that uses the Harness, so templates that use a different model summarize with the named one instead. Setting the field still builds a new revision. A {{< gloss "Revision" >}}revision{{< /gloss >}} ID is a digest of the inputs that kagent resolved, and those inputs include each source resource's `metadata.generation`. Editing the Harness bumps that generation regardless of whether or not the result differs. ## Verify the configuration -If the summarizer names a ModelConfig that does not exist in the Harness namespace, the Agent is not ready. The failure surfaces on the Agent as `ResolvedRefs=False`, with a reason such as `resolve summarizer ModelConfig "x": model config "x" not found`. Confirm the Agent compiled before relying on compaction: +If the summarizer names a ModelConfig that does not exist in the Harness namespace, the Agent is not ready. The failure surfaces on the Agent as `ResolvedRefs=False`, with a reason such as `resolve summarizer ModelConfig "x": model config "x" not found`. Confirm that the Agent is ready before relying on compaction: ```bash kagent agent get ``` -`READY` reports whether kagent compiled and prepared a runtime revision. If `READY` stays `False`, inspect the Agent's conditions to find the failing reference: +`READY` reports whether kagent built and prepared a revision. If `READY` stays `False`, inspect the Agent's conditions to find the failing reference: ```bash kubectl get agent -n kagent -o jsonpath='{.status.conditions}' | jq @@ -106,7 +104,7 @@ For more information, see [Your first agent]({{< link path="get-started/your-fir ## Next steps {{< cards >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Configure the rest of the Harness that compaction is enabled on." >}} + {{< card link=`{{< link path="agents/declarative-agents" >}}` title="Declarative agents" subtitle="Configure the rest of the kagent harness that compaction is enabled on." >}} {{< card link=`{{< link path="agents/agent-memory" >}}` title="Agent memory" subtitle="Give agents on this Harness memory that outlasts a single conversation." >}} {{< card link=`{{< link path="reference/api-ref#kagentharnesscompaction" >}}` title="API reference" subtitle="Field-by-field schema for Harness.spec.kagent.compaction." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/structured-output.md b/docs-site/content/kagent/1.x/agents/structured-output.md index 1fabd7b1..42b36a5e 100644 --- a/docs-site/content/kagent/1.x/agents/structured-output.md +++ b/docs-site/content/kagent/1.x/agents/structured-output.md @@ -5,7 +5,7 @@ weight: 35 author: kagent.dev --- -An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} can require that its final answer is JSON matching a schema. {{< reuse "kagent-docs/snippets/name-product.md" >}} checks the schema when it compiles a {{< gloss "Revision" >}}revision{{< /gloss >}} for an {{< gloss "Agent" >}}Agent{{< /gloss >}}. The revision records the schema and its digest. A schema that fails the checks stops the revision from compiling, so an Agent that has never been ready cannot start a {{< gloss "Session" >}}Session{{< /gloss >}}. At runtime, the agent validates its complete answer against the recorded schema before it publishes the answer. +An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} can require that its final answer is JSON matching a schema. {{< reuse "kagent-docs/snippets/name-product.md" >}} checks the schema when it builds a {{< gloss "Revision" >}}revision{{< /gloss >}} for an {{< gloss "Agent" >}}Agent{{< /gloss >}}. The revision records the schema and its digest. A schema that fails the checks stops the revision from compiling, so an Agent that has never been ready cannot start a {{< gloss "Session" >}}Session{{< /gloss >}}. At runtime, the agent validates its complete answer against the recorded schema before it publishes the answer. The schema goes in one of two AgentTemplate fields, `spec.outputSchema` or `spec.outputSchemaFrom`. The fields are mutually exclusive. An AgentTemplate that sets both is rejected when you apply it, with the message `outputSchema and outputSchemaFrom are mutually exclusive`. If you omit both fields, the agent's final answer is not constrained. @@ -19,7 +19,7 @@ The schema goes in one of two AgentTemplate fields, `spec.outputSchema` or `spec 1. [Create your first agent]({{< link path="get-started/your-first-agent" >}}), so that you have the `my-first-harness` Harness and the `default-model-config` {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} that the AgentTemplates in this guide use. That guide also has you install the kagent CLI and `jq`. - Structured output needs a Harness that uses the `kagent` runtime with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` runtime block and the same `workload.image` as `my-first-harness`. With the `codex`, `claude`, or `byo` runtime, an Agent whose template sets a schema is rejected with `Harness runtime "" does not support structured output`. For the differences between runtimes, see [Agent harness]({{< link path="agents/agent-harness#choose-a-runtime" >}}). + Structured output needs a Harness that uses the `kagent` harness with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` block and the same `workload.image` as `my-first-harness`. On the `codex`, `claude`, or `byo` harness, an Agent whose template sets a schema is rejected with `Harness runtime "" does not support structured output`. For the differences between runtimes, see [Agent harness]({{< link path="agents/agent-harness#choose-a-runtime" >}}). 2. Check your kagent CLI version. The steps on this page need the {{< reuse "kagent-docs/versions/kagent.md" >}} CLI. A CLI from another release can fail with `unknown command`. ```bash @@ -182,9 +182,9 @@ The root of the schema must declare `type: object`. kagent accepts the following - `$defs`, and references to it in the form `#/$defs/`, which cannot be recursive - `$schema` and `$id` -Anything else fails to compile, including `oneOf` and `allOf`, conditional schemas such as `if` and `then`, tuple arrays, references outside `$defs`, and validation keywords such as `pattern`, `format`, `minimum`, and `minLength`. To allow `null` alongside another type, use `anyOf`, because `type` takes one value. +Anything else is rejected, including `oneOf` and `allOf`, conditional schemas such as `if` and `then`, tuple arrays, references outside `$defs`, and validation keywords such as `pattern`, `format`, `minimum`, and `minLength`. To allow `null` alongside another type, use `anyOf`, because `type` takes one value. -kagent also enforces the following limits when it compiles the revision. A schema that exceeds a limit fails to compile, before any agent runs with it. +kagent also enforces the following limits when it builds the revision. A schema that exceeds a limit is rejected, before any agent runs with it. | Limit | Maximum | | ----- | ------- | @@ -295,7 +295,7 @@ For example, if the `shared-schemas` ConfigMap no longer has the `arithmetic-ans | `invalid output schema: schema does not match the portable output profile: ...` | `Compatible`, `UnsupportedConfiguration` | The schema uses a keyword or form outside the [portable output profile](#supported-schemas), or its root is not an object. | | `invalid output schema: resolve schema: ...` | `Compatible`, `UnsupportedConfiguration` | kagent cannot resolve the schema, for example because a `$ref` names a `$defs` entry that does not exist. | | `output schema is incompatible with Go ADK: ...` | `Compatible`, `UnsupportedConfiguration` | The schema has a recursive reference, or exceeds the depth or node limit. | -| `Harness runtime "x" does not support structured output` | `Compatible`, `UnsupportedConfiguration` | The Harness does not use the `kagent` runtime. | +| `Harness runtime "x" does not support structured output` | `Compatible`, `UnsupportedConfiguration` | The Harness does not use the `kagent` harness. | If the Agent has never been ready, `kagent agent session create` fails with `Agent does not have a ready prepared revision`. @@ -324,5 +324,5 @@ A change to a ConfigMap does not change the AgentTemplate's `metadata.generation {{< cards >}} {{< card link=`{{< link path="agents/system-prompts" >}}` title="System prompts" subtitle="Tell the agent what to put in the fields that the schema requires." >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the runtimes that a Harness can use." >}} + {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the four options that a Harness can select." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/system-prompts.md b/docs-site/content/kagent/1.x/agents/system-prompts.md index ebe5d227..7c720f06 100644 --- a/docs-site/content/kagent/1.x/agents/system-prompts.md +++ b/docs-site/content/kagent/1.x/agents/system-prompts.md @@ -1,11 +1,11 @@ --- title: System prompts -description: Set an agent's system prompt inline or from a ConfigMap, and template it with values that kagent resolves at compile time. +description: Set an agent's system prompt inline or from a ConfigMap, and template it with values that kagent resolves when it builds a revision. weight: 30 author: kagent.dev --- -An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}'s system prompt defines the agent's role and how it should behave. {{< reuse "kagent-docs/snippets/name-product.md" >}} resolves the prompt when it compiles a {{< gloss "Revision" >}}revision{{< /gloss >}}, so the text that an agent runs with is fixed for the life of a {{< gloss "Session" >}}Session{{< /gloss >}}. Editing the prompt affects sessions created after the edit compiles, but not ones that are already running. +An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}'s system prompt defines the agent's role and how it should behave. {{< reuse "kagent-docs/snippets/name-product.md" >}} resolves the prompt when it builds a {{< gloss "Revision" >}}revision{{< /gloss >}}, so the text that an agent runs with is fixed for the life of a {{< gloss "Session" >}}Session{{< /gloss >}}. Editing the prompt affects sessions created after the edit, but not ones that are already running. ## Write an effective prompt @@ -61,7 +61,7 @@ Use `systemPromptFrom` to keep the prompt outside the AgentTemplate. Several Age key: kubernetes-assistant ``` - `systemPrompt` and `systemPromptFrom` are mutually exclusive, and an AgentTemplate that sets both is rejected. If you omit both fields, the revision compiles with no system prompt at all, and the agent runs on its harness's default behavior. + `systemPrompt` and `systemPromptFrom` are mutually exclusive, and an AgentTemplate that sets both is rejected. If you omit both fields, kagent builds the revision without a system prompt, and the agent runs on its harness's default behavior. | Field | Description | | ----- | ----------- | @@ -98,7 +98,7 @@ The following values are available to a template. | `.Description` | The AgentTemplate's `spec.description`. | | `.ToolNames` | The tool names selected from every {{< gloss "MCP" >}}MCP{{< /gloss >}} server the AgentTemplate binds. Agents bound as tools are not included. Prefer this value over listing tools by hand, because it cannot drift from the bindings that the AgentTemplate declares. | -Additionally, the `include` function pulls in one key from a ConfigMap that `dataSources` lists. The argument is formatted `"/"`, where the source is the ConfigMap's name. Every key in every listed ConfigMap becomes available, so two sources that share a key name collide. kagent rejects that at compile time rather than picking one. +Additionally, the `include` function pulls in one key from a ConfigMap that `dataSources` lists. The argument is formatted `"/"`, where the source is the ConfigMap's name. Every key in every listed ConfigMap becomes available, so two sources that share a key name collide. kagent rejects the collision when it builds the revision. | Field | Description | | ----- | ----------- | @@ -125,7 +125,7 @@ spec: ## Troubleshooting -Prompt problems surface on the `ResolvedRefs` condition, because they are reference failures rather than runtime errors. No new revision compiles. An {{< gloss "Agent" >}}Agent{{< /gloss >}} that has never been ready cannot start a Session, and one that was ready before keeps starting new Sessions from its last ready revision. +Prompt problems surface on the `ResolvedRefs` condition, because they are reference failures rather than runtime errors. kagent does not build a new revision. An {{< gloss "Agent" >}}Agent{{< /gloss >}} that has never been ready cannot start a Session, and one that was ready before keeps starting new Sessions from its last ready revision. An AgentTemplate does not report status of its own, so read the conditions from the Agent that names it. diff --git a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md index 98373be1..7c77721d 100644 --- a/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md +++ b/docs-site/content/kagent/1.x/operations/upgrade-from-0x.md @@ -58,7 +58,7 @@ Your Kubernetes resources do carry forward, so export them before anything repla ## Install kagent 1.0 -Install 1.0 the same way as a first-time installation, with one addition: point it at the empty database that you provisioned. The full procedure installs Agent Substrate, kagent, and the identity material that they need. +Install 1.0 in the same way as a first-time installation, with one addition: point it at the empty database that you provisioned. The full procedure installs Agent Substrate, kagent, and the identity material that they need. 1. Store the connection string for the empty database in a Secret in the new cluster. ```bash diff --git a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md index 807b8679..da473f1e 100644 --- a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md +++ b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md @@ -5,7 +5,7 @@ weight: 10 author: kagent.dev --- -A `ModelConfig` is a Kubernetes custom resource that names one model at one provider, along with the credentials to reach it. An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} references a {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} by name in its `spec.modelConfig.name` field, and every agent that runs from that template calls the model that the ModelConfig names. +A ModelConfig is a Kubernetes custom resource that names one model at one provider, along with the credentials to reach it. An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} references a {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} by name in its `spec.modelConfig.name` field, and every agent that runs from that template calls the model that the ModelConfig names. The kagent installation creates a `default-model-config` ModelConfig from the provider API key that you supply at install time, so a first agent does not need extra setup. To use a different provider, a different model, or a different set of credentials, create additional ModelConfigs. diff --git a/docs-site/data/glossary.yaml b/docs-site/data/glossary.yaml index cc47f749..df0238d7 100644 --- a/docs-site/data/glossary.yaml +++ b/docs-site/data/glossary.yaml @@ -69,7 +69,7 @@ AgentTemplate: link: "/docs/kagent/1.x/about/core-concepts/#agenttemplate" Harness: - short: "A Kubernetes custom resource defining how an agent is allowed to run: its runtime, workload image, and WorkerPool and snapshot storage. An Agent pairs it with the AgentTemplate it runs." + short: "A Kubernetes custom resource defining how an agent is allowed to run: which of the four harnesses executes it, its workload image, and its WorkerPool and snapshot storage. An Agent pairs it with the AgentTemplate that it runs." link: "/docs/kagent/1.x/about/core-concepts/#harness" Worker: @@ -137,3 +137,7 @@ A2A: gVisor: short: "A user-space kernel that isolates a workload from the host kernel by intercepting its system calls. A default kagent installation compiles ActorTemplates to the gvisor sandbox class." link: "/docs/kagent/1.x/about/substrate-runtime/sandboxing/#sandbox-classes" + +Declarative agent: + short: "An agent built from an AgentTemplate rather than from code. The kagent harness reads that configuration and runs the agentic loop from it. Changing the agent's behavior means editing Kubernetes resources." + link: "/docs/kagent/1.x/agents/declarative-agents/" From dd0985c7f949f62a2b52c1d979c42bb85764ba3d Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 21:34:34 -0500 Subject: [PATCH 6/8] declarative and HITL Signed-off-by: Rachael Graham --- .../kagent/1.x/agents/declarative-agents.md | 122 ++++++++++++++++++ .../kagent/1.x/agents/human-in-the-loop.md | 110 +++++++++------- 2 files changed, 186 insertions(+), 46 deletions(-) create mode 100644 docs-site/content/kagent/1.x/agents/declarative-agents.md diff --git a/docs-site/content/kagent/1.x/agents/declarative-agents.md b/docs-site/content/kagent/1.x/agents/declarative-agents.md new file mode 100644 index 00000000..a0175799 --- /dev/null +++ b/docs-site/content/kagent/1.x/agents/declarative-agents.md @@ -0,0 +1,122 @@ +--- +title: Declarative agents +description: Build an agent from a system prompt, tools, skills, and plugins, and let the kagent harness run the agentic loop. +weight: 15 +author: kagent.dev +--- + +A declarative agent is an agent that you describe rather than build. In an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} resource, you write a system prompt, name a model, and bind the tools, skills, and plugins that the agent can use. The `kagent` {{< gloss "Harness" >}}Harness{{< /gloss >}} then runs kagent's built-in Go engine, which reads the AgentTemplate configuration and runs the agentic loop from it. To change what the agent does, you edit the AgentTemplate. + +## Declarative agents and BYO agents + +kagent runs an agent in one of two ways depending on who owns the agentic loop. A declarative agent hands the loop to kagent. A [BYO agent]({{< link path="agents/bring-your-own-agent" >}}) keeps the loop inside a container image that you build and maintain, and kagent runs the image instead. + +| | Declarative agent | BYO agent | +| --- | --- | --- | +| Harness | `kagent` | `byo` | +| What executes the agent | kagent's built-in Go engine | The container image that you build | +| Where the behavior is defined | The AgentTemplate | The image, which might read the AgentTemplate | +| Changing the behavior | Edit the AgentTemplate | Rebuild the image, unless the image reads the configuration that kagent delivers | +| [Structured output]({{< link path="agents/structured-output" >}}), [long-term memory]({{< link path="agents/agent-memory" >}}), and UI file attachments | Supported | Unsupported | + +Both routes receive the same resolved agent configuration, run in the same sandbox, follow the same snapshot policy, and route through the same gateway. For how a BYO image reads that configuration, and what its agent card leaves out, see [Compare BYO and declarative agents]({{< link path="agents/bring-your-own-agent#compare-byo-and-declarative-agents" >}}). + +The `codex` and `claude` harnesses provide a third route, in which a coding agent owns the loop and takes its configuration from the AgentTemplate. To compare all options side by side, see [Choose a harness]({{< link path="agents/agent-harness#choose-a-harness" >}}). + +## Configure the kagent harness + +Define settings that belong to the engine rather than to the agent in the `spec.kagent` section of the Harness resource. The section takes memory settings, which persist facts across conversations, and compaction settings, which keep a single conversation's prompt within a limit as the conversation grows. + +```yaml +spec: + kagent: + memory: + modelConfigRef: + name: embedding-model-config + ttlDays: 30 + compaction: + tokenThreshold: 120000 + eventRetentionSize: 20 +``` + +Compaction offers two strategies. Tail retention summarizes the older history once the prompt passes a token count, while a sliding window summarizes each group of completed invocations as the conversation goes. Setting `compaction` requires at least one of these two strategies, and setting both is valid. For the rules that the API server enforces, see [Context management]({{< link path="agents/context-management" >}}). + +| Field | Description | +| ----- | ----------- | +| `memory.modelConfigRef.name` | The {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} that supplies the embedding model, in the Harness's namespace. Required when `memory` is set. Setting `memory` gives every agent on this Harness memory that persists across conversations. For how agents store and retrieve it, see [Agent memory]({{< link path="agents/agent-memory" >}}). | +| `memory.ttlDays` | How many days a stored memory entry stays valid. Minimum 1. When omitted, the server applies a default of 15 days. | +| `compaction.tokenThreshold` | Tail retention. The prompt token count that triggers a summary. Once the prompt passes this count, kagent summarizes the older history before the next model call. Requires `compaction.eventRetentionSize`. | +| `compaction.eventRetentionSize` | Tail retention. The number of most recent events that kagent leaves out of that summary, so the latest exchanges reach the model in full. Requires `compaction.tokenThreshold`. | +| `compaction.compactionInterval` | Sliding window. The number of new user-initiated invocations that triggers a summary of those invocations. Set `5` to summarize each group of five. | +| `compaction.overlapSize` | Sliding window. The number of already-summarized invocations that kagent includes in the next summary, so that consecutive summaries overlap and carry context forward. Requires `compaction.compactionInterval`. | +| `compaction.summarizer` | Both strategies. The ModelConfig and prompt template that write the summaries. When omitted, kagent summarizes with the agent's own model and the engine's default prompt. | + +For the fields that every Harness shares, such as the workload image and the Agent Substrate placement, see [Configure a Harness]({{< link path="agents/agent-harness#configure-a-harness" >}}). + +## Apply a complete declarative agent + +The following example applies a declarative agent end to end, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. + +```yaml +kubectl apply -f - <}} + substrate: + workerPoolRef: + name: kagent-default + snapshotPolicy: + location: s3://ate-snapshots/kagent/ +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: AgentTemplate +metadata: + name: kagent-template + namespace: kagent +spec: + modelConfig: + name: kagent-model-config + systemPrompt: You are a concise, helpful assistant. +--- +apiVersion: api.kagent.dev/v1alpha3 +kind: Agent +metadata: + name: my-agent + namespace: kagent +spec: + template: + ref: + name: kagent-template + harnessRef: + name: kagent-harness +EOF +``` + +`spec.kagent` is an empty object in this example, because memory and compaction are both optional. The agent runs without them. + +## Next steps + +{{< cards >}} + {{< card link=`{{< link path="agents/system-prompts" >}}` title="System prompts" subtitle="Write the instruction that shapes what a declarative agent does." >}} + {{< card link=`{{< link path="skills-and-mcp/about-tools" >}}` title="About tools" subtitle="Bind the tools that the agent can call." >}} + {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the kagent harness against the three other ways to run an agent." >}} + {{< card link=`{{< link path="agents/bring-your-own-agent" >}}` title="Bring your own agent" subtitle="Run an agent that you built yourself, on your own container image." >}} +{{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/human-in-the-loop.md b/docs-site/content/kagent/1.x/agents/human-in-the-loop.md index 19a2c1cb..a4f04674 100644 --- a/docs-site/content/kagent/1.x/agents/human-in-the-loop.md +++ b/docs-site/content/kagent/1.x/agents/human-in-the-loop.md @@ -1,22 +1,24 @@ --- title: Human in the loop -description: Understand how an agent pauses to ask a question or to get a tool call approved, and what a client does to answer it. +description: Pause an agent before it acts, return the request to a person, and resume the turn once the person answers. weight: 50 author: kagent.dev --- -An agent that only answers questions can run unattended. An agent that takes action often should not. The human in the loop (HITL) mechanism lets an agent stop mid-turn, return a question or a pending tool call to a person, and continue once that person answers. +Some agents only answer questions, and those can run unattended. Others call tools that change a cluster, spend money, or read sensitive information. An agent that takes actions like those should get a person's approval first. The human in the loop (HITL) mechanism lets an agent stop mid-turn, return a question or a pending tool call to a person, and continue once that person answers. > [!IMPORTANT] -> HITL has two halves, and a working setup needs both. An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} decides which tool calls pause through `requireApproval` on a tool binding. The **client** decides whether it can answer a pause by negotiating the HITL extension on each call. A client that does not request the extension still gets the pause, as the agent stops and the task waits. That client cannot answer, because the request reaches it as text with no correlation `id`. +> A working HITL setup needs two halves. The **agent** must be configured to pause. You set `requireApproval` on a tool binding in an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The **client** must support the A2A human-in-the-loop extension. That extension presents the request to a person and returns the decision to the agent. A client without it still sees the agent stop, and cannot answer. Confirm that the client you plan to use supports the extension before you configure an agent to pause. For which clients qualify, see [Client support](#client-support). ## How a pause works -The following diagram traces one turn in which the agent stops for a person. +A client opens every turn by telling the agent which optional A2A extensions it can handle. A client that requests the HITL extension on that message can answer a pause later in the turn. kagent activates the extension only for the calls that request it, and attaches the pause payload only to those calls. A client that does not request the extension still receives a reply when the turn finishes. When the agent stops for a person, that client has no payload to answer. + +The following diagram traces one turn in which the agent stops. ```mermaid flowchart TB - caller["Client sends a message
requesting the HITL extension"] + caller["Client sends a message and asks
to activate the HITL extension"] working["Agent works on the turn"] decision{"Does the agent need
a person?"} pause["Task state becomes
INPUT_REQUIRED"] @@ -33,20 +35,20 @@ flowchart TB answer --> working ``` -The client opens the turn by sending a message that requests the HITL extension. The agent works until it either finishes, in which case the turn ends, or needs a person. When it needs a person, the task moves to `INPUT_REQUIRED` and its status message carries either a `tool_approval_request` or an `ask_user_request`. The client answers by sending a response message on the same task, and the agent resumes the turn where it left off. +The agent works until it either finishes the turn or needs a person. When it needs a person, the task moves to `INPUT_REQUIRED` and its status message carries either a `tool_approval_request` or an `ask_user_request`. The client answers by sending a response message on the same task, and the agent resumes the turn where it left off. ## Pause kinds -An agent pauses either to get permission before it acts or to ask a question. Each case raises its own request. +An agent pauses either to get permission before it acts or to ask a question. A tool approval and a question raise different requests, but both pause and resume the same way. A client that handles one handles the other with a different payload. | Request | Raised when | The client answers with | | ------- | ----------- | ----------------------- | | `tool_approval_request` | The agent wants to call a tool from a binding that sets `requireApproval`. | `tool_approval_response` | | `ask_user_request` | The agent calls the built-in `ask_user` tool because it needs information only a person has. | `ask_user_response` | -Both use the same pause and resume mechanism, so a client that handles one can handle the other with a different payload. +Every pause also adds a plain text part to its status message that states why the agent stopped. A client that never activated the extension receives that text and nothing else. It can show a person why the agent stopped, but it has no `id` to answer with, so the task stays at `INPUT_REQUIRED`. Treat the text as a diagnostic rather than as a fallback, and send the turn again from a client that requests the extension. The `hint` field of an activated payload holds the same string. -Every pause also puts a text part on its status message, and every runtime composes it the same way, so a client that never activated the extension still learns why the agent stopped. +The `kagent` harness composes this text from the pending calls. The wording depends on what the agent stopped for. | Pause | Text | | ----- | ---- | @@ -55,13 +57,28 @@ Every pause also puts a text part on its status message, and every runtime compo | A tool pause with no hints | `Approval is required for tool(s): delete_file` | | A pause carrying no tool call | `Human input is required before the agent can continue.` | -The `hint` field of an activated payload holds that same string. - -The `kagent` and `codex` runtimes both raise `ask_user_request`. The `claude` runtime does not, because the upstream Claude Code tool that backed it was removed, so a `claude` agent pauses for tool approval only. +The `codex` and `claude` harnesses compose the text differently. Both pass through the hint that Codex or Claude Code supplied with the request, so the wording comes from the coding agent rather than from kagent. ## Require approval for a tool -An agent pauses for a tool only when its binding asks for that. If you set `requireApproval` on an `mcp` tool binding in the AgentTemplate, the agent stops before each call to a tool that the binding exposes. +Approval is a property of a tool binding. For example, if you set `requireApproval` on an `mcp` tool binding in the AgentTemplate, the agent stops before each call to a tool that the binding exposes. + +### Harness support + +The Harness that runs an agent decides which pauses the agent can raise, and how precisely a binding can express approval. + +| Harness | Tool approval | `ask_user` question | Splitting one server across two bindings | +| ------- | ------------- | ------------------- | ---------------------------------------- | +| `kagent` | Supported | Supported | Supported | +| `codex` | Supported | Supported | Rejected, with `RemoteMCPServer "" is bound more than once`. | +| `claude` | Supported | Unsupported, because the upstream Claude Code tool that backed it was removed. A `claude` agent pauses for tool approval only. | Rejected, with `RemoteMCPServer "" is bound more than once`. A binding whose tool selection kagent cannot verify against the server's discovered tools exposes the whole server and reports a warning. | +| `byo` | Decided by your image | Decided by your image | Not applicable | + +kagent passes each binding's `requireApproval` setting to a `byo` image, and the image decides whether to honor it. The agent card for a `byo` Agent never declares the HITL extension, so a client cannot learn from the card that the agent pauses, even when the image implements the extension. For what else that card omits, see [Bring your own agent]({{< link path="agents/bring-your-own-agent#compare-byo-and-declarative-agents" >}}). + +### Configure a binding + +In the following AgentTemplate, the binding sets `requireApproval`, so the agent stops before it calls either Kubernetes tool. ```yaml apiVersion: api.kagent.dev/v1alpha3 @@ -81,37 +98,33 @@ spec: requireApproval: true ``` +{{< reuse "kagent-docs/snippets/review-table.md" >}} For the rest of the binding's fields, see [About tools]({{< link path="skills-and-mcp/about-tools" >}}). + | Field | Description | | ----- | ----------- | | `mcp.tools` | The names of the tools to bind. Omit the list, or leave it empty, to bind every tool that the server offers. | | `mcp.requireApproval` | Pauses before each invocation of a tool that this binding exposes. The pause covers the tools in `mcp.tools`, or every tool on the server when `mcp.tools` is omitted or empty. Omit to run the bound tools without approval. | -For the rest of the binding's fields, see [About tools]({{< link path="skills-and-mcp/about-tools" >}}). - -Approval belongs to the binding rather than to the tool name, so one server can supply both kinds of tool. Bind the tools that need a person in a binding that sets `requireApproval`, and bind the rest in a second binding that omits it. +Approval belongs to the binding rather than to the tool name, so one server can supply tools that require approval alongside tools that do not. Bind the tools that require approval in a binding that sets `requireApproval`, and bind the tools that do not in a second binding that omits it. The `codex` and `claude` harnesses reject a second binding to the same server. An agent on those harnesses applies one approval setting to every tool that the server offers. > [!NOTE] > kagent 0.x named the tools that needed approval in a `requireApproval` list on the `Agent` resource, which matched tool names across every server. In 1.x, approval is a property of one binding, so the same tool name can pause for one server and run freely for another. -Two limits apply to what a binding can express, and both depend on the runtime: +A tool that no binding covers with `requireApproval` runs without a pause. That includes every built-in tool, such as file access, shell, and web search, and every MCP tool on a binding that omits the field. The sandbox contains those calls. For more information, see [Sandboxing]({{< link path="about/substrate-runtime/sandboxing" >}}). -| Runtime | Approval | Splitting one server across two bindings | -| ------- | -------- | ---------------------------------------- | -| `kagent` | Supported. | Supported. | -| `codex` | Supported. | Rejected, with `RemoteMCPServer "" is bound more than once`. | -| `claude` | Supported. | Rejected, with `RemoteMCPServer "" is bound more than once`. A binding whose tool selection kagent cannot verify against the server's discovered tools exposes the whole server and reports a warning. | +## Implement a client that supports human approval -Anything the binding does not cover runs without a pause. A built-in tool, such as file access, shell, or web search, and any MCP tool on a binding that omits `requireApproval`, is approved automatically. The sandbox is the boundary that contains those calls. For more information, see [Sandboxing]({{< link path="about/substrate-runtime/sandboxing" >}}). +HITL is an [A2A](https://a2a-protocol.org) message extension, identified by a versioned URI. The following sections follow a client through one pause, from the header that it sends to the response that it returns. -## Negotiate the extension +### Request the extension -HITL is an [A2A](https://a2a-protocol.org) message extension, identified by a versioned URI. A client requests it by setting that URI as the `A2A-Extensions` header on the call that sends a message. +A client requests the extension by setting the extension URI as the `A2A-Extensions` header on the call that sends a message. ```http A2A-Extensions: https://kagent.dev/extensions/hitl/v1 ``` -kagent activates the extension only for calls that request it, and echoes the activated URI back. An agent's card declares the extension, so a client can discover HITL support before it sends a message. A client that never requests the extension sees ordinary turns until the agent needs a person. The turn then pauses like any other, and that client has no way to answer the request. +kagent activates the extension only for calls that request it. It then echoes the activated URI back, and attaches a structured pause payload only to an activated call. An agent's card declares the extension, so a client can discover HITL support before it sends anything. A gRPC call names the {{< gloss "Agent" >}}Agent{{< /gloss >}} in the standard A2A `tenant` field, as `/`, and requests the extension through a header. Port-forward the controller's gRPC port first, as in [Install kagent]({{< link path="setup/installation" >}}). @@ -128,9 +141,16 @@ grpcurl -plaintext \ }' localhost:8083 lf.a2a.v1.A2AService/SendStreamingMessage ``` -Omitting both a `contextId` and a task ID starts a new conversation. To continue an existing one, set the message's `contextId` to the {{< gloss "Session" >}}Session{{< /gloss >}} ID. Over HTTP, the URL path `/agents/{namespace}/{name}` selects the Agent instead, and no tenant is needed. For both transports, see [Call an agent over A2A]({{< link path="examples/a2a-agents" >}}). +A message that omits both a `contextId` and a task ID starts a new {{< gloss "Session" >}}Session{{< /gloss >}}. To continue an existing one, set the message's `contextId` to the Session ID. Over HTTP, the URL path `/agents/{namespace}/{name}` selects the Agent instead, and no tenant is needed. For both transports, see [Call an agent over A2A]({{< link path="examples/a2a-agents" >}}). + +> [!WARNING] +> A send that omits the header produces a pause that no one can answer. The turn still stops, and its status message states the question as prose, with no `metadata` and no correlation `id`. The client therefore has nothing to render and no `id` to answer with. Re-reading that task with the header does not recover the payload, because kagent never attached one. To prevent this, send the header on every call. Sending it on a read is harmless, and missing it on a send cannot be undone. + +### Read the pause + +When the agent pauses, the task moves to `INPUT_REQUIRED`. The payload arrives in the status message's `metadata`, keyed by the extension URI. The message's `extensions` array lists the same URI. Each payload carries a `type` field that names its shape. kagent stores an attached payload with the task. A later read returns it whether or not that read requests the extension. -When the agent pauses, the payload arrives in the status message's `metadata`, keyed by the extension URI. The URI is also listed in the message's `extensions` array. Each payload carries a `type` field that specifies its shape. +Each type travels in one direction. An agent raises a request, and a client answers with the matching response. | Type | Direction | | ---- | --------- | @@ -139,14 +159,9 @@ When the agent pauses, the payload arrives in the status message's `metadata`, k | `tool_approval_response` | Client to agent | | `ask_user_response` | Client to agent | -> [!WARNING] -> In case of failure, both halves of this negotiation fail silently, and neither failure reports anything. -- **A send that omits the header produces a pause that cannot be answered.** The turn still stops, but its status message carries the question as prose, with no `metadata` and no correlation `id`, so there is nothing to render and no `id` to answer with. Re-reading that task with the header does not recover it, because the payload was never attached. Send the header on every call: it is harmless on a read, and unrecoverable if missed on a send. An attached payload is stored with the task, so a later read returns it whether or not that read requests the extension. -- **A response that omits the `extensions` array is delivered as ordinary text.** kagent ignores the `metadata` payload unless the message itself lists the extension URI in `extensions`. The task resumes and the agent replies, so the call looks like it worked, but the structured decision never reached the agent. - -### Approving or rejecting a tool +### Approve or reject a tool -A `tool_approval_request` lists the pending calls, each with an `id`, the tool `name`, and the `args` the agent chose. The response decides every listed call. +A `tool_approval_request` lists the pending calls, each with an `id`, the tool `name`, and the `args` the agent chose. Present those to a person, then send one `tool_approval_response` that decides every call in the request. ```json { @@ -158,11 +173,11 @@ A `tool_approval_request` lists the pending calls, each with an `id`, the tool ` } ``` -A response must decide every call in the request. A rejection reason is optional but worth sending, because the agent receives it and can adapt rather than simply failing. +A rejection reason is optional and worth sending because the agent receives it and can adapt rather than fail. -### Answering a question +### Answer a question -An `ask_user_request` carries an `id` and a list of `questions`. The response echoes the same `id` and answers them in order. +An `ask_user_request` carries an `id` and a list of `questions`. The response echoes the same `id` and answers the questions in order. ```json { @@ -174,35 +189,38 @@ An `ask_user_request` carries an `id` and a list of `questions`. The response ec } ``` +> [!WARNING] +> Put the extension URI in the response message's `extensions` array as well as in its `metadata`. The `kagent` harness ignores a `metadata` payload that the array does not declare, and delivers the message as ordinary text. The task resumes and the agent replies, so the mistake is silent. The `codex` and `claude` harnesses reject the message with `tool approval response must declare https://kagent.dev/extensions/hitl/v1`. + ## Resume a paused task -A paused task waits. To resume, the client sends a message on the same task and context, carrying the response payload. kagent rejects a resume attempt on a task that is not waiting, with `task is not waiting for input`. +A paused task waits for the client to send a message that carries the response payload, on the same task and context. kagent rejects a resume attempt on a task that is not waiting. -While the task waits, kagent pauses the {{< gloss "Actor" >}}Actor{{< /gloss >}} rather than suspending it. A pause keeps the running process in a full {{< gloss "Snapshot" >}}snapshot{{< /gloss >}} on node-local storage, so a runtime that holds a live process across the wait, such as `codex` or `claude`, continues the same turn on resume. The {{< gloss "Worker" >}}Worker{{< /gloss >}} is released in the meantime, so a conversation that sits at `INPUT_REQUIRED` does not consume pool capacity. For more information on the suspend that a finished turn uses instead, see [Suspend and resume]({{< link path="about/substrate-runtime/suspend-and-resume" >}}). +While the task waits, kagent pauses the {{< gloss "Actor" >}}Actor{{< /gloss >}} rather than suspending it. A pause keeps the running process in a full {{< gloss "Snapshot" >}}snapshot{{< /gloss >}} on node-local storage. A harness that holds a live process across the wait, such as `codex` or `claude`, therefore continues the same turn on resume. The {{< gloss "Worker" >}}Worker{{< /gloss >}} is released in the meantime, so a conversation that sits at `INPUT_REQUIRED` does not consume pool capacity. For more information on the suspend that a finished turn uses instead, see [Suspend and resume]({{< link path="about/substrate-runtime/suspend-and-resume" >}}). Because the {{< gloss "Transcript" >}}transcript{{< /gloss >}} only grows, the question and the answer both stay in the task history, so a later reader can see what was asked and what a person decided. ## Task states -An A2A task moves through several states over its life. Two of them mean that the task has stopped and is waiting on a person, rather than working. +An A2A task moves through several states over its life. The following states mean that the task has stopped and is waiting, rather than working. | State | Meaning | | ----- | ------- | | `INPUT_REQUIRED` | The agent is waiting for a person. This is the state that a tool approval or a question produces. | -| `AUTH_REQUIRED` | The agent is waiting for credentials. kagent's own runtimes never set this state, but its gateway accepts a resume from it, so a `byo` runtime that produces it works. | +| `AUTH_REQUIRED` | The agent is waiting for credentials. kagent's own harnesses never set this state. The gateway accepts a resume from it, so a `byo` image that produces it works. | ## Agents bound as tools -An agent that a parent binds as a tool can raise a pause of its own. The request then carries a `nested` block naming the subagent, along with its task and context, so a client can tell the person which agent is actually asking rather than attributing it to the parent. +An agent that a parent binds as a tool can raise a pause of its own. The request then includes a `nested` block naming the subagent, along with its task and context. A client can therefore tell the person which agent is actually asking rather than attributing the question to the parent. ## Client support -The AgentTemplate decides that a turn pauses, but the client decides whether a person can answer it. What someone can do with a pause therefore depends on which client raised the turn. +The AgentTemplate decides that a turn pauses, and the client that raised the turn decides whether a person can answer it. To add support to a client of your own, see [Implement a client that supports human approval](#implement-a-client-that-supports-human-approval). | Client | HITL | | ------ | ---- | -| Your own A2A client | Full. Request the extension URI and handle the four payload types. | -| An {{< gloss "MCP" >}}MCP{{< /gloss >}} client that supports tasks | Supported. `invoke_agent_instance` returns a task, and input requests surface as MCP elicitations. | +| Your own A2A client | Full. Request the extension URI and handle every payload type. | +| An {{< gloss "MCP" >}}MCP{{< /gloss >}} client that supports tasks | Supported. The `invoke_session` tool returns a task, and input requests surface as MCP elicitations. | | The kagent CLI | Not supported, and a turn that pauses is stranded. `kagent agent invoke` does not request the extension, so an agent that needs a person parks the task at `INPUT_REQUIRED` with nothing to answer it by. The CLI reports `Input required to continue this Session.` and stops there. Send the turn again from a client that requests the extension. | ## Next steps From ce5a655d9c4049bffa70263e07b55f622f4fb7c6 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Wed, 14 Oct 2026 21:55:35 -0500 Subject: [PATCH 7/8] vocab pass Signed-off-by: Rachael Graham --- .../content/kagent/1.x/about/core-concepts.md | 4 ++-- .../substrate-runtime/networking-and-egress.md | 2 +- .../content/kagent/1.x/agents/agent-harness.md | 8 ++++---- .../kagent/1.x/agents/context-management.md | 4 ++-- .../kagent/1.x/agents/declarative-agents.md | 10 ++++++++-- .../kagent/1.x/agents/human-in-the-loop.md | 3 +-- .../kagent/1.x/agents/structured-output.md | 6 +++--- .../content/kagent/1.x/examples/a2a-byo.md | 2 +- .../kagent/1.x/observability/audit-prompts.md | 10 +++++----- .../kagent/1.x/observability/launch-ui.md | 2 +- .../kagent/1.x/observability/tracing.md | 8 ++++---- .../operations/operational-considerations.md | 2 +- .../model-providers/about-model-providers.md | 18 +++++++++--------- docs-site/data/glossary.yaml | 2 +- 14 files changed, 43 insertions(+), 38 deletions(-) diff --git a/docs-site/content/kagent/1.x/about/core-concepts.md b/docs-site/content/kagent/1.x/about/core-concepts.md index 82258744..04513cdf 100644 --- a/docs-site/content/kagent/1.x/about/core-concepts.md +++ b/docs-site/content/kagent/1.x/about/core-concepts.md @@ -14,7 +14,7 @@ author: kagent.dev The new model separates what an agent can do from how it is allowed to run, and then names the pairing explicitly: -- A [**Harness**](#harness) defines how an agent is allowed to run. It picks a harness and the infrastructure policy around it. +- A [**Harness**](#harness) resource defines how an agent is allowed to run. It names the harness that executes the agent, and the infrastructure policy around it. - An [**AgentTemplate**](#agenttemplate) defines what an agent can do: its model, prompt, and tools. - An [**Agent**](#agent) pairs one AgentTemplate with one Harness. Callers address the Agent, and the controller compiles it. - A [**Session**](#session) is a running conversation with an Agent. @@ -64,7 +64,7 @@ Examples include [Claude Code](https://code.claude.com/docs/en/how-claude-code-w A **Harness** in kagent is a Kubernetes custom resource that applies that idea to a cluster. It defines _how an agent is allowed to run_, and specifies: - **Execution**: What runs the agent. A Harness selects exactly one of `kagent`, `codex`, `claude`, or `byo`. `kagent` runs kagent's own agent engine, `codex` runs Codex, `claude` runs Claude, and `byo` runs any image that exposes kagent's A2A contract. Each accepts different model providers and different AgentTemplate features. -- **Workload**: The container image, command, and arguments that the harness runs as. +- **Workload**: The container image, command, and arguments that the agent process runs as. - **Environment**: Literal environment values for the agent process, set in `spec.env`. - **Substrate policy**: The capacity that the agent runs on, and where its state is kept when it goes idle. The Harness names a [WorkerPool]({{< link path="about/architecture/agent-substrate#workers-and-workerpools" >}}) to schedule onto and the storage location that snapshots write to. diff --git a/docs-site/content/kagent/1.x/about/substrate-runtime/networking-and-egress.md b/docs-site/content/kagent/1.x/about/substrate-runtime/networking-and-egress.md index f047e0b8..cb4c51c6 100644 --- a/docs-site/content/kagent/1.x/about/substrate-runtime/networking-and-egress.md +++ b/docs-site/content/kagent/1.x/about/substrate-runtime/networking-and-egress.md @@ -73,7 +73,7 @@ The host set is fixed when kagent compiles the policy, so an agent reaches only -An agent also needs a route to the OpenTelemetry collector, or its traces never leave the sandbox and the kagent UI shows nothing for this Session. kagent adds the collector host for agents on every runtime, `byo` included. A `byo` image that exports to a telemetry backend of its own, through a Harness `spec.env` entry, has no route to that backend, because the AgentTemplate never named it. For more information, see [Runtime coverage]({{< link path="observability/tracing#runtime-coverage" >}}). +An agent also needs a route to the OpenTelemetry collector, or its traces never leave the sandbox and the kagent UI shows nothing for this Session. kagent adds the collector host for agents on every harness, `byo` included. A `byo` image that exports to a telemetry backend of its own, through a Harness `spec.env` entry, has no route to that backend, because the AgentTemplate never named it. For more information, see [Harness coverage]({{< link path="observability/tracing#harness-coverage" >}}). ## Policy changes diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index ae366c5d..10d63ca5 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -11,7 +11,7 @@ This page covers the Harness schema, the four options that a Harness can select, ## Configure a Harness -The following configuration shows a complete Harness. Only `workload`, `substrate`, and one harness block are required. +The following configuration shows a complete Harness resource. Only `workload`, `substrate`, and one harness block are required. ```yaml kubectl apply -f - <}}). diff --git a/docs-site/content/kagent/1.x/agents/context-management.md b/docs-site/content/kagent/1.x/agents/context-management.md index a89fe4f6..5f2bff0c 100644 --- a/docs-site/content/kagent/1.x/agents/context-management.md +++ b/docs-site/content/kagent/1.x/agents/context-management.md @@ -9,7 +9,7 @@ An agent's prompt grows with the conversation: every message, tool call, and too This page applies to [declarative agents]({{< link path="agents/declarative-agents" >}}), which run on the `kagent` harness. Compaction is a `spec.kagent` setting, so a Harness that selects `codex`, `claude`, or `byo` does not take compaction settings. Omitting the `compaction` block leaves the history uncompacted. -Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The setting belongs to the runner that drives the root agent, which makes compaction harness policy rather than portable agent behavior. This is the same Harness-versus-AgentTemplate split that [agent memory]({{< link path="agents/agent-memory" >}}) follows. An AgentTemplate cannot enable, disable, or tune compaction on its own. +Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The setting belongs to the runner that drives the root agent, which makes compaction harness policy rather than portable agent behavior. [Agent memory]({{< link path="agents/agent-memory" >}}) follows the same Harness-versus-AgentTemplate split. An AgentTemplate cannot enable, disable, or tune compaction on its own. Two strategies ship, and both are configured on the same field: @@ -18,7 +18,7 @@ Two strategies ship, and both are configured on the same field: ## Configure compaction -The following manifest enables both strategies on a Harness that already selects the `kagent` harness. The `compaction` block is the only change. The rest of the Harness is unchanged. +The following manifest enables both strategies on a Harness resource that already selects the `kagent` harness. The `compaction` block is the only change. The rest of the Harness is unchanged. ```yaml apiVersion: api.kagent.dev/v1alpha3 diff --git a/docs-site/content/kagent/1.x/agents/declarative-agents.md b/docs-site/content/kagent/1.x/agents/declarative-agents.md index a0175799..fedbdadc 100644 --- a/docs-site/content/kagent/1.x/agents/declarative-agents.md +++ b/docs-site/content/kagent/1.x/agents/declarative-agents.md @@ -55,7 +55,7 @@ For the fields that every Harness shares, such as the workload image and the Age ## Apply a complete declarative agent -The following example applies a declarative agent end to end, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. +The following example applies a declarative agent end to end, from the ModelConfig to the Agent that runs it. The ModelConfig reads its API key from the `kagent-openai` Secret that the [OpenAI]({{< link path="setup/model-providers/openai#create-the-modelconfig" >}}) guide creates. `spec.kagent` is an empty object because memory and compaction are both optional. ```yaml kubectl apply -f - <}}revision{{< /gloss >}} for the pair. + +```bash +kagent agent get my-agent +``` + +A `READY` value of `False` immediately after you apply the Agent is expected, because kagent builds a snapshot of the agent before it reports the Agent ready. If `READY` stays `False`, read the conditions on the Agent to find the stage that failed, asdescribed in [Your first agent]({{< link path="get-started/your-first-agent#create-a-harness-an-agenttemplate-and-an-agent" >}}). To start a conversation with the agent, see [Create a Session]({{< link path="get-started/your-first-agent#create-a-session" >}}). ## Next steps diff --git a/docs-site/content/kagent/1.x/agents/human-in-the-loop.md b/docs-site/content/kagent/1.x/agents/human-in-the-loop.md index a4f04674..95ebb19b 100644 --- a/docs-site/content/kagent/1.x/agents/human-in-the-loop.md +++ b/docs-site/content/kagent/1.x/agents/human-in-the-loop.md @@ -7,8 +7,7 @@ author: kagent.dev Some agents only answer questions, and those can run unattended. Others call tools that change a cluster, spend money, or read sensitive information. An agent that takes actions like those should get a person's approval first. The human in the loop (HITL) mechanism lets an agent stop mid-turn, return a question or a pending tool call to a person, and continue once that person answers. -> [!IMPORTANT] -> A working HITL setup needs two halves. The **agent** must be configured to pause. You set `requireApproval` on a tool binding in an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The **client** must support the A2A human-in-the-loop extension. That extension presents the request to a person and returns the decision to the agent. A client without it still sees the agent stop, and cannot answer. Confirm that the client you plan to use supports the extension before you configure an agent to pause. For which clients qualify, see [Client support](#client-support). +A working HITL setup needs two halves. The agent must pause, which you configure by setting `requireApproval` on a tool binding in an {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The client must support the A2A human-in-the-loop extension, which presents the request to a person and returns the decision to the agent. A client without the extension still sees the agent stop, and cannot answer. Confirm that the client you plan to use supports the extension before you configure an agent to pause. For which clients qualify, see [Client support](#client-support). ## How a pause works diff --git a/docs-site/content/kagent/1.x/agents/structured-output.md b/docs-site/content/kagent/1.x/agents/structured-output.md index 42b36a5e..295582e6 100644 --- a/docs-site/content/kagent/1.x/agents/structured-output.md +++ b/docs-site/content/kagent/1.x/agents/structured-output.md @@ -5,7 +5,7 @@ weight: 35 author: kagent.dev --- -An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} can require that its final answer is JSON matching a schema. {{< reuse "kagent-docs/snippets/name-product.md" >}} checks the schema when it builds a {{< gloss "Revision" >}}revision{{< /gloss >}} for an {{< gloss "Agent" >}}Agent{{< /gloss >}}. The revision records the schema and its digest. A schema that fails the checks stops the revision from compiling, so an Agent that has never been ready cannot start a {{< gloss "Session" >}}Session{{< /gloss >}}. At runtime, the agent validates its complete answer against the recorded schema before it publishes the answer. +An {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}} can require that its final answer is JSON matching a schema. {{< reuse "kagent-docs/snippets/name-product.md" >}} checks the schema when it builds a {{< gloss "Revision" >}}revision{{< /gloss >}} for an {{< gloss "Agent" >}}Agent{{< /gloss >}}. The revision records the schema and its digest. kagent does not build a revision from a schema that fails the checks, so an Agent that has never been ready cannot start a {{< gloss "Session" >}}Session{{< /gloss >}}. At runtime, the agent validates its complete answer against the recorded schema before it publishes the answer. The schema goes in one of two AgentTemplate fields, `spec.outputSchema` or `spec.outputSchemaFrom`. The fields are mutually exclusive. An AgentTemplate that sets both is rejected when you apply it, with the message `outputSchema and outputSchemaFrom are mutually exclusive`. If you omit both fields, the agent's final answer is not constrained. @@ -19,7 +19,7 @@ The schema goes in one of two AgentTemplate fields, `spec.outputSchema` or `spec 1. [Create your first agent]({{< link path="get-started/your-first-agent" >}}), so that you have the `my-first-harness` Harness and the `default-model-config` {{< gloss "ModelConfig" >}}ModelConfig{{< /gloss >}} that the AgentTemplates in this guide use. That guide also has you install the kagent CLI and `jq`. - Structured output needs a Harness that uses the `kagent` harness with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` block and the same `workload.image` as `my-first-harness`. On the `codex`, `claude`, or `byo` harness, an Agent whose template sets a schema is rejected with `Harness runtime "" does not support structured output`. For the differences between runtimes, see [Agent harness]({{< link path="agents/agent-harness#choose-a-runtime" >}}). + Structured output needs a Harness resource that selects the `kagent` harness with the `golang-adk` image, as `my-first-harness` does. For a Harness of your own, use the `kagent` block and the same `workload.image` as `my-first-harness`. On the `codex`, `claude`, or `byo` harness, an Agent whose template sets a schema is rejected with `Harness runtime "" does not support structured output`. For the differences between harnesses, see [Choose a harness]({{< link path="agents/agent-harness#choose-a-harness" >}}). 2. Check your kagent CLI version. The steps on this page need the {{< reuse "kagent-docs/versions/kagent.md" >}} CLI. A CLI from another release can fail with `unknown command`. ```bash @@ -300,7 +300,7 @@ For example, if the `shared-schemas` ConfigMap no longer has the `arithmetic-ans If the Agent has never been ready, `kagent agent session create` fails with `Agent does not have a ready prepared revision`. > [!WARNING] -> A Session keeps the revision that it was created from, and validates its answers against that revision's schema. After you change a schema, create a new Session to use it. A changed schema that fails to compile does not stop new Sessions from starting. They start from the Agent's latest ready revision, which `status.latestSuccessfulRevision` reports, so they use the previous schema. +> A Session keeps the revision that it was created from, and validates its answers against that revision's schema. After you change a schema, create a new Session to use it. A changed schema that fails the checks does not stop new Sessions from starting. They start from the Agent's latest ready revision, which `status.latestSuccessfulRevision` reports, so they use the previous schema. A change to a ConfigMap does not change the AgentTemplate's `metadata.generation`, so check each condition's `lastTransitionTime` to tell whether kagent has seen your fix. diff --git a/docs-site/content/kagent/1.x/examples/a2a-byo.md b/docs-site/content/kagent/1.x/examples/a2a-byo.md index 7a22b605..544f5e93 100644 --- a/docs-site/content/kagent/1.x/examples/a2a-byo.md +++ b/docs-site/content/kagent/1.x/examples/a2a-byo.md @@ -213,7 +213,7 @@ application, err := app.New(app.AppConfig{ `ControlPlaneURL` is required because the helper reports task state to the kagent API. The `cmp.Or` fallbacks keep the image runnable outside Agent Substrate, where no configuration document exists. All of this stays as it is in an agent of your own. -This agent ignores the rest of the compiled configuration. To honor the AgentTemplate instead, read the other fields of the document that `LoadAgentConfig` returns. To review what it holds, see [Bring your own agent]({{< link path="agents/bring-your-own-agent#opaque-and-configured-agents" >}}). +This agent ignores the rest of the configuration. To honor the AgentTemplate instead, read the other fields of the document that `LoadAgentConfig` returns. To review what the document contains, see [Compare BYO and declarative agents]({{< link path="agents/bring-your-own-agent#compare-byo-and-declarative-agents" >}}). ## Build and run your own agent diff --git a/docs-site/content/kagent/1.x/observability/audit-prompts.md b/docs-site/content/kagent/1.x/observability/audit-prompts.md index 12d2de8c..87c97425 100644 --- a/docs-site/content/kagent/1.x/observability/audit-prompts.md +++ b/docs-site/content/kagent/1.x/observability/audit-prompts.md @@ -13,16 +13,16 @@ Audit the prompts (inputs) and replies (outputs) that pass between your agents a The `kagent` runtime does not write prompts or replies to log records, so a logging backend on its own cannot hold a prompt audit trail. Capture is off by default, because the content can include sensitive user and model data. -### What each runtime records +### Content capture by harness -Each runtime records the content on its own instrumentation, so where the content lands differs by runtime. The settings in the last column are the fields in the `config.runtimeDefaults.telemetry` Helm block. For the available runtimes, see [Choose a runtime]({{< link path="agents/agent-harness#choose-a-runtime" >}}). +Each harness records the content on its own instrumentation, so where the content lands differs by harness. The settings in the last column are the fields in the `config.runtimeDefaults.telemetry` Helm block. For the available harnesses, see [Choose a harness]({{< link path="agents/agent-harness#choose-a-harness" >}}). -| Runtime | Where the content goes | Settings | +| Harness | Where the content goes | Settings | | ------- | ---------------------- | -------- | | `kagent` | The `generate_content` span of each model call, in three attributes. See [What a record holds](#what-a-record-holds). | `captureContent` | | `codex` | The runtime's own spans. | `captureContent` | | `claude` | Prompts and tool details on spans, and assistant replies in the runtime's own log records. With `captureRawApiBodies`, the log records also carry the complete provider request and response bodies, which is a fuller record than the spans give you. | `captureContent`, `captureRawApiBodies` | -| `byo` | Wherever the image's own instrumentation records it. The controller sets `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` in this runtime, but an image that does not read the variable records nothing. | `captureContent` | +| `byo` | Wherever the image's own instrumentation records it. The controller sets `OTEL_INSTRUMENTATION_GENAI_CAPTURE_MESSAGE_CONTENT` on this harness, but an image that does not read the variable records nothing. | `captureContent` | For each setting, see the agent harness [telemetry content settings]({{< link path="agents/agent-harness#telemetry-content-settings" >}}). @@ -185,5 +185,5 @@ Turn off content capture, then create a new Session so that the change takes eff {{< cards >}} {{< card link=`{{< link path="observability/tracing" >}}` title="Tracing" subtitle="Read the spans and attributes of an agent request." >}} - {{< card link=`{{< link path="agents/agent-harness#telemetry-content-settings" >}}` title="Telemetry content settings" subtitle="Review how each content setting applies to each runtime." >}} + {{< card link=`{{< link path="agents/agent-harness#telemetry-content-settings" >}}` title="Telemetry content settings" subtitle="Review how each content setting applies to each harness." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/observability/launch-ui.md b/docs-site/content/kagent/1.x/observability/launch-ui.md index eadb7ce2..a1656170 100644 --- a/docs-site/content/kagent/1.x/observability/launch-ui.md +++ b/docs-site/content/kagent/1.x/observability/launch-ui.md @@ -85,7 +85,7 @@ Start at the **Agents** page to review your agents and the resources behind them {{< reuse-image-light src="img/kagent-ui-agents.png" alt="The Agents page, listing agents, templates, and harnesses" caption="Figure: The Agents page" >}} {{< reuse-image-dark srcDark="img/kagent-ui-agents-dark.png" alt="The Agents page, listing agents, templates, and harnesses" caption="Figure: The Agents page" >}} -The **Agents** tab authors the `Agent` custom resource directly. Create one to pair a template with a harness, edit one to change either side, and delete one to retire the pairing. Deleting an Agent leaves its Sessions in place, along with the AgentTemplate and Harness that it named. For CLI steps, see [Create your first agent]({{< link path="get-started/your-first-agent" >}}). +The **Agents** tab authors the Agent custom resource directly. Create one to pair a template with a Harness, edit one to change either side, and delete one to retire the pairing. Deleting an Agent leaves its Sessions in place, along with the AgentTemplate and Harness that it named. For CLI steps, see [Create your first agent]({{< link path="get-started/your-first-agent" >}}). ## Read a conversation diff --git a/docs-site/content/kagent/1.x/observability/tracing.md b/docs-site/content/kagent/1.x/observability/tracing.md index 9d16e871..d23f8e09 100644 --- a/docs-site/content/kagent/1.x/observability/tracing.md +++ b/docs-site/content/kagent/1.x/observability/tracing.md @@ -45,11 +45,11 @@ Each hop reports itself as a separate OpenTelemetry (OTel) service. A tracing ba - **The Agent Substrate router** reports as two services, because its pod runs two containers. The router's own spans, such as its lookup of the Actor for a request, report as `atenet-router`. The spans of the agentgateway proxy that forwards the request to the Worker report as `agentgateway`. Only the `agentgateway` spans join the agent request trace. The `atenet-router` spans form separate [Agent Substrate traces](#agent-substrate-traces). - **Each agent runtime** reports as its own service, named for the {{< gloss "Agent" >}}Agent{{< /gloss >}} it was compiled from. The `my-first-agent` Agent reports as `my-first-agent`. This is a change from kagent 0.x, where every agent reported under one `kagent` service. A backend that you filter by service now shows one entry for each Agent, and adding an Agent adds a service. -### Runtime coverage +### Harness coverage -The controller passes its tracing configuration to every runtime and adds the collector to the Actor's egress allowlist, but the spans that each runtime sends depend on its own instrumentation. For the available runtimes, see [Choose a runtime]({{< link path="agents/agent-harness#choose-a-runtime" >}}). For how the allowlist is built, see [Egress control]({{< link path="about/substrate-runtime/networking-and-egress#policy-generation" >}}). +The controller passes its tracing configuration to every harness and adds the collector to the Actor's egress allowlist, but the spans that each one sends depend on its own instrumentation. For the available harnesses, see [Choose a harness]({{< link path="agents/agent-harness#choose-a-harness" >}}). For how the allowlist is built, see [Egress control]({{< link path="about/substrate-runtime/networking-and-egress#policy-generation" >}}). -| Runtime | What the trace shows | +| Harness | What the trace shows | | ------- | -------------------- | | `kagent` | The runtime's spans. The span names on this page describe this runtime. | | `codex` and `claude` | The runtime's spans, from their own instrumentation. The span names differ from the ones on this page. | @@ -247,7 +247,7 @@ Agent Substrate exports traces only when its Helm release sets `otel.endpoint`, Agent Substrate {{< gloss "Checkpoint" >}}checkpoints{{< /gloss >}} an Actor as soon as the response body closes, which is sooner than a batching span exporter normally sends its buffer. Spans still in the buffer at that moment freeze inside the {{< gloss "Snapshot" >}}snapshot{{< /gloss >}} and reach the backend only when the session next resumes, or never at all for a conversation's last message. -To avoid losing them, the `kagent`, `codex`, and `claude` runtimes flush their span buffer after each A2A handler returns, before the response completes. The flush is unconditional and waits up to three seconds, and no setting changes either. An agent on the `byo` runtime flushes only if its own image does, so a conversation's last turn can lose its spans there. +To avoid losing them, the `kagent`, `codex`, and `claude` runtimes flush their span buffer after each A2A handler returns, before the response completes. The flush is unconditional and waits up to three seconds, and no setting changes either. An agent on the `byo` harness flushes only if its own image does, so a conversation's last turn can lose its spans there. The flush lets a kagent trace arrive promptly rather than on the exporter's own schedule. To understand what suspension does to an Actor, see [Suspend and resume]({{< link path="about/substrate-runtime/suspend-and-resume" >}}). diff --git a/docs-site/content/kagent/1.x/operations/operational-considerations.md b/docs-site/content/kagent/1.x/operations/operational-considerations.md index b07ccf66..92f60cfc 100644 --- a/docs-site/content/kagent/1.x/operations/operational-considerations.md +++ b/docs-site/content/kagent/1.x/operations/operational-considerations.md @@ -57,7 +57,7 @@ After you change these values, you can verify their validity by checking the con The only section of settings that the controller does not apply to itself is `config.runtimeDefaults`. The controller compiles those settings into each agent runtime that it starts. If you want a setting to apply to both the controller and the agents, such as the log level, the telemetry endpoints, or the content capture decision, you must configure that setting in both `config` and `config.runtimeDefaults`. -Each `config.runtimeDefaults` setting is the installation's default. A Harness can replace most of these settings for the agents that run on it by naming the equivalent variable in its `spec.env` field. A small set of names is reserved instead, such as the certificate trust variables that let a runtime reach the egress gateway. For the reserved names and the per-runtime differences, see [Reserved environment variables]({{< link path="agents/agent-harness#reserved-environment-variables" >}}). +Each `config.runtimeDefaults` setting is the installation's default. A Harness can replace most of these settings for the agents that run on it by naming the equivalent variable in its `spec.env` field. A small set of names is reserved instead, such as the certificate trust variables that let a runtime reach the egress gateway. For the reserved names and the per-harness differences, see [Environment variables on an Actor]({{< link path="agents/agent-harness#environment-variables-on-an-actor" >}}). ## Choose a database diff --git a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md index da473f1e..7f2db1e5 100644 --- a/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md +++ b/docs-site/content/kagent/1.x/setup/model-providers/about-model-providers.md @@ -15,7 +15,7 @@ Every ModelConfig shares the same three parts, regardless of the provider that i | Field | Description | | ----- | ----------- | -| `provider` | The provider to use.
  • Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`.
  • Defaults to `OpenAI`.
  • `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore` are rejected on every runtime.
For more information, see [Credentials that kagent rejects](#credentials-that-do-not-compile). | +| `provider` | The provider to use.
  • Accepted values are `OpenAI`, `Anthropic`, `AzureOpenAI`, `Ollama`, `Gemini`, `GeminiVertexAI`, `AnthropicVertexAI`, `Bedrock`, `SAPAICore`, `Foundry`, and `Mistral`.
  • Defaults to `OpenAI`.
  • `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore` are rejected on every harness.
For more information, see [Credentials that kagent rejects](#credentials-that-do-not-compile). | | `model` | The model name, as the provider spells it. | | `stream` | Whether the agent streams its model calls. Defaults to `true`. Set `false` for an endpoint that rejects streaming, which otherwise fails every turn. | | Provider block | A block named after the provider, such as `openAI` or `bedrock`, holding the settings that only that provider takes. An empty block is valid when the provider does not take extra settings. | @@ -81,7 +81,7 @@ Header injection accepts one shape of credential, a static string. A credential | Configuration | Why it cannot be injected | What to use instead | | ------------- | ------------------------- | ------------------- | | `Bedrock` with `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` | IAM keys sign each request locally. | A Bedrock bearer token in `AWS_BEARER_TOKEN_BEDROCK`. See [Amazon Bedrock]({{< link path="setup/model-providers/amazon-bedrock" >}}). | -| `AnthropicVertexAI` and `GeminiVertexAI` | A Google service account key is signed locally to obtain a token, and the `kagent` and `byo` runtimes also mount it as a file. | `Anthropic` or `Bedrock` for Claude models, and `Gemini` for Gemini models. See [Google Vertex AI]({{< link path="setup/model-providers/google-vertexai" >}}). | +| `AnthropicVertexAI` and `GeminiVertexAI` | A Google service account key is signed locally to obtain a token, and the `kagent` and `byo` harnesses also mount it as a file. | `Anthropic` or `Bedrock` for Claude models, and `Gemini` for Gemini models. See [Google Vertex AI]({{< link path="setup/model-providers/google-vertexai" >}}). | | `SAPAICore` | OAuth2 client credentials are exchanged for a token before any request. | A provider that authenticates with an API key. See [SAP AI Core]({{< link path="setup/model-providers/sap-ai-core" >}}). | | A `credentialRef` in a Harness `spec.env` entry | An arbitrary variable does not name a destination or a header to bind it to. | A ModelConfig or a RemoteMCPServer, each of which carries a destination. See [Agent harness]({{< link path="agents/agent-harness#configure-a-harness" >}}). | | `openAI.tokenExchange` | The block reads a mounted service account file to acquire a token. | An endpoint that accepts a static API key. See [OpenAI]({{< link path="setup/model-providers/openai" >}}). | @@ -91,17 +91,17 @@ A rejected credential reports one of two messages. A credential that cannot be i The `Ollama` provider is unaffected when it points at a local daemon, which authenticates with no credential. An Ollama Cloud model reaches `api.ollama.com` with an API key, and that key is injected as a header like any other. For when a model routes to the cloud, see [Ollama]({{< link path="setup/model-providers/ollama" >}}). -## Runtime provider support +## Provider support by harness -The runtime that a {{< gloss "Harness" >}}Harness{{< /gloss >}} selects constrains which providers an agent can use, because each runtime integrates a different set. +The harness that a {{< gloss "Harness" >}}Harness{{< /gloss >}} resource selects constrains which providers an agent can use, because each harness integrates a different set. -- The **`kagent`** runtime integrates every provider, and the **`byo`** runtime integrates the same set, because kagent builds a revision for both runtimes in the same way. -- The **`codex`** runtime integrates only `OpenAI` and `Bedrock`. -- The **`claude`** runtime integrates only `Anthropic` and `Bedrock`. +- The **`kagent`** harness integrates every provider, and the **`byo`** harness integrates the same set, because kagent builds a revision for both harnesses in the same way. +- The **`codex`** harness integrates only `OpenAI` and `Bedrock`. +- The **`claude`** harness integrates only `Anthropic` and `Bedrock`. -A provider is available only when the runtime integrates it and the egress gateway can inject its credential as a header. The `kagent` and `byo` runtimes integrate `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore`, but the gateway cannot inject a Google service account key or a set of OAuth2 client credentials, so kagent rejects a ModelConfig that names any of the three on every runtime. For the alternatives, see [Credentials that kagent rejects](#credentials-that-do-not-compile). +A provider is available only when the harness integrates it and the egress gateway can inject its credential as a header. The `kagent` and `byo` harnesses integrate `AnthropicVertexAI`, `GeminiVertexAI`, and `SAPAICore`, but the gateway cannot inject a Google service account key or a set of OAuth2 client credentials, so kagent rejects a ModelConfig that names any of the three on every harness. For the alternatives, see [Credentials that kagent rejects](#credentials-that-do-not-compile). -Neither `codex` nor `claude` accepts a ModelConfig that sets `defaultHeaders`, `tls`, or `apiKeyPassthrough`, and each narrows the provider settings that it takes. When a ModelConfig names a provider that its runtime does not integrate, the Agent reports the `Compatible` condition as `False` with the reason `UnsupportedConfiguration`. +Neither `codex` nor `claude` accepts a ModelConfig that sets `defaultHeaders`, `tls`, or `apiKeyPassthrough`, and each narrows the provider settings that it takes. When a ModelConfig names a provider that its harness does not integrate, the Agent reports the `Compatible` condition as `False` with the reason `UnsupportedConfiguration`. For the full matrix, including the per-combination restrictions, see [Agent harness]({{< link path="agents/agent-harness#model-provider-support" >}}). diff --git a/docs-site/data/glossary.yaml b/docs-site/data/glossary.yaml index df0238d7..9105618b 100644 --- a/docs-site/data/glossary.yaml +++ b/docs-site/data/glossary.yaml @@ -69,7 +69,7 @@ AgentTemplate: link: "/docs/kagent/1.x/about/core-concepts/#agenttemplate" Harness: - short: "A Kubernetes custom resource defining how an agent is allowed to run: which of the four harnesses executes it, its workload image, and its WorkerPool and snapshot storage. An Agent pairs it with the AgentTemplate that it runs." + short: "A Kubernetes custom resource defining how an agent is allowed to run: which harness executes the agent, its workload image, and its WorkerPool and snapshot storage. An Agent pairs it with the AgentTemplate that it runs." link: "/docs/kagent/1.x/about/core-concepts/#harness" Worker: From 6917de09831e52186eab7789c49db90c4a586465 Mon Sep 17 00:00:00 2001 From: Rachael Graham Date: Thu, 15 Oct 2026 09:30:31 -0500 Subject: [PATCH 8/8] Address review comments on the harness pages Takes Nadine's suggestions on the Harness field table and the Choose a harness intro. The intro sentence they replace counted the ways the harnesses differ, which goes stale the moment a fifth difference appears. Drops "an MCP server is bound whole" in both places it appeared. The clause after it already said the same thing in plain words, so the phrase carried no information a reader could not get from the rest of the row. Replaces "which makes compaction harness policy rather than portable agent behavior" with the consequence it was gesturing at: the same AgentTemplate compacts differently on two Harnesses that set different values. Moves the agent memory pointer to the end so the paragraph finishes on compaction. Normalizes the label for the set of four. The pages had drifted into four names for one thing -- "harness types", "options", "ways", and "harnesses" -- so they all say harnesses now. Where that collided with the resource of the same name, the resource takes the longer form. On the provider rejection sentence, takes "However" and "the following providers" but not "By default". Every model call reaches the provider through the egress gateway, so only the credential-holding half varies, and whether apiKeyPassthrough survives the gateway's header injection is still an open REVIEW note on about-model-providers.md. Co-Authored-By: Claude Opus 5 (1M context) Signed-off-by: Rachael Graham --- .../content/kagent/1.x/agents/agent-harness.md | 14 +++++++------- .../kagent/1.x/agents/context-management.md | 2 +- .../kagent/1.x/agents/declarative-agents.md | 2 +- .../content/kagent/1.x/agents/structured-output.md | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/docs-site/content/kagent/1.x/agents/agent-harness.md b/docs-site/content/kagent/1.x/agents/agent-harness.md index 10d63ca5..263ec8ae 100644 --- a/docs-site/content/kagent/1.x/agents/agent-harness.md +++ b/docs-site/content/kagent/1.x/agents/agent-harness.md @@ -7,7 +7,7 @@ author: kagent.dev A Harness defines how an agent is allowed to run. It names what executes the agent, the container image to start from, and the Agent Substrate capacity and snapshot storage that the agent runs on. A Harness runs nothing by itself. To run an agent, create an Agent that references a Harness and an AgentTemplate, which supplies the system prompt, the model, and the tools. -This page covers the Harness schema, the four options that a Harness can select, and what each one supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). +This page covers the Harness schema, the four harnesses, and what each one supports. For the concept and how it relates to the other resources, see the [core concepts]({{< link path="about/core-concepts#harness" >}}). ## Configure a Harness @@ -40,7 +40,7 @@ EOF | Field | Required | Description | | ----- | -------- | ----------- | -| One of `kagent`, `codex`, `claude`, `byo` | Yes | The harness that executes the agent. Naming none, or more than one, is rejected. For the four available, see [Choose a harness](#choose-a-harness). | +| One of `kagent`, `codex`, `claude`, `byo` | Yes | The harness that executes the agent. Naming none, or more than one, is rejected. To compare the four harnesses, see [Choose a harness](#choose-a-harness). | | `workload.image` | Yes | The container image to run, pinned by `sha256` digest. A tag with no digest is rejected, because a revision must be reproducible. | | `workload.command` | For `byo` | Overrides the image entrypoint, up to 32 entries. Required for the `byo` harness, optional otherwise. Every harness honors an explicit value, the `kagent` harness included, regardless of the language its image is written in. | | `workload.args` | No | Overrides the image arguments, up to 64 entries. An override that you omit stays unset rather than taking a default. | @@ -54,7 +54,7 @@ The image, command, arguments, environment, and resolved AgentTemplate together ## Choose a harness -A Harness names exactly one of the following four options, and that choice decides what executes an agent and how much of kagent's feature set the agent can use. +A Harness resource names exactly one of the following four harnesses, and that choice decides what executes an agent and how much of kagent's feature set the agent can use. | Harness | What it runs | When to use it | | ------- | ------------ | ----------- | @@ -63,7 +63,7 @@ A Harness names exactly one of the following four options, and that choice decid | `claude` | Claude | You want Claude to do the work, with Anthropic or Bedrock as the model. | | `byo` | A container image of your own that implements kagent's A2A contract | You already have an agent that is built with an agent framework, and you want to run that agent in kagent. For more information, see [Bring your own agent]({{< link path="agents/bring-your-own-agent" >}}). | -The harnesses differ in two ways that decide what an agent running on them can do. They accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. +The harnesses accept different model providers, which [Model provider support](#model-provider-support) lists, and they accept different AgentTemplate features, which [Tool and skill support](#tool-and-skill-support) lists. The agent chat in the kagent UI offers file attachments only on the `kagent` harness. An agent on a `byo`, `codex`, or `claude` Harness cannot attach files in the chat. For the file types and size limits that the UI enforces, see [Attach files to a message]({{< link path="observability/launch-ui#attach-files-to-a-message" >}}). @@ -254,7 +254,7 @@ The harness that an agent runs on decides which ModelConfig it can use. The foll | `GeminiVertexAI` | ❌ | ❌ | ❌ | ❌ | | `SAPAICore` | ❌ | ❌ | ❌ | ❌ | -kagent reaches a model provider through the egress gateway, which holds the credential and adds it to each request as an HTTP header. The three rejected providers authenticate in a way that this design cannot serve: +kagent reaches a model provider through the egress gateway, which holds the credential and adds it to each request as an HTTP header. However, the following providers authenticate in a way that this design cannot serve: * `AnthropicVertexAI` and `GeminiVertexAI` authenticate with a Google service account key, which kagent would have to mount as a file. An Actor does not take volumes, so a ModelConfig that names a credential Secret is rejected with `ModelConfig requires volume mounts unsupported by Substrate ActorTemplate`. * `SAPAICore` authenticates with an OAuth client ID and secret, which the runtime exchanges for a token itself. A ModelConfig that names a credential Secret is rejected with `environment credential "" cannot use gateway header injection`. @@ -277,7 +277,7 @@ The `kagent` harness accepts every AgentTemplate feature. Codex and Claude run a | Constraint | Applies to | | ---------- | ---------- | | A subagent binding cannot itself carry tools, skills, plugins, or nested agents, and must use the same provider and credentials as the agent that binds it. | `codex`, `claude` | -| An {{< gloss "MCP" >}}MCP{{< /gloss >}} server is bound whole. Claude does not support partial tool selection, so the agent sees every tool that the server offers. The Agent still reconciles, and reports the decision in `status.warnings` as `Claude RemoteMCPServer "" does not support partial tool selection`. | `claude` | +| The agent sees every tool that an {{< gloss "MCP" >}}MCP{{< /gloss >}} server offers, because Claude does not support partial tool selection. A binding that names a subset of tools binds the whole server instead. The Agent still reconciles, and reports the decision in `status.warnings` as `Claude RemoteMCPServer "" does not support partial tool selection`. | `claude` | | A RemoteMCPServer must use the `STREAMABLE_HTTP` protocol. `SSE` is rejected. | `codex` | | Structured output is rejected, with `Harness runtime "" does not support structured output`. | `codex`, `claude`, `byo` | @@ -386,7 +386,7 @@ The following conditions report the three stages that an Agent passes through. | `Compatible` | Whether the harness accepts the resolved configuration. A rejected model provider, a reserved environment variable, and an unsupported AgentTemplate feature all fail here. | | `Ready` | Whether Agent Substrate finished preparing the agent's capacity. | -An Agent can also reconcile and still report a non-blocking decision in `status.warnings`, such as Claude binding an MCP server whole. For the conditions in full, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). +An Agent can also reconcile and still report a non-blocking decision in `status.warnings`, such as Claude binding every tool on an MCP server. For the conditions in full, see [Your first agent]({{< link path="get-started/your-first-agent" >}}). ## Next steps diff --git a/docs-site/content/kagent/1.x/agents/context-management.md b/docs-site/content/kagent/1.x/agents/context-management.md index 5f2bff0c..bd6af69b 100644 --- a/docs-site/content/kagent/1.x/agents/context-management.md +++ b/docs-site/content/kagent/1.x/agents/context-management.md @@ -9,7 +9,7 @@ An agent's prompt grows with the conversation: every message, tool call, and too This page applies to [declarative agents]({{< link path="agents/declarative-agents" >}}), which run on the `kagent` harness. Compaction is a `spec.kagent` setting, so a Harness that selects `codex`, `claude`, or `byo` does not take compaction settings. Omitting the `compaction` block leaves the history uncompacted. -Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The setting belongs to the runner that drives the root agent, which makes compaction harness policy rather than portable agent behavior. [Agent memory]({{< link path="agents/agent-memory" >}}) follows the same Harness-versus-AgentTemplate split. An AgentTemplate cannot enable, disable, or tune compaction on its own. +Compaction is configured on the {{< gloss "Harness" >}}Harness{{< /gloss >}}, not on the {{< gloss "AgentTemplate" >}}AgentTemplate{{< /gloss >}}. The setting belongs to the runner that drives the root agent, so the same AgentTemplate compacts differently on two Harnesses that set different values. An AgentTemplate cannot enable, disable, or tune compaction on its own. [Agent memory]({{< link path="agents/agent-memory" >}}) follows the same Harness-versus-AgentTemplate split. Two strategies ship, and both are configured on the same field: diff --git a/docs-site/content/kagent/1.x/agents/declarative-agents.md b/docs-site/content/kagent/1.x/agents/declarative-agents.md index fedbdadc..61e2c1d0 100644 --- a/docs-site/content/kagent/1.x/agents/declarative-agents.md +++ b/docs-site/content/kagent/1.x/agents/declarative-agents.md @@ -123,6 +123,6 @@ A `READY` value of `False` immediately after you apply the Agent is expected, be {{< cards >}} {{< card link=`{{< link path="agents/system-prompts" >}}` title="System prompts" subtitle="Write the instruction that shapes what a declarative agent does." >}} {{< card link=`{{< link path="skills-and-mcp/about-tools" >}}` title="About tools" subtitle="Bind the tools that the agent can call." >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the kagent harness against the three other ways to run an agent." >}} + {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the kagent harness against the other three." >}} {{< card link=`{{< link path="agents/bring-your-own-agent" >}}` title="Bring your own agent" subtitle="Run an agent that you built yourself, on your own container image." >}} {{< /cards >}} diff --git a/docs-site/content/kagent/1.x/agents/structured-output.md b/docs-site/content/kagent/1.x/agents/structured-output.md index 295582e6..a502b69e 100644 --- a/docs-site/content/kagent/1.x/agents/structured-output.md +++ b/docs-site/content/kagent/1.x/agents/structured-output.md @@ -324,5 +324,5 @@ A change to a ConfigMap does not change the AgentTemplate's `metadata.generation {{< cards >}} {{< card link=`{{< link path="agents/system-prompts" >}}` title="System prompts" subtitle="Tell the agent what to put in the fields that the schema requires." >}} - {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the four options that a Harness can select." >}} + {{< card link=`{{< link path="agents/agent-harness" >}}` title="Agent harness" subtitle="Compare the four harnesses and what each one supports." >}} {{< /cards >}}