Laravel SDK
Report cost, latency, and quality for the AI agents in your Laravel app. If you use laravel/ai, every prompt, model step, tool call, failover, failure and embedding is captured automatically, no code changes. The SDK is non-blocking and never throws into your app.
Install
composer require agentping/laravel
Set your API key. The ingest region is read from the key, so there is nothing else to configure:
AGENTPING_API_KEY=apk_eu_...
Requires PHP 8.2+. The service provider is auto-discovered.
Already exporting OpenTelemetry? The same agents can reach Agent Ping over OTLP instead; see Laravel AI SDK with OpenTelemetry for the trade-offs.
Automatic instrumentation
With laravel/ai installed, the SDK listens to the framework's lifecycle events and turns each agent invocation into a run:
$reply = (new SalesCoach)->prompt('Score this email: ...'); // captured automatically
A prompt that calls a tool in the middle becomes a timeline of three events: the model call that asked for the tool, the tool call with its arguments and result, and the model call that produced the answer. Each model call carries its own tokens and is priced on the server, so the run's cost is the sum of what the provider billed.
| laravel/ai event | Agent Ping event | What is recorded |
|---|---|---|
StepCompleted |
llm_call |
Provider, model, input and output tokens (plus cached, cache-creation and reasoning tokens when non-zero), latency, step number, finish reason. |
StepFailed |
llm_call with status: error |
The exception message and class. The run stays open; the prompt may retry or fail over. |
ToolInvoked, ToolFailed |
tool_call |
Tool name, arguments, result, latency, and status: error with the exception when the tool threw. |
ProviderFailedOver, AgentFailedOver |
step (provider_failover) |
The provider and model given up on and the reason. Not an error; the next llm_call shows who served the prompt. |
AgentFailed |
error |
The exception that ended the invocation. The run finishes with status error. |
AgentPrompted, AgentStreamed |
llm_call |
Only for single-step prompts with no step events, so tokens are never counted twice. Streams carry stream: true. |
EmbeddingsGenerated |
llm_call |
Provider, model and input tokens. |
Prompt and completion text are off by default; AGENTPING_CAPTURE_LLM_CONTENT=true adds the prompt as input, the system prompt as system_instructions and the response text as output to each llm_call, clipped at AGENTPING_LLM_CONTENT_MAX_CHARS. laravel/ai stream events carry whole-second timestamps, so this SDK cannot report ttft_ms. Tool arguments and results are sent by default, because they are what makes a tool call readable on the timeline; turn that off or cap it if your tools handle sensitive data:
AGENTPING_CAPTURE_TOOL_PAYLOADS=false
AGENTPING_TOOL_PAYLOAD_MAX_CHARS=4000
An agent that calls another agent through a tool attaches to the outer run, so one user request stays one run named after the outermost agent. When your code has opened a run with AgentPing::run(), every invocation inside it attaches there instead of starting its own.
Disable auto-instrumentation any time with AGENTPING_LISTEN_TO_AI_SDK=false.
Naming your agents
Runs are grouped by agent name in Spend and Pulse. The name is resolved in this order:
- An active run:
AgentPing::run('name')orAgentPing::agent('name', fn () => ...). AgentPing::useAgent('name'): set once at the top of a request, job, or command; every auto-captured call in that scope uses it (reset automatically afterwards).- A named Agent class: a
laravel/aiAgent class likeMorningBriefingis auto-namedmorning_briefing, no extra code. AGENTPING_DEFAULT_AGENT(defaultai-agent).
The anonymous agent($prompt)->prompt(...) helper carries no name, so for those calls use one of the first two. Either name the whole scope once:
use AgentPing\Laravel\Facades\AgentPing;
AgentPing::useAgent('morning-briefing');
$summary = agent($systemPrompt)->prompt($userMessage, provider: 'anthropic');
or wrap a single call to also group it as one run:
$summary = AgentPing::agent('morning-briefing', fn () =>
agent($systemPrompt)->prompt($userMessage, provider: 'anthropic')
);
If you define your agents as classes instead of the agent() helper, naming is automatic.
Manual tracking
For agents that do not use laravel/ai, track runs directly:
use AgentPing\Laravel\Facades\AgentPing;
$run = AgentPing::run('support-triage', customerId: 'acme', feature: 'ticket-routing');
$run->event('llm_call', [
'provider' => 'anthropic',
'model' => 'claude-sonnet-4-6',
'input_tokens' => 1200,
'output_tokens' => 480,
]);
$run->finish('success', scores: ['confidence' => 0.92]);
Nest sub-agents by passing parentRunId: (or set the AGENTPING_PARENT_RUN env var) to build a run tree.
Heartbeats
For cron jobs and scheduled tasks, report one completion per run:
AgentPing::heartbeat('daily-summary', status: 'ok', costUsd: 0.084, durationMs: 12_300);
Guard
Before a scheduled command or queued job starts, ask the control plane whether it should. guardCheck compares your real spend against the rules you set and honours the pause switch on the dashboard:
use AgentPing\Laravel\Exceptions\Paused;
try {
AgentPing::guardCheck(customerRef: 'acme-corp', agent: 'nightly-summariser', function: 'run');
} catch (Paused $e) {
return; // $e->verdict says which rule tripped
}
Pass mode: 'soft' to get the verdict back instead of an exception, and onUnreachable: 'allow' to run when the gate cannot be reached (the default is to block). Guard is on the Team and Business plans; see Guard.
Queue workers
Telemetry flushes automatically at the end of each web request, console command, and queued job. Restart Horizon and your queue workers after deploying so they load the new code and key. For a custom long-running loop, call AgentPing::flush().
Configuration
| Variable | Default | Description |
|---|---|---|
AGENTPING_API_KEY |
required | Region-scoped team key (apk_...). |
AGENTPING_DEFAULT_AGENT |
ai-agent |
Name for un-named auto-captured calls. |
AGENTPING_LISTEN_TO_AI_SDK |
true |
Auto-instrument laravel/ai. |
AGENTPING_CAPTURE_TOOL_PAYLOADS |
true |
Send tool arguments and results on tool_call events. |
AGENTPING_TOOL_PAYLOAD_MAX_CHARS |
4000 |
Truncate each tool argument list and result at this length. |
AGENTPING_PARENT_RUN |
optional | Parent run id for nesting. |
AGENTPING_VERSION |
optional | Build or prompt version label for every run; AgentPing::run(..., version: ...) overrides it per run. |
AGENTPING_CAPTURE_LLM_CONTENT |
false |
Send the prompt, system prompt and response text on llm_call events. |
AGENTPING_LLM_CONTENT_MAX_CHARS |
4000 |
Truncate each captured piece at this length. |
Run php artisan vendor:publish --tag=agentping-config for the full config (queue size, batch size, timeouts, control URL). Use a team key for the SDK; ping_... tokens are for URLs only.
Source on GitHub, changelog. Requires laravel/ai 0.11 or later for the step and tool events; older versions still report AgentPrompted.