@alexandre_ai/wiener
v0.4.0
Published
A tasteful, minimal Agent SDK
Readme
Wiener
A tasteful, minimal Agent SDK for TypeScript.
Wiener focuses on a small core API that stays stable:
agent()to run/stream/abort agent loopstool()to define typed tools with Zod validationzas a re-export of Zod
Everything else (skills, harnesses, MCP, compaction, memory) composes on top.
Install
pnpm add @alexandre_ai/wiener60-Second Quick Start
import { agent, tool, z } from "@alexandre_ai/wiener";
import { openai } from "@alexandre_ai/wiener/providers/openai";
const calculate = tool(
"calculate",
"Do arithmetic",
{
a: z.number(),
b: z.number(),
op: z.enum(["+", "-", "*", "/"]),
},
async ({ a, b, op }) => {
const value = op === "+" ? a + b : op === "-" ? a - b : op === "*" ? a * b : a / b;
return { content: String(value) };
},
);
const a = agent({
provider: openai({ apiKey: process.env.OPENAI_API_KEY!, baseURL: "https://api.openai.com" }),
model: "gpt-4o",
tools: [calculate],
});
const result = await a.run("What is 42 * 17?");
console.log(result.text); // "714"Core API
agent(config)
Creates an agent instance with:
run(prompt)-> collects full resultstream(prompt)-> yields incrementalAgentEventabort()-> cancels in-flight run
tool(name, description, parameters, execute)
Defines a tool with typed params and runtime validation.
- Params use Zod object shape.
- Invalid params return an error
ToolResultto the model. - Tool execution failures are surfaced as internal errors and converted by the loop.
z
Re-export from zod for ergonomic imports:
import { tool, z } from "@alexandre_ai/wiener";Streaming Model
Use stream() when you need real-time events:
for await (const event of a.stream("Diagnose this issue")) {
if (event.type === "message:delta") process.stdout.write(event.delta);
if (event.type === "tool:start") console.log("->", event.name);
}Common event types:
turn:start,turn:endmessage:start,message:delta,message:endtool:start,tool:endcompaction,error,done
Memory
Three modes via createMemory():
- in-memory (default)
- file-backed
- custom provider
import { createMemory } from "wiener";
const memory = createMemory({ type: "file", path: ".wiener/memory.json" });Memory interface is minimal: load(), save(), clear().
Providers
Built-in:
wiener/providers/openaifor OpenAI-compatible chat APIswiener/providers/anthropicfor Anthropic APIs
You can implement your own Provider with a single chat() async generator interface.
Harnesses (Optional)
wiener/harness provides composable loop controls:
- Guardrails:
toolPolicy,costGuard,approval - Control loops:
ralphLoop,selfVerify,reflexion - Orchestration:
steer,followUp,logger
import { composeHooks, logger, toolPolicy, costGuard } from "@alexandre_ai/wiener/harness";
const hooks = composeHooks(
logger(),
toolPolicy({ deny: ["delete_file"] }),
costGuard({ maxTurns: 10, maxToolCalls: 20 }),
);MCP Integration
Bring your own MCP client and convert tools with fromMcp():
import { fromMcp } from "wiener";
const tools = await fromMcp(mcpClient);
const a = agent({ provider, model, tools });Production Docs
For release-grade usage, read:
docs/production.mddocs/troubleshooting.mddocs/compatibility.md
Examples
Run examples with:
npx tsx examples/01-hello-world.tsExample index:
| File | Focus | Expected Outcome |
|---|---|---|
| examples/01-hello-world.ts | Basic agent + tool | One successful tool-assisted answer |
| examples/02-memory-chat.ts | createMemory persistence | Prior user facts are recalled |
| examples/03-tool-validation.ts | Tool arg validation | Invalid args return model-visible error |
| examples/04-streaming.ts | Event streaming | Token deltas and tool lifecycle events appear |
| examples/05-hooks.ts | Raw hook API | Deny/transform/continue behavior shown |
| examples/06-skill-composition.ts | skill() composition | Prompt + tool composition works |
| examples/07-dynamic-tools.ts | ToolSelector | Only context-relevant tools are selected |
| examples/08-multi-agent.ts | Agent orchestration pattern | Delegation flow across responsibilities |
| examples/09-self-evolving.ts | Learning loop pattern | Agent behavior adapts between runs |
| examples/10-compaction.ts | Context compaction | Long context is summarized |
| examples/11-harness.ts | Full harness stack | Multiple harnesses compose safely |
| examples/12-steer.ts | External steering | Mid-run direction injection works |
| examples/13-follow-up.ts | Follow-up queue | Tasks chain automatically |
| examples/14-cost-guard.ts | Budget guardrail | Run is constrained by limits |
| examples/15-approval.ts | Human-in-the-loop | Sensitive tool calls require approval |
| examples/16-reflexion.ts | Cross-session reflections | Prior failures influence later runs |
Benchmarks
Benchmark framework docs and commands are in benchmarks/README.md.
Design Principles
- Keep core small and stable.
- Prefer composition over inheritance.
- Make reliability features opt-in, not mandatory.
- Preserve framework-agnostic boundaries.
License
MIT
