@effect/ai-openai 4.0.0-beta.2 → 4.0.0-beta.21
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 +4045 -4037
- 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 +3 -3
- package/dist/OpenAiClient.d.ts.map +1 -1
- package/dist/OpenAiError.d.ts +22 -32
- package/dist/OpenAiError.d.ts.map +1 -1
- package/dist/OpenAiLanguageModel.d.ts.map +1 -1
- package/dist/OpenAiLanguageModel.js +70 -20
- package/dist/OpenAiLanguageModel.js.map +1 -1
- package/dist/OpenAiTool.d.ts +24 -24
- package/package.json +3 -3
- package/src/Generated.ts +105 -121
- package/src/OpenAiClient.ts +3 -3
- package/src/OpenAiError.ts +24 -32
- package/src/OpenAiLanguageModel.ts +97 -20
package/src/OpenAiClient.ts
CHANGED
|
@@ -281,7 +281,7 @@ export const layerConfig = (options?: {
|
|
|
281
281
|
/**
|
|
282
282
|
* The config value to load for the API key.
|
|
283
283
|
*/
|
|
284
|
-
readonly apiKey?: Config.Config<Redacted.Redacted<string
|
|
284
|
+
readonly apiKey?: Config.Config<Redacted.Redacted<string> | undefined> | undefined
|
|
285
285
|
|
|
286
286
|
/**
|
|
287
287
|
* The config value to load for the API URL.
|
|
@@ -291,12 +291,12 @@ export const layerConfig = (options?: {
|
|
|
291
291
|
/**
|
|
292
292
|
* The config value to load for the organization ID.
|
|
293
293
|
*/
|
|
294
|
-
readonly organizationId?: Config.Config<Redacted.Redacted<string
|
|
294
|
+
readonly organizationId?: Config.Config<Redacted.Redacted<string> | undefined> | undefined
|
|
295
295
|
|
|
296
296
|
/**
|
|
297
297
|
* The config value to load for the project ID.
|
|
298
298
|
*/
|
|
299
|
-
readonly projectId?: Config.Config<Redacted.Redacted<string
|
|
299
|
+
readonly projectId?: Config.Config<Redacted.Redacted<string> | undefined> | undefined
|
|
300
300
|
|
|
301
301
|
/**
|
|
302
302
|
* Optional transformer for the HTTP client.
|
package/src/OpenAiError.ts
CHANGED
|
@@ -57,51 +57,43 @@ export type OpenAiRateLimitMetadata = OpenAiErrorMetadata & {
|
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
declare module "effect/unstable/ai/AiError" {
|
|
60
|
-
export interface
|
|
61
|
-
readonly
|
|
62
|
-
readonly openai?: OpenAiRateLimitMetadata | null
|
|
63
|
-
}
|
|
60
|
+
export interface RateLimitErrorMetadata {
|
|
61
|
+
readonly openai?: OpenAiRateLimitMetadata | null
|
|
64
62
|
}
|
|
65
63
|
|
|
66
|
-
export interface
|
|
67
|
-
readonly
|
|
68
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
69
|
-
}
|
|
64
|
+
export interface QuotaExhaustedErrorMetadata {
|
|
65
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
70
66
|
}
|
|
71
67
|
|
|
72
|
-
export interface
|
|
73
|
-
readonly
|
|
74
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
75
|
-
}
|
|
68
|
+
export interface AuthenticationErrorMetadata {
|
|
69
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
76
70
|
}
|
|
77
71
|
|
|
78
|
-
export interface
|
|
79
|
-
readonly
|
|
80
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
81
|
-
}
|
|
72
|
+
export interface ContentPolicyErrorMetadata {
|
|
73
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
82
74
|
}
|
|
83
75
|
|
|
84
|
-
export interface
|
|
85
|
-
readonly
|
|
86
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
87
|
-
}
|
|
76
|
+
export interface InvalidRequestErrorMetadata {
|
|
77
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
88
78
|
}
|
|
89
79
|
|
|
90
|
-
export interface
|
|
91
|
-
readonly
|
|
92
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
93
|
-
}
|
|
80
|
+
export interface InternalProviderErrorMetadata {
|
|
81
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
94
82
|
}
|
|
95
83
|
|
|
96
|
-
export interface
|
|
97
|
-
readonly
|
|
98
|
-
readonly openai?: OpenAiErrorMetadata | null
|
|
99
|
-
}
|
|
84
|
+
export interface InvalidOutputErrorMetadata {
|
|
85
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
100
86
|
}
|
|
101
87
|
|
|
102
|
-
export interface
|
|
103
|
-
readonly
|
|
104
|
-
|
|
105
|
-
|
|
88
|
+
export interface StructuredOutputErrorMetadata {
|
|
89
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
export interface UnsupportedSchemaErrorMetadata {
|
|
93
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
export interface UnknownErrorMetadata {
|
|
97
|
+
readonly openai?: OpenAiErrorMetadata | null
|
|
106
98
|
}
|
|
107
99
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import * as DateTime from "effect/DateTime"
|
|
10
10
|
import * as Effect from "effect/Effect"
|
|
11
|
-
import * as
|
|
11
|
+
import * as Encoding from "effect/Encoding"
|
|
12
12
|
import { dual } from "effect/Function"
|
|
13
13
|
import * as Layer from "effect/Layer"
|
|
14
14
|
import * as Predicate from "effect/Predicate"
|
|
@@ -23,6 +23,7 @@ import * as AiError from "effect/unstable/ai/AiError"
|
|
|
23
23
|
import * as IdGenerator from "effect/unstable/ai/IdGenerator"
|
|
24
24
|
import * as LanguageModel from "effect/unstable/ai/LanguageModel"
|
|
25
25
|
import * as AiModel from "effect/unstable/ai/Model"
|
|
26
|
+
import { toCodecOpenAI } from "effect/unstable/ai/OpenAiStructuredOutput"
|
|
26
27
|
import type * as Prompt from "effect/unstable/ai/Prompt"
|
|
27
28
|
import type * as Response from "effect/unstable/ai/Response"
|
|
28
29
|
import * as Tool from "effect/unstable/ai/Tool"
|
|
@@ -319,7 +320,7 @@ export const model = (
|
|
|
319
320
|
model: (string & {}) | Model,
|
|
320
321
|
config?: Omit<typeof Config.Service, "model">
|
|
321
322
|
): AiModel.Model<"openai", LanguageModel.LanguageModel, OpenAiClient> =>
|
|
322
|
-
AiModel.make("openai", layer({ model, config }))
|
|
323
|
+
AiModel.make("openai", model, layer({ model, config }))
|
|
323
324
|
|
|
324
325
|
// TODO
|
|
325
326
|
// /**
|
|
@@ -330,7 +331,7 @@ export const model = (
|
|
|
330
331
|
// model: (string & {}) | Model,
|
|
331
332
|
// config?: Omit<typeof Config.Service, "model">
|
|
332
333
|
// ): AiModel.Model<"openai", LanguageModel.LanguageModel | Tokenizer.Tokenizer, OpenAiClient> =>
|
|
333
|
-
// AiModel.make("openai", layerWithTokenizer({ model, config }))
|
|
334
|
+
// AiModel.make("openai", model, layerWithTokenizer({ model, config }))
|
|
334
335
|
|
|
335
336
|
/**
|
|
336
337
|
* Creates an OpenAI language model service.
|
|
@@ -369,7 +370,7 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
369
370
|
options,
|
|
370
371
|
toolNameMapper
|
|
371
372
|
})
|
|
372
|
-
const responseFormat = prepareResponseFormat({
|
|
373
|
+
const responseFormat = yield* prepareResponseFormat({
|
|
373
374
|
config,
|
|
374
375
|
options
|
|
375
376
|
})
|
|
@@ -429,7 +430,10 @@ export const make = Effect.fnUntraced(function*({ model, config: providerConfig
|
|
|
429
430
|
})
|
|
430
431
|
)
|
|
431
432
|
)
|
|
432
|
-
})
|
|
433
|
+
}).pipe(Effect.provideService(
|
|
434
|
+
LanguageModel.CurrentCodecTransformer,
|
|
435
|
+
toCodecOpenAI
|
|
436
|
+
))
|
|
433
437
|
})
|
|
434
438
|
|
|
435
439
|
/**
|
|
@@ -592,7 +596,7 @@ const prepareMessages = Effect.fnUntraced(
|
|
|
592
596
|
}
|
|
593
597
|
|
|
594
598
|
if (part.data instanceof Uint8Array) {
|
|
595
|
-
const base64 =
|
|
599
|
+
const base64 = Encoding.encodeBase64(part.data)
|
|
596
600
|
const imageUrl = `data:${mediaType};base64,${base64}`
|
|
597
601
|
content.push({ type: "input_image", image_url: imageUrl, detail })
|
|
598
602
|
}
|
|
@@ -606,7 +610,7 @@ const prepareMessages = Effect.fnUntraced(
|
|
|
606
610
|
}
|
|
607
611
|
|
|
608
612
|
if (part.data instanceof Uint8Array) {
|
|
609
|
-
const base64 =
|
|
613
|
+
const base64 = Encoding.encodeBase64(part.data)
|
|
610
614
|
const fileName = part.fileName ?? `part-${index}.pdf`
|
|
611
615
|
const fileData = `data:application/pdf;base64,${base64}`
|
|
612
616
|
content.push({ type: "input_file", filename: fileName, file_data: fileData })
|
|
@@ -1036,10 +1040,11 @@ const makeResponse = Effect.fnUntraced(
|
|
|
1036
1040
|
|
|
1037
1041
|
case "function_call": {
|
|
1038
1042
|
hasToolCalls = true
|
|
1043
|
+
|
|
1039
1044
|
const toolName = part.name
|
|
1040
|
-
|
|
1041
|
-
const
|
|
1042
|
-
try: () => Tool.unsafeSecureJsonParse(
|
|
1045
|
+
|
|
1046
|
+
const toolParams = yield* Effect.try({
|
|
1047
|
+
try: () => Tool.unsafeSecureJsonParse(part.arguments),
|
|
1043
1048
|
catch: (cause) =>
|
|
1044
1049
|
AiError.make({
|
|
1045
1050
|
module: "OpenAiLanguageModel",
|
|
@@ -1051,6 +1056,9 @@ const makeResponse = Effect.fnUntraced(
|
|
|
1051
1056
|
})
|
|
1052
1057
|
})
|
|
1053
1058
|
})
|
|
1059
|
+
|
|
1060
|
+
const params = yield* transformToolCallParams(options.tools, part.name, toolParams)
|
|
1061
|
+
|
|
1054
1062
|
parts.push({
|
|
1055
1063
|
type: "tool-call",
|
|
1056
1064
|
id: part.call_id,
|
|
@@ -1730,11 +1738,14 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
1730
1738
|
|
|
1731
1739
|
case "function_call": {
|
|
1732
1740
|
delete activeToolCalls[event.output_index]
|
|
1741
|
+
|
|
1733
1742
|
hasToolCalls = true
|
|
1743
|
+
|
|
1734
1744
|
const toolName = event.item.name
|
|
1735
|
-
const
|
|
1736
|
-
|
|
1737
|
-
|
|
1745
|
+
const toolArgs = event.item.arguments
|
|
1746
|
+
|
|
1747
|
+
const toolParams = yield* Effect.try({
|
|
1748
|
+
try: () => Tool.unsafeSecureJsonParse(toolArgs),
|
|
1738
1749
|
catch: (cause) =>
|
|
1739
1750
|
AiError.make({
|
|
1740
1751
|
module: "OpenAiLanguageModel",
|
|
@@ -1746,10 +1757,14 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
1746
1757
|
})
|
|
1747
1758
|
})
|
|
1748
1759
|
})
|
|
1760
|
+
|
|
1761
|
+
const params = yield* transformToolCallParams(options.tools, toolName, toolParams)
|
|
1762
|
+
|
|
1749
1763
|
parts.push({
|
|
1750
1764
|
type: "tool-params-end",
|
|
1751
1765
|
id: event.item.call_id
|
|
1752
1766
|
})
|
|
1767
|
+
|
|
1753
1768
|
parts.push({
|
|
1754
1769
|
type: "tool-call",
|
|
1755
1770
|
id: event.item.call_id,
|
|
@@ -1757,6 +1772,7 @@ const makeStreamResponse = Effect.fnUntraced(
|
|
|
1757
1772
|
params,
|
|
1758
1773
|
metadata: { openai: { ...makeItemIdMetadata(event.item.id) } }
|
|
1759
1774
|
})
|
|
1775
|
+
|
|
1760
1776
|
break
|
|
1761
1777
|
}
|
|
1762
1778
|
|
|
@@ -2281,12 +2297,14 @@ const prepareTools = Effect.fnUntraced(function*<Tools extends ReadonlyArray<Too
|
|
|
2281
2297
|
for (const tool of allowedTools) {
|
|
2282
2298
|
if (Tool.isUserDefined(tool)) {
|
|
2283
2299
|
const strict = Tool.getStrictMode(tool) ?? config.strictJsonSchema ?? true
|
|
2300
|
+
const description = Tool.getDescription(tool)
|
|
2301
|
+
const parameters = yield* tryJsonSchema(tool.parametersSchema, "prepareTools")
|
|
2284
2302
|
tools.push({
|
|
2285
2303
|
type: "function",
|
|
2286
2304
|
name: tool.name,
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
|
|
2305
|
+
parameters,
|
|
2306
|
+
strict,
|
|
2307
|
+
...(Predicate.isNotUndefined(description) ? { description } : undefined)
|
|
2290
2308
|
})
|
|
2291
2309
|
}
|
|
2292
2310
|
|
|
@@ -2480,23 +2498,45 @@ const makeItemIdMetadata = (itemId: string | undefined) => Predicate.isNotUndefi
|
|
|
2480
2498
|
const makeEncryptedContentMetadata = (encryptedContent: string | null | undefined) =>
|
|
2481
2499
|
Predicate.isNotNullish(encryptedContent) ? { encryptedContent } : undefined
|
|
2482
2500
|
|
|
2483
|
-
const
|
|
2501
|
+
const unsupportedSchemaError = (error: unknown, method: string): AiError.AiError =>
|
|
2502
|
+
AiError.make({
|
|
2503
|
+
module: "OpenAiLanguageModel",
|
|
2504
|
+
method,
|
|
2505
|
+
reason: new AiError.UnsupportedSchemaError({
|
|
2506
|
+
description: error instanceof Error ? error.message : String(error)
|
|
2507
|
+
})
|
|
2508
|
+
})
|
|
2509
|
+
|
|
2510
|
+
const tryCodecTransform = <S extends Schema.Top>(schema: S, method: string) =>
|
|
2511
|
+
Effect.try({
|
|
2512
|
+
try: () => toCodecOpenAI(schema),
|
|
2513
|
+
catch: (error) => unsupportedSchemaError(error, method)
|
|
2514
|
+
})
|
|
2515
|
+
|
|
2516
|
+
const tryJsonSchema = <S extends Schema.Top>(schema: S, method: string) =>
|
|
2517
|
+
Effect.try({
|
|
2518
|
+
try: () => Tool.getJsonSchemaFromSchema(schema, { transformer: toCodecOpenAI }),
|
|
2519
|
+
catch: (error) => unsupportedSchemaError(error, method)
|
|
2520
|
+
})
|
|
2521
|
+
|
|
2522
|
+
const prepareResponseFormat = Effect.fnUntraced(function*({ config, options }: {
|
|
2484
2523
|
readonly config: typeof Config.Service
|
|
2485
2524
|
readonly options: LanguageModel.ProviderOptions
|
|
2486
|
-
}): typeof Generated.TextResponseFormatConfiguration.Encoded
|
|
2525
|
+
}): Effect.fn.Return<typeof Generated.TextResponseFormatConfiguration.Encoded, AiError.AiError> {
|
|
2487
2526
|
if (options.responseFormat.type === "json") {
|
|
2488
2527
|
const name = options.responseFormat.objectName
|
|
2489
2528
|
const schema = options.responseFormat.schema
|
|
2529
|
+
const jsonSchema = yield* tryJsonSchema(schema, "prepareResponseFormat")
|
|
2490
2530
|
return {
|
|
2491
2531
|
type: "json_schema",
|
|
2492
2532
|
name,
|
|
2493
2533
|
description: AST.resolveDescription(schema.ast) ?? "Response with a JSON object",
|
|
2494
|
-
schema:
|
|
2534
|
+
schema: jsonSchema,
|
|
2495
2535
|
strict: config.strictJsonSchema ?? true
|
|
2496
2536
|
}
|
|
2497
2537
|
}
|
|
2498
2538
|
return { type: "text" }
|
|
2499
|
-
}
|
|
2539
|
+
})
|
|
2500
2540
|
|
|
2501
2541
|
interface ModelCapabilities {
|
|
2502
2542
|
readonly isReasoningModel: boolean
|
|
@@ -2606,3 +2646,40 @@ const getUsage = (usage: Generated.ResponseUsage | null | undefined): Response.U
|
|
|
2606
2646
|
}
|
|
2607
2647
|
}
|
|
2608
2648
|
}
|
|
2649
|
+
|
|
2650
|
+
const transformToolCallParams = Effect.fnUntraced(function*<Tools extends ReadonlyArray<Tool.Any>>(
|
|
2651
|
+
tools: Tools,
|
|
2652
|
+
toolName: string,
|
|
2653
|
+
toolParams: unknown
|
|
2654
|
+
): Effect.fn.Return<unknown, AiError.AiError> {
|
|
2655
|
+
const tool = tools.find((tool) => tool.name === toolName)
|
|
2656
|
+
|
|
2657
|
+
if (Predicate.isUndefined(tool)) {
|
|
2658
|
+
return yield* AiError.make({
|
|
2659
|
+
module: "OpenAiLanguageModel",
|
|
2660
|
+
method: "makeResponse",
|
|
2661
|
+
reason: new AiError.ToolNotFoundError({
|
|
2662
|
+
toolName,
|
|
2663
|
+
availableTools: tools.map((tool) => tool.name)
|
|
2664
|
+
})
|
|
2665
|
+
})
|
|
2666
|
+
}
|
|
2667
|
+
|
|
2668
|
+
const { codec } = yield* tryCodecTransform(tool.parametersSchema, "makeResponse")
|
|
2669
|
+
|
|
2670
|
+
const transform = Schema.decodeEffect(codec)
|
|
2671
|
+
|
|
2672
|
+
return yield* (
|
|
2673
|
+
transform(toolParams) as Effect.Effect<unknown, Schema.SchemaError>
|
|
2674
|
+
).pipe(Effect.mapError((error) =>
|
|
2675
|
+
AiError.make({
|
|
2676
|
+
module: "OpenAiLanguageModel",
|
|
2677
|
+
method: "makeResponse",
|
|
2678
|
+
reason: new AiError.ToolParameterValidationError({
|
|
2679
|
+
toolName,
|
|
2680
|
+
toolParams,
|
|
2681
|
+
description: error.issue.toString()
|
|
2682
|
+
})
|
|
2683
|
+
})
|
|
2684
|
+
))
|
|
2685
|
+
})
|