@ocis/myagent-sdk
v0.3.1
Published
Framework for building deployable agent services — compose a harness, run locally, deploy to the myagent platform
Readme
MyAgent SDK
A fluent-style agent harness SDK for TypeScript. Assembles a
@mariozechner/pi-agent-core
Agent from a declarative harness — tools, skills, MCP servers, subagent
profiles — and runs it in-process on Bun or Node.js (≥18).
AG-UI is the native session event protocol. Session.events is an
AsyncIterable<AGUIEvent> — the SDK translates pi-agent-core's internal
events into AG-UI events at the
session boundary. The @ocis/myagent-sdk/agui module exposes a native AG-UI SSE
endpoint; the openai-compat module is a pure AGUIEvent → OpenAI SSE
transformer for OpenAI-compatible clients.
Quick start
bun install @ocis/myagent-sdkimport { harness, createModelProvider, EventType } from "@ocis/myagent-sdk";
import { read, grep, bash } from "@ocis/myagent-sdk/tools";
const litellm = createModelProvider("litellm", {
baseUrl: process.env.LITELLM_BASE_URL!,
apiKey: process.env.LITELLM_KEY!,
});
const app = harness()
.model(litellm.model("openrouter-glm-5.2"))
.tool(read, grep, bash)
.agent({ instructions: "You are a concise coding agent." });
const session = app.session();
// Stream AG-UI lifecycle events concurrently with the prompt.
const consuming = (async () => {
for await (const ev of session.events) {
if (ev.type === EventType.TOOL_CALL_START) console.log(`→ ${ev.toolCallName}`);
if (ev.type === EventType.TOOL_CALL_RESULT) console.log(` ← ${ev.content.slice(0, 100)}`);
}
})();
const answer = await session.prompt("List the files in the current directory.");
await consuming;
console.log(answer);Package exports
| Import path | What you get |
|---|---|
| @ocis/myagent-sdk | harness, ModelProvider, createModelProvider, createMockModelProvider, loadSkills, connectMcpServer, loadMcpServers, compaction strategies (pruningCompaction, summarizingCompaction, customCompaction), AG-UI event types (AGUIEvent, EventType, …) + core types |
| @ocis/myagent-sdk/tools | Built-in file tools: read, write, edit, grep, ls, bash |
| @ocis/myagent-sdk/tools/url_fetch | webFetch (HTML→markdown; pulls optional deps) |
| @ocis/myagent-sdk/agui | createAgUiHandler — native AG-UI SSE endpoint (Session.events → SSE), SessionStore, AG-UI event types |
| @ocis/myagent-sdk/openai-compat | createOpenAiCompatHandler, agUiToOpenAiStream, AG-UI event types + OpenAI chunk types |
Mental model
ModelProvider.X(config?) create a provider object (outside the harness)
└── .model(id, thinkingLevel?) resolve a model id → ResolvedModel
harness (shared capability pool)
├── .model(ResolvedModel) default model
├── .workspace(dir?) workspace root (defaults to process.cwd())
├── .tool(...defs) shared tools pool
├── .skill(...defs) shared skills pool
├── .mcp(...servers) shared MCP tool pools
├── .subagent(...profiles) shared subagent profiles
├── .compaction(strategy) context compaction (pruning or summarization)
└── .agent(def) the single main agent
↓
.session() build a runnable Session
↓
session.prompt(text) run the agent loop
session.events stream AG-UI lifecycle events
session.getMessages() conversation history
session.submitToolResult() resume after a client tool call
↓
createAgUiHandler() expose as native AG-UI SSE endpoint
createOpenAiCompatHandler() expose as OpenAI /v1/chat/completionsAG-UI event protocol
Session.events is an AsyncIterable<AGUIEvent>. The SDK translates
pi-agent-core's internal AgentEvents into AG-UI events at the session
boundary (src/internal/agui-bridge.ts — single source of truth).
| AG-UI Event | When |
|---|---|
| RUN_STARTED / RUN_FINISHED / RUN_ERROR | Run lifecycle (terminal on finish/error) |
| STEP_STARTED / STEP_FINISHED | One LLM turn |
| TEXT_MESSAGE_START / CONTENT / END | An assistant message streams |
| TOOL_CALL_START / ARGS / END | A tool call is requested (args stream) |
| TOOL_CALL_RESULT | A tool call finishes executing (result content) |
| REASONING_MESSAGE_* | Thinking/reasoning content streams |
EventType (re-exported from @ocis/myagent-sdk) is a const object + string-literal
union for switching on ev.type. The AG-UI types are a zero-dependency mirror
of @ag-ui/core — no external runtime deps required.
AG-UI SSE server
The @ocis/myagent-sdk/agui module wraps a harness Session as a native AG-UI SSE
endpoint — no protocol translation. Sessions are reused by threadId, with
client-tool call/resume support:
import { createAgUiHandler } from "@ocis/myagent-sdk/agui";
const handler = createAgUiHandler({ harness: app });
Bun.serve({ port: 3000, fetch: (req) => handler(req) });OpenAI-compatible server
The openai-compat module wraps a harness Session as an OpenAI
/v1/chat/completions endpoint with streaming, client tools (function
calling), and session reuse. Since Session.events already yields
AGUIEvent, the transformer is a pure AGUIEvent → OpenAI SSE pipe:
import { createOpenAiCompatHandler } from "@ocis/myagent-sdk/openai-compat";
const handler = createOpenAiCompatHandler({ harness: app });
Bun.serve({ port: 3000, fetch: (req) => handler(req) });Or pipe events directly without the HTTP handler:
import { agUiToOpenAiStream } from "@ocis/myagent-sdk/openai-compat";
for await (const sse of agUiToOpenAiStream(session.events, { model: "gpt-4o" })) {
res.write(sse); // "data: {…chat.completion.chunk…}\n\n"
}Context compaction
Long conversations can exceed the model's context window. The SDK provides
compaction strategies wired into pi-agent-core's transformContext hook —
they run before each LLM call and reduce the transcript when a token
threshold is exceeded.
import { harness, pruningCompaction, summarizingCompaction } from "@ocis/myagent-sdk";
// Pruning: drop oldest messages (no LLM call — cheap, deterministic)
harness().compaction(pruningCompaction({ threshold: 0.7, keepRecent: 10 }));
// Summarization: summarize older messages into one summary via an LLM call
harness().compaction(summarizingCompaction({ threshold: 0.75, keepRecent: 8 }));
// Per-agent override (subagents opt in via AgentProfile.compaction)
harness().compaction(pruningCompaction()).agent({
instructions: "...",
compaction: summarizingCompaction(), // overrides harness default
});When compaction fires, a context_compacted CUSTOM event is emitted on
Session.events with { removedCount, summary, before, after }.
Mock model provider (testing)
For tests and local development without a real LLM endpoint:
import { ModelProvider, fauxAssistantMessage, fauxToolCall } from "@ocis/myagent-sdk";
const mock = ModelProvider.Mock({
contextWindow: 500, // small to trigger compaction in tests
responses: [fauxAssistantMessage("Hello!")],
});
const app = harness().model(mock.model("mock-1")).agent({ instructions: "..." });
const answer = await app.session().prompt("Hi"); // → "Hello!"Responses can be fauxAssistantMessage objects or dynamic factories. The
mock provider tracks callCount and supports setResponses /
appendResponses for queue management.
Build with a coding agent
The SDK is designed to be assembled by a coding agent (e.g. an AI assistant
in your editor) rather than hand-written boilerplate. Point your agent at
guide.md — a comprehensive developer guide written for coding
agents building agent harnesses with the SDK. It covers the full harness API,
capability inheritance, model providers, skills, subagents, MCP, the AG-UI
event protocol, session save/load, the prompt queue, and debug logging, with
copy-pasteable snippets.
A good starting point is the 01-hello example — a
minimal agent served over HTTP in a few lines. From there the examples build up
by number, from a single concept to a complete application. See its
README and index.ts.
Examples
The examples are numbered from simple to complex — each one introduces one new concept over the previous.
| Example | Demonstrates |
|---|---|
| 01-hello | Minimal agent served over HTTP (serve() + tools) |
| 02-custom-tool | Custom ToolDef with a typebox schema |
| 03-skills | loadSkills + the load_skill tool |
| 04-subagents | Auto-injected task delegation + InheritSpec inheritance patterns |
| 05-events-streaming | AG-UI event lifecycle + OpenAI-compatible endpoint & function calling |
| 06-sessions | Session lifecycle: persistence, token usage, prompt queue, compaction — all owned by serve() |
| 07-mcp-server | connectMcpServer (stdio transport) |
| 08-rag-assistant | Complete agentic RAG app (custom tools + skill + subagent + LanceDB + assistant-ui frontend) |
| 09-no-code-harness | No-code agent service — myagent.md + skills/ + agents/ + mcp.yaml (loadHarness) |
| 10-hooks | beforeTool/afterTool/lifecycle hooks — approval, rewriting, observability |
Each example has its own .env and package.json. Run from the example
directory:
cd examples/01-hello && bun run index.tsDevelopment
bun install # install dependencies
bun run typecheck # tsc --noEmit (strict) — the typecheck gate
bun run build # emit ESM + .d.ts to dist/ (tsc + fix-esm post-process)
bun test # all tests (bun:test)
bun test test/edit.test.ts # single test fileRuntime is Bun or Node.js (≥18). Package manager is Bun. The
package ships pre-built ESM + .d.ts in dist/ — main/types/exports
point at dist/, not source. A prepack script auto-builds before
npm pack / npm publish. No linter or formatter is configured;
tsc --noEmit is the only gate.
Build & publish
bun run build # tsc -p tsconfig.build.json && scripts/fix-esm.ts
bun pm pack # → ocis-myagent-sdk-<version>.tgz (prepack auto-builds)
npm publish # publish to npmjs (requires ocis org access)The scripts/fix-esm.ts post-build step rewrites extensionless relative
imports to .js / /index.js so the emitted ESM resolves under Node's
native loader. The bash/grep/mcp tools use a runtime-agnostic process
shim (src/internal/process.ts) — Bun.spawn on Bun, node:child_process
on Node — so the SDK runs unchanged on both runtimes.
Architecture
- Engine:
@mariozechner/pi-agent-coreAgent(v0.73.1). The SDK only assemblesAgentState; it does not reimplement the agent loop. - Schema:
typebox(pi-agent-core'sAgentTool<TSchema>is typebox-native). - Tools are stateless
ToolDef<T>with arun(ctx)callback.workspace/sessionId/runIdare injected at execution time. - AG-UI native events:
Session.eventsisAsyncIterable<AGUIEvent>. Translation lives insrc/internal/agui-bridge.ts(single source of truth). AG-UI types live insrc/agui/types.ts(zero-dep mirror of@ag-ui/core). - System prompt: the SDK does NOT assemble it.
AgentDef.instructionsis passed verbatim. No injection. - Model providers live outside the harness.
ModelProvider.X(config?)factories create provider objects;.model(id, thinkingLevel?)returns a self-containedResolvedModel. The harness never touches API keys.
See guide.md for a comprehensive developer guide and
AGENTS.md for the codebase orientation.
