elsium-ai 0.2.3 → 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.
package/dist/index.js CHANGED
@@ -511,6 +511,243 @@ function envBool(name, fallback) {
511
511
  metadata: { variable: name }
512
512
  });
513
513
  }
514
+ // ../core/src/schema.ts
515
+ var log = createLogger();
516
+ function zodDefKind(def) {
517
+ return typeof def.type === "string" ? def.type : def.typeName;
518
+ }
519
+ function zodObjectToJsonSchema(schema, convert) {
520
+ const shape = typeof schema.shape === "function" ? schema.shape() : schema.shape;
521
+ const properties = {};
522
+ const required = [];
523
+ for (const [key, value] of Object.entries(shape)) {
524
+ const fieldSchema = value;
525
+ properties[key] = convert(fieldSchema);
526
+ const fieldDef = fieldSchema._def;
527
+ const fieldKind = zodDefKind(fieldDef);
528
+ if (fieldKind !== "optional" && fieldKind !== "ZodOptional" && fieldKind !== "default" && fieldKind !== "ZodDefault") {
529
+ required.push(key);
530
+ }
531
+ if (fieldDef.description) {
532
+ properties[key].description = fieldDef.description;
533
+ }
534
+ }
535
+ return { type: "object", properties, required };
536
+ }
537
+ function zodToJsonSchema(schema) {
538
+ if (!("_def" in schema))
539
+ return { type: "object" };
540
+ const def = schema._def;
541
+ const kind = zodDefKind(def);
542
+ switch (kind) {
543
+ case "object":
544
+ case "ZodObject":
545
+ return zodObjectToJsonSchema(def, zodToJsonSchema);
546
+ case "string":
547
+ case "ZodString":
548
+ return { type: "string" };
549
+ case "number":
550
+ case "ZodNumber":
551
+ return { type: "number" };
552
+ case "boolean":
553
+ case "ZodBoolean":
554
+ return { type: "boolean" };
555
+ case "array":
556
+ case "ZodArray":
557
+ return {
558
+ type: "array",
559
+ items: zodToJsonSchema(def.element ?? def.type)
560
+ };
561
+ case "enum":
562
+ case "ZodEnum": {
563
+ const values = def.values ?? (def.entries ? Object.values(def.entries) : []);
564
+ return { type: "string", enum: values };
565
+ }
566
+ case "optional":
567
+ case "ZodOptional":
568
+ return zodToJsonSchema(def.innerType);
569
+ case "default":
570
+ case "ZodDefault":
571
+ return zodToJsonSchema(def.innerType);
572
+ case "nullable":
573
+ case "ZodNullable": {
574
+ const inner = zodToJsonSchema(def.innerType);
575
+ return { ...inner, nullable: true };
576
+ }
577
+ case "ZodLiteral":
578
+ return { type: typeof def.value, const: def.value };
579
+ case "ZodUnion": {
580
+ const options = def.options.map(zodToJsonSchema);
581
+ return { anyOf: options };
582
+ }
583
+ case "ZodRecord":
584
+ return {
585
+ type: "object",
586
+ additionalProperties: def.valueType ? zodToJsonSchema(def.valueType) : { type: "string" }
587
+ };
588
+ case "ZodTuple": {
589
+ const items = (def.items ?? []).map(zodToJsonSchema);
590
+ return { type: "array", prefixItems: items, minItems: items.length, maxItems: items.length };
591
+ }
592
+ case "ZodDate":
593
+ return { type: "string", format: "date-time" };
594
+ default:
595
+ log.warn(`zodToJsonSchema: unsupported type ${kind}, defaulting to string`);
596
+ return { type: "string" };
597
+ }
598
+ }
599
+ // ../core/src/registry.ts
600
+ var log2 = createLogger();
601
+ var BLOCKED_KEYS = new Set(["__proto__", "constructor", "prototype"]);
602
+ function createRegistry(label) {
603
+ const entries = new Map;
604
+ return {
605
+ register(name, factory) {
606
+ if (BLOCKED_KEYS.has(name)) {
607
+ log2.warn(`Registry(${label}): rejected blocked key "${name}"`);
608
+ return;
609
+ }
610
+ entries.set(name, factory);
611
+ log2.debug(`Registry(${label}): registered "${name}"`);
612
+ },
613
+ get(name) {
614
+ if (BLOCKED_KEYS.has(name))
615
+ return;
616
+ return entries.get(name);
617
+ },
618
+ list() {
619
+ return Array.from(entries.keys());
620
+ },
621
+ has(name) {
622
+ if (BLOCKED_KEYS.has(name))
623
+ return false;
624
+ return entries.has(name);
625
+ },
626
+ unregister(name) {
627
+ if (BLOCKED_KEYS.has(name))
628
+ return false;
629
+ const deleted = entries.delete(name);
630
+ if (deleted) {
631
+ log2.debug(`Registry(${label}): unregistered "${name}"`);
632
+ }
633
+ return deleted;
634
+ }
635
+ };
636
+ }
637
+ // ../core/src/tokens.ts
638
+ var MODEL_RATIOS = {
639
+ cl100k_base: 4,
640
+ "gpt-4o": 4,
641
+ "gpt-4o-mini": 4,
642
+ o1: 4,
643
+ "o1-mini": 4,
644
+ "o3-mini": 4,
645
+ "claude-opus-4-6": 3.5,
646
+ "claude-sonnet-4-6": 3.5,
647
+ "claude-haiku-4-5-20251001": 3.5,
648
+ "gemini-2.0-flash": 4,
649
+ "gemini-2.0-flash-lite": 4,
650
+ "gemini-2.5-pro-preview-05-06": 4,
651
+ "gemini-2.5-flash-preview-04-17": 4
652
+ };
653
+ function getRatio(model) {
654
+ if (!model)
655
+ return 4;
656
+ if (MODEL_RATIOS[model])
657
+ return MODEL_RATIOS[model];
658
+ if (model.startsWith("claude"))
659
+ return 3.5;
660
+ if (model.startsWith("gemini"))
661
+ return 4;
662
+ if (model.startsWith("gpt") || model.startsWith("o1") || model.startsWith("o3"))
663
+ return 4;
664
+ return 4;
665
+ }
666
+ function extractMessageText(msg) {
667
+ if (typeof msg.content === "string")
668
+ return msg.content;
669
+ return msg.content.filter((p) => p.type === "text" && ("text" in p)).map((p) => p.text).join("");
670
+ }
671
+ function countTokens(text, model) {
672
+ const ratio = getRatio(model);
673
+ return Math.ceil(text.length / ratio) + 4;
674
+ }
675
+ function createContextManager(config) {
676
+ const { maxTokens, strategy, reserveTokens = 0 } = config;
677
+ const budget = maxTokens - reserveTokens;
678
+ function estimateMessageTokens(msg) {
679
+ return countTokens(extractMessageText(msg)) + 4;
680
+ }
681
+ function estimateTokens(messages) {
682
+ return messages.reduce((sum, msg) => sum + estimateMessageTokens(msg), 0);
683
+ }
684
+ async function fitTruncate(messages, system) {
685
+ let available = budget;
686
+ if (system)
687
+ available -= countTokens(system);
688
+ const result = [];
689
+ for (let i = messages.length - 1;i >= 0; i--) {
690
+ const tokens = estimateMessageTokens(messages[i]);
691
+ if (available - tokens < 0 && result.length > 0)
692
+ break;
693
+ available -= tokens;
694
+ result.unshift(messages[i]);
695
+ }
696
+ return result;
697
+ }
698
+ async function fitSummarize(messages, system) {
699
+ if (!config.summarizer)
700
+ return fitTruncate(messages, system);
701
+ let available = budget;
702
+ if (system)
703
+ available -= countTokens(system);
704
+ const total = estimateTokens(messages);
705
+ if (total <= available)
706
+ return messages;
707
+ const keepCount = Math.max(1, Math.floor(messages.length / 3));
708
+ const toSummarize = messages.slice(0, messages.length - keepCount);
709
+ const toKeep = messages.slice(messages.length - keepCount);
710
+ const summary = await config.summarizer(toSummarize);
711
+ const summaryMsg = {
712
+ role: "system",
713
+ content: `Previous conversation summary: ${summary}`
714
+ };
715
+ return [summaryMsg, ...toKeep];
716
+ }
717
+ async function fitSlidingWindow(messages, system) {
718
+ let available = budget;
719
+ if (system)
720
+ available -= countTokens(system);
721
+ const result = [];
722
+ for (let i = messages.length - 1;i >= 0; i--) {
723
+ const tokens = estimateMessageTokens(messages[i]);
724
+ if (available - tokens < 0 && result.length > 0)
725
+ break;
726
+ available -= tokens;
727
+ result.unshift(messages[i]);
728
+ }
729
+ return result;
730
+ }
731
+ return {
732
+ estimateTokens,
733
+ async fit(messages, system) {
734
+ const total = estimateTokens(messages);
735
+ let available = budget;
736
+ if (system)
737
+ available -= countTokens(system);
738
+ if (total <= available)
739
+ return messages;
740
+ switch (strategy) {
741
+ case "truncate":
742
+ return fitTruncate(messages, system);
743
+ case "summarize":
744
+ return fitSummarize(messages, system);
745
+ case "sliding-window":
746
+ return fitSlidingWindow(messages, system);
747
+ }
748
+ }
749
+ };
750
+ }
514
751
  // ../core/src/circuit-breaker.ts
515
752
  function defaultShouldCount(error) {
516
753
  if (error && typeof error === "object" && "retryable" in error) {
@@ -763,16 +1000,16 @@ function composeMiddleware(middlewares) {
763
1000
  };
764
1001
  }
765
1002
  function loggingMiddleware(logger) {
766
- const log = logger ?? createLogger({ level: "info" });
1003
+ const log3 = logger ?? createLogger({ level: "info" });
767
1004
  return async (ctx, next) => {
768
- log.info("LLM request", {
1005
+ log3.info("LLM request", {
769
1006
  provider: ctx.provider,
770
1007
  model: ctx.model,
771
1008
  traceId: ctx.traceId,
772
1009
  messageCount: ctx.request.messages.length
773
1010
  });
774
1011
  const response = await next(ctx);
775
- log.info("LLM response", {
1012
+ log3.info("LLM response", {
776
1013
  provider: ctx.provider,
777
1014
  model: ctx.model,
778
1015
  traceId: ctx.traceId,
@@ -908,7 +1145,7 @@ function xrayMiddleware(options = {}) {
908
1145
  }
909
1146
 
910
1147
  // ../gateway/src/pricing.ts
911
- var log = createLogger();
1148
+ var log3 = createLogger();
912
1149
  var PRICING = {
913
1150
  "claude-opus-4-6": { inputPerMillion: 15, outputPerMillion: 75 },
914
1151
  "claude-sonnet-4-6": { inputPerMillion: 3, outputPerMillion: 15 },
@@ -946,7 +1183,7 @@ function resolveModelName(model) {
946
1183
  function calculateCost(model, usage) {
947
1184
  const pricing = PRICING[resolveModelName(model)];
948
1185
  if (!pricing) {
949
- log.warn(`Unknown model "${model}" — cost will be reported as $0. Register pricing with registerPricing().`);
1186
+ log3.warn(`Unknown model "${model}" — cost will be reported as $0. Register pricing with registerPricing().`);
950
1187
  return {
951
1188
  inputCost: 0,
952
1189
  outputCost: 0,
@@ -1040,15 +1277,33 @@ function createAnthropicProvider(config) {
1040
1277
  if (part.type === "text")
1041
1278
  return { type: "text", text: part.text };
1042
1279
  if (part.type === "image" && part.source?.type === "base64") {
1280
+ const src = part.source;
1043
1281
  return {
1044
1282
  type: "image",
1045
1283
  source: {
1046
1284
  type: "base64",
1047
- media_type: part.source.mediaType,
1048
- data: part.source.data
1285
+ media_type: src.mediaType,
1286
+ data: src.data
1049
1287
  }
1050
1288
  };
1051
1289
  }
1290
+ if (part.type === "document" && part.source) {
1291
+ if (part.source.type === "base64") {
1292
+ const src = part.source;
1293
+ return {
1294
+ type: "document",
1295
+ source: {
1296
+ type: "base64",
1297
+ media_type: src.mediaType,
1298
+ data: src.data
1299
+ }
1300
+ };
1301
+ }
1302
+ return { type: "text", text: "[document: url source not supported by Anthropic]" };
1303
+ }
1304
+ if (part.type === "audio") {
1305
+ return { type: "text", text: "[audio content not supported by this provider]" };
1306
+ }
1052
1307
  return { type: "text", text: "[unsupported content]" };
1053
1308
  }
1054
1309
  function formatMultipartContent(msg, role) {
@@ -1157,6 +1412,16 @@ function createAnthropicProvider(config) {
1157
1412
  const tools = formatTools(req.tools);
1158
1413
  if (tools)
1159
1414
  body.tools = tools;
1415
+ if (req.schema) {
1416
+ const jsonSchema = zodToJsonSchema(req.schema);
1417
+ const structuredTool = {
1418
+ name: "_structured_output",
1419
+ description: "Return structured output matching the required schema",
1420
+ input_schema: jsonSchema
1421
+ };
1422
+ body.tools = [...tools ?? [], structuredTool];
1423
+ body.tool_choice = { type: "tool", name: "_structured_output" };
1424
+ }
1160
1425
  const startTime = performance.now();
1161
1426
  const raw = await retry(async () => {
1162
1427
  const controller = new AbortController;
@@ -1377,6 +1642,18 @@ function createGoogleProvider(config) {
1377
1642
  } else {
1378
1643
  parts.push({ fileData: { mimeType: "image/jpeg", fileUri: img.source.url } });
1379
1644
  }
1645
+ } else if (p.type === "audio" || p.type === "document") {
1646
+ const media = p;
1647
+ if (media.source.type === "base64") {
1648
+ parts.push({
1649
+ inlineData: { mimeType: media.source.mediaType, data: media.source.data }
1650
+ });
1651
+ } else {
1652
+ const urlSource = media.source;
1653
+ parts.push({
1654
+ fileData: { mimeType: "application/octet-stream", fileUri: urlSource.url }
1655
+ });
1656
+ }
1380
1657
  }
1381
1658
  }
1382
1659
  return { role, parts };
@@ -1475,6 +1752,10 @@ function createGoogleProvider(config) {
1475
1752
  config2.topP = req.topP;
1476
1753
  if (req.stopSequences?.length)
1477
1754
  config2.stopSequences = req.stopSequences;
1755
+ if (req.schema) {
1756
+ config2.responseMimeType = "application/json";
1757
+ config2.responseSchema = zodToJsonSchema(req.schema);
1758
+ }
1478
1759
  return config2;
1479
1760
  }
1480
1761
  function buildRequestBody(req) {
@@ -1754,6 +2035,25 @@ function createOpenAIProvider(config) {
1754
2035
  } else {
1755
2036
  parts.push({ type: "image_url", image_url: { url: part.source.url } });
1756
2037
  }
2038
+ } else if (part.type === "audio") {
2039
+ if (part.source.type === "base64") {
2040
+ const format = part.source.mediaType.split("/")[1] ?? "wav";
2041
+ parts.push({
2042
+ type: "input_audio",
2043
+ input_audio: { data: part.source.data, format }
2044
+ });
2045
+ } else {
2046
+ parts.push({ type: "text", text: "[audio: url source requires file upload]" });
2047
+ }
2048
+ } else if (part.type === "document") {
2049
+ if (part.source.type === "base64") {
2050
+ parts.push({
2051
+ type: "text",
2052
+ text: `[document: ${part.source.mediaType} content attached as base64]`
2053
+ });
2054
+ } else {
2055
+ parts.push({ type: "text", text: `[document: ${part.source.url}]` });
2056
+ }
1757
2057
  }
1758
2058
  }
1759
2059
  return parts;
@@ -1850,6 +2150,17 @@ function createOpenAIProvider(config) {
1850
2150
  const tools = formatTools(req.tools);
1851
2151
  if (tools)
1852
2152
  body.tools = tools;
2153
+ if (req.schema) {
2154
+ const jsonSchema = zodToJsonSchema(req.schema);
2155
+ body.response_format = {
2156
+ type: "json_schema",
2157
+ json_schema: {
2158
+ name: "structured_output",
2159
+ strict: true,
2160
+ schema: jsonSchema
2161
+ }
2162
+ };
2163
+ }
1853
2164
  const startTime = performance.now();
1854
2165
  const raw = await retry(async () => {
1855
2166
  const controller = new AbortController;
@@ -2163,107 +2474,46 @@ function gateway(config) {
2163
2474
  },
2164
2475
  async generate(request) {
2165
2476
  const { schema, ...rest } = request;
2166
- const jsonSchema = schemaToJsonSchema(schema);
2167
- const systemPrompt = [
2168
- rest.system ?? "",
2169
- "You MUST respond with valid JSON matching this schema:",
2170
- JSON.stringify(jsonSchema, null, 2),
2171
- "Respond ONLY with the JSON object, no markdown or explanation."
2172
- ].filter(Boolean).join(`
2173
-
2174
- `);
2477
+ const jsonSchema = zodToJsonSchema(schema);
2175
2478
  const response = await executeWithMiddleware({
2176
2479
  ...rest,
2177
- system: systemPrompt
2480
+ schema,
2481
+ system: [
2482
+ rest.system ?? "",
2483
+ "You MUST respond with valid JSON matching this schema:",
2484
+ JSON.stringify(jsonSchema, null, 2),
2485
+ "Respond ONLY with the JSON object, no markdown or explanation."
2486
+ ].filter(Boolean).join(`
2487
+
2488
+ `)
2178
2489
  });
2179
- const text = typeof response.message.content === "string" ? response.message.content : "";
2180
- const jsonMatch = text.match(/\{[\s\S]*\}/);
2181
- if (!jsonMatch) {
2182
- throw ElsiumError.validation("LLM response did not contain valid JSON", {
2183
- response: text
2184
- });
2490
+ let parsed;
2491
+ if (response.stopReason === "tool_use" && response.message.toolCalls?.length) {
2492
+ const structuredCall = response.message.toolCalls.find((tc) => tc.name === "_structured_output");
2493
+ if (structuredCall) {
2494
+ parsed = structuredCall.arguments;
2495
+ }
2496
+ }
2497
+ if (parsed === undefined) {
2498
+ const text = typeof response.message.content === "string" ? response.message.content : "";
2499
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
2500
+ if (!jsonMatch) {
2501
+ throw ElsiumError.validation("LLM response did not contain valid JSON", {
2502
+ response: text
2503
+ });
2504
+ }
2505
+ parsed = JSON.parse(jsonMatch[0]);
2185
2506
  }
2186
- const parsed = JSON.parse(jsonMatch[0]);
2187
2507
  const result = schema.safeParse(parsed);
2188
2508
  if (!result.success) {
2189
2509
  throw ElsiumError.validation("LLM response did not match schema", {
2190
- errors: result.error.issues,
2191
- response: text
2510
+ errors: result.error.issues
2192
2511
  });
2193
2512
  }
2194
2513
  return { data: result.data, response };
2195
2514
  }
2196
2515
  };
2197
2516
  }
2198
- function schemaToJsonSchema(schema) {
2199
- try {
2200
- if ("_def" in schema) {
2201
- const def = schema._def;
2202
- const result = convertZodDef(def);
2203
- if (result)
2204
- return result;
2205
- }
2206
- } catch {}
2207
- return { type: "string" };
2208
- }
2209
- function zodDefKind(def) {
2210
- return typeof def.type === "string" ? def.type : def.typeName;
2211
- }
2212
- function convertZodDef(def) {
2213
- const kind = zodDefKind(def);
2214
- switch (kind) {
2215
- case "object":
2216
- case "ZodObject":
2217
- return convertZodObject(def);
2218
- case "string":
2219
- case "ZodString":
2220
- return { type: "string" };
2221
- case "number":
2222
- case "ZodNumber":
2223
- return { type: "number" };
2224
- case "boolean":
2225
- case "ZodBoolean":
2226
- return { type: "boolean" };
2227
- case "array":
2228
- case "ZodArray":
2229
- return convertZodArray(def);
2230
- case "enum":
2231
- case "ZodEnum": {
2232
- const values = def.values ?? (def.entries ? Object.values(def.entries) : []);
2233
- return { type: "string", enum: values };
2234
- }
2235
- case "optional":
2236
- case "ZodOptional":
2237
- return convertZodOptional(def);
2238
- default:
2239
- return null;
2240
- }
2241
- }
2242
- function convertZodObject(def) {
2243
- if (!def.shape)
2244
- return null;
2245
- const shape = typeof def.shape === "function" ? def.shape() : def.shape;
2246
- const properties = {};
2247
- const required = [];
2248
- for (const [key, value] of Object.entries(shape)) {
2249
- properties[key] = schemaToJsonSchema(value);
2250
- const valDef = value._def;
2251
- const valKind = zodDefKind(valDef);
2252
- if (valKind !== "optional" && valKind !== "ZodOptional") {
2253
- required.push(key);
2254
- }
2255
- }
2256
- return { type: "object", properties, required };
2257
- }
2258
- function convertZodArray(def) {
2259
- return {
2260
- type: "array",
2261
- items: schemaToJsonSchema(def.element ?? def.type)
2262
- };
2263
- }
2264
- function convertZodOptional(def) {
2265
- return schemaToJsonSchema(def.innerType ?? def.innerType);
2266
- }
2267
2517
  // ../gateway/src/security.ts
2268
2518
  var INJECTION_PATTERNS = [
2269
2519
  {
@@ -2514,6 +2764,321 @@ function securityMiddleware(config) {
2514
2764
  return response;
2515
2765
  };
2516
2766
  }
2767
+ // ../gateway/src/cache.ts
2768
+ import { createHash } from "node:crypto";
2769
+ var log4 = createLogger();
2770
+ function createInMemoryCache(maxSize = 1000) {
2771
+ const cache = new Map;
2772
+ function evict() {
2773
+ if (cache.size <= maxSize)
2774
+ return;
2775
+ const firstKey = cache.keys().next().value;
2776
+ if (firstKey !== undefined)
2777
+ cache.delete(firstKey);
2778
+ }
2779
+ return {
2780
+ async get(key) {
2781
+ const entry = cache.get(key);
2782
+ if (!entry)
2783
+ return null;
2784
+ if (Date.now() > entry.expiresAt) {
2785
+ cache.delete(key);
2786
+ return null;
2787
+ }
2788
+ cache.delete(key);
2789
+ cache.set(key, entry);
2790
+ return entry.value;
2791
+ },
2792
+ async set(key, value, ttlMs) {
2793
+ cache.set(key, { value, expiresAt: Date.now() + ttlMs });
2794
+ evict();
2795
+ },
2796
+ async delete(key) {
2797
+ cache.delete(key);
2798
+ },
2799
+ async clear() {
2800
+ cache.clear();
2801
+ }
2802
+ };
2803
+ }
2804
+ function defaultCacheKey(ctx) {
2805
+ const data = JSON.stringify({
2806
+ provider: ctx.provider,
2807
+ model: ctx.model,
2808
+ messages: ctx.request.messages,
2809
+ system: ctx.request.system,
2810
+ temperature: ctx.request.temperature
2811
+ });
2812
+ return createHash("sha256").update(data).digest("hex");
2813
+ }
2814
+ function defaultShouldCache(_ctx, response) {
2815
+ const temp = _ctx.request.temperature;
2816
+ if (temp !== undefined && temp !== 0)
2817
+ return false;
2818
+ return response.stopReason === "end_turn";
2819
+ }
2820
+ function cacheMiddleware(config) {
2821
+ const ttlMs = config?.ttlMs ?? 3600000;
2822
+ const adapter = config?.adapter ?? createInMemoryCache(config?.maxSize ?? 1000);
2823
+ const keyFn = config?.keyFn ?? defaultCacheKey;
2824
+ const shouldCache = config?.shouldCache ?? defaultShouldCache;
2825
+ let hits = 0;
2826
+ let misses = 0;
2827
+ const middleware = async (ctx, next) => {
2828
+ if (ctx.request.stream) {
2829
+ return next(ctx);
2830
+ }
2831
+ const key = keyFn(ctx);
2832
+ const cached = await adapter.get(key);
2833
+ if (cached) {
2834
+ hits++;
2835
+ log4.debug("Cache hit", { key: key.slice(0, 8), provider: ctx.provider });
2836
+ return cached;
2837
+ }
2838
+ misses++;
2839
+ const response = await next(ctx);
2840
+ if (shouldCache(ctx, response)) {
2841
+ await adapter.set(key, response, ttlMs);
2842
+ }
2843
+ return response;
2844
+ };
2845
+ return Object.assign(middleware, {
2846
+ adapter,
2847
+ stats() {
2848
+ const total = hits + misses;
2849
+ return {
2850
+ hits,
2851
+ misses,
2852
+ size: 0,
2853
+ hitRate: total > 0 ? hits / total : 0
2854
+ };
2855
+ }
2856
+ });
2857
+ }
2858
+ // ../gateway/src/output-guardrails.ts
2859
+ var log5 = createLogger();
2860
+ var PII_PATTERNS2 = [
2861
+ {
2862
+ pattern: /\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/g,
2863
+ label: "email",
2864
+ replacement: "[REDACTED_EMAIL]"
2865
+ },
2866
+ {
2867
+ pattern: /(?:\+?1[-.\s]?)?\(?\d{3}\)?[-.\s]?\d{3}[-.\s]?\d{4}\b/g,
2868
+ label: "phone",
2869
+ replacement: "[REDACTED_PHONE]"
2870
+ },
2871
+ {
2872
+ pattern: /\b\d{3}-\d{2}-\d{4}\b/g,
2873
+ label: "ssn",
2874
+ replacement: "[REDACTED_SSN]"
2875
+ },
2876
+ {
2877
+ pattern: /\b\d{4}[\s-]?\d{4}[\s-]?\d{4}[\s-]?\d{4}\b/g,
2878
+ label: "credit_card",
2879
+ replacement: "[REDACTED_CC]"
2880
+ }
2881
+ ];
2882
+ var SECRET_PATTERNS2 = [
2883
+ {
2884
+ pattern: /\bsk-[A-Za-z0-9]{20,}\b/g,
2885
+ label: "api_key",
2886
+ replacement: "[REDACTED_API_KEY]"
2887
+ },
2888
+ {
2889
+ pattern: /\bpk-[A-Za-z0-9]{20,}\b/g,
2890
+ label: "api_key",
2891
+ replacement: "[REDACTED_API_KEY]"
2892
+ },
2893
+ {
2894
+ pattern: /\bAKIA[A-Z0-9]{16}\b/g,
2895
+ label: "aws_key",
2896
+ replacement: "[REDACTED_AWS_KEY]"
2897
+ }
2898
+ ];
2899
+ function detectPII(text) {
2900
+ const violations = [];
2901
+ const normalized = text.normalize("NFKC");
2902
+ for (const { pattern, label } of [...PII_PATTERNS2, ...SECRET_PATTERNS2]) {
2903
+ const regex = new RegExp(pattern.source, pattern.flags);
2904
+ if (regex.test(normalized)) {
2905
+ violations.push({
2906
+ type: "pii",
2907
+ detail: `Detected ${label} in output`,
2908
+ pattern: label
2909
+ });
2910
+ }
2911
+ }
2912
+ return violations;
2913
+ }
2914
+ function redactPII(text) {
2915
+ let result = text;
2916
+ for (const { pattern, replacement } of [...PII_PATTERNS2, ...SECRET_PATTERNS2]) {
2917
+ const regex = new RegExp(pattern.source, pattern.flags);
2918
+ result = result.replace(regex, replacement);
2919
+ }
2920
+ return result;
2921
+ }
2922
+ function checkContentPolicy(text, policy) {
2923
+ const violations = [];
2924
+ if (policy.maxResponseLength && text.length > policy.maxResponseLength) {
2925
+ violations.push({
2926
+ type: "content_policy",
2927
+ detail: `Response length ${text.length} exceeds max ${policy.maxResponseLength}`
2928
+ });
2929
+ }
2930
+ if (policy.blockedPatterns) {
2931
+ for (const pattern of policy.blockedPatterns) {
2932
+ if (pattern.test(text)) {
2933
+ violations.push({
2934
+ type: "content_policy",
2935
+ detail: `Response matches blocked pattern: ${pattern.source}`,
2936
+ pattern: pattern.source
2937
+ });
2938
+ }
2939
+ }
2940
+ }
2941
+ return violations;
2942
+ }
2943
+ function checkCustomRules(text, rules) {
2944
+ const violations = [];
2945
+ for (const rule of rules) {
2946
+ if (rule.pattern.test(text)) {
2947
+ violations.push({
2948
+ type: "custom_rule",
2949
+ detail: rule.message ?? `Output matched custom rule: ${rule.name}`,
2950
+ pattern: rule.pattern.source
2951
+ });
2952
+ }
2953
+ }
2954
+ return violations;
2955
+ }
2956
+ function outputGuardrailMiddleware(config) {
2957
+ const mode = config.onViolation ?? "block";
2958
+ return async (ctx, next) => {
2959
+ const response = await next(ctx);
2960
+ const text = extractText(response.message.content);
2961
+ const violations = [];
2962
+ if (config.piiDetection) {
2963
+ violations.push(...detectPII(text));
2964
+ }
2965
+ if (config.contentPolicy) {
2966
+ violations.push(...checkContentPolicy(text, config.contentPolicy));
2967
+ }
2968
+ if (config.customRules?.length) {
2969
+ violations.push(...checkCustomRules(text, config.customRules));
2970
+ }
2971
+ if (violations.length === 0)
2972
+ return response;
2973
+ for (const v of violations) {
2974
+ config.onViolationCallback?.(v);
2975
+ }
2976
+ switch (mode) {
2977
+ case "block":
2978
+ throw ElsiumError.validation(`Output guardrail violation: ${violations.map((v) => v.detail).join("; ")}`, { violations });
2979
+ case "redact": {
2980
+ let redacted = text;
2981
+ if (config.piiDetection) {
2982
+ redacted = redactPII(redacted);
2983
+ }
2984
+ return {
2985
+ ...response,
2986
+ message: { ...response.message, content: redacted }
2987
+ };
2988
+ }
2989
+ case "warn":
2990
+ log5.warn("Output guardrail violations detected", { violations });
2991
+ return response;
2992
+ }
2993
+ };
2994
+ }
2995
+ // ../gateway/src/batch.ts
2996
+ var log6 = createLogger();
2997
+ function createBatch(gateway2, config) {
2998
+ const concurrency = config?.concurrency ?? 5;
2999
+ const retryPerItem = config?.retryPerItem ?? 0;
3000
+ return {
3001
+ async execute(requests) {
3002
+ const startTime = performance.now();
3003
+ const results = new Array(requests.length);
3004
+ let completed = 0;
3005
+ let totalSucceeded = 0;
3006
+ let totalFailed = 0;
3007
+ let running = 0;
3008
+ let nextIndex = 0;
3009
+ const signal = config?.signal;
3010
+ async function processItem(index) {
3011
+ if (signal?.aborted) {
3012
+ results[index] = {
3013
+ index,
3014
+ success: false,
3015
+ error: "Batch cancelled"
3016
+ };
3017
+ totalFailed++;
3018
+ return;
3019
+ }
3020
+ let lastError;
3021
+ for (let attempt = 0;attempt <= retryPerItem; attempt++) {
3022
+ try {
3023
+ const response = await gateway2.complete(requests[index]);
3024
+ results[index] = { index, success: true, response };
3025
+ totalSucceeded++;
3026
+ return;
3027
+ } catch (err2) {
3028
+ lastError = err2 instanceof Error ? err2.message : String(err2);
3029
+ if (attempt < retryPerItem && err2 instanceof ElsiumError && err2.retryable) {
3030
+ continue;
3031
+ }
3032
+ break;
3033
+ }
3034
+ }
3035
+ results[index] = { index, success: false, error: lastError };
3036
+ totalFailed++;
3037
+ }
3038
+ return new Promise((resolve) => {
3039
+ function scheduleNext() {
3040
+ while (running < concurrency && nextIndex < requests.length) {
3041
+ if (signal?.aborted) {
3042
+ for (let i = nextIndex;i < requests.length; i++) {
3043
+ results[i] = { index: i, success: false, error: "Batch cancelled" };
3044
+ totalFailed++;
3045
+ }
3046
+ nextIndex = requests.length;
3047
+ break;
3048
+ }
3049
+ const idx = nextIndex++;
3050
+ running++;
3051
+ processItem(idx).then(() => {
3052
+ running--;
3053
+ completed++;
3054
+ config?.onProgress?.(completed, requests.length);
3055
+ if (completed === requests.length) {
3056
+ resolve({
3057
+ results,
3058
+ totalSucceeded,
3059
+ totalFailed,
3060
+ totalDurationMs: Math.round(performance.now() - startTime)
3061
+ });
3062
+ } else {
3063
+ scheduleNext();
3064
+ }
3065
+ });
3066
+ }
3067
+ }
3068
+ if (requests.length === 0) {
3069
+ resolve({
3070
+ results: [],
3071
+ totalSucceeded: 0,
3072
+ totalFailed: 0,
3073
+ totalDurationMs: 0
3074
+ });
3075
+ return;
3076
+ }
3077
+ scheduleNext();
3078
+ });
3079
+ }
3080
+ };
3081
+ }
2517
3082
  // ../gateway/src/router.ts
2518
3083
  var REASONING_KEYWORDS = /\b(prove|explain why|analyze|compare|contrast|evaluate|critique|debate|reason|deduce|infer|justify|argue|synthesize|hypothesize|derive)\b/i;
2519
3084
  var CODE_KEYWORDS = /\b(implement|refactor|debug|optimize|architect|design pattern|algorithm|data structure|write code|code review|fix the bug|type system)\b/i;
@@ -2762,7 +3327,6 @@ function createProviderMesh(config) {
2762
3327
  };
2763
3328
  }
2764
3329
  // ../tools/src/define.ts
2765
- var log2 = createLogger();
2766
3330
  function defineTool(config) {
2767
3331
  const { name, description, input, output, handler, timeoutMs = 30000 } = config;
2768
3332
  return {
@@ -2811,114 +3375,31 @@ function defineTool(config) {
2811
3375
  }
2812
3376
  }
2813
3377
  return {
2814
- success: true,
2815
- data: result,
2816
- toolCallId,
2817
- durationMs: Math.round(performance.now() - startTime)
2818
- };
2819
- } catch (error) {
2820
- const message = error instanceof Error ? error.message : String(error);
2821
- return {
2822
- success: false,
2823
- error: message,
2824
- toolCallId,
2825
- durationMs: Math.round(performance.now() - startTime)
2826
- };
2827
- } finally {
2828
- clearTimeout(timer);
2829
- }
2830
- },
2831
- toDefinition() {
2832
- return {
2833
- name,
2834
- description,
2835
- inputSchema: zodToJsonSchema(input)
2836
- };
2837
- }
2838
- };
2839
- }
2840
- function zodDefKind2(def) {
2841
- return typeof def.type === "string" ? def.type : def.typeName;
2842
- }
2843
- function zodObjectToJsonSchema(def) {
2844
- const shape = typeof def.shape === "function" ? def.shape() : def.shape;
2845
- const properties = {};
2846
- const required = [];
2847
- for (const [key, value] of Object.entries(shape)) {
2848
- const fieldSchema = value;
2849
- properties[key] = zodToJsonSchema(fieldSchema);
2850
- const fieldDef = fieldSchema._def;
2851
- const fieldKind = zodDefKind2(fieldDef);
2852
- if (fieldKind !== "optional" && fieldKind !== "ZodOptional" && fieldKind !== "default" && fieldKind !== "ZodDefault") {
2853
- required.push(key);
2854
- }
2855
- if (fieldDef.description) {
2856
- properties[key].description = fieldDef.description;
2857
- }
2858
- }
2859
- return { type: "object", properties, required };
2860
- }
2861
- function zodToJsonSchema(schema) {
2862
- if (!("_def" in schema))
2863
- return { type: "object" };
2864
- const def = schema._def;
2865
- const kind = zodDefKind2(def);
2866
- switch (kind) {
2867
- case "object":
2868
- case "ZodObject":
2869
- return zodObjectToJsonSchema(def);
2870
- case "string":
2871
- case "ZodString":
2872
- return { type: "string" };
2873
- case "number":
2874
- case "ZodNumber":
2875
- return { type: "number" };
2876
- case "boolean":
2877
- case "ZodBoolean":
2878
- return { type: "boolean" };
2879
- case "array":
2880
- case "ZodArray":
2881
- return {
2882
- type: "array",
2883
- items: zodToJsonSchema(def.element ?? def.type)
2884
- };
2885
- case "enum":
2886
- case "ZodEnum": {
2887
- const values = def.values ?? (def.entries ? Object.values(def.entries) : []);
2888
- return { type: "string", enum: values };
2889
- }
2890
- case "optional":
2891
- case "ZodOptional":
2892
- return zodToJsonSchema(def.innerType);
2893
- case "default":
2894
- case "ZodDefault":
2895
- return zodToJsonSchema(def.innerType);
2896
- case "nullable":
2897
- case "ZodNullable": {
2898
- const inner = zodToJsonSchema(def.innerType);
2899
- return { ...inner, nullable: true };
2900
- }
2901
- case "ZodLiteral":
2902
- return { type: typeof def.value, const: def.value };
2903
- case "ZodUnion": {
2904
- const options = def.options.map(zodToJsonSchema);
2905
- return { anyOf: options };
2906
- }
2907
- case "ZodRecord":
3378
+ success: true,
3379
+ data: result,
3380
+ toolCallId,
3381
+ durationMs: Math.round(performance.now() - startTime)
3382
+ };
3383
+ } catch (error) {
3384
+ const message = error instanceof Error ? error.message : String(error);
3385
+ return {
3386
+ success: false,
3387
+ error: message,
3388
+ toolCallId,
3389
+ durationMs: Math.round(performance.now() - startTime)
3390
+ };
3391
+ } finally {
3392
+ clearTimeout(timer);
3393
+ }
3394
+ },
3395
+ toDefinition() {
2908
3396
  return {
2909
- type: "object",
2910
- additionalProperties: def.valueType ? zodToJsonSchema(def.valueType) : { type: "string" }
3397
+ name,
3398
+ description,
3399
+ inputSchema: zodToJsonSchema(input)
2911
3400
  };
2912
- case "ZodTuple": {
2913
- const items = (def.items ?? []).map(zodToJsonSchema);
2914
- return { type: "array", prefixItems: items, minItems: items.length, maxItems: items.length };
2915
3401
  }
2916
- case "ZodDate":
2917
- return { type: "string", format: "date-time" };
2918
- default:
2919
- log2.warn(`zodToJsonSchema: unsupported type ${kind}, defaulting to string`);
2920
- return { type: "string" };
2921
- }
3402
+ };
2922
3403
  }
2923
3404
  // ../tools/src/toolkit.ts
2924
3405
  function createToolkit(name, tools) {
@@ -7473,15 +7954,33 @@ function createMemory(config) {
7473
7954
  case "unlimited":
7474
7955
  break;
7475
7956
  }
7957
+ if (config.store && config.agentId) {
7958
+ config.store.save(config.agentId, [...messages]).catch(() => {});
7959
+ }
7476
7960
  },
7477
7961
  getMessages() {
7478
7962
  return [...messages];
7479
7963
  },
7480
7964
  clear() {
7481
7965
  messages.length = 0;
7966
+ if (config.store && config.agentId) {
7967
+ config.store.clear(config.agentId).catch(() => {});
7968
+ }
7482
7969
  },
7483
7970
  getTokenEstimate() {
7484
7971
  return messages.reduce((sum, m) => sum + estimateTokens(m), 0);
7972
+ },
7973
+ async loadFromStore() {
7974
+ if (!config.store || !config.agentId)
7975
+ return;
7976
+ const stored = await config.store.load(config.agentId);
7977
+ messages.length = 0;
7978
+ messages.push(...stored);
7979
+ },
7980
+ async saveToStore() {
7981
+ if (!config.store || !config.agentId)
7982
+ return;
7983
+ await config.store.save(config.agentId, [...messages]);
7485
7984
  }
7486
7985
  };
7487
7986
  }
@@ -7527,7 +8026,7 @@ var JAILBREAK_PATTERNS2 = [
7527
8026
  detail: "Opposite mode jailbreak attempt"
7528
8027
  }
7529
8028
  ];
7530
- var SECRET_PATTERNS2 = [
8029
+ var SECRET_PATTERNS3 = [
7531
8030
  {
7532
8031
  pattern: /\bsk-[a-zA-Z0-9_-]{20,}\b/g,
7533
8032
  detail: "API secret key detected",
@@ -7605,7 +8104,7 @@ function createAgentSecurity(config) {
7605
8104
  const violations = [];
7606
8105
  let redactedOutput = output;
7607
8106
  if (config.redactSecrets !== false) {
7608
- for (const { pattern, detail, replacement } of SECRET_PATTERNS2) {
8107
+ for (const { pattern, detail, replacement } of SECRET_PATTERNS3) {
7609
8108
  const regex = new RegExp(pattern.source, pattern.flags);
7610
8109
  if (regex.test(redactedOutput)) {
7611
8110
  violations.push({ type: "secret_detected", detail, severity: "medium" });
@@ -8318,6 +8817,104 @@ function defineAgent(config, deps) {
8318
8817
  }
8319
8818
  };
8320
8819
  }
8820
+ // ../agents/src/stores/memory-store.ts
8821
+ function createInMemoryMemoryStore() {
8822
+ const store = new Map;
8823
+ return {
8824
+ async load(agentId) {
8825
+ return [...store.get(agentId) ?? []];
8826
+ },
8827
+ async save(agentId, messages) {
8828
+ store.set(agentId, [...messages]);
8829
+ },
8830
+ async clear(agentId) {
8831
+ store.delete(agentId);
8832
+ }
8833
+ };
8834
+ }
8835
+ // ../agents/src/stores/sqlite-store.ts
8836
+ import { createRequire } from "node:module";
8837
+ var require2 = createRequire(import.meta.url);
8838
+ var log7 = createLogger();
8839
+ var BLOCKED_KEYS2 = new Set(["__proto__", "constructor", "prototype"]);
8840
+ var TABLE_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
8841
+ function createSqliteMemoryStore(config) {
8842
+ const { path, tableName = "agent_memory" } = config;
8843
+ if (BLOCKED_KEYS2.has(tableName)) {
8844
+ throw new Error(`Invalid table name: ${tableName}`);
8845
+ }
8846
+ if (!TABLE_NAME_PATTERN.test(tableName)) {
8847
+ throw new Error(`Invalid table name format: ${tableName}`);
8848
+ }
8849
+ let db = null;
8850
+ let initPromise = null;
8851
+ async function getDb() {
8852
+ if (db)
8853
+ return db;
8854
+ if (initPromise)
8855
+ return initPromise;
8856
+ initPromise = (async () => {
8857
+ try {
8858
+ const Database = require2("better-sqlite3");
8859
+ db = new Database(path);
8860
+ db.exec(`
8861
+ CREATE TABLE IF NOT EXISTS ${tableName} (
8862
+ agent_id TEXT NOT NULL,
8863
+ idx INTEGER NOT NULL,
8864
+ role TEXT NOT NULL,
8865
+ content TEXT NOT NULL,
8866
+ metadata TEXT,
8867
+ created_at INTEGER NOT NULL DEFAULT (unixepoch()),
8868
+ PRIMARY KEY (agent_id, idx)
8869
+ )
8870
+ `);
8871
+ return db;
8872
+ } catch (err2) {
8873
+ initPromise = null;
8874
+ log7.error("Failed to initialize SQLite memory store", {
8875
+ error: err2 instanceof Error ? err2.message : String(err2)
8876
+ });
8877
+ throw new Error("better-sqlite3 is required for SQLite memory store. Install it as a dependency.");
8878
+ }
8879
+ })();
8880
+ return initPromise;
8881
+ }
8882
+ return {
8883
+ async load(agentId) {
8884
+ if (BLOCKED_KEYS2.has(agentId))
8885
+ return [];
8886
+ const database = await getDb();
8887
+ const rows = database.prepare(`SELECT role, content, metadata FROM ${tableName} WHERE agent_id = ? ORDER BY idx`).all(agentId);
8888
+ return rows.map((row) => {
8889
+ const msg = {
8890
+ role: row.role,
8891
+ content: JSON.parse(row.content)
8892
+ };
8893
+ if (row.metadata) {
8894
+ msg.metadata = JSON.parse(row.metadata);
8895
+ }
8896
+ return msg;
8897
+ });
8898
+ },
8899
+ async save(agentId, messages) {
8900
+ if (BLOCKED_KEYS2.has(agentId))
8901
+ return;
8902
+ const database = await getDb();
8903
+ database.prepare(`DELETE FROM ${tableName} WHERE agent_id = ?`).run(agentId);
8904
+ const insert = database.prepare(`INSERT INTO ${tableName} (agent_id, idx, role, content, metadata) VALUES (?, ?, ?, ?, ?)`);
8905
+ for (let i = 0;i < messages.length; i++) {
8906
+ const msg = messages[i];
8907
+ insert.run(agentId, i, msg.role, JSON.stringify(msg.content), msg.metadata ? JSON.stringify(msg.metadata) : null);
8908
+ }
8909
+ },
8910
+ async clear(agentId) {
8911
+ if (BLOCKED_KEYS2.has(agentId))
8912
+ return;
8913
+ const database = await getDb();
8914
+ database.prepare(`DELETE FROM ${tableName} WHERE agent_id = ?`).run(agentId);
8915
+ }
8916
+ };
8917
+ }
8321
8918
  // ../agents/src/multi.ts
8322
8919
  async function runSequential(agents, input, options) {
8323
8920
  const results = [];
@@ -8815,7 +9412,11 @@ function createMockEmbeddings(dims = 128) {
8815
9412
  }
8816
9413
  };
8817
9414
  }
9415
+ var embeddingProviderRegistry = createRegistry("embeddingProvider");
8818
9416
  function getEmbeddingProvider(config) {
9417
+ const registered = embeddingProviderRegistry.get(config.provider);
9418
+ if (registered)
9419
+ return registered(config);
8819
9420
  switch (config.provider) {
8820
9421
  case "openai":
8821
9422
  return createOpenAIEmbeddings(config);
@@ -8824,12 +9425,13 @@ function getEmbeddingProvider(config) {
8824
9425
  default:
8825
9426
  throw new ElsiumError({
8826
9427
  code: "CONFIG_ERROR",
8827
- message: `Unknown embedding provider: ${config.provider}`,
9428
+ message: `Unknown embedding provider: ${config.provider}. Available: openai, mock${embeddingProviderRegistry.list().length ? `, ${embeddingProviderRegistry.list().join(", ")}` : ""}`,
8828
9429
  retryable: false
8829
9430
  });
8830
9431
  }
8831
9432
  }
8832
9433
  // ../rag/src/vectorstore.ts
9434
+ var vectorStoreRegistry = createRegistry("vectorStore");
8833
9435
  function cosineSimilarity(a, b) {
8834
9436
  if (a.length !== b.length)
8835
9437
  return 0;
@@ -8963,6 +9565,123 @@ function rag(config) {
8963
9565
  }
8964
9566
  };
8965
9567
  }
9568
+ // ../rag/src/stores/pgvector.ts
9569
+ import { createRequire as createRequire2 } from "node:module";
9570
+ var require3 = createRequire2(import.meta.url);
9571
+ var log8 = createLogger();
9572
+ var BLOCKED_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
9573
+ var TABLE_NAME_PATTERN2 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
9574
+ function createPgVectorStore(config) {
9575
+ const { connectionString, tableName = "vector_chunks", dimensions = 1536 } = config;
9576
+ if (BLOCKED_KEYS3.has(tableName)) {
9577
+ throw new Error(`Invalid table name: ${tableName}`);
9578
+ }
9579
+ if (!TABLE_NAME_PATTERN2.test(tableName)) {
9580
+ throw new Error(`Invalid table name format: ${tableName}`);
9581
+ }
9582
+ let client = null;
9583
+ let initialized = false;
9584
+ async function getClient() {
9585
+ if (client)
9586
+ return client;
9587
+ try {
9588
+ const pg = require3("pg");
9589
+ client = new pg.Client({ connectionString });
9590
+ await client.connect();
9591
+ if (!initialized) {
9592
+ await client.query("CREATE EXTENSION IF NOT EXISTS vector");
9593
+ await client.query(`
9594
+ CREATE TABLE IF NOT EXISTS ${tableName} (
9595
+ id TEXT PRIMARY KEY,
9596
+ content TEXT NOT NULL,
9597
+ document_id TEXT NOT NULL,
9598
+ chunk_index INTEGER NOT NULL,
9599
+ metadata JSONB DEFAULT '{}',
9600
+ embedding vector(${dimensions})
9601
+ )
9602
+ `);
9603
+ initialized = true;
9604
+ }
9605
+ return client;
9606
+ } catch (err2) {
9607
+ log8.error("Failed to initialize PgVector store", {
9608
+ error: err2 instanceof Error ? err2.message : String(err2)
9609
+ });
9610
+ throw new Error("pg is required for PgVector store. Install it as a dependency.");
9611
+ }
9612
+ }
9613
+ return {
9614
+ name: "pgvector",
9615
+ async upsert(chunks) {
9616
+ const pg = await getClient();
9617
+ for (const chunk of chunks) {
9618
+ if (BLOCKED_KEYS3.has(chunk.id))
9619
+ continue;
9620
+ const embedding = `[${chunk.embedding.values.join(",")}]`;
9621
+ await pg.query(`INSERT INTO ${tableName} (id, content, document_id, chunk_index, metadata, embedding)
9622
+ VALUES ($1, $2, $3, $4, $5, $6)
9623
+ ON CONFLICT (id) DO UPDATE SET
9624
+ content = EXCLUDED.content,
9625
+ document_id = EXCLUDED.document_id,
9626
+ chunk_index = EXCLUDED.chunk_index,
9627
+ metadata = EXCLUDED.metadata,
9628
+ embedding = EXCLUDED.embedding`, [
9629
+ chunk.id,
9630
+ chunk.content,
9631
+ chunk.documentId,
9632
+ chunk.index,
9633
+ JSON.stringify(chunk.metadata),
9634
+ embedding
9635
+ ]);
9636
+ }
9637
+ },
9638
+ async query(embedding, options) {
9639
+ const pg = await getClient();
9640
+ const topK = options?.topK ?? 5;
9641
+ const minScore = options?.minScore ?? 0;
9642
+ const embeddingStr = `[${embedding.values.join(",")}]`;
9643
+ const result = await pg.query(`SELECT id, content, document_id, chunk_index, metadata,
9644
+ 1 - (embedding <=> $1::vector) as score
9645
+ FROM ${tableName}
9646
+ WHERE 1 - (embedding <=> $1::vector) >= $2
9647
+ ORDER BY embedding <=> $1::vector
9648
+ LIMIT $3`, [embeddingStr, minScore, topK]);
9649
+ return result.rows.map((row) => ({
9650
+ chunk: {
9651
+ id: row.id,
9652
+ content: row.content,
9653
+ documentId: row.document_id,
9654
+ index: row.chunk_index,
9655
+ metadata: {
9656
+ startChar: 0,
9657
+ endChar: 0,
9658
+ tokenEstimate: 0,
9659
+ ...row.metadata ?? {}
9660
+ }
9661
+ },
9662
+ score: row.score,
9663
+ distance: 1 - row.score
9664
+ }));
9665
+ },
9666
+ async delete(ids) {
9667
+ const pg = await getClient();
9668
+ const filtered = ids.filter((id) => !BLOCKED_KEYS3.has(id));
9669
+ if (filtered.length === 0)
9670
+ return;
9671
+ const placeholders = filtered.map((_, i) => `$${i + 1}`).join(", ");
9672
+ await pg.query(`DELETE FROM ${tableName} WHERE id IN (${placeholders})`, filtered);
9673
+ },
9674
+ async clear() {
9675
+ const pg = await getClient();
9676
+ await pg.query(`DELETE FROM ${tableName}`);
9677
+ },
9678
+ async count() {
9679
+ const pg = await getClient();
9680
+ const result = await pg.query(`SELECT COUNT(*)::int as count FROM ${tableName}`);
9681
+ return result.rows[0]?.count ?? 0;
9682
+ }
9683
+ };
9684
+ }
8966
9685
  // ../workflows/src/step.ts
8967
9686
  function step(name, config) {
8968
9687
  return { name, ...config };
@@ -9545,7 +10264,7 @@ function createCostEngine(config = {}) {
9545
10264
  }
9546
10265
  // ../observe/src/tracer.ts
9547
10266
  import { writeFileSync } from "node:fs";
9548
- var log3 = createLogger();
10267
+ var log9 = createLogger();
9549
10268
  function observe(config = {}) {
9550
10269
  const {
9551
10270
  output = ["console"],
@@ -9568,7 +10287,7 @@ function observe(config = {}) {
9568
10287
  try {
9569
10288
  writeFileSync(filename, JSON.stringify(spansToExport, null, 2));
9570
10289
  } catch (err2) {
9571
- log3.error("Failed to write trace file", {
10290
+ log9.error("Failed to write trace file", {
9572
10291
  error: err2 instanceof Error ? err2.message : String(err2)
9573
10292
  });
9574
10293
  }
@@ -9643,7 +10362,7 @@ function observe(config = {}) {
9643
10362
  function consoleHandler(span) {
9644
10363
  const duration = span.durationMs !== undefined ? `${span.durationMs}ms` : "running";
9645
10364
  const status = span.status === "error" ? "[ERROR]" : span.status === "ok" ? "[OK]" : "[...]";
9646
- log3.info("span", {
10365
+ log9.info("span", {
9647
10366
  trace: span.traceId,
9648
10367
  span: span.name,
9649
10368
  kind: span.kind,
@@ -9741,8 +10460,86 @@ function createMetrics(options) {
9741
10460
  }
9742
10461
  };
9743
10462
  }
10463
+ // ../observe/src/experiment.ts
10464
+ import { createHash as createHash2 } from "node:crypto";
10465
+ var log10 = createLogger();
10466
+ function createExperiment(config) {
10467
+ const { name, variants } = config;
10468
+ if (variants.length === 0) {
10469
+ throw new Error("Experiment must have at least one variant");
10470
+ }
10471
+ const totalWeight = variants.reduce((sum, v) => sum + v.weight, 0);
10472
+ const stats = {};
10473
+ for (const v of variants) {
10474
+ stats[v.name] = { assignments: 0, metrics: {} };
10475
+ }
10476
+ function hashAssign(userId) {
10477
+ const hash = createHash2("sha256").update(`${name}:${userId}`).digest();
10478
+ const value = hash.readUInt32BE(0) % 1e4 / 1e4;
10479
+ return pickVariant(value);
10480
+ }
10481
+ function randomAssign() {
10482
+ const value = Math.random();
10483
+ return pickVariant(value);
10484
+ }
10485
+ function pickVariant(value) {
10486
+ let cumulative = 0;
10487
+ for (const v of variants) {
10488
+ cumulative += v.weight / totalWeight;
10489
+ if (value < cumulative)
10490
+ return v;
10491
+ }
10492
+ return variants[variants.length - 1];
10493
+ }
10494
+ return {
10495
+ assign(userId) {
10496
+ const variant = userId ? hashAssign(userId) : randomAssign();
10497
+ const s = stats[variant.name];
10498
+ if (s)
10499
+ s.assignments++;
10500
+ log10.debug("Experiment assignment", {
10501
+ experiment: name,
10502
+ variant: variant.name,
10503
+ userId
10504
+ });
10505
+ return variant;
10506
+ },
10507
+ record(variant, metrics) {
10508
+ const s = stats[variant];
10509
+ if (!s)
10510
+ return;
10511
+ for (const [key, value] of Object.entries(metrics)) {
10512
+ if (!s.metrics[key]) {
10513
+ s.metrics[key] = { sum: 0, count: 0 };
10514
+ }
10515
+ s.metrics[key].sum += value;
10516
+ s.metrics[key].count++;
10517
+ }
10518
+ },
10519
+ results() {
10520
+ let totalAssignments = 0;
10521
+ const variantResults = {};
10522
+ for (const [vName, s] of Object.entries(stats)) {
10523
+ totalAssignments += s.assignments;
10524
+ const metricsResult = {};
10525
+ for (const [key, m] of Object.entries(s.metrics)) {
10526
+ metricsResult[key] = {
10527
+ sum: m.sum,
10528
+ count: m.count,
10529
+ avg: m.count > 0 ? m.sum / m.count : 0
10530
+ };
10531
+ }
10532
+ variantResults[vName] = {
10533
+ assignments: s.assignments,
10534
+ metrics: metricsResult
10535
+ };
10536
+ }
10537
+ return { name, totalAssignments, variants: variantResults };
10538
+ }
10539
+ };
10540
+ }
9744
10541
  // ../observe/src/otel.ts
9745
- var log4 = createLogger();
10542
+ var log11 = createLogger();
9746
10543
  var SPAN_KIND_MAP = {
9747
10544
  llm: 3,
9748
10545
  tool: 1,
@@ -9883,10 +10680,10 @@ function createOTLPExporter(config) {
9883
10680
  body: JSON.stringify(payload)
9884
10681
  });
9885
10682
  if (!response.ok) {
9886
- log4.error(`OTLP export failed: ${response.status} ${response.statusText}`);
10683
+ log11.error(`OTLP export failed: ${response.status} ${response.statusText}`);
9887
10684
  }
9888
10685
  } catch (err2) {
9889
- log4.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
10686
+ log11.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
9890
10687
  }
9891
10688
  }
9892
10689
  function startAutoFlush() {
@@ -12081,12 +12878,12 @@ function requestIdMiddleware() {
12081
12878
  };
12082
12879
  }
12083
12880
  function requestLoggerMiddleware(logger) {
12084
- const log5 = logger ?? createLogger();
12881
+ const log12 = logger ?? createLogger();
12085
12882
  return async (c, next) => {
12086
12883
  const start = Date.now();
12087
12884
  await next();
12088
12885
  const duration = Date.now() - start;
12089
- log5.info(`${c.req.method} ${c.req.path}`, {
12886
+ log12.info(`${c.req.method} ${c.req.path}`, {
12090
12887
  method: c.req.method,
12091
12888
  path: c.req.path,
12092
12889
  status: c.res.status,
@@ -12096,6 +12893,158 @@ function requestLoggerMiddleware(logger) {
12096
12893
  };
12097
12894
  }
12098
12895
 
12896
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/utils/stream.js
12897
+ var StreamingApi = class {
12898
+ writer;
12899
+ encoder;
12900
+ writable;
12901
+ abortSubscribers = [];
12902
+ responseReadable;
12903
+ aborted = false;
12904
+ closed = false;
12905
+ constructor(writable, _readable) {
12906
+ this.writable = writable;
12907
+ this.writer = writable.getWriter();
12908
+ this.encoder = new TextEncoder;
12909
+ const reader = _readable.getReader();
12910
+ this.abortSubscribers.push(async () => {
12911
+ await reader.cancel();
12912
+ });
12913
+ this.responseReadable = new ReadableStream({
12914
+ async pull(controller) {
12915
+ const { done, value } = await reader.read();
12916
+ done ? controller.close() : controller.enqueue(value);
12917
+ },
12918
+ cancel: () => {
12919
+ this.abort();
12920
+ }
12921
+ });
12922
+ }
12923
+ async write(input) {
12924
+ try {
12925
+ if (typeof input === "string") {
12926
+ input = this.encoder.encode(input);
12927
+ }
12928
+ await this.writer.write(input);
12929
+ } catch {}
12930
+ return this;
12931
+ }
12932
+ async writeln(input) {
12933
+ await this.write(input + `
12934
+ `);
12935
+ return this;
12936
+ }
12937
+ sleep(ms) {
12938
+ return new Promise((res) => setTimeout(res, ms));
12939
+ }
12940
+ async close() {
12941
+ try {
12942
+ await this.writer.close();
12943
+ } catch {}
12944
+ this.closed = true;
12945
+ }
12946
+ async pipe(body) {
12947
+ this.writer.releaseLock();
12948
+ await body.pipeTo(this.writable, { preventClose: true });
12949
+ this.writer = this.writable.getWriter();
12950
+ }
12951
+ onAbort(listener) {
12952
+ this.abortSubscribers.push(listener);
12953
+ }
12954
+ abort() {
12955
+ if (!this.aborted) {
12956
+ this.aborted = true;
12957
+ this.abortSubscribers.forEach((subscriber) => subscriber());
12958
+ }
12959
+ }
12960
+ };
12961
+
12962
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/helper/streaming/utils.js
12963
+ var isOldBunVersion = () => {
12964
+ const version = typeof Bun !== "undefined" ? Bun.version : undefined;
12965
+ if (version === undefined) {
12966
+ return false;
12967
+ }
12968
+ const result = version.startsWith("1.1") || version.startsWith("1.0") || version.startsWith("0.");
12969
+ isOldBunVersion = () => result;
12970
+ return result;
12971
+ };
12972
+
12973
+ // ../../node_modules/.bun/hono@4.12.3/node_modules/hono/dist/helper/streaming/stream.js
12974
+ var contextStash = /* @__PURE__ */ new WeakMap;
12975
+ var stream = (c, cb, onError) => {
12976
+ const { readable, writable } = new TransformStream;
12977
+ const stream2 = new StreamingApi(writable, readable);
12978
+ if (isOldBunVersion()) {
12979
+ c.req.raw.signal.addEventListener("abort", () => {
12980
+ if (!stream2.closed) {
12981
+ stream2.abort();
12982
+ }
12983
+ });
12984
+ }
12985
+ contextStash.set(stream2.responseReadable, c);
12986
+ (async () => {
12987
+ try {
12988
+ await cb(stream2);
12989
+ } catch (e) {
12990
+ if (e === undefined) {} else if (e instanceof Error && onError) {
12991
+ await onError(e, stream2);
12992
+ } else {
12993
+ console.error(e);
12994
+ }
12995
+ } finally {
12996
+ stream2.close();
12997
+ }
12998
+ })();
12999
+ return c.newResponse(stream2.responseReadable);
13000
+ };
13001
+
13002
+ // ../app/src/sse.ts
13003
+ function sseHeaders() {
13004
+ return {
13005
+ "Content-Type": "text/event-stream",
13006
+ "Cache-Control": "no-cache",
13007
+ Connection: "keep-alive",
13008
+ "X-Accel-Buffering": "no"
13009
+ };
13010
+ }
13011
+ function formatSSE(event, data) {
13012
+ const json = JSON.stringify(data);
13013
+ if (event === "message") {
13014
+ return `data: ${json}
13015
+
13016
+ `;
13017
+ }
13018
+ return `event: ${event}
13019
+ data: ${json}
13020
+
13021
+ `;
13022
+ }
13023
+ function streamResponse(c, source) {
13024
+ const headers = sseHeaders();
13025
+ for (const [key, value] of Object.entries(headers)) {
13026
+ c.header(key, value);
13027
+ }
13028
+ return stream(c, async (s) => {
13029
+ try {
13030
+ for await (const event of source) {
13031
+ const sseData = formatSSE("message", event);
13032
+ await s.write(sseData);
13033
+ }
13034
+ } catch (err2) {
13035
+ const errorEvent = {
13036
+ type: "error",
13037
+ error: err2 instanceof Error ? err2 : new Error(String(err2))
13038
+ };
13039
+ const sseData = formatSSE("error", {
13040
+ type: "error",
13041
+ message: errorEvent.error.message
13042
+ });
13043
+ await s.write(sseData);
13044
+ }
13045
+ });
13046
+ }
13047
+
12099
13048
  // ../app/src/routes.ts
12100
13049
  function parseJsonBody(raw2) {
12101
13050
  try {
@@ -12168,6 +13117,14 @@ function createRoutes(deps) {
12168
13117
  if ("error" in resolved) {
12169
13118
  return c.json({ error: resolved.error }, 404);
12170
13119
  }
13120
+ if (body.stream) {
13121
+ const stream2 = deps.gateway.stream({
13122
+ messages: [{ role: "user", content: body.message }],
13123
+ system: resolved.agent.config.system,
13124
+ model: resolved.agent.config.model
13125
+ });
13126
+ return streamResponse(c, stream2);
13127
+ }
12171
13128
  let result;
12172
13129
  try {
12173
13130
  result = await resolved.agent.run(body.message);
@@ -12214,6 +13171,16 @@ function createRoutes(deps) {
12214
13171
  role: m.role,
12215
13172
  content: m.content
12216
13173
  }));
13174
+ if (body.stream) {
13175
+ const stream2 = deps.gateway.stream({
13176
+ messages,
13177
+ model: body.model,
13178
+ system: body.system,
13179
+ maxTokens: body.maxTokens,
13180
+ temperature: body.temperature
13181
+ });
13182
+ return streamResponse(c, stream2);
13183
+ }
12217
13184
  let response;
12218
13185
  try {
12219
13186
  response = await deps.gateway.complete({
@@ -12254,13 +13221,13 @@ function createRoutes(deps) {
12254
13221
  }
12255
13222
 
12256
13223
  // ../app/src/app.ts
12257
- var log5 = createLogger();
13224
+ var log12 = createLogger();
12258
13225
  function createApp(config) {
12259
13226
  const app = new Hono2;
12260
13227
  app.onError((err2, c) => {
12261
13228
  const statusCode = err2 instanceof ElsiumError ? err2.statusCode ?? 500 : 500;
12262
13229
  const code = err2 instanceof ElsiumError ? err2.code : "UNKNOWN";
12263
- log5.error("Unhandled error", { error: err2.message, code, path: c.req.path });
13230
+ log12.error("Unhandled error", { error: err2.message, code, path: c.req.path });
12264
13231
  return c.json({ error: err2.message, code }, statusCode);
12265
13232
  });
12266
13233
  app.notFound((c) => {
@@ -12281,7 +13248,7 @@ function createApp(config) {
12281
13248
  });
12282
13249
  const serverConfig = config.server ?? {};
12283
13250
  app.use("*", requestIdMiddleware());
12284
- app.use("*", requestLoggerMiddleware(log5));
13251
+ app.use("*", requestLoggerMiddleware(log12));
12285
13252
  if (serverConfig.cors) {
12286
13253
  app.use("*", corsMiddleware(serverConfig.cors));
12287
13254
  }
@@ -12325,11 +13292,11 @@ function createApp(config) {
12325
13292
  const drainTimeoutMs = typeof serverConfig.gracefulShutdown === "object" ? serverConfig.gracefulShutdown.drainTimeoutMs : undefined;
12326
13293
  shutdownManager = createShutdownManager({
12327
13294
  drainTimeoutMs,
12328
- onDrainStart: () => log5.info("Draining connections..."),
12329
- onDrainComplete: () => log5.info("Drain complete")
13295
+ onDrainStart: () => log12.info("Draining connections..."),
13296
+ onDrainComplete: () => log12.info("Drain complete")
12330
13297
  });
12331
13298
  }
12332
- log5.info("ElsiumAI server started", {
13299
+ log12.info("ElsiumAI server started", {
12333
13300
  url: `http://${hostname}:${listenPort}`,
12334
13301
  routes: ["POST /chat", "POST /complete", "GET /health", "GET /metrics", "GET /agents"]
12335
13302
  });
@@ -12346,7 +13313,54 @@ function createApp(config) {
12346
13313
  };
12347
13314
  }
12348
13315
  // ../app/src/rbac.ts
12349
- var log6 = createLogger();
13316
+ var log13 = createLogger();
13317
+ // ../app/src/tenant.ts
13318
+ var log14 = createLogger();
13319
+ function tenantMiddleware(config) {
13320
+ const { extractTenant, onUnknownTenant = "reject", defaultTenant } = config;
13321
+ return async (c, next) => {
13322
+ const tenant = extractTenant(c);
13323
+ if (!tenant) {
13324
+ if (onUnknownTenant === "default" && defaultTenant) {
13325
+ c.set("tenant", defaultTenant);
13326
+ log14.debug("Using default tenant", { tenantId: defaultTenant.tenantId });
13327
+ } else {
13328
+ return c.json({ error: "Tenant identification required" }, 401);
13329
+ }
13330
+ } else {
13331
+ c.set("tenant", tenant);
13332
+ log14.debug("Tenant identified", { tenantId: tenant.tenantId });
13333
+ }
13334
+ await next();
13335
+ };
13336
+ }
13337
+ function tenantRateLimitMiddleware() {
13338
+ const windows = new Map;
13339
+ return async (c, next) => {
13340
+ const tenant = c.get("tenant");
13341
+ if (!tenant?.limits?.maxRequestsPerMinute) {
13342
+ await next();
13343
+ return;
13344
+ }
13345
+ const limit = tenant.limits.maxRequestsPerMinute;
13346
+ const now = Date.now();
13347
+ const windowMs = 60000;
13348
+ const key = tenant.tenantId;
13349
+ let entry = windows.get(key);
13350
+ if (!entry || now - entry.windowStart > windowMs) {
13351
+ entry = { count: 0, windowStart: now };
13352
+ windows.set(key, entry);
13353
+ }
13354
+ entry.count++;
13355
+ if (entry.count > limit) {
13356
+ return c.json({
13357
+ error: "Rate limit exceeded",
13358
+ retryAfterMs: windowMs - (now - entry.windowStart)
13359
+ }, 429);
13360
+ }
13361
+ await next();
13362
+ };
13363
+ }
12350
13364
  // ../mcp/src/client.ts
12351
13365
  import { spawn } from "node:child_process";
12352
13366
  function createMCPClient(config) {
@@ -12558,7 +13572,7 @@ function createMCPClient(config) {
12558
13572
  };
12559
13573
  }
12560
13574
  // ../mcp/src/server.ts
12561
- var log7 = createLogger();
13575
+ var log15 = createLogger();
12562
13576
  function createMCPServer(config) {
12563
13577
  let running = false;
12564
13578
  const toolMap = new Map(config.tools.map((t) => [t.name, t]));
@@ -12693,7 +13707,7 @@ function createMCPServer(config) {
12693
13707
  pendingChunks.shift();
12694
13708
  buffer += chunk;
12695
13709
  if (buffer.length > MAX_BUFFER_SIZE2) {
12696
- log7.error("MCP server: buffer size limit exceeded, resetting");
13710
+ log15.error("MCP server: buffer size limit exceeded, resetting");
12697
13711
  buffer = "";
12698
13712
  continue;
12699
13713
  }
@@ -12728,6 +13742,119 @@ function createMCPServer(config) {
12728
13742
  }
12729
13743
  };
12730
13744
  }
13745
+ // ../client/dist/index.js
13746
+ async function* parseSSEStream(response) {
13747
+ if (!response.body) {
13748
+ throw new Error("Response body is null");
13749
+ }
13750
+ const reader = response.body.getReader();
13751
+ const decoder = new TextDecoder;
13752
+ let buffer = "";
13753
+ try {
13754
+ while (true) {
13755
+ const { done, value } = await reader.read();
13756
+ if (done)
13757
+ break;
13758
+ buffer += decoder.decode(value, { stream: true });
13759
+ const lines = buffer.split(`
13760
+ `);
13761
+ buffer = lines.pop() ?? "";
13762
+ for (const line of lines) {
13763
+ if (line.startsWith("event: error")) {
13764
+ continue;
13765
+ }
13766
+ if (!line.startsWith("data: "))
13767
+ continue;
13768
+ const data = line.slice(6).trim();
13769
+ if (!data || data === "[DONE]")
13770
+ continue;
13771
+ try {
13772
+ const event = JSON.parse(data);
13773
+ yield event;
13774
+ } catch {}
13775
+ }
13776
+ }
13777
+ } finally {
13778
+ reader.releaseLock();
13779
+ }
13780
+ }
13781
+ function createClient(config) {
13782
+ const { baseUrl, apiKey, timeout = 30000 } = config;
13783
+ function headers() {
13784
+ const h = {
13785
+ "Content-Type": "application/json"
13786
+ };
13787
+ if (apiKey) {
13788
+ h.Authorization = `Bearer ${apiKey}`;
13789
+ }
13790
+ return h;
13791
+ }
13792
+ async function request(method, path, body) {
13793
+ const controller = new AbortController;
13794
+ const timer = setTimeout(() => controller.abort(), timeout);
13795
+ try {
13796
+ const response = await fetch(`${baseUrl}${path}`, {
13797
+ method,
13798
+ headers: headers(),
13799
+ body: body ? JSON.stringify(body) : undefined,
13800
+ signal: controller.signal
13801
+ });
13802
+ if (!response.ok) {
13803
+ const errorBody = await response.text().catch(() => "Unknown error");
13804
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
13805
+ }
13806
+ return await response.json();
13807
+ } finally {
13808
+ clearTimeout(timer);
13809
+ }
13810
+ }
13811
+ async function streamRequest(path, body) {
13812
+ const controller = new AbortController;
13813
+ const timer = setTimeout(() => controller.abort(), timeout);
13814
+ try {
13815
+ const response = await fetch(`${baseUrl}${path}`, {
13816
+ method: "POST",
13817
+ headers: headers(),
13818
+ body: JSON.stringify(body),
13819
+ signal: controller.signal
13820
+ });
13821
+ if (!response.ok) {
13822
+ const errorBody = await response.text().catch(() => "Unknown error");
13823
+ clearTimeout(timer);
13824
+ throw new Error(`HTTP ${response.status}: ${errorBody}`);
13825
+ }
13826
+ return response;
13827
+ } catch (err2) {
13828
+ clearTimeout(timer);
13829
+ throw err2;
13830
+ }
13831
+ }
13832
+ return {
13833
+ async chat(req) {
13834
+ return request("POST", "/chat", { ...req, stream: false });
13835
+ },
13836
+ async* chatStream(req) {
13837
+ const response = await streamRequest("/chat", { ...req, stream: true });
13838
+ yield* parseSSEStream(response);
13839
+ },
13840
+ async complete(req) {
13841
+ return request("POST", "/complete", { ...req, stream: false });
13842
+ },
13843
+ async* completeStream(req) {
13844
+ const response = await streamRequest("/complete", { ...req, stream: true });
13845
+ yield* parseSSEStream(response);
13846
+ },
13847
+ async health() {
13848
+ return request("GET", "/health");
13849
+ },
13850
+ async metrics() {
13851
+ return request("GET", "/metrics");
13852
+ },
13853
+ async agents() {
13854
+ return request("GET", "/agents");
13855
+ }
13856
+ };
13857
+ }
12731
13858
  // ../testing/src/mock-provider.ts
12732
13859
  function mockProvider(options = {}) {
12733
13860
  const { responses = [], defaultResponse, onRequest } = options;
@@ -12836,10 +13963,10 @@ function mockProvider(options = {}) {
12836
13963
  };
12837
13964
  }
12838
13965
  // ../testing/src/fixtures.ts
12839
- import { createHash } from "node:crypto";
13966
+ import { createHash as createHash3 } from "node:crypto";
12840
13967
  function hashMessages(messages) {
12841
13968
  const content = messages.map((m) => `${m.role}:${m.content}`).join("|");
12842
- return createHash("sha256").update(content).digest("hex").slice(0, 16);
13969
+ return createHash3("sha256").update(content).digest("hex").slice(0, 16);
12843
13970
  }
12844
13971
  function createFixture(name, entries) {
12845
13972
  return {
@@ -13505,7 +14632,9 @@ function createReplayPlayer(entriesOrJson) {
13505
14632
  };
13506
14633
  }
13507
14634
  export {
14635
+ zodToJsonSchema,
13508
14636
  xrayMiddleware,
14637
+ vectorStoreRegistry,
13509
14638
  unwrapOr,
13510
14639
  unwrap,
13511
14640
  tryCatchSync,
@@ -13513,7 +14642,11 @@ export {
13513
14642
  toTraceparent,
13514
14643
  toOTelSpan,
13515
14644
  toOTelExportRequest,
14645
+ tenantRateLimitMiddleware,
14646
+ tenantMiddleware,
14647
+ streamResponse,
13516
14648
  step,
14649
+ sseHeaders,
13517
14650
  sleep,
13518
14651
  securityMiddleware,
13519
14652
  runSupervisor,
@@ -13526,6 +14659,7 @@ export {
13526
14659
  redactSecrets,
13527
14660
  rag,
13528
14661
  parseTraceparent,
14662
+ outputGuardrailMiddleware,
13529
14663
  ok,
13530
14664
  observe,
13531
14665
  mockProvider,
@@ -13541,6 +14675,7 @@ export {
13541
14675
  gateway,
13542
14676
  formatToolResultAsText,
13543
14677
  formatToolResult,
14678
+ formatSSE,
13544
14679
  formatEvalReport,
13545
14680
  extractTraceContext,
13546
14681
  extractText,
@@ -13549,6 +14684,7 @@ export {
13549
14684
  envNumber,
13550
14685
  envBool,
13551
14686
  env,
14687
+ embeddingProviderRegistry,
13552
14688
  detectPromptInjection,
13553
14689
  detectJailbreak,
13554
14690
  defineWorkflow,
@@ -13560,15 +14696,18 @@ export {
13560
14696
  currentTimeTool,
13561
14697
  createToolkit,
13562
14698
  createStream,
14699
+ createSqliteMemoryStore,
13563
14700
  createSpan,
13564
14701
  createSnapshotStore,
13565
14702
  createSemanticValidator,
13566
14703
  createReplayRecorder,
13567
14704
  createReplayPlayer,
13568
14705
  createRegressionSuite,
14706
+ createRegistry,
13569
14707
  createRecorder,
13570
14708
  createProviderMesh,
13571
14709
  createPromptRegistry,
14710
+ createPgVectorStore,
13572
14711
  createOpenAIProvider,
13573
14712
  createOpenAIEmbeddings,
13574
14713
  createOTLPExporter,
@@ -13579,17 +14718,25 @@ export {
13579
14718
  createMCPClient,
13580
14719
  createLogger,
13581
14720
  createInMemoryStore,
14721
+ createInMemoryMemoryStore,
14722
+ createInMemoryCache,
13582
14723
  createGoogleProvider,
13583
14724
  createFixture,
14725
+ createExperiment,
13584
14726
  createCostEngine,
14727
+ createContextManager,
13585
14728
  createConfidenceScorer,
14729
+ createClient,
14730
+ createBatch,
13586
14731
  createApp,
13587
14732
  createAnthropicProvider,
13588
14733
  createAgentSecurity,
14734
+ countTokens,
13589
14735
  costTrackingMiddleware,
13590
14736
  composeMiddleware,
13591
14737
  checkBlockedPatterns,
13592
14738
  calculatorTool,
13593
14739
  calculateCost,
14740
+ cacheMiddleware,
13594
14741
  ElsiumError
13595
14742
  };