@parhelia/core 0.1.12737 → 0.1.12744
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/editor/ai/AgentTerminal.js +122 -22
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/AgentTerminalStatusBar.js +62 -7
- package/dist/editor/ai/AgentTerminalStatusBar.js.map +1 -1
- package/dist/editor/ai/InlineAiDialog.js +6 -2
- package/dist/editor/ai/InlineAiDialog.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.js +15 -8
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/agentDiagnostics.d.ts +8 -1
- package/dist/editor/ai/agentDiagnostics.js +48 -1
- package/dist/editor/ai/agentDiagnostics.js.map +1 -1
- package/dist/editor/client/EditorShell.d.ts +5 -0
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.d.ts +5 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js +60 -2
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js +1 -2
- package/dist/editor/menubar/toolbar-sections/UtilityControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js +3 -2
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
- package/dist/editor/settings/WebSocketMessages.js +6 -3
- package/dist/editor/settings/WebSocketMessages.js.map +1 -1
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js +27 -8
- package/dist/editor/settings/panels/ProjectTemplatesPanel.js.map +1 -1
- package/dist/editor/sidebar/ComponentTree.js +37 -15
- package/dist/editor/sidebar/ComponentTree.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/task-board/components/ProjectDashboard.d.ts +11 -0
- package/dist/task-board/components/ProjectDashboard.js +87 -59
- package/dist/task-board/components/ProjectDashboard.js.map +1 -1
- package/package.json +1 -1
|
@@ -33,6 +33,7 @@ import { Splitter } from "../ui/Splitter";
|
|
|
33
33
|
import { ScrollingContentTree } from "../ScrollingContentTree";
|
|
34
34
|
import { MarkdownDisplay, } from "../../components/MarkdownDisplay";
|
|
35
35
|
const AGENT_HISTORY_LIMIT = 1000;
|
|
36
|
+
const RECENT_RUN_EVENTS_LIMIT = 50;
|
|
36
37
|
function mergeAgentOperationHistory(existing, incoming, limit = AGENT_HISTORY_LIMIT) {
|
|
37
38
|
const merged = new Map(existing.map((operation) => [operation.id, operation]));
|
|
38
39
|
for (const operation of incoming) {
|
|
@@ -1004,16 +1005,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1004
1005
|
return current.some((m) => !m.isCompleted && m.messageType === "streaming");
|
|
1005
1006
|
}, []);
|
|
1006
1007
|
const currentAgentId = agent?.id || agentStub.id;
|
|
1007
|
-
const
|
|
1008
|
+
const currentRunDiagnostics = useMemo(() => {
|
|
1008
1009
|
const normalizedAgentId = normalizeDialogAgentId(currentAgentId);
|
|
1009
|
-
if (!normalizedAgentId) {
|
|
1010
|
-
return [];
|
|
1010
|
+
if (!normalizedAgentId || !editContext) {
|
|
1011
|
+
return { events: [], totalCount: 0, receivedSeqs: [], missingSeqs: [] };
|
|
1011
1012
|
}
|
|
1012
|
-
|
|
1013
|
-
return [];
|
|
1014
|
-
}
|
|
1015
|
-
return (editContext.webSocketMessages || [])
|
|
1016
|
-
.filter((message) => {
|
|
1013
|
+
const agentRunMessages = (editContext.webSocketMessages || []).filter((message) => {
|
|
1017
1014
|
if (!message?.type?.startsWith("agent:run:")) {
|
|
1018
1015
|
return false;
|
|
1019
1016
|
}
|
|
@@ -1021,15 +1018,51 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1021
1018
|
return false;
|
|
1022
1019
|
}
|
|
1023
1020
|
return getAgentRunMessageAgentId(message.payload) === normalizedAgentId;
|
|
1024
|
-
})
|
|
1025
|
-
|
|
1021
|
+
});
|
|
1022
|
+
let runStartIndex = 0;
|
|
1023
|
+
for (let i = agentRunMessages.length - 1; i >= 0; i--) {
|
|
1024
|
+
if (agentRunMessages[i]?.type === "agent:run:start") {
|
|
1025
|
+
runStartIndex = i;
|
|
1026
|
+
break;
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
const currentRunMessages = agentRunMessages.slice(runStartIndex);
|
|
1030
|
+
const seqsSet = new Set();
|
|
1031
|
+
for (const message of currentRunMessages) {
|
|
1032
|
+
const seq = message.seq ?? getAgentRunMessageSeq(message.payload);
|
|
1033
|
+
if (typeof seq === "number" && seq > 0) {
|
|
1034
|
+
seqsSet.add(seq);
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
const receivedSeqs = [...seqsSet].sort((a, b) => a - b);
|
|
1038
|
+
const missingSeqs = [];
|
|
1039
|
+
const max = receivedSeqs[receivedSeqs.length - 1];
|
|
1040
|
+
if (max !== undefined) {
|
|
1041
|
+
for (let i = 1; i <= max; i++) {
|
|
1042
|
+
if (!seqsSet.has(i))
|
|
1043
|
+
missingSeqs.push(i);
|
|
1044
|
+
}
|
|
1045
|
+
}
|
|
1046
|
+
const events = currentRunMessages
|
|
1047
|
+
.slice(-RECENT_RUN_EVENTS_LIMIT)
|
|
1026
1048
|
.map((message) => ({
|
|
1027
1049
|
timestamp: message.timestamp,
|
|
1050
|
+
direction: message.direction ?? "incoming",
|
|
1028
1051
|
type: message.type,
|
|
1029
|
-
seq: getAgentRunMessageSeq(message.payload),
|
|
1030
|
-
detail:
|
|
1052
|
+
seq: message.seq ?? getAgentRunMessageSeq(message.payload),
|
|
1053
|
+
detail: message.detail ??
|
|
1054
|
+
getAgentRunMessageDetail(message.type, message.payload),
|
|
1055
|
+
rawMessage: message.rawMessage,
|
|
1056
|
+
payloadBytes: message.payloadBytes ?? null,
|
|
1031
1057
|
}));
|
|
1058
|
+
return {
|
|
1059
|
+
events,
|
|
1060
|
+
totalCount: currentRunMessages.length,
|
|
1061
|
+
receivedSeqs,
|
|
1062
|
+
missingSeqs,
|
|
1063
|
+
};
|
|
1032
1064
|
}, [currentAgentId, editContext?.webSocketMessages]);
|
|
1065
|
+
const recentAgentRunEvents = currentRunDiagnostics.events;
|
|
1033
1066
|
const appendToolUiEvent = useCallback((type, detail, seq) => {
|
|
1034
1067
|
const timestamp = new Date().toISOString();
|
|
1035
1068
|
setRecentToolUiEvents((prev) => {
|
|
@@ -1834,6 +1867,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1834
1867
|
const lastSeqRef = useRef(0);
|
|
1835
1868
|
const subscribedAgentIdRef = useRef(null);
|
|
1836
1869
|
const reconcileServerStateInFlightRef = useRef(false);
|
|
1870
|
+
const streamRecoveryInFlightRef = useRef(false);
|
|
1871
|
+
const lastStreamRecoveryAtRef = useRef(0);
|
|
1837
1872
|
const toolCallFirstSeenAtRef = useRef({});
|
|
1838
1873
|
const pendingToolCompletionTimersRef = useRef({});
|
|
1839
1874
|
// Cache mode/model/profile changes made while the agent is still "new" (not yet persisted)
|
|
@@ -2193,7 +2228,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2193
2228
|
const settleCompletedRun = useCallback((finalStatus = "completed") => {
|
|
2194
2229
|
clearStopGuard();
|
|
2195
2230
|
setError(null);
|
|
2196
|
-
lastSeqRef
|
|
2231
|
+
// Keep lastSeqRef populated so the diagnostic popover can show the
|
|
2232
|
+
// last observed seq after the run finishes. The next agent:run:start
|
|
2233
|
+
// resets it for the new run.
|
|
2197
2234
|
setLastRunStatusReason(null);
|
|
2198
2235
|
clearHeartbeatMessages();
|
|
2199
2236
|
setMessages((prev) => {
|
|
@@ -3921,8 +3958,9 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3921
3958
|
"AI could not complete this request.";
|
|
3922
3959
|
clearHeartbeatMessages();
|
|
3923
3960
|
setLastRunStatusReason(null);
|
|
3924
|
-
//
|
|
3925
|
-
|
|
3961
|
+
// Keep lastSeqRef populated so the diagnostic popover can show the
|
|
3962
|
+
// last observed seq after the error. The next agent:run:start resets
|
|
3963
|
+
// it for the new run.
|
|
3926
3964
|
setError(errorMsg);
|
|
3927
3965
|
// Update agent status to error
|
|
3928
3966
|
setAgent((prev) => prev ? { ...prev, status: "error", statusMessage: errorMsg } : prev);
|
|
@@ -3961,10 +3999,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3961
3999
|
if (subscribedAgentIdRef.current) {
|
|
3962
4000
|
const socket = globalThis.editorSocket;
|
|
3963
4001
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
3964
|
-
|
|
4002
|
+
const payload = {
|
|
3965
4003
|
type: "agent:unsubscribe",
|
|
3966
4004
|
agentId: subscribedAgentIdRef.current,
|
|
3967
|
-
}
|
|
4005
|
+
};
|
|
4006
|
+
console.debug("[AgentWebSocket] sent", payload);
|
|
4007
|
+
socket.send(JSON.stringify(payload));
|
|
3968
4008
|
}
|
|
3969
4009
|
subscribedAgentIdRef.current = null;
|
|
3970
4010
|
}
|
|
@@ -3973,10 +4013,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
3973
4013
|
// Send subscription message to server
|
|
3974
4014
|
const socket = globalThis.editorSocket;
|
|
3975
4015
|
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
3976
|
-
|
|
4016
|
+
const payload = {
|
|
3977
4017
|
type: "agent:subscribe",
|
|
3978
4018
|
agentId: agentStub.id,
|
|
3979
|
-
}
|
|
4019
|
+
};
|
|
4020
|
+
console.debug("[AgentWebSocket] sent", payload);
|
|
4021
|
+
socket.send(JSON.stringify(payload));
|
|
3980
4022
|
}
|
|
3981
4023
|
// Use the addSocketMessageListener helper from editContext
|
|
3982
4024
|
// Wrap the handler in a stable function that uses the ref
|
|
@@ -4021,10 +4063,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
4021
4063
|
if (socket &&
|
|
4022
4064
|
socket.readyState === WebSocket.OPEN &&
|
|
4023
4065
|
subscribedAgentIdRef.current) {
|
|
4024
|
-
|
|
4066
|
+
const payload = {
|
|
4025
4067
|
type: "agent:unsubscribe",
|
|
4026
4068
|
agentId: subscribedAgentIdRef.current,
|
|
4027
|
-
}
|
|
4069
|
+
};
|
|
4070
|
+
console.debug("[AgentWebSocket] sent", payload);
|
|
4071
|
+
socket.send(JSON.stringify(payload));
|
|
4028
4072
|
}
|
|
4029
4073
|
unsubscribe();
|
|
4030
4074
|
subscribedAgentIdRef.current = null;
|
|
@@ -5443,6 +5487,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5443
5487
|
const assistantGroupCount = useMemo(() => groupConsecutiveMessages(messages).filter((group) => group.type === "assistant-group").length, [messages]);
|
|
5444
5488
|
const runDiagnosticsSnapshot = useMemo(() => {
|
|
5445
5489
|
const lastEvent = recentAgentRunEvents[recentAgentRunEvents.length - 1];
|
|
5490
|
+
const { receivedSeqs, missingSeqs, totalCount } = currentRunDiagnostics;
|
|
5491
|
+
const observedMaxSeq = receivedSeqs[receivedSeqs.length - 1] ?? 0;
|
|
5446
5492
|
return {
|
|
5447
5493
|
agentId: currentAgentId,
|
|
5448
5494
|
isSubmitting,
|
|
@@ -5455,10 +5501,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5455
5501
|
hasActiveStreaming: hasActiveStreaming(),
|
|
5456
5502
|
isSubscribed: normalizeDialogAgentId(subscribedAgentIdRef.current) ===
|
|
5457
5503
|
normalizeDialogAgentId(currentAgentId),
|
|
5458
|
-
lastSeq: lastSeqRef.current,
|
|
5504
|
+
lastSeq: Math.max(lastSeqRef.current, observedMaxSeq),
|
|
5459
5505
|
lastEventType: lastEvent?.type ?? null,
|
|
5460
5506
|
lastEventAt: lastEvent?.timestamp ?? null,
|
|
5461
5507
|
recentEvents: recentAgentRunEvents,
|
|
5508
|
+
currentRunReceivedSeqs: receivedSeqs,
|
|
5509
|
+
currentRunMissingSeqs: missingSeqs,
|
|
5510
|
+
currentRunTotalEventCount: totalCount,
|
|
5462
5511
|
assistantMessageCount,
|
|
5463
5512
|
assistantGroupCount,
|
|
5464
5513
|
assistantGroupsWithRenderableToolCalls,
|
|
@@ -5472,6 +5521,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5472
5521
|
assistantGroupsWithRenderableToolCalls,
|
|
5473
5522
|
assistantMessageCount,
|
|
5474
5523
|
currentAgentId,
|
|
5524
|
+
currentRunDiagnostics,
|
|
5475
5525
|
hasActiveStreaming,
|
|
5476
5526
|
incompleteToolCallCount,
|
|
5477
5527
|
isAgentThinking,
|
|
@@ -5502,10 +5552,58 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5502
5552
|
settleCompletedRun(normalizeServerExecutionStatus(serverStatus) === "cancelled"
|
|
5503
5553
|
? "cancelled"
|
|
5504
5554
|
: "completed");
|
|
5555
|
+
return;
|
|
5556
|
+
}
|
|
5557
|
+
const serverLastSeq = diagnostics.currentSession?.lastDelivery?.lastSeq ??
|
|
5558
|
+
diagnostics.transport?.lastSeq ??
|
|
5559
|
+
null;
|
|
5560
|
+
const serverLastSuccessAt = diagnostics.currentSession?.lastDelivery?.lastSuccessAt ??
|
|
5561
|
+
diagnostics.transport?.lastBroadcastAt ??
|
|
5562
|
+
diagnostics.transport?.lastProducedAt ??
|
|
5563
|
+
null;
|
|
5564
|
+
const serverLastSuccessTime = serverLastSuccessAt
|
|
5565
|
+
? Date.parse(serverLastSuccessAt)
|
|
5566
|
+
: Number.NaN;
|
|
5567
|
+
const now = Date.now();
|
|
5568
|
+
const serverDeliveryOldEnough = Number.isFinite(serverLastSuccessTime) &&
|
|
5569
|
+
now - serverLastSuccessTime > 8_000;
|
|
5570
|
+
const recoveryCooldownElapsed = now - lastStreamRecoveryAtRef.current > 30_000;
|
|
5571
|
+
const localLastSeq = lastSeqRef.current;
|
|
5572
|
+
if (diagnostics.currentSession?.isConnected &&
|
|
5573
|
+
diagnostics.currentSession?.isSubscribed &&
|
|
5574
|
+
typeof serverLastSeq === "number" &&
|
|
5575
|
+
serverLastSeq > localLastSeq &&
|
|
5576
|
+
serverDeliveryOldEnough &&
|
|
5577
|
+
recoveryCooldownElapsed &&
|
|
5578
|
+
!streamRecoveryInFlightRef.current) {
|
|
5579
|
+
streamRecoveryInFlightRef.current = true;
|
|
5580
|
+
lastStreamRecoveryAtRef.current = now;
|
|
5581
|
+
appendToolUiEvent("ui:stream-recovery", `server seq ${serverLastSeq} is ahead of local seq ${localLastSeq}; reconnecting socket`, serverLastSeq);
|
|
5582
|
+
try {
|
|
5583
|
+
await loadAgent();
|
|
5584
|
+
}
|
|
5585
|
+
catch (loadError) {
|
|
5586
|
+
console.warn("[AgentTerminal] Failed to reload agent during stream recovery", loadError);
|
|
5587
|
+
}
|
|
5588
|
+
try {
|
|
5589
|
+
const socket = globalThis.editorSocket;
|
|
5590
|
+
if (socket && socket.readyState === WebSocket.OPEN) {
|
|
5591
|
+
socket.close(4000, "agent-stream-lag");
|
|
5592
|
+
}
|
|
5593
|
+
}
|
|
5594
|
+
catch (socketError) {
|
|
5595
|
+
console.warn("[AgentTerminal] Failed to reconnect stale agent stream socket", socketError);
|
|
5596
|
+
}
|
|
5597
|
+
finally {
|
|
5598
|
+
window.setTimeout(() => {
|
|
5599
|
+
streamRecoveryInFlightRef.current = false;
|
|
5600
|
+
}, 5_000);
|
|
5601
|
+
}
|
|
5505
5602
|
}
|
|
5506
5603
|
}
|
|
5507
5604
|
catch (error) {
|
|
5508
5605
|
console.warn("[AgentTerminal] Failed to reconcile agent run status", error);
|
|
5606
|
+
streamRecoveryInFlightRef.current = false;
|
|
5509
5607
|
}
|
|
5510
5608
|
};
|
|
5511
5609
|
// Avoid racing a freshly submitted run before the backend has registered it.
|
|
@@ -5522,6 +5620,8 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
5522
5620
|
editContext?.socketConnectionVersion,
|
|
5523
5621
|
isActive,
|
|
5524
5622
|
isExecuting,
|
|
5623
|
+
appendToolUiEvent,
|
|
5624
|
+
loadAgent,
|
|
5525
5625
|
settleCompletedRun,
|
|
5526
5626
|
]);
|
|
5527
5627
|
const showInitialThinkingSplash = messages.length === 0 &&
|