@sisu-ai/mw-react-parser
v9.0.0
Published
Lightweight ReAct-style tool loop. The model proposes an action in plain text, you parse it, execute a tool, then the model reflects and answers.
Maintainers
Readme
@sisu-ai/mw-react-parser
Lightweight ReAct-style tool loop. The model proposes an action in plain text, you parse it, execute a tool, then the model reflects and answers.
Setup
npm i @sisu-ai/mw-react-parserExports
reactToolLoop()— returns middleware that performs one ReAct cycle as described.
What It Does
- Think → Act → Observe → Reflect loop without provider‑specific function calling.
- Parses
Action: <tool>andAction Input: <json or text>from the assistant’s message. - Invokes a registered tool, feeds the observation back, and asks the model for a final answer.
How It Works
- Calls
model.generate(..., { toolChoice: 'none' })to get an initial assistant message. - Extracts
toolandargsvia regex; attemptsJSON.parseon the input, falls back to raw text. - Executes the tool and appends a user message like
Observation (tool): <result>. - Calls
model.generateagain (tools still disabled) and pushes the final assistant message.
This keeps the loop adapter‑agnostic and easy to reason about at the cost of relying on formatting.
Usage
import 'dotenv/config';
import { Agent, createConsoleLogger, InMemoryKV, NullStream, SimpleTools, type Ctx } from '@sisu-ai/core';
import { openAIAdapter } from '@sisu-ai/adapter-openai';
import { registerTools } from '@sisu-ai/mw-register-tools';
import { inputToMessage } from '@sisu-ai/mw-conversation-buffer';
import { reactToolLoop } from '@sisu-ai/mw-react-parser';
const model = openAIAdapter({ model: 'gpt-4o-mini' });
// Example tool
const webSearch = {
name: 'webSearch',
description: 'Search the web for a query',
schema: { type: 'object', properties: { q: { type: 'string' } }, required: ['q'] },
handler: async ({ q }: { q: string }) => ({ top: [`Result for ${q}`] })
};
const ctx: Ctx = {
input: 'Find the npm page for @sisu-ai/core then summarize.',
messages: [{ role: 'system', content: 'When helpful, decide an action using:\nAction: <tool>\nAction Input: <JSON>. Then reflect with the observation.' }],
model,
tools: new SimpleTools(),
memory: new InMemoryKV(),
stream: new NullStream(),
state: {},
signal: new AbortController().signal,
log: createConsoleLogger({ level: 'info' })
};
const app = new Agent()
.use(registerTools([webSearch as any]))
.use(inputToMessage)
.use(reactToolLoop());Prompting Tips
- Seed the system prompt with the required format, e.g.:
Use tools when helpful. Reply with:\nAction: <tool>\nAction Input: <JSON>
- Keep tool schemas strict and arguments small to make parsing robust.
When To Use
- You want a provider‑agnostic tool loop that works with any chat model.
- You need a simple ReAct cycle without native function calling.
When Not To Use
- You rely on provider‑native tools/function‑calling — prefer
@sisu-ai/mw-tool-callinginstead. - You need multi‑step or iterative planning — use
iterativeToolCallingor a planner middleware.
Notes & Gotchas
- Formatting sensitivity: parsing uses regex; poor formatting may fail to extract the action.
- Security: validate tool inputs (zod) and guard tools with allow‑lists/capabilities.
- Streaming: this middleware uses non‑streaming
generatecalls; pair with a streaming middleware if you need live tokens.
Community & Support
Discover what you can do through examples or documentation. Check it out at https://github.com/finger-gun/sisu. Example projects live under examples/ in the repo.
