Skip to content

Commit 0d35489

Browse files
Merge pull request #17 from atlas-php/main
Added new middleware feature at runtime.
2 parents 63b4073 + 86f5a03 commit 0d35489

File tree

20 files changed

+2448
-62
lines changed

20 files changed

+2448
-62
lines changed

.github/workflows/deploy-docs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ name: Deploy Documentation
22

33
on:
44
push:
5-
branches: [main]
5+
branches: [2.x]
66
paths:
77
- 'docs/**'
88
- '.github/workflows/deploy-docs.yml'

.gitignore

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,4 @@ sandbox/storage/logs/*
6666
# VitePress
6767
docs/.vitepress/cache
6868
docs/.vitepress/dist
69-
70-
# Package-specific ignores
7169
composer.lock

NOTES.md

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
# Development Notes
2+
3+
## TODO: PHPUnit Security Advisory (CVE-2026-24765)
4+
5+
**Date:** 2026-01-27
6+
7+
**Issue:** PHPUnit has a security vulnerability (CVE-2026-24765 - Unsafe Deserialization in PHPT Code Coverage Handling).
8+
9+
- **Fixed in:** PHPUnit 11.5.50
10+
- **Pest 3.x conflicts with:** PHPUnit >11.5.33
11+
- **Result:** Pest 3.x blocks the security fix
12+
13+
**Current Workaround:** Ignoring the advisory in `composer.json`:
14+
```json
15+
"audit": {
16+
"ignore": ["PKSA-z3gr-8qht-p93v"]
17+
}
18+
```
19+
20+
**Why not upgrade to Pest 4?** Pest 4.x requires PHPUnit 12.x - a major version change.
21+
22+
**Action Required:**
23+
- Monitor Pest 3.x releases for PHPUnit 11.5.50 support
24+
- Once Pest 3.x supports the fixed PHPUnit, remove the audit ignore
25+
- Alternatively, evaluate upgrading to Pest 4.x + PHPUnit 12.x
26+
27+
---
28+
29+
## Open Question: Should we commit `composer.lock`?
30+
31+
**Pros:**
32+
- Reproducible CI builds
33+
- Avoids surprise failures when upstream dependencies release breaking changes
34+
- Zero impact on consumers (lock file is ignored when package is installed as dependency)
35+
36+
**Cons:**
37+
- Traditional library convention is to not commit lock files
38+
- May mask dependency resolution issues until intentional updates
39+
40+
**Decision:** TBD

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -154,9 +154,9 @@ echo $response->text();
154154

155155
## Why Atlas?
156156

157-
**The problem:** Prompts scattered across controllers, duplicated configurations, businesses logic tightly coupled with tools, and no consistent way to add logging, validation or even proper error handling.
157+
**The problem:** Prompts scattered across controllers, duplicated configurations, business logic tightly coupled with tools, and no consistent way to add logging, validation or even proper error handling.
158158

159-
**Atlas decouples your businesses logic:**
159+
**Atlas decouples your business logic:**
160160

161161
- **Agents** - AI configurations live in dedicated classes, not inline across your codebase.
162162
- **Tools** - Business logic stays in tool classes with typed parameters. Agents call tools; tools call your services.

composer.json

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@
1515
"orchestra/testbench": "^9.0|^10.0",
1616
"pestphp/pest": "^3.0"
1717
},
18+
"config": {
19+
"sort-packages": true,
20+
"allow-plugins": {
21+
"pestphp/pest-plugin": true
22+
},
23+
"audit": {
24+
"ignore": ["PKSA-z3gr-8qht-p93v"]
25+
}
26+
},
1827
"suggest": {
1928
"prism-php/relay": "Required for MCP (Model Context Protocol) tool support"
2029
},
@@ -42,12 +51,6 @@
4251
"@test"
4352
]
4453
},
45-
"config": {
46-
"sort-packages": true,
47-
"allow-plugins": {
48-
"pestphp/pest-plugin": true
49-
}
50-
},
5154
"extra": {
5255
"laravel": {
5356
"providers": [

docs/capabilities/chat.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -220,6 +220,7 @@ $response = Atlas::agent('support-agent')
220220
| `withMedia(array $media)` | Attach Prism media objects via builder pattern |
221221
| `withTools(array $tools)` | Add Atlas tools at runtime (accumulates) |
222222
| `withMcpTools(array $tools)` | Add MCP tools at runtime ([details](/capabilities/mcp)) |
223+
| `middleware(array $handlers)` | Attach per-request pipeline handlers ([details](/core-concepts/pipelines#runtime-middleware)) |
223224

224225
</div>
225226

@@ -305,6 +306,10 @@ Atlas::agent(string|AgentContract $agent)
305306
->withTools(array $tools) // Add Atlas tools at runtime
306307
->withMcpTools(array $tools) // Add MCP tools at runtime
307308

309+
// Middleware
310+
->middleware(array $handlers) // Attach per-request pipeline handlers
311+
->withoutMiddleware() // Remove all runtime middleware
312+
308313
// Structured output
309314
->withSchema(SchemaBuilder|ObjectSchema $schema) // Schema for structured response
310315
->usingAutoMode() // Auto schema mode (default)
@@ -374,3 +379,4 @@ Image::fromFileId(string $fileId): Image;
374379
- [Streaming](/capabilities/streaming) — Real-time streaming responses
375380
- [Structured](/capabilities/structured-output) — Schema-based responses
376381
- [MCP](/capabilities/mcp) — External tools from MCP servers
382+
- [Pipelines](/core-concepts/pipelines#runtime-middleware) — Per-request middleware for validation, logging, and error recovery

docs/core-concepts/agents.md

Lines changed: 145 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -965,6 +965,148 @@ $registry->decoratorCount(); // number of registered decorators
965965
$registry->clearDecorators(); // remove all decorators
966966
```
967967

968+
## Runtime Middleware
969+
970+
Attach per-request middleware to agent executions without global registration. This is useful for request-specific validation, logging, or error recovery.
971+
972+
```php
973+
use Atlasphp\Atlas\Atlas;
974+
975+
$response = Atlas::agent('my-agent')
976+
->middleware([
977+
'agent.before_execute' => ValidateInputMiddleware::class,
978+
'agent.after_execute' => LogResponseMiddleware::class,
979+
])
980+
->chat($input);
981+
```
982+
983+
### Multiple Handlers
984+
985+
```php
986+
->middleware([
987+
'agent.before_execute' => [
988+
AuthMiddleware::class,
989+
RateLimitMiddleware::class,
990+
],
991+
])
992+
```
993+
994+
### Handler Instances
995+
996+
Pass configured instances for runtime configuration:
997+
998+
```php
999+
->middleware([
1000+
'agent.after_execute' => new MetricsMiddleware($statsd),
1001+
])
1002+
```
1003+
1004+
### Accumulating Middleware
1005+
1006+
Multiple calls merge handlers:
1007+
1008+
```php
1009+
->middleware(['agent.before_execute' => AuthMiddleware::class])
1010+
->middleware(['agent.after_execute' => LogMiddleware::class])
1011+
// Both middleware are applied
1012+
```
1013+
1014+
### Clearing Middleware
1015+
1016+
```php
1017+
->withoutMiddleware()
1018+
```
1019+
1020+
Runtime middleware merges with global handlers by priority. Global handlers run first (sorted by their registered priority), followed by runtime handlers (in registration order).
1021+
1022+
See [Runtime Middleware](/core-concepts/pipelines#runtime-middleware) for complete documentation including available events, execution order, and examples.
1023+
1024+
## Queue Processing
1025+
1026+
AgentContext supports serialization for queue-based async processing. This enables dispatching agent jobs to Laravel queues while Atlas handles only the context serialization—consumers manage all persistence.
1027+
1028+
### Dispatching to Queue
1029+
1030+
```php
1031+
// Build context and serialize for queue transport
1032+
$context = new AgentContext(
1033+
variables: [
1034+
'user_name' => $user->name
1035+
],
1036+
metadata: [
1037+
'task_id' => $task->id,
1038+
'user_id' => $user->id
1039+
],
1040+
);
1041+
1042+
// You create a job that accepts AgentContext as a constructor argument
1043+
ProcessAgentJob::dispatch(
1044+
agentKey: 'my-agent',
1045+
input: 'Generate a report',
1046+
context: $context->toArray(),
1047+
);
1048+
```
1049+
1050+
### Processing in Job
1051+
1052+
Create a processing job
1053+
1054+
```php
1055+
use Atlasphp\Atlas\Agents\Support\AgentContext;
1056+
1057+
class ProcessAgentJob implements ShouldQueue
1058+
{
1059+
public function __construct(
1060+
public string $agentKey,
1061+
public string $input,
1062+
public array $context,
1063+
) {}
1064+
1065+
public function handle(): void
1066+
{
1067+
$context = AgentContext::fromArray($this->context);
1068+
1069+
$response = Atlas::agent($this->agentKey)
1070+
->withContext($context)
1071+
->chat($this->input);
1072+
1073+
// Handle response...
1074+
}
1075+
}
1076+
```
1077+
1078+
### Serialization Notes
1079+
1080+
The following properties are fully serialized:
1081+
- `messages` — Conversation history in array format
1082+
- `variables` — System prompt variable bindings
1083+
- `metadata` — Pipeline metadata
1084+
- `providerOverride` / `modelOverride` — Provider and model overrides
1085+
- `prismCalls` — Captured Prism method calls
1086+
- `tools` — Atlas tool class names
1087+
- `middleware` — Runtime middleware (class-strings only; handler instances are excluded)
1088+
1089+
Runtime-only properties (not serialized):
1090+
- `prismMedia` — Media attachments (must be re-attached via `withMedia()`)
1091+
- `prismMessages` — Prism message objects (rebuilt at runtime)
1092+
- `mcpTools` — MCP tools (must be resolved at runtime)
1093+
- Middleware handler instances — Only class-string handlers are serialized
1094+
1095+
For media attachments, store the file path in metadata and re-attach in your job:
1096+
1097+
```php
1098+
public function handle(): void
1099+
{
1100+
$context = AgentContext::fromArray($this->context);
1101+
$imagePath = $context->getMeta('image_path');
1102+
1103+
$response = Atlas::agent($this->agentKey)
1104+
->withContext($context)
1105+
->withMedia(Image::fromPath($imagePath))
1106+
->chat($this->input);
1107+
}
1108+
```
1109+
9681110
## API Reference
9691111

9701112
```php
@@ -1000,6 +1142,8 @@ Atlas::agent(string|AgentContract $agent)
10001142
->withMedia(Image|Document|Audio|Video|array $media) // Attach media
10011143
->withTools(array $tools) // Add Atlas tools at runtime
10021144
->withMcpTools(array $tools) // Add MCP tools at runtime
1145+
->middleware(array $handlers) // Attach per-request pipeline handlers
1146+
->withoutMiddleware() // Remove all runtime middleware
10031147
->withSchema(SchemaBuilder|ObjectSchema $schema) // Structured output
10041148
->usingAutoMode() // Auto schema mode (default)
10051149
->usingNativeMode() // Native JSON schema mode
@@ -1063,4 +1207,4 @@ $registry->clearDecorators(): void;
10631207
- [System Prompts](/core-concepts/system-prompts) — Variable interpolation in prompts
10641208
- [Tools](/core-concepts/tools) — Add callable tools to agents
10651209
- [MCP](/capabilities/mcp) — External tools from MCP servers
1066-
- [Pipelines](/core-concepts/pipelines)Add middleware for agent execution
1210+
- [Pipelines](/core-concepts/pipelines)Global and per-request middleware for agent execution

0 commit comments

Comments
 (0)