Skip to content

fix(hooks): expose attempt_number, max_attempts, is_last_attempt on completion:error and completion:last_attempt hooks#2285

Open
Kcstring wants to merge 1 commit into567-labs:mainfrom
Kcstring:feat/expose-retry-metadata-on-error-hooks
Open

fix(hooks): expose attempt_number, max_attempts, is_last_attempt on completion:error and completion:last_attempt hooks#2285
Kcstring wants to merge 1 commit into567-labs:mainfrom
Kcstring:feat/expose-retry-metadata-on-error-hooks

Conversation

@Kcstring
Copy link
Copy Markdown

Summary

Closes #2222

completion:error and completion:last_attempt handlers can now receive retry metadata as keyword arguments — attempt_number, max_attempts, and is_last_attempt — without any breaking changes.

What changed

instructor/core/hooks.pyCompletionErrorHandler Protocol updated to document the kwargs that retry.py already passes:

class CompletionErrorHandler(Protocol):
    def __call__(
        self,
        error: Exception,
        *,
        attempt_number: int = ...,
        max_attempts: int | None = ...,
        is_last_attempt: bool = ...,
    ) -> None: ...

No changes to retry.py — it already passes these kwargs to emit_completion_error() and emit_completion_last_attempt(). The existing inspect.signature fallback in Hooks.emit() means old-style handlers (def handler(error)) continue to work unchanged.

Usage

def on_error(
    error: Exception,
    *,
    attempt_number: int = 1,
    max_attempts: int | None = None,
    is_last_attempt: bool = False,
) -> None:
    severity = "ERROR" if is_last_attempt else "WARNING"
    print(f"[{severity}] attempt {attempt_number}/{max_attempts}: {error}")

client.on("completion:error", on_error)
client.on("completion:last_attempt", on_error)

Tests

9 new unit tests in tests/test_hooks_retry_metadata.py — no real API calls needed:

  • attempt_number forwarded correctly
  • max_attempts forwarded (including None for unbounded)
  • is_last_attempt is False for intermediate errors, True for last attempt
  • Old-style handlers (error-only) still called without breaking

…rror hooks

CompletionErrorHandler Protocol now documents the retry metadata kwargs that
retry.py already passes to emit_completion_error() and
emit_completion_last_attempt(). Old-style handlers (error-only) continue to
work unchanged via the existing inspect.signature fallback in Hooks.emit().

Closes 567-labs#2222
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Expose attempt metadata on completion:error and completion:last_attempt hooks

1 participant