fabricatio 0.2.7.dev5__cp312-cp312-win_amd64.whl → 0.2.8__cp312-cp312-win_amd64.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.
Files changed (49) hide show
  1. fabricatio/__init__.py +4 -11
  2. fabricatio/actions/article.py +219 -92
  3. fabricatio/actions/article_rag.py +86 -21
  4. fabricatio/actions/output.py +71 -3
  5. fabricatio/actions/rag.py +3 -3
  6. fabricatio/actions/rules.py +39 -0
  7. fabricatio/capabilities/advanced_judge.py +23 -0
  8. fabricatio/capabilities/censor.py +90 -0
  9. fabricatio/capabilities/check.py +195 -0
  10. fabricatio/capabilities/correct.py +160 -96
  11. fabricatio/capabilities/propose.py +20 -4
  12. fabricatio/capabilities/rag.py +5 -4
  13. fabricatio/capabilities/rating.py +68 -23
  14. fabricatio/capabilities/review.py +21 -190
  15. fabricatio/capabilities/task.py +9 -10
  16. fabricatio/config.py +11 -3
  17. fabricatio/fs/curd.py +4 -0
  18. fabricatio/models/action.py +24 -10
  19. fabricatio/models/adv_kwargs_types.py +25 -0
  20. fabricatio/models/extra/__init__.py +1 -0
  21. fabricatio/models/extra/advanced_judge.py +32 -0
  22. fabricatio/models/extra/article_base.py +222 -86
  23. fabricatio/models/extra/article_essence.py +49 -176
  24. fabricatio/models/extra/article_main.py +35 -51
  25. fabricatio/models/extra/article_outline.py +10 -156
  26. fabricatio/models/extra/article_proposal.py +29 -13
  27. fabricatio/models/extra/patches.py +7 -0
  28. fabricatio/models/extra/problem.py +153 -0
  29. fabricatio/models/extra/rule.py +65 -0
  30. fabricatio/models/generic.py +311 -94
  31. fabricatio/models/kwargs_types.py +23 -17
  32. fabricatio/models/role.py +4 -1
  33. fabricatio/models/task.py +1 -1
  34. fabricatio/models/tool.py +149 -14
  35. fabricatio/models/usages.py +61 -47
  36. fabricatio/models/utils.py +0 -46
  37. fabricatio/parser.py +7 -8
  38. fabricatio/rust.cp312-win_amd64.pyd +0 -0
  39. fabricatio/{_rust.pyi → rust.pyi} +50 -0
  40. fabricatio/{_rust_instances.py → rust_instances.py} +1 -1
  41. fabricatio/utils.py +54 -0
  42. fabricatio-0.2.8.data/scripts/tdown.exe +0 -0
  43. {fabricatio-0.2.7.dev5.dist-info → fabricatio-0.2.8.dist-info}/METADATA +2 -1
  44. fabricatio-0.2.8.dist-info/RECORD +58 -0
  45. fabricatio/_rust.cp312-win_amd64.pyd +0 -0
  46. fabricatio-0.2.7.dev5.data/scripts/tdown.exe +0 -0
  47. fabricatio-0.2.7.dev5.dist-info/RECORD +0 -47
  48. {fabricatio-0.2.7.dev5.dist-info → fabricatio-0.2.8.dist-info}/WHEEL +0 -0
  49. {fabricatio-0.2.7.dev5.dist-info → fabricatio-0.2.8.dist-info}/licenses/LICENSE +0 -0
@@ -1,17 +1,20 @@
1
- """This module defines generic classes for models in the Fabricatio library."""
1
+ """This module defines generic classes for models in the Fabricatio library, providing a foundation for various model functionalities."""
2
2
 
3
- from abc import abstractmethod
3
+ from abc import ABC, abstractmethod
4
+ from datetime import datetime
4
5
  from pathlib import Path
5
6
  from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Union, final, overload
6
7
 
7
8
  import orjson
8
- from fabricatio._rust import blake3_hash
9
- from fabricatio._rust_instances import TEMPLATE_MANAGER
9
+ import rtoml
10
10
  from fabricatio.config import configs
11
11
  from fabricatio.fs.readers import MAGIKA, safe_text_read
12
12
  from fabricatio.journal import logger
13
- from fabricatio.models.utils import ok
14
13
  from fabricatio.parser import JsonCapture
14
+ from fabricatio.rust import blake3_hash
15
+ from fabricatio.rust_instances import TEMPLATE_MANAGER
16
+ from fabricatio.utils import ok
17
+ from litellm.utils import token_counter
15
18
  from pydantic import (
16
19
  BaseModel,
17
20
  ConfigDict,
@@ -27,13 +30,19 @@ from pydantic.json_schema import GenerateJsonSchema, JsonSchemaValue
27
30
 
28
31
 
29
32
  class Base(BaseModel):
30
- """Base class for all models with Pydantic configuration."""
33
+ """Base class for all models with Pydantic configuration.
34
+
35
+ This class sets up the basic Pydantic configuration for all models in the Fabricatio library.
36
+ """
31
37
 
32
38
  model_config = ConfigDict(use_attribute_docstrings=True)
33
39
 
34
40
 
35
41
  class Display(Base):
36
- """Class that provides a method to display the model in a formatted JSON string."""
42
+ """Class that provides a method to display the model in a formatted JSON string.
43
+
44
+ This class includes methods to display the model in both formatted and compact JSON strings.
45
+ """
37
46
 
38
47
  def display(self) -> str:
39
48
  """Display the model in a formatted JSON string.
@@ -51,23 +60,45 @@ class Display(Base):
51
60
  """
52
61
  return self.model_dump_json()
53
62
 
63
+ @staticmethod
64
+ def seq_display(seq: Iterable["Display"], compact: bool = False) -> str:
65
+ """Display a sequence of Display objects in a formatted JSON string.
66
+
67
+ Args:
68
+ seq (Iterable[Display]): The sequence of Display objects to display.
69
+ compact (bool): Whether to display the sequence in a compact format. Defaults to False.
70
+
71
+ Returns:
72
+ str: The formatted JSON string of the sequence.
73
+ """
74
+ return "\n".join(d.compact() if compact else d.display() for d in seq)
75
+
54
76
 
55
77
  class Named(Base):
56
- """Class that includes a name attribute."""
78
+ """Class that includes a name attribute.
57
79
 
58
- name: str = Field(frozen=True)
80
+ This class adds a name attribute to models, which is intended to be a unique identifier.
81
+ """
82
+
83
+ name: str
59
84
  """The name of the object."""
60
85
 
61
86
 
62
87
  class Described(Base):
63
- """Class that includes a description attribute."""
88
+ """Class that includes a description attribute.
89
+
90
+ This class adds a description attribute to models, providing additional context or information.
91
+ """
64
92
 
65
- description: str = Field(default="", frozen=True)
93
+ description: str
66
94
  """The description of the object."""
67
95
 
68
96
 
69
97
  class AsPrompt(Base):
70
- """Class that provides a method to generate a prompt from the model."""
98
+ """Class that provides a method to generate a prompt from the model.
99
+
100
+ This class includes a method to generate a prompt based on the model's attributes.
101
+ """
71
102
 
72
103
  @final
73
104
  def as_prompt(self) -> str:
@@ -82,33 +113,81 @@ class AsPrompt(Base):
82
113
  )
83
114
 
84
115
  @abstractmethod
85
- def _as_prompt_inner(self) -> Dict[str, str]: ...
116
+ def _as_prompt_inner(self) -> Dict[str, str]:
117
+ """Generate the inner part of the prompt.
118
+
119
+ This method should be implemented by subclasses to provide the specific data for the prompt.
120
+
121
+ Returns:
122
+ Dict[str, str]: The data for the prompt.
123
+ """
86
124
 
87
125
 
88
126
  class WithRef[T](Base):
89
- """Class that provides a reference to another object."""
127
+ """Class that provides a reference to another object.
128
+
129
+ This class manages a reference to another object, allowing for easy access and updates.
130
+ """
90
131
 
91
132
  _reference: Optional[T] = PrivateAttr(None)
92
133
 
93
134
  @property
94
135
  def referenced(self) -> T:
95
- """Get the referenced object."""
96
- return ok(self._reference, "_reference is None")
136
+ """Get the referenced object.
97
137
 
98
- def update_ref[S: "WithRef"](self: S, reference: T | S) -> S: # noqa: PYI019
99
- """Update the reference of the object."""
138
+ Returns:
139
+ T: The referenced object.
140
+
141
+ Raises:
142
+ ValueError: If the reference is not set.
143
+ """
144
+ return ok(
145
+ self._reference, f"`{self.__class__.__name__}`'s `_reference` field is None. Have you called `update_ref`?"
146
+ )
147
+
148
+ @overload
149
+ def update_ref[S: WithRef](self: S, reference: T) -> S: ...
150
+ @overload
151
+ def update_ref[S: WithRef](self: S, reference: "WithRef[T]") -> S: ...
152
+ @overload
153
+ def update_ref[S: WithRef](self: S, reference: None = None) -> S: ...
154
+ def update_ref[S: WithRef](self: S, reference: Union[T, "WithRef[T]", None] = None) -> S: # noqa: PYI019
155
+ """Update the reference of the object.
156
+
157
+ Args:
158
+ reference (Union[T, WithRef[T], None]): The new reference to set.
159
+
160
+ Returns:
161
+ S: The current instance with the updated reference.
162
+ """
100
163
  if isinstance(reference, self.__class__):
101
164
  self._reference = reference.referenced
102
165
  else:
103
- self._reference = reference
166
+ self._reference = reference # pyright: ignore [reportAttributeAccessIssue]
104
167
  return self
105
168
 
169
+ def derive[S: WithRef](self: S, reference: Any) -> S: # noqa: PYI019
170
+ """Derive a new object from the current object.
171
+
172
+ Args:
173
+ reference (Any): The reference for the new object.
174
+
175
+ Returns:
176
+ S: A new instance derived from the current object with the provided reference.
177
+ """
178
+ new = self.model_copy()
179
+ new._reference = reference
180
+ return new
181
+
106
182
 
107
183
  class PersistentAble(Base):
108
- """Class that provides a method to persist the object."""
184
+ """Class that provides a method to persist the object.
185
+
186
+ This class includes methods to persist the object to a file or directory.
187
+ """
109
188
 
110
189
  def persist(self, path: str | Path) -> Self:
111
- """Persist the object to a file.
190
+ """Persist the object to a file or directory.
112
191
 
113
192
  Args:
114
193
  path (str | Path): The path to save the object.
@@ -118,16 +197,27 @@ class PersistentAble(Base):
118
197
  """
119
198
  p = Path(path)
120
199
  out = self.model_dump_json()
200
+
201
+ # Generate a timestamp in the format YYYYMMDD_HHMMSS
202
+ timestamp = datetime.now().strftime("%Y%m%d")
203
+
204
+ # Generate the hash
205
+ file_hash = blake3_hash(out.encode())[:6]
206
+
207
+ # Construct the file name with timestamp and hash
208
+ file_name = f"{self.__class__.__name__}_{timestamp}_{file_hash}.json"
209
+
121
210
  if p.is_dir():
122
- p.joinpath(f"{self.__class__.__name__}_{blake3_hash(out.encode())[:6]}.json").write_text(
123
- out, encoding="utf-8"
124
- )
125
- return self
126
- p.mkdir(exist_ok=True, parents=True)
127
- p.write_text(out, encoding="utf-8")
211
+ p.joinpath(file_name).write_text(out, encoding="utf-8")
212
+ else:
213
+ p.mkdir(exist_ok=True, parents=True)
214
+ p.write_text(out, encoding="utf-8")
215
+
216
+ logger.info(f"Persisted `{self.__class__.__name__}` to {p.as_posix()}")
128
217
  return self
129
218
 
130
- def from_persistent(self, path: str | Path) -> Self:
219
+ @classmethod
220
+ def from_persistent(cls, path: str | Path) -> Self:
131
221
  """Load the object from a file.
132
222
 
133
223
  Args:
@@ -136,22 +226,42 @@ class PersistentAble(Base):
136
226
  Returns:
137
227
  Self: The current instance of the object.
138
228
  """
139
- return self.model_validate_json(Path(path).read_text(encoding="utf-8"))
229
+ return cls.model_validate_json(safe_text_read(path))
140
230
 
141
231
 
142
232
  class ModelHash(Base):
143
- """Class that provides a hash value for the object."""
233
+ """Class that provides a hash value for the object.
234
+
235
+ This class includes a method to calculate a hash value for the object based on its JSON representation.
236
+ """
144
237
 
145
238
  def __hash__(self) -> int:
146
- """Calculates a hash value for the ArticleBase object based on its model_dump_json representation."""
239
+ """Calculates a hash value for the object based on its model_dump_json representation.
240
+
241
+ Returns:
242
+ int: The hash value of the object.
243
+ """
147
244
  return hash(self.model_dump_json())
148
245
 
149
246
 
150
247
  class UpdateFrom(Base):
151
- """Class that provides a method to update the object from another object."""
248
+ """Class that provides a method to update the object from another object.
249
+
250
+ This class includes methods to update the current object with the attributes of another object.
251
+ """
152
252
 
153
253
  def update_pre_check(self, other: Self) -> Self:
154
- """Pre-check for updating the object from another object."""
254
+ """Pre-check for updating the object from another object.
255
+
256
+ Args:
257
+ other (Self): The other object to update from.
258
+
259
+ Returns:
260
+ Self: The current instance after pre-check.
261
+
262
+ Raises:
263
+ TypeError: If the other object is not of the same type.
264
+ """
155
265
  if not isinstance(other, self.__class__):
156
266
  raise TypeError(f"Cannot update from a non-{self.__class__.__name__} instance.")
157
267
 
@@ -159,16 +269,35 @@ class UpdateFrom(Base):
159
269
 
160
270
  @abstractmethod
161
271
  def update_from_inner(self, other: Self) -> Self:
162
- """Updates the current instance with the attributes of another instance."""
272
+ """Updates the current instance with the attributes of another instance.
273
+
274
+ This method should be implemented by subclasses to provide the specific update logic.
275
+
276
+ Args:
277
+ other (Self): The other instance to update from.
278
+
279
+ Returns:
280
+ Self: The current instance with updated attributes.
281
+ """
163
282
 
164
283
  @final
165
284
  def update_from(self, other: Self) -> Self:
166
- """Updates the current instance with the attributes of another instance."""
285
+ """Updates the current instance with the attributes of another instance.
286
+
287
+ Args:
288
+ other (Self): The other instance to update from.
289
+
290
+ Returns:
291
+ Self: The current instance with updated attributes.
292
+ """
167
293
  return self.update_pre_check(other).update_from_inner(other)
168
294
 
169
295
 
170
296
  class ResolveUpdateConflict(Base):
171
- """Class that provides a method to update the object from another object."""
297
+ """Class that provides a method to update the object from another object.
298
+
299
+ This class includes a method to resolve conflicts when updating the object from another object.
300
+ """
172
301
 
173
302
  @abstractmethod
174
303
  def resolve_update_conflict(self, other: Self) -> str:
@@ -183,7 +312,10 @@ class ResolveUpdateConflict(Base):
183
312
 
184
313
 
185
314
  class Introspect(Base):
186
- """Class that provides a method to introspect the object."""
315
+ """Class that provides a method to introspect the object.
316
+
317
+ This class includes a method to perform internal introspection of the object.
318
+ """
187
319
 
188
320
  @abstractmethod
189
321
  def introspect(self) -> str:
@@ -195,7 +327,10 @@ class Introspect(Base):
195
327
 
196
328
 
197
329
  class WithBriefing(Named, Described):
198
- """Class that provides a briefing based on the name and description."""
330
+ """Class that provides a briefing based on the name and description.
331
+
332
+ This class combines the name and description attributes to provide a brief summary of the object.
333
+ """
199
334
 
200
335
  @property
201
336
  def briefing(self) -> str:
@@ -206,47 +341,31 @@ class WithBriefing(Named, Described):
206
341
  """
207
342
  return f"{self.name}: {self.description}" if self.description else self.name
208
343
 
209
- def _prepend_inner(self, input_text: str) -> str:
210
- return f"# your personal briefing: \n{self.briefing}\n{input_text}"
211
344
 
212
- def prepend_sys_msg[D: (Dict[str, Any], str)](self, system_msg_like: D = "") -> Dict[str, Any]:
213
- """Prepend the system message with the briefing.
345
+ class UnsortGenerate(GenerateJsonSchema):
346
+ """Class that provides a reverse JSON schema of the model.
347
+
348
+ This class overrides the sorting behavior of the JSON schema generation to maintain the original order.
349
+ """
350
+
351
+ def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue:
352
+ """Not sort.
214
353
 
215
354
  Args:
216
- system_msg_like (str | dict): The system message or a dictionary containing the system message.
217
-
218
- Returns:
219
- dict: The system message with the briefing prepended.
220
- """
221
- match system_msg_like:
222
- case dict(d):
223
- d["system_message"] = self._prepend_inner(d.get("system_message", ""))
224
- return d
225
- case str(s):
226
- return {"system_message": self._prepend_inner(s)}
227
- case _:
228
- raise TypeError(f"{system_msg_like} is not a dict or str")
229
-
230
-
231
- class ReverseGenerate(GenerateJsonSchema):
232
- """Class that provides a reverse JSON schema of the model."""
233
-
234
- def _sort_recursive(self, value: Any, parent_key: str | None = None) -> Any:
235
- if isinstance(value, dict):
236
- sorted_dict: dict[str, JsonSchemaValue] = {}
237
- # Reverse all keys regardless of parent_key
238
- keys = reversed(value.keys())
239
- for key in keys:
240
- sorted_dict[key] = self._sort_recursive(value[key], parent_key=key)
241
- return sorted_dict
242
- if isinstance(value, list):
243
- # Reverse list order and process each item
244
- return [self._sort_recursive(item, parent_key) for item in reversed(value)]
355
+ value (JsonSchemaValue): The JSON schema value to sort.
356
+ parent_key (str | None): The parent key of the JSON schema value.
357
+
358
+ Returns:
359
+ JsonSchemaValue: The JSON schema value without sorting.
360
+ """
245
361
  return value
246
362
 
247
363
 
248
364
  class WithFormatedJsonSchema(Base):
249
- """Class that provides a formatted JSON schema of the model."""
365
+ """Class that provides a formatted JSON schema of the model.
366
+
367
+ This class includes a method to generate a formatted JSON schema of the model.
368
+ """
250
369
 
251
370
  @classmethod
252
371
  def formated_json_schema(cls) -> str:
@@ -256,31 +375,32 @@ class WithFormatedJsonSchema(Base):
256
375
  str: The JSON schema of the model in a formatted string.
257
376
  """
258
377
  return orjson.dumps(
259
- cls.model_json_schema(schema_generator=ReverseGenerate),
378
+ cls.model_json_schema(schema_generator=UnsortGenerate),
260
379
  option=orjson.OPT_INDENT_2,
261
380
  ).decode()
262
381
 
263
382
 
264
383
  class CreateJsonObjPrompt(WithFormatedJsonSchema):
265
- """Class that provides a prompt for creating a JSON object."""
384
+ """Class that provides a prompt for creating a JSON object.
385
+
386
+ This class includes a method to create a prompt for creating a JSON object based on the model's schema and a requirement.
387
+ """
266
388
 
267
389
  @classmethod
268
390
  @overload
269
391
  def create_json_prompt(cls, requirement: List[str]) -> List[str]: ...
270
-
271
392
  @classmethod
272
393
  @overload
273
394
  def create_json_prompt(cls, requirement: str) -> str: ...
274
-
275
395
  @classmethod
276
396
  def create_json_prompt(cls, requirement: str | List[str]) -> str | List[str]:
277
397
  """Create the prompt for creating a JSON object with given requirement.
278
398
 
279
399
  Args:
280
- requirement (str): The requirement for the JSON object.
400
+ requirement (str | List[str]): The requirement for the JSON object.
281
401
 
282
402
  Returns:
283
- str: The prompt for creating a JSON object with given requirement.
403
+ str | List[str]: The prompt for creating a JSON object with given requirement.
284
404
  """
285
405
  if isinstance(requirement, str):
286
406
  return TEMPLATE_MANAGER.render_template(
@@ -297,7 +417,10 @@ class CreateJsonObjPrompt(WithFormatedJsonSchema):
297
417
 
298
418
 
299
419
  class InstantiateFromString(Base):
300
- """Class that provides a method to instantiate the class from a string."""
420
+ """Class that provides a method to instantiate the class from a string.
421
+
422
+ This class includes a method to instantiate the class from a JSON string representation.
423
+ """
301
424
 
302
425
  @classmethod
303
426
  def instantiate_from_string(cls, string: str) -> Self | None:
@@ -309,15 +432,37 @@ class InstantiateFromString(Base):
309
432
  Returns:
310
433
  Self | None: The instance of the class or None if the string is not valid.
311
434
  """
312
- return JsonCapture.convert_with(string, cls.model_validate_json)
435
+ obj = JsonCapture.convert_with(string, cls.model_validate_json)
436
+ logger.debug(f"Instantiate `{cls.__name__}` from string, {'Failed' if obj is None else 'Success'}.")
437
+ return obj
313
438
 
314
439
 
315
440
  class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
316
- """Class that provides a method to propose a JSON object based on the requirement."""
441
+ """Class that provides a method to propose a JSON object based on the requirement.
442
+
443
+ This class combines the functionality to create a prompt for a JSON object and instantiate it from a string.
444
+ """
445
+
446
+
447
+ class SketchedAble(ProposedAble, Display):
448
+ """Class that provides a method to scratch the object.
449
+
450
+ This class combines the functionality to propose a JSON object, instantiate it from a string, and display it.
451
+ """
452
+
453
+
454
+ class ProposedUpdateAble(SketchedAble, UpdateFrom, ABC):
455
+ """Make the obj can be updated from the proposed obj in place.
456
+
457
+ This class provides the ability to update an object in place from a proposed object.
458
+ """
317
459
 
318
460
 
319
461
  class FinalizedDumpAble(Base):
320
- """Class that provides a method to finalize the dump of the object."""
462
+ """Class that provides a method to finalize the dump of the object.
463
+
464
+ This class includes methods to finalize the JSON representation of the object and dump it to a file.
465
+ """
321
466
 
322
467
  def finalized_dump(self) -> str:
323
468
  """Finalize the dump of the object.
@@ -340,12 +485,11 @@ class FinalizedDumpAble(Base):
340
485
  return self
341
486
 
342
487
 
343
- class CensoredAble(ProposedAble, FinalizedDumpAble):
344
- """Class that provides a method to censor the object."""
345
-
346
-
347
488
  class WithDependency(Base):
348
- """Class that manages file dependencies."""
489
+ """Class that manages file dependencies.
490
+
491
+ This class includes methods to manage file dependencies required for reading or writing.
492
+ """
349
493
 
350
494
  dependencies: List[str] = Field(default_factory=list)
351
495
  """The file dependencies which is needed to read or write to meet a specific requirement, a list of file paths."""
@@ -432,30 +576,42 @@ class WithDependency(Base):
432
576
  )
433
577
 
434
578
 
435
- class PrepareVectorization(Base):
436
- """Class that prepares the vectorization of the model."""
579
+ class Vectorizable(Base):
580
+ """Class that prepares the vectorization of the model.
581
+
582
+ This class includes methods to prepare the model for vectorization, ensuring it fits within a specified token length.
583
+ """
437
584
 
438
- @abstractmethod
439
585
  def _prepare_vectorization_inner(self) -> str:
440
- """Prepare the vectorization of the model."""
586
+ return rtoml.dumps(self.model_dump())
441
587
 
588
+ @final
442
589
  def prepare_vectorization(self, max_length: Optional[int] = None) -> str:
443
590
  """Prepare the vectorization of the model.
444
591
 
592
+ Args:
593
+ max_length (Optional[int]): The maximum token length for the vectorization. Defaults to the configuration.
594
+
445
595
  Returns:
446
596
  str: The prepared vectorization of the model.
597
+
598
+ Raises:
599
+ ValueError: If the chunk exceeds the maximum sequence length.
447
600
  """
448
601
  max_length = max_length or configs.embedding.max_sequence_length
449
602
  chunk = self._prepare_vectorization_inner()
450
- if max_length and len(chunk) > max_length:
451
- logger.error(err := f"Chunk exceeds maximum sequence length {max_length}.")
603
+ if max_length and (length := token_counter(text=chunk)) > max_length:
604
+ logger.error(err := f"Chunk exceeds maximum sequence length {max_length}, got {length}, see {chunk}")
452
605
  raise ValueError(err)
453
606
 
454
607
  return chunk
455
608
 
456
609
 
457
610
  class ScopedConfig(Base):
458
- """Class that manages a scoped configuration."""
611
+ """Class that manages a scoped configuration.
612
+
613
+ This class includes attributes and methods to manage configuration settings scoped to the instance.
614
+ """
459
615
 
460
616
  llm_api_endpoint: Optional[HttpUrl] = None
461
617
  """The OpenAI API endpoint."""
@@ -513,15 +669,19 @@ class ScopedConfig(Base):
513
669
 
514
670
  embedding_dimensions: Optional[PositiveInt] = None
515
671
  """The dimensions of the embedding."""
672
+
516
673
  embedding_caching: Optional[bool] = False
517
674
  """Whether to cache the embedding result."""
518
675
 
519
676
  milvus_uri: Optional[HttpUrl] = Field(default=None)
520
677
  """The URI of the Milvus server."""
678
+
521
679
  milvus_token: Optional[SecretStr] = Field(default=None)
522
680
  """The token for the Milvus server."""
681
+
523
682
  milvus_timeout: Optional[PositiveFloat] = Field(default=None)
524
683
  """The timeout for the Milvus server."""
684
+
525
685
  milvus_dimensions: Optional[PositiveInt] = Field(default=None)
526
686
  """The dimensions of the Milvus server."""
527
687
 
@@ -563,3 +723,60 @@ class ScopedConfig(Base):
563
723
  if (attr := getattr(self, attr_name)) is not None and getattr(other, attr_name) is None:
564
724
  setattr(other, attr_name, attr)
565
725
  return self
726
+
727
+
728
+ class Patch[T](ProposedAble):
729
+ """Base class for patches.
730
+
731
+ This class provides a base implementation for patches that can be applied to other objects.
732
+ """
733
+
734
+ def apply(self, other: T) -> T:
735
+ """Apply the patch to another instance.
736
+
737
+ Args:
738
+ other (T): The instance to apply the patch to.
739
+
740
+ Returns:
741
+ T: The instance with the patch applied.
742
+
743
+ Raises:
744
+ ValueError: If a field in the patch is not found in the target instance.
745
+ """
746
+ for field in self.__class__.model_fields:
747
+ if not hasattr(other, field):
748
+ raise ValueError(f"{field} not found in {other}, are you applying to the wrong type?")
749
+ setattr(other, field, getattr(self, field))
750
+ return other
751
+
752
+
753
+ class SequencePatch[T](ProposedUpdateAble):
754
+ """Base class for patches.
755
+
756
+ This class provides a base implementation for patches that can be applied to sequences of objects.
757
+ """
758
+
759
+ tweaked: List[T]
760
+ """Tweaked content list"""
761
+
762
+ def update_from_inner(self, other: Self) -> Self:
763
+ """Updates the current instance with the attributes of another instance.
764
+
765
+ Args:
766
+ other (Self): The other instance to update from.
767
+
768
+ Returns:
769
+ Self: The current instance with updated attributes.
770
+ """
771
+ self.tweaked.clear()
772
+ self.tweaked.extend(other.tweaked)
773
+ return self
774
+
775
+ @classmethod
776
+ def default(cls) -> Self:
777
+ """Defaults to empty list.
778
+
779
+ Returns:
780
+ Self: A new instance with an empty list of tweaks.
781
+ """
782
+ return cls(tweaked=[])