From 5754bdaa9886ad32c79cdbc0cf9de7cddb481cf8 Mon Sep 17 00:00:00 2001 From: NeilJo-GY <43027886+NeilJo-GY@users.noreply.github.com> Date: Wed, 14 Oct 2026 18:10:42 +0800 Subject: [PATCH 1/2] Show the agents in this chat on the interaction graph, and open it from the header. Co-authored-by: Cursor --- .../src/ranch-shell/InteractionPanel.tsx | 82 ++++++++++++++++--- .../src/ranch-shell/RanchChatShell.tsx | 45 +++++++++- 2 files changed, 113 insertions(+), 14 deletions(-) diff --git a/packages/agent-chat/src/ranch-shell/InteractionPanel.tsx b/packages/agent-chat/src/ranch-shell/InteractionPanel.tsx index 1fff493..718e106 100644 --- a/packages/agent-chat/src/ranch-shell/InteractionPanel.tsx +++ b/packages/agent-chat/src/ranch-shell/InteractionPanel.tsx @@ -44,11 +44,11 @@ function layout(ids: string[]): Record { const count = ids.length; ids.forEach((id, index) => { if (count === 1) { - out[id] = { x: 320, y: 150 }; + out[id] = { x: 180, y: 340 }; return; } const angle = -Math.PI / 2 + (2 * Math.PI * index) / count; - out[id] = { x: 320 + Math.cos(angle) * 190, y: 150 + Math.sin(angle) * 100 }; + out[id] = { x: 180 + Math.cos(angle) * 120, y: 340 + Math.sin(angle) * 150 }; }); return out; } @@ -57,7 +57,7 @@ function curve(from: { x: number; y: number }, to: { x: number; y: number }, ben const dx = to.x - from.x; const dy = to.y - from.y; const len = Math.hypot(dx, dy) || 1; - const pad = 28; + const pad = 36; const sx = from.x + (dx / len) * pad; const sy = from.y + (dy / len) * pad; const ex = to.x - (dx / len) * pad; @@ -81,12 +81,36 @@ export function InteractionPanel({ const [selectedKey, setSelectedKey] = useState(null); const members = new Set(memberIds.map((id) => bare(id).toLowerCase())); const ids: string[] = []; + const addId = (id: string) => { + const trimmed = id.trim(); + const key = bare(trimmed).toLowerCase(); + if (!key || key.startsWith("system:") || key.startsWith("local:")) return; + if (ids.some((have) => bare(have).toLowerCase() === key)) return; + ids.push(trimmed); + }; + for (const id of memberIds) addId(id); for (const hop of hops) { - if (!ids.includes(hop.fromId)) ids.push(hop.fromId); - if (!ids.includes(hop.toId)) ids.push(hop.toId); + addId(hop.fromId); + addId(hop.toId); } const pos = layout(ids); const selected = hops.find((hop) => hop.key === selectedKey) ?? null; + const present = ids.filter((id) => members.has(bare(id).toLowerCase())); + const quietPairs: Array<[string, string]> = []; + for (let i = 0; i < present.length; i++) { + for (let j = i + 1; j < present.length; j++) { + const from = present[i]; + const to = present[j]; + const called = hops.some((hop) => { + const a = bare(hop.fromId).toLowerCase(); + const b = bare(hop.toId).toLowerCase(); + const left = bare(from).toLowerCase(); + const right = bare(to).toLowerCase(); + return (a === left && b === right) || (a === right && b === left); + }); + if (!called) quietPairs.push([from, to]); + } + } const viewLabel = (

@@ -94,7 +118,7 @@ export function InteractionPanel({

); - if (!hops.length) { + if (!ids.length) { return (
{viewLabel} @@ -106,9 +130,25 @@ export function InteractionPanel({ } return ( -
+
{viewLabel} - + + {quietPairs.map(([fromId, toId]) => { + const from = pos[fromId]; + const to = pos[toId]; + if (!from || !to) return null; + return ( + ${toId}`} + data-relation="" + d={curve(from, to, 0)} + fill="none" + stroke={colors.muted} + strokeOpacity={0.45} + strokeWidth="1.4" + /> + ); + })} {hops.map((hop, index) => { const from = pos[hop.fromId]; const to = pos[hop.toId]; @@ -146,6 +186,10 @@ export function InteractionPanel({ ); })} + + + + {(["in_flight", "completed", "failed"] as const).map((phase) => ( @@ -157,22 +201,34 @@ export function InteractionPanel({ const inside = members.has(bare(id).toLowerCase()); const hop = hops.find((item) => item.toId === id); const label = displayName(id, names, hop?.name); + const initial = label.trim().slice(0, 1).toUpperCase() || "?"; return ( - + + {initial} + + {label} {inside ? null : ( - + {copy.outside} )} diff --git a/packages/agent-chat/src/ranch-shell/RanchChatShell.tsx b/packages/agent-chat/src/ranch-shell/RanchChatShell.tsx index c5cfdb9..f4a3b13 100644 --- a/packages/agent-chat/src/ranch-shell/RanchChatShell.tsx +++ b/packages/agent-chat/src/ranch-shell/RanchChatShell.tsx @@ -2155,6 +2155,23 @@ function IconBody() { ); } +/** Three agents linked. Opens the Interaction window. */ +function IconInteraction() { + return ( + + + + + + + ); +} + function IconHistory() { return ( @@ -5749,7 +5766,16 @@ export function RanchChatShell(props: RanchChatShellProps) { ) : activeDock.kind === "interaction" ? ( agentIdKey(id) === agentIdKey(active.agent_id))?.[1]?.trim() || + chatTitle(active), + } + : {}), + }} memberIds={active?.agent_id ? [active.agent_id, ...Object.keys(agentNames)] : Object.keys(agentNames)} copy={{ view: t.interactionView, @@ -6803,6 +6829,23 @@ export function RanchChatShell(props: RanchChatShellProps) { ) : null} +