Skip to main content
Linkup is a production-grade web search API for AI. In a Gradium voice agent, Linkup acts as the live web layer: the caller speaks a request, the agent turns it into a focused query, Linkup returns current web results with sources and images, and Gradium speaks the answer back while the sources stream to the screen.

Linkup

Explore Linkup’s search, fetch, and research APIs.

Hotel booking voice agent

See a Gradbot demo that books hotels using live web search.
A voice search agent built on Gradium and Linkup follows this loop:
  1. The caller asks a spoken question, such as “Find me a boutique hotel in Lisbon under 150 euros a night.”
  2. Gradium Speech-to-Text transcribes the request in real time.
  3. The agent calls a search tool with a focused query built from the caller’s spoken preferences.
  4. Linkup returns ranked results with titles, sources, snippets, and images.
  5. The agent filters, compares, and summarizes the results.
  6. Gradium Text-to-Speech streams the answer back to the caller.
This pattern lets callers control web search without typing. They can refine the search conversationally, ask for tradeoffs, compare sources, or narrow results by criteria like budget, location, style, or dates.

Core wiring

The hotel demo exposes search as voice-agent tools. Gradium handles the live STT and TTS session; the agent decides when to call search_hotels and get_hotel_details.

Search tool definition

gradbot.ToolDef(
    name="search_hotels",
    description=(
        "Search the web for available hotels in a destination. Takes some "
        "time to search. Keep chatting with the caller about the destination "
        "while waiting for results! IMPORTANT: Always include the caller's "
        "preferences (budget, style, etc.) in the preferences field so the "
        "search is targeted."
    ),
    parameters_json=json.dumps({
        "type": "object",
        "properties": {
            "destination": {
                "type": "string",
                "description": "The city or destination to search hotels in",
            },
            "preferences": {
                "type": "string",
                "description": (
                    "Caller's requirements: budget range, style, amenities, "
                    "etc. (e.g. 'under 100 euros per night, boutique style')"
                ),
            },
        },
        "required": ["destination"],
    }),
)

Calling the Linkup Search API

The demo uses the linkup-sdk package. Because the client is synchronous, the handler runs each search in a thread pool so it does not block the voice session. include_images=True returns image results alongside the text sources.
import asyncio
from linkup import LinkupClient

linkup_client = LinkupClient(api_key=os.environ["LINKUP_API_KEY"])

async def do_search(query: str, include_images: bool = True) -> dict:
    loop = asyncio.get_running_loop()
    result = await loop.run_in_executor(
        None,
        lambda: linkup_client.search(
            query=query,
            depth="standard",
            output_type="searchResults",
            include_images=include_images,
        ),
    )

    sources, images = [], []
    for item in result.results or []:
        if item.type == "image":
            images.append({"title": item.name, "url": item.url})
        else:
            sources.append({
                "title": item.name,
                "href": item.url,
                "body": item.content[:300] if item.content else "",
            })

    answer = "\n".join(f"- {s['title']}: {s['body']}" for s in sources[:5])
    return {"answer": answer, "sources": sources, "images": images}
Each text result carries a name, url, and content; image results carry a name and url. Two parameters shape the search:
  • depth trades latency for thoroughness. fast is sub-second keyword search for latency-critical paths like voice, standard is single-iteration agentic search at roughly one to three seconds and suits most agent lookups, and deep runs up to ten iterations at five to thirty seconds for complex, multi-source investigations. The demo uses standard.
  • output_type shapes the return value. searchResults returns ranked URLs and snippets for the agent to reason over, sourcedAnswer returns a generated answer with citations, and structured returns JSON matching a schema you provide. The demo uses searchResults so the agent can filter and summarize the sources itself.

Returning results to the agent

The tool handler streams the sources and images to the browser, swaps in a prompt built from the search results, and sends a compact summary back to the agent along with instructions for how to speak the answer. Keeping the payload small keeps the LLM leg of the turn fast.
async def handle_search_hotels(destination, preferences, tool_handle, input_handle, websocket):
    query = f"hotels in {destination} {preferences or ''} with star ratings, prices per night, and brief descriptions"
    result = await do_search(query)

    # Stream source cards and images to the frontend
    await websocket.send_json({
        "type": "search_results",
        "query": f"Hotels in {destination}",
        "results": result["sources"],
        "images": result.get("images", []),
    })

    await tool_handle.send(json.dumps({
        "success": True,
        "destination": destination,
        "answer": result["answer"],
        "sources": result["sources"],
        "message": (
            "Hotel search results are ready. Present the top options based on "
            "the search results, highlighting star ratings, price ranges, and "
            "key features. Ask which one interests the caller."
        ),
    }))

Agent session config

The session config wires the tools into a live Gradium voice session.
def make_config(instructions: str) -> gradbot.SessionConfig:
    return gradbot.SessionConfig(
        voice_id="cLONiZ4hQ8VpQ4Sz",
        instructions=instructions,
        language=gradbot.Lang.En,
        tools=build_tools(),
        silence_timeout_s=0.0,
    )

await gradbot.websocket.handle_session(
    websocket,
    on_start=on_start,
    on_config=on_config,
    on_tool_call=handle_tool_call,
)

Keep the voice loop fast

Latency is what makes voice search feel magical or broken. The demo applies a few rules worth copying:
  • Search off the event loop. The Linkup client is synchronous, so run it in a thread pool with run_in_executor to avoid blocking audio while a query is in flight.
  • Match depth to the turn. The demo uses standard depth and covers the wait with conversation. For lookups that need to land inside a conversational pause, depth="fast" returns sub-second keyword results; reserve deep for research-style questions where a few extra seconds is acceptable.
  • Cover the wait with conversation. Prompt the agent to keep chatting about the destination while the search runs, so the caller never hears dead air.
  • Cap and truncate results. A handful of sources with snippets trimmed to about 300 characters give the LLM enough to answer without inflating the prompt.
  • Stream sources to the screen. Send source cards and images to the browser as results arrive so the caller sees what the agent is talking about.
  • Handle failures in the agent’s voice. If a search fails, return an empty result and tell the agent to say it could not reach the web right now, rather than letting the model guess.

Authentication

Get an API key from the Linkup dashboard. Pass it to the LinkupClient or set it as an environment variable alongside your Gradium key:
VariablePurpose
LINKUP_API_KEYLinkup search key
GRADIUM_API_KEYGradium voice (STT and TTS)

Why use Linkup with Gradium?

  • Fresh answers in live voice sessions: give Gradium agents access to current web results without making callers leave the conversation.
  • Search that follows spoken constraints: turn natural-language preferences like budget, location, style, or dates into focused Linkup queries.
  • Sources and images together: results come back as clean structured data with text sources and images, ready to summarize, speak, and stream to the screen.
  • Grounded spoken answers: the agent answers from live web results instead of stale model memory, and can cite the source naturally.

Demo

The hotel booking voice agent shows the full pattern: a FastAPI app that runs a Gradbot session, walks the caller through choosing a destination, hotel, and room, and grounds each step in live Linkup search. Use it as a reference for building your own instant voice search experience.