> ## Documentation Index
> Fetch the complete documentation index at: https://docs.agentium.in/llms.txt
> Use this file to discover all available pages before exploring further.

# Choose steps, context, and completion

> Use step controllers, model roles, summary context, and reflection without bypassing runtime budgets.

The runtime offers three control points: a `StepController` selects the next model/tool configuration; a `ContextPolicy` builds a request from history; a `CompletionPolicy` accepts, revises, stops, or requests input after the driver returns.

## Select tools and model roles

A controller may implement `prepareRun(ctx)` and `prepareStep({ index, tools }, ctx)`. Either returns `StepOverrides` or `undefined`.

| Override | Constraint |
| - | - |
| `activeToolIds` | Must stay within granted, available tools and retain required tools. |
| `modelRole` | Must be granted and have a host provider binding, except the driver's default `main` provider. |
| `options` | Every overridden `ModelConfig` field must be allowed by that role's binding. |
| `contextPolicy` | Selects a context projection for the step. |
| `stop` | `{ reason }` stops execution before the next admitted model call. |

Opaque provider continuation data prevents unsafe model-role switching. Do not treat role selection as a way to move arbitrary provider state between models.

## Reflect on an answer and summarize long context

This complete configuration uses a separate role for policy calls. It constructs a runtime; it does not execute a request until you call `run()`.

```typescript theme={null}
import { openai } from "@agentium/core";
import {
  agentDriver,
  HarnessRuntime,
  reflectionPolicy,
  summaryContextPolicy,
} from "@agentium/harness";

const model = openai(process.env.OPENAI_MODEL ?? "gpt-6.1-sol");
export const runtime = new HarnessRuntime({
  driver: agentDriver({ name: "writer", model, instructions: "Answer the user's question clearly." }),
  models: {
    reviewer: { provider: model, options: ["maxTokens"] },
  },
  grants: { toolIds: [], modelRoles: ["main", "reviewer"] },
  budgets: { maxModelCalls: 8, maxToolCalls: 0, maxTokens: 16_000, maxRevisions: 1 },
  contextPolicy: summaryContextPolicy({
    modelRole: "reviewer",
    maxContextTokens: 6000,
    keepRecentTurns: 1,
    summaryMaxTokens: 1024,
  }),
  completionPolicy: reflectionPolicy({
    modelRole: "reviewer",
    criteria: "Answer the question directly. Do not claim sources that were not supplied.",
    maxTokens: 1024,
  }),
});
```

Both policies call `services.controlModel()`. These calls use shared budgets, cancellation, and events, but skip task controllers, context projection, and middleware to avoid recursion. They cannot execute tools or reuse task continuation state. The active task model role and tools remain unchanged.

## Reflection options and decisions

`reflectionPolicy()` requires `modelRole` and host-authored `criteria`. Optional `id` defaults to `agentium/reflection`, `maxInputBytes` to `65,536`, and `maxTokens` to `1,024`. Limits must be positive safe integers; the role's binding must allow `maxTokens`.

The model must return a valid JSON decision. Unknown fields, malformed JSON, an empty reason, an invalid action, or a revision without an instruction fail evaluation. Responses over 64 KB are rejected.

| Action | Runtime behavior |
| - | - |
| `accept` | Accept the output, then process any queued follow-up. |
| `revise` | Run again using `instruction`, within `maxRevisions` and the same budgets. |
| `stop` | Settle with `stopped`. |
| `await_input` | Settle with `awaiting_input`; further input starts a new run in the session. |

Every decision has `reason` and optional `evidence: string[]`. Only `revise` has `instruction`. At the revision limit the runtime returns `stopped` with `revision_limit`. New tool effects in revisions require `allowRevisionEffects: true` in addition to normal grants and execution policy.

## Summary context options

`summaryContextPolicy()` requires `modelRole` and `maxContextTokens`, an estimate for the projected request including retained turns, instructions, and summary. Its defaults are:

| Option | Default |
| - | - |
| `id` | `agentium/summary-context` |
| `keepRecentTurns` | `1` complete turn group, including the live turn |
| `summaryMaxTokens` | `1024` |
| `maxInputBytes` | `65536` |

The policy avoids a summary call when the request already fits. It preserves host system messages and complete recent turn groups, including tool-call/result and provider continuation structure. An indivisible recent turn, source group, or summary that cannot fit causes an error rather than silently producing a malformed request.

Summarization changes the model request projection. It does not overwrite canonical session history.

## Implement your own policies

`ContextPolicy.project({ history, entries }, ctx)` returns `{ messages, provenance }`. Each provenance item identifies a `sourceId`, whether it was `included`, and an optional `reason`. Preserve valid message groups and supply provenance matching the projected sources.

`CompletionPolicy.evaluate({ text, structured, revision }, ctx)` returns a `CompletionDecision`. A deterministic policy can return a decision without a model call. Use `controlModel` only when model evaluation adds value and bind its role explicitly.

See [all controller and policy types](/harness/api/policies), [grants and budgets](/harness/runtime), and [source context](/harness/context).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.