[GH-ISSUE #5032] procedure_pseudo_code output for one large function is too big to return #3091

Open
opened 2026-10-31 00:36:31 +00:00 by bsakaguchi · 4 comments
Owner

Originally created by @RoKenobi on GitHub (Oct 18, 2026).
Original GitHub issue: https://github.com/morluto/rea/issues/5032

REA 6.5.0, Ghidra provider, Claude Code client. Decompiling one large function in iTunes.exe (FUN_141310c60) returned about 98,000 characters. The client rejected the result as too large and saved it to a file, so I had to read the pseudocode from that file in pieces.

#4249 asks for paging for the list and search tools, but I couldn't find a way to page a single function's pseudocode, in 6.5.0 or 6.7.0. If inspect_analysis_view can already do this with the result's evidence ID, the tool description or the skill could say so. Otherwise, line-range paging for procedure_pseudo_code would help with large functions.

Originally created by @RoKenobi on GitHub (Oct 18, 2026). Original GitHub issue: https://github.com/morluto/rea/issues/5032 REA 6.5.0, Ghidra provider, Claude Code client. Decompiling one large function in `iTunes.exe` (`FUN_141310c60`) returned about 98,000 characters. The client rejected the result as too large and saved it to a file, so I had to read the pseudocode from that file in pieces. #4249 asks for paging for the list and search tools, but I couldn't find a way to page a single function's pseudocode, in 6.5.0 or 6.7.0. If `inspect_analysis_view` can already do this with the result's evidence ID, the tool description or the skill could say so. Otherwise, line-range paging for `procedure_pseudo_code` would help with large functions.
Author
Owner

@pablodiazjorge commented on GitHub (Oct 18, 2026):

I checked the source on main (23f984b1a) and the rea-agents-6.5.0 and 6.7.0 tags. There is a paging path in all three, but not from procedure_pseudo_code:

  • inspect_analysis_view pages pseudocode from analyze_function Evidence: view: {kind: "native", facet: "pseudocode", offset, limit}, with offset and limit in UTF-16 code units. The native view only accepts analyze_function as its parent (parent_operation: "analyze_function" in src/domain/analysisView/nativeFunctionView.ts), so Evidence from procedure_pseudo_code can't be paged there. The default limit is 64, which for pseudocode means 64 code units, so pass a larger one explicitly.
  • The catch is the first call: analyze_function takes only procedure and returns the whole dossier (pseudocode, assembly, references, blocks…), so for FUN_141310c60 its response would be larger than the 98,000 characters you got, and Claude Code would likely save it to a file as well. From there you could page with {source: {kind: "retained-evidence", evidence_id: "<its evidence_id>"}, view: {kind: "native", facet: "pseudocode", offset: 0, limit: 20000}}.

inspect_macho already avoids an oversized first result with detail: "summary", which retains the complete Evidence in the session and returns its inspect_analysis_view summary. The same option on analyze_function, or the line-range paging you suggest for procedure_pseudo_code, would cover this case; that's a scope call for the maintainers.

Not run: this comes from reading the contracts and the view code. I haven't decompiled a function this size or measured the dossier.

<!-- gh-comment-id:6250741447 --> @pablodiazjorge commented on GitHub (Oct 18, 2026): I checked the source on main (`23f984b1a`) and the `rea-agents-6.5.0` and `6.7.0` tags. There is a paging path in all three, but not from `procedure_pseudo_code`: - `inspect_analysis_view` pages pseudocode from `analyze_function` Evidence: `view: {kind: "native", facet: "pseudocode", offset, limit}`, with offset and limit in UTF-16 code units. The native view only accepts `analyze_function` as its parent (`parent_operation: "analyze_function"` in `src/domain/analysisView/nativeFunctionView.ts`), so Evidence from `procedure_pseudo_code` can't be paged there. The default `limit` is 64, which for pseudocode means 64 code units, so pass a larger one explicitly. - The catch is the first call: `analyze_function` takes only `procedure` and returns the whole dossier (pseudocode, assembly, references, blocks…), so for `FUN_141310c60` its response would be larger than the 98,000 characters you got, and Claude Code would likely save it to a file as well. From there you could page with `{source: {kind: "retained-evidence", evidence_id: "<its evidence_id>"}, view: {kind: "native", facet: "pseudocode", offset: 0, limit: 20000}}`. `inspect_macho` already avoids an oversized first result with `detail: "summary"`, which retains the complete Evidence in the session and returns its `inspect_analysis_view` summary. The same option on `analyze_function`, or the line-range paging you suggest for `procedure_pseudo_code`, would cover this case; that's a scope call for the maintainers. Not run: this comes from reading the contracts and the view code. I haven't decompiled a function this size or measured the dossier.
Author
Owner

@cpruijsen commented on GitHub (Oct 20, 2026):

This adds real-Ghidra measurements for the initial dossier cost described in the existing #5032 discussion.

After opening Elgato Control Center and completing provider startup, the recorded MCP session made these calls:

{"name":"analyze_function","arguments":{"procedure":"0x10004c694"}}
{"name":"analyze_function","arguments":{"procedure":"0x10004c86c"}}

Both calls succeeded. Short-report 8-bit trace request/result pairs are 134/135 and 136/137.

Captured component First function Second function
MCP text result, UTF-8 bytes 322,464 323,136
One normalized dossier, compact JSON bytes 158,563 158,899
Value-flow data per dossier copy, compact JSON bytes 100,125 100,125
Pseudocode per copy, compact JSON bytes 1,957 1,964

In both results, raw_result.value exactly equals normalized_result. Parsed text also equals structuredContent. The harness consumes only text, so it receives two dossier copies before clipping, not four. Its separate 12,000-byte text limit clipped both successful results. REA did not report a provider or transport failure.

Existing inspect_analysis_view native facets already provide selected or paged access after retention. procedure_pseudo_code also supplies narrower output. The remaining question is smaller initial dossier delivery, without removing the complete Evidence required by #551 and #723.

Source review at d532b18123916a9e88f98c7880ba4f984e23d715 confirms the procedure-only input and full-dossier contract. This is delivery evidence, not proof that the current contract is broken or paging is absent.

Observed revision: 3613fb11bd9d6b876822056a6d7ec2c18e3bfc9d. Environment: macOS arm64, Ghidra 12.1.4, Temurin 21.0.12.1+1-LTS. Target binary SHA-256: 865f822237eb41d837b9e49f0ebf6613125da7771fa9d2950be76de8a67d4954.

No latest-main runtime reproduction, proposed summary, or before/after token saving was measured. No raw logs or private paths are included.

<!-- gh-comment-id:6287923737 --> @cpruijsen commented on GitHub (Oct 20, 2026): This adds real-Ghidra measurements for the initial dossier cost described in [the existing #5032 discussion](https://github.com/morluto/rea/issues/5032#issuecomment-6250741447). After opening Elgato Control Center and completing provider startup, the recorded MCP session made these calls: ```json {"name":"analyze_function","arguments":{"procedure":"0x10004c694"}} {"name":"analyze_function","arguments":{"procedure":"0x10004c86c"}} ``` Both calls succeeded. Short-report 8-bit trace request/result pairs are 134/135 and 136/137. | Captured component | First function | Second function | |---|---:|---:| | MCP text result, UTF-8 bytes | 322,464 | 323,136 | | One normalized dossier, compact JSON bytes | 158,563 | 158,899 | | Value-flow data per dossier copy, compact JSON bytes | 100,125 | 100,125 | | Pseudocode per copy, compact JSON bytes | 1,957 | 1,964 | In both results, `raw_result.value` exactly equals `normalized_result`. Parsed text also equals `structuredContent`. The harness consumes only text, so it receives two dossier copies before clipping, not four. Its separate 12,000-byte text limit clipped both successful results. REA did not report a provider or transport failure. Existing `inspect_analysis_view` native facets already provide selected or paged access after retention. `procedure_pseudo_code` also supplies narrower output. The remaining question is smaller initial dossier delivery, without removing the complete Evidence required by [#551](https://github.com/morluto/rea/issues/551) and [#723](https://github.com/morluto/rea/issues/723). Source review at `d532b18123916a9e88f98c7880ba4f984e23d715` confirms the [procedure-only input](https://github.com/morluto/rea/blob/d532b18123916a9e88f98c7880ba4f984e23d715/src/contracts/enhancedInputs.ts#L53-L55) and [full-dossier contract](https://github.com/morluto/rea/blob/d532b18123916a9e88f98c7880ba4f984e23d715/src/contracts/functionWorkflowToolContracts.ts#L35-L41). This is delivery evidence, not proof that the current contract is broken or paging is absent. Observed revision: `3613fb11bd9d6b876822056a6d7ec2c18e3bfc9d`. Environment: macOS arm64, Ghidra 12.1.4, Temurin 21.0.12.1+1-LTS. Target binary SHA-256: `865f822237eb41d837b9e49f0ebf6613125da7771fa9d2950be76de8a67d4954`. No latest-main runtime reproduction, proposed summary, or before/after token saving was measured. No raw logs or private paths are included.
Author
Owner

@CryptoJones commented on GitHub (Oct 20, 2026):

More real-Ghidra measurements for the initial analyze_function dossier cost, from a Linux ELF with symbols and debug info. They are about an order of magnitude above the Elgato numbers above, and one function exceeded the 10 MiB response budget on its own.

Setup (observed). REA 6.7.0 built from 32f0e5120, MCP mode, Ghidra 12.1.4, Linux x86-64. Target: Delores (Delores: A Thimbleweed Park Mini-Adventure, version string Delores version 2.0.5 (build 20200914)), not stripped, 10,414,408 bytes, SHA-256 e0f33669e6d0d37a62eb500dee780d7287889d1ab220d4f46ef094e662fe9f4a. Client: dsh driving a local Qwen3.8-27B. Numbers below are from the recorded MCP tool results; sizes are compact JSON UTF-8 bytes of the parsed result.

Function normalized_result native_value_flow outgoing_references assembly pseudocode
main (64 lines) 92,230 64,658 13,284 2,428 1,979
GGPackfileManager::addPack (298 lines) 963,191 662,134 240,852 12,694 10,477
GameApp::initWithOptions (645 lines) 2,140,952 1,355,293 633,972 35,114 25,626
GGSDLApp::initMain not delivered: response_bytes_at_least 10,585,263 vs result_budget_bytes 10,484,736 26,113 code units (from the retained view)

Inside native_value_flow, operations is 51,169 / 524,722 / 1,116,232 bytes and def_use 8,993 / 122,347 / 227,915 for the three delivered functions. Pseudocode is 1.2 to 2.1 percent of the normalized dossier.

On this revision raw_result.value still equalled normalized_result byte for byte, so each delivered record was 189,119 / 1,931,379 / 4,286,867 bytes. #5355 removes that copy, so the table reports normalized sizes only.

Continuation path (observed). The resource_constraint error for initMain carried a ready inspect_analysis_view continuation with limit: 64. The agent called it with limit: 200 and received 200 of 26,113 code units (coverage.next_offset: 200), i.e. the signature. Paging works as documented, but the default page is the view contract default, not a useful pseudocode page.

Agent outcome (observed, one run, not a controlled comparison). The client clipped each tool result at about 50 KB and spilled the rest to a file. The first 50 KB of every analyze_function result is subject, provider, analysis_profile and the start of native_value_flow, so after 15 REA calls over 27 minutes the agent had seen one function signature and no pseudocode. That is a client limit, not a REA failure, but it is the regime an opt-in summary or pseudocode-first delivery would address.

Not run: no reproduction on latest main, no before/after token measurement, no proposed schema. Nothing private is included; the target is a retail Steam build.

<!-- gh-comment-id:6296242344 --> @CryptoJones commented on GitHub (Oct 20, 2026): More real-Ghidra measurements for the initial `analyze_function` dossier cost, from a Linux ELF with symbols and debug info. They are about an order of magnitude above the Elgato numbers above, and one function exceeded the 10 MiB response budget on its own. **Setup (observed).** REA 6.7.0 built from `32f0e5120`, MCP mode, Ghidra 12.1.4, Linux x86-64. Target: `Delores` (Delores: A Thimbleweed Park Mini-Adventure, version string `Delores version 2.0.5 (build 20200914)`), not stripped, 10,414,408 bytes, SHA-256 `e0f33669e6d0d37a62eb500dee780d7287889d1ab220d4f46ef094e662fe9f4a`. Client: dsh driving a local Qwen3.8-27B. Numbers below are from the recorded MCP tool results; sizes are compact JSON UTF-8 bytes of the parsed result. | Function | `normalized_result` | `native_value_flow` | `outgoing_references` | `assembly` | `pseudocode` | |---|---:|---:|---:|---:|---:| | `main` (64 lines) | 92,230 | 64,658 | 13,284 | 2,428 | 1,979 | | `GGPackfileManager::addPack` (298 lines) | 963,191 | 662,134 | 240,852 | 12,694 | 10,477 | | `GameApp::initWithOptions` (645 lines) | 2,140,952 | 1,355,293 | 633,972 | 35,114 | 25,626 | | `GGSDLApp::initMain` | not delivered: `response_bytes_at_least` 10,585,263 vs `result_budget_bytes` 10,484,736 | | | | 26,113 code units (from the retained view) | Inside `native_value_flow`, `operations` is 51,169 / 524,722 / 1,116,232 bytes and `def_use` 8,993 / 122,347 / 227,915 for the three delivered functions. Pseudocode is 1.2 to 2.1 percent of the normalized dossier. On this revision `raw_result.value` still equalled `normalized_result` byte for byte, so each delivered record was 189,119 / 1,931,379 / 4,286,867 bytes. #5355 removes that copy, so the table reports normalized sizes only. **Continuation path (observed).** The `resource_constraint` error for `initMain` carried a ready `inspect_analysis_view` continuation with `limit: 64`. The agent called it with `limit: 200` and received 200 of 26,113 code units (`coverage.next_offset: 200`), i.e. the signature. Paging works as documented, but the default page is the view contract default, not a useful pseudocode page. **Agent outcome (observed, one run, not a controlled comparison).** The client clipped each tool result at about 50 KB and spilled the rest to a file. The first 50 KB of every `analyze_function` result is `subject`, `provider`, `analysis_profile` and the start of `native_value_flow`, so after 15 REA calls over 27 minutes the agent had seen one function signature and no pseudocode. That is a client limit, not a REA failure, but it is the regime an opt-in summary or pseudocode-first delivery would address. Not run: no reproduction on latest `main`, no before/after token measurement, no proposed schema. Nothing private is included; the target is a retail Steam build.
Author
Owner

@morluto commented on GitHub (Oct 26, 2026):

Thanks for the concrete large-function example. analyze_function dossiers can page their retained pseudocode, but the standalone procedure_pseudo_code result has a separate scalar representation; #5046 proposes summary delivery and paging for that path. The issue remains open while that distinct change is reviewed. No Ghidra or Claude run was performed in this triage.

<!-- gh-comment-id:6428705642 --> @morluto commented on GitHub (Oct 26, 2026): Thanks for the concrete large-function example. `analyze_function` dossiers can page their retained pseudocode, but the standalone `procedure_pseudo_code` result has a separate scalar representation; #5046 proposes summary delivery and paging for that path. The issue remains open while that distinct change is reviewed. No Ghidra or Claude run was performed in this triage.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
morluto/rea#3091
No description provided.