Skip to content

Commit 08502e1

Browse files
committed
wip
1 parent aca2d07 commit 08502e1

File tree

13 files changed

+744
-114
lines changed

13 files changed

+744
-114
lines changed

src/Agents/Agent.php

Lines changed: 16 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@
3333
use Cortex\Events\AgentStreamChunk;
3434
use Cortex\Agents\Stages\AppendUsage;
3535
use Cortex\LLM\Data\ChatStreamResult;
36+
use Cortex\Agents\Contracts\Middleware;
3637
use Cortex\Events\Contracts\AgentEvent;
3738
use Cortex\Exceptions\GenericException;
3839
use Cortex\Memory\Stores\InMemoryStore;
@@ -338,33 +339,31 @@ protected function buildPipeline(): Pipeline
338339
*/
339340
protected function executionStages(): array
340341
{
341-
$beforePrompt = [];
342-
$beforeModel = [];
343-
$afterModel = [];
344-
345-
foreach ($this->middleware as $middleware) {
346-
if ($middleware instanceof BeforePromptMiddleware) {
347-
$beforePrompt[] = $middleware;
348-
} elseif ($middleware instanceof BeforeModelMiddleware) {
349-
$beforeModel[] = $middleware;
350-
} elseif ($middleware instanceof AfterModelMiddleware) {
351-
$afterModel[] = $middleware;
352-
}
353-
}
354-
355342
return [
356343
new TrackAgentStepStart($this),
357-
...$beforePrompt,
344+
...$this->getMiddleware(BeforePromptMiddleware::class),
358345
$this->prompt,
359-
...$beforeModel,
346+
...$this->getMiddleware(BeforeModelMiddleware::class),
360347
$this->llm,
361-
...$afterModel,
348+
...$this->getMiddleware(AfterModelMiddleware::class),
362349
new AddMessageToMemory($this->memory),
363350
new AppendUsage(),
364351
new TrackAgentStepEnd($this),
365352
];
366353
}
367354

355+
/**
356+
* Get the middleware of a specific type.
357+
*
358+
* @param class-string<\Cortex\Agents\Contracts\Middleware> $type
359+
*
360+
* @return array<int, \Cortex\Agents\Contracts\Middleware>
361+
*/
362+
protected function getMiddleware(string $type): array
363+
{
364+
return array_filter($this->middleware, fn(Middleware $middleware): bool => $middleware instanceof $type);
365+
}
366+
368367
/**
369368
* @param array<int, \Cortex\LLM\Contracts\Message> $messages
370369
* @param array<string, mixed> $input

src/Agents/Contracts/AfterModelMiddleware.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
namespace Cortex\Agents\Contracts;
66

7-
use Cortex\Contracts\Pipeable;
8-
97
/**
108
* Middleware that runs after the LLM model call.
11-
* Extends Pipeable to ensure RuntimeConfig is available as the second parameter.
129
*/
13-
interface AfterModelMiddleware extends Pipeable {}
10+
interface AfterModelMiddleware extends Middleware {}

src/Agents/Contracts/BeforeModelMiddleware.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
namespace Cortex\Agents\Contracts;
66

7-
use Cortex\Contracts\Pipeable;
8-
97
/**
108
* Middleware that runs before the LLM model call.
11-
* Extends Pipeable to ensure RuntimeConfig is available as the second parameter.
129
*/
13-
interface BeforeModelMiddleware extends Pipeable {}
10+
interface BeforeModelMiddleware extends Middleware {}

src/Agents/Contracts/BeforePromptMiddleware.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,7 @@
44

55
namespace Cortex\Agents\Contracts;
66

7-
use Cortex\Contracts\Pipeable;
8-
97
/**
108
* Middleware that runs before the prompt is processed.
11-
* Extends Pipeable to ensure RuntimeConfig is available as the second parameter.
129
*/
13-
interface BeforePromptMiddleware extends Pipeable {}
10+
interface BeforePromptMiddleware extends Middleware {}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cortex\Agents\Contracts;
6+
7+
use Cortex\Contracts\Pipeable;
8+
9+
/**
10+
* Base interface for all middleware.
11+
*/
12+
interface Middleware extends Pipeable {}

src/Agents/Stages/AddMessageToMemory.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public function handlePipeable(mixed $payload, RuntimeConfig $config, Closure $n
3434
// Add the message to the memory
3535
$this->memory->addMessage($message);
3636

37+
// Set the message for the current step
38+
$config->context->getCurrentStep()->setAssistantMessage($message);
39+
3740
// Set the message history in the context
3841
$config->context->setMessageHistory($this->memory->getMessages());
3942
}

src/Agents/Stages/HandleToolCalls.php

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,9 +38,6 @@ public function handlePipeable(mixed $payload, RuntimeConfig $config, Closure $n
3838
$generation = $this->getGeneration($payload);
3939

4040
while ($generation?->message?->hasToolCalls() && $this->currentStep++ < $this->maxSteps) {
41-
// Update the current step to indicate it had tool calls
42-
$config->context->getCurrentStep()->setAssistantMessage($generation->message);
43-
4441
// Get the results of the tool calls, represented as tool messages.
4542
$toolMessages = $generation->message->toolCalls->invokeAsToolMessages($this->tools);
4643

src/Agents/Stages/TrackAgentStepEnd.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,10 @@ public function handlePipeable(mixed $payload, RuntimeConfig $config, Closure $n
3333
default => null,
3434
};
3535

36-
// Set tool calls on the current step if the generation has them
37-
if ($generation !== null) {
38-
$config->context->getCurrentStep()->setAssistantMessage($generation->message);
39-
}
40-
4136
// Only push StepEnd chunk and dispatch event when it's the final chunk or a non-streaming result
4237
if ($generation !== null) {
4338
if ($config->streaming) {
39+
dump('pushing step end chunk');
4440
$config->stream->push(new ChatGenerationChunk(ChunkType::StepEnd));
4541
} else {
4642
$this->agent->dispatchEvent(new AgentStepEnd($this->agent, $config));

src/Http/Controllers/AgentsController.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -105,8 +105,8 @@ public function stream(string $agent, Request $request): void// : StreamedRespon
105105

106106
try {
107107
foreach ($result as $chunk) {
108-
dump($chunk->type->value);
109-
// dump(sprintf('%s: %s', $chunk->type->value, $chunk->message->content));
108+
// dump($chunk->type->value);
109+
dump(sprintf('%s: %s', $chunk->type->value, $chunk->message->content));
110110
}
111111

112112
// return $result->streamResponse();

src/LLM/Data/ChatStreamResult.php

Lines changed: 8 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -5,25 +5,21 @@
55
namespace Cortex\LLM\Data;
66

77
use Generator;
8-
use DateTimeImmutable;
98
use Cortex\LLM\Enums\ChunkType;
109
use Cortex\LLM\Enums\FinishReason;
1110
use Cortex\Pipeline\RuntimeConfig;
1211
use Illuminate\Support\LazyCollection;
13-
use Cortex\LLM\Streaming\AgUiDataStream;
14-
use Cortex\LLM\Streaming\VercelDataStream;
15-
use Cortex\LLM\Streaming\VercelTextStream;
1612
use Cortex\Events\RuntimeConfigStreamChunk;
17-
use Cortex\LLM\Contracts\StreamingProtocol;
18-
use Cortex\LLM\Streaming\DefaultDataStream;
1913
use Cortex\LLM\Data\Messages\AssistantMessage;
20-
use Symfony\Component\HttpFoundation\StreamedResponse;
14+
use Cortex\LLM\Data\Concerns\HasStreamResponses;
2115

2216
/**
2317
* @extends LazyCollection<int, \Cortex\LLM\Data\ChatGenerationChunk>
2418
*/
2519
class ChatStreamResult extends LazyCollection
2620
{
21+
use HasStreamResponses;
22+
2723
public function appendStreamBuffer(RuntimeConfig $config): self
2824
{
2925
return new self(function () use ($config): Generator {
@@ -34,7 +30,11 @@ public function appendStreamBuffer(RuntimeConfig $config): self
3430
// Drain items from the buffer and dispatch events for them
3531
if ($config->stream->isNotEmpty()) {
3632
foreach ($config->stream->drain() as $chunk) {
37-
$shouldYieldBeforeEvent = $chunk instanceof ChatGenerationChunk && ! $chunk->type->isEnd();
33+
if (! $chunk instanceof ChatGenerationChunk) {
34+
continue;
35+
}
36+
37+
$shouldYieldBeforeEvent = ! $chunk->type->isEnd();
3838

3939
if ($shouldYieldBeforeEvent) {
4040
$config->dispatchEvent(
@@ -56,55 +56,6 @@ public function appendStreamBuffer(RuntimeConfig $config): self
5656
});
5757
}
5858

59-
/**
60-
* Create a streaming response using the Vercel AI SDK protocol.
61-
*/
62-
public function streamResponse(): StreamedResponse
63-
{
64-
return $this->toStreamedResponse(new DefaultDataStream());
65-
}
66-
67-
/**
68-
* Create a plain text streaming response (Vercel AI SDK text format).
69-
* Streams only the text content without any JSON encoding or metadata.
70-
*
71-
* @see https://sdk.vercel.ai/docs/ai-sdk-core/generating-text
72-
*/
73-
public function vercelTextStreamResponse(): StreamedResponse
74-
{
75-
return $this->toStreamedResponse(new VercelTextStream());
76-
}
77-
78-
public function vercelDataStreamResponse(): StreamedResponse
79-
{
80-
return $this->toStreamedResponse(new VercelDataStream());
81-
}
82-
83-
/**
84-
* Create a streaming response using the AG-UI protocol.
85-
*
86-
* @see https://docs.ag-ui.com/concepts/events.md
87-
*/
88-
public function agUiStreamResponse(): StreamedResponse
89-
{
90-
return $this->toStreamedResponse(new AgUiDataStream());
91-
}
92-
93-
/**
94-
* Create a streaming response using a custom streaming protocol.
95-
*/
96-
public function toStreamedResponse(StreamingProtocol $protocol): StreamedResponse
97-
{
98-
/** @var \Illuminate\Routing\ResponseFactory $responseFactory */
99-
$responseFactory = response();
100-
101-
return $responseFactory->stream($protocol->streamResponse($this), headers: [
102-
'Content-Type' => 'text/event-stream',
103-
'Cache-Control' => 'no-cache',
104-
'X-Accel-Buffering' => 'no',
105-
]);
106-
}
107-
10859
public static function fake(?string $string = null, ?ToolCallCollection $toolCalls = null): self
10960
{
11061
return new self(function () use ($string, $toolCalls) {
@@ -120,7 +71,6 @@ public static function fake(?string $string = null, ?ToolCallCollection $toolCal
12071
type: ChunkType::TextDelta,
12172
id: 'fake-' . $index,
12273
message: new AssistantMessage($chunk, $toolCalls),
123-
createdAt: new DateTimeImmutable(),
12474
finishReason: $isFinal ? FinishReason::Stop : null,
12575
usage: new Usage(
12676
promptTokens: 0,

0 commit comments

Comments
 (0)