noumen 0.2.0 → 0.3.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.
Files changed (83) hide show
  1. package/README.md +95 -16
  2. package/dist/a2a/index.d.ts +5 -5
  3. package/dist/a2a/index.js +3 -3
  4. package/dist/a2a/index.js.map +1 -1
  5. package/dist/acp/index.d.ts +5 -5
  6. package/dist/acp/index.js +4 -4
  7. package/dist/acp/index.js.map +1 -1
  8. package/dist/{agent-BrkbZyOT.d.ts → agent-1nFVUP9E.d.ts} +319 -15
  9. package/dist/{cache-DVqaCX8v.d.ts → cache-DsRqxx6v.d.ts} +1 -1
  10. package/dist/{chunk-BGG2E6JD.js → chunk-3HEYCV26.js} +1 -1
  11. package/dist/chunk-3SK5GCI6.js +75 -0
  12. package/dist/chunk-3SK5GCI6.js.map +1 -0
  13. package/dist/{chunk-NBDFQYUZ.js → chunk-4HW6LN6D.js} +4784 -2411
  14. package/dist/chunk-4HW6LN6D.js.map +1 -0
  15. package/dist/{chunk-7ZMN7XJE.js → chunk-5JN4SPI7.js} +6 -6
  16. package/dist/chunk-5JN4SPI7.js.map +1 -0
  17. package/dist/{chunk-CPFHEPW4.js → chunk-CS6WNDCF.js} +73 -41
  18. package/dist/chunk-CS6WNDCF.js.map +1 -0
  19. package/dist/chunk-EKOGVTBT.js +472 -0
  20. package/dist/chunk-EKOGVTBT.js.map +1 -0
  21. package/dist/{chunk-KY6ZPWHO.js → chunk-HEQQQGK5.js} +47 -28
  22. package/dist/chunk-HEQQQGK5.js.map +1 -0
  23. package/dist/{chunk-QTJ7VTJY.js → chunk-HL6JCRZJ.js} +1599 -481
  24. package/dist/chunk-HL6JCRZJ.js.map +1 -0
  25. package/dist/chunk-L3L3FG5T.js +16 -0
  26. package/dist/chunk-L3L3FG5T.js.map +1 -0
  27. package/dist/cli/index.js +36 -30
  28. package/dist/cli/index.js.map +1 -1
  29. package/dist/client/index.d.ts +2 -2
  30. package/dist/{headless-Q7XHHZIW.js → headless-FFU2DESQ.js} +3 -4
  31. package/dist/headless-FFU2DESQ.js.map +1 -0
  32. package/dist/index.d.ts +218 -68
  33. package/dist/index.js +37 -23
  34. package/dist/lsp/index.d.ts +4 -4
  35. package/dist/mcp/index.d.ts +5 -5
  36. package/dist/mcp/index.js +2 -1
  37. package/dist/mcp/index.js.map +1 -1
  38. package/dist/{provider-factory-34MSWJZ3.js → provider-factory-KCLIF34X.js} +2 -2
  39. package/dist/providers/anthropic.d.ts +2 -2
  40. package/dist/providers/anthropic.js +5 -3
  41. package/dist/providers/anthropic.js.map +1 -1
  42. package/dist/providers/bedrock.d.ts +2 -2
  43. package/dist/providers/bedrock.js +5 -3
  44. package/dist/providers/bedrock.js.map +1 -1
  45. package/dist/providers/gemini.d.ts +2 -1
  46. package/dist/providers/gemini.js +133 -95
  47. package/dist/providers/gemini.js.map +1 -1
  48. package/dist/providers/ollama.d.ts +13 -0
  49. package/dist/{ollama-YNXAYP3R.js → providers/ollama.js} +6 -4
  50. package/dist/providers/ollama.js.map +1 -0
  51. package/dist/providers/openai.d.ts +4 -1
  52. package/dist/providers/openai.js +2 -1
  53. package/dist/providers/openrouter.d.ts +1 -1
  54. package/dist/providers/openrouter.js +2 -1
  55. package/dist/providers/openrouter.js.map +1 -1
  56. package/dist/providers/vertex.d.ts +4 -2
  57. package/dist/providers/vertex.js +6 -3
  58. package/dist/providers/vertex.js.map +1 -1
  59. package/dist/{resolve-XM52G7YE.js → resolve-4JA2BBDA.js} +2 -2
  60. package/dist/server/index.d.ts +35 -20
  61. package/dist/server/index.js +276 -207
  62. package/dist/server/index.js.map +1 -1
  63. package/dist/{server-Cg1yWGaV.d.ts → server-CHMxuWKq.d.ts} +1 -1
  64. package/dist/{types-DwdzmXfs.d.ts → types-CD0rUKKT.d.ts} +2 -0
  65. package/dist/{types-3c88cRKH.d.ts → types-LrU4LRmX.d.ts} +28 -0
  66. package/dist/{types-CwKKucOF.d.ts → types-RPKUTu1k.d.ts} +27 -2
  67. package/dist/uuid-RVN2T26F.js +8 -0
  68. package/dist/uuid-RVN2T26F.js.map +1 -0
  69. package/dist/zod-7YXKWYMC.js +12 -0
  70. package/dist/zod-7YXKWYMC.js.map +1 -0
  71. package/package.json +19 -13
  72. package/dist/chunk-2ZTGQLYK.js +0 -356
  73. package/dist/chunk-2ZTGQLYK.js.map +0 -1
  74. package/dist/chunk-7ZMN7XJE.js.map +0 -1
  75. package/dist/chunk-CPFHEPW4.js.map +0 -1
  76. package/dist/chunk-KY6ZPWHO.js.map +0 -1
  77. package/dist/chunk-NBDFQYUZ.js.map +0 -1
  78. package/dist/chunk-QTJ7VTJY.js.map +0 -1
  79. package/dist/headless-Q7XHHZIW.js.map +0 -1
  80. package/dist/ollama-YNXAYP3R.js.map +0 -1
  81. /package/dist/{chunk-BGG2E6JD.js.map → chunk-3HEYCV26.js.map} +0 -0
  82. /package/dist/{provider-factory-34MSWJZ3.js.map → provider-factory-KCLIF34X.js.map} +0 -0
  83. /package/dist/{resolve-XM52G7YE.js.map → resolve-4JA2BBDA.js.map} +0 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/server/index.ts"],"sourcesContent":["import { createServer as createHttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport { randomUUID } from \"node:crypto\";\nimport type { Agent } from \"../agent.js\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { PermissionResponse } from \"../permissions/types.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SSE_KEEPALIVE_INTERVAL_MS = 15_000;\nconst MAX_BODY_BYTES = 1_048_576; // 1 MB\nconst MAX_EVENT_BUFFER = 1000;\nconst DEFAULT_PENDING_TIMEOUT_MS = 120_000; // 2 minutes\nconst WS_PING_INTERVAL_MS = 30_000;\nconst SHUTDOWN_DRAIN_MS = 500;\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface ServerOptions {\n port: number;\n host?: string;\n /** Enable WebSocket transport (default true). Requires `ws` peer dependency. */\n ws?: boolean;\n auth?: AuthConfig;\n /** Maximum number of concurrent sessions (default unlimited). */\n maxSessions?: number;\n /** Automatically clean up sessions idle longer than this (ms). No timeout by default. */\n idleTimeoutMs?: number;\n /** Called on every new connection; return overrides for the session. */\n onConnection?: (info: ConnectionInfo) => MaybePromise<ConnectionOverrides>;\n onError?: (err: Error) => void;\n /** Enable CORS for browser clients (default true). */\n cors?: boolean;\n /** Timeout for pending permission/input responses before rejecting (ms). Default 120000. */\n pendingTimeoutMs?: number;\n}\n\n/**\n * Options for `createRequestHandler()` — same as `ServerOptions` but without\n * `port` / `host` / `ws` since the caller owns the HTTP server.\n */\nexport interface RequestHandlerOptions {\n auth?: AuthConfig;\n maxSessions?: number;\n idleTimeoutMs?: number;\n onConnection?: (info: ConnectionInfo) => MaybePromise<ConnectionOverrides>;\n onError?: (err: Error) => void;\n cors?: boolean;\n pendingTimeoutMs?: number;\n}\n\nexport type AuthConfig =\n | { type: \"bearer\"; token: string }\n | { type: \"custom\"; verify: (req: IncomingMessage) => MaybePromise<AuthResult | null> };\n\nexport interface AuthResult {\n [key: string]: unknown;\n}\n\nexport interface ConnectionInfo {\n auth: AuthResult;\n remoteAddress?: string;\n}\n\nexport interface ConnectionOverrides {\n cwd?: string;\n}\n\ninterface PromiseResolver<T> {\n resolve: (value: T) => void;\n reject: (err: Error) => void;\n}\n\ninterface BufferedEvent {\n seq: number;\n event: StreamEvent;\n}\n\ninterface SessionState {\n id: string;\n abortController: AbortController;\n pendingPermission: PromiseResolver<PermissionResponse> | null;\n pendingInput: PromiseResolver<string> | null;\n pendingPermissionTimer: ReturnType<typeof setTimeout> | null;\n pendingInputTimer: ReturnType<typeof setTimeout> | null;\n lastActivity: number;\n sseResponse: ServerResponse | null;\n sseKeepaliveTimer: ReturnType<typeof setInterval> | null;\n eventBuffer: BufferedEvent[];\n sequenceNum: number;\n done: boolean;\n cwd?: string;\n}\n\ntype WsWebSocket = {\n on(event: \"message\", cb: (data: Buffer | string) => void): void;\n on(event: \"close\", cb: () => void): void;\n on(event: \"error\", cb: (err: Error) => void): void;\n on(event: \"pong\", cb: () => void): void;\n send(data: string): void;\n ping(): void;\n close(): void;\n readyState: number;\n};\n\ntype WsServer = {\n on(event: \"connection\", cb: (ws: WsWebSocket, req: IncomingMessage) => void): void;\n close(cb?: () => void): void;\n};\n\n// ---------------------------------------------------------------------------\n// NoumenServer\n// ---------------------------------------------------------------------------\n\nexport class NoumenServer {\n private code: Agent;\n private options: ServerOptions;\n private httpServer: ReturnType<typeof createHttpServer> | null = null;\n private wss: WsServer | null = null;\n private sessions = new Map<string, SessionState>();\n private idleTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(code: Agent, options: ServerOptions) {\n this.code = code;\n this.options = options;\n }\n\n async start(): Promise<void> {\n this.httpServer = createHttpServer((req, res) => this.handleRequest(req, res));\n\n if (this.options.ws !== false) {\n await this.initWebSocket();\n }\n\n this.ensureIdleReaper();\n\n return new Promise<void>((resolve, reject) => {\n const host = this.options.host ?? \"0.0.0.0\";\n this.httpServer!.listen(this.options.port, host, () => resolve());\n this.httpServer!.once(\"error\", reject);\n });\n }\n\n async stop(): Promise<void> {\n if (this.idleTimer) {\n clearInterval(this.idleTimer);\n this.idleTimer = null;\n }\n\n // Signal all sessions to stop, then give a brief drain period\n for (const session of this.sessions.values()) {\n session.abortController.abort();\n }\n await new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_DRAIN_MS));\n\n for (const session of this.sessions.values()) {\n this.destroySession(session);\n }\n\n if (this.wss) {\n await new Promise<void>((resolve) => this.wss!.close(() => resolve()));\n this.wss = null;\n }\n\n if (this.httpServer) {\n if (typeof (this.httpServer as any).closeAllConnections === \"function\") {\n (this.httpServer as any).closeAllConnections();\n }\n await new Promise<void>((resolve, reject) =>\n this.httpServer!.close((err) => (err ? reject(err) : resolve())),\n );\n this.httpServer = null;\n }\n }\n\n getActiveSessions(): Map<string, { id: string; lastActivity: number; done: boolean }> {\n const result = new Map<string, { id: string; lastActivity: number; done: boolean }>();\n for (const [id, s] of this.sessions) {\n result.set(id, { id: s.id, lastActivity: s.lastActivity, done: s.done });\n }\n return result;\n }\n\n // -------------------------------------------------------------------------\n // WebSocket setup\n // -------------------------------------------------------------------------\n\n private async initWebSocket(): Promise<void> {\n let WsServerCtor: new (opts: { server: ReturnType<typeof createHttpServer> }) => WsServer;\n try {\n const ws = await import(\"ws\");\n WsServerCtor = (ws as any).WebSocketServer ?? (ws as any).default?.WebSocketServer;\n } catch {\n throw new Error(\n \"noumen/server: WebSocket support requires the 'ws' package. \" +\n \"Install it with: npm install ws\\n\" +\n \"Or disable WebSocket with { ws: false } in ServerOptions.\",\n );\n }\n\n this.wss = new WsServerCtor({ server: this.httpServer! });\n this.wss.on(\"connection\", (ws, req) => {\n this.handleWsConnection(ws, req).catch((err) =>\n this.options.onError?.(err instanceof Error ? err : new Error(String(err))),\n );\n });\n }\n\n /**\n * Handle an HTTP request. Used internally by `start()` and exposed for\n * `createRequestHandler()` so the same logic can be mounted on an\n * external Express / Fastify / Hono server.\n */\n async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n this.ensureIdleReaper();\n return this.handleHttp(req, res).catch((err) => {\n this.options.onError?.(err instanceof Error ? err : new Error(String(err)));\n if (!res.headersSent) jsonResponse(res, 500, { error: \"Internal server error\" });\n });\n }\n\n private idleReaperStarted = false;\n\n private ensureIdleReaper(): void {\n if (this.idleReaperStarted || !this.options.idleTimeoutMs) return;\n this.idleReaperStarted = true;\n const interval = Math.max(this.options.idleTimeoutMs / 2, 1000);\n this.idleTimer = setInterval(() => this.reapIdleSessions(), interval);\n this.idleTimer.unref();\n }\n\n // -------------------------------------------------------------------------\n // HTTP routing\n // -------------------------------------------------------------------------\n\n private async handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (this.options.cors !== false) {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, Last-Event-ID\");\n }\n\n const method = req.method ?? \"GET\";\n\n if (method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const path = url.pathname;\n\n if (path === \"/health\" && method === \"GET\") {\n return jsonResponse(res, 200, { status: \"ok\", sessions: this.sessions.size });\n }\n\n if (this.options.auth) {\n const authResult = await this.authenticate(req);\n if (!authResult) {\n return jsonResponse(res, 401, { error: \"Unauthorized\" });\n }\n }\n\n if (path === \"/sessions\" && method === \"POST\") {\n return this.handleCreateSession(req, res);\n }\n\n if (path === \"/sessions\" && method === \"GET\") {\n return this.handleListSessions(res);\n }\n\n const sessionMatch = path.match(/^\\/sessions\\/([^/]+)(?:\\/(.+))?$/);\n if (sessionMatch) {\n const sessionId = sessionMatch[1];\n const sub = sessionMatch[2] ?? \"\";\n\n if (sub === \"events\" && method === \"GET\") return this.handleSseStream(sessionId, req, res);\n if (sub === \"permissions\" && method === \"POST\") return this.handlePermissionResponse(sessionId, req, res);\n if (sub === \"input\" && method === \"POST\") return this.handleInputResponse(sessionId, req, res);\n if (sub === \"messages\" && method === \"POST\") return this.handleSendMessage(sessionId, req, res);\n if (sub === \"\" && method === \"DELETE\") return this.handleDeleteSession(sessionId, res);\n }\n\n jsonResponse(res, 404, { error: \"Not found\" });\n }\n\n // -------------------------------------------------------------------------\n // Auth\n // -------------------------------------------------------------------------\n\n private async authenticate(req: IncomingMessage): Promise<AuthResult | null> {\n const auth = this.options.auth;\n if (!auth) return {};\n\n if (auth.type === \"bearer\") {\n const header = req.headers.authorization;\n if (header === `Bearer ${auth.token}`) return {};\n return null;\n }\n\n return auth.verify(req);\n }\n\n // -------------------------------------------------------------------------\n // REST handlers\n // -------------------------------------------------------------------------\n\n private async handleCreateSession(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const body = await readBody(req);\n const { prompt, sessionId: requestedId } = body as { prompt?: string; sessionId?: string };\n\n if (!prompt || typeof prompt !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: prompt\" });\n }\n\n if (this.options.maxSessions && this.sessions.size >= this.options.maxSessions) {\n return jsonResponse(res, 429, { error: \"Maximum sessions reached\" });\n }\n\n const overrides = await this.resolveConnectionOverrides(req);\n const session = this.createSessionState(requestedId, overrides);\n\n this.runAgentSse(session, prompt, false);\n\n jsonResponse(res, 201, {\n sessionId: session.id,\n eventsUrl: `/sessions/${session.id}/events`,\n });\n }\n\n private handleListSessions(res: ServerResponse): void {\n const sessions = Array.from(this.sessions.values()).map((s) => ({\n id: s.id,\n lastActivity: s.lastActivity,\n done: s.done,\n }));\n jsonResponse(res, 200, sessions);\n }\n\n private handleSseStream(sessionId: string, req: IncomingMessage, res: ServerResponse): void {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n\n // Handle subscriber conflict: notify the old listener before replacing\n if (session.sseResponse) {\n const oldRes = session.sseResponse;\n writeSseEventRaw(oldRes, session.sequenceNum + 1, { type: \"subscriber_replaced\" });\n oldRes.end();\n this.clearSseKeepalive(session);\n session.sseResponse = null;\n }\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n });\n\n // Support Last-Event-ID for resumption after reconnect\n const lastEventId = req.headers[\"last-event-id\"] as string | undefined;\n const resumeAfterSeq = lastEventId ? parseInt(lastEventId, 10) : 0;\n\n for (const buffered of session.eventBuffer) {\n if (resumeAfterSeq && buffered.seq <= resumeAfterSeq) continue;\n writeSseEventRaw(res, buffered.seq, serializeEvent(buffered.event));\n }\n session.eventBuffer = [];\n session.sseResponse = res;\n\n // Start keepalive interval\n this.startSseKeepalive(session);\n\n res.on(\"close\", () => {\n if (session.sseResponse === res) {\n this.clearSseKeepalive(session);\n session.sseResponse = null;\n }\n });\n }\n\n private async handlePermissionResponse(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.pendingPermission) return jsonResponse(res, 409, { error: \"No pending permission request\" });\n\n const body = (await readBody(req)) as PermissionResponse;\n this.clearPendingPermissionTimer(session);\n session.pendingPermission.resolve(body);\n session.pendingPermission = null;\n jsonResponse(res, 200, { ok: true });\n }\n\n private async handleInputResponse(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.pendingInput) return jsonResponse(res, 409, { error: \"No pending input request\" });\n\n const body = (await readBody(req)) as { answer?: string };\n if (typeof body.answer !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: answer\" });\n }\n\n this.clearPendingInputTimer(session);\n session.pendingInput.resolve(body.answer);\n session.pendingInput = null;\n jsonResponse(res, 200, { ok: true });\n }\n\n private async handleSendMessage(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.done) return jsonResponse(res, 409, { error: \"Session is still running\" });\n\n const body = (await readBody(req)) as { prompt?: string };\n if (!body.prompt || typeof body.prompt !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: prompt\" });\n }\n\n session.done = false;\n session.abortController = new AbortController();\n this.runAgentSse(session, body.prompt, true);\n jsonResponse(res, 200, { ok: true });\n }\n\n private handleDeleteSession(sessionId: string, res: ServerResponse): void {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n this.destroySession(session);\n jsonResponse(res, 200, { ok: true });\n }\n\n // -------------------------------------------------------------------------\n // WebSocket handling\n // -------------------------------------------------------------------------\n\n private async handleWsConnection(ws: WsWebSocket, req: IncomingMessage): Promise<void> {\n if (this.options.auth) {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const tokenParam = url.searchParams.get(\"token\");\n if (tokenParam && this.options.auth.type === \"bearer\") {\n if (tokenParam !== this.options.auth.token) {\n ws.close();\n return;\n }\n } else {\n const authResult = await this.authenticate(req);\n if (!authResult) {\n ws.close();\n return;\n }\n }\n }\n\n const wsSessions = new Set<string>();\n\n // Ping/pong health check\n let pongReceived = true;\n const pingTimer = setInterval(() => {\n if (!pongReceived) {\n ws.close();\n return;\n }\n pongReceived = false;\n try { ws.ping(); } catch { /* connection may already be closing */ }\n }, WS_PING_INTERVAL_MS);\n\n ws.on(\"pong\", () => { pongReceived = true; });\n\n ws.on(\"message\", async (raw) => {\n try {\n const msg = JSON.parse(typeof raw === \"string\" ? raw : raw.toString());\n await this.handleWsMessage(ws, msg, wsSessions, req);\n } catch (err) {\n wsSend(ws, { type: \"error\", error: String(err) });\n }\n });\n\n ws.on(\"close\", () => {\n clearInterval(pingTimer);\n for (const sid of wsSessions) {\n const session = this.sessions.get(sid);\n if (session) this.destroySession(session);\n }\n });\n\n ws.on(\"error\", () => {\n clearInterval(pingTimer);\n });\n }\n\n private async handleWsMessage(\n ws: WsWebSocket,\n msg: Record<string, unknown>,\n wsSessions: Set<string>,\n req: IncomingMessage,\n ): Promise<void> {\n const msgType = msg.type as string;\n\n if (msgType === \"run\") {\n if (this.options.maxSessions && this.sessions.size >= this.options.maxSessions) {\n wsSend(ws, { type: \"error\", error: \"Maximum sessions reached\" });\n return;\n }\n const overrides = await this.resolveConnectionOverrides(req);\n const session = this.createSessionState(msg.sessionId as string | undefined, overrides);\n wsSessions.add(session.id);\n wsSend(ws, { type: \"session_created\", sessionId: session.id });\n this.runAgentWs(session, msg.prompt as string, ws, false);\n return;\n }\n\n if (msgType === \"message\") {\n const session = this.sessions.get(msg.sessionId as string);\n if (!session) { wsSend(ws, { type: \"error\", error: \"Session not found\" }); return; }\n if (!session.done) { wsSend(ws, { type: \"error\", error: \"Session is still running\" }); return; }\n session.done = false;\n session.abortController = new AbortController();\n this.runAgentWs(session, msg.prompt as string, ws, true);\n return;\n }\n\n if (msgType === \"permission_response\") {\n const session = this.sessions.get(msg.sessionId as string);\n if (!session?.pendingPermission) return;\n this.clearPendingPermissionTimer(session);\n const { sessionId: _sid, type: _type, ...response } = msg;\n session.pendingPermission.resolve(response as unknown as PermissionResponse);\n session.pendingPermission = null;\n return;\n }\n\n if (msgType === \"input_response\") {\n const session = this.sessions.get(msg.sessionId as string);\n if (!session?.pendingInput) return;\n this.clearPendingInputTimer(session);\n session.pendingInput.resolve((msg.answer as string) ?? \"\");\n session.pendingInput = null;\n return;\n }\n\n if (msgType === \"abort\") {\n const session = this.sessions.get(msg.sessionId as string);\n if (session) this.destroySession(session);\n }\n }\n\n // -------------------------------------------------------------------------\n // Session management\n // -------------------------------------------------------------------------\n\n private createSessionState(\n requestedId: string | undefined,\n overrides: ConnectionOverrides,\n ): SessionState {\n const sessionId = requestedId ?? randomUUID();\n\n const session: SessionState = {\n id: sessionId,\n abortController: new AbortController(),\n pendingPermission: null,\n pendingInput: null,\n pendingPermissionTimer: null,\n pendingInputTimer: null,\n lastActivity: Date.now(),\n sseResponse: null,\n sseKeepaliveTimer: null,\n eventBuffer: [],\n sequenceNum: 0,\n done: false,\n cwd: overrides.cwd,\n };\n\n this.sessions.set(sessionId, session);\n return session;\n }\n\n private makeThread(session: SessionState, resume: boolean) {\n const handlers = {\n cwd: session.cwd,\n permissionHandler: (req: import(\"../permissions/types.js\").PermissionRequest) =>\n this.bridgePermission(session.id, req),\n userInputHandler: (q: string) =>\n this.bridgeUserInput(session.id, q),\n };\n\n return resume\n ? this.code.resumeThread(session.id, handlers)\n : this.code.createThread({ sessionId: session.id, ...handlers });\n }\n\n private runAgentSse(session: SessionState, prompt: string, resume: boolean): void {\n const run = async () => {\n try {\n const thread = this.makeThread(session, resume);\n for await (const event of thread.run(prompt, { signal: session.abortController.signal })) {\n this.emitSseEvent(session, event);\n session.lastActivity = Date.now();\n }\n } catch (err) {\n if ((err as Error).name !== \"AbortError\") {\n this.emitSseEvent(session, {\n type: \"error\",\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n } finally {\n session.done = true;\n }\n };\n run().catch((err) => this.options.onError?.(err instanceof Error ? err : new Error(String(err))));\n }\n\n private runAgentWs(session: SessionState, prompt: string, ws: WsWebSocket, resume: boolean): void {\n const run = async () => {\n try {\n const thread = this.makeThread(session, resume);\n for await (const event of thread.run(prompt, { signal: session.abortController.signal })) {\n session.sequenceNum++;\n wsSend(ws, { ...serializeEvent(event), sessionId: session.id, seq: session.sequenceNum });\n session.lastActivity = Date.now();\n }\n } catch (err) {\n if ((err as Error).name !== \"AbortError\") {\n wsSend(ws, { type: \"error\", sessionId: session.id, error: String(err) });\n }\n } finally {\n session.done = true;\n }\n };\n run().catch((err) => this.options.onError?.(err instanceof Error ? err : new Error(String(err))));\n }\n\n private emitSseEvent(session: SessionState, event: StreamEvent): void {\n session.sequenceNum++;\n const seq = session.sequenceNum;\n\n if (session.sseResponse) {\n writeSseEventRaw(session.sseResponse, seq, serializeEvent(event));\n } else {\n // Buffer with cap — drop oldest if full\n if (session.eventBuffer.length >= MAX_EVENT_BUFFER) {\n session.eventBuffer.shift();\n }\n session.eventBuffer.push({ seq, event });\n }\n }\n\n private bridgePermission(\n sessionId: string,\n _request: import(\"../permissions/types.js\").PermissionRequest,\n ): Promise<PermissionResponse> {\n const session = this.sessions.get(sessionId);\n if (!session) return Promise.reject(new Error(\"Session not found\"));\n const timeoutMs = this.options.pendingTimeoutMs ?? DEFAULT_PENDING_TIMEOUT_MS;\n return new Promise<PermissionResponse>((resolve, reject) => {\n session.pendingPermission = { resolve, reject };\n session.pendingPermissionTimer = setTimeout(() => {\n session.pendingPermissionTimer = null;\n if (session.pendingPermission) {\n session.pendingPermission.reject(new Error(\"Permission request timed out\"));\n session.pendingPermission = null;\n }\n }, timeoutMs);\n });\n }\n\n private bridgeUserInput(sessionId: string, _question: string): Promise<string> {\n const session = this.sessions.get(sessionId);\n if (!session) return Promise.reject(new Error(\"Session not found\"));\n const timeoutMs = this.options.pendingTimeoutMs ?? DEFAULT_PENDING_TIMEOUT_MS;\n return new Promise<string>((resolve, reject) => {\n session.pendingInput = { resolve, reject };\n session.pendingInputTimer = setTimeout(() => {\n session.pendingInputTimer = null;\n if (session.pendingInput) {\n session.pendingInput.reject(new Error(\"User input request timed out\"));\n session.pendingInput = null;\n }\n }, timeoutMs);\n });\n }\n\n private startSseKeepalive(session: SessionState): void {\n this.clearSseKeepalive(session);\n session.sseKeepaliveTimer = setInterval(() => {\n if (session.sseResponse && !session.sseResponse.destroyed) {\n session.sseResponse.write(\":keepalive\\n\\n\");\n }\n }, SSE_KEEPALIVE_INTERVAL_MS);\n session.sseKeepaliveTimer.unref();\n }\n\n private clearSseKeepalive(session: SessionState): void {\n if (session.sseKeepaliveTimer) {\n clearInterval(session.sseKeepaliveTimer);\n session.sseKeepaliveTimer = null;\n }\n }\n\n private clearPendingPermissionTimer(session: SessionState): void {\n if (session.pendingPermissionTimer) {\n clearTimeout(session.pendingPermissionTimer);\n session.pendingPermissionTimer = null;\n }\n }\n\n private clearPendingInputTimer(session: SessionState): void {\n if (session.pendingInputTimer) {\n clearTimeout(session.pendingInputTimer);\n session.pendingInputTimer = null;\n }\n }\n\n private destroySession(session: SessionState): void {\n session.abortController.abort();\n this.clearSseKeepalive(session);\n this.clearPendingPermissionTimer(session);\n this.clearPendingInputTimer(session);\n if (session.pendingPermission) {\n session.pendingPermission.reject(new Error(\"Session aborted\"));\n session.pendingPermission = null;\n }\n if (session.pendingInput) {\n session.pendingInput.reject(new Error(\"Session aborted\"));\n session.pendingInput = null;\n }\n if (session.sseResponse) {\n session.sseResponse.end();\n session.sseResponse = null;\n }\n this.sessions.delete(session.id);\n }\n\n private reapIdleSessions(): void {\n const timeout = this.options.idleTimeoutMs;\n if (!timeout) return;\n const now = Date.now();\n for (const session of this.sessions.values()) {\n if (now - session.lastActivity > timeout) {\n this.destroySession(session);\n }\n }\n }\n\n private async resolveConnectionOverrides(req: IncomingMessage): Promise<ConnectionOverrides> {\n if (!this.options.onConnection) return {};\n const auth = (await this.authenticate(req)) ?? {};\n return this.options.onConnection({ auth, remoteAddress: req.socket.remoteAddress });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createServer(code: Agent, options: ServerOptions): NoumenServer {\n return new NoumenServer(code, options);\n}\n\n/**\n * Create a `(req, res)` handler that can be mounted on any Node HTTP\n * framework (Express, Fastify, Hono, bare `http.createServer`, etc.).\n *\n * ```ts\n * import express from \"express\";\n * import { createRequestHandler } from \"noumen/server\";\n *\n * const app = express();\n * app.use(\"/agent\", createRequestHandler(code, { auth: { type: \"bearer\", token: \"...\" } }));\n * ```\n *\n * WebSocket is not supported in middleware mode — use `createServer()` for WS.\n */\nexport function createRequestHandler(\n code: Agent,\n options?: RequestHandlerOptions,\n): (req: IncomingMessage, res: ServerResponse) => void {\n const serverOpts: ServerOptions = {\n port: 0,\n ws: false,\n ...options,\n };\n const server = new NoumenServer(code, serverOpts);\n return (req, res) => { server.handleRequest(req, res); };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction jsonResponse(res: ServerResponse, status: number, body: unknown): void {\n const json = JSON.stringify(body);\n res.writeHead(status, {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(json),\n });\n res.end(json);\n}\n\n/**\n * Serialize a StreamEvent to a JSON-safe object. Error instances are\n * converted to `{ message, name }` since `JSON.stringify(new Error())`\n * produces `{}`.\n */\nfunction serializeEvent(event: StreamEvent): Record<string, unknown> {\n if (event.type === \"error\") {\n return { type: \"error\", error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_exhausted\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_attempt\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n return event as unknown as Record<string, unknown>;\n}\n\nfunction writeSseEventRaw(res: ServerResponse, seq: number, data: Record<string, unknown>): void {\n res.write(`id: ${seq}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n}\n\nfunction readBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let totalBytes = 0;\n let rejected = false;\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => {\n if (rejected) return;\n totalBytes += chunk.length;\n if (totalBytes > MAX_BODY_BYTES) {\n rejected = true;\n req.destroy();\n reject(new Error(\"Request body too large\"));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => {\n if (rejected) return;\n try {\n const raw = Buffer.concat(chunks).toString();\n resolve(raw ? JSON.parse(raw) : {});\n } catch (err) {\n reject(err);\n }\n });\n req.on(\"error\", (err) => {\n if (!rejected) reject(err);\n });\n });\n}\n\nfunction wsSend(ws: WsWebSocket, data: unknown): void {\n if (ws.readyState === 1) ws.send(JSON.stringify(data));\n}\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../../src/server/index.ts","../../src/server/session-state.ts","../../src/server/event-buffer.ts","../../src/server/ws-dispatch.ts"],"sourcesContent":["import { createServer as createHttpServer, type IncomingMessage, type ServerResponse } from \"node:http\";\nimport type { Agent } from \"../agent.js\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { PermissionResponse } from \"../permissions/types.js\";\n\nimport {\n type SessionState,\n type ConnectionOverrides,\n DEFAULT_PENDING_TIMEOUT_MS,\n createSessionState,\n destroySession,\n reapIdleSessions,\n bridgePermission,\n bridgeUserInput,\n clearPendingPermissionTimer,\n clearPendingInputTimer,\n clearSseKeepalive,\n} from \"./session-state.js\";\n\nimport {\n MAX_EVENT_BUFFER,\n serializeEvent,\n pushEvent,\n getBufferedEventsAfter,\n writeSseEventRaw,\n} from \"./event-buffer.js\";\n\nimport {\n type WsWebSocket,\n type WsDispatchCallbacks,\n handleWsMessage as dispatchWsMessage,\n parseWsMessage,\n wsSend,\n} from \"./ws-dispatch.js\";\n\ntype MaybePromise<T> = T | Promise<T>;\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\nconst SSE_KEEPALIVE_INTERVAL_MS = 15_000;\nconst MAX_BODY_BYTES = 1_048_576; // 1 MB\nconst SHUTDOWN_DRAIN_MS = 500;\nconst WS_PING_INTERVAL_MS = 30_000;\n\n// ---------------------------------------------------------------------------\n// Public types\n// ---------------------------------------------------------------------------\n\nexport interface ServerOptions {\n port: number;\n host?: string;\n /** Enable WebSocket transport (default true). Requires `ws` peer dependency. */\n ws?: boolean;\n auth?: AuthConfig;\n /** Maximum number of concurrent sessions (default unlimited). */\n maxSessions?: number;\n /** Automatically clean up sessions idle longer than this (ms). No timeout by default. */\n idleTimeoutMs?: number;\n /** Called on every new connection; return overrides for the session. */\n onConnection?: (info: ConnectionInfo) => MaybePromise<ConnectionOverrides>;\n onError?: (err: Error) => void;\n /** Enable CORS for browser clients (default true). */\n cors?: boolean;\n /** Timeout for pending permission/input responses before rejecting (ms). Default 120000. */\n pendingTimeoutMs?: number;\n}\n\n/**\n * Options for `createRequestHandler()` — same as `ServerOptions` but without\n * `port` / `host` / `ws` since the caller owns the HTTP server.\n */\nexport interface RequestHandlerOptions {\n auth?: AuthConfig;\n maxSessions?: number;\n idleTimeoutMs?: number;\n onConnection?: (info: ConnectionInfo) => MaybePromise<ConnectionOverrides>;\n onError?: (err: Error) => void;\n cors?: boolean;\n pendingTimeoutMs?: number;\n}\n\nexport type AuthConfig =\n | { type: \"bearer\"; token: string }\n | { type: \"custom\"; verify: (req: IncomingMessage) => MaybePromise<AuthResult | null> };\n\nexport interface AuthResult {\n [key: string]: unknown;\n}\n\nexport interface ConnectionInfo {\n auth: AuthResult;\n remoteAddress?: string;\n}\n\n// Re-export types that consumers might need\nexport type { ConnectionOverrides, SessionState, BufferedEvent, PromiseResolver } from \"./session-state.js\";\n\ntype WsServer = {\n on(event: \"connection\", cb: (ws: WsWebSocket, req: IncomingMessage) => void): void;\n close(cb?: () => void): void;\n};\n\n// ---------------------------------------------------------------------------\n// NoumenServer\n// ---------------------------------------------------------------------------\n\nexport class NoumenServer {\n private code: Agent;\n private options: ServerOptions;\n private httpServer: ReturnType<typeof createHttpServer> | null = null;\n private wss: WsServer | null = null;\n private sessions = new Map<string, SessionState>();\n private idleTimer: ReturnType<typeof setInterval> | null = null;\n\n constructor(code: Agent, options: ServerOptions) {\n this.code = code;\n this.options = options;\n }\n\n async start(): Promise<void> {\n this.httpServer = createHttpServer((req, res) => this.handleRequest(req, res));\n\n if (this.options.ws !== false) {\n await this.initWebSocket();\n }\n\n this.ensureIdleReaper();\n\n return new Promise<void>((resolve, reject) => {\n const host = this.options.host ?? \"127.0.0.1\";\n this.httpServer!.listen(this.options.port, host, () => resolve());\n this.httpServer!.once(\"error\", reject);\n });\n }\n\n async stop(): Promise<void> {\n if (this.idleTimer) {\n clearInterval(this.idleTimer);\n this.idleTimer = null;\n }\n\n for (const session of this.sessions.values()) {\n session.abortController.abort();\n }\n await new Promise<void>((resolve) => setTimeout(resolve, SHUTDOWN_DRAIN_MS));\n\n for (const session of this.sessions.values()) {\n destroySession(this.sessions, session);\n }\n\n if (this.wss) {\n await new Promise<void>((resolve) => this.wss!.close(() => resolve()));\n this.wss = null;\n }\n\n if (this.httpServer) {\n if (typeof (this.httpServer as any).closeAllConnections === \"function\") {\n (this.httpServer as any).closeAllConnections();\n }\n await new Promise<void>((resolve, reject) =>\n this.httpServer!.close((err) => (err ? reject(err) : resolve())),\n );\n this.httpServer = null;\n }\n }\n\n getActiveSessions(): Map<string, { id: string; lastActivity: number; done: boolean }> {\n const result = new Map<string, { id: string; lastActivity: number; done: boolean }>();\n for (const [id, s] of this.sessions) {\n result.set(id, { id: s.id, lastActivity: s.lastActivity, done: s.done });\n }\n return result;\n }\n\n // -------------------------------------------------------------------------\n // WebSocket setup\n // -------------------------------------------------------------------------\n\n private async initWebSocket(): Promise<void> {\n let WsServerCtor: new (opts: { server: ReturnType<typeof createHttpServer> }) => WsServer;\n try {\n const ws = await import(\"ws\");\n WsServerCtor = (ws as any).WebSocketServer ?? (ws as any).default?.WebSocketServer;\n } catch {\n throw new Error(\n \"noumen/server: WebSocket support requires the 'ws' package. \" +\n \"Install it with: npm install ws\\n\" +\n \"Or disable WebSocket with { ws: false } in ServerOptions.\",\n );\n }\n\n this.wss = new WsServerCtor({ server: this.httpServer! });\n this.wss.on(\"connection\", (ws, req) => {\n this.handleWsConnection(ws, req).catch((err) =>\n this.options.onError?.(err instanceof Error ? err : new Error(String(err))),\n );\n });\n }\n\n /**\n * Handle an HTTP request. Used internally by `start()` and exposed for\n * `createRequestHandler()` so the same logic can be mounted on an\n * external Express / Fastify / Hono server.\n */\n async handleRequest(req: IncomingMessage, res: ServerResponse): Promise<void> {\n this.ensureIdleReaper();\n return this.handleHttp(req, res).catch((err) => {\n this.options.onError?.(err instanceof Error ? err : new Error(String(err)));\n if (!res.headersSent) jsonResponse(res, 500, { error: \"Internal server error\" });\n });\n }\n\n private idleReaperStarted = false;\n\n private ensureIdleReaper(): void {\n if (this.idleReaperStarted || !this.options.idleTimeoutMs) return;\n this.idleReaperStarted = true;\n const interval = Math.max(this.options.idleTimeoutMs / 2, 1000);\n this.idleTimer = setInterval(() => reapIdleSessions(this.sessions, this.options.idleTimeoutMs), interval);\n this.idleTimer.unref();\n }\n\n // -------------------------------------------------------------------------\n // HTTP routing\n // -------------------------------------------------------------------------\n\n private async handleHttp(req: IncomingMessage, res: ServerResponse): Promise<void> {\n if (this.options.cors !== false) {\n res.setHeader(\"Access-Control-Allow-Origin\", \"*\");\n res.setHeader(\"Access-Control-Allow-Methods\", \"GET, POST, DELETE, OPTIONS\");\n res.setHeader(\"Access-Control-Allow-Headers\", \"Content-Type, Authorization, Last-Event-ID\");\n }\n\n const method = req.method ?? \"GET\";\n\n if (method === \"OPTIONS\") {\n res.writeHead(204);\n res.end();\n return;\n }\n\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const path = url.pathname;\n\n if (path === \"/health\" && method === \"GET\") {\n return jsonResponse(res, 200, { status: \"ok\", sessions: this.sessions.size });\n }\n\n if (this.options.auth) {\n const authResult = await this.authenticate(req);\n if (!authResult) {\n return jsonResponse(res, 401, { error: \"Unauthorized\" });\n }\n }\n\n if (path === \"/sessions\" && method === \"POST\") {\n return this.handleCreateSession(req, res);\n }\n\n if (path === \"/sessions\" && method === \"GET\") {\n return this.handleListSessions(res);\n }\n\n const sessionMatch = path.match(/^\\/sessions\\/([^/]+)(?:\\/(.+))?$/);\n if (sessionMatch) {\n const sessionId = sessionMatch[1];\n const sub = sessionMatch[2] ?? \"\";\n\n if (sub === \"events\" && method === \"GET\") return this.handleSseStream(sessionId, req, res);\n if (sub === \"permissions\" && method === \"POST\") return this.handlePermissionResponse(sessionId, req, res);\n if (sub === \"input\" && method === \"POST\") return this.handleInputResponse(sessionId, req, res);\n if (sub === \"messages\" && method === \"POST\") return this.handleSendMessage(sessionId, req, res);\n if (sub === \"\" && method === \"DELETE\") return this.handleDeleteSession(sessionId, res);\n }\n\n jsonResponse(res, 404, { error: \"Not found\" });\n }\n\n // -------------------------------------------------------------------------\n // Auth\n // -------------------------------------------------------------------------\n\n private async authenticate(req: IncomingMessage): Promise<AuthResult | null> {\n const auth = this.options.auth;\n if (!auth) return {};\n\n if (auth.type === \"bearer\") {\n const header = req.headers.authorization;\n if (header === `Bearer ${auth.token}`) return {};\n return null;\n }\n\n return auth.verify(req);\n }\n\n // -------------------------------------------------------------------------\n // REST handlers\n // -------------------------------------------------------------------------\n\n private async handleCreateSession(req: IncomingMessage, res: ServerResponse): Promise<void> {\n const body = await readBody(req);\n const { prompt, sessionId: requestedId } = body as { prompt?: string; sessionId?: string };\n\n if (!prompt || typeof prompt !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: prompt\" });\n }\n\n if (this.options.maxSessions && this.sessions.size >= this.options.maxSessions) {\n return jsonResponse(res, 429, { error: \"Maximum sessions reached\" });\n }\n\n const overrides = await this.resolveConnectionOverrides(req);\n const session = createSessionState(this.sessions, requestedId, overrides);\n\n this.runAgentSse(session, prompt, false);\n\n jsonResponse(res, 201, {\n sessionId: session.id,\n eventsUrl: `/sessions/${session.id}/events`,\n });\n }\n\n private handleListSessions(res: ServerResponse): void {\n const sessions = Array.from(this.sessions.values()).map((s) => ({\n id: s.id,\n lastActivity: s.lastActivity,\n done: s.done,\n }));\n jsonResponse(res, 200, sessions);\n }\n\n private handleSseStream(sessionId: string, req: IncomingMessage, res: ServerResponse): void {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n\n if (session.sseResponse) {\n const oldRes = session.sseResponse;\n writeSseEventRaw(oldRes, session.sequenceNum + 1, { type: \"subscriber_replaced\" });\n oldRes.end();\n clearSseKeepalive(session);\n session.sseResponse = null;\n }\n\n res.writeHead(200, {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n \"Connection\": \"keep-alive\",\n \"X-Accel-Buffering\": \"no\",\n });\n\n const lastEventId = req.headers[\"last-event-id\"] as string | undefined;\n const resumeAfterSeq = lastEventId ? parseInt(lastEventId, 10) : 0;\n\n const eventsToReplay = getBufferedEventsAfter(session.eventBuffer, resumeAfterSeq);\n for (const buffered of eventsToReplay) {\n writeSseEventRaw(res, buffered.seq, serializeEvent(buffered.event));\n }\n session.eventBuffer = [];\n session.sseResponse = res;\n\n this.startSseKeepalive(session);\n\n res.on(\"close\", () => {\n if (session.sseResponse === res) {\n clearSseKeepalive(session);\n session.sseResponse = null;\n }\n });\n }\n\n private async handlePermissionResponse(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.pendingPermission) return jsonResponse(res, 409, { error: \"No pending permission request\" });\n\n const body = (await readBody(req)) as PermissionResponse;\n clearPendingPermissionTimer(session);\n session.pendingPermission.resolve(body);\n session.pendingPermission = null;\n jsonResponse(res, 200, { ok: true });\n }\n\n private async handleInputResponse(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.pendingInput) return jsonResponse(res, 409, { error: \"No pending input request\" });\n\n const body = (await readBody(req)) as { answer?: string };\n if (typeof body.answer !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: answer\" });\n }\n\n clearPendingInputTimer(session);\n session.pendingInput.resolve(body.answer);\n session.pendingInput = null;\n jsonResponse(res, 200, { ok: true });\n }\n\n private async handleSendMessage(\n sessionId: string,\n req: IncomingMessage,\n res: ServerResponse,\n ): Promise<void> {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n if (!session.done) return jsonResponse(res, 409, { error: \"Session is still running\" });\n\n const body = (await readBody(req)) as { prompt?: string };\n if (!body.prompt || typeof body.prompt !== \"string\") {\n return jsonResponse(res, 400, { error: \"Missing required field: prompt\" });\n }\n\n session.done = false;\n session.abortController = new AbortController();\n this.runAgentSse(session, body.prompt, true);\n jsonResponse(res, 200, { ok: true });\n }\n\n private handleDeleteSession(sessionId: string, res: ServerResponse): void {\n const session = this.sessions.get(sessionId);\n if (!session) return jsonResponse(res, 404, { error: \"Session not found\" });\n destroySession(this.sessions, session);\n jsonResponse(res, 200, { ok: true });\n }\n\n // -------------------------------------------------------------------------\n // WebSocket handling\n // -------------------------------------------------------------------------\n\n private async handleWsConnection(ws: WsWebSocket, req: IncomingMessage): Promise<void> {\n if (this.options.auth) {\n const url = new URL(req.url ?? \"/\", `http://${req.headers.host ?? \"localhost\"}`);\n const tokenParam = url.searchParams.get(\"token\");\n if (tokenParam && this.options.auth.type === \"bearer\") {\n if (tokenParam !== this.options.auth.token) {\n ws.close();\n return;\n }\n } else {\n const authResult = await this.authenticate(req);\n if (!authResult) {\n ws.close();\n return;\n }\n }\n }\n\n const wsSessions = new Set<string>();\n\n let pongReceived = true;\n const pingTimer = setInterval(() => {\n if (!pongReceived) {\n ws.close();\n return;\n }\n pongReceived = false;\n try { ws.ping(); } catch { /* connection may already be closing */ }\n }, WS_PING_INTERVAL_MS);\n\n ws.on(\"pong\", () => { pongReceived = true; });\n\n const callbacks: WsDispatchCallbacks = {\n onRun: async (prompt, requestedSessionId) => {\n const overrides = await this.resolveConnectionOverrides(req);\n const session = createSessionState(this.sessions, requestedSessionId, overrides);\n wsSessions.add(session.id);\n this.runAgentWs(session, prompt, ws, false);\n return session.id;\n },\n onMessage: (sessionId, prompt) => {\n const session = this.sessions.get(sessionId);\n if (!session) { wsSend(ws, { type: \"error\", error: \"Session not found\" }); return; }\n if (!session.done) { wsSend(ws, { type: \"error\", error: \"Session is still running\" }); return; }\n session.done = false;\n session.abortController = new AbortController();\n this.runAgentWs(session, prompt, ws, true);\n },\n onPermissionResponse: (sessionId, response) => {\n const session = this.sessions.get(sessionId);\n if (!session?.pendingPermission) return;\n clearPendingPermissionTimer(session);\n session.pendingPermission.resolve(response);\n session.pendingPermission = null;\n },\n onInputResponse: (sessionId, answer) => {\n const session = this.sessions.get(sessionId);\n if (!session?.pendingInput) return;\n clearPendingInputTimer(session);\n session.pendingInput.resolve(answer);\n session.pendingInput = null;\n },\n onAbort: (sessionId) => {\n const session = this.sessions.get(sessionId);\n if (session) destroySession(this.sessions, session);\n },\n };\n\n ws.on(\"message\", async (raw) => {\n try {\n const msg = parseWsMessage(raw);\n if (!msg) { wsSend(ws, { type: \"error\", error: \"Invalid JSON\" }); return; }\n const result = await dispatchWsMessage(msg, {\n maxSessions: this.options.maxSessions,\n currentSessionCount: this.sessions.size,\n }, callbacks);\n if (result.type === \"error\") {\n wsSend(ws, { type: \"error\", error: result.error });\n } else if (result.type === \"session_created\") {\n wsSend(ws, { type: \"session_created\", sessionId: result.sessionId });\n }\n } catch (err) {\n wsSend(ws, { type: \"error\", error: String(err) });\n }\n });\n\n ws.on(\"close\", () => {\n clearInterval(pingTimer);\n for (const sid of wsSessions) {\n const session = this.sessions.get(sid);\n if (session) destroySession(this.sessions, session);\n }\n });\n\n ws.on(\"error\", () => {\n clearInterval(pingTimer);\n });\n }\n\n // -------------------------------------------------------------------------\n // Agent runners\n // -------------------------------------------------------------------------\n\n private async makeThread(session: SessionState, resume: boolean) {\n const timeoutMs = this.options.pendingTimeoutMs ?? DEFAULT_PENDING_TIMEOUT_MS;\n const handlers = {\n cwd: session.cwd,\n permissionHandler: (_req: import(\"../permissions/types.js\").PermissionRequest) =>\n bridgePermission(this.sessions, session.id, timeoutMs),\n userInputHandler: (_q: string) =>\n bridgeUserInput(this.sessions, session.id, timeoutMs),\n };\n\n return resume\n ? this.code.resumeThread(session.id, handlers)\n : this.code.createThread({ sessionId: session.id, ...handlers });\n }\n\n private runAgentSse(session: SessionState, prompt: string, resume: boolean): void {\n const run = async () => {\n try {\n const thread = await this.makeThread(session, resume);\n for await (const event of thread.run(prompt, { signal: session.abortController.signal })) {\n pushEvent(session, event);\n session.lastActivity = Date.now();\n }\n } catch (err) {\n if ((err as Error).name !== \"AbortError\") {\n pushEvent(session, {\n type: \"error\",\n error: err instanceof Error ? err : new Error(String(err)),\n });\n }\n } finally {\n session.done = true;\n }\n };\n run().catch((err) => this.options.onError?.(err instanceof Error ? err : new Error(String(err))));\n }\n\n private runAgentWs(session: SessionState, prompt: string, ws: WsWebSocket, resume: boolean): void {\n const run = async () => {\n try {\n const thread = await this.makeThread(session, resume);\n for await (const event of thread.run(prompt, { signal: session.abortController.signal })) {\n session.sequenceNum++;\n wsSend(ws, { ...serializeEvent(event), sessionId: session.id, seq: session.sequenceNum });\n session.lastActivity = Date.now();\n }\n } catch (err) {\n if ((err as Error).name !== \"AbortError\") {\n wsSend(ws, { type: \"error\", sessionId: session.id, error: String(err) });\n }\n } finally {\n session.done = true;\n }\n };\n run().catch((err) => this.options.onError?.(err instanceof Error ? err : new Error(String(err))));\n }\n\n private startSseKeepalive(session: SessionState): void {\n clearSseKeepalive(session);\n session.sseKeepaliveTimer = setInterval(() => {\n if (session.sseResponse && !session.sseResponse.destroyed) {\n session.sseResponse.write(\":keepalive\\n\\n\");\n }\n }, SSE_KEEPALIVE_INTERVAL_MS);\n session.sseKeepaliveTimer.unref();\n }\n\n private async resolveConnectionOverrides(req: IncomingMessage): Promise<ConnectionOverrides> {\n if (!this.options.onConnection) return {};\n const auth = (await this.authenticate(req)) ?? {};\n return this.options.onConnection({ auth, remoteAddress: req.socket.remoteAddress });\n }\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createServer(code: Agent, options: ServerOptions): NoumenServer {\n return new NoumenServer(code, options);\n}\n\n/**\n * Create a `(req, res)` handler that can be mounted on any Node HTTP\n * framework (Express, Fastify, Hono, bare `http.createServer`, etc.).\n *\n * ```ts\n * import express from \"express\";\n * import { createRequestHandler } from \"noumen/server\";\n *\n * const app = express();\n * app.use(\"/agent\", createRequestHandler(code, { auth: { type: \"bearer\", token: \"...\" } }));\n * ```\n *\n * WebSocket is not supported in middleware mode — use `createServer()` for WS.\n */\nexport function createRequestHandler(\n code: Agent,\n options?: RequestHandlerOptions,\n): (req: IncomingMessage, res: ServerResponse) => void {\n const serverOpts: ServerOptions = {\n port: 0,\n ws: false,\n ...options,\n };\n const server = new NoumenServer(code, serverOpts);\n return (req, res) => { server.handleRequest(req, res); };\n}\n\n// ---------------------------------------------------------------------------\n// Helpers\n// ---------------------------------------------------------------------------\n\nfunction jsonResponse(res: ServerResponse, status: number, body: unknown): void {\n const json = JSON.stringify(body);\n res.writeHead(status, {\n \"Content-Type\": \"application/json\",\n \"Content-Length\": Buffer.byteLength(json),\n });\n res.end(json);\n}\n\nfunction readBody(req: IncomingMessage): Promise<unknown> {\n return new Promise((resolve, reject) => {\n let totalBytes = 0;\n let rejected = false;\n const chunks: Buffer[] = [];\n req.on(\"data\", (chunk: Buffer) => {\n if (rejected) return;\n totalBytes += chunk.length;\n if (totalBytes > MAX_BODY_BYTES) {\n rejected = true;\n req.destroy();\n reject(new Error(\"Request body too large\"));\n return;\n }\n chunks.push(chunk);\n });\n req.on(\"end\", () => {\n if (rejected) return;\n try {\n const raw = Buffer.concat(chunks).toString();\n resolve(raw ? JSON.parse(raw) : {});\n } catch (err) {\n reject(err);\n }\n });\n req.on(\"error\", (err) => {\n if (!rejected) reject(err);\n });\n });\n}\n","import { randomUUID } from \"node:crypto\";\nimport type { ServerResponse } from \"node:http\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { PermissionResponse } from \"../permissions/types.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface PromiseResolver<T> {\n resolve: (value: T) => void;\n reject: (err: Error) => void;\n}\n\nexport interface BufferedEvent {\n seq: number;\n event: StreamEvent;\n}\n\nexport interface SessionState {\n id: string;\n abortController: AbortController;\n pendingPermission: PromiseResolver<PermissionResponse> | null;\n pendingInput: PromiseResolver<string> | null;\n pendingPermissionTimer: ReturnType<typeof setTimeout> | null;\n pendingInputTimer: ReturnType<typeof setTimeout> | null;\n lastActivity: number;\n sseResponse: ServerResponse | null;\n sseKeepaliveTimer: ReturnType<typeof setInterval> | null;\n eventBuffer: BufferedEvent[];\n sequenceNum: number;\n done: boolean;\n cwd?: string;\n}\n\nexport interface ConnectionOverrides {\n cwd?: string;\n}\n\nexport const DEFAULT_PENDING_TIMEOUT_MS = 120_000; // 2 minutes\n\n// ---------------------------------------------------------------------------\n// Session lifecycle\n// ---------------------------------------------------------------------------\n\nexport function createSessionState(\n sessions: Map<string, SessionState>,\n requestedId: string | undefined,\n overrides: ConnectionOverrides,\n): SessionState {\n if (requestedId && sessions.has(requestedId)) {\n throw new Error(`Session ${requestedId} already exists`);\n }\n const sessionId = requestedId ?? randomUUID();\n\n const session: SessionState = {\n id: sessionId,\n abortController: new AbortController(),\n pendingPermission: null,\n pendingInput: null,\n pendingPermissionTimer: null,\n pendingInputTimer: null,\n lastActivity: Date.now(),\n sseResponse: null,\n sseKeepaliveTimer: null,\n eventBuffer: [],\n sequenceNum: 0,\n done: false,\n cwd: overrides.cwd,\n };\n\n sessions.set(sessionId, session);\n return session;\n}\n\nexport function destroySession(\n sessions: Map<string, SessionState>,\n session: SessionState,\n): void {\n session.abortController.abort();\n clearSseKeepalive(session);\n clearPendingPermissionTimer(session);\n clearPendingInputTimer(session);\n if (session.pendingPermission) {\n session.pendingPermission.reject(new Error(\"Session aborted\"));\n session.pendingPermission = null;\n }\n if (session.pendingInput) {\n session.pendingInput.reject(new Error(\"Session aborted\"));\n session.pendingInput = null;\n }\n if (session.sseResponse) {\n session.sseResponse.end();\n session.sseResponse = null;\n }\n sessions.delete(session.id);\n}\n\nexport function reapIdleSessions(\n sessions: Map<string, SessionState>,\n timeoutMs: number | undefined,\n): void {\n if (!timeoutMs) return;\n const now = Date.now();\n for (const session of sessions.values()) {\n if (now - session.lastActivity > timeoutMs) {\n destroySession(sessions, session);\n }\n }\n}\n\n// ---------------------------------------------------------------------------\n// Permission / input bridging\n// ---------------------------------------------------------------------------\n\nexport function bridgePermission(\n sessions: Map<string, SessionState>,\n sessionId: string,\n timeoutMs: number,\n): Promise<PermissionResponse> {\n const session = sessions.get(sessionId);\n if (!session) return Promise.reject(new Error(\"Session not found\"));\n return new Promise<PermissionResponse>((resolve, reject) => {\n session.pendingPermission = { resolve, reject };\n session.pendingPermissionTimer = setTimeout(() => {\n session.pendingPermissionTimer = null;\n if (session.pendingPermission) {\n session.pendingPermission.reject(new Error(\"Permission request timed out\"));\n session.pendingPermission = null;\n }\n }, timeoutMs);\n });\n}\n\nexport function bridgeUserInput(\n sessions: Map<string, SessionState>,\n sessionId: string,\n timeoutMs: number,\n): Promise<string> {\n const session = sessions.get(sessionId);\n if (!session) return Promise.reject(new Error(\"Session not found\"));\n return new Promise<string>((resolve, reject) => {\n session.pendingInput = { resolve, reject };\n session.pendingInputTimer = setTimeout(() => {\n session.pendingInputTimer = null;\n if (session.pendingInput) {\n session.pendingInput.reject(new Error(\"User input request timed out\"));\n session.pendingInput = null;\n }\n }, timeoutMs);\n });\n}\n\n// ---------------------------------------------------------------------------\n// Timer helpers\n// ---------------------------------------------------------------------------\n\nexport function clearPendingPermissionTimer(session: SessionState): void {\n if (session.pendingPermissionTimer) {\n clearTimeout(session.pendingPermissionTimer);\n session.pendingPermissionTimer = null;\n }\n}\n\nexport function clearPendingInputTimer(session: SessionState): void {\n if (session.pendingInputTimer) {\n clearTimeout(session.pendingInputTimer);\n session.pendingInputTimer = null;\n }\n}\n\nexport function clearSseKeepalive(session: SessionState): void {\n if (session.sseKeepaliveTimer) {\n clearInterval(session.sseKeepaliveTimer);\n session.sseKeepaliveTimer = null;\n }\n}\n","import type { ServerResponse } from \"node:http\";\nimport type { StreamEvent } from \"../session/types.js\";\nimport type { SessionState, BufferedEvent } from \"./session-state.js\";\n\nexport const MAX_EVENT_BUFFER = 1000;\n\n/**\n * Serialize a StreamEvent to a JSON-safe object. Error instances are\n * converted to `{ message, name }` since `JSON.stringify(new Error())`\n * produces `{}`.\n */\nexport function serializeEvent(event: StreamEvent): Record<string, unknown> {\n if (event.type === \"error\") {\n return { type: \"error\", error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_exhausted\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n if (event.type === \"retry_attempt\") {\n return { ...event, error: { message: event.error.message, name: event.error.name } };\n }\n return event as unknown as Record<string, unknown>;\n}\n\n/**\n * Push a stream event into the session's buffer, incrementing the sequence\n * number and writing to the live SSE response if one is attached.\n */\nexport function pushEvent(session: SessionState, event: StreamEvent): void {\n session.sequenceNum++;\n const seq = session.sequenceNum;\n\n if (session.eventBuffer.length >= MAX_EVENT_BUFFER) {\n session.eventBuffer.shift();\n }\n session.eventBuffer.push({ seq, event });\n\n if (session.sseResponse) {\n writeSseEventRaw(session.sseResponse, seq, serializeEvent(event));\n }\n}\n\n/**\n * Return buffered events whose sequence number is greater than `afterSeq`.\n */\nexport function getBufferedEventsAfter(\n buffer: BufferedEvent[],\n afterSeq: number,\n): BufferedEvent[] {\n if (!afterSeq) return [...buffer];\n return buffer.filter((e) => e.seq > afterSeq);\n}\n\nexport function writeSseEventRaw(\n res: ServerResponse,\n seq: number,\n data: Record<string, unknown>,\n): void {\n res.write(`id: ${seq}\\ndata: ${JSON.stringify(data)}\\n\\n`);\n}\n","import type { PermissionResponse } from \"../permissions/types.js\";\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport type WsWebSocket = {\n on(event: \"message\", cb: (data: Buffer | string) => void): void;\n on(event: \"close\", cb: () => void): void;\n on(event: \"error\", cb: (err: Error) => void): void;\n on(event: \"pong\", cb: () => void): void;\n send(data: string): void;\n ping(): void;\n close(): void;\n readyState: number;\n};\n\nexport interface WsDispatchCallbacks {\n /** Start a new session with the given prompt, optional requested session ID. */\n onRun: (prompt: string, requestedSessionId: string | undefined) => Promise<string>;\n /** Send a follow-up message to an existing session. */\n onMessage: (sessionId: string, prompt: string) => void;\n /** Forward a permission response to a session. */\n onPermissionResponse: (sessionId: string, response: PermissionResponse) => void;\n /** Forward a user input response to a session. */\n onInputResponse: (sessionId: string, answer: string) => void;\n /** Abort/destroy a session. */\n onAbort: (sessionId: string) => void;\n}\n\nexport interface WsDispatchContext {\n maxSessions: number | undefined;\n currentSessionCount: number;\n}\n\nexport type WsDispatchResult =\n | { type: \"ok\" }\n | { type: \"error\"; error: string }\n | { type: \"session_created\"; sessionId: string }\n\n// ---------------------------------------------------------------------------\n// Parsing\n// ---------------------------------------------------------------------------\n\nexport function parseWsMessage(raw: Buffer | string): Record<string, unknown> | null {\n try {\n return JSON.parse(typeof raw === \"string\" ? raw : raw.toString());\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Dispatch\n// ---------------------------------------------------------------------------\n\nexport async function handleWsMessage(\n msg: Record<string, unknown>,\n ctx: WsDispatchContext,\n callbacks: WsDispatchCallbacks,\n): Promise<WsDispatchResult> {\n const msgType = msg.type as string;\n\n if (msgType === \"run\") {\n if (ctx.maxSessions && ctx.currentSessionCount >= ctx.maxSessions) {\n return { type: \"error\", error: \"Maximum sessions reached\" };\n }\n if (typeof msg.prompt !== \"string\" || !msg.prompt.trim()) {\n return { type: \"error\", error: \"Missing or empty prompt\" };\n }\n try {\n const sessionId = await callbacks.onRun(\n msg.prompt,\n msg.sessionId as string | undefined,\n );\n return { type: \"session_created\", sessionId };\n } catch (err) {\n return { type: \"error\", error: err instanceof Error ? err.message : String(err) };\n }\n }\n\n if (msgType === \"message\") {\n if (typeof msg.prompt !== \"string\" || !msg.prompt.trim()) {\n return { type: \"error\", error: \"Missing or empty prompt\" };\n }\n const sessionId = msg.sessionId as string;\n if (!sessionId) {\n return { type: \"error\", error: \"Missing sessionId\" };\n }\n callbacks.onMessage(sessionId, msg.prompt);\n return { type: \"ok\" };\n }\n\n if (msgType === \"permission_response\") {\n const sessionId = msg.sessionId as string;\n const { sessionId: _sid, type: _type, ...response } = msg;\n callbacks.onPermissionResponse(sessionId, response as unknown as PermissionResponse);\n return { type: \"ok\" };\n }\n\n if (msgType === \"input_response\") {\n const sessionId = msg.sessionId as string;\n callbacks.onInputResponse(sessionId, (msg.answer as string) ?? \"\");\n return { type: \"ok\" };\n }\n\n if (msgType === \"abort\") {\n const sessionId = msg.sessionId as string;\n if (sessionId) callbacks.onAbort(sessionId);\n return { type: \"ok\" };\n }\n\n return { type: \"ok\" };\n}\n\nexport function wsSend(ws: WsWebSocket, data: unknown): void {\n if (ws.readyState === 1) ws.send(JSON.stringify(data));\n}\n"],"mappings":"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","names":[]}
@@ -1,4 +1,4 @@
1
- import { T as Tool, g as ToolResult, h as ToolContext } from './types-CwKKucOF.js';
1
+ import { T as Tool, g as ToolResult, h as ToolContext } from './types-RPKUTu1k.js';
2
2
  import { T as TokenStorage, M as McpServerConfig } from './types-2kTLUCnD.js';
3
3
 
4
4
  /**
@@ -66,6 +66,8 @@ interface PermissionRequest {
66
66
  suggestions?: PermissionRule[];
67
67
  isReadOnly: boolean;
68
68
  isDestructive: boolean;
69
+ /** Abort signal from the session — handlers should stop promptly when fired. */
70
+ signal?: AbortSignal;
69
71
  }
70
72
  interface PermissionResponse {
71
73
  allow: boolean;
@@ -25,6 +25,7 @@ interface UsageRecord {
25
25
  interface ModelUsageSummary {
26
26
  inputTokens: number;
27
27
  outputTokens: number;
28
+ thinkingTokens: number;
28
29
  cacheReadTokens: number;
29
30
  cacheCreationTokens: number;
30
31
  costUSD: number;
@@ -36,6 +37,7 @@ interface CostSummary {
36
37
  totalCostUSD: number;
37
38
  totalInputTokens: number;
38
39
  totalOutputTokens: number;
40
+ totalThinkingTokens: number;
39
41
  totalCacheReadTokens: number;
40
42
  totalCacheCreationTokens: number;
41
43
  byModel: Record<string, ModelUsageSummary>;
@@ -162,11 +164,26 @@ interface AssistantMessage {
162
164
  role: "assistant";
163
165
  content: string | null;
164
166
  tool_calls?: ToolCallContent[];
167
+ /** Accumulated thinking content for providers that support extended thinking (e.g. Anthropic). */
168
+ thinking_content?: string;
169
+ /** Thinking signature required by Anthropic to verify thinking blocks across turns. */
170
+ thinking_signature?: string;
171
+ /** Opaque data for Anthropic redacted_thinking blocks — must be echoed back verbatim. */
172
+ redacted_thinking_data?: string;
173
+ /**
174
+ * Internal turn identifier linking assistant chunks from the same provider
175
+ * response. Used by normalization to merge non-adjacent assistant messages
176
+ * that belong to the same logical turn (separated by tool result rows).
177
+ * Stripped before sending to providers.
178
+ */
179
+ _turnId?: string;
165
180
  }
166
181
  interface ToolResultMessage {
167
182
  role: "tool";
168
183
  tool_call_id: string;
169
184
  content: string | ContentPart[];
185
+ /** When true, signals to the provider that this tool result is an error. */
186
+ isError?: boolean;
170
187
  }
171
188
  interface SystemMessage {
172
189
  role: "system";
@@ -332,6 +349,10 @@ type StreamEvent = {
332
349
  type: "retry_exhausted";
333
350
  attempts: number;
334
351
  error: Error;
352
+ } | {
353
+ type: "model_switch";
354
+ from: string;
355
+ to: string;
335
356
  } | {
336
357
  type: "subagent_start";
337
358
  toolUseId: string;
@@ -389,6 +410,9 @@ type StreamEvent = {
389
410
  type: "max_turns_reached";
390
411
  maxTurns: number;
391
412
  turnCount: number;
413
+ } | {
414
+ type: "auto_compact_failed";
415
+ error: Error;
392
416
  };
393
417
  interface RunOptions {
394
418
  signal?: AbortSignal;
@@ -453,6 +477,8 @@ interface ChatStreamDelta {
453
477
  content?: string | null;
454
478
  thinking_content?: string | null;
455
479
  thinking_signature?: string | null;
480
+ /** Opaque data payload for Anthropic redacted_thinking blocks. */
481
+ redacted_thinking_data?: string | null;
456
482
  tool_calls?: Array<{
457
483
  index: number;
458
484
  id?: string;
@@ -525,6 +551,8 @@ interface ChatParams {
525
551
  * to avoid writing fork-only tails into the shared prompt cache.
526
552
  */
527
553
  skipCacheWrite?: boolean;
554
+ /** Abort signal — providers should forward this to cancel in-flight HTTP requests. */
555
+ signal?: AbortSignal;
528
556
  }
529
557
  interface AIProvider {
530
558
  chat(params: ChatParams): AsyncIterable<ChatStreamChunk>;
@@ -1,5 +1,5 @@
1
- import { c as CheckpointConfig, F as FileCheckpointState, D as DiffStats, d as FileCheckpointSnapshot, S as StreamEvent, e as ContentPart } from './types-3c88cRKH.js';
2
- import { a as PermissionMode, b as PermissionResult } from './types-DwdzmXfs.js';
1
+ import { c as CheckpointConfig, F as FileCheckpointState, D as DiffStats, d as FileCheckpointSnapshot, S as StreamEvent, e as ContentPart } from './types-LrU4LRmX.js';
2
+ import { a as PermissionMode, b as PermissionResult } from './types-CD0rUKKT.js';
3
3
 
4
4
  interface FileEntry {
5
5
  name: string;
@@ -17,6 +17,12 @@ interface FileStat {
17
17
  }
18
18
  interface ReadOptions {
19
19
  encoding?: BufferEncoding;
20
+ /**
21
+ * Maximum number of bytes to read. When set, only the first `maxBytes`
22
+ * bytes are returned (decoded as a string). Implementations that do not
23
+ * support this option may ignore it and return the full content.
24
+ */
25
+ maxBytes?: number;
20
26
  }
21
27
  /**
22
28
  * Sandboxed filesystem interface.
@@ -59,6 +65,7 @@ interface ExecOptions {
59
65
  timeout?: number;
60
66
  cwd?: string;
61
67
  env?: Record<string, string>;
68
+ signal?: AbortSignal;
62
69
  }
63
70
  interface CommandResult {
64
71
  exitCode: number;
@@ -138,6 +145,10 @@ interface PreToolUseHookOutput {
138
145
  updatedInput?: Record<string, unknown>;
139
146
  message?: string;
140
147
  preventContinuation?: boolean;
148
+ hookErrors?: Array<{
149
+ hook: string;
150
+ error: string;
151
+ }>;
141
152
  }
142
153
  interface PostToolUseHookInput {
143
154
  event: "PostToolUse";
@@ -239,6 +250,11 @@ interface HookDefinition {
239
250
  event: HookEvent;
240
251
  /** Optional tool name glob filter (e.g. "Bash", "mcp__*") */
241
252
  matcher?: string;
253
+ /**
254
+ * When true, errors thrown by this hook propagate as denials instead of
255
+ * being silently swallowed. Use for security-critical hooks.
256
+ */
257
+ blocking?: boolean;
242
258
  handler: (input: HookInput) => Promise<HookOutput> | HookOutput;
243
259
  }
244
260
 
@@ -542,6 +558,8 @@ interface ToolContext {
542
558
  fileStateCache?: FileStateCache;
543
559
  /** Fire a notification hook from within a tool (populated by Thread). */
544
560
  notifyHook?: (event: string, input: Record<string, unknown>) => Promise<void>;
561
+ /** Abort signal — tools should check this to terminate early on user abort. */
562
+ signal?: AbortSignal;
545
563
  }
546
564
  interface ToolParameterProperty {
547
565
  type: string;
@@ -614,6 +632,13 @@ interface Tool {
614
632
  * prompt even in bypassPermissions mode (e.g. AskUser).
615
633
  */
616
634
  requiresUserInteraction?: boolean;
635
+ /**
636
+ * Optional semantic validation after schema parse succeeds. Catches
637
+ * domain-specific errors (e.g. invalid file path, conflicting flags)
638
+ * before execution. Return a string error message to reject, or
639
+ * undefined to proceed.
640
+ */
641
+ validateInput?: (args: Record<string, unknown>, ctx: ToolContext) => string | undefined | Promise<string | undefined>;
617
642
  call(args: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>;
618
643
  }
619
644
 
@@ -0,0 +1,8 @@
1
+ import {
2
+ generateUUID
3
+ } from "./chunk-3HEYCV26.js";
4
+ import "./chunk-DGUM43GV.js";
5
+ export {
6
+ generateUUID
7
+ };
8
+ //# sourceMappingURL=uuid-RVN2T26F.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
@@ -0,0 +1,12 @@
1
+ import {
2
+ formatZodValidationError,
3
+ registerZodToJsonSchema,
4
+ zodToJsonSchema
5
+ } from "./chunk-3SK5GCI6.js";
6
+ import "./chunk-DGUM43GV.js";
7
+ export {
8
+ formatZodValidationError,
9
+ registerZodToJsonSchema,
10
+ zodToJsonSchema
11
+ };
12
+ //# sourceMappingURL=zod-7YXKWYMC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "noumen",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "type": "module",
5
- "description": "Programmatic AI coding agent library with pluggable providers and virtual infrastructure",
5
+ "description": "Programmatic AI agent runtime with pluggable providers and sandboxed virtual infrastructure",
6
6
  "main": "./dist/index.js",
7
7
  "module": "./dist/index.js",
8
8
  "types": "./dist/index.d.ts",
@@ -85,19 +85,20 @@
85
85
  "uuid": "^11.1.0"
86
86
  },
87
87
  "peerDependencies": {
88
+ "@anthropic-ai/bedrock-sdk": ">=0.10.0",
88
89
  "@anthropic-ai/sdk": "^0.39.0",
90
+ "@anthropic-ai/vertex-sdk": ">=0.4.0",
89
91
  "@google/genai": "^1.48.0",
90
92
  "@modelcontextprotocol/sdk": "^1.29.0",
91
- "openai": "^4.85.0",
92
- "vscode-jsonrpc": "^8.2.1",
93
93
  "@opentelemetry/api": "^1.0.0",
94
- "@anthropic-ai/bedrock-sdk": ">=0.10.0",
95
- "@anthropic-ai/vertex-sdk": ">=0.4.0",
96
- "google-auth-library": ">=9.0.0",
97
94
  "dockerode": ">=4.0.0",
98
95
  "e2b": ">=2.0.0",
99
- "ws": ">=8.0.0",
100
- "sharp": ">=0.33.0"
96
+ "freestyle-sandboxes": ">=0.1.0",
97
+ "google-auth-library": ">=9.0.0",
98
+ "openai": "^4.85.0",
99
+ "sharp": ">=0.33.0",
100
+ "vscode-jsonrpc": "^8.2.1",
101
+ "ws": ">=8.0.0"
101
102
  },
102
103
  "peerDependenciesMeta": {
103
104
  "@anthropic-ai/sdk": {
@@ -133,6 +134,9 @@
133
134
  "e2b": {
134
135
  "optional": true
135
136
  },
137
+ "freestyle-sandboxes": {
138
+ "optional": true
139
+ },
136
140
  "ws": {
137
141
  "optional": true
138
142
  },
@@ -144,19 +148,21 @@
144
148
  "@anthropic-ai/sdk": "^0.39.0",
145
149
  "@google/genai": "^1.48.0",
146
150
  "@modelcontextprotocol/sdk": "^1.29.0",
147
- "openai": "^4.85.0",
148
- "vscode-jsonrpc": "^8.2.1",
149
151
  "@opentelemetry/api": "^1.9.1",
152
+ "@types/dockerode": "^4.0.1",
150
153
  "@types/node": "^22.0.0",
151
154
  "@types/uuid": "^10.0.0",
155
+ "@types/ws": "^8.5.0",
152
156
  "@vitest/coverage-v8": "^3.2.4",
153
157
  "concurrently": "^9.2.1",
158
+ "freestyle-sandboxes": "^0.1.42",
159
+ "openai": "^4.85.0",
154
160
  "tsup": "^8.4.0",
155
161
  "tsx": "^4.21.0",
156
162
  "typescript": "^5.7.0",
157
163
  "vitest": "^3.0.0",
158
- "ws": "^8.18.0",
159
- "@types/ws": "^8.5.0"
164
+ "vscode-jsonrpc": "^8.2.1",
165
+ "ws": "^8.18.0"
160
166
  },
161
167
  "scripts": {
162
168
  "build": "tsup",