MCPcopy Create free account
hub / github.com/atomicdotdev/atomic / summarize_from_transcript

Function summarize_from_transcript

atomic-agent/src/record/message.rs:76–130  ·  view source on GitHub ↗

Extract a one-line commit message from the agent's transcript file. Reads the transcript JSONL, condenses it into structured entries, then looks for assistant text that appears **after the last tool call**. This is the wrap-up summary ("I've set up the project..."), not the opening analysis ("This appears to be a minimal repository..."). If there is no assistant text after the last tool call, re

(transcript_path: &std::path::Path)

Source from the content-addressed store, hash-verified

74///
75/// This is purely a file read. No subprocess, no API call, no network.
76pub(crate) fn summarize_from_transcript(transcript_path: &std::path::Path) -> Option<String> {
77 // Read the transcript file (best-effort, non-fatal)
78 let raw = match std::fs::read(transcript_path) {
79 Ok(data) if !data.is_empty() => data,
80 Ok(_) => {
81 log::debug!("Transcript file is empty");
82 return None;
83 }
84 Err(e) => {
85 log::debug!("Could not read transcript for summarization: {}", e);
86 return None;
87 }
88 };
89
90 // Parse into condensed entries using the existing transcript parser
91 let entries = transcript::condense_claude_transcript(&raw);
92 if entries.is_empty() {
93 return None;
94 }
95
96 // Find the index of the last tool call in the transcript.
97 // We only want assistant text that comes AFTER this point — that's
98 // the wrap-up summary. Text before tool calls is Claude planning,
99 // analyzing, or describing what it's about to do (not what it did).
100 let last_tool_idx = entries.iter().rposition(|e: &CondensedEntry| e.is_tool())?; // If no tool calls, no useful summary
101
102 // Find the first assistant text entry AFTER the last tool call.
103 // Claude's wrap-up message typically comes right after the final tool use.
104 let wrap_up = entries[last_tool_idx + 1..]
105 .iter()
106 .find(|e: &&CondensedEntry| e.is_assistant() && e.content.is_some())?;
107
108 let text = wrap_up.content.as_deref()?;
109 let text = text.trim();
110
111 if text.is_empty() {
112 return None;
113 }
114
115 // Extract the first sentence. Claude's summaries often start with:
116 // "I've set up the project with TypeScript, Express, and tests."
117 // "The authentication bug has been fixed in login.rs."
118 // "Here's what I did:\n\n1. Created..."
119 //
120 // We want just that first sentence as a commit message.
121 let summary = extract_first_sentence(text);
122
123 // Skip if the extracted sentence is too short to be useful,
124 // or if it looks like a question/filler rather than a summary.
125 if summary.len() <= 10 {
126 return None;
127 }
128
129 Some(summary)
130}
131
132/// Extract the first sentence from a block of text.
133///

Calls 7

extract_first_sentenceFunction · 0.85
is_toolMethod · 0.80
is_assistantMethod · 0.80
is_emptyMethod · 0.45
iterMethod · 0.45
lenMethod · 0.45