Skip to main content

Runtime

@agentskit/runtime is the execution engine for autonomous agents. It runs a ReAct loop — observe, think, act — until the model produces a final answer or a step limit is reached.

When to use

  • Headless agents (CLI workers, jobs, tests) with tools, memory, retrieval, and optional delegation.
  • You already use @agentskit/adapters; the same factories work here.

For interactive terminal chat prefer @agentskit/ink; for browser UI prefer @agentskit/react.

Install

npm install @agentskit/runtime @agentskit/adapters

@agentskit/core is included transitively; add it explicitly if you need types without pulling the full runtime graph.

Basic usage

import { createRuntime } from '@agentskit/runtime'
import { anthropic } from '@agentskit/adapters'

const runtime = createRuntime({
adapter: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, model: 'claude-sonnet-4-6' }),
})

const result = await runtime.run('What is 3 + 4?')
console.log(result.content) // "7"

Demo adapter (no API key)

import { createRuntime } from '@agentskit/runtime'
import { generic } from '@agentskit/adapters'

const runtime = createRuntime({
adapter: generic({ /* custom send/parse */ }),
})

ReAct loop

Each call to runtime.run() enters the following loop:

observe  →  think  →  act  →  observe  →  ...
  1. Observe — retrieve context from memory or a retriever and inject it into the prompt.
  2. Think — send messages + tools to the LLM and stream the response.
  3. Act — if the LLM calls tools, execute them and append results as tool messages.
  4. Repeat until the model returns a plain text response or maxSteps is reached.

RunResult

runtime.run() resolves to a RunResult object:

interface RunResult {
content: string // Final text response from the model
messages: Message[] // Full conversation including tool calls and results
steps: number // How many loop iterations ran
toolCalls: ToolCall[] // Every tool call made during the run
durationMs: number // Total wall-clock time
}

Example

const result = await runtime.run('List the files in the current directory', {
tools: [shell({ allowed: ['ls'] })],
})

console.log(result.content) // Model's final answer
console.log(result.steps) // e.g. 2
console.log(result.durationMs) // e.g. 1340
result.toolCalls.forEach(tc => {
console.log(tc.name, tc.args, tc.result)
})

RuntimeConfig

interface RuntimeConfig {
adapter: AdapterFactory // Required — the LLM provider
tools?: ToolDefinition[] // Tools available to the agent
systemPrompt?: string // Default system prompt
memory?: ChatMemory // Persist and reload conversation history
retriever?: Retriever // RAG source injected each step
observers?: Observer[] // Event listeners (logging, tracing)
maxSteps?: number // Max loop iterations (default: 10)
temperature?: number
maxTokens?: number
delegates?: Record<string, DelegateConfig>
maxDelegationDepth?: number // Default: 3
}

RunOptions

Override per-call defaults on runtime.run(task, options):

const result = await runtime.run('Summarize this document', {
systemPrompt: 'You are a concise summarizer.',
tools: [readFileTool],
maxSteps: 5,
skill: summarizer,
})

Aborting a run

Pass an AbortSignal to cancel mid-run. The runtime checks the signal before each step and before each tool call.

const controller = new AbortController()

setTimeout(() => controller.abort(), 5000) // cancel after 5 s

const result = await runtime.run('Long running task', {
signal: controller.signal,
})

Memory

When a memory is configured, the runtime saves all messages at the end of each run. On the next run it reloads prior context automatically.

import { createRuntime } from '@agentskit/runtime'
import { createInMemoryMemory } from '@agentskit/core'
import { anthropic } from '@agentskit/adapters'

const runtime = createRuntime({
adapter: anthropic({ apiKey: process.env.ANTHROPIC_API_KEY!, model: 'claude-sonnet-4-6' }),
memory: createInMemoryMemory(),
})

await runtime.run('My name is Alice.')
const result = await runtime.run('What is my name?')
console.log(result.content) // "Your name is Alice."

For durable storage use sqliteChatMemory or redisChatMemory from @agentskit/memory.

Memory is saved after RunResult is assembled — if you abort early, partial messages are still persisted up to the abort point.

Retriever (RAG)

Pass a Retriever (for example from createRAG) via retriever in RuntimeConfig. Each loop step can inject retrieved context before the model thinks — same contract as chat UI.

Observers

observers accepts Observer instances from @agentskit/core for low-level events. Pair with @agentskit/observability when you need structured traces.

Troubleshooting

SymptomLikely fix
Hits maxSteps with no answerModel keeps calling tools; raise maxSteps, tighten tool descriptions, or adjust system prompt.
Tool timeout / hangAdd signal with a deadline; ensure tools reject on overload.
No prior contextConfirm memory uses the same conversationId (for backends that scope by id).
Empty retrievalCheck embedder dimensions match vector store; verify ingest ran for your corpus.

See also

Start here · Packages · TypeDoc (@agentskit/runtime) · Tools · Skills · Delegation · @agentskit/core