dsh-context-compression-improved 0.5.1 → 0.5.3
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/.gitattributes +1 -0
- package/CHANGELOG.ja.md +144 -83
- package/CHANGELOG.ko.md +143 -82
- package/CHANGELOG.md +278 -212
- package/CHANGELOG.zh.md +131 -77
- package/docs/installation.md +103 -103
- package/docs/installation.zh.md +100 -100
- package/package.json +1 -1
- package/packages/selector/cordis.patch.yml +5 -6
- package/packages/selector/lib/advisor-state.js +4 -231
- package/packages/selector/lib/client.d.ts +0 -24
- package/packages/selector/lib/client.js +6 -501
- package/packages/selector/lib/index.d.ts +4 -10
- package/packages/selector/lib/index.js +16 -234
- package/packages/selector/lib/pruner.d.ts +13 -248
- package/packages/selector/lib/pruner.js +148 -552
- package/packages/selector/src/client/EstimatorControls.tsx +0 -101
- package/packages/selector/src/client/index.ts +0 -17
- package/packages/selector/src/client/locales.ts +0 -38
- package/packages/selector/src/client/preset-options.ts +3 -2
- package/packages/selector/src/client/settings-section.tsx +8 -17
- package/packages/selector/src/index.ts +24 -271
- package/packages/selector/src/profiles.ts +4 -27
- package/packages/selector/src/pruner/state.ts +2 -25
- package/packages/selector/src/pruner.ts +75 -403
- package/packages/selector/src/runtime/audit.ts +27 -21
- package/packages/selector/src/runtime/config.ts +6 -32
- package/packages/selector/src/runtime/tokenpilot/advisor-prompt.ts +188 -188
- package/packages/selector/src/runtime/tokenpilot/advisor-state.ts +149 -133
- package/packages/selector/src/runtime/tokenpilot/advisor.ts +419 -419
- package/packages/selector/src/runtime/tokenpilot/benefit.ts +200 -0
- package/packages/selector/src/runtime/types.ts +0 -17
- package/packages/selector/tests/advisor-report.host.spec.ts +223 -223
- package/packages/selector/tests/preset-options-write.client.spec.ts +7 -23
- package/packages/selector/tests/public/package-contract.client.spec.ts +20 -0
- package/packages/selector/tests/runtime/advice-never-withholds.host.spec.ts +232 -0
- package/packages/selector/tests/runtime/advisor-invariant.spec.ts +272 -272
- package/packages/selector/tests/runtime/advisor.spec.ts +226 -226
- package/packages/selector/tests/runtime/audit.spec.ts +35 -21
- package/packages/selector/tests/runtime/char-basis.spec.ts +30 -30
- package/packages/selector/tests/runtime/deprecated-preset-options.spec.ts +96 -0
- package/packages/selector/tests/runtime/tokenpilot/benefit.spec.ts +217 -0
- package/packages/selector/tests/runtime/tokenpilot/profile-baseline.spec.ts +4 -5
- package/packages/selector/tests/settings-seat.client.spec.ts +45 -14
- package/scripts/toolclass-corpus-replay.mjs +281 -281
- package/packages/selector/src/client/ReviewOverlay.tsx +0 -320
- package/packages/selector/src/client/review-scope.ts +0 -16
- package/packages/selector/src/runtime/tokenpilot/proposal.ts +0 -267
- package/packages/selector/src/runtime/tokenpilot/review-queue.ts +0 -231
- package/packages/selector/src/runtime/tokenpilot/review-registry.ts +0 -117
- package/packages/selector/src/runtime/tokenpilot/review-storage.ts +0 -122
- package/packages/selector/tests/review-overlay.client.spec.tsx +0 -118
- package/packages/selector/tests/review-routes-registry.host.spec.ts +0 -142
- package/packages/selector/tests/review-routes.host.spec.ts +0 -290
- package/packages/selector/tests/runtime/tokenpilot/proposal.spec.ts +0 -393
- package/packages/selector/tests/runtime/tokenpilot/pruner-review.spec.ts +0 -382
- package/packages/selector/tests/runtime/tokenpilot/review-queue.spec.ts +0 -168
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { o as CONTEXT_COMPRESSION_SETTINGS_NAMESPACE, s as ContextCompressionSettingsSchema, t as getAdvisorState } from "./advisor-state.js";
|
|
2
2
|
import z from "@deepseek-ai/schemastery";
|
|
3
3
|
import "@deepseek-ai/dsh-settings";
|
|
4
4
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
@@ -505,28 +505,12 @@ function restoreMethod(presets, snapshot) {
|
|
|
505
505
|
//#region src/index.ts
|
|
506
506
|
const CONTEXT_COMPRESSION_NAMESPACE = CONTEXT_COMPRESSION_SETTINGS_NAMESPACE;
|
|
507
507
|
const ESTIMATOR_CATALOG_ROUTES = ["/endpoint/dsh-context-compression-improved/estimator-catalog", "/api/dsh-context-compression-improved/estimator-catalog"];
|
|
508
|
-
const REVIEW_QUEUE_ROUTES = ["/endpoint/dsh-context-compression-improved/review-queue", "/api/dsh-context-compression-improved/review-queue"];
|
|
509
|
-
const REVIEW_DECIDE_ROUTES = ["/endpoint/dsh-context-compression-improved/review-decide", "/api/dsh-context-compression-improved/review-decide"];
|
|
510
508
|
const ADVISOR_REPORT_ROUTES = ["/endpoint/dsh-context-compression-improved/advisor-report", "/api/dsh-context-compression-improved/advisor-report"];
|
|
511
|
-
/**
|
|
512
|
-
* Resolve the review pipeline for the top-level routes.
|
|
513
|
-
*
|
|
514
|
-
* A top-level `toolResultPruner` service wins when a deployment actually mounts
|
|
515
|
-
* one, but in production every pruner lives inside an agent preset's isolated
|
|
516
|
-
* group, so the registry is the path that resolves. Without the fallback the
|
|
517
|
-
* queue route answered 503 "review pipeline unavailable" on every request while
|
|
518
|
-
* the review pipeline itself was running normally.
|
|
519
|
-
*/
|
|
520
|
-
function reviewPrunerOf(readService) {
|
|
521
|
-
const candidate = readService("toolResultPruner");
|
|
522
|
-
if (typeof candidate?.listReviewProposals === "function" && typeof candidate?.decideReviewProposal === "function") return candidate;
|
|
523
|
-
return resolveReviewPruner();
|
|
524
|
-
}
|
|
525
509
|
function sessionFor(readService, sessionId) {
|
|
526
510
|
const agents = readService("agents");
|
|
527
511
|
return typeof agents?.get === "function" ? agents.get(sessionId)?.session : void 0;
|
|
528
512
|
}
|
|
529
|
-
function
|
|
513
|
+
function jsonResponse(res, status, body) {
|
|
530
514
|
const resTyped = res;
|
|
531
515
|
resTyped.writeHead(status, {
|
|
532
516
|
"content-type": "application/json; charset=utf-8",
|
|
@@ -534,217 +518,9 @@ function reviewJson(res, status, body) {
|
|
|
534
518
|
});
|
|
535
519
|
resTyped.end(JSON.stringify(body));
|
|
536
520
|
}
|
|
537
|
-
function readRequestBody(req) {
|
|
538
|
-
return new Promise((resolve, reject) => {
|
|
539
|
-
const typed = req;
|
|
540
|
-
let data = "";
|
|
541
|
-
try {
|
|
542
|
-
typed.on?.("data", (chunk) => {
|
|
543
|
-
data += String(chunk ?? "");
|
|
544
|
-
if (data.length > 65536) {
|
|
545
|
-
data = "";
|
|
546
|
-
resolve("");
|
|
547
|
-
}
|
|
548
|
-
});
|
|
549
|
-
typed.on?.("end", () => resolve(data));
|
|
550
|
-
typed.on?.("error", reject);
|
|
551
|
-
} catch (error) {
|
|
552
|
-
reject(error instanceof Error ? error : new Error(String(error)));
|
|
553
|
-
}
|
|
554
|
-
});
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Serve the review pipeline's two HTTP routes (best effort, mirroring the
|
|
558
|
-
* estimator-catalog registration):
|
|
559
|
-
*
|
|
560
|
-
* - `GET .../review-queue?sessionId=…` → the session's pending proposals with
|
|
561
|
-
* their benefit numbers. Sanitized by construction: the queue never holds
|
|
562
|
-
* message content, and the response carries ids/seqs/counts only (digests
|
|
563
|
-
* stay in the runtime — the client cannot need them).
|
|
564
|
-
* - `POST .../review-decide` `{sessionId, proposalId, decision}` → one human
|
|
565
|
-
* decision. Invalid body → 400; unknown/not-pending proposal → 404; review
|
|
566
|
-
* mode off for the session → 503.
|
|
567
|
-
*/
|
|
568
|
-
function registerReviewQueueRoutes(ctx) {
|
|
569
|
-
const readService = (name) => {
|
|
570
|
-
try {
|
|
571
|
-
return ctx.get(name);
|
|
572
|
-
} catch {
|
|
573
|
-
return;
|
|
574
|
-
}
|
|
575
|
-
};
|
|
576
|
-
const log = (level, message, ...args) => {
|
|
577
|
-
console[level](message, ...args);
|
|
578
|
-
};
|
|
579
|
-
const registered = () => {
|
|
580
|
-
log("info", "context-compression review queue routes registered: %s / %s", REVIEW_QUEUE_ROUTES.join(", "), REVIEW_DECIDE_ROUTES.join(", "));
|
|
581
|
-
};
|
|
582
|
-
const getHandler = (req, res) => {
|
|
583
|
-
const pruner = reviewPrunerOf(readService);
|
|
584
|
-
if (pruner === void 0 || pruner.listAllReviewProposals === void 0) {
|
|
585
|
-
reviewJson(res, 503, {
|
|
586
|
-
ok: false,
|
|
587
|
-
error: "review pipeline unavailable"
|
|
588
|
-
});
|
|
589
|
-
return;
|
|
590
|
-
}
|
|
591
|
-
let sessionId = "";
|
|
592
|
-
try {
|
|
593
|
-
sessionId = new URL(String(req.url ?? ""), "http://localhost").searchParams.get("sessionId") ?? "";
|
|
594
|
-
} catch {
|
|
595
|
-
sessionId = "";
|
|
596
|
-
}
|
|
597
|
-
const sanitize = (sid, proposal) => ({
|
|
598
|
-
sessionId: sid,
|
|
599
|
-
id: proposal.id,
|
|
600
|
-
kind: proposal.kind,
|
|
601
|
-
items: proposal.items.map((item) => ({
|
|
602
|
-
seq: item.seq,
|
|
603
|
-
kind: item.kind,
|
|
604
|
-
component: item.component,
|
|
605
|
-
tokensBefore: item.tokensBefore,
|
|
606
|
-
tokensAfter: item.tokensAfter
|
|
607
|
-
})),
|
|
608
|
-
benefit: {
|
|
609
|
-
recoveredTokens: proposal.benefit.recoveredTokens,
|
|
610
|
-
penaltyTokens: proposal.benefit.penaltyTokens,
|
|
611
|
-
...proposal.benefit.paybackTurns === void 0 ? {} : { paybackTurns: proposal.benefit.paybackTurns },
|
|
612
|
-
...proposal.benefit.expectedSaving === void 0 ? {} : { expectedSaving: proposal.benefit.expectedSaving }
|
|
613
|
-
},
|
|
614
|
-
enqueuedTurn: proposal.enqueuedTurn,
|
|
615
|
-
lastTurnIndex: proposal.lastTurnIndex
|
|
616
|
-
});
|
|
617
|
-
if (sessionId === "") {
|
|
618
|
-
const pending = pruner.listAllReviewProposals().flatMap((entry) => entry.proposals.map((proposal) => sanitize(entry.sessionId, proposal)));
|
|
619
|
-
reviewJson(res, 200, {
|
|
620
|
-
ok: true,
|
|
621
|
-
total: pending.length,
|
|
622
|
-
pending
|
|
623
|
-
});
|
|
624
|
-
return;
|
|
625
|
-
}
|
|
626
|
-
const session = sessionFor(readService, sessionId);
|
|
627
|
-
if (session === void 0) {
|
|
628
|
-
reviewJson(res, 404, {
|
|
629
|
-
ok: false,
|
|
630
|
-
error: "unknown session"
|
|
631
|
-
});
|
|
632
|
-
return;
|
|
633
|
-
}
|
|
634
|
-
const pending = pruner.listReviewProposals(session).map((proposal) => sanitize(sessionId, proposal));
|
|
635
|
-
const summary = pruner.reviewSummary?.(session);
|
|
636
|
-
reviewJson(res, 200, {
|
|
637
|
-
ok: true,
|
|
638
|
-
sessionId,
|
|
639
|
-
total: pending.length,
|
|
640
|
-
pending,
|
|
641
|
-
...summary === void 0 ? {} : { summary }
|
|
642
|
-
});
|
|
643
|
-
};
|
|
644
|
-
const decideHandler = async (req, res) => {
|
|
645
|
-
const pruner = reviewPrunerOf(readService);
|
|
646
|
-
if (pruner === void 0) {
|
|
647
|
-
reviewJson(res, 503, {
|
|
648
|
-
ok: false,
|
|
649
|
-
error: "review pipeline unavailable"
|
|
650
|
-
});
|
|
651
|
-
return;
|
|
652
|
-
}
|
|
653
|
-
let body;
|
|
654
|
-
try {
|
|
655
|
-
body = JSON.parse(await readRequestBody(req));
|
|
656
|
-
} catch {
|
|
657
|
-
body = void 0;
|
|
658
|
-
}
|
|
659
|
-
if (typeof body !== "object" || body === null) {
|
|
660
|
-
reviewJson(res, 400, {
|
|
661
|
-
ok: false,
|
|
662
|
-
error: "invalid JSON body"
|
|
663
|
-
});
|
|
664
|
-
return;
|
|
665
|
-
}
|
|
666
|
-
const record = body;
|
|
667
|
-
if (typeof record.sessionId !== "string" || record.sessionId === "" || typeof record.proposalId !== "string" || record.proposalId === "") {
|
|
668
|
-
reviewJson(res, 400, {
|
|
669
|
-
ok: false,
|
|
670
|
-
error: "sessionId and proposalId are required"
|
|
671
|
-
});
|
|
672
|
-
return;
|
|
673
|
-
}
|
|
674
|
-
if (record.decision !== "approved" && record.decision !== "rejected" && record.decision !== "ignored") {
|
|
675
|
-
reviewJson(res, 400, {
|
|
676
|
-
ok: false,
|
|
677
|
-
error: "decision must be approved, rejected, or ignored"
|
|
678
|
-
});
|
|
679
|
-
return;
|
|
680
|
-
}
|
|
681
|
-
const session = sessionFor(readService, record.sessionId);
|
|
682
|
-
if (session === void 0) {
|
|
683
|
-
reviewJson(res, 404, {
|
|
684
|
-
ok: false,
|
|
685
|
-
error: "unknown session"
|
|
686
|
-
});
|
|
687
|
-
return;
|
|
688
|
-
}
|
|
689
|
-
const outcome = pruner.decideReviewProposal(session, record.proposalId, record.decision);
|
|
690
|
-
if (outcome === void 0) {
|
|
691
|
-
reviewJson(res, 503, {
|
|
692
|
-
ok: false,
|
|
693
|
-
error: "review mode is off for this session"
|
|
694
|
-
});
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if (!outcome.ok) {
|
|
698
|
-
reviewJson(res, 404, {
|
|
699
|
-
ok: false,
|
|
700
|
-
error: outcome.reason
|
|
701
|
-
});
|
|
702
|
-
return;
|
|
703
|
-
}
|
|
704
|
-
reviewJson(res, 200, {
|
|
705
|
-
ok: true,
|
|
706
|
-
sessionId: record.sessionId,
|
|
707
|
-
proposalId: record.proposalId,
|
|
708
|
-
decision: record.decision
|
|
709
|
-
});
|
|
710
|
-
};
|
|
711
|
-
const register = (webServer) => {
|
|
712
|
-
const disposers = [...[...REVIEW_QUEUE_ROUTES].map((path) => ({
|
|
713
|
-
path,
|
|
714
|
-
handler: getHandler
|
|
715
|
-
})), ...[...REVIEW_DECIDE_ROUTES].map((path) => ({
|
|
716
|
-
path,
|
|
717
|
-
handler: (req, res) => {
|
|
718
|
-
decideHandler(req, res);
|
|
719
|
-
}
|
|
720
|
-
}))].map((entry) => webServer.register({
|
|
721
|
-
kind: "exact",
|
|
722
|
-
path: entry.path,
|
|
723
|
-
handler: entry.handler
|
|
724
|
-
})).filter((off) => typeof off === "function");
|
|
725
|
-
ctx.effect(() => () => {
|
|
726
|
-
for (const off of disposers) off();
|
|
727
|
-
}, "contextCompressionSelector.review routes");
|
|
728
|
-
registered();
|
|
729
|
-
};
|
|
730
|
-
const active = asWebServer(readService("webServer"));
|
|
731
|
-
if (active !== void 0) {
|
|
732
|
-
register(active);
|
|
733
|
-
return;
|
|
734
|
-
}
|
|
735
|
-
ctx.inject(["webServer"], (injected) => {
|
|
736
|
-
const webServer = asWebServer(injected.webServer);
|
|
737
|
-
if (webServer === void 0) {
|
|
738
|
-
log("warn", "context-compression webServer exposes no register() — review routes not registered");
|
|
739
|
-
return;
|
|
740
|
-
}
|
|
741
|
-
register(webServer);
|
|
742
|
-
});
|
|
743
|
-
log("warn", "context-compression webServer not active yet — review routes pending: %s", REVIEW_QUEUE_ROUTES.join(", "));
|
|
744
|
-
}
|
|
745
521
|
/**
|
|
746
522
|
* Serve the advisory advisor's read-only report route (same registration
|
|
747
|
-
* skeleton as the
|
|
523
|
+
* skeleton as the estimator-catalog route):
|
|
748
524
|
*
|
|
749
525
|
* `GET .../advisor-report?sessionId=…` → the session's prefix-decay figure,
|
|
750
526
|
* the todolist-bound task summary, and the score distribution. Content-free
|
|
@@ -766,7 +542,7 @@ function registerAdvisorReportRoute(ctx) {
|
|
|
766
542
|
};
|
|
767
543
|
const getHandler = (req, res) => {
|
|
768
544
|
if (typeof readService("agents")?.get !== "function") {
|
|
769
|
-
|
|
545
|
+
jsonResponse(res, 503, {
|
|
770
546
|
ok: false,
|
|
771
547
|
error: "advisor report unavailable"
|
|
772
548
|
});
|
|
@@ -777,7 +553,7 @@ function registerAdvisorReportRoute(ctx) {
|
|
|
777
553
|
sessionId = new URL(String(req.url ?? ""), "http://localhost").searchParams.get("sessionId") ?? "";
|
|
778
554
|
} catch {}
|
|
779
555
|
if (sessionId === "") {
|
|
780
|
-
|
|
556
|
+
jsonResponse(res, 400, {
|
|
781
557
|
ok: false,
|
|
782
558
|
error: "sessionId is required"
|
|
783
559
|
});
|
|
@@ -785,14 +561,14 @@ function registerAdvisorReportRoute(ctx) {
|
|
|
785
561
|
}
|
|
786
562
|
const session = sessionFor(readService, sessionId);
|
|
787
563
|
if (session === void 0) {
|
|
788
|
-
|
|
564
|
+
jsonResponse(res, 404, {
|
|
789
565
|
ok: false,
|
|
790
566
|
error: "unknown session"
|
|
791
567
|
});
|
|
792
568
|
return;
|
|
793
569
|
}
|
|
794
570
|
const state = getAdvisorState(session);
|
|
795
|
-
|
|
571
|
+
jsonResponse(res, 200, {
|
|
796
572
|
ok: true,
|
|
797
573
|
sessionId,
|
|
798
574
|
advisor: {
|
|
@@ -805,7 +581,15 @@ function registerAdvisorReportRoute(ctx) {
|
|
|
805
581
|
score: entry.score,
|
|
806
582
|
turn: entry.turn
|
|
807
583
|
})),
|
|
808
|
-
lowRelevanceSeqs: [...state.recertified.keys()]
|
|
584
|
+
lowRelevanceSeqs: [...state.recertified.keys()],
|
|
585
|
+
lastAdvice: state.lastAdvice === void 0 ? null : {
|
|
586
|
+
band: state.lastAdvice.band,
|
|
587
|
+
turn: state.lastAdvice.turn,
|
|
588
|
+
itemSeqs: state.lastAdvice.itemSeqs,
|
|
589
|
+
recoveredTokens: state.lastAdvice.recoveredTokens,
|
|
590
|
+
penaltyTokens: state.lastAdvice.penaltyTokens,
|
|
591
|
+
paybackTurns: state.lastAdvice.paybackTurns ?? null
|
|
592
|
+
}
|
|
809
593
|
}
|
|
810
594
|
});
|
|
811
595
|
};
|
|
@@ -942,7 +726,6 @@ const SHARED_SETTINGS = Symbol.for("dsh-context-compression-improved/settings-re
|
|
|
942
726
|
const Config = z.object({
|
|
943
727
|
presetOverlay: z.boolean().default(false),
|
|
944
728
|
estimatorCatalogRoute: z.boolean().default(false),
|
|
945
|
-
reviewQueueRoute: z.boolean().default(false),
|
|
946
729
|
advisorReportRoute: z.boolean().default(false)
|
|
947
730
|
});
|
|
948
731
|
/** Register the persisted default read by the currently mounted root pruner. */
|
|
@@ -952,7 +735,6 @@ function apply(ctx, config = {}) {
|
|
|
952
735
|
acquireSettingsRegistration(settingsCtx);
|
|
953
736
|
});
|
|
954
737
|
if (config.estimatorCatalogRoute === true) registerEstimatorCatalogRoute(ctx);
|
|
955
|
-
if (config.reviewQueueRoute === true) registerReviewQueueRoutes(ctx);
|
|
956
738
|
if (config.advisorReportRoute === true) registerAdvisorReportRoute(ctx);
|
|
957
739
|
if (config.presetOverlay !== true) return;
|
|
958
740
|
ctx.inject(["agentPresets"], (presetsCtx) => {
|
|
@@ -96,18 +96,6 @@ interface PresetOptions {
|
|
|
96
96
|
readonly sampleLimit: number;
|
|
97
97
|
readonly minTokens: number;
|
|
98
98
|
};
|
|
99
|
-
/**
|
|
100
|
-
* Human-gated review pipeline (beta): edge/high-impact candidates queue for
|
|
101
|
-
* manual approval and execute in one merged batch at the next turn boundary
|
|
102
|
-
* instead of the automatic path (R4).
|
|
103
|
-
*/
|
|
104
|
-
readonly reviewMode: boolean;
|
|
105
|
-
/** Turn-boundary patience: pending review proposals older than this many turns auto-expire (R4). */
|
|
106
|
-
readonly reviewTimeoutTurns: number;
|
|
107
|
-
/** Cache-hit discount rate α in the benefit model; expectedSaving = α·R·Ŝ − (1−α)·tail. */
|
|
108
|
-
readonly cacheHitDiscountAlpha: number;
|
|
109
|
-
/** Candidates whose tokenBefore reaches this threshold bypass payback triage and always enter review (R4). */
|
|
110
|
-
readonly reviewHighImpactTokens: number;
|
|
111
99
|
}
|
|
112
100
|
/** Common user-authored Custom stages shared by persisted policy versions. */
|
|
113
101
|
interface CustomCompressionPolicyFields<HistoryPolicy> {
|
|
@@ -157,11 +145,6 @@ interface PresetOptionsSettings {
|
|
|
157
145
|
readonly prefixStabilizer?: boolean;
|
|
158
146
|
readonly readState?: boolean;
|
|
159
147
|
readonly estimatorMode?: '' | 'host' | 'direct';
|
|
160
|
-
/** Review-mode overrides (beta); see PresetOptions.reviewMode. */
|
|
161
|
-
readonly reviewMode?: boolean;
|
|
162
|
-
readonly reviewTimeoutTurns?: number;
|
|
163
|
-
readonly cacheHitDiscountAlpha?: number;
|
|
164
|
-
readonly reviewHighImpactTokens?: number;
|
|
165
148
|
/**
|
|
166
149
|
* Estimator endpoint fields. Persisted-settings only: they never enter the
|
|
167
150
|
* frozen CompressionPolicy, which is emitted verbatim by policy-resolved
|
|
@@ -414,157 +397,7 @@ interface EstimatorFailures {
|
|
|
414
397
|
cooldownUntil: number;
|
|
415
398
|
}
|
|
416
399
|
//#endregion
|
|
417
|
-
//#region src/runtime/tokenpilot/proposal.d.ts
|
|
418
|
-
interface BenefitEstimate {
|
|
419
|
-
/** Net reclaimed tokens across the batch; may be ≤ 0 when a batch is not worth it. */
|
|
420
|
-
readonly recoveredTokens: number;
|
|
421
|
-
/** The one-time cache-refill penalty the merged mutation pays: (1−α)·tailTokens. */
|
|
422
|
-
readonly penaltyTokens: number;
|
|
423
|
-
/** Turns of discounted recovery needed to recoup the penalty; `undefined` when α·R ≤ 0. */
|
|
424
|
-
readonly paybackTurns?: number;
|
|
425
|
-
/** Discounted net benefit over the remaining session; omitted when Ŝ is unknown. */
|
|
426
|
-
readonly expectedSaving?: number;
|
|
427
|
-
}
|
|
428
|
-
/** Human-facing reduction kind carried by every review proposal. */
|
|
429
|
-
type ProposalKind = 'estimator' | 'dedup' | 'read-state';
|
|
430
|
-
/** One frozen item inside a review proposal: metadata and digest, never content. */
|
|
431
|
-
interface ProposalItem {
|
|
432
|
-
readonly seq: number;
|
|
433
|
-
readonly component: string;
|
|
434
|
-
readonly kind: ProposalKind;
|
|
435
|
-
readonly tokensBefore: number;
|
|
436
|
-
readonly tokensAfter: number;
|
|
437
|
-
/** Content sha-256 frozen at enqueue time and re-checked at the apply point. */
|
|
438
|
-
readonly digest: string;
|
|
439
|
-
}
|
|
440
|
-
/** Proposal fields derivable at classification time; queue fields attach at enqueue. */
|
|
441
|
-
interface ProposalSkeleton {
|
|
442
|
-
readonly id: string;
|
|
443
|
-
readonly kind: ProposalKind;
|
|
444
|
-
readonly items: readonly ProposalItem[];
|
|
445
|
-
readonly benefit: BenefitEstimate;
|
|
446
|
-
}
|
|
447
|
-
//#endregion
|
|
448
|
-
//#region src/runtime/tokenpilot/review-queue.d.ts
|
|
449
|
-
/** Human-side proposal status. */
|
|
450
|
-
type ReviewProposalStatus = 'pending' | 'approved' | 'rejected' | 'ignored' | 'expired';
|
|
451
|
-
/** Execution-side receipt built only from real mutation evidence (never estimated). */
|
|
452
|
-
interface ReviewReceipt {
|
|
453
|
-
readonly status: 'applied' | 'deferred';
|
|
454
|
-
/** Reason code for deferred receipts, aligned with the upstream naming. */
|
|
455
|
-
readonly reasonCode?: string;
|
|
456
|
-
/** Predicted recovery from the benefit model at enqueue time. */
|
|
457
|
-
readonly estimatedTokens: number;
|
|
458
|
-
/** Measured recovery of the landed mutation; present only on applied. */
|
|
459
|
-
readonly appliedTokens?: number;
|
|
460
|
-
/** Canonical ISO timestamp of the execution evidence. */
|
|
461
|
-
readonly updatedAt: string;
|
|
462
|
-
}
|
|
463
|
-
/** One queued proposal: persisted metadata, never content. */
|
|
464
|
-
interface ReviewProposalRecord {
|
|
465
|
-
readonly id: string;
|
|
466
|
-
readonly sessionId: string;
|
|
467
|
-
readonly kind: ProposalKind;
|
|
468
|
-
readonly items: readonly {
|
|
469
|
-
readonly seq: number;
|
|
470
|
-
readonly component: string;
|
|
471
|
-
readonly kind: ProposalKind;
|
|
472
|
-
readonly tokensBefore: number;
|
|
473
|
-
readonly tokensAfter: number;
|
|
474
|
-
readonly digest: string;
|
|
475
|
-
}[];
|
|
476
|
-
readonly benefit: {
|
|
477
|
-
readonly recoveredTokens: number;
|
|
478
|
-
readonly penaltyTokens: number;
|
|
479
|
-
readonly paybackTurns?: number;
|
|
480
|
-
readonly expectedSaving?: number;
|
|
481
|
-
};
|
|
482
|
-
status: ReviewProposalStatus;
|
|
483
|
-
readonly enqueuedTurn: number;
|
|
484
|
-
lastTurnIndex: number;
|
|
485
|
-
}
|
|
486
|
-
/** Whole-session record: one durable KV value per session. */
|
|
487
|
-
interface ReviewSessionRecord {
|
|
488
|
-
readonly version: 1;
|
|
489
|
-
readonly proposals: readonly ReviewProposalRecord[];
|
|
490
|
-
}
|
|
491
|
-
/** A settled proposal: the live record plus its execution receipt. */
|
|
492
|
-
interface ReviewReceiptRecord extends ReviewProposalRecord {
|
|
493
|
-
readonly receipt: ReviewReceipt;
|
|
494
|
-
}
|
|
495
|
-
/** Minimal KV face the queue persists through. */
|
|
496
|
-
interface ReviewQueueStore {
|
|
497
|
-
load(sessionId: string): ReviewSessionRecord | undefined;
|
|
498
|
-
save(sessionId: string, record: ReviewSessionRecord): void;
|
|
499
|
-
/** Session ids with live records; optional (aggregate reads degrade to none). */
|
|
500
|
-
ids?(): readonly string[];
|
|
501
|
-
}
|
|
502
|
-
interface ReviewQueueOptions {
|
|
503
|
-
/** Pending proposals older than this many turns (since lastTurnIndex) expire. */
|
|
504
|
-
readonly timeoutTurns: number;
|
|
505
|
-
}
|
|
506
|
-
/** Decision outcomes for one decide call. */
|
|
507
|
-
type DecideOutcome = {
|
|
508
|
-
readonly ok: true;
|
|
509
|
-
} | {
|
|
510
|
-
readonly ok: false;
|
|
511
|
-
readonly reason: 'unknown-proposal' | 'not-pending';
|
|
512
|
-
};
|
|
513
|
-
declare class ReviewQueue {
|
|
514
|
-
private readonly store;
|
|
515
|
-
private readonly options;
|
|
516
|
-
constructor(store: ReviewQueueStore, options: ReviewQueueOptions);
|
|
517
|
-
/**
|
|
518
|
-
* Fail-open store access: a throwing seam must never break the compression
|
|
519
|
-
* pipeline. Reads degrade to "no stored record"; writes degrade to losing
|
|
520
|
-
* durability for that call (the store itself is expected to warn).
|
|
521
|
-
*/
|
|
522
|
-
private safeLoad;
|
|
523
|
-
private safeSave;
|
|
524
|
-
private sessionRecord;
|
|
525
|
-
/**
|
|
526
|
-
* Queue one classified proposal. A repeated classification of the same
|
|
527
|
-
* content re-does nothing but refresh the patience clock, so re-enqueue
|
|
528
|
-
* cannot duplicate a live proposal.
|
|
529
|
-
* @returns `false` when an identical live proposal already exists.
|
|
530
|
-
*/
|
|
531
|
-
enqueue(sessionId: string, skeleton: ProposalSkeleton, turnIndex: number): boolean;
|
|
532
|
-
/** Live pending proposals of one session, oldest enqueue first. */
|
|
533
|
-
listPending(sessionId: string): readonly ReviewProposalRecord[];
|
|
534
|
-
/** Approved proposals waiting for the next turn-boundary batch. */
|
|
535
|
-
listApproved(sessionId: string): readonly ReviewProposalRecord[];
|
|
536
|
-
/**
|
|
537
|
-
* Transition one pending proposal. Idempotent: deciding an unknown id or a
|
|
538
|
-
* non-pending proposal changes nothing and reports the miss.
|
|
539
|
-
*/
|
|
540
|
-
decide(sessionId: string, id: string, decision: 'approved' | 'rejected' | 'ignored'): DecideOutcome;
|
|
541
|
-
/**
|
|
542
|
-
* Expire every pending proposal whose patience has run out at this turn
|
|
543
|
-
* boundary. Expired proposals are removed from the store (the summary view
|
|
544
|
-
* aggregates them from the audit log instead).
|
|
545
|
-
* @returns the expired proposals, for the caller's audit emission.
|
|
546
|
-
*/
|
|
547
|
-
expireTurn(sessionId: string, turnIndex: number): readonly ReviewProposalRecord[];
|
|
548
|
-
/**
|
|
549
|
-
* Settle an approved proposal with its execution receipt and retire it from
|
|
550
|
-
* the live store. The caller is responsible for auditing the receipt; the
|
|
551
|
-
* queue only records which proposal left and why.
|
|
552
|
-
*/
|
|
553
|
-
recordReceipt(sessionId: string, id: string, receipt: ReviewReceipt): ReviewReceiptRecord | undefined;
|
|
554
|
-
}
|
|
555
|
-
//#endregion
|
|
556
400
|
//#region src/pruner/state.d.ts
|
|
557
|
-
/** Four-state per-session outcome counters behind the floating-window summary row. */
|
|
558
|
-
interface ReviewSessionSummary {
|
|
559
|
-
/** Rewrites that landed through the automatic path while review mode served this session. */
|
|
560
|
-
autoApplied: number;
|
|
561
|
-
/** Approved proposals whose merged batch executed with an applied receipt. */
|
|
562
|
-
reviewApplied: number;
|
|
563
|
-
/** Pending proposals that expired unhandled at a turn boundary. */
|
|
564
|
-
expired: number;
|
|
565
|
-
/** Approved proposals voided at the apply point (digest mismatch et al). */
|
|
566
|
-
voided: number;
|
|
567
|
-
}
|
|
568
401
|
/** Mutable per-session state bag used inside {@link ToolResultPruner}. */
|
|
569
402
|
interface PrunerState {
|
|
570
403
|
/** Resolved immutable deployment configuration. */
|
|
@@ -591,22 +424,12 @@ interface PrunerState {
|
|
|
591
424
|
readonly tailTrimBoundaryAttempts: WeakMap<Session, object>;
|
|
592
425
|
/** Last effective policy audit key emitted for each Session. */
|
|
593
426
|
readonly policyResolutionAudits: WeakMap<Session, string>;
|
|
594
|
-
/**
|
|
595
|
-
|
|
596
|
-
* fail-open fallback; swapped to the storageDomain-backed adapter when (and
|
|
597
|
-
* if) that seam opens successfully.
|
|
598
|
-
*/
|
|
599
|
-
reviewStore: ReviewQueueStore;
|
|
600
|
-
/** Per-session review queue carrying the frozen timeout policy. */
|
|
601
|
-
readonly reviewQueues: WeakMap<Session, ReviewQueue>;
|
|
602
|
-
/** Last observed turn index per Session: the monotonic clock for review expiries. */
|
|
603
|
-
readonly reviewClocks: WeakMap<Session, number>;
|
|
427
|
+
/** Last observed turn index per Session: the monotonic clock for advisory records. */
|
|
428
|
+
readonly turnClocks: WeakMap<Session, number>;
|
|
604
429
|
/** Estimator-reported remaining turns Ŝ per Session; advisory only. */
|
|
605
430
|
readonly estimatorRemainingTurns: WeakMap<Session, number>;
|
|
606
431
|
/** Per-session advisor side channel, constructed once with the advisor overrides. */
|
|
607
432
|
readonly advisorChannels: WeakMap<Session, SideChannel>;
|
|
608
|
-
/** Four-state outcome counters per Session (floating-window summary row). */
|
|
609
|
-
readonly reviewSummaries: WeakMap<Session, ReviewSessionSummary>;
|
|
610
433
|
}
|
|
611
434
|
//#endregion
|
|
612
435
|
//#region src/runtime/custom-policy.d.ts
|
|
@@ -930,78 +753,20 @@ declare class ToolResultPruner extends Service {
|
|
|
930
753
|
*/
|
|
931
754
|
private postflightAdvisorPass;
|
|
932
755
|
/**
|
|
933
|
-
*
|
|
934
|
-
* (
|
|
935
|
-
|
|
936
|
-
private reviewQueueFor;
|
|
937
|
-
/**
|
|
938
|
-
* Monotonic per-session turn clock for review patience and expiry. Bumped by
|
|
939
|
-
* the agent loop payloads (`pre-step` / `turn-stopping`); passes without a
|
|
940
|
-
* turn coordinate reuse the last observed value.
|
|
941
|
-
*/
|
|
942
|
-
private reviewClock;
|
|
943
|
-
private auditReviewOutcome;
|
|
944
|
-
/**
|
|
945
|
-
* Review-mode triage hook: classify one pass's planned replacements and
|
|
946
|
-
* withhold the review bucket from landing, enqueuing it for human approval
|
|
947
|
-
* instead. With review mode off (or nothing planned) this is the identity.
|
|
948
|
-
*
|
|
949
|
-
* The digest freezes each candidate's ORIGINAL surface content, so the apply
|
|
950
|
-
* point can prove "what is removed now is what was approved then".
|
|
951
|
-
*/
|
|
952
|
-
private triageForReview;
|
|
953
|
-
/**
|
|
954
|
-
* Execute every approved proposal of one session as ONE merged replacement
|
|
955
|
-
* batch at the current turn boundary, following the upstream applied-receipt
|
|
956
|
-
* discipline: applied receipts are built only from real mutation evidence —
|
|
957
|
-
* estimates never cross into applied savings.
|
|
958
|
-
*
|
|
959
|
-
* Per proposal: every item's frozen digest is re-checked against the current
|
|
960
|
-
* surface content; any mismatch voids the whole proposal (deferred with a
|
|
961
|
-
* reason code) instead of deleting something the user never approved.
|
|
962
|
-
* Fail-open: any unexpected error only logs and leaves the queue intact.
|
|
963
|
-
*/
|
|
964
|
-
applyApprovedProposals(session: Session): void;
|
|
965
|
-
/**
|
|
966
|
-
* Current surface content at one seq: the newest covering replacement's
|
|
967
|
-
* blocks when the seq was rewritten, otherwise the original event's blocks.
|
|
968
|
-
*/
|
|
969
|
-
private surfaceContentAt;
|
|
970
|
-
/**
|
|
971
|
-
* The execution-point digest check: `undefined` when every item's frozen
|
|
972
|
-
* digest still matches the current surface content, otherwise the aligned
|
|
973
|
-
* reason code explaining the void.
|
|
974
|
-
*/
|
|
975
|
-
private reviewProposalVoided;
|
|
976
|
-
private reviewSummaryFor;
|
|
977
|
-
/** Live pending review proposals of one session; empty when review mode is off. */
|
|
978
|
-
listReviewProposals(session: Session): readonly ReviewProposalRecord[];
|
|
979
|
-
/**
|
|
980
|
-
* Every session's live pending proposals, for the floating window's
|
|
981
|
-
* aggregate badge (the client carries no session id of its own).
|
|
982
|
-
*/
|
|
983
|
-
listAllReviewProposals(): readonly {
|
|
984
|
-
readonly sessionId: string;
|
|
985
|
-
readonly proposals: readonly ReviewProposalRecord[];
|
|
986
|
-
}[];
|
|
987
|
-
/** Four-state outcome counters of one session (floating-window summary row). */
|
|
988
|
-
reviewSummary(session: Session): ReviewSessionSummary;
|
|
989
|
-
/**
|
|
990
|
-
* Record one human decision. Returns the outcome, or `undefined` when
|
|
991
|
-
* review mode is off for this session (the route maps that to 503).
|
|
756
|
+
* Monotonic per-session turn clock for advisory records. Bumped by the agent
|
|
757
|
+
* loop payloads (`pre-step`); passes without a turn coordinate reuse the last
|
|
758
|
+
* observed value.
|
|
992
759
|
*/
|
|
993
|
-
|
|
994
|
-
ok: true;
|
|
995
|
-
} | {
|
|
996
|
-
ok: false;
|
|
997
|
-
reason: 'unknown-proposal' | 'not-pending';
|
|
998
|
-
} | undefined;
|
|
760
|
+
private turnClock;
|
|
999
761
|
/**
|
|
1000
|
-
*
|
|
1001
|
-
*
|
|
1002
|
-
*
|
|
762
|
+
* Advisory benefit-model hook — what the retired human-gated review pipeline
|
|
763
|
+
* left behind. It is the IDENTITY on the landing path: every plan it is given
|
|
764
|
+
* comes back unchanged, because a reduction must never block automatic
|
|
765
|
+
* processing. The model's band is published as a `reduction-advice` audit and
|
|
766
|
+
* snapshotted onto the advisor state for the read-only report route, so the
|
|
767
|
+
* cache-accounting insight survives without a gate.
|
|
1003
768
|
*/
|
|
1004
|
-
|
|
769
|
+
private adviseReplacements;
|
|
1005
770
|
private activePolicy;
|
|
1006
771
|
private contextWindowForRequest;
|
|
1007
772
|
private runRequestBoundary;
|