langchain_agentx_stream_ui 0.2.7 → 0.3.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.
- package/dist/{AskUserQuestionToolBody-BG1StdvE.d.ts → AskUserQuestionToolBody-CUXqUkar.d.ts} +1 -1
- package/dist/{chunk-SUEMZC4U.js → chunk-6ORA5RMV.js} +49 -194
- package/dist/chunk-6ORA5RMV.js.map +1 -0
- package/dist/{chunk-DP7V33X7.js → chunk-6Z4ZF36Z.js} +1 -1
- package/dist/chunk-6Z4ZF36Z.js.map +1 -0
- package/dist/{chunk-7CLAU74Y.js → chunk-FL2G7SV3.js} +378 -98
- package/dist/chunk-FL2G7SV3.js.map +1 -0
- package/dist/{chunk-4RIOBLGB.js → chunk-GBY5DJ7L.js} +1 -1
- package/dist/chunk-GBY5DJ7L.js.map +1 -0
- package/dist/{chunk-CUKNUCGU.js → chunk-ISQ7JWGD.js} +5 -5
- package/dist/chunk-ISQ7JWGD.js.map +1 -0
- package/dist/{chunk-6DYISADG.js → chunk-TCKOXX7O.js} +6 -33
- package/dist/chunk-TCKOXX7O.js.map +1 -0
- package/dist/index.d.ts +284 -63
- package/dist/index.js +704 -179
- package/dist/index.js.map +1 -1
- package/dist/{multi-session-xvSZstSN.d.ts → multi-session-CerO558Y.d.ts} +3 -1
- package/dist/multi-session.d.ts +2 -2
- package/dist/multi-session.js +6 -6
- package/dist/{sessionViewOptions-WM00Fpcn.d.ts → sessionViewOptions-DQRzPuN_.d.ts} +2 -0
- package/dist/tools-presentation.js +2 -2
- package/dist/tools.d.ts +3 -3
- package/dist/tools.js +4 -4
- package/dist/virtual.js +3 -3
- package/package.json +1 -1
- package/dist/chunk-4RIOBLGB.js.map +0 -1
- package/dist/chunk-6DYISADG.js.map +0 -1
- package/dist/chunk-7CLAU74Y.js.map +0 -1
- package/dist/chunk-CUKNUCGU.js.map +0 -1
- package/dist/chunk-DP7V33X7.js.map +0 -1
- package/dist/chunk-SUEMZC4U.js.map +0 -1
package/dist/index.js
CHANGED
|
@@ -23,7 +23,7 @@ import {
|
|
|
23
23
|
fixDiagramSvg,
|
|
24
24
|
markEventIdSeen,
|
|
25
25
|
shouldSkipDuplicateEvent
|
|
26
|
-
} from "./chunk-
|
|
26
|
+
} from "./chunk-ISQ7JWGD.js";
|
|
27
27
|
import {
|
|
28
28
|
DefaultToolBody,
|
|
29
29
|
InteractionBusContext,
|
|
@@ -32,8 +32,8 @@ import {
|
|
|
32
32
|
getNoopInteractionBus,
|
|
33
33
|
resolveToolBody,
|
|
34
34
|
useInteractionBus
|
|
35
|
-
} from "./chunk-
|
|
36
|
-
import "./chunk-
|
|
35
|
+
} from "./chunk-TCKOXX7O.js";
|
|
36
|
+
import "./chunk-6Z4ZF36Z.js";
|
|
37
37
|
import {
|
|
38
38
|
CollapseKind,
|
|
39
39
|
CollapsedExploreNode,
|
|
@@ -72,7 +72,6 @@ import {
|
|
|
72
72
|
createEmptyTree,
|
|
73
73
|
createProjectionContext,
|
|
74
74
|
entryKey,
|
|
75
|
-
formatExploreSummaryText,
|
|
76
75
|
formatHookFinishedSummary,
|
|
77
76
|
formatShellProgressSuffix,
|
|
78
77
|
formatTaskFooterLabel,
|
|
@@ -111,7 +110,7 @@ import {
|
|
|
111
110
|
useSessionStatus,
|
|
112
111
|
useSessionViewOptions,
|
|
113
112
|
useTimeline
|
|
114
|
-
} from "./chunk-
|
|
113
|
+
} from "./chunk-6ORA5RMV.js";
|
|
115
114
|
import {
|
|
116
115
|
Agent,
|
|
117
116
|
AgentToolBody,
|
|
@@ -137,8 +136,9 @@ import {
|
|
|
137
136
|
Write,
|
|
138
137
|
WriteToolBody,
|
|
139
138
|
createDefaultToolRegistry,
|
|
140
|
-
formatAgentTitle
|
|
141
|
-
|
|
139
|
+
formatAgentTitle,
|
|
140
|
+
formatExploreSummaryText
|
|
141
|
+
} from "./chunk-FL2G7SV3.js";
|
|
142
142
|
import {
|
|
143
143
|
BodyBlockList,
|
|
144
144
|
DiffView,
|
|
@@ -154,7 +154,7 @@ import {
|
|
|
154
154
|
formatTimeoutFooter,
|
|
155
155
|
parseDiffText,
|
|
156
156
|
truncateCommand
|
|
157
|
-
} from "./chunk-
|
|
157
|
+
} from "./chunk-GBY5DJ7L.js";
|
|
158
158
|
|
|
159
159
|
// src/view/AgentSession.tsx
|
|
160
160
|
import { useEffect as useEffect2, useMemo, useRef as useRef2 } from "react";
|
|
@@ -184,7 +184,8 @@ function safeReduce(tree, event, eventIndex, options) {
|
|
|
184
184
|
function createSessionStore(initialTree = createEmptyTree(), storeOptions) {
|
|
185
185
|
const reduceOpts = {
|
|
186
186
|
tierOverrides: storeOptions?.tierOverrides,
|
|
187
|
-
collectDebug: storeOptions?.debug === true
|
|
187
|
+
collectDebug: storeOptions?.debug === true,
|
|
188
|
+
subagentLeakGate: storeOptions?.subagentLeakGate === true
|
|
188
189
|
};
|
|
189
190
|
const initialEventCount = storeOptions?.initialEventCount ?? 0;
|
|
190
191
|
const seenEventIds = new Set(storeOptions?.initialSeenEventIds);
|
|
@@ -317,6 +318,15 @@ var PROFILE_PRESETS = {
|
|
|
317
318
|
...BOUNDED_DEFAULTS
|
|
318
319
|
},
|
|
319
320
|
terminal: WORKFLOW_TERMINAL_WITH_FALLBACK
|
|
321
|
+
},
|
|
322
|
+
"workflow-tail": {
|
|
323
|
+
profile: "workflow-tail",
|
|
324
|
+
replay: "none",
|
|
325
|
+
reconnect: {
|
|
326
|
+
mode: "bounded",
|
|
327
|
+
...BOUNDED_DEFAULTS
|
|
328
|
+
},
|
|
329
|
+
terminal: WORKFLOW_TERMINAL_WITH_FALLBACK
|
|
320
330
|
}
|
|
321
331
|
};
|
|
322
332
|
function legacyTerminal(expectedApplicationKind) {
|
|
@@ -778,19 +788,22 @@ function AgentSession({
|
|
|
778
788
|
exploreFullscreenBash = true,
|
|
779
789
|
memoryDir = null,
|
|
780
790
|
workspaceRoot = null,
|
|
791
|
+
subagentLeakGate = false,
|
|
781
792
|
children
|
|
782
793
|
}) {
|
|
783
794
|
const storeRef = useRef2(null);
|
|
784
795
|
if (storeRef.current === null) {
|
|
785
796
|
const replayOpts = {
|
|
786
797
|
tierOverrides: _tierOverrides,
|
|
787
|
-
collectDebug: debug
|
|
798
|
+
collectDebug: debug,
|
|
799
|
+
subagentLeakGate
|
|
788
800
|
};
|
|
789
801
|
const initialTree = initialEvents && initialEvents.length > 0 ? replayEvents(initialEvents, replayOpts) : void 0;
|
|
790
802
|
storeRef.current = createSessionStore(initialTree, {
|
|
791
803
|
tierOverrides: _tierOverrides,
|
|
792
804
|
debug,
|
|
793
|
-
initialEventCount: initialEvents?.length ?? 0
|
|
805
|
+
initialEventCount: initialEvents?.length ?? 0,
|
|
806
|
+
subagentLeakGate
|
|
794
807
|
});
|
|
795
808
|
}
|
|
796
809
|
const registryRef = useMemo(() => registry ?? createDefaultRegistry(), [registry]);
|
|
@@ -815,7 +828,8 @@ function AgentSession({
|
|
|
815
828
|
verbose,
|
|
816
829
|
exploreFullscreenBash,
|
|
817
830
|
memoryDir,
|
|
818
|
-
workspaceRoot
|
|
831
|
+
workspaceRoot,
|
|
832
|
+
subagentLeakGate
|
|
819
833
|
}),
|
|
820
834
|
[
|
|
821
835
|
groupParallelTools,
|
|
@@ -825,7 +839,8 @@ function AgentSession({
|
|
|
825
839
|
verbose,
|
|
826
840
|
exploreFullscreenBash,
|
|
827
841
|
memoryDir,
|
|
828
|
-
workspaceRoot
|
|
842
|
+
workspaceRoot,
|
|
843
|
+
subagentLeakGate
|
|
829
844
|
]
|
|
830
845
|
);
|
|
831
846
|
const onErrorRef = useRef2(onError);
|
|
@@ -864,11 +879,85 @@ function AgentSession({
|
|
|
864
879
|
}
|
|
865
880
|
|
|
866
881
|
// src/view/workflow/WorkflowSession.tsx
|
|
867
|
-
import { useEffect as
|
|
882
|
+
import { useEffect as useEffect10, useMemo as useMemo9, useRef as useRef4 } from "react";
|
|
868
883
|
|
|
869
884
|
// src/core/context/WorkflowSessionContext.tsx
|
|
870
885
|
import { createContext, useContext } from "react";
|
|
871
886
|
import { useStore } from "zustand";
|
|
887
|
+
|
|
888
|
+
// src/core/workflow/workflowAuthoritySelectors.ts
|
|
889
|
+
var AUTHORITY_TERMINAL = /* @__PURE__ */ new Set([
|
|
890
|
+
"done",
|
|
891
|
+
"error",
|
|
892
|
+
"canceled",
|
|
893
|
+
"partial_success"
|
|
894
|
+
]);
|
|
895
|
+
function isAuthorityTerminalStatus(status) {
|
|
896
|
+
return status != null && AUTHORITY_TERMINAL.has(status);
|
|
897
|
+
}
|
|
898
|
+
function isAuthorityTerminal(state) {
|
|
899
|
+
return isAuthorityTerminalStatus(state.authority?.status);
|
|
900
|
+
}
|
|
901
|
+
function shouldShowGlobalSpinner(state) {
|
|
902
|
+
const auth = state.authority?.status;
|
|
903
|
+
if (auth === "canceled") return false;
|
|
904
|
+
if (isAuthorityTerminalStatus(auth)) return false;
|
|
905
|
+
if (state.display.awaitingAuthority) return false;
|
|
906
|
+
if (auth == null || auth === "pending" || auth === "running") {
|
|
907
|
+
return true;
|
|
908
|
+
}
|
|
909
|
+
const proj = state.display.projectionStatus;
|
|
910
|
+
return proj === "running" || proj === "connecting";
|
|
911
|
+
}
|
|
912
|
+
function resolveWorkflowBanner(state) {
|
|
913
|
+
if (state.display.authoritySubscribeFailed) {
|
|
914
|
+
return { kind: "sync_failed", message: "\u72B6\u6001\u540C\u6B65\u5931\u8D25\uFF0C\u8BF7\u91CD\u8BD5" };
|
|
915
|
+
}
|
|
916
|
+
if (state.display.authoritySyncFailed) {
|
|
917
|
+
return { kind: "sync_failed", message: "\u540C\u6B65\u72B6\u6001\u5931\u8D25\uFF0C\u8BF7\u5237\u65B0" };
|
|
918
|
+
}
|
|
919
|
+
const auth = state.authority?.status;
|
|
920
|
+
if (auth === "error") {
|
|
921
|
+
return { kind: "authority_error", message: "Workflow \u6267\u884C\u5931\u8D25" };
|
|
922
|
+
}
|
|
923
|
+
if (state.snapshotHydrateFailed) {
|
|
924
|
+
return {
|
|
925
|
+
kind: "snapshot_unavailable",
|
|
926
|
+
message: "\u65E0\u6CD5\u52A0\u8F7D projection snapshot\uFF0C\u5C55\u793A\u53EF\u80FD\u4E0D\u5B8C\u6574"
|
|
927
|
+
};
|
|
928
|
+
}
|
|
929
|
+
if (state.display.awaitingAuthority) {
|
|
930
|
+
return { kind: "awaiting_authority", message: "\u6536\u5C3E\u4E2D\u2026" };
|
|
931
|
+
}
|
|
932
|
+
if (auth === "partial_success") {
|
|
933
|
+
const forced = state.display.terminalKind === "forced_closeout";
|
|
934
|
+
return {
|
|
935
|
+
kind: "partial_success",
|
|
936
|
+
message: forced ? "\u90E8\u5206\u5B8C\u6210\uFF08\u90E8\u5206\u5BB9\u5668\u672A\u6B63\u5E38\u7ED3\u675F\uFF09" : "\u90E8\u5206\u5B8C\u6210\uFF08\u6240\u6709\u5BB9\u5668\u6B63\u5E38\u7ED3\u675F\uFF09"
|
|
937
|
+
};
|
|
938
|
+
}
|
|
939
|
+
const meta = state.authority?.metadata;
|
|
940
|
+
if (auth === "done" && meta?.projection_status === "degraded") {
|
|
941
|
+
const dropped = meta.projection_dropped_count;
|
|
942
|
+
const suffix = dropped != null && dropped > 0 ? `\uFF08\u7EA6 ${dropped} \u6761\u4E8B\u4EF6\u672A\u5B8C\u6574\u5C55\u793A\uFF09` : "";
|
|
943
|
+
return {
|
|
944
|
+
kind: "projection_degraded",
|
|
945
|
+
message: `\u5C55\u793A\u53EF\u80FD\u4E0D\u5B8C\u6574${suffix}`
|
|
946
|
+
};
|
|
947
|
+
}
|
|
948
|
+
if (state.display.terminalKind === "forced_closeout" && auth === "done") {
|
|
949
|
+
return { kind: "forced_closeout", message: "Workflow \u5DF2\u7ED3\u675F\uFF08\u90E8\u5206\u5BB9\u5668\u672A\u6B63\u5E38\u5173\u95ED\uFF09" };
|
|
950
|
+
}
|
|
951
|
+
return { kind: "none", message: "" };
|
|
952
|
+
}
|
|
953
|
+
function getDisplayProjectionStatus(state) {
|
|
954
|
+
return state.display.projectionStatus;
|
|
955
|
+
}
|
|
956
|
+
function applyAuthoritySnapshotToState(state, snapshot) {
|
|
957
|
+
return { ...state, authority: snapshot };
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
// src/core/context/WorkflowSessionContext.tsx
|
|
872
961
|
var WorkflowSessionStoreContext = createContext(null);
|
|
873
962
|
function useWorkflowSessionStoreApi() {
|
|
874
963
|
const store = useContext(WorkflowSessionStoreContext);
|
|
@@ -879,7 +968,7 @@ function useWorkflowSessionStoreApi() {
|
|
|
879
968
|
}
|
|
880
969
|
function useWorkflowSessionStatus() {
|
|
881
970
|
const store = useWorkflowSessionStoreApi();
|
|
882
|
-
return useStore(store, (s) => s.state
|
|
971
|
+
return useStore(store, (s) => getDisplayProjectionStatus(s.state));
|
|
883
972
|
}
|
|
884
973
|
|
|
885
974
|
// src/core/context/WorkflowLoopReplayContext.tsx
|
|
@@ -944,6 +1033,17 @@ function containerTreeToSnapshot(tree) {
|
|
|
944
1033
|
}
|
|
945
1034
|
|
|
946
1035
|
// src/types/workflowSession.ts
|
|
1036
|
+
function createEmptyWorkflowDisplayProjection() {
|
|
1037
|
+
return {
|
|
1038
|
+
streamEnded: false,
|
|
1039
|
+
projectionStatus: "connecting",
|
|
1040
|
+
terminalKind: null,
|
|
1041
|
+
openChildIdentities: [],
|
|
1042
|
+
awaitingAuthority: false,
|
|
1043
|
+
authoritySyncFailed: false,
|
|
1044
|
+
authoritySubscribeFailed: false
|
|
1045
|
+
};
|
|
1046
|
+
}
|
|
947
1047
|
function createEmptyWorkflowProgress() {
|
|
948
1048
|
return {
|
|
949
1049
|
workflowId: null,
|
|
@@ -955,9 +1055,8 @@ function createEmptyWorkflowProgress() {
|
|
|
955
1055
|
}
|
|
956
1056
|
function createEmptyWorkflowSessionState() {
|
|
957
1057
|
return {
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
openChildIdentities: [],
|
|
1058
|
+
authority: null,
|
|
1059
|
+
display: createEmptyWorkflowDisplayProjection(),
|
|
961
1060
|
meta: { workflowRunId: null, startedAt: null, lastEventId: null },
|
|
962
1061
|
containerTree: createEmptyWorkflowContainerTreeState(),
|
|
963
1062
|
workflowProgress: createEmptyWorkflowProgress(),
|
|
@@ -965,6 +1064,10 @@ function createEmptyWorkflowSessionState() {
|
|
|
965
1064
|
stageDoneSummariesByContainerId: {},
|
|
966
1065
|
hotCompletedLoopSessionIds: [],
|
|
967
1066
|
activeLoopSessionId: null,
|
|
1067
|
+
projectionCursor: null,
|
|
1068
|
+
snapshotVersion: null,
|
|
1069
|
+
reconnectSuppressedReason: null,
|
|
1070
|
+
snapshotHydrateFailed: false,
|
|
968
1071
|
openScopeStack: [],
|
|
969
1072
|
internalErrors: []
|
|
970
1073
|
};
|
|
@@ -2150,7 +2253,10 @@ function readOpenChildIdentities(data) {
|
|
|
2150
2253
|
if (!Array.isArray(raw)) return [];
|
|
2151
2254
|
return raw.filter((item) => typeof item === "string");
|
|
2152
2255
|
}
|
|
2153
|
-
function
|
|
2256
|
+
function projectionStatusFromTerminalKind(kind, isWorkflowFailedEvent) {
|
|
2257
|
+
return sessionStatusFromTerminalKind(kind, isWorkflowFailedEvent);
|
|
2258
|
+
}
|
|
2259
|
+
function isDisplayProjectionTerminal(status) {
|
|
2154
2260
|
return status === "done" || status === "done_with_warning" || status === "error";
|
|
2155
2261
|
}
|
|
2156
2262
|
|
|
@@ -2523,18 +2629,16 @@ function applyStructureEvent(state, event) {
|
|
|
2523
2629
|
containerTree,
|
|
2524
2630
|
state.workflowProgress
|
|
2525
2631
|
);
|
|
2526
|
-
let
|
|
2527
|
-
if (
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
let terminalKind = state.terminalKind;
|
|
2531
|
-
let openChildIdentities = state.openChildIdentities;
|
|
2632
|
+
let projectionStatus = nextState.display.projectionStatus;
|
|
2633
|
+
if (projectionStatus === "connecting") projectionStatus = "running";
|
|
2634
|
+
let terminalKind = state.display.terminalKind;
|
|
2635
|
+
let openChildIdentities = state.display.openChildIdentities;
|
|
2532
2636
|
if (projectedEvent.event_type === "workflow-end" || projectedEvent.event_type === "workflow-failed") {
|
|
2533
2637
|
const resolved = resolveWorkflowTerminalKind(
|
|
2534
2638
|
structureData,
|
|
2535
2639
|
projectedEvent.event_type
|
|
2536
2640
|
);
|
|
2537
|
-
|
|
2641
|
+
projectionStatus = projectionStatusFromTerminalKind(
|
|
2538
2642
|
resolved,
|
|
2539
2643
|
projectedEvent.event_type === "workflow-failed"
|
|
2540
2644
|
);
|
|
@@ -2543,9 +2647,12 @@ function applyStructureEvent(state, event) {
|
|
|
2543
2647
|
}
|
|
2544
2648
|
const base = {
|
|
2545
2649
|
...nextState,
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2650
|
+
display: {
|
|
2651
|
+
...nextState.display,
|
|
2652
|
+
projectionStatus,
|
|
2653
|
+
terminalKind,
|
|
2654
|
+
openChildIdentities
|
|
2655
|
+
},
|
|
2549
2656
|
containerTree,
|
|
2550
2657
|
workflowProgress
|
|
2551
2658
|
};
|
|
@@ -2613,11 +2720,9 @@ function reduceWorkflowSession(state, event, eventIndex, options) {
|
|
|
2613
2720
|
next.containerTree,
|
|
2614
2721
|
next.workflowProgress
|
|
2615
2722
|
);
|
|
2616
|
-
let
|
|
2617
|
-
if (
|
|
2618
|
-
else if (
|
|
2619
|
-
else if (reducedLoop.status === "error") status = "error";
|
|
2620
|
-
else if (status === "connecting") status = "running";
|
|
2723
|
+
let projectionStatus = next.display.projectionStatus;
|
|
2724
|
+
if (reducedLoop.status === "error") projectionStatus = "error";
|
|
2725
|
+
else if (projectionStatus === "connecting") projectionStatus = "running";
|
|
2621
2726
|
return {
|
|
2622
2727
|
...next,
|
|
2623
2728
|
workflowProgress,
|
|
@@ -2626,61 +2731,38 @@ function reduceWorkflowSession(state, event, eventIndex, options) {
|
|
|
2626
2731
|
[loopSessionId]: reducedLoop
|
|
2627
2732
|
},
|
|
2628
2733
|
activeLoopSessionId: loopSessionId,
|
|
2629
|
-
|
|
2734
|
+
display: {
|
|
2735
|
+
...next.display,
|
|
2736
|
+
projectionStatus
|
|
2737
|
+
}
|
|
2630
2738
|
};
|
|
2631
2739
|
}
|
|
2632
|
-
function
|
|
2633
|
-
if (
|
|
2634
|
-
return {
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
return { ...state, status: "done", activeLoopSessionId: null };
|
|
2640
|
-
}
|
|
2641
|
-
const root = tree.containersById[rootId];
|
|
2642
|
-
if (!root) {
|
|
2643
|
-
return { ...state, status: "done", activeLoopSessionId: null };
|
|
2740
|
+
function finalizeWorkflowDisplayOnStreamEnded(state) {
|
|
2741
|
+
if (isDisplayProjectionTerminal(state.display.projectionStatus)) {
|
|
2742
|
+
return {
|
|
2743
|
+
...state,
|
|
2744
|
+
display: { ...state.display, streamEnded: true },
|
|
2745
|
+
activeLoopSessionId: null
|
|
2746
|
+
};
|
|
2644
2747
|
}
|
|
2645
|
-
const
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
const settledStageCount = topLevelStages.filter(
|
|
2653
|
-
(s) => s.status === "completed" || s.status === "failed" || s.status === "skipped"
|
|
2654
|
-
).length;
|
|
2655
|
-
const progressCurrent = Math.max(
|
|
2656
|
-
root.display?.progress_current ?? 0,
|
|
2657
|
-
settledStageCount
|
|
2658
|
-
);
|
|
2659
|
-
const rootParallelItems = Object.values(tree.containersById).filter(
|
|
2660
|
-
(node) => node.scope === "item" && node.workflow_path === root.workflow_path && node.workflow_depth === root.workflow_depth
|
|
2661
|
-
);
|
|
2662
|
-
const rootParallelSettled = topLevelStages.length === 0 && rootParallelItems.length > 0 && rootParallelItems.every(
|
|
2663
|
-
(item) => item.status === "completed" || item.status === "failed" || item.status === "skipped"
|
|
2664
|
-
) && !Object.values(tree.containersById).some(
|
|
2665
|
-
(node) => node.container_id !== rootId && node.workflow_path === root.workflow_path && node.workflow_depth === root.workflow_depth && (node.status === "running" || node.status === "retrying" || node.status === "pending")
|
|
2666
|
-
);
|
|
2667
|
-
const workflowVisuallyComplete = root.status === "completed" || root.status === "failed" || progressTotal > 0 && progressCurrent >= progressTotal || rootParallelSettled;
|
|
2668
|
-
if (!workflowVisuallyComplete) {
|
|
2669
|
-
return state;
|
|
2748
|
+
const withStreamEnded = {
|
|
2749
|
+
...state,
|
|
2750
|
+
display: { ...state.display, streamEnded: true },
|
|
2751
|
+
activeLoopSessionId: null
|
|
2752
|
+
};
|
|
2753
|
+
if (isAuthorityTerminalStatus(state.authority?.status)) {
|
|
2754
|
+
return forceSettleRunningContainersForDisplay(withStreamEnded);
|
|
2670
2755
|
}
|
|
2756
|
+
return withStreamEnded;
|
|
2757
|
+
}
|
|
2758
|
+
function forceSettleRunningContainersForDisplay(state) {
|
|
2759
|
+
const tree = state.containerTree;
|
|
2671
2760
|
let containersById = { ...tree.containersById };
|
|
2672
2761
|
for (const [id, node] of Object.entries(containersById)) {
|
|
2673
2762
|
if (node.status === "running" || node.status === "pending") {
|
|
2674
2763
|
containersById[id] = { ...node, status: "completed", is_open: false };
|
|
2675
2764
|
}
|
|
2676
2765
|
}
|
|
2677
|
-
const settledRoot = containersById[rootId] ?? root;
|
|
2678
|
-
if (settledRoot.status !== "completed" && settledRoot.status !== "failed") {
|
|
2679
|
-
containersById = {
|
|
2680
|
-
...containersById,
|
|
2681
|
-
[rootId]: { ...settledRoot, status: "completed", is_open: false }
|
|
2682
|
-
};
|
|
2683
|
-
}
|
|
2684
2766
|
const loopTreesBySessionId = { ...state.loopTreesBySessionId };
|
|
2685
2767
|
for (const [loopSessionId, loopTree] of Object.entries(loopTreesBySessionId)) {
|
|
2686
2768
|
if (loopTree.status === "running" || loopTree.status === "connecting") {
|
|
@@ -2694,15 +2776,9 @@ function finalizeWorkflowSessionOnStreamComplete(state) {
|
|
|
2694
2776
|
(id) => containersById[id]?.is_open
|
|
2695
2777
|
)
|
|
2696
2778
|
};
|
|
2697
|
-
const workflowProgress = syncWorkflowProgressFromContainerTree(
|
|
2698
|
-
containerTree,
|
|
2699
|
-
state.workflowProgress
|
|
2700
|
-
);
|
|
2701
2779
|
return {
|
|
2702
2780
|
...state,
|
|
2703
|
-
status: workflowProgress.status === "error" ? "error" : "done",
|
|
2704
2781
|
containerTree,
|
|
2705
|
-
workflowProgress,
|
|
2706
2782
|
loopTreesBySessionId,
|
|
2707
2783
|
activeLoopSessionId: null
|
|
2708
2784
|
};
|
|
@@ -2714,6 +2790,41 @@ function reduceWorkflowEvents(events, options) {
|
|
|
2714
2790
|
);
|
|
2715
2791
|
}
|
|
2716
2792
|
|
|
2793
|
+
// src/core/workflow/hydrateWorkflowSnapshot.ts
|
|
2794
|
+
function isAtOrBeforeProjectionCursor(projectionCursor, eventId) {
|
|
2795
|
+
if (!projectionCursor || !eventId) return false;
|
|
2796
|
+
const cursorNum = Number.parseInt(projectionCursor, 10);
|
|
2797
|
+
const eventNum = Number.parseInt(eventId, 10);
|
|
2798
|
+
if (!Number.isNaN(cursorNum) && !Number.isNaN(eventNum)) {
|
|
2799
|
+
return eventNum <= cursorNum;
|
|
2800
|
+
}
|
|
2801
|
+
return eventId <= projectionCursor;
|
|
2802
|
+
}
|
|
2803
|
+
function hydrateWorkflowFromSnapshot(state, snapshot, options = {}) {
|
|
2804
|
+
const authority = options.preserveAuthority ? state.authority : null;
|
|
2805
|
+
return {
|
|
2806
|
+
...createEmptyWorkflowSessionState(),
|
|
2807
|
+
authority,
|
|
2808
|
+
display: {
|
|
2809
|
+
...snapshot.display,
|
|
2810
|
+
streamEnded: false
|
|
2811
|
+
},
|
|
2812
|
+
containerTree: structuredClone(snapshot.containerTree),
|
|
2813
|
+
projectionCursor: snapshot.cursor,
|
|
2814
|
+
snapshotVersion: snapshot.snapshotVersion,
|
|
2815
|
+
meta: {
|
|
2816
|
+
...state.meta,
|
|
2817
|
+
workflowRunId: snapshot.taskId,
|
|
2818
|
+
lastEventId: snapshot.cursor,
|
|
2819
|
+
startedAt: state.meta.startedAt ?? snapshot.capturedAt
|
|
2820
|
+
},
|
|
2821
|
+
loopTreesBySessionId: {},
|
|
2822
|
+
internalErrors: [],
|
|
2823
|
+
reconnectSuppressedReason: null,
|
|
2824
|
+
snapshotHydrateFailed: false
|
|
2825
|
+
};
|
|
2826
|
+
}
|
|
2827
|
+
|
|
2717
2828
|
// src/core/workflowSessionStore.ts
|
|
2718
2829
|
var DEFAULT_HYDRATE_CHUNK_SIZE = 50;
|
|
2719
2830
|
function nextAnimationFrame() {
|
|
@@ -2764,7 +2875,10 @@ function finalizeWorkflowSessionOnStreamError(state, message, eventIndex, stack)
|
|
|
2764
2875
|
}
|
|
2765
2876
|
return {
|
|
2766
2877
|
...state,
|
|
2767
|
-
|
|
2878
|
+
display: {
|
|
2879
|
+
...state.display,
|
|
2880
|
+
projectionStatus: "error"
|
|
2881
|
+
},
|
|
2768
2882
|
containerTree: {
|
|
2769
2883
|
...state.containerTree,
|
|
2770
2884
|
containersById,
|
|
@@ -2799,8 +2913,12 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
|
|
|
2799
2913
|
hydratingLoopSessionIds: {},
|
|
2800
2914
|
applyEvent(event, ctx) {
|
|
2801
2915
|
const sseEventId = ctx?.sseEventId;
|
|
2802
|
-
if (shouldSkipDuplicateEvent(seenEventIds, sseEventId)) return;
|
|
2803
2916
|
const { state, eventCount } = get();
|
|
2917
|
+
if (isAtOrBeforeProjectionCursor(state.projectionCursor, sseEventId)) {
|
|
2918
|
+
markEventIdSeen(seenEventIds, sseEventId);
|
|
2919
|
+
return;
|
|
2920
|
+
}
|
|
2921
|
+
if (shouldSkipDuplicateEvent(seenEventIds, sseEventId)) return;
|
|
2804
2922
|
const { state: reduced } = safeReduceWorkflow(state, event, eventCount, reduceOpts);
|
|
2805
2923
|
const evicted = finalizeState(reduced);
|
|
2806
2924
|
const nextMeta = sseEventId ? { ...evicted.meta, lastEventId: sseEventId } : evicted.meta;
|
|
@@ -2809,7 +2927,10 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
|
|
|
2809
2927
|
state: {
|
|
2810
2928
|
...evicted,
|
|
2811
2929
|
meta: nextMeta,
|
|
2812
|
-
|
|
2930
|
+
display: {
|
|
2931
|
+
...evicted.display,
|
|
2932
|
+
projectionStatus: evicted.display.projectionStatus === "connecting" ? "running" : evicted.display.projectionStatus
|
|
2933
|
+
}
|
|
2813
2934
|
},
|
|
2814
2935
|
eventCount: eventCount + 1
|
|
2815
2936
|
});
|
|
@@ -2839,13 +2960,59 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
|
|
|
2839
2960
|
)
|
|
2840
2961
|
});
|
|
2841
2962
|
},
|
|
2842
|
-
|
|
2963
|
+
markStreamEnded() {
|
|
2843
2964
|
set((current) => ({
|
|
2844
2965
|
state: finalizeState(
|
|
2845
|
-
|
|
2966
|
+
finalizeWorkflowDisplayOnStreamEnded(current.state)
|
|
2846
2967
|
)
|
|
2847
2968
|
}));
|
|
2848
2969
|
},
|
|
2970
|
+
applyAuthoritySnapshot(snapshot) {
|
|
2971
|
+
set((current) => ({
|
|
2972
|
+
state: {
|
|
2973
|
+
...current.state,
|
|
2974
|
+
authority: snapshot,
|
|
2975
|
+
display: {
|
|
2976
|
+
...current.state.display,
|
|
2977
|
+
awaitingAuthority: false,
|
|
2978
|
+
authoritySyncFailed: false
|
|
2979
|
+
}
|
|
2980
|
+
}
|
|
2981
|
+
}));
|
|
2982
|
+
},
|
|
2983
|
+
setAwaitingAuthority(value) {
|
|
2984
|
+
set((current) => ({
|
|
2985
|
+
state: {
|
|
2986
|
+
...current.state,
|
|
2987
|
+
display: {
|
|
2988
|
+
...current.state.display,
|
|
2989
|
+
awaitingAuthority: value
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
}));
|
|
2993
|
+
},
|
|
2994
|
+
setAuthoritySyncFailed(value) {
|
|
2995
|
+
set((current) => ({
|
|
2996
|
+
state: {
|
|
2997
|
+
...current.state,
|
|
2998
|
+
display: {
|
|
2999
|
+
...current.state.display,
|
|
3000
|
+
authoritySyncFailed: value
|
|
3001
|
+
}
|
|
3002
|
+
}
|
|
3003
|
+
}));
|
|
3004
|
+
},
|
|
3005
|
+
setAuthoritySubscribeFailed(value) {
|
|
3006
|
+
set((current) => ({
|
|
3007
|
+
state: {
|
|
3008
|
+
...current.state,
|
|
3009
|
+
display: {
|
|
3010
|
+
...current.state.display,
|
|
3011
|
+
authoritySubscribeFailed: value
|
|
3012
|
+
}
|
|
3013
|
+
}
|
|
3014
|
+
}));
|
|
3015
|
+
},
|
|
2849
3016
|
/**
|
|
2850
3017
|
* P2:将 completed loop 加入 LRU 热缓存并淘汰溢出。
|
|
2851
3018
|
* running 保护由 collectProtectedLoopSessionIds 按状态自动覆盖,不再依赖永久 pin。
|
|
@@ -2948,15 +3115,114 @@ function createWorkflowSessionStore(initialState = createEmptyWorkflowSessionSta
|
|
|
2948
3115
|
loopSessionId
|
|
2949
3116
|
)
|
|
2950
3117
|
}));
|
|
3118
|
+
},
|
|
3119
|
+
hydrateFromSnapshot(snapshot, options) {
|
|
3120
|
+
const { state } = get();
|
|
3121
|
+
const next = finalizeState(
|
|
3122
|
+
hydrateWorkflowFromSnapshot(state, snapshot, options)
|
|
3123
|
+
);
|
|
3124
|
+
markEventIdSeen(seenEventIds, snapshot.cursor);
|
|
3125
|
+
set({ state: next });
|
|
3126
|
+
},
|
|
3127
|
+
markSnapshotHydrateFailed() {
|
|
3128
|
+
set((current) => ({
|
|
3129
|
+
state: {
|
|
3130
|
+
...current.state,
|
|
3131
|
+
snapshotHydrateFailed: true,
|
|
3132
|
+
reconnectSuppressedReason: "snapshot_unavailable"
|
|
3133
|
+
}
|
|
3134
|
+
}));
|
|
2951
3135
|
}
|
|
2952
3136
|
}));
|
|
2953
3137
|
}
|
|
2954
3138
|
|
|
3139
|
+
// src/core/workflow/useWorkflowAuthorityBinding.ts
|
|
3140
|
+
import { useEffect as useEffect3, useRef as useRef3 } from "react";
|
|
3141
|
+
|
|
3142
|
+
// src/core/workflow/normalizeAuthoritySnapshot.ts
|
|
3143
|
+
var KNOWN = /* @__PURE__ */ new Set([
|
|
3144
|
+
"pending",
|
|
3145
|
+
"running",
|
|
3146
|
+
"done",
|
|
3147
|
+
"error",
|
|
3148
|
+
"canceled",
|
|
3149
|
+
"partial_success"
|
|
3150
|
+
]);
|
|
3151
|
+
function normalizeAuthoritySnapshot(snapshot) {
|
|
3152
|
+
if (KNOWN.has(snapshot.status)) {
|
|
3153
|
+
return snapshot;
|
|
3154
|
+
}
|
|
3155
|
+
if (import.meta.env?.DEV) {
|
|
3156
|
+
console.warn(
|
|
3157
|
+
`[langchain_agentx_stream_ui] unknown authority.status "${String(snapshot.status)}"; defaulting to running`
|
|
3158
|
+
);
|
|
3159
|
+
}
|
|
3160
|
+
return { ...snapshot, status: "running" };
|
|
3161
|
+
}
|
|
3162
|
+
|
|
3163
|
+
// src/core/workflow/useWorkflowAuthorityBinding.ts
|
|
3164
|
+
function useWorkflowAuthorityBinding(store, authoritySource, callbacks) {
|
|
3165
|
+
const onAuthorityTerminalRef = useRef3(callbacks.onAuthorityTerminal);
|
|
3166
|
+
onAuthorityTerminalRef.current = callbacks.onAuthorityTerminal;
|
|
3167
|
+
const terminalFiredRef = useRef3(false);
|
|
3168
|
+
useEffect3(() => {
|
|
3169
|
+
terminalFiredRef.current = false;
|
|
3170
|
+
const apply = (raw) => {
|
|
3171
|
+
const snapshot = normalizeAuthoritySnapshot(raw);
|
|
3172
|
+
store.getState().applyAuthoritySnapshot(snapshot);
|
|
3173
|
+
if (!terminalFiredRef.current && isAuthorityTerminalStatus(snapshot.status)) {
|
|
3174
|
+
terminalFiredRef.current = true;
|
|
3175
|
+
onAuthorityTerminalRef.current?.(snapshot);
|
|
3176
|
+
}
|
|
3177
|
+
};
|
|
3178
|
+
const initial = authoritySource.getSnapshot();
|
|
3179
|
+
if (initial) {
|
|
3180
|
+
apply(initial);
|
|
3181
|
+
}
|
|
3182
|
+
let unsubscribe;
|
|
3183
|
+
try {
|
|
3184
|
+
unsubscribe = authoritySource.subscribe(apply);
|
|
3185
|
+
} catch (err) {
|
|
3186
|
+
if (import.meta.env?.DEV) {
|
|
3187
|
+
console.error("[langchain_agentx_stream_ui] authoritySource.subscribe failed:", err);
|
|
3188
|
+
}
|
|
3189
|
+
store.getState().setAuthoritySubscribeFailed(true);
|
|
3190
|
+
}
|
|
3191
|
+
return () => {
|
|
3192
|
+
unsubscribe?.();
|
|
3193
|
+
};
|
|
3194
|
+
}, [store, authoritySource]);
|
|
3195
|
+
}
|
|
3196
|
+
|
|
3197
|
+
// src/core/workflow/useWorkflowAwaitingAuthorityTimers.ts
|
|
3198
|
+
import { useEffect as useEffect4 } from "react";
|
|
3199
|
+
var AWAITING_MS = 3e4;
|
|
3200
|
+
var SYNC_FAILED_MS = 12e4;
|
|
3201
|
+
function useWorkflowAwaitingAuthorityTimers(store, streamEnded, authorityStatus) {
|
|
3202
|
+
useEffect4(() => {
|
|
3203
|
+
if (!streamEnded || authorityStatus !== "running") {
|
|
3204
|
+
store.getState().setAwaitingAuthority(false);
|
|
3205
|
+
store.getState().setAuthoritySyncFailed(false);
|
|
3206
|
+
return;
|
|
3207
|
+
}
|
|
3208
|
+
const tAwait = window.setTimeout(() => {
|
|
3209
|
+
store.getState().setAwaitingAuthority(true);
|
|
3210
|
+
}, AWAITING_MS);
|
|
3211
|
+
const tFail = window.setTimeout(() => {
|
|
3212
|
+
store.getState().setAuthoritySyncFailed(true);
|
|
3213
|
+
}, SYNC_FAILED_MS);
|
|
3214
|
+
return () => {
|
|
3215
|
+
window.clearTimeout(tAwait);
|
|
3216
|
+
window.clearTimeout(tFail);
|
|
3217
|
+
};
|
|
3218
|
+
}, [store, streamEnded, authorityStatus]);
|
|
3219
|
+
}
|
|
3220
|
+
|
|
2955
3221
|
// src/view/workflow/WorkflowChrome.tsx
|
|
2956
3222
|
import { useMemo as useMemo7, useState as useState6 } from "react";
|
|
2957
3223
|
|
|
2958
3224
|
// src/view/workflow/WorkflowAggregateContainer.tsx
|
|
2959
|
-
import { useCallback, useEffect as
|
|
3225
|
+
import { useCallback, useEffect as useEffect5, useMemo as useMemo2, useState, memo } from "react";
|
|
2960
3226
|
|
|
2961
3227
|
// src/view/workflow/WorkflowContainerLine.tsx
|
|
2962
3228
|
import { Fragment, jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
@@ -3366,7 +3632,7 @@ function WorkflowAggregateContainerInner({
|
|
|
3366
3632
|
const uiStatus = mapAggregateUiStatus(node);
|
|
3367
3633
|
const statusLabel = buildAggregateStatusLabel(node, siblingItems);
|
|
3368
3634
|
const [expanded, setExpanded] = useState(isRunning);
|
|
3369
|
-
|
|
3635
|
+
useEffect5(() => {
|
|
3370
3636
|
if (isRunning) setExpanded(true);
|
|
3371
3637
|
if (isDone) setExpanded(false);
|
|
3372
3638
|
}, [isRunning, isDone]);
|
|
@@ -3485,7 +3751,7 @@ var WorkflowAggregateContainer = memo(
|
|
|
3485
3751
|
);
|
|
3486
3752
|
|
|
3487
3753
|
// src/view/workflow/WorkflowParallelGroup.tsx
|
|
3488
|
-
import { useCallback as useCallback3, useEffect as
|
|
3754
|
+
import { useCallback as useCallback3, useEffect as useEffect7, useMemo as useMemo4, useState as useState3, memo as memo3 } from "react";
|
|
3489
3755
|
|
|
3490
3756
|
// src/core/workflow/workflowParallelGroupMetrics.ts
|
|
3491
3757
|
var ACTIVE_ITEM_STATUSES = /* @__PURE__ */ new Set([
|
|
@@ -3579,7 +3845,7 @@ function formatParallelGroupSummary(metrics) {
|
|
|
3579
3845
|
}
|
|
3580
3846
|
|
|
3581
3847
|
// src/view/workflow/WorkflowStageContainer.tsx
|
|
3582
|
-
import { useCallback as useCallback2, useEffect as
|
|
3848
|
+
import { useCallback as useCallback2, useEffect as useEffect6, useMemo as useMemo3, useState as useState2, memo as memo2 } from "react";
|
|
3583
3849
|
import { useStore as useStore2 } from "zustand";
|
|
3584
3850
|
|
|
3585
3851
|
// src/core/workflow/loopTreeUtils.ts
|
|
@@ -3666,7 +3932,7 @@ function WorkflowStageContainerInner({
|
|
|
3666
3932
|
const doneSummary = doneSummaryFromTree ?? (isDone ? cachedSummary : null);
|
|
3667
3933
|
const shouldAutoExpandRunning = effectivelyRunning && !isSkipped;
|
|
3668
3934
|
const [expanded, setExpanded] = useState2(shouldAutoExpandRunning);
|
|
3669
|
-
|
|
3935
|
+
useEffect6(() => {
|
|
3670
3936
|
if (shouldAutoExpandRunning) {
|
|
3671
3937
|
setExpanded(true);
|
|
3672
3938
|
return;
|
|
@@ -3691,7 +3957,7 @@ function WorkflowStageContainerInner({
|
|
|
3691
3957
|
return next;
|
|
3692
3958
|
});
|
|
3693
3959
|
}, [isDone, node.loopSessionId, loopTree, requestLoopHydration]);
|
|
3694
|
-
|
|
3960
|
+
useEffect6(() => {
|
|
3695
3961
|
const onKeyDown = (event) => {
|
|
3696
3962
|
if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "o") return;
|
|
3697
3963
|
setExpanded(true);
|
|
@@ -3844,7 +4110,7 @@ function WorkflowParallelGroupInner({
|
|
|
3844
4110
|
);
|
|
3845
4111
|
const allSettled = metrics.total > 0 && metrics.running === 0 && metrics.completed + metrics.failed >= metrics.total;
|
|
3846
4112
|
const [expanded, setExpanded] = useState3(hasActiveWork);
|
|
3847
|
-
|
|
4113
|
+
useEffect7(() => {
|
|
3848
4114
|
if (hasActiveWork) {
|
|
3849
4115
|
setExpanded(true);
|
|
3850
4116
|
return;
|
|
@@ -3856,7 +4122,7 @@ function WorkflowParallelGroupInner({
|
|
|
3856
4122
|
const toggleExpanded = useCallback3(() => {
|
|
3857
4123
|
setExpanded((prev) => !prev);
|
|
3858
4124
|
}, []);
|
|
3859
|
-
|
|
4125
|
+
useEffect7(() => {
|
|
3860
4126
|
const onKeyDown = (event) => {
|
|
3861
4127
|
if (!(event.ctrlKey || event.metaKey) || event.key.toLowerCase() !== "o") return;
|
|
3862
4128
|
setExpanded(true);
|
|
@@ -3956,7 +4222,7 @@ function WorkflowRootContainer({
|
|
|
3956
4222
|
}
|
|
3957
4223
|
|
|
3958
4224
|
// src/view/workflow/WorkflowRouteContainer.tsx
|
|
3959
|
-
import { useCallback as useCallback4, useEffect as
|
|
4225
|
+
import { useCallback as useCallback4, useEffect as useEffect8, useMemo as useMemo5, useState as useState4 } from "react";
|
|
3960
4226
|
import { jsx as jsx13, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
3961
4227
|
function WorkflowRouteContainer({
|
|
3962
4228
|
node,
|
|
@@ -3981,7 +4247,7 @@ function WorkflowRouteContainer({
|
|
|
3981
4247
|
const expandHint = doneSummary ? formatTeaserExpandHint(doneSummary.extraLines, verbose) : null;
|
|
3982
4248
|
const doneLabel = doneSummary?.label ?? "done";
|
|
3983
4249
|
const [expanded, setExpanded] = useState4(isRunning);
|
|
3984
|
-
|
|
4250
|
+
useEffect8(() => {
|
|
3985
4251
|
if (isSkipped) return;
|
|
3986
4252
|
if (isRunning) setExpanded(true);
|
|
3987
4253
|
if (isDone) setExpanded(false);
|
|
@@ -4057,7 +4323,7 @@ function WorkflowRouteContainer({
|
|
|
4057
4323
|
}
|
|
4058
4324
|
|
|
4059
4325
|
// src/view/workflow/WorkflowSubworkflowContainer.tsx
|
|
4060
|
-
import { useCallback as useCallback5, useEffect as
|
|
4326
|
+
import { useCallback as useCallback5, useEffect as useEffect9, useMemo as useMemo6, useState as useState5 } from "react";
|
|
4061
4327
|
import { jsx as jsx14, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
4062
4328
|
function buildDoneSummary(node) {
|
|
4063
4329
|
const display = node.display;
|
|
@@ -4088,7 +4354,7 @@ function WorkflowSubworkflowContainer({
|
|
|
4088
4354
|
return node.content_blocks[node.content_blocks.length - 1]?.preview ?? "";
|
|
4089
4355
|
}, [node.content_blocks]);
|
|
4090
4356
|
const [expanded, setExpanded] = useState5(effectivelyRunning);
|
|
4091
|
-
|
|
4357
|
+
useEffect9(() => {
|
|
4092
4358
|
if (effectivelyRunning) setExpanded(true);
|
|
4093
4359
|
else if (effectivelyDone) setExpanded(false);
|
|
4094
4360
|
}, [effectivelyRunning, effectivelyDone]);
|
|
@@ -4440,9 +4706,122 @@ function WorkflowChrome({
|
|
|
4440
4706
|
)) });
|
|
4441
4707
|
}
|
|
4442
4708
|
|
|
4709
|
+
// src/view/workflow/WorkflowGlobalSpinner.tsx
|
|
4710
|
+
import { useStore as useStore3 } from "zustand";
|
|
4711
|
+
import { jsx as jsx16, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
4712
|
+
function WorkflowGlobalSpinner() {
|
|
4713
|
+
const store = useWorkflowSessionStoreApi();
|
|
4714
|
+
const show = useStore3(store, (s) => shouldShowGlobalSpinner(s.state));
|
|
4715
|
+
if (!show) return null;
|
|
4716
|
+
return /* @__PURE__ */ jsx16(
|
|
4717
|
+
"div",
|
|
4718
|
+
{
|
|
4719
|
+
className: "lax-workflow-global-spinner lax-spinner-container",
|
|
4720
|
+
"data-testid": "lax-workflow-global-spinner",
|
|
4721
|
+
role: "status",
|
|
4722
|
+
children: /* @__PURE__ */ jsxs11("span", { className: "lax-spinner lax-workflow-global-spinner__inner", children: [
|
|
4723
|
+
/* @__PURE__ */ jsx16("span", { className: "lax-spinner-frame", children: "\u280B" }),
|
|
4724
|
+
/* @__PURE__ */ jsx16("span", { className: "lax-spinner-verb lax-spinner-verb--shimmer", children: "Workflow" })
|
|
4725
|
+
] })
|
|
4726
|
+
}
|
|
4727
|
+
);
|
|
4728
|
+
}
|
|
4729
|
+
|
|
4730
|
+
// src/view/workflow/WorkflowSessionBanners.tsx
|
|
4731
|
+
import { Fragment as Fragment3, jsx as jsx17, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
4732
|
+
function WorkflowSessionBanners({ state }) {
|
|
4733
|
+
const banner = resolveWorkflowBanner(state);
|
|
4734
|
+
const { display } = state;
|
|
4735
|
+
if (banner.kind === "none" && display.projectionStatus !== "error" && display.projectionStatus !== "done_with_warning" && state.internalErrors.length === 0) {
|
|
4736
|
+
return null;
|
|
4737
|
+
}
|
|
4738
|
+
const showTransportError = (display.projectionStatus === "error" || state.internalErrors.length > 0) && banner.kind !== "projection_degraded" && banner.kind !== "authority_error";
|
|
4739
|
+
return /* @__PURE__ */ jsxs12(Fragment3, { children: [
|
|
4740
|
+
banner.kind === "authority_error" ? /* @__PURE__ */ jsx17(
|
|
4741
|
+
"div",
|
|
4742
|
+
{
|
|
4743
|
+
className: "lax-workflow-banner lax-workflow-banner--authority-error",
|
|
4744
|
+
"data-testid": "lax-workflow-authority-error-banner",
|
|
4745
|
+
role: "alert",
|
|
4746
|
+
children: banner.message
|
|
4747
|
+
}
|
|
4748
|
+
) : null,
|
|
4749
|
+
banner.kind === "projection_degraded" ? /* @__PURE__ */ jsx17(
|
|
4750
|
+
"div",
|
|
4751
|
+
{
|
|
4752
|
+
className: "lax-workflow-banner lax-workflow-banner--projection-degraded",
|
|
4753
|
+
"data-testid": "lax-workflow-projection-degraded-banner",
|
|
4754
|
+
role: "status",
|
|
4755
|
+
children: banner.message
|
|
4756
|
+
}
|
|
4757
|
+
) : null,
|
|
4758
|
+
banner.kind === "snapshot_unavailable" ? /* @__PURE__ */ jsx17(
|
|
4759
|
+
"div",
|
|
4760
|
+
{
|
|
4761
|
+
className: "lax-workflow-banner lax-workflow-banner--snapshot-unavailable",
|
|
4762
|
+
"data-testid": "lax-workflow-snapshot-unavailable-banner",
|
|
4763
|
+
role: "status",
|
|
4764
|
+
children: banner.message
|
|
4765
|
+
}
|
|
4766
|
+
) : null,
|
|
4767
|
+
banner.kind === "partial_success" ? /* @__PURE__ */ jsx17(
|
|
4768
|
+
"div",
|
|
4769
|
+
{
|
|
4770
|
+
className: "lax-workflow-banner lax-workflow-banner--partial-success",
|
|
4771
|
+
"data-testid": "lax-workflow-partial-success-banner",
|
|
4772
|
+
role: "status",
|
|
4773
|
+
children: banner.message
|
|
4774
|
+
}
|
|
4775
|
+
) : null,
|
|
4776
|
+
banner.kind === "forced_closeout" || display.projectionStatus === "done_with_warning" ? /* @__PURE__ */ jsxs12(
|
|
4777
|
+
"div",
|
|
4778
|
+
{
|
|
4779
|
+
className: "lax-workflow-closeout-warning",
|
|
4780
|
+
"data-testid": "lax-workflow-closeout-warning",
|
|
4781
|
+
role: "status",
|
|
4782
|
+
children: [
|
|
4783
|
+
/* @__PURE__ */ jsx17("strong", { children: "Workflow forced closeout" }),
|
|
4784
|
+
/* @__PURE__ */ jsxs12("span", { children: [
|
|
4785
|
+
" ",
|
|
4786
|
+
"\u2014 stream ended with unresolved child scopes; not a healthy completion."
|
|
4787
|
+
] }),
|
|
4788
|
+
display.openChildIdentities.length > 0 ? /* @__PURE__ */ jsx17("ul", { className: "lax-workflow-closeout-warning__scopes", children: display.openChildIdentities.map((identity) => /* @__PURE__ */ jsx17("li", { children: identity }, identity)) }) : null
|
|
4789
|
+
]
|
|
4790
|
+
}
|
|
4791
|
+
) : null,
|
|
4792
|
+
banner.kind === "awaiting_authority" ? /* @__PURE__ */ jsx17(
|
|
4793
|
+
"div",
|
|
4794
|
+
{
|
|
4795
|
+
className: "lax-workflow-banner lax-workflow-banner--awaiting",
|
|
4796
|
+
"data-testid": "lax-workflow-awaiting-authority-banner",
|
|
4797
|
+
role: "status",
|
|
4798
|
+
children: banner.message
|
|
4799
|
+
}
|
|
4800
|
+
) : null,
|
|
4801
|
+
banner.kind === "sync_failed" ? /* @__PURE__ */ jsx17(
|
|
4802
|
+
"div",
|
|
4803
|
+
{
|
|
4804
|
+
className: "lax-workflow-banner lax-workflow-banner--sync-failed",
|
|
4805
|
+
"data-testid": "lax-workflow-authority-sync-failed-banner",
|
|
4806
|
+
role: "alert",
|
|
4807
|
+
children: banner.message
|
|
4808
|
+
}
|
|
4809
|
+
) : null,
|
|
4810
|
+
showTransportError ? /* @__PURE__ */ jsx17(
|
|
4811
|
+
"div",
|
|
4812
|
+
{
|
|
4813
|
+
className: "lax-workflow-error",
|
|
4814
|
+
"data-testid": "lax-workflow-error",
|
|
4815
|
+
role: "alert",
|
|
4816
|
+
children: state.internalErrors[state.internalErrors.length - 1]?.message ?? "Workflow stream error"
|
|
4817
|
+
}
|
|
4818
|
+
) : null
|
|
4819
|
+
] });
|
|
4820
|
+
}
|
|
4821
|
+
|
|
4443
4822
|
// src/view/workflow/WorkflowTaskListFooter.tsx
|
|
4444
4823
|
import { useMemo as useMemo8, useState as useState7 } from "react";
|
|
4445
|
-
import { useStore as
|
|
4824
|
+
import { useStore as useStore4 } from "zustand";
|
|
4446
4825
|
|
|
4447
4826
|
// src/view/workflow/workflowTaskListMerge.ts
|
|
4448
4827
|
var STATUS_ORDER = {
|
|
@@ -4483,7 +4862,7 @@ function deriveWorkflowTaskFooterState(state) {
|
|
|
4483
4862
|
tasks: mergeWorkflowLoopTasks(state.loopTreesBySessionId),
|
|
4484
4863
|
taskPhase: deriveWorkflowTaskPhase(trees),
|
|
4485
4864
|
hasEverShownTaskList: trees.some((tree) => tree.hasEverShownTaskList),
|
|
4486
|
-
sessionStatus: state
|
|
4865
|
+
sessionStatus: getDisplayProjectionStatus(state)
|
|
4487
4866
|
};
|
|
4488
4867
|
}
|
|
4489
4868
|
function shouldShowWorkflowTaskListFooter(state) {
|
|
@@ -4513,16 +4892,16 @@ function loopSessionDisplayLabel(loopSessionId) {
|
|
|
4513
4892
|
}
|
|
4514
4893
|
|
|
4515
4894
|
// src/view/workflow/WorkflowTaskListFooter.tsx
|
|
4516
|
-
import { jsx as
|
|
4895
|
+
import { jsx as jsx18, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
4517
4896
|
function MessageResponse({ children }) {
|
|
4518
|
-
return /* @__PURE__ */
|
|
4519
|
-
/* @__PURE__ */
|
|
4520
|
-
/* @__PURE__ */
|
|
4897
|
+
return /* @__PURE__ */ jsxs13("div", { className: "lax-message-response", children: [
|
|
4898
|
+
/* @__PURE__ */ jsx18("span", { className: "lax-message-response__marker", children: "\u23BF " }),
|
|
4899
|
+
/* @__PURE__ */ jsx18("span", { className: "lax-message-response__content", children })
|
|
4521
4900
|
] });
|
|
4522
4901
|
}
|
|
4523
4902
|
function WorkflowTaskListFooter() {
|
|
4524
4903
|
const store = useWorkflowSessionStoreApi();
|
|
4525
|
-
const state =
|
|
4904
|
+
const state = useStore4(store, (s) => s.state);
|
|
4526
4905
|
const [expanded, setExpanded] = useState7(false);
|
|
4527
4906
|
const footerState = useMemo8(() => deriveWorkflowTaskFooterState(state), [state]);
|
|
4528
4907
|
const visible = shouldShowWorkflowTaskListFooter(state);
|
|
@@ -4531,8 +4910,8 @@ function WorkflowTaskListFooter() {
|
|
|
4531
4910
|
}
|
|
4532
4911
|
const label = formatWorkflowTaskFooterLabel(state);
|
|
4533
4912
|
const groups = groupWorkflowTasksByLoop(footerState.tasks);
|
|
4534
|
-
return /* @__PURE__ */
|
|
4535
|
-
/* @__PURE__ */
|
|
4913
|
+
return /* @__PURE__ */ jsxs13("div", { className: "lax-workflow-task-list-footer", "data-testid": "lax-workflow-task-list-footer", children: [
|
|
4914
|
+
/* @__PURE__ */ jsxs13(
|
|
4536
4915
|
"button",
|
|
4537
4916
|
{
|
|
4538
4917
|
type: "button",
|
|
@@ -4542,18 +4921,18 @@ function WorkflowTaskListFooter() {
|
|
|
4542
4921
|
onClick: () => setExpanded((v) => !v),
|
|
4543
4922
|
children: [
|
|
4544
4923
|
label,
|
|
4545
|
-
/* @__PURE__ */
|
|
4924
|
+
/* @__PURE__ */ jsx18("span", { className: "lax-task-list-footer__hint", children: expanded ? " \xB7 \u2191 to hide" : " \xB7 \u2193 to view" })
|
|
4546
4925
|
]
|
|
4547
4926
|
}
|
|
4548
4927
|
),
|
|
4549
|
-
expanded ? /* @__PURE__ */
|
|
4928
|
+
expanded ? /* @__PURE__ */ jsx18(MessageResponse, { children: /* @__PURE__ */ jsx18("div", { className: "lax-workflow-task-list-groups", children: groups.map((group) => /* @__PURE__ */ jsxs13(
|
|
4550
4929
|
"div",
|
|
4551
4930
|
{
|
|
4552
4931
|
className: "lax-workflow-task-list-group",
|
|
4553
4932
|
"data-testid": `lax-workflow-task-group-${group.loopSessionId}`,
|
|
4554
4933
|
children: [
|
|
4555
|
-
/* @__PURE__ */
|
|
4556
|
-
/* @__PURE__ */
|
|
4934
|
+
/* @__PURE__ */ jsx18("div", { className: "lax-workflow-task-list-group-title", children: loopSessionDisplayLabel(group.loopSessionId) }),
|
|
4935
|
+
/* @__PURE__ */ jsx18(TaskList, { tasks: group.tasks })
|
|
4557
4936
|
]
|
|
4558
4937
|
},
|
|
4559
4938
|
group.loopSessionId
|
|
@@ -4562,10 +4941,13 @@ function WorkflowTaskListFooter() {
|
|
|
4562
4941
|
}
|
|
4563
4942
|
|
|
4564
4943
|
// src/view/workflow/WorkflowSession.tsx
|
|
4565
|
-
import { useStore as
|
|
4566
|
-
import { jsx as
|
|
4944
|
+
import { useStore as useStore5 } from "zustand";
|
|
4945
|
+
import { jsx as jsx19, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
4567
4946
|
function WorkflowSession({
|
|
4568
4947
|
source,
|
|
4948
|
+
authoritySource,
|
|
4949
|
+
snapshotBootstrap,
|
|
4950
|
+
snapshotHydrateFailed = false,
|
|
4569
4951
|
initialEvents,
|
|
4570
4952
|
registry,
|
|
4571
4953
|
tierOverrides,
|
|
@@ -4585,10 +4967,11 @@ function WorkflowSession({
|
|
|
4585
4967
|
groupParallelTools = false,
|
|
4586
4968
|
workflowScale,
|
|
4587
4969
|
onRequestLoopReplay,
|
|
4588
|
-
|
|
4970
|
+
onAuthorityTerminal,
|
|
4971
|
+
onDisplayStreamEnded,
|
|
4589
4972
|
children
|
|
4590
4973
|
}) {
|
|
4591
|
-
const storeRef =
|
|
4974
|
+
const storeRef = useRef4(null);
|
|
4592
4975
|
if (storeRef.current === null) {
|
|
4593
4976
|
const initialState = initialEvents && initialEvents.length > 0 ? reduceWorkflowEvents(initialEvents, { tierOverrides }) : void 0;
|
|
4594
4977
|
storeRef.current = createWorkflowSessionStore(initialState, {
|
|
@@ -4598,6 +4981,21 @@ function WorkflowSession({
|
|
|
4598
4981
|
maxHydratedCompletedLoops: workflowScale?.maxHydratedCompletedLoops ?? DEFAULT_WORKFLOW_SCALE_OPTIONS.maxHydratedCompletedLoops
|
|
4599
4982
|
});
|
|
4600
4983
|
}
|
|
4984
|
+
const store = storeRef.current;
|
|
4985
|
+
useWorkflowAuthorityBinding(store, authoritySource, { onAuthorityTerminal });
|
|
4986
|
+
const streamEnded = useStore5(store, (s) => s.state.display.streamEnded);
|
|
4987
|
+
const authorityStatus = useStore5(store, (s) => s.state.authority?.status);
|
|
4988
|
+
useWorkflowAwaitingAuthorityTimers(store, streamEnded, authorityStatus);
|
|
4989
|
+
useEffect10(() => {
|
|
4990
|
+
if (snapshotBootstrap) {
|
|
4991
|
+
store.getState().hydrateFromSnapshot(snapshotBootstrap, { preserveAuthority: true });
|
|
4992
|
+
}
|
|
4993
|
+
}, [snapshotBootstrap, store]);
|
|
4994
|
+
useEffect10(() => {
|
|
4995
|
+
if (snapshotHydrateFailed) {
|
|
4996
|
+
store.getState().markSnapshotHydrateFailed();
|
|
4997
|
+
}
|
|
4998
|
+
}, [snapshotHydrateFailed, store]);
|
|
4601
4999
|
const scaleOptions = useMemo9(
|
|
4602
5000
|
() => ({ ...DEFAULT_WORKFLOW_SCALE_OPTIONS, ...workflowScale }),
|
|
4603
5001
|
[workflowScale]
|
|
@@ -4635,38 +5033,23 @@ function WorkflowSession({
|
|
|
4635
5033
|
workspaceRoot
|
|
4636
5034
|
]
|
|
4637
5035
|
);
|
|
4638
|
-
const
|
|
4639
|
-
|
|
4640
|
-
|
|
4641
|
-
);
|
|
4642
|
-
const
|
|
4643
|
-
|
|
4644
|
-
(s) => s.state.loopTreesBySessionId
|
|
4645
|
-
);
|
|
4646
|
-
const openChildIdentities = useStore4(
|
|
4647
|
-
storeRef.current,
|
|
4648
|
-
(s) => s.state.openChildIdentities
|
|
4649
|
-
);
|
|
4650
|
-
const sessionStatus = useStore4(
|
|
4651
|
-
storeRef.current,
|
|
4652
|
-
(s) => s.state.status
|
|
4653
|
-
);
|
|
4654
|
-
const internalErrors = useStore4(
|
|
4655
|
-
storeRef.current,
|
|
4656
|
-
(s) => s.state.internalErrors
|
|
4657
|
-
);
|
|
4658
|
-
const onErrorRef = useRef3(onError);
|
|
4659
|
-
const onStreamCompleteRef = useRef3(onStreamComplete);
|
|
5036
|
+
const sessionState = useStore5(store, (s) => s.state);
|
|
5037
|
+
const containerTree = sessionState.containerTree;
|
|
5038
|
+
const loopTreesBySessionId = sessionState.loopTreesBySessionId;
|
|
5039
|
+
const onErrorRef = useRef4(onError);
|
|
5040
|
+
const onDisplayStreamEndedRef = useRef4(onDisplayStreamEnded);
|
|
5041
|
+
const streamAbortRef = useRef4(null);
|
|
4660
5042
|
onErrorRef.current = onError;
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
5043
|
+
onDisplayStreamEndedRef.current = onDisplayStreamEnded;
|
|
5044
|
+
useEffect10(() => {
|
|
5045
|
+
if (!source) return void 0;
|
|
4664
5046
|
const controller = new AbortController();
|
|
5047
|
+
streamAbortRef.current = controller;
|
|
4665
5048
|
void source.start((event, ctx) => {
|
|
4666
5049
|
store.getState().applyEvent(event, ctx);
|
|
4667
5050
|
}, controller.signal).then(() => {
|
|
4668
|
-
store.getState().
|
|
4669
|
-
|
|
5051
|
+
store.getState().markStreamEnded();
|
|
5052
|
+
onDisplayStreamEndedRef.current?.();
|
|
4670
5053
|
}).catch((err) => {
|
|
4671
5054
|
if (err instanceof SseTransportTerminalError) {
|
|
4672
5055
|
store.getState().markAsError(err);
|
|
@@ -4677,40 +5060,23 @@ function WorkflowSession({
|
|
|
4677
5060
|
});
|
|
4678
5061
|
return () => {
|
|
4679
5062
|
controller.abort();
|
|
5063
|
+
streamAbortRef.current = null;
|
|
4680
5064
|
};
|
|
4681
|
-
}, [source]);
|
|
4682
|
-
|
|
5065
|
+
}, [source, store]);
|
|
5066
|
+
useEffect10(() => {
|
|
5067
|
+
if (isAuthorityTerminalStatus(authorityStatus)) {
|
|
5068
|
+
streamAbortRef.current?.abort();
|
|
5069
|
+
}
|
|
5070
|
+
}, [authorityStatus]);
|
|
5071
|
+
return /* @__PURE__ */ jsx19(WorkflowSessionStoreContext.Provider, { value: store, children: /* @__PURE__ */ jsx19(WorkflowScaleContext.Provider, { value: scaleOptions, children: /* @__PURE__ */ jsx19(WorkflowLoopReplayProvider, { onRequestLoopReplay, children: /* @__PURE__ */ jsx19(InteractionBusContext.Provider, { value: busRef, children: /* @__PURE__ */ jsx19(NodeRegistryContext.Provider, { value: registryRef, children: /* @__PURE__ */ jsx19(MarkdownRendererContext.Provider, { value: markdownRenderer, children: /* @__PURE__ */ jsx19(ToolDisplayOptionsContext.Provider, { value: toolDisplayRef, children: /* @__PURE__ */ jsx19(SessionViewOptionsContext.Provider, { value: sessionViewRef, children: /* @__PURE__ */ jsxs14(
|
|
4683
5072
|
"div",
|
|
4684
5073
|
{
|
|
4685
5074
|
className: "lax-agent-session lax-workflow-session",
|
|
4686
5075
|
"data-testid": "lax-workflow-session",
|
|
4687
5076
|
children: [
|
|
4688
|
-
|
|
4689
|
-
|
|
4690
|
-
|
|
4691
|
-
className: "lax-workflow-closeout-warning",
|
|
4692
|
-
"data-testid": "lax-workflow-closeout-warning",
|
|
4693
|
-
role: "status",
|
|
4694
|
-
children: [
|
|
4695
|
-
/* @__PURE__ */ jsx17("strong", { children: "Workflow forced closeout" }),
|
|
4696
|
-
/* @__PURE__ */ jsxs12("span", { children: [
|
|
4697
|
-
" ",
|
|
4698
|
-
"\u2014 stream ended with unresolved child scopes; not a healthy completion."
|
|
4699
|
-
] }),
|
|
4700
|
-
openChildIdentities.length > 0 ? /* @__PURE__ */ jsx17("ul", { className: "lax-workflow-closeout-warning__scopes", children: openChildIdentities.map((identity) => /* @__PURE__ */ jsx17("li", { children: identity }, identity)) }) : null
|
|
4701
|
-
]
|
|
4702
|
-
}
|
|
4703
|
-
) : null,
|
|
4704
|
-
sessionStatus === "error" || internalErrors.length > 0 ? /* @__PURE__ */ jsx17(
|
|
4705
|
-
"div",
|
|
4706
|
-
{
|
|
4707
|
-
className: "lax-workflow-error",
|
|
4708
|
-
"data-testid": "lax-workflow-error",
|
|
4709
|
-
role: "alert",
|
|
4710
|
-
children: internalErrors[internalErrors.length - 1]?.message ?? "Workflow stream error"
|
|
4711
|
-
}
|
|
4712
|
-
) : null,
|
|
4713
|
-
/* @__PURE__ */ jsx17(
|
|
5077
|
+
/* @__PURE__ */ jsx19(WorkflowSessionBanners, { state: sessionState }),
|
|
5078
|
+
/* @__PURE__ */ jsx19(WorkflowGlobalSpinner, {}),
|
|
5079
|
+
/* @__PURE__ */ jsx19(
|
|
4714
5080
|
WorkflowChrome,
|
|
4715
5081
|
{
|
|
4716
5082
|
containerTree,
|
|
@@ -4720,13 +5086,158 @@ function WorkflowSession({
|
|
|
4720
5086
|
groupParallelTools
|
|
4721
5087
|
}
|
|
4722
5088
|
),
|
|
4723
|
-
/* @__PURE__ */
|
|
5089
|
+
/* @__PURE__ */ jsx19(WorkflowTaskListFooter, {}),
|
|
4724
5090
|
children
|
|
4725
5091
|
]
|
|
4726
5092
|
}
|
|
4727
5093
|
) }) }) }) }) }) }) }) });
|
|
4728
5094
|
}
|
|
4729
5095
|
|
|
5096
|
+
// src/core/workflow/createMockAuthoritySource.ts
|
|
5097
|
+
function defaultDoneSnapshot() {
|
|
5098
|
+
return {
|
|
5099
|
+
taskId: "mock-task",
|
|
5100
|
+
status: "done",
|
|
5101
|
+
updatedAt: Date.now()
|
|
5102
|
+
};
|
|
5103
|
+
}
|
|
5104
|
+
function defaultRunningSnapshot() {
|
|
5105
|
+
return {
|
|
5106
|
+
taskId: "mock-task",
|
|
5107
|
+
status: "running",
|
|
5108
|
+
updatedAt: Date.now()
|
|
5109
|
+
};
|
|
5110
|
+
}
|
|
5111
|
+
function createMockAuthoritySource(snapshotOrOptions) {
|
|
5112
|
+
let snapshot = null;
|
|
5113
|
+
let pendingUpdates = [];
|
|
5114
|
+
if (snapshotOrOptions == null) {
|
|
5115
|
+
snapshot = defaultRunningSnapshot();
|
|
5116
|
+
} else if (typeof snapshotOrOptions === "object" && ("pendingUpdates" in snapshotOrOptions || "snapshot" in snapshotOrOptions) && !("status" in snapshotOrOptions)) {
|
|
5117
|
+
const opts = snapshotOrOptions;
|
|
5118
|
+
snapshot = opts.snapshot ?? defaultDoneSnapshot();
|
|
5119
|
+
pendingUpdates = opts.pendingUpdates ?? [];
|
|
5120
|
+
} else if (snapshotOrOptions === null) {
|
|
5121
|
+
snapshot = null;
|
|
5122
|
+
} else {
|
|
5123
|
+
snapshot = snapshotOrOptions;
|
|
5124
|
+
}
|
|
5125
|
+
return {
|
|
5126
|
+
getSnapshot: () => snapshot,
|
|
5127
|
+
subscribe(cb) {
|
|
5128
|
+
if (snapshot) {
|
|
5129
|
+
cb(snapshot);
|
|
5130
|
+
}
|
|
5131
|
+
for (const update of pendingUpdates) {
|
|
5132
|
+
snapshot = update;
|
|
5133
|
+
cb(update);
|
|
5134
|
+
}
|
|
5135
|
+
return () => {
|
|
5136
|
+
};
|
|
5137
|
+
}
|
|
5138
|
+
};
|
|
5139
|
+
}
|
|
5140
|
+
function createDoneAuthoritySource(taskId = "mock-task") {
|
|
5141
|
+
return createMockAuthoritySource({
|
|
5142
|
+
taskId,
|
|
5143
|
+
status: "done",
|
|
5144
|
+
updatedAt: Date.now()
|
|
5145
|
+
});
|
|
5146
|
+
}
|
|
5147
|
+
function createRunningAuthoritySource(taskId = "mock-task") {
|
|
5148
|
+
return createMockAuthoritySource({
|
|
5149
|
+
taskId,
|
|
5150
|
+
status: "running",
|
|
5151
|
+
updatedAt: Date.now()
|
|
5152
|
+
});
|
|
5153
|
+
}
|
|
5154
|
+
function createControllableAuthoritySource(initial) {
|
|
5155
|
+
let snapshot = initial;
|
|
5156
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5157
|
+
return {
|
|
5158
|
+
getSnapshot: () => snapshot,
|
|
5159
|
+
subscribe(cb) {
|
|
5160
|
+
listeners.add(cb);
|
|
5161
|
+
cb(snapshot);
|
|
5162
|
+
return () => {
|
|
5163
|
+
listeners.delete(cb);
|
|
5164
|
+
};
|
|
5165
|
+
},
|
|
5166
|
+
push(next) {
|
|
5167
|
+
snapshot = next;
|
|
5168
|
+
for (const listener of listeners) {
|
|
5169
|
+
listener(next);
|
|
5170
|
+
}
|
|
5171
|
+
}
|
|
5172
|
+
};
|
|
5173
|
+
}
|
|
5174
|
+
|
|
5175
|
+
// src/core/workflow/createPollingAuthoritySource.ts
|
|
5176
|
+
var DEFAULT_INTERVAL_MS = 2e3;
|
|
5177
|
+
function createPollingAuthoritySource(taskId, fetchFn, options) {
|
|
5178
|
+
let cached = options?.initialSnapshot ?? null;
|
|
5179
|
+
let intervalId;
|
|
5180
|
+
let pollInFlight = false;
|
|
5181
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
5182
|
+
const notify = (snap) => {
|
|
5183
|
+
cached = snap;
|
|
5184
|
+
for (const listener of listeners) {
|
|
5185
|
+
listener(snap);
|
|
5186
|
+
}
|
|
5187
|
+
};
|
|
5188
|
+
const stopPoll = () => {
|
|
5189
|
+
if (intervalId != null) {
|
|
5190
|
+
clearInterval(intervalId);
|
|
5191
|
+
intervalId = void 0;
|
|
5192
|
+
}
|
|
5193
|
+
};
|
|
5194
|
+
const pollOnce = async () => {
|
|
5195
|
+
if (pollInFlight || options?.signal?.aborted) return;
|
|
5196
|
+
pollInFlight = true;
|
|
5197
|
+
try {
|
|
5198
|
+
const snap = await fetchFn(taskId);
|
|
5199
|
+
const prev = cached;
|
|
5200
|
+
if (prev == null || prev.status !== snap.status || prev.updatedAt !== snap.updatedAt) {
|
|
5201
|
+
notify(snap);
|
|
5202
|
+
}
|
|
5203
|
+
if (isAuthorityTerminalStatus(snap.status)) {
|
|
5204
|
+
stopPoll();
|
|
5205
|
+
}
|
|
5206
|
+
} finally {
|
|
5207
|
+
pollInFlight = false;
|
|
5208
|
+
}
|
|
5209
|
+
};
|
|
5210
|
+
const startPoll = () => {
|
|
5211
|
+
if (intervalId != null || options?.signal?.aborted) return;
|
|
5212
|
+
if (cached != null && isAuthorityTerminalStatus(cached.status)) {
|
|
5213
|
+
return;
|
|
5214
|
+
}
|
|
5215
|
+
void pollOnce();
|
|
5216
|
+
intervalId = setInterval(() => {
|
|
5217
|
+
void pollOnce();
|
|
5218
|
+
}, options?.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
5219
|
+
};
|
|
5220
|
+
options?.signal?.addEventListener("abort", stopPoll, { once: true });
|
|
5221
|
+
return {
|
|
5222
|
+
getSnapshot: () => cached,
|
|
5223
|
+
subscribe(cb) {
|
|
5224
|
+
listeners.add(cb);
|
|
5225
|
+
if (cached != null) {
|
|
5226
|
+
cb(cached);
|
|
5227
|
+
}
|
|
5228
|
+
if (cached == null || !isAuthorityTerminalStatus(cached.status)) {
|
|
5229
|
+
startPoll();
|
|
5230
|
+
}
|
|
5231
|
+
return () => {
|
|
5232
|
+
listeners.delete(cb);
|
|
5233
|
+
if (listeners.size === 0) {
|
|
5234
|
+
stopPoll();
|
|
5235
|
+
}
|
|
5236
|
+
};
|
|
5237
|
+
}
|
|
5238
|
+
};
|
|
5239
|
+
}
|
|
5240
|
+
|
|
4730
5241
|
// src/view/tools/groupParallelTools.ts
|
|
4731
5242
|
function buildTimelineEntries(rootIds, byId, options = {}) {
|
|
4732
5243
|
const filtered = options.hideStandalonePermissions ? rootIds.filter((id) => byId[id]?.kind !== "permission") : [...rootIds];
|
|
@@ -4764,18 +5275,18 @@ function buildTimelineEntries(rootIds, byId, options = {}) {
|
|
|
4764
5275
|
}
|
|
4765
5276
|
|
|
4766
5277
|
// src/view/nodes/SubAgentNode.tsx
|
|
4767
|
-
import { jsx as
|
|
5278
|
+
import { jsx as jsx20, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
4768
5279
|
function SubAgentBlock({ nodeId }) {
|
|
4769
5280
|
const node = useNodeTyped(nodeId, "subagent");
|
|
4770
5281
|
const childIds = useChildren(nodeId);
|
|
4771
5282
|
const registry = useNodeRegistry();
|
|
4772
5283
|
if (!node) return null;
|
|
4773
|
-
return /* @__PURE__ */
|
|
4774
|
-
/* @__PURE__ */
|
|
5284
|
+
return /* @__PURE__ */ jsxs15("div", { className: "lax-subagent-block", "data-status": node.status, children: [
|
|
5285
|
+
/* @__PURE__ */ jsxs15("div", { className: "lax-subagent-block__header", children: [
|
|
4775
5286
|
"SubAgent: ",
|
|
4776
5287
|
node.subagentId
|
|
4777
5288
|
] }),
|
|
4778
|
-
/* @__PURE__ */
|
|
5289
|
+
/* @__PURE__ */ jsx20("div", { className: "lax-subagent-block__children", children: childIds.map((childId) => /* @__PURE__ */ jsx20(TimelineItem, { nodeId: childId, registry }, childId)) })
|
|
4779
5290
|
] });
|
|
4780
5291
|
}
|
|
4781
5292
|
|
|
@@ -4894,6 +5405,7 @@ export {
|
|
|
4894
5405
|
WorkflowTaskListFooter,
|
|
4895
5406
|
Write,
|
|
4896
5407
|
WriteToolBody,
|
|
5408
|
+
applyAuthoritySnapshotToState,
|
|
4897
5409
|
buildBashBodyBlocks,
|
|
4898
5410
|
buildCanonicalFromTree,
|
|
4899
5411
|
buildProjectionContext,
|
|
@@ -4909,21 +5421,27 @@ export {
|
|
|
4909
5421
|
configurePlantumlServer,
|
|
4910
5422
|
createActiveSessionBridge,
|
|
4911
5423
|
createAgentxSseSource,
|
|
5424
|
+
createControllableAuthoritySource,
|
|
4912
5425
|
createDefaultRegistry,
|
|
4913
5426
|
createDefaultToolRegistry,
|
|
5427
|
+
createDoneAuthoritySource,
|
|
4914
5428
|
createEmptyTree,
|
|
4915
5429
|
createEmptyWorkflowSessionState,
|
|
4916
5430
|
createInteractionBus,
|
|
5431
|
+
createMockAuthoritySource,
|
|
4917
5432
|
createMockSource,
|
|
4918
5433
|
createMultiSessionStore,
|
|
5434
|
+
createPollingAuthoritySource,
|
|
4919
5435
|
createProjectionContext,
|
|
4920
5436
|
createReplaySource,
|
|
5437
|
+
createRunningAuthoritySource,
|
|
4921
5438
|
createSessionStore,
|
|
4922
5439
|
createWorkflowSessionStore,
|
|
4923
5440
|
deriveLoopSessionIdFromAgentEvent,
|
|
4924
5441
|
displayPath,
|
|
4925
5442
|
entryKey,
|
|
4926
5443
|
filterAgentLoopReplayEvents,
|
|
5444
|
+
finalizeWorkflowDisplayOnStreamEnded,
|
|
4927
5445
|
fixDiagramSvg,
|
|
4928
5446
|
formatAgentTitle,
|
|
4929
5447
|
formatDiffFromStrings,
|
|
@@ -4936,9 +5454,14 @@ export {
|
|
|
4936
5454
|
formatTimeoutFooter,
|
|
4937
5455
|
formatToolTitle,
|
|
4938
5456
|
getChildIds,
|
|
5457
|
+
getDisplayProjectionStatus,
|
|
4939
5458
|
getMainStageIds,
|
|
4940
5459
|
getNoopInteractionBus,
|
|
5460
|
+
hydrateWorkflowFromSnapshot,
|
|
4941
5461
|
isAgentLoopReplayEventType,
|
|
5462
|
+
isAtOrBeforeProjectionCursor,
|
|
5463
|
+
isAuthorityTerminal,
|
|
5464
|
+
isAuthorityTerminalStatus,
|
|
4942
5465
|
isGitOperationCommand,
|
|
4943
5466
|
isGroupableToolName,
|
|
4944
5467
|
isMcpToolName,
|
|
@@ -4962,8 +5485,10 @@ export {
|
|
|
4962
5485
|
resolveShellProgressFromPayload,
|
|
4963
5486
|
resolveSseTransportPolicy,
|
|
4964
5487
|
resolveToolBody,
|
|
5488
|
+
resolveWorkflowBanner,
|
|
4965
5489
|
shouldApplyGrouping,
|
|
4966
5490
|
shouldShowExploreDetail,
|
|
5491
|
+
shouldShowGlobalSpinner,
|
|
4967
5492
|
shouldShowTaskListFooter,
|
|
4968
5493
|
streamChunk,
|
|
4969
5494
|
truncateCommand,
|