fabricatio 0.2.7.dev5__cp312-cp312-win_amd64.whl → 0.2.8.dev0__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.
Binary file
@@ -1,5 +1,6 @@
1
1
  """Actions for transmitting tasks to targets."""
2
2
 
3
+ from asyncio import gather
3
4
  from pathlib import Path
4
5
  from typing import Any, Callable, List, Optional
5
6
 
@@ -55,13 +56,14 @@ class GenerateArticleProposal(Action):
55
56
  task_input: Optional[Task] = None,
56
57
  article_briefing: Optional[str] = None,
57
58
  article_briefing_path: Optional[str] = None,
59
+ langauge: Optional[str] = None,
58
60
  **_,
59
61
  ) -> Optional[ArticleProposal]:
60
62
  if article_briefing is None and article_briefing_path is None and task_input is None:
61
63
  logger.error("Task not approved, since all inputs are None.")
62
64
  return None
63
65
 
64
- return ok(
66
+ proposal = ok(
65
67
  await self.propose(
66
68
  ArticleProposal,
67
69
  briefing := (
@@ -78,8 +80,12 @@ class GenerateArticleProposal(Action):
78
80
  ),
79
81
  **self.prepend_sys_msg(),
80
82
  ),
81
- "Could not generate the proposal."
83
+ "Could not generate the proposal.",
82
84
  ).update_ref(briefing)
85
+ if langauge:
86
+ proposal.language = langauge
87
+
88
+ return proposal
83
89
 
84
90
 
85
91
  class GenerateOutline(Action):
@@ -102,27 +108,92 @@ class GenerateOutline(Action):
102
108
  "Could not generate the outline.",
103
109
  )
104
110
 
105
- manual = ok(await self.draft_rating_manual(
106
- topic=(
107
- topic
108
- := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
111
+ introspect_manual = ok(
112
+ await self.draft_rating_manual(
113
+ topic=(
114
+ intro_topic
115
+ := "Fix the error in the article outline, make sure there is no more error in the article outline."
116
+ ),
109
117
  ),
110
- ),"Could not generate the rating manual.")
118
+ "Could not generate the rating manual.",
119
+ )
111
120
 
112
- while pack := out.find_illegal():
121
+ while pack := out.find_introspected():
113
122
  component, err = ok(pack)
114
- logger.warning(f"Found error in the outline: \n{err}")
115
- corrected = ok(await self.correct_obj(
116
- component,
117
- reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}",
118
- topic=topic,
119
- rating_manual=manual,
120
- supervisor_check=False,
121
- ),"Could not correct the component.")
123
+ logger.warning(f"Found introspected error: {err}")
124
+ corrected = ok(
125
+ await self.correct_obj(
126
+ component,
127
+ reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}",
128
+ topic=intro_topic,
129
+ rating_manual=introspect_manual,
130
+ supervisor_check=False,
131
+ ),
132
+ "Could not correct the component.",
133
+ )
122
134
  component.update_from(corrected)
135
+
136
+ ref_manual = ok(
137
+ await self.draft_rating_manual(
138
+ topic=(
139
+ ref_topic
140
+ := "Fix the internal referring error, make sure there is no more `ArticleRef` pointing to a non-existing article component."
141
+ ),
142
+ ),
143
+ "Could not generate the rating manual.",
144
+ )
145
+
146
+ while pack := out.find_illegal_ref():
147
+ ref, err = ok(pack)
148
+ logger.warning(f"Found illegal referring error: {err}")
149
+ ok(
150
+ await self.correct_obj_inplace(
151
+ ref,
152
+ reference=f"# Original Article Outline\n{out.display()}\n# Error Need to be fixed\n{err}\n\n",
153
+ topic=ref_topic,
154
+ rating_manual=ref_manual,
155
+ supervisor_check=False,
156
+ )
157
+ )
123
158
  return out.update_ref(article_proposal)
124
159
 
125
160
 
161
+ class GenerateArticle(Action):
162
+ """Generate the article based on the outline."""
163
+
164
+ output_key: str = "article"
165
+ """The key of the output data."""
166
+
167
+ async def _execute(
168
+ self,
169
+ article_outline: ArticleOutline,
170
+ **_,
171
+ ) -> Optional[Article]:
172
+ article: Article = Article.from_outline(ok(article_outline, "Article outline not specified.")).update_ref(
173
+ article_outline
174
+ )
175
+
176
+ write_para_manual = ok(
177
+ await self.draft_rating_manual(w_topic := "write the following paragraph in the subsection.")
178
+ )
179
+
180
+ await gather(
181
+ *[
182
+ self.correct_obj_inplace(
183
+ subsec,
184
+ reference=f"# Original Article Outline\n{article_outline.display()}\n# Error Need to be fixed\n{err}",
185
+ topic=w_topic,
186
+ rating_manual=write_para_manual,
187
+ supervisor_check=False,
188
+ )
189
+ for _, __, subsec in article.iter_subsections()
190
+ if (err := subsec.introspect())
191
+ ],
192
+ return_exceptions=True,
193
+ )
194
+ return article
195
+
196
+
126
197
  class CorrectProposal(Action):
127
198
  """Correct the proposal of the article."""
128
199
 
@@ -150,60 +221,6 @@ class CorrectOutline(Action):
150
221
  )
151
222
 
152
223
 
153
- class GenerateArticle(Action):
154
- """Generate the article based on the outline."""
155
-
156
- output_key: str = "article"
157
- """The key of the output data."""
158
-
159
- async def _execute(
160
- self,
161
- article_outline: ArticleOutline,
162
- **_,
163
- ) -> Optional[Article]:
164
- article: Article = Article.from_outline(article_outline).update_ref(article_outline)
165
-
166
- writing_manual = ok(await self.draft_rating_manual(
167
- topic=(
168
- topic_1
169
- := "improve the content of the subsection to fit the outline. SHALL never add or remove any section or subsection, you can only add or delete paragraphs within the subsection."
170
- ),
171
- ))
172
- err_resolve_manual = ok(await self.draft_rating_manual(
173
- topic=(topic_2 := "this article component has violated the constrain, please correct it.")
174
- ))
175
- for c, deps in article.iter_dfs_with_deps(chapter=False):
176
- logger.info(f"Updating the article component: \n{c.display()}")
177
-
178
- out = ok(
179
- await self.correct_obj(
180
- c,
181
- reference=(
182
- ref := f"{article_outline.referenced.as_prompt()}\n" + "\n".join(d.display() for d in deps)
183
- ),
184
- topic=topic_1,
185
- rating_manual=writing_manual,
186
- supervisor_check=False,
187
- ),
188
- "Could not correct the article component.",
189
- )
190
- while err := c.resolve_update_conflict(out):
191
- logger.warning(f"Found error in the article component: \n{err}")
192
- out = ok(
193
- await self.correct_obj(
194
- out,
195
- reference=f"{ref}\n\n# Violated Error\n{err}",
196
- topic=topic_2,
197
- rating_manual=err_resolve_manual,
198
- supervisor_check=False,
199
- ),
200
- "Could not correct the article component.",
201
- )
202
-
203
- c.update_from(out)
204
- return article
205
-
206
-
207
224
  class CorrectArticle(Action):
208
225
  """Correct the article based on the outline."""
209
226
 
@@ -3,8 +3,9 @@
3
3
  from pathlib import Path
4
4
  from typing import Optional
5
5
 
6
+ from fabricatio.journal import logger
6
7
  from fabricatio.models.action import Action
7
- from fabricatio.models.generic import FinalizedDumpAble
8
+ from fabricatio.models.generic import FinalizedDumpAble, PersistentAble
8
9
  from fabricatio.models.task import Task
9
10
  from fabricatio.models.utils import ok
10
11
 
@@ -32,3 +33,37 @@ class DumpFinalizedOutput(Action):
32
33
  )
33
34
  ok(to_dump, "Could not dump the data since the path is not specified.").finalized_dump_to(dump_path)
34
35
  return dump_path.as_posix()
36
+
37
+
38
+ class PersistentAll(Action):
39
+ """Persist all the data to a file."""
40
+
41
+ output_key: str = "persistent_count"
42
+
43
+ async def _execute(
44
+ self,
45
+ task_input: Optional[Task] = None,
46
+ persist_dir: Optional[str | Path] = None,
47
+ **cxt,
48
+ ) -> int:
49
+ persist_dir = Path(
50
+ persist_dir
51
+ or ok(
52
+ await self.awhich_pathstr(
53
+ f"{ok(task_input, 'Neither `task_input` and `dump_path` is provided.').briefing}\n\nExtract a single path of the file, to which I will persist the data."
54
+ ),
55
+ "Can not find the path of file to persist the data.",
56
+ )
57
+ )
58
+
59
+ count = 0
60
+ if persist_dir.is_file():
61
+ logger.warning("Dump should be a directory, but it is a file. Skip dumping.")
62
+ return count
63
+ persist_dir.mkdir(parents=True, exist_ok=True)
64
+ for v in cxt.values():
65
+ if isinstance(v, PersistentAble):
66
+ v.persist(persist_dir)
67
+ count += 1
68
+
69
+ return count
@@ -10,7 +10,7 @@ from typing import Optional, Unpack, cast
10
10
  from fabricatio._rust_instances import TEMPLATE_MANAGER
11
11
  from fabricatio.capabilities.review import Review, ReviewResult
12
12
  from fabricatio.config import configs
13
- from fabricatio.models.generic import CensoredAble, Display, ProposedAble, WithBriefing
13
+ from fabricatio.models.generic import CensoredAble, Display, ProposedAble, ProposedUpdateAble, WithBriefing
14
14
  from fabricatio.models.kwargs_types import CensoredCorrectKwargs, CorrectKwargs, ReviewKwargs
15
15
  from fabricatio.models.task import Task
16
16
  from questionary import confirm, text
@@ -134,12 +134,32 @@ class Correct(Review):
134
134
  while await confirm("Begin to correct obj above with human censorship?").ask_async():
135
135
  while (topic := await text("What is the topic of the obj reviewing?").ask_async()) is not None and topic:
136
136
  ...
137
- if (modified_obj := await self.correct_obj(
138
- last_modified_obj,
139
- topic=topic,
140
- **kwargs,
141
- )) is None:
137
+ if (
138
+ modified_obj := await self.correct_obj(
139
+ last_modified_obj,
140
+ topic=topic,
141
+ **kwargs,
142
+ )
143
+ ) is None:
142
144
  break
143
145
  last_modified_obj = modified_obj
144
146
  rprint(last_modified_obj.finalized_dump())
145
147
  return modified_obj or last_modified_obj
148
+
149
+ async def correct_obj_inplace[M: ProposedUpdateAble](
150
+ self, obj: M, **kwargs: Unpack[CorrectKwargs[ReviewResult[str]]]
151
+ ) -> Optional[M]:
152
+ """Correct an object in place based on defined criteria and templates.
153
+
154
+ Args:
155
+ obj (M): The object to be corrected.
156
+ **kwargs (Unpack[CensoredCorrectKwargs]): Additional keyword arguments for the correction process.
157
+
158
+ Returns:
159
+ Optional[M]: The corrected object, or None if correction fails.
160
+ """
161
+ corrected_obj = await self.correct_obj(obj, **kwargs)
162
+ if corrected_obj is None:
163
+ return corrected_obj
164
+ obj.update_from(corrected_obj)
165
+ return obj
@@ -170,6 +170,8 @@ class WorkFlow(WithBriefing, ToolBoxUsage):
170
170
  # Update context with modified values
171
171
  modified_ctx = await act_task
172
172
  logger.success(f"Step execution finished: {current_action}")
173
+ if step.output_key:
174
+ logger.success(f"Setting output: {step.output_key}")
173
175
  await self._context.put(modified_ctx)
174
176
 
175
177
  logger.success(f"Workflow execution finished: {self.name}")
@@ -1,24 +1,22 @@
1
1
  """A foundation for hierarchical document components with dependency tracking."""
2
- from abc import ABC
2
+
3
+ from abc import abstractmethod
3
4
  from enum import StrEnum
4
- from typing import TYPE_CHECKING, Generator, List, Optional, Self, Union, overload
5
+ from functools import cache
6
+ from itertools import chain
7
+ from typing import Generator, List, Optional, Self, Tuple
5
8
 
6
9
  from fabricatio.models.generic import (
7
- Base,
8
10
  CensoredAble,
9
11
  Display,
12
+ FinalizedDumpAble,
10
13
  Introspect,
11
14
  ModelHash,
12
15
  PersistentAble,
13
- ProposedAble,
16
+ ProposedUpdateAble,
14
17
  ResolveUpdateConflict,
15
- UpdateFrom,
16
18
  )
17
19
 
18
- if TYPE_CHECKING:
19
- from fabricatio.models.extra.article_main import Article
20
- from fabricatio.models.extra.article_outline import ArticleOutline
21
-
22
20
 
23
21
  class ReferringType(StrEnum):
24
22
  """Enumeration of different types of references that can be made in an article."""
@@ -28,7 +26,11 @@ class ReferringType(StrEnum):
28
26
  SUBSECTION = "subsection"
29
27
 
30
28
 
31
- class ArticleRef(CensoredAble):
29
+ type RefKey = Tuple[str, Optional[str], Optional[str]]
30
+
31
+
32
+ @cache
33
+ class ArticleRef(CensoredAble, Display, ProposedUpdateAble):
32
34
  """Reference to a specific chapter, section or subsection within the article. You SHALL not refer to an article component that is external and not present within our own article.
33
35
 
34
36
  Examples:
@@ -61,30 +63,21 @@ class ArticleRef(CensoredAble):
61
63
  ```
62
64
  """
63
65
 
64
- referred_subsection_title: Optional[str] = None
65
- """`title` Field of the referenced subsection."""
66
-
67
- referred_section_title: Optional[str] = None
68
- """`title` Field of the referenced section."""
69
-
70
66
  referred_chapter_title: str
71
67
  """`title` Field of the referenced chapter"""
68
+ referred_section_title: Optional[str] = None
69
+ """`title` Field of the referenced section."""
70
+ referred_subsection_title: Optional[str] = None
71
+ """`title` Field of the referenced subsection."""
72
72
 
73
- def __hash__(self) -> int:
74
- """Overrides the default hash function to ensure consistent hashing across instances."""
75
- return hash((self.referred_chapter_title, self.referred_section_title, self.referred_subsection_title))
76
-
77
- @overload
78
- def deref(self, article: "Article") -> Optional["ArticleMainBase"]:
79
- """Dereference the reference to the actual section or subsection within the provided article."""
80
-
81
- @overload
82
- def deref(self, article: "ArticleOutline") -> Optional["ArticleOutlineBase"]:
83
- """Dereference the reference to the actual section or subsection within the provided article."""
73
+ def update_from_inner(self, other: Self) -> Self:
74
+ """Updates the current instance with the attributes of another instance."""
75
+ self.referred_chapter_title = other.referred_chapter_title
76
+ self.referred_section_title = other.referred_section_title
77
+ self.referred_subsection_title = other.referred_subsection_title
78
+ return self
84
79
 
85
- def deref(
86
- self, article: Union["ArticleOutline", "Article"]
87
- ) -> Union["ArticleOutlineBase", "ArticleMainBase", None]:
80
+ def deref(self, article: "ArticleBase") -> Optional["ArticleOutlineBase"]:
88
81
  """Dereference the reference to the actual section or subsection within the provided article.
89
82
 
90
83
  Args:
@@ -111,21 +104,70 @@ class ArticleRef(CensoredAble):
111
104
  return ReferringType.CHAPTER
112
105
 
113
106
 
114
- class SubSectionBase(
115
- UpdateFrom,
107
+ class ArticleMetaData(CensoredAble, Display):
108
+ """Metadata for an article component."""
109
+
110
+ description: str
111
+ """Description of the research component in academic style."""
112
+
113
+ support_to: List[ArticleRef]
114
+ """List of references to other component of this articles that this component supports."""
115
+ depend_on: List[ArticleRef]
116
+ """List of references to other component of this articles that this component depends on."""
117
+
118
+ writing_aim: List[str]
119
+ """List of writing aims of the research component in academic style."""
120
+ title: str
121
+ """Do not add any prefix or suffix to the title. should not contain special characters."""
122
+
123
+
124
+ class ArticleOutlineBase(
125
+ ArticleMetaData,
126
+ ResolveUpdateConflict,
127
+ ProposedUpdateAble,
128
+ PersistentAble,
129
+ ModelHash,
116
130
  Introspect,
117
131
  ):
118
- """Base class for article sections and subsections."""
132
+ """Base class for article outlines."""
119
133
 
120
- title: str
121
- """Title of the subsection, do not add any prefix or suffix to the title. should not contain special characters."""
134
+ @property
135
+ def metadata(self) -> ArticleMetaData:
136
+ """Returns the metadata of the article component."""
137
+ return ArticleMetaData.model_validate(self, from_attributes=True)
122
138
 
139
+ def update_metadata(self, other: ArticleMetaData) -> Self:
140
+ """Updates the metadata of the current instance with the attributes of another instance."""
141
+ self.support_to.clear()
142
+ self.support_to.extend(other.support_to)
143
+ self.depend_on.clear()
144
+ self.depend_on.extend(other.depend_on)
145
+ self.writing_aim.clear()
146
+ self.writing_aim.extend(other.writing_aim)
147
+ self.description = other.description
148
+ return self
149
+
150
+ def display_metadata(self) -> str:
151
+ """Displays the metadata of the current instance."""
152
+ return self.model_dump_json(
153
+ indent=1, include={"title", "writing_aim", "description", "support_to", "depend_on"}
154
+ )
155
+
156
+ def update_from_inner(self, other: Self) -> Self:
157
+ """Updates the current instance with the attributes of another instance."""
158
+ return self.update_metadata(other)
159
+
160
+ @abstractmethod
123
161
  def to_typst_code(self) -> str:
124
162
  """Converts the component into a Typst code snippet for rendering."""
125
- return f"=== {self.title}\n"
126
163
 
127
- def update_from_inner(self, other: Self) -> Self:
128
- return self
164
+
165
+ class SubSectionBase(ArticleOutlineBase):
166
+ """Base class for article sections and subsections."""
167
+
168
+ def to_typst_code(self) -> str:
169
+ """Converts the component into a Typst code snippet for rendering."""
170
+ return f"=== {self.title}\n"
129
171
 
130
172
  def introspect(self) -> str:
131
173
  """Introspects the article subsection outline."""
@@ -138,16 +180,11 @@ class SubSectionBase(
138
180
  return ""
139
181
 
140
182
 
141
- class SectionBase[T: SubSectionBase](
142
- UpdateFrom,
143
- Introspect,
144
- ):
183
+ class SectionBase[T: SubSectionBase](ArticleOutlineBase):
145
184
  """Base class for article sections and subsections."""
146
185
 
147
186
  subsections: List[T]
148
187
  """Subsections of the section. Contains at least one subsection. You can also add more as needed."""
149
- title: str
150
- """Title of the section, do not add any prefix or suffix to the title. should not contain special characters."""
151
188
 
152
189
  def to_typst_code(self) -> str:
153
190
  """Converts the section into a Typst formatted code snippet.
@@ -174,6 +211,7 @@ class SectionBase[T: SubSectionBase](
174
211
 
175
212
  def update_from_inner(self, other: Self) -> Self:
176
213
  """Updates the current instance with the attributes of another instance."""
214
+ super().update_from_inner(other)
177
215
  if len(self.subsections) == 0:
178
216
  self.subsections = other.subsections
179
217
  return self
@@ -189,16 +227,12 @@ class SectionBase[T: SubSectionBase](
189
227
  return ""
190
228
 
191
229
 
192
- class ChapterBase[T: SectionBase](
193
- UpdateFrom,
194
- Introspect,
195
- ):
230
+ class ChapterBase[T: SectionBase](ArticleOutlineBase):
196
231
  """Base class for article chapters."""
197
232
 
198
233
  sections: List[T]
199
234
  """Sections of the chapter. Contains at least one section. You can also add more as needed."""
200
- title: str
201
- """Title of the chapter, do not add any prefix or suffix to the title. should not contain special characters."""
235
+
202
236
  def to_typst_code(self) -> str:
203
237
  """Converts the chapter into a Typst formatted code snippet for rendering."""
204
238
  return f"= {self.title}\n" + "\n\n".join(sec.to_typst_code() for sec in self.sections)
@@ -233,21 +267,35 @@ class ChapterBase[T: SectionBase](
233
267
  return ""
234
268
 
235
269
 
236
- class ArticleBase[T: ChapterBase](Base):
270
+ class ArticleBase[T: ChapterBase](FinalizedDumpAble):
237
271
  """Base class for article outlines."""
238
272
 
273
+ language: str
274
+ """Written language of the article. SHALL be aligned to the language of the article proposal provided."""
275
+
276
+ title: str
277
+ """Title of the academic paper."""
278
+
279
+ prospect: str
280
+ """Consolidated research statement with four pillars:
281
+ 1. Problem Identification: Current limitations
282
+ 2. Methodological Response: Technical approach
283
+ 3. Empirical Validation: Evaluation strategy
284
+ 4. Scholarly Impact: Field contributions
285
+ """
286
+
287
+ abstract: str
288
+ """The abstract is a concise summary of the academic paper's main findings."""
239
289
  chapters: List[T]
240
290
  """Chapters of the article. Contains at least one chapter. You can also add more as needed."""
241
- title: str
242
- """Title of the article outline, do not add any prefix or suffix to the title. should not contain special characters."""
243
291
 
244
- def iter_dfs(
292
+ def iter_dfs_rev(
245
293
  self,
246
- ) -> Generator[ChapterBase | SectionBase | SubSectionBase, None, None]:
247
- """Performs a depth-first search (DFS) through the article structure.
294
+ ) -> Generator[ArticleOutlineBase, None, None]:
295
+ """Performs a depth-first search (DFS) through the article structure in reverse order.
248
296
 
249
297
  Returns:
250
- Generator[ArticleMainBase]: Each component in the article structure.
298
+ Generator[ArticleMainBase]: Each component in the article structure in reverse order.
251
299
  """
252
300
  for chap in self.chapters:
253
301
  for sec in chap.sections:
@@ -255,37 +303,80 @@ class ArticleBase[T: ChapterBase](Base):
255
303
  yield sec
256
304
  yield chap
257
305
 
306
+ def iter_dfs(self) -> Generator[ArticleOutlineBase, None, None]:
307
+ """Performs a depth-first search (DFS) through the article structure.
258
308
 
259
- class ArticleOutlineBase(
260
- CensoredAble,
261
- UpdateFrom,
262
- ResolveUpdateConflict,
263
- ProposedAble,
264
- PersistentAble,
265
- Display,
266
- ModelHash,
267
- ABC,
268
- ):
269
- """Base class for article outlines."""
309
+ Returns:
310
+ Generator[ArticleMainBase]: Each component in the article structure.
311
+ """
312
+ for chap in self.chapters:
313
+ yield chap
314
+ for sec in chap.sections:
315
+ yield sec
316
+ yield from sec.subsections
270
317
 
271
- description: str
272
- """Description of the research component in academic style."""
318
+ def iter_sections(self) -> Generator[Tuple[ChapterBase, SectionBase], None, None]:
319
+ """Iterates through all sections in the article.
273
320
 
274
- support_to: List[ArticleRef]
275
- """List of references to other component of this articles that this component supports."""
276
- depend_on: List[ArticleRef]
277
- """List of references to other component of this articles that this component depends on."""
321
+ Returns:
322
+ Generator[ArticleOutlineBase]: Each section in the article.
323
+ """
324
+ for chap in self.chapters:
325
+ for sec in chap.sections:
326
+ yield chap, sec
278
327
 
279
- writing_aim: List[str]
280
- """List of writing aims of the research component in academic style."""
328
+ def iter_subsections(self) -> Generator[Tuple[ChapterBase, SectionBase, SubSectionBase], None, None]:
329
+ """Iterates through all subsections in the article.
281
330
 
282
- def update_from_inner(self, other: Self) -> Self:
283
- """Updates the current instance with the attributes of another instance."""
284
- self.support_to.clear()
285
- self.support_to.extend(other.support_to)
286
- self.depend_on.clear()
287
- self.depend_on.extend(other.depend_on)
288
- self.writing_aim.clear()
289
- self.writing_aim.extend(other.writing_aim)
290
- self.description = other.description
291
- return self
331
+ Returns:
332
+ Generator[ArticleOutlineBase]: Each subsection in the article.
333
+ """
334
+ for chap, sec in self.iter_sections():
335
+ for subsec in sec.subsections:
336
+ yield chap, sec, subsec
337
+
338
+ def find_introspected(self) -> Optional[Tuple[ArticleOutlineBase, str]]:
339
+ """Finds the first introspected component in the article structure."""
340
+ summary = ""
341
+ for component in self.iter_dfs_rev():
342
+ summary += component.introspect()
343
+ if summary:
344
+ return component, summary
345
+ return None
346
+
347
+ def find_illegal_ref(self) -> Optional[Tuple[ArticleRef, str]]:
348
+ """Finds the first illegal component in the outline.
349
+
350
+ Returns:
351
+ Tuple[ArticleOutlineBase, str]: A tuple containing the illegal component and an error message.
352
+ """
353
+ summary = ""
354
+ for component in self.iter_dfs_rev():
355
+ for ref in chain(component.depend_on, component.support_to):
356
+ if not ref.deref(self):
357
+ summary += f"Invalid internal reference in `{component.__class__.__name__}` titled `{component.title}`, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
358
+ if summary:
359
+ return ref, summary
360
+ return None
361
+
362
+ def finalized_dump(self) -> str:
363
+ """Generates standardized hierarchical markup for academic publishing systems.
364
+
365
+ Implements ACL 2024 outline conventions with four-level structure:
366
+ = Chapter Title (Level 1)
367
+ == Section Title (Level 2)
368
+ === Subsection Title (Level 3)
369
+ ==== Subsubsection Title (Level 4)
370
+
371
+ Returns:
372
+ str: Strictly formatted outline with academic sectioning
373
+
374
+ Example:
375
+ = Methodology
376
+ == Neural Architecture Search Framework
377
+ === Differentiable Search Space
378
+ ==== Constrained Optimization Parameters
379
+ === Implementation Details
380
+ == Evaluation Protocol
381
+ """
382
+ return "\n\n".join(a.to_typst_code() for a in self.chapters)
@@ -7,7 +7,6 @@ from fabricatio.journal import logger
7
7
  from fabricatio.models.extra.article_base import (
8
8
  ArticleBase,
9
9
  ArticleOutlineBase,
10
- ArticleRef,
11
10
  ChapterBase,
12
11
  SectionBase,
13
12
  SubSectionBase,
@@ -28,21 +27,26 @@ class Paragraph(CensoredAble):
28
27
  writing_aim: List[str]
29
28
  """Specific communicative objectives for this paragraph's content."""
30
29
 
31
- sentences: List[str]
32
- """List of sentences forming the paragraph's content."""
30
+ content: str
31
+ """The actual content of the paragraph, represented as a string."""
33
32
 
34
33
 
35
- class ArticleSubsection(ArticleOutlineBase, SubSectionBase):
34
+ class ArticleSubsection(SubSectionBase):
36
35
  """Atomic argumentative unit with technical specificity."""
37
36
 
38
37
  paragraphs: List[Paragraph]
39
38
  """List of Paragraph objects containing the content of the subsection."""
40
39
 
40
+ def introspect(self) -> str:
41
+ """Introspects the subsection and returns a message if it has no paragraphs."""
42
+ if len(self.paragraphs) == 0:
43
+ return f"`{self.__class__.__name__}` titled `{self.title}` have no paragraphs, to achieve the goal of `{self.writing_aim}`."
44
+ return ""
45
+
41
46
  def update_from_inner(self, other: Self) -> Self:
42
47
  """Updates the current instance with the attributes of another instance."""
43
48
  logger.debug(f"Updating SubSection {self.title}")
44
- SubSectionBase.update_from(self, other)
45
- ArticleOutlineBase.update_from(self, other)
49
+ super().update_from_inner(other)
46
50
  self.paragraphs.clear()
47
51
  self.paragraphs.extend(other.paragraphs)
48
52
  return self
@@ -53,19 +57,17 @@ class ArticleSubsection(ArticleOutlineBase, SubSectionBase):
53
57
  Returns:
54
58
  str: Typst code snippet for rendering.
55
59
  """
56
- return f"=== {self.title}\n" + "\n\n".join("".join(p.sentences) for p in self.paragraphs)
60
+ return f"=== {self.title}\n" + "\n\n".join(p.content for p in self.paragraphs)
57
61
 
58
62
 
59
- class ArticleSection(ArticleOutlineBase, SectionBase[ArticleSubsection]):
63
+ class ArticleSection(SectionBase[ArticleSubsection]):
60
64
  """Atomic argumentative unit with high-level specificity."""
61
65
 
62
66
 
63
-
64
- class ArticleChapter(ArticleOutlineBase, ChapterBase[ArticleSection]):
67
+ class ArticleChapter(ChapterBase[ArticleSection]):
65
68
  """Thematic progression implementing research function."""
66
69
 
67
70
 
68
-
69
71
  class Article(
70
72
  Display,
71
73
  CensoredAble,
@@ -79,22 +81,9 @@ class Article(
79
81
  aiming to provide a comprehensive model for academic papers.
80
82
  """
81
83
 
82
- abstract: str
83
- """Contains a summary of the academic paper."""
84
-
85
- title: str
86
- """Represents the title of the academic paper."""
87
-
88
- language: str
89
- """Written language of the article. SHALL be aligned to the language of the article outline provided."""
90
-
91
- def finalized_dump(self) -> str:
92
- """Exports the article in `typst` format.
93
-
94
- Returns:
95
- str: Strictly formatted outline with typst formatting.
96
- """
97
- return "\n\n".join(c.to_typst_code() for c in self.chapters)
84
+ @override
85
+ def iter_subsections(self) -> Generator[Tuple[ArticleChapter, ArticleSection, ArticleSubsection], None, None]:
86
+ return super().iter_subsections()
98
87
 
99
88
  @classmethod
100
89
  def from_outline(cls, outline: ArticleOutline) -> "Article":
@@ -107,7 +96,7 @@ class Article(
107
96
  Article: The generated article.
108
97
  """
109
98
  # Set the title from the outline
110
- article = Article(**outline.model_dump(include={"title", "abstract"}), chapters=[])
99
+ article = Article(**outline.model_dump(exclude={"chapters"}), chapters=[])
111
100
 
112
101
  for chapter in outline.chapters:
113
102
  # Create a new chapter
@@ -132,33 +121,16 @@ class Article(
132
121
  article.chapters.append(article_chapter)
133
122
  return article
134
123
 
135
- @override
136
- def iter_dfs(
137
- self,
138
- ) -> Generator[ArticleChapter | ArticleSection | ArticleSubsection, None, None]:
139
- return super().iter_dfs()
140
-
141
- def deref(self, ref: ArticleRef) -> ArticleOutlineBase:
142
- """Resolves a reference to the corresponding section or subsection in the article.
143
-
144
- Args:
145
- ref (ArticleRef): The reference to resolve.
146
-
147
- Returns:
148
- ArticleOutlineBase: The corresponding section or subsection.
149
- """
150
- return ok(ref.deref(self), f"{ref} not found in {self.title}")
151
-
152
124
  def gather_dependencies(self, article: ArticleOutlineBase) -> List[ArticleOutlineBase]:
153
125
  """Gathers dependencies for all sections and subsections in the article.
154
126
 
155
127
  This method should be called after the article is fully constructed.
156
128
  """
157
- depends = [self.deref(a) for a in article.depend_on]
129
+ depends = [ok(a.deref(self)) for a in article.depend_on]
158
130
 
159
131
  supports = []
160
- for a in self.iter_dfs():
161
- if article in {self.deref(b) for b in a.support_to}:
132
+ for a in self.iter_dfs_rev():
133
+ if article in {ok(b.deref(self)) for b in a.support_to}:
162
134
  supports.append(a)
163
135
 
164
136
  return list(set(depends + supports))
@@ -220,7 +192,7 @@ class Article(
220
192
  if all((not chapter, not section, not subsection)):
221
193
  raise ValueError("At least one of chapter, section, or subsection must be True.")
222
194
 
223
- for component in self.iter_dfs():
195
+ for component in self.iter_dfs_rev():
224
196
  if not chapter and isinstance(component, ArticleChapter):
225
197
  continue
226
198
  if not section and isinstance(component, ArticleSection):
@@ -1,45 +1,26 @@
1
1
  """A module containing the ArticleOutline class, which represents the outline of an academic paper."""
2
2
 
3
- from typing import Generator, List, Optional, Self, Tuple, Union, override
4
-
5
- import regex
6
3
  from fabricatio.models.extra.article_base import (
7
4
  ArticleBase,
8
- ArticleOutlineBase,
9
5
  ChapterBase,
10
6
  SectionBase,
11
7
  SubSectionBase,
12
8
  )
13
9
  from fabricatio.models.extra.article_proposal import ArticleProposal
14
10
  from fabricatio.models.generic import CensoredAble, Display, PersistentAble, WithRef
15
- from fabricatio.models.utils import ok
16
11
 
17
12
 
18
- class ArticleSubsectionOutline(ArticleOutlineBase, SubSectionBase):
13
+ class ArticleSubsectionOutline(SubSectionBase):
19
14
  """Atomic research component specification for academic paper generation."""
20
15
 
21
16
 
22
-
23
- class ArticleSectionOutline(ArticleOutlineBase, SectionBase[ArticleSubsectionOutline]):
17
+ class ArticleSectionOutline(SectionBase[ArticleSubsectionOutline]):
24
18
  """A slightly more detailed research component specification for academic paper generation, Must contain subsections."""
25
19
 
26
20
 
27
- def update_from_inner(self, other: Self) -> Self:
28
- """Updates the current instance with the attributes of another instance."""
29
- super().update_from_inner(other)
30
- super(ArticleOutlineBase, self).update_from_inner(other)
31
- return self
32
-
33
-
34
- class ArticleChapterOutline(ArticleOutlineBase, ChapterBase[ArticleSectionOutline]):
21
+ class ArticleChapterOutline(ChapterBase[ArticleSectionOutline]):
35
22
  """Macro-structural unit implementing standard academic paper organization. Must contain sections."""
36
23
 
37
- def update_from_inner(self, other: Self) -> Self:
38
- """Updates the current instance with the attributes of another instance."""
39
- super().update_from_inner(other)
40
- super(ArticleOutlineBase, self).update_from_inner(other)
41
- return self
42
-
43
24
 
44
25
  class ArticleOutline(
45
26
  Display,
@@ -48,140 +29,4 @@ class ArticleOutline(
48
29
  PersistentAble,
49
30
  ArticleBase[ArticleChapterOutline],
50
31
  ):
51
- """A class representing the outline of an academic paper."""
52
-
53
- abstract: str
54
- """The abstract is a concise summary of the academic paper's main findings."""
55
-
56
- prospect: str
57
- """Consolidated research statement with four pillars:
58
- 1. Problem Identification: Current limitations
59
- 2. Methodological Response: Technical approach
60
- 3. Empirical Validation: Evaluation strategy
61
- 4. Scholarly Impact: Field contributions
62
- """
63
-
64
- title: str
65
- """Title of the academic paper."""
66
-
67
- language: str
68
- """Written language of the article. SHALL be aligned to the language of the article proposal provided."""
69
-
70
- def finalized_dump(self) -> str:
71
- """Generates standardized hierarchical markup for academic publishing systems.
72
-
73
- Implements ACL 2024 outline conventions with four-level structure:
74
- = Chapter Title (Level 1)
75
- == Section Title (Level 2)
76
- === Subsection Title (Level 3)
77
- ==== Subsubsection Title (Level 4)
78
-
79
- Returns:
80
- str: Strictly formatted outline with academic sectioning
81
-
82
- Example:
83
- = Methodology
84
- == Neural Architecture Search Framework
85
- === Differentiable Search Space
86
- ==== Constrained Optimization Parameters
87
- === Implementation Details
88
- == Evaluation Protocol
89
- """
90
- lines: List[str] = []
91
- for i, chapter in enumerate(self.chapters, 1):
92
- lines.append(f"= Chapter {i}: {chapter.title}")
93
- for j, section in enumerate(chapter.sections, 1):
94
- lines.append(f"== {i}.{j} {section.title}")
95
- for k, subsection in enumerate(section.subsections, 1):
96
- lines.append(f"=== {i}.{j}.{k} {subsection.title}")
97
- return "\n".join(lines)
98
-
99
- @override
100
- def iter_dfs(
101
- self,
102
- ) -> Generator[ArticleChapterOutline | ArticleSectionOutline | ArticleSubsectionOutline, None, None]:
103
- return super().iter_dfs()
104
- def find_illegal(self) -> Optional[Tuple[ArticleOutlineBase, str]]:
105
- """Finds the first illegal component in the outline.
106
-
107
- Returns:
108
- Tuple[ArticleOutlineBase, str]: A tuple containing the illegal component and an error message.
109
- """
110
- summary = ""
111
- for component in self.iter_dfs():
112
- for ref in component.depend_on:
113
- if not ref.deref(self):
114
- summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `depend_on` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
115
- for ref in component.support_to:
116
- if not ref.deref(self):
117
- summary += f"Invalid internal reference in {component.__class__.__name__} titled `{component.title}` at `support_to` field, because the referred {ref.referring_type} is not exists within the article, see the original obj dump: {ref.model_dump()}\n"
118
- summary += component.introspect()
119
- if summary:
120
- return component, summary
121
- return None
122
-
123
- @classmethod
124
- def from_typst_code(
125
- cls, typst_code: str, title: str = "", article_language: str = "en", prospect: str = "", abstract: str = ""
126
- ) -> "ArticleOutline":
127
- """Parses a Typst code string and creates an ArticleOutline instance."""
128
- self = cls(language=article_language, prospect=prospect, abstract=abstract, chapters=[], title=title)
129
- stack = [self] # 根节点为ArticleOutline实例
130
-
131
- for line in typst_code.splitlines():
132
- parsed = cls._parse_line(line)
133
- if not parsed:
134
- continue
135
- level, title = parsed
136
- cls._adjust_stack(stack, level)
137
- parent = stack[-1]
138
- component = cls._create_component(level, title)
139
- cls._add_to_parent(parent, component, level)
140
- stack.append(component)
141
-
142
- return self
143
-
144
- @classmethod
145
- def _parse_line(cls, line: str) -> Optional[Tuple[int, str]]:
146
- stripped = line.strip()
147
- if not stripped.startswith("="):
148
- return None
149
- match = regex.match(r"^(\=+)(.*)", stripped)
150
- if not match:
151
- return None
152
- eqs, title_part = match.groups()
153
- return len(eqs), title_part.strip()
154
-
155
- @classmethod
156
- def _adjust_stack(cls, stack: List[object], target_level: int) -> None:
157
- while len(stack) > target_level:
158
- stack.pop()
159
-
160
- @classmethod
161
- def _create_component(cls, level: int, title: str) -> ArticleOutlineBase:
162
- default_kwargs = {
163
- "writing_aim": [],
164
- "depend_on": [],
165
- "support_to": [],
166
- "description": [],
167
- }
168
- component_map = {
169
- 1: lambda: ArticleChapterOutline(title=title, sections=[], **default_kwargs),
170
- 2: lambda: ArticleSectionOutline(title=title, subsections=[], **default_kwargs),
171
- 3: lambda: ArticleSubsectionOutline(title=title, **default_kwargs),
172
- }
173
- return ok(component_map.get(level, lambda: None)(), "Invalid level")
174
-
175
- @classmethod
176
- def _add_to_parent(
177
- cls,
178
- parent: Union["ArticleOutline", ArticleChapterOutline, ArticleSectionOutline],
179
- component: ArticleOutlineBase,
180
- level: int,
181
- ) -> None:
182
- if level == 1 and isinstance(component, ArticleChapterOutline):
183
- parent.chapters.append(component)
184
- elif level == 2 and isinstance(component, ArticleSectionOutline): # noqa: PLR2004
185
- parent.sections.append(component)
186
- elif level == 3 and isinstance(component, ArticleSubsectionOutline): # noqa: PLR2004
187
- parent.subsections.append(component)
32
+ """Outline of an academic paper, containing chapters, sections, subsections."""
@@ -11,25 +11,23 @@ class ArticleProposal(CensoredAble, Display, WithRef[str], AsPrompt, PersistentA
11
11
  Guides LLM in generating comprehensive research proposals with clearly defined components.
12
12
  """
13
13
 
14
+ language: str
15
+ """The language in which the article is written. This should align with the language specified in the article briefing."""
16
+
17
+ title: str
18
+ """The title of the academic paper, formatted in Title Case."""
19
+
20
+ focused_problem: List[str]
21
+ """A list of specific research problems or questions that the paper aims to address."""
22
+
14
23
  technical_approaches: List[str]
15
- """Technical approaches"""
24
+ """A list of technical approaches or methodologies used to solve the research problems."""
16
25
 
17
26
  research_methods: List[str]
18
- """Methodological components (list of techniques/tools).
19
- Example: ['Differentiable architecture search', 'Transformer-based search space', 'Multi-lingual perplexity evaluation']"""
27
+ """A list of methodological components, including techniques and tools utilized in the research."""
20
28
 
21
29
  research_aim: List[str]
22
- """Primary research objectives (list of 2-4 measurable goals).
23
- Example: ['Develop parameter-efficient NAS framework', 'Establish cross-lingual architecture transfer metrics']"""
24
-
25
- focused_problem: List[str]
26
- """Specific research problem(s) or question(s) addressed (list of 1-3 concise statements).
27
- Example: ['NAS computational overhead in low-resource settings', 'Architecture transferability across language pairs']"""
28
-
29
- title: str
30
- """Paper title in academic style (Title Case, 8-15 words). Example: 'Exploring Neural Architecture Search for Low-Resource Machine Translation'"""
31
- language: str
32
- """Written language of the article. SHALL be aligned to the language of the article briefing provided."""
30
+ """A list of primary research objectives that the paper seeks to achieve."""
33
31
 
34
32
  def _as_prompt_inner(self) -> Dict[str, str]:
35
33
  return {"ArticleBriefing": self.referenced, "ArticleProposal": self.display()}
@@ -1,6 +1,6 @@
1
1
  """This module defines generic classes for models in the Fabricatio library."""
2
2
 
3
- from abc import abstractmethod
3
+ from abc import ABC, abstractmethod
4
4
  from pathlib import Path
5
5
  from typing import Any, Callable, Dict, Iterable, List, Optional, Self, Union, final, overload
6
6
 
@@ -108,7 +108,7 @@ class PersistentAble(Base):
108
108
  """Class that provides a method to persist the object."""
109
109
 
110
110
  def persist(self, path: str | Path) -> Self:
111
- """Persist the object to a file.
111
+ """Persist the object to a file or directory.
112
112
 
113
113
  Args:
114
114
  path (str | Path): The path to save the object.
@@ -117,7 +117,7 @@ class PersistentAble(Base):
117
117
  Self: The current instance of the object.
118
118
  """
119
119
  p = Path(path)
120
- out = self.model_dump_json()
120
+ out = self.model_dump_json(indent=1)
121
121
  if p.is_dir():
122
122
  p.joinpath(f"{self.__class__.__name__}_{blake3_hash(out.encode())[:6]}.json").write_text(
123
123
  out, encoding="utf-8"
@@ -125,6 +125,7 @@ class PersistentAble(Base):
125
125
  return self
126
126
  p.mkdir(exist_ok=True, parents=True)
127
127
  p.write_text(out, encoding="utf-8")
128
+ logger.info(f"Persisted {self} to {p.as_posix()}")
128
129
  return self
129
130
 
130
131
  def from_persistent(self, path: str | Path) -> Self:
@@ -228,20 +229,11 @@ class WithBriefing(Named, Described):
228
229
  raise TypeError(f"{system_msg_like} is not a dict or str")
229
230
 
230
231
 
231
- class ReverseGenerate(GenerateJsonSchema):
232
+ class UnsortGenerate(GenerateJsonSchema):
232
233
  """Class that provides a reverse JSON schema of the model."""
233
234
 
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)]
235
+ def sort(self, value: JsonSchemaValue, parent_key: str | None = None) -> JsonSchemaValue:
236
+ """Not sort."""
245
237
  return value
246
238
 
247
239
 
@@ -256,7 +248,7 @@ class WithFormatedJsonSchema(Base):
256
248
  str: The JSON schema of the model in a formatted string.
257
249
  """
258
250
  return orjson.dumps(
259
- cls.model_json_schema(schema_generator=ReverseGenerate),
251
+ cls.model_json_schema(schema_generator=UnsortGenerate),
260
252
  option=orjson.OPT_INDENT_2,
261
253
  ).decode()
262
254
 
@@ -316,6 +308,10 @@ class ProposedAble(CreateJsonObjPrompt, InstantiateFromString):
316
308
  """Class that provides a method to propose a JSON object based on the requirement."""
317
309
 
318
310
 
311
+ class ProposedUpdateAble(PersistentAble, UpdateFrom, ABC):
312
+ """Make the obj can be updated from the proposed obj in place."""
313
+
314
+
319
315
  class FinalizedDumpAble(Base):
320
316
  """Class that provides a method to finalize the dump of the object."""
321
317
 
@@ -1,5 +1,6 @@
1
1
  """This module contains classes that manage the usage of language models and tools in tasks."""
2
2
 
3
+ import traceback
3
4
  from asyncio import gather
4
5
  from typing import Callable, Dict, Iterable, List, Optional, Self, Sequence, Set, Type, Union, Unpack, overload
5
6
 
@@ -38,6 +39,8 @@ ROUTER = Router(
38
39
  allowed_fails=configs.routing.allowed_fails,
39
40
  retry_after=configs.routing.retry_after,
40
41
  cooldown_time=configs.routing.cooldown_time,
42
+ cache_responses=configs.cache.enabled,
43
+ cache_kwargs=configs.cache.params,
41
44
  )
42
45
 
43
46
 
@@ -135,7 +138,7 @@ class LLMUsage(ScopedConfig):
135
138
  List[Choices | StreamingChoices]: A list of choices or streaming choices from the model response.
136
139
  """
137
140
  resp = await self.aquery(
138
- messages=Messages().add_system_message(system_message).add_user_message(question),
141
+ messages=Messages().add_system_message(system_message).add_user_message(question).as_list(),
139
142
  n=n,
140
143
  **kwargs,
141
144
  )
@@ -324,6 +327,7 @@ class LLMUsage(ScopedConfig):
324
327
  continue
325
328
  except Exception as e: # noqa: BLE001
326
329
  logger.error(f"Error during validation: \n{e}")
330
+ logger.debug(traceback.format_exc())
327
331
  break
328
332
  if not kwargs.get("no_cache"):
329
333
  kwargs["no_cache"] = True
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fabricatio
3
- Version: 0.2.7.dev5
3
+ Version: 0.2.8.dev0
4
4
  Classifier: License :: OSI Approved :: MIT License
5
5
  Classifier: Programming Language :: Rust
6
6
  Classifier: Programming Language :: Python :: 3.12
@@ -1,11 +1,11 @@
1
- fabricatio-0.2.7.dev5.dist-info/METADATA,sha256=ANxpgCb6nTOneCJ-RdQ7ejNoefGzRdKyfQIvwVfCJiU,5259
2
- fabricatio-0.2.7.dev5.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
3
- fabricatio-0.2.7.dev5.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
4
- fabricatio/actions/article.py,sha256=cv1pyGOvgMVMaHJqVDKY6h5_u1XtVw3lzJCDFqx4aoc,8073
1
+ fabricatio-0.2.8.dev0.dist-info/METADATA,sha256=coMH1ZINCPxofmsl4UlmFGMsJRrE_Xx_9fzKOQcKSTY,5259
2
+ fabricatio-0.2.8.dev0.dist-info/WHEEL,sha256=jABKVkLC9kJr8mi_er5jOqpiQUjARSLXDUIIxDqsS50,96
3
+ fabricatio-0.2.8.dev0.dist-info/licenses/LICENSE,sha256=do7J7EiCGbq0QPbMAL_FqLYufXpHnCnXBOuqVPwSV8Y,1088
4
+ fabricatio/actions/article.py,sha256=2e96lVsk2WR9VsjRc3mE8cOUvEgdhE36kL4x_WxdJWk,8313
5
5
  fabricatio/actions/article_rag.py,sha256=PiOFxI6VTmLXm3BK-01g_KH1mTE9uOtnA-CwUjt16AU,1456
6
- fabricatio/actions/output.py,sha256=K7xsBH8MjXRH6JOy3ZO94KCQzX2jNrwPPK_rRXVkS0E,1161
6
+ fabricatio/actions/output.py,sha256=eHI4EH5n1nOt6MqQ00b7UWTjIqO8FerNakem_45d5qk,2315
7
7
  fabricatio/actions/rag.py,sha256=QBdzEM8MloM_ahx5pTBZAETm9_631lTe_0ih_he_Iuo,2759
8
- fabricatio/capabilities/correct.py,sha256=8GOU2VBPUakjG-r59SqsCgCD0QHX-l__IynCLO-ib8Q,6482
8
+ fabricatio/capabilities/correct.py,sha256=2093ggHkY8vQW8fl7VwXC8u39oW1xsfjxDjGoQ5puOA,7269
9
9
  fabricatio/capabilities/propose.py,sha256=y3kge5g6bb8HYuV8e9h4MdqOMTlsfAIZpqE_cagWPTY,1593
10
10
  fabricatio/capabilities/rag.py,sha256=XVvfH6rcog-moj1WCgwtR-l0-NdbFR6-fMQFLG7_asY,17690
11
11
  fabricatio/capabilities/rating.py,sha256=yEPqL5_DqVMj_AH9cMvKsHdMnSbvm8dN6PaKHLsJUPQ,14904
@@ -18,19 +18,19 @@ fabricatio/fs/curd.py,sha256=N6l2MncjrFfnXBRtteRouXp5Rjy8EAKC_i29_G-zz98,4618
18
18
  fabricatio/fs/readers.py,sha256=EZKN_AZdrp8DggJECP53QHw3uHeSDf-AwCAA_V7fNKU,1202
19
19
  fabricatio/fs/__init__.py,sha256=PCf0s_9KDjVfNw7AfPoJzGt3jMq4gJOfbcT4pb0D0ZY,588
20
20
  fabricatio/journal.py,sha256=stnEP88aUBA_GmU9gfTF2EZI8FS2OyMLGaMSTgK4QgA,476
21
- fabricatio/models/action.py,sha256=UlflniS__MMrUXglu_U3PDFAtKEjVsKEix17AT9oP3M,8769
21
+ fabricatio/models/action.py,sha256=FcgZPneEFQTgK2eEvafo2FvnGnqM5G8HytPddqHrq8A,8880
22
22
  fabricatio/models/events.py,sha256=QvlnS8FEELg6KNabcJMeh2GV_y0ZBzKOPphcteKYWYU,4183
23
- fabricatio/models/extra/article_base.py,sha256=Y4ZdC1yabs7jCNKwc-P8GpAJShGJx7EcLyhXuJ194Fo,11469
23
+ fabricatio/models/extra/article_base.py,sha256=SwFiSyGHU7n5cD1B3eN2UjrZjW_pXgYI4zelxsdcTCI,15270
24
24
  fabricatio/models/extra/article_essence.py,sha256=DUESuK4CGgkRvIMoJCv4l8MNp5MawRYoNOtLCrFRPXY,9229
25
- fabricatio/models/extra/article_main.py,sha256=l6HO3PajaesEET6Evd2A7OOpHRelGYr4y88JyoPmP3Y,8498
26
- fabricatio/models/extra/article_outline.py,sha256=VV6RUY7VzKwqCXoykDi-vL2nqHouOuo1Q3hLdCdNDpQ,7740
27
- fabricatio/models/extra/article_proposal.py,sha256=p0NPzqg9x6t65DZqdF52Z1P0JwP6kwo2_eP-NsXgifU,1720
28
- fabricatio/models/generic.py,sha256=yEpP4cvvmB0sDbs36pIl2KYFsnNRKq7V0m3HqoSQc7o,19492
25
+ fabricatio/models/extra/article_main.py,sha256=S-Bu91KYQB7Ep5yMTUBmpI54RFjq_emM8MoIFyVEROQ,7721
26
+ fabricatio/models/extra/article_outline.py,sha256=pIsO5bOSV-SUeWWdhkfkVpcr9RPOHgYmsceHsrXs67M,1145
27
+ fabricatio/models/extra/article_proposal.py,sha256=DWn3MQUNQlXj9Fcm3xSONyxARz8goAroJUA6pWvBhHw,1398
28
+ fabricatio/models/generic.py,sha256=nyfhgaIEsSvbDvcHrjULEgseBKRzZx2t21lfncwCsq4,19225
29
29
  fabricatio/models/kwargs_types.py,sha256=chJ-rHaeBVRUPuORHuGR3DdNxxTUrotz0eflPEh4l4w,5474
30
30
  fabricatio/models/role.py,sha256=mmQbJ6GKr2Gx3wtjEz8d-vYoXs09ffcEkT_eCXaDd3E,2782
31
31
  fabricatio/models/task.py,sha256=8NaR7ojQWyM740EDTqt9stwHKdrD6axCRpLKo0QzS-I,10492
32
32
  fabricatio/models/tool.py,sha256=kD0eB7OxO9geZOxO6JIKvCBeG-KOpRAkfRZqK_WGfW4,7105
33
- fabricatio/models/usages.py,sha256=BSqTENSva8Flga3bPBfwuc1nHo5Z_29oYzar99NbjLM,31566
33
+ fabricatio/models/usages.py,sha256=BZXHdm198wMOaYvCqL7wBcSzAHUMS4mYeD_VCi08mmY,31736
34
34
  fabricatio/models/utils.py,sha256=yjxPZ6N7QGpGwkI_Vb28Ud3EhkdlB-tyfGRHAZMcGxs,5872
35
35
  fabricatio/parser.py,sha256=9Jzw-yV6uKbFvf6sPna-XHdziVGVBZWvPctgX_6ODL8,6251
36
36
  fabricatio/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
@@ -42,6 +42,6 @@ fabricatio/workflows/rag.py,sha256=-YYp2tlE9Vtfgpg6ROpu6QVO8j8yVSPa6yDzlN3qVxs,5
42
42
  fabricatio/_rust.pyi,sha256=dGTGV7viu3YAGl1cRKIWrdHPc1hlwk3_hbaDaswxdVo,3831
43
43
  fabricatio/_rust_instances.py,sha256=2GwF8aVfYNemRI2feBzH1CZfBGno-XJJE5imJokGEYw,314
44
44
  fabricatio/__init__.py,sha256=SzBYsRhZeL77jLtfJEjmoHOSwHwUGyvMATX6xfndLDM,1135
45
- fabricatio/_rust.cp312-win_amd64.pyd,sha256=db4DHfetEQMNh7hqmL6All-asJooQxFIIXZkoWKAx4c,1835008
46
- fabricatio-0.2.7.dev5.data/scripts/tdown.exe,sha256=xZcDsLIn9rJZcM8iDNgS-eNK4ckH5rufC6mU6I2vmOo,3399680
47
- fabricatio-0.2.7.dev5.dist-info/RECORD,,
45
+ fabricatio/_rust.cp312-win_amd64.pyd,sha256=1wV10H3_yuAX2eZTIXTI1mhpTASH3dN491GXUBLKtDE,1830912
46
+ fabricatio-0.2.8.dev0.data/scripts/tdown.exe,sha256=fEInXr-uYE9QwK0N2CINOHDjc22Odu_DY9Dk2JPDIg8,3399680
47
+ fabricatio-0.2.8.dev0.dist-info/RECORD,,