unique_toolkit 0.8.19__py3-none-any.whl → 0.8.20__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.
@@ -1,4 +1,6 @@
1
1
  import logging
2
+ import mimetypes
3
+ from enum import StrEnum
2
4
  from pathlib import Path
3
5
  from typing import Any, overload
4
6
 
@@ -33,6 +35,29 @@ from unique_toolkit.content.schemas import (
33
35
  logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
34
36
 
35
37
 
38
+ class FileMimeType(StrEnum):
39
+ PDF = "application/pdf"
40
+ DOCX = "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
41
+ DOC = "application/msword"
42
+ XLSX = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
43
+ XLS = "application/vnd.ms-excel"
44
+ PPTX = "application/vnd.openxmlformats-officedocument.presentationml.presentation"
45
+ CSV = "text/csv"
46
+ HTML = "text/html"
47
+ MD = "text/markdown"
48
+ TXT = "text/plain"
49
+
50
+
51
+ class ImageMimeType(StrEnum):
52
+ JPEG = "image/jpeg"
53
+ PNG = "image/png"
54
+ GIF = "image/gif"
55
+ BMP = "image/bmp"
56
+ WEBP = "image/webp"
57
+ TIFF = "image/tiff"
58
+ SVG = "image/svg+xml"
59
+
60
+
36
61
  class ContentService:
37
62
  """
38
63
  Provides methods for searching, downloading and uploading content in the knowledge base.
@@ -622,3 +647,51 @@ class ContentService:
622
647
  content_id=content_id,
623
648
  chat_id=chat_id,
624
649
  )
650
+
651
+ def get_documents_uploaded_to_chat(self) -> list[Content]:
652
+ chat_contents = self.search_contents(
653
+ where={
654
+ "ownerId": {
655
+ "equals": self._chat_id,
656
+ },
657
+ },
658
+ )
659
+
660
+ content: list[Content] = []
661
+ for c in chat_contents:
662
+ if self.is_file_content(c.key):
663
+ content.append(c)
664
+
665
+ return content
666
+
667
+ def get_images_uploaded_to_chat(self) -> list[Content]:
668
+ chat_contents = self.search_contents(
669
+ where={
670
+ "ownerId": {
671
+ "equals": self._chat_id,
672
+ },
673
+ },
674
+ )
675
+
676
+ content: list[Content] = []
677
+ for c in chat_contents:
678
+ if self.is_image_content(c.key):
679
+ content.append(c)
680
+
681
+ return content
682
+
683
+ def is_file_content(self, filename: str) -> bool:
684
+ mimetype, _ = mimetypes.guess_type(filename)
685
+
686
+ if not mimetype:
687
+ return False
688
+
689
+ return mimetype in FileMimeType.__members__.values()
690
+
691
+ def is_image_content(self, filename: str) -> bool:
692
+ mimetype, _ = mimetypes.guess_type(filename)
693
+
694
+ if not mimetype:
695
+ return False
696
+
697
+ return mimetype in ImageMimeType.__members__.values()
@@ -132,6 +132,7 @@ class Source(BaseModel):
132
132
  class ToolPrompts(BaseModel):
133
133
  name: str
134
134
  display_name: str
135
+ tool_system_prompt: str
135
136
  tool_description: str
136
137
  tool_format_information_for_system_prompt: str
137
138
  input_model: dict[str, Any]
@@ -109,6 +109,7 @@ class Tool(ABC, Generic[ConfigType]):
109
109
  name=self.name,
110
110
  display_name=self.display_name(),
111
111
  tool_description=self.tool_description().description,
112
+ tool_system_prompt=self.tool_description_for_system_prompt(),
112
113
  tool_format_information_for_system_prompt=self.tool_format_information_for_system_prompt(),
113
114
  input_model=self.tool_description_as_json(),
114
115
  )
@@ -1,5 +1,6 @@
1
1
  import asyncio
2
2
  from logging import Logger, getLogger
3
+ from typing import Any
3
4
 
4
5
  from pydantic import BaseModel, Field
5
6
 
@@ -18,13 +19,6 @@ from unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
18
19
  from unique_toolkit.tools.utils.execution.execution import Result, SafeTaskExecutor
19
20
 
20
21
 
21
- class ForcedToolOption:
22
- type: str = "function"
23
-
24
- def __init__(self, name: str):
25
- self.name = name
26
-
27
-
28
22
  class ToolManagerConfig(BaseModel):
29
23
  tools: list[ToolBuildConfig] = Field(
30
24
  default=[],
@@ -122,13 +116,20 @@ class ToolManager:
122
116
  return tool
123
117
  return None
124
118
 
125
- def get_forced_tools(self) -> list[ForcedToolOption]:
119
+ def get_forced_tools(self) -> list[dict[str, Any]]:
126
120
  return [
127
- ForcedToolOption(t.name)
121
+ self._convert_to_forced_tool(t.name)
128
122
  for t in self._tools
129
123
  if t.name in self._tool_choices
130
124
  ]
131
125
 
126
+ def add_forced_tool(self, name):
127
+ tool = self.get_tool_by_name(name)
128
+ if not tool:
129
+ raise ValueError(f"Tool {name} not found")
130
+ self._tools.append(tool)
131
+ self._tool_choices.append(tool.name)
132
+
132
133
  def get_tool_definitions(
133
134
  self,
134
135
  ) -> list[LanguageModelTool | LanguageModelToolDescription]:
@@ -198,7 +199,9 @@ class ToolManager:
198
199
  ) -> ToolCallResponse:
199
200
  self._logger.info(f"Processing tool call: {tool_call.name}")
200
201
 
201
- tool_instance = self.get_tool_by_name(tool_call.name)
202
+ tool_instance = self.get_tool_by_name(
203
+ tool_call.name
204
+ ) # we need to copy this as it will have problematic interference on multi calls.
202
205
 
203
206
  if tool_instance:
204
207
  # Execute the tool
@@ -254,3 +257,11 @@ class ToolManager:
254
257
  f"Filtered out {len(tool_calls) - len(unique_tool_calls)} duplicate tool calls."
255
258
  )
256
259
  return unique_tool_calls
260
+
261
+ from typing import Any
262
+
263
+ def _convert_to_forced_tool(self, tool_name: str) -> dict[str, Any]:
264
+ return {
265
+ "type": "function",
266
+ "function": {"name": tool_name},
267
+ }
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 0.8.19
3
+ Version: 0.8.20
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Martin Fadler
@@ -114,6 +114,8 @@ All notable changes to this project will be documented in this file.
114
114
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
115
115
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
116
116
 
117
+ ## [0.8.20] - 2025-08-24
118
+ - Fixed forced-tool-calls
117
119
 
118
120
  ## [0.8.19] - 2025-08-24
119
121
  - Enforce usage of ruff using pipeline
@@ -27,7 +27,7 @@ unique_toolkit/content/__init__.py,sha256=EdJg_A_7loEtCQf4cah3QARQreJx6pdz89Rm96
27
27
  unique_toolkit/content/constants.py,sha256=1iy4Y67xobl5VTnJB6SxSyuoBWbdLl9244xfVMUZi5o,60
28
28
  unique_toolkit/content/functions.py,sha256=HZtDIAH3ZxWleq5Si_v30n_7vTnNRu6BCxpTHb9TxdA,18635
29
29
  unique_toolkit/content/schemas.py,sha256=KJ604BOx0vBh2AwlTCZkOo55aHsI6yj8vxDAARKKqEo,2995
30
- unique_toolkit/content/service.py,sha256=3zUu3vUcPV8Mb_v1TCyi2hicGVMLNBamKB3Q6-z1trY,21455
30
+ unique_toolkit/content/service.py,sha256=u4-9hXxali4eSpRtnjK93TunsV0YmB6EDqPY1rpnKQ4,23443
31
31
  unique_toolkit/content/utils.py,sha256=qNVmHTuETaPNGqheg7TbgPr1_1jbNHDc09N5RrmUIyo,7901
32
32
  unique_toolkit/debug_info_manager/debug_info_manager.py,sha256=7c2yb3ES0yu-SJy3o7EwpuCBGaq_8IOMEAvD-BQ-eLI,576
33
33
  unique_toolkit/embedding/__init__.py,sha256=uUyzjonPvuDCYsvXCIt7ErQXopLggpzX-MEQd3_e2kE,250
@@ -98,16 +98,16 @@ unique_toolkit/smart_rules/compile.py,sha256=cxWjb2dxEI2HGsakKdVCkSNi7VK9mr08w5s
98
98
  unique_toolkit/thinking_manager/thinking_manager.py,sha256=AJfmrTXTr-DxBnJ2_zYYpYo57kr5deqT0LiZb8UdaDQ,4175
99
99
  unique_toolkit/tools/config.py,sha256=CHelTOEd2uqktK-bSYIyaqb9M1hKz8fy_DAR2mVzXpc,2985
100
100
  unique_toolkit/tools/factory.py,sha256=w3uNHuYBIJ330Xi8PTdAkr8G3OMbQH2cBgvk5UT16oE,1253
101
- unique_toolkit/tools/schemas.py,sha256=Zsrkh9RXY6n2GLrW-afzhsWRrU9uIMuZhfAs-s_4_Lo,4692
101
+ unique_toolkit/tools/schemas.py,sha256=PJBWN9NcEBSUmhrAMznbnw06ordrf4lfbhcxYZFmAOc,4720
102
102
  unique_toolkit/tools/test/test_tool_progress_reporter.py,sha256=GTtmBqOUo0-4fh_q0lRgxDhwKeankc3FHFD5ULZAm4Y,6299
103
- unique_toolkit/tools/tool.py,sha256=oMhGR_XdCP36L08LKHELpNwus4_UnC1klb_josM2-vM,5552
104
- unique_toolkit/tools/tool_manager.py,sha256=_kbB6dA1nyMM9D2YLARn8Ims25SOclOy1944Z0NVGcE,8895
103
+ unique_toolkit/tools/tool.py,sha256=zreY6fGBAfOIPNujWkl4cV5fBojjzGzVyvYuNLDrbzQ,5626
104
+ unique_toolkit/tools/tool_manager.py,sha256=vYGmNF9IvQoAG3N20TIbCpzmsJfoTFn_SVaENTJIk1w,9358
105
105
  unique_toolkit/tools/tool_progress_reporter.py,sha256=ixud9VoHey1vlU1t86cW0-WTvyTwMxNSWBon8I11SUk,7955
106
106
  unique_toolkit/tools/utils/execution/execution.py,sha256=vjG2Y6awsGNtlvyQAGCTthQ5thWHYnn-vzZXaYLb3QE,7922
107
107
  unique_toolkit/tools/utils/source_handling/schema.py,sha256=vzAyf6ZWNexjMO0OrnB8y2glGkvAilmGGQXd6zcDaKw,870
108
108
  unique_toolkit/tools/utils/source_handling/source_formatting.py,sha256=C7uayNbdkNVJdEARA5CENnHtNY1SU6etlaqbgHNyxaQ,9152
109
109
  unique_toolkit/tools/utils/source_handling/tests/test_source_formatting.py,sha256=oM5ZxEgzROrnX1229KViCAFjRxl9wCTzWZoinYSHleM,6979
110
- unique_toolkit-0.8.19.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
111
- unique_toolkit-0.8.19.dist-info/METADATA,sha256=AQgIWpBO6zd4H4cWtY8ML4t2Wdhq5AxdmbjUakFiRFs,28002
112
- unique_toolkit-0.8.19.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
113
- unique_toolkit-0.8.19.dist-info/RECORD,,
110
+ unique_toolkit-0.8.20.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
111
+ unique_toolkit-0.8.20.dist-info/METADATA,sha256=aBoWGMKrGjXZztoTaCqQF4w5CZ-P-4aZJ0QCqL09sjk,28053
112
+ unique_toolkit-0.8.20.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
113
+ unique_toolkit-0.8.20.dist-info/RECORD,,