unique-sdk 2026.40.0.dev3__tar.gz → 2026.40.0.dev5__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.40.0.dev3 → unique_sdk-2026.40.0.dev5}/PKG-INFO +1 -1
  2. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/pyproject.toml +1 -1
  3. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_scheduled_task.py +3 -0
  4. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_space.py +54 -0
  5. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/cli.py +18 -1
  6. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/scheduled_tasks.py +7 -0
  7. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/formatting.py +5 -2
  8. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/shell.py +14 -2
  9. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-scheduled-tasks/SKILL.md +52 -8
  10. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/README.md +0 -0
  11. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/__init__.py +0 -0
  12. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_api_requestor.py +0 -0
  13. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_api_resource.py +0 -0
  14. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_api_version.py +0 -0
  15. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_error.py +0 -0
  16. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_http_client.py +0 -0
  17. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_list_object.py +0 -0
  18. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_object_classes.py +0 -0
  19. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_request_options.py +0 -0
  20. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_unique_object.py +0 -0
  21. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_unique_ql.py +0 -0
  22. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_unique_response.py +0 -0
  23. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_util.py +0 -0
  24. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_version.py +0 -0
  25. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/_webhook.py +0 -0
  26. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/__init__.py +0 -0
  27. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_acronyms.py +0 -0
  28. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_agentic_table.py +0 -0
  29. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_analytics_order.py +0 -0
  30. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_benchmarking.py +0 -0
  31. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_briefing.py +0 -0
  32. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_chat_completion.py +0 -0
  33. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_content.py +0 -0
  34. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_context_memory.py +0 -0
  35. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_elicitation.py +0 -0
  36. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_embedding.py +0 -0
  37. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_event.py +0 -0
  38. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_folder.py +0 -0
  39. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_group.py +0 -0
  40. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_integrated.py +0 -0
  41. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_llm_models.py +0 -0
  42. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_mcp.py +0 -0
  43. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_message.py +0 -0
  44. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_message_assessment.py +0 -0
  45. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_message_execution.py +0 -0
  46. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_message_log.py +0 -0
  47. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_message_tool.py +0 -0
  48. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_module.py +0 -0
  49. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_search.py +0 -0
  50. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_search_string.py +0 -0
  51. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_short_term_memory.py +0 -0
  52. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_user.py +0 -0
  53. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/api_resources/_web_search.py +0 -0
  54. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/__init__.py +0 -0
  55. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/__main__.py +0 -0
  56. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/__init__.py +0 -0
  57. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/_citation_manifest.py +0 -0
  58. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/agentic_table.py +0 -0
  59. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/agentic_table_write.py +0 -0
  60. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/browser.py +0 -0
  61. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/cite_file.py +0 -0
  62. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/elicitation.py +0 -0
  63. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/files.py +0 -0
  64. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/folders.py +0 -0
  65. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/mcp.py +0 -0
  66. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/navigation.py +0 -0
  67. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/read.py +0 -0
  68. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/search.py +0 -0
  69. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/subagent.py +0 -0
  70. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/web_search.py +0 -0
  71. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/commands/web_search_config.py +0 -0
  72. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/config.py +0 -0
  73. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/identity.py +0 -0
  74. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/metadata_filter.py +0 -0
  75. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-agentic-table/SKILL.md +0 -0
  76. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-elicitation/SKILL.md +0 -0
  77. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-file-management/SKILL.md +0 -0
  78. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-mcp/SKILL.md +0 -0
  79. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-search/SKILL.md +0 -0
  80. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-subagent/SKILL.md +0 -0
  81. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-uploaded-search/SKILL.md +0 -0
  82. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/skills/unique-cli-web-search/SKILL.md +0 -0
  83. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/state.py +0 -0
  84. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/cli/workspace.py +0 -0
  85. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/analytics_order_run.py +0 -0
  86. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/benchmarking_run.py +0 -0
  87. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/chat_history.py +0 -0
  88. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/chat_in_space.py +0 -0
  89. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/file_io.py +0 -0
  90. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/unique_sdk/utils/sources.py +0 -0
  91. {unique_sdk-2026.40.0.dev3 → unique_sdk-2026.40.0.dev5}/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.40.0.dev3
3
+ Version: 2026.40.0.dev5
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.40.0.dev3"
3
+ version = "2026.40.0.dev5"
4
4
  description = ""
5
5
  readme = "README.md"
6
6
  license = { text = "MIT" }
@@ -32,6 +32,7 @@ class ScheduledTask(APIResource["ScheduledTask"]):
32
32
  cronExpression: str
33
33
  assistantId: str
34
34
  prompt: str
35
+ name: NotRequired[str]
35
36
  chatId: NotRequired[str | None]
36
37
  enabled: NotRequired[bool]
37
38
 
@@ -39,6 +40,7 @@ class ScheduledTask(APIResource["ScheduledTask"]):
39
40
  cronExpression: NotRequired[str]
40
41
  assistantId: NotRequired[str]
41
42
  prompt: NotRequired[str]
43
+ name: NotRequired[str | None]
42
44
  chatId: NotRequired[str | None]
43
45
  enabled: NotRequired[bool]
44
46
 
@@ -51,6 +53,7 @@ class ScheduledTask(APIResource["ScheduledTask"]):
51
53
 
52
54
  id: str
53
55
  object: str
56
+ name: str | None
54
57
  cronExpression: str
55
58
  assistantId: str
56
59
  assistantName: str | None
@@ -238,6 +238,16 @@ class Space(APIResource["Space"]):
238
238
  title: str
239
239
  assistantId: str
240
240
 
241
+ class UpdateChatParams(RequestOptions):
242
+ """
243
+ Parameters for renaming a chat.
244
+
245
+ Attributes:
246
+ title: New chat title. Must be a non-empty string.
247
+ """
248
+
249
+ title: str
250
+
241
251
  class ChatResult(TypedDict):
242
252
  id: str
243
253
  title: str | None
@@ -434,6 +444,50 @@ class Space(APIResource["Space"]):
434
444
  ),
435
445
  )
436
446
 
447
+ @classmethod
448
+ def update_chat(
449
+ cls,
450
+ user_id: str,
451
+ company_id: str,
452
+ chat_id: str,
453
+ **params: Unpack["Space.UpdateChatParams"],
454
+ ) -> "Space.ChatResult":
455
+ """
456
+ Rename a chat in a space.
457
+ """
458
+ return cast(
459
+ "Space.ChatResult",
460
+ cls._static_request(
461
+ "patch",
462
+ f"/space/chat/{chat_id}",
463
+ user_id,
464
+ company_id,
465
+ params=params,
466
+ ),
467
+ )
468
+
469
+ @classmethod
470
+ async def update_chat_async(
471
+ cls,
472
+ user_id: str,
473
+ company_id: str,
474
+ chat_id: str,
475
+ **params: Unpack["Space.UpdateChatParams"],
476
+ ) -> "Space.ChatResult":
477
+ """
478
+ Async rename a chat in a space.
479
+ """
480
+ return cast(
481
+ "Space.ChatResult",
482
+ await cls._static_request_async(
483
+ "patch",
484
+ f"/space/chat/{chat_id}",
485
+ user_id,
486
+ company_id,
487
+ params=params,
488
+ ),
489
+ )
490
+
437
491
  @classmethod
438
492
  def get_chat_messages(
439
493
  cls,
@@ -1022,6 +1022,12 @@ def schedule_get(ctx: click.Context, task_id: str) -> None:
1022
1022
  required=True,
1023
1023
  help="Prompt text sent to the assistant on each trigger.",
1024
1024
  )
1025
+ @click.option(
1026
+ "--name",
1027
+ "-n",
1028
+ default=None,
1029
+ help="Short label for the task, shown in the UI. Falls back to the prompt if omitted.",
1030
+ )
1025
1031
  @click.option(
1026
1032
  "--chat-id",
1027
1033
  default=None,
@@ -1039,6 +1045,7 @@ def schedule_create(
1039
1045
  cron: str,
1040
1046
  assistant_id: str,
1041
1047
  prompt: str,
1048
+ name: str | None,
1042
1049
  chat_id: str | None,
1043
1050
  disabled: bool,
1044
1051
  ) -> None:
@@ -1058,7 +1065,8 @@ def schedule_create(
1058
1065
  unique-cli schedule create \\
1059
1066
  --cron "0 9 * * 1-5" \\
1060
1067
  --assistant clx1abc2d0001abcdef123456 \\
1061
- --prompt "Generate the daily sales report"
1068
+ --prompt "Generate the daily sales report" \\
1069
+ --name "Daily sales report"
1062
1070
 
1063
1071
  unique-cli schedule create \\
1064
1072
  -c "*/15 * * * *" -a clx1abc -p "Check inbox" --disabled
@@ -1068,6 +1076,7 @@ def schedule_create(
1068
1076
  cron=cron,
1069
1077
  assistant_id=assistant_id,
1070
1078
  prompt=prompt,
1079
+ name=name,
1071
1080
  chat_id=chat_id,
1072
1081
  enabled=not disabled,
1073
1082
  )
@@ -1083,6 +1092,7 @@ def schedule_create(
1083
1092
  "--assistant", "-a", "assistant_id", default=None, help="Updated assistant ID."
1084
1093
  )
1085
1094
  @click.option("--prompt", "-p", default=None, help="Updated prompt text.")
1095
+ @click.option("--name", "-n", default=None, help="Updated label (use 'none' to clear).")
1086
1096
  @click.option("--chat-id", default=None, help="Updated chat ID (use 'none' to clear).")
1087
1097
  @click.option("--enable", is_flag=True, default=False, help="Enable the task.")
1088
1098
  @click.option("--disable", is_flag=True, default=False, help="Disable the task.")
@@ -1093,6 +1103,7 @@ def schedule_update(
1093
1103
  cron: str | None,
1094
1104
  assistant_id: str | None,
1095
1105
  prompt: str | None,
1106
+ name: str | None,
1096
1107
  chat_id: str | None,
1097
1108
  enable: bool,
1098
1109
  disable: bool,
@@ -1109,6 +1120,7 @@ def schedule_update(
1109
1120
  unique-cli schedule update clx3ghi4f --disable
1110
1121
  unique-cli schedule update clx3ghi4f --enable --prompt "New prompt"
1111
1122
  unique-cli schedule update clx3ghi4f --chat-id none
1123
+ unique-cli schedule update clx3ghi4f --name "Monthly summary"
1112
1124
  """
1113
1125
  if enable and disable:
1114
1126
  click.echo(
@@ -1126,12 +1138,17 @@ def schedule_update(
1126
1138
  if chat_id and chat_id.lower() == "none":
1127
1139
  resolved_chat_id = ""
1128
1140
 
1141
+ resolved_name = name
1142
+ if name and name.lower() == "none":
1143
+ resolved_name = ""
1144
+
1129
1145
  output = cmd_schedule_update(
1130
1146
  LazyState.get(ctx),
1131
1147
  task_id,
1132
1148
  cron=cron,
1133
1149
  assistant_id=assistant_id,
1134
1150
  prompt=prompt,
1151
+ name=resolved_name,
1135
1152
  chat_id=resolved_chat_id,
1136
1153
  enabled=enabled,
1137
1154
  )
@@ -47,6 +47,7 @@ def cmd_schedule_create(
47
47
  assistant_id: str,
48
48
  prompt: str,
49
49
  *,
50
+ name: str | None = None,
50
51
  chat_id: str | None = None,
51
52
  enabled: bool = True,
52
53
  ) -> str:
@@ -58,6 +59,8 @@ def cmd_schedule_create(
58
59
  "prompt": prompt,
59
60
  "enabled": enabled,
60
61
  }
62
+ if name is not None:
63
+ params["name"] = name
61
64
  if chat_id is not None:
62
65
  params["chatId"] = chat_id
63
66
 
@@ -79,6 +82,7 @@ def cmd_schedule_update(
79
82
  cron: str | None = None,
80
83
  assistant_id: str | None = None,
81
84
  prompt: str | None = None,
85
+ name: str | None = None,
82
86
  chat_id: str | None = None,
83
87
  enabled: bool | None = None,
84
88
  ) -> str:
@@ -91,6 +95,9 @@ def cmd_schedule_update(
91
95
  params["assistantId"] = assistant_id
92
96
  if prompt is not None:
93
97
  params["prompt"] = prompt
98
+ # Empty string is the caller's "clear it" sentinel, sent to the API as null.
99
+ if name is not None:
100
+ params["name"] = name if name != "" else None
94
101
  if chat_id is not None:
95
102
  params["chatId"] = chat_id if chat_id != "" else None
96
103
  if enabled is not None:
@@ -160,6 +160,7 @@ def format_scheduled_task(task: ScheduledTask) -> str:
160
160
  enabled_str = "yes" if getattr(task, "enabled", False) else "no"
161
161
  rows = [
162
162
  ["ID:", getattr(task, "id", "?")],
163
+ ["Name:", getattr(task, "name", None) or "(falls back to prompt)"],
163
164
  ["Cron:", getattr(task, "cronExpression", "?")],
164
165
  [
165
166
  "Assistant:",
@@ -191,10 +192,12 @@ def format_scheduled_tasks(tasks: list[ScheduledTask]) -> str:
191
192
  snippet = prompt[:60].replace("\n", " ").strip()
192
193
  if len(prompt) > 60:
193
194
  snippet += "..."
195
+ # Mirrors the web UI: an unnamed task is identified by its prompt snippet.
196
+ label = getattr(t, "name", None) or snippet
194
197
  last_run = _format_date(getattr(t, "lastRunAt", None))
195
- rows.append([enabled, cron, assistant, snippet, task_id, last_run])
198
+ rows.append([enabled, label, cron, assistant, snippet, task_id, last_run])
196
199
 
197
- header = ["STATUS", "CRON", "ASSISTANT", "PROMPT", "ID", "LAST RUN"]
200
+ header = ["STATUS", "NAME", "CRON", "ASSISTANT", "PROMPT", "ID", "LAST RUN"]
198
201
  lines = [f"{len(tasks)} scheduled task(s):\n"]
199
202
  all_rows = [header] + rows
200
203
  lines.extend(_pad_columns(all_rows))
@@ -1109,6 +1109,7 @@ class UniqueShell(cmd.Cmd):
1109
1109
  --cron / -c <expr> Cron expression (required)
1110
1110
  --assistant / -a <id> Assistant ID (required)
1111
1111
  --prompt / -p <text> Prompt text (required)
1112
+ --name / -n <text> Short label shown in the UI (optional)
1112
1113
  --chat-id <id> Chat to continue (optional)
1113
1114
  --disabled Create in disabled state
1114
1115
 
@@ -1116,6 +1117,7 @@ class UniqueShell(cmd.Cmd):
1116
1117
  --cron / -c <expr> Updated cron expression
1117
1118
  --assistant / -a <id> Updated assistant ID
1118
1119
  --prompt / -p <text> Updated prompt
1120
+ --name / -n <text> Updated label ('none' to clear)
1119
1121
  --chat-id <id> Updated chat ID ('none' to clear)
1120
1122
  --enable Enable the task
1121
1123
  --disable Disable the task
@@ -1123,7 +1125,7 @@ class UniqueShell(cmd.Cmd):
1123
1125
  Examples:
1124
1126
  /> schedule list
1125
1127
  /> schedule get clx3ghi4f0003mnopqr345678
1126
- /> schedule create -c "0 9 * * 1-5" -a clx1abc -p "Daily report"
1128
+ /> schedule create -c "0 9 * * 1-5" -a clx1abc -p "Daily report" -n "Daily report"
1127
1129
  /> schedule update clx3ghi4f --disable
1128
1130
  /> schedule delete clx3ghi4f0003mnopqr345678
1129
1131
  """
@@ -1173,6 +1175,7 @@ class UniqueShell(cmd.Cmd):
1173
1175
  cron: str | None = None
1174
1176
  assistant_id: str | None = None
1175
1177
  prompt: str | None = None
1178
+ name: str | None = None
1176
1179
  chat_id: str | None = None
1177
1180
  disabled = False
1178
1181
 
@@ -1187,6 +1190,9 @@ class UniqueShell(cmd.Cmd):
1187
1190
  elif parts[i] in ("--prompt", "-p") and i + 1 < len(parts):
1188
1191
  prompt = parts[i + 1]
1189
1192
  i += 2
1193
+ elif parts[i] in ("--name", "-n") and i + 1 < len(parts):
1194
+ name = parts[i + 1]
1195
+ i += 2
1190
1196
  elif parts[i] == "--chat-id" and i + 1 < len(parts):
1191
1197
  chat_id = parts[i + 1]
1192
1198
  i += 2
@@ -1200,7 +1206,7 @@ class UniqueShell(cmd.Cmd):
1200
1206
  if not cron or not assistant_id or not prompt:
1201
1207
  self._print(
1202
1208
  "Usage: schedule create --cron <expr> --assistant <id> --prompt <text> "
1203
- "[--chat-id <id>] [--disabled]"
1209
+ "[--name <text>] [--chat-id <id>] [--disabled]"
1204
1210
  )
1205
1211
  return
1206
1212
 
@@ -1210,6 +1216,7 @@ class UniqueShell(cmd.Cmd):
1210
1216
  cron=cron,
1211
1217
  assistant_id=assistant_id,
1212
1218
  prompt=prompt,
1219
+ name=name,
1213
1220
  chat_id=chat_id,
1214
1221
  enabled=not disabled,
1215
1222
  )
@@ -1220,6 +1227,7 @@ class UniqueShell(cmd.Cmd):
1220
1227
  cron: str | None = None
1221
1228
  assistant_id: str | None = None
1222
1229
  prompt: str | None = None
1230
+ name: str | None = None
1223
1231
  chat_id: str | None = None
1224
1232
  enable = False
1225
1233
  disable = False
@@ -1235,6 +1243,9 @@ class UniqueShell(cmd.Cmd):
1235
1243
  elif parts[i] in ("--prompt", "-p") and i + 1 < len(parts):
1236
1244
  prompt = parts[i + 1]
1237
1245
  i += 2
1246
+ elif parts[i] in ("--name", "-n") and i + 1 < len(parts):
1247
+ name = "" if parts[i + 1].lower() == "none" else parts[i + 1]
1248
+ i += 2
1238
1249
  elif parts[i] == "--chat-id" and i + 1 < len(parts):
1239
1250
  chat_id = "" if parts[i + 1].lower() == "none" else parts[i + 1]
1240
1251
  i += 2
@@ -1265,6 +1276,7 @@ class UniqueShell(cmd.Cmd):
1265
1276
  cron=cron,
1266
1277
  assistant_id=assistant_id,
1267
1278
  prompt=prompt,
1279
+ name=name,
1268
1280
  chat_id=chat_id,
1269
1281
  enabled=enabled,
1270
1282
  )
@@ -28,6 +28,8 @@ Manage cron-tab style scheduled tasks that trigger an assistant on a recurring s
28
28
  | `0 9 * * 1-5` | "every weekday (Mon-Fri) at 9:00 AM" |
29
29
  | `0 0 * * *` | "every day at midnight" |
30
30
  | `0 8 1 * *` | "on the 1st of every month at 8:00 AM" |
31
+ | `0 8 L * *` | "on the last day of every month at 8:00 AM" |
32
+ | `0 8 30 * *` | "on the 30th of every month at 8:00 AM — on the last day in February" |
31
33
  | `30 17 * * 5` | "every Friday at 5:30 PM" |
32
34
  | `0 */2 * * *` | "every 2 hours" |
33
35
  | `0 9 * * 1` | "every Monday at 9:00 AM" |
@@ -40,6 +42,34 @@ Manage cron-tab style scheduled tasks that trigger an assistant on a recurring s
40
42
  - If the user says "every morning at 9" → use `0 9 * * *` but tell them "Scheduled to run **every day at 9:00 AM**."
41
43
  - Include the day-of-week names (Mon, Tue, etc.) rather than numbers.
42
44
  - Use 12-hour format with AM/PM for times when talking to the user.
45
+ - Always tell the user the **name** you gave the task when you create or rename it, e.g.
46
+ "Done — I created **Daily sales report**, running every weekday at 9:00 AM."
47
+
48
+ ## Monthly schedules and the last day of the month (critical)
49
+
50
+ **Write monthly schedules only as `minute hour day * *`**, where `day` is `1`–`30` or the `L`
51
+ token. In that form — and *only* in that form — a day the month does not have moves to the
52
+ month's last day instead of being skipped. A day list (`0 8 29,30,31 * *`), a range, a step or
53
+ a month restriction (`0 8 31 1,7 *`) falls outside that handling and **will** skip short
54
+ months, after you have told the user it would not.
55
+
56
+ **Rules:**
57
+ - **Never tell the user a month will be skipped.** In the supported form it is not — the run
58
+ moves to that month's last day.
59
+ - For **"the last day of every month"**, and for **"the 31st"**, use the `L` token:
60
+ `0 8 L * *`. `L` means the last day of whichever month it is, so it runs in all 12 months:
61
+ 31 January, 28 (or 29) February, 31 March, 30 April, and so on. Prefer `L` over `31` — it
62
+ says what it means and is unambiguous in every month.
63
+ - When the user asks for **the 29th or 30th**, keep that day (`0 8 30 * *`) and spell out
64
+ February: "…on the **30th of every month** — in February it runs on the **last day** of the
65
+ month."
66
+ - Never put `L` anywhere but the day-of-month field, and never combine it with a list, range
67
+ or step.
68
+ - The platform supports **daily, weekday, weekly and monthly** schedules. If the user asks for
69
+ something outside that — a yearly date such as a birthday, "every two weeks", or a one-off
70
+ reminder — say so plainly and offer the closest supported schedule. Do **not** invent a cron
71
+ expression that pins the month (`0 7 18 11 *`) to fake it: it will run, but the schedule
72
+ editor cannot display or edit it afterwards.
43
73
 
44
74
  ## Timezone handling (critical)
45
75
 
@@ -90,6 +120,10 @@ Before running `schedule create`, **resolve / ask the user**:
90
120
  - **Continue an existing chat** — the user must provide a chat ID (starts with `chat_`). Pass it via `--chat-id`.
91
121
  4. **When should it run?** — Ask in plain language (e.g. "every weekday at 9 AM"). Convert to a UTC cron expression.
92
122
  5. **Prompt text** — what the assistant should do on each trigger.
123
+ 6. **Name** — **you write it, do not ask for it.** Derive a short, descriptive label from the
124
+ prompt (a few words, title-style, e.g. "Daily sales report", "Weekly pipeline review").
125
+ Pass it as `--name`. Keep it **at most 128 characters** — a longer name is rejected and the
126
+ whole `schedule create` fails. Tell the user what you called it when you confirm.
93
127
 
94
128
  Only pass `--chat-id` when the user explicitly wants to continue a specific chat. Otherwise leave it out.
95
129
 
@@ -111,7 +145,7 @@ Only pass `--chat-id` when the user explicitly wants to continue a specific chat
111
145
  unique-cli schedule list
112
146
  ```
113
147
 
114
- Output shows a table with status, cron expression, assistant, prompt snippet, task ID, and last run time.
148
+ Output shows a table with status, name, cron expression, assistant, prompt snippet, task ID, and last run time. A task saved without a name shows its prompt snippet in the name column.
115
149
 
116
150
  ## Get Task Details
117
151
 
@@ -133,7 +167,8 @@ ask the user to provide one.
133
167
  unique-cli schedule create \
134
168
  --cron "0 9 * * 1-5" \
135
169
  --assistant "$UNIQUE_ASSISTANT_ID" \
136
- --prompt "Generate the daily sales report and email it to the team"
170
+ --prompt "Generate the daily sales report and email it to the team" \
171
+ --name "Daily sales report"
137
172
  ```
138
173
 
139
174
  ### Continue an existing chat
@@ -143,7 +178,8 @@ unique-cli schedule create \
143
178
  --cron "0 9 * * 1-5" \
144
179
  --assistant "$UNIQUE_ASSISTANT_ID" \
145
180
  --chat-id chat_b7ze6mpv0edy324yhjj1d92t \
146
- --prompt "Append today's numbers to the running report"
181
+ --prompt "Append today's numbers to the running report" \
182
+ --name "Running report top-up"
147
183
  ```
148
184
 
149
185
  ### Create options
@@ -153,6 +189,7 @@ unique-cli schedule create \
153
189
  | `--cron` | `-c` | Yes | 5-field cron expression |
154
190
  | `--assistant` | `-a` | Yes | Assistant ID to execute (starts with `assistant_`). **Always pass `"$UNIQUE_ASSISTANT_ID"`** — never ask the user. |
155
191
  | `--prompt` | `-p` | Yes | Prompt text sent each run |
192
+ | `--name` | `-n` | No | Short label shown in the UI (≤128 chars). **Always pass one** — you generate it; without it the UI falls back to the prompt text |
156
193
  | `--chat-id` | | No | Continue an existing chat (starts with `chat_`; **omit for new chat each run**) |
157
194
  | `--disabled` | | No | Create in disabled state |
158
195
 
@@ -166,6 +203,9 @@ The user will describe schedules in plain language. Translate silently:
166
203
  | "every weekday at 9 AM" / "every morning Mon–Fri" | `0 9 * * 1-5` |
167
204
  | "every day at midnight" | `0 0 * * *` |
168
205
  | "first of every month at 8 AM" | `0 8 1 * *` |
206
+ | "the 31st of every month at 8 AM" | `0 8 L * *` (the 31st means the last day) |
207
+ | "the 30th of every month at 8 AM" | `0 8 30 * *` (February runs on its last day) |
208
+ | "last day of every month at 8 AM" | `0 8 L * *` |
169
209
  | "every Friday at 5:30 PM" | `30 17 * * 5` |
170
210
  | "every 2 hours" | `0 */2 * * *` |
171
211
  | "twice a day at 9 AM and 5 PM, weekdays" | `0 9,17 * * 1-5` |
@@ -178,7 +218,7 @@ The user will describe schedules in plain language. Translate silently:
178
218
  ```
179
219
  ┌───────────── minute (0–59)
180
220
  │ ┌───────────── hour (0–23)
181
- │ │ ┌───────────── day of month (1–31)
221
+ │ │ ┌───────────── day of month (1–31, or L for the last day)
182
222
  │ │ │ ┌───────────── month (1–12)
183
223
  │ │ │ │ ┌───────────── day of week (0–7, 0 and 7 = Sunday)
184
224
  │ │ │ │ │
@@ -212,6 +252,7 @@ unique-cli schedule update <task_id> --chat-id none
212
252
  | `--cron` | `-c` | Updated cron expression |
213
253
  | `--assistant` | `-a` | Updated assistant ID (starts with `assistant_`) |
214
254
  | `--prompt` | `-p` | Updated prompt text |
255
+ | `--name` | `-n` | Updated label (`none` to clear it and fall back to the prompt) |
215
256
  | `--chat-id` | | Updated chat ID (starts with `chat_`; `none` to clear) |
216
257
  | `--enable` | | Enable the task |
217
258
  | `--disable` | | Disable the task |
@@ -241,10 +282,11 @@ Run:
241
282
  unique-cli schedule create \
242
283
  -c "0 7 * * 1-5" \
243
284
  -a "$UNIQUE_ASSISTANT_ID" \
244
- -p "Generate the daily sales report and email it to the team"
285
+ -p "Generate the daily sales report and email it to the team" \
286
+ -n "Daily sales report"
245
287
  ```
246
288
 
247
- Respond: "Done — I scheduled **this assistant** to run your daily sales report **every weekday (Mon–Fri) at 9:00 AM your time (Europe/Zurich)**. That's 7:00 AM UTC. A new chat will be created for each run. Note: when clocks change for daylight saving, the task will shift by one hour in your local time."
289
+ Respond: "Done — I created **Daily sales report**, running **every weekday (Mon–Fri) at 9:00 AM your time (Europe/Zurich)**. That's 7:00 AM UTC. A new chat will be created for each run. Note: when clocks change for daylight saving, the task will shift by one hour in your local time."
248
290
 
249
291
  ### Set up a recurring task that continues the same chat
250
292
 
@@ -258,10 +300,11 @@ unique-cli schedule create \
258
300
  -c "0 7 * * 1-5" \
259
301
  -a "$UNIQUE_ASSISTANT_ID" \
260
302
  --chat-id chat_b7ze6mpv0edy324yhjj1d92t \
261
- -p "Append today's numbers to the running report"
303
+ -p "Append today's numbers to the running report" \
304
+ -n "Running report top-up"
262
305
  ```
263
306
 
264
- Respond: "Done — scheduled **this assistant** to run **every weekday (Mon–Fri) at 9:00 AM your time** (7:00 AM UTC), continuing chat `chat_b7ze6mpv0edy324yhjj1d92t`."
307
+ Respond: "Done — I created **Running report top-up**, running **every weekday (Mon–Fri) at 9:00 AM your time** (7:00 AM UTC), continuing chat `chat_b7ze6mpv0edy324yhjj1d92t`."
265
308
 
266
309
  ### Pause and resume a task
267
310
 
@@ -316,6 +359,7 @@ task = unique_sdk.ScheduledTask.create(
316
359
  cronExpression="0 9 * * 1-5",
317
360
  assistantId="assistant_cvj3fd7x8hpt1hfp0akqu1rq",
318
361
  prompt="Generate daily report",
362
+ name="Daily report",
319
363
  )
320
364
 
321
365
  # Create (continue existing chat)