unique-sdk 2026.44.0.dev12__tar.gz → 2026.44.0.dev13__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.
Files changed (92) hide show
  1. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/PKG-INFO +1 -1
  2. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/pyproject.toml +1 -1
  3. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/files.py +19 -42
  4. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/navigation.py +16 -12
  5. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/metadata_filter.py +14 -0
  6. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/README.md +0 -0
  7. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/__init__.py +0 -0
  8. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_api_requestor.py +0 -0
  9. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_api_resource.py +0 -0
  10. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_api_version.py +0 -0
  11. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_error.py +0 -0
  12. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_http_client.py +0 -0
  13. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_list_object.py +0 -0
  14. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_object_classes.py +0 -0
  15. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_request_options.py +0 -0
  16. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_unique_object.py +0 -0
  17. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_unique_ql.py +0 -0
  18. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_unique_response.py +0 -0
  19. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_util.py +0 -0
  20. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_version.py +0 -0
  21. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/_webhook.py +0 -0
  22. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/__init__.py +0 -0
  23. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_acronyms.py +0 -0
  24. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_agentic_table.py +0 -0
  25. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_analytics_order.py +0 -0
  26. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_benchmarking.py +0 -0
  27. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_briefing.py +0 -0
  28. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_chat_completion.py +0 -0
  29. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_content.py +0 -0
  30. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_context_memory.py +0 -0
  31. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_elicitation.py +0 -0
  32. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_embedding.py +0 -0
  33. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_event.py +0 -0
  34. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_folder.py +0 -0
  35. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_group.py +0 -0
  36. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_integrated.py +0 -0
  37. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_llm_models.py +0 -0
  38. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_mcp.py +0 -0
  39. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_message.py +0 -0
  40. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_message_assessment.py +0 -0
  41. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_message_execution.py +0 -0
  42. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_message_log.py +0 -0
  43. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_message_tool.py +0 -0
  44. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_module.py +0 -0
  45. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_scheduled_task.py +0 -0
  46. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_search.py +0 -0
  47. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_search_string.py +0 -0
  48. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  49. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_space.py +0 -0
  50. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_user.py +0 -0
  51. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/api_resources/_web_search.py +0 -0
  52. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/__init__.py +0 -0
  53. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/__main__.py +0 -0
  54. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/cli.py +0 -0
  55. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/__init__.py +0 -0
  56. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
  57. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/agentic_table.py +0 -0
  58. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/agentic_table_write.py +0 -0
  59. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/browser.py +0 -0
  60. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/cite_file.py +0 -0
  61. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/elicitation.py +0 -0
  62. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/folders.py +0 -0
  63. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/mcp.py +0 -0
  64. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/read.py +0 -0
  65. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
  66. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/search.py +0 -0
  67. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/subagent.py +0 -0
  68. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/web_search.py +0 -0
  69. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/commands/web_search_config.py +0 -0
  70. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/config.py +0 -0
  71. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/formatting.py +0 -0
  72. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/identity.py +0 -0
  73. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/paths.py +0 -0
  74. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/shell.py +0 -0
  75. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
  76. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
  77. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
  78. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
  79. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
  80. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
  81. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
  82. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
  83. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
  84. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/state.py +0 -0
  85. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/cli/workspace.py +0 -0
  86. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/analytics_order_run.py +0 -0
  87. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/benchmarking_run.py +0 -0
  88. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/chat_history.py +0 -0
  89. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/chat_in_space.py +0 -0
  90. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/file_io.py +0 -0
  91. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/unique_sdk/utils/sources.py +0 -0
  92. {unique_sdk-2026.44.0.dev12 → unique_sdk-2026.44.0.dev13}/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.dev12
3
+ Version: 2026.44.0.dev13
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.44.0.dev12"
3
+ version = "2026.44.0.dev13"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -11,6 +11,7 @@ from typing import Any
11
11
 
12
12
  import unique_sdk
13
13
  from unique_sdk.cli.formatting import format_content_info
14
+ from unique_sdk.cli.metadata_filter import direct_children_filter
14
15
  from unique_sdk.cli.paths import canonical_folder_path, same_folder_path
15
16
  from unique_sdk.cli.state import ShellState
16
17
  from unique_sdk.utils.file_io import download_content, upload_file
@@ -40,9 +41,6 @@ _SUPPORTED_UPLOAD_MIME_TYPES = {
40
41
 
41
42
  # Bounds so one name resolve can never page through the whole knowledge base.
42
43
  _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
44
 
47
45
 
48
46
  def _normalize_unique_file_path(cwd: str, path: str) -> str:
@@ -178,19 +176,10 @@ def _resolve_content_id_in_folder(
178
176
  ),
179
177
  lookup_name=lookup_name,
180
178
  )
181
- capped = False
182
179
  if match is None:
183
- hits, capped = _hits_by_search(
184
- state=state, lookup_name=lookup_name, scope_id=scope_id
185
- )
180
+ hits = _hits_by_search(state=state, lookup_name=lookup_name, scope_id=scope_id)
186
181
  match = _pick_match(hits=hits, lookup_name=lookup_name)
187
182
  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
183
  raise ValueError(f"File not found: {name_or_id}")
195
184
 
196
185
  resolved_id, display_name = match
@@ -234,8 +223,7 @@ def _hits_by_file_path(
234
223
 
235
224
  def _hits_by_search(
236
225
  *, 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."""
226
+ ) -> Sequence[Any]:
239
227
  try:
240
228
  hits = unique_sdk.Content.search(
241
229
  user_id=state.config.user_id,
@@ -259,7 +247,7 @@ def _hits_by_search(
259
247
  lookup_name=lookup_name,
260
248
  scope_id=scope_id,
261
249
  )
262
- return hits, False
250
+ return hits
263
251
 
264
252
 
265
253
  def _pick_match(*, hits: Sequence[Any], lookup_name: str) -> tuple[str, str] | None:
@@ -290,32 +278,21 @@ def _resolve_content_id_via_infos_fallback(
290
278
  state: ShellState,
291
279
  lookup_name: str,
292
280
  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
- """
298
- skip = 0
299
- for _ in range(_MAX_RESOLVE_INFOS_PAGES):
300
- result = unique_sdk.Content.get_infos(
301
- user_id=state.config.user_id,
302
- company_id=state.config.company_id,
303
- parentId=scope_id,
304
- skip=skip,
305
- take=_RESOLVE_INFOS_PAGE_SIZE,
306
- )
307
- content_infos = result.get("contentInfos", [])
308
- if not content_infos:
309
- return [], False
310
- for info in content_infos:
311
- title = info.get("title") or ""
312
- key = info.get("key") or ""
313
- if lookup_name in {title, key}:
314
- return [info], False
315
- if len(content_infos) < _RESOLVE_INFOS_PAGE_SIZE:
316
- return [], False
317
- skip += len(content_infos)
318
- return [], True
281
+ ) -> list[Mapping[str, Any]]:
282
+ """Folder-scoped get_infos fallback, filtered by name so one page suffices."""
283
+ name_filter = {
284
+ "or": [
285
+ {"path": ["title"], "operator": "equals", "value": lookup_name},
286
+ {"path": ["key"], "operator": "equals", "value": lookup_name},
287
+ ]
288
+ }
289
+ result = unique_sdk.Content.get_infos(
290
+ user_id=state.config.user_id,
291
+ company_id=state.config.company_id,
292
+ metadataFilter={"and": [direct_children_filter(scope_id), name_filter]},
293
+ take=_MAX_RESOLVE_MATCH_CANDIDATES,
294
+ )
295
+ return list(result.get("contentInfos", []))
319
296
 
320
297
 
321
298
  def _detect_upload_mime_type(path: Path) -> str:
@@ -6,7 +6,10 @@ from typing import Any
6
6
 
7
7
  import unique_sdk
8
8
  from unique_sdk.cli.formatting import format_ls
9
- from unique_sdk.cli.metadata_filter import _collect_filter_targets
9
+ from unique_sdk.cli.metadata_filter import (
10
+ _collect_filter_targets,
11
+ direct_children_filter,
12
+ )
10
13
  from unique_sdk.cli.paths import canonical_folder_path, same_folder_path
11
14
  from unique_sdk.cli.state import ShellState
12
15
 
@@ -188,10 +191,8 @@ def cmd_ls(state: ShellState, target: str | None = None) -> str:
188
191
  return path_error
189
192
 
190
193
  folder_params: dict[str, Any] = {}
191
- content_params: dict[str, Any] = {}
192
194
  if scope_id:
193
195
  folder_params["parentId"] = scope_id
194
- content_params["parentId"] = scope_id
195
196
 
196
197
  folder_result = unique_sdk.Folder.get_infos(
197
198
  user_id=state.config.user_id,
@@ -199,16 +200,19 @@ def cmd_ls(state: ShellState, target: str | None = None) -> str:
199
200
  **folder_params,
200
201
  )
201
202
  folders = folder_result.get("folderInfos", [])
202
-
203
- content_result = unique_sdk.Content.get_infos(
204
- user_id=state.config.user_id,
205
- company_id=state.config.company_id,
206
- **content_params,
207
- )
208
- files = content_result.get("contentInfos", [])
209
-
210
203
  total_folders = folder_result.get("totalCount", len(folders))
211
- total_files = content_result.get("totalCount", len(files))
204
+
205
+ # Every file lives in a folder, so the root has no files of its own.
206
+ files: list[Any] = []
207
+ total_files = 0
208
+ if scope_id:
209
+ content_result = unique_sdk.Content.get_infos(
210
+ user_id=state.config.user_id,
211
+ company_id=state.config.company_id,
212
+ metadataFilter=direct_children_filter(scope_id),
213
+ )
214
+ files = content_result.get("contentInfos", [])
215
+ total_files = content_result.get("totalCount", len(files))
212
216
 
213
217
  if scope_id and not folders and not files:
214
218
  label = target if target is not None else resolved_path
@@ -38,6 +38,20 @@ ScopePathResolver = Callable[[str], "str | None"]
38
38
  ContentOwnerPathResolver = Callable[[str], "str | None"]
39
39
 
40
40
 
41
+ def direct_children_filter(scope_id: str) -> dict[str, Any]:
42
+ """UniqueQL for files directly in ``scope_id``, not in its subfolders."""
43
+ return {
44
+ "and": [
45
+ {"path": ["folderIdPath"], "operator": "contains", "value": scope_id},
46
+ {
47
+ "path": ["folderIdPath"],
48
+ "operator": "notContains",
49
+ "value": f"{scope_id}/",
50
+ },
51
+ ]
52
+ }
53
+
54
+
41
55
  def _extract_target_scope_id(value: Any) -> str | None:
42
56
  """Deepest folder scope id referenced by a ``folderIdPath`` filter value.
43
57