unique_toolkit 1.33.2__py3-none-any.whl → 1.34.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.
@@ -8,6 +8,7 @@ from openai import AsyncOpenAI
8
8
  from openai.types.responses.response_output_text import AnnotationContainerFileCitation
9
9
  from pydantic import BaseModel, Field, RootModel
10
10
 
11
+ from unique_toolkit import ChatService
11
12
  from unique_toolkit.agentic.postprocessor.postprocessor_manager import (
12
13
  ResponsesApiPostprocessor,
13
14
  )
@@ -27,9 +28,13 @@ logger = logging.getLogger(__name__)
27
28
 
28
29
  class DisplayCodeInterpreterFilesPostProcessorConfig(BaseModel):
29
30
  model_config = get_configuration_dict()
31
+ upload_to_chat: bool = Field(
32
+ default=False,
33
+ description="Whether to upload the generated files to the chat.",
34
+ )
30
35
  upload_scope_id: str = Field(
31
36
  default="<SCOPE_ID_PLACEHOLDER>",
32
- description="The scope ID where the generated files will be uploaded.",
37
+ description="The scope ID where the generated files will be uploaded. Ignored if `uploadToChat` is set.",
33
38
  )
34
39
 
35
40
  file_download_failed_message: str = Field(
@@ -75,6 +80,7 @@ class DisplayCodeInterpreterFilesPostProcessor(
75
80
  client: AsyncOpenAI,
76
81
  content_service: ContentService | KnowledgeBaseService,
77
82
  config: DisplayCodeInterpreterFilesPostProcessorConfig,
83
+ chat_service: ChatService | None = None,
78
84
  # Short term memory arguments, we prefer to explicitely pass the required auth variables
79
85
  # as it is crucial that we use chat-level short term memory not to leak user files to other chats.
80
86
  # Technically, short term memory can be scoped company-level, we would like to ensure this case is avoided.
@@ -83,9 +89,14 @@ class DisplayCodeInterpreterFilesPostProcessor(
83
89
  chat_id: str | None = None,
84
90
  ) -> None:
85
91
  super().__init__(self.__class__.__name__)
92
+
86
93
  self._content_service = content_service
87
- self._config = config
94
+ self._chat_service = chat_service
88
95
  self._client = client
96
+ self._config = config
97
+
98
+ if self._config.upload_to_chat and self._chat_service is None:
99
+ raise ValueError("ChatService is required if uploadToChat is True")
89
100
 
90
101
  self._short_term_memory_manager = None
91
102
  if chat_id is not None and user_id is not None and company_id is not None:
@@ -199,13 +210,23 @@ class DisplayCodeInterpreterFilesPostProcessor(
199
210
  "Uploading file content for %s to knowledge base",
200
211
  container_file.filename,
201
212
  )
202
- content = await self._content_service.upload_content_from_bytes_async(
203
- content=file_content.content,
204
- content_name=container_file.filename,
205
- skip_ingestion=True,
206
- mime_type=guess_type(container_file.filename)[0] or "text/plain",
207
- scope_id=self._config.upload_scope_id,
208
- )
213
+
214
+ if self._config.upload_to_chat:
215
+ assert self._chat_service is not None # Checked in __init__
216
+ content = await self._chat_service.upload_to_chat_from_bytes_async(
217
+ content=file_content.content,
218
+ content_name=container_file.filename,
219
+ mime_type=guess_type(container_file.filename)[0] or "text/plain",
220
+ skip_ingestion=True,
221
+ )
222
+ else:
223
+ content = await self._content_service.upload_content_from_bytes_async(
224
+ content=file_content.content,
225
+ content_name=container_file.filename,
226
+ mime_type=guess_type(container_file.filename)[0] or "text/plain",
227
+ scope_id=self._config.upload_scope_id,
228
+ skip_ingestion=True,
229
+ )
209
230
 
210
231
  return _ContentInfo(filename=container_file.filename, content_id=content.id)
211
232
 
@@ -1,12 +1,12 @@
1
- import json
2
1
  from enum import StrEnum
3
- from typing import Annotated, Any, Dict
2
+ from typing import Annotated, Any
4
3
 
5
4
  from pydantic import (
6
5
  BaseModel,
7
6
  BeforeValidator,
8
7
  Field,
9
8
  ValidationInfo,
9
+ field_serializer,
10
10
  model_validator,
11
11
  )
12
12
 
@@ -123,46 +123,6 @@ class ToolBuildConfig(BaseModel):
123
123
  value["configuration"] = config
124
124
  return value
125
125
 
126
- def model_dump(self) -> Dict[str, Any]:
127
- """
128
- Returns a dict representation of the tool config that preserves
129
- subclass fields from `configuration` by delegating to its own
130
- model_dump. This prevents `{}` when `configuration` is typed
131
- as `BaseToolConfig` but holds a subclass instance.
132
- """
133
- data: Dict[str, Any] = {
134
- "name": self.name,
135
- "configuration": self.configuration.model_dump()
136
- if self.configuration
137
- else None,
138
- "display_name": self.display_name,
139
- "icon": self.icon,
140
- "selection_policy": self.selection_policy,
141
- "is_exclusive": self.is_exclusive,
142
- "is_sub_agent": self.is_sub_agent,
143
- "is_enabled": self.is_enabled,
144
- }
145
- return data
146
-
147
- def model_dump_json(self) -> str:
148
- """
149
- Returns a JSON string representation of the tool config.
150
- Ensures `configuration` is fully serialized by using the
151
- subclass's `model_dump_json()` when available.
152
- """
153
- config_json = (
154
- self.configuration.model_dump_json() if self.configuration else None
155
- )
156
- config = json.loads(config_json) if config_json else None
157
-
158
- data: Dict[str, Any] = {
159
- "name": self.name,
160
- "configuration": config,
161
- "display_name": self.display_name,
162
- "icon": self.icon,
163
- "selection_policy": self.selection_policy,
164
- "is_exclusive": self.is_exclusive,
165
- "is_sub_agent": self.is_sub_agent,
166
- "is_enabled": self.is_enabled,
167
- }
168
- return json.dumps(data)
126
+ @field_serializer("configuration")
127
+ def serialize_config(self, value: BaseToolConfig) -> dict[str, Any]:
128
+ return value.__class__.model_dump(value)
@@ -70,6 +70,7 @@ from unique_toolkit.content.functions import (
70
70
  download_content_to_bytes,
71
71
  search_contents,
72
72
  upload_content_from_bytes,
73
+ upload_content_from_bytes_async,
73
74
  )
74
75
  from unique_toolkit.content.schemas import (
75
76
  Content,
@@ -1607,6 +1608,30 @@ class ChatService(ChatServiceDeprecated):
1607
1608
  metadata=metadata,
1608
1609
  )
1609
1610
 
1611
+ async def upload_to_chat_from_bytes_async(
1612
+ self,
1613
+ *,
1614
+ content: bytes,
1615
+ content_name: str,
1616
+ mime_type: str,
1617
+ scope_id: str | None = None,
1618
+ skip_ingestion: bool = False,
1619
+ ingestion_config: unique_sdk.Content.IngestionConfig | None = None,
1620
+ metadata: dict[str, Any] | None = None,
1621
+ ) -> Content:
1622
+ return await upload_content_from_bytes_async(
1623
+ user_id=self._user_id,
1624
+ company_id=self._company_id,
1625
+ content=content,
1626
+ content_name=content_name,
1627
+ mime_type=mime_type,
1628
+ scope_id=scope_id,
1629
+ chat_id=self._chat_id,
1630
+ skip_ingestion=skip_ingestion,
1631
+ ingestion_config=ingestion_config,
1632
+ metadata=metadata,
1633
+ )
1634
+
1610
1635
  def download_chat_content_to_bytes(self, *, content_id: str) -> bytes:
1611
1636
  return download_content_to_bytes(
1612
1637
  user_id=self._user_id,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.33.2
3
+ Version: 1.34.0
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -121,6 +121,12 @@ All notable changes to this project will be documented in this file.
121
121
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
122
122
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
123
123
 
124
+ ## [1.34.0] - 2025-12-02
125
+ - Add option to upload code interpreter generated files to the chat.
126
+
127
+ ## [1.33.3] - 2025-12-02
128
+ - Fix serialization of ToolBuildConfig `configuration` field.
129
+
124
130
  ## [1.33.2] - 2025-12-01
125
131
  - Upgrade numpy to >2.1.0 to ensure compatibility with langchain library
126
132
 
@@ -68,7 +68,7 @@ unique_toolkit/agentic/postprocessor/postprocessor_manager.py,sha256=s6HFhA61TE0
68
68
  unique_toolkit/agentic/reference_manager/reference_manager.py,sha256=x51CT0D8HHu2LzgXdHGy0leOYpjnsxVbPZ2nc28G9mA,4005
69
69
  unique_toolkit/agentic/responses_api/__init__.py,sha256=9WTO-ef7fGE9Y1QtZJFm8Q_jkwK8Srtl-HWvpAD2Wxs,668
70
70
  unique_toolkit/agentic/responses_api/postprocessors/code_display.py,sha256=h6ZqPR0kPQnxM0ynshYQTa1BrcN8XGbUz9p03m8rOj0,2339
71
- unique_toolkit/agentic/responses_api/postprocessors/generated_files.py,sha256=9KfuLdhRvsW4K7dO6Q1fkdpyzKUqmMbIwVCO5eu3fDw,10732
71
+ unique_toolkit/agentic/responses_api/postprocessors/generated_files.py,sha256=ZdxJQQlD5K2Arn_NJVQNzIUwp-q5SmIE17o-UquTa0A,11691
72
72
  unique_toolkit/agentic/responses_api/stream_handler.py,sha256=Y1IM0uiPBdlab5UuOTCsHTaVX-fd9MxfS3xkwhdFie4,647
73
73
  unique_toolkit/agentic/short_term_memory_manager/persistent_short_term_memory_manager.py,sha256=uF3HSoZF0hBfuNhIE9N8KRtuwDfpoeXUFVrv_cyZ3Sw,5839
74
74
  unique_toolkit/agentic/thinking_manager/thinking_manager.py,sha256=41QWFsdRrbWlQHBfYCFv726UDom4WbcvaRfjCmoUOQI,4183
@@ -99,7 +99,7 @@ unique_toolkit/agentic/tools/a2a/tool/_schema.py,sha256=wMwyunViTnxaURvenkATEvyf
99
99
  unique_toolkit/agentic/tools/a2a/tool/config.py,sha256=zK9onAMYlYrPc0MCz0gBocd22jm0H5ar1ihNJ7CyjJU,5780
100
100
  unique_toolkit/agentic/tools/a2a/tool/service.py,sha256=OJx1zc1roPgt4aa1fDw4XTF9VOCCF72dhEJaNMEMOSU,13865
101
101
  unique_toolkit/agentic/tools/agent_chunks_hanlder.py,sha256=x32Dp1Z8cVW5i-XzXbaMwX2KHPcNGmqEU-FB4AV9ZGo,1909
102
- unique_toolkit/agentic/tools/config.py,sha256=N7IVtMecCCf8hxGUf-1GEk6ldIoEZfXi4fo5GMpHKus,5418
102
+ unique_toolkit/agentic/tools/config.py,sha256=71PSq8LoR80irk2iJfy_AgXOPi4Nh3luW5z5cDvY8i0,3920
103
103
  unique_toolkit/agentic/tools/factory.py,sha256=A1Aliwx037UAk9ADiDsg0zjCWWnvzV_PxwJNoPTvW6c,1434
104
104
  unique_toolkit/agentic/tools/mcp/__init__.py,sha256=RLF_p-LDRC7GhiB3fdCi4u3bh6V9PY_w26fg61BLyco,122
105
105
  unique_toolkit/agentic/tools/mcp/manager.py,sha256=DPYwwDe6RSZyuPaxn-je49fP_qOOs0ZV46EM6GZcV4c,2748
@@ -189,7 +189,7 @@ unique_toolkit/language_model/service.py,sha256=rt5LoQnDifIa5TnykGkJNl03lj0QhCMd
189
189
  unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
190
190
  unique_toolkit/protocols/support.py,sha256=ZEnbQL5w2-T_1AeM8OHycZJ3qbdfVI1nXe0nL9esQEw,5544
191
191
  unique_toolkit/services/__init__.py,sha256=90-IT5FjMcnlqxjp5kme9Fqgp_on46rggctIqHMdqsw,195
192
- unique_toolkit/services/chat_service.py,sha256=vA97DO4iiXMeTNuwS-bYeskX0DnqO_8vL4yzJAfsGtw,60111
192
+ unique_toolkit/services/chat_service.py,sha256=tHFmpbDiooYIvM5vZePsnwHdYUEcIBeD3db4lcsMJ_s,60941
193
193
  unique_toolkit/services/knowledge_base.py,sha256=uc89GL_NZXeFkJKkdHSSh2y1Wx0tmgasWk6uyGi4G_M,36210
194
194
  unique_toolkit/short_term_memory/__init__.py,sha256=2mI3AUrffgH7Yt-xS57EGqnHf7jnn6xquoKEhJqk3Wg,185
195
195
  unique_toolkit/short_term_memory/constants.py,sha256=698CL6-wjup2MvU19RxSmQk3gX7aqW_OOpZB7sbz_Xg,34
@@ -199,7 +199,7 @@ unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBu
199
199
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
200
200
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
201
201
  unique_toolkit/test_utilities/events.py,sha256=_mwV2bs5iLjxS1ynDCjaIq-gjjKhXYCK-iy3dRfvO3g,6410
202
- unique_toolkit-1.33.2.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
203
- unique_toolkit-1.33.2.dist-info/METADATA,sha256=i3ioZ4szjn5j4MiVzeO2-LlbLi5H9MeCXllSwYn0gTc,45339
204
- unique_toolkit-1.33.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
205
- unique_toolkit-1.33.2.dist-info/RECORD,,
202
+ unique_toolkit-1.34.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
203
+ unique_toolkit-1.34.0.dist-info/METADATA,sha256=DNDLgni0ur55-wGblbTjZqzJpFMKfx_IsWIfwWD5Lvk,45523
204
+ unique_toolkit-1.34.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
205
+ unique_toolkit-1.34.0.dist-info/RECORD,,