| @@ -1215,26 +1215,37 @@ export abstract class McpAgentSessionDOBase< · 1214 unmodified lines |
| 1215 | } | 1215 | } |
| 1216 | if (request.method === "GET") { | 1216 | if (request.method === "GET") { |
| 1217 | const lastEventId = request.headers.get("last-event-id"); | 1217 | const lastEventId = request.headers.get("last-event-id"); |
| 1218 | if (lastEventId) { | 1218 | const resumeHasPendingEvents = |
| | 1219 | lastEventId !== null && (await this.eventStore.hasEventsAfter(lastEventId)); |
| | 1220 | if (lastEventId && resumeHasPendingEvents) { |
| 1219 | await this.supersedeReplayStream(transport, lastEventId); | 1221 | await this.supersedeReplayStream(transport, lastEventId); |
| 1220 | } else { | 1222 | } else { |
| | 1223 | // Standalone listener path — taken for a bare GET AND for a GET |
| | 1224 | // whose Last-Event-ID stream is fully drained. EventSource clients |
| | 1225 | // echo their last id on every reconnect, so a drained id must not |
| | 1226 | // enter the transport's resume (it closes a completed stream's |
| | 1227 | // resume immediately, turning the echo into a reconnect loop). |
| | 1228 | let serveRequest = request; |
| | 1229 | if (lastEventId) { |
| | 1230 | const headers = new Headers(request.headers); |
| | 1231 | headers.delete("last-event-id"); |
| | 1232 | serveRequest = new Request(request, { headers }); |
| | 1233 | } |
| 1221 | // Latest-listener-wins. Client cancellation is not reliably relayed | 1234 | // Latest-listener-wins. Client cancellation is not reliably relayed |
| 1222 | // through every workerd/Vite streaming hop, so explicitly retire a | 1235 | // through every workerd/Vite streaming hop, so explicitly retire a |
| 1223 | // stale standalone mapping before opening its replacement. | 1236 | // stale standalone mapping before opening its replacement. |
| 1224 | transport.closeStandaloneSSEStream(); | 1237 | transport.closeStandaloneSSEStream(); |
| 1225 | const replay = await this.collectUndeliveredReplay(); | 1238 | const replay = await this.collectUndeliveredReplay(); |
| 1226 | if (replay) { | 1239 | // Replayed responses ride as the opening frames of the transport's |
| 1227 | // Prepend the replay onto the transport's own long-lived | 1240 | // own long-lived standalone stream — the stream MUST stay open |
| 1228 | // standalone stream — the stream MUST stay open afterwards (see | 1241 | // afterwards (see collectUndeliveredReplay). Acknowledgement moves |
| 1229 | // collectUndeliveredReplay). Acknowledgement moves to stream end: | 1242 | // to stream end: "complete"/"rotate" imply the client stayed |
| 1230 | // "complete"/"rotate" imply the client stayed attached long | 1243 | // attached long enough to have drained the prepended frames. |
| 1231 | // enough to have drained the prepended frames. | 1244 | const response = await transport.handleRequest(serveRequest); |
| 1232 | const response = await transport.handleRequest(request); | 1245 | return this.trackedLegacyResponse( |
| 1233 | return this.trackedLegacyResponse(response, { | 1246 | response, |
| 1234 | initialFrame: replay.frame, | 1247 | replay ? { initialFrame: replay.frame, acknowledge: replay.streamIds } : {}, |
| 1235 | acknowledge: replay.streamIds, | 1248 | ); |
| 1236 | }); | | |
| 1237 | } | | |
| 1238 | } | 1249 | } |
| 1239 | } | 1250 | } |
| 1240 | const toolCallIds = legacyToolCallRequestIds(parsedBody); | 1251 | const toolCallIds = legacyToolCallRequestIds(parsedBody); |