Skip to content

Commit 9c9d105

Browse files
authored
fix: openai responses api (streaming) table and drawer view (#5027)
1 parent 4f73e5f commit 9c9d105

File tree

1 file changed

+67
-29
lines changed

1 file changed

+67
-29
lines changed

packages/llm-mapper/mappers/openai/responses.ts

Lines changed: 67 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,12 @@ export const getRequestText = (requestBody: OpenAIResponseRequest): string => {
105105

106106
if (Array.isArray(input) && input.length > 0) {
107107
const lastItem = input[input.length - 1];
108-
108+
109109
// Handle function_call_output items - they don't have extractable text
110110
if ((lastItem as any)?.type === "function_call_output") {
111111
return "";
112112
}
113-
113+
114114
const content = (lastItem as any)?.content;
115115

116116
// Content can be a string or an array of typed items
@@ -161,14 +161,17 @@ export const getResponseText = (
161161
if (statusCode === 0 || statusCode === null) {
162162
return "";
163163
}
164-
164+
165165
// Handle null/undefined inputs
166166
if (responseBody === null || responseBody === undefined) {
167167
return "";
168168
}
169-
169+
170170
// Handle empty objects
171-
if (typeof responseBody === "object" && Object.keys(responseBody).length === 0) {
171+
if (
172+
typeof responseBody === "object" &&
173+
Object.keys(responseBody).length === 0
174+
) {
172175
return "";
173176
}
174177

@@ -210,6 +213,28 @@ export const getResponseText = (
210213
}
211214
}
212215

216+
// streaming
217+
if (
218+
responseBody?.type === "response.completed" &&
219+
Array.isArray(responseBody?.response?.output) &&
220+
responseBody?.response?.output.length &&
221+
responseBody?.response?.output[0]?.content &&
222+
Array.isArray(responseBody?.response?.output[0]?.content) &&
223+
responseBody?.response?.output[0]?.content.length
224+
) {
225+
const contentArray = responseBody?.response?.output[0]?.content;
226+
const textContent = contentArray.find(
227+
(c: any) => c?.type === "output_text"
228+
);
229+
if (textContent?.text) {
230+
return textContent.text;
231+
}
232+
const firstItemType = contentArray[0]?.type;
233+
if (typeof firstItemType === "string" && firstItemType) {
234+
return `[${firstItemType}]`;
235+
}
236+
}
237+
213238
// Fallbacks
214239
if (typeof responseBody?.text === "string") {
215240
return responseBody.text;
@@ -219,7 +244,10 @@ export const getResponseText = (
219244
try {
220245
return JSON.stringify(responseBody);
221246
} catch (stringifyError) {
222-
if (stringifyError instanceof Error && stringifyError.message.includes('circular')) {
247+
if (
248+
stringifyError instanceof Error &&
249+
stringifyError.message.includes("circular")
250+
) {
223251
return "error_circular_reference";
224252
}
225253
throw stringifyError;
@@ -663,31 +691,37 @@ const convertResponse = (responseBody: any): Message[] => {
663691
}
664692

665693
// Check for the 'output' array specific to the Responses API
666-
if (!responseBody || !Array.isArray(responseBody.output)) return [];
694+
if (
695+
!responseBody ||
696+
!Array.isArray(responseBody.output ?? responseBody.response?.output)
697+
)
698+
return [];
667699

668700
// Iterate through the output array
669-
responseBody.output.forEach((outputItem: any, index: number) => {
670-
// Look for items of type 'message'
671-
if (outputItem.type === "message" && outputItem.content) {
672-
let messageText = "";
673-
// The content is an array, find the 'output_text' item
674-
if (Array.isArray(outputItem.content)) {
675-
const textContent = outputItem.content.find(
676-
(c: any) => c.type === "output_text"
677-
);
678-
if (textContent && textContent.text) {
679-
messageText = textContent.text;
701+
(responseBody.output ?? responseBody.response?.output).forEach(
702+
(outputItem: any, index: number) => {
703+
// Look for items of type 'message'
704+
if (outputItem.type === "message" && outputItem.content) {
705+
let messageText = "";
706+
// The content is an array, find the 'output_text' item
707+
if (Array.isArray(outputItem.content)) {
708+
const textContent = outputItem.content.find(
709+
(c: any) => c.type === "output_text"
710+
);
711+
if (textContent && textContent.text) {
712+
messageText = textContent.text;
713+
}
680714
}
681-
}
682715

683-
messages.push({
684-
_type: "message",
685-
role: outputItem.role || "assistant", // Get role from the message item
686-
content: messageText,
687-
id: outputItem.id || `resp-msg-${index}`, // Use ID from the output item if available
688-
});
716+
messages.push({
717+
_type: "message",
718+
role: outputItem.role || "assistant", // Get role from the message item
719+
content: messageText,
720+
id: outputItem.id || `resp-msg-${index}`, // Use ID from the output item if available
721+
});
722+
}
689723
}
690-
});
724+
);
691725

692726
return messages;
693727
};
@@ -729,15 +763,19 @@ export const mapOpenAIResponse = ({
729763
if (!requestMessages || requestMessages.length === 0) {
730764
return getRequestText(request); // Fallback to original method
731765
}
732-
766+
733767
// Look for the last user message or any message with content
734768
for (let i = requestMessages.length - 1; i >= 0; i--) {
735769
const message = requestMessages[i];
736-
if (message?.content && typeof message.content === "string" && message.content.trim().length > 0) {
770+
if (
771+
message?.content &&
772+
typeof message.content === "string" &&
773+
message.content.trim().length > 0
774+
) {
737775
return message.content;
738776
}
739777
}
740-
778+
741779
return "";
742780
};
743781

0 commit comments

Comments
 (0)