Skip to content

Pi Runner: gate parallel_tool_calls to compatible APIs#39356

Merged
vincentkoc merged 7 commits intomainfrom
vincentkoc-code/parallel-tool-calls-compat
Mar 8, 2026
Merged

Pi Runner: gate parallel_tool_calls to compatible APIs#39356
vincentkoc merged 7 commits intomainfrom
vincentkoc-code/parallel-tool-calls-compat

Conversation

@vincentkoc
Copy link
Copy Markdown
Member

Summary

  • Problem: some providers/models reject parallel_tool_calls, but OpenClaw still needs a way to pass the flag for compatible OpenAI-style payloads.
  • Why it matters: forcing the field into incompatible requests causes 400s that break tool execution entirely on affected models such as NVIDIA-hosted Kimi.
  • What changed: the embedded runner now honors parallel_tool_calls / parallelToolCalls only for openai-completions and openai-responses, preserves higher-precedence alias overrides across config/runtime layers, and ignores invalid non-boolean values.
  • What did NOT change (scope boundary): this does not add auto-retry on provider 400s, does not touch non-OpenAI payload schemas, and does not change unrelated runner/tool dispatch paths.

Change Type (select all)

  • Bug fix
  • Feature
  • Refactor
  • Docs
  • Security hardening
  • Chore/infra

Scope (select all touched areas)

  • Gateway / orchestration
  • Skills / tool execution
  • Auth / tokens
  • Memory / storage
  • Integrations
  • API / contracts
  • UI / DX
  • CI/CD / infra

Linked Issue/PR

User-visible / Behavior Changes

Model/provider params.parallel_tool_calls and params.parallelToolCalls now work for OpenAI-compatible request payloads without leaking into unsupported APIs. Higher-precedence overrides win even when different alias spellings are mixed.

Security Impact (required)

  • New permissions/capabilities? (No)
  • Secrets/tokens handling changed? (No)
  • New/changed network calls? (No)
  • Command/tool execution surface changed? (No)
  • Data access scope changed? (No)
  • If any Yes, explain risk + mitigation:

Repro + Verification

Environment

  • OS: macOS
  • Runtime/container: Node.js 22 + pnpm
  • Model/provider: unit-test path
  • Integration/channel (if any): n/a
  • Relevant config (redacted): n/a

Steps

  1. Configure parallel_tool_calls or parallelToolCalls in model params or runtime override.
  2. Route a request through applyExtraParamsToAgent(...) using openai-completions, openai-responses, and an unsupported API such as anthropic-messages.
  3. Observe payload mutation and alias precedence behavior.

Expected

  • supported OpenAI-style payloads receive the configured boolean
  • unsupported APIs are left untouched
  • higher-precedence alias overrides win even across snake/camel key styles
  • invalid non-boolean values are ignored with a warning

Actual

  • before this patch, there was no scoped runner handling for parallel_tool_calls, so affected providers could still fail from incompatible payload injection paths and mixed alias precedence could not be resolved cleanly

Evidence

  • Failing test/log before + passing after
  • Trace/log snippets
  • Screenshot/recording
  • Perf numbers (if relevant)

Human Verification (required)

What you personally verified (not just CI), and how:

  • Verified scenarios: pnpm vitest run src/agents/pi-embedded-runner-extraparams.test.ts; pnpm exec oxfmt --check src/agents/pi-embedded-runner/extra-params.ts src/agents/pi-embedded-runner-extraparams.test.ts; pnpm exec oxlint --type-aware src/agents/pi-embedded-runner/extra-params.ts src/agents/pi-embedded-runner-extraparams.test.ts
  • Edge cases checked: unsupported APIs no-op; mixed alias precedence across config + runtime; null override suppresses inherited value; invalid strings warn and skip injection
  • What you did not verify: live provider/channel end-to-end runs

Compatibility / Migration

  • Backward compatible? (Yes)
  • Config/env changes? (No)
  • Migration needed? (No)
  • If yes, exact upgrade steps:

Failure Recovery (if this breaks)

  • How to disable/revert this change quickly: revert commits b236476f87, af8b5035de, and bce1c1d5f6
  • Files/config to restore: src/agents/pi-embedded-runner/extra-params.ts, src/agents/pi-embedded-runner-extraparams.test.ts, CHANGELOG.md
  • Known bad symptoms reviewers should watch for: parallel_tool_calls injected into unsupported APIs, or mixed alias overrides losing higher-precedence values

Risks and Mitigations

  • Risk: alias resolution could preserve the wrong layer when snake_case and camelCase are mixed.
    • Mitigation: source-aware alias resolution is covered by explicit precedence tests for global->agent and config->runtime merges.
  • Risk: wrapper logs could imply payload mutation on unsupported APIs.
    • Mitigation: the log lives inside the API-gated wrapper, so it only fires when a compatible payload is actually being mutated.

Notes

  • pnpm check src/agents/pi-embedded-runner/extra-params.ts src/agents/pi-embedded-runner-extraparams.test.ts currently trips an unrelated pre-existing formatting issue in src/commands/status.service-summary.ts on this checkout, so verification here uses focused formatter/lint commands on the touched files instead of claiming a clean full check.

@vincentkoc vincentkoc self-assigned this Mar 8, 2026
@openclaw-barnacle openclaw-barnacle bot added agents Agent runtime and tooling size: M maintainer Maintainer-authored PR labels Mar 8, 2026
@vincentkoc vincentkoc marked this pull request as ready for review March 8, 2026 01:46
@greptile-apps
Copy link
Copy Markdown
Contributor

greptile-apps bot commented Mar 8, 2026

Greptile Summary

This PR adds API-gated handling for the parallel_tool_calls / parallelToolCalls extra param in the Pi embedded runner, fixing 400 errors on providers like NVIDIA-hosted Kimi that reject this field. The implementation introduces resolveAliasedParamValue (a last-write-wins alias resolver for snake_case/camelCase pairs) and createParallelToolCallsWrapper (a payload-level injector gated to openai-completions and openai-responses APIs), both wired through applyExtraParamsToAgent.

Strengths:

  • Alias resolution logic and API-gating are correct, with 7 targeted test cases covering injection, no-op, precedence, null suppression, and invalid-value warning
  • The resolveAliasedParamValue function reasonably prefers the snake_case key when a single source contains both aliases
  • Backward-compatible with no impact on unaffected APIs

Minor UX issue:

  • Passing parallelToolCalls: null to suppress an inherited value correctly prevents injection, but triggers log.warn("ignoring invalid parallel_tool_calls param: null") — the term "invalid" is misleading since null is a documented and intentional suppressor. Consider using a debug-level message or a distinct branch without the "invalid" framing.

Confidence Score: 4/5

  • Safe to merge; the change is backward-compatible, well-tested, and scoped to a clear injection guard with no risk of regressions on unaffected APIs.
  • The implementation is functionally correct: API-gating works as intended, alias resolution is sound, and all test cases pass. Deducting one point for the confusing log.warn message on null suppression — while not a functional bug, it produces misleading operator-facing messages that could trigger unnecessary investigation. This is a valid UX improvement worth addressing.
  • src/agents/pi-embedded-runner/extra-params.ts — the log message at lines 1305–1317 warrants clarification to distinguish intentional null suppression from truly invalid values.

Last reviewed commit: 045a821

@vincentkoc vincentkoc merged commit daecd2d into main Mar 8, 2026
22 of 26 checks passed
@vincentkoc vincentkoc deleted the vincentkoc-code/parallel-tool-calls-compat branch March 8, 2026 01:57
@aisle-research-bot
Copy link
Copy Markdown

aisle-research-bot bot commented Mar 8, 2026

🔒 Aisle Security Analysis

We found 1 potential security issue(s) in this PR:

# Severity Title
1 🔵 Low Log injection via unsanitized parallel_tool_calls value in warning message

1. 🔵 Log injection via unsanitized parallel_tool_calls value in warning message

Property Value
Severity Low
CWE CWE-117
Location src/agents/pi-embedded-runner/extra-params.ts:1311-1316

Description

The new applyExtraParamsToAgent logic logs an invalid parallel_tool_calls value by directly interpolating the user-controlled string into the log message.

  • rawParallelToolCalls can originate from extraParamsOverride (runtime overrides), which is not runtime-validated and can contain arbitrary strings.
  • When the value is a string, it is inserted verbatim into the warning message.
  • The console logger does not neutralize CR/LF characters, so an attacker can inject newlines to forge additional log lines (log forging / log injection), potentially confusing operators and downstream log parsers.

Vulnerable code:

const summary =
  typeof rawParallelToolCalls === "string"
    ? rawParallelToolCalls
    : typeof rawParallelToolCalls;
log.warn(`ignoring invalid parallel_tool_calls param: ${summary}`);

Recommendation

Neutralize untrusted values before writing them to logs (especially console logs).

Recommended approaches:

  1. Escape/encode the value (so newlines become \\n):
const summary =
  typeof rawParallelToolCalls === "string"
    ? JSON.stringify(rawParallelToolCalls) // escapes \r/\n etc.
    : typeof rawParallelToolCalls;
log.warn(`ignoring invalid parallel_tool_calls param: ${summary}`);
  1. Or strip CR/LF and cap length:
const summary =
  typeof rawParallelToolCalls === "string"
    ? rawParallelToolCalls.replace(/[\r\n]/g, " ").slice(0, 200)
    : typeof rawParallelToolCalls;
log.warn(`ignoring invalid parallel_tool_calls param: ${summary}`);

Also consider logging structured metadata rather than interpolating raw values into the message string (e.g. log.warn("ignoring invalid parallel_tool_calls param", { valueType: typeof rawParallelToolCalls })).


Analyzed PR: #39356 at commit fd52dbd

Last updated on: 2026-03-08T02:43:17Z

openperf pushed a commit to openperf/moltbot that referenced this pull request Mar 8, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
mcaxtr pushed a commit to mcaxtr/openclaw that referenced this pull request Mar 8, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
Saitop pushed a commit to NomiciAI/openclaw that referenced this pull request Mar 8, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
GordonSH-oss pushed a commit to GordonSH-oss/openclaw that referenced this pull request Mar 9, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
jenawant pushed a commit to jenawant/openclaw that referenced this pull request Mar 10, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
dhoman pushed a commit to dhoman/chrono-claw that referenced this pull request Mar 11, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
senw-developers pushed a commit to senw-developers/va-openclaw that referenced this pull request Mar 17, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
V-Gutierrez pushed a commit to V-Gutierrez/openclaw-vendor that referenced this pull request Mar 17, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 22, 2026
* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging

(cherry picked from commit daecd2d)

# Conflicts:
#	CHANGELOG.md
#	src/agents/pi-embedded-runner-extraparams.test.ts
#	src/agents/pi-embedded-runner/extra-params.ts
alexey-pelykh added a commit to remoteclaw/remoteclaw that referenced this pull request Mar 22, 2026
…r live test fixes (#1795)

* Changelog: credit openclaw#39328 to @vincentkoc

(cherry picked from commit 2ec478c)

* Changelog: move openclaw#39328 credit to section end

(cherry picked from commit 5b30c9d)

* Pi Runner: gate parallel_tool_calls to compatible APIs (openclaw#39356)

* Pi Runner: gate parallel_tool_calls payload injection

* Pi Runner: cover parallel_tool_calls alias precedence

* Changelog: note parallel_tool_calls compatibility fix

* Update CHANGELOG.md

* Pi Runner: clarify null parallel_tool_calls override logging

(cherry picked from commit daecd2d)

# Conflicts:
#	CHANGELOG.md
#	src/agents/pi-embedded-runner-extraparams.test.ts
#	src/agents/pi-embedded-runner/extra-params.ts

* docs: add changelog for Telegram DM draft restore (openclaw#39398)

(cherry picked from commit 722c5e5)

* fix: document discord agentComponents schema parity (openclaw#39378) (thanks @gambletan) (openclaw#39378)

Co-authored-by: Shadow <[email protected]>
(cherry picked from commit 9c8e34d)

* fix: land openclaw#39337 by @goodspeed-apps for acpx MCP bootstrap

Co-authored-by: Goodspeed App Studio <[email protected]>
(cherry picked from commit 5659d7f)

# Conflicts:
#	extensions/acpx/openclaw.plugin.json
#	extensions/acpx/src/config.test.ts
#	extensions/acpx/src/config.ts
#	extensions/acpx/src/runtime-internals/test-fixtures.ts
#	extensions/acpx/src/runtime.test.ts
#	extensions/acpx/src/runtime.ts
#	extensions/acpx/src/service.ts

* docs: clean up latest changelog sections

(cherry picked from commit c743fd9)

* fix: land contributor PR openclaw#39516 from @Imhermes1

macOS app/chat/browser/cron/permissions fixes.

Co-authored-by: ImHermes1 <[email protected]>
(cherry picked from commit d15b6af)

# Conflicts:
#	CHANGELOG.md
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeBrowserProxy.swift
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeModeCoordinator.swift
#	apps/macos/Sources/RemoteClaw/NodeMode/MacNodeRuntime.swift
#	apps/macos/Sources/RemoteClaw/PermissionsSettings.swift
#	apps/macos/Tests/RemoteClawIPCTests/MacNodeBrowserProxyTests.swift
#	apps/shared/RemoteClawKit/Sources/RemoteClawChatUI/ChatView.swift
#	apps/shared/RemoteClawKit/Sources/RemoteClawKit/BrowserCommands.swift
#	apps/shared/RemoteClawKit/Tests/RemoteClawKitTests/ChatComposerPasteSupportTests.swift

* fix: stage docker live tests from mounted source

(cherry picked from commit 21df014)

* fix: add minimal process shim for acpx mcp-agent-command

The upstream process.ts depends on gutted runtime-api, so provide a
minimal spawnAndCollect implementation that satisfies the import.

---------

Co-authored-by: Vincent Koc <[email protected]>
Co-authored-by: Ayaan Zaidi <[email protected]>
Co-authored-by: gambletan <[email protected]>
Co-authored-by: Shadow <[email protected]>
Co-authored-by: Peter Steinberger <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

agents Agent runtime and tooling maintainer Maintainer-authored PR size: M

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: [Bug] v2026.3.2 sends parallel_tool_calls to models that don't support it (breaks all tools)

1 participant