Skip to content

Commit d68ee81

Browse files
author
Dariusz Debowczyk
committed
refactor: simplify agent driver tool runtime contract
1 parent 924d539 commit d68ee81

File tree

11 files changed

+163
-63
lines changed

11 files changed

+163
-63
lines changed

packages/agents/src/AgentLoop.php

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
use Cognesy\Agents\Continuation\StopReason;
99
use Cognesy\Agents\Continuation\StopSignal;
1010
use Cognesy\Agents\Data\AgentState;
11+
use Cognesy\Agents\Drivers\CanAcceptToolRuntime;
1112
use Cognesy\Agents\Drivers\CanUseTools;
1213
use Cognesy\Agents\Enums\ExecutionStatus;
1314
use Cognesy\Agents\Drivers\ToolCalling\ToolCallingDriver;
@@ -92,13 +93,14 @@ public function execute(AgentState $state): AgentState {
9293

9394
#[\Override]
9495
public function iterate(AgentState $state): iterable {
96+
$driver = $this->bindToolRuntime($this->driver);
9597
$state = $this->onBeforeExecution($state);
9698
while (true) {
9799
$stepStarted = false;
98100
try {
99101
$state = $this->onBeforeStep($state);
100102
$stepStarted = true;
101-
$state = $this->handleToolUse($state);
103+
$state = $this->handleToolUse($state, $driver);
102104
} catch (AgentStopException $stop) {
103105
$state = $this->handleStopException($state, $stop);
104106
} catch (Throwable $error) {
@@ -170,9 +172,9 @@ protected function onError(AgentState $state, Throwable $error): AgentState {
170172

171173
// INTERNAL ///////////////////////////////////////////
172174

173-
private function handleToolUse(AgentState $state) : AgentState {
175+
private function handleToolUse(AgentState $state, CanUseTools $driver) : AgentState {
174176
try {
175-
$state = $this->useTools($state);
177+
$state = $this->useTools($state, $driver);
176178
} catch (ToolExecutionBlockedException $block) {
177179
$state = $this->handleToolBlockException($state, $block);
178180
}
@@ -206,15 +208,21 @@ protected function shouldStop(AgentState $state): bool {
206208
return $shouldStop;
207209
}
208210

209-
private function useTools(AgentState $state): AgentState {
210-
$state = $this->driver->useTools(
211-
state: $state,
212-
tools: $this->tools,
213-
executor: $this->toolExecutor
214-
);
211+
private function useTools(AgentState $state, CanUseTools $driver): AgentState {
212+
$state = $driver->useTools(state: $state);
215213
return $state;
216214
}
217215

216+
private function bindToolRuntime(CanUseTools $driver): CanUseTools {
217+
return match (true) {
218+
$driver instanceof CanAcceptToolRuntime => $driver->withToolRuntime(
219+
tools: $this->tools,
220+
executor: $this->toolExecutor,
221+
),
222+
default => $driver,
223+
};
224+
}
225+
218226
// EVENT DELEGATION ///////////////////////////////////
219227

220228
public function wiretap(callable $listener): self {

packages/agents/src/Builder/AgentConfigurator.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Cognesy\Agents\Context\CanAcceptMessageCompiler;
1111
use Cognesy\Agents\Context\CanCompileMessages;
1212
use Cognesy\Agents\Context\Compilers\ConversationWithCurrentToolTrace;
13+
use Cognesy\Agents\Drivers\CanAcceptToolRuntime;
1314
use Cognesy\Agents\Drivers\CanUseTools;
1415
use Cognesy\Agents\Drivers\ToolCalling\ToolCallingDriver;
1516
use Cognesy\Agents\Hook\Collections\RegisteredHooks;
@@ -62,7 +63,7 @@ public function install(CanProvideAgentCapability $capability): self {
6263
}
6364

6465
public function toAgentLoop(): AgentLoop {
65-
$driver = $this->resolveDriver();
66+
$driver = $this->normalizeDriver($this->toolUseDriver, $this->contextCompiler);
6667
$tools = $this->resolveTools($driver);
6768
$interceptor = $this->resolveInterceptor();
6869

@@ -72,6 +73,7 @@ public function toAgentLoop(): AgentLoop {
7273
interceptor: $interceptor,
7374
throwOnToolFailure: false,
7475
);
76+
$driver = $this->bindToolRuntime($driver, $tools, $executor);
7577

7678
return new AgentLoop(
7779
tools: $tools,
@@ -169,17 +171,24 @@ private function with(
169171
);
170172
}
171173

172-
private function resolveDriver(): CanUseTools {
173-
return $this->normalizeDriver($this->toolUseDriver, $this->contextCompiler);
174-
}
175-
176174
private function normalizeDriver(CanUseTools $driver, CanCompileMessages $compiler): CanUseTools {
177175
return match (true) {
178176
$driver instanceof CanAcceptMessageCompiler => $driver->withMessageCompiler($compiler),
179177
default => $driver,
180178
};
181179
}
182180

181+
private function bindToolRuntime(
182+
CanUseTools $driver,
183+
Tools $tools,
184+
ToolExecutor $executor,
185+
) : CanUseTools {
186+
return match (true) {
187+
$driver instanceof CanAcceptToolRuntime => $driver->withToolRuntime($tools, $executor),
188+
default => $driver,
189+
};
190+
}
191+
183192
private function resolveTools(CanUseTools $driver): Tools {
184193
return $this->deferredTools->resolve($this->tools, $driver, $this->events);
185194
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
<?php declare(strict_types=1);
2+
3+
namespace Cognesy\Agents\Drivers;
4+
5+
use Cognesy\Agents\Collections\Tools;
6+
use Cognesy\Agents\Tool\Contracts\CanExecuteToolCalls;
7+
8+
interface CanAcceptToolRuntime
9+
{
10+
public function withToolRuntime(Tools $tools, CanExecuteToolCalls $executor): static;
11+
}

packages/agents/src/Drivers/CanUseTools.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,9 @@
22

33
namespace Cognesy\Agents\Drivers;
44

5-
use Cognesy\Agents\Collections\Tools;
65
use Cognesy\Agents\Data\AgentState;
7-
use Cognesy\Agents\Tool\Contracts\CanExecuteToolCalls;
86

97
interface CanUseTools
108
{
11-
public function useTools(AgentState $state, Tools $tools, CanExecuteToolCalls $executor): AgentState;
9+
public function useTools(AgentState $state): AgentState;
1210
}

packages/agents/src/Drivers/ReAct/ReActDriver.php

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Cognesy\Agents\Data\AgentState;
1111
use Cognesy\Agents\Data\AgentStep;
1212
use Cognesy\Agents\Data\ToolExecution;
13+
use Cognesy\Agents\Drivers\CanAcceptToolRuntime;
1314
use Cognesy\Agents\Drivers\CanUseTools;
1415
use Cognesy\Agents\Drivers\ReAct\Actions\MakeReActPrompt;
1516
use Cognesy\Agents\Drivers\ReAct\Actions\MakeToolCalls;
@@ -22,6 +23,8 @@
2223
use Cognesy\Agents\Events\InferenceResponseReceived;
2324
use Cognesy\Agents\Events\ValidationFailed;
2425
use Cognesy\Agents\Exceptions\AgentException;
26+
use Cognesy\Agents\Interception\PassThroughInterceptor;
27+
use Cognesy\Agents\Tool\ToolExecutor;
2528
use Cognesy\Agents\Tool\Contracts\CanExecuteToolCalls;
2629
use Cognesy\Events\Contracts\CanHandleEvents;
2730
use Cognesy\Events\EventBusResolver;
@@ -51,7 +54,7 @@
5154
use Cognesy\Utils\Result\Result;
5255
use DateTimeImmutable;
5356

54-
final class ReActDriver implements CanUseTools, CanAcceptLLMConfig, CanAcceptMessageCompiler
57+
final class ReActDriver implements CanUseTools, CanAcceptToolRuntime, CanAcceptLLMConfig, CanAcceptMessageCompiler
5558
{
5659
private LLMProvider $llm;
5760
private ?HttpClient $httpClient = null;
@@ -66,6 +69,8 @@ final class ReActDriver implements CanUseTools, CanAcceptLLMConfig, CanAcceptMes
6669
private CanHandleEvents $events;
6770
private CanCreateInference $inference;
6871
private CanCreateStructuredOutput $structuredOutput;
72+
private Tools $tools;
73+
private CanExecuteToolCalls $executor;
6974

7075
public function __construct(
7176
CanCreateInference $inference,
@@ -81,6 +86,8 @@ public function __construct(
8186
OutputMode $mode = OutputMode::Json,
8287
?CanCompileMessages $messageCompiler = null,
8388
?CanHandleEvents $events = null,
89+
?Tools $tools = null,
90+
?CanExecuteToolCalls $executor = null,
8491
) {
8592
$this->inference = $inference;
8693
$this->structuredOutput = $structuredOutput;
@@ -95,13 +102,19 @@ public function __construct(
95102
$this->mode = $mode;
96103
$this->messageCompiler = $messageCompiler ?? new ConversationWithCurrentToolTrace();
97104
$this->events = EventBusResolver::using($events);
105+
$this->tools = $tools ?? new Tools();
106+
$this->executor = $executor ?? new ToolExecutor(
107+
tools: $this->tools,
108+
events: $this->events,
109+
interceptor: new PassThroughInterceptor(),
110+
);
98111
}
99112

100113
#[\Override]
101-
public function useTools(AgentState $state, Tools $tools, CanExecuteToolCalls $executor): AgentState {
114+
public function useTools(AgentState $state): AgentState {
102115
$state = $this->ensureStateLLMConfig($state);
103116
$messages = $this->messageCompiler->compile($state);
104-
$system = $this->buildSystemPrompt($tools);
117+
$system = $this->buildSystemPrompt($this->tools);
105118
$cachedContext = $this->structuredCachedContext($state);
106119

107120
$requestStartedAt = new DateTimeImmutable();
@@ -131,7 +144,7 @@ public function useTools(AgentState $state, Tools $tools, CanExecuteToolCalls $e
131144
$this->emitInferenceResponseReceived($state, $inferenceResponse, $requestStartedAt);
132145

133146
$validator = new ReActValidator();
134-
$validation = $validator->validateBasicDecision($decision, $tools->names());
147+
$validation = $validator->validateBasicDecision($decision, $this->tools->names());
135148
if ($validation->isInvalid()) {
136149
$this->emitValidationFailed(
137150
state: $state,
@@ -142,7 +155,7 @@ public function useTools(AgentState $state, Tools $tools, CanExecuteToolCalls $e
142155
return $state->withCurrentStep($step)->withFailure(new AgentException($validation->getErrorMessage()));
143156
}
144157

145-
$toolCalls = (new MakeToolCalls($tools, $validator))($decision);
158+
$toolCalls = (new MakeToolCalls($this->tools, $validator))($decision);
146159

147160
$usage = $inferenceResponse->usage();
148161

@@ -157,7 +170,7 @@ public function useTools(AgentState $state, Tools $tools, CanExecuteToolCalls $e
157170
return $state->withCurrentStep($step);
158171
}
159172

160-
$executions = $executor->executeTools($toolCalls, $state);
173+
$executions = $this->executor->executeTools($toolCalls, $state);
161174

162175
$outputMessages = $this->makeFollowUps($decision, $executions);
163176
$responseWithCalls = $this->withToolCalls($inferenceResponse, $toolCalls);
@@ -209,6 +222,11 @@ public function withMessageCompiler(CanCompileMessages $compiler): static {
209222
return $this->with(messageCompiler: $compiler);
210223
}
211224

225+
#[\Override]
226+
public function withToolRuntime(Tools $tools, CanExecuteToolCalls $executor): static {
227+
return $this->with(tools: $tools, executor: $executor);
228+
}
229+
212230
// INTERNAL ////////////////////////////////////////////////////////////////
213231

214232
private function with(
@@ -224,6 +242,8 @@ private function with(
224242
?CanCompileMessages $messageCompiler = null,
225243
?CanCreateInference $inference = null,
226244
?CanCreateStructuredOutput $structuredOutput = null,
245+
?Tools $tools = null,
246+
?CanExecuteToolCalls $executor = null,
227247
): self {
228248
return new self(
229249
inference: $inference ?? $this->inference,
@@ -239,6 +259,8 @@ private function with(
239259
mode: $mode ?? $this->mode,
240260
messageCompiler: $messageCompiler ?? $this->messageCompiler,
241261
events: $this->events,
262+
tools: $tools ?? $this->tools,
263+
executor: $executor ?? $this->executor,
242264
);
243265
}
244266

0 commit comments

Comments
 (0)