unique_toolkit 1.19.0__py3-none-any.whl → 1.19.2__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.

Potentially problematic release.


This version of unique_toolkit might be problematic. Click here for more details.

@@ -4,7 +4,7 @@ from logging import Logger
4
4
  from typing import Any, Generic
5
5
 
6
6
  import jinja2
7
- from pydantic import BaseModel
7
+ from pydantic import BaseModel, ValidationError
8
8
 
9
9
  from unique_toolkit._common.endpoint_builder import (
10
10
  ApiOperationProtocol,
@@ -41,11 +41,13 @@ NEXT_USER_MESSAGE_JINJA2_TEMPLATE = jinja2.Template("""I confirm the api call wi
41
41
  ```""")
42
42
 
43
43
 
44
- ASSISTANT_CONFIRMATION_MESSAGE_JINJA2_TEMPLATE = jinja2.Template("""I would like to call the api with the following data:
45
-
44
+ ASSISTANT_CONFIRMATION_MESSAGE_JINJA2_TEMPLATE = jinja2.Template(
45
+ """
46
+ \n
46
47
  {{ api_call_as_markdown_table }}
47
-
48
- [{{ button_text }}](https://prompt={{ next_user_message | urlencode }})""")
48
+ \n\n
49
+ [{{ button_text }}](https://prompt={{ next_user_message | urlencode }})"""
50
+ )
49
51
 
50
52
 
51
53
  class HumanVerificationManagerForApiCalling(
@@ -175,7 +177,9 @@ class HumanVerificationManagerForApiCalling(
175
177
  self._environment_payload_params.model_dump()
176
178
  )
177
179
 
178
- return self._operation.payload_model().model_validate(payload_dict)
180
+ return self._operation.payload_model().model_validate(
181
+ payload_dict, by_alias=True, by_name=True
182
+ )
179
183
 
180
184
  except Exception as e:
181
185
  self._logger.error(f"Error detecting api calls from user message: {e}")
@@ -211,7 +215,9 @@ class HumanVerificationManagerForApiCalling(
211
215
  modifiable_dict = payload_dict
212
216
 
213
217
  modifiable_params = self._modifiable_payload_params_model.model_validate(
214
- modifiable_dict
218
+ modifiable_dict,
219
+ by_alias=True,
220
+ by_name=True,
215
221
  )
216
222
  api_call = self._verification_model(
217
223
  modifiable_params=modifiable_params,
@@ -226,10 +232,12 @@ class HumanVerificationManagerForApiCalling(
226
232
  api_call_as_json=api_call.model_dump_json(indent=2)
227
233
  )
228
234
 
229
- def create_assistant_confirmation_message(self, *, payload: PayloadType) -> str:
235
+ def create_assistant_confirmation_message(
236
+ self, *, payload: PayloadType, button_text: str = "Confirm"
237
+ ) -> str:
230
238
  return ASSISTANT_CONFIRMATION_MESSAGE_JINJA2_TEMPLATE.render(
231
239
  api_call_as_markdown_table=dict_to_markdown_table(payload.model_dump()),
232
- button_text="Please confirm the call by pressing this button.",
240
+ button_text=button_text,
233
241
  next_user_message=self._create_next_user_message(payload),
234
242
  )
235
243
 
@@ -255,7 +263,11 @@ class HumanVerificationManagerForApiCalling(
255
263
  context=context,
256
264
  **params,
257
265
  )
258
- return self._operation.handle_response(response)
266
+ try:
267
+ return self._operation.handle_response(response)
268
+ except ValidationError as e:
269
+ self._logger.error(f"Error calling api: {e}. Response: {response}")
270
+ raise e
259
271
 
260
272
 
261
273
  if __name__ == "__main__":
@@ -3,6 +3,7 @@ This module provides a minimal framework for building endpoint classes such that
3
3
  the endpoints without having to know the details of the endpoints.
4
4
  """
5
5
 
6
+ import warnings
6
7
  from enum import StrEnum
7
8
  from string import Template
8
9
  from typing import (
@@ -15,7 +16,7 @@ from typing import (
15
16
  cast,
16
17
  )
17
18
 
18
- from pydantic import BaseModel
19
+ from pydantic import BaseModel, ValidationError
19
20
 
20
21
  # Paramspecs
21
22
  PayloadParamSpec = ParamSpec("PayloadParamSpec")
@@ -46,6 +47,42 @@ class HttpMethods(StrEnum):
46
47
  EndpointMethods = HttpMethods
47
48
 
48
49
 
50
+ class ResponseValidationException(Exception):
51
+ """
52
+ This exception is raised when the response validation fails.
53
+ """
54
+
55
+ def __init__(
56
+ self, operation_name: str, response: dict[str, Any], pydantic_error: str
57
+ ):
58
+ super().__init__(
59
+ f"Response validation failed for operation {operation_name}\n"
60
+ f"Response: {response}\n"
61
+ f"Pydantic error: {pydantic_error}"
62
+ )
63
+ self._operation_name = operation_name
64
+ self._response = response
65
+ self._pydantic_error = pydantic_error
66
+
67
+ @property
68
+ def operation_name(self) -> str:
69
+ return self._operation_name
70
+
71
+ @property
72
+ def response(self) -> dict[str, Any]:
73
+ return self._response
74
+
75
+ @property
76
+ def pydantic_error(self) -> str:
77
+ return self._pydantic_error
78
+
79
+ def __str__(self):
80
+ return (
81
+ f"Response validation failed for {self._operation_name}\n"
82
+ + f"Response: {self._response}"
83
+ )
84
+
85
+
49
86
  class ApiOperationProtocol(
50
87
  Protocol,
51
88
  Generic[
@@ -56,12 +93,21 @@ class ApiOperationProtocol(
56
93
  ResponseType,
57
94
  ],
58
95
  ):
96
+ @staticmethod
97
+ def path_dump_options() -> dict[str, Any]: ...
98
+
59
99
  @staticmethod
60
100
  def path_params_model() -> type[PathParamsType]: ...
61
101
 
102
+ @staticmethod
103
+ def payload_dump_options() -> dict[str, Any]: ...
104
+
62
105
  @staticmethod
63
106
  def payload_model() -> type[PayloadType]: ...
64
107
 
108
+ @staticmethod
109
+ def response_validate_options() -> dict[str, Any]: ...
110
+
65
111
  @staticmethod
66
112
  def response_model() -> type[ResponseType]: ...
67
113
 
@@ -71,17 +117,24 @@ class ApiOperationProtocol(
71
117
  ) -> str: ...
72
118
 
73
119
  @staticmethod
74
- def create_path_from_model(path_params: PathParamsType) -> str: ...
120
+ def create_path_from_model(
121
+ path_params: PathParamsType, *, model_dump_options: dict | None = None
122
+ ) -> str: ...
123
+
75
124
  @staticmethod
76
125
  def create_payload(
77
126
  *args: PayloadParamSpec.args, **kwargs: PayloadParamSpec.kwargs
78
127
  ) -> dict[str, Any]: ...
79
128
 
80
129
  @staticmethod
81
- def create_payload_from_model(payload: PayloadType) -> dict[str, Any]: ...
130
+ def create_payload_from_model(
131
+ payload: PayloadType, *, model_dump_options: dict | None = None
132
+ ) -> dict[str, Any]: ...
82
133
 
83
134
  @staticmethod
84
- def handle_response(response: dict[str, Any]) -> ResponseType: ...
135
+ def handle_response(
136
+ response: dict[str, Any], *, model_validate_options: dict | None = None
137
+ ) -> ResponseType: ...
85
138
 
86
139
  @staticmethod
87
140
  def request_method() -> EndpointMethods: ...
@@ -100,7 +153,10 @@ def build_api_operation(
100
153
  path_params_constructor: Callable[PathParamsSpec, PathParamsType],
101
154
  payload_constructor: Callable[PayloadParamSpec, PayloadType],
102
155
  response_model_type: type[ResponseType],
103
- dump_options: dict | None = None,
156
+ payload_dump_options: dict | None = None,
157
+ path_dump_options: dict | None = None,
158
+ response_validate_options: dict | None = None,
159
+ dump_options: dict | None = None, # Deprecated
104
160
  ) -> type[
105
161
  ApiOperationProtocol[
106
162
  PathParamsSpec,
@@ -126,16 +182,33 @@ def build_api_operation(
126
182
  "by_alias": True,
127
183
  "exclude_defaults": True,
128
184
  }
185
+ else:
186
+ warnings.warn(
187
+ "dump_options is deprecated. Use payload_dump_options instead.",
188
+ DeprecationWarning,
189
+ )
129
190
 
130
191
  class Operation(ApiOperationProtocol):
192
+ @staticmethod
193
+ def path_dump_options() -> dict[str, Any]:
194
+ return path_dump_options or {}
195
+
131
196
  @staticmethod
132
197
  def path_params_model() -> type[PathParamsType]:
133
198
  return cast(type[PathParamsType], path_params_constructor)
134
199
 
200
+ @staticmethod
201
+ def payload_dump_options() -> dict[str, Any]:
202
+ return payload_dump_options or {}
203
+
135
204
  @staticmethod
136
205
  def payload_model() -> type[PayloadType]:
137
206
  return cast(type[PayloadType], payload_constructor)
138
207
 
208
+ @staticmethod
209
+ def response_validate_options() -> dict[str, Any]:
210
+ return response_validate_options or {}
211
+
139
212
  @staticmethod
140
213
  def response_model() -> type[ResponseType]:
141
214
  return response_model_type
@@ -145,8 +218,18 @@ def build_api_operation(
145
218
  return path_template
146
219
 
147
220
  @staticmethod
148
- def create_path_from_model(path_params: PathParamsType) -> str:
149
- return path_template.substitute(**path_params.model_dump(**dump_options))
221
+ def create_path_from_model(
222
+ path_params: PathParamsType, *, model_dump_options: dict | None = None
223
+ ) -> str:
224
+ if model_dump_options is None:
225
+ if path_dump_options is None:
226
+ model_dump_options = dump_options
227
+ else:
228
+ model_dump_options = path_dump_options
229
+
230
+ return path_template.substitute(
231
+ **path_params.model_dump(**model_dump_options)
232
+ )
150
233
 
151
234
  @staticmethod
152
235
  def create_path(
@@ -157,19 +240,51 @@ def build_api_operation(
157
240
 
158
241
  @staticmethod
159
242
  def create_payload(
160
- *args: PayloadParamSpec.args, **kwargs: PayloadParamSpec.kwargs
243
+ *args: PayloadParamSpec.args,
244
+ **kwargs: PayloadParamSpec.kwargs,
161
245
  ) -> dict[str, Any]:
162
246
  """Create request body payload."""
247
+ if payload_dump_options is None:
248
+ model_dump_options = dump_options
249
+ else:
250
+ model_dump_options = payload_dump_options
251
+
163
252
  request_model = Operation.payload_model()(*args, **kwargs)
164
- return request_model.model_dump(**dump_options)
253
+ return request_model.model_dump(**model_dump_options)
165
254
 
166
255
  @staticmethod
167
- def create_payload_from_model(payload: PayloadType) -> dict[str, Any]:
168
- return payload.model_dump(**dump_options)
256
+ def create_payload_from_model(
257
+ payload: PayloadType, *, model_dump_options: dict | None = None
258
+ ) -> dict[str, Any]:
259
+ if model_dump_options is None:
260
+ if payload_dump_options is None:
261
+ model_dump_options = dump_options
262
+ else:
263
+ model_dump_options = payload_dump_options
264
+
265
+ return payload.model_dump(**model_dump_options)
169
266
 
170
267
  @staticmethod
171
- def handle_response(response: dict[str, Any]) -> ResponseType:
172
- return Operation.response_model().model_validate(response)
268
+ def handle_response(
269
+ response: dict[str, Any],
270
+ *,
271
+ model_validate_options: dict[str, Any] | None = None,
272
+ ) -> ResponseType:
273
+ if model_validate_options is None:
274
+ if response_validate_options is None:
275
+ model_validate_options = {}
276
+ else:
277
+ model_validate_options = response_validate_options
278
+ try:
279
+ return Operation.response_model().model_validate(
280
+ response, **model_validate_options
281
+ )
282
+ except ValidationError as e:
283
+ raise ResponseValidationException(
284
+ operation_name=Operation.__name__,
285
+ response=response,
286
+ pydantic_error=str(e),
287
+ ) from e
173
288
 
174
289
  @staticmethod
175
290
  def request_method() -> HttpMethods:
@@ -86,7 +86,10 @@ def build_fake_requestor(
86
86
  f"Invalid parameters passed to combined model {combined_model.__name__}: {e}"
87
87
  )
88
88
 
89
- return cls._operation.handle_response(return_value)
89
+ return cls._operation.handle_response(
90
+ return_value,
91
+ model_validate_options=cls._operation.response_validate_options(),
92
+ )
90
93
 
91
94
  @classmethod
92
95
  async def request_async(
@@ -132,11 +135,15 @@ def build_request_requestor(
132
135
  combined=kwargs
133
136
  )
134
137
 
135
- path = cls._operation.create_path_from_model(path_params)
138
+ path = cls._operation.create_path_from_model(
139
+ path_params, model_dump_options=cls._operation.path_dump_options()
140
+ )
136
141
  url = urljoin(context.base_url, path)
137
142
  _verify_url(url)
138
143
 
139
- payload = cls._operation.create_payload_from_model(payload_model)
144
+ payload = cls._operation.create_payload_from_model(
145
+ payload_model, model_dump_options=cls._operation.payload_dump_options()
146
+ )
140
147
 
141
148
  response = requests.request(
142
149
  method=cls._operation.request_method(),
@@ -144,7 +151,13 @@ def build_request_requestor(
144
151
  headers=context.headers,
145
152
  json=payload,
146
153
  )
147
- return cls._operation.handle_response(response.json())
154
+
155
+ response_json = response.json()
156
+
157
+ return cls._operation.handle_response(
158
+ response_json,
159
+ model_validate_options=cls._operation.response_validate_options(),
160
+ )
148
161
 
149
162
  @classmethod
150
163
  async def request_async(
@@ -191,7 +204,9 @@ def build_httpx_requestor(
191
204
  combined=kwargs
192
205
  )
193
206
 
194
- path = cls._operation.create_path_from_model(path_params)
207
+ path = cls._operation.create_path_from_model(
208
+ path_params, model_dump_options=cls._operation.path_dump_options()
209
+ )
195
210
  url = urljoin(context.base_url, path)
196
211
  _verify_url(url)
197
212
  with httpx.Client() as client:
@@ -199,9 +214,16 @@ def build_httpx_requestor(
199
214
  method=cls._operation.request_method(),
200
215
  url=url,
201
216
  headers=headers,
202
- json=cls._operation.create_payload_from_model(payload_model),
217
+ json=cls._operation.create_payload_from_model(
218
+ payload_model,
219
+ model_dump_options=cls._operation.payload_dump_options(),
220
+ ),
221
+ )
222
+ response_json = response.json()
223
+ return cls._operation.handle_response(
224
+ response_json,
225
+ model_validate_options=cls._operation.response_validate_options(),
203
226
  )
204
- return cls._operation.handle_response(response.json())
205
227
 
206
228
  @classmethod
207
229
  async def request_async(
@@ -216,7 +238,9 @@ def build_httpx_requestor(
216
238
  combined=kwargs
217
239
  )
218
240
 
219
- path = cls._operation.create_path_from_model(path_params)
241
+ path = cls._operation.create_path_from_model(
242
+ path_params, model_dump_options=cls._operation.path_dump_options()
243
+ )
220
244
  url = urljoin(context.base_url, path)
221
245
  _verify_url(url)
222
246
  async with httpx.AsyncClient() as client:
@@ -224,9 +248,16 @@ def build_httpx_requestor(
224
248
  method=cls._operation.request_method(),
225
249
  url=url,
226
250
  headers=headers,
227
- json=cls._operation.create_payload_from_model(payload_model),
251
+ json=cls._operation.create_payload_from_model(
252
+ payload_model,
253
+ model_dump_options=cls._operation.payload_dump_options(),
254
+ ),
255
+ )
256
+ response_json = response.json()
257
+ return cls._operation.handle_response(
258
+ response_json,
259
+ model_validate_options=cls._operation.response_validate_options(),
228
260
  )
229
- return cls._operation.handle_response(response.json())
230
261
 
231
262
  return HttpxRequestor
232
263
 
@@ -272,7 +303,9 @@ def build_aiohttp_requestor(
272
303
  path_params, payload_model = cls._operation.models_from_combined(
273
304
  combined=kwargs
274
305
  )
275
- path = cls._operation.create_path_from_model(path_params)
306
+ path = cls._operation.create_path_from_model(
307
+ path_params, model_dump_options=cls._operation.path_dump_options()
308
+ )
276
309
  url = urljoin(context.base_url, path)
277
310
  _verify_url(url)
278
311
 
@@ -281,9 +314,16 @@ def build_aiohttp_requestor(
281
314
  method=cls._operation.request_method(),
282
315
  url=url,
283
316
  headers=headers,
284
- json=cls._operation.create_payload_from_model(payload_model),
317
+ json=cls._operation.create_payload_from_model(
318
+ payload=payload_model,
319
+ model_dump_options=cls._operation.payload_dump_options(),
320
+ ),
321
+ )
322
+ response_json = await response.json()
323
+ return cls._operation.handle_response(
324
+ response=response_json,
325
+ model_validate_options=cls._operation.response_validate_options(),
285
326
  )
286
- return cls._operation.handle_response(await response.json())
287
327
 
288
328
  return AiohttpRequestor
289
329
 
@@ -367,7 +407,7 @@ if __name__ == "__main__":
367
407
 
368
408
  # Note that the return value is a pydantic UserResponse object
369
409
  response = FakeUserRequestor().request(
370
- context=RequestContext(headers={"a": "b"}),
410
+ context=RequestContext(base_url="https://example.com", headers={"a": "b"}),
371
411
  user_id=123,
372
412
  include_profile=True,
373
413
  )
@@ -379,7 +419,9 @@ if __name__ == "__main__":
379
419
 
380
420
  # Check type hints
381
421
  response = RequestRequestor().request(
382
- context=RequestContext(headers={"a": "b"}), user_id=123, include_profile=True
422
+ context=RequestContext(base_url="https://example.com", headers={"a": "b"}),
423
+ user_id=123,
424
+ include_profile=True,
383
425
  )
384
426
 
385
427
  print(response.model_dump())
@@ -35,3 +35,23 @@ class CommonException(Exception):
35
35
 
36
36
  class ConfigurationException(Exception):
37
37
  pass
38
+
39
+
40
+ class InfoExceptionForAi(Exception):
41
+ """
42
+ This exception is raised as information to the AI.
43
+ Such that it can be used to inform the user about the error.
44
+ In a meaningful way.
45
+ """
46
+
47
+ def __init__(
48
+ self,
49
+ error_message: str,
50
+ message_for_ai: str,
51
+ ):
52
+ super().__init__(error_message)
53
+ self._message_for_ai = message_for_ai
54
+
55
+ @property
56
+ def message_for_ai(self):
57
+ return self._message_for_ai
@@ -1,4 +1,4 @@
1
- from pydantic import BaseModel, Field
1
+ from pydantic import BaseModel
2
2
 
3
3
  from unique_toolkit.agentic.tools.config import get_configuration_dict
4
4
 
@@ -7,7 +7,3 @@ class FeatureExtendedSourceSerialization(BaseModel):
7
7
  """Mixin for experimental feature in Source serialization"""
8
8
 
9
9
  model_config = get_configuration_dict()
10
- full_sources_serialize_dump: bool = Field(
11
- default=False,
12
- description="Whether to include the full source object in the tool response. If True, includes the full Source object. If False, uses the old format with only source_number and content.",
13
- )
@@ -3,6 +3,9 @@ from typing import Annotated, Awaitable, Callable
3
3
 
4
4
  from pydantic import BaseModel, Field
5
5
 
6
+ from unique_toolkit._common.feature_flags.schema import (
7
+ FeatureExtendedSourceSerialization,
8
+ )
6
9
  from unique_toolkit._common.validators import LMI
7
10
  from unique_toolkit.agentic.history_manager.loop_token_reducer import LoopTokenReducer
8
11
  from unique_toolkit.agentic.history_manager.utils import transform_chunks_to_string
@@ -42,11 +45,7 @@ class UploadedContentConfig(BaseModel):
42
45
  )
43
46
 
44
47
 
45
- class ExperimentalFeatures(BaseModel):
46
- full_sources_serialize_dump: bool = Field(
47
- default=False,
48
- description="If True, the sources will be serialized in full, otherwise only the content will be serialized.",
49
- )
48
+ class ExperimentalFeatures(FeatureExtendedSourceSerialization): ...
50
49
 
51
50
 
52
51
  class HistoryManagerConfig(BaseModel):
@@ -172,8 +171,6 @@ class HistoryManager:
172
171
  stringified_sources, sources = transform_chunks_to_string(
173
172
  content_chunks,
174
173
  self._source_enumerator,
175
- None, # Use None for SourceFormatConfig
176
- self._config.experimental_features.full_sources_serialize_dump,
177
174
  )
178
175
 
179
176
  self._source_enumerator += len(
@@ -1,12 +1,10 @@
1
1
  import json
2
2
  import logging
3
3
  from copy import deepcopy
4
+ from typing import Any
4
5
 
5
6
  from unique_toolkit.agentic.tools.schemas import Source
6
- from unique_toolkit.agentic.tools.utils.source_handling.schema import (
7
- SourceFormatConfig,
8
- )
9
- from unique_toolkit.content.schemas import ContentChunk, ContentMetadata
7
+ from unique_toolkit.content.schemas import ContentChunk
10
8
  from unique_toolkit.language_model.schemas import (
11
9
  LanguageModelAssistantMessage,
12
10
  LanguageModelMessage,
@@ -62,58 +60,25 @@ def _convert_tool_call_response_to_content(
62
60
  def transform_chunks_to_string(
63
61
  content_chunks: list[ContentChunk],
64
62
  max_source_number: int,
65
- cfg: SourceFormatConfig | None,
66
- full_sources_serialize_dump: bool = False,
67
- ) -> tuple[str, list[Source]]:
63
+ ) -> tuple[str, list[dict[str, Any]]]:
68
64
  """Transform content chunks into a string of sources.
69
65
 
70
66
  Args:
71
67
  content_chunks (list[ContentChunk]): The content chunks to transform
72
68
  max_source_number (int): The maximum source number to use
73
- feature_full_sources (bool, optional): Whether to include the full source object. Defaults to False which is the old format.
74
69
 
75
70
  Returns:
76
71
  str: String for the tool call response
77
72
  """
78
73
  if not content_chunks:
79
74
  return "No relevant sources found.", []
80
- if full_sources_serialize_dump:
81
- sources = [
82
- Source(
83
- source_number=max_source_number + i,
84
- key=chunk.key,
85
- id=chunk.id,
86
- order=chunk.order,
87
- content=chunk.text,
88
- chunk_id=chunk.chunk_id,
89
- metadata=(
90
- _format_metadata(chunk.metadata, cfg) or None
91
- if chunk.metadata
92
- else None
93
- ),
94
- url=chunk.url,
95
- ).model_dump(
96
- exclude_none=True,
97
- exclude_defaults=True,
98
- by_alias=True,
99
- )
100
- for i, chunk in enumerate(content_chunks)
101
- ]
102
- else:
103
- sources = [
104
- {
105
- "source_number": max_source_number + i,
106
- "content": chunk.text,
107
- **(
108
- {"metadata": meta}
109
- if (
110
- meta := _format_metadata(chunk.metadata, cfg)
111
- ) # only add when not empty
112
- else {}
113
- ),
114
- }
115
- for i, chunk in enumerate(content_chunks)
116
- ]
75
+ sources: list[dict[str, Any]] = [
76
+ {
77
+ "source_number": max_source_number + i,
78
+ "content": chunk.text,
79
+ }
80
+ for i, chunk in enumerate(content_chunks)
81
+ ]
117
82
  return json.dumps(sources), sources
118
83
 
119
84
 
@@ -129,45 +94,3 @@ def load_sources_from_string(
129
94
  except (json.JSONDecodeError, ValueError):
130
95
  logger.warning("Failed to parse source string")
131
96
  return None
132
-
133
-
134
- def _format_metadata(
135
- metadata: ContentMetadata | None,
136
- cfg: SourceFormatConfig | None,
137
- ) -> str:
138
- """
139
- Build the concatenated tag string from the chunk's metadata
140
- and the templates found in cfg.sections.
141
- Example result:
142
- "<|topic|>GenAI<|/topic|>\n<|date|>This document is from: 2025-04-29<|/date|>\n"
143
- """
144
- if metadata is None:
145
- return ""
146
-
147
- if cfg is None or not cfg.sections:
148
- # If no configuration is provided, return empty string
149
- return ""
150
-
151
- meta_dict = metadata.model_dump(exclude_none=True, by_alias=True)
152
- sections = cfg.sections
153
-
154
- parts: list[str] = []
155
- for key, template in sections.items():
156
- if key in meta_dict:
157
- parts.append(template.format(meta_dict[key]))
158
-
159
- return "".join(parts)
160
-
161
-
162
- ### In case we do not want any formatting of metadata we could use this function
163
- # def _filtered_metadata(
164
- # meta: ContentMetadata | None,
165
- # cfg: SourceFormatConfig,
166
- # ) -> dict[str, str] | None:
167
- # if meta is None:
168
- # return None
169
-
170
- # allowed = set(cfg.sections)
171
- # raw = meta.model_dump(exclude_none=True, by_alias=True)
172
- # pruned = {k: v for k, v in raw.items() if k in allowed}
173
- # return pruned or None
@@ -18,7 +18,6 @@ from unique_toolkit.agentic.tools.a2a.tool._schema import (
18
18
  from unique_toolkit.agentic.tools.a2a.tool.config import (
19
19
  SubAgentToolConfig,
20
20
  )
21
- from unique_toolkit.agentic.tools.agent_chunks_hanlder import AgentChunksHandler
22
21
  from unique_toolkit.agentic.tools.factory import ToolFactory
23
22
  from unique_toolkit.agentic.tools.schemas import ToolCallResponse
24
23
  from unique_toolkit.agentic.tools.tool import Tool
@@ -31,7 +30,6 @@ from unique_toolkit.language_model import (
31
30
  LanguageModelFunction,
32
31
  LanguageModelToolDescription,
33
32
  )
34
- from unique_toolkit.language_model.schemas import LanguageModelMessage
35
33
 
36
34
 
37
35
  class SubAgentResponseSubscriber(Protocol):
@@ -199,13 +197,6 @@ class SubAgentTool(Tool[SubAgentToolConfig]):
199
197
  content=response_text_with_references,
200
198
  )
201
199
 
202
- @override
203
- def get_tool_call_result_for_loop_history(
204
- self,
205
- tool_response: ToolCallResponse,
206
- agent_chunks_handler: AgentChunksHandler,
207
- ) -> LanguageModelMessage: ... # Empty as method is deprecated
208
-
209
200
  async def _get_chat_id(self) -> str | None:
210
201
  if not self.config.reuse_chat:
211
202
  return None
@@ -13,7 +13,6 @@ from unique_toolkit.agentic.tools.tool_progress_reporter import (
13
13
  ToolProgressReporter,
14
14
  )
15
15
  from unique_toolkit.app.schemas import ChatEvent, McpServer, McpTool
16
- from unique_toolkit.language_model import LanguageModelMessage
17
16
  from unique_toolkit.language_model.schemas import (
18
17
  LanguageModelFunction,
19
18
  LanguageModelToolDescription,
@@ -99,12 +98,6 @@ class MCPToolWrapper(Tool[MCPToolConfig]):
99
98
  """Return evaluation checks based on tool response"""
100
99
  return []
101
100
 
102
- def get_tool_call_result_for_loop_history(
103
- self,
104
- tool_response: ToolCallResponse,
105
- ) -> LanguageModelMessage:
106
- raise NotImplementedError("function is not supported")
107
-
108
101
  async def run(self, tool_call: LanguageModelFunction) -> ToolCallResponse:
109
102
  """Execute the MCP tool using SDK to call public API"""
110
103
  self.logger.info(f"Running MCP tool: {self.name}")
@@ -50,11 +50,6 @@ class MockInternalSearchTool(Tool[BaseToolConfig]):
50
50
  def tool_format_information_for_system_prompt(self) -> str:
51
51
  return "Use this tool to search for content"
52
52
 
53
- def get_tool_call_result_for_loop_history(self, tool_response):
54
- from unique_toolkit.language_model.schemas import LanguageModelMessage
55
-
56
- return LanguageModelMessage(role="tool", content="Mock search result")
57
-
58
53
  def evaluation_check_list(self):
59
54
  return []
60
55
 
@@ -5,7 +5,6 @@ from typing import Any, Generic, TypeVar, cast
5
5
  from typing_extensions import deprecated
6
6
 
7
7
  from unique_toolkit.agentic.evaluation.schemas import EvaluationMetricName
8
- from unique_toolkit.agentic.tools.agent_chunks_hanlder import AgentChunksHandler
9
8
  from unique_toolkit.agentic.tools.config import ToolBuildConfig, ToolSelectionPolicy
10
9
  from unique_toolkit.agentic.tools.schemas import (
11
10
  BaseToolConfig,
@@ -20,7 +19,6 @@ from unique_toolkit.chat.service import (
20
19
  from unique_toolkit.language_model import LanguageModelToolDescription
21
20
  from unique_toolkit.language_model.schemas import (
22
21
  LanguageModelFunction,
23
- LanguageModelMessage,
24
22
  )
25
23
  from unique_toolkit.language_model.service import LanguageModelService
26
24
 
@@ -100,15 +98,6 @@ class Tool(ABC, Generic[ConfigType]):
100
98
  """
101
99
  return ""
102
100
 
103
- @deprecated("Do not use as is bound to loop agent only")
104
- @abstractmethod
105
- def get_tool_call_result_for_loop_history(
106
- self,
107
- tool_response: ToolCallResponse,
108
- agent_chunks_handler: AgentChunksHandler,
109
- ) -> LanguageModelMessage:
110
- raise NotImplementedError
111
-
112
101
  @deprecated(
113
102
  "Do not use. The tool should not determine how"
114
103
  "it is checked. This should be defined by the user"
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 1.19.0
3
+ Version: 1.19.2
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Cedric Klinkert
@@ -118,6 +118,13 @@ All notable changes to this project will be documented in this file.
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
120
 
121
+ ## [1.19.2] - 2025-10-29
122
+ - Removing unused tool specific `get_tool_call_result_for_loop_history` function
123
+ - Removing unused experimental config `full_sources_serialize_dump` in `history_manager`
124
+
125
+ ## [1.19.1] - 2025-10-29
126
+ - Make api operations more flexible
127
+ - Make verification button text adaptable
121
128
 
122
129
  ## [1.19.0] - 2025-10-28
123
130
  - Enable additional headers on openai and langchain client
@@ -1,7 +1,7 @@
1
1
  unique_toolkit/__init__.py,sha256=qrQ0kgAZnmGR6-UpWOpAL4yd-2ic5Jjwh6s8et-7ZTc,1372
2
2
  unique_toolkit/_common/_base_service.py,sha256=S8H0rAebx7GsOldA7xInLp3aQJt9yEPDQdsGSFRJsGg,276
3
3
  unique_toolkit/_common/_time_utils.py,sha256=ztmTovTvr-3w71Ns2VwXC65OKUUh-sQlzbHdKTQWm-w,135
4
- unique_toolkit/_common/api_calling/human_verification_manager.py,sha256=AeGzaGYlo8RHwEp7jhWM7gdx32dRyLUIioZRfrVbgUI,11905
4
+ unique_toolkit/_common/api_calling/human_verification_manager.py,sha256=cM_sS0BqnKhbgXMw90QGi140JPbTP5P6MsyR92SnLt8,12169
5
5
  unique_toolkit/_common/base_model_type_attribute.py,sha256=7rzVqjXa0deYEixeo_pJSJcQ7nKXpWK_UGpOiEH3yZY,10382
6
6
  unique_toolkit/_common/chunk_relevancy_sorter/config.py,sha256=tHETuMIC4CA_TPwU0oaHbckaKhvMFMYdO_d4lNRKnRc,1806
7
7
  unique_toolkit/_common/chunk_relevancy_sorter/exception.py,sha256=1mY4zjbvnXsd5oIxwiVsma09bS2XRnHrxW8KJBGtgCM,126
@@ -9,10 +9,10 @@ unique_toolkit/_common/chunk_relevancy_sorter/schemas.py,sha256=YAyvXzVk8h5q6FEs
9
9
  unique_toolkit/_common/chunk_relevancy_sorter/service.py,sha256=ZX1pxcy53zh3Ha0_pN6yYIbMX1acRxcvqKTPTKpGKwA,13938
10
10
  unique_toolkit/_common/chunk_relevancy_sorter/tests/test_service.py,sha256=giD9b5W8A0xP18dZCcrLUruoGi38BeBvPnO1phY7Sp0,8892
11
11
  unique_toolkit/_common/default_language_model.py,sha256=XCZu6n270QkxEeTpj5NZJda6Ok_IR-GcS8w30DU21aI,343
12
- unique_toolkit/_common/endpoint_builder.py,sha256=09Y8rC83oNsmxBLAf7WiHqK_OjZmeKb82TPzF0SLSVM,5499
13
- unique_toolkit/_common/endpoint_requestor.py,sha256=3B7ekfiTmgCEc2h1_m94DsfPwigE2yfiFUmbAAdjuVc,12039
14
- unique_toolkit/_common/exception.py,sha256=hwh60UUawHDyPFNs-Wom-Gc6Yb09gPelftAuW1tXE6o,779
15
- unique_toolkit/_common/feature_flags/schema.py,sha256=F1NdVJFNU8PKlS7bYzrIPeDu2LxRqHSM9pyw622a1Kk,547
12
+ unique_toolkit/_common/endpoint_builder.py,sha256=Ge83hyipUbh4fhxzA5XVeg3cj6T4JU4dL8Ue9MWElcw,9100
13
+ unique_toolkit/_common/endpoint_requestor.py,sha256=pY2SlRaHmHftNpPybmzxRsn4OBZCj_7niCMehL8I5O0,13744
14
+ unique_toolkit/_common/exception.py,sha256=ho0uBcPeZXU2w15IrSBhO5w7KUgxp1HcKAQrf2uin-w,1243
15
+ unique_toolkit/_common/feature_flags/schema.py,sha256=X32VqH4VMK7bhEfSd8Wbddl8FVs7Gh7ucuIEbmqc4Kw,268
16
16
  unique_toolkit/_common/pydantic/rjsf_tags.py,sha256=T3AZIF8wny3fFov66s258nEl1GqfKevFouTtG6k9PqU,31219
17
17
  unique_toolkit/_common/pydantic_helpers.py,sha256=1zzg6PlzSkHqPTdX-KoBaDHmBeeG7S5PprBsyMSCEuU,4806
18
18
  unique_toolkit/_common/string_utilities.py,sha256=pbsjpnz1mwGeugebHzubzmmDtlm18B8e7xJdSvLnor0,2496
@@ -44,9 +44,9 @@ unique_toolkit/agentic/evaluation/schemas.py,sha256=m9JMCUmeqP8KhsJOVEzsz6dRXUe1
44
44
  unique_toolkit/agentic/evaluation/tests/test_context_relevancy_service.py,sha256=4tDxHTApbaTMxN1sNS8WCqj2BweRk6YqZ5_zHP45jto,7977
45
45
  unique_toolkit/agentic/evaluation/tests/test_output_parser.py,sha256=RN_HcBbU6qy_e_PoYyUFcjWnp3ymJ6-gLj6TgEOupAI,3107
46
46
  unique_toolkit/agentic/history_manager/history_construction_with_contents.py,sha256=c8Zy3erSbHGT8AdICRRlSK91T_FN6tNpTznvUzpLbWk,9023
47
- unique_toolkit/agentic/history_manager/history_manager.py,sha256=xWA8w5CWrzueGW05ekIhc_Y_-_380hFfIB4rB5wlito,9470
47
+ unique_toolkit/agentic/history_manager/history_manager.py,sha256=6V4D5-YJFCsl_WthGVGw0Eq4WobXFgkFiX2YUtdjOZw,9275
48
48
  unique_toolkit/agentic/history_manager/loop_token_reducer.py,sha256=4XUX2-yVBnaYthV8p0zj2scVBUdK_3IhxBgoNlrytyQ,18498
49
- unique_toolkit/agentic/history_manager/utils.py,sha256=NDSSz0Jp3oVJU3iKlVScmM1AOe-6hTiVjLr16DUPsV0,5656
49
+ unique_toolkit/agentic/history_manager/utils.py,sha256=VIn_UmcR3jHtpux0qp5lQQzczgAm8XYSeQiPo87jC3A,3143
50
50
  unique_toolkit/agentic/postprocessor/postprocessor_manager.py,sha256=Z6rMQjhD0x6uC4p1cdxbUVv3jO-31hZTyNE1SiGYIu8,5680
51
51
  unique_toolkit/agentic/reference_manager/reference_manager.py,sha256=x51CT0D8HHu2LzgXdHGy0leOYpjnsxVbPZ2nc28G9mA,4005
52
52
  unique_toolkit/agentic/responses_api/__init__.py,sha256=9WTO-ef7fGE9Y1QtZJFm8Q_jkwK8Srtl-HWvpAD2Wxs,668
@@ -77,14 +77,14 @@ unique_toolkit/agentic/tools/a2a/tool/__init__.py,sha256=JIJKZBTLTA39OWhxoUd6uai
77
77
  unique_toolkit/agentic/tools/a2a/tool/_memory.py,sha256=w8bxjokrqHQZgApd55b5rHXF-DpgJwaKTg4CvLBLamc,1034
78
78
  unique_toolkit/agentic/tools/a2a/tool/_schema.py,sha256=wMwyunViTnxaURvenkATEvyfXn5LvLaP0HxbYqdZGls,158
79
79
  unique_toolkit/agentic/tools/a2a/tool/config.py,sha256=NcrS0hzIeYvjv1oMobAAPlZrbTPPWhcPhi0jUHLFBTI,2903
80
- unique_toolkit/agentic/tools/a2a/tool/service.py,sha256=Rutos0nmY4PhvO_ETlHr5mRdQFa2UuzSJWC2rmiAJng,10593
80
+ unique_toolkit/agentic/tools/a2a/tool/service.py,sha256=D1f3icUZ2D2nZKrnAnhi5YJUIaI68v2dXCH0iUIBlPg,10206
81
81
  unique_toolkit/agentic/tools/agent_chunks_hanlder.py,sha256=x32Dp1Z8cVW5i-XzXbaMwX2KHPcNGmqEU-FB4AV9ZGo,1909
82
82
  unique_toolkit/agentic/tools/config.py,sha256=QD83iy2xAJFyoPggYyLWq-MaSGSq00yS9iI31My1NBc,5387
83
83
  unique_toolkit/agentic/tools/factory.py,sha256=A1Aliwx037UAk9ADiDsg0zjCWWnvzV_PxwJNoPTvW6c,1434
84
84
  unique_toolkit/agentic/tools/mcp/__init__.py,sha256=RLF_p-LDRC7GhiB3fdCi4u3bh6V9PY_w26fg61BLyco,122
85
85
  unique_toolkit/agentic/tools/mcp/manager.py,sha256=DPYwwDe6RSZyuPaxn-je49fP_qOOs0ZV46EM6GZcV4c,2748
86
86
  unique_toolkit/agentic/tools/mcp/models.py,sha256=OyCCb7Vwv1ftzC_OCpFkf3TX9Aeb74ZZagG-qK5peIU,722
87
- unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256=37nkalHNUfti9rKdCH_rLEObbYdH7kDfkbLulf_sXmQ,9027
87
+ unique_toolkit/agentic/tools/mcp/tool_wrapper.py,sha256=MyR72E-N_vmGmlvAuSQtAQGbHo4AUUVdve-F0hcHgMU,8767
88
88
  unique_toolkit/agentic/tools/openai_builtin/__init__.py,sha256=NdVjkTa3LbW-JHhzPRjinTmgOCtEv090Zr9jGZXmgqs,345
89
89
  unique_toolkit/agentic/tools/openai_builtin/base.py,sha256=2Lw47XworwwkIQBQW5S1T6HS2mWqx13lx50moAMekRk,808
90
90
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/__init__.py,sha256=w2vONpnC6hKRPoJGwzDuRtNBsQd_o-gMUqArgIl_5KY,305
@@ -92,9 +92,9 @@ unique_toolkit/agentic/tools/openai_builtin/code_interpreter/config.py,sha256=r-
92
92
  unique_toolkit/agentic/tools/openai_builtin/code_interpreter/service.py,sha256=RKVExS1l3rJDVcu3mxKYA7SNV_Hphx2przhhiC-5PSo,7467
93
93
  unique_toolkit/agentic/tools/openai_builtin/manager.py,sha256=kU4wGit9AnDbkijB7LJEHcGXG8UeTBhiZh4a7lxTGA8,2246
94
94
  unique_toolkit/agentic/tools/schemas.py,sha256=0ZR8xCdGj1sEdPE0lfTIG2uSR5zqWoprUa3Seqez4C8,4837
95
- unique_toolkit/agentic/tools/test/test_mcp_manager.py,sha256=9q9TpzrQlxzQOwcyEGc6J7L4K55cclgvJme5jFQmc4M,19044
95
+ unique_toolkit/agentic/tools/test/test_mcp_manager.py,sha256=8j5fNQf3qELOcQ0m5fd8OkIFgunL5ILgdWzYD_Ccg1I,18816
96
96
  unique_toolkit/agentic/tools/test/test_tool_progress_reporter.py,sha256=dod5QPqgGUInVAGXAbsAKNTEypIi6pUEWhDbJr9YfUU,6307
97
- unique_toolkit/agentic/tools/tool.py,sha256=m56VLxiHuKU2_J5foZp00xhm5lTxWEW7zRLGbIE9ssU,6744
97
+ unique_toolkit/agentic/tools/tool.py,sha256=mFuxc3h4sghClDO8OVL2-6kifiHQ-U7JMYGUyXqTYLE,6338
98
98
  unique_toolkit/agentic/tools/tool_manager.py,sha256=DtxJobe_7QKFe6CjnMhCP-mnKO6MjnZeDXsO3jBoC9w,16283
99
99
  unique_toolkit/agentic/tools/tool_progress_reporter.py,sha256=ixud9VoHey1vlU1t86cW0-WTvyTwMxNSWBon8I11SUk,7955
100
100
  unique_toolkit/agentic/tools/utils/__init__.py,sha256=s75sjY5nrJchjLGs3MwSIqhDW08fFXIaX7eRQjFIA4s,346
@@ -165,7 +165,7 @@ unique_toolkit/short_term_memory/service.py,sha256=5PeVBu1ZCAfyDb2HLVvlmqSbyzBBu
165
165
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
166
166
  unique_toolkit/smart_rules/compile.py,sha256=Ozhh70qCn2yOzRWr9d8WmJeTo7AQurwd3tStgBMPFLA,1246
167
167
  unique_toolkit/test_utilities/events.py,sha256=_mwV2bs5iLjxS1ynDCjaIq-gjjKhXYCK-iy3dRfvO3g,6410
168
- unique_toolkit-1.19.0.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
169
- unique_toolkit-1.19.0.dist-info/METADATA,sha256=vFbZDvCyQYheZ7FvASbBZh5M7PqjI4GoRVqDbGkcAKY,38772
170
- unique_toolkit-1.19.0.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
171
- unique_toolkit-1.19.0.dist-info/RECORD,,
168
+ unique_toolkit-1.19.2.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
169
+ unique_toolkit-1.19.2.dist-info/METADATA,sha256=WefxvI5bONasMThIliFQ8k9tem_YLmNRrUve6sN5SJs,39071
170
+ unique_toolkit-1.19.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
171
+ unique_toolkit-1.19.2.dist-info/RECORD,,