fix: patch bug in approve plan mode (handle empty toolArgs for tools with no parameters) (#387)
Co-authored-by: Letta <noreply@letta.com>
This commit is contained in:
@@ -56,6 +56,9 @@ const PARALLEL_SAFE_TOOLS = new Set([
|
||||
"BashOutput",
|
||||
// Task spawns independent subagents
|
||||
"Task",
|
||||
// Plan mode tools (no parameters, no file operations)
|
||||
"EnterPlanMode",
|
||||
"ExitPlanMode",
|
||||
]);
|
||||
|
||||
function isParallelSafe(toolName: string): boolean {
|
||||
@@ -194,10 +197,18 @@ async function executeSingleDecision(
|
||||
|
||||
// Execute the approved tool
|
||||
try {
|
||||
const parsedArgs =
|
||||
typeof decision.approval.toolArgs === "string"
|
||||
? JSON.parse(decision.approval.toolArgs)
|
||||
: decision.approval.toolArgs || {};
|
||||
// Safe parse - toolArgs should be "{}" but handle edge cases
|
||||
let parsedArgs: Record<string, unknown> = {};
|
||||
if (typeof decision.approval.toolArgs === "string") {
|
||||
try {
|
||||
parsedArgs = JSON.parse(decision.approval.toolArgs);
|
||||
} catch {
|
||||
// Empty or malformed args - use empty object
|
||||
parsedArgs = {};
|
||||
}
|
||||
} else {
|
||||
parsedArgs = decision.approval.toolArgs || {};
|
||||
}
|
||||
|
||||
const toolResult = await executeTool(
|
||||
decision.approval.toolName,
|
||||
@@ -328,10 +339,18 @@ export async function executeApprovalBatch(
|
||||
parallelIndices.push(i);
|
||||
} else {
|
||||
// Get resource key for write tools
|
||||
const args =
|
||||
typeof decision.approval.toolArgs === "string"
|
||||
? JSON.parse(decision.approval.toolArgs)
|
||||
: decision.approval.toolArgs || {};
|
||||
// Safe parse - handle empty or malformed toolArgs
|
||||
let args: Record<string, unknown> = {};
|
||||
if (typeof decision.approval.toolArgs === "string") {
|
||||
try {
|
||||
args = JSON.parse(decision.approval.toolArgs);
|
||||
} catch {
|
||||
// Empty or malformed args - use empty object (will use global lock)
|
||||
args = {};
|
||||
}
|
||||
} else {
|
||||
args = decision.approval.toolArgs || {};
|
||||
}
|
||||
const resourceKey = getResourceKey(toolName, args);
|
||||
|
||||
const indices = writeToolsByResource.get(resourceKey) || [];
|
||||
|
||||
@@ -215,10 +215,12 @@ export async function drainStream(
|
||||
|
||||
// Include ALL tool_call_ids - don't filter out incomplete entries
|
||||
// Missing name/args will be handled by denial logic in App.tsx
|
||||
// Default empty toolArgs to "{}" - empty string causes JSON.parse("") to fail
|
||||
// This happens for tools with no parameters (e.g., EnterPlanMode, ExitPlanMode)
|
||||
approvals = allPending.map((a) => ({
|
||||
toolCallId: a.toolCallId,
|
||||
toolName: a.toolName || "",
|
||||
toolArgs: a.toolArgs || "",
|
||||
toolArgs: a.toolArgs || "{}",
|
||||
}));
|
||||
|
||||
if (approvals.length === 0) {
|
||||
|
||||
Reference in New Issue
Block a user