Add chat-ui-htmx module: streaming chat page on Spring AI 2.0.2 with htmx and its SSE extension (vendored), MessageChatMemoryAdvisor keyed by the HTTP session, a Stop button, and the traps measured: EventSource strips one leading space per data line, model text must be HTML-escaped, a cancelled stream left the upstream connection open in 7 of 8 runs until an OkHttp interceptor calls Call.cancel (8 of 8 closed after), and the SDK push source ignores back-pressure (limitRate changes only the demand; a bounded buffer works). The model is a stub OpenAI-compatible SSE server written for the module; no real provider was run.

Co-Authored-By: Claude Sonnet 5.5 <[email protected]>
Claude-Session: https://claude.ai/code/session_017ic4b6Kg9RWSTJzyz6KP9X
This commit is contained in:
2026-10-31 04:02:56 +00:00
co-authored by Claude Sonnet 5.5
parent c97bcf9adf
commit 68da642f9a
35 changed files with 1571 additions and 0 deletions
+45
View File
@@ -0,0 +1,45 @@
== chat.backpressure=none (stub delay 0 ms, 600 chunks x 32 KiB, client reads 64 KiB every 0.2 s)
t= 1.0s client got 0 KiB stub: chunksWritten=0 finished=0 abortedByClient=0 app heap after GC: used 34669K
t= 2.8s client got 197 KiB stub: chunksWritten=452 finished=0 abortedByClient=0 app heap after GC: used 134096K
t= 5.5s client got 896 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 86306K
t= 8.9s client got 1832 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 109343K
t=13.3s client got 2967 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 116565K
-- app log (demand + outcome):
213 web-side demand request(1)
213 model-side demand request(1)
1 CANCELLED by client after 213 tokens
== chat.backpressure=limitRate (stub delay 0 ms, 600 chunks x 32 KiB, client reads 64 KiB every 0.2 s)
t= 1.0s client got 0 KiB stub: chunksWritten=0 finished=0 abortedByClient=0 app heap after GC: used 42630K
t= 2.8s client got 242 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 86598K
t= 5.2s client got 896 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 86745K
t= 8.5s client got 1768 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 109571K
t=12.9s client got 2967 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 116491K
-- app log (demand + outcome):
213 web-side demand request(1)
35 model-side demand request(6)
1 model-side demand request(8)
1 CANCELLED by client after 213 tokens
== chat.backpressure=slow (stub delay 0 ms, 600 chunks x 32 KiB, client reads 64 KiB every 0.2 s)
t= 1.0s client got 0 KiB stub: chunksWritten=0 finished=0 abortedByClient=0 app heap after GC: used 40942K
t= 2.6s client got 72 KiB stub: chunksWritten=218 finished=0 abortedByClient=0 app heap after GC: used 146705K
t= 5.3s client got 787 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 111009K
t= 8.6s client got 1659 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 109188K
t=13.0s client got 2858 KiB stub: chunksWritten=603 finished=1 abortedByClient=0 app heap after GC: used 119593K
-- app log (demand + outcome):
221 model-side demand request(1)
220 web-side demand request(1)
1 CANCELLED by client after 220 tokens
== chat.backpressure=bounded (stub delay 0 ms, 600 chunks x 32 KiB, client reads 64 KiB every 0.2 s)
t= 1.0s client got 0 KiB stub: chunksWritten=0 finished=0 abortedByClient=0 app heap after GC: used 61061K
t= 2.7s client got 133 KiB stub: chunksWritten=256 finished=0 abortedByClient=0 app heap after GC: used 58420K
t= 5.1s client got 787 KiB stub: chunksWritten=256 finished=0 abortedByClient=1 app heap after GC: used 58420K
t= 8.5s client got 1659 KiB stub: chunksWritten=256 finished=0 abortedByClient=1 app heap after GC: used 30251K
t=12.8s client got 2858 KiB stub: chunksWritten=256 finished=0 abortedByClient=1 app heap after GC: used 30381K
-- app log (demand + outcome):
144 web-side demand request(1)
1 model-side demand request(unbounded)
1 error reactor.core.Exceptions$OverflowException: The receiver is overrun by more signals than expected (bounded queue...)