cd /news/developer-tools/give-your-laravel-ai-agent-real-time… · home topics developer-tools article
[ARTICLE · art-62593] src=dev.to ↗ pub= topic=developer-tools verified=true sentiment=· neutral

Give your Laravel AI agent real-time web knowledge

A developer built a custom web research tool for the Laravel AI SDK to replace provider-native web search and fetch tools, which silently fail when a fallback provider lacks support. The solution uses the Tabstack API to return structured, cited reports, ensuring agents can browse the web reliably across any provider.

read5 min views1 publishedJul 16, 2026

One of the best things about the Laravel AI SDK is that it doesn't lock you into a provider. Swap OpenAI for Anthropic, add Gemini as a failover, and your agent code barely changes. That's the entire pitch, and it mostly holds up.

Until your agent needs to browse the web.

The SDK ships two provider tools for giving agents access to the web: WebSearch

and WebFetch

. They're convenient, a couple lines and your agent can search or fetch a page. But they're not really part of the SDK's unified layer, they're implemented natively by whichever AI provider you're using, which means their availability depends entirely on which model you picked.

WebSearch

works on Anthropic, OpenAI, Gemini, and OpenRouter. WebFetch

only works on Anthropic and Gemini. So if you configure a failover chain that includes Groq, DeepSeek, Mistral, or xAI, and one of those becomes the active provider, your agent quietly loses the ability to browse. Not an error, not a warning, just an agent that stops citing sources or stops noticing the page it was supposed to check even changed.

That's a rough thing to discover in production. You built a failover chain specifically so a rate limit or outage wouldn't take your feature down, and it turns out one of your fallback providers was silently missing a capability the whole time.

Set the provider problem aside for a second. Even on a provider where WebSearch

and WebFetch

are both available, what you get back is raw: search results or fetched page content that the model has to reason over itself. There's no schema. There's no guaranteed citation tracking. If you want your agent to return a structured, sourced answer, that reasoning happens somewhere in the model's own inference, not in a layer you control or can test.

For a lot of use cases, that's fine. For anything where the answer needs to be defensible or reproducible, a research assistant, a competitive brief, anything a user might ask "where did this come from," it's not enough.

The fix is to stop relying on provider-native web tools and give your agent a custom tool instead, one backed by an API rather than whichever model happens to be answering the prompt. That's exactly what a Tool

class in the Laravel AI SDK is for.

juststeveking/tabstack

gives you the client to build it on. Its agent()->research()

method takes a question, searches multiple sources, synthesizes an answer, and streams back a report with citations, all as one call.

Since the package doesn't ship Laravel integration out of the box, the first step is binding it in a service provider so it can be injected anywhere:

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use JustSteveKing\Tabstack\Tabstack;

class AppServiceProvider extends ServiceProvider
{
    public function register(): void
    {
        $this->app->singleton(Tabstack::class, fn () => Tabstack::make(
            apiKey: config('services.tabstack.key'),
        ));
    }
}

Add the key to config/services.php

:

'tabstack' => [
    'key' => env('TABSTACK_API_KEY'),
],

Now the tool itself. This wraps agent()->research()

and hands the agent back a report with its sources listed:

<?php

namespace App\Ai\Tools;

use Illuminate\Contracts\JsonSchema\JsonSchema;
use JustSteveKing\Tabstack\Requests\AgentResearch;
use JustSteveKing\Tabstack\Requests\ResearchMode;
use JustSteveKing\Tabstack\Tabstack;
use Laravel\Ai\Contracts\Tool;
use Laravel\Ai\Tools\Request;
use Stringable;

class WebResearch implements Tool
{
    public function __construct(
        private readonly Tabstack $tabstack,
    ) {}

    public function description(): Stringable|string
    {
        return 'Answers a question by researching multiple sources on the web and returns a synthesized, cited report. Use this when you need current information not in your training data.';
    }

    public function handle(Request $request): Stringable|string
    {
        $result = $this->tabstack->agent()->research(
            params: new AgentResearch(
                query: $request['query'],
                mode: ResearchMode::Fast,
            ),
        )->result();

        $sources = collect($result->metadata->get('citedPages', []))
            ->map(fn ($page) => "- {$page['title']}: {$page['url']}")
            ->implode("\n");

        return "{$result->report}\n\nSources:\n{$sources}";
    }

    public function schema(JsonSchema $schema): array
    {
        return [
            'query' => $schema->string()
                ->required()
                ->description('The question to research'),
        ];
    }
}

The ->result()

call blocks until the stream finishes and hands back a typed ResearchResult

rather than making you consume events yourself, which keeps the tool's handle

method simple. If you'd rather stream progress back to the agent as it happens, the client also gives you ->each()

and raw iteration, but for a tool call the blocking result is usually what you want.

Wire it into any agent through the tools

method, same as any other tool:

<?php

namespace App\Ai\Agents;

use App\Ai\Tools\WebResearch;
use Laravel\Ai\Contracts\Agent;
use Laravel\Ai\Contracts\HasTools;
use Laravel\Ai\Promptable;

class MarketAnalyst implements Agent, HasTools
{
    use Promptable;

    public function instructions(): string
    {
        return 'You help analyze markets and competitors. Use the research tool whenever you need current information. Always mention your sources.';
    }

    public function tools(): iterable
    {
        return [
            app(WebResearch::class),
        ];
    }
}

Now switch providers all you want:

$response = (new MarketAnalyst)->prompt(
    'What are the current pricing trends for cloud browser automation APIs?',
    provider: [Lab::OpenAI, Lab::Anthropic, Lab::Groq],
);

The agent's ability to research the web doesn't depend on which of those three ends up answering the prompt. The tool is yours, it runs the same regardless of which model called it.

You could build something similar with WebFetch

on a supported provider, pointing it at a specific known URL. But that only works when you already know which page has the answer. /research

is built for the opposite case, a question with no known source, where the value is in picking the right sources, reading them, and synthesizing a single answer with the receipts attached. That's a genuinely different job than fetching one page, and it's the piece the SDK's built-in tools don't attempt.

The Laravel AI SDK's provider independence is one of its best features, right up until you reach for a tool that isn't actually part of that independence. Web access shouldn't be something your agent loses depending on which model answered the prompt. Building it as a real Tool

class backed by an API, rather than leaning on whatever the current provider happens to expose, keeps that promise intact.

If you're building agents with the Laravel AI SDK and want this kind of tool ready to go, juststeveking/tabstack on Packagist is where I'd start.

── more in #developer-tools 4 stories · sorted by recency
── more on @laravel ai sdk 3 stories trending now
sponsored brought to you by zahid.host 4,200+ EU-deployed projects
reading about agents? ship yours in a single git push.

Run your AI side-project on zahid.host

EU-based hosting, git-push deploys, automatic HTTPS, no cold starts. Free tier with a custom domain — perfect for shipping the agent you just read about.

$git push zahid main
Live at https://your-agent.zahid.host
Get free account → Pricing
from €0/mo · no card required
LIVE [news/give-your-laravel-ai…] indexed:0 read:5min 2026-07-16 ·