### 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 }; ``` -------------------------------- ### Model Fallback Chain for OpenAI Source: https://context7.com/nmnmcc/toolbox/llms.txt Sequentially tries a chain of OpenAI models, falling back to alternatives if the primary model fails. Logs warnings on each fallback attempt. Useful for ensuring service availability. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { fallback } from "@pipechain/openai" const robust = duplex(openai({ model: "gpt-4o" })).pipe( fallback(["gpt-4o-mini", "gpt-3.5-turbo"]), ).pipe(async (prompt: string, next) => next({ messages: [{ role: "user", content: prompt }] }), ) // If gpt-4o fails → tries gpt-4o-mini → tries gpt-3.5-turbo → throws const result = await robust("Explain quantum entanglement simply.") console.log(result.choices[0].message.content) // Console: "Model gpt-4o failed, falling back to gpt-4o-mini. Error: ..." ``` -------------------------------- ### Create Caching Middleware Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Creates a middleware that caches LLM responses. It uses a Map to store results based on a generated cache key. Cache hits are logged. ```typescript import type { LanguageModelMiddleware } from "@nmnmcc/toolbox"; const simple_cache = ( store: Map, ): LanguageModelMiddleware => { return async (context, next) => { const cache_key = `${context.description.name}:${JSON.stringify(context.input)}`; // Check cache const cached = store.get(cache_key); if (cached) { console.log("Cache hit!"); return cached; } // Call LLM and cache result const result = await next(context); store.set(cache_key, result); return result; }; }; ``` -------------------------------- ### Describe a Regular Function with Metadata Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Wrap a regular TypeScript function with metadata for use as a tool in ReAct agents. This involves defining the function's name, description, input schema using Zod, and output schema. ```typescript import { z } from "zod"; import { describe } from "@nmnmcc/toolbox"; const add_numbers = describe( { name: "add_numbers", description: "Add two numbers together", input: z.object({ a: z.number().describe("First addend"), b: z.number().describe("Second addend"), }), output: z.object({ sum: z.number().describe("Sum of both numbers") }), }, async ({ a, b }) => { return { sum: a + b }; }, ); const result = await add_numbers({ a: 1, b: 2 }); console.log(result.sum); // 3 ``` -------------------------------- ### Human Approval Gate with CLI Prompt Source: https://context7.com/nmnmcc/toolbox/llms.txt Intercepts LLM responses for user approval via CLI. Returns true to approve, false to reject, or a string to replace the response content. Requires `readline` for interactive input. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { humanInTheLoop } from "@pipechain/openai" import * as readline from "readline" // Interactive approval via CLI prompt const cliApprove = async (message: OpenAI.ChatCompletionMessage) => { console.log("\n--- Model response ---") console.log(message.content) console.log("---------------------") const rl = readline.createInterface({ input: process.stdin, output: process.stdout }) return new Promise((resolve) => { rl.question("Approve? (y/n/edit): ", (answer) => { rl.close() if (answer === "y") resolve(true) else if (answer === "n") resolve(false) else resolve(answer) // treat any other input as edited content }) }) } const supervised = duplex(openai({ model: "gpt-4o" })).pipe( humanInTheLoop(cliApprove), ).pipe(async (prompt: string, next) => next({ messages: [{ role: "user", content: prompt }] }), ) try { const result = await supervised("Draft an apology email.") console.log("Approved content:", result.choices[0].message.content) } catch (e) { console.error("Response rejected by human reviewer:", e.message) } ``` -------------------------------- ### Create a duplex pipeline with @pipechain/core Source: https://context7.com/nmnmcc/toolbox/llms.txt Use `duplex` for middleware-style bidirectional pipelines where each step wraps the entire downstream pipeline. This enables logic before and after the core function executes, supporting short-circuiting or post-processing. ```typescript import { duplex, type Middleware } from "@pipechain/core" const secret = async () => "42" // Middleware that gates access by ID const auth: Middleware = async (id, next) => id === 42 ? next(id) : "Forbidden" // Middleware that logs timing const logger: Middleware = async (input, next) => { const start = Date.now() const result = await next(input) console.log(`Completed in ${Date.now() - start}ms`) return result } const secure = duplex(secret).pipe(auth).pipe(logger) console.log(await secure(21)) // "Forbidden" console.log(await secure(42)) // "42" // Pre-seeding middlewares directly in the constructor const withDefaults = duplex(secret, auth, logger) console.log(await withDefaults(42)) // "42" ``` -------------------------------- ### Compose Multiple Middlewares Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Creates a middleware that aggregates multiple other middlewares into a single chain. The middlewares are applied in reverse order of their definition. ```typescript import type { LanguageModelMiddleware } from "@nmnmcc/toolbox"; const aggregator = ( ...middlewares: LanguageModelMiddleware[] ): LanguageModelMiddleware => { return async (context, next) => { const chain = middlewares.reduceRight( (prev, curr) => (ctx) => curr(ctx, prev), next, ); return chain(context); }; }; // Usage const standard_middlewares = aggregator(logging(), retry(3), timeout(30000)); ``` -------------------------------- ### Create Error Handling Middleware Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Creates a middleware that handles errors during LLM calls. It executes a provided callback function when an error occurs and then re-throws the error. ```typescript import type { LanguageModelMiddleware } from "@nmnmcc/toolbox"; const error_handler = ( on_error: (error: Error) => void, ): LanguageModelMiddleware => { return async (context, next) => { try { return await next(context); } catch (error) { on_error(error as Error); throw error; } }; }; ``` -------------------------------- ### Dynamic Tool Filtering with toolSelector Source: https://context7.com/nmnmcc/toolbox/llms.txt Use `toolSelector` to filter available tools before each model call. The selector function inspects the tool list and message history to provide the model only with relevant tools for the current step. This helps in controlling which tools the model can access. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { react, tool, toolSelector } from "@pipechain/openai" import { z } from "zod" const readFile = tool({ name: "read_file", description: "Read a file", parameters: z.object({ path: z.string() }), execute: async ({ path }) => `contents of ${path}` }) const writeFile = tool({ name: "write_file", description: "Write a file", parameters: z.object({ path: z.string(), content: z.string() }), execute: async ({ path }) => `wrote ${path}` }) const deleteFile = tool({ name: "delete_file", description: "Delete a file", parameters: z.object({ path: z.string() }), execute: async ({ path }) => `deleted ${path}` }) // Only expose destructive tools if the last user message explicitly permits it const selective = duplex(openai({ model: "gpt-4o" })) .pipe(toolSelector((tools, messages) => { const lastMsg = messages?.at(-1) const isExplicitDelete = typeof lastMsg?.content === "string" && lastMsg.content.toLowerCase().includes("delete") return tools?.filter(t => isExplicitDelete ? true : t.function.name !== "delete_file", ) })) .pipe(react({ tools: [readFile, writeFile, deleteFile] })) .pipe(async (q: string, next) => next({ messages: [{ role: "user", content: q }] }), ) ``` -------------------------------- ### Create Request Modification Middleware Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Creates a middleware that adds custom context to the LLM request history. This is useful for providing system-level instructions or background information. ```typescript import type { LanguageModelMiddleware } from "@nmnmcc/toolbox"; const add_context = ( additional_context: string, ): LanguageModelMiddleware => { return async (context, next) => { // Add additional context to history const modified_context = { ...context, history: [ ...context.history, [{ role: "system" as const, content: additional_context }, []], ], }; return await next(modified_context); }; }; ``` -------------------------------- ### Inject System Message with Date Source: https://context7.com/nmnmcc/toolbox/llms.txt Adds a system message containing the current date to the beginning of the message array before sending it to the model. Useful for providing time-sensitive context. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { contextEditing } from "@pipechain/openai" import type { OpenAI } from "openai" // Inject a date-stamped system message into every call const withDate = duplex(openai({ model: "gpt-4o-mini" })).pipe( contextEditing((messages) => [ { role: "system", content: `Today is ${new Date().toDateString()}. Answer concisely.`, }, ...messages, ]), ).pipe(async (prompt: string, next) => next({ messages: [{ role: "user", content: prompt }] }), ) const result = await withDate("What day is today?") console.log(result.choices[0].message.content) // Cites today's date ``` -------------------------------- ### Add Retries to Tools with toolRetry Source: https://context7.com/nmnmcc/toolbox/llms.txt The `toolRetry` utility wraps tool `execute` functions with retry logic. It retries up to `maxRetries` times on failure, logging a warning before re-throwing the last error. This is applied before tool execution within the ReAct loop. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { react, tool, toolRetry } from "@pipechain/openai" import { z } from "zod" const unstableTool = tool({ name: "fetch_data", description: "Fetch data from an unstable external API", parameters: z.object({ id: z.string() }), execute: async ({ id }) => { if (Math.random() < 0.7) throw new Error("API temporarily unavailable") return { id, data: "success" } }, }) // Wrap all tools with up to 3 retries each const resilientAgent = duplex(openai({ model: "gpt-4o" })) .pipe(toolRetry(3)) .pipe(react({ tools: [unstableTool] })) .pipe(async (q: string, next) => next({ messages: [{ role: "user", content: q }] }), ) // If fetch_data throws, retries up to 3x before propagating error // Console: "Tool fetch_data failed (attempt 1/3): Error: API temporarily unavailable" const result = await resilientAgent("Fetch data for ID abc-123") ``` -------------------------------- ### Partial Application with `defer` in TypeScript Source: https://context7.com/nmnmcc/toolbox/llms.txt Use `defer` to create a partially applied IO function. This is useful for binding static arguments like model names before providing dynamic inputs. ```typescript import { defer } from "@pipechain/core" const add = async (input: { a: number; b: number }) => input.a + input.b // Bind `a` now, supply `b` later const addFrom2 = defer(add)({ a: 2 }) console.log(await addFrom2({ b: 3 })) // 5 console.log(await addFrom2({ b: 10 })) // 12 // Real-world: bind OpenAI model params once, call with messages dynamically import { openai } from "@pipechain/openai" const gpt4 = openai({ model: "gpt-4o", temperature: 0.5 }) // gpt4 is now IO<{ messages: ... }, ChatCompletion> const response = await gpt4({ messages: [{ role: "user", content: "Hello!" }], }) console.log(response.choices[0].message.content) ``` -------------------------------- ### Limit Tool Calls Per Response Source: https://context7.com/nmnmcc/toolbox/llms.txt Enforces a maximum number of tool calls that can be returned in a single completion response. Throws an error if the count exceeds the budget. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { modelCallLimit, toolCallLimit } from "@pipechain/openai" // Limit tool calls per response to 3 const toolBudgeted = duplex(openai({ model: "gpt-4o" })) .pipe(toolCallLimit(3)) ``` -------------------------------- ### Extract Usage from Result History Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Access the latest completion usage details from the result's history. This is useful for logging or analyzing token consumption. ```typescript const usage = result.history.at(-1)?.[1].at(-1)?.usage; ``` -------------------------------- ### Middleware Interface Definition Source: https://github.com/nmnmcc/toolbox/blob/main/README.md Defines the `LanguageModelMiddleware` interface, which outlines the structure for custom middleware functions used in LLM-powered function chains. ```typescript import type { LanguageModelMiddleware, LanguageModelMiddlewareContext, LanguageModelMiddlewareNext, LanguageModelOutputContext, } from "@nmnmcc/toolbox"; type LanguageModelMiddleware = ( context: LanguageModelMiddlewareContext, next: LanguageModelMiddlewareNext, ) => Promise>; ``` -------------------------------- ### PII Redaction Middleware for OpenAI Source: https://context7.com/nmnmcc/toolbox/llms.txt Scrub personally identifiable information from messages using configurable regex patterns. Defaults cover email and US phone numbers. Patterns are applied to all string message content. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { pii } from "@pipechain/openai" // Default patterns: email + US phone const safe = duplex(openai({ model: "gpt-4o-mini" })).pipe(pii()).pipe( async (input: string, next) => next({ messages: [{ role: "user", content: input }] }), ) await safe("My email is alice@example.com and my phone is 555-123-4567") // Sent to OpenAI: "My email is [REDACTED] and my phone is [REDACTED]" // Custom patterns: also redact SSNs and credit card numbers const strictSafe = duplex(openai({ model: "gpt-4o-mini" })).pipe( pii([ /\b[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,}\b/gi, /\b\d{3}-\d{2}-\d{4}\b/g, // SSN /\b\d{4}[- ]?\d{4}[- ]?\d{4}[- ]?\d{4}\b/g, // Credit card ]), ) ``` -------------------------------- ### Enforce Model Call Limit Source: https://context7.com/nmnmcc/toolbox/llms.txt Limits the total number of LLM API calls made through the pipeline. Throws an error when the specified limit is exceeded. Useful for managing costs and preventing excessive API usage. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { modelCallLimit, toolCallLimit } from "@pipechain/openai" // Allow at most 5 model calls before throwing const budgeted = duplex(openai({ model: "gpt-4o-mini" })) .pipe(modelCallLimit(5)) .pipe(async (prompt: string, next) => next({ messages: [{ role: "user", content: prompt }] }), ) for (let i = 0; i < 6; i++) { try { await budgeted(`Question ${i}`) } catch (e) { console.error(e.message) // "Model call limit exceeded: 5" on 6th call } } ``` -------------------------------- ### Pipeline Timeout with `timeout` Middleware in TypeScript Source: https://context7.com/nmnmcc/toolbox/llms.txt The `timeout` middleware races a pipeline against a timer, throwing a `TimeoutError` if it doesn't resolve within the specified milliseconds. It's useful for preventing stuck operations. ```typescript import { duplex } from "@pipechain/core" import { timeout, TimeoutError } from "@pipechain/middlewares" const slow = async (n: number) => { await new Promise(r => setTimeout(r, 5000)) // 5 second delay return n } const bounded = duplex(slow).pipe(timeout(1000)) // 1 second limit try { await bounded(42) } catch (e) { if (e instanceof TimeoutError) { console.error("Operation timed out:", e.message) // "Operation timed out after 1000 ms" } } // Combine with retry for resilient calls import { retry } from "@pipechain/middlewares" const safe = duplex(slow).pipe(timeout(2000)).pipe(retry(2, 100)) ``` -------------------------------- ### Remove Assistant Messages to Reset Context Source: https://context7.com/nmnmcc/toolbox/llms.txt Filters out all previous assistant messages from the conversation history. This effectively resets the context for the model, making it behave as if previous assistant turns never happened. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { contextEditing } from "@pipechain/openai" import type { OpenAI } from "openai" // Remove all previous assistant messages (reset context) const forgetful = duplex(openai({ model: "gpt-4o-mini" })).pipe( contextEditing((messages) => messages.filter((m) => m.role !== "assistantAINLESS"), ), ) ``` -------------------------------- ### Automatic Retries with `retry` Middleware in TypeScript Source: https://context7.com/nmnmcc/toolbox/llms.txt The `retry` middleware automatically retries a pipeline up to `max` times upon encountering errors, with an optional delay between attempts. It works with any `Duplex` pipeline. ```typescript import { duplex } from "@pipechain/core" import { retry } from "@pipechain/middlewares" let attempts = 0 const flaky = async (n: number) => { attempts++ if (attempts < 3) throw new Error("Temporary failure") return n * 2 } // Retry up to 3 times with a 500ms delay between attempts const resilient = duplex(flaky).pipe(retry(3, 500)) const result = await resilient(21) console.log(result) // 42 console.log(attempts) // 3 ``` -------------------------------- ### Summarize Conversation History Source: https://context7.com/nmnmcc/toolbox/llms.txt Automatically summarizes older messages in a conversation when the history exceeds a specified number of messages (`maxMessages`). Uses a separate OpenAI client for summarization, preserving recent context. ```typescript import { duplex } from "@pipechain/core" import { openai } from "@pipechain/openai" import { summarize } from "@pipechain/openai" import OpenAI from "openai" const client = new OpenAI() // Summarize when conversation exceeds 10 messages; use gpt-4o-mini for summarization const chatAgent = duplex(openai({ model: "gpt-4o", client })).pipe( summarize({ maxMessages: 10, model: "gpt-4o-mini" }), ).pipe(async (userMsg: string, next) => next({ client, messages: [ { role: "system", content: "You are a helpful assistant." }, { role: "user", content: userMsg }, ], }), ) // As history grows beyond 10 messages, older turns are auto-summarized: // [system, summary_of_old_turns, ...last_8_messages] for (const turn of longConversation) { const result = await chatAgent(turn) console.log(result.choices[0].message.content) } ``` -------------------------------- ### Core Pipechain Type Primitives in TypeScript Source: https://context7.com/nmnmcc/toolbox/llms.txt Defines fundamental types like `IO`, `Async`, `Sync`, `Promisable`, `InferIOIn`, `InferIOOut`, and `Merge`. `IO` is the universal function shape. ```typescript import type { IO, Async, Sync, Promisable, InferIOIn, InferIOOut, Merge } from "@pipechain/core" // IO accepts no input when In = undefined const noArgs: IO = () => console.log("hello") // IO with input and output const double: IO = (n) => n * 2 const asyncDouble: Async = async (n) => n * 2 const syncDouble: Sync = (n) => n * 2 // Infer types from a function type In = InferIOIn // number type Out = InferIOOut // number // Merge: like Object.assign at the type level (Y overrides X) type A = { x: number; y: string } type B = { y: number; z: boolean } type C = Merge // { x: number; y: number; z: boolean } // Promisable: value that may or may not be wrapped in a Promise const maybeAsync: Promisable = Math.random() > 0.5 ? "sync" : Promise.resolve("async") ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.