Skip to content

Commit 131d0d9

Browse files
committed
sync: revert to the main
1 parent fb45a6d commit 131d0d9

2 files changed

Lines changed: 262 additions & 42 deletions

File tree

cli/decompose/decompose.py

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -27,22 +27,22 @@
2727

2828

2929
class DecompVersion(StrEnum):
30-
"""Available versions of the decomposition pipeline template.
30+
"""Available template versions for generated decomposition programs.
3131
32-
Newer versions must be declared last to ensure ``latest`` always resolves to
33-
the most recent template.
32+
Newer concrete versions must be declared after older ones so that
33+
``latest`` can resolve to the most recently declared template version.
3434
3535
Attributes:
36-
latest (str): Sentinel value that resolves to the last declared version.
37-
v1 (str): Version 1 of the decomposition pipeline template.
38-
v2 (str): Version 2 of the decomposition pipeline template.
39-
v3 (str): Version 3 of the decomposition pipeline template.
36+
latest: Sentinel value that resolves to the last declared concrete
37+
template version.
38+
v1: Version 1 of the decomposition program template.
39+
v2: Version 2 of the decomposition program template.
4040
"""
4141

4242
latest = "latest"
4343
v1 = "v1"
4444
v2 = "v2"
45-
v3 = "v3"
45+
# v3 = "v3"
4646

4747

4848
this_file_dir = Path(__file__).resolve().parent
@@ -227,44 +227,42 @@ def run(
227227
),
228228
] = LogMode.demo,
229229
) -> None:
230-
"""Decompose one or more user queries into subtasks with constraints and dependency metadata.
230+
"""Runs the ``m decompose`` CLI workflow and writes generated outputs.
231231
232-
Reads user queries either from a file or interactively, runs the LLM
233-
decomposition pipeline to produce subtask descriptions, Jinja2 prompt templates,
234-
constraint lists, and dependency metadata, and writes one ``.json`` result file
235-
plus one rendered ``.py`` script per task job to the output directory.
236-
237-
If ``input_file`` contains multiple non-empty lines, each line is treated as a
238-
separate task job.
232+
Reads user queries from a file or interactive input, runs the decomposition
233+
pipeline for each task job, and writes one JSON file, one rendered Python
234+
program, and any generated validation modules under a per-job output
235+
directory.
239236
240237
Args:
241-
out_dir: Path to an existing directory where output files are saved.
242-
out_name: Base name (no extension) for the output files. Defaults to
243-
``"m_decomp_result"``.
244-
input_file: Optional path to a text file containing one or more user
245-
queries. If the file contains multiple non-empty lines, each line is
246-
treated as a separate task job. If omitted, the query is collected
247-
interactively.
248-
model_id: Model name or ID used for all decomposition pipeline steps.
249-
backend: Inference backend -- ``"ollama"``, ``"openai"``, or ``"rits"``.
250-
backend_req_timeout: Request timeout in seconds for model inference calls.
251-
backend_endpoint: Base URL of the configured endpoint. Required when
252-
``backend="openai"`` or ``backend="rits"``.
253-
backend_api_key: API key for the configured endpoint. Required when
254-
``backend="openai"`` or ``backend="rits"``.
255-
version: Version of the decomposition pipeline template to use.
256-
input_var: Optional list of user-input variable names (e.g. ``"DOC"``).
257-
Each name must be a valid Python identifier. Pass this option
258-
multiple times to define multiple variables.
259-
log_mode: Logging detail mode for CLI and pipeline output.
238+
out_dir: Existing directory under which per-job output directories are
239+
created.
240+
out_name: Base name used for the per-job output directory and generated
241+
files.
242+
input_file: Optional path to a text file containing one or more task
243+
prompts. Each non-empty line is processed as a separate task job.
244+
When omitted, the command prompts interactively for one task.
245+
model_id: Model identifier used for all decomposition pipeline stages.
246+
backend: Inference backend used to execute model calls.
247+
backend_req_timeout: Request timeout in seconds for backend inference calls.
248+
backend_endpoint: Endpoint URL or base URL required by remote backends.
249+
backend_api_key: API key required by remote backends.
250+
version: Template version used to render the generated Python program.
251+
``latest`` resolves to the most recently declared concrete version.
252+
input_var: Optional user input variable names to expose in generated
253+
prompts and programs. Each name must be a valid non-keyword Python
254+
identifier.
255+
log_mode: Logging verbosity for CLI and pipeline execution.
260256
261257
Raises:
262-
AssertionError: If ``out_name`` contains invalid characters, if
263-
``out_dir`` does not exist or is not a directory, or if any
264-
``input_var`` name is not a valid Python identifier.
265-
ValueError: If the input file contains no non-empty task lines.
266-
Exception: Re-raised from the decomposition pipeline after cleaning up
267-
any partially written output directories.
258+
AssertionError: If ``out_name`` is invalid, ``out_dir`` does not name an
259+
existing directory, ``input_file`` does not name an existing file,
260+
or any declared ``input_var`` is not a valid Python identifier.
261+
ValueError: If ``input_file`` exists but contains no non-empty task
262+
lines.
263+
Exception: Propagates pipeline, rendering, parsing, or file-writing
264+
failures. Any output directories created earlier in the run are
265+
removed before the exception is re-raised.
268266
"""
269267
created_dirs: list[Path] = []
270268

@@ -410,4 +408,4 @@ def run(
410408
for decomp_dir in reversed(created_dirs):
411409
if decomp_dir.exists() and decomp_dir.is_dir():
412410
shutil.rmtree(decomp_dir)
413-
raise
411+
raise
Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
1+
# pytest: skip_always
2+
import textwrap
3+
4+
import mellea
5+
6+
# Note: This is an example of an intermediary result from using decompose in python_decompose_example.py, not an example of how to use decompose.
7+
8+
9+
m = mellea.start_session()
10+
11+
12+
# 1. Create a catchy title for the blog post about the benefits of morning exercise. - - BLOG_TITLE
13+
blog_title = m.instruct(
14+
textwrap.dedent(
15+
R"""
16+
Your task is to create a catchy title for a blog post about the benefits of morning exercise. Follow these steps to accomplish your task:
17+
18+
1. **Understand the Topic**: The blog post will focus on the benefits of morning exercise. The title should be engaging and clearly convey the main topic of the post.
19+
20+
2. **Identify Key Elements**: Consider the key elements that make morning exercise beneficial. These could include improved mood, increased energy, better focus, and enhanced metabolism.
21+
22+
3. **Use Power Words**: Incorporate power words that evoke curiosity, excitement, or a sense of urgency. Examples include "Boost," "Transform," "Unlock," "Energize," and "Revitalize."
23+
24+
4. **Keep It Concise**: The title should be short and to the point, ideally between 5 to 10 words. It should be easy to read and remember.
25+
26+
5. **Make It Action-Oriented**: Use verbs that encourage action, such as "Start," "Jumpstart," "Kickstart," or "Ignite."
27+
28+
6. **Consider SEO**: Think about common search terms related to morning exercise. Including relevant keywords can help improve the post's visibility.
29+
30+
7. **Examples for Inspiration**:
31+
- "Jumpstart Your Day: The Power of Morning Exercise"
32+
- "Energize Your Mornings: Unlock the Benefits of Morning Exercise"
33+
- "Transform Your Day with Morning Exercise"
34+
- "Boost Your Energy: The Magic of Morning Workouts"
35+
- "Revitalize Your Mornings: The Benefits of Morning Exercise"
36+
37+
8. **Create the Title**: Based on the above guidelines, create a catchy and engaging title for the blog post. Ensure it captures the essence of the topic and entices readers to click and read more.
38+
39+
Your final answer should be only the title text.
40+
""".strip()
41+
),
42+
requirements=["Include a catchy title"],
43+
)
44+
assert blog_title.value is not None, 'ERROR: task "blog_title" execution failed'
45+
46+
# 2. Write an introduction paragraph that sets the stage for the blog post. - - INTRODUCTION
47+
introduction = m.instruct(
48+
textwrap.dedent(
49+
R"""
50+
Your task is to write an engaging introduction paragraph for a blog post about the benefits of morning exercise. The introduction should set the stage for the blog post, capturing the reader's attention and providing a brief overview of what will be discussed.
51+
52+
To accomplish this, follow these steps:
53+
54+
1. **Understand the Context**:
55+
- The blog post is about the benefits of morning exercise.
56+
- The title of the blog post is: {{BLOG_TITLE}}
57+
58+
2. **Craft the Introduction**:
59+
- Start with a hook that grabs the reader's attention. This could be a question, a surprising fact, or a relatable scenario.
60+
- Briefly introduce the topic of morning exercise and why it is important.
61+
- Provide a smooth transition to the main benefits that will be discussed in the blog post.
62+
63+
3. **Ensure Engagement**:
64+
- Use a conversational and engaging tone to connect with the readers.
65+
- Keep the introduction concise and to the point, ideally between 3 to 5 sentences.
66+
67+
Here is an example structure to guide your writing:
68+
- **Sentence 1**: Hook to grab the reader's attention.
69+
- **Sentence 2**: Introduce the topic of morning exercise.
70+
- **Sentence 3**: Briefly mention the benefits that will be discussed.
71+
- **Sentence 4**: Transition to the main content of the blog post.
72+
73+
Ensure that the introduction flows naturally and sets the stage for the rest of the blog post. You should write only the introduction paragraph, do not include the guidance structure.
74+
""".strip()
75+
),
76+
requirements=["Include an introduction paragraph"],
77+
user_variables={"BLOG_TITLE": blog_title.value},
78+
)
79+
assert introduction.value is not None, 'ERROR: task "introduction" execution failed'
80+
81+
# 3. Identify and explain three main benefits of morning exercise with detailed explanations. - - BENEFITS
82+
benefits = m.instruct(
83+
textwrap.dedent(
84+
R"""
85+
Your task is to identify and explain three main benefits of morning exercise with detailed explanations. Follow these steps to accomplish your task:
86+
87+
First, review the title and introduction created in the previous steps to understand the context and tone of the blog post:
88+
<title>
89+
{{BLOG_TITLE}}
90+
</title>
91+
<introduction>
92+
{{INTRODUCTION}}
93+
</introduction>
94+
95+
Next, research and identify three main benefits of morning exercise. These benefits should be supported by evidence or expert opinions to ensure credibility.
96+
97+
For each benefit, provide a detailed explanation that includes:
98+
- The specific benefit of morning exercise
99+
- How this benefit positively impacts health, well-being, or daily life
100+
- Any relevant studies, expert opinions, or personal anecdotes that support the benefit
101+
102+
Ensure that the explanations are clear, concise, and engaging to keep the reader interested.
103+
104+
Finally, present the three main benefits with their detailed explanations in a structured format that can be easily integrated into the blog post.
105+
""".strip()
106+
),
107+
requirements=["Include three main benefits with explanations"],
108+
user_variables={"BLOG_TITLE": blog_title.value, "INTRODUCTION": introduction.value},
109+
)
110+
assert benefits.value is not None, 'ERROR: task "benefits" execution failed'
111+
112+
# 4. Write a conclusion that encourages readers to start their morning exercise routine. - - CONCLUSION
113+
conclusion = m.instruct(
114+
textwrap.dedent(
115+
R"""
116+
Your task is to write a compelling conclusion for a blog post about the benefits of morning exercise. The conclusion should encourage readers to start their morning exercise routine. Follow these steps to accomplish your task:
117+
118+
First, review the title and introduction of the blog post to understand the context and tone:
119+
<title>
120+
{{BLOG_TITLE}}
121+
</title>
122+
<introduction>
123+
{{INTRODUCTION}}
124+
</introduction>
125+
126+
Next, consider the three main benefits of morning exercise that have been previously identified and explained:
127+
<benefits>
128+
{{BENEFITS}}
129+
</benefits>
130+
131+
Use the information from the title, introduction, and benefits to craft a conclusion that:
132+
1. Summarizes the key points discussed in the blog post.
133+
2. Reinforces the importance of morning exercise.
134+
3. Encourages readers to take action and start their morning exercise routine.
135+
4. Maintains a positive and motivating tone.
136+
137+
Ensure the conclusion is concise, engaging, and leaves readers feeling inspired to make a change in their daily routine.
138+
139+
Finally, write the conclusion paragraph that encourages readers to start their morning exercise routine.
140+
""".strip()
141+
),
142+
requirements=[
143+
"Include a conclusion that encourages readers to start their morning exercise routine"
144+
],
145+
user_variables={
146+
"BLOG_TITLE": blog_title.value,
147+
"INTRODUCTION": introduction.value,
148+
"BENEFITS": benefits.value,
149+
},
150+
)
151+
assert conclusion.value is not None, 'ERROR: task "conclusion" execution failed'
152+
153+
# 5. Compile the title, introduction, three main benefits, and conclusion into a single cohesive blog post. - - FINAL_BLOG_POST
154+
final_blog_post = m.instruct(
155+
textwrap.dedent(
156+
R"""
157+
Your task is to compile the title, introduction, three main benefits, and conclusion into a single cohesive blog post about the benefits of morning exercise.
158+
159+
To accomplish this, follow these steps:
160+
161+
1. **Review the Components**:
162+
Carefully review the title, introduction, three main benefits, and conclusion that have been generated in the previous steps. These components are provided below:
163+
164+
<blog_title>
165+
{{BLOG_TITLE}}
166+
</blog_title>
167+
168+
<introduction>
169+
{{INTRODUCTION}}
170+
</introduction>
171+
172+
<benefits>
173+
{{BENEFITS}}
174+
</benefits>
175+
176+
<conclusion>
177+
{{CONCLUSION}}
178+
</conclusion>
179+
180+
2. **Structure the Blog Post**:
181+
Organize the components into a well-structured blog post. The structure should include:
182+
- The catchy title at the beginning.
183+
- The introduction paragraph that sets the stage for the blog post.
184+
- The three main benefits with detailed explanations.
185+
- The conclusion that encourages readers to start their morning exercise routine.
186+
187+
3. **Ensure Cohesion**:
188+
Make sure the blog post flows smoothly from one section to the next. The transitions between the introduction, benefits, and conclusion should be natural and logical.
189+
190+
4. **Check for Consistency**:
191+
Verify that the tone and style are consistent throughout the blog post. Ensure that the language used in the title, introduction, benefits, and conclusion aligns with the overall theme of the blog post.
192+
193+
5. **Final Review**:
194+
Read through the entire blog post to ensure it is cohesive, well-organized, and free of any grammatical or spelling errors. Make any necessary adjustments to improve clarity and readability.
195+
196+
6. **Output the Blog Post**:
197+
Provide the final compiled blog post as your answer. Ensure that the output includes only the blog post text without any additional information or instructions.
198+
199+
By following these steps, you will create a single cohesive blog post that effectively communicates the benefits of morning exercise.
200+
""".strip()
201+
),
202+
requirements=[
203+
"Include a catchy title",
204+
"Include an introduction paragraph",
205+
"Include three main benefits with explanations",
206+
"Include a conclusion that encourages readers to start their morning exercise routine",
207+
],
208+
user_variables={
209+
"BLOG_TITLE": blog_title.value,
210+
"INTRODUCTION": introduction.value,
211+
"BENEFITS": benefits.value,
212+
"CONCLUSION": conclusion.value,
213+
},
214+
)
215+
assert final_blog_post.value is not None, (
216+
'ERROR: task "final_blog_post" execution failed'
217+
)
218+
219+
220+
final_answer = final_blog_post.value
221+
222+
print(final_answer)

0 commit comments

Comments
 (0)