vulnerar/agent
Vulnerar Agent is a lightweight Laravel package that connects your application to the Vulnerar security platform for continuous vulnerability monitoring. It publishes configuration, reports installed dependencies, and helps surface security issues early, with simple Composer installation and per-env...
Install the package and publish its assets before writing any agent code:
composer require vulnerar/agent
php artisan vendor:publish --tag=agent-config # check the actual tag in the README
php artisan migrate # if the package ships conversation/message tables
Set the provider credentials the package expects (usually an AGENT_* or provider-standard key such as OPENAI_API_KEY) in .env, then confirm the defaults in config/agent.php — model, driver, storage disk, and queue connection are the four values you will touch most.
Where to look first:
config/agent.php — the single source of truth for driver, model, streaming, and file-storage behaviour.src/ namespace for the base agent class and any Contracts/ directory; that tells you what is swappable.php artisan tinker session to prove credentials and connectivity work before building anything.First use case: build the smallest possible agent — a class with instructions and no tools — and invoke it from a controller or a queued job. Once that round-trips, add either a tool or a Livewire chat component, not both at once. If you are on Livewire, upgrade to v1.1.1 immediately: file uploads from Livewire components were broken prior to this patch, and it is the most common first thing a developer tries.
Agents as classes. Define each agent as a dedicated class (instructions, model override, allowed tools, output shape) rather than configuring inline. This keeps prompts reviewable in diffs and lets you inject the agent into controllers, jobs, and tests via the container.
Invoke from a job, not a request. Any agent call that uses tools or long context will blow past typical PHP/web timeouts. Dispatch a job, persist the result, and broadcast or poll from the frontend. Reserve synchronous calls for short, single-turn prompts.
Streaming to the browser. If the package exposes a streaming response, wire it to a route with response()->stream() or an SSE endpoint and consume it with a small JS client. Do not attempt token-by-token streaming inside a standard Livewire render() cycle — the request lifecycle does not cooperate.
Livewire file uploads (v1.1.1+). Use Livewire\WithFileUploads, validate the upload as you normally would, then hand the TemporaryUploadedFile to the agent. The important pattern is to move the file to a permanent disk before dispatching a queued agent run — temporary uploads are purged at end of request, so a job that receives only the temp path will fail intermittently. Pass the stored path (or a model reference) into the job instead.
Tools / function calling. Keep each tool a thin adapter over an existing service class with a narrow, well-documented signature. Return plain arrays or DTOs, never Eloquent models — the serialisation into the tool result is where surprising payloads creep in. Add a hard cap on tool iterations to stop runaway loops.
Conversation persistence. If the package stores threads, always resolve the conversation by an owned model ($user->conversations()), not by an ID from the request. Agent history is user data and needs the same authorisation treatment as any other record.
Testing. Fake the underlying HTTP client (or the package's own fake, if one exists) and assert on the agent's assembled messages rather than on live responses. Snapshot tests on the prompt-building layer catch accidental instruction regressions cheaply.
WithFileUploads should be re-tested end-to-end after bumping, since the fix may change what object type the agent receives.updated* hook or a FormRequest; agent providers will happily bill you for a 40 MB PDF.config/agent.php, run php artisan config:clear. A cached config with a stale model name produces confusing 404s from the provider API.max_execution_time all need to be ordered sensibly; the shortest one wins and the error message rarely says which one fired.dd() inside the agent loop; the message array is usually malformed long before the provider rejects it.How can I help you explore Laravel packages today?