Commit b85feee
fix(runner): always emit MESSAGES_SNAPSHOT to prevent compaction failures (#1693)
## Summary
- **C1 — `grpc_transport.py`**: Skip gRPC messages with empty payloads
instead of building an empty-content message. An empty-content message
causes `process_messages` to return `""`, which triggers an early
`RunFinishedEvent` before `_stream_claude_sdk` ever runs — so
`run_messages` stays empty and `MESSAGES_SNAPSHOT` is never emitted.
Affects both Operator-managed and control-plane-reconciled runner
sessions.
- **C2 — `run.py`**: Assign UUIDs to message dicts missing an `id` in
`to_run_agent_input`. Without ids, `upsert_message` falls back to append
on every call, creating duplicates in the snapshot for multi-turn
sessions going through the gRPC dict message path.
- **C3 — `adapter.py`**: Remove the `if run_messages:` guard around
`MESSAGES_SNAPSHOT` emission. Runs that produce no assistant output
(interrupted, halted on frontend tool, state-management-tool-only turns)
still need a snapshot so `compactFinishedRun` can succeed. When
`run_messages` is empty the snapshot contains the stamped input history,
which is sufficient. Without a snapshot, compaction logs "session
corrupted, keeping raw events" and chat history is lost after the
tail-read optimization (ffe4a21).
## Root cause
`compactFinishedRun` (backend `agui_store.go`) requires
`MESSAGES_SNAPSHOT` to be present in the JSONL to perform compaction. If
absent, it aborts and leaves raw streaming delta events in the file. On
the next large-session tail-read (`8e3bac3`), those deltas may be
missing from the head scan and the user sees blank chat history on
reconnect.
The `MESSAGES_SNAPSHOT` gap was introduced when `ambient-control-plane`
added a second reconciled runner path: control-plane sessions reach the
runner via gRPC (`GRPCSessionListener`) rather than HTTP, and the gRPC
path has different message-shape guarantees that exposed all three gaps
simultaneously.
## Test plan
- [ ] Operator-managed session: send multiple messages, navigate away
and back — chat history intact
- [ ] Control-plane-reconciled session: same navigation test
- [ ] Session where Claude calls only state-management tools (no text
output): navigate away, verify prior history still present on return
- [ ] Session interrupted mid-run (stop button): reconnect, verify
history from previous complete turns is intact
- [ ] Check runner logs: `MESSAGES_SNAPSHOT` log line should appear for
every `RUN_FINISHED`/`RUN_ERROR` turn
- [ ] Check backend logs: `compaction` log should show `X raw events → Y
snapshot events` (not "session corrupted")
🤖 Generated with [Claude Code](https://claude.ai/claude-code)
<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit
## Release Notes
* **Bug Fixes**
* Improved handling of empty or malformed messages to prevent processing
failures
* Enhanced message snapshot construction to be more reliable across
scenarios
* Added automatic message ID generation to ensure data consistency
* Strengthened validation for incoming message payloads with better
error logging
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
Co-authored-by: Claude <noreply@anthropic.com>1 parent 7e918dd commit b85feee
3 files changed
Lines changed: 63 additions & 42 deletions
File tree
- components/runners/ambient-runner
- ag_ui_claude_sdk
- ambient_runner
- bridges/claude
- endpoints
Lines changed: 48 additions & 41 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1310 | 1310 | | |
1311 | 1311 | | |
1312 | 1312 | | |
1313 | | - | |
1314 | | - | |
1315 | | - | |
1316 | | - | |
1317 | | - | |
1318 | | - | |
1319 | | - | |
1320 | | - | |
1321 | | - | |
1322 | | - | |
1323 | | - | |
1324 | | - | |
1325 | | - | |
1326 | | - | |
1327 | | - | |
1328 | | - | |
1329 | | - | |
1330 | | - | |
1331 | | - | |
1332 | | - | |
1333 | | - | |
1334 | | - | |
1335 | | - | |
1336 | | - | |
1337 | | - | |
1338 | | - | |
1339 | | - | |
1340 | | - | |
1341 | | - | |
1342 | | - | |
1343 | | - | |
1344 | | - | |
1345 | | - | |
1346 | | - | |
| 1313 | + | |
| 1314 | + | |
| 1315 | + | |
| 1316 | + | |
| 1317 | + | |
| 1318 | + | |
| 1319 | + | |
| 1320 | + | |
| 1321 | + | |
| 1322 | + | |
| 1323 | + | |
| 1324 | + | |
| 1325 | + | |
| 1326 | + | |
1347 | 1327 | | |
1348 | 1328 | | |
1349 | | - | |
1350 | | - | |
| 1329 | + | |
| 1330 | + | |
1351 | 1331 | | |
1352 | 1332 | | |
1353 | 1333 | | |
1354 | | - | |
| 1334 | + | |
1355 | 1335 | | |
| 1336 | + | |
1356 | 1337 | | |
1357 | | - | |
1358 | | - | |
1359 | | - | |
| 1338 | + | |
| 1339 | + | |
| 1340 | + | |
| 1341 | + | |
| 1342 | + | |
| 1343 | + | |
| 1344 | + | |
| 1345 | + | |
| 1346 | + | |
| 1347 | + | |
| 1348 | + | |
| 1349 | + | |
| 1350 | + | |
| 1351 | + | |
| 1352 | + | |
| 1353 | + | |
| 1354 | + | |
| 1355 | + | |
| 1356 | + | |
| 1357 | + | |
| 1358 | + | |
| 1359 | + | |
| 1360 | + | |
| 1361 | + | |
| 1362 | + | |
| 1363 | + | |
| 1364 | + | |
| 1365 | + | |
1360 | 1366 | | |
1361 | | - | |
| 1367 | + | |
| 1368 | + | |
1362 | 1369 | | |
1363 | 1370 | | |
1364 | 1371 | | |
| |||
Lines changed: 6 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
294 | 294 | | |
295 | 295 | | |
296 | 296 | | |
| 297 | + | |
| 298 | + | |
| 299 | + | |
| 300 | + | |
| 301 | + | |
| 302 | + | |
297 | 303 | | |
298 | 304 | | |
299 | 305 | | |
| |||
Lines changed: 9 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
44 | 52 | | |
45 | 53 | | |
46 | 54 | | |
47 | 55 | | |
48 | | - | |
| 56 | + | |
49 | 57 | | |
50 | 58 | | |
51 | 59 | | |
| |||
0 commit comments