nucliadb-agentic-api 1.0.0.post207__tar.gz → 1.0.0.post211__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 (45) hide show
  1. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/PKG-INFO +1 -1
  2. nucliadb_agentic_api-1.0.0.post211/VERSION +1 -0
  3. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/pyproject.toml +1 -1
  4. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/pyproject.toml.orig +1 -1
  5. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/agentic/ask_result.py +9 -2
  6. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/db/agentic_configs.py +9 -3
  7. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/db/transform.py +12 -2
  8. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/server/session.py +22 -6
  9. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/ask.py +3 -3
  10. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/mcp_nucliadb.py +3 -3
  11. nucliadb_agentic_api-1.0.0.post207/VERSION +0 -1
  12. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/README.md +0 -0
  13. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic/README +0 -0
  14. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic/env.py +0 -0
  15. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic/script.py.mako +0 -0
  16. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic/versions/7f3b2f92a8c1_add_agentic_config_table.py +0 -0
  17. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic/versions/b3c4d5e6f7a8_add_sources_table.py +0 -0
  18. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/alembic.ini +0 -0
  19. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/VERSION +0 -0
  20. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/__init__.py +0 -0
  21. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/agentic/__init__.py +0 -0
  22. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/agentic/ask_handler.py +0 -0
  23. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/agentic/ask_transform_to_interaction.py +0 -0
  24. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/app.py +0 -0
  25. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/commands.py +0 -0
  26. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/db/__init__.py +0 -0
  27. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/db/settings.py +0 -0
  28. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/db/sources.py +0 -0
  29. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/exceptions.py +0 -0
  30. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/logging.py +0 -0
  31. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/models.py +0 -0
  32. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/py.typed +0 -0
  33. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/server/__init__.py +0 -0
  34. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/server/server.py +0 -0
  35. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/server/settings.py +0 -0
  36. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/settings.py +0 -0
  37. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/utils.py +0 -0
  38. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/__init__.py +0 -0
  39. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/agentic_configs.py +0 -0
  40. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/ask_websocket.py +0 -0
  41. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/mcp_content.py +0 -0
  42. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/oauth.py +0 -0
  43. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/router.py +0 -0
  44. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/sources.py +0 -0
  45. {nucliadb_agentic_api-1.0.0.post207 → nucliadb_agentic_api-1.0.0.post211}/src/nucliadb_agentic_api/v1/utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: nucliadb_agentic_api
3
- Version: 1.0.0.post207
3
+ Version: 1.0.0.post211
4
4
  Summary: NucliaDB Agentic API for Hyperforge
5
5
  Author: AI Data Team
6
6
  Author-email: AI Data Team <learning@nuclia.com>
@@ -0,0 +1 @@
1
+ 1.0.0.post211
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "nucliadb_agentic_api"
7
- version = "1.0.0.post207"
7
+ version = "1.0.0.post211"
8
8
  description = "NucliaDB Agentic API for Hyperforge"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.12"
@@ -4,7 +4,7 @@ build-backend = "uv_build"
4
4
 
5
5
  [project]
6
6
  name = "nucliadb_agentic_api"
7
- version = "1.0.0.post207"
7
+ version = "1.0.0.post211"
8
8
  authors = [{ name = "AI Data Team", email = "learning@nuclia.com" }]
9
9
  description = "NucliaDB Agentic API for Hyperforge"
10
10
  readme = "README.md"
@@ -15,6 +15,7 @@ from hyperforge_nucliadb_agentic.ask.model import (
15
15
  AskRetrievalMatch,
16
16
  AskTimings,
17
17
  AskTokens,
18
+ AugmentedContext,
18
19
  CitationsAskResponseItem,
19
20
  ConsumptionResponseItem,
20
21
  FootnoteCitationsAskResponseItem,
@@ -92,6 +93,14 @@ class AgenticAskResult(AskResult):
92
93
  self.generate_inner_answer = generate_inner_answer
93
94
  self.resource = resource
94
95
 
96
+ # These fields are populated by the native ask result, but the
97
+ # inherited synchronous serializer also expects them to exist.
98
+ self.prequeries_results = []
99
+ self.prompt_context = {}
100
+ self.prompt_context_order = {}
101
+ self.augmented_context = AugmentedContext()
102
+ self.debug_chat_model = None
103
+
95
104
  self._answer_text = ""
96
105
  self._reasoning_text: str | None = None
97
106
 
@@ -106,7 +115,6 @@ class AgenticAskResult(AskResult):
106
115
  self.best_matches: list[RetrievalMatch] = []
107
116
 
108
117
  async def loop(self):
109
-
110
118
  interaction = interaction_from_ask_request(self.ask_request)
111
119
  msg: AragAnswer
112
120
  async for msg in stream_response(
@@ -258,7 +266,6 @@ class AgenticAskResult(AskResult):
258
266
  async def websocket_to_ask(
259
267
  self,
260
268
  ) -> AsyncGenerator[TextGenerativeResponse | ReasoningGenerativeResponse, None]:
261
-
262
269
  output_nuclia_tokens = 0.0
263
270
  input_nuclia_tokens = 0.0
264
271
  timings = {}
@@ -8,7 +8,6 @@ import sqlalchemy as sa
8
8
  from hyperforge.database import metadata
9
9
  from hyperforge.retrieval.config import RetrievalAgentConfig
10
10
  from hyperforge_google.config import GoogleDriverConfig, GoogleInnerConfig
11
- from hyperforge_nucliadb_agentic.ask.model import AskRequest
12
11
  from hyperforge_perplexity.config import PerplexityDriverConfig, PerplexityInnerConfig
13
12
  from lru import LRU
14
13
  from nucliadb_telemetry.utils import get_telemetry, init_telemetry
@@ -20,6 +19,9 @@ from nucliadb_agentic_api.db.sources import Sources
20
19
  from nucliadb_agentic_api.db.transform import transform_agentic_config
21
20
  from nucliadb_agentic_api.models import AgenticConfigSchema
22
21
 
22
+ # Kept for the dormant AskRequest configuration path below.
23
+ # from hyperforge_nucliadb_agentic.ask.model import AskRequest
24
+
23
25
 
24
26
  # Imported lazily in methods to avoid any load-order sensitivity between the two
25
27
  # table modules (both share the same `hyperforge.database.metadata`).
@@ -241,7 +243,9 @@ class AgenticConfigs:
241
243
  external_nucliadb_url: str | None = None,
242
244
  default_memory: bool = False,
243
245
  workflow_id: str = "default",
244
- ask_request: AskRequest | None = None,
246
+ # The runtime AskRequest is consumed from QuestionMemory by NucliaDBAgent.
247
+ # Keep this dormant configuration parameter visible until its intended use is known.
248
+ # ask_request: AskRequest | None = None,
245
249
  ) -> RetrievalAgentConfig:
246
250
  # For now, we only support one config per KB, so we ignore agent_id and workflow_id, but in the future we can extend this method to support multiple configs per KB and select
247
251
  # the right one based on these parameters
@@ -257,7 +261,9 @@ class AgenticConfigs:
257
261
  internal_nucliadb_url=internal_nucliadb_url,
258
262
  external_nucliadb_url=external_nucliadb_url,
259
263
  external_nucliadb_key=external_nucliadb_key,
260
- ask_request=ask_request,
264
+ # The runtime AskRequest is consumed from QuestionMemory by NucliaDBAgent.
265
+ # Keep this dormant config path visible until its intended use is known.
266
+ # ask_request=ask_request,
261
267
  kbid=kbid,
262
268
  )
263
269
 
@@ -14,7 +14,6 @@ from hyperforge_nucliadb.driver_config import (
14
14
  NucliaDBConfig,
15
15
  NucliaDBConnection,
16
16
  )
17
- from hyperforge_nucliadb_agentic.ask.model import AskRequest
18
17
  from hyperforge_nucliadb_agentic.internal_driver import (
19
18
  InternalNucliaDBConfig,
20
19
  InternalNucliaDBConnection,
@@ -23,6 +22,9 @@ from hyperforge_nucliadb_agentic.internal_driver import (
23
22
  from nucliadb_agentic_api.db.sources import Sources
24
23
  from nucliadb_agentic_api.models import AgenticConfigSchema
25
24
 
25
+ # Kept for the dormant AskRequest configuration path below.
26
+ # from hyperforge_nucliadb_agentic.ask.model import AskRequest
27
+
26
28
 
27
29
  async def transform_agentic_config(
28
30
  agentic_config: AgenticConfigSchema,
@@ -32,7 +34,9 @@ async def transform_agentic_config(
32
34
  internal_nucliadb_url: str | None = None,
33
35
  external_nucliadb_url: str | None = None,
34
36
  external_nucliadb_key: str | None = None,
35
- ask_request: AskRequest | None = None,
37
+ # The runtime AskRequest is consumed from QuestionMemory by NucliaDBAgent.
38
+ # Keep this dormant configuration parameter visible until its intended use is known.
39
+ # ask_request: AskRequest | None = None,
36
40
  kbid: str = "",
37
41
  ) -> Tuple[RetrievalAgentConfig, Dict[str, DriverConfig], list[str]]:
38
42
  drivers: Dict[str, DriverConfig] = {}
@@ -89,6 +93,7 @@ async def transform_agentic_config(
89
93
  # Same KB different
90
94
  uid = uuid4().hex
91
95
 
96
+ source_config["id"] = f"nucliadb-agent-{source}"
92
97
  source_config["sources"] = [uid]
93
98
  source_config["module"] = "nucliadb_agent"
94
99
 
@@ -135,6 +140,9 @@ async def transform_agentic_config(
135
140
  registered_agents.append(source_config)
136
141
  elif source_obj.type == "mcp":
137
142
  uid = uuid4().hex
143
+ # See the nucliadb branch above for why this must be
144
+ # deterministic rather than random.
145
+ source_config["id"] = f"mcp-agent-{source}"
138
146
  source_config["sources"] = [uid]
139
147
  source_config["transport"] = Transport.HTTP
140
148
  source_config["module"] = "mcp"
@@ -151,11 +159,13 @@ async def transform_agentic_config(
151
159
  registered_agents.append(source_config)
152
160
 
153
161
  elif source_obj.type == "google":
162
+ source_config["id"] = f"google-agent-{source}"
154
163
  source_config["module"] = "google"
155
164
  global_driver.append("google")
156
165
  registered_agents.append(source_config)
157
166
 
158
167
  elif source_obj.type == "perplexity":
168
+ source_config["id"] = f"perplexity-agent-{source}"
159
169
  source_config["module"] = "perplexity"
160
170
  global_driver.append("perplexity")
161
171
  registered_agents.append(source_config)
@@ -24,6 +24,7 @@ from nucliadb_telemetry import errors
24
24
  from nucliadb_telemetry.utils import get_telemetry
25
25
  from nucliadb_utils.settings import AuditSettings
26
26
  from opentelemetry import trace
27
+ from pydantic import ValidationError
27
28
 
28
29
  from nucliadb_agentic_api import logger
29
30
  from nucliadb_agentic_api.db.agentic_configs import AgenticConfigs
@@ -90,11 +91,6 @@ class NucliaDBAgenticSessionManager(SessionManager):
90
91
  async def activate(self, message: StartInteraction):
91
92
  topic = None
92
93
 
93
- ask_request_json = message.arguments.get("ask_request")
94
- ask_request = None
95
- if ask_request_json:
96
- ask_request = AskRequest.model_validate_json(ask_request_json)
97
-
98
94
  logger.info("Activation message received: %s", message)
99
95
  observation = activation_observer()
100
96
  observation.start()
@@ -115,6 +111,24 @@ class NucliaDBAgenticSessionManager(SessionManager):
115
111
  message.workflow_id,
116
112
  )
117
113
 
114
+ ask_request_json = message.arguments.get("ask_request")
115
+ if ask_request_json is not None:
116
+ try:
117
+ AskRequest.model_validate_json(ask_request_json)
118
+ except ValidationError as exc:
119
+ logger.warning("Invalid ask_request argument: %s", exc)
120
+ observation.set_status("error")
121
+ await self.callback(
122
+ topic,
123
+ AragAnswer(
124
+ exception=ARAGException(detail=exc.json()),
125
+ operation=AnswerOperation.ERROR,
126
+ ),
127
+ )
128
+ await self.send_message(topic, AgentDone())
129
+ observation.end()
130
+ return
131
+
118
132
  # Get or load session
119
133
  config = await self.agent_manager.get_agent_config(
120
134
  account=message.account,
@@ -124,7 +138,9 @@ class NucliaDBAgenticSessionManager(SessionManager):
124
138
  external_nucliadb_url=self.settings.external_nucliadb_url,
125
139
  external_nucliadb_key=self.settings.external_nucliadb_key,
126
140
  workflow_id=message.workflow_id,
127
- ask_request=ask_request,
141
+ # The AskRequest is consumed from QuestionMemory by NucliaDBAgent.
142
+ # Keep this dormant config path visible until its intended use is known.
143
+ # ask_request=ask_request,
128
144
  )
129
145
 
130
146
  state = await get_state(
@@ -39,7 +39,7 @@ from nucliadb_agentic_api.v1.router import router
39
39
  status_code=200,
40
40
  summary="Ask Knowledge Box",
41
41
  description="Ask questions on a Knowledge Box",
42
- tags=["Search"],
42
+ tags=["Ask"],
43
43
  response_model=SyncAskResponse,
44
44
  )
45
45
  @requires(NucliaDBRoles.READER)
@@ -123,7 +123,7 @@ async def ask_knowledgebox_endpoint(
123
123
  status_code=200,
124
124
  summary="Ask a resource (by id)",
125
125
  description="Ask questions to a resource",
126
- tags=["Search"],
126
+ tags=["Ask"],
127
127
  response_model=SyncAskResponse,
128
128
  )
129
129
  @requires(NucliaDBRoles.READER)
@@ -185,7 +185,7 @@ async def resource_ask_endpoint_by_uuid(
185
185
  status_code=200,
186
186
  summary="Ask a resource (by slug)",
187
187
  description="Ask questions to a resource",
188
- tags=["Search"],
188
+ tags=["Ask"],
189
189
  response_model=SyncAskResponse,
190
190
  )
191
191
  @requires(NucliaDBRoles.READER)
@@ -621,7 +621,7 @@ async def read_resource(
621
621
  )
622
622
 
623
623
 
624
- @router.get("/.well-known/oauth-protected-resource/api/v1/kb/{kbid}/mcp")
624
+ @router.get("/.well-known/oauth-protected-resource/api/v1/kb/{kbid}/mcp", tags=["MCP"])
625
625
  async def mcp_protected_resource_metadata(
626
626
  request: Request,
627
627
  kbid: str,
@@ -642,8 +642,8 @@ async def mcp_protected_resource_metadata(
642
642
  }
643
643
 
644
644
 
645
- @router.get("/api/v1/kb/{kbid}/mcp")
646
- @router.post("/api/v1/kb/{kbid}/mcp")
645
+ @router.get("/api/v1/kb/{kbid}/mcp", tags=["MCP"])
646
+ @router.post("/api/v1/kb/{kbid}/mcp", tags=["MCP"])
647
647
  @requires_one([NucliaDBRoles.READER])
648
648
  async def mcp_handler(
649
649
  request: Request,
@@ -1 +0,0 @@
1
- 1.0.0.post207