right-rag 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- right_rag-0.1.0/.claude/skills/right-rag/SKILL.md +112 -0
- right_rag-0.1.0/.codex/skills/right-rag/SKILL.md +128 -0
- right_rag-0.1.0/.codex/skills/right-rag/agents/openai.yaml +4 -0
- right_rag-0.1.0/.github/workflows/ci.yml +34 -0
- right_rag-0.1.0/.github/workflows/publish.yml +37 -0
- right_rag-0.1.0/.gitignore +19 -0
- right_rag-0.1.0/.python-version +1 -0
- right_rag-0.1.0/AGENTS.md +222 -0
- right_rag-0.1.0/CLAUDE.md +200 -0
- right_rag-0.1.0/LICENSE +21 -0
- right_rag-0.1.0/PKG-INFO +552 -0
- right_rag-0.1.0/README.md +541 -0
- right_rag-0.1.0/eval/cases.example.json +23 -0
- right_rag-0.1.0/main.py +0 -0
- right_rag-0.1.0/pyproject.toml +21 -0
- right_rag-0.1.0/spec/__init__.py +0 -0
- right_rag-0.1.0/spec/answer_generators/__init__.py +1 -0
- right_rag-0.1.0/spec/answer_generators/default.py +21 -0
- right_rag-0.1.0/spec/chunk_parsers/__init__.py +0 -0
- right_rag-0.1.0/spec/chunk_parsers/default.py +47 -0
- right_rag-0.1.0/spec/chunk_savers/__init__.py +0 -0
- right_rag-0.1.0/spec/chunk_savers/default.py +88 -0
- right_rag-0.1.0/spec/document_loaders/__init__.py +0 -0
- right_rag-0.1.0/spec/document_loaders/default.py +97 -0
- right_rag-0.1.0/spec/evaluators/__init__.py +1 -0
- right_rag-0.1.0/spec/evaluators/default.py +119 -0
- right_rag-0.1.0/spec/reporters/__init__.py +1 -0
- right_rag-0.1.0/spec/reporters/default.py +100 -0
- right_rag-0.1.0/spec/retrievers/__init__.py +1 -0
- right_rag-0.1.0/spec/retrievers/default.py +55 -0
- right_rag-0.1.0/spec/unit_parsers/__init__.py +0 -0
- right_rag-0.1.0/spec/unit_parsers/default.py +50 -0
- right_rag-0.1.0/spec/unit_savers/__init__.py +0 -0
- right_rag-0.1.0/spec/unit_savers/default.py +93 -0
- right_rag-0.1.0/src/right_rag/__init__.py +2 -0
- right_rag-0.1.0/src/right_rag/__main__.py +6 -0
- right_rag-0.1.0/src/right_rag/cli.py +130 -0
- right_rag-0.1.0/src/right_rag/interfaces.py +155 -0
- right_rag-0.1.0/src/right_rag/model.py +481 -0
- right_rag-0.1.0/src/right_rag/pipeline.py +1011 -0
- right_rag-0.1.0/src/right_rag/pipeline_state.py +154 -0
- right_rag-0.1.0/src/right_rag/registry.py +455 -0
- right_rag-0.1.0/src/right_rag/spec/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/answer_generators/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/answer_generators/default.py +21 -0
- right_rag-0.1.0/src/right_rag/spec/chunk_parsers/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/chunk_parsers/default.py +47 -0
- right_rag-0.1.0/src/right_rag/spec/chunk_savers/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/chunk_savers/default.py +88 -0
- right_rag-0.1.0/src/right_rag/spec/document_loaders/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/document_loaders/default.py +97 -0
- right_rag-0.1.0/src/right_rag/spec/evaluators/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/evaluators/default.py +119 -0
- right_rag-0.1.0/src/right_rag/spec/reporters/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/reporters/default.py +100 -0
- right_rag-0.1.0/src/right_rag/spec/retrievers/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/retrievers/default.py +55 -0
- right_rag-0.1.0/src/right_rag/spec/unit_parsers/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/unit_parsers/default.py +50 -0
- right_rag-0.1.0/src/right_rag/spec/unit_savers/__init__.py +1 -0
- right_rag-0.1.0/src/right_rag/spec/unit_savers/default.py +93 -0
- right_rag-0.1.0/tests/__init__.py +1 -0
- right_rag-0.1.0/tests/test_cli.py +33 -0
- right_rag-0.1.0/tests/test_default_plugins.py +136 -0
- right_rag-0.1.0/tests/test_evaluation.py +75 -0
- right_rag-0.1.0/tests/test_model.py +67 -0
- right_rag-0.1.0/tests/test_pipeline.py +53 -0
- right_rag-0.1.0/tests/test_pipeline_state.py +48 -0
- right_rag-0.1.0/tests/test_registry.py +35 -0
- right_rag-0.1.0/uv.lock +3291 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: right-rag
|
|
3
|
+
description: Work on right-rag domain-structured RAG repositories. Use when the user asks to inspect, extend, run, debug, query, or evaluate a right-rag project; create or modify document loaders, unit parsers, chunk parsers, savers, retrievers, answer generators, evaluators, reporters, pipelines, or tests; design domain-specific RAG behavior without coupling the framework to vector, keyword, SQL, graph, or any specific search method.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Right RAG
|
|
7
|
+
|
|
8
|
+
## Core Model
|
|
9
|
+
|
|
10
|
+
Treat right-rag as a domain-structured RAG template, not a plain text chunker.
|
|
11
|
+
Keep the framework generic and put domain logic in `spec/` plugins.
|
|
12
|
+
|
|
13
|
+
The pipeline shape is:
|
|
14
|
+
|
|
15
|
+
- Index: document loader -> unit parser -> chunk parser -> unit/chunk savers -> artifacts.
|
|
16
|
+
- Query: one user query -> retrievers read artifacts -> answer generator combines retrieved values.
|
|
17
|
+
- Evaluate: eval cases -> query pipeline -> evaluator -> reporter.
|
|
18
|
+
|
|
19
|
+
Do not assume retrieval means vector search, keyword search, BM25, SQL, or graph traversal. A saver may store however it wants, and its produced artifact should expose the retrieval/use behavior needed by retrievers.
|
|
20
|
+
|
|
21
|
+
## Before Editing
|
|
22
|
+
|
|
23
|
+
Inspect local state first:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
git status --short
|
|
27
|
+
uv sync
|
|
28
|
+
python -m compileall src/right_rag
|
|
29
|
+
python -m unittest discover -s tests
|
|
30
|
+
uv run python -c "from right_rag.registry import build_registry; r=build_registry(); print(r.document_loaders, r.unit_parsers, r.chunk_parsers, r.unit_savers, r.chunk_savers)"
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
Respect dirty worktrees. Do not revert user changes or generated outputs unless explicitly asked.
|
|
34
|
+
|
|
35
|
+
## Extension Points
|
|
36
|
+
|
|
37
|
+
Prefer adding or editing plugins under `spec/` before changing core files:
|
|
38
|
+
|
|
39
|
+
- `spec/document_loaders/`: load source documents.
|
|
40
|
+
- `spec/unit_parsers/`: parse domain units and return `ParsedUnit`.
|
|
41
|
+
- `spec/chunk_parsers/`: chunk from semantic `Unit` objects.
|
|
42
|
+
- `spec/unit_savers/`: persist units and return unit artifacts.
|
|
43
|
+
- `spec/chunk_savers/`: persist chunks and return chunk artifacts.
|
|
44
|
+
- `spec/retrievers/`: read all artifacts and decide how to retrieve.
|
|
45
|
+
- `spec/answer_generators/`: generate an answer from retrieved values.
|
|
46
|
+
- `spec/evaluators/`: score query outputs.
|
|
47
|
+
- `spec/reporters/`: write evaluation reports.
|
|
48
|
+
|
|
49
|
+
Keep contracts small. Add a new abstraction only when it removes real coupling or is required for third-party plugins.
|
|
50
|
+
|
|
51
|
+
## Parser Rules
|
|
52
|
+
|
|
53
|
+
Model the author's real document structure:
|
|
54
|
+
|
|
55
|
+
- laws: act -> chapter -> section -> clause -> subclause
|
|
56
|
+
- contracts: agreement -> article -> clause -> schedule item
|
|
57
|
+
- policies: policy -> section -> rule -> exception
|
|
58
|
+
- manuals: manual -> chapter -> procedure -> step
|
|
59
|
+
- academic papers: paper -> section -> subsection -> paragraph/table/figure note
|
|
60
|
+
|
|
61
|
+
`UnitParser.parse_document()` returns `Iterable[ParsedUnit]`, not `Unit`. The core assigns ids, document ids, parent ids, raw text, source spans, and change replay.
|
|
62
|
+
|
|
63
|
+
Do not add catch-all production parsers. `parser_can_handle_document()` should be narrow, and parser acceptance should not overlap. Reject unsupported formats visibly instead of creating one huge document unit.
|
|
64
|
+
|
|
65
|
+
## Chunking
|
|
66
|
+
|
|
67
|
+
Chunk inside one `Unit`; every chunk must trace back to its unit. Keep chunks semantically complete: definition, rule, exception, method, condition, table row, or procedure step.
|
|
68
|
+
|
|
69
|
+
Carry citation and filtering attributes when available: source path, page, heading path, section number, role, unit type, effective date, jurisdiction, party, method, dataset, or citation.
|
|
70
|
+
|
|
71
|
+
## Artifacts And Retrieval
|
|
72
|
+
|
|
73
|
+
Savers define how stored data can be used later. A unit saver creates a unit artifact; a chunk saver creates a chunk artifact. Retrievers receive all artifacts, usually grouped by saver name, and decide how to combine them.
|
|
74
|
+
|
|
75
|
+
Design artifacts by capability, not storage brand:
|
|
76
|
+
|
|
77
|
+
- A vector-backed artifact may expose semantic search.
|
|
78
|
+
- A SQL-backed artifact may expose filter/query methods.
|
|
79
|
+
- A graph-backed artifact may expose traversal.
|
|
80
|
+
- A custom artifact may expose any domain-specific lookup.
|
|
81
|
+
|
|
82
|
+
Retrievers should not need to know saver implementation details. They should call artifact methods or protocol capabilities and produce retrieved value items for answer generation.
|
|
83
|
+
|
|
84
|
+
## Query Parameters
|
|
85
|
+
|
|
86
|
+
Keep user-facing query simple: one query string plus optional parameters. Broadcast generic parameters to all retrievers. Allow retriever-specific overrides only when explicitly namespaced by the CLI or request format.
|
|
87
|
+
|
|
88
|
+
Do not hard-code parameter names like `top_k` in core logic. Let each retriever declare or parse the parameters it supports so command help and validation can follow the selected retrievers.
|
|
89
|
+
|
|
90
|
+
## Evaluation
|
|
91
|
+
|
|
92
|
+
Provide a default evaluator only as smoke/regression coverage. Real projects should customize `spec/evaluators/` for their domain.
|
|
93
|
+
|
|
94
|
+
Useful default checks:
|
|
95
|
+
|
|
96
|
+
- expected retrieved ids are present
|
|
97
|
+
- answer contains required text
|
|
98
|
+
- retrieved evidence contains required text
|
|
99
|
+
- forbidden text is absent
|
|
100
|
+
- simple hit/recall/overlap metrics
|
|
101
|
+
|
|
102
|
+
Reports should be generated by reporters under `spec/reporters/`, commonly Markdown for humans and JSON for automation.
|
|
103
|
+
|
|
104
|
+
## Useful Commands
|
|
105
|
+
|
|
106
|
+
```powershell
|
|
107
|
+
right-rag index
|
|
108
|
+
right-rag query "your question"
|
|
109
|
+
right-rag evaluate eval\cases.example.json --output output\evaluation\report.md
|
|
110
|
+
python -m compileall src/right_rag
|
|
111
|
+
python -m unittest discover -s tests
|
|
112
|
+
```
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: right-rag
|
|
3
|
+
description: Work on right-rag domain-structured RAG repositories. Use when Codex needs to inspect, extend, run, debug, query, or evaluate a right-rag project; create or modify document loaders, unit parsers, chunk parsers, savers, retrievers, answer generators, evaluators, reporters, pipelines, or tests; design domain-specific RAG behavior without coupling the framework to vector, keyword, SQL, graph, or any specific search method.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Right RAG
|
|
7
|
+
|
|
8
|
+
## Core Model
|
|
9
|
+
|
|
10
|
+
Treat right-rag as a domain-structured RAG template, not a plain text chunker.
|
|
11
|
+
Keep the framework generic and put domain logic in `spec/` plugins.
|
|
12
|
+
|
|
13
|
+
The default shape is:
|
|
14
|
+
|
|
15
|
+
- Index: document loader -> unit parser -> chunk parser -> unit/chunk savers -> artifacts.
|
|
16
|
+
- Query: one user query -> retrievers read artifacts -> answer generator combines retrieved values.
|
|
17
|
+
- Evaluate: eval cases -> query pipeline -> evaluator -> reporter.
|
|
18
|
+
|
|
19
|
+
Do not assume retrieval means vector search, keyword search, BM25, SQL, or graph traversal. A saver may store however it wants, and its produced artifact should expose the retrieval/use behavior needed by retrievers.
|
|
20
|
+
|
|
21
|
+
## Before Editing
|
|
22
|
+
|
|
23
|
+
In a right-rag repo, first inspect local structure and current state:
|
|
24
|
+
|
|
25
|
+
```powershell
|
|
26
|
+
uv sync
|
|
27
|
+
python -m compileall src/right_rag
|
|
28
|
+
python -m unittest discover -s tests
|
|
29
|
+
uv run python -c "from right_rag.registry import build_registry; r=build_registry(); print(r.document_loaders, r.unit_parsers, r.chunk_parsers, r.unit_savers, r.chunk_savers)"
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
Respect dirty worktrees. Do not revert user changes or generated outputs unless explicitly asked.
|
|
33
|
+
|
|
34
|
+
## Extension Points
|
|
35
|
+
|
|
36
|
+
Prefer adding or editing plugins under `spec/` before changing core files:
|
|
37
|
+
|
|
38
|
+
- `spec/document_loaders/`: load source documents.
|
|
39
|
+
- `spec/unit_parsers/`: parse domain units and return `ParsedUnit`.
|
|
40
|
+
- `spec/chunk_parsers/`: chunk from semantic `Unit` objects.
|
|
41
|
+
- `spec/unit_savers/`: persist units and return unit artifacts.
|
|
42
|
+
- `spec/chunk_savers/`: persist chunks and return chunk artifacts.
|
|
43
|
+
- `spec/retrievers/`: read all artifacts and decide how to retrieve.
|
|
44
|
+
- `spec/answer_generators/`: generate an answer from retrieved values.
|
|
45
|
+
- `spec/evaluators/`: score query outputs.
|
|
46
|
+
- `spec/reporters/`: write evaluation reports.
|
|
47
|
+
|
|
48
|
+
Keep contracts small. Add a new abstraction only when it removes real coupling or is required for third-party plugins.
|
|
49
|
+
|
|
50
|
+
## Parser Rules
|
|
51
|
+
|
|
52
|
+
Model the author's real document structure. Examples:
|
|
53
|
+
|
|
54
|
+
- laws: act -> chapter -> section -> clause -> subclause
|
|
55
|
+
- contracts: agreement -> article -> clause -> schedule item
|
|
56
|
+
- policies: policy -> section -> rule -> exception
|
|
57
|
+
- manuals: manual -> chapter -> procedure -> step
|
|
58
|
+
- academic papers: paper -> section -> subsection -> paragraph/table/figure note
|
|
59
|
+
|
|
60
|
+
`UnitParser.parse_document()` returns `Iterable[ParsedUnit]`, not `Unit`. The core assigns ids, document ids, parent ids, raw text, source spans, and change replay.
|
|
61
|
+
|
|
62
|
+
Do not add catch-all production parsers. `parser_can_handle_document()` should be narrow, and parser acceptance should not overlap. Reject unsupported formats visibly instead of creating one huge document unit.
|
|
63
|
+
|
|
64
|
+
## Chunking
|
|
65
|
+
|
|
66
|
+
Chunk inside one `Unit`; every chunk must trace back to its unit. Keep chunks semantically complete: definition, rule, exception, method, condition, table row, or procedure step.
|
|
67
|
+
|
|
68
|
+
Carry citation and filtering attributes when available: source path, page, heading path, section number, role, unit type, effective date, jurisdiction, party, method, dataset, or citation.
|
|
69
|
+
|
|
70
|
+
## Artifacts And Retrieval
|
|
71
|
+
|
|
72
|
+
Savers define how stored data can be used later. A unit saver creates a unit artifact; a chunk saver creates a chunk artifact. Retrievers receive all artifacts, usually grouped by saver name, and decide how to combine them.
|
|
73
|
+
|
|
74
|
+
Design artifacts by capability, not storage brand:
|
|
75
|
+
|
|
76
|
+
- A vector-backed artifact may expose semantic search.
|
|
77
|
+
- A SQL-backed artifact may expose filter/query methods.
|
|
78
|
+
- A graph-backed artifact may expose traversal.
|
|
79
|
+
- A custom artifact may expose any domain-specific lookup.
|
|
80
|
+
|
|
81
|
+
Retrievers should not need to know the implementation details of a saver. They should call artifact methods or protocol capabilities and produce retrieved value items for answer generation.
|
|
82
|
+
|
|
83
|
+
## Query Parameters
|
|
84
|
+
|
|
85
|
+
Keep user-facing query simple: one query string plus optional parameters. Broadcast generic parameters to all retrievers. Allow retriever-specific overrides only when explicitly namespaced by the CLI or request format.
|
|
86
|
+
|
|
87
|
+
Do not hard-code parameter names like `top_k` in core logic. Let each retriever declare or parse the parameters it supports so command help and validation can follow the selected retrievers.
|
|
88
|
+
|
|
89
|
+
## Evaluation
|
|
90
|
+
|
|
91
|
+
Provide a default evaluator only as smoke/regression coverage. Make it explicit that real projects should customize `spec/evaluators/` for their domain.
|
|
92
|
+
|
|
93
|
+
Useful default checks:
|
|
94
|
+
|
|
95
|
+
- expected retrieved ids are present
|
|
96
|
+
- answer contains required text
|
|
97
|
+
- retrieved evidence contains required text
|
|
98
|
+
- forbidden text is absent
|
|
99
|
+
- simple hit/recall/overlap metrics
|
|
100
|
+
|
|
101
|
+
Reports should be generated by reporters under `spec/reporters/`, commonly Markdown for humans and JSON for automation.
|
|
102
|
+
|
|
103
|
+
## Useful Commands
|
|
104
|
+
|
|
105
|
+
Run index:
|
|
106
|
+
|
|
107
|
+
```powershell
|
|
108
|
+
right-rag index
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
Run query:
|
|
112
|
+
|
|
113
|
+
```powershell
|
|
114
|
+
right-rag query "your question"
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Run evaluation:
|
|
118
|
+
|
|
119
|
+
```powershell
|
|
120
|
+
right-rag evaluate eval\cases.example.json --output output\evaluation\report.md
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
Final verification after changes:
|
|
124
|
+
|
|
125
|
+
```powershell
|
|
126
|
+
python -m compileall src/right_rag
|
|
127
|
+
python -m unittest discover -s tests
|
|
128
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
test:
|
|
10
|
+
runs-on: ubuntu-latest
|
|
11
|
+
steps:
|
|
12
|
+
- uses: actions/checkout@v4
|
|
13
|
+
|
|
14
|
+
- uses: actions/setup-python@v5
|
|
15
|
+
with:
|
|
16
|
+
python-version: "3.13"
|
|
17
|
+
|
|
18
|
+
- name: Install uv
|
|
19
|
+
run: python -m pip install uv
|
|
20
|
+
|
|
21
|
+
- name: Install dependencies
|
|
22
|
+
run: uv sync
|
|
23
|
+
|
|
24
|
+
- name: Compile package
|
|
25
|
+
run: uv run python -m compileall src/right_rag
|
|
26
|
+
|
|
27
|
+
- name: Run tests
|
|
28
|
+
run: uv run python -m unittest discover -s tests
|
|
29
|
+
|
|
30
|
+
- name: Check CLI
|
|
31
|
+
run: uv run right-rag --help
|
|
32
|
+
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: uv build
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
name: Publish
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
permissions:
|
|
8
|
+
contents: read
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
publish:
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
environment: pypi
|
|
14
|
+
permissions:
|
|
15
|
+
id-token: write
|
|
16
|
+
contents: read
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: actions/setup-python@v5
|
|
21
|
+
with:
|
|
22
|
+
python-version: "3.13"
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
run: python -m pip install uv
|
|
26
|
+
|
|
27
|
+
- name: Install dependencies
|
|
28
|
+
run: uv sync
|
|
29
|
+
|
|
30
|
+
- name: Run tests
|
|
31
|
+
run: uv run python -m unittest discover -s tests
|
|
32
|
+
|
|
33
|
+
- name: Build package
|
|
34
|
+
run: uv build
|
|
35
|
+
|
|
36
|
+
- name: Publish to PyPI
|
|
37
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
# Python-generated files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[oc]
|
|
4
|
+
build/
|
|
5
|
+
dist/
|
|
6
|
+
wheels/
|
|
7
|
+
*.egg-info
|
|
8
|
+
|
|
9
|
+
# Virtual environments
|
|
10
|
+
.venv
|
|
11
|
+
|
|
12
|
+
# Local source documents
|
|
13
|
+
data/documents/*
|
|
14
|
+
|
|
15
|
+
# Pipeline state
|
|
16
|
+
.right-rag-state.json
|
|
17
|
+
|
|
18
|
+
# Generated pipeline output
|
|
19
|
+
output/
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.13
|
|
@@ -0,0 +1,222 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
Guide for AI agents working in this repository.
|
|
4
|
+
|
|
5
|
+
## Setup First
|
|
6
|
+
|
|
7
|
+
Before changing code, make sure the project is runnable:
|
|
8
|
+
|
|
9
|
+
```powershell
|
|
10
|
+
uv sync
|
|
11
|
+
python -m compileall src/right_rag
|
|
12
|
+
python -m unittest discover -s tests
|
|
13
|
+
uv run python -c "from right_rag.registry import build_registry; r=build_registry(); print(r.document_loaders, r.unit_parsers, r.chunk_parsers, r.unit_savers, r.chunk_savers)"
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
Source documents go in `data/documents/`. Pipeline output goes to `output/`.
|
|
17
|
+
|
|
18
|
+
## How This Repo Works
|
|
19
|
+
|
|
20
|
+
`right-rag` keeps the pipeline core separate from task-specific logic in
|
|
21
|
+
`spec/`.
|
|
22
|
+
|
|
23
|
+
Core files:
|
|
24
|
+
|
|
25
|
+
- `src/right_rag/interfaces.py`: plugin contracts.
|
|
26
|
+
- `src/right_rag/model.py`: `Document`, `ParsedUnit`, `Unit`, `Chunk`, change replay helpers.
|
|
27
|
+
- `src/right_rag/registry.py`: auto-discovers plugins under `spec/`.
|
|
28
|
+
- `src/right_rag/pipeline.py`: orchestration, incremental state, parser output normalization.
|
|
29
|
+
- `src/right_rag/pipeline_state.py`: JSON serialization and stable hashing.
|
|
30
|
+
- `tests/`: stdlib `unittest` suite for core behavior and default plugins.
|
|
31
|
+
|
|
32
|
+
Prefer editing or adding plugins in `spec/` before changing the pipeline core.
|
|
33
|
+
|
|
34
|
+
## Adapt Plugins To The Documents
|
|
35
|
+
|
|
36
|
+
`right-rag` is a domain-structured RAG pipeline, not a plain text chunker. The
|
|
37
|
+
default unit/chunk parsers are smoke-test tools only. Never use them for
|
|
38
|
+
production data. Real work belongs in domain parsers under `spec/`.
|
|
39
|
+
|
|
40
|
+
Read the user's actual document type before editing. Choose domain units from
|
|
41
|
+
the document's real structure:
|
|
42
|
+
|
|
43
|
+
- laws: act -> chapter -> section -> clause -> subclause
|
|
44
|
+
- contracts: agreement -> article -> clause -> schedule item
|
|
45
|
+
- policies: policy -> section -> rule -> exception
|
|
46
|
+
- manuals: manual -> chapter -> procedure -> step
|
|
47
|
+
- academic papers: paper -> section -> subsection -> paragraph/table/figure note
|
|
48
|
+
|
|
49
|
+
Plugin folders:
|
|
50
|
+
|
|
51
|
+
- `spec/document_loaders/`: `DocumentLoader`
|
|
52
|
+
- `spec/unit_parsers/`: `UnitParser` returning `ParsedUnit`
|
|
53
|
+
- `spec/chunk_parsers/`: `ChunkParser`
|
|
54
|
+
- `spec/unit_savers/`: `UnitSaver`
|
|
55
|
+
- `spec/chunk_savers/`: `ChunkSaver`
|
|
56
|
+
|
|
57
|
+
Use the default loader unless the source is not a normal local document folder
|
|
58
|
+
or its output is not enough. For PDFs, the default loader uses `pypdfium2` text
|
|
59
|
+
extraction first to avoid Docling OCR/preprocess memory errors; non-PDF files
|
|
60
|
+
still go through Docling. Scanned PDFs without a text layer need a custom OCR
|
|
61
|
+
loader.
|
|
62
|
+
|
|
63
|
+
## How To Design Parsers
|
|
64
|
+
|
|
65
|
+
1. Survey the documents and count the real formats.
|
|
66
|
+
2. Create one parser per stable document format.
|
|
67
|
+
3. Identify structural markers: `หมวด`, `มาตรา`, `ข้à¸`, `Section`, `Chapter`,
|
|
68
|
+
definitions, penalties, duties, prohibitions, transitory provisions, tables,
|
|
69
|
+
schedules, and appendices.
|
|
70
|
+
4. Make `UnitParser` return a `ParsedUnit` tree.
|
|
71
|
+
5. Make `ChunkParser` chunk from semantic `Unit` objects, not raw text.
|
|
72
|
+
|
|
73
|
+
Each parser must implement `parser_can_handle_document()` narrowly. Multiple
|
|
74
|
+
parsers are fine when the corpus has multiple formats, but their acceptance
|
|
75
|
+
rules should not overlap. Do not add catch-all parsers. Do not fallback to
|
|
76
|
+
`ParsedUnit(topic="document", fulltext=document.text)` or one huge chunk when
|
|
77
|
+
structure is missing. Reject/report the reason instead.
|
|
78
|
+
|
|
79
|
+
## Unit Parser Contract
|
|
80
|
+
|
|
81
|
+
`UnitParser.parse_document()` returns `Iterable[ParsedUnit]`, not `Unit`.
|
|
82
|
+
|
|
83
|
+
A `ParsedUnit` contains only what the parser should know:
|
|
84
|
+
|
|
85
|
+
```python
|
|
86
|
+
ParsedUnit(
|
|
87
|
+
topic="Clause 1",
|
|
88
|
+
fulltext="...",
|
|
89
|
+
temporal_topic="Procurement Rules 2569 Clause 1",
|
|
90
|
+
source_start=120,
|
|
91
|
+
source_end=260,
|
|
92
|
+
attributes={"page_start": 4, "page_end": 5, "clause": "1"},
|
|
93
|
+
metadata={"heading_path": ["Part 1", "Clause 1"]},
|
|
94
|
+
subunits=[
|
|
95
|
+
ParsedUnit(
|
|
96
|
+
topic="Subclause 1",
|
|
97
|
+
temporal_topic="Procurement Rules 2569 Clause 1 Subclause 1",
|
|
98
|
+
fulltext="...",
|
|
99
|
+
)
|
|
100
|
+
],
|
|
101
|
+
)
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
The library handles:
|
|
105
|
+
|
|
106
|
+
- `Unit.id`
|
|
107
|
+
- `document_id`
|
|
108
|
+
- `parent_id`
|
|
109
|
+
- copying `source_start` and `source_end` to `Unit`
|
|
110
|
+
- computing `Unit.raw_text` from `Document.text[source_start:source_end]`
|
|
111
|
+
- recursive subunit conversion
|
|
112
|
+
- `AddUnit`, `EditUnit`, `DeleteUnit`
|
|
113
|
+
- attribute changes
|
|
114
|
+
- parent `AddSubUnit`, `EditSubUnit`, `DeleteSubUnit`
|
|
115
|
+
- current-stage replay from changes
|
|
116
|
+
|
|
117
|
+
Identity uses `topic` plus the parent path. Metadata is stored only and is not
|
|
118
|
+
used for processing decisions. Child ids include the parent path, so repeated
|
|
119
|
+
topics under different parents do not collide.
|
|
120
|
+
|
|
121
|
+
## Unit Parser Best Practices
|
|
122
|
+
|
|
123
|
+
- Preserve the author's hierarchy. Do not flatten meaningful sections.
|
|
124
|
+
- Keep `topic` stable and normalized.
|
|
125
|
+
- Use `temporal_topic` only when the parser can identify version/date context.
|
|
126
|
+
- Put hierarchy in `ParsedUnit.subunits`.
|
|
127
|
+
- Set `source_start` and `source_end` to character offsets in `Document.text`.
|
|
128
|
+
- Keep `fulltext` faithful: no summaries, rewrites, translations, or invented
|
|
129
|
+
text.
|
|
130
|
+
- Store provenance in `attributes` or `metadata`: page, heading path, section
|
|
131
|
+
number, table id, figure id, citation, source filename.
|
|
132
|
+
- Mark heuristic extraction in metadata instead of pretending it is certain.
|
|
133
|
+
- Do not create `Unit` inside a unit parser.
|
|
134
|
+
|
|
135
|
+
## Chunk Parser Best Practices
|
|
136
|
+
|
|
137
|
+
Chunk parsers should make retrieval accurate and citable.
|
|
138
|
+
|
|
139
|
+
- Chunk inside one `Unit`; do not mix unrelated units.
|
|
140
|
+
- Include parent context in chunk text or attributes: `temporal_topic`, section
|
|
141
|
+
number, citation, and source path.
|
|
142
|
+
- Keep chunks semantically complete: definition, rule, exception, method,
|
|
143
|
+
condition, table row, or procedure step.
|
|
144
|
+
- Do not split controlling language from its exception or limitation.
|
|
145
|
+
- Use attributes for filters: document type, jurisdiction, effective date,
|
|
146
|
+
section number, party, topic, method, dataset, citation.
|
|
147
|
+
- Include `parser_name`, `unit_type`, `hierarchy`, and `role` when available.
|
|
148
|
+
- Keep source text grounded. Add labels only when they improve citation without
|
|
149
|
+
changing meaning.
|
|
150
|
+
- Prefer fewer useful chunks over many tiny fragments.
|
|
151
|
+
|
|
152
|
+
## Anti-Patterns
|
|
153
|
+
|
|
154
|
+
- One parser accepts every document.
|
|
155
|
+
- `parser_can_handle_document()` returns `True` for any non-empty text.
|
|
156
|
+
- Fallback to one document-sized unit or chunk.
|
|
157
|
+
- Chunking by text length before parsing structure.
|
|
158
|
+
- Using metadata instead of `ParsedUnit.subunits` for hierarchy.
|
|
159
|
+
- Assuming every document has the same format.
|
|
160
|
+
|
|
161
|
+
## Production Checklist
|
|
162
|
+
|
|
163
|
+
- Each parser documents what it accepts.
|
|
164
|
+
- Parser acceptance does not overlap.
|
|
165
|
+
- Documents with no parser are visible and reviewed.
|
|
166
|
+
- `unit_type` covers the domain.
|
|
167
|
+
- Domain roles are represented: definition, penalty, duty, prohibition,
|
|
168
|
+
transitory provision, or equivalents.
|
|
169
|
+
- Chunk attributes carry `parser_name`, `unit_type`, `hierarchy`, and `role`.
|
|
170
|
+
- No default parser and no catch-all parser is selected for production.
|
|
171
|
+
|
|
172
|
+
## Academic And Practical Accuracy
|
|
173
|
+
|
|
174
|
+
For scholarly, legal, policy, and technical RAG, accuracy means retrieval can be
|
|
175
|
+
audited back to source evidence.
|
|
176
|
+
|
|
177
|
+
- Preserve source file, page, section, heading path, citation, table, and figure
|
|
178
|
+
references when available.
|
|
179
|
+
- Separate extraction from interpretation. Parsers extract; downstream systems
|
|
180
|
+
summarize or reason.
|
|
181
|
+
- Preserve version context: date, edition, amendment, jurisdiction, policy
|
|
182
|
+
version, publication year.
|
|
183
|
+
- Make boundaries match the argument or rule in the document.
|
|
184
|
+
- Test with real domain questions and inspect saved unit/chunk JSON.
|
|
185
|
+
- Use parser coverage in `.right-rag-state.json` as the development loop after
|
|
186
|
+
a full pipeline run.
|
|
187
|
+
|
|
188
|
+
## Parser Coverage
|
|
189
|
+
|
|
190
|
+
After `uv run right-rag index`, each unit parser state records:
|
|
191
|
+
|
|
192
|
+
- `document_chars`
|
|
193
|
+
- `covered_chars`
|
|
194
|
+
- `uncovered_chars`
|
|
195
|
+
- `coverage_percent`
|
|
196
|
+
- `units_total`
|
|
197
|
+
- `units_with_source_span`
|
|
198
|
+
- merged `source_ranges`
|
|
199
|
+
|
|
200
|
+
Coverage is computed from all active units and subunits with source spans. Low
|
|
201
|
+
coverage means the parser missed source text. Very high coverage with very few
|
|
202
|
+
units may mean the units are too broad.
|
|
203
|
+
|
|
204
|
+
## Rules
|
|
205
|
+
|
|
206
|
+
- Keep changes small and local.
|
|
207
|
+
- Prefer editing `spec/` over core files.
|
|
208
|
+
- Use stdlib before adding dependencies.
|
|
209
|
+
- Add the smallest runnable check for non-trivial parser logic.
|
|
210
|
+
- Do not commit generated `output/`, `.right-rag-state.json`, or local source
|
|
211
|
+
documents.
|
|
212
|
+
|
|
213
|
+
## Checks
|
|
214
|
+
|
|
215
|
+
```powershell
|
|
216
|
+
python -m compileall src/right_rag
|
|
217
|
+
python -m unittest discover -s tests
|
|
218
|
+
uv run python -c "from right_rag.registry import build_registry; r=build_registry(); print(r.document_loaders, r.unit_parsers, r.chunk_parsers, r.unit_savers, r.chunk_savers)"
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
The test suite covers model conversion and change replay, parser coverage,
|
|
222
|
+
state serialization, registry discovery, and default plugins.
|