Skip to content

Replace container singleton with request-scoped runtime DI; simplify error logging - #101

Merged
GuanyiLi-Craig merged 2 commits into
mainfrom
runtime-di-and-error-logging
Jun 22, 2026
Merged

Replace container singleton with request-scoped runtime DI; simplify error logging#101
GuanyiLi-Craig merged 2 commits into
mainfrom
runtime-di-and-error-logging

Conversation

@GuanyiLi-Craig

Copy link
Copy Markdown
Contributor

Summary

Replaces the process-global SingletonMeta/Container/container service locator
with explicit, request-scoped dependency injection, and reduces execution-error
logging to a single concise, id-bearing line. No component invoke() signature
changes
— tools, nodes, and commands are untouched.

Runtime DI

  • New grafi/runtime: ExecutionServices (frozen, non-serializable bundle of
    event_store / tracer / error_reporter, each with an in-process
    default_factory default), GrafiRuntime (composition root + invoke entry
    point), and the request-scoped _current_services ContextVar with
    current_services() / bind_services().
  • GrafiRuntime.invoke() binds the services for the invocation; components
    resolve them via current_services(). Propagation relies on asyncio
    context copying (Graphite uses no thread offloads), giving genuine
    per-invocation isolation for concurrent invokes.
  • The four old container read sites (decorator, LLMCommand.get_tool_input,
    EventDrivenWorkflow, WorkflowRun) now read current_services().
  • ReActAgent.run() / a_run() run through a GrafiRuntime (optional
    runtime= param), so the agent API needs no manual scope binding.

Error diagnostics

  • One concise log line per failure, emitted once at the layer closest to it,
    carrying error_id + conversation/invoke/assistant_request ids — the full
    structured record (cause chain, traceback, component fields) is persisted to
    the event store, so the log only points at it.
  • error_id correlation preserved across re-wrapped exceptions; stable wrapper
    messages (no embedded str(cause)); no double-wrapped NodeExecutionError;
    the primary failure is preserved when failed-event persistence fails; a
    misbehaving reporter can never mask the execution failure; EventStorePostgres
    raises EventPersistenceError with operation context consistently.
  • ErrorReporter is a single concrete loguru-backed class (subclass to customize).

Breaking change

SingletonMeta, Container, the global container, register_event_store,
register_tracer, and AssistantBaseBuilder.event_store(...) are removed. Code
that relied on the global container now constructs a GrafiRuntime (or
GrafiRuntime() for in-process defaults) and invokes through it;
assistant.invoke(...) outside a bound scope raises a clear error instead of
silently defaulting. Grafi is pre-1.0; release notes/migration are in the new
runtime guide.

Docs

  • user-guide/containers.mduser-guide/runtime.md (request-scoped DI guide +
    migration table); mkdocs nav updated.
  • Event-store, OpenTelemetry, and MCP-server guides migrated to
    GrafiRuntime/ExecutionServices; builder/assistant guides drop the removed
    .event_store(...) call; direct workflow/tool/assistant examples now run inside
    a bound runtime scope.

Testing

  • pytest tests/702 passed (incl. a new tests/runtime/ suite: DI
    isolation, ContextVar propagation, serialization safety, error reporting).
  • mypy grafi — clean (88 source files).
  • isort + black + flake8 — clean across grafi, tests, tests_integration.
  • Integration examples migrated and byte-compiled; a sample run gets past the
    runtime binding and surfaces the normalized error chain
    (NodeExecutionError → LLMToolException → OpenAIError).

🤖 Generated with Claude Code

GuanyiLi-Craig and others added 2 commits June 22, 2026 19:33
…error logging

Remove the process-global `SingletonMeta`/`Container`/`container` service
locator in favor of explicit, request-scoped dependency injection, and reduce
execution-error logging to a single concise, id-bearing line.

Runtime DI (no component-interface change):
- Add grafi/runtime: `ExecutionServices` (frozen, non-serializable bundle of
  event_store/tracer/error_reporter with in-process default_factory defaults),
  `GrafiRuntime` (composition root + invoke entry point), and the request-scoped
  `_current_services` ContextVar with `current_services()` / `bind_services()`.
- `GrafiRuntime.invoke()` binds the services for the invocation; components
  resolve them via `current_services()`. No `invoke()` signature gains a
  `services` parameter -- tool/provider/node/command overrides are untouched.
  Relies on asyncio context propagation (grafi uses no thread offloads).
- Switch the four container read sites (record_base, llm_command,
  event_driven_workflow, WorkflowRun) to `current_services()`.
- Remove `container`, `SingletonMeta`, `register_event_store`/`register_tracer`,
  and `AssistantBaseBuilder.event_store`. Callers construct a `GrafiRuntime`
  (or `GrafiRuntime()` for in-process defaults) and invoke through it.

Error diagnostics:
- One concise log line per failure, emitted once at the layer closest to the
  failure, carrying error_id + conversation/invoke/assistant_request ids so the
  full structured record (cause chain, traceback, component fields) can be
  pulled from the event store. No traceback dumped to the log.
- Add `error_id` correlation preserved across re-wrapped exceptions; stable
  wrapper messages (no embedded `str(cause)`); no double-wrapped
  NodeExecutionError; preserve the primary failure when failed-event
  persistence fails; EventStorePostgres raises EventPersistenceError with
  operation context consistently.
- `ErrorReporter` is a single concrete loguru-backed class (subclass to
  customize); a misbehaving reporter can never mask the execution failure.

Tests/examples:
- conftest binds a default `ExecutionServices` per test (sync autouse fixture);
  migrate workflow/decorator tests off `container`; add tests/runtime suite
  (DI isolation, ContextVar propagation, serialization safety, error reporting).
- Migrate tests_integration examples to run inside a bound runtime scope.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up to the runtime-DI change: make the agent convenience API a first-class
runtime consumer, tidy the error path, and bring the docs in line.

- ReActAgent.run()/a_run() now run through GrafiRuntime (optional `runtime=`
  param, defaulting to an in-process GrafiRuntime()), so callers no longer wrap
  them in bind_services(...). a_run() simply relays runtime.invoke()'s output.
- _build_error_details walks the exception cause chain once (one
  _error_correlation pass returning error_id + root cause) instead of twice.
- record_base: fix a stale comment describing the pre-simplification logging.
- Docs: replace user-guide/containers.md with user-guide/runtime.md (request-
  scoped DI: ExecutionServices/GrafiRuntime/current_services/bind_services, with
  a migration table) and update mkdocs nav. Migrate the container/registration
  snippets in the event-store, OpenTelemetry, and MCP-server guides to
  GrafiRuntime/ExecutionServices; drop the removed `.event_store(...)` builder
  call from the builder-pattern and assistant guides; run direct
  workflow/tool/assistant examples inside a bound runtime scope.
- gitignore root-level *_manifest.json (generate_manifest test artifact).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 22, 2026 20:02

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot was unable to review this pull request because the user who requested the review has reached their quota limit.

@GuanyiLi-Craig
GuanyiLi-Craig merged commit de6853b into main Jun 22, 2026
19 of 20 checks passed
GuanyiLi-Craig added a commit that referenced this pull request Jun 23, 2026
Releases the changes merged since 0.0.35:
- #100 Refine LLM tools: modern API params
- #101 Replace container singleton with request-scoped runtime DI
- #102 Bump dependencies to clear Dependabot security alerts

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.

2 participants