guard() API
guard() wraps any function with runtime safety: budget, loop detection, side-effect tracking, and audit logging.
Basic usage
import { guard } from 'fuze-ai'
// Basic, defaults from registerTools() and fuze.toml
const search = guard(async function search(query: string) {
return await vectorDb.search(query)
})
// Specify the model for automatic cost tracking
const generateSummary = guard(
async function generateSummary(docs: string[]) {
return await openai.chat.completions.create({
model: 'gpt-4o',
messages: [{ role: 'user', content: docs.join('\n') }],
})
},
{ model: 'openai/gpt-4o' }
)
// Side-effect with compensation
const sendEmail = guard(
async function sendEmail(to: string, body: string) {
return await ses.sendEmail(to, body)
},
{
sideEffect: true,
compensate: async (result) => {
await ses.recallEmail(result.messageId)
},
}
)Operational defaults (maxRetries, timeout, maxBudget) come from registerTools() and can be tuned from the dashboard without redeploying. See Tools & Remote Config.
Options
All options are optional. Defaults come from fuze.toml and registerTools(), then from dashboard tool config (see Tools). Use guard options for things that describe the tool's nature (sideEffect, compensate, model), not for operational config that belongs in registerTools().
| Option | Type | Default | Description |
|---|---|---|---|
maxRetries | number | 3 | Max retry attempts for this function |
timeout | number | 30000 | Timeout in milliseconds |
maxCost | number | ∞ | Max cost in USD for this call. Overrides dashboard config when lower |
maxTokens | number | undefined | Max tokens for this call |
maxIterations | number | 25 | Hard iteration cap for this call |
onLoop | 'kill' | 'warn' | 'skip' | 'kill' | Behavior when a loop is detected |
model | string | undefined | Model identifier for auto cost extraction (e.g. 'openai/gpt-4o') |
costExtractor | Function | undefined | Custom function to read { tokensIn, tokensOut } from the return value |
sideEffect | boolean | false | Whether this call has real-world consequences |
compensate | Function | undefined | Rollback function called on failure |
Remote config override
When the SDK is connected to the Fuze cloud (FUZE_API_KEY set) or daemon, tool configurations set from the dashboard are applied at call time, without redeploying your code. The override logic is:
maxRetriesandtimeoutfrom the dashboard replace local values entirelymaxBudgetfrom the dashboard takes the minimum of local and remote values (the tighter limit always wins)- If
enabled: falseis set for a tool in the dashboard, the call throws immediately withFuzeError
Per-function guard options take the highest precedence and are never overridden remotely.
Return value
guard() returns a new function with the same signature. Call it exactly as you would the original.
Guard events
When Fuze intervenes, it throws typed errors:
| Error | Thrown when |
|---|---|
BudgetExceeded | Cost ceiling reached for the call or run |
LoopDetected | Repeated output pattern detected |
GuardTimeout | The guarded function exceeded its timeout |
FuzeError | Tool is disabled remotely, or a kill switch was activated |
createRun() API
createRun() creates a scoped run context that shares budget and loop state across multiple steps. Use it when a single logical task spans several guarded calls and you want aggregate limits to apply.
import { createRun } from 'fuze-ai'
const run = createRun('research-agent', { maxCostPerRun: 2.00, maxIterations: 50 })
// Wrap functions using the run's own guard, they share the run's budget
const search = run.guard(async function search(q: string) { return vectorDb.search(q) })
const summarize = run.guard(async function summarize(docs: string[]) { return llm.summarize(docs) })
const docs = await search('climate policy')
const summary = await summarize(docs)
// Check accumulated cost at any point
const { totalCost, stepCount } = run.getStatus()
// run.end() is optional, runs without an explicit end are shown as ongoing in the dashboard
await run.end()Each step within the run draws from the shared maxCostPerRun and maxIterations. If any step pushes the run over its ceiling, a BudgetExceeded error is thrown.
run.end() is optional. If omitted, the run appears as idle in the dashboard once activity stops for more than 5 minutes, and stale after an hour. This matches conversational agents where "completion" is not a defined event.
Auto cost extraction
Fuze automatically reads token counts from the return value of guarded functions. It recognises the response shapes of all major providers (OpenAI, Anthropic, Google, Cohere, Mistral, Groq, Together, AWS Bedrock). When a model is set, it uses the built-in price table to convert tokens to USD.
Provide a custom costExtractor only when your provider returns tokens in a non-standard format:
Return null from costExtractor to fall back to the pre-flight token estimate.
Timer cleanup
Fuze properly cleans up internal setTimeout timers on successful execution using a .finally(() => clearTimeout(timer)) pattern. This means:
- No resource leaks, timers are cleared whether the guarded function resolves or rejects.
- Safe for long-running processes, you can wrap thousands of calls without accumulating dangling timers.