@twinsearth/dsh-master 3.2.10 → 3.3.1
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 +4 -0
- package/client.js +50 -0
- package/dist-host/contract/client.js +7 -0
- package/dist-host/contract/constants.js +16 -2
- package/dist-host/contract/index.js +1 -0
- package/dist-host/contract/relay.js +239 -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/fang-relay.js +329 -0
- package/dist-host/cost/gate.js +189 -0
- package/dist-host/cost/host-surface.js +80 -0
- package/dist-host/cost/index.js +345 -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 +209 -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 +329 -27
- package/dist-host/plugins/superagent-router.js +104 -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 +24 -0
- package/docs/CHANGELOG.md +66 -0
- package/docs/DESIGN-v3.3.0-cost-optimization.md +1058 -0
- package/docs/EXPERIMENT-M5-fang-relay.md +117 -0
- package/docs/EXPERIMENT-M5-real-ab.md +87 -0
- package/docs/THIRD-PARTY.md +87 -0
- package/package.json +2 -2
- package/src/contract/client.js +7 -0
- package/src/contract/constants.js +17 -2
- package/src/contract/index.js +1 -0
- package/src/contract/relay.js +223 -0
- 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/fang-relay.ts +318 -0
- package/src/cost/gate.ts +191 -0
- package/src/cost/host-surface.ts +97 -0
- package/src/cost/index.ts +348 -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 +206 -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 +313 -26
- package/src/plugins/superagent-router.ts +96 -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,95 @@ 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
|
+
/**
|
|
314
|
+
* §5.6 / M5:回流出口状态来自成本服务(3.3.1 起是真实探测,不再是硬编码)。
|
|
315
|
+
* 没有成本服务时如实给 `cost-service-unavailable`,不编造“未就绪”原因。
|
|
316
|
+
*/
|
|
317
|
+
const relayBlock = (() => {
|
|
318
|
+
try {
|
|
319
|
+
const cost = safeGet(ctx, SERVICE.cost);
|
|
320
|
+
if (cost && typeof cost.relayStatus === 'function') {
|
|
321
|
+
const relay = cost.relayStatus();
|
|
322
|
+
if (relay && typeof relay === 'object')
|
|
323
|
+
return relay;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
catch { /* 回流状态读取失败不阻塞成本摘要 */ }
|
|
327
|
+
return { target: 'fang', available: false, reason: 'cost-service-unavailable' };
|
|
328
|
+
})();
|
|
329
|
+
const rows = [];
|
|
330
|
+
const totals = { events: 0, degraded: 0, substitutions: 0, estimated: 0, savedTokens: 0 };
|
|
331
|
+
for (const key of tickets) {
|
|
332
|
+
const events = (workerEvents.get(key) ?? []).filter((event) => event && event.type === 'cost');
|
|
333
|
+
if (events.length === 0)
|
|
334
|
+
continue;
|
|
335
|
+
const row = { ticketId: key, events: 0, degraded: 0, substitutions: 0, estimated: 0, savedTokens: 0, points: {}, modules: {} };
|
|
336
|
+
for (const event of events) {
|
|
337
|
+
const payload = event.payload ?? {};
|
|
338
|
+
row.events += 1;
|
|
339
|
+
row.points[String(payload.point ?? 'unknown')] = (row.points[String(payload.point ?? 'unknown')] ?? 0) + 1;
|
|
340
|
+
if (payload.point === 'degraded')
|
|
341
|
+
row.degraded += 1;
|
|
342
|
+
if (payload.estimated === true)
|
|
343
|
+
row.estimated += 1;
|
|
344
|
+
const compaction = payload.compaction;
|
|
345
|
+
if (compaction && compaction.applied === true) {
|
|
346
|
+
row.savedTokens += Math.max(0, Number(compaction.estimatedTokens ?? 0) || 0);
|
|
347
|
+
const moduleKey = String(compaction.module ?? 'a1-compact');
|
|
348
|
+
row.modules[moduleKey] = (row.modules[moduleKey] ?? 0) + Math.max(0, Number(compaction.estimatedTokens ?? 0) || 0);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
totals.events += row.events;
|
|
352
|
+
totals.degraded += row.degraded;
|
|
353
|
+
totals.substitutions += row.substitutions;
|
|
354
|
+
totals.estimated += row.estimated;
|
|
355
|
+
totals.savedTokens += row.savedTokens;
|
|
356
|
+
rows.push(row);
|
|
357
|
+
}
|
|
358
|
+
return {
|
|
359
|
+
ok: true,
|
|
360
|
+
ticketId: id,
|
|
361
|
+
tickets: rows,
|
|
362
|
+
totals,
|
|
363
|
+
/* §11:只读成本块(A 单价项 / B 跳过调用项分列 + 命中率),面板只读消费。 */
|
|
364
|
+
service: serviceBlock,
|
|
365
|
+
/* §5.6 / M5:瓮城回流出口真实状态(不可用必须显式带原因)。 */
|
|
366
|
+
relay: relayBlock,
|
|
367
|
+
};
|
|
368
|
+
};
|
|
278
369
|
const service = {
|
|
279
370
|
id: 'superagent-router',
|
|
280
371
|
version: '3.2.5',
|
|
@@ -284,6 +375,8 @@ export function apply(ctx, config = {}) {
|
|
|
284
375
|
forkerService: hasForker(),
|
|
285
376
|
streaming: { configured: Boolean(origin), ...broadcaster.describe(), tokens: tokenManager.counts() },
|
|
286
377
|
workerEvents: Object.fromEntries([...workerEvents.entries()].map(([k, v]) => [k, v.length])),
|
|
378
|
+
cost: costSummary().totals,
|
|
379
|
+
costRelay: costSummary().relay,
|
|
287
380
|
writeback: writeback.describe(),
|
|
288
381
|
quota: quotaStatus(),
|
|
289
382
|
sessions: { count: sessionMap.size, last: [...sessionMap.values()].slice(-3) },
|
|
@@ -301,6 +394,8 @@ export function apply(ctx, config = {}) {
|
|
|
301
394
|
workerEvents(ticketId) {
|
|
302
395
|
return { ok: true, ticketId: String(ticketId ?? ''), events: workerEvents.get(String(ticketId ?? '')) ?? [] };
|
|
303
396
|
},
|
|
397
|
+
/** §5.6:成本事件摘要(状态页/分身信息栏的数据源)。 */
|
|
398
|
+
cost(ticketId) { return costSummary(ticketId); },
|
|
304
399
|
tokenAudit(limit) { return tokenManager.audit(limit); },
|
|
305
400
|
rotateStreamToken(oldToken = '') { return tokenManager.rotate(oldToken, { kind: 'ui' }); },
|
|
306
401
|
quota: () => quotaStatus(),
|
|
@@ -459,6 +554,14 @@ export function apply(ctx, config = {}) {
|
|
|
459
554
|
return jsonResponse(res, 200, { ok: true, session: mapped });
|
|
460
555
|
},
|
|
461
556
|
});
|
|
557
|
+
register({
|
|
558
|
+
kind: 'exact', path: COST_PATH, method: 'GET',
|
|
559
|
+
handler: async (req, res) => {
|
|
560
|
+
const query = new URL(String(req?.url ?? '/'), 'http://x').searchParams;
|
|
561
|
+
const ticketId = query.get('ticketId');
|
|
562
|
+
return jsonResponse(res, 200, service.cost(ticketId === null ? undefined : String(ticketId)));
|
|
563
|
+
},
|
|
564
|
+
});
|
|
462
565
|
register({
|
|
463
566
|
kind: 'exact', path: GITHUB_PATH, method: 'POST',
|
|
464
567
|
handler: async (req, res) => {
|
|
@@ -496,4 +599,4 @@ export function apply(ctx, config = {}) {
|
|
|
496
599
|
catch { /* 无 webServer 时仍可通过服务调用 ingest */ }
|
|
497
600
|
return service;
|
|
498
601
|
}
|
|
499
|
-
export { EVENTS_PATH, STREAM_PATH, STREAM_TOKEN_PATH, STATUS_PATH, SESSION_PATH, readRawBody };
|
|
602
|
+
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']);
|