StructuredContent call tool result, added ability to return error from tool (#93)
This commit is contained in:
parent
6100ffcf3f
commit
d347c84472
3 changed files with 74 additions and 5 deletions
|
|
@ -38,12 +38,14 @@ class CallToolResult implements ResultInterface
|
||||||
/**
|
/**
|
||||||
* Create a new CallToolResult.
|
* Create a new CallToolResult.
|
||||||
*
|
*
|
||||||
* @param Content[] $content The content of the tool result
|
* @param Content[] $content The content of the tool result
|
||||||
* @param bool $isError Whether the tool execution resulted in an error. If not set, this is assumed to be false (the call was successful).
|
* @param bool $isError Whether the tool execution resulted in an error. If not set, this is assumed to be false (the call was successful).
|
||||||
|
* @param mixed[] $structuredContent JSON content for `structuredContent`
|
||||||
*/
|
*/
|
||||||
public function __construct(
|
public function __construct(
|
||||||
public readonly array $content,
|
public readonly array $content,
|
||||||
public readonly bool $isError = false,
|
public readonly bool $isError = false,
|
||||||
|
public readonly ?array $structuredContent = null,
|
||||||
) {
|
) {
|
||||||
foreach ($this->content as $item) {
|
foreach ($this->content as $item) {
|
||||||
if (!$item instanceof Content) {
|
if (!$item instanceof Content) {
|
||||||
|
|
@ -107,9 +109,15 @@ class CallToolResult implements ResultInterface
|
||||||
*/
|
*/
|
||||||
public function jsonSerialize(): array
|
public function jsonSerialize(): array
|
||||||
{
|
{
|
||||||
return [
|
$result = [
|
||||||
'content' => $this->content,
|
'content' => $this->content,
|
||||||
'isError' => $this->isError,
|
'isError' => $this->isError,
|
||||||
];
|
];
|
||||||
|
|
||||||
|
if ($this->structuredContent) {
|
||||||
|
$result['structuredContent'] = $this->structuredContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -59,14 +59,17 @@ final class CallToolHandler implements RequestHandlerInterface
|
||||||
}
|
}
|
||||||
|
|
||||||
$result = $this->referenceHandler->handle($reference, $arguments);
|
$result = $this->referenceHandler->handle($reference, $arguments);
|
||||||
$formatted = $reference->formatResult($result);
|
|
||||||
|
if (!$result instanceof CallToolResult) {
|
||||||
|
$result = new CallToolResult($reference->formatResult($result));
|
||||||
|
}
|
||||||
|
|
||||||
$this->logger->debug('Tool executed successfully', [
|
$this->logger->debug('Tool executed successfully', [
|
||||||
'name' => $toolName,
|
'name' => $toolName,
|
||||||
'result_type' => \gettype($result),
|
'result_type' => \gettype($result),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
return new Response($request->getId(), new CallToolResult($formatted));
|
return new Response($request->getId(), $result);
|
||||||
} catch (ToolNotFoundException $e) {
|
} catch (ToolNotFoundException $e) {
|
||||||
$this->logger->error('Tool not found', ['name' => $toolName]);
|
$this->logger->error('Tool not found', ['name' => $toolName]);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -342,6 +342,64 @@ class CallToolHandlerTest extends TestCase
|
||||||
$this->assertEquals($expectedResult, $response->result);
|
$this->assertEquals($expectedResult, $response->result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function testHandleReturnsStructuredContentResult(): void
|
||||||
|
{
|
||||||
|
$request = $this->createCallToolRequest('structured_tool', ['query' => 'php']);
|
||||||
|
$toolReference = $this->createMock(ToolReference::class);
|
||||||
|
$structuredResult = new CallToolResult([new TextContent('Rendered results')], false, ['result' => 'Rendered results']);
|
||||||
|
|
||||||
|
$this->referenceProvider
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getTool')
|
||||||
|
->with('structured_tool')
|
||||||
|
->willReturn($toolReference);
|
||||||
|
|
||||||
|
$this->referenceHandler
|
||||||
|
->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->with($toolReference, ['query' => 'php'])
|
||||||
|
->willReturn($structuredResult);
|
||||||
|
|
||||||
|
$toolReference
|
||||||
|
->expects($this->never())
|
||||||
|
->method('formatResult');
|
||||||
|
|
||||||
|
$response = $this->handler->handle($request, $this->session);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Response::class, $response);
|
||||||
|
$this->assertSame($structuredResult, $response->result);
|
||||||
|
$this->assertEquals(['result' => 'Rendered results'], $response->result->jsonSerialize()['structuredContent'] ?? []);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function testHandleReturnsCallToolResult(): void
|
||||||
|
{
|
||||||
|
$request = $this->createCallToolRequest('result_tool', ['query' => 'php']);
|
||||||
|
$toolReference = $this->createMock(ToolReference::class);
|
||||||
|
$callToolResult = new CallToolResult([new TextContent('Error result')], true);
|
||||||
|
|
||||||
|
$this->referenceProvider
|
||||||
|
->expects($this->once())
|
||||||
|
->method('getTool')
|
||||||
|
->with('result_tool')
|
||||||
|
->willReturn($toolReference);
|
||||||
|
|
||||||
|
$this->referenceHandler
|
||||||
|
->expects($this->once())
|
||||||
|
->method('handle')
|
||||||
|
->with($toolReference, ['query' => 'php'])
|
||||||
|
->willReturn($callToolResult);
|
||||||
|
|
||||||
|
$toolReference
|
||||||
|
->expects($this->never())
|
||||||
|
->method('formatResult');
|
||||||
|
|
||||||
|
$response = $this->handler->handle($request, $this->session);
|
||||||
|
|
||||||
|
$this->assertInstanceOf(Response::class, $response);
|
||||||
|
$this->assertSame($callToolResult, $response->result);
|
||||||
|
$this->assertArrayNotHasKey('structuredContent', $response->result->jsonSerialize());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array<string, mixed> $arguments
|
* @param array<string, mixed> $arguments
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue