hyperforge-nucliadb-agentic 1.0.0.post96__tar.gz → 1.0.0.post108__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.
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/PKG-INFO +1 -1
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/pyproject.toml +1 -1
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/pyproject.toml.orig +1 -1
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/agent.py +86 -35
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/audit.py +7 -2
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/rpc.py +32 -2
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/config.py +4 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/README.md +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/__init__.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/__init__.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/exceptions.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/lifespan.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/model.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/predict.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/predict_models.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/__init__.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/ask.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/graph_strategy.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/highlight.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/hydrator.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/metrics.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/parsers/__init__.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/parsers/ask.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/parsers/fetcher.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/parsers/find.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/prompt.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/rank_fusion.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/rerankers.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/search/retrieval.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/settings.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/utils/ids.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/utils/proto.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/utils/responses.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/ask/utils/text_blocks.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/internal_driver.py +0 -0
- {hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/src/hyperforge_nucliadb_agentic/py.typed +0 -0
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "hyperforge_nucliadb_agentic"
|
|
7
|
-
version = "1.0.0.
|
|
7
|
+
version = "1.0.0.post108"
|
|
8
8
|
license = "Apache-2.0"
|
|
9
9
|
description = "NucliaDB Hyperforge agent"
|
|
10
10
|
authors = [{ name = "Nuclia", email = "nucliadb@nuclia.com" }]
|
|
@@ -55,9 +55,31 @@ from hyperforge_nucliadb_agentic.ask.model import (
|
|
|
55
55
|
RagStrategies,
|
|
56
56
|
SyncAskResponse,
|
|
57
57
|
)
|
|
58
|
+
from hyperforge_nucliadb_agentic.ask.search import rpc
|
|
58
59
|
from hyperforge_nucliadb_agentic.ask.search.ask import ask
|
|
59
60
|
from hyperforge_nucliadb_agentic.config import NucliaDBAgentConfig
|
|
60
61
|
|
|
62
|
+
|
|
63
|
+
async def choose_sources(
|
|
64
|
+
memory: QuestionMemory,
|
|
65
|
+
manager: Manager,
|
|
66
|
+
sources: List[str],
|
|
67
|
+
question: str,
|
|
68
|
+
ident: str,
|
|
69
|
+
step_title: str,
|
|
70
|
+
) -> list[Source]:
|
|
71
|
+
if len(sources) == 1:
|
|
72
|
+
return [Source.model_construct(id=sources[0])]
|
|
73
|
+
return await choose_source(
|
|
74
|
+
memory,
|
|
75
|
+
manager,
|
|
76
|
+
sources,
|
|
77
|
+
question,
|
|
78
|
+
ident=ident,
|
|
79
|
+
step_title=step_title,
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
61
83
|
# Example filter expressions for catalog search
|
|
62
84
|
EXAMPLE_FILTER_EXP1 = [
|
|
63
85
|
{
|
|
@@ -746,7 +768,7 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
746
768
|
or_filters = [f"/l/{labelset}/{lv}" for lv in label_values]
|
|
747
769
|
|
|
748
770
|
# Choose sources based on the question/s and the in
|
|
749
|
-
chosen_sources = await
|
|
771
|
+
chosen_sources = await choose_sources(
|
|
750
772
|
memory,
|
|
751
773
|
manager,
|
|
752
774
|
sources,
|
|
@@ -783,7 +805,7 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
783
805
|
) -> List[tuple[str, str]]:
|
|
784
806
|
sources = self.config.sources
|
|
785
807
|
# Choose sources based on the question/s and the in
|
|
786
|
-
chosen_sources = await
|
|
808
|
+
chosen_sources = await choose_sources(
|
|
787
809
|
memory,
|
|
788
810
|
manager,
|
|
789
811
|
sources,
|
|
@@ -949,6 +971,57 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
949
971
|
else:
|
|
950
972
|
return combine_catalog_filter_expressions(to_combine, operator="and")
|
|
951
973
|
|
|
974
|
+
async def prepare_ask_request(
|
|
975
|
+
self,
|
|
976
|
+
nucliadb_driver: NucliaDBDriver,
|
|
977
|
+
question: str,
|
|
978
|
+
ask_request_json: str | None,
|
|
979
|
+
rag_strategies: list[RagStrategies],
|
|
980
|
+
) -> AskRequest:
|
|
981
|
+
"""Apply agent defaults, search config, public ASK overrides, and runtime query."""
|
|
982
|
+
# Load explicit options from the public ASK request.
|
|
983
|
+
ask_request: AskRequest | None = None
|
|
984
|
+
if ask_request_json:
|
|
985
|
+
try:
|
|
986
|
+
ask_request = AskRequest.model_validate_json(ask_request_json)
|
|
987
|
+
except ValidationError as e:
|
|
988
|
+
logger.error(
|
|
989
|
+
f"Failed to validate AskRequest received as memory argument: {e}"
|
|
990
|
+
)
|
|
991
|
+
|
|
992
|
+
# The SmartAgent query always wins.
|
|
993
|
+
if ask_request is None:
|
|
994
|
+
ask_request = AskRequest(query=question)
|
|
995
|
+
else:
|
|
996
|
+
ask_request = ask_request.model_copy(update={"query": question})
|
|
997
|
+
|
|
998
|
+
# Search config fills fields not explicitly set by the public ASK.
|
|
999
|
+
if self.config.search_config is not None:
|
|
1000
|
+
ask_request = ask_request.model_copy(
|
|
1001
|
+
update={"search_configuration": self.config.search_config}
|
|
1002
|
+
)
|
|
1003
|
+
ask_request = await rpc.apply_ask_search_configuration(
|
|
1004
|
+
nucliadb_driver.driver,
|
|
1005
|
+
nucliadb_driver.config.kbid,
|
|
1006
|
+
ask_request,
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
# Agent defaults fill any remaining fields.
|
|
1010
|
+
fallback_values = {
|
|
1011
|
+
"show": [ResourceProperties.BASIC, ResourceProperties.ORIGIN],
|
|
1012
|
+
"citations": CitationsType.LLM_FOOTNOTES,
|
|
1013
|
+
"generative_model": self.config.generative_model,
|
|
1014
|
+
"rag_strategies": rag_strategies,
|
|
1015
|
+
"generate_answer": self.config.generate_inner_answer,
|
|
1016
|
+
}
|
|
1017
|
+
return ask_request.model_copy(
|
|
1018
|
+
update={
|
|
1019
|
+
field: value
|
|
1020
|
+
for field, value in fallback_values.items()
|
|
1021
|
+
if field not in ask_request.model_fields_set
|
|
1022
|
+
}
|
|
1023
|
+
)
|
|
1024
|
+
|
|
952
1025
|
async def inner_rag(
|
|
953
1026
|
self,
|
|
954
1027
|
source_obj: Source,
|
|
@@ -992,21 +1065,12 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
992
1065
|
MetadataExtensionStrategy(types=["classification_labels", "origin"]), # type: ignore
|
|
993
1066
|
]
|
|
994
1067
|
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
ask_request_json
|
|
1002
|
-
).model_copy(update={"query": question})
|
|
1003
|
-
except ValidationError as e:
|
|
1004
|
-
logger.error(
|
|
1005
|
-
f"Failed to validate AskRequest received as memory argument: {e}"
|
|
1006
|
-
)
|
|
1007
|
-
ask_request = None
|
|
1008
|
-
else:
|
|
1009
|
-
ask_request = None
|
|
1068
|
+
ask_request = await self.prepare_ask_request(
|
|
1069
|
+
nucliadb_driver,
|
|
1070
|
+
question,
|
|
1071
|
+
memory.arguments.get("ask_request"),
|
|
1072
|
+
rag_strategies,
|
|
1073
|
+
)
|
|
1010
1074
|
|
|
1011
1075
|
filter_expression = await self.build_filter_expression(
|
|
1012
1076
|
nucliadb_driver,
|
|
@@ -1015,22 +1079,9 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
1015
1079
|
and_filters=and_filters,
|
|
1016
1080
|
or_filters=or_filters,
|
|
1017
1081
|
resource_filters=resource_filters,
|
|
1018
|
-
filter_expression=ask_request.filter_expression
|
|
1019
|
-
if ask_request is not None
|
|
1020
|
-
else None,
|
|
1082
|
+
filter_expression=ask_request.filter_expression,
|
|
1021
1083
|
)
|
|
1022
|
-
|
|
1023
|
-
ask_request = AskRequest(
|
|
1024
|
-
query=question,
|
|
1025
|
-
show=[ResourceProperties.BASIC, ResourceProperties.ORIGIN],
|
|
1026
|
-
citations=CitationsType.LLM_FOOTNOTES,
|
|
1027
|
-
generative_model=self.config.generative_model,
|
|
1028
|
-
filter_expression=filter_expression,
|
|
1029
|
-
rag_strategies=rag_strategies,
|
|
1030
|
-
generate_answer=self.config.generate_inner_answer,
|
|
1031
|
-
)
|
|
1032
|
-
else:
|
|
1033
|
-
ask_request.filter_expression = filter_expression
|
|
1084
|
+
ask_request.filter_expression = filter_expression
|
|
1034
1085
|
|
|
1035
1086
|
await memory.add_step(
|
|
1036
1087
|
step_module="nucliadb_agent",
|
|
@@ -1174,7 +1225,7 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
1174
1225
|
) -> List[Context]:
|
|
1175
1226
|
sources = self.config.sources
|
|
1176
1227
|
# Perform catalog faceted search
|
|
1177
|
-
chosen_sources = await
|
|
1228
|
+
chosen_sources = await choose_sources(
|
|
1178
1229
|
memory,
|
|
1179
1230
|
manager,
|
|
1180
1231
|
sources,
|
|
@@ -1333,7 +1384,7 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
1333
1384
|
) -> List[Context]:
|
|
1334
1385
|
sources = self.config.sources
|
|
1335
1386
|
# Perform catalog faceted search
|
|
1336
|
-
chosen_sources = await
|
|
1387
|
+
chosen_sources = await choose_sources(
|
|
1337
1388
|
memory,
|
|
1338
1389
|
manager,
|
|
1339
1390
|
sources,
|
|
@@ -1453,7 +1504,7 @@ class NucliaDBAgent(ContextAgent, Agent[NucliaDBAgentConfig]):
|
|
|
1453
1504
|
) -> List[Context]:
|
|
1454
1505
|
sources = self.config.sources
|
|
1455
1506
|
# Perform catalog search
|
|
1456
|
-
chosen_sources = await
|
|
1507
|
+
chosen_sources = await choose_sources(
|
|
1457
1508
|
memory,
|
|
1458
1509
|
manager,
|
|
1459
1510
|
sources,
|
|
@@ -187,7 +187,6 @@ class StreamAuditStorage:
|
|
|
187
187
|
nats_subject=cast(str, usage_settings.usage_jetstream_subject),
|
|
188
188
|
)
|
|
189
189
|
await self.kb_usage_utility.initialize()
|
|
190
|
-
|
|
191
190
|
self.initialized = True
|
|
192
191
|
|
|
193
192
|
async def finalize(self):
|
|
@@ -214,8 +213,14 @@ class StreamAuditStorage:
|
|
|
214
213
|
for event in step.external_usage or []
|
|
215
214
|
]
|
|
216
215
|
if not predicts or self.kb_usage_utility is None:
|
|
216
|
+
logger.warning(
|
|
217
|
+
"Skipping KB usage report account=%s kb=%s has_predicts=%s utility_available=%s",
|
|
218
|
+
account_id,
|
|
219
|
+
kbid,
|
|
220
|
+
bool(predicts),
|
|
221
|
+
self.kb_usage_utility is not None,
|
|
222
|
+
)
|
|
217
223
|
return
|
|
218
|
-
|
|
219
224
|
self.kb_usage_utility.send_kb_usage(
|
|
220
225
|
service=Service.RAO,
|
|
221
226
|
account_id=account_id,
|
|
@@ -2,7 +2,7 @@ import base64
|
|
|
2
2
|
from typing import Literal
|
|
3
3
|
|
|
4
4
|
from nucliadb_models.augment import AugmentRequest, AugmentResponse
|
|
5
|
-
from nucliadb_models.configuration import SearchConfiguration
|
|
5
|
+
from nucliadb_models.configuration import AskConfig, SearchConfiguration
|
|
6
6
|
from nucliadb_models.graph.requests import GraphNodesSearchRequest, GraphSearchRequest
|
|
7
7
|
from nucliadb_models.graph.responses import (
|
|
8
8
|
GraphNodesSearchResponse,
|
|
@@ -25,7 +25,7 @@ from hyperforge_nucliadb_agentic.ask.exceptions import (
|
|
|
25
25
|
KnowledgeBoxNotFound,
|
|
26
26
|
NucliaDBError,
|
|
27
27
|
)
|
|
28
|
-
from hyperforge_nucliadb_agentic.ask.model import Image
|
|
28
|
+
from hyperforge_nucliadb_agentic.ask.model import AskRequest, Image
|
|
29
29
|
from hyperforge_nucliadb_agentic.ask.settings import settings
|
|
30
30
|
from hyperforge_nucliadb_agentic.ask.utils.ids import FieldId
|
|
31
31
|
|
|
@@ -60,6 +60,36 @@ async def get_search_configuration(
|
|
|
60
60
|
return config
|
|
61
61
|
|
|
62
62
|
|
|
63
|
+
class SearchConfigurationNotFound(Exception):
|
|
64
|
+
pass
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class InvalidAskSearchConfiguration(Exception):
|
|
68
|
+
pass
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
async def apply_ask_search_configuration(
|
|
72
|
+
reader_sdk: NucliaDBAsync,
|
|
73
|
+
kbid: str,
|
|
74
|
+
ask_request: AskRequest,
|
|
75
|
+
) -> AskRequest:
|
|
76
|
+
if ask_request.search_configuration is None:
|
|
77
|
+
return ask_request
|
|
78
|
+
|
|
79
|
+
search_config = await get_search_configuration(
|
|
80
|
+
reader_sdk, kbid, name=ask_request.search_configuration
|
|
81
|
+
)
|
|
82
|
+
if search_config is None:
|
|
83
|
+
raise SearchConfigurationNotFound
|
|
84
|
+
if not isinstance(search_config.config, AskConfig):
|
|
85
|
+
raise InvalidAskSearchConfiguration
|
|
86
|
+
|
|
87
|
+
return AskRequest.model_validate(
|
|
88
|
+
search_config.config.model_dump(exclude_unset=True)
|
|
89
|
+
| ask_request.model_dump(exclude_unset=True)
|
|
90
|
+
)
|
|
91
|
+
|
|
92
|
+
|
|
63
93
|
async def find(
|
|
64
94
|
search_sdk: NucliaDBAsync,
|
|
65
95
|
kbid: str,
|
|
@@ -9,6 +9,10 @@ from pydantic.config import ConfigDict
|
|
|
9
9
|
class NucliaDBAgentConfig(ContextAgentConfig):
|
|
10
10
|
model_config = ConfigDict(title="Knowledge Box Agent")
|
|
11
11
|
module: Literal["nucliadb_agent"] = "nucliadb_agent"
|
|
12
|
+
search_config: Optional[str] = Field(
|
|
13
|
+
default=None,
|
|
14
|
+
description="ID of an ask search configuration applied to this agent",
|
|
15
|
+
)
|
|
12
16
|
sources: List[str] = Field(
|
|
13
17
|
default_factory=list,
|
|
14
18
|
json_schema_extra={
|
{hyperforge_nucliadb_agentic-1.0.0.post96 → hyperforge_nucliadb_agentic-1.0.0.post108}/README.md
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
|