fred-core 3.4.3__tar.gz → 3.4.4__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.
- {fred_core-3.4.3 → fred_core-3.4.4}/PKG-INFO +1 -1
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/resilient_sink.py +3 -5
- fred_core-3.4.4/fred_core/store/vector_search.py +128 -0
- fred_core-3.4.4/fred_core/tests/store/test_vector_search.py +84 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core.egg-info/PKG-INFO +1 -1
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core.egg-info/SOURCES.txt +1 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/pyproject.toml +1 -1
- fred_core-3.4.3/fred_core/store/vector_search.py +0 -72
- {fred_core-3.4.3 → fred_core-3.4.4}/README.md +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/cli/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/cli/auth.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/cli/ui.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/config_files.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/config_loader.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/env.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/fastapi_handlers.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/lru_cache.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/team_id.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/common/utils.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/document_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/document_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/document_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/postgres_document_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/documents/tag_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/filesystem/gcs_filesystem.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/filesystem/local_filesystem.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/filesystem/minio_filesystem.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/filesystem/structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/history/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/history/base_history_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/history/history_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/history/history_schema.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/history/postgres_history_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/base_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/base_kpi_writer.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/http_middleware.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_phase_metric.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_process.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_reader_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_writer.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/kpi_writer_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/log_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/noop_kpi_writer.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/opensearch_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/kpi/prometheus_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/audit_log.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/base_log_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/log_setup.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/log_store_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/log_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/memory_log_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/null_log_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/logs/opensearch_log_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/model/factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/model/http_clients.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/model/models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/models/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/models/base.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/portable/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/portable/observability.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/py.typed +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/scheduler/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/scheduler/backend.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/scheduler/scheduler_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/scheduler/temporal_client_provider.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/authorization.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/backend_to_backend_auth.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/keycloak/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/keycloak/keycloack_admin_client.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/oidc.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/outbound.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/noop_engine.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/openfga_engine.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/openfga_schema.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/rebac_engine.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/rebac_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/schema.fga +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/rebac/schema.fga.json +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/structure.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/whitelist_access_control/access_control.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/session_schema.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/stores/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/stores/base_session_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/stores/postgres_session_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/session/stores/session_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/sql/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/sql/alembic_env.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/sql/async_session.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/sql/base_sql.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/sql/mixin.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/store/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/store/base_content_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/store/local_content_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/store/minio_content_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/store/opensearch_mapping_validator.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/authz.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/bus.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/orm_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/service.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/sse.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tasks/workflow_control.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/teams/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/teams/metadata_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/teams/team_metatada_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/cli/test_auth.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/cli/test_ui.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_config_loader.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_env.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_fastapi_handlers.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_log_setup.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_lru_cache.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_resilient_sink.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/common/test_structures.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/filesystem/test_gcs_filesystem.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/filesystem/test_local_filesystem.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/integration/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/integration/test_rebac.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_http_middleware.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_noop_kpi_writer.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_opensearch_kpi_store_anonymise.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_opensearch_kpi_store_ensure_ready.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/logs/test_audit_log.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/logs/test_log_store_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/logs/test_memory_log_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/logs/test_opensearch_log_store_ensure_ready.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/model/test_anthropic_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/model/test_embedding_factory.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/model/test_http_clients.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/model/test_vertex_model_garden_auth.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/portable/test_observability.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/scheduler/test_backend.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/scheduler/test_temporal_client_provider.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_capability_scoping_1980.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_oidc_strict.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_rebac_config_defaults.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_rebac_engine_team_helpers.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_rebac_schema_authz05.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_security_profile.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_service_agent.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_whitelist_access_control.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/session/test_postgres_json_session_store_sqlite.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/store/test_local_content_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_authz.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_bus.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_reconcile.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_scheduling.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/tasks/test_sse.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/test_kpi_writer_fail_open.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/test_log_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/test_prometheus_kpi_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/users/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/users/store/__init__.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/users/store/base_user_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/users/store/postgres_user_store.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core/users/user_models.py +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core.egg-info/dependency_links.txt +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core.egg-info/requires.txt +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/fred_core.egg-info/top_level.txt +0 -0
- {fred_core-3.4.3 → fred_core-3.4.4}/setup.cfg +0 -0
|
@@ -50,17 +50,15 @@ from typing import Any, Protocol
|
|
|
50
50
|
logger = logging.getLogger(__name__)
|
|
51
51
|
|
|
52
52
|
|
|
53
|
-
# fmt: off
|
|
54
53
|
class _WritableStore(Protocol):
|
|
55
54
|
def ensure_ready(self) -> None:
|
|
56
|
-
|
|
55
|
+
pass
|
|
57
56
|
|
|
58
57
|
def index_event(self, event: Any) -> None:
|
|
59
|
-
|
|
58
|
+
pass
|
|
60
59
|
|
|
61
60
|
def bulk_index(self, events: list[Any]) -> None:
|
|
62
|
-
|
|
63
|
-
# fmt: on
|
|
61
|
+
pass
|
|
64
62
|
|
|
65
63
|
|
|
66
64
|
class _CircuitBreaker:
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
# Copyright Thales 2025
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
# fred_core/vector_search.py
|
|
16
|
+
|
|
17
|
+
from typing import List, Optional, Sequence
|
|
18
|
+
|
|
19
|
+
from pydantic import BaseModel, Field
|
|
20
|
+
|
|
21
|
+
# A pointer chunk (RAG-DATASET-DISCOVERY-RFC.md) describes a structured dataset
|
|
22
|
+
# for discovery — it carries no real content, so it must never be presented as
|
|
23
|
+
# a citable "source" the way a real content chunk is. `chunk_kind` distinguishes
|
|
24
|
+
# the two; this constant is the single place both writers (TabularProcessor)
|
|
25
|
+
# and readers (document_access, knowledge.search) agree on the pointer value.
|
|
26
|
+
DATASET_POINTER_CHUNK_KIND = "dataset_pointer"
|
|
27
|
+
|
|
28
|
+
# Default for `select_citable_sources`'s `min_score_ratio` — a hit scoring
|
|
29
|
+
# below half the best hit's score in the same search call is treated as noise
|
|
30
|
+
# relative to the strongest match, not a citable basis for an answer. Callers
|
|
31
|
+
# that expose this as a tunable field (e.g. DocumentAccessConfig) should use
|
|
32
|
+
# this as their own field default, so the two stay in sync.
|
|
33
|
+
DEFAULT_MIN_SOURCE_SCORE_RATIO = 0.5
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class VectorSearchHit(BaseModel):
|
|
37
|
+
# Content (chunk)
|
|
38
|
+
content: str
|
|
39
|
+
page: Optional[int] = None
|
|
40
|
+
section: Optional[str] = None
|
|
41
|
+
viewer_fragment: Optional[str] = None # e.g., "p=12&sel=340-520"
|
|
42
|
+
slide_id: Optional[int] = None
|
|
43
|
+
has_visual_evidence: Optional[bool] = None
|
|
44
|
+
slide_image_uri: Optional[str] = None
|
|
45
|
+
chunk_kind: Optional[str] = Field(
|
|
46
|
+
default=None,
|
|
47
|
+
description=(
|
|
48
|
+
"content (default, real ingested prose/data) or "
|
|
49
|
+
f"'{DATASET_POINTER_CHUNK_KIND}' (a discovery pointer to a structured "
|
|
50
|
+
"dataset, never citable as a source)."
|
|
51
|
+
),
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
# Identity
|
|
55
|
+
uid: str = Field(..., description="Document UID")
|
|
56
|
+
title: str
|
|
57
|
+
author: Optional[str] = None
|
|
58
|
+
created: Optional[str] = None
|
|
59
|
+
modified: Optional[str] = None
|
|
60
|
+
|
|
61
|
+
# File/source
|
|
62
|
+
file_name: Optional[str] = None
|
|
63
|
+
file_path: Optional[str] = None
|
|
64
|
+
repository: Optional[str] = None
|
|
65
|
+
pull_location: Optional[str] = None
|
|
66
|
+
language: Optional[str] = None
|
|
67
|
+
mime_type: Optional[str] = None
|
|
68
|
+
type: Optional[str] = Field(default=None, description="File type/category")
|
|
69
|
+
|
|
70
|
+
# Tags (UI wants *names*; keep ids too for filters)
|
|
71
|
+
tag_ids: List[str] = []
|
|
72
|
+
tag_names: List[str] = []
|
|
73
|
+
tag_full_paths: List[str] = []
|
|
74
|
+
|
|
75
|
+
# Link fields (internal viewers / external)
|
|
76
|
+
preview_url: Optional[str] = None # e.g., "/documents/{uid}"
|
|
77
|
+
preview_at_url: Optional[str] = None # e.g., "/documents/{uid}#{viewer_fragment}"
|
|
78
|
+
repo_url: Optional[str] = None # e.g., "https://git/.../blob/ref/path#Lx-Ly"
|
|
79
|
+
citation_url: Optional[str] = None # e.g., "/documents/{uid}#chunk={chunk_id}"
|
|
80
|
+
|
|
81
|
+
# Access (optional, forward-looking)
|
|
82
|
+
license: Optional[str] = None
|
|
83
|
+
confidential: Optional[bool] = None
|
|
84
|
+
|
|
85
|
+
# Metrics
|
|
86
|
+
score: float = Field(..., description="Similarity score from vector search")
|
|
87
|
+
rank: Optional[int] = None
|
|
88
|
+
embedding_model: Optional[str] = None
|
|
89
|
+
vector_index: Optional[str] = None
|
|
90
|
+
token_count: Optional[int] = None
|
|
91
|
+
|
|
92
|
+
# Provenance
|
|
93
|
+
retrieved_at: Optional[str] = None
|
|
94
|
+
retrieval_session_id: Optional[str] = None
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def select_citable_sources(
|
|
98
|
+
hits: Sequence[VectorSearchHit],
|
|
99
|
+
*,
|
|
100
|
+
min_score_ratio: float = DEFAULT_MIN_SOURCE_SCORE_RATIO,
|
|
101
|
+
) -> tuple[VectorSearchHit, ...]:
|
|
102
|
+
"""
|
|
103
|
+
Narrow a raw search-tool hit set down to what a chat "Sources" panel may
|
|
104
|
+
cite — the full, unfiltered hit set must still reach the model's tool
|
|
105
|
+
content (it needs every hit, including a dataset pointer, to decide how
|
|
106
|
+
to answer); this filter is for the human-facing citation list only.
|
|
107
|
+
|
|
108
|
+
Excludes two kinds of hit:
|
|
109
|
+
- dataset pointer chunks (RAG-DATASET-DISCOVERY-RFC.md) — descriptive
|
|
110
|
+
metadata about a structured dataset, never real content a human should
|
|
111
|
+
be pointed to as "the source" of a factual claim.
|
|
112
|
+
- hits scoring below `min_score_ratio` of the best score in this same
|
|
113
|
+
hit set — noise relative to the strongest match in the batch, found
|
|
114
|
+
live citing near-zero-relevance paragraphs from an unrelated document
|
|
115
|
+
alongside a SQL-derived answer (RAG-DATASET-DISCOVERY-RFC.md §7).
|
|
116
|
+
|
|
117
|
+
`min_score_ratio` is relative, not absolute, so it stays meaningful
|
|
118
|
+
across embedding models with different score scales/distributions.
|
|
119
|
+
"""
|
|
120
|
+
if not hits:
|
|
121
|
+
return ()
|
|
122
|
+
top_score = max(hit.score for hit in hits)
|
|
123
|
+
threshold = top_score * min_score_ratio
|
|
124
|
+
return tuple(
|
|
125
|
+
hit
|
|
126
|
+
for hit in hits
|
|
127
|
+
if hit.chunk_kind != DATASET_POINTER_CHUNK_KIND and hit.score >= threshold
|
|
128
|
+
)
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# Copyright Thales 2026
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
|
|
15
|
+
from fred_core.store.vector_search import (
|
|
16
|
+
DATASET_POINTER_CHUNK_KIND,
|
|
17
|
+
DEFAULT_MIN_SOURCE_SCORE_RATIO,
|
|
18
|
+
VectorSearchHit,
|
|
19
|
+
select_citable_sources,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def _hit(uid: str, score: float, chunk_kind: str | None = None) -> VectorSearchHit:
|
|
24
|
+
return VectorSearchHit(
|
|
25
|
+
uid=uid, title=f"Doc {uid}", content="body", score=score, chunk_kind=chunk_kind
|
|
26
|
+
)
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def test_select_citable_sources_excludes_dataset_pointer_regardless_of_score():
|
|
30
|
+
pointer = _hit("p1", score=0.9, chunk_kind=DATASET_POINTER_CHUNK_KIND)
|
|
31
|
+
real = _hit("d1", score=0.5)
|
|
32
|
+
|
|
33
|
+
result = select_citable_sources([pointer, real], min_score_ratio=0.1)
|
|
34
|
+
|
|
35
|
+
assert [hit.uid for hit in result] == ["d1"]
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
def test_select_citable_sources_excludes_hits_below_relative_score_threshold():
|
|
39
|
+
strong = _hit("d1", score=0.5)
|
|
40
|
+
noise = _hit("d2", score=0.05) # 10% of the top score
|
|
41
|
+
|
|
42
|
+
result = select_citable_sources([strong, noise], min_score_ratio=0.5)
|
|
43
|
+
|
|
44
|
+
assert [hit.uid for hit in result] == ["d1"]
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def test_select_citable_sources_keeps_hit_exactly_at_the_ratio_threshold():
|
|
48
|
+
strong = _hit("d1", score=1.0)
|
|
49
|
+
boundary = _hit("d2", score=0.5) # exactly 50% of the top score
|
|
50
|
+
|
|
51
|
+
result = select_citable_sources([strong, boundary], min_score_ratio=0.5)
|
|
52
|
+
|
|
53
|
+
assert {hit.uid for hit in result} == {"d1", "d2"}
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
def test_select_citable_sources_default_ratio_matches_the_shared_constant():
|
|
57
|
+
strong = _hit("d1", score=1.0)
|
|
58
|
+
just_below_default = _hit("d2", score=DEFAULT_MIN_SOURCE_SCORE_RATIO - 0.01)
|
|
59
|
+
|
|
60
|
+
result = select_citable_sources([strong, just_below_default])
|
|
61
|
+
|
|
62
|
+
assert [hit.uid for hit in result] == ["d1"]
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
def test_select_citable_sources_keeps_every_real_hit_when_scores_are_close():
|
|
66
|
+
a = _hit("d1", score=0.6)
|
|
67
|
+
b = _hit("d2", score=0.35) # ~58% of the top score
|
|
68
|
+
|
|
69
|
+
result = select_citable_sources([a, b], min_score_ratio=0.5)
|
|
70
|
+
|
|
71
|
+
assert {hit.uid for hit in result} == {"d1", "d2"}
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
def test_select_citable_sources_empty_input_returns_empty_tuple():
|
|
75
|
+
assert select_citable_sources([]) == ()
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
def test_select_citable_sources_all_pointers_returns_empty_tuple():
|
|
79
|
+
pointers = [
|
|
80
|
+
_hit("p1", score=0.9, chunk_kind=DATASET_POINTER_CHUNK_KIND),
|
|
81
|
+
_hit("p2", score=0.8, chunk_kind=DATASET_POINTER_CHUNK_KIND),
|
|
82
|
+
]
|
|
83
|
+
|
|
84
|
+
assert select_citable_sources(pointers) == ()
|
|
@@ -158,6 +158,7 @@ fred_core/tests/security/test_service_agent.py
|
|
|
158
158
|
fred_core/tests/security/test_whitelist_access_control.py
|
|
159
159
|
fred_core/tests/session/test_postgres_json_session_store_sqlite.py
|
|
160
160
|
fred_core/tests/store/test_local_content_store.py
|
|
161
|
+
fred_core/tests/store/test_vector_search.py
|
|
161
162
|
fred_core/tests/tasks/__init__.py
|
|
162
163
|
fred_core/tests/tasks/test_authz.py
|
|
163
164
|
fred_core/tests/tasks/test_bus.py
|
|
@@ -1,72 +0,0 @@
|
|
|
1
|
-
# Copyright Thales 2025
|
|
2
|
-
#
|
|
3
|
-
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
-
# you may not use this file except in compliance with the License.
|
|
5
|
-
# You may obtain a copy of the License at
|
|
6
|
-
#
|
|
7
|
-
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
-
#
|
|
9
|
-
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
-
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
-
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
-
# See the License for the specific language governing permissions and
|
|
13
|
-
# limitations under the License.
|
|
14
|
-
|
|
15
|
-
# fred_core/vector_search.py
|
|
16
|
-
|
|
17
|
-
from typing import List, Optional
|
|
18
|
-
|
|
19
|
-
from pydantic import BaseModel, Field
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
class VectorSearchHit(BaseModel):
|
|
23
|
-
# Content (chunk)
|
|
24
|
-
content: str
|
|
25
|
-
page: Optional[int] = None
|
|
26
|
-
section: Optional[str] = None
|
|
27
|
-
viewer_fragment: Optional[str] = None # e.g., "p=12&sel=340-520"
|
|
28
|
-
slide_id: Optional[int] = None
|
|
29
|
-
has_visual_evidence: Optional[bool] = None
|
|
30
|
-
slide_image_uri: Optional[str] = None
|
|
31
|
-
|
|
32
|
-
# Identity
|
|
33
|
-
uid: str = Field(..., description="Document UID")
|
|
34
|
-
title: str
|
|
35
|
-
author: Optional[str] = None
|
|
36
|
-
created: Optional[str] = None
|
|
37
|
-
modified: Optional[str] = None
|
|
38
|
-
|
|
39
|
-
# File/source
|
|
40
|
-
file_name: Optional[str] = None
|
|
41
|
-
file_path: Optional[str] = None
|
|
42
|
-
repository: Optional[str] = None
|
|
43
|
-
pull_location: Optional[str] = None
|
|
44
|
-
language: Optional[str] = None
|
|
45
|
-
mime_type: Optional[str] = None
|
|
46
|
-
type: Optional[str] = Field(None, description="File type/category")
|
|
47
|
-
|
|
48
|
-
# Tags (UI wants *names*; keep ids too for filters)
|
|
49
|
-
tag_ids: List[str] = []
|
|
50
|
-
tag_names: List[str] = []
|
|
51
|
-
tag_full_paths: List[str] = []
|
|
52
|
-
|
|
53
|
-
# Link fields (internal viewers / external)
|
|
54
|
-
preview_url: Optional[str] = None # e.g., "/documents/{uid}"
|
|
55
|
-
preview_at_url: Optional[str] = None # e.g., "/documents/{uid}#{viewer_fragment}"
|
|
56
|
-
repo_url: Optional[str] = None # e.g., "https://git/.../blob/ref/path#Lx-Ly"
|
|
57
|
-
citation_url: Optional[str] = None # e.g., "/documents/{uid}#chunk={chunk_id}"
|
|
58
|
-
|
|
59
|
-
# Access (optional, forward-looking)
|
|
60
|
-
license: Optional[str] = None
|
|
61
|
-
confidential: Optional[bool] = None
|
|
62
|
-
|
|
63
|
-
# Metrics
|
|
64
|
-
score: float = Field(..., description="Similarity score from vector search")
|
|
65
|
-
rank: Optional[int] = None
|
|
66
|
-
embedding_model: Optional[str] = None
|
|
67
|
-
vector_index: Optional[str] = None
|
|
68
|
-
token_count: Optional[int] = None
|
|
69
|
-
|
|
70
|
-
# Provenance
|
|
71
|
-
retrieved_at: Optional[str] = None
|
|
72
|
-
retrieval_session_id: Optional[str] = None
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/security/whitelist_access_control/access_control.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_opensearch_kpi_store_anonymise.py
RENAMED
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/kpi/test_opensearch_kpi_store_ensure_ready.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/logs/test_opensearch_log_store_ensure_ready.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/scheduler/test_temporal_client_provider.py
RENAMED
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_capability_scoping_1980.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_rebac_engine_team_helpers.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{fred_core-3.4.3 → fred_core-3.4.4}/fred_core/tests/security/test_whitelist_access_control.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|