@open-mercato/ui 0.5.1-develop.3036.f02c281f23 → 0.5.1-develop.3045.b4b3320cc2
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 -1
- package/__integration__/TC-AI-UI-003-aichat-registry.spec.tsx +204 -0
- package/dist/ai/AiAssistantLauncher.js +596 -0
- package/dist/ai/AiAssistantLauncher.js.map +7 -0
- package/dist/ai/AiChat.js +1092 -0
- package/dist/ai/AiChat.js.map +7 -0
- package/dist/ai/AiChatSessions.js +297 -0
- package/dist/ai/AiChatSessions.js.map +7 -0
- package/dist/ai/AiDock.js +347 -0
- package/dist/ai/AiDock.js.map +7 -0
- package/dist/ai/AiMessageContent.js +369 -0
- package/dist/ai/AiMessageContent.js.map +7 -0
- package/dist/ai/ChatPaneTabs.js +251 -0
- package/dist/ai/ChatPaneTabs.js.map +7 -0
- package/dist/ai/index.js +115 -0
- package/dist/ai/index.js.map +7 -0
- package/dist/ai/parts/ConfirmationCard.js +211 -0
- package/dist/ai/parts/ConfirmationCard.js.map +7 -0
- package/dist/ai/parts/FieldDiffCard.js +119 -0
- package/dist/ai/parts/FieldDiffCard.js.map +7 -0
- package/dist/ai/parts/MutationPreviewCard.js +224 -0
- package/dist/ai/parts/MutationPreviewCard.js.map +7 -0
- package/dist/ai/parts/MutationResultCard.js +240 -0
- package/dist/ai/parts/MutationResultCard.js.map +7 -0
- package/dist/ai/parts/approval-cards-map.js +15 -0
- package/dist/ai/parts/approval-cards-map.js.map +7 -0
- package/dist/ai/parts/index.js +24 -0
- package/dist/ai/parts/index.js.map +7 -0
- package/dist/ai/parts/pending-action-api.js +60 -0
- package/dist/ai/parts/pending-action-api.js.map +7 -0
- package/dist/ai/parts/types.js +1 -0
- package/dist/ai/parts/types.js.map +7 -0
- package/dist/ai/parts/useAiPendingActionPolling.js +126 -0
- package/dist/ai/parts/useAiPendingActionPolling.js.map +7 -0
- package/dist/ai/records/ActivityCard.js +83 -0
- package/dist/ai/records/ActivityCard.js.map +7 -0
- package/dist/ai/records/CompanyCard.js +81 -0
- package/dist/ai/records/CompanyCard.js.map +7 -0
- package/dist/ai/records/DealCard.js +76 -0
- package/dist/ai/records/DealCard.js.map +7 -0
- package/dist/ai/records/PersonCard.js +68 -0
- package/dist/ai/records/PersonCard.js.map +7 -0
- package/dist/ai/records/ProductCard.js +68 -0
- package/dist/ai/records/ProductCard.js.map +7 -0
- package/dist/ai/records/RecordCard.js +29 -0
- package/dist/ai/records/RecordCard.js.map +7 -0
- package/dist/ai/records/RecordCardShell.js +103 -0
- package/dist/ai/records/RecordCardShell.js.map +7 -0
- package/dist/ai/records/index.js +31 -0
- package/dist/ai/records/index.js.map +7 -0
- package/dist/ai/records/registry.js +51 -0
- package/dist/ai/records/registry.js.map +7 -0
- package/dist/ai/records/types.js +1 -0
- package/dist/ai/records/types.js.map +7 -0
- package/dist/ai/ui-part-registry.js +112 -0
- package/dist/ai/ui-part-registry.js.map +7 -0
- package/dist/ai/ui-part-slots.js +14 -0
- package/dist/ai/ui-part-slots.js.map +7 -0
- package/dist/ai/ui-parts/pending-phase3-placeholder.js +35 -0
- package/dist/ai/ui-parts/pending-phase3-placeholder.js.map +7 -0
- package/dist/ai/upload-adapter.js +256 -0
- package/dist/ai/upload-adapter.js.map +7 -0
- package/dist/ai/useAiChat.js +549 -0
- package/dist/ai/useAiChat.js.map +7 -0
- package/dist/ai/useAiChatUpload.js +127 -0
- package/dist/ai/useAiChatUpload.js.map +7 -0
- package/dist/ai/useAiShortcuts.js +43 -0
- package/dist/ai/useAiShortcuts.js.map +7 -0
- package/dist/backend/AppShell.js +8 -4
- package/dist/backend/AppShell.js.map +2 -2
- package/dist/backend/BackendChromeProvider.js +2 -0
- package/dist/backend/BackendChromeProvider.js.map +2 -2
- package/dist/backend/DataTable.js +19 -2
- package/dist/backend/DataTable.js.map +2 -2
- package/dist/backend/FilterBar.js +19 -15
- package/dist/backend/FilterBar.js.map +2 -2
- package/dist/backend/dashboard/DashboardScreen.js +31 -3
- package/dist/backend/dashboard/DashboardScreen.js.map +2 -2
- package/dist/backend/injection/spotIds.js +6 -0
- package/dist/backend/injection/spotIds.js.map +2 -2
- package/dist/backend/notifications/useNotificationEffect.js +38 -2
- package/dist/backend/notifications/useNotificationEffect.js.map +2 -2
- package/dist/index.js +1 -0
- package/dist/index.js.map +2 -2
- package/jest.config.cjs +7 -1
- package/jest.markdown-mock.tsx +7 -0
- package/package.json +10 -4
- package/src/ai/AiAssistantLauncher.tsx +805 -0
- package/src/ai/AiChat.tsx +1483 -0
- package/src/ai/AiChatSessions.tsx +429 -0
- package/src/ai/AiDock.tsx +505 -0
- package/src/ai/AiMessageContent.tsx +515 -0
- package/src/ai/ChatPaneTabs.tsx +310 -0
- package/src/ai/__tests__/AiChat.conversation.test.tsx +160 -0
- package/src/ai/__tests__/AiChat.debug.test.tsx +152 -0
- package/src/ai/__tests__/AiChat.registry.test.tsx +213 -0
- package/src/ai/__tests__/AiChat.test.tsx +257 -0
- package/src/ai/__tests__/AiDock.test.tsx +124 -0
- package/src/ai/__tests__/AiMessageContent.test.ts +111 -0
- package/src/ai/__tests__/ui-part-registry.test.ts +199 -0
- package/src/ai/__tests__/ui-part-slots.test.ts +43 -0
- package/src/ai/__tests__/upload-adapter.test.ts +213 -0
- package/src/ai/__tests__/useAiChatUpload.test.tsx +163 -0
- package/src/ai/__tests__/useAiShortcuts.test.tsx +100 -0
- package/src/ai/index.ts +125 -0
- package/src/ai/parts/ConfirmationCard.tsx +310 -0
- package/src/ai/parts/FieldDiffCard.tsx +173 -0
- package/src/ai/parts/MutationPreviewCard.tsx +302 -0
- package/src/ai/parts/MutationResultCard.tsx +360 -0
- package/src/ai/parts/__tests__/ConfirmationCard.test.tsx +169 -0
- package/src/ai/parts/__tests__/FieldDiffCard.test.tsx +74 -0
- package/src/ai/parts/__tests__/MutationPreviewCard.test.tsx +177 -0
- package/src/ai/parts/__tests__/MutationResultCard.test.tsx +127 -0
- package/src/ai/parts/__tests__/useAiPendingActionPolling.test.tsx +151 -0
- package/src/ai/parts/approval-cards-map.ts +24 -0
- package/src/ai/parts/index.ts +27 -0
- package/src/ai/parts/pending-action-api.ts +123 -0
- package/src/ai/parts/types.ts +84 -0
- package/src/ai/parts/useAiPendingActionPolling.ts +210 -0
- package/src/ai/records/ActivityCard.tsx +102 -0
- package/src/ai/records/CompanyCard.tsx +89 -0
- package/src/ai/records/DealCard.tsx +85 -0
- package/src/ai/records/PersonCard.tsx +77 -0
- package/src/ai/records/ProductCard.tsx +83 -0
- package/src/ai/records/RecordCard.tsx +37 -0
- package/src/ai/records/RecordCardShell.tsx +169 -0
- package/src/ai/records/index.ts +30 -0
- package/src/ai/records/registry.tsx +80 -0
- package/src/ai/records/types.ts +90 -0
- package/src/ai/ui-part-registry.ts +233 -0
- package/src/ai/ui-part-slots.ts +32 -0
- package/src/ai/ui-parts/pending-phase3-placeholder.tsx +50 -0
- package/src/ai/upload-adapter.ts +421 -0
- package/src/ai/useAiChat.ts +865 -0
- package/src/ai/useAiChatUpload.ts +180 -0
- package/src/ai/useAiShortcuts.ts +79 -0
- package/src/backend/AppShell.tsx +12 -5
- package/src/backend/BackendChromeProvider.tsx +2 -0
- package/src/backend/DataTable.tsx +20 -1
- package/src/backend/FilterBar.tsx +26 -13
- package/src/backend/__tests__/BackendChromeProvider.test.tsx +45 -0
- package/src/backend/dashboard/DashboardScreen.tsx +38 -3
- package/src/backend/dashboard/__tests__/DashboardScreen.test.tsx +24 -1
- package/src/backend/injection/spotIds.ts +6 -0
- package/src/backend/notifications/__tests__/useNotificationEffect.test.tsx +77 -0
- package/src/backend/notifications/useNotificationEffect.ts +47 -2
- package/src/index.ts +1 -0
|
@@ -0,0 +1,369 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
import { jsx } from "react/jsx-runtime";
|
|
3
|
+
import * as React from "react";
|
|
4
|
+
import { MarkdownContent } from "../backend/markdown/MarkdownContent.js";
|
|
5
|
+
import { RecordCard } from "./records/RecordCard.js";
|
|
6
|
+
const RECORD_CARD_FENCE_INFO_PREFIX = "open-mercato:";
|
|
7
|
+
const KNOWN_KINDS = /* @__PURE__ */ new Set([
|
|
8
|
+
"deal",
|
|
9
|
+
"person",
|
|
10
|
+
"company",
|
|
11
|
+
"product",
|
|
12
|
+
"activity"
|
|
13
|
+
]);
|
|
14
|
+
const FENCE_RE = /```([^\n`]*)\n([\s\S]*?)(```|$)/g;
|
|
15
|
+
function findFences(input) {
|
|
16
|
+
const matches = [];
|
|
17
|
+
FENCE_RE.lastIndex = 0;
|
|
18
|
+
for (; ; ) {
|
|
19
|
+
const match = FENCE_RE.exec(input);
|
|
20
|
+
if (!match) break;
|
|
21
|
+
matches.push({
|
|
22
|
+
start: match.index,
|
|
23
|
+
end: match.index + match[0].length,
|
|
24
|
+
info: (match[1] ?? "").trim(),
|
|
25
|
+
body: match[2] ?? "",
|
|
26
|
+
closed: match[3] === "```"
|
|
27
|
+
});
|
|
28
|
+
if (match[0].length === 0) {
|
|
29
|
+
FENCE_RE.lastIndex += 1;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return matches;
|
|
33
|
+
}
|
|
34
|
+
function coerceKind(value) {
|
|
35
|
+
if (typeof value !== "string") return null;
|
|
36
|
+
const normalized = value.toLowerCase().trim();
|
|
37
|
+
return KNOWN_KINDS.has(normalized) ? normalized : null;
|
|
38
|
+
}
|
|
39
|
+
function normalizeStringList(value) {
|
|
40
|
+
if (!Array.isArray(value)) return null;
|
|
41
|
+
const out = [];
|
|
42
|
+
for (const entry of value) {
|
|
43
|
+
if (typeof entry === "string" && entry.trim()) {
|
|
44
|
+
out.push(entry.trim());
|
|
45
|
+
} else if (entry && typeof entry === "object") {
|
|
46
|
+
const maybeLabel = entry.label;
|
|
47
|
+
const maybeName = entry.name;
|
|
48
|
+
if (typeof maybeLabel === "string") out.push(maybeLabel);
|
|
49
|
+
else if (typeof maybeName === "string") out.push(maybeName);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return out;
|
|
53
|
+
}
|
|
54
|
+
function normalizeRecordPayload(kind, raw) {
|
|
55
|
+
const id = typeof raw.id === "string" ? raw.id : void 0;
|
|
56
|
+
const href = typeof raw.href === "string" ? raw.href : void 0;
|
|
57
|
+
const tags = normalizeStringList(raw.tags) ?? null;
|
|
58
|
+
const status = typeof raw.status === "string" ? raw.status : null;
|
|
59
|
+
if (kind === "deal") {
|
|
60
|
+
const title = typeof raw.title === "string" && raw.title || typeof raw.name === "string" && raw.name || null;
|
|
61
|
+
if (!title) return null;
|
|
62
|
+
const payload = {
|
|
63
|
+
id,
|
|
64
|
+
href,
|
|
65
|
+
title,
|
|
66
|
+
status,
|
|
67
|
+
stage: typeof raw.stage === "string" ? raw.stage : null,
|
|
68
|
+
amount: typeof raw.amount === "number" || typeof raw.amount === "string" ? raw.amount : null,
|
|
69
|
+
currency: typeof raw.currency === "string" ? raw.currency : null,
|
|
70
|
+
closeDate: typeof raw.closeDate === "string" ? raw.closeDate : typeof raw.close_date === "string" ? raw.close_date : null,
|
|
71
|
+
ownerName: typeof raw.ownerName === "string" ? raw.ownerName : typeof raw.owner === "string" ? raw.owner : null,
|
|
72
|
+
personName: typeof raw.personName === "string" ? raw.personName : null,
|
|
73
|
+
companyName: typeof raw.companyName === "string" ? raw.companyName : null,
|
|
74
|
+
description: typeof raw.description === "string" ? raw.description : null,
|
|
75
|
+
tags
|
|
76
|
+
};
|
|
77
|
+
return { kind: "deal", ...payload };
|
|
78
|
+
}
|
|
79
|
+
if (kind === "person") {
|
|
80
|
+
const name = typeof raw.name === "string" && raw.name || [
|
|
81
|
+
typeof raw.firstName === "string" ? raw.firstName : "",
|
|
82
|
+
typeof raw.lastName === "string" ? raw.lastName : ""
|
|
83
|
+
].filter(Boolean).join(" ").trim() || null;
|
|
84
|
+
if (!name) return null;
|
|
85
|
+
const payload = {
|
|
86
|
+
id,
|
|
87
|
+
href,
|
|
88
|
+
name,
|
|
89
|
+
title: typeof raw.title === "string" ? raw.title : null,
|
|
90
|
+
email: typeof raw.email === "string" ? raw.email : null,
|
|
91
|
+
phone: typeof raw.phone === "string" ? raw.phone : null,
|
|
92
|
+
companyName: typeof raw.companyName === "string" ? raw.companyName : null,
|
|
93
|
+
ownerName: typeof raw.ownerName === "string" ? raw.ownerName : null,
|
|
94
|
+
status,
|
|
95
|
+
tags,
|
|
96
|
+
avatarUrl: typeof raw.avatarUrl === "string" ? raw.avatarUrl : typeof raw.avatar === "string" ? raw.avatar : null
|
|
97
|
+
};
|
|
98
|
+
return { kind: "person", ...payload };
|
|
99
|
+
}
|
|
100
|
+
if (kind === "company") {
|
|
101
|
+
const name = typeof raw.name === "string" ? raw.name : null;
|
|
102
|
+
if (!name) return null;
|
|
103
|
+
const payload = {
|
|
104
|
+
id,
|
|
105
|
+
href,
|
|
106
|
+
name,
|
|
107
|
+
industry: typeof raw.industry === "string" ? raw.industry : null,
|
|
108
|
+
website: typeof raw.website === "string" ? raw.website : null,
|
|
109
|
+
email: typeof raw.email === "string" ? raw.email : null,
|
|
110
|
+
phone: typeof raw.phone === "string" ? raw.phone : null,
|
|
111
|
+
city: typeof raw.city === "string" ? raw.city : null,
|
|
112
|
+
country: typeof raw.country === "string" ? raw.country : null,
|
|
113
|
+
ownerName: typeof raw.ownerName === "string" ? raw.ownerName : null,
|
|
114
|
+
status,
|
|
115
|
+
tags,
|
|
116
|
+
logoUrl: typeof raw.logoUrl === "string" ? raw.logoUrl : typeof raw.logo === "string" ? raw.logo : null
|
|
117
|
+
};
|
|
118
|
+
return { kind: "company", ...payload };
|
|
119
|
+
}
|
|
120
|
+
if (kind === "product") {
|
|
121
|
+
const name = typeof raw.name === "string" && raw.name || typeof raw.title === "string" && raw.title || null;
|
|
122
|
+
if (!name) return null;
|
|
123
|
+
const payload = {
|
|
124
|
+
id,
|
|
125
|
+
href,
|
|
126
|
+
name,
|
|
127
|
+
sku: typeof raw.sku === "string" ? raw.sku : null,
|
|
128
|
+
price: typeof raw.price === "number" || typeof raw.price === "string" ? raw.price : null,
|
|
129
|
+
currency: typeof raw.currency === "string" ? raw.currency : null,
|
|
130
|
+
status,
|
|
131
|
+
category: typeof raw.category === "string" ? raw.category : null,
|
|
132
|
+
description: typeof raw.description === "string" ? raw.description : null,
|
|
133
|
+
imageUrl: typeof raw.imageUrl === "string" ? raw.imageUrl : typeof raw.image === "string" ? raw.image : null,
|
|
134
|
+
tags
|
|
135
|
+
};
|
|
136
|
+
return { kind: "product", ...payload };
|
|
137
|
+
}
|
|
138
|
+
if (kind === "activity") {
|
|
139
|
+
const title = typeof raw.title === "string" && raw.title || typeof raw.subject === "string" && raw.subject || null;
|
|
140
|
+
if (!title) return null;
|
|
141
|
+
const payload = {
|
|
142
|
+
id,
|
|
143
|
+
href,
|
|
144
|
+
title,
|
|
145
|
+
type: typeof raw.type === "string" ? raw.type : null,
|
|
146
|
+
status,
|
|
147
|
+
dueDate: typeof raw.dueDate === "string" ? raw.dueDate : typeof raw.due_at === "string" ? raw.due_at : null,
|
|
148
|
+
completedAt: typeof raw.completedAt === "string" ? raw.completedAt : typeof raw.completed_at === "string" ? raw.completed_at : null,
|
|
149
|
+
ownerName: typeof raw.ownerName === "string" ? raw.ownerName : null,
|
|
150
|
+
relatedTo: typeof raw.relatedTo === "string" ? raw.relatedTo : typeof raw.related === "string" ? raw.related : null,
|
|
151
|
+
description: typeof raw.description === "string" ? raw.description : null,
|
|
152
|
+
tags
|
|
153
|
+
};
|
|
154
|
+
return { kind: "activity", ...payload };
|
|
155
|
+
}
|
|
156
|
+
return null;
|
|
157
|
+
}
|
|
158
|
+
function tryParseRecordCard(info, body) {
|
|
159
|
+
if (!info.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) return null;
|
|
160
|
+
const kind = coerceKind(info.slice(RECORD_CARD_FENCE_INFO_PREFIX.length));
|
|
161
|
+
if (!kind) return null;
|
|
162
|
+
const trimmed = body.trim();
|
|
163
|
+
if (!trimmed) return null;
|
|
164
|
+
let parsed;
|
|
165
|
+
try {
|
|
166
|
+
parsed = JSON.parse(trimmed);
|
|
167
|
+
} catch {
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
if (Array.isArray(parsed)) {
|
|
171
|
+
if (parsed.length === 0) return null;
|
|
172
|
+
parsed = parsed[0];
|
|
173
|
+
}
|
|
174
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
175
|
+
return normalizeRecordPayload(kind, parsed);
|
|
176
|
+
}
|
|
177
|
+
function tryParseFencelessRecordCard(text, startInfoIndex) {
|
|
178
|
+
const infoPrefix = text.slice(startInfoIndex);
|
|
179
|
+
if (!infoPrefix.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) return null;
|
|
180
|
+
const afterPrefix = startInfoIndex + RECORD_CARD_FENCE_INFO_PREFIX.length;
|
|
181
|
+
let kindEnd = afterPrefix;
|
|
182
|
+
while (kindEnd < text.length) {
|
|
183
|
+
const ch = text[kindEnd];
|
|
184
|
+
if (ch === " " || ch === " " || ch === "\n" || ch === "\r" || ch === "{") break;
|
|
185
|
+
kindEnd += 1;
|
|
186
|
+
}
|
|
187
|
+
const kind = coerceKind(text.slice(afterPrefix, kindEnd));
|
|
188
|
+
if (!kind) return null;
|
|
189
|
+
let braceStart = kindEnd;
|
|
190
|
+
while (braceStart < text.length) {
|
|
191
|
+
const ch = text[braceStart];
|
|
192
|
+
if (ch === "{") break;
|
|
193
|
+
if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r") return null;
|
|
194
|
+
braceStart += 1;
|
|
195
|
+
}
|
|
196
|
+
if (braceStart >= text.length || text[braceStart] !== "{") return null;
|
|
197
|
+
let depth = 0;
|
|
198
|
+
let inString = false;
|
|
199
|
+
let escaped = false;
|
|
200
|
+
let braceEnd = -1;
|
|
201
|
+
for (let i = braceStart; i < text.length; i += 1) {
|
|
202
|
+
const ch = text[i];
|
|
203
|
+
if (escaped) {
|
|
204
|
+
escaped = false;
|
|
205
|
+
continue;
|
|
206
|
+
}
|
|
207
|
+
if (inString) {
|
|
208
|
+
if (ch === "\\") {
|
|
209
|
+
escaped = true;
|
|
210
|
+
continue;
|
|
211
|
+
}
|
|
212
|
+
if (ch === '"') {
|
|
213
|
+
inString = false;
|
|
214
|
+
continue;
|
|
215
|
+
}
|
|
216
|
+
continue;
|
|
217
|
+
}
|
|
218
|
+
if (ch === '"') {
|
|
219
|
+
inString = true;
|
|
220
|
+
continue;
|
|
221
|
+
}
|
|
222
|
+
if (ch === "{") depth += 1;
|
|
223
|
+
else if (ch === "}") {
|
|
224
|
+
depth -= 1;
|
|
225
|
+
if (depth === 0) {
|
|
226
|
+
braceEnd = i + 1;
|
|
227
|
+
break;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
if (braceEnd < 0) return null;
|
|
232
|
+
const jsonSlice = text.slice(braceStart, braceEnd);
|
|
233
|
+
let parsed;
|
|
234
|
+
try {
|
|
235
|
+
parsed = JSON.parse(jsonSlice);
|
|
236
|
+
} catch {
|
|
237
|
+
return null;
|
|
238
|
+
}
|
|
239
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) return null;
|
|
240
|
+
const payload = normalizeRecordPayload(kind, parsed);
|
|
241
|
+
if (!payload) return null;
|
|
242
|
+
return { payload, rawStart: startInfoIndex, rawEnd: braceEnd };
|
|
243
|
+
}
|
|
244
|
+
function liftFencelessCards(text) {
|
|
245
|
+
const out = [];
|
|
246
|
+
let cursor = 0;
|
|
247
|
+
while (cursor < text.length) {
|
|
248
|
+
const next = text.indexOf(RECORD_CARD_FENCE_INFO_PREFIX, cursor);
|
|
249
|
+
if (next < 0) break;
|
|
250
|
+
const recovered = tryParseFencelessRecordCard(text, next);
|
|
251
|
+
if (!recovered) {
|
|
252
|
+
cursor = next + RECORD_CARD_FENCE_INFO_PREFIX.length;
|
|
253
|
+
continue;
|
|
254
|
+
}
|
|
255
|
+
if (recovered.rawStart > cursor) {
|
|
256
|
+
const head = text.slice(cursor, recovered.rawStart);
|
|
257
|
+
if (head.trim().length > 0 || head.length > 0) {
|
|
258
|
+
out.push({ kind: "markdown", text: head });
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
out.push({
|
|
262
|
+
kind: "record-card",
|
|
263
|
+
payload: recovered.payload,
|
|
264
|
+
raw: text.slice(recovered.rawStart, recovered.rawEnd)
|
|
265
|
+
});
|
|
266
|
+
cursor = recovered.rawEnd;
|
|
267
|
+
}
|
|
268
|
+
if (cursor < text.length) {
|
|
269
|
+
out.push({ kind: "markdown", text: text.slice(cursor) });
|
|
270
|
+
}
|
|
271
|
+
return out.length > 0 ? out : [{ kind: "markdown", text }];
|
|
272
|
+
}
|
|
273
|
+
function parseAiContentSegments(content) {
|
|
274
|
+
if (!content) return [];
|
|
275
|
+
const fences = findFences(content);
|
|
276
|
+
const fenceSegments = [];
|
|
277
|
+
if (fences.length === 0) {
|
|
278
|
+
fenceSegments.push({ kind: "markdown", text: content });
|
|
279
|
+
} else {
|
|
280
|
+
let cursor = 0;
|
|
281
|
+
for (const fence of fences) {
|
|
282
|
+
if (!fence.info.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) {
|
|
283
|
+
continue;
|
|
284
|
+
}
|
|
285
|
+
if (!fence.closed) {
|
|
286
|
+
if (fence.start > cursor) {
|
|
287
|
+
fenceSegments.push({ kind: "markdown", text: content.slice(cursor, fence.start) });
|
|
288
|
+
}
|
|
289
|
+
cursor = content.length;
|
|
290
|
+
break;
|
|
291
|
+
}
|
|
292
|
+
if (fence.start > cursor) {
|
|
293
|
+
fenceSegments.push({ kind: "markdown", text: content.slice(cursor, fence.start) });
|
|
294
|
+
}
|
|
295
|
+
const payload = tryParseRecordCard(fence.info, fence.body);
|
|
296
|
+
if (payload) {
|
|
297
|
+
fenceSegments.push({
|
|
298
|
+
kind: "record-card",
|
|
299
|
+
payload,
|
|
300
|
+
raw: content.slice(fence.start, fence.end)
|
|
301
|
+
});
|
|
302
|
+
} else {
|
|
303
|
+
fenceSegments.push({
|
|
304
|
+
kind: "invalid-card",
|
|
305
|
+
info: fence.info,
|
|
306
|
+
raw: content.slice(fence.start, fence.end)
|
|
307
|
+
});
|
|
308
|
+
}
|
|
309
|
+
cursor = fence.end;
|
|
310
|
+
}
|
|
311
|
+
if (cursor < content.length) {
|
|
312
|
+
fenceSegments.push({ kind: "markdown", text: content.slice(cursor) });
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
const out = [];
|
|
316
|
+
for (const segment of fenceSegments) {
|
|
317
|
+
if (segment.kind !== "markdown") {
|
|
318
|
+
out.push(segment);
|
|
319
|
+
continue;
|
|
320
|
+
}
|
|
321
|
+
if (!segment.text.includes(RECORD_CARD_FENCE_INFO_PREFIX)) {
|
|
322
|
+
out.push(segment);
|
|
323
|
+
continue;
|
|
324
|
+
}
|
|
325
|
+
out.push(...liftFencelessCards(segment.text));
|
|
326
|
+
}
|
|
327
|
+
return out;
|
|
328
|
+
}
|
|
329
|
+
function AiMessageContent({ content, className }) {
|
|
330
|
+
const segments = React.useMemo(() => parseAiContentSegments(content), [content]);
|
|
331
|
+
if (segments.length === 0) {
|
|
332
|
+
return null;
|
|
333
|
+
}
|
|
334
|
+
return /* @__PURE__ */ jsx("div", { className, "data-ai-message-content": "", children: segments.map((segment, index) => {
|
|
335
|
+
if (segment.kind === "record-card") {
|
|
336
|
+
return /* @__PURE__ */ jsx(RecordCard, { data: segment.payload }, `card-${index}`);
|
|
337
|
+
}
|
|
338
|
+
if (segment.kind === "invalid-card") {
|
|
339
|
+
return /* @__PURE__ */ jsx(
|
|
340
|
+
"pre",
|
|
341
|
+
{
|
|
342
|
+
className: "my-2 max-h-60 overflow-auto rounded-md border border-dashed border-border bg-muted p-2 text-xs",
|
|
343
|
+
children: segment.raw
|
|
344
|
+
},
|
|
345
|
+
`raw-${index}`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
if (!segment.text.trim()) {
|
|
349
|
+
return null;
|
|
350
|
+
}
|
|
351
|
+
return /* @__PURE__ */ jsx(
|
|
352
|
+
MarkdownContent,
|
|
353
|
+
{
|
|
354
|
+
body: segment.text,
|
|
355
|
+
format: "markdown",
|
|
356
|
+
className: "ai-markdown text-sm leading-relaxed [&_a]:text-primary [&_a]:underline [&_a:hover]:text-primary/80 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[12px] [&_pre]:my-2 [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-2 [&_pre]:text-xs [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-5 [&_p]:my-1 [&_h1]:mt-2 [&_h1]:text-base [&_h1]:font-semibold [&_h2]:mt-2 [&_h2]:text-sm [&_h2]:font-semibold [&_h3]:mt-2 [&_h3]:text-sm [&_h3]:font-semibold"
|
|
357
|
+
},
|
|
358
|
+
`md-${index}`
|
|
359
|
+
);
|
|
360
|
+
}) });
|
|
361
|
+
}
|
|
362
|
+
var AiMessageContent_default = AiMessageContent;
|
|
363
|
+
export {
|
|
364
|
+
AiMessageContent,
|
|
365
|
+
RECORD_CARD_FENCE_INFO_PREFIX,
|
|
366
|
+
AiMessageContent_default as default,
|
|
367
|
+
parseAiContentSegments
|
|
368
|
+
};
|
|
369
|
+
//# sourceMappingURL=AiMessageContent.js.map
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 3,
|
|
3
|
+
"sources": ["../../src/ai/AiMessageContent.tsx"],
|
|
4
|
+
"sourcesContent": ["\"use client\"\n\nimport * as React from 'react'\nimport { MarkdownContent } from '../backend/markdown/MarkdownContent'\nimport { RecordCard } from './records/RecordCard'\nimport type {\n ActivityRecordPayload,\n CompanyRecordPayload,\n DealRecordPayload,\n PersonRecordPayload,\n ProductRecordPayload,\n RecordCardKind,\n RecordCardPayload,\n} from './records/types'\n\n/**\n * Info-string prefix recognised inside fenced code blocks. Anything matching\n * ```open-mercato:<kind>``` is parsed as JSON and rendered via the matching\n * record card. Unknown kinds fall back to a plain `<code>` block so the\n * transcript never crashes on a malformed widget payload.\n */\nexport const RECORD_CARD_FENCE_INFO_PREFIX = 'open-mercato:'\n\nconst KNOWN_KINDS: ReadonlySet<RecordCardKind> = new Set([\n 'deal',\n 'person',\n 'company',\n 'product',\n 'activity',\n])\n\nexport type AiMessageContentSegment =\n | { kind: 'markdown'; text: string }\n | { kind: 'record-card'; payload: RecordCardPayload; raw: string }\n | { kind: 'invalid-card'; info: string; raw: string }\n\ninterface FenceMatch {\n start: number\n end: number\n info: string\n body: string\n closed: boolean\n}\n\nconst FENCE_RE = /```([^\\n`]*)\\n([\\s\\S]*?)(```|$)/g\n\nfunction findFences(input: string): FenceMatch[] {\n const matches: FenceMatch[] = []\n FENCE_RE.lastIndex = 0\n for (;;) {\n const match = FENCE_RE.exec(input)\n if (!match) break\n matches.push({\n start: match.index,\n end: match.index + match[0].length,\n info: (match[1] ?? '').trim(),\n body: match[2] ?? '',\n closed: match[3] === '```',\n })\n if (match[0].length === 0) {\n FENCE_RE.lastIndex += 1\n }\n }\n return matches\n}\n\nfunction coerceKind(value: unknown): RecordCardKind | null {\n if (typeof value !== 'string') return null\n const normalized = value.toLowerCase().trim()\n return KNOWN_KINDS.has(normalized as RecordCardKind)\n ? (normalized as RecordCardKind)\n : null\n}\n\nfunction normalizeStringList(value: unknown): string[] | null {\n if (!Array.isArray(value)) return null\n const out: string[] = []\n for (const entry of value) {\n if (typeof entry === 'string' && entry.trim()) {\n out.push(entry.trim())\n } else if (entry && typeof entry === 'object') {\n const maybeLabel = (entry as { label?: unknown; name?: unknown }).label\n const maybeName = (entry as { name?: unknown }).name\n if (typeof maybeLabel === 'string') out.push(maybeLabel)\n else if (typeof maybeName === 'string') out.push(maybeName)\n }\n }\n return out\n}\n\nfunction normalizeRecordPayload(\n kind: RecordCardKind,\n raw: Record<string, unknown>,\n): RecordCardPayload | null {\n const id = typeof raw.id === 'string' ? raw.id : undefined\n const href = typeof raw.href === 'string' ? raw.href : undefined\n const tags = normalizeStringList(raw.tags) ?? null\n const status = typeof raw.status === 'string' ? raw.status : null\n\n if (kind === 'deal') {\n const title =\n (typeof raw.title === 'string' && raw.title) ||\n (typeof raw.name === 'string' && raw.name) ||\n null\n if (!title) return null\n const payload: DealRecordPayload = {\n id,\n href,\n title,\n status,\n stage: typeof raw.stage === 'string' ? raw.stage : null,\n amount:\n typeof raw.amount === 'number' || typeof raw.amount === 'string'\n ? raw.amount\n : null,\n currency: typeof raw.currency === 'string' ? raw.currency : null,\n closeDate:\n typeof raw.closeDate === 'string'\n ? raw.closeDate\n : typeof (raw as { close_date?: unknown }).close_date === 'string'\n ? (raw as { close_date: string }).close_date\n : null,\n ownerName:\n typeof raw.ownerName === 'string'\n ? raw.ownerName\n : typeof (raw as { owner?: unknown }).owner === 'string'\n ? (raw as { owner: string }).owner\n : null,\n personName: typeof raw.personName === 'string' ? raw.personName : null,\n companyName: typeof raw.companyName === 'string' ? raw.companyName : null,\n description: typeof raw.description === 'string' ? raw.description : null,\n tags,\n }\n return { kind: 'deal', ...payload }\n }\n\n if (kind === 'person') {\n const name =\n (typeof raw.name === 'string' && raw.name) ||\n [\n typeof raw.firstName === 'string' ? raw.firstName : '',\n typeof raw.lastName === 'string' ? raw.lastName : '',\n ]\n .filter(Boolean)\n .join(' ')\n .trim() ||\n null\n if (!name) return null\n const payload: PersonRecordPayload = {\n id,\n href,\n name,\n title: typeof raw.title === 'string' ? raw.title : null,\n email: typeof raw.email === 'string' ? raw.email : null,\n phone: typeof raw.phone === 'string' ? raw.phone : null,\n companyName: typeof raw.companyName === 'string' ? raw.companyName : null,\n ownerName: typeof raw.ownerName === 'string' ? raw.ownerName : null,\n status,\n tags,\n avatarUrl:\n typeof raw.avatarUrl === 'string'\n ? raw.avatarUrl\n : typeof (raw as { avatar?: unknown }).avatar === 'string'\n ? (raw as { avatar: string }).avatar\n : null,\n }\n return { kind: 'person', ...payload }\n }\n\n if (kind === 'company') {\n const name = typeof raw.name === 'string' ? raw.name : null\n if (!name) return null\n const payload: CompanyRecordPayload = {\n id,\n href,\n name,\n industry: typeof raw.industry === 'string' ? raw.industry : null,\n website: typeof raw.website === 'string' ? raw.website : null,\n email: typeof raw.email === 'string' ? raw.email : null,\n phone: typeof raw.phone === 'string' ? raw.phone : null,\n city: typeof raw.city === 'string' ? raw.city : null,\n country: typeof raw.country === 'string' ? raw.country : null,\n ownerName: typeof raw.ownerName === 'string' ? raw.ownerName : null,\n status,\n tags,\n logoUrl:\n typeof raw.logoUrl === 'string'\n ? raw.logoUrl\n : typeof (raw as { logo?: unknown }).logo === 'string'\n ? (raw as { logo: string }).logo\n : null,\n }\n return { kind: 'company', ...payload }\n }\n\n if (kind === 'product') {\n const name =\n (typeof raw.name === 'string' && raw.name) ||\n (typeof raw.title === 'string' && raw.title) ||\n null\n if (!name) return null\n const payload: ProductRecordPayload = {\n id,\n href,\n name,\n sku: typeof raw.sku === 'string' ? raw.sku : null,\n price:\n typeof raw.price === 'number' || typeof raw.price === 'string'\n ? raw.price\n : null,\n currency: typeof raw.currency === 'string' ? raw.currency : null,\n status,\n category: typeof raw.category === 'string' ? raw.category : null,\n description: typeof raw.description === 'string' ? raw.description : null,\n imageUrl:\n typeof raw.imageUrl === 'string'\n ? raw.imageUrl\n : typeof (raw as { image?: unknown }).image === 'string'\n ? (raw as { image: string }).image\n : null,\n tags,\n }\n return { kind: 'product', ...payload }\n }\n\n if (kind === 'activity') {\n const title =\n (typeof raw.title === 'string' && raw.title) ||\n (typeof raw.subject === 'string' && raw.subject) ||\n null\n if (!title) return null\n const payload: ActivityRecordPayload = {\n id,\n href,\n title,\n type: typeof raw.type === 'string' ? raw.type : null,\n status,\n dueDate:\n typeof raw.dueDate === 'string'\n ? raw.dueDate\n : typeof (raw as { due_at?: unknown }).due_at === 'string'\n ? (raw as { due_at: string }).due_at\n : null,\n completedAt:\n typeof raw.completedAt === 'string'\n ? raw.completedAt\n : typeof (raw as { completed_at?: unknown }).completed_at === 'string'\n ? (raw as { completed_at: string }).completed_at\n : null,\n ownerName: typeof raw.ownerName === 'string' ? raw.ownerName : null,\n relatedTo:\n typeof raw.relatedTo === 'string'\n ? raw.relatedTo\n : typeof (raw as { related?: unknown }).related === 'string'\n ? (raw as { related: string }).related\n : null,\n description: typeof raw.description === 'string' ? raw.description : null,\n tags,\n }\n return { kind: 'activity', ...payload }\n }\n\n return null\n}\n\nfunction tryParseRecordCard(\n info: string,\n body: string,\n): RecordCardPayload | null {\n if (!info.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) return null\n const kind = coerceKind(info.slice(RECORD_CARD_FENCE_INFO_PREFIX.length))\n if (!kind) return null\n const trimmed = body.trim()\n if (!trimmed) return null\n let parsed: unknown\n try {\n parsed = JSON.parse(trimmed)\n } catch {\n return null\n }\n if (Array.isArray(parsed)) {\n // Take the first entry; multiple cards can be emitted as multiple fences.\n if (parsed.length === 0) return null\n parsed = parsed[0]\n }\n if (!parsed || typeof parsed !== 'object') return null\n return normalizeRecordPayload(kind, parsed as Record<string, unknown>)\n}\n\n/**\n * Recognise an `open-mercato:<kind> { ... }` token the model emitted\n * WITHOUT triple backticks and pull the JSON object out by counting\n * matching braces. Returns the parsed payload + the slice that should be\n * removed from the surrounding text.\n *\n * Models routinely drop the fence on this pattern (especially when the\n * card is one of many in a list) and the fallback renders the line as\n * plain prose, which is the user-visible bug we are guarding against.\n */\nfunction tryParseFencelessRecordCard(\n text: string,\n startInfoIndex: number,\n): { payload: RecordCardPayload; rawStart: number; rawEnd: number } | null {\n const infoPrefix = text.slice(startInfoIndex)\n if (!infoPrefix.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) return null\n // Read the kind up to the first whitespace, brace, or end-of-line.\n const afterPrefix = startInfoIndex + RECORD_CARD_FENCE_INFO_PREFIX.length\n let kindEnd = afterPrefix\n while (kindEnd < text.length) {\n const ch = text[kindEnd]\n if (ch === ' ' || ch === '\\t' || ch === '\\n' || ch === '\\r' || ch === '{') break\n kindEnd += 1\n }\n const kind = coerceKind(text.slice(afterPrefix, kindEnd))\n if (!kind) return null\n // Skip whitespace/newlines until we find the opening brace.\n let braceStart = kindEnd\n while (braceStart < text.length) {\n const ch = text[braceStart]\n if (ch === '{') break\n if (ch !== ' ' && ch !== '\\t' && ch !== '\\n' && ch !== '\\r') return null\n braceStart += 1\n }\n if (braceStart >= text.length || text[braceStart] !== '{') return null\n // Walk forward counting brace depth, respecting strings.\n let depth = 0\n let inString = false\n let escaped = false\n let braceEnd = -1\n for (let i = braceStart; i < text.length; i += 1) {\n const ch = text[i]\n if (escaped) {\n escaped = false\n continue\n }\n if (inString) {\n if (ch === '\\\\') { escaped = true; continue }\n if (ch === '\"') { inString = false; continue }\n continue\n }\n if (ch === '\"') { inString = true; continue }\n if (ch === '{') depth += 1\n else if (ch === '}') {\n depth -= 1\n if (depth === 0) { braceEnd = i + 1; break }\n }\n }\n if (braceEnd < 0) return null\n const jsonSlice = text.slice(braceStart, braceEnd)\n let parsed: unknown\n try {\n parsed = JSON.parse(jsonSlice)\n } catch {\n return null\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null\n const payload = normalizeRecordPayload(kind, parsed as Record<string, unknown>)\n if (!payload) return null\n return { payload, rawStart: startInfoIndex, rawEnd: braceEnd }\n}\n\n/**\n * Walk through a markdown segment and pull every `open-mercato:<kind>\n * { ... }` token (whether or not the model wrapped it in backticks) into\n * a record-card segment. Trailing/leading whitespace around the lifted\n * card is normalised so the surrounding prose stays clean.\n */\nfunction liftFencelessCards(text: string): AiMessageContentSegment[] {\n const out: AiMessageContentSegment[] = []\n let cursor = 0\n while (cursor < text.length) {\n const next = text.indexOf(RECORD_CARD_FENCE_INFO_PREFIX, cursor)\n if (next < 0) break\n const recovered = tryParseFencelessRecordCard(text, next)\n if (!recovered) {\n // Skip this occurrence to avoid an infinite loop.\n cursor = next + RECORD_CARD_FENCE_INFO_PREFIX.length\n continue\n }\n if (recovered.rawStart > cursor) {\n const head = text.slice(cursor, recovered.rawStart)\n if (head.trim().length > 0 || head.length > 0) {\n // Keep whitespace so list separators between cards survive.\n out.push({ kind: 'markdown', text: head })\n }\n }\n out.push({\n kind: 'record-card',\n payload: recovered.payload,\n raw: text.slice(recovered.rawStart, recovered.rawEnd),\n })\n cursor = recovered.rawEnd\n }\n if (cursor < text.length) {\n out.push({ kind: 'markdown', text: text.slice(cursor) })\n }\n return out.length > 0 ? out : [{ kind: 'markdown', text }]\n}\n\n/**\n * Split assistant text into ordered segments: markdown chunks interleaved\n * with parsed record-card payloads. Open / closing fences are matched\n * greedily \u2014 an unterminated fence is treated as still-in-flight markdown\n * (so partial streaming output never renders a half-built card). After\n * the fence pass, any remaining markdown segment is scanned for\n * `open-mercato:<kind> { ... }` tokens the model emitted without\n * backticks (a common LLM drift) and those are lifted into card segments\n * as well.\n */\nexport function parseAiContentSegments(content: string): AiMessageContentSegment[] {\n if (!content) return []\n const fences = findFences(content)\n const fenceSegments: AiMessageContentSegment[] = []\n if (fences.length === 0) {\n fenceSegments.push({ kind: 'markdown', text: content })\n } else {\n let cursor = 0\n for (const fence of fences) {\n if (!fence.info.startsWith(RECORD_CARD_FENCE_INFO_PREFIX)) {\n // Plain code fence \u2014 leave it for the markdown renderer.\n continue\n }\n if (!fence.closed) {\n // Streaming a card body: keep the leading text rendered, swallow the\n // half-arrived block until it closes.\n if (fence.start > cursor) {\n fenceSegments.push({ kind: 'markdown', text: content.slice(cursor, fence.start) })\n }\n cursor = content.length\n break\n }\n if (fence.start > cursor) {\n fenceSegments.push({ kind: 'markdown', text: content.slice(cursor, fence.start) })\n }\n const payload = tryParseRecordCard(fence.info, fence.body)\n if (payload) {\n fenceSegments.push({\n kind: 'record-card',\n payload,\n raw: content.slice(fence.start, fence.end),\n })\n } else {\n fenceSegments.push({\n kind: 'invalid-card',\n info: fence.info,\n raw: content.slice(fence.start, fence.end),\n })\n }\n cursor = fence.end\n }\n if (cursor < content.length) {\n fenceSegments.push({ kind: 'markdown', text: content.slice(cursor) })\n }\n }\n // Recovery pass: lift fenceless `open-mercato:<kind> { ... }` tokens out\n // of any remaining markdown segments. The model often forgets the\n // triple-backtick wrapper, especially when emitting many cards in a row.\n const out: AiMessageContentSegment[] = []\n for (const segment of fenceSegments) {\n if (segment.kind !== 'markdown') {\n out.push(segment)\n continue\n }\n if (!segment.text.includes(RECORD_CARD_FENCE_INFO_PREFIX)) {\n out.push(segment)\n continue\n }\n out.push(...liftFencelessCards(segment.text))\n }\n return out\n}\n\nexport interface AiMessageContentProps {\n content: string\n className?: string\n}\n\nexport function AiMessageContent({ content, className }: AiMessageContentProps) {\n const segments = React.useMemo(() => parseAiContentSegments(content), [content])\n if (segments.length === 0) {\n return null\n }\n return (\n <div className={className} data-ai-message-content=\"\">\n {segments.map((segment, index) => {\n if (segment.kind === 'record-card') {\n return <RecordCard key={`card-${index}`} data={segment.payload} />\n }\n if (segment.kind === 'invalid-card') {\n return (\n <pre\n key={`raw-${index}`}\n className=\"my-2 max-h-60 overflow-auto rounded-md border border-dashed border-border bg-muted p-2 text-xs\"\n >\n {segment.raw}\n </pre>\n )\n }\n if (!segment.text.trim()) {\n return null\n }\n return (\n <MarkdownContent\n key={`md-${index}`}\n body={segment.text}\n format=\"markdown\"\n className=\"ai-markdown text-sm leading-relaxed [&_a]:text-primary [&_a]:underline [&_a:hover]:text-primary/80 [&_code]:rounded [&_code]:bg-muted [&_code]:px-1 [&_code]:py-0.5 [&_code]:text-[12px] [&_pre]:my-2 [&_pre]:overflow-auto [&_pre]:rounded-md [&_pre]:bg-muted [&_pre]:p-2 [&_pre]:text-xs [&_ul]:my-1 [&_ul]:list-disc [&_ul]:pl-5 [&_ol]:my-1 [&_ol]:list-decimal [&_ol]:pl-5 [&_p]:my-1 [&_h1]:mt-2 [&_h1]:text-base [&_h1]:font-semibold [&_h2]:mt-2 [&_h2]:text-sm [&_h2]:font-semibold [&_h3]:mt-2 [&_h3]:text-sm [&_h3]:font-semibold\"\n />\n )\n })}\n </div>\n )\n}\n\nexport default AiMessageContent\n"],
|
|
5
|
+
"mappings": "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",
|
|
6
|
+
"names": []
|
|
7
|
+
}
|