@effect/ai-openai 0.29.1 → 0.30.0

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.
Files changed (62) hide show
  1. package/OpenAiTool/package.json +6 -0
  2. package/dist/cjs/Generated.js +5845 -4262
  3. package/dist/cjs/Generated.js.map +1 -1
  4. package/dist/cjs/OpenAiClient.js +1493 -129
  5. package/dist/cjs/OpenAiClient.js.map +1 -1
  6. package/dist/cjs/OpenAiEmbeddingModel.js +61 -50
  7. package/dist/cjs/OpenAiEmbeddingModel.js.map +1 -1
  8. package/dist/cjs/OpenAiLanguageModel.js +950 -326
  9. package/dist/cjs/OpenAiLanguageModel.js.map +1 -1
  10. package/dist/cjs/OpenAiTelemetry.js +4 -4
  11. package/dist/cjs/OpenAiTelemetry.js.map +1 -1
  12. package/dist/cjs/OpenAiTokenizer.js +46 -14
  13. package/dist/cjs/OpenAiTokenizer.js.map +1 -1
  14. package/dist/cjs/OpenAiTool.js +93 -0
  15. package/dist/cjs/OpenAiTool.js.map +1 -0
  16. package/dist/cjs/index.js +3 -1
  17. package/dist/cjs/internal/utilities.js +11 -3
  18. package/dist/cjs/internal/utilities.js.map +1 -1
  19. package/dist/dts/Generated.d.ts +19662 -11761
  20. package/dist/dts/Generated.d.ts.map +1 -1
  21. package/dist/dts/OpenAiClient.d.ts +3022 -14
  22. package/dist/dts/OpenAiClient.d.ts.map +1 -1
  23. package/dist/dts/OpenAiEmbeddingModel.d.ts +8 -8
  24. package/dist/dts/OpenAiEmbeddingModel.d.ts.map +1 -1
  25. package/dist/dts/OpenAiLanguageModel.d.ts +123 -43
  26. package/dist/dts/OpenAiLanguageModel.d.ts.map +1 -1
  27. package/dist/dts/OpenAiTelemetry.d.ts +4 -4
  28. package/dist/dts/OpenAiTelemetry.d.ts.map +1 -1
  29. package/dist/dts/OpenAiTokenizer.d.ts +1 -1
  30. package/dist/dts/OpenAiTokenizer.d.ts.map +1 -1
  31. package/dist/dts/OpenAiTool.d.ts +176 -0
  32. package/dist/dts/OpenAiTool.d.ts.map +1 -0
  33. package/dist/dts/index.d.ts +4 -0
  34. package/dist/dts/index.d.ts.map +1 -1
  35. package/dist/esm/Generated.js +5846 -12846
  36. package/dist/esm/Generated.js.map +1 -1
  37. package/dist/esm/OpenAiClient.js +1440 -128
  38. package/dist/esm/OpenAiClient.js.map +1 -1
  39. package/dist/esm/OpenAiEmbeddingModel.js +60 -49
  40. package/dist/esm/OpenAiEmbeddingModel.js.map +1 -1
  41. package/dist/esm/OpenAiLanguageModel.js +949 -325
  42. package/dist/esm/OpenAiLanguageModel.js.map +1 -1
  43. package/dist/esm/OpenAiTelemetry.js +4 -4
  44. package/dist/esm/OpenAiTelemetry.js.map +1 -1
  45. package/dist/esm/OpenAiTokenizer.js +46 -14
  46. package/dist/esm/OpenAiTokenizer.js.map +1 -1
  47. package/dist/esm/OpenAiTool.js +84 -0
  48. package/dist/esm/OpenAiTool.js.map +1 -0
  49. package/dist/esm/index.js +4 -0
  50. package/dist/esm/index.js.map +1 -1
  51. package/dist/esm/internal/utilities.js +10 -2
  52. package/dist/esm/internal/utilities.js.map +1 -1
  53. package/package.json +12 -4
  54. package/src/Generated.ts +9691 -5598
  55. package/src/OpenAiClient.ts +1761 -224
  56. package/src/OpenAiEmbeddingModel.ts +70 -62
  57. package/src/OpenAiLanguageModel.ts +1134 -369
  58. package/src/OpenAiTelemetry.ts +9 -9
  59. package/src/OpenAiTokenizer.ts +38 -39
  60. package/src/OpenAiTool.ts +110 -0
  61. package/src/index.ts +5 -0
  62. package/src/internal/utilities.ts +16 -4
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * @since 1.0.0
3
3
  */
4
- import * as AiTelemetry from "@effect/ai/AiTelemetry"
4
+ import * as Telemetry from "@effect/ai/Telemetry"
5
5
  import { dual } from "effect/Function"
6
6
  import * as Predicate from "effect/Predicate"
7
7
  import * as String from "effect/String"
@@ -18,9 +18,9 @@ import type { Simplify } from "effect/Types"
18
18
  * @category Models
19
19
  */
20
20
  export type OpenAiTelemetryAttributes = Simplify<
21
- & AiTelemetry.GenAITelemetryAttributes
22
- & AiTelemetry.AttributesWithPrefix<RequestAttributes, "gen_ai.openai.request">
23
- & AiTelemetry.AttributesWithPrefix<ResponseAttributes, "gen_ai.openai.request">
21
+ & Telemetry.GenAITelemetryAttributes
22
+ & Telemetry.AttributesWithPrefix<RequestAttributes, "gen_ai.openai.request">
23
+ & Telemetry.AttributesWithPrefix<ResponseAttributes, "gen_ai.openai.request">
24
24
  >
25
25
 
26
26
  /**
@@ -30,7 +30,7 @@ export type OpenAiTelemetryAttributes = Simplify<
30
30
  * @since 1.0.0
31
31
  * @category Models
32
32
  */
33
- export type AllAttributes = AiTelemetry.AllAttributes & RequestAttributes & ResponseAttributes
33
+ export type AllAttributes = Telemetry.AllAttributes & RequestAttributes & ResponseAttributes
34
34
 
35
35
  /**
36
36
  * Telemetry attributes which are part of the GenAI specification and are
@@ -97,17 +97,17 @@ export type WellKnownServiceTier = "auto" | "default"
97
97
  * @since 1.0.0
98
98
  * @since Models
99
99
  */
100
- export type OpenAiTelemetryAttributeOptions = AiTelemetry.GenAITelemetryAttributeOptions & {
100
+ export type OpenAiTelemetryAttributeOptions = Telemetry.GenAITelemetryAttributeOptions & {
101
101
  openai?: {
102
102
  request?: RequestAttributes | undefined
103
103
  response?: ResponseAttributes | undefined
104
104
  } | undefined
105
105
  }
106
106
 
107
- const addOpenAiRequestAttributes = AiTelemetry.addSpanAttributes("gen_ai.openai.request", String.camelToSnake)<
107
+ const addOpenAiRequestAttributes = Telemetry.addSpanAttributes("gen_ai.openai.request", String.camelToSnake)<
108
108
  RequestAttributes
109
109
  >
110
- const addOpenAiResponseAttributes = AiTelemetry.addSpanAttributes("gen_ai.openai.response", String.camelToSnake)<
110
+ const addOpenAiResponseAttributes = Telemetry.addSpanAttributes("gen_ai.openai.response", String.camelToSnake)<
111
111
  ResponseAttributes
112
112
  >
113
113
 
@@ -142,7 +142,7 @@ export const addGenAIAnnotations = dual<
142
142
  */
143
143
  (span: Span, options: OpenAiTelemetryAttributeOptions) => void
144
144
  >(2, (span, options) => {
145
- AiTelemetry.addGenAIAnnotations(span, options)
145
+ Telemetry.addGenAIAnnotations(span, options)
146
146
  if (Predicate.isNotNullable(options.openai)) {
147
147
  if (Predicate.isNotNullable(options.openai.request)) {
148
148
  addOpenAiRequestAttributes(span, options.openai.request)
@@ -1,14 +1,11 @@
1
1
  /**
2
2
  * @since 1.0.0
3
3
  */
4
- import { AiError } from "@effect/ai/AiError"
5
- import type * as AiInput from "@effect/ai/AiInput"
4
+ import * as AiError from "@effect/ai/AiError"
5
+ import type * as Prompt from "@effect/ai/Prompt"
6
6
  import * as Tokenizer from "@effect/ai/Tokenizer"
7
- import * as Arr from "effect/Array"
8
7
  import * as Effect from "effect/Effect"
9
8
  import * as Layer from "effect/Layer"
10
- import * as Option from "effect/Option"
11
- import * as Predicate from "effect/Predicate"
12
9
  import * as GptTokenizer from "gpt-tokenizer"
13
10
 
14
11
  /**
@@ -17,43 +14,42 @@ import * as GptTokenizer from "gpt-tokenizer"
17
14
  */
18
15
  export const make = (options: { readonly model: string }) =>
19
16
  Tokenizer.make({
20
- tokenize(input) {
17
+ tokenize(prompt) {
21
18
  return Effect.try({
22
- try: () =>
23
- GptTokenizer.encodeChat(
24
- Arr.flatMap(input.messages, (message) =>
25
- Arr.filterMap(
26
- message.parts as Array<
27
- | AiInput.AssistantMessagePart
28
- | AiInput.ToolMessagePart
29
- | AiInput.UserMessagePart
30
- >,
31
- (part) => {
32
- if (
33
- part._tag === "FilePart" ||
34
- part._tag === "FileUrlPart" ||
35
- part._tag === "ImagePart" ||
36
- part._tag === "ImageUrlPart" ||
37
- part._tag === "ReasoningPart" ||
38
- part._tag === "RedactedReasoningPart"
39
- ) return Option.none()
40
- return Option.some(
41
- {
42
- role: message._tag === "UserMessage" ? "user" : "assistant",
43
- name: message._tag === "UserMessage" && Predicate.isNotUndefined(message.userName)
44
- ? message.userName
45
- : undefined,
46
- content: part._tag === "TextPart"
47
- ? part.text
48
- : JSON.stringify(part._tag === "ToolCallPart" ? part.params : part.result)
49
- } as const
50
- )
19
+ try: () => {
20
+ const content: Array<{
21
+ readonly role: "assistant" | "system" | "user"
22
+ readonly content: string
23
+ }> = []
24
+
25
+ for (const message of prompt.content) {
26
+ if (message.role === "system") {
27
+ content.push({ role: getRole(message), content: message.content })
28
+ continue
29
+ }
30
+
31
+ for (const part of message.content) {
32
+ switch (part.type) {
33
+ case "reasoning":
34
+ case "text": {
35
+ content.push({ role: getRole(message), content: part.text })
36
+ break
37
+ }
38
+ case "tool-call": {
39
+ content.push({ role: getRole(message), content: JSON.stringify(part.params) })
40
+ break
51
41
  }
52
- )),
53
- options.model as any
54
- ),
42
+ case "tool-result": {
43
+ content.push({ role: getRole(message), content: JSON.stringify(part.result) })
44
+ break
45
+ }
46
+ }
47
+ }
48
+ }
49
+ return GptTokenizer.encodeChat(content, options.model as any)
50
+ },
55
51
  catch: (cause) =>
56
- new AiError({
52
+ new AiError.UnknownError({
57
53
  module: "OpenAiTokenizer",
58
54
  method: "tokenize",
59
55
  description: "Could not tokenize",
@@ -69,3 +65,6 @@ export const make = (options: { readonly model: string }) =>
69
65
  */
70
66
  export const layer = (options: { readonly model: string }): Layer.Layer<Tokenizer.Tokenizer> =>
71
67
  Layer.succeed(Tokenizer.Tokenizer, make(options))
68
+
69
+ const getRole = (message: Prompt.Message): "assistant" | "system" | "user" =>
70
+ message.role === "tool" ? "assistant" : message.role
@@ -0,0 +1,110 @@
1
+ /**
2
+ * @since 1.0.0
3
+ */
4
+ import * as Tool from "@effect/ai/Tool"
5
+ import * as Schema from "effect/Schema"
6
+ import * as Struct from "effect/Struct"
7
+ import * as Generated from "./Generated.js"
8
+
9
+ /**
10
+ * @since 1.0.0
11
+ * @category Tools
12
+ */
13
+ export const CodeInterpreter = Tool.providerDefined({
14
+ id: "openai.code_interpreter",
15
+ toolkitName: "OpenAiCodeInterpreter",
16
+ providerName: "code_interpreter",
17
+ args: {
18
+ /**
19
+ * The configuration for the code interpreter container.
20
+ *
21
+ * Can be either a string which specifies the ID of a container created via
22
+ * the `/v1/containers` endpoint, or an object which specifies an optional
23
+ * list of files to make available to the container.
24
+ */
25
+ container: Schema.Union(
26
+ Schema.String,
27
+ Schema.Struct({
28
+ type: Schema.Literal("auto"),
29
+ /**
30
+ * An optional list of uploaded files to make available to your code.
31
+ */
32
+ file_ids: Schema.optional(Schema.Array(Schema.String))
33
+ })
34
+ )
35
+ },
36
+ parameters: {
37
+ code: Schema.NullOr(Schema.String),
38
+ container_id: Schema.String
39
+ },
40
+ success: Schema.NullOr(Schema.Array(Schema.Union(
41
+ Generated.CodeInterpreterOutputLogs,
42
+ Generated.CodeInterpreterOutputImage
43
+ )))
44
+ })
45
+
46
+ /**
47
+ * @since 1.0.0
48
+ * @category Tools
49
+ */
50
+ export const FileSearch = Tool.providerDefined({
51
+ id: "openai.file_search",
52
+ toolkitName: "OpenAiFileSearch",
53
+ providerName: "file_search",
54
+ args: Struct.omit(Generated.FileSearchTool.fields, "type"),
55
+ success: Generated.FileSearchToolCall.pipe(Schema.omit("id", "type"))
56
+ })
57
+
58
+ /**
59
+ * @since 1.0.0
60
+ * @category Tools
61
+ */
62
+ export const WebSearch = Tool.providerDefined({
63
+ id: "openai.web_search",
64
+ toolkitName: "OpenAiWebSearch",
65
+ providerName: "web_search",
66
+ args: Struct.omit(Generated.WebSearchTool.fields, "type"),
67
+ parameters: {
68
+ action: Schema.Union(
69
+ Generated.WebSearchActionSearch,
70
+ Generated.WebSearchActionOpenPage,
71
+ Generated.WebSearchActionFind
72
+ )
73
+ },
74
+ success: Schema.Struct({
75
+ status: Generated.WebSearchToolCallStatus
76
+ })
77
+ })
78
+
79
+ /**
80
+ * @since 1.0.0
81
+ * @category Tools
82
+ */
83
+ export const WebSearchPreview = Tool.providerDefined({
84
+ id: "openai.web_search_preview",
85
+ toolkitName: "OpenAiWebSearchPreview",
86
+ providerName: "web_search_preview",
87
+ args: Struct.omit(Generated.WebSearchPreviewTool.fields, "type"),
88
+ parameters: {
89
+ action: Schema.Union(
90
+ Generated.WebSearchActionSearch,
91
+ Generated.WebSearchActionOpenPage,
92
+ Generated.WebSearchActionFind
93
+ )
94
+ },
95
+ success: Schema.Struct({
96
+ status: Generated.WebSearchToolCallStatus
97
+ })
98
+ })
99
+
100
+ type ProviderToolNames = "code_interpreter" | "file_search" | "web_search" | "web_search_preview"
101
+
102
+ const ProviderToolNamesMap: Map<ProviderToolNames | (string & {}), string> = new Map([
103
+ ["code_interpreter", "OpenAiCodeInterpreter"],
104
+ ["file_search", "OpenAiFileSearch"],
105
+ ["web_search", "OpenAiWebSearch"],
106
+ ["web_search_preview", "OpenAiWebSearchPreview"]
107
+ ])
108
+
109
+ /** @internal */
110
+ export const getProviderDefinedToolName = (name: string): string | undefined => ProviderToolNamesMap.get(name)
package/src/index.ts CHANGED
@@ -32,3 +32,8 @@ export * as OpenAiTelemetry from "./OpenAiTelemetry.js"
32
32
  * @since 1.0.0
33
33
  */
34
34
  export * as OpenAiTokenizer from "./OpenAiTokenizer.js"
35
+
36
+ /**
37
+ * @since 1.0.0
38
+ */
39
+ export * as OpenAiTool from "./OpenAiTool.js"
@@ -1,10 +1,13 @@
1
- import type * as AiResponse from "@effect/ai/AiResponse"
1
+ import type * as Response from "@effect/ai/Response"
2
2
  import * as Predicate from "effect/Predicate"
3
3
 
4
+ /** @internal */
5
+ export const ProviderOptionsKey = "@effect/ai-openai/OpenAiLanguageModel/ProviderOptions"
6
+
4
7
  /** @internal */
5
8
  export const ProviderMetadataKey = "@effect/ai-openai/OpenAiLanguageModel/ProviderMetadata"
6
9
 
7
- const finishReasonMap: Record<string, AiResponse.FinishReason> = {
10
+ const finishReasonMap: Record<string, Response.FinishReason> = {
8
11
  content_filter: "content-filter",
9
12
  function_call: "tool-calls",
10
13
  length: "length",
@@ -13,7 +16,16 @@ const finishReasonMap: Record<string, AiResponse.FinishReason> = {
13
16
  }
14
17
 
15
18
  /** @internal */
16
- export const resolveFinishReason = (finishReason: string): AiResponse.FinishReason => {
19
+ export const resolveFinishReason = (
20
+ finishReason: string | undefined,
21
+ hasToolCalls: boolean
22
+ ): Response.FinishReason => {
23
+ if (Predicate.isNullable(finishReason)) {
24
+ return hasToolCalls ? "tool-calls" : "stop"
25
+ }
17
26
  const reason = finishReasonMap[finishReason]
18
- return Predicate.isUndefined(reason) ? "unknown" : reason
27
+ if (Predicate.isNullable(reason)) {
28
+ return hasToolCalls ? "tool-calls" : "unknown"
29
+ }
30
+ return reason
19
31
  }