unique-sdk 2026.30.0.dev7__tar.gz → 2026.30.0.dev9__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/PKG-INFO +1 -1
  2. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/pyproject.toml +1 -1
  3. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/identity.py +5 -43
  4. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/chat_in_space.py +29 -4
  5. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/README.md +0 -0
  6. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/__init__.py +0 -0
  7. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_api_requestor.py +0 -0
  8. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_api_resource.py +0 -0
  9. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_api_version.py +0 -0
  10. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_error.py +0 -0
  11. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_http_client.py +0 -0
  12. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_list_object.py +0 -0
  13. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_object_classes.py +0 -0
  14. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_request_options.py +0 -0
  15. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_unique_object.py +0 -0
  16. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_unique_ql.py +0 -0
  17. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_unique_response.py +0 -0
  18. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_util.py +0 -0
  19. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_version.py +0 -0
  20. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/_webhook.py +0 -0
  21. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/__init__.py +0 -0
  22. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_acronyms.py +0 -0
  23. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_agentic_table.py +0 -0
  24. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_analytics_order.py +0 -0
  25. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_benchmarking.py +0 -0
  26. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_briefing.py +0 -0
  27. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_chat_completion.py +0 -0
  28. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_content.py +0 -0
  29. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_dynamic_frontend.py +0 -0
  30. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_elicitation.py +0 -0
  31. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_embedding.py +0 -0
  32. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_event.py +0 -0
  33. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_folder.py +0 -0
  34. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_group.py +0 -0
  35. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_integrated.py +0 -0
  36. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_llm_models.py +0 -0
  37. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_mcp.py +0 -0
  38. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_message.py +0 -0
  39. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_message_assessment.py +0 -0
  40. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_message_execution.py +0 -0
  41. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_message_log.py +0 -0
  42. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_message_tool.py +0 -0
  43. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_module.py +0 -0
  44. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_scheduled_task.py +0 -0
  45. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_search.py +0 -0
  46. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_search_string.py +0 -0
  47. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  48. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_space.py +0 -0
  49. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_user.py +0 -0
  50. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/api_resources/_web_search.py +0 -0
  51. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/__init__.py +0 -0
  52. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/__main__.py +0 -0
  53. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/cli.py +0 -0
  54. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/__init__.py +0 -0
  55. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
  56. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/browser.py +0 -0
  57. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/cite_file.py +0 -0
  58. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/dynamic_frontend.py +0 -0
  59. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/elicitation.py +0 -0
  60. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/files.py +0 -0
  61. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/folders.py +0 -0
  62. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/mcp.py +0 -0
  63. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/navigation.py +0 -0
  64. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/read.py +0 -0
  65. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/scheduled_tasks.py +0 -0
  66. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/search.py +0 -0
  67. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/subagent.py +0 -0
  68. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/web_search.py +0 -0
  69. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/commands/web_search_config.py +0 -0
  70. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/config.py +0 -0
  71. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/formatting.py +0 -0
  72. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/metadata_filter.py +0 -0
  73. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/shell.py +0 -0
  74. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-dynamic-frontend/SKILL.md +0 -0
  75. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
  76. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
  77. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
  78. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +0 -0
  79. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
  80. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
  81. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
  82. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
  83. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/cli/state.py +0 -0
  84. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/analytics_order_run.py +0 -0
  85. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/benchmarking_run.py +0 -0
  86. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/chat_history.py +0 -0
  87. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/file_io.py +0 -0
  88. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/sources.py +0 -0
  89. {unique_sdk-2026.30.0.dev7 → unique_sdk-2026.30.0.dev9}/unique_sdk/utils/token.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: unique-sdk
3
- Version: 2026.30.0.dev7
3
+ Version: 2026.30.0.dev9
4
4
  Summary:
5
5
  Author: Martin Fadler, Konstantin Krauss, Andreas Hauri
6
6
  Author-email: Martin Fadler <martin.fadler@unique.ch>, Konstantin Krauss <konstantin@unique.ch>, Andreas Hauri <andreas@unique.ch>
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "unique_sdk"
3
- version = "2026.30.0.dev7"
3
+ version = "2026.30.0.dev9"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -25,7 +25,6 @@ from pathlib import Path
25
25
 
26
26
  TURN_IDENTITY_ENV_VAR = "UNIQUE_TURN_IDENTITY_FILE"
27
27
  MESSAGE_ID_ENV_VAR = "UNIQUE_MESSAGE_ID"
28
- CHAT_ID_ENV_VAR = "UNIQUE_CHAT_ID"
29
28
 
30
29
 
31
30
  class TurnIdentityError(ValueError):
@@ -36,23 +35,13 @@ class TurnIdentityError(ValueError):
36
35
  class TurnIdentity:
37
36
  """Parsed contents of the per-turn identity file.
38
37
 
39
- Mirrors the JSON contract written by the platform runner. Only
40
- ``message_id`` is mandatory; the remaining fields are informational.
38
+ The runner writes a richer JSON object (chat/user/company/assistant IDs,
39
+ turn counter), but the CLI only consumes ``message_id`` — the one value
40
+ that goes stale in a persistent process environment. Extra keys are
41
+ ignored; parse a field here only once the CLI actually relies on it.
41
42
  """
42
43
 
43
44
  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
45
 
57
46
 
58
47
  def read_turn_identity(
@@ -99,15 +88,7 @@ def read_turn_identity(
99
88
  "'message_id' string"
100
89
  )
101
90
 
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
- )
91
+ return TurnIdentity(message_id=message_id.strip())
111
92
 
112
93
 
113
94
  def resolve_message_id(explicit: str | None = None) -> str | None:
@@ -129,22 +110,3 @@ def resolve_message_id(explicit: str | None = None) -> str | None:
129
110
  if env_id is not None and env_id.strip():
130
111
  return env_id.strip()
131
112
  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
@@ -1,3 +1,5 @@
1
+ from __future__ import annotations
2
+
1
3
  import asyncio
2
4
  import warnings
3
5
  from collections.abc import Awaitable, Callable, Sequence
@@ -11,6 +13,17 @@ from unique_sdk.utils.file_io import (
11
13
  )
12
14
 
13
15
 
16
+ def get_message_invocations(message: Space.Message) -> list[dict[str, Any]]:
17
+ """Per-LLM-invocation stats for a completed Space message, read from
18
+ `debugInfo.llm_invocations` (a plain list, one entry per LLM call).
19
+
20
+ Each entry has `modelName`, `tokenUsage`, and `source` keys.
21
+ """
22
+ debug_info = message.get("debugInfo") or {}
23
+ llm_invocations = debug_info.get("llm_invocations")
24
+ return llm_invocations if isinstance(llm_invocations, list) else []
25
+
26
+
14
27
  async def send_message_and_wait_for_completion(
15
28
  user_id: str,
16
29
  company_id: str,
@@ -23,10 +36,10 @@ async def send_message_and_wait_for_completion(
23
36
  poll_interval: float = 1.0,
24
37
  max_wait: float = 60.0,
25
38
  stop_condition: Literal["stoppedStreamingAt", "completedAt"] = "stoppedStreamingAt",
26
- correlation: "Space.Correlation | None" = None,
39
+ correlation: Space.Correlation | None = None,
27
40
  auto_approve_elicitation: bool | None = None,
28
- on_message_update: Callable[["Space.Message"], Awaitable[None]] | None = None,
29
- ) -> "Space.Message":
41
+ on_message_update: Callable[[Space.Message], Awaitable[None]] | None = None,
42
+ ) -> Space.Message:
30
43
  """
31
44
  Sends a prompt asynchronously and polls for completion. (until stoppedStreamingAt is not None)
32
45
 
@@ -42,6 +55,13 @@ async def send_message_and_wait_for_completion(
42
55
  poll_interval: Seconds between polls.
43
56
  max_wait: Maximum seconds to wait for completion.
44
57
  stop_condition: Defines when to expect a response back, when the assistant stop streaming or when it completes the message. (default: "stoppedStreamingAt")
58
+ Note: `debugInfo.llm_invocations` (see `get_message_invocations`) is written
59
+ near the very end of the orchestrator's run -- after postprocessors and
60
+ evaluations, which happen after the visible text stream ends. With the default
61
+ `"stoppedStreamingAt"`, or even `"completedAt"` (set slightly before the debugInfo
62
+ write completes), the returned message's invocations can still be incomplete
63
+ immediately after this function returns. Re-fetch the message after a short delay
64
+ if you need the full invocation list.
45
65
  correlation: Optional correlation data to link this message to a parent message in another chat.
46
66
  Should contain: parentMessageId, parentChatId, parentAssistantId.
47
67
  auto_approve_elicitation: When True, automatically approves elicitation requests during
@@ -91,6 +111,11 @@ async def send_message_and_wait_for_completion(
91
111
  last_update_signature = update_signature
92
112
  if answer.get(stop_condition) is not None:
93
113
  try:
114
+ # debugInfo/llm_invocations is written via update_debug_info_async(),
115
+ # which always targets the original USER message, not the
116
+ # assistant reply (assistant=False in
117
+ # ChatService._construct_message_modify_params) — re-fetch by
118
+ # `message_id`, not the polled assistant message's own id.
94
119
  user_message = await Message.retrieve_async(
95
120
  user_id, company_id, message_id, chatId=chat_id
96
121
  )
@@ -116,7 +141,7 @@ async def chat_against_file(
116
141
  poll_interval: float = 1.0,
117
142
  max_wait: float = 60.0,
118
143
  should_delete_chat: bool = True,
119
- ) -> "Space.Message":
144
+ ) -> Space.Message:
120
145
  """
121
146
  Chat against a file by uploading it, sending a message and waiting for a reply.
122
147
  Args: