Skip to content

Feature: Generic LlamaIndex Reader Plugin — wrap any reader via config #384

Description

@evanerwee

Package

lexical-graph

Problem statement

Adding support for new data sources (Confluence, Notion, Slack, Jira, Google Drive, etc.) currently requires writing a bespoke *_reader_provider.py for each one. This doesn't scale — LlamaIndex has 100+ reader packages, and each one follows the same pattern: import, instantiate with credentials, call load_data().

The real differences between readers are configuration (credentials, endpoints, filters), not code (import, instantiate, call, handle errors). We're writing the same boilerplate with different class names.

Proposed solution

A generic LlamaIndexPluginReaderProvider that wraps any LlamaIndex reader with just a config dict — no new Python file needed per reader.

from graphrag_toolkit.lexical_graph.indexing.load.readers.reader_provider_config import LlamaIndexPluginReaderConfig
from graphrag_toolkit.lexical_graph.indexing.load.readers.providers import LlamaIndexPluginReaderProvider

# Confluence — zero bespoke code
config = LlamaIndexPluginReaderConfig(
    package="llama-index-readers-confluence",
    module_path="llama_index.readers.confluence",
    reader_class="ConfluenceReader",
    init_args={"base_url": "https://mycompany.atlassian.net/wiki", "token": "..."},
    load_args={"space_key": "ENG"},
    timeout_seconds=60,
    max_retries=2,
    fail_on_error=False,
)
provider = LlamaIndexPluginReaderProvider(config)
docs = provider.read()

Same pattern for Notion, Slack, Jira, Google Drive, or any of the 100+ LlamaIndex readers.

Features

Feature Description
Dynamic import Resolves any llama-index-readers-* package at runtime
Configurable timeout ThreadPoolExecutor-based timeout prevents hangs
Retry with backoff Exponential backoff on transient errors (429, 503, timeouts)
Auth error detection Recognizes 401/403 patterns — never retried, clear error message
Graceful degradation fail_on_error=False returns [] instead of crashing pipelines
input_source flexibility Auto-fallback if reader doesn't accept the kwarg
Document validation Filters non-Document items, handles generators
Metadata enrichment Optional metadata_fn to tag all documents
Module path resolution Derives llama_index.readers.X from package name automatically

Error handling guarantees

  • Missing package → ReaderImportError with pip install instructions
  • Class not found → ReaderImportError listing available classes
  • Bad constructor args → ValueError with signature hint
  • Auth failure (401/403) → ReaderAuthError, never retried
  • Transient error (429/503) → retried with exponential backoff
  • Timeout → ReaderTimeoutError, retried if attempts remain
  • All retries exhausted → RuntimeError or [] based on config

Test coverage

30 unit tests covering:

  • Happy path (4 tests)
  • Import errors (3)
  • Config validation (2)
  • Auth failures (7 parametrized)
  • Timeout enforcement (2)
  • Retry with backoff (4)
  • Empty results (2)
  • Partial failures / generators (2)
  • Module path resolution (2)
  • Custom load methods (2)

Live tested

$ python3.12 -c "..."  # DadJokesReader via plugin
✅ 1 joke: Why didn't the orange win the race? It ran out of juice.

Implementation

Branch: feat/generic-llama-index-reader-plugin

Files:

  • lexical-graph/src/.../providers/llama_index_plugin_reader_provider.py (302 lines)
  • lexical-graph/src/.../reader_provider_config.py (+34 lines — config dataclass)
  • lexical-graph/src/.../providers/__init__.py (+2 lines — registration)
  • lexical-graph/tests/.../test_llama_index_plugin_reader_provider.py (596 lines)

PR ready to submit on request.

Alternatives considered

  1. Keep writing bespoke providers — doesn't scale, duplicates error handling
  2. Auto-generate providers from LlamaIndex metadata — fragile, breaks on API changes
  3. Generic plugin (this proposal) — one file handles all readers, config-driven, tested

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions