@happyvertical/ai 0.102.1 → 0.102.3

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.
Files changed (64) hide show
  1. package/AGENT.md +1 -1
  2. package/README.md +123 -2
  3. package/dist/chunks/{anthropic-6ZDF32jo.js → anthropic-CxOrttgj.js} +3 -4
  4. package/dist/chunks/{anthropic-6ZDF32jo.js.map → anthropic-CxOrttgj.js.map} +1 -1
  5. package/dist/chunks/{bedrock-BQi3Z9jR.js → bedrock-B0cNEXFa.js} +3 -4
  6. package/dist/chunks/{bedrock-BQi3Z9jR.js.map → bedrock-B0cNEXFa.js.map} +1 -1
  7. package/dist/chunks/{bifrost-DsI2I4ka.js → bifrost-CyO3-hBv.js} +4 -4
  8. package/dist/chunks/{bifrost-DsI2I4ka.js.map → bifrost-CyO3-hBv.js.map} +1 -1
  9. package/dist/chunks/{byteplus-modelark-Dq8AgCQD.js → byteplus-modelark-DZ0YL2vl.js} +3 -4
  10. package/dist/chunks/{byteplus-modelark-Dq8AgCQD.js.map → byteplus-modelark-DZ0YL2vl.js.map} +1 -1
  11. package/dist/chunks/{claude-cli-DIFxvG3c.js → claude-cli-CtBp-Uk-.js} +3 -4
  12. package/dist/chunks/{claude-cli-DIFxvG3c.js.map → claude-cli-CtBp-Uk-.js.map} +1 -1
  13. package/dist/chunks/{continuation-D0NisZA1.js → continuation-7o7400bp.js} +3 -3
  14. package/dist/chunks/continuation-7o7400bp.js.map +1 -0
  15. package/dist/chunks/{gateway-audio-models-Dn7Wrc6P.js → gateway-audio-models-BSZGgjd8.js} +2 -2
  16. package/dist/chunks/{gateway-audio-models-Dn7Wrc6P.js.map → gateway-audio-models-BSZGgjd8.js.map} +1 -1
  17. package/dist/chunks/{gemini-BLFwWN90.js → gemini-DUk4ssth.js} +3 -4
  18. package/dist/chunks/{gemini-BLFwWN90.js.map → gemini-DUk4ssth.js.map} +1 -1
  19. package/dist/chunks/{huggingface-BuRwlABZ.js → huggingface-C41BZOoI.js} +3 -4
  20. package/dist/chunks/{huggingface-BuRwlABZ.js.map → huggingface-C41BZOoI.js.map} +1 -1
  21. package/dist/chunks/{litellm-CpfCT6jN.js → litellm-BLR5cs8B.js} +4 -4
  22. package/dist/chunks/{litellm-CpfCT6jN.js.map → litellm-BLR5cs8B.js.map} +1 -1
  23. package/dist/chunks/{ollama-CnrskTUg.js → ollama--y88p8Bz.js} +4 -5
  24. package/dist/chunks/{ollama-CnrskTUg.js.map → ollama--y88p8Bz.js.map} +1 -1
  25. package/dist/chunks/{openai-compat-video-CJIDdkUO.js → openai-compat-video-erarPEz-.js} +3 -4
  26. package/dist/chunks/{openai-compat-video-CJIDdkUO.js.map → openai-compat-video-erarPEz-.js.map} +1 -1
  27. package/dist/chunks/{qwen-tts-PzEkWcEb.js → qwen-tts-C9w7teY6.js} +2 -2
  28. package/dist/chunks/{qwen-tts-PzEkWcEb.js.map → qwen-tts-C9w7teY6.js.map} +1 -1
  29. package/dist/chunks/{rate-limit-BzWfHA0e.js → rate-limit-Bln_w0rH.js} +3 -280
  30. package/dist/chunks/rate-limit-Bln_w0rH.js.map +1 -0
  31. package/dist/chunks/rolldown-runtime-D7D4PA-g.js +13 -0
  32. package/dist/chunks/{seevio-D2y5Io7C.js → seevio-CosohVa0.js} +3 -4
  33. package/dist/chunks/{seevio-D2y5Io7C.js.map → seevio-CosohVa0.js.map} +1 -1
  34. package/dist/chunks/{src-CLT6r1W0.js → src-DDEz_uOe.js} +25 -30
  35. package/dist/chunks/{src-CLT6r1W0.js.map → src-DDEz_uOe.js.map} +1 -1
  36. package/dist/chunks/{typesafe-CVUqQ8N1.js → typesafe-BNM-QAJ2.js} +3 -4
  37. package/dist/chunks/{typesafe-CVUqQ8N1.js.map → typesafe-BNM-QAJ2.js.map} +1 -1
  38. package/dist/chunks/usage-BaQKo8bc.js +484 -0
  39. package/dist/chunks/usage-BaQKo8bc.js.map +1 -0
  40. package/dist/chunks/webllm-CWgY5nnP.js +584 -0
  41. package/dist/chunks/webllm-CWgY5nnP.js.map +1 -0
  42. package/dist/index.js +3 -4
  43. package/dist/local.d.ts +33 -0
  44. package/dist/local.d.ts.map +1 -0
  45. package/dist/local.js +3 -0
  46. package/dist/node.js +4 -5
  47. package/dist/node.js.map +1 -1
  48. package/dist/shared/continuation.d.ts +1 -1
  49. package/dist/shared/continuation.d.ts.map +1 -1
  50. package/dist/shared/factory.d.ts.map +1 -1
  51. package/dist/shared/providers/webllm-shim.d.ts +9 -0
  52. package/dist/shared/providers/webllm-shim.d.ts.map +1 -0
  53. package/dist/shared/providers/webllm.d.ts +115 -0
  54. package/dist/shared/providers/webllm.d.ts.map +1 -0
  55. package/dist/shared/types.d.ts +73 -2
  56. package/dist/shared/types.d.ts.map +1 -1
  57. package/metadata.json +1 -0
  58. package/package.json +15 -2
  59. package/dist/chunks/continuation-D0NisZA1.js.map +0 -1
  60. package/dist/chunks/rate-limit-BzWfHA0e.js.map +0 -1
  61. package/dist/chunks/types-DB5W6_F-.js +0 -153
  62. package/dist/chunks/types-DB5W6_F-.js.map +0 -1
  63. package/dist/chunks/usage-C1Y1Nlg4.js +0 -35
  64. package/dist/chunks/usage-C1Y1Nlg4.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"typesafe-CVUqQ8N1.js","names":[],"sources":["../../src/shared/providers/typesafe.ts"],"sourcesContent":["/**\n * TypeSafe System One typed-decision provider.\n *\n * The public SDK contract deliberately calls TypeSafe's `noul` primitive a\n * `predicate`; vendor terminology stays confined to this wire translation.\n */\n\nimport { ValidationError } from '@happyvertical/utils';\n\nimport { rateLimitErrorFrom } from '../rate-limit';\nimport { normalizeBaseAIOptions, prepareRequestControls } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n ChoiceDecisionQuestion,\n CompletionOptions,\n DecisionAnswer,\n DecisionOptions,\n DecisionQuestion,\n DecisionRequest,\n DecisionResult,\n DecisionValue,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n ScoreDecisionQuestion,\n TTSOptions,\n TTSResponse,\n TypeSafeOptions,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError } from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'typesafe';\nconst DEFAULT_BASE_URL = 'https://api.typesafe.ai/v1';\nconst DEFAULT_MODEL = 'jev-latest';\nconst STRICT_DISTRIBUTION_EPSILON = 1e-6;\nconst HUNDREDTH_GRID_EPSILON = 1e-8;\nconst ROUNDED_DISTRIBUTION_MAX_ERROR = 0.01;\n\ntype WireQuestion =\n | {\n type: 'noul';\n instructions: DecisionValue;\n criteria?: Record<string, DecisionValue>;\n }\n | {\n type: 'choice';\n instructions: DecisionValue;\n criteria: Record<string, DecisionValue | null>;\n }\n | { type: 'score'; instructions: DecisionValue; criteria: DecisionValue[] };\n\ninterface WireResponse {\n model?: unknown;\n answers?: unknown;\n usage?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new AIError(\n `TypeSafe response ${field} must be finite`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return value;\n}\n\nfunction probability(value: unknown, field: string): number {\n const result = finite(value, field);\n if (result < 0 || result > 1) {\n throw new AIError(\n `TypeSafe response ${field} must be between 0 and 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction tokenCount(value: unknown, field: string): number {\n const result = finite(value, field);\n if (!Number.isSafeInteger(result) || result < 0) {\n throw new AIError(\n `TypeSafe response ${field} must be a non-negative integer`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction sameDecisionValue(left: DecisionValue, right: unknown): boolean {\n if (left === right) return true;\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => sameDecisionValue(value, right[index]))\n );\n }\n if (isRecord(left)) {\n return (\n isRecord(right) &&\n Object.keys(left).length === Object.keys(right).length &&\n Object.entries(left).every(\n ([key, value]) => key in right && sameDecisionValue(value, right[key]),\n )\n );\n }\n return false;\n}\n\nfunction validateValue(\n value: unknown,\n field: string,\n): asserts value is DecisionValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean')\n return;\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n throw new ValidationError(`${field} must contain finite numbers`, {\n provider: PROVIDER,\n });\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n validateValue(item, `${field}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n Object.entries(value).forEach(([key, item]) => {\n validateValue(item, `${field}.${key}`);\n });\n return;\n }\n throw new ValidationError(`${field} must be JSON-compatible`, {\n provider: PROVIDER,\n });\n}\n\nfunction validateRequest(request: DecisionRequest): void {\n validateValue(request.state, 'state');\n const entries = Object.entries(request.questions || {});\n if (entries.length === 0)\n throw new ValidationError('questions must not be empty', {\n provider: PROVIDER,\n });\n for (const [id, question] of entries) {\n if (!id.trim())\n throw new ValidationError('question IDs must not be empty', {\n provider: PROVIDER,\n });\n validateValue(question.instructions, `questions.${id}.instructions`);\n if (question.type === 'predicate') {\n if (question.criteria) {\n for (const [key, value] of Object.entries(question.criteria))\n validateValue(value, `questions.${id}.criteria.${key}`);\n }\n } else if (question.type === 'choice') {\n const options = Object.keys(question.criteria || {});\n if (options.length === 0 || options.length > 255)\n throw new ValidationError(\n `questions.${id}.criteria must contain 1 to 255 options`,\n { provider: PROVIDER },\n );\n for (const [key, value] of Object.entries(question.criteria))\n if (value !== null)\n validateValue(value, `questions.${id}.criteria.${key}`);\n } else if (question.type === 'score') {\n if (question.criteria.length < 2 || question.criteria.length > 10)\n throw new ValidationError(\n `questions.${id}.criteria must contain 2 to 10 ordered levels`,\n { provider: PROVIDER },\n );\n question.criteria.forEach((value, index) => {\n validateValue(value, `questions.${id}.criteria[${index}]`);\n });\n } else {\n throw new ValidationError(`questions.${id}.type is unsupported`, {\n provider: PROVIDER,\n });\n }\n }\n}\n\nfunction wireQuestion(question: DecisionQuestion): WireQuestion {\n if (question.type === 'predicate')\n return {\n type: 'noul',\n instructions: question.instructions,\n ...(question.criteria ? { criteria: question.criteria } : {}),\n };\n return question;\n}\n\nfunction distribution(\n value: unknown,\n expected: string[],\n field: string,\n): Record<string, number> {\n if (\n !isRecord(value) ||\n Object.keys(value).length !== expected.length ||\n expected.some((key) => !(key in value))\n ) {\n throw new AIError(\n `TypeSafe response ${field} must cover exactly the requested values`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const result = Object.fromEntries(\n expected.map((key) => [key, probability(value[key], `${field}.${key}`)]),\n );\n const sum = Object.values(result).reduce((total, item) => total + item, 0);\n if (Math.abs(sum - 1) <= STRICT_DISTRIBUTION_EPSILON) return result;\n\n // TypeSafe documents normalized distributions, but observed high-cardinality\n // wire responses use hundredth rounding. Accept only that measured form and\n // cap its total rounding error at one percentage point before normalizing.\n const maximumRoundingError = Math.min(\n expected.length * 0.005,\n ROUNDED_DISTRIBUTION_MAX_ERROR,\n );\n const isHundredthRounded = Object.values(result).every(\n (item) =>\n Math.abs(item * 100 - Math.round(item * 100)) <= HUNDREDTH_GRID_EPSILON,\n );\n if (\n sum <= 0 ||\n !isHundredthRounded ||\n Math.abs(sum - 1) > maximumRoundingError + HUNDREDTH_GRID_EPSILON\n )\n throw new AIError(\n `TypeSafe response ${field} must sum to 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return Object.fromEntries(\n Object.entries(result).map(([key, item]) => [key, item / sum]),\n );\n}\n\nfunction answer(\n question: DecisionQuestion,\n raw: unknown,\n id: string,\n): DecisionAnswer {\n if (!isRecord(raw))\n throw new AIError(\n `TypeSafe response answers.${id} must be an object`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'predicate') {\n if (raw.type !== 'noul')\n throw new AIError(\n `TypeSafe response answers.${id} type does not match predicate`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'predicate',\n probability: probability(raw.noul, `answers.${id}.noul`),\n };\n }\n if (raw.type !== question.type)\n throw new AIError(\n `TypeSafe response answers.${id} type does not match request`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'choice') {\n const choices = Object.keys(question.criteria);\n if (typeof raw.choice !== 'string' || !choices.includes(raw.choice))\n throw new AIError(\n `TypeSafe response answers.${id}.choice is not a requested option`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'choice',\n choice: raw.choice,\n probabilities: distribution(\n raw.probabilities,\n choices,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n };\n }\n const scoreQuestion = question as ScoreDecisionQuestion;\n const levels = scoreQuestion.criteria;\n const levelKeys = levels.map((_, index) => String(index));\n const score = finite(raw.score, `answers.${id}.score`);\n if (score < 0 || score > levels.length - 1)\n throw new AIError(\n `TypeSafe response answers.${id}.score is outside the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const legend = raw.legend;\n if (\n !isRecord(legend) ||\n levelKeys.some(\n (key, index) => !sameDecisionValue(levels[index], legend[key]),\n )\n )\n throw new AIError(\n `TypeSafe response answers.${id}.legend does not match the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'score',\n score,\n probabilities: distribution(\n raw.probabilities,\n levelKeys,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n levels,\n };\n}\n\n/** A decision-only adapter for TypeSafe's System One endpoint. */\nexport class TypeSafeProvider implements AIInterface {\n private readonly options: TypeSafeOptions;\n\n constructor(options: TypeSafeOptions) {\n this.options = normalizeBaseAIOptions({\n ...options,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n });\n }\n\n async decide(\n request: DecisionRequest,\n options: DecisionOptions = {},\n ): Promise<DecisionResult> {\n validateRequest(request);\n const apiKey = this.options.apiKey;\n if (!apiKey) throw new AuthenticationError(PROVIDER);\n const controls = prepareRequestControls(this.options, options);\n const startedAt = Date.now();\n const model = options.model || this.options.defaultModel || DEFAULT_MODEL;\n try {\n const response = await fetch(`${this.options.baseUrl}/systemone`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...this.options.headers,\n },\n body: JSON.stringify({\n state: request.state,\n model,\n questions: Object.fromEntries(\n Object.entries(request.questions).map(([id, question]) => [\n id,\n wireQuestion(question),\n ]),\n ),\n }),\n signal: controls.signal,\n });\n if (!response.ok) {\n if (response.status === 401) throw new AuthenticationError(PROVIDER);\n const text = await response.text();\n if (response.status === 429 || response.status === 529)\n throw rateLimitErrorFrom(\n PROVIDER,\n { headers: response.headers, message: text },\n { model },\n );\n throw new AIError(\n `TypeSafe request failed (${response.status}): ${text.slice(0, 500)}`,\n 'API_ERROR',\n PROVIDER,\n model,\n response.status >= 500,\n );\n }\n let body: WireResponse;\n try {\n body = (await response.json()) as WireResponse;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AIError(\n 'TypeSafe response contained invalid JSON',\n 'INVALID_RESPONSE',\n PROVIDER,\n model,\n );\n }\n throw error;\n }\n if (!body || typeof body.model !== 'string' || !body.model)\n throw new AIError(\n 'TypeSafe response model is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (!isRecord(body.answers))\n throw new AIError(\n 'TypeSafe response answers is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const responseAnswers = body.answers;\n const ids = Object.keys(request.questions);\n if (\n Object.keys(responseAnswers).length !== ids.length ||\n ids.some((id) => !(id in responseAnswers))\n )\n throw new AIError(\n 'TypeSafe response answers must match requested question IDs',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const answers = Object.fromEntries(\n ids.map((id) => [\n id,\n answer(request.questions[id], responseAnswers[id], id),\n ]),\n );\n let usage:\n | {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n }\n | undefined;\n if (body.usage !== undefined) {\n if (\n !isRecord(body.usage) ||\n !('input_tokens' in body.usage) ||\n !('output_tokens' in body.usage)\n ) {\n throw new AIError(\n 'TypeSafe response usage must include input_tokens and output_tokens',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const input = tokenCount(body.usage.input_tokens, 'usage.input_tokens');\n const output = tokenCount(\n body.usage.output_tokens,\n 'usage.output_tokens',\n );\n usage = {\n promptTokens: input,\n completionTokens: output,\n totalTokens: input + output,\n };\n }\n emitUsage(\n this.options,\n PROVIDER,\n 'decide',\n body.model,\n usage,\n startedAt,\n options.usageTags,\n );\n return {\n model: body.model,\n ...(usage ? { usage } : {}),\n provenance: { provider: PROVIDER, model: body.model },\n answers,\n };\n } catch (error) {\n if (controls.didTimeout())\n throw new AIError(\n `TypeSafe request timed out after ${controls.timeout}ms`,\n 'REQUEST_TIMEOUT',\n PROVIDER,\n model,\n true,\n );\n if (controls.signal.aborted && !(error instanceof AIError))\n throw new AIError(\n 'TypeSafe request was aborted',\n 'REQUEST_ABORTED',\n PROVIDER,\n model,\n );\n if (!(error instanceof AIError)) {\n throw new AIError(\n `Network error calling TypeSafe System One: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'NETWORK_ERROR',\n PROVIDER,\n model,\n true,\n );\n }\n throw error;\n } finally {\n controls.cleanup();\n }\n }\n\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: this.options.defaultModel || DEFAULT_MODEL,\n name: 'TypeSafe Jev',\n description: 'TypeSafe System One typed decisions',\n contextLength: 0,\n capabilities: ['decisions'],\n supportsFunctions: false,\n supportsVision: false,\n },\n ];\n }\n async getCapabilities(): Promise<AICapabilities> {\n return {\n decisions: true,\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: ['decide'],\n };\n }\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n }\n async chat(_a: AIMessage[], _b?: ChatOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async complete(_a: string, _b?: CompletionOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async message(_a: string, _b?: MessageOptions): Promise<string> {\n return this.unsupported();\n }\n async embed(\n _a: string | string[],\n _b?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async embedImage(\n _a: string | Buffer,\n _b?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async describeImage(\n _a: string | Buffer,\n _b?: string,\n _c?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n async generateImage(\n _a: string,\n _b?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n stream(_a: AIMessage[], _b?: ChatOptions): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async countTokens(_a: string): Promise<number> {\n return this.unsupported();\n }\n async submitVideoGenerationJob(\n _a: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return this.unsupported();\n }\n async getVideoGenerationJob(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.unsupported();\n }\n async fetchVideoGenerationResult(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return this.unsupported();\n }\n async cancelVideoGenerationJob(_a: VideoGenerationJob): Promise<void> {\n return this.unsupported();\n }\n async validateVideoGenerationAccess(): Promise<boolean> {\n return this.unsupported();\n }\n async synthesizeSpeech(_a: string, _b?: TTSOptions): Promise<TTSResponse> {\n return this.unsupported();\n }\n streamSpeech(_a: string, _b?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async cloneVoice(_a: VoiceCloneOptions): Promise<Voice> {\n return this.unsupported();\n }\n async designVoice(_a: VoiceDesignOptions): Promise<Voice> {\n return this.unsupported();\n }\n async getVoices(_a?: VoiceListOptions): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"typesafe-BNM-QAJ2.js","names":[],"sources":["../../src/shared/providers/typesafe.ts"],"sourcesContent":["/**\n * TypeSafe System One typed-decision provider.\n *\n * The public SDK contract deliberately calls TypeSafe's `noul` primitive a\n * `predicate`; vendor terminology stays confined to this wire translation.\n */\n\nimport { ValidationError } from '@happyvertical/utils';\n\nimport { rateLimitErrorFrom } from '../rate-limit';\nimport { normalizeBaseAIOptions, prepareRequestControls } from '../safety';\nimport type {\n AICapabilities,\n AIInterface,\n AIMessage,\n AIModel,\n AIResponse,\n ChatOptions,\n ChoiceDecisionQuestion,\n CompletionOptions,\n DecisionAnswer,\n DecisionOptions,\n DecisionQuestion,\n DecisionRequest,\n DecisionResult,\n DecisionValue,\n EmbeddingOptions,\n EmbeddingResponse,\n ImageDescriptionOptions,\n ImageEmbeddingOptions,\n ImageGenerationOptions,\n ImageGenerationResponse,\n MessageOptions,\n ScoreDecisionQuestion,\n TTSOptions,\n TTSResponse,\n TypeSafeOptions,\n VideoGenerationJob,\n VideoGenerationOptions,\n VideoGenerationResult,\n VideoGenerationStatusResult,\n Voice,\n VoiceCloneOptions,\n VoiceDesignOptions,\n VoiceListOptions,\n} from '../types';\nimport { AIError, AuthenticationError } from '../types';\nimport { emitUsage } from './usage';\n\nconst PROVIDER = 'typesafe';\nconst DEFAULT_BASE_URL = 'https://api.typesafe.ai/v1';\nconst DEFAULT_MODEL = 'jev-latest';\nconst STRICT_DISTRIBUTION_EPSILON = 1e-6;\nconst HUNDREDTH_GRID_EPSILON = 1e-8;\nconst ROUNDED_DISTRIBUTION_MAX_ERROR = 0.01;\n\ntype WireQuestion =\n | {\n type: 'noul';\n instructions: DecisionValue;\n criteria?: Record<string, DecisionValue>;\n }\n | {\n type: 'choice';\n instructions: DecisionValue;\n criteria: Record<string, DecisionValue | null>;\n }\n | { type: 'score'; instructions: DecisionValue; criteria: DecisionValue[] };\n\ninterface WireResponse {\n model?: unknown;\n answers?: unknown;\n usage?: unknown;\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return Boolean(value) && typeof value === 'object' && !Array.isArray(value);\n}\n\nfunction finite(value: unknown, field: string): number {\n if (typeof value !== 'number' || !Number.isFinite(value)) {\n throw new AIError(\n `TypeSafe response ${field} must be finite`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return value;\n}\n\nfunction probability(value: unknown, field: string): number {\n const result = finite(value, field);\n if (result < 0 || result > 1) {\n throw new AIError(\n `TypeSafe response ${field} must be between 0 and 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction tokenCount(value: unknown, field: string): number {\n const result = finite(value, field);\n if (!Number.isSafeInteger(result) || result < 0) {\n throw new AIError(\n `TypeSafe response ${field} must be a non-negative integer`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n return result;\n}\n\nfunction sameDecisionValue(left: DecisionValue, right: unknown): boolean {\n if (left === right) return true;\n if (Array.isArray(left)) {\n return (\n Array.isArray(right) &&\n left.length === right.length &&\n left.every((value, index) => sameDecisionValue(value, right[index]))\n );\n }\n if (isRecord(left)) {\n return (\n isRecord(right) &&\n Object.keys(left).length === Object.keys(right).length &&\n Object.entries(left).every(\n ([key, value]) => key in right && sameDecisionValue(value, right[key]),\n )\n );\n }\n return false;\n}\n\nfunction validateValue(\n value: unknown,\n field: string,\n): asserts value is DecisionValue {\n if (value === null || typeof value === 'string' || typeof value === 'boolean')\n return;\n if (typeof value === 'number') {\n if (!Number.isFinite(value))\n throw new ValidationError(`${field} must contain finite numbers`, {\n provider: PROVIDER,\n });\n return;\n }\n if (Array.isArray(value)) {\n value.forEach((item, index) => {\n validateValue(item, `${field}[${index}]`);\n });\n return;\n }\n if (isRecord(value)) {\n Object.entries(value).forEach(([key, item]) => {\n validateValue(item, `${field}.${key}`);\n });\n return;\n }\n throw new ValidationError(`${field} must be JSON-compatible`, {\n provider: PROVIDER,\n });\n}\n\nfunction validateRequest(request: DecisionRequest): void {\n validateValue(request.state, 'state');\n const entries = Object.entries(request.questions || {});\n if (entries.length === 0)\n throw new ValidationError('questions must not be empty', {\n provider: PROVIDER,\n });\n for (const [id, question] of entries) {\n if (!id.trim())\n throw new ValidationError('question IDs must not be empty', {\n provider: PROVIDER,\n });\n validateValue(question.instructions, `questions.${id}.instructions`);\n if (question.type === 'predicate') {\n if (question.criteria) {\n for (const [key, value] of Object.entries(question.criteria))\n validateValue(value, `questions.${id}.criteria.${key}`);\n }\n } else if (question.type === 'choice') {\n const options = Object.keys(question.criteria || {});\n if (options.length === 0 || options.length > 255)\n throw new ValidationError(\n `questions.${id}.criteria must contain 1 to 255 options`,\n { provider: PROVIDER },\n );\n for (const [key, value] of Object.entries(question.criteria))\n if (value !== null)\n validateValue(value, `questions.${id}.criteria.${key}`);\n } else if (question.type === 'score') {\n if (question.criteria.length < 2 || question.criteria.length > 10)\n throw new ValidationError(\n `questions.${id}.criteria must contain 2 to 10 ordered levels`,\n { provider: PROVIDER },\n );\n question.criteria.forEach((value, index) => {\n validateValue(value, `questions.${id}.criteria[${index}]`);\n });\n } else {\n throw new ValidationError(`questions.${id}.type is unsupported`, {\n provider: PROVIDER,\n });\n }\n }\n}\n\nfunction wireQuestion(question: DecisionQuestion): WireQuestion {\n if (question.type === 'predicate')\n return {\n type: 'noul',\n instructions: question.instructions,\n ...(question.criteria ? { criteria: question.criteria } : {}),\n };\n return question;\n}\n\nfunction distribution(\n value: unknown,\n expected: string[],\n field: string,\n): Record<string, number> {\n if (\n !isRecord(value) ||\n Object.keys(value).length !== expected.length ||\n expected.some((key) => !(key in value))\n ) {\n throw new AIError(\n `TypeSafe response ${field} must cover exactly the requested values`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const result = Object.fromEntries(\n expected.map((key) => [key, probability(value[key], `${field}.${key}`)]),\n );\n const sum = Object.values(result).reduce((total, item) => total + item, 0);\n if (Math.abs(sum - 1) <= STRICT_DISTRIBUTION_EPSILON) return result;\n\n // TypeSafe documents normalized distributions, but observed high-cardinality\n // wire responses use hundredth rounding. Accept only that measured form and\n // cap its total rounding error at one percentage point before normalizing.\n const maximumRoundingError = Math.min(\n expected.length * 0.005,\n ROUNDED_DISTRIBUTION_MAX_ERROR,\n );\n const isHundredthRounded = Object.values(result).every(\n (item) =>\n Math.abs(item * 100 - Math.round(item * 100)) <= HUNDREDTH_GRID_EPSILON,\n );\n if (\n sum <= 0 ||\n !isHundredthRounded ||\n Math.abs(sum - 1) > maximumRoundingError + HUNDREDTH_GRID_EPSILON\n )\n throw new AIError(\n `TypeSafe response ${field} must sum to 1`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return Object.fromEntries(\n Object.entries(result).map(([key, item]) => [key, item / sum]),\n );\n}\n\nfunction answer(\n question: DecisionQuestion,\n raw: unknown,\n id: string,\n): DecisionAnswer {\n if (!isRecord(raw))\n throw new AIError(\n `TypeSafe response answers.${id} must be an object`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'predicate') {\n if (raw.type !== 'noul')\n throw new AIError(\n `TypeSafe response answers.${id} type does not match predicate`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'predicate',\n probability: probability(raw.noul, `answers.${id}.noul`),\n };\n }\n if (raw.type !== question.type)\n throw new AIError(\n `TypeSafe response answers.${id} type does not match request`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (question.type === 'choice') {\n const choices = Object.keys(question.criteria);\n if (typeof raw.choice !== 'string' || !choices.includes(raw.choice))\n throw new AIError(\n `TypeSafe response answers.${id}.choice is not a requested option`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'choice',\n choice: raw.choice,\n probabilities: distribution(\n raw.probabilities,\n choices,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n };\n }\n const scoreQuestion = question as ScoreDecisionQuestion;\n const levels = scoreQuestion.criteria;\n const levelKeys = levels.map((_, index) => String(index));\n const score = finite(raw.score, `answers.${id}.score`);\n if (score < 0 || score > levels.length - 1)\n throw new AIError(\n `TypeSafe response answers.${id}.score is outside the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const legend = raw.legend;\n if (\n !isRecord(legend) ||\n levelKeys.some(\n (key, index) => !sameDecisionValue(levels[index], legend[key]),\n )\n )\n throw new AIError(\n `TypeSafe response answers.${id}.legend does not match the requested rubric`,\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n return {\n type: 'score',\n score,\n probabilities: distribution(\n raw.probabilities,\n levelKeys,\n `answers.${id}.probabilities`,\n ),\n confidence: probability(raw.confidence, `answers.${id}.confidence`),\n levels,\n };\n}\n\n/** A decision-only adapter for TypeSafe's System One endpoint. */\nexport class TypeSafeProvider implements AIInterface {\n private readonly options: TypeSafeOptions;\n\n constructor(options: TypeSafeOptions) {\n this.options = normalizeBaseAIOptions({\n ...options,\n baseUrl: (options.baseUrl || DEFAULT_BASE_URL).replace(/\\/+$/, ''),\n });\n }\n\n async decide(\n request: DecisionRequest,\n options: DecisionOptions = {},\n ): Promise<DecisionResult> {\n validateRequest(request);\n const apiKey = this.options.apiKey;\n if (!apiKey) throw new AuthenticationError(PROVIDER);\n const controls = prepareRequestControls(this.options, options);\n const startedAt = Date.now();\n const model = options.model || this.options.defaultModel || DEFAULT_MODEL;\n try {\n const response = await fetch(`${this.options.baseUrl}/systemone`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${apiKey}`,\n 'Content-Type': 'application/json',\n ...this.options.headers,\n },\n body: JSON.stringify({\n state: request.state,\n model,\n questions: Object.fromEntries(\n Object.entries(request.questions).map(([id, question]) => [\n id,\n wireQuestion(question),\n ]),\n ),\n }),\n signal: controls.signal,\n });\n if (!response.ok) {\n if (response.status === 401) throw new AuthenticationError(PROVIDER);\n const text = await response.text();\n if (response.status === 429 || response.status === 529)\n throw rateLimitErrorFrom(\n PROVIDER,\n { headers: response.headers, message: text },\n { model },\n );\n throw new AIError(\n `TypeSafe request failed (${response.status}): ${text.slice(0, 500)}`,\n 'API_ERROR',\n PROVIDER,\n model,\n response.status >= 500,\n );\n }\n let body: WireResponse;\n try {\n body = (await response.json()) as WireResponse;\n } catch (error) {\n if (error instanceof SyntaxError) {\n throw new AIError(\n 'TypeSafe response contained invalid JSON',\n 'INVALID_RESPONSE',\n PROVIDER,\n model,\n );\n }\n throw error;\n }\n if (!body || typeof body.model !== 'string' || !body.model)\n throw new AIError(\n 'TypeSafe response model is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n if (!isRecord(body.answers))\n throw new AIError(\n 'TypeSafe response answers is required',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const responseAnswers = body.answers;\n const ids = Object.keys(request.questions);\n if (\n Object.keys(responseAnswers).length !== ids.length ||\n ids.some((id) => !(id in responseAnswers))\n )\n throw new AIError(\n 'TypeSafe response answers must match requested question IDs',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n const answers = Object.fromEntries(\n ids.map((id) => [\n id,\n answer(request.questions[id], responseAnswers[id], id),\n ]),\n );\n let usage:\n | {\n promptTokens: number;\n completionTokens: number;\n totalTokens: number;\n }\n | undefined;\n if (body.usage !== undefined) {\n if (\n !isRecord(body.usage) ||\n !('input_tokens' in body.usage) ||\n !('output_tokens' in body.usage)\n ) {\n throw new AIError(\n 'TypeSafe response usage must include input_tokens and output_tokens',\n 'INVALID_RESPONSE',\n PROVIDER,\n );\n }\n const input = tokenCount(body.usage.input_tokens, 'usage.input_tokens');\n const output = tokenCount(\n body.usage.output_tokens,\n 'usage.output_tokens',\n );\n usage = {\n promptTokens: input,\n completionTokens: output,\n totalTokens: input + output,\n };\n }\n emitUsage(\n this.options,\n PROVIDER,\n 'decide',\n body.model,\n usage,\n startedAt,\n options.usageTags,\n );\n return {\n model: body.model,\n ...(usage ? { usage } : {}),\n provenance: { provider: PROVIDER, model: body.model },\n answers,\n };\n } catch (error) {\n if (controls.didTimeout())\n throw new AIError(\n `TypeSafe request timed out after ${controls.timeout}ms`,\n 'REQUEST_TIMEOUT',\n PROVIDER,\n model,\n true,\n );\n if (controls.signal.aborted && !(error instanceof AIError))\n throw new AIError(\n 'TypeSafe request was aborted',\n 'REQUEST_ABORTED',\n PROVIDER,\n model,\n );\n if (!(error instanceof AIError)) {\n throw new AIError(\n `Network error calling TypeSafe System One: ${\n error instanceof Error ? error.message : String(error)\n }`,\n 'NETWORK_ERROR',\n PROVIDER,\n model,\n true,\n );\n }\n throw error;\n } finally {\n controls.cleanup();\n }\n }\n\n async getModels(): Promise<AIModel[]> {\n return [\n {\n id: this.options.defaultModel || DEFAULT_MODEL,\n name: 'TypeSafe Jev',\n description: 'TypeSafe System One typed decisions',\n contextLength: 0,\n capabilities: ['decisions'],\n supportsFunctions: false,\n supportsVision: false,\n },\n ];\n }\n async getCapabilities(): Promise<AICapabilities> {\n return {\n decisions: true,\n chat: false,\n completion: false,\n embeddings: false,\n streaming: false,\n functions: false,\n vision: false,\n fineTuning: false,\n imageEmbeddings: false,\n imageGeneration: false,\n videoGeneration: false,\n tts: false,\n voiceCloning: false,\n voiceDesign: false,\n maxContextLength: 0,\n supportedOperations: ['decide'],\n };\n }\n private unsupported(): never {\n throw new AIError(\n 'This operation is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n }\n async chat(_a: AIMessage[], _b?: ChatOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async complete(_a: string, _b?: CompletionOptions): Promise<AIResponse> {\n return this.unsupported();\n }\n async message(_a: string, _b?: MessageOptions): Promise<string> {\n return this.unsupported();\n }\n async embed(\n _a: string | string[],\n _b?: EmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async embedImage(\n _a: string | Buffer,\n _b?: ImageEmbeddingOptions,\n ): Promise<EmbeddingResponse> {\n return this.unsupported();\n }\n async describeImage(\n _a: string | Buffer,\n _b?: string,\n _c?: ImageDescriptionOptions,\n ): Promise<string> {\n return this.unsupported();\n }\n async generateImage(\n _a: string,\n _b?: ImageGenerationOptions,\n ): Promise<ImageGenerationResponse> {\n return this.unsupported();\n }\n stream(_a: AIMessage[], _b?: ChatOptions): AsyncIterable<string> {\n const error = new AIError(\n 'Chat streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async countTokens(_a: string): Promise<number> {\n return this.unsupported();\n }\n async submitVideoGenerationJob(\n _a: VideoGenerationOptions,\n ): Promise<VideoGenerationJob> {\n return this.unsupported();\n }\n async getVideoGenerationJob(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationStatusResult> {\n return this.unsupported();\n }\n async fetchVideoGenerationResult(\n _a: VideoGenerationJob,\n ): Promise<VideoGenerationResult> {\n return this.unsupported();\n }\n async cancelVideoGenerationJob(_a: VideoGenerationJob): Promise<void> {\n return this.unsupported();\n }\n async validateVideoGenerationAccess(): Promise<boolean> {\n return this.unsupported();\n }\n async synthesizeSpeech(_a: string, _b?: TTSOptions): Promise<TTSResponse> {\n return this.unsupported();\n }\n streamSpeech(_a: string, _b?: TTSOptions): AsyncIterable<Buffer> {\n const error = new AIError(\n 'TTS streaming is not supported by the TypeSafe decision-only provider.',\n 'NOT_IMPLEMENTED',\n PROVIDER,\n );\n return {\n [Symbol.asyncIterator]: () => ({ next: () => Promise.reject(error) }),\n };\n }\n async cloneVoice(_a: VoiceCloneOptions): Promise<Voice> {\n return this.unsupported();\n }\n async designVoice(_a: VoiceDesignOptions): Promise<Voice> {\n return this.unsupported();\n }\n async getVoices(_a?: VoiceListOptions): Promise<Voice[]> {\n return this.unsupported();\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,484 @@
1
+ //#region src/shared/types.ts
2
+ /**
3
+ * Supported AI provider types
4
+ */
5
+ var AI_PROVIDER_TYPES = [
6
+ "openai",
7
+ "litellm",
8
+ "bifrost",
9
+ "ollama",
10
+ "gemini",
11
+ "anthropic",
12
+ "huggingface",
13
+ "bedrock",
14
+ "claude-cli",
15
+ "qwen3-tts",
16
+ "openai-compat-video",
17
+ "byteplus-modelark",
18
+ "seevio",
19
+ "typesafe",
20
+ "webllm"
21
+ ];
22
+ /**
23
+ * Extract text content from a message content field.
24
+ *
25
+ * Handles both simple string content and multimodal content arrays,
26
+ * extracting only the text parts and concatenating them.
27
+ *
28
+ * @param content - The message content (string or ContentPart array)
29
+ * @returns The extracted text content
30
+ */
31
+ function extractTextContent(content) {
32
+ if (typeof content === "string") return content;
33
+ return content.filter((part) => part.type === "text").map((part) => part.text).join("\n");
34
+ }
35
+ /**
36
+ * Base error class for all AI operations.
37
+ * Provider-specific errors are mapped to subclasses for structured error handling.
38
+ *
39
+ * @param message - Human-readable error description
40
+ * @param code - Machine-readable error code (e.g., 'AUTH_ERROR', 'RATE_LIMIT')
41
+ * @param provider - Provider that raised the error (e.g., 'openai', 'anthropic')
42
+ * @param model - Model involved in the error, if applicable
43
+ */
44
+ var AIError = class extends Error {
45
+ code;
46
+ provider;
47
+ model;
48
+ retryable;
49
+ constructor(message, code, provider, model, retryable = false) {
50
+ super(message);
51
+ this.code = code;
52
+ this.provider = provider;
53
+ this.model = model;
54
+ this.retryable = retryable;
55
+ this.name = "AIError";
56
+ }
57
+ };
58
+ /**
59
+ * Thrown when API key or credentials are invalid or missing.
60
+ *
61
+ * @param provider - Provider that rejected authentication
62
+ */
63
+ var AuthenticationError = class extends AIError {
64
+ constructor(provider) {
65
+ super("Authentication failed", "AUTH_ERROR", provider, void 0, false);
66
+ this.name = "AuthenticationError";
67
+ }
68
+ };
69
+ /**
70
+ * Default for {@link RateLimitErrorDetails.maxRetryDelayMs}: a rate limit that
71
+ * resets more than a minute away is not worth retrying in-process.
72
+ */
73
+ var DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS = 6e4;
74
+ /**
75
+ * Whether a rate limit that lifts after `waitMs` is worth retrying soon, given
76
+ * the longest acceptable wait. An unknown wait counts as retryable.
77
+ */
78
+ function isRateLimitRetryableSoon(waitMs, maxRetryDelayMs = DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS) {
79
+ return waitMs === void 0 || waitMs <= maxRetryDelayMs;
80
+ }
81
+ var MAX_RATE_LIMIT_REASON_LENGTH = 500;
82
+ /**
83
+ * Thrown when the provider's rate limit has been exceeded.
84
+ *
85
+ * @param provider - Provider that enforced the rate limit
86
+ * @param retryAfter - Seconds to wait before retrying, if provided by the API
87
+ * @param details - The provider's reason text and reset hints
88
+ */
89
+ var RateLimitError = class extends AIError {
90
+ /** Seconds until the limit resets, when the provider said so. */
91
+ retryAfter;
92
+ /** Milliseconds until the limit resets, when the provider said so. */
93
+ retryAfterMs;
94
+ /** Length of a limit window named without a reset time (see details). */
95
+ limitWindowMs;
96
+ /** The provider's own reason text, when it sent one. */
97
+ reason;
98
+ constructor(provider, retryAfter, details = {}) {
99
+ const retryAfterMs = finiteNonNegative(details.retryAfterMs ?? (retryAfter !== void 0 ? retryAfter * 1e3 : void 0));
100
+ const seconds = finiteNonNegative(retryAfter) ?? (retryAfterMs !== void 0 ? Math.ceil(retryAfterMs / 1e3) : void 0);
101
+ const reason = details.reason?.replace(/\s+/g, " ").trim().slice(0, MAX_RATE_LIMIT_REASON_LENGTH);
102
+ super(`Rate limit exceeded${reason ? `: ${reason}` : ""}${seconds ? `, retry after ${seconds}s` : ""}`, "RATE_LIMIT", provider, details.model, true);
103
+ this.name = "RateLimitError";
104
+ this.retryAfter = seconds;
105
+ this.retryAfterMs = retryAfterMs;
106
+ this.limitWindowMs = finiteNonNegative(details.limitWindowMs);
107
+ this.retryable = isRateLimitRetryableSoon(this.retryAfterMs ?? this.limitWindowMs, details.maxRetryDelayMs);
108
+ this.reason = reason || void 0;
109
+ if (details.cause !== void 0) this.cause = details.cause;
110
+ }
111
+ };
112
+ function finiteNonNegative(value) {
113
+ return typeof value === "number" && Number.isFinite(value) ? Math.max(0, value) : void 0;
114
+ }
115
+ /**
116
+ * Thrown when the requested model does not exist or is not available.
117
+ *
118
+ * @param model - The model identifier that was not found
119
+ * @param provider - Provider that was queried
120
+ */
121
+ var ModelNotFoundError = class extends AIError {
122
+ constructor(model, provider) {
123
+ super(`Model not found: ${model}`, "MODEL_NOT_FOUND", provider, model, false);
124
+ this.name = "ModelNotFoundError";
125
+ }
126
+ };
127
+ /**
128
+ * Thrown when the input exceeds the model's maximum context window.
129
+ *
130
+ * @param provider - Provider that reported the error
131
+ * @param model - Model whose context limit was exceeded
132
+ */
133
+ var ContextLengthError = class extends AIError {
134
+ constructor(provider, model) {
135
+ super("Input exceeds maximum context length", "CONTEXT_LENGTH_EXCEEDED", provider, model, false);
136
+ this.name = "ContextLengthError";
137
+ }
138
+ };
139
+ /**
140
+ * Thrown by the `webllm` provider when the browser exposes no WebGPU
141
+ * (`navigator.gpu` is absent). Catch it to show a fallback.
142
+ */
143
+ var WebGPUUnavailableError = class extends AIError {
144
+ constructor(provider = "webllm", detail) {
145
+ super(detail ?? "WebGPU is not available in this environment (navigator.gpu is missing); on-device inference cannot run.", "WEBGPU_UNAVAILABLE", provider, void 0, false);
146
+ this.name = "WebGPUUnavailableError";
147
+ }
148
+ };
149
+ /**
150
+ * Thrown by the `webllm` provider when the optional peer dependency
151
+ * `@mlc-ai/web-llm` cannot be imported.
152
+ */
153
+ var WebLLMPeerMissingError = class extends AIError {
154
+ constructor(cause) {
155
+ super("The webllm provider needs the optional peer dependency @mlc-ai/web-llm. Install it with `pnpm add @mlc-ai/web-llm` (or the npm/yarn equivalent).", "WEBLLM_PEER_MISSING", "webllm", void 0, false);
156
+ this.name = "WebLLMPeerMissingError";
157
+ if (cause !== void 0) this.cause = cause;
158
+ }
159
+ };
160
+ /**
161
+ * Thrown when content is blocked by the provider's safety/content filters.
162
+ *
163
+ * @param provider - Provider that filtered the content
164
+ * @param model - Model that triggered the filter
165
+ */
166
+ var ContentFilterError = class extends AIError {
167
+ constructor(provider, model) {
168
+ super("Content filtered by safety systems", "CONTENT_FILTERED", provider, model, false);
169
+ this.name = "ContentFilterError";
170
+ }
171
+ };
172
+ //#endregion
173
+ //#region src/shared/safety.ts
174
+ var DEFAULT_AI_TIMEOUT_MS = 12e4;
175
+ var DEFAULT_AI_MAX_RETRIES = 0;
176
+ var DEFAULT_AI_GENERATION_LIMITS = Object.freeze({
177
+ maxOutputTokens: 131072,
178
+ defaultOutputTokens: 4096,
179
+ maxReasoningTokens: 1024,
180
+ maxImagesPerRequest: 1,
181
+ onExceeded: "error"
182
+ });
183
+ function positiveInteger(value, fallback, field) {
184
+ if (value === void 0) return fallback;
185
+ if (!Number.isFinite(value) || value <= 0) throw new AIError(`${field} must be a positive finite number`, "AI_LIMIT_INVALID");
186
+ return Math.trunc(value);
187
+ }
188
+ function normalizeBaseAIOptions(options) {
189
+ const configuredLimits = options.generationLimits || {};
190
+ const generationLimits = {
191
+ maxOutputTokens: positiveInteger(configuredLimits.maxOutputTokens, DEFAULT_AI_GENERATION_LIMITS.maxOutputTokens, "generationLimits.maxOutputTokens"),
192
+ defaultOutputTokens: Math.min(positiveInteger(configuredLimits.defaultOutputTokens, DEFAULT_AI_GENERATION_LIMITS.defaultOutputTokens, "generationLimits.defaultOutputTokens"), positiveInteger(configuredLimits.maxOutputTokens, DEFAULT_AI_GENERATION_LIMITS.maxOutputTokens, "generationLimits.maxOutputTokens")),
193
+ maxReasoningTokens: positiveInteger(configuredLimits.maxReasoningTokens, DEFAULT_AI_GENERATION_LIMITS.maxReasoningTokens, "generationLimits.maxReasoningTokens"),
194
+ maxImagesPerRequest: positiveInteger(configuredLimits.maxImagesPerRequest, DEFAULT_AI_GENERATION_LIMITS.maxImagesPerRequest, "generationLimits.maxImagesPerRequest"),
195
+ onExceeded: configuredLimits.onExceeded || DEFAULT_AI_GENERATION_LIMITS.onExceeded
196
+ };
197
+ if (!["error", "clamp"].includes(generationLimits.onExceeded)) throw new AIError("generationLimits.onExceeded must be \"error\" or \"clamp\"", "AI_LIMIT_INVALID");
198
+ return {
199
+ ...options,
200
+ timeout: positiveInteger(options.timeout, DEFAULT_AI_TIMEOUT_MS, "timeout"),
201
+ maxRetries: (() => {
202
+ if (options.maxRetries === void 0) return 0;
203
+ if (!Number.isFinite(options.maxRetries) || options.maxRetries < 0) throw new AIError("maxRetries must be a non-negative finite number", "AI_LIMIT_INVALID");
204
+ return Math.trunc(options.maxRetries);
205
+ })(),
206
+ generationLimits
207
+ };
208
+ }
209
+ function reasoningTokensForEffort(effort) {
210
+ switch (effort) {
211
+ case false:
212
+ case "none": return 0;
213
+ case "minimal": return 1024;
214
+ case "low": return 2048;
215
+ case "medium": return 4096;
216
+ case "high": return 8192;
217
+ default: return;
218
+ }
219
+ }
220
+ function enforceLimit(requested, limit, behavior, label, provider, model) {
221
+ if (!Number.isFinite(requested) || requested < 0) throw new AIError(`${label} must be a non-negative finite number`, "AI_LIMIT_INVALID", provider, model);
222
+ const normalized = Math.trunc(requested);
223
+ if (normalized <= limit) return normalized;
224
+ if (behavior === "clamp") return limit;
225
+ throw new AIError(`${label} ${normalized} exceeds configured ceiling ${limit}`, "AI_LIMIT_EXCEEDED", provider, model);
226
+ }
227
+ function normalizeChatOptions(providerOptions, options, provider, model) {
228
+ const limits = normalizeBaseAIOptions(providerOptions).generationLimits;
229
+ const requestedOutput = options.maxTokens ?? limits.defaultOutputTokens ?? limits.maxOutputTokens;
230
+ const legacyEffort = options.thinkingLevel ?? providerOptions.thinkingLevel;
231
+ const requestedReasoning = options.reasoning !== void 0 || legacyEffort !== void 0 || options.includeThoughts === true ? options.reasoning?.maxTokens ?? reasoningTokensForEffort(options.reasoning?.effort ?? legacyEffort) ?? limits.maxReasoningTokens : 0;
232
+ return {
233
+ ...options,
234
+ maxTokens: enforceLimit(requestedOutput, limits.maxOutputTokens, limits.onExceeded, "maxTokens", provider, model),
235
+ reasoning: {
236
+ ...options.reasoning,
237
+ maxTokens: enforceLimit(requestedReasoning, limits.maxReasoningTokens, limits.onExceeded, "reasoning.maxTokens", provider, model),
238
+ includeThoughts: options.reasoning?.includeThoughts ?? options.includeThoughts
239
+ }
240
+ };
241
+ }
242
+ function normalizeImageGenerationOptions(providerOptions, options, provider, model) {
243
+ const limits = normalizeBaseAIOptions(providerOptions).generationLimits;
244
+ return {
245
+ ...options,
246
+ n: enforceLimit(options.n ?? 1, limits.maxImagesPerRequest, limits.onExceeded, "n", provider, model)
247
+ };
248
+ }
249
+ function prepareRequestControls(providerOptions, requestOptions = {}) {
250
+ const normalized = normalizeBaseAIOptions(providerOptions);
251
+ const timeout = positiveInteger(requestOptions.timeout, normalized.timeout, "timeout");
252
+ const controller = new AbortController();
253
+ let timedOut = false;
254
+ const abortFromCaller = () => controller.abort(requestOptions.signal?.reason);
255
+ if (requestOptions.signal?.aborted) abortFromCaller();
256
+ else requestOptions.signal?.addEventListener("abort", abortFromCaller, { once: true });
257
+ const timer = setTimeout(() => {
258
+ timedOut = true;
259
+ controller.abort(/* @__PURE__ */ new Error(`AI request timed out after ${timeout}ms`));
260
+ }, timeout);
261
+ return {
262
+ signal: controller.signal,
263
+ timeout,
264
+ didTimeout: () => timedOut,
265
+ cleanup: () => {
266
+ clearTimeout(timer);
267
+ requestOptions.signal?.removeEventListener("abort", abortFromCaller);
268
+ }
269
+ };
270
+ }
271
+ function mergeTags(providerOptions, callTags) {
272
+ return providerOptions.usageTags || callTags ? {
273
+ ...providerOptions.usageTags,
274
+ ...callTags
275
+ } : void 0;
276
+ }
277
+ function emitRequestEvent(providerOptions, event) {
278
+ if (!providerOptions.onRequest) return;
279
+ try {
280
+ providerOptions.onRequest({
281
+ ...event,
282
+ tags: mergeTags(providerOptions, event.tags)
283
+ });
284
+ } catch {}
285
+ }
286
+ function classifyRequestFailure(error, didTimeout = false) {
287
+ const code = error instanceof AIError ? error.code : void 0;
288
+ if (code === "AI_LIMIT_EXCEEDED" || code === "AI_LIMIT_INVALID") return {
289
+ status: "rejected",
290
+ errorCode: code
291
+ };
292
+ if (didTimeout || code === "AI_TIMEOUT" || code === "TIMEOUT" || code === "REQUEST_TIMEOUT") return {
293
+ status: "timed_out",
294
+ errorCode: code || "AI_TIMEOUT"
295
+ };
296
+ if (error instanceof Error && error.name === "AbortError") return {
297
+ status: "aborted",
298
+ errorCode: "ABORTED"
299
+ };
300
+ if (code === "AI_ABORTED" || code === "REQUEST_ABORTED") return {
301
+ status: "aborted",
302
+ errorCode: code
303
+ };
304
+ return {
305
+ status: "failed",
306
+ errorCode: code || (error instanceof Error ? error.name : void 0)
307
+ };
308
+ }
309
+ function requestEventBase(options) {
310
+ const normalized = normalizeBaseAIOptions(options.providerOptions);
311
+ return {
312
+ provider: options.provider,
313
+ model: options.model,
314
+ operation: options.operation,
315
+ attempts: normalized.maxRetries + 1,
316
+ requestedMaxOutputTokens: options.operation === "decide" ? void 0 : options.callOptions?.maxTokens,
317
+ effectiveMaxOutputTokens: options.operation === "decide" || options.operation === "generateImage" || VIDEO_GENERATION_OPERATIONS.has(options.operation) ? void 0 : options.effectiveMaxOutputTokens ?? Math.min(options.callOptions?.maxTokens ?? normalized.generationLimits.defaultOutputTokens ?? normalized.generationLimits.maxOutputTokens, normalized.generationLimits.maxOutputTokens),
318
+ tags: options.callOptions?.usageTags
319
+ };
320
+ }
321
+ var OBSERVED_OPERATIONS = /* @__PURE__ */ new Set([
322
+ "decide",
323
+ "chat",
324
+ "complete",
325
+ "message",
326
+ "describeImage",
327
+ "generateImage",
328
+ "stream",
329
+ "submitVideoGenerationJob",
330
+ "getVideoGenerationJob",
331
+ "fetchVideoGenerationResult",
332
+ "cancelVideoGenerationJob"
333
+ ]);
334
+ /**
335
+ * `getVideoGenerationJob` / `fetchVideoGenerationResult` /
336
+ * `cancelVideoGenerationJob` take a `VideoGenerationJob` handle as their
337
+ * first (and only) argument rather than a chat-shaped `options` object as
338
+ * the second argument. The handle still carries a `model` field, so
339
+ * `callOptionsFor` reads it from the same position as `submitVideoGenerationJob`'s
340
+ * `options` (index 0) rather than index 1.
341
+ */
342
+ var VIDEO_HANDLE_OPERATIONS = /* @__PURE__ */ new Set([
343
+ "getVideoGenerationJob",
344
+ "fetchVideoGenerationResult",
345
+ "cancelVideoGenerationJob"
346
+ ]);
347
+ var VIDEO_GENERATION_OPERATIONS = /* @__PURE__ */ new Set(["submitVideoGenerationJob", ...VIDEO_HANDLE_OPERATIONS]);
348
+ function callOptionsFor(operation, args) {
349
+ const value = args[operation === "decide" ? 1 : operation === "describeImage" ? 2 : operation === "submitVideoGenerationJob" || VIDEO_HANDLE_OPERATIONS.has(operation) ? 0 : 1];
350
+ return value && typeof value === "object" ? value : void 0;
351
+ }
352
+ function providerName(options) {
353
+ return options.type || "openai";
354
+ }
355
+ function effectiveOutputTokens(operation, providerOptions, callOptions) {
356
+ if (operation === "decide" || operation === "generateImage" || VIDEO_GENERATION_OPERATIONS.has(operation)) {
357
+ if (operation === "generateImage") normalizeImageGenerationOptions(providerOptions, callOptions || {}, providerName(providerOptions), callOptions?.model);
358
+ return;
359
+ }
360
+ return normalizeChatOptions(providerOptions, callOptions || {}, providerName(providerOptions), callOptions?.model || providerOptions.defaultModel).maxTokens;
361
+ }
362
+ /**
363
+ * Wrap a public provider instance with prompt-free lifecycle observation.
364
+ * Provider adapters still enforce limits internally so direct construction is
365
+ * protected; this wrapper adds one terminal event to the public getAI() path.
366
+ */
367
+ function createObservedAI(client, providerOptions) {
368
+ if (!providerOptions.onRequest) return client;
369
+ return new Proxy(client, { get(target, property, receiver) {
370
+ const value = Reflect.get(target, property, receiver);
371
+ if (typeof property !== "string" || typeof value !== "function" || !OBSERVED_OPERATIONS.has(property)) return typeof value === "function" ? value.bind(target) : value;
372
+ const operation = property;
373
+ if (operation === "stream") return async function* (...args) {
374
+ const startedAt = Date.now();
375
+ const callOptions = callOptionsFor(operation, args);
376
+ let base;
377
+ try {
378
+ base = requestEventBase({
379
+ providerOptions,
380
+ provider: providerName(providerOptions),
381
+ model: callOptions?.model || providerOptions.defaultModel || "unknown",
382
+ operation,
383
+ callOptions,
384
+ effectiveMaxOutputTokens: effectiveOutputTokens(operation, providerOptions, callOptions)
385
+ });
386
+ const iterable = Reflect.apply(value, target, args);
387
+ for await (const chunk of iterable) yield chunk;
388
+ emitRequestEvent(providerOptions, {
389
+ ...base,
390
+ status: "succeeded",
391
+ duration: Date.now() - startedAt
392
+ });
393
+ } catch (error) {
394
+ const failure = classifyRequestFailure(error);
395
+ base ||= requestEventBase({
396
+ providerOptions,
397
+ provider: providerName(providerOptions),
398
+ model: callOptions?.model || providerOptions.defaultModel || "unknown",
399
+ operation,
400
+ callOptions
401
+ });
402
+ emitRequestEvent(providerOptions, {
403
+ ...base,
404
+ ...failure,
405
+ duration: Date.now() - startedAt
406
+ });
407
+ throw error;
408
+ }
409
+ };
410
+ return async (...args) => {
411
+ const startedAt = Date.now();
412
+ const callOptions = callOptionsFor(operation, args);
413
+ let base;
414
+ try {
415
+ base = requestEventBase({
416
+ providerOptions,
417
+ provider: providerName(providerOptions),
418
+ model: callOptions?.model || providerOptions.defaultModel || "unknown",
419
+ operation,
420
+ callOptions,
421
+ effectiveMaxOutputTokens: effectiveOutputTokens(operation, providerOptions, callOptions)
422
+ });
423
+ const result = await Reflect.apply(value, target, args);
424
+ emitRequestEvent(providerOptions, {
425
+ ...base,
426
+ status: "succeeded",
427
+ duration: Date.now() - startedAt
428
+ });
429
+ return result;
430
+ } catch (error) {
431
+ const failure = classifyRequestFailure(error);
432
+ base ||= requestEventBase({
433
+ providerOptions,
434
+ provider: providerName(providerOptions),
435
+ model: callOptions?.model || providerOptions.defaultModel || "unknown",
436
+ operation,
437
+ callOptions
438
+ });
439
+ emitRequestEvent(providerOptions, {
440
+ ...base,
441
+ ...failure,
442
+ duration: Date.now() - startedAt
443
+ });
444
+ throw error;
445
+ }
446
+ };
447
+ } });
448
+ }
449
+ //#endregion
450
+ //#region src/shared/providers/usage.ts
451
+ /**
452
+ * Emit a usage event to the `onUsage` callback configured on provider options.
453
+ *
454
+ * @param providerOptions - The provider's stored options (for `onUsage` and global `usageTags`).
455
+ * @param providerName - Provider identifier (e.g. `'openai'`).
456
+ * @param operation - The operation type that generated this usage.
457
+ * @param model - Model that was used.
458
+ * @param usage - Token usage breakdown, if available.
459
+ * @param startTime - `Date.now()` captured before the API call.
460
+ * @param callTags - Per-call `usageTags` from the method's options.
461
+ */
462
+ function emitUsage(providerOptions, providerName, operation, model, usage, startTime, callTags) {
463
+ if (!providerOptions.onUsage) return;
464
+ const globalTags = providerOptions.usageTags;
465
+ const tags = globalTags || callTags ? {
466
+ ...globalTags,
467
+ ...callTags
468
+ } : void 0;
469
+ try {
470
+ providerOptions.onUsage({
471
+ provider: providerName,
472
+ model,
473
+ operation,
474
+ usage,
475
+ duration: Date.now() - startTime,
476
+ timestamp: /* @__PURE__ */ new Date(),
477
+ tags
478
+ });
479
+ } catch {}
480
+ }
481
+ //#endregion
482
+ export { RateLimitError as _, createObservedAI as a, extractTextContent as b, normalizeImageGenerationOptions as c, AI_PROVIDER_TYPES as d, AuthenticationError as f, ModelNotFoundError as g, DEFAULT_RATE_LIMIT_MAX_RETRY_DELAY_MS as h, DEFAULT_AI_TIMEOUT_MS as i, prepareRequestControls as l, ContextLengthError as m, DEFAULT_AI_GENERATION_LIMITS as n, normalizeBaseAIOptions as o, ContentFilterError as p, DEFAULT_AI_MAX_RETRIES as r, normalizeChatOptions as s, emitUsage as t, AIError as u, WebGPUUnavailableError as v, isRateLimitRetryableSoon as x, WebLLMPeerMissingError as y };
483
+
484
+ //# sourceMappingURL=usage-BaQKo8bc.js.map