@hiper2d/ai-agents 0.18.0 → 0.19.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.mjs CHANGED
@@ -713,6 +713,14 @@ var ModelInvalidResponseError = class extends ModelError {
713
713
  this.truncated = truncated;
714
714
  }
715
715
  };
716
+ var ModelTimeoutError = class extends ModelError {
717
+ timeoutMs;
718
+ constructor(modelType, timeoutMs) {
719
+ super(`${modelType} did not respond within ${Math.round(timeoutMs / 1e3)}s`, modelType);
720
+ this.name = "ModelTimeoutError";
721
+ this.timeoutMs = timeoutMs;
722
+ }
723
+ };
716
724
  var ModelRefusalError = class extends ModelError {
717
725
  reason;
718
726
  constructor(modelType, message = `${modelType} refused to answer (stop_reason: refusal)`, reason) {
@@ -798,6 +806,9 @@ var LLM_CONSTANTS = {
798
806
  GEMINI_PRO: "gemini-pro",
799
807
  GEMINI_FLASH: "gemini-flash",
800
808
  GEMINI_LITE: "gemini-lite",
809
+ // Reused 2026-10-06 for Mistral Large 4: the old id (Large 3) was retired 2026-09-18 and
810
+ // consumers had mapped it away, so the version-free id was free again.
811
+ MISTRAL_LARGE: "mistral-large",
801
812
  MISTRAL_MEDIUM: "mistral-medium",
802
813
  MISTRAL_SMALL: "mistral-small",
803
814
  GROK: "grok",
@@ -816,6 +827,7 @@ var LLM_CONSTANTS = {
816
827
  MUSE_SPARK: "muse-spark"
817
828
  };
818
829
  var DEFAULT_MAX_OUTPUT_TOKENS = 8192;
830
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
819
831
  var SupportedAiModels = {
820
832
  // Claude Fable 5.1 (2026-09-02, was Fable 5) - frontier reasoning model. Thinking is always on (no non-thinking variant).
821
833
  [LLM_CONSTANTS.CLAUDE_FABLE]: {
@@ -1004,6 +1016,21 @@ var SupportedAiModels = {
1004
1016
  // returns `mistral-medium-3-5`, `mistral-medium-3`, `mistral-medium-latest` and
1005
1017
  // `magistral-medium-latest` as one entry — so Magistral seats had silently become Medium
1006
1018
  // seats already. Consumers map both retired ids onto the surviving pair.
1019
+ //
1020
+ // Mistral Large 4 added 2026-10-06 under the freed `mistral-large` picker id. The model list
1021
+ // reports reasoning: true (Large 3 said false), 512K context; same reasoning_effort switch,
1022
+ // but only 'high' and 'none' are accepted (medium/low are a 400). Live 2026-10-06 at high:
1023
+ // a chat-turn schema ask took 14-21s with 1.3-2k output tokens (~$0.003), one constrained
1024
+ // pick took 49s — it thinks long, so it is cheap but slow.
1025
+ [LLM_CONSTANTS.MISTRAL_LARGE]: {
1026
+ displayName: "Mistral Large 4",
1027
+ // `mistral-large-4-0` is the same entry; `mistral-large-latest` still points at Large 3.
1028
+ modelApiName: "mistral-large-4",
1029
+ apiKeyName: API_KEY_CONSTANTS.MISTRAL,
1030
+ hasThinking: true,
1031
+ reasoningEffort: "high",
1032
+ tags: ["slow", "cheap"]
1033
+ },
1007
1034
  [LLM_CONSTANTS.MISTRAL_MEDIUM]: {
1008
1035
  displayName: "Mistral Medium 3.5",
1009
1036
  // The docs' explicit 3.5 id. It was `mistral-medium-3` until 2026-09-18, which Mistral
@@ -1393,7 +1420,13 @@ var MODEL_PRICING = {
1393
1420
  // Mistral models (mistral.ai/pricing/api, verified 2026-09-18). Cached tokens bill at 10% of
1394
1421
  // the input price (documented on the prompt_cache_key param; no per-model cached prices
1395
1422
  // published). Reasoning tokens are counted inside completion_tokens — no separate
1396
- // reasoning_tokens field — so the output rate already covers the trace.
1423
+ // reasoning_tokens field — so the output rate already covers the trace. Large 4 added
1424
+ // 2026-10-06 at its published rates ($0.07 cached, not an exact 10%).
1425
+ [SupportedAiModels[LLM_CONSTANTS.MISTRAL_LARGE].modelApiName]: {
1426
+ inputPrice: 0.68,
1427
+ outputPrice: 2.09,
1428
+ cacheHitPrice: 0.07
1429
+ },
1397
1430
  [SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName]: {
1398
1431
  inputPrice: 1.5,
1399
1432
  outputPrice: 7.5,
@@ -1491,6 +1524,7 @@ var HYBRID_THINKING_API_NAMES = /* @__PURE__ */ new Set([
1491
1524
  SupportedAiModels[LLM_CONSTANTS.MINIMAX].modelApiName,
1492
1525
  // Mistral reasons only when asked (`reasoning_effort`), and we always ask — hybrid by the
1493
1526
  // same definition as Qwen. Added 2026-09-18 when the two entries went thinking-on.
1527
+ SupportedAiModels[LLM_CONSTANTS.MISTRAL_LARGE].modelApiName,
1494
1528
  SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName,
1495
1529
  SupportedAiModels[LLM_CONSTANTS.MISTRAL_SMALL].modelApiName
1496
1530
  ]);
@@ -2227,6 +2261,12 @@ var AbstractAgent = class {
2227
2261
  */
2228
2262
  reasoningEffort;
2229
2263
  thinkingBudgetTokens;
2264
+ /**
2265
+ * Wall-clock limit on one ask (DEFAULT_REQUEST_TIMEOUT_MS). Past it the ask throws
2266
+ * ModelTimeoutError; the provider request is abandoned, not cancelled. Raise it per
2267
+ * instance for calls that legitimately run long, like maxOutputTokens.
2268
+ */
2269
+ requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
2230
2270
  instruction;
2231
2271
  /**
2232
2272
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -2261,7 +2301,7 @@ var AbstractAgent = class {
2261
2301
  if (beforeAskHook) await beforeAskHook(this);
2262
2302
  const startedAt = Date.now();
2263
2303
  try {
2264
- const [result, thinking, usage, signature] = await this.doAskWithZodSchema(zodSchema, messages);
2304
+ const [result, thinking, usage, signature] = await this.withTimeout(this.doAskWithZodSchema(zodSchema, messages));
2265
2305
  return [result, thinking, this.stampDuration(usage, startedAt), signature];
2266
2306
  } catch (error) {
2267
2307
  this.stampErrorDuration(error, startedAt);
@@ -2272,13 +2312,25 @@ var AbstractAgent = class {
2272
2312
  if (beforeAskHook) await beforeAskHook(this);
2273
2313
  const startedAt = Date.now();
2274
2314
  try {
2275
- const [content, thinking, usage, signature] = await this.doAskText(messages);
2315
+ const [content, thinking, usage, signature] = await this.withTimeout(this.doAskText(messages));
2276
2316
  return [content, thinking, this.stampDuration(usage, startedAt), signature];
2277
2317
  } catch (error) {
2278
2318
  this.stampErrorDuration(error, startedAt);
2279
2319
  throw error;
2280
2320
  }
2281
2321
  }
2322
+ /**
2323
+ * Races the provider call against requestTimeoutMs. A hung provider (accepts the request,
2324
+ * never answers) otherwise runs until the host kills the function with no error to show.
2325
+ */
2326
+ withTimeout(call) {
2327
+ const timeoutMs = this.requestTimeoutMs;
2328
+ let timer;
2329
+ const timeout = new Promise((_, reject) => {
2330
+ timer = setTimeout(() => reject(new ModelTimeoutError(this.model, timeoutMs)), timeoutMs);
2331
+ });
2332
+ return Promise.race([call, timeout]).finally(() => clearTimeout(timer));
2333
+ }
2282
2334
  stampDuration(usage, startedAt) {
2283
2335
  return usage ? { ...usage, durationMs: Date.now() - startedAt } : usage;
2284
2336
  }
@@ -5294,6 +5346,7 @@ var AgentFactory = class {
5294
5346
  case LLM_CONSTANTS.DEEPSEEK_PRO:
5295
5347
  return new DeepSeekV2Agent(name, instruction, model.modelApiName, key, model.temperature ?? 0, shouldEnableThinking);
5296
5348
  // Mistral models
5349
+ case LLM_CONSTANTS.MISTRAL_LARGE:
5297
5350
  case LLM_CONSTANTS.MISTRAL_MEDIUM:
5298
5351
  case LLM_CONSTANTS.MISTRAL_SMALL:
5299
5352
  return new MistralAgent(name, instruction, model.modelApiName, key, shouldEnableThinking);
@@ -5343,6 +5396,7 @@ export {
5343
5396
  DEEPSEEK_REASONING_EFFORTS,
5344
5397
  DEFAULT_LOGGING_CONFIG,
5345
5398
  DEFAULT_MAX_OUTPUT_TOKENS,
5399
+ DEFAULT_REQUEST_TIMEOUT_MS,
5346
5400
  DeepSeekV2Agent,
5347
5401
  FUGU_REASONING_EFFORTS,
5348
5402
  FuguAgent,
@@ -5372,6 +5426,7 @@ export {
5372
5426
  ModelQuotaExceededError,
5373
5427
  ModelRateLimitError,
5374
5428
  ModelRefusalError,
5429
+ ModelTimeoutError,
5375
5430
  ModelUnavailableError,
5376
5431
  OPENAI_REASONING_EFFORTS,
5377
5432
  OpenAiVoiceAgent,