@rcrsr/rill-ext-openai 0.8.6 → 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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # @rcrsr/rill-ext-openai
2
2
 
3
- [rill](https://rill.run) extension for [OpenAI](https://platform.openai.com/docs) API integration. Provides `message`, `messages`, `embed`, `embed_batch`, and `tool_loop` host functions. Compatible with any OpenAI-compatible server (LM Studio, Ollama, vLLM).
3
+ [rill](https://rill.run) extension for [OpenAI](https://platform.openai.com/docs) API integration. Provides `message`, `messages`, `embed`, `embed_batch`, `tool_loop`, and `generate` host functions. Compatible with any OpenAI-compatible server (LM Studio, Ollama, vLLM).
4
4
 
5
5
  > **Experimental.** Breaking changes will occur before stabilization.
6
6
 
@@ -20,7 +20,7 @@ import { createOpenAIExtension } from '@rcrsr/rill-ext-openai';
20
20
 
21
21
  const ext = createOpenAIExtension({
22
22
  api_key: process.env.OPENAI_API_KEY!,
23
- model: 'gpt-4-turbo',
23
+ model: 'gpt-4o',
24
24
  });
25
25
  const prefixed = prefixFunctions('openai', ext);
26
26
  const { dispose, ...functions } = prefixed;
@@ -36,134 +36,15 @@ const result = await execute(parse(script), ctx);
36
36
  dispose?.();
37
37
  ```
38
38
 
39
- ## Host Functions
40
-
41
- All functions return a dict with `content`, `model`, `usage`, `stop_reason`, `id`, and `messages`.
42
-
43
- ### openai::message(text, options?)
44
-
45
- Send a single message to OpenAI.
46
-
47
- ```rill
48
- openai::message("Analyze this code for security issues") => $response
49
- $response.content -> log
50
- $response.usage.output -> log
51
- ```
52
-
53
- ### openai::messages(messages, options?)
54
-
55
- Send a multi-turn conversation.
56
-
57
- ```rill
58
- openai::messages([
59
- [role: "user", content: "What is rill?"],
60
- [role: "assistant", content: "A scripting language for AI agents."],
61
- [role: "user", content: "Show me an example."]
62
- ]) => $response
63
- $response.content -> log
64
- ```
65
-
66
- ### openai::embed(text)
67
-
68
- Generate an embedding vector for text. Requires `embed_model` in config.
69
-
70
- ```rill
71
- openai::embed("Hello world") => $vector
72
- ```
73
-
74
- ### openai::embed_batch(texts)
75
-
76
- Generate embedding vectors for multiple texts in a single API call.
77
-
78
- ```rill
79
- openai::embed_batch(["Hello", "World"]) => $vectors
80
- ```
81
-
82
- ### openai::tool_loop(prompt, options)
83
-
84
- Execute a tool-use loop where the model calls rill functions iteratively.
85
-
86
- ```rill
87
- openai::tool_loop("Find the weather", [tools: $my_tools]) => $result
88
- $result.content -> log
89
- $result.turns -> log
90
- ```
91
-
92
- ## Configuration
93
-
94
- ```typescript
95
- const ext = createOpenAIExtension({
96
- api_key: process.env.OPENAI_API_KEY!,
97
- model: 'gpt-4-turbo',
98
- temperature: 0.7,
99
- base_url: 'http://localhost:1234/v1', // OpenAI-compatible server
100
- max_tokens: 4096,
101
- max_retries: 3,
102
- timeout: 30000,
103
- system: 'You are a helpful assistant.',
104
- embed_model: 'text-embedding-3-small',
105
- });
106
- ```
107
-
108
- | Option | Type | Default | Description |
109
- |--------|------|---------|-------------|
110
- | `api_key` | string | required | OpenAI API key |
111
- | `model` | string | required | Model identifier |
112
- | `temperature` | number | undefined | Temperature (0.0-2.0) |
113
- | `base_url` | string | undefined | Custom API endpoint URL |
114
- | `max_tokens` | number | `4096` | Max tokens in response |
115
- | `max_retries` | number | undefined | Max retry attempts |
116
- | `timeout` | number | undefined | Request timeout in ms |
117
- | `system` | string | undefined | Default system prompt |
118
- | `embed_model` | string | undefined | Embedding model identifier |
119
-
120
- ## Result Shape
121
-
122
- ```typescript
123
- interface OpenAIResult {
124
- content: string; // response text
125
- model: string; // model used
126
- usage: {
127
- input: number; // prompt tokens
128
- output: number; // completion tokens
129
- };
130
- stop_reason: string; // finish reason
131
- id: string; // request ID
132
- messages: Array<{ // full conversation history
133
- role: string;
134
- content: string;
135
- }>;
136
- }
137
- ```
138
-
139
- ## Lifecycle
140
-
141
- Call `dispose()` on the extension to cancel pending requests:
142
-
143
- ```typescript
144
- const ext = createOpenAIExtension({ ... });
145
- // ... use extension ...
146
- await ext.dispose?.();
147
- ```
148
-
149
- ## Test Host
150
-
151
- A runnable example at `examples/test-host.ts` wires up the extension with the rill runtime:
152
-
153
- ```bash
154
- pnpm exec tsx examples/test-host.ts
155
- pnpm exec tsx examples/test-host.ts -e 'openai::message("Tell me a joke") -> log'
156
- pnpm exec tsx examples/test-host.ts script.rill
157
- ```
39
+ ## Documentation
158
40
 
159
- Requires `OPENAI_API_KEY` environment variable (or `--base-url` for local servers).
41
+ See [full documentation](docs/extension-llm-openai.md) for configuration, functions, error handling, events, and examples.
160
42
 
161
- ## Documentation
43
+ ## Related
162
44
 
163
- | Document | Description |
164
- |----------|-------------|
165
- | [Extensions Guide](https://github.com/rcrsr/rill/blob/main/docs/integration-extensions.md) | Extension contract and patterns |
166
- | [Host API Reference](https://github.com/rcrsr/rill/blob/main/docs/ref-host-api.md) | Runtime context and host functions |
45
+ - [rill](https://github.com/rcrsr/rill) Core language runtime
46
+ - [Extensions Guide](https://github.com/rcrsr/rill/blob/main/docs/integration-extensions.md) — Extension contract and patterns
47
+ - [Host API Reference](https://github.com/rcrsr/rill/blob/main/docs/ref-host-api.md) Runtime context and host functions
167
48
 
168
49
  ## License
169
50
 
package/dist/index.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  // Generated by dts-bundle-generator v9.5.1
2
2
 
3
- import { ExtensionResult } from '@rcrsr/rill';
3
+ import { ExtensionConfigSchema, ExtensionResult } from '@rcrsr/rill';
4
4
 
5
5
  /**
6
6
  * Base configuration for LLM extensions
@@ -73,12 +73,8 @@ export type OpenAIExtensionConfig = LLMProviderConfig;
73
73
  * ```
74
74
  */
75
75
  export declare function createOpenAIExtension(config: OpenAIExtensionConfig): ExtensionResult;
76
- /**
77
- * @rcrsr/rill-ext-openai
78
- *
79
- * Extension for OpenAI API integration with rill scripts.
80
- */
81
76
  export declare const VERSION = "0.0.1";
77
+ export declare const configSchema: ExtensionConfigSchema;
82
78
 
83
79
  export {
84
80
  LLMProviderConfig as LLMExtensionConfig,
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  // src/factory.ts
2
2
  import OpenAI from "openai";
3
3
  import {
4
- RuntimeError as RuntimeError4,
4
+ RuntimeError as RuntimeError6,
5
5
  emitExtensionEvent,
6
6
  createVector,
7
- isCallable as isCallable2,
7
+ isDict as isDict2,
8
8
  isVector
9
9
  } from "@rcrsr/rill";
10
10
 
@@ -76,29 +76,152 @@ function mapProviderError(providerName, error, detect) {
76
76
  }
77
77
 
78
78
  // ../../shared/ext-llm/dist/tool-loop.js
79
- import { isCallable, isDict, RuntimeError as RuntimeError3 } from "@rcrsr/rill";
79
+ import { invokeCallable, isCallable, isDict, isRuntimeCallable, RuntimeError as RuntimeError4 } from "@rcrsr/rill";
80
+
81
+ // ../../shared/ext-llm/dist/schema.js
82
+ import { RuntimeError as RuntimeError3 } from "@rcrsr/rill";
83
+ var RILL_TYPE_MAP = {
84
+ string: "string",
85
+ number: "number",
86
+ bool: "boolean",
87
+ list: "array",
88
+ dict: "object",
89
+ vector: "object",
90
+ shape: "object"
91
+ };
92
+ function mapRillType(rillType) {
93
+ const jsonType = RILL_TYPE_MAP[rillType];
94
+ if (jsonType === void 0) {
95
+ throw new RuntimeError3("RILL-R004", `unsupported type: ${rillType}`);
96
+ }
97
+ return jsonType;
98
+ }
99
+ function buildPropertyFromStructuralType(rillType) {
100
+ if (rillType.type === "closure" || rillType.type === "tuple") {
101
+ throw new RuntimeError3("RILL-R004", `unsupported type for JSON Schema: ${rillType.type}`);
102
+ }
103
+ if (rillType.type === "any") {
104
+ return {};
105
+ }
106
+ if (rillType.type === "list") {
107
+ const property = { type: "array" };
108
+ if (rillType.element !== void 0) {
109
+ property.items = buildPropertyFromStructuralType(rillType.element);
110
+ }
111
+ return property;
112
+ }
113
+ if (rillType.type === "dict") {
114
+ return { type: "object" };
115
+ }
116
+ return { type: mapRillType(rillType.type) };
117
+ }
118
+ function buildJsonSchemaFromStructuralType(type, params) {
119
+ const properties = {};
120
+ const required = [];
121
+ if (type.type === "closure") {
122
+ const closureParams = type.params ?? [];
123
+ for (let i = 0; i < closureParams.length; i++) {
124
+ const [paramName, paramType] = closureParams[i];
125
+ const rillParam = params?.[i];
126
+ const property = buildPropertyFromStructuralType(paramType);
127
+ const description = rillParam?.annotations["description"];
128
+ if (typeof description === "string") {
129
+ property.description = description;
130
+ }
131
+ const enumAnnotation = rillParam?.annotations["enum"];
132
+ if (Array.isArray(enumAnnotation)) {
133
+ property.enum = enumAnnotation;
134
+ }
135
+ properties[paramName] = property;
136
+ if (rillParam === void 0 || rillParam.defaultValue === void 0) {
137
+ required.push(paramName);
138
+ }
139
+ }
140
+ }
141
+ return { type: "object", properties, required, additionalProperties: false };
142
+ }
143
+ function buildJsonSchema(rillSchema) {
144
+ const properties = {};
145
+ const required = [];
146
+ for (const [key, value] of Object.entries(rillSchema)) {
147
+ if (typeof value === "string") {
148
+ properties[key] = buildProperty(value);
149
+ } else if (typeof value === "object" && value !== null) {
150
+ properties[key] = buildProperty(value);
151
+ } else {
152
+ throw new RuntimeError3("RILL-R004", `unsupported type: ${String(value)}`);
153
+ }
154
+ required.push(key);
155
+ }
156
+ return { type: "object", properties, required, additionalProperties: false };
157
+ }
158
+ function buildProperty(descriptor) {
159
+ if (typeof descriptor === "string") {
160
+ const jsonType2 = mapRillType(descriptor);
161
+ return { type: jsonType2 };
162
+ }
163
+ const rillType = descriptor["type"];
164
+ if (typeof rillType !== "string") {
165
+ throw new RuntimeError3("RILL-R004", `unsupported type: ${String(rillType)}`);
166
+ }
167
+ const jsonType = mapRillType(rillType);
168
+ const property = { type: jsonType };
169
+ const description = descriptor["description"];
170
+ if (typeof description === "string") {
171
+ property.description = description;
172
+ }
173
+ if ("enum" in descriptor) {
174
+ if (rillType !== "string") {
175
+ throw new RuntimeError3("RILL-R004", "enum is only valid for string type");
176
+ }
177
+ const enumValues = descriptor["enum"];
178
+ if (Array.isArray(enumValues)) {
179
+ property.enum = enumValues;
180
+ }
181
+ }
182
+ if (rillType === "list" && "items" in descriptor) {
183
+ const items = descriptor["items"];
184
+ if (typeof items === "string") {
185
+ property.items = buildProperty(items);
186
+ } else if (typeof items === "object" && items !== null) {
187
+ property.items = buildProperty(items);
188
+ }
189
+ }
190
+ if (rillType === "dict" && "properties" in descriptor) {
191
+ const nestedProps = descriptor["properties"];
192
+ if (typeof nestedProps === "object" && nestedProps !== null) {
193
+ const subSchema = buildJsonSchema(nestedProps);
194
+ property.properties = subSchema.properties;
195
+ property.required = subSchema.required;
196
+ property.additionalProperties = false;
197
+ }
198
+ }
199
+ return property;
200
+ }
201
+
202
+ // ../../shared/ext-llm/dist/tool-loop.js
80
203
  async function executeToolCall(toolName, toolInput, tools, context) {
81
204
  if (!isDict(tools)) {
82
- throw new RuntimeError3("RILL-R004", "tools must be a dict mapping tool names to functions");
205
+ throw new RuntimeError4("RILL-R004", "tool_loop: tools must be a dict of name \u2192 callable");
83
206
  }
84
207
  const toolsDict = tools;
85
208
  const toolFn = toolsDict[toolName];
86
209
  if (toolFn === void 0 || toolFn === null) {
87
- throw new RuntimeError3("RILL-R004", `Unknown tool: ${toolName}`);
210
+ throw new RuntimeError4("RILL-R004", `Unknown tool: ${toolName}`);
88
211
  }
89
212
  if (!isCallable(toolFn)) {
90
- throw new RuntimeError3("RILL-R004", `Invalid tool input for ${toolName}: tool must be callable`);
213
+ throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: tool must be callable`);
91
214
  }
92
215
  if (typeof toolInput !== "object" || toolInput === null) {
93
- throw new RuntimeError3("RILL-R004", `Invalid tool input for ${toolName}: input must be an object`);
216
+ throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: input must be an object`);
94
217
  }
95
218
  const callable = toolFn;
96
- if (callable.kind !== "runtime" && callable.kind !== "application") {
97
- throw new RuntimeError3("RILL-R004", `Invalid tool input for ${toolName}: tool must be application or runtime callable`);
219
+ if (callable.kind !== "runtime" && callable.kind !== "application" && callable.kind !== "script") {
220
+ throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: tool must be application, runtime, or script callable`);
98
221
  }
99
222
  try {
100
223
  let args;
101
- if (callable.kind === "application" && callable.params) {
224
+ if ((callable.kind === "application" || callable.kind === "script") && callable.params && callable.params.length > 0) {
102
225
  const params = callable.params;
103
226
  const inputDict = toolInput;
104
227
  args = params.map((param) => {
@@ -108,6 +231,12 @@ async function executeToolCall(toolName, toolInput, tools, context) {
108
231
  } else {
109
232
  args = [toolInput];
110
233
  }
234
+ if (callable.kind === "script") {
235
+ if (!context) {
236
+ throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: script callable requires a runtime context`);
237
+ }
238
+ return await invokeCallable(callable, args, context);
239
+ }
111
240
  const ctx = context ?? {
112
241
  parent: void 0,
113
242
  variables: /* @__PURE__ */ new Map(),
@@ -116,77 +245,122 @@ async function executeToolCall(toolName, toolInput, tools, context) {
116
245
  const result = callable.fn(args, ctx);
117
246
  return result instanceof Promise ? await result : result;
118
247
  } catch (error) {
119
- if (error instanceof RuntimeError3) {
248
+ if (error instanceof RuntimeError4) {
120
249
  throw error;
121
250
  }
122
251
  const message = error instanceof Error ? error.message : "Unknown error";
123
- throw new RuntimeError3("RILL-R004", `Invalid tool input for ${toolName}: ${message}`);
252
+ throw new RuntimeError4("RILL-R004", `Invalid tool input for ${toolName}: ${message}`);
253
+ }
254
+ }
255
+ function sanitizeToolName(name) {
256
+ const match = name.match(/^[a-zA-Z0-9_-]*/);
257
+ const sanitized = match ? match[0] : "";
258
+ return sanitized.length > 0 ? sanitized : name;
259
+ }
260
+ function patchResponseToolCallNames(response, nameMap) {
261
+ if (!nameMap.size || !response || typeof response !== "object")
262
+ return;
263
+ const resp = response;
264
+ if (Array.isArray(resp["choices"])) {
265
+ for (const choice of resp["choices"]) {
266
+ const msg = choice?.["message"];
267
+ const tcs = msg?.["tool_calls"];
268
+ if (Array.isArray(tcs)) {
269
+ for (const tc of tcs) {
270
+ const fn = tc?.["function"];
271
+ if (fn && typeof fn["name"] === "string") {
272
+ const orig = fn["name"];
273
+ const san = nameMap.get(orig);
274
+ if (san !== void 0)
275
+ fn["name"] = san;
276
+ }
277
+ }
278
+ }
279
+ }
280
+ }
281
+ if (Array.isArray(resp["content"])) {
282
+ for (const block of resp["content"]) {
283
+ const b = block;
284
+ if (b?.["type"] === "tool_use" && typeof b?.["name"] === "string") {
285
+ const orig = b["name"];
286
+ const san = nameMap.get(orig);
287
+ if (san !== void 0)
288
+ b["name"] = san;
289
+ }
290
+ }
291
+ }
292
+ if (Array.isArray(resp["functionCalls"])) {
293
+ for (const fc of resp["functionCalls"]) {
294
+ const f = fc;
295
+ if (typeof f?.["name"] === "string") {
296
+ const orig = f["name"];
297
+ const san = nameMap.get(orig);
298
+ if (san !== void 0)
299
+ f["name"] = san;
300
+ }
301
+ }
302
+ }
303
+ if (Array.isArray(resp["candidates"])) {
304
+ for (const cand of resp["candidates"]) {
305
+ const content = cand?.["content"];
306
+ const parts = content?.["parts"];
307
+ if (Array.isArray(parts)) {
308
+ for (const part of parts) {
309
+ const fc = part?.["functionCall"];
310
+ if (fc && typeof fc["name"] === "string") {
311
+ const orig = fc["name"];
312
+ const san = nameMap.get(orig);
313
+ if (san !== void 0)
314
+ fc["name"] = san;
315
+ }
316
+ }
317
+ }
318
+ }
124
319
  }
125
320
  }
126
321
  async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent, maxTurns = 10, context) {
127
322
  if (tools === void 0) {
128
- throw new RuntimeError3("RILL-R004", "tools parameter is required");
323
+ throw new RuntimeError4("RILL-R004", "tools parameter is required");
129
324
  }
130
325
  if (!isDict(tools)) {
131
- throw new RuntimeError3("RILL-R004", "tools must be a dict mapping tool names to functions");
326
+ throw new RuntimeError4("RILL-R004", "tool_loop: tools must be a dict of name \u2192 callable");
132
327
  }
133
328
  const toolsDict = tools;
134
329
  const toolDescriptors = Object.entries(toolsDict).map(([name, fn]) => {
135
330
  const fnValue = fn;
331
+ if (isRuntimeCallable(fnValue)) {
332
+ throw new RuntimeError4("RILL-R004", `tool_loop: builtin "${name}" cannot be used as a tool \u2014 wrap in a closure`);
333
+ }
136
334
  if (!isCallable(fnValue)) {
137
- throw new RuntimeError3("RILL-R004", `tool '${name}' must be callable function`);
335
+ throw new RuntimeError4("RILL-R004", `tool_loop: tool "${name}" is not a callable`);
138
336
  }
139
337
  const callable = fnValue;
140
- const description = callable.kind === "application" && callable.description ? callable.description : "";
141
- const properties = {};
142
- const required = [];
143
- if (callable.kind === "application" && callable.params) {
144
- for (const param of callable.params) {
145
- let jsonSchemaType;
146
- switch (param.typeName) {
147
- case "string":
148
- jsonSchemaType = "string";
149
- break;
150
- case "number":
151
- jsonSchemaType = "number";
152
- break;
153
- case "bool":
154
- jsonSchemaType = "boolean";
155
- break;
156
- case "list":
157
- jsonSchemaType = "array";
158
- break;
159
- case "dict":
160
- case "vector":
161
- jsonSchemaType = "object";
162
- break;
163
- case null:
164
- jsonSchemaType = "string";
165
- break;
166
- default:
167
- jsonSchemaType = "string";
168
- break;
169
- }
170
- const property = {
171
- type: jsonSchemaType
172
- };
173
- if (param.description) {
174
- property["description"] = param.description;
175
- }
176
- properties[param.name] = property;
177
- if (param.defaultValue === null) {
178
- required.push(param.name);
179
- }
180
- }
338
+ let description;
339
+ if (callable.kind === "script") {
340
+ description = callable.annotations["description"] ?? "";
341
+ } else {
342
+ description = callable.description ?? "";
343
+ }
344
+ let inputSchema;
345
+ const params = callable.kind === "application" ? callable.params ?? [] : callable.kind === "script" ? callable.params : [];
346
+ if (params.length > 0) {
347
+ const closureType = {
348
+ type: "closure",
349
+ params: params.map((p2) => [p2.name, p2.type ?? { type: "any" }])
350
+ };
351
+ const builtSchema = buildJsonSchemaFromStructuralType(closureType, [...params]);
352
+ inputSchema = {
353
+ type: "object",
354
+ properties: builtSchema.properties,
355
+ required: builtSchema.required
356
+ };
357
+ } else {
358
+ inputSchema = { type: "object", properties: {}, required: [] };
181
359
  }
182
360
  return {
183
361
  name,
184
362
  description,
185
- input_schema: {
186
- type: "object",
187
- properties,
188
- required
189
- }
363
+ input_schema: inputSchema
190
364
  };
191
365
  });
192
366
  const providerTools = callbacks.buildTools(toolDescriptors);
@@ -203,7 +377,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
203
377
  response = await callbacks.callAPI(currentMessages, providerTools);
204
378
  } catch (error) {
205
379
  const message = error instanceof Error ? error.message : "Unknown error";
206
- throw new RuntimeError3("RILL-R004", `Provider API error: ${message}`, void 0, { cause: error });
380
+ throw new RuntimeError4("RILL-R004", `Provider API error: ${message}`, void 0, { cause: error });
207
381
  }
208
382
  if (typeof response === "object" && response !== null && "usage" in response) {
209
383
  const usage = response["usage"];
@@ -215,7 +389,17 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
215
389
  totalOutputTokens += outputTokens;
216
390
  }
217
391
  }
218
- const toolCalls = callbacks.extractToolCalls(response);
392
+ const rawToolCalls = callbacks.extractToolCalls(response);
393
+ const nameMap = /* @__PURE__ */ new Map();
394
+ const toolCalls = rawToolCalls?.map((tc) => {
395
+ const sanitized = sanitizeToolName(tc.name);
396
+ if (sanitized !== tc.name)
397
+ nameMap.set(tc.name, sanitized);
398
+ return sanitized !== tc.name ? { ...tc, name: sanitized } : tc;
399
+ }) ?? null;
400
+ if (nameMap.size > 0) {
401
+ patchResponseToolCallNames(response, nameMap);
402
+ }
219
403
  if (toolCalls === null || toolCalls.length === 0) {
220
404
  return {
221
405
  response,
@@ -240,7 +424,7 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
240
424
  const duration = Date.now() - toolStartTime;
241
425
  consecutiveErrors++;
242
426
  let originalError;
243
- if (error instanceof RuntimeError3) {
427
+ if (error instanceof RuntimeError4) {
244
428
  const prefix = `Invalid tool input for ${name}: `;
245
429
  if (error.message.startsWith(prefix)) {
246
430
  originalError = error.message.slice(prefix.length);
@@ -265,12 +449,20 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
265
449
  duration
266
450
  });
267
451
  if (consecutiveErrors >= maxErrors) {
268
- throw new RuntimeError3("RILL-R004", `Tool execution failed: ${maxErrors} consecutive errors`);
452
+ throw new RuntimeError4("RILL-R004", `Tool execution failed: ${maxErrors} consecutive errors (last: ${name}: ${originalError})`);
269
453
  }
270
454
  }
271
455
  }
456
+ const assistantMessage = callbacks.formatAssistantMessage(response);
457
+ if (assistantMessage != null) {
458
+ currentMessages.push(assistantMessage);
459
+ }
272
460
  const toolResultMessage = callbacks.formatToolResult(toolResults);
273
- currentMessages.push(toolResultMessage);
461
+ if (Array.isArray(toolResultMessage)) {
462
+ currentMessages.push(...toolResultMessage);
463
+ } else {
464
+ currentMessages.push(toolResultMessage);
465
+ }
274
466
  }
275
467
  return {
276
468
  response: null,
@@ -280,8 +472,128 @@ async function executeToolLoop(messages, tools, maxErrors, callbacks, emitEvent,
280
472
  };
281
473
  }
282
474
 
475
+ // ../../shared/ext-param/dist/param.js
476
+ import { RuntimeError as RuntimeError5 } from "@rcrsr/rill";
477
+ function validateParamName(name) {
478
+ if (name === "") {
479
+ throw new RuntimeError5("RILL-R001", "param name must not be empty");
480
+ }
481
+ if (/\s/.test(name)) {
482
+ throw new RuntimeError5("RILL-R001", "param name must be a valid identifier");
483
+ }
484
+ }
485
+ function buildAnnotations(desc) {
486
+ if (desc !== void 0) {
487
+ return { description: desc };
488
+ }
489
+ return {};
490
+ }
491
+ var p = {
492
+ /**
493
+ * IR-1: Creates a string parameter descriptor.
494
+ *
495
+ * @param name - Parameter name (must be a valid identifier)
496
+ * @param desc - Optional description
497
+ * @returns RillParam with type 'string'
498
+ */
499
+ str(name, desc) {
500
+ validateParamName(name);
501
+ return {
502
+ name,
503
+ type: { type: "string" },
504
+ defaultValue: void 0,
505
+ annotations: buildAnnotations(desc)
506
+ };
507
+ },
508
+ /**
509
+ * IR-2: Creates a number parameter descriptor.
510
+ *
511
+ * @param name - Parameter name (must be a valid identifier)
512
+ * @param desc - Optional description
513
+ * @param def - Optional default value
514
+ * @returns RillParam with type 'number'
515
+ */
516
+ num(name, desc, def) {
517
+ validateParamName(name);
518
+ return {
519
+ name,
520
+ type: { type: "number" },
521
+ defaultValue: def,
522
+ annotations: buildAnnotations(desc)
523
+ };
524
+ },
525
+ /**
526
+ * IR-3: Creates a boolean parameter descriptor.
527
+ *
528
+ * @param name - Parameter name (must be a valid identifier)
529
+ * @param desc - Optional description
530
+ * @param def - Optional default value
531
+ * @returns RillParam with type 'bool'
532
+ */
533
+ bool(name, desc, def) {
534
+ validateParamName(name);
535
+ return {
536
+ name,
537
+ type: { type: "bool" },
538
+ defaultValue: def,
539
+ annotations: buildAnnotations(desc)
540
+ };
541
+ },
542
+ /**
543
+ * IR-4: Creates a dict parameter descriptor.
544
+ *
545
+ * @param name - Parameter name (must be a valid identifier)
546
+ * @param desc - Optional description
547
+ * @param def - Optional default value
548
+ * @returns RillParam with type 'dict'
549
+ */
550
+ dict(name, desc, def) {
551
+ validateParamName(name);
552
+ return {
553
+ name,
554
+ type: { type: "dict" },
555
+ defaultValue: def,
556
+ annotations: buildAnnotations(desc)
557
+ };
558
+ },
559
+ /**
560
+ * IR-5: Creates a list parameter descriptor.
561
+ *
562
+ * @param name - Parameter name (must be a valid identifier)
563
+ * @param itemType - Optional element type; omitted when not provided
564
+ * @param desc - Optional description
565
+ * @returns RillParam with type 'list' (with element if itemType provided)
566
+ */
567
+ list(name, itemType, desc) {
568
+ validateParamName(name);
569
+ const type = itemType !== void 0 ? { type: "list", element: itemType } : { type: "list" };
570
+ return {
571
+ name,
572
+ type,
573
+ defaultValue: void 0,
574
+ annotations: buildAnnotations(desc)
575
+ };
576
+ },
577
+ /**
578
+ * IR-6: Creates a callable parameter descriptor.
579
+ *
580
+ * @param name - Parameter name (must be a valid identifier)
581
+ * @param desc - Optional description
582
+ * @returns RillParam with type 'closure'
583
+ */
584
+ callable(name, desc) {
585
+ validateParamName(name);
586
+ return {
587
+ name,
588
+ type: { type: "closure" },
589
+ defaultValue: void 0,
590
+ annotations: buildAnnotations(desc)
591
+ };
592
+ }
593
+ };
594
+
283
595
  // src/factory.ts
284
- var DEFAULT_MAX_TOKENS = 4096;
596
+ var DEFAULT_MAX_COMPLETION_TOKENS = 4096;
285
597
  var detectOpenAIError = (error) => {
286
598
  if (error instanceof OpenAI.APIError) {
287
599
  return {
@@ -303,7 +615,7 @@ function createOpenAIExtension(config) {
303
615
  });
304
616
  const factoryModel = config.model;
305
617
  const factoryTemperature = config.temperature;
306
- const factoryMaxTokens = config.max_tokens ?? DEFAULT_MAX_TOKENS;
618
+ const factoryMaxTokens = config.max_tokens ?? DEFAULT_MAX_COMPLETION_TOKENS;
307
619
  const factorySystem = config.system;
308
620
  const factoryEmbedModel = config.embed_model;
309
621
  void factoryEmbedModel;
@@ -328,8 +640,8 @@ function createOpenAIExtension(config) {
328
640
  // IR-4: openai::message
329
641
  message: {
330
642
  params: [
331
- { name: "text", type: "string" },
332
- { name: "options", type: "dict", defaultValue: {} }
643
+ p.str("text"),
644
+ p.dict("options", void 0, {})
333
645
  ],
334
646
  fn: async (args, ctx) => {
335
647
  const startTime = Date.now();
@@ -337,7 +649,7 @@ function createOpenAIExtension(config) {
337
649
  const text = args[0];
338
650
  const options = args[1] ?? {};
339
651
  if (text.trim().length === 0) {
340
- throw new RuntimeError4("RILL-R004", "prompt text cannot be empty");
652
+ throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
341
653
  }
342
654
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
343
655
  const maxTokens = typeof options["max_tokens"] === "number" ? options["max_tokens"] : factoryMaxTokens;
@@ -354,7 +666,7 @@ function createOpenAIExtension(config) {
354
666
  });
355
667
  const apiParams = {
356
668
  model: factoryModel,
357
- max_tokens: maxTokens,
669
+ max_completion_tokens: maxTokens,
358
670
  messages: apiMessages
359
671
  };
360
672
  if (factoryTemperature !== void 0) {
@@ -383,7 +695,9 @@ function createOpenAIExtension(config) {
383
695
  subsystem: "extension:openai",
384
696
  duration,
385
697
  model: response.model,
386
- usage: result2.usage
698
+ usage: result2.usage,
699
+ request: apiMessages,
700
+ content
387
701
  });
388
702
  return result2;
389
703
  } catch (error) {
@@ -403,13 +717,13 @@ function createOpenAIExtension(config) {
403
717
  }
404
718
  },
405
719
  description: "Send single message to OpenAI API",
406
- returnType: "dict"
720
+ returnType: { type: "dict" }
407
721
  },
408
722
  // IR-5: openai::messages
409
723
  messages: {
410
724
  params: [
411
- { name: "messages", type: "list" },
412
- { name: "options", type: "dict", defaultValue: {} }
725
+ p.list("messages"),
726
+ p.dict("options", void 0, {})
413
727
  ],
414
728
  fn: async (args, ctx) => {
415
729
  const startTime = Date.now();
@@ -417,7 +731,7 @@ function createOpenAIExtension(config) {
417
731
  const messages = args[0];
418
732
  const options = args[1] ?? {};
419
733
  if (messages.length === 0) {
420
- throw new RuntimeError4(
734
+ throw new RuntimeError6(
421
735
  "RILL-R004",
422
736
  "messages list cannot be empty"
423
737
  );
@@ -434,18 +748,18 @@ function createOpenAIExtension(config) {
434
748
  for (let i = 0; i < messages.length; i++) {
435
749
  const msg = messages[i];
436
750
  if (!msg || typeof msg !== "object" || !("role" in msg)) {
437
- throw new RuntimeError4(
751
+ throw new RuntimeError6(
438
752
  "RILL-R004",
439
753
  "message missing required 'role' field"
440
754
  );
441
755
  }
442
756
  const role = msg["role"];
443
757
  if (role !== "user" && role !== "assistant" && role !== "tool") {
444
- throw new RuntimeError4("RILL-R004", `invalid role '${role}'`);
758
+ throw new RuntimeError6("RILL-R004", `invalid role '${role}'`);
445
759
  }
446
760
  if (role === "user" || role === "tool") {
447
761
  if (!("content" in msg) || typeof msg["content"] !== "string") {
448
- throw new RuntimeError4(
762
+ throw new RuntimeError6(
449
763
  "RILL-R004",
450
764
  `${role} message requires 'content'`
451
765
  );
@@ -458,7 +772,7 @@ function createOpenAIExtension(config) {
458
772
  const hasContent = "content" in msg && msg["content"];
459
773
  const hasToolCalls = "tool_calls" in msg && msg["tool_calls"];
460
774
  if (!hasContent && !hasToolCalls) {
461
- throw new RuntimeError4(
775
+ throw new RuntimeError6(
462
776
  "RILL-R004",
463
777
  "assistant message requires 'content' or 'tool_calls'"
464
778
  );
@@ -473,7 +787,7 @@ function createOpenAIExtension(config) {
473
787
  }
474
788
  const apiParams = {
475
789
  model: factoryModel,
476
- max_tokens: maxTokens,
790
+ max_completion_tokens: maxTokens,
477
791
  messages: apiMessages
478
792
  };
479
793
  if (factoryTemperature !== void 0) {
@@ -507,7 +821,9 @@ function createOpenAIExtension(config) {
507
821
  subsystem: "extension:openai",
508
822
  duration,
509
823
  model: response.model,
510
- usage: result2.usage
824
+ usage: result2.usage,
825
+ request: apiMessages,
826
+ content
511
827
  });
512
828
  return result2;
513
829
  } catch (error) {
@@ -527,11 +843,11 @@ function createOpenAIExtension(config) {
527
843
  }
528
844
  },
529
845
  description: "Send multi-turn conversation to OpenAI API",
530
- returnType: "dict"
846
+ returnType: { type: "dict" }
531
847
  },
532
848
  // IR-6: openai::embed
533
849
  embed: {
534
- params: [{ name: "text", type: "string" }],
850
+ params: [p.str("text")],
535
851
  fn: async (args, ctx) => {
536
852
  const startTime = Date.now();
537
853
  try {
@@ -545,7 +861,7 @@ function createOpenAIExtension(config) {
545
861
  });
546
862
  const embeddingData = response.data[0]?.embedding;
547
863
  if (!embeddingData || embeddingData.length === 0) {
548
- throw new RuntimeError4(
864
+ throw new RuntimeError6(
549
865
  "RILL-R004",
550
866
  "OpenAI: empty embedding returned"
551
867
  );
@@ -578,11 +894,11 @@ function createOpenAIExtension(config) {
578
894
  }
579
895
  },
580
896
  description: "Generate embedding vector for text",
581
- returnType: "vector"
897
+ returnType: { type: "vector" }
582
898
  },
583
899
  // IR-7: openai::embed_batch
584
900
  embed_batch: {
585
- params: [{ name: "texts", type: "list" }],
901
+ params: [p.list("texts")],
586
902
  fn: async (args, ctx) => {
587
903
  const startTime = Date.now();
588
904
  try {
@@ -601,7 +917,7 @@ function createOpenAIExtension(config) {
601
917
  for (const embeddingItem of response.data) {
602
918
  const embeddingData = embeddingItem.embedding;
603
919
  if (!embeddingData || embeddingData.length === 0) {
604
- throw new RuntimeError4(
920
+ throw new RuntimeError6(
605
921
  "RILL-R004",
606
922
  "OpenAI: empty embedding returned"
607
923
  );
@@ -639,13 +955,13 @@ function createOpenAIExtension(config) {
639
955
  }
640
956
  },
641
957
  description: "Generate embedding vectors for multiple texts",
642
- returnType: "list"
958
+ returnType: { type: "list" }
643
959
  },
644
960
  // IR-8: openai::tool_loop
645
961
  tool_loop: {
646
962
  params: [
647
- { name: "prompt", type: "string" },
648
- { name: "options", type: "dict", defaultValue: {} }
963
+ p.str("prompt"),
964
+ p.dict("options", void 0, {})
649
965
  ],
650
966
  fn: async (args, ctx) => {
651
967
  const startTime = Date.now();
@@ -653,79 +969,14 @@ function createOpenAIExtension(config) {
653
969
  const prompt = args[0];
654
970
  const options = args[1] ?? {};
655
971
  if (prompt.trim().length === 0) {
656
- throw new RuntimeError4("RILL-R004", "prompt text cannot be empty");
972
+ throw new RuntimeError6("RILL-R004", "prompt text cannot be empty");
657
973
  }
658
- if (!("tools" in options) || !Array.isArray(options["tools"])) {
659
- throw new RuntimeError4(
974
+ if (!("tools" in options) || !isDict2(options["tools"])) {
975
+ throw new RuntimeError6(
660
976
  "RILL-R004",
661
977
  "tool_loop requires 'tools' option"
662
978
  );
663
979
  }
664
- const toolDescriptors = options["tools"];
665
- const toolsDict = {};
666
- for (const descriptor of toolDescriptors) {
667
- const name = typeof descriptor["name"] === "string" ? descriptor["name"] : null;
668
- if (!name) {
669
- throw new RuntimeError4(
670
- "RILL-R004",
671
- "tool descriptor missing name"
672
- );
673
- }
674
- const toolFnValue = descriptor["fn"];
675
- if (!toolFnValue) {
676
- throw new RuntimeError4(
677
- "RILL-R004",
678
- `tool '${name}' missing fn property`
679
- );
680
- }
681
- if (!isCallable2(toolFnValue)) {
682
- throw new RuntimeError4(
683
- "RILL-R004",
684
- `tool '${name}' fn must be callable`
685
- );
686
- }
687
- const paramsObj = descriptor["params"];
688
- const description = typeof descriptor["description"] === "string" ? descriptor["description"] : "";
689
- let enhancedCallable = toolFnValue;
690
- if (paramsObj && typeof paramsObj === "object" && !Array.isArray(paramsObj)) {
691
- const params = Object.entries(
692
- paramsObj
693
- ).map(([paramName, paramMeta]) => {
694
- const meta = paramMeta;
695
- const typeStr = typeof meta["type"] === "string" ? meta["type"] : null;
696
- let typeName = null;
697
- if (typeStr === "string") typeName = "string";
698
- else if (typeStr === "number") typeName = "number";
699
- else if (typeStr === "bool" || typeStr === "boolean")
700
- typeName = "bool";
701
- else if (typeStr === "list" || typeStr === "array")
702
- typeName = "list";
703
- else if (typeStr === "dict" || typeStr === "object")
704
- typeName = "dict";
705
- else if (typeStr === "vector") typeName = "vector";
706
- const param = {
707
- name: paramName,
708
- typeName,
709
- defaultValue: null,
710
- annotations: {}
711
- };
712
- if (typeof meta["description"] === "string") {
713
- param.description = meta["description"];
714
- }
715
- return param;
716
- });
717
- const baseCallable = toolFnValue;
718
- enhancedCallable = {
719
- __type: "callable",
720
- kind: "application",
721
- params,
722
- fn: baseCallable.fn,
723
- description,
724
- isProperty: baseCallable.isProperty ?? false
725
- };
726
- }
727
- toolsDict[name] = enhancedCallable;
728
- }
729
980
  const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
730
981
  const maxTokens = typeof options["max_tokens"] === "number" ? options["max_tokens"] : factoryMaxTokens;
731
982
  const maxErrors = typeof options["max_errors"] === "number" ? options["max_errors"] : 3;
@@ -741,17 +992,17 @@ function createOpenAIExtension(config) {
741
992
  const prependedMessages = options["messages"];
742
993
  for (const msg of prependedMessages) {
743
994
  if (!msg || typeof msg !== "object" || !("role" in msg)) {
744
- throw new RuntimeError4(
995
+ throw new RuntimeError6(
745
996
  "RILL-R004",
746
997
  "message missing required 'role' field"
747
998
  );
748
999
  }
749
1000
  const role = msg["role"];
750
1001
  if (role !== "user" && role !== "assistant") {
751
- throw new RuntimeError4("RILL-R004", `invalid role '${role}'`);
1002
+ throw new RuntimeError6("RILL-R004", `invalid role '${role}'`);
752
1003
  }
753
1004
  if (!("content" in msg) || typeof msg["content"] !== "string") {
754
- throw new RuntimeError4(
1005
+ throw new RuntimeError6(
755
1006
  "RILL-R004",
756
1007
  `${role} message requires 'content'`
757
1008
  );
@@ -782,7 +1033,7 @@ function createOpenAIExtension(config) {
782
1033
  callAPI: async (msgs, tools) => {
783
1034
  const apiParams = {
784
1035
  model: factoryModel,
785
- max_tokens: maxTokens,
1036
+ max_completion_tokens: maxTokens,
786
1037
  messages: msgs,
787
1038
  tools,
788
1039
  tool_choice: "auto"
@@ -839,6 +1090,21 @@ function createOpenAIExtension(config) {
839
1090
  };
840
1091
  });
841
1092
  },
1093
+ // Extract assistant message (with tool_calls) from OpenAI response
1094
+ formatAssistantMessage: (response2) => {
1095
+ if (!response2 || typeof response2 !== "object" || !("choices" in response2)) {
1096
+ return null;
1097
+ }
1098
+ const choices = response2.choices;
1099
+ if (!Array.isArray(choices) || choices.length === 0) {
1100
+ return null;
1101
+ }
1102
+ const choice = choices[0];
1103
+ if (!choice || typeof choice !== "object" || !("message" in choice)) {
1104
+ return null;
1105
+ }
1106
+ return choice.message;
1107
+ },
842
1108
  // Format tool results into OpenAI message format
843
1109
  formatToolResult: (toolResults) => {
844
1110
  return toolResults.map((tr) => ({
@@ -850,7 +1116,7 @@ function createOpenAIExtension(config) {
850
1116
  };
851
1117
  const loopResult = await executeToolLoop(
852
1118
  messages,
853
- toolsDict,
1119
+ options["tools"],
854
1120
  maxErrors,
855
1121
  callbacks,
856
1122
  (event, data) => {
@@ -908,7 +1174,9 @@ function createOpenAIExtension(config) {
908
1174
  subsystem: "extension:openai",
909
1175
  turns: loopResult.turns,
910
1176
  total_duration: duration,
911
- usage: result2.usage
1177
+ usage: result2.usage,
1178
+ request: messages,
1179
+ content
912
1180
  });
913
1181
  return result2;
914
1182
  } catch (error) {
@@ -928,7 +1196,126 @@ function createOpenAIExtension(config) {
928
1196
  }
929
1197
  },
930
1198
  description: "Execute tool-use loop with OpenAI API",
931
- returnType: "dict"
1199
+ returnType: { type: "dict" }
1200
+ },
1201
+ // IR-3: openai::generate
1202
+ generate: {
1203
+ params: [
1204
+ p.str("prompt"),
1205
+ p.dict("options")
1206
+ ],
1207
+ fn: async (args, ctx) => {
1208
+ const startTime = Date.now();
1209
+ try {
1210
+ const prompt = args[0];
1211
+ const options = args[1] ?? {};
1212
+ if (!("schema" in options) || options["schema"] === null || options["schema"] === void 0) {
1213
+ throw new RuntimeError6(
1214
+ "RILL-R004",
1215
+ "generate requires 'schema' option"
1216
+ );
1217
+ }
1218
+ const rillSchema = options["schema"];
1219
+ const jsonSchema = buildJsonSchema(rillSchema);
1220
+ const system = typeof options["system"] === "string" ? options["system"] : factorySystem;
1221
+ const maxTokens = typeof options["max_tokens"] === "number" ? options["max_tokens"] : factoryMaxTokens;
1222
+ const apiMessages = [];
1223
+ if (system !== void 0) {
1224
+ apiMessages.push({
1225
+ role: "system",
1226
+ content: system
1227
+ });
1228
+ }
1229
+ if ("messages" in options && Array.isArray(options["messages"])) {
1230
+ const prependedMessages = options["messages"];
1231
+ for (const msg of prependedMessages) {
1232
+ if (!msg || typeof msg !== "object" || !("role" in msg)) {
1233
+ throw new RuntimeError6(
1234
+ "RILL-R004",
1235
+ "message missing required 'role' field"
1236
+ );
1237
+ }
1238
+ const role = msg["role"];
1239
+ if (role !== "user" && role !== "assistant") {
1240
+ throw new RuntimeError6("RILL-R004", `invalid role '${role}'`);
1241
+ }
1242
+ if (!("content" in msg) || typeof msg["content"] !== "string") {
1243
+ throw new RuntimeError6(
1244
+ "RILL-R004",
1245
+ `${role} message requires 'content'`
1246
+ );
1247
+ }
1248
+ apiMessages.push({
1249
+ role,
1250
+ content: msg["content"]
1251
+ });
1252
+ }
1253
+ }
1254
+ apiMessages.push({ role: "user", content: prompt });
1255
+ const apiParams = {
1256
+ model: factoryModel,
1257
+ max_completion_tokens: maxTokens,
1258
+ messages: apiMessages,
1259
+ response_format: {
1260
+ type: "json_schema",
1261
+ json_schema: {
1262
+ name: "output",
1263
+ schema: jsonSchema,
1264
+ strict: true
1265
+ }
1266
+ }
1267
+ };
1268
+ if (factoryTemperature !== void 0) {
1269
+ apiParams.temperature = factoryTemperature;
1270
+ }
1271
+ const response = await client.chat.completions.create(apiParams);
1272
+ const raw = response.choices[0]?.message?.content ?? "";
1273
+ let data;
1274
+ try {
1275
+ data = JSON.parse(raw);
1276
+ } catch (parseError) {
1277
+ const detail = parseError instanceof Error ? parseError.message : String(parseError);
1278
+ throw new RuntimeError6(
1279
+ "RILL-R004",
1280
+ `generate: failed to parse response JSON: ${detail}`
1281
+ );
1282
+ }
1283
+ const result2 = {
1284
+ data,
1285
+ raw,
1286
+ model: response.model,
1287
+ usage: {
1288
+ input: response.usage?.prompt_tokens ?? 0,
1289
+ output: response.usage?.completion_tokens ?? 0
1290
+ },
1291
+ stop_reason: response.choices[0]?.finish_reason ?? "unknown",
1292
+ id: response.id
1293
+ };
1294
+ const duration = Date.now() - startTime;
1295
+ emitExtensionEvent(ctx, {
1296
+ event: "openai:generate",
1297
+ subsystem: "extension:openai",
1298
+ duration,
1299
+ model: response.model,
1300
+ usage: result2.usage,
1301
+ request: apiMessages,
1302
+ content: raw
1303
+ });
1304
+ return result2;
1305
+ } catch (error) {
1306
+ const duration = Date.now() - startTime;
1307
+ const rillError = error instanceof RuntimeError6 ? error : mapProviderError("OpenAI", error, detectOpenAIError);
1308
+ emitExtensionEvent(ctx, {
1309
+ event: "openai:error",
1310
+ subsystem: "extension:openai",
1311
+ error: rillError.message,
1312
+ duration
1313
+ });
1314
+ throw rillError;
1315
+ }
1316
+ },
1317
+ description: "Generate structured output from OpenAI API",
1318
+ returnType: { type: "dict" }
932
1319
  }
933
1320
  };
934
1321
  result.dispose = dispose;
@@ -937,7 +1324,19 @@ function createOpenAIExtension(config) {
937
1324
 
938
1325
  // src/index.ts
939
1326
  var VERSION = "0.0.1";
1327
+ var configSchema = {
1328
+ api_key: { type: "string", required: true, secret: true },
1329
+ model: { type: "string", required: true },
1330
+ base_url: { type: "string" },
1331
+ temperature: { type: "number" },
1332
+ max_tokens: { type: "number" },
1333
+ timeout: { type: "number" },
1334
+ max_retries: { type: "number" },
1335
+ system: { type: "string" },
1336
+ embed_model: { type: "string" }
1337
+ };
940
1338
  export {
941
1339
  VERSION,
1340
+ configSchema,
942
1341
  createOpenAIExtension
943
1342
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rcrsr/rill-ext-openai",
3
- "version": "0.8.6",
3
+ "version": "0.11.0",
4
4
  "description": "rill extension for OpenAI API integration",
5
5
  "license": "MIT",
6
6
  "author": "Andre Bremer",
@@ -17,33 +17,34 @@
17
17
  "scripting"
18
18
  ],
19
19
  "peerDependencies": {
20
- "@rcrsr/rill": "^0.8.6"
20
+ "@rcrsr/rill": "^0.11.0"
21
21
  },
22
22
  "devDependencies": {
23
- "@types/node": "^25.2.3",
23
+ "@rcrsr/rill": "^0.11.0",
24
+ "@types/node": "^25.3.0",
24
25
  "dts-bundle-generator": "^9.5.1",
25
- "tsup": "^8.5.0",
26
- "undici-types": "^7.21.0",
27
- "@rcrsr/rill-ext-llm-shared": "^0.0.1",
28
- "@rcrsr/rill": "^0.8.6"
26
+ "tsup": "^8.5.1",
27
+ "undici-types": "^7.22.0",
28
+ "@rcrsr/rill-ext-llm-shared": "^0.0.1"
29
29
  },
30
30
  "files": [
31
31
  "dist"
32
32
  ],
33
33
  "repository": {
34
34
  "type": "git",
35
- "url": "git+https://github.com/rcrsr/rill.git",
35
+ "url": "git+https://github.com/rcrsr/rill-ext.git",
36
36
  "directory": "packages/ext/llm-openai"
37
37
  },
38
- "homepage": "https://rill.run/docs/extensions/openai/",
38
+ "homepage": "https://github.com/rcrsr/rill-ext/tree/main/packages/ext/llm-openai#readme",
39
39
  "bugs": {
40
- "url": "https://github.com/rcrsr/rill/issues"
40
+ "url": "https://github.com/rcrsr/rill-ext/issues"
41
41
  },
42
42
  "publishConfig": {
43
43
  "access": "public"
44
44
  },
45
45
  "dependencies": {
46
- "openai": "^6.18.0"
46
+ "openai": "^6.25.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",