unique_toolkit 0.7.31__py3-none-any.whl → 0.7.33__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.
@@ -51,9 +51,9 @@ def _add_references(
51
51
  # Only reference a source once, even if it is mentioned multiple times in the text.
52
52
  with_footnotes = _add_footnotes_to_text(text=text, references=references)
53
53
 
54
- # Gemini 2.5 flash model has tendency to add multiple references for the same fact
54
+ # Gemini 2.5 models have tendency to add multiple references for the same fact
55
55
  # This is a workaround to limit the number of references to 5
56
- if model and model.startswith("litellm:gemini-2-5-flash"):
56
+ if model and model.startswith("litellm:gemini-2-5"):
57
57
  reduced_text = _limit_consecutive_source_references(with_footnotes)
58
58
 
59
59
  # Get the references that remain after reduction
@@ -92,8 +92,11 @@ def _preprocess_message(text: str) -> str:
92
92
  # Replace XML format '[<source XX>]', '[<sourceXX>]' and '[\<sourceXX>]' with [XX]
93
93
  text = re.sub(r"\[(\\)?<source[\s]?(\d+)>\]", r"[\2]", text)
94
94
 
95
- # Replace format '[source XX]' and '[sourceXX]' with [XX]
96
- text = re.sub(r"\[source[\s]?(\d+)\]", r"[\1]", text)
95
+ # Replace format 'source XX', 'source_X' and 'sourceXX' references with XX, where XX is a number
96
+ text = re.sub(r"source[\s_]?(\d+)", r"[\1]", text)
97
+
98
+ # Replace 'source_number="X"' with X, where X is a number
99
+ text = re.sub(r"source_number=\"(\d+)\"", r"[\1]", text)
97
100
 
98
101
  # Make all references non-bold
99
102
  text = re.sub(r"\[\*\*(\d+)\*\*\]", r"[\1]", text)
@@ -107,13 +110,19 @@ def _preprocess_message(text: str) -> str:
107
110
  # Replace '[<[XX]>]' and '[\<[XX]>]' with [XX]
108
111
  text = re.sub(r"\[(\\)?\[?<\[(\d+)\]?\]>\]", r"[\2]", text)
109
112
 
110
- # Replace '[[A], [B], ...]' or '[[A], B, C, ...]' with [A][B][C]...
113
+ # Replace '[source: X, Y, Z]' with [X][Y][Z], where X,Y,Z are numbers
114
+ def replace_source_colon(match):
115
+ numbers = re.findall(r"\d+", match.group(0))
116
+ return "".join(f"[{n}]" for n in numbers)
117
+ text = re.sub(r"\[source:\s*([\d,\s]+)\]", replace_source_colon, text)
118
+
119
+ # Replace '[[A], [B], ...]', '[[A], B, C, ...]', and '[X, Y, Z]' with [A][B][C]... where A,B,C are numbers
111
120
  def replace_combined_brackets(match):
112
121
  numbers = re.findall(r"\d+", match.group(0))
113
122
  return "".join(f"[{n}]" for n in numbers)
114
123
 
115
124
  text = re.sub(
116
- r"\[\[(\d+)\](?:,\s*(?:\[)?\d+(?:\])?)*\]", replace_combined_brackets, text
125
+ r"(?:\[\[(\d+)\](?:,\s*(?:\[)?\d+(?:\])?)*\]|\[([\d,\s]+)\])", replace_combined_brackets, text
117
126
  )
118
127
 
119
128
  return text
@@ -243,6 +243,40 @@ class LanguageModelMessages(RootModel):
243
243
  | LanguageModelUserMessage
244
244
  ]
245
245
 
246
+ @classmethod
247
+ def load_messages_to_root(cls, data: list[dict] | dict) -> Self:
248
+ """Convert list of dictionaries to appropriate message objects based on role."""
249
+ # Handle case where data is already wrapped in root
250
+ if isinstance(data, dict) and "root" in data:
251
+ messages_list = data["root"]
252
+ elif isinstance(data, list):
253
+ messages_list = data
254
+ else:
255
+ raise ValueError("Invalid data type")
256
+
257
+ # Convert the messages list
258
+ converted_messages = []
259
+ for item in messages_list:
260
+ if isinstance(item, dict):
261
+ role = item.get("role", "").lower()
262
+
263
+ # Map dictionary to appropriate message class based on role
264
+ if role == "system":
265
+ converted_messages.append(LanguageModelSystemMessage(**item))
266
+ elif role == "user":
267
+ converted_messages.append(LanguageModelUserMessage(**item))
268
+ elif role == "assistant":
269
+ converted_messages.append(LanguageModelAssistantMessage(**item))
270
+ elif role == "tool":
271
+ converted_messages.append(LanguageModelToolMessage(**item))
272
+ else:
273
+ # Fallback to base LanguageModelMessage
274
+ converted_messages.append(LanguageModelMessage(**item))
275
+ else:
276
+ # If it's already a message object, keep it as is
277
+ converted_messages.append(item)
278
+ return cls(root=converted_messages)
279
+
246
280
  def __str__(self):
247
281
  return "\n\n".join([str(message) for message in self.root])
248
282
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: unique_toolkit
3
- Version: 0.7.31
3
+ Version: 0.7.33
4
4
  Summary:
5
5
  License: Proprietary
6
6
  Author: Martin Fadler
@@ -17,7 +17,7 @@ Requires-Dist: python-dotenv (>=1.0.1,<2.0.0)
17
17
  Requires-Dist: regex (>=2024.5.15,<2025.0.0)
18
18
  Requires-Dist: tiktoken (>=0.7.0,<0.8.0)
19
19
  Requires-Dist: typing-extensions (>=4.9.0,<5.0.0)
20
- Requires-Dist: unique-sdk (>=0.9.33,<0.10.0)
20
+ Requires-Dist: unique-sdk (>=0.9.36,<0.10.0)
21
21
  Description-Content-Type: text/markdown
22
22
 
23
23
  # Unique Toolkit
@@ -111,6 +111,12 @@ All notable changes to this project will be documented in this file.
111
111
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
112
112
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
113
113
 
114
+ ## [0.7.33] - 2025-06-25
115
+ - Update reference post-processing
116
+
117
+ ## [0.7.32] - 2025-06-24
118
+ - Create `classmethod` for `LanguageModelMessages` to load raw messages to root
119
+
114
120
  ## [0.7.31] - 2025-06-19
115
121
  - Add typings to references in payload from `LanguageModelStreamResponseMessage`
116
122
  - Add `original_index` to the base reference to reflect updated api
@@ -50,8 +50,8 @@ unique_toolkit/language_model/constants.py,sha256=B-topqW0r83dkC_25DeQfnPk3n53qz
50
50
  unique_toolkit/language_model/functions.py,sha256=WhgHbJgz4Z2aZt9TLdOpI0PGyYWA5R90tdwkwdDeT8c,11987
51
51
  unique_toolkit/language_model/infos.py,sha256=w5__BVG-IiiEYKG1FwM838wzqNbYI3eCCEDocKezc0I,34801
52
52
  unique_toolkit/language_model/prompt.py,sha256=JSawaLjQg3VR-E2fK8engFyJnNdk21zaO8pPIodzN4Q,3991
53
- unique_toolkit/language_model/reference.py,sha256=ntoWdJ_hly8FntTgg1qpj0ta55SOCCVsC5L49VqOiAQ,8067
54
- unique_toolkit/language_model/schemas.py,sha256=_fJ9rckKaS082wd2x9DrJ9N6B7iTJ9ytFnq4eIFDNAQ,12781
53
+ unique_toolkit/language_model/reference.py,sha256=jd-JPuqLwEJDs56im56o-AdiT73pdwNtSzcW38LZ53o,8565
54
+ unique_toolkit/language_model/schemas.py,sha256=AeuDRJFblGzEYcEMyrlxpOPk12Di3J45I9rT2xZrhEU,14332
55
55
  unique_toolkit/language_model/service.py,sha256=VRkUk2XbijqGlnTTvqU7uCue6qtT7lpLd_Y8f3bWv1I,10486
56
56
  unique_toolkit/language_model/utils.py,sha256=bPQ4l6_YO71w-zaIPanUUmtbXC1_hCvLK0tAFc3VCRc,1902
57
57
  unique_toolkit/protocols/support.py,sha256=V15WEIFKVMyF1QCnR8vIi4GrJy4dfTCB6d6JlqPZ58o,2341
@@ -62,7 +62,7 @@ unique_toolkit/short_term_memory/schemas.py,sha256=OhfcXyF6ACdwIXW45sKzjtZX_gkcJ
62
62
  unique_toolkit/short_term_memory/service.py,sha256=cqpXA0nMbi4PhFweg-Cql3u0RvaTi5c8Xjv0uHMiSGc,8112
63
63
  unique_toolkit/smart_rules/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
64
64
  unique_toolkit/smart_rules/compile.py,sha256=cxWjb2dxEI2HGsakKdVCkSNi7VK9mr08w5sDcFCQyWI,9553
65
- unique_toolkit-0.7.31.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
66
- unique_toolkit-0.7.31.dist-info/METADATA,sha256=aNS24gdydQe6icQg_M3EFprEMJ2o8qcR-95-lya8tj8,24607
67
- unique_toolkit-0.7.31.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
68
- unique_toolkit-0.7.31.dist-info/RECORD,,
65
+ unique_toolkit-0.7.33.dist-info/LICENSE,sha256=GlN8wHNdh53xwOPg44URnwag6TEolCjoq3YD_KrWgss,193
66
+ unique_toolkit-0.7.33.dist-info/METADATA,sha256=iTa95C3sVeL6SR4HrO3jny6n2kmpoNunzUYeQNhdiNM,24774
67
+ unique_toolkit-0.7.33.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
68
+ unique_toolkit-0.7.33.dist-info/RECORD,,