( agentIdOrSessionId: string, )
| 144 | } |
| 145 | |
| 146 | export function createDumpPromptsFetch( |
| 147 | agentIdOrSessionId: string, |
| 148 | ): ClientOptions['fetch'] { |
| 149 | const filePath = getDumpPromptsPath(agentIdOrSessionId) |
| 150 | |
| 151 | return async (input: RequestInfo | URL, init?: RequestInit) => { |
| 152 | const state = dumpState.get(agentIdOrSessionId) ?? { |
| 153 | initialized: false, |
| 154 | messageCountSeen: 0, |
| 155 | lastInitDataHash: '', |
| 156 | lastInitFingerprint: '', |
| 157 | } |
| 158 | dumpState.set(agentIdOrSessionId, state) |
| 159 | |
| 160 | let timestamp: string | undefined |
| 161 | |
| 162 | if (init?.method === 'POST' && init.body) { |
| 163 | timestamp = new Date().toISOString() |
| 164 | // Parsing + stringifying the request (system prompt + tool schemas = MBs) |
| 165 | // takes hundreds of ms. Defer so it doesn't block the actual API call — |
| 166 | // this is debug tooling for /issue, not on the critical path. |
| 167 | setImmediate(dumpRequest, init.body as string, timestamp, state, filePath) |
| 168 | } |
| 169 | |
| 170 | // eslint-disable-next-line eslint-plugin-n/no-unsupported-features/node-builtins |
| 171 | const response = await globalThis.fetch(input, init) |
| 172 | |
| 173 | // Save response async |
| 174 | if (timestamp && response.ok && process.env.USER_TYPE === 'ant') { |
| 175 | const cloned = response.clone() |
| 176 | void (async () => { |
| 177 | try { |
| 178 | const isStreaming = cloned.headers |
| 179 | .get('content-type') |
| 180 | ?.includes('text/event-stream') |
| 181 | |
| 182 | let data: unknown |
| 183 | if (isStreaming && cloned.body) { |
| 184 | // Parse SSE stream into chunks |
| 185 | const reader = cloned.body.getReader() |
| 186 | const decoder = new TextDecoder() |
| 187 | let buffer = '' |
| 188 | try { |
| 189 | while (true) { |
| 190 | const { done, value } = await reader.read() |
| 191 | if (done) break |
| 192 | buffer += decoder.decode(value, { stream: true }) |
| 193 | } |
| 194 | } finally { |
| 195 | reader.releaseLock() |
| 196 | } |
| 197 | const chunks: unknown[] = [] |
| 198 | for (const event of buffer.split('\n\n')) { |
| 199 | for (const line of event.split('\n')) { |
| 200 | if (line.startsWith('data: ') && line !== 'data: [DONE]') { |
| 201 | try { |
| 202 | chunks.push(jsonParse(line.slice(6))) |
| 203 | } catch { |
no test coverage detected