Docs menu
Agent registry (createGnl)
The central entry point that defines agents, tools, and workflows in a single configuration and runs them durably; the server and Studio always consume this same registry.
What it's for / when to use it#
createGnl gathers every agent, shared tool, and workflow in an app into a single configuration object and turns it into a durable, callable-by-name runner. Storage (journal) is tied to this configuration; the returned gnl object is used the same way both directly from code (gnl.run(...)) and through createRestApi and createStudioApp.
Concrete scenario: you want to build a Star Wars encyclopedia agent — it's defined in a single place together with its model, system prompt, and tools; both the REST API and Studio read this definition to run the same agent and write results to the same journal.
Setup / import#
The main export comes from the @gnldev/durable package. Storage requires a sub-export (not the root package) — if you're using SQLite, import SqliteStorage from @gnldev/durable/sqlite.
import { SqliteStorage } from '@gnldev/durable/sqlite';
import { createGnl, toJournal } from '@gnldev/durable';
import type { CreateGnlConfig } from '@gnldev/durable';Step-by-step usage#
1) Set up your storage, 2) define your agents under agents (model, system, tools, maxSteps), 3) build the registry with createGnl(config), 4) run it under a runId with gnl.run(name, opts).
const storage = new SqliteStorage(process.env.DB_PATH ?? 'swapi-free.db');
const config: CreateGnlConfig = {
storage,
agents: {
starwars: { model: buildModel(), system: SYSTEM, tools: makeSwapiTools(), maxSteps: 4 },
},
};
const gnl = createGnl(config);
await gnl.run('starwars', { runId: 'demo-1', prompt: 'Who is Luke Skywalker?' });The same config object is also given to the REST API and Studio — all three share the same journal and the same agent definition:
app.route('/api', createRestApi(config, { title: 'SWAPI Free', auth }));
app.route('/studio', createStudioApp({
reader: toJournal(storage.runs),
apiBase: '/studio',
gnl: createStudioRunner(gnl, config, { toJsonSchema: aiToolSchema }),
auth,
}));The runId passed to gnl.run is also the key to the exactly-once and resume guarantee: if called again with the same runId, the run continues where it left off (see deterministic replay).
API reference#
createGnlReturns { agent, run, stream, listWorkflows, runWorkflow } from a configuration — an app's entire agent/workflow surface.
CreateGnlConfigstorage or journal, agents (Record<name, AgentConfig>), tools, memory/memoryFactory, processors, workflows fields.
AgentConfigmodel, tools, system, guard, maxSteps, processors, agents (sub-agent names), scorers — all of these can be a DynamicArg.
RunOptionsgnl.run/gnl.stream parameters: runId, prompt|messages, threadId, resourceId, approvals, context, model/temperature/topP/system override.
RequestContextThe request context (org/role/user) — passed to DynamicArg functions.
DynamicArg<T>Either a fixed value OR a function that receives RequestContext — used for model/system/tools.
WorkflowLikeThe structural interface of workflows registered under config.workflows (build/run/runResumable).
createAgentToolInternal helper that turns the sub-agents listed in AgentConfig.agents into agent_<name> tools (agent-as-tool).
agents field the names of other registered agents, each one is automatically exposed as a tool named agent_<name> (handoff); this runs exactly-once with a two-level journal.maxSteps isn't given, 12 steps are used (stepCountIs). If model is given as an array instead of a single value, it automatically falls back to the deterministic model fallback chain (see Model routing & fallback).Related topics#
- Automatic REST API + OpenAPI + SSETurns createGnl into a durable HTTP API + SSE stream in one line.
- Exactly-once toolsSide-effecting tools run exactly once per runId.
- Durable workflowsMulti-step workflows are suspend/resume-safe.
- Model routing & fallbackDeterministically falls back to the first working model in the candidate list.