Install
bun add @oh-my-pi/pi-coding-agentNode 20+ or any Bun version. The package is a TypeScript ES module; consumers compile against the published .d.ts.
Open a session
createAgentSession follows the same discovery rules as the CLI: it reads ~/.omp/agent/config.yml, finds credentials, loads extensions, MCP servers, skills, prompt templates. Pass any option to override one piece.
import {
ModelRegistry,
SessionManager,
createAgentSession,
discoverAuthStorage,
} from "@oh-my-pi/pi-coding-agent"
const authStorage = await discoverAuthStorage()
const modelRegistry = new ModelRegistry(authStorage)
await modelRegistry.refresh()
const { session, modelFallbackMessage } = await createAgentSession({
sessionManager: SessionManager.inMemory(),
authStorage,
modelRegistry,
model: modelRegistry.getAvailable()[0],
thinkingLevel: "medium",
})
if (modelFallbackMessage) {
process.stderr.write(modelFallbackMessage + "\n")
}
const unsubscribe = session.subscribe((event) => {
if (event.type === "message_update" && event.assistantMessageEvent.type === "text_delta") {
process.stdout.write(event.assistantMessageEvent.delta)
}
})
await session.prompt("Summarize this repository in three bullets.")
unsubscribe()
await session.dispose()SessionManager.inMemory() keeps everything ephemeral. Swap in SessionManager.create(cwd) for the on-disk JSONL store the CLI uses, or implement your own. See Sessions for how persisted sessions resume, fork, and branch across embeds.
Streaming a turn
session.subscribe(handler) returns an unsubscribe function. Every event carries a type; the ones you usually care about:
| Event | What it carries |
|---|---|
message_update | Assistant output. Inspect assistantMessageEvent.type for text_delta, thinking_delta, tool_call_start, tool_call_delta, or tool_result. |
tool_execution_start / _update / _end | Tool-call lifecycle outside the assistant message. toolCallId, toolName, intent label. |
agent_start / agent_end | Turn boundaries. agent_end carries a stop reason and is the terminator that a single session.prompt resolves on. |
auto_compaction_start / _end | Compaction firing mid-stream. |
What you can override
-
modelandthinkingLevel— or let discovery pick. -
systemPrompt— an array (replaces the default) or(defaults) => final. -
toolNames— narrows the active built-in set.requireYieldToolopts in the hiddenyieldtool. -
customTools— host-side tools the agent can call (see below). -
extensions,additionalExtensionPaths,disableExtensionDiscovery. -
skills,rules,promptTemplates,slashCommands,contextFiles— arrays override discovery. -
authStorage— defaults todiscoverAuthStorage()against~/.omp/agent/agent.db. -
sessionManager—inMemory(), file-backed (create(cwd)), or your own. -
enableMCP.enableLsp, or hand in your ownmcpManager.
Custom tools
A CustomTool is a plain object the agent can call back into. Parameters use a Zod schema (a TypeBox-style JSON schema also works); execute returns an AgentToolResult.
import { z } from "zod"
import { createAgentSession, type CustomTool } from "@oh-my-pi/pi-coding-agent"
const echoHost: CustomTool = {
name: "echo_host",
label: "Echo Host",
description: "Echo a value back through the embedding host.",
parameters: z.object({ message: z.string() }),
async execute(_id, { message }) {
return { content: [{ type: "text", text: `host: ${message}` }] }
},
}
const { session } = await createAgentSession({
customTools: [echoHost],
})Forward the signal argument into long-running subprocesses so an abort (Esc in the TUI, an abort on the RPC pipe, session.abort() in the SDK) actually cancels the work.
Lifecycle
| Method | Effect |
|---|---|
session.prompt(text, opts?) | Runs one turn. Resolves on agent_end. |
session.steer(text) | Inject a steering message into the running turn. |
session.abort() | Stop the current turn; emits agent_end with an aborted stop reason. |
session.compact() | Force a compaction pass. |
session.dispose() | Releases the model, MCP servers, and any LSP processes the session opened. |
Need a non-Node language, or a process boundary between agent and host? Use the RPC mode instead. Spawning omp through the SDK is one of several entry shapes covered in the CLI reference.\n