70ddc01e10
Behavior-preserving cleanup of AI-generated code smells in 5 files authored/moved by this PR: - src/hooks/model-fallback/fallback-state-controller.ts (-47/+47 net reorganization, redundant defensiveness removed) - src/shared/model-string-parser.ts (-4 LOC obvious-comment cleanup) - src/shared/ripgrep-cli.ts (-13 LOC obvious comments + redundant defensive checks) - src/tools/delegate-task/tool-description.ts (-6 LOC) - src/tools/look-at/look-at-input-preparer.ts (-6 LOC) Targets: obvious comments that restate code, over-defensive null checks on guaranteed values, redundant existence checks. No public API signatures changed, no type hints removed, no new abstractions introduced. Full test suite still passes.
152 lines
4.3 KiB
TypeScript
152 lines
4.3 KiB
TypeScript
import { basename } from "node:path"
|
|
import { pathToFileURL } from "node:url"
|
|
import type { LookAtArgs } from "./types"
|
|
import {
|
|
extractBase64Data,
|
|
inferMimeTypeFromBase64,
|
|
inferMimeTypeFromFilePath,
|
|
} from "./mime-type-inference"
|
|
import {
|
|
needsConversion,
|
|
convertImageToJpeg,
|
|
convertBase64ImageToJpeg,
|
|
cleanupConvertedImage,
|
|
} from "./image-converter"
|
|
import { log } from "../../shared"
|
|
|
|
export interface LookAtFilePart {
|
|
type: "file"
|
|
mime: string
|
|
url: string
|
|
filename: string
|
|
}
|
|
|
|
export interface PreparedLookAtInput {
|
|
readonly filePart: LookAtFilePart
|
|
readonly isBase64Input: boolean
|
|
readonly sourceDescription: string
|
|
cleanup(): void
|
|
}
|
|
|
|
type PrepareLookAtInputResult =
|
|
| { ok: true; value: PreparedLookAtInput }
|
|
| { ok: false; error: string }
|
|
|
|
function getTemporaryConversionPath(error: unknown): string | null {
|
|
if (!(error instanceof Error)) {
|
|
return null
|
|
}
|
|
|
|
const temporaryOutputPath = Reflect.get(error, "temporaryOutputPath")
|
|
if (typeof temporaryOutputPath === "string" && temporaryOutputPath.length > 0) {
|
|
return temporaryOutputPath
|
|
}
|
|
|
|
const temporaryDirectory = Reflect.get(error, "temporaryDirectory")
|
|
if (typeof temporaryDirectory === "string" && temporaryDirectory.length > 0) {
|
|
return temporaryDirectory
|
|
}
|
|
|
|
return null
|
|
}
|
|
|
|
export function prepareLookAtInput(args: LookAtArgs): PrepareLookAtInputResult {
|
|
const imageData = args.image_data
|
|
const filePath = args.file_path
|
|
|
|
if (imageData) {
|
|
const mimeType = inferMimeTypeFromBase64(imageData)
|
|
|
|
let finalBase64Data = extractBase64Data(imageData)
|
|
let finalMimeType = mimeType
|
|
let tempFilesToCleanup: string[] = []
|
|
|
|
if (needsConversion(mimeType)) {
|
|
log(`[look_at] Detected unsupported Base64 format: ${mimeType}, converting to JPEG...`)
|
|
try {
|
|
const { base64, tempFiles } = convertBase64ImageToJpeg(finalBase64Data, mimeType)
|
|
finalBase64Data = base64
|
|
finalMimeType = "image/jpeg"
|
|
tempFilesToCleanup = tempFiles
|
|
log("[look_at] Base64 conversion successful")
|
|
} catch (conversionError) {
|
|
log(`[look_at] Base64 conversion failed: ${conversionError}`)
|
|
return {
|
|
ok: false,
|
|
error: `Error: Failed to convert Base64 image format. ${conversionError}`,
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
value: {
|
|
isBase64Input: true,
|
|
sourceDescription: "clipboard/pasted image",
|
|
filePart: {
|
|
type: "file",
|
|
mime: finalMimeType,
|
|
url: `data:${finalMimeType};base64,${finalBase64Data}`,
|
|
filename: `clipboard-image.${finalMimeType.split("/")[1] || "png"}`,
|
|
},
|
|
cleanup() {
|
|
for (const temporaryFile of tempFilesToCleanup) {
|
|
cleanupConvertedImage(temporaryFile)
|
|
}
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
if (filePath) {
|
|
let mimeType = inferMimeTypeFromFilePath(filePath)
|
|
let actualFilePath = filePath
|
|
let tempConversionPath: string | null = null
|
|
|
|
if (needsConversion(mimeType)) {
|
|
log(`[look_at] Detected unsupported format: ${mimeType}, converting to JPEG...`)
|
|
try {
|
|
const convertedFilePath = convertImageToJpeg(filePath, mimeType)
|
|
tempConversionPath = convertedFilePath
|
|
actualFilePath = convertedFilePath
|
|
mimeType = "image/jpeg"
|
|
log(`[look_at] Conversion successful: ${convertedFilePath}`)
|
|
} catch (conversionError) {
|
|
const failedConversionPath = getTemporaryConversionPath(conversionError)
|
|
if (failedConversionPath) {
|
|
tempConversionPath = failedConversionPath
|
|
}
|
|
log(`[look_at] Conversion failed: ${conversionError}`)
|
|
return {
|
|
ok: false,
|
|
error: `Error: Failed to convert image format. ${conversionError}`,
|
|
}
|
|
}
|
|
}
|
|
|
|
return {
|
|
ok: true,
|
|
value: {
|
|
isBase64Input: false,
|
|
sourceDescription: filePath,
|
|
filePart: {
|
|
type: "file",
|
|
mime: mimeType,
|
|
url: pathToFileURL(actualFilePath).href,
|
|
filename: basename(actualFilePath),
|
|
},
|
|
cleanup() {
|
|
if (tempConversionPath) {
|
|
cleanupConvertedImage(tempConversionPath)
|
|
}
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
return {
|
|
ok: false,
|
|
error: "Error: Must provide either 'file_path' or 'image_data'.",
|
|
}
|
|
}
|