> ## Documentation Index
> Fetch the complete documentation index at: https://docs.superwire.dev/llms.txt
> Use this file to discover all available pages before exploring further.

# Laravel Integration

> Execute, stream, validate, format, map, and fake workflows from Laravel.

Laravel applications use the `Superwire\Laravel\Workflow` fluent API to send workflows to the executor.

## Install package

```bash theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
composer require superwire/superwire-laravel
```

## Run a workflow from a file

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs([
        'message' => 'Write a short welcome message.',
    ])
    ->secrets([
        'api_key' => config('services.openai.key'),
    ])
    ->run();

$output = $result->output;
```

## Run a workflow from source

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

$source = <<<'WIRE'
input {
    message: string
}

secrets {
    api_key: string
}

provider llm from openai {
    endpoint: "https://api.openai.com/v1"
    api_key: secrets.api_key
}

model fast from llm {
    id: "gpt-4.1-mini"
}

agent reply {
    model: model.fast
    instruction: "Reply to {{ input.message }}"

    output {
        message: string
    }
}

output {
    message: agent.reply.message
}
WIRE;

$result = Workflow::fromSource($source)
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => config('services.openai.key')])
    ->run();
```

## Cache key

Use `cacheKey()` to opt into executor caching for a specific client-controlled scope. Reuse the same key to reuse matching cached agent outputs, or change the key to start a fresh cache scope.

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => config('services.openai.key')])
    ->cacheKey("tenant:{$tenantId}:conversation:{$conversationId}")
    ->run();
```

## Stream workflow events

`stream()` yields `ExecutorEvent` instances.

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

foreach (
    Workflow::fromFile(resource_path('workflows/reply.wire'))
        ->inputs(['message' => 'Hello'])
        ->secrets(['api_key' => config('services.openai.key')])
        ->stream() as $event
) {
    if ($event->output() !== null) {
        $partialOrFinalOutput = $event->output();
    }

    if ($event->isTerminal()) {
        break;
    }
}
```

`streamToResult()` consumes the stream and returns the final `WorkflowResult`.

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => config('services.openai.key')])
    ->streamToResult();
```

## Event helpers

An `ExecutorEvent` exposes:

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
$event->kind;
$event->agentName;
$event->event;
$event->isTerminal();
$event->output();
$event->toArray();
```

Known event kinds include workflow started, workflow planned, agent started, agent completed, tool call started, tool call completed, tool call failed, MCP call started, MCP call completed, MCP call failed, workflow completed, and workflow failed.

## Validate and format

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
$validation = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->secrets(['api_key' => config('services.openai.key')])
    ->validate();

$formatted = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->format();
```

## Map output into a class

`mapInto()` maps the final output into a PHP class. If the class has a static `from()` method, it is used. Otherwise, array output is passed as named constructor arguments.

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
final readonly class ReplyOutput
{
    public function __construct(
        public string $message,
    ) {}
}

$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => config('services.openai.key')])
    ->mapInto(ReplyOutput::class)
    ->run();

$output = $result->output;
```

## Testing with fakes

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

Workflow::fake([
    'message' => 'Fake workflow output.',
]);

$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => 'test-key'])
    ->run();

Workflow::restoreFake();
```

## Testing patterns

Validate workflow contracts in tests:

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

$validation = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->secrets([
        'api_key' => config('services.openai.key'),
    ])
    ->validate();
```

Use fake execution for deterministic application tests:

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
use Superwire\Laravel\Workflow;

Workflow::fake([
    'message' => 'Hello from a fake workflow.',
]);

$result = Workflow::fromFile(resource_path('workflows/reply.wire'))
    ->inputs(['message' => 'Hello'])
    ->secrets(['api_key' => 'test-key'])
    ->run();

expect($result->output)->toBe([
    'message' => 'Hello from a fake workflow.',
]);

Workflow::restoreFake();
```

Test data guidance:

* Keep test workflows small.
* Use deterministic inputs.
* Avoid live provider calls in unit tests.
* Reserve end-to-end tests for the executor boundary.

## API summary

```php theme={"languages":{"custom":["/languages/wire.tmLanguage.json"]}}
Workflow::fromFile($path);
Workflow::fromSource($source);

$workflow->inputs([...]);
$workflow->secrets([...]);
$workflow->mapInto(SomeOutput::class);

$workflow->run();
$workflow->stream();
$workflow->streamToResult();
$workflow->validate();
$workflow->format();

Workflow::fake([...]);
Workflow::restoreFake();
```
