Skip to content

Composition Recipes

Each recipe is a complete, runnable .compose() block. Copy-paste and adapt.

Scrub sensitive data from tool results before the LLM sees them. Log everything to an audit trail.

import { ReactiveAgents } from 'reactive-agents';
import { redact } from './your-pii-redactor';
import { auditLog } from './your-audit-logger';
const agent = await ReactiveAgents.create()
.withProvider('anthropic')
.compose((harness) => {
harness.on('observation.tool-result', (obs) => ({
...obs,
content: obs.content ? redact(obs.content) : obs.content,
}));
harness.tap('**', (payload, ctx) => {
auditLog({ tag: ctx.phase, iteration: ctx.iteration, payload });
});
})
.build();

Translate nudges and system prompts for non-English deployments.

.compose((harness) => {
harness.on('nudge.*', async (msg) => await translate(msg, 'fr'));
harness.on('prompt.system', async (text) => await localize(text, { locale: 'fr-FR' }));
})

Inject tenant-specific headers into every system prompt.

.compose((harness) => {
harness.on('prompt.system', (text, ctx) =>
`[tenant: ${ctx.strategy}]\n[env: ${process.env.ENV}]\n\n${text}`
);
})

Route 50% of runs to a prompt variant for controlled research.

let variant = 'control';
.compose((harness) => {
harness.on('prompt.system', (text) =>
Math.random() < 0.5 ? variantAPrompt(text) : text
);
})

Disable every harness signal. Returns to pure ReAct baseline — useful for benchmarking harness overhead.

// This single line is the framework's own ablation mode
.compose((harness) => harness.on('nudge.*', () => null))

All nudges return null (suppressed). System prompts, tool results, and lifecycle events are unaffected.


Replace the default termination predicate with domain-specific criteria.

.compose((harness) => {
harness.before('complete', (ctx) => {
const output = (ctx.state as { output?: string }).output ?? '';
if (!output.includes('REPORT_GENERATED')) {
// Not done yet — prevent completion, loop continues
return { abort: 'stop', reason: 'missing-report-sentinel' };
}
});
})

Surface auto-healing events to users and annotate healed results.

.compose((harness) => {
harness.tap('nudge.healing-failure', (msg, ctx) => {
console.warn(`[iter ${ctx.iteration}] Healing failed: ${ctx.trigger}`);
});
harness.on('observation.tool-result', (obs, ctx) => {
if (ctx.healed) {
return { ...obs, metadata: { ...obs.metadata, healed: true } };
}
return obs;
});
})

Track cumulative token spend and trigger budget alerts.

import { budgetLimit } from 'reactive-agents/compose/killswitches';
const agent = await ReactiveAgents.create()
.withProvider('anthropic')
.compose(budgetLimit({ maxTokens: 50_000, maxCostUSD: 0.50 }))
.compose((harness) => {
harness.tap('control.strategy-evaluated', (eval) => {
costTracker.record(eval.currentStrategy, eval.score);
});
})
.build();

Single line: every internal agent signal forwarded to OTel.

import { trace } from '@opentelemetry/api';
const tracer = trace.getTracer('reactive-agents');
.compose((harness) => {
harness.tap('**', (payload, ctx) => {
const span = tracer.startSpan(`agent.${ctx.phase}`);
span.setAttributes({
'iteration': ctx.iteration,
'strategy': ctx.strategy,
});
span.end();
});
})

Pattern #9 is the foundation for the @reactive-agents/otel package planned for v0.12.


Killswitches compose cleanly. First trigger wins, each records its source:

const agent = await ReactiveAgents.create()
.withProvider('anthropic')
.compose(budgetLimit({ maxCostUSD: 1.0 }))
.compose(timeoutAfter({ wallClock: '5m' }))
.compose(requireApprovalFor({ tools: ['send_email'], approver: uiApprove }))
.compose(watchdog({ noProgressFor: '60s' }))
.build();