Reduce remaining file, LSP, and XAA debug detail

This commit is contained in:
2026-04-04 10:31:29 +08:00
parent 010ded8476
commit 4d506aabf7
6 changed files with 211 additions and 90 deletions

View File

@@ -57,6 +57,47 @@ function debug(msg: string): void {
logForDebugging(`[brief:upload] ${msg}`)
}
function summarizeUploadError(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
}
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)
}
function summarizeUploadResponse(data: unknown): string {
if (data === undefined) return 'undefined'
if (data === null) return 'null'
if (Array.isArray(data)) return `array(${data.length})`
if (typeof data === 'object') {
return jsonStringify({
responseType: 'object',
keys: Object.keys(data as Record<string, unknown>)
.sort()
.slice(0, 10),
})
}
return typeof data
}
/**
* Base URL for uploads. Must match the host the token is valid for.
*
@@ -100,7 +141,9 @@ export async function uploadBriefAttachment(
if (!ctx.replBridgeEnabled) return undefined
if (size > MAX_UPLOAD_BYTES) {
debug(`skip ${fullPath}: ${size} bytes exceeds ${MAX_UPLOAD_BYTES} limit`)
debug(
`skip attachment upload: ${size} bytes exceeds ${MAX_UPLOAD_BYTES} limit`,
)
return undefined
}
@@ -114,7 +157,7 @@ export async function uploadBriefAttachment(
try {
content = await readFile(fullPath)
} catch (e) {
debug(`read failed for ${fullPath}: ${e}`)
debug(`read failed before upload: ${summarizeUploadError(e)}`)
return undefined
}
@@ -150,23 +193,23 @@ export async function uploadBriefAttachment(
if (response.status !== 201) {
debug(
`upload failed for ${fullPath}: status=${response.status} body=${jsonStringify(response.data).slice(0, 200)}`,
`upload failed: status=${response.status} response=${summarizeUploadResponse(
response.data,
)}`,
)
return undefined
}
const parsed = uploadResponseSchema().safeParse(response.data)
if (!parsed.success) {
debug(
`unexpected response shape for ${fullPath}: ${parsed.error.message}`,
)
debug('unexpected upload response shape')
return undefined
}
debug(`uploaded ${fullPath}${parsed.data.file_uuid} (${size} bytes)`)
debug(`uploaded attachment (${size} bytes)`)
return parsed.data.file_uuid
} catch (e) {
debug(`upload threw for ${fullPath}: ${e}`)
debug(`upload threw: ${summarizeUploadError(e)}`)
return undefined
}
}

View File

@@ -15,7 +15,6 @@ import type {
ScopedMcpServerConfig,
} from '../../services/mcp/types.js'
import type { Tool } from '../../Tool.js'
import { errorMessage } from '../../utils/errors.js'
import { lazySchema } from '../../utils/lazySchema.js'
import { logMCPDebug, logMCPError } from '../../utils/log.js'
import type { PermissionDecision } from '../../utils/permissions/PermissionResult.js'
@@ -29,9 +28,11 @@ export type McpAuthOutput = {
authUrl?: string
}
function getConfigUrl(config: ScopedMcpServerConfig): string | undefined {
if ('url' in config) return config.url
return undefined
function summarizeMcpAuthToolError(error: unknown): string {
if (error instanceof Error) {
return `${error.name} (hasMessage=${error.message.length > 0})`
}
return `non-Error (${typeof error})`
}
/**
@@ -50,12 +51,10 @@ export function createMcpAuthTool(
serverName: string,
config: ScopedMcpServerConfig,
): Tool<InputSchema, McpAuthOutput> {
const url = getConfigUrl(config)
const transport = config.type ?? 'stdio'
const location = url ? `${transport} at ${url}` : transport
const description =
`The \`${serverName}\` MCP server (${location}) is installed but requires authentication. ` +
`The \`${serverName}\` MCP server (${transport}) is installed but requires authentication. ` +
`Call this tool to start the OAuth flow — you'll receive an authorization URL to share with the user. ` +
`Once the user completes authorization in their browser, the server's real tools will become available automatically.`
@@ -167,7 +166,9 @@ export function createMcpAuthTool(
.catch(err => {
logMCPError(
serverName,
`OAuth flow failed after tool-triggered start: ${errorMessage(err)}`,
`OAuth flow failed after tool-triggered start: ${summarizeMcpAuthToolError(
err,
)}`,
)
})
@@ -199,7 +200,7 @@ export function createMcpAuthTool(
return {
data: {
status: 'error' as const,
message: `Failed to start OAuth flow for ${serverName}: ${errorMessage(err)}. Ask the user to run /mcp and authenticate manually.`,
message: `Failed to start OAuth flow for ${serverName}. Ask the user to run /mcp and authenticate manually.`,
},
}
}