agentfootprint-lens 0.9.0 → 0.11.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,7 +1,7 @@
1
1
  import {
2
2
  deriveStages,
3
3
  fromAgentSnapshot
4
- } from "./chunk-R4XZ5FX5.js";
4
+ } from "./chunk-NVS4VYQV.js";
5
5
 
6
6
  // src/react/Lens.tsx
7
7
  import { useEffect as useEffect5, useReducer, useState as useState7 } from "react";
@@ -1793,17 +1793,50 @@ import { Fragment as Fragment3, jsx as jsx3, jsxs as jsxs3 } from "react/jsx-run
1793
1793
  var NODE_POSITIONS = {
1794
1794
  user: { x: 100, y: 20 },
1795
1795
  agent: { x: 100, y: 120 },
1796
- tool: { x: 100, y: 360 },
1797
- skill: { x: 320, y: 360 }
1796
+ tool: { x: 100, y: 310 }
1798
1797
  };
1799
1798
  var CONTEXT_NODE_POSITION = { x: 325, y: 120 };
1800
1799
  var TOOLS_NODE_POSITION = { x: -150, y: 120 };
1801
- var AGENT_CONTAINER_BOX = {
1802
- x: -166,
1803
- y: 84,
1804
- width: 707,
1805
- height: 362
1800
+ var SUBAGENT_BOX_WIDTH = 280;
1801
+ var SUBAGENT_BOX_HEIGHT = 90;
1802
+ var SUBAGENT_GAP = 30;
1803
+ var SUBAGENT_X = 100;
1804
+ var SUBAGENT_Y_START = 120;
1805
+ var NODE_SIZES = {
1806
+ user: { width: 150, height: 70 },
1807
+ agent: { width: 200, height: 190 },
1808
+ tool: { width: 150, height: 70 },
1809
+ context: { width: 200, height: 200 },
1810
+ toolsList: { width: 130, height: 200 }
1806
1811
  };
1812
+ function computeAgentContainerBox({
1813
+ showTool,
1814
+ showContext,
1815
+ showTools
1816
+ }) {
1817
+ const PADDING = 16;
1818
+ const HEADER_ROOM = 22;
1819
+ const anyAgentSurface = showTool || showContext || showTools;
1820
+ let xMin;
1821
+ let xMax;
1822
+ if (anyAgentSurface) {
1823
+ xMin = TOOLS_NODE_POSITION.x;
1824
+ xMax = CONTEXT_NODE_POSITION.x + NODE_SIZES.context.width;
1825
+ } else {
1826
+ xMin = NODE_POSITIONS.agent.x;
1827
+ xMax = NODE_POSITIONS.agent.x + NODE_SIZES.agent.width;
1828
+ }
1829
+ const yMin = NODE_POSITIONS.agent.y - HEADER_ROOM;
1830
+ const llmBottom = NODE_POSITIONS.agent.y + NODE_SIZES.agent.height;
1831
+ const toolBottom = showTool ? NODE_POSITIONS.tool.y + NODE_SIZES.tool.height : 0;
1832
+ const yMax = Math.max(llmBottom, toolBottom);
1833
+ return {
1834
+ x: xMin - PADDING,
1835
+ y: yMin - PADDING / 2,
1836
+ width: xMax - xMin + PADDING * 2,
1837
+ height: yMax - yMin + PADDING * 2
1838
+ };
1839
+ }
1807
1840
  function pickHandles(from, to) {
1808
1841
  if (from === "user" && to === "agent") return { sourceHandle: "b-out", targetHandle: "t-in" };
1809
1842
  if (from === "agent" && to === "user") return { sourceHandle: "t-out", targetHandle: "b-in" };
@@ -1874,6 +1907,33 @@ function StageFlow({
1874
1907
  return s;
1875
1908
  }, [activeStage]);
1876
1909
  const edges = useMemo(() => {
1910
+ const subs = timeline?.subAgents ?? [];
1911
+ if (subs.length > 0) {
1912
+ const out = [];
1913
+ out.push({
1914
+ id: `user\u2192subagent-${subs[0].id}`,
1915
+ source: "user",
1916
+ target: `subagent-${subs[0].id}`,
1917
+ type: "labelled",
1918
+ sourceHandle: "b-out",
1919
+ targetHandle: "t-in",
1920
+ data: { primitive: "message", active: false, isLoop: false, stage: void 0 }
1921
+ });
1922
+ for (let i = 0; i < subs.length - 1; i++) {
1923
+ const a = subs[i];
1924
+ const b = subs[i + 1];
1925
+ out.push({
1926
+ id: `subagent-${a.id}\u2192subagent-${b.id}`,
1927
+ source: `subagent-${a.id}`,
1928
+ target: `subagent-${b.id}`,
1929
+ type: "labelled",
1930
+ sourceHandle: "b-out",
1931
+ targetHandle: "t-in",
1932
+ data: { primitive: "message", active: false, isLoop: false, stage: void 0 }
1933
+ });
1934
+ }
1935
+ return out;
1936
+ }
1877
1937
  const byKey = /* @__PURE__ */ new Map();
1878
1938
  visible.forEach((s) => {
1879
1939
  byKey.set(`${s.from}\u2192${s.to}`, { from: s.from, to: s.to, lastStage: s });
@@ -1899,7 +1959,7 @@ function StageFlow({
1899
1959
  }
1900
1960
  };
1901
1961
  });
1902
- }, [visible, activeStage]);
1962
+ }, [visible, activeStage, timeline]);
1903
1963
  const toolsRoster = useMemo(() => {
1904
1964
  if (!timeline || !activeStage || activeStage.iterIndex === void 0) return null;
1905
1965
  const turn = timeline.turns[activeStage.turnIndex];
@@ -1949,25 +2009,73 @@ function StageFlow({
1949
2009
  }
1950
2010
  return [...bySource.values()];
1951
2011
  }, [activeInjectionsBySlot]);
2012
+ const isAgentRun = touched.has("tool") || contextSummary.length > 0 || toolsRoster !== null;
2013
+ const subAgents = timeline?.subAgents ?? [];
2014
+ const isMultiAgent = subAgents.length > 0;
1952
2015
  const nodes = useMemo(() => {
1953
- const containerNode = {
2016
+ if (isMultiAgent) {
2017
+ const userNode = {
2018
+ id: "user",
2019
+ type: "lens",
2020
+ position: NODE_POSITIONS.user,
2021
+ data: {
2022
+ id: "user",
2023
+ active: false,
2024
+ touched: true
2025
+ },
2026
+ draggable: false
2027
+ };
2028
+ const subAgentNodes = subAgents.map((sa, i) => {
2029
+ const turnCount = sa.turns.length;
2030
+ const iterCount = sa.turns.reduce((acc, t2) => acc + t2.iterations.length, 0);
2031
+ const toolCount = sa.tools.length;
2032
+ return {
2033
+ id: `subagent-${sa.id}`,
2034
+ type: "subagent",
2035
+ position: {
2036
+ x: SUBAGENT_X,
2037
+ y: SUBAGENT_Y_START + i * (SUBAGENT_BOX_HEIGHT + SUBAGENT_GAP)
2038
+ },
2039
+ data: {
2040
+ id: sa.id,
2041
+ name: sa.name,
2042
+ turnCount,
2043
+ iterCount,
2044
+ toolCount,
2045
+ // Active when the LAST turn of the LAST sub-agent matches
2046
+ // the focused stage's owner — primitive heuristic until
2047
+ // deriveStages tags stages with sub-agent. For MVP, the
2048
+ // sub-agent at the end of the chain is the "currently
2049
+ // running" one.
2050
+ active: i === subAgents.length - 1
2051
+ },
2052
+ draggable: false
2053
+ };
2054
+ });
2055
+ return [userNode, ...subAgentNodes];
2056
+ }
2057
+ const containerBox = computeAgentContainerBox({
2058
+ showTool: touched.has("tool"),
2059
+ showContext: contextSummary.length > 0,
2060
+ showTools: toolsRoster !== null
2061
+ });
2062
+ const containerNode = isAgentRun ? {
1954
2063
  id: "agent-container",
1955
2064
  type: "agent-container",
1956
- position: { x: AGENT_CONTAINER_BOX.x, y: AGENT_CONTAINER_BOX.y },
2065
+ position: { x: containerBox.x, y: containerBox.y },
1957
2066
  data: {
1958
2067
  agentName,
1959
- width: AGENT_CONTAINER_BOX.width,
1960
- height: AGENT_CONTAINER_BOX.height
2068
+ width: containerBox.width,
2069
+ height: containerBox.height
1961
2070
  },
1962
2071
  draggable: false,
1963
2072
  selectable: false,
1964
- // ReactFlow renders nodes in array order; the first node is at
1965
- // the back. zIndex on the wrapper div is also lowered for safety
1966
- // in case ReactFlow's render order differs across versions.
2073
+ // ReactFlow renders nodes in array order; first node is at
2074
+ // the back. zIndex -1 is belt-and-suspenders.
1967
2075
  zIndex: -1
1968
- };
2076
+ } : null;
1969
2077
  const base = Object.keys(NODE_POSITIONS).filter((id) => {
1970
- if (id === "skill") return touched.has("skill");
2078
+ if (id === "tool") return touched.has("tool");
1971
2079
  return true;
1972
2080
  }).map((id) => ({
1973
2081
  id,
@@ -2014,8 +2122,11 @@ function StageFlow({
2014
2122
  draggable: false
2015
2123
  });
2016
2124
  }
2017
- return [containerNode, ...base];
2125
+ return containerNode ? [containerNode, ...base] : base;
2018
2126
  }, [
2127
+ isAgentRun,
2128
+ isMultiAgent,
2129
+ subAgents,
2019
2130
  activeNodes,
2020
2131
  touched,
2021
2132
  activeStage,
@@ -2031,7 +2142,8 @@ function StageFlow({
2031
2142
  lens: LensNode,
2032
2143
  context: ContextNode,
2033
2144
  "tools-list": ToolsListNode,
2034
- "agent-container": AgentContainerNode
2145
+ "agent-container": AgentContainerNode,
2146
+ subagent: SubAgentNode
2035
2147
  }),
2036
2148
  []
2037
2149
  );
@@ -2361,6 +2473,98 @@ function AgentContainerNode({ data }) {
2361
2473
  }
2362
2474
  );
2363
2475
  }
2476
+ function SubAgentNode({ data }) {
2477
+ const t = useLensTheme();
2478
+ const d = data;
2479
+ const accent = d.active ? t.accent : t.border;
2480
+ return /* @__PURE__ */ jsxs3(
2481
+ "div",
2482
+ {
2483
+ style: {
2484
+ width: SUBAGENT_BOX_WIDTH,
2485
+ height: SUBAGENT_BOX_HEIGHT,
2486
+ position: "relative",
2487
+ padding: "12px 14px",
2488
+ borderRadius: 12,
2489
+ background: d.active ? `color-mix(in srgb, ${t.accent} 12%, ${t.bgElev})` : t.bgElev,
2490
+ border: `1.5px dashed ${accent}`,
2491
+ color: t.text,
2492
+ fontFamily: t.fontSans,
2493
+ boxShadow: d.active ? `0 0 16px color-mix(in srgb, ${t.accent} 30%, transparent)` : `0 1px 3px rgba(0,0,0,0.12)`,
2494
+ transition: "background 220ms ease, border-color 220ms ease, box-shadow 220ms ease"
2495
+ },
2496
+ children: [
2497
+ /* @__PURE__ */ jsxs3(
2498
+ "div",
2499
+ {
2500
+ style: {
2501
+ position: "absolute",
2502
+ top: -10,
2503
+ left: 14,
2504
+ padding: "1px 10px",
2505
+ background: t.bg,
2506
+ color: t.textMuted,
2507
+ fontSize: 9,
2508
+ fontWeight: 600,
2509
+ textTransform: "uppercase",
2510
+ letterSpacing: "0.08em",
2511
+ whiteSpace: "nowrap"
2512
+ },
2513
+ children: [
2514
+ "Agent \xB7 ",
2515
+ /* @__PURE__ */ jsx3("span", { style: { color: t.text, fontFamily: t.fontMono }, children: d.name })
2516
+ ]
2517
+ }
2518
+ ),
2519
+ /* @__PURE__ */ jsxs3(
2520
+ "div",
2521
+ {
2522
+ style: {
2523
+ display: "flex",
2524
+ alignItems: "center",
2525
+ gap: 10,
2526
+ marginTop: 4
2527
+ },
2528
+ children: [
2529
+ /* @__PURE__ */ jsx3(NodeIcon, { id: "agent", color: d.active ? t.accent : t.text }),
2530
+ /* @__PURE__ */ jsxs3("div", { style: { display: "flex", flexDirection: "column" }, children: [
2531
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: 14, fontWeight: 600, color: t.text }, children: "LLM" }),
2532
+ /* @__PURE__ */ jsx3("span", { style: { fontSize: 10, color: t.textSubtle }, children: "The API call" })
2533
+ ] })
2534
+ ]
2535
+ }
2536
+ ),
2537
+ /* @__PURE__ */ jsxs3(
2538
+ "div",
2539
+ {
2540
+ style: {
2541
+ display: "flex",
2542
+ gap: 12,
2543
+ marginTop: 8,
2544
+ fontSize: 10,
2545
+ color: t.textMuted,
2546
+ fontFamily: t.fontMono
2547
+ },
2548
+ children: [
2549
+ /* @__PURE__ */ jsxs3("span", { children: [
2550
+ /* @__PURE__ */ jsx3("strong", { style: { color: t.text }, children: d.iterCount }),
2551
+ " iter",
2552
+ d.iterCount === 1 ? "" : "s"
2553
+ ] }),
2554
+ /* @__PURE__ */ jsxs3("span", { children: [
2555
+ /* @__PURE__ */ jsx3("strong", { style: { color: t.text }, children: d.toolCount }),
2556
+ " tool",
2557
+ d.toolCount === 1 ? "" : "s"
2558
+ ] })
2559
+ ]
2560
+ }
2561
+ ),
2562
+ /* @__PURE__ */ jsx3(Handle, { type: "target", position: Position.Top, id: "t-in", style: HANDLE_STYLE }),
2563
+ /* @__PURE__ */ jsx3(Handle, { type: "source", position: Position.Bottom, id: "b-out", style: HANDLE_STYLE })
2564
+ ]
2565
+ }
2566
+ );
2567
+ }
2364
2568
  function ContextNode({ data }) {
2365
2569
  const t = useLensTheme();
2366
2570
  const d = data;
@@ -2964,11 +3168,14 @@ function AskCard({ timeline, focusIndex, stages }) {
2964
3168
  const currentTurn = currentStage !== void 0 ? timeline.turns[currentStage.turnIndex] : timeline.turns[0];
2965
3169
  const currentIter = currentStage?.iterIndex !== void 0 ? currentTurn?.iterations.find((it) => it.index === currentStage.iterIndex) : void 0;
2966
3170
  const currentTool = currentStage?.toolName && currentIter ? currentIter.toolCalls.find((tc) => tc.name === currentStage.toolName) : void 0;
2967
- return /* @__PURE__ */ jsxs5(
3171
+ return /* @__PURE__ */ jsx5(
2968
3172
  "div",
2969
3173
  {
2970
3174
  "data-fp-lens": "ask-card",
2971
3175
  style: {
3176
+ // Match the StageFlow's height (parent grid cell sets the
3177
+ // height; we fill it). Internal sections handle their own
3178
+ // scroll so the card itself never exceeds the cell.
2972
3179
  display: "flex",
2973
3180
  flexDirection: "column",
2974
3181
  gap: 12,
@@ -2976,133 +3183,136 @@ function AskCard({ timeline, focusIndex, stages }) {
2976
3183
  background: t.bg,
2977
3184
  fontFamily: t.fontSans,
2978
3185
  color: t.text,
2979
- overflow: "auto"
3186
+ // `100%` + `minHeight: 0` lets nested flex children (the
3187
+ // markdown blob in Agent Reasoning, etc.) decide their own
3188
+ // overflow behavior without forcing the whole card to grow.
3189
+ height: "100%",
3190
+ minHeight: 0,
3191
+ overflow: "hidden"
2980
3192
  },
2981
- children: [
2982
- /* @__PURE__ */ jsxs5("section", { children: [
2983
- /* @__PURE__ */ jsx5(Label3, { t, children: "Your question" }),
2984
- /* @__PURE__ */ jsx5(
2985
- "div",
2986
- {
2987
- style: {
2988
- marginTop: 4,
2989
- padding: "10px 12px",
2990
- background: `color-mix(in srgb, ${t.accent} 12%, ${t.bgElev})`,
2991
- border: `1px solid ${t.border}`,
2992
- borderRadius: 6,
2993
- fontSize: 13,
2994
- lineHeight: 1.5
2995
- },
2996
- children: currentTurn?.userPrompt ?? "No question yet."
2997
- }
2998
- )
2999
- ] }),
3000
- currentStage && /* @__PURE__ */ jsxs5("section", { children: [
3001
- /* @__PURE__ */ jsxs5(Label3, { t, children: [
3002
- "Step ",
3003
- focusIndex + 1,
3004
- " / ",
3005
- stages.length
3006
- ] }),
3007
- !(currentTool && currentStage.from === "tool") && /* @__PURE__ */ jsx5("div", { style: { marginTop: 4, fontSize: 13, color: t.text, lineHeight: 1.5 }, children: currentStage.label }),
3008
- /* @__PURE__ */ jsxs5(
3009
- "div",
3010
- {
3011
- style: {
3012
- marginTop: 8,
3013
- display: "flex",
3014
- gap: 6,
3015
- flexWrap: "wrap",
3016
- fontSize: 10,
3017
- color: t.textSubtle
3018
- },
3019
- children: [
3020
- /* @__PURE__ */ jsx5(Pill, { t, children: primitivePill(currentStage) }),
3021
- /* @__PURE__ */ jsxs5(Pill, { t, children: [
3022
- friendlyNode(currentStage.from),
3023
- " \u2192 ",
3024
- friendlyNode(currentStage.to)
3025
- ] }),
3026
- currentStage.toolName && /* @__PURE__ */ jsx5(Pill, { t, children: currentStage.toolName })
3027
- ]
3028
- }
3029
- )
3030
- ] }),
3031
- (() => {
3032
- const iterInjections = currentIter?.contextInjections ?? [];
3033
- if (iterInjections.length > 0) {
3034
- return /* @__PURE__ */ jsxs5("section", { children: [
3035
- /* @__PURE__ */ jsx5(Label3, { t, children: "Context injected" }),
3036
- /* @__PURE__ */ jsx5(InjectionTags, { injections: iterInjections, t })
3037
- ] });
3038
- }
3039
- const turnInjections = currentTurn?.contextInjections ?? [];
3040
- if (turnInjections.length === 0) return null;
3041
- return /* @__PURE__ */ jsxs5("section", { children: [
3042
- /* @__PURE__ */ jsx5(Label3, { t, children: "Context engineered this turn" }),
3043
- /* @__PURE__ */ jsx5(InjectionTags, { injections: turnInjections, t, dedupeBySource: true })
3044
- ] });
3045
- })(),
3046
- currentStage?.from === "agent" && currentIter?.assistantContent && /* @__PURE__ */ jsxs5("section", { children: [
3047
- /* @__PURE__ */ jsx5(Label3, { t, children: "Agent reasoning" }),
3048
- /* @__PURE__ */ jsx5(
3049
- "div",
3050
- {
3051
- style: {
3052
- marginTop: 4,
3053
- padding: "10px 12px",
3054
- background: t.bgElev,
3055
- border: `1px solid ${t.border}`,
3056
- borderLeft: `3px solid ${t.accent}`,
3057
- borderRadius: 6,
3058
- fontSize: 12,
3059
- lineHeight: 1.55,
3060
- whiteSpace: "pre-wrap",
3061
- maxHeight: 220,
3062
- overflow: "auto"
3063
- },
3064
- children: currentIter.assistantContent
3065
- }
3066
- )
3067
- ] }),
3068
- currentTool && /* @__PURE__ */ jsxs5("section", { children: [
3069
- /* @__PURE__ */ jsx5(Label3, { t, children: currentStage?.to === "tool" ? "Arguments" : "Tool returned" }),
3070
- /* @__PURE__ */ jsx5(
3071
- "pre",
3072
- {
3073
- style: {
3074
- marginTop: 4,
3075
- padding: "8px 10px",
3076
- background: t.bgElev,
3077
- border: `1px solid ${t.border}`,
3078
- borderRadius: 6,
3079
- fontSize: 11,
3080
- fontFamily: t.fontMono,
3081
- color: currentTool.error ? t.error : t.text,
3082
- whiteSpace: "pre-wrap",
3083
- maxHeight: 180,
3084
- overflow: "auto",
3085
- margin: 0
3086
- },
3087
- children: currentStage?.to === "tool" ? JSON.stringify(currentTool.arguments, null, 2) : currentTool.result
3088
- }
3089
- )
3090
- ] }),
3091
- timeline.turns.length > 1 && /* @__PURE__ */ jsxs5("section", { children: [
3092
- /* @__PURE__ */ jsx5(Label3, { t, children: "Conversation" }),
3093
- /* @__PURE__ */ jsxs5("div", { style: { marginTop: 4, fontSize: 12, color: t.textMuted, lineHeight: 1.5 }, children: [
3094
- timeline.turns.length,
3095
- " question",
3096
- timeline.turns.length === 1 ? "" : "s",
3097
- " so far \xB7",
3098
- " ",
3099
- timeline.tools.length,
3100
- " tool call",
3101
- timeline.tools.length === 1 ? "" : "s",
3102
- " total"
3103
- ] })
3104
- ] })
3105
- ]
3193
+ children: /* @__PURE__ */ jsxs5(
3194
+ "div",
3195
+ {
3196
+ style: {
3197
+ display: "flex",
3198
+ flexDirection: "column",
3199
+ gap: 12,
3200
+ flex: "1 1 0",
3201
+ minHeight: 0,
3202
+ overflow: "auto",
3203
+ // Narrow scrollbar so it doesn't steal width from content.
3204
+ scrollbarWidth: "thin",
3205
+ scrollbarGutter: "stable"
3206
+ },
3207
+ children: [
3208
+ currentStage && /* @__PURE__ */ jsxs5("section", { children: [
3209
+ /* @__PURE__ */ jsxs5(Label3, { t, children: [
3210
+ "Step ",
3211
+ focusIndex + 1,
3212
+ " / ",
3213
+ stages.length
3214
+ ] }),
3215
+ !(currentTool && currentStage.from === "tool") && /* @__PURE__ */ jsx5("div", { style: { marginTop: 4, fontSize: 13, color: t.text, lineHeight: 1.5 }, children: currentStage.label }),
3216
+ /* @__PURE__ */ jsxs5(
3217
+ "div",
3218
+ {
3219
+ style: {
3220
+ marginTop: 8,
3221
+ display: "flex",
3222
+ gap: 6,
3223
+ flexWrap: "wrap",
3224
+ fontSize: 10,
3225
+ color: t.textSubtle
3226
+ },
3227
+ children: [
3228
+ /* @__PURE__ */ jsx5(Pill, { t, children: primitivePill(currentStage) }),
3229
+ /* @__PURE__ */ jsxs5(Pill, { t, children: [
3230
+ friendlyNode(currentStage.from),
3231
+ " \u2192 ",
3232
+ friendlyNode(currentStage.to)
3233
+ ] }),
3234
+ currentStage.toolName && /* @__PURE__ */ jsx5(Pill, { t, children: currentStage.toolName })
3235
+ ]
3236
+ }
3237
+ )
3238
+ ] }),
3239
+ (() => {
3240
+ const iterInjections = currentIter?.contextInjections ?? [];
3241
+ if (iterInjections.length > 0) {
3242
+ return /* @__PURE__ */ jsxs5("section", { children: [
3243
+ /* @__PURE__ */ jsx5(Label3, { t, children: "Context injected" }),
3244
+ /* @__PURE__ */ jsx5(InjectionTags, { injections: iterInjections, t })
3245
+ ] });
3246
+ }
3247
+ const turnInjections = currentTurn?.contextInjections ?? [];
3248
+ if (turnInjections.length === 0) return null;
3249
+ return /* @__PURE__ */ jsxs5("section", { children: [
3250
+ /* @__PURE__ */ jsx5(Label3, { t, children: "Context engineered this turn" }),
3251
+ /* @__PURE__ */ jsx5(InjectionTags, { injections: turnInjections, t, dedupeBySource: true })
3252
+ ] });
3253
+ })(),
3254
+ currentStage?.from === "agent" && currentIter?.assistantContent && /* @__PURE__ */ jsxs5("section", { children: [
3255
+ /* @__PURE__ */ jsx5(Label3, { t, children: "Agent reasoning" }),
3256
+ /* @__PURE__ */ jsx5(
3257
+ "div",
3258
+ {
3259
+ style: {
3260
+ marginTop: 4,
3261
+ padding: "10px 12px",
3262
+ background: t.bgElev,
3263
+ border: `1px solid ${t.border}`,
3264
+ borderLeft: `3px solid ${t.accent}`,
3265
+ borderRadius: 6,
3266
+ fontSize: 12,
3267
+ lineHeight: 1.55,
3268
+ whiteSpace: "pre-wrap",
3269
+ maxHeight: 220,
3270
+ overflow: "auto"
3271
+ },
3272
+ children: currentIter.assistantContent
3273
+ }
3274
+ )
3275
+ ] }),
3276
+ currentTool && /* @__PURE__ */ jsxs5("section", { children: [
3277
+ /* @__PURE__ */ jsx5(Label3, { t, children: currentStage?.to === "tool" ? "Arguments" : "Tool returned" }),
3278
+ /* @__PURE__ */ jsx5(
3279
+ "pre",
3280
+ {
3281
+ style: {
3282
+ marginTop: 4,
3283
+ padding: "8px 10px",
3284
+ background: t.bgElev,
3285
+ border: `1px solid ${t.border}`,
3286
+ borderRadius: 6,
3287
+ fontSize: 11,
3288
+ fontFamily: t.fontMono,
3289
+ color: currentTool.error ? t.error : t.text,
3290
+ whiteSpace: "pre-wrap",
3291
+ maxHeight: 180,
3292
+ overflow: "auto",
3293
+ margin: 0
3294
+ },
3295
+ children: currentStage?.to === "tool" ? JSON.stringify(currentTool.arguments, null, 2) : currentTool.result
3296
+ }
3297
+ )
3298
+ ] }),
3299
+ timeline.turns.length > 1 && /* @__PURE__ */ jsxs5("section", { children: [
3300
+ /* @__PURE__ */ jsx5(Label3, { t, children: "Conversation" }),
3301
+ /* @__PURE__ */ jsxs5("div", { style: { marginTop: 4, fontSize: 12, color: t.textMuted, lineHeight: 1.5 }, children: [
3302
+ timeline.turns.length,
3303
+ " question",
3304
+ timeline.turns.length === 1 ? "" : "s",
3305
+ " so far \xB7",
3306
+ " ",
3307
+ timeline.tools.length,
3308
+ " tool call",
3309
+ timeline.tools.length === 1 ? "" : "s",
3310
+ " total"
3311
+ ] })
3312
+ ] })
3313
+ ]
3314
+ }
3315
+ )
3106
3316
  }
3107
3317
  );
3108
3318
  }
@@ -4288,18 +4498,34 @@ function Lens({
4288
4498
  const autoLens = useLiveTimeline();
4289
4499
  const [, bumpSnapshot] = useReducer((x) => x + 1, 0);
4290
4500
  useEffect5(() => {
4291
- if (!runnerProp?.observe) return;
4501
+ if (!runnerProp) return;
4292
4502
  autoLens.reset();
4503
+ const onTurnComplete = () => bumpSnapshot();
4504
+ if (runnerProp.attachRecorder) {
4505
+ const detachRecorder = runnerProp.attachRecorder(autoLens.recorder);
4506
+ const stopObserve = runnerProp.observe?.((event) => {
4507
+ const type = event && typeof event === "object" ? event.type : void 0;
4508
+ if (type === "turn_end" || type === "agentfootprint.agent.turn_complete") {
4509
+ onTurnComplete();
4510
+ }
4511
+ bumpSnapshot();
4512
+ });
4513
+ return () => {
4514
+ detachRecorder();
4515
+ stopObserve?.();
4516
+ };
4517
+ }
4518
+ if (!runnerProp.observe) return;
4293
4519
  const stop = runnerProp.observe((event) => {
4294
4520
  autoLens.ingest(event);
4295
4521
  const type = event && typeof event === "object" ? event.type : void 0;
4296
4522
  if (type === "turn_end" || type === "agentfootprint.agent.turn_complete") {
4297
- bumpSnapshot();
4523
+ onTurnComplete();
4298
4524
  }
4299
4525
  });
4300
4526
  return stop;
4301
4527
  }, [runnerProp]);
4302
- const usingRunner = !!runnerProp?.observe;
4528
+ const usingRunner = !!runnerProp?.observe || !!runnerProp?.attachRecorder;
4303
4529
  const resolvedTimeline = usingRunner ? autoLens.timeline : timeline;
4304
4530
  const resolvedSnapshot = usingRunner ? runnerProp?.getSnapshot?.() ?? null : runtimeSnapshot ?? null;
4305
4531
  const resolvedNarrative = usingRunner ? runnerProp?.getNarrativeEntries?.() : narrativeEntries;
@@ -5131,4 +5357,4 @@ export {
5131
5357
  ToolCallInspector,
5132
5358
  useLens
5133
5359
  };
5134
- //# sourceMappingURL=chunk-TB3TR43S.js.map
5360
+ //# sourceMappingURL=chunk-JMPGAQXS.js.map