maintainence love:)

This commit is contained in:
lovebird 2026-03-30 16:12:53 +02:00
parent 2f2d507baa
commit b2ccf37de9
10 changed files with 607 additions and 122 deletions

View File

@ -244,7 +244,21 @@ Integration tests live under **`orchestrator/`** (see comments in `orchestrator/
npm run test:ipc
```
Requires a built **`dist/kbot.exe`** (or `kbot` on Unix).
Classifier batch (semantic distances vs JobViewer labels):
```bash
npm run test:ipc:classifier
npm run test:ipc:classifier:openrouter
```
Stress: repeat the **same** batched `kbot-ai` call **N** times on **one** worker; prints per-run wall time, token usage (when present), then **min / max / avg / p50 / p95** and Σ tokens. Default **N = 5** for the OpenRouter stress script:
```bash
npm run test:ipc:classifier:openrouter:stress
KBOT_CLASSIFIER_STRESS_RUNS=10 npm run test:ipc:classifier:openrouter:stress
```
Requires a built **`dist/kbot.exe`** (or `kbot` on Unix). Set API keys via `config/postgres.toml` for OpenRouter.
## License

View File

@ -290,6 +290,28 @@ export function renderMarkdownReport(payload) {
}
}
if (payload.stress?.summary && typeof payload.stress.summary === 'object') {
const s = payload.stress.summary;
const w = s.wallMs;
lines.push('## Classifier stress (batch repeats)');
lines.push('');
lines.push(`| Metric | Value |`);
lines.push(`| --- | --- |`);
lines.push(`| Requested runs | ${s.requestedRuns ?? '—'} |`);
if (w && typeof w === 'object') {
lines.push(
`| Wall time (ms) | min ${w.min} · max ${w.max} · avg ${w.avg} · p50 ${w.p50} · p95 ${w.p95} |`
);
}
lines.push(`| Batch OK / fail | ${s.successCount ?? '—'} / ${s.failCount ?? '—'} |`);
if (s.totalTokens > 0 || s.totalPromptTokens > 0 || s.totalCompletionTokens > 0) {
lines.push(
`| Σ tokens (prompt / completion / total) | ${s.totalPromptTokens} / ${s.totalCompletionTokens} / ${s.totalTokens} |`
);
}
lines.push('');
}
if (payload.env && typeof payload.env === 'object') {
lines.push('## Environment (selected)');
lines.push('');

View File

@ -5,6 +5,10 @@
* to every business label (JobViewer.tsx ~205). Output is a single JSON array (+ meta).
*
* Run: npm run test:ipc:classifier
* CLI (overrides env): yargs see parseClassifierArgv()
* npm run test:ipc:classifier -- --help
* npm run test:ipc:classifier -- --provider openrouter --model openai/gpt-4o-mini --backend remote -n 3
* npm run test:ipc:classifier -- -r openrouter -m x -F stress,no-heartbeat
*
* Env:
* KBOT_IPC_CLASSIFIER_LLAMA set 0 to use OpenRouter (KBOT_ROUTER, KBOT_IPC_MODEL) instead of local llama :8888
@ -14,6 +18,8 @@
* KBOT_CLASSIFIER_TIMEOUT_MS single batched kbot-ai call (default: 300000)
*
* OpenRouter: npm run test:ipc:classifier:openrouter (sets KBOT_IPC_CLASSIFIER_LLAMA=0)
* Stress (batch repeats, one worker): KBOT_CLASSIFIER_STRESS_RUNS=N (default 1)
* npm run test:ipc:classifier:openrouter:stress OpenRouter + 5 runs (override N via env)
*
* Reports (reports.js): cwd/tests/test-ipc-classifier__HH-mm.{json,md}; array-only distances in
* test-ipc-classifier-distances__HH-mm.json (same timestamp as the main JSON).
@ -25,6 +31,8 @@ import { dirname } from 'node:path';
import { fileURLToPath } from 'node:url';
import net from 'node:net';
import { existsSync, unlinkSync } from 'node:fs';
import yargs from 'yargs';
import { hideBin } from 'yargs/helpers';
import {
distExePath,
@ -57,6 +65,116 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
/** Set at run start; used by catch for error reports */
let classifierMetricsCollector = null;
let classifierRunStartedAt = null;
/** Feature flags from `-F` / `--feature` (stress, no-heartbeat, no-report, quiet) */
let classifierFeatures = /** @type {Set<string>} */ (new Set());
/** Parsed argv (after yargs); set in parseClassifierArgv */
let classifierArgv = /** @type {Record<string, unknown> | null} */ (null);
/**
* @param {unknown} featureOpt
* @returns {Set<string>}
*/
function parseFeatureList(featureOpt) {
const out = [];
const arr = Array.isArray(featureOpt) ? featureOpt : [];
for (const f of arr) {
if (typeof f === 'string') out.push(...f.split(',').map((s) => s.trim()).filter(Boolean));
}
return new Set(out);
}
/**
* Parse CLI and apply to `process.env` (CLI wins over prior env).
* @returns {Record<string, unknown> & { featuresSet: Set<string> }}
*/
export function parseClassifierArgv() {
const y = yargs(hideBin(process.argv))
.scriptName('test-ipc-classifier')
.usage('$0 [options]\n\nIPC classifier batch test. Flags override env vars for this process.')
.option('provider', {
alias: 'r',
type: 'string',
describe: 'Router / provider → KBOT_ROUTER (e.g. openrouter, ollama, openai)',
})
.option('model', {
alias: 'm',
type: 'string',
describe: 'Model id → KBOT_IPC_MODEL',
})
.option('runs', {
alias: 'n',
type: 'number',
describe: 'Batch repeats (stress) → KBOT_CLASSIFIER_STRESS_RUNS',
})
.option('limit', {
alias: 'l',
type: 'number',
describe: 'Max labels → KBOT_CLASSIFIER_LIMIT',
})
.option('timeout', {
alias: 't',
type: 'number',
describe: 'LLM HTTP timeout ms → KBOT_CLASSIFIER_TIMEOUT_MS',
})
.option('backend', {
type: 'string',
choices: ['local', 'remote'],
describe: 'local = llama :8888; remote = router (sets KBOT_IPC_CLASSIFIER_LLAMA=0)',
})
.option('no-autostart', {
type: 'boolean',
default: false,
describe: 'Do not spawn run-7b.sh → KBOT_IPC_LLAMA_AUTOSTART=0',
})
.option('feature', {
alias: 'F',
type: 'array',
default: [],
describe:
'Feature flags (repeat or comma-separated): stress, no-heartbeat, no-report, quiet',
})
.strict()
.help()
.alias('h', 'help');
const argv = y.parseSync();
const featuresSet = parseFeatureList(argv.feature);
if (argv.provider != null && String(argv.provider).trim() !== '') {
process.env.KBOT_ROUTER = String(argv.provider).trim();
}
if (argv.model != null && String(argv.model).trim() !== '') {
process.env.KBOT_IPC_MODEL = String(argv.model).trim();
}
if (argv.runs != null && Number.isFinite(argv.runs) && argv.runs >= 1) {
process.env.KBOT_CLASSIFIER_STRESS_RUNS = String(Math.min(500, Math.floor(Number(argv.runs))));
}
if (argv.limit != null && Number.isFinite(argv.limit) && argv.limit >= 1) {
process.env.KBOT_CLASSIFIER_LIMIT = String(Math.floor(Number(argv.limit)));
}
if (argv.timeout != null && Number.isFinite(argv.timeout) && argv.timeout > 0) {
process.env.KBOT_CLASSIFIER_TIMEOUT_MS = String(Math.floor(Number(argv.timeout)));
}
if (argv['no-autostart'] === true) {
process.env.KBOT_IPC_LLAMA_AUTOSTART = '0';
}
if (argv.backend === 'remote') {
process.env.KBOT_IPC_CLASSIFIER_LLAMA = '0';
} else if (argv.backend === 'local') {
delete process.env.KBOT_IPC_CLASSIFIER_LLAMA;
}
if (featuresSet.has('stress') && (argv.runs == null || !Number.isFinite(argv.runs))) {
if (!process.env.KBOT_CLASSIFIER_STRESS_RUNS) {
process.env.KBOT_CLASSIFIER_STRESS_RUNS = '5';
}
}
classifierFeatures = featuresSet;
const out = { ...argv, featuresSet };
classifierArgv = out;
return out;
}
const EXE = distExePath(__dirname);
const stats = createAssert();
const { assert } = stats;
@ -166,6 +284,44 @@ function batchTimeoutMs() {
return Number.isFinite(n) && n > 0 ? n : 300_000;
}
/** Sequential batch iterations on one worker (stress). Default 1 = single run. */
function stressRunCount() {
const raw = process.env.KBOT_CLASSIFIER_STRESS_RUNS;
if (raw === undefined || raw === '') return 1;
const n = Number.parseInt(String(raw).trim(), 10);
if (!Number.isFinite(n) || n < 1) return 1;
return Math.min(n, 500);
}
/** @param {unknown} llm — job_result.llm from kbot-ai */
function usageTokens(llm) {
if (!llm || typeof llm !== 'object') return null;
const u = /** @type {Record<string, unknown>} */ (llm).usage;
if (!u || typeof u !== 'object') return null;
const o = /** @type {Record<string, unknown>} */ (u);
return {
prompt: o.prompt_tokens ?? o.promptTokens ?? null,
completion: o.completion_tokens ?? o.completionTokens ?? null,
total: o.total_tokens ?? o.totalTokens ?? null,
};
}
/** @param {number[]} values */
function summarizeMs(values) {
if (values.length === 0) return null;
const sorted = [...values].sort((a, b) => a - b);
const sum = values.reduce((a, b) => a + b, 0);
const mid = (a, b) => (a + b) / 2;
const p = (q) => sorted[Math.min(sorted.length - 1, Math.max(0, Math.floor(q * (sorted.length - 1))))];
return {
min: sorted[0],
max: sorted[sorted.length - 1],
avg: Math.round((sum / values.length) * 100) / 100,
p50: sorted.length % 2 ? sorted[Math.floor(sorted.length / 2)] : mid(sorted[sorted.length / 2 - 1], sorted[sorted.length / 2]),
p95: p(0.95),
};
}
/** Log progress while awaiting a long LLM call (no silent hang). */
function withHeartbeat(promise, ipcTimeoutMs, backendLabel) {
const every = 15_000;
@ -192,13 +348,66 @@ function buildKbotAiPayload(labels, tmo) {
};
}
/**
* Parse kbot-ai job_result; updates assertion stats.
* @returns {{ distances: {label:string,distance:number|null}[], missing: string[], parseError: string|null, rawText: string|null, batchOk: boolean }}
*/
function processBatchResponse(p, labels) {
let rawText = null;
let distances = [];
let parseError = null;
let missing = [];
let batchOk = false;
if (p?.status === 'success' && typeof p?.text === 'string') {
rawText = p.text;
const arr = extractJsonArray(p.text);
if (arr) {
const norm = normalizeBatchArray(arr, labels);
distances = norm.distances;
missing = norm.missing;
if (missing.length === 0) {
assert(true, 'batch JSON array: all labels have distance');
batchOk = true;
} else {
assert(false, `batch array complete (${missing.length} missing labels)`);
parseError = `missing: ${missing.join('; ')}`;
}
} else {
assert(false, 'batch response parses as JSON array');
parseError = 'could not parse JSON array from model text';
}
} else {
assert(false, 'kbot-ai success');
parseError = p?.error ?? 'not success';
}
return { distances, missing, parseError, rawText, batchOk };
}
async function runSingleBatch(ipc, labels, tmo, ipcDeadlineMs, waitLabel) {
const payload = buildKbotAiPayload(labels, tmo);
const t0 = performance.now();
const pending = ipc.request({ type: 'kbot-ai', payload }, ipcDeadlineMs);
const msg = classifierFeatures.has('no-heartbeat')
? await pending
: await withHeartbeat(pending, ipcDeadlineMs, waitLabel);
const elapsedMs = Math.round(performance.now() - t0);
const p = payloadObj(msg);
const parsed = processBatchResponse(p, labels);
return { elapsedMs, p, ...parsed };
}
async function run() {
const quiet = classifierFeatures.has('quiet');
classifierMetricsCollector = createMetricsCollector();
classifierRunStartedAt = new Date().toISOString();
const startedAt = classifierRunStartedAt;
const useLlama = ipcClassifierLlamaEnabled();
const backendLabel = useLlama ? `llama @ :${llama.port}` : `router=${router.fromEnv()}`;
console.log(`\n📐 IPC classifier (${backendLabel}) — one batch, distance vs "machine workshop"\n`);
if (!quiet) {
console.log(`\n📐 IPC classifier (${backendLabel}) — one batch, distance vs "machine workshop"\n`);
}
if (!existsSync(EXE)) {
console.error(`❌ Binary not found at ${EXE}`);
@ -248,47 +457,104 @@ async function run() {
const tmo = batchTimeoutMs();
const ipcDeadlineMs = tmo + 60_000;
console.log(` Single kbot-ai batch: ${labels.length} labels`);
console.log(` liboai HTTP timeout: ${tmo} ms (llm_timeout_ms) — rebuild kbot if this was stuck at ~30s before`);
console.log(` IPC wait deadline: ${ipcDeadlineMs} ms (HTTP + margin)`);
console.log(` (Large batches can take many minutes; heartbeat every 15s…)\n`);
const payload = buildKbotAiPayload(labels, tmo);
const waitLabel = useLlama ? 'llama' : router.fromEnv();
const msg = await withHeartbeat(
ipc.request({ type: 'kbot-ai', payload }, ipcDeadlineMs),
ipcDeadlineMs,
waitLabel
);
const p = payloadObj(msg);
const nRuns = stressRunCount();
let rawText = null;
let distances = [];
let parseError = null;
let missing = [];
if (p?.status === 'success' && typeof p?.text === 'string') {
rawText = p.text;
const arr = extractJsonArray(p.text);
if (arr) {
const norm = normalizeBatchArray(arr, labels);
distances = norm.distances;
missing = norm.missing;
if (missing.length === 0) {
assert(true, 'batch JSON array: all labels have distance');
} else {
assert(false, `batch array complete (${missing.length} missing labels)`);
parseError = `missing: ${missing.join('; ')}`;
}
} else {
assert(false, 'batch response parses as JSON array');
parseError = 'could not parse JSON array from model text';
}
} else {
assert(false, 'kbot-ai success');
parseError = p?.error ?? 'not success';
if (!quiet) {
console.log(` kbot-ai batch: ${labels.length} labels × ${nRuns} run(s)`);
console.log(` liboai HTTP timeout: ${tmo} ms (llm_timeout_ms) — rebuild kbot if this was stuck at ~30s before`);
console.log(` IPC wait deadline: ${ipcDeadlineMs} ms (HTTP + margin)`);
const hb = classifierFeatures.has('no-heartbeat') ? 'off' : '15s';
console.log(` (Large batches can take many minutes; heartbeat ${hb}…)\n`);
}
/** @type {Array<{ index: number, wallMs: number, batchOk: boolean, parseError: string|null, usage: ReturnType<typeof usageTokens>}>} */
const stressIterations = [];
let lastP = /** @type {Record<string, unknown>|null} */ (null);
let lastDistances = [];
let lastRawText = null;
let lastParseError = null;
let lastByDistance = [];
for (let r = 0; r < nRuns; r++) {
if (nRuns > 1 && !quiet) {
console.log(` ── Stress run ${r + 1}/${nRuns} ──`);
}
const batch = await runSingleBatch(ipc, labels, tmo, ipcDeadlineMs, waitLabel);
lastP = batch.p;
lastDistances = batch.distances;
lastRawText = batch.rawText;
lastParseError = batch.parseError;
lastByDistance = [...batch.distances].sort((a, b) => {
if (a.distance == null && b.distance == null) return 0;
if (a.distance == null) return 1;
if (b.distance == null) return -1;
return a.distance - b.distance;
});
const u = usageTokens(batch.p?.llm);
stressIterations.push({
index: r + 1,
wallMs: batch.elapsedMs,
batchOk: batch.batchOk,
parseError: batch.parseError,
usage: u,
});
if (nRuns > 1 && !quiet) {
const tok = u
? `tokens p/c/t ${u.prompt ?? '—'}/${u.completion ?? '—'}/${u.total ?? '—'}`
: 'tokens —';
console.log(` wall: ${batch.elapsedMs} ms ${batch.batchOk ? 'OK' : 'FAIL'} ${tok}`);
}
}
const wallMsList = stressIterations.map((x) => x.wallMs);
/** @type {null | { requestedRuns: number, wallMs: NonNullable<ReturnType<typeof summarizeMs>>, successCount: number, failCount: number, totalPromptTokens: number, totalCompletionTokens: number, totalTokens: number }} */
let stressSummary = null;
if (nRuns > 1) {
const w = summarizeMs(wallMsList);
stressSummary = {
requestedRuns: nRuns,
wallMs: /** @type {NonNullable<typeof w>} */ (w),
successCount: stressIterations.filter((x) => x.batchOk).length,
failCount: stressIterations.filter((x) => !x.batchOk).length,
totalPromptTokens: stressIterations.reduce((s, x) => s + (Number(x.usage?.prompt) || 0), 0),
totalCompletionTokens: stressIterations.reduce((s, x) => s + (Number(x.usage?.completion) || 0), 0),
totalTokens: stressIterations.reduce((s, x) => s + (Number(x.usage?.total) || 0), 0),
};
if (quiet) {
console.log(
`stress ${nRuns} runs: min=${stressSummary.wallMs.min}ms max=${stressSummary.wallMs.max}ms avg=${stressSummary.wallMs.avg}ms ok=${stressSummary.successCount}/${nRuns} tokensΣ=${stressSummary.totalTokens}`
);
} else {
console.log(`\n ═══════════════ Stress summary (${nRuns} batch runs) ═══════════════`);
console.log(
` Wall time (ms): min ${stressSummary.wallMs.min} max ${stressSummary.wallMs.max} avg ${stressSummary.wallMs.avg} p50 ${stressSummary.wallMs.p50} p95 ${stressSummary.wallMs.p95}`
);
console.log(
` Batches OK: ${stressSummary.successCount} fail: ${stressSummary.failCount} (assertions: passed ${stats.passed} failed ${stats.failed})`
);
if (
stressSummary.totalPromptTokens > 0 ||
stressSummary.totalCompletionTokens > 0 ||
stressSummary.totalTokens > 0
) {
console.log(
` Token totals (sum over runs): prompt ${stressSummary.totalPromptTokens} completion ${stressSummary.totalCompletionTokens} total ${stressSummary.totalTokens}`
);
}
console.log(` ═══════════════════════════════════════════════════════════════════\n`);
}
}
const p = lastP;
const distances = lastDistances;
const rawText = lastRawText;
const parseError = lastParseError;
const byDistance = lastByDistance;
const shutdownRes = await ipc.request({ type: 'shutdown' }, timeouts.ipcDefault);
assert(shutdownRes.type === 'shutdown_ack', 'shutdown ack');
await new Promise((r) => setTimeout(r, timeouts.postShutdownMs));
@ -297,14 +563,6 @@ async function run() {
const finishedAt = new Date().toISOString();
/** Final array: sorted by distance (nulls last). */
const byDistance = [...distances].sort((a, b) => {
if (a.distance == null && b.distance == null) return 0;
if (a.distance == null) return 1;
if (b.distance == null) return -1;
return a.distance - b.distance;
});
const reportNow = new Date();
const cwd = process.cwd();
@ -315,6 +573,13 @@ async function run() {
failed: stats.failed,
ok: stats.failed === 0,
ipcClassifierLlama: useLlama,
cli: {
features: [...classifierFeatures],
provider: process.env.KBOT_ROUTER ?? null,
model: process.env.KBOT_IPC_MODEL ?? null,
backend: useLlama ? 'local' : 'remote',
stressRuns: nRuns,
},
env: {
KBOT_IPC_CLASSIFIER_LLAMA: process.env.KBOT_IPC_CLASSIFIER_LLAMA ?? null,
KBOT_IPC_LLAMA_AUTOSTART: process.env.KBOT_IPC_LLAMA_AUTOSTART ?? null,
@ -322,6 +587,7 @@ async function run() {
KBOT_IPC_MODEL: process.env.KBOT_IPC_MODEL ?? null,
KBOT_CLASSIFIER_LIMIT: process.env.KBOT_CLASSIFIER_LIMIT ?? null,
KBOT_CLASSIFIER_TIMEOUT_MS: process.env.KBOT_CLASSIFIER_TIMEOUT_MS ?? null,
KBOT_CLASSIFIER_STRESS_RUNS: process.env.KBOT_CLASSIFIER_STRESS_RUNS ?? null,
KBOT_LLAMA_PORT: process.env.KBOT_LLAMA_PORT ?? null,
KBOT_LLAMA_BASE_URL: process.env.KBOT_LLAMA_BASE_URL ?? null,
},
@ -350,58 +616,79 @@ async function run() {
byDistance,
rawText,
parseError: parseError ?? null,
...(nRuns > 1 && stressSummary
? {
stress: {
requestedRuns: nRuns,
iterations: stressIterations,
summary: stressSummary,
},
}
: {}),
};
let jsonPath = '';
let mdPath = '';
try {
const written = await writeTestReports('test-ipc-classifier', reportData, { cwd, now: reportNow });
jsonPath = written.jsonPath;
mdPath = written.mdPath;
} catch (e) {
console.error(' ⚠️ Failed to write report:', e?.message ?? e);
let arrayPath = '';
if (!classifierFeatures.has('no-report')) {
try {
const written = await writeTestReports('test-ipc-classifier', reportData, { cwd, now: reportNow });
jsonPath = written.jsonPath;
mdPath = written.mdPath;
} catch (e) {
console.error(' ⚠️ Failed to write report:', e?.message ?? e);
}
/** Array-only artifact (same timestamp as main report). */
arrayPath = reportFilePathWithExt('test-ipc-classifier-distances', '.json', { cwd, now: reportNow });
await mkdir(dirname(arrayPath), { recursive: true });
await writeFile(arrayPath, `${JSON.stringify(distances, null, 2)}\n`, 'utf8');
}
/** Array-only artifact (same timestamp as main report). */
const arrayPath = reportFilePathWithExt('test-ipc-classifier-distances', '.json', { cwd, now: reportNow });
await mkdir(dirname(arrayPath), { recursive: true });
await writeFile(arrayPath, `${JSON.stringify(distances, null, 2)}\n`, 'utf8');
const { label: timeLabel } = timeParts(reportNow);
console.log(`\n────────────────────────────────`);
console.log(` Passed: ${stats.passed} Failed: ${stats.failed}`);
if (jsonPath) console.log(` Report JSON: ${jsonPath}`);
if (mdPath) console.log(` Report MD: ${mdPath}`);
console.log(` Distances JSON: ${arrayPath}`);
console.log(` Run id: test-ipc-classifier::${timeLabel}`);
console.log(` distances.length: ${distances.length}`);
console.log(`────────────────────────────────\n`);
if (!classifierFeatures.has('quiet')) {
console.log(`\n────────────────────────────────`);
console.log(` Passed: ${stats.passed} Failed: ${stats.failed}`);
if (jsonPath) console.log(` Report JSON: ${jsonPath}`);
if (mdPath) console.log(` Report MD: ${mdPath}`);
if (arrayPath) console.log(` Distances JSON: ${arrayPath}`);
console.log(` Run id: test-ipc-classifier::${timeLabel}`);
console.log(` distances.length: ${distances.length}`);
console.log(`────────────────────────────────\n`);
} else {
console.log(
`done: passed=${stats.passed} failed=${stats.failed} ok=${stats.failed === 0}${jsonPath ? ` json=${jsonPath}` : ''}`
);
}
process.exit(stats.failed > 0 ? 1 : 0);
}
parseClassifierArgv();
run().catch(async (err) => {
console.error('Classifier error:', err);
try {
const finishedAt = new Date().toISOString();
const c = classifierMetricsCollector ?? createMetricsCollector();
const started = classifierRunStartedAt ?? finishedAt;
await writeTestReports(
'test-ipc-classifier',
{
startedAt: started,
finishedAt,
error: String(err?.stack ?? err),
passed: stats.passed,
failed: stats.failed,
ok: false,
ipcClassifierLlama: ipcClassifierLlamaEnabled(),
metrics: buildMetricsBundle(c, started, finishedAt),
},
{ cwd: process.cwd() }
);
} catch (_) {
/* ignore */
if (!classifierFeatures.has('no-report')) {
try {
const finishedAt = new Date().toISOString();
const c = classifierMetricsCollector ?? createMetricsCollector();
const started = classifierRunStartedAt ?? finishedAt;
await writeTestReports(
'test-ipc-classifier',
{
startedAt: started,
finishedAt,
error: String(err?.stack ?? err),
passed: stats.passed,
failed: stats.failed,
ok: false,
ipcClassifierLlama: ipcClassifierLlamaEnabled(),
metrics: buildMetricsBundle(c, started, finishedAt),
},
{ cwd: process.cwd() }
);
} catch (_) {
/* ignore */
}
}
process.exit(1);
});

View File

@ -1,6 +1,193 @@
{
"name": "mono-cpp",
"name": "kbot-cpp",
"version": "1.0.0",
"lockfileVersion": 3,
"requires": true,
"packages": {}
"packages": {
"": {
"name": "kbot-cpp",
"version": "1.0.0",
"license": "ISC",
"dependencies": {
"yargs": "^17.7.2"
}
},
"node_modules/ansi-regex": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
"integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/ansi-styles": {
"version": "4.3.0",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
"license": "MIT",
"dependencies": {
"color-convert": "^2.0.1"
},
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
}
},
"node_modules/cliui": {
"version": "8.0.1",
"resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz",
"integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==",
"license": "ISC",
"dependencies": {
"string-width": "^4.2.0",
"strip-ansi": "^6.0.1",
"wrap-ansi": "^7.0.0"
},
"engines": {
"node": ">=12"
}
},
"node_modules/color-convert": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
"license": "MIT",
"dependencies": {
"color-name": "~1.1.4"
},
"engines": {
"node": ">=7.0.0"
}
},
"node_modules/color-name": {
"version": "1.1.4",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
"license": "MIT"
},
"node_modules/emoji-regex": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
"integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
"license": "MIT"
},
"node_modules/escalade": {
"version": "3.2.0",
"resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz",
"integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==",
"license": "MIT",
"engines": {
"node": ">=6"
}
},
"node_modules/get-caller-file": {
"version": "2.0.5",
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
"integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
"license": "ISC",
"engines": {
"node": "6.* || 8.* || >= 10.*"
}
},
"node_modules/is-fullwidth-code-point": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
"integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
"license": "MIT",
"engines": {
"node": ">=8"
}
},
"node_modules/require-directory": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
"integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/string-width": {
"version": "4.2.3",
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
"integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
"license": "MIT",
"dependencies": {
"emoji-regex": "^8.0.0",
"is-fullwidth-code-point": "^3.0.0",
"strip-ansi": "^6.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/strip-ansi": {
"version": "6.0.1",
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
"integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
"license": "MIT",
"dependencies": {
"ansi-regex": "^5.0.1"
},
"engines": {
"node": ">=8"
}
},
"node_modules/wrap-ansi": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
"integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
"license": "MIT",
"dependencies": {
"ansi-styles": "^4.0.0",
"string-width": "^4.1.0",
"strip-ansi": "^6.0.0"
},
"engines": {
"node": ">=10"
},
"funding": {
"url": "https://github.com/chalk/wrap-ansi?sponsor=1"
}
},
"node_modules/y18n": {
"version": "5.0.8",
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
"integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
"license": "ISC",
"engines": {
"node": ">=10"
}
},
"node_modules/yargs": {
"version": "17.7.2",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz",
"integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==",
"license": "MIT",
"dependencies": {
"cliui": "^8.0.1",
"escalade": "^3.1.1",
"get-caller-file": "^2.0.5",
"require-directory": "^2.1.1",
"string-width": "^4.2.3",
"y18n": "^5.0.5",
"yargs-parser": "^21.1.1"
},
"engines": {
"node": ">=12"
}
},
"node_modules/yargs-parser": {
"version": "21.1.1",
"resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz",
"integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==",
"license": "ISC",
"engines": {
"node": ">=12"
}
}
}
}

View File

@ -6,6 +6,9 @@
"directories": {
"test": "tests"
},
"dependencies": {
"yargs": "^17.7.2"
},
"scripts": {
"config": "cmake --preset dev",
"config:release": "cmake --preset release",
@ -24,6 +27,7 @@
"test:ipc": "node orchestrator/test-ipc.mjs",
"test:ipc:classifier": "node orchestrator/test-ipc-classifier.mjs",
"test:ipc:classifier:openrouter": "node orchestrator/classifier-openrouter.mjs",
"test:ipc:classifier:openrouter:stress": "node orchestrator/classifier-openrouter-stress.mjs",
"test:html": "cmake --preset release && cmake --build --preset release --target test_html && .\\dist\\test_html.exe"
},
"repository": {

View File

@ -5,21 +5,6 @@
},
{
"path": "../commons"
},
{
"path": "../cad"
},
{
"path": "../tasks"
},
{
"path": "../i18n"
},
{
"path": "../acl"
},
{
"path": "../llm"
}
],
"settings": {}

View File

@ -1,5 +1,5 @@
{
"timestamp": 1774802354444,
"timestamp": 1774879965316,
"models": [
{
"id": "gpt-4-0613",

View File

@ -1,5 +1,5 @@
{
"timestamp": 1774802355711,
"timestamp": 1774879966823,
"models": [
{
"id": "kwaipilot/kat-coder-pro-v2",
@ -256,21 +256,13 @@
},
"per_request_limits": null,
"supported_parameters": [
"frequency_penalty",
"include_reasoning",
"logit_bias",
"max_tokens",
"min_p",
"presence_penalty",
"reasoning",
"repetition_penalty",
"response_format",
"seed",
"stop",
"temperature",
"tool_choice",
"tools",
"top_k",
"top_p"
],
"default_parameters": {
@ -2419,11 +2411,7 @@
},
"pricing": {
"prompt": "0",
"completion": "0",
"request": "0",
"image": "0",
"web_search": "0",
"internal_reasoning": "0"
"completion": "0"
},
"top_provider": {
"context_length": 131000,
@ -5091,9 +5079,7 @@
"per_request_limits": null,
"supported_parameters": [
"frequency_penalty",
"logit_bias",
"max_tokens",
"min_p",
"presence_penalty",
"repetition_penalty",
"response_format",

File diff suppressed because one or more lines are too long

View File

@ -1,3 +1,3 @@
export enum E_OPENROUTER_MODEL_FREE {
MODEL_FREE_ARCEE_AI_TRINITY_LARGE_PREVIEW_FREE = "arcee-ai/trinity-large-preview:free"
}