Skip to content

fix(skill): stop hardcoding invoke_agent in load-skill override-forwarding prose - #3485

Merged
kwakayama merged 2 commits into
mainfrom
fix/delegation-tool-naming
Aug 8, 2026
Merged

fix(skill): stop hardcoding invoke_agent in load-skill override-forwarding prose#3485
kwakayama merged 2 commits into
mainfrom
fix/delegation-tool-naming

Conversation

@kwakayama

@kwakayama kwakayama commented Aug 8, 2026

Copy link
Copy Markdown
Contributor

Fixes veryfront/veryfront-issue-inbox#411

Summary

LOAD_SKILL_OVERRIDE_FORWARDING in src/skill/load-skill-policy.ts hard-coded the tool name invoke_agent, but some runs expose only scoped delegate tools named agent_<id> and no invoke_agent at all. On those runs the policy prose named a tool that isn't present.

This is pre-existing (found by Codex review on PR #3475, not introduced by it) and low severity — there's no measured impact from it. It's filed and fixed for consistency with the standard already applied to the surrounding prompt surface, not because of an observed failure.

Investigation

Swept every invoke_agent occurrence in src/:

grep -rn "invoke_agent" --include='*.ts' src/ | grep -v '\.test\.'

Every hit besides LOAD_SKILL_OVERRIDE_FORWARDING is either:

  • a legitimate code reference (tool ids/constants like INVOKE_AGENT_TOOL_ID, registry lookups, tracing span names, Set/array membership checks), or
  • a message/comment that only fires while the invoke_agent tool is actually executing (e.g. depth-limit errors, cancellation-retry messages in child-invoke-tool.ts / child-tool-input.ts / default-invoke-agent-tool.ts), so the name is accurate in that context — the tool did exist for that call.

Only LOAD_SKILL_OVERRIDE_FORWARDING is prose describing a delegation tool ahead of knowing whether it exists in the current run, so it's the only change in scope.

Change

Before:

"Pass through any returned model, thinking, or maxSteps overrides to invoke_agent when delegating."

After:

"Pass through any returned model, thinking, or maxSteps overrides to the available delegation tool when delegating."

This wording is correct regardless of which delegation tool (invoke_agent or a scoped agent_<id>) exists in a given run, since tool descriptions are static strings and can't be made dynamic to the run's tool inventory.

Design constraint preserved

LOAD_SKILL_OVERRIDE_FORWARDING remains appended only to the hosted tool's description (RUNTIME_LOAD_SKILL_DESCRIPTION in src/agent/runtime/load-skill-tool.ts), not to the factory-built createLoadSkillTool description in src/skill/tools.ts — only the hosted loader returns override fields (model/thinking/maxSteps). The existing pinning test for that asymmetry (src/skill/tools.test.ts, "promises override forwarding only from the loader that returns overrides") is untouched and still passes.

Files changed

  • src/skill/load-skill-policy.ts — reworded LOAD_SKILL_OVERRIDE_FORWARDING
  • src/skill/tools.test.ts — added a regression test pinning the new wording and asserting it no longer hardcodes invoke_agent

Test plan

  • New test added: does not hardcode a specific delegation tool name in src/skill/tools.test.ts. Verified it fails against the old wording (git stash of the policy file only) and passes after the fix.
  • DENO_TESTING=1 VF_DISABLE_LRU_INTERVAL=1 NODE_ENV=production LOG_FORMAT=text deno test --preload=src/schemas/_test-setup.ts --parallel --allow-all --no-check src/skill/ src/agent/1183 passed (2057 steps) | 0 failed
  • deno task typecheck → exit 0
  • deno lint → exit 0, "Checked 4882 files"
  • deno task lint:test-typecheck → exit 0, "Test typecheck baseline holds: 51 grandfathered files, 0 new."
  • deno task docs:api-reference:check → exit 0, "docs/api-reference is current (43 files)" (no regeneration needed)
  • deno fmt src/ → no changes
  • Pre-push hook full suite → 3769 passed (28028 steps) | 0 failed | 1 ignored (5 steps)

Claude-Session: https://claude.ai/code/session_01Xo93b6StAu691YV9g8Fm53

Summary by CodeRabbit

  • Bug Fixes

    • Improved skill-loading instructions to forward model, thinking, and step-limit settings to the available delegation tool.
    • Prevented delegation guidance from relying on a specific tool name.
  • Tests

    • Added coverage to verify delegation instructions remain tool-agnostic.

…rding prose

Some runs expose only scoped delegate tools named agent_<id> and no
invoke_agent, so the hardcoded name pointed the model at a tool that
wasn't there. Reword the hosted-only override-forwarding clause to
refer to "the available delegation tool" instead.

Claude-Session: https://claude.ai/code/session_01Xo93b6StAu691YV9g8Fm53
@kwakayama
kwakayama requested a review from kojiwakayama as a code owner August 8, 2026 19:44
@coderabbitai

coderabbitai Bot commented Aug 8, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@kwakayama, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 15 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d61a55a6-9504-4e85-9623-d2020930809a

📥 Commits

Reviewing files that changed from the base of the PR and between 9b5cc7a and a78f34f.

📒 Files selected for processing (3)
  • docs/api-reference/veryfront/agent.md
  • src/skill/load-skill-policy.ts
  • src/skill/tools.test.ts
📝 Walkthrough

Walkthrough

The load-skill override guidance now uses the available delegation tool instead of naming invoke_agent. A regression test verifies this tool-agnostic wording.

Changes

Load-skill delegation policy

Layer / File(s) Summary
Tool-agnostic override forwarding
src/skill/load-skill-policy.ts, src/skill/tools.test.ts
The policy forwards returned model, thinking, or maxSteps values to the available delegation tool. The regression test confirms that the guidance does not hardcode invoke_agent.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Possibly related PRs

Suggested reviewers: kojiwakayama

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: removing the hard-coded invoke_agent name from load-skill override-forwarding prose.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/delegation-tool-naming

Comment @coderabbitai help to get the list of available commands.

@chatgpt-codex-connector chatgpt-codex-connector 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.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 9b5cc7a0eb

ℹ️ 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".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/skill/load-skill-policy.ts Outdated
*/
export const LOAD_SKILL_OVERRIDE_FORWARDING =
"Pass through any returned model, thinking, or maxSteps overrides to invoke_agent when delegating.";
"Pass through any returned model, thinking, or maxSteps overrides to the available delegation tool when delegating.";

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Limit override forwarding to tools that support it

When a hosted agent declares delegates, buildLocalTools replaces invoke_agent with scoped agent_<id> tools, whose schema accepts only input and whose wrapper forwards only that value; applySkillDelegationOverridesToToolInput also recognizes only invoke_agent. After such an agent loads a skill with model, thinking, or maxSteps, this generic instruction therefore tells it to pass settings that its available delegation tool cannot represent, so the skill's requested settings are not applied. Keep the clause conditional on legacy invoke_agent, or implement override propagation for scoped delegate tools.

AGENTS.md reference: AGENTS.md:L13-L13

Useful? React with 👍 / 👎.

Generalising the clause to "the available delegation tool" was wrong. It
is not a naming problem: override forwarding only ever works for
invoke_agent, by design.

applySkillDelegationOverridesToToolInput returns its input unchanged for
any tool name other than invoke_agent, and scoped agent_<id> delegates
accept only { input } (AgentToolInput). A scoped delegate therefore
cannot carry model, thinking, or maxSteps at all. The generalised wording
told the model to do something impossible on those runs - worse than the
original, which at least named the one tool where it works.

State the condition in the prose instead. On a run without invoke_agent
the instruction is a no-op; on a run with it, it is accurate. No dynamic
description needed.

Found by Codex review on this PR.

Claude-Session: https://claude.ai/code/session_01Xo93b6StAu691YV9g8Fm53
@kwakayama

Copy link
Copy Markdown
Contributor Author

Codex is right, and the finding is sharper than the issue I filed. Pushed a78f34f1e.

The original framing was wrong

veryfront/veryfront-issue-inbox#411 treated this as a naming problem: prose hardcodes invoke_agent, some runs do not have it, so generalise the name. This PR did that — "…to the available delegation tool…".

That made it worse. Verified on this branch:

Claim Evidence
Scoped delegates cannot carry overrides AgentToolInput is v.object({ input: v.string() })src/agent/schemas/tool.schema.ts:6-7. No model, thinking, or maxSteps.
Overrides are applied to invoke_agent only applySkillDelegationOverridesToToolInput returns its input unchanged unless toolName === INVOKE_AGENT_TOOL_IDsrc/agent/runtime/skill-delegation-overrides.ts:72

So on a scoped-delegation run, "pass through overrides to the available delegation tool" instructs the model to do something the tool physically cannot represent. The original wording at least named the one tool where forwarding works; its only flaw was naming a tool that might be absent.

Override forwarding is invoke_agent-only by design, not by accident. That is the fact the prose has to encode.

The fix

- Pass through any returned model, thinking, or maxSteps overrides to the available delegation tool when delegating.
+ If invoke_agent is available, pass through any returned model, thinking, or maxSteps overrides when delegating to it.

Conditional in the prose, so it is static-safe: a no-op on runs without invoke_agent, accurate on runs with it. No dynamic description required.

The test now pins the condition rather than the absence of a tool name, and the module comment records why the condition is load-bearing so the next person does not "simplify" it back.

Verification

  • src/skill/, src/agent/ — 1183 passed, 2057 steps, 0 failed
  • deno task typecheck — 0 errors
  • deno lint, lint:test-typecheck — OK
  • docs:api-reference:check — regenerated, current

@kwakayama
kwakayama added this pull request to the merge queue Aug 8, 2026
Merged via the queue into main with commit ed0574a Aug 8, 2026
31 checks passed
@kwakayama
kwakayama deleted the fix/delegation-tool-naming branch August 8, 2026 20:31
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