ragfabric-core 0.3.1__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.
- ragfabric_core-0.3.1/.gitignore +49 -0
- ragfabric_core-0.3.1/PKG-INFO +50 -0
- ragfabric_core-0.3.1/README.md +3 -0
- ragfabric_core-0.3.1/pyproject.toml +64 -0
- ragfabric_core-0.3.1/src/ragfabric_core/__init__.py +3 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/contracts.py +70 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/cost.py +91 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/loop.py +574 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/nodes.py +545 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/policy.py +330 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/state.py +176 -0
- ragfabric_core-0.3.1/src/ragfabric_core/agent/tools.py +216 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/api_keys.py +126 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/base.py +14 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/policy.py +124 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/principal.py +64 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/ratelimit.py +16 -0
- ragfabric_core-0.3.1/src/ragfabric_core/auth/service.py +103 -0
- ragfabric_core-0.3.1/src/ragfabric_core/config.py +130 -0
- ragfabric_core-0.3.1/src/ragfabric_core/config_file.py +305 -0
- ragfabric_core-0.3.1/src/ragfabric_core/connectors/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/connectors/base.py +26 -0
- ragfabric_core-0.3.1/src/ragfabric_core/db/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/db/migrate.py +31 -0
- ragfabric_core-0.3.1/src/ragfabric_core/db/session.py +103 -0
- ragfabric_core-0.3.1/src/ragfabric_core/embeddings/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/embeddings/normalise.py +23 -0
- ragfabric_core-0.3.1/src/ragfabric_core/generate/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/generate/answer.py +316 -0
- ragfabric_core-0.3.1/src/ragfabric_core/generate/cited.py +660 -0
- ragfabric_core-0.3.1/src/ragfabric_core/generate/contract.py +119 -0
- ragfabric_core-0.3.1/src/ragfabric_core/generate/llm.py +239 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/citations.py +246 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/contracts.py +317 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/extract.py +793 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/resolve.py +1195 -0
- ragfabric_core-0.3.1/src/ragfabric_core/graph/traverse.py +592 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/chunk.py +101 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/clean.py +103 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/embed.py +112 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/indexing.py +85 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/parser.py +126 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/pipeline.py +272 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/reindex.py +116 -0
- ragfabric_core-0.3.1/src/ragfabric_core/ingest/storage.py +65 -0
- ragfabric_core-0.3.1/src/ragfabric_core/json_contract.py +77 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/alembic.ini +44 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/env.py +122 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/script.py.mako +25 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0001_initial_schema.py +147 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0002_platform_tables.py +457 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0003_ingestion_and_indexes.py +93 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0004_pin_vector_dim_and_hnsw.py +58 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0005_ingestion_runs.py +59 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0006_timezone_aware_timestamps.py +82 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0007_bm25_term_stats.py +53 -0
- ragfabric_core-0.3.1/src/ragfabric_core/migrations/versions/0008_graph_confidence_and_merges.py +158 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/__init__.py +14 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/access.py +118 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/base.py +42 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/document.py +160 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/evaluation.py +55 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/graph.py +179 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/index.py +82 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/runs.py +97 -0
- ragfabric_core-0.3.1/src/ragfabric_core/models/user.py +34 -0
- ragfabric_core-0.3.1/src/ragfabric_core/pricing.py +99 -0
- ragfabric_core-0.3.1/src/ragfabric_core/pricing.yaml +53 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/anthropic_provider.py +128 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/base.py +82 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/offline.py +182 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/openai_compat.py +225 -0
- ragfabric_core-0.3.1/src/ragfabric_core/providers/registry.py +84 -0
- ragfabric_core-0.3.1/src/ragfabric_core/queue/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/queue/base.py +19 -0
- ragfabric_core-0.3.1/src/ragfabric_core/queue/memory_queue.py +27 -0
- ragfabric_core-0.3.1/src/ragfabric_core/queue/redis_queue.py +42 -0
- ragfabric_core-0.3.1/src/ragfabric_core/queue/registry.py +13 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/base.py +61 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/cross_encoder.py +68 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/llm_reranker.py +99 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/noop.py +12 -0
- ragfabric_core-0.3.1/src/ragfabric_core/rerank/registry.py +20 -0
- ragfabric_core-0.3.1/src/ragfabric_core/runtime.py +32 -0
- ragfabric_core-0.3.1/src/ragfabric_core/security.py +66 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/access_sql.py +57 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/base.py +48 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/bm25_memory.py +187 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/bm25_sql.py +339 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/boosting.py +123 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/chroma_store.py +266 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/document_chunks.py +103 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/fusion.py +64 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/memory_cache.py +39 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/pgvector_store.py +167 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/postgres_fts.py +254 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/redis_cache.py +29 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/registry.py +83 -0
- ragfabric_core-0.3.1/src/ragfabric_core/stores/term_stats.py +189 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/agentic.py +179 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/base.py +174 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/contract.py +30 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/graph.py +395 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/registry_defaults.py +154 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/traditional.py +180 -0
- ragfabric_core-0.3.1/src/ragfabric_core/strategies/vectorless.py +185 -0
- ragfabric_core-0.3.1/src/ragfabric_core/telemetry/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/telemetry/tracing.py +88 -0
- ragfabric_core-0.3.1/src/ragfabric_core/testing/__init__.py +0 -0
- ragfabric_core-0.3.1/src/ragfabric_core/testing/fixtures.py +138 -0
- ragfabric_core-0.3.1/src/ragfabric_core/tokens.py +99 -0
- ragfabric_core-0.3.1/src/ragfabric_core/workers/__init__.py +1 -0
- ragfabric_core-0.3.1/src/ragfabric_core/workers/handlers.py +322 -0
- ragfabric_core-0.3.1/src/ragfabric_core/workers/runner.py +147 -0
- ragfabric_core-0.3.1/tests/agent_doubles.py +186 -0
- ragfabric_core-0.3.1/tests/test_access_policy.py +290 -0
- ragfabric_core-0.3.1/tests/test_access_sql.py +87 -0
- ragfabric_core-0.3.1/tests/test_agent_assess.py +215 -0
- ragfabric_core-0.3.1/tests/test_agent_branches.py +668 -0
- ragfabric_core-0.3.1/tests/test_agent_budgets.py +346 -0
- ragfabric_core-0.3.1/tests/test_agent_contracts.py +109 -0
- ragfabric_core-0.3.1/tests/test_agent_loop.py +270 -0
- ragfabric_core-0.3.1/tests/test_agent_plan.py +130 -0
- ragfabric_core-0.3.1/tests/test_agent_policy.py +198 -0
- ragfabric_core-0.3.1/tests/test_agent_progress.py +147 -0
- ragfabric_core-0.3.1/tests/test_agent_state.py +112 -0
- ragfabric_core-0.3.1/tests/test_agent_tools.py +390 -0
- ragfabric_core-0.3.1/tests/test_agentic_integration.py +288 -0
- ragfabric_core-0.3.1/tests/test_api_keys.py +106 -0
- ragfabric_core-0.3.1/tests/test_bm25_filters.py +144 -0
- ragfabric_core-0.3.1/tests/test_bm25_memory.py +162 -0
- ragfabric_core-0.3.1/tests/test_bm25_sql.py +244 -0
- ragfabric_core-0.3.1/tests/test_boosting.py +90 -0
- ragfabric_core-0.3.1/tests/test_caches.py +24 -0
- ragfabric_core-0.3.1/tests/test_chroma_store_unit.py +240 -0
- ragfabric_core-0.3.1/tests/test_citation_contract.py +115 -0
- ragfabric_core-0.3.1/tests/test_cited_generation.py +99 -0
- ragfabric_core-0.3.1/tests/test_clean.py +56 -0
- ragfabric_core-0.3.1/tests/test_config_agentic.py +155 -0
- ragfabric_core-0.3.1/tests/test_config_file.py +161 -0
- ragfabric_core-0.3.1/tests/test_fusion.py +57 -0
- ragfabric_core-0.3.1/tests/test_graph_config_wiring.py +658 -0
- ragfabric_core-0.3.1/tests/test_graph_contracts.py +534 -0
- ragfabric_core-0.3.1/tests/test_graph_empty.py +186 -0
- ragfabric_core-0.3.1/tests/test_graph_extract.py +446 -0
- ragfabric_core-0.3.1/tests/test_graph_extract_incremental.py +532 -0
- ragfabric_core-0.3.1/tests/test_graph_guided.py +240 -0
- ragfabric_core-0.3.1/tests/test_graph_integration.py +557 -0
- ragfabric_core-0.3.1/tests/test_graph_reingest.py +437 -0
- ragfabric_core-0.3.1/tests/test_graph_resolve.py +1385 -0
- ragfabric_core-0.3.1/tests/test_graph_surface_names.py +232 -0
- ragfabric_core-0.3.1/tests/test_graph_traverse.py +860 -0
- ragfabric_core-0.3.1/tests/test_indexing.py +431 -0
- ragfabric_core-0.3.1/tests/test_interfaces_shape.py +122 -0
- ragfabric_core-0.3.1/tests/test_migrations.py +306 -0
- ragfabric_core-0.3.1/tests/test_migrations_postgres.py +143 -0
- ragfabric_core-0.3.1/tests/test_migrations_postgres_0008.py +130 -0
- ragfabric_core-0.3.1/tests/test_models_graph_confidence.py +87 -0
- ragfabric_core-0.3.1/tests/test_models_term_stats.py +32 -0
- ragfabric_core-0.3.1/tests/test_normalise.py +20 -0
- ragfabric_core-0.3.1/tests/test_pipeline.py +465 -0
- ragfabric_core-0.3.1/tests/test_pricing.py +79 -0
- ragfabric_core-0.3.1/tests/test_production_safety.py +97 -0
- ragfabric_core-0.3.1/tests/test_provider_registry.py +76 -0
- ragfabric_core-0.3.1/tests/test_provider_streaming.py +18 -0
- ragfabric_core-0.3.1/tests/test_providers_anthropic.py +114 -0
- ragfabric_core-0.3.1/tests/test_providers_offline.py +47 -0
- ragfabric_core-0.3.1/tests/test_providers_openai_compat.py +180 -0
- ragfabric_core-0.3.1/tests/test_queue.py +52 -0
- ragfabric_core-0.3.1/tests/test_registry_agentic_wiring.py +138 -0
- ragfabric_core-0.3.1/tests/test_reindex.py +267 -0
- ragfabric_core-0.3.1/tests/test_rerank.py +241 -0
- ragfabric_core-0.3.1/tests/test_runtime.py +27 -0
- ragfabric_core-0.3.1/tests/test_storage.py +49 -0
- ragfabric_core-0.3.1/tests/test_stores_chroma.py +146 -0
- ragfabric_core-0.3.1/tests/test_stores_postgres.py +199 -0
- ragfabric_core-0.3.1/tests/test_stores_registry.py +70 -0
- ragfabric_core-0.3.1/tests/test_stores_sqlite.py +245 -0
- ragfabric_core-0.3.1/tests/test_strategy_agentic.py +193 -0
- ragfabric_core-0.3.1/tests/test_strategy_graph.py +406 -0
- ragfabric_core-0.3.1/tests/test_strategy_interface.py +141 -0
- ragfabric_core-0.3.1/tests/test_strategy_vectorless.py +226 -0
- ragfabric_core-0.3.1/tests/test_sub_question_reports.py +196 -0
- ragfabric_core-0.3.1/tests/test_term_stats.py +121 -0
- ragfabric_core-0.3.1/tests/test_tokens.py +116 -0
- ragfabric_core-0.3.1/tests/test_tracing.py +45 -0
- ragfabric_core-0.3.1/tests/test_traditional_strategy.py +246 -0
- ragfabric_core-0.3.1/tests/test_version.py +48 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# Environment
|
|
2
|
+
.env
|
|
3
|
+
.env.*
|
|
4
|
+
!.env.example
|
|
5
|
+
|
|
6
|
+
# local configuration (copy of ragfabric.example.yaml)
|
|
7
|
+
ragfabric.yaml
|
|
8
|
+
|
|
9
|
+
# OS
|
|
10
|
+
.DS_Store
|
|
11
|
+
|
|
12
|
+
# Python
|
|
13
|
+
__pycache__/
|
|
14
|
+
*.pyc
|
|
15
|
+
*.pyo
|
|
16
|
+
.venv/
|
|
17
|
+
venv/
|
|
18
|
+
.pytest_cache/
|
|
19
|
+
*.egg-info/
|
|
20
|
+
|
|
21
|
+
# Local data / databases
|
|
22
|
+
*.db
|
|
23
|
+
backend/data/uploads/
|
|
24
|
+
|
|
25
|
+
# Node / Angular
|
|
26
|
+
node_modules/
|
|
27
|
+
dist/
|
|
28
|
+
.angular/
|
|
29
|
+
npm-debug.log*
|
|
30
|
+
|
|
31
|
+
# Editors
|
|
32
|
+
.idea/
|
|
33
|
+
.vscode/
|
|
34
|
+
|
|
35
|
+
# Frontend test artifacts
|
|
36
|
+
coverage/
|
|
37
|
+
out-tsc/
|
|
38
|
+
|
|
39
|
+
# Local planning notes and scratch (never committed)
|
|
40
|
+
MEMORY*.md
|
|
41
|
+
*.local.md
|
|
42
|
+
.notes/
|
|
43
|
+
.scratch/
|
|
44
|
+
|
|
45
|
+
# Secrets and keys (belt and braces; .env already excluded above)
|
|
46
|
+
*.pem
|
|
47
|
+
*.key
|
|
48
|
+
*.p12
|
|
49
|
+
secrets/
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: ragfabric-core
|
|
3
|
+
Version: 0.3.1
|
|
4
|
+
Summary: RagFabric engine: retrieval strategies, providers, stores, ingestion, evaluation, access policy.
|
|
5
|
+
Project-URL: Homepage, https://github.com/ranjan-del/ragfabric
|
|
6
|
+
Project-URL: Repository, https://github.com/ranjan-del/ragfabric
|
|
7
|
+
Project-URL: Documentation, https://github.com/ranjan-del/ragfabric/tree/main/docs
|
|
8
|
+
Project-URL: Changelog, https://github.com/ranjan-del/ragfabric/blob/main/CHANGELOG.md
|
|
9
|
+
Project-URL: Issues, https://github.com/ranjan-del/ragfabric/issues
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: Operating System :: OS Independent
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
|
|
17
|
+
Requires-Python: <3.14,>=3.13
|
|
18
|
+
Requires-Dist: alembic>=1.20
|
|
19
|
+
Requires-Dist: bcrypt>=5.0
|
|
20
|
+
Requires-Dist: email-validator>=2.3
|
|
21
|
+
Requires-Dist: numpy>=2.3
|
|
22
|
+
Requires-Dist: opentelemetry-exporter-otlp-proto-http>=1.44
|
|
23
|
+
Requires-Dist: opentelemetry-sdk>=1.44
|
|
24
|
+
Requires-Dist: pgvector>=0.5
|
|
25
|
+
Requires-Dist: psycopg[binary]>=3.3
|
|
26
|
+
Requires-Dist: pydantic-settings>=2.15
|
|
27
|
+
Requires-Dist: pydantic>=2.13
|
|
28
|
+
Requires-Dist: pypdf>=6.18
|
|
29
|
+
Requires-Dist: python-docx>=1.2
|
|
30
|
+
Requires-Dist: python-jose[cryptography]>=3.5
|
|
31
|
+
Requires-Dist: python-pptx>=1.0
|
|
32
|
+
Requires-Dist: pyyaml>=6.0
|
|
33
|
+
Requires-Dist: redis>=8.1
|
|
34
|
+
Requires-Dist: sqlalchemy>=2.0.52
|
|
35
|
+
Requires-Dist: tiktoken>=0.12
|
|
36
|
+
Provides-Extra: anthropic
|
|
37
|
+
Requires-Dist: anthropic>=1.5; extra == 'anthropic'
|
|
38
|
+
Provides-Extra: bm25
|
|
39
|
+
Requires-Dist: rank-bm25>=0.2.2; extra == 'bm25'
|
|
40
|
+
Provides-Extra: chroma
|
|
41
|
+
Requires-Dist: chromadb>=1.5; extra == 'chroma'
|
|
42
|
+
Provides-Extra: openai
|
|
43
|
+
Requires-Dist: openai>=3.13; extra == 'openai'
|
|
44
|
+
Provides-Extra: rerank
|
|
45
|
+
Requires-Dist: sentence-transformers>=5.1; extra == 'rerank'
|
|
46
|
+
Description-Content-Type: text/markdown
|
|
47
|
+
|
|
48
|
+
# ragfabric-core
|
|
49
|
+
|
|
50
|
+
The RagFabric engine. See the repository README.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "ragfabric-core"
|
|
3
|
+
version = "0.3.1"
|
|
4
|
+
description = "RagFabric engine: retrieval strategies, providers, stores, ingestion, evaluation, access policy."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
license = "Apache-2.0"
|
|
7
|
+
requires-python = ">=3.13,<3.14"
|
|
8
|
+
classifiers = [
|
|
9
|
+
"Development Status :: 3 - Alpha",
|
|
10
|
+
"Intended Audience :: Developers",
|
|
11
|
+
"Operating System :: OS Independent",
|
|
12
|
+
"Programming Language :: Python :: 3",
|
|
13
|
+
"Programming Language :: Python :: 3.13",
|
|
14
|
+
"Topic :: Scientific/Engineering :: Artificial Intelligence",
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"pydantic>=2.13",
|
|
18
|
+
"pydantic-settings>=2.15",
|
|
19
|
+
"sqlalchemy>=2.0.52",
|
|
20
|
+
"alembic>=1.20",
|
|
21
|
+
"psycopg[binary]>=3.3",
|
|
22
|
+
"numpy>=2.3",
|
|
23
|
+
"pypdf>=6.18",
|
|
24
|
+
"python-docx>=1.2",
|
|
25
|
+
"python-pptx>=1.0",
|
|
26
|
+
"python-jose[cryptography]>=3.5",
|
|
27
|
+
"bcrypt>=5.0",
|
|
28
|
+
"email-validator>=2.3",
|
|
29
|
+
"pyyaml>=6.0",
|
|
30
|
+
"pgvector>=0.5",
|
|
31
|
+
"redis>=8.1",
|
|
32
|
+
"opentelemetry-sdk>=1.44",
|
|
33
|
+
"opentelemetry-exporter-otlp-proto-http>=1.44",
|
|
34
|
+
"tiktoken>=0.12",
|
|
35
|
+
]
|
|
36
|
+
|
|
37
|
+
[project.optional-dependencies]
|
|
38
|
+
chroma = ["chromadb>=1.5"]
|
|
39
|
+
# In-process BM25 (stores/bm25_memory.py). Optional because it is not the
|
|
40
|
+
# production path: the SQL store needs no extra at all, and a deployment
|
|
41
|
+
# that never uses the in-process store should not carry the dependency.
|
|
42
|
+
bm25 = ["rank_bm25>=0.2.2"]
|
|
43
|
+
rerank = ["sentence-transformers>=5.1"]
|
|
44
|
+
# Ollama also goes through OpenAICompatibleLLM/OpenAICompatibleEmbeddings
|
|
45
|
+
# (providers/openai_compat.py), since Ollama serves the OpenAI chat and
|
|
46
|
+
# embeddings API at /v1, so an Ollama-only deployment still needs this
|
|
47
|
+
# extra installed; only a deployment that uses neither OpenAI, Azure, vLLM,
|
|
48
|
+
# LM Studio nor Ollama can skip it.
|
|
49
|
+
openai = ["openai>=3.13"]
|
|
50
|
+
anthropic = ["anthropic>=1.5"]
|
|
51
|
+
|
|
52
|
+
[project.urls]
|
|
53
|
+
Homepage = "https://github.com/ranjan-del/ragfabric"
|
|
54
|
+
Repository = "https://github.com/ranjan-del/ragfabric"
|
|
55
|
+
Documentation = "https://github.com/ranjan-del/ragfabric/tree/main/docs"
|
|
56
|
+
Changelog = "https://github.com/ranjan-del/ragfabric/blob/main/CHANGELOG.md"
|
|
57
|
+
Issues = "https://github.com/ranjan-del/ragfabric/issues"
|
|
58
|
+
|
|
59
|
+
[build-system]
|
|
60
|
+
requires = ["hatchling>=1.27"]
|
|
61
|
+
build-backend = "hatchling.build"
|
|
62
|
+
|
|
63
|
+
[tool.hatch.build.targets.wheel]
|
|
64
|
+
packages = ["src/ragfabric_core"]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""The bounded retrieval agent: state, contracts, tools, nodes and the loop."""
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
"""What the agent asks a model for, and what it will accept back.
|
|
2
|
+
|
|
3
|
+
Every decision the agent delegates to a model comes back as JSON validated
|
|
4
|
+
against a schema here. There is no native tool calling involved, deliberately:
|
|
5
|
+
``LLMProvider`` exposes only ``complete`` and ``stream``, and building a
|
|
6
|
+
tool-calling surface would be a second subsystem that could not be exercised
|
|
7
|
+
without paid API credit. JSON contracts work on every provider, including a
|
|
8
|
+
3B model running locally, and they let the scripted test double drive every
|
|
9
|
+
branch of the loop offline.
|
|
10
|
+
|
|
11
|
+
The parsers are deliberately forgiving about *packaging* and strict about
|
|
12
|
+
*content*. Small models wrap JSON in a fenced block, preface it with a sentence
|
|
13
|
+
of agreement, or explain themselves afterwards. None of that is a real failure,
|
|
14
|
+
so it is tolerated. A missing field, an empty plan or an invented repair move
|
|
15
|
+
is a real failure, and it returns a ``ContractViolation`` rather than raising,
|
|
16
|
+
so the caller decides whether to retry with a corrective instruction or fall
|
|
17
|
+
back to a safe default. A malformed response must never crash a request and
|
|
18
|
+
must never be silently counted as success.
|
|
19
|
+
"""
|
|
20
|
+
|
|
21
|
+
from __future__ import annotations
|
|
22
|
+
|
|
23
|
+
from pydantic import BaseModel, Field
|
|
24
|
+
|
|
25
|
+
from ragfabric_core.agent.state import RepairMove
|
|
26
|
+
from ragfabric_core.json_contract import ContractViolation, parse_contract
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
class PlannedSubQuestion(BaseModel):
|
|
30
|
+
text: str = Field(min_length=1)
|
|
31
|
+
tool: str = Field(min_length=1)
|
|
32
|
+
why: str = ""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
class PlanResponse(BaseModel):
|
|
36
|
+
sub_questions: list[PlannedSubQuestion] = Field(min_length=1)
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class Verdict(BaseModel):
|
|
40
|
+
sub_question: str = Field(min_length=1)
|
|
41
|
+
answered: bool
|
|
42
|
+
missing: str | None = None
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class AssessResponse(BaseModel):
|
|
46
|
+
verdicts: list[Verdict]
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
class RepairResponse(BaseModel):
|
|
50
|
+
move: RepairMove
|
|
51
|
+
rewritten_query: str | None = None
|
|
52
|
+
why: str = ""
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def parse_plan(text: str) -> PlanResponse | ContractViolation:
|
|
56
|
+
"""A plan with no sub-questions is refused.
|
|
57
|
+
|
|
58
|
+
An empty plan leaves the loop nothing to retrieve for, and it would then
|
|
59
|
+
report no progress on the next pass, which hides the real problem.
|
|
60
|
+
"""
|
|
61
|
+
return parse_contract(text, "plan", PlanResponse)
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def parse_assess(text: str) -> AssessResponse | ContractViolation:
|
|
65
|
+
return parse_contract(text, "assess", AssessResponse)
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def parse_repair(text: str) -> RepairResponse | ContractViolation:
|
|
69
|
+
"""An invented move is refused by the schema before it reaches the policy."""
|
|
70
|
+
return parse_contract(text, "repair", RepairResponse)
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
"""What a run has spent, and the honest answer when nobody knows (ADR 0004).
|
|
2
|
+
|
|
3
|
+
The agent is the one strategy whose spend is not knowable before it runs, so a
|
|
4
|
+
cost cap has to be checked against tokens that have actually been returned.
|
|
5
|
+
This ledger holds those tokens, per model, and prices them through the same
|
|
6
|
+
``pricing.yaml`` table the rest of the product reads.
|
|
7
|
+
|
|
8
|
+
**The unpriced model is the whole design.** ``estimate_cost`` reports
|
|
9
|
+
``usd=None, known=False`` for a model the table has no price for, and there are
|
|
10
|
+
only two ways to carry that into a cap, one of which is a lie:
|
|
11
|
+
|
|
12
|
+
- treat unknown as zero, and the cap silently never binds while the trace still
|
|
13
|
+
implies it was watching;
|
|
14
|
+
- treat unknown as infinite, and every run on a self hosted model stops on its
|
|
15
|
+
first call.
|
|
16
|
+
|
|
17
|
+
So unknown means the cap cannot bind, and the ledger says which models it could
|
|
18
|
+
not price. The caller records that alongside the run rather than reporting a
|
|
19
|
+
number nobody measured. A price of zero is a different thing entirely: local
|
|
20
|
+
inference is priced at zero in the table, with a source saying why, and that is
|
|
21
|
+
a known cost of nothing rather than an unknown cost.
|
|
22
|
+
"""
|
|
23
|
+
|
|
24
|
+
from __future__ import annotations
|
|
25
|
+
|
|
26
|
+
from functools import lru_cache
|
|
27
|
+
|
|
28
|
+
from ragfabric_core.pricing import PricingTable, estimate_cost
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
@lru_cache(maxsize=1)
|
|
32
|
+
def _shared_table() -> PricingTable:
|
|
33
|
+
"""The packaged pricing table, read once per process.
|
|
34
|
+
|
|
35
|
+
Cached because the loop asks for a price several times per run and the file
|
|
36
|
+
cannot change under a running process.
|
|
37
|
+
"""
|
|
38
|
+
return PricingTable.load()
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
class CostLedger:
|
|
42
|
+
"""Real token counts per model, priced only where a price exists."""
|
|
43
|
+
|
|
44
|
+
def __init__(self, table: PricingTable | None = None) -> None:
|
|
45
|
+
self._table = table if table is not None else _shared_table()
|
|
46
|
+
self._tokens: dict[tuple[str, str], list[int]] = {}
|
|
47
|
+
|
|
48
|
+
def record(self, provider: str, model: str, input_tokens: int, output_tokens: int) -> None:
|
|
49
|
+
"""Add one completion's reported tokens.
|
|
50
|
+
|
|
51
|
+
A node that made no model call passes an empty provider and is ignored,
|
|
52
|
+
because an entry for a call that never happened would put a model in
|
|
53
|
+
the unpriced list on the strength of nothing.
|
|
54
|
+
"""
|
|
55
|
+
if not provider:
|
|
56
|
+
return
|
|
57
|
+
spent = self._tokens.setdefault((provider, model), [0, 0])
|
|
58
|
+
spent[0] += input_tokens
|
|
59
|
+
spent[1] += output_tokens
|
|
60
|
+
|
|
61
|
+
def unpriced_models(self) -> list[str]:
|
|
62
|
+
"""The ``provider/model`` keys this run used that the table cannot price."""
|
|
63
|
+
return sorted(
|
|
64
|
+
f"{provider}/{model}"
|
|
65
|
+
for (provider, model), (input_tokens, output_tokens) in self._tokens.items()
|
|
66
|
+
if not estimate_cost(self._table, provider, model, input_tokens, output_tokens).known
|
|
67
|
+
)
|
|
68
|
+
|
|
69
|
+
@property
|
|
70
|
+
def known(self) -> bool:
|
|
71
|
+
"""True when every model used so far has a price.
|
|
72
|
+
|
|
73
|
+
A run that has made no call at all is known: nothing has been spent,
|
|
74
|
+
and that is a measurement rather than a guess.
|
|
75
|
+
"""
|
|
76
|
+
return not self.unpriced_models()
|
|
77
|
+
|
|
78
|
+
def usd(self) -> float | None:
|
|
79
|
+
"""The estimated spend, or ``None`` when any model used has no price.
|
|
80
|
+
|
|
81
|
+
Deliberately all or nothing. Summing the priced part of a run and
|
|
82
|
+
presenting it as the total would understate the bill by exactly the
|
|
83
|
+
amount nobody can compute.
|
|
84
|
+
"""
|
|
85
|
+
if not self.known:
|
|
86
|
+
return None
|
|
87
|
+
total = 0.0
|
|
88
|
+
for (provider, model), (input_tokens, output_tokens) in self._tokens.items():
|
|
89
|
+
estimate = estimate_cost(self._table, provider, model, input_tokens, output_tokens)
|
|
90
|
+
total += estimate.usd or 0.0
|
|
91
|
+
return round(total, 8)
|