@open-mercato/ui 0.6.1-develop.3291.1.6fad645fd0 → 0.6.1
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/.turbo/turbo-build.log +1 -1
- package/AGENTS.md +2 -0
- package/dist/ai/AiAssistantLauncher.js +8 -8
- package/dist/ai/AiAssistantLauncher.js.map +2 -2
- package/dist/ai/AiChat.js +92 -93
- package/dist/ai/AiChat.js.map +2 -2
- package/dist/ai/AiIcon.js +17 -0
- package/dist/ai/AiIcon.js.map +7 -0
- package/dist/ai/LoopDisabledBanner.js +28 -0
- package/dist/ai/LoopDisabledBanner.js.map +7 -0
- package/dist/ai/LoopTracePanel.js +123 -0
- package/dist/ai/LoopTracePanel.js.map +7 -0
- package/dist/ai/ModelPicker.js.map +1 -1
- package/dist/ai/index.js +8 -0
- package/dist/ai/index.js.map +2 -2
- package/dist/ai/parts/ConfirmationCard.js +1 -5
- package/dist/ai/parts/ConfirmationCard.js.map +2 -2
- package/dist/ai/parts/FieldDiffCard.js +8 -15
- package/dist/ai/parts/FieldDiffCard.js.map +2 -2
- package/dist/ai/parts/MutationResultCard.js +1 -4
- package/dist/ai/parts/MutationResultCard.js.map +2 -2
- package/dist/ai/ui-parts/pending-phase3-placeholder.js +0 -2
- package/dist/ai/ui-parts/pending-phase3-placeholder.js.map +2 -2
- package/dist/ai/useAiChat.js +18 -4
- package/dist/ai/useAiChat.js.map +2 -2
- package/dist/backend/CrudForm.js +24 -2
- package/dist/backend/CrudForm.js.map +2 -2
- package/dist/backend/DataTable.js +2 -2
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/confirm-dialog/ConfirmDialog.js +102 -96
- package/dist/backend/confirm-dialog/ConfirmDialog.js.map +2 -2
- package/dist/backend/detail/CustomDataSection.js +22 -3
- package/dist/backend/detail/CustomDataSection.js.map +2 -2
- package/dist/backend/filters/AdvancedFilterBuilder.js +2 -2
- package/dist/backend/filters/AdvancedFilterBuilder.js.map +2 -2
- package/dist/backend/injection/ComponentOverrideProvider.js +1 -1
- package/dist/backend/injection/ComponentOverrideProvider.js.map +2 -2
- package/dist/backend/inputs/ComboboxInput.js +25 -7
- package/dist/backend/inputs/ComboboxInput.js.map +2 -2
- package/dist/backend/progress/useProgressPoll.js +58 -3
- package/dist/backend/progress/useProgressPoll.js.map +2 -2
- package/dist/backend/progress/useProgressSse.js +15 -2
- package/dist/backend/progress/useProgressSse.js.map +2 -2
- package/dist/backend/utils/bulkDelete.js +76 -0
- package/dist/backend/utils/bulkDelete.js.map +2 -2
- package/package.json +11 -6
- package/src/ai/AiAssistantLauncher.tsx +8 -8
- package/src/ai/AiChat.tsx +44 -38
- package/src/ai/AiIcon.tsx +12 -0
- package/src/ai/LoopDisabledBanner.tsx +38 -0
- package/src/ai/LoopTracePanel.tsx +184 -0
- package/src/ai/ModelPicker.tsx +1 -1
- package/src/ai/__tests__/AiChat.test.tsx +174 -5
- package/src/ai/index.ts +8 -0
- package/src/ai/parts/ConfirmationCard.tsx +1 -5
- package/src/ai/parts/FieldDiffCard.tsx +0 -3
- package/src/ai/parts/MutationResultCard.tsx +1 -4
- package/src/ai/parts/__tests__/MutationResultCard.test.tsx +5 -0
- package/src/ai/ui-parts/pending-phase3-placeholder.tsx +0 -2
- package/src/ai/useAiChat.ts +35 -5
- package/src/backend/CrudForm.tsx +30 -3
- package/src/backend/DataTable.tsx +2 -2
- package/src/backend/__tests__/CrudForm.custom-fields.test.tsx +72 -0
- package/src/backend/__tests__/CustomDataSection.test.tsx +76 -0
- package/src/backend/__tests__/DataTable.render.test.tsx +36 -0
- package/src/backend/__tests__/component-replacement.test.tsx +44 -0
- package/src/backend/confirm-dialog/ConfirmDialog.tsx +101 -91
- package/src/backend/confirm-dialog/__tests__/ConfirmDialog.test.tsx +19 -0
- package/src/backend/detail/CustomDataSection.tsx +26 -3
- package/src/backend/filters/AdvancedFilterBuilder.tsx +6 -6
- package/src/backend/injection/ComponentOverrideProvider.tsx +2 -1
- package/src/backend/inputs/ComboboxInput.tsx +29 -7
- package/src/backend/inputs/__tests__/ComboboxInput.test.tsx +33 -2
- package/src/backend/progress/useProgressPoll.ts +68 -3
- package/src/backend/progress/useProgressSse.ts +16 -2
- package/src/backend/utils/__tests__/bulkDelete.test.ts +42 -0
- package/src/backend/utils/bulkDelete.ts +93 -0
package/dist/ai/AiChat.js
CHANGED
|
@@ -41,6 +41,7 @@ import {
|
|
|
41
41
|
} from "./useAiChat.js";
|
|
42
42
|
import { useAiChatUpload } from "./useAiChatUpload.js";
|
|
43
43
|
import { useAiShortcuts } from "./useAiShortcuts.js";
|
|
44
|
+
import { LoopTracePanel } from "./LoopTracePanel.js";
|
|
44
45
|
const PREVIEW_DATA_URL_MAX_BYTES = 2 * 1024 * 1024;
|
|
45
46
|
const COMPACT_FOOTER_MAX_WIDTH = 640;
|
|
46
47
|
const MODEL_PICKER_STORAGE_PREFIX = "om-ai-model-picker:";
|
|
@@ -73,7 +74,7 @@ function writeModelPickerValue(agentId, value) {
|
|
|
73
74
|
}
|
|
74
75
|
function useAgentModels(agent) {
|
|
75
76
|
const [providers, setProviders] = React.useState([]);
|
|
76
|
-
const [
|
|
77
|
+
const [allowRuntimeOverride, setAllowRuntimeOverride] = React.useState(false);
|
|
77
78
|
const [defaultLabel, setDefaultLabel] = React.useState(null);
|
|
78
79
|
const [loaded, setLoaded] = React.useState(false);
|
|
79
80
|
React.useEffect(() => {
|
|
@@ -85,7 +86,8 @@ function useAgentModels(agent) {
|
|
|
85
86
|
setLoaded(true);
|
|
86
87
|
return;
|
|
87
88
|
}
|
|
88
|
-
|
|
89
|
+
const effectiveAllowRuntimeOverride = result.result.allowRuntimeOverride ?? result.result.allowRuntimeModelOverride ?? false;
|
|
90
|
+
setAllowRuntimeOverride(effectiveAllowRuntimeOverride);
|
|
89
91
|
setProviders(result.result.providers);
|
|
90
92
|
setDefaultLabel(
|
|
91
93
|
result.result.defaultProviderName && result.result.defaultModelName ? `${result.result.defaultProviderName} / ${result.result.defaultModelName}` : result.result.defaultProviderId && result.result.defaultModelId ? `${result.result.defaultProviderId} / ${result.result.defaultModelId}` : null
|
|
@@ -93,16 +95,13 @@ function useAgentModels(agent) {
|
|
|
93
95
|
setLoaded(true);
|
|
94
96
|
});
|
|
95
97
|
}, [agent]);
|
|
96
|
-
return {
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
}
|
|
104
|
-
}
|
|
105
|
-
return null;
|
|
98
|
+
return {
|
|
99
|
+
providers,
|
|
100
|
+
allowRuntimeOverride,
|
|
101
|
+
allowRuntimeModelOverride: allowRuntimeOverride,
|
|
102
|
+
defaultLabel,
|
|
103
|
+
loaded
|
|
104
|
+
};
|
|
106
105
|
}
|
|
107
106
|
function isModelPickerValueAvailable(value, providers) {
|
|
108
107
|
return providers.some(
|
|
@@ -197,70 +196,76 @@ function ToolCallList({ toolCalls }) {
|
|
|
197
196
|
const t = useT();
|
|
198
197
|
const [openId, setOpenId] = React.useState(null);
|
|
199
198
|
if (!toolCalls || toolCalls.length === 0) return null;
|
|
200
|
-
return /* @__PURE__ */
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
"
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
"button",
|
|
218
|
-
{
|
|
219
|
-
type: "button",
|
|
220
|
-
onClick: () => setOpenId(isOpen ? null : call.id),
|
|
221
|
-
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-xs font-medium hover:bg-muted/60",
|
|
222
|
-
children: [
|
|
223
|
-
isOpen ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
|
|
224
|
-
isPending ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(
|
|
225
|
-
Wrench,
|
|
226
|
-
{
|
|
227
|
-
className: cn(
|
|
228
|
-
"size-3.5",
|
|
229
|
-
isError ? "text-destructive" : "text-muted-foreground"
|
|
230
|
-
),
|
|
231
|
-
"aria-hidden": true
|
|
232
|
-
}
|
|
233
|
-
),
|
|
234
|
-
/* @__PURE__ */ jsx("span", { className: "font-mono", children: call.toolName }),
|
|
235
|
-
/* @__PURE__ */ jsx(
|
|
236
|
-
"span",
|
|
237
|
-
{
|
|
238
|
-
className: cn(
|
|
239
|
-
"ml-auto text-[10px] uppercase tracking-wide",
|
|
240
|
-
isError ? "text-destructive" : isComplete ? "text-status-success-text" : "text-muted-foreground"
|
|
241
|
-
),
|
|
242
|
-
children: statusLabel
|
|
243
|
-
}
|
|
244
|
-
)
|
|
245
|
-
]
|
|
246
|
-
}
|
|
199
|
+
return /* @__PURE__ */ jsxs("div", { className: "space-y-1", "data-ai-chat-tool-calls": "", children: [
|
|
200
|
+
/* @__PURE__ */ jsxs("div", { className: "flex items-center justify-between px-0.5 text-[11px] font-medium uppercase tracking-wide text-muted-foreground", children: [
|
|
201
|
+
/* @__PURE__ */ jsx("span", { children: t("ai_assistant.chat.agentTasksTitle", "Agent tasks") }),
|
|
202
|
+
/* @__PURE__ */ jsx("span", { children: toolCalls.length })
|
|
203
|
+
] }),
|
|
204
|
+
toolCalls.map((call) => {
|
|
205
|
+
const isOpen = openId === call.id;
|
|
206
|
+
const isError = call.state === "error";
|
|
207
|
+
const isPending = call.state === "pending";
|
|
208
|
+
const isComplete = call.state === "complete";
|
|
209
|
+
const statusLabel = isError ? t("ai_assistant.chat.toolError", "failed") : isPending ? t("ai_assistant.chat.toolRunning", "running\u2026") : t("ai_assistant.chat.toolDone", "done");
|
|
210
|
+
return /* @__PURE__ */ jsxs(
|
|
211
|
+
"div",
|
|
212
|
+
{
|
|
213
|
+
className: cn(
|
|
214
|
+
"rounded-md border border-border bg-muted/30",
|
|
215
|
+
isError ? "border-destructive/40 bg-destructive/5" : ""
|
|
247
216
|
),
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
217
|
+
"data-ai-chat-tool-call": call.toolName,
|
|
218
|
+
"data-ai-chat-tool-state": call.state,
|
|
219
|
+
children: [
|
|
220
|
+
/* @__PURE__ */ jsxs(
|
|
221
|
+
"button",
|
|
222
|
+
{
|
|
223
|
+
type: "button",
|
|
224
|
+
onClick: () => setOpenId(isOpen ? null : call.id),
|
|
225
|
+
className: "flex w-full items-center gap-2 px-2 py-1.5 text-left text-xs font-medium hover:bg-muted/60",
|
|
226
|
+
children: [
|
|
227
|
+
isOpen ? /* @__PURE__ */ jsx(ChevronDown, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(ChevronRight, { className: "size-3.5 text-muted-foreground", "aria-hidden": true }),
|
|
228
|
+
isPending ? /* @__PURE__ */ jsx(Loader2, { className: "size-3.5 animate-spin text-muted-foreground", "aria-hidden": true }) : /* @__PURE__ */ jsx(
|
|
229
|
+
Wrench,
|
|
230
|
+
{
|
|
231
|
+
className: cn(
|
|
232
|
+
"size-3.5",
|
|
233
|
+
isError ? "text-destructive" : "text-muted-foreground"
|
|
234
|
+
),
|
|
235
|
+
"aria-hidden": true
|
|
236
|
+
}
|
|
237
|
+
),
|
|
238
|
+
/* @__PURE__ */ jsx("span", { className: "font-mono", children: call.toolName }),
|
|
239
|
+
/* @__PURE__ */ jsx(
|
|
240
|
+
"span",
|
|
241
|
+
{
|
|
242
|
+
className: cn(
|
|
243
|
+
"ml-auto text-[10px] uppercase tracking-wide",
|
|
244
|
+
isError ? "text-destructive" : isComplete ? "text-status-success-text" : "text-muted-foreground"
|
|
245
|
+
),
|
|
246
|
+
children: statusLabel
|
|
247
|
+
}
|
|
248
|
+
)
|
|
249
|
+
]
|
|
250
|
+
}
|
|
251
|
+
),
|
|
252
|
+
isOpen ? /* @__PURE__ */ jsxs("div", { className: "space-y-1 border-t border-border/60 px-2 py-1.5 text-xs", children: [
|
|
253
|
+
call.input !== void 0 ? /* @__PURE__ */ jsxs("div", { children: [
|
|
254
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: t("ai_assistant.chat.toolInput", "Input") }),
|
|
255
|
+
/* @__PURE__ */ jsx("pre", { className: "mt-0.5 max-h-32 overflow-auto rounded bg-background p-1.5 font-mono text-[11px]", children: safeStringify(call.input) })
|
|
256
|
+
] }) : null,
|
|
257
|
+
call.output !== void 0 && !isError ? /* @__PURE__ */ jsxs("div", { children: [
|
|
258
|
+
/* @__PURE__ */ jsx("div", { className: "text-[10px] uppercase tracking-wide text-muted-foreground", children: t("ai_assistant.chat.toolOutput", "Output") }),
|
|
259
|
+
/* @__PURE__ */ jsx("pre", { className: "mt-0.5 max-h-32 overflow-auto rounded bg-background p-1.5 font-mono text-[11px]", children: safeStringify(call.output) })
|
|
260
|
+
] }) : null,
|
|
261
|
+
call.errorMessage ? /* @__PURE__ */ jsx("div", { className: "text-destructive", children: call.errorMessage }) : null
|
|
262
|
+
] }) : null
|
|
263
|
+
]
|
|
264
|
+
},
|
|
265
|
+
call.id
|
|
266
|
+
);
|
|
267
|
+
})
|
|
268
|
+
] });
|
|
264
269
|
}
|
|
265
270
|
function ReasoningPanel({ text, streaming }) {
|
|
266
271
|
const t = useT();
|
|
@@ -560,6 +565,7 @@ function AiChat({
|
|
|
560
565
|
uiParts: uiPartsProp,
|
|
561
566
|
debugTools,
|
|
562
567
|
debugPromptSections,
|
|
568
|
+
loopTrace,
|
|
563
569
|
conversationId,
|
|
564
570
|
suggestions,
|
|
565
571
|
contextItems,
|
|
@@ -602,6 +608,7 @@ function AiChat({
|
|
|
602
608
|
);
|
|
603
609
|
const {
|
|
604
610
|
providers: modelProviders,
|
|
611
|
+
allowRuntimeOverride,
|
|
605
612
|
allowRuntimeModelOverride,
|
|
606
613
|
defaultLabel: modelDefaultLabel,
|
|
607
614
|
loaded: modelProvidersLoaded
|
|
@@ -610,15 +617,15 @@ function AiChat({
|
|
|
610
617
|
() => readModelPickerValue(agent)
|
|
611
618
|
);
|
|
612
619
|
const effectiveModelPickerValue = React.useMemo(() => {
|
|
613
|
-
if (!modelProvidersLoaded || !
|
|
620
|
+
if (!modelProvidersLoaded || !allowRuntimeOverride || modelProviders.length === 0) {
|
|
614
621
|
return null;
|
|
615
622
|
}
|
|
616
623
|
if (modelPickerValue && isModelPickerValueAvailable(modelPickerValue, modelProviders)) {
|
|
617
624
|
return modelPickerValue;
|
|
618
625
|
}
|
|
619
|
-
return
|
|
626
|
+
return null;
|
|
620
627
|
}, [
|
|
621
|
-
|
|
628
|
+
allowRuntimeOverride,
|
|
622
629
|
modelPickerValue,
|
|
623
630
|
modelProviders,
|
|
624
631
|
modelProvidersLoaded
|
|
@@ -636,9 +643,8 @@ function AiChat({
|
|
|
636
643
|
return;
|
|
637
644
|
}
|
|
638
645
|
if (modelPickerValue && !isModelPickerValueAvailable(modelPickerValue, modelProviders)) {
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
writeModelPickerValue(agent, fallback);
|
|
646
|
+
setModelPickerValue(null);
|
|
647
|
+
writeModelPickerValue(agent, null);
|
|
642
648
|
}
|
|
643
649
|
}, [
|
|
644
650
|
agent,
|
|
@@ -695,26 +701,16 @@ function AiChat({
|
|
|
695
701
|
toolSig
|
|
696
702
|
].join("#");
|
|
697
703
|
}, [lastAssistant]);
|
|
698
|
-
const lastStreamUpdateRef = React.useRef(Date.now());
|
|
699
704
|
const lastSnapshotRef = React.useRef("");
|
|
700
705
|
const [, setStreamTick] = React.useState(0);
|
|
701
706
|
React.useEffect(() => {
|
|
702
707
|
if (assistantStreamSnapshot !== lastSnapshotRef.current) {
|
|
703
708
|
lastSnapshotRef.current = assistantStreamSnapshot;
|
|
704
|
-
lastStreamUpdateRef.current = Date.now();
|
|
705
709
|
setStreamTick((value) => value + 1);
|
|
706
710
|
}
|
|
707
711
|
}, [assistantStreamSnapshot]);
|
|
708
|
-
React.useEffect(() => {
|
|
709
|
-
if (!isStreaming && !isSubmitting) return;
|
|
710
|
-
const interval = window.setInterval(() => {
|
|
711
|
-
setStreamTick((value) => value + 1);
|
|
712
|
-
}, 200);
|
|
713
|
-
return () => window.clearInterval(interval);
|
|
714
|
-
}, [isStreaming, isSubmitting]);
|
|
715
|
-
const idleDuringStream = isStreaming && Date.now() - lastStreamUpdateRef.current >= 300;
|
|
716
712
|
const showThinkingIndicator = isSubmitting || isStreaming && (!hasAnyVisibleSignal || hasPendingToolCall || // Tool just returned and the model hasn't started speaking yet.
|
|
717
|
-
hasCompletedToolCall && !trimmedContent
|
|
713
|
+
hasCompletedToolCall && !trimmedContent);
|
|
718
714
|
const activeRegistry = registry ?? defaultAiUiPartRegistry;
|
|
719
715
|
const uiParts = React.useMemo(
|
|
720
716
|
() => (uiPartsProp ?? []).map((part) => ({
|
|
@@ -1043,7 +1039,7 @@ function AiChat({
|
|
|
1043
1039
|
children: /* @__PURE__ */ jsx(Paperclip, { className: "size-4", "aria-hidden": true })
|
|
1044
1040
|
}
|
|
1045
1041
|
),
|
|
1046
|
-
|
|
1042
|
+
allowRuntimeOverride && modelProviders.length > 0 ? /* @__PURE__ */ jsx(
|
|
1047
1043
|
ModelPicker,
|
|
1048
1044
|
{
|
|
1049
1045
|
agentId: agent,
|
|
@@ -1103,6 +1099,7 @@ function AiChat({
|
|
|
1103
1099
|
{
|
|
1104
1100
|
tools: debugTools,
|
|
1105
1101
|
promptSections: debugPromptSections,
|
|
1102
|
+
loopTrace: loopTrace ?? chat.lastLoopTrace ?? void 0,
|
|
1106
1103
|
lastRequestDebug: chat.lastRequestDebug,
|
|
1107
1104
|
lastResponseDebug: chat.lastResponseDebug,
|
|
1108
1105
|
status: chat.status,
|
|
@@ -1116,6 +1113,7 @@ function AiChat({
|
|
|
1116
1113
|
function AiChatDebugPanel({
|
|
1117
1114
|
tools,
|
|
1118
1115
|
promptSections,
|
|
1116
|
+
loopTrace,
|
|
1119
1117
|
lastRequestDebug,
|
|
1120
1118
|
lastResponseDebug,
|
|
1121
1119
|
status,
|
|
@@ -1129,6 +1127,7 @@ function AiChatDebugPanel({
|
|
|
1129
1127
|
"data-ai-chat-debug": "true",
|
|
1130
1128
|
children: [
|
|
1131
1129
|
/* @__PURE__ */ jsx("div", { className: "font-semibold", children: t("ai_assistant.chat.debug.panelTitle", "Debug panel") }),
|
|
1130
|
+
loopTrace ? /* @__PURE__ */ jsx(LoopTracePanel, { trace: loopTrace }) : null,
|
|
1132
1131
|
/* @__PURE__ */ jsxs("details", { className: "rounded border border-border bg-background", "data-ai-chat-debug-section": "tools", open: true, children: [
|
|
1133
1132
|
/* @__PURE__ */ jsxs("summary", { className: "cursor-pointer px-2 py-1 font-semibold", children: [
|
|
1134
1133
|
t("ai_assistant.chat.debug.toolsSection", "Resolved tools"),
|