@opencode/ai 2.0.22 → 2.0.24

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 (107) hide show
  1. package/README.md +61 -1
  2. package/dist/cache-policy.js +13 -9
  3. package/dist/protocols/alibaba-chat.d.ts +3 -3
  4. package/dist/protocols/alibaba-messages.d.ts +3 -0
  5. package/dist/protocols/alibaba-responses.d.ts +19 -12
  6. package/dist/protocols/alibaba-responses.js +3 -5
  7. package/dist/protocols/anthropic-messages.d.ts +3 -0
  8. package/dist/protocols/anthropic-messages.js +53 -48
  9. package/dist/protocols/bedrock-converse.js +3 -3
  10. package/dist/protocols/cartesia-speech.js +3 -3
  11. package/dist/protocols/cohere-chat.d.ts +178 -0
  12. package/dist/protocols/cohere-chat.js +299 -0
  13. package/dist/protocols/elevenlabs-speech.js +3 -3
  14. package/dist/protocols/gemini.d.ts +2 -2
  15. package/dist/protocols/gemini.js +3 -3
  16. package/dist/protocols/google-interactions.d.ts +236 -0
  17. package/dist/protocols/google-interactions.js +478 -0
  18. package/dist/protocols/google-speech.js +1 -1
  19. package/dist/protocols/google-transcription.js +1 -1
  20. package/dist/protocols/index.d.ts +2 -0
  21. package/dist/protocols/index.js +2 -0
  22. package/dist/protocols/meta-messages.d.ts +3 -0
  23. package/dist/protocols/meta-responses.d.ts +34 -58
  24. package/dist/protocols/meta-responses.js +8 -27
  25. package/dist/protocols/mistral-chat.d.ts +24 -9
  26. package/dist/protocols/mistral-chat.js +22 -10
  27. package/dist/protocols/open-responses.d.ts +424 -103
  28. package/dist/protocols/open-responses.js +30 -20
  29. package/dist/protocols/openai-chat.d.ts +401 -5
  30. package/dist/protocols/openai-chat.js +18 -21
  31. package/dist/protocols/openai-compatible-chat.d.ts +1 -1
  32. package/dist/protocols/openai-compatible-responses.d.ts +16 -4
  33. package/dist/protocols/openai-images.js +2 -2
  34. package/dist/protocols/openai-responses.d.ts +90 -223
  35. package/dist/protocols/openai-responses.js +6 -13
  36. package/dist/protocols/openai-speech.js +1 -1
  37. package/dist/protocols/openai-transcription.js +1 -1
  38. package/dist/protocols/shared.js +2 -2
  39. package/dist/protocols/stability-images.js +1 -1
  40. package/dist/protocols/utils/bedrock-media.js +2 -2
  41. package/dist/protocols/utils/gateway-protocol.d.ts +17 -0
  42. package/dist/protocols/utils/gateway-protocol.js +57 -0
  43. package/dist/protocols/utils/responses-checkpoint.js +2 -2
  44. package/dist/protocols/utils/responses-hosted-tools.js +1 -1
  45. package/dist/protocols/utils/tool-stream.js +15 -7
  46. package/dist/protocols/venice-chat.d.ts +280 -0
  47. package/dist/protocols/venice-chat.js +283 -0
  48. package/dist/protocols/xai-responses.d.ts +21 -21
  49. package/dist/protocols/xai-responses.js +2 -8
  50. package/dist/protocols/zai-chat.d.ts +3 -3
  51. package/dist/protocols/zai-messages.d.ts +3 -0
  52. package/dist/provider-error.js +7 -1
  53. package/dist/providers/alibaba.d.ts +17 -13
  54. package/dist/providers/amazon-bedrock/mantle/messages.d.ts +2 -0
  55. package/dist/providers/amazon-bedrock/mantle/messages.js +1 -0
  56. package/dist/providers/amazon-bedrock-mantle.d.ts +301 -9
  57. package/dist/providers/amazon-bedrock-mantle.js +28 -3
  58. package/dist/providers/azure.d.ts +13 -61
  59. package/dist/providers/baseten.d.ts +2 -2
  60. package/dist/providers/cerebras.d.ts +2 -2
  61. package/dist/providers/cloudflare-ai-gateway.d.ts +14 -62
  62. package/dist/providers/cloudflare-workers-ai.d.ts +2 -2
  63. package/dist/providers/cohere/chat.d.ts +4 -0
  64. package/dist/providers/cohere/chat.js +8 -0
  65. package/dist/providers/cohere.d.ts +395 -0
  66. package/dist/providers/cohere.js +48 -0
  67. package/dist/providers/deepinfra.d.ts +2 -2
  68. package/dist/providers/deepseek.d.ts +2 -2
  69. package/dist/providers/digitalocean.d.ts +5 -5
  70. package/dist/providers/fireworks.d.ts +2 -2
  71. package/dist/providers/google/interactions.d.ts +7 -0
  72. package/dist/providers/google/interactions.js +8 -0
  73. package/dist/providers/google-vertex-chat.d.ts +1 -1
  74. package/dist/providers/google-vertex-messages.js +1 -0
  75. package/dist/providers/google-vertex-responses.d.ts +16 -4
  76. package/dist/providers/google-vertex.d.ts +1 -1
  77. package/dist/providers/google.d.ts +95 -4
  78. package/dist/providers/google.js +8 -1
  79. package/dist/providers/groq.d.ts +4 -4
  80. package/dist/providers/index.d.ts +2 -0
  81. package/dist/providers/index.js +2 -0
  82. package/dist/providers/meta.d.ts +15 -28
  83. package/dist/providers/minimax.d.ts +17 -5
  84. package/dist/providers/mistral.d.ts +10 -4
  85. package/dist/providers/moonshot.d.ts +17 -5
  86. package/dist/providers/openai-compatible-responses.d.ts +16 -4
  87. package/dist/providers/openai-compatible.d.ts +1 -1
  88. package/dist/providers/openai-options.d.ts +1 -1
  89. package/dist/providers/openai.d.ts +7 -31
  90. package/dist/providers/openrouter.d.ts +5 -5
  91. package/dist/providers/togetherai.d.ts +2 -2
  92. package/dist/providers/venice.d.ts +183 -0
  93. package/dist/providers/venice.js +38 -0
  94. package/dist/providers/vercel-ai-gateway/chat.d.ts +2 -0
  95. package/dist/providers/vercel-ai-gateway/chat.js +1 -0
  96. package/dist/providers/vercel-ai-gateway/messages.d.ts +2 -0
  97. package/dist/providers/vercel-ai-gateway/messages.js +1 -0
  98. package/dist/providers/vercel-ai-gateway/responses.d.ts +2 -0
  99. package/dist/providers/vercel-ai-gateway/responses.js +1 -0
  100. package/dist/providers/vercel-ai-gateway.d.ts +91 -9
  101. package/dist/providers/vercel-ai-gateway.js +161 -21
  102. package/dist/providers/xai.d.ts +1 -1
  103. package/dist/providers/zai-coding-plan.d.ts +17 -5
  104. package/dist/providers/zai.d.ts +1 -1
  105. package/dist/route/client.js +2 -5
  106. package/dist/route/framing.js +23 -23
  107. package/package.json +3 -3
@@ -0,0 +1,478 @@
1
+ import { Effect, Schema } from "effect";
2
+ import { Route } from "../route/client.js";
3
+ import { Auth } from "../route/auth.js";
4
+ import { Endpoint } from "../route/endpoint.js";
5
+ import { Framing } from "../route/framing.js";
6
+ import { Protocol } from "../route/protocol.js";
7
+ import { AIError, LLMEvent, ProviderID, Usage, } from "../schema/index.js";
8
+ import { Media } from "../media.js";
9
+ import { classifyProviderFailure, providerErrorMessage } from "../provider-error.js";
10
+ import { encodeJson } from "../utils/json.js";
11
+ import { JsonObject, knownString, lenient, optionalNull, ProviderShared } from "./shared.js";
12
+ import { Lifecycle } from "./utils/lifecycle.js";
13
+ import { MediaInput } from "./utils/media-input.js";
14
+ import { ToolStream } from "./utils/tool-stream.js";
15
+ const ADAPTER = "google-interactions";
16
+ export const DEFAULT_BASE_URL = "https://generativelanguage.googleapis.com/v1beta";
17
+ // =============================================================================
18
+ // Public Model Input
19
+ // =============================================================================
20
+ const ThinkingLevel = knownString();
21
+ const Options = Schema.Struct({
22
+ previousInteractionId: lenient(Schema.String),
23
+ store: lenient(Schema.Boolean),
24
+ thinkingLevel: lenient(ThinkingLevel),
25
+ thinkingSummaries: lenient(knownString()),
26
+ serviceTier: lenient(knownString()),
27
+ });
28
+ const decodeOptions = ProviderShared.validateWith(Schema.decodeUnknownEffect(Options));
29
+ // =============================================================================
30
+ // Request Body Schema
31
+ // =============================================================================
32
+ const Text = Schema.Struct({ type: Schema.Literal("text"), text: Schema.String });
33
+ const MediaContent = Schema.Struct({
34
+ type: Schema.Literals(["image", "audio", "video", "document"]),
35
+ data: Schema.optional(Schema.String),
36
+ uri: Schema.optional(Schema.String),
37
+ mime_type: Schema.String,
38
+ });
39
+ const Content = Schema.Union([Text, MediaContent]);
40
+ const InputStep = Schema.Union([
41
+ Schema.Struct({ type: Schema.Literals(["user_input", "model_output"]), content: Schema.Array(Content) }),
42
+ Schema.Struct({
43
+ type: Schema.Literal("thought"),
44
+ signature: Schema.optional(Schema.String),
45
+ summary: Schema.optional(Schema.Array(Text)),
46
+ }),
47
+ Schema.Struct({
48
+ type: Schema.Literal("function_call"),
49
+ id: Schema.String,
50
+ name: Schema.String,
51
+ arguments: Schema.Unknown,
52
+ signature: Schema.optional(Schema.String),
53
+ }),
54
+ Schema.Struct({
55
+ type: Schema.Literal("function_result"),
56
+ call_id: Schema.String,
57
+ name: Schema.String,
58
+ result: Schema.Unknown,
59
+ is_error: Schema.optional(Schema.Boolean),
60
+ }),
61
+ ]);
62
+ const ToolChoice = Schema.Union([
63
+ Schema.Literals(["auto", "any", "none"]),
64
+ Schema.Struct({ allowed_tools: Schema.Struct({ mode: Schema.Literal("any"), tools: Schema.Array(Schema.String) }) }),
65
+ ]);
66
+ const Body = Schema.Struct({
67
+ model: Schema.String,
68
+ input: Schema.Array(InputStep),
69
+ stream: Schema.Literal(true),
70
+ store: Schema.Boolean,
71
+ previous_interaction_id: Schema.optional(Schema.String),
72
+ system_instruction: Schema.optional(Schema.String),
73
+ service_tier: Schema.optional(Schema.String),
74
+ tools: Schema.optional(Schema.Array(Schema.Struct({
75
+ type: Schema.Literal("function"),
76
+ name: Schema.String,
77
+ description: Schema.String,
78
+ parameters: JsonObject,
79
+ }))),
80
+ generation_config: Schema.Struct({
81
+ max_output_tokens: Schema.optional(Schema.Number),
82
+ temperature: Schema.optional(Schema.Number),
83
+ top_p: Schema.optional(Schema.Number),
84
+ seed: Schema.optional(Schema.Number),
85
+ stop_sequences: Schema.optional(Schema.Array(Schema.String)),
86
+ thinking_level: Schema.optional(ThinkingLevel),
87
+ thinking_summaries: Schema.optional(Schema.String),
88
+ tool_choice: Schema.optional(ToolChoice),
89
+ }),
90
+ });
91
+ // =============================================================================
92
+ // Streaming Event Schema
93
+ // =============================================================================
94
+ const RawUsage = Schema.StructWithRest(Schema.Struct({
95
+ total_input_tokens: optionalNull(Schema.Number),
96
+ total_cached_tokens: optionalNull(Schema.Number),
97
+ total_output_tokens: optionalNull(Schema.Number),
98
+ total_thought_tokens: optionalNull(Schema.Number),
99
+ total_tokens: optionalNull(Schema.Number),
100
+ raw_prompt_token: optionalNull(Schema.Number),
101
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
102
+ const OutputStep = Schema.Struct({
103
+ type: Schema.String,
104
+ id: Schema.optional(Schema.String),
105
+ name: Schema.optional(Schema.String),
106
+ arguments: Schema.optional(JsonObject),
107
+ signature: Schema.optional(Schema.String),
108
+ summary: Schema.optional(Schema.Array(Text)),
109
+ content: Schema.optional(Schema.Array(Schema.Struct({ type: Schema.String, text: Schema.optional(Schema.String) }))),
110
+ });
111
+ const Delta = Schema.Union([
112
+ Schema.Struct({ type: Schema.Literal("text"), text: Schema.String }),
113
+ Schema.Struct({ type: Schema.Literal("arguments_delta"), arguments: Schema.String }),
114
+ Schema.Struct({ type: Schema.Literal("thought_signature"), signature: Schema.String }),
115
+ Schema.Struct({ type: Schema.Literal("thought_summary"), content: Text }),
116
+ // Unknown output modalities must fail explicitly rather than disappearing from a successful response.
117
+ Schema.Struct({ type: Schema.String }),
118
+ ]);
119
+ const Interaction = Schema.StructWithRest(Schema.Struct({
120
+ id: Schema.optional(Schema.String),
121
+ status: Schema.String,
122
+ usage: Schema.optional(RawUsage),
123
+ }), [Schema.Record(Schema.String, Schema.Unknown)]);
124
+ const Event = Schema.Union([
125
+ Schema.Struct({ event_type: Schema.Literal("step.start"), index: Schema.Number, step: OutputStep }),
126
+ Schema.Struct({ event_type: Schema.Literal("step.delta"), index: Schema.Number, delta: Delta }),
127
+ Schema.Struct({ event_type: Schema.Literal("step.stop"), index: Schema.Number }),
128
+ Schema.Struct({
129
+ event_type: Schema.Literal("interaction.created"),
130
+ interaction: Schema.Struct({ id: Schema.optional(Schema.String) }),
131
+ }),
132
+ Schema.Struct({
133
+ event_type: Schema.Literal("interaction.status_update"),
134
+ interaction_id: Schema.optional(Schema.String),
135
+ status: Schema.String,
136
+ }),
137
+ Schema.Struct({ event_type: Schema.Literal("interaction.completed"), interaction: Interaction }),
138
+ Schema.Struct({ event_type: Schema.Literal("error"), error: Schema.Unknown }),
139
+ ]);
140
+ // =============================================================================
141
+ // Request Body Construction
142
+ // =============================================================================
143
+ const mediaContent = Effect.fnUntraced(function* (asset) {
144
+ if (asset.kind !== "image" &&
145
+ asset.kind !== "audio" &&
146
+ asset.kind !== "video" &&
147
+ asset.mediaType !== "application/pdf" &&
148
+ asset.mediaType !== "text/csv")
149
+ return yield* ProviderShared.invalidRequest(`Google Interactions does not support ${asset.mediaType} document input`);
150
+ const type = asset.kind === "image" || asset.kind === "audio" || asset.kind === "video" ? asset.kind : "document";
151
+ const uri = MediaInput.refID(asset, ProviderID.make("google"));
152
+ if (uri !== undefined)
153
+ return { type, uri, mime_type: asset.mediaType };
154
+ const inline = yield* ProviderShared.requireInlineMedia("Google Interactions", asset);
155
+ return { type, data: inline.base64, mime_type: inline.mime };
156
+ });
157
+ const signature = (metadata, key) => {
158
+ const value = metadata?.[key];
159
+ return ProviderShared.isRecord(value) && typeof value.interactionSignature === "string"
160
+ ? value.interactionSignature
161
+ : undefined;
162
+ };
163
+ const lowerMessages = Effect.fnUntraced(function* (request) {
164
+ const steps = [];
165
+ const key = request.model.route.providerMetadataKey ?? String(request.model.provider);
166
+ for (const message of request.messages) {
167
+ if (message.role === "system") {
168
+ const part = yield* ProviderShared.wrappedSystemUpdate("Google Interactions", message);
169
+ steps.push({ type: "user_input", content: [{ type: "text", text: part.text }] });
170
+ continue;
171
+ }
172
+ const start = steps.length;
173
+ // Consecutive ordinary content remains one native message; tools and thoughts retain their chronology.
174
+ const append = (content) => {
175
+ const type = message.role === "assistant" ? "model_output" : "user_input";
176
+ const last = steps.at(-1);
177
+ if (steps.length > start && last?.type === type)
178
+ steps[steps.length - 1] = { type, content: [...last.content, content] };
179
+ else
180
+ steps.push({ type, content: [content] });
181
+ };
182
+ for (const part of message.content) {
183
+ if (message.role === "tool") {
184
+ if (part.type !== "tool-result")
185
+ return yield* ProviderShared.unsupportedContent(ADAPTER, "tool", ["tool-result"]);
186
+ steps.push({
187
+ type: "function_result",
188
+ call_id: part.id,
189
+ name: part.name,
190
+ result: yield* lowerToolResult(part),
191
+ is_error: part.result.type === "error" || undefined,
192
+ });
193
+ continue;
194
+ }
195
+ if (part.type === "text") {
196
+ append({ type: "text", text: part.text });
197
+ continue;
198
+ }
199
+ if (part.type === "media") {
200
+ append(yield* mediaContent(part.media));
201
+ continue;
202
+ }
203
+ if (message.role === "assistant" && part.type === "reasoning") {
204
+ steps.push({
205
+ type: "thought",
206
+ signature: signature(part.providerMetadata, key),
207
+ summary: part.text ? [{ type: "text", text: part.text }] : undefined,
208
+ });
209
+ continue;
210
+ }
211
+ if (message.role === "assistant" && part.type === "tool-call") {
212
+ steps.push({
213
+ type: "function_call",
214
+ id: part.id,
215
+ name: part.name,
216
+ arguments: part.input,
217
+ signature: signature(part.providerMetadata, key),
218
+ });
219
+ continue;
220
+ }
221
+ return yield* ProviderShared.unsupportedContent(ADAPTER, message.role, message.role === "user" ? ["text", "media"] : ["text", "media", "reasoning", "tool-call"]);
222
+ }
223
+ }
224
+ return steps;
225
+ });
226
+ const lowerToolResult = Effect.fnUntraced(function* (part) {
227
+ if (part.result.type === "json" && ProviderShared.isRecord(part.result.value))
228
+ return part.result.value;
229
+ if (part.result.type !== "content")
230
+ return ProviderShared.toolResultText(part);
231
+ return yield* Effect.forEach(part.result.value, (item) => {
232
+ if (item.type === "text")
233
+ return Effect.succeed({ type: "text", text: item.text });
234
+ return mediaContent(ProviderShared.toolFileMedia(item).media);
235
+ });
236
+ });
237
+ const fromRequest = Effect.fn("GoogleInteractions.fromRequest")(function* (request) {
238
+ const options = yield* decodeOptions(request.providerOptions ?? {});
239
+ const flattened = ProviderShared.flattenToolRequest(request);
240
+ if (flattened.tools.some((tool) => tool.native !== undefined))
241
+ return yield* ProviderShared.invalidRequest("Google Interactions hosted tools are not supported");
242
+ if (request.generation?.topK !== undefined ||
243
+ request.generation?.frequencyPenalty !== undefined ||
244
+ request.generation?.presencePenalty !== undefined)
245
+ return yield* ProviderShared.invalidRequest("Google Interactions does not support topK, frequencyPenalty, or presencePenalty");
246
+ const choice = request.toolChoice === undefined
247
+ ? undefined
248
+ : yield* ProviderShared.matchToolChoice(ADAPTER, request.toolChoice, {
249
+ auto: () => "auto",
250
+ none: () => "none",
251
+ required: () => "any",
252
+ tool: (name) => ({ allowed_tools: { mode: "any", tools: [name] } }),
253
+ });
254
+ return {
255
+ model: request.model.id,
256
+ input: yield* lowerMessages(flattened.request),
257
+ stream: true,
258
+ // Full-history replay need not create retained provider resources. Continuation callers opt in to storage.
259
+ store: options.store ?? false,
260
+ previous_interaction_id: options.previousInteractionId,
261
+ system_instruction: request.system.length ? ProviderShared.joinText(request.system) : undefined,
262
+ service_tier: options.serviceTier,
263
+ tools: flattened.tools.length
264
+ ? flattened.tools.map((tool) => ({
265
+ type: "function",
266
+ name: tool.name,
267
+ description: tool.description,
268
+ parameters: tool.inputSchema,
269
+ }))
270
+ : undefined,
271
+ generation_config: {
272
+ max_output_tokens: request.generation?.maxTokens,
273
+ temperature: request.generation?.temperature,
274
+ top_p: request.generation?.topP,
275
+ seed: request.generation?.seed,
276
+ stop_sequences: request.generation?.stop,
277
+ thinking_level: options.thinkingLevel,
278
+ thinking_summaries: options.thinkingSummaries,
279
+ tool_choice: choice,
280
+ },
281
+ };
282
+ });
283
+ // =============================================================================
284
+ // Stream Parsing
285
+ // =============================================================================
286
+ const metadata = (state, step) => ({
287
+ [state.metadataKey]: { interactionSignature: step.signature },
288
+ });
289
+ const mapUsage = (usage, key) => {
290
+ if (!usage)
291
+ return undefined;
292
+ const input = usage.total_input_tokens ?? undefined;
293
+ const cached = usage.total_cached_tokens ?? undefined;
294
+ const reasoning = usage.total_thought_tokens ?? undefined;
295
+ const output = usage.total_output_tokens === undefined || usage.total_output_tokens === null
296
+ ? undefined
297
+ : usage.total_output_tokens + (reasoning ?? 0);
298
+ return new Usage({
299
+ contextTokens: usage.raw_prompt_token ?? input,
300
+ inputTokens: input,
301
+ outputTokens: output,
302
+ nonCachedInputTokens: ProviderShared.subtractTokens(input, cached),
303
+ cacheReadInputTokens: cached,
304
+ reasoningTokens: reasoning,
305
+ totalTokens: usage.total_tokens ?? undefined,
306
+ providerMetadata: { [key]: usage },
307
+ });
308
+ };
309
+ const onStart = Effect.fnUntraced(function* (state, index, step) {
310
+ const events = [];
311
+ let lifecycle = Lifecycle.stepStart(state.lifecycle, events);
312
+ let tools = state.tools;
313
+ const id = String(index);
314
+ if (step.type === "thought") {
315
+ lifecycle = Lifecycle.reasoningStart(lifecycle, events, id, metadata(state, step));
316
+ for (const part of step.summary ?? [])
317
+ lifecycle = Lifecycle.reasoningDelta(lifecycle, events, id, part.text);
318
+ }
319
+ else if (step.type === "model_output") {
320
+ lifecycle = Lifecycle.textStart(lifecycle, events, id);
321
+ for (const part of step.content ?? []) {
322
+ if (part.type !== "text")
323
+ return yield* ProviderShared.eventError(ADAPTER, `Unsupported Interactions output: ${part.type}`, encodeJson(step));
324
+ if (part.text)
325
+ lifecycle = Lifecycle.textDelta(lifecycle, events, id, part.text);
326
+ }
327
+ }
328
+ else if (step.type === "function_call") {
329
+ if (!step.id || !step.name)
330
+ return yield* ProviderShared.eventError(ADAPTER, "Interactions function call lacks id or name", encodeJson(step));
331
+ tools = ToolStream.start(tools, index, {
332
+ id: step.id,
333
+ name: step.name,
334
+ providerMetadata: metadata(state, step),
335
+ input: step.arguments && Object.keys(step.arguments).length ? encodeJson(step.arguments) : "",
336
+ });
337
+ events.push(LLMEvent.toolInputStart({ id: step.id, name: step.name, providerMetadata: metadata(state, step) }));
338
+ }
339
+ else
340
+ return yield* ProviderShared.eventError(ADAPTER, `Unsupported Interactions step: ${step.type}`, encodeJson(step));
341
+ return [{ ...state, lifecycle, tools, steps: { ...state.steps, [index]: step } }, events];
342
+ });
343
+ const onDelta = Effect.fnUntraced(function* (state, index, delta) {
344
+ const step = state.steps[index];
345
+ if (!step)
346
+ return yield* ProviderShared.eventError(ADAPTER, "Interactions delta without step.start", encodeJson(delta));
347
+ const events = [];
348
+ if (delta.type === "text" && "text" in delta && step.type === "model_output")
349
+ return [
350
+ { ...state, lifecycle: Lifecycle.textDelta(state.lifecycle, events, String(index), delta.text) },
351
+ events,
352
+ ];
353
+ if (delta.type === "thought_summary" && "content" in delta && step.type === "thought")
354
+ return [
355
+ { ...state, lifecycle: Lifecycle.reasoningDelta(state.lifecycle, events, String(index), delta.content.text) },
356
+ events,
357
+ ];
358
+ if (delta.type === "thought_signature" && "signature" in delta) {
359
+ const next = { ...step, signature: delta.signature };
360
+ const tool = state.tools[index];
361
+ return [
362
+ {
363
+ ...state,
364
+ steps: { ...state.steps, [index]: next },
365
+ tools: tool ? { ...state.tools, [index]: { ...tool, providerMetadata: metadata(state, next) } } : state.tools,
366
+ },
367
+ events,
368
+ ];
369
+ }
370
+ if (delta.type === "arguments_delta" && "arguments" in delta && step.type === "function_call") {
371
+ const result = ToolStream.appendExisting(ADAPTER, state.tools, index, delta.arguments, "Interactions arguments without function call");
372
+ if (ToolStream.isError(result))
373
+ return yield* result;
374
+ return [{ ...state, tools: result.tools }, result.events];
375
+ }
376
+ return yield* ProviderShared.eventError(ADAPTER, `Unsupported Interactions delta: ${delta.type}`, encodeJson(delta));
377
+ });
378
+ const onStop = Effect.fnUntraced(function* (state, index) {
379
+ const step = state.steps[index];
380
+ if (!step)
381
+ return yield* ProviderShared.eventError(ADAPTER, "Interactions step.stop without step.start");
382
+ const events = [];
383
+ if (step.type === "thought")
384
+ return [
385
+ { ...state, lifecycle: Lifecycle.reasoningEnd(state.lifecycle, events, String(index), metadata(state, step)) },
386
+ events,
387
+ ];
388
+ if (step.type === "model_output")
389
+ return [
390
+ { ...state, lifecycle: Lifecycle.textEnd(state.lifecycle, events, String(index)) },
391
+ events,
392
+ ];
393
+ const result = yield* ToolStream.finish(ADAPTER, state.tools, index);
394
+ return [{ ...state, tools: result.tools }, result.events ?? []];
395
+ });
396
+ const step = Effect.fnUntraced(function* (state, event) {
397
+ switch (event.event_type) {
398
+ case "step.start":
399
+ return yield* onStart(state, event.index, event.step);
400
+ case "step.delta":
401
+ return yield* onDelta(state, event.index, event.delta);
402
+ case "step.stop":
403
+ return yield* onStop(state, event.index);
404
+ case "interaction.created":
405
+ case "interaction.status_update":
406
+ return [state, []];
407
+ case "error":
408
+ return yield* new AIError({
409
+ reason: classifyProviderFailure({
410
+ message: providerErrorMessage(encodeJson(event)) ?? "Google Interactions stream error",
411
+ data: event.error,
412
+ rawBody: encodeJson(event),
413
+ }),
414
+ });
415
+ case "interaction.completed": {
416
+ const interaction = event.interaction;
417
+ if (interaction.status === "failed" || interaction.status === "cancelled")
418
+ return yield* new AIError({
419
+ reason: classifyProviderFailure({
420
+ message: `Google Interactions ${interaction.status}`,
421
+ data: interaction,
422
+ rawBody: encodeJson(event),
423
+ }),
424
+ });
425
+ if (!["completed", "requires_action", "incomplete"].includes(interaction.status))
426
+ return yield* ProviderShared.eventError(ADAPTER, `Unexpected terminal Interactions status: ${interaction.status}`, encodeJson(event));
427
+ const pending = yield* ToolStream.finishAll(ADAPTER, state.tools);
428
+ const events = [...pending.events];
429
+ const lifecycle = Lifecycle.finish(state.lifecycle, events, {
430
+ reason: {
431
+ normalized: interaction.status === "requires_action"
432
+ ? "tool-calls"
433
+ : interaction.status === "incomplete"
434
+ ? "length"
435
+ : "stop",
436
+ raw: interaction.status,
437
+ },
438
+ usage: mapUsage(interaction.usage, state.metadataKey),
439
+ providerMetadata: { [state.metadataKey]: { interactionId: interaction.id } },
440
+ });
441
+ return [{ ...state, lifecycle, tools: pending.tools, completed: true }, events];
442
+ }
443
+ }
444
+ });
445
+ // =============================================================================
446
+ // Protocol And Route
447
+ // =============================================================================
448
+ export const protocol = Protocol.make({
449
+ id: ADAPTER,
450
+ sanitizer: "gemini",
451
+ body: { schema: Body, from: fromRequest },
452
+ stream: {
453
+ event: Protocol.jsonEvent(Event),
454
+ initial: (request) => ({
455
+ route: `${request.model.provider}/${ADAPTER}`,
456
+ metadataKey: request.model.route.providerMetadataKey ?? String(request.model.provider),
457
+ lifecycle: Lifecycle.initial(),
458
+ steps: {},
459
+ tools: ToolStream.empty(),
460
+ completed: false,
461
+ }),
462
+ step,
463
+ terminal: (event) => event.event_type === "interaction.completed",
464
+ onHalt: (state) => state.completed
465
+ ? Effect.succeed([])
466
+ : Effect.fail(ProviderShared.eventError(ADAPTER, "Google Interactions stream ended before interaction.completed")),
467
+ },
468
+ });
469
+ export const route = Route.make({
470
+ id: ADAPTER,
471
+ provider: "google",
472
+ providerMetadataKey: "google",
473
+ protocol,
474
+ endpoint: Endpoint.path("/interactions", { baseURL: DEFAULT_BASE_URL }),
475
+ auth: Auth.none,
476
+ framing: Framing.sse,
477
+ });
478
+ export * as GoogleInteractions from "./google-interactions.js";
@@ -42,7 +42,7 @@ const fromRequest = Effect.fn("GoogleSpeech.fromRequest")(function* (request) {
42
42
  // ---------------------------------------------------------------------------
43
43
  // 6. Stream parsing
44
44
  // ---------------------------------------------------------------------------
45
- const step = Effect.fn("GoogleSpeech.step")(function* (state, frame) {
45
+ const step = Effect.fnUntraced(function* (state, frame) {
46
46
  const chunk = yield* decodeChunk(frame);
47
47
  const blocked = GeminiGenerateContent.blocked(route.name, chunk, frame);
48
48
  if (blocked !== undefined)
@@ -70,7 +70,7 @@ const turn = (part) => {
70
70
  },
71
71
  };
72
72
  };
73
- const step = Effect.fn("GoogleTranscription.step")(function* (state, frame) {
73
+ const step = Effect.fnUntraced(function* (state, frame) {
74
74
  const chunk = yield* decodeChunk(frame);
75
75
  const blocked = GeminiGenerateContent.blocked(route.name, chunk, frame);
76
76
  if (blocked !== undefined)
@@ -1,6 +1,8 @@
1
1
  export * as AnthropicMessages from "./anthropic-messages.js";
2
2
  export * as BedrockConverse from "./bedrock-converse.js";
3
+ export * as CohereChat from "./cohere-chat.js";
3
4
  export * as Gemini from "./gemini.js";
5
+ export * as GoogleInteractions from "./google-interactions.js";
4
6
  export * as MistralChat from "./mistral-chat.js";
5
7
  export * as OpenAIChat from "./openai-chat.js";
6
8
  export * as OpenAIImages from "./openai-images.js";
@@ -1,6 +1,8 @@
1
1
  export * as AnthropicMessages from "./anthropic-messages.js";
2
2
  export * as BedrockConverse from "./bedrock-converse.js";
3
+ export * as CohereChat from "./cohere-chat.js";
3
4
  export * as Gemini from "./gemini.js";
5
+ export * as GoogleInteractions from "./google-interactions.js";
4
6
  export * as MistralChat from "./mistral-chat.js";
5
7
  export * as OpenAIChat from "./openai-chat.js";
6
8
  export * as OpenAIImages from "./openai-images.js";
@@ -282,8 +282,10 @@ export declare const protocol: Protocol<{
282
282
  readonly top_k?: number | undefined;
283
283
  readonly stop_sequences?: readonly string[] | undefined;
284
284
  }, string, {
285
+ readonly [x: string]: unknown;
285
286
  readonly type: string;
286
287
  readonly message?: {
288
+ readonly [x: string]: unknown;
287
289
  readonly usage?: {
288
290
  readonly [x: string]: unknown;
289
291
  readonly input_tokens?: number | null | undefined;
@@ -316,6 +318,7 @@ export declare const protocol: Protocol<{
316
318
  } | undefined;
317
319
  } | undefined;
318
320
  readonly error?: {
321
+ readonly [x: string]: unknown;
319
322
  readonly type?: string | undefined;
320
323
  readonly message?: string | undefined;
321
324
  } | undefined;