@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.d.mts CHANGED
@@ -293,6 +293,17 @@ declare class ModelInvalidResponseError extends ModelError {
293
293
  * Google's non-configurable filter — no safetySettings change lifts it.
294
294
  * `reason` = the blockReason or finishReason string.
295
295
  */
296
+ /**
297
+ * The provider did not answer within the agent's `requestTimeoutMs`. The ask gives up
298
+ * instead of hanging until the host's serverless function is killed, which leaves no log
299
+ * line and no error for the player to retry from. Observed 2026-10-01: `deepseek-flash`
300
+ * accepted requests and never answered (no tokens, even streaming) while `deepseek-v4-pro`
301
+ * on the same key answered in 0.5s. Retryable — usually on another model.
302
+ */
303
+ declare class ModelTimeoutError extends ModelError {
304
+ timeoutMs: number;
305
+ constructor(modelType: string, timeoutMs: number);
306
+ }
296
307
  declare class ModelRefusalError extends ModelError {
297
308
  reason?: string;
298
309
  constructor(modelType: string, message?: string, reason?: string);
@@ -370,7 +381,6 @@ declare const LLM_CONSTANTS: {
370
381
  KIMI: string;
371
382
  GLM: string;
372
383
  GLM_FLASH: string;
373
- FUGU_ULTRA: string;
374
384
  FUGU_MAX: string;
375
385
  QWEN_MAX: string;
376
386
  QWEN_FLASH: string;
@@ -388,6 +398,13 @@ declare const LLM_CONSTANTS: {
388
398
  * runaway one. Reasoning effort and thinking budgets are the knobs that change spend.
389
399
  */
390
400
  declare const DEFAULT_MAX_OUTPUT_TOKENS = 8192;
401
+ /**
402
+ * Wall-clock limit on one ask, retries inside the provider SDK included. Past it the ask
403
+ * throws ModelTimeoutError. Measured 2026-10-01 over 7k production calls (14 days): 0.5%
404
+ * ran past 60s — mostly Grok turns and story generation. Callers that legitimately need
405
+ * longer raise `requestTimeoutMs` on the instance, like maxOutputTokens.
406
+ */
407
+ declare const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
391
408
  type ModelTag = 'very-fast' | 'fast' | 'slow' | 'very-slow' | 'extremely-slow' | 'cheap' | 'expensive';
392
409
  type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
393
410
  /**
@@ -534,11 +551,11 @@ declare function getProviderSignatureFields(aiType: string, signature?: string):
534
551
  * exactly that enum). The server default is xhigh for fugu-ultra and high for the rest.
535
552
  * - Meta Muse Spark (verified 2026-09-12): minimal|low|medium|high|xhigh|max ("none" → 400; max is
536
553
  * Standard tier only)
537
- * - Mistral Small 4 / Medium 3.5 (verified 2026-09-18): the API enum is
538
- * none|minimal|low|medium|high|xhigh, with reasoning OFF unless the field is sent. "none" is
539
- * not on the shared scale and means "don't reason", which an agent expresses by omitting the
540
- * field, so the exported slice starts at minimal. Only "high" is documented to return the
541
- * thinking chunk; the intermediate levels are accepted but unverified.
554
+ * - Mistral Small 4 / Medium 3.5 / Large 4: the documented API enum is
555
+ * none|minimal|low|medium|high|xhigh, but every model we run accepts only "none" and "high"
556
+ * (each other value is a 400 "not supported for this model, supported values: [high, none]",
557
+ * checked on all three 2026-10-06). Reasoning is OFF unless the field is sent; "none" means
558
+ * "don't reason", which an agent expresses by omitting the field, so the slice is just high.
542
559
  * - xAI Grok 4.7 (docs.x.ai/developers/model-capabilities/text/reasoning, 2026-09-22):
543
560
  * low|medium|high|xhigh, default high, sent on the Responses API as `reasoning: {effort}`.
544
561
  * Chat Completions has no equivalent. Grok 4.6 and earlier had no knob at all.
@@ -1286,6 +1303,12 @@ declare abstract class AbstractAgent {
1286
1303
  */
1287
1304
  reasoningEffort?: ReasoningEffort;
1288
1305
  thinkingBudgetTokens?: number;
1306
+ /**
1307
+ * Wall-clock limit on one ask (DEFAULT_REQUEST_TIMEOUT_MS). Past it the ask throws
1308
+ * ModelTimeoutError; the provider request is abandoned, not cancelled. Raise it per
1309
+ * instance for calls that legitimately run long, like maxOutputTokens.
1310
+ */
1311
+ requestTimeoutMs: number;
1289
1312
  protected readonly instruction: string;
1290
1313
  /**
1291
1314
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -1306,6 +1329,11 @@ declare abstract class AbstractAgent {
1306
1329
  */
1307
1330
  askWithZodSchema<T>(zodSchema: z.ZodSchema<T>, messages: AIMessage[]): Promise<[T, string, TokenUsage$1?, string?]>;
1308
1331
  askText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1332
+ /**
1333
+ * Races the provider call against requestTimeoutMs. A hung provider (accepts the request,
1334
+ * never answers) otherwise runs until the host kills the function with no error to show.
1335
+ */
1336
+ private withTimeout;
1309
1337
  private stampDuration;
1310
1338
  /** Failed calls carry their duration too — a 35s provider stall that errors is still signal. */
1311
1339
  private stampErrorDuration;
@@ -1804,4 +1832,4 @@ declare class MiniMaxAgent extends AbstractAgent {
1804
1832
  doAskText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1805
1833
  }
1806
1834
 
1807
- export { type AIMessage, ANTHROPIC_REASONING_EFFORTS, API_KEY_CONSTANTS, AbstractAgent, type AgentActivityData, AgentFactory, type AgentLoggingConfig, type AnthropicReasoningEffort, type AnthropicTokenUsage, type ApiKeyMap, type BeforeAskHook, BotResponseError, BudgetController, type BudgetControllerOptions, BudgetExceededError, type BudgetLimit, type BudgetVerdict, CACHE_TIER_MARKER, ClaudeAgent, type CostCalculationOptions, DEEPSEEK_PEAK_SCHEDULE, DEEPSEEK_REASONING_EFFORTS, DEFAULT_LOGGING_CONFIG, DEFAULT_MAX_OUTPUT_TOKENS, type DeepSeekReasoningEffort, type DeepSeekTokenUsage, DeepSeekV2Agent, FUGU_REASONING_EFFORTS, FuguAgent, type FuguReasoningEffort, GEMINI_AUDIO_TOKENS_PER_SECOND, GEMINI_REASONING_EFFORTS, GLM_REASONING_EFFORTS, type GeminiReasoningEffort, GlmAgent, type GlmReasoningEffort, GoogleAgent, type GoogleSttOptions, type GoogleSttResult, type GoogleTokenUsage, type GoogleTtsAudioOptions, type GoogleTtsResult, GoogleVoiceAgent, Gpt5Agent, GrokAgent, type GrokTokenUsage, InMemorySpendStore, type JsonSchemaOptions, KIMI_REASONING_EFFORTS, KimiAgent, type KimiReasoningEffort, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MISTRAL_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, type MistralReasoningEffort, type MistralTokenUsage, type Modality, ModelAuthenticationError, type ModelConfig, ModelError, ModelInvalidResponseError, ModelOverloadError, type ModelPricing, ModelQuotaExceededError, ModelRateLimitError, ModelRefusalError, type ModelTag, ModelUnavailableError, OPENAI_REASONING_EFFORTS, type OpenAIReasoningEffort, type OpenAITokenUsage, type OpenAiSttOptions, type OpenAiSttResult, type OpenAiTtsAudioOptions, type OpenAiTtsVoice, OpenAiVoiceAgent, type PeakPricing, type PricingUnit, type ProviderSchema, type TokenUsage as ProviderTokenUsage, type ProviderType, QwenAgent, REASONING_EFFORT_SCALE, type ReasoningEffort, SUPPORTED_VOICE_PROVIDERS, type SpeechRequest, type SpeechResult, type SpeechUsage, type SpendInput, type SpendKind, type SpendLedger, type SpendLedgers, type SpendStore, type SpendWindow, SupportedAiKeyNames, SupportedAiModels, type TokenPairUsage, type TokenUsage$1 as TokenUsage, type TranscriptionRequest, type TranscriptionResult, type TranscriptionUsage, VOICE_MODEL_CONSTANTS, VOICE_MODEL_PRICING, VOICE_PROVIDER_API_KEY, type VoiceAgent, VoiceAgentFactory, type VoiceModelPricing, type VoiceProvider, XAI_REASONING_EFFORTS, type XaiReasoningEffort, ZodSchemaConverter, applySpend, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, describeEmptyTtsResponse, evaluateBudget, extractAnthropicTokenUsage, extractTokenUsageFromResponse$2 as extractAnthropicTokenUsageFromResponse, extractDeepSeekTokenUsage, extractTokenUsageFromResponse$6 as extractDeepSeekTokenUsageFromResponse, extractFirstJsonObject, extractGoogleTokenUsage, extractTokenUsageFromResponse$1 as extractGoogleTokenUsageFromResponse, extractGrokTokenUsage, extractTokenUsageFromResponse$4 as extractGrokTokenUsageFromResponse, extractKimiTokenUsage, extractTokenUsageFromResponse$5 as extractKimiTokenUsageFromResponse, extractMetaTokenUsage, extractTokenUsageFromResponse$3 as extractMetaTokenUsageFromResponse, extractMistralTokenUsage, extractTokenUsageFromResponse as extractMistralTokenUsageFromResponse, extractOpenAITokenUsage, extractTokenUsageFromResponse$7 as extractOpenAITokenUsageFromResponse, extractTokenUsage, extractUsageAndCalculateCost, firstRefusal, generateGoogleTtsAudio, generateOpenAiTtsAudio, generateSchemaInstructions, getModelConfigByApiName, getModelDisplayName, getModelProviderName, getModelTags, getProviderSignatureFields, isBudgetExceededError, isHybridThinkingModel, isInPeakWindow, isPeakBilling, isSafetyBlocked, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, normalizeTtsStyle, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toKimiEffort, toMetaEffort, toMistralEffort, toOpenAIEffort, toXaiEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
1835
+ export { type AIMessage, ANTHROPIC_REASONING_EFFORTS, API_KEY_CONSTANTS, AbstractAgent, type AgentActivityData, AgentFactory, type AgentLoggingConfig, type AnthropicReasoningEffort, type AnthropicTokenUsage, type ApiKeyMap, type BeforeAskHook, BotResponseError, BudgetController, type BudgetControllerOptions, BudgetExceededError, type BudgetLimit, type BudgetVerdict, CACHE_TIER_MARKER, ClaudeAgent, type CostCalculationOptions, DEEPSEEK_PEAK_SCHEDULE, DEEPSEEK_REASONING_EFFORTS, DEFAULT_LOGGING_CONFIG, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_REQUEST_TIMEOUT_MS, type DeepSeekReasoningEffort, type DeepSeekTokenUsage, DeepSeekV2Agent, FUGU_REASONING_EFFORTS, FuguAgent, type FuguReasoningEffort, GEMINI_AUDIO_TOKENS_PER_SECOND, GEMINI_REASONING_EFFORTS, GLM_REASONING_EFFORTS, type GeminiReasoningEffort, GlmAgent, type GlmReasoningEffort, GoogleAgent, type GoogleSttOptions, type GoogleSttResult, type GoogleTokenUsage, type GoogleTtsAudioOptions, type GoogleTtsResult, GoogleVoiceAgent, Gpt5Agent, GrokAgent, type GrokTokenUsage, InMemorySpendStore, type JsonSchemaOptions, KIMI_REASONING_EFFORTS, KimiAgent, type KimiReasoningEffort, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MISTRAL_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, type MistralReasoningEffort, type MistralTokenUsage, type Modality, ModelAuthenticationError, type ModelConfig, ModelError, ModelInvalidResponseError, ModelOverloadError, type ModelPricing, ModelQuotaExceededError, ModelRateLimitError, ModelRefusalError, type ModelTag, ModelTimeoutError, ModelUnavailableError, OPENAI_REASONING_EFFORTS, type OpenAIReasoningEffort, type OpenAITokenUsage, type OpenAiSttOptions, type OpenAiSttResult, type OpenAiTtsAudioOptions, type OpenAiTtsVoice, OpenAiVoiceAgent, type PeakPricing, type PricingUnit, type ProviderSchema, type TokenUsage as ProviderTokenUsage, type ProviderType, QwenAgent, REASONING_EFFORT_SCALE, type ReasoningEffort, SUPPORTED_VOICE_PROVIDERS, type SpeechRequest, type SpeechResult, type SpeechUsage, type SpendInput, type SpendKind, type SpendLedger, type SpendLedgers, type SpendStore, type SpendWindow, SupportedAiKeyNames, SupportedAiModels, type TokenPairUsage, type TokenUsage$1 as TokenUsage, type TranscriptionRequest, type TranscriptionResult, type TranscriptionUsage, VOICE_MODEL_CONSTANTS, VOICE_MODEL_PRICING, VOICE_PROVIDER_API_KEY, type VoiceAgent, VoiceAgentFactory, type VoiceModelPricing, type VoiceProvider, XAI_REASONING_EFFORTS, type XaiReasoningEffort, ZodSchemaConverter, applySpend, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, describeEmptyTtsResponse, evaluateBudget, extractAnthropicTokenUsage, extractTokenUsageFromResponse$2 as extractAnthropicTokenUsageFromResponse, extractDeepSeekTokenUsage, extractTokenUsageFromResponse$6 as extractDeepSeekTokenUsageFromResponse, extractFirstJsonObject, extractGoogleTokenUsage, extractTokenUsageFromResponse$1 as extractGoogleTokenUsageFromResponse, extractGrokTokenUsage, extractTokenUsageFromResponse$4 as extractGrokTokenUsageFromResponse, extractKimiTokenUsage, extractTokenUsageFromResponse$5 as extractKimiTokenUsageFromResponse, extractMetaTokenUsage, extractTokenUsageFromResponse$3 as extractMetaTokenUsageFromResponse, extractMistralTokenUsage, extractTokenUsageFromResponse as extractMistralTokenUsageFromResponse, extractOpenAITokenUsage, extractTokenUsageFromResponse$7 as extractOpenAITokenUsageFromResponse, extractTokenUsage, extractUsageAndCalculateCost, firstRefusal, generateGoogleTtsAudio, generateOpenAiTtsAudio, generateSchemaInstructions, getModelConfigByApiName, getModelDisplayName, getModelProviderName, getModelTags, getProviderSignatureFields, isBudgetExceededError, isHybridThinkingModel, isInPeakWindow, isPeakBilling, isSafetyBlocked, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, normalizeTtsStyle, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toKimiEffort, toMetaEffort, toMistralEffort, toOpenAIEffort, toXaiEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
package/dist/index.d.ts CHANGED
@@ -293,6 +293,17 @@ declare class ModelInvalidResponseError extends ModelError {
293
293
  * Google's non-configurable filter — no safetySettings change lifts it.
294
294
  * `reason` = the blockReason or finishReason string.
295
295
  */
296
+ /**
297
+ * The provider did not answer within the agent's `requestTimeoutMs`. The ask gives up
298
+ * instead of hanging until the host's serverless function is killed, which leaves no log
299
+ * line and no error for the player to retry from. Observed 2026-10-01: `deepseek-flash`
300
+ * accepted requests and never answered (no tokens, even streaming) while `deepseek-v4-pro`
301
+ * on the same key answered in 0.5s. Retryable — usually on another model.
302
+ */
303
+ declare class ModelTimeoutError extends ModelError {
304
+ timeoutMs: number;
305
+ constructor(modelType: string, timeoutMs: number);
306
+ }
296
307
  declare class ModelRefusalError extends ModelError {
297
308
  reason?: string;
298
309
  constructor(modelType: string, message?: string, reason?: string);
@@ -370,7 +381,6 @@ declare const LLM_CONSTANTS: {
370
381
  KIMI: string;
371
382
  GLM: string;
372
383
  GLM_FLASH: string;
373
- FUGU_ULTRA: string;
374
384
  FUGU_MAX: string;
375
385
  QWEN_MAX: string;
376
386
  QWEN_FLASH: string;
@@ -388,6 +398,13 @@ declare const LLM_CONSTANTS: {
388
398
  * runaway one. Reasoning effort and thinking budgets are the knobs that change spend.
389
399
  */
390
400
  declare const DEFAULT_MAX_OUTPUT_TOKENS = 8192;
401
+ /**
402
+ * Wall-clock limit on one ask, retries inside the provider SDK included. Past it the ask
403
+ * throws ModelTimeoutError. Measured 2026-10-01 over 7k production calls (14 days): 0.5%
404
+ * ran past 60s — mostly Grok turns and story generation. Callers that legitimately need
405
+ * longer raise `requestTimeoutMs` on the instance, like maxOutputTokens.
406
+ */
407
+ declare const DEFAULT_REQUEST_TIMEOUT_MS = 60000;
391
408
  type ModelTag = 'very-fast' | 'fast' | 'slow' | 'very-slow' | 'extremely-slow' | 'cheap' | 'expensive';
392
409
  type ReasoningEffort = 'minimal' | 'low' | 'medium' | 'high' | 'xhigh' | 'max';
393
410
  /**
@@ -534,11 +551,11 @@ declare function getProviderSignatureFields(aiType: string, signature?: string):
534
551
  * exactly that enum). The server default is xhigh for fugu-ultra and high for the rest.
535
552
  * - Meta Muse Spark (verified 2026-09-12): minimal|low|medium|high|xhigh|max ("none" → 400; max is
536
553
  * Standard tier only)
537
- * - Mistral Small 4 / Medium 3.5 (verified 2026-09-18): the API enum is
538
- * none|minimal|low|medium|high|xhigh, with reasoning OFF unless the field is sent. "none" is
539
- * not on the shared scale and means "don't reason", which an agent expresses by omitting the
540
- * field, so the exported slice starts at minimal. Only "high" is documented to return the
541
- * thinking chunk; the intermediate levels are accepted but unverified.
554
+ * - Mistral Small 4 / Medium 3.5 / Large 4: the documented API enum is
555
+ * none|minimal|low|medium|high|xhigh, but every model we run accepts only "none" and "high"
556
+ * (each other value is a 400 "not supported for this model, supported values: [high, none]",
557
+ * checked on all three 2026-10-06). Reasoning is OFF unless the field is sent; "none" means
558
+ * "don't reason", which an agent expresses by omitting the field, so the slice is just high.
542
559
  * - xAI Grok 4.7 (docs.x.ai/developers/model-capabilities/text/reasoning, 2026-09-22):
543
560
  * low|medium|high|xhigh, default high, sent on the Responses API as `reasoning: {effort}`.
544
561
  * Chat Completions has no equivalent. Grok 4.6 and earlier had no knob at all.
@@ -1286,6 +1303,12 @@ declare abstract class AbstractAgent {
1286
1303
  */
1287
1304
  reasoningEffort?: ReasoningEffort;
1288
1305
  thinkingBudgetTokens?: number;
1306
+ /**
1307
+ * Wall-clock limit on one ask (DEFAULT_REQUEST_TIMEOUT_MS). Past it the ask throws
1308
+ * ModelTimeoutError; the provider request is abandoned, not cancelled. Raise it per
1309
+ * instance for calls that legitimately run long, like maxOutputTokens.
1310
+ */
1311
+ requestTimeoutMs: number;
1289
1312
  protected readonly instruction: string;
1290
1313
  /**
1291
1314
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -1306,6 +1329,11 @@ declare abstract class AbstractAgent {
1306
1329
  */
1307
1330
  askWithZodSchema<T>(zodSchema: z.ZodSchema<T>, messages: AIMessage[]): Promise<[T, string, TokenUsage$1?, string?]>;
1308
1331
  askText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1332
+ /**
1333
+ * Races the provider call against requestTimeoutMs. A hung provider (accepts the request,
1334
+ * never answers) otherwise runs until the host kills the function with no error to show.
1335
+ */
1336
+ private withTimeout;
1309
1337
  private stampDuration;
1310
1338
  /** Failed calls carry their duration too — a 35s provider stall that errors is still signal. */
1311
1339
  private stampErrorDuration;
@@ -1804,4 +1832,4 @@ declare class MiniMaxAgent extends AbstractAgent {
1804
1832
  doAskText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1805
1833
  }
1806
1834
 
1807
- export { type AIMessage, ANTHROPIC_REASONING_EFFORTS, API_KEY_CONSTANTS, AbstractAgent, type AgentActivityData, AgentFactory, type AgentLoggingConfig, type AnthropicReasoningEffort, type AnthropicTokenUsage, type ApiKeyMap, type BeforeAskHook, BotResponseError, BudgetController, type BudgetControllerOptions, BudgetExceededError, type BudgetLimit, type BudgetVerdict, CACHE_TIER_MARKER, ClaudeAgent, type CostCalculationOptions, DEEPSEEK_PEAK_SCHEDULE, DEEPSEEK_REASONING_EFFORTS, DEFAULT_LOGGING_CONFIG, DEFAULT_MAX_OUTPUT_TOKENS, type DeepSeekReasoningEffort, type DeepSeekTokenUsage, DeepSeekV2Agent, FUGU_REASONING_EFFORTS, FuguAgent, type FuguReasoningEffort, GEMINI_AUDIO_TOKENS_PER_SECOND, GEMINI_REASONING_EFFORTS, GLM_REASONING_EFFORTS, type GeminiReasoningEffort, GlmAgent, type GlmReasoningEffort, GoogleAgent, type GoogleSttOptions, type GoogleSttResult, type GoogleTokenUsage, type GoogleTtsAudioOptions, type GoogleTtsResult, GoogleVoiceAgent, Gpt5Agent, GrokAgent, type GrokTokenUsage, InMemorySpendStore, type JsonSchemaOptions, KIMI_REASONING_EFFORTS, KimiAgent, type KimiReasoningEffort, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MISTRAL_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, type MistralReasoningEffort, type MistralTokenUsage, type Modality, ModelAuthenticationError, type ModelConfig, ModelError, ModelInvalidResponseError, ModelOverloadError, type ModelPricing, ModelQuotaExceededError, ModelRateLimitError, ModelRefusalError, type ModelTag, ModelUnavailableError, OPENAI_REASONING_EFFORTS, type OpenAIReasoningEffort, type OpenAITokenUsage, type OpenAiSttOptions, type OpenAiSttResult, type OpenAiTtsAudioOptions, type OpenAiTtsVoice, OpenAiVoiceAgent, type PeakPricing, type PricingUnit, type ProviderSchema, type TokenUsage as ProviderTokenUsage, type ProviderType, QwenAgent, REASONING_EFFORT_SCALE, type ReasoningEffort, SUPPORTED_VOICE_PROVIDERS, type SpeechRequest, type SpeechResult, type SpeechUsage, type SpendInput, type SpendKind, type SpendLedger, type SpendLedgers, type SpendStore, type SpendWindow, SupportedAiKeyNames, SupportedAiModels, type TokenPairUsage, type TokenUsage$1 as TokenUsage, type TranscriptionRequest, type TranscriptionResult, type TranscriptionUsage, VOICE_MODEL_CONSTANTS, VOICE_MODEL_PRICING, VOICE_PROVIDER_API_KEY, type VoiceAgent, VoiceAgentFactory, type VoiceModelPricing, type VoiceProvider, XAI_REASONING_EFFORTS, type XaiReasoningEffort, ZodSchemaConverter, applySpend, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, describeEmptyTtsResponse, evaluateBudget, extractAnthropicTokenUsage, extractTokenUsageFromResponse$2 as extractAnthropicTokenUsageFromResponse, extractDeepSeekTokenUsage, extractTokenUsageFromResponse$6 as extractDeepSeekTokenUsageFromResponse, extractFirstJsonObject, extractGoogleTokenUsage, extractTokenUsageFromResponse$1 as extractGoogleTokenUsageFromResponse, extractGrokTokenUsage, extractTokenUsageFromResponse$4 as extractGrokTokenUsageFromResponse, extractKimiTokenUsage, extractTokenUsageFromResponse$5 as extractKimiTokenUsageFromResponse, extractMetaTokenUsage, extractTokenUsageFromResponse$3 as extractMetaTokenUsageFromResponse, extractMistralTokenUsage, extractTokenUsageFromResponse as extractMistralTokenUsageFromResponse, extractOpenAITokenUsage, extractTokenUsageFromResponse$7 as extractOpenAITokenUsageFromResponse, extractTokenUsage, extractUsageAndCalculateCost, firstRefusal, generateGoogleTtsAudio, generateOpenAiTtsAudio, generateSchemaInstructions, getModelConfigByApiName, getModelDisplayName, getModelProviderName, getModelTags, getProviderSignatureFields, isBudgetExceededError, isHybridThinkingModel, isInPeakWindow, isPeakBilling, isSafetyBlocked, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, normalizeTtsStyle, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toKimiEffort, toMetaEffort, toMistralEffort, toOpenAIEffort, toXaiEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
1835
+ export { type AIMessage, ANTHROPIC_REASONING_EFFORTS, API_KEY_CONSTANTS, AbstractAgent, type AgentActivityData, AgentFactory, type AgentLoggingConfig, type AnthropicReasoningEffort, type AnthropicTokenUsage, type ApiKeyMap, type BeforeAskHook, BotResponseError, BudgetController, type BudgetControllerOptions, BudgetExceededError, type BudgetLimit, type BudgetVerdict, CACHE_TIER_MARKER, ClaudeAgent, type CostCalculationOptions, DEEPSEEK_PEAK_SCHEDULE, DEEPSEEK_REASONING_EFFORTS, DEFAULT_LOGGING_CONFIG, DEFAULT_MAX_OUTPUT_TOKENS, DEFAULT_REQUEST_TIMEOUT_MS, type DeepSeekReasoningEffort, type DeepSeekTokenUsage, DeepSeekV2Agent, FUGU_REASONING_EFFORTS, FuguAgent, type FuguReasoningEffort, GEMINI_AUDIO_TOKENS_PER_SECOND, GEMINI_REASONING_EFFORTS, GLM_REASONING_EFFORTS, type GeminiReasoningEffort, GlmAgent, type GlmReasoningEffort, GoogleAgent, type GoogleSttOptions, type GoogleSttResult, type GoogleTokenUsage, type GoogleTtsAudioOptions, type GoogleTtsResult, GoogleVoiceAgent, Gpt5Agent, GrokAgent, type GrokTokenUsage, InMemorySpendStore, type JsonSchemaOptions, KIMI_REASONING_EFFORTS, KimiAgent, type KimiReasoningEffort, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MISTRAL_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, type MistralReasoningEffort, type MistralTokenUsage, type Modality, ModelAuthenticationError, type ModelConfig, ModelError, ModelInvalidResponseError, ModelOverloadError, type ModelPricing, ModelQuotaExceededError, ModelRateLimitError, ModelRefusalError, type ModelTag, ModelTimeoutError, ModelUnavailableError, OPENAI_REASONING_EFFORTS, type OpenAIReasoningEffort, type OpenAITokenUsage, type OpenAiSttOptions, type OpenAiSttResult, type OpenAiTtsAudioOptions, type OpenAiTtsVoice, OpenAiVoiceAgent, type PeakPricing, type PricingUnit, type ProviderSchema, type TokenUsage as ProviderTokenUsage, type ProviderType, QwenAgent, REASONING_EFFORT_SCALE, type ReasoningEffort, SUPPORTED_VOICE_PROVIDERS, type SpeechRequest, type SpeechResult, type SpeechUsage, type SpendInput, type SpendKind, type SpendLedger, type SpendLedgers, type SpendStore, type SpendWindow, SupportedAiKeyNames, SupportedAiModels, type TokenPairUsage, type TokenUsage$1 as TokenUsage, type TranscriptionRequest, type TranscriptionResult, type TranscriptionUsage, VOICE_MODEL_CONSTANTS, VOICE_MODEL_PRICING, VOICE_PROVIDER_API_KEY, type VoiceAgent, VoiceAgentFactory, type VoiceModelPricing, type VoiceProvider, XAI_REASONING_EFFORTS, type XaiReasoningEffort, ZodSchemaConverter, applySpend, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, describeEmptyTtsResponse, evaluateBudget, extractAnthropicTokenUsage, extractTokenUsageFromResponse$2 as extractAnthropicTokenUsageFromResponse, extractDeepSeekTokenUsage, extractTokenUsageFromResponse$6 as extractDeepSeekTokenUsageFromResponse, extractFirstJsonObject, extractGoogleTokenUsage, extractTokenUsageFromResponse$1 as extractGoogleTokenUsageFromResponse, extractGrokTokenUsage, extractTokenUsageFromResponse$4 as extractGrokTokenUsageFromResponse, extractKimiTokenUsage, extractTokenUsageFromResponse$5 as extractKimiTokenUsageFromResponse, extractMetaTokenUsage, extractTokenUsageFromResponse$3 as extractMetaTokenUsageFromResponse, extractMistralTokenUsage, extractTokenUsageFromResponse as extractMistralTokenUsageFromResponse, extractOpenAITokenUsage, extractTokenUsageFromResponse$7 as extractOpenAITokenUsageFromResponse, extractTokenUsage, extractUsageAndCalculateCost, firstRefusal, generateGoogleTtsAudio, generateOpenAiTtsAudio, generateSchemaInstructions, getModelConfigByApiName, getModelDisplayName, getModelProviderName, getModelTags, getProviderSignatureFields, isBudgetExceededError, isHybridThinkingModel, isInPeakWindow, isPeakBilling, isSafetyBlocked, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, normalizeTtsStyle, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toKimiEffort, toMetaEffort, toMistralEffort, toOpenAIEffort, toXaiEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
package/dist/index.js CHANGED
@@ -43,6 +43,7 @@ __export(src_exports, {
43
43
  DEEPSEEK_REASONING_EFFORTS: () => DEEPSEEK_REASONING_EFFORTS,
44
44
  DEFAULT_LOGGING_CONFIG: () => DEFAULT_LOGGING_CONFIG,
45
45
  DEFAULT_MAX_OUTPUT_TOKENS: () => DEFAULT_MAX_OUTPUT_TOKENS,
46
+ DEFAULT_REQUEST_TIMEOUT_MS: () => DEFAULT_REQUEST_TIMEOUT_MS,
46
47
  DeepSeekV2Agent: () => DeepSeekV2Agent,
47
48
  FUGU_REASONING_EFFORTS: () => FUGU_REASONING_EFFORTS,
48
49
  FuguAgent: () => FuguAgent,
@@ -72,6 +73,7 @@ __export(src_exports, {
72
73
  ModelQuotaExceededError: () => ModelQuotaExceededError,
73
74
  ModelRateLimitError: () => ModelRateLimitError,
74
75
  ModelRefusalError: () => ModelRefusalError,
76
+ ModelTimeoutError: () => ModelTimeoutError,
75
77
  ModelUnavailableError: () => ModelUnavailableError,
76
78
  OPENAI_REASONING_EFFORTS: () => OPENAI_REASONING_EFFORTS,
77
79
  OpenAiVoiceAgent: () => OpenAiVoiceAgent,
@@ -889,6 +891,14 @@ var ModelInvalidResponseError = class extends ModelError {
889
891
  this.truncated = truncated;
890
892
  }
891
893
  };
894
+ var ModelTimeoutError = class extends ModelError {
895
+ timeoutMs;
896
+ constructor(modelType, timeoutMs) {
897
+ super(`${modelType} did not respond within ${Math.round(timeoutMs / 1e3)}s`, modelType);
898
+ this.name = "ModelTimeoutError";
899
+ this.timeoutMs = timeoutMs;
900
+ }
901
+ };
892
902
  var ModelRefusalError = class extends ModelError {
893
903
  reason;
894
904
  constructor(modelType, message = `${modelType} refused to answer (stop_reason: refusal)`, reason) {
@@ -980,7 +990,6 @@ var LLM_CONSTANTS = {
980
990
  KIMI: "kimi",
981
991
  GLM: "glm",
982
992
  GLM_FLASH: "glm-flash",
983
- FUGU_ULTRA: "fugu-ultra",
984
993
  FUGU_MAX: "fugu-max",
985
994
  // Qwen (QwenCloud/DashScope). Stable picker ids without the version, matching the gpt/gemini
986
995
  // pattern, so future repoints don't orphan persisted ids.
@@ -992,6 +1001,7 @@ var LLM_CONSTANTS = {
992
1001
  MUSE_SPARK: "muse-spark"
993
1002
  };
994
1003
  var DEFAULT_MAX_OUTPUT_TOKENS = 8192;
1004
+ var DEFAULT_REQUEST_TIMEOUT_MS = 6e4;
995
1005
  var SupportedAiModels = {
996
1006
  // Claude Fable 5.1 (2026-09-02, was Fable 5) - frontier reasoning model. Thinking is always on (no non-thinking variant).
997
1007
  [LLM_CONSTANTS.CLAUDE_FABLE]: {
@@ -1152,16 +1162,20 @@ var SupportedAiModels = {
1152
1162
  },
1153
1163
  // Always-on reasoning — no non-thinking sibling. Bumped 4.6 → 4.7 on 2026-09-22 (id verified
1154
1164
  // against GET /v1/models). Same price, same 200K extended-context boundary; the context
1155
- // window is 500K. NOTE 4.7 newly accepts `reasoning_effort` (low | medium | high | xhigh,
1156
- // default high) where 4.6 had no knob at all. GrokAgent still sends none, so behaviour is
1157
- // unchanged — but Grok is the app's most expensive model per turn (94% of its output is
1158
- // reasoning), so a lower pin is the obvious lever to measure before anything else.
1165
+ // window is 500K. 4.7 accepts `reasoning: {effort}` (low | medium | high | xhigh, default
1166
+ // high) where 4.6 had no knob at all; GrokAgent sends the pin below.
1167
+ //
1168
+ // Pinned medium 2026-10-06. At high, production day summaries ran ~2 min and the werewolf
1169
+ // day-2 fixture measured votes 27-55s and summaries 44-55s (1.5-3k output tokens) — too
1170
+ // close to the 60s per-call timeout. At medium the same prompts took votes 5-8s and
1171
+ // summaries 23-25s (3-5x fewer output tokens) with the same vote target and summaries just
1172
+ // as specific.
1159
1173
  [LLM_CONSTANTS.GROK]: {
1160
1174
  displayName: "Grok 4.7",
1161
1175
  modelApiName: "grok-4.7",
1162
1176
  apiKeyName: API_KEY_CONSTANTS.GROK,
1163
1177
  hasThinking: true,
1164
- reasoningEffort: "high",
1178
+ reasoningEffort: "medium",
1165
1179
  temperature: 0.7
1166
1180
  },
1167
1181
  // Mistral models. Two hybrid entries since 2026-09-18: reasoning is off by default on the
@@ -1180,6 +1194,13 @@ var SupportedAiModels = {
1180
1194
  // returns `mistral-medium-3-5`, `mistral-medium-3`, `mistral-medium-latest` and
1181
1195
  // `magistral-medium-latest` as one entry — so Magistral seats had silently become Medium
1182
1196
  // seats already. Consumers map both retired ids onto the surviving pair.
1197
+ //
1198
+ // Mistral Large 4 (`mistral-large-4`, $0.68/$2.09, $0.07 cached) was added in 0.19.0 and
1199
+ // removed in 0.19.1 (2026-10-06/07): too slow to play. Like Small/Medium it accepts only
1200
+ // reasoning_effort high|none, and unlike them it reasons when the field is omitted. At high
1201
+ // a realistic day-2 vote took 25-154s (half past the 60s timeout) and its parallel story
1202
+ // batches finished ~100s apart (Mistral served them one at a time: ~6 min per story). Off,
1203
+ // it answers in ~1s with no trace. Re-test before re-adding.
1183
1204
  [LLM_CONSTANTS.MISTRAL_MEDIUM]: {
1184
1205
  displayName: "Mistral Medium 3.5",
1185
1206
  // The docs' explicit 3.5 id. It was `mistral-medium-3` until 2026-09-18, which Mistral
@@ -1264,9 +1285,9 @@ var SupportedAiModels = {
1264
1285
  // real against $0.85 tracked, a 5.7x undercharge. It is a router with no published price,
1265
1286
  // so the rate is not even guaranteed stable, and its cache hit rate was 9.3% — effectively
1266
1287
  // zero, since every hit came from a duplicate call seconds apart rather than turn-to-turn
1267
- // prefix reuse. Ultra costs the same and is predictable.
1288
+ // prefix reuse.
1268
1289
  //
1269
- // reasoningEffort is PINNED on both entries because the server default differs per model:
1290
+ // reasoningEffort was PINNED on both entries because the server default differs per model:
1270
1291
  // fugu-ultra defaults to `xhigh` (console.sakana.ai/models), fugu-max to `high`. Until
1271
1292
  // 2026-09-20 the agent sent no effort at all, so every Ultra turn ran at xhigh. Measured that
1272
1293
  // day on a 2k-token three-day game prompt (two samples each, chat completions, json mode):
@@ -1276,17 +1297,17 @@ var SupportedAiModels = {
1276
1297
  // max xhigh 41s / 47s $0.02
1277
1298
  // `max_tokens` is not a latency lever for Ultra: Sakana applies it to the final response only,
1278
1299
  // the orchestrator "still uses maximum token limit". Effort is the only knob.
1279
- [LLM_CONSTANTS.FUGU_ULTRA]: {
1280
- displayName: "Sakana Fugu Ultra",
1281
- modelApiName: "fugu-ultra",
1282
- apiKeyName: API_KEY_CONSTANTS.FUGU,
1283
- hasThinking: false,
1284
- reasoningEffort: "high",
1285
- tags: ["extremely-slow", "expensive"]
1286
- },
1300
+ //
1301
+ // Fugu Ultra (`fugu-ultra`, $5/$30, $0.50 cached; ×~2 above 272K) was REMOVED in 0.19.1
1302
+ // (2026-10-07): too slow and too expensive for what it played. At `high` a day-2 vote took
1303
+ // 39s and a turn 65-78s (past the 60s request timeout), and as Game Master its four parallel
1304
+ // story batches ran past 240s each. It also billed "orchestration" tokens (its internal expert
1305
+ // calls) on top of the visible counts; FuguAgent still folds those in, in case Max ever
1306
+ // reports them. Consumers map the id to Max.
1287
1307
  // Fugu Max (2026-09-20, fugu-max → fugu-max-v1.0): Sakana's "largest pool of models on the
1288
- // cost–performance Pareto frontier" — the everyday Fugu at 5x less than Ultra's output rate
1289
- // and a fraction of its latency. It reasons (reasoning_tokens 80-500 a turn) but, like
1308
+ // cost–performance Pareto frontier" — 5x less than Ultra's output rate and a fraction of its
1309
+ // latency; the only Fugu since 0.19.1. Live 2026-10-06: day-2 vote 11s, 15-character story
1310
+ // pipeline 100s. It reasons (reasoning_tokens 80-500 a turn) but, like
1290
1311
  // Ultra, never returns reasoning_content, hence hasThinking: false. No orchestration
1291
1312
  // tokens observed on any call.
1292
1313
  [LLM_CONSTANTS.FUGU_MAX]: {
@@ -1593,21 +1614,10 @@ var MODEL_PRICING = {
1593
1614
  extendedContextCacheHitPrice: 1,
1594
1615
  extendedContextThresholdTokens: 2e5
1595
1616
  },
1596
- // Sakana Fugu models (console.sakana.ai/pricing, read 2026-09-20). Base `fugu` was retired
1597
- // 2026-08-04 — it had no published price and measured out at these same ultra rates, so it
1598
- // has no pricing entry. fugu-ultra: above 272K context the rates roughly double. Ultra also
1599
- // reports "orchestration" tokens (its internal expert calls) in prompt_tokens_details /
1600
- // completion_tokens_details, billed at these same input/output rates — FuguAgent folds them
1601
- // into the token counts before pricing.
1602
- [SupportedAiModels[LLM_CONSTANTS.FUGU_ULTRA].modelApiName]: {
1603
- inputPrice: 5,
1604
- outputPrice: 30,
1605
- cacheHitPrice: 0.5,
1606
- extendedContextInputPrice: 10,
1607
- extendedContextOutputPrice: 45,
1608
- extendedContextCacheHitPrice: 1,
1609
- extendedContextThresholdTokens: 272e3
1610
- },
1617
+ // Sakana Fugu (console.sakana.ai/pricing, read 2026-09-20). Base `fugu` (retired 2026-08-04)
1618
+ // and `fugu-ultra` (removed 0.19.1) have no entries. Any "orchestration" tokens reported in
1619
+ // prompt_tokens_details / completion_tokens_details bill at these same rates — FuguAgent
1620
+ // folds them into the token counts before pricing.
1611
1621
  // fugu-max: flat rates, no context tiers.
1612
1622
  [SupportedAiModels[LLM_CONSTANTS.FUGU_MAX].modelApiName]: {
1613
1623
  inputPrice: 2,
@@ -1735,7 +1745,7 @@ var GLM_REASONING_EFFORTS = ["low", "high", "max"];
1735
1745
  var DEEPSEEK_REASONING_EFFORTS = ["low", "high", "max"];
1736
1746
  var FUGU_REASONING_EFFORTS = ["high", "xhigh", "max"];
1737
1747
  var META_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh", "max"];
1738
- var MISTRAL_REASONING_EFFORTS = ["minimal", "low", "medium", "high", "xhigh"];
1748
+ var MISTRAL_REASONING_EFFORTS = ["high"];
1739
1749
  var XAI_REASONING_EFFORTS = ["low", "medium", "high", "xhigh"];
1740
1750
  var KIMI_REASONING_EFFORTS = ["low", "high", "max"];
1741
1751
  function clampReasoningEffort(effort, allowed) {
@@ -2403,6 +2413,12 @@ var AbstractAgent = class {
2403
2413
  */
2404
2414
  reasoningEffort;
2405
2415
  thinkingBudgetTokens;
2416
+ /**
2417
+ * Wall-clock limit on one ask (DEFAULT_REQUEST_TIMEOUT_MS). Past it the ask throws
2418
+ * ModelTimeoutError; the provider request is abandoned, not cancelled. Raise it per
2419
+ * instance for calls that legitimately run long, like maxOutputTokens.
2420
+ */
2421
+ requestTimeoutMs = DEFAULT_REQUEST_TIMEOUT_MS;
2406
2422
  instruction;
2407
2423
  /**
2408
2424
  * The instruction split on CACHE_TIER_MARKER: [shared static tier, per-bot tier].
@@ -2437,7 +2453,7 @@ var AbstractAgent = class {
2437
2453
  if (beforeAskHook) await beforeAskHook(this);
2438
2454
  const startedAt = Date.now();
2439
2455
  try {
2440
- const [result, thinking, usage, signature] = await this.doAskWithZodSchema(zodSchema, messages);
2456
+ const [result, thinking, usage, signature] = await this.withTimeout(this.doAskWithZodSchema(zodSchema, messages));
2441
2457
  return [result, thinking, this.stampDuration(usage, startedAt), signature];
2442
2458
  } catch (error) {
2443
2459
  this.stampErrorDuration(error, startedAt);
@@ -2448,13 +2464,25 @@ var AbstractAgent = class {
2448
2464
  if (beforeAskHook) await beforeAskHook(this);
2449
2465
  const startedAt = Date.now();
2450
2466
  try {
2451
- const [content, thinking, usage, signature] = await this.doAskText(messages);
2467
+ const [content, thinking, usage, signature] = await this.withTimeout(this.doAskText(messages));
2452
2468
  return [content, thinking, this.stampDuration(usage, startedAt), signature];
2453
2469
  } catch (error) {
2454
2470
  this.stampErrorDuration(error, startedAt);
2455
2471
  throw error;
2456
2472
  }
2457
2473
  }
2474
+ /**
2475
+ * Races the provider call against requestTimeoutMs. A hung provider (accepts the request,
2476
+ * never answers) otherwise runs until the host kills the function with no error to show.
2477
+ */
2478
+ withTimeout(call) {
2479
+ const timeoutMs = this.requestTimeoutMs;
2480
+ let timer;
2481
+ const timeout = new Promise((_, reject) => {
2482
+ timer = setTimeout(() => reject(new ModelTimeoutError(this.model, timeoutMs)), timeoutMs);
2483
+ });
2484
+ return Promise.race([call, timeout]).finally(() => clearTimeout(timer));
2485
+ }
2458
2486
  stampDuration(usage, startedAt) {
2459
2487
  return usage ? { ...usage, durationMs: Date.now() - startedAt } : usage;
2460
2488
  }
@@ -5480,7 +5508,6 @@ var AgentFactory = class {
5480
5508
  case LLM_CONSTANTS.GLM_FLASH:
5481
5509
  return new GlmAgent(name, instruction, model.modelApiName, key, model.temperature, shouldEnableThinking);
5482
5510
  // Sakana Fugu models — always-on reasoning, no temperature (ignored by the model)
5483
- case LLM_CONSTANTS.FUGU_ULTRA:
5484
5511
  case LLM_CONSTANTS.FUGU_MAX:
5485
5512
  return new FuguAgent(name, instruction, model.modelApiName, key, shouldEnableThinking);
5486
5513
  // Qwen models — thinking-only (enable_thinking always sent)
@@ -5520,6 +5547,7 @@ var AgentFactory = class {
5520
5547
  DEEPSEEK_REASONING_EFFORTS,
5521
5548
  DEFAULT_LOGGING_CONFIG,
5522
5549
  DEFAULT_MAX_OUTPUT_TOKENS,
5550
+ DEFAULT_REQUEST_TIMEOUT_MS,
5523
5551
  DeepSeekV2Agent,
5524
5552
  FUGU_REASONING_EFFORTS,
5525
5553
  FuguAgent,
@@ -5549,6 +5577,7 @@ var AgentFactory = class {
5549
5577
  ModelQuotaExceededError,
5550
5578
  ModelRateLimitError,
5551
5579
  ModelRefusalError,
5580
+ ModelTimeoutError,
5552
5581
  ModelUnavailableError,
5553
5582
  OPENAI_REASONING_EFFORTS,
5554
5583
  OpenAiVoiceAgent,