Skip to content

Upgrading from v0.32 to 1.0

1.0 is the first release covered by the API stability promise. It renames the package, requires Python 3.11, and removes everything 0.27 and 0.28 deprecated. Two behaviors change for empty and truncated responses. Checkpoints and saved results from earlier releases still load and resume.

Before you upgrade

Upgrade to v0.32 first and run your tests with deprecation warnings as errors:

python -W error::DeprecationWarning -m pytest

Code that runs on v0.32 without a DeprecationWarning only needs the rename below and the behavior changes. Each warning names its replacement; the v0.28 and v0.27 guides explain them in more detail.

The package is now llm-minder

Releases through v0.32 were published as async-batch-llm. From 1.0:

Before From 1.0
pip install async-batch-llm[openai] pip install llm-minder[openai]
import async_batch_llm import llm_minder
logging.getLogger("async_batch_llm") logging.getLogger("llm_minder")
Prometheus metrics async_batch_llm_* llm_minder_*
AsyncBatchLLMError LLMMinderError (the old name still works as an alias)

Exported names, signatures and behavior don't change with the rename, so most code needs only its imports updated:

from llm_minder import ProcessorConfig, llm, process_prompts

Two things are easy to miss:

  • Logging configuration that names async_batch_llm silently stops applying. Search your code and logging config files for the old name.
  • Dashboards and alerts built on the Prometheus output need the new metric names.

Artifact and result files keep their format, including the async-batch-llm-result schema name, so a run checkpointed by an earlier release resumes under 1.0.

Python 3.11 or newer

1.0 requires Python 3.11. v0.32 is the last release for Python 3.10.

Removed names and parameters

Everything 0.27 and 0.28 deprecated is gone. A removed top-level name raises AttributeError naming its replacement. A removed config or processor keyword raises TypeError naming its replacement; WorkItemResult(gemini_safety_ratings=...) raises Python's plain TypeError.

Removed Use instead
LLMGateway LLMCallPool
BatchProcessor ParallelBatchProcessor
ProcessingStats The dict from get_stats()
grounding_metadata_extractor Nothing: built-in Gemini models already emit grounding
ParallelBatchProcessor(max_workers=..., timeout_per_item=..., rate_limit_cooldown=...) ParallelBatchProcessor(config=ProcessorConfig(...))
ProcessorConfig(timeout_per_item=...) ProcessorConfig(attempt_timeout=...)
ProcessorConfig(enable_detailed_logging=True) The llm_minder logger's level (Logging)
Positional arguments to the five config classes Keyword arguments
WorkItemResult.gemini_safety_ratings result.metadata["safety_ratings"]
batch.cache_hit_rate() batch.cache_hit_rate (a property)
effective_input_tokens() / estimated_cost() without a rate Pass cached_token_rate=CachedTokenRates.<PROVIDER>
Integer prompts to process_prompts / process_stream String prompts
A 2-tuple from execute() Return (output, tokens, metadata)

A strategy that still returns (output, tokens) doesn't fail when you build it: each item it runs fails with a ValueError (category logic_error, not retried), and its tokens are still counted.

Build WorkItemResult by keyword

Removing gemini_safety_ratings moves every WorkItemResult field after it up one position. Code that builds results positionally, usually in tests or custom middleware, can silently put values in the wrong fields. Build them by keyword:

from llm_minder import WorkItemResult

result = WorkItemResult(item_id="a", success=True, output="ok", error_category=None)

Behavior changes

Truncated responses have their own category

A response that hits the output-token limit before producing any usable text now fails with ErrorCategory.RESPONSE_TRUNCATED ("response_truncated") and raises TruncatedResponseError, a subclass of EmptyResponseError. It used to be empty_response. It still isn't retried.

A response that hits the limit after producing partial text still succeeds with that text, as before; result.metadata["finish_reason"] ("length", "MAX_TOKENS" or "incomplete", depending on the provider) shows it was cut off. The exception is DeepSeekModel on the Responses API, which fails any incomplete response.

If you abort on, filter on or count empty_response, add the new category:

from llm_minder import ErrorCategory, GuardrailConfig

guardrails = GuardrailConfig(
    abort_on_error_categories=frozenset(
        {ErrorCategory.EMPTY_RESPONSE, ErrorCategory.RESPONSE_TRUNCATED}
    )
)

except EmptyResponseError still catches truncations.

A cut-off empty string now fails

An empty-string reply ("", as opposed to missing text) from Gemini or a Chat Completions model now raises EmptyResponseError when the provider says it was cut off, blocked or refused. Before 1.0 it succeeded with empty text. An empty string after a normal stop, or alongside tool calls, still succeeds.

If you relied on getting "" back, for example to detect blocked prompts, check the failure instead. EmptyResponseError.reason says why, the same way for every provider:

from llm_minder import EmptyResponseError, WorkItemResult


def why_empty(result: WorkItemResult) -> str | None:
    if isinstance(result.exception, EmptyResponseError):
        return result.exception.reason  # "max_tokens", "content_filter", "refusal", ...
    return None

Now stable

The typed provider-output views .grounding, .reasoning and .tool_calls, and the Grounding, GroundingSource and ToolCall classes, are stable from 1.0. Real Gemini, OpenAI, OpenRouter and DeepSeek runs confirmed their shapes. .logprobs, EmptyResponseError.reason and the other APIs listed under Provisional can still change in a minor release.

Checklist

  • [ ] Your tests pass on v0.32 with -W error::DeprecationWarning.
  • [ ] Python 3.11 or newer.
  • [ ] Dependency changed from async-batch-llm to llm-minder; imports updated.
  • [ ] Logging configuration and dashboards use the llm_minder names.
  • [ ] Code matching empty_response also handles response_truncated.
  • [ ] Nothing depends on a cut-off or blocked reply succeeding with "".
  • [ ] WorkItemResult is built by keyword.