unique-sdk 2026.44.0.dev5__tar.gz → 2026.44.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.44.0.dev5 → unique_sdk-2026.44.0.dev6}/PKG-INFO +1 -1
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/pyproject.toml +1 -1
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/files.py +168 -38
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +4 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/README.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_context_memory.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/cli.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/agentic_table.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/agentic_table_write.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/browser.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/mcp.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/identity.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/metadata_filter.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/paths.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/shell.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/workspace.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.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.44.0.
|
|
3
|
+
Version: 2026.44.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>
|
|
@@ -38,6 +38,12 @@ _SUPPORTED_UPLOAD_MIME_TYPES = {
|
|
|
38
38
|
".md": "text/markdown",
|
|
39
39
|
}
|
|
40
40
|
|
|
41
|
+
# Bounds so one name resolve can never page through the whole knowledge base.
|
|
42
|
+
_MAX_RESOLVE_MATCH_CANDIDATES = 100
|
|
43
|
+
_MAX_RESOLVE_INFOS_PAGES = 10
|
|
44
|
+
_RESOLVE_INFOS_PAGE_SIZE = 100
|
|
45
|
+
_MAX_RESOLVE_INFOS_ENTRIES = _MAX_RESOLVE_INFOS_PAGES * _RESOLVE_INFOS_PAGE_SIZE
|
|
46
|
+
|
|
41
47
|
|
|
42
48
|
def _normalize_unique_file_path(cwd: str, path: str) -> str:
|
|
43
49
|
"""Normalize a Unique file path without allowing traversal above root."""
|
|
@@ -79,6 +85,7 @@ def _resolve_content_id(
|
|
|
79
85
|
return name_or_id, name_or_id
|
|
80
86
|
|
|
81
87
|
lookup_name = name_or_id
|
|
88
|
+
folder_path = state.cwd
|
|
82
89
|
scope_id = state.scope_id
|
|
83
90
|
if "/" in name_or_id:
|
|
84
91
|
unique_path = _normalize_unique_file_path(state.cwd, name_or_id)
|
|
@@ -124,16 +131,10 @@ def _resolve_content_id(
|
|
|
124
131
|
if not scope_id:
|
|
125
132
|
raise ValueError(f"folder not found: {folder_path}")
|
|
126
133
|
elif scope_id is None:
|
|
127
|
-
#
|
|
128
|
-
# Content.get_infos scan across the whole knowledge base.
|
|
134
|
+
# Resolving a bare name at the root would page the whole knowledge base.
|
|
129
135
|
if state.workspace_metadata_filter is not None:
|
|
130
|
-
# With a per-message filter active
|
|
131
|
-
#
|
|
132
|
-
# runs — and the deny-vs-not-found distinction is an existence/title
|
|
133
|
-
# oracle across the task boundary. That is broader than the
|
|
134
|
-
# ls/read-at-root gating intent, so require a bounded context
|
|
135
|
-
# instead. The cont_ fast-path, an explicit in-scope path, or a
|
|
136
|
-
# ``cd`` into an in-scope folder all still work. See UN-21780.
|
|
136
|
+
# With a per-message filter active that is also a cross-scope
|
|
137
|
+
# existence/title oracle. See UN-21780.
|
|
137
138
|
raise ValueError(
|
|
138
139
|
f"permission denied: {name_or_id} can't be resolved by name at "
|
|
139
140
|
f"the knowledge-base root while a task scope is active "
|
|
@@ -141,51 +142,180 @@ def _resolve_content_id(
|
|
|
141
142
|
"by content id, or 'cd' into an in-scope folder."
|
|
142
143
|
)
|
|
143
144
|
if not state.is_within_workspace():
|
|
144
|
-
# No per-message filter: defer to the static scopeIds boundary.
|
|
145
145
|
raise ValueError("permission denied (outside workspace scope)")
|
|
146
|
+
raise ValueError(
|
|
147
|
+
f"{name_or_id} can't be resolved by name at the knowledge-base "
|
|
148
|
+
"root. Use 'unique-cli search', pass a content id (cont_...), "
|
|
149
|
+
"or 'cd' into a folder first."
|
|
150
|
+
)
|
|
151
|
+
|
|
152
|
+
return _resolve_content_id_in_folder(
|
|
153
|
+
state=state,
|
|
154
|
+
name_or_id=name_or_id,
|
|
155
|
+
lookup_name=lookup_name,
|
|
156
|
+
folder_path=folder_path,
|
|
157
|
+
scope_id=scope_id,
|
|
158
|
+
allow_chat_files=allow_chat_files,
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def _resolve_content_id_in_folder(
|
|
163
|
+
*,
|
|
164
|
+
state: ShellState,
|
|
165
|
+
name_or_id: str,
|
|
166
|
+
lookup_name: str,
|
|
167
|
+
folder_path: str,
|
|
168
|
+
scope_id: str,
|
|
169
|
+
allow_chat_files: bool,
|
|
170
|
+
) -> tuple[str, str]:
|
|
171
|
+
"""Resolve ``lookup_name`` inside one folder without paging the whole KB."""
|
|
172
|
+
match = _pick_match(
|
|
173
|
+
hits=_hits_by_file_path(
|
|
174
|
+
state=state,
|
|
175
|
+
folder_path=folder_path,
|
|
176
|
+
lookup_name=lookup_name,
|
|
177
|
+
scope_id=scope_id,
|
|
178
|
+
),
|
|
179
|
+
lookup_name=lookup_name,
|
|
180
|
+
)
|
|
181
|
+
capped = False
|
|
182
|
+
if match is None:
|
|
183
|
+
hits, capped = _hits_by_search(
|
|
184
|
+
state=state, lookup_name=lookup_name, scope_id=scope_id
|
|
185
|
+
)
|
|
186
|
+
match = _pick_match(hits=hits, lookup_name=lookup_name)
|
|
187
|
+
if match is None:
|
|
188
|
+
if capped:
|
|
189
|
+
raise ValueError(
|
|
190
|
+
f"File not found in the first {_MAX_RESOLVE_INFOS_ENTRIES} "
|
|
191
|
+
f"entries of this folder: {name_or_id}. Use 'unique-cli "
|
|
192
|
+
"search' or pass a content id (cont_...)."
|
|
193
|
+
)
|
|
194
|
+
raise ValueError(f"File not found: {name_or_id}")
|
|
195
|
+
|
|
196
|
+
resolved_id, display_name = match
|
|
197
|
+
# Gate the *resolved* id too: resolving by file name or path must not
|
|
198
|
+
# bypass the per-message metadata-filter scope that the cont_ fast-path
|
|
199
|
+
# above enforces, and must honour the same read-only chat-file
|
|
200
|
+
# exemption (so rm/mv by name can't reach an out-of-scope attachment
|
|
201
|
+
# either). See UN-21780.
|
|
202
|
+
if not state.is_content_within_workspace(
|
|
203
|
+
resolved_id, allow_chat_files=allow_chat_files
|
|
204
|
+
):
|
|
205
|
+
raise ValueError(
|
|
206
|
+
f"permission denied: {name_or_id} is outside your "
|
|
207
|
+
f"task scope ({state.scope_denial_hint()}). Use "
|
|
208
|
+
"'unique-cli search' or 'ls' within that scope "
|
|
209
|
+
"instead."
|
|
210
|
+
)
|
|
211
|
+
return resolved_id, display_name
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _hits_by_file_path(
|
|
215
|
+
*, state: ShellState, folder_path: str, lookup_name: str, scope_id: str
|
|
216
|
+
) -> Sequence[Any]:
|
|
217
|
+
# One indexed lookup that returns no chunks and also finds files whose
|
|
218
|
+
# ingestion failed.
|
|
219
|
+
try:
|
|
220
|
+
result = unique_sdk.Content.get_info(
|
|
221
|
+
user_id=state.config.user_id,
|
|
222
|
+
company_id=state.config.company_id,
|
|
223
|
+
filePath=f"{folder_path.rstrip('/')}/{lookup_name}",
|
|
224
|
+
)
|
|
225
|
+
except unique_sdk.UniqueError:
|
|
226
|
+
return []
|
|
227
|
+
# A server that ignores filePath returns unrelated content.
|
|
228
|
+
return [
|
|
229
|
+
info
|
|
230
|
+
for info in result.get("contentInfo", [])
|
|
231
|
+
if info.get("ownerId") == scope_id
|
|
232
|
+
]
|
|
233
|
+
|
|
234
|
+
|
|
235
|
+
def _hits_by_search(
|
|
236
|
+
*, state: ShellState, lookup_name: str, scope_id: str
|
|
237
|
+
) -> tuple[Sequence[Any], bool]:
|
|
238
|
+
"""Return the hits, and whether the get_infos fallback hit its page cap."""
|
|
239
|
+
try:
|
|
240
|
+
hits = unique_sdk.Content.search(
|
|
241
|
+
user_id=state.config.user_id,
|
|
242
|
+
company_id=state.config.company_id,
|
|
243
|
+
where={
|
|
244
|
+
"AND": [
|
|
245
|
+
{"ownerId": {"equals": scope_id}},
|
|
246
|
+
{
|
|
247
|
+
"OR": [
|
|
248
|
+
{"title": {"equals": lookup_name}},
|
|
249
|
+
{"key": {"equals": lookup_name}},
|
|
250
|
+
]
|
|
251
|
+
},
|
|
252
|
+
]
|
|
253
|
+
},
|
|
254
|
+
includeFailedContent=True,
|
|
255
|
+
)
|
|
256
|
+
except unique_sdk.UniqueError:
|
|
257
|
+
return _resolve_content_id_via_infos_fallback(
|
|
258
|
+
state=state,
|
|
259
|
+
lookup_name=lookup_name,
|
|
260
|
+
scope_id=scope_id,
|
|
261
|
+
)
|
|
262
|
+
return hits, False
|
|
263
|
+
|
|
146
264
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
265
|
+
def _pick_match(*, hits: Sequence[Any], lookup_name: str) -> tuple[str, str] | None:
|
|
266
|
+
for content in hits[:_MAX_RESOLVE_MATCH_CANDIDATES]:
|
|
267
|
+
info = _as_content_fields(content)
|
|
268
|
+
resolved_id = info.get("id")
|
|
269
|
+
if not isinstance(resolved_id, str) or not resolved_id:
|
|
270
|
+
continue
|
|
271
|
+
title = info.get("title") or ""
|
|
272
|
+
key = info.get("key") or ""
|
|
273
|
+
if lookup_name in {title, key}:
|
|
274
|
+
return resolved_id, title or key
|
|
275
|
+
return None
|
|
150
276
|
|
|
151
|
-
|
|
277
|
+
|
|
278
|
+
def _as_content_fields(content: Any) -> Mapping[str, Any]:
|
|
279
|
+
if isinstance(content, Mapping):
|
|
280
|
+
return content
|
|
281
|
+
return {
|
|
282
|
+
"id": getattr(content, "id", None),
|
|
283
|
+
"title": getattr(content, "title", None),
|
|
284
|
+
"key": getattr(content, "key", None),
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
def _resolve_content_id_via_infos_fallback(
|
|
289
|
+
*,
|
|
290
|
+
state: ShellState,
|
|
291
|
+
lookup_name: str,
|
|
292
|
+
scope_id: str,
|
|
293
|
+
) -> tuple[list[Mapping[str, Any]], bool]:
|
|
294
|
+
"""Folder-scoped get_infos fallback with a hard page cap.
|
|
295
|
+
|
|
296
|
+
Returns the match (if any), and whether the cap stopped the scan early.
|
|
297
|
+
"""
|
|
152
298
|
skip = 0
|
|
153
|
-
|
|
299
|
+
for _ in range(_MAX_RESOLVE_INFOS_PAGES):
|
|
154
300
|
result = unique_sdk.Content.get_infos(
|
|
155
301
|
user_id=state.config.user_id,
|
|
156
302
|
company_id=state.config.company_id,
|
|
303
|
+
parentId=scope_id,
|
|
157
304
|
skip=skip,
|
|
158
|
-
take=
|
|
159
|
-
**params,
|
|
305
|
+
take=_RESOLVE_INFOS_PAGE_SIZE,
|
|
160
306
|
)
|
|
161
307
|
content_infos = result.get("contentInfos", [])
|
|
162
308
|
if not content_infos:
|
|
163
|
-
|
|
164
|
-
|
|
309
|
+
return [], False
|
|
165
310
|
for info in content_infos:
|
|
166
311
|
title = info.get("title") or ""
|
|
167
312
|
key = info.get("key") or ""
|
|
168
313
|
if lookup_name in {title, key}:
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
# the cont_ fast-path above enforces, and must honour the same
|
|
173
|
-
# read-only chat-file exemption (so rm/mv by name can't reach
|
|
174
|
-
# an out-of-scope attachment either). See UN-21780.
|
|
175
|
-
if not state.is_content_within_workspace(
|
|
176
|
-
resolved_id, allow_chat_files=allow_chat_files
|
|
177
|
-
):
|
|
178
|
-
raise ValueError(
|
|
179
|
-
f"permission denied: {name_or_id} is outside your "
|
|
180
|
-
f"task scope ({state.scope_denial_hint()}). Use "
|
|
181
|
-
"'unique-cli search' or 'ls' within that scope "
|
|
182
|
-
"instead."
|
|
183
|
-
)
|
|
184
|
-
return resolved_id, title or key
|
|
185
|
-
|
|
314
|
+
return [info], False
|
|
315
|
+
if len(content_infos) < _RESOLVE_INFOS_PAGE_SIZE:
|
|
316
|
+
return [], False
|
|
186
317
|
skip += len(content_infos)
|
|
187
|
-
|
|
188
|
-
raise ValueError(f"File not found: {name_or_id}")
|
|
318
|
+
return [], True
|
|
189
319
|
|
|
190
320
|
|
|
191
321
|
def _detect_upload_mime_type(path: Path) -> str:
|
|
@@ -99,6 +99,10 @@ unique-cli mv report.pdf "Annual Report 2025.pdf"
|
|
|
99
99
|
| Content ID | `cont_abc123` | File directly by ID |
|
|
100
100
|
| File path | `/Reports/Q1/report.pdf` | File in a folder |
|
|
101
101
|
|
|
102
|
+
A bare file name such as `report.pdf` resolves in the current folder. At the
|
|
103
|
+
root (`/`) a bare file name is an error: pass a full path, a content ID, or `cd`
|
|
104
|
+
into the folder first.
|
|
105
|
+
|
|
102
106
|
## Upload Destination Resolution
|
|
103
107
|
|
|
104
108
|
The `upload` command always enables immutable content versioning. It does not expose an unversioned upload mode. Its destination works like Linux `cp`:
|
|
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.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_context_memory.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.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.44.0.dev5 → unique_sdk-2026.44.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
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/agentic_table.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/cite_file.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/cli/commands/web_search.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.0.dev6}/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.44.0.dev5 → unique_sdk-2026.44.0.dev6}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.44.0.dev5 → unique_sdk-2026.44.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
|