Skip to content

Commit b31fcf2

Browse files
committed
fix: convert null tool args to empty object to prevent GenericFailure
When an LLM returns a ToolUse with null input (valid JSON), the JS callback throws TypeError accessing args.input on null. This was wrapped by napi-rs as GenericFailure. Fix: convert Value::Null args to empty object {} in PreToolUse and PostToolUse hook events, and in GenerateEnd tool_calls. Fixes: A3S-Lab#23 (GenericFailure / TypeError variant)
1 parent a9a8212 commit b31fcf2

1 file changed

Lines changed: 24 additions & 5 deletions

File tree

core/src/agent.rs

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1423,10 +1423,16 @@ impl AgentLoop {
14231423
recent_tools: Vec<String>,
14241424
) -> Option<HookResult> {
14251425
if let Some(he) = &self.config.hook_engine {
1426+
// Convert null args to empty object so JS callbacks don't get null.input errors
1427+
let safe_args = if args.is_null() {
1428+
serde_json::Value::Object(Default::default())
1429+
} else {
1430+
args.clone()
1431+
};
14261432
let event = HookEvent::PreToolUse(PreToolUseEvent {
14271433
session_id: session_id.to_string(),
14281434
tool: tool_name.to_string(),
1429-
args: args.clone(),
1435+
args: safe_args,
14301436
working_directory: self.tool_context.workspace.to_string_lossy().to_string(),
14311437
recent_tools,
14321438
});
@@ -1449,10 +1455,16 @@ impl AgentLoop {
14491455
duration_ms: u64,
14501456
) {
14511457
if let Some(he) = &self.config.hook_engine {
1458+
// Convert null args to empty object so JS callbacks don't get null.input errors
1459+
let safe_args = if args.is_null() {
1460+
serde_json::Value::Object(Default::default())
1461+
} else {
1462+
args.clone()
1463+
};
14521464
let event = HookEvent::PostToolUse(PostToolUseEvent {
14531465
session_id: session_id.to_string(),
14541466
tool: tool_name.to_string(),
1455-
args: args.clone(),
1467+
args: safe_args,
14561468
result: ToolResultData {
14571469
success,
14581470
output: output.to_string(),
@@ -1499,9 +1511,16 @@ impl AgentLoop {
14991511
let tool_calls: Vec<ToolCallInfo> = response
15001512
.tool_calls()
15011513
.iter()
1502-
.map(|tc| ToolCallInfo {
1503-
name: tc.name.clone(),
1504-
args: tc.args.clone(),
1514+
.map(|tc| {
1515+
let args = if tc.args.is_null() {
1516+
serde_json::Value::Object(Default::default())
1517+
} else {
1518+
tc.args.clone()
1519+
};
1520+
ToolCallInfo {
1521+
name: tc.name.clone(),
1522+
args,
1523+
}
15051524
})
15061525
.collect();
15071526

0 commit comments

Comments
 (0)