@burdenoff/fluidgrids-fe-sdk 2026.1111.4 → 2026.1111.5
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/{ExecutionDetailPage-CdcutZhM.js → ExecutionDetailPage-CKmm-MTf.js} +602 -33
- package/dist/{FailureTriagePanel-4z3sJbF-.js → FailureTriagePanel-LodnXzJr.js} +2 -2
- package/dist/{FluidGridsProvider-D4VBLmsU.js → FluidGridsProvider-BNzMznqt.js} +1 -1
- package/dist/{HistoryPage-DsuGx50x.js → HistoryPage-DIioKCod.js} +3 -3
- package/dist/{InsightsPage-DPSE3P7m.js → InsightsPage-Bm2oCTqf.js} +6 -6
- package/dist/{ManagedAiPolicyAuthority-Dc9UeQPh.js → ManagedAiPolicyAuthority-D624rJtj.js} +7 -7
- package/dist/{MissingNodesInstallModal-DLaS7YqW.js → MissingNodesInstallModal-5iwp-P3H.js} +2 -2
- package/dist/{NodesPage-C2woL-6F.js → NodesPage-CYijlEFV.js} +2 -2
- package/dist/{PublishCustomNodeAction-ByxKmyOF.js → PublishCustomNodeAction-CGrwIjy-.js} +1 -1
- package/dist/{TemplateConfigurationModal-Cc9ULJd8.js → TemplateConfigurationModal-BRjVScYa.js} +2 -2
- package/dist/{TemplateDetailPanel-CnlspQbn.js → TemplateDetailPanel-BP43BIne.js} +3 -3
- package/dist/{TemplatesPage-CZdxYIcf.js → TemplatesPage-Bw--Ybm9.js} +6 -6
- package/dist/{VersionDiffDialog-B6JNtNM1.js → VersionDiffDialog-87FMkJQb.js} +1 -1
- package/dist/{WorkflowProposalCard-Ci5kwjR4.js → WorkflowProposalCard-1Av72TtA.js} +2 -2
- package/dist/{WorkflowSearchRedirect-CoCTVuHn.js → WorkflowSearchRedirect-IDjgBWKT.js} +10 -10
- package/dist/{WorkflowShareDialog-DknKAi9x.js → WorkflowShareDialog-EsWpP8h1.js} +3 -3
- package/dist/{WorkflowsList-BzCLsBR-.js → WorkflowsList-C-beGZ58.js} +6 -6
- package/dist/{agent-form-hb7BR-JZ.js → agent-form-IKft_4iz.js} +1 -1
- package/dist/{agentTools-NEBmfRWF.js → agentTools-BQY87HJw.js} +2 -2
- package/dist/{ai-usage-CK61EZWc.js → ai-usage-CMWDlKmM.js} +2 -2
- package/dist/{codec-client-C3LkdZvc.js → codec-client-DEBa-Wl0.js} +1 -1
- package/dist/executions.js +1 -1
- package/dist/{flow-builder-28Hp8NgO.js → flow-builder-DOw2DgVO.js} +23 -23
- package/dist/{graphql-types-CulUbQWN.js → graphql-types-Bi7XFTD2.js} +18 -1
- package/dist/history.js +1 -1
- package/dist/{index-lX6U7gi1.d.ts → index-CavhNsSY.d.ts} +155 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +25 -25
- package/dist/{node-detail-view-CVkO4pda.js → node-detail-view-D56v1bff.js} +8 -8
- package/dist/{node-endpoint-configs-DS59aLlH.js → node-endpoint-configs-Dol5ckHv.js} +812 -1
- package/dist/nodes.js +1 -1
- package/dist/observability.d.ts +1 -1
- package/dist/observability.js +1 -1
- package/dist/{quick-config-panel-CpjVDTyF.js → quick-config-panel-BhkLeEy4.js} +2 -2
- package/dist/settings.js +1 -1
- package/dist/templates.js +1 -1
- package/dist/{useAgentDefinitions-SRq-nq4y.js → useAgentDefinitions-CUXSBw0L.js} +1 -1
- package/dist/{useExecutions-BdDmxTNK.js → useExecutions-CvGl7yhb.js} +3 -3
- package/dist/{useObservability-CrZ-YuBS.js → useObservability--lPyvKqs.js} +2 -2
- package/dist/{useRunHistory-BVxQmQ6g.js → useRunHistory-Cu_oiZBw.js} +3 -3
- package/dist/{useWorkflows-BfDQmAeS.js → useWorkflows-CGF0B59E.js} +2 -2
- package/dist/workflow-builder.js +2 -2
- package/dist/workflows-list.js +1 -1
- package/package.json +1 -1
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { t as __exportAll } from "./rolldown-runtime-hDbaFkMy.js";
|
|
3
|
-
import { $ as
|
|
4
|
-
import { $t as runDurationMs, Hn as useDurableFunctionNodesEnabled, Pn as runSignalTargets, Qt as nodeStateDurationMs, Un as useDurableParityEnabled, Yn as useWorkflowTestsEnabled, Zt as formatElapsedMs, jn as durableInterfaceOf, kn as canSignalRun, qn as usePhaseCFlags } from "./FluidGridsProvider-
|
|
3
|
+
import { $r as WorkflowRunsCountDocument, A as CreateWorkerTokenDocument, Bi as throwIfResultError, Dn as SetWorkerTokenConnectionAllowlistDocument, Ei as getFluidGridsClientSafe, Hn as TaskQueuesDocument, Kr as WorkflowRunHierarchyDocument, Li as describeOperationError, Ti as getFluidGridsClient, U as DeleteTaskQueueDocument, Vn as TaskQueueStatsDocument, W as DeleteWorkerTokenDocument, Wi as getFluidGridsConfig, Xr as WorkflowRunPendingDocument, Yr as WorkflowRunMetadataDocument, bi as WorkflowWorkersDocument, bn as RunLogsDocument, c as AgentTraceDocument, dt as ExplainRunDocument, fr as WorkerTokensDocument, k as CreateTaskQueueDocument, kn as SetWorkflowRunVersioningOverrideDocument, ln as RotateWorkerTokenDocument, na as useExecutionsStore, nt as DurableParityRunFieldsDocument, rr as UpdateTaskQueueDocument, s as AgentStepUpdatedDocument, ta as DEFAULT_EXECUTIONS_FILTER, un as RunAiUsageDocument, vn as RunLogAppendedDocument, yr as WorkflowBatchOperationUpdatedDocument } from "./node-endpoint-configs-Dol5ckHv.js";
|
|
4
|
+
import { $t as runDurationMs, Hn as useDurableFunctionNodesEnabled, Pn as runSignalTargets, Qt as nodeStateDurationMs, Un as useDurableParityEnabled, Yn as useWorkflowTestsEnabled, Zt as formatElapsedMs, jn as durableInterfaceOf, kn as canSignalRun, qn as usePhaseCFlags } from "./FluidGridsProvider-BNzMznqt.js";
|
|
5
5
|
import { r as useTr } from "./TranslationBridge-Da-TPgQm.js";
|
|
6
|
-
import { h as useWorkflowDefinitions, v as useWorkflowVersions } from "./useWorkflows-
|
|
7
|
-
import {
|
|
8
|
-
import { _ as statusCountFilter, c as OPERATORS_BY_TYPE, d as STATUS_COUNT_GROUP_BY, f as callbackTone, g as shortRunId, h as runChainLinks, i as useExecutionStats, l as buildSearchAttributeFilter, m as parseMetadataDefinition, n as useExecution, o as useExecutionsWithStore, p as overrideRequestOf, r as useExecutionActions, s as EMPTY_SEARCH_FILTER, t as useAutoRefresh, u as searchFilterConflicts, v as statusCountsOf, y as validateDateRange } from "./useExecutions-
|
|
6
|
+
import { h as useWorkflowDefinitions, v as useWorkflowVersions } from "./useWorkflows-CGF0B59E.js";
|
|
7
|
+
import { $u as ErrorType, AF as WorkflowResetType, L as AgentStepKind, fF as WorkflowBatchOperationType, kF as WorkflowQueryRejectCondition, mP as VersioningBehavior, pI as useFluidGridsPermission, qF as WorkflowUpdateWaitFor, sI as FLUIDGRIDS_PERMISSIONS, uI as SdkPermissionButton } from "./graphql-types-Bi7XFTD2.js";
|
|
8
|
+
import { _ as statusCountFilter, c as OPERATORS_BY_TYPE, d as STATUS_COUNT_GROUP_BY, f as callbackTone, g as shortRunId, h as runChainLinks, i as useExecutionStats, l as buildSearchAttributeFilter, m as parseMetadataDefinition, n as useExecution, o as useExecutionsWithStore, p as overrideRequestOf, r as useExecutionActions, s as EMPTY_SEARCH_FILTER, t as useAutoRefresh, u as searchFilterConflicts, v as statusCountsOf, y as validateDateRange } from "./useExecutions-CvGl7yhb.js";
|
|
9
9
|
import { n as useFluidGridsPageControls } from "./pageControlsBridge-0pX9s-3k.js";
|
|
10
10
|
import { t as executionsControls } from "./pageControlSpecs-DZJ9K37m.js";
|
|
11
11
|
import { t as FluidGridsDocsLink } from "./FluidGridsDocsLink-JxkBpOeb.js";
|
|
12
|
-
import { $ as startBatchTerminate, A as fetchBatchOperation, B as jsonArg, F as fetchRunControlFields, G as resetRun, I as fetchRunHistoryArchive, K as resetRunToLastCleanTask, L as fetchRunUpdate, N as fetchCodecServerSettings, O as failActivityById, P as fetchPauseRules, Q as startBatchOperation, R as fetchSearchAttributes, U as queryRun, V as pauseActivities, W as resetActivities, X as sendRunUpdate, Z as startBatchExport, _ as useResource, at as readTyped, c as FieldError, d as NativeSelect, f as RUN_CONTROL_DIALOG_STYLE, g as parseJsonObjectInput, h as parseJsonInput, it as upsertRunSearchAttributes, j as fetchBatchOperations, l as JsonBlock, m as newRunControlId, ot as writeTyped, p as StatusPill, q as revokeSignalToken, rt as updateActivityOptions, s as isAgentNodeType, tt as unpauseActivities, u as JsonField, w as createSignalToken, x as completeActivityById, y as cancelBatchOperation, z as fetchSignalTokens } from "./agent-form-
|
|
13
|
-
import { C as useAvailableTags, _ as buildNodeDisplayMap, b as EntityTagPicker, n as useWorkflowProposal, o as canSaveRunAsTestCase, r as saveRunAsTestCase, t as WorkflowProposalCard, v as formatRunVersion, y as nodeDisplayTitle } from "./WorkflowProposalCard-
|
|
12
|
+
import { $ as startBatchTerminate, A as fetchBatchOperation, B as jsonArg, F as fetchRunControlFields, G as resetRun, I as fetchRunHistoryArchive, K as resetRunToLastCleanTask, L as fetchRunUpdate, N as fetchCodecServerSettings, O as failActivityById, P as fetchPauseRules, Q as startBatchOperation, R as fetchSearchAttributes, U as queryRun, V as pauseActivities, W as resetActivities, X as sendRunUpdate, Z as startBatchExport, _ as useResource, at as readTyped, c as FieldError, d as NativeSelect, f as RUN_CONTROL_DIALOG_STYLE, g as parseJsonObjectInput, h as parseJsonInput, it as upsertRunSearchAttributes, j as fetchBatchOperations, l as JsonBlock, m as newRunControlId, ot as writeTyped, p as StatusPill, q as revokeSignalToken, rt as updateActivityOptions, s as isAgentNodeType, tt as unpauseActivities, u as JsonField, w as createSignalToken, x as completeActivityById, y as cancelBatchOperation, z as fetchSignalTokens } from "./agent-form-IKft_4iz.js";
|
|
13
|
+
import { C as useAvailableTags, _ as buildNodeDisplayMap, b as EntityTagPicker, n as useWorkflowProposal, o as canSaveRunAsTestCase, r as saveRunAsTestCase, t as WorkflowProposalCard, v as formatRunVersion, y as nodeDisplayTitle } from "./WorkflowProposalCard-1Av72TtA.js";
|
|
14
14
|
import { t as AiCreditBalanceSlot } from "./aiCreditsBridge-BuE92tKo.js";
|
|
15
|
-
import { a as fetchRunFailureClusters, i as dismissRunFailureCluster, o as runListFilterFromSearch, r as OPEN_STATUSES, s as runListLinkKey, t as BUCKET_LABELS } from "./FailureTriagePanel-
|
|
16
|
-
import { a as encodedPayloadBytes, f as EffectBadge, h as useRunPolicyDecisions, i as decodePayloads, l as formatBudgetUsd, n as checkCodecServerUrl, o as isEncodedPayload, r as containsEncodedPayload, t as CodecServerError } from "./codec-client-
|
|
17
|
-
import { a as useDurableRunFields, i as useDeterminismStatus, n as SignalRunDialog, o as useRunStackTrace, r as terminateDurableRun, s as RunHistoryView, t as useRunHistory } from "./useRunHistory-
|
|
18
|
-
import { a as formatTokens, o as modelLabel, r as aiCost } from "./ai-usage-
|
|
15
|
+
import { a as fetchRunFailureClusters, i as dismissRunFailureCluster, o as runListFilterFromSearch, r as OPEN_STATUSES, s as runListLinkKey, t as BUCKET_LABELS } from "./FailureTriagePanel-LodnXzJr.js";
|
|
16
|
+
import { a as encodedPayloadBytes, f as EffectBadge, h as useRunPolicyDecisions, i as decodePayloads, l as formatBudgetUsd, n as checkCodecServerUrl, o as isEncodedPayload, r as containsEncodedPayload, t as CodecServerError } from "./codec-client-DEBa-Wl0.js";
|
|
17
|
+
import { a as useDurableRunFields, i as useDeterminismStatus, n as SignalRunDialog, o as useRunStackTrace, r as terminateDurableRun, s as RunHistoryView, t as useRunHistory } from "./useRunHistory-Cu_oiZBw.js";
|
|
18
|
+
import { a as formatTokens, d as formatMicroUsd, o as modelLabel, r as aiCost } from "./ai-usage-CMWDlKmM.js";
|
|
19
19
|
import { useCallback, useEffect, useMemo, useRef, useState } from "react";
|
|
20
20
|
import { Link, useNavigate, useParams, useSearchParams } from "react-router";
|
|
21
21
|
import { Icon } from "@iconify/react";
|
|
@@ -1633,14 +1633,14 @@ function ExecutionTimeline({ executions, loading, onItemClick, onAction }) {
|
|
|
1633
1633
|
* instead of `steps`. Output is free-form JSON, so every read is defensive:
|
|
1634
1634
|
* a field of an unexpected shape is skipped, never thrown on.
|
|
1635
1635
|
*/
|
|
1636
|
-
function isRecord$
|
|
1636
|
+
function isRecord$3(value) {
|
|
1637
1637
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
1638
1638
|
}
|
|
1639
1639
|
function asRecord(value) {
|
|
1640
|
-
if (isRecord$
|
|
1640
|
+
if (isRecord$3(value)) return value;
|
|
1641
1641
|
if (typeof value === "string") {
|
|
1642
1642
|
const parsed = tryParseJson(value);
|
|
1643
|
-
return isRecord$
|
|
1643
|
+
return isRecord$3(parsed) ? parsed : null;
|
|
1644
1644
|
}
|
|
1645
1645
|
return null;
|
|
1646
1646
|
}
|
|
@@ -1702,7 +1702,7 @@ function classifyObservation(observation) {
|
|
|
1702
1702
|
};
|
|
1703
1703
|
}
|
|
1704
1704
|
function toStep(raw, index) {
|
|
1705
|
-
if (!isRecord$
|
|
1705
|
+
if (!isRecord$3(raw)) return null;
|
|
1706
1706
|
const tool = stringOrNull(raw.tool) ?? stringOrNull(raw.toolName) ?? stringOrNull(raw.action) ?? stringOrNull(raw.name);
|
|
1707
1707
|
if (!tool) return null;
|
|
1708
1708
|
const observationRaw = raw.observation ?? raw.output ?? raw.result;
|
|
@@ -1731,7 +1731,7 @@ function toPendingApprovals(raw) {
|
|
|
1731
1731
|
if (!Array.isArray(raw)) return [];
|
|
1732
1732
|
const pending = [];
|
|
1733
1733
|
for (const item of raw) {
|
|
1734
|
-
if (!isRecord$
|
|
1734
|
+
if (!isRecord$3(item)) continue;
|
|
1735
1735
|
const tool = stringOrNull(item.name) ?? stringOrNull(item.tool);
|
|
1736
1736
|
if (!tool) continue;
|
|
1737
1737
|
const callId = stringOrNull(item.id) ?? stringOrNull(item.callId);
|
|
@@ -1753,7 +1753,7 @@ const PAYLOAD_KEYS = [
|
|
|
1753
1753
|
"intermediateSteps"
|
|
1754
1754
|
];
|
|
1755
1755
|
function looksLikeAgentPayload(value) {
|
|
1756
|
-
return isRecord$
|
|
1756
|
+
return isRecord$3(value) && PAYLOAD_KEYS.some((key) => key in value);
|
|
1757
1757
|
}
|
|
1758
1758
|
/**
|
|
1759
1759
|
* The agent payload inside a node output: the output itself when it carries
|
|
@@ -5073,7 +5073,7 @@ function RunDataPrunedNotice({ dataPrunedAt }) {
|
|
|
5073
5073
|
}
|
|
5074
5074
|
|
|
5075
5075
|
// src/modules/executions/utils/run-queue-marker.ts
|
|
5076
|
-
function isRecord$
|
|
5076
|
+
function isRecord$2(value) {
|
|
5077
5077
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5078
5078
|
}
|
|
5079
5079
|
function isRunQueueScope(value) {
|
|
@@ -5081,9 +5081,9 @@ function isRunQueueScope(value) {
|
|
|
5081
5081
|
}
|
|
5082
5082
|
/** The queue marker on a run's context, or null when there is none or it is malformed. */
|
|
5083
5083
|
function readRunQueueMarker(context) {
|
|
5084
|
-
if (!isRecord$
|
|
5084
|
+
if (!isRecord$2(context)) return null;
|
|
5085
5085
|
const marker = context.concurrency;
|
|
5086
|
-
if (!isRecord$
|
|
5086
|
+
if (!isRecord$2(marker)) return null;
|
|
5087
5087
|
const { queuedAt, checkedAt, limit, active, position, scope } = marker;
|
|
5088
5088
|
if (typeof queuedAt !== "string" || typeof checkedAt !== "string" || typeof limit !== "number" || typeof active !== "number" || typeof position !== "number" || scope !== void 0 && !isRunQueueScope(scope)) return null;
|
|
5089
5089
|
return {
|
|
@@ -5903,19 +5903,199 @@ function selectionForRun(selection, runId, requested, fallback) {
|
|
|
5903
5903
|
};
|
|
5904
5904
|
}
|
|
5905
5905
|
|
|
5906
|
+
// src/modules/executions/utils/agent-steps.ts
|
|
5907
|
+
function isRecord$1(value) {
|
|
5908
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5909
|
+
}
|
|
5910
|
+
function text$1(value) {
|
|
5911
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
5912
|
+
}
|
|
5913
|
+
/** Every step of a trace, as one flat list. */
|
|
5914
|
+
function flattenAgentTrace(trace) {
|
|
5915
|
+
if (!trace) return [];
|
|
5916
|
+
return trace.nodes.flatMap((node) => node.iterations.flatMap((iteration) => iteration.steps));
|
|
5917
|
+
}
|
|
5918
|
+
/**
|
|
5919
|
+
* `current` with `incoming` added. A step already held keeps the newer copy
|
|
5920
|
+
* only when that copy carries a cost the held one lacks (a re-read after the
|
|
5921
|
+
* ledger priced the call); otherwise the held copy stays.
|
|
5922
|
+
*/
|
|
5923
|
+
function mergeAgentSteps(current, incoming) {
|
|
5924
|
+
const next = new Map(current);
|
|
5925
|
+
for (const step of incoming) {
|
|
5926
|
+
const held = next.get(step.id);
|
|
5927
|
+
if (!held || held.costMicroUsd === null && step.costMicroUsd !== null) next.set(step.id, step);
|
|
5928
|
+
}
|
|
5929
|
+
return next;
|
|
5930
|
+
}
|
|
5931
|
+
function sumCost(values) {
|
|
5932
|
+
const priced = values.filter((value) => value !== null);
|
|
5933
|
+
return priced.length ? priced.reduce((sum, value) => sum + value, 0) : null;
|
|
5934
|
+
}
|
|
5935
|
+
function toTurn(step) {
|
|
5936
|
+
const output = step.output;
|
|
5937
|
+
return {
|
|
5938
|
+
key: step.id,
|
|
5939
|
+
model: step.model,
|
|
5940
|
+
tokensIn: step.tokensIn,
|
|
5941
|
+
tokensOut: step.tokensOut,
|
|
5942
|
+
latencyMs: step.latencyMs,
|
|
5943
|
+
costMicroUsd: step.costMicroUsd,
|
|
5944
|
+
input: prettyValue(step.input),
|
|
5945
|
+
reply: isRecord$1(output) ? text$1(output.content) ?? prettyValue(output.toolCalls) ?? text$1(output.error) : prettyValue(output)
|
|
5946
|
+
};
|
|
5947
|
+
}
|
|
5948
|
+
function toFinal(step) {
|
|
5949
|
+
const output = step.output;
|
|
5950
|
+
if (!isRecord$1(output)) return {
|
|
5951
|
+
answer: prettyValue(output),
|
|
5952
|
+
structuredOutput: null,
|
|
5953
|
+
outputErrors: []
|
|
5954
|
+
};
|
|
5955
|
+
return {
|
|
5956
|
+
answer: text$1(output.answer),
|
|
5957
|
+
structuredOutput: prettyValue(output.structuredOutput),
|
|
5958
|
+
outputErrors: Array.isArray(output.outputErrors) ? output.outputErrors.filter((error) => typeof error === "string") : []
|
|
5959
|
+
};
|
|
5960
|
+
}
|
|
5961
|
+
function errorOf(step) {
|
|
5962
|
+
const output = step.output;
|
|
5963
|
+
return isRecord$1(output) ? text$1(output.error) : text$1(output);
|
|
5964
|
+
}
|
|
5965
|
+
function buildIteration(iteration, steps) {
|
|
5966
|
+
const turns = [];
|
|
5967
|
+
const toolCalls = [];
|
|
5968
|
+
const byCallId = /* @__PURE__ */ new Map();
|
|
5969
|
+
let final = null;
|
|
5970
|
+
let error = null;
|
|
5971
|
+
for (const step of steps) switch (step.kind) {
|
|
5972
|
+
case "PLAN":
|
|
5973
|
+
turns.push(toTurn(step));
|
|
5974
|
+
break;
|
|
5975
|
+
case "TOOL_CALL": {
|
|
5976
|
+
const output = step.output;
|
|
5977
|
+
const view = {
|
|
5978
|
+
key: step.id,
|
|
5979
|
+
callId: step.toolCallId,
|
|
5980
|
+
tool: step.toolName ?? "?",
|
|
5981
|
+
args: prettyValue(step.input),
|
|
5982
|
+
rule: isRecord$1(output) ? text$1(output.rule) : null,
|
|
5983
|
+
result: null,
|
|
5984
|
+
hasResult: false,
|
|
5985
|
+
outcome: "ok",
|
|
5986
|
+
reason: null,
|
|
5987
|
+
latencyMs: null,
|
|
5988
|
+
approvalId: null
|
|
5989
|
+
};
|
|
5990
|
+
toolCalls.push(view);
|
|
5991
|
+
if (step.toolCallId) byCallId.set(step.toolCallId, view);
|
|
5992
|
+
break;
|
|
5993
|
+
}
|
|
5994
|
+
case "TOOL_RESULT": {
|
|
5995
|
+
const { outcome, reason } = classifyObservation(step.output);
|
|
5996
|
+
const result = {
|
|
5997
|
+
result: prettyValue(step.output),
|
|
5998
|
+
hasResult: true,
|
|
5999
|
+
outcome,
|
|
6000
|
+
reason,
|
|
6001
|
+
latencyMs: step.latencyMs,
|
|
6002
|
+
approvalId: step.approvalId
|
|
6003
|
+
};
|
|
6004
|
+
const call = step.toolCallId ? byCallId.get(step.toolCallId) : void 0;
|
|
6005
|
+
if (call) Object.assign(call, result);
|
|
6006
|
+
else toolCalls.push({
|
|
6007
|
+
key: step.id,
|
|
6008
|
+
callId: step.toolCallId,
|
|
6009
|
+
tool: step.toolName ?? "?",
|
|
6010
|
+
args: null,
|
|
6011
|
+
rule: null,
|
|
6012
|
+
...result
|
|
6013
|
+
});
|
|
6014
|
+
break;
|
|
6015
|
+
}
|
|
6016
|
+
case "FINAL":
|
|
6017
|
+
final = toFinal(step);
|
|
6018
|
+
break;
|
|
6019
|
+
case "ERROR": error = errorOf(step);
|
|
6020
|
+
}
|
|
6021
|
+
return {
|
|
6022
|
+
iteration,
|
|
6023
|
+
turns,
|
|
6024
|
+
toolCalls,
|
|
6025
|
+
final,
|
|
6026
|
+
error,
|
|
6027
|
+
tokensIn: turns.reduce((sum, turn) => sum + (turn.tokensIn ?? 0), 0),
|
|
6028
|
+
tokensOut: turns.reduce((sum, turn) => sum + (turn.tokensOut ?? 0), 0),
|
|
6029
|
+
latencyMs: steps.reduce((sum, step) => sum + (step.latencyMs ?? 0), 0),
|
|
6030
|
+
costMicroUsd: sumCost(turns.map((turn) => turn.costMicroUsd))
|
|
6031
|
+
};
|
|
6032
|
+
}
|
|
6033
|
+
function nodeKey(step) {
|
|
6034
|
+
return step.nodeStateId ?? `node:${step.nodeId}`;
|
|
6035
|
+
}
|
|
6036
|
+
/**
|
|
6037
|
+
* The steps grouped by node execution (in the order the executions started)
|
|
6038
|
+
* and iteration. A tool result recorded after an approval pause belongs to
|
|
6039
|
+
* the iteration of its call.
|
|
6040
|
+
*/
|
|
6041
|
+
function groupAgentSteps(steps) {
|
|
6042
|
+
const byNode = /* @__PURE__ */ new Map();
|
|
6043
|
+
for (const step of steps) {
|
|
6044
|
+
const key = nodeKey(step);
|
|
6045
|
+
const list = byNode.get(key);
|
|
6046
|
+
if (list) list.push(step);
|
|
6047
|
+
else byNode.set(key, [step]);
|
|
6048
|
+
}
|
|
6049
|
+
const nodes = [];
|
|
6050
|
+
for (const list of byNode.values()) {
|
|
6051
|
+
list.sort((a, b) => a.sequence - b.sequence);
|
|
6052
|
+
const byIteration = /* @__PURE__ */ new Map();
|
|
6053
|
+
for (const step of list) {
|
|
6054
|
+
const group = byIteration.get(step.iteration);
|
|
6055
|
+
if (group) group.push(step);
|
|
6056
|
+
else byIteration.set(step.iteration, [step]);
|
|
6057
|
+
}
|
|
6058
|
+
const iterations = [...byIteration.entries()].sort(([a], [b]) => a - b).map(([iteration, group]) => buildIteration(iteration, group));
|
|
6059
|
+
const first = list[0];
|
|
6060
|
+
if (!first) continue;
|
|
6061
|
+
nodes.push({
|
|
6062
|
+
nodeId: first.nodeId,
|
|
6063
|
+
nodeStateId: first.nodeStateId,
|
|
6064
|
+
iterations,
|
|
6065
|
+
totals: {
|
|
6066
|
+
iterations: iterations.length,
|
|
6067
|
+
modelCalls: iterations.reduce((sum, it) => sum + it.turns.length, 0),
|
|
6068
|
+
toolCalls: iterations.reduce((sum, it) => sum + it.toolCalls.length, 0),
|
|
6069
|
+
tokensIn: iterations.reduce((sum, it) => sum + it.tokensIn, 0),
|
|
6070
|
+
tokensOut: iterations.reduce((sum, it) => sum + it.tokensOut, 0),
|
|
6071
|
+
costMicroUsd: sumCost(iterations.map((it) => it.costMicroUsd))
|
|
6072
|
+
},
|
|
6073
|
+
startedAt: list.reduce((earliest, step) => step.createdAt < earliest ? step.createdAt : earliest, first.createdAt)
|
|
6074
|
+
});
|
|
6075
|
+
}
|
|
6076
|
+
return nodes.sort((a, b) => a.startedAt.localeCompare(b.startedAt)).map(({ startedAt: _startedAt, ...node }) => node);
|
|
6077
|
+
}
|
|
6078
|
+
/** The step trace of one node execution, when the run recorded one. */
|
|
6079
|
+
function stepTraceFor(nodes, nodeStateId, nodeId) {
|
|
6080
|
+
return nodes.find((node) => node.nodeStateId === nodeStateId) ?? nodes.find((node) => node.nodeStateId === null && node.nodeId === nodeId) ?? null;
|
|
6081
|
+
}
|
|
6082
|
+
|
|
5906
6083
|
// src/modules/executions/components/AgentTracePanel.tsx
|
|
5907
6084
|
/**
|
|
5908
6085
|
* The run page's Agent tab (BOFF-9937): the run's AI usage roll-up and, per
|
|
5909
6086
|
* AI Agent node, what the agent did — its tool calls in order, the final
|
|
5910
6087
|
* response, and the calls waiting for a person's approval.
|
|
5911
6088
|
*
|
|
5912
|
-
* Read-only. The roll-up comes from `runAiUsage
|
|
5913
|
-
*
|
|
5914
|
-
*
|
|
5915
|
-
*
|
|
6089
|
+
* Read-only. The roll-up comes from `runAiUsage`. The per-node trace comes
|
|
6090
|
+
* from the step trace (`agentTrace`, BOFF-9936; see utils/agent-steps.ts):
|
|
6091
|
+
* each iteration's model calls with their tokens, timing and cost, what was
|
|
6092
|
+
* sent to the model and its reply, the tool calls and the final answer. A run
|
|
6093
|
+
* without a step trace (recorded before it existed) falls back to the node
|
|
6094
|
+
* states the run page already polls (see utils/agent-trace.ts).
|
|
5916
6095
|
*/
|
|
5917
|
-
function AgentTracePanel({ traces, nodeDisplay, usage, usageLoading, usageError, onRefreshUsage, focusNodeId }) {
|
|
6096
|
+
function AgentTracePanel({ traces, nodeDisplay, usage, usageLoading, usageError, onRefreshUsage, focusNodeId, stepTraces = [], stepTraceDataPruned = false, stepTraceError = null }) {
|
|
5918
6097
|
const tr = useTr();
|
|
6098
|
+
const anyStepTrace = traces.some((trace) => !!stepTraceFor(stepTraces, trace.nodeStateId, trace.nodeId));
|
|
5919
6099
|
return /* @__PURE__ */ jsxs("div", {
|
|
5920
6100
|
className: "space-y-6",
|
|
5921
6101
|
"data-testid": "agent-trace-panel",
|
|
@@ -5928,15 +6108,25 @@ function AgentTracePanel({ traces, nodeDisplay, usage, usageLoading, usageError,
|
|
|
5928
6108
|
nodeDisplay,
|
|
5929
6109
|
tr
|
|
5930
6110
|
}),
|
|
6111
|
+
stepTraceError && /* @__PURE__ */ jsx("div", {
|
|
6112
|
+
role: "alert",
|
|
6113
|
+
className: "rounded-lg border border-status-error-border bg-status-error-bg-subtle p-3 text-sm text-status-error-text",
|
|
6114
|
+
children: tr("fluidgrids.executions.executionDetail.agent.stepTraceError", "Could not load the agent's steps: {{message}}", { message: stepTraceError })
|
|
6115
|
+
}),
|
|
6116
|
+
anyStepTrace && stepTraceDataPruned && /* @__PURE__ */ jsx("p", {
|
|
6117
|
+
className: "text-sm text-text-secondary",
|
|
6118
|
+
children: tr("fluidgrids.executions.executionDetail.agent.stepDataPruned", "This run's data settings removed what each step sent and received. Models, tokens, timing and tools are still shown.")
|
|
6119
|
+
}),
|
|
5931
6120
|
traces.map((trace) => /* @__PURE__ */ jsx(AgentNodeCard, {
|
|
5932
6121
|
trace,
|
|
6122
|
+
steps: stepTraceFor(stepTraces, trace.nodeStateId, trace.nodeId),
|
|
5933
6123
|
title: nodeDisplayTitle(nodeDisplay[trace.nodeId], trace.nodeId),
|
|
5934
6124
|
focused: !!focusNodeId && focusNodeId === trace.nodeId,
|
|
5935
6125
|
tr
|
|
5936
6126
|
}, trace.nodeStateId)),
|
|
5937
|
-
/* @__PURE__ */ jsx("p", {
|
|
6127
|
+
!anyStepTrace && /* @__PURE__ */ jsx("p", {
|
|
5938
6128
|
className: "text-xs text-text-secondary",
|
|
5939
|
-
children: tr("fluidgrids.executions.executionDetail.agent.
|
|
6129
|
+
children: tr("fluidgrids.executions.executionDetail.agent.noStepTrace", "This run has no step trace, so each tool call is shown as the node recorded it, without the model calls.")
|
|
5940
6130
|
})
|
|
5941
6131
|
]
|
|
5942
6132
|
});
|
|
@@ -6109,7 +6299,10 @@ function UsageLines({ lines, nodeDisplay, tr }) {
|
|
|
6109
6299
|
})
|
|
6110
6300
|
});
|
|
6111
6301
|
}
|
|
6112
|
-
function AgentNodeCard({ trace, title, focused, tr }) {
|
|
6302
|
+
function AgentNodeCard({ trace, steps, title, focused, tr }) {
|
|
6303
|
+
const iterationCount = steps?.totals.iterations ?? trace.iterationCount;
|
|
6304
|
+
const tokensUsed = steps ? steps.totals.tokensIn + steps.totals.tokensOut : trace.tokensUsed;
|
|
6305
|
+
const toolCallCount = steps?.totals.toolCalls ?? trace.steps.length;
|
|
6113
6306
|
const ref = useRef(null);
|
|
6114
6307
|
useEffect(() => {
|
|
6115
6308
|
if (focused) ref.current?.scrollIntoView({ block: "start" });
|
|
@@ -6153,15 +6346,15 @@ function AgentNodeCard({ trace, title, focused, tr }) {
|
|
|
6153
6346
|
children: [
|
|
6154
6347
|
/* @__PURE__ */ jsx(Fact, {
|
|
6155
6348
|
label: tr("fluidgrids.executions.executionDetail.agent.iterations", "Iterations"),
|
|
6156
|
-
value:
|
|
6349
|
+
value: iterationCount?.toLocaleString("en-US") ?? "—"
|
|
6157
6350
|
}),
|
|
6158
6351
|
/* @__PURE__ */ jsx(Fact, {
|
|
6159
6352
|
label: tr("fluidgrids.executions.executionDetail.agent.tokensUsed", "Tokens used"),
|
|
6160
|
-
value:
|
|
6353
|
+
value: tokensUsed === null ? "—" : formatTokens(tokensUsed)
|
|
6161
6354
|
}),
|
|
6162
6355
|
/* @__PURE__ */ jsx(Fact, {
|
|
6163
6356
|
label: tr("fluidgrids.executions.executionDetail.agent.toolCalls", "Tool calls"),
|
|
6164
|
-
value:
|
|
6357
|
+
value: toolCallCount.toLocaleString("en-US")
|
|
6165
6358
|
}),
|
|
6166
6359
|
/* @__PURE__ */ jsx(Fact, {
|
|
6167
6360
|
label: tr("fluidgrids.executions.executionDetail.agent.duration", "Duration"),
|
|
@@ -6187,7 +6380,10 @@ function AgentNodeCard({ trace, title, focused, tr }) {
|
|
|
6187
6380
|
trace,
|
|
6188
6381
|
tr
|
|
6189
6382
|
}),
|
|
6190
|
-
/* @__PURE__ */
|
|
6383
|
+
steps ? /* @__PURE__ */ jsx(IterationList, {
|
|
6384
|
+
node: steps,
|
|
6385
|
+
tr
|
|
6386
|
+
}) : /* @__PURE__ */ jsxs("div", {
|
|
6191
6387
|
className: "mt-4",
|
|
6192
6388
|
children: [/* @__PURE__ */ jsx("h5", {
|
|
6193
6389
|
className: "mb-2 text-sm font-medium text-text-primary",
|
|
@@ -6318,6 +6514,233 @@ function StepBlock({ label, value, empty }) {
|
|
|
6318
6514
|
children: empty
|
|
6319
6515
|
})] });
|
|
6320
6516
|
}
|
|
6517
|
+
function StepCost({ value, tr }) {
|
|
6518
|
+
if (value === null) return /* @__PURE__ */ jsx(Fragment, { children: tr("fluidgrids.executions.executionDetail.agent.notPricedYet", "Not priced yet") });
|
|
6519
|
+
return /* @__PURE__ */ jsx(Fragment, { children: formatMicroUsd(value) });
|
|
6520
|
+
}
|
|
6521
|
+
function TokensInOut({ tokensIn, tokensOut, tr }) {
|
|
6522
|
+
return /* @__PURE__ */ jsx(Fragment, { children: tr("fluidgrids.executions.executionDetail.agent.tokensInOut", "{{input}} in / {{output}} out tokens", {
|
|
6523
|
+
input: formatTokens(tokensIn),
|
|
6524
|
+
output: formatTokens(tokensOut)
|
|
6525
|
+
}) });
|
|
6526
|
+
}
|
|
6527
|
+
function IterationList({ node, tr }) {
|
|
6528
|
+
const last = node.iterations.at(-1)?.iteration;
|
|
6529
|
+
return /* @__PURE__ */ jsxs("div", {
|
|
6530
|
+
className: "mt-4",
|
|
6531
|
+
children: [/* @__PURE__ */ jsx("h5", {
|
|
6532
|
+
className: "mb-2 text-sm font-medium text-text-primary",
|
|
6533
|
+
children: tr("fluidgrids.executions.executionDetail.agent.iterations", "Iterations")
|
|
6534
|
+
}), /* @__PURE__ */ jsx("ol", {
|
|
6535
|
+
className: "space-y-2",
|
|
6536
|
+
"data-testid": "agent-iterations",
|
|
6537
|
+
children: node.iterations.map((iteration) => /* @__PURE__ */ jsx(IterationRow, {
|
|
6538
|
+
iteration,
|
|
6539
|
+
open: iteration.iteration === last,
|
|
6540
|
+
tr
|
|
6541
|
+
}, iteration.iteration))
|
|
6542
|
+
})]
|
|
6543
|
+
});
|
|
6544
|
+
}
|
|
6545
|
+
function IterationRow({ iteration, open, tr }) {
|
|
6546
|
+
return /* @__PURE__ */ jsx("li", {
|
|
6547
|
+
className: `rounded border ${iteration.error ? "border-status-error-border" : "border-border-secondary"}`,
|
|
6548
|
+
"data-agent-iteration": iteration.iteration,
|
|
6549
|
+
children: /* @__PURE__ */ jsxs("details", {
|
|
6550
|
+
open,
|
|
6551
|
+
children: [/* @__PURE__ */ jsxs("summary", {
|
|
6552
|
+
className: "flex cursor-pointer flex-wrap items-center gap-x-3 gap-y-1 px-3 py-2 text-sm",
|
|
6553
|
+
children: [
|
|
6554
|
+
/* @__PURE__ */ jsx("span", {
|
|
6555
|
+
className: "font-medium text-text-primary",
|
|
6556
|
+
children: tr("fluidgrids.executions.executionDetail.agent.iterationNumber", "Iteration {{number}}", { number: iteration.iteration + 1 })
|
|
6557
|
+
}),
|
|
6558
|
+
/* @__PURE__ */ jsx("span", {
|
|
6559
|
+
className: "text-xs text-text-secondary",
|
|
6560
|
+
children: /* @__PURE__ */ jsx(TokensInOut, {
|
|
6561
|
+
tokensIn: iteration.tokensIn,
|
|
6562
|
+
tokensOut: iteration.tokensOut,
|
|
6563
|
+
tr
|
|
6564
|
+
})
|
|
6565
|
+
}),
|
|
6566
|
+
/* @__PURE__ */ jsx("span", {
|
|
6567
|
+
className: "text-xs text-text-secondary",
|
|
6568
|
+
children: formatElapsedMs(iteration.latencyMs, "—")
|
|
6569
|
+
}),
|
|
6570
|
+
iteration.turns.length > 0 && /* @__PURE__ */ jsx("span", {
|
|
6571
|
+
className: "ml-auto text-xs text-text-secondary",
|
|
6572
|
+
children: /* @__PURE__ */ jsx(StepCost, {
|
|
6573
|
+
value: iteration.costMicroUsd,
|
|
6574
|
+
tr
|
|
6575
|
+
})
|
|
6576
|
+
})
|
|
6577
|
+
]
|
|
6578
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
6579
|
+
className: "space-y-2 border-t border-border-secondary px-3 py-2",
|
|
6580
|
+
children: [
|
|
6581
|
+
iteration.turns.map((turn) => /* @__PURE__ */ jsx(ModelTurnRow, {
|
|
6582
|
+
turn,
|
|
6583
|
+
tr
|
|
6584
|
+
}, turn.key)),
|
|
6585
|
+
iteration.toolCalls.map((call) => /* @__PURE__ */ jsx(ToolCallRow, {
|
|
6586
|
+
call,
|
|
6587
|
+
tr
|
|
6588
|
+
}, call.key)),
|
|
6589
|
+
iteration.final && /* @__PURE__ */ jsxs("div", {
|
|
6590
|
+
className: "rounded bg-background-tertiary p-2",
|
|
6591
|
+
children: [
|
|
6592
|
+
/* @__PURE__ */ jsx("p", {
|
|
6593
|
+
className: "text-xs font-medium text-text-secondary",
|
|
6594
|
+
children: tr("fluidgrids.executions.executionDetail.agent.finalResponse", "Final response")
|
|
6595
|
+
}),
|
|
6596
|
+
iteration.final.answer && /* @__PURE__ */ jsx("pre", {
|
|
6597
|
+
className: "mt-1 max-h-64 overflow-auto font-mono text-xs whitespace-pre-wrap break-words text-text-primary",
|
|
6598
|
+
children: iteration.final.answer
|
|
6599
|
+
}),
|
|
6600
|
+
iteration.final.outputErrors.length > 0 && /* @__PURE__ */ jsxs("div", {
|
|
6601
|
+
className: "mt-2 text-sm text-status-error-text",
|
|
6602
|
+
children: [/* @__PURE__ */ jsx("p", {
|
|
6603
|
+
className: "font-medium",
|
|
6604
|
+
children: tr("fluidgrids.executions.executionDetail.agent.outputSchemaMissed", "The answer missed the output schema:")
|
|
6605
|
+
}), /* @__PURE__ */ jsx("ul", {
|
|
6606
|
+
className: "mt-1 list-disc pl-5",
|
|
6607
|
+
children: iteration.final.outputErrors.map((error) => /* @__PURE__ */ jsx("li", {
|
|
6608
|
+
className: "break-words",
|
|
6609
|
+
children: error
|
|
6610
|
+
}, error))
|
|
6611
|
+
})]
|
|
6612
|
+
})
|
|
6613
|
+
]
|
|
6614
|
+
}),
|
|
6615
|
+
iteration.error && /* @__PURE__ */ jsxs("div", {
|
|
6616
|
+
className: "rounded border border-status-error-border bg-status-error-bg-subtle p-2 text-sm text-status-error-text",
|
|
6617
|
+
children: [/* @__PURE__ */ jsxs("span", {
|
|
6618
|
+
className: "font-medium",
|
|
6619
|
+
children: [
|
|
6620
|
+
tr("fluidgrids.executions.executionDetail.agent.error", "Error"),
|
|
6621
|
+
":",
|
|
6622
|
+
" "
|
|
6623
|
+
]
|
|
6624
|
+
}), /* @__PURE__ */ jsx("span", {
|
|
6625
|
+
className: "break-words",
|
|
6626
|
+
children: iteration.error
|
|
6627
|
+
})]
|
|
6628
|
+
})
|
|
6629
|
+
]
|
|
6630
|
+
})]
|
|
6631
|
+
})
|
|
6632
|
+
});
|
|
6633
|
+
}
|
|
6634
|
+
function ModelTurnRow({ turn, tr }) {
|
|
6635
|
+
return /* @__PURE__ */ jsxs("details", {
|
|
6636
|
+
className: "rounded border border-border-secondary",
|
|
6637
|
+
children: [/* @__PURE__ */ jsxs("summary", {
|
|
6638
|
+
className: "flex cursor-pointer flex-wrap items-center gap-x-3 gap-y-1 px-3 py-2 text-sm",
|
|
6639
|
+
children: [
|
|
6640
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
6641
|
+
icon: "mdi:brain",
|
|
6642
|
+
width: 14,
|
|
6643
|
+
className: "shrink-0 text-text-secondary"
|
|
6644
|
+
}),
|
|
6645
|
+
/* @__PURE__ */ jsx("span", {
|
|
6646
|
+
className: "font-medium text-text-primary",
|
|
6647
|
+
children: tr("fluidgrids.executions.executionDetail.agent.modelCall", "Model call")
|
|
6648
|
+
}),
|
|
6649
|
+
turn.model && /* @__PURE__ */ jsx("span", {
|
|
6650
|
+
className: "min-w-0 break-all font-mono text-xs text-text-secondary",
|
|
6651
|
+
children: turn.model
|
|
6652
|
+
}),
|
|
6653
|
+
/* @__PURE__ */ jsx("span", {
|
|
6654
|
+
className: "text-xs text-text-secondary",
|
|
6655
|
+
children: /* @__PURE__ */ jsx(TokensInOut, {
|
|
6656
|
+
tokensIn: turn.tokensIn,
|
|
6657
|
+
tokensOut: turn.tokensOut,
|
|
6658
|
+
tr
|
|
6659
|
+
})
|
|
6660
|
+
}),
|
|
6661
|
+
/* @__PURE__ */ jsx("span", {
|
|
6662
|
+
className: "text-xs text-text-secondary",
|
|
6663
|
+
children: formatElapsedMs(turn.latencyMs, "—")
|
|
6664
|
+
}),
|
|
6665
|
+
/* @__PURE__ */ jsx("span", {
|
|
6666
|
+
className: "ml-auto text-xs text-text-secondary",
|
|
6667
|
+
children: /* @__PURE__ */ jsx(StepCost, {
|
|
6668
|
+
value: turn.costMicroUsd,
|
|
6669
|
+
tr
|
|
6670
|
+
})
|
|
6671
|
+
})
|
|
6672
|
+
]
|
|
6673
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
6674
|
+
className: "space-y-2 border-t border-border-secondary px-3 py-2",
|
|
6675
|
+
children: [/* @__PURE__ */ jsx(StepBlock, {
|
|
6676
|
+
label: tr("fluidgrids.executions.executionDetail.agent.sentToModel", "Sent to the model"),
|
|
6677
|
+
value: turn.input,
|
|
6678
|
+
empty: tr("fluidgrids.executions.executionDetail.agent.stepNotRecorded", "Not recorded")
|
|
6679
|
+
}), /* @__PURE__ */ jsx(StepBlock, {
|
|
6680
|
+
label: tr("fluidgrids.executions.executionDetail.agent.modelReply", "Reply"),
|
|
6681
|
+
value: turn.reply,
|
|
6682
|
+
empty: tr("fluidgrids.executions.executionDetail.agent.stepNotRecorded", "Not recorded")
|
|
6683
|
+
})]
|
|
6684
|
+
})]
|
|
6685
|
+
});
|
|
6686
|
+
}
|
|
6687
|
+
function ToolCallRow({ call, tr }) {
|
|
6688
|
+
const waiting = !call.hasResult && call.rule === "ask";
|
|
6689
|
+
let border = "border-border-secondary";
|
|
6690
|
+
if (call.outcome === "rejected" || waiting) border = "border-status-warning-border";
|
|
6691
|
+
else if (call.outcome === "failed") border = "border-status-error-border";
|
|
6692
|
+
return /* @__PURE__ */ jsxs("details", {
|
|
6693
|
+
className: `rounded border ${border}`,
|
|
6694
|
+
children: [/* @__PURE__ */ jsxs("summary", {
|
|
6695
|
+
className: "flex cursor-pointer flex-wrap items-center gap-2 px-3 py-2 text-sm",
|
|
6696
|
+
children: [
|
|
6697
|
+
/* @__PURE__ */ jsx(Icon, {
|
|
6698
|
+
icon: "mdi:wrench-outline",
|
|
6699
|
+
width: 14,
|
|
6700
|
+
className: "shrink-0 text-text-secondary"
|
|
6701
|
+
}),
|
|
6702
|
+
/* @__PURE__ */ jsx("span", {
|
|
6703
|
+
className: "min-w-0 break-all font-mono text-text-primary",
|
|
6704
|
+
children: call.tool
|
|
6705
|
+
}),
|
|
6706
|
+
waiting && /* @__PURE__ */ jsx("span", {
|
|
6707
|
+
className: "rounded bg-status-warning-bg-subtle px-1.5 py-0.5 text-xs text-status-warning-text",
|
|
6708
|
+
children: tr("fluidgrids.executions.executionDetail.agent.stepAwaitingApproval", "Waiting for approval")
|
|
6709
|
+
}),
|
|
6710
|
+
call.outcome === "rejected" && /* @__PURE__ */ jsx("span", {
|
|
6711
|
+
className: "rounded bg-status-warning-bg-subtle px-1.5 py-0.5 text-xs text-status-warning-text",
|
|
6712
|
+
children: tr("fluidgrids.executions.executionDetail.agent.stepRejected", "Rejected")
|
|
6713
|
+
}),
|
|
6714
|
+
call.outcome === "failed" && /* @__PURE__ */ jsx("span", {
|
|
6715
|
+
className: "rounded bg-status-error-bg-subtle px-1.5 py-0.5 text-xs text-status-error-text",
|
|
6716
|
+
children: tr("fluidgrids.executions.executionDetail.agent.stepFailed", "Failed")
|
|
6717
|
+
}),
|
|
6718
|
+
call.latencyMs !== null && /* @__PURE__ */ jsx("span", {
|
|
6719
|
+
className: "ml-auto text-xs text-text-secondary",
|
|
6720
|
+
children: formatElapsedMs(call.latencyMs)
|
|
6721
|
+
})
|
|
6722
|
+
]
|
|
6723
|
+
}), /* @__PURE__ */ jsxs("div", {
|
|
6724
|
+
className: "space-y-2 border-t border-border-secondary px-3 py-2",
|
|
6725
|
+
children: [
|
|
6726
|
+
call.outcome !== "ok" && call.reason && /* @__PURE__ */ jsx("p", {
|
|
6727
|
+
className: `text-sm ${call.outcome === "rejected" ? "text-status-warning-text" : "text-status-error-text"}`,
|
|
6728
|
+
children: call.reason
|
|
6729
|
+
}),
|
|
6730
|
+
/* @__PURE__ */ jsx(StepBlock, {
|
|
6731
|
+
label: tr("fluidgrids.executions.executionDetail.agent.stepArguments", "Arguments"),
|
|
6732
|
+
value: call.args,
|
|
6733
|
+
empty: tr("fluidgrids.executions.executionDetail.agent.stepNoArguments", "No arguments")
|
|
6734
|
+
}),
|
|
6735
|
+
/* @__PURE__ */ jsx(StepBlock, {
|
|
6736
|
+
label: tr("fluidgrids.executions.executionDetail.agent.stepResult", "Result"),
|
|
6737
|
+
value: call.result,
|
|
6738
|
+
empty: tr("fluidgrids.executions.executionDetail.agent.stepNoResult", "No result recorded")
|
|
6739
|
+
})
|
|
6740
|
+
]
|
|
6741
|
+
})]
|
|
6742
|
+
});
|
|
6743
|
+
}
|
|
6321
6744
|
|
|
6322
6745
|
// src/modules/executions/hooks/useRunAiUsage.ts
|
|
6323
6746
|
/**
|
|
@@ -6389,6 +6812,145 @@ function useRunAiUsage(runId, { enabled, live }) {
|
|
|
6389
6812
|
};
|
|
6390
6813
|
}
|
|
6391
6814
|
|
|
6815
|
+
// src/modules/executions/hooks/useAgentTrace.ts
|
|
6816
|
+
/**
|
|
6817
|
+
* useAgentTrace — the AI Agent step trace of a run (BOFF-9936) for the run
|
|
6818
|
+
* page's Agent tab.
|
|
6819
|
+
*
|
|
6820
|
+
* Two sources feed one list of steps, merged by step `id`:
|
|
6821
|
+
*
|
|
6822
|
+
* read `agentTrace`, the steps stored so far, with each model call's
|
|
6823
|
+
* priced cost.
|
|
6824
|
+
* live `agentStepUpdated`, the steps the worker records after the
|
|
6825
|
+
* subscription opens. It has no history, so the read comes first.
|
|
6826
|
+
*
|
|
6827
|
+
* While `live`, the read is repeated every {@link AGENT_TRACE_POLL_INTERVAL_MS}
|
|
6828
|
+
* until the stream proves it delivers, and once more when the run stops
|
|
6829
|
+
* being live, so the last steps and the costs the ledger priced meanwhile
|
|
6830
|
+
* always arrive. Nothing is read while `enabled` is false (the run has no AI
|
|
6831
|
+
* Agent node, or the tab is not shown).
|
|
6832
|
+
*/
|
|
6833
|
+
/** Re-read cadence while the live stream has not delivered yet. */
|
|
6834
|
+
const AGENT_TRACE_POLL_INTERVAL_MS = 5e3;
|
|
6835
|
+
/**
|
|
6836
|
+
* Follow a run's live steps: subscribe to `agentStepUpdated`, and re-read the
|
|
6837
|
+
* stored trace every {@link AGENT_TRACE_POLL_INTERVAL_MS} until the stream
|
|
6838
|
+
* delivers (again after it errors or ends). Returns the function that stops
|
|
6839
|
+
* both; nothing is called back after it ran.
|
|
6840
|
+
*/
|
|
6841
|
+
function followAgentSteps(client, runId, { reread, onSteps, onStreaming }) {
|
|
6842
|
+
let stopped = false;
|
|
6843
|
+
let delivered = false;
|
|
6844
|
+
const poll = setInterval(() => {
|
|
6845
|
+
if (!delivered) reread();
|
|
6846
|
+
}, AGENT_TRACE_POLL_INTERVAL_MS);
|
|
6847
|
+
const subscription = client.subscribe({
|
|
6848
|
+
query: AgentStepUpdatedDocument,
|
|
6849
|
+
variables: { runId }
|
|
6850
|
+
}).subscribe({
|
|
6851
|
+
next: ({ data }) => {
|
|
6852
|
+
if (stopped) return;
|
|
6853
|
+
delivered = true;
|
|
6854
|
+
onStreaming(true);
|
|
6855
|
+
const steps = data?.agentStepUpdated ?? [];
|
|
6856
|
+
if (steps.length > 0) onSteps(steps);
|
|
6857
|
+
},
|
|
6858
|
+
error: () => {
|
|
6859
|
+
delivered = false;
|
|
6860
|
+
if (!stopped) onStreaming(false);
|
|
6861
|
+
},
|
|
6862
|
+
complete: () => {
|
|
6863
|
+
delivered = false;
|
|
6864
|
+
if (!stopped) onStreaming(false);
|
|
6865
|
+
}
|
|
6866
|
+
});
|
|
6867
|
+
return () => {
|
|
6868
|
+
stopped = true;
|
|
6869
|
+
clearInterval(poll);
|
|
6870
|
+
subscription.unsubscribe();
|
|
6871
|
+
onStreaming(false);
|
|
6872
|
+
};
|
|
6873
|
+
}
|
|
6874
|
+
function useAgentTrace(runId, { enabled, live }) {
|
|
6875
|
+
const [state, setState] = useState(null);
|
|
6876
|
+
const [streaming, setStreaming] = useState(false);
|
|
6877
|
+
const request = useRef(0);
|
|
6878
|
+
const read = useCallback(async () => {
|
|
6879
|
+
const client = getFluidGridsClientSafe();
|
|
6880
|
+
if (!runId || !enabled || !client) return;
|
|
6881
|
+
const id = ++request.current;
|
|
6882
|
+
try {
|
|
6883
|
+
const result = await client.query({
|
|
6884
|
+
query: AgentTraceDocument,
|
|
6885
|
+
variables: { runId },
|
|
6886
|
+
fetchPolicy: "network-only"
|
|
6887
|
+
});
|
|
6888
|
+
throwIfResultError(result);
|
|
6889
|
+
const trace = result.data?.agentTrace ?? null;
|
|
6890
|
+
if (id !== request.current) return;
|
|
6891
|
+
setState((previous) => ({
|
|
6892
|
+
runId,
|
|
6893
|
+
steps: mergeAgentSteps(previous?.runId === runId ? previous.steps : /* @__PURE__ */ new Map(), flattenAgentTrace(trace)),
|
|
6894
|
+
dataPruned: trace?.dataPruned ?? false,
|
|
6895
|
+
read: true,
|
|
6896
|
+
error: null
|
|
6897
|
+
}));
|
|
6898
|
+
} catch (err) {
|
|
6899
|
+
if (id !== request.current) return;
|
|
6900
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
6901
|
+
setState((previous) => ({
|
|
6902
|
+
runId,
|
|
6903
|
+
steps: previous?.runId === runId ? previous.steps : /* @__PURE__ */ new Map(),
|
|
6904
|
+
dataPruned: previous?.runId === runId ? previous.dataPruned : false,
|
|
6905
|
+
read: true,
|
|
6906
|
+
error: message
|
|
6907
|
+
}));
|
|
6908
|
+
}
|
|
6909
|
+
}, [runId, enabled]);
|
|
6910
|
+
useEffect(() => {
|
|
6911
|
+
read();
|
|
6912
|
+
}, [read]);
|
|
6913
|
+
useEffect(() => {
|
|
6914
|
+
const client = getFluidGridsClientSafe();
|
|
6915
|
+
if (!runId || !enabled || !live || !client) return void 0;
|
|
6916
|
+
return followAgentSteps(client, runId, {
|
|
6917
|
+
reread: () => void read(),
|
|
6918
|
+
onStreaming: setStreaming,
|
|
6919
|
+
onSteps: (steps) => setState((previous) => ({
|
|
6920
|
+
runId,
|
|
6921
|
+
steps: mergeAgentSteps(previous?.runId === runId ? previous.steps : /* @__PURE__ */ new Map(), steps),
|
|
6922
|
+
dataPruned: previous?.runId === runId ? previous.dataPruned : false,
|
|
6923
|
+
read: previous?.runId === runId ? previous.read : false,
|
|
6924
|
+
error: previous?.runId === runId ? previous.error : null
|
|
6925
|
+
}))
|
|
6926
|
+
});
|
|
6927
|
+
}, [
|
|
6928
|
+
runId,
|
|
6929
|
+
enabled,
|
|
6930
|
+
live,
|
|
6931
|
+
read
|
|
6932
|
+
]);
|
|
6933
|
+
const wasLive = useRef(false);
|
|
6934
|
+
useEffect(() => {
|
|
6935
|
+
if (live) {
|
|
6936
|
+
wasLive.current = true;
|
|
6937
|
+
return;
|
|
6938
|
+
}
|
|
6939
|
+
if (!wasLive.current) return;
|
|
6940
|
+
wasLive.current = false;
|
|
6941
|
+
read();
|
|
6942
|
+
}, [live, read]);
|
|
6943
|
+
const current = enabled && state?.runId === runId ? state : null;
|
|
6944
|
+
return {
|
|
6945
|
+
nodes: useMemo(() => current ? groupAgentSteps(current.steps.values()) : [], [current]),
|
|
6946
|
+
dataPruned: current?.dataPruned ?? false,
|
|
6947
|
+
loading: enabled && !!runId && !current?.read,
|
|
6948
|
+
error: current?.error ?? null,
|
|
6949
|
+
streaming: enabled && live && streaming,
|
|
6950
|
+
refetch: read
|
|
6951
|
+
};
|
|
6952
|
+
}
|
|
6953
|
+
|
|
6392
6954
|
// src/modules/task-queues/api.ts
|
|
6393
6955
|
/**
|
|
6394
6956
|
* Task queues and self-hosted workers (BOFF-9906, spec code-first 04 §8 and
|
|
@@ -9096,6 +9658,10 @@ function ExecutionDetailPage() {
|
|
|
9096
9658
|
enabled: hasAgent && activeTab === "agent",
|
|
9097
9659
|
live: autoRefreshEnabled && isActive
|
|
9098
9660
|
});
|
|
9661
|
+
const agentStepTrace = useAgentTrace(runId, {
|
|
9662
|
+
enabled: hasAgent && activeTab === "agent",
|
|
9663
|
+
live: isActive
|
|
9664
|
+
});
|
|
9099
9665
|
const agentTraces = useMemo(() => agentNodeTraces(orderNodesByExecution(execution?.nodeStates ?? [], execution?.triggerNodeId ?? void 0)), [execution?.nodeStates, execution?.triggerNodeId]);
|
|
9100
9666
|
const activityControls = isDurableRun && phaseC.runControlDurable;
|
|
9101
9667
|
const runPending = useRunPending(runId, {
|
|
@@ -9776,7 +10342,10 @@ function ExecutionDetailPage() {
|
|
|
9776
10342
|
usageLoading: runAiUsage.loading,
|
|
9777
10343
|
usageError: runAiUsage.error,
|
|
9778
10344
|
onRefreshUsage: () => void runAiUsage.refetch(),
|
|
9779
|
-
focusNodeId: agentFocusNodeId
|
|
10345
|
+
focusNodeId: agentFocusNodeId,
|
|
10346
|
+
stepTraces: agentStepTrace.nodes,
|
|
10347
|
+
stepTraceDataPruned: agentStepTrace.dataPruned,
|
|
10348
|
+
stepTraceError: agentStepTrace.error
|
|
9780
10349
|
})]
|
|
9781
10350
|
}),
|
|
9782
10351
|
activeTab === "history" && isDurableRun && /* @__PURE__ */ jsxs("div", {
|