feat: 大规模清理 claude 的类型问题及依赖

This commit is contained in:
claude-code-best
2026-03-31 22:21:35 +08:00
parent 2c759fe6fa
commit 4c0a655a1c
38 changed files with 1154 additions and 718 deletions

View File

@@ -45,6 +45,7 @@ import {
import type {
AssistantMessage,
Message,
MessageContent,
StreamEvent,
SystemAPIErrorMessage,
UserMessage,
@@ -452,7 +453,7 @@ function configureEffortParams(
betas.push(EFFORT_BETA_HEADER)
} else if (typeof effortValue === 'string') {
// Send string effort level as is
outputConfig.effort = effortValue
outputConfig.effort = effortValue as "high" | "medium" | "low" | "max"
betas.push(EFFORT_BETA_HEADER)
} else if (process.env.USER_TYPE === 'ant') {
// Numeric effort override - ant-only (uses anthropic_internal)
@@ -735,7 +736,7 @@ export async function queryModelWithoutStreaming({
)
})) {
if (message.type === 'assistant') {
assistantMessage = message
assistantMessage = message as AssistantMessage
}
}
if (!assistantMessage) {
@@ -931,7 +932,7 @@ function getPreviousRequestIdFromMessages(
for (let i = messages.length - 1; i >= 0; i--) {
const msg = messages[i]!
if (msg.type === 'assistant' && msg.requestId) {
return msg.requestId
return msg.requestId as string
}
}
return undefined
@@ -964,7 +965,7 @@ export function stripExcessMediaItems(
if (isMedia(block)) toRemove++
if (isToolResult(block) && Array.isArray(block.content)) {
for (const nested of block.content) {
if (isMedia(nested)) toRemove++
if (isMedia(nested as BetaContentBlockParam)) toRemove++
}
}
}
@@ -987,7 +988,7 @@ export function stripExcessMediaItems(
)
return block
const filtered = block.content.filter(n => {
if (toRemove > 0 && isMedia(n)) {
if (toRemove > 0 && isMedia(n as BetaContentBlockParam)) {
toRemove--
return false
}
@@ -2196,7 +2197,7 @@ async function* queryModel(
[contentBlock] as BetaContentBlock[],
tools,
options.agentId,
),
) as MessageContent,
},
requestId: streamRequestId ?? undefined,
type: 'assistant',
@@ -2248,10 +2249,10 @@ async function* queryModel(
}
// Update cost
const costUSDForPart = calculateUSDCost(resolvedModel, usage)
const costUSDForPart = calculateUSDCost(resolvedModel, usage as unknown as BetaUsage)
costUSD += addToTotalSessionCost(
costUSDForPart,
usage,
usage as unknown as BetaUsage,
options.model,
)
@@ -2575,7 +2576,7 @@ async function* queryModel(
result.content,
tools,
options.agentId,
),
) as MessageContent,
},
requestId: streamRequestId ?? undefined,
type: 'assistant',
@@ -2672,7 +2673,7 @@ async function* queryModel(
result.content,
tools,
options.agentId,
),
) as MessageContent,
},
requestId: streamRequestId ?? undefined,
type: 'assistant',
@@ -2818,13 +2819,13 @@ async function* queryModel(
// message_delta handler before any yield. Fallback pushes to newMessages
// then yields, so tracking must be here to survive .return() at the yield.
if (fallbackMessage) {
const fallbackUsage = fallbackMessage.message.usage
const fallbackUsage = fallbackMessage.message.usage as BetaMessageDeltaUsage
usage = updateUsage(EMPTY_USAGE, fallbackUsage)
stopReason = fallbackMessage.message.stop_reason
const fallbackCost = calculateUSDCost(resolvedModel, fallbackUsage)
stopReason = fallbackMessage.message.stop_reason as BetaStopReason
const fallbackCost = calculateUSDCost(resolvedModel, fallbackUsage as unknown as BetaUsage)
costUSD += addToTotalSessionCost(
fallbackCost,
fallbackUsage,
fallbackUsage as unknown as BetaUsage,
options.model,
)
}
@@ -2857,7 +2858,7 @@ async function* queryModel(
void options.getToolPermissionContext().then(permissionContext => {
logAPISuccessAndDuration({
model:
newMessages[0]?.message.model ?? partialMessage?.model ?? options.model,
(newMessages[0]?.message.model as string | undefined) ?? partialMessage?.model ?? options.model,
preNormalizedModel: options.model,
usage,
start,

View File

@@ -656,20 +656,22 @@ export function logAPISuccessAndDuration({
let connectorCount = 0
for (const msg of newMessages) {
for (const block of msg.message.content) {
const contentArr = Array.isArray(msg.message.content) ? msg.message.content : []
for (const block of contentArr) {
if (typeof block === 'string') continue
if (block.type === 'text') {
textLen += block.text.length
textLen += (block as { type: 'text'; text: string }).text.length
} else if (feature('CONNECTOR_TEXT') && isConnectorTextBlock(block)) {
connectorCount++
} else if (block.type === 'thinking') {
thinkingLen += block.thinking.length
thinkingLen += (block as { type: 'thinking'; thinking: string }).thinking.length
} else if (
block.type === 'tool_use' ||
block.type === 'server_tool_use' ||
block.type === 'mcp_tool_use'
(block.type as string) === 'mcp_tool_use'
) {
const inputLen = jsonStringify(block.input).length
const sanitizedName = sanitizeToolNameForAnalytics(block.name)
const inputLen = jsonStringify((block as { input: unknown }).input).length
const sanitizedName = sanitizeToolNameForAnalytics((block as { name: string }).name)
toolLengths[sanitizedName] =
(toolLengths[sanitizedName] ?? 0) + inputLen
hasToolUse = true
@@ -692,7 +694,7 @@ export function logAPISuccessAndDuration({
preNormalizedModel,
messageCount,
messageTokens,
usage,
usage: usage as unknown as Usage,
durationMs,
durationMsIncludingRetries,
attempt,
@@ -735,29 +737,35 @@ export function logAPISuccessAndDuration({
// Model output - visible to all users
modelOutput =
newMessages
.flatMap(m =>
m.message.content
.filter(c => c.type === 'text')
.map(c => (c as { type: 'text'; text: string }).text),
)
.flatMap(m => {
const content = m.message.content
if (!Array.isArray(content)) return []
return content
.filter(c => typeof c !== 'string' && c.type === 'text')
.map(c => (c as { type: 'text'; text: string }).text)
})
.join('\n') || undefined
// Thinking output - Ant-only (build-time gated)
if (process.env.USER_TYPE === 'ant') {
thinkingOutput =
newMessages
.flatMap(m =>
m.message.content
.filter(c => c.type === 'thinking')
.map(c => (c as { type: 'thinking'; thinking: string }).thinking),
)
.flatMap(m => {
const content = m.message.content
if (!Array.isArray(content)) return []
return content
.filter(c => typeof c !== 'string' && c.type === 'thinking')
.map(c => (c as { type: 'thinking'; thinking: string }).thinking)
})
.join('\n') || undefined
}
// Check if any tool_use blocks were in the output
hasToolCall = newMessages.some(m =>
m.message.content.some(c => c.type === 'tool_use'),
)
hasToolCall = newMessages.some(m => {
const content = m.message.content
if (!Array.isArray(content)) return false
return content.some(c => typeof c !== 'string' && c.type === 'tool_use')
})
}
// Pass the span to correctly match responses to requests when beta tracing is enabled

View File

@@ -27,6 +27,8 @@ import type {
HookResultMessage,
Message,
PartialCompactDirection,
StreamEvent,
SystemAPIErrorMessage,
SystemCompactBoundaryMessage,
SystemMessage,
UserMessage,
@@ -263,7 +265,7 @@ export function truncateHeadForPTLRetry(
let acc = 0
dropCount = 0
for (const g of groups) {
acc += roughTokenCountEstimationForMessages(g)
acc += roughTokenCountEstimationForMessages(g as Parameters<typeof roughTokenCountEstimationForMessages>[0])
dropCount++
if (acc >= tokenGap) break
}
@@ -639,7 +641,7 @@ export async function compactConversation(
...summaryMessages,
...postCompactFileAttachments,
...hookMessages,
])
] as Parameters<typeof roughTokenCountEstimationForMessages>[0])
// Extract compaction API usage metrics
const compactionUsage = getTokenUsage(summaryResponse)
@@ -1328,29 +1330,30 @@ async function streamCompactSummary({
let next = await streamIter.next()
while (!next.done) {
const event = next.value
const event = next.value as StreamEvent | AssistantMessage | SystemAPIErrorMessage
const streamEvent = event as { type: string; event: { type: string; content_block: { type: string }; delta: { type: string; text: string } } }
if (
!hasStartedStreaming &&
event.type === 'stream_event' &&
event.event.type === 'content_block_start' &&
event.event.content_block.type === 'text'
streamEvent.type === 'stream_event' &&
streamEvent.event.type === 'content_block_start' &&
streamEvent.event.content_block.type === 'text'
) {
hasStartedStreaming = true
context.setStreamMode?.('responding')
}
if (
event.type === 'stream_event' &&
event.event.type === 'content_block_delta' &&
event.event.delta.type === 'text_delta'
streamEvent.type === 'stream_event' &&
streamEvent.event.type === 'content_block_delta' &&
streamEvent.event.delta.type === 'text_delta'
) {
const charactersStreamed = event.event.delta.text.length
const charactersStreamed = streamEvent.event.delta.text.length
context.setResponseLength?.(length => length + charactersStreamed)
}
if (event.type === 'assistant') {
response = event
response = event as AssistantMessage
}
next = await streamIter.next()