unique-sdk 2026.36.0.dev5__tar.gz → 2026.36.0.dev7__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.36.0.dev5 → unique_sdk-2026.36.0.dev7}/PKG-INFO +1 -1
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/pyproject.toml +1 -1
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/cli.py +83 -27
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/identity.py +57 -4
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/file_io.py +50 -25
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/README.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/agentic_table.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/agentic_table_write.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/browser.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/files.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/mcp.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/metadata_filter.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/shell.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/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.36.0.
|
|
3
|
+
Version: 2026.36.0.dev7
|
|
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>
|
|
@@ -94,7 +94,11 @@ from unique_sdk.cli.commands.web_search import (
|
|
|
94
94
|
)
|
|
95
95
|
from unique_sdk.cli.commands.web_search_config import ENV_CONFIG_PATH
|
|
96
96
|
from unique_sdk.cli.config import load_config
|
|
97
|
-
from unique_sdk.cli.identity import
|
|
97
|
+
from unique_sdk.cli.identity import (
|
|
98
|
+
TurnIdentityError,
|
|
99
|
+
resolve_chat_id,
|
|
100
|
+
resolve_message_id,
|
|
101
|
+
)
|
|
98
102
|
from unique_sdk.cli.shell import UniqueShell
|
|
99
103
|
from unique_sdk.cli.state import ShellState
|
|
100
104
|
|
|
@@ -124,6 +128,33 @@ def _resolve_cli_message_id(
|
|
|
124
128
|
return resolved
|
|
125
129
|
|
|
126
130
|
|
|
131
|
+
def _resolve_cli_chat_id(
|
|
132
|
+
ctx: click.Context,
|
|
133
|
+
explicit: str | None,
|
|
134
|
+
*,
|
|
135
|
+
required: bool = False,
|
|
136
|
+
) -> str | None:
|
|
137
|
+
"""Resolve chat id for Click commands; exit on turn-identity errors.
|
|
138
|
+
|
|
139
|
+
Preboot-placeholder ids (``chat_preboot*``) are re-resolved through the
|
|
140
|
+
turn-identity file so adopted preboot clients never send a chat id the
|
|
141
|
+
platform will reject as nonexistent.
|
|
142
|
+
"""
|
|
143
|
+
try:
|
|
144
|
+
resolved = resolve_chat_id(explicit)
|
|
145
|
+
except TurnIdentityError as exc:
|
|
146
|
+
click.echo(f"Error: {exc}", err=True)
|
|
147
|
+
ctx.exit(2)
|
|
148
|
+
if required and not resolved:
|
|
149
|
+
click.echo(
|
|
150
|
+
"Error: chat id is required. Pass --chat-id, or set "
|
|
151
|
+
"UNIQUE_TURN_IDENTITY_FILE / UNIQUE_CHAT_ID.",
|
|
152
|
+
err=True,
|
|
153
|
+
)
|
|
154
|
+
ctx.exit(2)
|
|
155
|
+
return resolved
|
|
156
|
+
|
|
157
|
+
|
|
127
158
|
MAIN_HELP = """\
|
|
128
159
|
Unique CLI -- Linux-like file explorer for the Unique AI Platform.
|
|
129
160
|
|
|
@@ -736,8 +767,12 @@ def uploaded_search(
|
|
|
736
767
|
@click.option(
|
|
737
768
|
"--chat-id",
|
|
738
769
|
"-c",
|
|
739
|
-
|
|
740
|
-
help=
|
|
770
|
+
default=None,
|
|
771
|
+
help=(
|
|
772
|
+
"Chat ID for the MCP tool call context. Defaults to the current "
|
|
773
|
+
"turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
774
|
+
"$UNIQUE_CHAT_ID."
|
|
775
|
+
),
|
|
741
776
|
)
|
|
742
777
|
@click.option(
|
|
743
778
|
"--message-id",
|
|
@@ -767,7 +802,7 @@ def uploaded_search(
|
|
|
767
802
|
def mcp(
|
|
768
803
|
ctx: click.Context,
|
|
769
804
|
payload: str | None,
|
|
770
|
-
chat_id: str,
|
|
805
|
+
chat_id: str | None,
|
|
771
806
|
message_id: str | None,
|
|
772
807
|
file_path: str | None,
|
|
773
808
|
use_stdin: bool,
|
|
@@ -780,9 +815,9 @@ def mcp(
|
|
|
780
815
|
|
|
781
816
|
\b
|
|
782
817
|
The JSON is forwarded 1:1 to the MCP call-tool API. Chat ID and
|
|
783
|
-
message ID
|
|
784
|
-
|
|
785
|
-
|
|
818
|
+
message ID identify the conversation context. When --message-id or
|
|
819
|
+
--chat-id is omitted, the CLI resolves it from
|
|
820
|
+
$UNIQUE_TURN_IDENTITY_FILE (preferred) or the matching env var.
|
|
786
821
|
|
|
787
822
|
\b
|
|
788
823
|
Input sources (exactly one required):
|
|
@@ -800,10 +835,11 @@ def mcp(
|
|
|
800
835
|
cat payload.json | unique-cli mcp -c chat_123 -m msg_456 --stdin
|
|
801
836
|
"""
|
|
802
837
|
resolved_message_id = _resolve_cli_message_id(ctx, message_id, required=True)
|
|
838
|
+
resolved_chat_id = _resolve_cli_chat_id(ctx, chat_id, required=True)
|
|
803
839
|
click.echo(
|
|
804
840
|
cmd_mcp(
|
|
805
841
|
LazyState.get(ctx),
|
|
806
|
-
chat_id=
|
|
842
|
+
chat_id=resolved_chat_id or "",
|
|
807
843
|
message_id=resolved_message_id or "",
|
|
808
844
|
payload=payload,
|
|
809
845
|
file=file_path,
|
|
@@ -826,8 +862,11 @@ def mcp(
|
|
|
826
862
|
"--chat-id",
|
|
827
863
|
"parent_chat_id",
|
|
828
864
|
default=None,
|
|
829
|
-
|
|
830
|
-
|
|
865
|
+
help=(
|
|
866
|
+
"Parent chat ID for message correlation. Defaults to the current "
|
|
867
|
+
"turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
868
|
+
"$UNIQUE_CHAT_ID."
|
|
869
|
+
),
|
|
831
870
|
)
|
|
832
871
|
@click.option(
|
|
833
872
|
"--message-id",
|
|
@@ -881,12 +920,13 @@ def subagent(
|
|
|
881
920
|
unique-cli subagent Finance "Summarize Q4 revenue" --reset-chat
|
|
882
921
|
"""
|
|
883
922
|
resolved_message_id = _resolve_cli_message_id(ctx, parent_message_id)
|
|
923
|
+
resolved_chat_id = _resolve_cli_chat_id(ctx, parent_chat_id)
|
|
884
924
|
output = cmd_subagent(
|
|
885
925
|
LazyState.get(ctx),
|
|
886
926
|
tool_name=tool_name,
|
|
887
927
|
message=message,
|
|
888
928
|
config_path=config_path,
|
|
889
|
-
parent_chat_id=
|
|
929
|
+
parent_chat_id=resolved_chat_id,
|
|
890
930
|
parent_message_id=resolved_message_id,
|
|
891
931
|
parent_assistant_id=parent_assistant_id,
|
|
892
932
|
reset_chat=reset_chat,
|
|
@@ -1144,7 +1184,15 @@ def elicit() -> None:
|
|
|
1144
1184
|
'"answer" string field when omitted.'
|
|
1145
1185
|
),
|
|
1146
1186
|
)
|
|
1147
|
-
@click.option(
|
|
1187
|
+
@click.option(
|
|
1188
|
+
"--chat-id",
|
|
1189
|
+
"-c",
|
|
1190
|
+
default=None,
|
|
1191
|
+
help=(
|
|
1192
|
+
"Associated chat ID. Defaults to the current turn identity file "
|
|
1193
|
+
"($UNIQUE_TURN_IDENTITY_FILE), then $UNIQUE_CHAT_ID."
|
|
1194
|
+
),
|
|
1195
|
+
)
|
|
1148
1196
|
@click.option(
|
|
1149
1197
|
"--message-id",
|
|
1150
1198
|
"-m",
|
|
@@ -1276,7 +1324,7 @@ def elicit_ask(
|
|
|
1276
1324
|
"message": message,
|
|
1277
1325
|
"tool_name": tool_name,
|
|
1278
1326
|
"schema": schema,
|
|
1279
|
-
"chat_id": chat_id,
|
|
1327
|
+
"chat_id": _resolve_cli_chat_id(ctx, chat_id),
|
|
1280
1328
|
"message_id": _resolve_cli_message_id(ctx, message_id),
|
|
1281
1329
|
"timeout": timeout,
|
|
1282
1330
|
"expires_in_seconds": expires_in_seconds,
|
|
@@ -1313,7 +1361,15 @@ def elicit_ask(
|
|
|
1313
1361
|
help="JSON schema (required for --mode FORM).",
|
|
1314
1362
|
)
|
|
1315
1363
|
@click.option("--url", default=None, help="External URL (required for --mode URL).")
|
|
1316
|
-
@click.option(
|
|
1364
|
+
@click.option(
|
|
1365
|
+
"--chat-id",
|
|
1366
|
+
"-c",
|
|
1367
|
+
default=None,
|
|
1368
|
+
help=(
|
|
1369
|
+
"Associated chat ID. Defaults to the current turn identity file "
|
|
1370
|
+
"($UNIQUE_TURN_IDENTITY_FILE), then $UNIQUE_CHAT_ID."
|
|
1371
|
+
),
|
|
1372
|
+
)
|
|
1317
1373
|
@click.option(
|
|
1318
1374
|
"--message-id",
|
|
1319
1375
|
"-m",
|
|
@@ -1426,7 +1482,7 @@ def elicit_create(
|
|
|
1426
1482
|
"tool_name": tool_name,
|
|
1427
1483
|
"schema": schema,
|
|
1428
1484
|
"url": url,
|
|
1429
|
-
"chat_id": chat_id,
|
|
1485
|
+
"chat_id": _resolve_cli_chat_id(ctx, chat_id),
|
|
1430
1486
|
"message_id": _resolve_cli_message_id(ctx, message_id),
|
|
1431
1487
|
"expires_in_seconds": expires_in_seconds,
|
|
1432
1488
|
"external_elicitation_id": external_elicitation_id,
|
|
@@ -2074,12 +2130,12 @@ Examples:
|
|
|
2074
2130
|
"--chat-id",
|
|
2075
2131
|
"chat_id",
|
|
2076
2132
|
default=None,
|
|
2077
|
-
envvar="UNIQUE_CHAT_ID",
|
|
2078
2133
|
help=(
|
|
2079
|
-
"Chat id this call is made on behalf of. Defaults to
|
|
2080
|
-
"
|
|
2081
|
-
"
|
|
2082
|
-
"Search is
|
|
2134
|
+
"Chat id this call is made on behalf of. Defaults to the current "
|
|
2135
|
+
"turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
2136
|
+
"$UNIQUE_CHAT_ID (auto-set in Conduct sandboxes). When set, the "
|
|
2137
|
+
"space's Web Search toggle is enforced server-side and the call is "
|
|
2138
|
+
"rejected if Web Search is disabled for that space."
|
|
2083
2139
|
),
|
|
2084
2140
|
)
|
|
2085
2141
|
@click.pass_context
|
|
@@ -2105,7 +2161,7 @@ def web_search_search_cmd(
|
|
|
2105
2161
|
crawler_config_raw=crawler_config_raw,
|
|
2106
2162
|
output_json=output_json,
|
|
2107
2163
|
config_path=resolved_config,
|
|
2108
|
-
chat_id=chat_id,
|
|
2164
|
+
chat_id=_resolve_cli_chat_id(ctx, chat_id),
|
|
2109
2165
|
)
|
|
2110
2166
|
_emit_web_search(ctx, output)
|
|
2111
2167
|
|
|
@@ -2165,12 +2221,12 @@ Examples:
|
|
|
2165
2221
|
"--chat-id",
|
|
2166
2222
|
"chat_id",
|
|
2167
2223
|
default=None,
|
|
2168
|
-
envvar="UNIQUE_CHAT_ID",
|
|
2169
2224
|
help=(
|
|
2170
|
-
"Chat id this call is made on behalf of. Defaults to
|
|
2171
|
-
"
|
|
2172
|
-
"
|
|
2173
|
-
"Search is
|
|
2225
|
+
"Chat id this call is made on behalf of. Defaults to the current "
|
|
2226
|
+
"turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
2227
|
+
"$UNIQUE_CHAT_ID (auto-set in Conduct sandboxes). When set, the "
|
|
2228
|
+
"space's Web Search toggle is enforced server-side and the call is "
|
|
2229
|
+
"rejected if Web Search is disabled for that space."
|
|
2174
2230
|
),
|
|
2175
2231
|
)
|
|
2176
2232
|
@click.pass_context
|
|
@@ -2200,7 +2256,7 @@ def web_search_crawl_cmd(
|
|
|
2200
2256
|
crawler_config_raw=crawler_config_raw,
|
|
2201
2257
|
output_json=output_json,
|
|
2202
2258
|
config_path=resolved_config,
|
|
2203
|
-
chat_id=chat_id,
|
|
2259
|
+
chat_id=_resolve_cli_chat_id(ctx, chat_id),
|
|
2204
2260
|
)
|
|
2205
2261
|
_emit_web_search(ctx, output)
|
|
2206
2262
|
|
|
@@ -14,6 +14,12 @@ Resolution precedence for message IDs:
|
|
|
14
14
|
|
|
15
15
|
When ``UNIQUE_TURN_IDENTITY_FILE`` is set but the file is missing or malformed,
|
|
16
16
|
resolution fails loudly — silent fallback to a stale env value is forbidden.
|
|
17
|
+
|
|
18
|
+
Chat IDs resolve the same way, with one twist: a client spawned during a
|
|
19
|
+
chatless preboot carries a synthetic ``chat_preboot*`` placeholder in its
|
|
20
|
+
frozen environment. The placeholder never names a real chat (the platform
|
|
21
|
+
rejects it), so it is treated as absent at every precedence level and the
|
|
22
|
+
turn-identity file supplies the adopted chat's real ID.
|
|
17
23
|
"""
|
|
18
24
|
|
|
19
25
|
from __future__ import annotations
|
|
@@ -25,6 +31,12 @@ from pathlib import Path
|
|
|
25
31
|
|
|
26
32
|
TURN_IDENTITY_ENV_VAR = "UNIQUE_TURN_IDENTITY_FILE"
|
|
27
33
|
MESSAGE_ID_ENV_VAR = "UNIQUE_MESSAGE_ID"
|
|
34
|
+
CHAT_ID_ENV_VAR = "UNIQUE_CHAT_ID"
|
|
35
|
+
|
|
36
|
+
# Synthetic chat-id prefix used by the sandbox runner for clients spawned
|
|
37
|
+
# before their chat exists (chatless preboot). Adoption re-keys the client
|
|
38
|
+
# to the real chat, but the spawn env keeps the placeholder forever.
|
|
39
|
+
PREBOOT_CHAT_ID_PREFIX = "chat_preboot"
|
|
28
40
|
|
|
29
41
|
|
|
30
42
|
class TurnIdentityError(ValueError):
|
|
@@ -36,12 +48,14 @@ class TurnIdentity:
|
|
|
36
48
|
"""Parsed contents of the per-turn identity file.
|
|
37
49
|
|
|
38
50
|
The runner writes a richer JSON object (chat/user/company/assistant IDs,
|
|
39
|
-
turn counter), but the CLI only consumes
|
|
40
|
-
|
|
41
|
-
|
|
51
|
+
turn counter), but the CLI only consumes the values that go stale in a
|
|
52
|
+
persistent process environment: ``message_id`` (every turn) and
|
|
53
|
+
``chat_id`` (adopted chatless-preboot clients). Extra keys are ignored;
|
|
54
|
+
parse a field here only once the CLI actually relies on it.
|
|
42
55
|
"""
|
|
43
56
|
|
|
44
57
|
message_id: str
|
|
58
|
+
chat_id: str | None = None
|
|
45
59
|
|
|
46
60
|
|
|
47
61
|
def read_turn_identity(
|
|
@@ -88,7 +102,11 @@ def read_turn_identity(
|
|
|
88
102
|
"'message_id' string"
|
|
89
103
|
)
|
|
90
104
|
|
|
91
|
-
|
|
105
|
+
chat_id = payload.get("chat_id")
|
|
106
|
+
parsed_chat_id = (
|
|
107
|
+
chat_id.strip() if isinstance(chat_id, str) and chat_id.strip() else None
|
|
108
|
+
)
|
|
109
|
+
return TurnIdentity(message_id=message_id.strip(), chat_id=parsed_chat_id)
|
|
92
110
|
|
|
93
111
|
|
|
94
112
|
def resolve_message_id(explicit: str | None = None) -> str | None:
|
|
@@ -110,3 +128,38 @@ def resolve_message_id(explicit: str | None = None) -> str | None:
|
|
|
110
128
|
if env_id is not None and env_id.strip():
|
|
111
129
|
return env_id.strip()
|
|
112
130
|
return None
|
|
131
|
+
|
|
132
|
+
|
|
133
|
+
def _usable_chat_id(value: str | None) -> str | None:
|
|
134
|
+
"""A non-empty chat id that is not a preboot placeholder, else None."""
|
|
135
|
+
if value is None:
|
|
136
|
+
return None
|
|
137
|
+
stripped = str(value).strip()
|
|
138
|
+
if not stripped or stripped.startswith(PREBOOT_CHAT_ID_PREFIX):
|
|
139
|
+
return None
|
|
140
|
+
return stripped
|
|
141
|
+
|
|
142
|
+
|
|
143
|
+
def resolve_chat_id(explicit: str | None = None) -> str | None:
|
|
144
|
+
"""Resolve the chat ID for a chat-bound CLI operation.
|
|
145
|
+
|
|
146
|
+
Same precedence as :func:`resolve_message_id` (explicit flag, then the
|
|
147
|
+
turn-identity file, then ``$UNIQUE_CHAT_ID``), except a ``chat_preboot*``
|
|
148
|
+
placeholder is skipped at every level — agents pass
|
|
149
|
+
``--chat-id "$UNIQUE_CHAT_ID"`` from an environment that may have been
|
|
150
|
+
frozen before their chat existed. Returns ``None`` when no source yields
|
|
151
|
+
a real chat id (chat-optional callers then omit the id). Raises
|
|
152
|
+
``TurnIdentityError`` when the turn-identity file is configured but
|
|
153
|
+
unusable.
|
|
154
|
+
"""
|
|
155
|
+
explicit_id = _usable_chat_id(explicit)
|
|
156
|
+
if explicit_id is not None:
|
|
157
|
+
return explicit_id
|
|
158
|
+
|
|
159
|
+
identity = read_turn_identity()
|
|
160
|
+
if identity is not None:
|
|
161
|
+
file_id = _usable_chat_id(identity.chat_id)
|
|
162
|
+
if file_id is not None:
|
|
163
|
+
return file_id
|
|
164
|
+
|
|
165
|
+
return _usable_chat_id(os.environ.get(CHAT_ID_ENV_VAR))
|
|
@@ -34,24 +34,48 @@ class _VersioningKwargs(TypedDict, total=False):
|
|
|
34
34
|
versioningEnabled: bool
|
|
35
35
|
|
|
36
36
|
|
|
37
|
+
# Streaming chunk size for blob downloads. Downloads MUST stream to disk:
|
|
38
|
+
# buffering whole files via ``response.content`` peaks at ~2x the file size
|
|
39
|
+
# in RAM and has OOM'd memory-limited runtimes downloading many large chat
|
|
40
|
+
# files concurrently (UN-24862).
|
|
41
|
+
_DOWNLOAD_CHUNK_BYTES = 1024 * 1024
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def _stream_response_to_file(response: requests.Response, file_path: Path) -> None:
|
|
45
|
+
"""Write the response body to *file_path* chunk by chunk.
|
|
46
|
+
|
|
47
|
+
Removes the partially written file when the transfer fails mid-stream so
|
|
48
|
+
callers never observe a truncated download at the destination path.
|
|
49
|
+
"""
|
|
50
|
+
# open() outside the cleanup scope: if it fails (permissions, EMFILE) the
|
|
51
|
+
# destination was never truncated, and a pre-existing complete file there
|
|
52
|
+
# must not be deleted.
|
|
53
|
+
file = open(file_path, "wb")
|
|
54
|
+
try:
|
|
55
|
+
with file:
|
|
56
|
+
for chunk in response.iter_content(chunk_size=_DOWNLOAD_CHUNK_BYTES):
|
|
57
|
+
file.write(chunk)
|
|
58
|
+
except BaseException:
|
|
59
|
+
file_path.unlink(missing_ok=True)
|
|
60
|
+
raise
|
|
61
|
+
|
|
62
|
+
|
|
37
63
|
# download readUrl a random directory in /tmp
|
|
38
64
|
def download_file(url: str, filename: str):
|
|
39
65
|
# Guard for callers without a type checker: fail fast with a clear error before reaching requests.
|
|
40
66
|
if not isinstance(url, str): # pyright: ignore[reportUnnecessaryIsInstance]
|
|
41
67
|
raise ValueError("URL must be a string.") # pyright: ignore[reportUnreachable]
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
68
|
+
with requests.get(
|
|
69
|
+
url, timeout=unique_sdk.blob_transfer_timeout, stream=True
|
|
70
|
+
) as response:
|
|
71
|
+
if response.status_code != 200:
|
|
72
|
+
raise Exception(
|
|
73
|
+
f"Error downloading file: Status code {response.status_code}"
|
|
74
|
+
)
|
|
47
75
|
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
with open(file_path, "wb") as file:
|
|
52
|
-
file.write(response.content)
|
|
53
|
-
else:
|
|
54
|
-
raise Exception(f"Error downloading file: Status code {response.status_code}")
|
|
76
|
+
random_dir = tempfile.mkdtemp(dir="/tmp")
|
|
77
|
+
file_path = Path(random_dir) / filename
|
|
78
|
+
_stream_response_to_file(response, file_path)
|
|
55
79
|
|
|
56
80
|
return file_path
|
|
57
81
|
|
|
@@ -369,21 +393,22 @@ def download_content(
|
|
|
369
393
|
# Issue the request before resolving the destination. A non-200
|
|
370
394
|
# response should never leave a half-created directory or empty
|
|
371
395
|
# file behind for callers who supplied ``target_path``.
|
|
372
|
-
|
|
373
|
-
url, headers=headers, timeout=unique_sdk.blob_transfer_timeout
|
|
374
|
-
)
|
|
375
|
-
|
|
376
|
-
|
|
396
|
+
with requests.get(
|
|
397
|
+
url, headers=headers, timeout=unique_sdk.blob_transfer_timeout, stream=True
|
|
398
|
+
) as response:
|
|
399
|
+
if response.status_code != 200:
|
|
400
|
+
raise Exception(
|
|
401
|
+
f"Error downloading file: Status code {response.status_code}"
|
|
402
|
+
)
|
|
377
403
|
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
404
|
+
if target_path is not None:
|
|
405
|
+
file_path = Path(target_path)
|
|
406
|
+
file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
407
|
+
else:
|
|
408
|
+
random_dir = tempfile.mkdtemp(dir="/tmp")
|
|
409
|
+
file_path = Path(random_dir) / filename
|
|
384
410
|
|
|
385
|
-
|
|
386
|
-
file.write(response.content)
|
|
411
|
+
_stream_response_to_file(response, file_path)
|
|
387
412
|
|
|
388
413
|
return file_path
|
|
389
414
|
|
|
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.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/api_resources/_search_string.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/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.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/agentic_table.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/cite_file.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/cli/commands/web_search.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/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
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.36.0.dev5 → unique_sdk-2026.36.0.dev7}/unique_sdk/utils/benchmarking_run.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|