




















@@ -70,6 +70,7 @@ import { mergeTransportMetadata, sanitizeTransportPayloadText } from "./transpor
7070const DEFAULT_AZURE_OPENAI_API_VERSION = "2024-12-01-preview";
7171const OPENAI_CODEX_RESPONSES_EMPTY_INPUT_TEXT = " ";
7272const GEMINI_THOUGHT_SIGNATURE_VALIDATOR_SKIP = "skip_thought_signature_validator";
73+const AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS = 30_000;
7374const log = createSubsystemLogger("openai-transport");
74757576type ReplayableResponseOutputMessage = Omit<ResponseOutputMessage, "id"> & { id?: string };
@@ -649,6 +650,61 @@ function resolveOpenAIStrictToolFlagWithDiagnostics(
649650return strict;
650651}
651652653+function createResponsesFirstEventTimeoutError(model: Model<Api>, timeoutMs: number): Error {
654+return new Error(
655+`Azure OpenAI Responses stream did not deliver a first event within ${timeoutMs}ms after HTTP streaming headers. ` +
656+`provider=${model.provider} model=${model.id}. ` +
657+"The provider may be stalled while parsing the tool payload; retry with a smaller tool surface or enable OPENCLAW_DEBUG_MODEL_PAYLOAD=tools to inspect exposed tools.",
658+);
659+}
660+661+function withResponsesFirstEventTimeout(
662+openaiStream: AsyncIterable<unknown>,
663+model: Model<Api>,
664+timeoutMs: number | undefined,
665+): AsyncIterable<unknown> {
666+if (timeoutMs === undefined || timeoutMs <= 0 || !Number.isFinite(timeoutMs)) {
667+return openaiStream;
668+}
669+return {
670+async *[Symbol.asyncIterator]() {
671+const iterator = openaiStream[Symbol.asyncIterator]();
672+let timer: ReturnType<typeof setTimeout> | undefined;
673+const clear = () => {
674+if (timer) {
675+clearTimeout(timer);
676+timer = undefined;
677+}
678+};
679+try {
680+const first = await new Promise<IteratorResult<unknown>>((resolve, reject) => {
681+timer = setTimeout(
682+() => reject(createResponsesFirstEventTimeoutError(model, timeoutMs)),
683+timeoutMs,
684+);
685+iterator.next().then(resolve, reject);
686+}).finally(clear);
687+if (first.done) {
688+return;
689+}
690+yield first.value;
691+for (;;) {
692+const next = await iterator.next();
693+if (next.done) {
694+return;
695+}
696+yield next.value;
697+}
698+} catch (error) {
699+void iterator.return?.().catch(() => undefined);
700+throw error;
701+} finally {
702+clear();
703+}
704+},
705+};
706+}
707+652708async function processResponsesStream(
653709openaiStream: AsyncIterable<unknown>,
654710output: MutableAssistantOutput,
@@ -660,6 +716,7 @@ async function processResponsesStream(
660716usage: MutableAssistantOutput["usage"],
661717serviceTier?: ResponseCreateParamsStreaming["service_tier"],
662718) => void;
719+firstEventTimeoutMs?: number;
663720},
664721) {
665722let currentItem: Record<string, unknown> | null = null;
@@ -669,7 +726,12 @@ async function processResponsesStream(
669726const eventTypes = new Map<string, number>();
670727const sseDebugMode = resolveModelSseDebugMode();
671728const blockIndex = () => output.content.length - 1;
672-for await (const rawEvent of openaiStream) {
729+const guardedStream = withResponsesFirstEventTimeout(
730+openaiStream,
731+model,
732+options?.firstEventTimeoutMs,
733+);
734+for await (const rawEvent of guardedStream) {
673735const event = rawEvent as Record<string, unknown>;
674736const type = stringifyUnknown(event.type);
675737eventCount += 1;
@@ -1421,7 +1483,9 @@ export function createAzureOpenAIResponsesTransportStreamFn(): StreamFn {
14211483`elapsedMs=${Date.now() - requestStartedAt}`,
14221484);
14231485stream.push({ type: "start", partial: output as never });
1424-await processResponsesStream(responseStream, output, stream, model);
1486+await processResponsesStream(responseStream, output, stream, model, {
1487+firstEventTimeoutMs: AZURE_RESPONSES_FIRST_EVENT_TIMEOUT_MS,
1488+});
14251489if (options?.signal?.aborted) {
14261490throw new Error("Request was aborted");
14271491}
@@ -2455,7 +2519,9 @@ export const __testing = {
24552519 sanitizeOpenAICodexResponsesParams,
24562520 buildOpenAICompletionsClientConfig,
24572521 processOpenAICompletionsStream,
2522+ processResponsesStream,
24582523 formatModelTransportDebugBaseUrl,
24592524 summarizeResponsesPayload,
24602525 summarizeResponsesTools,
2526+ withResponsesFirstEventTimeout,
24612527};
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。