Skip to content

fix(chat): real-test fixes; remove prx agent in favour of prx chat --message - #206

Merged
g1e2x87 merged 21 commits into
mainfrom
feat/chat-fixes-agent-removal
Nov 15, 2026
Merged

g1e2x87 merged 21 commits into
mainfrom
feat/chat-fixes-agent-removal

Conversation

@g1e2x87

@g1e2x87 g1e2x87 commented Nov 15, 2026

Copy link
Copy Markdown
Member

Chat fixes from the Part-2 real test, and prx agent folded into prx chat --message

The post-landing prx chat real test of the decision-engine strip found 8 bugs. This PR fixes them and removes the prx agent subcommand. Spec: REQ-CHAT-FIXES-AND-AGENT-REMOVAL.md, Codex-audited in 3 rounds, with controller rulings CR-1..CR-14.

Turn gates removed

  • Deleted the execution-requirement assessment and the completion review. Both were extra model calls that could fail an otherwise good turn ("execution is unverified", "violated an explicit request constraint").
  • The LLM decides tool use. Approval, policy and the executor remain the only enforcement.
  • Guarded delivery is unchanged: the response guards and outbound middleware run before anything renders.

Fixes

  • Supervised approvals: every tool can be approved in every front end. file_edit gets a single-use signed grant. --plain and --message show a terminal [y/N/a] prompt, and the TUI card gains [a] always.
  • Config hot reload: reloads run inside the runtime, so the decision engine can be enabled while the daemon runs.
  • Compaction: switch compaction works in the TUI and --plain. Manual /compact is forced and reports a lossy fallback honestly. /compact, the footer and the turn share one budget.
  • Chat lineage: the sessions tools are direct on chat turns and inherited by task and process children. Cron and xin are unchanged.
  • Recovery: no repeated "registry reconciliation unconfirmed" warning against a live owner.
  • Subscription usage: recorded as a $0 ledger row marked subscription, through the recovery outbox and exactly once across restarts. prx cost shows requests and tokens.
  • Smaller fixes:
    • prx service status names only the PRX job.
    • Unknown /api/* paths return 404 JSON.
    • New prx decision-engine analyses command; status asks the daemon first.
    • The current session id is shown.

prx agent removed

  • prx chat --message / -q runs one turn through the chat pipeline.
  • stdout carries the reply only. Exit codes: 0 success, 2 policy refusal (reply still printed), 1 other error.
  • Turns are not saved by default; --save, --session and --continue keep them.
  • prx go --message and --workdir use it too.
  • Migrated to --message: the Harbor benchmark adapter and its tests, the integration tests, the bootstrap hint and the docs.
  • The internal engine used by cron, xin and skill evaluation stays.

Verification (before this PR)

Full CI gate set mirrored on qaa at 9873218 (same toolchain, nextest profile and guard as CI). quick, fmt, both clippy runs, machete, architecture_boundaries (268) and doc-tests all PASS. Tests: 11102/11102 passed.

After landing

Regression real test on the Mac, from main, installed. Everything runs in one continuous prx chat session across the TUI and --plain: planted facts, automatic and manual compaction recall, every approval path, engine toggling while the service runs, cost/usage, prx chat --message exit codes, and a re-check of every demo bug.

…mpletion review; keep guarded delivery

The assessment and the completion review are deleted with no replacement
(CR-1): the model decides tool use; approval, policy and the executor are
the only enforcement. The adapter field verify_chat_completion becomes
guarded_delivery with the same values; response guards and outbound
middleware still run before any chat text renders (CR-6).

Mock provider, fixtures and docs drop the auxiliary requests. New real-wire
tests: TUI tool turn sends only main requests; guarded delivery over real
SSE in the TUI and in chat --plain (rejected draft never renders,
middleware output renders once and equals the persisted reply).
…not fight the live owner

The config watcher reloads inside the captured runtime context so
participants that build runtime-bound components can prepare; without a
runtime the reload is refused with ReloadRuntimeUnavailable.

Restart recovery treats a live registry row of the same owner as the sole
owner of the run before any source-identity check; only an upgrade of a
recovery-only row must match the recovered source. An unconfirmed
reconciliation warns once per launch per process.

Tests: hotreload participant in runtime context and refusal without one;
real-SQLite restore of a live row; real daemon applying decision-engine
toggles via hot reload; held chat --plain parent across a recovery sweep.
…N/a prompt for --plain

file_edit mints the same signed single-use file_edit:edit:* grant as
file_write. Line-mode chat asks on the controlling terminal (y once,
a for the session, anything else or EOF denies; Ctrl-C cancels the
turn); without a terminal only OPENPRX_APPROVAL_OVERRIDE can allow.
The fullscreen approval card gains the same session-wide 'a'.
…manual /compact, one budget, session id display
…scription usage counted through the recovery outbox
…ON; decision-engine analyses and daemon-backed status
…line; --save, --workdir; go --message and migrated callers
… tool surface

Root cause of the NO-HANDOFF regression in switch_compaction_and_recall
(TUI and plain): CF-R6 (G5) publishes sessions_spawn, sessions_send,
sessions_list and session_status directly on the chat surface (+7,429 bytes
of native schema). Measured from the llm.request.context.compiled estimates
(cl100k proxy), the reserved tool surface grew from 540 + 116 + 4 = 660 to
2,212 + 132 + 4 = 2,348 tokens (+1,688). In the 4,000-token test window the
history kept 4,000 - 256 - 2,348 = 1,396 tokens, 531 of them the system
prompt, so neither the handoff nor one tool-heavy turn fit and every switch
ended in a lossy trim that dropped the handoff before the recall turn.

Counterfactual on the same tree: excluding the four tools via
tool_tiering.always_exclude makes the unchanged 4,000 test pass, so the
budget is the only cause (G6 touches no chat budget code). The budget
arithmetic and the compaction code are correct: a surface that leaves no
room for the handoff must trim lossily.

The shared SMALL_WINDOW_TOKENS moves to tests/support/compaction_script.rs
at 5,700, restoring the pre-G5 history room:
5,700 - 256 - 2,348 = 3,096 (was 4,000 - 256 - 660 = 3,084).
…gine stays for cron, xin and skill evaluation

Deletes Commands::Agent and its help, CliCommand::Agent, AgentRunner, the
interactive REPL branch, boxed_cli_interactive, agent::run, AgentTurnRefused,
agent_cli_exit_code and AGENT_REFUSAL_EXIT_CODE with their re-export and exit
mapping. run_with_runtime_envelope takes message: String; run_quiet calls it
directly. A refused non-quiet run prints the reply and returns the original
ProviderSendRefused (D6). Architecture guards: entry.rs decision handoffs
2 -> 1, one forwarded compaction site; chat entry forwarding and the launchctl
status inventory row updated for G6/G7.
…on, xin and skill evaluation are the internal agent engine

README, configuration, tools, providers and web-console pages document
prx chat --message / --workdir and the terminal y/N/a prompt; the scheduled
paths are the internal agent engine and the operator tuple is the
local-operator CLI tuple. One migration entry for the removal. Source
comments and the hint-routing warning follow the same split.
matches! for the subscription replay branch, map_or_else for the launchd
state, no redundant clones in the new tests, JSON pointer reads instead of
indexing in the report test, struct-init config in the loopback support,
clone_from/clone_into assignments, const Pty::mark.
… class of their verified terminal settlement
…d record the refusal note without terminal-tui
…urn is refused before its input write

GatewayPendingInput::record returned early with ? when ingress preparation
failed, dropping the oneshot acknowledgement it had registered with the job
monitor. The monitor then read the drop as "terminal cleanup acknowledgement
was lost" and replaced the turn's own failure with that message. The
refused owner now answers its acknowledgement (nothing was written, so the
cleanup is confirmed and empty), the admission guard answers it when it
unwinds before a receipt, the terminal guard answers it when it cannot bind,
the webhook binds its terminal before the handoff, and the job monitor keeps
the work's own failure next to any unconfirmed cleanup.
…gement owner

The webhook admission path held its registered job-monitor acknowledgement
and cleanup ticket as bare locals across the ingress-preparation await.
Killing the job while preparation was pending dropped the sender unanswered
("terminal cleanup acknowledgement was lost") and dropped the unfinished
ticket, latching the gateway cleanup owner failed.

GatewayPendingInput now carries a PreInputOwner, built where both are
registered. Its Drop settles every exit before the input write (refusal,
error, cancellation, abort) as a confirmed empty cleanup; ingress
preparation keeps running to completion in its own task under its own
ticket. The write owner takes both parts synchronously before the spawn.

Test: a real async webhook job over real SQLite is killed while ingress
preparation is held through a test-only pause; the job ends cancelled with
no lost acknowledgement, the tracker is not latched failed, and a later
turn succeeds.
…ay have no swap — guarantee 24 GiB RAM+swap before the lib archive

The all-features lib test binary is one rustc whose peak RSS measured 16.9 GiB (3d38836 and main 614280a; 15.9 GiB even with CARGO_BUILD_JOBS=1). ubuntu-latest has 16 GiB RAM and only the image's 4 GiB /mnt swap when the VM has an Azure resource disk, so runners without it are lost mid-build (exit 143 or no log). The hosted lib job now adds a swap file so RAM + swap >= 24 GiB, failing loudly if the disk cannot hold it. Tests, features and targets are unchanged.
@g1e2x87
g1e2x87 merged commit 3c28471 into main Nov 15, 2026
32 checks passed
@g1e2x87
g1e2x87 deleted the feat/chat-fixes-agent-removal branch November 15, 2026 11:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant