jonaki

Limitations

What Jonaki does not do yet — stated plainly, because you will hit these.

Jonaki is 0.1.0. Here is what it does not do, so you can decide honestly whether it fits.

Context management is windowing only

There is no summarization. When history exceeds context.maxTokens, the oldest turns are dropped outright, not condensed. The earliest turns — often where the user stated the actual task — go first.

Windowing is opt-in: with no maxTokens, the full history is sent and you get a provider error rather than silent forgetting. Anything that must survive belongs in instructions, which is never dropped.

Workaround: keep durable facts in the system prompt, or summarize yourself and start a fresh session.

Token counts are estimated

Roughly four characters per token. It is not a real tokenizer and will not match any provider's count exactly. Budget with headroom.

Cost is computed from a static per-model price table. Unknown models price at zero, so usage.costUSD is a floor, not a guarantee. Check usage.inputTokens if you need certainty that a call happened.

PII redaction is regex-based

redactPII catches common formats of email, phone, and card numbers. It will miss variants and will occasionally match something that is not PII. It is a safety net, not a compliance control. Do not rely on it for GDPR, PCI, or HIPAA obligations.

Streaming is partial

text_delta streams from the provider's streaming API, but tool arguments are not streamed incrementally — a tool call arrives whole, once complete. If you want to show arguments filling in live, Jonaki cannot do that yet.

Replay matches by turn index

ReplayProvider serves recorded responses in the order they were captured. It does not fuzzy-match the request against the recording. If your agent's behaviour changes such that it makes model calls in a different order — while still calling the same tools — the replay may pass while testing the wrong thing.

Divergence is detected for two cases only: a tool the agent no longer exposes, and running out of recorded turns.

Stores are built for local development

FileStore.listRuns reads every run file, and neither it nor SQLiteStore is tuned for a large corpus. There is no pagination cursor, no retention policy, and no compaction. For production volume you will want your own Store implementation against a real database — the interface is five methods.

No built-in retries or rate-limit handling

A model call that fails moves to the next rung of the fallback ladder; if there is no next rung, the run fails with PROVIDER_ERROR. There is no exponential backoff, no 429-aware waiting, and no request queue. Wrap run() yourself — see the retry pattern.

No parallel tool execution

When a model requests several tools in one turn, Jonaki executes them one at a time, in order. This keeps the step machine deterministic and replayable, but it is slower than it could be for independent calls.

No multimodal input

Messages are text only. Images, audio, and files are not supported, even though all three providers offer them. Message.content is a string.

No MCP support

There is no Model Context Protocol client. Tools are defined in code with Zod.

Approval resume is single-decision

resume(runId, store, { agent, approved }) applies one decision to the pending call. If a turn requests several tools that each need approval, you approve them one at a time across successive resumes.

Not yet published, not yet in CI

At 0.1.0 the package has not been published to npm, and the repository has no CI workflow running the test suite on push. Both are next.


What it does do well

To be even-handed: replay testing, resumable state, the trace-as-data model, typed tools, and cross-provider fallback are all implemented, tested, and verified end to end against live APIs. The gaps above are real, but they are gaps at the edges rather than holes in the middle.

On this page