@rcrsr/rill-ext-openai 0.0.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.
- package/LICENSE +21 -0
- package/README.md +170 -0
- package/dist/factory.d.ts +27 -0
- package/dist/factory.d.ts.map +1 -0
- package/dist/factory.js +844 -0
- package/dist/factory.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +35 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +6 -0
- package/dist/types.js.map +1 -0
- package/package.json +50 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andre Bremer
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# @rcrsr/rill-ext-openai
|
|
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).
|
|
4
|
+
|
|
5
|
+
> **Experimental.** Breaking changes will occur before stabilization.
|
|
6
|
+
|
|
7
|
+
## Install
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @rcrsr/rill-ext-openai
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
**Peer dependencies:** `@rcrsr/rill`
|
|
14
|
+
|
|
15
|
+
## Quick Start
|
|
16
|
+
|
|
17
|
+
```typescript
|
|
18
|
+
import { parse, execute, createRuntimeContext, prefixFunctions } from '@rcrsr/rill';
|
|
19
|
+
import { createOpenAIExtension } from '@rcrsr/rill-ext-openai';
|
|
20
|
+
|
|
21
|
+
const ext = createOpenAIExtension({
|
|
22
|
+
api_key: process.env.OPENAI_API_KEY!,
|
|
23
|
+
model: 'gpt-4-turbo',
|
|
24
|
+
});
|
|
25
|
+
const prefixed = prefixFunctions('openai', ext);
|
|
26
|
+
const { dispose, ...functions } = prefixed;
|
|
27
|
+
|
|
28
|
+
const ctx = createRuntimeContext({
|
|
29
|
+
functions,
|
|
30
|
+
callbacks: { onLog: (v) => console.log(v) },
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
const script = `openai::message("Explain TCP handshakes")`;
|
|
34
|
+
const result = await execute(parse(script), ctx);
|
|
35
|
+
|
|
36
|
+
dispose?.();
|
|
37
|
+
```
|
|
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
|
+
```
|
|
158
|
+
|
|
159
|
+
Requires `OPENAI_API_KEY` environment variable (or `--base-url` for local servers).
|
|
160
|
+
|
|
161
|
+
## Documentation
|
|
162
|
+
|
|
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 |
|
|
167
|
+
|
|
168
|
+
## License
|
|
169
|
+
|
|
170
|
+
MIT
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension factory for OpenAI API integration.
|
|
3
|
+
* Creates extension instance with config validation and SDK lifecycle management.
|
|
4
|
+
*/
|
|
5
|
+
import { type ExtensionResult } from '@rcrsr/rill';
|
|
6
|
+
import type { OpenAIExtensionConfig } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Create OpenAI extension instance.
|
|
9
|
+
* Validates configuration and returns host functions with cleanup.
|
|
10
|
+
*
|
|
11
|
+
* @param config - Extension configuration
|
|
12
|
+
* @returns ExtensionResult with message, messages, embed, embed_batch, tool_loop and dispose
|
|
13
|
+
* @throws Error for invalid configuration (EC-1 through EC-4)
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```typescript
|
|
17
|
+
* const ext = createOpenAIExtension({
|
|
18
|
+
* api_key: process.env.OPENAI_API_KEY,
|
|
19
|
+
* model: 'gpt-4-turbo',
|
|
20
|
+
* temperature: 0.7
|
|
21
|
+
* });
|
|
22
|
+
* // Use with rill runtime...
|
|
23
|
+
* await ext.dispose();
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
export declare function createOpenAIExtension(config: OpenAIExtensionConfig): ExtensionResult;
|
|
27
|
+
//# sourceMappingURL=factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.d.ts","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAML,KAAK,eAAe,EAIrB,MAAM,aAAa,CAAC;AACrB,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAwGxD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,qBAAqB,CACnC,MAAM,EAAE,qBAAqB,GAC5B,eAAe,CA05BjB"}
|
package/dist/factory.js
ADDED
|
@@ -0,0 +1,844 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extension factory for OpenAI API integration.
|
|
3
|
+
* Creates extension instance with config validation and SDK lifecycle management.
|
|
4
|
+
*/
|
|
5
|
+
import OpenAI from 'openai';
|
|
6
|
+
import { RuntimeError, emitExtensionEvent, createVector, isCallable, isVector, } from '@rcrsr/rill';
|
|
7
|
+
// ============================================================
|
|
8
|
+
// CONSTANTS
|
|
9
|
+
// ============================================================
|
|
10
|
+
const MIN_TEMPERATURE = 0.0;
|
|
11
|
+
const MAX_TEMPERATURE = 2.0;
|
|
12
|
+
const DEFAULT_MAX_TOKENS = 4096;
|
|
13
|
+
// ============================================================
|
|
14
|
+
// HELPER FUNCTIONS
|
|
15
|
+
// ============================================================
|
|
16
|
+
/**
|
|
17
|
+
* Map OpenAI API error to RuntimeError with appropriate message.
|
|
18
|
+
*
|
|
19
|
+
* @param error - Error from OpenAI SDK
|
|
20
|
+
* @returns RuntimeError with appropriate message
|
|
21
|
+
*/
|
|
22
|
+
function mapOpenAIError(error) {
|
|
23
|
+
if (error instanceof OpenAI.APIError) {
|
|
24
|
+
const status = error.status;
|
|
25
|
+
const message = error.message;
|
|
26
|
+
if (status === 401) {
|
|
27
|
+
return new RuntimeError('RILL-R004', `OpenAI: authentication failed (401)`);
|
|
28
|
+
}
|
|
29
|
+
if (status === 429) {
|
|
30
|
+
return new RuntimeError('RILL-R004', `OpenAI: rate limit`);
|
|
31
|
+
}
|
|
32
|
+
if (status && status >= 400) {
|
|
33
|
+
return new RuntimeError('RILL-R004', `OpenAI: ${message} (${status})`);
|
|
34
|
+
}
|
|
35
|
+
return new RuntimeError('RILL-R004', `OpenAI: ${message}`);
|
|
36
|
+
}
|
|
37
|
+
if (error instanceof Error) {
|
|
38
|
+
if (error.name === 'AbortError' || error.message.includes('timeout')) {
|
|
39
|
+
return new RuntimeError('RILL-R004', 'OpenAI: request timeout');
|
|
40
|
+
}
|
|
41
|
+
return new RuntimeError('RILL-R004', `OpenAI: ${error.message}`);
|
|
42
|
+
}
|
|
43
|
+
return new RuntimeError('RILL-R004', 'OpenAI: unknown error');
|
|
44
|
+
}
|
|
45
|
+
// ============================================================
|
|
46
|
+
// VALIDATION
|
|
47
|
+
// ============================================================
|
|
48
|
+
/**
|
|
49
|
+
* Validate api_key is present and non-empty.
|
|
50
|
+
*
|
|
51
|
+
* @param api_key - API key to validate
|
|
52
|
+
* @throws Error if api_key missing or empty (EC-1, EC-3)
|
|
53
|
+
*/
|
|
54
|
+
function validateApiKey(api_key) {
|
|
55
|
+
if (api_key === undefined) {
|
|
56
|
+
throw new Error('api_key is required');
|
|
57
|
+
}
|
|
58
|
+
if (api_key === '') {
|
|
59
|
+
throw new Error('api_key cannot be empty');
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Validate model is present and non-empty.
|
|
64
|
+
*
|
|
65
|
+
* @param model - Model identifier to validate
|
|
66
|
+
* @throws Error if model missing or empty (EC-2)
|
|
67
|
+
*/
|
|
68
|
+
function validateModel(model) {
|
|
69
|
+
if (model === undefined || model === '') {
|
|
70
|
+
throw new Error('model is required');
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Validate temperature is within valid range (0.0-2.0).
|
|
75
|
+
*
|
|
76
|
+
* @param temperature - Temperature value to validate
|
|
77
|
+
* @throws Error if temperature out of range (EC-4)
|
|
78
|
+
*/
|
|
79
|
+
function validateTemperature(temperature) {
|
|
80
|
+
if (temperature !== undefined) {
|
|
81
|
+
if (temperature < MIN_TEMPERATURE || temperature > MAX_TEMPERATURE) {
|
|
82
|
+
throw new Error('temperature must be between 0 and 2');
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// ============================================================
|
|
87
|
+
// FACTORY
|
|
88
|
+
// ============================================================
|
|
89
|
+
/**
|
|
90
|
+
* Create OpenAI extension instance.
|
|
91
|
+
* Validates configuration and returns host functions with cleanup.
|
|
92
|
+
*
|
|
93
|
+
* @param config - Extension configuration
|
|
94
|
+
* @returns ExtensionResult with message, messages, embed, embed_batch, tool_loop and dispose
|
|
95
|
+
* @throws Error for invalid configuration (EC-1 through EC-4)
|
|
96
|
+
*
|
|
97
|
+
* @example
|
|
98
|
+
* ```typescript
|
|
99
|
+
* const ext = createOpenAIExtension({
|
|
100
|
+
* api_key: process.env.OPENAI_API_KEY,
|
|
101
|
+
* model: 'gpt-4-turbo',
|
|
102
|
+
* temperature: 0.7
|
|
103
|
+
* });
|
|
104
|
+
* // Use with rill runtime...
|
|
105
|
+
* await ext.dispose();
|
|
106
|
+
* ```
|
|
107
|
+
*/
|
|
108
|
+
export function createOpenAIExtension(config) {
|
|
109
|
+
// Validate required fields (§4.1)
|
|
110
|
+
validateApiKey(config.api_key);
|
|
111
|
+
validateModel(config.model);
|
|
112
|
+
validateTemperature(config.temperature);
|
|
113
|
+
// Instantiate SDK client at factory time (§4.1)
|
|
114
|
+
// Note: will be used in tasks 3.3 and 3.4 for actual function implementations
|
|
115
|
+
const client = new OpenAI({
|
|
116
|
+
apiKey: config.api_key,
|
|
117
|
+
baseURL: config.base_url,
|
|
118
|
+
maxRetries: config.max_retries,
|
|
119
|
+
timeout: config.timeout,
|
|
120
|
+
});
|
|
121
|
+
// Extract config values for use in functions
|
|
122
|
+
const factoryModel = config.model;
|
|
123
|
+
const factoryTemperature = config.temperature;
|
|
124
|
+
const factoryMaxTokens = config.max_tokens ?? DEFAULT_MAX_TOKENS;
|
|
125
|
+
const factorySystem = config.system;
|
|
126
|
+
const factoryEmbedModel = config.embed_model;
|
|
127
|
+
// Suppress unused variable warnings for values used in task 3.4
|
|
128
|
+
void factoryEmbedModel;
|
|
129
|
+
// AbortController for cancelling pending requests (§4.9, IR-11)
|
|
130
|
+
let abortController = new AbortController();
|
|
131
|
+
// Dispose function for cleanup (§4.9)
|
|
132
|
+
const dispose = async () => {
|
|
133
|
+
// AC-28: Idempotent cleanup, try-catch each step
|
|
134
|
+
try {
|
|
135
|
+
// Cancel pending API requests via AbortController (IR-11)
|
|
136
|
+
if (abortController) {
|
|
137
|
+
abortController.abort();
|
|
138
|
+
abortController = undefined;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
143
|
+
console.warn(`Failed to abort OpenAI requests: ${message}`);
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
// Cleanup SDK HTTP connections
|
|
147
|
+
// Note: OpenAI SDK doesn't expose a close() method, but we include
|
|
148
|
+
// this structure for consistency with extension pattern
|
|
149
|
+
}
|
|
150
|
+
catch (error) {
|
|
151
|
+
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
152
|
+
console.warn(`Failed to cleanup OpenAI SDK: ${message}`);
|
|
153
|
+
}
|
|
154
|
+
};
|
|
155
|
+
// Return extension result with implementations
|
|
156
|
+
const result = {
|
|
157
|
+
// IR-4: openai::message
|
|
158
|
+
message: {
|
|
159
|
+
params: [
|
|
160
|
+
{ name: 'text', type: 'string' },
|
|
161
|
+
{ name: 'options', type: 'dict', defaultValue: {} },
|
|
162
|
+
],
|
|
163
|
+
fn: async (args, ctx) => {
|
|
164
|
+
const startTime = Date.now();
|
|
165
|
+
try {
|
|
166
|
+
// Extract arguments
|
|
167
|
+
const text = args[0];
|
|
168
|
+
const options = (args[1] ?? {});
|
|
169
|
+
// EC-5: Validate text is non-empty
|
|
170
|
+
if (text.trim().length === 0) {
|
|
171
|
+
throw new RuntimeError('RILL-R004', 'prompt text cannot be empty');
|
|
172
|
+
}
|
|
173
|
+
// Extract options
|
|
174
|
+
const system = typeof options['system'] === 'string'
|
|
175
|
+
? options['system']
|
|
176
|
+
: factorySystem;
|
|
177
|
+
const maxTokens = typeof options['max_tokens'] === 'number'
|
|
178
|
+
? options['max_tokens']
|
|
179
|
+
: factoryMaxTokens;
|
|
180
|
+
// Build messages array (OpenAI uses system as first message, not separate param)
|
|
181
|
+
const apiMessages = [];
|
|
182
|
+
if (system !== undefined) {
|
|
183
|
+
apiMessages.push({
|
|
184
|
+
role: 'system',
|
|
185
|
+
content: system,
|
|
186
|
+
});
|
|
187
|
+
}
|
|
188
|
+
apiMessages.push({
|
|
189
|
+
role: 'user',
|
|
190
|
+
content: text,
|
|
191
|
+
});
|
|
192
|
+
// Call OpenAI API
|
|
193
|
+
const apiParams = {
|
|
194
|
+
model: factoryModel,
|
|
195
|
+
max_tokens: maxTokens,
|
|
196
|
+
messages: apiMessages,
|
|
197
|
+
};
|
|
198
|
+
// Add optional parameters only if defined
|
|
199
|
+
if (factoryTemperature !== undefined) {
|
|
200
|
+
apiParams.temperature = factoryTemperature;
|
|
201
|
+
}
|
|
202
|
+
const response = await client.chat.completions.create(apiParams);
|
|
203
|
+
// Extract text content from response (§4.2: choices[0].message.content)
|
|
204
|
+
const content = response.choices[0]?.message?.content ?? '';
|
|
205
|
+
// Build normalized response dict (§3.2)
|
|
206
|
+
const result = {
|
|
207
|
+
content,
|
|
208
|
+
model: response.model,
|
|
209
|
+
usage: {
|
|
210
|
+
input: response.usage?.prompt_tokens ?? 0,
|
|
211
|
+
output: response.usage?.completion_tokens ?? 0,
|
|
212
|
+
},
|
|
213
|
+
stop_reason: response.choices[0]?.finish_reason ?? 'unknown',
|
|
214
|
+
id: response.id,
|
|
215
|
+
messages: [
|
|
216
|
+
...(system ? [{ role: 'system', content: system }] : []),
|
|
217
|
+
{ role: 'user', content: text },
|
|
218
|
+
{ role: 'assistant', content },
|
|
219
|
+
],
|
|
220
|
+
};
|
|
221
|
+
// Emit success event (§4.10)
|
|
222
|
+
const duration = Date.now() - startTime;
|
|
223
|
+
emitExtensionEvent(ctx, {
|
|
224
|
+
event: 'openai:message',
|
|
225
|
+
subsystem: 'extension:openai',
|
|
226
|
+
duration,
|
|
227
|
+
model: response.model,
|
|
228
|
+
usage: result.usage,
|
|
229
|
+
});
|
|
230
|
+
return result;
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
// Map error and emit failure event
|
|
234
|
+
const duration = Date.now() - startTime;
|
|
235
|
+
const rillError = mapOpenAIError(error);
|
|
236
|
+
emitExtensionEvent(ctx, {
|
|
237
|
+
event: 'openai:error',
|
|
238
|
+
subsystem: 'extension:openai',
|
|
239
|
+
error: rillError.message,
|
|
240
|
+
duration,
|
|
241
|
+
});
|
|
242
|
+
throw rillError;
|
|
243
|
+
}
|
|
244
|
+
},
|
|
245
|
+
description: 'Send single message to OpenAI API',
|
|
246
|
+
returnType: 'dict',
|
|
247
|
+
},
|
|
248
|
+
// IR-5: openai::messages
|
|
249
|
+
messages: {
|
|
250
|
+
params: [
|
|
251
|
+
{ name: 'messages', type: 'list' },
|
|
252
|
+
{ name: 'options', type: 'dict', defaultValue: {} },
|
|
253
|
+
],
|
|
254
|
+
fn: async (args, ctx) => {
|
|
255
|
+
const startTime = Date.now();
|
|
256
|
+
try {
|
|
257
|
+
// Extract arguments
|
|
258
|
+
const messages = args[0];
|
|
259
|
+
const options = (args[1] ?? {});
|
|
260
|
+
// AC-23: Empty messages list raises error
|
|
261
|
+
if (messages.length === 0) {
|
|
262
|
+
throw new RuntimeError('RILL-R004', 'messages list cannot be empty');
|
|
263
|
+
}
|
|
264
|
+
// Extract options
|
|
265
|
+
const system = typeof options['system'] === 'string'
|
|
266
|
+
? options['system']
|
|
267
|
+
: factorySystem;
|
|
268
|
+
const maxTokens = typeof options['max_tokens'] === 'number'
|
|
269
|
+
? options['max_tokens']
|
|
270
|
+
: factoryMaxTokens;
|
|
271
|
+
// Build messages array (OpenAI uses system as first message)
|
|
272
|
+
const apiMessages = [];
|
|
273
|
+
if (system !== undefined) {
|
|
274
|
+
apiMessages.push({
|
|
275
|
+
role: 'system',
|
|
276
|
+
content: system,
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
// Validate and transform messages
|
|
280
|
+
for (let i = 0; i < messages.length; i++) {
|
|
281
|
+
const msg = messages[i];
|
|
282
|
+
// EC-10: Missing role raises error
|
|
283
|
+
if (!msg || typeof msg !== 'object' || !('role' in msg)) {
|
|
284
|
+
throw new RuntimeError('RILL-R004', "message missing required 'role' field");
|
|
285
|
+
}
|
|
286
|
+
const role = msg['role'];
|
|
287
|
+
// EC-11: Unknown role value raises error
|
|
288
|
+
if (role !== 'user' && role !== 'assistant' && role !== 'tool') {
|
|
289
|
+
throw new RuntimeError('RILL-R004', `invalid role '${role}'`);
|
|
290
|
+
}
|
|
291
|
+
// EC-12: User message missing content
|
|
292
|
+
if (role === 'user' || role === 'tool') {
|
|
293
|
+
if (!('content' in msg) || typeof msg['content'] !== 'string') {
|
|
294
|
+
throw new RuntimeError('RILL-R004', `${role} message requires 'content'`);
|
|
295
|
+
}
|
|
296
|
+
apiMessages.push({
|
|
297
|
+
role: role,
|
|
298
|
+
content: msg['content'],
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
// EC-13: Assistant missing both content and tool_calls
|
|
302
|
+
else if (role === 'assistant') {
|
|
303
|
+
const hasContent = 'content' in msg && msg['content'];
|
|
304
|
+
const hasToolCalls = 'tool_calls' in msg && msg['tool_calls'];
|
|
305
|
+
if (!hasContent && !hasToolCalls) {
|
|
306
|
+
throw new RuntimeError('RILL-R004', "assistant message requires 'content' or 'tool_calls'");
|
|
307
|
+
}
|
|
308
|
+
// For now, we only support content
|
|
309
|
+
if (hasContent) {
|
|
310
|
+
apiMessages.push({
|
|
311
|
+
role: 'assistant',
|
|
312
|
+
content: msg['content'],
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
// Call OpenAI API
|
|
318
|
+
const apiParams = {
|
|
319
|
+
model: factoryModel,
|
|
320
|
+
max_tokens: maxTokens,
|
|
321
|
+
messages: apiMessages,
|
|
322
|
+
};
|
|
323
|
+
// Add optional parameters only if defined
|
|
324
|
+
if (factoryTemperature !== undefined) {
|
|
325
|
+
apiParams.temperature = factoryTemperature;
|
|
326
|
+
}
|
|
327
|
+
const response = await client.chat.completions.create(apiParams);
|
|
328
|
+
// Extract text content from response
|
|
329
|
+
const content = response.choices[0]?.message?.content ?? '';
|
|
330
|
+
// Build full conversation history (§3.2)
|
|
331
|
+
const fullMessages = [
|
|
332
|
+
...messages.map((m) => {
|
|
333
|
+
const normalized = { role: m['role'] };
|
|
334
|
+
if ('content' in m)
|
|
335
|
+
normalized['content'] = m['content'];
|
|
336
|
+
if ('tool_calls' in m)
|
|
337
|
+
normalized['tool_calls'] = m['tool_calls'];
|
|
338
|
+
return normalized;
|
|
339
|
+
}),
|
|
340
|
+
{ role: 'assistant', content },
|
|
341
|
+
];
|
|
342
|
+
// Build normalized response dict (§3.2)
|
|
343
|
+
const result = {
|
|
344
|
+
content,
|
|
345
|
+
model: response.model,
|
|
346
|
+
usage: {
|
|
347
|
+
input: response.usage?.prompt_tokens ?? 0,
|
|
348
|
+
output: response.usage?.completion_tokens ?? 0,
|
|
349
|
+
},
|
|
350
|
+
stop_reason: response.choices[0]?.finish_reason ?? 'unknown',
|
|
351
|
+
id: response.id,
|
|
352
|
+
messages: fullMessages,
|
|
353
|
+
};
|
|
354
|
+
// Emit success event (§4.10)
|
|
355
|
+
const duration = Date.now() - startTime;
|
|
356
|
+
emitExtensionEvent(ctx, {
|
|
357
|
+
event: 'openai:messages',
|
|
358
|
+
subsystem: 'extension:openai',
|
|
359
|
+
duration,
|
|
360
|
+
model: response.model,
|
|
361
|
+
usage: result.usage,
|
|
362
|
+
});
|
|
363
|
+
return result;
|
|
364
|
+
}
|
|
365
|
+
catch (error) {
|
|
366
|
+
// Map error and emit failure event
|
|
367
|
+
const duration = Date.now() - startTime;
|
|
368
|
+
const rillError = mapOpenAIError(error);
|
|
369
|
+
emitExtensionEvent(ctx, {
|
|
370
|
+
event: 'openai:error',
|
|
371
|
+
subsystem: 'extension:openai',
|
|
372
|
+
error: rillError.message,
|
|
373
|
+
duration,
|
|
374
|
+
});
|
|
375
|
+
throw rillError;
|
|
376
|
+
}
|
|
377
|
+
},
|
|
378
|
+
description: 'Send multi-turn conversation to OpenAI API',
|
|
379
|
+
returnType: 'dict',
|
|
380
|
+
},
|
|
381
|
+
// IR-6: openai::embed
|
|
382
|
+
embed: {
|
|
383
|
+
params: [{ name: 'text', type: 'string' }],
|
|
384
|
+
fn: async (args, ctx) => {
|
|
385
|
+
const startTime = Date.now();
|
|
386
|
+
try {
|
|
387
|
+
// Extract arguments
|
|
388
|
+
const text = args[0];
|
|
389
|
+
// EC-15: Validate text is non-empty
|
|
390
|
+
if (text.trim().length === 0) {
|
|
391
|
+
throw new RuntimeError('RILL-R004', 'embed text cannot be empty');
|
|
392
|
+
}
|
|
393
|
+
// EC-16: Validate embed_model is configured
|
|
394
|
+
if (factoryEmbedModel === undefined || factoryEmbedModel === '') {
|
|
395
|
+
throw new RuntimeError('RILL-R004', 'embed_model not configured');
|
|
396
|
+
}
|
|
397
|
+
// Call OpenAI embeddings API
|
|
398
|
+
const response = await client.embeddings.create({
|
|
399
|
+
model: factoryEmbedModel,
|
|
400
|
+
input: text,
|
|
401
|
+
encoding_format: 'float',
|
|
402
|
+
});
|
|
403
|
+
// Extract embedding data
|
|
404
|
+
const embeddingData = response.data[0]?.embedding;
|
|
405
|
+
if (!embeddingData || embeddingData.length === 0) {
|
|
406
|
+
throw new RuntimeError('RILL-R004', 'OpenAI: empty embedding returned');
|
|
407
|
+
}
|
|
408
|
+
// Convert to Float32Array and create RillVector
|
|
409
|
+
const float32Data = new Float32Array(embeddingData);
|
|
410
|
+
const vector = createVector(float32Data, factoryEmbedModel);
|
|
411
|
+
// Emit success event (§4.10)
|
|
412
|
+
const duration = Date.now() - startTime;
|
|
413
|
+
emitExtensionEvent(ctx, {
|
|
414
|
+
event: 'openai:embed',
|
|
415
|
+
subsystem: 'extension:openai',
|
|
416
|
+
duration,
|
|
417
|
+
model: factoryEmbedModel,
|
|
418
|
+
dimensions: float32Data.length,
|
|
419
|
+
});
|
|
420
|
+
return vector;
|
|
421
|
+
}
|
|
422
|
+
catch (error) {
|
|
423
|
+
// Map error and emit failure event
|
|
424
|
+
const duration = Date.now() - startTime;
|
|
425
|
+
const rillError = mapOpenAIError(error);
|
|
426
|
+
emitExtensionEvent(ctx, {
|
|
427
|
+
event: 'openai:error',
|
|
428
|
+
subsystem: 'extension:openai',
|
|
429
|
+
error: rillError.message,
|
|
430
|
+
duration,
|
|
431
|
+
});
|
|
432
|
+
throw rillError;
|
|
433
|
+
}
|
|
434
|
+
},
|
|
435
|
+
description: 'Generate embedding vector for text',
|
|
436
|
+
returnType: 'vector',
|
|
437
|
+
},
|
|
438
|
+
// IR-7: openai::embed_batch
|
|
439
|
+
embed_batch: {
|
|
440
|
+
params: [{ name: 'texts', type: 'list' }],
|
|
441
|
+
fn: async (args, ctx) => {
|
|
442
|
+
const startTime = Date.now();
|
|
443
|
+
try {
|
|
444
|
+
// Extract arguments
|
|
445
|
+
const texts = args[0];
|
|
446
|
+
// AC-24: Empty list returns empty list
|
|
447
|
+
if (texts.length === 0) {
|
|
448
|
+
return [];
|
|
449
|
+
}
|
|
450
|
+
// EC-17: Validate embed_model is configured
|
|
451
|
+
if (factoryEmbedModel === undefined || factoryEmbedModel === '') {
|
|
452
|
+
throw new RuntimeError('RILL-R004', 'embed_model not configured');
|
|
453
|
+
}
|
|
454
|
+
// EC-18: Validate all elements are strings
|
|
455
|
+
const stringTexts = [];
|
|
456
|
+
for (let i = 0; i < texts.length; i++) {
|
|
457
|
+
const text = texts[i];
|
|
458
|
+
if (typeof text !== 'string') {
|
|
459
|
+
throw new RuntimeError('RILL-R004', 'embed_batch requires list of strings');
|
|
460
|
+
}
|
|
461
|
+
// EC-19: Check for empty strings
|
|
462
|
+
if (text.trim().length === 0) {
|
|
463
|
+
throw new RuntimeError('RILL-R004', `embed text cannot be empty at index ${i}`);
|
|
464
|
+
}
|
|
465
|
+
stringTexts.push(text);
|
|
466
|
+
}
|
|
467
|
+
// Call OpenAI embeddings API with batch
|
|
468
|
+
const response = await client.embeddings.create({
|
|
469
|
+
model: factoryEmbedModel,
|
|
470
|
+
input: stringTexts,
|
|
471
|
+
encoding_format: 'float',
|
|
472
|
+
});
|
|
473
|
+
// Convert embeddings to RillVector list
|
|
474
|
+
const vectors = [];
|
|
475
|
+
for (const embeddingItem of response.data) {
|
|
476
|
+
const embeddingData = embeddingItem.embedding;
|
|
477
|
+
if (!embeddingData || embeddingData.length === 0) {
|
|
478
|
+
throw new RuntimeError('RILL-R004', 'OpenAI: empty embedding returned');
|
|
479
|
+
}
|
|
480
|
+
const float32Data = new Float32Array(embeddingData);
|
|
481
|
+
const vector = createVector(float32Data, factoryEmbedModel);
|
|
482
|
+
vectors.push(vector);
|
|
483
|
+
}
|
|
484
|
+
// Emit success event (§4.10)
|
|
485
|
+
const duration = Date.now() - startTime;
|
|
486
|
+
const firstVector = vectors[0];
|
|
487
|
+
const dimensions = firstVector && isVector(firstVector) ? firstVector.data.length : 0;
|
|
488
|
+
emitExtensionEvent(ctx, {
|
|
489
|
+
event: 'openai:embed_batch',
|
|
490
|
+
subsystem: 'extension:openai',
|
|
491
|
+
duration,
|
|
492
|
+
model: factoryEmbedModel,
|
|
493
|
+
dimensions,
|
|
494
|
+
count: vectors.length,
|
|
495
|
+
});
|
|
496
|
+
return vectors;
|
|
497
|
+
}
|
|
498
|
+
catch (error) {
|
|
499
|
+
// Map error and emit failure event
|
|
500
|
+
const duration = Date.now() - startTime;
|
|
501
|
+
const rillError = mapOpenAIError(error);
|
|
502
|
+
emitExtensionEvent(ctx, {
|
|
503
|
+
event: 'openai:error',
|
|
504
|
+
subsystem: 'extension:openai',
|
|
505
|
+
error: rillError.message,
|
|
506
|
+
duration,
|
|
507
|
+
});
|
|
508
|
+
throw rillError;
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
description: 'Generate embedding vectors for multiple texts',
|
|
512
|
+
returnType: 'list',
|
|
513
|
+
},
|
|
514
|
+
// IR-8: openai::tool_loop
|
|
515
|
+
tool_loop: {
|
|
516
|
+
params: [
|
|
517
|
+
{ name: 'prompt', type: 'string' },
|
|
518
|
+
{ name: 'options', type: 'dict', defaultValue: {} },
|
|
519
|
+
],
|
|
520
|
+
fn: async (args, ctx) => {
|
|
521
|
+
const startTime = Date.now();
|
|
522
|
+
try {
|
|
523
|
+
// Extract arguments
|
|
524
|
+
const prompt = args[0];
|
|
525
|
+
const options = (args[1] ?? {});
|
|
526
|
+
// EC-20: Validate prompt is non-empty
|
|
527
|
+
if (prompt.trim().length === 0) {
|
|
528
|
+
throw new RuntimeError('RILL-R004', 'prompt text cannot be empty');
|
|
529
|
+
}
|
|
530
|
+
// EC-21: Validate tools option is present
|
|
531
|
+
if (!('tools' in options) || !Array.isArray(options['tools'])) {
|
|
532
|
+
throw new RuntimeError('RILL-R004', "tool_loop requires 'tools' option");
|
|
533
|
+
}
|
|
534
|
+
const toolDescriptors = options['tools'];
|
|
535
|
+
// Extract options with defaults
|
|
536
|
+
const system = typeof options['system'] === 'string'
|
|
537
|
+
? options['system']
|
|
538
|
+
: factorySystem;
|
|
539
|
+
const maxTokens = typeof options['max_tokens'] === 'number'
|
|
540
|
+
? options['max_tokens']
|
|
541
|
+
: factoryMaxTokens;
|
|
542
|
+
const maxTurns = typeof options['max_turns'] === 'number'
|
|
543
|
+
? options['max_turns']
|
|
544
|
+
: 10;
|
|
545
|
+
const maxErrors = typeof options['max_errors'] === 'number'
|
|
546
|
+
? options['max_errors']
|
|
547
|
+
: 3;
|
|
548
|
+
const initialMessages = Array.isArray(options['messages']) && options['messages'].length > 0
|
|
549
|
+
? options['messages']
|
|
550
|
+
: [];
|
|
551
|
+
// Build tool map and OpenAI tools array
|
|
552
|
+
const toolMap = new Map();
|
|
553
|
+
const openaiTools = [];
|
|
554
|
+
for (const tool of toolDescriptors) {
|
|
555
|
+
if (typeof tool !== 'object' ||
|
|
556
|
+
tool === null ||
|
|
557
|
+
!('name' in tool) ||
|
|
558
|
+
!('fn' in tool)) {
|
|
559
|
+
throw new RuntimeError('RILL-R004', 'invalid tool descriptor in tools list');
|
|
560
|
+
}
|
|
561
|
+
const toolName = tool['name'];
|
|
562
|
+
const toolFn = tool['fn'];
|
|
563
|
+
if (!isCallable(toolFn)) {
|
|
564
|
+
throw new RuntimeError('RILL-R004', `tool '${toolName}' not callable`);
|
|
565
|
+
}
|
|
566
|
+
toolMap.set(toolName, toolFn);
|
|
567
|
+
// Build OpenAI tool definition
|
|
568
|
+
const description = typeof tool['description'] === 'string'
|
|
569
|
+
? tool['description']
|
|
570
|
+
: '';
|
|
571
|
+
const params = tool['params'] ?? {};
|
|
572
|
+
// Convert rill params dict to JSON Schema
|
|
573
|
+
const properties = {};
|
|
574
|
+
const required = [];
|
|
575
|
+
if (typeof params === 'object' && params !== null) {
|
|
576
|
+
for (const [paramName, paramSpec] of Object.entries(params)) {
|
|
577
|
+
if (typeof paramSpec === 'object' &&
|
|
578
|
+
paramSpec !== null &&
|
|
579
|
+
'type' in paramSpec) {
|
|
580
|
+
const spec = paramSpec;
|
|
581
|
+
properties[paramName] = {
|
|
582
|
+
type: spec['type'] ?? 'string',
|
|
583
|
+
description: spec['description'] ?? '',
|
|
584
|
+
};
|
|
585
|
+
// All params are required by default
|
|
586
|
+
required.push(paramName);
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
openaiTools.push({
|
|
591
|
+
type: 'function',
|
|
592
|
+
function: {
|
|
593
|
+
name: toolName,
|
|
594
|
+
description,
|
|
595
|
+
parameters: {
|
|
596
|
+
type: 'object',
|
|
597
|
+
properties,
|
|
598
|
+
required,
|
|
599
|
+
},
|
|
600
|
+
},
|
|
601
|
+
});
|
|
602
|
+
}
|
|
603
|
+
// Build initial messages array
|
|
604
|
+
const conversationMessages = [];
|
|
605
|
+
if (system !== undefined) {
|
|
606
|
+
conversationMessages.push({
|
|
607
|
+
role: 'system',
|
|
608
|
+
content: system,
|
|
609
|
+
});
|
|
610
|
+
}
|
|
611
|
+
// Add history messages if provided
|
|
612
|
+
for (const msg of initialMessages) {
|
|
613
|
+
if (typeof msg === 'object' &&
|
|
614
|
+
msg !== null &&
|
|
615
|
+
'role' in msg &&
|
|
616
|
+
'content' in msg) {
|
|
617
|
+
const role = msg['role'];
|
|
618
|
+
if (role === 'user' || role === 'assistant') {
|
|
619
|
+
conversationMessages.push({
|
|
620
|
+
role: role,
|
|
621
|
+
content: msg['content'],
|
|
622
|
+
});
|
|
623
|
+
}
|
|
624
|
+
}
|
|
625
|
+
}
|
|
626
|
+
// Add user prompt
|
|
627
|
+
conversationMessages.push({
|
|
628
|
+
role: 'user',
|
|
629
|
+
content: prompt,
|
|
630
|
+
});
|
|
631
|
+
// Tool loop state
|
|
632
|
+
let turns = 0;
|
|
633
|
+
let consecutiveErrors = 0;
|
|
634
|
+
let totalInputTokens = 0;
|
|
635
|
+
let totalOutputTokens = 0;
|
|
636
|
+
let finalContent = '';
|
|
637
|
+
let stopReason = 'stop';
|
|
638
|
+
// Main tool loop
|
|
639
|
+
while (turns < maxTurns) {
|
|
640
|
+
turns++;
|
|
641
|
+
// Call OpenAI API with tools
|
|
642
|
+
const apiParams = {
|
|
643
|
+
model: factoryModel,
|
|
644
|
+
max_tokens: maxTokens,
|
|
645
|
+
messages: conversationMessages,
|
|
646
|
+
tools: openaiTools,
|
|
647
|
+
tool_choice: 'auto',
|
|
648
|
+
};
|
|
649
|
+
if (factoryTemperature !== undefined) {
|
|
650
|
+
apiParams.temperature = factoryTemperature;
|
|
651
|
+
}
|
|
652
|
+
const response = await client.chat.completions.create(apiParams);
|
|
653
|
+
// Aggregate usage
|
|
654
|
+
totalInputTokens += response.usage?.prompt_tokens ?? 0;
|
|
655
|
+
totalOutputTokens += response.usage?.completion_tokens ?? 0;
|
|
656
|
+
const choice = response.choices[0];
|
|
657
|
+
if (!choice) {
|
|
658
|
+
throw new RuntimeError('RILL-R004', 'OpenAI: no choices returned');
|
|
659
|
+
}
|
|
660
|
+
const message = choice.message;
|
|
661
|
+
const finishReason = choice.finish_reason;
|
|
662
|
+
// Check if we have tool calls
|
|
663
|
+
if (message.tool_calls && message.tool_calls.length > 0) {
|
|
664
|
+
// Add assistant message with tool calls to conversation
|
|
665
|
+
conversationMessages.push({
|
|
666
|
+
role: 'assistant',
|
|
667
|
+
content: message.content ?? null,
|
|
668
|
+
tool_calls: message.tool_calls,
|
|
669
|
+
});
|
|
670
|
+
// Execute tool calls (parallel for multiple calls)
|
|
671
|
+
const toolResults = await Promise.all(message.tool_calls.map(async (toolCall) => {
|
|
672
|
+
// Only handle function tool calls (not custom)
|
|
673
|
+
if (!('function' in toolCall)) {
|
|
674
|
+
throw new RuntimeError('RILL-R004', 'unsupported tool call type');
|
|
675
|
+
}
|
|
676
|
+
const toolStartTime = Date.now();
|
|
677
|
+
const toolName = toolCall.function.name;
|
|
678
|
+
const toolCallId = toolCall.id;
|
|
679
|
+
// Emit tool_call event
|
|
680
|
+
emitExtensionEvent(ctx, {
|
|
681
|
+
event: 'openai:tool_call',
|
|
682
|
+
subsystem: 'extension:openai',
|
|
683
|
+
tool_name: toolName,
|
|
684
|
+
args: toolCall.function.arguments,
|
|
685
|
+
});
|
|
686
|
+
// EC-22: Check tool exists (configuration error, abort immediately)
|
|
687
|
+
const toolFn = toolMap.get(toolName);
|
|
688
|
+
if (!toolFn) {
|
|
689
|
+
throw new RuntimeError('RILL-R004', `unknown tool '${toolName}'`);
|
|
690
|
+
}
|
|
691
|
+
try {
|
|
692
|
+
// Parse arguments
|
|
693
|
+
let toolArgs;
|
|
694
|
+
try {
|
|
695
|
+
toolArgs = JSON.parse(toolCall.function.arguments);
|
|
696
|
+
}
|
|
697
|
+
catch {
|
|
698
|
+
throw new RuntimeError('RILL-R004', `invalid tool arguments for '${toolName}'`);
|
|
699
|
+
}
|
|
700
|
+
// Convert to RillValue array (positional args from params)
|
|
701
|
+
const argsArray = [];
|
|
702
|
+
for (const [, value] of Object.entries(toolArgs)) {
|
|
703
|
+
argsArray.push(value);
|
|
704
|
+
}
|
|
705
|
+
// Invoke tool callable based on type
|
|
706
|
+
let result;
|
|
707
|
+
if (toolFn.kind === 'script') {
|
|
708
|
+
// ScriptCallable: not supported in tool_loop context
|
|
709
|
+
throw new RuntimeError('RILL-R004', 'script closures not yet supported in tool_loop');
|
|
710
|
+
}
|
|
711
|
+
else {
|
|
712
|
+
// RuntimeCallable or ApplicationCallable
|
|
713
|
+
result = await toolFn.fn(argsArray, ctx, undefined);
|
|
714
|
+
}
|
|
715
|
+
// Reset consecutive errors on success
|
|
716
|
+
consecutiveErrors = 0;
|
|
717
|
+
// Emit tool_result event
|
|
718
|
+
const toolDuration = Date.now() - toolStartTime;
|
|
719
|
+
emitExtensionEvent(ctx, {
|
|
720
|
+
event: 'openai:tool_result',
|
|
721
|
+
subsystem: 'extension:openai',
|
|
722
|
+
tool_name: toolName,
|
|
723
|
+
duration: toolDuration,
|
|
724
|
+
});
|
|
725
|
+
// Return tool result as string
|
|
726
|
+
return {
|
|
727
|
+
tool_call_id: toolCallId,
|
|
728
|
+
role: 'tool',
|
|
729
|
+
content: typeof result === 'string'
|
|
730
|
+
? result
|
|
731
|
+
: JSON.stringify(result),
|
|
732
|
+
};
|
|
733
|
+
}
|
|
734
|
+
catch (error) {
|
|
735
|
+
consecutiveErrors++;
|
|
736
|
+
// Format error for LLM
|
|
737
|
+
const errorMessage = error instanceof RuntimeError
|
|
738
|
+
? error.message
|
|
739
|
+
: error instanceof Error
|
|
740
|
+
? error.message
|
|
741
|
+
: 'unknown error';
|
|
742
|
+
// Emit tool_result event with error
|
|
743
|
+
const toolDuration = Date.now() - toolStartTime;
|
|
744
|
+
emitExtensionEvent(ctx, {
|
|
745
|
+
event: 'openai:tool_result',
|
|
746
|
+
subsystem: 'extension:openai',
|
|
747
|
+
tool_name: toolName,
|
|
748
|
+
duration: toolDuration,
|
|
749
|
+
error: errorMessage,
|
|
750
|
+
});
|
|
751
|
+
// EC-23: Check if max_errors exceeded
|
|
752
|
+
if (consecutiveErrors >= maxErrors) {
|
|
753
|
+
throw new RuntimeError('RILL-R004', `tool loop aborted after ${maxErrors} consecutive errors`);
|
|
754
|
+
}
|
|
755
|
+
// Return error to LLM as tool result
|
|
756
|
+
return {
|
|
757
|
+
tool_call_id: toolCallId,
|
|
758
|
+
role: 'tool',
|
|
759
|
+
content: JSON.stringify({
|
|
760
|
+
error: errorMessage,
|
|
761
|
+
code: 'RILL-R001',
|
|
762
|
+
}),
|
|
763
|
+
};
|
|
764
|
+
}
|
|
765
|
+
}));
|
|
766
|
+
// Add tool results to conversation
|
|
767
|
+
for (const toolResult of toolResults) {
|
|
768
|
+
conversationMessages.push(toolResult);
|
|
769
|
+
}
|
|
770
|
+
// Continue loop to get next response
|
|
771
|
+
continue;
|
|
772
|
+
}
|
|
773
|
+
// No tool calls - final response
|
|
774
|
+
finalContent = message.content ?? '';
|
|
775
|
+
stopReason = finishReason ?? 'stop';
|
|
776
|
+
break;
|
|
777
|
+
}
|
|
778
|
+
// Check if we hit max_turns
|
|
779
|
+
if (turns >= maxTurns && stopReason === 'stop') {
|
|
780
|
+
stopReason = 'max_turns';
|
|
781
|
+
}
|
|
782
|
+
// Build conversation history for response
|
|
783
|
+
const fullMessages = [];
|
|
784
|
+
for (const msg of conversationMessages) {
|
|
785
|
+
if (msg.role === 'system') {
|
|
786
|
+
// Skip system messages in history
|
|
787
|
+
continue;
|
|
788
|
+
}
|
|
789
|
+
const historyMsg = {
|
|
790
|
+
role: msg.role,
|
|
791
|
+
};
|
|
792
|
+
if ('content' in msg && msg.content) {
|
|
793
|
+
historyMsg['content'] = msg.content;
|
|
794
|
+
}
|
|
795
|
+
if ('tool_calls' in msg && msg.tool_calls) {
|
|
796
|
+
historyMsg['tool_calls'] = msg.tool_calls;
|
|
797
|
+
}
|
|
798
|
+
fullMessages.push(historyMsg);
|
|
799
|
+
}
|
|
800
|
+
// Build result dict
|
|
801
|
+
const result = {
|
|
802
|
+
content: finalContent,
|
|
803
|
+
model: factoryModel,
|
|
804
|
+
usage: {
|
|
805
|
+
input: totalInputTokens,
|
|
806
|
+
output: totalOutputTokens,
|
|
807
|
+
},
|
|
808
|
+
stop_reason: stopReason,
|
|
809
|
+
turns,
|
|
810
|
+
messages: fullMessages,
|
|
811
|
+
};
|
|
812
|
+
// Emit success event (§4.10)
|
|
813
|
+
const duration = Date.now() - startTime;
|
|
814
|
+
emitExtensionEvent(ctx, {
|
|
815
|
+
event: 'openai:tool_loop',
|
|
816
|
+
subsystem: 'extension:openai',
|
|
817
|
+
turns,
|
|
818
|
+
total_duration: duration,
|
|
819
|
+
usage: result.usage,
|
|
820
|
+
});
|
|
821
|
+
return result;
|
|
822
|
+
}
|
|
823
|
+
catch (error) {
|
|
824
|
+
// Map error and emit failure event
|
|
825
|
+
const duration = Date.now() - startTime;
|
|
826
|
+
const rillError = mapOpenAIError(error);
|
|
827
|
+
emitExtensionEvent(ctx, {
|
|
828
|
+
event: 'openai:error',
|
|
829
|
+
subsystem: 'extension:openai',
|
|
830
|
+
error: rillError.message,
|
|
831
|
+
duration,
|
|
832
|
+
});
|
|
833
|
+
throw rillError;
|
|
834
|
+
}
|
|
835
|
+
},
|
|
836
|
+
description: 'Execute tool-use loop with OpenAI API',
|
|
837
|
+
returnType: 'dict',
|
|
838
|
+
},
|
|
839
|
+
};
|
|
840
|
+
// IR-11: Attach dispose lifecycle method
|
|
841
|
+
result.dispose = dispose;
|
|
842
|
+
return result;
|
|
843
|
+
}
|
|
844
|
+
//# sourceMappingURL=factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"factory.js","sourceRoot":"","sources":["../src/factory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,MAAM,MAAM,QAAQ,CAAC;AAC5B,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,YAAY,EACZ,UAAU,EACV,QAAQ,GAKT,MAAM,aAAa,CAAC;AAGrB,+DAA+D;AAC/D,YAAY;AACZ,+DAA+D;AAE/D,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,eAAe,GAAG,GAAG,CAAC;AAC5B,MAAM,kBAAkB,GAAG,IAAI,CAAC;AAEhC,+DAA+D;AAC/D,mBAAmB;AACnB,+DAA+D;AAE/D;;;;;GAKG;AACH,SAAS,cAAc,CAAC,KAAc;IACpC,IAAI,KAAK,YAAY,MAAM,CAAC,QAAQ,EAAE,CAAC;QACrC,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,CAAC;QAC5B,MAAM,OAAO,GAAG,KAAK,CAAC,OAAO,CAAC;QAE9B,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,YAAY,CACrB,WAAW,EACX,qCAAqC,CACtC,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,KAAK,GAAG,EAAE,CAAC;YACnB,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,oBAAoB,CAAC,CAAC;QAC7D,CAAC;QAED,IAAI,MAAM,IAAI,MAAM,IAAI,GAAG,EAAE,CAAC;YAC5B,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,WAAW,OAAO,KAAK,MAAM,GAAG,CAAC,CAAC;QACzE,CAAC;QAED,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,WAAW,OAAO,EAAE,CAAC,CAAC;IAC7D,CAAC;IAED,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAC,EAAE,CAAC;YACrE,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,yBAAyB,CAAC,CAAC;QAClE,CAAC;QACD,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,WAAW,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACnE,CAAC;IAED,OAAO,IAAI,YAAY,CAAC,WAAW,EAAE,uBAAuB,CAAC,CAAC;AAChE,CAAC;AAED,+DAA+D;AAC/D,aAAa;AACb,+DAA+D;AAE/D;;;;;GAKG;AACH,SAAS,cAAc,CACrB,OAA2B;IAE3B,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QAC1B,MAAM,IAAI,KAAK,CAAC,qBAAqB,CAAC,CAAC;IACzC,CAAC;IACD,IAAI,OAAO,KAAK,EAAE,EAAE,CAAC;QACnB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,aAAa,CAAC,KAAyB;IAC9C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,MAAM,IAAI,KAAK,CAAC,mBAAmB,CAAC,CAAC;IACvC,CAAC;AACH,CAAC;AAED;;;;;GAKG;AACH,SAAS,mBAAmB,CAAC,WAA+B;IAC1D,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;QAC9B,IAAI,WAAW,GAAG,eAAe,IAAI,WAAW,GAAG,eAAe,EAAE,CAAC;YACnE,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;QACzD,CAAC;IACH,CAAC;AACH,CAAC;AAED,+DAA+D;AAC/D,UAAU;AACV,+DAA+D;AAE/D;;;;;;;;;;;;;;;;;;GAkBG;AACH,MAAM,UAAU,qBAAqB,CACnC,MAA6B;IAE7B,kCAAkC;IAClC,cAAc,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IAC/B,aAAa,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;IAC5B,mBAAmB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAC;IAExC,gDAAgD;IAChD,8EAA8E;IAC9E,MAAM,MAAM,GAAG,IAAI,MAAM,CAAC;QACxB,MAAM,EAAE,MAAM,CAAC,OAAO;QACtB,OAAO,EAAE,MAAM,CAAC,QAAQ;QACxB,UAAU,EAAE,MAAM,CAAC,WAAW;QAC9B,OAAO,EAAE,MAAM,CAAC,OAAO;KACxB,CAAC,CAAC;IAEH,6CAA6C;IAC7C,MAAM,YAAY,GAAG,MAAM,CAAC,KAAK,CAAC;IAClC,MAAM,kBAAkB,GAAG,MAAM,CAAC,WAAW,CAAC;IAC9C,MAAM,gBAAgB,GAAG,MAAM,CAAC,UAAU,IAAI,kBAAkB,CAAC;IACjE,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC;IACpC,MAAM,iBAAiB,GAAG,MAAM,CAAC,WAAW,CAAC;IAE7C,gEAAgE;IAChE,KAAK,iBAAiB,CAAC;IAEvB,gEAAgE;IAChE,IAAI,eAAe,GAAgC,IAAI,eAAe,EAAE,CAAC;IAEzE,sCAAsC;IACtC,MAAM,OAAO,GAAG,KAAK,IAAmB,EAAE;QACxC,iDAAiD;QACjD,IAAI,CAAC;YACH,0DAA0D;YAC1D,IAAI,eAAe,EAAE,CAAC;gBACpB,eAAe,CAAC,KAAK,EAAE,CAAC;gBACxB,eAAe,GAAG,SAAS,CAAC;YAC9B,CAAC;QACH,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,oCAAoC,OAAO,EAAE,CAAC,CAAC;QAC9D,CAAC;QAED,IAAI,CAAC;YACH,+BAA+B;YAC/B,mEAAmE;YACnE,wDAAwD;QAC1D,CAAC;QAAC,OAAO,KAAc,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,eAAe,CAAC;YACzE,OAAO,CAAC,IAAI,CAAC,iCAAiC,OAAO,EAAE,CAAC,CAAC;QAC3D,CAAC;IACH,CAAC,CAAC;IAEF,+CAA+C;IAC/C,MAAM,MAAM,GAAoB;QAC9B,wBAAwB;QACxB,OAAO,EAAE;YACP,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAChC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;aACpD;YACD,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAsB,EAAE;gBAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;oBAC/B,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;oBAE3D,mCAAmC;oBACnC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC7B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,6BAA6B,CAAC,CAAC;oBACrE,CAAC;oBAED,kBAAkB;oBAClB,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,QAAQ;wBACnC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;wBACnB,CAAC,CAAC,aAAa,CAAC;oBACpB,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ;wBACvC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;wBACvB,CAAC,CAAC,gBAAgB,CAAC;oBAEvB,iFAAiF;oBACjF,MAAM,WAAW,GAAwC,EAAE,CAAC;oBAE5D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBACzB,WAAW,CAAC,IAAI,CAAC;4BACf,IAAI,EAAE,QAAQ;4BACd,OAAO,EAAE,MAAM;yBAChB,CAAC,CAAC;oBACL,CAAC;oBAED,WAAW,CAAC,IAAI,CAAC;wBACf,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,IAAI;qBACd,CAAC,CAAC;oBAEH,kBAAkB;oBAClB,MAAM,SAAS,GAAkD;wBAC/D,KAAK,EAAE,YAAY;wBACnB,UAAU,EAAE,SAAS;wBACrB,QAAQ,EAAE,WAAW;qBACtB,CAAC;oBAEF,0CAA0C;oBAC1C,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;wBACrC,SAAS,CAAC,WAAW,GAAG,kBAAkB,CAAC;oBAC7C,CAAC;oBAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBAEjE,wEAAwE;oBACxE,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;oBAE5D,wCAAwC;oBACxC,MAAM,MAAM,GAAG;wBACb,OAAO;wBACP,KAAK,EAAE,QAAQ,CAAC,KAAK;wBACrB,KAAK,EAAE;4BACL,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;4BACzC,MAAM,EAAE,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,CAAC;yBAC/C;wBACD,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,SAAS;wBAC5D,EAAE,EAAE,QAAQ,CAAC,EAAE;wBACf,QAAQ,EAAE;4BACR,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BACxD,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,IAAI,EAAE;4BAC/B,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE;yBAC/B;qBACF,CAAC;oBAEF,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,gBAAgB;wBACvB,SAAS,EAAE,kBAAkB;wBAC7B,QAAQ;wBACR,KAAK,EAAE,QAAQ,CAAC,KAAK;wBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;qBACpB,CAAC,CAAC;oBAEH,OAAO,MAAmB,CAAC;gBAC7B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,mCAAmC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAExC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK,EAAE,SAAS,CAAC,OAAO;wBACxB,QAAQ;qBACT,CAAC,CAAC;oBAEH,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,WAAW,EAAE,mCAAmC;YAChD,UAAU,EAAE,MAAM;SACnB;QAED,yBAAyB;QACzB,QAAQ,EAAE;YACR,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE;gBAClC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;aACpD;YACD,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAsB,EAAE;gBAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,QAAQ,GAAG,IAAI,CAAC,CAAC,CAAmC,CAAC;oBAC3D,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;oBAE3D,0CAA0C;oBAC1C,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC1B,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,+BAA+B,CAChC,CAAC;oBACJ,CAAC;oBAED,kBAAkB;oBAClB,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,QAAQ;wBACnC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;wBACnB,CAAC,CAAC,aAAa,CAAC;oBACpB,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ;wBACvC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;wBACvB,CAAC,CAAC,gBAAgB,CAAC;oBAEvB,6DAA6D;oBAC7D,MAAM,WAAW,GAAwC,EAAE,CAAC;oBAE5D,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBACzB,WAAW,CAAC,IAAI,CAAC;4BACf,IAAI,EAAE,QAAQ;4BACd,OAAO,EAAE,MAAM;yBAChB,CAAC,CAAC;oBACL,CAAC;oBAED,kCAAkC;oBAClC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACzC,MAAM,GAAG,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;wBAExB,mCAAmC;wBACnC,IAAI,CAAC,GAAG,IAAI,OAAO,GAAG,KAAK,QAAQ,IAAI,CAAC,CAAC,MAAM,IAAI,GAAG,CAAC,EAAE,CAAC;4BACxD,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,uCAAuC,CACxC,CAAC;wBACJ,CAAC;wBAED,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;wBAEzB,yCAAyC;wBACzC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;4BAC/D,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,iBAAiB,IAAI,GAAG,CAAC,CAAC;wBAChE,CAAC;wBAED,sCAAsC;wBACtC,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;4BACvC,IAAI,CAAC,CAAC,SAAS,IAAI,GAAG,CAAC,IAAI,OAAO,GAAG,CAAC,SAAS,CAAC,KAAK,QAAQ,EAAE,CAAC;gCAC9D,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,GAAG,IAAI,6BAA6B,CACrC,CAAC;4BACJ,CAAC;4BACD,WAAW,CAAC,IAAI,CAAC;gCACf,IAAI,EAAE,IAAc;gCACpB,OAAO,EAAE,GAAG,CAAC,SAAS,CAAW;6BAClC,CAAC,CAAC;wBACL,CAAC;wBACD,uDAAuD;6BAClD,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;4BAC9B,MAAM,UAAU,GAAG,SAAS,IAAI,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;4BACtD,MAAM,YAAY,GAAG,YAAY,IAAI,GAAG,IAAI,GAAG,CAAC,YAAY,CAAC,CAAC;4BAE9D,IAAI,CAAC,UAAU,IAAI,CAAC,YAAY,EAAE,CAAC;gCACjC,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,sDAAsD,CACvD,CAAC;4BACJ,CAAC;4BAED,mCAAmC;4BACnC,IAAI,UAAU,EAAE,CAAC;gCACf,WAAW,CAAC,IAAI,CAAC;oCACf,IAAI,EAAE,WAAW;oCACjB,OAAO,EAAE,GAAG,CAAC,SAAS,CAAW;iCAClC,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,kBAAkB;oBAClB,MAAM,SAAS,GAAkD;wBAC/D,KAAK,EAAE,YAAY;wBACnB,UAAU,EAAE,SAAS;wBACrB,QAAQ,EAAE,WAAW;qBACtB,CAAC;oBAEF,0CAA0C;oBAC1C,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;wBACrC,SAAS,CAAC,WAAW,GAAG,kBAAkB,CAAC;oBAC7C,CAAC;oBAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;oBAEjE,qCAAqC;oBACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,OAAO,IAAI,EAAE,CAAC;oBAE5D,yCAAyC;oBACzC,MAAM,YAAY,GAAG;wBACnB,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;4BACpB,MAAM,UAAU,GAA4B,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,CAAC;4BAChE,IAAI,SAAS,IAAI,CAAC;gCAAE,UAAU,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,SAAS,CAAC,CAAC;4BACzD,IAAI,YAAY,IAAI,CAAC;gCAAE,UAAU,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,YAAY,CAAC,CAAC;4BAClE,OAAO,UAAU,CAAC;wBACpB,CAAC,CAAC;wBACF,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE;qBAC/B,CAAC;oBAEF,wCAAwC;oBACxC,MAAM,MAAM,GAAG;wBACb,OAAO;wBACP,KAAK,EAAE,QAAQ,CAAC,KAAK;wBACrB,KAAK,EAAE;4BACL,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC;4BACzC,MAAM,EAAE,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,CAAC;yBAC/C;wBACD,WAAW,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,aAAa,IAAI,SAAS;wBAC5D,EAAE,EAAE,QAAQ,CAAC,EAAE;wBACf,QAAQ,EAAE,YAAY;qBACvB,CAAC;oBAEF,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,iBAAiB;wBACxB,SAAS,EAAE,kBAAkB;wBAC7B,QAAQ;wBACR,KAAK,EAAE,QAAQ,CAAC,KAAK;wBACrB,KAAK,EAAE,MAAM,CAAC,KAAK;qBACpB,CAAC,CAAC;oBAEH,OAAO,MAAmB,CAAC;gBAC7B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,mCAAmC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAExC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK,EAAE,SAAS,CAAC,OAAO;wBACxB,QAAQ;qBACT,CAAC,CAAC;oBAEH,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,WAAW,EAAE,4CAA4C;YACzD,UAAU,EAAE,MAAM;SACnB;QAED,sBAAsB;QACtB,KAAK,EAAE;YACL,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAC;YAC1C,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAsB,EAAE;gBAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,IAAI,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;oBAE/B,oCAAoC;oBACpC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC7B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC;oBACpE,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,EAAE,EAAE,CAAC;wBAChE,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC;oBACpE,CAAC;oBAED,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;wBAC9C,KAAK,EAAE,iBAAiB;wBACxB,KAAK,EAAE,IAAI;wBACX,eAAe,EAAE,OAAO;qBACzB,CAAC,CAAC;oBAEH,yBAAyB;oBACzB,MAAM,aAAa,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,SAAS,CAAC;oBAClD,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACjD,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,kCAAkC,CACnC,CAAC;oBACJ,CAAC;oBAED,gDAAgD;oBAChD,MAAM,WAAW,GAAG,IAAI,YAAY,CAAC,aAAa,CAAC,CAAC;oBACpD,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;oBAE5D,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,QAAQ;wBACR,KAAK,EAAE,iBAAiB;wBACxB,UAAU,EAAE,WAAW,CAAC,MAAM;qBAC/B,CAAC,CAAC;oBAEH,OAAO,MAAmB,CAAC;gBAC7B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,mCAAmC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAExC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK,EAAE,SAAS,CAAC,OAAO;wBACxB,QAAQ;qBACT,CAAC,CAAC;oBAEH,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,WAAW,EAAE,oCAAoC;YACjD,UAAU,EAAE,QAAQ;SACrB;QAED,4BAA4B;QAC5B,WAAW,EAAE;YACX,MAAM,EAAE,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC;YACzC,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAsB,EAAE;gBAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,KAAK,GAAG,IAAI,CAAC,CAAC,CAAqB,CAAC;oBAE1C,uCAAuC;oBACvC,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBACvB,OAAO,EAAe,CAAC;oBACzB,CAAC;oBAED,4CAA4C;oBAC5C,IAAI,iBAAiB,KAAK,SAAS,IAAI,iBAAiB,KAAK,EAAE,EAAE,CAAC;wBAChE,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,4BAA4B,CAAC,CAAC;oBACpE,CAAC;oBAED,2CAA2C;oBAC3C,MAAM,WAAW,GAAa,EAAE,CAAC;oBACjC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;wBACtC,MAAM,IAAI,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC;wBACtB,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;4BAC7B,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,sCAAsC,CACvC,CAAC;wBACJ,CAAC;wBACD,iCAAiC;wBACjC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BAC7B,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,uCAAuC,CAAC,EAAE,CAC3C,CAAC;wBACJ,CAAC;wBACD,WAAW,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACzB,CAAC;oBAED,wCAAwC;oBACxC,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,MAAM,CAAC;wBAC9C,KAAK,EAAE,iBAAiB;wBACxB,KAAK,EAAE,WAAW;wBAClB,eAAe,EAAE,OAAO;qBACzB,CAAC,CAAC;oBAEH,wCAAwC;oBACxC,MAAM,OAAO,GAAgB,EAAE,CAAC;oBAChC,KAAK,MAAM,aAAa,IAAI,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAC1C,MAAM,aAAa,GAAG,aAAa,CAAC,SAAS,CAAC;wBAC9C,IAAI,CAAC,aAAa,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;4BACjD,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,kCAAkC,CACnC,CAAC;wBACJ,CAAC;wBACD,MAAM,WAAW,GAAG,IAAI,YAAY,CAAC,aAAa,CAAC,CAAC;wBACpD,MAAM,MAAM,GAAG,YAAY,CAAC,WAAW,EAAE,iBAAiB,CAAC,CAAC;wBAC5D,OAAO,CAAC,IAAI,CAAC,MAAmB,CAAC,CAAC;oBACpC,CAAC;oBAED,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,WAAW,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;oBAC/B,MAAM,UAAU,GACd,WAAW,IAAI,QAAQ,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;oBACrE,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,oBAAoB;wBAC3B,SAAS,EAAE,kBAAkB;wBAC7B,QAAQ;wBACR,KAAK,EAAE,iBAAiB;wBACxB,UAAU;wBACV,KAAK,EAAE,OAAO,CAAC,MAAM;qBACtB,CAAC,CAAC;oBAEH,OAAO,OAAoB,CAAC;gBAC9B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,mCAAmC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAExC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK,EAAE,SAAS,CAAC,OAAO;wBACxB,QAAQ;qBACT,CAAC,CAAC;oBAEH,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,WAAW,EAAE,+CAA+C;YAC5D,UAAU,EAAE,MAAM;SACnB;QAED,0BAA0B;QAC1B,SAAS,EAAE;YACT,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAClC,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,EAAE,EAAE;aACpD;YACD,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,GAAG,EAAsB,EAAE;gBAC1C,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gBAE7B,IAAI,CAAC;oBACH,oBAAoB;oBACpB,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAW,CAAC;oBACjC,MAAM,OAAO,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAA4B,CAAC;oBAE3D,sCAAsC;oBACtC,IAAI,MAAM,CAAC,IAAI,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;wBAC/B,MAAM,IAAI,YAAY,CAAC,WAAW,EAAE,6BAA6B,CAAC,CAAC;oBACrE,CAAC;oBAED,0CAA0C;oBAC1C,IAAI,CAAC,CAAC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC;wBAC9D,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,mCAAmC,CACpC,CAAC;oBACJ,CAAC;oBAED,MAAM,eAAe,GAAG,OAAO,CAAC,OAAO,CAEtC,CAAC;oBAEF,gCAAgC;oBAChC,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,QAAQ,CAAC,KAAK,QAAQ;wBACnC,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;wBACnB,CAAC,CAAC,aAAa,CAAC;oBACpB,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ;wBACvC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;wBACvB,CAAC,CAAC,gBAAgB,CAAC;oBACvB,MAAM,QAAQ,GACZ,OAAO,OAAO,CAAC,WAAW,CAAC,KAAK,QAAQ;wBACtC,CAAC,CAAC,OAAO,CAAC,WAAW,CAAC;wBACtB,CAAC,CAAC,EAAE,CAAC;oBACT,MAAM,SAAS,GACb,OAAO,OAAO,CAAC,YAAY,CAAC,KAAK,QAAQ;wBACvC,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC;wBACvB,CAAC,CAAC,CAAC,CAAC;oBACR,MAAM,eAAe,GACnB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC,IAAI,OAAO,CAAC,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC;wBAClE,CAAC,CAAE,OAAO,CAAC,UAAU,CAAoC;wBACzD,CAAC,CAAC,EAAE,CAAC;oBAET,wCAAwC;oBACxC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAwB,CAAC;oBAChD,MAAM,WAAW,GAAgC,EAAE,CAAC;oBAEpD,KAAK,MAAM,IAAI,IAAI,eAAe,EAAE,CAAC;wBACnC,IACE,OAAO,IAAI,KAAK,QAAQ;4BACxB,IAAI,KAAK,IAAI;4BACb,CAAC,CAAC,MAAM,IAAI,IAAI,CAAC;4BACjB,CAAC,CAAC,IAAI,IAAI,IAAI,CAAC,EACf,CAAC;4BACD,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,uCAAuC,CACxC,CAAC;wBACJ,CAAC;wBAED,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,CAAW,CAAC;wBACxC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC;wBAE1B,IAAI,CAAC,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;4BACxB,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,SAAS,QAAQ,gBAAgB,CAClC,CAAC;wBACJ,CAAC;wBAED,OAAO,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAsB,CAAC,CAAC;wBAE9C,+BAA+B;wBAC/B,MAAM,WAAW,GACf,OAAO,IAAI,CAAC,aAAa,CAAC,KAAK,QAAQ;4BACrC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC;4BACrB,CAAC,CAAC,EAAE,CAAC;wBACT,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,IAAI,EAAE,CAAC;wBAEpC,0CAA0C;wBAC1C,MAAM,UAAU,GAA4B,EAAE,CAAC;wBAC/C,MAAM,QAAQ,GAAa,EAAE,CAAC;wBAE9B,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI,EAAE,CAAC;4BAClD,KAAK,MAAM,CAAC,SAAS,EAAE,SAAS,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;gCAC5D,IACE,OAAO,SAAS,KAAK,QAAQ;oCAC7B,SAAS,KAAK,IAAI;oCAClB,MAAM,IAAI,SAAS,EACnB,CAAC;oCACD,MAAM,IAAI,GAAG,SAAoC,CAAC;oCAClD,UAAU,CAAC,SAAS,CAAC,GAAG;wCACtB,IAAI,EAAE,IAAI,CAAC,MAAM,CAAC,IAAI,QAAQ;wCAC9B,WAAW,EAAE,IAAI,CAAC,aAAa,CAAC,IAAI,EAAE;qCACvC,CAAC;oCACF,qCAAqC;oCACrC,QAAQ,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;gCAC3B,CAAC;4BACH,CAAC;wBACH,CAAC;wBAED,WAAW,CAAC,IAAI,CAAC;4BACf,IAAI,EAAE,UAAU;4BAChB,QAAQ,EAAE;gCACR,IAAI,EAAE,QAAQ;gCACd,WAAW;gCACX,UAAU,EAAE;oCACV,IAAI,EAAE,QAAQ;oCACd,UAAU;oCACV,QAAQ;iCACT;6BACF;yBACF,CAAC,CAAC;oBACL,CAAC;oBAED,+BAA+B;oBAC/B,MAAM,oBAAoB,GAAwC,EAAE,CAAC;oBAErE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;wBACzB,oBAAoB,CAAC,IAAI,CAAC;4BACxB,IAAI,EAAE,QAAQ;4BACd,OAAO,EAAE,MAAM;yBAChB,CAAC,CAAC;oBACL,CAAC;oBAED,mCAAmC;oBACnC,KAAK,MAAM,GAAG,IAAI,eAAe,EAAE,CAAC;wBAClC,IACE,OAAO,GAAG,KAAK,QAAQ;4BACvB,GAAG,KAAK,IAAI;4BACZ,MAAM,IAAI,GAAG;4BACb,SAAS,IAAI,GAAG,EAChB,CAAC;4BACD,MAAM,IAAI,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC;4BACzB,IAAI,IAAI,KAAK,MAAM,IAAI,IAAI,KAAK,WAAW,EAAE,CAAC;gCAC5C,oBAAoB,CAAC,IAAI,CAAC;oCACxB,IAAI,EAAE,IAA4B;oCAClC,OAAO,EAAE,GAAG,CAAC,SAAS,CAAW;iCAClC,CAAC,CAAC;4BACL,CAAC;wBACH,CAAC;oBACH,CAAC;oBAED,kBAAkB;oBAClB,oBAAoB,CAAC,IAAI,CAAC;wBACxB,IAAI,EAAE,MAAM;wBACZ,OAAO,EAAE,MAAM;qBAChB,CAAC,CAAC;oBAEH,kBAAkB;oBAClB,IAAI,KAAK,GAAG,CAAC,CAAC;oBACd,IAAI,iBAAiB,GAAG,CAAC,CAAC;oBAC1B,IAAI,gBAAgB,GAAG,CAAC,CAAC;oBACzB,IAAI,iBAAiB,GAAG,CAAC,CAAC;oBAC1B,IAAI,YAAY,GAAG,EAAE,CAAC;oBACtB,IAAI,UAAU,GAAG,MAAM,CAAC;oBAExB,iBAAiB;oBACjB,OAAO,KAAK,GAAG,QAAQ,EAAE,CAAC;wBACxB,KAAK,EAAE,CAAC;wBAER,6BAA6B;wBAC7B,MAAM,SAAS,GAAkD;4BAC/D,KAAK,EAAE,YAAY;4BACnB,UAAU,EAAE,SAAS;4BACrB,QAAQ,EAAE,oBAAoB;4BAC9B,KAAK,EAAE,WAAW;4BAClB,WAAW,EAAE,MAAM;yBACpB,CAAC;wBAEF,IAAI,kBAAkB,KAAK,SAAS,EAAE,CAAC;4BACrC,SAAS,CAAC,WAAW,GAAG,kBAAkB,CAAC;wBAC7C,CAAC;wBAED,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;wBAEjE,kBAAkB;wBAClB,gBAAgB,IAAI,QAAQ,CAAC,KAAK,EAAE,aAAa,IAAI,CAAC,CAAC;wBACvD,iBAAiB,IAAI,QAAQ,CAAC,KAAK,EAAE,iBAAiB,IAAI,CAAC,CAAC;wBAE5D,MAAM,MAAM,GAAG,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;wBACnC,IAAI,CAAC,MAAM,EAAE,CAAC;4BACZ,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,6BAA6B,CAC9B,CAAC;wBACJ,CAAC;wBAED,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC;wBAC/B,MAAM,YAAY,GAAG,MAAM,CAAC,aAAa,CAAC;wBAE1C,8BAA8B;wBAC9B,IAAI,OAAO,CAAC,UAAU,IAAI,OAAO,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;4BACxD,wDAAwD;4BACxD,oBAAoB,CAAC,IAAI,CAAC;gCACxB,IAAI,EAAE,WAAW;gCACjB,OAAO,EAAE,OAAO,CAAC,OAAO,IAAI,IAAI;gCAChC,UAAU,EAAE,OAAO,CAAC,UAAU;6BAC/B,CAAC,CAAC;4BAEH,mDAAmD;4BACnD,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,GAAG,CACnC,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,KAAK,EAAE,QAAQ,EAAE,EAAE;gCACxC,+CAA+C;gCAC/C,IAAI,CAAC,CAAC,UAAU,IAAI,QAAQ,CAAC,EAAE,CAAC;oCAC9B,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,4BAA4B,CAC7B,CAAC;gCACJ,CAAC;gCAED,MAAM,aAAa,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;gCACjC,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;gCACxC,MAAM,UAAU,GAAG,QAAQ,CAAC,EAAE,CAAC;gCAE/B,uBAAuB;gCACvB,kBAAkB,CAAC,GAAqB,EAAE;oCACxC,KAAK,EAAE,kBAAkB;oCACzB,SAAS,EAAE,kBAAkB;oCAC7B,SAAS,EAAE,QAAQ;oCACnB,IAAI,EAAE,QAAQ,CAAC,QAAQ,CAAC,SAAS;iCAClC,CAAC,CAAC;gCAEH,oEAAoE;gCACpE,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;gCACrC,IAAI,CAAC,MAAM,EAAE,CAAC;oCACZ,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,iBAAiB,QAAQ,GAAG,CAC7B,CAAC;gCACJ,CAAC;gCAED,IAAI,CAAC;oCACH,kBAAkB;oCAClB,IAAI,QAAiC,CAAC;oCACtC,IAAI,CAAC;wCACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;oCACrD,CAAC;oCAAC,MAAM,CAAC;wCACP,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,+BAA+B,QAAQ,GAAG,CAC3C,CAAC;oCACJ,CAAC;oCAED,2DAA2D;oCAC3D,MAAM,SAAS,GAAgB,EAAE,CAAC;oCAClC,KAAK,MAAM,CAAC,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC;wCACjD,SAAS,CAAC,IAAI,CAAC,KAAkB,CAAC,CAAC;oCACrC,CAAC;oCAED,qCAAqC;oCACrC,IAAI,MAAiB,CAAC;oCACtB,IAAI,MAAM,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;wCAC7B,qDAAqD;wCACrD,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,gDAAgD,CACjD,CAAC;oCACJ,CAAC;yCAAM,CAAC;wCACN,yCAAyC;wCACzC,MAAM,GAAG,MAAM,MAAM,CAAC,EAAE,CACtB,SAAS,EACT,GAAqB,EACrB,SAAS,CACV,CAAC;oCACJ,CAAC;oCAED,sCAAsC;oCACtC,iBAAiB,GAAG,CAAC,CAAC;oCAEtB,yBAAyB;oCACzB,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC;oCAChD,kBAAkB,CAAC,GAAqB,EAAE;wCACxC,KAAK,EAAE,oBAAoB;wCAC3B,SAAS,EAAE,kBAAkB;wCAC7B,SAAS,EAAE,QAAQ;wCACnB,QAAQ,EAAE,YAAY;qCACvB,CAAC,CAAC;oCAEH,+BAA+B;oCAC/B,OAAO;wCACL,YAAY,EAAE,UAAU;wCACxB,IAAI,EAAE,MAAe;wCACrB,OAAO,EACL,OAAO,MAAM,KAAK,QAAQ;4CACxB,CAAC,CAAC,MAAM;4CACR,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC;qCAC7B,CAAC;gCACJ,CAAC;gCAAC,OAAO,KAAc,EAAE,CAAC;oCACxB,iBAAiB,EAAE,CAAC;oCAEpB,uBAAuB;oCACvB,MAAM,YAAY,GAChB,KAAK,YAAY,YAAY;wCAC3B,CAAC,CAAC,KAAK,CAAC,OAAO;wCACf,CAAC,CAAC,KAAK,YAAY,KAAK;4CACtB,CAAC,CAAC,KAAK,CAAC,OAAO;4CACf,CAAC,CAAC,eAAe,CAAC;oCAExB,oCAAoC;oCACpC,MAAM,YAAY,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,aAAa,CAAC;oCAChD,kBAAkB,CAAC,GAAqB,EAAE;wCACxC,KAAK,EAAE,oBAAoB;wCAC3B,SAAS,EAAE,kBAAkB;wCAC7B,SAAS,EAAE,QAAQ;wCACnB,QAAQ,EAAE,YAAY;wCACtB,KAAK,EAAE,YAAY;qCACpB,CAAC,CAAC;oCAEH,sCAAsC;oCACtC,IAAI,iBAAiB,IAAI,SAAS,EAAE,CAAC;wCACnC,MAAM,IAAI,YAAY,CACpB,WAAW,EACX,2BAA2B,SAAS,qBAAqB,CAC1D,CAAC;oCACJ,CAAC;oCAED,qCAAqC;oCACrC,OAAO;wCACL,YAAY,EAAE,UAAU;wCACxB,IAAI,EAAE,MAAe;wCACrB,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC;4CACtB,KAAK,EAAE,YAAY;4CACnB,IAAI,EAAE,WAAW;yCAClB,CAAC;qCACH,CAAC;gCACJ,CAAC;4BACH,CAAC,CAAC,CACH,CAAC;4BAEF,mCAAmC;4BACnC,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gCACrC,oBAAoB,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;4BACxC,CAAC;4BAED,qCAAqC;4BACrC,SAAS;wBACX,CAAC;wBAED,iCAAiC;wBACjC,YAAY,GAAG,OAAO,CAAC,OAAO,IAAI,EAAE,CAAC;wBACrC,UAAU,GAAG,YAAY,IAAI,MAAM,CAAC;wBACpC,MAAM;oBACR,CAAC;oBAED,4BAA4B;oBAC5B,IAAI,KAAK,IAAI,QAAQ,IAAI,UAAU,KAAK,MAAM,EAAE,CAAC;wBAC/C,UAAU,GAAG,WAAW,CAAC;oBAC3B,CAAC;oBAED,0CAA0C;oBAC1C,MAAM,YAAY,GAAmC,EAAE,CAAC;oBACxD,KAAK,MAAM,GAAG,IAAI,oBAAoB,EAAE,CAAC;wBACvC,IAAI,GAAG,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;4BAC1B,kCAAkC;4BAClC,SAAS;wBACX,CAAC;wBACD,MAAM,UAAU,GAA4B;4BAC1C,IAAI,EAAE,GAAG,CAAC,IAAI;yBACf,CAAC;wBACF,IAAI,SAAS,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,EAAE,CAAC;4BACpC,UAAU,CAAC,SAAS,CAAC,GAAG,GAAG,CAAC,OAAO,CAAC;wBACtC,CAAC;wBACD,IAAI,YAAY,IAAI,GAAG,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;4BAC1C,UAAU,CAAC,YAAY,CAAC,GAAG,GAAG,CAAC,UAAU,CAAC;wBAC5C,CAAC;wBACD,YAAY,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;oBAChC,CAAC;oBAED,oBAAoB;oBACpB,MAAM,MAAM,GAAG;wBACb,OAAO,EAAE,YAAY;wBACrB,KAAK,EAAE,YAAY;wBACnB,KAAK,EAAE;4BACL,KAAK,EAAE,gBAAgB;4BACvB,MAAM,EAAE,iBAAiB;yBAC1B;wBACD,WAAW,EAAE,UAAU;wBACvB,KAAK;wBACL,QAAQ,EAAE,YAAY;qBACvB,CAAC;oBAEF,6BAA6B;oBAC7B,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,kBAAkB;wBACzB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK;wBACL,cAAc,EAAE,QAAQ;wBACxB,KAAK,EAAE,MAAM,CAAC,KAAK;qBACpB,CAAC,CAAC;oBAEH,OAAO,MAAmB,CAAC;gBAC7B,CAAC;gBAAC,OAAO,KAAc,EAAE,CAAC;oBACxB,mCAAmC;oBACnC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,CAAC;oBACxC,MAAM,SAAS,GAAG,cAAc,CAAC,KAAK,CAAC,CAAC;oBAExC,kBAAkB,CAAC,GAAqB,EAAE;wBACxC,KAAK,EAAE,cAAc;wBACrB,SAAS,EAAE,kBAAkB;wBAC7B,KAAK,EAAE,SAAS,CAAC,OAAO;wBACxB,QAAQ;qBACT,CAAC,CAAC;oBAEH,MAAM,SAAS,CAAC;gBAClB,CAAC;YACH,CAAC;YACD,WAAW,EAAE,uCAAuC;YACpD,UAAU,EAAE,MAAM;SACnB;KACF,CAAC;IAEF,yCAAyC;IACzC,MAAM,CAAC,OAAO,GAAG,OAAO,CAAC;IAEzB,OAAO,MAAM,CAAC;AAChB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rcrsr/rill-ext-openai
|
|
3
|
+
*
|
|
4
|
+
* Extension for OpenAI API integration with rill scripts.
|
|
5
|
+
*/
|
|
6
|
+
export declare const VERSION = "0.0.1";
|
|
7
|
+
export type { LLMExtensionConfig, OpenAIExtensionConfig } from './types.js';
|
|
8
|
+
export { createOpenAIExtension } from './factory.js';
|
|
9
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAMH,eAAO,MAAM,OAAO,UAAU,CAAC;AAM/B,YAAY,EAAE,kBAAkB,EAAE,qBAAqB,EAAE,MAAM,YAAY,CAAC;AAM5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @rcrsr/rill-ext-openai
|
|
3
|
+
*
|
|
4
|
+
* Extension for OpenAI API integration with rill scripts.
|
|
5
|
+
*/
|
|
6
|
+
// ============================================================
|
|
7
|
+
// VERSION
|
|
8
|
+
// ============================================================
|
|
9
|
+
export const VERSION = '0.0.1';
|
|
10
|
+
// ============================================================
|
|
11
|
+
// EXTENSION FACTORY
|
|
12
|
+
// ============================================================
|
|
13
|
+
export { createOpenAIExtension } from './factory.js';
|
|
14
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,+DAA+D;AAC/D,UAAU;AACV,+DAA+D;AAE/D,MAAM,CAAC,MAAM,OAAO,GAAG,OAAO,CAAC;AAQ/B,+DAA+D;AAC/D,oBAAoB;AACpB,+DAA+D;AAE/D,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Type definitions for OpenAI extension.
|
|
3
|
+
* Defines configuration, message types, and result structures.
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Base configuration interface for LLM extensions.
|
|
7
|
+
* Defines common fields across all LLM providers.
|
|
8
|
+
*/
|
|
9
|
+
export interface LLMExtensionConfig {
|
|
10
|
+
/** Model identifier (e.g., 'gpt-4-turbo') */
|
|
11
|
+
readonly model: string;
|
|
12
|
+
/** Temperature for response generation (0.0-2.0) */
|
|
13
|
+
readonly temperature?: number | undefined;
|
|
14
|
+
/** API key for authentication */
|
|
15
|
+
readonly api_key: string;
|
|
16
|
+
/** Custom base URL for API endpoint */
|
|
17
|
+
readonly base_url?: string | undefined;
|
|
18
|
+
/** Embedding model identifier for embed operations */
|
|
19
|
+
readonly embed_model?: string | undefined;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration options for OpenAI extension.
|
|
23
|
+
* Extends base LLM config with OpenAI-specific fields.
|
|
24
|
+
*/
|
|
25
|
+
export interface OpenAIExtensionConfig extends LLMExtensionConfig {
|
|
26
|
+
/** Maximum retry attempts for failed requests */
|
|
27
|
+
readonly max_retries?: number | undefined;
|
|
28
|
+
/** Request timeout in milliseconds */
|
|
29
|
+
readonly timeout?: number | undefined;
|
|
30
|
+
/** Maximum tokens in response */
|
|
31
|
+
readonly max_tokens?: number | undefined;
|
|
32
|
+
/** System prompt text */
|
|
33
|
+
readonly system?: string | undefined;
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IACjC,6CAA6C;IAC7C,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,oDAAoD;IACpD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,iCAAiC;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,uCAAuC;IACvC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACvC,sDAAsD;IACtD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC3C;AAED;;;GAGG;AACH,MAAM,WAAW,qBAAsB,SAAQ,kBAAkB;IAC/D,iDAAiD;IACjD,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1C,sCAAsC;IACtC,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,iCAAiC;IACjC,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACzC,yBAAyB;IACzB,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACtC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
package/package.json
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@rcrsr/rill-ext-openai",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "rill extension for OpenAI API integration",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"author": "Andre Bremer",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"main": "dist/index.js",
|
|
9
|
+
"types": "dist/index.d.ts",
|
|
10
|
+
"keywords": [
|
|
11
|
+
"rill",
|
|
12
|
+
"openai",
|
|
13
|
+
"gpt",
|
|
14
|
+
"llm",
|
|
15
|
+
"extension",
|
|
16
|
+
"ai",
|
|
17
|
+
"scripting"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "tsc --build",
|
|
21
|
+
"test": "vitest run",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"lint": "eslint --config ../../../eslint.config.js src/",
|
|
24
|
+
"check": "pnpm run build && pnpm run test && pnpm run lint"
|
|
25
|
+
},
|
|
26
|
+
"peerDependencies": {
|
|
27
|
+
"@rcrsr/rill": "workspace:^"
|
|
28
|
+
},
|
|
29
|
+
"devDependencies": {
|
|
30
|
+
"@rcrsr/rill": "workspace:^"
|
|
31
|
+
},
|
|
32
|
+
"files": [
|
|
33
|
+
"dist"
|
|
34
|
+
],
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/rcrsr/rill.git",
|
|
38
|
+
"directory": "packages/ext/openai"
|
|
39
|
+
},
|
|
40
|
+
"homepage": "https://github.com/rcrsr/rill/tree/main/packages/ext/openai#readme",
|
|
41
|
+
"bugs": {
|
|
42
|
+
"url": "https://github.com/rcrsr/rill/issues"
|
|
43
|
+
},
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"openai": "^6.18.0"
|
|
49
|
+
}
|
|
50
|
+
}
|