@effect/ai-openai 4.0.0-beta.7 → 4.0.0-beta.71
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/dist/Generated.d.ts +66734 -37723
- package/dist/Generated.d.ts.map +1 -1
- package/dist/Generated.js +1 -1
- package/dist/Generated.js.map +1 -1
- package/dist/OpenAiClient.d.ts +167 -27
- package/dist/OpenAiClient.d.ts.map +1 -1
- package/dist/OpenAiClient.js +337 -44
- package/dist/OpenAiClient.js.map +1 -1
- package/dist/OpenAiClientGenerated.d.ts +91 -0
- package/dist/OpenAiClientGenerated.d.ts.map +1 -0
- package/dist/OpenAiClientGenerated.js +84 -0
- package/dist/OpenAiClientGenerated.js.map +1 -0
- package/dist/OpenAiConfig.d.ts +114 -10
- package/dist/OpenAiConfig.d.ts.map +1 -1
- package/dist/OpenAiConfig.js +68 -7
- package/dist/OpenAiConfig.js.map +1 -1
- package/dist/OpenAiEmbeddingModel.d.ts +213 -0
- package/dist/OpenAiEmbeddingModel.d.ts.map +1 -0
- package/dist/OpenAiEmbeddingModel.js +219 -0
- package/dist/OpenAiEmbeddingModel.js.map +1 -0
- package/dist/OpenAiError.d.ts +168 -35
- package/dist/OpenAiError.d.ts.map +1 -1
- package/dist/OpenAiError.js +1 -1
- package/dist/OpenAiLanguageModel.d.ts +384 -62
- package/dist/OpenAiLanguageModel.d.ts.map +1 -1
- package/dist/OpenAiLanguageModel.js +416 -166
- package/dist/OpenAiLanguageModel.js.map +1 -1
- package/dist/OpenAiSchema.d.ts +2298 -0
- package/dist/OpenAiSchema.d.ts.map +1 -0
- package/dist/OpenAiSchema.js +814 -0
- package/dist/OpenAiSchema.js.map +1 -0
- package/dist/OpenAiTelemetry.d.ts +59 -18
- package/dist/OpenAiTelemetry.d.ts.map +1 -1
- package/dist/OpenAiTelemetry.js +35 -8
- package/dist/OpenAiTelemetry.js.map +1 -1
- package/dist/OpenAiTool.d.ts +157 -62
- package/dist/OpenAiTool.d.ts.map +1 -1
- package/dist/OpenAiTool.js +134 -39
- package/dist/OpenAiTool.js.map +1 -1
- package/dist/index.d.ts +19 -33
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -33
- package/dist/index.js.map +1 -1
- package/dist/internal/errors.js +4 -4
- package/dist/internal/errors.js.map +1 -1
- package/package.json +3 -3
- package/src/Generated.ts +9858 -5044
- package/src/OpenAiClient.ts +513 -95
- package/src/OpenAiClientGenerated.ts +202 -0
- package/src/OpenAiConfig.ts +115 -11
- package/src/OpenAiEmbeddingModel.ts +357 -0
- package/src/OpenAiError.ts +170 -35
- package/src/OpenAiLanguageModel.ts +802 -167
- package/src/OpenAiSchema.ts +1289 -0
- package/src/OpenAiTelemetry.ts +81 -23
- package/src/OpenAiTool.ts +135 -40
- package/src/index.ts +22 -33
- package/src/internal/errors.ts +6 -4
|
@@ -1,26 +1,58 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OpenAI
|
|
2
|
+
* The `OpenAiLanguageModel` module provides the OpenAI Responses API
|
|
3
|
+
* implementation of Effect AI's `LanguageModel` service. It translates Effect
|
|
4
|
+
* AI prompts, files, tools, structured output requests, reasoning metadata, and
|
|
5
|
+
* provider options into OpenAI response requests, then converts OpenAI
|
|
6
|
+
* responses and streams back into Effect AI response parts.
|
|
3
7
|
*
|
|
4
|
-
*
|
|
5
|
-
* supporting text generation, structured output, tool calling, and streaming.
|
|
8
|
+
* **Mental model**
|
|
6
9
|
*
|
|
7
|
-
*
|
|
10
|
+
* `OpenAiClient` owns HTTP transport and provider calls. This module owns
|
|
11
|
+
* protocol translation: request assembly, tool choice conversion, structured
|
|
12
|
+
* output codecs, streaming event handling, response metadata, and GenAI
|
|
13
|
+
* telemetry annotations. {@link model}, {@link layer}, and {@link make} all
|
|
14
|
+
* build the same OpenAI-backed `LanguageModel.LanguageModel` service from a
|
|
15
|
+
* model id and optional request defaults.
|
|
16
|
+
*
|
|
17
|
+
* **Common tasks**
|
|
18
|
+
*
|
|
19
|
+
* - Provide an OpenAI-backed `LanguageModel.LanguageModel` from an existing
|
|
20
|
+
* `OpenAiClient`
|
|
21
|
+
* - Generate text or stream text through Effect AI's provider-neutral language
|
|
22
|
+
* model API
|
|
23
|
+
* - Use OpenAI provider metadata for files, reasoning items, tool calls, and
|
|
24
|
+
* response parts
|
|
25
|
+
* - Scope Responses API defaults with {@link Config} and
|
|
26
|
+
* {@link withConfigOverride}
|
|
27
|
+
*
|
|
28
|
+
* **Gotchas**
|
|
29
|
+
*
|
|
30
|
+
* - Some OpenAI model families receive system instructions as developer
|
|
31
|
+
* messages because the Responses API treats them differently.
|
|
32
|
+
* - File prompt parts are sent either as provider file ids or as base64
|
|
33
|
+
* content, depending on `fileIdPrefixes`.
|
|
34
|
+
* - Structured output and tool-call behavior depends on both Effect AI tool
|
|
35
|
+
* definitions and OpenAI model capabilities.
|
|
36
|
+
*
|
|
37
|
+
* @since 4.0.0
|
|
8
38
|
*/
|
|
39
|
+
import * as Context from "effect/Context";
|
|
9
40
|
import * as DateTime from "effect/DateTime";
|
|
10
41
|
import * as Effect from "effect/Effect";
|
|
11
42
|
import * as Encoding from "effect/Encoding";
|
|
12
43
|
import { dual } from "effect/Function";
|
|
13
44
|
import * as Layer from "effect/Layer";
|
|
45
|
+
import * as Option from "effect/Option";
|
|
14
46
|
import * as Predicate from "effect/Predicate";
|
|
15
47
|
import * as Redactable from "effect/Redactable";
|
|
16
48
|
import * as Schema from "effect/Schema";
|
|
17
49
|
import * as AST from "effect/SchemaAST";
|
|
18
|
-
import * as ServiceMap from "effect/ServiceMap";
|
|
19
50
|
import * as Stream from "effect/Stream";
|
|
20
51
|
import * as AiError from "effect/unstable/ai/AiError";
|
|
21
52
|
import * as IdGenerator from "effect/unstable/ai/IdGenerator";
|
|
22
53
|
import * as LanguageModel from "effect/unstable/ai/LanguageModel";
|
|
23
54
|
import * as AiModel from "effect/unstable/ai/Model";
|
|
55
|
+
import { toCodecOpenAI } from "effect/unstable/ai/OpenAiStructuredOutput";
|
|
24
56
|
import * as Tool from "effect/unstable/ai/Tool";
|
|
25
57
|
import * as Generated from "./Generated.js";
|
|
26
58
|
import * as InternalUtilities from "./internal/utilities.js";
|
|
@@ -34,36 +66,75 @@ const SharedModelIds = Generated.ModelIdsShared.members[1];
|
|
|
34
66
|
/**
|
|
35
67
|
* Service definition for OpenAI language model configuration.
|
|
36
68
|
*
|
|
37
|
-
*
|
|
69
|
+
* **When to use**
|
|
70
|
+
*
|
|
71
|
+
* Use when you need to provide OpenAI Responses API request defaults through
|
|
72
|
+
* Effect context for language model operations.
|
|
73
|
+
*
|
|
74
|
+
* **Details**
|
|
75
|
+
*
|
|
76
|
+
* Config values are merged with the config object passed to `model`, `make`, or
|
|
77
|
+
* `layer`, with scoped context values taking precedence.
|
|
78
|
+
*
|
|
79
|
+
* @see {@link withConfigOverride} for scoping language model request overrides
|
|
80
|
+
*
|
|
38
81
|
* @category services
|
|
82
|
+
* @since 4.0.0
|
|
39
83
|
*/
|
|
40
|
-
export class Config extends /*#__PURE__*/
|
|
84
|
+
export class Config extends /*#__PURE__*/Context.Service()("@effect/ai-openai/OpenAiLanguageModel/Config") {}
|
|
41
85
|
// =============================================================================
|
|
42
86
|
// Language Model
|
|
43
87
|
// =============================================================================
|
|
44
88
|
/**
|
|
45
|
-
*
|
|
89
|
+
* Creates an OpenAI model descriptor that can be provided with
|
|
90
|
+
* `Effect.provide`.
|
|
91
|
+
*
|
|
92
|
+
* **When to use**
|
|
93
|
+
*
|
|
94
|
+
* Use when you want an OpenAI language model value that carries provider and
|
|
95
|
+
* model metadata and can be supplied directly to an Effect program.
|
|
96
|
+
*
|
|
97
|
+
* @see {@link layer} for creating a `LanguageModel.LanguageModel` layer directly
|
|
98
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
99
|
+
*
|
|
46
100
|
* @category constructors
|
|
101
|
+
* @since 4.0.0
|
|
47
102
|
*/
|
|
48
|
-
export const model = (model, config) => AiModel.make("openai", layer({
|
|
103
|
+
export const model = (model, config) => AiModel.make("openai", model, layer({
|
|
49
104
|
model,
|
|
50
105
|
config
|
|
51
106
|
}));
|
|
52
107
|
// TODO
|
|
53
108
|
// /**
|
|
54
|
-
// * @since
|
|
109
|
+
// * @since 4.0.0
|
|
55
110
|
// * @category constructors
|
|
56
111
|
// */
|
|
57
112
|
// export const modelWithTokenizer = (
|
|
58
113
|
// model: (string & {}) | Model,
|
|
59
114
|
// config?: Omit<typeof Config.Service, "model">
|
|
60
115
|
// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> =>
|
|
61
|
-
// AiModel.make("openai", layerWithTokenizer({ model, config }))
|
|
116
|
+
// AiModel.make("openai", model, layerWithTokenizer({ model, config }))
|
|
62
117
|
/**
|
|
63
|
-
* Creates an OpenAI
|
|
118
|
+
* Creates an OpenAI `LanguageModel` service from a model identifier and
|
|
119
|
+
* optional request defaults.
|
|
120
|
+
*
|
|
121
|
+
* **When to use**
|
|
122
|
+
*
|
|
123
|
+
* Use when an Effect needs to construct a `LanguageModel.Service` value backed
|
|
124
|
+
* by `OpenAiClient`.
|
|
125
|
+
*
|
|
126
|
+
* **Details**
|
|
127
|
+
*
|
|
128
|
+
* The returned effect requires `OpenAiClient`. Request defaults from the
|
|
129
|
+
* `config` option are merged with any `Config` service in the context, with
|
|
130
|
+
* context values taking precedence. The service supports both `generateText`
|
|
131
|
+
* and `streamText`.
|
|
132
|
+
*
|
|
133
|
+
* @see {@link layer} for providing the service as a `Layer`
|
|
134
|
+
* @see {@link model} for creating a model descriptor for `Effect.provide`
|
|
64
135
|
*
|
|
65
|
-
* @since 1.0.0
|
|
66
136
|
* @category constructors
|
|
137
|
+
* @since 4.0.0
|
|
67
138
|
*/
|
|
68
139
|
export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
69
140
|
model,
|
|
@@ -71,7 +142,7 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
71
142
|
}) {
|
|
72
143
|
const client = yield* OpenAiClient;
|
|
73
144
|
const makeConfig = Effect.gen(function* () {
|
|
74
|
-
const services = yield* Effect.
|
|
145
|
+
const services = yield* Effect.context();
|
|
75
146
|
return {
|
|
76
147
|
model,
|
|
77
148
|
...providerConfig,
|
|
@@ -100,28 +171,31 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
100
171
|
options,
|
|
101
172
|
toolNameMapper
|
|
102
173
|
});
|
|
103
|
-
const responseFormat = prepareResponseFormat({
|
|
174
|
+
const responseFormat = yield* prepareResponseFormat({
|
|
104
175
|
config,
|
|
105
176
|
options
|
|
106
177
|
});
|
|
178
|
+
const {
|
|
179
|
+
fileIdPrefixes: _fip,
|
|
180
|
+
strictJsonSchema: _sjs,
|
|
181
|
+
...apiConfig
|
|
182
|
+
} = config;
|
|
107
183
|
const request = {
|
|
108
|
-
...
|
|
184
|
+
...apiConfig,
|
|
109
185
|
input: messages,
|
|
110
|
-
include: include.size > 0 ? Array.from(include) :
|
|
186
|
+
include: include.size > 0 ? Array.from(include) : undefined,
|
|
111
187
|
text: {
|
|
112
|
-
verbosity: config.text?.verbosity ??
|
|
188
|
+
verbosity: config.text?.verbosity ?? undefined,
|
|
113
189
|
format: responseFormat
|
|
114
|
-
}
|
|
115
|
-
...(Predicate.isNotUndefined(tools) ? {
|
|
116
|
-
tools
|
|
117
|
-
} : undefined),
|
|
118
|
-
...(Predicate.isNotUndefined(toolChoice) ? {
|
|
119
|
-
tool_choice: toolChoice
|
|
120
|
-
} : undefined)
|
|
190
|
+
}
|
|
121
191
|
};
|
|
192
|
+
if (tools) request.tools = tools;
|
|
193
|
+
if (toolChoice) request.tool_choice = toolChoice;
|
|
194
|
+
if (options.previousResponseId) request.previous_response_id = options.previousResponseId;
|
|
122
195
|
return request;
|
|
123
196
|
});
|
|
124
197
|
return yield* LanguageModel.make({
|
|
198
|
+
codecTransformer: toCodecOpenAI,
|
|
125
199
|
generateText: Effect.fnUntraced(function* (options) {
|
|
126
200
|
const config = yield* makeConfig;
|
|
127
201
|
const toolNameMapper = new Tool.NameMapper(options.tools);
|
|
@@ -164,17 +238,49 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
164
238
|
});
|
|
165
239
|
});
|
|
166
240
|
/**
|
|
167
|
-
* Creates a layer
|
|
241
|
+
* Creates a layer that provides the OpenAI `LanguageModel.LanguageModel`
|
|
242
|
+
* service.
|
|
243
|
+
*
|
|
244
|
+
* **When to use**
|
|
245
|
+
*
|
|
246
|
+
* Use when composing application layers and you want OpenAI to satisfy
|
|
247
|
+
* `LanguageModel.LanguageModel` while supplying `OpenAiClient` from another
|
|
248
|
+
* layer.
|
|
249
|
+
*
|
|
250
|
+
* **Details**
|
|
251
|
+
*
|
|
252
|
+
* The `config` option supplies request defaults for the selected model. Scoped
|
|
253
|
+
* values from `withConfigOverride` are merged when each request is built and
|
|
254
|
+
* take precedence over these defaults.
|
|
255
|
+
*
|
|
256
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
257
|
+
* @see {@link model} for creating a model descriptor for `Effect.provide`
|
|
258
|
+
* @see {@link withConfigOverride} for scoped request configuration overrides
|
|
168
259
|
*
|
|
169
|
-
* @since 1.0.0
|
|
170
260
|
* @category layers
|
|
261
|
+
* @since 4.0.0
|
|
171
262
|
*/
|
|
172
263
|
export const layer = options => Layer.effect(LanguageModel.LanguageModel, make(options));
|
|
173
264
|
/**
|
|
174
|
-
* Provides config overrides for OpenAI language model operations.
|
|
265
|
+
* Provides scoped config overrides for OpenAI language model operations.
|
|
266
|
+
*
|
|
267
|
+
* **When to use**
|
|
268
|
+
*
|
|
269
|
+
* Use to apply OpenAI Responses API config overrides around one or more
|
|
270
|
+
* language model operations without changing the defaults passed to `model`,
|
|
271
|
+
* `make`, or `layer`.
|
|
272
|
+
*
|
|
273
|
+
* **Details**
|
|
274
|
+
*
|
|
275
|
+
* The override is dual, so it can be used in pipe form or as
|
|
276
|
+
* `withConfigOverride(effect, overrides)`. Overrides are merged with any
|
|
277
|
+
* existing `Config` service in the current context, and the override values take
|
|
278
|
+
* precedence.
|
|
279
|
+
*
|
|
280
|
+
* @see {@link Config} for the scoped configuration service consumed by this function
|
|
175
281
|
*
|
|
176
|
-
* @since 1.0.0
|
|
177
282
|
* @category configuration
|
|
283
|
+
* @since 4.0.0
|
|
178
284
|
*/
|
|
179
285
|
export const withConfigOverride = /*#__PURE__*/dual(2, (self, overrides) => Effect.flatMap(Effect.serviceOption(Config), config => Effect.provideService(self, Config, {
|
|
180
286
|
...(config._tag === "Some" ? config.value : {}),
|
|
@@ -207,14 +313,15 @@ const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
207
313
|
if (config.store === false && capabilities.isReasoningModel) {
|
|
208
314
|
include.add("reasoning.encrypted_content");
|
|
209
315
|
}
|
|
210
|
-
if (
|
|
316
|
+
if (codeInterpreterTool) {
|
|
211
317
|
include.add("code_interpreter_call.outputs");
|
|
212
318
|
}
|
|
213
|
-
if (
|
|
319
|
+
if (webSearchTool || webSearchPreviewTool) {
|
|
214
320
|
include.add("web_search_call.action.sources");
|
|
215
321
|
}
|
|
216
322
|
const messages = [];
|
|
217
|
-
|
|
323
|
+
const prompt = options.incrementalPrompt ?? options.prompt;
|
|
324
|
+
for (const message of prompt.content) {
|
|
218
325
|
switch (message.role) {
|
|
219
326
|
case "system":
|
|
220
327
|
{
|
|
@@ -378,7 +485,9 @@ const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
378
485
|
type: "reasoning",
|
|
379
486
|
id,
|
|
380
487
|
summary: summaryParts,
|
|
381
|
-
|
|
488
|
+
...(Predicate.isNotNull(encryptedContent) ? {
|
|
489
|
+
encrypted_content: encryptedContent
|
|
490
|
+
} : undefined)
|
|
382
491
|
};
|
|
383
492
|
messages.push(reasoningMessages[id]);
|
|
384
493
|
} else {
|
|
@@ -569,13 +678,15 @@ const buildHttpRequestDetails = request => ({
|
|
|
569
678
|
method: request.method,
|
|
570
679
|
url: request.url,
|
|
571
680
|
urlParams: Array.from(request.urlParams),
|
|
572
|
-
hash: request.hash,
|
|
681
|
+
hash: Option.getOrUndefined(request.hash),
|
|
573
682
|
headers: Redactable.redact(request.headers)
|
|
574
683
|
});
|
|
575
684
|
const buildHttpResponseDetails = response => ({
|
|
576
685
|
status: response.status,
|
|
577
686
|
headers: Redactable.redact(response.headers)
|
|
578
687
|
});
|
|
688
|
+
const knownResponseStreamEventTypes = /*#__PURE__*/new Set(["response.created", "response.completed", "response.incomplete", "response.failed", "response.output_item.added", "response.output_item.done", "response.output_text.delta", "response.output_text.annotation.added", "response.reasoning_summary_part.added", "response.reasoning_summary_part.done", "response.reasoning_summary_text.delta", "response.function_call_arguments.delta", "response.function_call_arguments.done", "response.code_interpreter_call_code.delta", "response.code_interpreter_call_code.done", "response.apply_patch_call_operation_diff.delta", "response.apply_patch_call_operation_diff.done", "response.image_generation_call.partial_image", "error"]);
|
|
689
|
+
const isKnownResponseStreamEvent = event => knownResponseStreamEventTypes.has(event.type);
|
|
579
690
|
const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
580
691
|
options,
|
|
581
692
|
rawResponse,
|
|
@@ -609,9 +720,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
609
720
|
operation: part.operation
|
|
610
721
|
},
|
|
611
722
|
metadata: {
|
|
612
|
-
openai:
|
|
613
|
-
...makeItemIdMetadata(part.id)
|
|
614
|
-
}
|
|
723
|
+
openai: makeItemIdMetadata(part.id)
|
|
615
724
|
}
|
|
616
725
|
});
|
|
617
726
|
break;
|
|
@@ -669,9 +778,8 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
669
778
|
{
|
|
670
779
|
hasToolCalls = true;
|
|
671
780
|
const toolName = part.name;
|
|
672
|
-
const toolParams =
|
|
673
|
-
|
|
674
|
-
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
781
|
+
const toolParams = yield* Effect.try({
|
|
782
|
+
try: () => Tool.unsafeSecureJsonParse(part.arguments),
|
|
675
783
|
catch: cause => AiError.make({
|
|
676
784
|
module: "OpenAiLanguageModel",
|
|
677
785
|
method: "makeResponse",
|
|
@@ -682,15 +790,14 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
682
790
|
})
|
|
683
791
|
})
|
|
684
792
|
});
|
|
793
|
+
const params = yield* transformToolCallParams(options.tools, part.name, toolParams);
|
|
685
794
|
parts.push({
|
|
686
795
|
type: "tool-call",
|
|
687
796
|
id: part.call_id,
|
|
688
797
|
name: toolName,
|
|
689
798
|
params,
|
|
690
799
|
metadata: {
|
|
691
|
-
openai:
|
|
692
|
-
...makeItemIdMetadata(part.id)
|
|
693
|
-
}
|
|
800
|
+
openai: makeItemIdMetadata(part.id)
|
|
694
801
|
}
|
|
695
802
|
});
|
|
696
803
|
break;
|
|
@@ -727,9 +834,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
727
834
|
action: part.action
|
|
728
835
|
},
|
|
729
836
|
metadata: {
|
|
730
|
-
openai:
|
|
731
|
-
...makeItemIdMetadata(part.id)
|
|
732
|
-
}
|
|
837
|
+
openai: makeItemIdMetadata(part.id)
|
|
733
838
|
}
|
|
734
839
|
});
|
|
735
840
|
break;
|
|
@@ -737,12 +842,19 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
737
842
|
case "mcp_call":
|
|
738
843
|
{
|
|
739
844
|
const toolId = Predicate.isNotNullish(part.approval_request_id) ? approvalRequests.get(part.approval_request_id) ?? part.id : part.id;
|
|
740
|
-
const
|
|
845
|
+
const {
|
|
846
|
+
toolName,
|
|
847
|
+
params
|
|
848
|
+
} = yield* normalizeMcpToolCall({
|
|
849
|
+
toolNameMapper,
|
|
850
|
+
toolParams: part.arguments,
|
|
851
|
+
method: "makeResponse"
|
|
852
|
+
});
|
|
741
853
|
parts.push({
|
|
742
854
|
type: "tool-call",
|
|
743
855
|
id: toolId,
|
|
744
856
|
name: toolName,
|
|
745
|
-
params
|
|
857
|
+
params,
|
|
746
858
|
providerExecuted: true
|
|
747
859
|
});
|
|
748
860
|
parts.push({
|
|
@@ -752,7 +864,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
752
864
|
isFailure: false,
|
|
753
865
|
providerExecuted: true,
|
|
754
866
|
result: {
|
|
755
|
-
type: "
|
|
867
|
+
type: "mcp_call",
|
|
756
868
|
name: part.name,
|
|
757
869
|
arguments: part.arguments,
|
|
758
870
|
server_label: part.server_label,
|
|
@@ -764,9 +876,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
764
876
|
} : undefined)
|
|
765
877
|
},
|
|
766
878
|
metadata: {
|
|
767
|
-
openai:
|
|
768
|
-
...makeItemIdMetadata(part.id)
|
|
769
|
-
}
|
|
879
|
+
openai: makeItemIdMetadata(part.id)
|
|
770
880
|
}
|
|
771
881
|
});
|
|
772
882
|
break;
|
|
@@ -780,18 +890,13 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
780
890
|
{
|
|
781
891
|
const approvalRequestId = part.approval_request_id ?? part.id;
|
|
782
892
|
const toolId = yield* idGenerator.generateId();
|
|
783
|
-
const
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
toolName,
|
|
791
|
-
toolParams: {},
|
|
792
|
-
description: `Failed securely JSON parse tool parameters: ${cause}`
|
|
793
|
-
})
|
|
794
|
-
})
|
|
893
|
+
const {
|
|
894
|
+
toolName,
|
|
895
|
+
params
|
|
896
|
+
} = yield* normalizeMcpToolCall({
|
|
897
|
+
toolNameMapper,
|
|
898
|
+
toolParams: part.arguments,
|
|
899
|
+
method: "makeResponse"
|
|
795
900
|
});
|
|
796
901
|
parts.push({
|
|
797
902
|
type: "tool-call",
|
|
@@ -952,9 +1057,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
952
1057
|
action: part.action
|
|
953
1058
|
},
|
|
954
1059
|
metadata: {
|
|
955
|
-
openai:
|
|
956
|
-
...makeItemIdMetadata(part.id)
|
|
957
|
-
}
|
|
1060
|
+
openai: makeItemIdMetadata(part.id)
|
|
958
1061
|
}
|
|
959
1062
|
});
|
|
960
1063
|
break;
|
|
@@ -990,13 +1093,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
990
1093
|
reason: finishReason,
|
|
991
1094
|
usage: getUsage(rawResponse.usage),
|
|
992
1095
|
response: buildHttpResponseDetails(response),
|
|
993
|
-
...(rawResponse.service_tier
|
|
994
|
-
metadata: {
|
|
995
|
-
openai: {
|
|
996
|
-
serviceTier: rawResponse.service_tier
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
})
|
|
1096
|
+
...toServiceTier(rawResponse.service_tier)
|
|
1000
1097
|
});
|
|
1001
1098
|
return parts;
|
|
1002
1099
|
});
|
|
@@ -1015,11 +1112,29 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1015
1112
|
const activeAnnotations = [];
|
|
1016
1113
|
// Track active reasoning items with state machine for proper concluding logic
|
|
1017
1114
|
const activeReasoning = {};
|
|
1115
|
+
const getOrCreateReasoningPart = (itemId, encryptedContent) => {
|
|
1116
|
+
const activePart = activeReasoning[itemId];
|
|
1117
|
+
if (Predicate.isNotUndefined(activePart)) {
|
|
1118
|
+
if (Predicate.isNotNullish(encryptedContent)) {
|
|
1119
|
+
activePart.encryptedContent = encryptedContent;
|
|
1120
|
+
}
|
|
1121
|
+
return activePart;
|
|
1122
|
+
}
|
|
1123
|
+
const reasoningPart = {
|
|
1124
|
+
encryptedContent: Predicate.isNotNullish(encryptedContent) ? encryptedContent : undefined,
|
|
1125
|
+
summaryParts: {}
|
|
1126
|
+
};
|
|
1127
|
+
activeReasoning[itemId] = reasoningPart;
|
|
1128
|
+
return reasoningPart;
|
|
1129
|
+
};
|
|
1018
1130
|
// Track active tool calls with optional provider-specific state
|
|
1019
1131
|
const activeToolCalls = {};
|
|
1020
1132
|
const webSearchTool = options.tools.find(tool => Tool.isProviderDefined(tool) && (tool.name === "OpenAiWebSearch" || tool.name === "OpenAiWebSearchPreview"));
|
|
1021
1133
|
return stream.pipe(Stream.mapEffect(Effect.fnUntraced(function* (event) {
|
|
1022
1134
|
const parts = [];
|
|
1135
|
+
if (!isKnownResponseStreamEvent(event)) {
|
|
1136
|
+
return parts;
|
|
1137
|
+
}
|
|
1023
1138
|
switch (event.type) {
|
|
1024
1139
|
case "response.created":
|
|
1025
1140
|
{
|
|
@@ -1050,13 +1165,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1050
1165
|
reason: InternalUtilities.resolveFinishReason(event.response.incomplete_details?.reason, hasToolCalls),
|
|
1051
1166
|
usage: getUsage(event.response.usage),
|
|
1052
1167
|
response: buildHttpResponseDetails(response),
|
|
1053
|
-
...(event.response.service_tier
|
|
1054
|
-
metadata: {
|
|
1055
|
-
openai: {
|
|
1056
|
-
serviceTier: event.response.service_tier
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
})
|
|
1168
|
+
...toServiceTier(event.response.service_tier)
|
|
1060
1169
|
});
|
|
1061
1170
|
break;
|
|
1062
1171
|
}
|
|
@@ -1157,7 +1266,10 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1157
1266
|
{
|
|
1158
1267
|
activeToolCalls[event.output_index] = {
|
|
1159
1268
|
id: event.item.call_id,
|
|
1160
|
-
name: event.item.name
|
|
1269
|
+
name: event.item.name,
|
|
1270
|
+
functionCall: {
|
|
1271
|
+
emitted: false
|
|
1272
|
+
}
|
|
1161
1273
|
};
|
|
1162
1274
|
parts.push({
|
|
1163
1275
|
type: "tool-params-start",
|
|
@@ -1195,39 +1307,34 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1195
1307
|
type: "text-start",
|
|
1196
1308
|
id: event.item.id,
|
|
1197
1309
|
metadata: {
|
|
1198
|
-
openai:
|
|
1199
|
-
...makeItemIdMetadata(event.item.id)
|
|
1200
|
-
}
|
|
1310
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1201
1311
|
}
|
|
1202
1312
|
});
|
|
1203
1313
|
break;
|
|
1204
1314
|
}
|
|
1205
1315
|
case "reasoning":
|
|
1206
1316
|
{
|
|
1207
|
-
const
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
1211
|
-
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
openai: {
|
|
1219
|
-
...makeItemIdMetadata(event.item.id),
|
|
1220
|
-
...makeEncryptedContentMetadata(event.item.encrypted_content)
|
|
1317
|
+
const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content);
|
|
1318
|
+
if (Predicate.isUndefined(reasoningPart.summaryParts[0])) {
|
|
1319
|
+
reasoningPart.summaryParts[0] = "active";
|
|
1320
|
+
parts.push({
|
|
1321
|
+
type: "reasoning-start",
|
|
1322
|
+
id: `${event.item.id}:0`,
|
|
1323
|
+
metadata: {
|
|
1324
|
+
openai: {
|
|
1325
|
+
...makeItemIdMetadata(event.item.id),
|
|
1326
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1327
|
+
}
|
|
1221
1328
|
}
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1329
|
+
});
|
|
1330
|
+
}
|
|
1224
1331
|
break;
|
|
1225
1332
|
}
|
|
1226
1333
|
case "shell_call":
|
|
1227
1334
|
{
|
|
1228
1335
|
const toolName = toolNameMapper.getCustomName("shell");
|
|
1229
1336
|
activeToolCalls[event.output_index] = {
|
|
1230
|
-
id: event.item.id,
|
|
1337
|
+
id: event.item.id ?? event.item.call_id,
|
|
1231
1338
|
name: toolName
|
|
1232
1339
|
};
|
|
1233
1340
|
break;
|
|
@@ -1272,7 +1379,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1272
1379
|
parts.push({
|
|
1273
1380
|
type: "tool-params-delta",
|
|
1274
1381
|
id: toolCall.id,
|
|
1275
|
-
delta: InternalUtilities.escapeJSONDelta(event.item.operation.diff)
|
|
1382
|
+
delta: InternalUtilities.escapeJSONDelta(event.item.operation.diff ?? "")
|
|
1276
1383
|
});
|
|
1277
1384
|
}
|
|
1278
1385
|
parts.push({
|
|
@@ -1298,9 +1405,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1298
1405
|
operation: event.item.operation
|
|
1299
1406
|
},
|
|
1300
1407
|
metadata: {
|
|
1301
|
-
openai:
|
|
1302
|
-
...makeItemIdMetadata(event.item.id)
|
|
1303
|
-
}
|
|
1408
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1304
1409
|
}
|
|
1305
1410
|
});
|
|
1306
1411
|
}
|
|
@@ -1372,12 +1477,17 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1372
1477
|
}
|
|
1373
1478
|
case "function_call":
|
|
1374
1479
|
{
|
|
1480
|
+
const toolCall = activeToolCalls[event.output_index];
|
|
1481
|
+
if (Predicate.isNotUndefined(toolCall?.functionCall?.emitted) && toolCall.functionCall.emitted) {
|
|
1482
|
+
delete activeToolCalls[event.output_index];
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1375
1485
|
delete activeToolCalls[event.output_index];
|
|
1376
1486
|
hasToolCalls = true;
|
|
1377
1487
|
const toolName = event.item.name;
|
|
1378
|
-
const
|
|
1379
|
-
const
|
|
1380
|
-
try: () => Tool.unsafeSecureJsonParse(
|
|
1488
|
+
const toolArgs = event.item.arguments;
|
|
1489
|
+
const toolParams = yield* Effect.try({
|
|
1490
|
+
try: () => Tool.unsafeSecureJsonParse(toolArgs),
|
|
1381
1491
|
catch: cause => AiError.make({
|
|
1382
1492
|
module: "OpenAiLanguageModel",
|
|
1383
1493
|
method: "makeStreamResponse",
|
|
@@ -1388,6 +1498,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1388
1498
|
})
|
|
1389
1499
|
})
|
|
1390
1500
|
});
|
|
1501
|
+
const params = yield* transformToolCallParams(options.tools, toolName, toolParams);
|
|
1391
1502
|
parts.push({
|
|
1392
1503
|
type: "tool-params-end",
|
|
1393
1504
|
id: event.item.call_id
|
|
@@ -1398,9 +1509,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1398
1509
|
name: toolName,
|
|
1399
1510
|
params,
|
|
1400
1511
|
metadata: {
|
|
1401
|
-
openai:
|
|
1402
|
-
...makeItemIdMetadata(event.item.id)
|
|
1403
|
-
}
|
|
1512
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1404
1513
|
}
|
|
1405
1514
|
});
|
|
1406
1515
|
break;
|
|
@@ -1431,9 +1540,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1431
1540
|
action: event.item.action
|
|
1432
1541
|
},
|
|
1433
1542
|
metadata: {
|
|
1434
|
-
openai:
|
|
1435
|
-
...makeItemIdMetadata(event.item.id)
|
|
1436
|
-
}
|
|
1543
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1437
1544
|
}
|
|
1438
1545
|
});
|
|
1439
1546
|
break;
|
|
@@ -1443,12 +1550,19 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1443
1550
|
const approvalRequestId = event.item.approval_request_id;
|
|
1444
1551
|
// Track approval with our own tool call identifiers
|
|
1445
1552
|
const toolId = Predicate.isNotNullish(approvalRequestId) ? streamApprovalRequests.get(approvalRequestId) ?? approvalRequests.get(approvalRequestId) ?? event.item.id : event.item.id;
|
|
1446
|
-
const
|
|
1553
|
+
const {
|
|
1554
|
+
toolName,
|
|
1555
|
+
params
|
|
1556
|
+
} = yield* normalizeMcpToolCall({
|
|
1557
|
+
toolNameMapper,
|
|
1558
|
+
toolParams: event.item.arguments,
|
|
1559
|
+
method: "makeStreamResponse"
|
|
1560
|
+
});
|
|
1447
1561
|
parts.push({
|
|
1448
1562
|
type: "tool-call",
|
|
1449
1563
|
id: toolId,
|
|
1450
1564
|
name: toolName,
|
|
1451
|
-
params
|
|
1565
|
+
params,
|
|
1452
1566
|
providerExecuted: true
|
|
1453
1567
|
});
|
|
1454
1568
|
parts.push({
|
|
@@ -1458,7 +1572,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1458
1572
|
isFailure: false,
|
|
1459
1573
|
providerExecuted: true,
|
|
1460
1574
|
result: {
|
|
1461
|
-
type: "
|
|
1575
|
+
type: "mcp_call",
|
|
1462
1576
|
name: event.item.name,
|
|
1463
1577
|
arguments: event.item.arguments,
|
|
1464
1578
|
server_label: event.item.server_label,
|
|
@@ -1470,9 +1584,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1470
1584
|
} : undefined)
|
|
1471
1585
|
},
|
|
1472
1586
|
metadata: {
|
|
1473
|
-
openai:
|
|
1474
|
-
...makeItemIdMetadata(event.item.id)
|
|
1475
|
-
}
|
|
1587
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1476
1588
|
}
|
|
1477
1589
|
});
|
|
1478
1590
|
break;
|
|
@@ -1487,12 +1599,19 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1487
1599
|
const toolId = yield* idGenerator.generateId();
|
|
1488
1600
|
const approvalRequestId = event.item.approval_request_id ?? event.item.id;
|
|
1489
1601
|
streamApprovalRequests.set(approvalRequestId, toolId);
|
|
1490
|
-
const
|
|
1602
|
+
const {
|
|
1603
|
+
toolName,
|
|
1604
|
+
params
|
|
1605
|
+
} = yield* normalizeMcpToolCall({
|
|
1606
|
+
toolNameMapper,
|
|
1607
|
+
toolParams: event.item.arguments,
|
|
1608
|
+
method: "makeStreamResponse"
|
|
1609
|
+
});
|
|
1491
1610
|
parts.push({
|
|
1492
1611
|
type: "tool-call",
|
|
1493
1612
|
id: toolId,
|
|
1494
1613
|
name: toolName,
|
|
1495
|
-
params
|
|
1614
|
+
params,
|
|
1496
1615
|
providerExecuted: true
|
|
1497
1616
|
});
|
|
1498
1617
|
parts.push({
|
|
@@ -1521,7 +1640,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1521
1640
|
}
|
|
1522
1641
|
case "reasoning":
|
|
1523
1642
|
{
|
|
1524
|
-
const reasoningPart =
|
|
1643
|
+
const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content);
|
|
1525
1644
|
for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) {
|
|
1526
1645
|
if (status === "active" || status === "can-conclude") {
|
|
1527
1646
|
parts.push({
|
|
@@ -1530,7 +1649,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1530
1649
|
metadata: {
|
|
1531
1650
|
openai: {
|
|
1532
1651
|
...makeItemIdMetadata(event.item.id),
|
|
1533
|
-
...makeEncryptedContentMetadata(
|
|
1652
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1534
1653
|
}
|
|
1535
1654
|
}
|
|
1536
1655
|
});
|
|
@@ -1545,15 +1664,13 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1545
1664
|
const toolName = toolNameMapper.getCustomName("shell");
|
|
1546
1665
|
parts.push({
|
|
1547
1666
|
type: "tool-call",
|
|
1548
|
-
id: event.item.id,
|
|
1667
|
+
id: event.item.id ?? event.item.call_id,
|
|
1549
1668
|
name: toolName,
|
|
1550
1669
|
params: {
|
|
1551
1670
|
action: event.item.action
|
|
1552
1671
|
},
|
|
1553
1672
|
metadata: {
|
|
1554
|
-
openai:
|
|
1555
|
-
...makeItemIdMetadata(event.item.id)
|
|
1556
|
-
}
|
|
1673
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1557
1674
|
}
|
|
1558
1675
|
});
|
|
1559
1676
|
break;
|
|
@@ -1670,6 +1787,41 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1670
1787
|
}
|
|
1671
1788
|
break;
|
|
1672
1789
|
}
|
|
1790
|
+
case "response.function_call_arguments.done":
|
|
1791
|
+
{
|
|
1792
|
+
const toolCall = activeToolCalls[event.output_index];
|
|
1793
|
+
if (Predicate.isNotUndefined(toolCall?.functionCall) && !toolCall.functionCall.emitted) {
|
|
1794
|
+
hasToolCalls = true;
|
|
1795
|
+
const toolParams = yield* Effect.try({
|
|
1796
|
+
try: () => Tool.unsafeSecureJsonParse(event.arguments),
|
|
1797
|
+
catch: cause => AiError.make({
|
|
1798
|
+
module: "OpenAiLanguageModel",
|
|
1799
|
+
method: "makeStreamResponse",
|
|
1800
|
+
reason: new AiError.ToolParameterValidationError({
|
|
1801
|
+
toolName: toolCall.name,
|
|
1802
|
+
toolParams: {},
|
|
1803
|
+
description: `Failed securely JSON parse tool parameters: ${cause}`
|
|
1804
|
+
})
|
|
1805
|
+
})
|
|
1806
|
+
});
|
|
1807
|
+
const params = yield* transformToolCallParams(options.tools, toolCall.name, toolParams);
|
|
1808
|
+
parts.push({
|
|
1809
|
+
type: "tool-params-end",
|
|
1810
|
+
id: toolCall.id
|
|
1811
|
+
});
|
|
1812
|
+
parts.push({
|
|
1813
|
+
type: "tool-call",
|
|
1814
|
+
id: toolCall.id,
|
|
1815
|
+
name: toolCall.name,
|
|
1816
|
+
params,
|
|
1817
|
+
metadata: {
|
|
1818
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1819
|
+
}
|
|
1820
|
+
});
|
|
1821
|
+
toolCall.functionCall.emitted = true;
|
|
1822
|
+
}
|
|
1823
|
+
break;
|
|
1824
|
+
}
|
|
1673
1825
|
case "response.apply_patch_call_operation_diff.delta":
|
|
1674
1826
|
{
|
|
1675
1827
|
const toolCall = activeToolCalls[event.output_index];
|
|
@@ -1765,28 +1917,27 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1765
1917
|
}
|
|
1766
1918
|
case "response.reasoning_summary_part.added":
|
|
1767
1919
|
{
|
|
1768
|
-
|
|
1920
|
+
const reasoningPart = getOrCreateReasoningPart(event.item_id);
|
|
1769
1921
|
if (event.summary_index > 0) {
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
...makeItemIdMetadata(event.item_id),
|
|
1781
|
-
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1782
|
-
}
|
|
1922
|
+
// Conclude all can-conclude parts before starting new one
|
|
1923
|
+
for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) {
|
|
1924
|
+
if (status === "can-conclude") {
|
|
1925
|
+
parts.push({
|
|
1926
|
+
type: "reasoning-end",
|
|
1927
|
+
id: `${event.item_id}:${summaryIndex}`,
|
|
1928
|
+
metadata: {
|
|
1929
|
+
openai: {
|
|
1930
|
+
...makeItemIdMetadata(event.item_id),
|
|
1931
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1783
1932
|
}
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1933
|
+
}
|
|
1934
|
+
});
|
|
1935
|
+
reasoningPart.summaryParts[Number(summaryIndex)] = "concluded";
|
|
1787
1936
|
}
|
|
1788
|
-
reasoningPart.summaryParts[event.summary_index] = "active";
|
|
1789
1937
|
}
|
|
1938
|
+
}
|
|
1939
|
+
if (Predicate.isUndefined(reasoningPart.summaryParts[event.summary_index])) {
|
|
1940
|
+
reasoningPart.summaryParts[event.summary_index] = "active";
|
|
1790
1941
|
parts.push({
|
|
1791
1942
|
type: "reasoning-start",
|
|
1792
1943
|
id: `${event.item_id}:${event.summary_index}`,
|
|
@@ -1807,15 +1958,14 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1807
1958
|
id: `${event.item_id}:${event.summary_index}`,
|
|
1808
1959
|
delta: event.delta,
|
|
1809
1960
|
metadata: {
|
|
1810
|
-
openai:
|
|
1811
|
-
...makeItemIdMetadata(event.item_id)
|
|
1812
|
-
}
|
|
1961
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1813
1962
|
}
|
|
1814
1963
|
});
|
|
1815
1964
|
break;
|
|
1816
1965
|
}
|
|
1817
1966
|
case "response.reasoning_summary_part.done":
|
|
1818
1967
|
{
|
|
1968
|
+
const reasoningPart = getOrCreateReasoningPart(event.item_id);
|
|
1819
1969
|
// When OpenAI stores message data, we can immediately conclude the
|
|
1820
1970
|
// reasoning part given that we do not need the encrypted content
|
|
1821
1971
|
if (config.store === true) {
|
|
@@ -1823,17 +1973,15 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1823
1973
|
type: "reasoning-end",
|
|
1824
1974
|
id: `${event.item_id}:${event.summary_index}`,
|
|
1825
1975
|
metadata: {
|
|
1826
|
-
openai:
|
|
1827
|
-
...makeItemIdMetadata(event.item_id)
|
|
1828
|
-
}
|
|
1976
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1829
1977
|
}
|
|
1830
1978
|
});
|
|
1831
1979
|
// Mark the summary part concluded
|
|
1832
|
-
|
|
1980
|
+
reasoningPart.summaryParts[event.summary_index] = "concluded";
|
|
1833
1981
|
} else {
|
|
1834
1982
|
// Mark the summary part as can-conclude given we still need a
|
|
1835
1983
|
// final summary part with the encrypted content
|
|
1836
|
-
|
|
1984
|
+
reasoningPart.summaryParts[event.summary_index] = "can-conclude";
|
|
1837
1985
|
}
|
|
1838
1986
|
break;
|
|
1839
1987
|
}
|
|
@@ -1936,14 +2084,18 @@ const prepareTools = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1936
2084
|
}
|
|
1937
2085
|
// Convert the tools in the toolkit to the provider-defined format
|
|
1938
2086
|
for (const tool of allowedTools) {
|
|
1939
|
-
if (Tool.isUserDefined(tool)) {
|
|
2087
|
+
if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) {
|
|
1940
2088
|
const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true;
|
|
2089
|
+
const description = Tool.getDescription(tool);
|
|
2090
|
+
const parameters = yield* tryToolJsonSchema(tool, "prepareTools");
|
|
1941
2091
|
tools.push({
|
|
1942
2092
|
type: "function",
|
|
1943
2093
|
name: tool.name,
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2094
|
+
parameters,
|
|
2095
|
+
strict,
|
|
2096
|
+
...(Predicate.isNotUndefined(description) ? {
|
|
2097
|
+
description
|
|
2098
|
+
} : undefined)
|
|
1947
2099
|
});
|
|
1948
2100
|
}
|
|
1949
2101
|
if (Tool.isProviderDefined(tool)) {
|
|
@@ -2111,29 +2263,53 @@ const getEncryptedContent = part => part.options.openai?.encryptedContent ?? nul
|
|
|
2111
2263
|
const getImageDetail = part => part.options.openai?.imageDetail ?? "auto";
|
|
2112
2264
|
const makeItemIdMetadata = itemId => Predicate.isNotUndefined(itemId) ? {
|
|
2113
2265
|
itemId
|
|
2114
|
-
} :
|
|
2266
|
+
} : {};
|
|
2115
2267
|
const makeEncryptedContentMetadata = encryptedContent => Predicate.isNotNullish(encryptedContent) ? {
|
|
2116
2268
|
encryptedContent
|
|
2117
2269
|
} : undefined;
|
|
2118
|
-
const
|
|
2270
|
+
const unsupportedSchemaError = (error, method) => AiError.make({
|
|
2271
|
+
module: "OpenAiLanguageModel",
|
|
2272
|
+
method,
|
|
2273
|
+
reason: new AiError.UnsupportedSchemaError({
|
|
2274
|
+
description: error instanceof Error ? error.message : String(error)
|
|
2275
|
+
})
|
|
2276
|
+
});
|
|
2277
|
+
const tryCodecTransform = (schema, method) => Effect.try({
|
|
2278
|
+
try: () => toCodecOpenAI(schema),
|
|
2279
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2280
|
+
});
|
|
2281
|
+
const tryJsonSchema = (schema, method) => Effect.try({
|
|
2282
|
+
try: () => Tool.getJsonSchemaFromSchema(schema, {
|
|
2283
|
+
transformer: toCodecOpenAI
|
|
2284
|
+
}),
|
|
2285
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2286
|
+
});
|
|
2287
|
+
const tryToolJsonSchema = (tool, method) => Effect.try({
|
|
2288
|
+
try: () => Tool.getJsonSchema(tool, {
|
|
2289
|
+
transformer: toCodecOpenAI
|
|
2290
|
+
}),
|
|
2291
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2292
|
+
});
|
|
2293
|
+
const prepareResponseFormat = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
2119
2294
|
config,
|
|
2120
2295
|
options
|
|
2121
|
-
})
|
|
2296
|
+
}) {
|
|
2122
2297
|
if (options.responseFormat.type === "json") {
|
|
2123
2298
|
const name = options.responseFormat.objectName;
|
|
2124
2299
|
const schema = options.responseFormat.schema;
|
|
2300
|
+
const jsonSchema = yield* tryJsonSchema(schema, "prepareResponseFormat");
|
|
2125
2301
|
return {
|
|
2126
2302
|
type: "json_schema",
|
|
2127
2303
|
name,
|
|
2128
2304
|
description: AST.resolveDescription(schema.ast) ?? "Response with a JSON object",
|
|
2129
|
-
schema:
|
|
2305
|
+
schema: jsonSchema,
|
|
2130
2306
|
strict: config.strictJsonSchema ?? true
|
|
2131
2307
|
};
|
|
2132
2308
|
}
|
|
2133
2309
|
return {
|
|
2134
2310
|
type: "text"
|
|
2135
2311
|
};
|
|
2136
|
-
};
|
|
2312
|
+
});
|
|
2137
2313
|
const getModelCapabilities = modelId => {
|
|
2138
2314
|
const supportsFlexProcessing = modelId.startsWith("o3") || modelId.startsWith("o4-mini") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat");
|
|
2139
2315
|
const supportsPriorityProcessing = modelId.startsWith("gpt-4") || modelId.startsWith("gpt-5-mini") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-nano") && !modelId.startsWith("gpt-5-chat") || modelId.startsWith("o3") || modelId.startsWith("o4-mini");
|
|
@@ -2170,6 +2346,35 @@ const getApprovalRequestIdMapping = prompt => {
|
|
|
2170
2346
|
}
|
|
2171
2347
|
return mapping;
|
|
2172
2348
|
};
|
|
2349
|
+
const normalizeMcpToolCall = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
2350
|
+
toolNameMapper,
|
|
2351
|
+
toolParams,
|
|
2352
|
+
method
|
|
2353
|
+
}) {
|
|
2354
|
+
const toolName = toolNameMapper.getCustomName("mcp");
|
|
2355
|
+
if (typeof toolParams !== "string") {
|
|
2356
|
+
return {
|
|
2357
|
+
toolName,
|
|
2358
|
+
params: toolParams
|
|
2359
|
+
};
|
|
2360
|
+
}
|
|
2361
|
+
const params = yield* Effect.try({
|
|
2362
|
+
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
2363
|
+
catch: cause => AiError.make({
|
|
2364
|
+
module: "OpenAiLanguageModel",
|
|
2365
|
+
method,
|
|
2366
|
+
reason: new AiError.ToolParameterValidationError({
|
|
2367
|
+
toolName,
|
|
2368
|
+
toolParams,
|
|
2369
|
+
description: `Failed to securely JSON parse tool parameters: ${cause}`
|
|
2370
|
+
})
|
|
2371
|
+
})
|
|
2372
|
+
});
|
|
2373
|
+
return {
|
|
2374
|
+
toolName,
|
|
2375
|
+
params
|
|
2376
|
+
};
|
|
2377
|
+
});
|
|
2173
2378
|
const getUsage = usage => {
|
|
2174
2379
|
if (Predicate.isNullish(usage)) {
|
|
2175
2380
|
return {
|
|
@@ -2188,8 +2393,8 @@ const getUsage = usage => {
|
|
|
2188
2393
|
}
|
|
2189
2394
|
const inputTokens = usage.input_tokens;
|
|
2190
2395
|
const outputTokens = usage.output_tokens;
|
|
2191
|
-
const cachedTokens = usage.input_tokens_details
|
|
2192
|
-
const reasoningTokens = usage.output_tokens_details
|
|
2396
|
+
const cachedTokens = getUsageTokenDetail(usage.input_tokens_details, "cached_tokens");
|
|
2397
|
+
const reasoningTokens = getUsageTokenDetail(usage.output_tokens_details, "reasoning_tokens");
|
|
2193
2398
|
return {
|
|
2194
2399
|
inputTokens: {
|
|
2195
2400
|
uncached: inputTokens - cachedTokens,
|
|
@@ -2204,4 +2409,49 @@ const getUsage = usage => {
|
|
|
2204
2409
|
}
|
|
2205
2410
|
};
|
|
2206
2411
|
};
|
|
2412
|
+
const toServiceTier = value => {
|
|
2413
|
+
switch (value) {
|
|
2414
|
+
case "default":
|
|
2415
|
+
case "auto":
|
|
2416
|
+
case "flex":
|
|
2417
|
+
case "scale":
|
|
2418
|
+
case "priority":
|
|
2419
|
+
return {
|
|
2420
|
+
metadata: {
|
|
2421
|
+
openai: {
|
|
2422
|
+
serviceTier: value
|
|
2423
|
+
}
|
|
2424
|
+
}
|
|
2425
|
+
};
|
|
2426
|
+
default:
|
|
2427
|
+
return undefined;
|
|
2428
|
+
}
|
|
2429
|
+
};
|
|
2430
|
+
const getUsageTokenDetail = (details, key) => Predicate.hasProperty(details, key) && typeof details[key] === "number" ? details[key] : 0;
|
|
2431
|
+
const transformToolCallParams = /*#__PURE__*/Effect.fnUntraced(function* (tools, toolName, toolParams) {
|
|
2432
|
+
const tool = tools.find(tool => tool.name === toolName);
|
|
2433
|
+
if (Predicate.isUndefined(tool)) {
|
|
2434
|
+
return yield* AiError.make({
|
|
2435
|
+
module: "OpenAiLanguageModel",
|
|
2436
|
+
method: "makeResponse",
|
|
2437
|
+
reason: new AiError.ToolNotFoundError({
|
|
2438
|
+
toolName,
|
|
2439
|
+
availableTools: tools.map(tool => tool.name)
|
|
2440
|
+
})
|
|
2441
|
+
});
|
|
2442
|
+
}
|
|
2443
|
+
const {
|
|
2444
|
+
codec
|
|
2445
|
+
} = yield* tryCodecTransform(tool.parametersSchema, "makeResponse");
|
|
2446
|
+
const transform = Schema.decodeEffect(codec);
|
|
2447
|
+
return yield* transform(toolParams).pipe(Effect.mapError(error => AiError.make({
|
|
2448
|
+
module: "OpenAiLanguageModel",
|
|
2449
|
+
method: "makeResponse",
|
|
2450
|
+
reason: new AiError.ToolParameterValidationError({
|
|
2451
|
+
toolName,
|
|
2452
|
+
toolParams,
|
|
2453
|
+
description: error.issue.toString()
|
|
2454
|
+
})
|
|
2455
|
+
})));
|
|
2456
|
+
});
|
|
2207
2457
|
//# sourceMappingURL=OpenAiLanguageModel.js.map
|