@rcrsr/rill-ext-gemini 0.18.4 → 0.19.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/dist/index.js +223 -88
- package/package.json +5 -5
package/dist/index.js
CHANGED
|
@@ -7,11 +7,13 @@ import {
|
|
|
7
7
|
Type
|
|
8
8
|
} from "@google/genai";
|
|
9
9
|
import {
|
|
10
|
-
RuntimeError as
|
|
10
|
+
RuntimeError as RuntimeError5,
|
|
11
|
+
RuntimeHaltSignal as RuntimeHaltSignal3,
|
|
11
12
|
emitExtensionEvent,
|
|
12
13
|
createRillStream,
|
|
13
14
|
createVector,
|
|
14
15
|
isVector,
|
|
16
|
+
getStatus as getStatus2,
|
|
15
17
|
structureToTypeValue,
|
|
16
18
|
toCallable
|
|
17
19
|
} from "@rcrsr/rill";
|
|
@@ -67,27 +69,133 @@ function validateEmbedModel(model) {
|
|
|
67
69
|
}
|
|
68
70
|
|
|
69
71
|
// ../../shared/ext-llm/dist/errors.js
|
|
70
|
-
import {
|
|
71
|
-
function
|
|
72
|
+
import { RuntimeHaltSignal } from "@rcrsr/rill";
|
|
73
|
+
function atomForStatus(status) {
|
|
74
|
+
if (status === 401)
|
|
75
|
+
return "AUTH";
|
|
76
|
+
if (status === 403)
|
|
77
|
+
return "FORBIDDEN";
|
|
78
|
+
if (status === 404)
|
|
79
|
+
return "NOT_FOUND";
|
|
80
|
+
if (status === 408)
|
|
81
|
+
return "TIMEOUT";
|
|
82
|
+
if (status === 409 || status === 412)
|
|
83
|
+
return "CONFLICT";
|
|
84
|
+
if (status === 429)
|
|
85
|
+
return "RATE_LIMIT";
|
|
86
|
+
if (status === 402)
|
|
87
|
+
return "QUOTA_EXCEEDED";
|
|
88
|
+
if (status >= 500 && status <= 599)
|
|
89
|
+
return "UNAVAILABLE";
|
|
90
|
+
if (status >= 400 && status <= 499)
|
|
91
|
+
return "INVALID_INPUT";
|
|
92
|
+
return "UNAVAILABLE";
|
|
93
|
+
}
|
|
94
|
+
function kindForStatus(status) {
|
|
95
|
+
if (status === 401)
|
|
96
|
+
return "authentication_failed";
|
|
97
|
+
if (status === 403)
|
|
98
|
+
return "forbidden";
|
|
99
|
+
if (status === 404)
|
|
100
|
+
return "not_found";
|
|
101
|
+
if (status === 408)
|
|
102
|
+
return "request_timeout";
|
|
103
|
+
if (status === 409 || status === 412)
|
|
104
|
+
return "conflict";
|
|
105
|
+
if (status === 429)
|
|
106
|
+
return "rate_limit_exceeded";
|
|
107
|
+
if (status === 402)
|
|
108
|
+
return "quota_exceeded";
|
|
109
|
+
if (status >= 500 && status <= 599)
|
|
110
|
+
return "server_error";
|
|
111
|
+
return "http_error";
|
|
112
|
+
}
|
|
113
|
+
function mapProviderError(ctx, provider, error, detect) {
|
|
114
|
+
if (error instanceof RuntimeHaltSignal) {
|
|
115
|
+
return ctx.invalidate(error, {
|
|
116
|
+
code: "TIMEOUT",
|
|
117
|
+
provider,
|
|
118
|
+
raw: { kind: "request_cancelled", message: `${provider}: request cancelled` }
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (error instanceof Error && error.name === "AbortError") {
|
|
122
|
+
return ctx.invalidate(error, {
|
|
123
|
+
code: "TIMEOUT",
|
|
124
|
+
provider,
|
|
125
|
+
raw: {
|
|
126
|
+
kind: "request_timeout",
|
|
127
|
+
message: `${provider} error: ${error.message}`
|
|
128
|
+
}
|
|
129
|
+
});
|
|
130
|
+
}
|
|
72
131
|
const detected = detect(error);
|
|
73
132
|
if (detected !== null) {
|
|
74
133
|
const { status, message } = detected;
|
|
75
134
|
if (status !== void 0) {
|
|
76
|
-
return
|
|
135
|
+
return ctx.invalidate(error, {
|
|
136
|
+
code: atomForStatus(status),
|
|
137
|
+
provider,
|
|
138
|
+
raw: {
|
|
139
|
+
kind: kindForStatus(status),
|
|
140
|
+
status,
|
|
141
|
+
message: `${provider} API error (HTTP ${status}): ${message}`
|
|
142
|
+
}
|
|
143
|
+
});
|
|
77
144
|
}
|
|
78
|
-
return
|
|
145
|
+
return ctx.invalidate(error, {
|
|
146
|
+
code: "UNAVAILABLE",
|
|
147
|
+
provider,
|
|
148
|
+
raw: {
|
|
149
|
+
kind: "provider_error",
|
|
150
|
+
message: `${provider} API error: ${message}`
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
if (error instanceof TypeError) {
|
|
155
|
+
return ctx.invalidate(error, {
|
|
156
|
+
code: "UNAVAILABLE",
|
|
157
|
+
provider,
|
|
158
|
+
raw: {
|
|
159
|
+
kind: "connection_failed",
|
|
160
|
+
message: `${provider} error: ${error.message}`
|
|
161
|
+
}
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
if (error instanceof SyntaxError) {
|
|
165
|
+
return ctx.invalidate(error, {
|
|
166
|
+
code: "PROTOCOL",
|
|
167
|
+
provider,
|
|
168
|
+
raw: {
|
|
169
|
+
kind: "unexpected_response_format",
|
|
170
|
+
message: `${provider} error: ${error.message}`
|
|
171
|
+
}
|
|
172
|
+
});
|
|
79
173
|
}
|
|
80
174
|
if (error instanceof Error) {
|
|
81
|
-
return
|
|
175
|
+
return ctx.invalidate(error, {
|
|
176
|
+
code: "UNAVAILABLE",
|
|
177
|
+
provider,
|
|
178
|
+
raw: {
|
|
179
|
+
kind: "unknown_error",
|
|
180
|
+
message: `${provider} error: ${error.message}`
|
|
181
|
+
}
|
|
182
|
+
});
|
|
82
183
|
}
|
|
83
|
-
return
|
|
184
|
+
return ctx.invalidate(error, {
|
|
185
|
+
code: "UNAVAILABLE",
|
|
186
|
+
provider,
|
|
187
|
+
raw: {
|
|
188
|
+
kind: "unknown_error",
|
|
189
|
+
message: `${provider} error: Unknown error`
|
|
190
|
+
}
|
|
191
|
+
});
|
|
84
192
|
}
|
|
85
193
|
|
|
86
194
|
// ../../shared/ext-llm/dist/tool-loop.js
|
|
87
|
-
import { invokeCallable, isCallable, isDict, isRuntimeCallable, RuntimeError as
|
|
195
|
+
import { getStatus, invokeCallable, isCallable, isDict, isRuntimeCallable, RuntimeError as RuntimeError3, RuntimeHaltSignal as RuntimeHaltSignal2 } from "@rcrsr/rill";
|
|
88
196
|
|
|
89
197
|
// ../../shared/ext-llm/dist/schema.js
|
|
90
|
-
import { RuntimeError as
|
|
198
|
+
import { RuntimeError as RuntimeError2 } from "@rcrsr/rill";
|
|
91
199
|
var RILL_TYPE_MAP = {
|
|
92
200
|
string: "string",
|
|
93
201
|
number: "number",
|
|
@@ -100,13 +208,13 @@ var RILL_TYPE_MAP = {
|
|
|
100
208
|
function mapRillType(rillType) {
|
|
101
209
|
const jsonType = RILL_TYPE_MAP[rillType];
|
|
102
210
|
if (jsonType === void 0) {
|
|
103
|
-
throw new
|
|
211
|
+
throw new RuntimeError2("RILL-R005", `unsupported type: ${rillType}`);
|
|
104
212
|
}
|
|
105
213
|
return jsonType;
|
|
106
214
|
}
|
|
107
215
|
function buildPropertyFromStructuralType(rillType) {
|
|
108
216
|
if (rillType.kind === "closure" || rillType.kind === "tuple") {
|
|
109
|
-
throw new
|
|
217
|
+
throw new RuntimeError2("RILL-R005", `unsupported type for JSON Schema: ${rillType.kind}`);
|
|
110
218
|
}
|
|
111
219
|
if (rillType.kind === "any") {
|
|
112
220
|
return {};
|
|
@@ -156,7 +264,7 @@ function buildJsonSchemaFromStructuralType(type, params) {
|
|
|
156
264
|
return buildDictSchema(type);
|
|
157
265
|
}
|
|
158
266
|
if (type.kind !== "closure") {
|
|
159
|
-
throw new
|
|
267
|
+
throw new RuntimeError2("RILL-R005", `unsupported schema kind: ${type.kind} (expected dict or closure)`);
|
|
160
268
|
}
|
|
161
269
|
const properties = {};
|
|
162
270
|
const required = [];
|
|
@@ -184,30 +292,51 @@ function buildJsonSchemaFromStructuralType(type, params) {
|
|
|
184
292
|
}
|
|
185
293
|
|
|
186
294
|
// ../../shared/ext-llm/dist/tool-loop.js
|
|
295
|
+
function readHaltMessage(halt) {
|
|
296
|
+
const status = getStatus(halt.value);
|
|
297
|
+
if (typeof status.message === "string" && status.message.length > 0) {
|
|
298
|
+
return status.message;
|
|
299
|
+
}
|
|
300
|
+
return halt.message;
|
|
301
|
+
}
|
|
302
|
+
function throwToolLoopHalt(ctx, code, kind, message) {
|
|
303
|
+
if (ctx !== void 0) {
|
|
304
|
+
const hostCtx = ctx;
|
|
305
|
+
if (typeof hostCtx.invalidate === "function") {
|
|
306
|
+
const invalid = hostCtx.invalidate(new Error(message), {
|
|
307
|
+
code,
|
|
308
|
+
provider: "tool_loop",
|
|
309
|
+
raw: { kind, message }
|
|
310
|
+
});
|
|
311
|
+
throw new RuntimeHaltSignal2(invalid, true);
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
throw new RuntimeError3("RILL-R005", message);
|
|
315
|
+
}
|
|
187
316
|
async function executeToolCall(toolName, toolInput, tools, context) {
|
|
188
317
|
if (!isDict(tools)) {
|
|
189
|
-
|
|
318
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tools_not_dict", "tool_loop: tools must be a dict of name \u2192 callable");
|
|
190
319
|
}
|
|
191
320
|
const toolsDict = tools;
|
|
192
321
|
const toolFn = toolsDict[toolName];
|
|
193
322
|
if (toolFn === void 0 || toolFn === null) {
|
|
194
|
-
|
|
323
|
+
throwToolLoopHalt(context, "NOT_FOUND", "unknown_tool", `Unknown tool: ${toolName}`);
|
|
195
324
|
}
|
|
196
325
|
if (!isCallable(toolFn)) {
|
|
197
|
-
|
|
326
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tool_not_callable", `Invalid tool input for ${toolName}: tool must be callable`);
|
|
198
327
|
}
|
|
199
328
|
if (typeof toolInput !== "object" || toolInput === null) {
|
|
200
|
-
|
|
329
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "invalid_tool_input", `Invalid tool input for ${toolName}: input must be an object`);
|
|
201
330
|
}
|
|
202
331
|
const callable = toolFn;
|
|
203
332
|
if (callable.kind !== "runtime" && callable.kind !== "application" && callable.kind !== "script") {
|
|
204
|
-
|
|
333
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tool_kind_unsupported", `Invalid tool input for ${toolName}: tool must be application, runtime, or script callable`);
|
|
205
334
|
}
|
|
206
335
|
try {
|
|
207
336
|
const inputDict = toolInput;
|
|
208
337
|
if (callable.kind === "script") {
|
|
209
338
|
if (!context) {
|
|
210
|
-
throw new
|
|
339
|
+
throw new RuntimeError3("RILL-R005", `Invalid tool input for ${toolName}: script callable requires a runtime context`);
|
|
211
340
|
}
|
|
212
341
|
let args;
|
|
213
342
|
if (callable.params && callable.params.length > 0) {
|
|
@@ -223,16 +352,17 @@ async function executeToolCall(toolName, toolInput, tools, context) {
|
|
|
223
352
|
const ctx = context ?? {
|
|
224
353
|
parent: void 0,
|
|
225
354
|
variables: /* @__PURE__ */ new Map(),
|
|
226
|
-
pipeValue: null
|
|
355
|
+
pipeValue: null,
|
|
356
|
+
hostContext: {}
|
|
227
357
|
};
|
|
228
358
|
const result = callable.fn(inputDict, ctx);
|
|
229
359
|
return result instanceof Promise ? await result : result;
|
|
230
360
|
} catch (error) {
|
|
231
|
-
if (error instanceof
|
|
361
|
+
if (error instanceof RuntimeError3) {
|
|
232
362
|
throw error;
|
|
233
363
|
}
|
|
234
364
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
235
|
-
throw new
|
|
365
|
+
throw new RuntimeError3("RILL-R005", `Invalid tool input for ${toolName}: ${message}`);
|
|
236
366
|
}
|
|
237
367
|
}
|
|
238
368
|
function sanitizeToolName(name) {
|
|
@@ -303,19 +433,19 @@ function patchResponseToolCallNames(response, nameMap) {
|
|
|
303
433
|
}
|
|
304
434
|
async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent, maxTurns = 10, context, yieldChunk, signal) {
|
|
305
435
|
if (tools === void 0) {
|
|
306
|
-
|
|
436
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tools_required", "tools parameter is required");
|
|
307
437
|
}
|
|
308
438
|
if (!isDict(tools)) {
|
|
309
|
-
|
|
439
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tools_not_dict", "tool_loop: tools must be a dict of name \u2192 callable");
|
|
310
440
|
}
|
|
311
441
|
const toolsDict = tools;
|
|
312
442
|
const toolDescriptors = Object.entries(toolsDict).map(([name, fn]) => {
|
|
313
443
|
const fnValue = fn;
|
|
314
444
|
if (isRuntimeCallable(fnValue)) {
|
|
315
|
-
|
|
445
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "builtin_tool_unsupported", `tool_loop: builtin "${name}" cannot be used as a tool \u2014 wrap in a closure`);
|
|
316
446
|
}
|
|
317
447
|
if (!isCallable(fnValue)) {
|
|
318
|
-
|
|
448
|
+
throwToolLoopHalt(context, "INVALID_INPUT", "tool_not_callable", `tool_loop: tool "${name}" is not a callable`);
|
|
319
449
|
}
|
|
320
450
|
const callable = fnValue;
|
|
321
451
|
const description = callable.annotations?.["description"] ?? "";
|
|
@@ -350,7 +480,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
|
|
|
350
480
|
let turnCount = 0;
|
|
351
481
|
while (turnCount < maxTurns) {
|
|
352
482
|
if (signal?.aborted) {
|
|
353
|
-
|
|
483
|
+
throwToolLoopHalt(context, "TIMEOUT", "tool_loop_cancelled", "tool_loop cancelled");
|
|
354
484
|
}
|
|
355
485
|
turnCount++;
|
|
356
486
|
let response;
|
|
@@ -364,8 +494,18 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
|
|
|
364
494
|
response = await callbacks.callAPI(currentMessages, providerTools, signal);
|
|
365
495
|
}
|
|
366
496
|
} catch (error) {
|
|
497
|
+
if (error instanceof RuntimeHaltSignal2) {
|
|
498
|
+
throw error;
|
|
499
|
+
}
|
|
500
|
+
if (context !== void 0 && callbacks.detectError !== void 0) {
|
|
501
|
+
const hostCtx = context;
|
|
502
|
+
if (typeof hostCtx.invalidate === "function") {
|
|
503
|
+
const invalid = mapProviderError(hostCtx, "tool_loop", error, callbacks.detectError);
|
|
504
|
+
throw new RuntimeHaltSignal2(invalid, true);
|
|
505
|
+
}
|
|
506
|
+
}
|
|
367
507
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
368
|
-
throw new
|
|
508
|
+
throw new RuntimeError3("RILL-R005", `Provider API error: ${message}`, void 0, { cause: error });
|
|
369
509
|
}
|
|
370
510
|
if (typeof response === "object" && response !== null && "usage" in response) {
|
|
371
511
|
const usage = response["usage"];
|
|
@@ -422,7 +562,11 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
|
|
|
422
562
|
const duration = Date.now() - toolStartTime;
|
|
423
563
|
consecutiveErrors++;
|
|
424
564
|
let originalError;
|
|
425
|
-
if (error instanceof
|
|
565
|
+
if (error instanceof RuntimeHaltSignal2) {
|
|
566
|
+
const haltMessage = readHaltMessage(error);
|
|
567
|
+
const prefix = `Invalid tool input for ${name}: `;
|
|
568
|
+
originalError = haltMessage.startsWith(prefix) ? haltMessage.slice(prefix.length) : haltMessage;
|
|
569
|
+
} else if (error instanceof RuntimeError3) {
|
|
426
570
|
const prefix = `Invalid tool input for ${name}: `;
|
|
427
571
|
if (error.message.startsWith(prefix)) {
|
|
428
572
|
originalError = error.message.slice(prefix.length);
|
|
@@ -447,7 +591,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
|
|
|
447
591
|
duration
|
|
448
592
|
});
|
|
449
593
|
if (consecutiveErrors >= maxErrors) {
|
|
450
|
-
|
|
594
|
+
throwToolLoopHalt(context, "UNAVAILABLE", "consecutive_tool_errors", `Tool execution failed: ${maxErrors} consecutive errors (last: ${name}: ${originalError})`);
|
|
451
595
|
}
|
|
452
596
|
}
|
|
453
597
|
}
|
|
@@ -474,13 +618,13 @@ function buildResponseMessages(inputMessages, assistantContent) {
|
|
|
474
618
|
}
|
|
475
619
|
|
|
476
620
|
// ../../shared/ext-param/dist/param.js
|
|
477
|
-
import { RuntimeError as
|
|
621
|
+
import { RuntimeError as RuntimeError4 } from "@rcrsr/rill";
|
|
478
622
|
function validateParamName(name) {
|
|
479
623
|
if (name === "") {
|
|
480
|
-
throw new
|
|
624
|
+
throw new RuntimeError4("RILL-R001", "param name must not be empty");
|
|
481
625
|
}
|
|
482
626
|
if (/\s/.test(name)) {
|
|
483
|
-
throw new
|
|
627
|
+
throw new RuntimeError4("RILL-R001", "param name must be a valid identifier");
|
|
484
628
|
}
|
|
485
629
|
}
|
|
486
630
|
function buildAnnotations(desc) {
|
|
@@ -597,6 +741,27 @@ var p = {
|
|
|
597
741
|
|
|
598
742
|
// src/factory.ts
|
|
599
743
|
var DEFAULT_MAX_TOKENS = 8192;
|
|
744
|
+
function mapToHalt(ctx, error) {
|
|
745
|
+
const invalid = mapProviderError(ctx, "Gemini", error, detectGeminiError);
|
|
746
|
+
return new RuntimeHaltSignal3(invalid, true);
|
|
747
|
+
}
|
|
748
|
+
function haltInvalid(ctx, code, rawKind, message) {
|
|
749
|
+
return new RuntimeHaltSignal3(
|
|
750
|
+
ctx.invalidate(new Error(message), {
|
|
751
|
+
code,
|
|
752
|
+
provider: "gemini",
|
|
753
|
+
raw: { kind: rawKind, message }
|
|
754
|
+
}),
|
|
755
|
+
true
|
|
756
|
+
);
|
|
757
|
+
}
|
|
758
|
+
function streamErrorMessage(err) {
|
|
759
|
+
if (err === void 0) return "";
|
|
760
|
+
if (err instanceof RuntimeHaltSignal3) {
|
|
761
|
+
return getStatus2(err.value).message || err.message;
|
|
762
|
+
}
|
|
763
|
+
return err.message;
|
|
764
|
+
}
|
|
600
765
|
var detectGeminiError = (error) => {
|
|
601
766
|
if (error instanceof Error) {
|
|
602
767
|
const message = error.message;
|
|
@@ -685,7 +850,7 @@ function createGeminiExtension(config) {
|
|
|
685
850
|
const text = args["text"];
|
|
686
851
|
const options = args["options"] ?? {};
|
|
687
852
|
if (text.trim().length === 0) {
|
|
688
|
-
throw
|
|
853
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "empty_prompt", "prompt text cannot be empty");
|
|
689
854
|
}
|
|
690
855
|
const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
|
|
691
856
|
const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
|
|
@@ -724,12 +889,12 @@ function createGeminiExtension(config) {
|
|
|
724
889
|
}
|
|
725
890
|
}
|
|
726
891
|
} catch (error) {
|
|
727
|
-
streamError = error instanceof
|
|
892
|
+
streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
728
893
|
const duration = Date.now() - messageStartTime;
|
|
729
894
|
emitExtensionEvent(ctx, {
|
|
730
895
|
event: "gemini:error",
|
|
731
896
|
subsystem: "extension:gemini",
|
|
732
|
-
error: streamError
|
|
897
|
+
error: streamErrorMessage(streamError),
|
|
733
898
|
duration
|
|
734
899
|
});
|
|
735
900
|
throw streamError;
|
|
@@ -820,10 +985,7 @@ function createGeminiExtension(config) {
|
|
|
820
985
|
const inputMessages = args["messages"];
|
|
821
986
|
const options = args["options"] ?? {};
|
|
822
987
|
if (inputMessages.length === 0) {
|
|
823
|
-
throw
|
|
824
|
-
"RILL-R004",
|
|
825
|
-
"messages list cannot be empty"
|
|
826
|
-
);
|
|
988
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "empty_messages", "messages list cannot be empty");
|
|
827
989
|
}
|
|
828
990
|
const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
|
|
829
991
|
const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
|
|
@@ -831,21 +993,15 @@ function createGeminiExtension(config) {
|
|
|
831
993
|
for (let i = 0; i < inputMessages.length; i++) {
|
|
832
994
|
const msg = inputMessages[i];
|
|
833
995
|
if (!msg || typeof msg !== "object" || !("role" in msg)) {
|
|
834
|
-
throw
|
|
835
|
-
"RILL-R004",
|
|
836
|
-
"message missing required 'role' field"
|
|
837
|
-
);
|
|
996
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "invalid_message_format", "message missing required 'role' field");
|
|
838
997
|
}
|
|
839
998
|
const role = msg["role"];
|
|
840
999
|
if (role !== "user" && role !== "assistant" && role !== "tool") {
|
|
841
|
-
throw
|
|
1000
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "invalid_role", `invalid role '${String(role)}'`);
|
|
842
1001
|
}
|
|
843
1002
|
if (role === "user" || role === "tool") {
|
|
844
1003
|
if (!("content" in msg) || typeof msg["content"] !== "string") {
|
|
845
|
-
throw
|
|
846
|
-
"RILL-R004",
|
|
847
|
-
`${role} message requires 'content'`
|
|
848
|
-
);
|
|
1004
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "missing_message_content", `${role} message requires 'content'`);
|
|
849
1005
|
}
|
|
850
1006
|
contents.push({
|
|
851
1007
|
role: "user",
|
|
@@ -855,10 +1011,7 @@ function createGeminiExtension(config) {
|
|
|
855
1011
|
const hasContent = "content" in msg && msg["content"];
|
|
856
1012
|
const hasToolCalls = "tool_calls" in msg && msg["tool_calls"];
|
|
857
1013
|
if (!hasContent && !hasToolCalls) {
|
|
858
|
-
throw
|
|
859
|
-
"RILL-R004",
|
|
860
|
-
"assistant message requires 'content' or 'tool_calls'"
|
|
861
|
-
);
|
|
1014
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "invalid_assistant_message", "assistant message requires 'content' or 'tool_calls'");
|
|
862
1015
|
}
|
|
863
1016
|
if (hasContent) {
|
|
864
1017
|
contents.push({
|
|
@@ -897,12 +1050,12 @@ function createGeminiExtension(config) {
|
|
|
897
1050
|
}
|
|
898
1051
|
}
|
|
899
1052
|
} catch (error) {
|
|
900
|
-
streamError = error instanceof
|
|
1053
|
+
streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
901
1054
|
const duration = Date.now() - messagesStartTime;
|
|
902
1055
|
emitExtensionEvent(ctx, {
|
|
903
1056
|
event: "gemini:error",
|
|
904
1057
|
subsystem: "extension:gemini",
|
|
905
|
-
error: streamError
|
|
1058
|
+
error: streamErrorMessage(streamError),
|
|
906
1059
|
duration
|
|
907
1060
|
});
|
|
908
1061
|
throw streamError;
|
|
@@ -995,10 +1148,7 @@ function createGeminiExtension(config) {
|
|
|
995
1148
|
});
|
|
996
1149
|
const embedding = response.embeddings?.[0];
|
|
997
1150
|
if (!embedding || !embedding.values || embedding.values.length === 0) {
|
|
998
|
-
throw
|
|
999
|
-
"RILL-R004",
|
|
1000
|
-
"Gemini: empty embedding returned"
|
|
1001
|
-
);
|
|
1151
|
+
throw haltInvalid(ctx, "PROTOCOL", "empty_embedding_response", "Gemini: empty embedding returned");
|
|
1002
1152
|
}
|
|
1003
1153
|
const float32Data = new Float32Array(embedding.values);
|
|
1004
1154
|
const vector = createVector(float32Data, factoryEmbedModel);
|
|
@@ -1013,11 +1163,11 @@ function createGeminiExtension(config) {
|
|
|
1013
1163
|
return vector;
|
|
1014
1164
|
} catch (error) {
|
|
1015
1165
|
const duration = Date.now() - startTime;
|
|
1016
|
-
const rillError = error instanceof
|
|
1166
|
+
const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
1017
1167
|
emitExtensionEvent(ctx, {
|
|
1018
1168
|
event: "gemini:error",
|
|
1019
1169
|
subsystem: "extension:gemini",
|
|
1020
|
-
error: rillError
|
|
1170
|
+
error: streamErrorMessage(rillError),
|
|
1021
1171
|
duration
|
|
1022
1172
|
});
|
|
1023
1173
|
throw rillError;
|
|
@@ -1044,17 +1194,11 @@ function createGeminiExtension(config) {
|
|
|
1044
1194
|
});
|
|
1045
1195
|
const vectors = [];
|
|
1046
1196
|
if (!response.embeddings || response.embeddings.length === 0) {
|
|
1047
|
-
throw
|
|
1048
|
-
"RILL-R004",
|
|
1049
|
-
"Gemini: empty embeddings returned"
|
|
1050
|
-
);
|
|
1197
|
+
throw haltInvalid(ctx, "PROTOCOL", "empty_embeddings_response", "Gemini: empty embeddings returned");
|
|
1051
1198
|
}
|
|
1052
1199
|
for (const embedding of response.embeddings) {
|
|
1053
1200
|
if (!embedding || !embedding.values || embedding.values.length === 0) {
|
|
1054
|
-
throw
|
|
1055
|
-
"RILL-R004",
|
|
1056
|
-
"Gemini: empty embedding returned"
|
|
1057
|
-
);
|
|
1201
|
+
throw haltInvalid(ctx, "PROTOCOL", "empty_embedding_response", "Gemini: empty embedding returned");
|
|
1058
1202
|
}
|
|
1059
1203
|
const float32Data = new Float32Array(embedding.values);
|
|
1060
1204
|
const vector = createVector(float32Data, factoryEmbedModel);
|
|
@@ -1074,11 +1218,11 @@ function createGeminiExtension(config) {
|
|
|
1074
1218
|
return vectors;
|
|
1075
1219
|
} catch (error) {
|
|
1076
1220
|
const duration = Date.now() - startTime;
|
|
1077
|
-
const rillError = error instanceof
|
|
1221
|
+
const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
1078
1222
|
emitExtensionEvent(ctx, {
|
|
1079
1223
|
event: "gemini:error",
|
|
1080
1224
|
subsystem: "extension:gemini",
|
|
1081
|
-
error: rillError
|
|
1225
|
+
error: streamErrorMessage(rillError),
|
|
1082
1226
|
duration
|
|
1083
1227
|
});
|
|
1084
1228
|
throw rillError;
|
|
@@ -1110,7 +1254,7 @@ function createGeminiExtension(config) {
|
|
|
1110
1254
|
const toolsDict = args["tools"];
|
|
1111
1255
|
const options = args["options"] ?? {};
|
|
1112
1256
|
if (prompt.trim().length === 0) {
|
|
1113
|
-
throw
|
|
1257
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "empty_prompt", "prompt text cannot be empty");
|
|
1114
1258
|
}
|
|
1115
1259
|
const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
|
|
1116
1260
|
const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
|
|
@@ -1309,7 +1453,7 @@ function createGeminiExtension(config) {
|
|
|
1309
1453
|
r();
|
|
1310
1454
|
}
|
|
1311
1455
|
}).catch((error) => {
|
|
1312
|
-
streamError = error instanceof
|
|
1456
|
+
streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
1313
1457
|
streamDone = true;
|
|
1314
1458
|
if (resolveNext) {
|
|
1315
1459
|
const r = resolveNext;
|
|
@@ -1358,7 +1502,7 @@ function createGeminiExtension(config) {
|
|
|
1358
1502
|
emitExtensionEvent(ctx, {
|
|
1359
1503
|
event: "gemini:error",
|
|
1360
1504
|
subsystem: "extension:gemini",
|
|
1361
|
-
error: streamError
|
|
1505
|
+
error: streamErrorMessage(streamError),
|
|
1362
1506
|
duration: Date.now()
|
|
1363
1507
|
});
|
|
1364
1508
|
return {
|
|
@@ -1374,7 +1518,7 @@ function createGeminiExtension(config) {
|
|
|
1374
1518
|
emitExtensionEvent(ctx, {
|
|
1375
1519
|
event: "gemini:error",
|
|
1376
1520
|
subsystem: "extension:gemini",
|
|
1377
|
-
error: streamError
|
|
1521
|
+
error: streamErrorMessage(streamError),
|
|
1378
1522
|
duration
|
|
1379
1523
|
});
|
|
1380
1524
|
throw streamError;
|
|
@@ -1447,16 +1591,10 @@ function createGeminiExtension(config) {
|
|
|
1447
1591
|
const schemaArg = args["schema"];
|
|
1448
1592
|
const options = args["options"] ?? {};
|
|
1449
1593
|
if (!schemaArg || !schemaArg.__rill_type || !schemaArg.structure) {
|
|
1450
|
-
throw
|
|
1451
|
-
"RILL-R004",
|
|
1452
|
-
"generate requires a type expression as schema"
|
|
1453
|
-
);
|
|
1594
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "invalid_schema", "generate requires a type expression as schema");
|
|
1454
1595
|
}
|
|
1455
1596
|
if (schemaArg.structure.kind !== "dict") {
|
|
1456
|
-
throw
|
|
1457
|
-
"RILL-R004",
|
|
1458
|
-
`generate requires a dict type as schema, got ${schemaArg.structure.kind}`
|
|
1459
|
-
);
|
|
1597
|
+
throw haltInvalid(ctx, "INVALID_INPUT", "invalid_schema_type", `generate requires a dict type as schema, got ${schemaArg.structure.kind}`);
|
|
1460
1598
|
}
|
|
1461
1599
|
const jsonSchema = buildJsonSchemaFromStructuralType(schemaArg.structure);
|
|
1462
1600
|
const geminiProperties = {};
|
|
@@ -1518,10 +1656,7 @@ function createGeminiExtension(config) {
|
|
|
1518
1656
|
data = JSON.parse(raw);
|
|
1519
1657
|
} catch (parseError) {
|
|
1520
1658
|
const detail = parseError instanceof Error ? parseError.message : String(parseError);
|
|
1521
|
-
throw
|
|
1522
|
-
"RILL-R004",
|
|
1523
|
-
`generate: failed to parse response JSON: ${detail}`
|
|
1524
|
-
);
|
|
1659
|
+
throw haltInvalid(ctx, "PROTOCOL", "json_parse_failed", `generate: failed to parse response JSON: ${detail}`);
|
|
1525
1660
|
}
|
|
1526
1661
|
const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
|
|
1527
1662
|
const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
|
|
@@ -1551,11 +1686,11 @@ function createGeminiExtension(config) {
|
|
|
1551
1686
|
return generateResult;
|
|
1552
1687
|
} catch (error) {
|
|
1553
1688
|
const duration = Date.now() - startTime;
|
|
1554
|
-
const rillError = error instanceof
|
|
1689
|
+
const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
|
|
1555
1690
|
emitExtensionEvent(ctx, {
|
|
1556
1691
|
event: "gemini:error",
|
|
1557
1692
|
subsystem: "extension:gemini",
|
|
1558
|
-
error: rillError
|
|
1693
|
+
error: streamErrorMessage(rillError),
|
|
1559
1694
|
duration
|
|
1560
1695
|
});
|
|
1561
1696
|
throw rillError;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rcrsr/rill-ext-gemini",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.19.0",
|
|
4
4
|
"description": "rill extension for Google Gemini API integration",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Andre Bremer",
|
|
@@ -17,16 +17,16 @@
|
|
|
17
17
|
"scripting"
|
|
18
18
|
],
|
|
19
19
|
"peerDependencies": {
|
|
20
|
-
"@rcrsr/rill": "~0.
|
|
20
|
+
"@rcrsr/rill": "~0.19.0"
|
|
21
21
|
},
|
|
22
22
|
"devDependencies": {
|
|
23
|
-
"@rcrsr/rill": "~0.
|
|
23
|
+
"@rcrsr/rill": "~0.19.0",
|
|
24
24
|
"@types/node": "^25.5.2",
|
|
25
25
|
"dts-bundle-generator": "^9.5.1",
|
|
26
26
|
"tsup": "^8.5.1",
|
|
27
27
|
"undici-types": "^8.0.2",
|
|
28
|
-
"@rcrsr/rill-ext-
|
|
29
|
-
"@rcrsr/rill-ext-
|
|
28
|
+
"@rcrsr/rill-ext-param-shared": "0.19.0",
|
|
29
|
+
"@rcrsr/rill-ext-llm-shared": "^0.19.0"
|
|
30
30
|
},
|
|
31
31
|
"files": [
|
|
32
32
|
"dist"
|