mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-17 22:05:50 +00:00
feat: 完成第二版类型清理
This commit is contained in:
@@ -288,8 +288,8 @@ async function countSystemTokens(
|
||||
)
|
||||
.map(content => ({ name: extractSectionName(content), content })),
|
||||
...Object.entries(systemContext)
|
||||
.filter(([, content]) => content.length > 0)
|
||||
.map(([name, content]) => ({ name, content })),
|
||||
.filter(([, content]) => (content as string).length > 0)
|
||||
.map(([name, content]) => ({ name, content: content as string })),
|
||||
]
|
||||
|
||||
if (namedEntries.length < 1) {
|
||||
@@ -445,9 +445,10 @@ async function countBuiltInToolTokens(
|
||||
if (messages) {
|
||||
const deferredToolNameSet = new Set(deferredBuiltinTools.map(t => t.name))
|
||||
for (const msg of messages) {
|
||||
if (msg.type === 'assistant') {
|
||||
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
|
||||
for (const block of msg.message.content) {
|
||||
if (
|
||||
typeof block !== 'string' &&
|
||||
'type' in block &&
|
||||
block.type === 'tool_use' &&
|
||||
'name' in block &&
|
||||
@@ -682,9 +683,10 @@ export async function countMcpToolTokens(
|
||||
if (isDeferred && messages) {
|
||||
const mcpToolNameSet = new Set(mcpTools.map(t => t.name))
|
||||
for (const msg of messages) {
|
||||
if (msg.type === 'assistant') {
|
||||
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
|
||||
for (const block of msg.message.content) {
|
||||
if (
|
||||
typeof block !== 'string' &&
|
||||
'type' in block &&
|
||||
block.type === 'tool_use' &&
|
||||
'name' in block &&
|
||||
@@ -784,11 +786,12 @@ function processAssistantMessage(
|
||||
breakdown: MessageBreakdown,
|
||||
): void {
|
||||
// Process each content block individually
|
||||
for (const block of msg.message.content) {
|
||||
const contentBlocks = Array.isArray(msg.message.content) ? msg.message.content : []
|
||||
for (const block of contentBlocks) {
|
||||
const blockStr = jsonStringify(block)
|
||||
const blockTokens = roughTokenCountEstimation(blockStr)
|
||||
|
||||
if ('type' in block && block.type === 'tool_use') {
|
||||
if (typeof block !== 'string' && 'type' in block && block.type === 'tool_use') {
|
||||
breakdown.toolCallTokens += blockTokens
|
||||
const toolName = ('name' in block ? block.name : undefined) || 'unknown'
|
||||
breakdown.toolCallsByType.set(
|
||||
@@ -871,12 +874,12 @@ async function approximateMessageTokens(
|
||||
// Build a map of tool_use_id to tool_name for easier lookup
|
||||
const toolUseIdToName = new Map<string, string>()
|
||||
for (const msg of microcompactResult.messages) {
|
||||
if (msg.type === 'assistant') {
|
||||
if (msg.type === 'assistant' && Array.isArray(msg.message.content)) {
|
||||
for (const block of msg.message.content) {
|
||||
if ('type' in block && block.type === 'tool_use') {
|
||||
const toolUseId = 'id' in block ? block.id : undefined
|
||||
if (typeof block !== 'string' && 'type' in block && block.type === 'tool_use') {
|
||||
const toolUseId = 'id' in block ? (block.id as string) : undefined
|
||||
const toolName =
|
||||
('name' in block ? block.name : undefined) || 'unknown'
|
||||
(('name' in block ? block.name : undefined) as string | undefined) || 'unknown'
|
||||
if (toolUseId) {
|
||||
toolUseIdToName.set(toolUseId, toolName)
|
||||
}
|
||||
@@ -888,11 +891,11 @@ async function approximateMessageTokens(
|
||||
// Process each message for detailed breakdown
|
||||
for (const msg of microcompactResult.messages) {
|
||||
if (msg.type === 'assistant') {
|
||||
processAssistantMessage(msg, breakdown)
|
||||
processAssistantMessage(msg as AssistantMessage, breakdown)
|
||||
} else if (msg.type === 'user') {
|
||||
processUserMessage(msg, breakdown, toolUseIdToName)
|
||||
processUserMessage(msg as UserMessage, breakdown, toolUseIdToName)
|
||||
} else if (msg.type === 'attachment') {
|
||||
processAttachment(msg, breakdown)
|
||||
processAttachment(msg as AttachmentMessage, breakdown)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,12 +905,12 @@ async function approximateMessageTokens(
|
||||
if (_.type === 'assistant') {
|
||||
return {
|
||||
// Important: strip out fields like id, etc. -- the counting API errors if they're present
|
||||
role: 'assistant',
|
||||
role: 'assistant' as const,
|
||||
content: _.message.content,
|
||||
}
|
||||
}
|
||||
return _.message
|
||||
}),
|
||||
}) as Anthropic.Beta.Messages.BetaMessageParam[],
|
||||
[],
|
||||
)
|
||||
|
||||
|
||||
@@ -995,11 +995,11 @@ export async function getAttachments(
|
||||
|
||||
clearTimeout(timeoutId)
|
||||
// Defensive: a getter leaking [undefined] crashes .map(a => a.type) below.
|
||||
return [
|
||||
return ([
|
||||
...userAttachmentResults.flat(),
|
||||
...threadAttachmentResults.flat(),
|
||||
...mainThreadAttachmentResults.flat(),
|
||||
].filter(a => a !== undefined && a !== null)
|
||||
] as Attachment[]).filter(a => a !== undefined && a !== null)
|
||||
}
|
||||
|
||||
async function maybe<A>(label: string, f: () => Promise<A[]>): Promise<A[]> {
|
||||
@@ -1095,7 +1095,7 @@ export function getAgentPendingMessageAttachments(
|
||||
return drained.map(msg => ({
|
||||
type: 'queued_command' as const,
|
||||
prompt: msg,
|
||||
origin: { kind: 'coordinator' as const },
|
||||
origin: { kind: 'coordinator' as const } as unknown as MessageOrigin,
|
||||
isMeta: true,
|
||||
}))
|
||||
}
|
||||
@@ -1525,8 +1525,8 @@ export function getAgentListingDeltaAttachment(
|
||||
for (const msg of messages ?? []) {
|
||||
if (msg.type !== 'attachment') continue
|
||||
if (msg.attachment.type !== 'agent_listing_delta') continue
|
||||
for (const t of msg.attachment.addedTypes) announced.add(t)
|
||||
for (const t of msg.attachment.removedTypes) announced.delete(t)
|
||||
for (const t of msg.attachment.addedTypes as string[]) announced.add(t)
|
||||
for (const t of msg.attachment.removedTypes as string[]) announced.delete(t)
|
||||
}
|
||||
|
||||
const currentTypes = new Set(filtered.map(a => a.agentType))
|
||||
@@ -2256,7 +2256,7 @@ export function collectSurfacedMemories(messages: ReadonlyArray<Message>): {
|
||||
let totalBytes = 0
|
||||
for (const m of messages) {
|
||||
if (m.type === 'attachment' && m.attachment.type === 'relevant_memories') {
|
||||
for (const mem of m.attachment.memories) {
|
||||
for (const mem of m.attachment.memories as { path: string; content: string; mtimeMs: number }[]) {
|
||||
paths.add(mem.path)
|
||||
totalBytes += mem.content.length
|
||||
}
|
||||
@@ -2776,7 +2776,7 @@ export function extractAtMentionedFiles(content: string): string[] {
|
||||
}
|
||||
|
||||
// Extract regular mentions
|
||||
const regularMatchArray = content.match(regularAtMentionRegex) || []
|
||||
const regularMatchArray: string[] = content.match(regularAtMentionRegex) ?? []
|
||||
regularMatchArray.forEach(match => {
|
||||
const filename = match.slice(match.indexOf('@') + 1)
|
||||
// Don't include if it starts with a quote (already handled as quoted)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -15,16 +15,16 @@ function isCompletedBackgroundBash(
|
||||
msg: RenderableMessage,
|
||||
): msg is NormalizedUserMessage {
|
||||
if (msg.type !== 'user') return false
|
||||
const content = msg.message.content[0]
|
||||
if (content?.type !== 'text') return false
|
||||
if (!content.text.includes(`<${TASK_NOTIFICATION_TAG}`)) return false
|
||||
const content0 = Array.isArray(msg.message.content) ? msg.message.content[0] : undefined
|
||||
if (!content0 || typeof content0 === 'string' || content0?.type !== 'text') return false
|
||||
if (!content0.text.includes(`<${TASK_NOTIFICATION_TAG}`)) return false
|
||||
// Only collapse successful completions — failed/killed stay visible individually.
|
||||
if (extractTag(content.text, STATUS_TAG) !== 'completed') return false
|
||||
if (extractTag(content0.text, STATUS_TAG) !== 'completed') return false
|
||||
// The prefix constant distinguishes bash-kind LocalShellTask completions from
|
||||
// agent/workflow/monitor notifications. Monitor-kind completions have their
|
||||
// own summary wording and deliberately don't collapse here.
|
||||
return (
|
||||
extractTag(content.text, SUMMARY_TAG)?.startsWith(
|
||||
extractTag(content0.text, SUMMARY_TAG)?.startsWith(
|
||||
BACKGROUND_BASH_SUMMARY_PREFIX,
|
||||
) ?? false
|
||||
)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -93,7 +93,7 @@ function migrateLegacyAttachmentTypes(message: Message): Message {
|
||||
type: 'file',
|
||||
displayPath: relative(getCwd(), attachment.filename as string),
|
||||
},
|
||||
} as SerializedMessage // Cast entire message since we know the structure is correct
|
||||
} as unknown as SerializedMessage // Cast entire message since we know the structure is correct
|
||||
}
|
||||
|
||||
if (attachment.type === 'new_directory') {
|
||||
@@ -104,7 +104,7 @@ function migrateLegacyAttachmentTypes(message: Message): Message {
|
||||
type: 'directory',
|
||||
displayPath: relative(getCwd(), attachment.path as string),
|
||||
},
|
||||
} as SerializedMessage // Cast entire message since we know the structure is correct
|
||||
} as unknown as SerializedMessage // Cast entire message since we know the structure is correct
|
||||
}
|
||||
|
||||
// Backfill displayPath for attachments from old sessions
|
||||
@@ -177,7 +177,7 @@ export function deserializeMessagesWithInterruptDetection(
|
||||
if (
|
||||
msg.type === 'user' &&
|
||||
msg.permissionMode !== undefined &&
|
||||
!validModes.has(msg.permissionMode)
|
||||
!validModes.has(msg.permissionMode as string)
|
||||
) {
|
||||
msg.permissionMode = undefined
|
||||
}
|
||||
@@ -320,7 +320,7 @@ function detectTurnInterruption(
|
||||
return { kind: 'interrupted_turn' }
|
||||
}
|
||||
// Plain text user prompt — CC hadn't started responding
|
||||
return { kind: 'interrupted_prompt', message: lastMessage }
|
||||
return { kind: 'interrupted_prompt', message: lastMessage as NormalizedUserMessage }
|
||||
}
|
||||
|
||||
if (lastMessage.type === 'attachment') {
|
||||
@@ -359,12 +359,14 @@ function isTerminalToolResult(
|
||||
for (let i = resultIdx - 1; i >= 0; i--) {
|
||||
const msg = messages[i]!
|
||||
if (msg.type !== 'assistant') continue
|
||||
for (const b of msg.message.content) {
|
||||
if (b.type === 'tool_use' && b.id === toolUseId) {
|
||||
const msgContent = msg.message.content
|
||||
if (!Array.isArray(msgContent)) continue
|
||||
for (const b of msgContent) {
|
||||
if (typeof b !== 'string' && 'type' in b && b.type === 'tool_use' && 'id' in b && b.id === toolUseId) {
|
||||
return (
|
||||
b.name === BRIEF_TOOL_NAME ||
|
||||
b.name === LEGACY_BRIEF_TOOL_NAME ||
|
||||
b.name === SEND_USER_FILE_TOOL_NAME
|
||||
('name' in b ? b.name : undefined) === BRIEF_TOOL_NAME ||
|
||||
('name' in b ? b.name : undefined) === LEGACY_BRIEF_TOOL_NAME ||
|
||||
('name' in b ? b.name : undefined) === SEND_USER_FILE_TOOL_NAME
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -385,7 +387,8 @@ export function restoreSkillStateFromMessages(messages: Message[]): void {
|
||||
continue
|
||||
}
|
||||
if (message.attachment.type === 'invoked_skills') {
|
||||
for (const skill of message.attachment.skills) {
|
||||
const skills = message.attachment.skills as Array<{ name?: string; path?: string; content?: string }>;
|
||||
for (const skill of skills) {
|
||||
if (skill.name && skill.path && skill.content) {
|
||||
// Resume only happens for the main session, so agentId is null
|
||||
addInvokedSkill(skill.name, skill.path, skill.content, null)
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -242,7 +242,7 @@ export function extractResultText(
|
||||
if (!lastAssistantMessage) return defaultText
|
||||
|
||||
const textContent = extractTextContent(
|
||||
lastAssistantMessage.message.content,
|
||||
Array.isArray(lastAssistantMessage.message.content) ? lastAssistantMessage.message.content : [],
|
||||
'\n',
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import type { BetaToolUseBlock } from '@anthropic-ai/sdk/resources/beta/messages/messages.mjs'
|
||||
import type { ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages/messages.mjs'
|
||||
import type { ContentBlockParam, ToolResultBlockParam } from '@anthropic-ai/sdk/resources/messages/messages.mjs'
|
||||
import type { Tools } from '../Tool.js'
|
||||
import type {
|
||||
GroupedToolUseMessage,
|
||||
@@ -34,10 +34,10 @@ function getToolsWithGrouping(tools: Tools): Set<string> {
|
||||
function getToolUseInfo(
|
||||
msg: MessageWithoutProgress,
|
||||
): { messageId: string; toolUseId: string; toolName: string } | null {
|
||||
if (msg.type === 'assistant' && msg.message.content[0]?.type === 'tool_use') {
|
||||
const content = msg.message.content[0]
|
||||
if (msg.type === 'assistant' && msg.message?.content && Array.isArray(msg.message.content) && (msg.message.content[0] as { type?: string })?.type === 'tool_use') {
|
||||
const content = msg.message.content[0] as unknown as { type: 'tool_use'; id: string; name: string; [key: string]: unknown }
|
||||
return {
|
||||
messageId: msg.message.id,
|
||||
messageId: msg.message.id as string,
|
||||
toolUseId: content.id,
|
||||
toolName: content.name,
|
||||
}
|
||||
@@ -59,7 +59,7 @@ export function applyGrouping(
|
||||
// In verbose mode, don't group - each message renders at its original position
|
||||
if (verbose) {
|
||||
return {
|
||||
messages: messages,
|
||||
messages: messages as RenderableMessage[],
|
||||
}
|
||||
}
|
||||
const toolsWithGrouping = getToolsWithGrouping(tools)
|
||||
@@ -104,13 +104,13 @@ export function applyGrouping(
|
||||
const resultsByToolUseId = new Map<string, NormalizedUserMessage>()
|
||||
|
||||
for (const msg of messages) {
|
||||
if (msg.type === 'user') {
|
||||
if (msg.type === 'user' && msg.message?.content && Array.isArray(msg.message.content)) {
|
||||
for (const content of msg.message.content) {
|
||||
if (
|
||||
content.type === 'tool_result' &&
|
||||
groupedToolUseIds.has(content.tool_use_id)
|
||||
(content as { type?: string }).type === 'tool_result' &&
|
||||
groupedToolUseIds.has((content as { tool_use_id: string }).tool_use_id)
|
||||
) {
|
||||
resultsByToolUseId.set(content.tool_use_id, msg)
|
||||
resultsByToolUseId.set((content as { tool_use_id: string }).tool_use_id, msg as NormalizedUserMessage)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -161,8 +161,8 @@ export function applyGrouping(
|
||||
}
|
||||
|
||||
// Skip user messages whose tool_results are all grouped
|
||||
if (msg.type === 'user') {
|
||||
const toolResults = msg.message.content.filter(
|
||||
if (msg.type === 'user' && msg.message?.content && Array.isArray(msg.message.content)) {
|
||||
const toolResults = (msg.message.content as Array<ContentBlockParam>).filter(
|
||||
(c): c is ToolResultBlockParam => c.type === 'tool_result',
|
||||
)
|
||||
if (toolResults.length > 0) {
|
||||
@@ -175,7 +175,7 @@ export function applyGrouping(
|
||||
}
|
||||
}
|
||||
|
||||
result.push(msg)
|
||||
result.push(msg as RenderableMessage)
|
||||
}
|
||||
|
||||
return { messages: result }
|
||||
|
||||
@@ -25,4 +25,3 @@ export function highlightMatch(text: string, query: string): React.ReactNode {
|
||||
if (offset < text.length) parts.push(text.slice(offset));
|
||||
return <>{parts}</>;
|
||||
}
|
||||
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJSZWFjdCIsIlRleHQiLCJoaWdobGlnaHRNYXRjaCIsInRleHQiLCJxdWVyeSIsIlJlYWN0Tm9kZSIsInF1ZXJ5TG93ZXIiLCJ0b0xvd2VyQ2FzZSIsInRleHRMb3dlciIsInBhcnRzIiwib2Zmc2V0IiwiaWR4IiwiaW5kZXhPZiIsInB1c2giLCJzbGljZSIsImxlbmd0aCJdLCJzb3VyY2VzIjpbImhpZ2hsaWdodE1hdGNoLnRzeCJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgKiBhcyBSZWFjdCBmcm9tICdyZWFjdCdcbmltcG9ydCB7IFRleHQgfSBmcm9tICcuLi9pbmsuanMnXG5cbi8qKlxuICogSW52ZXJzZS1oaWdobGlnaHQgZXZlcnkgb2NjdXJyZW5jZSBvZiBgcXVlcnlgIGluIGB0ZXh0YCAoY2FzZS1pbnNlbnNpdGl2ZSkuXG4gKiBVc2VkIGJ5IHNlYXJjaCBkaWFsb2dzIHRvIHNob3cgd2hlcmUgdGhlIHF1ZXJ5IG1hdGNoZWQgaW4gcmVzdWx0IHJvd3NcbiAqIGFuZCBwcmV2aWV3IHBhbmVzLlxuICovXG5leHBvcnQgZnVuY3Rpb24gaGlnaGxpZ2h0TWF0Y2godGV4dDogc3RyaW5nLCBxdWVyeTogc3RyaW5nKTogUmVhY3QuUmVhY3ROb2RlIHtcbiAgaWYgKCFxdWVyeSkgcmV0dXJuIHRleHRcbiAgY29uc3QgcXVlcnlMb3dlciA9IHF1ZXJ5LnRvTG93ZXJDYXNlKClcbiAgY29uc3QgdGV4dExvd2VyID0gdGV4dC50b0xvd2VyQ2FzZSgpXG4gIGNvbnN0IHBhcnRzOiBSZWFjdC5SZWFjdE5vZGVbXSA9IFtdXG4gIGxldCBvZmZzZXQgPSAwXG4gIGxldCBpZHggPSB0ZXh0TG93ZXIuaW5kZXhPZihxdWVyeUxvd2VyLCBvZmZzZXQpXG4gIGlmIChpZHggPT09IC0xKSByZXR1cm4gdGV4dFxuICB3aGlsZSAoaWR4ICE9PSAtMSkge1xuICAgIGlmIChpZHggPiBvZmZzZXQpIHBhcnRzLnB1c2godGV4dC5zbGljZShvZmZzZXQsIGlkeCkpXG4gICAgcGFydHMucHVzaChcbiAgICAgIDxUZXh0IGtleT17aWR4fSBpbnZlcnNlPlxuICAgICAgICB7dGV4dC5zbGljZShpZHgsIGlkeCArIHF1ZXJ5Lmxlbmd0aCl9XG4gICAgICA8L1RleHQ+LFxuICAgIClcbiAgICBvZmZzZXQgPSBpZHggKyBxdWVyeS5sZW5ndGhcbiAgICBpZHggPSB0ZXh0TG93ZXIuaW5kZXhPZihxdWVyeUxvd2VyLCBvZmZzZXQpXG4gIH1cbiAgaWYgKG9mZnNldCA8IHRleHQubGVuZ3RoKSBwYXJ0cy5wdXNoKHRleHQuc2xpY2Uob2Zmc2V0KSlcbiAgcmV0dXJuIDw+e3BhcnRzfTwvPlxufVxuIl0sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUtBLEtBQUssTUFBTSxPQUFPO0FBQzlCLFNBQVNDLElBQUksUUFBUSxXQUFXOztBQUVoQztBQUNBO0FBQ0E7QUFDQTtBQUNBO0FBQ0EsT0FBTyxTQUFTQyxjQUFjQSxDQUFDQyxJQUFJLEVBQUUsTUFBTSxFQUFFQyxLQUFLLEVBQUUsTUFBTSxDQUFDLEVBQUVKLEtBQUssQ0FBQ0ssU0FBUyxDQUFDO0VBQzNFLElBQUksQ0FBQ0QsS0FBSyxFQUFFLE9BQU9ELElBQUk7RUFDdkIsTUFBTUcsVUFBVSxHQUFHRixLQUFLLENBQUNHLFdBQVcsQ0FBQyxDQUFDO0VBQ3RDLE1BQU1DLFNBQVMsR0FBR0wsSUFBSSxDQUFDSSxXQUFXLENBQUMsQ0FBQztFQUNwQyxNQUFNRSxLQUFLLEVBQUVULEtBQUssQ0FBQ0ssU0FBUyxFQUFFLEdBQUcsRUFBRTtFQUNuQyxJQUFJSyxNQUFNLEdBQUcsQ0FBQztFQUNkLElBQUlDLEdBQUcsR0FBR0gsU0FBUyxDQUFDSSxPQUFPLENBQUNOLFVBQVUsRUFBRUksTUFBTSxDQUFDO0VBQy9DLElBQUlDLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRSxPQUFPUixJQUFJO0VBQzNCLE9BQU9RLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRTtJQUNqQixJQUFJQSxHQUFHLEdBQUdELE1BQU0sRUFBRUQsS0FBSyxDQUFDSSxJQUFJLENBQUNWLElBQUksQ0FBQ1csS0FBSyxDQUFDSixNQUFNLEVBQUVDLEdBQUcsQ0FBQyxDQUFDO0lBQ3JERixLQUFLLENBQUNJLElBQUksQ0FDUixDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQ0YsR0FBRyxDQUFDLENBQUMsT0FBTztBQUM3QixRQUFRLENBQUNSLElBQUksQ0FBQ1csS0FBSyxDQUFDSCxHQUFHLEVBQUVBLEdBQUcsR0FBR1AsS0FBSyxDQUFDVyxNQUFNLENBQUM7QUFDNUMsTUFBTSxFQUFFLElBQUksQ0FDUixDQUFDO0lBQ0RMLE1BQU0sR0FBR0MsR0FBRyxHQUFHUCxLQUFLLENBQUNXLE1BQU07SUFDM0JKLEdBQUcsR0FBR0gsU0FBUyxDQUFDSSxPQUFPLENBQUNOLFVBQVUsRUFBRUksTUFBTSxDQUFDO0VBQzdDO0VBQ0EsSUFBSUEsTUFBTSxHQUFHUCxJQUFJLENBQUNZLE1BQU0sRUFBRU4sS0FBSyxDQUFDSSxJQUFJLENBQUNWLElBQUksQ0FBQ1csS0FBSyxDQUFDSixNQUFNLENBQUMsQ0FBQztFQUN4RCxPQUFPLEVBQUUsQ0FBQ0QsS0FBSyxDQUFDLEdBQUc7QUFDckIiLCJpZ25vcmVMaXN0IjpbXX0=
|
||||
@@ -108,7 +108,7 @@ export function createApiQueryHook<TResult>(
|
||||
})
|
||||
|
||||
// Parse response
|
||||
const content = extractTextContent(response.message.content).trim()
|
||||
const content = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim()
|
||||
|
||||
try {
|
||||
const result = config.parseResponse(content, context)
|
||||
|
||||
@@ -102,7 +102,7 @@ Your response must be a JSON object matching one of the following schemas:
|
||||
cleanupSignal()
|
||||
|
||||
// Extract text content from response
|
||||
const content = extractTextContent(response.message.content)
|
||||
const content = extractTextContent(Array.isArray(response.message.content) ? response.message.content : [])
|
||||
|
||||
// Update response length for spinner display
|
||||
toolUseContext.setResponseLength(length => length + content.length)
|
||||
|
||||
@@ -249,7 +249,7 @@ Rules:
|
||||
},
|
||||
})
|
||||
|
||||
const responseText = extractTextContent(response.message.content).trim()
|
||||
const responseText = extractTextContent(Array.isArray(response.message.content) ? response.message.content : []).trim()
|
||||
|
||||
const updatedContent = extractTag(responseText, 'updated_file')
|
||||
if (!updatedContent) {
|
||||
|
||||
@@ -80,7 +80,7 @@ Parse the user's input into ISO 8601 format. Return ONLY the formatted string, o
|
||||
})
|
||||
|
||||
// Extract text from result
|
||||
const parsedText = extractTextContent(result.message.content).trim()
|
||||
const parsedText = extractTextContent(Array.isArray(result.message.content) ? result.message.content : []).trim()
|
||||
|
||||
// Validate that we got something usable
|
||||
if (!parsedText || parsedText === 'INVALID') {
|
||||
|
||||
@@ -113,7 +113,7 @@ function extractConversationContext(
|
||||
|
||||
for (const msg of assistantMessages.reverse()) {
|
||||
// Extract text content from assistant message
|
||||
const textBlocks = msg.message.content
|
||||
const textBlocks = (Array.isArray(msg.message.content) ? msg.message.content : [])
|
||||
.filter(c => c.type === 'text')
|
||||
.map(c => ('text' in c ? c.text : ''))
|
||||
.join(' ')
|
||||
|
||||
@@ -343,7 +343,7 @@ export function buildTranscriptEntries(messages: Message[]): TranscriptEntry[] {
|
||||
for (const block of msg.message.content) {
|
||||
// Only include tool_use blocks — assistant text is model-authored
|
||||
// and could be crafted to influence the classifier's decision.
|
||||
if (block.type === 'tool_use') {
|
||||
if (typeof block !== 'string' && block.type === 'tool_use') {
|
||||
blocks.push({
|
||||
type: 'tool_use',
|
||||
name: block.name,
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -408,7 +408,7 @@ export async function installResolvedPlugin({
|
||||
allowedCrossMarketplaces,
|
||||
)
|
||||
if (!resolution.ok) {
|
||||
return { ok: false, reason: 'resolution-failed', resolution }
|
||||
return { ok: false, reason: 'resolution-failed', resolution: resolution as ResolutionResult & { ok: false } }
|
||||
}
|
||||
|
||||
// ── Policy guard for transitive dependencies ──
|
||||
@@ -525,31 +525,32 @@ export async function installPluginFromMarketplace({
|
||||
})
|
||||
|
||||
if (!result.ok) {
|
||||
switch (result.reason) {
|
||||
const failedResult = result as Exclude<InstallCoreResult, { ok: true }>
|
||||
switch (failedResult.reason) {
|
||||
case 'local-source-no-location':
|
||||
return {
|
||||
success: false,
|
||||
error: `Cannot install local plugin "${result.pluginName}" without marketplace install location`,
|
||||
error: `Cannot install local plugin "${failedResult.pluginName}" without marketplace install location`,
|
||||
}
|
||||
case 'settings-write-failed':
|
||||
return {
|
||||
success: false,
|
||||
error: `Failed to update settings: ${result.message}`,
|
||||
error: `Failed to update settings: ${failedResult.message}`,
|
||||
}
|
||||
case 'resolution-failed':
|
||||
return {
|
||||
success: false,
|
||||
error: formatResolutionError(result.resolution),
|
||||
error: formatResolutionError(failedResult.resolution),
|
||||
}
|
||||
case 'blocked-by-policy':
|
||||
return {
|
||||
success: false,
|
||||
error: `Plugin "${result.pluginName}" is blocked by your organization's policy and cannot be installed`,
|
||||
error: `Plugin "${failedResult.pluginName}" is blocked by your organization's policy and cannot be installed`,
|
||||
}
|
||||
case 'dependency-blocked-by-policy':
|
||||
return {
|
||||
success: false,
|
||||
error: `Cannot install "${result.pluginName}": dependency "${result.blockedDependency}" is blocked by your organization's policy`,
|
||||
error: `Cannot install "${failedResult.pluginName}": dependency "${failedResult.blockedDependency}" is blocked by your organization's policy`,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -585,7 +586,7 @@ export async function installPluginFromMarketplace({
|
||||
|
||||
return {
|
||||
success: true,
|
||||
message: `✓ Installed ${entry.name}${result.depNote}. Run /reload-plugins to activate.`,
|
||||
message: `✓ Installed ${entry.name}${(result as Extract<InstallCoreResult, { ok: true }>).depNote}. Run /reload-plugins to activate.`,
|
||||
}
|
||||
} catch (err) {
|
||||
const errorMessage = err instanceof Error ? err.message : String(err)
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -307,8 +307,8 @@ async function processSessionFiles(
|
||||
|
||||
// Track model usage if available (skip synthetic messages)
|
||||
if (message.message?.usage) {
|
||||
const usage = message.message.usage
|
||||
const model = message.message.model || 'unknown'
|
||||
const usage = message.message.usage as Record<string, number>
|
||||
const model = (message.message.model as string) || 'unknown'
|
||||
|
||||
// Skip synthetic messages - they are internal and shouldn't appear in stats
|
||||
if (model === SYNTHETIC_MODEL) {
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1235,8 +1235,8 @@ export async function runInProcessTeammate(
|
||||
// Track in-progress tool use IDs for animation in transcript view
|
||||
let inProgressToolUseIDs = task.inProgressToolUseIDs
|
||||
if (message.type === 'assistant') {
|
||||
for (const block of message.message.content) {
|
||||
if (block.type === 'tool_use') {
|
||||
for (const block of (Array.isArray(message.message.content) ? message.message.content : [])) {
|
||||
if (typeof block !== 'string' && block.type === 'tool_use') {
|
||||
inProgressToolUseIDs = new Set([
|
||||
...(inProgressToolUseIDs ?? []),
|
||||
block.id,
|
||||
|
||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user