hyperforge-nucliadb-agentic 1.0.0.post78__tar.gz → 1.0.0.post83__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.
Files changed (36) hide show
  1. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/PKG-INFO +3 -3
  2. hyperforge_nucliadb_agentic-1.0.0.post83/pyproject.toml +49 -0
  3. hyperforge_nucliadb_agentic-1.0.0.post78/pyproject.toml → hyperforge_nucliadb_agentic-1.0.0.post83/pyproject.toml.orig +3 -3
  4. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/audit.py +64 -1
  5. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/README.md +0 -0
  6. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/__init__.py +0 -0
  7. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/agent.py +0 -0
  8. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/__init__.py +0 -0
  9. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/exceptions.py +0 -0
  10. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/lifespan.py +0 -0
  11. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/model.py +0 -0
  12. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/predict.py +0 -0
  13. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/predict_models.py +0 -0
  14. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/__init__.py +0 -0
  15. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/ask.py +0 -0
  16. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/graph_strategy.py +0 -0
  17. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/highlight.py +0 -0
  18. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/hydrator.py +0 -0
  19. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/metrics.py +0 -0
  20. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/parsers/__init__.py +0 -0
  21. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/parsers/ask.py +0 -0
  22. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/parsers/fetcher.py +0 -0
  23. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/parsers/find.py +0 -0
  24. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/prompt.py +0 -0
  25. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/rank_fusion.py +0 -0
  26. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/rerankers.py +0 -0
  27. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/retrieval.py +0 -0
  28. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/search/rpc.py +0 -0
  29. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/settings.py +0 -0
  30. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/utils/ids.py +0 -0
  31. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/utils/proto.py +0 -0
  32. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/utils/responses.py +0 -0
  33. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/ask/utils/text_blocks.py +0 -0
  34. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/config.py +0 -0
  35. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/internal_driver.py +0 -0
  36. {hyperforge_nucliadb_agentic-1.0.0.post78 → hyperforge_nucliadb_agentic-1.0.0.post83}/src/hyperforge_nucliadb_agentic/py.typed +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: hyperforge_nucliadb_agentic
3
- Version: 1.0.0.post78
3
+ Version: 1.0.0.post83
4
4
  Summary: NucliaDB Hyperforge agent
5
5
  Author: Nuclia
6
6
  Author-email: Nuclia <nucliadb@nuclia.com>
@@ -11,10 +11,10 @@ Classifier: Programming Language :: Python :: 3.11
11
11
  Classifier: Programming Language :: Python :: 3.12
12
12
  Classifier: Programming Language :: Python :: 3 :: Only
13
13
  Classifier: Topic :: Software Development :: Libraries :: Python Modules
14
- Requires-Dist: hyperforge>=1.0.0.post76
14
+ Requires-Dist: hyperforge>=1.0.0.post184
15
15
  Requires-Dist: lingua-language-detector
16
16
  Requires-Dist: nucliadb-sdk
17
- Requires-Python: >=3.10, <4
17
+ Requires-Python: >=3.12, <4
18
18
  Project-URL: Homepage, https://progress.com
19
19
  Project-URL: Repository, https://github.com/nuclia/nucliadb_agentic_api
20
20
  Project-URL: Changelog, https://github.com/nuclia/nucliadb_agentic_api/blob/main/agents/nucliadb/CHANGELOG.md
@@ -0,0 +1,49 @@
1
+ [build-system]
2
+ requires = ["uv_build>=0.11.19,<0.12"]
3
+ build-backend = "uv_build"
4
+
5
+ [project]
6
+ name = "hyperforge_nucliadb_agentic"
7
+ version = "1.0.0.post83"
8
+ license = "Apache-2.0"
9
+ description = "NucliaDB Hyperforge agent"
10
+ readme = "README.md"
11
+ classifiers = [
12
+ "Programming Language :: Python",
13
+ "Programming Language :: Python :: 3.10",
14
+ "Programming Language :: Python :: 3.11",
15
+ "Programming Language :: Python :: 3.12",
16
+ "Programming Language :: Python :: 3 :: Only",
17
+ "Topic :: Software Development :: Libraries :: Python Modules",
18
+ ]
19
+ requires-python = ">=3.12, <4"
20
+ dependencies = [
21
+ "hyperforge>=1.0.0.post184",
22
+ "lingua-language-detector",
23
+ "nucliadb_sdk",
24
+ ]
25
+
26
+ [[project.authors]]
27
+ name = "Nuclia"
28
+ email = "nucliadb@nuclia.com"
29
+
30
+ [project.urls]
31
+ Homepage = "https://progress.com"
32
+ Repository = "https://github.com/nuclia/nucliadb_agentic_api"
33
+ Changelog = "https://github.com/nuclia/nucliadb_agentic_api/blob/main/agents/nucliadb/CHANGELOG.md"
34
+
35
+ [dependency-groups]
36
+ dev = [
37
+ "pytest",
38
+ "pytest-benchmark",
39
+ "pytest-docker-fixtures>=1.4.2",
40
+ "pytest-lazy-fixtures",
41
+ "hyperforge_rephrase",
42
+ ]
43
+
44
+ [tool.pytest.ini_options]
45
+ asyncio_mode = "auto"
46
+ testpaths = ["tests"]
47
+
48
+ [tool.uv.build-backend]
49
+ source-exclude = ["tests/**/*"]
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "hyperforge_nucliadb_agentic"
7
- version = "1.0.0.post78"
7
+ version = "1.0.0.post83"
8
8
  license = "Apache-2.0"
9
9
  description = "NucliaDB Hyperforge agent"
10
10
  authors = [{ name = "Nuclia", email = "nucliadb@nuclia.com" }]
@@ -17,9 +17,9 @@ classifiers = [
17
17
  "Programming Language :: Python :: 3 :: Only",
18
18
  "Topic :: Software Development :: Libraries :: Python Modules",
19
19
  ]
20
- requires-python = ">=3.10, <4"
20
+ requires-python = ">=3.12, <4"
21
21
  dependencies = [
22
- "hyperforge>=1.0.0.post76",
22
+ "hyperforge>=1.0.0.post184",
23
23
  "lingua-language-detector",
24
24
  "nucliadb_sdk",
25
25
  ]
@@ -9,6 +9,7 @@ import mmh3
9
9
  import nats
10
10
  from fastapi import Request
11
11
  from hyperforge.feature_flag import Features, has_feature
12
+ from hyperforge.models import ExternalUsage, Step
12
13
  from nucliadb_models.retrieval import RawQuery, RetrievalRequest
13
14
  from nucliadb_models.search import (
14
15
  NucliaDBClientType,
@@ -19,9 +20,19 @@ from nucliadb_protos.audit_pb2 import (
19
20
  ChatContext,
20
21
  RetrievedContext,
21
22
  )
23
+ from nucliadb_protos.kb_usage_pb2 import (
24
+ ActivityLogMatch,
25
+ ActivityLogMatchType,
26
+ ClientType as KbUsageClientType,
27
+ KBSource,
28
+ Predict,
29
+ PredictType,
30
+ Service,
31
+ )
22
32
  from nucliadb_telemetry.jetstream import get_traced_jetstream, get_traced_nats_client
23
33
  from nucliadb_utils import logger
24
- from nucliadb_utils.settings import AuditSettings
34
+ from nucliadb_utils.nuclia_usage.utils.kb_usage_report import KbUsageReportUtility
35
+ from nucliadb_utils.settings import AuditSettings, usage_settings
25
36
  from nucliadb_utils.utilities import Utility, clean_utility, get_utility, set_utility
26
37
  from opentelemetry.trace import INVALID_SPAN, format_trace_id, get_current_span
27
38
  from starlette.background import BackgroundTask
@@ -38,6 +49,21 @@ from hyperforge_nucliadb_agentic.ask.predict import AnswerStatusCode
38
49
  from hyperforge_nucliadb_agentic.ask.utils.proto import client_type
39
50
 
40
51
 
52
+ def external_usage_to_predict(
53
+ event: ExternalUsage, ndb_client_type: NucliaDBClientType
54
+ ) -> Predict:
55
+ return Predict(
56
+ client=KbUsageClientType.Value(ndb_client_type.name),
57
+ type=PredictType.QUESTION_ANSWER,
58
+ model=f"{event.provider}/{event.model}",
59
+ input=event.input_tokens,
60
+ output=event.output_tokens,
61
+ num_predicts=event.requests,
62
+ image=event.image,
63
+ customer_key=False,
64
+ )
65
+
66
+
41
67
  class RequestContext:
42
68
  def __init__(self: "RequestContext"):
43
69
  self.audit_request: AuditRequest = AuditRequest()
@@ -120,6 +146,7 @@ class StreamAuditStorage:
120
146
  self.service = service
121
147
  self.task = None
122
148
  self.initialized = False
149
+ self.kb_usage_utility: KbUsageReportUtility | None = None
123
150
 
124
151
  def get_partition(self, kbid: str):
125
152
  return mmh3.hash(kbid, self.seed, signed=False) % self.partitions
@@ -155,10 +182,17 @@ class StreamAuditStorage:
155
182
 
156
183
  self.js = get_traced_jetstream(self.nc, self.service)
157
184
  self.task = asyncio.create_task(self.run())
185
+ self.kb_usage_utility = KbUsageReportUtility(
186
+ nats_stream=self.js,
187
+ nats_subject=cast(str, usage_settings.usage_jetstream_subject),
188
+ )
189
+ await self.kb_usage_utility.initialize()
158
190
 
159
191
  self.initialized = True
160
192
 
161
193
  async def finalize(self):
194
+ if self.kb_usage_utility is not None:
195
+ await self.kb_usage_utility.finalize()
162
196
  if self.task is not None:
163
197
  self.task.cancel()
164
198
  if self.nc:
@@ -166,6 +200,35 @@ class StreamAuditStorage:
166
200
  await self.nc.close()
167
201
  self.nc = None
168
202
 
203
+ def report_step_usage(
204
+ self,
205
+ *,
206
+ account_id: str,
207
+ kbid: str,
208
+ client_type: NucliaDBClientType,
209
+ step: Step,
210
+ trace_id: str | None = None,
211
+ ) -> None:
212
+ predicts = [
213
+ external_usage_to_predict(event, client_type)
214
+ for event in step.external_usage or []
215
+ ]
216
+ if not predicts or self.kb_usage_utility is None:
217
+ return
218
+
219
+ self.kb_usage_utility.send_kb_usage(
220
+ service=Service.RAO,
221
+ account_id=account_id,
222
+ kb_id=kbid,
223
+ kb_source=KBSource.HOSTED,
224
+ predicts=predicts,
225
+ activity_log_match=(
226
+ ActivityLogMatch(id=trace_id, type=ActivityLogMatchType.TRACE_ID)
227
+ if trace_id
228
+ else None
229
+ ),
230
+ )
231
+
169
232
  async def run(self):
170
233
  while True:
171
234
  item_dequeued = False