### Install @nmnmcc/toolbox
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Install the library along with its peer dependencies, zod and openai.
```bash
npm install @nmnmcc/toolbox zod openai
```
--------------------------------
### Create Simple Logging Middleware
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Example of a custom middleware that logs the start and end times of an LLM function call. It wraps the `next` function to measure execution duration.
```typescript
import type { LanguageModelMiddleware } from "@nmnmcc/toolbox";
const simple_logger = (): LanguageModelMiddleware<
Input,
Output
> => {
return async (context, next) => {
console.log(`[${context.description.name}] Starting call`);
const start = Date.now();
const result = await next(context);
const elapsed = Date.now() - start;
console.log(`[${context.description.name}] Completed in ${elapsed}ms`);
return result;
};
};
```
--------------------------------
### Define LLM-Powered Function with Middleware
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Use the `describe` function to create an LLM-powered function with a middleware chain. This example includes initializers, logging, retries, and finalizers.
```typescript
import {
z
} from "zod";
import {
describe
} from "@nmnmcc/toolbox";
import {
initializer
} from "@nmnmcc/toolbox/initializers/initializer";
import {
finalizer
} from "@nmnmcc/toolbox/finalizers/finalizer";
import {
retry
} from "@nmnmcc/toolbox/middlewares/retry";
import {
logging
} from "@nmnmcc/toolbox/middlewares/logging";
const summarize = describe(
{
name: "summarize",
description: "Summarize the provided text",
input: z.object({
text: z.string().describe("Text to summarize")
}),
output: z.object({
summary: z.string().describe("A concise summary")
}),
model: "gpt-4o",
temperature: 0.7,
},
[
initializer(
"You are a helpful assistant that summarizes text concisely.",
),
logging(),
retry(2),
finalizer(),
],
);
const result = await summarize({ text: "Long article text goes here..." });
console.log(result.summary);
```
--------------------------------
### Create Response Transformation Middleware
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Example of a custom middleware that modifies the LLM's response by adding a prefix to the content. It accesses and mutates the message content within the context's history.
```typescript
import type { LanguageModelMiddleware } from "@nmnmcc/toolbox";
const add_prefix = (
prefix: string,
): LanguageModelMiddleware => {
return async (context, next) => {
const result = await next(context);
// Modify the response content
const message = result.history.at(-1)?.[1].at(-1)?.choices[0]?.message;
if (message?.content) {
message.content = prefix + message.content;
}
return result;
};
};
```
--------------------------------
### Initialize and Use Stateful TodoList Middleware
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Create a stateful `todoList` middleware instance with initial tasks. This middleware can be piped into an LLM agent to manage a TODO list, injecting the current list into the system prompt and enabling the model to add, complete, or delete tasks via a `manage_todo` tool. State is preserved across multiple invocations.
```typescript
import { duplex } from "@pipechain/core"
import { openai } from "@pipechain/openai"
import { react, todoList } from "@pipechain/openai"
import type { TodoItem } from "@pipechain/openai"
const initialTodos: TodoItem[] = [
{ id: "abc", task: "Write unit tests", status: "pending" },
{ id: "def", task: "Deploy to staging", status: "pending" },
]
// todoList() is stateful — create once and reuse across calls
const todoMiddleware = todoList(initialTodos)
const taskAgent = duplex(openai({ model: "gpt-4o" }))
.pipe(todoMiddleware)
.pipe(react({ tools: [] })) // react handles the injected manage_todo tool
.pipe(async (instruction: string, next) =>
next({ messages: [{ role: "user", content: instruction }] }),
)
await taskAgent("Mark the unit tests task as complete.")
// System prompt now includes:
// "Current TODO List:
// - [x] Write unit tests (ID: abc)
// - [ ] Deploy to staging (ID: def)"
await taskAgent("Add a new task: Review pull requests")
// TODO list gains a new pending item
```
--------------------------------
### Type Signature for Describe Function
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Illustrates the type signatures for the `describe` function, differentiating between regular functions and LLM-powered functions with middleware.
```typescript
type Description = {
name: string;
description: string;
input: Input; // Zod schema
output: Output; // Zod schema
};
type LanguageModelDescription = Description & {
model: string; // OpenAI model name
temperature?: number;
max_tokens?: number;
// ... any OpenAI ChatCompletionCreateParams
client?: OpenAI; // Optional custom OpenAI client
};
// For regular functions
function describe(
description: Description,
implementation: (input: z.input) => Promise>,
): Described;
// For LLM-powered functions
function describe(
description: LanguageModelDescription,
imports: [initializer, ...middlewares, finalizer],
): Described;
```
--------------------------------
### Deferred OpenAI Chat Completion Factory
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Wraps `chat.completions.create` to separate static configuration from dynamic parameters. Returns an `IO` function for per-call arguments like messages. Supports custom OpenAI clients.
```typescript
import { duplex } from "@pipechain/core"
import { openai } from "@pipechain/openai"
import OpenAI from "openai"
// Bind model config once; messages are provided per call
const gpt4 = openai({ model: "gpt-4o", temperature: 0.7 })
const response = await gpt4({
messages: [{ role: "user", content: "What is 2 + 2?" }],
})
console.log(response.choices[0].message.content) // "4"
// Use a custom client (e.g., for Azure or testing)
const customClient = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
const gpt4Custom = openai({ model: "gpt-4o", client: customClient })
// Compose into a full pipeline
const echo = duplex(openai({ model: "gpt-4o-mini" })).pipe(
async (input: string, next) =>
next({
messages: [
{ role: "system", content: "Echo the user message back." },
{ role: "user", content: input },
],
}),
)
console.log(await echo("Hello, World!"))
```
--------------------------------
### Create a simplex pipeline with @pipechain/core
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Use `simplex` for one-way data flow pipelines where steps transform data sequentially. Steps are prepended, suitable for data transformation chains.
```typescript
import { simplex } from "@pipechain/core"
const toUpperCase = async (str: string) => str.toUpperCase()
const addExclamation = async (str: string) => `${str}!`
// Pipeline: input -> toUpperCase -> addExclamation -> output
const excitedUpperCase = simplex(addExclamation).pipe(toUpperCase)
console.log(await excitedUpperCase("hello")) // "HELLO!"
// Typed example with transformations
const parseAndDouble = simplex(async (n: number) => n * 2)
.pipe(async (s: string) => parseInt(s, 10))
console.log(await parseAndDouble("21")) // 42
```
--------------------------------
### Execute parallel dependencies with @pipechain/core connect
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Use `connect` to execute multiple named IO functions in parallel and aggregate their results. Ideal for fan-out/fan-in LLM workflows where each key in the `deps` map receives its own input slice.
```typescript
import { connect, duplex } from "@pipechain/core"
import { openai } from "@pipechain/openai"
const poem = duplex(openai({ model: "gpt-4o-mini" })).pipe(
async (topic: string, next) =>
next({ messages: [{ role: "user", content: `Write a haiku about ${topic}.` }] }),
)
const joke = duplex(openai({ model: "gpt-4o-mini" })).pipe(
async (topic: string, next) =>
next({ messages: [{ role: "user", content: `Tell a joke about ${topic}.` }] }),
)
// poem and joke run in parallel; results are merged into the handler
const workflow = (input: string) =>
connect({ poem, joke }, async ({ poem, joke }) => ({
poem: poem.choices[0]?.message.content ?? "",
joke: joke.choices[0]?.message.content ?? "",
}))({ poem: input, joke: input })
const result = await workflow("AI")
console.log(result.poem) // A haiku about AI
console.log(result.joke) // A joke about AI
```
--------------------------------
### Mock Tool Execution with toolEmulator
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Use `toolEmulator` to replace real tool implementations with mock functions during testing. This allows for ReAct pipeline testing without external service calls. Ensure the emulator provides mock data for the expected tool arguments.
```typescript
import { duplex } from "@pipechain/core"
import { openai } from "@pipechain/openai"
import { react, tool, toolEmulator } from "@pipechain/openai"
import { z } from "zod"
const searchWeb = tool({
name: "search_web",
description: "Search the web for information",
parameters: z.object({ query: z.string() }),
execute: async ({ query }) => fetch(`https://api.search.com?q=${query}`).then(r => r.json()),
})
// In tests: replace real fetch with mock data
const testAgent = duplex(openai({ model: "gpt-4o-mini" })).pipe(
toolEmulator({
search_web: ({ query }: { query: string }) => ({
results: [`Mock result for: ${query}`],
}),
}),
).pipe(react({ tools: [searchWeb] }))
.pipe(async (q: string, next) =>
next({ messages: [{ role: "user", content: q }] }),
)
// Runs without any real HTTP calls; emulator logs:
// "Emulating tool search_web with args { query: '...' }"
const result = await testAgent("Find recent news about TypeScript.")
console.log(result.choices[0].message.content)
```
--------------------------------
### ReAct Multi-Turn Tool Loop for OpenAI
Source: https://context7.com/nmnmcc/toolbox/llms.txt
Drives an autonomous agent that can use tools. The model receives tools, middleware executes calls, appends results, and loops until a final response or max turns is reached. Tools must be defined using `tool()`.
```typescript
import { duplex } from "@pipechain/core"
import { openai } from "@pipechain/openai"
import { react, tool, ReActMaxTurnsExceededError } from "@pipechain/openai"
import { z } from "zod"
const getWeather = tool({
name: "get_weather",
description: "Get current weather for a city",
parameters: z.object({ city: z.string().describe("City name") }),
execute: async ({ city }) => ({ city, temp: 22, condition: "sunny" }),
})
const getTime = tool({
name: "get_time",
description: "Get the current time in a timezone",
parameters: z.object({ timezone: z.string() }),
execute: async ({ timezone }) => ({ timezone, time: new Date().toISOString() }),
})
const agent = duplex(openai({ model: "gpt-4o" })).pipe(
react({ max_turns: 5, tools: [getWeather, getTime] }),
).pipe(async (query: string, next) =>
next({ messages: [{ role: "user", content: query }] }),
)
try {
const result = await agent("What's the weather in Paris and what time is it there?")
console.log(result.choices[0].message.content)
} catch (e) {
if (e instanceof ReActMaxTurnsExceededError) {
console.error("Agent exceeded turn limit")
}
}
```
--------------------------------
### Context Structure for Middleware
Source: https://github.com/nmnmcc/toolbox/blob/main/README.md
Details the `LanguageModelMiddlewareContext` and `LanguageModelOutputContext` types, showing the data available to middleware during LLM function execution.
```typescript
type LanguageModelMiddlewareContext = {
description: LanguageModelDescription;
initializer: LanguageModelInitializer;
middlewares: LanguageModelMiddleware[];
finalizer: LanguageModelFinalizer;
usage: OpenAI.CompletionUsage;
input: z.output;
tools?: OpenAI.Chat.Completions.ChatCompletionFunctionTool[];
history: [
OpenAI.Chat.ChatCompletionMessageParam,
OpenAI.Chat.Completions.ChatCompletion[],
][];
};
type LanguageModelOutputContext =
& LanguageModelMiddlewareContext
& { output: z.output