unique-sdk 2026.32.0.dev4__tar.gz → 2026.32.0.dev6__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/PKG-INFO +1 -1
  2. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/pyproject.toml +1 -1
  3. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_space.py +1 -0
  4. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/cli.py +2 -1
  5. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/shell.py +4 -7
  6. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +13 -14
  7. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/chat_in_space.py +20 -0
  8. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/README.md +0 -0
  9. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/__init__.py +0 -0
  10. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_api_requestor.py +0 -0
  11. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_api_resource.py +0 -0
  12. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_api_version.py +0 -0
  13. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_error.py +0 -0
  14. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_http_client.py +0 -0
  15. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_list_object.py +0 -0
  16. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_object_classes.py +0 -0
  17. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_request_options.py +0 -0
  18. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_unique_object.py +0 -0
  19. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_unique_ql.py +0 -0
  20. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_unique_response.py +0 -0
  21. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_util.py +0 -0
  22. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_version.py +0 -0
  23. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/_webhook.py +0 -0
  24. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/__init__.py +0 -0
  25. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_acronyms.py +0 -0
  26. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_agentic_table.py +0 -0
  27. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_analytics_order.py +0 -0
  28. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_benchmarking.py +0 -0
  29. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_briefing.py +0 -0
  30. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_chat_completion.py +0 -0
  31. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_content.py +0 -0
  32. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_dynamic_frontend.py +0 -0
  33. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_elicitation.py +0 -0
  34. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_embedding.py +0 -0
  35. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_event.py +0 -0
  36. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_folder.py +0 -0
  37. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_group.py +0 -0
  38. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_integrated.py +0 -0
  39. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_llm_models.py +0 -0
  40. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_mcp.py +0 -0
  41. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_message.py +0 -0
  42. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_message_assessment.py +0 -0
  43. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_message_execution.py +0 -0
  44. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_message_log.py +0 -0
  45. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_message_tool.py +0 -0
  46. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_module.py +0 -0
  47. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_scheduled_task.py +0 -0
  48. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_search.py +0 -0
  49. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_search_string.py +0 -0
  50. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  51. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_user.py +0 -0
  52. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/api_resources/_web_search.py +0 -0
  53. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/__init__.py +0 -0
  54. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/__main__.py +0 -0
  55. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/__init__.py +0 -0
  56. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
  57. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/agentic_table.py +0 -0
  58. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/browser.py +0 -0
  59. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/cite_file.py +0 -0
  60. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/dynamic_frontend.py +0 -0
  61. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/elicitation.py +0 -0
  62. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/files.py +0 -0
  63. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/folders.py +0 -0
  64. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/mcp.py +0 -0
  65. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/navigation.py +0 -0
  66. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/read.py +0 -0
  67. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
  68. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/search.py +0 -0
  69. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/subagent.py +0 -0
  70. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/web_search.py +0 -0
  71. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/commands/web_search_config.py +0 -0
  72. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/config.py +0 -0
  73. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/formatting.py +0 -0
  74. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/identity.py +0 -0
  75. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/metadata_filter.py +0 -0
  76. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
  77. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-dynamic-frontend/SKILL.md +0 -0
  78. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
  79. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
  80. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
  81. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
  82. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
  83. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
  84. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
  85. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/cli/state.py +0 -0
  86. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/analytics_order_run.py +0 -0
  87. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/benchmarking_run.py +0 -0
  88. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/chat_history.py +0 -0
  89. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/file_io.py +0 -0
  90. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/sources.py +0 -0
  91. {unique_sdk-2026.32.0.dev4 → unique_sdk-2026.32.0.dev6}/unique_sdk/utils/token.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-sdk
3
- Version: 2026.32.0.dev4
3
+ Version: 2026.32.0.dev6
4
4
  Summary:
5
5
  Author: Martin Fadler, Konstantin Krauss, Andreas Hauri
6
6
  Author-email: Martin Fadler <martin.fadler@unique.ch>, Konstantin Krauss <konstantin@unique.ch>, Andreas Hauri <andreas@unique.ch>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique_sdk"
3
- version = "2026.32.0.dev4"
3
+ version = "2026.32.0.dev6"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -213,6 +213,7 @@ class Space(APIResource["Space"]):
213
213
  stoppedStreamingAt: str | None
214
214
  references: list["Space.Reference"] | None
215
215
  assessment: list["Space.Assessment"] | None
216
+ triggeringUserMessageId: NotRequired[str]
216
217
 
217
218
  class DeleteChatResponse(TypedDict):
218
219
  """
@@ -1373,7 +1373,8 @@ def elicit_ask(
1373
1373
  @click.option(
1374
1374
  "--mode",
1375
1375
  type=click.Choice(["FORM", "URL"], case_sensitive=False),
1376
- required=True,
1376
+ default="FORM",
1377
+ show_default=True,
1377
1378
  help="Elicitation display mode.",
1378
1379
  )
1379
1380
  @click.option(
@@ -97,7 +97,7 @@ OVERVIEW_HELP = textwrap.dedent("""\
97
97
  --placeholder-text <text> Text on the placeholder thinking step
98
98
  --cleanup collapse|delete How to tear down the placeholder
99
99
  elicit create <message> [opts] Fire-and-forget create
100
- --mode FORM|URL Display mode (required)
100
+ --mode FORM|URL Display mode (default: FORM)
101
101
  --tool-name / -t <name> Tool label (required)
102
102
  --schema <json> JSON schema (FORM mode)
103
103
  --url <url> External URL (URL mode)
@@ -811,7 +811,7 @@ class UniqueShell(cmd.Cmd):
811
811
  --tool-name / -t <name> Tool label shown in the UI
812
812
  --schema <json> JSON schema for form fields
813
813
  --url <url> External URL (create with --mode URL)
814
- --mode FORM|URL Display mode (create only, required)
814
+ --mode FORM|URL Display mode (create only, default: FORM)
815
815
  --chat-id / -c <id> Associated chat ID
816
816
  --message-id / -m <id> Associated message ID
817
817
  --expires-in <seconds> Auto-expire the request (create only)
@@ -1033,18 +1033,15 @@ class UniqueShell(cmd.Cmd):
1033
1033
  message = opts["message"]
1034
1034
  if not message:
1035
1035
  self._print(
1036
- "Usage: elicit create <message> --mode FORM|URL --tool-name <name> [options]"
1036
+ "Usage: elicit create <message> [--mode FORM|URL] --tool-name <name> [options]"
1037
1037
  )
1038
1038
  return
1039
- if not opts["mode"]:
1040
- self._print("Error: --mode is required (FORM or URL).")
1041
- return
1042
1039
  if not opts["tool_name"]:
1043
1040
  self._print("Error: --tool-name / -t is required.")
1044
1041
  return
1045
1042
 
1046
1043
  create_kwargs: dict[str, Any] = {
1047
- "mode": opts["mode"],
1044
+ "mode": opts["mode"] or "FORM",
1048
1045
  "message": message,
1049
1046
  "tool_name": opts["tool_name"],
1050
1047
  "schema": opts["schema"],
@@ -161,22 +161,19 @@ unique-cli elicit ask "Which report format do you want?" \
161
161
 
162
162
  Always use this before `rm`, `rmdir -r`, mass uploads, or anything irreversible.
163
163
 
164
+ Use an **empty-properties schema** — the UI's Confirm/Cancel buttons ARE the
165
+ consent. Do **not** add a boolean `confirm` field: the button and the checkbox
166
+ are two separate signals, and a user who presses Confirm with the box unchecked
167
+ would show as **Accepted** in the UI while you would read `confirm: false` and
168
+ wrongly treat it as declined.
169
+
164
170
  ```bash
165
- unique-cli elicit ask "Confirm deleting /Archive/2024 and everything inside it" \
171
+ unique-cli elicit ask "Permanently delete /Archive/2024 and everything inside it? Confirming deletes it immediately — this cannot be undone." \
166
172
  --chat-id "$UNIQUE_CHAT_ID" \
167
- --schema '{
168
- "type": "object",
169
- "properties": {
170
- "confirm": {
171
- "type": "boolean",
172
- "description": "Tick to permanently delete"
173
- }
174
- },
175
- "required": ["confirm"]
176
- }'
173
+ --schema '{"type": "object", "properties": {}}'
177
174
  ```
178
175
 
179
- Proceed **only** if the response contains `"confirm": true`. Treat `DECLINED`, `CANCELLED`, `EXPIRED`, or `confirm: false` all as "do not proceed" -- tell the user you stopped and return control.
176
+ Proceed **only** if the `Status:` is `ACCEPTED`. Treat `DECLINED`, `CANCELLED`, or `EXPIRED` all as "do not proceed" -- tell the user you stopped and return control. Put everything the user needs to decide into the message text, since the form has no fields.
180
177
 
181
178
  ### Structured form (multiple fields)
182
179
 
@@ -201,7 +198,9 @@ The table below documents `elicit ask`'s flags. `elicit create` takes the
201
198
  same `--chat-id`, `--message-id`, `--tool-name`, `--schema`, `--metadata`,
202
199
  and `--assistant-id` flags, but uses `--expires-in <seconds>` instead of
203
200
  `--timeout`/`--poll-interval` (those two apply only to `elicit wait`, which
204
- you call separately in the polling pattern).
201
+ you call separately in the polling pattern). `elicit create` also takes
202
+ `--mode FORM|URL` (default: `FORM` — you only need to pass it for URL
203
+ elicitations).
205
204
 
206
205
  | Option | Short | Default | Description |
207
206
  |--------|-------|---------|-------------|
@@ -296,7 +295,7 @@ esac
296
295
 
297
296
  - Always set `"required"` for fields you actually need -- this guarantees the user cannot submit an empty form.
298
297
  - Use `enum` for closed choices so the UI can render a selector.
299
- - Use `"type": "boolean"` for confirmations; treat `true` as "go ahead", everything else as "stop".
298
+ - For pure yes/no confirmations use an **empty-properties schema** (`{"type": "object", "properties": {}}`) and gate on `Status: ACCEPTED` — never add a boolean `confirm` field (the Confirm button and the checkbox are two separate signals that can disagree). Reserve `"type": "boolean"` for genuine data fields where `false` is a valid answer the user can still submit with Confirm (e.g. `include_appendix`).
300
299
  - Add short `description` strings -- they are shown as help text next to each field.
301
300
  - Keep schemas small. Ask at most 5 questions in a single elicitation; if you need more, split the flow so the user is not confused by an oversized form.
302
301
 
@@ -39,6 +39,7 @@ async def send_message_and_wait_for_completion(
39
39
  correlation: Space.Correlation | None = None,
40
40
  auto_approve_elicitation: bool | None = None,
41
41
  on_message_update: Callable[[Space.Message], Awaitable[None]] | None = None,
42
+ wait_for_invocations: bool = False,
42
43
  ) -> Space.Message:
43
44
  """
44
45
  Sends a prompt asynchronously and polls for completion. (until stoppedStreamingAt is not None)
@@ -68,6 +69,8 @@ async def send_message_and_wait_for_completion(
68
69
  the assistant run. Use for non-interactive automation where no user is present.
69
70
  on_message_update: Optional async callback called whenever the latest assistant
70
71
  message changes while waiting for completion.
72
+ wait_for_invocations: When True, briefly wait for the orchestrator's final
73
+ ``debugInfo.llm_invocations`` write after the visible response completes.
71
74
 
72
75
  Returns:
73
76
  The completed Space.Message.
@@ -94,7 +97,15 @@ async def send_message_and_wait_for_completion(
94
97
  message_id = response.get("id")
95
98
 
96
99
  max_attempts = int(max_wait // poll_interval)
100
+ # The final up-to-3 polls spent waiting for `llm_invocations_complete`
101
+ # happen after the stop condition is already met, so they must not eat
102
+ # into the same budget as the wait for the stop condition itself --
103
+ # otherwise a response that completes near the max_wait deadline would
104
+ # spuriously time out while only debugInfo bookkeeping is still pending.
105
+ if wait_for_invocations:
106
+ max_attempts += 3
97
107
  last_update_signature: tuple[str | None, str | None] | None = None
108
+ invocation_wait_attempts = 0
98
109
  for _ in range(max_attempts):
99
110
  answer = await Space.get_latest_message_async(user_id, company_id, chat_id)
100
111
  if (
@@ -121,6 +132,15 @@ async def send_message_and_wait_for_completion(
121
132
  )
122
133
  debug_info = user_message.get("debugInfo")
123
134
  answer["debugInfo"] = debug_info
135
+ answer["triggeringUserMessageId"] = message_id
136
+ if (
137
+ wait_for_invocations
138
+ and not (debug_info or {}).get("llm_invocations_complete", False)
139
+ and invocation_wait_attempts < 3
140
+ ):
141
+ invocation_wait_attempts += 1
142
+ await asyncio.sleep(poll_interval)
143
+ continue
124
144
  except Exception as e:
125
145
  print(f"Failed to load debug info from user message: {e}")
126
146