agentfootprint-lens 0.10.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";
@@ -1797,6 +1797,11 @@ var NODE_POSITIONS = {
1797
1797
  };
1798
1798
  var CONTEXT_NODE_POSITION = { x: 325, y: 120 };
1799
1799
  var TOOLS_NODE_POSITION = { x: -150, y: 120 };
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;
1800
1805
  var NODE_SIZES = {
1801
1806
  user: { width: 150, height: 70 },
1802
1807
  agent: { width: 200, height: 190 },
@@ -1902,6 +1907,33 @@ function StageFlow({
1902
1907
  return s;
1903
1908
  }, [activeStage]);
1904
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
+ }
1905
1937
  const byKey = /* @__PURE__ */ new Map();
1906
1938
  visible.forEach((s) => {
1907
1939
  byKey.set(`${s.from}\u2192${s.to}`, { from: s.from, to: s.to, lastStage: s });
@@ -1927,7 +1959,7 @@ function StageFlow({
1927
1959
  }
1928
1960
  };
1929
1961
  });
1930
- }, [visible, activeStage]);
1962
+ }, [visible, activeStage, timeline]);
1931
1963
  const toolsRoster = useMemo(() => {
1932
1964
  if (!timeline || !activeStage || activeStage.iterIndex === void 0) return null;
1933
1965
  const turn = timeline.turns[activeStage.turnIndex];
@@ -1978,7 +2010,50 @@ function StageFlow({
1978
2010
  return [...bySource.values()];
1979
2011
  }, [activeInjectionsBySlot]);
1980
2012
  const isAgentRun = touched.has("tool") || contextSummary.length > 0 || toolsRoster !== null;
2013
+ const subAgents = timeline?.subAgents ?? [];
2014
+ const isMultiAgent = subAgents.length > 0;
1981
2015
  const nodes = useMemo(() => {
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
+ }
1982
2057
  const containerBox = computeAgentContainerBox({
1983
2058
  showTool: touched.has("tool"),
1984
2059
  showContext: contextSummary.length > 0,
@@ -2050,6 +2125,8 @@ function StageFlow({
2050
2125
  return containerNode ? [containerNode, ...base] : base;
2051
2126
  }, [
2052
2127
  isAgentRun,
2128
+ isMultiAgent,
2129
+ subAgents,
2053
2130
  activeNodes,
2054
2131
  touched,
2055
2132
  activeStage,
@@ -2065,7 +2142,8 @@ function StageFlow({
2065
2142
  lens: LensNode,
2066
2143
  context: ContextNode,
2067
2144
  "tools-list": ToolsListNode,
2068
- "agent-container": AgentContainerNode
2145
+ "agent-container": AgentContainerNode,
2146
+ subagent: SubAgentNode
2069
2147
  }),
2070
2148
  []
2071
2149
  );
@@ -2395,6 +2473,98 @@ function AgentContainerNode({ data }) {
2395
2473
  }
2396
2474
  );
2397
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
+ }
2398
2568
  function ContextNode({ data }) {
2399
2569
  const t = useLensTheme();
2400
2570
  const d = data;
@@ -4328,18 +4498,34 @@ function Lens({
4328
4498
  const autoLens = useLiveTimeline();
4329
4499
  const [, bumpSnapshot] = useReducer((x) => x + 1, 0);
4330
4500
  useEffect5(() => {
4331
- if (!runnerProp?.observe) return;
4501
+ if (!runnerProp) return;
4332
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;
4333
4519
  const stop = runnerProp.observe((event) => {
4334
4520
  autoLens.ingest(event);
4335
4521
  const type = event && typeof event === "object" ? event.type : void 0;
4336
4522
  if (type === "turn_end" || type === "agentfootprint.agent.turn_complete") {
4337
- bumpSnapshot();
4523
+ onTurnComplete();
4338
4524
  }
4339
4525
  });
4340
4526
  return stop;
4341
4527
  }, [runnerProp]);
4342
- const usingRunner = !!runnerProp?.observe;
4528
+ const usingRunner = !!runnerProp?.observe || !!runnerProp?.attachRecorder;
4343
4529
  const resolvedTimeline = usingRunner ? autoLens.timeline : timeline;
4344
4530
  const resolvedSnapshot = usingRunner ? runnerProp?.getSnapshot?.() ?? null : runtimeSnapshot ?? null;
4345
4531
  const resolvedNarrative = usingRunner ? runnerProp?.getNarrativeEntries?.() : narrativeEntries;
@@ -5171,4 +5357,4 @@ export {
5171
5357
  ToolCallInspector,
5172
5358
  useLens
5173
5359
  };
5174
- //# sourceMappingURL=chunk-Q2J47PIG.js.map
5360
+ //# sourceMappingURL=chunk-JMPGAQXS.js.map