unique-sdk 2026.32.0.dev3__tar.gz → 2026.32.0.dev4__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.32.0.dev3 → unique_sdk-2026.32.0.dev4}/PKG-INFO +1 -1
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/pyproject.toml +1 -1
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/mcp.py +107 -8
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/README.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_dynamic_frontend.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/cli.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/agentic_table.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/browser.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/dynamic_frontend.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/files.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/identity.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/metadata_filter.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/shell.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-dynamic-frontend/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/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.32.0.
|
|
3
|
+
Version: 2026.32.0.dev4
|
|
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>
|
|
@@ -2,8 +2,10 @@
|
|
|
2
2
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
|
+
import hashlib
|
|
5
6
|
import json
|
|
6
7
|
import logging
|
|
8
|
+
import os
|
|
7
9
|
import re
|
|
8
10
|
import sys
|
|
9
11
|
from pathlib import Path
|
|
@@ -44,6 +46,14 @@ _MCP_OUTPUT_TEXT_CHAR_LIMIT = 200_000
|
|
|
44
46
|
# the result carries no recognizable title.
|
|
45
47
|
_MCP_REFS_LOG_RELATIVE_PATH = Path(".unique") / "mcp-refs.jsonl"
|
|
46
48
|
_MCP_REFS_LOCK_FILENAME = "mcp-refs.lock"
|
|
49
|
+
# Persistent per-chat seed for ``[mcpsourceN]`` numbering. The SI runner wipes
|
|
50
|
+
# ``mcp-refs.jsonl`` between turns, so manifest-derived numbering restarts at 1
|
|
51
|
+
# every turn; this sibling file records the highest source number ever assigned
|
|
52
|
+
# in the chat so numbering stays monotonic across turns (UN-23199). Body is
|
|
53
|
+
# ``{"maxSourceNumber": <int>}``; the monorepo runner preserves this file across
|
|
54
|
+
# its per-turn reset. Absent/unreadable → seed 0 → identical to pre-seed
|
|
55
|
+
# behavior (forward/backward compatible).
|
|
56
|
+
_MCP_REFS_SEED_FILENAME = "mcp-refs-seed.json"
|
|
47
57
|
_MCP_SNIPPET_CHAR_LIMIT = 300
|
|
48
58
|
# Writer-side cap on the per-item ``text`` recorded in the refs manifest — the
|
|
49
59
|
# cited item's underlying text, consumed by the runner's hallucination check to
|
|
@@ -533,12 +543,75 @@ def _next_mcp_source_number(entries: list[dict[str, Any]]) -> int:
|
|
|
533
543
|
return max(numbers, default=0) + 1
|
|
534
544
|
|
|
535
545
|
|
|
546
|
+
def _read_mcp_refs_seed(seed_path: Path) -> int:
|
|
547
|
+
"""Read the persisted chat-wide ``maxSourceNumber`` from the seed file.
|
|
548
|
+
|
|
549
|
+
Best-effort: returns ``0`` when the file is absent, unreadable, or malformed
|
|
550
|
+
(never raises), so a missing seed reproduces the pre-seed numbering exactly.
|
|
551
|
+
"""
|
|
552
|
+
try:
|
|
553
|
+
raw = seed_path.read_text(encoding="utf-8")
|
|
554
|
+
value = json.loads(raw).get("maxSourceNumber")
|
|
555
|
+
if isinstance(value, int) and not isinstance(value, bool):
|
|
556
|
+
return value
|
|
557
|
+
except (OSError, ValueError, TypeError, AttributeError):
|
|
558
|
+
return 0
|
|
559
|
+
return 0
|
|
560
|
+
|
|
561
|
+
|
|
562
|
+
def _write_mcp_refs_seed(seed_path: Path, value: int) -> None:
|
|
563
|
+
"""Persist the chat-wide ``maxSourceNumber`` seed (best-effort, never raises).
|
|
564
|
+
|
|
565
|
+
Only writes when ``value`` exceeds the currently persisted seed, so numbers
|
|
566
|
+
never regress across turns.
|
|
567
|
+
|
|
568
|
+
The temp file is opened with ``O_NOFOLLOW`` so a symlink pre-planted at the
|
|
569
|
+
predictable temp path cannot redirect the write outside the refs directory
|
|
570
|
+
(defense in depth on top of the per-user workspace sandbox). ``os.replace``
|
|
571
|
+
operates on the directory entry and does not follow a symlink at the target.
|
|
572
|
+
``O_NOFOLLOW`` is POSIX-only; on platforms lacking it (e.g. Windows) it
|
|
573
|
+
degrades to ``0`` via ``getattr`` rather than raising ``AttributeError`` —
|
|
574
|
+
which, being outside the ``OSError`` handler, would otherwise bubble out of
|
|
575
|
+
``_annotate_mcp_results_for_citations`` after entries were written and blank
|
|
576
|
+
the Sources block.
|
|
577
|
+
"""
|
|
578
|
+
try:
|
|
579
|
+
if value <= _read_mcp_refs_seed(seed_path):
|
|
580
|
+
return
|
|
581
|
+
seed_path.parent.mkdir(parents=True, exist_ok=True)
|
|
582
|
+
tmp_path = seed_path.with_suffix(seed_path.suffix + ".tmp")
|
|
583
|
+
flags = os.O_WRONLY | os.O_CREAT | os.O_TRUNC | getattr(os, "O_NOFOLLOW", 0)
|
|
584
|
+
fd = os.open(tmp_path, flags, 0o600)
|
|
585
|
+
with os.fdopen(fd, "w", encoding="utf-8") as handle:
|
|
586
|
+
handle.write(json.dumps({"maxSourceNumber": value}))
|
|
587
|
+
os.replace(tmp_path, seed_path)
|
|
588
|
+
except OSError as exc:
|
|
589
|
+
_LOGGER.warning("mcp: failed to write refs seed: %s", exc)
|
|
590
|
+
|
|
591
|
+
|
|
536
592
|
def _item_dedup_key(tool_name: str, item: dict[str, Any]) -> str:
|
|
537
|
-
"""Dedup by title when present (same item = one chip), else by tool
|
|
593
|
+
"""Dedup by title when present (same item = one chip), else by tool + a short
|
|
594
|
+
content hash of the item's text.
|
|
595
|
+
|
|
596
|
+
Two distinct title-less fetches through one tool return different bodies, so
|
|
597
|
+
hashing the text keeps them as separate sources instead of collapsing onto
|
|
598
|
+
one number (identical bodies still merge). NOTE: this intentionally weakens
|
|
599
|
+
the search-then-fetch text-upgrade merge for title-less items only — titled
|
|
600
|
+
items still merge by title as before.
|
|
601
|
+
|
|
602
|
+
The text is capped at ``_MCP_REF_TEXT_CHAR_LIMIT`` BEFORE hashing — the same
|
|
603
|
+
cap the manifest stores under ``text``. Without it, the first call (live,
|
|
604
|
+
full-length item text) and a later call rebuilding this key from the
|
|
605
|
+
truncated manifest entry would hash to different values, so an oversized
|
|
606
|
+
title-less result would be re-assigned a duplicate ``[mcpsourceN]`` instead
|
|
607
|
+
of deduping.
|
|
608
|
+
"""
|
|
538
609
|
title = item.get("title")
|
|
539
610
|
if isinstance(title, str) and title.strip():
|
|
540
611
|
return f"title:{tool_name}:{title.strip()}"
|
|
541
|
-
|
|
612
|
+
capped_text = (item.get("text") or "")[:_MCP_REF_TEXT_CHAR_LIMIT]
|
|
613
|
+
text_hash = hashlib.sha256(capped_text.encode("utf-8")).hexdigest()[:12]
|
|
614
|
+
return f"tool:{tool_name}:{text_hash}"
|
|
542
615
|
|
|
543
616
|
|
|
544
617
|
def _ref_text(item: dict[str, Any]) -> str | None:
|
|
@@ -563,8 +636,11 @@ def _annotate_mcp_results_for_citations(
|
|
|
563
636
|
"""Assign per-turn ``[mcpsourceN]`` numbers to each retrieved item and append
|
|
564
637
|
the refs manifest. Returns ``[(sourceNumber, item)]`` for the Sources block.
|
|
565
638
|
|
|
566
|
-
Items dedup by title across the turn (same item keeps one number)
|
|
567
|
-
|
|
639
|
+
Items dedup by title across the turn (same item keeps one number); a
|
|
640
|
+
title-less item dedups by tool plus a content hash of its (capped) text, so
|
|
641
|
+
two distinct title-less results through one tool get distinct numbers while
|
|
642
|
+
identical bodies still merge (this weakens the search-then-fetch text-upgrade
|
|
643
|
+
merge for title-less items only). Best-effort — returns ``[]`` on any failure
|
|
568
644
|
(the tool result is unaffected; only the citation Sources block is skipped).
|
|
569
645
|
"""
|
|
570
646
|
refs_log_path = refs_log_path or (Path.cwd() / _MCP_REFS_LOG_RELATIVE_PATH)
|
|
@@ -581,6 +657,14 @@ def _annotate_mcp_results_for_citations(
|
|
|
581
657
|
refs_log_path, lock_filename=_MCP_REFS_LOCK_FILENAME
|
|
582
658
|
):
|
|
583
659
|
entries = _read_turn_refs_manifest(refs_log_path)
|
|
660
|
+
# Chat-wide monotonic seed: the runner wipes ``mcp-refs.jsonl``
|
|
661
|
+
# between turns, so manifest-derived numbering restarts at 1 each
|
|
662
|
+
# turn. The seed file (preserved across the runner's per-turn reset)
|
|
663
|
+
# records the highest number ever assigned in the chat so a fresh
|
|
664
|
+
# number exceeds both the current manifest max AND the chat-wide max.
|
|
665
|
+
seed_path = refs_log_path.parent / _MCP_REFS_SEED_FILENAME
|
|
666
|
+
seed = _read_mcp_refs_seed(seed_path)
|
|
667
|
+
highest_assigned = seed
|
|
584
668
|
numbers_by_key: dict[str, int] = {}
|
|
585
669
|
for entry in entries:
|
|
586
670
|
if isinstance(entry.get("sourceNumber"), int):
|
|
@@ -598,7 +682,7 @@ def _annotate_mcp_results_for_citations(
|
|
|
598
682
|
key = _item_dedup_key(tool_name, item)
|
|
599
683
|
source_number = numbers_by_key.get(key)
|
|
600
684
|
if source_number is None:
|
|
601
|
-
source_number = _next_mcp_source_number(entries)
|
|
685
|
+
source_number = max(_next_mcp_source_number(entries), seed + 1)
|
|
602
686
|
manifest_entry = {
|
|
603
687
|
"sourceNumber": source_number,
|
|
604
688
|
"toolName": tool_name,
|
|
@@ -618,6 +702,7 @@ def _annotate_mcp_results_for_citations(
|
|
|
618
702
|
numbers_by_key[key] = source_number
|
|
619
703
|
entries.append(manifest_entry)
|
|
620
704
|
entries_by_number[source_number] = manifest_entry
|
|
705
|
+
highest_assigned = max(highest_assigned, source_number)
|
|
621
706
|
else:
|
|
622
707
|
# Deduped: a prior call already claimed this source number.
|
|
623
708
|
# Backfill ``details`` the first call may have lacked (the
|
|
@@ -649,6 +734,10 @@ def _annotate_mcp_results_for_citations(
|
|
|
649
734
|
_LOGGER.warning(
|
|
650
735
|
"mcp: failed to backfill refs manifest enrichment: %s", exc
|
|
651
736
|
)
|
|
737
|
+
# Persist the chat-wide max so next turn's numbering continues above
|
|
738
|
+
# it even after the runner wipes ``mcp-refs.jsonl``.
|
|
739
|
+
if highest_assigned > seed:
|
|
740
|
+
_write_mcp_refs_seed(seed_path, highest_assigned)
|
|
652
741
|
except (UnsafeRefsLogPathError, OSError) as exc:
|
|
653
742
|
_LOGGER.warning("mcp: failed to append refs manifest: %s", exc)
|
|
654
743
|
return []
|
|
@@ -658,13 +747,19 @@ def _annotate_mcp_results_for_citations(
|
|
|
658
747
|
return annotated
|
|
659
748
|
|
|
660
749
|
|
|
661
|
-
def _citation_sources_block(
|
|
750
|
+
def _citation_sources_block(
|
|
751
|
+
annotated: list[tuple[int, dict[str, Any]]], *, tool_name: str
|
|
752
|
+
) -> str:
|
|
662
753
|
"""Tell the agent which marker to cite each retrieved item with.
|
|
663
754
|
|
|
664
755
|
Rendered *before* the tool output (leading block, not a trailing footer):
|
|
665
756
|
the agent harness spills oversized tool results to a file wholesale, and a
|
|
666
757
|
partial or programmatic read of that file only reliably sees the head — a
|
|
667
758
|
trailing marker list would be exactly what such reads miss (UN-22309).
|
|
759
|
+
|
|
760
|
+
Each line names the ``tool_name`` alongside the marker so the model has a
|
|
761
|
+
stronger anchor than a bare integer: ``{title} — {tool_name}`` when the item
|
|
762
|
+
carries a title, or ``{tool_name}`` for the title-less fallback.
|
|
668
763
|
"""
|
|
669
764
|
if not annotated:
|
|
670
765
|
return ""
|
|
@@ -674,7 +769,11 @@ def _citation_sources_block(annotated: list[tuple[int, dict[str, Any]]]) -> str:
|
|
|
674
769
|
"will not be referenced in the answer:",
|
|
675
770
|
]
|
|
676
771
|
for source_number, item in annotated:
|
|
677
|
-
|
|
772
|
+
title = item.get("title")
|
|
773
|
+
if isinstance(title, str) and title.strip():
|
|
774
|
+
label = f"{title.strip()} — {tool_name}"
|
|
775
|
+
else:
|
|
776
|
+
label = tool_name
|
|
678
777
|
lines.append(f" [mcpsource{source_number}] {label}")
|
|
679
778
|
return "\n".join(lines)
|
|
680
779
|
|
|
@@ -758,7 +857,7 @@ def record_mcp_citations(
|
|
|
758
857
|
reference_mapping=reference_mapping,
|
|
759
858
|
fallback_text=formatted_text,
|
|
760
859
|
)
|
|
761
|
-
return _citation_sources_block(annotated)
|
|
860
|
+
return _citation_sources_block(annotated, tool_name=tool_name)
|
|
762
861
|
|
|
763
862
|
|
|
764
863
|
def _read_payload(
|
|
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.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/api_resources/_search_string.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/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
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/agentic_table.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/cite_file.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/dynamic_frontend.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/web_search.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/cli/commands/web_search_config.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
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.32.0.dev3 → unique_sdk-2026.32.0.dev4}/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
|