Skip to content

refactor(core): replace positional execute params with ExecuteOptions bag#22674

Merged
adamfweidman merged 9 commits intomainfrom
afw/execute-options
Mar 16, 2026
Merged

refactor(core): replace positional execute params with ExecuteOptions bag#22674
adamfweidman merged 9 commits intomainfrom
afw/execute-options

Conversation

@adamfweidman
Copy link
Contributor

@adamfweidman adamfweidman commented Mar 16, 2026

Summary

Replaces positional shellExecutionConfig and setExecutionIdCallback parameters on execute() / executeToolWithHooks() with a single ExecuteOptions bag. This makes it straightforward to add new execution options (e.g. completionBehavior for background tasks) without growing positional parameter lists.

Details

  • Adds ExecuteOptions interface in tools.ts with shellExecutionConfig and setExecutionIdCallback fields
  • Updates ToolInvocation interface, BaseToolInvocation, DeclarativeTool.buildAndExecute, ShellToolInvocation.execute, executeToolWithHooks, and ToolExecutor call sites
  • Nests sanitizationConfig under shellExecutionConfig in a2a-server / ACP memory commands

The immediate motivation is that downstream PRs need to add completionBehavior for background task support. Without this refactor, that would mean yet another positional parameter that most callers pass as undefined:

// Before: positional params that most callers don't use
execute(signal, updateOutput, shellExecutionConfig, setExecutionIdCallback)

// After: options bag
execute(signal, updateOutput, options?: ExecuteOptions)

Part 2 of the background task support stack (base: #22544)

Related Issues

Related to #18197

How to Validate

  • CI passes across all workspaces
  • Existing tests in coreToolHookTriggers.test.ts, tool-executor.test.ts, and memory.test.ts updated and passing

Pre-Merge Checklist

  • Updated relevant documentation and README (if needed)
  • Added/updated tests (if needed)
  • Noted breaking changes (if any)
  • Validated on required platforms/methods:
    • MacOS
      • npm run
      • npx
      • Docker
      • Podman
      • Seatbelt
    • Windows
      • npm run
      • npx
      • Docker
    • Linux
      • npm run
      • npx
      • Docker

…ckground completion support

Rename UserHintService to InjectionService as a generic, source-agnostic
injection mechanism. InjectionService supports typed sources ('user_steering'
and 'background_completion') with source-specific gating — user_steering
respects the model steering toggle while background_completion always fires.

Add background completion lifecycle to ExecutionLifecycleService: tracks
backgrounded executions, fires onBackgroundComplete listeners when they
settle, and supports FormatInjectionFn callbacks so execution creators
control how their output is formatted for reinjection.

Wire AppContainer to route background completions through InjectionService
and submit them to the model when idle, independent of model steering.
Wire ExecutionLifecycleService.setInjectionService() in Config constructor
so backgrounded executions inject directly via settleExecution instead of
routing through a useEffect bridge in AppContainer.
…nt loop

The agent loop in local-executor now listens via onInjection (all sources)
instead of onUserHint (steering only), picking up background completions
between turns. This removes the separate bg completion useEffect, refs,
state, and callback from AppContainer entirely.
…rface

Remove legacy onUserHint/offUserHint/addUserHint methods. All callers
now use addInjection(text, source) and onInjection/offInjection with
source-based filtering where needed.
…ve dead code

Rename getUserHints/getUserHintsAfter/getLatestHintIndex to
getInjections/getInjectionsAfter/getLatestInjectionIndex with optional
source filter so bg completions don't get formatted as user hints.

Swap unshift ordering so bg completions appear before user hints in the
message — the model sees context before the user's reaction to it.

Remove unused getLastUserHintAt().
Wrap background completion output in <background_output> XML tags with
inline instructions to treat as data, consistent with <user_input> tags
used for user steering hints.

Guard listener iteration in InjectionService.addInjection and
ExecutionLifecycleService.settleExecution with try/catch so a throwing
listener doesn't block subsequent listeners or crash the caller.
… flow

Tests cover XML tag wrapping with safety instruction, ordering
(background completions before user hints), and source filtering
to prevent background output from leaking into user hint getters.
… bag

Collapse shellExecutionConfig and setExecutionIdCallback into a single
optional ExecuteOptions object on ToolInvocation.execute(). This avoids
forcing every tool implementation to accept shell-specific parameters
just to reach later positional args.
@adamfweidman adamfweidman requested review from a team as code owners March 16, 2026 16:13
@gemini-cli
Copy link
Contributor

gemini-cli bot commented Mar 16, 2026

Hi @adamfweidman, thank you so much for your contribution to Gemini CLI! We really appreciate the time and effort you've put into this.

We're making some updates to our contribution process to improve how we track and review changes. Please take a moment to review our recent discussion post: Improving Our Contribution Process & Introducing New Guidelines.

Key Update: Starting January 26, 2026, the Gemini CLI project will require all pull requests to be associated with an existing issue. Any pull requests not linked to an issue by that date will be automatically closed.

Thank you for your understanding and for being a part of our community!

@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a significant refactoring to the core tool execution mechanism by consolidating multiple positional parameters into a single, extensible ExecuteOptions object. This change simplifies function signatures, improves readability, and provides a clear path for adding new execution-related configurations without altering existing parameter lists. The update ensures that the tool invocation API remains clean and adaptable as new features, such as background task support, are integrated.

Highlights

  • Refactored Tool Execution Parameters: Replaced multiple positional parameters (shellExecutionConfig, setExecutionIdCallback) in execute() and executeToolWithHooks() with a single ExecuteOptions object, enhancing API extensibility.
  • Introduced ExecuteOptions Interface: Defined a new ExecuteOptions interface in tools.ts to encapsulate various execution-related configurations, making it easier to add future options.
  • Updated Call Sites and Implementations: Modified ToolInvocation, BaseToolInvocation, DeclarativeTool.buildAndExecute, ShellToolInvocation.execute, executeToolWithHooks, and ToolExecutor to adopt the new ExecuteOptions parameter.
  • Nested sanitizationConfig: Adjusted sanitizationConfig to be nested under shellExecutionConfig within the new ExecuteOptions structure in a2a-server and ACP memory commands.
Changelog
  • packages/a2a-server/src/commands/memory.test.ts
    • Updated sanitizationConfig to be nested under shellExecutionConfig within the execution options.
  • packages/a2a-server/src/commands/memory.ts
    • Updated sanitizationConfig to be nested under shellExecutionConfig when calling buildAndExecute.
  • packages/cli/src/acp/commands/memory.ts
    • Updated sanitizationConfig to be nested under shellExecutionConfig when calling buildAndExecute.
  • packages/core/src/core/coreToolHookTriggers.test.ts
    • Modified mock execute method to accept an options object instead of separate parameters.
    • Updated calls to executeToolWithHooks to pass an options object.
  • packages/core/src/core/coreToolHookTriggers.ts
    • Imported ExecuteOptions and removed ShellExecutionConfig import.
    • Updated the signature of executeToolWithHooks to use a single options parameter.
    • Adjusted the call to invocation.execute to pass the new options object.
  • packages/core/src/scheduler/tool-executor.test.ts
    • Updated mock executeToolWithHooks implementation to access setExecutionIdCallback from the options object.
  • packages/core/src/scheduler/tool-executor.ts
    • Modified the call to executeToolWithHooks to bundle shellExecutionConfig and setExecutionIdCallback into an options object.
  • packages/core/src/tools/shell.ts
    • Imported ExecuteOptions and removed ShellExecutionConfig import.
    • Updated the execute method signature to accept an options object.
    • Destructured shellExecutionConfig and setExecutionIdCallback from the options object.
  • packages/core/src/tools/tools.ts
    • Added the ExecuteOptions interface to define a bag for tool execution parameters.
    • Updated the ToolInvocation interface to use options instead of separate positional parameters.
    • Modified BaseToolInvocation abstract method signature to accept options.
    • Updated DeclarativeTool.buildAndExecute method signature and call to invocation.execute to use options.
Activity
  • The pull request description indicates that CI passes across all workspaces.
  • Existing tests in coreToolHookTriggers.test.ts, tool-executor.test.ts, and memory.test.ts were updated and are passing.
  • The pre-merge checklist shows that tests have been added/updated.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request refactors several tool execution methods to replace positional parameters (shellExecutionConfig and setExecutionIdCallback) with a single ExecuteOptions options bag. The changes are applied across interfaces (ToolInvocation), base classes (BaseToolInvocation, DeclarativeTool), concrete implementations (ShellToolInvocation), and core functions (executeToolWithHooks), along with their corresponding call sites and tests. This change improves API extensibility for tool execution.

Copy link
Collaborator

@mattKorwel mattKorwel left a comment

Choose a reason for hiding this comment

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

LGTM

Base automatically changed from afw/injection-service-infra to main March 16, 2026 21:20
# Conflicts:
#	packages/a2a-server/src/commands/memory.ts
#	packages/cli/src/acp/commands/memory.ts
@adamfweidman adamfweidman enabled auto-merge March 16, 2026 21:38
@github-actions
Copy link

Size Change: -31 B (0%)

Total Size: 26.2 MB

Filename Size Change
./bundle/chunk-D4UIQLPZ.js 0 B -13.5 MB (removed) 🏆
./bundle/chunk-GUH5F274.js 0 B -1.95 MB (removed) 🏆
./bundle/chunk-VHGQ6DP2.js 0 B -3.62 MB (removed) 🏆
./bundle/core-J3LLDXJD.js 0 B -41.1 kB (removed) 🏆
./bundle/devtoolsService-Z6FZLLHM.js 0 B -27.7 kB (removed) 🏆
./bundle/interactiveCli-S5LCTDKV.js 0 B -1.6 MB (removed) 🏆
./bundle/oauth2-provider-OYD37VZO.js 0 B -9.19 kB (removed) 🏆
./bundle/chunk-D3SBJUBW.js 13.5 MB +13.5 MB (new file) 🆕
./bundle/chunk-GGX3XPYO.js 3.62 MB +3.62 MB (new file) 🆕
./bundle/chunk-ONNDQLAT.js 1.95 MB +1.95 MB (new file) 🆕
./bundle/core-LTDEII7D.js 41.1 kB +41.1 kB (new file) 🆕
./bundle/devtoolsService-AKJEIDNA.js 27.7 kB +27.7 kB (new file) 🆕
./bundle/interactiveCli-GALGAV7I.js 1.6 MB +1.6 MB (new file) 🆕
./bundle/oauth2-provider-OL6J6MKQ.js 9.19 kB +9.19 kB (new file) 🆕
ℹ️ View Unchanged
Filename Size Change
./bundle/chunk-34MYV7JD.js 2.45 kB 0 B
./bundle/chunk-37ZTTFQF.js 966 kB 0 B
./bundle/chunk-5AUYMPVF.js 858 B 0 B
./bundle/chunk-664ZODQF.js 124 kB 0 B
./bundle/chunk-DAHVX5MI.js 206 kB 0 B
./bundle/chunk-IUUIT4SU.js 56.5 kB 0 B
./bundle/chunk-RJTRUG2J.js 39.8 kB 0 B
./bundle/devtools-36NN55EP.js 696 kB 0 B
./bundle/dist-T73EYRDX.js 356 B 0 B
./bundle/gemini.js 695 kB +46 B (+0.01%)
./bundle/getMachineId-bsd-TXG52NKR.js 1.55 kB 0 B
./bundle/getMachineId-darwin-7OE4DDZ6.js 1.55 kB 0 B
./bundle/getMachineId-linux-SHIFKOOX.js 1.34 kB 0 B
./bundle/getMachineId-unsupported-5U5DOEYY.js 1.06 kB 0 B
./bundle/getMachineId-win-6KLLGOI4.js 1.72 kB 0 B
./bundle/memoryDiscovery-AXX4BZNZ.js 0 B -922 B (removed) 🏆
./bundle/multipart-parser-KPBZEGQU.js 11.7 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/client/main.js 221 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/_client-assets.js 227 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/index.js 11.5 kB 0 B
./bundle/node_modules/@google/gemini-cli-devtools/dist/src/types.js 132 B 0 B
./bundle/sandbox-macos-permissive-open.sb 890 B 0 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB 0 B
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB 0 B
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB 0 B
./bundle/sandbox-macos-strict-open.sb 4.82 kB 0 B
./bundle/sandbox-macos-strict-proxied.sb 5.02 kB 0 B
./bundle/src-QVCVGIUX.js 47 kB 0 B
./bundle/tree-sitter-7U6MW5PS.js 274 kB 0 B
./bundle/tree-sitter-bash-34ZGLXVX.js 1.84 MB 0 B
./bundle/undici-4X2YZID5.js 360 B 0 B
./bundle/memoryDiscovery-IWDP2KJG.js 922 B +922 B (new file) 🆕

compressed-size-action

@adamfweidman adamfweidman added this pull request to the merge queue Mar 16, 2026
Merged via the queue into main with commit 605432e Mar 16, 2026
27 checks passed
@adamfweidman adamfweidman deleted the afw/execute-options branch March 16, 2026 22:09
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.

2 participants