Strip the heavy backend payload from a saved session while preserving its * rendered transcript. Loading such a file later tokenizes the text and * rebuilds the live KV with a full prefill. */
| 5247 | |
| 5248 | static void agent_history_publish_limited(agent_worker *w, const char *p, |
| 5249 | const char *end, int max_lines, |
| 5250 | size_t max_bytes) { |
| 5251 | bool truncated = false; |
| 5252 | const char *start = agent_history_tail_start(p, end, max_lines, max_bytes, |
| 5253 | &truncated); |
| 5254 | if (truncated) |
| 5255 | agent_publish(w, "\n... earlier history truncated; showing tail ...\n", |
| 5256 | strlen("\n... earlier history truncated; showing tail ...\n")); |
| 5257 | agent_publish(w, start, (size_t)(end - start)); |
| 5258 | if (end > start && end[-1] != '\n') agent_publish(w, "\n", 1); |
| 5259 | } |
| 5260 | |
| 5261 | static void agent_history_render_assistant(agent_worker *w, |
| 5262 | const char *p, const char *end) { |
| 5263 | agent_history_trim(&p, &end); |
| 5264 | if (p >= end) return; |
| 5265 | bool source_truncated = false; |
| 5266 | (void)agent_history_tail_start(p, end, |
| 5267 | AGENT_HISTORY_ASSISTANT_MAX_LINES, |
| 5268 | AGENT_HISTORY_ASSISTANT_MAX_BYTES, |
| 5269 | &source_truncated); |
| 5270 | bool use_color = isatty(STDOUT_FILENO) != 0; |
| 5271 | agent_tail_capture tail = { |
| 5272 | .cap = source_truncated ? AGENT_HISTORY_ASSISTANT_MAX_BYTES : 0, |
| 5273 | }; |
| 5274 | agent_token_renderer renderer = { |
| 5275 | .engine = w->engine, |
| 5276 | .worker = w, |
| 5277 | .format_thinking = true, |
| 5278 | /* History replay should look like the original live output: the user is |
| 5279 | * switching back to a session, not reading a different transcript |
| 5280 | * format. Tool calls are still dry-rendered below, so replay never |
| 5281 | * executes tools or mutates transcript state. */ |
| 5282 | .format_markdown = true, |
| 5283 | .use_color = use_color && !source_truncated, |
| 5284 | .last_output_newline = true, |
| 5285 | .capture = source_truncated ? &tail : NULL, |
| 5286 | }; |
| 5287 | agent_tool_syntax tool_syntax = agent_tool_syntax_for_engine(w->engine); |
| 5288 | agent_dsml_parser dsml = { |
| 5289 | .syntax = tool_syntax, |
| 5290 | .state = AGENT_DSML_SEARCH, |
| 5291 | }; |
| 5292 | agent_stream_renderer stream = { |
| 5293 | .renderer = &renderer, |
| 5294 | .parser = &dsml, |
| 5295 | .syntax = tool_syntax, |
| 5296 | .replay = true, |
| 5297 | }; |
| 5298 | |
| 5299 | /* Dry-run replay: the same streaming projection hides DSML and renders |
| 5300 | * semantic tool lines, but no tool is executed and no transcript state is |
| 5301 | * changed. The saved KV payload remains the only authority for resume. */ |
| 5302 | agent_stream_text(&stream, p, (size_t)(end - p), true); |
| 5303 | renderer_finish(&renderer); |
| 5304 | agent_dsml_parser_free(&dsml); |
| 5305 | |
| 5306 | if (source_truncated) { |
no test coverage detected