@effect-uai/responses 0.5.2 → 0.6.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.
- package/dist/OpenAIEmbedding.d.mts +2 -0
- package/dist/OpenAIEmbedding.d.mts.map +1 -1
- package/dist/OpenAIEmbedding.mjs +2 -2
- package/dist/OpenAIEmbedding.mjs.map +1 -1
- package/dist/Responses.d.mts +2 -0
- package/dist/Responses.d.mts.map +1 -1
- package/dist/Responses.mjs +2 -1
- package/dist/Responses.mjs.map +1 -1
- package/dist/codec.d.mts +4 -4
- package/dist/codec.d.mts.map +1 -1
- package/dist/codec.mjs +1 -1
- package/dist/codec.mjs.map +1 -1
- package/dist/index.d.mts +2 -1
- package/dist/index.mjs +2 -1
- package/dist/magic-string.es-PAZgLX4h.mjs +1013 -0
- package/dist/magic-string.es-PAZgLX4h.mjs.map +1 -0
- package/dist/region.d.mts +24 -0
- package/dist/region.d.mts.map +1 -0
- package/dist/region.mjs +16 -0
- package/dist/region.mjs.map +1 -0
- package/dist/region.test.d.mts +1 -0
- package/dist/region.test.mjs +13656 -0
- package/dist/region.test.mjs.map +1 -0
- package/package.json +2 -2
- package/src/OpenAIEmbedding.ts +3 -3
- package/src/Responses.ts +3 -1
- package/src/codec.ts +8 -7
- package/src/index.ts +1 -0
- package/src/region.test.ts +26 -0
- package/src/region.ts +29 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@effect-uai/responses",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "OpenAI Responses API provider for @effect-uai/core.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -49,7 +49,7 @@
|
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"effect": "4.0.0-beta.57",
|
|
51
51
|
"typescript": "^6.0.3",
|
|
52
|
-
"@effect-uai/core": "0.
|
|
52
|
+
"@effect-uai/core": "0.6.0"
|
|
53
53
|
},
|
|
54
54
|
"peerDependencies": {
|
|
55
55
|
"@effect-uai/core": ">=0.2.0 <1",
|
package/src/OpenAIEmbedding.ts
CHANGED
|
@@ -17,6 +17,7 @@ import {
|
|
|
17
17
|
type EmbedResponse,
|
|
18
18
|
} from "@effect-uai/core/EmbeddingModel"
|
|
19
19
|
import type { OpenAIEmbeddingModel } from "./models.js"
|
|
20
|
+
import { type OpenAiRegion, resolveHost } from "./region.js"
|
|
20
21
|
|
|
21
22
|
// ---------------------------------------------------------------------------
|
|
22
23
|
// Public types
|
|
@@ -56,6 +57,7 @@ export class OpenAIEmbedding extends Context.Service<OpenAIEmbedding, OpenAIEmbe
|
|
|
56
57
|
export type Config = {
|
|
57
58
|
readonly apiKey: Redacted.Redacted
|
|
58
59
|
readonly baseUrl?: string
|
|
60
|
+
readonly region?: OpenAiRegion
|
|
59
61
|
}
|
|
60
62
|
|
|
61
63
|
// ---------------------------------------------------------------------------
|
|
@@ -176,15 +178,13 @@ const transportFailure = (cause: unknown): AiError.AiError =>
|
|
|
176
178
|
// HTTP plumbing
|
|
177
179
|
// ---------------------------------------------------------------------------
|
|
178
180
|
|
|
179
|
-
const baseUrl = (cfg: Config): string => cfg.baseUrl ?? "https://api.openai.com/v1"
|
|
180
|
-
|
|
181
181
|
const postEmbed = (
|
|
182
182
|
cfg: Config,
|
|
183
183
|
body: WireBody,
|
|
184
184
|
): Effect.Effect<typeof WireResponse.Type, AiError.AiError, HttpClient.HttpClient> =>
|
|
185
185
|
Effect.gen(function* () {
|
|
186
186
|
const client = yield* HttpClient.HttpClient
|
|
187
|
-
const httpRequest = HttpClientRequest.post(`${
|
|
187
|
+
const httpRequest = HttpClientRequest.post(`${resolveHost(cfg)}/embeddings`).pipe(
|
|
188
188
|
HttpClientRequest.bearerToken(cfg.apiKey),
|
|
189
189
|
HttpClientRequest.bodyJsonUnsafe(body),
|
|
190
190
|
)
|
package/src/Responses.ts
CHANGED
|
@@ -12,6 +12,7 @@ import * as SSE from "@effect-uai/core/SSE"
|
|
|
12
12
|
import type { Turn, TurnEvent } from "@effect-uai/core/Turn"
|
|
13
13
|
import { itemsToInput } from "./codec.js"
|
|
14
14
|
import type { OpenAIModel } from "./models.js"
|
|
15
|
+
import { type OpenAiRegion, resolveHost } from "./region.js"
|
|
15
16
|
import {
|
|
16
17
|
KnownProviderEvent,
|
|
17
18
|
ProviderEvent,
|
|
@@ -95,6 +96,7 @@ export class Responses extends Context.Service<Responses, ResponsesService>()(
|
|
|
95
96
|
export type Config = {
|
|
96
97
|
readonly apiKey: Redacted.Redacted
|
|
97
98
|
readonly baseUrl?: string
|
|
99
|
+
readonly region?: OpenAiRegion
|
|
98
100
|
}
|
|
99
101
|
|
|
100
102
|
// ---------------------------------------------------------------------------
|
|
@@ -222,7 +224,7 @@ const httpStatusError = (status: number, body: string): AiError.AiError => {
|
|
|
222
224
|
}
|
|
223
225
|
|
|
224
226
|
const buildNativeStream = (cfg: Config) => {
|
|
225
|
-
const url = `${cfg
|
|
227
|
+
const url = `${resolveHost(cfg)}/responses`
|
|
226
228
|
return (
|
|
227
229
|
request: ResponsesRequest,
|
|
228
230
|
): Stream.Stream<ProviderEvent, AiError.AiError, HttpClient.HttpClient> =>
|
package/src/codec.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Encoding, Match, Option, Schema } from "effect"
|
|
2
|
-
import type { ContentBlock, InputImage,
|
|
2
|
+
import type { ContentBlock, InputImage, HistoryItem } from "@effect-uai/core/Items"
|
|
3
3
|
import type { Turn } from "@effect-uai/core/Turn"
|
|
4
4
|
|
|
5
5
|
// ---------------------------------------------------------------------------
|
|
@@ -137,7 +137,7 @@ export type WireResponseCompleted = typeof WireResponseCompleted.Type
|
|
|
137
137
|
* verbatim - preserves `encrypted_content`, item ids, and any field this
|
|
138
138
|
* codec doesn't model.
|
|
139
139
|
*/
|
|
140
|
-
const passthrough = (item:
|
|
140
|
+
const passthrough = (item: HistoryItem): Record<string, unknown> | undefined =>
|
|
141
141
|
item.providerData !== undefined &&
|
|
142
142
|
typeof item.providerData === "object" &&
|
|
143
143
|
item.providerData !== null
|
|
@@ -168,7 +168,7 @@ const contentBlockToInput = Match.type<ContentBlock>().pipe(
|
|
|
168
168
|
}),
|
|
169
169
|
)
|
|
170
170
|
|
|
171
|
-
const itemToInput = (item:
|
|
171
|
+
const itemToInput = (item: HistoryItem): Record<string, unknown> =>
|
|
172
172
|
passthrough(item) ??
|
|
173
173
|
Match.value(item).pipe(
|
|
174
174
|
Match.discriminatorsExhaustive("type")({
|
|
@@ -199,9 +199,10 @@ const itemToInput = (item: Item): Record<string, unknown> =>
|
|
|
199
199
|
}),
|
|
200
200
|
)
|
|
201
201
|
|
|
202
|
-
/** Convert our `
|
|
203
|
-
export const itemsToInput = (
|
|
204
|
-
items
|
|
202
|
+
/** Convert our `HistoryItem[]` history into the Responses API `input` array. */
|
|
203
|
+
export const itemsToInput = (
|
|
204
|
+
items: ReadonlyArray<HistoryItem>,
|
|
205
|
+
): ReadonlyArray<Record<string, unknown>> => items.map(itemToInput)
|
|
205
206
|
|
|
206
207
|
// ---------------------------------------------------------------------------
|
|
207
208
|
// Wire output items → our Items
|
|
@@ -218,7 +219,7 @@ const wireMessageContentToBlock = Match.type<typeof WireMessageContent.Type>().p
|
|
|
218
219
|
}),
|
|
219
220
|
)
|
|
220
221
|
|
|
221
|
-
export const wireItemToItem = (wire: WireOutputItem):
|
|
222
|
+
export const wireItemToItem = (wire: WireOutputItem): HistoryItem =>
|
|
222
223
|
Match.value(wire).pipe(
|
|
223
224
|
Match.discriminatorsExhaustive("type")({
|
|
224
225
|
message: (m) => ({
|
package/src/index.ts
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { describe, expect, it } from "vitest"
|
|
2
|
+
import { resolveHost } from "./region.js"
|
|
3
|
+
|
|
4
|
+
describe("responses/region.resolveHost", () => {
|
|
5
|
+
it("returns default host when no region or baseUrl", () => {
|
|
6
|
+
expect(resolveHost({})).toBe("https://api.openai.com/v1")
|
|
7
|
+
})
|
|
8
|
+
|
|
9
|
+
it("returns default host for region 'default'", () => {
|
|
10
|
+
expect(resolveHost({ region: "default" })).toBe("https://api.openai.com/v1")
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
it("computes EU host for region 'eu'", () => {
|
|
14
|
+
expect(resolveHost({ region: "eu" })).toBe("https://eu.api.openai.com/v1")
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it("passes unknown region through as host prefix", () => {
|
|
18
|
+
expect(resolveHost({ region: "apac" })).toBe("https://apac.api.openai.com/v1")
|
|
19
|
+
})
|
|
20
|
+
|
|
21
|
+
it("baseUrl wins over region", () => {
|
|
22
|
+
expect(resolveHost({ baseUrl: "http://localhost:8080/v1", region: "eu" })).toBe(
|
|
23
|
+
"http://localhost:8080/v1",
|
|
24
|
+
)
|
|
25
|
+
})
|
|
26
|
+
})
|
package/src/region.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenAI regional endpoints. `eu.api.openai.com` covers `/v1/responses`
|
|
3
|
+
* and `/v1/embeddings` (along with the rest of the REST surface) for
|
|
4
|
+
* projects with EU data residency enabled. Keys are project-scoped.
|
|
5
|
+
*
|
|
6
|
+
* Reference: https://developers.openai.com/api/docs/guides/your-data
|
|
7
|
+
*
|
|
8
|
+
* Defined locally in this package rather than imported from
|
|
9
|
+
* `@effect-uai/openai` to keep the packages decoupled.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
// eslint-disable-next-line @typescript-eslint/ban-types
|
|
13
|
+
export type OpenAiRegion = "default" | "eu" | (string & {})
|
|
14
|
+
|
|
15
|
+
const DEFAULT_HOST = "https://api.openai.com/v1"
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Resolve the HTTP base URL from a Config. `baseUrl` wins when set;
|
|
19
|
+
* otherwise the host is computed from `region`. Unknown region strings
|
|
20
|
+
* pass through as `{region}.api.openai.com/v1` for forward compat.
|
|
21
|
+
*/
|
|
22
|
+
export const resolveHost = (cfg: {
|
|
23
|
+
readonly baseUrl?: string
|
|
24
|
+
readonly region?: OpenAiRegion
|
|
25
|
+
}): string => {
|
|
26
|
+
if (cfg.baseUrl !== undefined) return cfg.baseUrl
|
|
27
|
+
if (cfg.region === undefined || cfg.region === "default") return DEFAULT_HOST
|
|
28
|
+
return `https://${cfg.region}.api.openai.com/v1`
|
|
29
|
+
}
|