@effect/ai-openai 4.0.0-beta.9 → 4.0.0-beta.90
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 +66675 -37672
- 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 +170 -29
- package/dist/OpenAiClient.d.ts.map +1 -1
- package/dist/OpenAiClient.js +321 -46
- 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 +88 -10
- package/dist/OpenAiConfig.d.ts.map +1 -1
- package/dist/OpenAiConfig.js +42 -7
- package/dist/OpenAiConfig.js.map +1 -1
- package/dist/OpenAiEmbeddingModel.d.ts +188 -0
- package/dist/OpenAiEmbeddingModel.d.ts.map +1 -0
- package/dist/OpenAiEmbeddingModel.js +194 -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 +357 -63
- package/dist/OpenAiLanguageModel.d.ts.map +1 -1
- package/dist/OpenAiLanguageModel.js +390 -168
- package/dist/OpenAiLanguageModel.js.map +1 -1
- package/dist/OpenAiSchema.d.ts +2325 -0
- package/dist/OpenAiSchema.d.ts.map +1 -0
- package/dist/OpenAiSchema.js +811 -0
- package/dist/OpenAiSchema.js.map +1 -0
- package/dist/OpenAiTelemetry.d.ts +63 -22
- package/dist/OpenAiTelemetry.d.ts.map +1 -1
- package/dist/OpenAiTelemetry.js +20 -10
- package/dist/OpenAiTelemetry.js.map +1 -1
- package/dist/OpenAiTool.d.ts +157 -67
- package/dist/OpenAiTool.d.ts.map +1 -1
- package/dist/OpenAiTool.js +125 -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/dist/internal/utilities.js +0 -4
- package/dist/internal/utilities.js.map +1 -1
- package/package.json +3 -3
- package/src/Generated.ts +9720 -4890
- package/src/OpenAiClient.ts +499 -98
- package/src/OpenAiClientGenerated.ts +202 -0
- package/src/OpenAiConfig.ts +89 -11
- package/src/OpenAiEmbeddingModel.ts +332 -0
- package/src/OpenAiError.ts +170 -35
- package/src/OpenAiLanguageModel.ts +776 -169
- package/src/OpenAiSchema.ts +1286 -0
- package/src/OpenAiTelemetry.ts +69 -28
- package/src/OpenAiTool.ts +126 -40
- package/src/index.ts +22 -33
- package/src/internal/errors.ts +6 -4
- package/src/internal/utilities.ts +0 -6
|
@@ -1,26 +1,30 @@
|
|
|
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
|
+
* non-streaming or streaming response results back into Effect AI response
|
|
7
|
+
* content and metadata.
|
|
3
8
|
*
|
|
4
|
-
*
|
|
5
|
-
* supporting text generation, structured output, tool calling, and streaming.
|
|
6
|
-
*
|
|
7
|
-
* @since 1.0.0
|
|
9
|
+
* @since 4.0.0
|
|
8
10
|
*/
|
|
11
|
+
import * as Context from "effect/Context";
|
|
9
12
|
import * as DateTime from "effect/DateTime";
|
|
10
13
|
import * as Effect from "effect/Effect";
|
|
11
14
|
import * as Encoding from "effect/Encoding";
|
|
12
15
|
import { dual } from "effect/Function";
|
|
13
16
|
import * as Layer from "effect/Layer";
|
|
17
|
+
import * as Option from "effect/Option";
|
|
14
18
|
import * as Predicate from "effect/Predicate";
|
|
15
19
|
import * as Redactable from "effect/Redactable";
|
|
16
20
|
import * as Schema from "effect/Schema";
|
|
17
21
|
import * as AST from "effect/SchemaAST";
|
|
18
|
-
import * as ServiceMap from "effect/ServiceMap";
|
|
19
22
|
import * as Stream from "effect/Stream";
|
|
20
23
|
import * as AiError from "effect/unstable/ai/AiError";
|
|
21
24
|
import * as IdGenerator from "effect/unstable/ai/IdGenerator";
|
|
22
25
|
import * as LanguageModel from "effect/unstable/ai/LanguageModel";
|
|
23
26
|
import * as AiModel from "effect/unstable/ai/Model";
|
|
27
|
+
import { toCodecOpenAI } from "effect/unstable/ai/OpenAiStructuredOutput";
|
|
24
28
|
import * as Tool from "effect/unstable/ai/Tool";
|
|
25
29
|
import * as Generated from "./Generated.js";
|
|
26
30
|
import * as InternalUtilities from "./internal/utilities.js";
|
|
@@ -32,38 +36,77 @@ const SharedModelIds = Generated.ModelIdsShared.members[1];
|
|
|
32
36
|
// Configuration
|
|
33
37
|
// =============================================================================
|
|
34
38
|
/**
|
|
35
|
-
*
|
|
39
|
+
* Context service for OpenAI language model configuration.
|
|
40
|
+
*
|
|
41
|
+
* **When to use**
|
|
42
|
+
*
|
|
43
|
+
* Use when you need to provide OpenAI Responses API request defaults through
|
|
44
|
+
* Effect context for language model operations.
|
|
45
|
+
*
|
|
46
|
+
* **Details**
|
|
47
|
+
*
|
|
48
|
+
* Config values are merged with the config object passed to `model`, `make`, or
|
|
49
|
+
* `layer`, with scoped context values taking precedence.
|
|
50
|
+
*
|
|
51
|
+
* @see {@link withConfigOverride} for scoping language model request overrides
|
|
36
52
|
*
|
|
37
|
-
* @since 1.0.0
|
|
38
53
|
* @category services
|
|
54
|
+
* @since 4.0.0
|
|
39
55
|
*/
|
|
40
|
-
export class Config extends /*#__PURE__*/
|
|
56
|
+
export class Config extends /*#__PURE__*/Context.Service()("@effect/ai-openai/OpenAiLanguageModel/Config") {}
|
|
41
57
|
// =============================================================================
|
|
42
58
|
// Language Model
|
|
43
59
|
// =============================================================================
|
|
44
60
|
/**
|
|
45
|
-
*
|
|
61
|
+
* Creates an OpenAI model descriptor that can be provided with
|
|
62
|
+
* `Effect.provide`.
|
|
63
|
+
*
|
|
64
|
+
* **When to use**
|
|
65
|
+
*
|
|
66
|
+
* Use when you want an OpenAI language model value that carries provider and
|
|
67
|
+
* model metadata and can be supplied directly to an Effect program.
|
|
68
|
+
*
|
|
69
|
+
* @see {@link layer} for creating a `LanguageModel.LanguageModel` layer directly
|
|
70
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
71
|
+
*
|
|
46
72
|
* @category constructors
|
|
73
|
+
* @since 4.0.0
|
|
47
74
|
*/
|
|
48
|
-
export const model = (model, config) => AiModel.make("openai", layer({
|
|
75
|
+
export const model = (model, config) => AiModel.make("openai", model, layer({
|
|
49
76
|
model,
|
|
50
77
|
config
|
|
51
78
|
}));
|
|
52
79
|
// TODO
|
|
53
80
|
// /**
|
|
54
|
-
// * @since
|
|
81
|
+
// * @since 4.0.0
|
|
55
82
|
// * @category constructors
|
|
56
83
|
// */
|
|
57
84
|
// export const modelWithTokenizer = (
|
|
58
85
|
// model: (string & {}) | Model,
|
|
59
86
|
// config?: Omit<typeof Config.Service, "model">
|
|
60
87
|
// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> =>
|
|
61
|
-
// AiModel.make("openai", layerWithTokenizer({ model, config }))
|
|
88
|
+
// AiModel.make("openai", model, layerWithTokenizer({ model, config }))
|
|
62
89
|
/**
|
|
63
|
-
* Creates an OpenAI
|
|
90
|
+
* Creates an OpenAI `LanguageModel` service from a model identifier and
|
|
91
|
+
* optional request defaults.
|
|
92
|
+
*
|
|
93
|
+
* **When to use**
|
|
94
|
+
*
|
|
95
|
+
* Use to construct an OpenAI Responses API language model service backed by
|
|
96
|
+
* `OpenAiClient`.
|
|
97
|
+
*
|
|
98
|
+
* **Details**
|
|
99
|
+
*
|
|
100
|
+
* The returned effect requires `OpenAiClient`. Request defaults from the
|
|
101
|
+
* `config` option are merged with any `Config` service in the context, with
|
|
102
|
+
* context values taking precedence. The service supports both `generateText`
|
|
103
|
+
* and `streamText`.
|
|
104
|
+
*
|
|
105
|
+
* @see {@link layer} for providing the service as a `Layer`
|
|
106
|
+
* @see {@link model} for creating a model descriptor for `Effect.provide`
|
|
64
107
|
*
|
|
65
|
-
* @since 1.0.0
|
|
66
108
|
* @category constructors
|
|
109
|
+
* @since 4.0.0
|
|
67
110
|
*/
|
|
68
111
|
export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
69
112
|
model,
|
|
@@ -71,7 +114,7 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
71
114
|
}) {
|
|
72
115
|
const client = yield* OpenAiClient;
|
|
73
116
|
const makeConfig = Effect.gen(function* () {
|
|
74
|
-
const services = yield* Effect.
|
|
117
|
+
const services = yield* Effect.context();
|
|
75
118
|
return {
|
|
76
119
|
model,
|
|
77
120
|
...providerConfig,
|
|
@@ -100,28 +143,31 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
100
143
|
options,
|
|
101
144
|
toolNameMapper
|
|
102
145
|
});
|
|
103
|
-
const responseFormat = prepareResponseFormat({
|
|
146
|
+
const responseFormat = yield* prepareResponseFormat({
|
|
104
147
|
config,
|
|
105
148
|
options
|
|
106
149
|
});
|
|
150
|
+
const {
|
|
151
|
+
fileIdPrefixes: _fip,
|
|
152
|
+
strictJsonSchema: _sjs,
|
|
153
|
+
...apiConfig
|
|
154
|
+
} = config;
|
|
107
155
|
const request = {
|
|
108
|
-
...
|
|
156
|
+
...apiConfig,
|
|
109
157
|
input: messages,
|
|
110
|
-
include: include.size > 0 ? Array.from(include) :
|
|
158
|
+
include: include.size > 0 ? Array.from(include) : undefined,
|
|
111
159
|
text: {
|
|
112
|
-
verbosity: config.text?.verbosity ??
|
|
160
|
+
verbosity: config.text?.verbosity ?? undefined,
|
|
113
161
|
format: responseFormat
|
|
114
|
-
}
|
|
115
|
-
...(Predicate.isNotUndefined(tools) ? {
|
|
116
|
-
tools
|
|
117
|
-
} : undefined),
|
|
118
|
-
...(Predicate.isNotUndefined(toolChoice) ? {
|
|
119
|
-
tool_choice: toolChoice
|
|
120
|
-
} : undefined)
|
|
162
|
+
}
|
|
121
163
|
};
|
|
164
|
+
if (tools) request.tools = tools;
|
|
165
|
+
if (toolChoice) request.tool_choice = toolChoice;
|
|
166
|
+
if (options.previousResponseId) request.previous_response_id = options.previousResponseId;
|
|
122
167
|
return request;
|
|
123
168
|
});
|
|
124
169
|
return yield* LanguageModel.make({
|
|
170
|
+
codecTransformer: toCodecOpenAI,
|
|
125
171
|
generateText: Effect.fnUntraced(function* (options) {
|
|
126
172
|
const config = yield* makeConfig;
|
|
127
173
|
const toolNameMapper = new Tool.NameMapper(options.tools);
|
|
@@ -164,17 +210,49 @@ export const make = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
164
210
|
});
|
|
165
211
|
});
|
|
166
212
|
/**
|
|
167
|
-
* Creates a layer
|
|
213
|
+
* Creates a layer that provides the OpenAI `LanguageModel.LanguageModel`
|
|
214
|
+
* service.
|
|
215
|
+
*
|
|
216
|
+
* **When to use**
|
|
217
|
+
*
|
|
218
|
+
* Use when composing application layers and you want OpenAI to satisfy
|
|
219
|
+
* `LanguageModel.LanguageModel` while supplying `OpenAiClient` from another
|
|
220
|
+
* layer.
|
|
221
|
+
*
|
|
222
|
+
* **Details**
|
|
223
|
+
*
|
|
224
|
+
* The `config` option supplies request defaults for the selected model. Scoped
|
|
225
|
+
* values from `withConfigOverride` are merged when each request is built and
|
|
226
|
+
* take precedence over these defaults.
|
|
227
|
+
*
|
|
228
|
+
* @see {@link make} for constructing the language model service effectfully
|
|
229
|
+
* @see {@link model} for creating a model descriptor for `Effect.provide`
|
|
230
|
+
* @see {@link withConfigOverride} for scoped request configuration overrides
|
|
168
231
|
*
|
|
169
|
-
* @since 1.0.0
|
|
170
232
|
* @category layers
|
|
233
|
+
* @since 4.0.0
|
|
171
234
|
*/
|
|
172
235
|
export const layer = options => Layer.effect(LanguageModel.LanguageModel, make(options));
|
|
173
236
|
/**
|
|
174
|
-
* Provides config overrides for OpenAI language model operations.
|
|
237
|
+
* Provides scoped config overrides for OpenAI language model operations.
|
|
238
|
+
*
|
|
239
|
+
* **When to use**
|
|
240
|
+
*
|
|
241
|
+
* Use to apply OpenAI Responses API config overrides around one or more
|
|
242
|
+
* language model operations without changing the defaults passed to `model`,
|
|
243
|
+
* `make`, or `layer`.
|
|
244
|
+
*
|
|
245
|
+
* **Details**
|
|
246
|
+
*
|
|
247
|
+
* The override is dual, so it can be used in pipe form or as
|
|
248
|
+
* `withConfigOverride(effect, overrides)`. Overrides are merged with any
|
|
249
|
+
* existing `Config` service in the current context, and the override values take
|
|
250
|
+
* precedence.
|
|
251
|
+
*
|
|
252
|
+
* @see {@link Config} for the scoped configuration service consumed by this function
|
|
175
253
|
*
|
|
176
|
-
* @since 1.0.0
|
|
177
254
|
* @category configuration
|
|
255
|
+
* @since 4.0.0
|
|
178
256
|
*/
|
|
179
257
|
export const withConfigOverride = /*#__PURE__*/dual(2, (self, overrides) => Effect.flatMap(Effect.serviceOption(Config), config => Effect.provideService(self, Config, {
|
|
180
258
|
...(config._tag === "Some" ? config.value : {}),
|
|
@@ -207,14 +285,15 @@ const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
207
285
|
if (config.store === false && capabilities.isReasoningModel) {
|
|
208
286
|
include.add("reasoning.encrypted_content");
|
|
209
287
|
}
|
|
210
|
-
if (
|
|
288
|
+
if (codeInterpreterTool) {
|
|
211
289
|
include.add("code_interpreter_call.outputs");
|
|
212
290
|
}
|
|
213
|
-
if (
|
|
291
|
+
if (webSearchTool || webSearchPreviewTool) {
|
|
214
292
|
include.add("web_search_call.action.sources");
|
|
215
293
|
}
|
|
216
294
|
const messages = [];
|
|
217
|
-
|
|
295
|
+
const prompt = options.incrementalPrompt ?? options.prompt;
|
|
296
|
+
for (const message of prompt.content) {
|
|
218
297
|
switch (message.role) {
|
|
219
298
|
case "system":
|
|
220
299
|
{
|
|
@@ -378,7 +457,9 @@ const prepareMessages = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
378
457
|
type: "reasoning",
|
|
379
458
|
id,
|
|
380
459
|
summary: summaryParts,
|
|
381
|
-
|
|
460
|
+
...(Predicate.isNotNull(encryptedContent) ? {
|
|
461
|
+
encrypted_content: encryptedContent
|
|
462
|
+
} : undefined)
|
|
382
463
|
};
|
|
383
464
|
messages.push(reasoningMessages[id]);
|
|
384
465
|
} else {
|
|
@@ -569,13 +650,15 @@ const buildHttpRequestDetails = request => ({
|
|
|
569
650
|
method: request.method,
|
|
570
651
|
url: request.url,
|
|
571
652
|
urlParams: Array.from(request.urlParams),
|
|
572
|
-
hash: request.hash,
|
|
653
|
+
hash: Option.getOrUndefined(request.hash),
|
|
573
654
|
headers: Redactable.redact(request.headers)
|
|
574
655
|
});
|
|
575
656
|
const buildHttpResponseDetails = response => ({
|
|
576
657
|
status: response.status,
|
|
577
658
|
headers: Redactable.redact(response.headers)
|
|
578
659
|
});
|
|
660
|
+
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"]);
|
|
661
|
+
const isKnownResponseStreamEvent = event => knownResponseStreamEventTypes.has(event.type);
|
|
579
662
|
const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
580
663
|
options,
|
|
581
664
|
rawResponse,
|
|
@@ -609,9 +692,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
609
692
|
operation: part.operation
|
|
610
693
|
},
|
|
611
694
|
metadata: {
|
|
612
|
-
openai:
|
|
613
|
-
...makeItemIdMetadata(part.id)
|
|
614
|
-
}
|
|
695
|
+
openai: makeItemIdMetadata(part.id)
|
|
615
696
|
}
|
|
616
697
|
});
|
|
617
698
|
break;
|
|
@@ -669,9 +750,8 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
669
750
|
{
|
|
670
751
|
hasToolCalls = true;
|
|
671
752
|
const toolName = part.name;
|
|
672
|
-
const toolParams =
|
|
673
|
-
|
|
674
|
-
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
753
|
+
const toolParams = yield* Effect.try({
|
|
754
|
+
try: () => Tool.unsafeSecureJsonParse(part.arguments),
|
|
675
755
|
catch: cause => AiError.make({
|
|
676
756
|
module: "OpenAiLanguageModel",
|
|
677
757
|
method: "makeResponse",
|
|
@@ -682,15 +762,14 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
682
762
|
})
|
|
683
763
|
})
|
|
684
764
|
});
|
|
765
|
+
const params = yield* transformToolCallParams(options.tools, part.name, toolParams);
|
|
685
766
|
parts.push({
|
|
686
767
|
type: "tool-call",
|
|
687
768
|
id: part.call_id,
|
|
688
769
|
name: toolName,
|
|
689
770
|
params,
|
|
690
771
|
metadata: {
|
|
691
|
-
openai:
|
|
692
|
-
...makeItemIdMetadata(part.id)
|
|
693
|
-
}
|
|
772
|
+
openai: makeItemIdMetadata(part.id)
|
|
694
773
|
}
|
|
695
774
|
});
|
|
696
775
|
break;
|
|
@@ -727,9 +806,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
727
806
|
action: part.action
|
|
728
807
|
},
|
|
729
808
|
metadata: {
|
|
730
|
-
openai:
|
|
731
|
-
...makeItemIdMetadata(part.id)
|
|
732
|
-
}
|
|
809
|
+
openai: makeItemIdMetadata(part.id)
|
|
733
810
|
}
|
|
734
811
|
});
|
|
735
812
|
break;
|
|
@@ -737,12 +814,19 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
737
814
|
case "mcp_call":
|
|
738
815
|
{
|
|
739
816
|
const toolId = Predicate.isNotNullish(part.approval_request_id) ? approvalRequests.get(part.approval_request_id) ?? part.id : part.id;
|
|
740
|
-
const
|
|
817
|
+
const {
|
|
818
|
+
toolName,
|
|
819
|
+
params
|
|
820
|
+
} = yield* normalizeMcpToolCall({
|
|
821
|
+
toolNameMapper,
|
|
822
|
+
toolParams: part.arguments,
|
|
823
|
+
method: "makeResponse"
|
|
824
|
+
});
|
|
741
825
|
parts.push({
|
|
742
826
|
type: "tool-call",
|
|
743
827
|
id: toolId,
|
|
744
828
|
name: toolName,
|
|
745
|
-
params
|
|
829
|
+
params,
|
|
746
830
|
providerExecuted: true
|
|
747
831
|
});
|
|
748
832
|
parts.push({
|
|
@@ -752,7 +836,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
752
836
|
isFailure: false,
|
|
753
837
|
providerExecuted: true,
|
|
754
838
|
result: {
|
|
755
|
-
type: "
|
|
839
|
+
type: "mcp_call",
|
|
756
840
|
name: part.name,
|
|
757
841
|
arguments: part.arguments,
|
|
758
842
|
server_label: part.server_label,
|
|
@@ -764,9 +848,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
764
848
|
} : undefined)
|
|
765
849
|
},
|
|
766
850
|
metadata: {
|
|
767
|
-
openai:
|
|
768
|
-
...makeItemIdMetadata(part.id)
|
|
769
|
-
}
|
|
851
|
+
openai: makeItemIdMetadata(part.id)
|
|
770
852
|
}
|
|
771
853
|
});
|
|
772
854
|
break;
|
|
@@ -780,18 +862,13 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
780
862
|
{
|
|
781
863
|
const approvalRequestId = part.approval_request_id ?? part.id;
|
|
782
864
|
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
|
-
})
|
|
865
|
+
const {
|
|
866
|
+
toolName,
|
|
867
|
+
params
|
|
868
|
+
} = yield* normalizeMcpToolCall({
|
|
869
|
+
toolNameMapper,
|
|
870
|
+
toolParams: part.arguments,
|
|
871
|
+
method: "makeResponse"
|
|
795
872
|
});
|
|
796
873
|
parts.push({
|
|
797
874
|
type: "tool-call",
|
|
@@ -952,9 +1029,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
952
1029
|
action: part.action
|
|
953
1030
|
},
|
|
954
1031
|
metadata: {
|
|
955
|
-
openai:
|
|
956
|
-
...makeItemIdMetadata(part.id)
|
|
957
|
-
}
|
|
1032
|
+
openai: makeItemIdMetadata(part.id)
|
|
958
1033
|
}
|
|
959
1034
|
});
|
|
960
1035
|
break;
|
|
@@ -990,13 +1065,7 @@ const makeResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
990
1065
|
reason: finishReason,
|
|
991
1066
|
usage: getUsage(rawResponse.usage),
|
|
992
1067
|
response: buildHttpResponseDetails(response),
|
|
993
|
-
...(rawResponse.service_tier
|
|
994
|
-
metadata: {
|
|
995
|
-
openai: {
|
|
996
|
-
serviceTier: rawResponse.service_tier
|
|
997
|
-
}
|
|
998
|
-
}
|
|
999
|
-
})
|
|
1068
|
+
...toServiceTier(rawResponse.service_tier)
|
|
1000
1069
|
});
|
|
1001
1070
|
return parts;
|
|
1002
1071
|
});
|
|
@@ -1015,11 +1084,29 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1015
1084
|
const activeAnnotations = [];
|
|
1016
1085
|
// Track active reasoning items with state machine for proper concluding logic
|
|
1017
1086
|
const activeReasoning = {};
|
|
1087
|
+
const getOrCreateReasoningPart = (itemId, encryptedContent) => {
|
|
1088
|
+
const activePart = activeReasoning[itemId];
|
|
1089
|
+
if (Predicate.isNotUndefined(activePart)) {
|
|
1090
|
+
if (Predicate.isNotNullish(encryptedContent)) {
|
|
1091
|
+
activePart.encryptedContent = encryptedContent;
|
|
1092
|
+
}
|
|
1093
|
+
return activePart;
|
|
1094
|
+
}
|
|
1095
|
+
const reasoningPart = {
|
|
1096
|
+
encryptedContent: Predicate.isNotNullish(encryptedContent) ? encryptedContent : undefined,
|
|
1097
|
+
summaryParts: {}
|
|
1098
|
+
};
|
|
1099
|
+
activeReasoning[itemId] = reasoningPart;
|
|
1100
|
+
return reasoningPart;
|
|
1101
|
+
};
|
|
1018
1102
|
// Track active tool calls with optional provider-specific state
|
|
1019
1103
|
const activeToolCalls = {};
|
|
1020
1104
|
const webSearchTool = options.tools.find(tool => Tool.isProviderDefined(tool) && (tool.name === "OpenAiWebSearch" || tool.name === "OpenAiWebSearchPreview"));
|
|
1021
1105
|
return stream.pipe(Stream.mapEffect(Effect.fnUntraced(function* (event) {
|
|
1022
1106
|
const parts = [];
|
|
1107
|
+
if (!isKnownResponseStreamEvent(event)) {
|
|
1108
|
+
return parts;
|
|
1109
|
+
}
|
|
1023
1110
|
switch (event.type) {
|
|
1024
1111
|
case "response.created":
|
|
1025
1112
|
{
|
|
@@ -1050,13 +1137,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1050
1137
|
reason: InternalUtilities.resolveFinishReason(event.response.incomplete_details?.reason, hasToolCalls),
|
|
1051
1138
|
usage: getUsage(event.response.usage),
|
|
1052
1139
|
response: buildHttpResponseDetails(response),
|
|
1053
|
-
...(event.response.service_tier
|
|
1054
|
-
metadata: {
|
|
1055
|
-
openai: {
|
|
1056
|
-
serviceTier: event.response.service_tier
|
|
1057
|
-
}
|
|
1058
|
-
}
|
|
1059
|
-
})
|
|
1140
|
+
...toServiceTier(event.response.service_tier)
|
|
1060
1141
|
});
|
|
1061
1142
|
break;
|
|
1062
1143
|
}
|
|
@@ -1157,7 +1238,10 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1157
1238
|
{
|
|
1158
1239
|
activeToolCalls[event.output_index] = {
|
|
1159
1240
|
id: event.item.call_id,
|
|
1160
|
-
name: event.item.name
|
|
1241
|
+
name: event.item.name,
|
|
1242
|
+
functionCall: {
|
|
1243
|
+
emitted: false
|
|
1244
|
+
}
|
|
1161
1245
|
};
|
|
1162
1246
|
parts.push({
|
|
1163
1247
|
type: "tool-params-start",
|
|
@@ -1195,39 +1279,34 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1195
1279
|
type: "text-start",
|
|
1196
1280
|
id: event.item.id,
|
|
1197
1281
|
metadata: {
|
|
1198
|
-
openai:
|
|
1199
|
-
...makeItemIdMetadata(event.item.id)
|
|
1200
|
-
}
|
|
1282
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1201
1283
|
}
|
|
1202
1284
|
});
|
|
1203
1285
|
break;
|
|
1204
1286
|
}
|
|
1205
1287
|
case "reasoning":
|
|
1206
1288
|
{
|
|
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)
|
|
1289
|
+
const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content);
|
|
1290
|
+
if (Predicate.isUndefined(reasoningPart.summaryParts[0])) {
|
|
1291
|
+
reasoningPart.summaryParts[0] = "active";
|
|
1292
|
+
parts.push({
|
|
1293
|
+
type: "reasoning-start",
|
|
1294
|
+
id: `${event.item.id}:0`,
|
|
1295
|
+
metadata: {
|
|
1296
|
+
openai: {
|
|
1297
|
+
...makeItemIdMetadata(event.item.id),
|
|
1298
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1299
|
+
}
|
|
1221
1300
|
}
|
|
1222
|
-
}
|
|
1223
|
-
}
|
|
1301
|
+
});
|
|
1302
|
+
}
|
|
1224
1303
|
break;
|
|
1225
1304
|
}
|
|
1226
1305
|
case "shell_call":
|
|
1227
1306
|
{
|
|
1228
1307
|
const toolName = toolNameMapper.getCustomName("shell");
|
|
1229
1308
|
activeToolCalls[event.output_index] = {
|
|
1230
|
-
id: event.item.id,
|
|
1309
|
+
id: event.item.id ?? event.item.call_id,
|
|
1231
1310
|
name: toolName
|
|
1232
1311
|
};
|
|
1233
1312
|
break;
|
|
@@ -1272,7 +1351,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1272
1351
|
parts.push({
|
|
1273
1352
|
type: "tool-params-delta",
|
|
1274
1353
|
id: toolCall.id,
|
|
1275
|
-
delta: InternalUtilities.escapeJSONDelta(event.item.operation.diff)
|
|
1354
|
+
delta: InternalUtilities.escapeJSONDelta(event.item.operation.diff ?? "")
|
|
1276
1355
|
});
|
|
1277
1356
|
}
|
|
1278
1357
|
parts.push({
|
|
@@ -1298,9 +1377,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1298
1377
|
operation: event.item.operation
|
|
1299
1378
|
},
|
|
1300
1379
|
metadata: {
|
|
1301
|
-
openai:
|
|
1302
|
-
...makeItemIdMetadata(event.item.id)
|
|
1303
|
-
}
|
|
1380
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1304
1381
|
}
|
|
1305
1382
|
});
|
|
1306
1383
|
}
|
|
@@ -1372,12 +1449,17 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1372
1449
|
}
|
|
1373
1450
|
case "function_call":
|
|
1374
1451
|
{
|
|
1452
|
+
const toolCall = activeToolCalls[event.output_index];
|
|
1453
|
+
if (Predicate.isNotUndefined(toolCall?.functionCall?.emitted) && toolCall.functionCall.emitted) {
|
|
1454
|
+
delete activeToolCalls[event.output_index];
|
|
1455
|
+
break;
|
|
1456
|
+
}
|
|
1375
1457
|
delete activeToolCalls[event.output_index];
|
|
1376
1458
|
hasToolCalls = true;
|
|
1377
1459
|
const toolName = event.item.name;
|
|
1378
|
-
const
|
|
1379
|
-
const
|
|
1380
|
-
try: () => Tool.unsafeSecureJsonParse(
|
|
1460
|
+
const toolArgs = event.item.arguments;
|
|
1461
|
+
const toolParams = yield* Effect.try({
|
|
1462
|
+
try: () => Tool.unsafeSecureJsonParse(toolArgs),
|
|
1381
1463
|
catch: cause => AiError.make({
|
|
1382
1464
|
module: "OpenAiLanguageModel",
|
|
1383
1465
|
method: "makeStreamResponse",
|
|
@@ -1388,6 +1470,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1388
1470
|
})
|
|
1389
1471
|
})
|
|
1390
1472
|
});
|
|
1473
|
+
const params = yield* transformToolCallParams(options.tools, toolName, toolParams);
|
|
1391
1474
|
parts.push({
|
|
1392
1475
|
type: "tool-params-end",
|
|
1393
1476
|
id: event.item.call_id
|
|
@@ -1398,9 +1481,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1398
1481
|
name: toolName,
|
|
1399
1482
|
params,
|
|
1400
1483
|
metadata: {
|
|
1401
|
-
openai:
|
|
1402
|
-
...makeItemIdMetadata(event.item.id)
|
|
1403
|
-
}
|
|
1484
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1404
1485
|
}
|
|
1405
1486
|
});
|
|
1406
1487
|
break;
|
|
@@ -1431,9 +1512,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1431
1512
|
action: event.item.action
|
|
1432
1513
|
},
|
|
1433
1514
|
metadata: {
|
|
1434
|
-
openai:
|
|
1435
|
-
...makeItemIdMetadata(event.item.id)
|
|
1436
|
-
}
|
|
1515
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1437
1516
|
}
|
|
1438
1517
|
});
|
|
1439
1518
|
break;
|
|
@@ -1443,12 +1522,19 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1443
1522
|
const approvalRequestId = event.item.approval_request_id;
|
|
1444
1523
|
// Track approval with our own tool call identifiers
|
|
1445
1524
|
const toolId = Predicate.isNotNullish(approvalRequestId) ? streamApprovalRequests.get(approvalRequestId) ?? approvalRequests.get(approvalRequestId) ?? event.item.id : event.item.id;
|
|
1446
|
-
const
|
|
1525
|
+
const {
|
|
1526
|
+
toolName,
|
|
1527
|
+
params
|
|
1528
|
+
} = yield* normalizeMcpToolCall({
|
|
1529
|
+
toolNameMapper,
|
|
1530
|
+
toolParams: event.item.arguments,
|
|
1531
|
+
method: "makeStreamResponse"
|
|
1532
|
+
});
|
|
1447
1533
|
parts.push({
|
|
1448
1534
|
type: "tool-call",
|
|
1449
1535
|
id: toolId,
|
|
1450
1536
|
name: toolName,
|
|
1451
|
-
params
|
|
1537
|
+
params,
|
|
1452
1538
|
providerExecuted: true
|
|
1453
1539
|
});
|
|
1454
1540
|
parts.push({
|
|
@@ -1458,7 +1544,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1458
1544
|
isFailure: false,
|
|
1459
1545
|
providerExecuted: true,
|
|
1460
1546
|
result: {
|
|
1461
|
-
type: "
|
|
1547
|
+
type: "mcp_call",
|
|
1462
1548
|
name: event.item.name,
|
|
1463
1549
|
arguments: event.item.arguments,
|
|
1464
1550
|
server_label: event.item.server_label,
|
|
@@ -1470,9 +1556,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1470
1556
|
} : undefined)
|
|
1471
1557
|
},
|
|
1472
1558
|
metadata: {
|
|
1473
|
-
openai:
|
|
1474
|
-
...makeItemIdMetadata(event.item.id)
|
|
1475
|
-
}
|
|
1559
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1476
1560
|
}
|
|
1477
1561
|
});
|
|
1478
1562
|
break;
|
|
@@ -1487,12 +1571,19 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1487
1571
|
const toolId = yield* idGenerator.generateId();
|
|
1488
1572
|
const approvalRequestId = event.item.approval_request_id ?? event.item.id;
|
|
1489
1573
|
streamApprovalRequests.set(approvalRequestId, toolId);
|
|
1490
|
-
const
|
|
1574
|
+
const {
|
|
1575
|
+
toolName,
|
|
1576
|
+
params
|
|
1577
|
+
} = yield* normalizeMcpToolCall({
|
|
1578
|
+
toolNameMapper,
|
|
1579
|
+
toolParams: event.item.arguments,
|
|
1580
|
+
method: "makeStreamResponse"
|
|
1581
|
+
});
|
|
1491
1582
|
parts.push({
|
|
1492
1583
|
type: "tool-call",
|
|
1493
1584
|
id: toolId,
|
|
1494
1585
|
name: toolName,
|
|
1495
|
-
params
|
|
1586
|
+
params,
|
|
1496
1587
|
providerExecuted: true
|
|
1497
1588
|
});
|
|
1498
1589
|
parts.push({
|
|
@@ -1521,7 +1612,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1521
1612
|
}
|
|
1522
1613
|
case "reasoning":
|
|
1523
1614
|
{
|
|
1524
|
-
const reasoningPart =
|
|
1615
|
+
const reasoningPart = getOrCreateReasoningPart(event.item.id, event.item.encrypted_content);
|
|
1525
1616
|
for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) {
|
|
1526
1617
|
if (status === "active" || status === "can-conclude") {
|
|
1527
1618
|
parts.push({
|
|
@@ -1530,7 +1621,7 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1530
1621
|
metadata: {
|
|
1531
1622
|
openai: {
|
|
1532
1623
|
...makeItemIdMetadata(event.item.id),
|
|
1533
|
-
...makeEncryptedContentMetadata(
|
|
1624
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1534
1625
|
}
|
|
1535
1626
|
}
|
|
1536
1627
|
});
|
|
@@ -1545,15 +1636,13 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1545
1636
|
const toolName = toolNameMapper.getCustomName("shell");
|
|
1546
1637
|
parts.push({
|
|
1547
1638
|
type: "tool-call",
|
|
1548
|
-
id: event.item.id,
|
|
1639
|
+
id: event.item.id ?? event.item.call_id,
|
|
1549
1640
|
name: toolName,
|
|
1550
1641
|
params: {
|
|
1551
1642
|
action: event.item.action
|
|
1552
1643
|
},
|
|
1553
1644
|
metadata: {
|
|
1554
|
-
openai:
|
|
1555
|
-
...makeItemIdMetadata(event.item.id)
|
|
1556
|
-
}
|
|
1645
|
+
openai: makeItemIdMetadata(event.item.id)
|
|
1557
1646
|
}
|
|
1558
1647
|
});
|
|
1559
1648
|
break;
|
|
@@ -1670,6 +1759,41 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1670
1759
|
}
|
|
1671
1760
|
break;
|
|
1672
1761
|
}
|
|
1762
|
+
case "response.function_call_arguments.done":
|
|
1763
|
+
{
|
|
1764
|
+
const toolCall = activeToolCalls[event.output_index];
|
|
1765
|
+
if (Predicate.isNotUndefined(toolCall?.functionCall) && !toolCall.functionCall.emitted) {
|
|
1766
|
+
hasToolCalls = true;
|
|
1767
|
+
const toolParams = yield* Effect.try({
|
|
1768
|
+
try: () => Tool.unsafeSecureJsonParse(event.arguments),
|
|
1769
|
+
catch: cause => AiError.make({
|
|
1770
|
+
module: "OpenAiLanguageModel",
|
|
1771
|
+
method: "makeStreamResponse",
|
|
1772
|
+
reason: new AiError.ToolParameterValidationError({
|
|
1773
|
+
toolName: toolCall.name,
|
|
1774
|
+
toolParams: {},
|
|
1775
|
+
description: `Failed securely JSON parse tool parameters: ${cause}`
|
|
1776
|
+
})
|
|
1777
|
+
})
|
|
1778
|
+
});
|
|
1779
|
+
const params = yield* transformToolCallParams(options.tools, toolCall.name, toolParams);
|
|
1780
|
+
parts.push({
|
|
1781
|
+
type: "tool-params-end",
|
|
1782
|
+
id: toolCall.id
|
|
1783
|
+
});
|
|
1784
|
+
parts.push({
|
|
1785
|
+
type: "tool-call",
|
|
1786
|
+
id: toolCall.id,
|
|
1787
|
+
name: toolCall.name,
|
|
1788
|
+
params,
|
|
1789
|
+
metadata: {
|
|
1790
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1791
|
+
}
|
|
1792
|
+
});
|
|
1793
|
+
toolCall.functionCall.emitted = true;
|
|
1794
|
+
}
|
|
1795
|
+
break;
|
|
1796
|
+
}
|
|
1673
1797
|
case "response.apply_patch_call_operation_diff.delta":
|
|
1674
1798
|
{
|
|
1675
1799
|
const toolCall = activeToolCalls[event.output_index];
|
|
@@ -1765,28 +1889,27 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1765
1889
|
}
|
|
1766
1890
|
case "response.reasoning_summary_part.added":
|
|
1767
1891
|
{
|
|
1768
|
-
|
|
1892
|
+
const reasoningPart = getOrCreateReasoningPart(event.item_id);
|
|
1769
1893
|
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
|
-
}
|
|
1894
|
+
// Conclude all can-conclude parts before starting new one
|
|
1895
|
+
for (const [summaryIndex, status] of Object.entries(reasoningPart.summaryParts)) {
|
|
1896
|
+
if (status === "can-conclude") {
|
|
1897
|
+
parts.push({
|
|
1898
|
+
type: "reasoning-end",
|
|
1899
|
+
id: `${event.item_id}:${summaryIndex}`,
|
|
1900
|
+
metadata: {
|
|
1901
|
+
openai: {
|
|
1902
|
+
...makeItemIdMetadata(event.item_id),
|
|
1903
|
+
...makeEncryptedContentMetadata(reasoningPart.encryptedContent)
|
|
1783
1904
|
}
|
|
1784
|
-
}
|
|
1785
|
-
|
|
1786
|
-
|
|
1905
|
+
}
|
|
1906
|
+
});
|
|
1907
|
+
reasoningPart.summaryParts[Number(summaryIndex)] = "concluded";
|
|
1787
1908
|
}
|
|
1788
|
-
reasoningPart.summaryParts[event.summary_index] = "active";
|
|
1789
1909
|
}
|
|
1910
|
+
}
|
|
1911
|
+
if (Predicate.isUndefined(reasoningPart.summaryParts[event.summary_index])) {
|
|
1912
|
+
reasoningPart.summaryParts[event.summary_index] = "active";
|
|
1790
1913
|
parts.push({
|
|
1791
1914
|
type: "reasoning-start",
|
|
1792
1915
|
id: `${event.item_id}:${event.summary_index}`,
|
|
@@ -1807,15 +1930,14 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1807
1930
|
id: `${event.item_id}:${event.summary_index}`,
|
|
1808
1931
|
delta: event.delta,
|
|
1809
1932
|
metadata: {
|
|
1810
|
-
openai:
|
|
1811
|
-
...makeItemIdMetadata(event.item_id)
|
|
1812
|
-
}
|
|
1933
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1813
1934
|
}
|
|
1814
1935
|
});
|
|
1815
1936
|
break;
|
|
1816
1937
|
}
|
|
1817
1938
|
case "response.reasoning_summary_part.done":
|
|
1818
1939
|
{
|
|
1940
|
+
const reasoningPart = getOrCreateReasoningPart(event.item_id);
|
|
1819
1941
|
// When OpenAI stores message data, we can immediately conclude the
|
|
1820
1942
|
// reasoning part given that we do not need the encrypted content
|
|
1821
1943
|
if (config.store === true) {
|
|
@@ -1823,17 +1945,15 @@ const makeStreamResponse = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1823
1945
|
type: "reasoning-end",
|
|
1824
1946
|
id: `${event.item_id}:${event.summary_index}`,
|
|
1825
1947
|
metadata: {
|
|
1826
|
-
openai:
|
|
1827
|
-
...makeItemIdMetadata(event.item_id)
|
|
1828
|
-
}
|
|
1948
|
+
openai: makeItemIdMetadata(event.item_id)
|
|
1829
1949
|
}
|
|
1830
1950
|
});
|
|
1831
1951
|
// Mark the summary part concluded
|
|
1832
|
-
|
|
1952
|
+
reasoningPart.summaryParts[event.summary_index] = "concluded";
|
|
1833
1953
|
} else {
|
|
1834
1954
|
// Mark the summary part as can-conclude given we still need a
|
|
1835
1955
|
// final summary part with the encrypted content
|
|
1836
|
-
|
|
1956
|
+
reasoningPart.summaryParts[event.summary_index] = "can-conclude";
|
|
1837
1957
|
}
|
|
1838
1958
|
break;
|
|
1839
1959
|
}
|
|
@@ -1936,14 +2056,18 @@ const prepareTools = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
|
1936
2056
|
}
|
|
1937
2057
|
// Convert the tools in the toolkit to the provider-defined format
|
|
1938
2058
|
for (const tool of allowedTools) {
|
|
1939
|
-
if (Tool.isUserDefined(tool)) {
|
|
2059
|
+
if (Tool.isUserDefined(tool) || Tool.isDynamic(tool)) {
|
|
1940
2060
|
const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true;
|
|
2061
|
+
const description = Tool.getDescription(tool);
|
|
2062
|
+
const parameters = yield* tryToolJsonSchema(tool, "prepareTools");
|
|
1941
2063
|
tools.push({
|
|
1942
2064
|
type: "function",
|
|
1943
2065
|
name: tool.name,
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
2066
|
+
parameters,
|
|
2067
|
+
strict,
|
|
2068
|
+
...(Predicate.isNotUndefined(description) ? {
|
|
2069
|
+
description
|
|
2070
|
+
} : undefined)
|
|
1947
2071
|
});
|
|
1948
2072
|
}
|
|
1949
2073
|
if (Tool.isProviderDefined(tool)) {
|
|
@@ -2111,29 +2235,53 @@ const getEncryptedContent = part => part.options.openai?.encryptedContent ?? nul
|
|
|
2111
2235
|
const getImageDetail = part => part.options.openai?.imageDetail ?? "auto";
|
|
2112
2236
|
const makeItemIdMetadata = itemId => Predicate.isNotUndefined(itemId) ? {
|
|
2113
2237
|
itemId
|
|
2114
|
-
} :
|
|
2238
|
+
} : {};
|
|
2115
2239
|
const makeEncryptedContentMetadata = encryptedContent => Predicate.isNotNullish(encryptedContent) ? {
|
|
2116
2240
|
encryptedContent
|
|
2117
2241
|
} : undefined;
|
|
2118
|
-
const
|
|
2242
|
+
const unsupportedSchemaError = (error, method) => AiError.make({
|
|
2243
|
+
module: "OpenAiLanguageModel",
|
|
2244
|
+
method,
|
|
2245
|
+
reason: new AiError.UnsupportedSchemaError({
|
|
2246
|
+
description: error instanceof Error ? error.message : String(error)
|
|
2247
|
+
})
|
|
2248
|
+
});
|
|
2249
|
+
const tryCodecTransform = (schema, method) => Effect.try({
|
|
2250
|
+
try: () => toCodecOpenAI(schema),
|
|
2251
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2252
|
+
});
|
|
2253
|
+
const tryJsonSchema = (schema, method) => Effect.try({
|
|
2254
|
+
try: () => Tool.getJsonSchemaFromSchema(schema, {
|
|
2255
|
+
transformer: toCodecOpenAI
|
|
2256
|
+
}),
|
|
2257
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2258
|
+
});
|
|
2259
|
+
const tryToolJsonSchema = (tool, method) => Effect.try({
|
|
2260
|
+
try: () => Tool.getJsonSchema(tool, {
|
|
2261
|
+
transformer: toCodecOpenAI
|
|
2262
|
+
}),
|
|
2263
|
+
catch: error => unsupportedSchemaError(error, method)
|
|
2264
|
+
});
|
|
2265
|
+
const prepareResponseFormat = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
2119
2266
|
config,
|
|
2120
2267
|
options
|
|
2121
|
-
})
|
|
2268
|
+
}) {
|
|
2122
2269
|
if (options.responseFormat.type === "json") {
|
|
2123
2270
|
const name = options.responseFormat.objectName;
|
|
2124
2271
|
const schema = options.responseFormat.schema;
|
|
2272
|
+
const jsonSchema = yield* tryJsonSchema(schema, "prepareResponseFormat");
|
|
2125
2273
|
return {
|
|
2126
2274
|
type: "json_schema",
|
|
2127
2275
|
name,
|
|
2128
2276
|
description: AST.resolveDescription(schema.ast) ?? "Response with a JSON object",
|
|
2129
|
-
schema:
|
|
2277
|
+
schema: jsonSchema,
|
|
2130
2278
|
strict: config.strictJsonSchema ?? true
|
|
2131
2279
|
};
|
|
2132
2280
|
}
|
|
2133
2281
|
return {
|
|
2134
2282
|
type: "text"
|
|
2135
2283
|
};
|
|
2136
|
-
};
|
|
2284
|
+
});
|
|
2137
2285
|
const getModelCapabilities = modelId => {
|
|
2138
2286
|
const supportsFlexProcessing = modelId.startsWith("o3") || modelId.startsWith("o4-mini") || modelId.startsWith("gpt-5") && !modelId.startsWith("gpt-5-chat");
|
|
2139
2287
|
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 +2318,35 @@ const getApprovalRequestIdMapping = prompt => {
|
|
|
2170
2318
|
}
|
|
2171
2319
|
return mapping;
|
|
2172
2320
|
};
|
|
2321
|
+
const normalizeMcpToolCall = /*#__PURE__*/Effect.fnUntraced(function* ({
|
|
2322
|
+
toolNameMapper,
|
|
2323
|
+
toolParams,
|
|
2324
|
+
method
|
|
2325
|
+
}) {
|
|
2326
|
+
const toolName = toolNameMapper.getCustomName("mcp");
|
|
2327
|
+
if (typeof toolParams !== "string") {
|
|
2328
|
+
return {
|
|
2329
|
+
toolName,
|
|
2330
|
+
params: toolParams
|
|
2331
|
+
};
|
|
2332
|
+
}
|
|
2333
|
+
const params = yield* Effect.try({
|
|
2334
|
+
try: () => Tool.unsafeSecureJsonParse(toolParams),
|
|
2335
|
+
catch: cause => AiError.make({
|
|
2336
|
+
module: "OpenAiLanguageModel",
|
|
2337
|
+
method,
|
|
2338
|
+
reason: new AiError.ToolParameterValidationError({
|
|
2339
|
+
toolName,
|
|
2340
|
+
toolParams,
|
|
2341
|
+
description: `Failed to securely JSON parse tool parameters: ${cause}`
|
|
2342
|
+
})
|
|
2343
|
+
})
|
|
2344
|
+
});
|
|
2345
|
+
return {
|
|
2346
|
+
toolName,
|
|
2347
|
+
params
|
|
2348
|
+
};
|
|
2349
|
+
});
|
|
2173
2350
|
const getUsage = usage => {
|
|
2174
2351
|
if (Predicate.isNullish(usage)) {
|
|
2175
2352
|
return {
|
|
@@ -2188,8 +2365,8 @@ const getUsage = usage => {
|
|
|
2188
2365
|
}
|
|
2189
2366
|
const inputTokens = usage.input_tokens;
|
|
2190
2367
|
const outputTokens = usage.output_tokens;
|
|
2191
|
-
const cachedTokens = usage.input_tokens_details
|
|
2192
|
-
const reasoningTokens = usage.output_tokens_details
|
|
2368
|
+
const cachedTokens = getUsageTokenDetail(usage.input_tokens_details, "cached_tokens");
|
|
2369
|
+
const reasoningTokens = getUsageTokenDetail(usage.output_tokens_details, "reasoning_tokens");
|
|
2193
2370
|
return {
|
|
2194
2371
|
inputTokens: {
|
|
2195
2372
|
uncached: inputTokens - cachedTokens,
|
|
@@ -2204,4 +2381,49 @@ const getUsage = usage => {
|
|
|
2204
2381
|
}
|
|
2205
2382
|
};
|
|
2206
2383
|
};
|
|
2384
|
+
const toServiceTier = value => {
|
|
2385
|
+
switch (value) {
|
|
2386
|
+
case "default":
|
|
2387
|
+
case "auto":
|
|
2388
|
+
case "flex":
|
|
2389
|
+
case "scale":
|
|
2390
|
+
case "priority":
|
|
2391
|
+
return {
|
|
2392
|
+
metadata: {
|
|
2393
|
+
openai: {
|
|
2394
|
+
serviceTier: value
|
|
2395
|
+
}
|
|
2396
|
+
}
|
|
2397
|
+
};
|
|
2398
|
+
default:
|
|
2399
|
+
return undefined;
|
|
2400
|
+
}
|
|
2401
|
+
};
|
|
2402
|
+
const getUsageTokenDetail = (details, key) => Predicate.hasProperty(details, key) && typeof details[key] === "number" ? details[key] : 0;
|
|
2403
|
+
const transformToolCallParams = /*#__PURE__*/Effect.fnUntraced(function* (tools, toolName, toolParams) {
|
|
2404
|
+
const tool = tools.find(tool => tool.name === toolName);
|
|
2405
|
+
if (Predicate.isUndefined(tool)) {
|
|
2406
|
+
return yield* AiError.make({
|
|
2407
|
+
module: "OpenAiLanguageModel",
|
|
2408
|
+
method: "makeResponse",
|
|
2409
|
+
reason: new AiError.ToolNotFoundError({
|
|
2410
|
+
toolName,
|
|
2411
|
+
availableTools: tools.map(tool => tool.name)
|
|
2412
|
+
})
|
|
2413
|
+
});
|
|
2414
|
+
}
|
|
2415
|
+
const {
|
|
2416
|
+
codec
|
|
2417
|
+
} = yield* tryCodecTransform(tool.parametersSchema, "makeResponse");
|
|
2418
|
+
const transform = Schema.decodeEffect(codec);
|
|
2419
|
+
return yield* transform(toolParams).pipe(Effect.mapError(error => AiError.make({
|
|
2420
|
+
module: "OpenAiLanguageModel",
|
|
2421
|
+
method: "makeResponse",
|
|
2422
|
+
reason: new AiError.ToolParameterValidationError({
|
|
2423
|
+
toolName,
|
|
2424
|
+
toolParams,
|
|
2425
|
+
description: error.issue.toString()
|
|
2426
|
+
})
|
|
2427
|
+
})));
|
|
2428
|
+
});
|
|
2207
2429
|
//# sourceMappingURL=OpenAiLanguageModel.js.map
|