@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,155 @@
1
+ import { Effect, Option } from "effect";
2
+ import { AIError, LLMEvent } from "../../schema/index.js";
3
+ import { eventError, parseToolInput } from "../shared.js";
4
+ import { parse } from "./partial-json.js";
5
+ const parsePartialInput = Option.liftThrowable(parse);
6
+ /** Create empty accumulator state for one provider stream. */
7
+ export const empty = () => ({});
8
+ const withTool = (tools, key, tool) => {
9
+ return { ...tools, [key]: tool };
10
+ };
11
+ const withoutTool = (tools, key) => {
12
+ const next = { ...tools };
13
+ delete next[key];
14
+ return next;
15
+ };
16
+ const inputStart = (tool) => LLMEvent.toolInputStart({
17
+ id: tool.id,
18
+ name: tool.name,
19
+ namespace: tool.namespace,
20
+ providerExecuted: tool.providerExecuted ? true : undefined,
21
+ providerMetadata: tool.providerMetadata,
22
+ });
23
+ const inputDelta = (tool, text) => LLMEvent.toolInputDelta({
24
+ id: tool.id,
25
+ name: tool.name,
26
+ namespace: tool.namespace,
27
+ text,
28
+ input: Option.getOrElse(parsePartialInput(tool.input), () => ({})),
29
+ });
30
+ const toolCall = (route, tool, inputOverride) => {
31
+ const raw = inputOverride ?? tool.input;
32
+ return parseToolInput(route, tool.name, raw).pipe(Effect.catch((error) => tool.providerExecuted
33
+ ? Effect.fail(error)
34
+ : Effect.succeed(Option.getOrElse(Option.map(parsePartialInput(raw), (input) => input ?? {}), () => ({})))), Effect.map((input) => LLMEvent.toolCall({
35
+ id: tool.id,
36
+ name: tool.name,
37
+ namespace: tool.namespace,
38
+ input,
39
+ providerExecuted: tool.providerExecuted ? true : undefined,
40
+ providerMetadata: tool.providerMetadata,
41
+ })));
42
+ };
43
+ const finishEvents = (tool, event) => [
44
+ LLMEvent.toolInputEnd({
45
+ id: tool.id,
46
+ name: tool.name,
47
+ namespace: tool.namespace,
48
+ providerMetadata: tool.providerMetadata,
49
+ }),
50
+ event,
51
+ ];
52
+ /** Store the updated tool and produce the optional public delta event. */
53
+ const appendTool = (tools, key, tool, text) => {
54
+ const events = [];
55
+ if (!tools[key])
56
+ events.push(inputStart(tool));
57
+ if (text.length > 0)
58
+ events.push(inputDelta(tool, text));
59
+ return {
60
+ tools: withTool(tools, key, tool),
61
+ tool,
62
+ events,
63
+ };
64
+ };
65
+ export const isError = (result) => result instanceof AIError;
66
+ /**
67
+ * Register a tool call whose start event arrived before any argument deltas.
68
+ * Used by Anthropic `content_block_start`, Bedrock `contentBlockStart`, and
69
+ * OpenAI Responses `response.output_item.added`.
70
+ */
71
+ export const start = (tools, key, tool) => withTool(tools, key, { ...tool, input: tool.input ?? "" });
72
+ /**
73
+ * Append a streamed argument delta, starting the tool if this provider encodes
74
+ * identity on the first delta instead of a separate start event. OpenAI Chat has
75
+ * this shape: `tool_calls[].index` is the stream key, and `id` / `name` may only
76
+ * appear on the first delta for that index.
77
+ */
78
+ export const appendOrStart = (route, tools, key, delta, missingToolMessage) => {
79
+ const current = tools[key];
80
+ const id = current?.id ?? delta.id;
81
+ const name = current?.name ?? delta.name;
82
+ if (!id || !name)
83
+ return eventError(route, missingToolMessage);
84
+ const tool = {
85
+ id,
86
+ name,
87
+ namespace: current?.namespace,
88
+ input: `${current?.input ?? ""}${delta.text}`,
89
+ providerExecuted: current?.providerExecuted,
90
+ providerMetadata: current?.providerMetadata,
91
+ };
92
+ if (current && delta.text.length === 0 && current.id === id && current.name === name)
93
+ return { tools, tool: current, events: [] };
94
+ return appendTool(tools, key, tool, delta.text);
95
+ };
96
+ /**
97
+ * Append argument text to a started tool. Returns `undefined` when no tool is
98
+ * open under `key`, for protocols that ignore deltas without a matching block.
99
+ */
100
+ export const append = (tools, key, text) => {
101
+ const current = tools[key];
102
+ if (!current)
103
+ return undefined;
104
+ if (text.length === 0)
105
+ return { tools, tool: current, events: [] };
106
+ return appendTool(tools, key, { ...current, input: `${current.input}${text}` }, text);
107
+ };
108
+ /**
109
+ * Append argument text to a tool that must already have been started. This keeps
110
+ * protocols honest when their stream grammar promises a start event before any
111
+ * argument delta.
112
+ */
113
+ export const appendExisting = (route, tools, key, text, missingToolMessage) => append(tools, key, text) ?? eventError(route, missingToolMessage);
114
+ /**
115
+ * Finalize one pending tool call: parse the accumulated raw JSON, remove it
116
+ * from state, and recover incomplete local arguments when needed.
117
+ * Missing keys are a no-op because some providers emit stop events for
118
+ * non-tool content blocks.
119
+ */
120
+ export const finish = (route, tools, key) => Effect.gen(function* () {
121
+ const tool = tools[key];
122
+ if (!tool)
123
+ return { tools };
124
+ return {
125
+ tools: withoutTool(tools, key),
126
+ events: finishEvents(tool, yield* toolCall(route, tool)),
127
+ };
128
+ });
129
+ /**
130
+ * Finalize one pending tool call with an authoritative final input string.
131
+ * OpenAI Responses can send accumulated deltas and then repeat the completed
132
+ * arguments on `response.output_item.done`; the final value wins.
133
+ */
134
+ export const finishWithInput = (route, tools, key, input) => Effect.gen(function* () {
135
+ const tool = tools[key];
136
+ if (!tool)
137
+ return { tools };
138
+ return {
139
+ tools: withoutTool(tools, key),
140
+ events: finishEvents(tool, yield* toolCall(route, tool, input)),
141
+ };
142
+ });
143
+ /**
144
+ * Finalize every pending tool call at once. OpenAI Chat has this shape: it does
145
+ * not emit per-tool stop events, so all accumulated calls finish independently
146
+ * when the choice receives a terminal `finish_reason`.
147
+ */
148
+ export const finishAll = (route, tools) => Effect.gen(function* () {
149
+ const pending = Object.values(tools).filter((tool) => tool !== undefined);
150
+ return {
151
+ tools: empty(),
152
+ events: yield* Effect.forEach(pending, (tool) => toolCall(route, tool).pipe(Effect.map((event) => finishEvents(tool, event)))).pipe(Effect.map((events) => events.flat())),
153
+ };
154
+ });
155
+ export * as ToolStream from "./tool-stream.js";
@@ -0,0 +1,26 @@
1
+ import { ImageModel } from "../image.js";
2
+ import { type Definition as AuthDefinition } from "../route/auth.js";
3
+ import { type HttpOptions } from "../schema/index.js";
4
+ export declare const DEFAULT_BASE_URL = "https://api.x.ai/v1";
5
+ export declare const PATH = "/images/generations";
6
+ export declare const EDIT_PATH = "/images/edits";
7
+ export type XAIImageString<Known extends string> = Known | (string & {});
8
+ export type XAIImageOptions = {
9
+ readonly n?: number;
10
+ readonly aspectRatio?: XAIImageString<"1:1" | "3:4" | "4:3" | "9:16" | "16:9" | "2:3" | "3:2" | "9:19.5" | "19.5:9" | "9:20" | "20:9" | "1:2" | "2:1" | "auto">;
11
+ readonly aspect_ratio?: XAIImageString<"1:1" | "3:4" | "4:3" | "9:16" | "16:9" | "2:3" | "3:2" | "9:19.5" | "19.5:9" | "9:20" | "20:9" | "1:2" | "2:1" | "auto">;
12
+ readonly resolution?: XAIImageString<"1k" | "2k">;
13
+ readonly responseFormat?: XAIImageString<"url" | "b64_json">;
14
+ readonly response_format?: XAIImageString<"url" | "b64_json">;
15
+ } & Record<string, unknown>;
16
+ export interface ModelInput {
17
+ readonly id: string;
18
+ readonly auth: AuthDefinition;
19
+ readonly baseURL?: string;
20
+ readonly headers?: Record<string, string>;
21
+ readonly http?: HttpOptions;
22
+ }
23
+ export declare const model: (input: ModelInput) => ImageModel<XAIImageOptions>;
24
+ export declare const XAIImages: {
25
+ readonly model: (input: ModelInput) => ImageModel<XAIImageOptions>;
26
+ };
@@ -0,0 +1,106 @@
1
+ import { Effect, Encoding, Schema } from "effect";
2
+ import { Headers, HttpClientRequest } from "effect/unstable/http";
3
+ import { GeneratedImage, ImageModel, ImageResponse } from "../image.js";
4
+ import { Auth } from "../route/auth.js";
5
+ import { Usage, mergeHttpOptions, mergeJsonRecords } from "../schema/index.js";
6
+ import { ProviderShared, optionalNull } from "./shared.js";
7
+ import { ImageInputs } from "./utils/image-input.js";
8
+ const ADAPTER = "xai-images";
9
+ export const DEFAULT_BASE_URL = "https://api.x.ai/v1";
10
+ export const PATH = "/images/generations";
11
+ export const EDIT_PATH = "/images/edits";
12
+ const XAIImageResponse = Schema.Struct({
13
+ data: Schema.Array(Schema.Struct({
14
+ b64_json: optionalNull(Schema.String),
15
+ url: optionalNull(Schema.String),
16
+ revised_prompt: optionalNull(Schema.String),
17
+ mime_type: optionalNull(Schema.String),
18
+ })),
19
+ usage: Schema.optional(Schema.Unknown),
20
+ });
21
+ const nativeOptions = (options) => {
22
+ if (!options)
23
+ return undefined;
24
+ const { aspectRatio, responseFormat, ...native } = options;
25
+ return {
26
+ aspect_ratio: aspectRatio,
27
+ response_format: responseFormat,
28
+ ...native,
29
+ };
30
+ };
31
+ const applyQuery = (url, query) => {
32
+ if (!query)
33
+ return url;
34
+ const next = new URL(url);
35
+ Object.entries(query).forEach(([key, value]) => next.searchParams.set(key, value));
36
+ return next.toString();
37
+ };
38
+ export const model = (input) => {
39
+ const route = {
40
+ id: ADAPTER,
41
+ generate: Effect.fn("XAIImages.generate")(function* (request, execute) {
42
+ const http = mergeHttpOptions(request.model.http, request.http);
43
+ const imageReferences = (request.images ?? []).map((image) => {
44
+ if (image.type === "bytes")
45
+ return { url: ImageInputs.dataUrl(image), type: "image_url" };
46
+ if (image.type === "url")
47
+ return { url: image.url, type: "image_url" };
48
+ if (image.type === "file-id")
49
+ return { file_id: image.id };
50
+ return undefined;
51
+ });
52
+ if (imageReferences.some((image) => image === undefined))
53
+ return yield* ImageInputs.invalid("xAI Images accepts image URLs, data URLs, bytes, and file IDs");
54
+ const requestBody = mergeJsonRecords({
55
+ model: request.model.id,
56
+ prompt: request.prompt,
57
+ image: imageReferences.length === 1 ? imageReferences[0] : undefined,
58
+ images: imageReferences.length > 1 ? imageReferences : undefined,
59
+ }, nativeOptions(request.options), http?.body);
60
+ const text = ProviderShared.encodeJson(requestBody);
61
+ const url = applyQuery(`${(input.baseURL ?? DEFAULT_BASE_URL).replace(/\/$/, "")}${imageReferences.length === 0 ? PATH : EDIT_PATH}`, http?.query);
62
+ const headers = yield* Auth.toEffect(input.auth)({
63
+ request,
64
+ method: "POST",
65
+ url,
66
+ body: text,
67
+ headers: Headers.fromInput({ ...input.headers, ...http?.headers }),
68
+ });
69
+ const response = yield* execute(HttpClientRequest.post(url).pipe(HttpClientRequest.setHeaders(headers), HttpClientRequest.bodyText(text, "application/json")));
70
+ const output = yield* ProviderShared.imageResponse(ADAPTER, "xAI Images", response);
71
+ const decoded = yield* Schema.decodeUnknownEffect(Schema.fromJsonString(XAIImageResponse))(output.body).pipe(Effect.mapError((cause) => output.invalid("xAI Images returned an invalid response", cause)));
72
+ const images = yield* Effect.forEach(decoded.data, (item, index) => {
73
+ const mediaType = item.mime_type ?? "application/octet-stream";
74
+ if (item.b64_json)
75
+ return Effect.fromResult(Encoding.decodeBase64(item.b64_json)).pipe(Effect.mapError((cause) => output.invalid(`xAI Images result ${index} contains invalid base64 data`, cause)), Effect.map((data) => new GeneratedImage({
76
+ mediaType,
77
+ data,
78
+ providerMetadata: item.revised_prompt === undefined || item.revised_prompt === null
79
+ ? undefined
80
+ : { xai: { revisedPrompt: item.revised_prompt } },
81
+ })));
82
+ if (item.url)
83
+ return Effect.succeed(new GeneratedImage({
84
+ mediaType,
85
+ data: item.url,
86
+ providerMetadata: item.revised_prompt === undefined || item.revised_prompt === null
87
+ ? undefined
88
+ : { xai: { revisedPrompt: item.revised_prompt } },
89
+ }));
90
+ return Effect.fail(output.invalid(`xAI Images result ${index} has neither image data nor a URL`));
91
+ });
92
+ if (images.length === 0)
93
+ return yield* output.invalid("xAI Images returned no images");
94
+ const usage = ProviderShared.isRecord(decoded.usage) ? decoded.usage : undefined;
95
+ return new ImageResponse({
96
+ images,
97
+ usage: usage === undefined ? undefined : new Usage({ providerMetadata: { xai: usage } }),
98
+ providerMetadata: usage === undefined ? undefined : { xai: { usage } },
99
+ });
100
+ }),
101
+ };
102
+ return ImageModel.make({ id: input.id, provider: "xai", route, http: input.http });
103
+ };
104
+ export const XAIImages = {
105
+ model,
106
+ };
@@ -0,0 +1,250 @@
1
+ import { Protocol } from "../route/protocol.js";
2
+ import { OpenResponses } from "./open-responses.js";
3
+ export declare const protocol: Protocol<{
4
+ readonly input: readonly ({
5
+ readonly [x: string]: unknown;
6
+ readonly id: string;
7
+ readonly type: "web_search_call";
8
+ readonly status?: string | undefined;
9
+ readonly action?: {
10
+ readonly [x: string]: unknown;
11
+ } | null | undefined;
12
+ } | {
13
+ readonly [x: string]: unknown;
14
+ readonly id: string;
15
+ readonly type: "file_search_call";
16
+ readonly status?: string | undefined;
17
+ readonly queries?: readonly string[] | undefined;
18
+ readonly results?: readonly {
19
+ readonly [x: string]: unknown;
20
+ }[] | null | undefined;
21
+ } | {
22
+ readonly [x: string]: unknown;
23
+ readonly id: string;
24
+ readonly type: "code_interpreter_call";
25
+ readonly status?: string | undefined;
26
+ readonly code?: string | null | undefined;
27
+ readonly container_id?: string | null | undefined;
28
+ readonly outputs?: readonly {
29
+ readonly [x: string]: unknown;
30
+ }[] | null | undefined;
31
+ } | {
32
+ readonly [x: string]: unknown;
33
+ readonly id: string;
34
+ readonly type: "mcp_call";
35
+ readonly status?: string | undefined;
36
+ readonly name?: string | undefined;
37
+ readonly output?: string | null | undefined;
38
+ readonly error?: unknown;
39
+ readonly arguments?: string | undefined;
40
+ readonly server_label?: string | undefined;
41
+ } | {
42
+ readonly type: "reasoning";
43
+ readonly summary: readonly {
44
+ readonly type: "summary_text";
45
+ readonly text: string;
46
+ }[];
47
+ readonly id?: string | undefined;
48
+ readonly encrypted_content?: string | null | undefined;
49
+ } | {
50
+ readonly type: "compaction";
51
+ readonly encrypted_content: string;
52
+ readonly id?: string | null | undefined;
53
+ } | {
54
+ readonly role: "system";
55
+ readonly content: string;
56
+ } | {
57
+ readonly role: "developer";
58
+ readonly content: string;
59
+ } | {
60
+ readonly content: readonly ({
61
+ readonly type: "input_image";
62
+ readonly image_url: string;
63
+ readonly detail?: string | undefined;
64
+ } | {
65
+ readonly type: "input_file";
66
+ readonly filename: string;
67
+ readonly detail?: string | undefined;
68
+ readonly file_data?: string | undefined;
69
+ readonly file_url?: string | undefined;
70
+ } | {
71
+ readonly type: "input_text";
72
+ readonly text: string;
73
+ })[];
74
+ readonly role: "user";
75
+ readonly id?: string | undefined;
76
+ readonly type?: "message" | undefined;
77
+ readonly status?: string | undefined;
78
+ } | {
79
+ readonly type: "message";
80
+ readonly content: readonly {
81
+ readonly type: "output_text";
82
+ readonly text: string;
83
+ }[];
84
+ readonly role: "assistant";
85
+ readonly id?: string | undefined;
86
+ readonly status?: string | undefined;
87
+ readonly phase?: "commentary" | "final_answer" | null | undefined;
88
+ } | {
89
+ readonly type: "function_call";
90
+ readonly name: string;
91
+ readonly arguments: string;
92
+ readonly call_id: string;
93
+ readonly id?: string | undefined;
94
+ readonly namespace?: string | undefined;
95
+ } | {
96
+ readonly type: "function_call_output";
97
+ readonly call_id: string;
98
+ readonly output: string | readonly ({
99
+ readonly type: "input_image";
100
+ readonly image_url: string;
101
+ readonly detail?: string | undefined;
102
+ } | {
103
+ readonly type: "input_file";
104
+ readonly filename: string;
105
+ readonly detail?: string | undefined;
106
+ readonly file_data?: string | undefined;
107
+ readonly file_url?: string | undefined;
108
+ } | {
109
+ readonly type: "input_text";
110
+ readonly text: string;
111
+ } | {
112
+ readonly type: "input_video";
113
+ readonly video_url: string;
114
+ })[];
115
+ } | {
116
+ readonly [x: string]: unknown;
117
+ readonly id: string;
118
+ readonly type: "x_search_call";
119
+ readonly status?: string | undefined;
120
+ readonly action?: {
121
+ readonly [x: string]: unknown;
122
+ } | null | undefined;
123
+ } | {
124
+ readonly [x: string]: unknown;
125
+ readonly id: string;
126
+ readonly type: "image_generation_call";
127
+ readonly status?: string | undefined;
128
+ readonly error?: unknown;
129
+ readonly result?: unknown;
130
+ })[];
131
+ readonly model: string;
132
+ readonly stream: true;
133
+ readonly metadata?: {
134
+ readonly [x: string]: string;
135
+ } | undefined;
136
+ readonly instructions?: string | undefined;
137
+ readonly reasoning?: {
138
+ readonly summary?: "auto" | "concise" | "detailed" | undefined;
139
+ readonly effort?: import("./utils/open-responses-options.js").ReasoningEffort | undefined;
140
+ } | undefined;
141
+ readonly tools?: readonly {
142
+ readonly type: "function";
143
+ readonly description: string;
144
+ readonly name: string;
145
+ readonly parameters: {
146
+ readonly [x: string]: unknown;
147
+ };
148
+ readonly strict?: boolean | undefined;
149
+ }[] | undefined;
150
+ readonly text?: {
151
+ readonly verbosity?: import("./utils/open-responses-options.js").TextVerbosity | undefined;
152
+ } | undefined;
153
+ readonly temperature?: number | undefined;
154
+ readonly service_tier?: import("./utils/open-responses-options.js").ServiceTier | undefined;
155
+ readonly tool_choice?: "required" | "auto" | "none" | {
156
+ readonly type: "function";
157
+ readonly name: string;
158
+ } | {
159
+ readonly type: "allowed_tools";
160
+ readonly mode: "required" | "auto" | "none";
161
+ readonly tools: readonly {
162
+ readonly type: "function";
163
+ readonly name: string;
164
+ }[];
165
+ } | undefined;
166
+ readonly top_p?: number | undefined;
167
+ readonly frequency_penalty?: number | undefined;
168
+ readonly presence_penalty?: number | undefined;
169
+ readonly prompt_cache_key?: string | undefined;
170
+ readonly parallel_tool_calls?: boolean | undefined;
171
+ readonly store?: boolean | undefined;
172
+ readonly include?: readonly import("./utils/open-responses-options.js").ResponseIncludable[] | undefined;
173
+ readonly truncation?: "auto" | "disabled" | undefined;
174
+ readonly stream_options?: {
175
+ readonly include_obfuscation?: boolean | undefined;
176
+ } | undefined;
177
+ readonly safety_identifier?: string | undefined;
178
+ readonly top_logprobs?: number | undefined;
179
+ readonly max_output_tokens?: number | undefined;
180
+ readonly max_tool_calls?: number | undefined;
181
+ }, string, {
182
+ readonly [x: string]: unknown;
183
+ readonly type: string;
184
+ readonly status?: unknown;
185
+ readonly code?: string | null | undefined;
186
+ readonly message?: string | undefined;
187
+ readonly headers?: unknown;
188
+ readonly text?: string | undefined;
189
+ readonly error?: {
190
+ readonly type?: string | null | undefined;
191
+ readonly code?: string | null | undefined;
192
+ readonly message?: string | null | undefined;
193
+ readonly param?: string | null | undefined;
194
+ } | null | undefined;
195
+ readonly item?: {
196
+ readonly [x: string]: unknown;
197
+ readonly type: string;
198
+ readonly id?: string | undefined;
199
+ readonly name?: string | undefined;
200
+ readonly namespace?: string | undefined;
201
+ readonly arguments?: string | undefined;
202
+ readonly encrypted_content?: string | null | undefined;
203
+ readonly call_id?: string | undefined;
204
+ } | null | undefined;
205
+ readonly delta?: string | undefined;
206
+ readonly response?: {
207
+ readonly [x: string]: unknown;
208
+ readonly id?: string | undefined;
209
+ readonly output?: readonly {
210
+ readonly [x: string]: unknown;
211
+ readonly type: string;
212
+ readonly id?: string | undefined;
213
+ readonly name?: string | undefined;
214
+ readonly namespace?: string | undefined;
215
+ readonly arguments?: string | undefined;
216
+ readonly encrypted_content?: string | null | undefined;
217
+ readonly call_id?: string | undefined;
218
+ }[] | undefined;
219
+ readonly error?: {
220
+ readonly type?: string | null | undefined;
221
+ readonly code?: string | null | undefined;
222
+ readonly message?: string | null | undefined;
223
+ readonly param?: string | null | undefined;
224
+ } | null | undefined;
225
+ readonly usage?: {
226
+ readonly input_tokens?: number | undefined;
227
+ readonly output_tokens?: number | undefined;
228
+ readonly output_tokens_details?: {
229
+ readonly reasoning_tokens?: number | undefined;
230
+ } | null | undefined;
231
+ readonly total_tokens?: number | undefined;
232
+ readonly input_tokens_details?: {
233
+ readonly cached_tokens?: number | undefined;
234
+ readonly cache_write_tokens?: number | undefined;
235
+ } | null | undefined;
236
+ } | null | undefined;
237
+ readonly service_tier?: string | null | undefined;
238
+ readonly incomplete_details?: {
239
+ readonly reason?: string | undefined;
240
+ } | null | undefined;
241
+ } | undefined;
242
+ readonly arguments?: string | undefined;
243
+ readonly param?: string | null | undefined;
244
+ readonly status_code?: unknown;
245
+ readonly item_id?: string | undefined;
246
+ readonly output_index?: number | undefined;
247
+ readonly summary_index?: number | undefined;
248
+ }, OpenResponses.ParserState>;
249
+ export declare const compact: import("../route/client.js").CompactOperation;
250
+ export * as XAIResponses from "./xai-responses.js";
@@ -0,0 +1,81 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Protocol } from "../route/protocol.js";
3
+ import { OpenResponses } from "./open-responses.js";
4
+ import { JsonObject, optionalNull, ProviderShared } from "./shared.js";
5
+ import { ResponsesHostedTools } from "./utils/responses-hosted-tools.js";
6
+ import { ResponsesCompaction } from "./utils/responses-compaction.js";
7
+ const ADAPTER = "xai-responses";
8
+ const NAME = "xAI Responses";
9
+ const XAIResponsesHostedToolItem = Schema.Union([
10
+ Schema.StructWithRest(Schema.Struct({
11
+ type: Schema.tag("x_search_call"),
12
+ id: Schema.String,
13
+ status: Schema.optional(Schema.String),
14
+ action: optionalNull(JsonObject),
15
+ }), [JsonObject]),
16
+ Schema.StructWithRest(Schema.Struct({
17
+ type: Schema.tag("image_generation_call"),
18
+ id: Schema.String,
19
+ status: Schema.optional(Schema.String),
20
+ result: Schema.optional(Schema.Unknown),
21
+ error: Schema.optional(Schema.Unknown),
22
+ }), [JsonObject]),
23
+ ]);
24
+ const XAIResponsesBody = Schema.Struct({
25
+ ...OpenResponses.coreFields,
26
+ input: Schema.Array(Schema.Union([OpenResponses.InputItem, XAIResponsesHostedToolItem])),
27
+ stream: Schema.Literal(true),
28
+ });
29
+ const adapter = {
30
+ id: ADAPTER,
31
+ name: NAME,
32
+ restoreHostedToolItem: (item) => (Schema.is(XAIResponsesHostedToolItem)(item) ? item : undefined),
33
+ };
34
+ const decodeBody = ProviderShared.validateWith(Schema.decodeUnknownEffect(XAIResponsesBody));
35
+ const fromRequest = Effect.fn("XAIResponses.fromRequest")(function* (request) {
36
+ if (request.providerOptions?.contextManagement !== undefined)
37
+ return yield* ProviderShared.unsupportedOperation({
38
+ operation: "in-band-compaction",
39
+ provider: request.model.provider,
40
+ route: request.model.route.id,
41
+ message: "xAI requires explicit compaction through LLMClient.compact; automatic context management is not supported",
42
+ });
43
+ return yield* decodeBody(yield* OpenResponses.fromRequestWithAdapter(request, adapter));
44
+ });
45
+ const HOSTED_TOOLS = {
46
+ web_search_call: { name: "web_search", input: (item) => item.action ?? {} },
47
+ x_search_call: { name: "x_search", input: (item) => item.action ?? {} },
48
+ file_search_call: { name: "file_search", input: (item) => ({ queries: item.queries ?? [] }) },
49
+ code_interpreter_call: {
50
+ name: "code_interpreter",
51
+ input: (item) => ({ code: item.code, container_id: item.container_id }),
52
+ },
53
+ image_generation_call: { name: "image_generation", input: () => ({}) },
54
+ mcp_call: {
55
+ name: "mcp",
56
+ input: (item) => ({ server_label: item.server_label, name: item.name, arguments: item.arguments }),
57
+ },
58
+ };
59
+ // Grok speaks the standard Responses reasoning dialect (`reasoning_summary_text.*`,
60
+ // handled by the baseline); only its hosted tool vocabulary differs.
61
+ const step = (state, input) => {
62
+ const event = OpenResponses.normalize(state, input);
63
+ if (event.type === "response.output_item.done" && event.item && ResponsesHostedTools.isItem(event.item, HOSTED_TOOLS))
64
+ return ResponsesHostedTools.onDone(state, event.item, HOSTED_TOOLS);
65
+ return OpenResponses.step(state, event);
66
+ };
67
+ export const protocol = Protocol.make({
68
+ id: ADAPTER,
69
+ body: {
70
+ schema: XAIResponsesBody,
71
+ from: fromRequest,
72
+ },
73
+ stream: {
74
+ event: OpenResponses.protocol.stream.event,
75
+ initial: (request) => OpenResponses.initial(request, adapter),
76
+ step,
77
+ terminal: OpenResponses.terminal,
78
+ },
79
+ });
80
+ export const compact = ResponsesCompaction.make(adapter);
81
+ export * as XAIResponses from "./xai-responses.js";
@@ -0,0 +1,22 @@
1
+ import { ImageModel } from "../image.js";
2
+ import { type Definition as AuthDefinition } from "../route/auth.js";
3
+ import { type HttpOptions } from "../schema/index.js";
4
+ export declare const DEFAULT_BASE_URL = "https://api.z.ai/api/paas/v4";
5
+ export declare const PATH = "/images/generations";
6
+ export type ZAIImageString<Known extends string> = Known | (string & {});
7
+ export type ZAIImageOptions = {
8
+ readonly size?: ZAIImageString<"1024x1024" | "768x1344" | "864x1152" | "1344x768" | "1152x864" | "1440x720" | "720x1440">;
9
+ readonly quality?: ZAIImageString<"hd" | "standard">;
10
+ readonly userID?: string;
11
+ } & Record<string, unknown>;
12
+ export interface ModelInput {
13
+ readonly id: string;
14
+ readonly auth: AuthDefinition;
15
+ readonly baseURL?: string;
16
+ readonly headers?: Record<string, string>;
17
+ readonly http?: HttpOptions;
18
+ }
19
+ export declare const model: (input: ModelInput) => ImageModel<ZAIImageOptions>;
20
+ export declare const ZAIImages: {
21
+ readonly model: (input: ModelInput) => ImageModel<ZAIImageOptions>;
22
+ };