@hiper2d/ai-agents 0.17.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]: {
@@ -911,9 +923,11 @@ var SupportedAiModels = {
911
923
  // ($4/$20 → $2/$10) and Luna halved ($0.20/$1.20 → $0.10/$0.50). Note GPT-6 Sol now
912
924
  // undercuts GPT-5.6 Terra ($2/$12) on output at the same input rate, which makes the Terra
913
925
  // slot largely redundant — retiring it is a product call, not a catalog one.
926
+ // Sol → GPT-6.1 Sol on 2026-09-29 (id verified against GET /v1/models; gpt-6-sol is still
927
+ // served). Same price as GPT-6 Sol; its no-param default effort still measures `medium`.
914
928
  [LLM_CONSTANTS.GPT_SOL]: {
915
- displayName: "GPT-6 Sol",
916
- modelApiName: "gpt-6-sol",
929
+ displayName: "GPT-6.1 Sol",
930
+ modelApiName: "gpt-6.1-sol",
917
931
  apiKeyName: API_KEY_CONSTANTS.OPENAI,
918
932
  reasoningEffort: "medium",
919
933
  hasThinking: true,
@@ -1002,6 +1016,21 @@ var SupportedAiModels = {
1002
1016
  // returns `mistral-medium-3-5`, `mistral-medium-3`, `mistral-medium-latest` and
1003
1017
  // `magistral-medium-latest` as one entry — so Magistral seats had silently become Medium
1004
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
+ },
1005
1034
  [LLM_CONSTANTS.MISTRAL_MEDIUM]: {
1006
1035
  displayName: "Mistral Medium 3.5",
1007
1036
  // The docs' explicit 3.5 id. It was `mistral-medium-3` until 2026-09-18, which Mistral
@@ -1265,6 +1294,7 @@ var MODEL_PRICING = {
1265
1294
  // As with Astra, OpenAI's table doesn't restate the short/long boundary, so we keep the
1266
1295
  // 272k threshold the 5.6 siblings use. Cache WRITES (Sol $2.50/$5, Luna $0.125/$0.25) are
1267
1296
  // not modelled: OpenAI caching is automatic and the API only reports hits.
1297
+ // GPT-6.1 Sol (2026-09-29) kept GPT-6 Sol's rates exactly, cache writes included.
1268
1298
  [SupportedAiModels[LLM_CONSTANTS.GPT_SOL].modelApiName]: {
1269
1299
  inputPrice: 2,
1270
1300
  outputPrice: 10,
@@ -1390,7 +1420,13 @@ var MODEL_PRICING = {
1390
1420
  // Mistral models (mistral.ai/pricing/api, verified 2026-09-18). Cached tokens bill at 10% of
1391
1421
  // the input price (documented on the prompt_cache_key param; no per-model cached prices
1392
1422
  // published). Reasoning tokens are counted inside completion_tokens — no separate
1393
- // 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
+ },
1394
1430
  [SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName]: {
1395
1431
  inputPrice: 1.5,
1396
1432
  outputPrice: 7.5,
@@ -1488,6 +1524,7 @@ var HYBRID_THINKING_API_NAMES = /* @__PURE__ */ new Set([
1488
1524
  SupportedAiModels[LLM_CONSTANTS.MINIMAX].modelApiName,
1489
1525
  // Mistral reasons only when asked (`reasoning_effort`), and we always ask — hybrid by the
1490
1526
  // same definition as Qwen. Added 2026-09-18 when the two entries went thinking-on.
1527
+ SupportedAiModels[LLM_CONSTANTS.MISTRAL_LARGE].modelApiName,
1491
1528
  SupportedAiModels[LLM_CONSTANTS.MISTRAL_MEDIUM].modelApiName,
1492
1529
  SupportedAiModels[LLM_CONSTANTS.MISTRAL_SMALL].modelApiName
1493
1530
  ]);
@@ -2224,6 +2261,12 @@ var AbstractAgent = class {
2224
2261
  */
2225
2262
  reasoningEffort;
2226
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;
2227
2270
  instruction;
2228
2271
  /**
2229
2272
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -2258,7 +2301,7 @@ var AbstractAgent = class {
2258
2301
  if (beforeAskHook) await beforeAskHook(this);
2259
2302
  const startedAt = Date.now();
2260
2303
  try {
2261
- const [result, thinking, usage, signature] = await this.doAskWithZodSchema(zodSchema, messages);
2304
+ const [result, thinking, usage, signature] = await this.withTimeout(this.doAskWithZodSchema(zodSchema, messages));
2262
2305
  return [result, thinking, this.stampDuration(usage, startedAt), signature];
2263
2306
  } catch (error) {
2264
2307
  this.stampErrorDuration(error, startedAt);
@@ -2269,13 +2312,25 @@ var AbstractAgent = class {
2269
2312
  if (beforeAskHook) await beforeAskHook(this);
2270
2313
  const startedAt = Date.now();
2271
2314
  try {
2272
- const [content, thinking, usage, signature] = await this.doAskText(messages);
2315
+ const [content, thinking, usage, signature] = await this.withTimeout(this.doAskText(messages));
2273
2316
  return [content, thinking, this.stampDuration(usage, startedAt), signature];
2274
2317
  } catch (error) {
2275
2318
  this.stampErrorDuration(error, startedAt);
2276
2319
  throw error;
2277
2320
  }
2278
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
+ }
2279
2334
  stampDuration(usage, startedAt) {
2280
2335
  return usage ? { ...usage, durationMs: Date.now() - startedAt } : usage;
2281
2336
  }
@@ -5291,6 +5346,7 @@ var AgentFactory = class {
5291
5346
  case LLM_CONSTANTS.DEEPSEEK_PRO:
5292
5347
  return new DeepSeekV2Agent(name, instruction, model.modelApiName, key, model.temperature ?? 0, shouldEnableThinking);
5293
5348
  // Mistral models
5349
+ case LLM_CONSTANTS.MISTRAL_LARGE:
5294
5350
  case LLM_CONSTANTS.MISTRAL_MEDIUM:
5295
5351
  case LLM_CONSTANTS.MISTRAL_SMALL:
5296
5352
  return new MistralAgent(name, instruction, model.modelApiName, key, shouldEnableThinking);
@@ -5340,6 +5396,7 @@ export {
5340
5396
  DEEPSEEK_REASONING_EFFORTS,
5341
5397
  DEFAULT_LOGGING_CONFIG,
5342
5398
  DEFAULT_MAX_OUTPUT_TOKENS,
5399
+ DEFAULT_REQUEST_TIMEOUT_MS,
5343
5400
  DeepSeekV2Agent,
5344
5401
  FUGU_REASONING_EFFORTS,
5345
5402
  FuguAgent,
@@ -5369,6 +5426,7 @@ export {
5369
5426
  ModelQuotaExceededError,
5370
5427
  ModelRateLimitError,
5371
5428
  ModelRefusalError,
5429
+ ModelTimeoutError,
5372
5430
  ModelUnavailableError,
5373
5431
  OPENAI_REASONING_EFFORTS,
5374
5432
  OpenAiVoiceAgent,