@navels/neal 0.5.0 → 0.6.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.
@@ -175,6 +175,84 @@ older run state.
175
175
 
176
176
  If a prompt change would force validator or retained parser behavior to change, treat that as a contract change and review the prompt spec, prompt builder, schema builder, and tests together.
177
177
 
178
+ ## Prompt size bounds
179
+
180
+ Prompt inputs that grow with run length are either capped at render time or
181
+ deliberately left unbounded with the provider input budget as their backstop,
182
+ and each section below says which. The contract has four parts.
183
+
184
+ **The completion packet carries a verification tally, not the history.**
185
+ `buildFinalCompletionPacket()` embeds `verificationTally`
186
+ (`buildVerificationTally` in `src/neal/verification-events.ts`): total command
187
+ runs, distinct commands, passed/failed/unknown counts over the latest result
188
+ per distinct command, and the last 10 failing commands with exit codes, each
189
+ command string capped at 300 characters. Both completion prompts embed the
190
+ tally and point at the run directory's `events.ndjson` for the complete
191
+ per-command record. The events file is the source of truth; the packet never
192
+ carries the full history and no extra artifact is written.
193
+
194
+ **Run-scaling sections are capped where they enter a prompt.** The shared
195
+ helpers live in `src/neal/context/inline-review-context.ts` and truncation is
196
+ render-time only: stored state, persisted artifacts, and schema-validated
197
+ coder outputs are never mutated to satisfy a bound.
198
+
199
+ - Inlined range-diff sections: `INLINE_SECTION_MAX_CHARS` (200,000
200
+ characters) via `truncateInlineSectionBody`, with an explicit truncation
201
+ marker.
202
+ - Operator guidance: `USER_GUIDANCE_MAX_CHARS` (20,000 characters) applies
203
+ per role file (`src/neal/prompts/guidance.ts`; `neal check` warns when a
204
+ guidance file exceeds the cap), to the persisted plan-review recovery
205
+ guidance message, and to the latest blocked-recovery guidance line.
206
+ - Agent-authored free text (completion summaries, finding claims, round
207
+ summaries, blocked reasons, the last implementation scope's commit
208
+ subject): `boundFreeTextValues` shares
209
+ `AGENT_FREE_TEXT_SECTION_MAX_CHARS` (20,000 characters) across each fixed
210
+ group of values, markers included. The completion packet's completed-scope
211
+ summary, its scope-accounting summary, and the scope reviewer's recent
212
+ accepted-scope history are single strings capped at the same constant via
213
+ `truncateInlineSectionBody`.
214
+ - Changed-file lists: `boundChangedFileList` renders the first
215
+ `CHANGED_FILE_LIST_LIMIT` (20) paths and collapses the rest to a
216
+ `(+N more)` entry; the underlying arrays keep every path for non-prompt
217
+ consumers.
218
+ - Commit-subject lists (the aggregate completion range and the scope
219
+ review's commits-in-scope list): `boundCommitSubjectList` renders the
220
+ first `COMMIT_SUBJECT_LIST_LIMIT` (20) subjects under the shared free-text
221
+ budget and collapses the rest to a `(+N more)` entry.
222
+ - Git diff-stat blocks (aggregate completion range and scope review):
223
+ `GIT_SUMMARY_SECTION_MAX_CHARS` (20,000 characters) via
224
+ `truncateInlineSectionBody`.
225
+
226
+ Every bound is a module constant, not configuration. Three sections are
227
+ intentionally unbounded and rely on the provider input budget below as their
228
+ backstop: the inlined plan text, the progress text, and the review-findings
229
+ selected-range diff (`buildReviewFindingsInlinedDiffSection` in
230
+ `src/neal/review-findings/prompts.ts` inlines the full resolved-range diff
231
+ for read-only reviewers because it is the source of truth for what the range
232
+ changed — only the separate draft-prompt preview is capped, at
233
+ `DIFF_PREVIEW_LIMIT`). The `INLINE_SECTION_MAX_CHARS` cap applies to the
234
+ inlined range-diff sections built through `truncateInlineSectionBody`, not to
235
+ every diff that reaches a prompt.
236
+
237
+ **Providers with a hard limit reject oversized prompts before the SDK call.**
238
+ A capability role that declares `maxInputChars` gets an adapter-boundary
239
+ preflight on the exact text each turn sends; over-limit prompts fail fast
240
+ with a non-retryable `input_too_large` error naming the prompt size, the
241
+ limit, and the three largest `## ` sections. See
242
+ [providers.md](providers.md) for the capability field, the preflight
243
+ mechanics, and the error kind.
244
+
245
+ **Input-size failures are recoverable without state surgery.** There is no
246
+ sticky gate: the preflight re-measures the actual rebuilt prompt on every
247
+ attempt, so `neal resume` after the prompt shrinks proceeds normally, while
248
+ an unchanged oversized prompt fails fast before any provider call. While the
249
+ latest failure is `input_too_large`, `neal status` renders a conditional Next
250
+ Action: shrink the named largest input first (trim operator guidance files,
251
+ or upgrade neal so current prompt bounds apply on resume), then resume; if
252
+ the prompt can't fit under the limit, start a new run on a provider with a
253
+ larger or no declared limit, because per-run provider rebinding doesn't
254
+ exist.
255
+
178
256
  ## Provider variants
179
257
 
180
258
  Provider-specific variants are allowed, but they are not the default escape hatch. Each spec declares `providerVariants` for `shared` (status `default`) plus `openai-codex` and `anthropic-claude` (status `reserved_for_justified_divergence`).
package/docs/providers.md CHANGED
@@ -72,6 +72,7 @@ Each provider capability role declares:
72
72
 
73
73
  - whether the role is supported
74
74
  - read, write, and shell tool access
75
+ - an optional hard per-turn input limit in characters (`maxInputChars`)
75
76
  - session resume support
76
77
  - model override support
77
78
  - neal structured control protocol support
@@ -85,6 +86,16 @@ structured-advisor capability and read tool access: every reviewer inspects
85
86
  the repository directly. Session resume support is required when a persisted
86
87
  session handle is present.
87
88
 
89
+ A role that declares `maxInputChars` gets an input-budget preflight
90
+ (`src/neal/providers/input-budget.ts`) in the adapter on the exact text each
91
+ SDK turn sends: the bare prompt for plain turns, the protocol-wrapped prompt
92
+ for structured turns, and each generated repair prompt before its repair
93
+ thread is created. Every call site is covered without per-site wiring. A
94
+ prompt over the limit fails fast with a non-retryable `input_too_large` error
95
+ before any SDK call and without consuming API-retry budget; the error message
96
+ names the prompt size, the limit, and the three largest `## ` sections. Roles
97
+ without a declared limit skip the preflight.
98
+
88
99
  Current built-in capabilities are intentionally conservative:
89
100
 
90
101
  - OpenAI Codex supports coder and structured-advisor roles. The coder role is
@@ -92,6 +103,8 @@ Current built-in capabilities are intentionally conservative:
92
103
  broad local access. The structured-advisor (reviewer) role is read capable
93
104
  but never write or shell capable (see
94
105
  [The read-only reviewer invariant](#the-read-only-reviewer-invariant)).
106
+ Both roles declare `maxInputChars: 1,048,576` — the size at which Codex's
107
+ app-server rejects a turn with its `input_too_large` input-error code.
95
108
  - Anthropic Claude supports coder and structured-advisor roles. The coder role
96
109
  is read, write, and shell capable. The structured-advisor (reviewer) role is
97
110
  read capable but never write or shell capable.
@@ -402,6 +415,12 @@ Normalized error kinds are:
402
415
  - `structured_output_invalid`
403
416
  - `permission_denied`
404
417
  - `session_unavailable`
418
+ - `input_too_large` (the assembled prompt exceeds the role's declared
419
+ `maxInputChars`; thrown by the adapter's preflight before any SDK call, and
420
+ a provider-side over-limit rejection — Codex's `input_too_large`
421
+ input-error code — normalizes to the same kind. Always non-retryable; the
422
+ message names the prompt size, the limit, and the three largest `## `
423
+ sections)
405
424
  - `provider_failed`
406
425
  - `unknown`
407
426
 
package/neal.yml CHANGED
@@ -40,7 +40,7 @@
40
40
  #
41
41
  # # Maximum number of times final completion review may send execution back
42
42
  # # for more work before neal stops reopening the plan.
43
- # final_completion_continue_execution_max: 2
43
+ # final_completion_continue_execution_max: 3
44
44
  #
45
45
  # # Optional local notification command. Leave commented to keep
46
46
  # # notifications disabled.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@navels/neal",
3
- "version": "0.5.0",
3
+ "version": "0.6.0",
4
4
  "description": "A source-first multi-agent CLI for planning, executing, reviewing, and resuming scoped code changes.",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -56,7 +56,7 @@
56
56
  },
57
57
  "dependencies": {
58
58
  "@ai-sdk/openai-compatible": "3.0.34",
59
- "@anthropic-ai/claude-agent-sdk": "0.3.238",
59
+ "@anthropic-ai/claude-agent-sdk": "0.3.240",
60
60
  "@openai/codex-sdk": "0.149.0",
61
61
  "ai": "7.0.74",
62
62
  "dotenv": "^17.4.2",