unique-sdk 2026.30.0.dev4__tar.gz → 2026.30.0.dev6__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.
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/PKG-INFO +1 -1
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/pyproject.toml +1 -1
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/mcp.py +88 -6
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/web_search_config.py +6 -6
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/README.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_dynamic_frontend.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/cli.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/browser.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/dynamic_frontend.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/files.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/metadata_filter.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/shell.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-dynamic-frontend/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/token.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.3
|
|
2
2
|
Name: unique-sdk
|
|
3
|
-
Version: 2026.30.0.
|
|
3
|
+
Version: 2026.30.0.dev6
|
|
4
4
|
Summary:
|
|
5
5
|
Author: Martin Fadler, Konstantin Krauss, Andreas Hauri
|
|
6
6
|
Author-email: Martin Fadler <martin.fadler@unique.ch>, Konstantin Krauss <konstantin@unique.ch>, Andreas Hauri <andreas@unique.ch>
|
|
@@ -45,6 +45,13 @@ _MCP_OUTPUT_TEXT_CHAR_LIMIT = 200_000
|
|
|
45
45
|
_MCP_REFS_LOG_RELATIVE_PATH = Path(".unique") / "mcp-refs.jsonl"
|
|
46
46
|
_MCP_REFS_LOCK_FILENAME = "mcp-refs.lock"
|
|
47
47
|
_MCP_SNIPPET_CHAR_LIMIT = 300
|
|
48
|
+
# Writer-side cap on the per-item ``text`` recorded in the refs manifest — the
|
|
49
|
+
# cited item's underlying text, consumed by the runner's hallucination check to
|
|
50
|
+
# ground each ``[mcpsourceN]`` citation on what was actually retrieved
|
|
51
|
+
# (UN-22762). Half the flat-output cap (``_MCP_OUTPUT_TEXT_CHAR_LIMIT``): one
|
|
52
|
+
# cited item (a page, an issue record) rarely exceeds it, and the eval side
|
|
53
|
+
# bounds the combined cited-text payload separately.
|
|
54
|
+
_MCP_REF_TEXT_CHAR_LIMIT = 100_000
|
|
48
55
|
|
|
49
56
|
# Keys an MCP tool's JSON result commonly uses for a record's human title.
|
|
50
57
|
_TITLE_KEYS = ("title", "name", "displayName", "subject", "summary", "key")
|
|
@@ -247,6 +254,7 @@ def _titles_from_json(text: str) -> list[dict[str, Any]]:
|
|
|
247
254
|
"title": title,
|
|
248
255
|
"snippet": None,
|
|
249
256
|
"details": _details_from_json(entry),
|
|
257
|
+
"text": _record_text(entry),
|
|
250
258
|
}
|
|
251
259
|
)
|
|
252
260
|
return items
|
|
@@ -350,6 +358,31 @@ def _first_text_title(response: Any, max_chars: int) -> str | None:
|
|
|
350
358
|
return None
|
|
351
359
|
|
|
352
360
|
|
|
361
|
+
def _all_text_blocks(response: Any) -> str | None:
|
|
362
|
+
"""Concatenation of every text block — the underlying text of a single-item
|
|
363
|
+
result (e.g. a fetched document) recorded as that item's ground truth."""
|
|
364
|
+
texts: list[str] = []
|
|
365
|
+
for block in getattr(response, "content", None) or []:
|
|
366
|
+
if not isinstance(block, dict) or block.get("type") != "text":
|
|
367
|
+
continue
|
|
368
|
+
text = block.get("text")
|
|
369
|
+
if isinstance(text, str) and text.strip():
|
|
370
|
+
texts.append(text)
|
|
371
|
+
return "\n\n".join(texts) or None
|
|
372
|
+
|
|
373
|
+
|
|
374
|
+
def _record_text(record: Any) -> str | None:
|
|
375
|
+
"""A record's underlying text for citation grounding: the record itself
|
|
376
|
+
when it is a plain string, else the serialized record — which carries the
|
|
377
|
+
titled field plus all metadata the agent may cite."""
|
|
378
|
+
if isinstance(record, str):
|
|
379
|
+
return record or None
|
|
380
|
+
try:
|
|
381
|
+
return json.dumps(record, ensure_ascii=False, default=str)
|
|
382
|
+
except (TypeError, ValueError):
|
|
383
|
+
return None
|
|
384
|
+
|
|
385
|
+
|
|
353
386
|
def _extract_with_reference_mapping(
|
|
354
387
|
response: Any, mapping: dict[str, Any]
|
|
355
388
|
) -> list[dict[str, Any]]:
|
|
@@ -409,6 +442,7 @@ def _extract_with_reference_mapping(
|
|
|
409
442
|
"title": title,
|
|
410
443
|
"snippet": None,
|
|
411
444
|
"details": str(details).strip() if details else None,
|
|
445
|
+
"text": _record_text(record),
|
|
412
446
|
}
|
|
413
447
|
)
|
|
414
448
|
if items:
|
|
@@ -421,7 +455,14 @@ def _extract_with_reference_mapping(
|
|
|
421
455
|
if not records and title_from_text:
|
|
422
456
|
title = _first_text_title(response, title_max_chars)
|
|
423
457
|
if title:
|
|
424
|
-
return [
|
|
458
|
+
return [
|
|
459
|
+
{
|
|
460
|
+
"title": title,
|
|
461
|
+
"snippet": None,
|
|
462
|
+
"details": None,
|
|
463
|
+
"text": _all_text_blocks(response),
|
|
464
|
+
}
|
|
465
|
+
]
|
|
425
466
|
return items
|
|
426
467
|
|
|
427
468
|
|
|
@@ -431,8 +472,9 @@ def _extract_mcp_citation_items(
|
|
|
431
472
|
tool_name: str,
|
|
432
473
|
server_name: str | None,
|
|
433
474
|
reference_mapping: dict[str, Any] | None = None,
|
|
475
|
+
fallback_text: str | None = None,
|
|
434
476
|
) -> list[dict[str, Any]]:
|
|
435
|
-
"""Context for what the tool retrieved: ``{title, snippet}`` per item.
|
|
477
|
+
"""Context for what the tool retrieved: ``{title, snippet, text}`` per item.
|
|
436
478
|
|
|
437
479
|
An optional admin ``reference_mapping`` is applied first (deterministic
|
|
438
480
|
destructuring of a list result); when it yields nothing we fall back to the
|
|
@@ -441,6 +483,12 @@ def _extract_mcp_citation_items(
|
|
|
441
483
|
JSON-in-text). No URLs are extracted — the chip is display-only. Falls back
|
|
442
484
|
to a single title-less item (the runner names it after the tool) when the
|
|
443
485
|
result carries no recognizable title.
|
|
486
|
+
|
|
487
|
+
``text`` is the item's underlying retrieved text (the serialized record, a
|
|
488
|
+
fetched document body, or — for the title-less fallback — ``fallback_text``,
|
|
489
|
+
the whole formatted output). The runner grounds the hallucination check for
|
|
490
|
+
each cited ``[mcpsourceN]`` on it. A ``resource_link`` carries no body, so
|
|
491
|
+
its ``text`` is the link description only.
|
|
444
492
|
"""
|
|
445
493
|
if reference_mapping:
|
|
446
494
|
mapped = _extract_with_reference_mapping(response, reference_mapping)
|
|
@@ -457,7 +505,11 @@ def _extract_mcp_citation_items(
|
|
|
457
505
|
name = (block.get("name") or "").strip()
|
|
458
506
|
if name:
|
|
459
507
|
items.append(
|
|
460
|
-
{
|
|
508
|
+
{
|
|
509
|
+
"title": name,
|
|
510
|
+
"snippet": _snippet(block.get("description")),
|
|
511
|
+
"text": block.get("description") or None,
|
|
512
|
+
}
|
|
461
513
|
)
|
|
462
514
|
|
|
463
515
|
if not items:
|
|
@@ -467,7 +519,7 @@ def _extract_mcp_citation_items(
|
|
|
467
519
|
|
|
468
520
|
if not items:
|
|
469
521
|
# No recognizable title — one chip named after the tool itself.
|
|
470
|
-
items.append({"title": None, "snippet": None})
|
|
522
|
+
items.append({"title": None, "snippet": None, "text": fallback_text})
|
|
471
523
|
|
|
472
524
|
return items
|
|
473
525
|
|
|
@@ -489,6 +541,16 @@ def _item_dedup_key(tool_name: str, item: dict[str, Any]) -> str:
|
|
|
489
541
|
return f"tool:{tool_name}"
|
|
490
542
|
|
|
491
543
|
|
|
544
|
+
def _ref_text(item: dict[str, Any]) -> str | None:
|
|
545
|
+
"""The item's underlying text for the manifest, capped at
|
|
546
|
+
``_MCP_REF_TEXT_CHAR_LIMIT`` (single write-side cap shared by all
|
|
547
|
+
extraction modes)."""
|
|
548
|
+
text = item.get("text")
|
|
549
|
+
if not isinstance(text, str) or not text:
|
|
550
|
+
return None
|
|
551
|
+
return text[:_MCP_REF_TEXT_CHAR_LIMIT]
|
|
552
|
+
|
|
553
|
+
|
|
492
554
|
def _annotate_mcp_results_for_citations(
|
|
493
555
|
response: Any,
|
|
494
556
|
*,
|
|
@@ -496,6 +558,7 @@ def _annotate_mcp_results_for_citations(
|
|
|
496
558
|
server_name: str | None,
|
|
497
559
|
refs_log_path: Path | None = None,
|
|
498
560
|
reference_mapping: dict[str, Any] | None = None,
|
|
561
|
+
fallback_text: str | None = None,
|
|
499
562
|
) -> list[tuple[int, dict[str, Any]]]:
|
|
500
563
|
"""Assign per-turn ``[mcpsourceN]`` numbers to each retrieved item and append
|
|
501
564
|
the refs manifest. Returns ``[(sourceNumber, item)]`` for the Sources block.
|
|
@@ -512,6 +575,7 @@ def _annotate_mcp_results_for_citations(
|
|
|
512
575
|
tool_name=tool_name,
|
|
513
576
|
server_name=server_name,
|
|
514
577
|
reference_mapping=reference_mapping,
|
|
578
|
+
fallback_text=fallback_text,
|
|
515
579
|
)
|
|
516
580
|
with _locked_turn_refs_manifest(
|
|
517
581
|
refs_log_path, lock_filename=_MCP_REFS_LOCK_FILENAME
|
|
@@ -542,6 +606,7 @@ def _annotate_mcp_results_for_citations(
|
|
|
542
606
|
"title": item.get("title"),
|
|
543
607
|
"snippet": item.get("snippet"),
|
|
544
608
|
"details": item.get("details"),
|
|
609
|
+
"text": _ref_text(item),
|
|
545
610
|
}
|
|
546
611
|
try:
|
|
547
612
|
_append_turn_refs_manifest_entry(refs_log_path, manifest_entry)
|
|
@@ -563,13 +628,26 @@ def _annotate_mcp_results_for_citations(
|
|
|
563
628
|
if stored is not None and new_details and not stored.get("details"):
|
|
564
629
|
stored["details"] = new_details
|
|
565
630
|
needs_rewrite = True
|
|
631
|
+
# ``text`` upgrades to the longer capture: the common turn
|
|
632
|
+
# is a search (small per-record JSON) followed by a full
|
|
633
|
+
# fetch of the same titled item — the later, richer text is
|
|
634
|
+
# the better ground truth for the hallucination check.
|
|
635
|
+
new_text = _ref_text(item)
|
|
636
|
+
if stored is not None and new_text:
|
|
637
|
+
stored_text = stored.get("text")
|
|
638
|
+
stored_len = (
|
|
639
|
+
len(stored_text) if isinstance(stored_text, str) else 0
|
|
640
|
+
)
|
|
641
|
+
if len(new_text) > stored_len:
|
|
642
|
+
stored["text"] = new_text
|
|
643
|
+
needs_rewrite = True
|
|
566
644
|
annotated.append((source_number, item))
|
|
567
645
|
if needs_rewrite:
|
|
568
646
|
try:
|
|
569
647
|
_rewrite_turn_refs_manifest(refs_log_path, entries)
|
|
570
648
|
except (UnsafeRefsLogPathError, OSError) as exc:
|
|
571
649
|
_LOGGER.warning(
|
|
572
|
-
"mcp: failed to backfill refs manifest
|
|
650
|
+
"mcp: failed to backfill refs manifest enrichment: %s", exc
|
|
573
651
|
)
|
|
574
652
|
except (UnsafeRefsLogPathError, OSError) as exc:
|
|
575
653
|
_LOGGER.warning("mcp: failed to append refs manifest: %s", exc)
|
|
@@ -656,7 +734,10 @@ def record_mcp_citations(
|
|
|
656
734
|
- ``response`` is the raw ``unique_sdk.MCP`` result, used for citation
|
|
657
735
|
extraction (titles from ``resource_link`` names / JSON bodies).
|
|
658
736
|
- ``formatted_text`` is the source text the model actually saw for this
|
|
659
|
-
tool result, recorded as the hallucination groundedness context.
|
|
737
|
+
tool result, recorded as the hallucination groundedness context. It also
|
|
738
|
+
serves as the per-item ``text`` of the title-less fallback chip, so a
|
|
739
|
+
cited ``[mcpsourceN]`` without extractable records still grounds on the
|
|
740
|
+
whole output.
|
|
660
741
|
|
|
661
742
|
Best-effort and never raises: the underlying manifest writers swallow their
|
|
662
743
|
own errors, and ``_annotate_mcp_results_for_citations`` owns the per-turn
|
|
@@ -675,6 +756,7 @@ def record_mcp_citations(
|
|
|
675
756
|
server_name=server_name,
|
|
676
757
|
refs_log_path=unique_dir / _MCP_REFS_LOG_RELATIVE_PATH.name,
|
|
677
758
|
reference_mapping=reference_mapping,
|
|
759
|
+
fallback_text=formatted_text,
|
|
678
760
|
)
|
|
679
761
|
return _citation_sources_block(annotated)
|
|
680
762
|
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/web_search_config.py
RENAMED
|
@@ -12,8 +12,8 @@ Two file shapes are recognised:
|
|
|
12
12
|
1. **Full platform config** — a complete ``WebSearchConfig`` payload as
|
|
13
13
|
emitted by the platform (camelCase or snake_case). Detected by the
|
|
14
14
|
presence of ``webSearchActiveMode`` / ``web_search_active_mode`` or a
|
|
15
|
-
discriminator field (``
|
|
16
|
-
``crawler_type`` / ``crawlerType``) inside the nested engine/crawler
|
|
15
|
+
discriminator field (``engine`` / ``searchEngineName`` / ``search_engine_name``,
|
|
16
|
+
``crawler`` / ``crawler_type`` / ``crawlerType``) inside the nested engine/crawler
|
|
17
17
|
dicts. The nested ``searchEngineConfig`` and ``crawlerConfig`` blocks
|
|
18
18
|
are forwarded verbatim to the API.
|
|
19
19
|
|
|
@@ -37,8 +37,8 @@ DEFAULT_CONFIG_PATH = Path.home() / ".unique-websearch.json"
|
|
|
37
37
|
ENV_CONFIG_PATH = "UNIQUE_WEBSEARCH_CONFIG"
|
|
38
38
|
|
|
39
39
|
_MODE_KEYS = frozenset({"webSearchActiveMode", "web_search_active_mode"})
|
|
40
|
-
_ENGINE_DISCRIMINATORS = frozenset({"
|
|
41
|
-
_CRAWLER_DISCRIMINATORS = frozenset({"crawler_type", "crawlerType"})
|
|
40
|
+
_ENGINE_DISCRIMINATORS = frozenset({"engine", "searchEngineName", "search_engine_name"})
|
|
41
|
+
_CRAWLER_DISCRIMINATORS = frozenset({"crawler", "crawler_type", "crawlerType"})
|
|
42
42
|
|
|
43
43
|
_ENGINE_KEYS = ("searchEngineConfig", "search_engine_config")
|
|
44
44
|
_CRAWLER_KEYS = ("crawlerConfig", "crawler_config")
|
|
@@ -134,8 +134,8 @@ def is_full_platform_config(data: dict[str, Any]) -> bool:
|
|
|
134
134
|
|
|
135
135
|
A full config is identified by the ``webSearchActiveMode`` /
|
|
136
136
|
``web_search_active_mode`` top-level key, or by a discriminator
|
|
137
|
-
(``searchEngineName`` / ``crawlerType``)
|
|
138
|
-
engine/crawler config dicts.
|
|
137
|
+
(``engine`` / ``searchEngineName``; ``crawler`` / ``crawlerType``)
|
|
138
|
+
inside the nested engine/crawler config dicts.
|
|
139
139
|
"""
|
|
140
140
|
if set(data.keys()) & _MODE_KEYS:
|
|
141
141
|
return True
|
|
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
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_search_string.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/api_resources/_web_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/cite_file.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/dynamic_frontend.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/cli/commands/web_search.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
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev4 → unique_sdk-2026.30.0.dev6}/unique_sdk/utils/benchmarking_run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|