@rcrsr/rill-ext-gemini 0.18.4 → 0.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +233 -93
  2. 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 RuntimeError6,
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 { RuntimeError as RuntimeError2 } from "@rcrsr/rill";
71
- function mapProviderError(providerName, error, detect) {
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 new RuntimeError2("RILL-R004", `${providerName} API error (HTTP ${status}): ${message}`, void 0, { cause: error });
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 new RuntimeError2("RILL-R004", `${providerName} API error: ${message}`, void 0, { cause: error });
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 new RuntimeError2("RILL-R004", `${providerName} error: ${error.message}`, void 0, { cause: error });
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 new RuntimeError2("RILL-R004", `${providerName} error: Unknown error`, void 0, { cause: error });
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 RuntimeError4 } from "@rcrsr/rill";
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 RuntimeError3 } from "@rcrsr/rill";
198
+ import { RuntimeError as RuntimeError2 } from "@rcrsr/rill";
91
199
  var RILL_TYPE_MAP = {
92
200
  string: "string",
93
201
  number: "number",
@@ -100,24 +208,24 @@ 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 RuntimeError3("RILL-R004", `unsupported type: ${rillType}`);
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 RuntimeError3("RILL-R004", `unsupported type for JSON Schema: ${rillType.kind}`);
217
+ throw new RuntimeError2("RILL-R005", `unsupported type for JSON Schema: ${rillType.kind}`);
110
218
  }
111
219
  if (rillType.kind === "any") {
112
220
  return {};
113
221
  }
114
222
  if (rillType.kind === "list") {
115
223
  const listType = rillType;
116
- const property = { type: "array" };
224
+ const property2 = { type: "array" };
117
225
  if (listType.element !== void 0) {
118
- property.items = buildPropertyFromStructuralType(listType.element);
226
+ property2.items = buildPropertyFromStructuralType(listType.element);
119
227
  }
120
- return property;
228
+ return property2;
121
229
  }
122
230
  if (rillType.kind === "dict") {
123
231
  const dictType = rillType;
@@ -130,9 +238,14 @@ function buildPropertyFromStructuralType(rillType) {
130
238
  additionalProperties: false
131
239
  };
132
240
  }
133
- return { type: "object" };
241
+ return { type: "object", additionalProperties: false };
242
+ }
243
+ const jsonType = mapRillType(rillType.kind);
244
+ const property = { type: jsonType };
245
+ if (jsonType === "object") {
246
+ property.additionalProperties = false;
134
247
  }
135
- return { type: mapRillType(rillType.kind) };
248
+ return property;
136
249
  }
137
250
  function buildDictSchema(dictType) {
138
251
  const properties = {};
@@ -156,7 +269,7 @@ function buildJsonSchemaFromStructuralType(type, params) {
156
269
  return buildDictSchema(type);
157
270
  }
158
271
  if (type.kind !== "closure") {
159
- throw new RuntimeError3("RILL-R004", `unsupported schema kind: ${type.kind} (expected dict or closure)`);
272
+ throw new RuntimeError2("RILL-R005", `unsupported schema kind: ${type.kind} (expected dict or closure)`);
160
273
  }
161
274
  const properties = {};
162
275
  const required = [];
@@ -184,30 +297,51 @@ function buildJsonSchemaFromStructuralType(type, params) {
184
297
  }
185
298
 
186
299
  // ../../shared/ext-llm/dist/tool-loop.js
300
+ function readHaltMessage(halt) {
301
+ const status = getStatus(halt.value);
302
+ if (typeof status.message === "string" && status.message.length > 0) {
303
+ return status.message;
304
+ }
305
+ return halt.message;
306
+ }
307
+ function throwToolLoopHalt(ctx, code, kind, message) {
308
+ if (ctx !== void 0) {
309
+ const hostCtx = ctx;
310
+ if (typeof hostCtx.invalidate === "function") {
311
+ const invalid = hostCtx.invalidate(new Error(message), {
312
+ code,
313
+ provider: "tool_loop",
314
+ raw: { kind, message }
315
+ });
316
+ throw new RuntimeHaltSignal2(invalid, true);
317
+ }
318
+ }
319
+ throw new RuntimeError3("RILL-R005", message);
320
+ }
187
321
  async function executeToolCall(toolName, toolInput, tools, context) {
188
322
  if (!isDict(tools)) {
189
- throw new RuntimeError4("RILL-R004", "tool_loop: tools must be a dict of name \u2192 callable");
323
+ throwToolLoopHalt(context, "INVALID_INPUT", "tools_not_dict", "tool_loop: tools must be a dict of name \u2192 callable");
190
324
  }
191
325
  const toolsDict = tools;
192
326
  const toolFn = toolsDict[toolName];
193
327
  if (toolFn === void 0 || toolFn === null) {
194
- throw new RuntimeError4("RILL-R004", `Unknown tool: ${toolName}`);
328
+ throwToolLoopHalt(context, "NOT_FOUND", "unknown_tool", `Unknown tool: ${toolName}`);
195
329
  }
196
330
  if (!isCallable(toolFn)) {
197
- throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: tool must be callable`);
331
+ throwToolLoopHalt(context, "INVALID_INPUT", "tool_not_callable", `Invalid tool input for ${toolName}: tool must be callable`);
198
332
  }
199
333
  if (typeof toolInput !== "object" || toolInput === null) {
200
- throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: input must be an object`);
334
+ throwToolLoopHalt(context, "INVALID_INPUT", "invalid_tool_input", `Invalid tool input for ${toolName}: input must be an object`);
201
335
  }
202
336
  const callable = toolFn;
203
337
  if (callable.kind !== "runtime" && callable.kind !== "application" && callable.kind !== "script") {
204
- throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: tool must be application, runtime, or script callable`);
338
+ throwToolLoopHalt(context, "INVALID_INPUT", "tool_kind_unsupported", `Invalid tool input for ${toolName}: tool must be application, runtime, or script callable`);
205
339
  }
206
340
  try {
207
341
  const inputDict = toolInput;
208
342
  if (callable.kind === "script") {
209
343
  if (!context) {
210
- throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: script callable requires a runtime context`);
344
+ throw new RuntimeError3("RILL-R005", `Invalid tool input for ${toolName}: script callable requires a runtime context`);
211
345
  }
212
346
  let args;
213
347
  if (callable.params && callable.params.length > 0) {
@@ -223,16 +357,17 @@ async function executeToolCall(toolName, toolInput, tools, context) {
223
357
  const ctx = context ?? {
224
358
  parent: void 0,
225
359
  variables: /* @__PURE__ */ new Map(),
226
- pipeValue: null
360
+ pipeValue: null,
361
+ hostContext: {}
227
362
  };
228
363
  const result = callable.fn(inputDict, ctx);
229
364
  return result instanceof Promise ? await result : result;
230
365
  } catch (error) {
231
- if (error instanceof RuntimeError4) {
366
+ if (error instanceof RuntimeError3) {
232
367
  throw error;
233
368
  }
234
369
  const message = error instanceof Error ? error.message : "Unknown error";
235
- throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: ${message}`);
370
+ throw new RuntimeError3("RILL-R005", `Invalid tool input for ${toolName}: ${message}`);
236
371
  }
237
372
  }
238
373
  function sanitizeToolName(name) {
@@ -303,19 +438,19 @@ function patchResponseToolCallNames(response, nameMap) {
303
438
  }
304
439
  async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent, maxTurns = 10, context, yieldChunk, signal) {
305
440
  if (tools === void 0) {
306
- throw new RuntimeError4("RILL-R004", "tools parameter is required");
441
+ throwToolLoopHalt(context, "INVALID_INPUT", "tools_required", "tools parameter is required");
307
442
  }
308
443
  if (!isDict(tools)) {
309
- throw new RuntimeError4("RILL-R004", "tool_loop: tools must be a dict of name \u2192 callable");
444
+ throwToolLoopHalt(context, "INVALID_INPUT", "tools_not_dict", "tool_loop: tools must be a dict of name \u2192 callable");
310
445
  }
311
446
  const toolsDict = tools;
312
447
  const toolDescriptors = Object.entries(toolsDict).map(([name, fn]) => {
313
448
  const fnValue = fn;
314
449
  if (isRuntimeCallable(fnValue)) {
315
- throw new RuntimeError4("RILL-R004", `tool_loop: builtin "${name}" cannot be used as a tool \u2014 wrap in a closure`);
450
+ throwToolLoopHalt(context, "INVALID_INPUT", "builtin_tool_unsupported", `tool_loop: builtin "${name}" cannot be used as a tool \u2014 wrap in a closure`);
316
451
  }
317
452
  if (!isCallable(fnValue)) {
318
- throw new RuntimeError4("RILL-R004", `tool_loop: tool "${name}" is not a callable`);
453
+ throwToolLoopHalt(context, "INVALID_INPUT", "tool_not_callable", `tool_loop: tool "${name}" is not a callable`);
319
454
  }
320
455
  const callable = fnValue;
321
456
  const description = callable.annotations?.["description"] ?? "";
@@ -350,7 +485,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
350
485
  let turnCount = 0;
351
486
  while (turnCount < maxTurns) {
352
487
  if (signal?.aborted) {
353
- throw new RuntimeError4("RILL-R004", "tool_loop cancelled");
488
+ throwToolLoopHalt(context, "TIMEOUT", "tool_loop_cancelled", "tool_loop cancelled");
354
489
  }
355
490
  turnCount++;
356
491
  let response;
@@ -364,8 +499,18 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
364
499
  response = await callbacks.callAPI(currentMessages, providerTools, signal);
365
500
  }
366
501
  } catch (error) {
502
+ if (error instanceof RuntimeHaltSignal2) {
503
+ throw error;
504
+ }
505
+ if (context !== void 0 && callbacks.detectError !== void 0) {
506
+ const hostCtx = context;
507
+ if (typeof hostCtx.invalidate === "function") {
508
+ const invalid = mapProviderError(hostCtx, "tool_loop", error, callbacks.detectError);
509
+ throw new RuntimeHaltSignal2(invalid, true);
510
+ }
511
+ }
367
512
  const message = error instanceof Error ? error.message : "Unknown error";
368
- throw new RuntimeError4("RILL-R004", `Provider API error: ${message}`, void 0, { cause: error });
513
+ throw new RuntimeError3("RILL-R005", `Provider API error: ${message}`, void 0, { cause: error });
369
514
  }
370
515
  if (typeof response === "object" && response !== null && "usage" in response) {
371
516
  const usage = response["usage"];
@@ -422,7 +567,11 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
422
567
  const duration = Date.now() - toolStartTime;
423
568
  consecutiveErrors++;
424
569
  let originalError;
425
- if (error instanceof RuntimeError4) {
570
+ if (error instanceof RuntimeHaltSignal2) {
571
+ const haltMessage = readHaltMessage(error);
572
+ const prefix = `Invalid tool input for ${name}: `;
573
+ originalError = haltMessage.startsWith(prefix) ? haltMessage.slice(prefix.length) : haltMessage;
574
+ } else if (error instanceof RuntimeError3) {
426
575
  const prefix = `Invalid tool input for ${name}: `;
427
576
  if (error.message.startsWith(prefix)) {
428
577
  originalError = error.message.slice(prefix.length);
@@ -447,7 +596,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
447
596
  duration
448
597
  });
449
598
  if (consecutiveErrors >= maxErrors) {
450
- throw new RuntimeError4("RILL-R004", `Tool execution failed: ${maxErrors} consecutive errors (last: ${name}: ${originalError})`);
599
+ throwToolLoopHalt(context, "UNAVAILABLE", "consecutive_tool_errors", `Tool execution failed: ${maxErrors} consecutive errors (last: ${name}: ${originalError})`);
451
600
  }
452
601
  }
453
602
  }
@@ -474,13 +623,13 @@ function buildResponseMessages(inputMessages, assistantContent) {
474
623
  }
475
624
 
476
625
  // ../../shared/ext-param/dist/param.js
477
- import { RuntimeError as RuntimeError5 } from "@rcrsr/rill";
626
+ import { RuntimeError as RuntimeError4 } from "@rcrsr/rill";
478
627
  function validateParamName(name) {
479
628
  if (name === "") {
480
- throw new RuntimeError5("RILL-R001", "param name must not be empty");
629
+ throw new RuntimeError4("RILL-R001", "param name must not be empty");
481
630
  }
482
631
  if (/\s/.test(name)) {
483
- throw new RuntimeError5("RILL-R001", "param name must be a valid identifier");
632
+ throw new RuntimeError4("RILL-R001", "param name must be a valid identifier");
484
633
  }
485
634
  }
486
635
  function buildAnnotations(desc) {
@@ -597,6 +746,27 @@ var p = {
597
746
 
598
747
  // src/factory.ts
599
748
  var DEFAULT_MAX_TOKENS = 8192;
749
+ function mapToHalt(ctx, error) {
750
+ const invalid = mapProviderError(ctx, "Gemini", error, detectGeminiError);
751
+ return new RuntimeHaltSignal3(invalid, true);
752
+ }
753
+ function haltInvalid(ctx, code, rawKind, message) {
754
+ return new RuntimeHaltSignal3(
755
+ ctx.invalidate(new Error(message), {
756
+ code,
757
+ provider: "gemini",
758
+ raw: { kind: rawKind, message }
759
+ }),
760
+ true
761
+ );
762
+ }
763
+ function streamErrorMessage(err) {
764
+ if (err === void 0) return "";
765
+ if (err instanceof RuntimeHaltSignal3) {
766
+ return getStatus2(err.value).message || err.message;
767
+ }
768
+ return err.message;
769
+ }
600
770
  var detectGeminiError = (error) => {
601
771
  if (error instanceof Error) {
602
772
  const message = error.message;
@@ -685,7 +855,7 @@ function createGeminiExtension(config) {
685
855
  const text = args["text"];
686
856
  const options = args["options"] ?? {};
687
857
  if (text.trim().length === 0) {
688
- throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
858
+ throw haltInvalid(ctx, "INVALID_INPUT", "empty_prompt", "prompt text cannot be empty");
689
859
  }
690
860
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
691
861
  const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
@@ -724,12 +894,12 @@ function createGeminiExtension(config) {
724
894
  }
725
895
  }
726
896
  } catch (error) {
727
- streamError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
897
+ streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
728
898
  const duration = Date.now() - messageStartTime;
729
899
  emitExtensionEvent(ctx, {
730
900
  event: "gemini:error",
731
901
  subsystem: "extension:gemini",
732
- error: streamError.message,
902
+ error: streamErrorMessage(streamError),
733
903
  duration
734
904
  });
735
905
  throw streamError;
@@ -820,10 +990,7 @@ function createGeminiExtension(config) {
820
990
  const inputMessages = args["messages"];
821
991
  const options = args["options"] ?? {};
822
992
  if (inputMessages.length === 0) {
823
- throw new RuntimeError6(
824
- "RILL-R004",
825
- "messages list cannot be empty"
826
- );
993
+ throw haltInvalid(ctx, "INVALID_INPUT", "empty_messages", "messages list cannot be empty");
827
994
  }
828
995
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
829
996
  const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
@@ -831,21 +998,15 @@ function createGeminiExtension(config) {
831
998
  for (let i = 0; i < inputMessages.length; i++) {
832
999
  const msg = inputMessages[i];
833
1000
  if (!msg || typeof msg !== "object" || !("role" in msg)) {
834
- throw new RuntimeError6(
835
- "RILL-R004",
836
- "message missing required 'role' field"
837
- );
1001
+ throw haltInvalid(ctx, "INVALID_INPUT", "invalid_message_format", "message missing required 'role' field");
838
1002
  }
839
1003
  const role = msg["role"];
840
1004
  if (role !== "user" && role !== "assistant" && role !== "tool") {
841
- throw new RuntimeError6("RILL-R004", `invalid role '${role}'`);
1005
+ throw haltInvalid(ctx, "INVALID_INPUT", "invalid_role", `invalid role '${String(role)}'`);
842
1006
  }
843
1007
  if (role === "user" || role === "tool") {
844
1008
  if (!("content" in msg) || typeof msg["content"] !== "string") {
845
- throw new RuntimeError6(
846
- "RILL-R004",
847
- `${role} message requires 'content'`
848
- );
1009
+ throw haltInvalid(ctx, "INVALID_INPUT", "missing_message_content", `${role} message requires 'content'`);
849
1010
  }
850
1011
  contents.push({
851
1012
  role: "user",
@@ -855,10 +1016,7 @@ function createGeminiExtension(config) {
855
1016
  const hasContent = "content" in msg && msg["content"];
856
1017
  const hasToolCalls = "tool_calls" in msg && msg["tool_calls"];
857
1018
  if (!hasContent && !hasToolCalls) {
858
- throw new RuntimeError6(
859
- "RILL-R004",
860
- "assistant message requires 'content' or 'tool_calls'"
861
- );
1019
+ throw haltInvalid(ctx, "INVALID_INPUT", "invalid_assistant_message", "assistant message requires 'content' or 'tool_calls'");
862
1020
  }
863
1021
  if (hasContent) {
864
1022
  contents.push({
@@ -897,12 +1055,12 @@ function createGeminiExtension(config) {
897
1055
  }
898
1056
  }
899
1057
  } catch (error) {
900
- streamError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1058
+ streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
901
1059
  const duration = Date.now() - messagesStartTime;
902
1060
  emitExtensionEvent(ctx, {
903
1061
  event: "gemini:error",
904
1062
  subsystem: "extension:gemini",
905
- error: streamError.message,
1063
+ error: streamErrorMessage(streamError),
906
1064
  duration
907
1065
  });
908
1066
  throw streamError;
@@ -995,10 +1153,7 @@ function createGeminiExtension(config) {
995
1153
  });
996
1154
  const embedding = response.embeddings?.[0];
997
1155
  if (!embedding || !embedding.values || embedding.values.length === 0) {
998
- throw new RuntimeError6(
999
- "RILL-R004",
1000
- "Gemini: empty embedding returned"
1001
- );
1156
+ throw haltInvalid(ctx, "PROTOCOL", "empty_embedding_response", "Gemini: empty embedding returned");
1002
1157
  }
1003
1158
  const float32Data = new Float32Array(embedding.values);
1004
1159
  const vector = createVector(float32Data, factoryEmbedModel);
@@ -1013,11 +1168,11 @@ function createGeminiExtension(config) {
1013
1168
  return vector;
1014
1169
  } catch (error) {
1015
1170
  const duration = Date.now() - startTime;
1016
- const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1171
+ const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
1017
1172
  emitExtensionEvent(ctx, {
1018
1173
  event: "gemini:error",
1019
1174
  subsystem: "extension:gemini",
1020
- error: rillError.message,
1175
+ error: streamErrorMessage(rillError),
1021
1176
  duration
1022
1177
  });
1023
1178
  throw rillError;
@@ -1044,17 +1199,11 @@ function createGeminiExtension(config) {
1044
1199
  });
1045
1200
  const vectors = [];
1046
1201
  if (!response.embeddings || response.embeddings.length === 0) {
1047
- throw new RuntimeError6(
1048
- "RILL-R004",
1049
- "Gemini: empty embeddings returned"
1050
- );
1202
+ throw haltInvalid(ctx, "PROTOCOL", "empty_embeddings_response", "Gemini: empty embeddings returned");
1051
1203
  }
1052
1204
  for (const embedding of response.embeddings) {
1053
1205
  if (!embedding || !embedding.values || embedding.values.length === 0) {
1054
- throw new RuntimeError6(
1055
- "RILL-R004",
1056
- "Gemini: empty embedding returned"
1057
- );
1206
+ throw haltInvalid(ctx, "PROTOCOL", "empty_embedding_response", "Gemini: empty embedding returned");
1058
1207
  }
1059
1208
  const float32Data = new Float32Array(embedding.values);
1060
1209
  const vector = createVector(float32Data, factoryEmbedModel);
@@ -1074,11 +1223,11 @@ function createGeminiExtension(config) {
1074
1223
  return vectors;
1075
1224
  } catch (error) {
1076
1225
  const duration = Date.now() - startTime;
1077
- const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1226
+ const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
1078
1227
  emitExtensionEvent(ctx, {
1079
1228
  event: "gemini:error",
1080
1229
  subsystem: "extension:gemini",
1081
- error: rillError.message,
1230
+ error: streamErrorMessage(rillError),
1082
1231
  duration
1083
1232
  });
1084
1233
  throw rillError;
@@ -1110,7 +1259,7 @@ function createGeminiExtension(config) {
1110
1259
  const toolsDict = args["tools"];
1111
1260
  const options = args["options"] ?? {};
1112
1261
  if (prompt.trim().length === 0) {
1113
- throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
1262
+ throw haltInvalid(ctx, "INVALID_INPUT", "empty_prompt", "prompt text cannot be empty");
1114
1263
  }
1115
1264
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
1116
1265
  const maxTokens = typeof options["max_tokens"] === "number" && options["max_tokens"] > 0 ? options["max_tokens"] : factoryMaxTokens;
@@ -1309,7 +1458,7 @@ function createGeminiExtension(config) {
1309
1458
  r();
1310
1459
  }
1311
1460
  }).catch((error) => {
1312
- streamError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1461
+ streamError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
1313
1462
  streamDone = true;
1314
1463
  if (resolveNext) {
1315
1464
  const r = resolveNext;
@@ -1358,7 +1507,7 @@ function createGeminiExtension(config) {
1358
1507
  emitExtensionEvent(ctx, {
1359
1508
  event: "gemini:error",
1360
1509
  subsystem: "extension:gemini",
1361
- error: streamError.message,
1510
+ error: streamErrorMessage(streamError),
1362
1511
  duration: Date.now()
1363
1512
  });
1364
1513
  return {
@@ -1374,7 +1523,7 @@ function createGeminiExtension(config) {
1374
1523
  emitExtensionEvent(ctx, {
1375
1524
  event: "gemini:error",
1376
1525
  subsystem: "extension:gemini",
1377
- error: streamError.message,
1526
+ error: streamErrorMessage(streamError),
1378
1527
  duration
1379
1528
  });
1380
1529
  throw streamError;
@@ -1447,16 +1596,10 @@ function createGeminiExtension(config) {
1447
1596
  const schemaArg = args["schema"];
1448
1597
  const options = args["options"] ?? {};
1449
1598
  if (!schemaArg || !schemaArg.__rill_type || !schemaArg.structure) {
1450
- throw new RuntimeError6(
1451
- "RILL-R004",
1452
- "generate requires a type expression as schema"
1453
- );
1599
+ throw haltInvalid(ctx, "INVALID_INPUT", "invalid_schema", "generate requires a type expression as schema");
1454
1600
  }
1455
1601
  if (schemaArg.structure.kind !== "dict") {
1456
- throw new RuntimeError6(
1457
- "RILL-R004",
1458
- `generate requires a dict type as schema, got ${schemaArg.structure.kind}`
1459
- );
1602
+ throw haltInvalid(ctx, "INVALID_INPUT", "invalid_schema_type", `generate requires a dict type as schema, got ${schemaArg.structure.kind}`);
1460
1603
  }
1461
1604
  const jsonSchema = buildJsonSchemaFromStructuralType(schemaArg.structure);
1462
1605
  const geminiProperties = {};
@@ -1518,10 +1661,7 @@ function createGeminiExtension(config) {
1518
1661
  data = JSON.parse(raw);
1519
1662
  } catch (parseError) {
1520
1663
  const detail = parseError instanceof Error ? parseError.message : String(parseError);
1521
- throw new RuntimeError6(
1522
- "RILL-R004",
1523
- `generate: failed to parse response JSON: ${detail}`
1524
- );
1664
+ throw haltInvalid(ctx, "PROTOCOL", "json_parse_failed", `generate: failed to parse response JSON: ${detail}`);
1525
1665
  }
1526
1666
  const inputTokens = response.usageMetadata?.promptTokenCount ?? 0;
1527
1667
  const outputTokens = response.usageMetadata?.candidatesTokenCount ?? 0;
@@ -1551,11 +1691,11 @@ function createGeminiExtension(config) {
1551
1691
  return generateResult;
1552
1692
  } catch (error) {
1553
1693
  const duration = Date.now() - startTime;
1554
- const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1694
+ const rillError = error instanceof RuntimeError5 || error instanceof RuntimeHaltSignal3 ? error : mapToHalt(ctx, error);
1555
1695
  emitExtensionEvent(ctx, {
1556
1696
  event: "gemini:error",
1557
1697
  subsystem: "extension:gemini",
1558
- error: rillError.message,
1698
+ error: streamErrorMessage(rillError),
1559
1699
  duration
1560
1700
  });
1561
1701
  throw rillError;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rcrsr/rill-ext-gemini",
3
- "version": "0.18.4",
3
+ "version": "0.19.1",
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.18.4"
20
+ "@rcrsr/rill": "~0.19.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@rcrsr/rill": "~0.18.4",
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-llm-shared": "^0.18.4",
29
- "@rcrsr/rill-ext-param-shared": "0.18.4"
28
+ "@rcrsr/rill-ext-llm-shared": "^0.19.0",
29
+ "@rcrsr/rill-ext-param-shared": "0.19.0"
30
30
  },
31
31
  "files": [
32
32
  "dist"