unique-sdk 2026.30.0.dev6__tar.gz → 2026.30.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.30.0.dev6 → unique_sdk-2026.30.0.dev7}/PKG-INFO +1 -1
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/pyproject.toml +1 -1
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/cli.py +65 -12
- unique_sdk-2026.30.0.dev7/unique_sdk/cli/identity.py +150 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +98 -22
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +1 -1
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +4 -2
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/README.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_api_requestor.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_api_resource.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_api_version.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_error.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_http_client.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_list_object.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_object_classes.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_request_options.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_unique_object.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_unique_ql.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_unique_response.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_util.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_version.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/_webhook.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_acronyms.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_agentic_table.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_analytics_order.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_benchmarking.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_briefing.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_chat_completion.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_content.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_dynamic_frontend.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_elicitation.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_embedding.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_event.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_folder.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_group.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_integrated.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_llm_models.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_mcp.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_assessment.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_execution.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_log.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_tool.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_module.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_scheduled_task.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_search.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_search_string.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_short_term_memory.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_space.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_user.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_web_search.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/__main__.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/__init__.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/browser.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/cite_file.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/dynamic_frontend.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/elicitation.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/files.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/folders.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/mcp.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/navigation.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/read.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/search.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/subagent.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/web_search.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/web_search_config.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/config.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/formatting.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/metadata_filter.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/shell.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-dynamic-frontend/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/state.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/analytics_order_run.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/benchmarking_run.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/chat_history.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/chat_in_space.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/file_io.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/sources.py +0 -0
- {unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.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.30.0.
|
|
3
|
+
Version: 2026.30.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>
|
|
@@ -84,11 +84,38 @@ from unique_sdk.cli.commands.web_search import (
|
|
|
84
84
|
)
|
|
85
85
|
from unique_sdk.cli.commands.web_search_config import ENV_CONFIG_PATH
|
|
86
86
|
from unique_sdk.cli.config import load_config
|
|
87
|
+
from unique_sdk.cli.identity import TurnIdentityError, resolve_message_id
|
|
87
88
|
from unique_sdk.cli.shell import UniqueShell
|
|
88
89
|
from unique_sdk.cli.state import ShellState
|
|
89
90
|
|
|
90
91
|
_DYNAMIC_FRONTEND_ERROR_PREFIX = "dynamic-frontend "
|
|
91
92
|
|
|
93
|
+
|
|
94
|
+
def _resolve_cli_message_id(
|
|
95
|
+
ctx: click.Context,
|
|
96
|
+
explicit: str | None,
|
|
97
|
+
*,
|
|
98
|
+
required: bool = False,
|
|
99
|
+
) -> str | None:
|
|
100
|
+
"""Resolve message id for Click commands; exit on turn-identity errors.
|
|
101
|
+
|
|
102
|
+
When *required* is True and no source yields a value, exits with code 2.
|
|
103
|
+
"""
|
|
104
|
+
try:
|
|
105
|
+
resolved = resolve_message_id(explicit)
|
|
106
|
+
except TurnIdentityError as exc:
|
|
107
|
+
click.echo(f"Error: {exc}", err=True)
|
|
108
|
+
ctx.exit(2)
|
|
109
|
+
if required and not resolved:
|
|
110
|
+
click.echo(
|
|
111
|
+
"Error: message id is required. Pass --message-id, or set "
|
|
112
|
+
"UNIQUE_TURN_IDENTITY_FILE / UNIQUE_MESSAGE_ID.",
|
|
113
|
+
err=True,
|
|
114
|
+
)
|
|
115
|
+
ctx.exit(2)
|
|
116
|
+
return resolved
|
|
117
|
+
|
|
118
|
+
|
|
92
119
|
MAIN_HELP = """\
|
|
93
120
|
Unique CLI -- Linux-like file explorer for the Unique AI Platform.
|
|
94
121
|
|
|
@@ -802,8 +829,12 @@ def uploaded_search(
|
|
|
802
829
|
@click.option(
|
|
803
830
|
"--message-id",
|
|
804
831
|
"-m",
|
|
805
|
-
|
|
806
|
-
help=
|
|
832
|
+
default=None,
|
|
833
|
+
help=(
|
|
834
|
+
"Message ID for the MCP tool call context. Defaults to the "
|
|
835
|
+
"current turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
836
|
+
"$UNIQUE_MESSAGE_ID."
|
|
837
|
+
),
|
|
807
838
|
)
|
|
808
839
|
@click.option(
|
|
809
840
|
"--file",
|
|
@@ -824,7 +855,7 @@ def mcp(
|
|
|
824
855
|
ctx: click.Context,
|
|
825
856
|
payload: str | None,
|
|
826
857
|
chat_id: str,
|
|
827
|
-
message_id: str,
|
|
858
|
+
message_id: str | None,
|
|
828
859
|
file_path: str | None,
|
|
829
860
|
use_stdin: bool,
|
|
830
861
|
) -> None:
|
|
@@ -837,7 +868,8 @@ def mcp(
|
|
|
837
868
|
\b
|
|
838
869
|
The JSON is forwarded 1:1 to the MCP call-tool API. Chat ID and
|
|
839
870
|
message ID are provided as separate flags to identify the
|
|
840
|
-
conversation context.
|
|
871
|
+
conversation context. When --message-id is omitted, the CLI resolves
|
|
872
|
+
it from $UNIQUE_TURN_IDENTITY_FILE (preferred) or $UNIQUE_MESSAGE_ID.
|
|
841
873
|
|
|
842
874
|
\b
|
|
843
875
|
Input sources (exactly one required):
|
|
@@ -854,11 +886,12 @@ def mcp(
|
|
|
854
886
|
|
|
855
887
|
cat payload.json | unique-cli mcp -c chat_123 -m msg_456 --stdin
|
|
856
888
|
"""
|
|
889
|
+
resolved_message_id = _resolve_cli_message_id(ctx, message_id, required=True)
|
|
857
890
|
click.echo(
|
|
858
891
|
cmd_mcp(
|
|
859
892
|
LazyState.get(ctx),
|
|
860
893
|
chat_id=chat_id,
|
|
861
|
-
message_id=
|
|
894
|
+
message_id=resolved_message_id or "",
|
|
862
895
|
payload=payload,
|
|
863
896
|
file=file_path,
|
|
864
897
|
stdin=use_stdin,
|
|
@@ -887,8 +920,11 @@ def mcp(
|
|
|
887
920
|
"--message-id",
|
|
888
921
|
"parent_message_id",
|
|
889
922
|
default=None,
|
|
890
|
-
|
|
891
|
-
|
|
923
|
+
help=(
|
|
924
|
+
"Parent message ID for message correlation. Defaults to the "
|
|
925
|
+
"current turn identity file ($UNIQUE_TURN_IDENTITY_FILE), then "
|
|
926
|
+
"$UNIQUE_MESSAGE_ID."
|
|
927
|
+
),
|
|
892
928
|
)
|
|
893
929
|
@click.option(
|
|
894
930
|
"--assistant-id",
|
|
@@ -931,13 +967,14 @@ def subagent(
|
|
|
931
967
|
unique-cli subagent LegalReview "Review this contract clause"
|
|
932
968
|
unique-cli subagent Finance "Summarize Q4 revenue" --reset-chat
|
|
933
969
|
"""
|
|
970
|
+
resolved_message_id = _resolve_cli_message_id(ctx, parent_message_id)
|
|
934
971
|
output = cmd_subagent(
|
|
935
972
|
LazyState.get(ctx),
|
|
936
973
|
tool_name=tool_name,
|
|
937
974
|
message=message,
|
|
938
975
|
config_path=config_path,
|
|
939
976
|
parent_chat_id=parent_chat_id,
|
|
940
|
-
parent_message_id=
|
|
977
|
+
parent_message_id=resolved_message_id,
|
|
941
978
|
parent_assistant_id=parent_assistant_id,
|
|
942
979
|
reset_chat=reset_chat,
|
|
943
980
|
output_json=output_json,
|
|
@@ -1195,7 +1232,15 @@ def elicit() -> None:
|
|
|
1195
1232
|
),
|
|
1196
1233
|
)
|
|
1197
1234
|
@click.option("--chat-id", "-c", default=None, help="Associated chat ID.")
|
|
1198
|
-
@click.option(
|
|
1235
|
+
@click.option(
|
|
1236
|
+
"--message-id",
|
|
1237
|
+
"-m",
|
|
1238
|
+
default=None,
|
|
1239
|
+
help=(
|
|
1240
|
+
"Associated message ID. Defaults to the current turn identity "
|
|
1241
|
+
"file ($UNIQUE_TURN_IDENTITY_FILE), then $UNIQUE_MESSAGE_ID."
|
|
1242
|
+
),
|
|
1243
|
+
)
|
|
1199
1244
|
@click.option(
|
|
1200
1245
|
"--timeout",
|
|
1201
1246
|
type=int,
|
|
@@ -1299,7 +1344,7 @@ def elicit_ask(
|
|
|
1299
1344
|
"tool_name": tool_name,
|
|
1300
1345
|
"schema": schema,
|
|
1301
1346
|
"chat_id": chat_id,
|
|
1302
|
-
"message_id": message_id,
|
|
1347
|
+
"message_id": _resolve_cli_message_id(ctx, message_id),
|
|
1303
1348
|
"timeout": timeout,
|
|
1304
1349
|
"poll_interval": poll_interval,
|
|
1305
1350
|
"metadata": parsed_metadata or None,
|
|
@@ -1334,7 +1379,15 @@ def elicit_ask(
|
|
|
1334
1379
|
)
|
|
1335
1380
|
@click.option("--url", default=None, help="External URL (required for --mode URL).")
|
|
1336
1381
|
@click.option("--chat-id", "-c", default=None, help="Associated chat ID.")
|
|
1337
|
-
@click.option(
|
|
1382
|
+
@click.option(
|
|
1383
|
+
"--message-id",
|
|
1384
|
+
"-m",
|
|
1385
|
+
default=None,
|
|
1386
|
+
help=(
|
|
1387
|
+
"Associated message ID. Defaults to the current turn identity "
|
|
1388
|
+
"file ($UNIQUE_TURN_IDENTITY_FILE), then $UNIQUE_MESSAGE_ID."
|
|
1389
|
+
),
|
|
1390
|
+
)
|
|
1338
1391
|
@click.option(
|
|
1339
1392
|
"--expires-in",
|
|
1340
1393
|
"expires_in_seconds",
|
|
@@ -1439,7 +1492,7 @@ def elicit_create(
|
|
|
1439
1492
|
"schema": schema,
|
|
1440
1493
|
"url": url,
|
|
1441
1494
|
"chat_id": chat_id,
|
|
1442
|
-
"message_id": message_id,
|
|
1495
|
+
"message_id": _resolve_cli_message_id(ctx, message_id),
|
|
1443
1496
|
"expires_in_seconds": expires_in_seconds,
|
|
1444
1497
|
"external_elicitation_id": external_elicitation_id,
|
|
1445
1498
|
"metadata": parsed_metadata or None,
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
"""Resolve the current turn's assistant message identity.
|
|
2
|
+
|
|
3
|
+
Persistent agent subprocesses freeze their OS environment at spawn time, so
|
|
4
|
+
``UNIQUE_MESSAGE_ID`` can be stale on later turns. The parent runner writes a
|
|
5
|
+
per-turn identity file and exposes its path via ``UNIQUE_TURN_IDENTITY_FILE``
|
|
6
|
+
(stable across turns). Fresh ``unique-cli`` invocations then read the current
|
|
7
|
+
message ID from that file.
|
|
8
|
+
|
|
9
|
+
Resolution precedence for message IDs:
|
|
10
|
+
|
|
11
|
+
1. Explicit ``--message-id`` / ``-m`` flag value
|
|
12
|
+
2. Turn-identity file pointed to by ``$UNIQUE_TURN_IDENTITY_FILE``
|
|
13
|
+
3. ``$UNIQUE_MESSAGE_ID`` environment variable (one-shot / external callers)
|
|
14
|
+
|
|
15
|
+
When ``UNIQUE_TURN_IDENTITY_FILE`` is set but the file is missing or malformed,
|
|
16
|
+
resolution fails loudly — silent fallback to a stale env value is forbidden.
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
from __future__ import annotations
|
|
20
|
+
|
|
21
|
+
import json
|
|
22
|
+
import os
|
|
23
|
+
from dataclasses import dataclass
|
|
24
|
+
from pathlib import Path
|
|
25
|
+
|
|
26
|
+
TURN_IDENTITY_ENV_VAR = "UNIQUE_TURN_IDENTITY_FILE"
|
|
27
|
+
MESSAGE_ID_ENV_VAR = "UNIQUE_MESSAGE_ID"
|
|
28
|
+
CHAT_ID_ENV_VAR = "UNIQUE_CHAT_ID"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class TurnIdentityError(ValueError):
|
|
32
|
+
"""Raised when the turn-identity file is configured but unusable."""
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
@dataclass(frozen=True)
|
|
36
|
+
class TurnIdentity:
|
|
37
|
+
"""Parsed contents of the per-turn identity file.
|
|
38
|
+
|
|
39
|
+
Mirrors the JSON contract written by the platform runner. Only
|
|
40
|
+
``message_id`` is mandatory; the remaining fields are informational.
|
|
41
|
+
"""
|
|
42
|
+
|
|
43
|
+
message_id: str
|
|
44
|
+
chat_id: str | None = None
|
|
45
|
+
user_id: str | None = None
|
|
46
|
+
company_id: str | None = None
|
|
47
|
+
assistant_id: str | None = None
|
|
48
|
+
turn: int | None = None
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _optional_str(payload: dict[str, object], key: str) -> str | None:
|
|
52
|
+
value = payload.get(key)
|
|
53
|
+
if isinstance(value, str) and value.strip():
|
|
54
|
+
return value.strip()
|
|
55
|
+
return None
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def read_turn_identity(
|
|
59
|
+
path: str | Path | None = None,
|
|
60
|
+
) -> TurnIdentity | None:
|
|
61
|
+
"""Load and validate the turn-identity JSON file.
|
|
62
|
+
|
|
63
|
+
When *path* is ``None``, reads ``$UNIQUE_TURN_IDENTITY_FILE``. Returns
|
|
64
|
+
``None`` when neither is set. Raises ``TurnIdentityError`` if the env
|
|
65
|
+
var / path is set but the file cannot be read or does not contain a
|
|
66
|
+
non-empty ``message_id`` string.
|
|
67
|
+
"""
|
|
68
|
+
raw_path = str(path) if path is not None else os.environ.get(TURN_IDENTITY_ENV_VAR)
|
|
69
|
+
if not raw_path:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
identity_path = Path(raw_path)
|
|
73
|
+
if not identity_path.is_file():
|
|
74
|
+
raise TurnIdentityError(
|
|
75
|
+
f"{TURN_IDENTITY_ENV_VAR} is set to {raw_path!r} but the file "
|
|
76
|
+
"is missing; refusing to fall back to a stale message id"
|
|
77
|
+
)
|
|
78
|
+
if identity_path.is_symlink():
|
|
79
|
+
raise TurnIdentityError(
|
|
80
|
+
f"refusing to read turn-identity file {raw_path!r}: path is a symlink"
|
|
81
|
+
)
|
|
82
|
+
|
|
83
|
+
try:
|
|
84
|
+
payload = json.loads(identity_path.read_text(encoding="utf-8"))
|
|
85
|
+
except (OSError, UnicodeError, json.JSONDecodeError) as exc:
|
|
86
|
+
raise TurnIdentityError(
|
|
87
|
+
f"failed to read turn-identity file {raw_path!r}: {exc}"
|
|
88
|
+
) from exc
|
|
89
|
+
|
|
90
|
+
if not isinstance(payload, dict):
|
|
91
|
+
raise TurnIdentityError(
|
|
92
|
+
f"turn-identity file {raw_path!r} must contain a JSON object"
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
message_id = payload.get("message_id")
|
|
96
|
+
if not isinstance(message_id, str) or not message_id.strip():
|
|
97
|
+
raise TurnIdentityError(
|
|
98
|
+
f"turn-identity file {raw_path!r} is missing a non-empty "
|
|
99
|
+
"'message_id' string"
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
raw_turn = payload.get("turn")
|
|
103
|
+
return TurnIdentity(
|
|
104
|
+
message_id=message_id.strip(),
|
|
105
|
+
chat_id=_optional_str(payload, "chat_id"),
|
|
106
|
+
user_id=_optional_str(payload, "user_id"),
|
|
107
|
+
company_id=_optional_str(payload, "company_id"),
|
|
108
|
+
assistant_id=_optional_str(payload, "assistant_id"),
|
|
109
|
+
turn=raw_turn if isinstance(raw_turn, int) else None,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def resolve_message_id(explicit: str | None = None) -> str | None:
|
|
114
|
+
"""Resolve the assistant message ID for a message-bound CLI operation.
|
|
115
|
+
|
|
116
|
+
Returns ``None`` when no source yields a value (callers may then mint a
|
|
117
|
+
placeholder message, as elicit does for visible prompts without a chat
|
|
118
|
+
context). Raises ``TurnIdentityError`` when the turn-identity file is
|
|
119
|
+
configured but unusable.
|
|
120
|
+
"""
|
|
121
|
+
if explicit is not None and str(explicit).strip():
|
|
122
|
+
return str(explicit).strip()
|
|
123
|
+
|
|
124
|
+
identity = read_turn_identity()
|
|
125
|
+
if identity is not None:
|
|
126
|
+
return identity.message_id
|
|
127
|
+
|
|
128
|
+
env_id = os.environ.get(MESSAGE_ID_ENV_VAR)
|
|
129
|
+
if env_id is not None and env_id.strip():
|
|
130
|
+
return env_id.strip()
|
|
131
|
+
return None
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
def resolve_chat_id(explicit: str | None = None) -> str | None:
|
|
135
|
+
"""Resolve chat ID with the same file-then-env precedence as message ID.
|
|
136
|
+
|
|
137
|
+
Explicit flag wins. The turn-identity file is consulted next (and fails
|
|
138
|
+
loudly when configured but unusable). Falls back to ``$UNIQUE_CHAT_ID``.
|
|
139
|
+
"""
|
|
140
|
+
if explicit is not None and str(explicit).strip():
|
|
141
|
+
return str(explicit).strip()
|
|
142
|
+
|
|
143
|
+
identity = read_turn_identity()
|
|
144
|
+
if identity is not None and identity.chat_id is not None:
|
|
145
|
+
return identity.chat_id
|
|
146
|
+
|
|
147
|
+
env_id = os.environ.get(CHAT_ID_ENV_VAR)
|
|
148
|
+
if env_id is not None and env_id.strip():
|
|
149
|
+
return env_id.strip()
|
|
150
|
+
return None
|
|
@@ -5,8 +5,9 @@ description: >-
|
|
|
5
5
|
question in free-form chat -- for clarifications, confirmations
|
|
6
6
|
(especially destructive actions), missing parameters, multiple-choice
|
|
7
7
|
decisions, or structured form input. Elicitations are routed through
|
|
8
|
-
the Unique AI Platform UI via `unique-cli elicit
|
|
9
|
-
|
|
8
|
+
the Unique AI Platform UI via `unique-cli elicit create` + `elicit wait`
|
|
9
|
+
(or `elicit ask` outside an agent harness) so the user gets a proper
|
|
10
|
+
structured prompt and you get a structured answer back.
|
|
10
11
|
Do NOT ask the user in plain chat when you can use this skill instead.
|
|
11
12
|
---
|
|
12
13
|
|
|
@@ -14,21 +15,82 @@ description: >-
|
|
|
14
15
|
|
|
15
16
|
Use this skill **whenever you need input from the user** -- a clarifying question, a confirmation before a destructive action, a choice between options, or a structured form. Elicitations create a first-class UI prompt on the Unique AI Platform and return the answer as structured JSON.
|
|
16
17
|
|
|
17
|
-
> **Rule of thumb:** if you catch yourself about to write "Could you clarify…?" or "Do you want me to…?" or "Which one should I pick?" in chat, stop and
|
|
18
|
+
> **Rule of thumb:** if you catch yourself about to write "Could you clarify…?" or "Do you want me to…?" or "Which one should I pick?" in chat, stop and use `unique-cli elicit create` + `elicit wait` instead (see "The pattern" below).
|
|
18
19
|
|
|
19
20
|
!!! danger "`--visible` is currently MANDATORY"
|
|
20
|
-
You **must always
|
|
21
|
-
|
|
22
|
-
## The
|
|
23
|
-
|
|
24
|
-
|
|
21
|
+
You **must always create elicitations with visibility on** (it is on by default for both `elicit create` and `elicit ask` — just don't pass `--no-visible`). Until the UN-19815 UI fix ships in your environment, an elicitation created without the visibility workaround is stored by the backend but **never rendered in the chat UI** — the user simply never sees the question and you will wait forever. There is no situation in which you should disable it today.
|
|
22
|
+
|
|
23
|
+
## The pattern: `elicit create` + short polling loop with `elicit wait`
|
|
24
|
+
|
|
25
|
+
Do **not** call `elicit ask` from inside an agent harness (Claude Code, Codex,
|
|
26
|
+
or any environment where your Bash/shell tool has its own foreground-wait
|
|
27
|
+
timeout — commonly ~2 minutes). `elicit ask` blocks synchronously for up to
|
|
28
|
+
`--timeout` seconds (default 2 hours) waiting for the human to answer, but a
|
|
29
|
+
human reading and answering a prompt routinely takes longer than a typical
|
|
30
|
+
Bash tool timeout. If that timeout fires first, your harness will silently
|
|
31
|
+
detach the process to the background and hand you a "running in background"
|
|
32
|
+
stub instead of the real answer — you will not see the user's response, and
|
|
33
|
+
the chat may appear stuck to the user.
|
|
34
|
+
|
|
35
|
+
Instead, use `elicit create` (returns immediately) followed by a short
|
|
36
|
+
polling loop with `elicit wait`, where **every individual command finishes
|
|
37
|
+
comfortably under your harness's Bash foreground timeout** (90s is a safe
|
|
38
|
+
default — comfortably under Claude Code's ~120s):
|
|
39
|
+
|
|
40
|
+
1. **Create** the elicitation:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
create_output=$(unique-cli elicit create "<question>" \
|
|
44
|
+
--mode FORM \
|
|
45
|
+
--tool-name "<tool_name>" \
|
|
46
|
+
--chat-id "$UNIQUE_CHAT_ID" \
|
|
47
|
+
--expires-in 7200 \
|
|
48
|
+
--schema '<json schema>')
|
|
49
|
+
elicitation_id=$(echo "$create_output" | awk '/^Created elicitation/{print $3}')
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
2. **Poll in short bursts**, each well under your harness's Bash foreground
|
|
53
|
+
timeout:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
status="PENDING"
|
|
57
|
+
elapsed=0
|
|
58
|
+
total_timeout=7200 # match --expires-in above
|
|
59
|
+
chunk=90
|
|
60
|
+
while [ "$elapsed" -lt "$total_timeout" ]; do
|
|
61
|
+
result=$(unique-cli elicit wait "$elicitation_id" --timeout "$chunk" --poll-interval 3)
|
|
62
|
+
status=$(echo "$result" | awk -F': *' '/^Status:/{print $2}')
|
|
63
|
+
case "$status" in
|
|
64
|
+
RESPONDED|ACCEPTED|DECLINED|CANCELLED|REJECTED|EXPIRED|COMPLETED) break ;;
|
|
65
|
+
esac
|
|
66
|
+
elapsed=$((elapsed + chunk))
|
|
67
|
+
done
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
Each `elicit wait ... --timeout 90` call is a normal, short-lived Bash
|
|
71
|
+
invocation that always returns within ~90 seconds — either with a
|
|
72
|
+
terminal status (done) or the current non-terminal status (loop again).
|
|
73
|
+
Your harness never sees a single call run long enough to background it.
|
|
74
|
+
|
|
75
|
+
3. Parse `Response:` from the final `$result` exactly as you would with
|
|
76
|
+
`elicit ask`'s output — the format is identical (see "Reading the
|
|
77
|
+
response" below).
|
|
78
|
+
|
|
79
|
+
`elicit ask` remains the right choice for **non-agent, scripted, or
|
|
80
|
+
human-operated CLI usage** where a single blocking call is expected and
|
|
81
|
+
there is no surrounding tool-timeout concern (tests, ops scripts, manual CLI
|
|
82
|
+
use). Do not reach for it from inside an agent turn.
|
|
25
83
|
|
|
26
84
|
```bash
|
|
27
85
|
unique-cli elicit ask "<question>" [options]
|
|
28
86
|
```
|
|
29
87
|
|
|
30
|
-
!!! danger "`--chat-id`
|
|
31
|
-
You **must always pass
|
|
88
|
+
!!! danger "`--chat-id` is MANDATORY"
|
|
89
|
+
You **must always pass** `--chat-id "$UNIQUE_CHAT_ID"` on every
|
|
90
|
+
`elicit create`/`elicit ask` call. Omit `--message-id`: the CLI resolves
|
|
91
|
+
the current turn's assistant message ID from `$UNIQUE_TURN_IDENTITY_FILE`
|
|
92
|
+
(preferred) or `$UNIQUE_MESSAGE_ID`. Do **not** pass a stale
|
|
93
|
+
`$UNIQUE_MESSAGE_ID` from a persistent process environment.
|
|
32
94
|
|
|
33
95
|
## When to use
|
|
34
96
|
|
|
@@ -43,12 +105,16 @@ unique-cli elicit ask "<question>" [options]
|
|
|
43
105
|
|
|
44
106
|
## Examples
|
|
45
107
|
|
|
108
|
+
> The examples below use `elicit ask` for brevity to show the schema shapes.
|
|
109
|
+
> From an agent harness, use the same `--schema`/`--message`/`--tool-name`
|
|
110
|
+
> arguments with `elicit create` instead, then poll with `elicit wait` as
|
|
111
|
+
> shown in "The pattern" above.
|
|
112
|
+
|
|
46
113
|
### Minimal — free-text answer
|
|
47
114
|
|
|
48
115
|
```bash
|
|
49
116
|
unique-cli elicit ask "Which quarter should I report on?" \
|
|
50
|
-
--chat-id "$UNIQUE_CHAT_ID"
|
|
51
|
-
--message-id "$UNIQUE_MESSAGE_ID"
|
|
117
|
+
--chat-id "$UNIQUE_CHAT_ID"
|
|
52
118
|
```
|
|
53
119
|
|
|
54
120
|
Under the hood this creates a form with a single required string field `answer`. The reply you receive will look like:
|
|
@@ -71,7 +137,6 @@ Provide an explicit JSON schema so the user sees proper UI controls instead of a
|
|
|
71
137
|
```bash
|
|
72
138
|
unique-cli elicit ask "Which report format do you want?" \
|
|
73
139
|
--chat-id "$UNIQUE_CHAT_ID" \
|
|
74
|
-
--message-id "$UNIQUE_MESSAGE_ID" \
|
|
75
140
|
--schema '{
|
|
76
141
|
"type": "object",
|
|
77
142
|
"properties": {
|
|
@@ -92,7 +157,6 @@ Always use this before `rm`, `rmdir -r`, mass uploads, or anything irreversible.
|
|
|
92
157
|
```bash
|
|
93
158
|
unique-cli elicit ask "Confirm deleting /Archive/2024 and everything inside it" \
|
|
94
159
|
--chat-id "$UNIQUE_CHAT_ID" \
|
|
95
|
-
--message-id "$UNIQUE_MESSAGE_ID" \
|
|
96
160
|
--schema '{
|
|
97
161
|
"type": "object",
|
|
98
162
|
"properties": {
|
|
@@ -112,7 +176,6 @@ Proceed **only** if the response contains `"confirm": true`. Treat `DECLINED`, `
|
|
|
112
176
|
```bash
|
|
113
177
|
unique-cli elicit ask "Please provide report settings" \
|
|
114
178
|
--chat-id "$UNIQUE_CHAT_ID" \
|
|
115
|
-
--message-id "$UNIQUE_MESSAGE_ID" \
|
|
116
179
|
--schema '{
|
|
117
180
|
"type": "object",
|
|
118
181
|
"properties": {
|
|
@@ -127,10 +190,16 @@ unique-cli elicit ask "Please provide report settings" \
|
|
|
127
190
|
|
|
128
191
|
## Options
|
|
129
192
|
|
|
193
|
+
The table below documents `elicit ask`'s flags. `elicit create` takes the
|
|
194
|
+
same `--chat-id`, `--message-id`, `--tool-name`, `--schema`, `--metadata`,
|
|
195
|
+
and `--assistant-id` flags, but uses `--expires-in <seconds>` instead of
|
|
196
|
+
`--timeout`/`--poll-interval` (those two apply only to `elicit wait`, which
|
|
197
|
+
you call separately in the polling pattern).
|
|
198
|
+
|
|
130
199
|
| Option | Short | Default | Description |
|
|
131
200
|
|--------|-------|---------|-------------|
|
|
132
201
|
| `--chat-id` | `-c` | none | **MANDATORY.** Chat to show the question in. Always pass `"$UNIQUE_CHAT_ID"`. Without it the visibility workaround cannot run and the user will not see the elicitation. |
|
|
133
|
-
| `--message-id` | `-m` |
|
|
202
|
+
| `--message-id` | `-m` | auto | Optional. Prefer omitting this flag — the CLI resolves the current turn's message ID from `$UNIQUE_TURN_IDENTITY_FILE` (preferred) or `$UNIQUE_MESSAGE_ID`. Do not pass a stale env value from a persistent process. |
|
|
134
203
|
| `--tool-name` | `-t` | `agent_question` | Short snake_case label shown to the user (e.g. `clarify`, `confirm_delete`, `choose_report`). |
|
|
135
204
|
| `--schema` | | single `answer` string | JSON Schema for the form body. |
|
|
136
205
|
| `--timeout` | | `7200` | Max seconds to block locally before giving up. This is the single knob for `ask`: it also sets when the request expires on the platform, so the prompt expires exactly when you stop waiting and the chat UI can offer the user a way to continue. |
|
|
@@ -187,14 +256,20 @@ If the exact structured response is useful for auditing or debugging, put it beh
|
|
|
187
256
|
|
|
188
257
|
Do not expose raw JSON by default when a natural-language confirmation would be clearer.
|
|
189
258
|
|
|
190
|
-
## Scripting pattern
|
|
259
|
+
## Scripting pattern (non-agent-harness only)
|
|
260
|
+
|
|
261
|
+
This one-shot pattern is for **scripts, tests, or manual CLI use outside an
|
|
262
|
+
agent harness** — i.e. contexts with no Bash-tool foreground timeout to worry
|
|
263
|
+
about. From inside an agent harness, use the `elicit create` + `elicit wait`
|
|
264
|
+
polling pattern from "The pattern" section above instead; the output parsing
|
|
265
|
+
below (pulling `Response:` out of the text) is identical either way, only the
|
|
266
|
+
command(s) producing that output differ.
|
|
191
267
|
|
|
192
268
|
In a shell script or agent tool wrapper, capture the output and pull out the `Response:` line:
|
|
193
269
|
|
|
194
270
|
```bash
|
|
195
271
|
result=$(unique-cli elicit ask "Which region?" \
|
|
196
272
|
--chat-id "$UNIQUE_CHAT_ID" \
|
|
197
|
-
--message-id "$UNIQUE_MESSAGE_ID" \
|
|
198
273
|
--schema '{
|
|
199
274
|
"type":"object",
|
|
200
275
|
"properties":{"region":{"type":"string","enum":["EU","US","APAC"]}},
|
|
@@ -220,9 +295,9 @@ esac
|
|
|
220
295
|
|
|
221
296
|
## Agent workflow rules
|
|
222
297
|
|
|
223
|
-
1. **Default to `elicit
|
|
298
|
+
1. **Default to `elicit create` + `elicit wait` polling.** If you need an answer from the user, use this pattern, not a chat message and not a single blocking `elicit ask` call. See "The pattern" above.
|
|
224
299
|
2. **Always pass `--chat-id "$UNIQUE_CHAT_ID"`.** Without it the elicitation is not attached to a chat and the user will not see it.
|
|
225
|
-
3. **
|
|
300
|
+
3. **Omit `--message-id`.** The CLI resolves the current turn's assistant message ID from `$UNIQUE_TURN_IDENTITY_FILE` (preferred) or `$UNIQUE_MESSAGE_ID`. Do not pass a stale `$UNIQUE_MESSAGE_ID` from a persistent process environment.
|
|
226
301
|
4. **Never pass `--no-visible`.** See the warning above. The visibility workaround is mandatory today.
|
|
227
302
|
5. **Never run destructive CLI commands without a confirmation elicitation.** This includes `rm`, `rmdir -r`, bulk renames, large uploads, schedule deletion, etc.
|
|
228
303
|
6. **Pick a meaningful `--tool-name`.** `confirm_delete`, `choose_region`, `pick_report` -- short snake_case describing the intent.
|
|
@@ -231,7 +306,7 @@ esac
|
|
|
231
306
|
9. **Handle non-`RESPONDED` outcomes explicitly.** If the status is `DECLINED` / `CANCELLED` / `EXPIRED`, tell the user you stopped and ask what they want to do next instead of silently proceeding.
|
|
232
307
|
10. **Don't spam elicitations.** One well-designed form with a few related fields is better than five sequential yes/no questions.
|
|
233
308
|
11. **Cap each elicitation at 5 questions.** If you need more than 5 answers, split them into multiple focused elicitations so the user can respond confidently.
|
|
234
|
-
12. **
|
|
309
|
+
12. **Never make a single blocking call longer than your harness's Bash foreground timeout.** Use `--expires-in` on `elicit create` to set the real, human-scale deadline (e.g. 7200s / 2 hours), but keep each individual `elicit wait --timeout N` call short (≈90s) and loop until a terminal status or the overall deadline is reached. Never call `elicit ask` with a multi-minute `--timeout` from an agent harness.
|
|
235
310
|
|
|
236
311
|
## Prerequisites
|
|
237
312
|
|
|
@@ -243,7 +318,8 @@ UNIQUE_COMPANY_ID # Company ID (required)
|
|
|
243
318
|
UNIQUE_API_KEY # API key -- optional on localhost / secured cluster
|
|
244
319
|
UNIQUE_APP_ID # App ID -- optional on localhost / secured cluster
|
|
245
320
|
UNIQUE_CHAT_ID # Current chat ID -- always pass as --chat-id (required)
|
|
246
|
-
|
|
321
|
+
UNIQUE_TURN_IDENTITY_FILE # Per-turn identity JSON — CLI resolves message ID from here
|
|
322
|
+
UNIQUE_MESSAGE_ID # Fallback message ID when no turn-identity file is present
|
|
247
323
|
```
|
|
248
324
|
|
|
249
325
|
Install: `pip install unique-sdk`
|
|
@@ -77,7 +77,7 @@ unique-cli mcp [--chat-id <id>] [--message-id <id>] [PAYLOAD | --file <path> | -
|
|
|
77
77
|
| Option | Short | Required | Description |
|
|
78
78
|
|--------|-------|----------|-------------|
|
|
79
79
|
| `--chat-id` | `-c` | Yes | Chat ID for the conversation context |
|
|
80
|
-
| `--message-id` | `-m` |
|
|
80
|
+
| `--message-id` | `-m` | No | Message ID for the conversation context. Optional — resolved from `$UNIQUE_TURN_IDENTITY_FILE` (preferred) or `$UNIQUE_MESSAGE_ID` when omitted. |
|
|
81
81
|
| `PAYLOAD` | | One of three | Inline JSON string |
|
|
82
82
|
| `--file` | `-f` | One of three | Path to a JSON file |
|
|
83
83
|
| `--stdin` | | One of three | Read JSON from stdin |
|
|
@@ -17,10 +17,12 @@ the tool name shown in the generated connected-space skill.
|
|
|
17
17
|
```bash
|
|
18
18
|
unique-cli subagent "<tool_name>" "<message>" \
|
|
19
19
|
--chat-id "$UNIQUE_CHAT_ID" \
|
|
20
|
-
--message-id "$UNIQUE_MESSAGE_ID" \
|
|
21
20
|
--assistant-id "$UNIQUE_ASSISTANT_ID"
|
|
22
21
|
```
|
|
23
22
|
|
|
23
|
+
Omit `--message-id`: the CLI resolves the current turn's assistant message ID
|
|
24
|
+
from `$UNIQUE_TURN_IDENTITY_FILE` automatically.
|
|
25
|
+
|
|
24
26
|
## Rules
|
|
25
27
|
|
|
26
28
|
1. Use the exact tool name from the connected-space skill or from
|
|
@@ -49,7 +51,7 @@ The platform sets these environment variables automatically:
|
|
|
49
51
|
UNIQUE_USER_ID
|
|
50
52
|
UNIQUE_COMPANY_ID
|
|
51
53
|
UNIQUE_CHAT_ID
|
|
52
|
-
|
|
54
|
+
UNIQUE_TURN_IDENTITY_FILE
|
|
53
55
|
UNIQUE_ASSISTANT_ID
|
|
54
56
|
UNIQUE_API_KEY
|
|
55
57
|
UNIQUE_APP_ID
|
|
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.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/__init__.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_acronyms.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_agentic_table.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_analytics_order.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_benchmarking.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_briefing.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_chat_completion.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_content.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_elicitation.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_embedding.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_integrated.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_llm_models.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_log.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_message_tool.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/api_resources/_scheduled_task.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.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.30.0.dev6 → unique_sdk-2026.30.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
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/cite_file.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/dynamic_frontend.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/elicitation.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/navigation.py
RENAMED
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/scheduled_tasks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/cli/commands/web_search.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.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
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/unique_sdk/utils/analytics_order_run.py
RENAMED
|
File without changes
|
{unique_sdk-2026.30.0.dev6 → unique_sdk-2026.30.0.dev7}/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
|