@alpaca-editor/core 1.0.4187 → 1.0.4190
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/agents-view/AgentCard.js +1 -1
- package/dist/agents-view/AgentCard.js.map +1 -1
- package/dist/agents-view/AgentsView.js +7 -5
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/components/ui/PlaceholderInput.d.ts +41 -0
- package/dist/components/ui/PlaceholderInput.js +160 -0
- package/dist/components/ui/PlaceholderInput.js.map +1 -0
- package/dist/components/ui/PlaceholderInputTypes.d.ts +41 -0
- package/dist/components/ui/PlaceholderInputTypes.js +48 -0
- package/dist/components/ui/PlaceholderInputTypes.js.map +1 -0
- package/dist/components/ui/PlaceholderItemSelector.d.ts +7 -0
- package/dist/components/ui/PlaceholderItemSelector.js +154 -0
- package/dist/components/ui/PlaceholderItemSelector.js.map +1 -0
- package/dist/config/config.js +7 -14
- package/dist/config/config.js.map +1 -1
- package/dist/editor/ItemInfo.js +3 -3
- package/dist/editor/ItemInfo.js.map +1 -1
- package/dist/editor/QuickItemSwitcher.js +1 -1
- package/dist/editor/QuickItemSwitcher.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.d.ts +7 -1
- package/dist/editor/ai/AgentTerminal.js +256 -382
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +198 -84
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.d.ts +3 -1
- package/dist/editor/ai/AiResponseMessage.js +63 -12
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ToolCallDisplay.d.ts +2 -1
- package/dist/editor/ai/ToolCallDisplay.js +13 -5
- package/dist/editor/ai/ToolCallDisplay.js.map +1 -1
- package/dist/editor/client/EditorShell.js +6 -5
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.js +6 -4
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/commands/componentCommands.js +2 -0
- package/dist/editor/commands/componentCommands.js.map +1 -1
- package/dist/editor/control-center/About.js +1 -1
- package/dist/editor/control-center/About.js.map +1 -1
- package/dist/editor/control-center/AllAgentsPanel.js +1 -1
- package/dist/editor/field-types/MultiLineText.js +1 -1
- package/dist/editor/field-types/MultiLineText.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +1 -0
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/editor/sidebar/Validation.js +1 -1
- package/dist/editor/sidebar/Validation.js.map +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/page-wizard/PageWizard.js +3 -3
- package/dist/page-wizard/PageWizard.js.map +1 -1
- package/dist/page-wizard/WizardSteps.js +1 -1
- package/dist/page-wizard/WizardSteps.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/ModernSplashScreen.d.ts +8 -0
- package/dist/splash-screen/ModernSplashScreen.js +36 -0
- package/dist/splash-screen/ModernSplashScreen.js.map +1 -0
- package/dist/splash-screen/OpenPage.js +10 -6
- package/dist/splash-screen/OpenPage.js.map +1 -1
- package/dist/splash-screen/ParheliaAssistantChat.d.ts +8 -0
- package/dist/splash-screen/ParheliaAssistantChat.js +155 -0
- package/dist/splash-screen/ParheliaAssistantChat.js.map +1 -0
- package/dist/splash-screen/RecentAgents.d.ts +7 -0
- package/dist/splash-screen/RecentAgents.js +76 -0
- package/dist/splash-screen/RecentAgents.js.map +1 -0
- package/dist/splash-screen/RecentPages.js +2 -2
- package/dist/splash-screen/RecentPages.js.map +1 -1
- package/dist/splash-screen/SplashScreen.js +1 -1
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +241 -12
- package/package.json +1 -1
- package/src/agents-view/AgentCard.tsx +1 -6
- package/src/agents-view/AgentsView.tsx +18 -30
- package/src/components/ui/PlaceholderInput.tsx +290 -0
- package/src/components/ui/PlaceholderInputTypes.tsx +97 -0
- package/src/components/ui/PlaceholderItemSelector.tsx +253 -0
- package/src/config/config.tsx +8 -17
- package/src/editor/ItemInfo.tsx +3 -2
- package/src/editor/QuickItemSwitcher.tsx +1 -1
- package/src/editor/ai/AgentTerminal.tsx +544 -649
- package/src/editor/ai/Agents.tsx +464 -250
- package/src/editor/ai/AiResponseMessage.tsx +154 -29
- package/src/editor/ai/ToolCallDisplay.tsx +18 -4
- package/src/editor/client/EditorShell.tsx +9 -6
- package/src/editor/client/hooks/useSocketMessageHandler.ts +6 -7
- package/src/editor/commands/componentCommands.tsx +1 -0
- package/src/editor/control-center/About.tsx +2 -2
- package/src/editor/control-center/AllAgentsPanel.tsx +1 -1
- package/src/editor/field-types/MultiLineText.tsx +1 -1
- package/src/editor/services/aiService.ts +2 -0
- package/src/editor/sidebar/Validation.tsx +1 -1
- package/src/index.ts +5 -0
- package/src/page-wizard/PageWizard.tsx +3 -3
- package/src/page-wizard/WizardSteps.tsx +1 -1
- package/src/revision.ts +2 -2
- package/src/splash-screen/ModernSplashScreen.tsx +158 -0
- package/src/splash-screen/OpenPage.tsx +12 -4
- package/src/splash-screen/ParheliaAssistantChat.tsx +273 -0
- package/src/splash-screen/RecentAgents.tsx +151 -0
- package/src/splash-screen/RecentPages.tsx +58 -61
- package/src/splash-screen/SplashScreen.tsx +1 -1
- package/styles.css +20 -0
|
@@ -1,11 +1,12 @@
|
|
|
1
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";
|
|
2
|
+
import React, { useEffect, useState, useRef, useCallback, useLayoutEffect, useMemo, ViewTransition, } from "react";
|
|
3
3
|
import { Send, AlertCircle, Loader2, User, Wand2, Square, Mic, MicOff, ChevronDown, ChevronUp, ListTodo, } from "lucide-react";
|
|
4
4
|
import { DancingDots } from "./DancingDots";
|
|
5
|
-
import { getAgent, startAgent,
|
|
5
|
+
import { getAgent, startAgent, updateAgentSettings, updateAgentCostLimit, cancelAgent, canonicalizeAgentMetadata, } from "../services/agentService";
|
|
6
6
|
import { useEditContext, useFieldsEditContext } from "../client/editContext";
|
|
7
7
|
import { Textarea } from "../../components/ui/textarea";
|
|
8
8
|
import { Button } from "../../components/ui/button";
|
|
9
|
+
import { PlaceholderInput } from "../../components/ui/PlaceholderInput";
|
|
9
10
|
import { AiResponseMessage } from "./AiResponseMessage";
|
|
10
11
|
import { AgentCostDisplay } from "./AgentCostDisplay";
|
|
11
12
|
import { ContextInfoBar } from "./ContextInfoBar";
|
|
@@ -439,6 +440,12 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
|
|
|
439
440
|
id: agentMessage.id,
|
|
440
441
|
content: agentMessage.content,
|
|
441
442
|
formattedContent: agentMessage.content
|
|
443
|
+
?.replace(/^######\s+(.+)$/gm, "<h6>$1</h6>")
|
|
444
|
+
?.replace(/^#####\s+(.+)$/gm, "<h5>$1</h5>")
|
|
445
|
+
?.replace(/^####\s+(.+)$/gm, "<h4>$1</h4>")
|
|
446
|
+
?.replace(/^###\s+(.+)$/gm, "<h3>$1</h3>")
|
|
447
|
+
?.replace(/^##\s+(.+)$/gm, "<h2>$1</h2>")
|
|
448
|
+
?.replace(/^#\s+(.+)$/gm, "<h1>$1</h1>")
|
|
442
449
|
?.replace(/\*\*(.*?)\*\*/g, "<strong>$1</strong>")
|
|
443
450
|
?.replace(/\n/g, "<br/>"),
|
|
444
451
|
name: agentMessage.name,
|
|
@@ -468,7 +475,7 @@ const convertAgentMessagesToAiFormat = (agentMessages) => {
|
|
|
468
475
|
// interface AgentTerminalProps {
|
|
469
476
|
// agentStub: Agent;
|
|
470
477
|
// }
|
|
471
|
-
export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, }) {
|
|
478
|
+
export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive = true, compact = false, hideContext = false, hideBottomControls = false, hideGreeting = false, className, initialPrompt, }) {
|
|
472
479
|
const editContext = useEditContext();
|
|
473
480
|
const fieldsContext = useFieldsEditContext();
|
|
474
481
|
const [agent, setAgent] = useState(undefined);
|
|
@@ -478,6 +485,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
478
485
|
const [isLoading, setIsLoading] = useState(false);
|
|
479
486
|
const [isConnecting, setIsConnecting] = useState(false);
|
|
480
487
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
|
488
|
+
const [activePlaceholderInput, setActivePlaceholderInput] = useState(null);
|
|
481
489
|
const [agentMetadata, setAgentMetadata] = useState(null);
|
|
482
490
|
// Generate a stable clientSessionId per component instance for stream deduplication
|
|
483
491
|
const clientSessionIdRef = useRef(null);
|
|
@@ -650,6 +658,12 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
650
658
|
setIsVoiceSupported(false);
|
|
651
659
|
}
|
|
652
660
|
}, []);
|
|
661
|
+
// Auto-focus terminal input on mount
|
|
662
|
+
useEffect(() => {
|
|
663
|
+
if (textareaRef.current) {
|
|
664
|
+
textareaRef.current.focus();
|
|
665
|
+
}
|
|
666
|
+
}, []);
|
|
653
667
|
// Start voice recognition
|
|
654
668
|
const startVoice = useCallback(() => {
|
|
655
669
|
try {
|
|
@@ -1178,9 +1192,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1178
1192
|
const loadAgent = useCallback(async () => {
|
|
1179
1193
|
try {
|
|
1180
1194
|
if (agentStub.status === "new") {
|
|
1181
|
-
// Set agent ID immediately for new agents
|
|
1182
|
-
window.currentAgentId = agentStub.id;
|
|
1183
|
-
// Set currentAgentId for new agent
|
|
1184
1195
|
// Derive initial profile from provided metadata if present
|
|
1185
1196
|
const initialProfileIdFromMeta = (() => {
|
|
1186
1197
|
try {
|
|
@@ -1365,8 +1376,6 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1365
1376
|
const merged = mergeMessagesById(dbMessages, prevMessages);
|
|
1366
1377
|
return merged;
|
|
1367
1378
|
});
|
|
1368
|
-
// Set agent ID for existing agents too
|
|
1369
|
-
window.currentAgentId = agentData.id;
|
|
1370
1379
|
// Check if cost limit was exceeded (detect from existing messages)
|
|
1371
1380
|
try {
|
|
1372
1381
|
const costLimitMessage = (agentData.messages || []).find((msg) => msg.role === "assistant" &&
|
|
@@ -1878,18 +1887,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1878
1887
|
return () => window.removeEventListener("editor:focusAgentPrompt", focusHandler);
|
|
1879
1888
|
}, []);
|
|
1880
1889
|
// Profiles are provided by parent component (Agents). No local loading here.
|
|
1881
|
-
// Select active profile based on agent.profileId or
|
|
1890
|
+
// Select active profile based on agent.profileId or agentStub.profileId
|
|
1882
1891
|
useEffect(() => {
|
|
1883
1892
|
if (!profiles || profiles.length === 0)
|
|
1884
1893
|
return;
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1894
|
+
// For new agents, use agentStub.profileId; for loaded agents, use agent.profileId
|
|
1895
|
+
const profileIdToUse = agent?.profileId || agentStub.profileId;
|
|
1896
|
+
const candidate = profileIdToUse
|
|
1897
|
+
? (profiles.find((p) => p.id === profileIdToUse) ?? profiles[0])
|
|
1888
1898
|
: profiles[0];
|
|
1889
1899
|
if (candidate && (!activeProfile || activeProfile.id !== candidate.id)) {
|
|
1890
1900
|
setActiveProfile(candidate);
|
|
1891
1901
|
}
|
|
1892
|
-
}, [profiles, agent?.profileId]);
|
|
1902
|
+
}, [profiles, agent?.profileId, agentStub.profileId]);
|
|
1893
1903
|
// Update selected model when the active profile or agent model changes
|
|
1894
1904
|
useEffect(() => {
|
|
1895
1905
|
if (!activeProfile)
|
|
@@ -1966,12 +1976,13 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1966
1976
|
}
|
|
1967
1977
|
}, [agent?.id]);
|
|
1968
1978
|
const handleSubmit = async () => {
|
|
1969
|
-
if (
|
|
1979
|
+
if (isSubmitting || !editContext)
|
|
1970
1980
|
return;
|
|
1971
1981
|
try {
|
|
1972
1982
|
setIsSubmitting(true);
|
|
1973
1983
|
setError(null);
|
|
1974
|
-
|
|
1984
|
+
// For new agents, use agentStub.id; for existing agents, use agent.id
|
|
1985
|
+
const agentId = agent?.id || agentStub.id;
|
|
1975
1986
|
if (!agentId)
|
|
1976
1987
|
return;
|
|
1977
1988
|
// Optional context factory: invoke if configured and available, otherwise continue
|
|
@@ -1995,7 +2006,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
1995
2006
|
// It will be added when we receive the agent:user:message broadcast from the server
|
|
1996
2007
|
// This ensures all tabs (including the sending tab) have the same messageId from the database
|
|
1997
2008
|
const request = {
|
|
1998
|
-
agentId:
|
|
2009
|
+
agentId: agentId,
|
|
1999
2010
|
message: prompt.trim(),
|
|
2000
2011
|
sessionId: editContext.sessionId,
|
|
2001
2012
|
profileId: activeProfile?.id || profiles[0]?.id || "",
|
|
@@ -2152,232 +2163,35 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2152
2163
|
setIsSubmitting(false);
|
|
2153
2164
|
}
|
|
2154
2165
|
};
|
|
2155
|
-
//
|
|
2156
|
-
const
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2165
|
-
|
|
2166
|
-
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
},
|
|
2173
|
-
};
|
|
2174
|
-
if (next.additionalData && next.additionalData.context) {
|
|
2175
|
-
const ctx = next.additionalData.context;
|
|
2176
|
-
if (key === "items" && typeof index === "number" && ctx.items) {
|
|
2177
|
-
ctx.items.splice(index, 1);
|
|
2178
|
-
if (ctx.items.length === 0)
|
|
2179
|
-
delete ctx.items;
|
|
2180
|
-
}
|
|
2181
|
-
else if (key === "componentIds" &&
|
|
2182
|
-
typeof index === "number" &&
|
|
2183
|
-
ctx.componentIds) {
|
|
2184
|
-
ctx.componentIds.splice(index, 1);
|
|
2185
|
-
if (ctx.componentIds.length === 0)
|
|
2186
|
-
delete ctx.componentIds;
|
|
2187
|
-
}
|
|
2188
|
-
else if (key === "field") {
|
|
2189
|
-
delete ctx.field;
|
|
2190
|
-
}
|
|
2191
|
-
else if (key === "comment") {
|
|
2192
|
-
delete ctx.comment;
|
|
2193
|
-
}
|
|
2194
|
-
}
|
|
2195
|
-
try {
|
|
2196
|
-
// For new (not yet persisted) agents, only update local state
|
|
2197
|
-
if (agent.status === "new") {
|
|
2198
|
-
setAgentMetadata(next);
|
|
2199
|
-
return;
|
|
2200
|
-
}
|
|
2201
|
-
// Persisted agents: update server and local cache
|
|
2202
|
-
await updateAgentContext(agent.id, next);
|
|
2203
|
-
setAgentMetadata(next);
|
|
2204
|
-
setAgent((prev) => prev ? { ...prev, metadata: JSON.stringify(next) } : prev);
|
|
2205
|
-
}
|
|
2206
|
-
catch (e) {
|
|
2207
|
-
console.error("Failed to update agent metadata", e);
|
|
2208
|
-
}
|
|
2209
|
-
}, [agent?.id, agentMetadata]);
|
|
2210
|
-
const addPagesToContext = async () => {
|
|
2211
|
-
if (!agent?.id || !editContext?.currentItemDescriptor)
|
|
2212
|
-
return;
|
|
2213
|
-
// Add the current page (currentItemDescriptor represents the current page)
|
|
2214
|
-
// Note: Currently only supports adding the current page. To support multiple pages,
|
|
2215
|
-
// we'd need a page selection mechanism in the UI (e.g., a page picker dialog)
|
|
2216
|
-
const item = editContext.currentItemDescriptor;
|
|
2217
|
-
const pageToAdd = {
|
|
2218
|
-
id: item.id,
|
|
2219
|
-
language: item.language,
|
|
2220
|
-
version: item.version,
|
|
2221
|
-
name: editContext.contentEditorItem?.name,
|
|
2222
|
-
path: undefined,
|
|
2223
|
-
};
|
|
2224
|
-
const current = agentMetadata || {};
|
|
2225
|
-
const currentPages = current.additionalData?.context?.items || [];
|
|
2226
|
-
// Check if this page is already in context
|
|
2227
|
-
const existingPageIds = new Set(currentPages.map((p) => `${p.id}-${p.language}-${p.version}`));
|
|
2228
|
-
if (existingPageIds.has(`${pageToAdd.id}-${pageToAdd.language}-${pageToAdd.version}`)) {
|
|
2229
|
-
return; // Page already exists
|
|
2230
|
-
}
|
|
2231
|
-
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2232
|
-
const currentWithoutContext = { ...current };
|
|
2233
|
-
delete currentWithoutContext.context;
|
|
2234
|
-
const next = {
|
|
2235
|
-
...currentWithoutContext,
|
|
2236
|
-
additionalData: {
|
|
2237
|
-
...(current.additionalData || {}),
|
|
2238
|
-
context: {
|
|
2239
|
-
...((current.additionalData &&
|
|
2240
|
-
current.additionalData.context) ||
|
|
2241
|
-
{}),
|
|
2242
|
-
items: [...currentPages, pageToAdd],
|
|
2243
|
-
},
|
|
2244
|
-
},
|
|
2245
|
-
};
|
|
2246
|
-
try {
|
|
2247
|
-
if (agent.status === "new") {
|
|
2248
|
-
setAgentMetadata(next);
|
|
2249
|
-
return;
|
|
2250
|
-
}
|
|
2251
|
-
await updateAgentContext(agent.id, next);
|
|
2252
|
-
setAgentMetadata(next);
|
|
2253
|
-
setAgent((prev) => prev ? { ...prev, metadata: JSON.stringify(next) } : prev);
|
|
2254
|
-
}
|
|
2255
|
-
catch (e) {
|
|
2256
|
-
console.error("Failed to update agent metadata (add pages)", e);
|
|
2257
|
-
}
|
|
2258
|
-
};
|
|
2259
|
-
const addSelectedComponentsToContext = async () => {
|
|
2260
|
-
if (!agent?.id || !editContext?.selection?.length)
|
|
2261
|
-
return;
|
|
2262
|
-
const current = agentMetadata || {};
|
|
2263
|
-
const currentComponentIds = current.additionalData?.context?.componentIds ||
|
|
2264
|
-
[];
|
|
2265
|
-
// Merge with existing components, avoiding duplicates
|
|
2266
|
-
const existingIds = new Set(currentComponentIds);
|
|
2267
|
-
const newComponentIds = editContext.selection.filter((id) => !existingIds.has(id));
|
|
2268
|
-
if (newComponentIds.length === 0)
|
|
2269
|
-
return; // No new components to add
|
|
2270
|
-
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2271
|
-
const currentWithoutContext = { ...current };
|
|
2272
|
-
delete currentWithoutContext.context;
|
|
2273
|
-
const next = {
|
|
2274
|
-
...currentWithoutContext,
|
|
2275
|
-
additionalData: {
|
|
2276
|
-
...(current.additionalData || {}),
|
|
2277
|
-
context: {
|
|
2278
|
-
...((current.additionalData &&
|
|
2279
|
-
current.additionalData.context) ||
|
|
2280
|
-
{}),
|
|
2281
|
-
componentIds: [...currentComponentIds, ...newComponentIds],
|
|
2282
|
-
},
|
|
2283
|
-
},
|
|
2284
|
-
};
|
|
2285
|
-
try {
|
|
2286
|
-
if (agent.status === "new") {
|
|
2287
|
-
setAgentMetadata(next);
|
|
2288
|
-
return;
|
|
2289
|
-
}
|
|
2290
|
-
await updateAgentContext(agent.id, next);
|
|
2291
|
-
setAgentMetadata(next);
|
|
2292
|
-
setAgent((prev) => prev ? { ...prev, metadata: JSON.stringify(next) } : prev);
|
|
2293
|
-
}
|
|
2294
|
-
catch (e) {
|
|
2295
|
-
console.error("Failed to update agent metadata (add components)", e);
|
|
2296
|
-
}
|
|
2297
|
-
};
|
|
2298
|
-
const addComponentIdsToContext = async (ids) => {
|
|
2299
|
-
if (!agent?.id || !ids?.length)
|
|
2300
|
-
return;
|
|
2301
|
-
const current = agentMetadata || {};
|
|
2302
|
-
const currentComponentIds = current.additionalData?.context?.componentIds ||
|
|
2303
|
-
[];
|
|
2304
|
-
// Merge with existing components, avoiding duplicates
|
|
2305
|
-
const existingIds = new Set(currentComponentIds);
|
|
2306
|
-
const newComponentIds = ids.filter((id) => !!id && !existingIds.has(id));
|
|
2307
|
-
if (newComponentIds.length === 0)
|
|
2308
|
-
return;
|
|
2309
|
-
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2310
|
-
const currentWithoutContext = { ...current };
|
|
2311
|
-
delete currentWithoutContext.context;
|
|
2312
|
-
const next = {
|
|
2313
|
-
...currentWithoutContext,
|
|
2314
|
-
additionalData: {
|
|
2315
|
-
...(current.additionalData || {}),
|
|
2316
|
-
context: {
|
|
2317
|
-
...((current.additionalData &&
|
|
2318
|
-
current.additionalData.context) ||
|
|
2319
|
-
{}),
|
|
2320
|
-
componentIds: [...currentComponentIds, ...newComponentIds],
|
|
2321
|
-
},
|
|
2322
|
-
},
|
|
2323
|
-
};
|
|
2324
|
-
try {
|
|
2325
|
-
if (agent.status === "new") {
|
|
2326
|
-
setAgentMetadata(next);
|
|
2327
|
-
return;
|
|
2328
|
-
}
|
|
2329
|
-
await updateAgentContext(agent.id, next);
|
|
2330
|
-
setAgentMetadata(next);
|
|
2331
|
-
setAgent((prev) => prev ? { ...prev, metadata: JSON.stringify(next) } : prev);
|
|
2332
|
-
}
|
|
2333
|
-
catch (e) {
|
|
2334
|
-
console.error("Failed to update agent metadata (add components)", e);
|
|
2335
|
-
}
|
|
2336
|
-
};
|
|
2337
|
-
const addPagesToContextFromItems = async (items) => {
|
|
2338
|
-
if (!agent?.id || !items?.length)
|
|
2339
|
-
return;
|
|
2340
|
-
const current = agentMetadata || {};
|
|
2341
|
-
const currentPages = current.additionalData?.context?.items || [];
|
|
2342
|
-
const existingPageIds = new Set(currentPages.map((p) => `${p.id}-${p.language}-${p.version}`));
|
|
2343
|
-
const pagesToAdd = items
|
|
2344
|
-
.filter((it) => !!it?.id)
|
|
2345
|
-
.map((it) => ({
|
|
2346
|
-
id: it.id,
|
|
2347
|
-
language: it.language,
|
|
2348
|
-
version: it.version,
|
|
2349
|
-
}))
|
|
2350
|
-
.filter((p) => !existingPageIds.has(`${p.id}-${p.language}-${p.version}`));
|
|
2351
|
-
if (pagesToAdd.length === 0)
|
|
2352
|
-
return;
|
|
2353
|
-
// Exclude top-level context to avoid duplicate keys when spreading
|
|
2354
|
-
const currentWithoutContext = { ...current };
|
|
2355
|
-
delete currentWithoutContext.context;
|
|
2356
|
-
const next = {
|
|
2357
|
-
...currentWithoutContext,
|
|
2358
|
-
additionalData: {
|
|
2359
|
-
...(current.additionalData || {}),
|
|
2360
|
-
context: {
|
|
2361
|
-
...((current.additionalData &&
|
|
2362
|
-
current.additionalData.context) ||
|
|
2363
|
-
{}),
|
|
2364
|
-
items: [...currentPages, ...pagesToAdd],
|
|
2365
|
-
},
|
|
2366
|
-
},
|
|
2367
|
-
};
|
|
2368
|
-
try {
|
|
2369
|
-
if (agent.status === "new") {
|
|
2370
|
-
setAgentMetadata(next);
|
|
2371
|
-
return;
|
|
2372
|
-
}
|
|
2373
|
-
await updateAgentContext(agent.id, next);
|
|
2374
|
-
setAgentMetadata(next);
|
|
2375
|
-
setAgent((prev) => prev ? { ...prev, metadata: JSON.stringify(next) } : prev);
|
|
2376
|
-
}
|
|
2377
|
-
catch (e) {
|
|
2378
|
-
console.error("Failed to update agent metadata (add items/pages)", e);
|
|
2166
|
+
// Auto-send initial prompt if provided and agent has no messages yet
|
|
2167
|
+
const initialPromptSentRef = useRef(false);
|
|
2168
|
+
useEffect(() => {
|
|
2169
|
+
if (initialPrompt !== undefined &&
|
|
2170
|
+
!isLoading &&
|
|
2171
|
+
!initialPromptSentRef.current &&
|
|
2172
|
+
messages.length === 0 &&
|
|
2173
|
+
agentStub.id &&
|
|
2174
|
+
editContext &&
|
|
2175
|
+
activeProfile && // MUST have activeProfile set, not just profiles.length
|
|
2176
|
+
profiles.length > 0) {
|
|
2177
|
+
initialPromptSentRef.current = true;
|
|
2178
|
+
// Delay slightly to ensure all state is ready
|
|
2179
|
+
setTimeout(() => {
|
|
2180
|
+
setPrompt(initialPrompt);
|
|
2181
|
+
// Trigger submit programmatically
|
|
2182
|
+
handleSubmit();
|
|
2183
|
+
}, 200);
|
|
2379
2184
|
}
|
|
2380
|
-
}
|
|
2185
|
+
}, [
|
|
2186
|
+
initialPrompt,
|
|
2187
|
+
isLoading,
|
|
2188
|
+
messages.length,
|
|
2189
|
+
agentStub.id,
|
|
2190
|
+
editContext,
|
|
2191
|
+
activeProfile,
|
|
2192
|
+
profiles.length,
|
|
2193
|
+
handleSubmit,
|
|
2194
|
+
]);
|
|
2381
2195
|
// Resolve display names when metadata or editor state changes
|
|
2382
2196
|
useEffect(() => {
|
|
2383
2197
|
const metaCtx = agentMetadata;
|
|
@@ -2551,11 +2365,11 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2551
2365
|
}
|
|
2552
2366
|
}, children: "Extend limit and continue" }) })] }));
|
|
2553
2367
|
};
|
|
2554
|
-
return (_jsxs("div", { className:
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2368
|
+
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: "h-8 w-8 animate-spin text-gray-400 mx-auto" })) : (_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: {
|
|
2369
|
+
__html: activeProfile.svgIcon,
|
|
2370
|
+
} })) : (_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: {
|
|
2371
|
+
__html: activeProfile.greetingMessage,
|
|
2372
|
+
} }) })) : (_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." })] }))] })) }) })), _jsx("div", { className: "space-y-0 divide-y divide-gray-100 select-text", children: groupConsecutiveMessages(messages).map((group, groupIndex) => {
|
|
2559
2373
|
if (group.type === "user" && group.messages[0]) {
|
|
2560
2374
|
// Render user message
|
|
2561
2375
|
return (_jsx(UserMessage, { message: group.messages[0] }, groupIndex));
|
|
@@ -2575,13 +2389,23 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2575
2389
|
return null;
|
|
2576
2390
|
}
|
|
2577
2391
|
const convertedMessages = convertAgentMessagesToAiFormat(filteredMessages);
|
|
2578
|
-
return (_jsx(AiResponseMessage, { messages: convertedMessages, finished: !isSubmitting && !isConnecting, editOperations: [], error: error || undefined, profileSvgIcon: activeProfile?.svgIcon, onQuickAction: (action) => {
|
|
2392
|
+
return (_jsx(AiResponseMessage, { messages: convertedMessages, finished: !isSubmitting && !isConnecting, editOperations: [], error: error || undefined, profileSvgIcon: activeProfile?.svgIcon, agentId: agent?.id || agentStub.id, agentName: activeProfile?.name, onQuickAction: (action) => {
|
|
2579
2393
|
const text = (action.prompt ||
|
|
2580
2394
|
action.value ||
|
|
2581
2395
|
action.label ||
|
|
2582
2396
|
"").trim();
|
|
2583
2397
|
if (!text)
|
|
2584
2398
|
return;
|
|
2399
|
+
// Check if text contains placeholders ({placeholder} or <placeholder>)
|
|
2400
|
+
const hasPlaceholders = /\{([^}]+)\}|<([^>]+)>/.test(text);
|
|
2401
|
+
if (hasPlaceholders) {
|
|
2402
|
+
// Show placeholder input
|
|
2403
|
+
setActivePlaceholderInput({
|
|
2404
|
+
text,
|
|
2405
|
+
behavior: action.behavior,
|
|
2406
|
+
});
|
|
2407
|
+
return;
|
|
2408
|
+
}
|
|
2585
2409
|
if (action.behavior === "compose") {
|
|
2586
2410
|
setPrompt(text);
|
|
2587
2411
|
setInputPlaceholder(action.placeholder ||
|
|
@@ -2607,154 +2431,204 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, isActive =
|
|
|
2607
2431
|
sendQuickMessage(text);
|
|
2608
2432
|
} }, groupIndex));
|
|
2609
2433
|
}
|
|
2610
|
-
}) }), _jsx("div", { className: showDots ? "visible" : "invisible", children: _jsx(DancingDots, {}) }), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), renderContextInfoBar(), _jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata }), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [
|
|
2434
|
+
}) }), _jsx("div", { className: showDots ? "visible" : "invisible", children: _jsx(DancingDots, {}) }), renderCostLimitBanner(), _jsx("div", { ref: messagesEndRef })] }), !hideContext && renderContextInfoBar(), !hideContext && (_jsx(TodoListPanel, { messages: messages, agentMetadata: agentMetadata })), _jsxs("div", { className: "border-t border-gray-200 p-4", children: [activePlaceholderInput ? (
|
|
2435
|
+
// Placeholder Input (from quick actions)
|
|
2436
|
+
_jsx(PlaceholderInput, { text: activePlaceholderInput.text, showButtons: false, onComplete: (filledText) => {
|
|
2437
|
+
setActivePlaceholderInput(null);
|
|
2438
|
+
if (activePlaceholderInput.behavior === "compose") {
|
|
2439
|
+
setPrompt(filledText);
|
|
2440
|
+
setInputPlaceholder("Review and edit, then press Enter to send");
|
|
2441
|
+
if (textareaRef.current) {
|
|
2442
|
+
try {
|
|
2443
|
+
textareaRef.current.focus();
|
|
2444
|
+
const v = textareaRef.current.value || "";
|
|
2445
|
+
textareaRef.current.selectionStart = v.length;
|
|
2446
|
+
textareaRef.current.selectionEnd = v.length;
|
|
2447
|
+
}
|
|
2448
|
+
catch { }
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
else {
|
|
2452
|
+
// Submit behavior or default
|
|
2453
|
+
if (isExecuting) {
|
|
2454
|
+
try {
|
|
2455
|
+
handleStop();
|
|
2456
|
+
}
|
|
2457
|
+
catch { }
|
|
2458
|
+
}
|
|
2459
|
+
sendQuickMessage(filledText);
|
|
2460
|
+
}
|
|
2461
|
+
}, onCancel: () => {
|
|
2462
|
+
setActivePlaceholderInput(null);
|
|
2463
|
+
} })) : prompt && /\{([^}]+)\}|<([^>]+)>/.test(prompt) ? (
|
|
2464
|
+
// Template mode: show PlaceholderInput when prompt contains placeholders
|
|
2465
|
+
_jsx(PlaceholderInput, { text: prompt, showButtons: false, onComplete: (filledText) => {
|
|
2466
|
+
setPrompt(filledText);
|
|
2467
|
+
// Auto-submit after filling placeholders
|
|
2468
|
+
if (filledText.trim()) {
|
|
2469
|
+
if (isExecuting) {
|
|
2470
|
+
try {
|
|
2471
|
+
handleStop();
|
|
2472
|
+
}
|
|
2473
|
+
catch { }
|
|
2474
|
+
}
|
|
2475
|
+
sendQuickMessage(filledText);
|
|
2476
|
+
}
|
|
2477
|
+
}, onCancel: () => {
|
|
2478
|
+
setPrompt("");
|
|
2479
|
+
setInputPlaceholder("Type your message... (Enter to send, Shift+Enter or Ctrl+Enter for new line)");
|
|
2480
|
+
} })) : (_jsx("div", { className: "flex items-stretch gap-2", children: _jsx(Textarea, { ref: textareaRef, value: prompt, onChange: (e) => {
|
|
2611
2481
|
setPrompt(e.target.value);
|
|
2612
2482
|
// Reset history index when user starts typing
|
|
2613
2483
|
if (currentHistoryIndex !== -1) {
|
|
2614
2484
|
setCurrentHistoryIndex(-1);
|
|
2615
2485
|
}
|
|
2616
|
-
}, onKeyDown: handleKeyPress, placeholder: inputPlaceholder, className: "h-[80px] flex-1 resize-none overflow-y-auto text-xs", "data-testid": "agent-terminal-prompt", disabled: isSubmitting }) }), _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"
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
mode: nextMode,
|
|
2628
|
-
};
|
|
2629
|
-
try {
|
|
2630
|
-
if (!agent?.id || agent.status === "new") {
|
|
2631
|
-
setAgentMetadata(nextMeta);
|
|
2632
|
-
// Cache until first start when agent is persisted
|
|
2633
|
-
pendingSettingsRef.current = {
|
|
2634
|
-
...(pendingSettingsRef.current || {}),
|
|
2486
|
+
}, onKeyDown: handleKeyPress, 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"
|
|
2487
|
+
? "border-green-300 bg-green-50 text-green-700"
|
|
2488
|
+
: mode === "supervised"
|
|
2489
|
+
? "border-amber-300 bg-amber-50 text-amber-700"
|
|
2490
|
+
: "border-red-300 bg-red-50 text-red-700"}`, value: mode, onChange: async (e) => {
|
|
2491
|
+
const nextMode = e.target.value || "supervised";
|
|
2492
|
+
// Optimistic UI update
|
|
2493
|
+
setMode(nextMode);
|
|
2494
|
+
const current = agentMetadata || {};
|
|
2495
|
+
const nextMeta = {
|
|
2496
|
+
...current,
|
|
2635
2497
|
mode: nextMode,
|
|
2636
2498
|
};
|
|
2637
|
-
|
|
2499
|
+
try {
|
|
2500
|
+
if (!agent?.id || agent.status === "new") {
|
|
2501
|
+
setAgentMetadata(nextMeta);
|
|
2502
|
+
// Cache until first start when agent is persisted
|
|
2503
|
+
pendingSettingsRef.current = {
|
|
2504
|
+
...(pendingSettingsRef.current || {}),
|
|
2505
|
+
mode: nextMode,
|
|
2506
|
+
};
|
|
2507
|
+
return;
|
|
2508
|
+
}
|
|
2509
|
+
await updateAgentSettings(agent.id, {
|
|
2510
|
+
mode: nextMode,
|
|
2511
|
+
});
|
|
2512
|
+
setAgentMetadata(nextMeta);
|
|
2513
|
+
setAgent((prev) => prev
|
|
2514
|
+
? { ...prev, metadata: JSON.stringify(nextMeta) }
|
|
2515
|
+
: prev);
|
|
2516
|
+
}
|
|
2517
|
+
catch (e2) {
|
|
2518
|
+
console.error("Failed to persist mode change", e2);
|
|
2519
|
+
}
|
|
2520
|
+
}, 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) => {
|
|
2521
|
+
const nextProfile = profiles.find((x) => x.id === e.target.value);
|
|
2522
|
+
if (!nextProfile)
|
|
2523
|
+
return;
|
|
2524
|
+
setActiveProfile(nextProfile);
|
|
2525
|
+
try {
|
|
2526
|
+
if (agent?.id && agent.status !== "new") {
|
|
2527
|
+
await updateAgentSettings(agent.id, {
|
|
2528
|
+
profileId: nextProfile.id,
|
|
2529
|
+
profileName: nextProfile.name,
|
|
2530
|
+
});
|
|
2531
|
+
}
|
|
2532
|
+
else {
|
|
2533
|
+
// cache until first start
|
|
2534
|
+
pendingSettingsRef.current = {
|
|
2535
|
+
...(pendingSettingsRef.current || {}),
|
|
2536
|
+
// we cache profile by updating local metadata
|
|
2537
|
+
};
|
|
2538
|
+
setAgentMetadata((current) => {
|
|
2539
|
+
const next = { ...(current || {}) };
|
|
2540
|
+
next.profile = nextProfile.name;
|
|
2541
|
+
next.additionalData = {
|
|
2542
|
+
...(next.additionalData || {}),
|
|
2543
|
+
profileId: nextProfile.id,
|
|
2544
|
+
profileName: nextProfile.name,
|
|
2545
|
+
};
|
|
2546
|
+
return next;
|
|
2547
|
+
});
|
|
2548
|
+
}
|
|
2549
|
+
// reflect in local agent stub so tabs and titles can use it if needed
|
|
2550
|
+
setAgent((prev) => prev
|
|
2551
|
+
? {
|
|
2552
|
+
...prev,
|
|
2553
|
+
metadata: JSON.stringify({
|
|
2554
|
+
...(agentMetadata || {}),
|
|
2555
|
+
profile: nextProfile.name,
|
|
2556
|
+
additionalData: {
|
|
2557
|
+
...(agentMetadata
|
|
2558
|
+
?.additionalData || {}),
|
|
2559
|
+
profileId: nextProfile.id,
|
|
2560
|
+
profileName: nextProfile.name,
|
|
2561
|
+
},
|
|
2562
|
+
}),
|
|
2638
2563
|
}
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2564
|
+
: prev);
|
|
2565
|
+
}
|
|
2566
|
+
catch (err) {
|
|
2567
|
+
console.error("Failed to persist agent profile", err);
|
|
2568
|
+
}
|
|
2569
|
+
}, 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) => {
|
|
2570
|
+
const nextId = e.target.value;
|
|
2571
|
+
setSelectedModelId(nextId);
|
|
2572
|
+
const modelName = activeProfile?.models?.find((m) => m.id === nextId)
|
|
2573
|
+
?.name || "";
|
|
2574
|
+
// Update local agent state immediately for UX and to reflect in streaming stub
|
|
2575
|
+
setAgent((prev) => prev ? { ...prev, model: modelName } : prev);
|
|
2576
|
+
// Persist only for existing agents; otherwise cache until first start
|
|
2577
|
+
try {
|
|
2578
|
+
if (agent?.id && agent.status !== "new") {
|
|
2579
|
+
await updateAgentSettings(agent.id, {
|
|
2580
|
+
model: modelName,
|
|
2581
|
+
});
|
|
2644
2582
|
}
|
|
2645
|
-
|
|
2646
|
-
|
|
2583
|
+
else {
|
|
2584
|
+
pendingSettingsRef.current = {
|
|
2585
|
+
...(pendingSettingsRef.current || {}),
|
|
2586
|
+
modelName,
|
|
2587
|
+
};
|
|
2647
2588
|
}
|
|
2648
|
-
}, 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) => {
|
|
2649
|
-
const nextProfile = profiles.find((x) => x.id === e.target.value);
|
|
2650
|
-
if (!nextProfile)
|
|
2651
|
-
return;
|
|
2652
|
-
setActiveProfile(nextProfile);
|
|
2653
|
-
try {
|
|
2654
|
-
if (agent?.id && agent.status !== "new") {
|
|
2655
|
-
await updateAgentSettings(agent.id, {
|
|
2656
|
-
profileId: nextProfile.id,
|
|
2657
|
-
profileName: nextProfile.name,
|
|
2658
|
-
});
|
|
2659
|
-
}
|
|
2660
|
-
else {
|
|
2661
|
-
// cache until first start
|
|
2662
|
-
pendingSettingsRef.current = {
|
|
2663
|
-
...(pendingSettingsRef.current || {}),
|
|
2664
|
-
// we cache profile by updating local metadata
|
|
2665
|
-
};
|
|
2666
|
-
setAgentMetadata((current) => {
|
|
2667
|
-
const next = { ...(current || {}) };
|
|
2668
|
-
next.profile = nextProfile.name;
|
|
2669
|
-
next.additionalData = {
|
|
2670
|
-
...(next.additionalData || {}),
|
|
2671
|
-
profileId: nextProfile.id,
|
|
2672
|
-
profileName: nextProfile.name,
|
|
2673
|
-
};
|
|
2674
|
-
return next;
|
|
2675
|
-
});
|
|
2676
|
-
}
|
|
2677
|
-
// reflect in local agent stub so tabs and titles can use it if needed
|
|
2678
|
-
setAgent((prev) => prev
|
|
2679
|
-
? {
|
|
2680
|
-
...prev,
|
|
2681
|
-
metadata: JSON.stringify({
|
|
2682
|
-
...(agentMetadata || {}),
|
|
2683
|
-
profile: nextProfile.name,
|
|
2684
|
-
additionalData: {
|
|
2685
|
-
...(agentMetadata?.additionalData ||
|
|
2686
|
-
{}),
|
|
2687
|
-
profileId: nextProfile.id,
|
|
2688
|
-
profileName: nextProfile.name,
|
|
2689
|
-
},
|
|
2690
|
-
}),
|
|
2691
2589
|
}
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2590
|
+
catch (err) {
|
|
2591
|
+
console.error("Failed to persist agent model", err);
|
|
2592
|
+
}
|
|
2593
|
+
}, 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: () => {
|
|
2594
|
+
setPrompt(p.prompt);
|
|
2595
|
+
setShowPredefined(false);
|
|
2596
|
+
if (textareaRef.current)
|
|
2597
|
+
textareaRef.current.focus();
|
|
2598
|
+
}, 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 && !prompt.trim(), 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: [_jsx(AgentCostDisplay, { totalTokens: liveTotals
|
|
2599
|
+
? {
|
|
2600
|
+
input: liveTotals.input,
|
|
2601
|
+
output: liveTotals.output,
|
|
2602
|
+
cached: liveTotals.cached,
|
|
2603
|
+
cacheWrite: liveTotals.cacheWrite ?? 0,
|
|
2604
|
+
inputCost: liveTotals.inputCost,
|
|
2605
|
+
outputCost: liveTotals.outputCost,
|
|
2606
|
+
cachedCost: liveTotals.cachedCost,
|
|
2607
|
+
cacheWriteCost: liveTotals.cacheWriteCost ?? 0,
|
|
2608
|
+
totalCost: liveTotals.totalCost,
|
|
2696
2609
|
}
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2709
|
-
else {
|
|
2710
|
-
pendingSettingsRef.current = {
|
|
2711
|
-
...(pendingSettingsRef.current || {}),
|
|
2712
|
-
modelName,
|
|
2713
|
-
};
|
|
2610
|
+
: totalTokens, costLimit: effectiveCostLimit }), (() => {
|
|
2611
|
+
try {
|
|
2612
|
+
const s = window.__agentContextWindowStatus;
|
|
2613
|
+
if (!s || !s.contextWindowTokens)
|
|
2614
|
+
return null;
|
|
2615
|
+
const pct = typeof s.contextUsedPercent === "number"
|
|
2616
|
+
? `${s.contextUsedPercent.toFixed(1)}%`
|
|
2617
|
+
: undefined;
|
|
2618
|
+
// Helper function to format tokens as "k"
|
|
2619
|
+
const formatTokens = (tokens) => {
|
|
2620
|
+
if (tokens >= 1000) {
|
|
2621
|
+
return `${(tokens / 1000).toFixed(1)}k`;
|
|
2714
2622
|
}
|
|
2715
|
-
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
|
|
2720
|
-
setPrompt(p.prompt);
|
|
2721
|
-
setShowPredefined(false);
|
|
2722
|
-
if (textareaRef.current)
|
|
2723
|
-
textareaRef.current.focus();
|
|
2724
|
-
}, 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 && !prompt.trim(), 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: [_jsx(AgentCostDisplay, { totalTokens: liveTotals
|
|
2725
|
-
? {
|
|
2726
|
-
input: liveTotals.input,
|
|
2727
|
-
output: liveTotals.output,
|
|
2728
|
-
cached: liveTotals.cached,
|
|
2729
|
-
cacheWrite: liveTotals.cacheWrite ?? 0,
|
|
2730
|
-
inputCost: liveTotals.inputCost,
|
|
2731
|
-
outputCost: liveTotals.outputCost,
|
|
2732
|
-
cachedCost: liveTotals.cachedCost,
|
|
2733
|
-
cacheWriteCost: liveTotals.cacheWriteCost ?? 0,
|
|
2734
|
-
totalCost: liveTotals.totalCost,
|
|
2735
|
-
}
|
|
2736
|
-
: totalTokens, costLimit: effectiveCostLimit }), (() => {
|
|
2737
|
-
try {
|
|
2738
|
-
const s = window.__agentContextWindowStatus;
|
|
2739
|
-
if (!s || !s.contextWindowTokens)
|
|
2740
|
-
return null;
|
|
2741
|
-
const pct = typeof s.contextUsedPercent === "number"
|
|
2742
|
-
? `${s.contextUsedPercent.toFixed(1)}%`
|
|
2743
|
-
: undefined;
|
|
2744
|
-
// Helper function to format tokens as "k"
|
|
2745
|
-
const formatTokens = (tokens) => {
|
|
2746
|
-
if (tokens >= 1000) {
|
|
2747
|
-
return `${(tokens / 1000).toFixed(1)}k`;
|
|
2623
|
+
return tokens.toString();
|
|
2624
|
+
};
|
|
2625
|
+
if (!pct)
|
|
2626
|
+
return null;
|
|
2627
|
+
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "cursor-help rounded border border-gray-200 bg-gray-50 px-2 py-0.5", children: ["Context: ", pct] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", s.model, s.normalizedModel && ` (${s.normalizedModel})`] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(s.estimatedInputTokens || 0), " /", " ", formatTokens(s.contextWindowTokens), " tokens"] }), typeof s.maxCompletionTokens === "number" && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Max completion:" }), " ", formatTokens(s.maxCompletionTokens), " tokens"] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] }) })] }));
|
|
2748
2628
|
}
|
|
2749
|
-
|
|
2750
|
-
|
|
2751
|
-
|
|
2752
|
-
|
|
2753
|
-
return (_jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsxs("div", { className: "cursor-help rounded border border-gray-200 bg-gray-50 px-2 py-0.5", children: ["Context: ", pct] }) }), _jsx(TooltipContent, { side: "top", sideOffset: 6, children: _jsxs("div", { className: "max-w-[320px] space-y-1 text-xs", children: [_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Model:" }), " ", s.model, s.normalizedModel && ` (${s.normalizedModel})`] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Context window:" }), " ", formatTokens(s.estimatedInputTokens || 0), " /", " ", formatTokens(s.contextWindowTokens), " tokens"] }), typeof s.maxCompletionTokens === "number" && (_jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Max completion:" }), " ", formatTokens(s.maxCompletionTokens), " tokens"] })), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Used:" }), " ", pct] })] }) })] }));
|
|
2754
|
-
}
|
|
2755
|
-
catch {
|
|
2756
|
-
return null;
|
|
2757
|
-
}
|
|
2758
|
-
})()] })] })] }));
|
|
2629
|
+
catch {
|
|
2630
|
+
return null;
|
|
2631
|
+
}
|
|
2632
|
+
})()] })] }))] })] }));
|
|
2759
2633
|
}
|
|
2760
2634
|
//# sourceMappingURL=AgentTerminal.js.map
|