fix: accumulate multiple --allowedTools flags for Agent SDK (#719)

* fix: merge allowedTools from claudeArgs when using Agent SDK

When USE_AGENT_SDK=true, the allowedTools from claudeArgs (which contains
tag mode's required tools like mcp__github_comment__update_claude_comment)
were being lost because parseClaudeArgsToExtraArgs converts args to a
Record<string, string>, and the SDK was using sdkOptions.allowedTools
(from direct options) instead of merging with extraArgs.allowedTools.

This fix:
- Extracts allowedTools/disallowedTools from extraArgs after parsing
- Merges them with any direct options.allowedTools/disallowedTools
- Removes them from extraArgs to prevent duplicate CLI flags
- Passes the merged list as sdkOptions.allowedTools

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

* fix: accumulate multiple --allowedTools flags in claudeArgs

When tag mode adds its --allowedTools (with MCP tools) and the user also
provides --allowedTools in their claude_args, the parseClaudeArgsToExtraArgs
function was only keeping the last value. This caused tag mode's required
tools like mcp__github_comment__update_claude_comment to be lost.

Now allowedTools and disallowedTools flags accumulate their values when
they appear multiple times in claudeArgs, so both tag mode's tools and
user's tools are preserved.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
Ashwin Bhat
2025-12-04 10:25:54 -08:00
committed by GitHub
parent bb4a3f68f7
commit 05c95aed79
2 changed files with 206 additions and 8 deletions

View File

@@ -11,9 +11,13 @@ export type ParsedSdkOptions = {
hasJsonSchema: boolean;
};
// Flags that should accumulate multiple values instead of overwriting
const ACCUMULATING_FLAGS = new Set(["allowedTools", "disallowedTools"]);
/**
* Parse claudeArgs string into extraArgs record for SDK pass-through
* The SDK/CLI will handle --mcp-config, --json-schema, etc.
* For allowedTools and disallowedTools, multiple occurrences are accumulated (comma-joined).
*/
function parseClaudeArgsToExtraArgs(
claudeArgs?: string,
@@ -33,7 +37,12 @@ function parseClaudeArgsToExtraArgs(
// Check if next arg is a value (not another flag)
if (nextArg && !nextArg.startsWith("--")) {
result[flag] = nextArg;
// For accumulating flags, join multiple values with commas
if (ACCUMULATING_FLAGS.has(flag) && result[flag]) {
result[flag] = `${result[flag]},${nextArg}`;
} else {
result[flag] = nextArg;
}
i++; // Skip the value
} else {
result[flag] = null; // Boolean flag
@@ -59,6 +68,33 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
// Detect if --json-schema is present (for hasJsonSchema flag)
const hasJsonSchema = "json-schema" in extraArgs;
// Extract and merge allowedTools from both sources:
// 1. From extraArgs (parsed from claudeArgs - contains tag mode's tools)
// 2. From options.allowedTools (direct input - may be undefined)
// This prevents duplicate flags being overwritten when claudeArgs contains --allowedTools
const extraArgsAllowedTools = extraArgs["allowedTools"]
? extraArgs["allowedTools"].split(",").map((t) => t.trim())
: [];
const directAllowedTools = options.allowedTools
? options.allowedTools.split(",").map((t) => t.trim())
: [];
const mergedAllowedTools = [
...new Set([...extraArgsAllowedTools, ...directAllowedTools]),
];
delete extraArgs["allowedTools"];
// Same for disallowedTools
const extraArgsDisallowedTools = extraArgs["disallowedTools"]
? extraArgs["disallowedTools"].split(",").map((t) => t.trim())
: [];
const directDisallowedTools = options.disallowedTools
? options.disallowedTools.split(",").map((t) => t.trim())
: [];
const mergedDisallowedTools = [
...new Set([...extraArgsDisallowedTools, ...directDisallowedTools]),
];
delete extraArgs["disallowedTools"];
// Build custom environment
const env: Record<string, string | undefined> = { ...process.env };
if (process.env.INPUT_ACTION_INPUTS_PRESENT) {
@@ -77,22 +113,21 @@ export function parseSdkOptions(options: ClaudeOptions): ParsedSdkOptions {
};
}
// Build SDK options - use direct options for explicit inputs, extraArgs for claudeArgs pass-through
// Build SDK options - use merged tools from both direct options and claudeArgs
const sdkOptions: SdkOptions = {
// Direct options from ClaudeOptions inputs
model: options.model,
maxTurns: options.maxTurns ? parseInt(options.maxTurns, 10) : undefined,
allowedTools: options.allowedTools
? options.allowedTools.split(",").map((t) => t.trim())
: undefined,
disallowedTools: options.disallowedTools
? options.disallowedTools.split(",").map((t) => t.trim())
: undefined,
allowedTools:
mergedAllowedTools.length > 0 ? mergedAllowedTools : undefined,
disallowedTools:
mergedDisallowedTools.length > 0 ? mergedDisallowedTools : undefined,
systemPrompt,
fallbackModel: options.fallbackModel,
pathToClaudeCodeExecutable: options.pathToClaudeCodeExecutable,
// Pass through claudeArgs as extraArgs - CLI handles --mcp-config, --json-schema, etc.
// Note: allowedTools and disallowedTools have been removed from extraArgs to prevent duplicates
extraArgs,
env,
};