Changelog
Release notes
New features, SDK improvements, and platform updates.
Releases
2026.10
October 20263 updatesBug fixes: experiment stats, session tag filters
Fixed the experiment stats page failing to load entirely when a metric had no variation to compare, the session tag filter erroring out for orgs with a mix of tagged and untagged sessions, and a malformed team link returning a server error instead of a clean "not found."
Agent specs are now a true graph
AgentSpec moves from a nested tree of steps to nodes and edges. A loop is just an edge pointing back to an earlier node; fanning out into parallel work is just a node with more than one unconditional edge leaving it — cycles and fan-out/fan-in just work, with no dedicated step types to maintain.
niitaka run now actually executes the compiled agent end to end. Specs saved under the old format upgrade automatically — nothing to migrate by hand.
AgentSpec(nodes=[...], edges=[...]) · niitaka run agent.yamlHardened event ingestion against one bad write taking down everything
A single malformed write — missing a field it needed — could get stuck retrying indefinitely and block every other event queued behind it, not just its own.
Writes that can never succeed are now set aside individually instead of blocking the rest of the queue, and anything stranded by a restart is automatically reclaimed instead of sitting lost.
2026.9
September 20267 updatesSession duration and event ordering, more accurate
Session duration no longer briefly shows a negative number at session end, and now has its own end timestamp set the moment a session reaches a terminal status — instead of being inferred from whether there happened to be an event nearby.
Dual-logged events can now assert their true call order explicitly rather than relying on arrival time.
log_independent_event(..., sequence_num=n)Retroactively correct a streaming call's cost
A streamed response only reveals its real usage once reconstructed after the fact — until now, that reconstructed cost had nowhere to go, and the already-logged event stayed at $0 forever.
patch_event_cost() corrects it after the fact from any thread, and the session's running total moves with it.
client.patch_event_cost(event_id, cost)Tool calls, captured the same way across every provider
OpenAI, Anthropic, Gemini, Groq, and LangChain each stored a model's tool-call decision differently — Gemini's native path and LangChain didn't capture it at all. A pure tool-call turn with no text content could look like an empty response.
Every provider now normalizes to one shape, and the session panel renders it explicitly instead of dropping it silently.
Pricing table refresh
Cross-checked the full pricing table against live provider rates: corrected three models whose price had moved since the last update — including a 3x drop on Claude Opus — and added eight current-generation models that had no pricing data at all.
Policy enforcement that spans multiple calls — even across processes
A proxy or gateway forwarding calls to another process used to need a brand-new session around every single call just to get retry, fallback, and cost_limit enforcement at all — several unwanted top-level sessions for what was really one user turn, with no visibility into cumulative cost across them.
policy_scope() lets enforcement span multiple calls, even across separate sessions; attach_session() lets a downstream process log into the caller's real session instead of creating its own.
niitaka.policy_scope(cost_limit_usd=...) · niitaka.attach_session(session_id)Policy guardrails: fixed several ways they could silently stop applying
A variant configured through the dashboard's current two-tier guardrail editor had its limits silently ignored at runtime — the SDK only read the older flat shape. Separately, a background policy fetch could write into the wrong thread's state once automatic instrumentation was involved, so retry/fallback/cost_limit never applied no matter how long the agent ran.
Both are fixed, and policy files now sync to the dashboard automatically instead of needing a manual push that never actually worked.
Experiment setup, redesigned
A clearer three-mode picker for how much of a variant's config to override, inherited policy values shown as editable dashed references instead of invisible blanks, and a one-click Undo on an agent's active version.
Promoting or reverting a variant is now atomic — no more window where a half-applied change could leave an experiment stuck.
2026.8
August 20267 updatesExpose session and analytics data to your own customers, safely
A new scoped, read-only token type lets you expose session and analytics data to your own customers — restricted to the tags you choose, with no write access and no visibility into anything outside that scope.
Your existing API key is untouched; this is a separate, additive credential for exactly this case.
X-Scoped-Token · GET /sessions, /analytics/cost, /analytics/qualitySession detail page, redesigned
A clearer, more scannable layout: status, cost, and tags up front; a stat strip showing duration, event count, LLM calls, cost, and errors at a glance; a dedicated Graph tab; and a searchable, filterable timeline you can navigate with the keyboard.
Event detail now leads with the answer, not the raw input.
Event graph: pan, zoom, and a clear starting point
Drag to pan and scroll to zoom instead of scrollbars. Every session graph now starts from a single visible node instead of scattered top-level steps, and tool calls show their real name — not a generic "tool" label.
Trace cause and effect between LLM calls and the actions they trigger
log_tool(), log_decision(), and log_error() now accept a parent_event_id — nest an event under the LLM call that caused it, so the timeline and graph show real causal structure instead of a flat list of unconnected steps.
log_tool(..., parent_event_id=get_last_llm_event_id())Tool call duration
log_tool() now accepts the same metadata your LLM calls already use — attach a latency and see it in the timeline and graph exactly like an LLM call's duration.
log_tool(..., metadata={"latency": seconds})Model and cost accuracy
Sessions now show which model they used — including when a session mixes models — derived automatically from your LLM calls.
Fixed Gemini calls under-reporting cost despite correct token counts, added pricing for newer models, and models with no pricing data are now flagged instead of silently showing $0.
More resilient under load
Live session updates no longer cut off early just because a session's status changed. Hardened backend request handling so brief overload is handled gracefully instead of cascading.
A failed request to load your sessions list now shows a clear retry prompt instead of looking like an empty account.
2026.7
July 20261 updateClosed a gap in event delivery
Closed an edge case where a batch of events could be silently dropped during a brief network hiccup in the ingestion pipeline.
Events are now retried until they're confirmed durable, instead of being lost if the hiccup landed at the wrong moment.
2026.6
June 20265 updatesTrack outcome metrics, broken down any way you like
A new Metrics tab on Analytics discovers every set_metrics() key automatically and infers its type — score, rating, sentiment, boolean, or numeric.
See distribution and trend per key, then group results by agent or any tag (model, connection, environment) to compare performance across your fleet.
session_ctx.set_metrics({...})Faster agent startup
start_session() no longer waits on network round-trips to fetch policies and pricing — both happen in the background now, and session end is fire-and-forget too.
Startup latency is no longer coupled to Niitaka's response time, even on a slow connection.
start_session() — returns instantlyThread-safe session tracking
Session state is now fully isolated per thread. Fixed a race condition where a background thread — an async LLM-judge call, a parallel tool run — could cross-contaminate session state with the main request thread under concurrent load.
Credentials redacted, local models priced correctly
LLM call inputs are now scrubbed of api_key, api_base, and other credential fields before they reach Niitaka.
Local models (Ollama and friends) get accurate $0 cost tracking instead of being billed at fallback rates — and any unrecognised model now shows $0 rather than a guessed price.
Connection reliability
Hardened backend connection handling against transient network drops, and fixed a rare error when viewing decision traces for background-thread sessions.
2026.5
May 20262 updatesFilter sessions by custom tags
Tag any session with key-value pairs — connection name, team, region, user ID, or any dimension that matters to you. Tags appear as clickable chips in the Sessions table: click a chip to filter instantly.
Stack multiple tag filters; the stat tiles update in real time to reflect only the tagged subset.
start_session(tags={...})SDK works gracefully without configuration
No more defensive boilerplate. When api_key is not set, start_session() silently returns a no-op context manager and all logging calls are silent.
Your agent code is identical whether Niitaka is configured or not — adopt it at your own pace or disable it in test environments.
start_session() returns no-op when unconfigured · niitaka.create_session()2026.4
May 20263 updatesName your LLM call sites, configure prompts from the dashboard
Tag each LLM call site in your agent with a named slot — "planner", "sql_generator", "interpreter".
When a runtime config or experiment variant defines a prompt_slots override for that name, the correct system prompt is injected automatically — no code changes, no redeploy.
niitaka.prompt_slot("name")Async LiteLLM fully instrumented
litellm.acompletion() is now captured alongside synchronous litellm.completion().
Async agents — FastAPI backends, asyncio pipelines, async LangChain chains — are fully observed with zero extra setup after calling instrument_litellm().
niitaka.instrument_litellm()Organise agents into folder hierarchies
Group related agents under slash-separated folder paths. Folders are created automatically on first use — no dashboard setup required.
Navigate the hierarchy in the Agents view, or scope policies and runtime configs to an entire folder at once.
start_session(folder_path="team/subfolder")2026.3
April 20262 updatesSearch across all sessions and events
Full-text search across session goals, event content, tool inputs/outputs, decisions, and error messages — all from one search bar.
PostgreSQL trigram indexes power fast partial-match results with highlighted snippets so you can spot the relevant line without opening each event.
One-click Slack integration for alerts
Connect your Slack workspace directly from the Alerts settings page — no webhook URL hunting or manual channel configuration.
OAuth scopes are minimal: Niitaka only requests permission to post to the channels you select. Existing webhook-based channels continue to work unchanged.