@hiper2d/ai-agents 0.18.0 → 0.19.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.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) {
@@ -804,7 +812,6 @@ var LLM_CONSTANTS = {
804
812
  KIMI: "kimi",
805
813
  GLM: "glm",
806
814
  GLM_FLASH: "glm-flash",
807
- FUGU_ULTRA: "fugu-ultra",
808
815
  FUGU_MAX: "fugu-max",
809
816
  // Qwen (QwenCloud/DashScope). Stable picker ids without the version, matching the gpt/gemini
810
817
  // pattern, so future repoints don't orphan persisted ids.
@@ -816,6 +823,7 @@ var LLM_CONSTANTS = {
816
823
  MUSE_SPARK: "muse-spark"
817
824
  };
818
825
  var DEFAULT_MAX_OUTPUT_TOKENS = 8192;
826
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
819
827
  var SupportedAiModels = {
820
828
  // Claude Fable 5.1 (2026-09-02, was Fable 5) - frontier reasoning model. Thinking is always on (no non-thinking variant).
821
829
  [LLM_CONSTANTS.CLAUDE_FABLE]: {
@@ -976,16 +984,20 @@ var SupportedAiModels = {
976
984
  },
977
985
  // Always-on reasoning — no non-thinking sibling. Bumped 4.6 → 4.7 on 2026-09-22 (id verified
978
986
  // against GET /v1/models). Same price, same 200K extended-context boundary; the context
979
- // window is 500K. NOTE 4.7 newly accepts `reasoning_effort` (low | medium | high | xhigh,
980
- // default high) where 4.6 had no knob at all. GrokAgent still sends none, so behaviour is
981
- // unchanged — but Grok is the app's most expensive model per turn (94% of its output is
982
- // reasoning), so a lower pin is the obvious lever to measure before anything else.
987
+ // window is 500K. 4.7 accepts `reasoning: {effort}` (low | medium | high | xhigh, default
988
+ // high) where 4.6 had no knob at all; GrokAgent sends the pin below.
989
+ //
990
+ // Pinned medium 2026-10-06. At high, production day summaries ran ~2 min and the werewolf
991
+ // day-2 fixture measured votes 27-55s and summaries 44-55s (1.5-3k output tokens) — too
992
+ // close to the 60s per-call timeout. At medium the same prompts took votes 5-8s and
993
+ // summaries 23-25s (3-5x fewer output tokens) with the same vote target and summaries just
994
+ // as specific.
983
995
  [LLM_CONSTANTS.GROK]: {
984
996
  displayName: "Grok 4.7",
985
997
  modelApiName: "grok-4.7",
986
998
  apiKeyName: API_KEY_CONSTANTS.GROK,
987
999
  hasThinking: true,
988
- reasoningEffort: "high",
1000
+ reasoningEffort: "medium",
989
1001
  temperature: 0.7
990
1002
  },
991
1003
  // Mistral models. Two hybrid entries since 2026-09-18: reasoning is off by default on the
@@ -1004,6 +1016,13 @@ 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 (`mistral-large-4`, $0.68/$2.09, $0.07 cached) was added in 0.19.0 and
1021
+ // removed in 0.19.1 (2026-10-06/07): too slow to play. Like Small/Medium it accepts only
1022
+ // reasoning_effort high|none, and unlike them it reasons when the field is omitted. At high
1023
+ // a realistic day-2 vote took 25-154s (half past the 60s timeout) and its parallel story
1024
+ // batches finished ~100s apart (Mistral served them one at a time: ~6 min per story). Off,
1025
+ // it answers in ~1s with no trace. Re-test before re-adding.
1007
1026
  [LLM_CONSTANTS.MISTRAL_MEDIUM]: {
1008
1027
  displayName: "Mistral Medium 3.5",
1009
1028
  // The docs' explicit 3.5 id. It was `mistral-medium-3` until 2026-09-18, which Mistral
@@ -1088,9 +1107,9 @@ var SupportedAiModels = {
1088
1107
  // real against $0.85 tracked, a 5.7x undercharge. It is a router with no published price,
1089
1108
  // so the rate is not even guaranteed stable, and its cache hit rate was 9.3% — effectively
1090
1109
  // zero, since every hit came from a duplicate call seconds apart rather than turn-to-turn
1091
- // prefix reuse. Ultra costs the same and is predictable.
1110
+ // prefix reuse.
1092
1111
  //
1093
- // reasoningEffort is PINNED on both entries because the server default differs per model:
1112
+ // reasoningEffort was PINNED on both entries because the server default differs per model:
1094
1113
  // fugu-ultra defaults to `xhigh` (console.sakana.ai/models), fugu-max to `high`. Until
1095
1114
  // 2026-09-20 the agent sent no effort at all, so every Ultra turn ran at xhigh. Measured that
1096
1115
  // day on a 2k-token three-day game prompt (two samples each, chat completions, json mode):
@@ -1100,17 +1119,17 @@ var SupportedAiModels = {
1100
1119
  // max xhigh 41s / 47s $0.02
1101
1120
  // `max_tokens` is not a latency lever for Ultra: Sakana applies it to the final response only,
1102
1121
  // the orchestrator "still uses maximum token limit". Effort is the only knob.
1103
- [LLM_CONSTANTS.FUGU_ULTRA]: {
1104
- displayName: "Sakana Fugu Ultra",
1105
- modelApiName: "fugu-ultra",
1106
- apiKeyName: API_KEY_CONSTANTS.FUGU,
1107
- hasThinking: false,
1108
- reasoningEffort: "high",
1109
- tags: ["extremely-slow", "expensive"]
1110
- },
1122
+ //
1123
+ // Fugu Ultra (`fugu-ultra`, $5/$30, $0.50 cached; ×~2 above 272K) was REMOVED in 0.19.1
1124
+ // (2026-10-07): too slow and too expensive for what it played. At `high` a day-2 vote took
1125
+ // 39s and a turn 65-78s (past the 60s request timeout), and as Game Master its four parallel
1126
+ // story batches ran past 240s each. It also billed "orchestration" tokens (its internal expert
1127
+ // calls) on top of the visible counts; FuguAgent still folds those in, in case Max ever
1128
+ // reports them. Consumers map the id to Max.
1111
1129
  // Fugu Max (2026-09-20, fugu-max → fugu-max-v1.0): Sakana's "largest pool of models on the
1112
- // cost–performance Pareto frontier" — the everyday Fugu at 5x less than Ultra's output rate
1113
- // and a fraction of its latency. It reasons (reasoning_tokens 80-500 a turn) but, like
1130
+ // cost–performance Pareto frontier" — 5x less than Ultra's output rate and a fraction of its
1131
+ // latency; the only Fugu since 0.19.1. Live 2026-10-06: day-2 vote 11s, 15-character story
1132
+ // pipeline 100s. It reasons (reasoning_tokens 80-500 a turn) but, like
1114
1133
  // Ultra, never returns reasoning_content, hence hasThinking: false. No orchestration
1115
1134
  // tokens observed on any call.
1116
1135
  [LLM_CONSTANTS.FUGU_MAX]: {
@@ -1417,21 +1436,10 @@ var MODEL_PRICING = {
1417
1436
  extendedContextCacheHitPrice: 1,
1418
1437
  extendedContextThresholdTokens: 2e5
1419
1438
  },
1420
- // Sakana Fugu models (console.sakana.ai/pricing, read 2026-09-20). Base `fugu` was retired
1421
- // 2026-08-04 — it had no published price and measured out at these same ultra rates, so it
1422
- // has no pricing entry. fugu-ultra: above 272K context the rates roughly double. Ultra also
1423
- // reports "orchestration" tokens (its internal expert calls) in prompt_tokens_details /
1424
- // completion_tokens_details, billed at these same input/output rates — FuguAgent folds them
1425
- // into the token counts before pricing.
1426
- [SupportedAiModels[LLM_CONSTANTS.FUGU_ULTRA].modelApiName]: {
1427
- inputPrice: 5,
1428
- outputPrice: 30,
1429
- cacheHitPrice: 0.5,
1430
- extendedContextInputPrice: 10,
1431
- extendedContextOutputPrice: 45,
1432
- extendedContextCacheHitPrice: 1,
1433
- extendedContextThresholdTokens: 272e3
1434
- },
1439
+ // Sakana Fugu (console.sakana.ai/pricing, read 2026-09-20). Base `fugu` (retired 2026-08-04)
1440
+ // and `fugu-ultra` (removed 0.19.1) have no entries. Any "orchestration" tokens reported in
1441
+ // prompt_tokens_details / completion_tokens_details bill at these same rates — FuguAgent
1442
+ // folds them into the token counts before pricing.
1435
1443
  // fugu-max: flat rates, no context tiers.
1436
1444
  [SupportedAiModels[LLM_CONSTANTS.FUGU_MAX].modelApiName]: {
1437
1445
  inputPrice: 2,
@@ -1559,7 +1567,7 @@ var GLM_REASONING_EFFORTS = ["low", "high", "max"];
1559
1567
  var DEEPSEEK_REASONING_EFFORTS = ["low", "high", "max"];
1560
1568
  var FUGU_REASONING_EFFORTS = ["high", "xhigh", "max"];
1561
1569
  var META_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh", "max"];
1562
- var MISTRAL_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
1570
+ var MISTRAL_REASONING_EFFORTS = ["high"];
1563
1571
  var XAI_REASONING_EFFORTS = ["low", "medium", "high", "xhigh"];
1564
1572
  var KIMI_REASONING_EFFORTS = ["low", "high", "max"];
1565
1573
  function clampReasoningEffort(effort, allowed) {
@@ -2227,6 +2235,12 @@ var AbstractAgent = class {
2227
2235
  */
2228
2236
  reasoningEffort;
2229
2237
  thinkingBudgetTokens;
2238
+ /**
2239
+ * Wall-clock limit on one ask (DEFAULT_REQUEST_TIMEOUT_MS). Past it the ask throws
2240
+ * ModelTimeoutError; the provider request is abandoned, not cancelled. Raise it per
2241
+ * instance for calls that legitimately run long, like maxOutputTokens.
2242
+ */
2243
+ requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
2230
2244
  instruction;
2231
2245
  /**
2232
2246
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -2261,7 +2275,7 @@ var AbstractAgent = class {
2261
2275
  if (beforeAskHook) await beforeAskHook(this);
2262
2276
  const startedAt = Date.now();
2263
2277
  try {
2264
- const [result, thinking, usage, signature] = await this.doAskWithZodSchema(zodSchema, messages);
2278
+ const [result, thinking, usage, signature] = await this.withTimeout(this.doAskWithZodSchema(zodSchema, messages));
2265
2279
  return [result, thinking, this.stampDuration(usage, startedAt), signature];
2266
2280
  } catch (error) {
2267
2281
  this.stampErrorDuration(error, startedAt);
@@ -2272,13 +2286,25 @@ var AbstractAgent = class {
2272
2286
  if (beforeAskHook) await beforeAskHook(this);
2273
2287
  const startedAt = Date.now();
2274
2288
  try {
2275
- const [content, thinking, usage, signature] = await this.doAskText(messages);
2289
+ const [content, thinking, usage, signature] = await this.withTimeout(this.doAskText(messages));
2276
2290
  return [content, thinking, this.stampDuration(usage, startedAt), signature];
2277
2291
  } catch (error) {
2278
2292
  this.stampErrorDuration(error, startedAt);
2279
2293
  throw error;
2280
2294
  }
2281
2295
  }
2296
+ /**
2297
+ * Races the provider call against requestTimeoutMs. A hung provider (accepts the request,
2298
+ * never answers) otherwise runs until the host kills the function with no error to show.
2299
+ */
2300
+ withTimeout(call) {
2301
+ const timeoutMs = this.requestTimeoutMs;
2302
+ let timer;
2303
+ const timeout = new Promise((_, reject) => {
2304
+ timer = setTimeout(() => reject(new ModelTimeoutError(this.model, timeoutMs)), timeoutMs);
2305
+ });
2306
+ return Promise.race([call, timeout]).finally(() => clearTimeout(timer));
2307
+ }
2282
2308
  stampDuration(usage, startedAt) {
2283
2309
  return usage ? { ...usage, durationMs: Date.now() - startedAt } : usage;
2284
2310
  }
@@ -5304,7 +5330,6 @@ var AgentFactory = class {
5304
5330
  case LLM_CONSTANTS.GLM_FLASH:
5305
5331
  return new GlmAgent(name, instruction, model.modelApiName, key, model.temperature, shouldEnableThinking);
5306
5332
  // Sakana Fugu models — always-on reasoning, no temperature (ignored by the model)
5307
- case LLM_CONSTANTS.FUGU_ULTRA:
5308
5333
  case LLM_CONSTANTS.FUGU_MAX:
5309
5334
  return new FuguAgent(name, instruction, model.modelApiName, key, shouldEnableThinking);
5310
5335
  // Qwen models — thinking-only (enable_thinking always sent)
@@ -5343,6 +5368,7 @@ export {
5343
5368
  DEEPSEEK_REASONING_EFFORTS,
5344
5369
  DEFAULT_LOGGING_CONFIG,
5345
5370
  DEFAULT_MAX_OUTPUT_TOKENS,
5371
+ DEFAULT_REQUEST_TIMEOUT_MS,
5346
5372
  DeepSeekV2Agent,
5347
5373
  FUGU_REASONING_EFFORTS,
5348
5374
  FuguAgent,
@@ -5372,6 +5398,7 @@ export {
5372
5398
  ModelQuotaExceededError,
5373
5399
  ModelRateLimitError,
5374
5400
  ModelRefusalError,
5401
+ ModelTimeoutError,
5375
5402
  ModelUnavailableError,
5376
5403
  OPENAI_REASONING_EFFORTS,
5377
5404
  OpenAiVoiceAgent,