Skip to content

Commit 08c6600

Browse files
committed
Address PR review feedback
- Remove redundant docblock comments - Use readonly properties instead of readonly class - Rename variable to $event for consistency - Simplify event subscriber method signature
1 parent d9ad1cc commit 08c6600

File tree

12 files changed

+88
-77
lines changed

12 files changed

+88
-77
lines changed

src/agent/CHANGELOG.md

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@ CHANGELOG
44
0.4
55
---
66

7-
* Add human-in-the-loop tool confirmation system with `PolicyInterface`, `ConfirmationHandlerInterface`, and `ConfirmationSubscriber`
7+
* Add human-in-the-loop tool confirmation system
88
* Add `ToolCallRequested` event dispatched before tool execution
9-
* Add `DefaultPolicy` for smart auto-allow of read operations with configurable allow/deny lists
10-
* Add `AlwaysAllowPolicy` for bypassing confirmation checks
119

1210
0.3
1311
---

src/agent/src/Toolbox/Confirmation/AlwaysAllowPolicy.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515

1616
/**
1717
* Policy that always allows tool execution without confirmation.
18-
*
1918
* Use with caution - this bypasses all safety checks.
2019
*
2120
* @author Christopher Hertel <mail@christopher-hertel.de>

src/agent/src/Toolbox/Confirmation/ConfirmationResult.php

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,13 @@
1212
namespace Symfony\AI\Agent\Toolbox\Confirmation;
1313

1414
/**
15-
* Represents the result of a user confirmation request.
16-
*
1715
* @author Christopher Hertel <mail@christopher-hertel.de>
1816
*/
19-
final readonly class ConfirmationResult
17+
final class ConfirmationResult
2018
{
2119
private function __construct(
22-
public bool $confirmed,
23-
public bool $rememberChoice,
20+
public readonly bool $confirmed,
21+
public readonly bool $rememberChoice,
2422
) {
2523
}
2624

src/agent/src/Toolbox/Confirmation/ConfirmationSubscriber.php

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,6 @@
1515
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
1616

1717
/**
18-
* Listens to ToolCallRequested events and applies policy-based confirmation.
19-
*
20-
* This subscriber enables human-in-the-loop patterns by:
21-
* 1. Checking the policy for each tool call
22-
* 2. Asking the user for confirmation when required
23-
* 3. Denying or allowing the tool call based on the result
24-
*
2518
* @author Christopher Hertel <mail@christopher-hertel.de>
2619
*/
2720
final class ConfirmationSubscriber implements EventSubscriberInterface
@@ -35,7 +28,7 @@ public function __construct(
3528
public static function getSubscribedEvents(): array
3629
{
3730
return [
38-
ToolCallRequested::class => ['onToolCallRequested', 0],
31+
ToolCallRequested::class => 'onToolCallRequested',
3932
];
4033
}
4134

src/agent/src/Toolbox/Confirmation/PolicyDecision.php

Lines changed: 0 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -12,24 +12,11 @@
1212
namespace Symfony\AI\Agent\Toolbox\Confirmation;
1313

1414
/**
15-
* Represents the decision made by a policy for a tool call.
16-
*
1715
* @author Christopher Hertel <mail@christopher-hertel.de>
1816
*/
1917
enum PolicyDecision: string
2018
{
21-
/**
22-
* Allow the tool execution without asking the user.
23-
*/
2419
case Allow = 'allow';
25-
26-
/**
27-
* Deny the tool execution without asking the user.
28-
*/
2920
case Deny = 'deny';
30-
31-
/**
32-
* Ask the user for confirmation before executing the tool.
33-
*/
3421
case AskUser = 'ask_user';
3522
}

src/agent/src/Toolbox/Event/ToolCallRequested.php

Lines changed: 0 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,6 @@
1717
use Symfony\AI\Platform\Tool\Tool;
1818

1919
/**
20-
* Dispatched before a tool is executed, allowing listeners to deny or modify the execution.
21-
*
22-
* This event supports human-in-the-loop patterns by allowing:
23-
* - Denying tool execution with a reason
24-
* - Setting a custom result to skip execution
25-
* - Inspecting the tool call before it happens
26-
*
2720
* @author Christopher Hertel <mail@christopher-hertel.de>
2821
*/
2922
final class ToolCallRequested implements StoppableEventInterface

src/agent/src/Toolbox/Toolbox.php

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -79,18 +79,17 @@ public function execute(ToolCall $toolCall): ToolResult
7979
{
8080
$metadata = $this->getMetadata($toolCall);
8181

82-
// Dispatch stoppable event before execution for human-in-the-loop patterns
83-
$requestedEvent = new ToolCallRequested($toolCall, $metadata);
84-
$this->eventDispatcher?->dispatch($requestedEvent);
82+
$event = new ToolCallRequested($toolCall, $metadata);
83+
$this->eventDispatcher?->dispatch($event);
8584

86-
if ($requestedEvent->isDenied()) {
87-
$this->logger->debug(\sprintf('Tool "%s" denied: %s', $toolCall->getName(), $requestedEvent->getDenialReason()));
85+
if ($event->isDenied()) {
86+
$this->logger->debug(\sprintf('Tool "%s" denied: %s', $toolCall->getName(), $event->getDenialReason()));
8887

89-
return new ToolResult($toolCall, $requestedEvent->getDenialReason() ?? 'Tool execution denied.');
88+
return new ToolResult($toolCall, $event->getDenialReason() ?? 'Tool execution denied.');
9089
}
9190

92-
if ($requestedEvent->hasResult()) {
93-
return $requestedEvent->getResult();
91+
if ($event->hasResult()) {
92+
return $event->getResult();
9493
}
9594

9695
$tool = $this->getExecutable($metadata);
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Agent\Tests\Fixtures\Tool;
13+
14+
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
16+
#[AsTool('delete_file', 'Deletes a file')]
17+
final class DeleteFileTool
18+
{
19+
public function __invoke(string $path): string
20+
{
21+
return 'Deleted '.$path;
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Agent\Tests\Fixtures\Tool;
13+
14+
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
16+
#[AsTool('read_file', 'Reads content from a file')]
17+
final class ReadFileTool
18+
{
19+
public function __invoke(string $path): string
20+
{
21+
return 'Content of '.$path;
22+
}
23+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <fabien@symfony.com>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
namespace Symfony\AI\Agent\Tests\Fixtures\Tool;
13+
14+
use Symfony\AI\Agent\Toolbox\Attribute\AsTool;
15+
16+
#[AsTool('write_file', 'Writes content to a file')]
17+
final class WriteFileTool
18+
{
19+
public function __invoke(string $path, string $content): string
20+
{
21+
return 'Written to '.$path;
22+
}
23+
}

0 commit comments

Comments
 (0)