@alpaca-editor/core 1.0.4085 → 1.0.4088
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/components/ui/card.d.ts +1 -1
- package/dist/components/ui/paste-button.d.ts +14 -0
- package/dist/components/ui/paste-button.js +114 -0
- package/dist/components/ui/paste-button.js.map +1 -0
- package/dist/config/config.js +60 -3
- package/dist/config/config.js.map +1 -1
- package/dist/config/types.d.ts +25 -0
- package/dist/editor/ContentTree.js +43 -21
- package/dist/editor/ContentTree.js.map +1 -1
- package/dist/editor/FieldListField.js +62 -2
- package/dist/editor/FieldListField.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.d.ts +3 -1
- package/dist/editor/ai/AgentTerminal.js +96 -74
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +46 -2
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +171 -75
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/AiTerminal.js +27 -14
- package/dist/editor/ai/AiTerminal.js.map +1 -1
- package/dist/editor/client/EditorShell.js +110 -17
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/editContext.d.ts +4 -0
- package/dist/editor/client/editContext.js.map +1 -1
- package/dist/editor/client/hooks/useSocketMessageHandler.d.ts +1 -0
- package/dist/editor/client/hooks/useSocketMessageHandler.js +54 -20
- package/dist/editor/client/hooks/useSocketMessageHandler.js.map +1 -1
- package/dist/editor/client/hooks/useWorkbox.d.ts +1 -1
- package/dist/editor/client/hooks/useWorkbox.js +4 -4
- package/dist/editor/client/hooks/useWorkbox.js.map +1 -1
- package/dist/editor/client/itemsRepository.d.ts +13 -1
- package/dist/editor/client/itemsRepository.js +34 -21
- package/dist/editor/client/itemsRepository.js.map +1 -1
- package/dist/editor/client/pageModelBuilder.js +1 -1
- package/dist/editor/client/pageModelBuilder.js.map +1 -1
- package/dist/editor/control-center/Setup.d.ts +1 -0
- package/dist/editor/control-center/Setup.js +18 -0
- package/dist/editor/control-center/Setup.js.map +1 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep.d.ts +2 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep.js +287 -0
- package/dist/editor/control-center/setup-steps/AiSetupStep.js.map +1 -0
- package/dist/editor/control-center/setup-steps/DbSetupStep.d.ts +2 -0
- package/dist/editor/control-center/setup-steps/DbSetupStep.js +46 -0
- package/dist/editor/control-center/setup-steps/DbSetupStep.js.map +1 -0
- package/dist/editor/control-center/setup-steps/IndexSetupStep.d.ts +2 -0
- package/dist/editor/control-center/setup-steps/IndexSetupStep.js +34 -0
- package/dist/editor/control-center/setup-steps/IndexSetupStep.js.map +1 -0
- package/dist/editor/control-center/setup-steps/SettingsSetupStep.d.ts +2 -0
- package/dist/editor/control-center/setup-steps/SettingsSetupStep.js +104 -0
- package/dist/editor/control-center/setup-steps/SettingsSetupStep.js.map +1 -0
- package/dist/editor/field-types/InternalLinkFieldEditor.js +3 -1
- package/dist/editor/field-types/InternalLinkFieldEditor.js.map +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js +1 -1
- package/dist/editor/field-types/RichTextEditorComponent.js.map +1 -1
- package/dist/editor/field-types/richtext/components/ReactSlate.js +2 -2
- package/dist/editor/field-types/richtext/components/ReactSlate.js.map +1 -1
- package/dist/editor/field-types/richtext/utils/profileServiceCache.d.ts +1 -1
- package/dist/editor/field-types/richtext/utils/profileServiceCache.js +16 -14
- package/dist/editor/field-types/richtext/utils/profileServiceCache.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/CompareControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/CompareControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/EditControls.js.map +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js +1 -1
- package/dist/editor/menubar/toolbar-sections/ViewportControls.js.map +1 -1
- package/dist/editor/page-editor-chrome/InlineEditor.js +25 -6
- package/dist/editor/page-editor-chrome/InlineEditor.js.map +1 -1
- package/dist/editor/page-viewer/EditorForm.js +9 -2
- package/dist/editor/page-viewer/EditorForm.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +5 -0
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/pageModel.d.ts +1 -0
- package/dist/editor/reviews/Comment.js +1 -1
- package/dist/editor/reviews/Comment.js.map +1 -1
- package/dist/editor/reviews/CommentDisplayPopover.js +3 -24
- package/dist/editor/reviews/CommentDisplayPopover.js.map +1 -1
- package/dist/editor/reviews/CommentPopover.js +3 -23
- package/dist/editor/reviews/CommentPopover.js.map +1 -1
- package/dist/editor/reviews/CommentView.js +2 -1
- package/dist/editor/reviews/CommentView.js.map +1 -1
- package/dist/editor/reviews/Comments.js +88 -37
- package/dist/editor/reviews/Comments.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +3 -0
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/sidebar/Debug.js +1 -5
- package/dist/editor/sidebar/Debug.js.map +1 -1
- package/dist/editor/sidebar/ViewSelector.js +72 -6
- package/dist/editor/sidebar/ViewSelector.js.map +1 -1
- package/dist/editor/ui/Icons.d.ts +5 -0
- package/dist/editor/ui/Icons.js +14 -0
- package/dist/editor/ui/Icons.js.map +1 -1
- package/dist/editor/utils.d.ts +5 -0
- package/dist/editor/utils.js +29 -0
- package/dist/editor/utils.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/splash-screen/SplashScreen.js +2 -2
- package/dist/splash-screen/SplashScreen.js.map +1 -1
- package/dist/styles.css +3 -0
- package/dist/types.d.ts +2 -0
- package/package.json +1 -1
- package/src/components/ui/card.tsx +1 -1
- package/src/components/ui/paste-button.tsx +163 -0
- package/src/config/config.tsx +68 -2
- package/src/config/types.ts +26 -0
- package/src/editor/ContentTree.tsx +48 -23
- package/src/editor/FieldListField.tsx +75 -2
- package/src/editor/ai/AgentTerminal.tsx +118 -71
- package/src/editor/ai/Agents.tsx +52 -1
- package/src/editor/ai/AiResponseMessage.tsx +234 -78
- package/src/editor/ai/AiTerminal.tsx +30 -14
- package/src/editor/client/EditorShell.tsx +128 -25
- package/src/editor/client/editContext.ts +1 -0
- package/src/editor/client/hooks/useSocketMessageHandler.ts +70 -21
- package/src/editor/client/hooks/useWorkbox.ts +4 -4
- package/src/editor/client/itemsRepository.ts +56 -25
- package/src/editor/client/pageModelBuilder.ts +1 -1
- package/src/editor/control-center/Setup.tsx +26 -0
- package/src/editor/control-center/setup-steps/AiSetupStep.tsx +462 -0
- package/src/editor/control-center/setup-steps/DbSetupStep.tsx +84 -0
- package/src/editor/control-center/setup-steps/IndexSetupStep.tsx +56 -0
- package/src/editor/control-center/setup-steps/SettingsSetupStep.tsx +176 -0
- package/src/editor/field-types/InternalLinkFieldEditor.tsx +3 -1
- package/src/editor/field-types/RichTextEditorComponent.tsx +0 -1
- package/src/editor/field-types/richtext/components/ReactSlate.tsx +14 -6
- package/src/editor/field-types/richtext/utils/profileServiceCache.ts +42 -32
- package/src/editor/menubar/toolbar-sections/CompareControls.tsx +1 -0
- package/src/editor/menubar/toolbar-sections/EditControls.tsx +1 -0
- package/src/editor/menubar/toolbar-sections/ViewportControls.tsx +1 -0
- package/src/editor/page-editor-chrome/InlineEditor.tsx +29 -6
- package/src/editor/page-viewer/EditorForm.tsx +13 -2
- package/src/editor/page-viewer/PageViewerFrame.tsx +4 -0
- package/src/editor/pageModel.ts +1 -0
- package/src/editor/reviews/Comment.tsx +1 -1
- package/src/editor/reviews/CommentDisplayPopover.tsx +2 -22
- package/src/editor/reviews/CommentPopover.tsx +3 -24
- package/src/editor/reviews/CommentView.tsx +3 -2
- package/src/editor/reviews/Comments.tsx +162 -35
- package/src/editor/reviews/commentAi.ts +5 -0
- package/src/editor/sidebar/Debug.tsx +1 -5
- package/src/editor/sidebar/ViewSelector.tsx +144 -28
- package/src/editor/ui/Icons.tsx +55 -0
- package/src/editor/utils.ts +33 -0
- package/src/revision.ts +2 -2
- package/src/splash-screen/SplashScreen.tsx +5 -6
- package/src/types.ts +3 -0
|
@@ -35,7 +35,7 @@ import { AgentCostDisplay } from "./AgentCostDisplay";
|
|
|
35
35
|
import { Message } from "./AiTerminal";
|
|
36
36
|
import { getComponentById } from "../componentTreeHelper";
|
|
37
37
|
import { Comment } from "../../types";
|
|
38
|
-
import { AiProfile
|
|
38
|
+
import { AiProfile } from "../services/aiService";
|
|
39
39
|
import {
|
|
40
40
|
Popover,
|
|
41
41
|
PopoverContent,
|
|
@@ -179,9 +179,11 @@ const convertAgentMessagesToAiFormat = (
|
|
|
179
179
|
export function AgentTerminal({
|
|
180
180
|
agentStub,
|
|
181
181
|
initialMetadata,
|
|
182
|
+
profiles,
|
|
182
183
|
}: {
|
|
183
184
|
agentStub: Agent;
|
|
184
185
|
initialMetadata?: AgentMetadata;
|
|
186
|
+
profiles: AiProfile[];
|
|
185
187
|
}) {
|
|
186
188
|
const editContext = useEditContext();
|
|
187
189
|
const fieldsContext = useFieldsEditContext();
|
|
@@ -245,7 +247,6 @@ export function AgentTerminal({
|
|
|
245
247
|
});
|
|
246
248
|
const [currentHistoryIndex, setCurrentHistoryIndex] = useState<number>(-1);
|
|
247
249
|
const [showPredefined, setShowPredefined] = useState(false);
|
|
248
|
-
const [profiles, setProfiles] = useState<AiProfile[]>([]);
|
|
249
250
|
const [activeProfile, setActiveProfile] = useState<AiProfile | undefined>(
|
|
250
251
|
undefined,
|
|
251
252
|
);
|
|
@@ -909,48 +910,102 @@ export function AgentTerminal({
|
|
|
909
910
|
setIsLoading(false);
|
|
910
911
|
|
|
911
912
|
// Initialize local context for a brand-new agent (not yet persisted)
|
|
912
|
-
//
|
|
913
|
+
// Seed with current page/selection/focused field. If initialMetadata is provided (e.g., profile only), merge context in.
|
|
914
|
+
const item = editContext?.currentItemDescriptor;
|
|
915
|
+
const localCtx: AgentMetadata | null = item
|
|
916
|
+
? {
|
|
917
|
+
additionalData: {
|
|
918
|
+
context: {
|
|
919
|
+
pages: [
|
|
920
|
+
{
|
|
921
|
+
id: item.id,
|
|
922
|
+
language: item.language,
|
|
923
|
+
version: item.version,
|
|
924
|
+
name: editContext?.contentEditorItem?.name,
|
|
925
|
+
},
|
|
926
|
+
],
|
|
927
|
+
componentIds: editContext?.selection?.length
|
|
928
|
+
? editContext.selection
|
|
929
|
+
: undefined,
|
|
930
|
+
field:
|
|
931
|
+
fieldsContext?.focusedField?.fieldId &&
|
|
932
|
+
(fieldsContext.focusedField as any)?.item?.id
|
|
933
|
+
? {
|
|
934
|
+
fieldId: fieldsContext.focusedField.fieldId,
|
|
935
|
+
itemId: (fieldsContext.focusedField as any).item.id,
|
|
936
|
+
name: (fieldsContext.focusedField as any).fieldName,
|
|
937
|
+
}
|
|
938
|
+
: undefined,
|
|
939
|
+
},
|
|
940
|
+
},
|
|
941
|
+
}
|
|
942
|
+
: null;
|
|
943
|
+
|
|
944
|
+
let nextMetadata: AgentMetadata | null = null;
|
|
913
945
|
if (initialMetadata) {
|
|
914
|
-
|
|
946
|
+
// Merge initial metadata (e.g., profile) with local context
|
|
947
|
+
const base: AgentMetadata = {
|
|
948
|
+
...(initialMetadata as any),
|
|
949
|
+
additionalData: {
|
|
950
|
+
...((initialMetadata as any)?.additionalData || {}),
|
|
951
|
+
context: {
|
|
952
|
+
...(((initialMetadata as any)?.additionalData
|
|
953
|
+
?.context as any) || {}),
|
|
954
|
+
},
|
|
955
|
+
},
|
|
956
|
+
} as AgentMetadata;
|
|
957
|
+
|
|
958
|
+
if (localCtx?.additionalData?.context) {
|
|
959
|
+
const ctx = base.additionalData!.context as any;
|
|
960
|
+
const local = localCtx.additionalData!.context as any;
|
|
961
|
+
// Merge pages (avoid duplicates)
|
|
962
|
+
if (local.pages && local.pages.length) {
|
|
963
|
+
const existing = new Set(
|
|
964
|
+
(ctx.pages || []).map(
|
|
965
|
+
(p: any) => `${p.id}-${p.language}-${p.version}`,
|
|
966
|
+
),
|
|
967
|
+
);
|
|
968
|
+
const mergedPages = [
|
|
969
|
+
...(ctx.pages || []),
|
|
970
|
+
...local.pages.filter(
|
|
971
|
+
(p: any) =>
|
|
972
|
+
!existing.has(`${p.id}-${p.language}-${p.version}`),
|
|
973
|
+
),
|
|
974
|
+
];
|
|
975
|
+
if (mergedPages.length) ctx.pages = mergedPages;
|
|
976
|
+
}
|
|
977
|
+
// Merge componentIds
|
|
978
|
+
if (local.componentIds && local.componentIds.length) {
|
|
979
|
+
const existingIds = new Set(ctx.componentIds || []);
|
|
980
|
+
const mergedIds = [
|
|
981
|
+
...(ctx.componentIds || []),
|
|
982
|
+
...local.componentIds.filter(
|
|
983
|
+
(id: string) => !existingIds.has(id),
|
|
984
|
+
),
|
|
985
|
+
];
|
|
986
|
+
if (mergedIds.length) ctx.componentIds = mergedIds;
|
|
987
|
+
}
|
|
988
|
+
// Set field if missing
|
|
989
|
+
if (!ctx.field && local.field) {
|
|
990
|
+
ctx.field = local.field;
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
|
|
994
|
+
nextMetadata = base;
|
|
995
|
+
} else {
|
|
996
|
+
nextMetadata = localCtx;
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
if (nextMetadata) {
|
|
1000
|
+
setAgentMetadata(nextMetadata);
|
|
915
1001
|
// If an initial prompt is provided via metadata, seed the input once
|
|
916
1002
|
try {
|
|
917
|
-
const maybePrompt = (
|
|
1003
|
+
const maybePrompt = (nextMetadata as any)?.additionalData
|
|
918
1004
|
?.initialPrompt;
|
|
919
1005
|
if (typeof maybePrompt === "string" && maybePrompt.trim()) {
|
|
920
1006
|
setPrompt(maybePrompt);
|
|
921
1007
|
}
|
|
922
1008
|
} catch {}
|
|
923
|
-
} else {
|
|
924
|
-
const item = editContext?.currentItemDescriptor;
|
|
925
|
-
const initialLocalContext: AgentMetadata | null = item
|
|
926
|
-
? {
|
|
927
|
-
additionalData: {
|
|
928
|
-
context: {
|
|
929
|
-
pages: [
|
|
930
|
-
{
|
|
931
|
-
id: item.id,
|
|
932
|
-
language: item.language,
|
|
933
|
-
version: item.version,
|
|
934
|
-
name: editContext?.contentEditorItem?.name,
|
|
935
|
-
},
|
|
936
|
-
],
|
|
937
|
-
componentIds: editContext?.selection?.length
|
|
938
|
-
? editContext.selection
|
|
939
|
-
: undefined,
|
|
940
|
-
field:
|
|
941
|
-
fieldsContext?.focusedField?.fieldId &&
|
|
942
|
-
(fieldsContext.focusedField as any)?.item?.id
|
|
943
|
-
? {
|
|
944
|
-
fieldId: fieldsContext.focusedField.fieldId,
|
|
945
|
-
itemId: (fieldsContext.focusedField as any).item.id,
|
|
946
|
-
name: (fieldsContext.focusedField as any).fieldName,
|
|
947
|
-
}
|
|
948
|
-
: undefined,
|
|
949
|
-
},
|
|
950
|
-
},
|
|
951
|
-
}
|
|
952
|
-
: null;
|
|
953
|
-
if (initialLocalContext) setAgentMetadata(initialLocalContext);
|
|
954
1009
|
}
|
|
955
1010
|
return;
|
|
956
1011
|
}
|
|
@@ -1052,23 +1107,7 @@ export function AgentTerminal({
|
|
|
1052
1107
|
);
|
|
1053
1108
|
}, []);
|
|
1054
1109
|
|
|
1055
|
-
//
|
|
1056
|
-
useEffect(() => {
|
|
1057
|
-
let cancelled = false;
|
|
1058
|
-
(async () => {
|
|
1059
|
-
try {
|
|
1060
|
-
if (!editContext?.currentItemDescriptor) return;
|
|
1061
|
-
const fetched = await loadAiProfiles(editContext.currentItemDescriptor);
|
|
1062
|
-
if (cancelled) return;
|
|
1063
|
-
setProfiles(fetched || []);
|
|
1064
|
-
} catch (e) {
|
|
1065
|
-
console.error("Failed to load AI profiles", e);
|
|
1066
|
-
}
|
|
1067
|
-
})();
|
|
1068
|
-
return () => {
|
|
1069
|
-
cancelled = true;
|
|
1070
|
-
};
|
|
1071
|
-
}, [editContext?.currentItemDescriptor]);
|
|
1110
|
+
// Profiles are provided by parent component (Agents). No local loading here.
|
|
1072
1111
|
|
|
1073
1112
|
// Select active profile based on agent.profileId or default to first
|
|
1074
1113
|
useEffect(() => {
|
|
@@ -1121,6 +1160,17 @@ export function AgentTerminal({
|
|
|
1121
1160
|
|
|
1122
1161
|
if (!agentId) return;
|
|
1123
1162
|
|
|
1163
|
+
const shouldAddTodoFormat = /\b(to-?do|check\s*list|task\s*list)\b/i.test(
|
|
1164
|
+
prompt,
|
|
1165
|
+
);
|
|
1166
|
+
const todoFormatInstructions =
|
|
1167
|
+
"If you produce a to-do list, output it as a 'todo_list' JSON block. Prefer one of these two forms only, with no extra commentary before/after it: \n" +
|
|
1168
|
+
'```todo_list\n{ "title": "<optional title>", "items": [ { "text": "<task>", "done": false, "note": "<optional>" } ] }\n```\n' +
|
|
1169
|
+
"or a plain header: todo_list: { ... }. Include only fields: title (optional), items (array of {text, done?, note?}).";
|
|
1170
|
+
const finalMessageForAgent = shouldAddTodoFormat
|
|
1171
|
+
? `${prompt.trim()}\n\n${todoFormatInstructions}`
|
|
1172
|
+
: prompt.trim();
|
|
1173
|
+
|
|
1124
1174
|
// Add user message to local state immediately for better UX
|
|
1125
1175
|
const userMessage: AgentChatMessage = {
|
|
1126
1176
|
id: `user-${Date.now()}`,
|
|
@@ -1147,20 +1197,17 @@ export function AgentTerminal({
|
|
|
1147
1197
|
setMessages((prev) => [...prev, userMessage]);
|
|
1148
1198
|
|
|
1149
1199
|
const metaCtx = (agentMetadata as any)?.additionalData?.context as
|
|
1150
|
-
| { componentIds?: string[] }
|
|
1200
|
+
| { componentIds?: string[]; comment?: { selectedText?: string } }
|
|
1151
1201
|
| undefined;
|
|
1152
1202
|
const selectionFromCtx = metaCtx?.componentIds?.length
|
|
1153
1203
|
? metaCtx.componentIds
|
|
1154
1204
|
: undefined;
|
|
1155
|
-
const effectiveSelection = selectionFromCtx
|
|
1156
|
-
|
|
1157
|
-
: editContext.selection && editContext.selection.length > 0
|
|
1158
|
-
? editContext.selection
|
|
1159
|
-
: undefined;
|
|
1205
|
+
const effectiveSelection = selectionFromCtx;
|
|
1206
|
+
const selectedTextFromCtx = metaCtx?.comment?.selectedText || undefined;
|
|
1160
1207
|
|
|
1161
1208
|
const request: StartAgentRequest = {
|
|
1162
1209
|
agentId: agent.id,
|
|
1163
|
-
message:
|
|
1210
|
+
message: finalMessageForAgent,
|
|
1164
1211
|
sessionId: editContext.sessionId,
|
|
1165
1212
|
profileId: activeProfile?.id || "default",
|
|
1166
1213
|
profile: activeProfile?.name || "default",
|
|
@@ -1169,7 +1216,7 @@ export function AgentTerminal({
|
|
|
1169
1216
|
language: editContext.currentItemDescriptor?.language || "en",
|
|
1170
1217
|
version: editContext.currentItemDescriptor?.version || 1,
|
|
1171
1218
|
selection: effectiveSelection,
|
|
1172
|
-
selectedText:
|
|
1219
|
+
selectedText: selectedTextFromCtx,
|
|
1173
1220
|
addSelectedComponents: !!effectiveSelection?.length,
|
|
1174
1221
|
addContextContent: false,
|
|
1175
1222
|
addAllContent: false,
|
|
@@ -1296,16 +1343,13 @@ export function AgentTerminal({
|
|
|
1296
1343
|
setMessages((prev) => [...prev, userMessage]);
|
|
1297
1344
|
|
|
1298
1345
|
const metaCtx = (agentMetadata as any)?.additionalData?.context as
|
|
1299
|
-
| { componentIds?: string[] }
|
|
1346
|
+
| { componentIds?: string[]; comment?: { selectedText?: string } }
|
|
1300
1347
|
| undefined;
|
|
1301
1348
|
const selectionFromCtx = metaCtx?.componentIds?.length
|
|
1302
1349
|
? metaCtx.componentIds
|
|
1303
1350
|
: undefined;
|
|
1304
|
-
const effectiveSelection = selectionFromCtx
|
|
1305
|
-
|
|
1306
|
-
: editContext.selection && editContext.selection.length > 0
|
|
1307
|
-
? editContext.selection
|
|
1308
|
-
: undefined;
|
|
1351
|
+
const effectiveSelection = selectionFromCtx;
|
|
1352
|
+
const selectedTextFromCtx = metaCtx?.comment?.selectedText || undefined;
|
|
1309
1353
|
|
|
1310
1354
|
const request: StartAgentRequest = {
|
|
1311
1355
|
agentId: agent.id,
|
|
@@ -1318,7 +1362,7 @@ export function AgentTerminal({
|
|
|
1318
1362
|
language: editContext.currentItemDescriptor?.language || "en",
|
|
1319
1363
|
version: editContext.currentItemDescriptor?.version || 1,
|
|
1320
1364
|
selection: effectiveSelection,
|
|
1321
|
-
selectedText:
|
|
1365
|
+
selectedText: selectedTextFromCtx,
|
|
1322
1366
|
addSelectedComponents: !!effectiveSelection?.length,
|
|
1323
1367
|
addContextContent: false,
|
|
1324
1368
|
addAllContent: false,
|
|
@@ -1957,12 +2001,12 @@ export function AgentTerminal({
|
|
|
1957
2001
|
})}
|
|
1958
2002
|
</div>
|
|
1959
2003
|
|
|
1960
|
-
{/* Show dancing dots only after 1s of inactivity */}
|
|
1961
|
-
{showDots && <DancingDots />}
|
|
1962
|
-
|
|
1963
2004
|
<div ref={messagesEndRef} />
|
|
1964
2005
|
</div>
|
|
1965
2006
|
|
|
2007
|
+
{/* Show dancing dots only after 1s of inactivity */}
|
|
2008
|
+
{showDots && <DancingDots />}
|
|
2009
|
+
|
|
1966
2010
|
{/* Context Info Bar */}
|
|
1967
2011
|
{renderContextInfoBar()}
|
|
1968
2012
|
|
|
@@ -1982,6 +2026,7 @@ export function AgentTerminal({
|
|
|
1982
2026
|
onKeyDown={handleKeyPress}
|
|
1983
2027
|
placeholder="Type your message... (Enter to send, Ctrl+Enter for new line)"
|
|
1984
2028
|
className="h-[80px] flex-1 resize-none overflow-y-auto text-xs"
|
|
2029
|
+
data-testid="agent-terminal-prompt"
|
|
1985
2030
|
disabled={isSubmitting}
|
|
1986
2031
|
/>
|
|
1987
2032
|
</div>
|
|
@@ -1998,6 +2043,7 @@ export function AgentTerminal({
|
|
|
1998
2043
|
}}
|
|
1999
2044
|
title="Profile"
|
|
2000
2045
|
aria-label="Profile"
|
|
2046
|
+
data-testid="agent-profile-select"
|
|
2001
2047
|
>
|
|
2002
2048
|
{profiles.map((p) => (
|
|
2003
2049
|
<option key={p.id} value={p.id}>
|
|
@@ -2013,6 +2059,7 @@ export function AgentTerminal({
|
|
|
2013
2059
|
onChange={(e) => setSelectedModelId(e.target.value)}
|
|
2014
2060
|
title="Model"
|
|
2015
2061
|
aria-label="Model"
|
|
2062
|
+
data-testid="agent-model-select"
|
|
2016
2063
|
>
|
|
2017
2064
|
{activeProfile.models.map((m) => (
|
|
2018
2065
|
<option key={m.id} value={m.id}>
|
package/src/editor/ai/Agents.tsx
CHANGED
|
@@ -58,6 +58,7 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
58
58
|
const [agents, setAgents] = useState<Agent[]>([]);
|
|
59
59
|
const [activeAgentId, setActiveAgentId] = useState<string | null>(null);
|
|
60
60
|
const activeAgentIdRef = useRef<string | null>(null);
|
|
61
|
+
const singleAgentModeRef = useRef<boolean>(false);
|
|
61
62
|
const [historyPopoverOpen, setHistoryPopoverOpen] = useState(false);
|
|
62
63
|
const [menuPopoverOpen, setMenuPopoverOpen] = useState(false);
|
|
63
64
|
const [addPopoverOpen, setAddPopoverOpen] = useState(false);
|
|
@@ -73,6 +74,16 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
73
74
|
|
|
74
75
|
const editContext = useEditContext();
|
|
75
76
|
|
|
77
|
+
// Detect single-agent mode from query parameter once on mount
|
|
78
|
+
useEffect(() => {
|
|
79
|
+
try {
|
|
80
|
+
const params = new URLSearchParams(window.location.search);
|
|
81
|
+
const value = params.get("singleAgent");
|
|
82
|
+
singleAgentModeRef.current =
|
|
83
|
+
value === "true" || params.has("singleAgent");
|
|
84
|
+
} catch {}
|
|
85
|
+
}, []);
|
|
86
|
+
|
|
76
87
|
// Helper function to filter agents by name
|
|
77
88
|
const getFilteredInactiveAgents = (): Agent[] => {
|
|
78
89
|
if (!historyFilter.trim()) {
|
|
@@ -139,6 +150,29 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
139
150
|
};
|
|
140
151
|
}, [addPopoverOpen, agents.length, editContext?.currentItemDescriptor]);
|
|
141
152
|
|
|
153
|
+
// Ensure profiles are loaded once for terminals (centralized load)
|
|
154
|
+
useEffect(() => {
|
|
155
|
+
let cancelled = false;
|
|
156
|
+
(async () => {
|
|
157
|
+
try {
|
|
158
|
+
if (!editContext?.currentItemDescriptor) return;
|
|
159
|
+
setLoadingProfiles(true);
|
|
160
|
+
const profiles = await loadAiProfiles(
|
|
161
|
+
editContext.currentItemDescriptor,
|
|
162
|
+
);
|
|
163
|
+
if (cancelled) return;
|
|
164
|
+
setAvailableProfiles(profiles || []);
|
|
165
|
+
} catch (e) {
|
|
166
|
+
console.error("Failed to load AI profiles", e);
|
|
167
|
+
} finally {
|
|
168
|
+
if (!cancelled) setLoadingProfiles(false);
|
|
169
|
+
}
|
|
170
|
+
})();
|
|
171
|
+
return () => {
|
|
172
|
+
cancelled = true;
|
|
173
|
+
};
|
|
174
|
+
}, [editContext?.currentItemDescriptor]);
|
|
175
|
+
|
|
142
176
|
// Listen for external requests to add a new agent (e.g., AI command)
|
|
143
177
|
useEffect(() => {
|
|
144
178
|
const handleAddNewAgent = (ev: Event) => {
|
|
@@ -229,6 +263,15 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
229
263
|
|
|
230
264
|
const loadAgentsFromBackend = async () => {
|
|
231
265
|
try {
|
|
266
|
+
// In single-agent mode, skip loading any pre-existing/open agents or history
|
|
267
|
+
if (singleAgentModeRef.current) {
|
|
268
|
+
setAgents([]);
|
|
269
|
+
setInactiveAgents([]);
|
|
270
|
+
setActiveAgentIdWithStorage(null);
|
|
271
|
+
setLoadingAgents(false);
|
|
272
|
+
return;
|
|
273
|
+
}
|
|
274
|
+
|
|
232
275
|
setLoadingAgents(true);
|
|
233
276
|
|
|
234
277
|
// Load active agents
|
|
@@ -458,6 +501,7 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
458
501
|
createAgentWithSelectedProfile(value);
|
|
459
502
|
}}
|
|
460
503
|
aria-label="Profile"
|
|
504
|
+
data-testid="agents-empty-profile-select"
|
|
461
505
|
>
|
|
462
506
|
<option value="">Select a profile…</option>
|
|
463
507
|
{availableProfiles.map((p) => (
|
|
@@ -676,7 +720,11 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
676
720
|
className="text-gray-600 hover:text-gray-800"
|
|
677
721
|
/>
|
|
678
722
|
</PopoverTrigger>
|
|
679
|
-
<PopoverContent
|
|
723
|
+
<PopoverContent
|
|
724
|
+
className="w-72 p-3"
|
|
725
|
+
align="end"
|
|
726
|
+
data-testid="agents-add-popover"
|
|
727
|
+
>
|
|
680
728
|
<div className="mb-2 text-xs font-medium text-gray-600">
|
|
681
729
|
Select profile
|
|
682
730
|
</div>
|
|
@@ -689,6 +737,8 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
689
737
|
key={p.id}
|
|
690
738
|
onClick={() => createAgentWithSelectedProfile(p.id)}
|
|
691
739
|
className="w-full cursor-pointer rounded px-3 py-2 text-left text-xs hover:bg-gray-50"
|
|
740
|
+
data-testid="agents-add-profile-option"
|
|
741
|
+
data-profile-id={p.id}
|
|
692
742
|
>
|
|
693
743
|
{p.name}
|
|
694
744
|
</button>
|
|
@@ -722,6 +772,7 @@ export function Agents({ closeButton }: { closeButton?: React.ReactNode }) {
|
|
|
722
772
|
<AgentTerminal
|
|
723
773
|
agentStub={agent}
|
|
724
774
|
initialMetadata={initialMetadataMap[agent.id]}
|
|
775
|
+
profiles={availableProfiles}
|
|
725
776
|
/>
|
|
726
777
|
</div>
|
|
727
778
|
))}
|