@hsuite/smart-engines-sdk 3.12.0 → 3.13.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.
package/dist/index.d.ts CHANGED
@@ -3885,7 +3885,7 @@ export type AgentExecuteRequest = {
3885
3885
  params: Record<string, unknown>;
3886
3886
  };
3887
3887
  export type AgentExecuteStepResult = {
3888
- kind: "onchain" | "offchain";
3888
+ kind: "onchain" | "offchain" | "function";
3889
3889
  status: string;
3890
3890
  transactionBytes?: string;
3891
3891
  ref?: string;
@@ -5405,6 +5405,8 @@ export type InferArgs = {
5405
5405
  system?: string;
5406
5406
  messages: ChatMessage[];
5407
5407
  maxTokens?: number;
5408
+ timeoutMs?: number;
5409
+ signal?: AbortSignal;
5408
5410
  };
5409
5411
  export type InferResult = {
5410
5412
  ok: boolean;
@@ -5421,8 +5423,9 @@ export declare function createAnthropicProvider(opts: {
5421
5423
  model: string;
5422
5424
  }): IModelProvider;
5423
5425
  export declare function createOpenAiProvider(opts: {
5424
- apiKey: string;
5426
+ apiKey?: string;
5425
5427
  model: string;
5428
+ baseURL?: string;
5426
5429
  }): IModelProvider;
5427
5430
  export declare function createGeminiProvider(opts: {
5428
5431
  apiKey: string;
@@ -5430,8 +5433,9 @@ export declare function createGeminiProvider(opts: {
5430
5433
  }): IModelProvider;
5431
5434
  export declare function createModelProvider(opts: {
5432
5435
  provider: ModelProvider;
5433
- apiKey: string;
5436
+ apiKey?: string;
5434
5437
  model: string;
5438
+ baseURL?: string;
5435
5439
  }): IModelProvider;
5436
5440
  export type InferJsonResult<T> = {
5437
5441
  ok: boolean;
@@ -5441,11 +5445,14 @@ export type InferJsonResult<T> = {
5441
5445
  };
5442
5446
  export declare function inferJson<T = unknown>(opts: {
5443
5447
  provider: ModelProvider;
5444
- apiKey: string;
5448
+ apiKey?: string;
5445
5449
  model: string;
5450
+ baseURL?: string;
5446
5451
  system?: string;
5447
5452
  input: unknown;
5448
5453
  maxTokens?: number;
5454
+ timeoutMs?: number;
5455
+ signal?: AbortSignal;
5449
5456
  parse?: (raw: unknown) => T;
5450
5457
  }): Promise<InferJsonResult<T>>;
5451
5458
  export type StateRootResponse = {
package/dist/index.js CHANGED
@@ -10385,6 +10385,65 @@ __export(ai_exports, {
10385
10385
  inferJson: () => inferJson
10386
10386
  });
10387
10387
 
10388
+ // src/ai/types.ts
10389
+ var DEFAULT_INFER_TIMEOUT_MS = 3e4;
10390
+
10391
+ // src/ai/http.ts
10392
+ var InferTimeoutError = class extends Error {
10393
+ constructor(timeoutMs) {
10394
+ super(`request timed out after ${timeoutMs}ms`);
10395
+ this.name = "InferTimeoutError";
10396
+ }
10397
+ };
10398
+ function isAbortError(err) {
10399
+ if (err instanceof InferTimeoutError) {
10400
+ return true;
10401
+ }
10402
+ return typeof err === "object" && err !== null && err.name === "AbortError";
10403
+ }
10404
+ function errMsg(err) {
10405
+ return err instanceof Error ? err.message : String(err);
10406
+ }
10407
+ async function fetchWithTimeout(url, init, opts = {}) {
10408
+ const timeoutMs = opts.timeoutMs ?? DEFAULT_INFER_TIMEOUT_MS;
10409
+ const callerSignal = opts.signal;
10410
+ const controller = new AbortController();
10411
+ let timedOut = false;
10412
+ let timer;
10413
+ if (timeoutMs > 0) {
10414
+ timer = setTimeout(() => {
10415
+ timedOut = true;
10416
+ controller.abort();
10417
+ }, timeoutMs);
10418
+ if (typeof timer === "object" && typeof timer.unref === "function") {
10419
+ timer.unref();
10420
+ }
10421
+ }
10422
+ const onCallerAbort = () => controller.abort();
10423
+ if (callerSignal) {
10424
+ if (callerSignal.aborted) {
10425
+ controller.abort();
10426
+ } else {
10427
+ callerSignal.addEventListener("abort", onCallerAbort, { once: true });
10428
+ }
10429
+ }
10430
+ try {
10431
+ return await fetch(url, { ...init, signal: controller.signal });
10432
+ } catch (err) {
10433
+ if (timedOut) {
10434
+ throw new InferTimeoutError(timeoutMs);
10435
+ }
10436
+ throw err;
10437
+ } finally {
10438
+ if (timer !== void 0) {
10439
+ clearTimeout(timer);
10440
+ }
10441
+ if (callerSignal) {
10442
+ callerSignal.removeEventListener("abort", onCallerAbort);
10443
+ }
10444
+ }
10445
+ }
10446
+
10388
10447
  // src/ai/anthropic.ts
10389
10448
  var ANTHROPIC_URL = "https://api.anthropic.com/v1/messages";
10390
10449
  var ANTHROPIC_VERSION = "2023-06-01";
@@ -10403,15 +10462,27 @@ function createAnthropicProvider(opts) {
10403
10462
  if (args.system) {
10404
10463
  body.system = args.system;
10405
10464
  }
10406
- const res = await fetch(ANTHROPIC_URL, {
10407
- method: "POST",
10408
- headers: {
10409
- "x-api-key": apiKey,
10410
- "anthropic-version": ANTHROPIC_VERSION,
10411
- "content-type": "application/json"
10412
- },
10413
- body: JSON.stringify(body)
10414
- });
10465
+ let res;
10466
+ try {
10467
+ res = await fetchWithTimeout(
10468
+ ANTHROPIC_URL,
10469
+ {
10470
+ method: "POST",
10471
+ headers: {
10472
+ "x-api-key": apiKey,
10473
+ "anthropic-version": ANTHROPIC_VERSION,
10474
+ "content-type": "application/json"
10475
+ },
10476
+ body: JSON.stringify(body)
10477
+ },
10478
+ { timeoutMs: args.timeoutMs, signal: args.signal }
10479
+ );
10480
+ } catch (err) {
10481
+ if (isAbortError(err)) {
10482
+ return { ok: false, error: errMsg(err) };
10483
+ }
10484
+ throw err;
10485
+ }
10415
10486
  if (!res.ok) {
10416
10487
  throw new Error(`Anthropic request failed with status ${res.status}`);
10417
10488
  }
@@ -10426,10 +10497,11 @@ function createAnthropicProvider(opts) {
10426
10497
  }
10427
10498
 
10428
10499
  // src/ai/openai.ts
10429
- var OPENAI_URL = "https://api.openai.com/v1/chat/completions";
10500
+ var DEFAULT_OPENAI_BASE_URL = "https://api.openai.com/v1";
10430
10501
  var DEFAULT_MAX_TOKENS2 = 1024;
10431
10502
  function createOpenAiProvider(opts) {
10432
10503
  const { apiKey, model } = opts;
10504
+ const url = `${(opts.baseURL ?? DEFAULT_OPENAI_BASE_URL).replace(/\/+$/, "")}/chat/completions`;
10433
10505
  return {
10434
10506
  provider: "openai",
10435
10507
  async infer(args) {
@@ -10440,18 +10512,32 @@ function createOpenAiProvider(opts) {
10440
10512
  for (const m of args.messages) {
10441
10513
  messages.push({ role: m.role, content: m.content });
10442
10514
  }
10443
- const res = await fetch(OPENAI_URL, {
10444
- method: "POST",
10445
- headers: {
10446
- Authorization: `Bearer ${apiKey}`,
10447
- "content-type": "application/json"
10448
- },
10449
- body: JSON.stringify({
10450
- model,
10451
- max_tokens: args.maxTokens ?? DEFAULT_MAX_TOKENS2,
10452
- messages
10453
- })
10454
- });
10515
+ let res;
10516
+ try {
10517
+ res = await fetchWithTimeout(
10518
+ url,
10519
+ {
10520
+ method: "POST",
10521
+ headers: {
10522
+ // Auth only when a key is supplied — a keyless local server (Ollama)
10523
+ // rejects a bogus Bearer header.
10524
+ ...apiKey ? { Authorization: `Bearer ${apiKey}` } : {},
10525
+ "content-type": "application/json"
10526
+ },
10527
+ body: JSON.stringify({
10528
+ model,
10529
+ max_tokens: args.maxTokens ?? DEFAULT_MAX_TOKENS2,
10530
+ messages
10531
+ })
10532
+ },
10533
+ { timeoutMs: args.timeoutMs, signal: args.signal }
10534
+ );
10535
+ } catch (err) {
10536
+ if (isAbortError(err)) {
10537
+ return { ok: false, error: errMsg(err) };
10538
+ }
10539
+ throw err;
10540
+ }
10455
10541
  if (!res.ok) {
10456
10542
  throw new Error(`OpenAI request failed with status ${res.status}`);
10457
10543
  }
@@ -10484,12 +10570,27 @@ function createGeminiProvider(opts) {
10484
10570
  if (args.system) {
10485
10571
  body.systemInstruction = { parts: [{ text: args.system }] };
10486
10572
  }
10487
- const url = `${GEMINI_BASE}/${model}:generateContent?key=${encodeURIComponent(apiKey)}`;
10488
- const res = await fetch(url, {
10489
- method: "POST",
10490
- headers: { "content-type": "application/json" },
10491
- body: JSON.stringify(body)
10492
- });
10573
+ const url = `${GEMINI_BASE}/${model}:generateContent`;
10574
+ let res;
10575
+ try {
10576
+ res = await fetchWithTimeout(
10577
+ url,
10578
+ {
10579
+ method: "POST",
10580
+ headers: {
10581
+ "content-type": "application/json",
10582
+ "x-goog-api-key": apiKey
10583
+ },
10584
+ body: JSON.stringify(body)
10585
+ },
10586
+ { timeoutMs: args.timeoutMs, signal: args.signal }
10587
+ );
10588
+ } catch (err) {
10589
+ if (isAbortError(err)) {
10590
+ return { ok: false, error: errMsg(err) };
10591
+ }
10592
+ throw err;
10593
+ }
10493
10594
  if (!res.ok) {
10494
10595
  throw new Error(`Gemini request failed with status ${res.status}`);
10495
10596
  }
@@ -10505,14 +10606,14 @@ function createGeminiProvider(opts) {
10505
10606
 
10506
10607
  // src/ai/factory.ts
10507
10608
  function createModelProvider(opts) {
10508
- const { provider, apiKey, model } = opts;
10609
+ const { provider, apiKey, model, baseURL } = opts;
10509
10610
  switch (provider) {
10510
10611
  case "anthropic":
10511
- return createAnthropicProvider({ apiKey, model });
10612
+ return createAnthropicProvider({ apiKey: apiKey ?? "", model });
10512
10613
  case "openai":
10513
- return createOpenAiProvider({ apiKey, model });
10614
+ return createOpenAiProvider({ apiKey, model, baseURL });
10514
10615
  case "gemini":
10515
- return createGeminiProvider({ apiKey, model });
10616
+ return createGeminiProvider({ apiKey: apiKey ?? "", model });
10516
10617
  default: {
10517
10618
  const never = provider;
10518
10619
  throw new Error(`Unsupported model provider: ${String(never)}`);
@@ -10523,19 +10624,64 @@ function createModelProvider(opts) {
10523
10624
  // src/ai/infer-json.ts
10524
10625
  var JSON_ONLY_INSTRUCTION = "Respond with ONLY a single JSON object, no prose.";
10525
10626
  var RETRY_INSTRUCTION = "Return valid JSON only.";
10627
+ function nextBalancedObject(raw, from) {
10628
+ const start = raw.indexOf("{", from);
10629
+ if (start === -1) {
10630
+ return null;
10631
+ }
10632
+ let depth = 0;
10633
+ let inString = false;
10634
+ let escaped = false;
10635
+ for (let i = start; i < raw.length; i++) {
10636
+ const ch = raw[i];
10637
+ if (inString) {
10638
+ if (escaped) {
10639
+ escaped = false;
10640
+ } else if (ch === "\\") {
10641
+ escaped = true;
10642
+ } else if (ch === '"') {
10643
+ inString = false;
10644
+ }
10645
+ continue;
10646
+ }
10647
+ if (ch === '"') {
10648
+ inString = true;
10649
+ } else if (ch === "{") {
10650
+ depth++;
10651
+ } else if (ch === "}") {
10652
+ depth--;
10653
+ if (depth === 0) {
10654
+ return [start, i];
10655
+ }
10656
+ }
10657
+ }
10658
+ return null;
10659
+ }
10526
10660
  function extractJson(raw) {
10527
- const start = raw.indexOf("{");
10528
- const end = raw.lastIndexOf("}");
10529
- if (start === -1 || end === -1 || end < start) {
10530
- throw new Error("no JSON object found in reply");
10661
+ let from = 0;
10662
+ let sawCandidate = false;
10663
+ for (; ; ) {
10664
+ const span = nextBalancedObject(raw, from);
10665
+ if (!span) {
10666
+ break;
10667
+ }
10668
+ sawCandidate = true;
10669
+ const slice = raw.slice(span[0], span[1] + 1);
10670
+ try {
10671
+ return JSON.parse(slice);
10672
+ } catch {
10673
+ from = span[0] + 1;
10674
+ }
10531
10675
  }
10532
- return JSON.parse(raw.slice(start, end + 1));
10676
+ throw new Error(
10677
+ sawCandidate ? "no valid JSON object found in reply" : "no JSON object found in reply"
10678
+ );
10533
10679
  }
10534
10680
  async function inferJson(opts) {
10535
- const { provider, apiKey, model, system, input, maxTokens, parse } = opts;
10681
+ const { provider, apiKey, model, baseURL, system, input, maxTokens, timeoutMs, signal, parse } = opts;
10536
10682
  let client;
10537
10683
  try {
10538
- client = createModelProvider({ provider, apiKey, model });
10684
+ client = createModelProvider({ provider, apiKey, model, baseURL });
10539
10685
  } catch (err) {
10540
10686
  return { ok: false, error: errMsg(err) };
10541
10687
  }
@@ -10544,7 +10690,11 @@ async function inferJson(opts) {
10544
10690
  ${JSON_ONLY_INSTRUCTION}` : JSON_ONLY_INSTRUCTION;
10545
10691
  const userContent = typeof input === "string" ? input : JSON.stringify(input);
10546
10692
  const messages = [{ role: "user", content: userContent }];
10547
- const first = await runOnce(client, { system: systemPrompt, messages, maxTokens }, parse);
10693
+ const first = await runOnce(
10694
+ client,
10695
+ { system: systemPrompt, messages, maxTokens, timeoutMs, signal },
10696
+ parse
10697
+ );
10548
10698
  if (first.ok) {
10549
10699
  return first;
10550
10700
  }
@@ -10555,7 +10705,7 @@ ${JSON_ONLY_INSTRUCTION}` : JSON_ONLY_INSTRUCTION;
10555
10705
  retryMessages.push({ role: "user", content: RETRY_INSTRUCTION });
10556
10706
  const second = await runOnce(
10557
10707
  client,
10558
- { system: systemPrompt, messages: retryMessages, maxTokens },
10708
+ { system: systemPrompt, messages: retryMessages, maxTokens, timeoutMs, signal },
10559
10709
  parse
10560
10710
  );
10561
10711
  return second;
@@ -10579,9 +10729,6 @@ async function runOnce(client, args, parse) {
10579
10729
  return { ok: false, error: errMsg(err), raw };
10580
10730
  }
10581
10731
  }
10582
- function errMsg(err) {
10583
- return err instanceof Error ? err.message : String(err);
10584
- }
10585
10732
 
10586
10733
  // src/baas/index.ts
10587
10734
  var baas_exports = {};