chore: Enable "curly" rule to avoid single-statement if confusion/errors.

This commit is contained in:
cpojer
2026-01-31 16:19:20 +09:00
parent 009b16fab8
commit 5ceff756e1
1266 changed files with 27871 additions and 9393 deletions

View File

@@ -20,13 +20,19 @@ type ThoughtSignatureSanitizeOptions = {
function isBase64Signature(value: string): boolean {
const trimmed = value.trim();
if (!trimmed) return false;
if (!trimmed) {
return false;
}
const compact = trimmed.replace(/\s+/g, "");
if (!/^[A-Za-z0-9+/=_-]+$/.test(compact)) return false;
if (!/^[A-Za-z0-9+/=_-]+$/.test(compact)) {
return false;
}
const isUrl = compact.includes("-") || compact.includes("_");
try {
const buf = Buffer.from(compact, isUrl ? "base64url" : "base64");
if (buf.length === 0) return false;
if (buf.length === 0) {
return false;
}
const encoded = buf.toString(isUrl ? "base64url" : "base64");
const normalize = (input: string) => input.replace(/=+$/g, "");
return normalize(encoded) === normalize(compact);
@@ -45,7 +51,9 @@ export function stripThoughtSignatures<T>(
content: T,
options?: ThoughtSignatureSanitizeOptions,
): T {
if (!Array.isArray(content)) return content;
if (!Array.isArray(content)) {
return content;
}
const allowBase64Only = options?.allowBase64Only ?? false;
const includeCamelCase = options?.includeCamelCase ?? false;
const shouldStripSignature = (value: unknown): boolean => {
@@ -55,7 +63,9 @@ export function stripThoughtSignatures<T>(
return typeof value !== "string" || !isBase64Signature(value);
};
return content.map((block) => {
if (!block || typeof block !== "object") return block;
if (!block || typeof block !== "object") {
return block;
}
const rec = block as ContentBlockWithSignature;
const stripSnake = shouldStripSignature(rec.thought_signature);
const stripCamel = includeCamelCase ? shouldStripSignature(rec.thoughtSignature) : false;
@@ -63,8 +73,12 @@ export function stripThoughtSignatures<T>(
return block;
}
const next = { ...rec };
if (stripSnake) delete next.thought_signature;
if (stripCamel) delete next.thoughtSignature;
if (stripSnake) {
delete next.thought_signature;
}
if (stripCamel) {
delete next.thoughtSignature;
}
return next;
}) as T;
}
@@ -162,7 +176,9 @@ export function buildBootstrapContextFiles(
continue;
}
const trimmed = trimBootstrapContent(file.content ?? "", file.name, maxChars);
if (!trimmed.content) continue;
if (!trimmed.content) {
continue;
}
if (trimmed.truncated) {
opts?.warn?.(
`workspace bootstrap file ${file.name} is ${trimmed.originalLength} chars (limit ${trimmed.maxChars}); truncating in injected context`,
@@ -188,7 +204,9 @@ export function sanitizeGoogleTurnOrdering(messages: AgentMessage[]): AgentMessa
) {
return messages;
}
if (role !== "assistant") return messages;
if (role !== "assistant") {
return messages;
}
// Cloud Code Assist rejects histories that begin with a model turn (tool call or text).
// Prepend a tiny synthetic user turn so the rest of the transcript can be used.

View File

@@ -5,7 +5,9 @@ import { formatSandboxToolPolicyBlockedMessage } from "../sandbox.js";
import type { FailoverReason } from "./types.js";
export function isContextOverflowError(errorMessage?: string): boolean {
if (!errorMessage) return false;
if (!errorMessage) {
return false;
}
const lower = errorMessage.toLowerCase();
const hasRequestSizeExceeds = lower.includes("request size exceeds");
const hasContextWindow =
@@ -30,15 +32,25 @@ const CONTEXT_OVERFLOW_HINT_RE =
/context.*overflow|context window.*(too (?:large|long)|exceed|over|limit|max(?:imum)?|requested|sent|tokens)|(?:prompt|request|input).*(too (?:large|long)|exceed|over|limit|max(?:imum)?)/i;
export function isLikelyContextOverflowError(errorMessage?: string): boolean {
if (!errorMessage) return false;
if (CONTEXT_WINDOW_TOO_SMALL_RE.test(errorMessage)) return false;
if (isContextOverflowError(errorMessage)) return true;
if (!errorMessage) {
return false;
}
if (CONTEXT_WINDOW_TOO_SMALL_RE.test(errorMessage)) {
return false;
}
if (isContextOverflowError(errorMessage)) {
return true;
}
return CONTEXT_OVERFLOW_HINT_RE.test(errorMessage);
}
export function isCompactionFailureError(errorMessage?: string): boolean {
if (!errorMessage) return false;
if (!isContextOverflowError(errorMessage)) return false;
if (!errorMessage) {
return false;
}
if (!isContextOverflowError(errorMessage)) {
return false;
}
const lower = errorMessage.toLowerCase();
return (
lower.includes("summarization failed") ||
@@ -73,15 +85,21 @@ const HTTP_ERROR_HINTS = [
];
function stripFinalTagsFromText(text: string): string {
if (!text) return text;
if (!text) {
return text;
}
return text.replace(FINAL_TAG_RE, "");
}
function collapseConsecutiveDuplicateBlocks(text: string): string {
const trimmed = text.trim();
if (!trimmed) return text;
if (!trimmed) {
return text;
}
const blocks = trimmed.split(/\n{2,}/);
if (blocks.length < 2) return text;
if (blocks.length < 2) {
return text;
}
const normalizeBlock = (value: string) => value.trim().replace(/\s+/g, " ");
const result: string[] = [];
@@ -96,15 +114,21 @@ function collapseConsecutiveDuplicateBlocks(text: string): string {
lastNormalized = normalized;
}
if (result.length === blocks.length) return text;
if (result.length === blocks.length) {
return text;
}
return result.join("\n\n");
}
function isLikelyHttpErrorText(raw: string): boolean {
const match = raw.match(HTTP_STATUS_PREFIX_RE);
if (!match) return false;
if (!match) {
return false;
}
const code = Number(match[1]);
if (!Number.isFinite(code) || code < 400) return false;
if (!Number.isFinite(code) || code < 400) {
return false;
}
const message = match[2].toLowerCase();
return HTTP_ERROR_HINTS.some((hint) => message.includes(hint));
}
@@ -112,10 +136,16 @@ function isLikelyHttpErrorText(raw: string): boolean {
type ErrorPayload = Record<string, unknown>;
function isErrorPayloadObject(payload: unknown): payload is ErrorPayload {
if (!payload || typeof payload !== "object" || Array.isArray(payload)) return false;
if (!payload || typeof payload !== "object" || Array.isArray(payload)) {
return false;
}
const record = payload as ErrorPayload;
if (record.type === "error") return true;
if (typeof record.request_id === "string" || typeof record.requestId === "string") return true;
if (record.type === "error") {
return true;
}
if (typeof record.request_id === "string" || typeof record.requestId === "string") {
return true;
}
if ("error" in record) {
const err = record.error;
if (err && typeof err === "object" && !Array.isArray(err)) {
@@ -133,18 +163,26 @@ function isErrorPayloadObject(payload: unknown): payload is ErrorPayload {
}
function parseApiErrorPayload(raw: string): ErrorPayload | null {
if (!raw) return null;
if (!raw) {
return null;
}
const trimmed = raw.trim();
if (!trimmed) return null;
if (!trimmed) {
return null;
}
const candidates = [trimmed];
if (ERROR_PAYLOAD_PREFIX_RE.test(trimmed)) {
candidates.push(trimmed.replace(ERROR_PAYLOAD_PREFIX_RE, "").trim());
}
for (const candidate of candidates) {
if (!candidate.startsWith("{") || !candidate.endsWith("}")) continue;
if (!candidate.startsWith("{") || !candidate.endsWith("}")) {
continue;
}
try {
const parsed = JSON.parse(candidate) as unknown;
if (isErrorPayloadObject(parsed)) return parsed;
if (isErrorPayloadObject(parsed)) {
return parsed;
}
} catch {
// ignore parse errors
}
@@ -166,9 +204,13 @@ function stableStringify(value: unknown): string {
}
export function getApiErrorPayloadFingerprint(raw?: string): string | null {
if (!raw) return null;
if (!raw) {
return null;
}
const payload = parseApiErrorPayload(raw);
if (!payload) return null;
if (!payload) {
return null;
}
return stableStringify(payload);
}
@@ -184,9 +226,13 @@ export type ApiErrorInfo = {
};
export function parseApiErrorInfo(raw?: string): ApiErrorInfo | null {
if (!raw) return null;
if (!raw) {
return null;
}
const trimmed = raw.trim();
if (!trimmed) return null;
if (!trimmed) {
return null;
}
let httpCode: string | undefined;
let candidate = trimmed;
@@ -198,7 +244,9 @@ export function parseApiErrorInfo(raw?: string): ApiErrorInfo | null {
}
const payload = parseApiErrorPayload(candidate);
if (!payload) return null;
if (!payload) {
return null;
}
const requestId =
typeof payload.request_id === "string"
@@ -214,9 +262,15 @@ export function parseApiErrorInfo(raw?: string): ApiErrorInfo | null {
let errMessage: string | undefined;
if (payload.error && typeof payload.error === "object" && !Array.isArray(payload.error)) {
const err = payload.error as Record<string, unknown>;
if (typeof err.type === "string") errType = err.type;
if (typeof err.code === "string" && !errType) errType = err.code;
if (typeof err.message === "string") errMessage = err.message;
if (typeof err.type === "string") {
errType = err.type;
}
if (typeof err.code === "string" && !errType) {
errType = err.code;
}
if (typeof err.message === "string") {
errMessage = err.message;
}
}
return {
@@ -229,7 +283,9 @@ export function parseApiErrorInfo(raw?: string): ApiErrorInfo | null {
export function formatRawAssistantErrorForUi(raw?: string): string {
const trimmed = (raw ?? "").trim();
if (!trimmed) return "LLM request failed with an unknown error.";
if (!trimmed) {
return "LLM request failed with an unknown error.";
}
const httpMatch = trimmed.match(HTTP_STATUS_PREFIX_RE);
if (httpMatch) {
@@ -256,8 +312,12 @@ export function formatAssistantErrorText(
): string | undefined {
// Also format errors if errorMessage is present, even if stopReason isn't "error"
const raw = (msg.errorMessage ?? "").trim();
if (msg.stopReason !== "error" && !raw) return undefined;
if (!raw) return "LLM request failed with an unknown error.";
if (msg.stopReason !== "error" && !raw) {
return undefined;
}
if (!raw) {
return "LLM request failed with an unknown error.";
}
const unknownTool =
raw.match(/unknown tool[:\s]+["']?([a-z0-9_-]+)["']?/i) ??
@@ -268,7 +328,9 @@ export function formatAssistantErrorText(
sessionKey: opts?.sessionKey,
toolName: unknownTool[1],
});
if (rewritten) return rewritten;
if (rewritten) {
return rewritten;
}
}
if (isContextOverflowError(raw)) {
@@ -311,10 +373,14 @@ export function formatAssistantErrorText(
}
export function sanitizeUserFacingText(text: string): string {
if (!text) return text;
if (!text) {
return text;
}
const stripped = stripFinalTagsFromText(text);
const trimmed = stripped.trim();
if (!trimmed) return stripped;
if (!trimmed) {
return stripped;
}
if (/incorrect role information|roles must alternate/i.test(trimmed)) {
return (
@@ -348,7 +414,9 @@ export function sanitizeUserFacingText(text: string): string {
}
export function isRateLimitAssistantError(msg: AssistantMessage | undefined): boolean {
if (!msg || msg.stopReason !== "error") return false;
if (!msg || msg.stopReason !== "error") {
return false;
}
return isRateLimitErrorMessage(msg.errorMessage ?? "");
}
@@ -404,7 +472,9 @@ const IMAGE_DIMENSION_PATH_RE = /messages\.(\d+)\.content\.(\d+)\.image/i;
const IMAGE_SIZE_ERROR_RE = /image exceeds\s*(\d+(?:\.\d+)?)\s*mb/i;
function matchesErrorPatterns(raw: string, patterns: readonly ErrorPattern[]): boolean {
if (!raw) return false;
if (!raw) {
return false;
}
const value = raw.toLowerCase();
return patterns.some((pattern) =>
pattern instanceof RegExp ? pattern.test(value) : value.includes(pattern),
@@ -421,8 +491,12 @@ export function isTimeoutErrorMessage(raw: string): boolean {
export function isBillingErrorMessage(raw: string): boolean {
const value = raw.toLowerCase();
if (!value) return false;
if (matchesErrorPatterns(value, ERROR_PATTERNS.billing)) return true;
if (!value) {
return false;
}
if (matchesErrorPatterns(value, ERROR_PATTERNS.billing)) {
return true;
}
return (
value.includes("billing") &&
(value.includes("upgrade") ||
@@ -433,7 +507,9 @@ export function isBillingErrorMessage(raw: string): boolean {
}
export function isBillingAssistantError(msg: AssistantMessage | undefined): boolean {
if (!msg || msg.stopReason !== "error") return false;
if (!msg || msg.stopReason !== "error") {
return false;
}
return isBillingErrorMessage(msg.errorMessage ?? "");
}
@@ -451,9 +527,13 @@ export function parseImageDimensionError(raw: string): {
contentIndex?: number;
raw: string;
} | null {
if (!raw) return null;
if (!raw) {
return null;
}
const lower = raw.toLowerCase();
if (!lower.includes("image dimensions exceed max allowed size")) return null;
if (!lower.includes("image dimensions exceed max allowed size")) {
return null;
}
const limitMatch = raw.match(IMAGE_DIMENSION_ERROR_RE);
const pathMatch = raw.match(IMAGE_DIMENSION_PATH_RE);
return {
@@ -472,9 +552,13 @@ export function parseImageSizeError(raw: string): {
maxMb?: number;
raw: string;
} | null {
if (!raw) return null;
if (!raw) {
return null;
}
const lower = raw.toLowerCase();
if (!lower.includes("image exceeds") || !lower.includes("mb")) return null;
if (!lower.includes("image exceeds") || !lower.includes("mb")) {
return null;
}
const match = raw.match(IMAGE_SIZE_ERROR_RE);
return {
maxMb: match?.[1] ? Number.parseFloat(match[1]) : undefined,
@@ -483,7 +567,9 @@ export function parseImageSizeError(raw: string): {
}
export function isImageSizeError(errorMessage?: string): boolean {
if (!errorMessage) return false;
if (!errorMessage) {
return false;
}
return Boolean(parseImageSizeError(errorMessage));
}
@@ -492,19 +578,37 @@ export function isCloudCodeAssistFormatError(raw: string): boolean {
}
export function isAuthAssistantError(msg: AssistantMessage | undefined): boolean {
if (!msg || msg.stopReason !== "error") return false;
if (!msg || msg.stopReason !== "error") {
return false;
}
return isAuthErrorMessage(msg.errorMessage ?? "");
}
export function classifyFailoverReason(raw: string): FailoverReason | null {
if (isImageDimensionErrorMessage(raw)) return null;
if (isImageSizeError(raw)) return null;
if (isRateLimitErrorMessage(raw)) return "rate_limit";
if (isOverloadedErrorMessage(raw)) return "rate_limit";
if (isCloudCodeAssistFormatError(raw)) return "format";
if (isBillingErrorMessage(raw)) return "billing";
if (isTimeoutErrorMessage(raw)) return "timeout";
if (isAuthErrorMessage(raw)) return "auth";
if (isImageDimensionErrorMessage(raw)) {
return null;
}
if (isImageSizeError(raw)) {
return null;
}
if (isRateLimitErrorMessage(raw)) {
return "rate_limit";
}
if (isOverloadedErrorMessage(raw)) {
return "rate_limit";
}
if (isCloudCodeAssistFormatError(raw)) {
return "format";
}
if (isBillingErrorMessage(raw)) {
return "billing";
}
if (isTimeoutErrorMessage(raw)) {
return "timeout";
}
if (isAuthErrorMessage(raw)) {
return "auth";
}
return null;
}
@@ -513,6 +617,8 @@ export function isFailoverErrorMessage(raw: string): boolean {
}
export function isFailoverAssistantError(msg: AssistantMessage | undefined): boolean {
if (!msg || msg.stopReason !== "error") return false;
if (!msg || msg.stopReason !== "error") {
return false;
}
return isFailoverErrorMessage(msg.errorMessage ?? "");
}

View File

@@ -13,7 +13,9 @@ export function isAntigravityClaude(params: {
}): boolean {
const provider = params.provider?.toLowerCase();
const api = params.api?.toLowerCase();
if (provider !== "google-antigravity" && api !== "google-antigravity") return false;
if (provider !== "google-antigravity" && api !== "google-antigravity") {
return false;
}
return params.modelId?.toLowerCase().includes("claude") ?? false;
}

View File

@@ -11,12 +11,20 @@ export function isEmptyAssistantMessageContent(
message: Extract<AgentMessage, { role: "assistant" }>,
): boolean {
const content = message.content;
if (content == null) return true;
if (!Array.isArray(content)) return false;
if (content == null) {
return true;
}
if (!Array.isArray(content)) {
return false;
}
return content.every((block) => {
if (!block || typeof block !== "object") return true;
if (!block || typeof block !== "object") {
return true;
}
const rec = block as { type?: unknown; text?: unknown };
if (rec.type !== "text") return false;
if (rec.type !== "text") {
return false;
}
return typeof rec.text !== "string" || rec.text.trim().length === 0;
});
}
@@ -110,9 +118,13 @@ export async function sanitizeSessionMessagesImages(
: stripThoughtSignatures(content, options?.sanitizeThoughtSignatures); // Strip for Gemini
const filteredContent = strippedContent.filter((block) => {
if (!block || typeof block !== "object") return true;
if (!block || typeof block !== "object") {
return true;
}
const rec = block as { type?: unknown; text?: unknown };
if (rec.type !== "text" || typeof rec.text !== "string") return true;
if (rec.type !== "text" || typeof rec.text !== "string") {
return true;
}
return rec.text.trim().length > 0;
});
const finalContent = (await sanitizeContentBlocksImages(

View File

@@ -20,17 +20,27 @@ export function isMessagingToolDuplicateNormalized(
normalized: string,
normalizedSentTexts: string[],
): boolean {
if (normalizedSentTexts.length === 0) return false;
if (!normalized || normalized.length < MIN_DUPLICATE_TEXT_LENGTH) return false;
if (normalizedSentTexts.length === 0) {
return false;
}
if (!normalized || normalized.length < MIN_DUPLICATE_TEXT_LENGTH) {
return false;
}
return normalizedSentTexts.some((normalizedSent) => {
if (!normalizedSent || normalizedSent.length < MIN_DUPLICATE_TEXT_LENGTH) return false;
if (!normalizedSent || normalizedSent.length < MIN_DUPLICATE_TEXT_LENGTH) {
return false;
}
return normalized.includes(normalizedSent) || normalizedSent.includes(normalized);
});
}
export function isMessagingToolDuplicate(text: string, sentTexts: string[]): boolean {
if (sentTexts.length === 0) return false;
if (sentTexts.length === 0) {
return false;
}
const normalized = normalizeTextForComparison(text);
if (!normalized || normalized.length < MIN_DUPLICATE_TEXT_LENGTH) return false;
if (!normalized || normalized.length < MIN_DUPLICATE_TEXT_LENGTH) {
return false;
}
return isMessagingToolDuplicateNormalized(normalized, sentTexts.map(normalizeTextForComparison));
}

View File

@@ -12,11 +12,15 @@ type OpenAIReasoningSignature = {
};
function parseOpenAIReasoningSignature(value: unknown): OpenAIReasoningSignature | null {
if (!value) return null;
if (!value) {
return null;
}
let candidate: { id?: unknown; type?: unknown } | null = null;
if (typeof value === "string") {
const trimmed = value.trim();
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) return null;
if (!trimmed.startsWith("{") || !trimmed.endsWith("}")) {
return null;
}
try {
candidate = JSON.parse(trimmed) as { id?: unknown; type?: unknown };
} catch {
@@ -25,10 +29,14 @@ function parseOpenAIReasoningSignature(value: unknown): OpenAIReasoningSignature
} else if (typeof value === "object") {
candidate = value as { id?: unknown; type?: unknown };
}
if (!candidate) return null;
if (!candidate) {
return null;
}
const id = typeof candidate.id === "string" ? candidate.id : "";
const type = typeof candidate.type === "string" ? candidate.type : "";
if (!id.startsWith("rs_")) return null;
if (!id.startsWith("rs_")) {
return null;
}
if (type === "reasoning" || type.startsWith("reasoning.")) {
return { id, type };
}
@@ -41,8 +49,12 @@ function hasFollowingNonThinkingBlock(
): boolean {
for (let i = index + 1; i < content.length; i++) {
const block = content[i];
if (!block || typeof block !== "object") return true;
if ((block as { type?: unknown }).type !== "thinking") return true;
if (!block || typeof block !== "object") {
return true;
}
if ((block as { type?: unknown }).type !== "thinking") {
return true;
}
}
return false;
}

View File

@@ -3,7 +3,9 @@ import { normalizeThinkLevel, type ThinkLevel } from "../../auto-reply/thinking.
function extractSupportedValues(raw: string): string[] {
const match =
raw.match(/supported values are:\s*([^\n.]+)/i) ?? raw.match(/supported values:\s*([^\n.]+)/i);
if (!match?.[1]) return [];
if (!match?.[1]) {
return [];
}
const fragment = match[1];
const quoted = Array.from(fragment.matchAll(/['"]([^'"]+)['"]/g)).map((entry) =>
entry[1]?.trim(),
@@ -22,13 +24,21 @@ export function pickFallbackThinkingLevel(params: {
attempted: Set<ThinkLevel>;
}): ThinkLevel | undefined {
const raw = params.message?.trim();
if (!raw) return undefined;
if (!raw) {
return undefined;
}
const supported = extractSupportedValues(raw);
if (supported.length === 0) return undefined;
if (supported.length === 0) {
return undefined;
}
for (const entry of supported) {
const normalized = normalizeThinkLevel(entry);
if (!normalized) continue;
if (params.attempted.has(normalized)) continue;
if (!normalized) {
continue;
}
if (params.attempted.has(normalized)) {
continue;
}
return normalized;
}
return undefined;