From 7520de1d9139772c83db846c5889d7b0686a1370 Mon Sep 17 00:00:00 2001 From: Kinfe123 Date: Thu, 29 Oct 2026 18:54:32 -0700 Subject: [PATCH] fix(openai): accept SDK response event interfaces --- API.md | 4 ++++ CHANGELOG.md | 2 ++ examples/tsconfig.json | 2 +- package.json | 1 + packages/core/src/openai.d.ts | 1 + pnpm-lock.yaml | 45 +++++++++++++++++++++++++++++++---- tests/openai-sdk.ts | 16 +++++++++++++ 7 files changed, 66 insertions(+), 5 deletions(-) create mode 100644 tests/openai-sdk.ts diff --git a/API.md b/API.md index ff66ee4..df9a831 100644 --- a/API.md +++ b/API.md @@ -336,6 +336,10 @@ composable integration value: | `streamfold/langchain` | `langchain` | | `streamfold/ag-ui` | `agUI` | +The OpenAI integration accepts `client.responses.create({ ..., stream: true })` +directly, including SDK event interfaces for text and other non-tool events. +Non-tool events are ignored; callers do not need to cast or filter the stream. + | Method | Returns | | --- | --- | | `pushAll(event)` | All lifecycle updates caused by this event, in order; `[]` for ignored events | diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e00533..6a7f96b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Unreleased +- Accept OpenAI SDK response stream event types directly in the OpenAI adapter + and managed reader, including non-tool events. - Reuse the final frozen snapshot in immutable pool completions, avoiding a second JSON value tree while keeping live final values independently parsed. - Release consumed completion payloads in managed SDK readers while preserving diff --git a/examples/tsconfig.json b/examples/tsconfig.json index fe54bd6..148f7e8 100644 --- a/examples/tsconfig.json +++ b/examples/tsconfig.json @@ -5,5 +5,5 @@ "checkJs": true, "skipLibCheck": true }, - "files": ["assistant-ui.mjs", "vercel-ai.mjs", "custom.mjs", "../tests/langchain-sdk.ts"] + "files": ["assistant-ui.mjs", "vercel-ai.mjs", "custom.mjs", "../tests/langchain-sdk.ts", "../tests/openai-sdk.ts"] } diff --git a/package.json b/package.json index a47a2e8..96728e6 100644 --- a/package.json +++ b/package.json @@ -36,6 +36,7 @@ "assistant-stream": "0.3.42", "bumpp": "^12.3.0", "fast-check": "4.10.2", + "openai": "7.45.1", "playwright": "^1.63.0", "streamfold": "workspace:*", "typescript": "^7.0.2", diff --git a/packages/core/src/openai.d.ts b/packages/core/src/openai.d.ts index 7cec84f..9dc0fd6 100644 --- a/packages/core/src/openai.d.ts +++ b/packages/core/src/openai.d.ts @@ -23,6 +23,7 @@ export type OpenAiResponsesToolEvent = readonly item_id: string; readonly arguments: string; } + | { readonly type: string } | { readonly type: string; readonly [key: string]: unknown; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 7381c13..a77a676 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -10,7 +10,7 @@ importers: devDependencies: '@langchain/core': specifier: 1.3.0 - version: 1.3.0 + version: 1.3.0(openai@7.45.1(undici@7.30.1)(zod@4.6.7)) ai: specifier: 7.0.152 version: 7.0.152(zod@4.6.7) @@ -23,6 +23,9 @@ importers: fast-check: specifier: 4.10.2 version: 4.10.2 + openai: + specifier: 7.45.1 + version: 7.45.1(undici@7.30.1)(zod@4.6.7) playwright: specifier: ^1.63.0 version: 1.63.0 @@ -293,6 +296,33 @@ packages: engines: {node: ^22 || ^24 || >=26} hasBin: true + openai@7.45.1: + resolution: {integrity: sha512-mutrJXwhJIMZ24Lab2COFtNp44OcpZSnV4O2O7q38wAHUa2m2fQqUO5pj1XS3PqLfOTeODBUS9YoadqDnnGk5A==} + engines: {node: '>=22.0.0'} + peerDependencies: + '@aws-sdk/credential-provider-node': '>=3.972.0 <4' + '@smithy/hash-node': '>=4.3.0 <5' + '@smithy/signature-v4': '>=5.4.0 <6' + google-auth-library: '>=9.15.1 <12' + undici: '>=5 <9' + ws: ^8.21.0 + zod: ^3.25 || ^4.0 + peerDependenciesMeta: + '@aws-sdk/credential-provider-node': + optional: true + '@smithy/hash-node': + optional: true + '@smithy/signature-v4': + optional: true + google-auth-library: + optional: true + undici: + optional: true + ws: + optional: true + zod: + optional: true + p-finally@1.0.0: resolution: {integrity: sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==} engines: {node: '>=4'} @@ -390,12 +420,12 @@ snapshots: '@cfworker/json-schema@4.1.1': {} - '@langchain/core@1.3.0': + '@langchain/core@1.3.0(openai@7.45.1(undici@7.30.1)(zod@4.6.7))': dependencies: '@cfworker/json-schema': 4.1.1 '@standard-schema/spec': 1.1.0 js-tiktoken: 1.0.21 - langsmith: 0.11.4 + langsmith: 0.11.4(openai@7.45.1(undici@7.30.1)(zod@4.6.7)) mustache: 4.2.0 p-queue: 6.6.2 zod: 4.6.7 @@ -531,14 +561,21 @@ snapshots: jsonc-parser@3.3.1: {} - langsmith@0.11.4: + langsmith@0.11.4(openai@7.45.1(undici@7.30.1)(zod@4.6.7)): dependencies: p-queue: 6.6.2 + optionalDependencies: + openai: 7.45.1(undici@7.30.1)(zod@4.6.7) mustache@4.2.0: {} nanoid@6.0.1: {} + openai@7.45.1(undici@7.30.1)(zod@4.6.7): + optionalDependencies: + undici: 7.30.1 + zod: 4.6.7 + p-finally@1.0.0: {} p-queue@6.6.2: diff --git a/tests/openai-sdk.ts b/tests/openai-sdk.ts new file mode 100644 index 0000000..ba46a9c --- /dev/null +++ b/tests/openai-sdk.ts @@ -0,0 +1,16 @@ +import OpenAI from "openai"; +import type { ResponseStreamEvent } from "openai/resources/responses/responses"; +import { readStructured } from "streamfold"; +import { openAI } from "streamfold/openai"; + +const client = new OpenAI({ apiKey: "typecheck-only" }); +const events = await client.responses.create({ + model: "fixture", input: "Weather in Paris?", stream: true, +}); +readStructured(events, { integration: openAI }); +const stream = openAI(); +for await (const event of events) stream.pushAll(event); + +declare const event: ResponseStreamEvent; +stream.push(event); +stream.pushAll({ type: "response.future_event", metadata: { source: "provider" } });