@alpaca-editor/core 1.0.4118 → 1.0.4121

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.
Files changed (65) hide show
  1. package/dist/components/ui/input.js +3 -1
  2. package/dist/components/ui/input.js.map +1 -1
  3. package/dist/components/ui/textarea.js +3 -1
  4. package/dist/components/ui/textarea.js.map +1 -1
  5. package/dist/editor/ContentTree.js +52 -4
  6. package/dist/editor/ContentTree.js.map +1 -1
  7. package/dist/editor/ContextMenu.d.ts +2 -0
  8. package/dist/editor/ContextMenu.js +9 -7
  9. package/dist/editor/ContextMenu.js.map +1 -1
  10. package/dist/editor/FieldListField.js +1 -1
  11. package/dist/editor/PictureEditor.d.ts +2 -1
  12. package/dist/editor/PictureEditor.js +2 -2
  13. package/dist/editor/PictureEditor.js.map +1 -1
  14. package/dist/editor/ai/AgentTerminal.js +163 -49
  15. package/dist/editor/ai/AgentTerminal.js.map +1 -1
  16. package/dist/editor/ai/ContextInfoBar.js +2 -2
  17. package/dist/editor/ai/ContextInfoBar.js.map +1 -1
  18. package/dist/editor/client/EditorShell.js +3 -0
  19. package/dist/editor/client/EditorShell.js.map +1 -1
  20. package/dist/editor/client/editContext.d.ts +2 -1
  21. package/dist/editor/client/editContext.js.map +1 -1
  22. package/dist/editor/control-center/setup-steps/SettingsSetupStep.js +9 -6
  23. package/dist/editor/control-center/setup-steps/SettingsSetupStep.js.map +1 -1
  24. package/dist/editor/page-editor-chrome/FrameMenu.js +6 -1
  25. package/dist/editor/page-editor-chrome/FrameMenu.js.map +1 -1
  26. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js +34 -1
  27. package/dist/editor/page-editor-chrome/PictureEditorOverlay.js.map +1 -1
  28. package/dist/editor/page-viewer/PageViewerFrame.js +20 -4
  29. package/dist/editor/page-viewer/PageViewerFrame.js.map +1 -1
  30. package/dist/editor/services/agentService.d.ts +1 -0
  31. package/dist/editor/services/agentService.js.map +1 -1
  32. package/dist/editor/sidebar/ComponentTree.js +8 -9
  33. package/dist/editor/sidebar/ComponentTree.js.map +1 -1
  34. package/dist/editor/ui/DragPreview.d.ts +3 -2
  35. package/dist/editor/ui/DragPreview.js +4 -6
  36. package/dist/editor/ui/DragPreview.js.map +1 -1
  37. package/dist/editor/ui/PerfectTree.d.ts +4 -2
  38. package/dist/editor/ui/PerfectTree.js +4 -4
  39. package/dist/editor/ui/PerfectTree.js.map +1 -1
  40. package/dist/editor/ui/Splitter.js +8 -5
  41. package/dist/editor/ui/Splitter.js.map +1 -1
  42. package/dist/revision.d.ts +2 -2
  43. package/dist/revision.js +2 -2
  44. package/dist/styles.css +43 -0
  45. package/package.json +1 -1
  46. package/src/components/ui/input.tsx +2 -1
  47. package/src/components/ui/textarea.tsx +3 -1
  48. package/src/editor/ContentTree.tsx +51 -2
  49. package/src/editor/ContextMenu.tsx +30 -8
  50. package/src/editor/FieldListField.tsx +2 -2
  51. package/src/editor/PictureEditor.tsx +3 -0
  52. package/src/editor/ai/AgentTerminal.tsx +224 -65
  53. package/src/editor/ai/ContextInfoBar.tsx +7 -1
  54. package/src/editor/client/EditorShell.tsx +3 -0
  55. package/src/editor/client/editContext.ts +2 -1
  56. package/src/editor/control-center/setup-steps/SettingsSetupStep.tsx +11 -6
  57. package/src/editor/page-editor-chrome/FrameMenu.tsx +6 -1
  58. package/src/editor/page-editor-chrome/PictureEditorOverlay.tsx +46 -0
  59. package/src/editor/page-viewer/PageViewerFrame.tsx +19 -3
  60. package/src/editor/services/agentService.ts +6 -1
  61. package/src/editor/sidebar/ComponentTree.tsx +9 -9
  62. package/src/editor/ui/DragPreview.tsx +10 -5
  63. package/src/editor/ui/PerfectTree.tsx +12 -1
  64. package/src/editor/ui/Splitter.tsx +11 -5
  65. package/src/revision.ts +2 -2
@@ -13,6 +13,7 @@ import { getComponentById } from "../componentTreeHelper";
13
13
  import { Popover, PopoverContent, PopoverTrigger, } from "../../components/ui/popover";
14
14
  import { SecretAgentIcon } from "../ui/Icons";
15
15
  import { formatTime } from "../utils";
16
+ import { Tooltip, TooltipTrigger, TooltipContent, } from "../../components/ui/tooltip";
16
17
  // Simple user message component
17
18
  const UserMessage = ({ message }) => {
18
19
  return (_jsxs("div", { className: "flex gap-3 p-4", children: [_jsx("div", { className: "flex-shrink-0", children: _jsx(User, { className: "h-6 w-6 text-blue-600", strokeWidth: 1 }) }), _jsxs("div", { className: "min-w-0 flex-1 select-text", children: [_jsxs("div", { className: "mb-1 flex items-center gap-2", children: [_jsx("span", { className: "text-xs font-medium text-gray-900", children: "You" }), message.createdDate && (_jsx("span", { className: "text-xs text-gray-400", children: formatTime(new Date(message.createdDate)) }))] }), _jsx("div", { className: "prose prose-sm max-w-none text-xs text-gray-700 select-text", children: message.content })] })] }));
@@ -456,7 +457,17 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
456
457
  }, [createNewStreamMessage]);
457
458
  const handleToolCall = useCallback((message, agentData) => {
458
459
  const toolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
459
- const toolCallMessageId = message.data?.messageId;
460
+ // Prefer provided messageId, otherwise fall back to the last streaming assistant message
461
+ let toolCallMessageId = message.data?.messageId;
462
+ if (!toolCallMessageId) {
463
+ const current = messagesRef.current;
464
+ const lastStreaming = [...current]
465
+ .reverse()
466
+ .find((m) => m.role === "assistant" && !m.isCompleted);
467
+ if (lastStreaming?.id) {
468
+ toolCallMessageId = lastStreaming.id;
469
+ }
470
+ }
460
471
  // Find or create the target message for this tool call
461
472
  if (toolCallMessageId) {
462
473
  const currentMessages = messagesRef.current;
@@ -531,10 +542,20 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
531
542
  }, [createNewStreamMessage]);
532
543
  const handleToolResult = useCallback((message, agentData) => {
533
544
  const resultToolCallId = message.data?.toolCallId || message.data?.id || crypto.randomUUID();
534
- const resultMessageId = message.data?.messageId;
545
+ // Prefer provided messageId, otherwise fall back to the last streaming assistant message
546
+ let resultMessageId = message.data?.messageId;
547
+ if (!resultMessageId) {
548
+ const current = messagesRef.current;
549
+ const lastStreaming = [...current]
550
+ .reverse()
551
+ .find((m) => m.role === "assistant" && !m.isCompleted);
552
+ if (lastStreaming?.id) {
553
+ resultMessageId = lastStreaming.id;
554
+ }
555
+ }
535
556
  // Update tool result directly in the messages array
536
557
  if (!resultMessageId) {
537
- console.warn("⚠️ No messageId provided for tool result");
558
+ console.warn("⚠️ No messageId available for tool result");
538
559
  return;
539
560
  }
540
561
  console.log("📋 Updating tool result in message:", resultMessageId);
@@ -631,6 +652,73 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
631
652
  handleToolResult(message, currentAgent);
632
653
  break;
633
654
  case "statusUpdate":
655
+ try {
656
+ const kind = message?.data?.kind;
657
+ if (kind === "contextWindow") {
658
+ const data = message.data || {};
659
+ // Store last context window status in a ref so we can render it below
660
+ window.__agentContextWindowStatus = {
661
+ model: data.model,
662
+ normalizedModel: data.normalizedModel,
663
+ contextWindowTokens: data.contextWindowTokens,
664
+ maxCompletionTokens: data.maxCompletionTokens,
665
+ estimatedInputTokens: data.estimatedInputTokens,
666
+ messageCount: data.messageCount,
667
+ contextUsedPercent: data.contextUsedPercent,
668
+ };
669
+ // Force a re-render by toggling state (cheap no-op)
670
+ setMessages((prev) => [...prev]);
671
+ }
672
+ else if (kind === "contextChanged") {
673
+ const data = message.data || {};
674
+ const nextContext = data.context || {};
675
+ // Merge incoming context into local metadata
676
+ setAgentMetadata((prev) => {
677
+ const current = (prev || {});
678
+ const next = {
679
+ ...current,
680
+ additionalData: {
681
+ ...(current.additionalData || {}),
682
+ context: nextContext,
683
+ },
684
+ };
685
+ return next;
686
+ });
687
+ // Also reflect in agent metadata string for consistency
688
+ setAgent((prevAgent) => {
689
+ if (!prevAgent)
690
+ return prevAgent;
691
+ try {
692
+ const currentMeta = (() => {
693
+ try {
694
+ return prevAgent.metadata
695
+ ? JSON.parse(prevAgent.metadata)
696
+ : null;
697
+ }
698
+ catch {
699
+ return null;
700
+ }
701
+ })();
702
+ const nextMeta = {
703
+ ...(currentMeta || {}),
704
+ additionalData: {
705
+ ...(currentMeta?.additionalData ||
706
+ {}),
707
+ context: nextContext,
708
+ },
709
+ };
710
+ return {
711
+ ...prevAgent,
712
+ metadata: JSON.stringify(nextMeta),
713
+ };
714
+ }
715
+ catch {
716
+ return prevAgent;
717
+ }
718
+ });
719
+ }
720
+ }
721
+ catch { }
634
722
  break;
635
723
  case "completed":
636
724
  const completedMessageId = message.data?.messageId;
@@ -920,25 +1008,32 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
920
1008
  if (localCtx?.additionalData?.context) {
921
1009
  const ctx = base.additionalData.context;
922
1010
  const local = localCtx.additionalData.context;
1011
+ // Normalize existing shape: migrate items -> pages if needed
1012
+ if (!ctx.pages && ctx.items) {
1013
+ ctx.pages = ctx.items;
1014
+ delete ctx.items;
1015
+ }
923
1016
  // Merge pages (avoid duplicates)
924
- if (local.pages && local.pages.length) {
925
- const existing = new Set((ctx.pages || []).map((p) => `${p.id}-${p.language}-${p.version}`));
926
- const mergedPages = [
927
- ...(ctx.pages || []),
928
- ...local.pages.filter((p) => !existing.has(`${p.id}-${p.language}-${p.version}`)),
929
- ];
930
- if (mergedPages.length)
931
- ctx.pages = mergedPages;
1017
+ if ((local.pages && local.pages.length) ||
1018
+ (local.items && local.items.length)) {
1019
+ const targetPages = Array.isArray(ctx.pages)
1020
+ ? [...ctx.pages]
1021
+ : [];
1022
+ const existingKeys = new Set(targetPages.map((p) => `${p.id}-${p.language || ""}-${p.version || ""}`));
1023
+ const incoming = (local.pages || local.items);
1024
+ const additions = incoming.filter((p) => !existingKeys.has(`${p.id}-${p.language || ""}-${p.version || ""}`));
1025
+ if (additions.length)
1026
+ ctx.pages = [...targetPages, ...additions];
932
1027
  }
933
- // Merge componentIds
1028
+ // Merge componentIds (avoid duplicates)
934
1029
  if (local.componentIds && local.componentIds.length) {
935
- const existingIds = new Set(ctx.componentIds || []);
936
- const mergedIds = [
937
- ...(ctx.componentIds || []),
938
- ...local.componentIds.filter((id) => !existingIds.has(id)),
939
- ];
940
- if (mergedIds.length)
941
- ctx.componentIds = mergedIds;
1030
+ const currentIds = Array.isArray(ctx.componentIds)
1031
+ ? ctx.componentIds
1032
+ : [];
1033
+ const existingIds = new Set(currentIds);
1034
+ const additions = local.componentIds.filter((id) => !!id && !existingIds.has(id));
1035
+ if (additions.length)
1036
+ ctx.componentIds = [...currentIds, ...additions];
942
1037
  }
943
1038
  // Set field if missing
944
1039
  if (!ctx.field && local.field) {
@@ -1240,6 +1335,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
1240
1335
  addSelectedComponents: !!effectiveSelection?.length,
1241
1336
  addContextContent: false,
1242
1337
  addAllContent: false,
1338
+ context: agentMetadata?.additionalData?.context,
1243
1339
  deterministic: deterministicFlags.deterministic,
1244
1340
  seed: deterministicFlags.seed,
1245
1341
  };
@@ -1398,6 +1494,7 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
1398
1494
  addSelectedComponents: !!effectiveSelection?.length,
1399
1495
  addContextContent: false,
1400
1496
  addAllContent: false,
1497
+ context: agentMetadata?.additionalData?.context,
1401
1498
  deterministic: deterministicFlags.deterministic,
1402
1499
  seed: deterministicFlags.seed,
1403
1500
  };
@@ -1947,35 +2044,39 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
1947
2044
  if (currentHistoryIndex !== -1) {
1948
2045
  setCurrentHistoryIndex(-1);
1949
2046
  }
1950
- }, 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 items-center justify-start gap-2", children: [_jsxs("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: mode, onChange: async (e) => {
1951
- const nextMode = e.target.value || "agent";
1952
- // Optimistic UI update
1953
- setMode(nextMode);
1954
- const current = agentMetadata || {};
1955
- const nextMeta = {
1956
- ...current,
1957
- mode: nextMode,
1958
- };
1959
- try {
1960
- if (!agent?.id || agent.status === "new") {
1961
- setAgentMetadata(nextMeta);
1962
- // Cache until first start when agent is persisted
1963
- pendingSettingsRef.current = {
1964
- ...(pendingSettingsRef.current || {}),
1965
- mode: nextMode,
1966
- };
1967
- return;
1968
- }
1969
- await updateAgentSettings(agent.id, { mode: nextMode });
1970
- setAgentMetadata(nextMeta);
1971
- setAgent((prev) => prev
1972
- ? { ...prev, metadata: JSON.stringify(nextMeta) }
1973
- : prev);
1974
- }
1975
- catch (e2) {
1976
- console.error("Failed to persist mode change", e2);
1977
- }
1978
- }, title: "Mode", "aria-label": "Mode", "data-testid": "agent-mode-select", children: [_jsx("option", { value: "restricted", children: "Restricted" }), _jsx("option", { value: "agent", children: "Agent" }), _jsx("option", { value: "ask", children: "Ask" })] }), profiles?.length > 0 && (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: activeProfile?.id || "", onChange: (e) => {
2047
+ }, 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 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 === "ask"
2048
+ ? "border-green-300 bg-green-50 text-green-700"
2049
+ : mode === "restricted"
2050
+ ? "border-amber-300 bg-amber-50 text-amber-700"
2051
+ : "border-red-300 bg-red-50 text-red-700"}`, value: mode, onChange: async (e) => {
2052
+ const nextMode = e.target.value || "agent";
2053
+ // Optimistic UI update
2054
+ setMode(nextMode);
2055
+ const current = agentMetadata || {};
2056
+ const nextMeta = {
2057
+ ...current,
2058
+ mode: nextMode,
2059
+ };
2060
+ try {
2061
+ if (!agent?.id || agent.status === "new") {
2062
+ setAgentMetadata(nextMeta);
2063
+ // Cache until first start when agent is persisted
2064
+ pendingSettingsRef.current = {
2065
+ ...(pendingSettingsRef.current || {}),
2066
+ mode: nextMode,
2067
+ };
2068
+ return;
2069
+ }
2070
+ await updateAgentSettings(agent.id, { mode: nextMode });
2071
+ setAgentMetadata(nextMeta);
2072
+ setAgent((prev) => prev
2073
+ ? { ...prev, metadata: JSON.stringify(nextMeta) }
2074
+ : prev);
2075
+ }
2076
+ catch (e2) {
2077
+ console.error("Failed to persist mode change", e2);
2078
+ }
2079
+ }, title: "Mode", "aria-label": "Mode", "data-testid": "agent-mode-select", children: [_jsx("option", { value: "restricted", children: "Restricted" }), _jsx("option", { value: "agent", children: "Agent" }), _jsx("option", { value: "ask", children: "Ask" })] }) }), _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", children: "Restricted" }), ": Same as Agent, but writes are limited to pages/items in the current context."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Agent" }), ": Full tool access; can write across the site/project."] }), _jsxs("div", { children: [_jsx("span", { className: "font-semibold", children: "Ask" }), ": Limited tool access as configured by the profile (Ask Mode Tools)."] })] }) })] }), profiles?.length > 0 && (_jsx("select", { className: "h-5 rounded border px-1.5 text-[10px] text-gray-500", value: activeProfile?.id || "", onChange: (e) => {
1979
2080
  const p = profiles.find((x) => x.id === e.target.value);
1980
2081
  if (p)
1981
2082
  setActiveProfile(p);
@@ -2006,6 +2107,19 @@ export function AgentTerminal({ agentStub, initialMetadata, profiles, }) {
2006
2107
  setShowPredefined(false);
2007
2108
  if (textareaRef.current)
2008
2109
  textareaRef.current.focus();
2009
- }, 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 })) })] })] }), _jsx("div", { className: "mt-1 flex justify-start", children: _jsx(AgentCostDisplay, { totalTokens: totalTokens }) })] })] }));
2110
+ }, 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 })) })] })] }), _jsx("div", { className: "mt-1 flex justify-start", children: _jsx(AgentCostDisplay, { totalTokens: totalTokens }) }), _jsx("div", { className: "mt-1 flex items-center gap-2 text-[10px] text-gray-500", children: (() => {
2111
+ try {
2112
+ const s = window.__agentContextWindowStatus;
2113
+ if (!s || !s.contextWindowTokens)
2114
+ return null;
2115
+ const pct = typeof s.contextUsedPercent === "number"
2116
+ ? `${s.contextUsedPercent.toFixed(1)}%`
2117
+ : undefined;
2118
+ return (_jsxs("div", { className: "rounded border border-gray-200 bg-gray-50 px-2 py-0.5", children: [_jsxs("span", { title: `Model: ${s.model} (${s.normalizedModel || ""})`, children: ["Context window: ", s.estimatedInputTokens || 0, " /", " ", s.contextWindowTokens] }), typeof s.maxCompletionTokens === "number" && (_jsxs("span", { children: [" \u00B7 Max completion: ", s.maxCompletionTokens] })), pct && _jsxs("span", { children: [" \u00B7 Used: ", pct] })] }));
2119
+ }
2120
+ catch {
2121
+ return null;
2122
+ }
2123
+ })() })] })] }));
2010
2124
  }
2011
2125
  //# sourceMappingURL=AgentTerminal.js.map