@cremini/skillpack 1.0.9 → 1.1.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/README.md +4 -4
- package/dist/cli.js +4 -0
- package/package.json +4 -3
- package/runtime/README.md +11 -1
- package/runtime/server/dist/adapters/markdown.js +74 -0
- package/runtime/server/dist/adapters/markdown.js.map +1 -0
- package/runtime/server/dist/adapters/slack.js +369 -0
- package/runtime/server/dist/adapters/slack.js.map +1 -0
- package/runtime/server/dist/adapters/telegram.js +199 -0
- package/runtime/server/dist/adapters/telegram.js.map +1 -0
- package/runtime/server/dist/adapters/types.js +2 -0
- package/runtime/server/dist/adapters/types.js.map +1 -0
- package/runtime/server/dist/adapters/web.js +201 -0
- package/runtime/server/dist/adapters/web.js.map +1 -0
- package/runtime/server/dist/agent.js +223 -0
- package/runtime/server/dist/agent.js.map +1 -0
- package/runtime/server/dist/config.js +79 -0
- package/runtime/server/dist/config.js.map +1 -0
- package/runtime/server/dist/index.js +146 -0
- package/runtime/server/dist/index.js.map +1 -0
- package/runtime/server/dist/lifecycle.js +85 -0
- package/runtime/server/dist/lifecycle.js.map +1 -0
- package/runtime/server/dist/memory.js +195 -0
- package/runtime/server/dist/memory.js.map +1 -0
- package/runtime/server/package-lock.json +4028 -244
- package/runtime/server/package.json +13 -3
- package/runtime/start.bat +40 -4
- package/runtime/start.sh +30 -2
- package/runtime/web/index.html +145 -18
- package/runtime/web/js/api-key-dialog.js +153 -0
- package/runtime/web/js/api.js +25 -0
- package/runtime/web/js/chat-apps-dialog.js +194 -0
- package/runtime/web/{app.js → js/chat.js} +112 -193
- package/runtime/web/js/config.js +16 -0
- package/runtime/web/js/main.js +56 -0
- package/runtime/web/js/settings.js +205 -0
- package/runtime/web/styles.css +311 -10
- package/runtime/server/chat-proxy.js +0 -229
- package/runtime/server/index.js +0 -63
- package/runtime/server/routes.js +0 -104
|
@@ -1,69 +1,47 @@
|
|
|
1
|
-
|
|
2
|
-
let chatHistory = [];
|
|
1
|
+
import { state } from "./config.js";
|
|
3
2
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
setupEventListeners();
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
async function loadConfig() {
|
|
11
|
-
try {
|
|
12
|
-
const res = await fetch(API_BASE + "/api/config");
|
|
13
|
-
const config = await res.json();
|
|
14
|
-
|
|
15
|
-
document.getElementById("pack-name").textContent = config.name;
|
|
16
|
-
document.getElementById("pack-desc").textContent = config.description;
|
|
17
|
-
document.title = config.name;
|
|
18
|
-
|
|
19
|
-
// Skills
|
|
20
|
-
const skillsList = document.getElementById("skills-list");
|
|
21
|
-
skillsList.innerHTML = config.skills
|
|
22
|
-
.map(
|
|
23
|
-
(s) =>
|
|
24
|
-
`<li><div class="skill-name">${s.name}</div><div class="skill-desc">${s.description}</div></li>`,
|
|
25
|
-
)
|
|
26
|
-
.join("");
|
|
27
|
-
|
|
28
|
-
// Pre-fill when there is exactly one prompt
|
|
29
|
-
if (config.prompts && config.prompts.length === 1) {
|
|
30
|
-
const input = document.getElementById("user-input");
|
|
31
|
-
input.value = config.prompts[0];
|
|
32
|
-
input.style.height = "auto";
|
|
33
|
-
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
34
|
-
}
|
|
3
|
+
export const chatHistory = [];
|
|
4
|
+
let ws = null;
|
|
5
|
+
let currentAssistantMsg = null;
|
|
35
6
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
keyStatus.textContent = "API key configured";
|
|
40
|
-
keyStatus.className = "status-text success";
|
|
41
|
-
}
|
|
7
|
+
export function initChat() {
|
|
8
|
+
// Send button
|
|
9
|
+
document.getElementById("send-btn").addEventListener("click", sendMessage);
|
|
42
10
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
11
|
+
// Send on Enter
|
|
12
|
+
document.getElementById("user-input").addEventListener("keydown", (e) => {
|
|
13
|
+
if (e.key === "Enter" && !e.shiftKey) {
|
|
14
|
+
e.preventDefault();
|
|
15
|
+
sendMessage();
|
|
46
16
|
}
|
|
17
|
+
});
|
|
47
18
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
else input.placeholder = "sk-...";
|
|
54
|
-
};
|
|
19
|
+
// Auto-resize the input box
|
|
20
|
+
document.getElementById("user-input").addEventListener("input", (e) => {
|
|
21
|
+
e.target.style.height = "auto";
|
|
22
|
+
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
23
|
+
});
|
|
55
24
|
|
|
56
|
-
|
|
57
|
-
|
|
25
|
+
// Prompt click (Welcome message prompts)
|
|
26
|
+
const welcomeContent = document.getElementById("welcome-content");
|
|
27
|
+
if (welcomeContent) {
|
|
28
|
+
welcomeContent.addEventListener("click", (e) => {
|
|
29
|
+
const item = e.target.closest(".prompt-card");
|
|
30
|
+
if (!item) return;
|
|
31
|
+
const index = parseInt(item.dataset.index);
|
|
58
32
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
33
|
+
if (state.config && state.config.prompts[index]) {
|
|
34
|
+
const input = document.getElementById("user-input");
|
|
35
|
+
input.value = state.config.prompts[index];
|
|
36
|
+
input.focus();
|
|
37
|
+
input.style.height = "auto";
|
|
38
|
+
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
39
|
+
}
|
|
40
|
+
});
|
|
63
41
|
}
|
|
64
42
|
}
|
|
65
43
|
|
|
66
|
-
function showWelcome(config) {
|
|
44
|
+
export function showWelcome(config) {
|
|
67
45
|
const welcomeContent = document.getElementById("welcome-content");
|
|
68
46
|
|
|
69
47
|
let promptsHtml = "";
|
|
@@ -94,94 +72,69 @@ function showWelcome(config) {
|
|
|
94
72
|
}
|
|
95
73
|
}
|
|
96
74
|
|
|
97
|
-
function
|
|
98
|
-
|
|
99
|
-
|
|
75
|
+
export async function sendMessage() {
|
|
76
|
+
const input = document.getElementById("user-input");
|
|
77
|
+
const text = input.value.trim();
|
|
78
|
+
if (!text) return;
|
|
100
79
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
}
|
|
107
|
-
});
|
|
80
|
+
const chatArea = document.getElementById("chat-area");
|
|
81
|
+
if (chatArea.classList.contains("mode-welcome")) {
|
|
82
|
+
chatArea.classList.remove("mode-welcome");
|
|
83
|
+
chatArea.classList.add("mode-chat");
|
|
84
|
+
}
|
|
108
85
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
e.target.style.height = "auto";
|
|
112
|
-
e.target.style.height = Math.min(e.target.scrollHeight, 120) + "px";
|
|
113
|
-
});
|
|
86
|
+
input.value = "";
|
|
87
|
+
input.style.height = "auto";
|
|
114
88
|
|
|
115
|
-
|
|
116
|
-
|
|
89
|
+
appendMessage("user", text);
|
|
90
|
+
chatHistory.push({ role: "user", content: text });
|
|
117
91
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
if (welcomeContent) {
|
|
121
|
-
welcomeContent.addEventListener("click", (e) => {
|
|
122
|
-
const item = e.target.closest(".prompt-card");
|
|
123
|
-
if (!item) return;
|
|
124
|
-
const index = parseInt(item.dataset.index);
|
|
92
|
+
const sendBtn = document.getElementById("send-btn");
|
|
93
|
+
sendBtn.disabled = true;
|
|
125
94
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
input.style.height = "auto";
|
|
135
|
-
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
136
|
-
}
|
|
137
|
-
});
|
|
138
|
-
});
|
|
95
|
+
currentAssistantMsg = appendMessage("assistant", "");
|
|
96
|
+
showLoadingIndicator();
|
|
97
|
+
|
|
98
|
+
try {
|
|
99
|
+
const socket = await getOrCreateWs();
|
|
100
|
+
socket.send(JSON.stringify({ text }));
|
|
101
|
+
} catch (err) {
|
|
102
|
+
handleError(err.message);
|
|
139
103
|
}
|
|
140
104
|
}
|
|
141
105
|
|
|
142
|
-
async function
|
|
143
|
-
const
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
const provider = providerSelect ? providerSelect.value : "openai";
|
|
148
|
-
|
|
149
|
-
if (!key) {
|
|
150
|
-
status.textContent = "Enter an API key";
|
|
151
|
-
status.className = "status-text error";
|
|
152
|
-
return;
|
|
106
|
+
export async function sendBotCommand(cmdText) {
|
|
107
|
+
const chatArea = document.getElementById("chat-area");
|
|
108
|
+
if (chatArea.classList.contains("mode-welcome")) {
|
|
109
|
+
chatArea.classList.remove("mode-welcome");
|
|
110
|
+
chatArea.classList.add("mode-chat");
|
|
153
111
|
}
|
|
154
112
|
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
method: "POST",
|
|
158
|
-
headers: { "Content-Type": "application/json" },
|
|
159
|
-
body: JSON.stringify({ key, provider }),
|
|
160
|
-
});
|
|
113
|
+
appendMessage("user", cmdText);
|
|
114
|
+
chatHistory.push({ role: "user", content: cmdText });
|
|
161
115
|
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
116
|
+
const sendBtn = document.getElementById("send-btn");
|
|
117
|
+
sendBtn.disabled = true;
|
|
118
|
+
|
|
119
|
+
currentAssistantMsg = appendMessage("assistant", "");
|
|
120
|
+
showLoadingIndicator();
|
|
121
|
+
|
|
122
|
+
try {
|
|
123
|
+
const socket = await getOrCreateWs();
|
|
124
|
+
socket.send(JSON.stringify({ text: cmdText }));
|
|
170
125
|
} catch (err) {
|
|
171
|
-
|
|
172
|
-
status.className = "status-text error";
|
|
126
|
+
handleError(err.message);
|
|
173
127
|
}
|
|
174
128
|
}
|
|
175
129
|
|
|
176
|
-
|
|
177
|
-
let currentAssistantMsg = null;
|
|
130
|
+
// ========== Internal Rendering & WS logic ==========
|
|
178
131
|
|
|
179
132
|
function renderMarkdown(mdText, { renderEmbeddedMarkdown = true } = {}) {
|
|
180
|
-
if (typeof marked === "undefined") {
|
|
133
|
+
if (typeof window.marked === "undefined") {
|
|
181
134
|
return escapeHtml(mdText);
|
|
182
135
|
}
|
|
183
136
|
|
|
184
|
-
const html = ensureLinksOpenInNewTab(marked.parse(mdText));
|
|
137
|
+
const html = ensureLinksOpenInNewTab(window.marked.parse(mdText));
|
|
185
138
|
if (!renderEmbeddedMarkdown) {
|
|
186
139
|
return html;
|
|
187
140
|
}
|
|
@@ -208,11 +161,9 @@ function renderEmbeddedMarkdownBlocks(html) {
|
|
|
208
161
|
const codeBlocks = template.content.querySelectorAll("pre > code");
|
|
209
162
|
codeBlocks.forEach((codeEl) => {
|
|
210
163
|
const languageClass = Array.from(codeEl.classList).find((className) =>
|
|
211
|
-
className.startsWith("language-")
|
|
164
|
+
className.startsWith("language-")
|
|
212
165
|
);
|
|
213
|
-
const language = languageClass
|
|
214
|
-
? languageClass.slice("language-".length)
|
|
215
|
-
: "";
|
|
166
|
+
const language = languageClass ? languageClass.slice("language-".length) : "";
|
|
216
167
|
|
|
217
168
|
if (!/^(markdown|md)$/i.test(language)) {
|
|
218
169
|
return;
|
|
@@ -240,11 +191,9 @@ async function getOrCreateWs() {
|
|
|
240
191
|
|
|
241
192
|
return new Promise((resolve, reject) => {
|
|
242
193
|
const protocol = window.location.protocol === "https:" ? "wss:" : "ws:";
|
|
243
|
-
const
|
|
244
|
-
const provider = providerSelect ? providerSelect.value : "openai";
|
|
194
|
+
const provider = state.config && state.config.provider ? state.config.provider : "openai";
|
|
245
195
|
|
|
246
|
-
|
|
247
|
-
const wsUrl = `${protocol}//${window.location.host}${API_BASE}/api/chat?provider=${provider}`;
|
|
196
|
+
const wsUrl = `${protocol}//${window.location.host}${state.API_BASE}/api/chat?provider=${provider}`;
|
|
248
197
|
|
|
249
198
|
ws = new WebSocket(wsUrl);
|
|
250
199
|
|
|
@@ -327,12 +276,27 @@ function handleAgentEvent(event) {
|
|
|
327
276
|
|
|
328
277
|
if (
|
|
329
278
|
["text_delta", "thinking_delta", "tool_start", "tool_end"].includes(
|
|
330
|
-
event.type
|
|
279
|
+
event.type
|
|
331
280
|
)
|
|
332
281
|
) {
|
|
333
282
|
hideLoadingIndicator();
|
|
334
283
|
}
|
|
335
284
|
|
|
285
|
+
// Handle bot command results injected by the backend WebSocket response
|
|
286
|
+
if (event.type === "command_result") {
|
|
287
|
+
const textBlock = getOrCreateTextBlock();
|
|
288
|
+
let resText = `Command \`${event.command}\` succeeded.`;
|
|
289
|
+
if (event.errorMessage) {
|
|
290
|
+
resText = `Command \`${event.command}\` failed: ${event.errorMessage}`;
|
|
291
|
+
} else if (event.result) {
|
|
292
|
+
resText = `Command \`${event.command}\` result:\n\n${event.result}`;
|
|
293
|
+
}
|
|
294
|
+
textBlock.dataset.mdContent += resText;
|
|
295
|
+
textBlock.innerHTML = renderMarkdown(textBlock.dataset.mdContent);
|
|
296
|
+
scrollToBottom();
|
|
297
|
+
return;
|
|
298
|
+
}
|
|
299
|
+
|
|
336
300
|
switch (event.type) {
|
|
337
301
|
case "agent_start":
|
|
338
302
|
case "message_start":
|
|
@@ -348,7 +312,7 @@ function handleAgentEvent(event) {
|
|
|
348
312
|
const thinkingBlock = getOrCreateThinkingBlock();
|
|
349
313
|
thinkingBlock.dataset.mdContent += event.delta;
|
|
350
314
|
const contentEl = thinkingBlock.querySelector(".thinking-content");
|
|
351
|
-
if (typeof marked !== "undefined") {
|
|
315
|
+
if (typeof window.marked !== "undefined") {
|
|
352
316
|
contentEl.innerHTML = renderMarkdown(thinkingBlock.dataset.mdContent);
|
|
353
317
|
} else {
|
|
354
318
|
contentEl.textContent = thinkingBlock.dataset.mdContent;
|
|
@@ -359,7 +323,7 @@ function handleAgentEvent(event) {
|
|
|
359
323
|
case "text_delta":
|
|
360
324
|
const textBlock = getOrCreateTextBlock();
|
|
361
325
|
textBlock.dataset.mdContent += event.delta;
|
|
362
|
-
if (typeof marked !== "undefined") {
|
|
326
|
+
if (typeof window.marked !== "undefined") {
|
|
363
327
|
textBlock.innerHTML = renderMarkdown(textBlock.dataset.mdContent);
|
|
364
328
|
} else {
|
|
365
329
|
textBlock.textContent = textBlock.dataset.mdContent;
|
|
@@ -376,9 +340,9 @@ function handleAgentEvent(event) {
|
|
|
376
340
|
: JSON.stringify(event.toolInput, null, 2);
|
|
377
341
|
|
|
378
342
|
let inputHtml = "";
|
|
379
|
-
if (typeof marked !== "undefined") {
|
|
343
|
+
if (typeof window.marked !== "undefined") {
|
|
380
344
|
inputHtml = ensureLinksOpenInNewTab(
|
|
381
|
-
marked.parse("
|
|
345
|
+
window.marked.parse("\`\`\`json\n" + safeInput + "\n\`\`\`")
|
|
382
346
|
);
|
|
383
347
|
} else {
|
|
384
348
|
inputHtml = escapeHtml(safeInput);
|
|
@@ -387,7 +351,7 @@ function handleAgentEvent(event) {
|
|
|
387
351
|
toolCard.innerHTML = `
|
|
388
352
|
<div class="tool-header">
|
|
389
353
|
<span class="tool-chevron">
|
|
390
|
-
|
|
354
|
+
<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
|
391
355
|
</span>
|
|
392
356
|
<span class="tool-icon">🛠️</span>
|
|
393
357
|
<span class="tool-name">${escapeHtml(event.toolName)}</span>
|
|
@@ -403,9 +367,7 @@ function handleAgentEvent(event) {
|
|
|
403
367
|
toolCard.classList.toggle("collapsed");
|
|
404
368
|
});
|
|
405
369
|
|
|
406
|
-
|
|
407
|
-
const toolIndicator =
|
|
408
|
-
currentAssistantMsg.querySelector(".loading-indicator");
|
|
370
|
+
const toolIndicator = currentAssistantMsg.querySelector(".loading-indicator");
|
|
409
371
|
if (toolIndicator) {
|
|
410
372
|
currentAssistantMsg.insertBefore(toolCard, toolIndicator);
|
|
411
373
|
} else {
|
|
@@ -414,17 +376,12 @@ function handleAgentEvent(event) {
|
|
|
414
376
|
|
|
415
377
|
toolCard.dataset.toolName = event.toolName;
|
|
416
378
|
scrollToBottom();
|
|
417
|
-
|
|
418
379
|
showLoadingIndicator();
|
|
419
380
|
break;
|
|
420
381
|
|
|
421
382
|
case "tool_end":
|
|
422
|
-
const cards = Array.from(
|
|
423
|
-
|
|
424
|
-
);
|
|
425
|
-
const card = cards
|
|
426
|
-
.reverse()
|
|
427
|
-
.find((c) => c.dataset.toolName === event.toolName);
|
|
383
|
+
const cards = Array.from(currentAssistantMsg.querySelectorAll(".tool-card.running"));
|
|
384
|
+
const card = cards.reverse().find((c) => c.dataset.toolName === event.toolName);
|
|
428
385
|
if (card) {
|
|
429
386
|
card.classList.remove("running");
|
|
430
387
|
card.classList.add(event.isError ? "error" : "success");
|
|
@@ -448,17 +405,16 @@ function handleAgentEvent(event) {
|
|
|
448
405
|
event.result &&
|
|
449
406
|
typeof event.result === "string" &&
|
|
450
407
|
(event.result.includes("\n") || event.result.length > 50)
|
|
451
|
-
? "
|
|
452
|
-
: "
|
|
408
|
+
? "\`\`\`bash\n" + safeResult + "\n\`\`\`"
|
|
409
|
+
: "\`\`\`json\n" + safeResult + "\n\`\`\`";
|
|
453
410
|
|
|
454
|
-
if (typeof marked !== "undefined") {
|
|
455
|
-
resultEl.innerHTML = ensureLinksOpenInNewTab(marked.parse(mdText));
|
|
411
|
+
if (typeof window.marked !== "undefined") {
|
|
412
|
+
resultEl.innerHTML = ensureLinksOpenInNewTab(window.marked.parse(mdText));
|
|
456
413
|
} else {
|
|
457
414
|
resultEl.textContent = safeResult;
|
|
458
415
|
}
|
|
459
416
|
}
|
|
460
417
|
scrollToBottom();
|
|
461
|
-
|
|
462
418
|
showLoadingIndicator();
|
|
463
419
|
break;
|
|
464
420
|
}
|
|
@@ -466,7 +422,7 @@ function handleAgentEvent(event) {
|
|
|
466
422
|
|
|
467
423
|
function getOrCreateThinkingBlock() {
|
|
468
424
|
const children = Array.from(currentAssistantMsg.children).filter(
|
|
469
|
-
(c) => !c.classList.contains("loading-indicator")
|
|
425
|
+
(c) => !c.classList.contains("loading-indicator")
|
|
470
426
|
);
|
|
471
427
|
let lastChild = children[children.length - 1];
|
|
472
428
|
|
|
@@ -478,7 +434,7 @@ function getOrCreateThinkingBlock() {
|
|
|
478
434
|
lastChild.innerHTML = `
|
|
479
435
|
<div class="tool-header thinking-header">
|
|
480
436
|
<span class="tool-chevron">
|
|
481
|
-
|
|
437
|
+
<svg viewBox="0 0 24 24" width="16" height="16" stroke="currentColor" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"><polyline points="9 18 15 12 9 6"></polyline></svg>
|
|
482
438
|
</span>
|
|
483
439
|
<span class="tool-icon">🧠</span>
|
|
484
440
|
<span class="tool-name" style="color: var(--text-secondary);">Thinking Process</span>
|
|
@@ -502,7 +458,7 @@ function getOrCreateThinkingBlock() {
|
|
|
502
458
|
|
|
503
459
|
function getOrCreateTextBlock() {
|
|
504
460
|
const children = Array.from(currentAssistantMsg.children).filter(
|
|
505
|
-
(c) => !c.classList.contains("loading-indicator")
|
|
461
|
+
(c) => !c.classList.contains("loading-indicator")
|
|
506
462
|
);
|
|
507
463
|
let lastChild = children[children.length - 1];
|
|
508
464
|
|
|
@@ -527,40 +483,6 @@ function enableInput() {
|
|
|
527
483
|
currentAssistantMsg = null;
|
|
528
484
|
}
|
|
529
485
|
|
|
530
|
-
async function sendMessage() {
|
|
531
|
-
const input = document.getElementById("user-input");
|
|
532
|
-
const text = input.value.trim();
|
|
533
|
-
if (!text) return;
|
|
534
|
-
|
|
535
|
-
const chatArea = document.getElementById("chat-area");
|
|
536
|
-
if (chatArea.classList.contains("mode-welcome")) {
|
|
537
|
-
chatArea.classList.remove("mode-welcome");
|
|
538
|
-
chatArea.classList.add("mode-chat");
|
|
539
|
-
}
|
|
540
|
-
|
|
541
|
-
input.value = "";
|
|
542
|
-
input.style.height = "auto";
|
|
543
|
-
|
|
544
|
-
// Add the user message
|
|
545
|
-
appendMessage("user", text);
|
|
546
|
-
chatHistory.push({ role: "user", content: text });
|
|
547
|
-
|
|
548
|
-
// Disable input while the agent is responding
|
|
549
|
-
const sendBtn = document.getElementById("send-btn");
|
|
550
|
-
sendBtn.disabled = true;
|
|
551
|
-
|
|
552
|
-
// Create an assistant message placeholder
|
|
553
|
-
currentAssistantMsg = appendMessage("assistant", "");
|
|
554
|
-
showLoadingIndicator();
|
|
555
|
-
|
|
556
|
-
try {
|
|
557
|
-
const socket = await getOrCreateWs();
|
|
558
|
-
socket.send(JSON.stringify({ text }));
|
|
559
|
-
} catch (err) {
|
|
560
|
-
handleError(err.message);
|
|
561
|
-
}
|
|
562
|
-
}
|
|
563
|
-
|
|
564
486
|
function appendMessage(role, text) {
|
|
565
487
|
const messages = document.getElementById("messages");
|
|
566
488
|
const div = document.createElement("div");
|
|
@@ -591,6 +513,3 @@ function scrollToBottom() {
|
|
|
591
513
|
const messages = document.getElementById("messages");
|
|
592
514
|
messages.scrollTop = messages.scrollHeight;
|
|
593
515
|
}
|
|
594
|
-
|
|
595
|
-
// Start the app
|
|
596
|
-
init();
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export const state = {
|
|
2
|
+
config: null,
|
|
3
|
+
API_BASE: "",
|
|
4
|
+
restartRequired: false,
|
|
5
|
+
};
|
|
6
|
+
|
|
7
|
+
export async function loadConfig() {
|
|
8
|
+
try {
|
|
9
|
+
const res = await fetch(state.API_BASE + "/api/config");
|
|
10
|
+
state.config = await res.json();
|
|
11
|
+
return state.config;
|
|
12
|
+
} catch (err) {
|
|
13
|
+
console.error("Failed to load config:", err);
|
|
14
|
+
throw err;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { state, loadConfig } from "./config.js";
|
|
2
|
+
import { initSettings } from "./settings.js";
|
|
3
|
+
import { initApiKeyDialog, updateApiKeyButton } from "./api-key-dialog.js";
|
|
4
|
+
import { initChatAppsDialog, updateChatAppsButton } from "./chat-apps-dialog.js";
|
|
5
|
+
import { initChat, showWelcome } from "./chat.js";
|
|
6
|
+
|
|
7
|
+
async function init() {
|
|
8
|
+
try {
|
|
9
|
+
const config = await loadConfig();
|
|
10
|
+
|
|
11
|
+
// Set Pack Name & Description
|
|
12
|
+
const elName = document.getElementById("pack-name");
|
|
13
|
+
const elDesc = document.getElementById("pack-desc");
|
|
14
|
+
if (elName) elName.textContent = config.name || "Skills Pack";
|
|
15
|
+
if (elDesc) elDesc.textContent = config.description || "";
|
|
16
|
+
document.title = config.name || "Skills Pack";
|
|
17
|
+
|
|
18
|
+
// Set Sidebar Skills list
|
|
19
|
+
const skillsList = document.getElementById("skills-list");
|
|
20
|
+
if (skillsList && config.skills) {
|
|
21
|
+
skillsList.innerHTML = config.skills
|
|
22
|
+
.map(
|
|
23
|
+
(s) =>
|
|
24
|
+
`<li><div class="skill-name">${s.name}</div><div class="skill-desc">${s.description}</div></li>`,
|
|
25
|
+
)
|
|
26
|
+
.join("");
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// Pre-fill prompt if exactly one
|
|
30
|
+
if (config.prompts && config.prompts.length === 1) {
|
|
31
|
+
const input = document.getElementById("user-input");
|
|
32
|
+
if (input) {
|
|
33
|
+
input.value = config.prompts[0];
|
|
34
|
+
input.style.height = "auto";
|
|
35
|
+
input.style.height = Math.min(input.scrollHeight, 120) + "px";
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
showWelcome(config);
|
|
40
|
+
} catch (err) {
|
|
41
|
+
console.error("Initialization Failed:", err);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
// Initialize all dialog modules
|
|
45
|
+
initSettings();
|
|
46
|
+
initApiKeyDialog();
|
|
47
|
+
initChatAppsDialog();
|
|
48
|
+
initChat();
|
|
49
|
+
|
|
50
|
+
// Update action button states based on config
|
|
51
|
+
updateApiKeyButton();
|
|
52
|
+
updateChatAppsButton();
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
// Start application
|
|
56
|
+
init();
|