fix: remove final planned as-any casts

This commit is contained in:
James Feng 2026-06-07 15:48:33 +08:00
parent ac807aeb08
commit abde5e813a
4 changed files with 85 additions and 25 deletions

View File

@ -909,12 +909,12 @@ async function callInner(
resolvedFilePath,
parsedRange ?? undefined,
)
if (!extractResult.success) {
throw new Error((extractResult as any).error.message)
if (extractResult.success === false) {
throw new Error(extractResult.error.message)
}
logEvent('tengu_pdf_page_extraction', {
success: true,
pageCount: (extractResult as any).data.file.count,
pageCount: extractResult.data.file.count,
fileSize: extractResult.data.file.originalSize,
hasPageRange: true,
})
@ -981,7 +981,9 @@ async function callInner(
} else {
logEvent('tengu_pdf_page_extraction', {
success: false,
available: (extractResult as any).error.reason !== 'unavailable',
available:
extractResult.success === false &&
extractResult.error.reason !== 'unavailable',
fileSize: stats.size,
})
}
@ -996,8 +998,8 @@ async function callInner(
}
const readResult = await readPDF(resolvedFilePath)
if (!readResult.success) {
throw new Error((readResult as any).error.message)
if (readResult.success === false) {
throw new Error(readResult.error.message)
}
const pdfData = readResult.data
logFileOperation({
@ -1167,14 +1169,27 @@ export async function readImageWithTokenBudget(
// Fallback: heavily compressed version from the SAME buffer
try {
const sharpModule = await import('sharp')
type SharpFactory = (
input: Buffer,
) => {
resize(
width: number,
height: number,
options: {
fit: 'inside'
withoutEnlargement: boolean
},
): {
jpeg(options: { quality: number }): {
toBuffer(): Promise<Buffer>
}
}
}
const sharp =
(
sharpModule as unknown as {
default?: typeof sharpModule
} & typeof sharpModule
).default || sharpModule
((sharpModule as unknown as { default?: unknown }).default ??
sharpModule) as SharpFactory
const fallbackBuffer = await (sharp as any)(imageBuffer)
const fallbackBuffer = await sharp(imageBuffer)
.resize(400, 400, {
fit: 'inside',
withoutEnlargement: true,

View File

@ -1,4 +1,8 @@
import { type Options as ExecaOptions, execaSync } from 'execa'
import {
type Options as ExecaOptions,
type ExecaSyncMethod,
execaSync,
} from 'execa'
import { getCwd } from '../utils/cwd.js'
import { slowLogging } from './slowOperations.js'
@ -12,6 +16,11 @@ type ExecSyncOptions = {
stdio?: ExecaOptions['stdio']
}
type ShellCommandExecaSync = (
command: string,
options: ExecaOptions,
) => ReturnType<ExecaSyncMethod>
/**
* @deprecated Use `execa` directly with `{ shell: true, reject: false }` for non-blocking execution.
* Sync exec calls block the event loop and cause performance issues.
@ -72,7 +81,8 @@ export function execSyncWithDefaults_DEPRECATED(
// DEPRECATED: caller is responsible for sanitizing shell metacharacters
// in the command argument. This function uses shell: true which can lead
// to command injection if command contains untrusted input.
const result = (execaSync as any)(command, {
const runShellCommand = execaSync as unknown as ShellCommandExecaSync
const result = runShellCommand(command, {
env: process.env,
maxBuffer: 1_000_000,
timeout: finalTimeout,
@ -85,7 +95,15 @@ export function execSyncWithDefaults_DEPRECATED(
if (!result.stdout) {
return null
}
return result.stdout.trim() || null
const stdout =
typeof result.stdout === 'string'
? result.stdout
: result.stdout instanceof Uint8Array
? new TextDecoder().decode(result.stdout)
: Array.isArray(result.stdout)
? result.stdout.join('')
: String(result.stdout)
return stdout.trim() || null
} catch {
return null
}

View File

@ -1,5 +1,6 @@
import type Anthropic from '@anthropic-ai/sdk'
import type { BetaToolUnion } from '@anthropic-ai/sdk/resources/beta/messages.js'
import type { ChatCompletionCreateParamsNonStreaming } from 'openai/resources/chat/completions'
import {
getLastApiCompletionTimestamp,
getSessionId,
@ -210,7 +211,7 @@ async function sideQueryViaOpenAICompatible(
const start = Date.now()
const requestParams: Record<string, unknown> = {
const requestParams: ChatCompletionCreateParamsNonStreaming = {
model: openaiModel,
messages: openaiMessages,
max_tokens,
@ -218,10 +219,13 @@ async function sideQueryViaOpenAICompatible(
if (temperature !== undefined) requestParams.temperature = temperature
if (openaiTools && openaiTools.length > 0) {
requestParams.tools = openaiTools
if (openaiToolChoice) requestParams.tool_choice = openaiToolChoice
if (openaiToolChoice) {
requestParams.tool_choice =
openaiToolChoice as ChatCompletionCreateParamsNonStreaming['tool_choice']
}
}
const response = await client.chat.completions.create(requestParams as any, {
const response = await client.chat.completions.create(requestParams, {
signal,
})

View File

@ -5,6 +5,7 @@
// teleportToRemote's CreateSession events array.
import type {
ContentBlock,
ToolResultBlockParam,
ToolUseBlock,
} from '@anthropic-ai/sdk/resources'
@ -23,6 +24,27 @@ const POLL_INTERVAL_MS = 3000
// at any nonzero 5xx rate one blip would kill the run.
const MAX_CONSECUTIVE_FAILURES = 5
function getSDKMessageContent(message: SDKMessage): unknown {
const sdkMessage = message.message
if (typeof sdkMessage !== 'object' || sdkMessage === null) return undefined
return (sdkMessage as { content?: unknown }).content
}
function isToolUseBlock(block: ContentBlock): block is ToolUseBlock {
return block.type === 'tool_use'
}
function isToolResultBlock(block: unknown): block is ToolResultBlockParam {
return (
typeof block === 'object' &&
block !== null &&
'type' in block &&
block.type === 'tool_result' &&
'tool_use_id' in block &&
typeof block.tool_use_id === 'string'
)
}
export type PollFailReason =
| 'terminated'
| 'timeout_pending'
@ -101,18 +123,19 @@ export class ExitPlanModeScanner {
ingest(newEvents: SDKMessage[]): ScanResult {
for (const m of newEvents) {
if (m.type === 'assistant') {
for (const block of (m as any).message.content) {
if (block.type !== 'tool_use') continue
const tu = block as ToolUseBlock
if (tu.name === EXIT_PLAN_MODE_V2_TOOL_NAME) {
this.exitPlanCalls.push(tu.id)
const content = getSDKMessageContent(m)
if (!Array.isArray(content)) continue
for (const block of content as ContentBlock[]) {
if (!isToolUseBlock(block)) continue
if (block.name === EXIT_PLAN_MODE_V2_TOOL_NAME) {
this.exitPlanCalls.push(block.id)
}
}
} else if (m.type === 'user') {
const content = (m as any).message.content
const content = getSDKMessageContent(m)
if (!Array.isArray(content)) continue
for (const block of content) {
if (block.type === 'tool_result') {
if (isToolResultBlock(block)) {
this.results.set(block.tool_use_id, block)
}
}