Gateway API

The @trikhub/gateway package is the runtime for loading and routing messages to triks. Use it directly when integrating with frameworks other than LangChain, or when you need full control over the routing lifecycle.

For LangChain/LangGraph projects, see the LangChain integration which wraps this API with a convenient enhance() function.

Installation

npm install @trikhub/gateway

Quick Start

import { TrikGateway } from '@trikhub/gateway'; // Create and initialize gateway const gateway = new TrikGateway(); await gateway.initialize(); // Load triks from .trikhub/config.json await gateway.loadTriksFromConfig(); // Route a user message const sessionId = 'user-123'; const result = await gateway.routeMessage('Find me AI articles', sessionId); switch (result.target) { case 'main': // No active handoff -- send to your main agent // result.handoffTools contains available handoff tool definitions break; case 'trik': // Active handoff -- trik responded // result.response.message is what to show the user break; case 'transfer_back': // Trik transferred back -- show result.message to user // Inject result.summary into main agent's history break; case 'force_back': // User typed /back -- inject result.summary into history break; }

Loading Triks

From Config File

The recommended approach. Loads triks listed in .trikhub/config.json:

const gateway = new TrikGateway(); await gateway.initialize(); const manifests = await gateway.loadTriksFromConfig({ configPath: '.trikhub/config.json', // optional, this is the default baseDir: process.cwd(), // optional }); console.log(`Loaded ${manifests.length} triks`);

The config file is a simple JSON file:

{ "triks": [ "@molefas/article-search", "@acme/weather" ] }

The gateway resolves each trik by looking in node_modules first, then falling back to .trikhub/triks/ for cross-language triks.

Manual Loading

Load a single trik from a file path:

const gateway = new TrikGateway(); await gateway.initialize(); const manifest = await gateway.loadTrik('./my-triks/article-search');

From Directory

Load all triks found in a directory (supports scoped structure):

const manifests = await gateway.loadTriksFromDirectory('~/.trikhub/triks');

Message Routing

The routeMessage() method is the heart of the gateway. It handles the full routing lifecycle:

const result = await gateway.routeMessage(message, sessionId);

Route Results

The result is a discriminated union based on the target field:

RouteToMain

No active handoff. The message should be sent to your main agent.

interface RouteToMain { target: 'main'; handoffTools: HandoffToolDefinition[]; }

The handoffTools array contains definitions for all loaded conversational triks. Pass these to your agent framework so the agent can initiate handoffs.

RouteToTrik

An active handoff is in progress. The gateway already sent the message to the trik and received a response.

interface RouteToTrik { target: 'trik'; trikId: string; response: TrikResponse; sessionId: string; }

Show response.message to the user. The handoff remains active — the next message will also route to this trik.

RouteTransferBack

The trik signaled that it is done and wants to transfer the conversation back to the main agent.

interface RouteTransferBack { target: 'transfer_back'; trikId: string; message: string; // Show to user summary: string; // Inject into main agent's history sessionId: string; }

RouteForceBack

The user typed /back to force a transfer-back.

interface RouteForceBack { target: 'force_back'; trikId: string; message: string; // Empty string summary: string; // Inject into main agent's history sessionId: string; }

Starting Handoffs

When your main agent calls a talk_to_<trik> tool, use startHandoff() to initiate the handoff:

const result = await gateway.startHandoff(trikId, context, sessionId);

This creates a handoff session and routes the initial context message to the trik. The result is either RouteToTrik (trik responded, handoff active) or RouteTransferBack (trik completed immediately).

Tool Definitions

Handoff Tools

Get tool definitions for all loaded conversational triks:

const handoffTools = gateway.getHandoffTools(); for (const tool of handoffTools) { console.log(`${tool.name}: ${tool.description}`); // tool.inputSchema is a JSON Schema for the tool's input }

Each handoff tool has:

  • nametalk_to_<trik_id> (normalized)
  • description — from the trik’s agent.handoffDescription
  • inputSchema — expects a context string

Exposed Tools

Get tool definitions from all loaded tool-mode triks:

const exposedTools = gateway.getExposedTools(); for (const tool of exposedTools) { console.log(`${tool.toolName} (from ${tool.trikId}): ${tool.description}`); // tool.inputSchema, tool.outputSchema, tool.outputTemplate }

Each exposed tool has:

  • trikId — which trik it belongs to
  • toolName — the tool’s name
  • description — what the tool does
  • inputSchema — JSON Schema for input validation
  • outputSchema — JSON Schema for output validation
  • outputTemplate — template string for formatting output

Executing Exposed Tools

Execute a tool-mode trik’s tool directly:

const result = await gateway.executeExposedTool( '@acme/weather', // trik ID 'getWeather', // tool name { city: 'London' } // input (validated against inputSchema) ); // result is a string formatted via the outputTemplate console.log(result); // "Weather in London: 12C, cloudy, humidity 78%"

The gateway validates input against inputSchema, calls the trik’s executeTool() method, validates output against outputSchema, strips undeclared properties, and fills the outputTemplate with the validated output.

Gateway Configuration

const gateway = new TrikGateway({ // Restrict which triks can be loaded allowedTriks: ['@molefas/article-search'], // Directory for auto-discovery of installed triks triksDirectory: '~/.trikhub/triks', // Custom config store for trik secrets configStore: myConfigStore, // Custom storage provider for persistent trik data storageProvider: myStorageProvider, // Custom session storage for handoff sessions sessionStorage: mySessionStorage, // Skip config validation (useful for listing triks) validateConfig: false, // Maximum turns per handoff before auto-transfer-back maxTurnsPerHandoff: 20, });

Querying Loaded Triks

// List all loaded trik IDs const trikIds = gateway.getLoadedTriks(); // Check if a specific trik is loaded const isLoaded = gateway.isLoaded('@molefas/article-search'); // Get a trik's manifest const manifest = gateway.getManifest('@molefas/article-search'); // Unload a trik gateway.unloadTrik('@molefas/article-search'); // Check active handoff state const handoff = gateway.getActiveHandoff(); if (handoff) { console.log(`Active handoff: ${handoff.trikId} (${handoff.turnCount} turns)`); }

Error Handling

try { const result = await gateway.routeMessage(message, sessionId); // Handle result based on target... } catch (error) { // Gateway-level errors: // - Trik not loaded // - Manifest validation failed // - Config file not found console.error('Gateway error:', error); }

If a trik throws an error during a handoff, the gateway catches it and returns a RouteTransferBack with the error as the summary. The handoff is automatically ended.

If a handoff exceeds maxTurnsPerHandoff (default: 20), the gateway automatically transfers back.

Next Steps