agentsonar
v0.3.0-alpha.4
Published
Coordination intelligence for AI. Detection, prevention, governance, and FinOps across single agents, agents calling tools, MCP servers, multi-agent orchestrators, RAG pipelines, and custom buses.
Maintainers
Readme
AgentSonar
Coordination intelligence for AI. Detection, prevention, governance, and FinOps — across every AI system shape: single agents, agents calling tools, agents wired to MCP servers, multi-agent orchestrators, RAG pipelines, and custom buses.
Status: alpha. API may shift before 1.0. Tested against 10,000 differential fuzz cases byte-identical to the Python SDK. Bundle: 20 KB gzipped, zero runtime dependencies. Node 18+.
Install
npm install agentsonarNo Python. No sidecar. No second process.
Try it in 5 seconds
npx agentsonar demoRuns a bundled hello-world: three agents (Researcher → Writer → Reviewer)
loop forever, Prevent Mode trips at rotation 5, the demo catches the
PreventError and writes a self-contained HTML report you can open in
your browser. No config, no API keys, no external dependencies. Useful
both as a smoke test (confirms the install works) and as a 30-second
walkthrough of what AgentSonar does.
The agentsonar bin script is wired up by the package's bin field —
once installed, ./node_modules/.bin/agentsonar demo works too, or
install globally (npm install -g agentsonar) for plain agentsonar demo.
30 seconds in
import { AgentSonar } from 'agentsonar'
const sonar = new AgentSonar()
sonar.delegation('planner', 'researcher')
sonar.delegation('researcher', 'writer')
sonar.delegation('writer', 'planner')
// ... your agent code keeps running ...
sonar.shutdown()
// Open agentsonar_logs/run-<slug>/report.html in a browser.That's the whole API for the simplest case. Call delegation(source, target) wherever your code hands work from one agent (or step, or tool, or retrieval) to another. AgentSonar models the call graph, watches for failure patterns, and writes a self-contained HTML report on shutdown.
What AgentSonar does
Four pillars. The first two ship today; the last two are on the roadmap and will land without breaking the API surface you're learning now.
1. Detection (shipped)
Three failure classes, all graph-shaped, all invisible to span-based tracing:
- Cyclic delegation —
A → B → C → Alooping until the bill arrives. One stuck loop overnight burns thousands of dollars. WARNING at the rotation threshold, CRITICAL when it crosses a deeper one. - Repetitive delegation — same edge fired hundreds of times in a short window. RAG agents re-retrieving the same chunks 20× per session, or a single agent retrying the same tool call. Detected via exponential decay + z-score so legitimate bursts don't trip it.
- Resource exhaustion — sliding-window rate-limit detection per edge and globally. Catches the moment any agent — single or multi — hammers a downstream model, tool, or MCP server.
Same detector engine ships in the production Python SDK, ported byte-identical and validated by 10,000 differential fuzz cases (see parity below).
2. Prevention (shipped)
Throw a typed PreventError from delegation() the moment a cycle crosses a configured rotation count. Catch it once at the orchestrator boundary; everything below stays simple. The failure stops before the next API call instead of after the postmortem. Code below in Prevent Mode.
3. Governance (roadmap, 0.5+)
Authority-violation detection (an agent calling a tool it isn't authorized for), audit-trail JSONL outputs structured for EU AI Act / SOC 2 review, and policy hooks for "who can delegate to whom." Schema slots already live on CoordinationEvent; detector layers ship in 0.5.
4. FinOps (roadmap, 0.6+)
Token-velocity anomalies (cost runaway during a session, not after the bill), per-edge / per-agent cost attribution, and projected cost-to-critical for active cycles. Schema fields will land in 0.6 with a cost_impact block on CoordinationEvent; today's events deliberately ship without cost data so you don't pin to a half-baked surface.
Prevent Mode — stop the burn before the next API call
Cyclic loops are the highest-leverage failure to catch during the run, not in the postmortem. Pass prevent: { cyclicDelegation: true } and AgentSonar throws a typed PreventError from delegation() the moment a cycle crosses your threshold. Catch it once at the orchestrator boundary; everything below stays simple.
import { AgentSonar, PreventError } from 'agentsonar'
const sonar = new AgentSonar({
warningThreshold: 1,
criticalThreshold: 3,
prevent: { cyclicDelegation: { maxRotations: 5 } },
})
try {
while (true) {
sonar.delegation('researcher', 'writer')
sonar.delegation('writer', 'reviewer')
sonar.delegation('reviewer', 'researcher')
// Each iteration represents an LLM call. Without Prevent Mode this
// burns budget until the host kills the process.
}
} catch (err) {
if (err instanceof PreventError) {
console.log(`Stopped after ${err.rotations} rotations`)
console.log(`Cycle: ${err.cyclePath.join(' → ')}`)
console.log(`Reason: ${err.reason}`)
} else {
throw err
}
}
sonar.shutdown()Golden rule: PreventError is the only exception AgentSonar will ever propagate. Bad config, bad input, internal failures, disk errors — all swallowed. Observability never breaks the observed.
Singleton API — recordDelegation anywhere
For codebases where threading an AgentSonar instance through every function is friction. Configure once at startup, then call recordDelegation from any module. Async by signature so future versions can batch or buffer without breaking callers.
import {
configureAgentSonar,
recordDelegation,
shutdownAgentSonar,
PreventError,
} from 'agentsonar'
configureAgentSonar({
warningThreshold: 2,
criticalThreshold: 5,
prevent: { cyclicDelegation: true },
})
try {
await recordDelegation('a', 'b')
await recordDelegation('b', 'c')
await recordDelegation('c', 'a')
// ... from anywhere in your codebase ...
} catch (err) {
if (err instanceof PreventError) console.log(err.reason)
}
await shutdownAgentSonar()What you get on disk
After every session:
agentsonar_logs/run-<timestamp>-<slug>/
├── report.html # standalone, openable in any browser; 3 tabs (Failures / Activity / Raw JSON)
├── report.json # the same data, machine-readable; pipe into your own dashboards
├── timeline.jsonl # every event in order, one JSON object per line
└── alerts.log # plain-text alert stream, grep-friendlyThe HTML report has theme toggle, severity filter, copy-to-clipboard JSON, and renders prevention events distinct from organic alerts so you can see why the run was stopped.
Opt out per-instance with new AgentSonar({ fileOutput: false }), or globally with AGENTSONAR_DISABLED=1 (the engine becomes a no-op; delegation() accepts and silently drops every event).
Python parity
This package is a TypeScript port of the Python SDK. The detection layer is byte-identical, validated continuously by:
- 8 conformance fixtures in
agentsonar-spec/that both implementations replay and must produce the same output for. - 10,000 differential fuzz cases generated by the Python engine and replayed through the TypeScript engine with strict deep-equal on every alert and the final summary. Run yourself with
npm run test:fuzz.
If you have an existing Python pipeline using AgentSonar and want to adopt TS in front of an Electron app, browser extension, or Node service — the alerts, severities, fingerprints, and graph snapshots match. No vocabulary translation.
API at a glance
// The class API — explicit lifecycle, one instance per orchestrator.
new AgentSonar(config?, adapter?)
sonar.delegation(source, target, metadata?, timestamp?)
sonar.getSummary() // counts, edges, alert tally
sonar.getRecentEvents() // last 200 CoordinationEvents
sonar.healthCheck() // { reachable, version, adapter, degraded, reason? }
sonar.incrementIteration() // for orchestrators that count distinct iterations
sonar.shutdown() // idempotent; flushes report files
// The singleton API — fire-and-forget from any module.
configureAgentSonar(config?, adapter?)
recordDelegation(source, target, opts?) // returns Promise<void>
shutdownAgentSonar() // idempotent
// Naming-parity aliases for users coming from the Python SDK.
import { CustomAdapter, monitorOrchestrator } from 'agentsonar'
// CustomAdapter === AgentSonar (same class, second name).
// monitorOrchestrator() returns an AgentSonar with adapter='custom_ts'.Full type surface in dist/index.d.ts.
Examples
examples/ on GitHub has 6 runnable demos:
| File | Demonstrates |
|---|---|
| 01-hello-world.ts | Minimum viable; clean run, no failures |
| 02-cycle-detection.ts | 5 rotations of a 3-agent cycle → CRITICAL |
| 03-prevent-mode.ts | Loop pattern + PreventError catch |
| 04-warning-and-critical.ts | Severity progression + dedupe + inhibit |
| 05-singleton-api.ts | The 1-liner pattern |
| 06-custom-orchestrator.ts | Realistic researcher → writer → reviewer loop |
git clone https://github.com/agentsonar/agentsonar
cd agentsonar/agentsonar-npm
npm install && npm run build
cd examples && npm install
npx tsx 02-cycle-detection.tsConfiguration
Defaults are sensible. Override what you care about:
new AgentSonar({
// Layer 4: severity thresholds.
//
// GENERIC (apply to every pattern unless overridden by a per-pattern
// key below):
warningThreshold: 5,
criticalThreshold: 15,
// PER-PATTERN OVERRIDES (added in 0.3.0-alpha.2). Use these when
// you want different thresholds per pattern — e.g. silence cycle
// alerts in a noisy prod workload while keeping edge_anomaly tight,
// or vice versa. Leave undefined to fall back to the generic above.
//
// Setting `warningThreshold: 999` to "disable cycles" silences EVERY
// pattern uniformly. Use the `cycle*` keys instead to scope the
// override to one pattern.
cycleWarningThreshold: undefined, // default: warningThreshold
cycleCriticalThreshold: undefined, // default: criticalThreshold
edgeAnomalyWarningThreshold: undefined, // default: warningThreshold
edgeAnomalyCriticalThreshold: undefined, // default: criticalThreshold
// Layer 1: rate limiter
windowSize: 60, // seconds
perEdgeLimit: 10,
globalLimit: 100,
// Layer 2: repetitive-delegation detector
halfLifeSeconds: 60,
hardWeightLimit: 10,
zScoreThreshold: 3,
// Prevent Mode (off by default)
prevent: { cyclicDelegation: { maxRotations: 5 } },
// Output (file output is on by default)
fileOutput: true,
logDir: './agentsonar_logs', // override location
})Status & roadmap
This is the 0.3.0-alpha.4 release of the TypeScript engine. Detection and prevention are feature-complete and parity-tested with the Python SDK (10,000 differential fuzz cases byte-identical). The roadmap fills in the other two pillars:
- 0.4 — framework adapters (CrewAI bridge, LangGraph bridge, OpenAI Agents SDK
wrapAgentproxy, MCP server bridge). - 0.5 — governance pillar. Authority-violation detector, audit-trail format compatible with EU AI Act / SOC 2 review, policy hooks. Plus opt-in telemetry endpoint for the AgentSonar dashboard.
- 0.6 — FinOps pillar. Token-velocity anomalies, per-edge cost attribution, projected cost-to-critical on active cycles.
- 1.0 — API stable; semver guarantees begin.
Breaking changes are possible between 0.3 and 1.0; we'll mark them clearly in the changelog.
Design partners welcome
If you're hitting silent agent failures in production and want a direct line, open an issue or email [email protected]. We're actively shaping the framework adapters around real customer pain.
Links
- Website: agent-sonar.com
- Python SDK: agentsonar on PyPI
- Source: github.com/agentsonar/agentsonar
- Issues: github.com/agentsonar/agentsonar/issues
