nucliadb-agentic-api 1.0.0.post294__tar.gz → 1.0.0.post301__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.
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/PKG-INFO +1 -1
- nucliadb_agentic_api-1.0.0.post301/VERSION +1 -0
- nucliadb_agentic_api-1.0.0.post301/alembic/versions/b3781ec6a8ad_migration_of_aws_claude_4_1_opus.py +26 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/pyproject.toml +1 -1
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/pyproject.toml.orig +1 -1
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/mcp_nucliadb.py +147 -25
- nucliadb_agentic_api-1.0.0.post294/VERSION +0 -1
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/README.md +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/README +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/env.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/script.py.mako +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/versions/0fe6c7b5f33d_migrate_sonnet_and_gpt_5_6_models.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/versions/7f3b2f92a8c1_add_agentic_config_table.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/versions/b3c4d5e6f7a8_add_sources_table.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/versions/c4d5e6f7a8b9_add_agentic_config_soft_deletion.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic.ini +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/VERSION +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/__init__.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/agentic/__init__.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/agentic/ask_handler.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/agentic/ask_result.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/agentic/ask_transform_to_interaction.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/app.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/commands.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/__init__.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/agentic_configs.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/llm_migration_utils.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/settings.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/sources.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/db/transform.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/exceptions.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/logging.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/models.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/py.typed +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/server/__init__.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/server/server.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/server/session.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/server/settings.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/settings.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/utils.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/__init__.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/agentic_configs.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/ask.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/ask_websocket.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/mcp_content.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/oauth.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/router.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/sources.py +0 -0
- {nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/src/nucliadb_agentic_api/v1/utils.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
1.0.0.post301
|
nucliadb_agentic_api-1.0.0.post301/alembic/versions/b3781ec6a8ad_migration_of_aws_claude_4_1_opus.py
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
"""migration of aws claude 4 1 opus
|
|
2
|
+
|
|
3
|
+
Revision ID: b3781ec6a8ad
|
|
4
|
+
Revises: 0fe6c7b5f33d
|
|
5
|
+
Create Date: 2026-10-01 13:04:16.465758
|
|
6
|
+
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from typing import Sequence, Union
|
|
10
|
+
|
|
11
|
+
from alembic import op
|
|
12
|
+
from nucliadb_agentic_api.db.llm_migration_utils import migrate_llm_models
|
|
13
|
+
|
|
14
|
+
# revision identifiers, used by Alembic.
|
|
15
|
+
revision: str = "b3781ec6a8ad"
|
|
16
|
+
down_revision: Union[str, Sequence[str], None] = "0fe6c7b5f33d"
|
|
17
|
+
branch_labels: Union[str, Sequence[str], None] = None
|
|
18
|
+
depends_on: Union[str, Sequence[str], None] = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def upgrade() -> None:
|
|
22
|
+
migrate_llm_models(op.get_bind(), {"aws-claude-4-1-opus": "aws-claude-4-8-opus"})
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def downgrade() -> None:
|
|
26
|
+
pass
|
{nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/pyproject.toml.orig
RENAMED
|
@@ -4,7 +4,7 @@ build-backend = "uv_build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "nucliadb_agentic_api"
|
|
7
|
-
version = "1.0.0.
|
|
7
|
+
version = "1.0.0.post301"
|
|
8
8
|
authors = [{ name = "AI Data Team", email = "learning@nuclia.com" }]
|
|
9
9
|
description = "NucliaDB Agentic API for Hyperforge"
|
|
10
10
|
readme = "README.md"
|
|
@@ -45,6 +45,7 @@ from hyperforge_nucliadb_agentic.ask.exceptions import (
|
|
|
45
45
|
)
|
|
46
46
|
from hyperforge_nucliadb_agentic.ask.model import (
|
|
47
47
|
AskRequest,
|
|
48
|
+
ChatOptions,
|
|
48
49
|
CitationsType,
|
|
49
50
|
FieldExtensionStrategy,
|
|
50
51
|
Filter,
|
|
@@ -52,6 +53,7 @@ from hyperforge_nucliadb_agentic.ask.model import (
|
|
|
52
53
|
MetadataExtensionType,
|
|
53
54
|
NeighbouringParagraphsStrategy,
|
|
54
55
|
)
|
|
56
|
+
from hyperforge_nucliadb_agentic.ask.search import rpc
|
|
55
57
|
from hyperforge_nucliadb_agentic.ask.search.ask import (
|
|
56
58
|
AskResult,
|
|
57
59
|
ask,
|
|
@@ -100,11 +102,11 @@ class SearchDocumentsArgs(BaseModel):
|
|
|
100
102
|
)
|
|
101
103
|
search_configuration: str | None = Field(
|
|
102
104
|
None,
|
|
103
|
-
description="Optional. The name of
|
|
105
|
+
description="Optional. The name of a saved Search Configuration (ask or find) whose settings (filters, retrieval and RAG strategies, prompts, model...) are applied to the search. If not provided, default settings are used.",
|
|
104
106
|
)
|
|
105
107
|
filters: list[Filter] | None = Field(
|
|
106
108
|
None,
|
|
107
|
-
description="Optional. A list of filter objects to narrow results. Each filter can include 'all' (AND), 'any' (OR), and/or 'not_all' (NOT AND) label paths like '/l/labelset/label'.",
|
|
109
|
+
description="Optional. A list of filter objects to narrow results. Each filter can include 'all' (AND), 'any' (OR), and/or 'not_all' (NOT AND) label paths like '/l/labelset/label'. When a Search Configuration is used, these filters are combined (AND) with its saved filters.",
|
|
108
110
|
)
|
|
109
111
|
|
|
110
112
|
|
|
@@ -217,35 +219,155 @@ def _append_document_ids_to_answer(
|
|
|
217
219
|
return f"{answer_text}\n\nDocument IDs:\n{document_ids_text}"
|
|
218
220
|
|
|
219
221
|
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
222
|
+
def _mcp_default_ask_parameters() -> dict[str, Any]:
|
|
223
|
+
"""Parameters used by the MCP tool when the search configuration does not set them."""
|
|
224
|
+
return {
|
|
225
|
+
"rag_strategies": [
|
|
226
|
+
FieldExtensionStrategy(fields=["a/title", "a/summary"]),
|
|
227
|
+
NeighbouringParagraphsStrategy(before=5, after=5),
|
|
228
|
+
MetadataExtensionStrategy(
|
|
229
|
+
types=[
|
|
230
|
+
MetadataExtensionType.CLASSIFICATION_LABELS,
|
|
231
|
+
MetadataExtensionType.ORIGIN,
|
|
232
|
+
]
|
|
233
|
+
),
|
|
234
|
+
],
|
|
235
|
+
"debug": True,
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
# Parameters the MCP tool response format depends on (answer text + footnote
|
|
240
|
+
# citations mapped to documents), so they always win over the search configuration.
|
|
241
|
+
_MCP_FORCED_ASK_PARAMETERS: dict[str, Any] = {
|
|
242
|
+
"generate_answer": True,
|
|
243
|
+
"citations": CitationsType.LLM_FOOTNOTES,
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
|
|
247
|
+
async def _load_search_configuration(context: MCPContext, name: str) -> dict[str, Any]:
|
|
248
|
+
"""Fetch a saved Search Configuration and return the ask parameters it sets.
|
|
249
|
+
|
|
250
|
+
Both `ask` and `find` configurations are supported: `search_documents` runs an
|
|
251
|
+
ask, so `find` configurations contribute their retrieval parameters (filters,
|
|
252
|
+
top_k, features, reranker, ...) and parameters with no ask equivalent are ignored.
|
|
253
|
+
"""
|
|
254
|
+
try:
|
|
255
|
+
search_config = await rpc.get_search_configuration(
|
|
256
|
+
context.ndb_reader, context.kbid, name=name
|
|
257
|
+
)
|
|
258
|
+
except Exception as e:
|
|
259
|
+
logger.exception(f"Error fetching search configuration '{name}'")
|
|
260
|
+
raise ResourceError(
|
|
261
|
+
f"Failed to load search configuration '{name}'"
|
|
262
|
+
+ (f": {e}" if str(e) else "")
|
|
263
|
+
) from e
|
|
264
|
+
if search_config is None:
|
|
265
|
+
raise ResourceError(f"Search configuration not found: '{name}'")
|
|
266
|
+
|
|
267
|
+
# AskConfig/FindConfig are built with `create_model`, so mypy can't see them as models
|
|
268
|
+
config_model: BaseModel = search_config.config
|
|
269
|
+
params = config_model.model_dump(mode="json", exclude_unset=True)
|
|
270
|
+
params.pop("query", None) # the tool query always wins
|
|
271
|
+
ignored = sorted(set(params) - set(AskRequest.model_fields))
|
|
272
|
+
if "features" in params:
|
|
273
|
+
# Find supports features ask does not (e.g. `graph`)
|
|
274
|
+
ask_features = {o.value for o in ChatOptions}
|
|
275
|
+
features = [f for f in params["features"] if f in ask_features]
|
|
276
|
+
if len(features) != len(params["features"]):
|
|
277
|
+
ignored.append(f"features={sorted(set(params['features']) - ask_features)}")
|
|
278
|
+
if features:
|
|
279
|
+
params["features"] = features
|
|
280
|
+
else:
|
|
281
|
+
params.pop("features") # nothing left, use the defaults
|
|
282
|
+
if ignored:
|
|
283
|
+
logger.info(
|
|
284
|
+
f"Search configuration '{name}' ({search_config.kind}) parameters not "
|
|
285
|
+
f"applicable to search_documents are ignored: {ignored}"
|
|
286
|
+
)
|
|
287
|
+
return {k: v for k, v in params.items() if k in AskRequest.model_fields}
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
def _combine_filters(
|
|
291
|
+
config_params: dict[str, Any], tool_filters: list[Filter], name: str
|
|
292
|
+
) -> list[dict[str, Any]]:
|
|
293
|
+
"""AND the tool filters with the search configuration filters.
|
|
294
|
+
|
|
295
|
+
The tool filters can only narrow results further: they never replace the
|
|
296
|
+
filters saved in the search configuration.
|
|
297
|
+
"""
|
|
298
|
+
if config_params.get("filter_expression") is not None:
|
|
299
|
+
raise ResourceError(
|
|
300
|
+
f"Search configuration '{name}' defines a filter expression, which "
|
|
301
|
+
"cannot be combined with the 'filters' argument. Retry without 'filters'."
|
|
302
|
+
)
|
|
303
|
+
combined: list[dict[str, Any]] = [
|
|
304
|
+
{"all": [f]} if isinstance(f, str) else f
|
|
305
|
+
for f in config_params.get("filters") or []
|
|
236
306
|
]
|
|
307
|
+
combined.extend(f.model_dump(mode="json", exclude_unset=True) for f in tool_filters)
|
|
308
|
+
return combined
|
|
237
309
|
|
|
238
|
-
if args.filters is not None:
|
|
239
|
-
ask_request.filters = args.filters
|
|
240
310
|
|
|
311
|
+
async def _build_ask_request(
|
|
312
|
+
context: MCPContext, args: SearchDocumentsArgs
|
|
313
|
+
) -> AskRequest:
|
|
314
|
+
"""Build the ask request for `search_documents`.
|
|
315
|
+
|
|
316
|
+
Precedence: tool query/filters and MCP output requirements > saved search
|
|
317
|
+
configuration > MCP defaults.
|
|
318
|
+
"""
|
|
319
|
+
params: dict[str, Any] = {}
|
|
241
320
|
if args.search_configuration is not None:
|
|
242
|
-
|
|
321
|
+
params = await _load_search_configuration(context, args.search_configuration)
|
|
322
|
+
if params.get("answer_json_schema") is not None:
|
|
323
|
+
# The MCP response only renders text answers with footnote citations
|
|
324
|
+
raise ResourceError(
|
|
325
|
+
f"Search configuration '{args.search_configuration}' uses a structured "
|
|
326
|
+
"answer (answer_json_schema), which search_documents does not support"
|
|
327
|
+
)
|
|
328
|
+
params["search_configuration"] = args.search_configuration
|
|
329
|
+
|
|
330
|
+
for key, value in _mcp_default_ask_parameters().items():
|
|
331
|
+
params.setdefault(key, value)
|
|
332
|
+
|
|
333
|
+
if args.filters is not None:
|
|
334
|
+
if args.search_configuration is not None:
|
|
335
|
+
params["filters"] = _combine_filters(
|
|
336
|
+
params, args.filters, args.search_configuration
|
|
337
|
+
)
|
|
338
|
+
else:
|
|
339
|
+
params["filters"] = args.filters
|
|
340
|
+
|
|
341
|
+
params.update(_MCP_FORCED_ASK_PARAMETERS)
|
|
342
|
+
params["audit_metadata"] = {
|
|
343
|
+
**(params.get("audit_metadata") or {}),
|
|
344
|
+
"source": "mcp_tool",
|
|
345
|
+
}
|
|
346
|
+
params["query"] = args.query
|
|
347
|
+
|
|
348
|
+
try:
|
|
349
|
+
return AskRequest.model_validate(params)
|
|
350
|
+
except ValidationError as e:
|
|
351
|
+
error_details = "; ".join(
|
|
352
|
+
f"'{'.'.join(str(p) for p in err['loc'])}': {err['msg']}"
|
|
353
|
+
for err in e.errors()
|
|
354
|
+
)
|
|
355
|
+
raise ResourceError(
|
|
356
|
+
"Invalid search parameters"
|
|
357
|
+
+ (
|
|
358
|
+
f" from search configuration '{args.search_configuration}'"
|
|
359
|
+
if args.search_configuration
|
|
360
|
+
else ""
|
|
361
|
+
)
|
|
362
|
+
+ f": {error_details}"
|
|
363
|
+
) from e
|
|
243
364
|
|
|
244
|
-
# citations does not work with rag strategies yet
|
|
245
365
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
366
|
+
async def _tool_search_documents(
|
|
367
|
+
context: MCPContext,
|
|
368
|
+
args: SearchDocumentsArgs,
|
|
369
|
+
) -> Sequence[TextContent | ImageContent | EmbeddedResource]:
|
|
370
|
+
ask_request = await _build_ask_request(context, args)
|
|
249
371
|
try:
|
|
250
372
|
ask_result: AskResult = await ask(
|
|
251
373
|
search_sdk=context.ndb_search,
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
1.0.0.post294
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{nucliadb_agentic_api-1.0.0.post294 → nucliadb_agentic_api-1.0.0.post301}/alembic/script.py.mako
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
|