| 1 | """Parse actions & format observations without toolcalls.
|
| 2 | This was the method used for mini-swe-agent v1.0 and the original SWE-agent.
|
| 3 | As of mini-swe-agent v2.0, we strongly recommend to use toolcalls instead.
|
| 4 | """
|
| 5 |
|
| 6 | import re
|
| 7 | import time
|
| 8 |
|
| 9 | from jinja2 import StrictUndefined, Template
|
| 10 |
|
| 11 | from minisweagent.exceptions import FormatError
|
| 12 | from minisweagent.models.utils.openai_multimodal import expand_multimodal_content
|
| 13 |
|
| 14 |
|
| 15 | def parse_regex_actions(content: str, *, action_regex: str, format_error_template: str) -> list[dict]:
|
| 16 | """Parse actions from text content using regex. Raises FormatError if not exactly one action."""
|
| 17 | actions = [a.strip() for a in re.findall(action_regex, content, re.DOTALL)]
|
| 18 | if len(actions) != 1:
|
| 19 | raise FormatError(
|
| 20 | {
|
| 21 | "role": "user",
|
| 22 | "content": Template(format_error_template, undefined=StrictUndefined).render(actions=actions),
|
| 23 | "extra": {
|
| 24 | "interrupt_type": "FormatError",
|
| 25 | "n_actions": len(actions),
|
| 26 | "model_response": content,
|
| 27 | },
|
| 28 | }
|
| 29 | )
|
| 30 | return [{"command": action} for action in actions]
|
| 31 |
|
| 32 |
|
| 33 | def format_observation_messages(
|
| 34 | outputs: list[dict],
|
| 35 | *,
|
| 36 | observation_template: str,
|
| 37 | template_vars: dict | None = None,
|
| 38 | multimodal_regex: str = "",
|
| 39 | ) -> list[dict]:
|
| 40 | """Format execution outputs into user observation messages."""
|
| 41 | results = []
|
| 42 | for output in outputs:
|
| 43 | content = Template(observation_template, undefined=StrictUndefined).render(
|
| 44 | output=output, **(template_vars or {})
|
| 45 | )
|
| 46 | msg: dict = {
|
| 47 | "role": "user",
|
| 48 | "content": content,
|
| 49 | "extra": {
|
| 50 | "raw_output": output.get("output", ""),
|
| 51 | "returncode": output.get("returncode"),
|
| 52 | "timestamp": time.time(),
|
| 53 | "exception_info": output.get("exception_info"),
|
| 54 | **output.get("extra", {}),
|
| 55 | },
|
| 56 | }
|
| 57 | if multimodal_regex:
|
| 58 | msg = expand_multimodal_content(msg, pattern=multimodal_regex)
|
| 59 | results.append(msg)
|
| 60 | return results
|
| 61 |
|