* fix: redact secrets in traces, bash env, and dashboard payloads Adds src/utils/redaction.ts and applies best-effort redaction at three sinks where sensitive data could leak: - tool_call trace events (input, output) - the bash tool's output buffer - the post-run dashboard's embedded JSON payload The bash tool no longer inherits the parent process.env. Child processes receive a fixed allowlist (HOME, LANG, LC_ALL, LOGNAME, PATH, SHELL, TEMP, TERM, TMP, TMPDIR, USER), so provider API keys and similar secrets are no longer visible to spawned shells. The post-run dashboard no longer loads Tailwind CDN, Google Fonts, or Material Symbols at view time. The page is self-contained and renders without network access. llmMessagesToAiSdkModelMessages no longer concatenates the opaque redactedData payload into the reasoning text emitted to the AI SDK; it emits only the [redacted_thinking] marker. The MCP GitHub example uses --no-install instead of -y and passes an explicit env allowlist instead of spreading process.env. * fix(redaction): consume full value for quoted and unquoted assignments The single ASSIGNMENT_PATTERN stopped at the first whitespace inside a value, so values with spaces were only partially redacted and the remainder leaked into trace events, dashboard payloads, and the bash output buffer. Three reviewer-reported cases on PR #263: password=secret value -> password=[redacted] value password="secret value" -> password="[redacted]" value" apiKey: "abc def" -> apiKey: "[redacted]" def" Splits the single pattern into two passes. The quoted pass consumes to the back-referenced closing quote so password="my pass" is fully matched. The unquoted pass consumes to the next structural delimiter (comma, semicolon, brace, bracket, newline) so password=my pass is fully matched. Adds tests/redaction.test.ts covering the three reviewer cases, the existing Authorization orphan-bracket regression, common token literal patterns, and idempotence.
2.2 KiB
Observability
open-multi-agent exposes three telemetry layers: live progress events, structured trace spans, and a static post-run dashboard.
Progress Events
Use onProgress when you need lightweight lifecycle events for logs, terminal output, or a live UI.
const orchestrator = new OpenMultiAgent({
onProgress: (event) => {
console.log(event.type, event.task ?? event.agent ?? '')
},
})
Common event types include task_start, task_complete, task_retry, task_skipped, agent_start, agent_complete, budget_exceeded, and error.
Trace Spans
Use onTrace when you need structured spans for LLM calls, tool executions, and tasks. Each span carries parent IDs, durations, token counts, and best-effort-redacted tool I/O.
const orchestrator = new OpenMultiAgent({
onTrace: async (span) => {
await traceSink.write(span)
},
})
Forward trace spans to OpenTelemetry, Datadog, Honeycomb, Langfuse, or your own run database only after deciding what data is safe for that sink. See integrations/trace-observability for a runnable example.
Post-Run Dashboard
renderTeamRunDashboard(result) returns a static HTML page that visualizes the executed task DAG with timing, token usage, per-task status, and task details.
import { writeFileSync } from 'node:fs'
import { renderTeamRunDashboard } from '@open-multi-agent/core'
const result = await orchestrator.runTeam(team, goal)
writeFileSync('run.html', renderTeamRunDashboard(result))
The library does not write files by itself. The CLI can write dashboard HTML for you with oma run --dashboard; see docs/cli.md.
The generated dashboard is self-contained and does not load remote scripts, stylesheets, or fonts. Sensitive-looking values in the embedded run payload are redacted before rendering.
What to Persist
For production runs, persist enough data to reconstruct a failure without replaying the entire job:
TeamRunResult.tasksfor the executed DAG and task states.TeamRunResult.totalTokenUsagefor cost attribution.onTracespans for LLM calls and tool executions.- The rendered dashboard HTML when you need a shareable post-mortem artifact.