agentfootprint-lens 0.2.1 → 0.4.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.
- package/dist/index.cjs +3116 -307
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +238 -13
- package/dist/index.d.ts +238 -13
- package/dist/index.js +3110 -309
- package/dist/index.js.map +1 -1
- package/package.json +7 -2
package/dist/index.cjs
CHANGED
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,16 +17,30 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
|
|
20
30
|
// src/index.ts
|
|
21
31
|
var src_exports = {};
|
|
22
32
|
__export(src_exports, {
|
|
23
33
|
AgentLens: () => AgentLens,
|
|
34
|
+
AskCard: () => AskCard,
|
|
24
35
|
IterationStrip: () => IterationStrip,
|
|
25
36
|
LiveTimelineBuilder: () => LiveTimelineBuilder,
|
|
26
37
|
MessagesPanel: () => MessagesPanel,
|
|
38
|
+
RunSummary: () => RunSummary,
|
|
39
|
+
SkillsPanel: () => SkillsPanel,
|
|
40
|
+
StageFlow: () => StageFlow,
|
|
41
|
+
TimeTravel: () => TimeTravel,
|
|
27
42
|
ToolCallInspector: () => ToolCallInspector,
|
|
43
|
+
deriveStages: () => deriveStages,
|
|
28
44
|
fromAgentSnapshot: () => fromAgentSnapshot,
|
|
29
45
|
resolveLensTheme: () => resolve,
|
|
30
46
|
useLensTheme: () => useLensTheme,
|
|
@@ -33,7 +49,7 @@ __export(src_exports, {
|
|
|
33
49
|
module.exports = __toCommonJS(src_exports);
|
|
34
50
|
|
|
35
51
|
// src/AgentLens.tsx
|
|
36
|
-
var
|
|
52
|
+
var import_react6 = require("react");
|
|
37
53
|
|
|
38
54
|
// src/adapters/fromAgentSnapshot.ts
|
|
39
55
|
function fromAgentSnapshot(runtime) {
|
|
@@ -193,8 +209,10 @@ function assembleTurns(messages, llmCalls, toolExecs, instructionEvals, toolReso
|
|
|
193
209
|
...tc,
|
|
194
210
|
turnIndex: currentTurn.index
|
|
195
211
|
}));
|
|
212
|
+
const msgsBefore = messages.indexOf(msg);
|
|
196
213
|
const iteration = {
|
|
197
214
|
index: iterIndex,
|
|
215
|
+
messagesSentCount: msgsBefore >= 0 ? msgsBefore : 0,
|
|
198
216
|
...call?.model && { model: call.model },
|
|
199
217
|
...call?.inputTokens !== void 0 && { inputTokens: call.inputTokens },
|
|
200
218
|
...call?.outputTokens !== void 0 && { outputTokens: call.outputTokens },
|
|
@@ -239,7 +257,7 @@ function finalizeTurn(t) {
|
|
|
239
257
|
}
|
|
240
258
|
|
|
241
259
|
// src/panels/MessagesPanel.tsx
|
|
242
|
-
var import_react = require("react");
|
|
260
|
+
var import_react = __toESM(require("react"), 1);
|
|
243
261
|
|
|
244
262
|
// src/theme/useLensTheme.ts
|
|
245
263
|
var import_footprint_explainable_ui = require("footprint-explainable-ui");
|
|
@@ -276,27 +294,105 @@ function MessagesPanel({
|
|
|
276
294
|
timeline,
|
|
277
295
|
onToolCallClick,
|
|
278
296
|
systemPrompt,
|
|
279
|
-
selectedIterKey
|
|
297
|
+
selectedIterKey,
|
|
298
|
+
stages,
|
|
299
|
+
focusIndex,
|
|
300
|
+
onFocusChange,
|
|
301
|
+
isLive
|
|
280
302
|
}) {
|
|
281
303
|
const t = useLensTheme();
|
|
282
304
|
const scrollRef = (0, import_react.useRef)(null);
|
|
305
|
+
const iterRanges = useIterationStageRanges(stages);
|
|
306
|
+
(0, import_react.useEffect)(() => {
|
|
307
|
+
if (!scrollRef.current) {
|
|
308
|
+
console.log("[Lens scroll] selectedIter effect skipped: no scrollRef");
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
if (selectedIterKey) {
|
|
312
|
+
const target = scrollRef.current.querySelector(
|
|
313
|
+
`[data-iter-key="${CSS.escape(selectedIterKey)}"]`
|
|
314
|
+
);
|
|
315
|
+
console.log("[Lens scroll] selectedIterKey path", {
|
|
316
|
+
selectedIterKey,
|
|
317
|
+
foundTarget: !!target
|
|
318
|
+
});
|
|
319
|
+
if (target) {
|
|
320
|
+
target.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
321
|
+
target.setAttribute("data-iter-selected", "true");
|
|
322
|
+
const h = window.setTimeout(() => target.removeAttribute("data-iter-selected"), 1200);
|
|
323
|
+
return () => window.clearTimeout(h);
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
}, [selectedIterKey]);
|
|
283
327
|
(0, import_react.useEffect)(() => {
|
|
284
|
-
|
|
328
|
+
const ctx = {
|
|
329
|
+
focusIndex,
|
|
330
|
+
isLive,
|
|
331
|
+
stagesLen: stages?.length ?? 0,
|
|
332
|
+
iterRangesSize: iterRanges.size,
|
|
333
|
+
hasScrollRef: !!scrollRef.current
|
|
334
|
+
};
|
|
335
|
+
if (!scrollRef.current || focusIndex === void 0 || !stages?.length) {
|
|
336
|
+
console.log("[Lens scroll] focus effect SKIPPED", ctx);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (isLive) {
|
|
340
|
+
const el = scrollRef.current;
|
|
341
|
+
const beforeTop2 = el.scrollTop;
|
|
342
|
+
const sh = el.scrollHeight;
|
|
343
|
+
const ch = el.clientHeight;
|
|
344
|
+
const canScroll = sh > ch;
|
|
345
|
+
const alreadyAtBottom = Math.abs(sh - ch - beforeTop2) < 2;
|
|
346
|
+
el.scrollTo({ top: sh, behavior: "auto" });
|
|
347
|
+
const afterTop = el.scrollTop;
|
|
348
|
+
const moved = afterTop !== beforeTop2;
|
|
349
|
+
console.log(
|
|
350
|
+
`[Lens scroll] LIVE tail \u2192 ${moved ? "moved" : canScroll ? "NO-OP (scrollTo returned same top)" : alreadyAtBottom ? "already at bottom" : "CONTAINER NOT SCROLLABLE (scrollHeight<=clientHeight)"} \xB7 sh=${sh} ch=${ch} before=${beforeTop2} after=${afterTop}`,
|
|
351
|
+
{ ...ctx, scrollHeight: sh, clientHeight: ch, beforeScrollTop: beforeTop2, afterScrollTop: afterTop }
|
|
352
|
+
);
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
const key = keyForStage(iterRanges, focusIndex);
|
|
356
|
+
if (!key) {
|
|
357
|
+
console.log("[Lens scroll] focus effect: no iterKey for focusIndex", ctx);
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
285
360
|
const target = scrollRef.current.querySelector(
|
|
286
|
-
`[data-iter-key="${CSS.escape(
|
|
361
|
+
`[data-iter-key="${CSS.escape(key)}"]`
|
|
287
362
|
);
|
|
288
|
-
if (!target)
|
|
363
|
+
if (!target) {
|
|
364
|
+
console.log("[Lens scroll] focus effect: DOM node missing for key", {
|
|
365
|
+
...ctx,
|
|
366
|
+
key
|
|
367
|
+
});
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
const container = scrollRef.current;
|
|
371
|
+
const rect = target.getBoundingClientRect();
|
|
372
|
+
const cRect = container.getBoundingClientRect();
|
|
373
|
+
const relTop = rect.top - cRect.top;
|
|
374
|
+
const beforeTop = container.scrollTop;
|
|
289
375
|
target.scrollIntoView({ block: "start", behavior: "smooth" });
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
376
|
+
console.log(
|
|
377
|
+
`[Lens scroll] SCRUB key=${key} \xB7 relTop=${Math.round(relTop)} sh=${container.scrollHeight} ch=${container.clientHeight} before=${beforeTop}`,
|
|
378
|
+
{ ...ctx, key }
|
|
379
|
+
);
|
|
380
|
+
}, [focusIndex, isLive, iterRanges, stages?.length]);
|
|
294
381
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
295
382
|
"div",
|
|
296
383
|
{
|
|
297
384
|
ref: scrollRef,
|
|
298
385
|
"data-fp-lens": "messages-panel",
|
|
299
386
|
style: {
|
|
387
|
+
// Absolute + inset:0 inside a `position: relative` wrapper
|
|
388
|
+
// forces the panel to be EXACTLY the size of its wrapper cell,
|
|
389
|
+
// regardless of flex/grid height resolution quirks upstream.
|
|
390
|
+
// Without this, percentage heights and 1fr rows can fail to
|
|
391
|
+
// resolve and the panel grows to its content → no scroll.
|
|
392
|
+
// The grid-area wrapper in AgentLens sets `position: relative`
|
|
393
|
+
// to make this the containing block.
|
|
394
|
+
position: "absolute",
|
|
395
|
+
inset: 0,
|
|
300
396
|
display: "flex",
|
|
301
397
|
flexDirection: "column",
|
|
302
398
|
gap: 16,
|
|
@@ -311,7 +407,19 @@ function MessagesPanel({
|
|
|
311
407
|
},
|
|
312
408
|
children: [
|
|
313
409
|
systemPrompt && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(SystemBubble, { text: systemPrompt }),
|
|
314
|
-
timeline.turns.map((turn) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
410
|
+
timeline.turns.map((turn) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
411
|
+
TurnBlock,
|
|
412
|
+
{
|
|
413
|
+
turn,
|
|
414
|
+
allMessages: timeline.messages,
|
|
415
|
+
onToolCallClick,
|
|
416
|
+
iterRanges,
|
|
417
|
+
focusIndex,
|
|
418
|
+
stages,
|
|
419
|
+
onFocusChange
|
|
420
|
+
},
|
|
421
|
+
turn.index
|
|
422
|
+
))
|
|
315
423
|
]
|
|
316
424
|
}
|
|
317
425
|
);
|
|
@@ -348,7 +456,7 @@ function SystemBubble({ text }) {
|
|
|
348
456
|
font: "inherit"
|
|
349
457
|
},
|
|
350
458
|
children: [
|
|
351
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "
|
|
459
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: "How Neo is configured" }),
|
|
352
460
|
" ",
|
|
353
461
|
open ? "\u25BE" : "\u25B8",
|
|
354
462
|
" ",
|
|
@@ -375,31 +483,55 @@ function SystemBubble({ text }) {
|
|
|
375
483
|
}
|
|
376
484
|
function TurnBlock({
|
|
377
485
|
turn,
|
|
378
|
-
|
|
486
|
+
allMessages,
|
|
487
|
+
onToolCallClick,
|
|
488
|
+
iterRanges,
|
|
489
|
+
focusIndex,
|
|
490
|
+
stages,
|
|
491
|
+
onFocusChange
|
|
379
492
|
}) {
|
|
380
493
|
const t = useLensTheme();
|
|
381
494
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
|
|
382
495
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(TurnHeader, { turn }),
|
|
383
496
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(UserBubble, { text: turn.userPrompt }),
|
|
384
|
-
turn.iterations.map((iter) =>
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
497
|
+
turn.iterations.map((iter, i) => {
|
|
498
|
+
const key = `${turn.index}.${iter.index}`;
|
|
499
|
+
const range = iterRanges?.get(key);
|
|
500
|
+
let state = "future";
|
|
501
|
+
if (range && focusIndex !== void 0) {
|
|
502
|
+
if (focusIndex < range.firstStageIndex) state = "future";
|
|
503
|
+
else if (focusIndex > range.lastStageIndex) state = "past";
|
|
504
|
+
else state = "active";
|
|
505
|
+
} else if (!range && focusIndex === void 0) {
|
|
506
|
+
state = "active";
|
|
507
|
+
}
|
|
508
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
509
|
+
IterationBlock,
|
|
510
|
+
{
|
|
511
|
+
iter,
|
|
512
|
+
iterPositionInTurn: i + 1,
|
|
513
|
+
turnIndex: turn.index,
|
|
514
|
+
allMessages,
|
|
515
|
+
onToolCallClick,
|
|
516
|
+
state,
|
|
517
|
+
stages,
|
|
518
|
+
range,
|
|
519
|
+
focusIndex,
|
|
520
|
+
...range && onFocusChange ? { onClick: () => onFocusChange(range.lastStageIndex) } : {}
|
|
521
|
+
},
|
|
522
|
+
iter.index
|
|
523
|
+
);
|
|
524
|
+
}),
|
|
393
525
|
turn.finalContent && turn.iterations.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 11, color: t.textSubtle, textAlign: "center" }, children: [
|
|
394
|
-
"
|
|
395
|
-
turn.index + 1,
|
|
396
|
-
" final \xB7 ",
|
|
526
|
+
"Answer compiled \xB7 ",
|
|
397
527
|
turn.iterations.length,
|
|
398
|
-
"
|
|
528
|
+
" step",
|
|
529
|
+
turn.iterations.length === 1 ? "" : "s",
|
|
530
|
+
" \xB7 ",
|
|
399
531
|
turn.totalInputTokens,
|
|
400
532
|
"\u2192",
|
|
401
533
|
turn.totalOutputTokens,
|
|
402
|
-
"
|
|
534
|
+
" tokens \xB7 ",
|
|
403
535
|
(turn.totalDurationMs / 1e3).toFixed(1),
|
|
404
536
|
"s"
|
|
405
537
|
] })
|
|
@@ -423,7 +555,7 @@ function TurnHeader({ turn }) {
|
|
|
423
555
|
children: [
|
|
424
556
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, height: 1, background: t.border } }),
|
|
425
557
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { children: [
|
|
426
|
-
"
|
|
558
|
+
"Your question ",
|
|
427
559
|
turn.index + 1
|
|
428
560
|
] }),
|
|
429
561
|
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { flex: 1, height: 1, background: t.border } })
|
|
@@ -449,13 +581,110 @@ function UserBubble({ text }) {
|
|
|
449
581
|
}
|
|
450
582
|
) });
|
|
451
583
|
}
|
|
584
|
+
function iterationHeadline(iter) {
|
|
585
|
+
if (iter.toolCalls.length === 0) {
|
|
586
|
+
return "Neo is ready to answer";
|
|
587
|
+
}
|
|
588
|
+
if (iter.toolCalls.length === 1) {
|
|
589
|
+
return singleToolHeadline(iter.toolCalls[0]);
|
|
590
|
+
}
|
|
591
|
+
const names = iter.toolCalls.map((tc) => tc.name);
|
|
592
|
+
if (names.length <= 3) {
|
|
593
|
+
return `Neo called ${names.length} tools in parallel (${names.join(", ")})`;
|
|
594
|
+
}
|
|
595
|
+
return `Neo gathered data from ${names.length} tools in parallel`;
|
|
596
|
+
}
|
|
597
|
+
function singleToolHeadline(tc) {
|
|
598
|
+
if (tc.name === "list_skills") return "Neo is looking up available skills";
|
|
599
|
+
if (tc.name === "read_skill") {
|
|
600
|
+
const id = tc.arguments?.id ?? "?";
|
|
601
|
+
return `Neo activated the "${id}" skill`;
|
|
602
|
+
}
|
|
603
|
+
if (tc.name === "ask_human" || tc.name === "ask_user") {
|
|
604
|
+
return "Neo asked the user for clarification";
|
|
605
|
+
}
|
|
606
|
+
return `Neo called tool (${tc.name})`;
|
|
607
|
+
}
|
|
452
608
|
function IterationBlock({
|
|
453
609
|
iter,
|
|
610
|
+
iterPositionInTurn,
|
|
454
611
|
turnIndex,
|
|
455
|
-
|
|
612
|
+
allMessages,
|
|
613
|
+
onToolCallClick,
|
|
614
|
+
state = "active",
|
|
615
|
+
stages,
|
|
616
|
+
range,
|
|
617
|
+
focusIndex,
|
|
618
|
+
onClick
|
|
456
619
|
}) {
|
|
457
620
|
const t = useLensTheme();
|
|
621
|
+
const [showContext, setShowContext] = (0, import_react.useState)(false);
|
|
458
622
|
const key = `${turnIndex}.${iter.index}`;
|
|
623
|
+
const headline = iterationHeadline(iter);
|
|
624
|
+
const contextMessages = allMessages.slice(0, iter.messagesSentCount);
|
|
625
|
+
let revealIdx = Number.POSITIVE_INFINITY;
|
|
626
|
+
if (range && focusIndex !== void 0) {
|
|
627
|
+
if (state === "future") revealIdx = -1;
|
|
628
|
+
else if (state === "past") revealIdx = range.lastStageIndex;
|
|
629
|
+
else revealIdx = focusIndex;
|
|
630
|
+
}
|
|
631
|
+
const roundHasStarted = revealIdx >= (range?.firstStageIndex ?? 0);
|
|
632
|
+
const revealedMutations = (() => {
|
|
633
|
+
if (!stages || !range) return void 0;
|
|
634
|
+
const agg = {
|
|
635
|
+
systemPrompt: false,
|
|
636
|
+
tools: false,
|
|
637
|
+
systemPromptDeltaChars: 0,
|
|
638
|
+
toolsAdded: 0,
|
|
639
|
+
toolsRemoved: 0,
|
|
640
|
+
systemPromptAdded: "",
|
|
641
|
+
toolsAddedList: []
|
|
642
|
+
};
|
|
643
|
+
const stop = Math.min(revealIdx, range.lastStageIndex);
|
|
644
|
+
for (let i = range.firstStageIndex; i <= stop; i++) {
|
|
645
|
+
const m = stages[i]?.mutations;
|
|
646
|
+
if (!m) continue;
|
|
647
|
+
if (m.systemPrompt) agg.systemPrompt = true;
|
|
648
|
+
if (m.tools) agg.tools = true;
|
|
649
|
+
if (m.systemPromptDeltaChars) agg.systemPromptDeltaChars += m.systemPromptDeltaChars;
|
|
650
|
+
if (m.toolsAdded) agg.toolsAdded += m.toolsAdded;
|
|
651
|
+
if (m.toolsRemoved) agg.toolsRemoved += m.toolsRemoved;
|
|
652
|
+
if (m.systemPromptAdded) {
|
|
653
|
+
agg.systemPromptAdded = agg.systemPromptAdded ? `${agg.systemPromptAdded}
|
|
654
|
+
|
|
655
|
+
${m.systemPromptAdded}` : m.systemPromptAdded;
|
|
656
|
+
}
|
|
657
|
+
if (m.activatedSkillId && !agg.activatedSkillId) {
|
|
658
|
+
agg.activatedSkillId = m.activatedSkillId;
|
|
659
|
+
}
|
|
660
|
+
if (m.toolsAddedList?.length) {
|
|
661
|
+
for (const name of m.toolsAddedList) {
|
|
662
|
+
if (!agg.toolsAddedList.includes(name)) agg.toolsAddedList.push(name);
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
}
|
|
666
|
+
return agg;
|
|
667
|
+
})();
|
|
668
|
+
const mutations = revealedMutations;
|
|
669
|
+
const toolStageIdx = /* @__PURE__ */ new Map();
|
|
670
|
+
if (stages) {
|
|
671
|
+
for (const tc of iter.toolCalls) {
|
|
672
|
+
let outIdx = -1;
|
|
673
|
+
let retIdx = -1;
|
|
674
|
+
for (let i = 0; i < stages.length; i++) {
|
|
675
|
+
const s = stages[i];
|
|
676
|
+
if (s.turnIndex !== turnIndex || s.iterIndex !== iter.index) continue;
|
|
677
|
+
if (s.toolName !== tc.name) continue;
|
|
678
|
+
if (s.from === "agent" && s.to === "tool" && outIdx < 0) outIdx = i;
|
|
679
|
+
else if (s.from === "tool" && s.to === "agent" && retIdx < 0) retIdx = i;
|
|
680
|
+
}
|
|
681
|
+
toolStageIdx.set(tc.id, { outIdx, retIdx });
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
const opacity = state === "future" ? 0.4 : state === "past" ? 0.85 : 1;
|
|
685
|
+
const isActiveRound = state === "active";
|
|
686
|
+
const background = isActiveRound ? `color-mix(in srgb, ${t.accent} 10%, ${t.bg})` : "transparent";
|
|
687
|
+
const boxShadow = isActiveRound ? `0 0 0 1px ${t.accent}, 0 0 24px color-mix(in srgb, ${t.accent} 22%, transparent)` : "none";
|
|
459
688
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
460
689
|
"div",
|
|
461
690
|
{
|
|
@@ -463,227 +692,2885 @@ function IterationBlock({
|
|
|
463
692
|
"data-turn-index": turnIndex,
|
|
464
693
|
"data-iter-index": iter.index,
|
|
465
694
|
style: {
|
|
695
|
+
position: "relative",
|
|
466
696
|
display: "flex",
|
|
467
697
|
flexDirection: "column",
|
|
468
698
|
gap: 6,
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
transition: "outline-color 180ms ease, background 180ms ease"
|
|
699
|
+
padding: 12,
|
|
700
|
+
margin: isActiveRound ? "2px -12px" : "-8px",
|
|
701
|
+
borderRadius: 8,
|
|
702
|
+
background,
|
|
703
|
+
borderLeft: isActiveRound ? `3px solid ${t.accent}` : "3px solid transparent",
|
|
704
|
+
boxShadow,
|
|
705
|
+
opacity,
|
|
706
|
+
transition: "background 220ms ease, box-shadow 220ms ease, opacity 220ms ease, border-left-color 220ms ease, margin 220ms ease"
|
|
478
707
|
},
|
|
479
708
|
children: [
|
|
480
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
481
|
-
|
|
709
|
+
isActiveRound && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
710
|
+
"span",
|
|
711
|
+
{
|
|
712
|
+
"aria-hidden": "true",
|
|
713
|
+
style: {
|
|
714
|
+
position: "absolute",
|
|
715
|
+
left: -3,
|
|
716
|
+
top: 8,
|
|
717
|
+
bottom: 8,
|
|
718
|
+
width: 3,
|
|
719
|
+
background: t.accent,
|
|
720
|
+
boxShadow: `0 0 8px ${t.accent}`,
|
|
721
|
+
pointerEvents: "none"
|
|
722
|
+
}
|
|
723
|
+
}
|
|
724
|
+
),
|
|
725
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
482
726
|
"div",
|
|
483
727
|
{
|
|
484
728
|
style: {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
729
|
+
display: "flex",
|
|
730
|
+
alignItems: "baseline",
|
|
731
|
+
gap: 8,
|
|
732
|
+
fontSize: 13,
|
|
733
|
+
color: t.textMuted
|
|
734
|
+
},
|
|
735
|
+
children: [
|
|
736
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
737
|
+
"button",
|
|
738
|
+
{
|
|
739
|
+
onClick,
|
|
740
|
+
disabled: !onClick,
|
|
741
|
+
title: onClick ? "Jump the slider to this round" : void 0,
|
|
742
|
+
style: {
|
|
743
|
+
background: "transparent",
|
|
744
|
+
border: "none",
|
|
745
|
+
padding: 0,
|
|
746
|
+
margin: 0,
|
|
747
|
+
display: "flex",
|
|
748
|
+
alignItems: "baseline",
|
|
749
|
+
gap: 8,
|
|
750
|
+
cursor: onClick ? "pointer" : "default",
|
|
751
|
+
color: "inherit",
|
|
752
|
+
font: "inherit",
|
|
753
|
+
width: "auto",
|
|
754
|
+
textAlign: "left"
|
|
755
|
+
},
|
|
756
|
+
children: [
|
|
757
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { color: t.accent, fontWeight: 600 }, children: [
|
|
758
|
+
"Round ",
|
|
759
|
+
iterPositionInTurn,
|
|
760
|
+
":"
|
|
761
|
+
] }),
|
|
762
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: t.text }, children: headline })
|
|
763
|
+
]
|
|
764
|
+
}
|
|
765
|
+
),
|
|
766
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
|
|
767
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
768
|
+
"span",
|
|
769
|
+
{
|
|
770
|
+
style: {
|
|
771
|
+
fontSize: 10,
|
|
772
|
+
color: t.textSubtle,
|
|
773
|
+
fontFamily: t.fontMono
|
|
774
|
+
},
|
|
775
|
+
children: [
|
|
776
|
+
iter.inputTokens !== void 0 && `${iter.inputTokens}\u2192${iter.outputTokens ?? "?"} tok \xB7 `,
|
|
777
|
+
iter.durationMs !== void 0 && `${(iter.durationMs / 1e3).toFixed(2)}s`
|
|
778
|
+
]
|
|
779
|
+
}
|
|
780
|
+
),
|
|
781
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
782
|
+
"button",
|
|
783
|
+
{
|
|
784
|
+
onClick: () => setShowContext((v) => !v),
|
|
785
|
+
title: "See exactly what Neo saw when deciding this step",
|
|
786
|
+
style: {
|
|
787
|
+
fontSize: 11,
|
|
788
|
+
color: t.textMuted,
|
|
789
|
+
background: "transparent",
|
|
790
|
+
border: `1px solid ${t.border}`,
|
|
791
|
+
borderRadius: 4,
|
|
792
|
+
padding: "2px 8px",
|
|
793
|
+
cursor: "pointer",
|
|
794
|
+
fontWeight: 400,
|
|
795
|
+
width: "auto"
|
|
796
|
+
},
|
|
797
|
+
children: [
|
|
798
|
+
showContext ? "Hide" : "Show",
|
|
799
|
+
" what Neo saw"
|
|
800
|
+
]
|
|
801
|
+
}
|
|
802
|
+
)
|
|
803
|
+
]
|
|
804
|
+
}
|
|
805
|
+
),
|
|
806
|
+
roundHasStarted && (iter.model || iter.stopReason || (iter.matchedInstructions?.length ?? 0) > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
807
|
+
"div",
|
|
808
|
+
{
|
|
809
|
+
style: {
|
|
810
|
+
display: "flex",
|
|
811
|
+
flexWrap: "wrap",
|
|
812
|
+
gap: 6,
|
|
813
|
+
fontSize: 10,
|
|
814
|
+
color: t.textSubtle,
|
|
815
|
+
fontFamily: t.fontMono,
|
|
816
|
+
paddingLeft: 12
|
|
491
817
|
},
|
|
492
|
-
children:
|
|
818
|
+
children: [
|
|
819
|
+
iter.model && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MetaPill, { t, title: "Model the LLM call was routed to", children: iter.model }),
|
|
820
|
+
iter.stopReason && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(MetaPill, { t, title: "Why the LLM stopped producing tokens", children: [
|
|
821
|
+
"stop: ",
|
|
822
|
+
iter.stopReason
|
|
823
|
+
] }),
|
|
824
|
+
iter.matchedInstructions?.map((id) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
825
|
+
MetaPill,
|
|
826
|
+
{
|
|
827
|
+
t,
|
|
828
|
+
title: "Instruction injected into this round",
|
|
829
|
+
accent: true,
|
|
830
|
+
children: [
|
|
831
|
+
"\u25B8 ",
|
|
832
|
+
id
|
|
833
|
+
]
|
|
834
|
+
},
|
|
835
|
+
id
|
|
836
|
+
))
|
|
837
|
+
]
|
|
493
838
|
}
|
|
494
839
|
),
|
|
495
|
-
|
|
840
|
+
roundHasStarted && iter.assistantContent && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(ReasoningBubble, { text: iter.assistantContent }),
|
|
841
|
+
roundHasStarted && 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) => {
|
|
842
|
+
const idx = toolStageIdx.get(tc.id);
|
|
843
|
+
const cardRevealed = !idx || idx.outIdx < 0 || revealIdx >= idx.outIdx;
|
|
844
|
+
if (!cardRevealed) return null;
|
|
845
|
+
const resultRevealed = !idx || idx.retIdx < 0 || revealIdx >= idx.retIdx;
|
|
846
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
847
|
+
ToolCallCard,
|
|
848
|
+
{
|
|
849
|
+
invocation: tc,
|
|
850
|
+
onClick: onToolCallClick,
|
|
851
|
+
resultRevealed
|
|
852
|
+
},
|
|
853
|
+
tc.id
|
|
854
|
+
);
|
|
855
|
+
}) }),
|
|
856
|
+
mutations && (mutations.systemPrompt || mutations.tools) && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(MutationStrip, { mutations, iter }),
|
|
857
|
+
showContext && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
858
|
+
ContextDrawer,
|
|
859
|
+
{
|
|
860
|
+
messagesSentCount: iter.messagesSentCount,
|
|
861
|
+
contextMessages,
|
|
862
|
+
iter
|
|
863
|
+
}
|
|
864
|
+
)
|
|
496
865
|
]
|
|
497
866
|
}
|
|
498
867
|
);
|
|
499
868
|
}
|
|
500
|
-
function
|
|
869
|
+
function ReasoningBubble({ text }) {
|
|
501
870
|
const t = useLensTheme();
|
|
502
|
-
const
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
if (iter.stopReason) bits.push(iter.stopReason);
|
|
871
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
872
|
+
const PREVIEW_LEN = 140;
|
|
873
|
+
const flat = text.replace(/\s+/g, " ").trim();
|
|
874
|
+
const needsToggle = flat.length > PREVIEW_LEN;
|
|
875
|
+
const preview = needsToggle ? flat.slice(0, PREVIEW_LEN - 1) + "\u2026" : flat;
|
|
508
876
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
509
877
|
"div",
|
|
510
878
|
{
|
|
511
879
|
style: {
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
880
|
+
background: t.bgElev,
|
|
881
|
+
border: `1px solid ${t.border}`,
|
|
882
|
+
borderRadius: `2px ${t.radius} ${t.radius} ${t.radius}`,
|
|
883
|
+
padding: "10px 14px",
|
|
884
|
+
maxWidth: 820,
|
|
885
|
+
whiteSpace: "pre-wrap",
|
|
886
|
+
fontSize: 13,
|
|
887
|
+
lineHeight: 1.55
|
|
519
888
|
},
|
|
520
|
-
children:
|
|
889
|
+
children: needsToggle && !open ? /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
890
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: preview }),
|
|
891
|
+
" ",
|
|
892
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
893
|
+
"button",
|
|
894
|
+
{
|
|
895
|
+
onClick: () => setOpen(true),
|
|
896
|
+
style: {
|
|
897
|
+
background: "transparent",
|
|
898
|
+
border: "none",
|
|
899
|
+
padding: 0,
|
|
900
|
+
color: t.accent,
|
|
901
|
+
cursor: "pointer",
|
|
902
|
+
fontSize: 12,
|
|
903
|
+
fontWeight: 600,
|
|
904
|
+
width: "auto"
|
|
905
|
+
},
|
|
906
|
+
children: "\u25B8 Show full reasoning"
|
|
907
|
+
}
|
|
908
|
+
)
|
|
909
|
+
] }) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
910
|
+
text,
|
|
911
|
+
needsToggle && /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { marginTop: 6 }, children: /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
912
|
+
"button",
|
|
913
|
+
{
|
|
914
|
+
onClick: () => setOpen(false),
|
|
915
|
+
style: {
|
|
916
|
+
background: "transparent",
|
|
917
|
+
border: "none",
|
|
918
|
+
padding: 0,
|
|
919
|
+
color: t.textMuted,
|
|
920
|
+
cursor: "pointer",
|
|
921
|
+
fontSize: 12,
|
|
922
|
+
fontWeight: 500,
|
|
923
|
+
width: "auto"
|
|
924
|
+
},
|
|
925
|
+
children: "\u25BE Collapse"
|
|
926
|
+
}
|
|
927
|
+
) })
|
|
928
|
+
] })
|
|
521
929
|
}
|
|
522
930
|
);
|
|
523
931
|
}
|
|
524
|
-
function
|
|
525
|
-
|
|
526
|
-
|
|
932
|
+
function MetaPill({
|
|
933
|
+
t,
|
|
934
|
+
children,
|
|
935
|
+
title,
|
|
936
|
+
accent
|
|
937
|
+
}) {
|
|
938
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
939
|
+
"span",
|
|
940
|
+
{
|
|
941
|
+
title,
|
|
942
|
+
style: {
|
|
943
|
+
padding: "1px 6px",
|
|
944
|
+
borderRadius: 3,
|
|
945
|
+
background: accent ? `color-mix(in srgb, ${t.warning} 18%, transparent)` : t.bgElev,
|
|
946
|
+
color: accent ? t.warning : t.textSubtle,
|
|
947
|
+
fontWeight: accent ? 600 : 500,
|
|
948
|
+
letterSpacing: "0.02em",
|
|
949
|
+
whiteSpace: "nowrap"
|
|
950
|
+
},
|
|
951
|
+
children
|
|
952
|
+
}
|
|
953
|
+
);
|
|
954
|
+
}
|
|
955
|
+
function MutationStrip({
|
|
956
|
+
mutations,
|
|
957
|
+
iter
|
|
527
958
|
}) {
|
|
528
959
|
const t = useLensTheme();
|
|
529
960
|
const [open, setOpen] = (0, import_react.useState)(false);
|
|
530
|
-
const
|
|
531
|
-
const
|
|
961
|
+
const fallbackReadSkill = mutations.systemPromptAdded ? void 0 : iter.toolCalls.find((tc) => tc.name === "read_skill");
|
|
962
|
+
const skillId = mutations.activatedSkillId || (fallbackReadSkill?.arguments?.id ?? "");
|
|
963
|
+
const skillBody = mutations.systemPromptAdded || fallbackReadSkill?.result || "";
|
|
532
964
|
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
533
965
|
"div",
|
|
534
966
|
{
|
|
535
967
|
style: {
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
968
|
+
display: "flex",
|
|
969
|
+
flexDirection: "column",
|
|
970
|
+
gap: 6,
|
|
971
|
+
paddingLeft: 12,
|
|
972
|
+
fontSize: 11,
|
|
973
|
+
color: t.textMuted,
|
|
974
|
+
fontFamily: t.fontSans
|
|
541
975
|
},
|
|
542
976
|
children: [
|
|
543
977
|
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
544
|
-
"
|
|
978
|
+
"button",
|
|
545
979
|
{
|
|
546
|
-
onClick: () =>
|
|
547
|
-
setOpen((v) => !v);
|
|
548
|
-
onClick?.(invocation);
|
|
549
|
-
},
|
|
980
|
+
onClick: () => setOpen((v) => !v),
|
|
550
981
|
style: {
|
|
551
|
-
padding: "8px 12px",
|
|
552
|
-
cursor: "pointer",
|
|
553
982
|
display: "flex",
|
|
983
|
+
flexWrap: "wrap",
|
|
554
984
|
alignItems: "center",
|
|
555
|
-
gap:
|
|
556
|
-
|
|
557
|
-
|
|
985
|
+
gap: 6,
|
|
986
|
+
background: "transparent",
|
|
987
|
+
border: "none",
|
|
988
|
+
padding: 0,
|
|
989
|
+
margin: 0,
|
|
990
|
+
cursor: "pointer",
|
|
991
|
+
color: "inherit",
|
|
992
|
+
font: "inherit",
|
|
993
|
+
width: "auto",
|
|
994
|
+
textAlign: "left"
|
|
558
995
|
},
|
|
996
|
+
title: "Click to see the actual diff",
|
|
559
997
|
children: [
|
|
560
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: {
|
|
561
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
562
|
-
"(",
|
|
563
|
-
preview,
|
|
564
|
-
")"
|
|
565
|
-
] }),
|
|
566
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
|
|
567
|
-
invocation.decisionUpdate && Object.keys(invocation.decisionUpdate).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
998
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { fontSize: 10, color: t.textSubtle }, children: open ? "\u25BE" : "\u25B8" }),
|
|
999
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
568
1000
|
"span",
|
|
569
1001
|
{
|
|
570
1002
|
style: {
|
|
571
|
-
|
|
572
|
-
|
|
1003
|
+
fontWeight: 700,
|
|
1004
|
+
color: t.accent,
|
|
1005
|
+
textTransform: "uppercase",
|
|
1006
|
+
letterSpacing: "0.06em",
|
|
1007
|
+
fontSize: 10
|
|
1008
|
+
},
|
|
1009
|
+
children: "\u270E Changed"
|
|
1010
|
+
}
|
|
1011
|
+
),
|
|
1012
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { children: "in Neo's input:" }),
|
|
1013
|
+
mutations.systemPrompt && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1014
|
+
"span",
|
|
1015
|
+
{
|
|
1016
|
+
style: {
|
|
1017
|
+
padding: "1px 7px",
|
|
573
1018
|
borderRadius: 3,
|
|
574
|
-
background: `color-mix(in srgb, ${t.
|
|
575
|
-
color: t.
|
|
576
|
-
fontFamily: t.fontSans,
|
|
1019
|
+
background: `color-mix(in srgb, ${t.accent} 18%, transparent)`,
|
|
1020
|
+
color: t.accent,
|
|
577
1021
|
fontWeight: 600,
|
|
578
|
-
|
|
1022
|
+
letterSpacing: "0.02em"
|
|
579
1023
|
},
|
|
580
|
-
children:
|
|
1024
|
+
children: [
|
|
1025
|
+
"System Prompt",
|
|
1026
|
+
mutations.systemPromptDeltaChars > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontWeight: 400, marginLeft: 4 }, children: [
|
|
1027
|
+
"+",
|
|
1028
|
+
mutations.systemPromptDeltaChars.toLocaleString(),
|
|
1029
|
+
" chars"
|
|
1030
|
+
] })
|
|
1031
|
+
]
|
|
581
1032
|
}
|
|
582
1033
|
),
|
|
583
|
-
/* @__PURE__ */ (0, import_jsx_runtime.
|
|
1034
|
+
mutations.tools && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1035
|
+
"span",
|
|
1036
|
+
{
|
|
1037
|
+
style: {
|
|
1038
|
+
padding: "1px 7px",
|
|
1039
|
+
borderRadius: 3,
|
|
1040
|
+
background: `color-mix(in srgb, ${t.accent} 18%, transparent)`,
|
|
1041
|
+
color: t.accent,
|
|
1042
|
+
fontWeight: 600,
|
|
1043
|
+
letterSpacing: "0.02em"
|
|
1044
|
+
},
|
|
1045
|
+
children: [
|
|
1046
|
+
"Tools",
|
|
1047
|
+
(mutations.toolsAdded > 0 || mutations.toolsRemoved > 0) && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { fontWeight: 400, marginLeft: 4 }, children: [
|
|
1048
|
+
mutations.toolsAdded > 0 ? `+${mutations.toolsAdded}` : "",
|
|
1049
|
+
mutations.toolsRemoved > 0 ? ` -${mutations.toolsRemoved}` : ""
|
|
1050
|
+
] })
|
|
1051
|
+
]
|
|
1052
|
+
}
|
|
1053
|
+
)
|
|
584
1054
|
]
|
|
585
1055
|
}
|
|
586
1056
|
),
|
|
587
|
-
open && /* @__PURE__ */ (0, import_jsx_runtime.
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
1057
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1058
|
+
MutationDiffModal,
|
|
1059
|
+
{
|
|
1060
|
+
mutations,
|
|
1061
|
+
skillId,
|
|
1062
|
+
skillBody,
|
|
1063
|
+
visibleTools: iter.visibleTools,
|
|
1064
|
+
onClose: () => setOpen(false)
|
|
1065
|
+
}
|
|
1066
|
+
)
|
|
1067
|
+
]
|
|
1068
|
+
}
|
|
1069
|
+
);
|
|
1070
|
+
}
|
|
1071
|
+
function MutationDiffModal({
|
|
1072
|
+
mutations,
|
|
1073
|
+
skillId,
|
|
1074
|
+
skillBody,
|
|
1075
|
+
visibleTools,
|
|
1076
|
+
onClose
|
|
1077
|
+
}) {
|
|
1078
|
+
const t = useLensTheme();
|
|
1079
|
+
(0, import_react.useEffect)(() => {
|
|
1080
|
+
const onKey = (e) => {
|
|
1081
|
+
if (e.key === "Escape") onClose();
|
|
1082
|
+
};
|
|
1083
|
+
window.addEventListener("keydown", onKey);
|
|
1084
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
1085
|
+
}, [onClose]);
|
|
1086
|
+
const toolsToShow = mutations.toolsAddedList.length > 0 ? mutations.toolsAddedList : visibleTools;
|
|
1087
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1088
|
+
"div",
|
|
1089
|
+
{
|
|
1090
|
+
onClick: onClose,
|
|
1091
|
+
role: "dialog",
|
|
1092
|
+
"aria-modal": "true",
|
|
1093
|
+
style: {
|
|
1094
|
+
position: "fixed",
|
|
1095
|
+
inset: 0,
|
|
1096
|
+
background: "rgba(0, 0, 0, 0.55)",
|
|
1097
|
+
backdropFilter: "blur(4px)",
|
|
1098
|
+
WebkitBackdropFilter: "blur(4px)",
|
|
1099
|
+
display: "flex",
|
|
1100
|
+
alignItems: "center",
|
|
1101
|
+
justifyContent: "center",
|
|
1102
|
+
zIndex: 1e3,
|
|
1103
|
+
padding: 24
|
|
1104
|
+
},
|
|
1105
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1106
|
+
"div",
|
|
1107
|
+
{
|
|
1108
|
+
onClick: (e) => e.stopPropagation(),
|
|
1109
|
+
style: {
|
|
1110
|
+
background: t.bg,
|
|
1111
|
+
color: t.text,
|
|
1112
|
+
border: `1px solid ${t.border}`,
|
|
1113
|
+
borderRadius: 12,
|
|
1114
|
+
boxShadow: "0 24px 64px rgba(0, 0, 0, 0.45)",
|
|
1115
|
+
width: "min(880px, 100%)",
|
|
1116
|
+
maxHeight: "min(80dvh, 800px)",
|
|
1117
|
+
display: "flex",
|
|
1118
|
+
flexDirection: "column",
|
|
1119
|
+
fontFamily: t.fontSans
|
|
1120
|
+
},
|
|
1121
|
+
children: [
|
|
1122
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1123
|
+
"div",
|
|
594
1124
|
{
|
|
595
1125
|
style: {
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
1126
|
+
display: "flex",
|
|
1127
|
+
alignItems: "center",
|
|
1128
|
+
padding: "14px 18px",
|
|
1129
|
+
borderBottom: `1px solid ${t.border}`
|
|
1130
|
+
},
|
|
1131
|
+
children: [
|
|
1132
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { children: [
|
|
1133
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1134
|
+
"div",
|
|
1135
|
+
{
|
|
1136
|
+
style: {
|
|
1137
|
+
fontSize: 10,
|
|
1138
|
+
color: t.textSubtle,
|
|
1139
|
+
textTransform: "uppercase",
|
|
1140
|
+
letterSpacing: "0.08em",
|
|
1141
|
+
fontWeight: 600
|
|
1142
|
+
},
|
|
1143
|
+
children: "\u270E Changed in Neo's input"
|
|
1144
|
+
}
|
|
1145
|
+
),
|
|
1146
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { fontSize: 15, fontWeight: 600, marginTop: 2 }, children: [
|
|
1147
|
+
"Round diff",
|
|
1148
|
+
skillId && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1149
|
+
" \xB7 ",
|
|
1150
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1151
|
+
"code",
|
|
1152
|
+
{
|
|
1153
|
+
style: {
|
|
1154
|
+
fontFamily: t.fontMono,
|
|
1155
|
+
color: t.accent,
|
|
1156
|
+
fontWeight: 600
|
|
1157
|
+
},
|
|
1158
|
+
children: skillId
|
|
1159
|
+
}
|
|
1160
|
+
)
|
|
1161
|
+
] })
|
|
1162
|
+
] })
|
|
1163
|
+
] }),
|
|
1164
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
|
|
1165
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1166
|
+
"button",
|
|
1167
|
+
{
|
|
1168
|
+
onClick: onClose,
|
|
1169
|
+
title: "Close (Esc)",
|
|
1170
|
+
style: {
|
|
1171
|
+
background: "transparent",
|
|
1172
|
+
border: `1px solid ${t.border}`,
|
|
1173
|
+
color: t.textMuted,
|
|
1174
|
+
padding: "4px 10px",
|
|
1175
|
+
borderRadius: 6,
|
|
1176
|
+
cursor: "pointer",
|
|
1177
|
+
fontSize: 12,
|
|
1178
|
+
width: "auto"
|
|
1179
|
+
},
|
|
1180
|
+
children: "Esc"
|
|
1181
|
+
}
|
|
1182
|
+
)
|
|
1183
|
+
]
|
|
1184
|
+
}
|
|
1185
|
+
),
|
|
1186
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1187
|
+
"div",
|
|
1188
|
+
{
|
|
1189
|
+
style: {
|
|
1190
|
+
padding: 18,
|
|
604
1191
|
overflow: "auto",
|
|
605
|
-
|
|
1192
|
+
display: "flex",
|
|
1193
|
+
flexDirection: "column",
|
|
1194
|
+
gap: 16
|
|
606
1195
|
},
|
|
607
|
-
children:
|
|
1196
|
+
children: [
|
|
1197
|
+
mutations.systemPrompt && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
|
|
1198
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1199
|
+
"div",
|
|
1200
|
+
{
|
|
1201
|
+
style: {
|
|
1202
|
+
fontSize: 11,
|
|
1203
|
+
color: t.textSubtle,
|
|
1204
|
+
textTransform: "uppercase",
|
|
1205
|
+
letterSpacing: "0.08em",
|
|
1206
|
+
fontWeight: 600,
|
|
1207
|
+
marginBottom: 8
|
|
1208
|
+
},
|
|
1209
|
+
children: [
|
|
1210
|
+
"System Prompt",
|
|
1211
|
+
mutations.systemPromptDeltaChars > 0 && ` \xB7 +${mutations.systemPromptDeltaChars.toLocaleString()} chars`
|
|
1212
|
+
]
|
|
1213
|
+
}
|
|
1214
|
+
),
|
|
1215
|
+
skillBody ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1216
|
+
"pre",
|
|
1217
|
+
{
|
|
1218
|
+
style: {
|
|
1219
|
+
margin: 0,
|
|
1220
|
+
padding: "12px 14px",
|
|
1221
|
+
background: t.bgElev,
|
|
1222
|
+
border: `1px solid ${t.border}`,
|
|
1223
|
+
borderLeft: `3px solid ${t.accent}`,
|
|
1224
|
+
borderRadius: 6,
|
|
1225
|
+
fontSize: 12,
|
|
1226
|
+
lineHeight: 1.55,
|
|
1227
|
+
fontFamily: t.fontMono,
|
|
1228
|
+
color: t.text,
|
|
1229
|
+
whiteSpace: "pre-wrap"
|
|
1230
|
+
},
|
|
1231
|
+
children: skillBody
|
|
1232
|
+
}
|
|
1233
|
+
) : /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1234
|
+
"div",
|
|
1235
|
+
{
|
|
1236
|
+
style: {
|
|
1237
|
+
padding: "10px 12px",
|
|
1238
|
+
border: `1px dashed ${t.border}`,
|
|
1239
|
+
borderRadius: 6,
|
|
1240
|
+
color: t.textSubtle,
|
|
1241
|
+
fontStyle: "italic",
|
|
1242
|
+
fontSize: 12
|
|
1243
|
+
},
|
|
1244
|
+
children: [
|
|
1245
|
+
"System Prompt grew by ",
|
|
1246
|
+
mutations.systemPromptDeltaChars.toLocaleString(),
|
|
1247
|
+
" ",
|
|
1248
|
+
"chars but the source text isn't flowing through the adapter for this round."
|
|
1249
|
+
]
|
|
1250
|
+
}
|
|
1251
|
+
)
|
|
1252
|
+
] }),
|
|
1253
|
+
mutations.tools && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("section", { children: [
|
|
1254
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1255
|
+
"div",
|
|
1256
|
+
{
|
|
1257
|
+
style: {
|
|
1258
|
+
fontSize: 11,
|
|
1259
|
+
color: t.textSubtle,
|
|
1260
|
+
textTransform: "uppercase",
|
|
1261
|
+
letterSpacing: "0.08em",
|
|
1262
|
+
fontWeight: 600,
|
|
1263
|
+
marginBottom: 8
|
|
1264
|
+
},
|
|
1265
|
+
children: [
|
|
1266
|
+
"Tools",
|
|
1267
|
+
mutations.toolsAdded > 0 && ` \xB7 +${mutations.toolsAdded} added`,
|
|
1268
|
+
mutations.toolsRemoved > 0 && ` \xB7 -${mutations.toolsRemoved} removed`
|
|
1269
|
+
]
|
|
1270
|
+
}
|
|
1271
|
+
),
|
|
1272
|
+
toolsToShow.length > 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { display: "flex", flexWrap: "wrap", gap: 6 }, children: toolsToShow.map((name) => /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1273
|
+
"span",
|
|
1274
|
+
{
|
|
1275
|
+
style: {
|
|
1276
|
+
padding: "3px 9px",
|
|
1277
|
+
borderRadius: 4,
|
|
1278
|
+
background: t.bgElev,
|
|
1279
|
+
border: `1px solid ${t.border}`,
|
|
1280
|
+
color: t.text,
|
|
1281
|
+
fontFamily: t.fontMono,
|
|
1282
|
+
fontSize: 11
|
|
1283
|
+
},
|
|
1284
|
+
children: name
|
|
1285
|
+
},
|
|
1286
|
+
name
|
|
1287
|
+
)) }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1288
|
+
"div",
|
|
1289
|
+
{
|
|
1290
|
+
style: {
|
|
1291
|
+
padding: "10px 12px",
|
|
1292
|
+
border: `1px dashed ${t.border}`,
|
|
1293
|
+
borderRadius: 6,
|
|
1294
|
+
color: t.textSubtle,
|
|
1295
|
+
fontStyle: "italic",
|
|
1296
|
+
fontSize: 12
|
|
1297
|
+
},
|
|
1298
|
+
children: "The tool list that came online in this round isn't flowing through the adapter yet \u2014 counts are available, names aren't."
|
|
1299
|
+
}
|
|
1300
|
+
)
|
|
1301
|
+
] })
|
|
1302
|
+
]
|
|
608
1303
|
}
|
|
609
1304
|
)
|
|
610
|
-
]
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(JsonBlock, { value: invocation.decisionUpdate })
|
|
614
|
-
] })
|
|
615
|
-
] })
|
|
616
|
-
]
|
|
1305
|
+
]
|
|
1306
|
+
}
|
|
1307
|
+
)
|
|
617
1308
|
}
|
|
618
1309
|
);
|
|
619
1310
|
}
|
|
620
|
-
function
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
1311
|
+
function ContextDrawer({
|
|
1312
|
+
messagesSentCount,
|
|
1313
|
+
contextMessages,
|
|
1314
|
+
iter
|
|
624
1315
|
}) {
|
|
625
|
-
|
|
1316
|
+
const t = useLensTheme();
|
|
1317
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
626
1318
|
"div",
|
|
627
1319
|
{
|
|
628
1320
|
style: {
|
|
629
|
-
|
|
630
|
-
|
|
1321
|
+
border: `1px dashed ${t.border}`,
|
|
1322
|
+
borderRadius: t.radius,
|
|
1323
|
+
padding: "10px 12px",
|
|
1324
|
+
background: t.bg,
|
|
1325
|
+
fontSize: 12,
|
|
1326
|
+
color: t.textMuted
|
|
1327
|
+
},
|
|
1328
|
+
children: [
|
|
1329
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1330
|
+
"div",
|
|
1331
|
+
{
|
|
1332
|
+
style: {
|
|
1333
|
+
fontSize: 10,
|
|
1334
|
+
color: t.textSubtle,
|
|
1335
|
+
textTransform: "uppercase",
|
|
1336
|
+
letterSpacing: "0.08em",
|
|
1337
|
+
fontWeight: 600,
|
|
1338
|
+
marginBottom: 8
|
|
1339
|
+
},
|
|
1340
|
+
children: "What Neo saw before this step"
|
|
1341
|
+
}
|
|
1342
|
+
),
|
|
1343
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { color: t.text, marginBottom: 8 }, children: [
|
|
1344
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("strong", { children: messagesSentCount }),
|
|
1345
|
+
" message",
|
|
1346
|
+
messagesSentCount === 1 ? "" : "s",
|
|
1347
|
+
" in context",
|
|
1348
|
+
iter.model ? ` \xB7 sent to ${iter.model}` : "",
|
|
1349
|
+
iter.inputTokens !== void 0 && ` \xB7 ${iter.inputTokens} input tokens`
|
|
1350
|
+
] }),
|
|
1351
|
+
contextMessages.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime.jsx)("div", { style: { color: t.textSubtle, fontStyle: "italic" }, children: "Just the system configuration \u2014 this is the first call of the conversation." }) : /* @__PURE__ */ (0, import_jsx_runtime.jsx)("ol", { style: { margin: 0, paddingLeft: 18, display: "flex", flexDirection: "column", gap: 6 }, children: contextMessages.map((m, i) => /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("li", { style: { fontSize: 12 }, children: [
|
|
1352
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1353
|
+
"span",
|
|
1354
|
+
{
|
|
1355
|
+
style: {
|
|
1356
|
+
display: "inline-block",
|
|
1357
|
+
padding: "1px 6px",
|
|
1358
|
+
borderRadius: 3,
|
|
1359
|
+
background: m.role === "user" ? `color-mix(in srgb, ${t.accent} 20%, transparent)` : m.role === "assistant" ? t.bgElev : m.role === "tool" ? `color-mix(in srgb, ${t.success} 18%, transparent)` : t.bgElev,
|
|
1360
|
+
color: m.role === "user" ? t.accent : m.role === "tool" ? t.success : t.text,
|
|
1361
|
+
fontFamily: t.fontMono,
|
|
1362
|
+
fontSize: 10,
|
|
1363
|
+
fontWeight: 600,
|
|
1364
|
+
textTransform: "uppercase",
|
|
1365
|
+
marginRight: 6
|
|
1366
|
+
},
|
|
1367
|
+
children: m.role
|
|
1368
|
+
}
|
|
1369
|
+
),
|
|
1370
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: t.textMuted }, children: summarizeMessage(m) })
|
|
1371
|
+
] }, i)) }),
|
|
1372
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1373
|
+
"div",
|
|
1374
|
+
{
|
|
1375
|
+
style: {
|
|
1376
|
+
marginTop: 10,
|
|
1377
|
+
fontSize: 11,
|
|
1378
|
+
color: t.textSubtle,
|
|
1379
|
+
fontStyle: "italic"
|
|
1380
|
+
},
|
|
1381
|
+
children: "Plus the system configuration (see top of conversation) and the tools Neo had access to."
|
|
1382
|
+
}
|
|
1383
|
+
)
|
|
1384
|
+
]
|
|
1385
|
+
}
|
|
1386
|
+
);
|
|
1387
|
+
}
|
|
1388
|
+
function summarizeMessage(m) {
|
|
1389
|
+
if (m.role === "tool") {
|
|
1390
|
+
return `tool result (${m.content.length.toLocaleString()} chars)`;
|
|
1391
|
+
}
|
|
1392
|
+
const t = m.content.replace(/\s+/g, " ").trim();
|
|
1393
|
+
return t.length > 120 ? t.slice(0, 120) + "\u2026" : t;
|
|
1394
|
+
}
|
|
1395
|
+
function ToolCallCard({
|
|
1396
|
+
invocation,
|
|
1397
|
+
onClick,
|
|
1398
|
+
resultRevealed = true
|
|
1399
|
+
}) {
|
|
1400
|
+
const t = useLensTheme();
|
|
1401
|
+
const [open, setOpen] = (0, import_react.useState)(false);
|
|
1402
|
+
const preview = shortArgs(invocation.arguments);
|
|
1403
|
+
const errored = invocation.error === true;
|
|
1404
|
+
const friendlyVerb = toolVerb(invocation);
|
|
1405
|
+
const borderStyle = resultRevealed ? "solid" : "dashed";
|
|
1406
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1407
|
+
"div",
|
|
1408
|
+
{
|
|
1409
|
+
style: {
|
|
1410
|
+
border: `1px ${borderStyle} ${errored ? t.error : t.border}`,
|
|
1411
|
+
borderLeft: `3px ${borderStyle} ${errored ? t.error : t.accent}`,
|
|
1412
|
+
borderRadius: 6,
|
|
1413
|
+
background: t.bg,
|
|
1414
|
+
overflow: "hidden"
|
|
1415
|
+
},
|
|
1416
|
+
children: [
|
|
1417
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsxs)(
|
|
1418
|
+
"div",
|
|
1419
|
+
{
|
|
1420
|
+
onClick: () => {
|
|
1421
|
+
setOpen((v) => !v);
|
|
1422
|
+
onClick?.(invocation);
|
|
1423
|
+
},
|
|
1424
|
+
style: {
|
|
1425
|
+
padding: "8px 12px",
|
|
1426
|
+
cursor: "pointer",
|
|
1427
|
+
display: "flex",
|
|
1428
|
+
alignItems: "center",
|
|
1429
|
+
gap: 10,
|
|
1430
|
+
fontSize: 12
|
|
1431
|
+
},
|
|
1432
|
+
children: [
|
|
1433
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: t.textMuted, fontFamily: t.fontSans }, children: friendlyVerb }),
|
|
1434
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: errored ? t.error : t.accent, fontWeight: 600, fontFamily: t.fontMono }, children: invocation.name }),
|
|
1435
|
+
preview && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("span", { style: { color: t.textMuted, fontFamily: t.fontMono }, children: [
|
|
1436
|
+
"(",
|
|
1437
|
+
preview,
|
|
1438
|
+
")"
|
|
1439
|
+
] }),
|
|
1440
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { flex: 1 } }),
|
|
1441
|
+
!resultRevealed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1442
|
+
"span",
|
|
1443
|
+
{
|
|
1444
|
+
style: {
|
|
1445
|
+
fontSize: 10,
|
|
1446
|
+
padding: "1px 6px",
|
|
1447
|
+
borderRadius: 3,
|
|
1448
|
+
background: `color-mix(in srgb, ${t.accent} 18%, transparent)`,
|
|
1449
|
+
color: t.accent,
|
|
1450
|
+
fontWeight: 600,
|
|
1451
|
+
textTransform: "uppercase",
|
|
1452
|
+
letterSpacing: "0.04em"
|
|
1453
|
+
},
|
|
1454
|
+
title: "Args sent; waiting for the tool to return",
|
|
1455
|
+
children: "in flight"
|
|
1456
|
+
}
|
|
1457
|
+
),
|
|
1458
|
+
invocation.decisionUpdate && Object.keys(invocation.decisionUpdate).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1459
|
+
"span",
|
|
1460
|
+
{
|
|
1461
|
+
style: {
|
|
1462
|
+
fontSize: 10,
|
|
1463
|
+
padding: "1px 6px",
|
|
1464
|
+
borderRadius: 3,
|
|
1465
|
+
background: `color-mix(in srgb, ${t.warning} 20%, transparent)`,
|
|
1466
|
+
color: t.warning,
|
|
1467
|
+
fontWeight: 600,
|
|
1468
|
+
textTransform: "uppercase"
|
|
1469
|
+
},
|
|
1470
|
+
title: "This tool changed what skill is active",
|
|
1471
|
+
children: "skill change"
|
|
1472
|
+
}
|
|
1473
|
+
),
|
|
1474
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)("span", { style: { color: t.textSubtle }, children: open ? "\u25BE" : "\u25B8" })
|
|
1475
|
+
]
|
|
1476
|
+
}
|
|
1477
|
+
),
|
|
1478
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)("div", { style: { padding: "8px 12px", borderTop: `1px solid ${t.border}` }, children: [
|
|
1479
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, { t, children: "What Neo asked for" }),
|
|
1480
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(JsonBlock, { value: invocation.arguments }),
|
|
1481
|
+
resultRevealed && invocation.result && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1482
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, { t, style: { marginTop: 10 }, children: "What the tool returned" }),
|
|
1483
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1484
|
+
"pre",
|
|
1485
|
+
{
|
|
1486
|
+
style: {
|
|
1487
|
+
margin: 0,
|
|
1488
|
+
padding: "8px 10px",
|
|
1489
|
+
background: t.bgElev,
|
|
1490
|
+
borderRadius: 4,
|
|
1491
|
+
fontSize: 11,
|
|
1492
|
+
fontFamily: t.fontMono,
|
|
1493
|
+
color: errored ? t.error : t.text,
|
|
1494
|
+
maxHeight: 280,
|
|
1495
|
+
overflow: "auto",
|
|
1496
|
+
whiteSpace: "pre-wrap"
|
|
1497
|
+
},
|
|
1498
|
+
children: invocation.result
|
|
1499
|
+
}
|
|
1500
|
+
)
|
|
1501
|
+
] }),
|
|
1502
|
+
!resultRevealed && /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1503
|
+
"div",
|
|
1504
|
+
{
|
|
1505
|
+
style: {
|
|
1506
|
+
marginTop: 10,
|
|
1507
|
+
padding: "10px 12px",
|
|
1508
|
+
border: `1px dashed ${t.border}`,
|
|
1509
|
+
borderRadius: 4,
|
|
1510
|
+
fontSize: 12,
|
|
1511
|
+
color: t.textSubtle,
|
|
1512
|
+
fontStyle: "italic"
|
|
1513
|
+
},
|
|
1514
|
+
children: "Neo has sent the args; advance the slider to see the result this tool returned."
|
|
1515
|
+
}
|
|
1516
|
+
),
|
|
1517
|
+
resultRevealed && invocation.decisionUpdate && Object.keys(invocation.decisionUpdate).length > 0 && /* @__PURE__ */ (0, import_jsx_runtime.jsxs)(import_jsx_runtime.Fragment, { children: [
|
|
1518
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(Label, { t, style: { marginTop: 10 }, children: "What changed in Neo's state" }),
|
|
1519
|
+
/* @__PURE__ */ (0, import_jsx_runtime.jsx)(JsonBlock, { value: invocation.decisionUpdate })
|
|
1520
|
+
] })
|
|
1521
|
+
] })
|
|
1522
|
+
]
|
|
1523
|
+
}
|
|
1524
|
+
);
|
|
1525
|
+
}
|
|
1526
|
+
function toolVerb(inv) {
|
|
1527
|
+
if (inv.name === "list_skills") return "Asked for";
|
|
1528
|
+
if (inv.name === "read_skill") return "Activated";
|
|
1529
|
+
if (inv.name === "ask_human" || inv.name === "ask_user") return "Asked user for";
|
|
1530
|
+
return "Called tool";
|
|
1531
|
+
}
|
|
1532
|
+
function Label({
|
|
1533
|
+
t,
|
|
1534
|
+
children,
|
|
1535
|
+
style
|
|
1536
|
+
}) {
|
|
1537
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1538
|
+
"div",
|
|
1539
|
+
{
|
|
1540
|
+
style: {
|
|
1541
|
+
fontSize: 10,
|
|
1542
|
+
color: t.textSubtle,
|
|
1543
|
+
textTransform: "uppercase",
|
|
1544
|
+
letterSpacing: "0.08em",
|
|
1545
|
+
fontWeight: 600,
|
|
1546
|
+
marginBottom: 4,
|
|
1547
|
+
...style
|
|
1548
|
+
},
|
|
1549
|
+
children
|
|
1550
|
+
}
|
|
1551
|
+
);
|
|
1552
|
+
}
|
|
1553
|
+
function JsonBlock({ value }) {
|
|
1554
|
+
const t = useLensTheme();
|
|
1555
|
+
return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(
|
|
1556
|
+
"pre",
|
|
1557
|
+
{
|
|
1558
|
+
style: {
|
|
1559
|
+
margin: 0,
|
|
1560
|
+
padding: "8px 10px",
|
|
1561
|
+
background: t.bgElev,
|
|
1562
|
+
borderRadius: 4,
|
|
1563
|
+
fontSize: 11,
|
|
1564
|
+
fontFamily: t.fontMono,
|
|
1565
|
+
color: t.text,
|
|
1566
|
+
maxHeight: 200,
|
|
1567
|
+
overflow: "auto"
|
|
1568
|
+
},
|
|
1569
|
+
children: JSON.stringify(value, null, 2)
|
|
1570
|
+
}
|
|
1571
|
+
);
|
|
1572
|
+
}
|
|
1573
|
+
function shortArgs(args) {
|
|
1574
|
+
const keys = Object.keys(args);
|
|
1575
|
+
if (keys.length === 0) return "";
|
|
1576
|
+
if (keys.length === 1) {
|
|
1577
|
+
const v = args[keys[0]];
|
|
1578
|
+
if (typeof v === "string" && v.length < 40) return `${keys[0]}: "${v}"`;
|
|
1579
|
+
}
|
|
1580
|
+
return keys.join(", ");
|
|
1581
|
+
}
|
|
1582
|
+
function useIterationStageRanges(stages) {
|
|
1583
|
+
return import_react.default.useMemo(() => {
|
|
1584
|
+
const map = /* @__PURE__ */ new Map();
|
|
1585
|
+
if (!stages?.length) return map;
|
|
1586
|
+
const turnIters = /* @__PURE__ */ new Map();
|
|
1587
|
+
for (const s of stages) {
|
|
1588
|
+
if (s.iterIndex === void 0) continue;
|
|
1589
|
+
const list = turnIters.get(s.turnIndex) ?? [];
|
|
1590
|
+
if (!list.includes(s.iterIndex)) list.push(s.iterIndex);
|
|
1591
|
+
turnIters.set(s.turnIndex, list);
|
|
1592
|
+
}
|
|
1593
|
+
stages.forEach((s, idx) => {
|
|
1594
|
+
let iter = s.iterIndex;
|
|
1595
|
+
if (iter === void 0) {
|
|
1596
|
+
const iters = turnIters.get(s.turnIndex);
|
|
1597
|
+
if (!iters?.length) return;
|
|
1598
|
+
iter = s.from === "user" ? iters[0] : iters[iters.length - 1];
|
|
1599
|
+
}
|
|
1600
|
+
const key = `${s.turnIndex}.${iter}`;
|
|
1601
|
+
const prev = map.get(key);
|
|
1602
|
+
if (!prev) {
|
|
1603
|
+
map.set(key, { firstStageIndex: idx, lastStageIndex: idx });
|
|
1604
|
+
} else {
|
|
1605
|
+
map.set(key, {
|
|
1606
|
+
firstStageIndex: Math.min(prev.firstStageIndex, idx),
|
|
1607
|
+
lastStageIndex: Math.max(prev.lastStageIndex, idx)
|
|
1608
|
+
});
|
|
1609
|
+
}
|
|
1610
|
+
});
|
|
1611
|
+
return map;
|
|
1612
|
+
}, [stages]);
|
|
1613
|
+
}
|
|
1614
|
+
function keyForStage(ranges, focusIndex) {
|
|
1615
|
+
for (const [key, r] of ranges) {
|
|
1616
|
+
if (focusIndex >= r.firstStageIndex && focusIndex <= r.lastStageIndex) return key;
|
|
1617
|
+
}
|
|
1618
|
+
return null;
|
|
1619
|
+
}
|
|
1620
|
+
|
|
1621
|
+
// src/panels/SkillsPanel.tsx
|
|
1622
|
+
var import_react2 = require("react");
|
|
1623
|
+
var import_jsx_runtime2 = require("react/jsx-runtime");
|
|
1624
|
+
function SkillsPanel({ skills, onClose, activeSkillId }) {
|
|
1625
|
+
const t = useLensTheme();
|
|
1626
|
+
const [selectedId, setSelectedId] = (0, import_react2.useState)(
|
|
1627
|
+
activeSkillId ?? skills[0]?.id ?? null
|
|
1628
|
+
);
|
|
1629
|
+
const [mode, setMode] = (0, import_react2.useState)("formatted");
|
|
1630
|
+
const selected = skills.find((s) => s.id === selectedId) ?? null;
|
|
1631
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1632
|
+
"div",
|
|
1633
|
+
{
|
|
1634
|
+
onClick: onClose,
|
|
1635
|
+
style: {
|
|
1636
|
+
position: "absolute",
|
|
1637
|
+
inset: 0,
|
|
1638
|
+
background: "rgba(0, 0, 0, 0.5)",
|
|
1639
|
+
zIndex: 100,
|
|
1640
|
+
display: "flex",
|
|
1641
|
+
alignItems: "stretch",
|
|
1642
|
+
justifyContent: "stretch"
|
|
1643
|
+
},
|
|
1644
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1645
|
+
"div",
|
|
1646
|
+
{
|
|
1647
|
+
onClick: (e) => e.stopPropagation(),
|
|
1648
|
+
style: {
|
|
1649
|
+
display: "grid",
|
|
1650
|
+
gridTemplateColumns: "minmax(220px, 280px) 1fr",
|
|
1651
|
+
gridTemplateRows: "auto 1fr",
|
|
1652
|
+
gridTemplateAreas: '"header header" "list detail"',
|
|
1653
|
+
width: "100%",
|
|
1654
|
+
height: "100%",
|
|
1655
|
+
background: t.bg,
|
|
1656
|
+
color: t.text,
|
|
1657
|
+
fontFamily: t.fontSans,
|
|
1658
|
+
border: `1px solid ${t.border}`
|
|
1659
|
+
},
|
|
1660
|
+
children: [
|
|
1661
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1662
|
+
"div",
|
|
1663
|
+
{
|
|
1664
|
+
style: {
|
|
1665
|
+
gridArea: "header",
|
|
1666
|
+
padding: "10px 14px",
|
|
1667
|
+
borderBottom: `1px solid ${t.border}`,
|
|
1668
|
+
background: t.bgElev,
|
|
1669
|
+
display: "flex",
|
|
1670
|
+
alignItems: "center",
|
|
1671
|
+
gap: 10
|
|
1672
|
+
},
|
|
1673
|
+
children: [
|
|
1674
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("strong", { style: { color: t.text, fontSize: 13 }, children: "Skills registered with Neo" }),
|
|
1675
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t.textMuted, fontSize: 12 }, children: [
|
|
1676
|
+
skills.length,
|
|
1677
|
+
" total"
|
|
1678
|
+
] }),
|
|
1679
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { flex: 1 } }),
|
|
1680
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1681
|
+
"button",
|
|
1682
|
+
{
|
|
1683
|
+
onClick: onClose,
|
|
1684
|
+
style: {
|
|
1685
|
+
background: "transparent",
|
|
1686
|
+
border: `1px solid ${t.border}`,
|
|
1687
|
+
color: t.textMuted,
|
|
1688
|
+
borderRadius: 4,
|
|
1689
|
+
padding: "2px 10px",
|
|
1690
|
+
cursor: "pointer",
|
|
1691
|
+
fontSize: 14,
|
|
1692
|
+
width: "auto",
|
|
1693
|
+
fontWeight: 400
|
|
1694
|
+
},
|
|
1695
|
+
title: "Close (Esc)",
|
|
1696
|
+
children: "\u2715"
|
|
1697
|
+
}
|
|
1698
|
+
)
|
|
1699
|
+
]
|
|
1700
|
+
}
|
|
1701
|
+
),
|
|
1702
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1703
|
+
"div",
|
|
1704
|
+
{
|
|
1705
|
+
style: {
|
|
1706
|
+
gridArea: "list",
|
|
1707
|
+
borderRight: `1px solid ${t.border}`,
|
|
1708
|
+
overflow: "auto",
|
|
1709
|
+
background: t.bg
|
|
1710
|
+
},
|
|
1711
|
+
children: [
|
|
1712
|
+
skills.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { padding: 14, color: t.textSubtle, fontSize: 12 }, children: "No skills registered." }),
|
|
1713
|
+
skills.map((s) => {
|
|
1714
|
+
const isActive = s.id === selectedId;
|
|
1715
|
+
const isAgentActive = s.id === activeSkillId;
|
|
1716
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1717
|
+
"button",
|
|
1718
|
+
{
|
|
1719
|
+
onClick: () => setSelectedId(s.id),
|
|
1720
|
+
style: {
|
|
1721
|
+
display: "block",
|
|
1722
|
+
width: "100%",
|
|
1723
|
+
textAlign: "left",
|
|
1724
|
+
padding: "10px 14px",
|
|
1725
|
+
background: isActive ? t.bgHover : "transparent",
|
|
1726
|
+
border: "none",
|
|
1727
|
+
borderLeft: `3px solid ${isActive ? t.accent : isAgentActive ? t.success : "transparent"}`,
|
|
1728
|
+
borderBottom: `1px solid ${t.border}`,
|
|
1729
|
+
color: t.text,
|
|
1730
|
+
cursor: "pointer",
|
|
1731
|
+
fontFamily: "inherit"
|
|
1732
|
+
},
|
|
1733
|
+
children: [
|
|
1734
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1735
|
+
"div",
|
|
1736
|
+
{
|
|
1737
|
+
style: {
|
|
1738
|
+
display: "flex",
|
|
1739
|
+
alignItems: "baseline",
|
|
1740
|
+
gap: 6,
|
|
1741
|
+
fontSize: 13
|
|
1742
|
+
},
|
|
1743
|
+
children: [
|
|
1744
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { fontWeight: 600 }, children: s.title ?? s.id }),
|
|
1745
|
+
isAgentActive && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1746
|
+
"span",
|
|
1747
|
+
{
|
|
1748
|
+
style: {
|
|
1749
|
+
fontSize: 9,
|
|
1750
|
+
padding: "1px 5px",
|
|
1751
|
+
borderRadius: 3,
|
|
1752
|
+
background: `color-mix(in srgb, ${t.success} 25%, transparent)`,
|
|
1753
|
+
color: t.success,
|
|
1754
|
+
fontWeight: 600,
|
|
1755
|
+
textTransform: "uppercase"
|
|
1756
|
+
},
|
|
1757
|
+
children: "active"
|
|
1758
|
+
}
|
|
1759
|
+
)
|
|
1760
|
+
]
|
|
1761
|
+
}
|
|
1762
|
+
),
|
|
1763
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1764
|
+
"div",
|
|
1765
|
+
{
|
|
1766
|
+
style: {
|
|
1767
|
+
fontSize: 10,
|
|
1768
|
+
color: t.textSubtle,
|
|
1769
|
+
fontFamily: t.fontMono,
|
|
1770
|
+
marginTop: 1
|
|
1771
|
+
},
|
|
1772
|
+
children: [
|
|
1773
|
+
s.id,
|
|
1774
|
+
s.version && ` \xB7 v${s.version}`
|
|
1775
|
+
]
|
|
1776
|
+
}
|
|
1777
|
+
),
|
|
1778
|
+
s.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1779
|
+
"div",
|
|
1780
|
+
{
|
|
1781
|
+
style: {
|
|
1782
|
+
fontSize: 11,
|
|
1783
|
+
color: t.textMuted,
|
|
1784
|
+
marginTop: 4,
|
|
1785
|
+
lineHeight: 1.4,
|
|
1786
|
+
display: "-webkit-box",
|
|
1787
|
+
WebkitLineClamp: 3,
|
|
1788
|
+
WebkitBoxOrient: "vertical",
|
|
1789
|
+
overflow: "hidden"
|
|
1790
|
+
},
|
|
1791
|
+
children: s.description
|
|
1792
|
+
}
|
|
1793
|
+
)
|
|
1794
|
+
]
|
|
1795
|
+
},
|
|
1796
|
+
s.id
|
|
1797
|
+
);
|
|
1798
|
+
})
|
|
1799
|
+
]
|
|
1800
|
+
}
|
|
1801
|
+
),
|
|
1802
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1803
|
+
"div",
|
|
1804
|
+
{
|
|
1805
|
+
style: {
|
|
1806
|
+
gridArea: "detail",
|
|
1807
|
+
overflow: "auto",
|
|
1808
|
+
padding: "14px 18px",
|
|
1809
|
+
fontSize: 13,
|
|
1810
|
+
lineHeight: 1.6
|
|
1811
|
+
},
|
|
1812
|
+
children: !selected ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: t.textSubtle }, children: "Select a skill to see details." }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(import_jsx_runtime2.Fragment, { children: [
|
|
1813
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", alignItems: "baseline", gap: 10, marginBottom: 10 }, children: [
|
|
1814
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("h2", { style: { margin: 0, fontSize: 18, color: t.text }, children: selected.title ?? selected.id }),
|
|
1815
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("span", { style: { color: t.textSubtle, fontFamily: t.fontMono, fontSize: 11 }, children: [
|
|
1816
|
+
selected.id,
|
|
1817
|
+
selected.version && ` \xB7 v${selected.version}`
|
|
1818
|
+
] }),
|
|
1819
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("span", { style: { flex: 1 } }),
|
|
1820
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(
|
|
1821
|
+
"div",
|
|
1822
|
+
{
|
|
1823
|
+
role: "tablist",
|
|
1824
|
+
style: {
|
|
1825
|
+
display: "flex",
|
|
1826
|
+
gap: 1,
|
|
1827
|
+
border: `1px solid ${t.border}`,
|
|
1828
|
+
borderRadius: 4,
|
|
1829
|
+
overflow: "hidden"
|
|
1830
|
+
},
|
|
1831
|
+
children: [
|
|
1832
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1833
|
+
"button",
|
|
1834
|
+
{
|
|
1835
|
+
onClick: () => setMode("formatted"),
|
|
1836
|
+
style: {
|
|
1837
|
+
padding: "3px 10px",
|
|
1838
|
+
fontSize: 11,
|
|
1839
|
+
background: mode === "formatted" ? t.accent : "transparent",
|
|
1840
|
+
color: mode === "formatted" ? "#fff" : t.textMuted,
|
|
1841
|
+
border: "none",
|
|
1842
|
+
cursor: "pointer",
|
|
1843
|
+
width: "auto",
|
|
1844
|
+
fontWeight: 400
|
|
1845
|
+
},
|
|
1846
|
+
children: "Formatted"
|
|
1847
|
+
}
|
|
1848
|
+
),
|
|
1849
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1850
|
+
"button",
|
|
1851
|
+
{
|
|
1852
|
+
onClick: () => setMode("json"),
|
|
1853
|
+
style: {
|
|
1854
|
+
padding: "3px 10px",
|
|
1855
|
+
fontSize: 11,
|
|
1856
|
+
background: mode === "json" ? t.accent : "transparent",
|
|
1857
|
+
color: mode === "json" ? "#fff" : t.textMuted,
|
|
1858
|
+
border: "none",
|
|
1859
|
+
cursor: "pointer",
|
|
1860
|
+
width: "auto",
|
|
1861
|
+
fontWeight: 400
|
|
1862
|
+
},
|
|
1863
|
+
children: "Raw JSON"
|
|
1864
|
+
}
|
|
1865
|
+
)
|
|
1866
|
+
]
|
|
1867
|
+
}
|
|
1868
|
+
)
|
|
1869
|
+
] }),
|
|
1870
|
+
mode === "formatted" ? /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SkillFormatted, { skill: selected }) : /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(SkillJson, { skill: selected })
|
|
1871
|
+
] })
|
|
1872
|
+
}
|
|
1873
|
+
)
|
|
1874
|
+
]
|
|
1875
|
+
}
|
|
1876
|
+
)
|
|
1877
|
+
}
|
|
1878
|
+
);
|
|
1879
|
+
}
|
|
1880
|
+
function SkillFormatted({ skill }) {
|
|
1881
|
+
const t = useLensTheme();
|
|
1882
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("div", { style: { display: "flex", flexDirection: "column", gap: 12 }, children: [
|
|
1883
|
+
skill.description && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { children: [
|
|
1884
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Label2, { t, children: "Description" }),
|
|
1885
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { color: t.text }, children: skill.description })
|
|
1886
|
+
] }),
|
|
1887
|
+
skill.scope && skill.scope.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { children: [
|
|
1888
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Label2, { t, children: "Scope" }),
|
|
1889
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" }, children: skill.scope.map((s) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1890
|
+
"span",
|
|
1891
|
+
{
|
|
1892
|
+
style: {
|
|
1893
|
+
padding: "2px 8px",
|
|
1894
|
+
background: t.bgElev,
|
|
1895
|
+
border: `1px solid ${t.border}`,
|
|
1896
|
+
borderRadius: 3,
|
|
1897
|
+
fontSize: 11,
|
|
1898
|
+
fontFamily: t.fontMono,
|
|
1899
|
+
color: t.textMuted
|
|
1900
|
+
},
|
|
1901
|
+
children: s
|
|
1902
|
+
},
|
|
1903
|
+
s
|
|
1904
|
+
)) })
|
|
1905
|
+
] }),
|
|
1906
|
+
skill.tools && skill.tools.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { children: [
|
|
1907
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsxs)(Label2, { t, children: [
|
|
1908
|
+
"Tools this skill exposes \xB7 ",
|
|
1909
|
+
skill.tools.length
|
|
1910
|
+
] }),
|
|
1911
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" }, children: skill.tools.map((id) => /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1912
|
+
"span",
|
|
1913
|
+
{
|
|
1914
|
+
style: {
|
|
1915
|
+
padding: "2px 8px",
|
|
1916
|
+
background: `color-mix(in srgb, ${t.accent} 15%, transparent)`,
|
|
1917
|
+
border: `1px solid ${t.border}`,
|
|
1918
|
+
borderRadius: 3,
|
|
1919
|
+
fontSize: 11,
|
|
1920
|
+
fontFamily: t.fontMono,
|
|
1921
|
+
color: t.accent
|
|
1922
|
+
},
|
|
1923
|
+
children: id
|
|
1924
|
+
},
|
|
1925
|
+
id
|
|
1926
|
+
)) }),
|
|
1927
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)("div", { style: { fontSize: 11, color: t.textSubtle, marginTop: 4, fontStyle: "italic" }, children: "Only these tools reach the LLM while this skill is active (autoActivate)." })
|
|
1928
|
+
] }),
|
|
1929
|
+
skill.body && /* @__PURE__ */ (0, import_jsx_runtime2.jsxs)("section", { children: [
|
|
1930
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(Label2, { t, children: "Body (sent to LLM on read_skill)" }),
|
|
1931
|
+
/* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1932
|
+
"pre",
|
|
1933
|
+
{
|
|
1934
|
+
style: {
|
|
1935
|
+
margin: 0,
|
|
1936
|
+
padding: "10px 12px",
|
|
1937
|
+
background: t.bgElev,
|
|
1938
|
+
border: `1px solid ${t.border}`,
|
|
1939
|
+
borderRadius: 4,
|
|
1940
|
+
fontSize: 12,
|
|
1941
|
+
lineHeight: 1.55,
|
|
1942
|
+
fontFamily: t.fontMono,
|
|
1943
|
+
whiteSpace: "pre-wrap",
|
|
1944
|
+
color: t.text,
|
|
1945
|
+
maxHeight: 480,
|
|
1946
|
+
overflow: "auto"
|
|
1947
|
+
},
|
|
1948
|
+
children: skill.body
|
|
1949
|
+
}
|
|
1950
|
+
)
|
|
1951
|
+
] })
|
|
1952
|
+
] });
|
|
1953
|
+
}
|
|
1954
|
+
function SkillJson({ skill }) {
|
|
1955
|
+
const t = useLensTheme();
|
|
1956
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
1957
|
+
"pre",
|
|
1958
|
+
{
|
|
1959
|
+
style: {
|
|
1960
|
+
margin: 0,
|
|
1961
|
+
padding: "10px 12px",
|
|
1962
|
+
background: t.bgElev,
|
|
1963
|
+
border: `1px solid ${t.border}`,
|
|
1964
|
+
borderRadius: 4,
|
|
1965
|
+
fontSize: 12,
|
|
1966
|
+
lineHeight: 1.55,
|
|
1967
|
+
fontFamily: t.fontMono,
|
|
1968
|
+
whiteSpace: "pre-wrap",
|
|
1969
|
+
color: t.text,
|
|
1970
|
+
maxHeight: "calc(100vh - 200px)",
|
|
1971
|
+
overflow: "auto"
|
|
1972
|
+
},
|
|
1973
|
+
children: safeJsonStringify(skill)
|
|
1974
|
+
}
|
|
1975
|
+
);
|
|
1976
|
+
}
|
|
1977
|
+
function safeJsonStringify(value) {
|
|
1978
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
1979
|
+
try {
|
|
1980
|
+
return JSON.stringify(
|
|
1981
|
+
value,
|
|
1982
|
+
(_k, v) => {
|
|
1983
|
+
if (typeof v === "object" && v !== null) {
|
|
1984
|
+
if (seen.has(v)) return "[Circular]";
|
|
1985
|
+
seen.add(v);
|
|
1986
|
+
}
|
|
1987
|
+
if (typeof v === "function") return `[function ${v.name || "anonymous"}]`;
|
|
1988
|
+
return v;
|
|
1989
|
+
},
|
|
1990
|
+
2
|
|
1991
|
+
);
|
|
1992
|
+
} catch (err) {
|
|
1993
|
+
return `[stringify error: ${err instanceof Error ? err.message : String(err)}]`;
|
|
1994
|
+
}
|
|
1995
|
+
}
|
|
1996
|
+
function Label2({
|
|
1997
|
+
t,
|
|
1998
|
+
children
|
|
1999
|
+
}) {
|
|
2000
|
+
return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
|
|
2001
|
+
"div",
|
|
2002
|
+
{
|
|
2003
|
+
style: {
|
|
2004
|
+
fontSize: 10,
|
|
2005
|
+
color: t.textSubtle,
|
|
2006
|
+
textTransform: "uppercase",
|
|
2007
|
+
letterSpacing: "0.08em",
|
|
2008
|
+
fontWeight: 600,
|
|
2009
|
+
marginBottom: 4
|
|
2010
|
+
},
|
|
2011
|
+
children
|
|
2012
|
+
}
|
|
2013
|
+
);
|
|
2014
|
+
}
|
|
2015
|
+
|
|
2016
|
+
// src/panels/StageFlow.tsx
|
|
2017
|
+
var import_react3 = require("react");
|
|
2018
|
+
var import_react4 = require("@xyflow/react");
|
|
2019
|
+
var import_style = require("@xyflow/react/dist/style.css");
|
|
2020
|
+
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
2021
|
+
var NODE_POSITIONS = {
|
|
2022
|
+
user: { x: 100, y: 20 },
|
|
2023
|
+
agent: { x: 100, y: 160 },
|
|
2024
|
+
tool: { x: 100, y: 380 },
|
|
2025
|
+
skill: { x: 320, y: 380 }
|
|
2026
|
+
};
|
|
2027
|
+
function pickHandles(from, to) {
|
|
2028
|
+
if (from === "user" && to === "agent") return { sourceHandle: "b-out", targetHandle: "t-in" };
|
|
2029
|
+
if (from === "agent" && to === "user") return { sourceHandle: "t-out", targetHandle: "b-in" };
|
|
2030
|
+
if (from === "agent" && to === "tool") return { sourceHandle: "b-out", targetHandle: "t-in" };
|
|
2031
|
+
if (from === "tool" && to === "agent") return { sourceHandle: "t-out", targetHandle: "b-in" };
|
|
2032
|
+
if (from === "agent" && to === "skill") return { sourceHandle: "r-out", targetHandle: "l-in" };
|
|
2033
|
+
if (from === "skill" && to === "agent") return { sourceHandle: "l-out", targetHandle: "r-in" };
|
|
2034
|
+
return { sourceHandle: "r-out", targetHandle: "l-in" };
|
|
2035
|
+
}
|
|
2036
|
+
var NODE_LABELS = {
|
|
2037
|
+
user: "User",
|
|
2038
|
+
agent: "Agent",
|
|
2039
|
+
tool: "Tool",
|
|
2040
|
+
skill: "Skill"
|
|
2041
|
+
};
|
|
2042
|
+
var NODE_SUBLABELS = {
|
|
2043
|
+
user: "You",
|
|
2044
|
+
agent: "The LLM",
|
|
2045
|
+
tool: "Data source / action",
|
|
2046
|
+
// "Adds context + tools" is what the user actually observes when a
|
|
2047
|
+
// skill activates — the skill body lands in System Prompt and its
|
|
2048
|
+
// tool list surfaces in Tools. That's the whole effect; no need for
|
|
2049
|
+
// jargon like "bracket over a primitive."
|
|
2050
|
+
skill: "Adds context + tools"
|
|
2051
|
+
};
|
|
2052
|
+
function StageFlow({
|
|
2053
|
+
stages,
|
|
2054
|
+
focusIndex,
|
|
2055
|
+
onEdgeClick,
|
|
2056
|
+
height = 460,
|
|
2057
|
+
activeSkillId
|
|
2058
|
+
}) {
|
|
2059
|
+
const t = useLensTheme();
|
|
2060
|
+
const focus = focusIndex !== void 0 && focusIndex >= 0 ? focusIndex : stages.length - 1;
|
|
2061
|
+
const visible = (0, import_react3.useMemo)(() => stages.slice(0, focus + 1), [stages, focus]);
|
|
2062
|
+
const activeStage = visible[visible.length - 1];
|
|
2063
|
+
const touched = (0, import_react3.useMemo)(() => {
|
|
2064
|
+
const set = /* @__PURE__ */ new Set();
|
|
2065
|
+
for (const s of visible) {
|
|
2066
|
+
set.add(s.from);
|
|
2067
|
+
set.add(s.to);
|
|
2068
|
+
if (s.alsoLights) set.add(s.alsoLights);
|
|
2069
|
+
}
|
|
2070
|
+
return set;
|
|
2071
|
+
}, [visible]);
|
|
2072
|
+
const activeNodes = (0, import_react3.useMemo)(() => {
|
|
2073
|
+
const s = /* @__PURE__ */ new Set();
|
|
2074
|
+
if (activeStage) {
|
|
2075
|
+
s.add(activeStage.to);
|
|
2076
|
+
if (activeStage.alsoLights) s.add(activeStage.alsoLights);
|
|
2077
|
+
}
|
|
2078
|
+
return s;
|
|
2079
|
+
}, [activeStage]);
|
|
2080
|
+
const edges = (0, import_react3.useMemo)(() => {
|
|
2081
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
2082
|
+
visible.forEach((s) => {
|
|
2083
|
+
byKey.set(`${s.from}\u2192${s.to}`, { from: s.from, to: s.to, lastStage: s });
|
|
2084
|
+
});
|
|
2085
|
+
return [...byKey.values()].map(({ from, to, lastStage }) => {
|
|
2086
|
+
const isActive = activeStage !== void 0 && from === activeStage.from && to === activeStage.to;
|
|
2087
|
+
const { sourceHandle, targetHandle } = pickHandles(from, to);
|
|
2088
|
+
const isLoop = to === "agent" && (from === "tool" || from === "skill");
|
|
2089
|
+
return {
|
|
2090
|
+
id: `${from}\u2192${to}`,
|
|
2091
|
+
source: from,
|
|
2092
|
+
target: to,
|
|
2093
|
+
sourceHandle,
|
|
2094
|
+
targetHandle,
|
|
2095
|
+
type: "labelled",
|
|
2096
|
+
// Only loop edges get the marching-ants animation.
|
|
2097
|
+
animated: isLoop,
|
|
2098
|
+
data: {
|
|
2099
|
+
primitive: lastStage.primitive,
|
|
2100
|
+
active: isActive,
|
|
2101
|
+
isLoop,
|
|
2102
|
+
stage: lastStage
|
|
2103
|
+
}
|
|
2104
|
+
};
|
|
2105
|
+
});
|
|
2106
|
+
}, [visible, activeStage]);
|
|
2107
|
+
const nodes = (0, import_react3.useMemo)(() => {
|
|
2108
|
+
return Object.keys(NODE_POSITIONS).filter((id) => {
|
|
2109
|
+
if (id === "skill") return touched.has("skill");
|
|
2110
|
+
return true;
|
|
2111
|
+
}).map((id) => ({
|
|
2112
|
+
id,
|
|
2113
|
+
type: "lens",
|
|
2114
|
+
position: NODE_POSITIONS[id],
|
|
2115
|
+
data: {
|
|
2116
|
+
id,
|
|
2117
|
+
active: activeNodes.has(id),
|
|
2118
|
+
touched: touched.has(id),
|
|
2119
|
+
// Which of the Agent's three ports actually MUTATED this step.
|
|
2120
|
+
// Multiple can be true at once (read_skill touches all three).
|
|
2121
|
+
...id === "agent" && activeStage ? { activeMutations: activeStage.mutations } : {},
|
|
2122
|
+
// Skill annotation on the Agent node — tells the user which
|
|
2123
|
+
// skill is governing the current System Prompt + Tools. Pure
|
|
2124
|
+
// context signal; doesn't affect layout.
|
|
2125
|
+
...id === "agent" && activeSkillId ? { activeSkillId } : {},
|
|
2126
|
+
// Tool node shows the SPECIFIC tool name that's currently
|
|
2127
|
+
// being called — debugging without this is guesswork ("we
|
|
2128
|
+
// called a tool — but which one?"). Only surfaces when the
|
|
2129
|
+
// active stage actually references a tool name.
|
|
2130
|
+
...id === "tool" && activeStage?.toolName && (activeStage.from === "tool" || activeStage.to === "tool") ? {
|
|
2131
|
+
activeLabel: activeStage.toolName,
|
|
2132
|
+
...activeStage.parallelCount ? { parallelCount: activeStage.parallelCount } : {}
|
|
2133
|
+
} : {}
|
|
2134
|
+
},
|
|
2135
|
+
draggable: false
|
|
2136
|
+
}));
|
|
2137
|
+
}, [activeNodes, touched, activeStage, activeSkillId]);
|
|
2138
|
+
const nodeTypes = (0, import_react3.useMemo)(() => ({ lens: LensNode }), []);
|
|
2139
|
+
const edgeTypes = (0, import_react3.useMemo)(() => ({ labelled: LensEdge(onEdgeClick) }), [onEdgeClick]);
|
|
2140
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2141
|
+
"div",
|
|
2142
|
+
{
|
|
2143
|
+
"data-fp-lens": "stage-flow",
|
|
2144
|
+
style: {
|
|
2145
|
+
height,
|
|
2146
|
+
background: t.bg,
|
|
2147
|
+
borderBottom: `1px solid ${t.border}`
|
|
2148
|
+
},
|
|
2149
|
+
children: [
|
|
2150
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(EdgeMarkerDefs, {}),
|
|
2151
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2152
|
+
import_react4.ReactFlow,
|
|
2153
|
+
{
|
|
2154
|
+
nodes,
|
|
2155
|
+
edges,
|
|
2156
|
+
nodeTypes,
|
|
2157
|
+
edgeTypes,
|
|
2158
|
+
fitView: true,
|
|
2159
|
+
fitViewOptions: { padding: 0.15 },
|
|
2160
|
+
proOptions: { hideAttribution: true },
|
|
2161
|
+
nodesDraggable: false,
|
|
2162
|
+
nodesConnectable: false,
|
|
2163
|
+
elementsSelectable: false,
|
|
2164
|
+
panOnDrag: false,
|
|
2165
|
+
zoomOnScroll: false,
|
|
2166
|
+
zoomOnPinch: false,
|
|
2167
|
+
zoomOnDoubleClick: false,
|
|
2168
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2169
|
+
import_react4.Background,
|
|
2170
|
+
{
|
|
2171
|
+
variant: import_react4.BackgroundVariant.Dots,
|
|
2172
|
+
gap: 18,
|
|
2173
|
+
size: 1,
|
|
2174
|
+
color: t.border
|
|
2175
|
+
}
|
|
2176
|
+
)
|
|
2177
|
+
}
|
|
2178
|
+
)
|
|
2179
|
+
]
|
|
2180
|
+
}
|
|
2181
|
+
);
|
|
2182
|
+
}
|
|
2183
|
+
function EdgeMarkerDefs() {
|
|
2184
|
+
const t = useLensTheme();
|
|
2185
|
+
const active = t.accent;
|
|
2186
|
+
const loop = `color-mix(in srgb, ${t.accent} 55%, ${t.border})`;
|
|
2187
|
+
const dim = t.border;
|
|
2188
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2189
|
+
"svg",
|
|
2190
|
+
{
|
|
2191
|
+
"aria-hidden": "true",
|
|
2192
|
+
style: { position: "absolute", width: 0, height: 0, pointerEvents: "none" },
|
|
2193
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("defs", { children: [
|
|
2194
|
+
{ id: "lens-arrow-active", fill: active },
|
|
2195
|
+
{ id: "lens-arrow-loop", fill: loop },
|
|
2196
|
+
{ id: "lens-arrow-dim", fill: dim }
|
|
2197
|
+
].map((m) => /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2198
|
+
"marker",
|
|
2199
|
+
{
|
|
2200
|
+
id: m.id,
|
|
2201
|
+
viewBox: "0 0 10 10",
|
|
2202
|
+
refX: "9",
|
|
2203
|
+
refY: "5",
|
|
2204
|
+
markerWidth: "6",
|
|
2205
|
+
markerHeight: "6",
|
|
2206
|
+
orient: "auto-start-reverse",
|
|
2207
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M 0 0 L 10 5 L 0 10 z", fill: m.fill })
|
|
2208
|
+
},
|
|
2209
|
+
m.id
|
|
2210
|
+
)) })
|
|
2211
|
+
}
|
|
2212
|
+
);
|
|
2213
|
+
}
|
|
2214
|
+
var NODE_KEYFRAMES_ID = "fp-lens-node-keyframes";
|
|
2215
|
+
var NODE_KEYFRAMES_CSS = `
|
|
2216
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
2217
|
+
@keyframes fp-lens-pulse {
|
|
2218
|
+
0%, 100% { opacity: 0.4; transform: scale(1); }
|
|
2219
|
+
50% { opacity: 0.12; transform: scale(1.08); }
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
@media (prefers-reduced-motion: reduce) {
|
|
2223
|
+
@keyframes fp-lens-pulse { 0%, 100% { opacity: 0.3; } }
|
|
2224
|
+
}
|
|
2225
|
+
`;
|
|
2226
|
+
function injectNodeKeyframes() {
|
|
2227
|
+
if (typeof document === "undefined") return;
|
|
2228
|
+
if (document.getElementById(NODE_KEYFRAMES_ID)) return;
|
|
2229
|
+
const el = document.createElement("style");
|
|
2230
|
+
el.id = NODE_KEYFRAMES_ID;
|
|
2231
|
+
el.textContent = NODE_KEYFRAMES_CSS;
|
|
2232
|
+
document.head.appendChild(el);
|
|
2233
|
+
}
|
|
2234
|
+
function LensNode({ data }) {
|
|
2235
|
+
const t = useLensTheme();
|
|
2236
|
+
const d = data;
|
|
2237
|
+
injectNodeKeyframes();
|
|
2238
|
+
const isActive = d.active;
|
|
2239
|
+
const isDone = !d.active && d.touched;
|
|
2240
|
+
const bg = isActive ? t.accent : isDone ? t.bgElev : t.bg;
|
|
2241
|
+
const border = isActive ? t.accent : isDone ? t.border : t.border;
|
|
2242
|
+
const textColor = isActive ? "#ffffff" : isDone ? t.text : t.textSubtle;
|
|
2243
|
+
const shadow = isActive ? `0 0 18px color-mix(in srgb, ${t.accent} 42%, transparent)` : isDone ? `0 2px 8px rgba(0,0,0,0.18)` : `0 1px 3px rgba(0,0,0,0.08)`;
|
|
2244
|
+
const label = NODE_LABELS[d.id];
|
|
2245
|
+
const sub = isActive && d.activeLabel ? d.activeLabel : NODE_SUBLABELS[d.id];
|
|
2246
|
+
const isAgent = d.id === "agent";
|
|
2247
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { position: "relative", display: "inline-block" }, children: [
|
|
2248
|
+
isActive && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2249
|
+
"div",
|
|
2250
|
+
{
|
|
2251
|
+
style: {
|
|
2252
|
+
position: "absolute",
|
|
2253
|
+
inset: -6,
|
|
2254
|
+
borderRadius: 14,
|
|
2255
|
+
border: `2px solid ${t.accent}`,
|
|
2256
|
+
opacity: 0.35,
|
|
2257
|
+
pointerEvents: "none",
|
|
2258
|
+
animation: "fp-lens-pulse 1.6s ease-out infinite"
|
|
2259
|
+
}
|
|
2260
|
+
}
|
|
2261
|
+
),
|
|
2262
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2263
|
+
"div",
|
|
2264
|
+
{
|
|
2265
|
+
style: {
|
|
2266
|
+
width: isAgent ? 200 : 150,
|
|
2267
|
+
padding: "12px 16px",
|
|
2268
|
+
borderRadius: 10,
|
|
2269
|
+
background: bg,
|
|
2270
|
+
border: `2px solid ${border}`,
|
|
2271
|
+
color: textColor,
|
|
2272
|
+
fontFamily: t.fontSans,
|
|
2273
|
+
textAlign: "center",
|
|
2274
|
+
boxShadow: shadow,
|
|
2275
|
+
transition: "background 220ms ease, border-color 220ms ease, box-shadow 220ms ease, color 220ms ease"
|
|
2276
|
+
},
|
|
2277
|
+
children: [
|
|
2278
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("div", { style: { display: "flex", alignItems: "center", justifyContent: "center", gap: 6 }, children: [
|
|
2279
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(NodeIcon, { id: d.id, color: textColor }),
|
|
2280
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: 13, fontWeight: 600 }, children: label })
|
|
2281
|
+
] }),
|
|
2282
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2283
|
+
"div",
|
|
2284
|
+
{
|
|
2285
|
+
style: {
|
|
2286
|
+
fontSize: isActive && d.activeLabel ? 11 : 10,
|
|
2287
|
+
color: isActive ? "rgba(255,255,255,0.95)" : t.textSubtle,
|
|
2288
|
+
marginTop: 2,
|
|
2289
|
+
fontWeight: isActive && d.activeLabel ? 600 : 400,
|
|
2290
|
+
fontFamily: isActive && d.activeLabel ? t.fontMono : t.fontSans,
|
|
2291
|
+
maxWidth: isAgent ? 180 : 130,
|
|
2292
|
+
overflow: "hidden",
|
|
2293
|
+
textOverflow: "ellipsis",
|
|
2294
|
+
whiteSpace: "nowrap",
|
|
2295
|
+
margin: "2px auto 0"
|
|
2296
|
+
},
|
|
2297
|
+
title: sub,
|
|
2298
|
+
children: sub
|
|
2299
|
+
}
|
|
2300
|
+
),
|
|
2301
|
+
d.id === "tool" && isActive && (d.parallelCount ?? 0) > 1 && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2302
|
+
"div",
|
|
2303
|
+
{
|
|
2304
|
+
title: `This tool is one of ${d.parallelCount} called in parallel this round`,
|
|
2305
|
+
style: {
|
|
2306
|
+
marginTop: 4,
|
|
2307
|
+
alignSelf: "center",
|
|
2308
|
+
display: "inline-block",
|
|
2309
|
+
padding: "1px 7px",
|
|
2310
|
+
borderRadius: 999,
|
|
2311
|
+
background: "rgba(255,255,255,0.25)",
|
|
2312
|
+
color: "#ffffff",
|
|
2313
|
+
fontSize: 9,
|
|
2314
|
+
fontWeight: 700,
|
|
2315
|
+
letterSpacing: "0.08em",
|
|
2316
|
+
textTransform: "uppercase"
|
|
2317
|
+
},
|
|
2318
|
+
children: [
|
|
2319
|
+
"\u26A1 Parallel \xB7 ",
|
|
2320
|
+
d.parallelCount
|
|
2321
|
+
]
|
|
2322
|
+
}
|
|
2323
|
+
),
|
|
2324
|
+
isAgent && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
2325
|
+
d.activeSkillId && /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2326
|
+
"div",
|
|
2327
|
+
{
|
|
2328
|
+
title: `System Prompt + Tools are currently governed by the ${d.activeSkillId} skill`,
|
|
2329
|
+
style: {
|
|
2330
|
+
marginTop: 8,
|
|
2331
|
+
padding: "3px 9px",
|
|
2332
|
+
borderRadius: 999,
|
|
2333
|
+
background: isActive ? "rgba(255,255,255,0.18)" : t.bgElev,
|
|
2334
|
+
border: `1px solid ${isActive ? "rgba(255,255,255,0.35)" : t.border}`,
|
|
2335
|
+
color: isActive ? "#ffffff" : t.accent,
|
|
2336
|
+
fontSize: 10,
|
|
2337
|
+
fontFamily: t.fontMono,
|
|
2338
|
+
fontWeight: 600,
|
|
2339
|
+
whiteSpace: "nowrap",
|
|
2340
|
+
maxWidth: 180,
|
|
2341
|
+
overflow: "hidden",
|
|
2342
|
+
textOverflow: "ellipsis",
|
|
2343
|
+
display: "inline-block"
|
|
2344
|
+
},
|
|
2345
|
+
children: [
|
|
2346
|
+
"\u{1F4DA} ",
|
|
2347
|
+
d.activeSkillId
|
|
2348
|
+
]
|
|
2349
|
+
}
|
|
2350
|
+
),
|
|
2351
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2352
|
+
AgentPorts,
|
|
2353
|
+
{
|
|
2354
|
+
active: d.active,
|
|
2355
|
+
mutations: d.activeMutations,
|
|
2356
|
+
filledCard: isActive
|
|
2357
|
+
}
|
|
2358
|
+
)
|
|
2359
|
+
] }),
|
|
2360
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "source", position: import_react4.Position.Top, id: "t-out", style: handleStyle(-14, 0) }),
|
|
2361
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "target", position: import_react4.Position.Top, id: "t-in", style: handleStyle(14, 0) }),
|
|
2362
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "source", position: import_react4.Position.Bottom, id: "b-out", style: handleStyle(14, 0) }),
|
|
2363
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "target", position: import_react4.Position.Bottom, id: "b-in", style: handleStyle(-14, 0) }),
|
|
2364
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "source", position: import_react4.Position.Left, id: "l-out", style: handleStyle(0, 10) }),
|
|
2365
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "target", position: import_react4.Position.Left, id: "l-in", style: handleStyle(0, -10) }),
|
|
2366
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "source", position: import_react4.Position.Right, id: "r-out", style: handleStyle(0, -10) }),
|
|
2367
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(import_react4.Handle, { type: "target", position: import_react4.Position.Right, id: "r-in", style: handleStyle(0, 10) })
|
|
2368
|
+
]
|
|
2369
|
+
}
|
|
2370
|
+
)
|
|
2371
|
+
] });
|
|
2372
|
+
}
|
|
2373
|
+
function NodeIcon({ id, color }) {
|
|
2374
|
+
const size = 16;
|
|
2375
|
+
const props = {
|
|
2376
|
+
width: size,
|
|
2377
|
+
height: size,
|
|
2378
|
+
viewBox: `0 0 ${size} ${size}`,
|
|
2379
|
+
fill: "none",
|
|
2380
|
+
style: { flexShrink: 0 }
|
|
2381
|
+
};
|
|
2382
|
+
if (id === "user") {
|
|
2383
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...props, children: [
|
|
2384
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8", cy: "5", r: "2.5", stroke: color, strokeWidth: "1.5" }),
|
|
2385
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3.5 14C3.5 11 5.5 9 8 9S12.5 11 12.5 14", stroke: color, strokeWidth: "1.5", strokeLinecap: "round" })
|
|
2386
|
+
] });
|
|
2387
|
+
}
|
|
2388
|
+
if (id === "agent") {
|
|
2389
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...props, children: [
|
|
2390
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8", cy: "8", r: "6", stroke: color, strokeWidth: "1.5" }),
|
|
2391
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5.5 8C5.5 6.5 6.5 5 8 5S10.5 6.5 10.5 8", stroke: color, strokeWidth: "1.2", strokeLinecap: "round" }),
|
|
2392
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8", cy: "9.5", r: "1", fill: color }),
|
|
2393
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "8", y1: "2", x2: "8", y2: "3.5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
|
|
2394
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "12.5", y1: "4", x2: "11.2", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" }),
|
|
2395
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("line", { x1: "3.5", y1: "4", x2: "4.8", y2: "5", stroke: color, strokeWidth: "1", strokeLinecap: "round" })
|
|
2396
|
+
] });
|
|
2397
|
+
}
|
|
2398
|
+
if (id === "tool") {
|
|
2399
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...props, children: [
|
|
2400
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("circle", { cx: "8", cy: "8", r: "3", stroke: color, strokeWidth: "1.5" }),
|
|
2401
|
+
[0, 45, 90, 135, 180, 225, 270, 315].map((angle) => {
|
|
2402
|
+
const rad = angle * Math.PI / 180;
|
|
2403
|
+
const x1 = 8 + Math.cos(rad) * 4.5;
|
|
2404
|
+
const y1 = 8 + Math.sin(rad) * 4.5;
|
|
2405
|
+
const x2 = 8 + Math.cos(rad) * 6;
|
|
2406
|
+
const y2 = 8 + Math.sin(rad) * 6;
|
|
2407
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2408
|
+
"line",
|
|
2409
|
+
{
|
|
2410
|
+
x1,
|
|
2411
|
+
y1,
|
|
2412
|
+
x2,
|
|
2413
|
+
y2,
|
|
2414
|
+
stroke: color,
|
|
2415
|
+
strokeWidth: "1.5",
|
|
2416
|
+
strokeLinecap: "round"
|
|
2417
|
+
},
|
|
2418
|
+
angle
|
|
2419
|
+
);
|
|
2420
|
+
})
|
|
2421
|
+
] });
|
|
2422
|
+
}
|
|
2423
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)("svg", { ...props, children: [
|
|
2424
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M3 4h7a2 2 0 0 1 2 2v7a1 1 0 0 1-1 1H4a1 1 0 0 1-1-1V4z", stroke: color, strokeWidth: "1.4", strokeLinejoin: "round" }),
|
|
2425
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("path", { d: "M5.5 7h4M5.5 9.5h4", stroke: color, strokeWidth: "1.2", strokeLinecap: "round" })
|
|
2426
|
+
] });
|
|
2427
|
+
}
|
|
2428
|
+
function handleStyle(dx, dy) {
|
|
2429
|
+
return {
|
|
2430
|
+
...HANDLE_STYLE,
|
|
2431
|
+
transform: `translate(${dx}px, ${dy}px)`
|
|
2432
|
+
};
|
|
2433
|
+
}
|
|
2434
|
+
function AgentPorts({
|
|
2435
|
+
active,
|
|
2436
|
+
mutations,
|
|
2437
|
+
filledCard
|
|
2438
|
+
}) {
|
|
2439
|
+
const t = useLensTheme();
|
|
2440
|
+
const litSP = active && mutations?.systemPrompt === true;
|
|
2441
|
+
const litMsg = active && mutations?.messages === true;
|
|
2442
|
+
const litTools = active && mutations?.tools === true;
|
|
2443
|
+
const spBadge = mutations?.systemPromptDeltaChars !== void 0 ? `+${mutations.systemPromptDeltaChars.toLocaleString()} chars` : null;
|
|
2444
|
+
const toolsBadge = (() => {
|
|
2445
|
+
const added = mutations?.toolsAdded ?? 0;
|
|
2446
|
+
const removed = mutations?.toolsRemoved ?? 0;
|
|
2447
|
+
if (added === 0 && removed === 0) return null;
|
|
2448
|
+
const bits = [];
|
|
2449
|
+
if (added > 0) bits.push(`+${added}`);
|
|
2450
|
+
if (removed > 0) bits.push(`-${removed}`);
|
|
2451
|
+
return bits.join(" / ");
|
|
2452
|
+
})();
|
|
2453
|
+
const ports = [
|
|
2454
|
+
{
|
|
2455
|
+
key: "system-prompt",
|
|
2456
|
+
label: "System Prompt",
|
|
2457
|
+
hint: "Instructions Neo runs on",
|
|
2458
|
+
lit: litSP,
|
|
2459
|
+
badge: litSP ? spBadge : null
|
|
2460
|
+
},
|
|
2461
|
+
{
|
|
2462
|
+
key: "message",
|
|
2463
|
+
label: "Messages",
|
|
2464
|
+
hint: "Conversation so far",
|
|
2465
|
+
lit: litMsg,
|
|
2466
|
+
badge: null
|
|
2467
|
+
},
|
|
2468
|
+
{
|
|
2469
|
+
key: "tool",
|
|
2470
|
+
label: "Tools",
|
|
2471
|
+
hint: "What Neo can call",
|
|
2472
|
+
lit: litTools,
|
|
2473
|
+
badge: litTools ? toolsBadge : null
|
|
2474
|
+
}
|
|
2475
|
+
];
|
|
2476
|
+
const boxBg = filledCard ? "rgba(255,255,255,0.12)" : t.bg;
|
|
2477
|
+
const boxBorder = filledCard ? "rgba(255,255,255,0.25)" : t.border;
|
|
2478
|
+
const portIdle = filledCard ? "rgba(255,255,255,0.7)" : t.textMuted;
|
|
2479
|
+
const portLitBg = filledCard ? "rgba(255,255,255,0.25)" : `color-mix(in srgb, ${t.accent} 30%, transparent)`;
|
|
2480
|
+
const portLitColor = filledCard ? "#ffffff" : t.accent;
|
|
2481
|
+
const portLitBorder = filledCard ? "#ffffff" : t.accent;
|
|
2482
|
+
const portIdleBorder = filledCard ? "rgba(255,255,255,0.3)" : t.border;
|
|
2483
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2484
|
+
"div",
|
|
2485
|
+
{
|
|
2486
|
+
style: {
|
|
2487
|
+
display: "flex",
|
|
2488
|
+
flexDirection: "column",
|
|
2489
|
+
gap: 3,
|
|
2490
|
+
marginTop: 8,
|
|
2491
|
+
padding: 4,
|
|
2492
|
+
background: boxBg,
|
|
2493
|
+
border: `1px solid ${boxBorder}`,
|
|
2494
|
+
borderRadius: 6
|
|
2495
|
+
},
|
|
2496
|
+
children: ports.map((p) => /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(
|
|
2497
|
+
"div",
|
|
2498
|
+
{
|
|
2499
|
+
title: p.hint,
|
|
2500
|
+
style: {
|
|
2501
|
+
padding: "2px 8px",
|
|
2502
|
+
borderRadius: 3,
|
|
2503
|
+
background: p.lit ? portLitBg : "transparent",
|
|
2504
|
+
color: p.lit ? portLitColor : portIdle,
|
|
2505
|
+
fontSize: 10,
|
|
2506
|
+
fontWeight: p.lit ? 600 : 500,
|
|
2507
|
+
letterSpacing: "0.02em",
|
|
2508
|
+
textAlign: "left",
|
|
2509
|
+
fontFamily: t.fontSans,
|
|
2510
|
+
display: "flex",
|
|
2511
|
+
alignItems: "center",
|
|
2512
|
+
gap: 6,
|
|
2513
|
+
borderLeft: `2px solid ${p.lit ? portLitBorder : portIdleBorder}`
|
|
2514
|
+
},
|
|
2515
|
+
children: [
|
|
2516
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { fontSize: 8 }, children: "\u25B8" }),
|
|
2517
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)("span", { style: { flex: 1 }, children: p.label }),
|
|
2518
|
+
p.badge && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2519
|
+
"span",
|
|
2520
|
+
{
|
|
2521
|
+
style: {
|
|
2522
|
+
fontSize: 9,
|
|
2523
|
+
padding: "0 4px",
|
|
2524
|
+
borderRadius: 3,
|
|
2525
|
+
background: filledCard ? "rgba(255,255,255,0.22)" : t.bg,
|
|
2526
|
+
color: p.lit ? portLitColor : portIdle,
|
|
2527
|
+
fontFamily: t.fontMono,
|
|
2528
|
+
fontWeight: 600
|
|
2529
|
+
},
|
|
2530
|
+
children: p.badge
|
|
2531
|
+
}
|
|
2532
|
+
)
|
|
2533
|
+
]
|
|
2534
|
+
},
|
|
2535
|
+
p.key
|
|
2536
|
+
))
|
|
2537
|
+
}
|
|
2538
|
+
);
|
|
2539
|
+
}
|
|
2540
|
+
var HANDLE_STYLE = {
|
|
2541
|
+
opacity: 0,
|
|
2542
|
+
pointerEvents: "none",
|
|
2543
|
+
width: 1,
|
|
2544
|
+
height: 1
|
|
2545
|
+
};
|
|
2546
|
+
function LensEdge(onEdgeClick) {
|
|
2547
|
+
return function LensEdgeInner({
|
|
2548
|
+
id,
|
|
2549
|
+
sourceX,
|
|
2550
|
+
sourceY,
|
|
2551
|
+
targetX,
|
|
2552
|
+
targetY,
|
|
2553
|
+
sourcePosition,
|
|
2554
|
+
targetPosition,
|
|
2555
|
+
data
|
|
2556
|
+
}) {
|
|
2557
|
+
const t = useLensTheme();
|
|
2558
|
+
const d = data;
|
|
2559
|
+
const [edgePath] = (0, import_react4.getSmoothStepPath)({
|
|
2560
|
+
sourceX,
|
|
2561
|
+
sourceY,
|
|
2562
|
+
sourcePosition,
|
|
2563
|
+
targetX,
|
|
2564
|
+
targetY,
|
|
2565
|
+
targetPosition,
|
|
2566
|
+
borderRadius: 10
|
|
2567
|
+
});
|
|
2568
|
+
const stroke = d.active ? t.accent : d.isLoop ? `color-mix(in srgb, ${t.accent} 55%, ${t.border})` : t.border;
|
|
2569
|
+
const strokeWidth = d.active ? 2.25 : d.isLoop ? 1.75 : 1.5;
|
|
2570
|
+
const strokeDasharray = d.isLoop ? "5 4" : void 0;
|
|
2571
|
+
const markerId = d.active ? "lens-arrow-active" : d.isLoop ? "lens-arrow-loop" : "lens-arrow-dim";
|
|
2572
|
+
return /* @__PURE__ */ (0, import_jsx_runtime3.jsxs)(import_jsx_runtime3.Fragment, { children: [
|
|
2573
|
+
/* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2574
|
+
import_react4.BaseEdge,
|
|
2575
|
+
{
|
|
2576
|
+
id,
|
|
2577
|
+
path: edgePath,
|
|
2578
|
+
style: {
|
|
2579
|
+
stroke,
|
|
2580
|
+
strokeWidth,
|
|
2581
|
+
strokeDasharray,
|
|
2582
|
+
filter: d.active ? `drop-shadow(0 0 6px color-mix(in srgb, ${t.accent} 50%, transparent))` : void 0,
|
|
2583
|
+
cursor: onEdgeClick ? "pointer" : "default"
|
|
2584
|
+
},
|
|
2585
|
+
markerEnd: `url(#${markerId})`
|
|
2586
|
+
}
|
|
2587
|
+
),
|
|
2588
|
+
onEdgeClick && /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
2589
|
+
"path",
|
|
2590
|
+
{
|
|
2591
|
+
d: edgePath,
|
|
2592
|
+
fill: "none",
|
|
2593
|
+
stroke: "transparent",
|
|
2594
|
+
strokeWidth: 12,
|
|
2595
|
+
style: { cursor: "pointer" },
|
|
2596
|
+
onClick: () => onEdgeClick(d.stage)
|
|
2597
|
+
}
|
|
2598
|
+
)
|
|
2599
|
+
] });
|
|
2600
|
+
};
|
|
2601
|
+
}
|
|
2602
|
+
|
|
2603
|
+
// src/panels/TimeTravel.tsx
|
|
2604
|
+
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
2605
|
+
function TimeTravel({
|
|
2606
|
+
stages,
|
|
2607
|
+
focusIndex,
|
|
2608
|
+
onFocusChange,
|
|
2609
|
+
isLive
|
|
2610
|
+
}) {
|
|
2611
|
+
const t = useLensTheme();
|
|
2612
|
+
const max = Math.max(0, stages.length - 1);
|
|
2613
|
+
function step(delta) {
|
|
2614
|
+
const next = Math.min(max, Math.max(0, focusIndex + delta));
|
|
2615
|
+
onFocusChange(next);
|
|
2616
|
+
}
|
|
2617
|
+
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
2618
|
+
"div",
|
|
2619
|
+
{
|
|
2620
|
+
"data-fp-lens": "time-travel",
|
|
2621
|
+
style: {
|
|
2622
|
+
// Frosted-glass oval pill, floating clear of the surrounding
|
|
2623
|
+
// surfaces. `color-mix` gives a translucent tint using the
|
|
2624
|
+
// current theme's elevated bg; `backdrop-filter` blurs
|
|
2625
|
+
// whatever's behind (the graph + ask card show through
|
|
2626
|
+
// softly). Margin creates air around the pill so it reads as
|
|
2627
|
+
// a distinct floating control, not a toolbar bar.
|
|
2628
|
+
display: "flex",
|
|
2629
|
+
alignItems: "center",
|
|
2630
|
+
gap: 10,
|
|
2631
|
+
padding: "8px 14px",
|
|
2632
|
+
margin: "10px 14px",
|
|
2633
|
+
background: `color-mix(in srgb, ${t.bgElev} 55%, transparent)`,
|
|
2634
|
+
backdropFilter: "blur(14px) saturate(140%)",
|
|
2635
|
+
WebkitBackdropFilter: "blur(14px) saturate(140%)",
|
|
2636
|
+
border: `1px solid color-mix(in srgb, ${t.border} 70%, transparent)`,
|
|
2637
|
+
borderRadius: 999,
|
|
2638
|
+
boxShadow: "0 4px 16px rgba(0, 0, 0, 0.12), inset 0 1px 0 rgba(255, 255, 255, 0.06)",
|
|
2639
|
+
fontFamily: t.fontSans
|
|
2640
|
+
},
|
|
2641
|
+
children: [
|
|
2642
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2643
|
+
"button",
|
|
2644
|
+
{
|
|
2645
|
+
onClick: () => step(-1),
|
|
2646
|
+
disabled: focusIndex <= 0 || stages.length === 0,
|
|
2647
|
+
style: btnStyle(t, false),
|
|
2648
|
+
title: "Previous step (\u2190)",
|
|
2649
|
+
children: "\u25C0"
|
|
2650
|
+
}
|
|
2651
|
+
),
|
|
2652
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2653
|
+
"button",
|
|
2654
|
+
{
|
|
2655
|
+
onClick: () => step(1),
|
|
2656
|
+
disabled: focusIndex >= max || stages.length === 0,
|
|
2657
|
+
style: btnStyle(t, false),
|
|
2658
|
+
title: "Next step (\u2192)",
|
|
2659
|
+
children: "\u25B6"
|
|
2660
|
+
}
|
|
2661
|
+
),
|
|
2662
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2663
|
+
"button",
|
|
2664
|
+
{
|
|
2665
|
+
onClick: () => onFocusChange(max),
|
|
2666
|
+
disabled: stages.length === 0 || isLive === true,
|
|
2667
|
+
style: btnStyle(t, isLive !== true && stages.length > 0),
|
|
2668
|
+
title: "Jump to latest step",
|
|
2669
|
+
children: "\u27F3 Live"
|
|
2670
|
+
}
|
|
2671
|
+
),
|
|
2672
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2673
|
+
"input",
|
|
2674
|
+
{
|
|
2675
|
+
type: "range",
|
|
2676
|
+
min: 0,
|
|
2677
|
+
max,
|
|
2678
|
+
value: Math.min(focusIndex, max),
|
|
2679
|
+
onChange: (e) => onFocusChange(Number(e.target.value)),
|
|
2680
|
+
disabled: stages.length <= 1,
|
|
2681
|
+
style: { flex: 1, accentColor: t.accent, minWidth: 120 }
|
|
2682
|
+
}
|
|
2683
|
+
),
|
|
2684
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
2685
|
+
"div",
|
|
2686
|
+
{
|
|
2687
|
+
style: {
|
|
2688
|
+
fontSize: 11,
|
|
2689
|
+
color: t.textMuted,
|
|
2690
|
+
fontFamily: t.fontMono,
|
|
2691
|
+
whiteSpace: "nowrap",
|
|
2692
|
+
minWidth: 80,
|
|
2693
|
+
textAlign: "right"
|
|
2694
|
+
},
|
|
2695
|
+
children: stages.length === 0 ? "no steps yet" : `Step ${focusIndex + 1} / ${stages.length}`
|
|
2696
|
+
}
|
|
2697
|
+
)
|
|
2698
|
+
]
|
|
2699
|
+
}
|
|
2700
|
+
);
|
|
2701
|
+
}
|
|
2702
|
+
function btnStyle(t, highlighted) {
|
|
2703
|
+
return {
|
|
2704
|
+
background: highlighted ? t.accent : `color-mix(in srgb, ${t.bg} 40%, transparent)`,
|
|
2705
|
+
color: highlighted ? "#fff" : t.textMuted,
|
|
2706
|
+
border: `1px solid color-mix(in srgb, ${t.border} 60%, transparent)`,
|
|
2707
|
+
borderRadius: 999,
|
|
2708
|
+
padding: "3px 12px",
|
|
2709
|
+
fontSize: 12,
|
|
2710
|
+
cursor: "pointer",
|
|
2711
|
+
width: "auto",
|
|
2712
|
+
fontWeight: 500,
|
|
2713
|
+
whiteSpace: "nowrap",
|
|
2714
|
+
transition: "background 140ms ease, border-color 140ms ease, color 140ms ease"
|
|
2715
|
+
};
|
|
2716
|
+
}
|
|
2717
|
+
|
|
2718
|
+
// src/panels/AskCard.tsx
|
|
2719
|
+
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
2720
|
+
function AskCard({ timeline, focusIndex, stages }) {
|
|
2721
|
+
const t = useLensTheme();
|
|
2722
|
+
const currentStage = stages[focusIndex];
|
|
2723
|
+
const currentTurn = currentStage !== void 0 ? timeline.turns[currentStage.turnIndex] : timeline.turns[0];
|
|
2724
|
+
const currentIter = currentStage?.iterIndex !== void 0 ? currentTurn?.iterations.find((it) => it.index === currentStage.iterIndex) : void 0;
|
|
2725
|
+
const currentTool = currentStage?.toolName && currentIter ? currentIter.toolCalls.find((tc) => tc.name === currentStage.toolName) : void 0;
|
|
2726
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2727
|
+
"div",
|
|
2728
|
+
{
|
|
2729
|
+
"data-fp-lens": "ask-card",
|
|
2730
|
+
style: {
|
|
2731
|
+
display: "flex",
|
|
2732
|
+
flexDirection: "column",
|
|
2733
|
+
gap: 12,
|
|
2734
|
+
padding: 14,
|
|
2735
|
+
background: t.bg,
|
|
2736
|
+
fontFamily: t.fontSans,
|
|
2737
|
+
color: t.text,
|
|
2738
|
+
overflow: "auto"
|
|
2739
|
+
},
|
|
2740
|
+
children: [
|
|
2741
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
|
|
2742
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Label3, { t, children: "Your question" }),
|
|
2743
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2744
|
+
"div",
|
|
2745
|
+
{
|
|
2746
|
+
style: {
|
|
2747
|
+
marginTop: 4,
|
|
2748
|
+
padding: "10px 12px",
|
|
2749
|
+
background: `color-mix(in srgb, ${t.accent} 12%, ${t.bgElev})`,
|
|
2750
|
+
border: `1px solid ${t.border}`,
|
|
2751
|
+
borderRadius: 6,
|
|
2752
|
+
fontSize: 13,
|
|
2753
|
+
lineHeight: 1.5
|
|
2754
|
+
},
|
|
2755
|
+
children: currentTurn?.userPrompt ?? "No question yet."
|
|
2756
|
+
}
|
|
2757
|
+
)
|
|
2758
|
+
] }),
|
|
2759
|
+
currentStage && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
|
|
2760
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Label3, { t, children: [
|
|
2761
|
+
"Step ",
|
|
2762
|
+
focusIndex + 1,
|
|
2763
|
+
" / ",
|
|
2764
|
+
stages.length
|
|
2765
|
+
] }),
|
|
2766
|
+
!(currentTool && currentStage.from === "tool") && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("div", { style: { marginTop: 4, fontSize: 13, color: t.text, lineHeight: 1.5 }, children: currentStage.label }),
|
|
2767
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
2768
|
+
"div",
|
|
2769
|
+
{
|
|
2770
|
+
style: {
|
|
2771
|
+
marginTop: 8,
|
|
2772
|
+
display: "flex",
|
|
2773
|
+
gap: 6,
|
|
2774
|
+
flexWrap: "wrap",
|
|
2775
|
+
fontSize: 10,
|
|
2776
|
+
color: t.textSubtle
|
|
2777
|
+
},
|
|
2778
|
+
children: [
|
|
2779
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Pill, { t, children: primitivePill(currentStage) }),
|
|
2780
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(Pill, { t, children: [
|
|
2781
|
+
friendlyNode(currentStage.from),
|
|
2782
|
+
" \u2192 ",
|
|
2783
|
+
friendlyNode(currentStage.to)
|
|
2784
|
+
] }),
|
|
2785
|
+
currentStage.toolName && /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Pill, { t, children: currentStage.toolName })
|
|
2786
|
+
]
|
|
2787
|
+
}
|
|
2788
|
+
)
|
|
2789
|
+
] }),
|
|
2790
|
+
currentStage?.from === "agent" && currentIter?.assistantContent && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
|
|
2791
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Label3, { t, children: "Agent reasoning" }),
|
|
2792
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2793
|
+
"div",
|
|
2794
|
+
{
|
|
2795
|
+
style: {
|
|
2796
|
+
marginTop: 4,
|
|
2797
|
+
padding: "10px 12px",
|
|
2798
|
+
background: t.bgElev,
|
|
2799
|
+
border: `1px solid ${t.border}`,
|
|
2800
|
+
borderLeft: `3px solid ${t.accent}`,
|
|
2801
|
+
borderRadius: 6,
|
|
2802
|
+
fontSize: 12,
|
|
2803
|
+
lineHeight: 1.55,
|
|
2804
|
+
whiteSpace: "pre-wrap",
|
|
2805
|
+
maxHeight: 220,
|
|
2806
|
+
overflow: "auto"
|
|
2807
|
+
},
|
|
2808
|
+
children: currentIter.assistantContent
|
|
2809
|
+
}
|
|
2810
|
+
)
|
|
2811
|
+
] }),
|
|
2812
|
+
currentTool && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
|
|
2813
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Label3, { t, children: currentStage?.to === "tool" ? "Arguments" : "Tool returned" }),
|
|
2814
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2815
|
+
"pre",
|
|
2816
|
+
{
|
|
2817
|
+
style: {
|
|
2818
|
+
marginTop: 4,
|
|
2819
|
+
padding: "8px 10px",
|
|
2820
|
+
background: t.bgElev,
|
|
2821
|
+
border: `1px solid ${t.border}`,
|
|
2822
|
+
borderRadius: 6,
|
|
2823
|
+
fontSize: 11,
|
|
2824
|
+
fontFamily: t.fontMono,
|
|
2825
|
+
color: currentTool.error ? t.error : t.text,
|
|
2826
|
+
whiteSpace: "pre-wrap",
|
|
2827
|
+
maxHeight: 180,
|
|
2828
|
+
overflow: "auto",
|
|
2829
|
+
margin: 0
|
|
2830
|
+
},
|
|
2831
|
+
children: currentStage?.to === "tool" ? JSON.stringify(currentTool.arguments, null, 2) : currentTool.result
|
|
2832
|
+
}
|
|
2833
|
+
)
|
|
2834
|
+
] }),
|
|
2835
|
+
timeline.turns.length > 1 && /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("section", { children: [
|
|
2836
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)(Label3, { t, children: "Conversation" }),
|
|
2837
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { style: { marginTop: 4, fontSize: 12, color: t.textMuted, lineHeight: 1.5 }, children: [
|
|
2838
|
+
timeline.turns.length,
|
|
2839
|
+
" question",
|
|
2840
|
+
timeline.turns.length === 1 ? "" : "s",
|
|
2841
|
+
" so far \xB7",
|
|
2842
|
+
" ",
|
|
2843
|
+
timeline.tools.length,
|
|
2844
|
+
" tool call",
|
|
2845
|
+
timeline.tools.length === 1 ? "" : "s",
|
|
2846
|
+
" total"
|
|
2847
|
+
] })
|
|
2848
|
+
] })
|
|
2849
|
+
]
|
|
2850
|
+
}
|
|
2851
|
+
);
|
|
2852
|
+
}
|
|
2853
|
+
function Label3({
|
|
2854
|
+
t,
|
|
2855
|
+
children
|
|
2856
|
+
}) {
|
|
2857
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2858
|
+
"div",
|
|
2859
|
+
{
|
|
2860
|
+
style: {
|
|
2861
|
+
fontSize: 10,
|
|
2862
|
+
color: t.textSubtle,
|
|
2863
|
+
textTransform: "uppercase",
|
|
2864
|
+
letterSpacing: "0.08em",
|
|
2865
|
+
fontWeight: 600
|
|
2866
|
+
},
|
|
2867
|
+
children
|
|
2868
|
+
}
|
|
2869
|
+
);
|
|
2870
|
+
}
|
|
2871
|
+
function Pill({
|
|
2872
|
+
t,
|
|
2873
|
+
children,
|
|
2874
|
+
warn
|
|
2875
|
+
}) {
|
|
2876
|
+
return /* @__PURE__ */ (0, import_jsx_runtime5.jsx)(
|
|
2877
|
+
"span",
|
|
2878
|
+
{
|
|
2879
|
+
style: {
|
|
2880
|
+
padding: "1px 6px",
|
|
2881
|
+
borderRadius: 3,
|
|
2882
|
+
background: warn ? `color-mix(in srgb, ${t.warning} 20%, transparent)` : t.bgElev,
|
|
2883
|
+
color: warn ? t.warning : t.textMuted,
|
|
2884
|
+
fontWeight: 600,
|
|
2885
|
+
textTransform: "uppercase",
|
|
2886
|
+
letterSpacing: "0.04em"
|
|
2887
|
+
},
|
|
2888
|
+
children
|
|
2889
|
+
}
|
|
2890
|
+
);
|
|
2891
|
+
}
|
|
2892
|
+
function friendlyNode(id) {
|
|
2893
|
+
if (!id) return id;
|
|
2894
|
+
return id.charAt(0).toUpperCase() + id.slice(1);
|
|
2895
|
+
}
|
|
2896
|
+
function primitivePill(stage) {
|
|
2897
|
+
if (stage.primitive === "system-prompt") return "System Prompt";
|
|
2898
|
+
if (stage.primitive === "message") return "Message";
|
|
2899
|
+
if (stage.toolKind === "skill") return "Tool (Skill)";
|
|
2900
|
+
if (stage.toolKind === "ask-human") return "Tool (Ask user)";
|
|
2901
|
+
return "Tool";
|
|
2902
|
+
}
|
|
2903
|
+
|
|
2904
|
+
// src/panels/RunSummary.tsx
|
|
2905
|
+
var import_react5 = require("react");
|
|
2906
|
+
var import_jsx_runtime6 = require("react/jsx-runtime");
|
|
2907
|
+
function RunSummary({ timeline }) {
|
|
2908
|
+
const t = useLensTheme();
|
|
2909
|
+
const [open, setOpen] = (0, import_react5.useState)(false);
|
|
2910
|
+
const completedTurns = timeline.turns.filter((turn) => turn.finalContent !== "");
|
|
2911
|
+
if (completedTurns.length === 0) return null;
|
|
2912
|
+
const toolCounts = /* @__PURE__ */ new Map();
|
|
2913
|
+
for (const tc of timeline.tools) {
|
|
2914
|
+
const prev = toolCounts.get(tc.name) ?? { count: 0, totalMs: 0 };
|
|
2915
|
+
toolCounts.set(tc.name, {
|
|
2916
|
+
count: prev.count + 1,
|
|
2917
|
+
totalMs: prev.totalMs + (tc.durationMs ?? 0)
|
|
2918
|
+
});
|
|
2919
|
+
}
|
|
2920
|
+
const toolList = [...toolCounts.entries()].sort((a, b) => b[1].count - a[1].count);
|
|
2921
|
+
const activatedSkills = /* @__PURE__ */ new Set();
|
|
2922
|
+
for (const tc of timeline.tools) {
|
|
2923
|
+
if (tc.name === "read_skill") {
|
|
2924
|
+
const id = tc.arguments?.id;
|
|
2925
|
+
if (typeof id === "string") activatedSkills.add(id);
|
|
2926
|
+
}
|
|
2927
|
+
}
|
|
2928
|
+
const totalIn = timeline.turns.reduce((s, turn) => s + turn.totalInputTokens, 0);
|
|
2929
|
+
const totalOut = timeline.turns.reduce((s, turn) => s + turn.totalOutputTokens, 0);
|
|
2930
|
+
const totalMs = timeline.turns.reduce((s, turn) => s + turn.totalDurationMs, 0);
|
|
2931
|
+
const totalIters = timeline.turns.reduce((s, turn) => s + turn.iterations.length, 0);
|
|
2932
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2933
|
+
"div",
|
|
2934
|
+
{
|
|
2935
|
+
"data-fp-lens": "run-summary",
|
|
2936
|
+
style: {
|
|
2937
|
+
borderTop: `1px solid ${t.border}`,
|
|
2938
|
+
background: t.bgElev,
|
|
2939
|
+
fontFamily: t.fontSans
|
|
2940
|
+
},
|
|
2941
|
+
children: [
|
|
2942
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
2943
|
+
"button",
|
|
2944
|
+
{
|
|
2945
|
+
onClick: () => setOpen((v) => !v),
|
|
2946
|
+
style: {
|
|
2947
|
+
display: "flex",
|
|
2948
|
+
alignItems: "center",
|
|
2949
|
+
gap: 8,
|
|
2950
|
+
width: "100%",
|
|
2951
|
+
padding: "8px 14px",
|
|
2952
|
+
background: "transparent",
|
|
2953
|
+
border: "none",
|
|
2954
|
+
color: t.textMuted,
|
|
2955
|
+
fontFamily: "inherit",
|
|
2956
|
+
fontSize: 12,
|
|
2957
|
+
cursor: "pointer",
|
|
2958
|
+
textAlign: "left",
|
|
2959
|
+
fontWeight: 400
|
|
2960
|
+
},
|
|
2961
|
+
children: [
|
|
2962
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { fontSize: 10 }, children: open ? "\u25BE" : "\u25B8" }),
|
|
2963
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
2964
|
+
"span",
|
|
2965
|
+
{
|
|
2966
|
+
style: {
|
|
2967
|
+
fontSize: 10,
|
|
2968
|
+
color: t.textSubtle,
|
|
2969
|
+
textTransform: "uppercase",
|
|
2970
|
+
letterSpacing: "0.08em",
|
|
2971
|
+
fontWeight: 600
|
|
2972
|
+
},
|
|
2973
|
+
children: "Run summary"
|
|
2974
|
+
}
|
|
2975
|
+
),
|
|
2976
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { flex: 1 } }),
|
|
2977
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { fontSize: 11, color: t.textMuted }, children: [
|
|
2978
|
+
timeline.tools.length,
|
|
2979
|
+
" tool call",
|
|
2980
|
+
timeline.tools.length === 1 ? "" : "s",
|
|
2981
|
+
" \xB7",
|
|
2982
|
+
" ",
|
|
2983
|
+
activatedSkills.size,
|
|
2984
|
+
" skill",
|
|
2985
|
+
activatedSkills.size === 1 ? "" : "s",
|
|
2986
|
+
" \xB7",
|
|
2987
|
+
" ",
|
|
2988
|
+
totalIn.toLocaleString(),
|
|
2989
|
+
"\u2192",
|
|
2990
|
+
totalOut.toLocaleString(),
|
|
2991
|
+
" tok \xB7",
|
|
2992
|
+
" ",
|
|
2993
|
+
(totalMs / 1e3).toFixed(1),
|
|
2994
|
+
"s"
|
|
2995
|
+
] })
|
|
2996
|
+
]
|
|
2997
|
+
}
|
|
2998
|
+
),
|
|
2999
|
+
open && /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3000
|
+
"div",
|
|
3001
|
+
{
|
|
3002
|
+
style: {
|
|
3003
|
+
padding: "6px 14px 14px",
|
|
3004
|
+
display: "grid",
|
|
3005
|
+
gridTemplateColumns: "1fr 1fr",
|
|
3006
|
+
gap: 14,
|
|
3007
|
+
fontSize: 12,
|
|
3008
|
+
color: t.text
|
|
3009
|
+
},
|
|
3010
|
+
children: [
|
|
3011
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { children: [
|
|
3012
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label4, { t, children: [
|
|
3013
|
+
"Tools used \xB7 ",
|
|
3014
|
+
timeline.tools.length
|
|
3015
|
+
] }),
|
|
3016
|
+
toolList.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: t.textSubtle, fontSize: 11, fontStyle: "italic" }, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { margin: 0, padding: 0, listStyle: "none" }, children: toolList.map(([name, stats]) => /* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3017
|
+
"li",
|
|
3018
|
+
{
|
|
3019
|
+
style: {
|
|
3020
|
+
display: "flex",
|
|
3021
|
+
gap: 8,
|
|
3022
|
+
padding: "3px 0",
|
|
3023
|
+
fontFamily: t.fontMono,
|
|
3024
|
+
fontSize: 11
|
|
3025
|
+
},
|
|
3026
|
+
children: [
|
|
3027
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: t.accent, flex: 1 }, children: name }),
|
|
3028
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { color: t.textMuted }, children: [
|
|
3029
|
+
"\xD7",
|
|
3030
|
+
stats.count
|
|
3031
|
+
] }),
|
|
3032
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: t.textSubtle, minWidth: 60, textAlign: "right" }, children: stats.totalMs > 0 ? `${Math.round(stats.totalMs)}ms` : "\u2014" })
|
|
3033
|
+
]
|
|
3034
|
+
},
|
|
3035
|
+
name
|
|
3036
|
+
)) })
|
|
3037
|
+
] }),
|
|
3038
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("section", { children: [
|
|
3039
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(Label4, { t, children: [
|
|
3040
|
+
"Skills activated \xB7 ",
|
|
3041
|
+
activatedSkills.size
|
|
3042
|
+
] }),
|
|
3043
|
+
activatedSkills.size === 0 ? /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("div", { style: { color: t.textSubtle, fontSize: 11, fontStyle: "italic" }, children: "None." }) : /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("ul", { style: { margin: 0, padding: 0, listStyle: "none" }, children: [...activatedSkills].map((id) => /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3044
|
+
"li",
|
|
3045
|
+
{
|
|
3046
|
+
style: {
|
|
3047
|
+
padding: "3px 0",
|
|
3048
|
+
fontFamily: t.fontMono,
|
|
3049
|
+
fontSize: 11,
|
|
3050
|
+
color: t.text
|
|
3051
|
+
},
|
|
3052
|
+
children: id
|
|
3053
|
+
},
|
|
3054
|
+
id
|
|
3055
|
+
)) }),
|
|
3056
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("div", { style: { marginTop: 10 }, children: [
|
|
3057
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(Label4, { t, children: "Totals" }),
|
|
3058
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)(
|
|
3059
|
+
"div",
|
|
3060
|
+
{
|
|
3061
|
+
style: {
|
|
3062
|
+
display: "grid",
|
|
3063
|
+
gridTemplateColumns: "auto 1fr",
|
|
3064
|
+
gap: "3px 10px",
|
|
3065
|
+
marginTop: 4,
|
|
3066
|
+
fontSize: 11,
|
|
3067
|
+
color: t.textMuted
|
|
3068
|
+
},
|
|
3069
|
+
children: [
|
|
3070
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Tokens" }),
|
|
3071
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { color: t.text, fontFamily: t.fontMono }, children: [
|
|
3072
|
+
totalIn.toLocaleString(),
|
|
3073
|
+
" \u2192 ",
|
|
3074
|
+
totalOut.toLocaleString()
|
|
3075
|
+
] }),
|
|
3076
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Wall time" }),
|
|
3077
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsxs)("span", { style: { color: t.text, fontFamily: t.fontMono }, children: [
|
|
3078
|
+
(totalMs / 1e3).toFixed(2),
|
|
3079
|
+
"s"
|
|
3080
|
+
] }),
|
|
3081
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "LLM calls" }),
|
|
3082
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: t.text, fontFamily: t.fontMono }, children: totalIters }),
|
|
3083
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { children: "Turns" }),
|
|
3084
|
+
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { style: { color: t.text, fontFamily: t.fontMono }, children: completedTurns.length })
|
|
3085
|
+
]
|
|
3086
|
+
}
|
|
3087
|
+
)
|
|
3088
|
+
] })
|
|
3089
|
+
] })
|
|
3090
|
+
]
|
|
3091
|
+
}
|
|
3092
|
+
)
|
|
3093
|
+
]
|
|
3094
|
+
}
|
|
3095
|
+
);
|
|
3096
|
+
}
|
|
3097
|
+
function Label4({
|
|
3098
|
+
t,
|
|
3099
|
+
children
|
|
3100
|
+
}) {
|
|
3101
|
+
return /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
3102
|
+
"div",
|
|
3103
|
+
{
|
|
3104
|
+
style: {
|
|
3105
|
+
fontSize: 10,
|
|
3106
|
+
color: t.textSubtle,
|
|
631
3107
|
textTransform: "uppercase",
|
|
632
3108
|
letterSpacing: "0.08em",
|
|
633
3109
|
fontWeight: 600,
|
|
634
|
-
marginBottom: 4
|
|
635
|
-
...style
|
|
3110
|
+
marginBottom: 4
|
|
636
3111
|
},
|
|
637
3112
|
children
|
|
638
3113
|
}
|
|
639
3114
|
);
|
|
640
3115
|
}
|
|
641
|
-
|
|
3116
|
+
|
|
3117
|
+
// src/adapters/deriveStages.ts
|
|
3118
|
+
function deriveStages(timeline) {
|
|
3119
|
+
const stages = [];
|
|
3120
|
+
let idx = 0;
|
|
3121
|
+
const push = (s) => {
|
|
3122
|
+
stages.push({ ...s, index: idx++ });
|
|
3123
|
+
};
|
|
3124
|
+
let pending = null;
|
|
3125
|
+
const consumePending = (base) => {
|
|
3126
|
+
if (!pending) return base;
|
|
3127
|
+
const merged = { ...base, ...pending };
|
|
3128
|
+
pending = null;
|
|
3129
|
+
return merged;
|
|
3130
|
+
};
|
|
3131
|
+
for (const turn of timeline.turns) {
|
|
3132
|
+
push({
|
|
3133
|
+
from: "user",
|
|
3134
|
+
to: "agent",
|
|
3135
|
+
label: truncate(turn.userPrompt, 60),
|
|
3136
|
+
primitive: "message",
|
|
3137
|
+
turnIndex: turn.index,
|
|
3138
|
+
mutations: consumePending({ messages: true })
|
|
3139
|
+
});
|
|
3140
|
+
for (const iter of turn.iterations) {
|
|
3141
|
+
const parallelCount = iter.toolCalls.length > 1 ? iter.toolCalls.length : void 0;
|
|
3142
|
+
for (const tc of iter.toolCalls) {
|
|
3143
|
+
const kind = classifyTool(tc);
|
|
3144
|
+
if (kind === "skill-management") {
|
|
3145
|
+
push({
|
|
3146
|
+
from: "agent",
|
|
3147
|
+
to: "tool",
|
|
3148
|
+
alsoLights: "skill",
|
|
3149
|
+
label: skillManagementLabel(tc),
|
|
3150
|
+
primitive: "tool",
|
|
3151
|
+
turnIndex: turn.index,
|
|
3152
|
+
iterIndex: iter.index,
|
|
3153
|
+
toolName: tc.name,
|
|
3154
|
+
toolKind: "skill",
|
|
3155
|
+
mutations: consumePending({ messages: true })
|
|
3156
|
+
});
|
|
3157
|
+
const isReadSkill = tc.name === "read_skill";
|
|
3158
|
+
push({
|
|
3159
|
+
from: "tool",
|
|
3160
|
+
to: "agent",
|
|
3161
|
+
alsoLights: "skill",
|
|
3162
|
+
label: isReadSkill ? `Skill body delivered (+${tc.result.length} chars) \u2014 will activate next step` : `Skills list (${countSkills(tc.result)} skills)`,
|
|
3163
|
+
primitive: "tool",
|
|
3164
|
+
turnIndex: turn.index,
|
|
3165
|
+
iterIndex: iter.index,
|
|
3166
|
+
toolName: tc.name,
|
|
3167
|
+
toolKind: "skill",
|
|
3168
|
+
mutations: { messages: true }
|
|
3169
|
+
});
|
|
3170
|
+
if (isReadSkill) {
|
|
3171
|
+
const spDelta = tc.result.length;
|
|
3172
|
+
const activatedSkillId = tc.arguments?.id ?? void 0;
|
|
3173
|
+
pending = {
|
|
3174
|
+
systemPrompt: true,
|
|
3175
|
+
tools: true,
|
|
3176
|
+
systemPromptDeltaChars: spDelta,
|
|
3177
|
+
// Stash the ACTUAL content that just entered the System
|
|
3178
|
+
// Prompt + the skill id that activated. These ride along
|
|
3179
|
+
// `pending` and land on the next outgoing LLM edge where
|
|
3180
|
+
// the mutation is attributed, so the UI can render a
|
|
3181
|
+
// real diff instead of a "not captured" placeholder.
|
|
3182
|
+
systemPromptAdded: tc.result,
|
|
3183
|
+
...activatedSkillId ? { activatedSkillId } : {}
|
|
3184
|
+
};
|
|
3185
|
+
}
|
|
3186
|
+
} else if (kind === "ask-human") {
|
|
3187
|
+
push({
|
|
3188
|
+
from: "agent",
|
|
3189
|
+
to: "user",
|
|
3190
|
+
label: askHumanLabel(tc),
|
|
3191
|
+
primitive: "message",
|
|
3192
|
+
turnIndex: turn.index,
|
|
3193
|
+
iterIndex: iter.index,
|
|
3194
|
+
toolName: tc.name,
|
|
3195
|
+
toolKind: "ask-human",
|
|
3196
|
+
mutations: consumePending({ messages: true })
|
|
3197
|
+
});
|
|
3198
|
+
} else {
|
|
3199
|
+
push({
|
|
3200
|
+
from: "agent",
|
|
3201
|
+
to: "tool",
|
|
3202
|
+
label: `Called ${tc.name}`,
|
|
3203
|
+
primitive: "tool",
|
|
3204
|
+
turnIndex: turn.index,
|
|
3205
|
+
iterIndex: iter.index,
|
|
3206
|
+
toolName: tc.name,
|
|
3207
|
+
...parallelCount ? { parallelCount } : {},
|
|
3208
|
+
mutations: consumePending({ messages: true })
|
|
3209
|
+
});
|
|
3210
|
+
push({
|
|
3211
|
+
from: "tool",
|
|
3212
|
+
to: "agent",
|
|
3213
|
+
label: truncate(tc.result, 80),
|
|
3214
|
+
primitive: "tool",
|
|
3215
|
+
turnIndex: turn.index,
|
|
3216
|
+
iterIndex: iter.index,
|
|
3217
|
+
toolName: tc.name,
|
|
3218
|
+
...parallelCount ? { parallelCount } : {},
|
|
3219
|
+
mutations: { messages: true }
|
|
3220
|
+
});
|
|
3221
|
+
}
|
|
3222
|
+
}
|
|
3223
|
+
}
|
|
3224
|
+
if (turn.finalContent) {
|
|
3225
|
+
const lastIter = turn.iterations[turn.iterations.length - 1];
|
|
3226
|
+
push({
|
|
3227
|
+
from: "agent",
|
|
3228
|
+
to: "user",
|
|
3229
|
+
label: truncate(turn.finalContent, 80),
|
|
3230
|
+
primitive: "message",
|
|
3231
|
+
turnIndex: turn.index,
|
|
3232
|
+
...lastIter ? { iterIndex: lastIter.index } : {},
|
|
3233
|
+
mutations: consumePending({ messages: true })
|
|
3234
|
+
});
|
|
3235
|
+
}
|
|
3236
|
+
}
|
|
3237
|
+
return stages;
|
|
3238
|
+
}
|
|
3239
|
+
function classifyTool(tc) {
|
|
3240
|
+
if (tc.name === "list_skills" || tc.name === "read_skill") return "skill-management";
|
|
3241
|
+
if (tc.name === "ask_human" || tc.name === "ask_user") return "ask-human";
|
|
3242
|
+
return "regular";
|
|
3243
|
+
}
|
|
3244
|
+
function skillManagementLabel(tc) {
|
|
3245
|
+
if (tc.name === "list_skills") return "Asked what skills are available";
|
|
3246
|
+
if (tc.name === "read_skill") {
|
|
3247
|
+
const id = tc.arguments?.id ?? "?";
|
|
3248
|
+
return `Activated the "${id}" skill`;
|
|
3249
|
+
}
|
|
3250
|
+
return `Called ${tc.name}`;
|
|
3251
|
+
}
|
|
3252
|
+
function askHumanLabel(tc) {
|
|
3253
|
+
const q = tc.arguments?.question ?? "";
|
|
3254
|
+
return q ? `Asked user: ${truncate(q, 50)}` : "Asked user for clarification";
|
|
3255
|
+
}
|
|
3256
|
+
function countSkills(result) {
|
|
3257
|
+
try {
|
|
3258
|
+
const parsed = JSON.parse(result);
|
|
3259
|
+
if (Array.isArray(parsed?.skills)) return parsed.skills.length;
|
|
3260
|
+
if (Array.isArray(parsed)) return parsed.length;
|
|
3261
|
+
} catch {
|
|
3262
|
+
}
|
|
3263
|
+
return 0;
|
|
3264
|
+
}
|
|
3265
|
+
function truncate(s, max) {
|
|
3266
|
+
const one = s.replace(/\s+/g, " ").trim();
|
|
3267
|
+
return one.length <= max ? one : one.slice(0, max - 1).trim() + "\u2026";
|
|
3268
|
+
}
|
|
3269
|
+
|
|
3270
|
+
// src/AgentLens.tsx
|
|
3271
|
+
var import_jsx_runtime7 = require("react/jsx-runtime");
|
|
3272
|
+
function AgentLens({
|
|
3273
|
+
runtimeSnapshot,
|
|
3274
|
+
timeline: providedTimeline,
|
|
3275
|
+
systemPrompt,
|
|
3276
|
+
onToolCallClick,
|
|
3277
|
+
skills,
|
|
3278
|
+
activeSkillId
|
|
3279
|
+
}) {
|
|
642
3280
|
const t = useLensTheme();
|
|
643
|
-
|
|
644
|
-
|
|
3281
|
+
const timeline = (0, import_react6.useMemo)(() => {
|
|
3282
|
+
if (providedTimeline) return providedTimeline;
|
|
3283
|
+
if (!runtimeSnapshot) return null;
|
|
3284
|
+
return fromAgentSnapshot(runtimeSnapshot);
|
|
3285
|
+
}, [providedTimeline, runtimeSnapshot]);
|
|
3286
|
+
const [selectedIterKey, setSelectedIterKey] = (0, import_react6.useState)(null);
|
|
3287
|
+
const [skillsOpen, setSkillsOpen] = (0, import_react6.useState)(false);
|
|
3288
|
+
const derivedActiveSkill = activeSkillId ?? (typeof timeline?.finalDecision?.currentSkill === "string" ? timeline.finalDecision.currentSkill : null);
|
|
3289
|
+
(0, import_react6.useEffect)(() => {
|
|
3290
|
+
if (!skillsOpen) return;
|
|
3291
|
+
const onKey = (e) => {
|
|
3292
|
+
if (e.key === "Escape") setSkillsOpen(false);
|
|
3293
|
+
};
|
|
3294
|
+
window.addEventListener("keydown", onKey);
|
|
3295
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
3296
|
+
}, [skillsOpen]);
|
|
3297
|
+
const handleToolClick = (0, import_react6.useCallback)(
|
|
3298
|
+
(inv) => {
|
|
3299
|
+
setSelectedIterKey(`${inv.turnIndex}.${inv.iterationIndex}`);
|
|
3300
|
+
onToolCallClick?.(inv);
|
|
3301
|
+
},
|
|
3302
|
+
[onToolCallClick]
|
|
3303
|
+
);
|
|
3304
|
+
if (!timeline) {
|
|
3305
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3306
|
+
"div",
|
|
3307
|
+
{
|
|
3308
|
+
"data-fp-lens": "empty",
|
|
3309
|
+
style: {
|
|
3310
|
+
padding: 32,
|
|
3311
|
+
color: t.textMuted,
|
|
3312
|
+
fontFamily: t.fontSans,
|
|
3313
|
+
textAlign: "center",
|
|
3314
|
+
background: t.bg
|
|
3315
|
+
},
|
|
3316
|
+
children: [
|
|
3317
|
+
"No agent run to show yet. Pass ",
|
|
3318
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("code", { children: "runtimeSnapshot" }),
|
|
3319
|
+
" after the agent runs."
|
|
3320
|
+
]
|
|
3321
|
+
}
|
|
3322
|
+
);
|
|
3323
|
+
}
|
|
3324
|
+
const derivedSystemPrompt = systemPrompt ?? (typeof timeline.rawSnapshot?.sharedState?.systemPrompt === "string" ? timeline.rawSnapshot.sharedState.systemPrompt : void 0);
|
|
3325
|
+
const stages = (0, import_react6.useMemo)(() => timeline ? deriveStages(timeline) : [], [timeline]);
|
|
3326
|
+
const [focusIndex, setFocusIndex] = (0, import_react6.useState)(-1);
|
|
3327
|
+
const liveIndex = stages.length - 1;
|
|
3328
|
+
const resolvedFocus = focusIndex === -1 ? liveIndex : Math.min(focusIndex, liveIndex);
|
|
3329
|
+
const isLive = focusIndex === -1;
|
|
3330
|
+
const liveIndexRef = (0, import_react6.useRef)(liveIndex);
|
|
3331
|
+
liveIndexRef.current = liveIndex;
|
|
3332
|
+
const handleFocusChange = (0, import_react6.useCallback)((i) => {
|
|
3333
|
+
setFocusIndex(i >= liveIndexRef.current ? -1 : i);
|
|
3334
|
+
}, []);
|
|
3335
|
+
(0, import_react6.useEffect)(() => {
|
|
3336
|
+
if (stages.length === 0) return;
|
|
3337
|
+
const onKey = (e) => {
|
|
3338
|
+
if (skillsOpen) return;
|
|
3339
|
+
if (e.key !== "ArrowLeft" && e.key !== "ArrowRight") return;
|
|
3340
|
+
const tgt = e.target;
|
|
3341
|
+
const tag = tgt?.tagName;
|
|
3342
|
+
if (tag === "INPUT" || tag === "TEXTAREA" || tag === "SELECT" || tgt?.isContentEditable) return;
|
|
3343
|
+
const delta = e.key === "ArrowLeft" ? -1 : 1;
|
|
3344
|
+
const next = Math.min(
|
|
3345
|
+
liveIndex,
|
|
3346
|
+
Math.max(0, resolvedFocus + delta)
|
|
3347
|
+
);
|
|
3348
|
+
handleFocusChange(next);
|
|
3349
|
+
e.preventDefault();
|
|
3350
|
+
};
|
|
3351
|
+
window.addEventListener("keydown", onKey);
|
|
3352
|
+
return () => window.removeEventListener("keydown", onKey);
|
|
3353
|
+
}, [resolvedFocus, liveIndex, stages.length, skillsOpen]);
|
|
3354
|
+
const handleEdgeClick = (0, import_react6.useCallback)(
|
|
3355
|
+
(stage) => {
|
|
3356
|
+
if (stage.iterIndex === void 0) return;
|
|
3357
|
+
setSelectedIterKey(`${stage.turnIndex}.${stage.iterIndex}`);
|
|
3358
|
+
handleFocusChange(stage.index);
|
|
3359
|
+
},
|
|
3360
|
+
[handleFocusChange]
|
|
3361
|
+
);
|
|
3362
|
+
return /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3363
|
+
"div",
|
|
645
3364
|
{
|
|
3365
|
+
"data-fp-lens": "shell",
|
|
646
3366
|
style: {
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
3367
|
+
display: "grid",
|
|
3368
|
+
// Top: TimeTravel slider (tt) + Skills button trailing on the
|
|
3369
|
+
// right. Middle-left: vertical StageFlow. Middle-right: AskCard
|
|
3370
|
+
// with current question + active step detail. Below: MessagesPanel
|
|
3371
|
+
// full width. Footer: RunSummary (only after first turn completes).
|
|
3372
|
+
gridTemplateColumns: "minmax(320px, 1fr) minmax(220px, 320px)",
|
|
3373
|
+
gridTemplateRows: "auto auto minmax(0, 1fr) auto",
|
|
3374
|
+
gridTemplateAreas: '"tt tt" "graph ask" "messages messages" "summary summary"',
|
|
3375
|
+
// Self-constraining sizing contract — Lens never requires the
|
|
3376
|
+
// host to get their flex chain exactly right.
|
|
3377
|
+
//
|
|
3378
|
+
// • `maxHeight: 100dvh` is the hard cap. Even if NOTHING
|
|
3379
|
+
// upstream delivers a bounded height, the shell can never
|
|
3380
|
+
// exceed the viewport. This is what makes the grid's
|
|
3381
|
+
// `minmax(0, 1fr)` messages row actually resolve to a
|
|
3382
|
+
// bounded number of pixels instead of expanding to content.
|
|
3383
|
+
// • `height: 100%` + `flex: 1 1 0%` let well-constrained
|
|
3384
|
+
// hosts still shrink Lens below the viewport cap when they
|
|
3385
|
+
// want a narrower sidebar.
|
|
3386
|
+
// • `overflow: hidden` clips children that would otherwise
|
|
3387
|
+
// blow past the grid and make scrollHeight == clientHeight
|
|
3388
|
+
// on MessagesPanel (the exact bug this block prevents).
|
|
3389
|
+
// • `minHeight: 0` unblocks grid + flex size resolution.
|
|
3390
|
+
flex: "1 1 0%",
|
|
3391
|
+
minHeight: 0,
|
|
3392
|
+
height: "100%",
|
|
3393
|
+
maxHeight: "100dvh",
|
|
3394
|
+
overflow: "hidden",
|
|
3395
|
+
background: t.bg,
|
|
653
3396
|
color: t.text,
|
|
654
|
-
|
|
655
|
-
overflow: "auto"
|
|
3397
|
+
fontFamily: t.fontSans
|
|
656
3398
|
},
|
|
657
|
-
children:
|
|
3399
|
+
children: [
|
|
3400
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("style", { children: `
|
|
3401
|
+
[data-iter-selected="true"] {
|
|
3402
|
+
outline-color: currentColor !important;
|
|
3403
|
+
background: color-mix(in srgb, currentColor 8%, transparent);
|
|
3404
|
+
}
|
|
3405
|
+
` }),
|
|
3406
|
+
stages.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(import_jsx_runtime7.Fragment, { children: [
|
|
3407
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3408
|
+
"div",
|
|
3409
|
+
{
|
|
3410
|
+
style: {
|
|
3411
|
+
gridArea: "tt",
|
|
3412
|
+
display: "flex",
|
|
3413
|
+
alignItems: "center"
|
|
3414
|
+
},
|
|
3415
|
+
children: [
|
|
3416
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { flex: 1, minWidth: 0 }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3417
|
+
TimeTravel,
|
|
3418
|
+
{
|
|
3419
|
+
stages,
|
|
3420
|
+
focusIndex: resolvedFocus,
|
|
3421
|
+
onFocusChange: handleFocusChange,
|
|
3422
|
+
isLive
|
|
3423
|
+
}
|
|
3424
|
+
) }),
|
|
3425
|
+
skills && skills.length > 0 && /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)(
|
|
3426
|
+
"button",
|
|
3427
|
+
{
|
|
3428
|
+
onClick: () => setSkillsOpen(true),
|
|
3429
|
+
title: "See all skills registered with the agent",
|
|
3430
|
+
style: {
|
|
3431
|
+
// Borderless — rides on the same airy feel as the
|
|
3432
|
+
// floating time-travel pill. A faint translucent fill
|
|
3433
|
+
// on hover keeps it discoverable.
|
|
3434
|
+
background: "transparent",
|
|
3435
|
+
border: "none",
|
|
3436
|
+
color: t.textMuted,
|
|
3437
|
+
padding: "0 16px",
|
|
3438
|
+
margin: "0 14px 0 0",
|
|
3439
|
+
fontSize: 12,
|
|
3440
|
+
cursor: "pointer",
|
|
3441
|
+
whiteSpace: "nowrap",
|
|
3442
|
+
display: "flex",
|
|
3443
|
+
alignItems: "center",
|
|
3444
|
+
gap: 6,
|
|
3445
|
+
fontWeight: 400,
|
|
3446
|
+
width: "auto"
|
|
3447
|
+
},
|
|
3448
|
+
children: [
|
|
3449
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { "aria-hidden": "true", children: "\u{1F4DA}" }),
|
|
3450
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("span", { children: [
|
|
3451
|
+
"Skills \xB7 ",
|
|
3452
|
+
skills.length
|
|
3453
|
+
] }),
|
|
3454
|
+
derivedActiveSkill && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3455
|
+
"span",
|
|
3456
|
+
{
|
|
3457
|
+
style: {
|
|
3458
|
+
fontSize: 9,
|
|
3459
|
+
padding: "1px 5px",
|
|
3460
|
+
borderRadius: 3,
|
|
3461
|
+
background: `color-mix(in srgb, ${t.success} 25%, transparent)`,
|
|
3462
|
+
color: t.success,
|
|
3463
|
+
fontWeight: 600,
|
|
3464
|
+
textTransform: "uppercase"
|
|
3465
|
+
},
|
|
3466
|
+
children: derivedActiveSkill
|
|
3467
|
+
}
|
|
3468
|
+
)
|
|
3469
|
+
]
|
|
3470
|
+
}
|
|
3471
|
+
)
|
|
3472
|
+
]
|
|
3473
|
+
}
|
|
3474
|
+
),
|
|
3475
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3476
|
+
"div",
|
|
3477
|
+
{
|
|
3478
|
+
style: {
|
|
3479
|
+
gridArea: "graph",
|
|
3480
|
+
minHeight: 0,
|
|
3481
|
+
overflow: "hidden",
|
|
3482
|
+
borderRight: `1px solid ${t.border}`
|
|
3483
|
+
},
|
|
3484
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3485
|
+
StageFlow,
|
|
3486
|
+
{
|
|
3487
|
+
stages,
|
|
3488
|
+
focusIndex: resolvedFocus,
|
|
3489
|
+
onEdgeClick: handleEdgeClick,
|
|
3490
|
+
activeSkillId: derivedActiveSkill
|
|
3491
|
+
}
|
|
3492
|
+
)
|
|
3493
|
+
}
|
|
3494
|
+
),
|
|
3495
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3496
|
+
"div",
|
|
3497
|
+
{
|
|
3498
|
+
style: {
|
|
3499
|
+
gridArea: "ask",
|
|
3500
|
+
minHeight: 0,
|
|
3501
|
+
overflow: "hidden",
|
|
3502
|
+
background: t.bg
|
|
3503
|
+
},
|
|
3504
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3505
|
+
AskCard,
|
|
3506
|
+
{
|
|
3507
|
+
timeline,
|
|
3508
|
+
stages,
|
|
3509
|
+
focusIndex: resolvedFocus
|
|
3510
|
+
}
|
|
3511
|
+
)
|
|
3512
|
+
}
|
|
3513
|
+
)
|
|
3514
|
+
] }),
|
|
3515
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3516
|
+
"div",
|
|
3517
|
+
{
|
|
3518
|
+
style: {
|
|
3519
|
+
gridArea: "messages",
|
|
3520
|
+
minHeight: 0,
|
|
3521
|
+
overflow: "hidden",
|
|
3522
|
+
// `position: relative` is the containing block for the
|
|
3523
|
+
// absolutely-positioned MessagesPanel inside. This is the
|
|
3524
|
+
// mechanism that forces the panel's height to match this
|
|
3525
|
+
// cell exactly, no matter what the upstream flex/grid
|
|
3526
|
+
// chain does.
|
|
3527
|
+
position: "relative"
|
|
3528
|
+
},
|
|
3529
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3530
|
+
MessagesPanel,
|
|
3531
|
+
{
|
|
3532
|
+
timeline,
|
|
3533
|
+
onToolCallClick: handleToolClick,
|
|
3534
|
+
selectedIterKey,
|
|
3535
|
+
stages,
|
|
3536
|
+
focusIndex: resolvedFocus,
|
|
3537
|
+
onFocusChange: handleFocusChange,
|
|
3538
|
+
isLive,
|
|
3539
|
+
...derivedSystemPrompt && { systemPrompt: derivedSystemPrompt }
|
|
3540
|
+
}
|
|
3541
|
+
)
|
|
3542
|
+
}
|
|
3543
|
+
),
|
|
3544
|
+
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("div", { style: { gridArea: "summary" }, children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(RunSummary, { timeline }) }),
|
|
3545
|
+
skillsOpen && skills && /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
3546
|
+
SkillsPanel,
|
|
3547
|
+
{
|
|
3548
|
+
skills,
|
|
3549
|
+
activeSkillId: derivedActiveSkill,
|
|
3550
|
+
onClose: () => setSkillsOpen(false)
|
|
3551
|
+
}
|
|
3552
|
+
)
|
|
3553
|
+
]
|
|
658
3554
|
}
|
|
659
3555
|
);
|
|
660
3556
|
}
|
|
661
|
-
function shortArgs(args) {
|
|
662
|
-
const keys = Object.keys(args);
|
|
663
|
-
if (keys.length === 0) return "";
|
|
664
|
-
if (keys.length === 1) {
|
|
665
|
-
const v = args[keys[0]];
|
|
666
|
-
if (typeof v === "string" && v.length < 40) return `${keys[0]}: "${v}"`;
|
|
667
|
-
}
|
|
668
|
-
return keys.join(", ");
|
|
669
|
-
}
|
|
670
3557
|
|
|
671
3558
|
// src/panels/IterationStrip.tsx
|
|
672
|
-
var
|
|
3559
|
+
var import_jsx_runtime8 = require("react/jsx-runtime");
|
|
673
3560
|
function IterationStrip({ timeline, selectedKey, onSelect }) {
|
|
674
3561
|
const t = useLensTheme();
|
|
675
3562
|
const chips = timeline.turns.flatMap(
|
|
676
|
-
(turn) => turn.iterations.map((iter) => ({
|
|
3563
|
+
(turn) => turn.iterations.map((iter, stepIdx) => ({
|
|
677
3564
|
key: `${turn.index}.${iter.index}`,
|
|
678
3565
|
turn: turn.index + 1,
|
|
679
|
-
|
|
680
|
-
label:
|
|
681
|
-
tools: iter.toolCalls.length,
|
|
3566
|
+
step: stepIdx + 1,
|
|
3567
|
+
label: stepHeadline(iter),
|
|
682
3568
|
durationMs: iter.durationMs ?? 0,
|
|
683
|
-
stopReason: iter.stopReason
|
|
3569
|
+
stopReason: iter.stopReason,
|
|
3570
|
+
toolCount: iter.toolCalls.length
|
|
684
3571
|
}))
|
|
685
3572
|
);
|
|
686
|
-
return /* @__PURE__ */ (0,
|
|
3573
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
687
3574
|
"div",
|
|
688
3575
|
{
|
|
689
3576
|
"data-fp-lens": "iteration-strip",
|
|
@@ -696,11 +3583,12 @@ function IterationStrip({ timeline, selectedKey, onSelect }) {
|
|
|
696
3583
|
background: t.bgElev
|
|
697
3584
|
},
|
|
698
3585
|
children: [
|
|
699
|
-
chips.length === 0 && /* @__PURE__ */ (0,
|
|
3586
|
+
chips.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { color: t.textSubtle, fontSize: 11 }, children: "No iterations yet." }),
|
|
700
3587
|
chips.map((c) => {
|
|
701
3588
|
const active = c.key === selectedKey;
|
|
702
|
-
const isFinal = c.
|
|
703
|
-
|
|
3589
|
+
const isFinal = c.toolCount === 0;
|
|
3590
|
+
const secs = c.durationMs >= 1e3 ? `${(c.durationMs / 1e3).toFixed(1)}s` : `${Math.round(c.durationMs)}ms`;
|
|
3591
|
+
return /* @__PURE__ */ (0, import_jsx_runtime8.jsxs)(
|
|
704
3592
|
"button",
|
|
705
3593
|
{
|
|
706
3594
|
onClick: () => onSelect?.(c.key),
|
|
@@ -709,23 +3597,27 @@ function IterationStrip({ timeline, selectedKey, onSelect }) {
|
|
|
709
3597
|
color: active ? "#fff" : t.textMuted,
|
|
710
3598
|
border: `1px solid ${active ? t.accent : t.border}`,
|
|
711
3599
|
borderRadius: 4,
|
|
712
|
-
padding: "4px
|
|
3600
|
+
padding: "4px 10px",
|
|
713
3601
|
fontSize: 11,
|
|
714
|
-
fontFamily:
|
|
3602
|
+
fontFamily: t.fontSans,
|
|
715
3603
|
cursor: "pointer",
|
|
716
3604
|
whiteSpace: "nowrap",
|
|
717
|
-
flexShrink: 0
|
|
3605
|
+
flexShrink: 0,
|
|
3606
|
+
maxWidth: 280,
|
|
3607
|
+
overflow: "hidden",
|
|
3608
|
+
textOverflow: "ellipsis"
|
|
718
3609
|
},
|
|
719
|
-
title: `
|
|
3610
|
+
title: `Question ${c.turn} \xB7 Step ${c.step} \xB7 ${secs}${c.stopReason ? ` \xB7 stop: ${c.stopReason}` : ""}`,
|
|
720
3611
|
children: [
|
|
721
|
-
"
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
|
|
727
|
-
|
|
728
|
-
|
|
3612
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: { fontWeight: 600 }, children: [
|
|
3613
|
+
"Step ",
|
|
3614
|
+
c.step
|
|
3615
|
+
] }),
|
|
3616
|
+
/* @__PURE__ */ (0, import_jsx_runtime8.jsxs)("span", { style: { opacity: 0.85 }, children: [
|
|
3617
|
+
" \xB7 ",
|
|
3618
|
+
c.label
|
|
3619
|
+
] }),
|
|
3620
|
+
isFinal && /* @__PURE__ */ (0, import_jsx_runtime8.jsx)("span", { style: { marginLeft: 6 }, children: "\u2713" })
|
|
729
3621
|
]
|
|
730
3622
|
},
|
|
731
3623
|
c.key
|
|
@@ -735,22 +3627,35 @@ function IterationStrip({ timeline, selectedKey, onSelect }) {
|
|
|
735
3627
|
}
|
|
736
3628
|
);
|
|
737
3629
|
}
|
|
738
|
-
function
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
|
|
3630
|
+
function stepHeadline(iter) {
|
|
3631
|
+
if (iter.toolCalls.length === 0) return "Ready to answer";
|
|
3632
|
+
if (iter.toolCalls.length === 1) {
|
|
3633
|
+
const tc = iter.toolCalls[0];
|
|
3634
|
+
if (tc.name === "list_skills") return "Looking up skills";
|
|
3635
|
+
if (tc.name === "read_skill") {
|
|
3636
|
+
const id = tc.arguments?.id;
|
|
3637
|
+
return id ? `Activated ${id}` : "Activating skill";
|
|
3638
|
+
}
|
|
3639
|
+
if (tc.name === "ask_human" || tc.name === "ask_user") {
|
|
3640
|
+
return "Asked user";
|
|
3641
|
+
}
|
|
3642
|
+
return `Called tool (${tc.name})`;
|
|
3643
|
+
}
|
|
3644
|
+
if (iter.toolCalls.length <= 3) {
|
|
3645
|
+
return `Called ${iter.toolCalls.length} tools (${iter.toolCalls.map((tc) => tc.name).join(", ")})`;
|
|
3646
|
+
}
|
|
3647
|
+
return `Called ${iter.toolCalls.length} tools in parallel`;
|
|
743
3648
|
}
|
|
744
3649
|
|
|
745
3650
|
// src/panels/ToolCallInspector.tsx
|
|
746
|
-
var
|
|
3651
|
+
var import_jsx_runtime9 = require("react/jsx-runtime");
|
|
747
3652
|
function ToolCallInspector({
|
|
748
3653
|
timeline,
|
|
749
3654
|
selectedId,
|
|
750
3655
|
onSelect
|
|
751
3656
|
}) {
|
|
752
3657
|
const t = useLensTheme();
|
|
753
|
-
return /* @__PURE__ */ (0,
|
|
3658
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
754
3659
|
"div",
|
|
755
3660
|
{
|
|
756
3661
|
"data-fp-lens": "tool-call-inspector",
|
|
@@ -764,7 +3669,7 @@ function ToolCallInspector({
|
|
|
764
3669
|
overflow: "hidden"
|
|
765
3670
|
},
|
|
766
3671
|
children: [
|
|
767
|
-
/* @__PURE__ */ (0,
|
|
3672
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
768
3673
|
"div",
|
|
769
3674
|
{
|
|
770
3675
|
style: {
|
|
@@ -778,17 +3683,17 @@ function ToolCallInspector({
|
|
|
778
3683
|
background: t.bgElev
|
|
779
3684
|
},
|
|
780
3685
|
children: [
|
|
781
|
-
"
|
|
3686
|
+
"Every tool Neo called \xB7 ",
|
|
782
3687
|
timeline.tools.length
|
|
783
3688
|
]
|
|
784
3689
|
}
|
|
785
3690
|
),
|
|
786
|
-
/* @__PURE__ */ (0,
|
|
787
|
-
timeline.tools.length === 0 && /* @__PURE__ */ (0,
|
|
3691
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)("div", { style: { overflow: "auto", flex: 1 }, children: [
|
|
3692
|
+
timeline.tools.length === 0 && /* @__PURE__ */ (0, import_jsx_runtime9.jsx)("div", { style: { padding: 14, color: t.textSubtle, fontSize: 12 }, children: "Neo hasn't called any tools yet." }),
|
|
788
3693
|
timeline.tools.map((tc) => {
|
|
789
3694
|
const active = tc.id === selectedId;
|
|
790
3695
|
const errored = tc.error === true;
|
|
791
|
-
return /* @__PURE__ */ (0,
|
|
3696
|
+
return /* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
792
3697
|
"button",
|
|
793
3698
|
{
|
|
794
3699
|
onClick: () => onSelect?.(tc),
|
|
@@ -808,7 +3713,7 @@ function ToolCallInspector({
|
|
|
808
3713
|
fontFamily: "inherit"
|
|
809
3714
|
},
|
|
810
3715
|
children: [
|
|
811
|
-
/* @__PURE__ */ (0,
|
|
3716
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
812
3717
|
"div",
|
|
813
3718
|
{
|
|
814
3719
|
style: {
|
|
@@ -819,8 +3724,8 @@ function ToolCallInspector({
|
|
|
819
3724
|
fontFamily: t.fontMono
|
|
820
3725
|
},
|
|
821
3726
|
children: [
|
|
822
|
-
/* @__PURE__ */ (0,
|
|
823
|
-
/* @__PURE__ */ (0,
|
|
3727
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)("span", { style: { color: errored ? t.error : t.accent, fontWeight: 600 }, children: tc.name }),
|
|
3728
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsxs)(
|
|
824
3729
|
"span",
|
|
825
3730
|
{
|
|
826
3731
|
style: { color: t.textSubtle, fontSize: 10, marginLeft: "auto" },
|
|
@@ -836,7 +3741,7 @@ function ToolCallInspector({
|
|
|
836
3741
|
]
|
|
837
3742
|
}
|
|
838
3743
|
),
|
|
839
|
-
/* @__PURE__ */ (0,
|
|
3744
|
+
/* @__PURE__ */ (0, import_jsx_runtime9.jsx)(
|
|
840
3745
|
"div",
|
|
841
3746
|
{
|
|
842
3747
|
style: {
|
|
@@ -872,111 +3777,6 @@ function shortArgs2(args) {
|
|
|
872
3777
|
}).join(", ");
|
|
873
3778
|
}
|
|
874
3779
|
|
|
875
|
-
// src/AgentLens.tsx
|
|
876
|
-
var import_jsx_runtime4 = require("react/jsx-runtime");
|
|
877
|
-
function AgentLens({
|
|
878
|
-
runtimeSnapshot,
|
|
879
|
-
timeline: providedTimeline,
|
|
880
|
-
systemPrompt,
|
|
881
|
-
onToolCallClick
|
|
882
|
-
}) {
|
|
883
|
-
const t = useLensTheme();
|
|
884
|
-
const timeline = (0, import_react2.useMemo)(() => {
|
|
885
|
-
if (providedTimeline) return providedTimeline;
|
|
886
|
-
if (!runtimeSnapshot) return null;
|
|
887
|
-
return fromAgentSnapshot(runtimeSnapshot);
|
|
888
|
-
}, [providedTimeline, runtimeSnapshot]);
|
|
889
|
-
const [selectedToolId, setSelectedToolId] = (0, import_react2.useState)(null);
|
|
890
|
-
const [selectedIterKey, setSelectedIterKey] = (0, import_react2.useState)(null);
|
|
891
|
-
function handleToolClick(inv) {
|
|
892
|
-
setSelectedToolId(inv.id);
|
|
893
|
-
setSelectedIterKey(`${inv.turnIndex}.${inv.iterationIndex}`);
|
|
894
|
-
onToolCallClick?.(inv);
|
|
895
|
-
}
|
|
896
|
-
if (!timeline) {
|
|
897
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
898
|
-
"div",
|
|
899
|
-
{
|
|
900
|
-
"data-fp-lens": "empty",
|
|
901
|
-
style: {
|
|
902
|
-
padding: 32,
|
|
903
|
-
color: t.textMuted,
|
|
904
|
-
fontFamily: t.fontSans,
|
|
905
|
-
textAlign: "center",
|
|
906
|
-
background: t.bg
|
|
907
|
-
},
|
|
908
|
-
children: [
|
|
909
|
-
"No agent run to show yet. Pass ",
|
|
910
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("code", { children: "runtimeSnapshot" }),
|
|
911
|
-
" after the agent runs."
|
|
912
|
-
]
|
|
913
|
-
}
|
|
914
|
-
);
|
|
915
|
-
}
|
|
916
|
-
const derivedSystemPrompt = systemPrompt ?? (typeof timeline.rawSnapshot?.sharedState?.systemPrompt === "string" ? timeline.rawSnapshot.sharedState.systemPrompt : void 0);
|
|
917
|
-
return /* @__PURE__ */ (0, import_jsx_runtime4.jsxs)(
|
|
918
|
-
"div",
|
|
919
|
-
{
|
|
920
|
-
"data-fp-lens": "shell",
|
|
921
|
-
style: {
|
|
922
|
-
display: "grid",
|
|
923
|
-
gridTemplateColumns: "1fr 320px",
|
|
924
|
-
gridTemplateRows: "auto 1fr",
|
|
925
|
-
gridTemplateAreas: '"strip strip" "messages inspector"',
|
|
926
|
-
height: "100%",
|
|
927
|
-
minHeight: 0,
|
|
928
|
-
background: t.bg,
|
|
929
|
-
color: t.text,
|
|
930
|
-
fontFamily: t.fontSans
|
|
931
|
-
},
|
|
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
|
-
` }),
|
|
939
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "strip" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
940
|
-
IterationStrip,
|
|
941
|
-
{
|
|
942
|
-
timeline,
|
|
943
|
-
selectedKey: selectedIterKey,
|
|
944
|
-
onSelect: setSelectedIterKey
|
|
945
|
-
}
|
|
946
|
-
) }),
|
|
947
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("div", { style: { gridArea: "messages", minHeight: 0, overflow: "hidden" }, children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
948
|
-
MessagesPanel,
|
|
949
|
-
{
|
|
950
|
-
timeline,
|
|
951
|
-
onToolCallClick: handleToolClick,
|
|
952
|
-
selectedIterKey,
|
|
953
|
-
...derivedSystemPrompt && { systemPrompt: derivedSystemPrompt }
|
|
954
|
-
}
|
|
955
|
-
) }),
|
|
956
|
-
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
957
|
-
"div",
|
|
958
|
-
{
|
|
959
|
-
style: {
|
|
960
|
-
gridArea: "inspector",
|
|
961
|
-
minHeight: 0,
|
|
962
|
-
overflow: "hidden",
|
|
963
|
-
borderLeft: `1px solid ${t.border}`
|
|
964
|
-
},
|
|
965
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)(
|
|
966
|
-
ToolCallInspector,
|
|
967
|
-
{
|
|
968
|
-
timeline,
|
|
969
|
-
selectedId: selectedToolId,
|
|
970
|
-
onSelect: handleToolClick
|
|
971
|
-
}
|
|
972
|
-
)
|
|
973
|
-
}
|
|
974
|
-
)
|
|
975
|
-
]
|
|
976
|
-
}
|
|
977
|
-
);
|
|
978
|
-
}
|
|
979
|
-
|
|
980
3780
|
// src/adapters/LiveTimelineBuilder.ts
|
|
981
3781
|
var LiveTimelineBuilder = class {
|
|
982
3782
|
constructor() {
|
|
@@ -1054,7 +3854,10 @@ var LiveTimelineBuilder = class {
|
|
|
1054
3854
|
toolCalls: [],
|
|
1055
3855
|
decisionAtStart: {},
|
|
1056
3856
|
visibleTools: [],
|
|
1057
|
-
startMs: Date.now()
|
|
3857
|
+
startMs: Date.now(),
|
|
3858
|
+
// Freeze the message count here so "What Neo saw" can reproduce
|
|
3859
|
+
// the context window at this exact iteration later.
|
|
3860
|
+
messagesSentCount: this.messages.length
|
|
1058
3861
|
};
|
|
1059
3862
|
this.currentTurn.iterations.push(this.currentIter);
|
|
1060
3863
|
}
|
|
@@ -1158,48 +3961,48 @@ var LiveTimelineBuilder = class {
|
|
|
1158
3961
|
};
|
|
1159
3962
|
|
|
1160
3963
|
// src/adapters/useLiveTimeline.ts
|
|
1161
|
-
var
|
|
3964
|
+
var import_react7 = require("react");
|
|
1162
3965
|
function useLiveTimeline() {
|
|
1163
|
-
const builderRef = (0,
|
|
3966
|
+
const builderRef = (0, import_react7.useRef)(null);
|
|
1164
3967
|
if (!builderRef.current) builderRef.current = new LiveTimelineBuilder();
|
|
1165
3968
|
const builder = builderRef.current;
|
|
1166
|
-
const [timeline, setTimeline] = (0,
|
|
1167
|
-
const sync = (0,
|
|
3969
|
+
const [timeline, setTimeline] = (0, import_react7.useState)(() => builder.getTimeline());
|
|
3970
|
+
const sync = (0, import_react7.useCallback)(() => {
|
|
1168
3971
|
setTimeline(builder.getTimeline());
|
|
1169
3972
|
}, [builder]);
|
|
1170
|
-
const ingest = (0,
|
|
3973
|
+
const ingest = (0, import_react7.useCallback)(
|
|
1171
3974
|
(event) => {
|
|
1172
3975
|
builder.ingest(event);
|
|
1173
3976
|
sync();
|
|
1174
3977
|
},
|
|
1175
3978
|
[builder, sync]
|
|
1176
3979
|
);
|
|
1177
|
-
const startTurn = (0,
|
|
3980
|
+
const startTurn = (0, import_react7.useCallback)(
|
|
1178
3981
|
(userPrompt) => {
|
|
1179
3982
|
builder.startTurn(userPrompt);
|
|
1180
3983
|
sync();
|
|
1181
3984
|
},
|
|
1182
3985
|
[builder, sync]
|
|
1183
3986
|
);
|
|
1184
|
-
const setSystemPrompt = (0,
|
|
3987
|
+
const setSystemPrompt = (0, import_react7.useCallback)(
|
|
1185
3988
|
(prompt) => {
|
|
1186
3989
|
builder.setSystemPrompt(prompt);
|
|
1187
3990
|
sync();
|
|
1188
3991
|
},
|
|
1189
3992
|
[builder, sync]
|
|
1190
3993
|
);
|
|
1191
|
-
const setFinalDecision = (0,
|
|
3994
|
+
const setFinalDecision = (0, import_react7.useCallback)(
|
|
1192
3995
|
(decision) => {
|
|
1193
3996
|
builder.setFinalDecision(decision);
|
|
1194
3997
|
sync();
|
|
1195
3998
|
},
|
|
1196
3999
|
[builder, sync]
|
|
1197
4000
|
);
|
|
1198
|
-
const reset = (0,
|
|
4001
|
+
const reset = (0, import_react7.useCallback)(() => {
|
|
1199
4002
|
builder.reset();
|
|
1200
4003
|
sync();
|
|
1201
4004
|
}, [builder, sync]);
|
|
1202
|
-
return (0,
|
|
4005
|
+
return (0, import_react7.useMemo)(
|
|
1203
4006
|
() => ({ timeline, ingest, startTurn, setSystemPrompt, setFinalDecision, reset, builder }),
|
|
1204
4007
|
[timeline, ingest, startTurn, setSystemPrompt, setFinalDecision, reset, builder]
|
|
1205
4008
|
);
|
|
@@ -1207,10 +4010,16 @@ function useLiveTimeline() {
|
|
|
1207
4010
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1208
4011
|
0 && (module.exports = {
|
|
1209
4012
|
AgentLens,
|
|
4013
|
+
AskCard,
|
|
1210
4014
|
IterationStrip,
|
|
1211
4015
|
LiveTimelineBuilder,
|
|
1212
4016
|
MessagesPanel,
|
|
4017
|
+
RunSummary,
|
|
4018
|
+
SkillsPanel,
|
|
4019
|
+
StageFlow,
|
|
4020
|
+
TimeTravel,
|
|
1213
4021
|
ToolCallInspector,
|
|
4022
|
+
deriveStages,
|
|
1214
4023
|
fromAgentSnapshot,
|
|
1215
4024
|
resolveLensTheme,
|
|
1216
4025
|
useLensTheme,
|