Skip to main content
createHarness<State, TOOLS, OutputDefinition>(spec): Harness<TOOLS, OutputDefinition>
Construct a portable AI SDK v6 turn engine over an explicit ports object. Type Parameters Parameters Returns Harness<TOOLS, OutputDefinition>

spec.ports

ports: AgentHarnessPorts<State>
Persistent host capabilities supplied through the versioned ports seam.

spec.model

model: LanguageModel
AI SDK v6 language model. Any AI SDK provider supplies the model. A failed call to it surfaces as HarnessProviderError, which keeps only allow-listed diagnostics.

spec.models

optional models?: Readonly<Record<string, LanguageModel>>
Host-owned models selectable only by a named runtime configuration key. The runtime configuration selects one for a turn by its name.

spec.tools

tools: TOOLS
The one explicit, flat tool set available to the model. Tools are keyed by the name the model calls them by. createHarness() throws a TypeError unless every tool follows these rules.
  • It has an execute function.
  • It is an ordinary function tool, not a dynamic or provider tool.
  • It sets needsApproval only to true.
  • It uses no deferred results, no toModelOutput and none of the onInput hooks.
A tool with needsApproval: true runs only inside a persistent run. A direct turn() whose tools include one throws TypeError("Harness approval-capable tools require durable runs"). Such a turn starts with accept() and executes through run().

spec.activeTools

optional activeTools?: readonly (keyof TOOLS & string)[]
Optional static subset of the injected tool set. When it is given, only the named tools are offered to the model. The runtime configuration can offer another subset for a turn.

spec.authorization

optional authorization?: Readonly<{ approvalTtlMs?: number; toolActions: Readonly<Record<string, string>>; }>
Private, host-owned Service Account action mapping. Every supplied tool is mapped exactly once when approval-capable tools are present; model/tool metadata is never treated as an authorization authority. Both fields are required when any tool sets needsApproval. createHarness() throws a TypeError when a rule is broken.
  • toolActions maps each tool in spec.tools to an action, and names no other tool.
  • An action is one or more runs of letters and digits joined by dots, such as orders.refund, at most 512 bytes.
  • approvalTtlMs is an approval’s lifetime from its request, in milliseconds, from 300000 (5 minutes) to 86400000 (24 hours).
approvals decides each held call.

spec.instructions

optional instructions?: string
Optional static instructions supplied to every model step. The text is the model’s system prompt on every step. The harness assembles nothing into it, so its content is decided before the harness is built.

spec.output

optional output?: OutputDefinition
Optional host-owned structured output mode. output is an AI SDK output definition, such as Output.object({ schema }) from ai. The model’s final text is parsed through it, and the parsed value is returned as output in the HarnessTurnResult, beside text. A harness with output or outputs cannot take begin() turns.

spec.outputs

optional outputs?: Readonly<Record<string, OutputDefinition>>
Host-owned output modes selectable only by a named runtime configuration key. The runtime configuration selects one for a turn by its name.

spec.limits

limits: Readonly<{ steps: number; }>
Required bounded turn limits. steps is a positive integer that bounds the model steps of one turn. When the last allowed step still calls a tool, the turn throws HarnessStepLimitError. The runtime configuration can replace it for a turn.

spec.middleware

optional middleware?: Readonly<{ modelStep?: readonly HarnessMiddleware<HarnessModelStepMiddlewareContext<TOOLS>, unknown>[]; tool?: readonly HarnessMiddleware<HarnessToolMiddlewareContext<TOOLS>, unknown>[]; turn?: readonly HarnessMiddleware<HarnessTurnMiddlewareContext<TOOLS, OutputDefinition>, HarnessTurnResult<HarnessParsedOutput<OutputDefinition>>>[]; }>
Ordered transport-neutral lifecycle middleware. Each list wraps one phase of a turn.
  • turn wraps the whole turn.
  • modelStep wraps each call to the model, and requires a model object rather than a model id.
  • tool wraps each tool execution.
A list runs in its given order, its first entry outermost. An entry that does not call next ends the phase with its own result. A harness with turn or modelStep middleware cannot take begin() turns. HarnessMiddleware documents the contexts.

spec.durability

optional durability?: Readonly<{ checkpoints?: HarnessCheckpoint; onToolCallStart?: GenerateTextOnToolCallStartCallback<TOOLS>; toolStepVersion?: string; }>
Deterministic persistence seams used by recovery tests. A host leaves durability unset. Its seams exist for recovery tests.

Runtime Configuration

At the start of every turn, the harness reads one key of the instance’s state, __telnyx_agent_harness, and resolves the turn’s configuration from it.
  • model and output name an entry of spec.models and spec.outputs.
  • instructions replaces the static text.
  • tools names the tools offered, from spec.tools, in place of spec.activeTools.
  • limits.steps replaces the step limit.
Every field is optional, and a field left out or null takes its static value. A value that does not validate, such as one with an unknown name or key, is ignored whole, and the last valid configuration stands.