Back to KB
Difficulty
Intermediate
Read Time
5 min

Backfill Article - 2026-05-07

By Codcompass TeamΒ·Β·5 min read

Decentralized, Autonomous Vacation Booking System with Protolink

Current Situation Analysis

The AI agent landscape is rapidly shifting from monolithic, single-model scripts toward Multi-Agent Systems (MAS) where specialized, autonomous agents collaborate to solve complex workflows. However, traditional MAS frameworks introduce significant architectural friction:

  • Vendor & Runtime Lock-in: Most frameworks tie agents to a specific LLM provider (OpenAI, Anthropic, etc.), enforce rigid transport layers (e.g., gRPC-only or HTTP-only), and restrict execution to specific runtimes or cloud environments.
  • Rigid Orchestration Bottlenecks: Conventional approaches treat agents as isolated functions or force them through centralized orchestrators, creating single points of failure and high latency.
  • Tooling & Communication Constraints: Developers are forced to adopt framework-specific tooling schemes, making it difficult to reuse existing deterministic services or extend communication protocols.
  • Lifecycle & State Management Overhead: Handling agent discovery, memory, authentication, logging, and inference routing manually leads to fragmented codebases and debugging nightmares.

Traditional methods fail because they prioritize framework convenience over architectural flexibility. Agents become tightly coupled to their execution environment, making scaling, interoperability, and vendor migration prohibitively expensive.

WOW Moment: Key Findings

Protolink eliminates framework-induced friction by treating agents as modular, autonomous objects that communicate over a flexible, extensible Agent-to-Agent (A2A) protocol. Unlike base A2A specifications, Protolink allows agents to directly invoke another agent's LLM for reasoning, call tools natively, or define custom communication schemes without rigid orchestration layers.

ApproachSetup ComplexityLLM PortabilityTransport FlexibilityOrchestration LatencyVendor Lock-in
Traditional MAS (Monolithic)High (Hardcoded deps)Low (Single vendor)Low (Fixed transport)High (Central bottleneck)Critical
Protolink Mesh ArchitectureLow (Modular plugins)High (Any LLM/Local/Cloud)High (HTTP/gRPC/Custom)Low (Direct A2A routing)None

Key Findings:

  • Zero Vendor Lock-in: Swap LLMs, transports, or storage backends without rewriting agent logic.
  • Native A2A Extension: Agents can leverage each other's reasoning capabilities and tools directly, bypassing unnecessary serialization overhead.
  • Built-in Observability: Automatic HTTP/CSS/JS status cards expose runtime metrics, agent registration states, and mesh topology without external monitoring stacks.
  • Deterministic + Generative Hybridization: Pure reasoning agents (LLM-only) and deterministic agents (Tool-only) coexist seamlessly in the same mesh.

Core Solution

The vacation booking system implements a four-agent mesh coordinated by a central Registry. Agents communicate via Protolink's standard agent_call protocol over HTTP, enabling local or distributed deployment.

1. Architecture Overview

  • Coordinator Agent: User-facing orchestrator (LLM + Tools). Decomposes requests and delegates tasks.
  • Holiday Advisor: Pure reasoning agent (LLM). Evaluates destinations and travel preferences.
  • Weather Agent: Deterministic agent (Tools). Fetches and processes weather forecast

s.

  • Hotel Agent: Deterministic agent (Tools). Executes booking logic and availability checks.
  • Registry: Central discovery service. Agents register and query the mesh via HTTP transport.

2. Environment & Dependency Setup

Install Protolink (Python β‰₯ 3.11 required):

pip install protolink

3. Execution Context & Async Handling

Protolink relies on asynchronous execution. When running all agents in a single file, wrap the logic in an async def block:

import asyncio
from dotenv import load_dotenv

load_dotenv(".env")

async def main():
  <PUT CODE HERE>
  ...

if __name__ == "__main__":
  asyncio.run(main())

For distributed deployments (separate scripts per agent), use .start(blocking=True) to maintain the runtime lifecycle:

# In separate agent scripts
agent.start(blocking=True)

4. LLM Configuration & API Management

Configure credentials via .env or pass directly to the LLM constructor. Protolink supports multiple providers out-of-the-box:

OPENAI_API_KEY=
ANTHROPIC_API_KEY=
GEMINI_API_KEY=
HF_API_TOKEN=
OLLAMA_URL=
OLLAMA_MODEL=

Direct instantiation example:

from protolink.llms.api import AnthropicLLM

llm = AnthropicLLM(api_key="<YOUR_API_KEY>")

Supported LLM modules:

  • protolink.llms.api: OpenAILLM, AnthropicLLM, GeminiLLM, DeepSeekLLM, GrokLLM
  • protolink.llms.server: OllamaLLM
  • protolink.llms.local: TBD

Custom LLM wrappers can be implemented by overriding call and call_stream methods. Base class reference: protolink/llms/base.py.

5. Registry Initialization & Mesh Discovery

Start the Registry to enable agent discovery and network mapping:

from protolink.discovery import Registry

registry = Registry(transport="http", url="http://localhost:9000")

# Start the Registry simply by using .start()
await registry.start()

Built-in Observability: Starting the Registry or any agent with HTTP transport automatically exposes a monitoring card at /status. Access http://localhost:9000/status in your browser to view real-time mesh topology, agent registration states, and communication health.

6. Agent Communication Flow

All agents register with the Registry and expose an Agent Card containing capability metadata, available tools, and LLM configurations. The Coordinator routes requests using the agent_call protocol, allowing direct tool invocation or LLM delegation across the mesh without intermediate orchestration layers.

(Note: The original guide references a flowchart illustrating the agent_call protocol routing. The mesh operates on direct peer-to-peer HTTP calls after initial Registry discovery.)

Pitfall Guide

  1. Async Context Misalignment: Using await outside an async def block or mixing synchronous and asynchronous runtimes will cause RuntimeError. Always wrap Protolink initialization and agent calls in an async context or use asyncio.run().
  2. Blocking vs Non-Blocking Runtime Management: Running agents in separate scripts without .start(blocking=True) causes the process to exit immediately after initialization. Use blocking mode for standalone services; omit it for Jupyter notebooks or single-file orchestrations.
  3. Environment Variable Resolution Failures: Protolink's LLM constructors fall back to .env variables. If keys are missing or misnamed, initialization fails silently or throws authentication errors. Validate .env placement in the script's working directory or explicitly pass keys via constructor arguments.
  4. Registry Port Conflicts: The default Registry URL (http://localhost:9000) may clash with existing services. Always verify port availability or override the url parameter during Registry instantiation.
  5. Over-Engineering Agent Communication: Attempting to implement custom HTTP routing or message serialization bypasses Protolink's native agent_call protocol. Rely on the built-in discovery and routing mechanisms; only extend communication schemes when base A2A limitations are encountered.
  6. Ignoring Built-in Observability: Deploying without monitoring the /status endpoint leads to blind failures during agent registration or tool invocation. Use the auto-generated HTTP/CSS/JS cards to validate mesh topology and agent health before routing production traffic.

Deliverables

πŸ“ Architecture Blueprint

  • Mesh topology diagram mapping Coordinator β†’ Advisor/Weather/Hotel agents
  • Registry discovery flow and Agent Card schema structure
  • A2A protocol extension points for custom tool/LLM delegation

βœ… Deployment Checklist

  • Python β‰₯ 3.11 environment configured
  • protolink installed via pip or uv
  • .env file populated with target LLM credentials
  • Registry started on available port (default: 9000)
  • Agents registered and verified via /status endpoint
  • Async execution context validated (asyncio.run() or blocking=True)
  • End-to-end agent_call routing tested across mesh

βš™οΈ Configuration Templates

  • .env credential mapping (OpenAI, Anthropic, Gemini, Ollama, HF)
  • LLM constructor patterns (API key injection vs environment fallback)
  • Registry & Agent startup snippets (single-file async vs distributed blocking)
  • Custom LLM wrapper skeleton (call/call_stream override template)