Skip to content

Commit 1e484de

Browse files
feat: add chat streaming functionality and corresponding tests
1 parent 7b8b61f commit 1e484de

3 files changed

Lines changed: 105 additions & 0 deletions

File tree

routes/web.php

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
<?php
22

3+
use App\Http\Controllers\ChatController;
34
use Illuminate\Support\Facades\Route;
45
use Inertia\Inertia;
56
use Laravel\Fortify\Features;
@@ -14,4 +15,8 @@
1415
return Inertia::render('dashboard');
1516
})->middleware(['auth', 'verified'])->name('dashboard');
1617

18+
Route::middleware(['auth', 'verified'])->group(function () {
19+
Route::post('chat/stream', [ChatController::class, 'stream'])->name('chat.stream');
20+
});
21+
1722
require __DIR__.'/settings.php';
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
<?php
2+
3+
use App\Ai\Agents\CustomerSupport;
4+
use Laravel\Ai\Prompts\AgentPrompt;
5+
6+
beforeEach(function () {
7+
CustomerSupport::fake([
8+
'Hello! How can I help you today?',
9+
'I can help you with that. Let me look into it.',
10+
]);
11+
});
12+
13+
it('can respond to a customer prompt', function () {
14+
$response = (new CustomerSupport)->prompt('I need help with my order.');
15+
16+
expect($response->text)->toBe('Hello! How can I help you today?');
17+
18+
CustomerSupport::assertPrompted(function (AgentPrompt $prompt) {
19+
return $prompt->contains('order');
20+
});
21+
});
22+
23+
it('can handle multiple prompts in sequence', function () {
24+
$agent = new CustomerSupport;
25+
26+
$first = $agent->prompt('I have a question.');
27+
$second = $agent->prompt('Can you tell me more?');
28+
29+
expect($first->text)->toBe('Hello! How can I help you today?');
30+
expect($second->text)->toBe('I can help you with that. Let me look into it.');
31+
});
32+
33+
it('has proper instructions', function () {
34+
$agent = new CustomerSupport;
35+
36+
expect($agent->instructions())->toContain('customer support agent');
37+
});
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
<?php
2+
3+
use App\Ai\Agents\CustomerSupport;
4+
use App\Models\User;
5+
use Illuminate\Support\Facades\DB;
6+
use Illuminate\Support\Str;
7+
8+
beforeEach(function () {
9+
CustomerSupport::fake([
10+
'Hello! How can I help you today?',
11+
]);
12+
});
13+
14+
test('guests cannot access the stream endpoint', function () {
15+
$this->postJson(route('chat.stream'), [
16+
'message' => 'Hello',
17+
])->assertUnauthorized();
18+
});
19+
20+
test('stream endpoint validates the message field', function () {
21+
$this->actingAs(User::factory()->create())
22+
->postJson(route('chat.stream'), [])
23+
->assertJsonValidationErrors(['message']);
24+
});
25+
26+
test('stream endpoint validates conversation_id is a uuid', function () {
27+
$this->actingAs(User::factory()->create())
28+
->postJson(route('chat.stream'), [
29+
'message' => 'Hello',
30+
'conversation_id' => 'not-a-uuid',
31+
])
32+
->assertJsonValidationErrors(['conversation_id']);
33+
});
34+
35+
test('stream endpoint returns a streamed response', function () {
36+
$this->actingAs(User::factory()->create())
37+
->post(route('chat.stream'), [
38+
'message' => 'Hello',
39+
])
40+
->assertOk()
41+
->assertStreamed();
42+
});
43+
44+
test('stream endpoint prevents access to another user\'s conversation', function () {
45+
$owner = User::factory()->create();
46+
$other = User::factory()->create();
47+
$conversationId = (string) Str::uuid7();
48+
49+
DB::table('agent_conversations')->insert([
50+
'id' => $conversationId,
51+
'user_id' => $owner->id,
52+
'title' => 'Private conversation',
53+
'created_at' => now(),
54+
'updated_at' => now(),
55+
]);
56+
57+
$this->actingAs($other)
58+
->postJson(route('chat.stream'), [
59+
'message' => 'Hello',
60+
'conversation_id' => $conversationId,
61+
])
62+
->assertForbidden();
63+
});

0 commit comments

Comments
 (0)