unique-sdk 2026.26.0.dev7__tar.gz → 2026.26.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.26.0.dev7 → unique_sdk-2026.26.0.dev9}/PKG-INFO +1 -1
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/pyproject.toml +1 -1
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/__init__.py +3 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_content.py +158 -0
- unique_sdk-2026.26.0.dev9/unique_sdk/api_resources/_dynamic_frontend.py +81 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/cli.py +149 -12
- unique_sdk-2026.26.0.dev9/unique_sdk/cli/commands/dynamic_frontend.py +116 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/files.py +136 -10
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/shell.py +110 -26
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +21 -3
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/file_io.py +7 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/README.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/mcp.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.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.26.0.
|
|
3
|
+
Version: 2026.26.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>
|
|
@@ -77,6 +77,9 @@ from unique_sdk.api_resources._message import Message as Message
|
|
|
77
77
|
from unique_sdk.api_resources._integrated import Integrated as Integrated
|
|
78
78
|
from unique_sdk.api_resources._search import Search as Search
|
|
79
79
|
from unique_sdk.api_resources._content import Content as Content
|
|
80
|
+
from unique_sdk.api_resources._dynamic_frontend import (
|
|
81
|
+
DynamicFrontend as DynamicFrontend,
|
|
82
|
+
)
|
|
80
83
|
from unique_sdk.api_resources._search_string import SearchString as SearchString
|
|
81
84
|
from unique_sdk.api_resources._short_term_memory import (
|
|
82
85
|
ShortTermMemory as ShortTermMemory,
|
{unique_sdk-2026.26.0.dev7 → unique_sdk-2026.26.0.dev9}/unique_sdk/api_resources/_content.py
RENAMED
|
@@ -170,6 +170,50 @@ class Content(APIResource["Content"]):
|
|
|
170
170
|
# a SAS URL the caller PUTs the PDF bytes to. ``file_io.upload_file``
|
|
171
171
|
# exposes this as ``preview_pdf_path`` for a one-call flow.
|
|
172
172
|
previewPdfFileName: NotRequired[str | None]
|
|
173
|
+
# When true, the platform archives previous blobs for this
|
|
174
|
+
# content and makes them restorable through the version APIs.
|
|
175
|
+
versioningEnabled: NotRequired[bool | None]
|
|
176
|
+
|
|
177
|
+
class VersionsParams(RequestOptions):
|
|
178
|
+
contentId: str
|
|
179
|
+
skip: NotRequired[int | None]
|
|
180
|
+
take: NotRequired[int | None]
|
|
181
|
+
|
|
182
|
+
class ContentVersion(TypedDict):
|
|
183
|
+
id: str
|
|
184
|
+
contentId: str
|
|
185
|
+
versionNumber: int
|
|
186
|
+
reason: str
|
|
187
|
+
blobObjectKey: str
|
|
188
|
+
key: str
|
|
189
|
+
title: str | None
|
|
190
|
+
description: str | None
|
|
191
|
+
url: str | None
|
|
192
|
+
byteSize: int
|
|
193
|
+
mimeType: str
|
|
194
|
+
ownerType: str
|
|
195
|
+
ownerId: str
|
|
196
|
+
contentHash: str | None
|
|
197
|
+
archivedAt: str
|
|
198
|
+
archivedBy: str | None
|
|
199
|
+
originalCreatedAt: str
|
|
200
|
+
originalCreatedBy: str | None
|
|
201
|
+
createdBy: str | None
|
|
202
|
+
|
|
203
|
+
class PaginatedContentVersions(TypedDict):
|
|
204
|
+
data: list["Content.ContentVersion"]
|
|
205
|
+
object: str
|
|
206
|
+
|
|
207
|
+
class VersionDownloadUrlParams(RequestOptions):
|
|
208
|
+
contentVersionId: str
|
|
209
|
+
|
|
210
|
+
class ContentVersionDownloadUrl(TypedDict):
|
|
211
|
+
id: str
|
|
212
|
+
object: str
|
|
213
|
+
url: str
|
|
214
|
+
|
|
215
|
+
class RestoreVersionParams(RequestOptions):
|
|
216
|
+
contentVersionId: str
|
|
173
217
|
|
|
174
218
|
class UpdateParams(RequestOptions):
|
|
175
219
|
contentId: NotRequired[str]
|
|
@@ -467,6 +511,120 @@ class Content(APIResource["Content"]):
|
|
|
467
511
|
),
|
|
468
512
|
)
|
|
469
513
|
|
|
514
|
+
@classmethod
|
|
515
|
+
def versions(
|
|
516
|
+
cls,
|
|
517
|
+
user_id: str,
|
|
518
|
+
company_id: str,
|
|
519
|
+
**params: Unpack["Content.VersionsParams"],
|
|
520
|
+
) -> "Content.PaginatedContentVersions":
|
|
521
|
+
content_id = params.pop("contentId")
|
|
522
|
+
return cast(
|
|
523
|
+
Content.PaginatedContentVersions,
|
|
524
|
+
cls._static_request(
|
|
525
|
+
"get",
|
|
526
|
+
f"/content/{content_id}/versions",
|
|
527
|
+
user_id,
|
|
528
|
+
company_id,
|
|
529
|
+
params=params,
|
|
530
|
+
),
|
|
531
|
+
)
|
|
532
|
+
|
|
533
|
+
@classmethod
|
|
534
|
+
async def versions_async(
|
|
535
|
+
cls,
|
|
536
|
+
user_id: str,
|
|
537
|
+
company_id: str,
|
|
538
|
+
**params: Unpack["Content.VersionsParams"],
|
|
539
|
+
) -> "Content.PaginatedContentVersions":
|
|
540
|
+
content_id = params.pop("contentId")
|
|
541
|
+
return cast(
|
|
542
|
+
Content.PaginatedContentVersions,
|
|
543
|
+
await cls._static_request_async(
|
|
544
|
+
"get",
|
|
545
|
+
f"/content/{content_id}/versions",
|
|
546
|
+
user_id,
|
|
547
|
+
company_id,
|
|
548
|
+
params=params,
|
|
549
|
+
),
|
|
550
|
+
)
|
|
551
|
+
|
|
552
|
+
@classmethod
|
|
553
|
+
def version_download_url(
|
|
554
|
+
cls,
|
|
555
|
+
user_id: str,
|
|
556
|
+
company_id: str,
|
|
557
|
+
**params: Unpack["Content.VersionDownloadUrlParams"],
|
|
558
|
+
) -> "Content.ContentVersionDownloadUrl":
|
|
559
|
+
content_version_id = params.pop("contentVersionId")
|
|
560
|
+
return cast(
|
|
561
|
+
Content.ContentVersionDownloadUrl,
|
|
562
|
+
cls._static_request(
|
|
563
|
+
"get",
|
|
564
|
+
f"/content/versions/{content_version_id}/download-url",
|
|
565
|
+
user_id,
|
|
566
|
+
company_id,
|
|
567
|
+
params=params,
|
|
568
|
+
),
|
|
569
|
+
)
|
|
570
|
+
|
|
571
|
+
@classmethod
|
|
572
|
+
async def version_download_url_async(
|
|
573
|
+
cls,
|
|
574
|
+
user_id: str,
|
|
575
|
+
company_id: str,
|
|
576
|
+
**params: Unpack["Content.VersionDownloadUrlParams"],
|
|
577
|
+
) -> "Content.ContentVersionDownloadUrl":
|
|
578
|
+
content_version_id = params.pop("contentVersionId")
|
|
579
|
+
return cast(
|
|
580
|
+
Content.ContentVersionDownloadUrl,
|
|
581
|
+
await cls._static_request_async(
|
|
582
|
+
"get",
|
|
583
|
+
f"/content/versions/{content_version_id}/download-url",
|
|
584
|
+
user_id,
|
|
585
|
+
company_id,
|
|
586
|
+
params=params,
|
|
587
|
+
),
|
|
588
|
+
)
|
|
589
|
+
|
|
590
|
+
@classmethod
|
|
591
|
+
def restore_version(
|
|
592
|
+
cls,
|
|
593
|
+
user_id: str,
|
|
594
|
+
company_id: str,
|
|
595
|
+
**params: Unpack["Content.RestoreVersionParams"],
|
|
596
|
+
) -> "Content.ContentInfo":
|
|
597
|
+
content_version_id = params.pop("contentVersionId")
|
|
598
|
+
return cast(
|
|
599
|
+
Content.ContentInfo,
|
|
600
|
+
cls._static_request(
|
|
601
|
+
"post",
|
|
602
|
+
f"/content/versions/{content_version_id}/restore",
|
|
603
|
+
user_id,
|
|
604
|
+
company_id,
|
|
605
|
+
params=params,
|
|
606
|
+
),
|
|
607
|
+
)
|
|
608
|
+
|
|
609
|
+
@classmethod
|
|
610
|
+
async def restore_version_async(
|
|
611
|
+
cls,
|
|
612
|
+
user_id: str,
|
|
613
|
+
company_id: str,
|
|
614
|
+
**params: Unpack["Content.RestoreVersionParams"],
|
|
615
|
+
) -> "Content.ContentInfo":
|
|
616
|
+
content_version_id = params.pop("contentVersionId")
|
|
617
|
+
return cast(
|
|
618
|
+
Content.ContentInfo,
|
|
619
|
+
await cls._static_request_async(
|
|
620
|
+
"post",
|
|
621
|
+
f"/content/versions/{content_version_id}/restore",
|
|
622
|
+
user_id,
|
|
623
|
+
company_id,
|
|
624
|
+
params=params,
|
|
625
|
+
),
|
|
626
|
+
)
|
|
627
|
+
|
|
470
628
|
@classmethod
|
|
471
629
|
def ingest_magic_table_sheets(
|
|
472
630
|
cls,
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
from typing import Literal, cast
|
|
2
|
+
|
|
3
|
+
from typing_extensions import NotRequired, Unpack
|
|
4
|
+
|
|
5
|
+
from unique_sdk._api_resource import APIResource
|
|
6
|
+
from unique_sdk._request_options import RequestOptions
|
|
7
|
+
from unique_sdk._util import classproperty
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
class DynamicFrontend(APIResource["DynamicFrontend"]):
|
|
11
|
+
@classproperty
|
|
12
|
+
def OBJECT_NAME(cls) -> Literal["dynamic-frontend"]:
|
|
13
|
+
return "dynamic-frontend"
|
|
14
|
+
|
|
15
|
+
id: str
|
|
16
|
+
spaceId: str
|
|
17
|
+
name: str
|
|
18
|
+
contentId: str
|
|
19
|
+
status: dict[str, object] | None
|
|
20
|
+
|
|
21
|
+
class CreateParams(RequestOptions):
|
|
22
|
+
name: str
|
|
23
|
+
contentId: str
|
|
24
|
+
|
|
25
|
+
class UpdateParams(RequestOptions):
|
|
26
|
+
contentId: str
|
|
27
|
+
name: NotRequired[str | None]
|
|
28
|
+
|
|
29
|
+
@classmethod
|
|
30
|
+
def create(
|
|
31
|
+
cls,
|
|
32
|
+
user_id: str,
|
|
33
|
+
company_id: str,
|
|
34
|
+
**params: Unpack["DynamicFrontend.CreateParams"],
|
|
35
|
+
) -> "DynamicFrontend":
|
|
36
|
+
return cast(
|
|
37
|
+
DynamicFrontend,
|
|
38
|
+
cls._static_request(
|
|
39
|
+
"post",
|
|
40
|
+
"/dynamic-frontend",
|
|
41
|
+
user_id,
|
|
42
|
+
company_id,
|
|
43
|
+
params=params,
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
@classmethod
|
|
48
|
+
def modify(
|
|
49
|
+
cls,
|
|
50
|
+
space_id: str,
|
|
51
|
+
user_id: str,
|
|
52
|
+
company_id: str,
|
|
53
|
+
**params: Unpack["DynamicFrontend.UpdateParams"],
|
|
54
|
+
) -> "DynamicFrontend":
|
|
55
|
+
return cast(
|
|
56
|
+
DynamicFrontend,
|
|
57
|
+
cls._static_request(
|
|
58
|
+
"patch",
|
|
59
|
+
f"/dynamic-frontend/{space_id}",
|
|
60
|
+
user_id,
|
|
61
|
+
company_id,
|
|
62
|
+
params=params,
|
|
63
|
+
),
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
@classmethod
|
|
67
|
+
def list(
|
|
68
|
+
cls,
|
|
69
|
+
user_id: str,
|
|
70
|
+
company_id: str,
|
|
71
|
+
) -> list["DynamicFrontend"]:
|
|
72
|
+
response = cls._static_request(
|
|
73
|
+
"get",
|
|
74
|
+
"/dynamic-frontend",
|
|
75
|
+
user_id,
|
|
76
|
+
company_id,
|
|
77
|
+
)
|
|
78
|
+
if isinstance(response, list):
|
|
79
|
+
return cast(list[DynamicFrontend], response)
|
|
80
|
+
data = response.get("data", []) if isinstance(response, dict) else []
|
|
81
|
+
return cast(list[DynamicFrontend], data)
|
|
@@ -8,6 +8,10 @@ import click
|
|
|
8
8
|
|
|
9
9
|
from unique_sdk.cli import __version__
|
|
10
10
|
from unique_sdk.cli.commands.cite_file import cmd_cite_file
|
|
11
|
+
from unique_sdk.cli.commands.dynamic_frontend import (
|
|
12
|
+
cmd_dynamic_frontend_deploy,
|
|
13
|
+
cmd_dynamic_frontend_list,
|
|
14
|
+
)
|
|
11
15
|
from unique_sdk.cli.commands.elicitation import (
|
|
12
16
|
cmd_elicit_ask,
|
|
13
17
|
cmd_elicit_create,
|
|
@@ -16,7 +20,14 @@ from unique_sdk.cli.commands.elicitation import (
|
|
|
16
20
|
cmd_elicit_respond,
|
|
17
21
|
cmd_elicit_wait,
|
|
18
22
|
)
|
|
19
|
-
from unique_sdk.cli.commands.files import
|
|
23
|
+
from unique_sdk.cli.commands.files import (
|
|
24
|
+
cmd_download,
|
|
25
|
+
cmd_mv_file,
|
|
26
|
+
cmd_restore_version,
|
|
27
|
+
cmd_rm,
|
|
28
|
+
cmd_upload,
|
|
29
|
+
cmd_versions,
|
|
30
|
+
)
|
|
20
31
|
from unique_sdk.cli.commands.folders import cmd_mkdir, cmd_mvdir, cmd_rmdir
|
|
21
32
|
from unique_sdk.cli.commands.mcp import cmd_mcp
|
|
22
33
|
from unique_sdk.cli.commands.navigation import cmd_cd, cmd_ls, cmd_pwd
|
|
@@ -53,6 +64,8 @@ from unique_sdk.cli.config import load_config
|
|
|
53
64
|
from unique_sdk.cli.shell import UniqueShell
|
|
54
65
|
from unique_sdk.cli.state import ShellState
|
|
55
66
|
|
|
67
|
+
_DYNAMIC_FRONTEND_ERROR_PREFIX = "dynamic-frontend "
|
|
68
|
+
|
|
56
69
|
MAIN_HELP = """\
|
|
57
70
|
Unique CLI -- Linux-like file explorer for the Unique AI Platform.
|
|
58
71
|
|
|
@@ -85,6 +98,7 @@ Path formats accepted by all commands:
|
|
|
85
98
|
\b
|
|
86
99
|
File identifiers:
|
|
87
100
|
report.pdf File name (matched in current directory)
|
|
101
|
+
/Reports/report.pdf File path (absolute or relative)
|
|
88
102
|
cont_abc123 Content ID (used directly)
|
|
89
103
|
|
|
90
104
|
\b
|
|
@@ -93,12 +107,15 @@ Examples:
|
|
|
93
107
|
unique-cli ls List root folders
|
|
94
108
|
unique-cli ls /Reports List a specific folder
|
|
95
109
|
unique-cli search "revenue" -l 50 Search with custom limit
|
|
96
|
-
unique-cli upload ./file.pdf Upload to current folder
|
|
110
|
+
unique-cli upload ./file.pdf Upload versioned to current folder
|
|
97
111
|
unique-cli download cont_abc123 Download by content ID
|
|
112
|
+
unique-cli versions cont_abc123 List archived file versions
|
|
113
|
+
unique-cli restore-version cver_1 Restore a file from a version
|
|
98
114
|
unique-cli elicit ask "Which?" Ask the user a question synchronously
|
|
99
115
|
unique-cli subagent Legal "Review" Invoke a connected space/subagent
|
|
100
116
|
unique-cli web-search search "x" Search the web via the public API
|
|
101
117
|
unique-cli web-search crawl URL Crawl a URL via the public API
|
|
118
|
+
unique-cli dynamic-frontend list List manageable Dynamic Frontend spaces
|
|
102
119
|
"""
|
|
103
120
|
|
|
104
121
|
|
|
@@ -254,12 +271,13 @@ def mvdir(ctx: click.Context, old_name: str, new_name: str) -> None:
|
|
|
254
271
|
@click.argument("destination", required=False, default=None)
|
|
255
272
|
@click.pass_context
|
|
256
273
|
def upload(ctx: click.Context, local_path: str, destination: str | None) -> None:
|
|
257
|
-
"""Upload a local file (works like Linux cp).
|
|
274
|
+
"""Upload a local file with versioning enabled (works like Linux cp).
|
|
258
275
|
|
|
259
276
|
\b
|
|
260
|
-
Uploads LOCAL_PATH to the Unique platform
|
|
261
|
-
the target in cp -- it can be a
|
|
262
|
-
a combination of both. MIME type is
|
|
277
|
+
Uploads LOCAL_PATH to the Unique platform with immutable versioning
|
|
278
|
+
enabled. DESTINATION works like the target in cp -- it can be a
|
|
279
|
+
folder path, a new filename, or a combination of both. MIME type is
|
|
280
|
+
auto-detected.
|
|
263
281
|
|
|
264
282
|
\b
|
|
265
283
|
Destination formats:
|
|
@@ -281,6 +299,48 @@ def upload(ctx: click.Context, local_path: str, destination: str | None) -> None
|
|
|
281
299
|
click.echo(cmd_upload(LazyState.get(ctx), local_path, destination))
|
|
282
300
|
|
|
283
301
|
|
|
302
|
+
@main.command()
|
|
303
|
+
@click.argument("name_or_id")
|
|
304
|
+
@click.option("--skip", type=int, default=None, help="Number of versions to skip.")
|
|
305
|
+
@click.option("--take", type=int, default=None, help="Number of versions to return.")
|
|
306
|
+
@click.pass_context
|
|
307
|
+
def versions(
|
|
308
|
+
ctx: click.Context,
|
|
309
|
+
name_or_id: str,
|
|
310
|
+
skip: int | None,
|
|
311
|
+
take: int | None,
|
|
312
|
+
) -> None:
|
|
313
|
+
"""List archived versions for a file.
|
|
314
|
+
|
|
315
|
+
\b
|
|
316
|
+
NAME_OR_ID is a file path, a file name matched in the current
|
|
317
|
+
directory, or a content ID (cont_...) which is resolved directly.
|
|
318
|
+
|
|
319
|
+
\b
|
|
320
|
+
Examples:
|
|
321
|
+
unique-cli versions report.pdf
|
|
322
|
+
unique-cli versions /Reports/Q1/report.pdf
|
|
323
|
+
unique-cli versions cont_abc123 --take 10
|
|
324
|
+
"""
|
|
325
|
+
click.echo(cmd_versions(LazyState.get(ctx), name_or_id, skip=skip, take=take))
|
|
326
|
+
|
|
327
|
+
|
|
328
|
+
@main.command(name="restore-version")
|
|
329
|
+
@click.argument("content_version_id")
|
|
330
|
+
@click.pass_context
|
|
331
|
+
def restore_version(ctx: click.Context, content_version_id: str) -> None:
|
|
332
|
+
"""Restore a file from a content version ID.
|
|
333
|
+
|
|
334
|
+
\b
|
|
335
|
+
CONTENT_VERSION_ID is returned by `unique-cli versions`.
|
|
336
|
+
|
|
337
|
+
\b
|
|
338
|
+
Examples:
|
|
339
|
+
unique-cli restore-version cver_abc123
|
|
340
|
+
"""
|
|
341
|
+
click.echo(cmd_restore_version(LazyState.get(ctx), content_version_id))
|
|
342
|
+
|
|
343
|
+
|
|
284
344
|
@main.command()
|
|
285
345
|
@click.argument("name_or_id")
|
|
286
346
|
@click.argument("local_dest", required=False, default=None)
|
|
@@ -289,8 +349,8 @@ def download(ctx: click.Context, name_or_id: str, local_dest: str | None) -> Non
|
|
|
289
349
|
"""Download a file to your local machine.
|
|
290
350
|
|
|
291
351
|
\b
|
|
292
|
-
NAME_OR_ID is a file name
|
|
293
|
-
a content ID (cont_...) which is resolved directly.
|
|
352
|
+
NAME_OR_ID is a file path, a file name matched in the current
|
|
353
|
+
directory, or a content ID (cont_...) which is resolved directly.
|
|
294
354
|
|
|
295
355
|
\b
|
|
296
356
|
LOCAL_DEST is an optional path (directory or file) to save to.
|
|
@@ -299,6 +359,7 @@ def download(ctx: click.Context, name_or_id: str, local_dest: str | None) -> Non
|
|
|
299
359
|
\b
|
|
300
360
|
Examples:
|
|
301
361
|
unique-cli download annual.pdf
|
|
362
|
+
unique-cli download /Reports/Q1/annual.pdf
|
|
302
363
|
unique-cli download annual.pdf ./downloads/
|
|
303
364
|
unique-cli download cont_abc123 ~/Desktop/
|
|
304
365
|
"""
|
|
@@ -324,10 +385,12 @@ def cite(
|
|
|
324
385
|
\b
|
|
325
386
|
Registers [filesourceN] markers for pages you referenced in your answer.
|
|
326
387
|
Does NOT read or extract the file — use your own tools for that.
|
|
388
|
+
NAME_OR_ID can be a file path, current-directory file name, or content ID.
|
|
327
389
|
|
|
328
390
|
\b
|
|
329
391
|
Examples:
|
|
330
392
|
unique-cli cite report.pdf --pages 3,5,7
|
|
393
|
+
unique-cli cite /Reports/Q1/report.pdf --pages 3,5,7
|
|
331
394
|
unique-cli cite cont_abc123 --pages 1-4
|
|
332
395
|
"""
|
|
333
396
|
click.echo(cmd_cite_file(LazyState.get(ctx), name_or_id, pages))
|
|
@@ -359,19 +422,92 @@ def read_cmd(ctx: click.Context, cont_id: str) -> None:
|
|
|
359
422
|
click.echo(output)
|
|
360
423
|
|
|
361
424
|
|
|
425
|
+
@main.group(name="dynamic-frontend")
|
|
426
|
+
def dynamic_frontend() -> None:
|
|
427
|
+
"""Deploy and list Dynamic Frontend spaces."""
|
|
428
|
+
|
|
429
|
+
|
|
430
|
+
@dynamic_frontend.command(name="deploy")
|
|
431
|
+
@click.option(
|
|
432
|
+
"--file",
|
|
433
|
+
"file_path",
|
|
434
|
+
default=None,
|
|
435
|
+
type=click.Path(exists=True),
|
|
436
|
+
help="Path to an upload-ready Dynamic Frontend ZIP bundle.",
|
|
437
|
+
)
|
|
438
|
+
@click.option(
|
|
439
|
+
"--content-id",
|
|
440
|
+
default=None,
|
|
441
|
+
help="Existing Knowledge Base content id for the ZIP bundle.",
|
|
442
|
+
)
|
|
443
|
+
@click.option(
|
|
444
|
+
"--name",
|
|
445
|
+
default=None,
|
|
446
|
+
help="Space display name. Required when creating; optional rename when updating.",
|
|
447
|
+
)
|
|
448
|
+
@click.option(
|
|
449
|
+
"--space-id", default=None, help="Existing Dynamic Frontend space id to update."
|
|
450
|
+
)
|
|
451
|
+
@click.option(
|
|
452
|
+
"--json", "output_json", is_flag=True, default=False, help="Print raw JSON."
|
|
453
|
+
)
|
|
454
|
+
@click.pass_context
|
|
455
|
+
def dynamic_frontend_deploy(
|
|
456
|
+
ctx: click.Context,
|
|
457
|
+
file_path: str | None,
|
|
458
|
+
content_id: str | None,
|
|
459
|
+
name: str | None,
|
|
460
|
+
space_id: str | None,
|
|
461
|
+
output_json: bool,
|
|
462
|
+
) -> None:
|
|
463
|
+
"""Create or update a Dynamic Frontend space.
|
|
464
|
+
|
|
465
|
+
\b
|
|
466
|
+
Examples:
|
|
467
|
+
unique-cli dynamic-frontend deploy --file ./app.zip --name "Revenue Dashboard"
|
|
468
|
+
unique-cli dynamic-frontend deploy --content-id content_123 --name "Revenue Dashboard"
|
|
469
|
+
unique-cli dynamic-frontend deploy --space-id assistant_123 --file ./app.zip
|
|
470
|
+
"""
|
|
471
|
+
output = cmd_dynamic_frontend_deploy(
|
|
472
|
+
LazyState.get(ctx),
|
|
473
|
+
file=file_path,
|
|
474
|
+
content_id=content_id,
|
|
475
|
+
name=name,
|
|
476
|
+
space_id=space_id,
|
|
477
|
+
output_json=output_json,
|
|
478
|
+
)
|
|
479
|
+
click.echo(output)
|
|
480
|
+
if output.startswith(_DYNAMIC_FRONTEND_ERROR_PREFIX):
|
|
481
|
+
ctx.exit(1)
|
|
482
|
+
|
|
483
|
+
|
|
484
|
+
@dynamic_frontend.command(name="list")
|
|
485
|
+
@click.option(
|
|
486
|
+
"--json", "output_json", is_flag=True, default=False, help="Print raw JSON."
|
|
487
|
+
)
|
|
488
|
+
@click.pass_context
|
|
489
|
+
def dynamic_frontend_list(ctx: click.Context, output_json: bool) -> None:
|
|
490
|
+
"""List Dynamic Frontend spaces the current user can manage."""
|
|
491
|
+
output = cmd_dynamic_frontend_list(LazyState.get(ctx), output_json=output_json)
|
|
492
|
+
click.echo(output)
|
|
493
|
+
if output.startswith(_DYNAMIC_FRONTEND_ERROR_PREFIX):
|
|
494
|
+
ctx.exit(1)
|
|
495
|
+
|
|
496
|
+
|
|
362
497
|
@main.command()
|
|
363
498
|
@click.argument("name_or_id")
|
|
364
499
|
@click.pass_context
|
|
365
500
|
def rm(ctx: click.Context, name_or_id: str) -> None:
|
|
366
|
-
"""Delete a file by name or content ID.
|
|
501
|
+
"""Delete a file by path, name, or content ID.
|
|
367
502
|
|
|
368
503
|
\b
|
|
369
|
-
NAME_OR_ID is a file name
|
|
370
|
-
a content ID (cont_...).
|
|
504
|
+
NAME_OR_ID is a file path, a file name matched in the current
|
|
505
|
+
directory, or a content ID (cont_...).
|
|
371
506
|
|
|
372
507
|
\b
|
|
373
508
|
Examples:
|
|
374
509
|
unique-cli rm report.pdf
|
|
510
|
+
unique-cli rm /Reports/Q1/report.pdf
|
|
375
511
|
unique-cli rm cont_abc123
|
|
376
512
|
"""
|
|
377
513
|
click.echo(cmd_rm(LazyState.get(ctx), name_or_id))
|
|
@@ -386,11 +522,12 @@ def mv(ctx: click.Context, old_name: str, new_name: str) -> None:
|
|
|
386
522
|
|
|
387
523
|
\b
|
|
388
524
|
Changes the file's display title without changing its content ID
|
|
389
|
-
or location. OLD_NAME can be a file name or content ID.
|
|
525
|
+
or location. OLD_NAME can be a file path, file name, or content ID.
|
|
390
526
|
|
|
391
527
|
\b
|
|
392
528
|
Examples:
|
|
393
529
|
unique-cli mv annual.pdf annual-2025.pdf
|
|
530
|
+
unique-cli mv /Reports/Q1/annual.pdf annual-2025.pdf
|
|
394
531
|
unique-cli mv cont_abc123 "New Title.pdf"
|
|
395
532
|
"""
|
|
396
533
|
click.echo(cmd_mv_file(LazyState.get(ctx), old_name, new_name))
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
from pathlib import Path
|
|
5
|
+
|
|
6
|
+
import unique_sdk
|
|
7
|
+
from unique_sdk.cli.state import ShellState
|
|
8
|
+
from unique_sdk.utils.file_io import upload_file
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def _upload_bundle(state: ShellState, file_path: str) -> str:
|
|
12
|
+
path = Path(file_path).expanduser().resolve()
|
|
13
|
+
if not path.is_file():
|
|
14
|
+
raise ValueError(f"local file not found: {file_path}")
|
|
15
|
+
|
|
16
|
+
if not state.scope_id:
|
|
17
|
+
raise ValueError("cannot upload bundle to root. cd into a folder first.")
|
|
18
|
+
|
|
19
|
+
result = upload_file(
|
|
20
|
+
userId=state.config.user_id,
|
|
21
|
+
companyId=state.config.company_id,
|
|
22
|
+
path_to_file=str(path),
|
|
23
|
+
displayed_filename=path.name,
|
|
24
|
+
mime_type="application/zip",
|
|
25
|
+
scope_or_unique_path=state.scope_id,
|
|
26
|
+
)
|
|
27
|
+
content_id = getattr(result, "id", None)
|
|
28
|
+
if not isinstance(content_id, str) or not content_id:
|
|
29
|
+
raise ValueError("upload did not return a content id")
|
|
30
|
+
return content_id
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def _format_space(space: object) -> str:
|
|
34
|
+
space_id = getattr(space, "spaceId", None) or getattr(space, "id", "")
|
|
35
|
+
name = getattr(space, "name", "")
|
|
36
|
+
content_id = getattr(space, "contentId", "")
|
|
37
|
+
status = getattr(space, "status", None)
|
|
38
|
+
phase = ""
|
|
39
|
+
url = ""
|
|
40
|
+
if isinstance(status, dict):
|
|
41
|
+
phase = str(status.get("phase") or "")
|
|
42
|
+
url = str(status.get("url") or "")
|
|
43
|
+
return "\t".join(
|
|
44
|
+
part for part in [str(space_id), str(name), str(content_id), phase, url] if part
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
def cmd_dynamic_frontend_deploy(
|
|
49
|
+
state: ShellState,
|
|
50
|
+
*,
|
|
51
|
+
file: str | None = None,
|
|
52
|
+
content_id: str | None = None,
|
|
53
|
+
name: str | None = None,
|
|
54
|
+
space_id: str | None = None,
|
|
55
|
+
output_json: bool = False,
|
|
56
|
+
) -> str:
|
|
57
|
+
try:
|
|
58
|
+
if not file and not content_id:
|
|
59
|
+
return "dynamic-frontend deploy: provide either --file or --content-id."
|
|
60
|
+
if file and content_id:
|
|
61
|
+
return "dynamic-frontend deploy: --file and --content-id are mutually exclusive."
|
|
62
|
+
if not space_id and not name:
|
|
63
|
+
return "dynamic-frontend deploy: provide --name when creating a Dynamic Frontend space."
|
|
64
|
+
|
|
65
|
+
resolved_content_id = _upload_bundle(state, file) if file else content_id
|
|
66
|
+
if not resolved_content_id:
|
|
67
|
+
return "dynamic-frontend deploy: expected a content id after resolving deploy input."
|
|
68
|
+
|
|
69
|
+
if space_id:
|
|
70
|
+
update_params: unique_sdk.DynamicFrontend.UpdateParams = {
|
|
71
|
+
"contentId": resolved_content_id,
|
|
72
|
+
}
|
|
73
|
+
if name is not None:
|
|
74
|
+
update_params["name"] = name
|
|
75
|
+
space = unique_sdk.DynamicFrontend.modify(
|
|
76
|
+
space_id,
|
|
77
|
+
user_id=state.config.user_id,
|
|
78
|
+
company_id=state.config.company_id,
|
|
79
|
+
**update_params,
|
|
80
|
+
)
|
|
81
|
+
action = "Updated"
|
|
82
|
+
else:
|
|
83
|
+
space = unique_sdk.DynamicFrontend.create(
|
|
84
|
+
user_id=state.config.user_id,
|
|
85
|
+
company_id=state.config.company_id,
|
|
86
|
+
name=name or "",
|
|
87
|
+
contentId=resolved_content_id,
|
|
88
|
+
)
|
|
89
|
+
action = "Created"
|
|
90
|
+
|
|
91
|
+
if output_json:
|
|
92
|
+
return json.dumps(dict(space), indent=2, default=str)
|
|
93
|
+
|
|
94
|
+
space_id_value = getattr(space, "spaceId", None) or getattr(space, "id", "")
|
|
95
|
+
name_value = getattr(space, "name", name or "")
|
|
96
|
+
return (
|
|
97
|
+
f'{action} Dynamic Frontend space "{name_value}" ({space_id_value})\n'
|
|
98
|
+
f"Content: {resolved_content_id}"
|
|
99
|
+
)
|
|
100
|
+
except (ValueError, unique_sdk.APIError, OSError) as e:
|
|
101
|
+
return f"dynamic-frontend deploy: {e}"
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
def cmd_dynamic_frontend_list(state: ShellState, *, output_json: bool = False) -> str:
|
|
105
|
+
try:
|
|
106
|
+
spaces = unique_sdk.DynamicFrontend.list(
|
|
107
|
+
user_id=state.config.user_id,
|
|
108
|
+
company_id=state.config.company_id,
|
|
109
|
+
)
|
|
110
|
+
if output_json:
|
|
111
|
+
return json.dumps(spaces, indent=2, default=str)
|
|
112
|
+
if not spaces:
|
|
113
|
+
return "No manageable Dynamic Frontend spaces found."
|
|
114
|
+
return "\n".join(_format_space(space) for space in spaces)
|
|
115
|
+
except unique_sdk.APIError as e:
|
|
116
|
+
return f"dynamic-frontend list: {e}"
|