Reduce remaining file, LSP, and XAA debug detail
This commit is contained in:
@@ -14,9 +14,10 @@ import * as path from 'path'
|
||||
import { count } from '../../utils/array.js'
|
||||
import { getCwd } from '../../utils/cwd.js'
|
||||
import { logForDebugging } from '../../utils/debug.js'
|
||||
import { errorMessage } from '../../utils/errors.js'
|
||||
import { errorMessage, getErrnoCode } from '../../utils/errors.js'
|
||||
import { logError } from '../../utils/log.js'
|
||||
import { sleep } from '../../utils/sleep.js'
|
||||
import { jsonStringify } from '../../utils/slowOperations.js'
|
||||
import {
|
||||
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
||||
logEvent,
|
||||
@@ -45,6 +46,37 @@ function logDebug(message: string): void {
|
||||
logForDebugging(`[files-api] ${message}`)
|
||||
}
|
||||
|
||||
function summarizeFilesApiError(error: unknown): string {
|
||||
const summary: Record<string, boolean | number | string> = {}
|
||||
|
||||
if (error instanceof Error) {
|
||||
summary.errorType = error.constructor.name
|
||||
summary.errorName = error.name
|
||||
summary.hasMessage = error.message.length > 0
|
||||
} else {
|
||||
summary.errorType = typeof error
|
||||
summary.hasValue = error !== undefined && error !== null
|
||||
}
|
||||
|
||||
const errno = getErrnoCode(error)
|
||||
if (errno) {
|
||||
summary.errno = errno
|
||||
}
|
||||
|
||||
if (axios.isAxiosError(error)) {
|
||||
summary.errorType = 'AxiosError'
|
||||
if (error.code) {
|
||||
summary.axiosCode = error.code
|
||||
}
|
||||
if (typeof error.response?.status === 'number') {
|
||||
summary.httpStatus = error.response.status
|
||||
}
|
||||
summary.hasResponseData = error.response?.data !== undefined
|
||||
}
|
||||
|
||||
return jsonStringify(summary)
|
||||
}
|
||||
|
||||
/**
|
||||
* File specification parsed from CLI args
|
||||
* Format: --file=<file_id>:<relative_path>
|
||||
@@ -108,9 +140,7 @@ async function retryWithBackoff<T>(
|
||||
}
|
||||
|
||||
lastError = result.error || `${operation} failed`
|
||||
logDebug(
|
||||
`${operation} attempt ${attempt}/${MAX_RETRIES} failed: ${lastError}`,
|
||||
)
|
||||
logDebug(`${operation} attempt ${attempt}/${MAX_RETRIES} failed`)
|
||||
|
||||
if (attempt < MAX_RETRIES) {
|
||||
const delayMs = BASE_DELAY_MS * Math.pow(2, attempt - 1)
|
||||
@@ -142,7 +172,7 @@ export async function downloadFile(
|
||||
'anthropic-beta': FILES_API_BETA_HEADER,
|
||||
}
|
||||
|
||||
logDebug(`Downloading file ${fileId} from ${url}`)
|
||||
logDebug(`Downloading file ${fileId} from configured Files API endpoint`)
|
||||
|
||||
return retryWithBackoff(`Download file ${fileId}`, async () => {
|
||||
try {
|
||||
@@ -191,9 +221,7 @@ export function buildDownloadPath(
|
||||
): string | null {
|
||||
const normalized = path.normalize(relativePath)
|
||||
if (normalized.startsWith('..')) {
|
||||
logDebugError(
|
||||
`Invalid file path: ${relativePath}. Path must not traverse above workspace`,
|
||||
)
|
||||
logDebugError('Invalid file path rejected: path traversal is not allowed')
|
||||
return null
|
||||
}
|
||||
|
||||
@@ -243,7 +271,7 @@ export async function downloadAndSaveFile(
|
||||
// Write the file
|
||||
await fs.writeFile(fullPath, content)
|
||||
|
||||
logDebug(`Saved file ${fileId} to ${fullPath} (${content.length} bytes)`)
|
||||
logDebug(`Saved file ${fileId} (${content.length} bytes)`)
|
||||
|
||||
return {
|
||||
fileId,
|
||||
@@ -252,10 +280,16 @@ export async function downloadAndSaveFile(
|
||||
bytesWritten: content.length,
|
||||
}
|
||||
} catch (error) {
|
||||
logDebugError(`Failed to download file ${fileId}: ${errorMessage(error)}`)
|
||||
if (error instanceof Error) {
|
||||
logError(error)
|
||||
}
|
||||
logDebugError(
|
||||
`Failed to download file ${fileId}: ${summarizeFilesApiError(error)}`,
|
||||
)
|
||||
logError(
|
||||
new Error(
|
||||
`Files API download failed for ${fileId}: ${summarizeFilesApiError(
|
||||
error,
|
||||
)}`,
|
||||
),
|
||||
)
|
||||
|
||||
return {
|
||||
fileId,
|
||||
@@ -390,7 +424,7 @@ export async function uploadFile(
|
||||
'anthropic-beta': FILES_API_BETA_HEADER,
|
||||
}
|
||||
|
||||
logDebug(`Uploading file ${filePath} as ${relativePath}`)
|
||||
logDebug('Uploading file to configured Files API endpoint')
|
||||
|
||||
// Read file content first (outside retry loop since it's not a network operation)
|
||||
let content: Buffer
|
||||
@@ -455,7 +489,7 @@ export async function uploadFile(
|
||||
const body = Buffer.concat(bodyParts)
|
||||
|
||||
try {
|
||||
return await retryWithBackoff(`Upload file ${relativePath}`, async () => {
|
||||
return await retryWithBackoff('Upload session file', async () => {
|
||||
try {
|
||||
const response = await axios.post(url, body, {
|
||||
headers: {
|
||||
@@ -476,7 +510,7 @@ export async function uploadFile(
|
||||
error: 'Upload succeeded but no file ID returned',
|
||||
}
|
||||
}
|
||||
logDebug(`Uploaded file ${filePath} -> ${fileId} (${fileSize} bytes)`)
|
||||
logDebug(`Uploaded file (${fileSize} bytes)`)
|
||||
return {
|
||||
done: true,
|
||||
value: {
|
||||
@@ -735,9 +769,7 @@ export function parseFileSpecs(fileSpecs: string[]): File[] {
|
||||
const relativePath = spec.substring(colonIndex + 1)
|
||||
|
||||
if (!fileId || !relativePath) {
|
||||
logDebugError(
|
||||
`Invalid file spec: ${spec}. Both file_id and path are required`,
|
||||
)
|
||||
logDebugError('Invalid file spec: missing file_id or relative path')
|
||||
continue
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user