unique_toolkit 0.8.4__py3-none-any.whl → 0.8.6__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.
@@ -0,0 +1,215 @@
1
+ import pytest
2
+ from unique_toolkit.content.schemas import ContentChunk
3
+ from unique_toolkit.tools.utils.source_handling.schema import SourceFormatConfig
4
+ from unique_toolkit.tools.utils.source_handling.source_formatting import (
5
+ _format_page_range,
6
+ format_chunk,
7
+ )
8
+
9
+
10
+ @pytest.fixture
11
+ def default_config():
12
+ return SourceFormatConfig()
13
+
14
+
15
+ @pytest.fixture
16
+ def xml_style_config_without_page_number():
17
+ return SourceFormatConfig(
18
+ source_template="<source${index}>${document}${info}${text}</source${index}>",
19
+ sections={
20
+ "document": "<|document|>{}<|/document|>\n",
21
+ "info": "<|info|>{}<|/info|>\n",
22
+ },
23
+ )
24
+
25
+
26
+ @pytest.fixture
27
+ def xml_style_config_with_page_number():
28
+ return SourceFormatConfig(
29
+ source_template="<source${index}>${document}${page}${info}${text}</source${index}>",
30
+ sections={
31
+ "document": "<|document|>{}<|/document|>\n",
32
+ "info": "<|info|>{}<|/info|>\n",
33
+ "page": "<|page|>{}<|/page|>\n",
34
+ },
35
+ )
36
+
37
+
38
+ @pytest.fixture
39
+ def xml_style_config_with_metadata():
40
+ return SourceFormatConfig(
41
+ source_template="<source${index}>${document}${date}${text}</source${index}>",
42
+ sections={
43
+ "document": "<|document|>{}<|/document|>\n",
44
+ "date": "<|DateFromMetaData|>{}<|/DateFromMetaData|>\n",
45
+ },
46
+ )
47
+
48
+
49
+ @pytest.fixture
50
+ def json_style_config():
51
+ return SourceFormatConfig(
52
+ source_template="{'source_number': ${index}, 'content': '${document}${page}${info}${text}'}",
53
+ sections={
54
+ "document": "<|document|>{}<|/document|>\n",
55
+ "info": "<|info|>{}<|/info|>\n",
56
+ "page": "<|page|>{}<|/page|>\n",
57
+ },
58
+ )
59
+
60
+
61
+ def test_format_page_range():
62
+ # Test same start and end page
63
+ chunk = ContentChunk(id="1", order=1, text="test", start_page=1, end_page=1)
64
+ assert _format_page_range(chunk) == "1"
65
+
66
+ # Test page range
67
+ chunk = ContentChunk(id="1", order=1, text="test", start_page=1, end_page=3)
68
+ assert _format_page_range(chunk) == "1 - 3"
69
+
70
+ # Test invalid pages
71
+ chunk = ContentChunk(id="1", order=1, text="test", start_page=0, end_page=0)
72
+ assert _format_page_range(chunk) == ""
73
+
74
+
75
+ def test_json_style_formatting(json_style_config):
76
+ chunk = ContentChunk(
77
+ id="1",
78
+ order=1,
79
+ text="<|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text",
80
+ start_page=1,
81
+ end_page=2,
82
+ )
83
+
84
+ formatted = format_chunk(1, chunk, json_style_config)
85
+ expected = "{'source_number': 1, 'content': '<|document|>Doc1<|/document|>\n<|page|>1 - 2<|/page|>\n<|info|>Important<|/info|>\nContent text'}"
86
+ assert formatted == expected
87
+
88
+
89
+ def test_metadata_handling(xml_style_config_with_metadata):
90
+ # Test with metadata that matches a section name
91
+ chunk = ContentChunk(
92
+ id="1",
93
+ order=1,
94
+ text="<|document|>Doc1<|/document|>\nContent text",
95
+ metadata={
96
+ "key": "metadata-key",
97
+ "mimeType": "text/plain",
98
+ "date": "12.03.2025",
99
+ }, # type: ignore
100
+ )
101
+
102
+ formatted = format_chunk(1, chunk, xml_style_config_with_metadata)
103
+ expected = "<source1><|document|>Doc1<|/document|>\n<|DateFromMetaData|>12.03.2025<|/DateFromMetaData|>\nContent text</source1>"
104
+ assert formatted == expected
105
+
106
+ # Test with metadata that doesn't match a section name
107
+ chunk = ContentChunk(
108
+ id="1",
109
+ order=1,
110
+ text="<|document|>Doc1<|/document|>\nContent text",
111
+ metadata={
112
+ "key": "metadata-key",
113
+ "mimeType": "text/plain",
114
+ "unrelated_key": "Some value",
115
+ }, # type: ignore
116
+ )
117
+
118
+ formatted = format_chunk(1, chunk, xml_style_config_with_metadata)
119
+ expected = "<source1><|document|>Doc1<|/document|>\nContent text</source1>"
120
+ assert formatted == expected
121
+
122
+ # Test with minimal metadata
123
+ chunk = ContentChunk(
124
+ id="1",
125
+ order=1,
126
+ text="<|document|>Doc1<|/document|>\nContent text",
127
+ metadata={"key": "metadata-key", "mimeType": "text/plain"}, # type: ignore
128
+ )
129
+
130
+ formatted = format_chunk(1, chunk, xml_style_config_with_metadata)
131
+ expected = "<source1><|document|>Doc1<|/document|>\nContent text</source1>"
132
+ assert formatted == expected
133
+
134
+
135
+ def test_default_style(
136
+ default_config,
137
+ ):
138
+ chunk = ContentChunk(
139
+ id="1",
140
+ order=1,
141
+ text="<|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text",
142
+ start_page=1,
143
+ end_page=2,
144
+ )
145
+
146
+ formatted = format_chunk(1, chunk, default_config)
147
+ expected = "<source1><|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text</source1>"
148
+ assert formatted == expected
149
+
150
+
151
+ def test_xml_style_without_page_number_formatting(
152
+ xml_style_config_without_page_number,
153
+ ):
154
+ chunk = ContentChunk(
155
+ id="1",
156
+ order=1,
157
+ text="<|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text",
158
+ start_page=1,
159
+ end_page=2,
160
+ )
161
+
162
+ formatted = format_chunk(1, chunk, xml_style_config_without_page_number)
163
+ expected = "<source1><|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text</source1>"
164
+ assert formatted == expected
165
+
166
+
167
+ def test_xml_style_with_page_number_formatting(
168
+ xml_style_config_with_page_number,
169
+ ):
170
+ chunk = ContentChunk(
171
+ id="1",
172
+ order=1,
173
+ text="<|document|>Doc1<|/document|>\n<|info|>Important<|/info|>\nContent text",
174
+ start_page=1,
175
+ end_page=2,
176
+ )
177
+
178
+ formatted = format_chunk(1, chunk, xml_style_config_with_page_number)
179
+ expected = "<source1><|document|>Doc1<|/document|>\n<|page|>1 - 2<|/page|>\n<|info|>Important<|/info|>\nContent text</source1>"
180
+ assert formatted == expected
181
+
182
+
183
+ def test_special_characters_handling(json_style_config):
184
+ chunk = ContentChunk(
185
+ id="1",
186
+ order=1,
187
+ text="<|document|>Doc's \"title\"<|/document|>\n<|info|>Info with {brackets}<|/info|>\nContent: with 'quotes'",
188
+ start_page=1,
189
+ end_page=1,
190
+ )
191
+
192
+ formatted = format_chunk(1, chunk, json_style_config)
193
+ expected = "{'source_number': 1, 'content': '<|document|>Doc's \"title\"<|/document|>\n<|page|>1<|/page|>\n<|info|>Info with {brackets}<|/info|>\nContent: with 'quotes''}"
194
+ assert formatted == expected
195
+
196
+
197
+ def test_empty_sections(xml_style_config_without_page_number, json_style_config):
198
+ chunk = ContentChunk(
199
+ id="1",
200
+ order=1,
201
+ text="Just plain text without any sections",
202
+ start_page=None,
203
+ end_page=None,
204
+ )
205
+
206
+ # Test XML style
207
+ xml_formatted = format_chunk(1, chunk, xml_style_config_without_page_number)
208
+ assert xml_formatted == "<source1>Just plain text without any sections</source1>"
209
+
210
+ # Test JSON style
211
+ json_formatted = format_chunk(1, chunk, json_style_config)
212
+ assert (
213
+ json_formatted
214
+ == "{'source_number': 1, 'content': 'Just plain text without any sections'}"
215
+ )
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 0.8.4
3
+ Version: 0.8.6
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Martin Fadler
@@ -113,6 +113,12 @@ All notable changes to this project will be documented in this file.
113
113
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
114
114
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
115
115
 
116
+ ## [0.8.6] - 2025-08-11
117
+ - Add GPT-5, GPT-5_MINI, GPT-5_NANO, GPT-5_CHAT to supported models list
118
+
119
+ ## [0.8.5] - 2025-08-06
120
+ - Refactored tools to be in the tool-kit
121
+
116
122
  ## [0.8.4] - 2025-08-06
117
123
  - Make unique settings compatible with legacy environment variables
118
124
 
@@ -10,7 +10,7 @@ unique_toolkit/app/init_logging.py,sha256=Sh26SRxOj8i8dzobKhYha2lLrkrMTHfB1V4jR3
10
10
  unique_toolkit/app/init_sdk.py,sha256=5_oDoETr6akwYyBCb0ivTdMNu3SVgPSkrXcDS6ELyY8,2269
11
11
  unique_toolkit/app/performance/async_tasks.py,sha256=H0l3OAcosLwNHZ8d2pd-Di4wHIXfclEvagi5kfqLFPA,1941
12
12
  unique_toolkit/app/performance/async_wrapper.py,sha256=yVVcRDkcdyfjsxro-N29SBvi-7773wnfDplef6-y8xw,1077
13
- unique_toolkit/app/schemas.py,sha256=JdC2rNVPRrr6QhGMZweE0ID760onbRY2oq9m1LVFego,7429
13
+ unique_toolkit/app/schemas.py,sha256=J584RzwzIVSsdZyq0uVLI6efxIpWiMPKNz_IjIoOrxo,7432
14
14
  unique_toolkit/app/unique_settings.py,sha256=Gn8qxy_hNraVTTlP4wfZJzgxPU8cU6s84Uw6FK6ixGg,5946
15
15
  unique_toolkit/app/verification.py,sha256=GxFFwcJMy25fCA_Xe89wKW7bgqOu8PAs5y8QpHF0GSc,3861
16
16
  unique_toolkit/chat/__init__.py,sha256=LRs2G-JTVuci4lbtHTkVUiNcZcSR6uqqfnAyo7af6nY,619
@@ -55,13 +55,14 @@ unique_toolkit/language_model/__init__.py,sha256=lRQyLlbwHbNFf4-0foBU13UGb09lwEe
55
55
  unique_toolkit/language_model/builder.py,sha256=69WCcmkm2rMP2-YEH_EjHiEp6OzwjwCs8VbhjVJaCe0,3168
56
56
  unique_toolkit/language_model/constants.py,sha256=B-topqW0r83dkC_25DeQfnPk3n53qzIHUCBS7YJ0-1U,119
57
57
  unique_toolkit/language_model/functions.py,sha256=WhgHbJgz4Z2aZt9TLdOpI0PGyYWA5R90tdwkwdDeT8c,11987
58
- unique_toolkit/language_model/infos.py,sha256=Abxcw-l7UXkBohxZsigpNz0OUUCtDf404LLr7R-ys4E,33757
58
+ unique_toolkit/language_model/infos.py,sha256=mnUnbjDQNOIuPS2VE1SsgyKOxdRulo-9Z5k7_S1Q8Cw,37631
59
59
  unique_toolkit/language_model/prompt.py,sha256=JSawaLjQg3VR-E2fK8engFyJnNdk21zaO8pPIodzN4Q,3991
60
60
  unique_toolkit/language_model/reference.py,sha256=nkX2VFz-IrUz8yqyc3G5jUMNwrNpxITBrMEKkbqqYoI,8583
61
- unique_toolkit/language_model/schemas.py,sha256=AeuDRJFblGzEYcEMyrlxpOPk12Di3J45I9rT2xZrhEU,14332
61
+ unique_toolkit/language_model/schemas.py,sha256=r6c_lJ9Gl9wvY-N0FlmyFZjv5vPSc6CurFhpyST1Z5Y,14762
62
62
  unique_toolkit/language_model/service.py,sha256=zlvC_t9T1wixwcGDPRxl6yYniaKl2725NxWrbW51jUs,11290
63
63
  unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
64
64
  unique_toolkit/protocols/support.py,sha256=V15WEIFKVMyF1QCnR8vIi4GrJy4dfTCB6d6JlqPZ58o,2341
65
+ unique_toolkit/reference_manager/reference_manager.py,sha256=FNCW4CQSsimS8UG7OTdu4-JNQXUMhPrOfRuKAbK9vvE,2305
65
66
  unique_toolkit/short_term_memory/__init__.py,sha256=2mI3AUrffgH7Yt-xS57EGqnHf7jnn6xquoKEhJqk3Wg,185
66
67
  unique_toolkit/short_term_memory/constants.py,sha256=698CL6-wjup2MvU19RxSmQk3gX7aqW_OOpZB7sbz_Xg,34
67
68
  unique_toolkit/short_term_memory/functions.py,sha256=3WiK-xatY5nh4Dr5zlDUye1k3E6kr41RiscwtTplw5k,4484
@@ -69,11 +70,19 @@ unique_toolkit/short_term_memory/schemas.py,sha256=OhfcXyF6ACdwIXW45sKzjtZX_gkcJ
69
70
  unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBuE9sI2o9Aajqjxg,8884
70
71
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
71
72
  unique_toolkit/smart_rules/compile.py,sha256=cxWjb2dxEI2HGsakKdVCkSNi7VK9mr08w5sDcFCQyWI,9553
72
- unique_toolkit/tools/tool_definitions.py,sha256=YYu53vXMJBeJtuSU1L_FJBsiN52LSA5LIDt9O-1HBgE,4500
73
- unique_toolkit/tools/tool_definitionsV2.py,sha256=yjLmP85pFGd1QtIVMC3oLQPSQ2NckBj9hIihjIr2FZg,5728
74
- unique_toolkit/tools/tool_factory.py,sha256=ux11jd7Oobb-6eBeS51T-tviH14k6HKqsKmljA7h6qA,879
75
- unique_toolkit/tools/tool_progress_reporter.py,sha256=AyPdgxpd48qotJyPB8qJ7h7ghiv2w2EK8nlyqQVFRt4,8048
76
- unique_toolkit-0.8.4.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
77
- unique_toolkit-0.8.4.dist-info/METADATA,sha256=l-59S348l-GsL9MWnt8MbhSalpI1wTmv61Tp7EUmchk,26179
78
- unique_toolkit-0.8.4.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
79
- unique_toolkit-0.8.4.dist-info/RECORD,,
73
+ unique_toolkit/tools/agent_chunks_handler.py,sha256=ORjC22ulfHTfPxUHmU7QU0H53j3AdLmt1a0opeI91V8,1809
74
+ unique_toolkit/tools/config.py,sha256=9bYxdDuUPmAxhYyIdLbmXLzX1X2AUw--_WISQxQ4G2U,3003
75
+ unique_toolkit/tools/factory.py,sha256=vxxchbPTrk2lVjSMdpcFN-6FRcMLiy-NgHHS3w0wYCA,1271
76
+ unique_toolkit/tools/schemas.py,sha256=C9caE0EZNS6iGBPz2fsW5_Bao4GGGbAOda5D-XjnAQ0,4743
77
+ unique_toolkit/tools/test/test_tool_progress_reporter.py,sha256=YCR7uJ4_sn-z3CJskzSNWNDYYcThr9m2Q6gRBxbLVfg,6298
78
+ unique_toolkit/tools/tool.py,sha256=Zx9E5YSkzZ_ZUhxLgSLP_iDI8aYGq5wgOahMrnhfNV0,5751
79
+ unique_toolkit/tools/tool_manager.py,sha256=m1yt45rJ0OtC7wLVG5oqf_HvZygC7wV8g9OJWwr4ups,8490
80
+ unique_toolkit/tools/tool_progress_reporter.py,sha256=j6iVTpoLU_PjLwoK6fpIy9vmX_MLWF_-_v-nTDUcwas,7954
81
+ unique_toolkit/tools/utils/execution/execution.py,sha256=vjG2Y6awsGNtlvyQAGCTthQ5thWHYnn-vzZXaYLb3QE,7922
82
+ unique_toolkit/tools/utils/source_handling/schema.py,sha256=pvNhtL2daDLpCVIQpfdn6R35GvKmITVLXjZNLAwpgUE,871
83
+ unique_toolkit/tools/utils/source_handling/source_formatting.py,sha256=C7uayNbdkNVJdEARA5CENnHtNY1SU6etlaqbgHNyxaQ,9152
84
+ unique_toolkit/tools/utils/source_handling/tests/test_source_formatting.py,sha256=zu3AJnYH9CMqZPrxKEH3IgI-fM3nlvIBuspJG6W6B18,6978
85
+ unique_toolkit-0.8.6.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
86
+ unique_toolkit-0.8.6.dist-info/METADATA,sha256=KtED18vX71U_F50SqM0mqkrj4ZQqNF1P7FBp8G5p-z4,26343
87
+ unique_toolkit-0.8.6.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
88
+ unique_toolkit-0.8.6.dist-info/RECORD,,
@@ -1,145 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from enum import StrEnum
3
- from typing import Any, Generic, List, Self, TypeVar
4
- from unique_toolkit.language_model import LanguageModelToolDescription
5
- from typing_extensions import deprecated
6
- # import baseModel from pedantic
7
- from unique_toolkit.language_model import LanguageModelFunction
8
- from pydantic import BaseModel, Field, model_validator, root_validator
9
-
10
- from unique_toolkit.unique_toolkit.app.schemas import ChatEvent
11
- from unique_toolkit.unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
12
-
13
- class ToolSelectionPolicy(StrEnum):
14
- """Determine the usage policy of tools."""
15
-
16
- FORCED_BY_DEFAULT = "ForcedByDefault"
17
- ON_BY_DEFAULT = "OnByDefault"
18
- BY_USER = "ByUser"
19
-
20
- class UqToolName(StrEnum):
21
- WEB_SEARCH = "WebSearch"
22
- INTERNAL_SEARCH = "InternalSearch"
23
- DOCUMENT_SUMMARIZER = "DocumentSummarizer"
24
- CHART_GENERATOR = "ChartGenerator"
25
- DOCUMENT_GENERATOR = "DocumentGenerator"
26
- DOCUMENT_PARSER = "DocumentParser"
27
- IMAGE_CONTENT = "ImageContent"
28
- TABLE_SEARCH = "TableSearch"
29
- BAR_CHART = "BarChart"
30
- LINE_CHART = "LineChart"
31
- PIE_CHART = "PieChart"
32
- BASE_TOOL = "BaseTool"
33
-
34
-
35
- class BaseToolConfig(BaseModel):
36
- pass
37
-
38
-
39
- ConfigType = TypeVar("ConfigType", bound=BaseToolConfig)
40
-
41
-
42
- class ToolSettings(Generic[ConfigType]):
43
- configuration: ConfigType
44
- display_name: str
45
- icon: str
46
- selection_policy: ToolSelectionPolicy = Field(
47
- default=ToolSelectionPolicy.BY_USER,
48
- )
49
- is_exclusive: bool = Field(default=False)
50
- is_enabled: bool = Field(default=True)
51
-
52
- @classmethod
53
- def from_service_dict(cls, service_dict: dict[str, Any]) -> Self | None:
54
- try:
55
- return cls(**service_dict)
56
- except (ValueError, TypeError) as e:
57
- print(e)
58
- return None
59
-
60
-
61
- class ToolCallResponse(BaseModel):
62
- id: str
63
- name: str
64
- debug_info: dict = {}
65
-
66
-
67
- class ToolPromptInstructions(BaseModel):
68
- system_prompt: str = Field(
69
- default="",
70
- description=("Helps the LLM understand how to use the tool. "
71
- "This is injected into the system prompt."
72
- "This might not be needed for every tool but some of the work better with user prompt "
73
- "instructions while others work better with system prompt instructions."),
74
- )
75
-
76
- user_prompt: str = Field(
77
- default="",
78
- description=("Helps the LLM understand how to use the tool. "
79
- "This is injected into the user prompt. "
80
- "This might not be needed for every tool but some of the work better with user prompt "
81
- "instructions while others work better with system prompt instructions.")
82
- )
83
-
84
- system_prompt_tool_chosen: str = Field(
85
- default="",
86
- description=("Once the tool is chosen, this is injected into the system prompt"
87
- " to help the LLM understand how work with the tools results."),
88
- )
89
-
90
- user_prompt_tool_chosen: str = Field(
91
- default="",
92
- description=("Once the tool is chosen, this is injected into the user prompt "
93
- "to help the LLM understand how to work with the tools results."),
94
- )
95
-
96
-
97
- class Tool(ABC, Generic[ConfigType]):
98
- name: str
99
-
100
- def tool_description(self) -> LanguageModelToolDescription:
101
- raise NotImplementedError
102
-
103
-
104
- def get_prompt_instructions(self) -> ToolPromptInstructions:
105
- return ToolPromptInstructions(
106
- system_prompt="",
107
- user_prompt="",
108
- system_prompt_tool_chosen="",
109
- user_prompt_tool_chosen="",
110
- )
111
-
112
-
113
- def is_exclusive(self) -> bool:
114
- return self.settings.is_exclusive
115
-
116
- def is_enabled(self) -> bool:
117
- return self.settings.is_enabled
118
-
119
- def display_name(self) -> str:
120
- return self.settings.display_name
121
-
122
- def icon(self) -> str:
123
- return self.settings.icon
124
-
125
- def tool_selection_policy(self) -> ToolSelectionPolicy:
126
- return self.settings.selection_policy
127
-
128
-
129
- @abstractmethod
130
- async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
131
- raise NotImplementedError
132
-
133
-
134
-
135
- def __init__(
136
- self,
137
- settings: ToolSettings[ConfigType],
138
- event: ChatEvent,
139
- tool_progress_reporter: ToolProgressReporter
140
- ):
141
- self.settings = settings
142
- self.tool_progress_reporter = tool_progress_reporter
143
- self.event = event
144
-
145
-
@@ -1,137 +0,0 @@
1
- from abc import ABC, abstractmethod
2
- from enum import StrEnum
3
- from typing import Any, Generic, List, Self, TypeVar
4
- from unique_toolkit.language_model import LanguageModelToolDescription
5
- from typing_extensions import deprecated
6
- # import baseModel from pedantic
7
- from unique_toolkit.language_model import LanguageModelFunction
8
- from pydantic import BaseModel, Field, model_validator, root_validator
9
-
10
- from unique_toolkit.unique_toolkit.app.schemas import ChatEvent
11
- from unique_toolkit.unique_toolkit.tools.tool_definitions import BaseToolConfig, Tool, ToolCallResponse, ToolPromptInstructions, ToolSettings
12
- from unique_toolkit.unique_toolkit.tools.tool_progress_reporter import ToolProgressReporter
13
-
14
-
15
- class BaseToolConfigV2(BaseToolConfig):
16
- class ToolCallConfig(BaseModel):
17
- description: str = Field(
18
- default="Base",
19
- description="The tool description must be set by subclasses",
20
- )
21
-
22
- parameters: type[BaseModel] = Field(
23
- default=BaseModel,
24
- description="The tool parameters configuration must be set by subclasses",
25
- )
26
-
27
- class PromptInstructionsConfig(BaseModel):
28
- system_prompt: str = Field(
29
- default="",
30
- description=("Helps the LLM understand how to use the tool. "
31
- "This is injected into the system prompt."
32
- "This might not be needed for every tool but some of the work better with user prompt "
33
- "instructions while others work better with system prompt instructions."),
34
- )
35
-
36
- user_prompt: str = Field(
37
- default="",
38
- description=("Helps the LLM understand how to use the tool. "
39
- "This is injected into the user prompt. "
40
- "This might not be needed for every tool but some of the work better with user prompt "
41
- "instructions while others work better with system prompt instructions.")
42
- )
43
-
44
- system_prompt_tool_chosen: str = Field(
45
- default="",
46
- description=("Once the tool is chosen, this is injected into the system prompt"
47
- " to help the LLM understand how work with the tools results."),
48
- )
49
-
50
- user_prompt_tool_chosen: str = Field(
51
- default="",
52
- description=("Once the tool is chosen, this is injected into the user prompt "
53
- "to help the LLM understand how to work with the tools results."),
54
- )
55
-
56
- tool_call: ToolCallConfig = Field(
57
- default_factory=ToolCallConfig,
58
- description="Configuration for the tool, including description and parameters",
59
- )
60
-
61
- prompts: PromptInstructionsConfig = Field(
62
- default_factory=PromptInstructionsConfig,
63
- description="Configuration for prompts related to the tool",
64
- )
65
-
66
- # This makes sure that the settings are all present in all subclasses and that they define a default value.
67
- @model_validator(mode="after")
68
- def validate_tool_description(cls):
69
- if cls.__class__ is BaseToolConfig:
70
- return cls # Skip validation for the base class
71
- if cls.tool_call.description == "Base":
72
- raise ValueError(
73
- f"Subclass {cls.__class__.__name__} must define a default value for 'tool_description'."
74
- )
75
- if cls.tool_call.parameters == BaseModel:
76
- raise ValueError(
77
- f"Subclass {cls.__class__.__name__} must define a default value for 'tool_parameters_config'."
78
- )
79
- if cls.prompts.system_prompt == "":
80
- raise ValueError(
81
- f"Subclass {cls.__class__.__name__} must define a default value for 'system_prompt_base_instructions'."
82
- )
83
- if cls.prompts.user_prompt == "":
84
- raise ValueError(
85
- f"Subclass {cls.__class__.__name__} must define a default value for 'user_prompt_base_instructions'."
86
- )
87
- if cls.prompts.system_prompt_tool_chosen == "":
88
- raise ValueError(
89
- f"Subclass {cls.__class__.__name__} must define a default value for 'system_prompt_tool_chosen_instructions'."
90
- )
91
- if cls.prompts.user_prompt_tool_chosen == "":
92
- raise ValueError(
93
- f"Subclass {cls.__class__.__name__} must define a default value for 'user_prompt_tool_chosen_instructions'."
94
- )
95
- return cls
96
-
97
-
98
- ConfigTypeV2 = TypeVar("ConfigTypeV2", bound=BaseToolConfigV2)
99
-
100
-
101
-
102
- class ToolV2(Tool[ConfigTypeV2]):
103
- name: str
104
-
105
- def tool_description(self) -> LanguageModelToolDescription:
106
- return LanguageModelToolDescription(
107
- name=self.name,
108
- description=self.settings.configuration.tool_call.description,
109
- parameters=self.settings.configuration.tool_call.parameters,
110
- )
111
-
112
- def get_prompt_instructions(self) -> ToolPromptInstructions:
113
- return ToolPromptInstructions(
114
- system_prompt=self.settings.configuration.prompts.system_prompt,
115
- user_prompt=self.settings.configuration.prompts.user_prompt,
116
- system_prompt_tool_chosen=self.settings.configuration.prompts.system_prompt_tool_chosen,
117
- user_prompt_tool_chosen=self.settings.configuration.prompts.user_prompt_tool_chosen
118
- )
119
-
120
-
121
- @abstractmethod
122
- async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
123
- raise NotImplementedError
124
-
125
-
126
-
127
- def __init__(
128
- self,
129
- settings: ToolSettings[ConfigTypeV2],
130
- event: ChatEvent,
131
- tool_progress_reporter: ToolProgressReporter
132
- ):
133
- self.settings = settings
134
- self.tool_progress_reporter = tool_progress_reporter
135
- self.event = event
136
-
137
-