Skip to content

Commit ff45062

Browse files
committed
refactor: remove _tag wrapper and fix type safety in streaming events
- Import proper OpenResponsesStreamEvent type instead of using any - Remove _tag wrapper from getFullResponsesStream events - Emit events directly with clean discriminated union on type field - Add ToolPreliminaryResultEvent type for generator tool results - Add isToolPreliminaryResultEvent type guard helper - Update tests to use clean API without internal _tag field - Export new type and helper from main index This provides a cleaner API surface without exposing internal implementation details like _tag, while maintaining full type safety.
1 parent 4817480 commit ff45062

File tree

4 files changed

+35
-25
lines changed

4 files changed

+35
-25
lines changed

src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ export type { Fetcher, HTTPClientOptions } from "./lib/http.js";
1010
export { ResponseWrapper } from "./lib/response-wrapper.js";
1111
export type { GetResponseOptions } from "./lib/response-wrapper.js";
1212
export { ReusableReadableStream } from "./lib/reusable-stream.js";
13-
export { ToolType } from "./lib/tool-types.js";
13+
export { ToolType, isToolPreliminaryResultEvent } from "./lib/tool-types.js";
1414
export type {
1515
EnhancedTool,
1616
ToolWithExecute,
@@ -23,6 +23,7 @@ export type {
2323
EnhancedResponseStreamEvent,
2424
ToolStreamEvent,
2525
ChatStreamEvent,
26+
ToolPreliminaryResultEvent,
2627
} from "./lib/tool-types.js";
2728
// #endregion
2829
export * from "./sdk/sdk.js";

src/lib/response-wrapper.ts

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -339,19 +339,18 @@ export class ResponseWrapper {
339339

340340
const consumer = this.reusableStream.createConsumer();
341341

342-
// Yield original events wrapped
342+
// Yield original events directly
343343
for await (const event of consumer) {
344-
yield { _tag: "original" as const, event };
344+
yield event;
345345
}
346346

347347
// After stream completes, check if tools were executed and emit preliminary results
348348
await this.executeToolsIfNeeded();
349349

350-
// Emit all preliminary results
350+
// Emit all preliminary results as new event types
351351
for (const [toolCallId, results] of this.preliminaryResults) {
352352
for (const result of results) {
353353
yield {
354-
_tag: "tool_preliminary" as const,
355354
type: "tool.preliminary_result" as const,
356355
toolCallId,
357356
result,

src/lib/tool-types.ts

Lines changed: 22 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import { z, type ZodType, type ZodObject, type ZodRawShape } from "zod/v4";
22
import * as models from "../models/index.js";
3+
import type { OpenResponsesStreamEvent } from "../models/index.js";
34

45
/**
56
* Tool type enum for enhanced tools
@@ -210,19 +211,32 @@ export interface APITool {
210211
parameters: { [k: string]: any | null } | null;
211212
}
212213

214+
/**
215+
* Tool preliminary result event emitted during generator tool execution
216+
*/
217+
export type ToolPreliminaryResultEvent = {
218+
type: "tool.preliminary_result";
219+
toolCallId: string;
220+
result: unknown;
221+
timestamp: number;
222+
};
223+
213224
/**
214225
* Enhanced stream event types for getFullResponsesStream
215226
* Extends OpenResponsesStreamEvent with tool preliminary results
216227
*/
217228
export type EnhancedResponseStreamEvent =
218-
| { _tag: "original"; event: any } // Original OpenResponsesStreamEvent
219-
| {
220-
_tag: "tool_preliminary";
221-
type: "tool.preliminary_result";
222-
toolCallId: string;
223-
result: unknown;
224-
timestamp: number;
225-
};
229+
| OpenResponsesStreamEvent
230+
| ToolPreliminaryResultEvent;
231+
232+
/**
233+
* Type guard to check if an event is a tool preliminary result event
234+
*/
235+
export function isToolPreliminaryResultEvent(
236+
event: EnhancedResponseStreamEvent
237+
): event is ToolPreliminaryResultEvent {
238+
return event.type === "tool.preliminary_result";
239+
}
226240

227241
/**
228242
* Tool stream event types for getToolStream

tests/e2e/getResponse.test.ts

Lines changed: 8 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -306,23 +306,19 @@ describe("getResponse E2E Tests", () => {
306306

307307
for await (const event of response.getFullResponsesStream()) {
308308
expect(event).toBeDefined();
309-
expect("_tag" in event).toBe(true);
309+
expect("type" in event).toBe(true);
310310
events.push(event);
311311
}
312312

313313
expect(events.length).toBeGreaterThan(0);
314314

315-
// Get original events only
316-
const originalEvents = events.filter((e) => e._tag === "original");
317-
expect(originalEvents.length).toBeGreaterThan(0);
318-
319-
// Verify we have different event types in original events
320-
const eventTypes = new Set(originalEvents.map((e) => e.event?.type).filter(Boolean));
315+
// Verify we have different event types
316+
const eventTypes = new Set(events.map((e) => e.type));
321317
expect(eventTypes.size).toBeGreaterThan(1);
322318

323319
// Should have completion event
324-
const hasCompletionEvent = originalEvents.some(
325-
(e) => e.event?.type === "response.completed" || e.event?.type === "response.incomplete"
320+
const hasCompletionEvent = events.some(
321+
(e) => e.type === "response.completed" || e.type === "response.incomplete"
326322
);
327323
expect(hasCompletionEvent).toBe(true);
328324
}, 15000);
@@ -340,9 +336,9 @@ describe("getResponse E2E Tests", () => {
340336

341337
const textDeltaEvents: any[] = [];
342338

343-
for await (const wrappedEvent of response.getFullResponsesStream()) {
344-
if (wrappedEvent._tag === "original" && wrappedEvent.event?.type === "response.output_text.delta") {
345-
textDeltaEvents.push(wrappedEvent.event);
339+
for await (const event of response.getFullResponsesStream()) {
340+
if (event.type === "response.output_text.delta") {
341+
textDeltaEvents.push(event);
346342
}
347343
}
348344

0 commit comments

Comments
 (0)