@alpaca-editor/core 1.0.4174 → 1.0.4176
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/AgentsView.js +0 -20
- package/dist/agents-view/AgentsView.js.map +1 -1
- package/dist/editor/QuickItemSwitcher.js +5 -1
- package/dist/editor/QuickItemSwitcher.js.map +1 -1
- package/dist/editor/ai/AgentTerminal.js +47 -83
- package/dist/editor/ai/AgentTerminal.js.map +1 -1
- package/dist/editor/ai/Agents.js +7 -5
- package/dist/editor/ai/Agents.js.map +1 -1
- package/dist/editor/ai/AiResponseMessage.js +1 -1
- package/dist/editor/ai/AiResponseMessage.js.map +1 -1
- package/dist/editor/ai/ContextInfoBar.js +30 -64
- package/dist/editor/ai/ContextInfoBar.js.map +1 -1
- package/dist/editor/ai/useAgentStatus.js +81 -2
- package/dist/editor/ai/useAgentStatus.js.map +1 -1
- package/dist/editor/client/EditorShell.js +44 -7
- package/dist/editor/client/EditorShell.js.map +1 -1
- package/dist/editor/client/operations.js +30 -3
- package/dist/editor/client/operations.js.map +1 -1
- package/dist/editor/control-center/WebSocketMessages.js +0 -1
- package/dist/editor/control-center/WebSocketMessages.js.map +1 -1
- package/dist/editor/page-viewer/PageViewerFrame.js +14 -3
- package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
- package/dist/editor/reviews/commentAi.js +43 -32
- package/dist/editor/reviews/commentAi.js.map +1 -1
- package/dist/editor/services/agentService.d.ts +8 -4
- package/dist/editor/services/agentService.js +30 -53
- package/dist/editor/services/agentService.js.map +1 -1
- package/dist/editor/services/aiService.d.ts +19 -1
- package/dist/editor/services/aiService.js +75 -2
- package/dist/editor/services/aiService.js.map +1 -1
- package/dist/page-wizard/steps/ContentStep.js +29 -57
- package/dist/page-wizard/steps/ContentStep.js.map +1 -1
- package/dist/page-wizard/steps/MetaDataStep.js +14 -23
- package/dist/page-wizard/steps/MetaDataStep.js.map +1 -1
- package/dist/page-wizard/steps/SelectStep.js +12 -42
- package/dist/page-wizard/steps/SelectStep.js.map +1 -1
- package/dist/revision.d.ts +2 -2
- package/dist/revision.js +2 -2
- package/dist/styles.css +0 -8
- package/package.json +1 -1
- package/src/agents-view/AgentsView.tsx +1 -21
- package/src/editor/QuickItemSwitcher.tsx +23 -19
- package/src/editor/ai/AgentTerminal.tsx +83 -142
- package/src/editor/ai/Agents.tsx +9 -6
- package/src/editor/ai/AiResponseMessage.tsx +5 -1
- package/src/editor/ai/ContextInfoBar.tsx +34 -75
- package/src/editor/ai/useAgentStatus.ts +82 -4
- package/src/editor/client/EditorShell.tsx +62 -9
- package/src/editor/client/operations.ts +42 -4
- package/src/editor/control-center/WebSocketMessages.tsx +5 -1
- package/src/editor/page-viewer/PageViewerFrame.tsx +15 -2
- package/src/editor/reviews/commentAi.ts +48 -36
- package/src/editor/services/agentService.ts +38 -55
- package/src/editor/services/aiService.ts +104 -3
- package/src/page-wizard/steps/ContentStep.tsx +47 -81
- package/src/page-wizard/steps/MetaDataStep.tsx +52 -60
- package/src/page-wizard/steps/SelectStep.tsx +13 -51
- package/src/revision.ts +2 -2
|
@@ -169,12 +169,16 @@ export type AgentContextData = {
|
|
|
169
169
|
name?: string;
|
|
170
170
|
};
|
|
171
171
|
}>;
|
|
172
|
-
/** @deprecated Use components instead to get page information per component */
|
|
173
|
-
componentIds?: string[];
|
|
174
172
|
field?: {
|
|
175
173
|
fieldId: string;
|
|
176
|
-
|
|
177
|
-
|
|
174
|
+
fieldName?: string;
|
|
175
|
+
item?: {
|
|
176
|
+
id: string;
|
|
177
|
+
language: string;
|
|
178
|
+
version: number;
|
|
179
|
+
path?: string;
|
|
180
|
+
name?: string;
|
|
181
|
+
};
|
|
178
182
|
};
|
|
179
183
|
comment?: {
|
|
180
184
|
id: string;
|
|
@@ -842,71 +846,63 @@ export function canonicalizeAgentMetadata(
|
|
|
842
846
|
}
|
|
843
847
|
}
|
|
844
848
|
|
|
845
|
-
// Process
|
|
849
|
+
// Process items
|
|
846
850
|
const allPages: any[] = [];
|
|
847
|
-
if (Array.isArray(m.pages)) allPages.push(...m.pages); // legacy
|
|
848
851
|
if (Array.isArray(m.items)) allPages.push(...m.items);
|
|
849
852
|
for (const ctx of contextSources) {
|
|
850
|
-
if (Array.isArray(ctx.pages)) allPages.push(...ctx.pages); // legacy
|
|
851
853
|
if (Array.isArray(ctx.items)) allPages.push(...ctx.items);
|
|
852
854
|
}
|
|
853
855
|
if (allPages.length > 0) {
|
|
854
856
|
const dedup: any[] = [];
|
|
855
857
|
const seen = new Set<string>();
|
|
856
858
|
for (const p of allPages) {
|
|
857
|
-
const id = p?.id
|
|
859
|
+
const id = p?.id;
|
|
858
860
|
if (!id) continue;
|
|
859
|
-
const lang = (p?.language ??
|
|
860
|
-
const ver = (p?.version ??
|
|
861
|
+
const lang = (p?.language ?? "").toString();
|
|
862
|
+
const ver = (p?.version ?? "").toString();
|
|
861
863
|
const key = `${String(id)}-${lang}-${ver}`.toLowerCase();
|
|
862
864
|
if (seen.has(key)) continue;
|
|
863
865
|
seen.add(key);
|
|
864
866
|
dedup.push({
|
|
865
867
|
id: String(id),
|
|
866
|
-
language: p?.language
|
|
867
|
-
version: p?.version
|
|
868
|
-
name: p?.name
|
|
869
|
-
path: p?.path
|
|
868
|
+
language: p?.language,
|
|
869
|
+
version: p?.version,
|
|
870
|
+
name: p?.name,
|
|
871
|
+
path: p?.path,
|
|
870
872
|
});
|
|
871
873
|
}
|
|
872
874
|
m.items = dedup;
|
|
873
875
|
} else {
|
|
874
|
-
// Clear both if no items
|
|
875
876
|
delete m.items;
|
|
876
877
|
}
|
|
877
878
|
|
|
878
|
-
//
|
|
879
|
-
delete m.pages;
|
|
880
|
-
|
|
881
|
-
// Process components with page info (new structure)
|
|
879
|
+
// Process components with page info
|
|
882
880
|
const allComponents: any[] = [];
|
|
883
881
|
if (Array.isArray(m.components)) allComponents.push(...m.components);
|
|
884
|
-
if (Array.isArray(m.Components)) allComponents.push(...m.Components);
|
|
885
882
|
for (const ctx of contextSources) {
|
|
886
883
|
if (Array.isArray(ctx.components)) allComponents.push(...ctx.components);
|
|
887
|
-
if (Array.isArray(ctx.Components)) allComponents.push(...ctx.Components);
|
|
888
884
|
}
|
|
889
885
|
if (allComponents.length > 0) {
|
|
890
886
|
const dedup: any[] = [];
|
|
891
887
|
const seen = new Set<string>();
|
|
892
888
|
for (const c of allComponents) {
|
|
893
889
|
if (!c) continue;
|
|
894
|
-
const componentId = c.componentId
|
|
890
|
+
const componentId = c.componentId;
|
|
895
891
|
if (!componentId || typeof componentId !== "string") continue;
|
|
896
892
|
const key = componentId.toLowerCase();
|
|
897
893
|
if (seen.has(key)) continue;
|
|
898
894
|
seen.add(key);
|
|
899
895
|
|
|
900
|
-
const pageItem = c.pageItem
|
|
896
|
+
const pageItem = c.pageItem;
|
|
901
897
|
dedup.push({
|
|
902
898
|
componentId: String(componentId),
|
|
903
899
|
pageItem: pageItem
|
|
904
900
|
? {
|
|
905
|
-
id: String(pageItem.id ??
|
|
906
|
-
language: pageItem.language
|
|
907
|
-
version: pageItem.version
|
|
908
|
-
name: pageItem.name
|
|
909
|
-
path: pageItem.path
|
|
901
|
+
id: String(pageItem.id ?? ""),
|
|
902
|
+
language: pageItem.language,
|
|
903
|
+
version: pageItem.version,
|
|
904
|
+
name: pageItem.name,
|
|
905
|
+
path: pageItem.path,
|
|
910
906
|
}
|
|
911
907
|
: undefined,
|
|
912
908
|
});
|
|
@@ -914,35 +910,25 @@ export function canonicalizeAgentMetadata(
|
|
|
914
910
|
m.components = dedup;
|
|
915
911
|
}
|
|
916
912
|
|
|
917
|
-
// Process
|
|
918
|
-
const allComponentIds: any[] = [];
|
|
919
|
-
if (Array.isArray(m.componentIds)) allComponentIds.push(...m.componentIds);
|
|
913
|
+
// Process field - merge/complete from context sources if needed
|
|
920
914
|
for (const ctx of contextSources) {
|
|
921
|
-
if (
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
if (allComponentIds.length > 0) {
|
|
925
|
-
const ids = allComponentIds
|
|
926
|
-
.map((x) => (typeof x === "string" ? x : (x?.id ?? x?.Id)))
|
|
927
|
-
.filter((x): x is string => !!x && typeof x === "string");
|
|
928
|
-
m.componentIds = Array.from(new Set(ids));
|
|
929
|
-
}
|
|
930
|
-
|
|
931
|
-
// Process field
|
|
932
|
-
if (!m.field) {
|
|
933
|
-
for (const ctx of contextSources) {
|
|
934
|
-
if (ctx.field) {
|
|
915
|
+
if (ctx.field) {
|
|
916
|
+
// If field doesn't exist, create it from context
|
|
917
|
+
if (!m.field) {
|
|
935
918
|
m.field = {
|
|
936
|
-
fieldId:
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
ctx.field.id ??
|
|
940
|
-
ctx.field.Id,
|
|
941
|
-
itemId: ctx.field.itemId ?? ctx.field.ItemId,
|
|
942
|
-
name: ctx.field.name ?? ctx.field.Name,
|
|
919
|
+
fieldId: ctx.field.fieldId,
|
|
920
|
+
fieldName: ctx.field.fieldName,
|
|
921
|
+
item: ctx.field.item,
|
|
943
922
|
};
|
|
944
923
|
break;
|
|
945
924
|
}
|
|
925
|
+
// If field exists but is incomplete, fill in missing properties
|
|
926
|
+
if (m.field && !m.field.item && ctx.field.item) {
|
|
927
|
+
m.field.item = ctx.field.item;
|
|
928
|
+
}
|
|
929
|
+
if (m.field && !m.field.fieldName && ctx.field.fieldName) {
|
|
930
|
+
m.field.fieldName = ctx.field.fieldName;
|
|
931
|
+
}
|
|
946
932
|
}
|
|
947
933
|
}
|
|
948
934
|
|
|
@@ -967,9 +953,6 @@ export function canonicalizeAgentMetadata(
|
|
|
967
953
|
}
|
|
968
954
|
|
|
969
955
|
m.additionalData = Object.keys(additional).length ? additional : undefined;
|
|
970
|
-
if (Object.prototype.hasOwnProperty.call(m, "AdditionalData")) {
|
|
971
|
-
delete m.AdditionalData;
|
|
972
|
-
}
|
|
973
956
|
|
|
974
957
|
return m as AgentContextData;
|
|
975
958
|
}
|
|
@@ -86,7 +86,8 @@ type Message = {
|
|
|
86
86
|
|
|
87
87
|
export interface ExecutePromptResponse {
|
|
88
88
|
editOperations: any[];
|
|
89
|
-
|
|
89
|
+
content: string;
|
|
90
|
+
messages?: Message[];
|
|
90
91
|
numInputTokens: number;
|
|
91
92
|
numOutputTokens: number;
|
|
92
93
|
numCachedTokens: number;
|
|
@@ -184,23 +185,25 @@ export async function executePrompt(
|
|
|
184
185
|
};
|
|
185
186
|
|
|
186
187
|
// Use migrated endpoint under agent controller
|
|
187
|
-
const endpoint = options.endpoint || "/alpaca/editor/
|
|
188
|
+
const endpoint = options.endpoint || "/alpaca/editor/page-wizard/prompt";
|
|
188
189
|
|
|
189
190
|
const response = await fetch(endpoint, finalRequestOptions);
|
|
190
191
|
|
|
191
192
|
if (!response.ok) {
|
|
192
193
|
// Always return rich error format
|
|
193
194
|
const text = await response.text();
|
|
195
|
+
const errorContent = "There was an error processing your request: " + text;
|
|
194
196
|
return {
|
|
195
197
|
messages: [
|
|
196
198
|
{
|
|
197
|
-
content:
|
|
199
|
+
content: errorContent,
|
|
198
200
|
name: "assistant",
|
|
199
201
|
role: "assistant",
|
|
200
202
|
id: crypto.randomUUID(),
|
|
201
203
|
tool_calls: [],
|
|
202
204
|
},
|
|
203
205
|
],
|
|
206
|
+
content: errorContent,
|
|
204
207
|
editOperations: [],
|
|
205
208
|
numInputTokens: 0,
|
|
206
209
|
numOutputTokens: 0,
|
|
@@ -330,6 +333,104 @@ export async function executePrompt(
|
|
|
330
333
|
return result;
|
|
331
334
|
}
|
|
332
335
|
|
|
336
|
+
/**
|
|
337
|
+
* Helper function to parse JSON content from AI response
|
|
338
|
+
* Strips markdown code blocks if present and parses the JSON
|
|
339
|
+
* Handles incomplete markdown blocks during streaming
|
|
340
|
+
*/
|
|
341
|
+
function parseJsonContent<T>(content: string): T {
|
|
342
|
+
let cleanedContent = content;
|
|
343
|
+
|
|
344
|
+
// Strip markdown code blocks if present
|
|
345
|
+
if (cleanedContent.startsWith("```json")) {
|
|
346
|
+
// Remove the opening ```json
|
|
347
|
+
cleanedContent = cleanedContent.substring(7).trim();
|
|
348
|
+
// Remove the closing ``` if present
|
|
349
|
+
if (cleanedContent.endsWith("```")) {
|
|
350
|
+
cleanedContent = cleanedContent
|
|
351
|
+
.substring(0, cleanedContent.length - 3)
|
|
352
|
+
.trim();
|
|
353
|
+
}
|
|
354
|
+
} else if (cleanedContent.startsWith("```")) {
|
|
355
|
+
// Remove the opening ```
|
|
356
|
+
cleanedContent = cleanedContent.substring(3).trim();
|
|
357
|
+
// Remove the closing ``` if present
|
|
358
|
+
if (cleanedContent.endsWith("```")) {
|
|
359
|
+
cleanedContent = cleanedContent
|
|
360
|
+
.substring(0, cleanedContent.length - 3)
|
|
361
|
+
.trim();
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
// Apply JsonCleaner to handle incomplete JSON during streaming
|
|
366
|
+
const cleanupResult = JsonCleaner.cleanupJson(cleanedContent);
|
|
367
|
+
console.log("CLEANED CONTENT: ", cleanupResult.cleanedJson);
|
|
368
|
+
|
|
369
|
+
return JSON.parse(cleanupResult.cleanedJson) as T;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Executes a prompt and returns the parsed JSON result
|
|
374
|
+
* @param messages - The messages to send
|
|
375
|
+
* @param context - The AI context
|
|
376
|
+
* @param options - Execution options
|
|
377
|
+
* @param requestOptions - Additional request options
|
|
378
|
+
* @param callback - Optional callback for streaming responses
|
|
379
|
+
* @param stream - Whether to stream the response
|
|
380
|
+
* @returns The parsed JSON object from the response content
|
|
381
|
+
* @throws Error if the response cannot be parsed or is not in the expected format
|
|
382
|
+
*/
|
|
383
|
+
export async function executePromptWithJsonResult<T = any>(
|
|
384
|
+
messages: Message[],
|
|
385
|
+
context:
|
|
386
|
+
| AiContext
|
|
387
|
+
| {
|
|
388
|
+
editContext: EditContextType;
|
|
389
|
+
createAiContext: ({ editContext }: { editContext: any }) => AiContext;
|
|
390
|
+
},
|
|
391
|
+
options: ExecutePromptOptions = {},
|
|
392
|
+
requestOptions?: RequestInit,
|
|
393
|
+
callback?: (parsedJson: T) => void,
|
|
394
|
+
stream?: boolean,
|
|
395
|
+
): Promise<T> {
|
|
396
|
+
// Wrap the callback to parse JSON before passing to the original callback
|
|
397
|
+
const wrappedCallback = callback
|
|
398
|
+
? (response: any) => {
|
|
399
|
+
if (!response || !response.content) {
|
|
400
|
+
return;
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
try {
|
|
404
|
+
const parsed = parseJsonContent<T>(response.content);
|
|
405
|
+
callback(parsed);
|
|
406
|
+
} catch (parseError) {
|
|
407
|
+
console.error("Error parsing JSON in callback:", parseError);
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
: undefined;
|
|
411
|
+
|
|
412
|
+
const result = await executePrompt(
|
|
413
|
+
messages,
|
|
414
|
+
context,
|
|
415
|
+
options,
|
|
416
|
+
requestOptions,
|
|
417
|
+
wrappedCallback,
|
|
418
|
+
stream,
|
|
419
|
+
);
|
|
420
|
+
|
|
421
|
+
if (!result || !result.content) {
|
|
422
|
+
throw new Error("No content in response");
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
try {
|
|
426
|
+
return parseJsonContent<T>(result.content);
|
|
427
|
+
} catch (parseError) {
|
|
428
|
+
throw new Error(
|
|
429
|
+
`Failed to parse JSON response: ${parseError instanceof Error ? parseError.message : String(parseError)}`,
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
|
|
333
434
|
// moved to searchService.ts
|
|
334
435
|
|
|
335
436
|
export async function generateImage(
|
|
@@ -21,7 +21,10 @@ import { convertPageSchemaToWizardComponents } from "./schema";
|
|
|
21
21
|
import { WizardPageModel } from "../PageWizard";
|
|
22
22
|
import { createWizardAiContext, wipeComponents } from "../service";
|
|
23
23
|
|
|
24
|
-
import {
|
|
24
|
+
import {
|
|
25
|
+
executePrompt,
|
|
26
|
+
executePromptWithJsonResult,
|
|
27
|
+
} from "../../editor/services/aiService";
|
|
25
28
|
import { usePageCreator } from "./usePageCreator";
|
|
26
29
|
import { useThrottledCallback } from "use-debounce";
|
|
27
30
|
import { Textarea } from "../../components/ui/textarea";
|
|
@@ -152,7 +155,10 @@ export function ContentStep({
|
|
|
152
155
|
|
|
153
156
|
console.log("PROMPT (selectTargetItem):", promptContent);
|
|
154
157
|
|
|
155
|
-
const result = await
|
|
158
|
+
const result = await executePromptWithJsonResult<{
|
|
159
|
+
id: string;
|
|
160
|
+
path: string;
|
|
161
|
+
}>(
|
|
156
162
|
[
|
|
157
163
|
{
|
|
158
164
|
content: promptContent,
|
|
@@ -169,16 +175,11 @@ export function ContentStep({
|
|
|
169
175
|
{ signal: abortController.signal },
|
|
170
176
|
(response) => {
|
|
171
177
|
try {
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
path: string;
|
|
175
|
-
};
|
|
176
|
-
|
|
177
|
-
if (folderResult.id && folderResult.path) {
|
|
178
|
-
setFolderSelectionResult(folderResult);
|
|
178
|
+
if (response.id && response.path) {
|
|
179
|
+
setFolderSelectionResult(response);
|
|
179
180
|
// Update target folder with the selected folder
|
|
180
181
|
setTargetFolder({
|
|
181
|
-
id:
|
|
182
|
+
id: response.id,
|
|
182
183
|
language: language,
|
|
183
184
|
} as ItemDescriptor);
|
|
184
185
|
}
|
|
@@ -186,23 +187,13 @@ export function ContentStep({
|
|
|
186
187
|
},
|
|
187
188
|
);
|
|
188
189
|
|
|
189
|
-
if (result && result.
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
if (folderResult.id && folderResult.path) {
|
|
198
|
-
setFolderSelectionResult(folderResult);
|
|
199
|
-
// Update target folder with the selected folder
|
|
200
|
-
setTargetFolder({
|
|
201
|
-
id: folderResult.id,
|
|
202
|
-
language: language,
|
|
203
|
-
} as ItemDescriptor);
|
|
204
|
-
}
|
|
205
|
-
}
|
|
190
|
+
if (result && result.id && result.path) {
|
|
191
|
+
setFolderSelectionResult(result);
|
|
192
|
+
// Update target folder with the selected folder
|
|
193
|
+
setTargetFolder({
|
|
194
|
+
id: result.id,
|
|
195
|
+
language: language,
|
|
196
|
+
} as ItemDescriptor);
|
|
206
197
|
}
|
|
207
198
|
} catch (error) {
|
|
208
199
|
console.error("Error selecting target folder", error);
|
|
@@ -288,38 +279,30 @@ export function ContentStep({
|
|
|
288
279
|
|
|
289
280
|
console.log("PROMPT (generatePageName):", promptContent);
|
|
290
281
|
|
|
291
|
-
const
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
282
|
+
const pageModelResult =
|
|
283
|
+
await executePromptWithJsonResult<WizardPageModel>(
|
|
284
|
+
[
|
|
285
|
+
{
|
|
286
|
+
content: `${processedInstructions?.trim()} Reply with a json object of type PageModel = { name: string; };
|
|
287
|
+
The language of the page is ${language}.`,
|
|
288
|
+
name: "system",
|
|
289
|
+
role: "system",
|
|
290
|
+
id: crypto.randomUUID(),
|
|
291
|
+
},
|
|
292
|
+
{
|
|
293
|
+
content: promptContent,
|
|
294
|
+
name: "user",
|
|
295
|
+
role: "user",
|
|
296
|
+
id: crypto.randomUUID(),
|
|
297
|
+
},
|
|
298
|
+
],
|
|
299
|
+
{ editContext, createAiContext: createWizardAiContext },
|
|
300
|
+
{ model: step.fields.aiModel || undefined },
|
|
301
|
+
{ signal: abortController.signal },
|
|
302
|
+
);
|
|
312
303
|
|
|
313
|
-
if (
|
|
314
|
-
|
|
315
|
-
if (lastMessage && lastMessage.content) {
|
|
316
|
-
const pageModelResult = JSON.parse(
|
|
317
|
-
lastMessage.content,
|
|
318
|
-
) as WizardPageModel;
|
|
319
|
-
if (pageModelResult?.name) {
|
|
320
|
-
setPageModel((prev) => ({ ...prev, name: pageModelResult.name }));
|
|
321
|
-
}
|
|
322
|
-
}
|
|
304
|
+
if (pageModelResult && pageModelResult.name) {
|
|
305
|
+
setPageModel((prev) => ({ ...prev, name: pageModelResult.name }));
|
|
323
306
|
}
|
|
324
307
|
} catch (error) {
|
|
325
308
|
console.error("Error generating page name", error);
|
|
@@ -838,7 +821,7 @@ export function ContentStep({
|
|
|
838
821
|
|
|
839
822
|
console.log("PROMPT: ", prompt, filteredSchema, existingPageModel);
|
|
840
823
|
|
|
841
|
-
const result = await
|
|
824
|
+
const result = await executePromptWithJsonResult<WizardPageModel>(
|
|
842
825
|
prompt,
|
|
843
826
|
{
|
|
844
827
|
editContext: editContextRef.current!,
|
|
@@ -850,33 +833,16 @@ export function ContentStep({
|
|
|
850
833
|
endpoint: "/alpaca/editor/page-wizard/prompt",
|
|
851
834
|
},
|
|
852
835
|
{ signal: localAbortController.signal },
|
|
853
|
-
(response:
|
|
836
|
+
(response: WizardPageModel) => {
|
|
854
837
|
try {
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
response.content ||
|
|
858
|
-
response.messages?.[response.messages.length - 1]?.content;
|
|
859
|
-
if (content) {
|
|
860
|
-
const newLayout = JSON.parse(content) as WizardPageModel;
|
|
861
|
-
|
|
862
|
-
if (newLayout) {
|
|
863
|
-
setPageModel((prev) => mergeLayout(prev, newLayout));
|
|
864
|
-
}
|
|
865
|
-
|
|
866
|
-
setMessage(newLayout.message);
|
|
867
|
-
}
|
|
838
|
+
setPageModel((prev) => mergeLayout(prev, response));
|
|
839
|
+
setMessage(response.message);
|
|
868
840
|
} catch (parseError: unknown) {}
|
|
869
841
|
},
|
|
870
842
|
);
|
|
871
843
|
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
if (lastMessage && lastMessage.content) {
|
|
875
|
-
const finalLayout = JSON.parse(lastMessage.content);
|
|
876
|
-
console.log("RESULT LAYOUT: ", finalLayout);
|
|
877
|
-
setPageModel((prev) => mergeLayout(prev, finalLayout));
|
|
878
|
-
}
|
|
879
|
-
}
|
|
844
|
+
console.log("RESULT LAYOUT: ", result);
|
|
845
|
+
setPageModel((prev) => mergeLayout(prev, result));
|
|
880
846
|
setStepCompleted(true);
|
|
881
847
|
} catch (error) {
|
|
882
848
|
console.error(error);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useEffect, useState } from "react";
|
|
2
2
|
import { FullItem } from "../../editor/pageModel";
|
|
3
3
|
import { WizardPageModel } from "../PageWizard";
|
|
4
|
-
import {
|
|
4
|
+
import { executePromptWithJsonResult } from "../../editor/services/aiService";
|
|
5
5
|
import { createWizardAiContext } from "../service";
|
|
6
6
|
import { useEditContext } from "../../editor/client/editContext";
|
|
7
7
|
import { Textarea } from "../../components/ui/textarea";
|
|
@@ -24,7 +24,6 @@ export function MetaDataStep({
|
|
|
24
24
|
setStepCompleted,
|
|
25
25
|
}: StepComponentProps) {
|
|
26
26
|
const [isGenerating, setIsGenerating] = useState(false);
|
|
27
|
-
const [fullParentItem, setFullParentItem] = useState<FullItem>();
|
|
28
27
|
const editContext = useEditContext();
|
|
29
28
|
|
|
30
29
|
useEffect(() => {
|
|
@@ -35,15 +34,6 @@ export function MetaDataStep({
|
|
|
35
34
|
}
|
|
36
35
|
}, [editContext]);
|
|
37
36
|
|
|
38
|
-
useEffect(() => {
|
|
39
|
-
const loadParentItem = async () => {
|
|
40
|
-
if (!parentItem) return;
|
|
41
|
-
const item = await editContext?.itemsRepository.getItem(parentItem);
|
|
42
|
-
setFullParentItem(item);
|
|
43
|
-
};
|
|
44
|
-
loadParentItem();
|
|
45
|
-
}, [parentItem]);
|
|
46
|
-
|
|
47
37
|
// Mark step as completed immediately since this is now just informational
|
|
48
38
|
useEffect(() => {
|
|
49
39
|
setStepCompleted(true);
|
|
@@ -87,56 +77,58 @@ export function MetaDataStep({
|
|
|
87
77
|
try {
|
|
88
78
|
const abortController = new AbortController();
|
|
89
79
|
|
|
90
|
-
const
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
setPageModel
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
80
|
+
const pageModelResult =
|
|
81
|
+
await executePromptWithJsonResult<WizardPageModel>(
|
|
82
|
+
[
|
|
83
|
+
{
|
|
84
|
+
content: `${processedSystemInstructions}\nYou are a helpful assistant that generates SEO metadata for a page.\n\nReturn ONLY valid JSON in this exact shape: {"metaDescription": string, "metaKeywords": string}.\nLanguage: ${parentItem?.language || "en"}.`,
|
|
85
|
+
name: "system",
|
|
86
|
+
role: "system",
|
|
87
|
+
id: crypto.randomUUID(),
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
content: `${processedInstructions}\n\nCurrent data: ${JSON.stringify(
|
|
91
|
+
inputData,
|
|
92
|
+
null,
|
|
93
|
+
2,
|
|
94
|
+
)}`,
|
|
95
|
+
name: "user",
|
|
96
|
+
role: "user",
|
|
97
|
+
id: crypto.randomUUID(),
|
|
98
|
+
},
|
|
99
|
+
],
|
|
100
|
+
{ editContext, createAiContext: createWizardAiContext },
|
|
101
|
+
{ model: step.fields.aiModel || undefined },
|
|
102
|
+
{ signal: abortController.signal },
|
|
103
|
+
(response: any) => {
|
|
104
|
+
try {
|
|
105
|
+
const newLayout = JSON.parse(response.content) as WizardPageModel;
|
|
106
|
+
if (newLayout && setPageModel) {
|
|
107
|
+
setPageModel((prev) => ({
|
|
108
|
+
...prev,
|
|
109
|
+
metaDescription:
|
|
110
|
+
(newLayout as any)?.metaDescription ?? prev.metaDescription,
|
|
111
|
+
metaKeywords:
|
|
112
|
+
(newLayout as any)?.metaKeywords ?? prev.metaKeywords,
|
|
113
|
+
}));
|
|
114
|
+
}
|
|
115
|
+
} catch {
|
|
116
|
+
// Ignore parsing errors during streaming
|
|
123
117
|
}
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
if (
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
}));
|
|
139
|
-
}
|
|
118
|
+
},
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Parse the final result
|
|
122
|
+
if (
|
|
123
|
+
pageModelResult &&
|
|
124
|
+
pageModelResult.metaDescription &&
|
|
125
|
+
pageModelResult.metaKeywords
|
|
126
|
+
) {
|
|
127
|
+
setPageModel((prev) => ({
|
|
128
|
+
...prev,
|
|
129
|
+
metaDescription: pageModelResult.metaDescription,
|
|
130
|
+
metaKeywords: pageModelResult.metaKeywords,
|
|
131
|
+
}));
|
|
140
132
|
}
|
|
141
133
|
} catch (error) {
|
|
142
134
|
console.error("Error generating meta fields", error);
|