Skip to Content
DocsMigrationsLoom 0.1 → 0.2

Migrating from 0.1 → 0.2

Loom 0.2.0 is mostly additive but ships two breaking changes. This guide shows what to change and why.

TL;DR

- agent = Agent("You are helpful.") + agent = Agent("You are helpful.", model="claude-opus-4-7")
- with pytest.raises(ValueError): - Agent("hi", model="bad-spec") + from loomflow.core.errors import ConfigError + with pytest.raises(ConfigError): + Agent("hi", model="bad-spec")

That’s it for breaking changes. Everything else in 0.2.0 is new features and polish.


Breaking change 1: model= is required

Agent(...) used to silently default to EchoModel when model= was omitted. Users got "Echo: ..." output and assumed they were talking to an LLM. v0.2.0 fails fast with a helpful error:

ConfigError: Agent() requires a `model` argument. Pass one of: model='claude-opus-4-7' (Anthropic, needs ANTHROPIC_API_KEY) model='gpt-4o' (OpenAI, needs OPENAI_API_KEY) model='echo' (zero-key fake — text echoes the prompt; for dev/tests) model='mistral-large' (LiteLLM, also: command-, bedrock/, vertex_ai/, ollama/, ...) model=AnthropicModel(...) or any Model-protocol instance for full control.

Migration

If you want…Pass
To talk to Claude (most readers’ real use case)model="claude-opus-4-7"
To talk to GPTmodel="gpt-4o"
To talk to Mistral / Cohere / Bedrock / etc.model="mistral-large" (etc.)
The zero-key fake for tests / devmodel="echo"
Full control over constructionmodel=AnthropicModel("claude-opus-4-7", ...)

Why we did it. Default behaviour that produces plausible-looking but wrong output is the worst kind of footgun. If users want the echo behaviour they have to opt in explicitly. Easier to debug, easier to read, no silent fallback.


Breaking change 2: Resolver errors → ConfigError

_resolve_model("totally-unknown-spec") used to raise ValueError. Now it raises ConfigError (from loomflow.core.errors), matching the rest of the configuration-error vocabulary.

- with pytest.raises(ValueError, match="unknown model spec"): - Agent("hi", model="bad-spec") + from loomflow.core.errors import ConfigError + with pytest.raises(ConfigError, match="unknown model spec"): + Agent("hi", model="bad-spec")

If you were catching the resolver error in production code:

try: agent = Agent(prompt, model=user_input_spec) - except ValueError: + except ConfigError: ...

What’s new in 0.2.0 (non-breaking)

Provider coverage

LiteLLMModel. Single adapter for ~100 providers via the LiteLLM SDK. The string resolver dispatches the common prefixes:

Agent("...", model="mistral-large") # → LiteLLMModel Agent("...", model="command-r-plus") # → LiteLLMModel Agent("...", model="bedrock/anthropic.claude-3-sonnet-20240229-v1:0") Agent("...", model="vertex_ai/gemini-pro") Agent("...", model="ollama/llama3") # local Ollama Agent("...", model="groq/llama-3.1-70b") Agent("...", model="litellm/claude-3-haiku") # explicit opt-in

New embedders: VoyageEmbedder, CohereEmbedder. Same shape as OpenAIEmbedder.

Polish

  • Agent.__repr__() for dev-time inspection.
  • RunResult.total_tokens and RunResult.duration properties.
  • agent.consolidate() -> int returns the count of new facts extracted (was None).
  • tools=my_fn. Pass a single callable or Tool directly without list-wrapping. Lists still work.

New plugin API

  • agent.add_tool(fn). Register a tool after construction.
  • agent.remove_tool(name). Unregister by name.
  • agent.tools_list(). List registered tool names.
  • Public introspection properties: agent.model, agent.memory, agent.runtime, agent.tool_host, agent.budget, agent.permissions.
  • agent.recall(query, kind=, limit=). Convenience wrapper around agent.memory.recall(...).

Background work

ConsolidationWorker(memory, interval_seconds=60). Long-running anyio task that periodically calls memory.consolidate(). Surfaces new fact counts via on_consolidated(count) callback; consolidator failures via on_error(exc) so a transient hiccup doesn’t kill the worker. Doubles as an async context manager:

async with ConsolidationWorker(memory, interval_seconds=60): await main() # worker runs in background # Worker is cancelled when the block exits.

Common pitfall: stale install shadowing the editable

If you have a previous pip install loomflow in your env, an editable install (pip install -e .) of 0.2.0 may not take precedence because pip’s regular install sometimes wins on the import path:

$ python -c "import loomflow; print(loomflow.__version__)" 0.1.0 # ← stale; expected 0.2.0

Fix:

pip uninstall loomflow -y pip install -e '.[dev,...]'

Verify with:

python -c "import loomflow; print(loomflow.__version__, loomflow.__file__)" # Should print: 0.2.0 /your/checkout/path/loomflow/__init__.py

This is a Python packaging quirk, not a Loom bug. But worth flagging since it produces confusing AttributeError: ... has no attribute 'total_tokens' failures when 0.1’s RunResult is imported instead of 0.2’s.

Last updated on