@agentic-patterns/server 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Pattern Stack
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/dist/index.cjs ADDED
@@ -0,0 +1,242 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ agentEventToSSE: () => agentEventToSSE,
24
+ createServer: () => createServer
25
+ });
26
+ module.exports = __toCommonJS(index_exports);
27
+
28
+ // src/app.ts
29
+ var import_hono6 = require("hono");
30
+
31
+ // src/middleware/cors.ts
32
+ var import_cors = require("hono/cors");
33
+ function corsMiddleware(config) {
34
+ return (0, import_cors.cors)({
35
+ origin: config?.origin ?? "*",
36
+ allowMethods: config?.allowMethods ?? ["GET", "POST", "OPTIONS"],
37
+ allowHeaders: config?.allowHeaders ?? ["Content-Type"],
38
+ ...config?.maxAge !== void 0 ? { maxAge: config.maxAge } : {},
39
+ ...config?.credentials !== void 0 ? { credentials: config.credentials } : {},
40
+ ...config?.exposeHeaders !== void 0 ? { exposeHeaders: config.exposeHeaders } : {}
41
+ });
42
+ }
43
+
44
+ // src/middleware/error-handler.ts
45
+ var errorHandler = (err, c) => {
46
+ console.error("Server error:", err);
47
+ return c.json({ error: err.message || "Internal server error" }, 500);
48
+ };
49
+
50
+ // src/routes/admin.ts
51
+ var import_hono = require("hono");
52
+ function adminRoutes(config) {
53
+ const app = new import_hono.Hono();
54
+ app.get("/admin/dashboard", async (c) => {
55
+ const stats = await config.adminService.getDashboardStats();
56
+ return c.json(stats);
57
+ });
58
+ app.get("/admin/agents", async (c) => {
59
+ const agents = await config.adminService.getAllAgentStats();
60
+ return c.json(agents);
61
+ });
62
+ app.get("/admin/tools", async (c) => {
63
+ const tools = await config.adminService.getToolAnalytics();
64
+ return c.json(tools);
65
+ });
66
+ app.get("/admin/tokens", async (c) => {
67
+ const groupBy = c.req.query("group_by") ?? "agent";
68
+ const usage = await config.adminService.getTokenUsage({ groupBy });
69
+ return c.json(usage);
70
+ });
71
+ app.get("/admin/events/stream", (c) => {
72
+ const stream = config.sseExporter.connect();
73
+ c.req.raw.signal.addEventListener("abort", () => {
74
+ config.sseExporter.disconnect(stream);
75
+ });
76
+ return new Response(stream, {
77
+ headers: {
78
+ "Content-Type": "text/event-stream",
79
+ "Cache-Control": "no-cache",
80
+ Connection: "keep-alive"
81
+ }
82
+ });
83
+ });
84
+ return app;
85
+ }
86
+
87
+ // src/routes/agents.ts
88
+ var import_hono2 = require("hono");
89
+ function agentRoutes(agents) {
90
+ const app = new import_hono2.Hono();
91
+ app.get("/agents", (c) => {
92
+ const summaries = agents.map((a) => ({
93
+ id: a.id,
94
+ name: a.name,
95
+ description: a.description ?? ""
96
+ }));
97
+ return c.json(summaries);
98
+ });
99
+ return app;
100
+ }
101
+
102
+ // src/routes/conversations.ts
103
+ var import_runtime2 = require("@agentic-patterns/runtime");
104
+ var import_hono3 = require("hono");
105
+ var import_streaming = require("hono/streaming");
106
+
107
+ // src/sse.ts
108
+ var import_runtime = require("@agentic-patterns/runtime");
109
+ var INTERNAL_EVENT_TYPES = /* @__PURE__ */ new Set([
110
+ "agent.iteration.start",
111
+ "agent.iteration.end",
112
+ "agent.llm.start",
113
+ "agent.llm.end"
114
+ ]);
115
+ function agentEventToSSE(event) {
116
+ if (INTERNAL_EVENT_TYPES.has(event.type)) return null;
117
+ const mapping = (0, import_runtime.toSSEMapping)(event);
118
+ if (!mapping) return null;
119
+ return { event: mapping.name, data: JSON.stringify(mapping.payload) };
120
+ }
121
+
122
+ // src/routes/conversations.ts
123
+ function conversationRoutes(agents, conversations, eventBus) {
124
+ const app = new import_hono3.Hono();
125
+ app.post("/conversations", async (c) => {
126
+ const body = await c.req.json();
127
+ const agentId = body.agent_id;
128
+ const reg = agents.find((a) => a.id === agentId);
129
+ if (!reg) {
130
+ return c.json({ error: "Agent not found" }, 404);
131
+ }
132
+ const toolExecutor = (0, import_runtime2.createToolboxExecutor)(
133
+ reg.agent
134
+ );
135
+ const conversation = new import_runtime2.Conversation(reg.agent, reg.runner, { toolExecutor });
136
+ conversations.set(conversation.id, { conversation, agentId });
137
+ return c.json({ id: conversation.id, agent_id: agentId }, 201);
138
+ });
139
+ app.post("/conversations/:id/messages", async (c) => {
140
+ const convId = c.req.param("id");
141
+ const entry = conversations.get(convId);
142
+ if (!entry) {
143
+ return c.json({ error: "Conversation not found" }, 404);
144
+ }
145
+ const body = await c.req.json();
146
+ const content = body.content;
147
+ if (!content || typeof content !== "string") {
148
+ return c.json({ error: "content is required" }, 400);
149
+ }
150
+ const { conversation } = entry;
151
+ if (!conversation.runner.stream) {
152
+ return c.json({ error: "Streaming not supported by this runner" }, 501);
153
+ }
154
+ return (0, import_streaming.streamSSE)(c, async (stream) => {
155
+ for await (const event of conversation.stream(content, { eventBus })) {
156
+ const msg = agentEventToSSE(event);
157
+ if (msg) {
158
+ await stream.writeSSE(msg);
159
+ }
160
+ }
161
+ await stream.writeSSE({ event: "done", data: "{}" });
162
+ });
163
+ });
164
+ return app;
165
+ }
166
+
167
+ // src/routes/health.ts
168
+ var import_hono4 = require("hono");
169
+ function healthRoutes() {
170
+ const app = new import_hono4.Hono();
171
+ app.get("/health", (c) => c.json({ status: "ok" }));
172
+ return app;
173
+ }
174
+
175
+ // src/routes/hooks.ts
176
+ var import_runtime3 = require("@agentic-patterns/runtime");
177
+ var import_hono5 = require("hono");
178
+ function newSpanId() {
179
+ if (typeof globalThis !== "undefined" && "crypto" in globalThis) {
180
+ return globalThis.crypto.randomUUID();
181
+ }
182
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
183
+ }
184
+ function hookRoutes(eventBus) {
185
+ const app = new import_hono5.Hono();
186
+ app.post("/hooks/:eventType", async (c) => {
187
+ const eventType = c.req.param("eventType");
188
+ if (!(0, import_runtime3.isClaudeCodeHookName)(eventType)) {
189
+ return c.json({ error: `unknown hook event: ${eventType}` }, 400);
190
+ }
191
+ const body = await c.req.json().catch(() => ({}));
192
+ const sessionId = typeof body.session_id === "string" ? body.session_id : "unknown";
193
+ const runnerCorrelationId = c.req.header("x-ap-runner-correlation-id") ?? void 0;
194
+ const hookEvent = {
195
+ type: "claude_code.hook",
196
+ traceId: sessionId,
197
+ runId: sessionId,
198
+ spanId: newSpanId(),
199
+ timestamp: /* @__PURE__ */ new Date(),
200
+ hookName: eventType,
201
+ sessionId,
202
+ transcriptPath: typeof body.transcript_path === "string" ? body.transcript_path : void 0,
203
+ cwd: typeof body.cwd === "string" ? body.cwd : void 0,
204
+ permissionMode: typeof body.permission_mode === "string" ? body.permission_mode : void 0,
205
+ toolName: typeof body.tool_name === "string" ? body.tool_name : void 0,
206
+ toolInput: body.tool_input,
207
+ toolResponse: body.tool_response,
208
+ toolUseId: typeof body.tool_use_id === "string" ? body.tool_use_id : void 0,
209
+ payload: body,
210
+ ...runnerCorrelationId ? { runnerCorrelationId } : {}
211
+ };
212
+ await eventBus.publish(hookEvent);
213
+ if (!runnerCorrelationId) {
214
+ const derived = (0, import_runtime3.mapClaudeCodeHookToAgentEvents)(hookEvent);
215
+ for (const e of derived) {
216
+ await eventBus.publish(e);
217
+ }
218
+ }
219
+ return c.json({ ok: true });
220
+ });
221
+ return app;
222
+ }
223
+
224
+ // src/app.ts
225
+ function createServer(config) {
226
+ const app = new import_hono6.Hono();
227
+ const conversations = /* @__PURE__ */ new Map();
228
+ app.use("*", corsMiddleware(config.cors));
229
+ app.onError(errorHandler);
230
+ app.route("/", healthRoutes());
231
+ app.route("/", agentRoutes(config.agents));
232
+ app.route("/", conversationRoutes(config.agents, conversations, config.eventBus));
233
+ app.route("/", adminRoutes(config));
234
+ app.route("/", hookRoutes(config.eventBus));
235
+ return app;
236
+ }
237
+ // Annotate the CommonJS export names for ESM import in node:
238
+ 0 && (module.exports = {
239
+ agentEventToSSE,
240
+ createServer
241
+ });
242
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/app.ts","../src/middleware/cors.ts","../src/middleware/error-handler.ts","../src/routes/admin.ts","../src/routes/agents.ts","../src/routes/conversations.ts","../src/sse.ts","../src/routes/health.ts","../src/routes/hooks.ts"],"sourcesContent":["// @agentic-patterns/server — barrel export\nexport { createServer } from \"./app.js\";\nexport type {\n ServerConfig,\n AgentRegistration,\n AdminServiceProtocol,\n SSEExporterLike,\n ConversationStoreLike,\n CORSConfig,\n} from \"./config.js\";\nexport { agentEventToSSE, type SSEMessage } from \"./sse.js\";\n","/**\n * Hono application factory.\n */\n\nimport { Hono } from \"hono\";\nimport type { ServerConfig } from \"./config.js\";\nimport { corsMiddleware } from \"./middleware/cors.js\";\nimport { errorHandler } from \"./middleware/error-handler.js\";\nimport { adminRoutes } from \"./routes/admin.js\";\nimport { agentRoutes } from \"./routes/agents.js\";\nimport { type ConversationEntry, conversationRoutes } from \"./routes/conversations.js\";\nimport { healthRoutes } from \"./routes/health.js\";\nimport { hookRoutes } from \"./routes/hooks.js\";\n\n/**\n * Create a configured Hono app with all routes.\n *\n * Each call creates a fresh conversation registry, so multiple\n * servers in the same process do not share conversation state.\n */\nexport function createServer(config: ServerConfig): Hono {\n const app = new Hono();\n const conversations = new Map<string, ConversationEntry>();\n\n // Middleware\n app.use(\"*\", corsMiddleware(config.cors));\n app.onError(errorHandler);\n\n // Routes\n app.route(\"/\", healthRoutes());\n app.route(\"/\", agentRoutes(config.agents));\n app.route(\"/\", conversationRoutes(config.agents, conversations, config.eventBus));\n app.route(\"/\", adminRoutes(config));\n app.route(\"/\", hookRoutes(config.eventBus));\n\n return app;\n}\n","/**\n * CORS middleware for dashboard dev.\n */\n\nimport { cors } from \"hono/cors\";\nimport type { CORSConfig } from \"../config.js\";\n\n/**\n * Build the Hono cors middleware for this server.\n *\n * Defaults are permissive (`origin: \"*\"`) for local development; callers\n * should pin origin/headers/credentials for production via `ServerConfig.cors`.\n */\nexport function corsMiddleware(config?: CORSConfig) {\n return cors({\n origin: config?.origin ?? \"*\",\n allowMethods: config?.allowMethods ?? [\"GET\", \"POST\", \"OPTIONS\"],\n allowHeaders: config?.allowHeaders ?? [\"Content-Type\"],\n ...(config?.maxAge !== undefined ? { maxAge: config.maxAge } : {}),\n ...(config?.credentials !== undefined ? { credentials: config.credentials } : {}),\n ...(config?.exposeHeaders !== undefined ? { exposeHeaders: config.exposeHeaders } : {}),\n });\n}\n","/**\n * Global error handler.\n */\n\nimport type { ErrorHandler } from \"hono\";\n\nexport const errorHandler: ErrorHandler = (err, c) => {\n console.error(\"Server error:\", err);\n return c.json({ error: err.message || \"Internal server error\" }, 500);\n};\n","/**\n * Admin routes — dashboard stats, tool analytics, token usage, live event stream.\n */\n\nimport { Hono } from \"hono\";\nimport type { ServerConfig } from \"../config.js\";\n\nexport function adminRoutes(config: ServerConfig): Hono {\n const app = new Hono();\n\n app.get(\"/admin/dashboard\", async (c) => {\n const stats = await config.adminService.getDashboardStats();\n return c.json(stats);\n });\n\n app.get(\"/admin/agents\", async (c) => {\n const agents = await config.adminService.getAllAgentStats();\n return c.json(agents);\n });\n\n app.get(\"/admin/tools\", async (c) => {\n const tools = await config.adminService.getToolAnalytics();\n return c.json(tools);\n });\n\n app.get(\"/admin/tokens\", async (c) => {\n const groupBy = (c.req.query(\"group_by\") as \"agent\" | \"model\") ?? \"agent\";\n const usage = await config.adminService.getTokenUsage({ groupBy });\n return c.json(usage);\n });\n\n app.get(\"/admin/events/stream\", (c) => {\n const stream = config.sseExporter.connect();\n\n c.req.raw.signal.addEventListener(\"abort\", () => {\n config.sseExporter.disconnect(stream);\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n });\n\n return app;\n}\n","/**\n * Agent listing routes.\n */\n\nimport { Hono } from \"hono\";\nimport type { AgentRegistration } from \"../config.js\";\n\nexport function agentRoutes(agents: AgentRegistration[]): Hono {\n const app = new Hono();\n\n app.get(\"/agents\", (c) => {\n const summaries = agents.map((a) => ({\n id: a.id,\n name: a.name,\n description: a.description ?? \"\",\n }));\n return c.json(summaries);\n });\n\n return app;\n}\n","/**\n * Conversation routes — create conversations and stream messages via SSE.\n */\n\nimport type { AgentEventBus } from \"@agentic-patterns/runtime\";\nimport { Conversation, createToolboxExecutor } from \"@agentic-patterns/runtime\";\nimport { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { AgentRegistration } from \"../config.js\";\nimport { agentEventToSSE } from \"../sse.js\";\n\n/** Entry in the per-server conversation registry. */\nexport interface ConversationEntry {\n conversation: Conversation;\n agentId: string;\n}\n\nexport function conversationRoutes(\n agents: AgentRegistration[],\n conversations: Map<string, ConversationEntry>,\n eventBus: AgentEventBus,\n): Hono {\n const app = new Hono();\n\n // POST /conversations — create a new conversation\n app.post(\"/conversations\", async (c) => {\n const body = await c.req.json<{ agent_id: string }>();\n const agentId = body.agent_id;\n\n const reg = agents.find((a) => a.id === agentId);\n if (!reg) {\n return c.json({ error: \"Agent not found\" }, 404);\n }\n\n // Wire a ToolExecutor so AgentRunner can actually execute tool calls\n // from the agent's Capability toolboxes (not just format them for the LLM).\n const toolExecutor = createToolboxExecutor(\n reg.agent as unknown as Parameters<typeof createToolboxExecutor>[0],\n );\n const conversation = new Conversation(reg.agent, reg.runner, { toolExecutor });\n conversations.set(conversation.id, { conversation, agentId });\n\n return c.json({ id: conversation.id, agent_id: agentId }, 201);\n });\n\n // POST /conversations/:id/messages — send message, stream SSE response\n app.post(\"/conversations/:id/messages\", async (c) => {\n const convId = c.req.param(\"id\");\n const entry = conversations.get(convId);\n\n if (!entry) {\n return c.json({ error: \"Conversation not found\" }, 404);\n }\n\n const body = await c.req.json<{ content: string }>();\n const content = body.content;\n\n if (!content || typeof content !== \"string\") {\n return c.json({ error: \"content is required\" }, 400);\n }\n\n const { conversation } = entry;\n\n if (!conversation.runner.stream) {\n return c.json({ error: \"Streaming not supported by this runner\" }, 501);\n }\n\n // SSE streaming response. We pass the server's shared eventBus so\n // emitted events reach every attached exporter (collector, SSE\n // broadcast, etc.) in addition to flowing through the generator for\n // this client stream.\n return streamSSE(c, async (stream) => {\n for await (const event of conversation.stream(content, { eventBus })) {\n const msg = agentEventToSSE(event);\n if (msg) {\n await stream.writeSSE(msg);\n }\n }\n\n await stream.writeSSE({ event: \"done\", data: \"{}\" });\n });\n });\n\n return app;\n}\n","/**\n * SSE formatting for Hono streaming.\n *\n * Converts AgentEvents to `{ event, data }` objects compatible with Hono's\n * streamSSE writeSSE() method.\n *\n * Delegates wire-name and payload mapping to the runtime's canonical\n * `toSSEMapping` so the server stays in sync with the 20-event vocabulary\n * defined in the spec. Only internal observability events (iteration.* and\n * llm.*) are filtered here — they remain available over the admin SSE\n * stream (SSEExporter) for operators.\n */\n\nimport type { AgentEvent, AgentEventType } from \"@agentic-patterns/runtime\";\nimport { toSSEMapping } from \"@agentic-patterns/runtime\";\n\n/** SSE message shape for Hono's writeSSE(). */\nexport interface SSEMessage {\n event: string;\n data: string;\n}\n\n/**\n * Internal observability events not surfaced to end clients. They remain\n * available over the admin SSE stream for operators.\n */\nconst INTERNAL_EVENT_TYPES: ReadonlySet<AgentEventType> = new Set<AgentEventType>([\n \"agent.iteration.start\",\n \"agent.iteration.end\",\n \"agent.llm.start\",\n \"agent.llm.end\",\n]);\n\n/**\n * Convert an AgentEvent to an SSE message for Hono streaming.\n *\n * Returns `null` for events that are not part of the client-facing\n * protocol (internal observability events, or events with no SSE mapping).\n */\nexport function agentEventToSSE(event: AgentEvent): SSEMessage | null {\n if (INTERNAL_EVENT_TYPES.has(event.type)) return null;\n const mapping = toSSEMapping(event);\n if (!mapping) return null;\n return { event: mapping.name, data: JSON.stringify(mapping.payload) };\n}\n","/**\n * Health check route.\n */\n\nimport { Hono } from \"hono\";\n\nexport function healthRoutes(): Hono {\n const app = new Hono();\n app.get(\"/health\", (c) => c.json({ status: \"ok\" }));\n return app;\n}\n","/**\n * Claude Code hook bridge — receive hook callbacks from the Claude Code\n * CLI and republish them on the AgentEventBus.\n *\n * The Claude Code CLI is configured (via `.claude/settings.json`) to POST\n * each hook callback as JSON to `/hooks/:eventType`. We validate the\n * event name against the known hook list, normalize the payload into a\n * `ClaudeCodeHookEvent`, publish it to the bus, then publish any derived\n * canonical events (PreToolUse → agent.tool.start, etc.).\n */\n\nimport {\n type AgentEventBus,\n type ClaudeCodeHookEvent,\n isClaudeCodeHookName,\n mapClaudeCodeHookToAgentEvents,\n} from \"@agentic-patterns/runtime\";\nimport { Hono } from \"hono\";\n\nfunction newSpanId(): string {\n if (typeof globalThis !== \"undefined\" && \"crypto\" in globalThis) {\n return (globalThis as unknown as { crypto: { randomUUID(): string } }).crypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function hookRoutes(eventBus: AgentEventBus): Hono {\n const app = new Hono();\n\n app.post(\"/hooks/:eventType\", async (c) => {\n const eventType = c.req.param(\"eventType\");\n if (!isClaudeCodeHookName(eventType)) {\n return c.json({ error: `unknown hook event: ${eventType}` }, 400);\n }\n\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sessionId = typeof body.session_id === \"string\" ? body.session_id : \"unknown\";\n\n // Runner correlation: when a ClaudeCodeRunner spawned this CC session it\n // tags every hook POST with `x-ap-runner-correlation-id`. We preserve the\n // raw hook (PreCompact, PermissionRequest, etc. give value the runner\n // doesn't emit) but SKIP deriving `agent.tool.start`/`agent.tool.end`\n // events to avoid double-counting alongside the runner's own tool events.\n const runnerCorrelationId =\n c.req.header(\"x-ap-runner-correlation-id\") ?? undefined;\n\n const hookEvent: ClaudeCodeHookEvent = {\n type: \"claude_code.hook\",\n traceId: sessionId,\n runId: sessionId,\n spanId: newSpanId(),\n timestamp: new Date(),\n hookName: eventType,\n sessionId,\n transcriptPath:\n typeof body.transcript_path === \"string\" ? body.transcript_path : undefined,\n cwd: typeof body.cwd === \"string\" ? body.cwd : undefined,\n permissionMode:\n typeof body.permission_mode === \"string\" ? body.permission_mode : undefined,\n toolName: typeof body.tool_name === \"string\" ? body.tool_name : undefined,\n toolInput: body.tool_input,\n toolResponse: body.tool_response,\n toolUseId: typeof body.tool_use_id === \"string\" ? body.tool_use_id : undefined,\n payload: body,\n ...(runnerCorrelationId ? { runnerCorrelationId } : {}),\n };\n\n await eventBus.publish(hookEvent);\n\n if (!runnerCorrelationId) {\n const derived = mapClaudeCodeHookToAgentEvents(hookEvent);\n for (const e of derived) {\n await eventBus.publish(e);\n }\n }\n\n return c.json({ ok: true });\n });\n\n return app;\n}\n"],"mappings":"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","names":["import_hono","import_hono","import_runtime","import_hono","import_hono","import_runtime","import_hono"]}
@@ -0,0 +1,106 @@
1
+ import { Hono } from 'hono';
2
+ import { AgentLike, RunnerProtocol, RunResult, AdminServiceProtocol, AgentEventBus, AgentEvent } from '@agentic-patterns/runtime';
3
+ export { AdminServiceProtocol } from '@agentic-patterns/runtime';
4
+
5
+ /**
6
+ * Server configuration types.
7
+ */
8
+
9
+ /**
10
+ * Agent registration — what the server knows about each agent.
11
+ *
12
+ * `agent` and `runner.run/stream` use the canonical protocol shapes
13
+ * (`AgentLike`, `RunnerProtocol`, `RunResult`) from the runtime so the
14
+ * server and runtime share a single contract end-to-end.
15
+ */
16
+ interface AgentRegistration {
17
+ readonly id: string;
18
+ readonly name: string;
19
+ readonly description?: string;
20
+ readonly agent: AgentLike;
21
+ readonly runner: Pick<RunnerProtocol, "run" | "stream"> & {
22
+ run(agent: AgentLike, message: string, options?: Record<string, unknown>): Promise<RunResult>;
23
+ };
24
+ }
25
+
26
+ /**
27
+ * SSE exporter interface — structural typing for SSEExporter from runtime.
28
+ */
29
+ interface SSEExporterLike {
30
+ connect(): ReadableStream<Uint8Array>;
31
+ disconnect(stream: ReadableStream<Uint8Array>): void;
32
+ }
33
+ /**
34
+ * Conversation store interface — structural typing for ConversationStoreProtocol.
35
+ */
36
+ interface ConversationStoreLike {
37
+ get(id: string): Promise<unknown>;
38
+ list(): Promise<unknown[]>;
39
+ }
40
+ /**
41
+ * CORS configuration passed to the Hono cors middleware.
42
+ *
43
+ * Default is `origin: "*"` for local development. Production deployments
44
+ * should pin to known origins.
45
+ */
46
+ interface CORSConfig {
47
+ readonly origin?: string | string[];
48
+ readonly allowMethods?: string[];
49
+ readonly allowHeaders?: string[];
50
+ readonly maxAge?: number;
51
+ readonly credentials?: boolean;
52
+ readonly exposeHeaders?: string[];
53
+ }
54
+ /**
55
+ * Server configuration.
56
+ */
57
+ interface ServerConfig {
58
+ readonly agents: AgentRegistration[];
59
+ readonly adminService: AdminServiceProtocol;
60
+ readonly eventBus: AgentEventBus;
61
+ readonly sseExporter: SSEExporterLike;
62
+ readonly store?: ConversationStoreLike;
63
+ readonly staticDir?: string;
64
+ /** CORS options forwarded to Hono's cors middleware. Defaults to `origin: "*"`. */
65
+ readonly cors?: CORSConfig;
66
+ }
67
+
68
+ /**
69
+ * Hono application factory.
70
+ */
71
+
72
+ /**
73
+ * Create a configured Hono app with all routes.
74
+ *
75
+ * Each call creates a fresh conversation registry, so multiple
76
+ * servers in the same process do not share conversation state.
77
+ */
78
+ declare function createServer(config: ServerConfig): Hono;
79
+
80
+ /**
81
+ * SSE formatting for Hono streaming.
82
+ *
83
+ * Converts AgentEvents to `{ event, data }` objects compatible with Hono's
84
+ * streamSSE writeSSE() method.
85
+ *
86
+ * Delegates wire-name and payload mapping to the runtime's canonical
87
+ * `toSSEMapping` so the server stays in sync with the 20-event vocabulary
88
+ * defined in the spec. Only internal observability events (iteration.* and
89
+ * llm.*) are filtered here — they remain available over the admin SSE
90
+ * stream (SSEExporter) for operators.
91
+ */
92
+
93
+ /** SSE message shape for Hono's writeSSE(). */
94
+ interface SSEMessage {
95
+ event: string;
96
+ data: string;
97
+ }
98
+ /**
99
+ * Convert an AgentEvent to an SSE message for Hono streaming.
100
+ *
101
+ * Returns `null` for events that are not part of the client-facing
102
+ * protocol (internal observability events, or events with no SSE mapping).
103
+ */
104
+ declare function agentEventToSSE(event: AgentEvent): SSEMessage | null;
105
+
106
+ export { type AgentRegistration, type CORSConfig, type ConversationStoreLike, type SSEExporterLike, type SSEMessage, type ServerConfig, agentEventToSSE, createServer };
@@ -0,0 +1,106 @@
1
+ import { Hono } from 'hono';
2
+ import { AgentLike, RunnerProtocol, RunResult, AdminServiceProtocol, AgentEventBus, AgentEvent } from '@agentic-patterns/runtime';
3
+ export { AdminServiceProtocol } from '@agentic-patterns/runtime';
4
+
5
+ /**
6
+ * Server configuration types.
7
+ */
8
+
9
+ /**
10
+ * Agent registration — what the server knows about each agent.
11
+ *
12
+ * `agent` and `runner.run/stream` use the canonical protocol shapes
13
+ * (`AgentLike`, `RunnerProtocol`, `RunResult`) from the runtime so the
14
+ * server and runtime share a single contract end-to-end.
15
+ */
16
+ interface AgentRegistration {
17
+ readonly id: string;
18
+ readonly name: string;
19
+ readonly description?: string;
20
+ readonly agent: AgentLike;
21
+ readonly runner: Pick<RunnerProtocol, "run" | "stream"> & {
22
+ run(agent: AgentLike, message: string, options?: Record<string, unknown>): Promise<RunResult>;
23
+ };
24
+ }
25
+
26
+ /**
27
+ * SSE exporter interface — structural typing for SSEExporter from runtime.
28
+ */
29
+ interface SSEExporterLike {
30
+ connect(): ReadableStream<Uint8Array>;
31
+ disconnect(stream: ReadableStream<Uint8Array>): void;
32
+ }
33
+ /**
34
+ * Conversation store interface — structural typing for ConversationStoreProtocol.
35
+ */
36
+ interface ConversationStoreLike {
37
+ get(id: string): Promise<unknown>;
38
+ list(): Promise<unknown[]>;
39
+ }
40
+ /**
41
+ * CORS configuration passed to the Hono cors middleware.
42
+ *
43
+ * Default is `origin: "*"` for local development. Production deployments
44
+ * should pin to known origins.
45
+ */
46
+ interface CORSConfig {
47
+ readonly origin?: string | string[];
48
+ readonly allowMethods?: string[];
49
+ readonly allowHeaders?: string[];
50
+ readonly maxAge?: number;
51
+ readonly credentials?: boolean;
52
+ readonly exposeHeaders?: string[];
53
+ }
54
+ /**
55
+ * Server configuration.
56
+ */
57
+ interface ServerConfig {
58
+ readonly agents: AgentRegistration[];
59
+ readonly adminService: AdminServiceProtocol;
60
+ readonly eventBus: AgentEventBus;
61
+ readonly sseExporter: SSEExporterLike;
62
+ readonly store?: ConversationStoreLike;
63
+ readonly staticDir?: string;
64
+ /** CORS options forwarded to Hono's cors middleware. Defaults to `origin: "*"`. */
65
+ readonly cors?: CORSConfig;
66
+ }
67
+
68
+ /**
69
+ * Hono application factory.
70
+ */
71
+
72
+ /**
73
+ * Create a configured Hono app with all routes.
74
+ *
75
+ * Each call creates a fresh conversation registry, so multiple
76
+ * servers in the same process do not share conversation state.
77
+ */
78
+ declare function createServer(config: ServerConfig): Hono;
79
+
80
+ /**
81
+ * SSE formatting for Hono streaming.
82
+ *
83
+ * Converts AgentEvents to `{ event, data }` objects compatible with Hono's
84
+ * streamSSE writeSSE() method.
85
+ *
86
+ * Delegates wire-name and payload mapping to the runtime's canonical
87
+ * `toSSEMapping` so the server stays in sync with the 20-event vocabulary
88
+ * defined in the spec. Only internal observability events (iteration.* and
89
+ * llm.*) are filtered here — they remain available over the admin SSE
90
+ * stream (SSEExporter) for operators.
91
+ */
92
+
93
+ /** SSE message shape for Hono's writeSSE(). */
94
+ interface SSEMessage {
95
+ event: string;
96
+ data: string;
97
+ }
98
+ /**
99
+ * Convert an AgentEvent to an SSE message for Hono streaming.
100
+ *
101
+ * Returns `null` for events that are not part of the client-facing
102
+ * protocol (internal observability events, or events with no SSE mapping).
103
+ */
104
+ declare function agentEventToSSE(event: AgentEvent): SSEMessage | null;
105
+
106
+ export { type AgentRegistration, type CORSConfig, type ConversationStoreLike, type SSEExporterLike, type SSEMessage, type ServerConfig, agentEventToSSE, createServer };
package/dist/index.js ADDED
@@ -0,0 +1,217 @@
1
+ // src/app.ts
2
+ import { Hono as Hono6 } from "hono";
3
+
4
+ // src/middleware/cors.ts
5
+ import { cors } from "hono/cors";
6
+ function corsMiddleware(config) {
7
+ return cors({
8
+ origin: config?.origin ?? "*",
9
+ allowMethods: config?.allowMethods ?? ["GET", "POST", "OPTIONS"],
10
+ allowHeaders: config?.allowHeaders ?? ["Content-Type"],
11
+ ...config?.maxAge !== void 0 ? { maxAge: config.maxAge } : {},
12
+ ...config?.credentials !== void 0 ? { credentials: config.credentials } : {},
13
+ ...config?.exposeHeaders !== void 0 ? { exposeHeaders: config.exposeHeaders } : {}
14
+ });
15
+ }
16
+
17
+ // src/middleware/error-handler.ts
18
+ var errorHandler = (err, c) => {
19
+ console.error("Server error:", err);
20
+ return c.json({ error: err.message || "Internal server error" }, 500);
21
+ };
22
+
23
+ // src/routes/admin.ts
24
+ import { Hono } from "hono";
25
+ function adminRoutes(config) {
26
+ const app = new Hono();
27
+ app.get("/admin/dashboard", async (c) => {
28
+ const stats = await config.adminService.getDashboardStats();
29
+ return c.json(stats);
30
+ });
31
+ app.get("/admin/agents", async (c) => {
32
+ const agents = await config.adminService.getAllAgentStats();
33
+ return c.json(agents);
34
+ });
35
+ app.get("/admin/tools", async (c) => {
36
+ const tools = await config.adminService.getToolAnalytics();
37
+ return c.json(tools);
38
+ });
39
+ app.get("/admin/tokens", async (c) => {
40
+ const groupBy = c.req.query("group_by") ?? "agent";
41
+ const usage = await config.adminService.getTokenUsage({ groupBy });
42
+ return c.json(usage);
43
+ });
44
+ app.get("/admin/events/stream", (c) => {
45
+ const stream = config.sseExporter.connect();
46
+ c.req.raw.signal.addEventListener("abort", () => {
47
+ config.sseExporter.disconnect(stream);
48
+ });
49
+ return new Response(stream, {
50
+ headers: {
51
+ "Content-Type": "text/event-stream",
52
+ "Cache-Control": "no-cache",
53
+ Connection: "keep-alive"
54
+ }
55
+ });
56
+ });
57
+ return app;
58
+ }
59
+
60
+ // src/routes/agents.ts
61
+ import { Hono as Hono2 } from "hono";
62
+ function agentRoutes(agents) {
63
+ const app = new Hono2();
64
+ app.get("/agents", (c) => {
65
+ const summaries = agents.map((a) => ({
66
+ id: a.id,
67
+ name: a.name,
68
+ description: a.description ?? ""
69
+ }));
70
+ return c.json(summaries);
71
+ });
72
+ return app;
73
+ }
74
+
75
+ // src/routes/conversations.ts
76
+ import { Conversation, createToolboxExecutor } from "@agentic-patterns/runtime";
77
+ import { Hono as Hono3 } from "hono";
78
+ import { streamSSE } from "hono/streaming";
79
+
80
+ // src/sse.ts
81
+ import { toSSEMapping } from "@agentic-patterns/runtime";
82
+ var INTERNAL_EVENT_TYPES = /* @__PURE__ */ new Set([
83
+ "agent.iteration.start",
84
+ "agent.iteration.end",
85
+ "agent.llm.start",
86
+ "agent.llm.end"
87
+ ]);
88
+ function agentEventToSSE(event) {
89
+ if (INTERNAL_EVENT_TYPES.has(event.type)) return null;
90
+ const mapping = toSSEMapping(event);
91
+ if (!mapping) return null;
92
+ return { event: mapping.name, data: JSON.stringify(mapping.payload) };
93
+ }
94
+
95
+ // src/routes/conversations.ts
96
+ function conversationRoutes(agents, conversations, eventBus) {
97
+ const app = new Hono3();
98
+ app.post("/conversations", async (c) => {
99
+ const body = await c.req.json();
100
+ const agentId = body.agent_id;
101
+ const reg = agents.find((a) => a.id === agentId);
102
+ if (!reg) {
103
+ return c.json({ error: "Agent not found" }, 404);
104
+ }
105
+ const toolExecutor = createToolboxExecutor(
106
+ reg.agent
107
+ );
108
+ const conversation = new Conversation(reg.agent, reg.runner, { toolExecutor });
109
+ conversations.set(conversation.id, { conversation, agentId });
110
+ return c.json({ id: conversation.id, agent_id: agentId }, 201);
111
+ });
112
+ app.post("/conversations/:id/messages", async (c) => {
113
+ const convId = c.req.param("id");
114
+ const entry = conversations.get(convId);
115
+ if (!entry) {
116
+ return c.json({ error: "Conversation not found" }, 404);
117
+ }
118
+ const body = await c.req.json();
119
+ const content = body.content;
120
+ if (!content || typeof content !== "string") {
121
+ return c.json({ error: "content is required" }, 400);
122
+ }
123
+ const { conversation } = entry;
124
+ if (!conversation.runner.stream) {
125
+ return c.json({ error: "Streaming not supported by this runner" }, 501);
126
+ }
127
+ return streamSSE(c, async (stream) => {
128
+ for await (const event of conversation.stream(content, { eventBus })) {
129
+ const msg = agentEventToSSE(event);
130
+ if (msg) {
131
+ await stream.writeSSE(msg);
132
+ }
133
+ }
134
+ await stream.writeSSE({ event: "done", data: "{}" });
135
+ });
136
+ });
137
+ return app;
138
+ }
139
+
140
+ // src/routes/health.ts
141
+ import { Hono as Hono4 } from "hono";
142
+ function healthRoutes() {
143
+ const app = new Hono4();
144
+ app.get("/health", (c) => c.json({ status: "ok" }));
145
+ return app;
146
+ }
147
+
148
+ // src/routes/hooks.ts
149
+ import {
150
+ isClaudeCodeHookName,
151
+ mapClaudeCodeHookToAgentEvents
152
+ } from "@agentic-patterns/runtime";
153
+ import { Hono as Hono5 } from "hono";
154
+ function newSpanId() {
155
+ if (typeof globalThis !== "undefined" && "crypto" in globalThis) {
156
+ return globalThis.crypto.randomUUID();
157
+ }
158
+ return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
159
+ }
160
+ function hookRoutes(eventBus) {
161
+ const app = new Hono5();
162
+ app.post("/hooks/:eventType", async (c) => {
163
+ const eventType = c.req.param("eventType");
164
+ if (!isClaudeCodeHookName(eventType)) {
165
+ return c.json({ error: `unknown hook event: ${eventType}` }, 400);
166
+ }
167
+ const body = await c.req.json().catch(() => ({}));
168
+ const sessionId = typeof body.session_id === "string" ? body.session_id : "unknown";
169
+ const runnerCorrelationId = c.req.header("x-ap-runner-correlation-id") ?? void 0;
170
+ const hookEvent = {
171
+ type: "claude_code.hook",
172
+ traceId: sessionId,
173
+ runId: sessionId,
174
+ spanId: newSpanId(),
175
+ timestamp: /* @__PURE__ */ new Date(),
176
+ hookName: eventType,
177
+ sessionId,
178
+ transcriptPath: typeof body.transcript_path === "string" ? body.transcript_path : void 0,
179
+ cwd: typeof body.cwd === "string" ? body.cwd : void 0,
180
+ permissionMode: typeof body.permission_mode === "string" ? body.permission_mode : void 0,
181
+ toolName: typeof body.tool_name === "string" ? body.tool_name : void 0,
182
+ toolInput: body.tool_input,
183
+ toolResponse: body.tool_response,
184
+ toolUseId: typeof body.tool_use_id === "string" ? body.tool_use_id : void 0,
185
+ payload: body,
186
+ ...runnerCorrelationId ? { runnerCorrelationId } : {}
187
+ };
188
+ await eventBus.publish(hookEvent);
189
+ if (!runnerCorrelationId) {
190
+ const derived = mapClaudeCodeHookToAgentEvents(hookEvent);
191
+ for (const e of derived) {
192
+ await eventBus.publish(e);
193
+ }
194
+ }
195
+ return c.json({ ok: true });
196
+ });
197
+ return app;
198
+ }
199
+
200
+ // src/app.ts
201
+ function createServer(config) {
202
+ const app = new Hono6();
203
+ const conversations = /* @__PURE__ */ new Map();
204
+ app.use("*", corsMiddleware(config.cors));
205
+ app.onError(errorHandler);
206
+ app.route("/", healthRoutes());
207
+ app.route("/", agentRoutes(config.agents));
208
+ app.route("/", conversationRoutes(config.agents, conversations, config.eventBus));
209
+ app.route("/", adminRoutes(config));
210
+ app.route("/", hookRoutes(config.eventBus));
211
+ return app;
212
+ }
213
+ export {
214
+ agentEventToSSE,
215
+ createServer
216
+ };
217
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/app.ts","../src/middleware/cors.ts","../src/middleware/error-handler.ts","../src/routes/admin.ts","../src/routes/agents.ts","../src/routes/conversations.ts","../src/sse.ts","../src/routes/health.ts","../src/routes/hooks.ts"],"sourcesContent":["/**\n * Hono application factory.\n */\n\nimport { Hono } from \"hono\";\nimport type { ServerConfig } from \"./config.js\";\nimport { corsMiddleware } from \"./middleware/cors.js\";\nimport { errorHandler } from \"./middleware/error-handler.js\";\nimport { adminRoutes } from \"./routes/admin.js\";\nimport { agentRoutes } from \"./routes/agents.js\";\nimport { type ConversationEntry, conversationRoutes } from \"./routes/conversations.js\";\nimport { healthRoutes } from \"./routes/health.js\";\nimport { hookRoutes } from \"./routes/hooks.js\";\n\n/**\n * Create a configured Hono app with all routes.\n *\n * Each call creates a fresh conversation registry, so multiple\n * servers in the same process do not share conversation state.\n */\nexport function createServer(config: ServerConfig): Hono {\n const app = new Hono();\n const conversations = new Map<string, ConversationEntry>();\n\n // Middleware\n app.use(\"*\", corsMiddleware(config.cors));\n app.onError(errorHandler);\n\n // Routes\n app.route(\"/\", healthRoutes());\n app.route(\"/\", agentRoutes(config.agents));\n app.route(\"/\", conversationRoutes(config.agents, conversations, config.eventBus));\n app.route(\"/\", adminRoutes(config));\n app.route(\"/\", hookRoutes(config.eventBus));\n\n return app;\n}\n","/**\n * CORS middleware for dashboard dev.\n */\n\nimport { cors } from \"hono/cors\";\nimport type { CORSConfig } from \"../config.js\";\n\n/**\n * Build the Hono cors middleware for this server.\n *\n * Defaults are permissive (`origin: \"*\"`) for local development; callers\n * should pin origin/headers/credentials for production via `ServerConfig.cors`.\n */\nexport function corsMiddleware(config?: CORSConfig) {\n return cors({\n origin: config?.origin ?? \"*\",\n allowMethods: config?.allowMethods ?? [\"GET\", \"POST\", \"OPTIONS\"],\n allowHeaders: config?.allowHeaders ?? [\"Content-Type\"],\n ...(config?.maxAge !== undefined ? { maxAge: config.maxAge } : {}),\n ...(config?.credentials !== undefined ? { credentials: config.credentials } : {}),\n ...(config?.exposeHeaders !== undefined ? { exposeHeaders: config.exposeHeaders } : {}),\n });\n}\n","/**\n * Global error handler.\n */\n\nimport type { ErrorHandler } from \"hono\";\n\nexport const errorHandler: ErrorHandler = (err, c) => {\n console.error(\"Server error:\", err);\n return c.json({ error: err.message || \"Internal server error\" }, 500);\n};\n","/**\n * Admin routes — dashboard stats, tool analytics, token usage, live event stream.\n */\n\nimport { Hono } from \"hono\";\nimport type { ServerConfig } from \"../config.js\";\n\nexport function adminRoutes(config: ServerConfig): Hono {\n const app = new Hono();\n\n app.get(\"/admin/dashboard\", async (c) => {\n const stats = await config.adminService.getDashboardStats();\n return c.json(stats);\n });\n\n app.get(\"/admin/agents\", async (c) => {\n const agents = await config.adminService.getAllAgentStats();\n return c.json(agents);\n });\n\n app.get(\"/admin/tools\", async (c) => {\n const tools = await config.adminService.getToolAnalytics();\n return c.json(tools);\n });\n\n app.get(\"/admin/tokens\", async (c) => {\n const groupBy = (c.req.query(\"group_by\") as \"agent\" | \"model\") ?? \"agent\";\n const usage = await config.adminService.getTokenUsage({ groupBy });\n return c.json(usage);\n });\n\n app.get(\"/admin/events/stream\", (c) => {\n const stream = config.sseExporter.connect();\n\n c.req.raw.signal.addEventListener(\"abort\", () => {\n config.sseExporter.disconnect(stream);\n });\n\n return new Response(stream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n });\n\n return app;\n}\n","/**\n * Agent listing routes.\n */\n\nimport { Hono } from \"hono\";\nimport type { AgentRegistration } from \"../config.js\";\n\nexport function agentRoutes(agents: AgentRegistration[]): Hono {\n const app = new Hono();\n\n app.get(\"/agents\", (c) => {\n const summaries = agents.map((a) => ({\n id: a.id,\n name: a.name,\n description: a.description ?? \"\",\n }));\n return c.json(summaries);\n });\n\n return app;\n}\n","/**\n * Conversation routes — create conversations and stream messages via SSE.\n */\n\nimport type { AgentEventBus } from \"@agentic-patterns/runtime\";\nimport { Conversation, createToolboxExecutor } from \"@agentic-patterns/runtime\";\nimport { Hono } from \"hono\";\nimport { streamSSE } from \"hono/streaming\";\nimport type { AgentRegistration } from \"../config.js\";\nimport { agentEventToSSE } from \"../sse.js\";\n\n/** Entry in the per-server conversation registry. */\nexport interface ConversationEntry {\n conversation: Conversation;\n agentId: string;\n}\n\nexport function conversationRoutes(\n agents: AgentRegistration[],\n conversations: Map<string, ConversationEntry>,\n eventBus: AgentEventBus,\n): Hono {\n const app = new Hono();\n\n // POST /conversations — create a new conversation\n app.post(\"/conversations\", async (c) => {\n const body = await c.req.json<{ agent_id: string }>();\n const agentId = body.agent_id;\n\n const reg = agents.find((a) => a.id === agentId);\n if (!reg) {\n return c.json({ error: \"Agent not found\" }, 404);\n }\n\n // Wire a ToolExecutor so AgentRunner can actually execute tool calls\n // from the agent's Capability toolboxes (not just format them for the LLM).\n const toolExecutor = createToolboxExecutor(\n reg.agent as unknown as Parameters<typeof createToolboxExecutor>[0],\n );\n const conversation = new Conversation(reg.agent, reg.runner, { toolExecutor });\n conversations.set(conversation.id, { conversation, agentId });\n\n return c.json({ id: conversation.id, agent_id: agentId }, 201);\n });\n\n // POST /conversations/:id/messages — send message, stream SSE response\n app.post(\"/conversations/:id/messages\", async (c) => {\n const convId = c.req.param(\"id\");\n const entry = conversations.get(convId);\n\n if (!entry) {\n return c.json({ error: \"Conversation not found\" }, 404);\n }\n\n const body = await c.req.json<{ content: string }>();\n const content = body.content;\n\n if (!content || typeof content !== \"string\") {\n return c.json({ error: \"content is required\" }, 400);\n }\n\n const { conversation } = entry;\n\n if (!conversation.runner.stream) {\n return c.json({ error: \"Streaming not supported by this runner\" }, 501);\n }\n\n // SSE streaming response. We pass the server's shared eventBus so\n // emitted events reach every attached exporter (collector, SSE\n // broadcast, etc.) in addition to flowing through the generator for\n // this client stream.\n return streamSSE(c, async (stream) => {\n for await (const event of conversation.stream(content, { eventBus })) {\n const msg = agentEventToSSE(event);\n if (msg) {\n await stream.writeSSE(msg);\n }\n }\n\n await stream.writeSSE({ event: \"done\", data: \"{}\" });\n });\n });\n\n return app;\n}\n","/**\n * SSE formatting for Hono streaming.\n *\n * Converts AgentEvents to `{ event, data }` objects compatible with Hono's\n * streamSSE writeSSE() method.\n *\n * Delegates wire-name and payload mapping to the runtime's canonical\n * `toSSEMapping` so the server stays in sync with the 20-event vocabulary\n * defined in the spec. Only internal observability events (iteration.* and\n * llm.*) are filtered here — they remain available over the admin SSE\n * stream (SSEExporter) for operators.\n */\n\nimport type { AgentEvent, AgentEventType } from \"@agentic-patterns/runtime\";\nimport { toSSEMapping } from \"@agentic-patterns/runtime\";\n\n/** SSE message shape for Hono's writeSSE(). */\nexport interface SSEMessage {\n event: string;\n data: string;\n}\n\n/**\n * Internal observability events not surfaced to end clients. They remain\n * available over the admin SSE stream for operators.\n */\nconst INTERNAL_EVENT_TYPES: ReadonlySet<AgentEventType> = new Set<AgentEventType>([\n \"agent.iteration.start\",\n \"agent.iteration.end\",\n \"agent.llm.start\",\n \"agent.llm.end\",\n]);\n\n/**\n * Convert an AgentEvent to an SSE message for Hono streaming.\n *\n * Returns `null` for events that are not part of the client-facing\n * protocol (internal observability events, or events with no SSE mapping).\n */\nexport function agentEventToSSE(event: AgentEvent): SSEMessage | null {\n if (INTERNAL_EVENT_TYPES.has(event.type)) return null;\n const mapping = toSSEMapping(event);\n if (!mapping) return null;\n return { event: mapping.name, data: JSON.stringify(mapping.payload) };\n}\n","/**\n * Health check route.\n */\n\nimport { Hono } from \"hono\";\n\nexport function healthRoutes(): Hono {\n const app = new Hono();\n app.get(\"/health\", (c) => c.json({ status: \"ok\" }));\n return app;\n}\n","/**\n * Claude Code hook bridge — receive hook callbacks from the Claude Code\n * CLI and republish them on the AgentEventBus.\n *\n * The Claude Code CLI is configured (via `.claude/settings.json`) to POST\n * each hook callback as JSON to `/hooks/:eventType`. We validate the\n * event name against the known hook list, normalize the payload into a\n * `ClaudeCodeHookEvent`, publish it to the bus, then publish any derived\n * canonical events (PreToolUse → agent.tool.start, etc.).\n */\n\nimport {\n type AgentEventBus,\n type ClaudeCodeHookEvent,\n isClaudeCodeHookName,\n mapClaudeCodeHookToAgentEvents,\n} from \"@agentic-patterns/runtime\";\nimport { Hono } from \"hono\";\n\nfunction newSpanId(): string {\n if (typeof globalThis !== \"undefined\" && \"crypto\" in globalThis) {\n return (globalThis as unknown as { crypto: { randomUUID(): string } }).crypto.randomUUID();\n }\n return `${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;\n}\n\nexport function hookRoutes(eventBus: AgentEventBus): Hono {\n const app = new Hono();\n\n app.post(\"/hooks/:eventType\", async (c) => {\n const eventType = c.req.param(\"eventType\");\n if (!isClaudeCodeHookName(eventType)) {\n return c.json({ error: `unknown hook event: ${eventType}` }, 400);\n }\n\n const body = (await c.req.json().catch(() => ({}))) as Record<string, unknown>;\n const sessionId = typeof body.session_id === \"string\" ? body.session_id : \"unknown\";\n\n // Runner correlation: when a ClaudeCodeRunner spawned this CC session it\n // tags every hook POST with `x-ap-runner-correlation-id`. We preserve the\n // raw hook (PreCompact, PermissionRequest, etc. give value the runner\n // doesn't emit) but SKIP deriving `agent.tool.start`/`agent.tool.end`\n // events to avoid double-counting alongside the runner's own tool events.\n const runnerCorrelationId =\n c.req.header(\"x-ap-runner-correlation-id\") ?? undefined;\n\n const hookEvent: ClaudeCodeHookEvent = {\n type: \"claude_code.hook\",\n traceId: sessionId,\n runId: sessionId,\n spanId: newSpanId(),\n timestamp: new Date(),\n hookName: eventType,\n sessionId,\n transcriptPath:\n typeof body.transcript_path === \"string\" ? body.transcript_path : undefined,\n cwd: typeof body.cwd === \"string\" ? body.cwd : undefined,\n permissionMode:\n typeof body.permission_mode === \"string\" ? body.permission_mode : undefined,\n toolName: typeof body.tool_name === \"string\" ? body.tool_name : undefined,\n toolInput: body.tool_input,\n toolResponse: body.tool_response,\n toolUseId: typeof body.tool_use_id === \"string\" ? body.tool_use_id : undefined,\n payload: body,\n ...(runnerCorrelationId ? { runnerCorrelationId } : {}),\n };\n\n await eventBus.publish(hookEvent);\n\n if (!runnerCorrelationId) {\n const derived = mapClaudeCodeHookToAgentEvents(hookEvent);\n for (const e of derived) {\n await eventBus.publish(e);\n }\n }\n\n return c.json({ ok: true });\n });\n\n return app;\n}\n"],"mappings":"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","names":["Hono","Hono","Hono","Hono","Hono","Hono","Hono"]}
package/package.json ADDED
@@ -0,0 +1,71 @@
1
+ {
2
+ "name": "@agentic-patterns/server",
3
+ "version": "0.1.0",
4
+ "description": "Hono HTTP server for agentic-patterns agents — routes, SSE streaming, admin API",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/pattern-stack/agentic-patterns-ts.git",
10
+ "directory": "packages/agent-server"
11
+ },
12
+ "engines": {
13
+ "node": ">=20"
14
+ },
15
+ "publishConfig": {
16
+ "access": "public"
17
+ },
18
+ "keywords": [
19
+ "agents",
20
+ "llm",
21
+ "ai",
22
+ "server",
23
+ "hono",
24
+ "sse"
25
+ ],
26
+ "homepage": "https://github.com/pattern-stack/agentic-patterns-ts",
27
+ "bugs": "https://github.com/pattern-stack/agentic-patterns-ts/issues",
28
+ "main": "./dist/index.cjs",
29
+ "module": "./dist/index.js",
30
+ "types": "./dist/index.d.ts",
31
+ "exports": {
32
+ ".": {
33
+ "import": {
34
+ "types": "./dist/index.d.ts",
35
+ "default": "./dist/index.js"
36
+ },
37
+ "require": {
38
+ "types": "./dist/index.d.cts",
39
+ "default": "./dist/index.cjs"
40
+ }
41
+ }
42
+ },
43
+ "files": [
44
+ "dist"
45
+ ],
46
+ "dependencies": {
47
+ "hono": "^4.0.0",
48
+ "@agentic-patterns/core": "0.1.0",
49
+ "@agentic-patterns/runtime": "0.1.0"
50
+ },
51
+ "devDependencies": {
52
+ "@hono/node-server": "^1.13.0",
53
+ "@types/node": "^25.6.0",
54
+ "tsup": "^8.3.0",
55
+ "tsx": "^4.21.0",
56
+ "typescript": "^5.7.0",
57
+ "vitest": "^3.0.0",
58
+ "zod": "^3.23.0"
59
+ },
60
+ "peerDependencies": {
61
+ "zod": "^3.23.0"
62
+ },
63
+ "scripts": {
64
+ "build": "tsup",
65
+ "typecheck": "tsc --noEmit",
66
+ "test": "vitest run",
67
+ "lint": "biome check src/",
68
+ "demo": "tsx examples/live-demo.ts",
69
+ "dev": "tsx --watch examples/live-demo.ts"
70
+ }
71
+ }