diff --git a/API.md b/API.md index 833f681..7879eb6 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 fc3b7ac..f763a36 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. - Preserve Gemini Interactions tool arguments from `arguments_delta` events without treating the initial empty object as the completed input. - Reuse the final frozen snapshot in immutable pool completions, avoiding a diff --git a/examples/tsconfig.json b/examples/tsconfig.json index 361cdab..4623a24 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", "../tests/gemini-sdk.ts"] + "files": ["assistant-ui.mjs", "vercel-ai.mjs", "custom.mjs", "../tests/langchain-sdk.ts", "../tests/gemini-sdk.ts", "../tests/openai-sdk.ts"] } diff --git a/package.json b/package.json index cc5fc8a..2b8b2a1 100644 --- a/package.json +++ b/package.json @@ -37,6 +37,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 bcc4c7d..86b43b9 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -13,7 +13,7 @@ importers: version: 2.31.0 '@langchain/core': specifier: 1.3.0 - version: 1.3.0(ws@8.22.0) + version: 1.3.0(openai@7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7))(ws@8.22.0) ai: specifier: 7.0.152 version: 7.0.152(zod@4.6.7) @@ -26,6 +26,9 @@ importers: fast-check: specifier: 4.10.2 version: 4.10.2 + openai: + specifier: 7.45.1 + version: 7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7) playwright: specifier: ^1.63.0 version: 1.63.0 @@ -419,6 +422,33 @@ packages: resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + 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'} @@ -561,12 +591,12 @@ snapshots: - supports-color - utf-8-validate - '@langchain/core@1.3.0(ws@8.22.0)': + '@langchain/core@1.3.0(openai@7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7))(ws@8.22.0)': dependencies: '@cfworker/json-schema': 4.1.1 '@standard-schema/spec': 1.1.0 js-tiktoken: 1.0.21 - langsmith: 0.11.4(ws@8.22.0) + langsmith: 0.11.4(openai@7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7))(ws@8.22.0) mustache: 4.2.0 p-queue: 6.6.2 zod: 4.6.7 @@ -806,10 +836,11 @@ snapshots: jwa: 2.0.1 safe-buffer: 5.2.1 - langsmith@0.11.4(ws@8.22.0): + langsmith@0.11.4(openai@7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7))(ws@8.22.0): dependencies: p-queue: 6.6.2 optionalDependencies: + openai: 7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7) ws: 8.22.0 long@5.3.2: {} @@ -828,6 +859,13 @@ snapshots: fetch-blob: 3.2.0 formdata-polyfill: 4.0.10 + openai@7.45.1(google-auth-library@10.9.1)(undici@7.30.1)(ws@8.22.0)(zod@4.6.7): + optionalDependencies: + google-auth-library: 10.9.1 + undici: 7.30.1 + ws: 8.22.0 + 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" } });