@alpaca-editor/core 1.0.4124 → 1.0.4128
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/AgentCostDisplay.js +3 -1
- package/dist/editor/ai/AgentCostDisplay.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +349 -21
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +31 -10
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +6 -0
- package/dist/editor/ai/ToolCallDisplay.js +118 -14
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/ai/types.d.ts +5 -0
- package/dist/editor/services/agentService.d.ts +16 -0
- package/dist/editor/services/agentService.js +39 -11
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/ui/Splitter.js +72 -2
- package/dist/editor/ui/Splitter.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +25 -0
- package/package.json +1 -1
- package/src/editor/ai/AgentCostDisplay.tsx +3 -1
- package/src/editor/ai/AgentTerminal.tsx +494 -19
- package/src/editor/ai/ContextInfoBar.tsx +83 -58
- package/src/editor/ai/ToolCallDisplay.tsx +193 -11
- package/src/editor/ai/types.ts +6 -0
- package/src/editor/services/agentService.ts +69 -11
- package/src/editor/ui/Splitter.tsx +88 -2
- package/src/revision.ts +2 -2
|
@@ -26,7 +26,9 @@ export function AgentCostDisplay({ className = "", response, totalTokens, }) {
|
|
|
26
26
|
// Calculate estimated cost based on typical pricing (rough estimates)
|
|
27
27
|
// Claude 3.5 Sonnet pricing: ~$3/MTok input, ~$15/MTok output
|
|
28
28
|
const calculateEstimatedCost = (inputTokens, outputTokens, cachedTokens) => {
|
|
29
|
-
|
|
29
|
+
// Cached tokens are a subset of input tokens, not additional tokens
|
|
30
|
+
const freshInputTokens = inputTokens - cachedTokens;
|
|
31
|
+
const inputCost = (freshInputTokens / 1000000) * 3; // $3 per million tokens
|
|
30
32
|
const outputCost = (outputTokens / 1000000) * 15; // $15 per million tokens
|
|
31
33
|
const cachedCost = (cachedTokens / 1000000) * 0.3; // Cached tokens are typically much cheaper
|
|
32
34
|
return {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"AgentCostDisplay.js","sourceRoot":"","sources":["../../../src/editor/ai/AgentCostDisplay.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAC;;AAEb,OAAO,EAAe,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AACjE,OAAO,EACL,OAAO,EACP,cAAc,EACd,cAAc,GACf,MAAM,6BAA6B,CAAC;AACrC,OAAO,EAAE,iBAAiB,EAAE,MAAM,4BAA4B,CAAC;AA6B/D,MAAM,UAAU,gBAAgB,CAAC,EAC/B,SAAS,GAAG,EAAE,EACd,QAAQ,EACR,WAAW,GACW;IACtB,MAAM,CAAC,eAAe,EAAE,kBAAkB,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC;IAC9D,MAAM,cAAc,GAAG,MAAM,CAAiB,IAAI,CAAC,CAAC;IACpD,MAAM,cAAc,GAAG,iBAAiB,EAAE,CAAC;IAC3C,MAAM,QAAQ,GAAG,cAAc,EAAE,QAAQ,IAAI,KAAK,CAAC;IAEnD,wCAAwC;IACxC,SAAS,CAAC,GAAG,EAAE;QACb,SAAS,kBAAkB,CAAC,KAAiB;YAC3C,IACE,cAAc,CAAC,OAAO;gBACtB,CAAC,cAAc,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,MAAc,CAAC,EACtD,CAAC;gBACD,kBAAkB,CAAC,KAAK,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC;QAED,IAAI,eAAe,EAAE,CAAC;YACpB,QAAQ,CAAC,gBAAgB,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YACvD,OAAO,GAAG,EAAE;gBACV,QAAQ,CAAC,mBAAmB,CAAC,OAAO,EAAE,kBAAkB,CAAC,CAAC;YAC5D,CAAC,CAAC;QACJ,CAAC;IACH,CAAC,EAAE,CAAC,eAAe,CAAC,CAAC,CAAC;IAEtB,sEAAsE;IACtE,8DAA8D;IAC9D,MAAM,sBAAsB,GAAG,CAC7B,WAAmB,EACnB,YAAoB,EACpB,YAAoB,EACpB,EAAE;QACF,MAAM,SAAS,GAAG,CAAC,
|
|
1
|
+
{"version":3,"file":"AgentCostDisplay.js","sourceRoot":"","sources":["../../../src/editor/ai/AgentCostDisplay.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
-
import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, } from "react";
|
|
3
|
-
import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, } from "lucide-react";
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, useMemo, } from "react";
|
|
3
|
+
import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, } from "lucide-react";
|
|
4
4
|
import { DancingDots } from "./DancingDots";
|
|
5
5
|
import { getAgent, startAgent, connectToAgentStream, updateAgentMetadata, updateAgentSettings, updateAgentCostLimit, } from "../services/agentService";
|
|
6
6
|
import { useEditContext, useFieldsEditContext } from "../client/editContext";
|
|
@@ -18,6 +18,115 @@ import { Tooltip, TooltipTrigger, TooltipContent, } from "../../components/ui/to
|
|
|
18
18
|
const UserMessage = ({ message }) => {
|
|
19
19
|
return (_jsxs("div", { className: "flex gap-3 p-4", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(User, { className: "h-6 w-6 text-blue-600", strokeWidth: 1 }) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-medium text-gray-900", children: "You" }), message.createdDate && (_jsx("span", { className: "text-xs text-gray-400", children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose-sm max-w-none text-xs text-gray-700 select-text", children: message.content })] })] }));
|
|
20
20
|
};
|
|
21
|
+
const extractTodosFromMessages = (messages) => {
|
|
22
|
+
const todos = [];
|
|
23
|
+
const fencedTodoToken = "```todo_list";
|
|
24
|
+
const plainTodoToken = "todo_list";
|
|
25
|
+
for (const message of messages) {
|
|
26
|
+
if (message.role !== "assistant" || !message.content)
|
|
27
|
+
continue;
|
|
28
|
+
const content = message.content;
|
|
29
|
+
let cursor = 0;
|
|
30
|
+
while (cursor < content.length) {
|
|
31
|
+
const nextFenced = content.indexOf(fencedTodoToken, cursor);
|
|
32
|
+
const nextPlain = content.indexOf(plainTodoToken, cursor);
|
|
33
|
+
let todoStart = -1;
|
|
34
|
+
let isFenced = false;
|
|
35
|
+
if (nextFenced !== -1 && (nextPlain === -1 || nextFenced < nextPlain)) {
|
|
36
|
+
todoStart = nextFenced;
|
|
37
|
+
isFenced = true;
|
|
38
|
+
}
|
|
39
|
+
else if (nextPlain !== -1) {
|
|
40
|
+
// Check if it's at line start
|
|
41
|
+
const before = nextPlain > 0 ? content[nextPlain - 1] : "\n";
|
|
42
|
+
if (before === "\n" || before === "\r" || nextPlain === 0) {
|
|
43
|
+
todoStart = nextPlain;
|
|
44
|
+
isFenced = false;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (todoStart === -1)
|
|
48
|
+
break;
|
|
49
|
+
try {
|
|
50
|
+
let jsonText = "";
|
|
51
|
+
if (isFenced) {
|
|
52
|
+
const afterToken = todoStart + fencedTodoToken.length;
|
|
53
|
+
const closePos = content.indexOf("```", afterToken);
|
|
54
|
+
if (closePos === -1)
|
|
55
|
+
break;
|
|
56
|
+
jsonText = content.slice(afterToken, closePos).trim();
|
|
57
|
+
cursor = closePos + 3;
|
|
58
|
+
}
|
|
59
|
+
else {
|
|
60
|
+
const afterToken = todoStart + plainTodoToken.length;
|
|
61
|
+
const braceStart = content.indexOf("{", afterToken);
|
|
62
|
+
if (braceStart === -1)
|
|
63
|
+
break;
|
|
64
|
+
let depth = 0;
|
|
65
|
+
let braceEnd = -1;
|
|
66
|
+
for (let i = braceStart; i < content.length; i++) {
|
|
67
|
+
if (content[i] === "{")
|
|
68
|
+
depth++;
|
|
69
|
+
if (content[i] === "}") {
|
|
70
|
+
depth--;
|
|
71
|
+
if (depth === 0) {
|
|
72
|
+
braceEnd = i;
|
|
73
|
+
break;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
if (braceEnd === -1)
|
|
78
|
+
break;
|
|
79
|
+
jsonText = content.slice(braceStart, braceEnd + 1).trim();
|
|
80
|
+
cursor = braceEnd + 1;
|
|
81
|
+
}
|
|
82
|
+
const parsed = JSON.parse(jsonText);
|
|
83
|
+
const todoItems = Array.isArray(parsed) ? parsed : parsed?.items || [];
|
|
84
|
+
const title = Array.isArray(parsed) ? undefined : parsed?.title;
|
|
85
|
+
todoItems.forEach((item) => {
|
|
86
|
+
if (!item)
|
|
87
|
+
return;
|
|
88
|
+
const text = item.text || item.label || String(item.task || item.title || "");
|
|
89
|
+
if (!text)
|
|
90
|
+
return;
|
|
91
|
+
todos.push({
|
|
92
|
+
id: item.id,
|
|
93
|
+
text,
|
|
94
|
+
done: !!(item.done ?? item.completed ?? item.checked),
|
|
95
|
+
note: item.note || item.description,
|
|
96
|
+
messageId: message.id,
|
|
97
|
+
sourceTitle: title,
|
|
98
|
+
});
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
catch (e) {
|
|
102
|
+
cursor++;
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return todos;
|
|
108
|
+
};
|
|
109
|
+
// TodoListPanel component
|
|
110
|
+
const TodoListPanel = ({ messages }) => {
|
|
111
|
+
const [isExpanded, setIsExpanded] = useState(true);
|
|
112
|
+
const todos = useMemo(() => extractTodosFromMessages(messages), [messages]);
|
|
113
|
+
// Check if there's an active streaming message with todo content
|
|
114
|
+
const isUpdating = useMemo(() => {
|
|
115
|
+
return messages.some((msg) => {
|
|
116
|
+
if (msg.role !== "assistant" || msg.isCompleted)
|
|
117
|
+
return false;
|
|
118
|
+
const content = msg.content || "";
|
|
119
|
+
return content.includes("```todo_list") || content.includes("todo_list");
|
|
120
|
+
});
|
|
121
|
+
}, [messages]);
|
|
122
|
+
if (todos.length === 0 && !isUpdating)
|
|
123
|
+
return null;
|
|
124
|
+
const completedCount = todos.filter((t) => t.done).length;
|
|
125
|
+
const totalCount = todos.length;
|
|
126
|
+
return (_jsxs("div", { className: "border-t border-gray-200 bg-gray-50", children: [_jsxs("button", { onClick: () => setIsExpanded(!isExpanded), className: "flex w-full cursor-pointer items-center justify-between px-4 py-2 text-left transition-colors hover:bg-gray-100", children: [_jsxs("div", { className: "flex items-center gap-2", children: [_jsx(ListTodo, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }), _jsx("span", { className: "text-xs font-medium text-gray-700", children: "Todo List" }), isUpdating ? (_jsxs("span", { className: "flex items-center gap-1 text-xs text-blue-600", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), "Updating..."] })) : (_jsxs("span", { className: "text-xs text-gray-500", children: [completedCount, "/", totalCount, " completed"] }))] }), isExpanded ? (_jsx(ChevronUp, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 })) : (_jsx(ChevronDown, { className: "h-4 w-4 text-gray-500", strokeWidth: 1 }))] }), isExpanded && (_jsx("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: isUpdating && todos.length === 0 ? (_jsxs("div", { className: "flex items-center justify-center gap-2 py-4 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", strokeWidth: 1 }), _jsx("span", { children: "Loading todo list..." })] })) : (_jsxs(_Fragment, { children: [_jsx("div", { className: "space-y-1.5", children: todos.map((todo, idx) => (_jsxs("div", { className: "flex items-start gap-2 rounded bg-white p-2 text-xs", children: [_jsx("div", { className: "flex-shrink-0 pt-0.5", children: todo.done ? (_jsx("div", { className: "flex h-4 w-4 items-center justify-center rounded border-2 border-green-500 bg-green-500", children: _jsx("svg", { className: "h-3 w-3 text-white", fill: "none", strokeWidth: 2, stroke: "currentColor", viewBox: "0 0 24 24", children: _jsx("path", { strokeLinecap: "round", strokeLinejoin: "round", d: "M5 13l4 4L19 7" }) }) })) : (_jsx("div", { className: "h-4 w-4 rounded border-2 border-gray-300" })) }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: `${todo.done
|
|
127
|
+
? "text-gray-500 line-through"
|
|
128
|
+
: "text-gray-900"}`, children: todo.text }), todo.note && (_jsx("div", { className: "mt-0.5 text-xs text-gray-500", children: todo.note }))] })] }, todo.id || `${todo.messageId}-${idx}`))) }), isUpdating && todos.length > 0 && (_jsxs("div", { className: "mt-2 flex items-center gap-2 rounded bg-blue-50 px-3 py-2 text-xs text-blue-700", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), _jsx("span", { children: "Updating todo list..." })] }))] })) }))] }));
|
|
129
|
+
};
|
|
21
130
|
const groupConsecutiveMessages = (agentMessages) => {
|
|
22
131
|
// Work directly with the messages array - streaming messages are identified by their properties
|
|
23
132
|
const allMessages = agentMessages;
|
|
@@ -93,6 +202,8 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
|
|
|
93
202
|
result: toolCall.functionResult,
|
|
94
203
|
error: toolCall.functionError,
|
|
95
204
|
},
|
|
205
|
+
// Pass through approval info if present on the tool call
|
|
206
|
+
requiresApproval: toolCall.requiresApproval,
|
|
96
207
|
}))
|
|
97
208
|
: [],
|
|
98
209
|
};
|
|
@@ -515,6 +626,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
515
626
|
isCompleted: false,
|
|
516
627
|
responseTimeMs: message.data.responseTimeMs,
|
|
517
628
|
createdDate: new Date().toISOString(),
|
|
629
|
+
requiresApproval: message.data?.requiresApproval,
|
|
518
630
|
};
|
|
519
631
|
// Check for duplicates using the current messages ref
|
|
520
632
|
const currentMessages = messagesRef.current;
|
|
@@ -623,6 +735,18 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
623
735
|
messagesRef.current = updated;
|
|
624
736
|
return updated;
|
|
625
737
|
});
|
|
738
|
+
// Dispatch a local event so the UI can attempt reconnect when approvals get resolved while paused
|
|
739
|
+
try {
|
|
740
|
+
const ev = new CustomEvent("agent:toolApprovalResolved", {
|
|
741
|
+
detail: {
|
|
742
|
+
messageId: resultMessageId,
|
|
743
|
+
toolCallId: resultToolCallId,
|
|
744
|
+
approved: !(message.data?.functionError || message.data?.error),
|
|
745
|
+
},
|
|
746
|
+
});
|
|
747
|
+
window.dispatchEvent(ev);
|
|
748
|
+
}
|
|
749
|
+
catch { }
|
|
626
750
|
// Tool result activity; reset idle timer
|
|
627
751
|
resetDotsTimer();
|
|
628
752
|
}, [resetDotsTimer]);
|
|
@@ -640,7 +764,15 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
640
764
|
try {
|
|
641
765
|
setIsConnecting(true);
|
|
642
766
|
console.log("🔌 connectToStream: Starting stream connection");
|
|
767
|
+
// Expose agent id globally for approval actions
|
|
768
|
+
window.currentAgentId = currentAgent.id;
|
|
769
|
+
console.log("🔗 Setting currentAgentId:", currentAgent.id);
|
|
770
|
+
console.log("🌐 Attempting to connect to agent stream for:", currentAgent.id);
|
|
643
771
|
await connectToAgentStream(currentAgent.id, (message) => {
|
|
772
|
+
console.log("📨 Received stream message:", {
|
|
773
|
+
type: message.type,
|
|
774
|
+
data: message.data,
|
|
775
|
+
});
|
|
644
776
|
switch (message.type) {
|
|
645
777
|
case "contentChunk":
|
|
646
778
|
handleContentChunk(message, currentAgent);
|
|
@@ -654,6 +786,49 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
654
786
|
case "statusUpdate":
|
|
655
787
|
try {
|
|
656
788
|
const kind = message?.data?.kind;
|
|
789
|
+
console.log("📡 Received status update:", {
|
|
790
|
+
kind,
|
|
791
|
+
data: message.data,
|
|
792
|
+
});
|
|
793
|
+
if (kind === "toolApprovalsRequired") {
|
|
794
|
+
const data = message.data || {};
|
|
795
|
+
const msgId = data.messageId;
|
|
796
|
+
const ids = data.toolCallIds || [];
|
|
797
|
+
console.log("⏸️ Approvals required; pausing stream until approval:", { msgId, ids });
|
|
798
|
+
// Annotate tool calls with a temporary pending marker so UI can reflect paused state on reload
|
|
799
|
+
if (msgId && Array.isArray(ids) && ids.length > 0) {
|
|
800
|
+
setMessages((prev) => {
|
|
801
|
+
const updated = prev.map((m) => {
|
|
802
|
+
if (m.id !== msgId)
|
|
803
|
+
return m;
|
|
804
|
+
const existingToolCalls = m.toolCalls || [];
|
|
805
|
+
const updatedToolCalls = existingToolCalls.map((tc) => {
|
|
806
|
+
if (!ids.includes(tc.toolCallId))
|
|
807
|
+
return tc;
|
|
808
|
+
const fn = tc.functionName || "";
|
|
809
|
+
return {
|
|
810
|
+
...tc,
|
|
811
|
+
functionName: fn.includes("(pending approval)")
|
|
812
|
+
? fn
|
|
813
|
+
: fn + " (pending approval)",
|
|
814
|
+
};
|
|
815
|
+
});
|
|
816
|
+
return { ...m, toolCalls: updatedToolCalls };
|
|
817
|
+
});
|
|
818
|
+
messagesRef.current = updated;
|
|
819
|
+
return updated;
|
|
820
|
+
});
|
|
821
|
+
}
|
|
822
|
+
// Proactively stop the current stream so that the page can be reloaded safely or stay idle until approval
|
|
823
|
+
try {
|
|
824
|
+
abortControllerRef.current?.abort();
|
|
825
|
+
abortControllerRef.current = null;
|
|
826
|
+
setIsConnecting(false);
|
|
827
|
+
setIsWaitingForResponse(false);
|
|
828
|
+
}
|
|
829
|
+
catch { }
|
|
830
|
+
break;
|
|
831
|
+
}
|
|
657
832
|
if (kind === "contextWindow") {
|
|
658
833
|
const data = message.data || {};
|
|
659
834
|
// Store last context window status in a ref so we can render it below
|
|
@@ -675,8 +850,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
675
850
|
// Merge incoming context into local metadata
|
|
676
851
|
setAgentMetadata((prev) => {
|
|
677
852
|
const current = (prev || {});
|
|
853
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
854
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
678
855
|
const next = {
|
|
679
|
-
...
|
|
856
|
+
...currentWithoutContext,
|
|
680
857
|
additionalData: {
|
|
681
858
|
...(current.additionalData || {}),
|
|
682
859
|
context: nextContext,
|
|
@@ -717,6 +894,55 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
717
894
|
}
|
|
718
895
|
});
|
|
719
896
|
}
|
|
897
|
+
else if (kind === "toolApprovalGranted" ||
|
|
898
|
+
kind === "toolApprovalRejected") {
|
|
899
|
+
const data = message.data || {};
|
|
900
|
+
const toolCallId = data.toolCallId;
|
|
901
|
+
const msgId = data.messageId;
|
|
902
|
+
console.log("🔧 Processing tool approval:", {
|
|
903
|
+
kind,
|
|
904
|
+
toolCallId,
|
|
905
|
+
msgId,
|
|
906
|
+
data,
|
|
907
|
+
});
|
|
908
|
+
if (toolCallId && msgId) {
|
|
909
|
+
setMessages((prev) => {
|
|
910
|
+
console.log("🔍 Looking for message:", {
|
|
911
|
+
targetMsgId: msgId,
|
|
912
|
+
availableMessages: prev.map((m) => ({
|
|
913
|
+
id: m.id,
|
|
914
|
+
toolCallsCount: m.toolCalls?.length || 0,
|
|
915
|
+
})),
|
|
916
|
+
});
|
|
917
|
+
const updated = prev.map((m) => {
|
|
918
|
+
if (m.id !== msgId)
|
|
919
|
+
return m;
|
|
920
|
+
const existingToolCalls = m.toolCalls || [];
|
|
921
|
+
const updatedToolCalls = existingToolCalls.map((tc) => {
|
|
922
|
+
if (tc.toolCallId !== toolCallId)
|
|
923
|
+
return tc;
|
|
924
|
+
const suffix = kind === "toolApprovalGranted"
|
|
925
|
+
? " (approved)"
|
|
926
|
+
: " (rejected)";
|
|
927
|
+
const newFunctionName = (tc.functionName || "") + suffix;
|
|
928
|
+
console.log("🏷️ Updating function name:", {
|
|
929
|
+
toolCallId,
|
|
930
|
+
oldName: tc.functionName,
|
|
931
|
+
newName: newFunctionName,
|
|
932
|
+
});
|
|
933
|
+
return {
|
|
934
|
+
...tc,
|
|
935
|
+
functionName: newFunctionName,
|
|
936
|
+
};
|
|
937
|
+
});
|
|
938
|
+
return { ...m, toolCalls: updatedToolCalls };
|
|
939
|
+
});
|
|
940
|
+
messagesRef.current = updated;
|
|
941
|
+
return updated;
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
break;
|
|
945
|
+
}
|
|
720
946
|
}
|
|
721
947
|
catch { }
|
|
722
948
|
break;
|
|
@@ -875,16 +1101,93 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
875
1101
|
}
|
|
876
1102
|
}
|
|
877
1103
|
finally {
|
|
1104
|
+
console.log("🔌 Stream connection finished, cleaning up");
|
|
878
1105
|
setIsConnecting(false);
|
|
879
1106
|
// Guard: clear waiting state if connection finished without content
|
|
880
1107
|
setIsWaitingForResponse(false);
|
|
881
1108
|
}
|
|
882
1109
|
}, [agent?.id, handleContentChunk, handleToolCall, handleToolResult]);
|
|
1110
|
+
// Attempt to reconnect stream when all pending approvals are resolved
|
|
1111
|
+
const attemptReconnectIfNoPending = useCallback(async () => {
|
|
1112
|
+
try {
|
|
1113
|
+
const currentAgent = agent;
|
|
1114
|
+
if (!currentAgent)
|
|
1115
|
+
return;
|
|
1116
|
+
// Check if we're already connected
|
|
1117
|
+
if (abortControllerRef.current) {
|
|
1118
|
+
console.log("🔄 Already connected to stream, skipping reconnect");
|
|
1119
|
+
return;
|
|
1120
|
+
}
|
|
1121
|
+
const msgs = messagesRef.current || [];
|
|
1122
|
+
const hasPending = msgs.some((m) => (m.toolCalls || []).some((tc) => (tc.functionName || "").includes("(pending approval)")));
|
|
1123
|
+
if (!hasPending) {
|
|
1124
|
+
console.log("🔄 No pending approvals; reconnecting stream");
|
|
1125
|
+
await connectToStream(currentAgent);
|
|
1126
|
+
}
|
|
1127
|
+
else {
|
|
1128
|
+
console.log("⏸️ Still have pending approvals, not reconnecting yet");
|
|
1129
|
+
}
|
|
1130
|
+
}
|
|
1131
|
+
catch (err) {
|
|
1132
|
+
console.error("❌ Error attempting reconnect:", err);
|
|
1133
|
+
}
|
|
1134
|
+
}, [agent, connectToStream]);
|
|
1135
|
+
// Listen for local approval resolution (when stream is paused) to update UI and reconnect
|
|
1136
|
+
useEffect(() => {
|
|
1137
|
+
const onApprovalResolved = (ev) => {
|
|
1138
|
+
try {
|
|
1139
|
+
const detail = ev?.detail || {};
|
|
1140
|
+
const messageId = detail.messageId;
|
|
1141
|
+
const toolCallId = detail.toolCallId;
|
|
1142
|
+
const approved = !!detail.approved;
|
|
1143
|
+
if (!messageId || !toolCallId)
|
|
1144
|
+
return;
|
|
1145
|
+
console.log("🔔 Approval resolved:", {
|
|
1146
|
+
messageId,
|
|
1147
|
+
toolCallId,
|
|
1148
|
+
approved,
|
|
1149
|
+
});
|
|
1150
|
+
setMessages((prev) => {
|
|
1151
|
+
const updated = prev.map((m) => {
|
|
1152
|
+
if (m.id !== messageId)
|
|
1153
|
+
return m;
|
|
1154
|
+
const updatedToolCalls = (m.toolCalls || []).map((tc) => {
|
|
1155
|
+
if (tc.toolCallId !== toolCallId)
|
|
1156
|
+
return tc;
|
|
1157
|
+
const base = (tc.functionName || "")
|
|
1158
|
+
.replace(" (pending approval)", "")
|
|
1159
|
+
.replace(" (approved)", "")
|
|
1160
|
+
.replace(" (rejected)", "");
|
|
1161
|
+
return {
|
|
1162
|
+
...tc,
|
|
1163
|
+
functionName: base + (approved ? " (approved)" : " (rejected)"),
|
|
1164
|
+
};
|
|
1165
|
+
});
|
|
1166
|
+
return { ...m, toolCalls: updatedToolCalls };
|
|
1167
|
+
});
|
|
1168
|
+
messagesRef.current = updated;
|
|
1169
|
+
return updated;
|
|
1170
|
+
});
|
|
1171
|
+
// Try to reconnect if no more pending approvals remain
|
|
1172
|
+
setTimeout(() => {
|
|
1173
|
+
attemptReconnectIfNoPending();
|
|
1174
|
+
}, 100);
|
|
1175
|
+
}
|
|
1176
|
+
catch (err) {
|
|
1177
|
+
console.error("❌ Error handling approval resolution:", err);
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
window.addEventListener("agent:toolApprovalResolved", onApprovalResolved);
|
|
1181
|
+
return () => window.removeEventListener("agent:toolApprovalResolved", onApprovalResolved);
|
|
1182
|
+
}, [attemptReconnectIfNoPending]);
|
|
883
1183
|
// Load agent data and messages
|
|
884
1184
|
const loadAgent = useCallback(async () => {
|
|
885
1185
|
try {
|
|
886
1186
|
if (agentStub.status === "new") {
|
|
887
|
-
console.log("✅ Setting up new agent");
|
|
1187
|
+
console.log("✅ Setting up new agent", agentStub.id);
|
|
1188
|
+
// Set agent ID immediately for new agents
|
|
1189
|
+
window.currentAgentId = agentStub.id;
|
|
1190
|
+
console.log("🔗 Setting currentAgentId for new agent:", agentStub.id);
|
|
888
1191
|
// Derive initial profile from provided metadata if present
|
|
889
1192
|
const initialProfileIdFromMeta = (() => {
|
|
890
1193
|
try {
|
|
@@ -1064,12 +1367,21 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1064
1367
|
const agentData = await getAgent(agentStub.id);
|
|
1065
1368
|
setAgent(agentData);
|
|
1066
1369
|
setMessages(agentData.messages || []);
|
|
1370
|
+
// Set agent ID for existing agents too
|
|
1371
|
+
window.currentAgentId = agentData.id;
|
|
1372
|
+
console.log("🔗 Setting currentAgentId for existing agent:", agentData.id);
|
|
1067
1373
|
// Parse metadata from DB if present (do not seed for existing agents)
|
|
1068
1374
|
const parsedMeta = (() => {
|
|
1069
1375
|
try {
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1376
|
+
if (!agentData.metadata)
|
|
1377
|
+
return null;
|
|
1378
|
+
const meta = JSON.parse(agentData.metadata);
|
|
1379
|
+
// Clean up: remove top-level context if present (should only be in additionalData)
|
|
1380
|
+
if (meta && meta.context) {
|
|
1381
|
+
const { context: _, ...cleanMeta } = meta;
|
|
1382
|
+
return cleanMeta;
|
|
1383
|
+
}
|
|
1384
|
+
return meta;
|
|
1073
1385
|
}
|
|
1074
1386
|
catch {
|
|
1075
1387
|
return null;
|
|
@@ -1094,6 +1406,16 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1094
1406
|
}
|
|
1095
1407
|
// Reset streaming state for reconnection
|
|
1096
1408
|
shouldCreateNewMessage.current = false;
|
|
1409
|
+
// If there are pending approvals in current messages, skip reconnect for now
|
|
1410
|
+
try {
|
|
1411
|
+
const hasPending = (agentData.messages || []).some((m) => (m.toolCalls || []).some((tc) => typeof tc?.functionName === "string" &&
|
|
1412
|
+
tc.functionName.includes("(pending approval)")));
|
|
1413
|
+
if (hasPending) {
|
|
1414
|
+
console.log("⏸️ loadAgent: Pending approvals detected, delaying stream reconnect");
|
|
1415
|
+
return;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
catch { }
|
|
1097
1419
|
// Use the existing connectToStream function with the loaded agent data
|
|
1098
1420
|
await connectToStream(agentData);
|
|
1099
1421
|
}, 100);
|
|
@@ -1230,12 +1552,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1230
1552
|
scrollToBottom();
|
|
1231
1553
|
}
|
|
1232
1554
|
}, [messages, scrollToBottom, shouldAutoScroll]);
|
|
1233
|
-
// Re-apply bottom alignment when loading dots appear/disappear, as it changes the content height
|
|
1234
|
-
useEffect(() => {
|
|
1235
|
-
if (shouldAutoScroll) {
|
|
1236
|
-
scrollToBottom();
|
|
1237
|
-
}
|
|
1238
|
-
}, [showDots, shouldAutoScroll, scrollToBottom]);
|
|
1239
1555
|
// Persist any pending settings (mode/model) once an agent exists server-side
|
|
1240
1556
|
const persistPendingSettingsIfNeeded = useCallback(async () => {
|
|
1241
1557
|
try {
|
|
@@ -1521,8 +1837,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1521
1837
|
if (!agent?.id)
|
|
1522
1838
|
return;
|
|
1523
1839
|
const current = agentMetadata || {};
|
|
1840
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
1841
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1524
1842
|
const next = {
|
|
1525
|
-
...
|
|
1843
|
+
...currentWithoutContext,
|
|
1526
1844
|
additionalData: {
|
|
1527
1845
|
...(current.additionalData || {}),
|
|
1528
1846
|
context: {
|
|
@@ -1589,8 +1907,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1589
1907
|
if (existingPageIds.has(`${pageToAdd.id}-${pageToAdd.language}-${pageToAdd.version}`)) {
|
|
1590
1908
|
return; // Page already exists
|
|
1591
1909
|
}
|
|
1910
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
1911
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1592
1912
|
const next = {
|
|
1593
|
-
...
|
|
1913
|
+
...currentWithoutContext,
|
|
1594
1914
|
additionalData: {
|
|
1595
1915
|
...(current.additionalData || {}),
|
|
1596
1916
|
context: {
|
|
@@ -1625,8 +1945,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1625
1945
|
const newComponentIds = editContext.selection.filter((id) => !existingIds.has(id));
|
|
1626
1946
|
if (newComponentIds.length === 0)
|
|
1627
1947
|
return; // No new components to add
|
|
1948
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
1949
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1628
1950
|
const next = {
|
|
1629
|
-
...
|
|
1951
|
+
...currentWithoutContext,
|
|
1630
1952
|
additionalData: {
|
|
1631
1953
|
...(current.additionalData || {}),
|
|
1632
1954
|
context: {
|
|
@@ -1661,8 +1983,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1661
1983
|
const newComponentIds = ids.filter((id) => !!id && !existingIds.has(id));
|
|
1662
1984
|
if (newComponentIds.length === 0)
|
|
1663
1985
|
return;
|
|
1986
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
1987
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1664
1988
|
const next = {
|
|
1665
|
-
...
|
|
1989
|
+
...currentWithoutContext,
|
|
1666
1990
|
additionalData: {
|
|
1667
1991
|
...(current.additionalData || {}),
|
|
1668
1992
|
context: {
|
|
@@ -1702,8 +2026,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1702
2026
|
.filter((p) => !existingPageIds.has(`${p.id}-${p.language}-${p.version}`));
|
|
1703
2027
|
if (pagesToAdd.length === 0)
|
|
1704
2028
|
return;
|
|
2029
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2030
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1705
2031
|
const next = {
|
|
1706
|
-
...
|
|
2032
|
+
...currentWithoutContext,
|
|
1707
2033
|
additionalData: {
|
|
1708
2034
|
...(current.additionalData || {}),
|
|
1709
2035
|
context: {
|
|
@@ -1802,8 +2128,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
1802
2128
|
return undefined;
|
|
1803
2129
|
})();
|
|
1804
2130
|
const current = agentMetadata || {};
|
|
2131
|
+
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2132
|
+
const { context: _, ...currentWithoutContext } = current;
|
|
1805
2133
|
const next = {
|
|
1806
|
-
...
|
|
2134
|
+
...currentWithoutContext,
|
|
1807
2135
|
additionalData: {
|
|
1808
2136
|
...(current.additionalData || {}),
|
|
1809
2137
|
context: {
|
|
@@ -2038,7 +2366,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
|
|
|
2038
2366
|
sendQuickMessage(text);
|
|
2039
2367
|
} }, groupIndex));
|
|
2040
2368
|
}
|
|
2041
|
-
}) }), showDots
|
|
2369
|
+
}) }), _jsx("div", { className: showDots ? "visible" : "invisible", children: _jsx(DancingDots, {}) }), _jsx("div", { ref: messagesEndRef })] }), renderContextInfoBar(), _jsx(TodoListPanel, { messages: messages }), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [_jsx("div", { className: "flex items-stretch gap-2", children: _jsx(Textarea, { ref: textareaRef, value: prompt, onChange: (e) => {
|
|
2042
2370
|
setPrompt(e.target.value);
|
|
2043
2371
|
// Reset history index when user starts typing
|
|
2044
2372
|
if (currentHistoryIndex !== -1) {
|