@@ -8,12 +8,13 @@ import type {
88 ResponseCreateParams ,
99 ResponseInputItem ,
1010 ResponseOutputItem ,
11+ ResponseStreamEvent ,
1112} from 'openai/resources/responses/responses'
1213import { match , P } from 'ts-pattern'
1314import type { ChatMessage , InputMessages , MessagePart , OutputMessage , OutputMessages } from '../otel/genai'
14- import { BaseAPI } from './base'
15+ import { BaseAPI , type ExtractedRequest , type ExtractedResponse , type ExtractorConfig } from './base'
1516
16- export class ResponsesAPI extends BaseAPI < ResponseCreateParams , Response > {
17+ export class ResponsesAPI extends BaseAPI < ResponseCreateParams , Response , ResponseStreamEvent > {
1718 apiFlavor = 'responses'
1819
1920 // The Responses API does not support stop sequences.
@@ -47,6 +48,79 @@ export class ResponsesAPI extends BaseAPI<ResponseCreateParams, Response> {
4748 outputMessages = ( responseBody : Response ) : OutputMessages | undefined => {
4849 return responseBody . output . map ( mapOutputMessage )
4950 }
51+
52+ // SafeExtractor implementation
53+
54+ requestExtractors : ExtractorConfig < ResponseCreateParams , ExtractedRequest > = {
55+ requestModel : ( requestBody : ResponseCreateParams ) => {
56+ this . extractedRequest . requestModel = requestBody . model ?? undefined
57+ } ,
58+ maxTokens : ( requestBody : ResponseCreateParams ) => {
59+ this . extractedRequest . maxTokens = requestBody . max_output_tokens ?? undefined
60+ } ,
61+ temperature : ( requestBody : ResponseCreateParams ) => {
62+ this . extractedRequest . temperature = requestBody . temperature ?? undefined
63+ } ,
64+ topP : ( requestBody : ResponseCreateParams ) => {
65+ this . extractedRequest . topP = requestBody . top_p ?? undefined
66+ } ,
67+ inputMessages : ( requestBody : ResponseCreateParams ) => {
68+ this . extractedRequest . inputMessages = this . inputMessages ( requestBody )
69+ } ,
70+ }
71+
72+ responseExtractors : ExtractorConfig < Response , ExtractedResponse > = {
73+ usage : ( responseBody : Response ) => {
74+ if ( responseBody . usage ) {
75+ this . extractedResponse . usage = this . extractUsage ( responseBody )
76+ }
77+ } ,
78+ responseModel : ( responseBody : Response ) => {
79+ this . extractedResponse . responseModel = responseBody . model ?? undefined
80+ } ,
81+ responseId : ( responseBody : Response ) => {
82+ this . extractedResponse . responseId = responseBody . id ?? undefined
83+ } ,
84+ finishReasons : ( responseBody : Response ) => {
85+ this . extractedResponse . finishReasons = responseBody . incomplete_details ?. reason
86+ ? [ responseBody . incomplete_details . reason ]
87+ : undefined
88+ } ,
89+ outputMessages : ( responseBody : Response ) => {
90+ this . extractedResponse . outputMessages = responseBody . output . map ( mapOutputMessage )
91+ } ,
92+ }
93+
94+ chunkExtractors : ExtractorConfig < ResponseStreamEvent , ExtractedResponse > = {
95+ usage : ( chunk : ResponseStreamEvent ) => {
96+ if ( 'response' in chunk ) {
97+ if ( chunk . response ?. usage ) {
98+ this . extractedResponse . usage = this . extractUsage ( chunk . response )
99+ }
100+ }
101+ } ,
102+ responseModel : ( chunk : ResponseStreamEvent ) => {
103+ if ( 'response' in chunk ) {
104+ if ( chunk . response ?. model ) {
105+ this . extractedResponse . responseModel = chunk . response . model
106+ }
107+ }
108+ } ,
109+ responseId : ( chunk : ResponseStreamEvent ) => {
110+ if ( 'response' in chunk ) {
111+ if ( chunk . response ?. id ) {
112+ this . extractedResponse . responseId = chunk . response . id
113+ }
114+ }
115+ } ,
116+ finishReasons : ( chunk : ResponseStreamEvent ) => {
117+ if ( 'response' in chunk ) {
118+ if ( chunk . response ?. incomplete_details ?. reason ) {
119+ this . extractedResponse . finishReasons = [ chunk . response . incomplete_details . reason ]
120+ }
121+ }
122+ } ,
123+ }
50124}
51125
52126function mapInputMessage ( input : ResponseInputItem ) : ChatMessage {
0 commit comments