Skip to content

v1.6.0 — Observable Runtime

Choose a tag to compare

@U-C4N U-C4N released this 13 Jul 14:51
· 51 commits to main since this release

Observable Runtime

Every Deuz run now emits a versioned observation event protocol (ObserveEvent, schemaVersion: 1) through the new Dependencies.observer seam — local-first, zero runtime dependencies, no hosted service, no OpenTelemetry dependency, and nothing recorded by default.

What you can see

  • Runs & models — start/end, provider/model/surface, TTFT (tool-call-first responses now count), per-retry reason + backoff delay, finish reason, full token usage, sync/async USD cost via priceProvider
  • Agent steps — effective per-step model (post-prepareStep), per-step duration (new), per-step + cumulative usage, endReason incl. the previously invisible runaway-tool-error stop
  • Tools — per-call timing in real parallel completion order, original thrown errors captured at the only site that still has them, machine-readable denial causes
  • Approvals — requested/resolved with source (server / client-response / default-deny) and resume wait time
  • Durable runs — checkpoint saves/loads/failures; one runId across suspend/resume legs, fresh executionId per leg, checkpoint.loaded before run.started { resumed: true }
  • Compaction — per-layer events with estimate token + message counts; the summarize side-call is a visible, tagged model call (usage counted exactly once)
  • Sub-agents — full tree under the parent runId, keyed by agentPath, with durable childRunId

New subpaths

import { createMemoryObserver, summarizeRun } from '@deuz-sdk/core/observe';
import { createJsonlObserver, readJsonlEvents } from '@deuz-sdk/core/observe/node';

const observer = createMemoryObserver();
await generateText({ model, messages, tools, maxSteps: 5, deps: { observer } });
console.log(summarizeRun(observer.latestRun() ?? []));

Built-ins: createMemoryObserver · createCallbackObserver · composeObservers · filterObserver · summarizeRun · Node JSONL persistence (one valid JSON line per event, binary-safe, bounded queue — a slow disk can never affect a run).

Privacy & safety guarantees

  • Events carry only counts/ids/names/durations/enums; prompt/tool/reasoning/error content is opt-in per field and always passes a [REDACTED] redaction profile + structural limits (regression-tested against planted secrets in every channel)
  • Observers can never break a run: isolated, never awaited; with no observer the hot path pays a single boolean branch and draws no ids
  • Deterministic per-run sampling (sampleRate) — a run is all-in or all-out
  • streamChat stays synchronous and lazy (G2); exactly one terminal event per execution leg

Tracer bridge — the span hierarchy, completed

An injected Dependencies.tracer now receives the documented invoke → step → execute_tool hierarchy driven by the same events (1.5 emitted only flat per-model-call invoke spans). Span names and attribute keys are unchanged; agentic loops now produce one invoke with step/tool children instead of N flat invokes. A user abort still ends the span without an exception.

Behavior fix

A tool-call-first response now clears the TTFT timer — previously only text/reasoning deltas did, so a tool-first stream could falsely trip the 60-second ttft timeout.


Quality: 558 tests (147 new across 14 observation suites, including the repo's first span tests and a P0 secret-leak matrix), full 10-stage npm run check + docs build green. Bundle budgets raised once with measurement: core 86 000 → 100 000 raw bytes (measured 97.7 KB fully instrumented), edge 76 000 → 90 000.

Docs: Observability guide · Event catalog · Design spec (code-verified) · CHANGELOG