@burdenoff/fluidgrids-fe-sdk 2026.1104.3 → 2026.1105.2

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.
Files changed (69) hide show
  1. package/README.md +38 -0
  2. package/dist/ExecutionDetailPage-HQB2SWBP.js +28 -0
  3. package/dist/ExecutionsListPage-RSLL634L.js +22 -0
  4. package/dist/WorkflowBuilder-E3PNZX74.js +32 -0
  5. package/dist/WorkflowsList-473FRRP2.js +21 -0
  6. package/dist/{agentTools-SZZN6TP3.js → agentTools-5N3ZEZDW.js} +8 -7
  7. package/dist/{chunk-NIY6R42C.js → chunk-2KUZBEWW.js} +7 -5
  8. package/dist/{chunk-NTWG3CJX.js → chunk-3IXU7WUC.js} +32 -21
  9. package/dist/{chunk-AAIZ6S6E.js → chunk-3QCRKKTI.js} +70 -88
  10. package/dist/{chunk-WTV6SQYK.js → chunk-3XUWPDKJ.js} +616 -25
  11. package/dist/{chunk-XCSCD3IU.js → chunk-5CFCFA6O.js} +8 -7
  12. package/dist/{chunk-DFIX6YWP.js → chunk-62CCBMDC.js} +40 -21
  13. package/dist/{chunk-KHXRYQYP.js → chunk-64JN2TVX.js} +4 -3
  14. package/dist/{chunk-NYBL5WHP.js → chunk-6IS7EXIY.js} +3 -3
  15. package/dist/{chunk-YYVRBROH.js → chunk-6ZK4MRVA.js} +1 -1
  16. package/dist/{chunk-4YCMMBSK.js → chunk-AJVU5YW6.js} +3 -3
  17. package/dist/{chunk-NGXJHYV5.js → chunk-AMXJLVZN.js} +2 -2
  18. package/dist/{chunk-PXIFUMLA.js → chunk-AU7LACOY.js} +16 -11
  19. package/dist/{chunk-GEY7RXRZ.js → chunk-CH3YUGWR.js} +4 -4
  20. package/dist/{chunk-XNU2PLJ2.js → chunk-CNKTQ5MG.js} +189 -9
  21. package/dist/{chunk-BIB7IH26.js → chunk-EYQ7GJRW.js} +5 -5
  22. package/dist/{chunk-X6PIU7FE.js → chunk-GKFMK7FF.js} +4 -3
  23. package/dist/{chunk-NJRCAE6K.js → chunk-HK76ZUAK.js} +5 -5
  24. package/dist/{chunk-F7LQL43U.js → chunk-IL343FKX.js} +2 -2
  25. package/dist/{chunk-5D4XS3WJ.js → chunk-J3YQCEP3.js} +18 -4
  26. package/dist/{chunk-4EUEKSEQ.js → chunk-L2N6DDOI.js} +2 -2
  27. package/dist/chunk-NZAYYUQ4.js +172 -0
  28. package/dist/{chunk-ON7LK6QH.js → chunk-O7CJJNW6.js} +278 -197
  29. package/dist/{chunk-ZDCJPQ5M.js → chunk-OXXXUAWM.js} +2 -2
  30. package/dist/{chunk-D4WA2M2N.js → chunk-QFC6E3WD.js} +4 -3
  31. package/dist/{chunk-AFX3EKFN.js → chunk-QFGZXWTM.js} +16 -4
  32. package/dist/{chunk-IK7IGG6T.js → chunk-QPLFALVV.js} +9 -8
  33. package/dist/{chunk-MF7JLSJX.js → chunk-SALZ3LQB.js} +11 -2
  34. package/dist/{chunk-SS7Y66P5.js → chunk-TCIBTMJI.js} +70 -4
  35. package/dist/{chunk-OMB3WMDQ.js → chunk-TNFBRXU7.js} +11 -10
  36. package/dist/chunk-UEG2WC3G.js +502 -0
  37. package/dist/chunk-US5QSLPV.js +316 -0
  38. package/dist/{chunk-5UHAB75U.js → chunk-W5WML3OO.js} +1 -1
  39. package/dist/chunk-WZ3EJVS6.js +93 -0
  40. package/dist/{chunk-Q72EOY4T.js → chunk-X25NCWG2.js} +9 -3
  41. package/dist/{chunk-VDJFTZ2H.js → chunk-XFH6SLDK.js} +4 -93
  42. package/dist/{chunk-TBHAZK52.js → chunk-Y6M7K4UG.js} +1 -1
  43. package/dist/{chunk-AVHBWJRY.js → chunk-Z3ABLERJ.js} +3 -1
  44. package/dist/client-YVZMLEQX.js +3 -0
  45. package/dist/config-66FUPSG5.js +1 -0
  46. package/dist/executions.js +18 -15
  47. package/dist/global-client-N5EIFW6T.js +3 -0
  48. package/dist/history.js +9 -8
  49. package/dist/index.d.ts +172 -133
  50. package/dist/index.js +95 -74
  51. package/dist/{node-detail-view-GAGSLHAO.js → node-detail-view-WIWW5N6N.js} +36 -11
  52. package/dist/nodes.js +5 -3
  53. package/dist/observability.js +10 -8
  54. package/dist/{quick-config-panel-44RBX6YR.js → quick-config-panel-O64TXXK3.js} +10 -8
  55. package/dist/settings.js +11 -9
  56. package/dist/templates.js +15 -14
  57. package/dist/{workflow-builder-BMGVSwpy.d.ts → workflow-builder-7vv9dCdp.d.ts} +413 -2
  58. package/dist/workflow-builder.d.ts +2 -1
  59. package/dist/workflow-builder.js +17 -16
  60. package/dist/workflows-list.js +11 -10
  61. package/package.json +1 -1
  62. package/dist/ExecutionDetailPage-ND2VMU45.js +0 -25
  63. package/dist/ExecutionsListPage-EZ65FXER.js +0 -20
  64. package/dist/WorkflowBuilder-4I44FWII.js +0 -31
  65. package/dist/WorkflowsList-YFD2RKKQ.js +0 -20
  66. package/dist/chunk-6AMNEX2Y.js +0 -214
  67. package/dist/client-EYQDMR4O.js +0 -1
  68. package/dist/config-3DBXLCK3.js +0 -1
  69. package/dist/global-client-O2HCG5CJ.js +0 -1
@@ -1,20 +1,22 @@
1
- import { useDurableRunFields, useRunHistory, useDeterminismStatus, useRunStackTrace, RunHistoryView, SignalRunDialog, terminateDurableRun } from './chunk-D4WA2M2N.js';
2
- import { useDurableParityRunFields, useRunMetadata, useRunPending, ExecutionStatusBadge, NodeTimeline, RunLogViewer, setRunVersioningOverride } from './chunk-XNU2PLJ2.js';
3
- import { useExecution, useExecutionActions, useAutoRefresh, runChainLinks, shortRunId, callbackTone, parseMetadataDefinition, overrideRequestOf } from './chunk-5D4XS3WJ.js';
4
- import { fetchRunFailureClusters, OPEN_STATUSES, dismissRunFailureCluster, BUCKET_LABELS } from './chunk-SS7Y66P5.js';
5
- import { useRunPolicyDecisions, RunPolicyDecisions } from './chunk-NGXJHYV5.js';
6
- import { EntityTagPicker, canSaveRunAsTestCase, useWorkflowProposal, WorkflowProposalCard, MAX_CASE_NAME, saveRunAsTestCase } from './chunk-BIB7IH26.js';
7
- import { buildNodeDisplayMap, formatRunVersion } from './chunk-F7LQL43U.js';
1
+ import { useDurableRunFields, useRunHistory, useDeterminismStatus, useRunStackTrace, RunHistoryView, SignalRunDialog, terminateDurableRun } from './chunk-QFC6E3WD.js';
2
+ import { useDurableParityRunFields, hasAgentNodeState, agentNodeTraces, orderNodesByExecution, useRunMetadata, useRunPending, ExecutionStatusBadge, NodeTimeline, RunLogViewer, NodeStatusBadge, setRunVersioningOverride } from './chunk-CNKTQ5MG.js';
3
+ import { useExecution, useExecutionActions, useAutoRefresh, runChainLinks, shortRunId, callbackTone, parseMetadataDefinition, overrideRequestOf } from './chunk-J3YQCEP3.js';
4
+ import { fetchRunFailureClusters, OPEN_STATUSES, dismissRunFailureCluster, BUCKET_LABELS, formatDuration } from './chunk-TCIBTMJI.js';
5
+ import { aiCost, formatTokens, modelLabel } from './chunk-NZAYYUQ4.js';
6
+ import { useRunPolicyDecisions, RunPolicyDecisions } from './chunk-AMXJLVZN.js';
7
+ import { EntityTagPicker, canSaveRunAsTestCase, useWorkflowProposal, WorkflowProposalCard, MAX_CASE_NAME, saveRunAsTestCase } from './chunk-EYQ7GJRW.js';
8
+ import { buildNodeDisplayMap, formatRunVersion, nodeDisplayTitle } from './chunk-IL343FKX.js';
8
9
  import { AiCreditBalanceSlot } from './chunk-Y53CVZVV.js';
9
- import { useWorkflowVersions } from './chunk-AFX3EKFN.js';
10
- import { throwIfResultError, useDurableFunctionNodesEnabled, useDurableParityEnabled, runSignalTargets, canSignalRun, useWorkflowTestsEnabled, describeOperationError } from './chunk-AAIZ6S6E.js';
10
+ import { useWorkflowVersions } from './chunk-QFGZXWTM.js';
11
+ import { useDurableFunctionNodesEnabled, useDurableParityEnabled, runSignalTargets, canSignalRun, useWorkflowTestsEnabled } from './chunk-3QCRKKTI.js';
11
12
  import { useFluidGridsPermission, FLUIDGRIDS_PERMISSIONS, SdkPermissionButton } from './chunk-5375NUIO.js';
12
- import { getFluidGridsConfig } from './chunk-6AMNEX2Y.js';
13
- import { RunLogsDocument, RunLogAppendedDocument, ExplainRunDocument } from './chunk-AVHBWJRY.js';
13
+ import { RunLogsDocument, RunLogAppendedDocument, ExplainRunDocument, RunAiUsageDocument } from './chunk-Z3ABLERJ.js';
14
14
  import { useTr } from './chunk-UULVIT25.js';
15
- import { getFluidGridsClient, getFluidGridsClientSafe } from './chunk-NTWG3CJX.js';
15
+ import { getFluidGridsClient, getFluidGridsClientSafe } from './chunk-3IXU7WUC.js';
16
+ import { throwIfResultError, describeOperationError } from './chunk-US5QSLPV.js';
17
+ import { getFluidGridsConfig } from './chunk-UEG2WC3G.js';
16
18
  import { useState, useRef, useCallback, useEffect, useMemo } from 'react';
17
- import { useParams, useNavigate, Link } from 'react-router';
19
+ import { useParams, useNavigate, useSearchParams, Link } from 'react-router';
18
20
  import { Icon } from '@iconify/react';
19
21
  import { toast } from 'sonner';
20
22
  import { Button } from '@burdenoff/fe-libs/button';
@@ -1434,6 +1436,533 @@ function resolveDetailTab(selection, runId, available, fallback) {
1434
1436
  if (selection.runId !== runId) return fallback;
1435
1437
  return available.includes(selection.tab) ? selection.tab : fallback;
1436
1438
  }
1439
+ function parseDetailTabParam(value, known) {
1440
+ if (!value) return null;
1441
+ return known.includes(value) ? value : null;
1442
+ }
1443
+ function selectionForRun(selection, runId, requested, fallback) {
1444
+ if (selection.runId === runId) return selection;
1445
+ return { runId, tab: requested ?? fallback };
1446
+ }
1447
+ function AgentTracePanel({
1448
+ traces,
1449
+ nodeDisplay,
1450
+ usage,
1451
+ usageLoading,
1452
+ usageError,
1453
+ onRefreshUsage,
1454
+ focusNodeId
1455
+ }) {
1456
+ const tr = useTr();
1457
+ return /* @__PURE__ */ jsxs("div", { className: "space-y-6", "data-testid": "agent-trace-panel", children: [
1458
+ /* @__PURE__ */ jsx(
1459
+ AiUsageRollup,
1460
+ {
1461
+ usage,
1462
+ loading: usageLoading,
1463
+ error: usageError,
1464
+ onRefresh: onRefreshUsage,
1465
+ nodeDisplay,
1466
+ tr
1467
+ }
1468
+ ),
1469
+ traces.map((trace) => /* @__PURE__ */ jsx(
1470
+ AgentNodeCard,
1471
+ {
1472
+ trace,
1473
+ title: nodeDisplayTitle(nodeDisplay[trace.nodeId], trace.nodeId),
1474
+ focused: !!focusNodeId && focusNodeId === trace.nodeId,
1475
+ tr
1476
+ },
1477
+ trace.nodeStateId
1478
+ )),
1479
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: tr(
1480
+ "fluidgrids.executions.executionDetail.agent.traceApiNote",
1481
+ "Each tool call is shown as the agent recorded it. The prompt and completion of each model call, and the timing of each iteration, will appear here once agent tracing is available."
1482
+ ) })
1483
+ ] });
1484
+ }
1485
+ function CostValue({
1486
+ usage,
1487
+ tr
1488
+ }) {
1489
+ const cost = aiCost(usage);
1490
+ if (cost.kind === "priced") return /* @__PURE__ */ jsx(Fragment, { children: cost.text });
1491
+ if (cost.kind === "unpriced") {
1492
+ return /* @__PURE__ */ jsx("span", { className: "text-text-secondary", children: tr(
1493
+ "fluidgrids.executions.executionDetail.agent.notPricedYet",
1494
+ "Not priced yet"
1495
+ ) });
1496
+ }
1497
+ return /* @__PURE__ */ jsx(Fragment, { children: "\u2014" });
1498
+ }
1499
+ function Stat({
1500
+ label,
1501
+ children,
1502
+ detail
1503
+ }) {
1504
+ return /* @__PURE__ */ jsxs("div", { className: "rounded-lg border border-border-secondary bg-background-primary p-3", children: [
1505
+ /* @__PURE__ */ jsx("p", { className: "text-xs text-text-secondary", children: label }),
1506
+ /* @__PURE__ */ jsx("p", { className: "mt-1 text-lg font-semibold text-text-primary break-words", children }),
1507
+ detail && /* @__PURE__ */ jsx("p", { className: "mt-0.5 text-xs text-text-secondary", children: detail })
1508
+ ] });
1509
+ }
1510
+ function AiUsageRollup({
1511
+ usage,
1512
+ loading,
1513
+ error,
1514
+ onRefresh,
1515
+ nodeDisplay,
1516
+ tr
1517
+ }) {
1518
+ const total = usage?.total ?? null;
1519
+ const cost = aiCost(total);
1520
+ return /* @__PURE__ */ jsxs(
1521
+ "section",
1522
+ {
1523
+ "aria-label": tr(
1524
+ "fluidgrids.executions.executionDetail.agent.usageHeading",
1525
+ "AI usage"
1526
+ ),
1527
+ className: "space-y-3",
1528
+ children: [
1529
+ /* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between gap-3", children: [
1530
+ /* @__PURE__ */ jsx("h3", { className: "text-base font-semibold text-text-primary", children: tr(
1531
+ "fluidgrids.executions.executionDetail.agent.usageHeading",
1532
+ "AI usage"
1533
+ ) }),
1534
+ /* @__PURE__ */ jsxs(
1535
+ "button",
1536
+ {
1537
+ type: "button",
1538
+ onClick: onRefresh,
1539
+ disabled: loading,
1540
+ className: "flex items-center gap-1 rounded px-2 py-1 text-xs text-text-secondary hover:text-text-primary disabled:opacity-50",
1541
+ children: [
1542
+ /* @__PURE__ */ jsx(
1543
+ Icon,
1544
+ {
1545
+ icon: "mdi:refresh",
1546
+ width: 14,
1547
+ className: loading ? "animate-spin" : void 0
1548
+ }
1549
+ ),
1550
+ tr(
1551
+ "fluidgrids.executions.executionDetail.agent.refreshUsage",
1552
+ "Refresh"
1553
+ )
1554
+ ]
1555
+ }
1556
+ )
1557
+ ] }),
1558
+ error && /* @__PURE__ */ jsx(
1559
+ "div",
1560
+ {
1561
+ role: "alert",
1562
+ className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle p-3 text-sm text-status-error-text",
1563
+ children: tr(
1564
+ "fluidgrids.executions.executionDetail.agent.usageError",
1565
+ "Could not load this run's AI usage: {{message}}",
1566
+ { message: error }
1567
+ )
1568
+ }
1569
+ ),
1570
+ !usage && loading && /* @__PURE__ */ jsx("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", "aria-busy": "true", children: [1, 2, 3, 4].map((item) => /* @__PURE__ */ jsx(
1571
+ "div",
1572
+ {
1573
+ className: "h-20 animate-pulse rounded-lg bg-background-tertiary"
1574
+ },
1575
+ item
1576
+ )) }),
1577
+ total ? /* @__PURE__ */ jsxs(Fragment, { children: [
1578
+ /* @__PURE__ */ jsxs("div", { className: "grid grid-cols-2 gap-3 lg:grid-cols-4", children: [
1579
+ /* @__PURE__ */ jsx(
1580
+ Stat,
1581
+ {
1582
+ label: tr(
1583
+ "fluidgrids.executions.executionDetail.agent.modelCalls",
1584
+ "Model calls"
1585
+ ),
1586
+ children: total.calls.toLocaleString("en-US")
1587
+ }
1588
+ ),
1589
+ /* @__PURE__ */ jsx(
1590
+ Stat,
1591
+ {
1592
+ label: tr(
1593
+ "fluidgrids.executions.executionDetail.agent.inputTokens",
1594
+ "Input tokens"
1595
+ ),
1596
+ detail: total.cachedInputTokens > 0 ? tr(
1597
+ "fluidgrids.executions.executionDetail.agent.cachedTokens",
1598
+ "{{count}} cached",
1599
+ { count: formatTokens(total.cachedInputTokens) }
1600
+ ) : null,
1601
+ children: formatTokens(total.inputTokens)
1602
+ }
1603
+ ),
1604
+ /* @__PURE__ */ jsx(
1605
+ Stat,
1606
+ {
1607
+ label: tr(
1608
+ "fluidgrids.executions.executionDetail.agent.outputTokens",
1609
+ "Output tokens"
1610
+ ),
1611
+ children: formatTokens(total.outputTokens)
1612
+ }
1613
+ ),
1614
+ /* @__PURE__ */ jsx(
1615
+ Stat,
1616
+ {
1617
+ label: tr(
1618
+ "fluidgrids.executions.executionDetail.agent.estimatedCost",
1619
+ "Estimated cost"
1620
+ ),
1621
+ detail: cost.kind === "priced" && cost.partial ? tr(
1622
+ "fluidgrids.executions.executionDetail.agent.partialCost",
1623
+ "Calls not priced yet: {{count}}",
1624
+ { count: cost.unpricedCalls }
1625
+ ) : null,
1626
+ children: /* @__PURE__ */ jsx(CostValue, { usage: total, tr })
1627
+ }
1628
+ )
1629
+ ] }),
1630
+ total.calls === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-text-secondary", children: tr(
1631
+ "fluidgrids.executions.executionDetail.agent.noModelCalls",
1632
+ "No model calls recorded for this run yet."
1633
+ ) }) : usage && usage.lines.length > 0 && /* @__PURE__ */ jsx(
1634
+ UsageLines,
1635
+ {
1636
+ lines: usage.lines,
1637
+ nodeDisplay,
1638
+ tr
1639
+ }
1640
+ )
1641
+ ] }) : null
1642
+ ]
1643
+ }
1644
+ );
1645
+ }
1646
+ function UsageLines({
1647
+ lines,
1648
+ nodeDisplay,
1649
+ tr
1650
+ }) {
1651
+ return /* @__PURE__ */ jsx("div", { className: "overflow-x-auto rounded-lg border border-border-secondary", children: /* @__PURE__ */ jsxs("table", { className: "w-full min-w-[560px] text-sm", children: [
1652
+ /* @__PURE__ */ jsx("thead", { className: "bg-background-tertiary text-left text-xs text-text-secondary", children: /* @__PURE__ */ jsxs("tr", { children: [
1653
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: tr(
1654
+ "fluidgrids.executions.executionDetail.agent.lineNode",
1655
+ "Node"
1656
+ ) }),
1657
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 font-medium", children: tr(
1658
+ "fluidgrids.executions.executionDetail.agent.lineModel",
1659
+ "Model"
1660
+ ) }),
1661
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: tr(
1662
+ "fluidgrids.executions.executionDetail.agent.lineCalls",
1663
+ "Calls"
1664
+ ) }),
1665
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: tr(
1666
+ "fluidgrids.executions.executionDetail.agent.lineTokens",
1667
+ "Tokens in / out"
1668
+ ) }),
1669
+ /* @__PURE__ */ jsx("th", { className: "px-3 py-2 text-right font-medium", children: tr(
1670
+ "fluidgrids.executions.executionDetail.agent.lineCost",
1671
+ "Cost"
1672
+ ) })
1673
+ ] }) }),
1674
+ /* @__PURE__ */ jsx("tbody", { children: lines.map((line) => /* @__PURE__ */ jsxs(
1675
+ "tr",
1676
+ {
1677
+ className: "border-t border-border-secondary",
1678
+ children: [
1679
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-text-primary", children: nodeDisplayTitle(nodeDisplay[line.nodeId], line.nodeId) }),
1680
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 font-mono text-xs text-text-secondary", children: modelLabel(line.providerKey, line.modelKey) ?? tr(
1681
+ "fluidgrids.executions.executionDetail.agent.unknownModel",
1682
+ "Unknown model"
1683
+ ) }),
1684
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right text-text-primary", children: line.usage.calls.toLocaleString("en-US") }),
1685
+ /* @__PURE__ */ jsxs("td", { className: "px-3 py-2 text-right text-text-primary", children: [
1686
+ formatTokens(line.usage.inputTokens),
1687
+ " /",
1688
+ " ",
1689
+ formatTokens(line.usage.outputTokens)
1690
+ ] }),
1691
+ /* @__PURE__ */ jsx("td", { className: "px-3 py-2 text-right text-text-primary", children: /* @__PURE__ */ jsx(CostValue, { usage: line.usage, tr }) })
1692
+ ]
1693
+ },
1694
+ `${line.nodeId}:${line.operation}:${line.providerKey ?? ""}:${line.modelKey ?? ""}`
1695
+ )) })
1696
+ ] }) });
1697
+ }
1698
+ function AgentNodeCard({
1699
+ trace,
1700
+ title,
1701
+ focused,
1702
+ tr
1703
+ }) {
1704
+ const ref = useRef(null);
1705
+ useEffect(() => {
1706
+ if (focused) ref.current?.scrollIntoView({ block: "start" });
1707
+ }, [focused]);
1708
+ return /* @__PURE__ */ jsxs(
1709
+ "section",
1710
+ {
1711
+ ref,
1712
+ "aria-label": title,
1713
+ "data-agent-node": trace.nodeId,
1714
+ className: `rounded-lg border bg-background-primary p-4 ${focused ? "border-action-primary-bg" : "border-border-secondary"}`,
1715
+ children: [
1716
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
1717
+ /* @__PURE__ */ jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
1718
+ /* @__PURE__ */ jsx(
1719
+ Icon,
1720
+ {
1721
+ icon: "mdi:robot-outline",
1722
+ width: 18,
1723
+ className: "shrink-0 text-text-secondary"
1724
+ }
1725
+ ),
1726
+ /* @__PURE__ */ jsx("h4", { className: "truncate font-medium text-text-primary", children: title })
1727
+ ] }),
1728
+ /* @__PURE__ */ jsx("div", { className: "self-start sm:self-auto", children: /* @__PURE__ */ jsx(NodeStatusBadge, { status: trace.status, size: "sm" }) })
1729
+ ] }),
1730
+ /* @__PURE__ */ jsxs("dl", { className: "mt-3 grid grid-cols-2 gap-x-4 gap-y-2 text-sm sm:grid-cols-4", children: [
1731
+ /* @__PURE__ */ jsx(
1732
+ Fact,
1733
+ {
1734
+ label: tr(
1735
+ "fluidgrids.executions.executionDetail.agent.iterations",
1736
+ "Iterations"
1737
+ ),
1738
+ value: trace.iterationCount?.toLocaleString("en-US") ?? "\u2014"
1739
+ }
1740
+ ),
1741
+ /* @__PURE__ */ jsx(
1742
+ Fact,
1743
+ {
1744
+ label: tr(
1745
+ "fluidgrids.executions.executionDetail.agent.tokensUsed",
1746
+ "Tokens used"
1747
+ ),
1748
+ value: trace.tokensUsed === null ? "\u2014" : formatTokens(trace.tokensUsed)
1749
+ }
1750
+ ),
1751
+ /* @__PURE__ */ jsx(
1752
+ Fact,
1753
+ {
1754
+ label: tr(
1755
+ "fluidgrids.executions.executionDetail.agent.toolCalls",
1756
+ "Tool calls"
1757
+ ),
1758
+ value: trace.steps.length.toLocaleString("en-US")
1759
+ }
1760
+ ),
1761
+ /* @__PURE__ */ jsx(
1762
+ Fact,
1763
+ {
1764
+ label: tr(
1765
+ "fluidgrids.executions.executionDetail.agent.duration",
1766
+ "Duration"
1767
+ ),
1768
+ value: trace.durationMs === null ? "\u2014" : formatDuration(trace.durationMs / 1e3)
1769
+ }
1770
+ )
1771
+ ] }),
1772
+ trace.error && /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded border border-status-error-border bg-status-error-bg-subtle p-3 text-sm text-status-error-text", children: [
1773
+ /* @__PURE__ */ jsxs("span", { className: "font-medium", children: [
1774
+ tr("fluidgrids.executions.executionDetail.agent.error", "Error"),
1775
+ ":",
1776
+ " "
1777
+ ] }),
1778
+ /* @__PURE__ */ jsx("span", { className: "break-words", children: trace.error })
1779
+ ] }),
1780
+ trace.waitingForApproval && /* @__PURE__ */ jsx(PendingApprovals, { trace, tr }),
1781
+ /* @__PURE__ */ jsxs("div", { className: "mt-4", children: [
1782
+ /* @__PURE__ */ jsx("h5", { className: "mb-2 text-sm font-medium text-text-primary", children: tr(
1783
+ "fluidgrids.executions.executionDetail.agent.stepsHeading",
1784
+ "Tool calls"
1785
+ ) }),
1786
+ trace.steps.length === 0 ? /* @__PURE__ */ jsx("p", { className: "text-sm text-text-secondary", children: tr(
1787
+ "fluidgrids.executions.executionDetail.agent.noSteps",
1788
+ "The agent made no tool calls."
1789
+ ) }) : /* @__PURE__ */ jsx("ol", { className: "space-y-2", children: trace.steps.map((step) => /* @__PURE__ */ jsx(AgentStepRow, { step, tr }, step.index)) })
1790
+ ] }),
1791
+ trace.response && /* @__PURE__ */ jsxs("details", { className: "mt-4", open: true, children: [
1792
+ /* @__PURE__ */ jsx("summary", { className: "cursor-pointer text-sm font-medium text-text-primary", children: tr(
1793
+ "fluidgrids.executions.executionDetail.agent.finalResponse",
1794
+ "Final response"
1795
+ ) }),
1796
+ /* @__PURE__ */ jsx("pre", { className: "mt-2 max-h-80 overflow-auto rounded bg-background-tertiary p-3 font-mono text-xs whitespace-pre-wrap break-words text-text-primary", children: trace.response })
1797
+ ] })
1798
+ ]
1799
+ }
1800
+ );
1801
+ }
1802
+ function Fact({ label, value }) {
1803
+ return /* @__PURE__ */ jsxs("div", { children: [
1804
+ /* @__PURE__ */ jsx("dt", { className: "text-xs text-text-secondary", children: label }),
1805
+ /* @__PURE__ */ jsx("dd", { className: "text-text-primary", children: value })
1806
+ ] });
1807
+ }
1808
+ function PendingApprovals({
1809
+ trace,
1810
+ tr
1811
+ }) {
1812
+ return /* @__PURE__ */ jsxs("div", { className: "mt-3 rounded-lg border border-status-warning-border bg-status-warning-bg-subtle p-3", children: [
1813
+ /* @__PURE__ */ jsxs("div", { className: "flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between", children: [
1814
+ /* @__PURE__ */ jsxs("p", { className: "flex items-center gap-2 text-sm font-medium text-status-warning-text", children: [
1815
+ /* @__PURE__ */ jsx(Icon, { icon: "mdi:account-clock-outline", width: 16 }),
1816
+ tr(
1817
+ "fluidgrids.executions.executionDetail.agent.awaitingApproval",
1818
+ "Tool calls waiting for approval: {{count}}",
1819
+ { count: trace.pendingApprovals.length }
1820
+ )
1821
+ ] }),
1822
+ /* @__PURE__ */ jsx(
1823
+ Link,
1824
+ {
1825
+ to: "../approvals",
1826
+ className: "text-sm font-medium text-text-link underline-offset-2 hover:text-text-linkHover hover:underline",
1827
+ children: tr(
1828
+ "fluidgrids.executions.executionDetail.agent.reviewApprovals",
1829
+ "Review in Approvals"
1830
+ )
1831
+ }
1832
+ )
1833
+ ] }),
1834
+ trace.pendingApprovals.length > 0 && /* @__PURE__ */ jsx("ul", { className: "mt-2 space-y-2", children: trace.pendingApprovals.map((call) => /* @__PURE__ */ jsxs("li", { className: "rounded bg-background-primary p-2", children: [
1835
+ /* @__PURE__ */ jsx("p", { className: "font-mono text-xs font-medium text-text-primary", children: call.tool }),
1836
+ call.args && /* @__PURE__ */ jsx("pre", { className: "mt-1 max-h-48 overflow-auto font-mono text-xs whitespace-pre-wrap break-words text-text-secondary", children: call.args })
1837
+ ] }, call.key)) })
1838
+ ] });
1839
+ }
1840
+ function AgentStepRow({ step, tr }) {
1841
+ const marked = step.outcome !== "ok";
1842
+ return /* @__PURE__ */ jsx(
1843
+ "li",
1844
+ {
1845
+ className: `rounded border ${step.outcome === "rejected" ? "border-status-warning-border" : step.outcome === "failed" ? "border-status-error-border" : "border-border-secondary"}`,
1846
+ children: /* @__PURE__ */ jsxs("details", { children: [
1847
+ /* @__PURE__ */ jsxs("summary", { className: "flex cursor-pointer flex-wrap items-center gap-2 px-3 py-2 text-sm", children: [
1848
+ /* @__PURE__ */ jsxs("span", { className: "text-xs text-text-secondary", children: [
1849
+ step.index + 1,
1850
+ "."
1851
+ ] }),
1852
+ /* @__PURE__ */ jsx("span", { className: "min-w-0 break-all font-mono text-text-primary", children: step.tool }),
1853
+ step.outcome === "rejected" && /* @__PURE__ */ jsx("span", { className: "rounded bg-status-warning-bg-subtle px-1.5 py-0.5 text-xs text-status-warning-text", children: tr(
1854
+ "fluidgrids.executions.executionDetail.agent.stepRejected",
1855
+ "Rejected"
1856
+ ) }),
1857
+ step.outcome === "failed" && /* @__PURE__ */ jsx("span", { className: "rounded bg-status-error-bg-subtle px-1.5 py-0.5 text-xs text-status-error-text", children: tr(
1858
+ "fluidgrids.executions.executionDetail.agent.stepFailed",
1859
+ "Failed"
1860
+ ) }),
1861
+ step.durationMs !== null && /* @__PURE__ */ jsx("span", { className: "ml-auto text-xs text-text-secondary", children: formatDuration(step.durationMs / 1e3) })
1862
+ ] }),
1863
+ /* @__PURE__ */ jsxs("div", { className: "space-y-2 border-t border-border-secondary px-3 py-2", children: [
1864
+ marked && step.reason && /* @__PURE__ */ jsx(
1865
+ "p",
1866
+ {
1867
+ className: `text-sm ${step.outcome === "rejected" ? "text-status-warning-text" : "text-status-error-text"}`,
1868
+ children: step.reason
1869
+ }
1870
+ ),
1871
+ /* @__PURE__ */ jsx(
1872
+ StepBlock,
1873
+ {
1874
+ label: tr(
1875
+ "fluidgrids.executions.executionDetail.agent.stepArguments",
1876
+ "Arguments"
1877
+ ),
1878
+ value: step.args,
1879
+ empty: tr(
1880
+ "fluidgrids.executions.executionDetail.agent.stepNoArguments",
1881
+ "No arguments"
1882
+ )
1883
+ }
1884
+ ),
1885
+ /* @__PURE__ */ jsx(
1886
+ StepBlock,
1887
+ {
1888
+ label: tr(
1889
+ "fluidgrids.executions.executionDetail.agent.stepResult",
1890
+ "Result"
1891
+ ),
1892
+ value: step.observation,
1893
+ empty: tr(
1894
+ "fluidgrids.executions.executionDetail.agent.stepNoResult",
1895
+ "No result recorded"
1896
+ )
1897
+ }
1898
+ )
1899
+ ] })
1900
+ ] })
1901
+ }
1902
+ );
1903
+ }
1904
+ function StepBlock({
1905
+ label,
1906
+ value,
1907
+ empty
1908
+ }) {
1909
+ return /* @__PURE__ */ jsxs("div", { children: [
1910
+ /* @__PURE__ */ jsx("p", { className: "text-xs font-medium text-text-secondary", children: label }),
1911
+ value ? /* @__PURE__ */ jsx("pre", { className: "mt-1 max-h-64 overflow-auto rounded bg-background-tertiary p-2 font-mono text-xs whitespace-pre-wrap break-words text-text-primary", children: value }) : /* @__PURE__ */ jsx("p", { className: "mt-1 text-xs text-text-secondary", children: empty })
1912
+ ] });
1913
+ }
1914
+ var RUN_AI_USAGE_POLL_INTERVAL_MS = 5e3;
1915
+ async function fetchRunAiUsage(runId) {
1916
+ const result = await getFluidGridsClient().query({
1917
+ query: RunAiUsageDocument,
1918
+ variables: { runId },
1919
+ fetchPolicy: "network-only"
1920
+ });
1921
+ throwIfResultError(result);
1922
+ return result.data?.runAiUsage ?? null;
1923
+ }
1924
+ function useRunAiUsage(runId, { enabled, live }) {
1925
+ const [sent, setSent] = useState(0);
1926
+ const [settled, setSettled] = useState(null);
1927
+ const request = useRef(0);
1928
+ const read = useCallback(async () => {
1929
+ if (!runId || !enabled) return;
1930
+ const id = ++request.current;
1931
+ setSent(id);
1932
+ let next;
1933
+ try {
1934
+ next = { usage: await fetchRunAiUsage(runId), error: null };
1935
+ } catch (err) {
1936
+ next = {
1937
+ usage: null,
1938
+ error: err instanceof Error ? err.message : String(err)
1939
+ };
1940
+ }
1941
+ if (id !== request.current) return;
1942
+ setSettled((previous) => ({
1943
+ request: id,
1944
+ runId,
1945
+ // A failed refresh keeps the last good read of the same run on screen.
1946
+ usage: next.usage ?? (next.error && previous?.runId === runId ? previous.usage : null),
1947
+ error: next.error
1948
+ }));
1949
+ }, [runId, enabled]);
1950
+ useEffect(() => {
1951
+ void read();
1952
+ }, [read]);
1953
+ useEffect(() => {
1954
+ if (!enabled || !live) return;
1955
+ const timer = setInterval(() => void read(), RUN_AI_USAGE_POLL_INTERVAL_MS);
1956
+ return () => clearInterval(timer);
1957
+ }, [enabled, live, read]);
1958
+ const current = enabled && settled?.runId === runId ? settled : null;
1959
+ return {
1960
+ usage: current?.usage ?? null,
1961
+ loading: enabled && !!runId && (current?.request ?? -1) !== sent,
1962
+ error: current?.error ?? null,
1963
+ refetch: read
1964
+ };
1965
+ }
1437
1966
  function formatTime(value) {
1438
1967
  if (!value) return null;
1439
1968
  const date = new Date(value);
@@ -2298,19 +2827,43 @@ function SaveRunAsTestCase({ runId }) {
2298
2827
  var ALL_DETAIL_TABS = [
2299
2828
  "timeline",
2300
2829
  "history",
2830
+ "agent",
2301
2831
  "logs",
2302
2832
  "input",
2303
2833
  "context"
2304
2834
  ];
2305
- var GRAPH_DETAIL_TABS = ALL_DETAIL_TABS.filter(
2306
- (tab) => tab !== "history"
2307
- );
2835
+ function availableDetailTabs(isDurableRun, hasAgent) {
2836
+ return ALL_DETAIL_TABS.filter(
2837
+ (tab) => (tab !== "history" || isDurableRun) && (tab !== "agent" || hasAgent)
2838
+ );
2839
+ }
2308
2840
  function ExecutionDetailPage() {
2309
2841
  const tr = useTr();
2310
2842
  const { runId } = useParams();
2311
2843
  const navigate = useNavigate();
2312
- const [tabSelection, setTabSelection] = useState({ runId, tab: "timeline" });
2313
- const setActiveTab = (tab) => setTabSelection({ runId, tab });
2844
+ const [searchParams, setSearchParams] = useSearchParams();
2845
+ const requestedTab = parseDetailTabParam(
2846
+ searchParams.get("tab"),
2847
+ ALL_DETAIL_TABS
2848
+ );
2849
+ const requestedNodeId = searchParams.get("node");
2850
+ const [tabSelection, setTabSelection] = useState({ runId, tab: requestedTab ?? "timeline" });
2851
+ const [agentFocus, setAgentFocus] = useState({ runId, nodeId: requestedNodeId });
2852
+ const setActiveTab = (tab, focusNodeId = null) => {
2853
+ setTabSelection({ runId, tab });
2854
+ setAgentFocus({ runId, nodeId: focusNodeId });
2855
+ setSearchParams(
2856
+ (params) => {
2857
+ const next = new URLSearchParams(params);
2858
+ if (tab === "timeline") next.delete("tab");
2859
+ else next.set("tab", tab);
2860
+ if (focusNodeId) next.set("node", focusNodeId);
2861
+ else next.delete("node");
2862
+ return next;
2863
+ },
2864
+ { replace: true }
2865
+ );
2866
+ };
2314
2867
  const [autoRefreshEnabled, setAutoRefreshEnabled] = useState(true);
2315
2868
  const [showTerminateDialog, setShowTerminateDialog] = useState(false);
2316
2869
  const { allowed: canControlRuns } = useFluidGridsPermission(
@@ -2426,12 +2979,27 @@ function ExecutionDetailPage() {
2426
2979
  minLevel: minLogLevel
2427
2980
  });
2428
2981
  const isDurableRun = durableEnabled && execution?.executionKind === "DURABLE_FN";
2982
+ const hasAgent = hasAgentNodeState(execution?.nodeStates);
2429
2983
  const activeTab = resolveDetailTab(
2430
- tabSelection,
2984
+ selectionForRun(tabSelection, runId, requestedTab, "timeline"),
2431
2985
  runId,
2432
- isDurableRun ? ALL_DETAIL_TABS : GRAPH_DETAIL_TABS,
2986
+ availableDetailTabs(isDurableRun, hasAgent),
2433
2987
  "timeline"
2434
2988
  );
2989
+ const agentFocusNodeId = agentFocus.runId === runId ? agentFocus.nodeId : requestedNodeId;
2990
+ const runAiUsage = useRunAiUsage(runId, {
2991
+ enabled: hasAgent && activeTab === "agent",
2992
+ live: autoRefreshEnabled && isActive
2993
+ });
2994
+ const agentTraces = useMemo(
2995
+ () => agentNodeTraces(
2996
+ orderNodesByExecution(
2997
+ execution?.nodeStates ?? [],
2998
+ execution?.triggerNodeId ?? void 0
2999
+ )
3000
+ ),
3001
+ [execution?.nodeStates, execution?.triggerNodeId]
3002
+ );
2435
3003
  const runHistory = useRunHistory(runId, {
2436
3004
  enabled: isDurableRun && activeTab === "history",
2437
3005
  live: isActive
@@ -2546,7 +3114,7 @@ function ExecutionDetailPage() {
2546
3114
  },
2547
3115
  [navigate]
2548
3116
  );
2549
- const formatDuration = (ms) => {
3117
+ const formatDuration2 = (ms) => {
2550
3118
  if (!ms) return "-";
2551
3119
  if (ms < 1e3) return `${ms}ms`;
2552
3120
  if (ms < 6e4) return `${(ms / 1e3).toFixed(1)}s`;
@@ -2676,6 +3244,16 @@ function ExecutionDetailPage() {
2676
3244
  icon: "mdi:history"
2677
3245
  }
2678
3246
  ] : [],
3247
+ ...hasAgent ? [
3248
+ {
3249
+ id: "agent",
3250
+ label: tr(
3251
+ "fluidgrids.executions.executionDetail.agentTab",
3252
+ "Agent"
3253
+ ),
3254
+ icon: "mdi:robot-outline"
3255
+ }
3256
+ ] : [],
2679
3257
  {
2680
3258
  id: "logs",
2681
3259
  label: tr("fluidgrids.executions.executionDetail.logsTab", "Logs"),
@@ -3000,7 +3578,7 @@ function ExecutionDetailPage() {
3000
3578
  "fluidgrids.executions.executionDetail.durationStat",
3001
3579
  "Duration"
3002
3580
  ) }),
3003
- /* @__PURE__ */ jsx("div", { className: "text-xl font-bold text-text-primary mt-1", children: formatDuration(execution.duration) })
3581
+ /* @__PURE__ */ jsx("div", { className: "text-xl font-bold text-text-primary mt-1", children: formatDuration2(execution.duration) })
3004
3582
  ] }),
3005
3583
  /* @__PURE__ */ jsxs("div", { className: "bg-background-secondary rounded-lg border border-border-secondary p-4", children: [
3006
3584
  /* @__PURE__ */ jsx("div", { className: "text-sm text-text-secondary", children: tr(
@@ -3125,12 +3703,12 @@ function ExecutionDetailPage() {
3125
3703
  onViewChildRun: handleViewChildRun
3126
3704
  }
3127
3705
  ),
3128
- /* @__PURE__ */ jsx("div", { className: "border-b border-border-secondary mb-6", children: /* @__PURE__ */ jsx("nav", { className: "flex gap-4 -mb-px", children: tabs.map((tab) => /* @__PURE__ */ jsxs(
3706
+ /* @__PURE__ */ jsx("div", { className: "border-b border-border-secondary mb-6", children: /* @__PURE__ */ jsx("nav", { className: "flex gap-4 -mb-px overflow-x-auto", children: tabs.map((tab) => /* @__PURE__ */ jsxs(
3129
3707
  "button",
3130
3708
  {
3131
3709
  onClick: () => setActiveTab(tab.id),
3132
3710
  className: `
3133
- flex items-center gap-2 px-4 py-3 border-b-2 text-sm font-medium transition-colors
3711
+ flex shrink-0 items-center gap-2 whitespace-nowrap px-4 py-3 border-b-2 text-sm font-medium transition-colors
3134
3712
  ${activeTab === tab.id ? "border-action-primary-bg text-action-primary-text" : "border-transparent text-text-secondary hover:text-text-primary hover:border-border-primary"}
3135
3713
  `,
3136
3714
  children: [
@@ -3148,7 +3726,20 @@ function ExecutionDetailPage() {
3148
3726
  nodeDisplay,
3149
3727
  triggerNodeId: execution.triggerNodeId ?? void 0,
3150
3728
  onRetryNode: canControlRuns ? handleRetryNode : void 0,
3151
- onViewChildRun: handleViewChildRun
3729
+ onViewChildRun: handleViewChildRun,
3730
+ onViewAgentTrace: (nodeId) => setActiveTab("agent", nodeId)
3731
+ }
3732
+ ) }),
3733
+ activeTab === "agent" && hasAgent && /* @__PURE__ */ jsx("div", { className: "p-4 sm:p-6", children: /* @__PURE__ */ jsx(
3734
+ AgentTracePanel,
3735
+ {
3736
+ traces: agentTraces,
3737
+ nodeDisplay,
3738
+ usage: runAiUsage.usage,
3739
+ usageLoading: runAiUsage.loading,
3740
+ usageError: runAiUsage.error,
3741
+ onRefreshUsage: () => void runAiUsage.refetch(),
3742
+ focusNodeId: agentFocusNodeId
3152
3743
  }
3153
3744
  ) }),
3154
3745
  activeTab === "history" && isDurableRun && /* @__PURE__ */ jsxs("div", { className: "space-y-4 p-4 sm:p-6", children: [