@rcrsr/rill-ext-gemini 0.9.0 → 0.11.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.
Files changed (2) hide show
  1. package/dist/index.js +207 -67
  2. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import {
4
4
  Type
5
5
  } from "@google/genai";
6
6
  import {
7
- RuntimeError as RuntimeError5,
7
+ RuntimeError as RuntimeError6,
8
8
  emitExtensionEvent,
9
9
  createVector,
10
10
  isVector,
@@ -99,6 +99,50 @@ function mapRillType(rillType) {
99
99
  }
100
100
  return jsonType;
101
101
  }
102
+ function buildPropertyFromStructuralType(rillType) {
103
+ if (rillType.type === "closure" || rillType.type === "tuple") {
104
+ throw new RuntimeError3("RILL-R004", `unsupported type for JSON Schema: ${rillType.type}`);
105
+ }
106
+ if (rillType.type === "any") {
107
+ return {};
108
+ }
109
+ if (rillType.type === "list") {
110
+ const property = { type: "array" };
111
+ if (rillType.element !== void 0) {
112
+ property.items = buildPropertyFromStructuralType(rillType.element);
113
+ }
114
+ return property;
115
+ }
116
+ if (rillType.type === "dict") {
117
+ return { type: "object" };
118
+ }
119
+ return { type: mapRillType(rillType.type) };
120
+ }
121
+ function buildJsonSchemaFromStructuralType(type, params) {
122
+ const properties = {};
123
+ const required = [];
124
+ if (type.type === "closure") {
125
+ const closureParams = type.params ?? [];
126
+ for (let i = 0; i < closureParams.length; i++) {
127
+ const [paramName, paramType] = closureParams[i];
128
+ const rillParam = params?.[i];
129
+ const property = buildPropertyFromStructuralType(paramType);
130
+ const description = rillParam?.annotations["description"];
131
+ if (typeof description === "string") {
132
+ property.description = description;
133
+ }
134
+ const enumAnnotation = rillParam?.annotations["enum"];
135
+ if (Array.isArray(enumAnnotation)) {
136
+ property.enum = enumAnnotation;
137
+ }
138
+ properties[paramName] = property;
139
+ if (rillParam === void 0 || rillParam.defaultValue === void 0) {
140
+ required.push(paramName);
141
+ }
142
+ }
143
+ }
144
+ return { type: "object", properties, required, additionalProperties: false };
145
+ }
102
146
  function buildJsonSchema(rillSchema) {
103
147
  const properties = {};
104
148
  const required = [];
@@ -303,39 +347,15 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
303
347
  let inputSchema;
304
348
  const params = callable.kind === "application" ? callable.params ?? [] : callable.kind === "script" ? callable.params : [];
305
349
  if (params.length > 0) {
306
- const properties = {};
307
- const required = [];
308
- for (const param of params) {
309
- const property = {};
310
- if (param.typeName !== null) {
311
- const descriptor = {
312
- [param.name]: { type: param.typeName }
313
- };
314
- const schema = buildJsonSchema(descriptor);
315
- const built = schema.properties[param.name];
316
- if (built !== void 0) {
317
- Object.assign(property, built);
318
- }
319
- }
320
- let paramDesc;
321
- if (callable.kind === "script") {
322
- const annot = callable.paramAnnotations[param.name];
323
- paramDesc = annot?.["description"] ?? "";
324
- } else {
325
- paramDesc = param.description ?? "";
326
- }
327
- if (paramDesc) {
328
- property["description"] = paramDesc;
329
- }
330
- properties[param.name] = property;
331
- if (param.defaultValue === null) {
332
- required.push(param.name);
333
- }
334
- }
350
+ const closureType = {
351
+ type: "closure",
352
+ params: params.map((p2) => [p2.name, p2.type ?? { type: "any" }])
353
+ };
354
+ const builtSchema = buildJsonSchemaFromStructuralType(closureType, [...params]);
335
355
  inputSchema = {
336
356
  type: "object",
337
- properties,
338
- required
357
+ properties: builtSchema.properties,
358
+ required: builtSchema.required
339
359
  };
340
360
  } else {
341
361
  inputSchema = { type: "object", properties: {}, required: [] };
@@ -455,6 +475,126 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
455
475
  };
456
476
  }
457
477
 
478
+ // ../../shared/ext-param/dist/param.js
479
+ import { RuntimeError as RuntimeError5 } from "@rcrsr/rill";
480
+ function validateParamName(name) {
481
+ if (name === "") {
482
+ throw new RuntimeError5("RILL-R001", "param name must not be empty");
483
+ }
484
+ if (/\s/.test(name)) {
485
+ throw new RuntimeError5("RILL-R001", "param name must be a valid identifier");
486
+ }
487
+ }
488
+ function buildAnnotations(desc) {
489
+ if (desc !== void 0) {
490
+ return { description: desc };
491
+ }
492
+ return {};
493
+ }
494
+ var p = {
495
+ /**
496
+ * IR-1: Creates a string parameter descriptor.
497
+ *
498
+ * @param name - Parameter name (must be a valid identifier)
499
+ * @param desc - Optional description
500
+ * @returns RillParam with type 'string'
501
+ */
502
+ str(name, desc) {
503
+ validateParamName(name);
504
+ return {
505
+ name,
506
+ type: { type: "string" },
507
+ defaultValue: void 0,
508
+ annotations: buildAnnotations(desc)
509
+ };
510
+ },
511
+ /**
512
+ * IR-2: Creates a number parameter descriptor.
513
+ *
514
+ * @param name - Parameter name (must be a valid identifier)
515
+ * @param desc - Optional description
516
+ * @param def - Optional default value
517
+ * @returns RillParam with type 'number'
518
+ */
519
+ num(name, desc, def) {
520
+ validateParamName(name);
521
+ return {
522
+ name,
523
+ type: { type: "number" },
524
+ defaultValue: def,
525
+ annotations: buildAnnotations(desc)
526
+ };
527
+ },
528
+ /**
529
+ * IR-3: Creates a boolean parameter descriptor.
530
+ *
531
+ * @param name - Parameter name (must be a valid identifier)
532
+ * @param desc - Optional description
533
+ * @param def - Optional default value
534
+ * @returns RillParam with type 'bool'
535
+ */
536
+ bool(name, desc, def) {
537
+ validateParamName(name);
538
+ return {
539
+ name,
540
+ type: { type: "bool" },
541
+ defaultValue: def,
542
+ annotations: buildAnnotations(desc)
543
+ };
544
+ },
545
+ /**
546
+ * IR-4: Creates a dict parameter descriptor.
547
+ *
548
+ * @param name - Parameter name (must be a valid identifier)
549
+ * @param desc - Optional description
550
+ * @param def - Optional default value
551
+ * @returns RillParam with type 'dict'
552
+ */
553
+ dict(name, desc, def) {
554
+ validateParamName(name);
555
+ return {
556
+ name,
557
+ type: { type: "dict" },
558
+ defaultValue: def,
559
+ annotations: buildAnnotations(desc)
560
+ };
561
+ },
562
+ /**
563
+ * IR-5: Creates a list parameter descriptor.
564
+ *
565
+ * @param name - Parameter name (must be a valid identifier)
566
+ * @param itemType - Optional element type; omitted when not provided
567
+ * @param desc - Optional description
568
+ * @returns RillParam with type 'list' (with element if itemType provided)
569
+ */
570
+ list(name, itemType, desc) {
571
+ validateParamName(name);
572
+ const type = itemType !== void 0 ? { type: "list", element: itemType } : { type: "list" };
573
+ return {
574
+ name,
575
+ type,
576
+ defaultValue: void 0,
577
+ annotations: buildAnnotations(desc)
578
+ };
579
+ },
580
+ /**
581
+ * IR-6: Creates a callable parameter descriptor.
582
+ *
583
+ * @param name - Parameter name (must be a valid identifier)
584
+ * @param desc - Optional description
585
+ * @returns RillParam with type 'closure'
586
+ */
587
+ callable(name, desc) {
588
+ validateParamName(name);
589
+ return {
590
+ name,
591
+ type: { type: "closure" },
592
+ defaultValue: void 0,
593
+ annotations: buildAnnotations(desc)
594
+ };
595
+ }
596
+ };
597
+
458
598
  // src/factory.ts
459
599
  var DEFAULT_MAX_TOKENS = 8192;
460
600
  var detectGeminiError = (error) => {
@@ -535,8 +675,8 @@ function createGeminiExtension(config) {
535
675
  // IR-4: gemini::message
536
676
  message: {
537
677
  params: [
538
- { name: "text", type: "string" },
539
- { name: "options", type: "dict", defaultValue: {} }
678
+ p.str("text"),
679
+ p.dict("options", void 0, {})
540
680
  ],
541
681
  fn: async (args, ctx) => {
542
682
  const startTime = Date.now();
@@ -544,7 +684,7 @@ function createGeminiExtension(config) {
544
684
  const text = args[0];
545
685
  const options = args[1] ?? {};
546
686
  if (text.trim().length === 0) {
547
- throw new RuntimeError5("RILL-R004", "prompt text cannot be empty");
687
+ throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
548
688
  }
549
689
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
550
690
  const maxTokens = typeof options["max_tokens"] === "number" ? options["max_tokens"] : factoryMaxTokens;
@@ -600,7 +740,7 @@ function createGeminiExtension(config) {
600
740
  return result2;
601
741
  } catch (error) {
602
742
  const duration = Date.now() - startTime;
603
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
743
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
604
744
  emitExtensionEvent(ctx, {
605
745
  event: "gemini:error",
606
746
  subsystem: "extension:gemini",
@@ -611,13 +751,13 @@ function createGeminiExtension(config) {
611
751
  }
612
752
  },
613
753
  description: "Send single message to Gemini API",
614
- returnType: "dict"
754
+ returnType: { type: "dict" }
615
755
  },
616
756
  // IR-5: gemini::messages
617
757
  messages: {
618
758
  params: [
619
- { name: "messages", type: "list" },
620
- { name: "options", type: "dict", defaultValue: {} }
759
+ p.list("messages"),
760
+ p.dict("options", void 0, {})
621
761
  ],
622
762
  fn: async (args, ctx) => {
623
763
  const startTime = Date.now();
@@ -625,7 +765,7 @@ function createGeminiExtension(config) {
625
765
  const messages = args[0];
626
766
  const options = args[1] ?? {};
627
767
  if (messages.length === 0) {
628
- throw new RuntimeError5(
768
+ throw new RuntimeError6(
629
769
  "RILL-R004",
630
770
  "messages list cannot be empty"
631
771
  );
@@ -636,18 +776,18 @@ function createGeminiExtension(config) {
636
776
  for (let i = 0; i < messages.length; i++) {
637
777
  const msg = messages[i];
638
778
  if (!msg || typeof msg !== "object" || !("role" in msg)) {
639
- throw new RuntimeError5(
779
+ throw new RuntimeError6(
640
780
  "RILL-R004",
641
781
  "message missing required 'role' field"
642
782
  );
643
783
  }
644
784
  const role = msg["role"];
645
785
  if (role !== "user" && role !== "assistant" && role !== "tool") {
646
- throw new RuntimeError5("RILL-R004", `invalid role '${role}'`);
786
+ throw new RuntimeError6("RILL-R004", `invalid role '${role}'`);
647
787
  }
648
788
  if (role === "user" || role === "tool") {
649
789
  if (!("content" in msg) || typeof msg["content"] !== "string") {
650
- throw new RuntimeError5(
790
+ throw new RuntimeError6(
651
791
  "RILL-R004",
652
792
  `${role} message requires 'content'`
653
793
  );
@@ -660,7 +800,7 @@ function createGeminiExtension(config) {
660
800
  const hasContent = "content" in msg && msg["content"];
661
801
  const hasToolCalls = "tool_calls" in msg && msg["tool_calls"];
662
802
  if (!hasContent && !hasToolCalls) {
663
- throw new RuntimeError5(
803
+ throw new RuntimeError6(
664
804
  "RILL-R004",
665
805
  "assistant message requires 'content' or 'tool_calls'"
666
806
  );
@@ -724,7 +864,7 @@ function createGeminiExtension(config) {
724
864
  return result2;
725
865
  } catch (error) {
726
866
  const duration = Date.now() - startTime;
727
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
867
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
728
868
  emitExtensionEvent(ctx, {
729
869
  event: "gemini:error",
730
870
  subsystem: "extension:gemini",
@@ -735,11 +875,11 @@ function createGeminiExtension(config) {
735
875
  }
736
876
  },
737
877
  description: "Send multi-turn conversation to Gemini API",
738
- returnType: "dict"
878
+ returnType: { type: "dict" }
739
879
  },
740
880
  // IR-6: gemini::embed
741
881
  embed: {
742
- params: [{ name: "text", type: "string" }],
882
+ params: [p.str("text")],
743
883
  fn: async (args, ctx) => {
744
884
  const startTime = Date.now();
745
885
  try {
@@ -752,7 +892,7 @@ function createGeminiExtension(config) {
752
892
  });
753
893
  const embedding = response.embeddings?.[0];
754
894
  if (!embedding || !embedding.values || embedding.values.length === 0) {
755
- throw new RuntimeError5(
895
+ throw new RuntimeError6(
756
896
  "RILL-R004",
757
897
  "Gemini: empty embedding returned"
758
898
  );
@@ -770,7 +910,7 @@ function createGeminiExtension(config) {
770
910
  return vector;
771
911
  } catch (error) {
772
912
  const duration = Date.now() - startTime;
773
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
913
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
774
914
  emitExtensionEvent(ctx, {
775
915
  event: "gemini:error",
776
916
  subsystem: "extension:gemini",
@@ -781,11 +921,11 @@ function createGeminiExtension(config) {
781
921
  }
782
922
  },
783
923
  description: "Generate embedding vector for text",
784
- returnType: "vector"
924
+ returnType: { type: "vector" }
785
925
  },
786
926
  // IR-7: gemini::embed_batch
787
927
  embed_batch: {
788
- params: [{ name: "texts", type: "list" }],
928
+ params: [p.list("texts")],
789
929
  fn: async (args, ctx) => {
790
930
  const startTime = Date.now();
791
931
  try {
@@ -801,14 +941,14 @@ function createGeminiExtension(config) {
801
941
  });
802
942
  const vectors = [];
803
943
  if (!response.embeddings || response.embeddings.length === 0) {
804
- throw new RuntimeError5(
944
+ throw new RuntimeError6(
805
945
  "RILL-R004",
806
946
  "Gemini: empty embeddings returned"
807
947
  );
808
948
  }
809
949
  for (const embedding of response.embeddings) {
810
950
  if (!embedding || !embedding.values || embedding.values.length === 0) {
811
- throw new RuntimeError5(
951
+ throw new RuntimeError6(
812
952
  "RILL-R004",
813
953
  "Gemini: empty embedding returned"
814
954
  );
@@ -831,7 +971,7 @@ function createGeminiExtension(config) {
831
971
  return vectors;
832
972
  } catch (error) {
833
973
  const duration = Date.now() - startTime;
834
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
974
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
835
975
  emitExtensionEvent(ctx, {
836
976
  event: "gemini:error",
837
977
  subsystem: "extension:gemini",
@@ -842,13 +982,13 @@ function createGeminiExtension(config) {
842
982
  }
843
983
  },
844
984
  description: "Generate embedding vectors for multiple texts",
845
- returnType: "list"
985
+ returnType: { type: "list" }
846
986
  },
847
987
  // IR-8: gemini::tool_loop
848
988
  tool_loop: {
849
989
  params: [
850
- { name: "prompt", type: "string" },
851
- { name: "options", type: "dict", defaultValue: {} }
990
+ p.str("prompt"),
991
+ p.dict("options", void 0, {})
852
992
  ],
853
993
  fn: async (args, ctx) => {
854
994
  const startTime = Date.now();
@@ -856,10 +996,10 @@ function createGeminiExtension(config) {
856
996
  const prompt = args[0];
857
997
  const options = args[1] ?? {};
858
998
  if (prompt.trim().length === 0) {
859
- throw new RuntimeError5("RILL-R004", "prompt text cannot be empty");
999
+ throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
860
1000
  }
861
1001
  if (!("tools" in options) || !isDict2(options["tools"])) {
862
- throw new RuntimeError5(
1002
+ throw new RuntimeError6(
863
1003
  "RILL-R004",
864
1004
  "tool_loop requires 'tools' option"
865
1005
  );
@@ -1036,7 +1176,7 @@ function createGeminiExtension(config) {
1036
1176
  return result2;
1037
1177
  } catch (error) {
1038
1178
  const duration = Date.now() - startTime;
1039
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
1179
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1040
1180
  emitExtensionEvent(ctx, {
1041
1181
  event: "gemini:error",
1042
1182
  subsystem: "extension:gemini",
@@ -1047,13 +1187,13 @@ function createGeminiExtension(config) {
1047
1187
  }
1048
1188
  },
1049
1189
  description: "Execute tool-use loop with Gemini API",
1050
- returnType: "dict"
1190
+ returnType: { type: "dict" }
1051
1191
  },
1052
1192
  // IR-3: gemini::generate
1053
1193
  generate: {
1054
1194
  params: [
1055
- { name: "prompt", type: "string" },
1056
- { name: "options", type: "dict" }
1195
+ p.str("prompt"),
1196
+ p.dict("options")
1057
1197
  ],
1058
1198
  fn: async (args, ctx) => {
1059
1199
  const startTime = Date.now();
@@ -1061,7 +1201,7 @@ function createGeminiExtension(config) {
1061
1201
  const prompt = args[0];
1062
1202
  const options = args[1] ?? {};
1063
1203
  if (!("schema" in options) || options["schema"] === null || options["schema"] === void 0) {
1064
- throw new RuntimeError5(
1204
+ throw new RuntimeError6(
1065
1205
  "RILL-R004",
1066
1206
  "generate requires 'schema' option"
1067
1207
  );
@@ -1127,7 +1267,7 @@ function createGeminiExtension(config) {
1127
1267
  data = JSON.parse(raw);
1128
1268
  } catch (parseError) {
1129
1269
  const detail = parseError instanceof Error ? parseError.message : String(parseError);
1130
- throw new RuntimeError5(
1270
+ throw new RuntimeError6(
1131
1271
  "RILL-R004",
1132
1272
  `generate: failed to parse response JSON: ${detail}`
1133
1273
  );
@@ -1160,7 +1300,7 @@ function createGeminiExtension(config) {
1160
1300
  return generateResult;
1161
1301
  } catch (error) {
1162
1302
  const duration = Date.now() - startTime;
1163
- const rillError = error instanceof RuntimeError5 ? error : mapProviderError("Gemini", error, detectGeminiError);
1303
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("Gemini", error, detectGeminiError);
1164
1304
  emitExtensionEvent(ctx, {
1165
1305
  event: "gemini:error",
1166
1306
  subsystem: "extension:gemini",
@@ -1171,7 +1311,7 @@ function createGeminiExtension(config) {
1171
1311
  }
1172
1312
  },
1173
1313
  description: "Generate structured output from Gemini API",
1174
- returnType: "dict"
1314
+ returnType: { type: "dict" }
1175
1315
  }
1176
1316
  };
1177
1317
  result.dispose = dispose;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rcrsr/rill-ext-gemini",
3
- "version": "0.9.0",
3
+ "version": "0.11.0",
4
4
  "description": "rill extension for Google Gemini API integration",
5
5
  "license": "MIT",
6
6
  "author": "Andre Bremer",
@@ -17,10 +17,10 @@
17
17
  "scripting"
18
18
  ],
19
19
  "peerDependencies": {
20
- "@rcrsr/rill": "^0.9.0"
20
+ "@rcrsr/rill": "^0.11.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@rcrsr/rill": "^0.9.0",
23
+ "@rcrsr/rill": "^0.11.0",
24
24
  "@types/node": "^25.3.0",
25
25
  "dts-bundle-generator": "^9.5.1",
26
26
  "tsup": "^8.5.1",
@@ -43,7 +43,8 @@
43
43
  "access": "public"
44
44
  },
45
45
  "dependencies": {
46
- "@google/genai": "^1.42.0"
46
+ "@google/genai": "^1.42.0",
47
+ "@rcrsr/rill-ext-param-shared": "0.0.1"
47
48
  },
48
49
  "scripts": {
49
50
  "build": "tsup && dts-bundle-generator --config dts-bundle-generator.config.cjs",