Developer walkthrough

LangChain or a custom agent framework? Run the same tool in both

Run the same local tool with a custom dispatcher and LangChain, then compare validation, approval, persistence and maintenance responsibilities.

As of 2026-10-10

One call, four checks

Start with a local allocation preview. It accepts a ticker and percentage, validates them, and returns a receipt with the original call ID. The SPY 20% input is a teaching fixture, not a trading recommendation or a NexusTrade portfolio request.

Proposed call passes tool, permission and argument checks before a correlated receipt returns.
Executable local fixture. No model, market data, saved portfolio or orders.

Run the example

  1. 1. Save the files together

    Download dispatcher.mjs and dispatcher.test.mjs into an empty folder. Use Node.js 24, the version used to verify this example.

  2. 2. Run the scripted calls

    Run node dispatcher.mjs. You should see one successful preview, one invalid percentage and one unknown tool.

  3. 3. Test the failure paths

    Run node --test dispatcher.test.mjs. Tests cover duplicate IDs, concurrent reuse, unsupported fields, denied writes, exhausted budget and redacted errors.

Shell
node dispatcher.mjs
node --test dispatcher.test.mjs

The actual local output

These receipts were produced by running the downloadable fixture. call_3 fails at tool lookup: place_order is deliberately absent from the registry. A registered preview with permission write fails with PERMISSION_DENIED.

JSON
{"id":"call_1","status":"ok","result":{"symbol":"SPY","allocationPercent":20,"persisted":false}}
{"id":"call_2","status":"error","code":"INVALID_ARGUMENTS"}
{"id":"call_3","status":"error","code":"UNKNOWN_TOOL"}

Run the LangChain adapter without a model

The adapter uses LangChain's tool schema and invoke method around the same handler. The dispatcher retains the same permission, budget and receipt policy, so the comparison changes tool registration rather than the domain task. No createAgent call or model key is needed.

Verified locally with langchain 1.5.16, zod 4.6.5 and Node.js 24.21.0. The adapter returned the three receipts shown above.

  1. 1. Add the adapter and dependency files

    Keep dispatcher.mjs, its tests, langchain-adapter.mjs and its tests together. Download package.json and package-lock.json into the same folder.

  2. 2. Install the frozen dependency set

    Run npm ci --ignore-scripts in that folder. The lockfile preserves the dependency tree used for the verified run.

  3. 3. Run and compare

    Run the adapter and both test files using the commands below. Its three receipts should match the custom dispatcher output.

Shell
npm ci --ignore-scripts
node langchain-adapter.mjs
node --test dispatcher.test.mjs langchain-adapter.test.mjs

The adapter code

JavaScript
import { pathToFileURL } from "node:url";
import { tool } from "langchain";
import * as z from "zod";
import { demo, validateDraft } from "./dispatcher.mjs";
export const preview = tool(validateDraft, {
  name: "preview_allocation",
  description: "Validate a local allocation teaching fixture without saving it.",
  schema: z.object({
    symbol: z.string().regex(/^[A-Z]{1,5}$/),
    allocationPercent: z.number().finite().gt(0).lte(100),
  }).strict(),
});
// Same domain validator preserves the tutorial's error receipt contract.
if (process.argv[1] && import.meta.url === pathToFileURL(process.argv[1]).href) await demo(async args => {
  validateDraft(args);
  return preview.invoke(args);
});

What the library gives you

LangChain documents schema-defined tools, an agent loop and middleware. Its human review middleware can pause a proposed call and resume after approval, editing or rejection; that flow requires a checkpointer. These are supported alternatives to implementing those mechanisms yourself.

The local run tests tool invocation only. It does not measure model quality, provider latency, checkpoint recovery or production throughput. Both implementations produce the same fixture receipts because they share the same domain checks.

Choose around the work you need

For a new agent needing approval pauses and conversation persistence, start by evaluating the library's existing runtime. For an established product with its own execution ledger and domain handlers, a narrow adapter may preserve those contracts. NexusTrade's internal implementation is one such product-specific design, not a performance benchmark against LangChain.

A small fixed set of local toolsSchema tools reduce registration work.A small dispatcher can be easy to inspect.
Pause and resume for human reviewUse documented middleware plus durable checkpointing.Build and test persisted state, decisions and replay rules.
Existing domain approvals and operation IDsConnect those controls through tools and middleware.Reuse domain controls directly; keep transport separate.
Multiple model providers and agent orchestrationUse the documented integrations and agent runtime.Own adapters, tool-result formats, limits and upgrades.

Keep the same production boundaries

Tool schema validation checks shape, not account authority. Derive permissions from the authenticated server, even when a model proposes a valid request. The tutorial permission value is a fixture only.

Checkpointing does not by itself make external writes exactly once. Give side effects durable operation identities and read their status before retrying. A process-local Map is only a local duplicate guard.

If an installation fails, use the pinned package versions shown here and Node.js 24. If an input fails validation, correct the request rather than removing the strict schema. Connect a provider only after these local paths pass; that later step can incur model charges.

Continue exploring