@orion-agents/orion-code 0.1.8 → 0.1.9

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 (232) hide show
  1. package/CHANGELOG.md +445 -0
  2. package/README.md +15 -6
  3. package/README.zh-CN.md +26 -7
  4. package/dist/agents/coordinator.d.ts.map +1 -1
  5. package/dist/agents/coordinator.js +49 -9
  6. package/dist/agents/coordinator.js.map +1 -1
  7. package/dist/agents/fork.d.ts +5 -1
  8. package/dist/agents/fork.d.ts.map +1 -1
  9. package/dist/agents/fork.js +9 -10
  10. package/dist/agents/fork.js.map +1 -1
  11. package/dist/agents/worker-pool.d.ts.map +1 -1
  12. package/dist/agents/worker-pool.js +8 -3
  13. package/dist/agents/worker-pool.js.map +1 -1
  14. package/dist/cli.js +6 -6
  15. package/dist/cli.js.map +1 -1
  16. package/dist/commands/context-tool-command-handlers.d.ts.map +1 -1
  17. package/dist/commands/context-tool-command-handlers.js +42 -0
  18. package/dist/commands/context-tool-command-handlers.js.map +1 -1
  19. package/dist/commands/model-command-handlers.d.ts +1 -1
  20. package/dist/commands/model-command-handlers.d.ts.map +1 -1
  21. package/dist/commands/model-command-handlers.js +166 -1
  22. package/dist/commands/model-command-handlers.js.map +1 -1
  23. package/dist/commands/session-command-handlers.d.ts.map +1 -1
  24. package/dist/commands/session-command-handlers.js +97 -5
  25. package/dist/commands/session-command-handlers.js.map +1 -1
  26. package/dist/commands/session-commands.js +2 -2
  27. package/dist/commands/session-commands.js.map +1 -1
  28. package/dist/commands/types.d.ts +6 -0
  29. package/dist/commands/types.d.ts.map +1 -1
  30. package/dist/commands/types.js.map +1 -1
  31. package/dist/framework/index.d.ts +5 -3
  32. package/dist/framework/index.d.ts.map +1 -1
  33. package/dist/framework/index.js +9 -1
  34. package/dist/framework/index.js.map +1 -1
  35. package/dist/framework/query.d.ts +26 -4
  36. package/dist/framework/query.d.ts.map +1 -1
  37. package/dist/framework/query.js +319 -62
  38. package/dist/framework/query.js.map +1 -1
  39. package/dist/framework/stop-decision.d.ts +56 -0
  40. package/dist/framework/stop-decision.d.ts.map +1 -0
  41. package/dist/framework/stop-decision.js +36 -0
  42. package/dist/framework/stop-decision.js.map +1 -0
  43. package/dist/framework/tool-scheduler.d.ts +5 -0
  44. package/dist/framework/tool-scheduler.d.ts.map +1 -1
  45. package/dist/framework/tool-scheduler.js +24 -9
  46. package/dist/framework/tool-scheduler.js.map +1 -1
  47. package/dist/harness/assembler.d.ts.map +1 -1
  48. package/dist/harness/assembler.js +77 -19
  49. package/dist/harness/assembler.js.map +1 -1
  50. package/dist/harness/capability-profile.d.ts +3 -0
  51. package/dist/harness/capability-profile.d.ts.map +1 -0
  52. package/dist/harness/capability-profile.js +44 -0
  53. package/dist/harness/capability-profile.js.map +1 -0
  54. package/dist/harness/capsule.d.ts.map +1 -1
  55. package/dist/harness/capsule.js +22 -3
  56. package/dist/harness/capsule.js.map +1 -1
  57. package/dist/harness/compact-benchmark-corpus.d.ts +10 -0
  58. package/dist/harness/compact-benchmark-corpus.d.ts.map +1 -0
  59. package/dist/harness/compact-benchmark-corpus.js +56 -0
  60. package/dist/harness/compact-benchmark-corpus.js.map +1 -0
  61. package/dist/harness/context-harness.d.ts +23 -3
  62. package/dist/harness/context-harness.d.ts.map +1 -1
  63. package/dist/harness/context-harness.js +183 -11
  64. package/dist/harness/context-harness.js.map +1 -1
  65. package/dist/harness/contract.d.ts.map +1 -1
  66. package/dist/harness/contract.js +106 -11
  67. package/dist/harness/contract.js.map +1 -1
  68. package/dist/harness/drift-guard.d.ts +2 -1
  69. package/dist/harness/drift-guard.d.ts.map +1 -1
  70. package/dist/harness/drift-guard.js +315 -20
  71. package/dist/harness/drift-guard.js.map +1 -1
  72. package/dist/harness/evidence.d.ts.map +1 -1
  73. package/dist/harness/evidence.js +25 -12
  74. package/dist/harness/evidence.js.map +1 -1
  75. package/dist/harness/index.d.ts +7 -2
  76. package/dist/harness/index.d.ts.map +1 -1
  77. package/dist/harness/index.js +19 -1
  78. package/dist/harness/index.js.map +1 -1
  79. package/dist/harness/ledger.d.ts.map +1 -1
  80. package/dist/harness/ledger.js +44 -14
  81. package/dist/harness/ledger.js.map +1 -1
  82. package/dist/harness/progress-controller.d.ts +14 -0
  83. package/dist/harness/progress-controller.d.ts.map +1 -0
  84. package/dist/harness/progress-controller.js +110 -0
  85. package/dist/harness/progress-controller.js.map +1 -0
  86. package/dist/harness/state.d.ts.map +1 -1
  87. package/dist/harness/state.js +5 -2
  88. package/dist/harness/state.js.map +1 -1
  89. package/dist/harness/stop-controller.d.ts +15 -0
  90. package/dist/harness/stop-controller.d.ts.map +1 -0
  91. package/dist/harness/stop-controller.js +87 -0
  92. package/dist/harness/stop-controller.js.map +1 -0
  93. package/dist/harness/types.d.ts +137 -0
  94. package/dist/harness/types.d.ts.map +1 -1
  95. package/dist/harness/verification.d.ts +7 -0
  96. package/dist/harness/verification.d.ts.map +1 -0
  97. package/dist/harness/verification.js +122 -0
  98. package/dist/harness/verification.js.map +1 -0
  99. package/dist/index.d.ts +5 -5
  100. package/dist/index.d.ts.map +1 -1
  101. package/dist/index.js +7 -1
  102. package/dist/index.js.map +1 -1
  103. package/dist/ink-ui/screens/ReplScreen.d.ts +3 -0
  104. package/dist/ink-ui/screens/ReplScreen.d.ts.map +1 -1
  105. package/dist/ink-ui/screens/ReplScreen.js +30 -5
  106. package/dist/ink-ui/screens/ReplScreen.js.map +1 -1
  107. package/dist/memory/index.d.ts +1 -0
  108. package/dist/memory/index.d.ts.map +1 -1
  109. package/dist/memory/index.js +1 -0
  110. package/dist/memory/index.js.map +1 -1
  111. package/dist/memory/prompt-context.d.ts +42 -0
  112. package/dist/memory/prompt-context.d.ts.map +1 -0
  113. package/dist/memory/prompt-context.js +129 -0
  114. package/dist/memory/prompt-context.js.map +1 -0
  115. package/dist/runtime/chat-compact.d.ts +26 -0
  116. package/dist/runtime/chat-compact.d.ts.map +1 -0
  117. package/dist/runtime/chat-compact.js +132 -0
  118. package/dist/runtime/chat-compact.js.map +1 -0
  119. package/dist/runtime/chat-controller.d.ts.map +1 -1
  120. package/dist/runtime/chat-controller.js +64 -74
  121. package/dist/runtime/chat-controller.js.map +1 -1
  122. package/dist/runtime/goals/coordinator.d.ts +3 -0
  123. package/dist/runtime/goals/coordinator.d.ts.map +1 -1
  124. package/dist/runtime/goals/coordinator.js +5 -15
  125. package/dist/runtime/goals/coordinator.js.map +1 -1
  126. package/dist/runtime/goals/prompt.js +1 -1
  127. package/dist/runtime/goals/prompt.js.map +1 -1
  128. package/dist/runtime/goals/stop-policy.d.ts +9 -0
  129. package/dist/runtime/goals/stop-policy.d.ts.map +1 -0
  130. package/dist/runtime/goals/stop-policy.js +83 -0
  131. package/dist/runtime/goals/stop-policy.js.map +1 -0
  132. package/dist/runtime/goals/types.d.ts +0 -1
  133. package/dist/runtime/goals/types.d.ts.map +1 -1
  134. package/dist/runtime/goals/types.js +0 -1
  135. package/dist/runtime/goals/types.js.map +1 -1
  136. package/dist/runtime/model-coordinator.d.ts +44 -1
  137. package/dist/runtime/model-coordinator.d.ts.map +1 -1
  138. package/dist/runtime/model-coordinator.js +161 -19
  139. package/dist/runtime/model-coordinator.js.map +1 -1
  140. package/dist/runtime/subagents/index.d.ts +1 -1
  141. package/dist/runtime/subagents/index.d.ts.map +1 -1
  142. package/dist/runtime/subagents/index.js.map +1 -1
  143. package/dist/runtime/subagents/production.d.ts +6 -2
  144. package/dist/runtime/subagents/production.d.ts.map +1 -1
  145. package/dist/runtime/subagents/production.js +25 -6
  146. package/dist/runtime/subagents/production.js.map +1 -1
  147. package/dist/runtime/subagents/runner.d.ts +12 -1
  148. package/dist/runtime/subagents/runner.d.ts.map +1 -1
  149. package/dist/runtime/subagents/runner.js +62 -1
  150. package/dist/runtime/subagents/runner.js.map +1 -1
  151. package/dist/runtime/subagents/runtime-integration.d.ts.map +1 -1
  152. package/dist/runtime/subagents/runtime-integration.js +2 -1
  153. package/dist/runtime/subagents/runtime-integration.js.map +1 -1
  154. package/dist/runtime/subagents/supervisor.d.ts.map +1 -1
  155. package/dist/runtime/subagents/supervisor.js +6 -0
  156. package/dist/runtime/subagents/supervisor.js.map +1 -1
  157. package/dist/runtime/subagents/types.d.ts +4 -1
  158. package/dist/runtime/subagents/types.d.ts.map +1 -1
  159. package/dist/runtime/subagents/types.js.map +1 -1
  160. package/dist/runtime/ui-events.d.ts +2 -0
  161. package/dist/runtime/ui-events.d.ts.map +1 -1
  162. package/dist/runtime/ui-events.js.map +1 -1
  163. package/dist/services/compact/auto-compact.d.ts +82 -2
  164. package/dist/services/compact/auto-compact.d.ts.map +1 -1
  165. package/dist/services/compact/auto-compact.js +226 -44
  166. package/dist/services/compact/auto-compact.js.map +1 -1
  167. package/dist/services/compact/compact.d.ts +54 -37
  168. package/dist/services/compact/compact.d.ts.map +1 -1
  169. package/dist/services/compact/compact.js +512 -127
  170. package/dist/services/compact/compact.js.map +1 -1
  171. package/dist/services/compact/coordinator.d.ts +5 -1
  172. package/dist/services/compact/coordinator.d.ts.map +1 -1
  173. package/dist/services/compact/coordinator.js +10 -1
  174. package/dist/services/compact/coordinator.js.map +1 -1
  175. package/dist/services/compact/fingerprint.d.ts +27 -0
  176. package/dist/services/compact/fingerprint.d.ts.map +1 -0
  177. package/dist/services/compact/fingerprint.js +69 -0
  178. package/dist/services/compact/fingerprint.js.map +1 -0
  179. package/dist/services/compact/index.d.ts +7 -5
  180. package/dist/services/compact/index.d.ts.map +1 -1
  181. package/dist/services/compact/index.js +19 -6
  182. package/dist/services/compact/index.js.map +1 -1
  183. package/dist/services/compact/planner.d.ts +41 -0
  184. package/dist/services/compact/planner.d.ts.map +1 -0
  185. package/dist/services/compact/planner.js +102 -0
  186. package/dist/services/compact/planner.js.map +1 -0
  187. package/dist/services/compact/semantic-summary.d.ts +93 -0
  188. package/dist/services/compact/semantic-summary.d.ts.map +1 -0
  189. package/dist/services/compact/semantic-summary.js +158 -0
  190. package/dist/services/compact/semantic-summary.js.map +1 -0
  191. package/dist/services/compact/summary-generator.d.ts +23 -0
  192. package/dist/services/compact/summary-generator.d.ts.map +1 -1
  193. package/dist/services/compact/summary-generator.js +173 -39
  194. package/dist/services/compact/summary-generator.js.map +1 -1
  195. package/dist/services/file-context.d.ts.map +1 -1
  196. package/dist/services/file-context.js +29 -33
  197. package/dist/services/file-context.js.map +1 -1
  198. package/dist/services/global-config.d.ts +6 -0
  199. package/dist/services/global-config.d.ts.map +1 -1
  200. package/dist/services/global-config.js +8 -0
  201. package/dist/services/global-config.js.map +1 -1
  202. package/dist/services/llm.d.ts +3 -0
  203. package/dist/services/llm.d.ts.map +1 -1
  204. package/dist/services/llm.js +7 -0
  205. package/dist/services/llm.js.map +1 -1
  206. package/dist/services/project-instructions.d.ts.map +1 -1
  207. package/dist/services/project-instructions.js +10 -17
  208. package/dist/services/project-instructions.js.map +1 -1
  209. package/dist/services/safe-project-reader.d.ts +30 -0
  210. package/dist/services/safe-project-reader.d.ts.map +1 -0
  211. package/dist/services/safe-project-reader.js +141 -0
  212. package/dist/services/safe-project-reader.js.map +1 -0
  213. package/dist/services/session-storage.d.ts +134 -5
  214. package/dist/services/session-storage.d.ts.map +1 -1
  215. package/dist/services/session-storage.js +727 -57
  216. package/dist/services/session-storage.js.map +1 -1
  217. package/dist/services/usage-state.d.ts +7 -0
  218. package/dist/services/usage-state.d.ts.map +1 -1
  219. package/dist/services/usage-state.js +117 -16
  220. package/dist/services/usage-state.js.map +1 -1
  221. package/dist/skills/runtime.d.ts.map +1 -1
  222. package/dist/skills/runtime.js +34 -35
  223. package/dist/skills/runtime.js.map +1 -1
  224. package/docs/migration/v0.1.8-to-v0.1.9.md +60 -0
  225. package/docs/plan/v0.1.9-release-checklist.md +64 -0
  226. package/docs/readme.md +27 -0
  227. package/npm-shrinkwrap.json +14 -38
  228. package/package.json +5 -1
  229. package/dist/services/compact/micro-compact.d.ts +0 -21
  230. package/dist/services/compact/micro-compact.d.ts.map +0 -1
  231. package/dist/services/compact/micro-compact.js +0 -99
  232. package/dist/services/compact/micro-compact.js.map +0 -1
@@ -11,6 +11,7 @@
11
11
  */
12
12
  Object.defineProperty(exports, "__esModule", { value: true });
13
13
  exports.QueryLoopError = exports.DEFAULT_LOOP_BUDGET = exports.DEFAULT_MAX_MODEL_VISIBLE_TOOL_RESULT_BYTES = void 0;
14
+ exports.withLoopFinishReason = withLoopFinishReason;
14
15
  exports.createLocalFastPathLoopStats = createLocalFastPathLoopStats;
15
16
  exports.createFailedLoopStats = createFailedLoopStats;
16
17
  exports.query = query;
@@ -18,12 +19,14 @@ const llm_1 = require("../services/llm");
18
19
  const tool_1 = require("./tool");
19
20
  const strategy_tracker_1 = require("../core/strategy-tracker");
20
21
  const auto_compact_1 = require("../services/compact/auto-compact");
22
+ const fingerprint_1 = require("../services/compact/fingerprint");
21
23
  const tool_call_groups_1 = require("../services/compact/tool-call-groups");
22
24
  const tool_scheduler_1 = require("./tool-scheduler");
23
25
  const token_estimate_1 = require("../utils/token-estimate");
24
26
  const tool_serializer_1 = require("./tool-serializer");
25
27
  const model_context_1 = require("../services/model-context");
26
28
  const tools_1 = require("../tools");
29
+ const stop_decision_1 = require("./stop-decision");
27
30
  exports.DEFAULT_MAX_MODEL_VISIBLE_TOOL_RESULT_BYTES = 4096;
28
31
  function isAborted(signal) {
29
32
  return signal?.aborted === true;
@@ -120,23 +123,152 @@ function createLoopStats() {
120
123
  localFastPathUsed: false,
121
124
  };
122
125
  }
123
- function cloneLoopStats(stats, finishReason) {
124
- return {
126
+ function stopDecisionForLoop(stats, finishReason) {
127
+ if (finishReason === 'compact_paused' && stats.compactFailure) {
128
+ const failure = stats.compactFailure;
129
+ return (0, stop_decision_1.createStopDecision)({
130
+ scope: 'request',
131
+ status: 'stopped',
132
+ disposition: 'pause_scope',
133
+ reason: { code: failure.code, message: failure.message },
134
+ evidence: [
135
+ {
136
+ kind: 'resource_limit',
137
+ source: `compact:${failure.mode}`,
138
+ detail: `${failure.beforeTokens} tokens before compact; ${failure.afterTokens ?? 'unknown'} after; target ${failure.targetTokens}.`,
139
+ },
140
+ ],
141
+ nextActions: [
142
+ { kind: 'inspect', label: 'Inspect current context pressure', command: '/context' },
143
+ { kind: 'change_input', label: 'Narrow or split the current instruction' },
144
+ { kind: 'raise_budget', label: 'Select a larger-context model or raise the budget' },
145
+ { kind: 'resume', label: 'Resume after changing context or budget', command: '继续' },
146
+ ],
147
+ resources: {
148
+ tokens: {
149
+ used: Math.max(0, Math.round(failure.afterTokens ?? failure.beforeTokens)),
150
+ limit: Math.max(0, Math.round(failure.targetTokens)),
151
+ },
152
+ },
153
+ });
154
+ }
155
+ const status = finishReason === 'completed'
156
+ ? 'completed'
157
+ : finishReason === 'cancelled'
158
+ ? 'cancelled'
159
+ : finishReason === 'failed'
160
+ ? 'failed'
161
+ : finishReason === 'blocked'
162
+ ? 'blocked'
163
+ : 'stopped';
164
+ const reasonCode = finishReason === 'budget_exceeded'
165
+ ? /LLM request budget/iu.test(stats.budgetExceededReason ?? '')
166
+ ? 'llm_request_budget'
167
+ : /tool call budget/iu.test(stats.budgetExceededReason ?? '')
168
+ ? 'tool_call_budget'
169
+ : /preflight|provider/iu.test(stats.budgetExceededReason ?? '')
170
+ ? 'provider_preflight_budget'
171
+ : 'resource_budget'
172
+ : finishReason;
173
+ const resumable = finishReason === 'budget_exceeded' ||
174
+ finishReason === 'completion_gate' ||
175
+ finishReason === 'blocked';
176
+ const evidence = [];
177
+ if (finishReason === 'budget_exceeded') {
178
+ evidence.push({
179
+ kind: 'resource_limit',
180
+ source: 'query',
181
+ detail: stats.budgetExceededReason ?? 'request resource budget reached',
182
+ });
183
+ }
184
+ if (stats.lastToolName) {
185
+ evidence.push({
186
+ kind: 'tool_boundary',
187
+ source: stats.lastToolName,
188
+ detail: stats.lastToolSummary ?? `last tool success=${String(stats.lastToolSuccess)}`,
189
+ });
190
+ }
191
+ const nextActions = [];
192
+ for (const action of stats.continuationActions ?? []) {
193
+ if (action === 'reply_continue') {
194
+ nextActions.push({ kind: 'continue', label: 'Continue the same objective', command: '继续' });
195
+ }
196
+ else if (action === 'raise_budget') {
197
+ nextActions.push({ kind: 'raise_budget', label: 'Raise the intentional loop budget' });
198
+ }
199
+ else if (action === 'inspect_loop_stats') {
200
+ nextActions.push({
201
+ kind: 'inspect',
202
+ label: 'Inspect loop statistics',
203
+ command: '/loop-stats',
204
+ });
205
+ }
206
+ else {
207
+ nextActions.push({ kind: 'change_input', label: 'Provide a narrower instruction' });
208
+ }
209
+ }
210
+ return (0, stop_decision_1.createStopDecision)({
211
+ scope: 'request',
212
+ status,
213
+ disposition: resumable ? 'resume_allowed' : 'finish_scope',
214
+ reason: {
215
+ code: reasonCode,
216
+ message: finishReason === 'budget_exceeded'
217
+ ? (stats.budgetExceededReason ?? 'Request resource budget reached')
218
+ : `Request finished with ${finishReason}`,
219
+ },
220
+ evidence,
221
+ nextActions,
222
+ resources: {
223
+ turns: { used: stats.turnsStarted },
224
+ llmRequests: {
225
+ used: stats.llmRequests,
226
+ ...(stats.loopBudgetMaxLlmRequests === undefined
227
+ ? {}
228
+ : { limit: stats.loopBudgetMaxLlmRequests }),
229
+ },
230
+ toolCalls: {
231
+ used: stats.toolCalls,
232
+ ...(stats.loopBudgetMaxToolCalls === undefined
233
+ ? {}
234
+ : { limit: stats.loopBudgetMaxToolCalls }),
235
+ },
236
+ modelVisibleToolBytes: {
237
+ used: stats.modelVisibleToolBytes,
238
+ ...(stats.loopBudgetMaxModelVisibleBytes === undefined
239
+ ? {}
240
+ : { limit: stats.loopBudgetMaxModelVisibleBytes }),
241
+ },
242
+ },
243
+ });
244
+ }
245
+ /** Rebuild terminal loop stats and its StopDecision as one atomic projection. */
246
+ function withLoopFinishReason(stats, finishReason) {
247
+ const resolvedReason = finishReason;
248
+ const cloned = {
125
249
  ...stats,
126
- finishReason: finishReason ?? stats.finishReason,
250
+ finishReason: resolvedReason,
127
251
  };
252
+ if (resolvedReason !== 'running')
253
+ cloned.stopDecision = stopDecisionForLoop(cloned, resolvedReason);
254
+ else
255
+ delete cloned.stopDecision;
256
+ return cloned;
257
+ }
258
+ function cloneLoopStats(stats, finishReason) {
259
+ return withLoopFinishReason(stats, finishReason ?? stats.finishReason);
128
260
  }
129
261
  function byteLength(text) {
130
262
  return Buffer.byteLength(text, 'utf8');
131
263
  }
132
264
  function createLocalFastPathLoopStats(overrides = {}) {
133
- return {
265
+ return cloneLoopStats({
134
266
  ...createLoopStats(),
135
267
  turnsStarted: 1,
136
268
  finishReason: 'completed',
137
269
  localFastPathUsed: true,
138
270
  ...overrides,
139
- };
271
+ });
140
272
  }
141
273
  function createFailedLoopStats(options = {}) {
142
274
  const { loopBudget, diagnostics, ...overrides } = options;
@@ -149,7 +281,7 @@ function createFailedLoopStats(options = {}) {
149
281
  };
150
282
  applyLoopBudgetStats(stats, resolveLoopBudget(loopBudget));
151
283
  applyLlmRequestDiagnostics(stats, diagnostics);
152
- return stats;
284
+ return cloneLoopStats(stats);
153
285
  }
154
286
  function isLoopBudgetSource(value) {
155
287
  return value === 'default' || value === 'complex' || value === 'release' || value === 'config';
@@ -404,18 +536,44 @@ function omitModelVisibleToolResult(executed, maxAggregateBytes) {
404
536
  summarizedBytes: Math.max(0, fullBytes - bytes),
405
537
  };
406
538
  }
539
+ function queryCompactCommit(mode, result, before, after, prepareSource, semanticHarnessState) {
540
+ return {
541
+ mode,
542
+ modelHistory: result.messages.map(message => ({ ...message })),
543
+ summary: {
544
+ text: result.summary,
545
+ generatedAt: result.summaryGeneratedAt,
546
+ source: result.summarySource,
547
+ },
548
+ before,
549
+ after,
550
+ prepareSource,
551
+ semanticHarnessState,
552
+ fingerprint: result.fingerprint,
553
+ beforeTokens: result.beforeTokens,
554
+ afterTokens: result.afterTokens,
555
+ plan: structuredClone(result.plan),
556
+ semanticSummary: structuredClone(result.semanticSummary),
557
+ diagnostics: result.diagnostics.map(diagnostic => ({ ...diagnostic })),
558
+ };
559
+ }
407
560
  function attachCompactCommit(event, compact, messages, usage) {
408
561
  const eventWithUsage = usage ? { ...event, usage: { ...usage } } : event;
409
562
  return compact
410
563
  ? {
411
564
  ...eventWithUsage,
412
- compact: {
413
- ...compact,
414
- modelHistory: messages.map(message => ({ ...message })),
415
- },
565
+ compact: bindCompactCommitToHistory(compact, messages),
416
566
  }
417
567
  : eventWithUsage;
418
568
  }
569
+ function bindCompactCommitToHistory(compact, messages) {
570
+ const modelHistory = messages.map(message => ({ ...message }));
571
+ return {
572
+ ...compact,
573
+ modelHistory,
574
+ afterTokens: (0, token_estimate_1.estimateMessagesTokens)(modelHistory),
575
+ };
576
+ }
419
577
  function publishContextUsage(params, autoCompact, modelId, usedTokens, source = 'estimated') {
420
578
  const stats = autoCompact.getStats();
421
579
  const usage = (0, model_context_1.createContextUsageSnapshot)({
@@ -443,6 +601,57 @@ function publishAutoCompact(callback, notice) {
443
601
  // Runtime observers must never break autonomous compaction.
444
602
  }
445
603
  }
604
+ function validateFinalCompactRequest(result, autoCompact, modelId, harness, messagesForHarness, input) {
605
+ const assembled = harness
606
+ ? harness.assembleMessages(result.messages, {
607
+ input,
608
+ tools: messagesForHarness,
609
+ })
610
+ : result.messages;
611
+ const estimatedTokens = (0, token_estimate_1.estimateMessagesTokens)(assembled);
612
+ const observedTokens = autoCompact.adjustTokenEstimate(estimatedTokens, modelId);
613
+ const compactStats = autoCompact.getStats();
614
+ const targetTokens = Math.max(1, Math.floor(compactStats.safeInputBudget * compactStats.targetRatio));
615
+ if (observedTokens <= targetTokens)
616
+ return { valid: true, observedTokens, targetTokens };
617
+ return {
618
+ valid: false,
619
+ code: 'no_headroom',
620
+ message: `Final assembled request uses ${observedTokens} tokens after compact; safe target is ${targetTokens}.`,
621
+ observedTokens,
622
+ targetTokens,
623
+ };
624
+ }
625
+ function failureForUnchangedCompactAttempt(attempt, autoCompact) {
626
+ const compactStats = autoCompact.getStats();
627
+ const beforeTokens = (0, token_estimate_1.estimateMessagesTokens)(attempt.messages);
628
+ return {
629
+ code: attempt.status === 'duplicate' ? 'context_thrash' : 'no_headroom',
630
+ message: attempt.status === 'duplicate'
631
+ ? 'The same high-pressure context reached compact again without new durable progress.'
632
+ : 'Compact could not reduce the high-pressure context, so the request was paused.',
633
+ mode: attempt.mode,
634
+ fingerprint: attempt.fingerprint,
635
+ consecutiveNoProgressAttempts: attempt.consecutiveNoProgressAttempts,
636
+ beforeTokens,
637
+ afterTokens: beforeTokens,
638
+ safeInputBudget: compactStats.safeInputBudget,
639
+ targetTokens: Math.max(1, Math.floor(compactStats.safeInputBudget * compactStats.targetRatio)),
640
+ };
641
+ }
642
+ function compactPausedEvent(llm, stats, failure, content) {
643
+ stats.compactFailure = {
644
+ ...failure,
645
+ validationErrors: failure.validationErrors?.map(error => ({ ...error })),
646
+ };
647
+ return {
648
+ type: 'complete',
649
+ content: content ??
650
+ `Context compaction paused this request: ${failure.message} Change context or budget, then resume.`,
651
+ model: llm.getModel(),
652
+ stats: cloneLoopStats(stats, 'compact_paused'),
653
+ };
654
+ }
446
655
  // ============================================================================
447
656
  // query() — async generator
448
657
  // ============================================================================
@@ -462,19 +671,49 @@ function publishAutoCompact(callback, notice) {
462
671
  * }
463
672
  */
464
673
  async function* query(params) {
465
- const { messages, tools, toolExecutor, llm, maxTurns, // 无默认值,可选参数
466
- abortSignal, streamCallbacks, costTracker, strategyTracker = (0, strategy_tracker_1.createStrategyTracker)({ maxAttempts: 5 }), // 增加到 5 次
674
+ const { messages, tools, toolExecutor, llm, abortSignal, streamCallbacks, costTracker, strategyTracker = (0, strategy_tracker_1.createStrategyTracker)({ maxAttempts: 5 }), // 增加到 5 次
467
675
  harness, input, maxParallelToolCalls = 6, } = params;
468
676
  const openaiTools = (0, tool_1.toOpenAITools)(tools);
469
677
  let turn = 0;
470
678
  let consecutiveCompletionGateBlocks = 0;
471
679
  const stats = createLoopStats();
472
680
  let pendingCompact;
681
+ let compactPrepareSource;
682
+ const captureCompactPrepareSource = () => {
683
+ if (compactPrepareSource)
684
+ return compactPrepareSource;
685
+ try {
686
+ compactPrepareSource = params.onCompactPrepare?.();
687
+ }
688
+ catch {
689
+ // Candidate preparation may continue in memory, but persistence will fail
690
+ // closed because semantic checkpoint commits require this receipt.
691
+ compactPrepareSource = undefined;
692
+ }
693
+ return compactPrepareSource;
694
+ };
473
695
  let aggregateUsage;
474
- let loopBudget = resolveLoopBudget(params.loopBudget);
696
+ // Preserve the old option as a resource-budget alias. It no longer emits a
697
+ // task-like `max_turns` completion or claims that the objective completed.
698
+ const legacyRequestBudget = typeof params.maxTurns === 'number' && Number.isFinite(params.maxTurns) && params.maxTurns > 0
699
+ ? Math.floor(params.maxTurns)
700
+ : undefined;
701
+ let loopBudget = resolveLoopBudget({
702
+ ...params.loopBudget,
703
+ ...(params.loopBudget?.maxLlmRequestsPerUserTurn === undefined && legacyRequestBudget
704
+ ? { maxLlmRequestsPerUserTurn: legacyRequestBudget }
705
+ : {}),
706
+ });
475
707
  applyLoopBudgetStats(stats, loopBudget);
476
708
  const maxModelVisibleToolResultBytes = Math.max(512, params.maxModelVisibleToolResultBytes ?? exports.DEFAULT_MAX_MODEL_VISIBLE_TOOL_RESULT_BYTES);
477
709
  const fragmentedReadOnlyTools = new Set(tools_1.BATCH_READ_ALLOWED_TOOLS);
710
+ harness?.updateCapabilityProfile?.({
711
+ modelId: llm.getModel(),
712
+ contextWindow: (0, model_context_1.getModelContextWindow)(llm.getModel()),
713
+ permissionMode: params.permissionMode ?? 'default',
714
+ toolConfirmation: params.toolConfirmation ?? 'allow',
715
+ tools: tools.map(tool => tool.name),
716
+ });
478
717
  // 无限循环,依赖安全机制停止
479
718
  while (true) {
480
719
  turn++;
@@ -483,16 +722,6 @@ async function* query(params) {
483
722
  yield attachCompactCommit(cancelledCompleteEvent(llm, stats), pendingCompact, messages, aggregateUsage);
484
723
  return;
485
724
  }
486
- // Safety valve: check maxTurns if specified (optional)
487
- if (maxTurns && turn > maxTurns) {
488
- yield attachCompactCommit({
489
- type: 'complete',
490
- content: `Reached maximum turns (${maxTurns}). Task may be incomplete.`,
491
- model: llm.getModel(),
492
- stats: cloneLoopStats(stats, 'max_turns'),
493
- }, pendingCompact, messages, aggregateUsage);
494
- return;
495
- }
496
725
  if (shouldPromoteDefaultBudget(stats, loopBudget)) {
497
726
  loopBudget = promoteDefaultBudgetToComplex(loopBudget);
498
727
  applyLoopBudgetStats(stats, loopBudget);
@@ -532,8 +761,27 @@ async function* query(params) {
532
761
  const predictedTokens = autoCompact.adjustTokenEstimate(requestEstimatedTokens, llm.getModel());
533
762
  const contextBeforePredictiveCompact = publishContextUsage(params, autoCompact, llm.getModel(), predictedTokens, autoCompact.hasProviderCalibration(llm.getModel()) ? 'provider_adjusted' : 'estimated');
534
763
  const preCompactObjective = harness?.getCapsule()?.contract?.objective;
535
- const preCompacted = await autoCompact.checkPredictiveAndCompact(messages, predictedTokens);
536
- if (preCompacted !== messages) {
764
+ const compactToolDescriptions = tools.map(tool => ({
765
+ name: tool.name,
766
+ description: tool.description,
767
+ }));
768
+ const predictiveStats = autoCompact.getStats();
769
+ if (predictiveStats.enabled &&
770
+ predictedTokens / Math.max(1, predictiveStats.safeInputBudget) >=
771
+ predictiveStats.predictiveCompactThreshold) {
772
+ captureCompactPrepareSource();
773
+ }
774
+ const preCompactAttempt = await autoCompact.checkPredictiveCompactOutcome(messages, predictedTokens, result => validateFinalCompactRequest(result, autoCompact, llm.getModel(), harness, compactToolDescriptions, input));
775
+ if (preCompactAttempt.status === 'paused') {
776
+ yield attachCompactCommit(compactPausedEvent(llm, stats, preCompactAttempt.failure), pendingCompact, messages, aggregateUsage);
777
+ return;
778
+ }
779
+ if (preCompactAttempt.status === 'duplicate' || preCompactAttempt.status === 'rejected') {
780
+ yield attachCompactCommit(compactPausedEvent(llm, stats, failureForUnchangedCompactAttempt(preCompactAttempt, autoCompact)), pendingCompact, messages, aggregateUsage);
781
+ return;
782
+ }
783
+ const preCompacted = preCompactAttempt.messages;
784
+ if (preCompactAttempt.status === 'compacted') {
537
785
  stats.compactTrigger = 'pre_turn';
538
786
  messages.length = 0;
539
787
  messages.push(...preCompacted);
@@ -556,20 +804,7 @@ async function* query(params) {
556
804
  const compactedTokens = autoCompact.adjustTokenEstimate(requestEstimatedTokens, llm.getModel());
557
805
  autoCompact.getCtxPercent(compactedTokens);
558
806
  const contextAfterPredictiveCompact = publishContextUsage(params, autoCompact, llm.getModel(), compactedTokens, autoCompact.hasProviderCalibration(llm.getModel()) ? 'provider_adjusted' : 'estimated');
559
- const result = autoCompact.getLastCompactResult();
560
- if (result) {
561
- pendingCompact = {
562
- mode: 'predictive',
563
- modelHistory: result.messages.map(message => ({ ...message })),
564
- summary: {
565
- text: result.summary,
566
- generatedAt: result.summaryGeneratedAt,
567
- source: result.summarySource,
568
- },
569
- before: contextBeforePredictiveCompact,
570
- after: contextAfterPredictiveCompact,
571
- };
572
- }
807
+ pendingCompact = queryCompactCommit('predictive', preCompactAttempt.result, contextBeforePredictiveCompact, contextAfterPredictiveCompact, compactPrepareSource, harness?.toJSON());
573
808
  publishAutoCompact(params.onAutoCompact, {
574
809
  mode: 'predictive',
575
810
  before: contextBeforePredictiveCompact,
@@ -591,7 +826,25 @@ async function* query(params) {
591
826
  omittedEvidence: compactPromptEvidence(assemblyStats.omittedEvidence, 8),
592
827
  includedEvidenceCount: assemblyStats.includedEvidence.length,
593
828
  omittedEvidenceCount: assemblyStats.omittedEvidence.length,
829
+ sectionManifest: assemblyStats.sectionManifest?.map(item => ({ ...item })) ?? [],
830
+ overBudget: assemblyStats.overBudget === true,
831
+ capabilityProfileVersion: assemblyStats.capabilityProfileVersion,
832
+ capabilityProfileFingerprint: assemblyStats.capabilityProfileFingerprint,
594
833
  };
834
+ if (assemblyStats.overBudget) {
835
+ yield attachCompactCommit(compactPausedEvent(llm, stats, {
836
+ code: 'mandatory_context_over_budget',
837
+ message: `Mandatory Harness context uses ${assemblyStats.estimatedTokens} tokens; its atomic section budget is ${assemblyStats.budgetTokens}.`,
838
+ mode: 'predictive',
839
+ fingerprint: (0, fingerprint_1.canonicalMessagesFingerprint)(requestMessages),
840
+ consecutiveNoProgressAttempts: 1,
841
+ beforeTokens: assemblyStats.estimatedTokens,
842
+ afterTokens: assemblyStats.estimatedTokens,
843
+ safeInputBudget: assemblyStats.budgetTokens,
844
+ targetTokens: assemblyStats.budgetTokens,
845
+ }, 'Mandatory task context does not fit its atomic prompt budget. Narrow the contract or choose a larger-context model, then resume.'), pendingCompact, messages, aggregateUsage);
846
+ return;
847
+ }
595
848
  }
596
849
  if (isAborted(abortSignal)) {
597
850
  yield attachCompactCommit(cancelledCompleteEvent(llm, stats), pendingCompact, messages, aggregateUsage);
@@ -881,11 +1134,15 @@ async function* query(params) {
881
1134
  const missing = completionGate.missing?.length
882
1135
  ? completionGate.missing.join('; ')
883
1136
  : 'required verification evidence is missing';
1137
+ const stoppedStats = cloneLoopStats(stats, 'completion_gate');
1138
+ if (completionGate.stopDecision) {
1139
+ stoppedStats.stopDecision = completionGate.stopDecision;
1140
+ }
884
1141
  yield attachCompactCommit({
885
1142
  type: 'complete',
886
1143
  content: `Completion gate stopped this turn: ${missing}\nRun the required verification, then continue.`,
887
1144
  model: response.model || llm.getModel(),
888
- stats: cloneLoopStats(stats, 'completion_gate'),
1145
+ stats: stoppedStats,
889
1146
  }, pendingCompact, messages, aggregateUsage);
890
1147
  return;
891
1148
  }
@@ -908,8 +1165,26 @@ async function* query(params) {
908
1165
  const contextBeforeThresholdCompact = publishContextUsage(params, autoCompact, response.model || llm.getModel(), currentContextTokens, autoCompact.hasProviderCalibration(response.model || llm.getModel())
909
1166
  ? 'provider_adjusted'
910
1167
  : 'estimated');
911
- const compacted = await autoCompact.checkAndCompact(messages, currentContextTokens);
912
- if (compacted !== messages) {
1168
+ const validatePostCompact = (result) => validateFinalCompactRequest(result, autoCompact, response.model || llm.getModel(), harness, compactToolDescriptions, input);
1169
+ const thresholdStats = autoCompact.getStats();
1170
+ if (!pendingCompact &&
1171
+ thresholdStats.enabled &&
1172
+ currentContextTokens / Math.max(1, thresholdStats.safeInputBudget) >= thresholdStats.threshold) {
1173
+ captureCompactPrepareSource();
1174
+ }
1175
+ const postCompactAttempt = pendingCompact
1176
+ ? await autoCompact.ensureHeadroomAndCompactOutcome(messages, currentContextTokens, validatePostCompact)
1177
+ : await autoCompact.checkAndCompactOutcome(messages, currentContextTokens, validatePostCompact);
1178
+ if (postCompactAttempt.status === 'paused') {
1179
+ yield attachCompactCommit(compactPausedEvent(llm, stats, postCompactAttempt.failure, response.content), pendingCompact, messages, aggregateUsage);
1180
+ return;
1181
+ }
1182
+ if (postCompactAttempt.status === 'duplicate' || postCompactAttempt.status === 'rejected') {
1183
+ yield attachCompactCommit(compactPausedEvent(llm, stats, failureForUnchangedCompactAttempt(postCompactAttempt, autoCompact), response.content), pendingCompact, messages, aggregateUsage);
1184
+ return;
1185
+ }
1186
+ const compacted = postCompactAttempt.messages;
1187
+ if (postCompactAttempt.status === 'compacted') {
913
1188
  stats.compactTrigger = stats.compactTrigger ?? 'post_turn';
914
1189
  messages.length = 0;
915
1190
  messages.push(...compacted);
@@ -919,20 +1194,7 @@ async function* query(params) {
919
1194
  const contextAfterThresholdCompact = publishContextUsage(params, autoCompact, response.model || llm.getModel(), compactedTokens, autoCompact.hasProviderCalibration(response.model || llm.getModel())
920
1195
  ? 'provider_adjusted'
921
1196
  : 'estimated');
922
- const result = autoCompact.getLastCompactResult();
923
- if (result) {
924
- pendingCompact = {
925
- mode: 'threshold',
926
- modelHistory: result.messages.map(message => ({ ...message })),
927
- summary: {
928
- text: result.summary,
929
- generatedAt: result.summaryGeneratedAt,
930
- source: result.summarySource,
931
- },
932
- before: contextBeforeThresholdCompact,
933
- after: contextAfterThresholdCompact,
934
- };
935
- }
1197
+ pendingCompact = queryCompactCommit(pendingCompact?.mode ?? 'threshold', postCompactAttempt.result, contextBeforeThresholdCompact, contextAfterThresholdCompact, pendingCompact?.prepareSource ?? compactPrepareSource, pendingCompact?.semanticHarnessState ?? harness?.toJSON());
936
1198
  publishAutoCompact(params.onAutoCompact, {
937
1199
  mode: 'threshold',
938
1200
  before: contextBeforeThresholdCompact,
@@ -951,12 +1213,7 @@ async function* query(params) {
951
1213
  usage: aggregateUsage,
952
1214
  model: response.model,
953
1215
  stats: cloneLoopStats(stats, 'completed'),
954
- compact: pendingCompact
955
- ? {
956
- ...pendingCompact,
957
- modelHistory: messages.map(message => ({ ...message })),
958
- }
959
- : undefined,
1216
+ compact: pendingCompact ? bindCompactCommitToHistory(pendingCompact, messages) : undefined,
960
1217
  };
961
1218
  return;
962
1219
  }