Changelog¶
All notable changes to this project will be documented in this file. Format follows Keep a Changelog. Versioning follows Semantic Versioning.
[Unreleased]¶
Added¶
ReplanEngine— guardian of the dynamic replan loop. The adaptive counterpart toPlanfor pipelines whose shape is decided at runtime by a planner agent. The planner is a tool in the parentAgent'stool_map(built withoutput=PlanRound, located byplanner_name); it is called every round and the tasks it emits are dispatched viatool.run(**task.kwargs)— agents, plain functions, and pool routes alike, with no special-casing. Tasks flaggedparallel=Truerun concurrently viaasyncio.gather. Passstore=+checkpoint_key=to persist round state after every round andresume=Trueto continue from the last checkpoint; same compare-and-swap single-writer semantics asPlan(ConcurrentPlanRunErroron a contended key).max_rounds(default20) caps the loop; adone=Trueround must carry afinal_answer.PlanRoundandTask(lazybridge.engines.replan, re-exported fromlazybridge) — the planner's structured output schema.PlanRoundcarriesreasoning, a list ofTask, adoneflag, and the terminalfinal_answer;Taskis one tool call (tool+kwargs+parallel). Added to the public API snapshot. New guide:docs/guides/full/replan-engine.md; reference entries indocs/reference/engines.md.
Fixed¶
ext.plannersDAG builder —add_stepnow exposesfrom_parallel_all. The incremental builder tool'stask_kindannotation wasLiteral["literal", "from_prev", "from_step", "from_parallel"], omittingfrom_parallel_alleven thoughStepSpec, the step validator,_resolve_task, andPLANNER_GUIDANCEall already supported it — so the value the guidance steers the planner toward was not selectable through the generated tool schema. Added"from_parallel_all"to theadd_stepLiteral and documented it in the tool docstring. Additive; no existing behaviour changes.
[0.9.1] — 2026-05-28 — Store.items(prefix=) range scan¶
Added¶
Store.items(prefix=)— returns(key, value)pairs restricted to keys starting withprefixvia a single indexed B-tree range scan (WHERE key >= ? AND key < ?). Sub-linear in total keyspace size; O(M) in the number of matching keys. The in-memory path filters under the store lock usingstr.startswith. Passprefix=None(default) orprefix=""to iterate the full store. TheEncryptedStoreAdapterdelegates to the inner store and decrypts each returned value._prefix_upper_bound(prefix)— private helper that computes the exclusive upper bound for the B-tree scan. Handles the U+10FFFF edge case by falling back to a Python-levelstartswithfilter.
Compatibility¶
Additive — no existing behaviour changed. LazyPulse 0.2.0 uses this method
to replace its O(N+1) _scan_records implementation.
[0.9.0] — 2026-05-24 — lazytoolkit extraction (Phase 3: shims removed)¶
Removed (breaking)¶
The lazy deprecation shims left behind by the 0.8 extraction are gone.
Import from lazytools directly.
lazybridge.ext.mcp→ uselazytools.connectors.mcp(pip install 'lazytoolkit[mcp]').lazybridge.ext.gateway→ uselazytools.connectors.gateway.lazybridge.external_tools.read_docs→ uselazytools.documents(pip install 'lazytoolkit[docs]').lazybridge.external_tools.doc_skills→ uselazytools.skills.- The whole
lazybridge.external_toolsnamespace is deleted.
The old paths now raise ModuleNotFoundError instead of emitting a
DeprecationWarning. lazybridge still has no runtime dependency on
lazytools.
[0.8.0] — 2026-05-24 — lazytoolkit extraction (Phases 0–2)¶
The concrete, dependency-carrying tools moved to the new sibling package
lazytoolkit (repo: selvaz/LazyTools). LazyBridge keeps only the minimal
runtime + framework extensions.
Moved (lazy deprecation shims left behind; removed in 0.9)¶
lazybridge.ext.mcp→lazytools.connectors.mcp(pip install 'lazytoolkit[mcp]').lazybridge.ext.gateway→lazytools.connectors.gateway.lazybridge.external_tools.read_docs→lazytools.documents(pip install 'lazytoolkit[docs]').lazybridge.external_tools.doc_skills→lazytools.skills.
Old import paths still work and emit a DeprecationWarning pointing at the new
location. The shims are lazy (PEP 562 __getattr__) so import lazybridge
never imports lazytools — lazybridge has no runtime dependency on the
toolkit. The mcp and tools extras were removed (use lazytoolkit[mcp] /
lazytoolkit[docs]).
[0.7.9] — 2026-05-10 — simplification release¶
The headline change: deletion-led simplification. The framework
had no users yet, so we ship breaking changes without deprecation
paths or shims. Net public surface change: −1 in
lazybridge.__all__ (50 → 49), 5 deleted Agent.from_* class
methods, 9 silent-fallback paths converted to explicit errors, and
the entire report_builder subsystem extracted to its own repo.
Zero new public concept.
The single LLM-friendliness lever is consistency: one canonical form per concept, errors always raise, no opt-in modes.
See docs/migrations/0.7-to-0.79.md for per-deletion before/after
codemod snippets.
Breaking — extraction¶
lazybridge.external_tools.report_builderextracted to the sibling reposelvaz/LazyReport(PyPI:lazybridge-reports). Every import pathlazybridge.external_tools.report_builder.*is gone — replace withlazybridge_reports.*after installing the new package. The five optional extras[report],[report-charts],[report-citations],[report-fallback],[pdf]are gone fromlazybridge'spyproject.toml; their replacements live aslazybridge-reports[charts,citations,fallback,pdf]. No shim — there is no fallback import path.- New optional extra:
[encryption]→cryptography>=42,<46for the newlazybridge.store.encryption.EncryptedStoreAdapter(Fernet at-rest encryption forStorevalues, withMultiFernetkey rotation).
Breaking — deletions¶
- 5
Agent.from_*factories deleted:from_model,from_engine,from_chain,from_plan,from_parallel. All five were pure-alias forwarders (verified by audit). Use the canonicalAgent(engine=...)ctor or the kept-because-non-trivial factories (Agent.chain,Agent.parallel,Agent.from_provider). - 3 config dataclasses deleted:
AgentRuntimeConfig,ResilienceConfig,ObservabilityConfig. These were wrapper-of-flat-kwargs configs whose only behaviour was aflat kwarg > config object > defaultprecedence merge that required a private_UNSETsentinel on every kwarg. The precedence game and_UNSETare gone with them.CacheConfigis kept — it carries real semantic value (enabled/ttl) consumed byLLMEngine. mode="auto"graceful-fallback ladder removed fromTool/tool(). Both default tomode="signature"now; passmode="hybrid"ormode="llm"plusschema_llm=to opt into LLM-driven schema generation. Passingmode="auto"raisesValueError._ParallelAgentrenamed toParallelAgentand its return contract changed.ParallelAgent.__call__andrun()now return ONEEnvelopewhose.payloadis the labelled-text join across every branch (with transitive cost rollup inmetadata.nested_*and first-error short-circuit in.error) — restoring the framework invariant that every Agent returnsEnvelope. For typed per-branchlist[Envelope], call the newrun_branches(task)async helper.wrap_toolmade private (_wrap_tool). Use the publictool(...)factory instead.LLMEngine(tool_choice="parallel")raisesValueError(was a 0.7-eraDeprecationWarningthat downgraded to"auto").\n Concurrent tool execution is the default and not configurable.Old doc/directory deleted (1.2 MB, zero references).pythonpath = ["lazybridge"]removed frompyproject.toml(unused).
Breaking — silent fallbacks → explicit errors¶
from_step("typo")/from_parallel("typo")no longer warn + fall back to the start envelope — they raisePlanRuntimeErrorwith the actual step history and a typo-aware "Did you mean?" hint.LLMEnginewith an unknown model raisesValueErrorinstead of silently routing to Anthropic. SetLLMEngine.set_default_provider("...")for the legacy behaviour.- MCP server emitting a non-
objectinputSchemaraisesValueError(was silently coerced to an empty parameter set). Envelope.text()on a non-JSON-serialisable payload raisesTypeError(wasstr(payload)fallback).Memory(summarizer_timeout < 5.0)warns at construction (timeout almost always fires for typical summariser shapes).BaseProvider._resolve_modelraisesValueErrorwhen nothing is configured (was empty string fallback).Agent(engine=<non-LLM>)requires an explicitname=(was silently named"agent"and collided when used as a tool).Agent(model=..., engine=<non-LLM>)raisesValueError(was silently dropped).
Added¶
lazybridge.matrix— declarative provider-capability lookup.provider_capabilities()andnative_tool_support()aggregate the per-providerClassVarflags into a single typed dict for docs / introspection / capability-aware error messages.BaseProvidercapabilityClassVarflags:supports_streaming/supports_structured_output/supports_thinking. Subclasses override when a backend doesn't.-
Standard error-message format — every
PlanCompileError/PlanRuntimeError/UnsupportedFeatureErrorfollows::Step '
' (# ) — = . Defined steps: [...].> Did you mean ' '? (when applicable) Fix: . -
OTel
gen_ai.agent.nesting_levelattribute on agent spans — dashboards filtering on=0get clean root-only views. Session.emitexporter-exception dedup — warn-once per(exporter class, exception class)pair with a count of suppressed identical failures.test_public_api_snapshot.py— pinslazybridge.__all__and locks the deleted-in-0.7.9 names as permanently gone.
Fixed (bug fixes from Phase 1)¶
- B1: DeepSeek provider — defensively rebuild
params['messages']rather than mutating in place. - B2: Anthropic
_compute_costacceptscached_input_tokens=0and applies the standard 10% cache-read rate; cost telemetry was over-counted on cached calls pre-fix. - B4: Anthropic provider warns on URL-source
AudioContent(was silently dropped). - B6: Plan compiler typo-aware "Did you mean?" suggestions on
from_step/from_agent/from_memoryunknown-target errors. - B7: Plan serialisation raises
ValueErroron unknown sentinelkind(was silently fallback tofrom_prev). - B8: OTel exporter logs SDK exceptions at WARNING (was swallowed).
- B9: Blackboard planner closure state resets per
run()call (was leaking between successive runs). - B10: Plan compiler rejects sentinels referencing auto-named
_anon_<id>steps (LLMs cannot meaningfully produce that name). - B11: Plan resume replays Store sidecar writes from the checkpoint
kvso external consumers see complete state after a crash in the checkpoint→Store-write window. - I5: Anthropic adaptive-thinking warning corrected for Opus 4.7
(pre-fix said "use 'effort'" but Opus 4.7 only accepts
display).
Documentation¶
SKILL.mdrewritten for the 0.7.9 surface; canonical Plan block, default-model fallback advice viafrom_provider(tier=...), anti-pattern entries for every deletion.docs/migrations/0.7-to-0.79.md(new) — per-deletion before/after snippets and a TL;DR table.docs/reference/configs.mdrewritten — onlyCacheConfigremains documented; rest of file explains the deletion.docs/reference/engines.mdadds thethinking=knob.docs/reference/providers.mdadds thestop_reasonnormalisation table (GoogleMAX_TOKENSmapping fix).docs/guides/mid/parallel.mdrewritten for the new single-Envelope return contract.- the MCP guide example now shows
allow=filtering as best practice. examples/verify_judge_loop.py(new),examples/guardrails_demo.py(new), env preflight inexamples/daily_news_report.py.
Tooling¶
lazybridge.skill_docs._buildrecovered + wired into thetest.ymltypecheck job (drift gate that asserts every public symbol in__all__is mentioned in SKILL.md).docs.ymlassertssite/llms.txtandsite/llms-full.txtare non-empty (≥1 KB) aftermkdocs build --strict.- Top-level
permissions: contents: readadded to.github/workflows/test.yml(least-privilege baseline).
[Unreleased] — 2026-05-05 — bug-fix and routing hardening¶
Breaking¶
LLMEngine.stream_idle_timeoutdefault changed fromNoneto90.0s. Old default left provider streams unbounded — a half-open HTTP/2 connection (TCP RST never delivered, PING dropped) would pin a worker indefinitely. New default raisesStreamStallErrorafter 90 s of inter-chunk silence, which is large enough to absorb provider-side thinking pauses on Opus / Gemini Pro. Passstream_idle_timeout=Noneto opt out explicitly — a one-shotUserWarningflags the choice because the failure mode (worker pinned forever) is silent and hard to diagnose. The class-level default exposed for__new__/ subclass paths shifts the same way. No code change is required for callers that already pass an explicit value.
Features¶
Step.after_branches— exclusive-branch rejoin point. Set alongsideroutes/routes_byto route to exactly one branch and skip all sibling steps; execution resumes at the named step after the branch completes. Withoutafter_branches, routing is a detour (linear progression resumes from the routed-to step's declared position). SeeStepdocstring for the full example.
Hardening¶
MCP.stdio()now warns on unrestricted tool surface. When bothallow=anddeny=are omitted a one-shotUserWarningreminds the caller that every tool the subprocess advertises will reach the LLM. Trust model is unchanged (stdio is still audit-on-init, not deny-by-default likeMCP.http); silence the warning by passingallow=["*"]once you've audited the surface, or restrict it with a glob. SeeSECURITY.mdfor the full guidance.- CI now enforces skill-doc drift.
test.ymlrunspython -m lazybridge.skill_docs._build --checkin the typecheck job: a fragment edit without a re-render now fails the PR instead of slipping through (this was the documented contract; CI just hadn't been wired). mkdocs build --strict. A missing nav target or unresolved cross-reference indocs/now fails the docs workflow instead of shipping an empty page.
Documentation¶
- README — added an "alpha (0.7.x)" status callout up top, and
expanded the Full tier sentinel list to cover all five exports
(
from_prev/from_start/from_step/from_parallel/from_parallel_all). - SECURITY.md — new "MCP Servers — Tool Surface Audit" section
documenting the deny-by-default contract on
MCP.httpand the audit-on-init warning onMCP.stdio. - API reference —
_UNSETsentinels in generated signatures now have an explicit explanation at the top of the reference page, including theLLMEngine.stream_idle_timeoutsemantics. - Skill docs reference grouping fixed —
from_parallel_all,GuardError, andEventExporterare now classified under their proper categories instead of falling through to "Core types". - CHANGELOG hygiene — the second
[Unreleased]section was renamed to[0.7.0 — short-term audit hardening]so the file no longer carries two unreleased headers.
Bug Fixes (Critical)¶
- Store SQLite CAS: open transaction on
JSONDecodeError— theexcept sqlite3.Errorclause incompare_and_swapdid not catchjson.loadsfailures on corrupt rows, leavingBEGIN IMMEDIATEopen on the thread-local connection and poisoning every subsequent call on that thread. Widened toexcept (sqlite3.Error, ValueError)(json.JSONDecodeErroris aValueErrorsubclass). - Store in-memory: mutable references break CAS invariants —
read()andwrite()returned / stored the live Python object, so callers mutating the result could silently alter the stored value and defeatcompare_and_swap. Both paths now go through_deep_copy_safe(deep-copy with a non-copyable fallback). LLMEnginetool_choice="any"infinite loop — after the model satisfied the "must call at least one tool" contract on the first turn,provider_tcstayed"any", forcing every subsequent turn to also call a tool. The loop never exited untilmax_turnswas exhausted. Fixed:provider_tcis reset to"auto"immediately after the first tool-result turn.LLMEnginetool_choice="any"sent as literal tool name — Anthropic and OpenAI rejecttool_choice="any"as an unknown tool name. The framework now maps"any"→"required"when building the provider request so the wire value is always a recognised constant.- Plan: parallel-band failure checkpoint pointed at failing step —
when a step inside a parallel band failed, the checkpoint recorded
current_stepas the failing step rather than the band-start, soresume=Truere-entered mid-band in an inconsistent state. Now points at the band-start step. - Agent: failed structured-output retries contaminated memory —
correction retries in
_validate_and_retrywere called with the livememoryobject, so each failed attempt added a garbage turn to the agent's conversation history. Retries now passmemory=None; only the final accepted result reaches memory. Agent.stream(): input guard bypassed —acheck_inputwas not called in the streaming path, soguard=had no effect when callers usedasync for token in agent.stream(...). The guard check now runs before the first token is emitted.
Bug Fixes (High)¶
LLMGuardsync path:timeout=ignored —_judgeinvokedself._agent(prompt)directly on the calling thread without any deadline. Fixed by running the judge in a daemon thread and callingthread.join(timeout=self._timeout).- Memory
strategy="sliding"silently disabled withmax_tokens=None—_plan_compressiongated all compression onbool(self.max_tokens), sostrategy="sliding"with the defaultmax_tokens=Nonenever triggered. Fixed: only"auto"requires a token budget;"sliding"and"summary"compress by turn count independently ofmax_tokens. - Memory:
_overflow_warnedflag shared between turn-cap and summarizer timeout — a summariser timeout silenced the turn-cap warning (or vice versa) because both used the same flag. Split into_overflow_warned(turn cap) and_summarizer_warned(summariser timeout). - Predicates:
empty()/not_empty()treated0/Falseas empty — onlyNoneand zero-length containers (str,list,dict,tuple,set,frozenset) are now considered empty. Numerics and booleans are always non-empty; useeq(0)/eq(False)for those cases. - Google provider:
finish_reasonnever mapped to"max_tokens"— theMAX_TOKENSstop reason from the Google API was not translated, so callers inspectingstop_reasonalways sawNoneinstead of"max_tokens". - Tool schema:
model_dump()destroyed Pydantic model args —Tool.definition()calledmodel_dump()on the entire arguments dict, collapsing Pydantic model instances to plain dicts before the schema was built. Fixed:getattrper field preserves the original objects.
[0.7.0] — pre-1.0 reset, simplified namespace layout¶
Major reorganization. The framework is dropping back to pre-1.0 and
reshaping its namespace boundaries before stabilizing. Everything is
alpha.
Breaking¶
- Version downgrade:
1.0.0 → 0.7.0. The 1.0 release was premature given the API churn since; 0.7.x is the honest baseline. - Single stability tier: every surface is
alpha. Thestable / beta / alpha / domain4-tier taxonomy is removed. Per-module__stability__and__lazybridge_min__markers are removed; onlylazybridge.__stability__ = "alpha"remains. - Namespace reorganization — domain modules moved out of
lazybridge.ext.*: lazybridge.ext.read_docs→lazybridge.external_tools.read_docslazybridge.ext.doc_skills→lazybridge.external_tools.doc_skillslazybridge.ext.data_downloader→lazybridge.external_tools.data_downloaderlazybridge.ext.stat_runtime→lazybridge.external_tools.stat_runtimelazybridge.ext.report_builder→lazybridge.external_tools.report_builderlazybridge.ext.external_tools→lazybridge.ext.gateway(file rename to free the namespace)lazybridge.ext.*is now reserved for framework extensions that augment the agent runtime (mcp,otel,hil,evals,gateway,planners,viz).- New namespace
lazybridge.external_tools.*— domain tool packages (returnslist[Tool]).
Removed¶
lazybridge.ext.veoandlazybridge.ext.quant_agent— neither was ready for use and they only created confusion. Re-introduce later if the underlying integrations stabilize.lazybridge.external_tools.stat_runtime(statistical / econometrics sandbox) andlazybridge.external_tools.data_downloader(Yahoo / FRED / ECB market-data ingestion) — same rationale: scope-creep domain examples that distract from the framework's actual surface. The matching[stats]and[downloader]optional-deps extras are also removed frompyproject.toml.
Tool factory shape (breaking)¶
- All surviving
external_tools/*factories standardize ondef X_tools(*, ...) -> list[Tool]— keyword-only arguments, always returning a list. Single-tool cases return a 1-element list. report_tools(*, output_dir=...)fragment_tools(*, bus, default_section=None, step_name=None)skill_tools(*, skill_dir, ...)(wasskill_tool(skill_dir, ...) -> Tool)skill_builder_tools(*, ...)(wasskill_builder_tool(...) -> Tool)read_docs_tools(*, base_dir=None)— new factory wrappingread_folder_docsas a Tool.
Boundary¶
- New CI check (
tools/check_ext_imports.py):ext/andexternal_tools/may only import from publiclazybridge.*, never from internallazybridge.core.*or other private submodules.
Migration¶
# before
from lazybridge.ext.read_docs import read_docs_tools
from lazybridge.ext.external_tools import ExternalToolGateway
# after
from lazybridge.external_tools.read_docs import read_docs_tools
from lazybridge.ext.gateway import ExternalToolGateway
[0.7.0 — short-term audit hardening] — bundled into the 0.7.0 cut¶
Closes the high-severity findings from the deep architecture audit
(plan §5.1). All changes are additive; defaults shift only on
Session(batched=True) (on_full="hybrid" instead of "drop") which
strictly improves the safety of the existing path — critical events
that previously could be dropped under saturation now block the
producer. Pass on_full="drop" to opt back into the legacy policy.
Hardening¶
- OTel GenAI conventions (audit H-D).
OTelExporternow emitsgen_ai.system/gen_ai.request.model/gen_ai.usage.*/gen_ai.tool.*attributes per the OpenTelemetry Semantic Conventions for Generative AI, and constructs a real parent-child span hierarchy (invoke_agent → chat,invoke_agent → execute_tool) with cross-agent context propagation through OTel contextvars. Tool spans correlate viatool_use_idso N parallel invocations of the same tool no longer collide. Span registry is per-instance so multipleOTelExporters in a process don't fight over the global tracer provider. Memory.summarizer_timeout=(audit H-B). Default 30 s. An LLM summariser that hangs no longer blocksadd()— the keyword fallback runs and a one-shot warning surfaces. Compression also computes the summary OUTSIDEMemory._lock, so concurrentadd()calls progress while a slow summariser is in flight.- Per-event-type back-pressure in
EventLog(audit H-A). New defaulton_full="hybrid"— the writer queue blocks the producer for audit-critical events (AGENT_*/TOOL_*/HIL_DECISION) but drops cheap telemetry (LOOP_STEP/MODEL_REQUEST/MODEL_RESPONSE) under saturation. Override the set viaSession(critical_events=...)."block"and"drop"policies remain available unchanged. - MCP
_tools_cacheTTL + invalidation (audit H-E). Newcache_tools_ttlparameter onMCPServer/MCP.stdio/MCP.http(default 60 s) and aninvalidate_tools_cache()method. An MCP server that hot-loads or unloads tools is eventually reflected in the agent's tool list instead of forever-stale. - Loud surfacing of malformed tool-call arguments (audit M-A).
Provider
_safe_json_loadshelpers (OpenAI, LiteLLM) now tag the raw argument blob with_parse_erroron JSON decode failure or non-object payload.LLMEngine._exec_toolshort-circuits on the tag and emits a structuredTOOL_ERROR(type: "ToolArgumentParseError",parse_error,raw_arguments) instead of letting the tool fail downstream with a misleading "missing required field" message. Tool events also carrytool_use_idfor downstream correlation.
Tests / CI¶
- New
tests/unit/test_audit_short_term.py(17 tests) covering each of the above plus the streaming + tool-call accumulation regression for Gemini / DeepSeek shape (audit M-B). - Coverage policy widened (audit M-I):
lazybridge/ext/{otel,mcp,hil, planners,evals}are now in scope for the gate (previously omitted wholesale). Domain extensions (stat_runtime,data_downloader,doc_skills,veo,quant_agent,read_docs,external_tools) remain omitted because their dedicated test suites live undertests/unit/ext/and are skipped by the default run. Gate stays at 70 with broader coverage; target for 1.1 is 80. - New CI workflows (audit M-J):
release.yml(PyPI Trusted Publishing onv*.*.*tags),codeql.yml(weekly scheduled SAST + per-PR),dependabot.yml(weekly action + pip updates with major SDK pins preserved). Pre-commit hooks now run as a CI job.
[1.0.0] — 2026-04-26 — initial public release¶
Historical: this entry describes the deleted 4-tier stability taxonomy (
stable / beta / alpha / domain) and the original namespace layout. Both were removed in 0.7.0; entries below are kept for historical accuracy only.
Core¶
Agent— universal façade with swappable engines (LLMEngine,Plan, plusHumanEngine/SupervisorEnginefromlazybridge.ext.hil). One call surface (agent.run/agent(...)/agent.stream) regardless of engine.- Tool-is-Tool: plain functions,
Agentinstances,Agent.as_tool()results, and tool providers (e.g. an MCP server) all plug intotools=[...]with the same dispatch contract. Nested agents inherit the outer session for end-to-end observability. - Compile-time DAG validation:
PlanCompilerrejects duplicate step names, forward references, brokenfrom_step/from_parallel/from_parallel_allsentinels, and parallel-band misuse before any LLM call. - Crash-resume:
Plancheckpoints toStoreviacompare_and_swap. Concurrent runs on the samecheckpoint_keycollide at claim time;resume=Trueadopts an in-flight checkpoint. - Parallel tool dispatch: when an LLM emits multiple tool calls in
one turn, the engine runs them concurrently via
asyncio.gather. - Structured output:
output=SomeBaseModelflips the engine into schema-validated mode with retry-with-feedback up tomax_output_retries. - Sources / Memory / Store / Session / Guard: composable
observability and state primitives.
Sessionis SQLite-backed with thread-local connections and a batched event-log writer. - Sync façade:
agent("…")works inside or outside a running event loop. When invoked from inside one, the worker-thread loop inherits the caller'scontextvarscontext so OTel spans / request IDs / structured-logging context flow through.
Providers¶
AnthropicProvider,OpenAIProvider,GoogleProvider,DeepSeekProvider,LiteLLMProvider,LMStudioProvider.- Provider-tier aliasing (
super_cheap→cheap→medium→expensive→top) keeps preview / date-pinned model strings in one place per provider. - LMStudio adapter is a thin
OpenAIProvidersubclass that targets the local server (http://localhost:1234/v1by default), pinned to Chat Completions, with zero cost and no native tools. - Native server-side tools per provider:
WEB_SEARCH/CODE_EXECUTION/FILE_SEARCH/COMPUTER_USE/GOOGLE_SEARCH/GOOGLE_MAPS. - Prompt-caching forwarded via
cache=True(Anthropic explicit, OpenAI / DeepSeek auto, Google via separate API).
Extensions (lazybridge.ext)¶
Extensions ship at __stability__ = "alpha" by default and may break
between minor releases. Promotion: alpha → beta → stable → core. See
docs/guides/core-vs-ext.md for the policy.
ext.hil—HumanEngine(approval gate) andSupervisorEngine(full REPL with tool calls, retry-with-feedback, store access).ext.planners—make_planner(DAG builder) andmake_blackboard_planner(todo-list).ext.mcp— Model Context Protocol integration at the tool boundary.MCP.stdio/MCP.http/MCP.from_transportbuild a tool provider that drops intoAgent(tools=[server]).ext.otel— OpenTelemetry exporter forSession.ext.evals—EvalSuite/EvalCase/llm_judge/ built-in matchers.ext.stat_runtime— sandboxed DuckDB query engine with AST-validated SQL (sqlglot DuckDB dialect; defence-in-depth regex layer for environments without sqlglot).ext.data_downloader,ext.quant_agent,ext.doc_skills,ext.read_docs,ext.veo— domain extensions.
Documentation¶
- Per-tier guides (
docs/tiers/{basic,mid,full,advanced}.md). - Decision trees (
docs/decisions/) — when to use which primitive. - Recipes (
docs/recipes/) — tool calling, structured output, pipeline with resume, human-in-the-loop, MCP, orchestration tools. - LLM-assistant skill (
lazybridge/skill_docs/) ships with the package; same content as the site, signature-first for LLM consumption. Single-source viapython -m lazybridge.skill_docs._build.