Skip to content

Add dependency injection system#25

Open
DaviddeBest-TNO wants to merge 18 commits into
mainfrom
11-dependency-injection
Open

Add dependency injection system#25
DaviddeBest-TNO wants to merge 18 commits into
mainfrom
11-dependency-injection

Conversation

@DaviddeBest-TNO
Copy link
Copy Markdown
Contributor

Adds FastAPI-like dependency injection system.
Define dependencies in handler arguments with a factory function that are loaded once per handler and work recursively (dependencies define their own dependencies), see example.

DaviddeBest-TNO and others added 18 commits May 11, 2026 13:13
- Add KnowledgeBaseBuilder in src/knowledge_base_builder.py
- KnowledgeBase.from_settings() now returns a KnowledgeBaseBuilder instead
  of a KnowledgeBase; KnowledgeBase has no _build_settings field
- KnowledgeBaseBuilder.handler(name, func) attaches a handler to an
  ANSWER or REACT KI declared in settings
- ASK and POST KIs are auto-registered from settings at builder.build() time
- builder.build() raises ValueError if any ANSWER/REACT KI has no handler
- Export KnowledgeBaseBuilder from src/__init__.py
- Update test_configuration.py to use the builder pattern
- Add tests/test_knowledge_base_builder.py with 12 new behaviour tests
- Update CONTEXT.md to reflect new layout and builder API

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Handlers can now declare dependencies using Depends() in Annotated type
hints. The framework resolves them at call time before invoking the handler.

  from typing import Annotated
  from src import Depends

  def get_db() -> MyDatabase:
      return MyDatabase(url='...')

  @kb.answer_ki(name='...', graph_pattern='...')
  def handler(
      binding_set: list[PersonBinding],
      info: KnowledgeInteractionInfo,
      db: Annotated[MyDatabase, Depends(get_db)],
  ) -> list[PersonBinding]:
      return db.query(binding_set)

- src/depends.py: Depends(factory, cache=True) dataclass
- src/di.py: resolve_dependencies() — inspects Annotated hints, resolves
  transitively, caches per-call by factory identity when cache=True
- KnowledgeBase.call(): resolves deps and passes as kwargs before handler call
- Depends exported from src public API

Behaviour:
- Sync-only factories (async deferred to a follow-up issue)
- Transitive resolution: factories can themselves declare Depends params
- cache=True (default): factory called once per KI call, result shared
- cache=False: factory called fresh every time it is needed

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Demonstrates Depends() with a realistic sensor-readings KB:
- Basic injection: SensorRepository injected via Depends(get_sensor_repository)
- Transitive deps: get_sensor_repository declares Depends(get_config)
- Shared cache: get_config called once even though both the factory and
  the handler parameter depend on it

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@DaviddeBest-TNO DaviddeBest-TNO requested a review from Sophietje May 13, 2026 08:49
@DaviddeBest-TNO DaviddeBest-TNO self-assigned this May 13, 2026
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.

1 participant