@tea-agent/loop-agent 0.40.0-next.10 → 0.40.0-next.12

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.
Files changed (97) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/application/dag/generate-task-dag.js +6 -2
  3. package/dist/build-stamp.json +3 -3
  4. package/dist/commands/client-recovery.js +8 -36
  5. package/dist/executors/pi-sdk-executor.js +33 -5
  6. package/dist/executors/shell-executor.js +64 -17
  7. package/dist/governance/checks.js +1 -0
  8. package/dist/shared/pi-context-pressure/checkpoint.js +116 -0
  9. package/dist/shared/pi-context-pressure/compaction-policy.js +151 -0
  10. package/dist/shared/pi-context-pressure/env.js +58 -0
  11. package/dist/shared/pi-context-pressure/extension.js +100 -0
  12. package/dist/shared/pi-context-pressure/index.js +7 -0
  13. package/dist/shared/pi-context-pressure/overflow.js +252 -0
  14. package/dist/shared/pi-context-pressure/sift-bridge.js +386 -0
  15. package/dist/shared/pi-context-pressure/telemetry.js +51 -0
  16. package/dist/worker/console/chat/pi-runtime.js +146 -5
  17. package/dist/worker/console/chat/provider-error.js +2 -1
  18. package/dist/worker/console/chat/routes.js +3 -0
  19. package/dist/worker/console/chat/sift-bridge.js +1 -0
  20. package/dist/worker/console/dag-execution-receipt.js +20 -2
  21. package/dist/worker/console/operator-actions.js +4 -3
  22. package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-Bs-CDAXM.js → abnfDiagram-N423BO3Z-C_hkwt2J.js} +1 -1
  23. package/dist/worker/console/static/assets/{arc-CAkA3We3.js → arc-s2Q6r96B.js} +1 -1
  24. package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-DEmI_zqr.js → architectureDiagram-T3A2C74G-CtgsrwU1.js} +1 -1
  25. package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-uDHANebE.js → blockDiagram-VBNYF7ZC-DZ-A7EiJ.js} +1 -1
  26. package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-Bv97b4_B.js → c4Diagram-5PPSVZJV-D2qv0Nyo.js} +1 -1
  27. package/dist/worker/console/static/assets/channel-BluaMT3-.js +1 -0
  28. package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-shmQKsFz.js → chunk-2GRJ4B5K-D-UYpSaW.js} +1 -1
  29. package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-BAraNvcN.js → chunk-2Q5K7J3B-DAS3jrrt.js} +1 -1
  30. package/dist/worker/console/static/assets/{chunk-5RXB4S5H-BirhxUop.js → chunk-5RXB4S5H-CSbuRcGB.js} +1 -1
  31. package/dist/worker/console/static/assets/{chunk-5VM5RSS4-C9LgUJpR.js → chunk-5VM5RSS4-BDH1ZO40.js} +1 -1
  32. package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-DrU-s-t7.js → chunk-6Q2QTUOP-Dc2cqQIb.js} +1 -1
  33. package/dist/worker/console/static/assets/{chunk-GF5L2VYU-Tx-H_FA2.js → chunk-GF5L2VYU-CkZuemIW.js} +1 -1
  34. package/dist/worker/console/static/assets/{chunk-JWPE2WC7-BjLtNFrR.js → chunk-JWPE2WC7-URwjQnte.js} +1 -1
  35. package/dist/worker/console/static/assets/{chunk-KBJHAD2P-UNLVwSsy.js → chunk-KBJHAD2P-04RHylJK.js} +1 -1
  36. package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CBEUX8XD.js → chunk-RYQCIY6F-CvQX56Hh.js} +1 -1
  37. package/dist/worker/console/static/assets/{chunk-XXDRQBXY-WTL7IZOq.js → chunk-XXDRQBXY-dUF7qura.js} +1 -1
  38. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-H-ZpSafr.js +1 -0
  39. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-H-ZpSafr.js +1 -0
  40. package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-CkHG6W3s.js → cose-bilkent-JH36ORCC-COwbfxJE.js} +1 -1
  41. package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-BRzFqTaL.js → cynefin-VYW2F7L2-CaBEJekQ.js} +1 -1
  42. package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-2_CFp_i7.js → cynefinDiagram-MW4NZA55-COWUBdet.js} +1 -1
  43. package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-BJtsmdkE.js → dagre-VZM6K2ZE-BLxVqTn4.js} +1 -1
  44. package/dist/worker/console/static/assets/{diagram-7IWD3JNH-DNEFFo6w.js → diagram-7IWD3JNH-WL0yKfEQ.js} +1 -1
  45. package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-B_IWV7eo.js → diagram-B4RE2ZJO-DaVkKCle.js} +1 -1
  46. package/dist/worker/console/static/assets/{diagram-LBJQPF4R-DvvRx2dz.js → diagram-LBJQPF4R-DdTgnRGf.js} +1 -1
  47. package/dist/worker/console/static/assets/{diagram-Q27KOJAE-CsibsWLg.js → diagram-Q27KOJAE-PG2Axo6A.js} +1 -1
  48. package/dist/worker/console/static/assets/{diagram-UB23O5K3-les_djBQ.js → diagram-UB23O5K3-6vuQzlzI.js} +1 -1
  49. package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-BEm2n7qJ.js → ebnfDiagram-BXEA7PRR-BpXeBz-g.js} +1 -1
  50. package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-BI7vHHVm.js → erDiagram-JOGREHBK-PxtUnaa1.js} +1 -1
  51. package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CUFCERrB.js → flowDiagram-UKHOOZJN-B--Qgvs1.js} +1 -1
  52. package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-wxyLiGWt.js → ganttDiagram-PKOTCBZU-BIfQCgtx.js} +1 -1
  53. package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-Bt897K8Z.js → gitGraphDiagram-DS77QQ5N-BRaX_E4j.js} +1 -1
  54. package/dist/worker/console/static/assets/index-Crrgl8Mx.css +1 -0
  55. package/dist/worker/console/static/assets/{index-DqJbO3-p.js → index-vPsp-idE.js} +102 -72
  56. package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-DYNx_IPv.js → infoDiagram-6WML65LV-Cd93r4Ab.js} +1 -1
  57. package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-CzpLNEu6.js → ishikawaDiagram-WSZJBQD7-C4c80iHt.js} +1 -1
  58. package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-97f9owNU.js → journeyDiagram-NVQOT4AX-Ch5ajf3s.js} +1 -1
  59. package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-BxM9hyBn.js → kanban-definition-27J2QSJJ-DbpyW1Ut.js} +1 -1
  60. package/dist/worker/console/static/assets/{linear-ByuxcHvp.js → linear-BHVjBnTW.js} +1 -1
  61. package/dist/worker/console/static/assets/{mermaid.core-DwPGvpCv.js → mermaid.core-DO70kJ34.js} +5 -5
  62. package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-DCoqG9RT.js → mindmap-definition-FAOFIHXS-_P44Zpvs.js} +1 -1
  63. package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-BLSBmBMx.js → pegDiagram-VL7TDLO6-Bgi9FmEd.js} +1 -1
  64. package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-B0t_0oJW.js → pieDiagram-7S7Q4E2Y-C9InDfJn.js} +1 -1
  65. package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-sTzDk7Nt.js → quadrantDiagram-CIZ2JOQS-DtKrUouv.js} +1 -1
  66. package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-B3jRdATC.js → railroadDiagram-AXF67PYL-zgAD_6Yo.js} +1 -1
  67. package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-D-cTtXEN.js → requirementDiagram-LRYGKXZP-CQNO6kj4.js} +1 -1
  68. package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-B25igJRE.js → sankeyDiagram-W5VNT64P-knKu111P.js} +1 -1
  69. package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-jW_lM1_D.js → sequenceDiagram-SI44F4Z6-D6tshiQ6.js} +1 -1
  70. package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-CrzTgsHE.js → sizeCapture-X5ZJPWSS-BMIWJcir.js} +1 -1
  71. package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-B01MvlqE.js → stateDiagram-OKZ733FA-BP9wRDqc.js} +1 -1
  72. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-ClEhytQG.js +1 -0
  73. package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-YcF12FiU.js → swimlanes-SLNWSIFB-DEkM5Dhe.js} +2 -2
  74. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DPg5IMuu.js +8 -0
  75. package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-ClnRcg2s.js → timeline-definition-Z64GVDOM-ByBKsL35.js} +1 -1
  76. package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-B6gr_z-q.js → vennDiagram-T6HMQDX7-waFbNCUy.js} +1 -1
  77. package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-CvSgguGH.js → wardleyDiagram-T6FBY63Y-1ljiY0eZ.js} +1 -1
  78. package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-23OtSZCb.js → xychartDiagram-ELKLHX3M-B4ZLHr_L.js} +1 -1
  79. package/dist/worker/console/static/index.html +2 -2
  80. package/dist/worker/observe/static/styles.css +9 -0
  81. package/dist/worker/observe/static/views/dag-inspector.js +40 -0
  82. package/dist/worker/observe/static/views/session-timeline.js +135 -0
  83. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +157 -7
  84. package/dist/workflows/dag/backend-test-pytest-collection.js +70 -2
  85. package/dist/workflows/dag/backend-test-result-contract.js +4 -0
  86. package/dist/workflows/dag/backend-test-scenario-param.js +339 -53
  87. package/dist/workflows/dag/backend-test-writer-completeness.js +11 -0
  88. package/dist/workflows/dag/init-hybrid.js +2 -2
  89. package/docs/architecture/runtime-boundaries.md +2 -1
  90. package/docs/templates/backend-test-dag.json +4 -3
  91. package/package.json +3 -2
  92. package/dist/worker/console/static/assets/channel-amxUpk7o.js +0 -1
  93. package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-bejwBVIz.js +0 -1
  94. package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-bejwBVIz.js +0 -1
  95. package/dist/worker/console/static/assets/index-BHhUOTri.css +0 -1
  96. package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-BvFKEtm2.js +0 -1
  97. package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-DIB2eVg-.js +0 -8
@@ -0,0 +1,151 @@
1
+ import { parseBoundedNumber, readContextPressureMode, } from "./env.js";
2
+ export const PI_DEFAULT_RESERVE_TOKENS = 16_384;
3
+ export const DEFAULT_TRAILING_BUDGET_TOKENS = 8_192;
4
+ export const DEFAULT_SAFETY_MARGIN_TOKENS = 4_096;
5
+ export const DEFAULT_MINIMUM_WORKING_SET = 32_768;
6
+ export const DEFAULT_KEEP_RECENT_TOKENS = 20_000;
7
+ export function parseCompactionPolicy(env = process.env) {
8
+ const diagnostics = [];
9
+ const modeResult = readContextPressureMode(env);
10
+ if (modeResult.diagnostic)
11
+ diagnostics.push(modeResult.diagnostic);
12
+ const k = parseBoundedNumber(env.HARNESS_CONTEXT_GATEWAY_K, 1, 1, 8);
13
+ if (k.diagnostic)
14
+ diagnostics.push(k.diagnostic);
15
+ const trailing = parseBoundedNumber(env.HARNESS_CONTEXT_TRAILING_BUDGET_TOKENS, DEFAULT_TRAILING_BUDGET_TOKENS, 256, 128_000);
16
+ if (trailing.diagnostic)
17
+ diagnostics.push(trailing.diagnostic);
18
+ const safety = parseBoundedNumber(env.HARNESS_CONTEXT_SAFETY_MARGIN_TOKENS, DEFAULT_SAFETY_MARGIN_TOKENS, 0, 64_000);
19
+ if (safety.diagnostic)
20
+ diagnostics.push(safety.diagnostic);
21
+ const explicit = env.HARNESS_COMPACTION_RESERVE_TOKENS;
22
+ const explicitReserve = explicit === undefined || explicit.trim() === ""
23
+ ? undefined
24
+ : parseBoundedNumber(explicit, PI_DEFAULT_RESERVE_TOKENS, 1_024, 1_000_000);
25
+ if (explicitReserve?.diagnostic)
26
+ diagnostics.push(explicitReserve.diagnostic);
27
+ return {
28
+ mode: modeResult.mode,
29
+ k: k.value,
30
+ trailingBudgetTokens: trailing.value,
31
+ safetyMarginTokens: safety.value,
32
+ minimumWorkingSet: DEFAULT_MINIMUM_WORKING_SET,
33
+ ...(explicitReserve ? { explicitReserveTokens: explicitReserve.value } : {}),
34
+ diagnostics,
35
+ };
36
+ }
37
+ export function deriveEffectiveWindow(contextWindow, policy) {
38
+ const W = Math.floor(contextWindow);
39
+ if (!Number.isFinite(W) || W <= 0) {
40
+ return {
41
+ recommendedReserve: PI_DEFAULT_RESERVE_TOKENS,
42
+ triggerTokens: 0,
43
+ fallback: true,
44
+ };
45
+ }
46
+ if (policy.explicitReserveTokens !== undefined) {
47
+ const recommendedReserve = Math.min(Math.max(policy.explicitReserveTokens, 1), Math.max(1, W - 1));
48
+ return {
49
+ recommendedReserve,
50
+ triggerTokens: Math.max(0, W - recommendedReserve),
51
+ fallback: false,
52
+ };
53
+ }
54
+ const rawTrigger = Math.floor(W / policy.k) -
55
+ policy.trailingBudgetTokens -
56
+ policy.safetyMarginTokens;
57
+ const rawReserve = W - rawTrigger;
58
+ const maxReserve = Math.max(1, W - policy.minimumWorkingSet);
59
+ if (!Number.isFinite(rawTrigger) ||
60
+ !Number.isFinite(rawReserve) ||
61
+ maxReserve < PI_DEFAULT_RESERVE_TOKENS) {
62
+ const recommendedReserve = Math.min(PI_DEFAULT_RESERVE_TOKENS, Math.max(1, W - 1));
63
+ return {
64
+ recommendedReserve,
65
+ triggerTokens: Math.max(0, W - recommendedReserve),
66
+ fallback: true,
67
+ };
68
+ }
69
+ const recommendedReserve = Math.min(Math.max(PI_DEFAULT_RESERVE_TOKENS, rawReserve), maxReserve);
70
+ return {
71
+ recommendedReserve,
72
+ triggerTokens: Math.max(0, W - recommendedReserve),
73
+ fallback: false,
74
+ };
75
+ }
76
+ export function conservativeTokenEstimate(text, imageCount = 0) {
77
+ const chars = Array.from(text);
78
+ let cjk = 0;
79
+ let other = 0;
80
+ for (const char of chars) {
81
+ if (/\p{Script=Han}|\p{Script=Hiragana}|\p{Script=Katakana}/u.test(char)) {
82
+ cjk += 1;
83
+ }
84
+ else {
85
+ other += 1;
86
+ }
87
+ }
88
+ const utf8 = Buffer.byteLength(text, "utf8");
89
+ const fromChars = cjk + Math.ceil(other / 2);
90
+ const fromBytes = Math.ceil(utf8 / 2);
91
+ return (Math.max(fromChars, fromBytes, Math.ceil(chars.length / 2)) +
92
+ Math.max(0, imageCount) * 1024);
93
+ }
94
+ export function projectPromptPressure(input) {
95
+ if (input.currentContextTokens === null ||
96
+ input.currentContextTokens === undefined ||
97
+ !Number.isFinite(input.currentContextTokens)) {
98
+ return { projected: 0, usageUnavailable: true };
99
+ }
100
+ return {
101
+ projected: Math.max(0, input.currentContextTokens) +
102
+ conservativeTokenEstimate(input.promptText, input.imageCount ?? 0),
103
+ usageUnavailable: false,
104
+ };
105
+ }
106
+ function isExplicitlyDisabled(manager) {
107
+ const project = manager.getProjectSettings?.()?.compaction?.enabled;
108
+ const global = manager.getGlobalSettings?.()?.compaction?.enabled;
109
+ return project === false || (project === undefined && global === false);
110
+ }
111
+ export function applyProcessCompactionOverride(manager, input) {
112
+ if (!manager?.applyOverrides || input.policy.mode === "off") {
113
+ return { applied: false };
114
+ }
115
+ const explicitOff = input.policy.mode === "safe" && isExplicitlyDisabled(manager);
116
+ const enabled = input.policy.mode === "strict" ? true : explicitOff ? false : true;
117
+ const window = typeof input.contextWindow === "number" && input.contextWindow > 0
118
+ ? deriveEffectiveWindow(input.contextWindow, input.policy)
119
+ : undefined;
120
+ const compaction = { enabled };
121
+ if (window && enabled) {
122
+ compaction.reserveTokens = window.recommendedReserve;
123
+ compaction.keepRecentTokens = DEFAULT_KEEP_RECENT_TOKENS;
124
+ }
125
+ manager.applyOverrides({ compaction });
126
+ return {
127
+ applied: true,
128
+ enabled,
129
+ ...(typeof compaction.reserveTokens === "number"
130
+ ? { reserveTokens: compaction.reserveTokens }
131
+ : {}),
132
+ ...(typeof compaction.keepRecentTokens === "number"
133
+ ? { keepRecentTokens: compaction.keepRecentTokens }
134
+ : {}),
135
+ ...(window?.fallback
136
+ ? { diagnostic: "small-or-invalid-window-fell-back-to-pi-default-reserve" }
137
+ : {}),
138
+ };
139
+ }
140
+ export function inMemoryCompactionSettings(policy) {
141
+ if (policy.mode === "off") {
142
+ return { enabled: true };
143
+ }
144
+ return {
145
+ enabled: true,
146
+ keepRecentTokens: DEFAULT_KEEP_RECENT_TOKENS,
147
+ ...(policy.explicitReserveTokens
148
+ ? { reserveTokens: policy.explicitReserveTokens }
149
+ : {}),
150
+ };
151
+ }
@@ -0,0 +1,58 @@
1
+ const TRUTHY = new Set(["1", "true", "on"]);
2
+ const FALSY = new Set(["0", "false", "off"]);
3
+ export function parseEnabledFlag(raw, defaultEnabled) {
4
+ if (raw === undefined || raw.trim() === "") {
5
+ return { enabled: defaultEnabled };
6
+ }
7
+ const value = raw.trim().toLowerCase();
8
+ if (TRUTHY.has(value))
9
+ return { enabled: true };
10
+ if (FALSY.has(value))
11
+ return { enabled: false };
12
+ return {
13
+ enabled: defaultEnabled,
14
+ diagnostic: `invalid flag ${JSON.stringify(raw)}; clamped to default ${defaultEnabled}`,
15
+ };
16
+ }
17
+ export function parseContextPressureMode(raw) {
18
+ if (raw === undefined || raw.trim() === "")
19
+ return { mode: "safe" };
20
+ const value = raw.trim().toLowerCase();
21
+ if (value === "off" || value === "safe" || value === "strict") {
22
+ return { mode: value };
23
+ }
24
+ return {
25
+ mode: "safe",
26
+ diagnostic: `invalid HARNESS_CONTEXT_PRESSURE_MODE ${JSON.stringify(raw)}; clamped to safe`,
27
+ };
28
+ }
29
+ export function parseBoundedNumber(raw, fallback, min, max) {
30
+ if (raw === undefined || raw.trim() === "") {
31
+ return { value: fallback };
32
+ }
33
+ const parsed = Number(raw);
34
+ if (!Number.isFinite(parsed)) {
35
+ return {
36
+ value: fallback,
37
+ diagnostic: `invalid number ${JSON.stringify(raw)}; clamped to ${fallback}`,
38
+ };
39
+ }
40
+ const clamped = Math.min(max, Math.max(min, parsed));
41
+ if (clamped !== parsed) {
42
+ return {
43
+ value: clamped,
44
+ diagnostic: `number ${parsed} clamped to [${min}, ${max}] => ${clamped}`,
45
+ };
46
+ }
47
+ return { value: parsed };
48
+ }
49
+ /** Console/DAG sift: default ON; `0|false|off` disables. */
50
+ export function isConsoleSiftEnabled(env = process.env) {
51
+ return parseEnabledFlag(env.HARNESS_CONSOLE_SIFT, true);
52
+ }
53
+ export function isDagSiftEnabled(env = process.env) {
54
+ return parseEnabledFlag(env.HARNESS_DAG_SIFT, true);
55
+ }
56
+ export function readContextPressureMode(env = process.env) {
57
+ return parseContextPressureMode(env.HARNESS_CONTEXT_PRESSURE_MODE);
58
+ }
@@ -0,0 +1,100 @@
1
+ import { buildOverflowCheckpoint } from "./checkpoint.js";
2
+ import { shouldRewriteAssistantOverflow } from "./overflow.js";
3
+ import { clearRetrieveBypass, compressProviderPayload, createSiftRetrieveToolDefinition, SIFT_RETRIEVE_TOOL_NAME, } from "./sift-bridge.js";
4
+ import { emptyContextPressureCounters, incrementCounter, } from "./telemetry.js";
5
+ export function createCompactionController() {
6
+ return {
7
+ proactiveCompaction: false,
8
+ counters: emptyContextPressureCounters(),
9
+ };
10
+ }
11
+ export function createContextPressureExtension(options) {
12
+ const l2 = options.policy.mode !== "off";
13
+ const l1 = Boolean(options.sift);
14
+ if (!l2 && !l1)
15
+ return undefined;
16
+ return {
17
+ name: options.name ?? "operator-chat-context-pressure",
18
+ hidden: true,
19
+ factory: (api) => {
20
+ if (l2) {
21
+ api.on("message_end", (event) => {
22
+ const message = event.message;
23
+ if (!message || typeof message !== "object")
24
+ return undefined;
25
+ const rec = message;
26
+ if (typeof rec.errorMessage === "string") {
27
+ options.controller.lastError = rec.errorMessage;
28
+ }
29
+ if (rec.role === "assistant") {
30
+ clearRetrieveBypassIfPresent(options.sift);
31
+ }
32
+ const rewritten = shouldRewriteAssistantOverflow(message);
33
+ if (!rewritten)
34
+ return undefined;
35
+ incrementCounter(options.controller.counters, "overflow");
36
+ return {
37
+ message: {
38
+ ...rec,
39
+ errorMessage: rewritten,
40
+ },
41
+ };
42
+ });
43
+ api.on("session_before_compact", (event) => {
44
+ const reason = event.reason;
45
+ if (reason === "overflow") {
46
+ incrementCounter(options.controller.counters, "overflow");
47
+ }
48
+ if (reason === "manual") {
49
+ incrementCounter(options.controller.counters, "manual");
50
+ }
51
+ const useCheckpoint = options.policy.mode === "strict" &&
52
+ (reason === "overflow" ||
53
+ (reason === "manual" && options.controller.proactiveCompaction));
54
+ if (!useCheckpoint)
55
+ return undefined;
56
+ const checkpoint = buildOverflowCheckpoint({
57
+ preparation: event.preparation,
58
+ todos: options.controller.todos,
59
+ lastError: options.controller.lastError,
60
+ });
61
+ if (!checkpoint)
62
+ return undefined;
63
+ return {
64
+ compaction: {
65
+ summary: checkpoint.summary,
66
+ firstKeptEntryId: checkpoint.firstKeptEntryId,
67
+ tokensBefore: checkpoint.tokensBefore,
68
+ },
69
+ };
70
+ });
71
+ }
72
+ if (l1 && options.sift) {
73
+ const sift = options.sift;
74
+ api.on("before_provider_request", (event) => {
75
+ return compressProviderPayload(sift, event.payload);
76
+ });
77
+ api.on("message_end", (event) => {
78
+ const message = event.message;
79
+ if (message &&
80
+ typeof message === "object" &&
81
+ message.role === "assistant") {
82
+ clearRetrieveBypass(sift);
83
+ }
84
+ return undefined;
85
+ });
86
+ try {
87
+ api.registerTool?.(createSiftRetrieveToolDefinition(sift));
88
+ }
89
+ catch {
90
+ sift.diagnostics.add("register-tool-failed");
91
+ }
92
+ }
93
+ },
94
+ };
95
+ }
96
+ function clearRetrieveBypassIfPresent(sift) {
97
+ if (sift)
98
+ clearRetrieveBypass(sift);
99
+ }
100
+ export { SIFT_RETRIEVE_TOOL_NAME };
@@ -0,0 +1,7 @@
1
+ export { isContextOverflow, CONTEXT_OVERFLOW_PHRASES, OVERFLOW_FIXTURES, NORMALIZED_OVERFLOW_PREFIX, shouldRewriteAssistantOverflow, normalizeOverflowErrorMessage, buildGeneratedOverflowClassifierSource, } from "./overflow.js";
2
+ export { parseCompactionPolicy, deriveEffectiveWindow, conservativeTokenEstimate, projectPromptPressure, applyProcessCompactionOverride, inMemoryCompactionSettings, PI_DEFAULT_RESERVE_TOKENS, DEFAULT_KEEP_RECENT_TOKENS, } from "./compaction-policy.js";
3
+ export { buildOverflowCheckpoint } from "./checkpoint.js";
4
+ export { createContextPressureExtension, createCompactionController, } from "./extension.js";
5
+ export { createSiftBridgeState, parseSiftBridgeConfig, compressProviderPayload, executeSiftRetrieve, housekeepSiftStash, createSiftRetrieveToolDefinition, SIFT_RETRIEVE_TOOL_NAME, SIFT_POLICY_VERSION, } from "./sift-bridge.js";
6
+ export { isConsoleSiftEnabled, isDagSiftEnabled, readContextPressureMode, parseEnabledFlag, parseContextPressureMode, } from "./env.js";
7
+ export { emptyContextPressureCounters, projectSafeTelemetry, } from "./telemetry.js";
@@ -0,0 +1,252 @@
1
+ /**
2
+ * Unique overflow classifier for Console UI, SDK extensions, and generated
3
+ * client-recovery plugins. Phrase match wins; type/code never classify alone.
4
+ */
5
+ export const CONTEXT_OVERFLOW_PHRASES = [
6
+ "请求上下文过大",
7
+ "上下文过大",
8
+ "上下文太大",
9
+ "上下文过长",
10
+ "上下文超限",
11
+ "context_length_exceeded",
12
+ "context overflow",
13
+ "context length overflow",
14
+ "too many tokens",
15
+ "maximum context",
16
+ "prompt is too long",
17
+ "prompt too long",
18
+ "request_too_large",
19
+ "reduce the length of the messages",
20
+ "context window",
21
+ ];
22
+ const OVERFLOW_PATTERN = new RegExp(CONTEXT_OVERFLOW_PHRASES.map(escapeRegExpLiteral).join("|"), "i");
23
+ const AUTH_STATUS = new Set([401, 403]);
24
+ export const OVERFLOW_FIXTURES = {
25
+ positives: {
26
+ P1: `{"object":"error","message":"请求上下文过大","type":"BadRequestError","code":400}`,
27
+ P2: `data:{"object":"error","message":"请求上下文过大","type":"BadRequestError","code":400}`,
28
+ P3: `400 {"object":"error","message":"请求上下文过大","type":"BadRequestError","code":400}`,
29
+ P4: "请求上下文过大",
30
+ P5: "请求上下文过大 (BadRequestError 400)",
31
+ P6: "LLMRequestError: 请求上下文过大 (BadRequestError 400)",
32
+ P7: "LLM upstream returned an error payload in a 200 stream: 请求上下文过大 (BadRequestError 400)",
33
+ P8: "LLM upstream returned HTTP 400: 请求上下文过大",
34
+ P9: `{"object":"error","type":"BadRequestError","code":"200","message":"{\\"object\\":\\"error\\",\\"code\\":400,\\"type\\":\\"BadRequestError\\",\\"param\\":null,\\"message\\":\\"请求上下文过大\\"}"}`,
35
+ P10: {
36
+ stopReason: "error",
37
+ errorMessage: "请求上下文过大 (BadRequestError 400)",
38
+ errorCode: "stream_payload_error",
39
+ providerType: "BadRequestError",
40
+ providerCode: "400",
41
+ },
42
+ // P11/P12: 2026-08-27 真实企业网关捕获(openai-completions / wizard-local /
43
+ // aicoder-plus)。HTTP 状态行 + 换行 + `data:` SSE 前缀 + JSON + 尾部空行
44
+ // 同串组合;完整事件样本见 exec-plan §1.1 附录 A。
45
+ P11: "400\n data:{\"object\":\"error\",\"message\":\"请求上下文过大\",\"type\":\"BadRequestError\",\"code\":400}\n\n",
46
+ P12: {
47
+ message: {
48
+ role: "assistant",
49
+ content: [],
50
+ api: "openai-completions",
51
+ provider: "wizard-local",
52
+ model: "aicoder-plus",
53
+ usage: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
54
+ stopReason: "error",
55
+ errorMessage: "400\n data:{\"object\":\"error\",\"message\":\"请求上下文过大\",\"type\":\"BadRequestError\",\"code\":400}\n\n",
56
+ },
57
+ },
58
+ },
59
+ negatives: {
60
+ N1: `{"object":"error","message":"认证错误!","type":"BadRequestError","code":401}`,
61
+ N2: "当前请求超时, 请重试 (BadRequestError 502)",
62
+ N2b: "LLMRequestError: 当前请求超时, 请重试 (BadRequestError 502)",
63
+ N3: "The requested resource was not found. (BadRequestError 404)",
64
+ N3b: "The requested resource was not found. (NotFoundError 404)",
65
+ N4: "LLMRequestError: (BadRequestError 400)",
66
+ N5: `{"object":"error","type":"BadRequestError","code":"200","message":"{\\"object\\":\\"error\\",\\"code\\":502,\\"type\\":\\"BadRequestError\\",\\"message\\":\\"当前请求超时, 请重试\\"}"}`,
67
+ },
68
+ };
69
+ export const NORMALIZED_OVERFLOW_PREFIX = "context_length_exceeded:";
70
+ function escapeRegExpLiteral(value) {
71
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
72
+ }
73
+ function asText(value) {
74
+ if (typeof value === "string")
75
+ return value;
76
+ if (value == null)
77
+ return "";
78
+ try {
79
+ return JSON.stringify(value);
80
+ }
81
+ catch {
82
+ return String(value);
83
+ }
84
+ }
85
+ function tryParseJson(text) {
86
+ const trimmed = text.trim();
87
+ const candidates = [trimmed];
88
+ const dataPrefix = trimmed.match(/^data:\s*(\{[\s\S]*)$/i);
89
+ if (dataPrefix)
90
+ candidates.push(dataPrefix[1] ?? "");
91
+ const statusPrefix = trimmed.match(/^\d{3}\s+(\{[\s\S]*)$/);
92
+ if (statusPrefix)
93
+ candidates.push(statusPrefix[1] ?? "");
94
+ const start = trimmed.indexOf("{");
95
+ const end = trimmed.lastIndexOf("}");
96
+ if (start >= 0 && end > start)
97
+ candidates.push(trimmed.slice(start, end + 1));
98
+ for (const candidate of candidates) {
99
+ if (!candidate)
100
+ continue;
101
+ try {
102
+ return JSON.parse(candidate);
103
+ }
104
+ catch {
105
+ // Keep scanning other envelopes.
106
+ }
107
+ }
108
+ return undefined;
109
+ }
110
+ function collectStringFields(value, depth, out) {
111
+ if (depth > 6 || value == null)
112
+ return;
113
+ if (typeof value === "string") {
114
+ if (value)
115
+ out.push(value);
116
+ const nested = tryParseJson(value);
117
+ if (nested !== undefined && nested !== value) {
118
+ collectStringFields(nested, depth + 1, out);
119
+ }
120
+ return;
121
+ }
122
+ if (typeof value !== "object")
123
+ return;
124
+ const record = value;
125
+ for (const key of ["message", "errorMessage", "error"]) {
126
+ if (key in record)
127
+ collectStringFields(record[key], depth + 1, out);
128
+ }
129
+ }
130
+ function extractStatus(text) {
131
+ const suffix = text.match(/\((?:BadRequestError|NotFoundError|AuthenticationError|RateLimitError)\s+(\d{3})\)/i);
132
+ if (suffix)
133
+ return Number(suffix[1]);
134
+ const http = text.match(/\bHTTP\s+(\d{3})\b/i);
135
+ if (http)
136
+ return Number(http[1]);
137
+ const parsed = tryParseJson(text);
138
+ if (parsed && typeof parsed === "object") {
139
+ const record = parsed;
140
+ const code = record.code ?? record.status ?? record.statusCode;
141
+ if (typeof code === "number" && Number.isFinite(code))
142
+ return code;
143
+ if (typeof code === "string" && /^\d{3}$/.test(code.trim())) {
144
+ return Number(code.trim());
145
+ }
146
+ }
147
+ return undefined;
148
+ }
149
+ export function collectOverflowHaystack(error) {
150
+ if (typeof error === "string")
151
+ return error;
152
+ if (!error || typeof error !== "object")
153
+ return asText(error);
154
+ const record = error;
155
+ const parts = [
156
+ asText(record.message),
157
+ asText(record.errorMessage),
158
+ asText(record.error),
159
+ asText(record.name),
160
+ asText(record.status),
161
+ asText(record.code),
162
+ asText(record.data),
163
+ ];
164
+ return parts.filter(Boolean).join("\n");
165
+ }
166
+ export function isContextOverflow(error) {
167
+ const haystack = collectOverflowHaystack(error);
168
+ const fields = [haystack];
169
+ collectStringFields(error, 0, fields);
170
+ collectStringFields(tryParseJson(haystack), 0, fields);
171
+ const combined = fields.join("\n");
172
+ if (!OVERFLOW_PATTERN.test(combined))
173
+ return false;
174
+ const status = extractStatus(combined);
175
+ if (status !== undefined && AUTH_STATUS.has(status))
176
+ return false;
177
+ return true;
178
+ }
179
+ export function normalizeOverflowErrorMessage(current) {
180
+ if (!current)
181
+ return undefined;
182
+ if (current.startsWith(NORMALIZED_OVERFLOW_PREFIX) ||
183
+ /context_length_exceeded/i.test(current)) {
184
+ return undefined;
185
+ }
186
+ if (!isContextOverflow(current))
187
+ return undefined;
188
+ const bounded = current.length <= 1500 ? current : `${current.slice(0, 1499)}…`;
189
+ return `${NORMALIZED_OVERFLOW_PREFIX} ${bounded}`;
190
+ }
191
+ export function shouldRewriteAssistantOverflow(message) {
192
+ if (!message || typeof message !== "object")
193
+ return undefined;
194
+ const record = message;
195
+ if (record.role !== "assistant")
196
+ return undefined;
197
+ if (record.stopReason !== undefined && record.stopReason !== "error") {
198
+ return undefined;
199
+ }
200
+ const current = typeof record.errorMessage === "string" ? record.errorMessage : "";
201
+ if (!current)
202
+ return undefined;
203
+ return normalizeOverflowErrorMessage(current);
204
+ }
205
+ export function buildGeneratedOverflowClassifierSource() {
206
+ return `const CONTEXT_OVERFLOW_PHRASES = ${JSON.stringify([
207
+ ...CONTEXT_OVERFLOW_PHRASES,
208
+ ])};
209
+ const OVERFLOW_PATTERN = new RegExp(
210
+ CONTEXT_OVERFLOW_PHRASES.map((phrase) =>
211
+ phrase.replace(/[.*+?^\${}()|[\\]\\\\]/g, "\\\\$&"),
212
+ ).join("|"),
213
+ "i",
214
+ );
215
+ function tryParseJson(text) {
216
+ if (typeof text !== "string") return undefined;
217
+ const trimmed = text.trim();
218
+ const candidates = [trimmed];
219
+ const dataPrefix = trimmed.match(/^data:\\s*(\\{[\\s\\S]*)$/i);
220
+ if (dataPrefix) candidates.push(dataPrefix[1]);
221
+ const start = trimmed.indexOf("{");
222
+ const end = trimmed.lastIndexOf("}");
223
+ if (start >= 0 && end > start) candidates.push(trimmed.slice(start, end + 1));
224
+ for (const candidate of candidates) {
225
+ try { return JSON.parse(candidate); } catch {}
226
+ }
227
+ return undefined;
228
+ }
229
+ function collectFields(value, depth, out) {
230
+ if (depth > 6 || value == null) return;
231
+ if (typeof value === "string") {
232
+ if (value) out.push(value);
233
+ const nested = tryParseJson(value);
234
+ if (nested !== undefined && nested !== value) collectFields(nested, depth + 1, out);
235
+ return;
236
+ }
237
+ if (typeof value !== "object") return;
238
+ if (typeof value.message === "string") collectFields(value.message, depth + 1, out);
239
+ if (typeof value.errorMessage === "string") collectFields(value.errorMessage, depth + 1, out);
240
+ if (value.error) collectFields(value.error, depth + 1, out);
241
+ }
242
+ function isOverflowMessage(text) {
243
+ if (typeof text !== "string" || !text) return false;
244
+ const fields = [text];
245
+ collectFields(text, 0, fields);
246
+ collectFields(tryParseJson(text), 0, fields);
247
+ const combined = fields.join("\\n");
248
+ if (!OVERFLOW_PATTERN.test(combined)) return false;
249
+ if (/\\((?:BadRequestError|AuthenticationError)\\s+40[13]\\)/i.test(combined)) return false;
250
+ return true;
251
+ }`;
252
+ }