unique-sdk 2026.24.0.dev8__tar.gz → 2026.24.0.dev9__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.24.0.dev8 → unique_sdk-2026.24.0.dev9}/PKG-INFO +1 -1
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/pyproject.toml +2 -1
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_util.py +1 -1
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/cli.py +29 -0
- unique_sdk-2026.24.0.dev9/unique_sdk/cli/commands/cite_file.py +150 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/shell.py +35 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +27 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/README.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/files.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/mcp.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/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.24.0.
|
|
3
|
+
Version: 2026.24.0.dev9
|
|
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>
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
[project]
|
|
2
2
|
name = "unique_sdk"
|
|
3
|
-
version = "2026.24.0.
|
|
3
|
+
version = "2026.24.0.dev9"
|
|
4
4
|
description = ""
|
|
5
5
|
readme = "README.md"
|
|
6
6
|
license = { text = "MIT" }
|
|
@@ -77,6 +77,7 @@ reportUnusedCallResult = "none"
|
|
|
77
77
|
reportUnannotatedClassAttribute = "none"
|
|
78
78
|
reportImplicitOverride = "none"
|
|
79
79
|
reportImplicitStringConcatenation = "none"
|
|
80
|
+
reportPrivateUsage = "none"
|
|
80
81
|
reportUnusedParameter = "none"
|
|
81
82
|
reportImportCycles = "none"
|
|
82
83
|
|
|
@@ -7,6 +7,7 @@ from typing import Any
|
|
|
7
7
|
import click
|
|
8
8
|
|
|
9
9
|
from unique_sdk.cli import __version__
|
|
10
|
+
from unique_sdk.cli.commands.cite_file import cmd_cite_file
|
|
10
11
|
from unique_sdk.cli.commands.elicitation import (
|
|
11
12
|
cmd_elicit_ask,
|
|
12
13
|
cmd_elicit_create,
|
|
@@ -300,6 +301,34 @@ def download(ctx: click.Context, name_or_id: str, local_dest: str | None) -> Non
|
|
|
300
301
|
click.echo(cmd_download(LazyState.get(ctx), name_or_id, local_dest))
|
|
301
302
|
|
|
302
303
|
|
|
304
|
+
@main.command(name="cite")
|
|
305
|
+
@click.argument("name_or_id")
|
|
306
|
+
@click.option(
|
|
307
|
+
"--pages",
|
|
308
|
+
"-p",
|
|
309
|
+
default=None,
|
|
310
|
+
help="Page numbers to cite: '3-7' or '1,3,5'. Omit for whole-file.",
|
|
311
|
+
)
|
|
312
|
+
@click.pass_context
|
|
313
|
+
def cite(
|
|
314
|
+
ctx: click.Context,
|
|
315
|
+
name_or_id: str,
|
|
316
|
+
pages: str | None,
|
|
317
|
+
) -> None:
|
|
318
|
+
"""Declare page citations for a file.
|
|
319
|
+
|
|
320
|
+
\b
|
|
321
|
+
Registers [filesourceN] markers for pages you referenced in your answer.
|
|
322
|
+
Does NOT read or extract the file — use your own tools for that.
|
|
323
|
+
|
|
324
|
+
\b
|
|
325
|
+
Examples:
|
|
326
|
+
unique-cli cite report.pdf --pages 3,5,7
|
|
327
|
+
unique-cli cite cont_abc123 --pages 1-4
|
|
328
|
+
"""
|
|
329
|
+
click.echo(cmd_cite_file(LazyState.get(ctx), name_or_id, pages))
|
|
330
|
+
|
|
331
|
+
|
|
303
332
|
@main.command()
|
|
304
333
|
@click.argument("name_or_id")
|
|
305
334
|
@click.pass_context
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Cite command: declare file page citations without extracting text."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import json
|
|
6
|
+
from pathlib import Path
|
|
7
|
+
|
|
8
|
+
from unique_sdk.cli.commands._citation_manifest import (
|
|
9
|
+
UnsafeRefsLogPathError,
|
|
10
|
+
_append_turn_refs_manifest_entry,
|
|
11
|
+
_locked_turn_refs_manifest,
|
|
12
|
+
_read_turn_refs_manifest,
|
|
13
|
+
)
|
|
14
|
+
from unique_sdk.cli.commands.files import _resolve_content_id
|
|
15
|
+
from unique_sdk.cli.state import ShellState
|
|
16
|
+
|
|
17
|
+
CITE_ERROR_PREFIX = "cite:"
|
|
18
|
+
|
|
19
|
+
_FILE_REFS_LOG_RELATIVE_PATH = Path(".unique") / "file-refs.jsonl"
|
|
20
|
+
_FILE_REFS_LOCK_FILENAME = "file-refs.lock"
|
|
21
|
+
_CHAT_FILES_MANIFEST = Path(".unique") / "chat-files.json"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
_MAX_PAGES_PER_CALL = 500
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
def _parse_pages(pages: str | None) -> list[int]:
|
|
28
|
+
"""Parse '3-7' or '1,3,5' into a list of 1-based page numbers.
|
|
29
|
+
|
|
30
|
+
Returns [0] (whole-file) when pages is None or empty.
|
|
31
|
+
Returns [] on invalid input (triggers error in caller).
|
|
32
|
+
"""
|
|
33
|
+
if not pages or not pages.strip():
|
|
34
|
+
return [0]
|
|
35
|
+
selected: list[int] = []
|
|
36
|
+
for part in pages.split(","):
|
|
37
|
+
part = part.strip()
|
|
38
|
+
if not part:
|
|
39
|
+
continue
|
|
40
|
+
if "-" in part:
|
|
41
|
+
bounds = part.split("-", 1)
|
|
42
|
+
start_s, end_s = bounds[0].strip(), bounds[1].strip()
|
|
43
|
+
if not start_s.isdecimal() or not end_s.isdecimal():
|
|
44
|
+
return []
|
|
45
|
+
start, end = int(start_s), int(end_s)
|
|
46
|
+
if start < 1 or end < start or (end - start + 1) > _MAX_PAGES_PER_CALL:
|
|
47
|
+
return []
|
|
48
|
+
selected.extend(range(start, end + 1))
|
|
49
|
+
else:
|
|
50
|
+
if not part.isdecimal() or int(part) < 1:
|
|
51
|
+
return []
|
|
52
|
+
selected.append(int(part))
|
|
53
|
+
if not selected:
|
|
54
|
+
return []
|
|
55
|
+
if len(set(selected)) > _MAX_PAGES_PER_CALL:
|
|
56
|
+
return []
|
|
57
|
+
return sorted(set(selected))
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
def _resolve_content_id_with_manifest(
|
|
61
|
+
state: ShellState, name_or_id: str
|
|
62
|
+
) -> tuple[str, str]:
|
|
63
|
+
"""Resolve a filename/content_id checking the chat-files manifest first.
|
|
64
|
+
|
|
65
|
+
Resolution order:
|
|
66
|
+
1. If name_or_id starts with "cont_", return it directly.
|
|
67
|
+
2. Check .unique/chat-files.json for a matching filename (exact or basename).
|
|
68
|
+
3. Fall back to KB resolution via _resolve_content_id.
|
|
69
|
+
"""
|
|
70
|
+
if name_or_id.startswith("cont_"):
|
|
71
|
+
return name_or_id, name_or_id
|
|
72
|
+
|
|
73
|
+
manifest_path = Path.cwd() / _CHAT_FILES_MANIFEST
|
|
74
|
+
if manifest_path.is_file():
|
|
75
|
+
try:
|
|
76
|
+
manifest: dict[str, str] = json.loads(
|
|
77
|
+
manifest_path.read_text(encoding="utf-8")
|
|
78
|
+
)
|
|
79
|
+
except (json.JSONDecodeError, OSError):
|
|
80
|
+
manifest = {}
|
|
81
|
+
|
|
82
|
+
basename = Path(name_or_id).name
|
|
83
|
+
content_id = manifest.get(name_or_id) or manifest.get(basename)
|
|
84
|
+
if content_id:
|
|
85
|
+
return content_id, basename
|
|
86
|
+
|
|
87
|
+
return _resolve_content_id(state, name_or_id)
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def cmd_cite_file(
|
|
91
|
+
state: ShellState,
|
|
92
|
+
name_or_id: str,
|
|
93
|
+
pages: str | None,
|
|
94
|
+
) -> str:
|
|
95
|
+
"""Declare citations for a file's pages.
|
|
96
|
+
|
|
97
|
+
Writes entries to .unique/file-refs.jsonl and returns [filesourceN]
|
|
98
|
+
markers for the agent to use inline.
|
|
99
|
+
"""
|
|
100
|
+
try:
|
|
101
|
+
content_id, filename = _resolve_content_id_with_manifest(state, name_or_id)
|
|
102
|
+
except Exception as exc:
|
|
103
|
+
return f"{CITE_ERROR_PREFIX} {exc}"
|
|
104
|
+
|
|
105
|
+
page_list = _parse_pages(pages)
|
|
106
|
+
if not page_list:
|
|
107
|
+
return f"{CITE_ERROR_PREFIX} invalid --pages value"
|
|
108
|
+
|
|
109
|
+
refs_log_path = Path.cwd() / _FILE_REFS_LOG_RELATIVE_PATH
|
|
110
|
+
|
|
111
|
+
try:
|
|
112
|
+
with _locked_turn_refs_manifest(
|
|
113
|
+
refs_log_path, lock_filename=_FILE_REFS_LOCK_FILENAME
|
|
114
|
+
):
|
|
115
|
+
existing = _read_turn_refs_manifest(refs_log_path)
|
|
116
|
+
|
|
117
|
+
existing_keys: dict[tuple[str, int], int] = {}
|
|
118
|
+
for entry in existing:
|
|
119
|
+
key = (entry.get("contentId", ""), entry.get("page", 0))
|
|
120
|
+
existing_keys[key] = entry.get("sourceNumber", 0)
|
|
121
|
+
|
|
122
|
+
next_source_number = max(existing_keys.values()) + 1 if existing_keys else 1
|
|
123
|
+
|
|
124
|
+
output_lines: list[str] = []
|
|
125
|
+
for page in page_list:
|
|
126
|
+
key = (content_id, page)
|
|
127
|
+
if key in existing_keys:
|
|
128
|
+
sn = existing_keys[key]
|
|
129
|
+
output_lines.append(
|
|
130
|
+
f"[filesource{sn}] -> {filename} page {page} (already declared)"
|
|
131
|
+
)
|
|
132
|
+
continue
|
|
133
|
+
|
|
134
|
+
entry = {
|
|
135
|
+
"sourceNumber": next_source_number,
|
|
136
|
+
"contentId": content_id,
|
|
137
|
+
"filename": filename,
|
|
138
|
+
"page": page,
|
|
139
|
+
}
|
|
140
|
+
_append_turn_refs_manifest_entry(refs_log_path, entry)
|
|
141
|
+
output_lines.append(
|
|
142
|
+
f"[filesource{next_source_number}] -> {filename} page {page}"
|
|
143
|
+
)
|
|
144
|
+
existing_keys[key] = next_source_number
|
|
145
|
+
next_source_number += 1
|
|
146
|
+
|
|
147
|
+
except UnsafeRefsLogPathError as exc:
|
|
148
|
+
return f"{CITE_ERROR_PREFIX} {exc}"
|
|
149
|
+
|
|
150
|
+
return "\n".join(output_lines)
|
|
@@ -52,6 +52,7 @@ OVERVIEW_HELP = textwrap.dedent("""\
|
|
|
52
52
|
download <name|id> [dest] Download a file to local machine
|
|
53
53
|
rm <name|id> Delete a file
|
|
54
54
|
mv <old> <new> Rename a file
|
|
55
|
+
cite <name|id> [--pages] Declare page citations for a file
|
|
55
56
|
|
|
56
57
|
Search:
|
|
57
58
|
search <query> [options] Combined search (vector + full-text)
|
|
@@ -359,6 +360,40 @@ class UniqueShell(cmd.Cmd):
|
|
|
359
360
|
local_dest = parts[1] if len(parts) > 1 else None
|
|
360
361
|
self._print(cmd_download(self.state, name_or_id, local_dest))
|
|
361
362
|
|
|
363
|
+
def do_cite(self, arg: str) -> None:
|
|
364
|
+
"""Declare page citations for a file.
|
|
365
|
+
|
|
366
|
+
Usage: cite <name|content_id> [--pages RANGE]
|
|
367
|
+
|
|
368
|
+
Examples:
|
|
369
|
+
/Reports> cite report.pdf --pages 3,5,7
|
|
370
|
+
/Reports> cite cont_abc123 --pages 1-4
|
|
371
|
+
"""
|
|
372
|
+
from unique_sdk.cli.commands.cite_file import cmd_cite_file
|
|
373
|
+
|
|
374
|
+
parts = shlex.split(arg)
|
|
375
|
+
if not parts:
|
|
376
|
+
self._print("Usage: cite <name|content_id> [--pages RANGE]")
|
|
377
|
+
return
|
|
378
|
+
pages: str | None = None
|
|
379
|
+
positional: list[str] = []
|
|
380
|
+
index = 0
|
|
381
|
+
while index < len(parts):
|
|
382
|
+
token = parts[index]
|
|
383
|
+
if token in ("--pages", "-p"):
|
|
384
|
+
if index + 1 >= len(parts):
|
|
385
|
+
self._print("cite: --pages requires a value")
|
|
386
|
+
return
|
|
387
|
+
pages = parts[index + 1]
|
|
388
|
+
index += 2
|
|
389
|
+
else:
|
|
390
|
+
positional.append(token)
|
|
391
|
+
index += 1
|
|
392
|
+
if not positional:
|
|
393
|
+
self._print("Usage: cite <name|content_id> [--pages RANGE]")
|
|
394
|
+
return
|
|
395
|
+
self._print(cmd_cite_file(self.state, positional[0], pages))
|
|
396
|
+
|
|
362
397
|
def do_rm(self, arg: str) -> None:
|
|
363
398
|
"""Delete a file.
|
|
364
399
|
|
|
@@ -59,6 +59,10 @@ unique-cli upload ./data.csv scope_abc123
|
|
|
59
59
|
unique-cli download report.pdf ./local/
|
|
60
60
|
unique-cli download cont_abc123 ~/Desktop/
|
|
61
61
|
|
|
62
|
+
# Declare page citations after reading a file
|
|
63
|
+
unique-cli cite report.pdf --pages 3,5,7
|
|
64
|
+
unique-cli cite cont_abc123 --pages 1-4
|
|
65
|
+
|
|
62
66
|
# Delete a file
|
|
63
67
|
unique-cli rm report.pdf
|
|
64
68
|
unique-cli rm cont_abc123
|
|
@@ -119,6 +123,29 @@ unique-cli mkdir "2025/Q1/Financials"
|
|
|
119
123
|
unique-cli upload ./budget.xlsx /2025/Q1/Financials/
|
|
120
124
|
```
|
|
121
125
|
|
|
126
|
+
## Citing File Pages
|
|
127
|
+
|
|
128
|
+
After reading **any** file and using its content in your answer, declare citations:
|
|
129
|
+
|
|
130
|
+
```bash
|
|
131
|
+
unique-cli cite report.pdf --pages 3,5
|
|
132
|
+
unique-cli cite cont_abc123 --pages 1-4
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
This registers `[filesourceN]` markers. Use them inline in your answer.
|
|
136
|
+
The platform converts `[filesourceN]` into footnotes and clickable reference chips.
|
|
137
|
+
|
|
138
|
+
**MANDATORY 3-step verification before EVERY `unique-cli cite` call — NO EXCEPTIONS:**
|
|
139
|
+
|
|
140
|
+
1. `pdfinfo file.pdf | grep Pages` — get total physical page count.
|
|
141
|
+
2. For **each** page you intend to cite, run `pdftotext -f N -l N file.pdf -` and confirm the content you are referencing is actually on that physical page. Do NOT skip this. Do NOT assume page numbers.
|
|
142
|
+
3. Only after step 2 confirms a match, call `unique-cli cite` with the verified physical page numbers.
|
|
143
|
+
|
|
144
|
+
Page numbers are **physical PDF positions** (1-based). NEVER use printed page numbers from headers/footers — they often differ from physical positions.
|
|
145
|
+
|
|
146
|
+
- Numbers are **per-turn only**; do not reuse from prior turns.
|
|
147
|
+
- Do NOT use `cite` for content from `unique-cli search` or `unique-cli web-search`.
|
|
148
|
+
|
|
122
149
|
## Error Handling
|
|
123
150
|
|
|
124
151
|
- If env vars are missing, the CLI exits with a clear error listing the missing variables.
|
|
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.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_search_string.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/api_resources/_web_search.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/cli/commands/web_search.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/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
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.24.0.dev8 → unique_sdk-2026.24.0.dev9}/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
|