beast-agent 2.63.4 → 2.63.6
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/engine.js +33 -16
- package/src/agent/financetools.js +44 -17
- package/src/agent/seeds/typesafe-ai/SKILL.md +60 -0
- package/src/agent/tools.js +5 -2
- package/src/agent/typesafe.js +278 -0
- package/src/main.js +766 -77
- package/src/preload.js +4 -0
- package/src/renderer/i18n.js +38 -0
- package/src/renderer/index.html +3 -1
- package/src/renderer/renderer.js +165 -23
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
/* ---------- TypeSafe / System One (Jev) adaptörü ----------
|
|
4
|
+
TypeSafe'in System One API'si (docs.typesafe.ai) — state + tipli sorular
|
|
5
|
+
gönderilir, metin ÜRETİLMEZ; noul/choice/score yanıtları olasılıklarıyla
|
|
6
|
+
döner. Beast ajanları typesafe_decision aracıyla bu kararları doğrudan
|
|
7
|
+
kod gibi tüketir (ör. "bu haber altını yukarı iter mi?" → 0.78).
|
|
8
|
+
|
|
9
|
+
Uç: POST https://api.typesafe.ai/v1/systemone
|
|
10
|
+
Auth: Authorization: Bearer <API_KEY>
|
|
11
|
+
Zero npm bağımlılık — Node 18+ global fetch (supermemory.js deseni).
|
|
12
|
+
|
|
13
|
+
Konfig main süreçten enjekte edilir: setConfig(fn) → { apiKey, model }. */
|
|
14
|
+
|
|
15
|
+
const BASE_URL = 'https://api.typesafe.ai';
|
|
16
|
+
const DEFAULT_MODEL = 'jev-latest';
|
|
17
|
+
const DEFAULT_TIMEOUT_MS = 20000;
|
|
18
|
+
const PROBE_TIMEOUT_MS = 25000;
|
|
19
|
+
|
|
20
|
+
let getCfg = () => ({ apiKey: '', model: DEFAULT_MODEL });
|
|
21
|
+
|
|
22
|
+
function setConfig(fn) {
|
|
23
|
+
if (typeof fn === 'function') getCfg = fn;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
function cfg() {
|
|
27
|
+
const c = getCfg() || {};
|
|
28
|
+
return {
|
|
29
|
+
apiKey: String(c.apiKey || '').trim(),
|
|
30
|
+
model: String(c.model || '').trim() || DEFAULT_MODEL,
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function errorForStatus(status, bodyText) {
|
|
35
|
+
const detail = String(bodyText || '').slice(0, 240);
|
|
36
|
+
if (status === 401 || status === 403) return 'TypeSafe API anahtarı geçersiz (Ayarlar → TypeSafe sekmesinden kontrol et)' + (detail ? ' — ' + detail : '');
|
|
37
|
+
if (status === 429) return 'TypeSafe hız limiti (429) — biraz bekleyip yeniden dene';
|
|
38
|
+
if (status === 529) return 'TypeSafe geçici olarak yoğun (529) — biraz bekleyip yeniden dene';
|
|
39
|
+
if (status === 422) return 'TypeSafe istek doğrulaması başarısız (422) — questions/state biçimini kontrol et' + (detail ? ' — ' + detail : '');
|
|
40
|
+
return 'TypeSafe HTTP ' + status + (detail ? ': ' + detail : '');
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/* Soru gövdelerini doğrula + normalleştir (id → {type, instructions, criteria}) */
|
|
44
|
+
function normalizeQuestions(questions) {
|
|
45
|
+
if (!questions || typeof questions !== 'object' || Array.isArray(questions)) {
|
|
46
|
+
throw new Error('questions bir nesne olmalı: { id: {type, instructions, criteria} }');
|
|
47
|
+
}
|
|
48
|
+
const out = {};
|
|
49
|
+
for (const [id, q] of Object.entries(questions)) {
|
|
50
|
+
const key = String(id || '').trim();
|
|
51
|
+
if (!key) continue;
|
|
52
|
+
const o = q && typeof q === 'object' ? q : {};
|
|
53
|
+
const type = String(o.type || '').toLowerCase();
|
|
54
|
+
if (!['noul', 'choice', 'score'].includes(type)) {
|
|
55
|
+
throw new Error(`soru "${key}": type noul|choice|score olmalı (gelen: ${o.type || 'boş'})`);
|
|
56
|
+
}
|
|
57
|
+
if (o.instructions == null || String(o.instructions).trim() === '') {
|
|
58
|
+
throw new Error(`soru "${key}": instructions zorunlu`);
|
|
59
|
+
}
|
|
60
|
+
const item = { type, instructions: o.instructions };
|
|
61
|
+
if (type === 'choice') {
|
|
62
|
+
if (!o.criteria || typeof o.criteria !== 'object' || Array.isArray(o.criteria) || !Object.keys(o.criteria).length) {
|
|
63
|
+
throw new Error(`soru "${key}": choice için criteria nesnesi zorunlu {seçenek: açıklama|null}`);
|
|
64
|
+
}
|
|
65
|
+
item.criteria = o.criteria;
|
|
66
|
+
} else if (type === 'score') {
|
|
67
|
+
if (!Array.isArray(o.criteria) || o.criteria.length < 2) {
|
|
68
|
+
throw new Error(`soru "${key}": score için en az 2 seviyeli criteria dizisi zorunlu`);
|
|
69
|
+
}
|
|
70
|
+
item.criteria = o.criteria;
|
|
71
|
+
} else if (o.criteria && typeof o.criteria === 'object') {
|
|
72
|
+
item.criteria = o.criteria;
|
|
73
|
+
}
|
|
74
|
+
out[key] = item;
|
|
75
|
+
}
|
|
76
|
+
if (!Object.keys(out).length) throw new Error('questions boş — en az 1 soru gerekli');
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/* systemOne çağrısı: state + questions → answers */
|
|
81
|
+
async function systemOne({ state, questions, model, timeoutMs, signal } = {}) {
|
|
82
|
+
const c = cfg();
|
|
83
|
+
if (!c.apiKey) throw new Error('TypeSafe API anahtarı yok — Ayarlar → TypeSafe sekmesinden gir');
|
|
84
|
+
if (state == null || (typeof state === 'string' && !state.trim())) {
|
|
85
|
+
throw new Error('state boş — değerlendirilecek içerik gerekli (metin ya da JSON nesne/dizi)');
|
|
86
|
+
}
|
|
87
|
+
const qs = normalizeQuestions(questions);
|
|
88
|
+
const body = { state, model: String(model || '').trim() || c.model, questions: qs };
|
|
89
|
+
const ctrl = new AbortController();
|
|
90
|
+
const timer = setTimeout(() => ctrl.abort(), Number(timeoutMs) > 0 ? Number(timeoutMs) : DEFAULT_TIMEOUT_MS);
|
|
91
|
+
const onAbort = () => ctrl.abort();
|
|
92
|
+
if (signal && typeof signal.addEventListener === 'function') signal.addEventListener('abort', onAbort, { once: true });
|
|
93
|
+
try {
|
|
94
|
+
const res = await fetch(BASE_URL + '/v1/systemone', {
|
|
95
|
+
method: 'POST',
|
|
96
|
+
headers: { 'content-type': 'application/json', authorization: 'Bearer ' + c.apiKey },
|
|
97
|
+
body: JSON.stringify(body),
|
|
98
|
+
signal: ctrl.signal,
|
|
99
|
+
});
|
|
100
|
+
if (!res.ok) {
|
|
101
|
+
const txt = await res.text().catch(() => '');
|
|
102
|
+
throw new Error(errorForStatus(res.status, txt));
|
|
103
|
+
}
|
|
104
|
+
const data = await res.json();
|
|
105
|
+
return {
|
|
106
|
+
model: String((data && data.model) || body.model),
|
|
107
|
+
answers: (data && data.answers) || {},
|
|
108
|
+
usage: (data && data.usage) || null,
|
|
109
|
+
};
|
|
110
|
+
} catch (e) {
|
|
111
|
+
if (e && (e.name === 'AbortError' || e.name === 'TimeoutError')) {
|
|
112
|
+
if (signal && signal.aborted) throw new Error('TypeSafe çağrısı iptal edildi');
|
|
113
|
+
throw new Error('TypeSafe zaman aşımı — istek ' + Math.round((Number(timeoutMs) > 0 ? Number(timeoutMs) : DEFAULT_TIMEOUT_MS) / 1000) + ' sn içinde yanıtlanmadı');
|
|
114
|
+
}
|
|
115
|
+
throw e;
|
|
116
|
+
} finally {
|
|
117
|
+
clearTimeout(timer);
|
|
118
|
+
if (signal && typeof signal.removeEventListener === 'function') signal.removeEventListener('abort', onAbort);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/* Anahtar testi: tek soruluk ucuz systemOne çağrısı (bağlantı + auth doğrular) */
|
|
123
|
+
async function probe(apiKey, model) {
|
|
124
|
+
const key = String(apiKey || '').trim();
|
|
125
|
+
if (!key) return { ok: false, error: 'API anahtarı boş' };
|
|
126
|
+
const useModel = String(model || '').trim() || DEFAULT_MODEL;
|
|
127
|
+
const ctrl = new AbortController();
|
|
128
|
+
const timer = setTimeout(() => ctrl.abort(), PROBE_TIMEOUT_MS);
|
|
129
|
+
try {
|
|
130
|
+
const res = await fetch(BASE_URL + '/v1/systemone', {
|
|
131
|
+
method: 'POST',
|
|
132
|
+
headers: { 'content-type': 'application/json', authorization: 'Bearer ' + key },
|
|
133
|
+
body: JSON.stringify({
|
|
134
|
+
state: 'ping',
|
|
135
|
+
model: useModel,
|
|
136
|
+
questions: { ok: { type: 'noul', instructions: 'Is this request working?' } },
|
|
137
|
+
}),
|
|
138
|
+
signal: ctrl.signal,
|
|
139
|
+
});
|
|
140
|
+
if (res.status === 401 || res.status === 403) return { ok: false, error: errorForStatus(res.status, '') };
|
|
141
|
+
if (!res.ok) {
|
|
142
|
+
const txt = await res.text().catch(() => '');
|
|
143
|
+
return { ok: false, error: errorForStatus(res.status, txt) };
|
|
144
|
+
}
|
|
145
|
+
const data = await res.json().catch(() => null);
|
|
146
|
+
return { ok: true, model: String((data && data.model) || useModel), answers: (data && data.answers) || {} };
|
|
147
|
+
} catch (e) {
|
|
148
|
+
if (e && (e.name === 'AbortError' || e.name === 'TimeoutError')) {
|
|
149
|
+
return { ok: false, error: 'TypeSafe zaman aşımı — anahtar/İnternet kontrol et' };
|
|
150
|
+
}
|
|
151
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
152
|
+
} finally {
|
|
153
|
+
clearTimeout(timer);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/* ---------- Ajan aracı: typesafe_decision ---------- */
|
|
158
|
+
|
|
159
|
+
const definitions = [
|
|
160
|
+
{
|
|
161
|
+
type: 'function',
|
|
162
|
+
function: {
|
|
163
|
+
name: 'typesafe_decision',
|
|
164
|
+
description:
|
|
165
|
+
'TypeSafe System One (Jev) ile TİPLİ KARAR: state + sorular gönderir, metin üretmeden olasılıklı yanıt alır (noul: 0-1 evet olasılığı; choice: seçenek + dağılım; score: ağırlıklı puan + dağılım). ' +
|
|
166
|
+
'Şüpheli/semantik yargılar için chat modeli gibi cevap yazdırıp JSON ayrıştırmak yerine BUNU kullan — hızlı, kalibre olasılıklı, doğrudan kod gibi tüketilir. ' +
|
|
167
|
+
'Örnekler: "bu haber X sembolünü yukarı iter mi?" (noul), "hangi seans/setup?" (choice), "setup kalitesi" (score). ' +
|
|
168
|
+
'questions: { id: {type:"noul"|"choice"|"score", instructions, criteria} }; noul criteria {true,false} (ops.), choice criteria {seçenek:açıklama|null}, score criteria [seviye...] (en az 2). ' +
|
|
169
|
+
'Aynı state üzerindeki bağımsız soruları TEK çağrıda birlikte sor. Yanıtları olasılık değerleriyle raporla.',
|
|
170
|
+
parameters: {
|
|
171
|
+
type: 'object',
|
|
172
|
+
properties: {
|
|
173
|
+
state: {
|
|
174
|
+
description: 'Değerlendirilecek içerik: serbest metin, ya da JSON nesne/dizi (ör. {haber, fiyat, pozisyon}). Tüm bağlamı ver — model yalnız bunu görür.',
|
|
175
|
+
},
|
|
176
|
+
questions: {
|
|
177
|
+
type: 'object',
|
|
178
|
+
description:
|
|
179
|
+
'Soru haritası: anahtar = kısa soru id (kod için; modele gitmez), değer = {type:"noul"|"choice"|"score", instructions, criteria}. ' +
|
|
180
|
+
'noul: evet/hayır sorusu; choice: criteria {seçenek: açıklama|null}; score: criteria ["seviye1","seviye2",...].',
|
|
181
|
+
additionalProperties: {
|
|
182
|
+
type: 'object',
|
|
183
|
+
properties: {
|
|
184
|
+
type: { type: 'string', enum: ['noul', 'choice', 'score'] },
|
|
185
|
+
instructions: { description: 'Karar sorusu (metin ya da JSON yapı)' },
|
|
186
|
+
criteria: { description: 'choice → nesne; score → dizi; noul → {true,false} (opsiyonel)' },
|
|
187
|
+
},
|
|
188
|
+
required: ['type', 'instructions'],
|
|
189
|
+
},
|
|
190
|
+
},
|
|
191
|
+
model: { type: 'string', description: 'TypeSafe modeli (varsayılan jev-latest)' },
|
|
192
|
+
},
|
|
193
|
+
required: ['state', 'questions'],
|
|
194
|
+
},
|
|
195
|
+
},
|
|
196
|
+
},
|
|
197
|
+
];
|
|
198
|
+
|
|
199
|
+
/* Yanıtı ajan için insan-okur özete çevir (kod yine ham `answers` alanını okur) */
|
|
200
|
+
function summarize(answers) {
|
|
201
|
+
const lines = [];
|
|
202
|
+
for (const [id, a] of Object.entries(answers || {})) {
|
|
203
|
+
const o = a && typeof a === 'object' ? a : {};
|
|
204
|
+
if (o.type === 'noul') {
|
|
205
|
+
lines.push(`- ${id}: noul=${Number(o.noul).toFixed(3)} (evet olasılığı)`);
|
|
206
|
+
} else if (o.type === 'choice') {
|
|
207
|
+
const probs = o.probabilities && typeof o.probabilities === 'object'
|
|
208
|
+
? Object.entries(o.probabilities).map(([k, v]) => `${k}=${Number(v).toFixed(3)}`).join(', ')
|
|
209
|
+
: '';
|
|
210
|
+
lines.push(`- ${id}: choice=${o.choice} · confidence=${Number(o.confidence).toFixed(3)}${probs ? ' · ' + probs : ''}`);
|
|
211
|
+
} else if (o.type === 'score') {
|
|
212
|
+
const probs = o.probabilities && typeof o.probabilities === 'object'
|
|
213
|
+
? Object.entries(o.probabilities).map(([k, v]) => `${k}=${Number(v).toFixed(3)}`).join(', ')
|
|
214
|
+
: '';
|
|
215
|
+
lines.push(`- ${id}: score=${o.score} · confidence=${Number(o.confidence).toFixed(3)}${probs ? ' · ' + probs : ''}`);
|
|
216
|
+
} else {
|
|
217
|
+
lines.push(`- ${id}: ${JSON.stringify(o).slice(0, 200)}`);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return lines.join('\n');
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
async function handler(args, ctx) {
|
|
224
|
+
const a = args && typeof args === 'object' ? args : {};
|
|
225
|
+
const c = cfg();
|
|
226
|
+
if (!c.apiKey) {
|
|
227
|
+
return { ok: false, error: 'TypeSafe API anahtarı yok — Ayarlar → TypeSafe sekmesinden gir (kullanıcıya bunu söyle)' };
|
|
228
|
+
}
|
|
229
|
+
let state = a.state;
|
|
230
|
+
if (typeof state === 'string') {
|
|
231
|
+
const s = state.trim();
|
|
232
|
+
if (!s) return { ok: false, error: 'state boş' };
|
|
233
|
+
state = s;
|
|
234
|
+
} else if (state && typeof state === 'object') {
|
|
235
|
+
/* olduğu gibi bırak */
|
|
236
|
+
} else {
|
|
237
|
+
return { ok: false, error: 'state gerekli (metin ya da JSON nesne/dizi)' };
|
|
238
|
+
}
|
|
239
|
+
let qs;
|
|
240
|
+
try {
|
|
241
|
+
qs = normalizeQuestions(a.questions);
|
|
242
|
+
} catch (e) {
|
|
243
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
244
|
+
}
|
|
245
|
+
try {
|
|
246
|
+
const r = await systemOne({
|
|
247
|
+
state,
|
|
248
|
+
questions: qs,
|
|
249
|
+
model: a.model,
|
|
250
|
+
timeoutMs: Number(a.timeout_ms) > 0 ? Number(a.timeout_ms) : DEFAULT_TIMEOUT_MS,
|
|
251
|
+
signal: ctx && ctx.signal,
|
|
252
|
+
});
|
|
253
|
+
return {
|
|
254
|
+
ok: true,
|
|
255
|
+
model: r.model,
|
|
256
|
+
answers: r.answers,
|
|
257
|
+
summary: summarize(r.answers),
|
|
258
|
+
usage: r.usage,
|
|
259
|
+
hint: 'Olasılıkları karar eşiklerinle (ör. >0.65 aksiyon, 0.35-0.65 belirsiz→insana sor) birlikte yorumla.',
|
|
260
|
+
};
|
|
261
|
+
} catch (e) {
|
|
262
|
+
return { ok: false, error: String((e && e.message) || e) };
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const handlers = { typesafe_decision: handler };
|
|
267
|
+
|
|
268
|
+
module.exports = {
|
|
269
|
+
definitions,
|
|
270
|
+
handlers,
|
|
271
|
+
systemOne,
|
|
272
|
+
probe,
|
|
273
|
+
setConfig,
|
|
274
|
+
cfg,
|
|
275
|
+
normalizeQuestions,
|
|
276
|
+
BASE_URL,
|
|
277
|
+
DEFAULT_MODEL,
|
|
278
|
+
};
|