@goodandready/dsh-moa 0.2.26 → 0.2.29
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 +30 -0
- package/README.ru.md +30 -0
- package/lib/client.js +194 -0
- package/lib/file-workspace.js +5 -4
- package/lib/history.js +12 -6
- package/lib/index.js +39 -1
- package/lib/logger.js +40 -0
- package/lib/moa-budget.js +97 -0
- package/lib/moa-candidates.js +91 -22
- package/lib/moa-context.js +70 -0
- package/lib/moa-multi-judge.js +301 -0
- package/lib/moa-prompts.js +3 -0
- package/lib/moa-report.js +124 -0
- package/lib/moa-router.js +102 -0
- package/lib/moa-runner.js +108 -127
- package/lib/moa-stream.js +117 -0
- package/lib/moa-test-gate.js +4 -3
- package/lib/routes.js +92 -7
- package/package.json +1 -1
package/lib/routes.js
CHANGED
|
@@ -11,6 +11,8 @@ import {
|
|
|
11
11
|
import { promoteCandidateWorkspace, readCandidateFiles, computeLineDiff, isSafeRelativePath } from './file-workspace.js'
|
|
12
12
|
import { isSafeWriteRequest } from './updater.js'
|
|
13
13
|
import { runMoAPipeline } from './moa-runner.js'
|
|
14
|
+
import { generateMoABenchmarkReport } from './moa-report.js'
|
|
15
|
+
import { resolvePresetForPrompt } from './moa-router.js'
|
|
14
16
|
|
|
15
17
|
let _modelsCache = { timestamp: 0, models: [] }
|
|
16
18
|
const MODELS_CACHE_TTL = 60 * 1000
|
|
@@ -44,7 +46,11 @@ ctx.effect(() => {
|
|
|
44
46
|
return ctx.webServer.register({
|
|
45
47
|
kind: 'exact',
|
|
46
48
|
path: '/dsh-moa/status',
|
|
47
|
-
handler: (
|
|
49
|
+
handler: (req, res) => {
|
|
50
|
+
if (req.method !== 'GET') {
|
|
51
|
+
writeJson(res, 405, { ok: false, error: 'GET required' })
|
|
52
|
+
return
|
|
53
|
+
}
|
|
48
54
|
try {
|
|
49
55
|
const cfg = live()
|
|
50
56
|
writeJson(res, 200, {
|
|
@@ -65,7 +71,11 @@ ctx.effect(() => {
|
|
|
65
71
|
return ctx.webServer.register({
|
|
66
72
|
kind: 'exact',
|
|
67
73
|
path: '/dsh-moa/models',
|
|
68
|
-
handler: async (
|
|
74
|
+
handler: async (req, res) => {
|
|
75
|
+
if (req.method !== 'GET') {
|
|
76
|
+
writeJson(res, 405, { ok: false, error: 'GET required' })
|
|
77
|
+
return
|
|
78
|
+
}
|
|
69
79
|
if (_modelsCache.models.length > 0 && Date.now() - _modelsCache.timestamp < MODELS_CACHE_TTL) {
|
|
70
80
|
writeJson(res, 200, { ok: true, models: _modelsCache.models, cached: true })
|
|
71
81
|
return
|
|
@@ -92,7 +102,7 @@ ctx.effect(() => {
|
|
|
92
102
|
}
|
|
93
103
|
}
|
|
94
104
|
} catch (e) {
|
|
95
|
-
|
|
105
|
+
ctx.logger?.warn?.('[dsh-moa] ctx.llm.listAvailableModels error:', e)
|
|
96
106
|
}
|
|
97
107
|
|
|
98
108
|
try {
|
|
@@ -117,7 +127,7 @@ ctx.effect(() => {
|
|
|
117
127
|
await Promise.allSettled(queries)
|
|
118
128
|
}
|
|
119
129
|
} catch (e) {
|
|
120
|
-
|
|
130
|
+
ctx.logger?.warn?.('[dsh-moa] ctx.llm.listConfigurableProviders error:', e)
|
|
121
131
|
}
|
|
122
132
|
}
|
|
123
133
|
|
|
@@ -154,7 +164,7 @@ ctx.effect(() => {
|
|
|
154
164
|
}
|
|
155
165
|
}
|
|
156
166
|
} catch (e) {
|
|
157
|
-
|
|
167
|
+
ctx.logger?.warn?.('[dsh-moa] Error reading settings:', e)
|
|
158
168
|
}
|
|
159
169
|
|
|
160
170
|
_modelsCache = { timestamp: Date.now(), models: result }
|
|
@@ -239,8 +249,10 @@ ctx.effect(() => {
|
|
|
239
249
|
}
|
|
240
250
|
try {
|
|
241
251
|
const u = new URL(req.url, 'http://localhost')
|
|
242
|
-
const
|
|
243
|
-
const
|
|
252
|
+
const rawLimit = parseInt(u.searchParams.get('limit') || '20', 10)
|
|
253
|
+
const rawOffset = parseInt(u.searchParams.get('offset') || '0', 10)
|
|
254
|
+
const limit = Math.max(1, Math.min(100, Number.isFinite(rawLimit) ? rawLimit : 20))
|
|
255
|
+
const offset = Math.max(0, Number.isFinite(rawOffset) ? rawOffset : 0)
|
|
244
256
|
const data = getMoaHistory(limit, offset)
|
|
245
257
|
writeJson(res, 200, { ok: true, ...data })
|
|
246
258
|
} catch (err) {
|
|
@@ -423,16 +435,83 @@ ctx.effect(() => {
|
|
|
423
435
|
const urlPath = req.url.split('?')[0]
|
|
424
436
|
const parts = urlPath.split('/').filter(Boolean)
|
|
425
437
|
const runId = parts[2] || ''
|
|
438
|
+
const isReport = parts[3] === 'report'
|
|
426
439
|
const run = runId ? getMoaRunById(runId) : null
|
|
427
440
|
if (!run) {
|
|
428
441
|
writeJson(res, 404, { ok: false, error: 'Run not found' })
|
|
429
442
|
return
|
|
430
443
|
}
|
|
444
|
+
if (isReport) {
|
|
445
|
+
const u = new URL(req.url, 'http://127.0.0.1')
|
|
446
|
+
const format = u.searchParams.get('format') || 'md'
|
|
447
|
+
const report = run.benchmarkReport || generateMoABenchmarkReport({
|
|
448
|
+
runId: run.id,
|
|
449
|
+
timestamp: run.timestamp,
|
|
450
|
+
preset: run.preset,
|
|
451
|
+
prompt: run.prompt,
|
|
452
|
+
durationMs: run.durationMs,
|
|
453
|
+
usage: { totalTokens: run.totalTokens },
|
|
454
|
+
costUsd: run.totalCostUsd,
|
|
455
|
+
candidates: run.candidates,
|
|
456
|
+
winningIndex: run.winnerIndex,
|
|
457
|
+
winningLabel: run.winnerModel,
|
|
458
|
+
})
|
|
459
|
+
if (format === 'json') {
|
|
460
|
+
writeJson(res, 200, { ok: true, report: typeof report === 'object' ? (report.json || report) : report })
|
|
461
|
+
return
|
|
462
|
+
}
|
|
463
|
+
const mdText = typeof report === 'string' ? report : (report.markdown || JSON.stringify(report, null, 2))
|
|
464
|
+
res.writeHead(200, { 'Content-Type': 'text/markdown; charset=utf-8' })
|
|
465
|
+
res.end(mdText)
|
|
466
|
+
return
|
|
467
|
+
}
|
|
431
468
|
writeJson(res, 200, { ok: true, run })
|
|
432
469
|
},
|
|
433
470
|
})
|
|
434
471
|
}, 'dsh-moa: run by id route')
|
|
435
472
|
|
|
473
|
+
// Route: /dsh-moa/route-preset
|
|
474
|
+
ctx.effect(() => {
|
|
475
|
+
return ctx.webServer.register({
|
|
476
|
+
kind: 'exact',
|
|
477
|
+
path: '/dsh-moa/route-preset',
|
|
478
|
+
handler: async (req, res) => {
|
|
479
|
+
if (req.method !== 'POST') {
|
|
480
|
+
writeJson(res, 405, { ok: false, error: 'POST required' })
|
|
481
|
+
return
|
|
482
|
+
}
|
|
483
|
+
if (!isSafeWriteRequest(req)) {
|
|
484
|
+
writeJson(res, 403, { ok: false, error: 'Forbidden: cross-site request rejected' })
|
|
485
|
+
return
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
const cfg = live()
|
|
489
|
+
if (cfg.enabled === false) {
|
|
490
|
+
writeJson(res, 400, { ok: false, error: 'MoA is disabled in settings' })
|
|
491
|
+
return
|
|
492
|
+
}
|
|
493
|
+
const raw = await readBody(req)
|
|
494
|
+
const body = JSON.parse(raw || '{}')
|
|
495
|
+
const prompt = body?.prompt || ''
|
|
496
|
+
const result = await resolvePresetForPrompt({
|
|
497
|
+
prompt,
|
|
498
|
+
presets: cfg.presets || [],
|
|
499
|
+
defaultPreset: cfg.default_preset || 'default',
|
|
500
|
+
routingModel: cfg.smart_routing_model,
|
|
501
|
+
callLlm,
|
|
502
|
+
enabled: cfg.enabled !== false,
|
|
503
|
+
})
|
|
504
|
+
writeJson(res, 200, { ok: true, ...result })
|
|
505
|
+
} catch (err) {
|
|
506
|
+
writeJson(res, 500, { ok: false, error: err?.message || String(err) })
|
|
507
|
+
}
|
|
508
|
+
},
|
|
509
|
+
})
|
|
510
|
+
}, 'dsh-moa: route preset endpoint')
|
|
511
|
+
|
|
512
|
+
let _lastRunTimestamp = 0
|
|
513
|
+
const RUN_MIN_INTERVAL_MS = 1000
|
|
514
|
+
|
|
436
515
|
// Route: /dsh-moa/run
|
|
437
516
|
ctx.effect(() => {
|
|
438
517
|
return ctx.webServer.register({
|
|
@@ -447,6 +526,12 @@ ctx.effect(() => {
|
|
|
447
526
|
writeJson(res, 403, { ok: false, error: 'Forbidden: cross-site request rejected' })
|
|
448
527
|
return
|
|
449
528
|
}
|
|
529
|
+
const now = Date.now()
|
|
530
|
+
if (now - _lastRunTimestamp < RUN_MIN_INTERVAL_MS) {
|
|
531
|
+
writeJson(res, 429, { ok: false, error: 'Rate limit exceeded: please wait before starting another run' })
|
|
532
|
+
return
|
|
533
|
+
}
|
|
534
|
+
_lastRunTimestamp = now
|
|
450
535
|
|
|
451
536
|
try {
|
|
452
537
|
const raw = await readBody(req)
|