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
6 changes: 3 additions & 3 deletions examples/toolbox/weather-event.php
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,9 @@

// Add tool call result listener to enforce chain exits direct with structured response for weather tools
$eventDispatcher->addListener(ToolCallsExecuted::class, function (ToolCallsExecuted $event): void {
foreach ($event->toolResults as $toolCallResult) {
if (str_starts_with($toolCallResult->toolCall->getName(), 'weather_')) {
$event->result = new ObjectResult($toolCallResult->result);
foreach ($event->getToolResults() as $toolCallResult) {
if (str_starts_with($toolCallResult->getToolCall()->getName(), 'weather_')) {
$event->setResult(new ObjectResult($toolCallResult->getResult()));
}
}
});
Expand Down
8 changes: 7 additions & 1 deletion src/agent/src/Memory/Memory.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,13 @@
*/
final readonly class Memory
{
public function __construct(public string $content)
public function __construct(
private string $content,
) {
}

public function getContent(): string
{
return $this->content;
}
}
2 changes: 1 addition & 1 deletion src/agent/src/Memory/MemoryInputProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ public function processInput(Input $input): void
$memory .= \PHP_EOL.\PHP_EOL;
$memory .= implode(
\PHP_EOL,
array_map(static fn (Memory $memory): string => $memory->content, $memoryMessages),
array_map(static fn (Memory $memory): string => $memory->getContent(), $memoryMessages),
);
}

Expand Down
14 changes: 12 additions & 2 deletions src/agent/src/MultiAgent/Handoff/Decision.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@
* @param string $reasoning The reasoning behind the selection
*/
public function __construct(
public string $agentName,
public string $reasoning = 'No reasoning provided',
private string $agentName,
private string $reasoning = 'No reasoning provided',
) {
}

Expand All @@ -35,4 +35,14 @@ public function hasAgent(): bool
{
return '' !== $this->agentName;
}

public function getAgentName(): string
{
return $this->agentName;
}

public function getReasoning(): string
{
return $this->reasoning;
}
}
10 changes: 5 additions & 5 deletions src/agent/src/MultiAgent/MultiAgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,8 @@ public function call(MessageBag $messages, array $options = []): ResultInterface
}

$this->logger->debug('MultiAgent: Agent selection completed', [
'selected_agent' => $decision->agentName,
'reasoning' => $decision->reasoning,
'selected_agent' => $decision->getAgentName(),
'reasoning' => $decision->getReasoning(),
]);

if (!$decision->hasAgent()) {
Expand All @@ -104,22 +104,22 @@ public function call(MessageBag $messages, array $options = []): ResultInterface
// Find the target agent by name
$targetAgent = null;
foreach ($this->handoffs as $handoff) {
if ($handoff->getTo()->getName() === $decision->agentName) {
if ($handoff->getTo()->getName() === $decision->getAgentName()) {
$targetAgent = $handoff->getTo();
break;
}
}

if (!$targetAgent) {
$this->logger->debug('MultiAgent: Target agent not found, using fallback agent', [
'requested_agent' => $decision->agentName,
'requested_agent' => $decision->getAgentName(),
'reason' => 'agent_not_found',
]);

return $this->fallback->call($messages, $options);
}

$this->logger->debug('MultiAgent: Delegating to agent', ['agent_name' => $decision->agentName]);
$this->logger->debug('MultiAgent: Delegating to agent', ['agent_name' => $decision->getAgentName()]);

// Call the selected agent with the original user question
return $targetAgent->call(new MessageBag($userMessage), $options);
Expand Down
2 changes: 1 addition & 1 deletion src/agent/src/Toolbox/AgentProcessor.php
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ private function handleToolCallsCallback(Output $output): \Closure
$event = new ToolCallsExecuted(...$results);
$this->eventDispatcher?->dispatch($event);

$result = $event->hasResponse() ? $event->result : $this->agent->call($messages, $output->getOptions());
$result = $event->hasResponse() ? $event->getResult() : $this->agent->call($messages, $output->getOptions());
} while ($result instanceof ToolCallResult);

return $result;
Expand Down
24 changes: 21 additions & 3 deletions src/agent/src/Toolbox/Event/ToolCallArgumentsResolved.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,27 @@
* @param array<string, mixed> $arguments
*/
public function __construct(
public object $tool,
public Tool $metadata,
public array $arguments,
private object $tool,
private Tool $metadata,
private array $arguments,
) {
}

public function getTool(): object
{
return $this->tool;
}

public function getMetadata(): Tool
{
return $this->metadata;
}

/**
* @return array<string, mixed>
*/
public function getArguments(): array
{
return $this->arguments;
}
}
31 changes: 27 additions & 4 deletions src/agent/src/Toolbox/Event/ToolCallFailed.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,33 @@
* @param array<string, mixed> $arguments
*/
public function __construct(
public object $tool,
public Tool $metadata,
public array $arguments,
public \Throwable $exception,
private object $tool,
private Tool $metadata,
private array $arguments,
private \Throwable $exception,
) {
}

public function getTool(): object
{
return $this->tool;
}

public function getMetadata(): Tool
{
return $this->metadata;
}

/**
* @return array<string, mixed>
*/
public function getArguments(): array
{
return $this->arguments;
}

public function getException(): \Throwable
{
return $this->exception;
}
}
31 changes: 27 additions & 4 deletions src/agent/src/Toolbox/Event/ToolCallSucceeded.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,33 @@
* @param array<string, mixed> $arguments
*/
public function __construct(
public object $tool,
public Tool $metadata,
public array $arguments,
public mixed $result,
private object $tool,
private Tool $metadata,
private array $arguments,
private mixed $result,
) {
}

public function getTool(): object
{
return $this->tool;
}

public function getMetadata(): Tool
{
return $this->metadata;
}

/**
* @return array<string, mixed>
*/
public function getArguments(): array
{
return $this->arguments;
}

public function getResult(): mixed
{
return $this->result;
}
}
22 changes: 20 additions & 2 deletions src/agent/src/Toolbox/Event/ToolCallsExecuted.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ final class ToolCallsExecuted
/**
* @var ToolResult[]
*/
public readonly array $toolResults;
public ResultInterface $result;
private readonly array $toolResults;
private ResultInterface $result;

public function __construct(ToolResult ...$toolResults)
{
Expand All @@ -34,4 +34,22 @@ public function hasResponse(): bool
{
return isset($this->result);
}

public function setResult(ResultInterface $result): void
{
$this->result = $result;
}

public function getResult(): ResultInterface
{
return $this->result;
}

/**
* @return ToolResult[]
*/
public function getToolResults(): array
{
return $this->toolResults;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
*/
final class ToolExecutionException extends \RuntimeException implements ToolExecutionExceptionInterface
{
public ?ToolCall $toolCall = null;
private ?ToolCall $toolCall = null;

public static function executionFailed(ToolCall $toolCall, \Throwable $previous): self
{
Expand All @@ -28,6 +28,11 @@ public static function executionFailed(ToolCall $toolCall, \Throwable $previous)
return $exception;
}

public function getToolCall(): ?ToolCall
{
return $this->toolCall;
}

public function getToolCallResult(): string
{
return \sprintf('An error occurred while executing tool "%s".', $this->toolCall->getName());
Expand Down
7 changes: 6 additions & 1 deletion src/agent/src/Toolbox/Exception/ToolNotFoundException.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
*/
final class ToolNotFoundException extends \RuntimeException implements ExceptionInterface
{
public ?ToolCall $toolCall = null;
private ?ToolCall $toolCall = null;

public static function notFoundForToolCall(ToolCall $toolCall): self
{
Expand All @@ -33,4 +33,9 @@ public static function notFoundForReference(ExecutionReference $reference): self
{
return new self(\sprintf('Tool not found for reference: %s::%s.', $reference->getClass(), $reference->getMethod()));
}

public function getToolCall(): ?ToolCall
{
return $this->toolCall;
}
}
14 changes: 12 additions & 2 deletions src/agent/src/Toolbox/ToolResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,18 @@
final readonly class ToolResult
{
public function __construct(
public ToolCall $toolCall,
public mixed $result,
private ToolCall $toolCall,
private mixed $result,
) {
}

public function getToolCall(): ToolCall
{
return $this->toolCall;
}

public function getResult(): mixed
{
return $this->result;
}
}
2 changes: 1 addition & 1 deletion src/agent/tests/Memory/EmbeddingProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ public function testItIsCreatingMemoryWithFoundVectors()

{"fact":"The sky is blue"}{"fact":"Water is wet"}
MARKDOWN,
$memory[0]->content,
$memory[0]->getContent(),
);
}
}
2 changes: 1 addition & 1 deletion src/agent/tests/Memory/StaticMemoryProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ public function testItDeliversFormattedFacts()
$this->assertCount(1, $memory);
$this->assertInstanceOf(Memory::class, $memory[0]);
$expectedContent = "## Static Memory\n\n- {$fact1}\n- {$fact2}";
$this->assertSame($expectedContent, $memory[0]->content);
$this->assertSame($expectedContent, $memory[0]->getContent());
}
}
16 changes: 8 additions & 8 deletions src/agent/tests/MultiAgent/Handoff/DecisionTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,35 +23,35 @@ public function testConstructorWithAgentName()
{
$decision = new Decision('technical', 'This is a technical question');

$this->assertSame('technical', $decision->agentName);
$this->assertSame('This is a technical question', $decision->reasoning);
$this->assertSame('technical', $decision->getAgentName());
$this->assertSame('This is a technical question', $decision->getReasoning());
$this->assertTrue($decision->hasAgent());
}

public function testConstructorWithEmptyAgentName()
{
$decision = new Decision('', 'No specific agent needed');

$this->assertSame('', $decision->agentName);
$this->assertSame('No specific agent needed', $decision->reasoning);
$this->assertSame('', $decision->getAgentName());
$this->assertSame('No specific agent needed', $decision->getReasoning());
$this->assertFalse($decision->hasAgent());
}

public function testConstructorWithDefaultReasoning()
{
$decision = new Decision('general');

$this->assertSame('general', $decision->agentName);
$this->assertSame('No reasoning provided', $decision->reasoning);
$this->assertSame('general', $decision->getAgentName());
$this->assertSame('No reasoning provided', $decision->getReasoning());
$this->assertTrue($decision->hasAgent());
}

public function testConstructorWithEmptyAgentAndDefaultReasoning()
{
$decision = new Decision('');

$this->assertSame('', $decision->agentName);
$this->assertSame('No reasoning provided', $decision->reasoning);
$this->assertSame('', $decision->getAgentName());
$this->assertSame('No reasoning provided', $decision->getReasoning());
$this->assertFalse($decision->hasAgent());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,17 +35,17 @@ public function __construct(

public function __invoke(ToolCallArgumentsResolved $event): void
{
$tool = $event->tool;
$tool = $event->getTool();
$class = new \ReflectionClass($tool);
$method = $class->getMethod($event->metadata->getReference()->getMethod());
$method = $class->getMethod($event->getMetadata()->getReference()->getMethod());
$classAttributes = $class->getAttributes(IsGrantedTool::class);
$methodAttributes = $method->getAttributes(IsGrantedTool::class);

if (!$classAttributes && !$methodAttributes) {
return;
}

$arguments = $event->arguments;
$arguments = $event->getArguments();

foreach (array_merge($classAttributes, $methodAttributes) as $attr) {
/** @var IsGrantedTool $attribute */
Expand Down