unique_toolkit 0.7.25__py3-none-any.whl → 0.7.27__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,10 +1,14 @@
1
+ import json
1
2
  from enum import StrEnum
3
+ from pathlib import Path
2
4
  from typing import Any, Optional
3
5
 
4
6
  from humps import camelize
5
- from pydantic import BaseModel, ConfigDict, Field
7
+ from pydantic import BaseModel, ConfigDict, Field, field_validator
6
8
  from typing_extensions import deprecated
7
9
 
10
+ from unique_toolkit.smart_rules.compile import UniqueQL, parse_uniqueql
11
+
8
12
  # set config to convert camelCase to snake_case
9
13
  model_config = ConfigDict(
10
14
  alias_generator=camelize,
@@ -25,6 +29,14 @@ class BaseEvent(BaseModel):
25
29
  user_id: str
26
30
  company_id: str
27
31
 
32
+ @classmethod
33
+ def from_json_file(cls, file_path: Path) -> "BaseEvent":
34
+ if not file_path.exists():
35
+ raise FileNotFoundError(f"File not found: {file_path}")
36
+ with file_path.open("r", encoding="utf-8") as f:
37
+ data = json.load(f)
38
+ return cls.model_validate(data)
39
+
28
40
 
29
41
  ###
30
42
  # ChatEvent schemas
@@ -95,15 +107,31 @@ class ChatEventPayload(BaseModel):
95
107
  assistant_id: str
96
108
  user_message: ChatEventUserMessage
97
109
  assistant_message: ChatEventAssistantMessage
98
- text: Optional[str] = None
99
- additional_parameters: Optional[ChatEventAdditionalParameters] = None
100
- user_metadata: Optional[dict[str, Any]] = None
101
- tool_choices: Optional[list[str]] = Field(
102
- default=[],
110
+ text: str | None = None
111
+ additional_parameters: ChatEventAdditionalParameters | None = None
112
+ user_metadata: dict[str, Any] | None = Field(
113
+ default_factory=dict,
114
+ )
115
+ tool_choices: list[str] = Field(
116
+ default_factory=list,
103
117
  description="A list containing the tool names the user has chosen to be activated.",
104
118
  )
105
- tool_parameters: Optional[dict[str, Any]] = None
106
- metadata_filter: Optional[dict[str, Any]] = None
119
+ tool_parameters: dict[str, Any] = Field(
120
+ default_factory=dict,
121
+ description="Parameters extracted from module selection function calling the tool.",
122
+ )
123
+ metadata_filter: dict[str, Any] = Field(
124
+ default_factory=dict,
125
+ description="Metadata filter compiled after module selection function calling and scope rules.",
126
+ )
127
+ raw_scope_rules: UniqueQL | None = Field(
128
+ default=None,
129
+ description="Raw UniqueQL rule that can be compiled to a metadata filter.",
130
+ )
131
+
132
+ @field_validator("raw_scope_rules", mode="before")
133
+ def validate_scope_rules(cls, value: dict[str, Any]) -> UniqueQL:
134
+ return parse_uniqueql(value)
107
135
 
108
136
 
109
137
  @deprecated("""Use `ChatEventPayload` instead.
@@ -122,6 +150,14 @@ class ChatEvent(BaseEvent):
122
150
  created_at: Optional[int] = None
123
151
  version: Optional[str] = None
124
152
 
153
+ @classmethod
154
+ def from_json_file(cls, file_path: Path) -> "ChatEvent":
155
+ if not file_path.exists():
156
+ raise FileNotFoundError(f"File not found: {file_path}")
157
+ with file_path.open("r", encoding="utf-8") as f:
158
+ data = json.load(f)
159
+ return cls.model_validate(data)
160
+
125
161
 
126
162
  @deprecated(
127
163
  """Use the more specific `ChatEvent` instead that has the same properties. \
@@ -132,3 +168,11 @@ class Event(ChatEvent):
132
168
  # The below should only affect type hints
133
169
  # event: EventName T
134
170
  # payload: EventPayload
171
+
172
+ @classmethod
173
+ def from_json_file(cls, file_path: Path) -> "Event":
174
+ if not file_path.exists():
175
+ raise FileNotFoundError(f"File not found: {file_path}")
176
+ with file_path.open("r", encoding="utf-8") as f:
177
+ data = json.load(f)
178
+ return cls.model_validate(data)
@@ -3,6 +3,7 @@ import re
3
3
  from typing import Any, Dict, List, cast
4
4
 
5
5
  import unique_sdk
6
+ from typing_extensions import deprecated
6
7
  from unique_sdk._list_object import ListObject
7
8
 
8
9
  from unique_toolkit._common import _time_utils
@@ -673,6 +674,7 @@ async def modify_message_assessment_async(
673
674
  raise e
674
675
 
675
676
 
677
+ @deprecated("Use stream_complete_with_references instead")
676
678
  def stream_complete_to_chat(
677
679
  company_id: str,
678
680
  user_id: str,
@@ -682,7 +684,43 @@ def stream_complete_to_chat(
682
684
  assistant_id: str,
683
685
  messages: LanguageModelMessages,
684
686
  model_name: LanguageModelName | str,
685
- content_chunks: list[ContentChunk] = [],
687
+ content_chunks: list[ContentChunk] | None = None,
688
+ debug_info: dict = {},
689
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
690
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
691
+ tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
692
+ start_text: str | None = None,
693
+ other_options: dict | None = None,
694
+ ) -> LanguageModelStreamResponse:
695
+ return stream_complete_with_references(
696
+ company_id=company_id,
697
+ user_id=user_id,
698
+ assistant_message_id=assistant_message_id,
699
+ user_message_id=user_message_id,
700
+ chat_id=chat_id,
701
+ assistant_id=assistant_id,
702
+ messages=messages,
703
+ model_name=model_name,
704
+ content_chunks=content_chunks,
705
+ debug_info=debug_info,
706
+ temperature=temperature,
707
+ timeout=timeout,
708
+ tools=tools,
709
+ start_text=start_text,
710
+ other_options=other_options,
711
+ )
712
+
713
+
714
+ def stream_complete_with_references(
715
+ company_id: str,
716
+ user_id: str,
717
+ assistant_message_id: str,
718
+ user_message_id: str,
719
+ chat_id: str,
720
+ assistant_id: str,
721
+ messages: LanguageModelMessages,
722
+ model_name: LanguageModelName | str,
723
+ content_chunks: list[ContentChunk] | None = None,
686
724
  debug_info: dict = {},
687
725
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
688
726
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -719,7 +757,7 @@ def stream_complete_to_chat(
719
757
  temperature=temperature,
720
758
  tools=tools,
721
759
  other_options=other_options,
722
- content_chunks=content_chunks,
760
+ content_chunks=content_chunks or [],
723
761
  )
724
762
 
725
763
  try:
@@ -747,6 +785,7 @@ def stream_complete_to_chat(
747
785
  raise e
748
786
 
749
787
 
788
+ @deprecated("Use stream_complete_with_references_async instead")
750
789
  async def stream_complete_to_chat_async(
751
790
  company_id: str,
752
791
  user_id: str,
@@ -756,7 +795,43 @@ async def stream_complete_to_chat_async(
756
795
  assistant_id: str,
757
796
  messages: LanguageModelMessages,
758
797
  model_name: LanguageModelName | str,
759
- content_chunks: list[ContentChunk] = [],
798
+ content_chunks: list[ContentChunk] | None = None,
799
+ debug_info: dict = {},
800
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
801
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
802
+ tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
803
+ start_text: str | None = None,
804
+ other_options: dict | None = None,
805
+ ) -> LanguageModelStreamResponse:
806
+ return await stream_complete_with_references_async(
807
+ company_id=company_id,
808
+ user_id=user_id,
809
+ assistant_message_id=assistant_message_id,
810
+ user_message_id=user_message_id,
811
+ chat_id=chat_id,
812
+ assistant_id=assistant_id,
813
+ messages=messages,
814
+ model_name=model_name,
815
+ content_chunks=content_chunks,
816
+ debug_info=debug_info,
817
+ temperature=temperature,
818
+ timeout=timeout,
819
+ tools=tools,
820
+ start_text=start_text,
821
+ other_options=other_options,
822
+ )
823
+
824
+
825
+ async def stream_complete_with_references_async(
826
+ company_id: str,
827
+ user_id: str,
828
+ assistant_message_id: str,
829
+ user_message_id: str,
830
+ chat_id: str,
831
+ assistant_id: str,
832
+ messages: LanguageModelMessages,
833
+ model_name: LanguageModelName | str,
834
+ content_chunks: list[ContentChunk] | None = None,
760
835
  debug_info: dict = {},
761
836
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
762
837
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -778,7 +853,7 @@ async def stream_complete_to_chat_async(
778
853
  temperature=temperature,
779
854
  tools=tools,
780
855
  other_options=other_options,
781
- content_chunks=content_chunks,
856
+ content_chunks=content_chunks or [],
782
857
  )
783
858
 
784
859
  try:
@@ -48,8 +48,8 @@ from unique_toolkit.language_model.schemas import (
48
48
  )
49
49
 
50
50
  from .functions import (
51
- stream_complete_to_chat,
52
- stream_complete_to_chat_async,
51
+ stream_complete_with_references,
52
+ stream_complete_with_references_async,
53
53
  )
54
54
 
55
55
  logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
@@ -1084,11 +1084,36 @@ class ChatService:
1084
1084
  label=label,
1085
1085
  )
1086
1086
 
1087
+ @deprecated("Use complete_with_references instead")
1087
1088
  def stream_complete(
1088
1089
  self,
1089
1090
  messages: LanguageModelMessages,
1090
1091
  model_name: LanguageModelName | str,
1091
- content_chunks: list[ContentChunk] = [],
1092
+ content_chunks: list[ContentChunk] | None = None,
1093
+ debug_info: dict = {},
1094
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1095
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
1096
+ tools: Optional[list[LanguageModelTool | LanguageModelToolDescription]] = None,
1097
+ start_text: Optional[str] = None,
1098
+ other_options: Optional[dict] = None,
1099
+ ) -> LanguageModelStreamResponse:
1100
+ return self.complete_with_references(
1101
+ messages=messages,
1102
+ model_name=model_name,
1103
+ content_chunks=content_chunks,
1104
+ debug_info=debug_info,
1105
+ temperature=temperature,
1106
+ timeout=timeout,
1107
+ tools=tools,
1108
+ start_text=start_text,
1109
+ other_options=other_options,
1110
+ )
1111
+
1112
+ def complete_with_references(
1113
+ self,
1114
+ messages: LanguageModelMessages,
1115
+ model_name: LanguageModelName | str,
1116
+ content_chunks: list[ContentChunk] | None = None,
1092
1117
  debug_info: dict = {},
1093
1118
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1094
1119
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -1117,7 +1142,7 @@ class ChatService:
1117
1142
  ]
1118
1143
  )
1119
1144
 
1120
- return stream_complete_to_chat(
1145
+ return stream_complete_with_references(
1121
1146
  company_id=company_id,
1122
1147
  user_id=user_id,
1123
1148
  assistant_message_id=assistant_message_id,
@@ -1139,7 +1164,7 @@ class ChatService:
1139
1164
  self,
1140
1165
  messages: LanguageModelMessages,
1141
1166
  model_name: LanguageModelName | str,
1142
- content_chunks: list[ContentChunk] = [],
1167
+ content_chunks: list[ContentChunk] | None = None,
1143
1168
  debug_info: dict = {},
1144
1169
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1145
1170
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -1147,7 +1172,7 @@ class ChatService:
1147
1172
  start_text: Optional[str] = None,
1148
1173
  other_options: Optional[dict] = None,
1149
1174
  ) -> LanguageModelResponse:
1150
- response = self.stream_complete(
1175
+ response = self.complete_with_references(
1151
1176
  messages=messages,
1152
1177
  model_name=model_name,
1153
1178
  content_chunks=content_chunks,
@@ -1161,11 +1186,12 @@ class ChatService:
1161
1186
 
1162
1187
  return LanguageModelResponse.from_stream_response(response)
1163
1188
 
1189
+ @deprecated("use complete_with_references_async instead.")
1164
1190
  async def stream_complete_async(
1165
1191
  self,
1166
1192
  messages: LanguageModelMessages,
1167
1193
  model_name: LanguageModelName | str,
1168
- content_chunks: list[ContentChunk] = [],
1194
+ content_chunks: list[ContentChunk] | None = None,
1169
1195
  debug_info: dict = {},
1170
1196
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1171
1197
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -1173,10 +1199,31 @@ class ChatService:
1173
1199
  start_text: Optional[str] = None,
1174
1200
  other_options: Optional[dict] = None,
1175
1201
  ) -> LanguageModelStreamResponse:
1176
- """
1177
- Streams a completion in the chat session asynchronously.
1178
- """
1202
+ """Stream a completion in the chat session asynchronously."""
1203
+ return await self.complete_with_references_async(
1204
+ messages=messages,
1205
+ model_name=model_name,
1206
+ content_chunks=content_chunks,
1207
+ debug_info=debug_info,
1208
+ temperature=temperature,
1209
+ timeout=timeout,
1210
+ tools=tools,
1211
+ start_text=start_text,
1212
+ other_options=other_options,
1213
+ )
1179
1214
 
1215
+ async def complete_with_references_async(
1216
+ self,
1217
+ messages: LanguageModelMessages,
1218
+ model_name: LanguageModelName | str,
1219
+ content_chunks: list[ContentChunk] | None = None,
1220
+ debug_info: dict = {},
1221
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1222
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
1223
+ tools: Optional[list[LanguageModelTool | LanguageModelToolDescription]] = None,
1224
+ start_text: Optional[str] = None,
1225
+ other_options: Optional[dict] = None,
1226
+ ) -> LanguageModelStreamResponse:
1180
1227
  [
1181
1228
  company_id,
1182
1229
  user_id,
@@ -1195,7 +1242,7 @@ class ChatService:
1195
1242
  ]
1196
1243
  )
1197
1244
 
1198
- return await stream_complete_to_chat_async(
1245
+ return await stream_complete_with_references_async(
1199
1246
  company_id=company_id,
1200
1247
  user_id=user_id,
1201
1248
  assistant_message_id=assistant_message_id,
@@ -1217,7 +1264,7 @@ class ChatService:
1217
1264
  self,
1218
1265
  messages: LanguageModelMessages,
1219
1266
  model_name: LanguageModelName | str,
1220
- content_chunks: list[ContentChunk] = [],
1267
+ content_chunks: list[ContentChunk] | None,
1221
1268
  debug_info: dict = {},
1222
1269
  temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
1223
1270
  timeout: int = DEFAULT_COMPLETE_TIMEOUT,
@@ -1225,7 +1272,7 @@ class ChatService:
1225
1272
  start_text: Optional[str] = None,
1226
1273
  other_options: Optional[dict] = None,
1227
1274
  ) -> LanguageModelResponse:
1228
- response = self.stream_complete_async(
1275
+ response = self.complete_with_references_async(
1229
1276
  messages=messages,
1230
1277
  model_name=model_name,
1231
1278
  content_chunks=content_chunks,
@@ -3,6 +3,7 @@ import os
3
3
  import re
4
4
  import tempfile
5
5
  from pathlib import Path
6
+ from typing import Any
6
7
 
7
8
  import requests
8
9
  import unique_sdk
@@ -214,7 +215,7 @@ def upload_content_from_bytes(
214
215
  chat_id: str | None = None,
215
216
  skip_ingestion: bool = False,
216
217
  ingestion_config: unique_sdk.Content.IngestionConfig | None = None,
217
- metadata: dict[str, any] | None = None,
218
+ metadata: dict[str, Any] | None = None,
218
219
  ):
219
220
  """
220
221
  Uploads content to the knowledge base.
@@ -229,7 +230,7 @@ def upload_content_from_bytes(
229
230
  chat_id (str | None): The chat ID. Defaults to None.
230
231
  skip_ingestion (bool): Whether to skip ingestion. Defaults to False.
231
232
  ingestion_config (unique_sdk.Content.IngestionConfig | None): The ingestion configuration. Defaults to None.
232
- metadata ( dict[str, any] | None): The metadata for the content. Defaults to None.
233
+ metadata ( dict[str, Any] | None): The metadata for the content. Defaults to None.
233
234
 
234
235
  Returns:
235
236
  Content: The uploaded content.
@@ -263,7 +264,7 @@ def upload_content(
263
264
  chat_id: str | None = None,
264
265
  skip_ingestion: bool = False,
265
266
  ingestion_config: unique_sdk.Content.IngestionConfig | None = None,
266
- metadata: dict[str, any] | None = None,
267
+ metadata: dict[str, Any] | None = None,
267
268
  ):
268
269
  """
269
270
  Uploads content to the knowledge base.
@@ -278,7 +279,7 @@ def upload_content(
278
279
  chat_id (str | None): The chat ID. Defaults to None.
279
280
  skip_ingestion (bool): Whether to skip ingestion. Defaults to False.
280
281
  ingestion_config (unique_sdk.Content.IngestionConfig | None): The ingestion configuration. Defaults to None.
281
- metadata ( dict[str, any] | None): The metadata for the content. Defaults to None.
282
+ metadata ( dict[str, Any] | None): The metadata for the content. Defaults to None.
282
283
 
283
284
  Returns:
284
285
  Content: The uploaded content.
@@ -312,7 +313,7 @@ def _trigger_upload_content(
312
313
  chat_id: str | None = None,
313
314
  skip_ingestion: bool = False,
314
315
  ingestion_config: unique_sdk.Content.IngestionConfig | None = None,
315
- metadata: dict[str, any] | None = None,
316
+ metadata: dict[str, Any] | None = None,
316
317
  ):
317
318
  """
318
319
  Uploads content to the knowledge base.
@@ -327,7 +328,7 @@ def _trigger_upload_content(
327
328
  chat_id (str | None): The chat ID. Defaults to None.
328
329
  skip_ingestion (bool): Whether to skip ingestion. Defaults to False.
329
330
  ingestion_config (unique_sdk.Content.IngestionConfig | None): The ingestion configuration. Defaults to None.
330
- metadata (dict[str, any] | None): The metadata for the content. Defaults to None.
331
+ metadata (dict[str, Any] | None): The metadata for the content. Defaults to None.
331
332
 
332
333
  Returns:
333
334
  Content: The uploaded content.
@@ -1,6 +1,6 @@
1
1
  from datetime import datetime
2
2
  from enum import StrEnum
3
- from typing import Optional
3
+ from typing import Any, Optional
4
4
 
5
5
  from humps import camelize
6
6
  from pydantic import BaseModel, ConfigDict, Field
@@ -54,7 +54,7 @@ class Content(BaseModel):
54
54
  read_url: str | None = None
55
55
  created_at: datetime | None = None
56
56
  updated_at: datetime | None = None
57
- metadata: dict[str, any] | None = None
57
+ metadata: dict[str, Any] | None = None
58
58
  ingestion_config: dict | None = None
59
59
 
60
60
 
@@ -422,7 +422,7 @@ class ContentService:
422
422
  chat_id (str | None): The chat ID. Defaults to None.
423
423
  skip_ingestion (bool): Whether to skip ingestion. Defaults to False.
424
424
  ingestion_config (unique_sdk.Content.IngestionConfig | None): The ingestion configuration. Defaults to None.
425
- metadata (dict[str, any] | None): The metadata to associate with the content. Defaults to None.
425
+ metadata (dict[str, Any] | None): The metadata to associate with the content. Defaults to None.
426
426
 
427
427
  Returns:
428
428
  Content: The uploaded content.
@@ -1,23 +1,33 @@
1
+ import copy
1
2
  import logging
2
- from typing import cast
3
+ from datetime import datetime, timezone
4
+ from typing import Any, cast
3
5
 
4
6
  import unique_sdk
5
7
  from pydantic import BaseModel
6
8
 
9
+ from unique_toolkit.chat.schemas import ChatMessage, ChatMessageRole
7
10
  from unique_toolkit.content.schemas import ContentChunk
8
11
  from unique_toolkit.evaluators import DOMAIN_NAME
9
-
10
- from .constants import (
11
- DEFAULT_COMPLETE_TEMPERATURE,
12
- DEFAULT_COMPLETE_TIMEOUT,
13
- )
14
- from .infos import LanguageModelName
15
- from .schemas import (
12
+ from unique_toolkit.language_model import (
13
+ LanguageModelMessageRole,
16
14
  LanguageModelMessages,
17
15
  LanguageModelResponse,
16
+ LanguageModelStreamResponse,
17
+ LanguageModelStreamResponseMessage,
18
18
  LanguageModelTool,
19
19
  LanguageModelToolDescription,
20
20
  )
21
+ from unique_toolkit.language_model.infos import LanguageModelName
22
+ from unique_toolkit.language_model.reference import (
23
+ PotentialReference,
24
+ add_references_to_message,
25
+ )
26
+
27
+ from .constants import (
28
+ DEFAULT_COMPLETE_TEMPERATURE,
29
+ DEFAULT_COMPLETE_TIMEOUT,
30
+ )
21
31
 
22
32
  logger = logging.getLogger(f"toolkit.{DOMAIN_NAME}.{__name__}")
23
33
 
@@ -36,6 +46,7 @@ def complete(
36
46
  """Call the completion endpoint synchronously without streaming the response.
37
47
 
38
48
  Args:
49
+ ----
39
50
  company_id (str): The company ID associated with the request.
40
51
  messages (LanguageModelMessages): The messages to complete.
41
52
  model_name (LanguageModelName | str): The model name to use for the completion.
@@ -45,6 +56,7 @@ def complete(
45
56
  other_options (Optional[dict]): Additional options to use. Defaults to None.
46
57
 
47
58
  Returns:
59
+ -------
48
60
  LanguageModelResponse: The response object containing the completed result.
49
61
 
50
62
  """
@@ -93,6 +105,7 @@ async def complete_async(
93
105
  the completed result.
94
106
 
95
107
  Args:
108
+ ----
96
109
  company_id (str): The company ID associated with the request.
97
110
  messages (LanguageModelMessages): The messages to complete.
98
111
  model_name (LanguageModelName | str): The model name to use for the completion.
@@ -102,9 +115,11 @@ async def complete_async(
102
115
  other_options (Optional[dict]): The other options to use. Defaults to None.
103
116
 
104
117
  Returns:
118
+ -------
105
119
  LanguageModelResponse: The response object containing the completed result.
106
120
 
107
121
  Raises:
122
+ ------
108
123
  Exception: If an error occurs during the request, an exception is raised
109
124
  and logged.
110
125
 
@@ -198,7 +213,8 @@ def _prepare_completion_params_util(
198
213
  ) -> tuple[dict, str, dict, dict | None]:
199
214
  """Prepare common parameters for completion requests.
200
215
 
201
- Returns:
216
+ Returns
217
+ -------
202
218
  tuple containing:
203
219
  - options (dict): Combined options including tools and temperature
204
220
  - model (str): Resolved model name
@@ -232,3 +248,120 @@ def _prepare_completion_params_util(
232
248
  )
233
249
 
234
250
  return options, model, messages_dict, search_context
251
+
252
+
253
+ def complete_with_references(
254
+ company_id: str,
255
+ messages: LanguageModelMessages,
256
+ model_name: LanguageModelName | str,
257
+ content_chunks: list[ContentChunk] | None = None,
258
+ debug_dict: dict = {},
259
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
260
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
261
+ tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
262
+ start_text: str | None = None,
263
+ other_options: dict[str, Any] | None = None,
264
+ ) -> LanguageModelStreamResponse:
265
+ # Use toolkit language model functions for chat completion
266
+ response = complete(
267
+ company_id=company_id,
268
+ model_name=model_name,
269
+ messages=messages,
270
+ temperature=temperature,
271
+ timeout=timeout,
272
+ tools=tools,
273
+ other_options=other_options,
274
+ )
275
+
276
+ return _create_language_model_stream_response_with_references(
277
+ response=response,
278
+ content_chunks=content_chunks,
279
+ start_text=start_text,
280
+ )
281
+
282
+
283
+ async def complete_with_references_async(
284
+ company_id: str,
285
+ messages: LanguageModelMessages,
286
+ model_name: LanguageModelName | str,
287
+ content_chunks: list[ContentChunk] | None = None,
288
+ debug_dict: dict = {},
289
+ temperature: float = DEFAULT_COMPLETE_TEMPERATURE,
290
+ timeout: int = DEFAULT_COMPLETE_TIMEOUT,
291
+ tools: list[LanguageModelTool | LanguageModelToolDescription] | None = None,
292
+ start_text: str | None = None,
293
+ other_options: dict[str, Any] | None = None,
294
+ ) -> LanguageModelStreamResponse:
295
+ # Use toolkit language model functions for chat completion
296
+ response = await complete_async(
297
+ company_id=company_id,
298
+ model_name=model_name,
299
+ messages=messages,
300
+ temperature=temperature,
301
+ timeout=timeout,
302
+ tools=tools,
303
+ other_options=other_options,
304
+ )
305
+
306
+ return _create_language_model_stream_response_with_references(
307
+ response=response,
308
+ content_chunks=content_chunks,
309
+ start_text=start_text,
310
+ )
311
+
312
+
313
+ def _create_language_model_stream_response_with_references(
314
+ response: LanguageModelResponse,
315
+ content_chunks: list[ContentChunk] | None = None,
316
+ start_text: str | None = None,
317
+ ):
318
+ content = response.choices[0].message.content
319
+ content_chunks = content_chunks or []
320
+
321
+ if content is None:
322
+ raise ValueError("Content is None, which is not supported")
323
+ elif isinstance(content, list):
324
+ raise ValueError("Content is a list, which is not supported")
325
+ else:
326
+ content = start_text or "" + str(content)
327
+
328
+ message = ChatMessage(
329
+ id="msg_unknown",
330
+ text=copy.deepcopy(content),
331
+ role=ChatMessageRole.ASSISTANT,
332
+ created_at=datetime.now(timezone.utc),
333
+ chat_id="chat_unknown",
334
+ )
335
+
336
+ search_context = [
337
+ PotentialReference(
338
+ id=source.id,
339
+ chunk_id=source.id,
340
+ title=source.title,
341
+ key=source.key or "",
342
+ url=source.url,
343
+ )
344
+ for source in content_chunks
345
+ ]
346
+
347
+ message, __ = add_references_to_message(
348
+ message=message,
349
+ search_context=search_context,
350
+ )
351
+
352
+ stream_response_message = LanguageModelStreamResponseMessage(
353
+ id="stream_unknown",
354
+ previous_message_id=None,
355
+ role=LanguageModelMessageRole.ASSISTANT,
356
+ text=message.content or "",
357
+ original_text=content,
358
+ references=[u.model_dump() for u in message.references or []],
359
+ )
360
+
361
+ tool_calls = [r.function for r in response.choices[0].message.tool_calls or []]
362
+ tool_calls = tool_calls if len(tool_calls) > 0 else None
363
+
364
+ return LanguageModelStreamResponse(
365
+ message=stream_response_message,
366
+ tool_calls=tool_calls,
367
+ )