@effect/ai-openai 0.29.1 → 0.30.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/OpenAiTool/package.json +6 -0
- package/dist/cjs/Generated.js +5845 -4262
- package/dist/cjs/Generated.js.map +1 -1
- package/dist/cjs/OpenAiClient.js +1493 -129
- package/dist/cjs/OpenAiClient.js.map +1 -1
- package/dist/cjs/OpenAiEmbeddingModel.js +61 -50
- package/dist/cjs/OpenAiEmbeddingModel.js.map +1 -1
- package/dist/cjs/OpenAiLanguageModel.js +973 -333
- package/dist/cjs/OpenAiLanguageModel.js.map +1 -1
- package/dist/cjs/OpenAiTelemetry.js +4 -4
- package/dist/cjs/OpenAiTelemetry.js.map +1 -1
- package/dist/cjs/OpenAiTokenizer.js +46 -14
- package/dist/cjs/OpenAiTokenizer.js.map +1 -1
- package/dist/cjs/OpenAiTool.js +93 -0
- package/dist/cjs/OpenAiTool.js.map +1 -0
- package/dist/cjs/index.js +3 -1
- package/dist/cjs/internal/utilities.js +11 -3
- package/dist/cjs/internal/utilities.js.map +1 -1
- package/dist/dts/Generated.d.ts +19662 -11761
- package/dist/dts/Generated.d.ts.map +1 -1
- package/dist/dts/OpenAiClient.d.ts +3022 -14
- package/dist/dts/OpenAiClient.d.ts.map +1 -1
- package/dist/dts/OpenAiEmbeddingModel.d.ts +8 -8
- package/dist/dts/OpenAiEmbeddingModel.d.ts.map +1 -1
- package/dist/dts/OpenAiLanguageModel.d.ts +146 -49
- package/dist/dts/OpenAiLanguageModel.d.ts.map +1 -1
- package/dist/dts/OpenAiTelemetry.d.ts +4 -4
- package/dist/dts/OpenAiTelemetry.d.ts.map +1 -1
- package/dist/dts/OpenAiTokenizer.d.ts +1 -1
- package/dist/dts/OpenAiTokenizer.d.ts.map +1 -1
- package/dist/dts/OpenAiTool.d.ts +176 -0
- package/dist/dts/OpenAiTool.d.ts.map +1 -0
- package/dist/dts/index.d.ts +4 -0
- package/dist/dts/index.d.ts.map +1 -1
- package/dist/esm/Generated.js +5846 -12846
- package/dist/esm/Generated.js.map +1 -1
- package/dist/esm/OpenAiClient.js +1440 -128
- package/dist/esm/OpenAiClient.js.map +1 -1
- package/dist/esm/OpenAiEmbeddingModel.js +60 -49
- package/dist/esm/OpenAiEmbeddingModel.js.map +1 -1
- package/dist/esm/OpenAiLanguageModel.js +971 -330
- package/dist/esm/OpenAiLanguageModel.js.map +1 -1
- package/dist/esm/OpenAiTelemetry.js +4 -4
- package/dist/esm/OpenAiTelemetry.js.map +1 -1
- package/dist/esm/OpenAiTokenizer.js +46 -14
- package/dist/esm/OpenAiTokenizer.js.map +1 -1
- package/dist/esm/OpenAiTool.js +84 -0
- package/dist/esm/OpenAiTool.js.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/internal/utilities.js +10 -2
- package/dist/esm/internal/utilities.js.map +1 -1
- package/package.json +12 -4
- package/src/Generated.ts +9691 -5598
- package/src/OpenAiClient.ts +1761 -224
- package/src/OpenAiEmbeddingModel.ts +70 -62
- package/src/OpenAiLanguageModel.ts +1193 -377
- package/src/OpenAiTelemetry.ts +9 -9
- package/src/OpenAiTokenizer.ts +38 -39
- package/src/OpenAiTool.ts +110 -0
- package/src/index.ts +5 -0
- package/src/internal/utilities.ts +16 -4
|
@@ -3,33 +3,30 @@
|
|
|
3
3
|
Object.defineProperty(exports, "__esModule", {
|
|
4
4
|
value: true
|
|
5
5
|
});
|
|
6
|
-
exports.withConfigOverride = exports.modelWithTokenizer = exports.model = exports.make = exports.layerWithTokenizer = exports.layer = exports.
|
|
7
|
-
var
|
|
8
|
-
var
|
|
9
|
-
var
|
|
10
|
-
var
|
|
11
|
-
var
|
|
6
|
+
exports.withConfigOverride = exports.modelWithTokenizer = exports.model = exports.make = exports.layerWithTokenizer = exports.layer = exports.Config = void 0;
|
|
7
|
+
var AiError = _interopRequireWildcard(require("@effect/ai/AiError"));
|
|
8
|
+
var IdGenerator = _interopRequireWildcard(require("@effect/ai/IdGenerator"));
|
|
9
|
+
var LanguageModel = _interopRequireWildcard(require("@effect/ai/LanguageModel"));
|
|
10
|
+
var AiModel = _interopRequireWildcard(require("@effect/ai/Model"));
|
|
11
|
+
var Tool = _interopRequireWildcard(require("@effect/ai/Tool"));
|
|
12
12
|
var Context = _interopRequireWildcard(require("effect/Context"));
|
|
13
|
+
var DateTime = _interopRequireWildcard(require("effect/DateTime"));
|
|
13
14
|
var Effect = _interopRequireWildcard(require("effect/Effect"));
|
|
14
15
|
var Encoding = _interopRequireWildcard(require("effect/Encoding"));
|
|
15
16
|
var _Function = require("effect/Function");
|
|
16
17
|
var Layer = _interopRequireWildcard(require("effect/Layer"));
|
|
17
|
-
var Option = _interopRequireWildcard(require("effect/Option"));
|
|
18
18
|
var Predicate = _interopRequireWildcard(require("effect/Predicate"));
|
|
19
19
|
var Stream = _interopRequireWildcard(require("effect/Stream"));
|
|
20
|
-
var
|
|
21
|
-
var InternalUtilities = _utilities;
|
|
20
|
+
var InternalUtilities = _interopRequireWildcard(require("./internal/utilities.js"));
|
|
22
21
|
var _OpenAiClient = require("./OpenAiClient.js");
|
|
23
22
|
var _OpenAiTelemetry = require("./OpenAiTelemetry.js");
|
|
24
23
|
var OpenAiTokenizer = _interopRequireWildcard(require("./OpenAiTokenizer.js"));
|
|
24
|
+
var OpenAiTool = _interopRequireWildcard(require("./OpenAiTool.js"));
|
|
25
25
|
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
|
|
26
26
|
/**
|
|
27
27
|
* @since 1.0.0
|
|
28
28
|
*/
|
|
29
29
|
|
|
30
|
-
const constDisableValidation = {
|
|
31
|
-
disableValidation: true
|
|
32
|
-
};
|
|
33
30
|
// =============================================================================
|
|
34
31
|
// Configuration
|
|
35
32
|
// =============================================================================
|
|
@@ -44,32 +41,23 @@ class Config extends /*#__PURE__*/Context.Tag("@effect/ai-openai/OpenAiLanguageM
|
|
|
44
41
|
static getOrUndefined = /*#__PURE__*/Effect.map(/*#__PURE__*/Effect.context(), context => context.unsafeMap.get(Config.key));
|
|
45
42
|
}
|
|
46
43
|
// =============================================================================
|
|
47
|
-
//
|
|
44
|
+
// OpenAI Language Model
|
|
48
45
|
// =============================================================================
|
|
49
46
|
/**
|
|
50
47
|
* @since 1.0.0
|
|
51
|
-
* @category
|
|
48
|
+
* @category Ai Models
|
|
52
49
|
*/
|
|
53
50
|
exports.Config = Config;
|
|
54
|
-
|
|
55
|
-
// =============================================================================
|
|
56
|
-
// OpenAi Language Model
|
|
57
|
-
// =============================================================================
|
|
58
|
-
/**
|
|
59
|
-
* @since 1.0.0
|
|
60
|
-
* @category AiModel
|
|
61
|
-
*/
|
|
62
|
-
exports.ProviderMetadata = ProviderMetadata;
|
|
63
|
-
const model = (model, config) => AiModel.make(layer({
|
|
51
|
+
const model = (model, config) => AiModel.make("openai", layer({
|
|
64
52
|
model,
|
|
65
53
|
config
|
|
66
54
|
}));
|
|
67
55
|
/**
|
|
68
56
|
* @since 1.0.0
|
|
69
|
-
* @category
|
|
57
|
+
* @category Ai Models
|
|
70
58
|
*/
|
|
71
59
|
exports.model = model;
|
|
72
|
-
const modelWithTokenizer = (model, config) => AiModel.make(layerWithTokenizer({
|
|
60
|
+
const modelWithTokenizer = (model, config) => AiModel.make("openai", layerWithTokenizer({
|
|
73
61
|
model,
|
|
74
62
|
config
|
|
75
63
|
}));
|
|
@@ -80,87 +68,57 @@ const modelWithTokenizer = (model, config) => AiModel.make(layerWithTokenizer({
|
|
|
80
68
|
exports.modelWithTokenizer = modelWithTokenizer;
|
|
81
69
|
const make = exports.make = /*#__PURE__*/Effect.fnUntraced(function* (options) {
|
|
82
70
|
const client = yield* _OpenAiClient.OpenAiClient;
|
|
83
|
-
const makeRequest = Effect.fnUntraced(function* (
|
|
84
|
-
prompt,
|
|
85
|
-
system,
|
|
86
|
-
toolChoice,
|
|
87
|
-
tools
|
|
88
|
-
}) {
|
|
71
|
+
const makeRequest = Effect.fnUntraced(function* (providerOptions) {
|
|
89
72
|
const context = yield* Effect.context();
|
|
90
|
-
const
|
|
91
|
-
let tool_choice = undefined;
|
|
92
|
-
if (Predicate.isNotUndefined(toolChoice) && !useStructured && tools.length > 0) {
|
|
93
|
-
if (toolChoice === "auto" || toolChoice === "required") {
|
|
94
|
-
tool_choice = toolChoice;
|
|
95
|
-
} else if (typeof toolChoice === "object") {
|
|
96
|
-
tool_choice = {
|
|
97
|
-
type: "function",
|
|
98
|
-
function: {
|
|
99
|
-
name: toolChoice.tool
|
|
100
|
-
}
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
const messages = yield* makeMessages(method, system, prompt);
|
|
105
|
-
return {
|
|
73
|
+
const config = {
|
|
106
74
|
model: options.model,
|
|
107
75
|
...options.config,
|
|
108
|
-
...context.unsafeMap.get(Config.key)
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
tool_choice
|
|
76
|
+
...context.unsafeMap.get(Config.key)
|
|
77
|
+
};
|
|
78
|
+
const messages = yield* prepareMessages(providerOptions, config);
|
|
79
|
+
const {
|
|
80
|
+
toolChoice,
|
|
81
|
+
tools
|
|
82
|
+
} = yield* prepareTools(providerOptions);
|
|
83
|
+
const include = prepareInclude(providerOptions, config);
|
|
84
|
+
const responseFormat = prepareResponseFormat(providerOptions);
|
|
85
|
+
const verbosity = config.text?.verbosity;
|
|
86
|
+
const request = {
|
|
87
|
+
...config,
|
|
88
|
+
input: messages,
|
|
89
|
+
include,
|
|
90
|
+
text: {
|
|
91
|
+
format: responseFormat,
|
|
92
|
+
verbosity
|
|
93
|
+
},
|
|
94
|
+
tools,
|
|
95
|
+
tool_choice: toolChoice
|
|
129
96
|
};
|
|
97
|
+
return request;
|
|
130
98
|
});
|
|
131
|
-
return yield*
|
|
99
|
+
return yield* LanguageModel.make({
|
|
132
100
|
generateText: Effect.fnUntraced(function* (options) {
|
|
133
|
-
const
|
|
134
|
-
const request = yield* makeRequest("generateText", options);
|
|
101
|
+
const request = yield* makeRequest(options);
|
|
135
102
|
annotateRequest(options.span, request);
|
|
136
|
-
const rawResponse = yield* client.
|
|
137
|
-
|
|
138
|
-
|
|
103
|
+
const rawResponse = yield* client.createResponse(request);
|
|
104
|
+
annotateResponse(options.span, rawResponse);
|
|
105
|
+
return yield* makeResponse(rawResponse, options);
|
|
106
|
+
}),
|
|
107
|
+
streamText: Effect.fnUntraced(function* (options) {
|
|
108
|
+
const request = yield* makeRequest(options);
|
|
109
|
+
annotateRequest(options.span, request);
|
|
110
|
+
return client.createResponseStream(request);
|
|
111
|
+
}, (effect, options) => effect.pipe(Effect.flatMap(stream => makeStreamResponse(stream, options)), Stream.unwrap, Stream.map(response => {
|
|
112
|
+
annotateStreamResponse(options.span, response);
|
|
139
113
|
return response;
|
|
140
|
-
}
|
|
141
|
-
module: "OpenAiLanguageModel",
|
|
142
|
-
method: "generateText",
|
|
143
|
-
description: "An error occurred",
|
|
144
|
-
cause
|
|
145
|
-
}))),
|
|
146
|
-
streamText(options) {
|
|
147
|
-
return makeRequest("streamText", options).pipe(Effect.tap(request => annotateRequest(options.span, request)), Effect.map(client.stream), Stream.unwrap, Stream.map(response => {
|
|
148
|
-
annotateStreamResponse(options.span, response);
|
|
149
|
-
return response;
|
|
150
|
-
}), Stream.catchAll(cause => _AiError.AiError.is(cause) ? cause : new _AiError.AiError({
|
|
151
|
-
module: "OpenAiLanguageModel",
|
|
152
|
-
method: "streamText",
|
|
153
|
-
description: "An error occurred",
|
|
154
|
-
cause
|
|
155
|
-
})));
|
|
156
|
-
}
|
|
114
|
+
})))
|
|
157
115
|
});
|
|
158
116
|
});
|
|
159
117
|
/**
|
|
160
118
|
* @since 1.0.0
|
|
161
119
|
* @category Layers
|
|
162
120
|
*/
|
|
163
|
-
const layer = options => Layer.effect(
|
|
121
|
+
const layer = options => Layer.effect(LanguageModel.LanguageModel, make({
|
|
164
122
|
model: options.model,
|
|
165
123
|
config: options.config
|
|
166
124
|
}));
|
|
@@ -179,262 +137,817 @@ const withConfigOverride = exports.withConfigOverride = /*#__PURE__*/(0, _Functi
|
|
|
179
137
|
...config,
|
|
180
138
|
...overrides
|
|
181
139
|
})));
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
140
|
+
// =============================================================================
|
|
141
|
+
// Prompt Conversion
|
|
142
|
+
// =============================================================================
|
|
143
|
+
const getSystemMessageMode = model => model.startsWith("o") || model.startsWith("gpt-5") || model.startsWith("codex-") || model.startsWith("computer-use") ? "developer" : "system";
|
|
144
|
+
const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* (options, config) {
|
|
145
|
+
const messages = [];
|
|
146
|
+
for (const message of options.prompt.content) {
|
|
147
|
+
switch (message.role) {
|
|
148
|
+
case "system":
|
|
149
|
+
{
|
|
150
|
+
messages.push({
|
|
151
|
+
role: getSystemMessageMode(config.model),
|
|
152
|
+
content: message.content
|
|
153
|
+
});
|
|
154
|
+
break;
|
|
155
|
+
}
|
|
156
|
+
case "user":
|
|
193
157
|
{
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
switch (part.
|
|
198
|
-
case "
|
|
158
|
+
const content = [];
|
|
159
|
+
for (let index = 0; index < message.content.length; index++) {
|
|
160
|
+
const part = message.content[index];
|
|
161
|
+
switch (part.type) {
|
|
162
|
+
case "text":
|
|
199
163
|
{
|
|
200
|
-
|
|
164
|
+
content.push({
|
|
165
|
+
type: "input_text",
|
|
166
|
+
text: part.text
|
|
167
|
+
});
|
|
201
168
|
break;
|
|
202
169
|
}
|
|
203
|
-
case "
|
|
170
|
+
case "file":
|
|
204
171
|
{
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
172
|
+
if (part.mediaType.startsWith("image/")) {
|
|
173
|
+
const detail = getImageDetail(part);
|
|
174
|
+
const mediaType = part.mediaType === "image/*" ? "image/jpeg" : part.mediaType;
|
|
175
|
+
if (typeof part.data === "string" && isFileId(part.data, config)) {
|
|
176
|
+
content.push({
|
|
177
|
+
type: "input_image",
|
|
178
|
+
file_id: part.data,
|
|
179
|
+
detail
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
if (part.data instanceof URL) {
|
|
183
|
+
content.push({
|
|
184
|
+
type: "input_image",
|
|
185
|
+
image_url: part.data.toString(),
|
|
186
|
+
detail
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
if (part.data instanceof Uint8Array) {
|
|
190
|
+
const base64 = Encoding.encodeBase64(part.data);
|
|
191
|
+
const imageUrl = `data:${mediaType};base64,${base64}`;
|
|
192
|
+
content.push({
|
|
193
|
+
type: "input_image",
|
|
194
|
+
image_url: imageUrl,
|
|
195
|
+
detail
|
|
196
|
+
});
|
|
211
197
|
}
|
|
198
|
+
}
|
|
199
|
+
if (part.mediaType === "application/pdf") {
|
|
200
|
+
if (typeof part.data === "string" && isFileId(part.data, config)) {
|
|
201
|
+
content.push({
|
|
202
|
+
type: "input_file",
|
|
203
|
+
file_id: part.data
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
if (part.data instanceof URL) {
|
|
207
|
+
content.push({
|
|
208
|
+
type: "input_file",
|
|
209
|
+
file_url: part.data.toString()
|
|
210
|
+
});
|
|
211
|
+
}
|
|
212
|
+
if (part.data instanceof Uint8Array) {
|
|
213
|
+
const base64 = Encoding.encodeBase64(part.data);
|
|
214
|
+
const fileName = part.fileName ?? `part-${index}.pdf`;
|
|
215
|
+
const fileData = `data:application/pdf;base64,${base64}`;
|
|
216
|
+
content.push({
|
|
217
|
+
type: "input_file",
|
|
218
|
+
filename: fileName,
|
|
219
|
+
file_data: fileData
|
|
220
|
+
});
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
return yield* new AiError.MalformedInput({
|
|
224
|
+
module: "OpenAiLanguageModel",
|
|
225
|
+
method: "prepareMessages",
|
|
226
|
+
description: `Detected unsupported media type for file: '${part.mediaType}'`
|
|
212
227
|
});
|
|
213
|
-
break;
|
|
214
228
|
}
|
|
215
229
|
}
|
|
216
230
|
}
|
|
217
231
|
messages.push({
|
|
218
|
-
role: "
|
|
219
|
-
content
|
|
220
|
-
tool_calls: toolCalls.length > 0 ? toolCalls : undefined
|
|
232
|
+
role: "user",
|
|
233
|
+
content
|
|
221
234
|
});
|
|
222
235
|
break;
|
|
223
236
|
}
|
|
224
|
-
case "
|
|
237
|
+
case "assistant":
|
|
225
238
|
{
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
239
|
+
const reasoningMessages = {};
|
|
240
|
+
for (const part of message.content) {
|
|
241
|
+
switch (part.type) {
|
|
242
|
+
case "text":
|
|
243
|
+
{
|
|
244
|
+
messages.push({
|
|
245
|
+
role: "assistant",
|
|
246
|
+
content: [{
|
|
247
|
+
type: "output_text",
|
|
248
|
+
text: part.text
|
|
249
|
+
}],
|
|
250
|
+
id: getItemId(part)
|
|
251
|
+
});
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
case "reasoning":
|
|
255
|
+
{
|
|
256
|
+
const options = part.options.openai;
|
|
257
|
+
if (Predicate.isNotUndefined(options?.itemId)) {
|
|
258
|
+
const reasoningMessage = reasoningMessages[options.itemId];
|
|
259
|
+
const summaryParts = [];
|
|
260
|
+
if (part.text.length > 0) {
|
|
261
|
+
summaryParts.push({
|
|
262
|
+
type: "summary_text",
|
|
263
|
+
text: part.text
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
if (Predicate.isUndefined(reasoningMessage)) {
|
|
267
|
+
reasoningMessages[options.itemId] = {
|
|
268
|
+
id: options.itemId,
|
|
269
|
+
type: "reasoning",
|
|
270
|
+
summary: summaryParts,
|
|
271
|
+
encrypted_content: options.encryptedContent
|
|
272
|
+
};
|
|
273
|
+
messages.push(reasoningMessages[options.itemId]);
|
|
274
|
+
} else {
|
|
275
|
+
for (const summaryPart of summaryParts) {
|
|
276
|
+
reasoningMessage.summary.push(summaryPart);
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
break;
|
|
281
|
+
}
|
|
282
|
+
case "tool-call":
|
|
283
|
+
{
|
|
284
|
+
if (!part.providerExecuted) {
|
|
285
|
+
messages.push({
|
|
286
|
+
id: getItemId(part),
|
|
287
|
+
type: "function_call",
|
|
288
|
+
call_id: part.id,
|
|
289
|
+
name: part.name,
|
|
290
|
+
arguments: JSON.stringify(part.params)
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
break;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
232
296
|
}
|
|
233
297
|
break;
|
|
234
298
|
}
|
|
235
|
-
case "
|
|
299
|
+
case "tool":
|
|
236
300
|
{
|
|
237
|
-
|
|
238
|
-
if (message.parts.length === 1 && message.parts[0]._tag === "TextPart") {
|
|
301
|
+
for (const part of message.content) {
|
|
239
302
|
messages.push({
|
|
240
|
-
|
|
241
|
-
|
|
303
|
+
type: "function_call_output",
|
|
304
|
+
call_id: part.id,
|
|
305
|
+
result: JSON.stringify(part.result)
|
|
242
306
|
});
|
|
243
|
-
break;
|
|
244
307
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
return messages;
|
|
313
|
+
});
|
|
314
|
+
// =============================================================================
|
|
315
|
+
// Response Conversion
|
|
316
|
+
// =============================================================================
|
|
317
|
+
const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* (response, options) {
|
|
318
|
+
const idGenerator = yield* IdGenerator.IdGenerator;
|
|
319
|
+
const webSearchTool = options.tools.find(tool => Tool.isProviderDefined(tool) && (tool.id === "openai.web_search" || tool.id === "openai.web_search_preview"));
|
|
320
|
+
let hasToolCalls = false;
|
|
321
|
+
const parts = [];
|
|
322
|
+
const createdAt = new Date(response.created_at * 1000);
|
|
323
|
+
parts.push({
|
|
324
|
+
type: "response-metadata",
|
|
325
|
+
id: response.id,
|
|
326
|
+
modelId: response.model,
|
|
327
|
+
timestamp: DateTime.formatIso(DateTime.unsafeFromDate(createdAt))
|
|
328
|
+
});
|
|
329
|
+
for (const part of response.output) {
|
|
330
|
+
switch (part.type) {
|
|
331
|
+
case "message":
|
|
332
|
+
{
|
|
333
|
+
for (const contentPart of part.content) {
|
|
334
|
+
switch (contentPart.type) {
|
|
335
|
+
case "output_text":
|
|
251
336
|
{
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
input_audio: {
|
|
259
|
-
data,
|
|
260
|
-
format: "wav"
|
|
261
|
-
}
|
|
262
|
-
});
|
|
263
|
-
break;
|
|
264
|
-
}
|
|
265
|
-
case "audio/mp3":
|
|
266
|
-
case "audio/mpeg":
|
|
267
|
-
{
|
|
268
|
-
content.push({
|
|
269
|
-
type: "input_audio",
|
|
270
|
-
input_audio: {
|
|
271
|
-
data,
|
|
272
|
-
format: "mp3"
|
|
273
|
-
}
|
|
274
|
-
});
|
|
275
|
-
break;
|
|
276
|
-
}
|
|
277
|
-
case "application/pdf":
|
|
278
|
-
{
|
|
279
|
-
content.push({
|
|
280
|
-
type: "file",
|
|
281
|
-
file: {
|
|
282
|
-
filename: part.name ?? `part-${index}.pdf`,
|
|
283
|
-
file_data: `data:application/pdf;base64,${data}`
|
|
284
|
-
}
|
|
285
|
-
});
|
|
286
|
-
break;
|
|
287
|
-
}
|
|
288
|
-
default:
|
|
289
|
-
{
|
|
290
|
-
return yield* new _AiError.AiError({
|
|
291
|
-
module: "OpenAiLanguageModel",
|
|
292
|
-
method: "",
|
|
293
|
-
description: `OpenAi does not support file inputs of type "${part.mediaType}"`
|
|
294
|
-
});
|
|
337
|
+
parts.push({
|
|
338
|
+
type: "text",
|
|
339
|
+
text: contentPart.text,
|
|
340
|
+
metadata: {
|
|
341
|
+
openai: {
|
|
342
|
+
itemId: part.id
|
|
295
343
|
}
|
|
344
|
+
}
|
|
345
|
+
});
|
|
346
|
+
for (const annotation of contentPart.annotations) {
|
|
347
|
+
if (annotation.type === "file_citation") {
|
|
348
|
+
const metadata = {
|
|
349
|
+
type: annotation.type,
|
|
350
|
+
index: annotation.index
|
|
351
|
+
};
|
|
352
|
+
parts.push({
|
|
353
|
+
type: "source",
|
|
354
|
+
sourceType: "document",
|
|
355
|
+
id: yield* idGenerator.generateId(),
|
|
356
|
+
mediaType: "text/plain",
|
|
357
|
+
title: annotation.filename ?? "Untitled Document",
|
|
358
|
+
metadata: {
|
|
359
|
+
openai: metadata
|
|
360
|
+
}
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (annotation.type === "url_citation") {
|
|
364
|
+
const metadata = {
|
|
365
|
+
type: annotation.type,
|
|
366
|
+
startIndex: annotation.start_index,
|
|
367
|
+
endIndex: annotation.end_index
|
|
368
|
+
};
|
|
369
|
+
parts.push({
|
|
370
|
+
type: "source",
|
|
371
|
+
sourceType: "url",
|
|
372
|
+
id: yield* idGenerator.generateId(),
|
|
373
|
+
url: annotation.url,
|
|
374
|
+
title: annotation.title,
|
|
375
|
+
metadata: {
|
|
376
|
+
openai: metadata
|
|
377
|
+
}
|
|
378
|
+
});
|
|
379
|
+
}
|
|
296
380
|
}
|
|
297
381
|
break;
|
|
298
382
|
}
|
|
299
|
-
case "
|
|
383
|
+
case "refusal":
|
|
300
384
|
{
|
|
301
|
-
|
|
302
|
-
module: "OpenAiLanguageModel",
|
|
303
|
-
method,
|
|
304
|
-
description: "OpenAi does not support file content parts with URL data"
|
|
305
|
-
});
|
|
306
|
-
}
|
|
307
|
-
case "TextPart":
|
|
308
|
-
{
|
|
309
|
-
content.push({
|
|
385
|
+
parts.push({
|
|
310
386
|
type: "text",
|
|
311
|
-
text:
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
{
|
|
317
|
-
const mediaType = part.mediaType ?? "image/jpeg";
|
|
318
|
-
const base64 = Encoding.encodeBase64(part.data);
|
|
319
|
-
const url = `data:${mediaType};base64,${base64}`;
|
|
320
|
-
content.push({
|
|
321
|
-
type: "image_url",
|
|
322
|
-
image_url: {
|
|
323
|
-
url
|
|
387
|
+
text: "",
|
|
388
|
+
metadata: {
|
|
389
|
+
openai: {
|
|
390
|
+
refusal: contentPart.refusal
|
|
391
|
+
}
|
|
324
392
|
}
|
|
325
393
|
});
|
|
326
394
|
break;
|
|
327
395
|
}
|
|
328
|
-
case "ImageUrlPart":
|
|
329
|
-
{
|
|
330
|
-
// TODO: provider options
|
|
331
|
-
// const detail = part.providerOptions?.openai?.imageDetail as any
|
|
332
|
-
content.push({
|
|
333
|
-
type: "image_url",
|
|
334
|
-
image_url: {
|
|
335
|
-
url: part.url.toString()
|
|
336
|
-
}
|
|
337
|
-
});
|
|
338
|
-
}
|
|
339
396
|
}
|
|
340
397
|
}
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
398
|
+
break;
|
|
399
|
+
}
|
|
400
|
+
case "function_call":
|
|
401
|
+
{
|
|
402
|
+
hasToolCalls = true;
|
|
403
|
+
const toolName = part.name;
|
|
404
|
+
const toolParams = part.arguments;
|
|
405
|
+
const params = yield* Effect.try({
|
|
406
|
+
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
407
|
+
catch: cause => new AiError.MalformedOutput({
|
|
408
|
+
module: "OpenAiLanguageModel",
|
|
409
|
+
method: "makeResponse",
|
|
410
|
+
description: "Failed to securely parse tool call parameters " + `for tool '${toolName}':\nParameters: ${toolParams}`,
|
|
411
|
+
cause
|
|
412
|
+
})
|
|
413
|
+
});
|
|
414
|
+
parts.push({
|
|
415
|
+
type: "tool-call",
|
|
416
|
+
id: part.call_id,
|
|
417
|
+
name: toolName,
|
|
418
|
+
params,
|
|
419
|
+
metadata: {
|
|
420
|
+
openai: {
|
|
421
|
+
itemId: part.id
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
break;
|
|
426
|
+
}
|
|
427
|
+
case "code_interpreter_call":
|
|
428
|
+
{
|
|
429
|
+
parts.push({
|
|
430
|
+
type: "tool-call",
|
|
431
|
+
id: part.id,
|
|
432
|
+
name: "OpenAiCodeInterpreter",
|
|
433
|
+
params: {
|
|
434
|
+
code: part.code,
|
|
435
|
+
container_id: part.container_id
|
|
436
|
+
},
|
|
437
|
+
providerName: "code_interpreter",
|
|
438
|
+
providerExecuted: true
|
|
439
|
+
});
|
|
440
|
+
parts.push({
|
|
441
|
+
type: "tool-result",
|
|
442
|
+
id: part.id,
|
|
443
|
+
name: "OpenAiCodeInterpreter",
|
|
444
|
+
result: {
|
|
445
|
+
outputs: part.outputs
|
|
446
|
+
},
|
|
447
|
+
providerName: "code_interpreter",
|
|
448
|
+
providerExecuted: true
|
|
449
|
+
});
|
|
450
|
+
break;
|
|
451
|
+
}
|
|
452
|
+
case "file_search_call":
|
|
453
|
+
{
|
|
454
|
+
parts.push({
|
|
455
|
+
type: "tool-call",
|
|
456
|
+
id: part.id,
|
|
457
|
+
name: "OpenAiFileSearch",
|
|
458
|
+
params: {},
|
|
459
|
+
providerName: "file_search",
|
|
460
|
+
providerExecuted: true
|
|
461
|
+
});
|
|
462
|
+
parts.push({
|
|
463
|
+
type: "tool-result",
|
|
464
|
+
id: part.id,
|
|
465
|
+
name: "OpenAiFileSearch",
|
|
466
|
+
result: {
|
|
467
|
+
status: part.status,
|
|
468
|
+
queries: part.queries,
|
|
469
|
+
...(part.results && {
|
|
470
|
+
results: part.results
|
|
471
|
+
})
|
|
472
|
+
},
|
|
473
|
+
providerName: "file_search",
|
|
474
|
+
providerExecuted: true
|
|
475
|
+
});
|
|
476
|
+
break;
|
|
477
|
+
}
|
|
478
|
+
case "web_search_call":
|
|
479
|
+
{
|
|
480
|
+
parts.push({
|
|
481
|
+
type: "tool-call",
|
|
482
|
+
id: part.id,
|
|
483
|
+
name: webSearchTool?.name ?? "OpenAiWebSearch",
|
|
484
|
+
params: {
|
|
485
|
+
action: part.action
|
|
486
|
+
},
|
|
487
|
+
providerName: webSearchTool?.providerName ?? "web_search",
|
|
488
|
+
providerExecuted: true
|
|
489
|
+
});
|
|
490
|
+
parts.push({
|
|
491
|
+
type: "tool-result",
|
|
492
|
+
id: part.id,
|
|
493
|
+
name: webSearchTool?.name ?? "OpenAiWebSearch",
|
|
494
|
+
result: {
|
|
495
|
+
status: part.status
|
|
496
|
+
},
|
|
497
|
+
providerName: webSearchTool?.providerName ?? "web_search",
|
|
498
|
+
providerExecuted: true
|
|
499
|
+
});
|
|
500
|
+
break;
|
|
501
|
+
}
|
|
502
|
+
// TODO(Max): support computer use
|
|
503
|
+
// case "computer_call": {
|
|
504
|
+
// parts.push({
|
|
505
|
+
// type: "tool-call",
|
|
506
|
+
// id: part.id,
|
|
507
|
+
// name: "OpenAiComputerUse",
|
|
508
|
+
// params: { action: part.action },
|
|
509
|
+
// providerName: webSearchTool?.providerName ?? "web_search",
|
|
510
|
+
// providerExecuted: true
|
|
511
|
+
// })
|
|
512
|
+
//
|
|
513
|
+
// parts.push({
|
|
514
|
+
// type: "tool-result",
|
|
515
|
+
// id: part.id,
|
|
516
|
+
// name: webSearchTool?.name ?? "OpenAiWebSearch",
|
|
517
|
+
// result: { status: part.status },
|
|
518
|
+
// providerName: webSearchTool?.providerName ?? "web_search",
|
|
519
|
+
// providerExecuted: true
|
|
520
|
+
// })
|
|
521
|
+
// break
|
|
522
|
+
// }
|
|
523
|
+
case "reasoning":
|
|
524
|
+
{
|
|
525
|
+
// If there are no summary parts, we have to add an empty one to
|
|
526
|
+
// propagate the part identifier
|
|
527
|
+
if (part.summary.length === 0) {
|
|
528
|
+
parts.push({
|
|
529
|
+
type: "reasoning",
|
|
530
|
+
text: "",
|
|
531
|
+
metadata: {
|
|
532
|
+
openai: {
|
|
533
|
+
itemId: part.id
|
|
534
|
+
}
|
|
535
|
+
}
|
|
346
536
|
});
|
|
537
|
+
} else {
|
|
538
|
+
for (const summary of part.summary) {
|
|
539
|
+
const metadata = {
|
|
540
|
+
itemId: part.id,
|
|
541
|
+
encryptedContent: part.encrypted_content ?? undefined
|
|
542
|
+
};
|
|
543
|
+
parts.push({
|
|
544
|
+
type: "reasoning",
|
|
545
|
+
text: summary.text,
|
|
546
|
+
metadata: {
|
|
547
|
+
openai: metadata
|
|
548
|
+
}
|
|
549
|
+
});
|
|
550
|
+
}
|
|
347
551
|
}
|
|
348
552
|
break;
|
|
349
553
|
}
|
|
350
554
|
}
|
|
351
555
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
556
|
+
const finishReason = InternalUtilities.resolveFinishReason(response.incomplete_details?.reason, hasToolCalls);
|
|
557
|
+
const metadata = {
|
|
558
|
+
serviceTier: response.service_tier
|
|
559
|
+
};
|
|
560
|
+
parts.push({
|
|
561
|
+
type: "finish",
|
|
562
|
+
reason: finishReason,
|
|
563
|
+
usage: {
|
|
564
|
+
inputTokens: response.usage?.input_tokens,
|
|
565
|
+
outputTokens: response.usage?.output_tokens,
|
|
566
|
+
totalTokens: (response.usage?.input_tokens ?? 0) + (response.usage?.output_tokens ?? 0),
|
|
567
|
+
reasoningTokens: response.usage?.output_tokens_details?.reasoning_tokens,
|
|
568
|
+
cachedInputTokens: response.usage?.input_tokens_details?.cached_tokens
|
|
569
|
+
},
|
|
570
|
+
metadata: {
|
|
571
|
+
openai: metadata
|
|
572
|
+
}
|
|
359
573
|
});
|
|
574
|
+
return parts;
|
|
360
575
|
});
|
|
361
|
-
const
|
|
362
|
-
const
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
576
|
+
const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* (stream, options) {
|
|
577
|
+
const idGenerator = yield* IdGenerator.IdGenerator;
|
|
578
|
+
let hasToolCalls = false;
|
|
579
|
+
const activeReasoning = {};
|
|
580
|
+
const activeToolCalls = {};
|
|
581
|
+
const webSearchTool = options.tools.find(tool => Tool.isProviderDefined(tool) && (tool.id === "openai.web_search" || tool.id === "openai.web_search_preview"));
|
|
582
|
+
return stream.pipe(Stream.mapEffect(Effect.fnUntraced(function* (event) {
|
|
583
|
+
const parts = [];
|
|
584
|
+
switch (event.type) {
|
|
585
|
+
case "response.created":
|
|
586
|
+
{
|
|
587
|
+
const createdAt = new Date(event.response.created_at * 1000);
|
|
588
|
+
parts.push({
|
|
589
|
+
type: "response-metadata",
|
|
590
|
+
id: event.response.id,
|
|
591
|
+
modelId: event.response.model,
|
|
592
|
+
timestamp: DateTime.formatIso(DateTime.unsafeFromDate(createdAt))
|
|
593
|
+
});
|
|
594
|
+
break;
|
|
595
|
+
}
|
|
596
|
+
case "error":
|
|
597
|
+
{
|
|
598
|
+
parts.push({
|
|
599
|
+
type: "error",
|
|
600
|
+
error: event
|
|
601
|
+
});
|
|
602
|
+
break;
|
|
603
|
+
}
|
|
604
|
+
case "response.completed":
|
|
605
|
+
case "response.incomplete":
|
|
606
|
+
case "response.failed":
|
|
607
|
+
{
|
|
608
|
+
parts.push({
|
|
609
|
+
type: "finish",
|
|
610
|
+
reason: InternalUtilities.resolveFinishReason(event.response.incomplete_details?.reason, hasToolCalls),
|
|
611
|
+
usage: {
|
|
612
|
+
inputTokens: event.response.usage?.input_tokens,
|
|
613
|
+
outputTokens: event.response.usage?.output_tokens,
|
|
614
|
+
totalTokens: (event.response.usage?.input_tokens ?? 0) + (event.response.usage?.output_tokens ?? 0),
|
|
615
|
+
reasoningTokens: event.response.usage?.output_tokens_details?.reasoning_tokens,
|
|
616
|
+
cachedInputTokens: event.response.usage?.input_tokens_details?.cached_tokens
|
|
617
|
+
},
|
|
618
|
+
metadata: {
|
|
619
|
+
openai: {
|
|
620
|
+
serviceTier: event.response.service_tier
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
});
|
|
624
|
+
break;
|
|
625
|
+
}
|
|
626
|
+
case "response.output_item.added":
|
|
627
|
+
{
|
|
628
|
+
switch (event.item.type) {
|
|
629
|
+
case "computer_call":
|
|
630
|
+
{
|
|
631
|
+
// TODO(Max): support computer use
|
|
632
|
+
break;
|
|
633
|
+
}
|
|
634
|
+
case "file_search_call":
|
|
635
|
+
{
|
|
636
|
+
activeToolCalls[event.output_index] = {
|
|
637
|
+
id: event.item.id,
|
|
638
|
+
name: "OpenAiFileSearch"
|
|
639
|
+
};
|
|
640
|
+
parts.push({
|
|
641
|
+
type: "tool-params-start",
|
|
642
|
+
id: event.item.id,
|
|
643
|
+
name: "OpenAiFileSearch",
|
|
644
|
+
providerName: "file_search",
|
|
645
|
+
providerExecuted: true
|
|
646
|
+
});
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
649
|
+
case "function_call":
|
|
650
|
+
{
|
|
651
|
+
activeToolCalls[event.output_index] = {
|
|
652
|
+
id: event.item.call_id,
|
|
653
|
+
name: event.item.name
|
|
654
|
+
};
|
|
655
|
+
parts.push({
|
|
656
|
+
type: "tool-params-start",
|
|
657
|
+
id: event.item.call_id,
|
|
658
|
+
name: event.item.name
|
|
659
|
+
});
|
|
660
|
+
break;
|
|
661
|
+
}
|
|
662
|
+
case "message":
|
|
663
|
+
{
|
|
664
|
+
parts.push({
|
|
665
|
+
type: "text-start",
|
|
666
|
+
id: event.item.id,
|
|
667
|
+
metadata: {
|
|
668
|
+
openai: {
|
|
669
|
+
itemId: event.item.id
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
});
|
|
673
|
+
break;
|
|
674
|
+
}
|
|
675
|
+
case "reasoning":
|
|
676
|
+
{
|
|
677
|
+
activeReasoning[event.item.id] = {
|
|
678
|
+
summaryParts: [0],
|
|
679
|
+
encryptedContent: event.item.encrypted_content
|
|
680
|
+
};
|
|
681
|
+
parts.push({
|
|
682
|
+
type: "reasoning-start",
|
|
683
|
+
id: `${event.item.id}:0`,
|
|
684
|
+
metadata: {
|
|
685
|
+
openai: {
|
|
686
|
+
itemId: event.item.id,
|
|
687
|
+
encryptedContent: event.item.encrypted_content
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
});
|
|
691
|
+
break;
|
|
692
|
+
}
|
|
693
|
+
case "web_search_call":
|
|
694
|
+
{
|
|
695
|
+
activeToolCalls[event.output_index] = {
|
|
696
|
+
id: event.item.id,
|
|
697
|
+
name: webSearchTool?.name ?? "OpenAiWebSearch"
|
|
698
|
+
};
|
|
699
|
+
parts.push({
|
|
700
|
+
type: "tool-params-start",
|
|
701
|
+
id: event.item.id,
|
|
702
|
+
name: webSearchTool?.name ?? "OpenAiWebSearch",
|
|
703
|
+
providerName: webSearchTool?.providerName ?? "web_search",
|
|
704
|
+
providerExecuted: true
|
|
705
|
+
});
|
|
706
|
+
break;
|
|
707
|
+
}
|
|
708
|
+
}
|
|
709
|
+
break;
|
|
710
|
+
}
|
|
711
|
+
case "response.output_item.done":
|
|
712
|
+
{
|
|
713
|
+
switch (event.item.type) {
|
|
714
|
+
case "code_interpreter_call":
|
|
715
|
+
{
|
|
716
|
+
parts.push({
|
|
717
|
+
type: "tool-call",
|
|
718
|
+
id: event.item.id,
|
|
719
|
+
name: "OpenAiCodeInterpreter",
|
|
720
|
+
params: {
|
|
721
|
+
code: event.item.code,
|
|
722
|
+
container_id: event.item.container_id
|
|
723
|
+
},
|
|
724
|
+
providerName: "code_interpreter",
|
|
725
|
+
providerExecuted: true
|
|
726
|
+
});
|
|
727
|
+
parts.push({
|
|
728
|
+
type: "tool-result",
|
|
729
|
+
id: event.item.id,
|
|
730
|
+
name: "OpenAiCodeInterpreter",
|
|
731
|
+
result: {
|
|
732
|
+
outputs: event.item.outputs
|
|
733
|
+
},
|
|
734
|
+
providerName: "code_interpreter",
|
|
735
|
+
providerExecuted: true
|
|
736
|
+
});
|
|
737
|
+
break;
|
|
738
|
+
}
|
|
739
|
+
// TODO(Max): support computer use
|
|
740
|
+
case "computer_call":
|
|
741
|
+
{
|
|
742
|
+
break;
|
|
743
|
+
}
|
|
744
|
+
case "file_search_call":
|
|
745
|
+
{
|
|
746
|
+
delete activeToolCalls[event.output_index];
|
|
747
|
+
parts.push({
|
|
748
|
+
type: "tool-params-end",
|
|
749
|
+
id: event.item.id
|
|
750
|
+
});
|
|
751
|
+
parts.push({
|
|
752
|
+
type: "tool-call",
|
|
753
|
+
id: event.item.id,
|
|
754
|
+
name: "OpenAiFileSearch",
|
|
755
|
+
params: {},
|
|
756
|
+
providerName: "file_search",
|
|
757
|
+
providerExecuted: true
|
|
758
|
+
});
|
|
759
|
+
parts.push({
|
|
760
|
+
type: "tool-result",
|
|
761
|
+
id: event.item.id,
|
|
762
|
+
name: "OpenAiFileSearch",
|
|
763
|
+
result: {
|
|
764
|
+
status: event.item.status,
|
|
765
|
+
queries: event.item.queries,
|
|
766
|
+
...(event.item.results && {
|
|
767
|
+
results: event.item.results
|
|
768
|
+
})
|
|
769
|
+
},
|
|
770
|
+
providerName: "file_search",
|
|
771
|
+
providerExecuted: true
|
|
772
|
+
});
|
|
773
|
+
break;
|
|
774
|
+
}
|
|
775
|
+
case "function_call":
|
|
776
|
+
{
|
|
777
|
+
hasToolCalls = true;
|
|
778
|
+
const toolName = event.item.name;
|
|
779
|
+
const toolParams = event.item.arguments;
|
|
780
|
+
const params = yield* Effect.try({
|
|
781
|
+
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
782
|
+
catch: cause => new AiError.MalformedOutput({
|
|
783
|
+
module: "OpenAiLanguageModel",
|
|
784
|
+
method: "makeStreamResponse",
|
|
785
|
+
description: "Failed to securely parse tool call parameters " + `for tool '${toolName}':\nParameters: ${toolParams}`,
|
|
786
|
+
cause
|
|
787
|
+
})
|
|
788
|
+
});
|
|
789
|
+
parts.push({
|
|
790
|
+
type: "tool-params-end",
|
|
791
|
+
id: event.item.call_id
|
|
792
|
+
});
|
|
793
|
+
parts.push({
|
|
794
|
+
type: "tool-call",
|
|
795
|
+
id: event.item.call_id,
|
|
796
|
+
name: toolName,
|
|
797
|
+
params,
|
|
798
|
+
metadata: {
|
|
799
|
+
openai: {
|
|
800
|
+
itemId: event.item.id
|
|
801
|
+
}
|
|
802
|
+
}
|
|
803
|
+
});
|
|
804
|
+
delete activeToolCalls[event.output_index];
|
|
805
|
+
break;
|
|
806
|
+
}
|
|
807
|
+
case "message":
|
|
808
|
+
{
|
|
809
|
+
parts.push({
|
|
810
|
+
type: "text-end",
|
|
811
|
+
id: event.item.id
|
|
812
|
+
});
|
|
813
|
+
break;
|
|
814
|
+
}
|
|
815
|
+
case "reasoning":
|
|
816
|
+
{
|
|
817
|
+
const reasoningPart = activeReasoning[event.item.id];
|
|
818
|
+
for (const summaryIndex of reasoningPart.summaryParts) {
|
|
819
|
+
parts.push({
|
|
820
|
+
type: "reasoning-end",
|
|
821
|
+
id: `${event.item.id}:${summaryIndex}`,
|
|
822
|
+
metadata: {
|
|
823
|
+
openai: {
|
|
824
|
+
itemId: event.item.id,
|
|
825
|
+
encryptedContent: event.item.encrypted_content
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
}
|
|
830
|
+
delete activeReasoning[event.item.id];
|
|
831
|
+
break;
|
|
832
|
+
}
|
|
833
|
+
case "web_search_call":
|
|
834
|
+
{
|
|
835
|
+
delete activeToolCalls[event.output_index];
|
|
836
|
+
parts.push({
|
|
837
|
+
type: "tool-params-end",
|
|
838
|
+
id: event.item.id
|
|
839
|
+
});
|
|
840
|
+
parts.push({
|
|
841
|
+
type: "tool-call",
|
|
842
|
+
id: event.item.id,
|
|
843
|
+
name: "OpenAiWebSearch",
|
|
844
|
+
params: {
|
|
845
|
+
action: event.item.action
|
|
846
|
+
},
|
|
847
|
+
providerName: "web_search",
|
|
848
|
+
providerExecuted: true
|
|
849
|
+
});
|
|
850
|
+
parts.push({
|
|
851
|
+
type: "tool-result",
|
|
852
|
+
id: event.item.id,
|
|
853
|
+
name: "OpenAiWebSearch",
|
|
854
|
+
result: {
|
|
855
|
+
status: event.item.status
|
|
856
|
+
},
|
|
857
|
+
providerName: "web_search",
|
|
858
|
+
providerExecuted: true
|
|
859
|
+
});
|
|
860
|
+
break;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
863
|
+
break;
|
|
864
|
+
}
|
|
865
|
+
case "response.output_text.delta":
|
|
866
|
+
{
|
|
867
|
+
parts.push({
|
|
868
|
+
type: "text-delta",
|
|
869
|
+
id: event.item_id,
|
|
870
|
+
delta: event.delta
|
|
871
|
+
});
|
|
872
|
+
break;
|
|
873
|
+
}
|
|
874
|
+
case "response.output_text.annotation.added":
|
|
875
|
+
{
|
|
876
|
+
if (event.annotation.type === "file_citation") {
|
|
877
|
+
parts.push({
|
|
878
|
+
type: "source",
|
|
879
|
+
sourceType: "document",
|
|
880
|
+
id: yield* idGenerator.generateId(),
|
|
881
|
+
mediaType: "text/plain",
|
|
882
|
+
title: event.annotation.filename ?? "Untitled Document",
|
|
883
|
+
fileName: event.annotation.filename ?? event.annotation.file_id
|
|
884
|
+
});
|
|
885
|
+
}
|
|
886
|
+
if (event.annotation.type === "url_citation") {
|
|
887
|
+
parts.push({
|
|
888
|
+
type: "source",
|
|
889
|
+
sourceType: "url",
|
|
890
|
+
id: yield* idGenerator.generateId(),
|
|
891
|
+
url: event.annotation.url,
|
|
892
|
+
title: event.annotation.title
|
|
893
|
+
});
|
|
894
|
+
}
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
case "response.function_call_arguments.delta":
|
|
898
|
+
{
|
|
899
|
+
const toolCallPart = activeToolCalls[event.output_index];
|
|
900
|
+
if (Predicate.isNotUndefined(toolCallPart)) {
|
|
901
|
+
parts.push({
|
|
902
|
+
type: "tool-params-delta",
|
|
903
|
+
id: toolCallPart.id,
|
|
904
|
+
delta: event.delta
|
|
905
|
+
});
|
|
906
|
+
}
|
|
907
|
+
break;
|
|
908
|
+
}
|
|
909
|
+
case "response.reasoning_summary_part.added":
|
|
910
|
+
{
|
|
911
|
+
// The first reasoning start is pushed in the `response.output_item.added` block
|
|
912
|
+
if (event.summary_index > 0) {
|
|
913
|
+
const reasoningPart = activeReasoning[event.item_id];
|
|
914
|
+
if (Predicate.isNotUndefined(reasoningPart)) {
|
|
915
|
+
reasoningPart.summaryParts.push(event.summary_index);
|
|
916
|
+
}
|
|
917
|
+
parts.push({
|
|
918
|
+
type: "reasoning-start",
|
|
919
|
+
id: `${event.item_id}:${event.summary_index}`,
|
|
920
|
+
metadata: {
|
|
921
|
+
openai: {
|
|
922
|
+
itemId: event.item_id,
|
|
923
|
+
encryptedContent: reasoningPart?.encryptedContent
|
|
924
|
+
}
|
|
925
|
+
}
|
|
926
|
+
});
|
|
927
|
+
}
|
|
928
|
+
break;
|
|
929
|
+
}
|
|
930
|
+
case "response.reasoning_summary_text.delta":
|
|
931
|
+
{
|
|
932
|
+
parts.push({
|
|
933
|
+
type: "reasoning-delta",
|
|
934
|
+
id: `${event.item_id}:${event.summary_index}`,
|
|
935
|
+
delta: event.delta,
|
|
936
|
+
metadata: {
|
|
937
|
+
openai: {
|
|
938
|
+
itemId: event.item_id
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
});
|
|
942
|
+
break;
|
|
943
|
+
}
|
|
412
944
|
}
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
parts.push(new AiResponse.TextPart({
|
|
416
|
-
text: choice.message.content
|
|
417
|
-
}, constDisableValidation));
|
|
418
|
-
}
|
|
419
|
-
const output = new AiResponse.AiResponse({
|
|
420
|
-
parts
|
|
421
|
-
}, constDisableValidation);
|
|
422
|
-
if (Predicate.isNotUndefined(structuredTool)) {
|
|
423
|
-
return yield* AiResponse.withToolCallsJson(output, [{
|
|
424
|
-
id: response.id,
|
|
425
|
-
name: structuredTool.name,
|
|
426
|
-
params: choice.message.content
|
|
427
|
-
}]);
|
|
428
|
-
}
|
|
429
|
-
if (Predicate.isNotUndefined(choice.message.tool_calls) && choice.message.tool_calls.length > 0) {
|
|
430
|
-
return yield* AiResponse.withToolCallsJson(output, choice.message.tool_calls.map(tool => ({
|
|
431
|
-
id: tool.id,
|
|
432
|
-
name: tool.function.name,
|
|
433
|
-
params: tool.function.arguments
|
|
434
|
-
})));
|
|
435
|
-
}
|
|
436
|
-
return output;
|
|
945
|
+
return parts;
|
|
946
|
+
})), Stream.flattenIterables);
|
|
437
947
|
});
|
|
948
|
+
// =============================================================================
|
|
949
|
+
// Telemetry
|
|
950
|
+
// =============================================================================
|
|
438
951
|
const annotateRequest = (span, request) => {
|
|
439
952
|
(0, _OpenAiTelemetry.addGenAIAnnotations)(span, {
|
|
440
953
|
system: "openai",
|
|
@@ -445,59 +958,186 @@ const annotateRequest = (span, request) => {
|
|
|
445
958
|
model: request.model,
|
|
446
959
|
temperature: request.temperature,
|
|
447
960
|
topP: request.top_p,
|
|
448
|
-
maxTokens: request.
|
|
449
|
-
stopSequences: Arr.ensure(request.stop).filter(Predicate.isNotNullable),
|
|
450
|
-
frequencyPenalty: request.frequency_penalty,
|
|
451
|
-
presencePenalty: request.presence_penalty,
|
|
452
|
-
seed: request.seed
|
|
961
|
+
maxTokens: request.max_output_tokens
|
|
453
962
|
},
|
|
454
963
|
openai: {
|
|
455
964
|
request: {
|
|
456
|
-
responseFormat: request.
|
|
965
|
+
responseFormat: request.text?.format?.type,
|
|
457
966
|
serviceTier: request.service_tier
|
|
458
967
|
}
|
|
459
968
|
}
|
|
460
969
|
});
|
|
461
970
|
};
|
|
462
|
-
const
|
|
971
|
+
const annotateResponse = (span, response) => {
|
|
972
|
+
const finishReason = response.incomplete_details?.reason;
|
|
463
973
|
(0, _OpenAiTelemetry.addGenAIAnnotations)(span, {
|
|
464
974
|
response: {
|
|
465
975
|
id: response.id,
|
|
466
976
|
model: response.model,
|
|
467
|
-
finishReasons:
|
|
977
|
+
finishReasons: Predicate.isNotUndefined(finishReason) ? [finishReason] : undefined
|
|
468
978
|
},
|
|
469
979
|
usage: {
|
|
470
|
-
inputTokens: response.usage?.
|
|
471
|
-
outputTokens: response.usage?.
|
|
980
|
+
inputTokens: response.usage?.input_tokens,
|
|
981
|
+
outputTokens: response.usage?.output_tokens
|
|
472
982
|
},
|
|
473
983
|
openai: {
|
|
474
984
|
response: {
|
|
475
|
-
systemFingerprint: response.system_fingerprint,
|
|
476
985
|
serviceTier: response.service_tier
|
|
477
986
|
}
|
|
478
987
|
}
|
|
479
988
|
});
|
|
480
989
|
};
|
|
481
|
-
const annotateStreamResponse = (span,
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
outputTokens: finishPart?.usage.outputTokens
|
|
494
|
-
},
|
|
495
|
-
openai: {
|
|
990
|
+
const annotateStreamResponse = (span, part) => {
|
|
991
|
+
if (part.type === "response-metadata") {
|
|
992
|
+
(0, _OpenAiTelemetry.addGenAIAnnotations)(span, {
|
|
993
|
+
response: {
|
|
994
|
+
id: part.id,
|
|
995
|
+
model: part.modelId
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
}
|
|
999
|
+
if (part.type === "finish") {
|
|
1000
|
+
const serviceTier = part.metadata?.openai?.serviceTier;
|
|
1001
|
+
(0, _OpenAiTelemetry.addGenAIAnnotations)(span, {
|
|
496
1002
|
response: {
|
|
497
|
-
|
|
498
|
-
|
|
1003
|
+
finishReasons: [part.reason]
|
|
1004
|
+
},
|
|
1005
|
+
usage: {
|
|
1006
|
+
inputTokens: part.usage.inputTokens,
|
|
1007
|
+
outputTokens: part.usage.outputTokens
|
|
1008
|
+
},
|
|
1009
|
+
openai: {
|
|
1010
|
+
response: {
|
|
1011
|
+
serviceTier
|
|
1012
|
+
}
|
|
1013
|
+
}
|
|
1014
|
+
});
|
|
1015
|
+
}
|
|
1016
|
+
};
|
|
1017
|
+
const prepareTools = /*#__PURE__*/Effect.fnUntraced(function* (options) {
|
|
1018
|
+
// Return immediately if no tools are in the toolkit
|
|
1019
|
+
if (options.tools.length === 0) {
|
|
1020
|
+
return {
|
|
1021
|
+
tools: undefined,
|
|
1022
|
+
toolChoice: undefined
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
const tools = [];
|
|
1026
|
+
let toolChoice = undefined;
|
|
1027
|
+
// Filter the incoming tools down to the set of allowed tools as indicated by
|
|
1028
|
+
// the tool choice. This must be done here given that there is no tool name
|
|
1029
|
+
// in OpenAI's provider-defined tools, so there would be no way to perform
|
|
1030
|
+
// this filter otherwise
|
|
1031
|
+
let allowedTools = options.tools;
|
|
1032
|
+
if (typeof options.toolChoice === "object" && "oneOf" in options.toolChoice) {
|
|
1033
|
+
const allowedToolNames = new Set(options.toolChoice.oneOf);
|
|
1034
|
+
allowedTools = options.tools.filter(tool => allowedToolNames.has(tool.name));
|
|
1035
|
+
toolChoice = options.toolChoice.mode === "required" ? "required" : "auto";
|
|
1036
|
+
}
|
|
1037
|
+
// Convert the tools in the toolkit to the provider-defined format
|
|
1038
|
+
for (const tool of allowedTools) {
|
|
1039
|
+
if (Tool.isUserDefined(tool)) {
|
|
1040
|
+
tools.push({
|
|
1041
|
+
type: "function",
|
|
1042
|
+
name: tool.name,
|
|
1043
|
+
description: Tool.getDescription(tool),
|
|
1044
|
+
parameters: Tool.getJsonSchema(tool),
|
|
1045
|
+
strict: true
|
|
1046
|
+
});
|
|
1047
|
+
}
|
|
1048
|
+
if (Tool.isProviderDefined(tool)) {
|
|
1049
|
+
switch (tool.id) {
|
|
1050
|
+
case "openai.code_interpreter":
|
|
1051
|
+
{
|
|
1052
|
+
tools.push({
|
|
1053
|
+
...tool.args,
|
|
1054
|
+
type: "code_interpreter"
|
|
1055
|
+
});
|
|
1056
|
+
break;
|
|
1057
|
+
}
|
|
1058
|
+
case "openai.file_search":
|
|
1059
|
+
{
|
|
1060
|
+
tools.push({
|
|
1061
|
+
...tool.args,
|
|
1062
|
+
type: "file_search"
|
|
1063
|
+
});
|
|
1064
|
+
break;
|
|
1065
|
+
}
|
|
1066
|
+
case "openai.web_search":
|
|
1067
|
+
{
|
|
1068
|
+
tools.push({
|
|
1069
|
+
...tool.args,
|
|
1070
|
+
type: "web_search"
|
|
1071
|
+
});
|
|
1072
|
+
break;
|
|
1073
|
+
}
|
|
1074
|
+
case "openai.web_search_preview":
|
|
1075
|
+
{
|
|
1076
|
+
tools.push({
|
|
1077
|
+
...tool.args,
|
|
1078
|
+
type: "web_search_preview"
|
|
1079
|
+
});
|
|
1080
|
+
break;
|
|
1081
|
+
}
|
|
1082
|
+
default:
|
|
1083
|
+
{
|
|
1084
|
+
return yield* new AiError.MalformedInput({
|
|
1085
|
+
module: "AnthropicLanguageModel",
|
|
1086
|
+
method: "prepareTools",
|
|
1087
|
+
description: `Received request to call unknown provider-defined tool '${tool.name}'`
|
|
1088
|
+
});
|
|
1089
|
+
}
|
|
499
1090
|
}
|
|
500
1091
|
}
|
|
501
|
-
}
|
|
1092
|
+
}
|
|
1093
|
+
if (options.toolChoice === "auto" || options.toolChoice === "none" || options.toolChoice === "required") {
|
|
1094
|
+
toolChoice = options.toolChoice;
|
|
1095
|
+
}
|
|
1096
|
+
if (typeof options.toolChoice === "object" && "tool" in options.toolChoice) {
|
|
1097
|
+
toolChoice = Predicate.isUndefined(OpenAiTool.getProviderDefinedToolName(options.toolChoice.tool)) ? {
|
|
1098
|
+
type: "function",
|
|
1099
|
+
name: options.toolChoice.tool
|
|
1100
|
+
} : {
|
|
1101
|
+
type: options.toolChoice.tool
|
|
1102
|
+
};
|
|
1103
|
+
}
|
|
1104
|
+
return {
|
|
1105
|
+
tools,
|
|
1106
|
+
toolChoice
|
|
1107
|
+
};
|
|
1108
|
+
});
|
|
1109
|
+
// =============================================================================
|
|
1110
|
+
// Utilities
|
|
1111
|
+
// =============================================================================
|
|
1112
|
+
const isFileId = (data, config) => Predicate.isNotUndefined(config.fileIdPrefixes) && config.fileIdPrefixes.some(prefix => data.startsWith(prefix));
|
|
1113
|
+
const getItemId = part => part.options.openai?.itemId;
|
|
1114
|
+
const getImageDetail = part => part.options.openai?.imageDetail ?? "auto";
|
|
1115
|
+
const prepareInclude = (options, config) => {
|
|
1116
|
+
const include = new Set(config.include ?? []);
|
|
1117
|
+
const codeInterpreterTool = options.tools.find(tool => Tool.isProviderDefined(tool) && tool.id === "openai.code_interpreter");
|
|
1118
|
+
if (Predicate.isNotUndefined(codeInterpreterTool)) {
|
|
1119
|
+
include.add("code_interpreter_call.outputs");
|
|
1120
|
+
}
|
|
1121
|
+
const webSearchTool = options.tools.find(tool => Tool.isProviderDefined(tool) && (tool.id === "openai.web_search" || tool.id === "openai.web_search_preview"));
|
|
1122
|
+
if (Predicate.isNotUndefined(webSearchTool)) {
|
|
1123
|
+
include.add("web_search_call.action.sources");
|
|
1124
|
+
}
|
|
1125
|
+
return Array.from(include);
|
|
1126
|
+
};
|
|
1127
|
+
const prepareResponseFormat = options => {
|
|
1128
|
+
if (options.responseFormat.type === "json") {
|
|
1129
|
+
const name = options.responseFormat.objectName;
|
|
1130
|
+
const schema = options.responseFormat.schema;
|
|
1131
|
+
return {
|
|
1132
|
+
type: "json_schema",
|
|
1133
|
+
name,
|
|
1134
|
+
description: Tool.getDescriptionFromSchemaAst(schema.ast) ?? "Response with a JSON object",
|
|
1135
|
+
schema: Tool.getJsonSchemaFromSchemaAst(schema.ast),
|
|
1136
|
+
strict: true
|
|
1137
|
+
};
|
|
1138
|
+
}
|
|
1139
|
+
return {
|
|
1140
|
+
type: "text"
|
|
1141
|
+
};
|
|
502
1142
|
};
|
|
503
1143
|
//# sourceMappingURL=OpenAiLanguageModel.js.map
|