open-multi-agent-kit 0.99.0 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (271) hide show
  1. package/CHANGELOG.md +24 -0
  2. package/README.md +3 -3
  3. package/dist/bun/cli.d.ts.map +1 -1
  4. package/dist/bun/cli.js +1 -0
  5. package/dist/bun/cli.js.map +1 -1
  6. package/dist/bun/register-bundled-coding-agent.d.ts +10 -0
  7. package/dist/bun/register-bundled-coding-agent.d.ts.map +1 -0
  8. package/dist/bun/register-bundled-coding-agent.js +12 -0
  9. package/dist/bun/register-bundled-coding-agent.js.map +1 -0
  10. package/dist/cli/args.d.ts +1 -1
  11. package/dist/cli/args.d.ts.map +1 -1
  12. package/dist/cli/args.js +1 -1
  13. package/dist/cli/args.js.map +1 -1
  14. package/dist/cli/help.d.ts.map +1 -1
  15. package/dist/cli/help.js +1 -1
  16. package/dist/cli/help.js.map +1 -1
  17. package/dist/cli.d.ts.map +1 -1
  18. package/dist/cli.js +14 -2
  19. package/dist/cli.js.map +1 -1
  20. package/dist/commands/neo-cli.d.ts +9 -0
  21. package/dist/commands/neo-cli.d.ts.map +1 -0
  22. package/dist/commands/neo-cli.js +61 -0
  23. package/dist/commands/neo-cli.js.map +1 -0
  24. package/dist/core/agent-session.d.ts +29 -2
  25. package/dist/core/agent-session.d.ts.map +1 -1
  26. package/dist/core/agent-session.js +107 -30
  27. package/dist/core/agent-session.js.map +1 -1
  28. package/dist/core/bundled-skills.d.ts +4 -0
  29. package/dist/core/bundled-skills.d.ts.map +1 -0
  30. package/dist/core/bundled-skills.js +32 -0
  31. package/dist/core/bundled-skills.js.map +1 -0
  32. package/dist/core/cli-diagnostics.d.ts +6 -0
  33. package/dist/core/cli-diagnostics.d.ts.map +1 -0
  34. package/dist/core/cli-diagnostics.js +20 -0
  35. package/dist/core/cli-diagnostics.js.map +1 -0
  36. package/dist/core/context-budget-headroom.d.ts +12 -0
  37. package/dist/core/context-budget-headroom.d.ts.map +1 -1
  38. package/dist/core/context-budget-headroom.js +35 -0
  39. package/dist/core/context-budget-headroom.js.map +1 -1
  40. package/dist/core/context-budget-v2-input-validation.d.ts +4 -0
  41. package/dist/core/context-budget-v2-input-validation.d.ts.map +1 -0
  42. package/dist/core/context-budget-v2-input-validation.js +79 -0
  43. package/dist/core/context-budget-v2-input-validation.js.map +1 -0
  44. package/dist/core/context-budget-v2-observability.d.ts +15 -0
  45. package/dist/core/context-budget-v2-observability.d.ts.map +1 -0
  46. package/dist/core/context-budget-v2-observability.js +35 -0
  47. package/dist/core/context-budget-v2-observability.js.map +1 -0
  48. package/dist/core/context-budget-v2-planned-items.d.ts +5 -0
  49. package/dist/core/context-budget-v2-planned-items.d.ts.map +1 -0
  50. package/dist/core/context-budget-v2-planned-items.js +40 -0
  51. package/dist/core/context-budget-v2-planned-items.js.map +1 -0
  52. package/dist/core/context-budget-v2-planner.d.ts.map +1 -1
  53. package/dist/core/context-budget-v2-planner.js +57 -38
  54. package/dist/core/context-budget-v2-planner.js.map +1 -1
  55. package/dist/core/context-budget-v2-selection.d.ts +19 -3
  56. package/dist/core/context-budget-v2-selection.d.ts.map +1 -1
  57. package/dist/core/context-budget-v2-selection.js +35 -57
  58. package/dist/core/context-budget-v2-selection.js.map +1 -1
  59. package/dist/core/context-budget-v2-tiers.d.ts.map +1 -1
  60. package/dist/core/context-budget-v2-tiers.js +9 -42
  61. package/dist/core/context-budget-v2-tiers.js.map +1 -1
  62. package/dist/core/context-budget-v2-types.d.ts +8 -1
  63. package/dist/core/context-budget-v2-types.d.ts.map +1 -1
  64. package/dist/core/context-budget-v2-types.js.map +1 -1
  65. package/dist/core/extensions/bundled-virtual-modules.d.ts +15 -0
  66. package/dist/core/extensions/bundled-virtual-modules.d.ts.map +1 -0
  67. package/dist/core/extensions/bundled-virtual-modules.js +63 -0
  68. package/dist/core/extensions/bundled-virtual-modules.js.map +1 -0
  69. package/dist/core/extensions/loader.d.ts.map +1 -1
  70. package/dist/core/extensions/loader.js +2 -42
  71. package/dist/core/extensions/loader.js.map +1 -1
  72. package/dist/core/extensions/runner.d.ts +1 -0
  73. package/dist/core/extensions/runner.d.ts.map +1 -1
  74. package/dist/core/extensions/runner.js +6 -0
  75. package/dist/core/extensions/runner.js.map +1 -1
  76. package/dist/core/extensions/types.d.ts +10 -0
  77. package/dist/core/extensions/types.d.ts.map +1 -1
  78. package/dist/core/extensions/types.js.map +1 -1
  79. package/dist/core/index.d.ts +2 -1
  80. package/dist/core/index.d.ts.map +1 -1
  81. package/dist/core/index.js +2 -1
  82. package/dist/core/index.js.map +1 -1
  83. package/dist/core/loadout-runtime.d.ts +2 -8
  84. package/dist/core/loadout-runtime.d.ts.map +1 -1
  85. package/dist/core/loadout-runtime.js.map +1 -1
  86. package/dist/core/mcp/client.d.ts +27 -6
  87. package/dist/core/mcp/client.d.ts.map +1 -1
  88. package/dist/core/mcp/client.js +80 -20
  89. package/dist/core/mcp/client.js.map +1 -1
  90. package/dist/core/mcp/manager.d.ts +10 -1
  91. package/dist/core/mcp/manager.d.ts.map +1 -1
  92. package/dist/core/mcp/manager.js +68 -9
  93. package/dist/core/mcp/manager.js.map +1 -1
  94. package/dist/core/mcp/protocol.d.ts +9 -3
  95. package/dist/core/mcp/protocol.d.ts.map +1 -1
  96. package/dist/core/mcp/protocol.js +61 -15
  97. package/dist/core/mcp/protocol.js.map +1 -1
  98. package/dist/core/mcp/stdio-transport.d.ts +12 -1
  99. package/dist/core/mcp/stdio-transport.d.ts.map +1 -1
  100. package/dist/core/mcp/stdio-transport.js +30 -2
  101. package/dist/core/mcp/stdio-transport.js.map +1 -1
  102. package/dist/core/mcp-descriptor-injection.d.ts +26 -0
  103. package/dist/core/mcp-descriptor-injection.d.ts.map +1 -0
  104. package/dist/core/mcp-descriptor-injection.js +25 -0
  105. package/dist/core/mcp-descriptor-injection.js.map +1 -0
  106. package/dist/core/mcp-public-presets.d.ts +1 -3
  107. package/dist/core/mcp-public-presets.d.ts.map +1 -1
  108. package/dist/core/mcp-public-presets.js +3 -15
  109. package/dist/core/mcp-public-presets.js.map +1 -1
  110. package/dist/core/model-registry.d.ts.map +1 -1
  111. package/dist/core/model-registry.js +24 -3
  112. package/dist/core/model-registry.js.map +1 -1
  113. package/dist/core/neo/catalog.d.ts +20 -0
  114. package/dist/core/neo/catalog.d.ts.map +1 -0
  115. package/dist/core/neo/catalog.js +50 -0
  116. package/dist/core/neo/catalog.js.map +1 -0
  117. package/dist/core/neo/setup.d.ts +3 -0
  118. package/dist/core/neo/setup.d.ts.map +1 -0
  119. package/dist/core/neo/setup.js +47 -0
  120. package/dist/core/neo/setup.js.map +1 -0
  121. package/dist/core/provider-default-models.d.ts +1 -0
  122. package/dist/core/provider-default-models.d.ts.map +1 -1
  123. package/dist/core/provider-default-models.js +1 -0
  124. package/dist/core/provider-default-models.js.map +1 -1
  125. package/dist/core/provider-display-names.d.ts.map +1 -1
  126. package/dist/core/provider-display-names.js +1 -0
  127. package/dist/core/provider-display-names.js.map +1 -1
  128. package/dist/core/provider-error-classification.d.ts +57 -0
  129. package/dist/core/provider-error-classification.d.ts.map +1 -0
  130. package/dist/core/provider-error-classification.js +103 -0
  131. package/dist/core/provider-error-classification.js.map +1 -0
  132. package/dist/core/provider-resilience.d.ts +10 -0
  133. package/dist/core/provider-resilience.d.ts.map +1 -1
  134. package/dist/core/provider-resilience.js +36 -3
  135. package/dist/core/provider-resilience.js.map +1 -1
  136. package/dist/core/provider-usage-commandcode.d.ts +9 -0
  137. package/dist/core/provider-usage-commandcode.d.ts.map +1 -0
  138. package/dist/core/provider-usage-commandcode.js +198 -0
  139. package/dist/core/provider-usage-commandcode.js.map +1 -0
  140. package/dist/core/provider-usage-devin.d.ts +5 -3
  141. package/dist/core/provider-usage-devin.d.ts.map +1 -1
  142. package/dist/core/provider-usage-devin.js +15 -5
  143. package/dist/core/provider-usage-devin.js.map +1 -1
  144. package/dist/core/provider-usage-types.d.ts +1 -1
  145. package/dist/core/provider-usage-types.d.ts.map +1 -1
  146. package/dist/core/provider-usage-types.js.map +1 -1
  147. package/dist/core/provider-usage.d.ts.map +1 -1
  148. package/dist/core/provider-usage.js +6 -0
  149. package/dist/core/provider-usage.js.map +1 -1
  150. package/dist/core/resource-admission.d.ts +36 -0
  151. package/dist/core/resource-admission.d.ts.map +1 -1
  152. package/dist/core/resource-admission.js +59 -0
  153. package/dist/core/resource-admission.js.map +1 -1
  154. package/dist/core/resource-loader.d.ts.map +1 -1
  155. package/dist/core/resource-loader.js +2 -2
  156. package/dist/core/resource-loader.js.map +1 -1
  157. package/dist/core/run-usage-ledger.d.ts +47 -0
  158. package/dist/core/run-usage-ledger.d.ts.map +1 -0
  159. package/dist/core/run-usage-ledger.js +162 -0
  160. package/dist/core/run-usage-ledger.js.map +1 -0
  161. package/dist/core/run-usage-operation.d.ts +8 -0
  162. package/dist/core/run-usage-operation.d.ts.map +1 -0
  163. package/dist/core/run-usage-operation.js +12 -0
  164. package/dist/core/run-usage-operation.js.map +1 -0
  165. package/dist/core/sdk.d.ts.map +1 -1
  166. package/dist/core/sdk.js +5 -6
  167. package/dist/core/sdk.js.map +1 -1
  168. package/dist/core/session-failure-cause.d.ts.map +1 -1
  169. package/dist/core/session-failure-cause.js +14 -5
  170. package/dist/core/session-failure-cause.js.map +1 -1
  171. package/dist/core/session-prompt-lifecycle.d.ts +6 -0
  172. package/dist/core/session-prompt-lifecycle.d.ts.map +1 -1
  173. package/dist/core/session-prompt-lifecycle.js +47 -2
  174. package/dist/core/session-prompt-lifecycle.js.map +1 -1
  175. package/dist/core/session-termination.d.ts.map +1 -1
  176. package/dist/core/session-termination.js +4 -2
  177. package/dist/core/session-termination.js.map +1 -1
  178. package/dist/core/subagent-lane-authority.d.ts +28 -0
  179. package/dist/core/subagent-lane-authority.d.ts.map +1 -0
  180. package/dist/core/subagent-lane-authority.js +119 -0
  181. package/dist/core/subagent-lane-authority.js.map +1 -0
  182. package/dist/core/subagent-lane-contract.d.ts +114 -0
  183. package/dist/core/subagent-lane-contract.d.ts.map +1 -0
  184. package/dist/core/subagent-lane-contract.js +18 -0
  185. package/dist/core/subagent-lane-contract.js.map +1 -0
  186. package/dist/core/subagent-lane-launcher.d.ts +3 -6
  187. package/dist/core/subagent-lane-launcher.d.ts.map +1 -1
  188. package/dist/core/subagent-lane-launcher.js +53 -12
  189. package/dist/core/subagent-lane-launcher.js.map +1 -1
  190. package/dist/core/subagent-orchestration.d.ts +4 -17
  191. package/dist/core/subagent-orchestration.d.ts.map +1 -1
  192. package/dist/core/subagent-orchestration.js.map +1 -1
  193. package/dist/core/verified-run/broker.d.ts.map +1 -1
  194. package/dist/core/verified-run/broker.js +4 -1
  195. package/dist/core/verified-run/broker.js.map +1 -1
  196. package/dist/core/workload-permit-pool.d.ts +1 -1
  197. package/dist/core/workload-permit-pool.d.ts.map +1 -1
  198. package/dist/core/workload-permit-pool.js +3 -0
  199. package/dist/core/workload-permit-pool.js.map +1 -1
  200. package/dist/guardrails/strict-evidence-approval-adapter.d.ts +34 -0
  201. package/dist/guardrails/strict-evidence-approval-adapter.d.ts.map +1 -0
  202. package/dist/guardrails/strict-evidence-approval-adapter.js +70 -0
  203. package/dist/guardrails/strict-evidence-approval-adapter.js.map +1 -0
  204. package/dist/index.d.ts +3 -0
  205. package/dist/index.d.ts.map +1 -1
  206. package/dist/index.js +1 -0
  207. package/dist/index.js.map +1 -1
  208. package/dist/main.d.ts.map +1 -1
  209. package/dist/main.js +11 -18
  210. package/dist/main.js.map +1 -1
  211. package/dist/modes/acp/acp-agent.d.ts +24 -0
  212. package/dist/modes/acp/acp-agent.d.ts.map +1 -0
  213. package/dist/modes/acp/acp-agent.js +133 -0
  214. package/dist/modes/acp/acp-agent.js.map +1 -0
  215. package/dist/modes/acp/acp-mode.d.ts +4 -0
  216. package/dist/modes/acp/acp-mode.d.ts.map +1 -0
  217. package/dist/modes/acp/acp-mode.js +34 -0
  218. package/dist/modes/acp/acp-mode.js.map +1 -0
  219. package/dist/modes/acp/acp-session.d.ts +4 -0
  220. package/dist/modes/acp/acp-session.d.ts.map +1 -0
  221. package/dist/modes/acp/acp-session.js +76 -0
  222. package/dist/modes/acp/acp-session.js.map +1 -0
  223. package/dist/modes/acp/acp-transport.d.ts +5 -0
  224. package/dist/modes/acp/acp-transport.d.ts.map +1 -0
  225. package/dist/modes/acp/acp-transport.js +90 -0
  226. package/dist/modes/acp/acp-transport.js.map +1 -0
  227. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  228. package/dist/modes/interactive/interactive-mode.js +1 -0
  229. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  230. package/docs/audit-revalidation-2026-09-17.md +77 -0
  231. package/docs/devin-harness.md +33 -4
  232. package/docs/ecraf-normalization.md +83 -0
  233. package/docs/model-catalog-refresh.md +51 -1
  234. package/docs/models.md +1 -1
  235. package/docs/neo.md +134 -0
  236. package/docs/providers.md +72 -6
  237. package/docs/run-usage-ledger.md +56 -0
  238. package/docs/runtime-algorithms.md +44 -0
  239. package/docs/skills.md +1 -1
  240. package/docs/usage.md +2 -1
  241. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  242. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  243. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  244. package/examples/extensions/gondolin/package-lock.json +2 -2
  245. package/examples/extensions/gondolin/package.json +1 -1
  246. package/examples/extensions/sandbox/package-lock.json +2 -2
  247. package/examples/extensions/sandbox/package.json +1 -1
  248. package/examples/extensions/subagent/adaptive-agent-runtime.ts +14 -1
  249. package/examples/extensions/subagent/graph-result.ts +48 -0
  250. package/examples/extensions/subagent/index.ts +246 -111
  251. package/examples/extensions/subagent/managed-process-tree.ts +42 -0
  252. package/examples/extensions/subagent/managed-process.test.ts +24 -0
  253. package/examples/extensions/subagent/managed-process.ts +93 -112
  254. package/examples/extensions/subagent/subagent-runtime-types.ts +17 -1
  255. package/examples/extensions/subagent/subagent-stream.ts +161 -0
  256. package/examples/extensions/terminal-browser/README.md +54 -0
  257. package/examples/extensions/terminal-browser/bridge-protocol.ts +29 -0
  258. package/examples/extensions/terminal-browser/bridge.ts +219 -0
  259. package/examples/extensions/terminal-browser/browser-surface.ts +288 -0
  260. package/examples/extensions/terminal-browser/index.ts +215 -0
  261. package/examples/extensions/terminal-browser/placeholders.ts +49 -0
  262. package/examples/extensions/with-deps/package-lock.json +2 -2
  263. package/examples/extensions/with-deps/package.json +1 -1
  264. package/npm-shrinkwrap.json +18 -18
  265. package/package.json +8 -7
  266. package/resources/neo/skills/omk-browser/SKILL.md +32 -0
  267. package/resources/neo/skills/omk-code-review/SKILL.md +24 -0
  268. package/resources/neo/skills/omk-computeruse/SKILL.md +34 -0
  269. package/resources/neo/skills/omk-mcp-setup/SKILL.md +48 -0
  270. package/resources/neo/skills/omk-research/SKILL.md +24 -0
  271. package/resources/neo/skills/omk-site/SKILL.md +28 -0
@@ -18,7 +18,7 @@ import { basename, dirname, join as joinPath } from "node:path";
18
18
  import { isDeepStrictEqual } from "node:util";
19
19
  import { getVisionRouteModel } from "omk-agent-core";
20
20
  import { clampThinkingLevel, cleanupSessionResources, deriveContextPromptCacheKey, getSupportedThinkingLevels, isBuiltinStreamFn, modelsAreEqual, resetApiProviders, } from "omk-ai";
21
- import { APP_NAME, VERSION } from "../config.js";
21
+ import { APP_NAME, getAgentDir, VERSION } from "../config.js";
22
22
  import { theme } from "../modes/interactive/theme/theme.js";
23
23
  import { stripFrontmatter } from "../utils/frontmatter.js";
24
24
  import { resolvePath } from "../utils/paths.js";
@@ -33,6 +33,7 @@ import { getCompactionHeadroomThreshold } from "./compaction/compaction.js";
33
33
  import { createCompactionHysteresisConfig, createCompactionHysteresisState, stepCompactionHysteresis, } from "./compaction/hysteresis.js";
34
34
  import { calculateContextTokens, collectEntriesForBranchSummary, compact, estimateContextTokens, estimateProjectedContextTokens, generateBranchSummary, prepareCompaction, resolveCompactionModel, } from "./compaction/index.js";
35
35
  import { summarizeWithOAuthRecovery } from "./compaction/oauth-recovery.js";
36
+ import { overflowRetryBlocked } from "./compaction/overflow-retry-guard.js";
36
37
  import { compactionEmitWillRetry } from "./compaction/resume-policy.js";
37
38
  import { isSessionModelOverflow, shouldSkipCompactionCheck } from "./compaction-gate.js";
38
39
  import { estimateToolResultReserve, } from "./context-budget-reserved-tokens.js";
@@ -47,11 +48,14 @@ import { ExtensionRunner, wrapRegisteredTools, } from "./extensions/index.js";
47
48
  import { emitSessionShutdownEvent } from "./extensions/runner.js";
48
49
  import { assertTextChatModelForCompletion, grokHarnessAutoApplyEnabled, isGrokOAuthProvider, selectGrokHarnessSkills, } from "./grok-harness.js";
49
50
  import { grokPlaybookAppendForProvider } from "./grok-playbook.js";
51
+ import { loadHookInventory } from "./hook-inventory.js";
50
52
  import { captureHostResourceSnapshot } from "./host-resource-snapshot.js";
51
53
  import { decideLoadoutAccess } from "./loadout-access-policy.js";
54
+ import { buildCapabilityInventory } from "./loadout-runtime.js";
52
55
  import { loadMcpServerConfigs } from "./mcp/config.js";
53
56
  import { McpManager } from "./mcp/manager.js";
54
57
  import { buildRuntimeProvenance } from "./runtime-provenance.js";
58
+ import { createSubagentLaneAuthority } from "./subagent-lane-authority.js";
55
59
  import { TurnMetricsSink } from "./turn-metrics.js";
56
60
  /** Values that disable a session-level feature through its environment variable. */
57
61
  const DISABLED_ENV_VALUES = new Set(["0", "false", "off", "disable", "disabled"]);
@@ -94,12 +98,12 @@ import { classifyPromptCacheTransition } from "./prompt-cache.js";
94
98
  import * as promptSettlement from "./prompt-settlement.js";
95
99
  import { expandPromptTemplate } from "./prompt-templates.js";
96
100
  import { isQuotaExhaustionMessage, isStickySafetyModel, isUpstreamUnavailableMessage, pickFailoverCandidate, resolveFailoverCandidates, resolveProviderResilience, sameModelRouteCandidates, shouldEjectStickySafetyModel, shouldHonorSafetyFailover, stickySafetyBlockMessage, } from "./provider-resilience.js";
97
- import { computeRetryDelayMs, failoverModelKey, isFailoverTriggerError, isRetryableAssistantError, nextRetryAttempt, retryBudgetForAssistantError, } from "./provider-retry.js";
101
+ import { computeRetryDelayMs, failoverModelKey, isEmptyStreamedCompletion, isFailoverTriggerError, isRetryableAssistantError, nextRetryAttempt, retryBudgetForAssistantError, } from "./provider-retry.js";
98
102
  import { getBiasStepsForCell, parseRouterBiasSnapshot } from "./reasoning-router-bias.js";
99
103
  import { classifyTaskV4, deriveRouterFeedbackFeaturesV4, resolveThinkingLevelV4WithUncertainty, TASK_CLASS_THINKING_LEVELS_V4, } from "./reasoning-router-v4.js";
100
104
  import { redactSensitiveText, redactSensitiveTextForced } from "./redaction.js";
101
105
  import { getRepositoryRouterLearningPaths } from "./repository-learning-scope.js";
102
- import { decideResourceAdmission } from "./resource-admission.js";
106
+ import { createResourcePressureStabilizer, decideResourceAdmission, evaluateResourcePressure, rederiveResourceAdmissionForPressure, } from "./resource-admission.js";
103
107
  import { resolveResourceGovernorSettings } from "./resource-governor-settings.js";
104
108
  import { admissionObservationFacts, classificationObservationFacts, ResourceObservationJournal, settledObservationFacts, snapshotObservationFacts, soundObservationFacts, } from "./resource-observation-journal.js";
105
109
  import { decideResourceSafetyGate, RESOURCE_PRESSURE_REQUIRED_ACTION } from "./resource-safety-gate.js";
@@ -289,6 +293,10 @@ export class AgentSession {
289
293
  _resourceObservationJournals = new Map();
290
294
  _latestResourcePromptRunId = null;
291
295
  _lastResourceAdmission = null;
296
+ // Per-session pressure hysteresis (audit §16.1): escalation is immediate,
297
+ // recovery requires consecutive healthier probes so the applied cap does
298
+ // not flap around a threshold between prompts.
299
+ _resourcePressureStabilizer;
292
300
  _workloadPermitPool;
293
301
  _pendingRuntimeTerminationCause;
294
302
  _activeRunToolTermination;
@@ -861,8 +869,13 @@ export class AgentSession {
861
869
  this._overflowRecoveryAttempts = 0;
862
870
  }
863
871
  // Reset retry counter immediately on successful assistant response
864
- // This prevents accumulation across multiple LLM calls within a turn
865
- if (assistantMsg.stopReason !== "error" && this._retryAttempt > 0) {
872
+ // This prevents accumulation across multiple LLM calls within a turn.
873
+ // An empty streamed completion wears a success shape (stop=stop, zero
874
+ // usable output) but is a dead stream — counting it as success reset
875
+ // the budget every cycle and retried forever (union-alpha relay loop).
876
+ if (assistantMsg.stopReason !== "error" &&
877
+ !isEmptyStreamedCompletion(assistantMsg) &&
878
+ this._retryAttempt > 0) {
866
879
  this._emit({
867
880
  type: "auto_retry_end",
868
881
  success: true,
@@ -1371,16 +1384,19 @@ export class AgentSession {
1371
1384
  * Extract the most recent user query text from conversation messages.
1372
1385
  * Returns undefined when no user message exists or content is empty.
1373
1386
  * Handles both string content and multimodal (array) content.
1387
+ *
1388
+ * The scan walks the whole transcript backwards and stops at the first user
1389
+ * message. A fixed tail window cannot work here: tool results are their own
1390
+ * messages, so a single turn that calls two tools already leaves
1391
+ * `[user, assistant, toolResult, toolResult]` and buries the task four deep.
1392
+ * Losing it mid-turn collapses every skill to the neutral relevance score and
1393
+ * degrades ranking to catalogue order, precisely while tools are running and
1394
+ * a matching skill matters most.
1374
1395
  */
1375
1396
  _extractCurrentQuery() {
1376
1397
  const messages = this.messages;
1377
- if (messages.length === 0) {
1378
- return undefined;
1379
- }
1380
- // Scan recent messages (last 3) for the most recent user message
1381
- const recent = messages.slice(-3);
1382
- for (let i = recent.length - 1; i >= 0; i--) {
1383
- const msg = recent[i];
1398
+ for (let i = messages.length - 1; i >= 0; i--) {
1399
+ const msg = messages[i];
1384
1400
  if (!msg || !("role" in msg) || msg.role !== "user") {
1385
1401
  continue;
1386
1402
  }
@@ -1576,8 +1592,12 @@ export class AgentSession {
1576
1592
  }
1577
1593
  const snapshot = await captureHostResourceSnapshot(probeOptions);
1578
1594
  const decision = decideResourceAdmission({ snapshot, config: resolved.admission, configuredCaps });
1595
+ const stabilized = this._stabilizeResourcePressure(snapshot, resolved);
1596
+ const appliedDecision = stabilized === decision.pressure
1597
+ ? decision
1598
+ : rederiveResourceAdmissionForPressure(decision, resolved.admission.caps, configuredCaps, stabilized);
1579
1599
  if (this._latestResourcePromptRunId === promptRunId) {
1580
- this._lastResourceAdmission = decision;
1600
+ this._lastResourceAdmission = appliedDecision;
1581
1601
  }
1582
1602
  resourceObservations?.record("resource_snapshot_v1", snapshotObservationFacts(snapshot));
1583
1603
  resourceObservations?.record("resource_admission_v1", admissionObservationFacts(decision));
@@ -1587,7 +1607,7 @@ export class AgentSession {
1587
1607
  this.agent.maxToolConcurrency = cap;
1588
1608
  },
1589
1609
  });
1590
- const lease = this._resourceLeaseController.acquire({ promptRunId, decision });
1610
+ const lease = this._resourceLeaseController.acquire({ promptRunId, decision: appliedDecision });
1591
1611
  resourceObservations?.record("resource_lease_acquired_v1", {
1592
1612
  decisionId: decision.decisionId,
1593
1613
  appliedToolCap: decision.maxToolConcurrency,
@@ -1598,6 +1618,15 @@ export class AgentSession {
1598
1618
  return null;
1599
1619
  }
1600
1620
  }
1621
+ /**
1622
+ * Feed one snapshot's raw pressure through the per-session stabilizer.
1623
+ * Created lazily so sessions that never probe carry no state; the first
1624
+ * observation installs its own level directly (no warmup lag).
1625
+ */
1626
+ _stabilizeResourcePressure(snapshot, resolved) {
1627
+ this._resourcePressureStabilizer ??= createResourcePressureStabilizer();
1628
+ return this._resourcePressureStabilizer.observe(evaluateResourcePressure(snapshot, resolved.admission.thresholds));
1629
+ }
1601
1630
  _openResourceObservations(promptRunId) {
1602
1631
  this._latestResourcePromptRunId = promptRunId;
1603
1632
  try {
@@ -1633,6 +1662,30 @@ export class AgentSession {
1633
1662
  getCurrentResourceAdmission() {
1634
1663
  return this._lastResourceAdmission;
1635
1664
  }
1665
+ /**
1666
+ * Spec 020 Req1 — canonical subagent lane authority bound to this session.
1667
+ * Rebuilt on each call so it tracks the live admission decision, shared
1668
+ * permit pool, and open prompt run. Extension tool contexts read it through
1669
+ * `ctx.getSubagentLaneAuthority()`.
1670
+ */
1671
+ _getSubagentLaneAuthority() {
1672
+ const hookInventory = loadHookInventory(getAgentDir());
1673
+ const sessionView = {
1674
+ _baseToolDefinitions: this._baseToolDefinitions,
1675
+ _extensionRunner: this._extensionRunner,
1676
+ _customTools: this._customTools,
1677
+ };
1678
+ const inventory = buildCapabilityInventory(sessionView, this._resourceLoader, this._cwd, hookInventory);
1679
+ return createSubagentLaneAuthority({
1680
+ runId: this._activeRunId ?? `session-${this.sessionManager.getSessionId() ?? "unknown"}`,
1681
+ promptRunId: this._promptLifecycle.activePromptRunId,
1682
+ decision: this._lastResourceAdmission,
1683
+ permitPool: this.workloadPermitPool,
1684
+ inventory,
1685
+ signal: this.agent?.signal,
1686
+ noteDetachedChild: () => this._promptLifecycle.noteDetachedChild(),
1687
+ });
1688
+ }
1636
1689
  /** §19.4 read-only SDK surface: capture a fresh host resource snapshot. */
1637
1690
  async getHostResourceSnapshot() {
1638
1691
  const resolved = resolveResourceGovernorSettings(this.settingsManager.getResourceGovernorSettings());
@@ -1741,12 +1794,15 @@ export class AgentSession {
1741
1794
  if (this._isRetryableError(msg) && (await this._prepareRetry(msg))) {
1742
1795
  return true;
1743
1796
  }
1744
- if (msg.stopReason === "error" && this._retryAttempt > 0) {
1797
+ // The retry budget is exhausted without a real answer. This covers the
1798
+ // empty-streamed-completion path whose success-shaped stopReason
1799
+ // otherwise left the UI pinned in the retrying state forever.
1800
+ if (this._retryAttempt > 0) {
1745
1801
  this._emit({
1746
1802
  type: "auto_retry_end",
1747
1803
  success: false,
1748
1804
  attempt: this._retryAttempt,
1749
- finalError: msg.errorMessage,
1805
+ finalError: msg.errorMessage ?? "The provider returned an empty response.",
1750
1806
  });
1751
1807
  this._retryAttempt = 0;
1752
1808
  this._refusedModels.clear();
@@ -3008,8 +3064,13 @@ export class AgentSession {
3008
3064
  /**
3009
3065
  * Effective context window for the upcoming turn.
3010
3066
  * Image-bearing turns with a text-only session model are auto-routed to the
3011
- * vision model (gpt-5.6-luna, 1M) — that window is the real limit. Text-only
3012
- * turns keep the session model's (typically much larger) window.
3067
+ * vision model (gpt-5.6-luna, 1M), so the request has to fit both windows and
3068
+ * the binding limit is the smaller one. Session windows fall on both sides of
3069
+ * 1M: most catalogued models are smaller (median near 300K) and keep their own
3070
+ * window as the limit, while the larger-than-1M models are the ones the clamp
3071
+ * exists for — without it their threshold is computed against a window the
3072
+ * vision route will not honour, and the request overflows before compaction
3073
+ * fires. Text-only turns keep the session model's window untouched.
3013
3074
  */
3014
3075
  _effectiveTurnContextWindow(pendingMessages, sessionWindow) {
3015
3076
  // Vision routing keys off the full transcript, not just the pending turn:
@@ -3288,16 +3349,25 @@ export class AgentSession {
3288
3349
  // the compaction_end event (so the TUI flushes its queued messages
3289
3350
  // correctly) and the return value below.
3290
3351
  const resumeMessages = this.agent.state.messages;
3291
- let lastAssistantMsg;
3292
- for (let i = resumeMessages.length - 1; i >= 0; i--) {
3293
- const candidate = resumeMessages[i];
3294
- if (candidate.role === "assistant") {
3295
- lastAssistantMsg = candidate;
3296
- break;
3297
- }
3298
- }
3352
+ const lastAssistantMsg = this._findLastAssistantMessage();
3299
3353
  const endedCleanly = lastAssistantMsg?.stopReason === "stop";
3300
3354
  const willResume = this.agent.hasQueuedMessages() || !endedCleanly;
3355
+ // overflow-retry-guard 배선: 압축 후 재전송 컨텍스트가 창을 확실히 초과하면
3356
+ // 재시도는 프로바이더 왕복만 소모한다 — 정확한 수치 진단과 함께 차단한다.
3357
+ const overflowBlock = willRetry
3358
+ ? overflowRetryBlocked(resumeMessages, this.model?.contextWindow ?? 0)
3359
+ : undefined;
3360
+ if (overflowBlock !== undefined) {
3361
+ this._emit({
3362
+ type: "compaction_end",
3363
+ reason,
3364
+ result,
3365
+ aborted: false,
3366
+ willRetry: false,
3367
+ errorMessage: overflowBlock,
3368
+ });
3369
+ return false;
3370
+ }
3301
3371
  const emitWillRetry = compactionEmitWillRetry(willRetry, willResume);
3302
3372
  this._emit({ type: "compaction_end", reason, result, aborted: false, willRetry: emitWillRetry });
3303
3373
  if (willRetry) {
@@ -3534,6 +3604,10 @@ export class AgentSession {
3534
3604
  },
3535
3605
  getSystemPrompt: () => this.systemPrompt,
3536
3606
  getSystemPromptOptions: () => this._baseSystemPromptOptions,
3607
+ // Spec 020 Req1 — session-bound lane authority for extension tool
3608
+ // contexts (subagent spawn funnel). Rebuilt on demand so it always
3609
+ // sees the live admission decision, permit pool, and prompt run.
3610
+ getSubagentLaneAuthority: () => this._getSubagentLaneAuthority(),
3537
3611
  }, {
3538
3612
  registerProvider: (name, config) => {
3539
3613
  this._modelRegistry.registerProvider(name, config);
@@ -3965,10 +4039,13 @@ export class AgentSession {
3965
4039
  if (attempt === undefined)
3966
4040
  return false;
3967
4041
  this._retryAttempt = attempt;
3968
- // Upstream-unavailable (gateway 5xx / dropped stream): rotate to another
3969
- // authenticated route of the SAME model family so the retry lands on a
3970
- // live endpoint instead of hammering the dead one.
3971
- const rotatedTo = isUpstreamUnavailableMessage(message.errorMessage)
4042
+ // Upstream-unavailable (gateway 5xx / dropped stream / dead relay stream):
4043
+ // rotate to another authenticated route of the SAME model family so the
4044
+ // retry lands on a live endpoint instead of hammering the dead one. An
4045
+ // empty streamed completion is the same dead-stream signature wearing a
4046
+ // success stopReason, so it rotates too — otherwise the retry re-hits the
4047
+ // route that just returned nothing.
4048
+ const rotatedTo = isUpstreamUnavailableMessage(message.errorMessage) || isEmptyStreamedCompletion(message)
3972
4049
  ? await this._maybeRotateModelRoutes()
3973
4050
  : undefined;
3974
4051
  // Content/safety stop (Fable/Opus/Sonnet): switch model BEFORE delay so retry is not same-model refusal.