Skip to content

Architecture

Dusan Milicevic edited this page Apr 24, 2026 · 2 revisions

Architecture

Contract-driven agent platform for travel distribution, with pipeline validation and LLM orchestration.

High-Level View

graph TB
    subgraph "LLM Layer"
        LLM["Claude / any tool-calling LLM"]
    end

    subgraph "Agent Layer (75 agents)"
        REF["Stage 0 Reference (7)"]
        SEARCH["Stage 1 Search (9)"]
        PRICE["Stage 2 Pricing (7)"]
        BOOK["Stage 3 Booking (8)"]
        TICKET["Stage 4 Ticketing (5)"]
        EXCH["Stage 5 Exchange (6)"]
        SETTLE["Stage 6 Settlement (6)"]
        RECON["Stage 7 Reconciliation (6)"]
        TMC["Stage 8 TMC (5)"]
        PLAT["Stage 9 Platform (9)"]
        LODGE["Stage 20 Lodging (7)"]
    end

    subgraph "Pipeline Infrastructure"
        TB["Tool Bridge<br/>agentToTool()"]
        PV["Pipeline Validator<br/>6 gates"]
        CR["Capability Registry"]
        ES["EventStore"]
    end

    subgraph "Adapter Layer"
        AMADEUS["Amadeus GDS"]
        SABRE["Sabre GDS"]
        NAV["Navitaire LCC"]
        TP["TripPro Aggregator"]
        DUFFEL["Duffel NDC"]
        HAIP["HAIP Hotel"]
    end

    subgraph "Suppliers"
        S1["Airlines"]
        S2["Hotels"]
    end

    LLM -->|tool_use| TB
    TB -->|runAgent| PV
    PV -->|execute| REF & SEARCH & PRICE & BOOK & TICKET & EXCH & SETTLE & RECON & TMC & PLAT & LODGE
    PV -->|append| ES
    SEARCH & BOOK --> CR
    CR --> AMADEUS & SABRE & NAV & TP & DUFFEL & HAIP
    AMADEUS & SABRE & NAV & TP & DUFFEL --> S1
    HAIP --> S2
Loading

Pipeline Validator — Gate Sequence

Every agent invocation runs through six gates. Gates 1–4 run before execute(), gates 5–6 run after.

sequenceDiagram
    participant LLM
    participant Bridge as Tool Bridge
    participant PV as Pipeline Validator
    participant Agent
    participant ES as EventStore

    LLM->>Bridge: tool_use(input)
    Bridge->>PV: runAgent(session, agentId, input)

    Note over PV: Gate 1 — Intent Lock
    PV->>PV: checkIntentRelevance & drift

    Note over PV: Gate 2 — Schema In
    PV->>PV: inputSchema.safeParse(input)

    Note over PV: Gate 3 — Semantic In
    PV->>PV: contract.validate(input, ctx)

    Note over PV: Gate 4 — Cross-Agent
    PV->>PV: checkConsistency(input, priorOutputs)

    PV->>Agent: execute(input)
    Agent-->>PV: AgentOutput

    Note over PV: Gate 5 — Schema Out + Confidence
    PV->>PV: outputSchema.safeParse & confidence >= floor

    Note over PV: Gate 6 — Action Classification
    PV->>PV: irreversible mutations require approval

    PV->>ES: append(agent.executed)
    PV-->>Bridge: RunAgentResult
    Bridge-->>LLM: tool_result
Loading
Gate Runs Purpose
1 Intent Lock before execute Agent is relevant to the session intent; no drift
2 Schema In before execute Zod safeParse on input against contract.inputSchema
3 Semantic In before execute Domain checks via contract.validate()
4 Cross-Agent before execute Input fields consistent with prior agent outputs
5 Schema Out + Confidence after execute Output structure valid; output.confidence >= threshold
6 Action Classification after execute Irreversible mutations gated behind approval

Tool Bridge — Agent to LLM

The tool bridge converts a contracted agent into an LLM-callable tool. No hand-written JSON schemas.

graph LR
    subgraph "Contract"
        AC["AgentContract<br/>inputSchema<br/>outputSchema<br/>actionType<br/>validate()"]
    end

    subgraph "Bridge"
        ATT["agentToTool()"]
    end

    subgraph "ToolDefinition"
        TD["name (AGENT_TOOL_NAMES)<br/>description<br/>inputSchema: Zod<br/>execute()"]
    end

    subgraph "Anthropic API"
        AT["Anthropic.Tool<br/>input_schema: JSON Schema"]
    end

    AC --> ATT --> TD -->|zodToJsonSchema| AT
Loading

The agent loop (@otaip/core/agent-loop) drives the Anthropic Messages API, converts each tool_use block into a runAgent() call against the pipeline validator, then returns tool_result blocks to the model.

EventStore

Every agent execution is appended to the EventStore. Governance agents (9.6–9.9) query the store to audit the platform.

graph TB
    subgraph "Event types"
        AE["agent.executed"]
        RD["routing.decided"]
        RO["routing.outcome"]
        BC["booking.completed"]
        BF["booking.failed"]
        AH["adapter.health"]
    end

    subgraph "EventStore"
        ES["append(event)<br/>query(filter)<br/>aggregate(metric, window)"]
    end

    subgraph "Implementations"
        IM["InMemoryEventStore (ships with core)"]
        PG["PostgresEventStore (planned)"]
    end

    AE & RD & RO & BC & BF & AH --> ES --> IM
    ES -.-> PG
Loading

Capability Registry

The capability registry maps abstract functions (search, price, book, ticket, refund) to concrete channels. Each adapter registers a ChannelCapabilityManifest:

  • channelId, channelType (gds | ndc | lcc | hospitality | aggregator)
  • supportedCarriers, supportedFunctions
  • reliabilityScore, latencyScore, costScore
  • supportsOrders (when AIDM 24.1 order operations are implemented)

The GdsNdcRouter (3.1) reads the registry to route a booking to the best channel for each carrier.

Package Structure — 16 Workspaces

packages/
  core/                   @otaip/core — Agent interface, errors, pipeline validator,
                          tool bridge, EventStore, agent loop, OfferEvaluator (1.9)
  connect/                @otaip/connect — ConnectAdapter interface, BaseAdapter,
                          Amadeus, Sabre, Navitaire, TripPro, HAIP
  adapters/duffel/        @otaip/adapter-duffel — standalone Duffel NDC adapter
  cli/                    @otaip/cli — command-line interface
  agents/
    reference/            @otaip/agents-reference — Stage 0
    search/               @otaip/agents-search — Stage 1
    pricing/              @otaip/agents-pricing — Stage 2
    booking/              @otaip/agents-booking — Stage 3
    ticketing/            @otaip/agents-ticketing — Stage 4
    exchange/             @otaip/agents-exchange — Stage 5
    settlement/           @otaip/agents-settlement — Stage 6
    reconciliation/       @otaip/agents-reconciliation — Stage 7
    lodging/              @otaip/agents-lodging — Stage 20
  agents-tmc/             @otaip/agents-tmc — Stage 8
  agents-platform/        @otaip/agents-platform — Stage 9
examples/
  ota/                    @otaip/ota-example — reference OTA
demo/                     pipeline demos

All 16 packages typecheck clean with TypeScript strict mode.

Design Principles

  1. Contract-first. Agent behavior is declared as an AgentContract with Zod schemas. No hand-written JSON schemas.
  2. Pipeline-validated. Six gates run around every execute() call. The LLM cannot hallucinate offer IDs, change destinations mid-flow, or ticket without approval.
  3. Event-sourced observability. Every execution is logged with duration, confidence, and gate results for governance agents to analyze.
  4. Adapter-agnostic. Agents talk to a ConnectAdapter / DistributionAdapter interface. Swapping suppliers does not touch agent code.
  5. Domain-safe. No invented domain logic. Travel edge cases are surfaced as DOMAIN_QUESTION comments, never guessed.

See also

Clone this wiki locally