Scope branch listings to a divergence point via node_id
ForkInfo now carries the divergence node's id, and the branches endpoint accepts node_id + viewing_branch_id to return only the position-ranked sibling branches at that fork (snippets taken from after the divergence, skipping tool scaffolding) instead of every leaf in the tree. Options in the same subtree as the viewing leaf anchor to that leaf so clients can reliably identify "the branch I'm on". Tree-wide listing is unchanged when node_id is absent. - llm_client: descendant_leaves + branch_options_at helpers; optional position rank on BranchLeafInfo. - insight_chat: ForkInfo.node_id set during render_tree_path; get_branches takes the scoping params. - handlers: dedicated ChatBranchesQuery; unknown node_id maps to 400. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
+36
-5
@@ -717,12 +717,20 @@ impl InsightChatService {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Return branch leaf metadata (id, snippet, message_count) and the
|
||||
/// active leaf ID for a photo's conversation tree.
|
||||
/// Return branch metadata and the active leaf ID for a photo's
|
||||
/// conversation tree.
|
||||
///
|
||||
/// With `node_id = None` this lists every leaf in the tree. With
|
||||
/// `node_id = Some(fork)` (from `ForkInfo.node_id`) it lists only the
|
||||
/// sibling branches diverging at that node, position-ranked; options in
|
||||
/// the same subtree as `viewing_leaf` anchor to that leaf so the client
|
||||
/// can recognise "the branch I'm on".
|
||||
pub fn get_branches(
|
||||
&self,
|
||||
library_id: i32,
|
||||
file_path: &str,
|
||||
node_id: Option<u64>,
|
||||
viewing_leaf: Option<u64>,
|
||||
) -> Result<(Vec<BranchLeafInfo>, u64)> {
|
||||
let normalized = normalize_path(file_path);
|
||||
let cx = opentelemetry::Context::new();
|
||||
@@ -745,7 +753,16 @@ impl InsightChatService {
|
||||
.map_err(|e| anyhow!("failed to deserialize chat history: {}", e))?
|
||||
};
|
||||
|
||||
Ok((store.leaves_with_info(), store.active_leaf_id))
|
||||
let list = match node_id {
|
||||
Some(fork_node) => {
|
||||
if !store.nodes.iter().any(|n| n.id == fork_node) {
|
||||
bail!("node_id {} not found in tree", fork_node);
|
||||
}
|
||||
store.branch_options_at(fork_node, viewing_leaf.unwrap_or(store.active_leaf_id))
|
||||
}
|
||||
None => store.leaves_with_info(),
|
||||
};
|
||||
Ok((list, store.active_leaf_id))
|
||||
}
|
||||
|
||||
/// Streaming variant of `chat_turn`. Emits user-facing events as the
|
||||
@@ -2465,6 +2482,10 @@ pub(crate) fn restore_system_prompt_override(
|
||||
pub struct ForkInfo {
|
||||
pub position: usize,
|
||||
pub total: usize,
|
||||
/// The divergence node itself (the parent whose children fork). Pass as
|
||||
/// `node_id` to the branches endpoint to list the sibling branches at
|
||||
/// this exact point rather than every leaf in the tree.
|
||||
pub node_id: u64,
|
||||
}
|
||||
|
||||
/// Render a path of tree nodes into the UI-friendly `RenderedMessage` format,
|
||||
@@ -2498,8 +2519,16 @@ fn render_tree_path(
|
||||
// Update the carried fork BEFORE rendering: a non-rendered fork child
|
||||
// (e.g. a tool-dispatch assistant) must colour the rendered message
|
||||
// that follows it.
|
||||
if let Some((position, total)) = store.fork_at_node(node.id) {
|
||||
last_fork = Some(ForkInfo { position, total });
|
||||
// (fork_at_node only fires for nodes with a parent, so the pair
|
||||
// pattern below can't drop a real fork.)
|
||||
if let (Some(node_id), Some((position, total))) =
|
||||
(node.parent_id, store.fork_at_node(node.id))
|
||||
{
|
||||
last_fork = Some(ForkInfo {
|
||||
position,
|
||||
total,
|
||||
node_id,
|
||||
});
|
||||
}
|
||||
let msg = &node.message;
|
||||
match msg.role.as_str() {
|
||||
@@ -2839,6 +2868,7 @@ mod tests {
|
||||
.as_ref()
|
||||
.expect("fork indicator carried onto the rendered reply");
|
||||
assert_eq!((f.position, f.total), (2, 2));
|
||||
assert_eq!(f.node_id, u, "divergence node is the forked user turn");
|
||||
}
|
||||
|
||||
#[test]
|
||||
@@ -2859,6 +2889,7 @@ mod tests {
|
||||
.as_ref()
|
||||
.expect("fork indicator on the divergent rendered reply");
|
||||
assert_eq!((f.position, f.total), (2, 2));
|
||||
assert_eq!(f.node_id, u, "divergence node is the forked user turn");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in New Issue
Block a user