cortex
cortex is the function-calling agent loop behind SmartChats. It runs an
LLM with tools, executes the code the model writes in an injected sandbox,
and reports progress as events. It also holds the model registry, agent
presets and the voice catalog that the other packages read.
The production agent runs in the browser. The core has no DOM references: the sandbox and the LLM call are passed in, so the same loop runs under Node in the package’s own tests.
The pieces
┌─────────────────────────────┐
│ Cortex │ run loop, message history
└──────┬──────────────────────┘
│
┌──────────────┼────────────────┐
▼ ▼ ▼
┌─────────┐ ┌──────────────┐ ┌───────────────┐
│ Runner │ │ SystemContext│ │ ProcessManager│
│ (LLM │ │ Manager │ │ (child │
│ call + │ │ (prompt │ │ agents and │
│ parse) │ │ modules) │ │ processes) │
└─────────┘ └──────────────┘ └───────────────┘
│
▼
┌──────────────┐
│ Sandbox │ runs generated code (SandboxExecutor)
│ Executor │
└──────────────┘Quick orientation
import { Cortex, StreamingRunnerV3, SystemContextManager, createIntroModule, createStreamingCodeGenModule } from 'cortex';
const scm = new SystemContextManager();
scm.add_module(createIntroModule('SmartChats'));
scm.add_module(createStreamingCodeGenModule());
const cortex = new Cortex({
model: 'claude-haiku-5-5',
name: 'my-agent',
sandbox: mySandboxExecutor, // implements SandboxExecutor
scm,
llmCallFn: myLlmCall, // non-streaming call, used by child processes
});
cortex.setRunner(new StreamingRunnerV3({ streamingLlmCallFn: myStreamingCall }));
cortex.on('event', (evt) => console.log(evt.type, evt));
const reply = await cortex.chat('add 2 + 2');CortexOps
| Field | Notes |
|---|---|
model | Registry key |
name | Agent name |
sandbox | A SandboxExecutor. Required |
scm | A SystemContextManager. When set, it replaces functions and additional_system_msg |
functions, additional_system_msg | Required when scm is not given |
provider | Optional. Otherwise read from the registry |
llmCallFn | ({ model, input, schema?, schema_name?, signal?, effort? }) => Promise<any> |
runner | Default SynchronousRunner |
insights | Telemetry client (optional) |
utilities | Platform helpers passed to generated code |
apiBaseUrl | Optional API base URL |
Cortex
Cortex extends EventEmitter and emits one event name, 'event', with a
type field. Types include turn_start, turn_complete, thought,
thought_chunk, response_chunk, response_complete, stream_chunk,
stream_end, context_status and workspace_update. With a process
manager it also forwards process_spawned, process_output,
process_state_change, process_complete, process_agent_event,
process_needs_input and process_idle_batch.
Commonly used methods:
| Method | Does |
|---|---|
chat(text, maxLoops = 4) | Adds the user text and runs the runner. Resolves with the reply |
run_llm(loop = 6) | Runs the runner on the current history |
setRunner(runner) | Swaps the runner and rebuilds the system prompt for its output format |
cancel() | Aborts the running turn |
add_user_text_input(text) | Appends a user turn |
snapshot() / restore(s) | Save and restore the context (ContextSnapshot) |
getContextStatus() | Token use against the model’s context window |
getUsage() / resetUsage() | Accumulated UsageStats (tokens, costUsd, callCount) |
initProcessManager(sandboxFactory) | Enables child processes |
Runners
A runner owns the LLM call and parses the model output into spoken text, code and thoughts.
| Runner | Format | Used by |
|---|---|---|
StreamingRunnerV3 | JSON, parsed while it streams by JsonStreamParser | The app’s main agent |
StreamingRunner | Delimited text (<<<RESPONSE>>>, <<<CODE>>>, <<<THOUGHTS>>>), parsed by StreamParser | Earlier streaming protocol |
SynchronousRunner | Structured JSON (CodeOutput schema), parsed after the full response | Default when no runner is given |
Child processes forked by ProcessManager run an internal non-streaming
runner (SynchronousRunnerV2, not exported) that uses the delimited
protocol through llmCallFn.
StreamingRunnerV3 takes { streamingLlmCallFn }, a function that
receives { model, input, max_tokens?, temperature?, effort?, text_format?, signal? }
and returns { stream, data }. Because the response field streams first,
the voice layer can start speaking before the model finishes writing code.
SystemContextManager
The system prompt is built from context modules. Each module has an id,
name and position (0 to 100), and any of system_msg, functions,
output_instructions, output_structure, state and a beforeBuild hook.
import { SystemContextManager, createIntroModule, createCodeGenModule, createKnowledgeGraphModule } from 'cortex';
const scm = new SystemContextManager();
scm.add_module(createIntroModule('SmartChats'));
scm.add_module(createCodeGenModule());
scm.add_module(createKnowledgeGraphModule());
scm.add_module({
id: 'my_tools',
name: 'My Tools',
position: 50,
system_msg: 'You can use these tools.',
functions: [/* Function objects */],
});
const { system_prompt, functions, output_structure } = scm.build();Methods: add_module, remove_module, update_module, update_state,
get_module, list_modules, has_module, clone, get_usage, build
and build_messages(conversation). build_messages calls each module’s
beforeBuild and appends module state as a trailing message.
Module factories:
| Factory | Arguments |
|---|---|
createIntroModule | (agentName?, model?) |
createCodeGenModule | none |
createStreamingCodeGenModule | none |
createDynamicFunctionsModule | none |
createKnowledgeGraphModule | none |
createResponseGuidanceModule | (guidance?) |
createCodeOutputModule | none |
createStreamingOutputModule | none |
Sandbox
SandboxExecutor is an interface:
interface SandboxExecutor {
execute(code: string, context: Record<string, any>, timeout: number): Promise<SandboxResult>;
initializePersistent(): Promise<void>;
reset(): Promise<void>;
destroy(): void;
abort?(reason: string): void;
setupEventStream?(handler: (event: SandboxRuntimeEvent) => void): () => void;
syncWorkspace?(workspace: Record<string, any>): void;
}SandboxResult has ok, data, error, executionId, logs and
events. DEFAULT_SANDBOX_TIMEOUT is exported. The app ships an iframe
implementation (apps/smartchats/app/src/IframeSandbox.ts). The package
itself ships none.
ProcessManager
initProcessManager(sandboxFactory) lets the agent run work that outlives
one turn: child agents and background code. The class is internal (only its
types are exported). It forks with fork, lists with ps, reads output with
read, stops with kill and forwards input with sendInput.
In the app, the agent reaches these through the functions fork_process,
ps, read_process, kill_process and send_process_input, defined in
apps/smartchats/app/modules/process.ts.
Model registry
MODEL_REGISTRY covers Anthropic, OpenAI, Google Gemini, xAI and
Together-hosted models: context window, max output, dated price periods,
effort levels, tier, release and shutdown dates.
import { getModelInfo, calculateCost } from 'cortex';
const info = getModelInfo('claude-haiku-5-5');
// { id, provider, contextWindow, maxOutputTokens, prices, effort?, inputPricePer1M, outputPricePer1M, cachedInputPricePer1M, cacheWritePricePer1M, ... }
const usd = calculateCost('claude-haiku-5-5', { input_tokens: 1000, output_tokens: 500 });Prices are USD per million tokens. The flat *PricePer1M fields are the base
rates in force now. Billing uses calculateCost(model, usage, provider?, at?, opts?)
or getPricesAt, which apply the price period for a date and long-context
tiers. usage takes input_tokens, output_tokens, cached_input_tokens
and cache_creation_input_tokens.
Other registry exports: getRegisteredModels, getModelsByProvider,
getModelByTier, listTieredModels, getSelectableModels,
isSelectableModel, resolveSelectableModel, isModelRetired,
isModelDisabled, getEffortSpec, supportsEffort, EFFORT_ORDER,
getModelMaker, isThirdPartyHosted, modelsReleasedSince, and
GPT4O_MINI_TTS_PRICING with estimateGpt4oMiniTtsCost.
Presets, voices and catalog
AGENT_PRESETS,DEFAULT_PRESET_ID,getPreset,getPresetOrDefault,findMatchingPreset,resolvePresetIdForAvailability. AnAgentPresetbundlesaiModel,ttsProvider('openai' | 'azure') andttsVoice.VOICE_CATALOG,listVoicesForProvider,listVoiceIdsForProvider,findVoice,listAllVoices.describeModel,listModelCatalog,MODEL_STRENGTHS: the agent-facing view of the registry.- Token counting:
countTokens,countTokensEstimate,countMessageTokens,getTokenBreakdown.
See also
- llm-service, which routes calls by the registry
- tivi for the voice layer the streaming runner feeds
- Source:
packages/cortex/src/index.ts