feat(13-10): node-side chat history, scoped by caller, compacted not truncated
history.rs persists the ChatMessage transcript under data_dir (D-08), keyed by a HistoryKey derived from CallerScope so an operator's AIUI session and a mesh peer's transcript are structurally distinct files, not two rows a filter could forget. Writes are atomic (temp sibling + rename, matching music/index.rs::save_atomic's precedent) and 0600, following grants.rs's convention. Tool results longer than MAX_TOOL_RESULT_CHARS are truncated with a visible marker before entering history -- a new, assistant-scoped constant, never assist.rs's LoRa-airtime-tuned reply cap. Once the transcript exceeds KEEP_VERBATIM_TURNS, older turns fold into a running summary extended incrementally as turns age out, never regenerated from the full transcript. Wallet/files-category tool-call arguments are never persisted (AI-SPEC §7b's field policy applied to storage, not only tracing) -- categories are resolved by the caller from the same tools registry execute_tool uses, so history.rs never re-derives a second, driftable category list. Nothing reachable from confirm.rs's pending- confirmation state has a parameter path into this module at all (S-09 stays true structurally). assistant.history / assistant.clear-history route through 13-01's existing assistant.* dispatcher arm (dispatcher.rs untouched), each scoped to the calling session's own HistoryKey. run_loop (loop_.rs) now returns (answer, full_history) instead of just the answer string -- structurally necessary so chat() (mod.rs) can persist the tool-call/tool-result messages the loop built internally, not only the user question and final answer (Rule 3, mirroring 13-05's precedent of touching a file outside its own plan's files_modified list when the plan's own intent requires it). chat() persists this turn after run_loop returns; it does not yet feed prior persisted turns back into live model context -- a documented, deliberately scoped follow-up (see mod.rs's chat() doc comment and the plan SUMMARY). 8 new tests under assistant::history::tests::, including operator_and_mesh_transcripts_are_separate and wallet_tool_arguments_never_reach_the_transcript (asserted against both the deserialized struct and the raw on-disk bytes). Full assistant:: suite: 50/50 (42 baseline-after-Task-1 + 8 new); confirm::tests:: restart_drops_pending_not_executes still passes -- S-09 not weakened. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
821d8700ce
commit
3da9928cc9
@@ -1110,7 +1110,7 @@ mod tests {
|
||||
];
|
||||
let backend2 = ScriptedBackend::new(turns2);
|
||||
let tools_list2 = vec![app_logs_tool()];
|
||||
let answer = run_loop(&backend2, "sys", &tools_list2, vec![], &ctx2)
|
||||
let (answer, _history) = run_loop(&backend2, "sys", &tools_list2, vec![], &ctx2)
|
||||
.await
|
||||
.expect("run_loop should abort gracefully with an apology, not error");
|
||||
assert_ne!(
|
||||
|
||||
Reference in New Issue
Block a user