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/gatewayQuick 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:
name—talk_to_<trik_id>(normalized)description— from the trik’sagent.handoffDescriptioninputSchema— expects acontextstring
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 totoolName— the tool’s namedescription— what the tool doesinputSchema— JSON Schema for input validationoutputSchema— JSON Schema for output validationoutputTemplate— 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
- See the LangChain integration for a higher-level API
- Learn how to create your own triks