@opencode/ai 0.0.0-beta-19275

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 (252) hide show
  1. package/README.md +682 -0
  2. package/dist/cache-policy.d.ts +2 -0
  3. package/dist/cache-policy.js +129 -0
  4. package/dist/image-client.d.ts +19 -0
  5. package/dist/image-client.js +28 -0
  6. package/dist/image.d.ts +110 -0
  7. package/dist/image.js +103 -0
  8. package/dist/index.d.ts +18 -0
  9. package/dist/index.js +12 -0
  10. package/dist/llm.d.ts +252 -0
  11. package/dist/llm.js +74 -0
  12. package/dist/protocols/anthropic-messages.d.ts +957 -0
  13. package/dist/protocols/anthropic-messages.js +1414 -0
  14. package/dist/protocols/bedrock-converse.d.ts +499 -0
  15. package/dist/protocols/bedrock-converse.js +643 -0
  16. package/dist/protocols/bedrock-event-stream.d.ts +9 -0
  17. package/dist/protocols/bedrock-event-stream.js +97 -0
  18. package/dist/protocols/gemini.d.ts +285 -0
  19. package/dist/protocols/gemini.js +671 -0
  20. package/dist/protocols/google-images.d.ts +30 -0
  21. package/dist/protocols/google-images.js +181 -0
  22. package/dist/protocols/index.d.ts +12 -0
  23. package/dist/protocols/index.js +12 -0
  24. package/dist/protocols/meta-images.d.ts +26 -0
  25. package/dist/protocols/meta-images.js +89 -0
  26. package/dist/protocols/meta-messages.d.ts +350 -0
  27. package/dist/protocols/meta-messages.js +41 -0
  28. package/dist/protocols/meta-responses.d.ts +473 -0
  29. package/dist/protocols/meta-responses.js +173 -0
  30. package/dist/protocols/mistral-chat.d.ts +540 -0
  31. package/dist/protocols/mistral-chat.js +624 -0
  32. package/dist/protocols/open-responses-channel.d.ts +23 -0
  33. package/dist/protocols/open-responses-channel.js +141 -0
  34. package/dist/protocols/open-responses-continuation.d.ts +12 -0
  35. package/dist/protocols/open-responses-continuation.js +161 -0
  36. package/dist/protocols/open-responses.d.ts +1583 -0
  37. package/dist/protocols/open-responses.js +1206 -0
  38. package/dist/protocols/openai-chat.d.ts +860 -0
  39. package/dist/protocols/openai-chat.js +966 -0
  40. package/dist/protocols/openai-compatible-chat.d.ts +109 -0
  41. package/dist/protocols/openai-compatible-chat.js +19 -0
  42. package/dist/protocols/openai-compatible-responses.d.ts +172 -0
  43. package/dist/protocols/openai-compatible-responses.js +18 -0
  44. package/dist/protocols/openai-images.d.ts +32 -0
  45. package/dist/protocols/openai-images.js +183 -0
  46. package/dist/protocols/openai-responses.d.ts +1389 -0
  47. package/dist/protocols/openai-responses.js +260 -0
  48. package/dist/protocols/shared.d.ts +193 -0
  49. package/dist/protocols/shared.js +290 -0
  50. package/dist/protocols/utils/bedrock-auth.d.ts +60 -0
  51. package/dist/protocols/utils/bedrock-auth.js +85 -0
  52. package/dist/protocols/utils/bedrock-cache.d.ts +19 -0
  53. package/dist/protocols/utils/bedrock-cache.js +49 -0
  54. package/dist/protocols/utils/bedrock-media.d.ts +55 -0
  55. package/dist/protocols/utils/bedrock-media.js +73 -0
  56. package/dist/protocols/utils/cache.d.ts +6 -0
  57. package/dist/protocols/utils/cache.js +5 -0
  58. package/dist/protocols/utils/gemini-tool-schema.d.ts +2 -0
  59. package/dist/protocols/utils/gemini-tool-schema.js +103 -0
  60. package/dist/protocols/utils/image-input.d.ts +21 -0
  61. package/dist/protocols/utils/image-input.js +20 -0
  62. package/dist/protocols/utils/lifecycle.d.ts +24 -0
  63. package/dist/protocols/utils/lifecycle.js +72 -0
  64. package/dist/protocols/utils/meta-image.d.ts +2 -0
  65. package/dist/protocols/utils/meta-image.js +13 -0
  66. package/dist/protocols/utils/open-responses-options.d.ts +56 -0
  67. package/dist/protocols/utils/open-responses-options.js +61 -0
  68. package/dist/protocols/utils/openai-image.d.ts +5 -0
  69. package/dist/protocols/utils/openai-image.js +18 -0
  70. package/dist/protocols/utils/openai-options.d.ts +16 -0
  71. package/dist/protocols/utils/openai-options.js +14 -0
  72. package/dist/protocols/utils/partial-json-options.d.ts +62 -0
  73. package/dist/protocols/utils/partial-json-options.js +52 -0
  74. package/dist/protocols/utils/partial-json.d.ts +8 -0
  75. package/dist/protocols/utils/partial-json.js +279 -0
  76. package/dist/protocols/utils/responses-checkpoint.d.ts +4 -0
  77. package/dist/protocols/utils/responses-checkpoint.js +107 -0
  78. package/dist/protocols/utils/responses-compaction.d.ts +4 -0
  79. package/dist/protocols/utils/responses-compaction.js +129 -0
  80. package/dist/protocols/utils/responses-hosted-tools.d.ts +26 -0
  81. package/dist/protocols/utils/responses-hosted-tools.js +32 -0
  82. package/dist/protocols/utils/tool-schema.d.ts +8 -0
  83. package/dist/protocols/utils/tool-schema.js +54 -0
  84. package/dist/protocols/utils/tool-stream.d.ts +710 -0
  85. package/dist/protocols/utils/tool-stream.js +155 -0
  86. package/dist/protocols/xai-images.d.ts +26 -0
  87. package/dist/protocols/xai-images.js +106 -0
  88. package/dist/protocols/xai-responses.d.ts +250 -0
  89. package/dist/protocols/xai-responses.js +81 -0
  90. package/dist/protocols/zai-images.d.ts +22 -0
  91. package/dist/protocols/zai-images.js +79 -0
  92. package/dist/protocols.d.ts +1 -0
  93. package/dist/protocols.js +1 -0
  94. package/dist/provider-error.d.ts +15 -0
  95. package/dist/provider-error.js +125 -0
  96. package/dist/provider-package.d.ts +11 -0
  97. package/dist/provider-package.js +1 -0
  98. package/dist/provider.d.ts +23 -0
  99. package/dist/provider.js +2 -0
  100. package/dist/providers/amazon-bedrock/mantle/chat.d.ts +2 -0
  101. package/dist/providers/amazon-bedrock/mantle/chat.js +1 -0
  102. package/dist/providers/amazon-bedrock/mantle/responses.d.ts +2 -0
  103. package/dist/providers/amazon-bedrock/mantle/responses.js +1 -0
  104. package/dist/providers/amazon-bedrock/mantle.d.ts +2 -0
  105. package/dist/providers/amazon-bedrock/mantle.js +1 -0
  106. package/dist/providers/amazon-bedrock-mantle.d.ts +371 -0
  107. package/dist/providers/amazon-bedrock-mantle.js +76 -0
  108. package/dist/providers/amazon-bedrock.d.ts +173 -0
  109. package/dist/providers/amazon-bedrock.js +41 -0
  110. package/dist/providers/anthropic-compatible.d.ts +304 -0
  111. package/dist/providers/anthropic-compatible.js +44 -0
  112. package/dist/providers/anthropic.d.ts +302 -0
  113. package/dist/providers/anthropic.js +39 -0
  114. package/dist/providers/azure/chat.d.ts +2 -0
  115. package/dist/providers/azure/chat.js +1 -0
  116. package/dist/providers/azure/responses.d.ts +2 -0
  117. package/dist/providers/azure/responses.js +1 -0
  118. package/dist/providers/azure.d.ts +599 -0
  119. package/dist/providers/azure.js +115 -0
  120. package/dist/providers/baseten.d.ts +229 -0
  121. package/dist/providers/baseten.js +38 -0
  122. package/dist/providers/cerebras.d.ts +228 -0
  123. package/dist/providers/cerebras.js +40 -0
  124. package/dist/providers/cloudflare-ai-gateway.d.ts +238 -0
  125. package/dist/providers/cloudflare-ai-gateway.js +59 -0
  126. package/dist/providers/cloudflare-workers-ai.d.ts +232 -0
  127. package/dist/providers/cloudflare-workers-ai.js +45 -0
  128. package/dist/providers/deepinfra.d.ts +228 -0
  129. package/dist/providers/deepinfra.js +43 -0
  130. package/dist/providers/deepseek.d.ts +229 -0
  131. package/dist/providers/deepseek.js +41 -0
  132. package/dist/providers/fireworks.d.ts +229 -0
  133. package/dist/providers/fireworks.js +38 -0
  134. package/dist/providers/google-vertex/chat.d.ts +2 -0
  135. package/dist/providers/google-vertex/chat.js +1 -0
  136. package/dist/providers/google-vertex/gemini.d.ts +2 -0
  137. package/dist/providers/google-vertex/gemini.js +1 -0
  138. package/dist/providers/google-vertex/messages.d.ts +2 -0
  139. package/dist/providers/google-vertex/messages.js +1 -0
  140. package/dist/providers/google-vertex/responses.d.ts +2 -0
  141. package/dist/providers/google-vertex/responses.js +1 -0
  142. package/dist/providers/google-vertex-chat.d.ts +133 -0
  143. package/dist/providers/google-vertex-chat.js +55 -0
  144. package/dist/providers/google-vertex-messages.d.ts +301 -0
  145. package/dist/providers/google-vertex-messages.js +75 -0
  146. package/dist/providers/google-vertex-responses.d.ts +198 -0
  147. package/dist/providers/google-vertex-responses.js +56 -0
  148. package/dist/providers/google-vertex-shared.d.ts +22 -0
  149. package/dist/providers/google-vertex-shared.js +61 -0
  150. package/dist/providers/google-vertex.d.ts +120 -0
  151. package/dist/providers/google-vertex.js +92 -0
  152. package/dist/providers/google.d.ts +115 -0
  153. package/dist/providers/google.js +42 -0
  154. package/dist/providers/groq.d.ts +315 -0
  155. package/dist/providers/groq.js +81 -0
  156. package/dist/providers/index.d.ts +28 -0
  157. package/dist/providers/index.js +28 -0
  158. package/dist/providers/meta/chat.d.ts +2 -0
  159. package/dist/providers/meta/chat.js +1 -0
  160. package/dist/providers/meta/messages.d.ts +2 -0
  161. package/dist/providers/meta/messages.js +1 -0
  162. package/dist/providers/meta/responses.d.ts +2 -0
  163. package/dist/providers/meta/responses.js +1 -0
  164. package/dist/providers/meta.d.ts +631 -0
  165. package/dist/providers/meta.js +113 -0
  166. package/dist/providers/minimax/chat.d.ts +4 -0
  167. package/dist/providers/minimax/chat.js +8 -0
  168. package/dist/providers/minimax/messages.d.ts +1 -0
  169. package/dist/providers/minimax/messages.js +1 -0
  170. package/dist/providers/minimax/responses.d.ts +4 -0
  171. package/dist/providers/minimax/responses.js +8 -0
  172. package/dist/providers/minimax.d.ts +593 -0
  173. package/dist/providers/minimax.js +89 -0
  174. package/dist/providers/mistral.d.ts +208 -0
  175. package/dist/providers/mistral.js +28 -0
  176. package/dist/providers/open-responses-options.d.ts +6 -0
  177. package/dist/providers/open-responses-options.js +1 -0
  178. package/dist/providers/openai/chat.d.ts +2 -0
  179. package/dist/providers/openai/chat.js +1 -0
  180. package/dist/providers/openai/responses.d.ts +2 -0
  181. package/dist/providers/openai/responses.js +1 -0
  182. package/dist/providers/openai-compatible/responses.d.ts +1 -0
  183. package/dist/providers/openai-compatible/responses.js +1 -0
  184. package/dist/providers/openai-compatible-responses.d.ts +196 -0
  185. package/dist/providers/openai-compatible-responses.js +32 -0
  186. package/dist/providers/openai-compatible.d.ts +131 -0
  187. package/dist/providers/openai-compatible.js +33 -0
  188. package/dist/providers/openai-options.d.ts +26 -0
  189. package/dist/providers/openai-options.js +41 -0
  190. package/dist/providers/openai.d.ts +405 -0
  191. package/dist/providers/openai.js +82 -0
  192. package/dist/providers/openrouter.d.ts +564 -0
  193. package/dist/providers/openrouter.js +114 -0
  194. package/dist/providers/togetherai.d.ts +228 -0
  195. package/dist/providers/togetherai.js +40 -0
  196. package/dist/providers/xai.d.ts +164 -0
  197. package/dist/providers/xai.js +84 -0
  198. package/dist/providers/zai.d.ts +24 -0
  199. package/dist/providers/zai.js +21 -0
  200. package/dist/providers.d.ts +1 -0
  201. package/dist/providers.js +1 -0
  202. package/dist/route/auth-options.d.ts +34 -0
  203. package/dist/route/auth-options.js +14 -0
  204. package/dist/route/auth.d.ts +51 -0
  205. package/dist/route/auth.js +87 -0
  206. package/dist/route/client.d.ts +430 -0
  207. package/dist/route/client.js +304 -0
  208. package/dist/route/endpoint.d.ts +28 -0
  209. package/dist/route/endpoint.js +21 -0
  210. package/dist/route/executor.d.ts +27 -0
  211. package/dist/route/executor.js +183 -0
  212. package/dist/route/framing.d.ts +29 -0
  213. package/dist/route/framing.js +14 -0
  214. package/dist/route/index.d.ts +16 -0
  215. package/dist/route/index.js +9 -0
  216. package/dist/route/protocol.d.ts +76 -0
  217. package/dist/route/protocol.js +16 -0
  218. package/dist/route/transport/http.d.ts +34 -0
  219. package/dist/route/transport/http.js +68 -0
  220. package/dist/route/transport/index.d.ts +41 -0
  221. package/dist/route/transport/index.js +4 -0
  222. package/dist/route/transport/websocket-channel.d.ts +57 -0
  223. package/dist/route/transport/websocket-channel.js +1 -0
  224. package/dist/route/transport/websocket.d.ts +56 -0
  225. package/dist/route/transport/websocket.js +366 -0
  226. package/dist/route.d.ts +1 -0
  227. package/dist/route.js +1 -0
  228. package/dist/schema/errors.d.ts +158 -0
  229. package/dist/schema/errors.js +120 -0
  230. package/dist/schema/events.d.ts +8123 -0
  231. package/dist/schema/events.js +550 -0
  232. package/dist/schema/ids.d.ts +17 -0
  233. package/dist/schema/ids.js +10 -0
  234. package/dist/schema/index.d.ts +5 -0
  235. package/dist/schema/index.js +5 -0
  236. package/dist/schema/messages.d.ts +646 -0
  237. package/dist/schema/messages.js +301 -0
  238. package/dist/schema/options.d.ts +157 -0
  239. package/dist/schema/options.js +187 -0
  240. package/dist/testing.d.ts +1693 -0
  241. package/dist/testing.js +129 -0
  242. package/dist/tool-history.d.ts +2 -0
  243. package/dist/tool-history.js +84 -0
  244. package/dist/tool-runtime.d.ts +15 -0
  245. package/dist/tool-runtime.js +62 -0
  246. package/dist/tool.d.ts +136 -0
  247. package/dist/tool.js +66 -0
  248. package/dist/utils/record.d.ts +2 -0
  249. package/dist/utils/record.js +2 -0
  250. package/dist/utils/sanitize.d.ts +1 -0
  251. package/dist/utils/sanitize.js +12 -0
  252. package/package.json +48 -0
@@ -0,0 +1,624 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Auth } from "../route/auth.js";
3
+ import { Route } from "../route/client.js";
4
+ import { Endpoint } from "../route/endpoint.js";
5
+ import { Framing } from "../route/framing.js";
6
+ import { Protocol } from "../route/protocol.js";
7
+ import { HttpTransport } from "../route/transport/index.js";
8
+ import { AIError, InvalidProviderOutputError, LLMEvent, ProviderInternalError, UnknownProviderError, Usage, } from "../schema/index.js";
9
+ import { classifyProviderFailure } from "../provider-error.js";
10
+ import { JsonObject, optionalArray, optionalNull, ProviderShared } from "./shared.js";
11
+ import { Lifecycle } from "./utils/lifecycle.js";
12
+ import { ToolStream } from "./utils/tool-stream.js";
13
+ const ADAPTER = "mistral-chat";
14
+ const DONE = "[DONE]";
15
+ const TOOL_ID = /^[A-Za-z0-9]{9}$/;
16
+ export const DEFAULT_BASE_URL = "https://api.mistral.ai/v1";
17
+ export const PATH = "/chat/completions";
18
+ const MistralTextContent = Schema.Struct({
19
+ type: Schema.Literal("text"),
20
+ text: Schema.String,
21
+ });
22
+ const MistralThinkingUnit = Schema.StructWithRest(Schema.Struct({
23
+ type: Schema.optional(Schema.String),
24
+ text: Schema.optional(Schema.String),
25
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
26
+ const MistralThinkingContent = Schema.StructWithRest(Schema.Struct({
27
+ type: Schema.Literal("thinking"),
28
+ thinking: Schema.Array(MistralThinkingUnit),
29
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
30
+ const isMistralThinkingContent = Schema.is(MistralThinkingContent);
31
+ const MistralUserContent = Schema.Union([
32
+ MistralTextContent,
33
+ Schema.Struct({ type: Schema.Literal("image_url"), image_url: Schema.String }),
34
+ Schema.Struct({ type: Schema.Literal("document_url"), document_url: Schema.String }),
35
+ ]);
36
+ const MistralAssistantToolCall = Schema.Struct({
37
+ id: Schema.String,
38
+ type: Schema.Literal("function"),
39
+ function: Schema.Struct({ name: Schema.String, arguments: Schema.String }),
40
+ });
41
+ const MistralMessage = Schema.Union([
42
+ Schema.Struct({ role: Schema.Literal("system"), content: Schema.String }),
43
+ Schema.Struct({
44
+ role: Schema.Literal("user"),
45
+ content: Schema.Union([Schema.String, Schema.Array(MistralUserContent)]),
46
+ }),
47
+ Schema.Struct({
48
+ role: Schema.Literal("assistant"),
49
+ content: Schema.Union([Schema.String, Schema.Array(Schema.Union([MistralTextContent, MistralThinkingContent]))]),
50
+ tool_calls: optionalArray(MistralAssistantToolCall),
51
+ prefix: Schema.optional(Schema.Literal(true)),
52
+ }),
53
+ Schema.Struct({
54
+ role: Schema.Literal("tool"),
55
+ tool_call_id: Schema.String,
56
+ name: Schema.String,
57
+ content: Schema.Union([Schema.String, Schema.Array(MistralUserContent)]),
58
+ }),
59
+ ]).pipe(Schema.toTaggedUnion("role"));
60
+ const MistralTool = Schema.Struct({
61
+ type: Schema.Literal("function"),
62
+ function: Schema.Struct({
63
+ name: Schema.String,
64
+ description: Schema.String,
65
+ parameters: JsonObject,
66
+ strict: Schema.Literal(false),
67
+ }),
68
+ });
69
+ const MistralOptions = Schema.Struct({
70
+ safePrompt: Schema.optional(Schema.Boolean),
71
+ documentImageLimit: Schema.optional(Schema.Number),
72
+ documentPageLimit: Schema.optional(Schema.Number),
73
+ parallelToolCalls: Schema.optional(Schema.Boolean),
74
+ reasoningEffort: Schema.optional(Schema.String),
75
+ promptMode: Schema.optional(Schema.Literal("reasoning")),
76
+ promptCacheKey: Schema.optional(Schema.String),
77
+ });
78
+ const MistralBody = Schema.Struct({
79
+ model: Schema.String,
80
+ messages: Schema.Array(MistralMessage),
81
+ tools: optionalArray(MistralTool),
82
+ tool_choice: Schema.optional(Schema.Union([
83
+ Schema.Literals(["auto", "none", "any"]),
84
+ Schema.Struct({ type: Schema.Literal("function"), function: Schema.Struct({ name: Schema.String }) }),
85
+ ])),
86
+ stream: Schema.Literal(true),
87
+ max_tokens: Schema.optional(Schema.Number),
88
+ random_seed: Schema.optional(Schema.Number),
89
+ temperature: Schema.optional(Schema.Number),
90
+ top_p: Schema.optional(Schema.Number),
91
+ frequency_penalty: Schema.optional(Schema.Number),
92
+ presence_penalty: Schema.optional(Schema.Number),
93
+ stop: optionalArray(Schema.String),
94
+ prompt_cache_key: Schema.optional(Schema.String),
95
+ safe_prompt: Schema.optional(Schema.Boolean),
96
+ document_image_limit: Schema.optional(Schema.Number),
97
+ document_page_limit: Schema.optional(Schema.Number),
98
+ parallel_tool_calls: Schema.optional(Schema.Boolean),
99
+ reasoning_effort: Schema.optional(Schema.String),
100
+ prompt_mode: Schema.optional(Schema.Literal("reasoning")),
101
+ });
102
+ const MistralUsageDetails = Schema.StructWithRest(Schema.Struct({ cached_tokens: optionalNull(Schema.Number) }), [
103
+ Schema.Record(Schema.String, Schema.Unknown),
104
+ ]);
105
+ const MistralUsage = Schema.StructWithRest(Schema.Struct({
106
+ prompt_tokens: optionalNull(Schema.Number),
107
+ completion_tokens: optionalNull(Schema.Number),
108
+ total_tokens: optionalNull(Schema.Number),
109
+ num_cached_tokens: optionalNull(Schema.Number),
110
+ prompt_token_details: optionalNull(MistralUsageDetails),
111
+ prompt_tokens_details: optionalNull(MistralUsageDetails),
112
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
113
+ const MistralOutputContent = Schema.StructWithRest(Schema.Struct({
114
+ type: Schema.String,
115
+ text: optionalNull(Schema.String),
116
+ thinking: optionalNull(Schema.Unknown),
117
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
118
+ const MistralToolDelta = Schema.Struct({
119
+ index: optionalNull(Schema.Number),
120
+ id: optionalNull(Schema.String),
121
+ function: optionalNull(Schema.Struct({
122
+ name: optionalNull(Schema.String),
123
+ arguments: optionalNull(Schema.Union([Schema.String, JsonObject])),
124
+ })),
125
+ });
126
+ const MistralChoice = Schema.StructWithRest(Schema.Struct({
127
+ delta: optionalNull(Schema.StructWithRest(Schema.Struct({
128
+ content: optionalNull(Schema.Union([Schema.String, Schema.Array(MistralOutputContent)])),
129
+ tool_calls: optionalNull(Schema.Array(MistralToolDelta)),
130
+ }), [Schema.Record(Schema.String, Schema.Unknown)])),
131
+ finish_reason: optionalNull(Schema.String),
132
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
133
+ const MistralError = Schema.StructWithRest(Schema.Struct({
134
+ message: Schema.String,
135
+ code: optionalNull(Schema.Union([Schema.String, Schema.Number])),
136
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
137
+ const MistralEvent = Schema.StructWithRest(Schema.Struct({
138
+ choices: optionalNull(Schema.Array(MistralChoice)),
139
+ usage: optionalNull(MistralUsage),
140
+ error: optionalNull(MistralError),
141
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
142
+ const MistralStreamEvent = Schema.Union([Schema.Literal(DONE), Protocol.jsonEvent(MistralEvent)]);
143
+ const hashID = (value) => {
144
+ const hash = (seed) => {
145
+ let result = seed;
146
+ for (const char of value)
147
+ result = Math.imul(result ^ char.charCodeAt(0), 16777619);
148
+ return (result >>> 0).toString(36);
149
+ };
150
+ return `${hash(2166136261).padStart(7, "0")}${hash(2246822519).padStart(7, "0")}`.slice(-9);
151
+ };
152
+ const toolIDNormalizer = (request) => {
153
+ const ids = request.messages.flatMap((message) => message.content.flatMap((part) => (part.type === "tool-call" || part.type === "tool-result" ? [part.id] : [])));
154
+ const used = new Set(ids.filter((id) => TOOL_ID.test(id)));
155
+ const normalized = new Map();
156
+ return (id) => {
157
+ if (TOOL_ID.test(id))
158
+ return id;
159
+ const previous = normalized.get(id);
160
+ if (previous)
161
+ return previous;
162
+ let attempt = 0;
163
+ let candidate = hashID(id);
164
+ while (used.has(candidate))
165
+ candidate = hashID(`${id}:${++attempt}`);
166
+ used.add(candidate);
167
+ normalized.set(id, candidate);
168
+ return candidate;
169
+ };
170
+ };
171
+ const lowerMedia = Effect.fn("MistralChat.lowerMedia")(function* (part) {
172
+ const media = ProviderShared.normalizeMedia(part);
173
+ const url = typeof part.data === "string" && /^(?:https?:|data:)/.test(part.data) ? part.data : media.dataUrl;
174
+ if (media.mime.startsWith("image/"))
175
+ return { type: "image_url", image_url: url };
176
+ if (media.mime === "application/pdf")
177
+ return { type: "document_url", document_url: url };
178
+ return yield* ProviderShared.invalidRequest(`Mistral Chat does not support media type ${part.mediaType}`);
179
+ });
180
+ const lowerUser = Effect.fn("MistralChat.lowerUser")(function* (message) {
181
+ const content = [];
182
+ for (const part of message.content) {
183
+ if (part.type === "text") {
184
+ content.push({ type: "text", text: part.text });
185
+ continue;
186
+ }
187
+ if (part.type === "media") {
188
+ content.push(yield* lowerMedia(part));
189
+ continue;
190
+ }
191
+ return yield* ProviderShared.unsupportedContent("Mistral Chat", "user", ["text", "media"]);
192
+ }
193
+ if (content.every((part) => part.type === "text"))
194
+ return { role: "user", content: content.map((part) => part.text).join("") };
195
+ return { role: "user", content };
196
+ });
197
+ const lowerToolCall = (part, normalizeID) => ({
198
+ id: normalizeID(part.id),
199
+ type: "function",
200
+ function: { name: part.name, arguments: ProviderShared.encodeJson(part.input) },
201
+ });
202
+ const lowerAssistant = Effect.fn("MistralChat.lowerAssistant")(function* (message, normalizeID, prefix) {
203
+ const structured = message.content.some((part) => part.type === "reasoning" && isMistralThinkingContent(part.providerMetadata?.mistral?.thinking));
204
+ const content = [];
205
+ const text = [];
206
+ const toolCalls = [];
207
+ for (const part of message.content) {
208
+ if (part.type === "text") {
209
+ if (structured)
210
+ content.push({ type: "text", text: part.text });
211
+ else
212
+ text.push(part.text);
213
+ continue;
214
+ }
215
+ if (part.type === "reasoning") {
216
+ const native = part.providerMetadata?.mistral?.thinking;
217
+ if (structured && isMistralThinkingContent(native))
218
+ content.push(native);
219
+ else if (structured)
220
+ content.push({ type: "text", text: part.text });
221
+ else
222
+ text.push(part.text);
223
+ continue;
224
+ }
225
+ if (part.type === "tool-call") {
226
+ toolCalls.push(lowerToolCall(part, normalizeID));
227
+ continue;
228
+ }
229
+ return yield* ProviderShared.unsupportedContent("Mistral Chat", "assistant", ["text", "reasoning", "tool-call"]);
230
+ }
231
+ return {
232
+ role: "assistant",
233
+ content: structured ? content : text.join(""),
234
+ ...(toolCalls.length > 0 ? { tool_calls: toolCalls } : {}),
235
+ ...(prefix ? { prefix: true } : {}),
236
+ };
237
+ });
238
+ const lowerToolResults = Effect.fn("MistralChat.lowerToolResults")(function* (message, normalizeID) {
239
+ const output = [];
240
+ for (const part of message.content) {
241
+ if (part.type !== "tool-result")
242
+ return yield* ProviderShared.unsupportedContent("Mistral Chat", "tool", ["tool-result"]);
243
+ if (part.result.type !== "content") {
244
+ output.push({
245
+ role: "tool",
246
+ tool_call_id: normalizeID(part.id),
247
+ name: part.name,
248
+ content: ProviderShared.toolResultText(part),
249
+ });
250
+ continue;
251
+ }
252
+ const content = [];
253
+ for (const item of part.result.value) {
254
+ if (item.type === "text") {
255
+ content.push({ type: "text", text: item.text });
256
+ continue;
257
+ }
258
+ content.push(yield* lowerMedia({ type: "media", mediaType: item.mime, data: item.uri, filename: item.name }));
259
+ }
260
+ output.push({
261
+ role: "tool",
262
+ tool_call_id: normalizeID(part.id),
263
+ name: part.name,
264
+ content: content.some((item) => item.type !== "text")
265
+ ? content
266
+ : content.map((item) => (item.type === "text" ? item.text : "")).join(""),
267
+ });
268
+ }
269
+ return output;
270
+ });
271
+ const lowerMessages = Effect.fn("MistralChat.lowerMessages")(function* (request) {
272
+ const normalizeID = toolIDNormalizer(request);
273
+ const messages = request.system.length === 0 ? [] : [{ role: "system", content: ProviderShared.joinText(request.system) }];
274
+ for (const message of request.messages) {
275
+ if (message.role === "system") {
276
+ const update = yield* ProviderShared.wrappedSystemUpdate("Mistral Chat", message);
277
+ messages.push({
278
+ role: "user",
279
+ content: update.text,
280
+ });
281
+ continue;
282
+ }
283
+ if (message.role === "user") {
284
+ messages.push(yield* lowerUser(message));
285
+ continue;
286
+ }
287
+ if (message.role === "assistant") {
288
+ const hasToolCalls = message.content.some((part) => part.type === "tool-call");
289
+ const hasNativeThinking = message.content.some((part) => part.type === "reasoning" && isMistralThinkingContent(part.providerMetadata?.mistral?.thinking));
290
+ const text = message.content
291
+ .flatMap((part) => (part.type === "text" || part.type === "reasoning" ? [part.text] : []))
292
+ .join("");
293
+ if (!hasToolCalls && !hasNativeThinking && text.trim() === "")
294
+ continue;
295
+ messages.push(yield* lowerAssistant(message, normalizeID, !hasToolCalls && message === request.messages.at(-1)));
296
+ continue;
297
+ }
298
+ messages.push(...(yield* lowerToolResults(message, normalizeID)));
299
+ }
300
+ return messages;
301
+ });
302
+ const lowerTool = (tool) => ({
303
+ type: "function",
304
+ function: { name: tool.name, description: tool.description, parameters: tool.inputSchema, strict: false },
305
+ });
306
+ export const fromRequest = Effect.fn("MistralChat.fromRequest")(function* (request) {
307
+ const options = yield* ProviderShared.validateWith(Schema.decodeUnknownEffect(MistralOptions))(request.providerOptions ?? {});
308
+ const selected = request.toolChoice?.type === "tool" ? request.toolChoice.name : undefined;
309
+ if (request.toolChoice?.type === "tool" && !selected)
310
+ return yield* ProviderShared.invalidRequest("Mistral Chat tool choice requires a tool name");
311
+ if (options.reasoningEffort !== undefined && options.promptMode !== undefined)
312
+ return yield* ProviderShared.invalidRequest("Mistral Chat reasoningEffort and promptMode provider options are mutually exclusive");
313
+ const toolChoice = request.toolChoice
314
+ ? yield* ProviderShared.matchToolChoice("Mistral Chat", request.toolChoice, {
315
+ auto: () => "auto",
316
+ none: () => "none",
317
+ required: () => "any",
318
+ tool: (name) => ({ type: "function", function: { name } }),
319
+ })
320
+ : undefined;
321
+ const flattened = ProviderShared.flattenToolRequest(request);
322
+ return {
323
+ model: request.model.id,
324
+ messages: yield* lowerMessages(flattened.request),
325
+ tools: flattened.tools.length > 0 ? flattened.tools.map(lowerTool) : undefined,
326
+ tool_choice: toolChoice,
327
+ stream: true,
328
+ max_tokens: request.generation?.maxTokens,
329
+ random_seed: request.generation?.seed,
330
+ temperature: request.generation?.temperature,
331
+ top_p: request.generation?.topP,
332
+ frequency_penalty: request.generation?.frequencyPenalty,
333
+ presence_penalty: request.generation?.presencePenalty,
334
+ stop: request.generation?.stop,
335
+ prompt_cache_key: request.cache === "none" ? undefined : (options.promptCacheKey ?? request.promptCacheKey),
336
+ safe_prompt: options.safePrompt,
337
+ document_image_limit: options.documentImageLimit,
338
+ document_page_limit: options.documentPageLimit,
339
+ parallel_tool_calls: options.parallelToolCalls ?? (request.toolChoice?.disableParallelToolUse === true ? false : undefined),
340
+ reasoning_effort: options.reasoningEffort,
341
+ prompt_mode: options.promptMode,
342
+ };
343
+ });
344
+ const mapUsage = (usage) => {
345
+ if (!usage)
346
+ return undefined;
347
+ const input = usage.prompt_tokens ?? undefined;
348
+ const reported = usage.num_cached_tokens ??
349
+ usage.prompt_tokens_details?.cached_tokens ??
350
+ usage.prompt_token_details?.cached_tokens ??
351
+ undefined;
352
+ const cached = input === undefined || reported === undefined ? undefined : Math.max(0, Math.min(input, reported));
353
+ const output = usage.completion_tokens ?? undefined;
354
+ return new Usage({
355
+ inputTokens: input,
356
+ outputTokens: output,
357
+ nonCachedInputTokens: ProviderShared.subtractTokens(input, cached),
358
+ cacheReadInputTokens: cached,
359
+ totalTokens: ProviderShared.totalTokens(input, output, usage.total_tokens ?? undefined),
360
+ providerMetadata: { mistral: usage },
361
+ });
362
+ };
363
+ const mapFinishReason = (reason) => {
364
+ switch (reason) {
365
+ case "stop":
366
+ return "stop";
367
+ case "length":
368
+ case "model_length":
369
+ return "length";
370
+ case "tool_calls":
371
+ return "tool-calls";
372
+ case "content_filter":
373
+ return "content-filter";
374
+ case "error":
375
+ case "network_error":
376
+ return "error";
377
+ default:
378
+ return "unknown";
379
+ }
380
+ };
381
+ const thinkingUnits = (value) => {
382
+ if (typeof value === "string")
383
+ return [{ type: "text", text: value }];
384
+ if (!Array.isArray(value))
385
+ return [];
386
+ return value.filter(Schema.is(MistralThinkingUnit));
387
+ };
388
+ const thinkingText = (thinking) => thinking.flatMap((unit) => (typeof unit.text === "string" ? [unit.text] : [])).join("");
389
+ const thinkingMetadata = (thinking) => ({ mistral: { thinking } });
390
+ const closeActive = (state, events) => {
391
+ if (!state.active)
392
+ return state;
393
+ const lifecycle = state.active.type === "text"
394
+ ? Lifecycle.textEnd(state.lifecycle, events, state.active.id)
395
+ : Lifecycle.reasoningEnd(state.lifecycle, events, state.active.id, thinkingMetadata(state.active.thinking ?? { type: "thinking", thinking: [] }), thinkingText(state.active.thinking?.thinking ?? []));
396
+ return { ...state, lifecycle, active: undefined };
397
+ };
398
+ const appendText = (state, events, text) => {
399
+ if (text.length === 0)
400
+ return state;
401
+ const current = state.active?.type === "text" ? state : closeActive(state, events);
402
+ const active = current.active ?? { type: "text", id: `text-${current.nextContent}` };
403
+ return {
404
+ ...current,
405
+ lifecycle: Lifecycle.textDelta(current.lifecycle, events, active.id, text),
406
+ active,
407
+ nextContent: current.active ? current.nextContent : current.nextContent + 1,
408
+ };
409
+ };
410
+ const appendThinking = (state, events, part) => {
411
+ const current = state.active?.type === "reasoning" ? state : closeActive(state, events);
412
+ const units = thinkingUnits(part.thinking);
413
+ const active = current.active ?? { type: "reasoning", id: `reasoning-${current.nextContent}` };
414
+ const thinking = {
415
+ ...active.thinking,
416
+ ...part,
417
+ type: "thinking",
418
+ thinking: [...(active.thinking?.thinking ?? []), ...units],
419
+ };
420
+ const text = thinkingText(units);
421
+ return {
422
+ ...current,
423
+ lifecycle: text.length > 0
424
+ ? Lifecycle.reasoningDelta(current.lifecycle, events, active.id, text, thinkingMetadata(thinking))
425
+ : Lifecycle.reasoningStart(current.lifecycle, events, active.id, thinkingMetadata(thinking)),
426
+ active: { ...active, thinking },
427
+ nextContent: current.active ? current.nextContent : current.nextContent + 1,
428
+ };
429
+ };
430
+ const appendContent = (state, events, content) => {
431
+ if (typeof content === "string")
432
+ return appendText(state, events, content);
433
+ return content.reduce((current, part) => {
434
+ if (part.type === "text")
435
+ return appendText(current, events, part.text ?? "");
436
+ if (part.type === "thinking")
437
+ return appendThinking(current, events, part);
438
+ return closeActive(current, events);
439
+ }, state);
440
+ };
441
+ const normalizeStreamToolID = (state, source) => {
442
+ if (TOOL_ID.test(source))
443
+ return { id: source, state: { ...state, usedToolIDs: new Set([...state.usedToolIDs, source]) } };
444
+ const previous = state.toolIDs.get(source);
445
+ if (previous)
446
+ return { id: previous, state };
447
+ let attempt = 0;
448
+ let id = hashID(source);
449
+ while (state.usedToolIDs.has(id))
450
+ id = hashID(`${source}:${++attempt}`);
451
+ return {
452
+ id,
453
+ state: {
454
+ ...state,
455
+ toolIDs: new Map([...state.toolIDs, [source, id]]),
456
+ usedToolIDs: new Set([...state.usedToolIDs, id]),
457
+ },
458
+ };
459
+ };
460
+ const toolText = (tool) => {
461
+ const value = tool.function?.arguments;
462
+ if (typeof value === "string")
463
+ return value;
464
+ return value === null || value === undefined ? "" : ProviderShared.encodeJson(value);
465
+ };
466
+ const appendTools = Effect.fn("MistralChat.appendTools")(function* (initial, events, deltas) {
467
+ if (deltas.length === 0)
468
+ return initial;
469
+ let state = closeActive(initial, events);
470
+ for (const [position, delta] of deltas.entries()) {
471
+ const wireID = delta.id?.trim() || undefined;
472
+ const providedID = wireID === "null" ? undefined : wireID;
473
+ const key = delta.index ??
474
+ (providedID
475
+ ? `id:${providedID}`
476
+ : deltas.length > 1
477
+ ? `position:${position}`
478
+ : (state.latestToolKey ?? `missing:${state.generatedTools}`));
479
+ const existing = state.tools[key];
480
+ const pending = state.pendingTools[key];
481
+ const source = providedID ?? `generated:${String(key)}`;
482
+ const normalized = existing || pending ? { id: existing?.id ?? pending?.id ?? "", state } : normalizeStreamToolID(state, source);
483
+ state = normalized.state;
484
+ const name = existing?.name ?? pending?.name ?? (delta.function?.name?.trim() || undefined);
485
+ const text = `${pending?.input ?? ""}${toolText(delta)}`;
486
+ if (!name) {
487
+ state = {
488
+ ...state,
489
+ pendingTools: { ...state.pendingTools, [key]: { id: normalized.id, input: text } },
490
+ latestToolKey: key,
491
+ generatedTools: state.generatedTools + (!providedID && !pending ? 1 : 0),
492
+ };
493
+ continue;
494
+ }
495
+ const result = ToolStream.appendOrStart(ADAPTER, state.tools, key, { id: normalized.id, name, text }, "Mistral Chat tool call delta is missing a name");
496
+ if (ToolStream.isError(result))
497
+ return yield* result;
498
+ if (result.events.length > 0)
499
+ state = { ...state, lifecycle: Lifecycle.stepStart(state.lifecycle, events) };
500
+ events.push(...result.events);
501
+ const pendingTools = { ...state.pendingTools };
502
+ delete pendingTools[key];
503
+ state = {
504
+ ...state,
505
+ tools: result.tools,
506
+ pendingTools,
507
+ latestToolKey: key,
508
+ generatedTools: state.generatedTools + (!providedID && !existing && !pending ? 1 : 0),
509
+ };
510
+ }
511
+ return state;
512
+ });
513
+ const hasLateContent = (event) => {
514
+ const delta = event.choices?.[0]?.delta;
515
+ if (typeof delta?.content === "string" && delta.content.length > 0)
516
+ return true;
517
+ if (Array.isArray(delta?.content) && delta.content.length > 0)
518
+ return true;
519
+ return (delta?.tool_calls ?? []).some((tool) => Boolean(tool.id) || Boolean(tool.function?.name) || tool.function?.arguments !== undefined);
520
+ };
521
+ const step = Effect.fn("MistralChat.step")(function* (state, event) {
522
+ if (event.error) {
523
+ const body = ProviderShared.encodeJson(event);
524
+ return yield* new AIError({
525
+ reason: classifyProviderFailure({
526
+ message: event.error.message,
527
+ status: typeof event.error.code === "number" ? event.error.code : undefined,
528
+ rawBody: body,
529
+ }),
530
+ });
531
+ }
532
+ const events = [];
533
+ const usage = mapUsage(event.usage) ?? state.usage;
534
+ if (state.finishReason) {
535
+ if (hasLateContent(event))
536
+ return yield* ProviderShared.eventError(ADAPTER, "Mistral Chat received content after the finish reason", ProviderShared.encodeJson(event));
537
+ return [{ ...state, usage }, events];
538
+ }
539
+ const choice = event.choices?.[0];
540
+ const withContent = choice?.delta?.content == null ? state : appendContent(state, events, choice.delta.content);
541
+ const withTools = yield* appendTools(withContent, events, choice?.delta?.tool_calls ?? []);
542
+ if (!choice?.finish_reason)
543
+ return [{ ...withTools, usage }, events];
544
+ const finishReason = {
545
+ normalized: mapFinishReason(choice.finish_reason),
546
+ raw: choice.finish_reason,
547
+ };
548
+ if (finishReason.normalized === "error") {
549
+ const details = {
550
+ message: `Mistral Chat stopped with ${finishReason.raw}`,
551
+ body: ProviderShared.encodeJson(event),
552
+ };
553
+ return yield* new AIError({
554
+ reason: finishReason.raw === "network_error" ? new ProviderInternalError(details) : new UnknownProviderError(details),
555
+ });
556
+ }
557
+ const incomplete = finishReason.normalized === "length" || finishReason.normalized === "content-filter";
558
+ if (!incomplete && Object.keys(withTools.pendingTools).length > 0)
559
+ return yield* ProviderShared.eventError(ADAPTER, "Mistral Chat tool call delta is missing a name", ProviderShared.encodeJson(event));
560
+ const finished = !incomplete && Object.keys(withTools.tools).length > 0
561
+ ? yield* ToolStream.finishAll(ADAPTER, withTools.tools)
562
+ : undefined;
563
+ return [
564
+ {
565
+ ...withTools,
566
+ tools: finished?.tools ?? withTools.tools,
567
+ completedTools: finished?.events ?? withTools.completedTools,
568
+ usage,
569
+ finishReason,
570
+ },
571
+ events,
572
+ ];
573
+ });
574
+ const finishEvents = Effect.fn("MistralChat.finishEvents")(function* (state) {
575
+ if (!state.finishReason)
576
+ return yield* new AIError({
577
+ reason: new InvalidProviderOutputError({
578
+ message: "Mistral Chat stream ended without finish_reason",
579
+ classification: "incomplete-stream",
580
+ route: ADAPTER,
581
+ }),
582
+ });
583
+ const events = [];
584
+ const closed = closeActive(state, events);
585
+ const lifecycle = closed.completedTools.length > 0 ? Lifecycle.stepStart(closed.lifecycle, events) : closed.lifecycle;
586
+ events.push(...closed.completedTools);
587
+ const reason = state.finishReason.normalized === "stop" && closed.completedTools.some(LLMEvent.is.toolCall)
588
+ ? { ...state.finishReason, normalized: "tool-calls" }
589
+ : state.finishReason;
590
+ Lifecycle.finish(lifecycle, events, { reason, usage: closed.usage });
591
+ return events;
592
+ });
593
+ export const protocol = Protocol.make({
594
+ id: ADAPTER,
595
+ body: { schema: MistralBody, from: fromRequest },
596
+ stream: {
597
+ event: MistralStreamEvent,
598
+ initial: () => ({
599
+ tools: ToolStream.empty(),
600
+ pendingTools: {},
601
+ toolIDs: new Map(),
602
+ usedToolIDs: new Set(),
603
+ completedTools: [],
604
+ generatedTools: 0,
605
+ lifecycle: Lifecycle.initial(),
606
+ nextContent: 0,
607
+ }),
608
+ step: (state, event) => (event === DONE ? Effect.succeed([state, []]) : step(state, event)),
609
+ terminal: (event) => event === DONE,
610
+ onHalt: finishEvents,
611
+ },
612
+ });
613
+ export const framing = Framing.sseWithDone;
614
+ export const httpTransport = HttpTransport.sseJson.with().with({ framing });
615
+ export const route = Route.make({
616
+ id: ADAPTER,
617
+ provider: "mistral",
618
+ providerMetadataKey: "mistral",
619
+ protocol,
620
+ endpoint: Endpoint.path(PATH, { baseURL: DEFAULT_BASE_URL }),
621
+ auth: Auth.none,
622
+ transport: httpTransport,
623
+ });
624
+ export * as MistralChat from "./mistral-chat.js";
@@ -0,0 +1,23 @@
1
+ import { Headers } from "effect/unstable/http";
2
+ import { HttpTransport, type Transport, type WebSocketChannelDriver } from "../route/transport/index.js";
3
+ export interface Options {
4
+ readonly id: string;
5
+ readonly name: string;
6
+ readonly rotateAfterMs?: number;
7
+ readonly enabled?: (url: string) => boolean;
8
+ readonly url?: (url: string) => string;
9
+ readonly headers?: (headers: Headers.Headers) => Headers.Headers;
10
+ }
11
+ export interface Prepared {
12
+ readonly http: HttpTransport.HttpPrepared<string>;
13
+ readonly channel?: {
14
+ readonly url: string;
15
+ readonly headers: Headers.Headers;
16
+ readonly rotateAfterMs?: number;
17
+ readonly driver: WebSocketChannelDriver;
18
+ };
19
+ }
20
+ export declare const transport: <Body>(options: Options) => Transport<Body, Prepared, string>;
21
+ export declare const OpenResponsesChannel: {
22
+ readonly transport: <Body>(options: Options) => Transport<Body, Prepared, string>;
23
+ };