MCPcopy
hub / github.com/codeaashu/claude-code / normalizeMessagesForAPI

Function normalizeMessagesForAPI

src/utils/messages.ts:1989–2370  ·  view source on GitHub ↗
(
  messages: Message[],
  tools: Tools = [],
)

Source from the content-addressed store, hash-verified

1987}
1988
1989export function normalizeMessagesForAPI(
1990 messages: Message[],
1991 tools: Tools = [],
1992): (UserMessage | AssistantMessage)[] {
1993 // Build set of available tool names for filtering unavailable tool references
1994 const availableToolNames = new Set(tools.map(t => t.name))
1995
1996 // First, reorder attachments to bubble up until they hit a tool result or assistant message
1997 // Then strip virtual messages — they're display-only (e.g. REPL inner tool
1998 // calls) and must never reach the API.
1999 const reorderedMessages = reorderAttachmentsForAPI(messages).filter(
2000 m => !((m.type === 'user' || m.type === 'assistant') && m.isVirtual),
2001 )
2002
2003 // Build a map from error text → which block types to strip from the preceding user message.
2004 const errorToBlockTypes: Record<string, Set<string>> = {
2005 [getPdfTooLargeErrorMessage()]: new Set(['document']),
2006 [getPdfPasswordProtectedErrorMessage()]: new Set(['document']),
2007 [getPdfInvalidErrorMessage()]: new Set(['document']),
2008 [getImageTooLargeErrorMessage()]: new Set(['image']),
2009 [getRequestTooLargeErrorMessage()]: new Set(['document', 'image']),
2010 }
2011
2012 // Walk the reordered messages to build a targeted strip map:
2013 // userMessageUUID → set of block types to strip from that message.
2014 const stripTargets = new Map<string, Set<string>>()
2015 for (let i = 0; i < reorderedMessages.length; i++) {
2016 const msg = reorderedMessages[i]!
2017 if (!isSyntheticApiErrorMessage(msg)) {
2018 continue
2019 }
2020 // Determine which error this is
2021 const errorText =
2022 Array.isArray(msg.message.content) &&
2023 msg.message.content[0]?.type === 'text'
2024 ? msg.message.content[0].text
2025 : undefined
2026 if (!errorText) {
2027 continue
2028 }
2029 const blockTypesToStrip = errorToBlockTypes[errorText]
2030 if (!blockTypesToStrip) {
2031 continue
2032 }
2033 // Walk backward to find the nearest preceding isMeta user message
2034 for (let j = i - 1; j >= 0; j--) {
2035 const candidate = reorderedMessages[j]!
2036 if (candidate.type === 'user' && candidate.isMeta) {
2037 const existing = stripTargets.get(candidate.uuid)
2038 if (existing) {
2039 for (const t of blockTypesToStrip) {
2040 existing.add(t)
2041 }
2042 } else {
2043 stripTargets.set(candidate.uuid, new Set(blockTypesToStrip))
2044 }
2045 break
2046 }

Callers 9

queryLoopFunction · 0.85
FeedbackFunction · 0.85
submitTranscriptShareFunction · 0.85
generateAgentFunction · 0.85
analyzeContextFunction · 0.85
approximateMessageTokensFunction · 0.85
withVCRFunction · 0.85
streamCompactSummaryFunction · 0.85
queryModelFunction · 0.85

Tested by

no test coverage detected