Cogitator Runtime
The main runtime that orchestrates agent execution, LLM routing, memory, and observability.
Overview
The Cogitator class is the central runtime for executing AI agents. It manages LLM backend connections, memory persistence, the global tool registry, approvals and observability. You create one instance and use it to run any number of agents.
import { Cogitator, Agent } from '@cogitator-ai/core';
const cog = new Cogitator({
llm: {
defaultProvider: 'openai',
providers: {
openai: { apiKey: process.env.OPENAI_API_KEY! },
},
},
});
const agent = new Agent({
name: 'assistant',
model: 'openai/gpt-6.1-sol',
instructions: 'You are a helpful assistant.',
});
const result = await cog.run(agent, { input: 'Hello!' });
console.log(result.output);
await cog.close();Constructor
const cog = new Cogitator(config?: CogitatorConfig);The config object is entirely optional. Without it, Cogitator talks to Ollama at localhost:11434, and every agent must name its own model. Nothing connects in the constructor: backends, memory and other services start on first use.
Configuration
interface CogitatorConfig {
llm?: {
defaultProvider?: LLMProvider; // for model strings without a known provider prefix (default 'ollama')
defaultModel?: string; // for agents that set no model
providers?: LLMProvidersConfig; // API keys and URLs per provider
backends?: Record<string, LLMBackend>; // your own backends, by name
plugins?: Record<string, unknown>; // config for registerLLMBackend() plugins
retry?: LLMRetryConfig | false; // default: 2 retries with backoff
promptCache?: PromptCacheConfig | false; // default: on
};
limits?: {
maxConcurrentRuns?: number; // runs over the limit wait in order
defaultTimeout?: number; // ms, for agents and runs that set no timeout (default 120000)
maxTokensPerRun?: number; // checked before each model call
};
memory?: MemoryConfig;
runCheckpoints?: RunCheckpointStore; // where paused runs wait
prompts?: PromptsConfig; // instruction versions and A/B tests
sandbox?: SandboxManagerConfig;
reflection?: ReflectionConfig;
guardrails?: Partial<GuardrailConfig>;
costRouting?: CostRoutingConfig;
security?: { promptInjection?: Partial<PromptInjectionConfig>; pii?: PiiConfig };
context?: ContextManagerConfig;
logging?: LoggingConfig; // level, format and destination of the process-wide logger
deploy?: DeployConfig; // read by `cogitator deploy`
}The same object can come from cogitator.yml and the environment via loadConfig(). Retries and prompt caching are described in LLM Backends; security in Security.
Defaults and Limits
llm.defaultModelis the model of every agent that sets nomodelof its own.cog.resolveModel(agent)returns the model a run would use and throwsCONFIGURATION_ERRORwhen there is none.limits.maxConcurrentRunscaps how manyrun()calls execute at once on this instance. The rest wait in arrival order; their timeout and abort signal also cover the wait.limits.defaultTimeoutapplies to runs whose options and agent set notimeout. Without it, runs time out after 2 minutes. A run that times out throws aCogitatorErrorwith codeRUN_TIMEOUT(HTTP 504 in the server adapters).limits.maxTokensPerRunis checked before every model call: once the run has used that many input and output tokens, the next call fails withRUN_TOKEN_LIMIT_EXCEEDED. The answer of the call that crosses the limit is still returned.loggingreplaces the process-wide logger (getLogger()) when the runtime is created, so with several runtimes the last one created withloggingwins.level: 'silent'turns logging off;destination: 'file'appends JSON lines tofilePath. See Configuration.
Multi-Provider Setup
Configure multiple LLM providers and let agents route to whichever they need:
const cog = new Cogitator({
llm: {
defaultProvider: 'ollama',
providers: {
ollama: { baseUrl: 'http://localhost:11434' },
openai: { apiKey: process.env.OPENAI_API_KEY! },
anthropic: { apiKey: process.env.ANTHROPIC_API_KEY! },
google: { apiKey: process.env.GOOGLE_API_KEY! },
},
},
});Backends are created lazily -- Cogitator only instantiates a provider's client the first time an agent requests it. The provider is determined by the model string prefix (openai/gpt-6.1-sol routes to OpenAI, anthropic/claude-sonnet-5-5 routes to Anthropic). cog.route(model) returns the backend and model name a run would use, and cog.getLLMBackend(model) just the backend, already wrapped with retries and PII masking.
Running Agents
The run() method executes an agent and returns a RunResult:
const result = await cog.run(agent, {
input: 'Search for TypeScript tutorials',
threadId: 'session-123',
stream: true,
onToken: (token) => process.stdout.write(token),
onToolCall: (call) => console.log('Tool:', call.name),
onToolResult: (result) => console.log('Result:', result),
});RunOptions
| Option | Type | Description |
|---|---|---|
input | string | User prompt (required) |
images | ImageInput[] | Images to include with the input (Vision & Audio) |
audio | AudioInput[] | Audio files to transcribe and include |
threadId | string | Conversation to continue; a new one is created when omitted |
userId | string | The user the run acts for: owns new threads, scopes memory, reaches tools as context.userId |
threadAccess | 'owner' | 'shared' | 'owner' (default): only the thread's creator may continue it (Multi-User) |
context | Record<string, unknown> | Additional context injected into the system prompt |
stream | boolean | Enable token streaming |
signal | AbortSignal | Cancel the run and linked provider/tool work |
timeout | number | Override the agent timeout (ms) |
reasoning | ReasoningConfig | Override the agent's reasoning for this run |
parallelToolCalls | boolean | Execute tool calls in parallel (default: sequential) |
useMemory | boolean | Enable/disable memory for this run (default: on when an adapter is configured) |
loadHistory | boolean | Load prior memory history for this run (default: true) |
saveHistory | boolean | Persist run messages to memory (default: true) |
onApproval | (request) => decision | 'pause' | Decide calls of tools with requiresApproval (Approvals) |
onToken | (token: string) => void | Streaming callback |
onReasoning | (delta: string) => void | Streamed reasoning summary (needs reasoning.summary) |
onToolCall | (call: ToolCall) => void | Called when the agent invokes a tool |
onToolResult | (result: ToolResult) => void | Called when a tool returns |
onHandoff | (handoff: HandoffEvent) => void | Called when an agent hands the conversation over (Handoffs) |
onRunStart | ({ runId, agentId, input, threadId }) => void | Called when the run starts |
onRunComplete | (result: RunResult) => void | Called with the result |
onRunError | (error: Error, runId: string) => void | Called when the run fails |
onMemoryError | (error: Error, operation: 'save' | 'load') => void | Called when loading or saving history fails (the run goes on) |
onSpan | (span: Span) => void | Observability callback for tracing |
channelType, channelId | string | Where the message came from; passed on to tools in their context |
RunResult
interface RunResult {
output: string; // final answer text
structured?: unknown; // parsed JSON for json / json_schema agents
runId: string;
agentId: string;
threadId: string;
modelUsed?: string; // differs from agent.model under cost routing
usage: {
inputTokens: number;
outputTokens: number;
totalTokens: number;
cost: number; // USD, from the model registry's prices
duration: number; // ms
reasoningTokens?: number;
cachedInputTokens?: number;
cacheWriteTokens?: number;
};
reasoning?: string; // reasoning summary, when asked for
prompt?: RunPrompt; // instruction version / A/B variant used
handoffs?: HandoffEvent[];
finalAgent?: string; // the agent that answered after handoffs
status?: 'completed' | 'paused';
pendingApprovals?: ToolApprovalRequest[]; // when paused
checkpoint?: RunCheckpoint; // when paused, for cog.resume()
toolCalls: ToolCall[];
messages: Message[];
trace: { traceId: string; spans: Span[] };
reflections?: Reflection[];
reflectionSummary?: ReflectionSummary;
}All fields are readonly.
Pausing and Resuming
A run that reaches a tool call with requiresApproval and no onApproval decision pauses: it returns with status: 'paused', the waiting calls in pendingApprovals and a JSON checkpoint. Continue it later by thread id (the checkpoint is kept in runCheckpoints, by default in the memory adapter's threads or in process memory) or from the checkpoint itself:
const paused = await cog.run(agent, { input: 'Refund order 42', threadId, userId });
if (paused.status === 'paused') {
const result = await cog.resume(agent, threadId, {
userId,
decisions: { [paused.pendingApprovals![0].toolCallId]: { approved: true } },
});
}See Approvals for decisions, stores and servers.
Prompt Versions
cog.prompts deploys new instructions for an agent without changing code, rolls them back, and runs A/B tests on live traffic; every run records its outcome against the version it used:
await cog.prompts.deploy(agent, 'You write release notes. Lead with what changed for the user.');
const result = await cog.run(agent, { input });
result.prompt; // { key: 'assistant', versionId: '...', version: 2 }See Prompt Versions.
Cost Estimation
Estimate the cost before running an agent:
const estimate = await cog.estimateCost({
agent,
input: 'Analyze this document and summarize key points',
options: { assumeIterations: 3, assumeToolCalls: 5 },
});
console.log(`Expected cost: $${estimate.expectedCost.toFixed(4)}`);
console.log(`Confidence: ${(estimate.confidence * 100).toFixed(0)}%`);With costRouting enabled, cog.getCostSummary() returns what runs have spent and cog.getCostRouter() the router itself, both before the first run as well (Cost Routing). A run over budget throws a CogitatorError with code BUDGET_EXCEEDED (HTTP 429).
Global Tool Registry
Cogitator exposes a shared tools registry. Tools registered here are available to every agent run on this instance, next to the agent's own tools (an agent tool with the same name wins):
cog.tools.register(myGlobalTool);Memory
The configured memory adapter connects on the first run. To read threads before any agent has run — an endpoint that lists a conversation, an export job — ask for it:
const memory = await cog.getMemory(); // undefined when memory is not configuredcog.memory is the same adapter once connected, and undefined before. Assigning cog.memory = adapter uses an adapter you connected yourself, for example one the config cannot create.
Other Methods
| Method | Returns |
|---|---|
getGuardrails() / setConstitution(constitution) | The Constitutional AI instance, or replace its rules; usable before the first run when guardrails.model or llm.defaultModel is set |
getInsights(agentId) / getReflectionSummary(agentId) | Reflection insights and summary |
reflectionEngine | The reflection engine, when reflection is enabled |
Cleanup
Always call close() when done to release connections:
await cog.close();This disconnects memory adapters, shuts down sandbox containers, and clears backend connections.