Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion includes/class-openclawp-message-adapter.php
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,30 @@ private static function tool_call_part( array $message ) {
return null;
}
$id = (string) ( $meta['tool_call_id'] ?? '' );
$args = is_array( $payload['parameters'] ?? null ) ? $payload['parameters'] : array();
$args = self::function_call_args( $payload['parameters'] ?? array() );

$call = new \WordPress\AiClient\Tools\DTO\FunctionCall( '' !== $id ? $id : null, $name, $args );
return new \WordPress\AiClient\Messages\DTO\MessagePart( $call );
}

/**
* Return provider-safe function-call args for transcript replay.
*
* Anthropic requires `tool_use.input` to be a JSON object. PHP encodes an
* empty array as `[]`, so a no-argument tool call must be carried as an
* empty object when replayed through WP AI Client.
*
* @param mixed $parameters Stored tool parameters.
* @return mixed
*/
private static function function_call_args( $parameters ) {
if ( array() === $parameters ) {
return new \stdClass();
}

return is_array( $parameters ) ? $parameters : array();
}

/**
* Build a `MessagePart` wrapping the `FunctionResponse` for a stored
* `tool_result` transcript message, matched to its call by `tool_call_id`.
Expand Down
28 changes: 25 additions & 3 deletions tests/unit/MessageAdapterTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,27 @@ public function test_to_ai_client_messages_round_trips_tool_mediation_parts(): v
$this->assertSame( array( 'ok' => true ), $response->getResponse() );
}

public function test_to_ai_client_messages_replays_empty_tool_parameters_as_object(): void {
self::install_ai_client_stubs();

$output = OpenclaWP_Message_Adapter::to_ai_client_messages(
array(
array(
'type' => 'tool_call',
'payload' => array(
'tool_name' => 'client/openclawp__current-context',
'parameters' => array(),
),
'metadata' => array( 'tool_call_id' => 'call-empty' ),
),
)
);

$call = $output[0]->getParts()[0]->getContent();
$this->assertInstanceOf( \stdClass::class, $call->getArgs() );
$this->assertSame( '{}', json_encode( $call->getArgs() ) );
}

public function test_last_assistant_text_returns_most_recent_assistant_message(): void {
$messages = array(
array( 'role' => 'user', 'content' => 'q1' ),
Expand Down Expand Up @@ -200,9 +221,10 @@ public function getContent() {
final class FunctionCall {
private ?string $id;
private string $name;
private array $args;
/** @var mixed */
private $args;

public function __construct( ?string $id, string $name, array $args ) {
public function __construct( ?string $id, string $name, $args ) {
$this->id = $id;
$this->name = $name;
$this->args = $args;
Expand All @@ -216,7 +238,7 @@ public function getName(): string {
return $this->name;
}

public function getArgs(): array {
public function getArgs() {
return $this->args;
}
}
Expand Down
Loading