Production runtime substrate for domain agents. Owns the task lifecycle
(knowledge readiness, control loop, session resume, sanitized telemetry,
canonical RuntimeRunRow persistence + cost ledger) so domain repos stop
inventing their own.
pnpm add @tangle-network/agent-runtime @tangle-network/agent-eval| Entry point | When to reach for it |
|---|---|
runAgentTask |
Single-shot adapter-driven task with eval/verification |
runAgentTaskStream |
Streaming product loop with session resume + backends |
startRuntimeRun |
Canonical production-run row + cost ledger |
createTraceBridge |
Map RuntimeStreamEvent → agent-eval TraceEvent |
decideKnowledgeReadiness |
ready / blocked / caveat branch for routes / UI |
createOpenAICompatibleBackend |
OpenAI-compatible streaming backend (TCloud / cli-bridge) |
createSandboxPromptBackend |
Sandbox / sidecar streamPrompt clients |
createRuntimeStreamEventCollector |
Default-redacted sanitized telemetry over a stream |
Every public export is annotated @stable or @experimental. @stable
exports do not change shape inside a minor; @experimental exports may
change inside a minor and require a deliberate consumer bump.
import { runAgentTask } from '@tangle-network/agent-runtime'
const result = await runAgentTask({
task: {
id: 'review-2026-return',
intent: 'Review the return for missing evidence',
domain: 'tax',
},
adapter: {
async observe() { return { /* domain state */ } },
async validate({ state }) { return [/* eval results */] },
async decide({ state }) {
return { type: 'stop', pass: true, score: 1, reason: 'review complete' }
},
async act() { return undefined },
},
})
console.log(result.status, result.runRecords)startRuntimeRun records what the agent did on behalf of a customer,
what it cost, and how it ended. Replaces bespoke agentRuns-row helpers
across consumer repos with a single contract.
import { startRuntimeRun, runAgentTaskStream } from '@tangle-network/agent-runtime'
const run = startRuntimeRun({
workspaceId: 'ws-1',
sessionId: threadId,
agentId: 'legal-chat-runtime',
taskSpec,
scenarioId: `legal-chat:${threadId}`,
adapter: { upsert: (row) => db.insert(agentRuns).values(row) },
})
for await (const event of runAgentTaskStream({ task: taskSpec, backend, input })) {
run.observe(event) // llm_call events update the cost ledger
if (event.type === 'final') {
run.complete({
status: event.status === 'completed' ? 'completed' : 'failed',
resultSummary: event.text ?? '',
error: event.status === 'failed' ? event.reason : undefined,
})
}
}
await run.persist({ runtimeEvents: telemetry.events })
console.log(run.cost()) // { tokensIn, tokensOut, costUsd, wallMs, llmCalls }Full runnable: examples/runtime-run/.
If you persist traces in agent-eval's TraceStore, the bridge maps
runtime stream events to TraceEvent so consumer repos don't hand-roll
the adapter:
import { createTraceBridge } from '@tangle-network/agent-runtime'
const bridge = createTraceBridge({ runId, spanId })
for await (const event of runAgentTaskStream({ task, backend, input })) {
const trace = bridge.toTraceEvent(event)
if (trace) await traceStore.appendEvent(trace)
}Every public function throws one of:
| Error | When |
|---|---|
ValidationError |
Caller passed invalid arguments |
ConfigError |
Required env / config missing |
NotFoundError |
A named resource does not exist |
BackendTransportError |
Backend HTTP / IPC call returned non-success |
SessionMismatchError |
Resume requested against a different backend |
RuntimeRunStateError |
RuntimeRunHandle lifecycle methods called out of order |
All extend AgentEvalError (re-exported from @tangle-network/agent-eval)
and carry a stable code so cross-package handlers can pattern-match
without importing the runtime.
task.intent flows through sanitized telemetry on every event. Never
set it to user input — use a fixed string describing the operation
kind (e.g. "Run a chat turn", "Score a tax return"). Route user-
visible content through task.inputs (redacted by default).
import { createRuntimeStreamEventCollector, runAgentTaskStream } from '@tangle-network/agent-runtime'
const telemetry = createRuntimeStreamEventCollector()
for await (const event of runAgentTaskStream({ task, backend })) {
telemetry.onEvent(event)
}
console.log(telemetry.events, telemetry.summary())By default the collector redacts task inputs, user answers, credential
questions, control payloads, evidence IDs, task metadata, and eval
details. Private diagnostics opt-in via RuntimeTelemetryOptions.
| Package | Owns |
|---|---|
agent-runtime |
Lifecycle, adapters, backends, RuntimeRunHandle, trace bridge |
agent-runtime/platform |
Server-side clients for the Tangle platform: cross-site SSO (PlatformAuthClient) and integrations hub (PlatformHubClient) |
agent-eval |
Control loops, readiness scoring, traces, evals, failure classes, release evidence |
agent-knowledge |
Evidence, claims, wiki pages, retrieval, knowledge bundle builders |
| Domain packages | Domain tools, policies, credentials, UI text, rubrics |
import {
PlatformAuthClient,
PlatformHubClient,
} from '@tangle-network/agent-runtime/platform'
// Login with Tangle (cross-site SSO bridge).
const auth = new PlatformAuthClient({
baseUrl: process.env.TANGLE_PLATFORM_URL!, // https://id.tangle.tools
appId: 'gtm-agent', // must be registered in TRUSTED_APPS
})
const url = auth.authorizeUrl({ state: csrfToken, redirectUri: callbackUrl })
// …user redirected to `url`, returns to callbackUrl with ?code=…
const { apiKey, user } = await auth.exchange(code)
// Integrations hub (uses the user's apiKey from cross-site exchange).
const hub = new PlatformHubClient({
baseUrl: process.env.TANGLE_PLATFORM_URL!,
bearer: apiKey,
})
const connections = await hub.listConnections()
const { authorizationUrl } = await hub.startAuth({
providerId: 'google',
connectorId: 'gmail',
returnUrl: 'https://gtm.tangle.tools/integrations',
})The API uses runAgentTask, not runVerticalAgentTask. domain is
metadata on the task because the runtime is reusable across many kinds of
agents without baking taxonomy into type names.
Runnable in examples/:
basic-task/— smallestrunAgentTaskwith-knowledge-readiness/— readiness gating +onKnowledgeBlockedsanitized-telemetry/—createRuntimeEventCollector+ redactionsanitized-telemetry-streaming/— streaming collector + redactionsse-stream/— Server-Sent Events for browser clientssandbox-stream-backend/—createSandboxPromptBackendopenai-stream-backend/—createOpenAICompatibleBackendruntime-run/—startRuntimeRun+ cost ledger + persistence adapter