LangChain / LangGraph Integration

TrikHub provides a first-class LangChain adapter that wraps your LangGraph agent with handoff routing. The adapter converts trik definitions into LangChain DynamicStructuredTool instances and manages the full handoff lifecycle.

Quick Start

The simplest way to integrate is with enhance() and a createAgent factory:

import { createReactAgent } from '@langchain/langgraph/prebuilt'; import { ChatOpenAI } from '@langchain/openai'; import { enhance } from '@trikhub/gateway/langchain'; const model = new ChatOpenAI({ model: 'gpt-4o-mini' }); const app = await enhance(null, { createAgent: (trikTools) => createReactAgent({ llm: model, tools: [...myTools, ...trikTools] }), }); const response = await app.processMessage('Find me some AI articles'); console.log(response.message); // What to show the user console.log(response.source); // "main", a trik ID, or "system"

enhance() does the following:

  1. Creates a TrikGateway and loads triks from .trikhub/config.json
  2. Generates handoff tools (talk_to_<trik>) for each conversational trik
  3. Calls your createAgent factory with trik tools, building the agent
  4. Intercepts handoff tool calls from the agent and routes them through the gateway
  5. Manages per-session message history and injects transfer-back summaries
  6. Automatically rebuilds the agent when triks are installed or uninstalled at runtime

The enhance() API

import { enhance } from '@trikhub/gateway/langchain'; import type { EnhancedAgent, EnhanceOptions } from '@trikhub/gateway/langchain'; const app: EnhancedAgent = await enhance(agent, options);

The first argument is either a pre-built agent or null when using createAgent.

Options

OptionTypeDescription
createAgent(trikTools: DynamicStructuredTool[]) => InvokableAgentFactory that builds the agent with trik tools included. Agent is rebuilt automatically when triks change. (Recommended)
gatewayTrikGatewayConfigGateway configuration (triks directory, config store, etc.)
configLoadFromConfigOptionsConfig file loading options (custom path, base dir)
gatewayInstanceTrikGatewayPre-built gateway instance (skips creating a new one)
debugbooleanEnable debug logging for handoff events
verbosebooleanEnable verbose logging with full message history dumps

EnhancedAgent

The object returned by enhance():

Property / MethodTypeDescription
processMessage(message, sessionId?)Promise<EnhancedResponse>Process a user message through the routing layer
gatewayTrikGatewayAccess the underlying gateway
getLoadedTriks()string[]Get the list of loaded trik IDs

EnhancedResponse

FieldTypeDescription
messagestringThe message to show the user
sourcestringWhere the response came from: "main", a trik ID, or "system"

Advanced: Manual Tool Binding

If you need direct access to trik tools — for example, to inspect them or apply custom logic — use the exported helper functions. Note that the createAgent factory approach above is preferred, as it handles dynamic reload automatically.

import { TrikGateway } from '@trikhub/gateway'; import { enhance, getHandoffToolsForAgent, getExposedToolsForAgent, } from '@trikhub/gateway/langchain'; // Set up gateway manually const gateway = new TrikGateway(); await gateway.initialize(); await gateway.loadTriksFromConfig(); // Get trik tools as LangChain DynamicStructuredTool instances const handoffTools = getHandoffToolsForAgent(gateway); const exposedTools = getExposedToolsForAgent(gateway); // Create agent with all tools const agent = createReactAgent({ llm: model, tools: [...myTools, ...handoffTools, ...exposedTools], }); // Wrap with handoff routing, passing the pre-built gateway const app = await enhance(agent, { gatewayInstance: gateway });

Note: With a pre-built agent, the agent is not automatically rebuilt when triks change at runtime. Use the createAgent factory for dynamic reload support.

getHandoffToolsForAgent(gateway)

Returns an array of DynamicStructuredTool instances, one per loaded conversational trik. Each tool is named talk_to_<trik_id> and accepts a single context parameter describing what the user needs.

These tools are placeholders — they do not execute directly. The enhance() wrapper intercepts calls to handoff tools and routes them through the gateway’s startHandoff() method.

getExposedToolsForAgent(gateway)

Returns an array of DynamicStructuredTool instances, one per tool declared by tool-mode triks. These tools execute directly by calling gateway.executeExposedTool(), which validates input/output and returns a template-filled string.

Tool Naming

Handoff Tools (conversational mode)

The trik’s id is normalized into the tool name:

Trik IDHandoff Tool Name
@demo/article-searchtalk_to_demo_article_search
@acme/weathertalk_to_acme_weather

The tool description comes from the trik’s agent.handoffDescription field in the manifest.

Exposed Tools (tool mode)

Tool-mode trik tools are exposed using their declared tool name directly:

Trik IDTool Name in ManifestExposed As
@acme/weathergetWeathergetWeather
@acme/weathergetForecastgetForecast

The gateway ensures tool names are unique across all loaded tool-mode triks — duplicate names will cause a load error.

Handoff Flow

Here is what happens when the main agent decides to call a handoff tool:

1. Main agent calls talk_to_demo_article_search({ context: "User wants AI articles" }) 2. enhance() intercepts the tool call 3. gateway.startHandoff("demo/article-search", context, sessionId) is called 4. The trik agent receives the context and responds 5. If the trik is still working: response goes to the user, session stays active 6. Next user message -> gateway.routeMessage() sends it directly to the trik 7. When the trik sets transferBack: true, the session ends 8. A session summary is injected into the main agent's message history 9. Future messages go back to the main agent

Users can force a transfer-back at any time by typing /back.

Debug Logging

Enable debug logging to trace handoff events:

const app = await enhance(null, { createAgent: (trikTools) => createReactAgent({ llm: model, tools: trikTools }), debug: true, });

This logs handoff starts, transfer-backs, and routing decisions to the console with a [trikhub] prefix.

For full message dumps on each agent invocation, use verbose mode:

const app = await enhance(null, { createAgent: (trikTools) => createReactAgent({ llm: model, tools: trikTools }), verbose: true, });

Next Steps