@alvin0/ai-agent-sdk-protocol-gemini-interactions 0.1.0

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 alvin0 (chaulamdinhai) <chaulamdinhai@gmail.com>
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,11 @@
1
+ # @alvin0/ai-agent-sdk-protocol-gemini-interactions
2
+
3
+ Runtime: **Universal** (Edge/Worker, browser, Deno, Bun, and Node).
4
+
5
+ ```sh
6
+ pnpm add @alvin0/ai-agent-sdk-core @alvin0/ai-agent-sdk-protocol-gemini-interactions
7
+ ```
8
+
9
+ Universal serializer and SSE translator for the Gemini Interactions API. This
10
+ package implements only the `/v1beta/interactions` wire protocol; use
11
+ `@alvin0/ai-agent-sdk-provider-gemini` for the Google endpoint and API-key setup.
@@ -0,0 +1,187 @@
1
+ import { GenerateOptions, StreamChunk, UsageCounters } from "@alvin0/ai-agent-sdk-core";
2
+ //#region src/contract.d.ts
3
+ interface ProtocolRequest {
4
+ readonly options: GenerateOptions;
5
+ readonly maxTokens: number;
6
+ }
7
+ interface ProtocolSseEvent {
8
+ readonly event: string | undefined;
9
+ readonly data: string;
10
+ }
11
+ type ProtocolStreamChunk = Exclude<StreamChunk, {
12
+ readonly type: 'usage';
13
+ }> | {
14
+ readonly type: 'usage';
15
+ readonly usage: UsageCounters;
16
+ };
17
+ interface ProtocolDefinition<Dialect> {
18
+ readonly id: string;
19
+ readonly defaultDialect: Dialect;
20
+ endpointPath(request: ProtocolRequest, dialect: Dialect): string;
21
+ protocolHeaders?(dialect: Dialect): Record<string, string>;
22
+ serialize(request: ProtocolRequest, dialect: Dialect): unknown | Promise<unknown>;
23
+ translate(events: AsyncIterable<ProtocolSseEvent>, request: ProtocolRequest, displayName: string): AsyncGenerator<ProtocolStreamChunk>;
24
+ }
25
+ //#endregion
26
+ //#region src/wire.d.ts
27
+ interface GeminiInteractionsDialect {
28
+ /** Whether Google may retain the request and interaction. Defaults to false. */
29
+ readonly store: boolean;
30
+ /** Whether thought summaries should be requested when reasoning is selected. */
31
+ readonly thinkingSummaries: 'auto' | 'none';
32
+ }
33
+ interface WireTextContent {
34
+ type: 'text';
35
+ text: string;
36
+ annotations?: WireAnnotation[];
37
+ }
38
+ interface WireImageContent {
39
+ type: 'image';
40
+ data?: string;
41
+ uri?: string;
42
+ mime_type?: string;
43
+ resolution?: 'low' | 'medium' | 'high' | 'ultra_high';
44
+ }
45
+ type WireContent = WireTextContent | WireImageContent;
46
+ type WireStep = {
47
+ type: 'user_input';
48
+ content: WireContent[];
49
+ } | {
50
+ type: 'model_output';
51
+ content: WireContent[];
52
+ } | {
53
+ type: 'thought';
54
+ signature?: string;
55
+ summary?: WireContent[];
56
+ } | {
57
+ type: 'function_call';
58
+ id: string;
59
+ name: string;
60
+ arguments: Record<string, unknown>;
61
+ } | {
62
+ type: 'function_result';
63
+ call_id: string;
64
+ name?: string;
65
+ result: string | Record<string, unknown> | WireContent[];
66
+ is_error?: boolean;
67
+ };
68
+ interface WireFunctionTool {
69
+ type: 'function';
70
+ name: string;
71
+ description: string;
72
+ parameters: Readonly<Record<string, unknown>>;
73
+ }
74
+ interface WireGoogleSearchTool {
75
+ type: 'google_search';
76
+ search_types: ['web_search'];
77
+ }
78
+ type WireTool = WireFunctionTool | WireGoogleSearchTool;
79
+ type WireToolChoice = 'auto' | 'any' | 'none' | {
80
+ allowed_tools: {
81
+ mode: 'any';
82
+ tools: string[];
83
+ };
84
+ };
85
+ interface WireGenerationConfig {
86
+ max_output_tokens: number;
87
+ temperature?: number;
88
+ top_p?: number;
89
+ stop_sequences?: string[];
90
+ thinking_level?: string;
91
+ thinking_summaries?: 'auto' | 'none';
92
+ tool_choice?: WireToolChoice;
93
+ }
94
+ type WireResponseFormat = {
95
+ type: 'text';
96
+ mime_type: 'text/plain';
97
+ } | {
98
+ type: 'text';
99
+ mime_type: 'application/json';
100
+ schema: Readonly<Record<string, unknown>>;
101
+ };
102
+ interface WireRequest {
103
+ model: string;
104
+ input: WireStep[];
105
+ system_instruction?: string;
106
+ tools?: WireTool[];
107
+ response_format?: WireResponseFormat;
108
+ stream: true;
109
+ store: boolean;
110
+ generation_config: WireGenerationConfig;
111
+ }
112
+ interface GeminiThoughtState {
113
+ signature?: string;
114
+ summary?: readonly WireContent[];
115
+ }
116
+ interface WireAnnotation {
117
+ type?: string;
118
+ url?: string;
119
+ title?: string;
120
+ start_index?: number;
121
+ end_index?: number;
122
+ [key: string]: unknown;
123
+ }
124
+ interface WireStepData {
125
+ type?: string;
126
+ content?: unknown;
127
+ summary?: unknown;
128
+ signature?: string;
129
+ id?: string;
130
+ name?: string;
131
+ arguments?: unknown;
132
+ }
133
+ interface WireDelta {
134
+ type?: string;
135
+ text?: string;
136
+ arguments?: string;
137
+ signature?: string;
138
+ content?: unknown;
139
+ annotations?: unknown;
140
+ }
141
+ interface WireUsage {
142
+ total_input_tokens?: number;
143
+ total_output_tokens?: number;
144
+ total_cached_tokens?: number;
145
+ total_thought_tokens?: number;
146
+ total_tool_use_tokens?: number;
147
+ total_tokens?: number;
148
+ }
149
+ interface WireInteraction {
150
+ id?: string;
151
+ status?: string;
152
+ usage?: WireUsage | null;
153
+ }
154
+ interface WireError {
155
+ code?: string;
156
+ message?: string;
157
+ }
158
+ interface WireStreamEvent {
159
+ event_type?: string;
160
+ index?: number;
161
+ step?: WireStepData;
162
+ delta?: WireDelta;
163
+ interaction?: WireInteraction;
164
+ error?: WireError;
165
+ }
166
+ //#endregion
167
+ //#region src/protocol.d.ts
168
+ declare const GEMINI_INTERACTIONS_PROTOCOL_ID = "gemini-interactions";
169
+ interface GeminiInteractionsProtocolDefinition {
170
+ readonly kind: 'http-wire-protocol';
171
+ readonly apiVersion: 1;
172
+ readonly id: string;
173
+ readonly defaultDialect: GeminiInteractionsDialect;
174
+ readonly endpointPath: () => '/interactions';
175
+ readonly serialize: (request: ProtocolRequest, dialect: GeminiInteractionsDialect) => Readonly<Record<string, unknown>>;
176
+ readonly translate: (events: AsyncIterable<ProtocolSseEvent>, request: ProtocolRequest, displayName: string) => AsyncGenerator<ProtocolStreamChunk>;
177
+ }
178
+ declare const geminiInteractionsProtocol: ProtocolDefinition<GeminiInteractionsDialect> & GeminiInteractionsProtocolDefinition;
179
+ //#endregion
180
+ //#region src/serialize.d.ts
181
+ declare function serializeGeminiInteractionsRequest(request: ProtocolRequest, dialect: GeminiInteractionsDialect): WireRequest;
182
+ //#endregion
183
+ //#region src/translate.d.ts
184
+ declare function translateGeminiInteractionsStream(events: AsyncIterable<ProtocolSseEvent>, displayName: string, _request?: ProtocolRequest): AsyncGenerator<ProtocolStreamChunk>;
185
+ //#endregion
186
+ export { GEMINI_INTERACTIONS_PROTOCOL_ID, type GeminiInteractionsDialect, type GeminiInteractionsProtocolDefinition, type GeminiThoughtState, type ProtocolDefinition, type ProtocolRequest, type ProtocolSseEvent, type ProtocolStreamChunk, type WireAnnotation, type WireContent, type WireDelta, type WireError, type WireFunctionTool, type WireGenerationConfig, type WireGoogleSearchTool, type WireImageContent, type WireInteraction, type WireRequest, type WireResponseFormat, type WireStep, type WireStepData, type WireStreamEvent, type WireTextContent, type WireTool, type WireToolChoice, type WireUsage, geminiInteractionsProtocol, serializeGeminiInteractionsRequest, translateGeminiInteractionsStream };
187
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/contract.ts","../src/wire.ts","../src/protocol.ts","../src/serialize.ts","../src/translate.ts"],"mappings":";;UAEiB;WACN,SAAS;WACT;;UAGM;WACN;WACA;;KAGC,sBACR,QAAQ;WAAwB;;WACrB;WAAwB,OAAO;;UAE7B,mBAAmB;WACzB;WACA,gBAAgB;EACzB,aAAa,SAAS,iBAAiB,SAAS;EAChD,iBAAiB,SAAS,UAAU;EACpC,UAAU,SAAS,iBAAiB,SAAS,oBAAoB;EACjE,UACE,QAAQ,cAAc,mBACtB,SAAS,iBACT,sBACC,eAAe;;;;UC1BH;;WAEN;;WAEA;;UAGM;EACf;EACA;EACA,cAAc;;UAGC;EACf;EACA;EACA;EACA;EACA;;KAGU,cAAc,kBAAkB;KAEhC;EACN;EAAoB,SAAS;;EAC7B;EAAsB,SAAS;;EAC/B;EAAiB;EAAoB,UAAU;;EAC/C;EAAuB;EAAY;EAAc,WAAW;;EAE9D;EACA;EACA;EACA,iBAAiB,0BAA0B;EAC3C;;UAGa;EACf;EACA;EACA;EACA,YAAY,SAAS;;UAGN;EACf;EACA;;KAGU,WAAW,mBAAmB;KAE9B;EAKR;IACE;IACA;;;UAIW;EACf;EACA;EACA;EACA;EACA;EACA;EACA,cAAc;;KAGJ;EACN;EAAc;;EAEhB;EACA;EACA,QAAQ,SAAS;;UAGJ;EACf;EACA,OAAO;EACP;EACA,QAAQ;EACR,kBAAkB;EAClB;EACA;EACA,mBAAmB;;UAGJ;EACf;EACA,mBAAmB;;UAGJ;EACf;EACA;EACA;EACA;EACA;GACC;;UAGc;EACf;EACA;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA;EACA;EACA;EACA;;UAGe;EACf;EACA;EACA,QAAQ;;UAGO;EACf;EACA;;UAGe;EACf;EACA;EACA,OAAO;EACP,QAAQ;EACR,cAAc;EACd,QAAQ;;;;cChJG;UAOI;WACN;WACA;WACA;WACA,gBAAgB;WAChB;WACA,YACP,SAAS,iBACT,SAAS,8BACN,SAAS;WACL,YACP,QAAQ,cAAc,mBACtB,SAAS,iBACT,wBACG,eAAe;;cAGT,4BAA4B,mBAAmB,6BACxD;;;iBCwOY,mCACd,SAAS,iBACT,SAAS,4BACR;;;iBCnFoB,kCACrB,QAAQ,cAAc,mBACtB,qBACA,WAAW,kBACV,eAAe"}
package/dist/index.js ADDED
@@ -0,0 +1,465 @@
1
+ import { CONTEXT_WINDOW_EXCEEDED_CODE, MODEL_ERROR_CODES, ModelError, QUOTA_EXCEEDED_CODE, ToolCallId, isNativeToolSchema } from "@alvin0/ai-agent-sdk-core";
2
+
3
+ //#region src/serialize.ts
4
+ function imageContent(block) {
5
+ const resolution = block.detail === "low" || block.detail === "high" ? block.detail : void 0;
6
+ if (block.source.kind === "base64") return {
7
+ type: "image",
8
+ data: block.source.data,
9
+ mime_type: block.source.mediaType,
10
+ ...resolution === void 0 ? {} : { resolution }
11
+ };
12
+ return {
13
+ type: "image",
14
+ uri: block.source.kind === "url" ? block.source.url : block.source.fileId,
15
+ ...resolution === void 0 ? {} : { resolution }
16
+ };
17
+ }
18
+ function annotationOf(annotation) {
19
+ if (annotation.type !== "url-citation") return void 0;
20
+ return {
21
+ type: "url_citation",
22
+ url: annotation.url,
23
+ ...annotation.title === void 0 ? {} : { title: annotation.title },
24
+ ...annotation.startIndex === void 0 ? {} : { start_index: annotation.startIndex },
25
+ ...annotation.endIndex === void 0 ? {} : { end_index: annotation.endIndex }
26
+ };
27
+ }
28
+ function contentOf(block) {
29
+ if (block.type === "text") {
30
+ const annotations = block.annotations?.map(annotationOf).filter((item) => item !== void 0);
31
+ return {
32
+ type: "text",
33
+ text: block.text,
34
+ ...annotations === void 0 || annotations.length === 0 ? {} : { annotations }
35
+ };
36
+ }
37
+ if (block.type === "image") return imageContent(block);
38
+ }
39
+ function thoughtStateOf(value) {
40
+ if (typeof value !== "object" || value === null) return {};
41
+ const state = value;
42
+ return {
43
+ ...typeof state.signature === "string" ? { signature: state.signature } : {},
44
+ ...Array.isArray(state.summary) ? { summary: structuredClone(state.summary) } : {}
45
+ };
46
+ }
47
+ function argumentsObject(raw) {
48
+ if (raw.length === 0) return {};
49
+ let value;
50
+ try {
51
+ value = JSON.parse(raw);
52
+ } catch (error) {
53
+ throw new ModelError("Gemini Interactions requires function-call arguments to be a JSON object", MODEL_ERROR_CODES.INVALID_REQUEST, { cause: error });
54
+ }
55
+ if (typeof value !== "object" || value === null || Array.isArray(value)) throw new ModelError("Gemini Interactions requires function-call arguments to be a JSON object", MODEL_ERROR_CODES.INVALID_REQUEST);
56
+ return value;
57
+ }
58
+ function toolResult(block, toolNames) {
59
+ const contents = block.content.map(contentOf).filter((item) => item !== void 0);
60
+ const name = toolNames.get(block.toolCallId);
61
+ return {
62
+ type: "function_result",
63
+ call_id: block.toolCallId,
64
+ ...name === void 0 ? {} : { name },
65
+ result: contents,
66
+ ...block.isError === void 0 ? {} : { is_error: block.isError }
67
+ };
68
+ }
69
+ function appendUserMessage(message, output, toolNames) {
70
+ let content = [];
71
+ const flush = () => {
72
+ if (content.length === 0) return;
73
+ output.push({
74
+ type: "user_input",
75
+ content
76
+ });
77
+ content = [];
78
+ };
79
+ for (const block of message.content) {
80
+ if (block.type === "tool-result") {
81
+ flush();
82
+ output.push(toolResult(block, toolNames));
83
+ continue;
84
+ }
85
+ const mapped = contentOf(block);
86
+ if (mapped !== void 0) content.push(mapped);
87
+ }
88
+ flush();
89
+ }
90
+ function appendAssistantMessage(message, output) {
91
+ let content = [];
92
+ const flush = () => {
93
+ if (content.length === 0) return;
94
+ output.push({
95
+ type: "model_output",
96
+ content
97
+ });
98
+ content = [];
99
+ };
100
+ for (const block of message.content) {
101
+ if (block.type === "text" || block.type === "image") {
102
+ const mapped = contentOf(block);
103
+ if (mapped !== void 0) content.push(mapped);
104
+ continue;
105
+ }
106
+ flush();
107
+ if (block.type === "reasoning") {
108
+ const state = thoughtStateOf(block.providerState);
109
+ const summary = state.summary ?? (block.text.length === 0 ? void 0 : [{
110
+ type: "text",
111
+ text: block.text
112
+ }]);
113
+ output.push({
114
+ type: "thought",
115
+ ...state.signature === void 0 ? {} : { signature: state.signature },
116
+ ...summary === void 0 || summary.length === 0 ? {} : { summary: [...summary] }
117
+ });
118
+ } else if (block.type === "tool-call") output.push({
119
+ type: "function_call",
120
+ id: block.id,
121
+ name: block.name,
122
+ arguments: argumentsObject(block.arguments)
123
+ });
124
+ }
125
+ flush();
126
+ }
127
+ function inputOf(request) {
128
+ const output = [];
129
+ const toolNames = /* @__PURE__ */ new Map();
130
+ for (const message of request.options.messages) for (const block of message.content) if (block.type === "tool-call") toolNames.set(block.id, block.name);
131
+ for (const message of request.options.messages) {
132
+ if (message.role === "system") continue;
133
+ if (message.role === "assistant") appendAssistantMessage(message, output);
134
+ else appendUserMessage(message, output, toolNames);
135
+ }
136
+ return output;
137
+ }
138
+ function systemInstructionOf(request) {
139
+ const messages = request.options.messages.filter((message) => message.role === "system").flatMap((message) => message.content).filter((block) => block.type === "text").map((block) => block.text);
140
+ return [request.options.system, ...messages].filter((value) => value !== void 0 && value.length > 0).join("\n\n");
141
+ }
142
+ function functionTool(tool) {
143
+ return {
144
+ type: "function",
145
+ name: tool.name,
146
+ description: tool.description,
147
+ parameters: tool.parameters
148
+ };
149
+ }
150
+ function googleSearchTool(tool) {
151
+ if (tool.searchContextSize !== void 0 || tool.allowedDomains !== void 0 || tool.blockedDomains !== void 0 || tool.userLocation !== void 0 || tool.maxUses !== void 0) throw new ModelError("Gemini Interactions web search does not support SDK search filters or limits", MODEL_ERROR_CODES.INVALID_REQUEST);
152
+ return {
153
+ type: "google_search",
154
+ search_types: ["web_search"]
155
+ };
156
+ }
157
+ function toolOf(tool) {
158
+ if (!isNativeToolSchema(tool)) return functionTool(tool);
159
+ if (tool.name === "web-search") return googleSearchTool(tool);
160
+ throw new ModelError("Gemini Interactions does not expose image generation as an SDK native tool", MODEL_ERROR_CODES.INVALID_REQUEST);
161
+ }
162
+ function toolChoiceOf(choice) {
163
+ if (choice === "required") return "any";
164
+ if (typeof choice === "string") return choice;
165
+ return { allowed_tools: {
166
+ mode: "any",
167
+ tools: [choice.type === "native" && choice.name === "web-search" ? "google_search" : choice.name]
168
+ } };
169
+ }
170
+ function responseFormatOf(format) {
171
+ if (format === void 0) return void 0;
172
+ if (format.type === "text") return {
173
+ type: "text",
174
+ mime_type: "text/plain"
175
+ };
176
+ return {
177
+ type: "text",
178
+ mime_type: "application/json",
179
+ schema: format.schema
180
+ };
181
+ }
182
+ function generationConfigOf(request, dialect) {
183
+ const options = request.options;
184
+ return {
185
+ max_output_tokens: request.maxTokens,
186
+ ...options.temperature === void 0 ? {} : { temperature: options.temperature },
187
+ ...options.topP === void 0 ? {} : { top_p: options.topP },
188
+ ...options.stop === void 0 || options.stop.length === 0 ? {} : { stop_sequences: [...options.stop] },
189
+ ...options.reasoningEffort === void 0 ? {} : {
190
+ thinking_level: String(options.reasoningEffort),
191
+ thinking_summaries: dialect.thinkingSummaries
192
+ },
193
+ ...options.toolChoice === void 0 ? {} : { tool_choice: toolChoiceOf(options.toolChoice) }
194
+ };
195
+ }
196
+ function serializeGeminiInteractionsRequest(request, dialect) {
197
+ const systemInstruction = systemInstructionOf(request);
198
+ const tools = request.options.tools?.map(toolOf);
199
+ const responseFormat = responseFormatOf(request.options.outputFormat);
200
+ return {
201
+ model: request.options.model,
202
+ input: inputOf(request),
203
+ ...systemInstruction.length === 0 ? {} : { system_instruction: systemInstruction },
204
+ ...tools === void 0 || tools.length === 0 ? {} : { tools },
205
+ ...responseFormat === void 0 ? {} : { response_format: responseFormat },
206
+ stream: true,
207
+ store: dialect.store,
208
+ generation_config: generationConfigOf(request, dialect)
209
+ };
210
+ }
211
+
212
+ //#endregion
213
+ //#region src/translate.ts
214
+ function stepKind(type) {
215
+ if (type === "model_output") return "text";
216
+ if (type === "thought") return "reasoning";
217
+ if (type === "function_call") return "tool-call";
218
+ }
219
+ function contentList(value) {
220
+ if (!Array.isArray(value)) return [];
221
+ return value.filter((item) => typeof item === "object" && item !== null && (item.type === "text" || item.type === "image"));
222
+ }
223
+ function textOf(contents) {
224
+ return contents.filter((item) => item.type === "text").map((item) => item.text).join("");
225
+ }
226
+ function annotationsOf(value) {
227
+ if (!Array.isArray(value)) return [];
228
+ return value.flatMap((item) => {
229
+ if (typeof item !== "object" || item === null) return [];
230
+ const annotation = item;
231
+ if (annotation.type !== "url_citation" || typeof annotation.url !== "string") return [];
232
+ return [{
233
+ type: "url-citation",
234
+ url: annotation.url,
235
+ ...typeof annotation.title === "string" ? { title: annotation.title } : {},
236
+ ...typeof annotation.start_index === "number" ? { startIndex: annotation.start_index } : {},
237
+ ...typeof annotation.end_index === "number" ? { endIndex: annotation.end_index } : {},
238
+ providerState: structuredClone(annotation)
239
+ }];
240
+ });
241
+ }
242
+ function contentAnnotations(contents) {
243
+ return contents.flatMap((item) => item.type === "text" ? annotationsOf(item.annotations) : []);
244
+ }
245
+ function createOpenStep(step, index) {
246
+ const kind = stepKind(step.type);
247
+ if (kind === void 0) return void 0;
248
+ const content = contentList(step.content);
249
+ const summary = contentList(step.summary);
250
+ return {
251
+ index,
252
+ kind,
253
+ text: kind === "text" ? textOf(content) : kind === "reasoning" ? textOf(summary) : "",
254
+ arguments: "",
255
+ initialArguments: step.arguments,
256
+ callId: step.id ?? `call-${index}`,
257
+ name: step.name ?? "",
258
+ signature: step.signature,
259
+ summary,
260
+ annotations: contentAnnotations(content)
261
+ };
262
+ }
263
+ function blockOf(step) {
264
+ if (step.kind === "text") return {
265
+ type: "text",
266
+ text: step.text,
267
+ ...step.annotations.length === 0 ? {} : { annotations: step.annotations }
268
+ };
269
+ if (step.kind === "reasoning") {
270
+ const state = {
271
+ ...step.signature === void 0 ? {} : { signature: step.signature },
272
+ ...step.summary.length === 0 ? {} : { summary: step.summary }
273
+ };
274
+ return {
275
+ type: "reasoning",
276
+ text: step.text,
277
+ providerState: state
278
+ };
279
+ }
280
+ const argumentsText = step.arguments.length > 0 ? step.arguments : jsonArguments(step.initialArguments);
281
+ return {
282
+ type: "tool-call",
283
+ id: ToolCallId(step.callId),
284
+ name: step.name,
285
+ arguments: argumentsText
286
+ };
287
+ }
288
+ function jsonArguments(value) {
289
+ if (typeof value !== "object" || value === null || Array.isArray(value)) return "{}";
290
+ return JSON.stringify(value);
291
+ }
292
+ function thoughtSummaryContent(value) {
293
+ if (Array.isArray(value)) return contentList(value);
294
+ if (typeof value === "object" && value !== null) return contentList([value]);
295
+ return [];
296
+ }
297
+ function mapUsage(usage) {
298
+ const source = usage;
299
+ const rawInput = source.total_input_tokens;
300
+ const visibleOutput = source.total_output_tokens;
301
+ const cached = source.total_cached_tokens;
302
+ const reasoning = source.total_thought_tokens;
303
+ const total = source.total_tokens;
304
+ if ([
305
+ rawInput,
306
+ visibleOutput,
307
+ cached,
308
+ reasoning,
309
+ total
310
+ ].every((value) => value === void 0)) return void 0;
311
+ const output = typeof visibleOutput === "number" && typeof reasoning === "number" ? visibleOutput + reasoning : visibleOutput;
312
+ const normalized = {
313
+ ...output === void 0 ? {} : { outputTokens: output },
314
+ ...total === void 0 ? {} : { totalTokens: total },
315
+ ...cached === void 0 || cached === 0 ? {} : { cacheReadTokens: cached },
316
+ ...reasoning === void 0 || reasoning === 0 ? {} : { reasoningTokens: reasoning }
317
+ };
318
+ if (rawInput !== void 0) normalized.inputTokens = typeof rawInput === "number" && (cached === void 0 || typeof cached === "number") ? rawInput - (cached ?? 0) : rawInput;
319
+ return normalized;
320
+ }
321
+ function errorCode(code, message) {
322
+ const joined = `${code ?? ""} ${message}`.toLowerCase();
323
+ if (/context|token limit|too many tokens/.test(joined)) return CONTEXT_WINDOW_EXCEEDED_CODE;
324
+ if (/quota|resource_exhausted/.test(joined)) return QUOTA_EXCEEDED_CODE;
325
+ if (/invalid_argument|bad request/.test(joined)) return MODEL_ERROR_CODES.INVALID_REQUEST;
326
+ if (/rate|too many requests/.test(joined)) return MODEL_ERROR_CODES.RATE_LIMIT;
327
+ return MODEL_ERROR_CODES.SERVER;
328
+ }
329
+ function streamError(event, displayName) {
330
+ const message = event.error?.message ?? `${displayName} reported a streaming error`;
331
+ return new ModelError(message, errorCode(event.error?.code, message));
332
+ }
333
+ function finishReason(interaction, sawToolCall) {
334
+ const status = interaction?.status;
335
+ if (status === "requires_action" || sawToolCall) return { kind: "tool-calls" };
336
+ if (status === "incomplete" || status === "budget_exceeded") return { kind: "max-tokens" };
337
+ return { kind: "stop" };
338
+ }
339
+ async function* translateGeminiInteractionsStream(events, displayName, _request) {
340
+ const open = /* @__PURE__ */ new Map();
341
+ let nextIndex = 0;
342
+ let sawToolCall = false;
343
+ for await (const raw of events) {
344
+ if (raw.data === "[DONE]") continue;
345
+ let event;
346
+ try {
347
+ event = JSON.parse(raw.data);
348
+ } catch (error) {
349
+ throw new ModelError(`${displayName} sent a malformed stream event`, MODEL_ERROR_CODES.MALFORMED_RESPONSE, { cause: error });
350
+ }
351
+ const eventType = event.event_type ?? raw.event;
352
+ if (eventType === "step.start") {
353
+ if (event.index === void 0 || event.step === void 0 || open.has(event.index)) continue;
354
+ const step = createOpenStep(event.step, nextIndex++);
355
+ if (step === void 0) continue;
356
+ open.set(event.index, step);
357
+ if (step.kind === "tool-call") sawToolCall = true;
358
+ yield {
359
+ type: "block-start",
360
+ index: step.index,
361
+ blockType: step.kind
362
+ };
363
+ if (step.text.length > 0) yield step.kind === "reasoning" ? {
364
+ type: "reasoning-delta",
365
+ index: step.index,
366
+ text: step.text
367
+ } : {
368
+ type: "text-delta",
369
+ index: step.index,
370
+ text: step.text
371
+ };
372
+ continue;
373
+ }
374
+ if (eventType === "step.delta") {
375
+ const step = event.index === void 0 ? void 0 : open.get(event.index);
376
+ if (step === void 0 || event.delta === void 0) continue;
377
+ const delta = event.delta;
378
+ if (delta.type === "text" && typeof delta.text === "string" && step.kind === "text") {
379
+ step.text += delta.text;
380
+ yield {
381
+ type: "text-delta",
382
+ index: step.index,
383
+ text: delta.text
384
+ };
385
+ } else if (delta.type === "arguments_delta" && typeof delta.arguments === "string" && step.kind === "tool-call") {
386
+ step.arguments += delta.arguments;
387
+ yield {
388
+ type: "tool-call-delta",
389
+ index: step.index,
390
+ id: ToolCallId(step.callId),
391
+ ...step.name.length === 0 ? {} : { name: step.name },
392
+ argumentsDelta: delta.arguments
393
+ };
394
+ } else if (delta.type === "thought_signature" && typeof delta.signature === "string" && step.kind === "reasoning") step.signature = delta.signature;
395
+ else if (delta.type === "thought_summary" && step.kind === "reasoning") {
396
+ const content = thoughtSummaryContent(delta.content);
397
+ const text = textOf(content);
398
+ step.summary.push(...content);
399
+ step.text += text;
400
+ if (text.length > 0) yield {
401
+ type: "reasoning-delta",
402
+ index: step.index,
403
+ text
404
+ };
405
+ } else if (delta.type === "text_annotation_delta" && step.kind === "text") step.annotations.push(...annotationsOf(delta.annotations));
406
+ continue;
407
+ }
408
+ if (eventType === "step.stop") {
409
+ const step = event.index === void 0 ? void 0 : open.get(event.index);
410
+ if (step === void 0) continue;
411
+ yield {
412
+ type: "block-end",
413
+ index: step.index,
414
+ block: blockOf(step)
415
+ };
416
+ open.delete(event.index);
417
+ continue;
418
+ }
419
+ if (eventType === "error") throw streamError(event, displayName);
420
+ if (eventType === "interaction.completed") {
421
+ const interaction = event.interaction;
422
+ if (interaction?.status === "failed" || interaction?.status === "cancelled") throw new ModelError(`${displayName} interaction ${interaction.status}`, MODEL_ERROR_CODES.SERVER);
423
+ for (const step of open.values()) yield {
424
+ type: "block-end",
425
+ index: step.index,
426
+ block: blockOf(step)
427
+ };
428
+ const usage = interaction?.usage ?? void 0;
429
+ const mapped = usage === void 0 ? void 0 : mapUsage(usage);
430
+ if (mapped !== void 0) yield {
431
+ type: "usage",
432
+ usage: mapped
433
+ };
434
+ yield {
435
+ type: "finish",
436
+ reason: finishReason(interaction, sawToolCall)
437
+ };
438
+ return;
439
+ }
440
+ }
441
+ throw new ModelError(`${displayName} stream ended before the interaction completed`, MODEL_ERROR_CODES.STREAM_CLOSED);
442
+ }
443
+
444
+ //#endregion
445
+ //#region src/protocol.ts
446
+ const GEMINI_INTERACTIONS_PROTOCOL_ID = "gemini-interactions";
447
+ const DEFAULT_DIALECT = Object.freeze({
448
+ store: false,
449
+ thinkingSummaries: "auto"
450
+ });
451
+ const geminiInteractionsProtocol = Object.freeze({
452
+ kind: "http-wire-protocol",
453
+ apiVersion: 1,
454
+ id: GEMINI_INTERACTIONS_PROTOCOL_ID,
455
+ defaultDialect: DEFAULT_DIALECT,
456
+ endpointPath: () => "/interactions",
457
+ serialize(request, dialect) {
458
+ return serializeGeminiInteractionsRequest(request, dialect);
459
+ },
460
+ translate: (events, request, displayName) => translateGeminiInteractionsStream(events, displayName, request)
461
+ });
462
+
463
+ //#endregion
464
+ export { GEMINI_INTERACTIONS_PROTOCOL_ID, geminiInteractionsProtocol, serializeGeminiInteractionsRequest, translateGeminiInteractionsStream };
465
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../src/serialize.ts","../src/translate.ts","../src/protocol.ts"],"sourcesContent":["import {\n isNativeToolSchema,\n MODEL_ERROR_CODES,\n ModelError,\n type ContentBlock,\n type ImageBlock,\n type Message,\n type ModelOutputFormat,\n type ModelToolSchema,\n type NativeWebSearchTool,\n type TextAnnotation,\n type ToolChoice,\n type ToolSchema,\n} from '@alvin0/ai-agent-sdk-core'\nimport type { ProtocolRequest } from './contract.ts'\nimport type {\n GeminiInteractionsDialect,\n GeminiThoughtState,\n WireContent,\n WireGenerationConfig,\n WireRequest,\n WireResponseFormat,\n WireStep,\n WireTool,\n WireToolChoice,\n} from './wire.ts'\n\nfunction imageContent(block: ImageBlock): WireContent {\n const resolution = block.detail === 'low' || block.detail === 'high'\n ? block.detail\n : undefined\n if (block.source.kind === 'base64') {\n return {\n type: 'image', data: block.source.data, mime_type: block.source.mediaType,\n ...(resolution === undefined ? {} : { resolution }),\n }\n }\n return {\n type: 'image', uri: block.source.kind === 'url' ? block.source.url : block.source.fileId,\n ...(resolution === undefined ? {} : { resolution }),\n }\n}\n\nfunction annotationOf(annotation: TextAnnotation) {\n if (annotation.type !== 'url-citation') return undefined\n return {\n type: 'url_citation',\n url: annotation.url,\n ...(annotation.title === undefined ? {} : { title: annotation.title }),\n ...(annotation.startIndex === undefined ? {} : { start_index: annotation.startIndex }),\n ...(annotation.endIndex === undefined ? {} : { end_index: annotation.endIndex }),\n }\n}\n\nfunction contentOf(block: ContentBlock): WireContent | undefined {\n if (block.type === 'text') {\n const annotations = block.annotations?.map(annotationOf)\n .filter((item): item is NonNullable<typeof item> => item !== undefined)\n return {\n type: 'text', text: block.text,\n ...(annotations === undefined || annotations.length === 0 ? {} : { annotations }),\n }\n }\n if (block.type === 'image') return imageContent(block)\n return undefined\n}\n\nfunction thoughtStateOf(value: unknown): GeminiThoughtState {\n if (typeof value !== 'object' || value === null) return {}\n const state = value as GeminiThoughtState\n return {\n ...(typeof state.signature === 'string' ? { signature: state.signature } : {}),\n ...(Array.isArray(state.summary) ? { summary: structuredClone(state.summary) } : {}),\n }\n}\n\nfunction argumentsObject(raw: string): Record<string, unknown> {\n if (raw.length === 0) return {}\n let value: unknown\n try {\n value = JSON.parse(raw)\n } catch (error: unknown) {\n throw new ModelError(\n 'Gemini Interactions requires function-call arguments to be a JSON object',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n { cause: error },\n )\n }\n if (typeof value !== 'object' || value === null || Array.isArray(value)) {\n throw new ModelError(\n 'Gemini Interactions requires function-call arguments to be a JSON object',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n }\n return value as Record<string, unknown>\n}\n\nfunction toolResult(\n block: Extract<ContentBlock, { type: 'tool-result' }>,\n toolNames: ReadonlyMap<string, string>,\n): WireStep {\n const contents = block.content.map(contentOf)\n .filter((item): item is WireContent => item !== undefined)\n const name = toolNames.get(block.toolCallId)\n return {\n type: 'function_result',\n call_id: block.toolCallId,\n ...(name === undefined ? {} : { name }),\n result: contents,\n ...(block.isError === undefined ? {} : { is_error: block.isError }),\n }\n}\n\nfunction appendUserMessage(\n message: Message,\n output: WireStep[],\n toolNames: ReadonlyMap<string, string>,\n): void {\n let content: WireContent[] = []\n const flush = (): void => {\n if (content.length === 0) return\n output.push({ type: 'user_input', content })\n content = []\n }\n for (const block of message.content) {\n if (block.type === 'tool-result') {\n flush()\n output.push(toolResult(block, toolNames))\n continue\n }\n const mapped = contentOf(block)\n if (mapped !== undefined) content.push(mapped)\n }\n flush()\n}\n\nfunction appendAssistantMessage(message: Message, output: WireStep[]): void {\n let content: WireContent[] = []\n const flush = (): void => {\n if (content.length === 0) return\n output.push({ type: 'model_output', content })\n content = []\n }\n for (const block of message.content) {\n if (block.type === 'text' || block.type === 'image') {\n const mapped = contentOf(block)\n if (mapped !== undefined) content.push(mapped)\n continue\n }\n flush()\n if (block.type === 'reasoning') {\n const state = thoughtStateOf(block.providerState)\n const summary = state.summary ?? (block.text.length === 0\n ? undefined\n : [{ type: 'text' as const, text: block.text }])\n output.push({\n type: 'thought',\n ...(state.signature === undefined ? {} : { signature: state.signature }),\n ...(summary === undefined || summary.length === 0 ? {} : { summary: [...summary] }),\n })\n } else if (block.type === 'tool-call') {\n output.push({\n type: 'function_call', id: block.id, name: block.name,\n arguments: argumentsObject(block.arguments),\n })\n }\n }\n flush()\n}\n\nfunction inputOf(request: ProtocolRequest): WireStep[] {\n const output: WireStep[] = []\n const toolNames = new Map<string, string>()\n for (const message of request.options.messages) {\n for (const block of message.content) {\n if (block.type === 'tool-call') toolNames.set(block.id, block.name)\n }\n }\n for (const message of request.options.messages) {\n if (message.role === 'system') continue\n if (message.role === 'assistant') appendAssistantMessage(message, output)\n else appendUserMessage(message, output, toolNames)\n }\n return output\n}\n\nfunction systemInstructionOf(request: ProtocolRequest): string {\n const messages = request.options.messages\n .filter(message => message.role === 'system')\n .flatMap(message => message.content)\n .filter((block): block is Extract<ContentBlock, { type: 'text' }> => block.type === 'text')\n .map(block => block.text)\n return [request.options.system, ...messages]\n .filter((value): value is string => value !== undefined && value.length > 0)\n .join('\\n\\n')\n}\n\nfunction functionTool(tool: ToolSchema): WireTool {\n return {\n type: 'function', name: tool.name, description: tool.description,\n parameters: tool.parameters,\n }\n}\n\nfunction googleSearchTool(tool: NativeWebSearchTool): WireTool {\n if (tool.searchContextSize !== undefined || tool.allowedDomains !== undefined\n || tool.blockedDomains !== undefined || tool.userLocation !== undefined\n || tool.maxUses !== undefined) {\n throw new ModelError(\n 'Gemini Interactions web search does not support SDK search filters or limits',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n }\n return { type: 'google_search', search_types: ['web_search'] }\n}\n\nfunction toolOf(tool: ModelToolSchema): WireTool {\n if (!isNativeToolSchema(tool)) return functionTool(tool)\n if (tool.name === 'web-search') return googleSearchTool(tool)\n throw new ModelError(\n 'Gemini Interactions does not expose image generation as an SDK native tool',\n MODEL_ERROR_CODES.INVALID_REQUEST,\n )\n}\n\nfunction toolChoiceOf(choice: ToolChoice): WireToolChoice {\n if (choice === 'required') return 'any'\n if (typeof choice === 'string') return choice\n const name = choice.type === 'native' && choice.name === 'web-search'\n ? 'google_search'\n : choice.name\n return { allowed_tools: { mode: 'any', tools: [name] } }\n}\n\nfunction responseFormatOf(format: ModelOutputFormat | undefined): WireResponseFormat | undefined {\n if (format === undefined) return undefined\n if (format.type === 'text') return { type: 'text', mime_type: 'text/plain' }\n return { type: 'text', mime_type: 'application/json', schema: format.schema }\n}\n\nfunction generationConfigOf(\n request: ProtocolRequest,\n dialect: GeminiInteractionsDialect,\n): WireGenerationConfig {\n const options = request.options\n return {\n max_output_tokens: request.maxTokens,\n ...(options.temperature === undefined ? {} : { temperature: options.temperature }),\n ...(options.topP === undefined ? {} : { top_p: options.topP }),\n ...(options.stop === undefined || options.stop.length === 0\n ? {}\n : { stop_sequences: [...options.stop] }),\n ...(options.reasoningEffort === undefined\n ? {}\n : {\n thinking_level: String(options.reasoningEffort),\n thinking_summaries: dialect.thinkingSummaries,\n }),\n ...(options.toolChoice === undefined ? {} : { tool_choice: toolChoiceOf(options.toolChoice) }),\n }\n}\n\nexport function serializeGeminiInteractionsRequest(\n request: ProtocolRequest,\n dialect: GeminiInteractionsDialect,\n): WireRequest {\n const systemInstruction = systemInstructionOf(request)\n const tools = request.options.tools?.map(toolOf)\n const responseFormat = responseFormatOf(request.options.outputFormat)\n return {\n model: request.options.model,\n input: inputOf(request),\n ...(systemInstruction.length === 0 ? {} : { system_instruction: systemInstruction }),\n ...(tools === undefined || tools.length === 0 ? {} : { tools }),\n ...(responseFormat === undefined ? {} : { response_format: responseFormat }),\n stream: true,\n store: dialect.store,\n generation_config: generationConfigOf(request, dialect),\n }\n}\n","import {\n CONTEXT_WINDOW_EXCEEDED_CODE,\n MODEL_ERROR_CODES,\n ModelError,\n QUOTA_EXCEEDED_CODE,\n ToolCallId,\n type ContentBlock,\n type FinishReason,\n type TextAnnotation,\n type UsageCounters,\n} from '@alvin0/ai-agent-sdk-core'\nimport type { ProtocolRequest, ProtocolSseEvent, ProtocolStreamChunk } from './contract.ts'\nimport type {\n GeminiThoughtState,\n WireAnnotation,\n WireContent,\n WireInteraction,\n WireStepData,\n WireStreamEvent,\n WireUsage,\n} from './wire.ts'\n\ntype StepKind = 'text' | 'reasoning' | 'tool-call'\n\ninterface OpenStep {\n readonly index: number\n readonly kind: StepKind\n text: string\n arguments: string\n readonly initialArguments: unknown\n callId: string\n name: string\n signature: string | undefined\n summary: WireContent[]\n annotations: TextAnnotation[]\n}\n\nfunction stepKind(type: string | undefined): StepKind | undefined {\n if (type === 'model_output') return 'text'\n if (type === 'thought') return 'reasoning'\n if (type === 'function_call') return 'tool-call'\n return undefined\n}\n\nfunction contentList(value: unknown): WireContent[] {\n if (!Array.isArray(value)) return []\n return value.filter((item): item is WireContent => typeof item === 'object' && item !== null\n && ((item as { type?: unknown }).type === 'text' || (item as { type?: unknown }).type === 'image'))\n}\n\nfunction textOf(contents: readonly WireContent[]): string {\n return contents.filter((item): item is Extract<WireContent, { type: 'text' }> => item.type === 'text')\n .map(item => item.text)\n .join('')\n}\n\nfunction annotationsOf(value: unknown): TextAnnotation[] {\n if (!Array.isArray(value)) return []\n return value.flatMap((item): TextAnnotation[] => {\n if (typeof item !== 'object' || item === null) return []\n const annotation = item as WireAnnotation\n if (annotation.type !== 'url_citation' || typeof annotation.url !== 'string') return []\n return [{\n type: 'url-citation',\n url: annotation.url,\n ...(typeof annotation.title === 'string' ? { title: annotation.title } : {}),\n ...(typeof annotation.start_index === 'number' ? { startIndex: annotation.start_index } : {}),\n ...(typeof annotation.end_index === 'number' ? { endIndex: annotation.end_index } : {}),\n providerState: structuredClone(annotation),\n }]\n })\n}\n\nfunction contentAnnotations(contents: readonly WireContent[]): TextAnnotation[] {\n return contents.flatMap(item => item.type === 'text' ? annotationsOf(item.annotations) : [])\n}\n\nfunction createOpenStep(step: WireStepData, index: number): OpenStep | undefined {\n const kind = stepKind(step.type)\n if (kind === undefined) return undefined\n const content = contentList(step.content)\n const summary = contentList(step.summary)\n return {\n index,\n kind,\n text: kind === 'text' ? textOf(content) : kind === 'reasoning' ? textOf(summary) : '',\n arguments: '',\n initialArguments: step.arguments,\n callId: step.id ?? `call-${index}`,\n name: step.name ?? '',\n signature: step.signature,\n summary,\n annotations: contentAnnotations(content),\n }\n}\n\nfunction blockOf(step: OpenStep): ContentBlock {\n if (step.kind === 'text') {\n return {\n type: 'text', text: step.text,\n ...(step.annotations.length === 0 ? {} : { annotations: step.annotations }),\n }\n }\n if (step.kind === 'reasoning') {\n const state: GeminiThoughtState = {\n ...(step.signature === undefined ? {} : { signature: step.signature }),\n ...(step.summary.length === 0 ? {} : { summary: step.summary }),\n }\n return { type: 'reasoning', text: step.text, providerState: state }\n }\n const argumentsText = step.arguments.length > 0\n ? step.arguments\n : jsonArguments(step.initialArguments)\n return {\n type: 'tool-call', id: ToolCallId(step.callId), name: step.name,\n arguments: argumentsText,\n }\n}\n\nfunction jsonArguments(value: unknown): string {\n if (typeof value !== 'object' || value === null || Array.isArray(value)) return '{}'\n return JSON.stringify(value)\n}\n\nfunction thoughtSummaryContent(value: unknown): WireContent[] {\n if (Array.isArray(value)) return contentList(value)\n if (typeof value === 'object' && value !== null) return contentList([value])\n return []\n}\n\nfunction mapUsage(usage: WireUsage): UsageCounters | undefined {\n const source = usage as unknown as Record<string, unknown>\n const rawInput = source.total_input_tokens\n const visibleOutput = source.total_output_tokens\n const cached = source.total_cached_tokens\n const reasoning = source.total_thought_tokens\n const total = source.total_tokens\n if ([rawInput, visibleOutput, cached, reasoning, total].every(value => value === undefined)) return undefined\n\n // Gemini reports thought tokens beside visible output, while the SDK models\n // reasoning as a subset of the full output bucket. Fold them into output once,\n // then retain the subset for cost breakdowns.\n const output = typeof visibleOutput === 'number' && typeof reasoning === 'number'\n ? visibleOutput + reasoning\n : visibleOutput\n\n const normalized: Record<string, unknown> = {\n ...(output === undefined ? {} : { outputTokens: output }),\n ...(total === undefined ? {} : { totalTokens: total }),\n ...(cached === undefined || cached === 0 ? {} : { cacheReadTokens: cached }),\n ...(reasoning === undefined || reasoning === 0 ? {} : { reasoningTokens: reasoning }),\n }\n if (rawInput !== undefined) {\n normalized.inputTokens = typeof rawInput === 'number'\n && (cached === undefined || typeof cached === 'number')\n ? rawInput - (cached ?? 0)\n : rawInput\n }\n return normalized as UsageCounters\n}\n\nfunction errorCode(code: string | undefined, message: string): string {\n const joined = `${code ?? ''} ${message}`.toLowerCase()\n if (/context|token limit|too many tokens/.test(joined)) return CONTEXT_WINDOW_EXCEEDED_CODE\n if (/quota|resource_exhausted/.test(joined)) return QUOTA_EXCEEDED_CODE\n if (/invalid_argument|bad request/.test(joined)) return MODEL_ERROR_CODES.INVALID_REQUEST\n if (/rate|too many requests/.test(joined)) return MODEL_ERROR_CODES.RATE_LIMIT\n return MODEL_ERROR_CODES.SERVER\n}\n\nfunction streamError(event: WireStreamEvent, displayName: string): ModelError {\n const message = event.error?.message ?? `${displayName} reported a streaming error`\n return new ModelError(message, errorCode(event.error?.code, message))\n}\n\nfunction finishReason(interaction: WireInteraction | undefined, sawToolCall: boolean): FinishReason {\n const status = interaction?.status\n if (status === 'requires_action' || sawToolCall) return { kind: 'tool-calls' }\n if (status === 'incomplete' || status === 'budget_exceeded') return { kind: 'max-tokens' }\n return { kind: 'stop' }\n}\n\nexport async function* translateGeminiInteractionsStream(\n events: AsyncIterable<ProtocolSseEvent>,\n displayName: string,\n _request?: ProtocolRequest,\n): AsyncGenerator<ProtocolStreamChunk> {\n const open = new Map<number, OpenStep>()\n let nextIndex = 0\n let sawToolCall = false\n\n for await (const raw of events) {\n if (raw.data === '[DONE]') continue\n let event: WireStreamEvent\n try {\n event = JSON.parse(raw.data) as WireStreamEvent\n } catch (error: unknown) {\n throw new ModelError(\n `${displayName} sent a malformed stream event`,\n MODEL_ERROR_CODES.MALFORMED_RESPONSE,\n { cause: error },\n )\n }\n const eventType = event.event_type ?? raw.event\n\n if (eventType === 'step.start') {\n if (event.index === undefined || event.step === undefined || open.has(event.index)) continue\n const step = createOpenStep(event.step, nextIndex++)\n if (step === undefined) continue\n open.set(event.index, step)\n if (step.kind === 'tool-call') sawToolCall = true\n yield { type: 'block-start', index: step.index, blockType: step.kind }\n if (step.text.length > 0) {\n yield step.kind === 'reasoning'\n ? { type: 'reasoning-delta', index: step.index, text: step.text }\n : { type: 'text-delta', index: step.index, text: step.text }\n }\n continue\n }\n\n if (eventType === 'step.delta') {\n const step = event.index === undefined ? undefined : open.get(event.index)\n if (step === undefined || event.delta === undefined) continue\n const delta = event.delta\n if (delta.type === 'text' && typeof delta.text === 'string' && step.kind === 'text') {\n step.text += delta.text\n yield { type: 'text-delta', index: step.index, text: delta.text }\n } else if (delta.type === 'arguments_delta' && typeof delta.arguments === 'string'\n && step.kind === 'tool-call') {\n step.arguments += delta.arguments\n yield {\n type: 'tool-call-delta', index: step.index, id: ToolCallId(step.callId),\n ...(step.name.length === 0 ? {} : { name: step.name }),\n argumentsDelta: delta.arguments,\n }\n } else if (delta.type === 'thought_signature' && typeof delta.signature === 'string'\n && step.kind === 'reasoning') {\n step.signature = delta.signature\n } else if (delta.type === 'thought_summary' && step.kind === 'reasoning') {\n const content = thoughtSummaryContent(delta.content)\n const text = textOf(content)\n step.summary.push(...content)\n step.text += text\n if (text.length > 0) yield { type: 'reasoning-delta', index: step.index, text }\n } else if (delta.type === 'text_annotation_delta' && step.kind === 'text') {\n step.annotations.push(...annotationsOf(delta.annotations))\n }\n continue\n }\n\n if (eventType === 'step.stop') {\n const step = event.index === undefined ? undefined : open.get(event.index)\n if (step === undefined) continue\n yield { type: 'block-end', index: step.index, block: blockOf(step) }\n open.delete(event.index!)\n continue\n }\n\n if (eventType === 'error') throw streamError(event, displayName)\n\n if (eventType === 'interaction.completed') {\n const interaction = event.interaction\n if (interaction?.status === 'failed' || interaction?.status === 'cancelled') {\n throw new ModelError(\n `${displayName} interaction ${interaction.status}`,\n MODEL_ERROR_CODES.SERVER,\n )\n }\n // Close any step defensively if a provider omitted its `step.stop` frame.\n for (const step of open.values()) {\n yield { type: 'block-end', index: step.index, block: blockOf(step) }\n }\n const usage = interaction?.usage ?? undefined\n const mapped = usage === undefined ? undefined : mapUsage(usage)\n if (mapped !== undefined) yield { type: 'usage', usage: mapped }\n yield { type: 'finish', reason: finishReason(interaction, sawToolCall) }\n return\n }\n }\n\n throw new ModelError(\n `${displayName} stream ended before the interaction completed`,\n MODEL_ERROR_CODES.STREAM_CLOSED,\n )\n}\n","import type { ProtocolDefinition, ProtocolRequest, ProtocolSseEvent, ProtocolStreamChunk } from './contract.ts'\nimport { serializeGeminiInteractionsRequest } from './serialize.ts'\nimport { translateGeminiInteractionsStream } from './translate.ts'\nimport type { GeminiInteractionsDialect } from './wire.ts'\n\nexport const GEMINI_INTERACTIONS_PROTOCOL_ID = 'gemini-interactions'\n\nconst DEFAULT_DIALECT: GeminiInteractionsDialect = Object.freeze({\n store: false,\n thinkingSummaries: 'auto',\n})\n\nexport interface GeminiInteractionsProtocolDefinition {\n readonly kind: 'http-wire-protocol'\n readonly apiVersion: 1\n readonly id: string\n readonly defaultDialect: GeminiInteractionsDialect\n readonly endpointPath: () => '/interactions'\n readonly serialize: (\n request: ProtocolRequest,\n dialect: GeminiInteractionsDialect,\n ) => Readonly<Record<string, unknown>>\n readonly translate: (\n events: AsyncIterable<ProtocolSseEvent>,\n request: ProtocolRequest,\n displayName: string,\n ) => AsyncGenerator<ProtocolStreamChunk>\n}\n\nexport const geminiInteractionsProtocol: ProtocolDefinition<GeminiInteractionsDialect>\n & GeminiInteractionsProtocolDefinition = Object.freeze({\n kind: 'http-wire-protocol' as const,\n apiVersion: 1 as const,\n id: GEMINI_INTERACTIONS_PROTOCOL_ID,\n defaultDialect: DEFAULT_DIALECT,\n endpointPath: () => '/interactions' as const,\n serialize(request: ProtocolRequest, dialect: GeminiInteractionsDialect): Readonly<Record<string, unknown>> {\n return serializeGeminiInteractionsRequest(request, dialect) as unknown as Readonly<Record<string, unknown>>\n },\n translate: (\n events: AsyncIterable<ProtocolSseEvent>,\n request: ProtocolRequest,\n displayName: string,\n ): AsyncGenerator<ProtocolStreamChunk> => translateGeminiInteractionsStream(events, displayName, request),\n})\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,70 @@
1
+ {
2
+ "name": "@alvin0/ai-agent-sdk-protocol-gemini-interactions",
3
+ "author": {
4
+ "name": "alvin0 - chaulamdinhai",
5
+ "email": "chaulamdinhai@gmail.com"
6
+ },
7
+ "version": "0.1.0",
8
+ "description": "Universal Gemini Interactions wire schema, serializer, and SSE translator for ai-agent-sdk",
9
+ "license": "MIT",
10
+ "repository": {
11
+ "type": "git",
12
+ "url": "git+https://github.com/alvin0/ai-agent-sdk.git",
13
+ "directory": "packages/protocol-gemini-interactions"
14
+ },
15
+ "homepage": "https://github.com/alvin0/ai-agent-sdk/tree/main/packages/protocol-gemini-interactions#readme",
16
+ "bugs": {
17
+ "url": "https://github.com/alvin0/ai-agent-sdk/issues"
18
+ },
19
+ "type": "module",
20
+ "sideEffects": false,
21
+ "files": [
22
+ "dist",
23
+ "README.md",
24
+ "LICENSE"
25
+ ],
26
+ "main": "./dist/index.js",
27
+ "types": "./dist/index.d.ts",
28
+ "exports": {
29
+ ".": {
30
+ "types": "./dist/index.d.ts",
31
+ "import": "./dist/index.js",
32
+ "default": "./dist/index.js"
33
+ },
34
+ "./package.json": "./package.json"
35
+ },
36
+ "publishConfig": {
37
+ "access": "public",
38
+ "provenance": true
39
+ },
40
+ "peerDependencies": {
41
+ "@alvin0/ai-agent-sdk-core": "^0.1.0"
42
+ },
43
+ "devDependencies": {
44
+ "@alvin0/ai-agent-sdk-core": "^0.1.0",
45
+ "@arethetypeswrong/cli": "0.18.5",
46
+ "playwright": "1.62.1",
47
+ "publint": "0.3.24",
48
+ "tsdown": "0.22.14",
49
+ "typescript": "7.0.2",
50
+ "vitest": "4.1.11",
51
+ "wrangler": "4.127.1"
52
+ },
53
+ "aiAgentSdk": {
54
+ "runtime": "universal",
55
+ "coreApi": 1,
56
+ "roles": [
57
+ "wire-protocol"
58
+ ]
59
+ },
60
+ "scripts": {
61
+ "build": "tsdown",
62
+ "clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true});require('node:fs').rmSync('artifacts',{recursive:true,force:true})\"",
63
+ "typecheck": "tsc --noEmit",
64
+ "test": "vitest run --config vitest.config.ts",
65
+ "pack": "pnpm pack --pack-destination artifacts",
66
+ "test:pack": "node ../../scripts/test-packed-protocol.mts protocol-gemini-interactions",
67
+ "check:publint": "publint",
68
+ "check:types": "attw --profile esm-only --pack ."
69
+ }
70
+ }