style: reformat

This commit is contained in:
can1357
2026-04-01 04:50:07 +02:00
parent 77eddf80e9
commit 906123c97d
9 changed files with 74 additions and 65 deletions
@@ -20,7 +20,13 @@ import {
} from "../types";
import { AssistantMessageEventStream } from "../utils/event-stream";
import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
import { createFirstEventWatchdog, getOpenAIStreamIdleTimeoutMs, getStreamFirstEventTimeoutMs, iterateWithIdleTimeout, markFirstStreamEvent } from "../utils/idle-iterator";
import {
createFirstEventWatchdog,
getOpenAIStreamIdleTimeoutMs,
getStreamFirstEventTimeoutMs,
iterateWithIdleTimeout,
markFirstStreamEvent,
} from "../utils/idle-iterator";
import { mapToOpenAIResponsesToolChoice } from "../utils/tool-choice";
import { supportsDeveloperRole } from "./openai-responses";
import {
@@ -121,9 +127,8 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
? AbortSignal.any([options.signal, requestAbortController.signal])
: requestAbortController.signal;
const idleTimeoutMs = getOpenAIStreamIdleTimeoutMs();
const firstEventWatchdog = createFirstEventWatchdog(
getStreamFirstEventTimeoutMs(idleTimeoutMs),
() => requestAbortController.abort(),
const firstEventWatchdog = createFirstEventWatchdog(getStreamFirstEventTimeoutMs(idleTimeoutMs), () =>
requestAbortController.abort(),
);
options?.onPayload?.(params);
rawRequestDump = {
@@ -138,14 +143,11 @@ export const streamAzureOpenAIResponses: StreamFunction<"azure-openai-responses"
stream.push({ type: "start", partial: output });
await processResponsesStream(
iterateWithIdleTimeout(
markFirstStreamEvent(openaiStream, firstEventWatchdog),
{
idleTimeoutMs,
errorMessage: "Azure OpenAI responses stream stalled while waiting for the next event",
onIdle: () => requestAbortController.abort(),
},
),
iterateWithIdleTimeout(markFirstStreamEvent(openaiStream, firstEventWatchdog), {
idleTimeoutMs,
errorMessage: "Azure OpenAI responses stream stalled while waiting for the next event",
onIdle: () => requestAbortController.abort(),
}),
output,
stream,
model,
+14 -12
View File
@@ -30,7 +30,13 @@ import {
} from "../utils";
import { AssistantMessageEventStream } from "../utils/event-stream";
import { finalizeErrorMessage, type RawHttpRequestDump } from "../utils/http-inspector";
import { createFirstEventWatchdog, getOpenAIStreamIdleTimeoutMs, getStreamFirstEventTimeoutMs, iterateWithIdleTimeout, markFirstStreamEvent } from "../utils/idle-iterator";
import {
createFirstEventWatchdog,
getOpenAIStreamIdleTimeoutMs,
getStreamFirstEventTimeoutMs,
iterateWithIdleTimeout,
markFirstStreamEvent,
} from "../utils/idle-iterator";
import { adaptSchemaForStrict, NO_STRICT } from "../utils/schema";
import { mapToOpenAIResponsesToolChoice } from "../utils/tool-choice";
import {
@@ -173,9 +179,8 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
? AbortSignal.any([options.signal, requestAbortController.signal])
: requestAbortController.signal;
const idleTimeoutMs = getOpenAIStreamIdleTimeoutMs();
const firstEventWatchdog = createFirstEventWatchdog(
getStreamFirstEventTimeoutMs(idleTimeoutMs),
() => requestAbortController.abort(),
const firstEventWatchdog = createFirstEventWatchdog(getStreamFirstEventTimeoutMs(idleTimeoutMs), () =>
requestAbortController.abort(),
);
options?.onPayload?.(params);
rawRequestDump = {
@@ -192,14 +197,11 @@ export const streamOpenAIResponses: StreamFunction<"openai-responses"> = (
const nativeOutputItems: Array<Record<string, unknown>> = [];
await processResponsesStream(
iterateWithIdleTimeout(
markFirstStreamEvent(openaiStream, firstEventWatchdog),
{
idleTimeoutMs,
errorMessage: "OpenAI responses stream stalled while waiting for the next event",
onIdle: () => requestAbortController.abort(),
},
),
iterateWithIdleTimeout(markFirstStreamEvent(openaiStream, firstEventWatchdog), {
idleTimeoutMs,
errorMessage: "OpenAI responses stream stalled while waiting for the next event",
onIdle: () => requestAbortController.abort(),
}),
output,
stream,
model,
+12 -7
View File
@@ -26,7 +26,10 @@ export function getOpenAIStreamIdleTimeoutMs(): number | undefined {
* Set `PI_STREAM_FIRST_EVENT_TIMEOUT_MS=0` to disable the watchdog.
*/
export function getStreamFirstEventTimeoutMs(idleTimeoutMs?: number): number | undefined {
const fallback = Math.min(DEFAULT_STREAM_FIRST_EVENT_TIMEOUT_MS, idleTimeoutMs ?? DEFAULT_STREAM_FIRST_EVENT_TIMEOUT_MS);
const fallback = Math.min(
DEFAULT_STREAM_FIRST_EVENT_TIMEOUT_MS,
idleTimeoutMs ?? DEFAULT_STREAM_FIRST_EVENT_TIMEOUT_MS,
);
return normalizeIdleTimeoutMs($env.PI_STREAM_FIRST_EVENT_TIMEOUT_MS, fallback);
}
@@ -39,10 +42,7 @@ export interface FirstEventWatchdog {
* Starts a watchdog that aborts a request if no first stream event arrives in time.
* Call `markFirstEventReceived()` as soon as the first event is observed.
*/
export function createFirstEventWatchdog(
timeoutMs: number | undefined,
onTimeout: () => void,
): FirstEventWatchdog {
export function createFirstEventWatchdog(timeoutMs: number | undefined, onTimeout: () => void): FirstEventWatchdog {
let timer: NodeJS.Timeout | undefined;
if (timeoutMs !== undefined && timeoutMs > 0) {
timer = setTimeout(() => {
@@ -105,7 +105,10 @@ export async function* iterateWithIdleTimeout<T>(
options: IdleTimeoutIteratorOptions,
): AsyncGenerator<T> {
const firstItemTimeoutMs = options.firstItemTimeoutMs ?? options.idleTimeoutMs;
if ((firstItemTimeoutMs === undefined || firstItemTimeoutMs <= 0) && (options.idleTimeoutMs === undefined || options.idleTimeoutMs <= 0)) {
if (
(firstItemTimeoutMs === undefined || firstItemTimeoutMs <= 0) &&
(options.idleTimeoutMs === undefined || options.idleTimeoutMs <= 0)
) {
for await (const item of iterable) {
yield item;
}
@@ -152,7 +155,9 @@ export async function* iterateWithIdleTimeout<T>(
if (returnPromise) {
void returnPromise.catch(() => {});
}
throw new Error(sawFirstItem ? options.errorMessage : (options.firstItemErrorMessage ?? options.errorMessage));
throw new Error(
sawFirstItem ? options.errorMessage : (options.firstItemErrorMessage ?? options.errorMessage),
);
}
if (outcome.kind === "error") {
throw outcome.error;
@@ -11,8 +11,7 @@
import type { OAuthController } from "./types";
const AUTH_URL =
"https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway%2Fapi-keys&title=AI+Gateway+API+Keys";
const AUTH_URL = "https://vercel.com/d?to=%2F%5Bteam%5D%2F%7E%2Fai-gateway%2Fapi-keys&title=AI+Gateway+API+Keys";
/**
* Login to Vercel AI Gateway.
@@ -20,32 +19,29 @@ const AUTH_URL =
* Opens browser to Vercel AI Gateway docs and prompts for an API key.
* Returns the API key directly (not OAuthCredentials - this isn't OAuth).
*/
export async function loginVercelAiGateway(
options: OAuthController,
): Promise<string> {
if (!options.onPrompt) {
throw new Error("Vercel AI Gateway login requires onPrompt callback");
}
export async function loginVercelAiGateway(options: OAuthController): Promise<string> {
if (!options.onPrompt) {
throw new Error("Vercel AI Gateway login requires onPrompt callback");
}
options.onAuth?.({
url: AUTH_URL,
instructions:
"Copy your Vercel AI Gateway API key from the Vercel dashboard",
});
options.onAuth?.({
url: AUTH_URL,
instructions: "Copy your Vercel AI Gateway API key from the Vercel dashboard",
});
const apiKey = await options.onPrompt({
message: "Paste your Vercel AI Gateway API key",
placeholder: "vck_...",
});
const apiKey = await options.onPrompt({
message: "Paste your Vercel AI Gateway API key",
placeholder: "vck_...",
});
if (options.signal?.aborted) {
throw new Error("Login cancelled");
}
if (options.signal?.aborted) {
throw new Error("Login cancelled");
}
const trimmed = apiKey.trim();
if (!trimmed) {
throw new Error("API key is required");
}
const trimmed = apiKey.trim();
if (!trimmed) {
throw new Error("API key is required");
}
return trimmed;
return trimmed;
}
+3 -1
View File
@@ -19,7 +19,9 @@ describe("isProviderRetryableError", () => {
});
it("retries first-event timeout errors", () => {
expect(isProviderRetryableError(new Error("Anthropic stream timed out while waiting for the first event"))).toBe(true);
expect(isProviderRetryableError(new Error("Anthropic stream timed out while waiting for the first event"))).toBe(
true,
);
});
it("does not retry non-transient validation errors", () => {
@@ -100,9 +100,9 @@ describe("anthropic first-event timeout retries", () => {
vi.spyOn(Messages.prototype, "stream").mockImplementation((_body, requestOptions) => {
attempt += 1;
const signal = (requestOptions as { signal?: AbortSignal } | undefined)?.signal;
return (attempt === 1
? createHangingAnthropicStream(signal)
: createSuccessfulAnthropicStream("retry recovered")) as never;
return (
attempt === 1 ? createHangingAnthropicStream(signal) : createSuccessfulAnthropicStream("retry recovered")
) as never;
});
const result = await streamAnthropic(model, context, { apiKey: "sk-ant-test" }).result();
@@ -31,7 +31,7 @@ import { type ConfigError, ConfigFile } from "../config";
import { parseModelString } from "../config/model-resolver";
import { isValidThemeColor, type ThemeColor } from "../modes/theme/theme";
import type { AuthStorage, OAuthCredential } from "../session/auth-storage";
import { settings, type Settings } from "./settings";
import { type Settings, settings } from "./settings";
export const kNoAuth = "N/A";
+6 -3
View File
@@ -21,7 +21,7 @@ import {
shortenPath,
truncateDiffByHunk,
} from "../tools/render-utils";
import { Ellipsis, Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
import { Hasher, type RenderCache, renderStatusLine, truncateToWidth } from "../tui";
import type { HashlineToolEdit } from "./index";
import type { DiffError, DiffResult, Operation } from "./types";
@@ -242,7 +242,9 @@ function wrapEditRendererLine(line: string, width: number): string[] {
const continuationPrefix = `${" ".repeat(Math.max(0, prefixWidth - 1))}|`;
const wrappedContent = wrapTextWithAnsi(content, contentWidth);
return wrappedContent.map((segment, index) => `${startAnsi}${index === 0 ? prefix : continuationPrefix}${segment}\x1b[39m`);
return wrappedContent.map(
(segment, index) => `${startAnsi}${index === 0 ? prefix : continuationPrefix}${segment}\x1b[39m`,
);
}
export const editToolRenderer = {
@@ -379,7 +381,8 @@ export const editToolRenderer = {
);
}
const lines = width > 0 ? text.split("\n").flatMap(line => wrapEditRendererLine(line, width)) : text.split("\n");
const lines =
width > 0 ? text.split("\n").flatMap(line => wrapEditRendererLine(line, width)) : text.split("\n");
cached = { key, lines };
return lines;
},
@@ -28,7 +28,6 @@ function getTitleModel(
const availableModels = registry.getAvailable();
if (availableModels.length === 0) return undefined;
const matchPreferences = { usageOrder: settings.getStorage()?.getModelUsageOrder() };
const titleModel = resolveRoleSelection(["commit", "smol"], settings, availableModels);
if (titleModel) {
return { model: titleModel.model, thinkingLevel: titleModel.thinkingLevel };