beast-agent 2.8.0 → 2.8.2
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/package.json +1 -1
- package/src/agent/llm.js +20 -0
- package/src/main.js +20 -5
- package/src/renderer/renderer.js +42 -1
package/package.json
CHANGED
package/src/agent/llm.js
CHANGED
|
@@ -10,6 +10,7 @@
|
|
|
10
10
|
prompt_cache_key) 400'den otomatik öğrenir → model-caps.json'a kalıcı. */
|
|
11
11
|
|
|
12
12
|
const fs = require('fs');
|
|
13
|
+
const crypto = require('crypto');
|
|
13
14
|
|
|
14
15
|
const RETRYABLE_STATUS = new Set([408, 409, 425, 429, 500, 502, 503, 504]);
|
|
15
16
|
const MAX_RETRIES = 3; /* sağlayıcı geçici HTTP hataları */
|
|
@@ -328,6 +329,24 @@ async function withRetries(fn, { signal, onRetry } = {}) {
|
|
|
328
329
|
}
|
|
329
330
|
}
|
|
330
331
|
|
|
332
|
+
/* x-opencode-session: konuşma-başına sabit oturum kimliği — TÜM sağlayıcılara
|
|
333
|
+
standart gönderilir (opencode bununla isteği optimize eder; 09/06'dan
|
|
334
|
+
itibaren headersız istek hata dönebilir). Gerçek sohbetlerde cacheKey =
|
|
335
|
+
session.id; cacheKey'siz yardımcı isteklerde süreç-başına sabit yedek. */
|
|
336
|
+
let _sessionFallback = null;
|
|
337
|
+
function sessionHeaderId(body) {
|
|
338
|
+
const ck = String((body && body.cacheKey) || '').trim();
|
|
339
|
+
if (ck) return ck;
|
|
340
|
+
if (!_sessionFallback) {
|
|
341
|
+
try {
|
|
342
|
+
_sessionFallback = crypto.randomUUID();
|
|
343
|
+
} catch {
|
|
344
|
+
_sessionFallback = 'beast-' + Date.now().toString(36) + Math.random().toString(36).slice(2, 10);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
return _sessionFallback;
|
|
348
|
+
}
|
|
349
|
+
|
|
331
350
|
async function openChat(sel, body, { stream, signal, drops } = {}) {
|
|
332
351
|
const d = drops || {};
|
|
333
352
|
const payload = {
|
|
@@ -357,6 +376,7 @@ async function openChat(sel, body, { stream, signal, drops } = {}) {
|
|
|
357
376
|
Authorization: `Bearer ${sel.key}`,
|
|
358
377
|
'HTTP-Referer': 'https://localhost/beast',
|
|
359
378
|
'X-Title': 'Beast Agent',
|
|
379
|
+
'x-opencode-session': sessionHeaderId(body),
|
|
360
380
|
},
|
|
361
381
|
body: JSON.stringify(payload),
|
|
362
382
|
});
|
package/src/main.js
CHANGED
|
@@ -6,6 +6,10 @@ const fs = require('fs');
|
|
|
6
6
|
const http = require('http');
|
|
7
7
|
const dns = require('dns');
|
|
8
8
|
const crypto = require('crypto');
|
|
9
|
+
/* x-opencode-session: opencode (Zen/Go) isteklerinde beklenen oturum kimliği —
|
|
10
|
+
kurulum/probe/model-liste istekleri için süreç-başına sabit değer; sohbet
|
|
11
|
+
isteklerindeki konuşma-başına kimlik agent/llm.js'te üretilir */
|
|
12
|
+
const OPENCODE_SESSION = 'beast-' + crypto.randomUUID();
|
|
9
13
|
const { spawn } = require('child_process');
|
|
10
14
|
const { Engine, OBSERVE_MARK } = require('./agent/engine');
|
|
11
15
|
const { loadBeastConfig, parseEnvFile, beastDir } = require('./agent/config');
|
|
@@ -8387,7 +8391,7 @@ async function refreshModelsAll() {
|
|
|
8387
8391
|
try {
|
|
8388
8392
|
const b = String(p.baseUrl).trim().replace(/\/+$/, '');
|
|
8389
8393
|
const url = /\/v\d+$/.test(b) ? b + '/models' : b + '/v1/models';
|
|
8390
|
-
const h = { Authorization: 'Bearer ' + p.key };
|
|
8394
|
+
const h = { Authorization: 'Bearer ' + p.key, 'x-opencode-session': OPENCODE_SESSION };
|
|
8391
8395
|
try {
|
|
8392
8396
|
if (new URL(url).hostname === 'api.anthropic.com') {
|
|
8393
8397
|
h['x-api-key'] = p.key;
|
|
@@ -8484,7 +8488,10 @@ function findZenToken() {
|
|
|
8484
8488
|
|
|
8485
8489
|
async function fetchZenFreeModels() {
|
|
8486
8490
|
try {
|
|
8487
|
-
const res = await fetch(ZEN_BASE + '/models', {
|
|
8491
|
+
const res = await fetch(ZEN_BASE + '/models', {
|
|
8492
|
+
headers: { 'x-opencode-session': OPENCODE_SESSION },
|
|
8493
|
+
signal: AbortSignal.timeout(15000),
|
|
8494
|
+
});
|
|
8488
8495
|
if (res.ok) {
|
|
8489
8496
|
const j = await res.json();
|
|
8490
8497
|
const ids = (j.data || []).map((m) => (typeof m === 'string' ? m : m.id)).filter(Boolean);
|
|
@@ -8584,7 +8591,11 @@ async function testZenModel(key, model) {
|
|
|
8584
8591
|
try {
|
|
8585
8592
|
const res = await fetch(ZEN_BASE + '/chat/completions', {
|
|
8586
8593
|
method: 'POST',
|
|
8587
|
-
headers: {
|
|
8594
|
+
headers: {
|
|
8595
|
+
'Content-Type': 'application/json',
|
|
8596
|
+
Authorization: 'Bearer ' + key,
|
|
8597
|
+
'x-opencode-session': OPENCODE_SESSION,
|
|
8598
|
+
},
|
|
8588
8599
|
body: JSON.stringify({
|
|
8589
8600
|
model,
|
|
8590
8601
|
messages: [{ role: 'user', content: 'ping' }],
|
|
@@ -8623,7 +8634,11 @@ async function testZenReasoning(key, model) {
|
|
|
8623
8634
|
try {
|
|
8624
8635
|
const res = await fetch(ZEN_BASE + '/chat/completions', {
|
|
8625
8636
|
method: 'POST',
|
|
8626
|
-
headers: {
|
|
8637
|
+
headers: {
|
|
8638
|
+
'Content-Type': 'application/json',
|
|
8639
|
+
Authorization: 'Bearer ' + key,
|
|
8640
|
+
'x-opencode-session': OPENCODE_SESSION,
|
|
8641
|
+
},
|
|
8627
8642
|
body: JSON.stringify({
|
|
8628
8643
|
model,
|
|
8629
8644
|
messages: [{ role: 'user', content: 'ping' }],
|
|
@@ -8731,7 +8746,7 @@ ipcMain.handle('custom:fetchModels', async (_e, { baseUrl, key }) => {
|
|
|
8731
8746
|
let b = String(baseUrl || '').trim().replace(/\/+$/, '');
|
|
8732
8747
|
if (!/^https?:\/\//i.test(b)) return { ok: false, error: 'URL http(s) ile başlamalı' };
|
|
8733
8748
|
const url = /\/v\d+$/.test(b) ? b + '/models' : b + '/v1/models';
|
|
8734
|
-
const headers = key ? { Authorization: 'Bearer ' + key } : {};
|
|
8749
|
+
const headers = { 'x-opencode-session': OPENCODE_SESSION, ...(key ? { Authorization: 'Bearer ' + key } : {}) };
|
|
8735
8750
|
/* Anthropic: /v1/models yerel API — x-api-key + versiyon başlığı ister */
|
|
8736
8751
|
try {
|
|
8737
8752
|
if (new URL(url).hostname === 'api.anthropic.com') {
|
package/src/renderer/renderer.js
CHANGED
|
@@ -317,9 +317,13 @@ function onNetEvent(ev) {
|
|
|
317
317
|
}
|
|
318
318
|
|
|
319
319
|
const TODO_GLYPH = { done: '✓', active: '▸', pending: '○' };
|
|
320
|
+
const TODO_DONE_HIDE_MS = 2500; /* tüm görevler bitince liste bu kadar sonra otomatik kapanır */
|
|
321
|
+
let todoHideTimer = null;
|
|
320
322
|
|
|
321
323
|
function renderTodos(items) {
|
|
322
324
|
const list = Array.isArray(items) ? items : [];
|
|
325
|
+
clearTimeout(todoHideTimer);
|
|
326
|
+
todoHideTimer = null;
|
|
323
327
|
if (!list.length) { els.todoPanel.hidden = true; els.todoPanel.innerHTML = ''; return; }
|
|
324
328
|
const done = list.filter((t) => t.status === 'done').length;
|
|
325
329
|
const rows = list
|
|
@@ -333,10 +337,23 @@ function renderTodos(items) {
|
|
|
333
337
|
`<span class="td-right"><span class="td-count">${done}/${list.length}</span>` +
|
|
334
338
|
`<button class="td-x" title="${_t('td_hide')}">×</button></span></div>` + rows;
|
|
335
339
|
els.todoPanel.hidden = false;
|
|
340
|
+
/* tüm görevler bitti → kullanıcı tamamlanan listeyi görsün diye kısa beklet,
|
|
341
|
+
sonra panel otomatik kapanır; yeni görev gelirse zamanlayıcı iptal olur */
|
|
342
|
+
if (done === list.length) {
|
|
343
|
+
todoHideTimer = setTimeout(() => {
|
|
344
|
+
todoHideTimer = null;
|
|
345
|
+
els.todoPanel.hidden = true;
|
|
346
|
+
els.todoPanel.innerHTML = '';
|
|
347
|
+
}, TODO_DONE_HIDE_MS);
|
|
348
|
+
}
|
|
336
349
|
/* X yalnız BU listeyi gizler — kalıcı kapanma yok: bir sonraki görev
|
|
337
350
|
güncellemesi (yeni görev eklendi / görev yapıldı) paneli yeniden gösterir */
|
|
338
351
|
const x = els.todoPanel.querySelector('.td-x');
|
|
339
|
-
if (x) x.addEventListener('click', () => {
|
|
352
|
+
if (x) x.addEventListener('click', () => {
|
|
353
|
+
clearTimeout(todoHideTimer);
|
|
354
|
+
todoHideTimer = null;
|
|
355
|
+
els.todoPanel.hidden = true;
|
|
356
|
+
});
|
|
340
357
|
}
|
|
341
358
|
function setBusy(b) {
|
|
342
359
|
busy = b;
|
|
@@ -8504,9 +8521,12 @@ function bcToolBoxEnd(callId, ok, result, diff) {
|
|
|
8504
8521
|
/* ---------- Beast Code todo kartı ----------
|
|
8505
8522
|
Inputun (chat) hemen üstünde ortalı kompakt kutu; #bcTodoWrap içinde yaşar,
|
|
8506
8523
|
scroll'lu çıktı akışını kirletmez. */
|
|
8524
|
+
let bcTodoHideTimer = null;
|
|
8507
8525
|
function bcRenderTodos(todos) {
|
|
8508
8526
|
const list = Array.isArray(todos) ? todos : [];
|
|
8509
8527
|
if (!els.bcTodoWrap) return;
|
|
8528
|
+
clearTimeout(bcTodoHideTimer);
|
|
8529
|
+
bcTodoHideTimer = null;
|
|
8510
8530
|
bcFlushStream();
|
|
8511
8531
|
if (!list.length) {
|
|
8512
8532
|
bcHideTodos();
|
|
@@ -8531,9 +8551,18 @@ function bcRenderTodos(todos) {
|
|
|
8531
8551
|
row.querySelector('.bc-todotext').textContent = String(t.title || '');
|
|
8532
8552
|
wrap.appendChild(row);
|
|
8533
8553
|
}
|
|
8554
|
+
/* tüm görevler bitti → kısa görün, sonra kart otomatik kapanır */
|
|
8555
|
+
if (done === list.length) {
|
|
8556
|
+
bcTodoHideTimer = setTimeout(() => {
|
|
8557
|
+
bcTodoHideTimer = null;
|
|
8558
|
+
bcHideTodos();
|
|
8559
|
+
}, TODO_DONE_HIDE_MS);
|
|
8560
|
+
}
|
|
8534
8561
|
}
|
|
8535
8562
|
|
|
8536
8563
|
function bcHideTodos() {
|
|
8564
|
+
clearTimeout(bcTodoHideTimer);
|
|
8565
|
+
bcTodoHideTimer = null;
|
|
8537
8566
|
if (els.bcTodoWrap) {
|
|
8538
8567
|
els.bcTodoWrap.hidden = true;
|
|
8539
8568
|
els.bcTodoWrap.innerHTML = '';
|
|
@@ -8961,9 +8990,12 @@ function stNoteStream(delta) {
|
|
|
8961
8990
|
return true;
|
|
8962
8991
|
}
|
|
8963
8992
|
|
|
8993
|
+
let stTodoHideTimer = null;
|
|
8964
8994
|
function stRenderTodos(todos) {
|
|
8965
8995
|
const list = Array.isArray(todos) ? todos : [];
|
|
8966
8996
|
if (!els.stTodoWrap) return;
|
|
8997
|
+
clearTimeout(stTodoHideTimer);
|
|
8998
|
+
stTodoHideTimer = null;
|
|
8967
8999
|
stFlushStream();
|
|
8968
9000
|
if (!list.length) {
|
|
8969
9001
|
stHideTodos();
|
|
@@ -8988,9 +9020,18 @@ function stRenderTodos(todos) {
|
|
|
8988
9020
|
row.querySelector('.bc-todotext').textContent = String(t.title || '');
|
|
8989
9021
|
wrap.appendChild(row);
|
|
8990
9022
|
}
|
|
9023
|
+
/* tüm görevler bitti → kısa görün, sonra kart otomatik kapanır */
|
|
9024
|
+
if (done === list.length) {
|
|
9025
|
+
stTodoHideTimer = setTimeout(() => {
|
|
9026
|
+
stTodoHideTimer = null;
|
|
9027
|
+
stHideTodos();
|
|
9028
|
+
}, TODO_DONE_HIDE_MS);
|
|
9029
|
+
}
|
|
8991
9030
|
}
|
|
8992
9031
|
|
|
8993
9032
|
function stHideTodos() {
|
|
9033
|
+
clearTimeout(stTodoHideTimer);
|
|
9034
|
+
stTodoHideTimer = null;
|
|
8994
9035
|
if (els.stTodoWrap) {
|
|
8995
9036
|
els.stTodoWrap.hidden = true;
|
|
8996
9037
|
els.stTodoWrap.innerHTML = '';
|