-
Notifications
You must be signed in to change notification settings - Fork 105
feat: (m-decompose) Module Prompt V3 #770
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
f9e0c26
b1bc264
c281891
445ce45
1e39de1
84027cc
985a75f
0376fae
cad3c65
415fef5
fb45a6d
131d0d9
dd7a58e
532ff9a
46fd70a
1ef938f
fc89d78
ef56b2c
ab7082f
1db129e
718115d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,100 @@ | ||
| {% if user_inputs -%} | ||
| import os | ||
| {% endif -%} | ||
| import textwrap | ||
|
|
||
| import mellea | ||
|
|
||
| {%- set ns = namespace(need_req=false) -%} | ||
| {%- for item in subtasks -%} | ||
| {%- for c in item.constraints or [] -%} | ||
| {%- if c.val_fn -%} | ||
| {%- set ns.need_req = true -%} | ||
| {%- endif -%} | ||
| {%- endfor -%} | ||
| {%- endfor %} | ||
|
|
||
| {%- if ns.need_req %} | ||
| from mellea.stdlib.requirements import req | ||
| {%- for c in identified_constraints %} | ||
| {%- if c.val_fn and c.val_fn_name %} | ||
| from validations.{{ c.val_fn_name }} import validate_input as {{ c.val_fn_name }} | ||
| {%- endif %} | ||
| {%- endfor %} | ||
| {%- endif %} | ||
|
|
||
| m = mellea.start_session(model_id="mistral-small3.2:latest") | ||
| {%- if user_inputs %} | ||
|
|
||
|
|
||
| # User Input Variables | ||
| try: | ||
| {%- for var in user_inputs %} | ||
| {{ var | lower }} = os.environ["{{ var | upper }}"] | ||
| {%- endfor %} | ||
| except KeyError as e: | ||
| raise SystemExit(f"ERROR: One or more required environment variables are not set: {e}") | ||
| {%- endif %} | ||
| {%- for item in subtasks %} | ||
|
|
||
|
|
||
| {{ item.tag | lower }}_gnrl = textwrap.dedent( | ||
| R""" | ||
| {{ item.general_instructions | trim | indent(width=4, first=False) }} | ||
| """.strip() | ||
| ) | ||
| {{ item.tag | lower }} = m.instruct( | ||
| {%- if not (item.input_vars_required or []) %} | ||
| {{ item.subtask[3:] | trim | tojson }}, | ||
| {%- else %} | ||
| textwrap.dedent( | ||
| R""" | ||
| {{ item.subtask[3:] | trim }} | ||
|
|
||
| Here are the input variables and their content: | ||
| {%- for var in item.input_vars_required or [] %} | ||
|
|
||
| - {{ var | upper }} = {{ "{{" }}{{ var | upper }}{{ "}}" }} | ||
| {%- endfor %} | ||
| """.strip() | ||
| ), | ||
| {%- endif %} | ||
| {%- if item.constraints %} | ||
| requirements=[ | ||
| {%- for c in item.constraints %} | ||
| {%- if c.val_fn and c.val_fn_name %} | ||
| req( | ||
| {{ c.constraint | tojson}}, | ||
| validation_fn={{ c.val_fn_name }}, | ||
| ), | ||
| {%- else %} | ||
| {{ c.constraint | tojson}}, | ||
| {%- endif %} | ||
| {%- endfor %} | ||
| ], | ||
| {%- else %} | ||
| requirements=None, | ||
| {%- endif %} | ||
| {%- if item.input_vars_required %} | ||
| user_variables={ | ||
| {%- for var in item.input_vars_required or [] %} | ||
| {{ var | upper | tojson }}: {{ var | lower }}, | ||
| {%- endfor %} | ||
| }, | ||
| {%- endif %} | ||
| grounding_context={ | ||
| "GENERAL_INSTRUCTIONS": {{ item.tag | lower }}_gnrl, | ||
| {%- for var in item.depends_on or [] %} | ||
| {{ var | upper | tojson }}: {{ var | lower }}.value, | ||
| {%- endfor %} | ||
| }, | ||
| ) | ||
| assert {{ item.tag | lower }}.value is not None, 'ERROR: task "{{ item.tag | lower }}" execution failed' | ||
| {%- if loop.last %} | ||
|
|
||
|
|
||
| final_answer = {{ item.tag | lower }}.value | ||
|
|
||
| print(final_answer) | ||
| {%- endif -%} | ||
| {%- endfor -%} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -19,7 +19,7 @@ | |
| ) | ||
|
|
||
| RE_ASSIGNED_CONS = re.compile( | ||
| r"<assigned_constraints>(.+?)</assigned_constraints>", | ||
| r"<assigned_constraints>(.*?)</assigned_constraints>", | ||
| flags=re.IGNORECASE | re.DOTALL, | ||
| ) | ||
|
|
||
|
|
@@ -57,12 +57,12 @@ def _default_parser(generated_str: str) -> list[SubtaskPromptConstraintsItem]: | |
| For example | ||
| ``` | ||
| [ SubtaskPromptConstraintsItem( | ||
| subtask=<str>, | ||
| tag=<str>, | ||
| prompt_template=<str> | ||
| constraints=<list[str]> | ||
| ), | ||
| ... | ||
| subtask=<str>, | ||
| tag=<str>, | ||
| prompt_template=<str> | ||
| constraints=<list[str]> | ||
| ), | ||
| ... | ||
| ] | ||
| ``` | ||
|
|
||
|
|
@@ -92,18 +92,24 @@ def _default_parser(generated_str: str) -> list[SubtaskPromptConstraintsItem]: | |
|
|
||
| subtask_constraint_assign_match = re.search(RE_ASSIGNED_CONS, data[3]) | ||
|
|
||
| subtask_constraint_assign_str: str | None = ( | ||
| # ===== fallback: use raw text when there is no tag ===== | ||
| subtask_constraint_assign_str: str = ( | ||
| subtask_constraint_assign_match.group(1).strip() | ||
| if subtask_constraint_assign_match | ||
| else None | ||
| else data[3].strip() | ||
| ) | ||
|
|
||
| if subtask_constraint_assign_str is None: | ||
| raise TagExtractionError( | ||
| 'LLM failed to generate correct tags for extraction: "<assigned_constraints>"' | ||
| ) | ||
| subtask_constraint_assign_str = re.sub( | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. pattern is already compiled as |
||
| r"\n*All tags are closed and my assignment is finished\.\s*$", | ||
| "", | ||
| subtask_constraint_assign_str, | ||
| flags=re.IGNORECASE, | ||
| ).strip() | ||
|
|
||
| subtask_constraint_assign_str_upper = subtask_constraint_assign_str.upper() | ||
|
|
||
| subtask_constraint_assign: list[str] = [] | ||
|
|
||
| if ( | ||
| "N/A" in subtask_constraint_assign_str_upper | ||
| or "N / A" in subtask_constraint_assign_str_upper | ||
|
|
@@ -112,10 +118,22 @@ def _default_parser(generated_str: str) -> list[SubtaskPromptConstraintsItem]: | |
| ): | ||
| subtask_constraint_assign = [] | ||
| else: | ||
| subtask_constraint_assign = [ | ||
| line.strip()[2:] if line.strip()[:2] == "- " else line.strip() | ||
| for line in subtask_constraint_assign_str.splitlines() | ||
| ] | ||
| for line in subtask_constraint_assign_str.splitlines(): | ||
| stripped = line.strip() | ||
|
|
||
| if not stripped: | ||
| continue | ||
|
|
||
| # Only keep lines starting with "- " | ||
| if stripped.startswith("- "): | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This silently drops any constraint not prefixed with |
||
| value = stripped[2:].strip() | ||
| if value: | ||
| subtask_constraint_assign.append(value) | ||
|
|
||
| # Remove duplicates while preserving order | ||
| subtask_constraint_assign = list( | ||
| dict.fromkeys(subtask_constraint_assign) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Probably fine in practice, but |
||
| ) | ||
|
|
||
| result.append( | ||
| SubtaskPromptConstraintsItem( | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
silently swallows the block when the tag is missing. general-instructions parser has a nicer graduated fallback (open-tag-only). Log warning at a minimum (how do we return?)