@twinsearth/dsh-master 3.2.10 → 3.3.0
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 +3 -0
- package/client.js +50 -0
- package/dist-host/cost/attribution.js +183 -0
- package/dist-host/cost/audit.js +163 -0
- package/dist-host/cost/budget.js +211 -0
- package/dist-host/cost/bus.js +95 -0
- package/dist-host/cost/cert-chain.js +100 -0
- package/dist-host/cost/experiment.js +132 -0
- package/dist-host/cost/gate.js +189 -0
- package/dist-host/cost/host-surface.js +80 -0
- package/dist-host/cost/index.js +312 -0
- package/dist-host/cost/ledger-report.js +193 -0
- package/dist-host/cost/ledger.js +401 -0
- package/dist-host/cost/metrics.js +198 -0
- package/dist-host/cost/milestones.js +171 -0
- package/dist-host/cost/modules/index.js +5 -0
- package/dist-host/cost/modules/manifests.js +130 -0
- package/dist-host/cost/policy.js +276 -0
- package/dist-host/cost/report.js +156 -0
- package/dist-host/cost/reuse-report.js +128 -0
- package/dist-host/cost/rsi.js +367 -0
- package/dist-host/cost/toolface.js +147 -0
- package/dist-host/cost/types.js +31 -0
- package/dist-host/kernel.js +28 -2
- package/dist-host/plugins/cost-optimizer.js +277 -27
- package/dist-host/plugins/superagent-router.js +88 -1
- package/dist-host/superagent/types.js +8 -0
- package/dist-worker/agent-loop.js +449 -7
- package/dist-worker/baseline-fit.js +66 -0
- package/dist-worker/budget-guard.js +93 -0
- package/dist-worker/ccs.js +99 -0
- package/dist-worker/cost-hooks.js +115 -0
- package/dist-worker/cost-modules.js +330 -0
- package/dist-worker/cost-spi.js +3 -0
- package/dist-worker/edg.js +372 -0
- package/dist-worker/gdr.js +159 -0
- package/dist-worker/index.js +80 -2
- package/dist-worker/llm-http.js +20 -0
- package/dist-worker/sink-http.js +1 -0
- package/dist-worker/spill.js +115 -0
- package/dist-worker/tool-batch.js +66 -0
- package/dist-worker/tool-compact.js +275 -0
- package/dist-worker/tool-disclosure.js +90 -0
- package/dist-worker/tools.js +16 -0
- package/docs/ARCHITECTURE.md +21 -0
- package/docs/CHANGELOG.md +50 -0
- package/docs/DESIGN-v3.3.0-cost-optimization.md +1053 -0
- package/docs/EXPERIMENT-M5-real-ab.md +82 -0
- package/docs/THIRD-PARTY.md +87 -0
- package/package.json +1 -1
- package/src/cost/attribution.ts +186 -0
- package/src/cost/audit.ts +170 -0
- package/src/cost/budget.ts +226 -0
- package/src/cost/bus.ts +97 -0
- package/src/cost/cert-chain.ts +102 -0
- package/src/cost/experiment.ts +136 -0
- package/src/cost/gate.ts +191 -0
- package/src/cost/host-surface.ts +97 -0
- package/src/cost/index.ts +316 -0
- package/src/cost/ledger-report.ts +186 -0
- package/src/cost/ledger.ts +385 -0
- package/src/cost/metrics.ts +193 -0
- package/src/cost/milestones.ts +170 -0
- package/src/cost/modules/index.ts +13 -0
- package/src/cost/modules/manifests.ts +129 -0
- package/src/cost/policy.ts +276 -0
- package/src/cost/report.ts +158 -0
- package/src/cost/reuse-report.ts +131 -0
- package/src/cost/rsi.ts +364 -0
- package/src/cost/toolface.ts +151 -0
- package/src/cost/types.ts +298 -0
- package/src/kernel.ts +27 -2
- package/src/plugins/cost-optimizer.ts +271 -26
- package/src/plugins/superagent-router.ts +82 -1
- package/src/superagent/types.ts +70 -0
- package/worker/agent-loop.ts +444 -7
- package/worker/baseline-fit.ts +80 -0
- package/worker/budget-guard.ts +156 -0
- package/worker/ccs.ts +202 -0
- package/worker/cost-hooks.ts +133 -0
- package/worker/cost-modules.ts +356 -0
- package/worker/cost-spi.ts +283 -0
- package/worker/edg.ts +424 -0
- package/worker/gdr.ts +233 -0
- package/worker/index.ts +84 -3
- package/worker/llm-http.ts +18 -0
- package/worker/sink-http.ts +5 -2
- package/worker/spill.ts +133 -0
- package/worker/tool-batch.ts +124 -0
- package/worker/tool-compact.ts +317 -0
- package/worker/tool-disclosure.ts +131 -0
- package/worker/tools.ts +553 -531
- package/worker/types.ts +191 -0
|
@@ -27,6 +27,8 @@ const EVENTS_PATH = '/dsh-master/api/superagent/worker-events';
|
|
|
27
27
|
const STREAM_PATH = '/dsh-master/api/superagent/stream';
|
|
28
28
|
const STREAM_TOKEN_PATH = '/dsh-master/api/superagent/stream-token';
|
|
29
29
|
const STATUS_PATH = '/dsh-master/api/superagent/status';
|
|
30
|
+
/** §5.6:成本事件摘要(状态页 / 分身信息栏读取)。 */
|
|
31
|
+
const COST_PATH = '/dsh-master/api/superagent/cost';
|
|
30
32
|
const SESSION_PATH = '/dsh-master/api/superagent/session';
|
|
31
33
|
const PR_PATH = '/dsh-master/api/superagent/pr';
|
|
32
34
|
const GITHUB_PATH = '/dsh-master/api/superagent/github';
|
|
@@ -275,6 +277,79 @@ export function apply(ctx, config = {}) {
|
|
|
275
277
|
if (token)
|
|
276
278
|
tokenManager.revoke(token, 'ticket-done');
|
|
277
279
|
};
|
|
280
|
+
/**
|
|
281
|
+
* §5.6:把 Worker 上报的 `cost` 事件按 ticket 汇成只读摘要,
|
|
282
|
+
* 供状态页与「分身信息栏」读取(不暴露任何 token)。
|
|
283
|
+
*/
|
|
284
|
+
const costSummary = (ticketId) => {
|
|
285
|
+
const id = ticketId === undefined ? null : String(ticketId);
|
|
286
|
+
// §11:只读成本块的数据源——系统层 savings 两列(A 单价 / B 跳过调用)+ 命中率。
|
|
287
|
+
const serviceBlock = (() => {
|
|
288
|
+
try {
|
|
289
|
+
const cost = safeGet(ctx, SERVICE.cost);
|
|
290
|
+
if (!cost)
|
|
291
|
+
return null;
|
|
292
|
+
const status = typeof cost.status === 'function' ? cost.status() : null;
|
|
293
|
+
const report = typeof cost.savingsReport === 'function' ? cost.savingsReport({ amortize: 'even', limit: 2000 }) : null;
|
|
294
|
+
return {
|
|
295
|
+
savings: status?.savings ?? null,
|
|
296
|
+
columns: status?.savingsColumns ?? null,
|
|
297
|
+
policy: status?.policy ?? null,
|
|
298
|
+
ledger: status?.ledger?.entries !== undefined ? { entries: status.ledger.entries } : null,
|
|
299
|
+
unitPriceSaved: report?.columns?.unitPrice?.savedTokens ?? 0,
|
|
300
|
+
skippedCallSaved: report?.columns?.skippedCalls?.savedTokens ?? 0,
|
|
301
|
+
skippedCalls: report?.columns?.skippedCalls?.calls ?? 0,
|
|
302
|
+
netLossTasks: report?.netLossTasks?.map((task) => task.taskId) ?? [],
|
|
303
|
+
doubleCountGuard: report?.doubleCountGuard === true,
|
|
304
|
+
/** 守卫命中率需要各任务上报的 guard 统计聚合;未聚合前如实给 null,不猜。 */
|
|
305
|
+
hitRate: null,
|
|
306
|
+
};
|
|
307
|
+
}
|
|
308
|
+
catch {
|
|
309
|
+
return null;
|
|
310
|
+
}
|
|
311
|
+
})();
|
|
312
|
+
const tickets = id === null ? [...workerEvents.keys()] : [id];
|
|
313
|
+
const rows = [];
|
|
314
|
+
const totals = { events: 0, degraded: 0, substitutions: 0, estimated: 0, savedTokens: 0 };
|
|
315
|
+
for (const key of tickets) {
|
|
316
|
+
const events = (workerEvents.get(key) ?? []).filter((event) => event && event.type === 'cost');
|
|
317
|
+
if (events.length === 0)
|
|
318
|
+
continue;
|
|
319
|
+
const row = { ticketId: key, events: 0, degraded: 0, substitutions: 0, estimated: 0, savedTokens: 0, points: {}, modules: {} };
|
|
320
|
+
for (const event of events) {
|
|
321
|
+
const payload = event.payload ?? {};
|
|
322
|
+
row.events += 1;
|
|
323
|
+
row.points[String(payload.point ?? 'unknown')] = (row.points[String(payload.point ?? 'unknown')] ?? 0) + 1;
|
|
324
|
+
if (payload.point === 'degraded')
|
|
325
|
+
row.degraded += 1;
|
|
326
|
+
if (payload.estimated === true)
|
|
327
|
+
row.estimated += 1;
|
|
328
|
+
const compaction = payload.compaction;
|
|
329
|
+
if (compaction && compaction.applied === true) {
|
|
330
|
+
row.savedTokens += Math.max(0, Number(compaction.estimatedTokens ?? 0) || 0);
|
|
331
|
+
const moduleKey = String(compaction.module ?? 'a1-compact');
|
|
332
|
+
row.modules[moduleKey] = (row.modules[moduleKey] ?? 0) + Math.max(0, Number(compaction.estimatedTokens ?? 0) || 0);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
totals.events += row.events;
|
|
336
|
+
totals.degraded += row.degraded;
|
|
337
|
+
totals.substitutions += row.substitutions;
|
|
338
|
+
totals.estimated += row.estimated;
|
|
339
|
+
totals.savedTokens += row.savedTokens;
|
|
340
|
+
rows.push(row);
|
|
341
|
+
}
|
|
342
|
+
return {
|
|
343
|
+
ok: true,
|
|
344
|
+
ticketId: id,
|
|
345
|
+
tickets: rows,
|
|
346
|
+
totals,
|
|
347
|
+
/* §11:只读成本块(A 单价项 / B 跳过调用项分列 + 命中率),面板只读消费。 */
|
|
348
|
+
service: serviceBlock,
|
|
349
|
+
/* §5.6:瓮城「产物回流」尚未就绪 —— 显式 unavailable,不假装成功、不阻塞主线。 */
|
|
350
|
+
relay: { target: 'fang', available: false, reason: 'fang-channel-not-ready' },
|
|
351
|
+
};
|
|
352
|
+
};
|
|
278
353
|
const service = {
|
|
279
354
|
id: 'superagent-router',
|
|
280
355
|
version: '3.2.5',
|
|
@@ -284,6 +359,8 @@ export function apply(ctx, config = {}) {
|
|
|
284
359
|
forkerService: hasForker(),
|
|
285
360
|
streaming: { configured: Boolean(origin), ...broadcaster.describe(), tokens: tokenManager.counts() },
|
|
286
361
|
workerEvents: Object.fromEntries([...workerEvents.entries()].map(([k, v]) => [k, v.length])),
|
|
362
|
+
cost: costSummary().totals,
|
|
363
|
+
costRelay: costSummary().relay,
|
|
287
364
|
writeback: writeback.describe(),
|
|
288
365
|
quota: quotaStatus(),
|
|
289
366
|
sessions: { count: sessionMap.size, last: [...sessionMap.values()].slice(-3) },
|
|
@@ -301,6 +378,8 @@ export function apply(ctx, config = {}) {
|
|
|
301
378
|
workerEvents(ticketId) {
|
|
302
379
|
return { ok: true, ticketId: String(ticketId ?? ''), events: workerEvents.get(String(ticketId ?? '')) ?? [] };
|
|
303
380
|
},
|
|
381
|
+
/** §5.6:成本事件摘要(状态页/分身信息栏的数据源)。 */
|
|
382
|
+
cost(ticketId) { return costSummary(ticketId); },
|
|
304
383
|
tokenAudit(limit) { return tokenManager.audit(limit); },
|
|
305
384
|
rotateStreamToken(oldToken = '') { return tokenManager.rotate(oldToken, { kind: 'ui' }); },
|
|
306
385
|
quota: () => quotaStatus(),
|
|
@@ -459,6 +538,14 @@ export function apply(ctx, config = {}) {
|
|
|
459
538
|
return jsonResponse(res, 200, { ok: true, session: mapped });
|
|
460
539
|
},
|
|
461
540
|
});
|
|
541
|
+
register({
|
|
542
|
+
kind: 'exact', path: COST_PATH, method: 'GET',
|
|
543
|
+
handler: async (req, res) => {
|
|
544
|
+
const query = new URL(String(req?.url ?? '/'), 'http://x').searchParams;
|
|
545
|
+
const ticketId = query.get('ticketId');
|
|
546
|
+
return jsonResponse(res, 200, service.cost(ticketId === null ? undefined : String(ticketId)));
|
|
547
|
+
},
|
|
548
|
+
});
|
|
462
549
|
register({
|
|
463
550
|
kind: 'exact', path: GITHUB_PATH, method: 'POST',
|
|
464
551
|
handler: async (req, res) => {
|
|
@@ -496,4 +583,4 @@ export function apply(ctx, config = {}) {
|
|
|
496
583
|
catch { /* 无 webServer 时仍可通过服务调用 ingest */ }
|
|
497
584
|
return service;
|
|
498
585
|
}
|
|
499
|
-
export { EVENTS_PATH, STREAM_PATH, STREAM_TOKEN_PATH, STATUS_PATH, SESSION_PATH, readRawBody };
|
|
586
|
+
export { EVENTS_PATH, STREAM_PATH, STREAM_TOKEN_PATH, STATUS_PATH, SESSION_PATH, COST_PATH, readRawBody };
|
|
@@ -142,3 +142,11 @@ export function publicTicket(ticket, extra = {}) {
|
|
|
142
142
|
...extra,
|
|
143
143
|
};
|
|
144
144
|
}
|
|
145
|
+
/* ------------------------------------------------------------------ *
|
|
146
|
+
* 3.3.0 §11:成本域对外类型(宿主侧)
|
|
147
|
+
*
|
|
148
|
+
* 这些是**跨进程/跨插件边界的形状**:Worker 侧同名类型在 worker/*.ts,
|
|
149
|
+
* 宿主侧以本文件为准。字段名保持一致,便于证书与事件在两侧无损传递。
|
|
150
|
+
* ------------------------------------------------------------------ */
|
|
151
|
+
/** 成本事件类型(§5.6 事件总线)。 */
|
|
152
|
+
export const COST_EVENT_TYPE = Object.freeze(['cost:event', 'cost:degraded', 'cost:substitution']);
|