Skip to content

v0.6.0 — Concurrency, High Availability, Observability & Multi-Language SDKs

Latest

Choose a tag to compare

@HoweChen HoweChen released this 13 Sep 04:12
· 3 commits to main since this release

Highlights

This release removes the last single-threaded bottleneck in the HTTP data plane, makes multi-replica System 2 worker deployments safe, adds first-class Prometheus observability, and ships official Python and TypeScript SDKs alongside the Go client.

  • Concurrent HTTP data plane. The global request mutex that serialized every engine call is gone. Requests across workspaces now run fully in parallel; writes serialize only at the storage backend (SQLite WAL single-writer; Postgres fully parallel).
  • Multi-replica System 2 workers. Cycle-level leader election (Postgres advisory lock / SQLite flock) lets you run standby workers for failover without duplicate consolidation cycles.
  • Prometheus metrics. A native /metrics endpoint backed by prometheus/client_golang, plus a --metrics-addr flag that exposes metrics from the worker role.
  • Python & TypeScript SDKs. Zero-runtime-dependency clients for the HTTP data plane, feature-parity with the Go client.
  • Test coverage raised to 97.9% (Postgres mode), with scenario-named suites across every package.

What's Changed

Performance & Concurrency

  • engine.Scope — a zero-I/O, workspace-bound engine view that shares Store/Provider/LLM-agent caches. Per-request state mutation (withWorkspace) is eliminated; the two write endpoints route through scopes. Non-default workspaces get isolated L0 buffers via sync.Map.
  • Handler.mu removed — all 11 lock sites deleted from the API layer. Concurrency is now guarded by fine-grained component locks: the engine's agent-cache mutex, per-workspace working-memory mutexes, and a new RWMutex on the previously unlocked InMemoryVectorIndex.
  • langgraph retain node no longer constructs a short-lived engine (and store connection) per request — it uses Scope instead.
  • A 32-goroutine × 4-workspace mixed-workload test verifies isolation and runs clean under -race.

High Availability

  • Store.TryAcquireWorkerLock() — new cross-process mutual exclusion for System 2 cycles, mirroring the existing index-lock design: session-scoped Postgres advisory lock (key 727276) and SQLite flock(<db>.worker.lock). Both release automatically on process/session death.
  • Worker loop and engine.StartSystem2 acquire the lock per cycle: a held lock skips the cycle (standby, not a failure); a crashed replica's work is picked up by any survivor on the next cycle. deploy.replicas: 2+ is now safe for the worker role.

Observability

  • GET /metrics (auth-exempt, outside /api/) serves a Prometheus text exposition via client_golang: ladym_http_requests_total{endpoint,status}, ladym_http_request_duration_seconds histogram, ladym_http_requests_in_flight, ladym_system2_cycles_total{result}, ladym_go_goroutines. Endpoint labels use route patterns, so id-addressed paths cannot explode cardinality; pre-routing rejections (401s) count under endpoint="unknown".
  • ladym worker --metrics-addr :9090 serves /metrics + /healthz from the worker role.
  • The existing /api/metrics JSON shape is unchanged and now reads from the same registry.

SDKs

  • sdk/python (ladym-client, uv, stdlib-only): remember/recall/record_event/consolidate/stats/link/forget + memories CRUD, LadymError with HTTP status, injectable transport, 100% statement coverage.
  • sdk/typescript (ladym-client, zero runtime deps, Node ≥ 20 / browsers): camelCase API surface with injectable fetch, AbortSignal timeouts, 100% line coverage.
  • Both ship unit suites plus a gated integration leg (LADYM_SDK_IT=1) that builds ladym, serves a throwaway SQLite instance, and runs the full round-trip.

Testing & Quality

  • Coverage: 97.9% in Postgres mode (make test-pg), up from 95.2%; engine 100%, api 99.6%, cli 98.9%, storage 98.2% (PG), cmd/ladymconsole 0→100% on both editions. New suites are scenario-named (e.g. worker_lock_failover_test.go, cjk_dict_global_state_test.go).
  • Fixed a vector-index delete test whose branch coverage depended on map iteration order, and floored the read-path p95 baseline so the scaling budget is stable on loaded CI runners.

Breaking Changes

None. All public APIs (engine, api, MCP tools, CLI) are backward-compatible; Engine.Remember/RecordEvent signatures are unchanged.

Behavioral notes

  • /api/metrics endpoint keys are now route patterns (/api/memories/{id}) instead of raw paths, preventing unbounded growth of the JSON map.
  • The /metrics response Content-Type carries escaping=underscores (client_golang 1.24 behavior).

Upgrade Guide

  • Docker / Compose: pulling the v0.6.0 image is sufficient; no configuration migration. To run standby workers, raise the worker service's replica count — cycles are mutually exclusive automatically.
  • Prometheus: add a scrape job per api replica and per worker (--metrics-addr); see docs/deployment.md §4.
  • Go library users: no code changes required; engine.Scope is additive.
  • Postgres-backed coverage runs: make test-pg with LADYM_TEST_PG_DSN pointing at a pgvector instance.

Dependencies

  • Added: github.com/prometheus/client_golang v1.24.1 (plus standard transitive deps).
  • Runtime dependencies of the SDKs: none.

Full Changelog: v0.5.4...v0.6.0