Cogitator
Core

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.defaultModel is the model of every agent that sets no model of its own. cog.resolveModel(agent) returns the model a run would use and throws CONFIGURATION_ERROR when there is none.
  • limits.maxConcurrentRuns caps how many run() calls execute at once on this instance. The rest wait in arrival order; their timeout and abort signal also cover the wait.
  • limits.defaultTimeout applies to runs whose options and agent set no timeout. Without it, runs time out after 2 minutes. A run that times out throws a CogitatorError with code RUN_TIMEOUT (HTTP 504 in the server adapters).
  • limits.maxTokensPerRun is checked before every model call: once the run has used that many input and output tokens, the next call fails with RUN_TOKEN_LIMIT_EXCEEDED. The answer of the call that crosses the limit is still returned.
  • logging replaces the process-wide logger (getLogger()) when the runtime is created, so with several runtimes the last one created with logging wins. level: 'silent' turns logging off; destination: 'file' appends JSON lines to filePath. 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

OptionTypeDescription
inputstringUser prompt (required)
imagesImageInput[]Images to include with the input (Vision & Audio)
audioAudioInput[]Audio files to transcribe and include
threadIdstringConversation to continue; a new one is created when omitted
userIdstringThe 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)
contextRecord<string, unknown>Additional context injected into the system prompt
streambooleanEnable token streaming
signalAbortSignalCancel the run and linked provider/tool work
timeoutnumberOverride the agent timeout (ms)
reasoningReasoningConfigOverride the agent's reasoning for this run
parallelToolCallsbooleanExecute tool calls in parallel (default: sequential)
useMemorybooleanEnable/disable memory for this run (default: on when an adapter is configured)
loadHistorybooleanLoad prior memory history for this run (default: true)
saveHistorybooleanPersist run messages to memory (default: true)
onApproval(request) => decision | 'pause'Decide calls of tools with requiresApproval (Approvals)
onToken(token: string) => voidStreaming callback
onReasoning(delta: string) => voidStreamed reasoning summary (needs reasoning.summary)
onToolCall(call: ToolCall) => voidCalled when the agent invokes a tool
onToolResult(result: ToolResult) => voidCalled when a tool returns
onHandoff(handoff: HandoffEvent) => voidCalled when an agent hands the conversation over (Handoffs)
onRunStart({ runId, agentId, input, threadId }) => voidCalled when the run starts
onRunComplete(result: RunResult) => voidCalled with the result
onRunError(error: Error, runId: string) => voidCalled when the run fails
onMemoryError(error: Error, operation: 'save' | 'load') => voidCalled when loading or saving history fails (the run goes on)
onSpan(span: Span) => voidObservability callback for tracing
channelType, channelIdstringWhere 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 configured

cog.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

MethodReturns
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
reflectionEngineThe 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.

On this page