From 18a7dc429a50540dfa30aef7b98e063054fb5205 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nicol=C3=B2=20Boschi?= Date: Fri, 28 Nov 2025 10:05:12 +0100 Subject: [PATCH] fix compile --- hindsight-cli/src/commands/explore.rs | 160 +++++++++++++++--- .../src/app/api/operations/[agentId]/route.ts | 8 +- .../src/app/api/stats/[agentId]/route.ts | 2 +- 3 files changed, 144 insertions(+), 26 deletions(-) diff --git a/hindsight-cli/src/commands/explore.rs b/hindsight-cli/src/commands/explore.rs index c4a4c6bf..eacf09f0 100644 --- a/hindsight-cli/src/commands/explore.rs +++ b/hindsight-cli/src/commands/explore.rs @@ -74,6 +74,7 @@ struct App { documents: Vec>, documents_state: ListState, + viewing_document: Option>, // Recall state recall_query: String, @@ -121,6 +122,7 @@ impl App { documents: Vec::new(), documents_state: ListState::default(), + viewing_document: None, recall_query: String::new(), recall_results: Vec::new(), @@ -459,12 +461,46 @@ impl App { } } } + View::Documents(bank_id) => { + if let Some(i) = self.documents_state.selected() { + if let Some(doc) = self.documents.get(i) { + // Fetch full document content + let doc_id = doc.get("id") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + if !doc_id.is_empty() { + match self.client.get_document(bank_id, doc_id, false) { + Ok(full_doc) => { + // Convert to Map for display + let doc_map: Map = serde_json::from_value( + serde_json::to_value(full_doc)? + )?; + self.viewing_document = Some(doc_map); + self.status_message = format!("Viewing document: {}", doc_id); + } + Err(e) => { + self.error_message = format!("Failed to load document: {}", e); + } + } + } + } + } + } _ => {} } Ok(()) } fn go_back(&mut self) { + // If viewing a document, close it first + if self.viewing_document.is_some() { + self.viewing_document = None; + self.status_message = "Closed document view".to_string(); + return; + } + + // Otherwise go back to previous view if let Some(prev_view) = self.view_history.pop() { self.view = prev_view; let _ = self.refresh(); @@ -479,6 +515,31 @@ impl App { } Ok(()) } + + fn delete_selected_document(&mut self) -> Result<()> { + if let View::Documents(bank_id) = &self.view { + if let Some(i) = self.documents_state.selected() { + if let Some(doc) = self.documents.get(i) { + let doc_id = doc.get("id") + .and_then(|v| v.as_str()) + .unwrap_or(""); + + if !doc_id.is_empty() { + match self.client.delete_document(bank_id, doc_id, false) { + Ok(_) => { + self.status_message = format!("Deleted document: {}", doc_id); + self.refresh()?; + } + Err(e) => { + self.error_message = format!("Failed to delete document: {}", e); + } + } + } + } + } + } + Ok(()) + } } fn ui(f: &mut Frame, app: &mut App) { @@ -779,31 +840,77 @@ fn render_entities(f: &mut Frame, app: &mut App, area: Rect) { } fn render_documents(f: &mut Frame, app: &mut App, area: Rect) { - let items: Vec = app - .documents - .iter() - .map(|doc| { - let id = doc.get("id") - .and_then(|v| v.as_str()) - .unwrap_or("unknown"); - let content_type = doc.get("content_type") - .and_then(|v| v.as_str()) - .unwrap_or("unknown"); - let content = format!("{} ({})", id, content_type); - ListItem::new(content).style(Style::default().fg(Color::White)) - }) - .collect(); + // If viewing a document, show its content + if let Some(doc) = &app.viewing_document { + let chunks = Layout::default() + .direction(Direction::Vertical) + .constraints([ + Constraint::Length(5), // Document metadata + Constraint::Min(0), // Content + ]) + .split(area); - let list = List::new(items) - .block(Block::default().borders(Borders::ALL).title("Documents")) - .highlight_style( - Style::default() - .bg(Color::DarkGray) - .add_modifier(Modifier::BOLD), - ) - .highlight_symbol(">> "); + // Metadata section + let doc_id = doc.get("id") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let content_type = doc.get("content_type") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let created_at = doc.get("created_at") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); - f.render_stateful_widget(list, area, &mut app.documents_state); + let metadata_text = format!( + "ID: {}\nType: {}\nCreated: {}\n", + doc_id, content_type, created_at + ); + + let metadata = Paragraph::new(metadata_text) + .block(Block::default().borders(Borders::ALL).title("Document Metadata")) + .style(Style::default().fg(Color::Cyan)); + + f.render_widget(metadata, chunks[0]); + + // Content section + let content = doc.get("content") + .and_then(|v| v.as_str()) + .unwrap_or("No content available"); + + let content_widget = Paragraph::new(content) + .block(Block::default().borders(Borders::ALL).title("Content (Esc to close)")) + .wrap(Wrap { trim: false }) + .style(Style::default().fg(Color::White)); + + f.render_widget(content_widget, chunks[1]); + } else { + // Show document list + let items: Vec = app + .documents + .iter() + .map(|doc| { + let id = doc.get("id") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let content_type = doc.get("content_type") + .and_then(|v| v.as_str()) + .unwrap_or("unknown"); + let content = format!("{} ({})", id, content_type); + ListItem::new(content).style(Style::default().fg(Color::White)) + }) + .collect(); + + let list = List::new(items) + .block(Block::default().borders(Borders::ALL).title("Documents")) + .highlight_style( + Style::default() + .bg(Color::DarkGray) + .add_modifier(Modifier::BOLD), + ) + .highlight_symbol(">> "); + + f.render_stateful_widget(list, area, &mut app.documents_state); + } } fn render_recall(f: &mut Frame, app: &mut App, area: Rect) { @@ -1010,6 +1117,13 @@ fn run_app(terminal: &mut Terminal, mut app: App) -> Result<()> { } } + // Delete document + KeyCode::Delete => { + if matches!(app.view, View::Documents(_)) { + app.delete_selected_document()?; + } + } + _ => {} } } diff --git a/hindsight-control-plane/src/app/api/operations/[agentId]/route.ts b/hindsight-control-plane/src/app/api/operations/[agentId]/route.ts index fec6b991..a3eab2a3 100644 --- a/hindsight-control-plane/src/app/api/operations/[agentId]/route.ts +++ b/hindsight-control-plane/src/app/api/operations/[agentId]/route.ts @@ -11,7 +11,9 @@ export async function GET( client: lowLevelClient, path: { bank_id: agentId } }); - return NextResponse.json(response.data, { status: 200 }); + // Ensure proper JSON serialization + const data = JSON.parse(JSON.stringify(response.data)); + return NextResponse.json(data, { status: 200 }); } catch (error) { console.error('Error fetching operations:', error); return NextResponse.json( @@ -42,7 +44,9 @@ export async function DELETE( path: { bank_id: agentId, operation_id: operationId } }); - return NextResponse.json(response.data, { status: 200 }); + // Ensure proper JSON serialization + const data = JSON.parse(JSON.stringify(response.data)); + return NextResponse.json(data, { status: 200 }); } catch (error) { console.error('Error canceling operation:', error); return NextResponse.json( diff --git a/hindsight-control-plane/src/app/api/stats/[agentId]/route.ts b/hindsight-control-plane/src/app/api/stats/[agentId]/route.ts index 6f4b34f1..a08f7cda 100644 --- a/hindsight-control-plane/src/app/api/stats/[agentId]/route.ts +++ b/hindsight-control-plane/src/app/api/stats/[agentId]/route.ts @@ -7,7 +7,7 @@ export async function GET( ) { try { const { agentId } = await params; - const response = await sdk.getBankStats({ + const response = await sdk.getAgentStats({ client: lowLevelClient, path: { bank_id: agentId } });