HTTP with Hono
Second BYO HTTP stack: agent SSE and interruptible graph resume on Hono, installing @monorch/ai from npm (not the monorepo workspace).
1. Install (published package)
Clone the repo example or copy the pattern into your app. The example lives outside the pnpm workspace so it cannot accidentally link packages/ai.
terminal
bash
cd examples/hono-npm
npm install # pulls @monorch/ai@0.2.0 from the registry
npm run smoke # or: pnpm smoke:hono from the monorepo root2. Agent + SSE
stream.ts
typescript
import { Hono } from "hono";
import { streamSSE } from "hono/streaming";
import { agent, mock, tool } from "@monorch/ai";
import { z } from "zod";
const add = tool({
name: "add",
input: z.object({ a: z.number(), b: z.number() }),
permission: { type: "roles", roles: ["agent"] },
execute: ({ a, b }) => ({ sum: a + b }),
});
const app = new Hono();
app.post("/support/stream", async (c) => {
const bot = agent({
name: "support",
model: mock([
{ toolCalls: [{ id: "c1", name: "add", arguments: { a: 2, b: 3 } }] },
{ text: "2 + 3 = 5" },
]),
tools: [add],
});
return streamSSE(c, async (stream) => {
for await (const ev of bot.stream("2+3")) {
await stream.writeSSE({ data: JSON.stringify(ev) });
}
});
});3. Interrupt + resume
refund.ts
typescript
import { AiError, graph, memorySaver } from "@monorch/ai";
const refund = graph("refund")
.node("lookup", async ({ input }) => ({
output: `order:${input.orderId}`,
state: { orderId: input.orderId },
}))
.interrupt("approve", { prompt: "Approve refund?" })
.node("pay", async ({ outputs }) => `refunded:${outputs.lookup}`)
.compile({ checkpointer: memorySaver() });
app.post("/refund", async (c) => {
const { orderId, threadId } = await c.req.json();
const run = await refund.start({ orderId }, { threadId });
return c.json({ status: run.status, threadId });
});
app.post("/refund/:threadId/resume", async (c) => {
try {
const run = await refund.restore(c.req.param("threadId"));
const done = await run.resume("approved");
return c.json({ status: done.status, outputs: done.outputs });
} catch (e) {
if (e instanceof AiError && e.code === "CHECKPOINT_NOT_FOUND") {
return c.json({ error: "unknown thread" }, 404);
}
throw e;
}
});Related
Fastify variant: HTTP with Fastify. HITL details: HITL refund. Failure codes: Errors & failure modes.