From 77fb6f7c9d8442a47d4e750d2b3e697631d1dadb Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Mon, 8 Jun 2026 20:16:03 +0000 Subject: [PATCH 1/2] test: add compatibility test cases for interactions API --- test/unit/compat_errors_test.ts | 24 ++++++++++++++++ test/unit/compat_request_options_test.ts | 35 ++++++++++++++++++++++++ 2 files changed, 59 insertions(+) create mode 100644 test/unit/compat_errors_test.ts create mode 100644 test/unit/compat_request_options_test.ts diff --git a/test/unit/compat_errors_test.ts b/test/unit/compat_errors_test.ts new file mode 100644 index 0000000000..cad3ab0350 --- /dev/null +++ b/test/unit/compat_errors_test.ts @@ -0,0 +1,24 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GoogleGenAI } from '../../src/client.js'; +import { BadRequestError, NotFoundError } from '../../src/interactions/core/error.js'; + +describe('TypeScript compat: Errors', () => { + it('imports and catches Stainless error classes', async () => { + const client = new GoogleGenAI({ apiKey: 'test' }); + try { + await client.interactions.create({ model: 'gemini-2.0-flash', input: 'hello' }); + } catch (e) { + if (e instanceof BadRequestError) { + console.log(`Bad request status: ${e.status}`); + console.log(`Error JSON: ${JSON.stringify(e.error)}`); + } else if (e instanceof NotFoundError) { + console.log("Not found"); + } + } + }); +}); diff --git a/test/unit/compat_request_options_test.ts b/test/unit/compat_request_options_test.ts new file mode 100644 index 0000000000..053411af47 --- /dev/null +++ b/test/unit/compat_request_options_test.ts @@ -0,0 +1,35 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GoogleGenAI } from '../../src/client.js'; + +describe('TypeScript compat: Request options', () => { + it('exercises request options pattern from old SDK', async () => { + const client = new GoogleGenAI({ apiKey: 'test' }); + const model = "gemini-2.0-flash"; + const input = "hello"; + const requestInit = {}; + + // In Stainless, we can pass requestInit as the options parameter + try { + await client.interactions.create({ model, input, stream: false }, requestInit); + } catch (e) { + // ignore actual network error during unit test execution + } + + // Custom query and body are officially supported in Stainless request options + try { + await client.interactions.create({ model, input, stream: false }, { + timeout: 30000, + headers: { "X-Custom": "value" }, + query: { custom_param: "value" }, + body: { custom_body: "value" }, + }); + } catch (e) { + // ignore actual network error + } + }); +}); From 2f150e7d2fdc340ce8d5e4f0c4698b79fbf0cddf Mon Sep 17 00:00:00 2001 From: Mark Daoust Date: Tue, 9 Jun 2026 04:22:20 +0000 Subject: [PATCH 2/2] progress --- test/unit/compat_api_promise_test.ts | 29 ++++++++++++++++++++++++++++ test/unit/compat_streaming_test.ts | 22 +++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 test/unit/compat_api_promise_test.ts create mode 100644 test/unit/compat_streaming_test.ts diff --git a/test/unit/compat_api_promise_test.ts b/test/unit/compat_api_promise_test.ts new file mode 100644 index 0000000000..7722acc8f1 --- /dev/null +++ b/test/unit/compat_api_promise_test.ts @@ -0,0 +1,29 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { GoogleGenAI } from '../../src/client.js'; + +describe('TypeScript compat: APIPromise methods', () => { + it('interactions.create() returns a promise with .asResponse() and .withResponse()', async () => { + // In the Stainless SDK, resource methods return APIPromise which has + // .asResponse() and .withResponse() for accessing raw response headers. + // In the Speakeasy SDK, these methods are gone — standard Promise is returned. + const client = new GoogleGenAI({ apiKey: 'test' }); + + const promise = client.interactions.create({ + model: 'gemini-2.0-flash', + input: 'hello', + stream: false, + }); + + // These should exist on the Stainless APIPromise + expect(typeof (promise as any).asResponse).toBe('function'); + expect(typeof (promise as any).withResponse).toBe('function'); + + // Consume promise to avoid unhandled rejection + await promise.catch(() => {}); + }); +}); diff --git a/test/unit/compat_streaming_test.ts b/test/unit/compat_streaming_test.ts new file mode 100644 index 0000000000..b739548b9a --- /dev/null +++ b/test/unit/compat_streaming_test.ts @@ -0,0 +1,22 @@ +/** + * @license + * Copyright 2026 Google LLC + * SPDX-License-Identifier: Apache-2.0 + */ + +import { Stream } from '../../src/interactions/core/streaming.js'; + +describe('TypeScript compat: Streaming', () => { + it('imports Stream from interactions/core/streaming.js', () => { + // In the Stainless SDK, Stream is importable from interactions/core/streaming.js + // In the Speakeasy SDK, this path may not exist — EventStream is the replacement. + expect(Stream).toBeDefined(); + }); + + it('Stream has .tee() and .toReadableStream() methods', () => { + // Stainless Stream has: .tee() -> [Stream, Stream] and .toReadableStream() -> ReadableStream + // Speakeasy EventStream (extends ReadableStream) does NOT have these. + expect(typeof Stream.prototype.tee).toBe('function'); + expect(typeof Stream.prototype.toReadableStream).toBe('function'); + }); +});