@gendive/chatllm 0.21.5 → 0.21.7
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/react/index.d.mts +65 -1
- package/dist/react/index.d.ts +65 -1
- package/dist/react/index.js +222 -38
- package/dist/react/index.js.map +1 -1
- package/dist/react/index.mjs +221 -38
- package/dist/react/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/react/index.mjs
CHANGED
|
@@ -2761,6 +2761,11 @@ ${projectMemoryContext}`);
|
|
|
2761
2761
|
- \uB370\uC774\uD130 \uBE44\uAD50/\uCD94\uC774 \u2192 html (Chart.js CDN \uC0AC\uC6A9, <artifact> \uD0DC\uADF8)
|
|
2762
2762
|
- \uC544\uC774\uCF58/\uB85C\uACE0/\uC77C\uB7EC\uC2A4\uD2B8 \u2192 svg
|
|
2763
2763
|
|
|
2764
|
+
**mermaid \uC8FC\uC758\uC0AC\uD56D:**
|
|
2765
|
+
- \uB178\uB4DC \uB77C\uBCA8\uC5D0 \uAD04\uD638 () \uC0AC\uC6A9 \uAE08\uC9C0 \u2192 \uB300\uAD04\uD638 [] \uC0AC\uC6A9: B[\uC0C1\uD0DC \uAD00\uB9AC useState] \u2705 B[\uC0C1\uD0DC \uAD00\uB9AC (useState)] \u274C
|
|
2766
|
+
- \uB178\uB4DC \uB77C\uBCA8\uC5D0 \uD2B9\uC218\uBB38\uC790\uAC00 \uC788\uC73C\uBA74 \uD070\uB530\uC634\uD45C\uB85C \uAC10\uC2F8\uAE30: B["API \uD638\uCD9C \u2192 \uC751\uB2F5"]
|
|
2767
|
+
- \uC18C\uAD04\uD638 ()\uB294 mermaid \uBB38\uBC95\uC5D0\uC11C \uB465\uADFC \uB178\uB4DC\uB97C \uC758\uBBF8\uD558\uBBC0\uB85C \uB77C\uBCA8 \uD14D\uC2A4\uD2B8\uC5D0 \uC808\uB300 \uD3EC\uD568\uD558\uC9C0 \uB9C8\uC138\uC694
|
|
2768
|
+
|
|
2764
2769
|
**mermaid \uC608\uC2DC:**
|
|
2765
2770
|
\`\`\`mermaid
|
|
2766
2771
|
graph TD
|
|
@@ -2785,7 +2790,7 @@ new Chart(document.getElementById('chart'), {
|
|
|
2785
2790
|
- html \uC2DC\uAC01\uD654\uB294 \uBC18\uB4DC\uC2DC <artifact language="html"> \uD0DC\uADF8\uB85C \uAC10\uC2F8\uC57C \uD568 (\`\`\`html \uCF54\uB4DC\uBE14\uB85D \uC0AC\uC6A9 \uAE08\uC9C0)
|
|
2786
2791
|
- \uC0AC\uC6A9\uC790\uAC00 \uC2DC\uAC01\uD654\uB97C \uC694\uCCAD\uD558\uC9C0 \uC54A\uC544\uB3C4 \uC801\uC808\uD558\uBA74 \uC790\uB3D9\uC73C\uB85C \uD3EC\uD568
|
|
2787
2792
|
- \uC2DC\uAC01\uD654 \uC55E\uB4A4\uC5D0 \uAC04\uACB0\uD55C \uD14D\uC2A4\uD2B8 \uC124\uBA85 \uD3EC\uD568
|
|
2788
|
-
- mermaid \
|
|
2793
|
+
- mermaid \uB178\uB4DC \uB77C\uBCA8\uC5D0 \uC18C\uAD04\uD638 () \uC808\uB300 \uC0AC\uC6A9 \uAE08\uC9C0 \u2014 \uD30C\uC2F1 \uC5D0\uB7EC \uC6D0\uC778`);
|
|
2789
2794
|
if (shouldIncludeSkills) {
|
|
2790
2795
|
const skillsPrompt = buildSkillsPrompt();
|
|
2791
2796
|
if (skillsPrompt) {
|
|
@@ -3118,18 +3123,29 @@ ${newConversation}
|
|
|
3118
3123
|
setIsSessionLoading(true);
|
|
3119
3124
|
try {
|
|
3120
3125
|
const sessionDetail = await onLoadSessionRef.current(id);
|
|
3121
|
-
let loadedMessages = sessionDetail.messages.map((m, idx) =>
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3126
|
+
let loadedMessages = sessionDetail.messages.map((m, idx) => {
|
|
3127
|
+
const msg = {
|
|
3128
|
+
id: m.id || generateId5("msg"),
|
|
3129
|
+
role: typeof m.role === "string" ? m.role.toLowerCase() : m.role,
|
|
3130
|
+
// API는 message 필드, 내부는 content 필드 사용
|
|
3131
|
+
content: m.content || m.message || "",
|
|
3132
|
+
timestamp: m.created_at ? new Date(m.created_at).getTime() : Date.now() - (sessionDetail.messages.length - idx) * 1e3,
|
|
3133
|
+
model: m.model,
|
|
3134
|
+
alternatives: m.alternatives,
|
|
3135
|
+
sources: m.sources,
|
|
3136
|
+
/** @Todo vibecode - 백엔드에서 전달받은 contentParts 복원 (이미지/파일 등) */
|
|
3137
|
+
...m.contentParts && { contentParts: m.contentParts }
|
|
3138
|
+
};
|
|
3139
|
+
if (!msg.contentParts && msg.role === "assistant" && hasArtifactTag(msg.content)) {
|
|
3140
|
+
const { artifacts, cleanContent } = parseArtifactsFromContent(msg.content);
|
|
3141
|
+
if (artifacts.length > 0) {
|
|
3142
|
+
const textPart = cleanContent.trim() ? [{ type: "text", content: cleanContent }] : [];
|
|
3143
|
+
msg.content = cleanContent;
|
|
3144
|
+
msg.contentParts = [...textPart, ...artifacts];
|
|
3145
|
+
}
|
|
3146
|
+
}
|
|
3147
|
+
return msg;
|
|
3148
|
+
});
|
|
3133
3149
|
let resolvedTitle = sessionDetail.title;
|
|
3134
3150
|
let resolvedSessionContext = sessionDetail.sessionContext;
|
|
3135
3151
|
if (loadedMessages.length === 0) {
|
|
@@ -3504,13 +3520,17 @@ ${finalContent}`;
|
|
|
3504
3520
|
for (const [skillName, skillConfig] of attachmentSkills) {
|
|
3505
3521
|
let matchedFiles = currentAttachments.filter((att) => {
|
|
3506
3522
|
if (!skillConfig.acceptedTypes || skillConfig.acceptedTypes.length === 0) return true;
|
|
3523
|
+
const fileName = (att.name || "").toLowerCase();
|
|
3524
|
+
const fileMime = (att.mimeType || "").toLowerCase();
|
|
3525
|
+
const fileExt = fileName.includes(".") ? fileName.slice(fileName.lastIndexOf(".")) : "";
|
|
3507
3526
|
return skillConfig.acceptedTypes.some((type) => {
|
|
3508
|
-
|
|
3509
|
-
if (
|
|
3510
|
-
|
|
3511
|
-
|
|
3527
|
+
const t = type.toLowerCase();
|
|
3528
|
+
if (t.startsWith(".")) return fileExt === t || fileName.endsWith(t);
|
|
3529
|
+
if (t.includes("*")) {
|
|
3530
|
+
const regex = new RegExp("^" + t.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace("\\*", ".*") + "$");
|
|
3531
|
+
return regex.test(fileMime);
|
|
3512
3532
|
}
|
|
3513
|
-
return
|
|
3533
|
+
return fileMime === t;
|
|
3514
3534
|
});
|
|
3515
3535
|
});
|
|
3516
3536
|
if (skipImageAttachmentSkill) {
|
|
@@ -3965,25 +3985,26 @@ ${attachmentContext}
|
|
|
3965
3985
|
}
|
|
3966
3986
|
}
|
|
3967
3987
|
}
|
|
3968
|
-
const saveMessagesOnEarlyReturn = () => {
|
|
3988
|
+
const saveMessagesOnEarlyReturn = (overrideContentParts) => {
|
|
3969
3989
|
if (!useExternalStorage || !capturedSessionId) return;
|
|
3970
|
-
|
|
3990
|
+
setTimeout(() => {
|
|
3971
3991
|
const latestSession = sessionsRef.current.find((s) => s.id === capturedSessionId);
|
|
3972
3992
|
if (!latestSession) return;
|
|
3973
3993
|
const latestMessages = latestSession.messages;
|
|
3974
3994
|
const assistantMsg = [...latestMessages].reverse().find((m) => m.role === "assistant");
|
|
3975
3995
|
const userMsg = latestMessages.find((m) => m.role === "user" && m.content === finalContent);
|
|
3976
3996
|
const assistantContent = assistantMsg?.content || "";
|
|
3977
|
-
|
|
3997
|
+
const finalContentParts = overrideContentParts || assistantMsg?.contentParts;
|
|
3998
|
+
if ((assistantContent || finalContentParts) && onSaveMessagesRef.current) {
|
|
3978
3999
|
onSaveMessagesRef.current(capturedSessionId, [
|
|
3979
4000
|
{ role: "user", message: finalContent, ...userMsg?.contentParts && { contentParts: userMsg.contentParts } },
|
|
3980
|
-
{ role: "assistant", message: assistantContent, ...
|
|
4001
|
+
{ role: "assistant", message: assistantContent, ...finalContentParts && { contentParts: finalContentParts } }
|
|
3981
4002
|
]).catch((e) => console.error("[useChatUI] Failed to save messages:", e));
|
|
3982
4003
|
}
|
|
3983
4004
|
if (latestSession.messages.length > 0) {
|
|
3984
4005
|
writeSessionCache(storageKey, latestSession);
|
|
3985
4006
|
}
|
|
3986
|
-
});
|
|
4007
|
+
}, 0);
|
|
3987
4008
|
};
|
|
3988
4009
|
if (!shouldSkipSkillParsing) {
|
|
3989
4010
|
const assistantContent = accumulatedContent;
|
|
@@ -4173,7 +4194,7 @@ ${attachmentContext}
|
|
|
4173
4194
|
promoteToSessionContext(capturedSessionId, toolName, result.content, result.metadata, toolLabel || toolName);
|
|
4174
4195
|
}
|
|
4175
4196
|
if (resultType === "image" || resultType === "file") {
|
|
4176
|
-
saveMessagesOnEarlyReturn();
|
|
4197
|
+
saveMessagesOnEarlyReturn(parts);
|
|
4177
4198
|
removeLoadingSession(capturedSessionId);
|
|
4178
4199
|
abortControllersRef.current.delete(capturedSessionId);
|
|
4179
4200
|
return;
|
|
@@ -4184,7 +4205,7 @@ ${attachmentContext}
|
|
|
4184
4205
|
shouldContinue = decision === "continue";
|
|
4185
4206
|
}
|
|
4186
4207
|
if (!shouldContinue) {
|
|
4187
|
-
saveMessagesOnEarlyReturn();
|
|
4208
|
+
saveMessagesOnEarlyReturn(parts);
|
|
4188
4209
|
removeLoadingSession(capturedSessionId);
|
|
4189
4210
|
abortControllersRef.current.delete(capturedSessionId);
|
|
4190
4211
|
return;
|
|
@@ -4259,13 +4280,13 @@ ${result.content}
|
|
|
4259
4280
|
shouldContinueImgFile = decision === "continue";
|
|
4260
4281
|
}
|
|
4261
4282
|
if (!shouldContinueImgFile) {
|
|
4262
|
-
saveMessagesOnEarlyReturn();
|
|
4283
|
+
saveMessagesOnEarlyReturn(imgFileParts);
|
|
4263
4284
|
removeLoadingSession(capturedSessionId);
|
|
4264
4285
|
abortControllersRef.current.delete(capturedSessionId);
|
|
4265
4286
|
return;
|
|
4266
4287
|
}
|
|
4267
4288
|
skipNextSkillParsingRef.current = true;
|
|
4268
|
-
saveMessagesOnEarlyReturn();
|
|
4289
|
+
saveMessagesOnEarlyReturn(imgFileParts);
|
|
4269
4290
|
const imgFilePrompt = skillResultType === "image" ? `"${detectedSkill.name}" \uC2A4\uD0AC\uB85C \uC774\uBBF8\uC9C0\uAC00 \uC0DD\uC131\uB418\uC5B4 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD45C\uC2DC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uC774\uBBF8\uC9C0 URL\uC744 \uD14D\uC2A4\uD2B8\uC5D0 \uD3EC\uD568\uD558\uC9C0 \uB9D0\uACE0, \uC0DD\uC131\uB41C \uC774\uBBF8\uC9C0\uC5D0 \uB300\uD574 \uAC04\uB2E8\uD788 \uC548\uB0B4\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.` : `"${detectedSkill.name}" \uC2A4\uD0AC\uB85C \uD30C\uC77C\uC774 \uC0DD\uC131\uB418\uC5B4 \uC0AC\uC6A9\uC790\uC5D0\uAC8C \uD45C\uC2DC\uB418\uC5C8\uC2B5\uB2C8\uB2E4. \uD30C\uC77C URL\uC744 \uD14D\uC2A4\uD2B8\uC5D0 \uD3EC\uD568\uD558\uC9C0 \uB9D0\uACE0, \uACB0\uACFC\uC5D0 \uB300\uD574 \uAC04\uB2E8\uD788 \uC548\uB0B4\uD574\uC8FC\uC138\uC694. skill_use \uD0DC\uADF8\uB294 \uC0AC\uC6A9\uD558\uC9C0 \uB9C8\uC138\uC694.`;
|
|
4270
4291
|
setTimeout(() => {
|
|
4271
4292
|
sendMessage(imgFilePrompt, { hiddenUserMessage: true });
|
|
@@ -10203,9 +10224,39 @@ var MermaidArtifact = ({ code }) => {
|
|
|
10203
10224
|
}
|
|
10204
10225
|
);
|
|
10205
10226
|
};
|
|
10206
|
-
var
|
|
10227
|
+
var svgToPngBlob = (svgString, scale = 2) => {
|
|
10228
|
+
return new Promise((resolve) => {
|
|
10229
|
+
const parser = new DOMParser();
|
|
10230
|
+
const doc = parser.parseFromString(svgString, "image/svg+xml");
|
|
10231
|
+
const svgEl = doc.querySelector("svg");
|
|
10232
|
+
if (!svgEl) return resolve(null);
|
|
10233
|
+
const w = parseInt(svgEl.getAttribute("width") || "800", 10);
|
|
10234
|
+
const h = parseInt(svgEl.getAttribute("height") || "600", 10);
|
|
10235
|
+
const canvas = document.createElement("canvas");
|
|
10236
|
+
canvas.width = w * scale;
|
|
10237
|
+
canvas.height = h * scale;
|
|
10238
|
+
const ctx = canvas.getContext("2d");
|
|
10239
|
+
if (!ctx) return resolve(null);
|
|
10240
|
+
ctx.scale(scale, scale);
|
|
10241
|
+
const blob = new Blob([new XMLSerializer().serializeToString(svgEl)], { type: "image/svg+xml;charset=utf-8" });
|
|
10242
|
+
const url = URL.createObjectURL(blob);
|
|
10243
|
+
const img = new Image();
|
|
10244
|
+
img.onload = () => {
|
|
10245
|
+
ctx.drawImage(img, 0, 0, w, h);
|
|
10246
|
+
URL.revokeObjectURL(url);
|
|
10247
|
+
canvas.toBlob((pngBlob) => resolve(pngBlob), "image/png");
|
|
10248
|
+
};
|
|
10249
|
+
img.onerror = () => {
|
|
10250
|
+
URL.revokeObjectURL(url);
|
|
10251
|
+
resolve(null);
|
|
10252
|
+
};
|
|
10253
|
+
img.src = url;
|
|
10254
|
+
});
|
|
10255
|
+
};
|
|
10256
|
+
var ArtifactActions = ({ code, language, containerRef }) => {
|
|
10207
10257
|
const [showCode, setShowCode] = useState15(false);
|
|
10208
10258
|
const [copied, setCopied] = useState15(false);
|
|
10259
|
+
const [saving, setSaving] = useState15(false);
|
|
10209
10260
|
const handleCopy = async () => {
|
|
10210
10261
|
try {
|
|
10211
10262
|
await navigator.clipboard.writeText(code);
|
|
@@ -10214,6 +10265,39 @@ var ArtifactActions = ({ code, language }) => {
|
|
|
10214
10265
|
} catch {
|
|
10215
10266
|
}
|
|
10216
10267
|
};
|
|
10268
|
+
const handleSaveImage = async () => {
|
|
10269
|
+
setSaving(true);
|
|
10270
|
+
try {
|
|
10271
|
+
let blob = null;
|
|
10272
|
+
if (language === "svg" || language === "mermaid") {
|
|
10273
|
+
const svgEl = containerRef?.current?.querySelector("svg");
|
|
10274
|
+
if (svgEl) {
|
|
10275
|
+
blob = await svgToPngBlob(svgEl.outerHTML);
|
|
10276
|
+
}
|
|
10277
|
+
} else if (language === "html") {
|
|
10278
|
+
const htmlBlob = new Blob([code], { type: "text/html;charset=utf-8" });
|
|
10279
|
+
const url = URL.createObjectURL(htmlBlob);
|
|
10280
|
+
const a = document.createElement("a");
|
|
10281
|
+
a.href = url;
|
|
10282
|
+
a.download = `artifact.html`;
|
|
10283
|
+
a.click();
|
|
10284
|
+
URL.revokeObjectURL(url);
|
|
10285
|
+
setSaving(false);
|
|
10286
|
+
return;
|
|
10287
|
+
}
|
|
10288
|
+
if (blob) {
|
|
10289
|
+
const url = URL.createObjectURL(blob);
|
|
10290
|
+
const a = document.createElement("a");
|
|
10291
|
+
a.href = url;
|
|
10292
|
+
a.download = `artifact.png`;
|
|
10293
|
+
a.click();
|
|
10294
|
+
URL.revokeObjectURL(url);
|
|
10295
|
+
}
|
|
10296
|
+
} catch {
|
|
10297
|
+
} finally {
|
|
10298
|
+
setSaving(false);
|
|
10299
|
+
}
|
|
10300
|
+
};
|
|
10217
10301
|
const langLabel = language === "mermaid" ? "Mermaid" : language === "svg" ? "SVG" : "HTML";
|
|
10218
10302
|
return /* @__PURE__ */ jsxs13("div", { children: [
|
|
10219
10303
|
/* @__PURE__ */ jsxs13(
|
|
@@ -10279,6 +10363,30 @@ var ArtifactActions = ({ code, language }) => {
|
|
|
10279
10363
|
copied ? "\uBCF5\uC0AC\uB428" : "\uBCF5\uC0AC"
|
|
10280
10364
|
]
|
|
10281
10365
|
}
|
|
10366
|
+
),
|
|
10367
|
+
/* @__PURE__ */ jsxs13(
|
|
10368
|
+
"button",
|
|
10369
|
+
{
|
|
10370
|
+
onClick: handleSaveImage,
|
|
10371
|
+
disabled: saving,
|
|
10372
|
+
style: {
|
|
10373
|
+
display: "flex",
|
|
10374
|
+
alignItems: "center",
|
|
10375
|
+
gap: "4px",
|
|
10376
|
+
padding: "4px 8px",
|
|
10377
|
+
fontSize: "12px",
|
|
10378
|
+
color: "var(--chatllm-text-muted, #64748b)",
|
|
10379
|
+
backgroundColor: "transparent",
|
|
10380
|
+
border: "none",
|
|
10381
|
+
borderRadius: "4px",
|
|
10382
|
+
cursor: saving ? "wait" : "pointer",
|
|
10383
|
+
opacity: saving ? 0.5 : 1
|
|
10384
|
+
},
|
|
10385
|
+
children: [
|
|
10386
|
+
/* @__PURE__ */ jsx14(IconSvg, { name: "download-line", size: 12, color: "var(--chatllm-text-muted, #64748b)" }),
|
|
10387
|
+
language === "html" ? "HTML \uC800\uC7A5" : "\uC774\uBBF8\uC9C0 \uC800\uC7A5"
|
|
10388
|
+
]
|
|
10389
|
+
}
|
|
10282
10390
|
)
|
|
10283
10391
|
]
|
|
10284
10392
|
}
|
|
@@ -10313,6 +10421,7 @@ var ArtifactActions = ({ code, language }) => {
|
|
|
10313
10421
|
] });
|
|
10314
10422
|
};
|
|
10315
10423
|
var ArtifactCard = ({ part, index = 0 }) => {
|
|
10424
|
+
const contentRef = useRef9(null);
|
|
10316
10425
|
return /* @__PURE__ */ jsxs13(
|
|
10317
10426
|
"div",
|
|
10318
10427
|
{
|
|
@@ -10352,12 +10461,12 @@ var ArtifactCard = ({ part, index = 0 }) => {
|
|
|
10352
10461
|
]
|
|
10353
10462
|
}
|
|
10354
10463
|
),
|
|
10355
|
-
/* @__PURE__ */ jsxs13("div", { style: { padding: part.language === "html" ? 0 : "12px" }, children: [
|
|
10464
|
+
/* @__PURE__ */ jsxs13("div", { ref: contentRef, style: { padding: part.language === "html" ? 0 : "12px" }, children: [
|
|
10356
10465
|
part.language === "html" && /* @__PURE__ */ jsx14(HtmlArtifact, { code: part.code }),
|
|
10357
10466
|
part.language === "svg" && /* @__PURE__ */ jsx14(SvgArtifact, { code: part.code }),
|
|
10358
10467
|
part.language === "mermaid" && /* @__PURE__ */ jsx14(MermaidArtifact, { code: part.code })
|
|
10359
10468
|
] }),
|
|
10360
|
-
/* @__PURE__ */ jsx14(ArtifactActions, { code: part.code, language: part.language })
|
|
10469
|
+
/* @__PURE__ */ jsx14(ArtifactActions, { code: part.code, language: part.language, containerRef: contentRef })
|
|
10361
10470
|
]
|
|
10362
10471
|
}
|
|
10363
10472
|
);
|
|
@@ -15196,6 +15305,7 @@ var useDragResize = (options) => {
|
|
|
15196
15305
|
const dragStartRef = useRef11(null);
|
|
15197
15306
|
const isDraggingRef = useRef11(false);
|
|
15198
15307
|
const wasDragRef = useRef11(false);
|
|
15308
|
+
const userDraggedRef = useRef11(false);
|
|
15199
15309
|
const dragDeltaRef = useRef11({ dx: 0, dy: 0 });
|
|
15200
15310
|
const fabElRef = useRef11(null);
|
|
15201
15311
|
const dragCleanupRef = useRef11(null);
|
|
@@ -15262,6 +15372,7 @@ var useDragResize = (options) => {
|
|
|
15262
15372
|
if (!isDraggingRef.current && distance > DRAG_THRESHOLD) {
|
|
15263
15373
|
isDraggingRef.current = true;
|
|
15264
15374
|
wasDragRef.current = true;
|
|
15375
|
+
userDraggedRef.current = true;
|
|
15265
15376
|
setIsDragging(true);
|
|
15266
15377
|
fabElRef.current?.classList.add("chatllm-fab-dragging");
|
|
15267
15378
|
}
|
|
@@ -15501,7 +15612,11 @@ var useDragResize = (options) => {
|
|
|
15501
15612
|
const newVw = window.innerWidth;
|
|
15502
15613
|
const newVh = window.innerHeight;
|
|
15503
15614
|
setViewport({ width: newVw, height: newVh });
|
|
15504
|
-
|
|
15615
|
+
if (!userDraggedRef.current) {
|
|
15616
|
+
setFabPos(getInitialFabPosition(initialPosition));
|
|
15617
|
+
} else {
|
|
15618
|
+
setFabPos((prev) => clampToViewport(prev.x, prev.y, newVw, newVh));
|
|
15619
|
+
}
|
|
15505
15620
|
};
|
|
15506
15621
|
window.addEventListener("resize", handleResize);
|
|
15507
15622
|
return () => window.removeEventListener("resize", handleResize);
|
|
@@ -17101,23 +17216,39 @@ var ChatFloatingWidget = ({
|
|
|
17101
17216
|
return [chatTab, ...customTabs];
|
|
17102
17217
|
}, [tabs]);
|
|
17103
17218
|
const [unreadBadge, setUnreadBadge] = useState28(0);
|
|
17104
|
-
const seenMessageIdsRef = useRef17(new Set(
|
|
17219
|
+
const seenMessageIdsRef = useRef17(/* @__PURE__ */ new Set());
|
|
17220
|
+
useEffect19(() => {
|
|
17221
|
+
if (seenMessageIdsRef.current.size === 0 && chatState.messages.length > 0) {
|
|
17222
|
+
for (const m of chatState.messages) {
|
|
17223
|
+
seenMessageIdsRef.current.add(m.id);
|
|
17224
|
+
}
|
|
17225
|
+
}
|
|
17226
|
+
}, [chatState.messages]);
|
|
17105
17227
|
useEffect19(() => {
|
|
17106
|
-
if (
|
|
17228
|
+
if (isOpen) {
|
|
17229
|
+
for (const m of chatState.messages) {
|
|
17230
|
+
seenMessageIdsRef.current.add(m.id);
|
|
17231
|
+
}
|
|
17232
|
+
} else {
|
|
17107
17233
|
const newAssistant = chatState.messages.filter(
|
|
17108
17234
|
(m) => m.role === "assistant" && !seenMessageIdsRef.current.has(m.id)
|
|
17109
17235
|
);
|
|
17110
17236
|
if (newAssistant.length > 0) {
|
|
17111
17237
|
setUnreadBadge((prev) => prev + newAssistant.length);
|
|
17238
|
+
for (const m of newAssistant) {
|
|
17239
|
+
seenMessageIdsRef.current.add(m.id);
|
|
17240
|
+
}
|
|
17112
17241
|
}
|
|
17113
17242
|
}
|
|
17114
|
-
for (const m of chatState.messages) {
|
|
17115
|
-
seenMessageIdsRef.current.add(m.id);
|
|
17116
|
-
}
|
|
17117
17243
|
}, [chatState.messages, isOpen]);
|
|
17118
17244
|
useEffect19(() => {
|
|
17119
|
-
if (isOpen)
|
|
17120
|
-
|
|
17245
|
+
if (isOpen) {
|
|
17246
|
+
setUnreadBadge(0);
|
|
17247
|
+
for (const m of chatState.messages) {
|
|
17248
|
+
seenMessageIdsRef.current.add(m.id);
|
|
17249
|
+
}
|
|
17250
|
+
}
|
|
17251
|
+
}, [isOpen, chatState.messages]);
|
|
17121
17252
|
const totalBadge = useMemo7(() => {
|
|
17122
17253
|
return tabs.reduce((sum, t) => sum + (t.badge || 0), 0) + unreadBadge;
|
|
17123
17254
|
}, [tabs, unreadBadge]);
|
|
@@ -17553,6 +17684,57 @@ var useDeepResearch = (options) => {
|
|
|
17553
17684
|
};
|
|
17554
17685
|
};
|
|
17555
17686
|
|
|
17687
|
+
// src/react/utils/conversationSearchAdapter.ts
|
|
17688
|
+
var formatSearchResults = (results) => {
|
|
17689
|
+
if (results.length === 0) {
|
|
17690
|
+
return "\uAD00\uB828 \uB300\uD654\uB97C \uCC3E\uC9C0 \uBABB\uD588\uC2B5\uB2C8\uB2E4.";
|
|
17691
|
+
}
|
|
17692
|
+
const formatted = results.map((r, i) => {
|
|
17693
|
+
const header = r.sessionTitle ? `[${r.sessionTitle}]` : "";
|
|
17694
|
+
const time = r.timestamp ? ` (${new Date(r.timestamp).toLocaleDateString("ko-KR")})` : "";
|
|
17695
|
+
return `[${i + 1}] ${header}${time} (${r.role}): ${r.content}`;
|
|
17696
|
+
}).join("\n\n");
|
|
17697
|
+
return `\uAC80\uC0C9 \uACB0\uACFC (${results.length}\uAC74):
|
|
17698
|
+
|
|
17699
|
+
${formatted}`;
|
|
17700
|
+
};
|
|
17701
|
+
var createConversationSearchSkill = (options) => {
|
|
17702
|
+
const { onSearch, label, disabled } = options;
|
|
17703
|
+
return {
|
|
17704
|
+
description: '\uC774\uC804 \uB300\uD654 \uB0B4\uC6A9\uC744 \uAC80\uC0C9\uD569\uB2C8\uB2E4. \uBC18\uB4DC\uC2DC \uD638\uCD9C\uD574\uC57C \uD558\uB294 \uC0C1\uD669: \uC0AC\uC6A9\uC790\uAC00 "\uC804\uC5D0", "\uC9C0\uB09C\uBC88\uC5D0", "\uC608\uC804\uC5D0", "\uC544\uAE4C", "\uC774\uC804\uC5D0", "\uB2E4\uC2DC \uC54C\uB824\uC918", "\uB610", "\uADF8\uB54C" \uB4F1 \uACFC\uAC70 \uB300\uD654\uB97C \uCC38\uC870\uD558\uB294 \uD45C\uD604\uC744 \uC0AC\uC6A9\uD560 \uB54C. \uACFC\uAC70\uC5D0 \uB17C\uC758\uD588\uB358 \uC8FC\uC81C\uB97C \uB2E4\uC2DC \uBB3C\uC5B4\uBCFC \uB54C\uB3C4 \uD638\uCD9C\uD558\uC138\uC694.',
|
|
17705
|
+
trigger: "auto",
|
|
17706
|
+
label: label || "\uB300\uD654 \uAC80\uC0C9",
|
|
17707
|
+
icon: "search-line",
|
|
17708
|
+
disabled,
|
|
17709
|
+
persist: false,
|
|
17710
|
+
parameters: {
|
|
17711
|
+
type: "object",
|
|
17712
|
+
properties: {
|
|
17713
|
+
query: {
|
|
17714
|
+
type: "string",
|
|
17715
|
+
description: "\uAC80\uC0C9 \uD0A4\uC6CC\uB4DC \uB610\uB294 \uBB38\uC7A5 (\uC0AC\uC6A9\uC790 \uC758\uB3C4\uB97C \uBC18\uC601\uD55C \uAC80\uC0C9\uC5B4)"
|
|
17716
|
+
},
|
|
17717
|
+
limit: {
|
|
17718
|
+
type: "number",
|
|
17719
|
+
description: "\uCD5C\uB300 \uACB0\uACFC \uC218 (\uAE30\uBCF8: 5)"
|
|
17720
|
+
}
|
|
17721
|
+
},
|
|
17722
|
+
required: ["query"]
|
|
17723
|
+
},
|
|
17724
|
+
execute: async (params) => {
|
|
17725
|
+
const { query, limit } = params;
|
|
17726
|
+
if (!query) {
|
|
17727
|
+
return { content: "\uAC80\uC0C9\uC5B4\uAC00 \uD544\uC694\uD569\uB2C8\uB2E4." };
|
|
17728
|
+
}
|
|
17729
|
+
const results = await onSearch(query, { limit: limit || 5 });
|
|
17730
|
+
return {
|
|
17731
|
+
content: formatSearchResults(results),
|
|
17732
|
+
metadata: { resultCount: results.length }
|
|
17733
|
+
};
|
|
17734
|
+
}
|
|
17735
|
+
};
|
|
17736
|
+
};
|
|
17737
|
+
|
|
17556
17738
|
// src/react/components/EmptyState.tsx
|
|
17557
17739
|
import { jsx as jsx31, jsxs as jsxs30 } from "react/jsx-runtime";
|
|
17558
17740
|
var EmptyState = ({
|
|
@@ -18068,6 +18250,7 @@ export {
|
|
|
18068
18250
|
convertSkillsToOpenAITools,
|
|
18069
18251
|
convertToolsToSkills,
|
|
18070
18252
|
createAdvancedResearchSkill,
|
|
18253
|
+
createConversationSearchSkill,
|
|
18071
18254
|
createDeepResearchSkill,
|
|
18072
18255
|
migrateSessionsToProjects,
|
|
18073
18256
|
useChatUI,
|