Skip to content

fix: reasoning distillation budget, hook-forced ask input and DAG node questions - #717

Merged
LeXwDeX merged 9 commits into
mainfrom
fix/distillation-budget-forced-ask
Oct 8, 2026
Merged

LeXwDeX merged 9 commits into
mainfrom
fix/distillation-budget-forced-ask

Conversation

@LeXwDeX

@LeXwDeX LeXwDeX commented Oct 8, 2026

Copy link
Copy Markdown
Owner

Issue for this PR

Closes #714
Closes #715
Closes #716

Why

A review of opt-in reasoning distillation found that it silently stopped after about ten turns per session, paused permanently after one transient failure, did quadratic work on the turn-end foreground path, and could adopt replacements longer than their source. A review of hook-forced permission asks found that users could approve one input while the tool ran a hook-rewritten one, and that a confirmed call could prompt twice. DAG nodes also had no guidance to ask their parent rather than the user, and the parent had none on how to answer.

Type of change

  • Bug fix
  • New feature
  • Refactor / code improvement
  • Documentation

What changed

  • Reasoning distillation (fix: reconcile reasoning distillation budget and gate unhelpful replacements #714): reservations reconciled with reported usage; calls without a response refunded, three consecutive failures pause; interrupted calls refunded inside the per-session lock in both hosts; reasoning below 32 estimated tokens skipped; replacements that are not smaller dropped; only the explicit marker clears a multi-part slot; new reasoningDistillation.language (zh default, en); turn-end snapshot limited to the completed turn; core runner honours the auxiliary timeout flag and a declared none variant; compatibility documented as legacy-only.
  • Hook-forced ask (fix: confirm the effective input for hook-forced permission asks #715): forced dialog and PermissionRequest hooks receive the effective input (with updatedInput); TUI and web app show it with the hook reason (bounded generic preview for edit/write/MCP tools) and hide "Allow always" when nothing would persist; a confirmed forced ask settles ask-level rules for the same call while deny rules still apply; tool parts keep the model's own input; ignored PermissionRequest allow logged; semantics documented.
  • DAG (fix: route DAG node questions to the parent and require grounded parent answers #716): agent tool and orchestration policy route node questions to the owning parent and require grounded parent answers.
  • v1.0.64 release notes updated.

What does this PR do?

Narrow fixes with regression tests. Adds one optional config field (reasoningDistillation.language); the regenerated v2 SDK type differs only by that field. No database schema, event identity or route change.

Evidence

Local, on this head:

  • bun run lint: 4796 warnings (main: 4796; cap 4850)
  • bun run typecheck: 31/31
  • core 1568 / 0, tui 282 / 0, app 456 / 0
  • opencode full suite: 5332 pass; 9 prompt.test.ts cases hit the 30 s timeout under host load, and prompt.test.ts alone passed 158 / 0
  • bun run test:dag-core: all critical behavior and coverage floors passed
  • bun run test:httpapi: 239 scenarios, 0 fail/skip/missing
  • packages/client generate + packages/sdk/js build: only the intended language field
  • Release notes render via script/release-notes.ts for graphagent-v1.0.64

How did you verify your code works?

New regression tests fail on the previous code (budget exhaustion, failure pause, interrupt refund, rewritten-input dialog, single confirmation). Isolated live checks used the configured DeepSeek and GLM models with a temporary config and database: a 3,309-character reasoning part was organized by one small-model call into 909 Chinese characters and adopted, with the reservation reconciled to reported usage; reasoning under the minimum was skipped without a call. An independent review of the diff found one medium and three low issues; all were fixed with tests.

Screenshots / recordings

Exercised in the TUI (attached to an isolated server) and the web app: a hook-forced ask with a rewritten command shows the hook reason, the rewritten command and only "Allow once / Reject"; approving runs the rewritten command once with no second dialog. A forced file write shows its path and content preview and was rejected without writing.

Checklist

  • I have tested my changes locally
  • I have not included unrelated changes in this PR

🤖 Generated with Claude Code

…cements

- Reconcile each organizer reservation with reported usage so long sessions
  keep distilling; refund calls without a response and pause only after three
  consecutive failures.
- Skip reasoning too small to repay the call and drop replacements that are not
  smaller; only the explicit marker clears a part in multi-part batches.
- Add reasoningDistillation.language (zh default, en) for organizer prose.
- Build a completed-turn-only snapshot on the turn-end path instead of hashing
  the whole session.
- Core runner honours the auxiliary timeout flag and a declared none variant.
- Document that compatibility records only gate the legacy wire projector.

Refs #714
- The forced dialog and PermissionRequest hooks receive the input the tool
  will run with, including updatedInput; the tool's own checks use it too.
- TUI and web app show the hook reason and the effective input, and hide
  "Allow always" when a request has nothing to remember.
- A confirmed forced ask settles ask-level rules for the same call without a
  second dialog; deny rules still apply.
- Log an ignored PermissionRequest allow and document forced-ask semantics,
  including approval under run --dangerously-skip-permissions.

Refs #715
…nt answers

Nodes ask their owning parent through the agent tool instead of the user, and
the parent answers with a conclusion grounded in the user's instructions or
checked evidence, stating remaining uncertainty and a safe course otherwise.

Refs #716
…odel input

- TUI shows a bounded preview of the effective input (path and content or
  arguments) for tools without an input-based view, such as edit, write,
  apply_patch and MCP tools; the web dock shows full arguments, not only a path.
- Tool parts keep the model's own input while the rewritten input runs, so
  history and doom-loop detection still compare model calls.

Refs #715
…lock

- Core runner refunds an admitted organizer call interrupted before a
  response; the previous flag never ran because interruption does not resume.
- OpenCode host aborts the organizer on interruption and waits for its
  accounting while the per-session lock is held.

Refs #714
@LeXwDeX
LeXwDeX marked this pull request as ready for review October 8, 2026 08:11
@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Oct 8, 2026 •

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-10-08T08:20:59.444224Z 41c7f47 Draft marked ready
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

The dock now hides "Allow always" when a request has no pattern to
persist, so the fixture with always: [] shows two actions. Assert the
exact actions for both cases.
@LeXwDeX
LeXwDeX enabled auto-merge October 8, 2026 08:27
@LeXwDeX
LeXwDeX merged commit 108cfa2 into main Oct 8, 2026
9 checks passed
@LeXwDeX
LeXwDeX deleted the fix/distillation-budget-forced-ask branch October 8, 2026 08:47
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant