Fake the harness. No provider, no queue worker, no network, but the real coordinator, event store, approvals, and artifacts:

use Clutch\Laravel\Facades\Clutch;
use Clutch\Laravel\Runtime\ClutchResult;

Clutch::fake([
    'Draft a brief' => ClutchResult::text('The proposed brief...'),
]);

$session = Clutch::agent(ResearchAgent::class)->for($user)->create();

$session->queue('Draft a brief');

Clutch::assertSessionCreated(ResearchAgent::class);
Clutch::assertRunQueued('Draft a brief');
Clutch::assertRunCompleted();
Clutch::assertNothingAwaitingApproval();

Test a paused run:

Clutch::fake([
    ClutchResult::awaitingApproval(
        tool: 'publish_article',
        arguments: ['article_id' => 123],
    ),
]);

$run = $session->queue('Publish the approved article.');

Clutch::assertApprovalRequested('publish_article');

Script richer ones:

Clutch::fake([
    ClutchResult::text('Report ready.')
        ->withToolCall('search_web', ['q' => 'pricing'], '12 results')
        ->withArtifact(Artifact::fromContents($pdf, 'report.pdf')->name('Report')),

    ClutchResult::structured(['score' => 87]),
    ClutchResult::failure('The provider is down.'),
]);

The assertions available: assertSessionCreated, assertNoSessionCreated, assertRunQueued, assertRunCompleted, assertRunFailed, assertRunCancelled, assertRunExceededBudget, assertRunAwaitingApproval, assertApprovalRequested, assertApproved, assertRejected, assertNothingAwaitingApproval, assertArtifactCreated, assertEventRecorded, assertPromptedTimes, assertNothingPrompted.

Failure messages say what actually happened:

Expected a harness run to have reached [completed] for a prompt containing [Draft a brief].
Runs recorded: awaiting_approval ("Draft a brief")

Back to top

A community package, not affiliated with or endorsed by Laravel. Released under the MIT licence.

This site uses Just the Docs, a documentation theme for Jekyll.