Skip to content

Commit cec91e0

Browse files
committed
Agent docs + cont cleanup
1 parent d83ef89 commit cec91e0

File tree

169 files changed

+5512
-951
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

169 files changed

+5512
-951
lines changed

docs-build/packages/addons/agent_hooks.mdx

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ $agent = AgentBuilder::new()
4444
})
4545

4646
->build();
47-
// @doctest id="d533"
47+
// @doctest id="0b6a"
4848
```
4949

5050
## Lifecycle Events
@@ -104,7 +104,7 @@ HookOutcome::block('Dangerous command detected');
104104

105105
// Stop the entire agent execution
106106
HookOutcome::stop('Budget exceeded');
107-
// @doctest id="5fcb"
107+
// @doctest id="c30c"
108108
```
109109

110110
### Semantic Differences
@@ -146,7 +146,7 @@ function afterTool(ToolHookContext $ctx): HookOutcome {
146146

147147
return HookOutcome::proceed();
148148
}
149-
// @doctest id="3350"
149+
// @doctest id="c2c9"
150150
```
151151

152152
### StepHookContext
@@ -167,7 +167,7 @@ function onStep(StepHookContext $ctx): HookOutcome {
167167

168168
return HookOutcome::proceed();
169169
}
170-
// @doctest id="5436"
170+
// @doctest id="a05b"
171171
```
172172

173173
### StopHookContext
@@ -187,7 +187,7 @@ function onStop(StopHookContext $ctx): HookOutcome {
187187

188188
return HookOutcome::proceed(); // Allow stop
189189
}
190-
// @doctest id="9ed0"
190+
// @doctest id="4b98"
191191
```
192192

193193
### ExecutionHookContext
@@ -206,7 +206,7 @@ function onExecution(ExecutionHookContext $ctx): HookOutcome {
206206

207207
return HookOutcome::proceed();
208208
}
209-
// @doctest id="b895"
209+
// @doctest id="b2ba"
210210
```
211211

212212
### FailureHookContext
@@ -223,7 +223,7 @@ function onFailure(FailureHookContext $ctx): HookOutcome {
223223

224224
return HookOutcome::proceed();
225225
}
226-
// @doctest id="4fb2"
226+
// @doctest id="d10a"
227227
```
228228

229229
## Matchers
@@ -247,7 +247,7 @@ new ToolNameMatcher('*'); // Match all
247247

248248
// Regex patterns
249249
new ToolNameMatcher('/^(read|write)_.+$/');
250-
// @doctest id="b8d2"
250+
// @doctest id="551f"
251251
```
252252

253253
### EventTypeMatcher
@@ -263,7 +263,7 @@ new EventTypeMatcher(HookEvent::PreToolUse);
263263

264264
// Multiple events
265265
new EventTypeMatcher(HookEvent::BeforeStep, HookEvent::AfterStep);
266-
// @doctest id="cdc1"
266+
// @doctest id="e7d1"
267267
```
268268

269269
### CompositeMatcher
@@ -294,7 +294,7 @@ $matcher = CompositeMatcher::and(
294294
),
295295
new CallableMatcher(fn($ctx) => $ctx->state()->metadata()->get('safe_mode')),
296296
);
297-
// @doctest id="1cbe"
297+
// @doctest id="3fa0"
298298
```
299299

300300
### CallableMatcher
@@ -307,7 +307,7 @@ use Cognesy\Addons\Agent\Hooks\Matchers\CallableMatcher;
307307
$matcher = new CallableMatcher(function (HookContext $ctx): bool {
308308
return $ctx->state()->metadata()->get('priority') === 'high';
309309
});
310-
// @doctest id="206c"
310+
// @doctest id="11ff"
311311
```
312312

313313
## Priority
@@ -324,7 +324,7 @@ $builder
324324

325325
// Logging hooks run last (low priority)
326326
->onAfterToolUse($logger, priority: -100);
327-
// @doctest id="8d5b"
327+
// @doctest id="cc4f"
328328
```
329329

330330
**Priority Guidelines:**
@@ -352,7 +352,7 @@ $builder->onAfterToolUse(
352352
priority: int = 0,
353353
matcher: string|HookMatcher|null = null,
354354
);
355-
// @doctest id="cf6b"
355+
// @doctest id="1890"
356356
```
357357

358358
### Step Hooks
@@ -367,7 +367,7 @@ $builder->onBeforeStep(
367367
$builder->onAfterStep(
368368
callback: callable, // (AgentState) -> AgentState
369369
);
370-
// @doctest id="1c3a"
370+
// @doctest id="1cde"
371371
```
372372

373373
### Execution Hooks
@@ -384,7 +384,7 @@ $builder->onExecutionEnd(
384384
callback: callable, // (ExecutionHookContext) -> HookOutcome|void
385385
priority: int = 0,
386386
);
387-
// @doctest id="764c"
387+
// @doctest id="03ea"
388388
```
389389

390390
### Continuation Hooks
@@ -401,7 +401,7 @@ $builder->onSubagentStop(
401401
callback: callable, // (StopHookContext) -> HookOutcome|void
402402
priority: int = 0,
403403
);
404-
// @doctest id="bc96"
404+
// @doctest id="e288"
405405
```
406406

407407
### Error Hooks
@@ -412,7 +412,7 @@ $builder->onAgentFailed(
412412
callback: callable, // (FailureHookContext) -> HookOutcome|void
413413
priority: int = 0,
414414
);
415-
// @doctest id="2105"
415+
// @doctest id="8753"
416416
```
417417

418418
### Unified Registration
@@ -428,7 +428,7 @@ $builder->addHook(
428428
hook: new CallableHook($callback, $matcher),
429429
priority: 100,
430430
);
431-
// @doctest id="a2f3"
431+
// @doctest id="f4ae"
432432
```
433433

434434
## Creating Custom Hooks
@@ -457,7 +457,7 @@ class RateLimitHook implements Hook
457457
return $next($context);
458458
}
459459
}
460-
// @doctest id="c4e8"
460+
// @doctest id="b8bf"
461461
```
462462

463463
## Using HookStack Directly
@@ -482,7 +482,7 @@ if ($outcome->isBlocked()) {
482482
} elseif ($outcome->isStopped()) {
483483
// Handle stopped
484484
}
485-
// @doctest id="d55e"
485+
// @doctest id="0117"
486486
```
487487

488488
## Backward Compatibility
@@ -498,7 +498,7 @@ use Cognesy\Addons\Agent\Hooks\Adapters\StateProcessorAdapter;
498498

499499
$processor = new YourStateProcessor();
500500
$hook = new StateProcessorAdapter($processor, position: 'after');
501-
// @doctest id="7fc3"
501+
// @doctest id="cc72"
502502
```
503503

504504
### ContinuationCriteriaAdapter
@@ -508,7 +508,7 @@ use Cognesy\Addons\Agent\Hooks\Adapters\ContinuationCriteriaAdapter;
508508

509509
$criterion = new YourContinuationCriterion();
510510
$hook = new ContinuationCriteriaAdapter($criterion);
511-
// @doctest id="7f26"
511+
// @doctest id="3046"
512512
```
513513

514514
## Common Patterns
@@ -533,7 +533,7 @@ $builder->onBeforeToolUse(
533533
priority: 100, // Run first
534534
matcher: 'bash',
535535
);
536-
// @doctest id="3218"
536+
// @doctest id="954f"
537537
```
538538

539539
### Execution Timing
@@ -550,7 +550,7 @@ $builder
550550
$duration = microtime(true) - $started;
551551
$this->metrics->record('execution_duration', $duration);
552552
});
553-
// @doctest id="9c44"
553+
// @doctest id="b850"
554554
```
555555

556556
### Conditional Continuation
@@ -573,7 +573,7 @@ $builder->onStop(function (StopHookContext $ctx): HookOutcome {
573573

574574
return HookOutcome::proceed();
575575
});
576-
// @doctest id="b9e6"
576+
// @doctest id="3ec4"
577577
```
578578

579579
### Error Recovery Logging
@@ -599,7 +599,7 @@ $builder->onAgentFailed(function (FailureHookContext $ctx): void {
599599
$this->alerting->sendCritical($exception);
600600
}
601601
});
602-
// @doctest id="eafe"
602+
// @doctest id="973e"
603603
```
604604

605605
## Architecture
@@ -631,7 +631,7 @@ $builder->onAgentFailed(function (FailureHookContext $ctx): void {
631631
│ │ execution│ │ action │ │ entirely │ │
632632
│ └──────────┘ └──────────┘ └──────────┘ │
633633
└─────────────────────────────────────────────────────────────┘
634-
// @doctest id="e007"
634+
// @doctest id="d779"
635635
```
636636

637637
## File Structure
@@ -672,5 +672,5 @@ packages/addons/src/Agent/Hooks/
672672
└── Adapters/
673673
├── StateProcessorAdapter.php
674674
└── ContinuationCriteriaAdapter.php
675-
// @doctest id="d08d"
675+
// @doctest id="5d5f"
676676
```
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# Introduction
2+
3+
The Agents package provides a minimal, composable foundation for building LLM-powered agents that reason and act through tool use.
4+
5+
At its core, an agent is a **loop**: send messages to an LLM, receive a response (possibly with tool calls), execute those tools, feed results back, and repeat until done.
6+
7+
## Key Design Principles
8+
9+
- **Immutable state** - `AgentState` is a readonly value object. Every mutation returns a new instance.
10+
- **Pluggable drivers** - Swap between `ToolCallingDriver` (native function calling) and `ReActDriver` (Thought/Action/Observation) without changing your agent code.
11+
- **Lifecycle hooks** - Intercept any phase of execution to add guards, logging, or custom behavior.
12+
- **Testable by default** - `FakeAgentDriver` lets you script deterministic scenarios without LLM calls.
13+
14+
## Package Structure
15+
16+
```
17+
Core/ # AgentLoop, AgentState, tools, stop signals
18+
Context/ # AgentContext, message compilers
19+
Hooks/ # Lifecycle interceptors and guard hooks
20+
Drivers/ # ToolCallingDriver, ReActDriver, FakeAgentDriver
21+
Events/ # Agent event system
22+
Exceptions/ # Domain exceptions
23+
// @doctest id="60e4"
24+
```
25+
26+
## Minimal Example
27+
28+
```php
29+
use Cognesy\Agents\Core\AgentLoop;
30+
use Cognesy\Agents\Core\Data\AgentState;
31+
32+
$loop = AgentLoop::default();
33+
$state = AgentState::empty()->withUserMessage('Hello!');
34+
$result = $loop->execute($state);
35+
36+
echo $result->finalResponse()->toString();
37+
// @doctest id="a416"
38+
```
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Basic Agent
2+
3+
The simplest agent uses `AgentLoop` to send a message and get a response.
4+
5+
## Hello World
6+
7+
```php
8+
use Cognesy\Agents\Core\AgentLoop;
9+
use Cognesy\Agents\Core\Data\AgentState;
10+
11+
$loop = AgentLoop::default();
12+
$state = AgentState::empty()->withUserMessage('What is 2+2?');
13+
$result = $loop->execute($state);
14+
15+
echo $result->finalResponse()->toString();
16+
// "2 + 2 equals 4."
17+
// @doctest id="635f"
18+
```
19+
20+
## What Happens
21+
22+
1. `AgentLoop::execute()` starts the loop
23+
2. The driver (`ToolCallingDriver`) sends messages to the LLM
24+
3. LLM responds with text (no tool calls)
25+
4. The loop detects no tool calls and stops
26+
5. Final response is available via `$result->finalResponse()`
27+
28+
## Customizing the Loop
29+
30+
Use `with()` to swap components on the default loop:
31+
32+
```php
33+
use Cognesy\Agents\Core\Collections\Tools;
34+
use Cognesy\Agents\Drivers\ReAct\ReActDriver;
35+
36+
// Add tools
37+
$loop = AgentLoop::default()->withTool($myTool);
38+
39+
// Swap driver
40+
$loop = AgentLoop::default()->withDriver(new ReActDriver(model: 'gpt-4o'));
41+
// @doctest id="ded1"
42+
```
43+
44+
## System Prompt
45+
46+
```php
47+
$state = AgentState::empty()
48+
->withSystemPrompt('You are a helpful assistant.')
49+
->withUserMessage('Hello!');
50+
// @doctest id="aae4"
51+
```
Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
# Tools
2+
3+
Tools let the agent take actions. The LLM decides which tool to call and with what arguments.
4+
5+
## Registering Tools
6+
7+
Pass tools to the `Tools` collection:
8+
9+
```php
10+
use Cognesy\Agents\Core\Collections\Tools;
11+
use Cognesy\Agents\Core\Tools\MockTool;
12+
13+
$calculator = MockTool::returning('calculator', 'Performs math', '42');
14+
$tools = new Tools($calculator);
15+
// @doctest id="6d99"
16+
```
17+
18+
## Using FunctionTool
19+
20+
Wrap any callable as a tool. Parameter schema is auto-generated from the function signature:
21+
22+
```php
23+
use Cognesy\Agents\Core\Tools\FunctionTool;
24+
25+
$tool = FunctionTool::fromCallable(
26+
function (string $city): string {
27+
return "Weather in {$city}: 72F, sunny";
28+
}
29+
);
30+
31+
$tools = new Tools($tool);
32+
// @doctest id="9675"
33+
```
34+
35+
## Agent with Tools
36+
37+
```php
38+
use Cognesy\Agents\Core\AgentLoop;
39+
use Cognesy\Agents\Core\Collections\Tools;
40+
use Cognesy\Agents\Core\Data\AgentState;
41+
42+
$loop = AgentLoop::default()->withTool($tool);
43+
44+
$state = AgentState::empty()->withUserMessage('What is the weather in Paris?');
45+
$result = $loop->execute($state);
46+
// LLM calls the weather tool, gets result, then responds
47+
// @doctest id="255a"
48+
```
49+
50+
## How It Works
51+
52+
1. LLM sees tool schemas and decides to call a tool
53+
2. `ToolExecutor` runs the tool with provided arguments
54+
3. Tool results are formatted as messages and fed back to the LLM
55+
4. LLM uses the results to formulate a final response
56+
5. Loop continues until LLM responds without tool calls

0 commit comments

Comments
 (0)