Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ai Laravel Package

durable-workflow/ai

Durable Workflow AI brings resilient, long-running AI workflows to Laravel. Define multi-step agents and pipelines in PHP with automatic retries, persisted state, and human-in-the-loop approvals, so AI tasks survive failures and run reliably in the background.

View on GitHub
Deep Wiki
Context7

Getting Started

What you are actually installing. durable-workflow/ai is not an agent framework in the LangChain sense and it is not a queue wrapper. It is a thin, opinionated layer that puts sandbox lifecycle under durable orchestration: provisioning containers/VMs, running commands and tools inside them, snapshotting, expiring leases, and tearing them down — all recorded in a workflow history so a crash mid-agent-run resumes instead of orphaning a paid-for sandbox. The value proposition for a Laravel team is the part that is hardest to build yourself: reconciling "did that sandbox actually get created?" after a lost acknowledgement.

Version reality check (updated for 2.0.0-rc.8). The current release is a prerelease on the 2.0 line (2.0.0-rc.8), published as a validation artifact for the Durable Workflow 2.0 runtime. The release notes contain no changelog, no migration guide, and no API surface description — just a source commit (b0a5e4a5c192974a1ed4cc75d77be07ada94ffba). Treat that as a signal, not a formality:

  • An eighth release candidate means the 2.0 API has been churning for a while and is still not declared stable. Budget for a breaking change between now and 2.0.0 final.
  • The absence of notes means you must derive the diff yourself: compare the tagged source against the last 1.x tag (git diff v1.x..2.0.0-rc.8 -- config/ src/) and read UPGRADING.md / CHANGELOG.md in the repo if present. Do this before you write code, not after.
  • Do not assume 1.x workflow histories replay on 2.0. A major bump is exactly when replay compatibility breaks — see Gotchas below on draining runs.
  • If you have not shipped on this package yet, start on 2.0.0-rc.8 anyway (you want the RC's API shape, not a soon-dead 1.x), but pin it exactly and expect to bump the pin when final lands.

Prerequisites you should confirm before writing code:

  1. The base durable-workflow runtime, at the version 2.0 expects (worker process + persistence backend for workflow history). The AI package is a layer on top; without the runtime there is nothing durable. An RC of the AI layer almost certainly pairs with an RC of the runtime — check composer.json constraints rather than mixing 1.x runtime with 2.0 AI.
  2. A sandbox provider account/credential (whatever backends the package ships adapters for — check the README's provider list). Provider adapter signatures are a likely break point between 1.x and 2.0; re-read them even if you know the 1.x API.
  3. PHP + Laravel versions per composer.json. With one star and zero dependents, read composer.json and the CI matrix rather than trusting the badge. An RC may raise the minimum PHP/Laravel beyond what your app currently runs — check this before composer require.

Where to look first, in this order:

  • CHANGELOG.md / UPGRADING.md / GitHub compare 1.x...2.0.0-rc.8 — the release notes we were given are empty, so this is the only way to learn what actually changed.
  • README.md — install command, service provider auto-discovery, config publish tag, migration publish tag, and the canonical example. This is the only place an API reference is likely to exist. Confirm the 2.0 example still matches the 1.x-shaped pseudocode in this assessment; where it differs, the README wins.
  • skills/durable-execution/SKILL.md — the org's design doctrine. Read the "Durable Supervision For AI Agents" section before you design your first workflow. It is effectively the package's conceptual manual, and it is the part most likely to survive the 2.0 churn unchanged.
  • config/*.php after publishing — this tells you more about the real API surface than the README does: provider names, timeouts, lease durations, retention. Diff it against the 1.x config you may have published to spot renamed/removed keys.
  • tests/ — with a low-star package, tests are the de facto documentation of behaviour under failure, and for an RC they are the best evidence of what the maintainers consider stable.
  • https://github.com/durable-workflow/.github/blob/main/AGENTS.md — shared conformance/release rules; useful for judging how seriously the org treats replay correctness, and for understanding whether an rc.8 is a real release gate or just a nightly tag.

Minimal first run (Laravel):

composer require durable-workflow/ai:2.0.0-rc.8   # pin exactly for an RC
php artisan vendor:publish --tag=durable-workflow-config   # confirm tag in README
php artisan vendor:publish --tag=durable-workflow-migrations
php artisan migrate

Then, in outline: define a workflow class whose handle() is deterministic, put sandbox calls in activity classes, register the sandbox provider in config with credentials from config/services.php or env, and run the durable worker (php artisan durable:work or equivalent — verify the command name; a 2.0 RC is a plausible moment for artisan command names to change) as a supervised process alongside your normal queue:work.

First use case to build: one agent session, one sandbox, two tool calls, one teardown.

provision(sandbox)  -> record provider id durably
run(tool: "composer install")
run(tool: "php artisan test")
snapshot -> destroy

Deliberately kill -9 the worker between the second and third step. If your second run resumes at "snapshot" rather than provisioning a second sandbox, the integration is wired correctly and you have internalised the model. Do this test on day one — it is the only test that proves you bought anything. On an RC it doubles as your upgrade compatibility proof: rerun the same kill test on the next RC before you promote it.

Implementation Patterns

The core discipline: workflow supervises, activities touch the world. Everything nondeterministic — the LLM call, exec inside the sandbox, HTTP, Storage::put, secrets, wall-clock time — belongs in an activity/task. Workflow code contains branching, loops, timers, waits, child-workflow calls, and compensation order. If you find yourself writing config('...'), now(), Str::random(), or an Eloquent query inside the workflow class, stop: that code will replay against different values and diverge. This rule is API-version-independent, which is why it is the one thing you should enforce even while the package is moving.

Model the sandbox as a saga, not a try/finally. This is the pattern you will use most:

// pseudocode — names follow the skill guide, verify against README
$sandboxId = yield $this->activity(ProvisionSandbox::class, [
    'idempotency_key' => "{$runId}:provision",
    'image'           => 'php:8.3-cli',
]);

try {
    $result = yield $this->agentLoop($sandboxId);   // child workflow or loop of activities
} finally {
    yield $this->activity(SnapshotSandbox::class, ['sandbox_id' => $sandboxId]);
    yield $this->activity(DestroySandbox::class,  ['sandbox_id' => $sandboxId]);
}

The finally block is best effort — it does not run on hard termination or runtime loss. Pair it with the package's lease/expiry reconciler so sandboxes are eventually reclaimed regardless. Treat lease expiry as the primary guarantee and finally as the fast path. If the package does not expose a reconciler command, that is a gap you must fill with a scheduled artisan command that reconciles provider-side sandboxes against open runs. Re-verify this exists in 2.0 — reconciler wiring is precisely the sort of thing that gets reworked in a major version.

Idempotency keys derived from run identity. "{$runId}:{$stepName}" is the shape. Pass it to the sandbox provider if it supports it; otherwise maintain an application receipt table keyed on it with a unique index, storing the provider's sandbox/operation ID. Because the package records activity results durably, a replayed workflow re-reads the provision result from history instead of provisioning again — but only if you persist the provider ID as the activity's return value, not as a side-channel log line.

Approvals and cancellation via signals/updates. A human-in-the-loop gate is a durable wait, not a polling loop:

yield $this->waitForSignal('approval', timeout: Duration::hours(24));

with an explicit rejection path and an explicit expiry path. Both terminal states must be modelled as business states — rejected_by_reviewer and approval_timed_out are different from failed. Signal/update naming is a common 2.0 breaking change; wrap your own requestApproval() helper around it so the rename is one file.

Budget guards, not just iteration caps. The skill guide is blunt about this: bound iterations, elapsed time, spend, and parallelism. In Laravel terms, an AgentBudget value object threaded through the workflow — maxToolCalls, maxWallClockMinutes, maxSpendCents — checked at the top of the loop, all values recorded in history. A durable infinite loop is still an infinite loop, and it will happily burn sandbox-hours. Put the budget check in your own base workflow class, not inline, so it survives the upgrade.

Keep transcripts out of history. History is for decisions: the sandbox ID, the last tool result summary, the token counts, the approval token. Persist full LLM transcripts, generated files, and screenshots to S3 or a run_artifacts table and record an immutable reference plus a checksum. History payload growth is the most common way these systems fall over in month two. If 2.0 changed its serialization or payload limits, recheck your largest recorded payloads before upgrading in place.

Fan-out with child workflows. Parallel sub-agents get one child workflow each, not a yield inside a foreach in the parent. Child workflows give you independent retry/cancel policy and isolate a bad run. Apply an explicit concurrency limit — durable fan-out will saturate a downstream API exactly as easily as a naive Promise::all.

Laravel integration points that work well:

  • Dispatch from a controller with a business correlation key as the workflow ID, so a duplicate submit is idempotent by construction.
  • Emit domain events (SandboxProvisioned, AgentRunAwaitingApproval) from activities, not from workflow code, so listeners don't fire twice on replay.
  • A Filament/Livewire status page should read a projection table updated by activities, or use the runtime's query API — never read or write the runtime's persistence tables directly. Your projection table is also your upgrade safety net: it keeps working when the runtime schema changes.
  • Keep the durable worker in its own Supervisor program, separate from queue:work. They fail differently and scale differently. Run the RC as a separate Supervisor pool alongside your stable workers during the upgrade window.

Testing. Two layers: (a) normal Pest/PHPUnit tests against activity classes with a fake provider — these are cheap and catch most bugs; (b) replay tests that feed a recorded production history through a changed workflow class before deployment. Layer (b) is what the org guide means by "test replay against representative production histories," and it is non-negotiable once you have runs older than your last deploy. For the 2.0 upgrade specifically: capture a handful of real 1.x histories, run them through the 2.0 workers in a staging namespace, and let that result — not the release notes — decide whether you can upgrade in place or must drain.

Gotchas and Tips

Determinism bugs will come from Laravel itself, not from your code. Facades are ambient and easy to invoke accidentally. now(), Str::uuid(), cache(), config(), env(), auth()->user(), and any Model::find() inside workflow code all break replay. Use the runtime's deterministic clock/random/UUID helpers inside workflows; if the package doesn't provide them, resolve them in an activity and record the result. Add a code-review checklist item or, better, a static rule forbidding facade calls in the Workflows/ namespace. If 2.0 renamed or moved those helpers, that rename will bite you in every workflow at once — grep for the old names as step one of the upgrade.

Never let an Eloquent model or a credential into history. History is persisted, retained, and often human-readable. Pass scalars and IDs. Resolve secrets inside activities from config or a secrets manager. This is a security boundary, not a style preference. An RC is a good moment to re-audit: if 2.0 changed default retention or added history export tooling, previously-internal payloads may become more exposed.

A major-version RC is a replay-compatibility event, so plan the drain. Treat 2.0.0-rc.8 as a new history dialect until proven otherwise. Concretely: keep 1.x workers running until no open 1.x runs remain (or force them to terminal state via the documented cancel/terminate APIs), deploy 2.0 workers to a separate task queue/namespace, and only cut over after replay tests pass. Never point 2.0 workers at a persistence backend holding in-flight 1.x histories unless 2.0's docs explicitly claim forward compatibility. Also confirm whether 2.0 pins code versions or records patch markers — without that, an old run replays new code and you get silent divergence rather than an error.

Ambiguous timeouts are the dangerous case. A CreateSandbox that times out may have succeeded. Do not retry blindly — reconcile by idempotency key or provider operation ID first. Same for exec of anything with external effect. Classify errors before retrying: transient/rate-limit → bounded retry with jitter; validation/permission → fail fast; business rejection → record and follow policy; unknown outcome → reconcile. If 2.0 reworked its exception hierarchy or error classifier extension point, your classifier mappings need re-verification; a mis-mapped error on an ambiguous outcome is how you get two sandboxes and one orphaned invoice.

Sandbox loss is normal, not exceptional. Provider reaps the VM, network partitions, image gets GC'd. Design every tool call to tolerate sandbox_not_found by restoring from snapshot and retrying once. Snapshotting is only useful if you have actually tested the restore path. Provider adapters are a likely 2.0 break point — rerun your restore test against the RC before trusting it.

Do not assume redeploying rewrites history. Old runs replay old code paths. Check whether this package/runtime pins code versions or records patch markers; if not, keep old workflow handlers alive until no compatible runs remain, or migrate runs with reset/continue-as-new. Make payload changes additive with defaults for missing fields. Roll workers forward before running irreversible migrations. During the 2.0 transition this means: two worker pools, one shared projection table, feature-flagged dispatch so new runs go to 2.0 and old runs finish on 1.x.

Debug from history, not from logs or by poking the database. Every time someone "fixes" a stuck run with an UPDATE against the runtime's tables, you lose the ability to reason about it later. Use the documented signal/update/cancel/retry/reset/terminate APIs. Make your logs replay-aware — include a replay boolean — or your telemetry will double-count every activity. Note that the operational API names are exactly what a major version tends to rename; keep a thin internal RunAdmin service wrapping them so your on-call runbook survives the next RC.

Vendor-risk mitigation for a 1-star, 0-dependent package on a prerelease. Pin the exact version ("durable-workflow/ai": "2.0.0-rc.8", not ^2.0 and certainly not ^2.0@rc) and commit the lock file with "minimum-stability": "stable" plus an explicit @rc allowlist so a stray composer update cannot pull a different candidate into production. Record the source commit (b0a5e4a5…) in your upgrade notes so you can diff precisely what you ran. Because the RC cadence is clearly fast, keep your domain logic — prompt construction, tool definitions, result parsing — in your own classes behind narrow interfaces, so a provider adapter or lifecycle API change is a one-file diff. Budget for the rc.8 → 2.0.0 delta explicitly; do not plan a roadmap that assumes an RC is an API freeze. The org-level design doctrine in skills/durable-execution/ will outlive any specific API in this package; that doctrine is the durable part of the dependency.

Extension points worth locating on day one (they determine how much you can shape without forking, and they are the most likely things to have moved in 2.0): the sandbox provider interface (for a custom/on-prem backend), activity middleware or interceptors (for tracing, cost accounting, redaction), custom exception classifiers (mapping provider errors to retry/reconcile/fail), query handlers for your status page, and history retention/archival config. Diff each against what you know of 1.x if you are upgrading. If any of these are missing, note the gap explicitly — the workaround will be a scheduled command or a wrapping service, and you want that decision documented before you have a thousand runs.

Watch these alerts from week one: sandboxes open longer than the expected session length (leak), retry exhaustion rate, runs stalled in a wait past the business deadline, failed compensations, and p95 history payload size. A long-running agent is not itself unhealthy; a sandbox with no matching open run is. During the RC period add one more: count of runs pinned to the old version, which should monotonically fall to zero before you delete the 1.x handlers.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle