@hiper2d/ai-agents 0.5.0 → 0.5.2

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
@@ -272,15 +272,29 @@ declare class ModelInvalidResponseError extends ModelError {
272
272
  constructor(modelType: string, detail: string, truncated?: boolean);
273
273
  }
274
274
  /**
275
- * The model declined to answer: Anthropic returns `stop_reason: "refusal"` with no content
276
- * blocks when its safety layer rejects the request as a whole. Not retryable as-is — the
277
- * same prompt will refuse again — the caller has to change the prompt or the model.
278
- * Observed 2026-08-30 on Claude Fable 5: a persona system prompt plus a narrated multi-turn
279
- * history that ends by asking the character what it does refuses, while either half alone
280
- * answers; Sonnet 5 and Opus 4.8 answer the same requests.
275
+ * The model declined to answer. Not retryable as-is — the same prompt will refuse again —
276
+ * the caller has to change the prompt or the model. `reason` is the provider's own label
277
+ * for the refusal, when it gives one:
278
+ *
279
+ * Anthropic `stop_reason: "refusal"` with no content blocks when its safety layer rejects
280
+ * the request as a whole. Observed 2026-08-30 on Claude Fable 5: a persona
281
+ * system prompt plus a narrated multi-turn history that ends by asking the
282
+ * character what it does refuses, while either half alone answers; Sonnet 5
283
+ * and Opus 4.8 answer the same requests. `reason` = "refusal".
284
+ * Google a 200 with no candidates and `promptFeedback.blockReason` set (the prompt
285
+ * itself was rejected: PROHIBITED_CONTENT, SAFETY, BLOCKLIST, JAILBREAK,
286
+ * MODEL_ARMOR, OTHER), or a candidate whose `finishReason` is a content
287
+ * block (SAFETY, PROHIBITED_CONTENT, BLOCKLIST, RECITATION, SPII,
288
+ * IMAGE_SAFETY, ...). Observed 2026-09-13 in production: an explicit
289
+ * sexual roleplay game was refused by Gemini 3.8 Flash and 3.1 Pro with
290
+ * blockReason PROHIBITED_CONTENT in ~200ms and zero output tokens, while
291
+ * Mistral, MiniMax and Muse answered the same prompt. PROHIBITED_CONTENT is
292
+ * Google's non-configurable filter — no safetySettings change lifts it.
293
+ * `reason` = the blockReason or finishReason string.
281
294
  */
282
295
  declare class ModelRefusalError extends ModelError {
283
- constructor(modelType: string, message?: string);
296
+ reason?: string;
297
+ constructor(modelType: string, message?: string, reason?: string);
284
298
  }
285
299
 
286
300
  /**
@@ -1022,6 +1036,13 @@ interface GoogleTtsResult {
1022
1036
  declare function buildGoogleTtsPrompt(text: string, voiceStyle?: string): string;
1023
1037
  /** Wraps raw 16-bit mono PCM in a WAV header. */
1024
1038
  declare function pcmToWav(pcmData: Uint8Array, sampleRate?: number): ArrayBuffer;
1039
+ /**
1040
+ * Why a 200 came back without audio. Gemini occasionally returns an empty candidate
1041
+ * (a transient `OTHER` / `RECITATION` finish, a safety block reported in
1042
+ * promptFeedback, or a text part instead of audio); naming it in the error is the
1043
+ * difference between a diagnosable log line and "no audio data".
1044
+ */
1045
+ declare function describeEmptyTtsResponse(response: any): string;
1025
1046
  /**
1026
1047
  * Core Gemini TTS call: text + API key in, WAV + token usage out.
1027
1048
  *
@@ -1669,4 +1690,4 @@ declare class MiniMaxAgent extends AbstractAgent {
1669
1690
  doAskText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1670
1691
  }
1671
1692
 
1672
- 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, KimiAgent, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, 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, ZodSchemaConverter, applySpend, buildGoogleTtsPrompt, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, 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, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toMetaEffort, toOpenAIEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
1693
+ 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, KimiAgent, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, 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, ZodSchemaConverter, applySpend, buildGoogleTtsPrompt, 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, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toMetaEffort, toOpenAIEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
package/dist/index.d.ts CHANGED
@@ -272,15 +272,29 @@ declare class ModelInvalidResponseError extends ModelError {
272
272
  constructor(modelType: string, detail: string, truncated?: boolean);
273
273
  }
274
274
  /**
275
- * The model declined to answer: Anthropic returns `stop_reason: "refusal"` with no content
276
- * blocks when its safety layer rejects the request as a whole. Not retryable as-is — the
277
- * same prompt will refuse again — the caller has to change the prompt or the model.
278
- * Observed 2026-08-30 on Claude Fable 5: a persona system prompt plus a narrated multi-turn
279
- * history that ends by asking the character what it does refuses, while either half alone
280
- * answers; Sonnet 5 and Opus 4.8 answer the same requests.
275
+ * The model declined to answer. Not retryable as-is — the same prompt will refuse again —
276
+ * the caller has to change the prompt or the model. `reason` is the provider's own label
277
+ * for the refusal, when it gives one:
278
+ *
279
+ * Anthropic `stop_reason: "refusal"` with no content blocks when its safety layer rejects
280
+ * the request as a whole. Observed 2026-08-30 on Claude Fable 5: a persona
281
+ * system prompt plus a narrated multi-turn history that ends by asking the
282
+ * character what it does refuses, while either half alone answers; Sonnet 5
283
+ * and Opus 4.8 answer the same requests. `reason` = "refusal".
284
+ * Google a 200 with no candidates and `promptFeedback.blockReason` set (the prompt
285
+ * itself was rejected: PROHIBITED_CONTENT, SAFETY, BLOCKLIST, JAILBREAK,
286
+ * MODEL_ARMOR, OTHER), or a candidate whose `finishReason` is a content
287
+ * block (SAFETY, PROHIBITED_CONTENT, BLOCKLIST, RECITATION, SPII,
288
+ * IMAGE_SAFETY, ...). Observed 2026-09-13 in production: an explicit
289
+ * sexual roleplay game was refused by Gemini 3.8 Flash and 3.1 Pro with
290
+ * blockReason PROHIBITED_CONTENT in ~200ms and zero output tokens, while
291
+ * Mistral, MiniMax and Muse answered the same prompt. PROHIBITED_CONTENT is
292
+ * Google's non-configurable filter — no safetySettings change lifts it.
293
+ * `reason` = the blockReason or finishReason string.
281
294
  */
282
295
  declare class ModelRefusalError extends ModelError {
283
- constructor(modelType: string, message?: string);
296
+ reason?: string;
297
+ constructor(modelType: string, message?: string, reason?: string);
284
298
  }
285
299
 
286
300
  /**
@@ -1022,6 +1036,13 @@ interface GoogleTtsResult {
1022
1036
  declare function buildGoogleTtsPrompt(text: string, voiceStyle?: string): string;
1023
1037
  /** Wraps raw 16-bit mono PCM in a WAV header. */
1024
1038
  declare function pcmToWav(pcmData: Uint8Array, sampleRate?: number): ArrayBuffer;
1039
+ /**
1040
+ * Why a 200 came back without audio. Gemini occasionally returns an empty candidate
1041
+ * (a transient `OTHER` / `RECITATION` finish, a safety block reported in
1042
+ * promptFeedback, or a text part instead of audio); naming it in the error is the
1043
+ * difference between a diagnosable log line and "no audio data".
1044
+ */
1045
+ declare function describeEmptyTtsResponse(response: any): string;
1025
1046
  /**
1026
1047
  * Core Gemini TTS call: text + API key in, WAV + token usage out.
1027
1048
  *
@@ -1669,4 +1690,4 @@ declare class MiniMaxAgent extends AbstractAgent {
1669
1690
  doAskText(messages: AIMessage[]): Promise<[string, string, TokenUsage$1?, string?]>;
1670
1691
  }
1671
1692
 
1672
- 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, KimiAgent, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, 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, ZodSchemaConverter, applySpend, buildGoogleTtsPrompt, calculateAnthropicCost, calculateCost, calculateDeepSeekCost, calculateGeminiSttCost, calculateGeminiTtsCost, calculateGoogleCost, calculateGrokCost, calculateKimiCost, calculateMetaCost, calculateMistralCost, calculateModelCost, calculateOpenAICost, calculateOpenAiSttCost, calculateOpenAiTtsCost, clampReasoningEffort, cleanResponse, createCatalog, createVoiceAgent, 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, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toMetaEffort, toOpenAIEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
1693
+ 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, KimiAgent, type KimiTokenUsage, type LLMModel, LLM_CONSTANTS, type LlmLogger, type LoggingConfig, MESSAGE_ROLE, META_REASONING_EFFORTS, MODEL_PRICING, MetaAgent, type MetaReasoningEffort, type MetaTokenUsage, MiniMaxAgent, MistralAgent, 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, ZodSchemaConverter, applySpend, buildGoogleTtsPrompt, 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, isWeekendAt, ledgerSpend, logger, mergeThinking, modelHasTag, modelIsFast, needsPromptBasedSchema, parseAndValidateLlmJson, pcmToWav, periodEnd, periodKey, safeValidateResponse, setBeforeAskHook, setLlmLogger, stableHashHex, stripInlineThinking, supportsNativeJsonSchema, toAnthropicEffort, toDeepSeekEffort, toFuguEffort, toGeminiEffort, toGlmEffort, toMetaEffort, toOpenAIEffort, transcribeWithGemini, transcribeWithOpenAi, validateResponse };
package/dist/index.js CHANGED
@@ -103,6 +103,7 @@ __export(src_exports, {
103
103
  cleanResponse: () => cleanResponse,
104
104
  createCatalog: () => createCatalog,
105
105
  createVoiceAgent: () => createVoiceAgent,
106
+ describeEmptyTtsResponse: () => describeEmptyTtsResponse,
106
107
  evaluateBudget: () => evaluateBudget,
107
108
  extractAnthropicTokenUsage: () => extractAnthropicTokenUsage,
108
109
  extractAnthropicTokenUsageFromResponse: () => extractTokenUsageFromResponse6,
@@ -882,9 +883,11 @@ var ModelInvalidResponseError = class extends ModelError {
882
883
  }
883
884
  };
884
885
  var ModelRefusalError = class extends ModelError {
885
- constructor(modelType, message = `${modelType} refused to answer (stop_reason: refusal)`) {
886
+ reason;
887
+ constructor(modelType, message = `${modelType} refused to answer (stop_reason: refusal)`, reason) {
886
888
  super(message, modelType);
887
889
  this.name = "ModelRefusalError";
890
+ this.reason = reason;
888
891
  }
889
892
  };
890
893
 
@@ -1998,6 +2001,21 @@ function pcmToWav(pcmData, sampleRate = SAMPLE_RATE) {
1998
2001
  new Uint8Array(buffer, headerSize).set(pcmData);
1999
2002
  return buffer;
2000
2003
  }
2004
+ function describeEmptyTtsResponse(response) {
2005
+ const candidate = response?.candidates?.[0];
2006
+ const parts = candidate?.content?.parts ?? [];
2007
+ const bits = [];
2008
+ bits.push(`finishReason=${candidate?.finishReason ?? "none"}`);
2009
+ if (!response?.candidates?.length) bits.push("no candidates");
2010
+ const block = response?.promptFeedback?.blockReason;
2011
+ if (block) bits.push(`blockReason=${block}`);
2012
+ const text = parts.map((p) => typeof p?.text === "string" ? p.text : "").join(" ").trim();
2013
+ if (text) bits.push(`text="${text.slice(0, 120)}"`);
2014
+ const otherMimes = parts.map((p) => p?.inlineData?.mimeType).filter(Boolean);
2015
+ if (otherMimes.length) bits.push(`inlineData=${otherMimes.join(",")}`);
2016
+ if (!parts.length) bits.push("no parts");
2017
+ return bits.join(", ");
2018
+ }
2001
2019
  async function generateGoogleTtsAudio(text, apiKey, options) {
2002
2020
  const client = new import_genai.GoogleGenAI({ apiKey });
2003
2021
  const response = await client.models.generateContent({
@@ -2008,10 +2026,11 @@ async function generateGoogleTtsAudio(text, apiKey, options) {
2008
2026
  speechConfig: { voiceConfig: { prebuiltVoiceConfig: { voiceName: options.voiceName } } }
2009
2027
  }
2010
2028
  });
2011
- const parts = response.candidates?.[0]?.content?.parts ?? [];
2029
+ const candidate = response.candidates?.[0];
2030
+ const parts = candidate?.content?.parts ?? [];
2012
2031
  const audioPart = parts.find((part) => part.inlineData?.mimeType?.startsWith("audio/"));
2013
2032
  if (!audioPart?.inlineData?.data) {
2014
- throw new Error("No audio data in Google TTS response");
2033
+ throw new Error(`No audio data in Google TTS response (${describeEmptyTtsResponse(response)})`);
2015
2034
  }
2016
2035
  const pcmData = new Uint8Array(Buffer.from(audioPart.inlineData.data, "base64"));
2017
2036
  const usageMetadata = response.usageMetadata ?? {};
@@ -2806,7 +2825,7 @@ ${schemaDescription}`;
2806
2825
  throw new Error(this.errorMessages.apiError(apiError));
2807
2826
  }
2808
2827
  if (response.stop_reason === "refusal") {
2809
- throw new ModelRefusalError(this.model);
2828
+ throw new ModelRefusalError(this.model, void 0, "refusal");
2810
2829
  }
2811
2830
  if (!("content" in response) || !Array.isArray(response.content) || response.content.length === 0) {
2812
2831
  throw new Error(this.errorMessages.emptyResponse);
@@ -2900,7 +2919,7 @@ ${schemaDescription}`;
2900
2919
  throw new Error(this.errorMessages.apiError(apiError));
2901
2920
  }
2902
2921
  if (response.stop_reason === "refusal") {
2903
- throw new ModelRefusalError(this.model);
2922
+ throw new ModelRefusalError(this.model, void 0, "refusal");
2904
2923
  }
2905
2924
  if (!("content" in response) || !Array.isArray(response.content) || response.content.length === 0) {
2906
2925
  throw new Error(this.errorMessages.emptyResponse);
@@ -2956,6 +2975,45 @@ ${schemaDescription}`;
2956
2975
 
2957
2976
  // src/agents/google-agent.ts
2958
2977
  var import_genai3 = require("@google/genai");
2978
+ var GEMINI_REFUSAL_FINISH_REASONS = /* @__PURE__ */ new Set([
2979
+ "SAFETY",
2980
+ "RECITATION",
2981
+ "BLOCKLIST",
2982
+ "PROHIBITED_CONTENT",
2983
+ "SPII",
2984
+ "IMAGE_SAFETY",
2985
+ "IMAGE_PROHIBITED_CONTENT",
2986
+ "IMAGE_RECITATION"
2987
+ ]);
2988
+ function throwForEmptyGeminiResponse(model, response, fallback) {
2989
+ const blockReason = response?.promptFeedback?.blockReason;
2990
+ const candidate = response?.candidates?.[0];
2991
+ const finishReason = candidate?.finishReason;
2992
+ const finishMessage = candidate?.finishMessage;
2993
+ const ratings = (candidate?.safetyRatings ?? response?.promptFeedback?.safetyRatings ?? []).filter((r) => r?.blocked || r?.probability && r.probability !== "NEGLIGIBLE");
2994
+ const ratingText = ratings.length ? `; safetyRatings: ${ratings.map((r) => `${r.category}=${r.probability ?? (r.blocked ? "blocked" : "?")}`).join(", ")}` : "";
2995
+ if (blockReason) {
2996
+ throw new ModelRefusalError(
2997
+ model,
2998
+ `${model} refused the prompt (blockReason: ${blockReason}${finishMessage ? `, ${finishMessage}` : ""}${ratingText})`,
2999
+ blockReason
3000
+ );
3001
+ }
3002
+ if (finishReason && GEMINI_REFUSAL_FINISH_REASONS.has(finishReason)) {
3003
+ throw new ModelRefusalError(
3004
+ model,
3005
+ `${model} refused to answer (finishReason: ${finishReason}${finishMessage ? `, ${finishMessage}` : ""}${ratingText})`,
3006
+ finishReason
3007
+ );
3008
+ }
3009
+ if (finishReason === "MAX_TOKENS") {
3010
+ throw new ModelInvalidResponseError(model, "empty response, finishReason MAX_TOKENS (thinking consumed the whole output budget)", true);
3011
+ }
3012
+ const bits = [`finishReason=${finishReason ?? "none"}`];
3013
+ if (!response?.candidates?.length) bits.push("no candidates");
3014
+ if (finishMessage) bits.push(`finishMessage="${finishMessage}"`);
3015
+ throw new Error(`${fallback} (${bits.join(", ")})`);
3016
+ }
2959
3017
  var GoogleAgent = class extends AbstractAgent {
2960
3018
  client;
2961
3019
  defaultConfig = {
@@ -2967,7 +3025,7 @@ var GoogleAgent = class extends AbstractAgent {
2967
3025
  };
2968
3026
  // Error message templates
2969
3027
  errorMessages = {
2970
- emptyResponse: "Empty response from Google API - check logs for detailed response info",
3028
+ emptyResponse: "Empty response from Google API",
2971
3029
  invalidFormat: "Invalid response format from Google API",
2972
3030
  apiError: (error) => `Failed to get response from Google API: ${error instanceof Error ? error.message : String(error)}`,
2973
3031
  unsupportedRole: (role) => `Unsupported role type: ${role}`
@@ -3139,7 +3197,7 @@ var GoogleAgent = class extends AbstractAgent {
3139
3197
  }
3140
3198
  this.logger(`Zod schema response received - hasText: ${!!response.text}, textLength: ${response.text ? response.text.length : 0}`);
3141
3199
  if (!response.text) {
3142
- throw new Error(this.errorMessages.emptyResponse);
3200
+ throwForEmptyGeminiResponse(this.model, response, this.errorMessages.emptyResponse);
3143
3201
  }
3144
3202
  const parsedData = parseAndValidateLlmJson(response.text, zodSchema, (m) => this.logger(m));
3145
3203
  if (parsedData) {
@@ -3227,7 +3285,7 @@ var GoogleAgent = class extends AbstractAgent {
3227
3285
  }
3228
3286
  this.logger(`Plain text response received - hasText: ${!!response.text}, textLength: ${response.text ? response.text.length : 0}`);
3229
3287
  if (!response.text) {
3230
- throw new Error(this.errorMessages.emptyResponse);
3288
+ throwForEmptyGeminiResponse(this.model, response, this.errorMessages.emptyResponse);
3231
3289
  }
3232
3290
  this.logReply(response.text, thinkingContent || void 0, tokenUsage);
3233
3291
  return [response.text, thinkingContent, tokenUsage, googleThoughtSignature || void 0];
@@ -5262,6 +5320,7 @@ var AgentFactory = class {
5262
5320
  cleanResponse,
5263
5321
  createCatalog,
5264
5322
  createVoiceAgent,
5323
+ describeEmptyTtsResponse,
5265
5324
  evaluateBudget,
5266
5325
  extractAnthropicTokenUsage,
5267
5326
  extractAnthropicTokenUsageFromResponse,