@opencode/ai 0.0.0-dev-20498 → 0.0.0-dev-20501
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +25 -0
- package/dist/protocols/alibaba-chat.d.ts +3 -3
- package/dist/protocols/alibaba-responses.d.ts +16 -12
- package/dist/protocols/alibaba-responses.js +3 -5
- package/dist/protocols/google-interactions.d.ts +236 -0
- package/dist/protocols/google-interactions.js +478 -0
- package/dist/protocols/index.d.ts +1 -0
- package/dist/protocols/index.js +1 -0
- package/dist/protocols/meta-responses.d.ts +31 -58
- package/dist/protocols/meta-responses.js +5 -24
- package/dist/protocols/mistral-chat.d.ts +1 -1
- package/dist/protocols/open-responses.d.ts +406 -91
- package/dist/protocols/open-responses.js +12 -6
- package/dist/protocols/openai-chat.d.ts +5 -5
- package/dist/protocols/openai-compatible-chat.d.ts +1 -1
- package/dist/protocols/openai-compatible-responses.d.ts +16 -4
- package/dist/protocols/openai-responses.d.ts +87 -223
- package/dist/protocols/openai-responses.js +3 -10
- package/dist/protocols/xai-responses.d.ts +18 -21
- package/dist/protocols/xai-responses.js +2 -8
- package/dist/protocols/zai-chat.d.ts +3 -3
- package/dist/providers/alibaba.d.ts +17 -13
- package/dist/providers/amazon-bedrock-mantle.d.ts +17 -5
- package/dist/providers/azure.d.ts +13 -61
- package/dist/providers/baseten.d.ts +2 -2
- package/dist/providers/cerebras.d.ts +2 -2
- package/dist/providers/cloudflare-ai-gateway.d.ts +14 -62
- package/dist/providers/cloudflare-workers-ai.d.ts +2 -2
- package/dist/providers/cohere.d.ts +2 -2
- package/dist/providers/deepinfra.d.ts +2 -2
- package/dist/providers/deepseek.d.ts +2 -2
- package/dist/providers/digitalocean.d.ts +5 -5
- package/dist/providers/fireworks.d.ts +2 -2
- package/dist/providers/google/interactions.d.ts +7 -0
- package/dist/providers/google/interactions.js +8 -0
- package/dist/providers/google-vertex-chat.d.ts +1 -1
- package/dist/providers/google-vertex-responses.d.ts +16 -4
- package/dist/providers/google.d.ts +94 -3
- package/dist/providers/google.js +8 -1
- package/dist/providers/groq.d.ts +4 -4
- package/dist/providers/meta.d.ts +15 -28
- package/dist/providers/minimax.d.ts +17 -5
- package/dist/providers/moonshot.d.ts +17 -5
- package/dist/providers/openai-compatible-responses.d.ts +16 -4
- package/dist/providers/openai-compatible.d.ts +1 -1
- package/dist/providers/openai.d.ts +7 -31
- package/dist/providers/openrouter.d.ts +5 -5
- package/dist/providers/togetherai.d.ts +2 -2
- package/dist/providers/xai.d.ts +1 -1
- package/dist/providers/zai-coding-plan.d.ts +17 -5
- package/dist/providers/zai.d.ts +1 -1
- package/dist/route/client.js +2 -5
- 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.fn("GoogleInteractions.mediaContent")(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.fn("GoogleInteractions.lowerMessages")(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.fn("GoogleInteractions.lowerToolResult")(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.fn("GoogleInteractions.onStart")(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.fn("GoogleInteractions.onDelta")(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.fn("GoogleInteractions.onStop")(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.fn("GoogleInteractions.step")(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";
|
|
@@ -2,6 +2,7 @@ export * as AnthropicMessages from "./anthropic-messages.js";
|
|
|
2
2
|
export * as BedrockConverse from "./bedrock-converse.js";
|
|
3
3
|
export * as CohereChat from "./cohere-chat.js";
|
|
4
4
|
export * as Gemini from "./gemini.js";
|
|
5
|
+
export * as GoogleInteractions from "./google-interactions.js";
|
|
5
6
|
export * as MistralChat from "./mistral-chat.js";
|
|
6
7
|
export * as OpenAIChat from "./openai-chat.js";
|
|
7
8
|
export * as OpenAIImages from "./openai-images.js";
|
package/dist/protocols/index.js
CHANGED
|
@@ -2,6 +2,7 @@ export * as AnthropicMessages from "./anthropic-messages.js";
|
|
|
2
2
|
export * as BedrockConverse from "./bedrock-converse.js";
|
|
3
3
|
export * as CohereChat from "./cohere-chat.js";
|
|
4
4
|
export * as Gemini from "./gemini.js";
|
|
5
|
+
export * as GoogleInteractions from "./google-interactions.js";
|
|
5
6
|
export * as MistralChat from "./mistral-chat.js";
|
|
6
7
|
export * as OpenAIChat from "./openai-chat.js";
|
|
7
8
|
export * as OpenAIImages from "./openai-images.js";
|