Skip to content

feat(coding-agent): session_before_refine extension hook - #1558

Open
snimu wants to merge 5 commits into
mainfrom
feat/session-before-refine-hook
Open

feat(coding-agent): session_before_refine extension hook#1558
snimu wants to merge 5 commits into
mainfrom
feat/session-before-refine-hook

Conversation

@snimu

@snimu snimu commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

What this does

Adds a session_before_refine extension hook so extensions can customize continual-harness refinement the same way session_before_compact customizes compaction. Generalizes discussion #1464 (cheaper model for /refine) into an extensibility point for refinement-policy experimentation.

How it works

The hook fires before the planning LLM call for both /refine and auto-refine, with the planning inputs:

pi.on("session_before_refine", async (event, ctx) => {
  const { trigger, instructions, scope, planningState, history, conversationText } = event.preparation;
  return { proposal: { summary, rationale, expectedOutcome, edits } }; // replace the built-in planner
  // or { skip: true }  — suppress this refinement round
  // or undefined       — fall back to the default planner
});
  • Replace: extension proposals go through the exact same apply path as built-in plans — per-edit validateEdit plus baseline conflict rejection — so a bad proposal degrades to per-edit errors, never harness corruption.
  • Skip: manual /refine surfaces a RefineSkippedError; auto-refine treats it like a reviewer decline (serialized path maps it to the existing skip status).
  • Fallback: returning nothing runs the built-in planner unchanged.
  • Rollback refinements bypass the hook (mechanical, no LLM).
  • trigger distinguishes "manual" (/refine, refine.run) from "auto" (auto-refine), threaded through all three planning entry points (direct refine, queued/serialized refine, background auto-plan).
  • The internal planning prompt stays private; the public surface is the already-existing HarnessState / RefinementProposal / RefinementEdit types (now exported from the package index alongside the new event types).

Also included

  • examples/extensions/custom-refinement.ts — working example that plans with a cheaper model (the literal Allow using a different model for /refine #1464 ask, ~a screenful of code)
  • Docs: lifecycle diagram + event section in extensions.md, which also documents the previously undocumented refine_complete event
  • Tests (agent-session-refine-extension.test.ts): proposal replaces planner (no LLM call), invalid extension edits rejected at apply time, skip propagation, fallback-on-undefined

Validation

  • Full repo typecheck clean; biome clean
  • New suite passes plus all existing refine/compaction-extension suites (219 passed across refine-skill, serialized-refine, refinement, compaction-extensions, prompt-races; daemon serialized-refine suites green)

Linear: ENG-5323
Covers: #1464


Note

Medium Risk
Touches continual-harness planning and skip/failure semantics for both manual and auto-refine. Invalid extension proposals still fail at apply time rather than corrupting harness state.

Overview
Extensions can now intercept continual-harness refinement (/refine and auto-refine) via session_before_refine, matching the compaction hook pattern.

Handlers receive planning inputs (trigger, scope, harness state, history, truncated conversation) and may skip the round, replace the built-in planner with a RefinementProposal, or fall through. Rollbacks bypass the hook. Extension edits still go through the existing apply-time validation.

Skip is treated as a non-failure for auto-refine (like a reviewer decline) and as RefineSkippedError / refine_failed for explicit /refine. Docs, public types (RefinementProposal, event types), a cheaper-model example (custom-refinement.ts), and tests cover replace, skip, fallback, and invalid edits.

Reviewed by Cursor Bugbot for commit 1b1bb37. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add session_before_refine extension hook to agent session refinement

  • Adds a new session_before_refine extension event in agent-session.ts that fires before each refinement round, giving extensions the ability to skip refinement or supply a custom RefinementProposal without invoking the built-in planner.
  • Extensions receive the trigger type ('auto' or 'manual'), planning inputs, and a serialized conversation (truncated to ~80k chars); returning { skip: true } throws the new RefineSkippedError, and returning a proposal bypasses planning entirely.
  • Rollback-triggered refinements bypass the hook; explicit /refine skips surface as refine_failed, while auto-refine skips are treated as non-failures.
  • Exports new types (RefinePreparation, SessionBeforeRefineEvent, SessionBeforeRefineResult, RefinementProposal, etc.) from the public index and adds a custom-refinement.ts example.
  • Risk: extensions returning invalid edits in a proposal will fail at apply time, not at hook invocation time.

Macroscope summarized 1b1bb37.

Let extensions customize continual-harness refinement the same way
session_before_compact customizes compaction. The hook fires before the
planning LLM call for /refine and auto-refine with the planning inputs
(trigger, instructions, scope, planning harness state, refinement
history, serialized conversation). An extension can return a
RefinementProposal to replace the built-in planner (edits still pass
apply-time validation and baseline conflict rejection), return
{ skip: true } to suppress the round, or return nothing to fall back to
the default planner. Rollback refinements bypass the hook.

Includes examples/extensions/custom-refinement.ts (planning with a
cheaper model, covering discussion #1464) and documents the existing
refine_complete event.
Comment thread packages/coding-agent/src/core/agent-session.ts Outdated
Comment thread packages/coding-agent/src/core/agent-session.ts
Comment thread packages/coding-agent/src/core/agent-session.ts
Comment thread packages/coding-agent/src/core/agent-session.ts
Comment thread packages/coding-agent/examples/extensions/custom-refinement.ts
snimu added 3 commits August 19, 2026 11:45
…ne paths

Serialized auto-refine now reaches session_before_refine with trigger
"auto", an extension skip there stamps the cooldown without emitting
refine_failed, and a skipped explicit refine.run surfaces the
RefineSkippedError instead of passing as a silent reviewer decline. The
example planner now labels entry ids with their scope and tells the
model other-scope entries are read-only.
…efine-hook

# Conflicts:
#	packages/coding-agent/CHANGELOG.md

@cursor cursor Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit ba2a500. Configure here.

Comment thread packages/coding-agent/src/core/agent-session.ts
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