elsium-ai 0.12.0 → 0.12.1

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 (2) hide show
  1. package/dist/index.js +82 -45
  2. package/package.json +12 -12
package/dist/index.js CHANGED
@@ -4215,6 +4215,15 @@ function createWorkerSandboxRunner(config, defaultTimeoutMs) {
4215
4215
  }
4216
4216
 
4217
4217
  // ../tools/src/define.ts
4218
+ var log7 = createLogger();
4219
+ var IS_BUN = typeof globalThis.Bun !== "undefined" || typeof process !== "undefined" && Boolean(process.versions.bun);
4220
+ var bunSandboxWarningShown = false;
4221
+ function warnBunSandboxOnce(toolName) {
4222
+ if (bunSandboxWarningShown)
4223
+ return;
4224
+ bunSandboxWarningShown = true;
4225
+ log7.warn(`Tool "${toolName}" uses sandbox.mode="worker" under Bun. Crash isolation is incomplete on Bun: process.exit() inside the handler does NOT terminate the worker (it does on Node). Other guarantees (process, memory, closure-state, timeout, abort) hold. Track: https://github.com/elsium-ai/elsium-ai/issues — search for "Bun crash isolation".`);
4226
+ }
4218
4227
  function formatZodErrors(error) {
4219
4228
  return error.issues.map((i) => `${i.path.join(".")}: ${i.message}`).join(", ");
4220
4229
  }
@@ -4234,6 +4243,30 @@ function buildExecutionSuccess(toolCallId, startTime, data) {
4234
4243
  durationMs: Math.round(performance.now() - startTime)
4235
4244
  };
4236
4245
  }
4246
+ function wireUserSignalToController(controller, userSignal) {
4247
+ if (!userSignal)
4248
+ return;
4249
+ if (userSignal.aborted) {
4250
+ controller.abort();
4251
+ return;
4252
+ }
4253
+ userSignal.addEventListener("abort", () => controller.abort(), { once: true });
4254
+ }
4255
+ function createAbortRejection(signal, isTimeout, name, timeoutMs) {
4256
+ return new Promise((_, reject) => {
4257
+ signal.addEventListener("abort", () => {
4258
+ if (isTimeout()) {
4259
+ reject(ElsiumError.timeout(name, timeoutMs));
4260
+ } else {
4261
+ reject(new ElsiumError({
4262
+ code: "TOOL_ERROR",
4263
+ message: `Tool "${name}" was aborted`,
4264
+ retryable: false
4265
+ }));
4266
+ }
4267
+ }, { once: true });
4268
+ });
4269
+ }
4237
4270
  function defineTool(config) {
4238
4271
  const input = config.input ?? config.parameters;
4239
4272
  if (!input) {
@@ -4245,6 +4278,9 @@ function defineTool(config) {
4245
4278
  if (config.sandbox && config.sandbox.mode !== "worker") {
4246
4279
  throw ElsiumError.validation(`Tool "${config.name}" sandbox.mode must be "worker" (received "${config.sandbox.mode}")`);
4247
4280
  }
4281
+ if (config.sandbox && IS_BUN) {
4282
+ warnBunSandboxOnce(config.name);
4283
+ }
4248
4284
  const { name, description, output, sandbox, timeoutMs = 30000 } = config;
4249
4285
  const handler = config.handler;
4250
4286
  let sandboxRunner = null;
@@ -4282,20 +4318,21 @@ function defineTool(config) {
4282
4318
  return buildExecutionFailure(toolCallId, startTime, `Invalid input: ${formatZodErrors(parsed.error)}`);
4283
4319
  }
4284
4320
  const controller = new AbortController;
4285
- const timer = setTimeout(() => controller.abort(), timeoutMs);
4321
+ let timedOut = false;
4322
+ const timer = setTimeout(() => {
4323
+ timedOut = true;
4324
+ controller.abort();
4325
+ }, timeoutMs);
4326
+ wireUserSignalToController(controller, partialCtx?.signal);
4286
4327
  const context = {
4287
4328
  toolCallId,
4288
4329
  traceId: partialCtx?.traceId,
4289
- signal: partialCtx?.signal ?? controller.signal
4330
+ signal: controller.signal
4290
4331
  };
4291
4332
  try {
4292
4333
  const result = await Promise.race([
4293
4334
  runHandler(parsed.data, context),
4294
- new Promise((_, reject) => {
4295
- context.signal?.addEventListener("abort", () => {
4296
- reject(ElsiumError.timeout(name, timeoutMs));
4297
- });
4298
- })
4335
+ createAbortRejection(controller.signal, () => timedOut, name, timeoutMs)
4299
4336
  ]);
4300
4337
  if (output) {
4301
4338
  const validated = output.safeParse(result);
@@ -10260,7 +10297,7 @@ function createInMemoryMemoryStore() {
10260
10297
  // ../agents/src/stores/sqlite-store.ts
10261
10298
  import { createRequire } from "node:module";
10262
10299
  var require2 = createRequire(import.meta.url);
10263
- var log7 = createLogger();
10300
+ var log8 = createLogger();
10264
10301
  var BLOCKED_KEYS2 = new Set(["__proto__", "constructor", "prototype"]);
10265
10302
  var TABLE_NAME_PATTERN = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
10266
10303
  function createSqliteMemoryStore(config) {
@@ -10296,7 +10333,7 @@ function createSqliteMemoryStore(config) {
10296
10333
  return db;
10297
10334
  } catch (err2) {
10298
10335
  initPromise = null;
10299
- log7.error("Failed to initialize SQLite memory store", {
10336
+ log8.error("Failed to initialize SQLite memory store", {
10300
10337
  error: err2 instanceof Error ? err2.message : String(err2)
10301
10338
  });
10302
10339
  throw new Error("better-sqlite3 is required for SQLite memory store. Install it as a dependency.");
@@ -10770,7 +10807,7 @@ function createInMemoryThreadStore() {
10770
10807
  };
10771
10808
  }
10772
10809
  // ../agents/src/async-agent.ts
10773
- var log8 = createLogger();
10810
+ var log9 = createLogger();
10774
10811
  function createAsyncAgent(config) {
10775
10812
  const tasks = new Map;
10776
10813
  function emitProgress(task, event) {
@@ -10798,7 +10835,7 @@ function createAsyncAgent(config) {
10798
10835
  const store = config.taskStore;
10799
10836
  const snapshot = toPersistedTask(task);
10800
10837
  store.save(snapshot).catch((err2) => {
10801
- log8.warn("async agent task persistence failed", {
10838
+ log9.warn("async agent task persistence failed", {
10802
10839
  taskId: task.id,
10803
10840
  status: task.status,
10804
10841
  error: err2 instanceof Error ? err2.message : String(err2)
@@ -12363,7 +12400,7 @@ function rag(config) {
12363
12400
  // ../rag/src/stores/pgvector.ts
12364
12401
  import { createRequire as createRequire2 } from "node:module";
12365
12402
  var require3 = createRequire2(import.meta.url);
12366
- var log9 = createLogger();
12403
+ var log10 = createLogger();
12367
12404
  var BLOCKED_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
12368
12405
  var TABLE_NAME_PATTERN2 = /^[a-zA-Z_][a-zA-Z0-9_]*$/;
12369
12406
  function createPgVectorStore(config) {
@@ -12399,7 +12436,7 @@ function createPgVectorStore(config) {
12399
12436
  }
12400
12437
  return client;
12401
12438
  } catch (err2) {
12402
- log9.error("Failed to initialize PgVector store", {
12439
+ log10.error("Failed to initialize PgVector store", {
12403
12440
  error: err2 instanceof Error ? err2.message : String(err2)
12404
12441
  });
12405
12442
  throw new Error("pg is required for PgVector store. Install it as a dependency.");
@@ -13674,7 +13711,7 @@ function createCostEngine(config = {}) {
13674
13711
  }
13675
13712
  // ../observe/src/tracer.ts
13676
13713
  import { writeFileSync } from "node:fs";
13677
- var log10 = createLogger();
13714
+ var log11 = createLogger();
13678
13715
  function observe(config = {}) {
13679
13716
  const {
13680
13717
  output = ["console"],
@@ -13697,7 +13734,7 @@ function observe(config = {}) {
13697
13734
  try {
13698
13735
  writeFileSync(filename, JSON.stringify(spansToExport, null, 2));
13699
13736
  } catch (err2) {
13700
- log10.error("Failed to write trace file", {
13737
+ log11.error("Failed to write trace file", {
13701
13738
  error: err2 instanceof Error ? err2.message : String(err2)
13702
13739
  });
13703
13740
  }
@@ -13772,7 +13809,7 @@ function observe(config = {}) {
13772
13809
  function consoleHandler(span) {
13773
13810
  const duration = span.durationMs !== undefined ? `${span.durationMs}ms` : "running";
13774
13811
  const status = span.status === "error" ? "[ERROR]" : span.status === "ok" ? "[OK]" : "[...]";
13775
- log10.info("span", {
13812
+ log11.info("span", {
13776
13813
  trace: span.traceId,
13777
13814
  span: span.name,
13778
13815
  kind: span.kind,
@@ -13874,7 +13911,7 @@ function createMetrics(options) {
13874
13911
  import { createHash as createHash5 } from "node:crypto";
13875
13912
 
13876
13913
  // ../observe/src/audit-sink.ts
13877
- var log11 = createLogger();
13914
+ var log12 = createLogger();
13878
13915
  function getRetryDelay2(attempt, baseDelayMs, maxDelayMs) {
13879
13916
  const delay = Math.min(baseDelayMs * 2 ** attempt, maxDelayMs);
13880
13917
  return delay * (0.5 + Math.random() * 0.5);
@@ -13902,14 +13939,14 @@ async function deliverToSink(sink, events, retryConfig, deadLetterSink, onError)
13902
13939
  try {
13903
13940
  await sendWithRetry(sink, filtered, retryConfig);
13904
13941
  } catch (error) {
13905
- log11.error("Audit sink delivery failed", { sink: sink.name });
13942
+ log12.error("Audit sink delivery failed", { sink: sink.name });
13906
13943
  onError?.(sink.name, error);
13907
13944
  if (!deadLetterSink)
13908
13945
  return;
13909
13946
  try {
13910
13947
  await deadLetterSink.send(filtered);
13911
13948
  } catch (dlqError) {
13912
- log11.error("Dead letter sink delivery failed", { sink: deadLetterSink.name });
13949
+ log12.error("Dead letter sink delivery failed", { sink: deadLetterSink.name });
13913
13950
  onError?.(deadLetterSink.name, dlqError);
13914
13951
  }
13915
13952
  }
@@ -13953,7 +13990,7 @@ function createSinkManager(config) {
13953
13990
  dispatch(event) {
13954
13991
  if (buffer.length >= maxBufferSize) {
13955
13992
  buffer.shift();
13956
- log11.warn("Audit sink buffer full, dropping oldest event");
13993
+ log12.warn("Audit sink buffer full, dropping oldest event");
13957
13994
  }
13958
13995
  buffer.push(event);
13959
13996
  if (buffer.length >= batchSize)
@@ -14462,7 +14499,7 @@ function createDatadogSink(config) {
14462
14499
  // ../observe/src/audit-sink-jsonl.ts
14463
14500
  import { mkdir as mkdir2, open } from "node:fs/promises";
14464
14501
  import { dirname } from "node:path";
14465
- var log12 = createLogger();
14502
+ var log13 = createLogger();
14466
14503
  function createJsonlSink(config) {
14467
14504
  const { path, fsync = true } = config;
14468
14505
  let handle = null;
@@ -14501,7 +14538,7 @@ function createJsonlSink(config) {
14501
14538
  try {
14502
14539
  await fh.sync();
14503
14540
  } catch (err2) {
14504
- log12.warn("jsonl sink fsync failed", { error: err2 });
14541
+ log13.warn("jsonl sink fsync failed", { error: err2 });
14505
14542
  }
14506
14543
  }
14507
14544
  });
@@ -14582,7 +14619,7 @@ function createProvenanceTracker(options) {
14582
14619
  import { createHash as createHash7 } from "node:crypto";
14583
14620
  import { existsSync, mkdirSync, readFileSync, writeFileSync as writeFileSync2 } from "node:fs";
14584
14621
  import { join as join2 } from "node:path";
14585
- var log13 = createLogger();
14622
+ var log14 = createLogger();
14586
14623
  function createFileExperimentStore(dir) {
14587
14624
  return {
14588
14625
  save(name, data) {
@@ -14593,7 +14630,7 @@ function createFileExperimentStore(dir) {
14593
14630
  const filePath = join2(dir, `${name}.json`);
14594
14631
  writeFileSync2(filePath, JSON.stringify(data, null, 2));
14595
14632
  } catch (err2) {
14596
- log13.error("Failed to save experiment", {
14633
+ log14.error("Failed to save experiment", {
14597
14634
  name,
14598
14635
  error: err2 instanceof Error ? err2.message : String(err2)
14599
14636
  });
@@ -14624,7 +14661,7 @@ function loadFromStore(store, name, stats) {
14624
14661
  stats[vName].metrics[key] = { sum: m.sum, count: m.count };
14625
14662
  }
14626
14663
  }
14627
- log13.debug("Loaded experiment state", { name, totalAssignments: saved.totalAssignments });
14664
+ log14.debug("Loaded experiment state", { name, totalAssignments: saved.totalAssignments });
14628
14665
  }
14629
14666
  function recordMetrics(s, metrics) {
14630
14667
  for (const [key, value] of Object.entries(metrics)) {
@@ -14692,7 +14729,7 @@ function createExperiment(config) {
14692
14729
  const s = stats[variant.name];
14693
14730
  if (s)
14694
14731
  s.assignments++;
14695
- log13.debug("Experiment assignment", {
14732
+ log14.debug("Experiment assignment", {
14696
14733
  experiment: name,
14697
14734
  variant: variant.name,
14698
14735
  userId
@@ -14763,7 +14800,7 @@ function instrumentAgent(agent, tracer) {
14763
14800
  // ../observe/src/studio-exporter.ts
14764
14801
  import { existsSync as existsSync2, mkdirSync as mkdirSync2, readFileSync as readFileSync2, writeFileSync as writeFileSync3 } from "node:fs";
14765
14802
  import { join as join3 } from "node:path";
14766
- var log14 = createLogger();
14803
+ var log15 = createLogger();
14767
14804
  function ensureDir(dirPath) {
14768
14805
  if (!existsSync2(dirPath)) {
14769
14806
  mkdirSync2(dirPath, { recursive: true });
@@ -14773,7 +14810,7 @@ function safeWriteJSON(filePath, data) {
14773
14810
  try {
14774
14811
  writeFileSync3(filePath, JSON.stringify(data, null, 2));
14775
14812
  } catch (err2) {
14776
- log14.error("Studio exporter write failed", {
14813
+ log15.error("Studio exporter write failed", {
14777
14814
  file: filePath,
14778
14815
  error: err2 instanceof Error ? err2.message : String(err2)
14779
14816
  });
@@ -15158,7 +15195,7 @@ function formatComplianceReport(report) {
15158
15195
  `);
15159
15196
  }
15160
15197
  // ../observe/src/otel.ts
15161
- var log15 = createLogger();
15198
+ var log16 = createLogger();
15162
15199
  var SPAN_KIND_MAP = {
15163
15200
  llm: 3,
15164
15201
  tool: 1,
@@ -15299,10 +15336,10 @@ function createOTLPExporter(config) {
15299
15336
  body: JSON.stringify(payload)
15300
15337
  });
15301
15338
  if (!response.ok) {
15302
- log15.error(`OTLP export failed: ${response.status} ${response.statusText}`);
15339
+ log16.error(`OTLP export failed: ${response.status} ${response.statusText}`);
15303
15340
  }
15304
15341
  } catch (err2) {
15305
- log15.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
15342
+ log16.error("OTLP export error", { error: err2 instanceof Error ? err2.message : String(err2) });
15306
15343
  }
15307
15344
  }
15308
15345
  function startAutoFlush() {
@@ -17584,12 +17621,12 @@ function requestIdMiddleware() {
17584
17621
  };
17585
17622
  }
17586
17623
  function requestLoggerMiddleware(logger) {
17587
- const log16 = logger ?? createLogger();
17624
+ const log17 = logger ?? createLogger();
17588
17625
  return async (c, next) => {
17589
17626
  const start = Date.now();
17590
17627
  await next();
17591
17628
  const duration = Date.now() - start;
17592
- log16.info(`${c.req.method} ${c.req.path}`, {
17629
+ log17.info(`${c.req.method} ${c.req.path}`, {
17593
17630
  method: c.req.method,
17594
17631
  path: c.req.path,
17595
17632
  status: c.res.status,
@@ -17932,13 +17969,13 @@ function createRoutes(deps) {
17932
17969
  }
17933
17970
 
17934
17971
  // ../app/src/app.ts
17935
- var log16 = createLogger();
17972
+ var log17 = createLogger();
17936
17973
  function createApp(config) {
17937
17974
  const app = new Hono2;
17938
17975
  app.onError((err2, c) => {
17939
17976
  const statusCode = err2 instanceof ElsiumError ? err2.statusCode ?? 500 : 500;
17940
17977
  const code = err2 instanceof ElsiumError ? err2.code : "UNKNOWN";
17941
- log16.error("Unhandled error", { error: err2.message, code, path: c.req.path });
17978
+ log17.error("Unhandled error", { error: err2.message, code, path: c.req.path });
17942
17979
  return c.json({ error: err2.message, code }, statusCode);
17943
17980
  });
17944
17981
  app.notFound((c) => {
@@ -17984,7 +18021,7 @@ function createApp(config) {
17984
18021
  });
17985
18022
  const serverConfig = config.server ?? {};
17986
18023
  app.use("*", requestIdMiddleware());
17987
- app.use("*", requestLoggerMiddleware(log16));
18024
+ app.use("*", requestLoggerMiddleware(log17));
17988
18025
  if (serverConfig.cors) {
17989
18026
  app.use("*", corsMiddleware(serverConfig.cors));
17990
18027
  }
@@ -18030,11 +18067,11 @@ function createApp(config) {
18030
18067
  const drainTimeoutMs = typeof serverConfig.gracefulShutdown === "object" ? serverConfig.gracefulShutdown.drainTimeoutMs : undefined;
18031
18068
  shutdownManager = createShutdownManager({
18032
18069
  drainTimeoutMs,
18033
- onDrainStart: () => log16.info("Draining connections..."),
18034
- onDrainComplete: () => log16.info("Drain complete")
18070
+ onDrainStart: () => log17.info("Draining connections..."),
18071
+ onDrainComplete: () => log17.info("Drain complete")
18035
18072
  });
18036
18073
  }
18037
- log16.info("ElsiumAI server started", {
18074
+ log17.info("ElsiumAI server started", {
18038
18075
  url: `http://${hostname}:${listenPort}`,
18039
18076
  routes: ["POST /chat", "POST /complete", "GET /health", "GET /metrics", "GET /agents"]
18040
18077
  });
@@ -18051,9 +18088,9 @@ function createApp(config) {
18051
18088
  };
18052
18089
  }
18053
18090
  // ../app/src/rbac.ts
18054
- var log17 = createLogger();
18055
- // ../app/src/tenant.ts
18056
18091
  var log18 = createLogger();
18092
+ // ../app/src/tenant.ts
18093
+ var log19 = createLogger();
18057
18094
  var tenantUsage = new Map;
18058
18095
  function tenantMiddleware(config) {
18059
18096
  const { extractTenant, onUnknownTenant = "reject", defaultTenant } = config;
@@ -18062,13 +18099,13 @@ function tenantMiddleware(config) {
18062
18099
  if (!tenant) {
18063
18100
  if (onUnknownTenant === "default" && defaultTenant) {
18064
18101
  c.set("tenant", defaultTenant);
18065
- log18.debug("Using default tenant", { tenantId: defaultTenant.tenantId });
18102
+ log19.debug("Using default tenant", { tenantId: defaultTenant.tenantId });
18066
18103
  } else {
18067
18104
  return c.json({ error: "Tenant identification required" }, 401);
18068
18105
  }
18069
18106
  } else {
18070
18107
  c.set("tenant", tenant);
18071
- log18.debug("Tenant identified", { tenantId: tenant.tenantId });
18108
+ log19.debug("Tenant identified", { tenantId: tenant.tenantId });
18072
18109
  }
18073
18110
  await next();
18074
18111
  };
@@ -18502,7 +18539,7 @@ function createStdioMCPClient(config) {
18502
18539
  };
18503
18540
  }
18504
18541
  // ../mcp/src/server.ts
18505
- var log19 = createLogger();
18542
+ var log20 = createLogger();
18506
18543
  function createMCPServer(config) {
18507
18544
  let running = false;
18508
18545
  const toolMap = new Map(config.tools.map((t) => [t.name, t]));
@@ -18730,7 +18767,7 @@ function createMCPServer(config) {
18730
18767
  pendingChunks.shift();
18731
18768
  buffer += chunk;
18732
18769
  if (buffer.length > MAX_BUFFER_SIZE2) {
18733
- log19.error("MCP server: buffer size limit exceeded, resetting");
18770
+ log20.error("MCP server: buffer size limit exceeded, resetting");
18734
18771
  buffer = "";
18735
18772
  continue;
18736
18773
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "elsium-ai",
3
- "version": "0.12.0",
3
+ "version": "0.12.1",
4
4
  "description": "ElsiumAI — A high-performance, TypeScript-first AI framework",
5
5
  "license": "MIT",
6
6
  "author": "Eric Utrera <ebutrera9103@gmail.com>",
@@ -25,17 +25,17 @@
25
25
  "build": "bun build ./src/index.ts --outdir ./dist --target node && bun x tsc -p tsconfig.build.json --emitDeclarationOnly"
26
26
  },
27
27
  "dependencies": {
28
- "@elsium-ai/core": "^0.12.0",
29
- "@elsium-ai/gateway": "^0.12.0",
30
- "@elsium-ai/agents": "^0.12.0",
31
- "@elsium-ai/tools": "^0.12.0",
32
- "@elsium-ai/rag": "^0.12.0",
33
- "@elsium-ai/workflows": "^0.12.0",
34
- "@elsium-ai/observe": "^0.12.0",
35
- "@elsium-ai/app": "^0.12.0",
36
- "@elsium-ai/testing": "^0.12.0",
37
- "@elsium-ai/mcp": "^0.12.0",
38
- "@elsium-ai/client": "^0.12.0"
28
+ "@elsium-ai/core": "^0.12.1",
29
+ "@elsium-ai/gateway": "^0.12.1",
30
+ "@elsium-ai/agents": "^0.12.1",
31
+ "@elsium-ai/tools": "^0.12.1",
32
+ "@elsium-ai/rag": "^0.12.1",
33
+ "@elsium-ai/workflows": "^0.12.1",
34
+ "@elsium-ai/observe": "^0.12.1",
35
+ "@elsium-ai/app": "^0.12.1",
36
+ "@elsium-ai/testing": "^0.12.1",
37
+ "@elsium-ai/mcp": "^0.12.1",
38
+ "@elsium-ai/client": "^0.12.1"
39
39
  },
40
40
  "devDependencies": {
41
41
  "typescript": "^5.7.0"