@parhelia/core 0.1.11141 → 0.1.11147

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.
@@ -45,7 +45,7 @@ const UserMessage = ({ message }) => {
45
45
  message.sourceAgent?.name;
46
46
  }
47
47
  const displayName = sourceAgentName ? `[From ${sourceAgentName}]` : "You";
48
- 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: displayName }), message.createdDate && (_jsx("span", { className: "text-xs text-gray-400", "data-testid": "user-message-timestamp", "data-timestamp": message.createdDate, children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose-sm max-w-none text-xs text-gray-700 select-text", children: displayContent })] })] }));
48
+ 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-[11px] font-medium text-gray-900", children: displayName }), message.createdDate && (_jsx("span", { className: "text-[11px] text-gray-400", "data-testid": "user-message-timestamp", "data-timestamp": message.createdDate, children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose max-w-none text-[11px] text-gray-700 select-text", children: displayContent })] })] }));
49
49
  };
50
50
  // Helper to extract todos from potentially incomplete JSON during streaming
51
51
  const extractPartialTodos = (jsonText) => {
@@ -378,9 +378,9 @@ const TodoListPanel = ({ messages, agentMetadata, }) => {
378
378
  return null;
379
379
  const completedCount = todos.filter((t) => t.done).length;
380
380
  const totalCount = todos.length;
381
- 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 && (_jsxs("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: [todos.length > 0 && (_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
381
+ 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-[11px] font-medium text-gray-700", children: "Todo List" }), isUpdating ? (_jsxs("span", { className: "flex items-center gap-1 text-[11px] text-blue-600", children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), "Updating..."] })) : (_jsxs("span", { className: "text-[11px] 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 && (_jsxs("div", { className: "max-h-64 overflow-y-auto px-4 pb-3", children: [todos.length > 0 && (_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-[11px]", 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
382
382
  ? "text-gray-500 line-through"
383
- : "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 && (_jsxs("div", { className: `flex items-center gap-2 rounded px-3 py-2 text-xs ${todos.length > 0
383
+ : "text-gray-900"}`, children: todo.text }), todo.note && (_jsx("div", { className: "mt-0.5 text-[11px] text-gray-500", children: todo.note }))] })] }, todo.id || `${todo.messageId}-${idx}`))) })), isUpdating && (_jsxs("div", { className: `flex items-center gap-2 rounded px-3 py-2 text-[11px] ${todos.length > 0
384
384
  ? "mt-2 bg-blue-50 text-blue-700"
385
385
  : "justify-center bg-white text-gray-500"}`, children: [_jsx(Loader2, { className: "h-3 w-3 animate-spin", strokeWidth: 1 }), _jsx("span", { children: todos.length > 0
386
386
  ? "Updating todo list..."
@@ -683,6 +683,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
683
683
  const messagesEndRef = useRef(null);
684
684
  const textareaRef = useRef(null);
685
685
  const placeholderInputRef = useRef(null);
686
+ const promptPlaceholderInputRef = useRef(null);
686
687
  const messagesContainerRef = useRef(null);
687
688
  const [shouldAutoScroll, setShouldAutoScroll] = useState(true);
688
689
  // WebSocket subscription state for agent streaming
@@ -1248,7 +1249,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
1248
1249
  toolCallId,
1249
1250
  approved,
1250
1251
  });
1251
- console.log("[AgentTerminal] Current message IDs:", messagesRef.current.map((m) => m.id));
1252
1252
  if (!messageId || !toolCallId)
1253
1253
  return;
1254
1254
  // Update local state to reflect approval status
@@ -2304,6 +2304,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2304
2304
  console.warn("[AgentTerminal] handleSubmit blocked: already submitting");
2305
2305
  return;
2306
2306
  }
2307
+ // Block submission while there is a pending tool call approval decision
2308
+ if (hasPendingApprovals()) {
2309
+ console.warn("[AgentTerminal] handleSubmit blocked: pending tool call approval");
2310
+ return;
2311
+ }
2307
2312
  if (!editContext) {
2308
2313
  console.error("[AgentTerminal] handleSubmit blocked: editContext is undefined");
2309
2314
  setError("Editor context not available. Please refresh the page.");
@@ -2314,6 +2319,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2314
2319
  placeholderInputRef.current?.submit();
2315
2320
  return;
2316
2321
  }
2322
+ // If prompt contains placeholders, delegate to the prompt placeholder input's submit method
2323
+ if (prompt && /\{\{[^{}]+\}\}|<<[^<>]+>>/.test(prompt) && allPlaceholdersFilled) {
2324
+ promptPlaceholderInputRef.current?.submit();
2325
+ return;
2326
+ }
2317
2327
  // Save the prompt text before any state changes
2318
2328
  const savedPrompt = prompt.trim();
2319
2329
  // Check if agent is new - allow empty prompts for new agents to trigger greeting
@@ -2534,6 +2544,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
2534
2544
  console.warn("[AgentTerminal] sendQuickMessage blocked: already submitting");
2535
2545
  return;
2536
2546
  }
2547
+ // Block submission while there is a pending tool call approval decision
2548
+ if (hasPendingApprovals()) {
2549
+ console.warn("[AgentTerminal] sendQuickMessage blocked: pending tool call approval");
2550
+ return;
2551
+ }
2537
2552
  if (!editContext) {
2538
2553
  console.error("[AgentTerminal] sendQuickMessage blocked: editContext is undefined");
2539
2554
  setError("Editor context not available. Please refresh the page.");
@@ -3000,14 +3015,14 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3000
3015
  }
3001
3016
  }, [activeProfile, profiles, agent?.profileId]);
3002
3017
  if (isLoading) {
3003
- return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsxs("div", { className: "flex items-center gap-2 text-xs text-gray-500", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", strokeWidth: 1 }), "Loading agent..."] }) }));
3018
+ return (_jsx("div", { className: "flex h-full items-center justify-center", children: _jsxs("div", { className: "flex items-center gap-2 text-[11px] text-gray-500", children: [_jsx(Loader2, { className: "h-4 w-4 animate-spin", strokeWidth: 1 }), "Loading agent..."] }) }));
3004
3019
  }
3005
3020
  const renderContextInfoBar = () => (_jsx(ContextInfoBar, { agent: agent, agentMetadata: agentMetadata, setAgentMetadata: setAgentMetadata, setAgent: setAgent, resolvedPageName: resolvedPageName, resolvedComponentName: resolvedComponentName, resolvedFieldName: resolvedFieldName, isLiveEditorContextMode: isLiveEditorContextMode, activeProfile: activeProfile }));
3006
3021
  const renderCostLimitBanner = () => {
3007
3022
  if (!costLimitExceeded)
3008
3023
  return null;
3009
3024
  const { totalCost, costLimit, initialCostLimit } = costLimitExceeded;
3010
- return (_jsxs("div", { className: "m-3 rounded border border-amber-300 bg-amber-50 p-3 text-xs text-amber-900", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-amber-500", strokeWidth: 1 }), _jsxs("span", { children: ["Cost limit exceeded. Spent $", totalCost.toFixed(2), " / $", costLimit.toFixed(2), "."] })] }), _jsx("div", { className: "flex gap-2", children: _jsx("button", { className: "rounded border border-amber-300 bg-white px-2 py-1 hover:bg-amber-100", onClick: async () => {
3025
+ return (_jsxs("div", { className: "m-3 rounded border border-amber-300 bg-amber-50 p-3 text-[11px] text-amber-900", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx(AlertCircle, { className: "h-4 w-4 text-amber-500", strokeWidth: 1 }), _jsxs("span", { children: ["Cost limit exceeded. Spent $", totalCost.toFixed(2), " / $", costLimit.toFixed(2), "."] })] }), _jsx("div", { className: "flex gap-2", children: _jsx("button", { className: "rounded border border-amber-300 bg-white px-2 py-1 hover:bg-amber-100", onClick: async () => {
3011
3026
  if (!agent?.id)
3012
3027
  return;
3013
3028
  try {
@@ -3039,13 +3054,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3039
3054
  const errorMessage = currentAgent?.statusMessage;
3040
3055
  if (!isErrorStatus || !errorMessage)
3041
3056
  return null;
3042
- return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-xs text-red-900", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-red-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Agent Error" }), _jsx("div", { className: "text-red-800", children: errorMessage })] })] }) }));
3057
+ return (_jsx("div", { className: "m-3 rounded border border-red-300 bg-red-50 p-3 text-[11px] text-red-900", children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsx(AlertCircle, { className: "mt-0.5 h-4 w-4 flex-shrink-0 text-red-500", strokeWidth: 1 }), _jsxs("div", { className: "flex-1", children: [_jsx("div", { className: "mb-1 font-semibold", children: "Agent Error" }), _jsx("div", { className: "text-red-800", children: errorMessage })] })] }) }));
3043
3058
  };
3044
- return (_jsxs("div", { className: `flex h-full flex-col ${className || ""}`, children: [_jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error && (_jsx("div", { className: "m-4 rounded-lg border-l-4 border-red-500 bg-red-50 p-3 select-text", children: _jsxs("div", { className: "flex items-start", children: [_jsx(AlertCircle, { className: "mt-0.5 h-5 w-5 text-red-400", strokeWidth: 1 }), _jsxs("div", { className: "ml-3", children: [_jsx("p", { className: "text-sm font-medium text-red-800", children: "Error" }), _jsx("p", { className: "mt-1 text-sm text-red-700", children: error })] })] }) })), messages.length === 0 && !error && !hideGreeting && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsx("div", { className: "max-w-prose text-center", children: !activeProfile ? (_jsx(Loader2, { className: "mx-auto h-8 w-8 animate-spin text-gray-400" })) : (_jsxs(_Fragment, { children: [activeProfile.svgIcon ? (_jsx("div", { className: "mx-auto mb-4 flex h-24 w-24 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
3059
+ return (_jsxs("div", { className: `flex h-full flex-col ${className || ""}`, children: [_jsxs("div", { ref: messagesContainerRef, className: "flex-1 overflow-y-auto", onScroll: handleScroll, children: [error && (_jsx("div", { className: "m-4 rounded-lg border-l-4 border-red-500 bg-red-50 p-3 select-text", children: _jsxs("div", { className: "flex items-start", children: [_jsx(AlertCircle, { className: "mt-0.5 h-5 w-5 text-red-400", strokeWidth: 1 }), _jsxs("div", { className: "ml-3", children: [_jsx("p", { className: "text-[11px] font-medium text-red-800", children: "Error" }), _jsx("p", { className: "mt-1 text-[11px] text-red-700", children: error })] })] }) })), messages.length === 0 && !error && !hideGreeting && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsx("div", { className: "max-w-prose text-center", children: !activeProfile ? (_jsx(Loader2, { className: "mx-auto h-8 w-8 animate-spin text-gray-400" })) : (_jsxs(_Fragment, { children: [activeProfile.svgIcon ? (_jsx("div", { className: "mx-auto mb-4 flex h-24 w-24 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
3045
3060
  __html: activeProfile.svgIcon,
3046
- } })) : (_jsx(SecretAgentIcon, { size: 96, strokeWidth: 1, className: "mx-auto mb-4 text-gray-400" })), activeProfile.greetingMessage ? (_jsx(ViewTransition, { children: _jsx("div", { className: "prose prose-sm mx-auto text-center", dangerouslySetInnerHTML: {
3061
+ } })) : (_jsx(SecretAgentIcon, { size: 96, strokeWidth: 1, className: "mx-auto mb-4 text-gray-400" })), activeProfile.greetingMessage ? (_jsx(ViewTransition, { children: _jsx("div", { className: "prose prose mx-auto text-center text-[20px]", dangerouslySetInnerHTML: {
3047
3062
  __html: activeProfile.greetingMessage,
3048
- } }) })) : (_jsxs(_Fragment, { children: [_jsx("h3", { className: "mb-2 text-lg font-medium text-gray-900", children: "Start a conversation" }), _jsx("p", { className: "mb-4 text-sm text-gray-500", children: "Send a message to begin working with your AI agent." }), _jsx("div", { className: "text-xs text-gray-400", children: "Your agent can help with content editing, research, and automation tasks." })] }))] })) }) })), messages.length === 0 &&
3063
+ } }) })) : (_jsxs(_Fragment, { children: [_jsx("h3", { className: "mb-2 text-[11px] font-medium text-gray-900", children: "Start a conversation" }), _jsx("p", { className: "mb-4 text-[11px] text-gray-500", children: "Send a message to begin working with your AI agent." }), _jsx("div", { className: "text-[11px] text-gray-400", children: "Your agent can help with content editing, research, and automation tasks." })] }))] })) }) })), messages.length === 0 &&
3049
3064
  !error &&
3050
3065
  hideGreeting &&
3051
3066
  (isSubmitting || isConnecting) && (_jsx("div", { className: "flex h-full items-center justify-center p-8", children: _jsxs("div", { className: "flex flex-col items-center gap-4", children: [activeProfile?.svgIcon ? (_jsx("div", { className: "flex h-16 w-16 items-center justify-center text-gray-400 [&>svg]:h-full [&>svg]:w-full", dangerouslySetInnerHTML: {
@@ -3125,7 +3140,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3125
3140
  }
3126
3141
  // Content exists - show dots WITHOUT icon (inline at bottom)
3127
3142
  return (_jsxs("div", { className: "flex gap-3 px-4 pb-4", children: [_jsx("div", { className: "w-7 flex-shrink-0" }), _jsx("div", { className: "min-w-0 flex-1", children: _jsxs("div", { className: "flex items-center gap-1", children: [_jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.3s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400 [animation-delay:-0.15s]" }), _jsx("div", { className: "h-1 w-1 animate-bounce rounded-full bg-gray-400" })] }) })] }));
3128
- })(), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && agent?.id && activeProfile && (_jsx(AgentDocumentList, { agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), !hideContext && agent?.id && (_jsx(AgentEditOperationsPanel, { agentId: agent.id })), queuedPrompts.length > 0 && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-xs font-semibold text-amber-900", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "space-y-2", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-xs", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[10px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", children: qp.prompt }), qp.createdDate && (_jsx("div", { className: "mt-1.5 text-[10px] text-gray-400", children: formatTime(new Date(qp.createdDate)) }))] }) }) }, qp.id))) })] }) })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
3143
+ })(), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && agent?.id && activeProfile && (_jsx(AgentDocumentList, { agentId: agent.id, maxFileSizeMB: activeProfile.maxDocumentSizeMB ?? 10, enabled: activeProfile.enableDocumentUpload ?? false, profileId: activeProfile.id }, `${agent.id}-${agent.updatedDate || ""}-${activeProfile.id}`)), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), !hideContext && agent?.id && (_jsx(AgentEditOperationsPanel, { agentId: agent.id })), queuedPrompts.length > 0 && (_jsx("div", { className: "border-t border-gray-200 bg-amber-50/50", children: _jsxs("div", { className: "px-4 pt-3 pb-2", children: [_jsxs("div", { className: "mb-2 flex items-center gap-2", children: [_jsx("div", { className: "h-2 w-2 animate-pulse rounded-full bg-amber-500" }), _jsxs("span", { className: "text-[11px] font-semibold text-amber-900", children: ["Queued Messages (", queuedPrompts.length, ")"] })] }), _jsx("div", { className: "space-y-2", children: queuedPrompts.map((qp) => (_jsx("div", { className: "rounded-md border border-amber-200 bg-white p-2.5 text-[11px]", children: _jsx("div", { className: "flex items-start justify-between gap-2", children: _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "mb-1 flex items-center gap-1.5", children: qp.sourceAgentName ? (_jsxs(_Fragment, { children: [_jsxs("span", { className: "font-medium text-gray-700", children: ["From ", qp.sourceAgentName] }), qp.priority > 5 && (_jsx("span", { className: "rounded bg-red-100 px-1.5 py-0.5 text-[11px] font-medium text-red-700", children: "High Priority" }))] })) : (_jsx("span", { className: "font-medium text-gray-700", children: "From User" })) }), _jsx("div", { className: "break-words whitespace-pre-wrap text-gray-600", children: qp.prompt }), qp.createdDate && (_jsx("div", { className: "mt-1.5 text-[11px] text-gray-400", children: formatTime(new Date(qp.createdDate)) }))] }) }) }, qp.id))) })] }) })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
3129
3144
  // Placeholder Input (from quick actions)
3130
3145
  // Show buttons when hideBottomControls is true (e.g., splash screen) since normal submit area is hidden
3131
3146
  _jsx(PlaceholderInput, { ref: placeholderInputRef, text: activePlaceholderInput.text, showButtons: hideBottomControls, buttonsClassName: hideBottomControls ? "justify-end" : "", onFilledChange: setAllPlaceholdersFilled, onComplete: (filledText) => {
@@ -3157,10 +3172,10 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3157
3172
  }, onCancel: () => {
3158
3173
  setActivePlaceholderInput(null);
3159
3174
  setAllPlaceholdersFilled(false);
3160
- } })) : prompt && /\{([^}]+)\}|<([^>]+)>/.test(prompt) ? (
3175
+ } })) : prompt && /\{\{[^{}]+\}\}|<<[^<>]+>>/.test(prompt) ? (
3161
3176
  // Template mode: show PlaceholderInput when prompt contains placeholders
3162
3177
  // Show buttons when hideBottomControls is true (e.g., splash screen) since normal submit area is hidden
3163
- _jsx(PlaceholderInput, { text: prompt, showButtons: hideBottomControls, buttonsClassName: hideBottomControls ? "justify-end" : "", onFilledChange: setAllPlaceholdersFilled, onComplete: (filledText) => {
3178
+ _jsx(PlaceholderInput, { ref: promptPlaceholderInputRef, text: prompt, showButtons: hideBottomControls, buttonsClassName: hideBottomControls ? "justify-end" : "", onFilledChange: setAllPlaceholdersFilled, onComplete: (filledText) => {
3164
3179
  setPrompt(filledText);
3165
3180
  setAllPlaceholdersFilled(false);
3166
3181
  // Auto-submit after filling placeholders
@@ -3180,7 +3195,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3180
3195
  } })) : (_jsx("div", { className: "flex items-stretch gap-2", children: _jsx(Textarea, { ref: textareaRef, value: prompt, onChange: (e) => {
3181
3196
  setPrompt(e.target.value);
3182
3197
  // Reset placeholder filled state when prompt changes
3183
- if (!/\{([^}]+)\}|<([^>]+)>/.test(e.target.value)) {
3198
+ if (!/\{\{[^{}]+\}\}|<<[^<>]+>>/.test(e.target.value)) {
3184
3199
  setAllPlaceholdersFilled(false);
3185
3200
  }
3186
3201
  // Reset history index when user starts typing
@@ -3191,7 +3206,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3191
3206
  shouldMaintainFocusRef.current = true;
3192
3207
  }, onBlur: () => {
3193
3208
  shouldMaintainFocusRef.current = false;
3194
- }, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-xs", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) })), !hideBottomControls && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-stretch justify-between gap-2", children: [_jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-start gap-2", children: [_jsxs(Tooltip, { delayDuration: 400, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("select", { className: `h-5 rounded border px-1.5 text-[10px] ${mode === "read-only"
3209
+ }, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-[11px]", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) })), !hideBottomControls && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "flex items-stretch justify-between gap-2", children: [_jsxs("div", { className: "mt-2 flex flex-wrap items-center justify-start gap-2", children: [_jsxs(Tooltip, { delayDuration: 400, children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("select", { className: `h-5 rounded border px-1.5 text-[11px] ${mode === "read-only"
3195
3210
  ? "border-green-300 bg-green-50 text-green-700"
3196
3211
  : mode === "supervised"
3197
3212
  ? "border-amber-300 bg-amber-50 text-amber-700"
@@ -3225,7 +3240,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3225
3240
  catch (e2) {
3226
3241
  console.error("Failed to persist mode change", e2);
3227
3242
  }
3228
- }, title: "Mode", "aria-label": "Mode", "data-testid": "agent-mode-select", children: [_jsx("option", { value: "supervised", children: "Supervised" }), _jsx("option", { value: "autonomous", children: "Autonomous" }), _jsx("option", { value: "read-only", children: "Read-Only" })] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold text-green-500", children: "Read-Only" }), ": Limited tool access as configured by the profile (Ask Mode Tools)."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-amber-500", children: "Supervised" }), ": Full tool access, but writes are limited to pages/items in the current context. Creating new items or updating existing items outside the current context requires explicit approval."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-red-500", children: "Autonomous" }), ": Full tool access; can write across the site/project only limited by user permissions."] })] }) })] }), profiles?.length > 0 && (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: activeProfile?.id || "", onChange: async (e) => {
3243
+ }, title: "Mode", "aria-label": "Mode", "data-testid": "agent-mode-select", children: [_jsx("option", { value: "supervised", children: "Supervised" }), _jsx("option", { value: "autonomous", children: "Autonomous" }), _jsx("option", { value: "read-only", children: "Read-Only" })] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold text-green-500", children: "Read-Only" }), ": Limited tool access as configured by the profile (Ask Mode Tools)."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-amber-500", children: "Supervised" }), ": Full tool access, but writes are limited to pages/items in the current context. Creating new items or updating existing items outside the current context requires explicit approval."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold text-red-500", children: "Autonomous" }), ": Full tool access; can write across the site/project only limited by user permissions."] })] }) })] }), profiles?.length > 0 && (_jsx("select", { className: "h-5 rounded border px-1.5 text-[11px] text-gray-500", value: activeProfile?.id || "", onChange: async (e) => {
3229
3244
  const nextProfile = profiles.find((x) => x.id === e.target.value);
3230
3245
  if (!nextProfile)
3231
3246
  return;
@@ -3274,7 +3289,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3274
3289
  catch (err) {
3275
3290
  console.error("Failed to persist agent profile", err);
3276
3291
  }
3277
- }, title: "Profile", "aria-label": "Profile", "data-testid": "agent-profile-select", children: profiles.map((p) => (_jsx("option", { value: p.id, children: p.name }, p.id))) })), activeProfile?.models?.length ? (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: selectedModelId || "", onChange: async (e) => {
3292
+ }, title: "Profile", "aria-label": "Profile", "data-testid": "agent-profile-select", children: profiles.map((p) => (_jsx("option", { value: p.id, children: p.name }, p.id))) })), activeProfile?.models?.length ? (_jsx("select", { className: "h-5 rounded border px-1.5 text-[11px] text-gray-500", value: selectedModelId || "", onChange: async (e) => {
3278
3293
  const nextId = e.target.value;
3279
3294
  setSelectedModelId(nextId);
3280
3295
  const modelName = activeProfile?.models?.find((m) => m.id === nextId)
@@ -3298,17 +3313,22 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3298
3313
  catch (err) {
3299
3314
  console.error("Failed to persist agent model", err);
3300
3315
  }
3301
- }, title: "Model", "aria-label": "Model", "data-testid": "agent-model-select", children: activeProfile.models.map((m) => (_jsx("option", { value: m.id, children: m.name }, m.id))) })) : null, activeProfile?.prompts?.length ? (_jsxs(Popover, { open: showPredefined, onOpenChange: setShowPredefined, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "rounded p-1 hover:bg-gray-100", onClick: () => { }, title: "Predefined prompts", "aria-label": "Predefined prompts", children: _jsx(Wand2, { className: "h-3 w-3", strokeWidth: 1 }) }) }), _jsx(PopoverContent, { className: "w-64 p-0", align: "start", children: _jsx("div", { className: "max-h-56 overflow-y-auto p-2", children: activeProfile.prompts.map((p, index) => (_jsx("div", { className: "cursor-pointer rounded p-1.5 text-xs text-gray-700 hover:bg-gray-100", onClick: () => {
3316
+ }, title: "Model", "aria-label": "Model", "data-testid": "agent-model-select", children: activeProfile.models.map((m) => (_jsx("option", { value: m.id, children: m.name }, m.id))) })) : null, activeProfile?.prompts?.length ? (_jsxs(Popover, { open: showPredefined, onOpenChange: setShowPredefined, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "rounded p-1 hover:bg-gray-100", onClick: () => { }, title: "Predefined prompts", "aria-label": "Predefined prompts", children: _jsx(Wand2, { className: "h-3 w-3", strokeWidth: 1 }) }) }), _jsx(PopoverContent, { className: "w-64 p-0", align: "start", children: _jsx("div", { className: "max-h-56 overflow-y-auto p-2", children: activeProfile.prompts.map((p, index) => (_jsx("div", { className: "cursor-pointer rounded p-1.5 text-[11px] text-gray-700 hover:bg-gray-100", onClick: () => {
3302
3317
  setPrompt(p.prompt);
3303
3318
  setShowPredefined(false);
3304
3319
  if (textareaRef.current)
3305
3320
  textareaRef.current.focus();
3306
3321
  }, children: p.title }, index))) }) })] })) : null] }), _jsxs("div", { className: "flex items-center gap-1 self-end", children: [isVoiceSupported ? (_jsx(Button, { onClick: toggleVoice, size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isListening ? "Stop voice input" : "Start voice input", "aria-label": isListening ? "Stop voice input" : "Start voice input", "aria-pressed": isListening, children: isListening ? (_jsx(MicOff, { className: "size-3", strokeWidth: 1 })) : (_jsx(Mic, { className: "size-3", strokeWidth: 1 })) })) : null, _jsx(Button, { onClick: isExecuting ? handleStop : handleSubmit, disabled: !isExecuting &&
3307
- ((!prompt.trim() && !activePlaceholderInput) ||
3322
+ (allPendingApprovals.length > 0 ||
3323
+ (!prompt.trim() && !activePlaceholderInput) ||
3308
3324
  (!!prompt &&
3309
- /\{([^}]+)\}|<([^>]+)>/.test(prompt) &&
3325
+ /\{\{[^{}]+\}\}|<<[^<>]+>>/.test(prompt) &&
3310
3326
  !allPlaceholdersFilled) ||
3311
- (!!activePlaceholderInput && !allPlaceholdersFilled)), size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isExecuting ? "Stop" : "Send", "aria-label": isExecuting ? "Stop" : "Send", "data-testid": "agent-send-stop-button", "data-executing": isExecuting ? "true" : "false", children: isExecuting ? (_jsx(Square, { className: "size-3", strokeWidth: 1 })) : (_jsx(Send, { className: "size-3", strokeWidth: 1 })) })] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-gray-500", children: [agent?.id &&
3327
+ (!!activePlaceholderInput && !allPlaceholdersFilled)), size: "sm", className: "h-5.5 w-5.5 cursor-pointer rounded-full", title: isExecuting
3328
+ ? "Stop"
3329
+ : allPendingApprovals.length > 0
3330
+ ? "Approve or reject pending tool calls first"
3331
+ : "Send", "aria-label": isExecuting ? "Stop" : "Send", "data-testid": "agent-send-stop-button", "data-executing": isExecuting ? "true" : "false", children: isExecuting ? (_jsx(Square, { className: "size-3", strokeWidth: 1 })) : (_jsx(Send, { className: "size-3", strokeWidth: 1 })) })] })] }), _jsxs("div", { className: "mt-1 flex items-center gap-2 text-[11px] text-gray-500", children: [agent?.id &&
3312
3332
  (() => {
3313
3333
  const hasData = contextWindowStatus &&
3314
3334
  contextWindowStatus.contextWindowTokens;
@@ -3338,11 +3358,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3338
3358
  }
3339
3359
  return tokens.toString();
3340
3360
  };
3341
- return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "flex cursor-help items-center", children: _jsxs("svg", { className: "h-3 w-3", viewBox: "0 0 36 36", "aria-hidden": "true", children: [_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: "#e5e7eb", strokeWidth: "4" }), hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: `${percentValue} 100`, strokeLinecap: "round", style: {
3361
+ return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("div", { className: "flex cursor-help items-center justify-center", children: _jsxs("svg", { className: "h-3 w-3 flex-shrink-0", viewBox: "0 0 36 36", "aria-hidden": "true", children: [_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: "#e5e7eb", strokeWidth: "4" }), hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: `${percentValue} 100`, strokeLinecap: "round", style: {
3342
3362
  transformOrigin: "center",
3343
3363
  transform: "rotate(-90deg)",
3344
- } })), !hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: "0 100", strokeLinecap: "round", opacity: 0.5 }))] }) }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: hasData && contextWindowStatus ? (_jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [contextWindowStatus.model && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", contextWindowStatus.model] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(contextWindowStatus.estimatedInputTokens || 0), " ", "/", " ", formatTokens(contextWindowStatus.contextWindowTokens), " ", "tokens"] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] })) : (_jsx("div", { className: "max-w-[320px] text-xs", children: "Context window usage will appear here when the agent starts processing." })) })] }));
3345
- })(), agent?.compressionMarkerIndex != null && (_jsxs(Popover, { open: showCompressionPopover, onOpenChange: setShowCompressionPopover, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "cursor-pointer rounded border border-blue-200 bg-blue-50 px-2 py-0.5 text-[10px] text-blue-700 transition-colors hover:bg-blue-100", onClick: () => setShowCompressionPopover(!showCompressionPopover), children: "Compressed" }) }), _jsx(PopoverContent, { className: "w-96 p-4", align: "start", side: "top", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-sm font-semibold text-gray-900", children: "Conversation Compressed" }), _jsxs("p", { className: "mt-1 text-xs text-gray-600", children: ["First ", agent.compressionMarkerIndex, " messages have been summarized to reduce context usage."] })] }), agent.compressedSummary && (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "text-xs font-medium text-gray-700", children: "Summary:" }), _jsx("div", { className: "max-h-64 overflow-y-auto rounded border border-gray-200 bg-gray-50 p-3 text-xs whitespace-pre-wrap text-gray-700", children: agent.compressedSummary })] }))] }) })] })), _jsx(AgentCostDisplay, { totalTokens: liveTotals
3364
+ } })), !hasData && (_jsx("circle", { cx: "18", cy: "18", r: radius, fill: "none", stroke: contextColor, strokeWidth: "4", strokeDasharray: "0 100", strokeLinecap: "round", opacity: 0.5 }))] }) }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: hasData && contextWindowStatus ? (_jsxs("div", { className: "max-w-[320px] space-y-1 text-[11px]", children: [contextWindowStatus.model && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", contextWindowStatus.model] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(contextWindowStatus.estimatedInputTokens || 0), " ", "/", " ", formatTokens(contextWindowStatus.contextWindowTokens), " ", "tokens"] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] })) : (_jsx("div", { className: "max-w-[320px] text-[11px]", children: "Context window usage will appear here when the agent starts processing." })) })] }));
3365
+ })(), agent?.compressionMarkerIndex != null && (_jsxs(Popover, { open: showCompressionPopover, onOpenChange: setShowCompressionPopover, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsx("button", { className: "flex cursor-pointer items-center rounded border border-blue-200 bg-blue-50 px-2 py-0.5 text-[11px] text-blue-700 transition-colors hover:bg-blue-100", onClick: () => setShowCompressionPopover(!showCompressionPopover), children: "Compressed" }) }), _jsx(PopoverContent, { className: "w-96 p-4", align: "start", side: "top", children: _jsxs("div", { className: "space-y-3", children: [_jsxs("div", { children: [_jsx("h3", { className: "text-[10px] font-semibold text-gray-900", children: "Conversation Compressed" }), _jsxs("p", { className: "mt-1 text-[11px] text-gray-600", children: ["First ", agent.compressionMarkerIndex, " messages have been summarized to reduce context usage."] })] }), agent.compressedSummary && (_jsxs("div", { className: "space-y-1", children: [_jsx("div", { className: "text-[11px] font-medium text-gray-700", children: "Summary:" }), _jsx("div", { className: "max-h-64 overflow-y-auto rounded border border-gray-200 bg-gray-50 p-3 text-[11px] whitespace-pre-wrap text-gray-700", children: agent.compressedSummary })] }))] }) })] })), _jsx(AgentCostDisplay, { totalTokens: liveTotals
3346
3366
  ? {
3347
3367
  input: liveTotals.input,
3348
3368
  output: liveTotals.output,
@@ -3354,7 +3374,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
3354
3374
  cacheWriteCost: liveTotals.cacheWriteCost ?? 0,
3355
3375
  totalCost: liveTotals.totalCost,
3356
3376
  }
3357
- : totalTokens, costLimit: effectiveCostLimit }), activeProfile && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex items-center gap-1 text-gray-400 hover:text-gray-600", onClick: async () => {
3377
+ : totalTokens, costLimit: effectiveCostLimit }), activeProfile && (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("button", { type: "button", className: "flex items-center gap-1 text-[10px] text-gray-400 hover:text-gray-600", onClick: async () => {
3358
3378
  if (!editContext || !activeProfile?.id)
3359
3379
  return;
3360
3380
  // Load the profile item using editContext