mirror of
https://github.com/Nezumi-2711/9router.git
synced 2026-09-22 13:38:31 +00:00
feat(responses): respect client streaming preference + string input support (#121)
- Remove forced stream=true from responsesHandler - Add stream-to-JSON converter for non-streaming clients (Codex) - Accept string input in Responses API (normalize to array) - Codex SSE header fallback for missing Content-Type - Refactor: extract shared normalizeResponsesInput() Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com> Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
committed by
decolua
co-authored by
Claude Sonnet 4.5
Cursor
parent
202fee714b
commit
ac7cedd27e
@@ -1,3 +1,18 @@
|
||||
/**
|
||||
* Normalize Responses API input to array format.
|
||||
* Accepts string or array, returns array of message items.
|
||||
* @param {string|Array} input - raw input from Responses API body
|
||||
* @returns {Array|null} normalized array or null if invalid
|
||||
*/
|
||||
export function normalizeResponsesInput(input) {
|
||||
if (typeof input === "string") {
|
||||
const text = input.trim() === "" ? "..." : input;
|
||||
return [{ type: "message", role: "user", content: [{ type: "input_text", text }] }];
|
||||
}
|
||||
if (Array.isArray(input)) return input;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert OpenAI Responses API format to standard chat completions format
|
||||
* Responses API uses: { input: [...], instructions: "..." }
|
||||
@@ -19,7 +34,10 @@ export function convertResponsesApiFormat(body) {
|
||||
let pendingToolCalls = [];
|
||||
let pendingToolResults = [];
|
||||
|
||||
for (const item of body.input) {
|
||||
const inputItems = normalizeResponsesInput(body.input);
|
||||
if (!inputItems) return body;
|
||||
|
||||
for (const item of inputItems) {
|
||||
// Determine item type - Droid CLI sends role-based items without 'type' field
|
||||
// Fallback: if no type but has role property, treat as message
|
||||
const itemType = item.type || (item.role ? "message" : null);
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
*/
|
||||
import { register } from "../index.js";
|
||||
import { FORMATS } from "../formats.js";
|
||||
import { normalizeResponsesInput } from "../helpers/responsesApiHelper.js";
|
||||
|
||||
/**
|
||||
* Convert OpenAI Responses API request to OpenAI Chat Completions format
|
||||
@@ -25,7 +26,10 @@ export function openaiResponsesToOpenAIRequest(model, body, stream, credentials)
|
||||
let currentAssistantMsg = null;
|
||||
let pendingToolResults = [];
|
||||
|
||||
for (const item of body.input) {
|
||||
const inputItems = normalizeResponsesInput(body.input);
|
||||
if (!inputItems) return body;
|
||||
|
||||
for (const item of inputItems) {
|
||||
// Determine item type - Droid CLI sends role-based items without 'type' field
|
||||
// Fallback: if no type but has role property, treat as message
|
||||
const itemType = item.type || (item.role ? "message" : null);
|
||||
@@ -234,4 +238,3 @@ export function openaiToOpenAIResponsesRequest(model, body, stream, credentials)
|
||||
// Register both directions
|
||||
register(FORMATS.OPENAI_RESPONSES, FORMATS.OPENAI, openaiResponsesToOpenAIRequest, null);
|
||||
register(FORMATS.OPENAI, FORMATS.OPENAI_RESPONSES, openaiToOpenAIResponsesRequest, null);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user