agentfootprint-lens 0.1.0 → 0.2.1
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.
- package/dist/index.cjs +307 -22
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +131 -2
- package/dist/index.d.ts +131 -2
- package/dist/index.js +305 -22
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -22,11 +22,13 @@ var src_exports = {};
|
|
|
22
22
|
__export(src_exports, {
|
|
23
23
|
AgentLens: () => AgentLens,
|
|
24
24
|
IterationStrip: () => IterationStrip,
|
|
25
|
+
LiveTimelineBuilder: () => LiveTimelineBuilder,
|
|
25
26
|
MessagesPanel: () => MessagesPanel,
|
|
26
27
|
ToolCallInspector: () => ToolCallInspector,
|
|
27
28
|
fromAgentSnapshot: () => fromAgentSnapshot,
|
|
28
29
|
resolveLensTheme: () => resolve,
|
|
29
|
-
useLensTheme: () => useLensTheme
|
|
30
|
+
useLensTheme: () => useLensTheme,
|
|
31
|
+
useLiveTimeline: () => useLiveTimeline
|
|
30
32
|
});
|
|
31
33
|
module.exports = __toCommonJS(src_exports);
|
|
32
34
|
|
|
@@ -273,12 +275,26 @@ var import_jsx_runtime = require("react/jsx-runtime");
|
|
|
273
275
|
function MessagesPanel({
|
|
274
276
|
timeline,
|
|
275
277
|
onToolCallClick,
|
|
276
|
-
systemPrompt
|
|
278
|
+
systemPrompt,
|
|
279
|
+
selectedIterKey
|
|
277
280
|
}) {
|
|
278
281
|
const t = useLensTheme();
|
|
282
|
+
const scrollRef = (0, import_react.useRef)(null);
|
|
283
|
+
(0, import_react.useEffect)(() => {
|
|
284
|
+
if (!selectedIterKey || !scrollRef.current) return;
|
|
285
|
+
const target = scrollRef.current.querySelector(
|
|
286
|
+
`[data-iter-key="${CSS.escape(selectedIterKey)}"]`
|
|
287
|
+
);
|
|
288
|
+
if (!target) return;
|
|
289
|
+
target.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
290
|
+
target.setAttribute("data-iter-selected", "true");
|
|
291
|
+
const h = window.setTimeout(() => target.removeAttribute("data-iter-selected"), 1200);
|
|
292
|
+
return () => window.clearTimeout(h);
|
|
293
|
+
}, [selectedIterKey]);
|
|
279
294
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
280
295
|
"div",
|
|
281
296
|
{
|
|
297
|
+
ref: scrollRef,
|
|
282
298
|
"data-fp-lens": "messages-panel",
|
|
283
299
|
style: {
|
|
284
300
|
display: "flex",
|
|
@@ -365,7 +381,15 @@ function TurnBlock({
|
|
|
365
381
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
|
|
366
382
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TurnHeader, { turn }),
|
|
367
383
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserBubble, { text: turn.userPrompt }),
|
|
368
|
-
turn.iterations.map((iter) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
384
|
+
turn.iterations.map((iter) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
385
|
+
IterationBlock,
|
|
386
|
+
{
|
|
387
|
+
iter,
|
|
388
|
+
turnIndex: turn.index,
|
|
389
|
+
onToolCallClick
|
|
390
|
+
},
|
|
391
|
+
iter.index
|
|
392
|
+
)),
|
|
369
393
|
turn.finalContent && turn.iterations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 11, color: t.textSubtle, textAlign: "center" }, children: [
|
|
370
394
|
"turn ",
|
|
371
395
|
turn.index + 1,
|
|
@@ -427,27 +451,51 @@ function UserBubble({ text }) {
|
|
|
427
451
|
}
|
|
428
452
|
function IterationBlock({
|
|
429
453
|
iter,
|
|
454
|
+
turnIndex,
|
|
430
455
|
onToolCallClick
|
|
431
456
|
}) {
|
|
432
457
|
const t = useLensTheme();
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
458
|
+
const key = `${turnIndex}.${iter.index}`;
|
|
459
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
460
|
+
"div",
|
|
461
|
+
{
|
|
462
|
+
"data-iter-key": key,
|
|
463
|
+
"data-turn-index": turnIndex,
|
|
464
|
+
"data-iter-index": iter.index,
|
|
465
|
+
style: {
|
|
466
|
+
display: "flex",
|
|
467
|
+
flexDirection: "column",
|
|
468
|
+
gap: 6,
|
|
469
|
+
// When the parent adds data-iter-selected (via IterationStrip
|
|
470
|
+
// click), pulse a soft ring using the accent color. Subtle so
|
|
471
|
+
// the chat itself stays readable.
|
|
472
|
+
padding: 8,
|
|
473
|
+
margin: -8,
|
|
474
|
+
borderRadius: t.radius,
|
|
475
|
+
outline: "2px solid transparent",
|
|
476
|
+
outlineOffset: 2,
|
|
477
|
+
transition: "outline-color 180ms ease, background 180ms ease"
|
|
478
|
+
},
|
|
479
|
+
children: [
|
|
480
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(IterationBadge, { iter }),
|
|
481
|
+
iter.assistantContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
482
|
+
"div",
|
|
483
|
+
{
|
|
484
|
+
style: {
|
|
485
|
+
background: t.bgElev,
|
|
486
|
+
border: `1px solid ${t.border}`,
|
|
487
|
+
borderRadius: `2px ${t.radius} ${t.radius} ${t.radius}`,
|
|
488
|
+
padding: "10px 14px",
|
|
489
|
+
maxWidth: 820,
|
|
490
|
+
whiteSpace: "pre-wrap"
|
|
491
|
+
},
|
|
492
|
+
children: iter.assistantContent
|
|
493
|
+
}
|
|
494
|
+
),
|
|
495
|
+
iter.toolCalls.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexDirection: "column", gap: 6, paddingLeft: 12 }, children: iter.toolCalls.map((tc) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ToolCallCard, { invocation: tc, onClick: onToolCallClick }, tc.id)) })
|
|
496
|
+
]
|
|
497
|
+
}
|
|
498
|
+
);
|
|
451
499
|
}
|
|
452
500
|
function IterationBadge({ iter }) {
|
|
453
501
|
const t = useLensTheme();
|
|
@@ -882,6 +930,12 @@ function AgentLens({
|
|
|
882
930
|
fontFamily: t.fontSans
|
|
883
931
|
},
|
|
884
932
|
children: [
|
|
933
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("style", { children: `
|
|
934
|
+
[data-iter-selected="true"] {
|
|
935
|
+
outline-color: currentColor !important;
|
|
936
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
937
|
+
}
|
|
938
|
+
` }),
|
|
885
939
|
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "strip" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
886
940
|
IterationStrip,
|
|
887
941
|
{
|
|
@@ -895,6 +949,7 @@ function AgentLens({
|
|
|
895
949
|
{
|
|
896
950
|
timeline,
|
|
897
951
|
onToolCallClick: handleToolClick,
|
|
952
|
+
selectedIterKey,
|
|
898
953
|
...derivedSystemPrompt && { systemPrompt: derivedSystemPrompt }
|
|
899
954
|
}
|
|
900
955
|
) }),
|
|
@@ -921,14 +976,244 @@ function AgentLens({
|
|
|
921
976
|
}
|
|
922
977
|
);
|
|
923
978
|
}
|
|
979
|
+
|
|
980
|
+
// src/adapters/LiveTimelineBuilder.ts
|
|
981
|
+
var LiveTimelineBuilder = class {
|
|
982
|
+
constructor() {
|
|
983
|
+
this.turns = [];
|
|
984
|
+
this.currentTurn = null;
|
|
985
|
+
this.currentIter = null;
|
|
986
|
+
this.toolByCallId = /* @__PURE__ */ new Map();
|
|
987
|
+
this.messages = [];
|
|
988
|
+
this.finalDecision = {};
|
|
989
|
+
}
|
|
990
|
+
/**
|
|
991
|
+
* Begin a new turn. Call this BEFORE `agent.run(userPrompt)` so the
|
|
992
|
+
* user's prompt appears alongside the iterations it produced. Safe to
|
|
993
|
+
* call even mid-conversation — it closes the previous turn cleanly.
|
|
994
|
+
*/
|
|
995
|
+
startTurn(userPrompt) {
|
|
996
|
+
if (this.currentTurn) this.commitCurrentTurn();
|
|
997
|
+
this.currentTurn = {
|
|
998
|
+
index: this.turns.length,
|
|
999
|
+
userPrompt,
|
|
1000
|
+
iterations: [],
|
|
1001
|
+
finalContent: "",
|
|
1002
|
+
totalInputTokens: 0,
|
|
1003
|
+
totalOutputTokens: 0,
|
|
1004
|
+
totalDurationMs: 0,
|
|
1005
|
+
startMs: Date.now()
|
|
1006
|
+
};
|
|
1007
|
+
this.messages.push({ role: "user", content: userPrompt });
|
|
1008
|
+
}
|
|
1009
|
+
/**
|
|
1010
|
+
* Optional — attach the system prompt so MessagesPanel can render it
|
|
1011
|
+
* in the collapsible preamble. Usually set once at agent construction.
|
|
1012
|
+
*/
|
|
1013
|
+
setSystemPrompt(prompt) {
|
|
1014
|
+
this.systemPrompt = prompt;
|
|
1015
|
+
}
|
|
1016
|
+
/**
|
|
1017
|
+
* Feed one agent stream event. Safe to call for unknown events; we
|
|
1018
|
+
* ignore anything we don't recognize.
|
|
1019
|
+
*/
|
|
1020
|
+
ingest(event) {
|
|
1021
|
+
const e = event;
|
|
1022
|
+
if (!e || typeof e.type !== "string") return;
|
|
1023
|
+
switch (e.type) {
|
|
1024
|
+
case "llm_start":
|
|
1025
|
+
case "agentfootprint.stream.llm_start":
|
|
1026
|
+
this.onLLMStart(e);
|
|
1027
|
+
return;
|
|
1028
|
+
case "llm_end":
|
|
1029
|
+
case "agentfootprint.stream.llm_end":
|
|
1030
|
+
this.onLLMEnd(e);
|
|
1031
|
+
return;
|
|
1032
|
+
case "tool_start":
|
|
1033
|
+
case "agentfootprint.stream.tool_start":
|
|
1034
|
+
this.onToolStart(e);
|
|
1035
|
+
return;
|
|
1036
|
+
case "tool_end":
|
|
1037
|
+
case "agentfootprint.stream.tool_end":
|
|
1038
|
+
this.onToolEnd(e);
|
|
1039
|
+
return;
|
|
1040
|
+
case "turn_end":
|
|
1041
|
+
case "agentfootprint.agent.turn_complete":
|
|
1042
|
+
this.commitCurrentTurn();
|
|
1043
|
+
return;
|
|
1044
|
+
default:
|
|
1045
|
+
return;
|
|
1046
|
+
}
|
|
1047
|
+
}
|
|
1048
|
+
onLLMStart(e) {
|
|
1049
|
+
if (!this.currentTurn) return;
|
|
1050
|
+
const iterNum = e.iteration ?? this.currentTurn.iterations.length + 1;
|
|
1051
|
+
this.currentIter = {
|
|
1052
|
+
index: iterNum,
|
|
1053
|
+
assistantContent: "",
|
|
1054
|
+
toolCalls: [],
|
|
1055
|
+
decisionAtStart: {},
|
|
1056
|
+
visibleTools: [],
|
|
1057
|
+
startMs: Date.now()
|
|
1058
|
+
};
|
|
1059
|
+
this.currentTurn.iterations.push(this.currentIter);
|
|
1060
|
+
}
|
|
1061
|
+
onLLMEnd(e) {
|
|
1062
|
+
if (!this.currentIter || !this.currentTurn) return;
|
|
1063
|
+
this.currentIter.assistantContent = e.content ?? this.currentIter.assistantContent;
|
|
1064
|
+
if (e.model) this.currentIter.model = e.model;
|
|
1065
|
+
if (e.usage?.inputTokens !== void 0) this.currentIter.inputTokens = e.usage.inputTokens;
|
|
1066
|
+
if (e.usage?.outputTokens !== void 0) this.currentIter.outputTokens = e.usage.outputTokens;
|
|
1067
|
+
if (e.stopReason) this.currentIter.stopReason = e.stopReason;
|
|
1068
|
+
this.currentIter.durationMs = e.durationMs ?? Date.now() - this.currentIter.startMs;
|
|
1069
|
+
this.currentTurn.totalInputTokens += this.currentIter.inputTokens ?? 0;
|
|
1070
|
+
this.currentTurn.totalOutputTokens += this.currentIter.outputTokens ?? 0;
|
|
1071
|
+
this.currentTurn.totalDurationMs += this.currentIter.durationMs ?? 0;
|
|
1072
|
+
if (this.currentIter.assistantContent) {
|
|
1073
|
+
this.messages.push({ role: "assistant", content: this.currentIter.assistantContent });
|
|
1074
|
+
}
|
|
1075
|
+
if ((e.toolCallCount ?? 0) === 0) {
|
|
1076
|
+
this.currentTurn.finalContent = this.currentIter.assistantContent;
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
onToolStart(e) {
|
|
1080
|
+
if (!this.currentIter || !this.currentTurn) return;
|
|
1081
|
+
const tool = {
|
|
1082
|
+
id: e.toolCallId ?? `tool-${this.currentIter.toolCalls.length}`,
|
|
1083
|
+
name: e.toolName ?? "unknown",
|
|
1084
|
+
arguments: e.args ?? {},
|
|
1085
|
+
result: "",
|
|
1086
|
+
iterationIndex: this.currentIter.index,
|
|
1087
|
+
turnIndex: this.currentTurn.index,
|
|
1088
|
+
startMs: Date.now()
|
|
1089
|
+
};
|
|
1090
|
+
this.currentIter.toolCalls.push(tool);
|
|
1091
|
+
this.toolByCallId.set(tool.id, tool);
|
|
1092
|
+
}
|
|
1093
|
+
onToolEnd(e) {
|
|
1094
|
+
const tool = this.toolByCallId.get(e.toolCallId ?? "");
|
|
1095
|
+
if (!tool) return;
|
|
1096
|
+
const r = e.result;
|
|
1097
|
+
if (typeof r === "string") {
|
|
1098
|
+
tool.result = r;
|
|
1099
|
+
} else if (r && typeof r === "object") {
|
|
1100
|
+
tool.result = r.content ?? "";
|
|
1101
|
+
if (r.error === true) tool.error = true;
|
|
1102
|
+
}
|
|
1103
|
+
tool.durationMs = e.durationMs ?? Date.now() - tool.startMs;
|
|
1104
|
+
this.messages.push({ role: "tool", content: tool.result, toolCallId: tool.id });
|
|
1105
|
+
}
|
|
1106
|
+
commitCurrentTurn() {
|
|
1107
|
+
if (!this.currentTurn) return;
|
|
1108
|
+
this.turns.push(this.currentTurn);
|
|
1109
|
+
this.currentTurn = null;
|
|
1110
|
+
this.currentIter = null;
|
|
1111
|
+
}
|
|
1112
|
+
/**
|
|
1113
|
+
* Snapshot the current state as an immutable `AgentTimeline`. Safe to
|
|
1114
|
+
* call at any point — mid-run gives you the partial state so Lens can
|
|
1115
|
+
* live-update.
|
|
1116
|
+
*/
|
|
1117
|
+
getTimeline() {
|
|
1118
|
+
const allTurns = [...this.turns];
|
|
1119
|
+
if (this.currentTurn) allTurns.push(this.currentTurn);
|
|
1120
|
+
const tools = [];
|
|
1121
|
+
const frozenTurns = allTurns.map((t) => {
|
|
1122
|
+
const iterations = t.iterations.map((i) => {
|
|
1123
|
+
const tcs = i.toolCalls.map((tc) => ({ ...tc }));
|
|
1124
|
+
tools.push(...tcs);
|
|
1125
|
+
return { ...i, toolCalls: tcs };
|
|
1126
|
+
});
|
|
1127
|
+
return { ...t, iterations };
|
|
1128
|
+
});
|
|
1129
|
+
return {
|
|
1130
|
+
turns: frozenTurns,
|
|
1131
|
+
messages: [...this.messages],
|
|
1132
|
+
tools,
|
|
1133
|
+
finalDecision: { ...this.finalDecision },
|
|
1134
|
+
rawSnapshot: null
|
|
1135
|
+
};
|
|
1136
|
+
}
|
|
1137
|
+
/**
|
|
1138
|
+
* Fold in a final `decision` scope after the run — useful when
|
|
1139
|
+
* the consumer wants the Decision Ribbon (phase-2) to reflect the
|
|
1140
|
+
* post-run state. Safe no-op during the run itself.
|
|
1141
|
+
*/
|
|
1142
|
+
setFinalDecision(decision) {
|
|
1143
|
+
this.finalDecision = decision;
|
|
1144
|
+
}
|
|
1145
|
+
/** Get the optional system prompt for the Messages preamble. */
|
|
1146
|
+
getSystemPrompt() {
|
|
1147
|
+
return this.systemPrompt;
|
|
1148
|
+
}
|
|
1149
|
+
/** Wipe state. Useful when the consumer starts a fresh conversation. */
|
|
1150
|
+
reset() {
|
|
1151
|
+
this.turns = [];
|
|
1152
|
+
this.currentTurn = null;
|
|
1153
|
+
this.currentIter = null;
|
|
1154
|
+
this.toolByCallId.clear();
|
|
1155
|
+
this.messages = [];
|
|
1156
|
+
this.finalDecision = {};
|
|
1157
|
+
}
|
|
1158
|
+
};
|
|
1159
|
+
|
|
1160
|
+
// src/adapters/useLiveTimeline.ts
|
|
1161
|
+
var import_react3 = require("react");
|
|
1162
|
+
function useLiveTimeline() {
|
|
1163
|
+
const builderRef = (0, import_react3.useRef)(null);
|
|
1164
|
+
if (!builderRef.current) builderRef.current = new LiveTimelineBuilder();
|
|
1165
|
+
const builder = builderRef.current;
|
|
1166
|
+
const [timeline, setTimeline] = (0, import_react3.useState)(() => builder.getTimeline());
|
|
1167
|
+
const sync = (0, import_react3.useCallback)(() => {
|
|
1168
|
+
setTimeline(builder.getTimeline());
|
|
1169
|
+
}, [builder]);
|
|
1170
|
+
const ingest = (0, import_react3.useCallback)(
|
|
1171
|
+
(event) => {
|
|
1172
|
+
builder.ingest(event);
|
|
1173
|
+
sync();
|
|
1174
|
+
},
|
|
1175
|
+
[builder, sync]
|
|
1176
|
+
);
|
|
1177
|
+
const startTurn = (0, import_react3.useCallback)(
|
|
1178
|
+
(userPrompt) => {
|
|
1179
|
+
builder.startTurn(userPrompt);
|
|
1180
|
+
sync();
|
|
1181
|
+
},
|
|
1182
|
+
[builder, sync]
|
|
1183
|
+
);
|
|
1184
|
+
const setSystemPrompt = (0, import_react3.useCallback)(
|
|
1185
|
+
(prompt) => {
|
|
1186
|
+
builder.setSystemPrompt(prompt);
|
|
1187
|
+
sync();
|
|
1188
|
+
},
|
|
1189
|
+
[builder, sync]
|
|
1190
|
+
);
|
|
1191
|
+
const setFinalDecision = (0, import_react3.useCallback)(
|
|
1192
|
+
(decision) => {
|
|
1193
|
+
builder.setFinalDecision(decision);
|
|
1194
|
+
sync();
|
|
1195
|
+
},
|
|
1196
|
+
[builder, sync]
|
|
1197
|
+
);
|
|
1198
|
+
const reset = (0, import_react3.useCallback)(() => {
|
|
1199
|
+
builder.reset();
|
|
1200
|
+
sync();
|
|
1201
|
+
}, [builder, sync]);
|
|
1202
|
+
return (0, import_react3.useMemo)(
|
|
1203
|
+
() => ({ timeline, ingest, startTurn, setSystemPrompt, setFinalDecision, reset, builder }),
|
|
1204
|
+
[timeline, ingest, startTurn, setSystemPrompt, setFinalDecision, reset, builder]
|
|
1205
|
+
);
|
|
1206
|
+
}
|
|
924
1207
|
// Annotate the CommonJS export names for ESM import in node:
|
|
925
1208
|
0 && (module.exports = {
|
|
926
1209
|
AgentLens,
|
|
927
1210
|
IterationStrip,
|
|
1211
|
+
LiveTimelineBuilder,
|
|
928
1212
|
MessagesPanel,
|
|
929
1213
|
ToolCallInspector,
|
|
930
1214
|
fromAgentSnapshot,
|
|
931
1215
|
resolveLensTheme,
|
|
932
|
-
useLensTheme
|
|
1216
|
+
useLensTheme,
|
|
1217
|
+
useLiveTimeline
|
|
933
1218
|
});
|
|
934
1219
|
//# sourceMappingURL=index.cjs.map
|