@abassey/aid 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.
Files changed (53) hide show
  1. package/dist/agents/index.cjs +741 -0
  2. package/dist/agents/index.d.cts +78 -0
  3. package/dist/agents/index.d.ts +78 -0
  4. package/dist/agents/index.js +741 -0
  5. package/dist/ai-AWJOUXFM.js +9 -0
  6. package/dist/ai-DOAYJKKI.cjs +9 -0
  7. package/dist/chunk-2TNYBUNK.js +124 -0
  8. package/dist/chunk-3LGKZRGY.cjs +124 -0
  9. package/dist/chunk-AUR2BBB5.cjs +1436 -0
  10. package/dist/chunk-IJLTRQF4.cjs +276 -0
  11. package/dist/chunk-JPD7UBAZ.js +58 -0
  12. package/dist/chunk-M4RQALTT.js +276 -0
  13. package/dist/chunk-NB65IHJE.cjs +58 -0
  14. package/dist/chunk-YNIEOBDF.js +1436 -0
  15. package/dist/client/index.cjs +18 -0
  16. package/dist/client/index.d.cts +8 -0
  17. package/dist/client/index.d.ts +8 -0
  18. package/dist/client/index.js +18 -0
  19. package/dist/errors-CUVTnseb.d.ts +13 -0
  20. package/dist/errors-CgCce4cK.d.cts +158 -0
  21. package/dist/errors-CgCce4cK.d.ts +158 -0
  22. package/dist/errors-zAPbTlpe.d.cts +13 -0
  23. package/dist/eval/index.cjs +308 -0
  24. package/dist/eval/index.d.cts +106 -0
  25. package/dist/eval/index.d.ts +106 -0
  26. package/dist/eval/index.js +308 -0
  27. package/dist/index.cjs +35 -0
  28. package/dist/index.d.cts +107 -0
  29. package/dist/index.d.ts +107 -0
  30. package/dist/index.js +35 -0
  31. package/dist/middleware/index.cjs +201 -0
  32. package/dist/middleware/index.d.cts +36 -0
  33. package/dist/middleware/index.d.ts +36 -0
  34. package/dist/middleware/index.js +201 -0
  35. package/dist/observability/index.cjs +147 -0
  36. package/dist/observability/index.d.cts +30 -0
  37. package/dist/observability/index.d.ts +30 -0
  38. package/dist/observability/index.js +147 -0
  39. package/dist/react/index.cjs +253 -0
  40. package/dist/react/index.d.cts +64 -0
  41. package/dist/react/index.d.ts +64 -0
  42. package/dist/react/index.js +253 -0
  43. package/dist/serve/index.cjs +545 -0
  44. package/dist/serve/index.d.cts +69 -0
  45. package/dist/serve/index.d.ts +69 -0
  46. package/dist/serve/index.js +545 -0
  47. package/dist/types-BJReASS-.d.cts +196 -0
  48. package/dist/types-BJReASS-.d.ts +196 -0
  49. package/dist/types-CguX3F16.d.cts +173 -0
  50. package/dist/types-CrFH-_qp.d.cts +68 -0
  51. package/dist/types-DvdzPmW0.d.ts +173 -0
  52. package/dist/types-qfE32ADy.d.ts +68 -0
  53. package/package.json +144 -0
@@ -0,0 +1,545 @@
1
+ import {
2
+ ai
3
+ } from "../chunk-YNIEOBDF.js";
4
+ import {
5
+ AidError,
6
+ MODEL_MAP
7
+ } from "../chunk-2TNYBUNK.js";
8
+
9
+ // src/serve/index.ts
10
+ import http from "http";
11
+
12
+ // src/serve/router.ts
13
+ function matchRoute(routes, method, url) {
14
+ const path = (url.split("?")[0] ?? url).replace(/\/+$/, "") || "/";
15
+ const pathSegments = path.split("/").filter(Boolean);
16
+ const patternMatches = [];
17
+ for (const route of routes) {
18
+ const patternSegments = route.pattern.split("/").filter(Boolean);
19
+ if (patternSegments.length !== pathSegments.length) continue;
20
+ const params = {};
21
+ let isMatch = true;
22
+ for (let i = 0; i < patternSegments.length; i++) {
23
+ const seg = patternSegments[i];
24
+ if (seg.startsWith(":")) {
25
+ params[seg.slice(1)] = pathSegments[i];
26
+ } else if (seg !== pathSegments[i]) {
27
+ isMatch = false;
28
+ break;
29
+ }
30
+ }
31
+ if (isMatch) {
32
+ patternMatches.push({ route, params });
33
+ }
34
+ }
35
+ if (patternMatches.length === 0) {
36
+ return { matched: false, params: {}, status: 404 };
37
+ }
38
+ const methodMatch = patternMatches.find(
39
+ (m) => m.route.method === method
40
+ );
41
+ if (methodMatch) {
42
+ return {
43
+ matched: true,
44
+ route: methodMatch.route,
45
+ params: methodMatch.params
46
+ };
47
+ }
48
+ const allowedMethods = [
49
+ ...new Set(patternMatches.map((m) => m.route.method))
50
+ ];
51
+ return {
52
+ matched: false,
53
+ params: {},
54
+ status: 405,
55
+ allowedMethods
56
+ };
57
+ }
58
+
59
+ // src/serve/sse.ts
60
+ var SSE_HEADERS = {
61
+ "Content-Type": "text/event-stream",
62
+ "Cache-Control": "no-cache",
63
+ "Connection": "keep-alive"
64
+ };
65
+ function sendEvent(res, data) {
66
+ res.write(`data: ${JSON.stringify(data)}
67
+
68
+ `);
69
+ }
70
+ async function writeStreamSSE(res, stream) {
71
+ res.writeHead(200, SSE_HEADERS);
72
+ let closed = false;
73
+ res.on("close", () => {
74
+ closed = true;
75
+ stream.abort();
76
+ });
77
+ try {
78
+ for await (const chunk of stream) {
79
+ if (closed) break;
80
+ if (chunk.done && chunk.response) {
81
+ sendEvent(res, {
82
+ type: "done",
83
+ text: chunk.response.text,
84
+ model: chunk.response.model,
85
+ tokens: chunk.response.tokens,
86
+ cost: chunk.response.cost,
87
+ latencyMs: chunk.response.latencyMs
88
+ });
89
+ } else {
90
+ sendEvent(res, { type: "text", text: chunk.delta });
91
+ }
92
+ }
93
+ } catch (err) {
94
+ if (!closed) {
95
+ const message = err instanceof Error ? err.message : String(err);
96
+ const code = err instanceof AidError ? err.code : "provider_error";
97
+ sendEvent(res, { type: "error", code, message });
98
+ }
99
+ } finally {
100
+ if (!closed) {
101
+ res.end();
102
+ }
103
+ }
104
+ }
105
+ async function writeAgentSSE(res, agent, task) {
106
+ res.writeHead(200, SSE_HEADERS);
107
+ let closed = false;
108
+ res.on("close", () => {
109
+ closed = true;
110
+ });
111
+ const send = (data) => {
112
+ if (!closed) sendEvent(res, data);
113
+ };
114
+ const onStepStart = (payload) => {
115
+ send({ type: "step:start", step: payload.step });
116
+ };
117
+ const onStepEnd = (payload) => {
118
+ send({ type: "step:end", step: payload.step });
119
+ };
120
+ const onToolCall = (payload) => {
121
+ send({ type: "tool:call", name: payload.name, args: payload.args });
122
+ };
123
+ const onToolResult = (payload) => {
124
+ send({ type: "tool:result", name: payload.name, result: payload.result });
125
+ };
126
+ const onMessage = (payload) => {
127
+ send({ type: "text", text: payload.content });
128
+ };
129
+ const onError = (payload) => {
130
+ send({ type: "error", code: payload.error.code, message: payload.error.message });
131
+ };
132
+ agent.on("step:start", onStepStart);
133
+ agent.on("step:end", onStepEnd);
134
+ agent.on("tool:call", onToolCall);
135
+ agent.on("tool:result", onToolResult);
136
+ agent.on("message", onMessage);
137
+ agent.on("error", onError);
138
+ const cleanup = () => {
139
+ agent.off("step:start", onStepStart);
140
+ agent.off("step:end", onStepEnd);
141
+ agent.off("tool:call", onToolCall);
142
+ agent.off("tool:result", onToolResult);
143
+ agent.off("message", onMessage);
144
+ agent.off("error", onError);
145
+ };
146
+ try {
147
+ const result = await agent.run(task);
148
+ if (!closed) {
149
+ sendEvent(res, {
150
+ type: "done",
151
+ text: result.text,
152
+ tokens: result.tokens,
153
+ cost: result.cost,
154
+ steps: result.steps.length
155
+ });
156
+ }
157
+ } catch (err) {
158
+ if (!closed) {
159
+ const message = err instanceof Error ? err.message : String(err);
160
+ const code = err instanceof AidError ? err.code : "provider_error";
161
+ sendEvent(res, { type: "error", code, message });
162
+ }
163
+ } finally {
164
+ cleanup();
165
+ if (!closed) {
166
+ res.end();
167
+ }
168
+ }
169
+ }
170
+
171
+ // src/serve/chat-store.ts
172
+ import { randomUUID } from "crypto";
173
+ var InMemoryChatStore = class {
174
+ sessions = /* @__PURE__ */ new Map();
175
+ maxSessions;
176
+ sessionTtl;
177
+ chatConfig;
178
+ constructor(options) {
179
+ this.maxSessions = options?.maxSessions ?? 1e3;
180
+ this.sessionTtl = options?.sessionTtl ?? 36e5;
181
+ this.chatConfig = {
182
+ system: options?.system,
183
+ model: options?.model,
184
+ maxHistory: options?.maxHistory
185
+ };
186
+ }
187
+ create(options) {
188
+ if (this.sessions.size >= this.maxSessions) {
189
+ this.evictOldest();
190
+ }
191
+ const system = options?.system ?? this.chatConfig.system;
192
+ const model = options?.model ?? this.chatConfig.model;
193
+ const conversation = ai.conversation({
194
+ system,
195
+ model,
196
+ maxHistory: this.chatConfig.maxHistory
197
+ });
198
+ const now = Date.now();
199
+ const session = {
200
+ id: randomUUID(),
201
+ conversation,
202
+ createdAt: now,
203
+ lastActiveAt: now,
204
+ model,
205
+ system
206
+ };
207
+ this.sessions.set(session.id, session);
208
+ return session;
209
+ }
210
+ get(id) {
211
+ const session = this.sessions.get(id);
212
+ if (!session) return void 0;
213
+ if (Date.now() - session.lastActiveAt > this.sessionTtl) {
214
+ this.sessions.delete(id);
215
+ return void 0;
216
+ }
217
+ return session;
218
+ }
219
+ delete(id) {
220
+ return this.sessions.delete(id);
221
+ }
222
+ list() {
223
+ return Array.from(this.sessions.values()).map((s) => ({
224
+ id: s.id,
225
+ createdAt: s.createdAt,
226
+ lastActiveAt: s.lastActiveAt
227
+ }));
228
+ }
229
+ evictOldest() {
230
+ let oldest;
231
+ for (const session of this.sessions.values()) {
232
+ if (!oldest || session.lastActiveAt < oldest.lastActiveAt) {
233
+ oldest = session;
234
+ }
235
+ }
236
+ if (oldest) {
237
+ this.sessions.delete(oldest.id);
238
+ }
239
+ }
240
+ };
241
+
242
+ // src/serve/handler.ts
243
+ var MAX_BODY_SIZE = 1048576;
244
+ function sendJson(res, status, data) {
245
+ const body = JSON.stringify(data);
246
+ res.writeHead(status, {
247
+ "Content-Type": "application/json",
248
+ "Content-Length": Buffer.byteLength(body)
249
+ });
250
+ res.end(body);
251
+ }
252
+ function sendError(res, status, code, message) {
253
+ sendJson(res, status, { error: { code, message } });
254
+ }
255
+ function errorToStatus(code) {
256
+ switch (code) {
257
+ case "invalid_request":
258
+ return 400;
259
+ case "auth_error":
260
+ return 401;
261
+ case "not_found":
262
+ return 404;
263
+ case "rate_limit":
264
+ return 429;
265
+ case "timeout":
266
+ return 504;
267
+ default:
268
+ return 500;
269
+ }
270
+ }
271
+ async function readBody(req) {
272
+ return new Promise((resolve, reject) => {
273
+ const chunks = [];
274
+ let size = 0;
275
+ req.on("data", (chunk) => {
276
+ size += chunk.length;
277
+ if (size > MAX_BODY_SIZE) {
278
+ req.destroy();
279
+ reject(new AidError("invalid_request", "Request body too large"));
280
+ return;
281
+ }
282
+ chunks.push(chunk);
283
+ });
284
+ req.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
285
+ req.on("error", reject);
286
+ });
287
+ }
288
+ function applyCors(req, res, cors) {
289
+ if (!cors) return false;
290
+ if (cors === true) {
291
+ res.setHeader("Access-Control-Allow-Origin", "*");
292
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
293
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
294
+ } else {
295
+ const origin = req.headers.origin;
296
+ if (origin && cors.origins.includes(origin)) {
297
+ res.setHeader("Access-Control-Allow-Origin", origin);
298
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
299
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type");
300
+ }
301
+ }
302
+ if (req.method === "OPTIONS") {
303
+ res.writeHead(204);
304
+ res.end();
305
+ return true;
306
+ }
307
+ return false;
308
+ }
309
+ function createHandler(config) {
310
+ const routes = [];
311
+ const agents = config.agents ?? {};
312
+ const chatConfig = config.chat === true ? {} : config.chat ? config.chat : void 0;
313
+ const chatStore = chatConfig ? new InMemoryChatStore({
314
+ maxSessions: chatConfig.maxSessions,
315
+ sessionTtl: chatConfig.sessionTtl,
316
+ system: chatConfig.system,
317
+ model: chatConfig.model,
318
+ maxHistory: chatConfig.maxHistory
319
+ }) : void 0;
320
+ const handleAi = async (_req, res, _params, body) => {
321
+ const { prompt, model, system, temperature, maxTokens } = body;
322
+ if (!prompt || typeof prompt !== "string") {
323
+ sendError(res, 400, "invalid_request", "Missing required field: prompt");
324
+ return;
325
+ }
326
+ const response = await ai(prompt, { model, system, temperature, maxTokens });
327
+ sendJson(res, 200, {
328
+ text: response.text,
329
+ model: response.model,
330
+ tokens: response.tokens,
331
+ cost: response.cost,
332
+ latencyMs: response.latencyMs
333
+ });
334
+ };
335
+ const handleAiStream = async (_req, res, _params, body) => {
336
+ const { prompt, model, system, temperature, maxTokens } = body;
337
+ if (!prompt || typeof prompt !== "string") {
338
+ sendError(res, 400, "invalid_request", "Missing required field: prompt");
339
+ return;
340
+ }
341
+ const stream = ai.stream(prompt, { model, system, temperature, maxTokens });
342
+ await writeStreamSSE(res, stream);
343
+ };
344
+ const handleAgent = async (_req, res, params, body) => {
345
+ const agentName = params.name;
346
+ const agentInstance = agents[agentName];
347
+ if (!agentInstance) {
348
+ sendError(res, 404, "not_found", `Agent '${agentName}' not found`);
349
+ return;
350
+ }
351
+ const { task } = body;
352
+ if (!task || typeof task !== "string") {
353
+ sendError(res, 400, "invalid_request", "Missing required field: task");
354
+ return;
355
+ }
356
+ const result = await agentInstance.run(task);
357
+ sendJson(res, 200, {
358
+ text: result.text,
359
+ model: agentInstance.config.model ?? "default",
360
+ tokens: result.tokens,
361
+ cost: result.cost,
362
+ steps: result.steps.length
363
+ });
364
+ };
365
+ const handleAgentStream = async (_req, res, params, body) => {
366
+ const agentName = params.name;
367
+ const agentInstance = agents[agentName];
368
+ if (!agentInstance) {
369
+ sendError(res, 404, "not_found", `Agent '${agentName}' not found`);
370
+ return;
371
+ }
372
+ const { task } = body;
373
+ if (!task || typeof task !== "string") {
374
+ sendError(res, 400, "invalid_request", "Missing required field: task");
375
+ return;
376
+ }
377
+ await writeAgentSSE(res, agentInstance, task);
378
+ };
379
+ const handleChatCreate = async (_req, res, _params, body) => {
380
+ const { system, model } = body ?? {};
381
+ const session = chatStore.create({ system, model });
382
+ sendJson(res, 201, { sessionId: session.id });
383
+ };
384
+ const handleChatMessage = async (_req, res, params, body) => {
385
+ const session = chatStore.get(params.id);
386
+ if (!session) {
387
+ sendError(res, 404, "not_found", `Session '${params.id}' not found`);
388
+ return;
389
+ }
390
+ const { message } = body;
391
+ if (!message || typeof message !== "string") {
392
+ sendError(res, 400, "invalid_request", "Missing required field: message");
393
+ return;
394
+ }
395
+ session.lastActiveAt = Date.now();
396
+ const response = await session.conversation.say(message);
397
+ sendJson(res, 200, {
398
+ text: response.text,
399
+ model: response.model,
400
+ tokens: response.tokens,
401
+ cost: response.cost
402
+ });
403
+ };
404
+ const handleChatStream = async (_req, res, params, body) => {
405
+ const session = chatStore.get(params.id);
406
+ if (!session) {
407
+ sendError(res, 404, "not_found", `Session '${params.id}' not found`);
408
+ return;
409
+ }
410
+ const { message } = body;
411
+ if (!message || typeof message !== "string") {
412
+ sendError(res, 400, "invalid_request", "Missing required field: message");
413
+ return;
414
+ }
415
+ session.lastActiveAt = Date.now();
416
+ const saved = session.conversation.save();
417
+ const messages = [...saved.messages, { role: "user", content: message }];
418
+ const stream = ai.stream(message, {
419
+ system: saved.system || void 0,
420
+ model: session.model,
421
+ _messages: messages
422
+ });
423
+ await writeStreamSSE(res, stream);
424
+ };
425
+ const handleChatHistory = async (_req, res, params) => {
426
+ const session = chatStore.get(params.id);
427
+ if (!session) {
428
+ sendError(res, 404, "not_found", `Session '${params.id}' not found`);
429
+ return;
430
+ }
431
+ const saved = session.conversation.save();
432
+ sendJson(res, 200, {
433
+ sessionId: session.id,
434
+ messages: saved.messages,
435
+ createdAt: session.createdAt,
436
+ lastActiveAt: session.lastActiveAt
437
+ });
438
+ };
439
+ const handleChatDelete = async (_req, res, params) => {
440
+ const deleted = chatStore.delete(params.id);
441
+ if (!deleted) {
442
+ sendError(res, 404, "not_found", `Session '${params.id}' not found`);
443
+ return;
444
+ }
445
+ sendJson(res, 200, { deleted: true });
446
+ };
447
+ const handleHealth = async (_req, res) => {
448
+ sendJson(res, 200, { status: "ok" });
449
+ };
450
+ const handleModels = async (_req, res) => {
451
+ const models = Object.entries(MODEL_MAP).map(([alias, entry]) => ({
452
+ alias,
453
+ provider: entry.provider,
454
+ model: entry.model
455
+ }));
456
+ sendJson(res, 200, { models });
457
+ };
458
+ routes.push({ method: "GET", pattern: "/health", handler: handleHealth });
459
+ routes.push({ method: "GET", pattern: "/models", handler: handleModels });
460
+ if (config.ai) {
461
+ routes.push({ method: "POST", pattern: "/ai", handler: handleAi });
462
+ routes.push({ method: "POST", pattern: "/ai/stream", handler: handleAiStream });
463
+ }
464
+ if (config.agents && Object.keys(config.agents).length > 0) {
465
+ routes.push({ method: "POST", pattern: "/agents/:name", handler: handleAgent });
466
+ routes.push({ method: "POST", pattern: "/agents/:name/stream", handler: handleAgentStream });
467
+ }
468
+ if (chatStore) {
469
+ routes.push({ method: "POST", pattern: "/chat", handler: handleChatCreate });
470
+ routes.push({ method: "POST", pattern: "/chat/:id", handler: handleChatMessage });
471
+ routes.push({ method: "POST", pattern: "/chat/:id/stream", handler: handleChatStream });
472
+ routes.push({ method: "GET", pattern: "/chat/:id", handler: handleChatHistory });
473
+ routes.push({ method: "DELETE", pattern: "/chat/:id", handler: handleChatDelete });
474
+ }
475
+ return (req, res) => {
476
+ const handled = applyCors(req, res, config.cors);
477
+ if (handled) return;
478
+ const method = req.method ?? "GET";
479
+ const url = req.url ?? "/";
480
+ const match = matchRoute(routes, method, url);
481
+ if (!match.matched) {
482
+ if (match.status === 405 && match.allowedMethods) {
483
+ res.setHeader("Allow", match.allowedMethods.join(", "));
484
+ sendError(res, 405, "invalid_request", "Method not allowed");
485
+ } else {
486
+ sendError(res, 404, "not_found", "Not found");
487
+ }
488
+ return;
489
+ }
490
+ const needsBody = ["POST", "PUT", "PATCH"].includes(method);
491
+ const dispatch = async () => {
492
+ let body = {};
493
+ if (needsBody) {
494
+ try {
495
+ const raw = await readBody(req);
496
+ body = raw.length > 0 ? JSON.parse(raw) : {};
497
+ } catch (err) {
498
+ if (err instanceof AidError) {
499
+ sendError(res, 400, err.code, err.message);
500
+ } else {
501
+ sendError(res, 400, "invalid_request", "Invalid JSON in request body");
502
+ }
503
+ return;
504
+ }
505
+ }
506
+ await match.route.handler(req, res, match.params, body);
507
+ };
508
+ dispatch().catch((err) => {
509
+ if (err instanceof AidError) {
510
+ sendError(res, errorToStatus(err.code), err.code, err.message);
511
+ } else {
512
+ const message = err instanceof Error ? err.message : "Internal server error";
513
+ sendError(res, 500, "serve_error", message);
514
+ }
515
+ });
516
+ };
517
+ }
518
+
519
+ // src/serve/index.ts
520
+ function serve(config = {}) {
521
+ const handler = createHandler(config);
522
+ const port = config.port ?? 3e3;
523
+ let server = null;
524
+ return {
525
+ handler,
526
+ async listen() {
527
+ server = http.createServer(handler);
528
+ return new Promise((resolve) => {
529
+ server.listen(port, resolve);
530
+ });
531
+ },
532
+ async close() {
533
+ if (!server) return;
534
+ return new Promise((resolve, reject) => {
535
+ server.close((err) => err ? reject(err) : resolve());
536
+ server = null;
537
+ });
538
+ }
539
+ };
540
+ }
541
+ export {
542
+ InMemoryChatStore,
543
+ createHandler,
544
+ serve
545
+ };