unique_toolkit 1.11.3__py3-none-any.whl → 1.12.0__py3-none-any.whl

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.
@@ -714,6 +714,7 @@ class ChatService(ChatServiceDeprecated):
714
714
 
715
715
  def create_message_log(
716
716
  self,
717
+ *,
717
718
  message_id: str,
718
719
  text: str,
719
720
  status: MessageLogStatus,
@@ -754,6 +755,7 @@ class ChatService(ChatServiceDeprecated):
754
755
 
755
756
  async def create_message_log_async(
756
757
  self,
758
+ *,
757
759
  message_id: str,
758
760
  text: str,
759
761
  status: MessageLogStatus,
@@ -794,6 +796,7 @@ class ChatService(ChatServiceDeprecated):
794
796
 
795
797
  def update_message_log(
796
798
  self,
799
+ *,
797
800
  message_log_id: str,
798
801
  order: int,
799
802
  text: str | None = None,
@@ -834,6 +837,7 @@ class ChatService(ChatServiceDeprecated):
834
837
 
835
838
  async def update_message_log_async(
836
839
  self,
840
+ *,
837
841
  message_log_id: str,
838
842
  order: int,
839
843
  text: str | None = None,
@@ -874,6 +878,7 @@ class ChatService(ChatServiceDeprecated):
874
878
 
875
879
  def create_assistant_message_log(
876
880
  self,
881
+ *,
877
882
  text: str,
878
883
  status: MessageLogStatus,
879
884
  order: int,
@@ -912,6 +917,7 @@ class ChatService(ChatServiceDeprecated):
912
917
 
913
918
  async def create_assistant_message_log_async(
914
919
  self,
920
+ *,
915
921
  text: str,
916
922
  status: MessageLogStatus,
917
923
  order: int,
@@ -953,6 +959,7 @@ class ChatService(ChatServiceDeprecated):
953
959
 
954
960
  def create_message_execution(
955
961
  self,
962
+ *,
956
963
  message_id: str,
957
964
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
958
965
  seconds_remaining: int | None = None,
@@ -985,6 +992,7 @@ class ChatService(ChatServiceDeprecated):
985
992
 
986
993
  async def create_message_execution_async(
987
994
  self,
995
+ *,
988
996
  message_id: str,
989
997
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
990
998
  seconds_remaining: int | None = None,
@@ -1017,6 +1025,7 @@ class ChatService(ChatServiceDeprecated):
1017
1025
 
1018
1026
  def get_message_execution(
1019
1027
  self,
1028
+ *,
1020
1029
  message_id: str,
1021
1030
  ) -> MessageExecution:
1022
1031
  """Gets a message execution by message ID synchronously.
@@ -1039,6 +1048,7 @@ class ChatService(ChatServiceDeprecated):
1039
1048
 
1040
1049
  async def get_message_execution_async(
1041
1050
  self,
1051
+ *,
1042
1052
  message_id: str,
1043
1053
  ) -> MessageExecution:
1044
1054
  """Gets a message execution by message ID asynchronously.
@@ -1061,6 +1071,7 @@ class ChatService(ChatServiceDeprecated):
1061
1071
 
1062
1072
  def update_message_execution(
1063
1073
  self,
1074
+ *,
1064
1075
  message_id: str,
1065
1076
  status: MessageExecutionUpdateStatus,
1066
1077
  seconds_remaining: int | None = None,
@@ -1092,6 +1103,7 @@ class ChatService(ChatServiceDeprecated):
1092
1103
 
1093
1104
  async def update_message_execution_async(
1094
1105
  self,
1106
+ *,
1095
1107
  message_id: str,
1096
1108
  status: MessageExecutionUpdateStatus,
1097
1109
  seconds_remaining: int | None = None,
@@ -1123,6 +1135,7 @@ class ChatService(ChatServiceDeprecated):
1123
1135
 
1124
1136
  def create_assistant_message_execution(
1125
1137
  self,
1138
+ *,
1126
1139
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1127
1140
  seconds_remaining: int | None = None,
1128
1141
  percentage_completed: int | None = None,
@@ -1152,6 +1165,7 @@ class ChatService(ChatServiceDeprecated):
1152
1165
 
1153
1166
  async def create_assistant_message_execution_async(
1154
1167
  self,
1168
+ *,
1155
1169
  type: MessageExecutionType = MessageExecutionType.DEEP_RESEARCH,
1156
1170
  seconds_remaining: int | None = None,
1157
1171
  percentage_completed: int | None = None,
@@ -1211,6 +1225,7 @@ class ChatService(ChatServiceDeprecated):
1211
1225
 
1212
1226
  def update_assistant_message_execution(
1213
1227
  self,
1228
+ *,
1214
1229
  status: MessageExecutionUpdateStatus,
1215
1230
  seconds_remaining: int | None = None,
1216
1231
  percentage_completed: int | None = None,
@@ -1240,6 +1255,7 @@ class ChatService(ChatServiceDeprecated):
1240
1255
 
1241
1256
  async def update_assistant_message_execution_async(
1242
1257
  self,
1258
+ *,
1243
1259
  status: MessageExecutionUpdateStatus,
1244
1260
  seconds_remaining: int | None = None,
1245
1261
  percentage_completed: int | None = None,
@@ -1,5 +1,8 @@
1
+ import base64
2
+ import mimetypes
1
3
  from collections.abc import Iterable
2
- from typing import Self
4
+ from pathlib import Path
5
+ from typing import Self, overload
3
6
 
4
7
  from openai.types.chat.chat_completion_assistant_message_param import (
5
8
  Audio,
@@ -7,6 +10,10 @@ from openai.types.chat.chat_completion_assistant_message_param import (
7
10
  ContentArrayOfContentPart,
8
11
  FunctionCall,
9
12
  )
13
+ from openai.types.chat.chat_completion_content_part_image_param import (
14
+ ChatCompletionContentPartImageParam,
15
+ ImageURL,
16
+ )
10
17
  from openai.types.chat.chat_completion_content_part_param import (
11
18
  ChatCompletionContentPartParam,
12
19
  )
@@ -32,6 +39,83 @@ from openai.types.chat.chat_completion_tool_message_param import (
32
39
  from openai.types.chat.chat_completion_user_message_param import (
33
40
  ChatCompletionUserMessageParam,
34
41
  )
42
+ from typing_extensions import Literal
43
+
44
+
45
+ class OpenAIUserMessageBuilder:
46
+ def __init__(
47
+ self,
48
+ ) -> None:
49
+ self._messages: list[ChatCompletionContentPartParam] = []
50
+
51
+ def append_text(self, content: str) -> Self:
52
+ part = ChatCompletionContentPartTextParam(
53
+ type="text",
54
+ text=content,
55
+ )
56
+ self._messages.append(part)
57
+ return self
58
+
59
+ @overload
60
+ def append_image(
61
+ self, *, url: str, detail: Literal["auto", "low", "high"] = "auto"
62
+ ) -> Self: ...
63
+
64
+ @overload
65
+ def append_image(
66
+ self, *, path: Path, detail: Literal["auto", "low", "high"] = "auto"
67
+ ) -> Self: ...
68
+
69
+ @overload
70
+ def append_image(
71
+ self,
72
+ *,
73
+ content: bytes,
74
+ mime_type: str,
75
+ detail: Literal["auto", "low", "high"] = "auto",
76
+ ) -> Self: ...
77
+
78
+ def append_image(
79
+ self,
80
+ *,
81
+ url: str | None = None,
82
+ path: Path | None = None,
83
+ content: bytes | None = None,
84
+ mime_type: str | None = None,
85
+ detail: Literal["auto", "low", "high"] = "auto",
86
+ ) -> Self:
87
+ if url is None and path is None and (content is None or mime_type is None):
88
+ raise ValueError("Either url or path must be provided")
89
+
90
+ if path is not None:
91
+ # Read image file and encode as base64 data URI
92
+ image_data = path.read_bytes()
93
+ base64_image = base64.b64encode(image_data).decode("utf-8")
94
+ mime_type = mimetypes.guess_type(str(path))[0] or "image/jpeg"
95
+ url = f"data:{mime_type};base64,{base64_image}"
96
+
97
+ if content is not None and mime_type is not None:
98
+ base64_image = base64.b64encode(content).decode("utf-8")
99
+ url = f"data:{mime_type};base64,{base64_image}"
100
+
101
+ image_url = ImageURL(url=url or "", detail=detail)
102
+ part = ChatCompletionContentPartImageParam(
103
+ type="image_url",
104
+ image_url=image_url,
105
+ )
106
+ self._messages.append(part)
107
+ return self
108
+
109
+ @property
110
+ def user_message(self) -> ChatCompletionUserMessageParam:
111
+ return ChatCompletionUserMessageParam(
112
+ content=self._messages,
113
+ role="user",
114
+ )
115
+
116
+ @property
117
+ def iterable_content(self) -> Iterable[ChatCompletionContentPartParam]:
118
+ return self._messages
35
119
 
36
120
 
37
121
  class OpenAIMessageBuilder:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.11.3
3
+ Version: 1.12.0
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -117,7 +117,15 @@ All notable changes to this project will be documented in this file.
117
117
 
118
118
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
119
119
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
120
- ## [1.11.3] - 2026-10-06
120
+
121
+ ## [1.12.0] - 2026-10-07
122
+ - Add the `OpenAIUserMessageBuilder` for complex user messages with images
123
+ - More examples with documents/images on the chat
124
+
125
+ ## [1.11.4] - 2026-10-07
126
+ - Make newer `MessageExecution` and `MessageLog` method keyword only
127
+
128
+ ## [1.11.3] - 2026-10-07
121
129
  - Move smart rules to content
122
130
  - Add to documentation
123
131
 
@@ -107,7 +107,7 @@ unique_toolkit/chat/constants.py,sha256=05kq6zjqUVB2d6_P7s-90nbljpB3ryxwCI-CAz0r
107
107
  unique_toolkit/chat/deprecated/service.py,sha256=CYwzXi7OB0RjHd73CO2jq8SlpdBmDYLatzPFkb5sA0k,6529
108
108
  unique_toolkit/chat/functions.py,sha256=qxBjxIFoko5vyQNJDYpIkMtBhEGGcSlWn6fkAY-dFVE,45213
109
109
  unique_toolkit/chat/schemas.py,sha256=u3WPdMkOlmwPGHUueQC-nk8k-QkM7ZSUcU0f-32g6Uc,6718
110
- unique_toolkit/chat/service.py,sha256=fHiaHWHe4BJDwUX6bw6uzpxmk8E07Hyi5rz3QR75xNs,54454
110
+ unique_toolkit/chat/service.py,sha256=ZiVQiNBv54GKdPeiPKCmFzdkt0poLKxAuQejtu7p8lE,54630
111
111
  unique_toolkit/chat/state.py,sha256=Cjgwv_2vhDFbV69xxsn7SefhaoIAEqLx3ferdVFCnOg,1445
112
112
  unique_toolkit/chat/utils.py,sha256=ihm-wQykBWhB4liR3LnwPVPt_qGW6ETq21Mw4HY0THE,854
113
113
  unique_toolkit/content/__init__.py,sha256=EdJg_A_7loEtCQf4cah3QARQreJx6pdz89Rm96YbMVg,940
@@ -128,7 +128,7 @@ unique_toolkit/framework_utilities/langchain/client.py,sha256=9LDRS2l9XGxL0HoFLh
128
128
  unique_toolkit/framework_utilities/langchain/history.py,sha256=R9RuCeSFNaUO3OZ0G_LmIC4gmOCIANcl91MfyWLnZ1c,650
129
129
  unique_toolkit/framework_utilities/openai/__init__.py,sha256=CrHYoC7lv2pBscitLerAFweqy5jh1R671LA_jZQ4lWo,232
130
130
  unique_toolkit/framework_utilities/openai/client.py,sha256=ct1cqPcIK1wPl11G9sJV39ZnLJwKr2kDUDSra0FjvtM,2007
131
- unique_toolkit/framework_utilities/openai/message_builder.py,sha256=VU6mJm_upLcarJQKFft_t1RlLRncWDxDuLC5LIJ5lQQ,4339
131
+ unique_toolkit/framework_utilities/openai/message_builder.py,sha256=RT1pZjxH42TFZlAxQ5zlqdKPvHKVTjc5t3JDUy58I7Q,6887
132
132
  unique_toolkit/framework_utilities/utils.py,sha256=JK7g2yMfEx3eMprug26769xqNpS5WJcizf8n2zWMBng,789
133
133
  unique_toolkit/knowledge_base.py,sha256=SHAFs68zDQuHJZdrFcdU7wnkUdfNQlNzpSLNckx3Scg,20167
134
134
  unique_toolkit/language_model/__init__.py,sha256=lRQyLlbwHbNFf4-0foBU13UGb09lwEeodbVsfsSgaCk,1971
@@ -149,7 +149,7 @@ unique_toolkit/short_term_memory/schemas.py,sha256=OhfcXyF6ACdwIXW45sKzjtZX_gkcJ
149
149
  unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBuE9sI2o9Aajqjxg,8884
150
150
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
151
151
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
152
- unique_toolkit-1.11.3.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
153
- unique_toolkit-1.11.3.dist-info/METADATA,sha256=bc9ld0sdYyiytQL4O7lba5xUSLJb5XtkzoWts984bi4,35749
154
- unique_toolkit-1.11.3.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
155
- unique_toolkit-1.11.3.dist-info/RECORD,,
152
+ unique_toolkit-1.12.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
153
+ unique_toolkit-1.12.0.dist-info/METADATA,sha256=aDgLpV0zMymHSt92WH1-JLA16MaIBoQ61wzrXJnPFtE,35996
154
+ unique_toolkit-1.12.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
155
+ unique_toolkit-1.12.0.dist-info/RECORD,,