(raw: JournalEntry)
| 862 | const MAX_ADDED_NAMES = 1000 |
| 863 | |
| 864 | export function compactEntry(raw: JournalEntry): JournalEntry { |
| 865 | const entry: JournalEntry = { type: raw.type } |
| 866 | |
| 867 | if (raw.timestamp !== undefined) entry.timestamp = raw.timestamp |
| 868 | if (raw.sessionId !== undefined) entry.sessionId = raw.sessionId |
| 869 | if (raw.cwd !== undefined) entry.cwd = raw.cwd |
| 870 | |
| 871 | const att = (raw as Record<string, unknown>)['attachment'] |
| 872 | if (att && typeof att === 'object') { |
| 873 | const a = att as Record<string, unknown> |
| 874 | if (a['type'] === 'deferred_tools_delta' && Array.isArray(a['addedNames'])) { |
| 875 | const names: string[] = [] |
| 876 | for (let i = 0; i < Math.min(a['addedNames'].length, MAX_ADDED_NAMES); i++) { |
| 877 | const n = a['addedNames'][i] |
| 878 | if (typeof n === 'string') names.push(n) |
| 879 | } |
| 880 | ;(entry as Record<string, unknown>)['attachment'] = { type: 'deferred_tools_delta', addedNames: names } |
| 881 | } |
| 882 | } |
| 883 | |
| 884 | if (!raw.message) return entry |
| 885 | |
| 886 | if (raw.message.role === 'user') { |
| 887 | const content = raw.message.content |
| 888 | if (typeof content === 'string') { |
| 889 | entry.message = { role: 'user', content: content.slice(0, USER_TEXT_CAP) } |
| 890 | } else if (Array.isArray(content)) { |
| 891 | let remaining = USER_TEXT_CAP |
| 892 | const blocks: { type: 'text'; text: string }[] = [] |
| 893 | for (const b of content) { |
| 894 | if (remaining <= 0) break |
| 895 | if (!b || typeof b !== 'object' || b.type !== 'text') continue |
| 896 | const text = (b as { text?: unknown }).text |
| 897 | if (typeof text !== 'string') continue |
| 898 | const sliced = text.slice(0, remaining) |
| 899 | blocks.push({ type: 'text', text: sliced }) |
| 900 | remaining -= sliced.length |
| 901 | } |
| 902 | entry.message = { role: 'user', content: blocks } |
| 903 | } |
| 904 | return entry |
| 905 | } |
| 906 | |
| 907 | const msg = raw.message as AssistantMessageContent |
| 908 | if (!msg.usage || !msg.model) return entry |
| 909 | |
| 910 | const rawContent = msg.content |
| 911 | const contentArr = Array.isArray(rawContent) ? rawContent : [] |
| 912 | const toolBlocks = contentArr.filter((b): b is ToolUseBlock => b != null && typeof b === 'object' && b.type === 'tool_use') |
| 913 | const compactContent: ContentBlock[] = toolBlocks.slice(0, MAX_TOOL_BLOCKS).map(tb => { |
| 914 | let input: Record<string, unknown> = {} |
| 915 | if (tb.name === 'Skill') { |
| 916 | const ri = (tb.input ?? {}) as Record<string, unknown> |
| 917 | if (typeof ri['skill'] === 'string') input['skill'] = (ri['skill'] as string).slice(0, 200) |
| 918 | if (typeof ri['name'] === 'string') input['name'] = (ri['name'] as string).slice(0, 200) |
| 919 | } else if (tb.name === 'Read' || tb.name === 'FileReadTool' || EDIT_TOOLS.has(tb.name)) { |
| 920 | const ri = (tb.input ?? {}) as Record<string, unknown> |
| 921 | if (typeof ri['file_path'] === 'string') input['file_path'] = (ri['file_path'] as string).slice(0, BASH_COMMAND_CAP) |
no outgoing calls
no test coverage detected