@effect-uai/responses 0.17.0 → 0.19.0-dev-20261109183959

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.
@@ -1,5 +1,5 @@
1
1
  import { resolveHost } from "./region.mjs";
2
- import { n as describe, r as it, t as globalExpect } from "./test.DNmyFkvJ-N3QqMRwZ.mjs";
2
+ import { n as describe, r as it, t as globalExpect } from "./index.C4tKZ0yW-xEu55bU4.mjs";
3
3
  //#region src/region.test.ts
4
4
  describe("responses/region.resolveHost", () => {
5
5
  it("returns default host when no region or baseUrl", () => {
@@ -1,6 +1,6 @@
1
1
  import { codeInterpreterTool, fileSearchTool, renderProviderTools, webSearchTool } from "./ResponsesTools.mjs";
2
2
  import { KnownProviderEvent, eventToDeltas, makeCallIdLookup } from "./streamEvents.mjs";
3
- import { n as describe, r as it, t as globalExpect } from "./test.DNmyFkvJ-N3QqMRwZ.mjs";
3
+ import { n as describe, r as it, t as globalExpect } from "./index.C4tKZ0yW-xEu55bU4.mjs";
4
4
  import { Result, Schema } from "effect";
5
5
  import * as Tool from "@effect-uai/core/Tool";
6
6
  import { providerToolsOf } from "@effect-uai/core/Tool";
@@ -1,5 +1,6 @@
1
1
  //#region \0rolldown/runtime.js
2
2
  var __defProp = Object.defineProperty;
3
+ var __commonJSMin = (cb, mod) => () => (mod || (cb((mod = { exports: {} }).exports, mod), cb = null), mod.exports);
3
4
  var __exportAll = (all, no_symbols) => {
4
5
  let target = {};
5
6
  for (var name in all) __defProp(target, name, {
@@ -10,4 +11,4 @@ var __exportAll = (all, no_symbols) => {
10
11
  return target;
11
12
  };
12
13
  //#endregion
13
- export { __exportAll as t };
14
+ export { __exportAll as n, __commonJSMin as t };
@@ -1,4 +1,4 @@
1
- import { t as __exportAll } from "./rolldown-runtime-D7D4PA-g.mjs";
1
+ import { n as __exportAll } from "./rolldown-runtime-EAsCxrDo.mjs";
2
2
  import { WireAnnotation, WireOutputItem, WireResponseCompleted, turnFromCompleted } from "./codec.mjs";
3
3
  import { Match, Schema } from "effect";
4
4
  import { TurnEvent } from "@effect-uai/core/Turn";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@effect-uai/responses",
3
- "version": "0.17.0",
3
+ "version": "0.19.0-dev-20261109183959",
4
4
  "description": "OpenAI Responses API provider for @effect-uai/core.",
5
5
  "keywords": [
6
6
  "ai",
@@ -55,13 +55,13 @@
55
55
  "access": "public"
56
56
  },
57
57
  "devDependencies": {
58
- "effect": "4.0.0-rc.111",
58
+ "effect": "4.1.2",
59
59
  "typescript": "^7.0.2",
60
- "@effect-uai/core": "0.17.0"
60
+ "@effect-uai/core": "0.19.0-dev-20261109183959"
61
61
  },
62
62
  "peerDependencies": {
63
- "@effect-uai/core": ">=0.2.0 <1",
64
- "effect": ">=4.0.0-rc.111 <5.0.0"
63
+ "@effect-uai/core": "0.19.0-dev-20261109183959",
64
+ "effect": ">=4.0.1 <5.0.0"
65
65
  },
66
66
  "scripts": {
67
67
  "build": "tsdown",
@@ -1,5 +1,5 @@
1
1
  import { Context, Effect, Layer, Match, Option, Redacted, Schema, Stream } from "effect"
2
- import { HttpClient, HttpClientRequest } from "effect/unstable/http"
2
+ import { HttpClient, HttpClientRequest } from "effect/http"
3
3
  import * as AiError from "@effect-uai/core/AiError"
4
4
  import {
5
5
  DeepResearch,
@@ -1,5 +1,5 @@
1
1
  import { Context, Effect, Layer, Redacted, Schema } from "effect"
2
- import { HttpClient, HttpClientRequest } from "effect/unstable/http"
2
+ import { HttpClient, HttpClientRequest } from "effect/http"
3
3
  import * as AiError from "@effect-uai/core/AiError"
4
4
  import * as Capabilities from "@effect-uai/core/Capabilities"
5
5
  import type {
package/src/Responses.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Context, Effect, Layer, Match, Option, Redacted, Result, Schema, Stream } from "effect"
2
- import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/unstable/http"
2
+ import { HttpClient, HttpClientRequest, HttpClientResponse } from "effect/http"
3
3
  import * as AiError from "@effect-uai/core/AiError"
4
4
  import * as Capabilities from "@effect-uai/core/Capabilities"
5
5
  import * as StructuredFormat from "@effect-uai/core/StructuredFormat"
package/src/codec.test.ts CHANGED
@@ -1,3 +1,6 @@
1
+ import { fileBase64, fileUrl } from "@effect-uai/core/File"
2
+ import { imageBytes } from "@effect-uai/core/Image"
3
+ import * as Items from "@effect-uai/core/Items"
1
4
  import type { HistoryItem } from "@effect-uai/core/Items"
2
5
  import { describe, expect, it } from "vitest"
3
6
  import { itemsToInput, wireItemToItem } from "./codec.js"
@@ -85,3 +88,53 @@ describe("providerData is a shared slot", () => {
85
88
  ])
86
89
  })
87
90
  })
91
+
92
+ describe("tool output", () => {
93
+ const output = (parts: Items.ToolCallOutput["output"], isError?: boolean) =>
94
+ itemsToInput([
95
+ {
96
+ type: "function_call_output",
97
+ call_id: "c1",
98
+ output: parts,
99
+ ...(isError !== undefined && { isError }),
100
+ },
101
+ ])
102
+
103
+ it("sends text and JSON as one string, JSON serialized once", () => {
104
+ expect(
105
+ output([Items.text("found 2"), Items.json({ hits: [1, 2], note: 'a "quote"' })], true),
106
+ ).toEqual([
107
+ {
108
+ type: "function_call_output",
109
+ call_id: "c1",
110
+ output: 'found 2\n{"hits":[1,2],"note":"a \\"quote\\""}',
111
+ },
112
+ ])
113
+ })
114
+
115
+ it("sends media as native parts: images as image_url, files as file_data or file_url", () => {
116
+ expect(
117
+ output([
118
+ Items.json({ title: "Home" }),
119
+ Items.image(imageBytes(new Uint8Array([1, 2, 3]), "image/png")),
120
+ Items.file(fileBase64("JVBE", "application/pdf"), "report.pdf"),
121
+ Items.file(fileUrl("https://x/a.pdf")),
122
+ ]),
123
+ ).toEqual([
124
+ {
125
+ type: "function_call_output",
126
+ call_id: "c1",
127
+ output: [
128
+ { type: "input_text", text: '{"title":"Home"}' },
129
+ { type: "input_image", image_url: "data:image/png;base64,AQID" },
130
+ {
131
+ type: "input_file",
132
+ file_data: "data:application/pdf;base64,JVBE",
133
+ filename: "report.pdf",
134
+ },
135
+ { type: "input_file", file_url: "https://x/a.pdf" },
136
+ ],
137
+ },
138
+ ])
139
+ })
140
+ })
package/src/codec.ts CHANGED
@@ -1,5 +1,13 @@
1
- import { Array as Arr, Encoding, Match, Option, Result, Schema, pipe } from "effect"
2
- import type { ContentBlock, InputImage, HistoryItem } from "@effect-uai/core/Items"
1
+ import { Array as Arr, Match, Option, Result, Schema, pipe } from "effect"
2
+ import { Base64 } from "effect/encoding"
3
+ import type {
4
+ ContentBlock,
5
+ HistoryItem,
6
+ InputFile,
7
+ InputImage,
8
+ ToolOutputContent,
9
+ } from "@effect-uai/core/Items"
10
+ import * as ToolOutput from "@effect-uai/core/ToolOutput"
3
11
  import type { Turn } from "@effect-uai/core/Turn"
4
12
 
5
13
  // ---------------------------------------------------------------------------
@@ -198,10 +206,37 @@ const passthrough = (item: HistoryItem): StoredItem | undefined =>
198
206
  const imageSourceToUrl = Match.type<InputImage["source"]>().pipe(
199
207
  Match.tag("url", (s) => s.url),
200
208
  Match.tag("base64", (s) => `data:${s.mimeType};base64,${s.base64}`),
201
- Match.tag("bytes", (s) => `data:${s.mimeType};base64,${Encoding.encodeBase64(s.bytes)}`),
209
+ Match.tag("bytes", (s) => `data:${s.mimeType};base64,${Base64.encode(s.bytes)}`),
202
210
  Match.exhaustive,
203
211
  )
204
212
 
213
+ const fileSourceToInput = Match.type<InputFile["source"]>().pipe(
214
+ Match.tag("url", (s) => ({ file_url: s.url })),
215
+ Match.tag("base64", (s) => ({ file_data: `data:${s.mimeType};base64,${s.base64}` })),
216
+ Match.tag("bytes", (s) => ({
217
+ file_data: `data:${s.mimeType};base64,${Base64.encode(s.bytes)}`,
218
+ })),
219
+ Match.exhaustive,
220
+ )
221
+
222
+ const toolOutputPart = Match.type<ToolOutputContent>().pipe(
223
+ Match.discriminatorsExhaustive("type")({
224
+ input_text: (p) => ({ type: "input_text", text: ToolOutput.partText(p) }),
225
+ input_json: (p) => ({ type: "input_text", text: ToolOutput.partText(p) }),
226
+ input_image: (p) => ({ type: "input_image", image_url: imageSourceToUrl(p.source) }),
227
+ input_file: (p) => ({
228
+ type: "input_file",
229
+ ...fileSourceToInput(p.source),
230
+ ...(p.filename !== undefined && { filename: p.filename }),
231
+ }),
232
+ }),
233
+ )
234
+
235
+ // Text and JSON only: one string (the widest supported form). With media: native parts.
236
+ // No error flag on this wire: a failure is told by its content.
237
+ const toolOutput = (parts: ReadonlyArray<ToolOutputContent>): string | ReadonlyArray<object> =>
238
+ Option.getOrElse(ToolOutput.text(parts), () => parts.map(toolOutputPart))
239
+
205
240
  const contentBlockToInput = Match.type<ContentBlock>().pipe(
206
241
  Match.discriminatorsExhaustive("type")({
207
242
  input_text: (b) => ({ type: "input_text", text: b.text }),
@@ -238,7 +273,7 @@ const itemToInput = (item: HistoryItem): Record<string, unknown> =>
238
273
  function_call_output: (o) => ({
239
274
  type: "function_call_output",
240
275
  call_id: o.call_id,
241
- output: o.output,
276
+ output: toolOutput(o.output),
242
277
  }),
243
278
  reasoning: (r) => ({
244
279
  type: "reasoning",