Skip to content

Commit bee2f29

Browse files
authored
Merge pull request #7421 from loopx-project/codex/context-native-output-budget-20261027
fix(context): apply native reader pages with their output budgets
2 parents bb15059 + 7c3d03e commit bee2f29

11 files changed

Lines changed: 167 additions & 41 deletions

File tree

‎benchmark/runtime/RUNTIME.md‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,16 @@ reads, native discovery and hook IO in treatment cost, not just the delta bytes.
9696

9797
Codex App setup uses the same product configuration renderer as the worker:
9898
`loopx --format json quota context-config --context-delivery on --codex-app --codex-context-root DIR --goal-id GOAL --agent-id AGENT`.
99-
It returns native hooks and persistent recovery instructions, without installing
100-
files or changing trust. A shared root isolates journals by native session;
99+
It returns native hooks, persistent recovery instructions and native output
100+
`config_overrides`, without installing files or changing trust. The opted-in
101+
worker applies those same overrides automatically: 64000-byte continuation
102+
outputs, a 20000-token history limit and a shell-scoped reader declaration. Page
103+
zero remains within the ordinary 7900-byte guard limit. Persistent instructions
104+
request 22000 tokens per reader result and 24000 for code-mode emission, one
105+
directly forwarded stdout at a time. Unknown budgets retain small pages. These
106+
limits do not prove model retention or net cost savings. Fresh off trials install
107+
none of this configuration; rollback also removes generated output overrides.
108+
A shared root isolates journals by native session;
101109
the trial-local single-session `--codex-context-dir` remains supported.
102110
See [heartbeat setup](../../docs/heartbeat-automation-prompt.md#opt-in-native-context-delivery)
103111
for activation, readback and rollback. Generated setup and a native

‎benchmark/runtime/context_delivery.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,4 +102,6 @@ def prepare_context_delivery(env: dict[str, str], home: Path) -> None:
102102
# a failed SessionStart handler cannot erase the read-only recovery route.
103103
native_args = ["-c", "hooks.state={" + ",".join(entries) + "}",
104104
"-c", "developer_instructions=" + json.dumps(configuration["developer_instructions"])]
105+
native_args += [argument for key, value in configuration["config_overrides"].items()
106+
for argument in ("-c", key + "=" + json.dumps(value))]
105107
env["LOOPX_CODEX_CONTEXT_TRUST_ARGS"] = json.dumps(native_args)

‎benchmark/tests/test_shared_codex_runtime.py‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1299,6 +1299,8 @@ def request(method, params):
12991299
overrides = {trusted[i + 1].split("=", 1)[0]: trusted[i + 1].split("=", 1)[1]
13001300
for i, value in enumerate(trusted) if value == "-c"}
13011301
assert not any(key.startswith("model_provider") for key in overrides)
1302+
assert overrides["tool_output_token_limit"] == "20000"
1303+
assert json.loads(overrides["shell_environment_policy.set.LOOPX_CONTEXT_PAGE_OUTPUT_BYTES"]) == "64000"
13021304
assert "CODEX_ROLLOUT_TRACE_ROOT" not in env
13031305
assert not (home / "context-traces").exists()
13041306

‎docs/heartbeat-automation-prompt.md‎

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -476,12 +476,22 @@ loopx --format json quota context-config --context-delivery on --codex-app \
476476
--goal-id <goal> --agent-id <agent>
477477
```
478478

479-
The result contains `native_config.hooks` and
479+
The result contains `native_config.config_overrides`, `native_config.hooks` and
480480
`native_config.developer_instructions`. Merge the hooks into the host's existing
481481
`hooks.json` or inline hook configuration, and append the recovery instruction to
482-
its existing developer instructions. Preserve other configuration. Review and
482+
its existing developer instructions. Apply each flat key/value in `config_overrides`
483+
to the native host configuration (or as a `-c key=value` override). This selects
484+
64000-byte context continuations, a 20000-token history limit, and a shell-scoped
485+
reader budget declaration. The initial guard stays small. Its instruction requests
486+
22000 tokens per reader result and 24000 for code-mode emission, with one directly
487+
forwarded stdout per call. Unconfigured hosts retain the small-page default;
488+
the isolated benchmark worker applies this profile automatically when opted in.
489+
Preserve other configuration. Review and
483490
trust only these exact hooks through Codex's native hook trust surface; the CLI
484491
does not install files, approve hashes, enable diagnostics or run a guard.
492+
Rollback removes these generated output overrides along with the context hooks
493+
and recovery instruction; restore any previous host values. The profile does not
494+
establish model retention, task gains or net fee savings.
485495
An already loaded native thread may keep its earlier hook configuration even
486496
when `hooks/list` discovers the new handlers as enabled and trusted. That readback
487497
does not deliver `SessionStart` or initialize its context journal. After active

‎docs/reference/required-work-context.md‎

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ Native `quota should-run` and the saved `context-project` entry share the same
255255
paged presentation. Each returns page zero, a digest-pinned continuation and full
256256
recovery without another admission. The inline page contains up to 3 KiB and shrinks
257257
to keep the complete guard stdout, including recovery and instruction fields,
258-
within 7900 UTF-8 bytes. Continuations
258+
within 7900 UTF-8 bytes. Without the generated native output configuration, continuations
259259
request up to 8 KiB of content with `--max-page-output-bytes 7900`, which bounds
260260
successful JSON stdout including escaping, commands and newline. Consume the inline
261261
page before following next_command; when the retained-history limit is unknown,
@@ -280,7 +280,16 @@ their separate confirmed-input contract.
280280

281281
For native setup, `quota context-config --codex-app --goal-id GOAL --agent-id AGENT`
282282
under machine on prepares only that private transport leaf and renders the
283-
existing hooks and recovery instructions. For an SSH Goal, replace `--codex-app`
283+
existing hooks, recovery instructions and `config_overrides`. Applying those overrides
284+
selects 64000-byte continuation outputs and a 20000-token native history limit;
285+
the initial guard remains within 7900 bytes. The worker applies this configuration
286+
automatically inside its isolated opt-in trial. The persistent instruction requests
287+
22000 tokens for each context-read tool result and 24000 for its code-mode emission,
288+
forwarding one stdout at a time. Unknown or unsupported output declarations retain
289+
the small-page default. Remove the generated output overrides together with the
290+
context setup on rollback; saving a machine preference alone does not apply them.
291+
This output sizing does not prove retained input, lower fees or task benefit.
292+
For an SSH Goal, replace `--codex-app`
284293
with `--runtime-profile codex_app_ssh_goal` in setup and the thin/bootstrap prompt.
285294
Its generated guard keeps the native Goal identity and visible-Goal settlement;
286295
it does not become a hosted heartbeat. It does not install or trust hooks,
@@ -473,11 +482,17 @@ SSH Goal 使用 `--runtime-profile codex_app_ssh_goal` 生成 context-config 和
473482
沿用可见 Goal 的执行与结算身份;仅启用差分时接入捕获目录,不转换成自动心跳。
474483
原生 `quota should-run` 与已保存捕获的 `context-project` 共用分页呈现,直接返回第零页、
475484
固定摘要的后续读取与完整恢复,不另行准入。内联正文最多 3 KiB,必要时缩小,使包含
476-
恢复字段与完整指引的 guard stdout 不超过 7900 UTF-8 字节;后续命令最多请求
485+
恢复字段与完整指引的 guard stdout 不超过 7900 UTF-8 字节。未应用生成的原生输出配置时,后续命令最多请求
477486
8 KiB 正文,并用 `--max-page-output-bytes 7900` 将成功 JSON stdout(含转义、
478487
后续命令与换行)限制为 7900 字节。先消费内联页,再跟随 next_command;保留历史
479488
上限未知时,每次只读一个有界输出。该上限不证明模型保留。Code Mode 直接转发
480489
exec stdout;把整包重打进哈希工具不构成原始字节已被保留的证明。
490+
原生配置同时返回 `config_overrides`:应用后,续读输出上限为 64000 字节,原生历史
491+
上限为 20000 token,首次 guard 仍保持 7900 字节。开启的 benchmark worker 在其
492+
隔离会话内自动应用;持久指引要求每次续读直接输出预算 22000 token、Code Mode
493+
输出预算 24000 token,每次直接转发一份 stdout。未知或不支持的输出声明保持小页。
494+
回滚时同时移除生成的输出覆盖项;仅保存机器偏好并不会应用这些宿主配置。
495+
该设置不证明输入保留、总费用降低或任务效果改善。
481496
读取器校验不可变 capture 的摘要。Post-tool 适配层复用显式输入观察的字节范围校验,
482497
先将实际 UTF-8 正文与可信 journal 指向的物理捕获及固定摘要核对,再合并读取范围。
483498
正文改变、文件丢失或替换、符号链接及摘要失败均不得晋升基线;保留原始恢复引用,
@@ -551,7 +566,7 @@ exact digest and Turn receipt; they never rerun admission or spend quota.
551566
With delivery on, a successful saved projection also returns page zero using
552567
the existing `context_capture_page_v1` fields. Its content is bounded to 3 KiB
553568
and shrinks against the final presentation's 7900-byte stdout limit, including
554-
recovery, activation and instruction metadata. Subsequent native commands request up to
569+
recovery, activation and instruction metadata. Without the generated output profile, subsequent native commands request up to
555570
8 KiB of content within a 7900-byte successful JSON stdout limit. The optional
556571
JSON-only `--max-page-output-bytes` flag shrinks content at UTF-8 boundaries and
557572
preserves the limit in `next_command`. An insufficient limit returns an error
@@ -567,7 +582,10 @@ Codex 0.162.1 qualification uses a 10,000-token history setting and a 12,000-tok
567582
code-mode result budget with one directly forwarded stdout per call. Unknown
568583
budgets keep the existing 7900-byte native default. A larger requested result
569584
alone never proves history retention; missing output still needs same-capture
570-
recovery. This changes no host setting automatically.
585+
recovery. The reader flag changes no host setting. The shared native setup described
586+
above supplies the larger 64000-byte profile and its matching history/execution
587+
budgets together; only the opted-in worker applies them automatically. A legacy
588+
consumer that has not applied that setup keeps the existing small-page boundary.
571589
Consume `content`, then follow `next_command` through `eof` for full byte coverage.
572590
The reader verifies the original digest; do not retype or hash the content. The
573591
existing `command` still restarts at zero for older readers or incomplete inline
@@ -585,7 +603,7 @@ input retention.
585603

586604
开启时,成功的已保存投影同时用现有 `context_capture_page_v1` 字段返回第一页。
587605
该页内容最多 3 KiB,按最终呈现的 7900 字节 stdout 上限缩小,包含恢复、启用配置与
588-
完整指引元数据;后续原生命令最多请求 8 KiB
606+
完整指引元数据;未应用生成的输出配置时,后续原生命令最多请求 8 KiB
589607
正文,成功 JSON stdout 限制为 7900 字节。可选的 JSON 专用参数
590608
`--max-page-output-bytes` 按 UTF-8 边界缩减正文,并在 `next_command` 中保留。
591609
上限不足时返回错误,不返回无进展的分页;增大上限后重读同一捕获。省略该参数
@@ -595,7 +613,9 @@ input retention.
595613
上限才能请求超过 8 KiB 的正文,最大仍受既有 capture 大小限制;上限包含转义、
596614
JSON 外层与换行,后续命令继承该值。Codex 0.162.1 定向验证采用 10,000 token 历史
597615
设置和 12,000 token code-mode 输出预算,每次直接转发一份 stdout。未知预算保持
598-
7900 字节原生默认;大输出请求不证明历史保留,缺失仍恢复同一 capture,不自动修改宿主设置。
616+
7900 字节原生默认;大输出请求不证明历史保留,缺失仍恢复同一 capture。
617+
读取参数本身不修改宿主设置。上述共享原生配置将 64000 字节分页与配套的历史和执行
618+
预算一起提供,仅开启的 worker 自动应用;尚未应用该配置的旧读取方保持小页边界。
599619
先读取 `content`,再沿 `next_command` 读至 `eof`,确保完整字节覆盖。
600620
读取器校验原始摘要;无需重抄正文或计算哈希。
601621
原有 `command` 仍从零开始,供旧读取方或内联输出不完整时重读;可选的首屏读取

‎loopx/cli_commands/quota_capture.py‎

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,8 @@
1818
from ..control_plane.quota.error_codes import QuotaCommandValidationError, QuotaDecisionTransportError
1919
from ..control_plane.turn_driver.decision_capture import (
2020
validate_handoff_socket, CONTEXT_CAPTURE_READ_GUIDANCE, CONTEXT_CAPTURE_PAGE_GUIDANCE, context_capture_read_command,
21-
NATIVE_CONTEXT_PAGE_BYTES, NATIVE_CONTEXT_PAGE_OUTPUT_BYTES,
21+
NATIVE_CONTEXT_PAGE_OUTPUT_BYTES,
22+
native_context_page_budget,
2223
read_context_capture_file as _read_capture,
2324
)
2425

@@ -35,7 +36,8 @@ def native_context_activation(args: argparse.Namespace) -> dict[str, Any]:
3536
def _capture_page(path: Path, raw: bytes, digest: str, *, offset: int, size: int,
3637
output_limit: int | None, instruction: bool,
3738
presentation: dict[str, Any] | None = None,
38-
next_page_bytes: int | None = None) -> dict[str, Any]:
39+
next_page_bytes: int | None = None,
40+
next_page_output_bytes: int | None = None) -> dict[str, Any]:
3941
end = min(offset + size, len(raw))
4042
while end < len(raw) and raw[end] & 0xC0 == 0x80:
4143
end -= 1
@@ -50,7 +52,7 @@ def page(text: str) -> dict[str, Any]:
5052
result["read_instruction"] = CONTEXT_CAPTURE_PAGE_GUIDANCE
5153
if cursor < len(raw):
5254
result["next_command"] = context_capture_read_command(path, digest, offset=cursor, page_bytes=next_page_bytes or size,
53-
max_page_output_bytes=output_limit)
55+
max_page_output_bytes=next_page_output_bytes or output_limit)
5456
return result
5557

5658
def fits(result: dict[str, Any]) -> bool:
@@ -78,7 +80,8 @@ def fits(result: dict[str, Any]) -> bool:
7880

7981

8082
def read_context_capture(args: argparse.Namespace, *, presentation: dict[str, Any] | None = None,
81-
next_page_bytes: int | None = None) -> dict[str, Any]:
83+
next_page_bytes: int | None = None,
84+
next_page_output_bytes: int | None = None) -> dict[str, Any]:
8285
"""Bounded local IO over immutable JSON, not a new context/authority owner.
8386
8487
Verify the complete byte digest on every page. The cursor addresses bytes
@@ -120,7 +123,8 @@ def read_context_capture(args: argparse.Namespace, *, presentation: dict[str, An
120123
raise ValueError("capture offset is outside the file or not a UTF-8 boundary; use the returned next offset")
121124
return _capture_page(path, raw, digest, offset=offset, size=size,
122125
output_limit=output_limit, instruction=bool(context_dir),
123-
presentation=presentation, next_page_bytes=next_page_bytes)
126+
presentation=presentation, next_page_bytes=next_page_bytes,
127+
next_page_output_bytes=next_page_output_bytes)
124128
except (OSError, ValueError, RecursionError) as exc:
125129
# Recovery is presentation-only: keep failures separate from quota's
126130
# collection error path and retain the existing receipt/capture.
@@ -147,8 +151,9 @@ def native_context_capture_view(projected: dict[str, Any], directory: Path, *,
147151
mode, target = projected["mode"], projected["target"]
148152
if mode == "full":
149153
reference = {key: projected["recovery"][key] for key in ("path", "sha256")}
154+
page_bytes, output_bytes = native_context_page_budget()
150155
reference["command"] = context_capture_read_command(Path(reference["path"]), reference["sha256"],
151-
page_bytes=NATIVE_CONTEXT_PAGE_BYTES, max_page_output_bytes=NATIVE_CONTEXT_PAGE_OUTPUT_BYTES)
156+
page_bytes=page_bytes, max_page_output_bytes=output_bytes)
152157
result = {"ok": True, **(metadata or {}), "mode": mode, **reference,
153158
**({"target": target} if target else {})}
154159
# The codec puts native continuity semantics before its change tree. Keep
@@ -167,7 +172,7 @@ def native_context_capture_view(projected: dict[str, Any], directory: Path, *,
167172
page = read_context_capture(argparse.Namespace(capture_file=reference["path"],
168173
capture_sha256=reference["sha256"], offset=0, page_bytes=3072,
169174
format="json", max_page_output_bytes=NATIVE_CONTEXT_PAGE_OUTPUT_BYTES),
170-
presentation=result, next_page_bytes=NATIVE_CONTEXT_PAGE_BYTES)
175+
presentation=result, next_page_bytes=page_bytes, next_page_output_bytes=output_bytes)
171176
if page["ok"]:
172177
result = page
173178
from ..control_plane.turn_driver.codex_context import register_native_context_view
@@ -482,7 +487,7 @@ def handle_native_context_command(args: argparse.Namespace, *, print_payload: Ca
482487
cli_argv=cli_argv, scenario=activation["scenario"], session_root=bool(getattr(args, "codex_context_root", None)),
483488
inherit_machine=bool(machine_runtime))
484489
payload = {"ok": True, "context_delivery": activation, "native_config": config,
485-
"activation": "Merge hooks and append developer_instructions to the existing native configuration; "
490+
"activation": "Apply config_overrides, merge hooks and append developer_instructions to the existing native configuration; "
486491
"review and trust only these exact hooks in Codex. "
487492
"Existing loaded threads may retain their original hook configuration; enabled/trusted "
488493
"discovery is not session initialization or live adoption. Start/resume through the host "
@@ -492,7 +497,9 @@ def handle_native_context_command(args: argparse.Namespace, *, print_payload: Ca
492497
"Pass --context-delivery on with the same declared host mode, context location and a decision-output-root to heartbeat-prompt/should-run. ")
493498
+
494499
"Normal completed full reads establish an explicit continuity assumption; no input diagnostics or provider change is required. "
495-
"Known invalidation or incomplete reads keep full recovery. Set --context-delivery off and remove context options to restore ordinary output. "
500+
"The generated output profile uses 64000-byte continuations and a 20000-token native history limit; "
501+
"unknown budgets retain small pages. Known invalidation or incomplete reads keep full recovery. "
502+
"Set --context-delivery off and remove the generated context configuration, including its output overrides, to restore ordinary output. "
496503
"This command installs nothing and grants no execution authority."}
497504
except (OSError, ValueError, TypeError) as exc:
498505
payload = {"ok": False, "reason": str(exc)}

0 commit comments

Comments
 (0)