( body: string, ts: string, state: DumpState, filePath: string, )
| 88 | } |
| 89 | |
| 90 | function dumpRequest( |
| 91 | body: string, |
| 92 | ts: string, |
| 93 | state: DumpState, |
| 94 | filePath: string, |
| 95 | ): void { |
| 96 | try { |
| 97 | const req = jsonParse(body) as Record<string, unknown> |
| 98 | addApiRequestToCache(req) |
| 99 | |
| 100 | if (process.env.USER_TYPE !== 'ant') return |
| 101 | const entries: string[] = [] |
| 102 | const messages = (req.messages ?? []) as Array<{ role?: string }> |
| 103 | |
| 104 | // Write init data (system, tools, metadata) on first request, |
| 105 | // and a system_update entry whenever it changes. |
| 106 | // Cheap fingerprint first: system+tools don't change between turns, |
| 107 | // so skip the 300ms stringify when the shape is unchanged. |
| 108 | const fingerprint = initFingerprint(req) |
| 109 | if (!state.initialized || fingerprint !== state.lastInitFingerprint) { |
| 110 | const { messages: _, ...initData } = req |
| 111 | const initDataStr = jsonStringify(initData) |
| 112 | const initDataHash = hashString(initDataStr) |
| 113 | state.lastInitFingerprint = fingerprint |
| 114 | if (!state.initialized) { |
| 115 | state.initialized = true |
| 116 | state.lastInitDataHash = initDataHash |
| 117 | // Reuse initDataStr rather than re-serializing initData inside a wrapper. |
| 118 | // timestamp from toISOString() contains no chars needing JSON escaping. |
| 119 | entries.push( |
| 120 | `{"type":"init","timestamp":"${ts}","data":${initDataStr}}`, |
| 121 | ) |
| 122 | } else if (initDataHash !== state.lastInitDataHash) { |
| 123 | state.lastInitDataHash = initDataHash |
| 124 | entries.push( |
| 125 | `{"type":"system_update","timestamp":"${ts}","data":${initDataStr}}`, |
| 126 | ) |
| 127 | } |
| 128 | } |
| 129 | |
| 130 | // Write only new user messages (assistant messages captured in response) |
| 131 | for (const msg of messages.slice(state.messageCountSeen)) { |
| 132 | if (msg.role === 'user') { |
| 133 | entries.push( |
| 134 | jsonStringify({ type: 'message', timestamp: ts, data: msg }), |
| 135 | ) |
| 136 | } |
| 137 | } |
| 138 | state.messageCountSeen = messages.length |
| 139 | |
| 140 | appendToFile(filePath, entries) |
| 141 | } catch { |
| 142 | // Ignore parsing errors |
| 143 | } |
| 144 | } |
| 145 | |
| 146 | export function createDumpPromptsFetch( |
| 147 | agentIdOrSessionId: string, |
nothing calls this directly
no test coverage detected