kingkont 0.10.5 → 0.10.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/lib/providers.js +7 -1
- package/package.json +1 -1
- package/renderer/chat.js +29 -11
- package/renderer/cloudProjects.js +25 -0
- package/server.js +5 -1
package/lib/providers.js
CHANGED
|
@@ -170,7 +170,13 @@ async function chatiumWait(s, taskId, opts = {}) {
|
|
|
170
170
|
}
|
|
171
171
|
return d;
|
|
172
172
|
}
|
|
173
|
-
if (d.status === 'failed')
|
|
173
|
+
if (d.status === 'failed') {
|
|
174
|
+
// Префиксуем чтобы было понятно что упало именно на стороне Chatium
|
|
175
|
+
// (а не локально). Без префикса юзер видит только cryptic JS-error
|
|
176
|
+
// от @start/sdk и думает что дело в renderer'е.
|
|
177
|
+
const msg = d.error || d.failedReason || 'failed';
|
|
178
|
+
throw new Error(`Chatium task failed: ${String(msg).slice(0, 400)}`);
|
|
179
|
+
}
|
|
174
180
|
await new Promise(r => setTimeout(r, 1500));
|
|
175
181
|
}
|
|
176
182
|
throw new Error(`chatium poll timeout after ${timeoutMs / 1000}s`);
|
package/package.json
CHANGED
package/renderer/chat.js
CHANGED
|
@@ -294,12 +294,32 @@
|
|
|
294
294
|
}
|
|
295
295
|
|
|
296
296
|
// ============== LLM call + tool-loop ==============
|
|
297
|
+
// Превращаем messages в transcript-style prompt — работает независимо
|
|
298
|
+
// от того поддерживает ли backend multi-turn messages-формат. Если
|
|
299
|
+
// multi-turn вызывает 502 на Chatium (как было), transcript всё равно
|
|
300
|
+
// работает через стандартный prompt+system путь.
|
|
301
|
+
function messagesToPrompt(messages) {
|
|
302
|
+
const lines = [];
|
|
303
|
+
for (const m of messages) {
|
|
304
|
+
const role = m.role === 'assistant' ? 'ASSISTANT' : m.role === 'user' ? 'USER' : m.role.toUpperCase();
|
|
305
|
+
const content = typeof m.content === 'string'
|
|
306
|
+
? m.content
|
|
307
|
+
: Array.isArray(m.content)
|
|
308
|
+
? m.content.map(b => typeof b?.text === 'string' ? b.text : '').join('\n')
|
|
309
|
+
: '';
|
|
310
|
+
lines.push(`${role}: ${content}`);
|
|
311
|
+
}
|
|
312
|
+
lines.push('ASSISTANT:'); // подсказываем модели что её очередь
|
|
313
|
+
return lines.join('\n\n');
|
|
314
|
+
}
|
|
315
|
+
|
|
297
316
|
async function callLLM(messages, system) {
|
|
317
|
+
const prompt = messagesToPrompt(messages);
|
|
298
318
|
const body = {
|
|
299
|
-
|
|
319
|
+
prompt, system,
|
|
300
320
|
model: 'anthropic/claude-sonnet-4.6',
|
|
301
321
|
};
|
|
302
|
-
console.log('[chat] → POST /api/text', {
|
|
322
|
+
console.log('[chat] → POST /api/text', { promptLen: prompt.length, hasSystem: !!system });
|
|
303
323
|
const r = await fetch('/api/text', {
|
|
304
324
|
method: 'POST',
|
|
305
325
|
headers: { 'Content-Type': 'application/json' },
|
|
@@ -316,20 +336,18 @@
|
|
|
316
336
|
}
|
|
317
337
|
|
|
318
338
|
// Превращает internal history → массив для /api/text. Используем
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
//
|
|
339
|
+
// string-content (OpenAI-style) — это формат который понимают обе
|
|
340
|
+
// backend-имплементации (Chatium @start/sdk и OpenRouter напрямую).
|
|
341
|
+
// Раньше пробовали Anthropic content-blocks `[{type:'text', text}]` —
|
|
342
|
+
// но это вызывало «Cannot read properties of undefined (reading 'length')»
|
|
343
|
+
// в @start/sdk. String-content универсальнее.
|
|
323
344
|
function historyToMessages() {
|
|
324
345
|
const out = [];
|
|
325
346
|
for (const m of history) {
|
|
326
347
|
if (m.role === 'system') continue;
|
|
327
348
|
const content = String(m.content || '');
|
|
328
|
-
if (!content) continue; //
|
|
329
|
-
out.push({
|
|
330
|
-
role: m.role,
|
|
331
|
-
content: [{ type: 'text', text: content }],
|
|
332
|
-
});
|
|
349
|
+
if (!content) continue; // пустые messages не отправляем
|
|
350
|
+
out.push({ role: m.role, content });
|
|
333
351
|
}
|
|
334
352
|
return out;
|
|
335
353
|
}
|
|
@@ -644,6 +644,31 @@
|
|
|
644
644
|
$('newCloudProject')?.addEventListener('click', createNewCloudProject);
|
|
645
645
|
$('openCloudProjects')?.addEventListener('click', openCloudProjectsModal);
|
|
646
646
|
$('saveProjectCloud')?.addEventListener('click', saveCloudProject);
|
|
647
|
+
// ПКМ на «☁ Сохранить на сервер» — расширенное меню: «Сохранить как
|
|
648
|
+
// шаблон» (доступно ВСЕМ типам проектов, включая cloud — реализация
|
|
649
|
+
// в templates.js работает через filmHandle, cloudFs-shim тоже подходит).
|
|
650
|
+
$('saveProjectCloud')?.addEventListener('contextmenu', e => {
|
|
651
|
+
e.preventDefault();
|
|
652
|
+
e.stopPropagation();
|
|
653
|
+
const menu = document.getElementById('nodeMenu');
|
|
654
|
+
if (!menu) return;
|
|
655
|
+
menu.innerHTML = '';
|
|
656
|
+
const add = (label, fn) => {
|
|
657
|
+
const b = document.createElement('button');
|
|
658
|
+
b.textContent = label;
|
|
659
|
+
b.addEventListener('click', () => { menu.classList.add('hidden'); fn(); });
|
|
660
|
+
menu.appendChild(b);
|
|
661
|
+
};
|
|
662
|
+
add('☁ Сохранить на сервер', saveCloudProject);
|
|
663
|
+
add('💾 Сохранить как шаблон…', () => {
|
|
664
|
+
if (typeof saveCurrentProjectAsTemplate === 'function') saveCurrentProjectAsTemplate();
|
|
665
|
+
else alert('saveCurrentProjectAsTemplate недоступен');
|
|
666
|
+
});
|
|
667
|
+
if (typeof positionFloatingMenu === 'function') {
|
|
668
|
+
positionFloatingMenu(menu, e.clientX, e.clientY);
|
|
669
|
+
}
|
|
670
|
+
setTimeout(() => document.addEventListener('mousedown', () => menu.classList.add('hidden'), { once: true }), 0);
|
|
671
|
+
});
|
|
647
672
|
setCloudButtonsVisibility();
|
|
648
673
|
// Переинициализируем видимость кнопок раз в 5 сек — для случая когда юзер
|
|
649
674
|
// login/logout в Chatium через настройки (нет других сигналов).
|
package/server.js
CHANGED
|
@@ -166,7 +166,11 @@ async function handleText(req, res) {
|
|
|
166
166
|
const body = await readJson(req);
|
|
167
167
|
const r = await providers.generateText({ ...body, settings: getSettings() });
|
|
168
168
|
send(res, 200, { text: r.text, model: r.model, cost: r.cost }, { 'X-Provider': r.provider });
|
|
169
|
-
} catch (e) {
|
|
169
|
+
} catch (e) {
|
|
170
|
+
// Печатаем stack — иначе на клиенте не понятно где упало.
|
|
171
|
+
console.error('[/api/text] error:', e.stack || e.message || e);
|
|
172
|
+
sendError(res, e, 502);
|
|
173
|
+
}
|
|
170
174
|
}
|
|
171
175
|
|
|
172
176
|
async function handleTts(req, res) {
|