session-log-segments実装

This commit is contained in:
2026-04-29 22:42:10 +09:00
parent 8a9e3b4fe3
commit e3b36371e9
14 changed files with 310 additions and 65 deletions
+17 -3
View File
@@ -452,10 +452,24 @@ impl App {
self.blocks.push(Block::TurnHeader {
turn: self.turn_index,
});
if !text.is_empty() {
self.blocks.push(Block::UserMessage {
segments: vec![Segment::text(text)],
// Pod attaches the original `Vec<Segment>` to
// user messages from live submissions, so we
// can rebuild typed atoms (paste chips, refs)
// here. Seed history loaded post-compaction
// has no `segments` field — fall back to a
// single text segment.
let segments = item
.get("segments")
.and_then(|v| serde_json::from_value::<Vec<Segment>>(v.clone()).ok())
.unwrap_or_else(|| {
if text.is_empty() {
Vec::new()
} else {
vec![Segment::text(text.clone())]
}
});
if !segments.is_empty() {
self.blocks.push(Block::UserMessage { segments });
}
}
"assistant" if !text.is_empty() => {
+4 -14
View File
@@ -21,8 +21,7 @@ use ratatui::widgets::Paragraph;
use ratatui::{Frame, TerminalOptions, Viewport};
use pod_registry::lookup_session;
use session_store::{
ContentPart, FsStore, HashedEntry, Item, LogEntry, LoggedContentPart, LoggedItem, SessionId,
Store,
FsStore, HashedEntry, LogEntry, LoggedContentPart, LoggedItem, SessionId, Store,
};
const MAX_ROWS: usize = 10;
@@ -176,8 +175,9 @@ async fn build_preview(store: &FsStore, id: SessionId) -> String {
fn last_message_preview(entries: &[HashedEntry]) -> Option<String> {
for hashed in entries.iter().rev() {
match &hashed.entry {
LogEntry::UserInput { item, .. } => {
if let Some(text) = first_text(item) {
LogEntry::UserInput { segments, .. } => {
let text = protocol::Segment::flatten_to_text(segments);
if !text.is_empty() {
return Some(format!("user: {}", trim_one_line(&text, 60)));
}
}
@@ -192,16 +192,6 @@ fn last_message_preview(entries: &[HashedEntry]) -> Option<String> {
None
}
fn first_text(item: &Item) -> Option<String> {
match item {
Item::Message { content, .. } => content.iter().find_map(|p| match p {
ContentPart::Text { text } => Some(text.clone()),
_ => None,
}),
_ => None,
}
}
fn first_text_logged(item: &LoggedItem) -> Option<String> {
match item {
LoggedItem::Message { content, .. } => content.iter().find_map(|p| match p {