Write parse_react_trace(text) returning a list of step dicts. A step may have keys thought, action, action_input, observation. Actions look like 'Action: name[input]'. An 'Observation:' line closes the current step; a new 'Thought:' also starts a new step if the current one already has content. Standard library only.
from unittest import TestCase
from exercise import parse_react_trace
class Evaluate(TestCase):
def test_parses_action_name(self):
steps = parse_react_trace('Thought: add them\nAction: add[2, 3]\nObservation: 5')
self.assertEqual(steps[0]['action'], 'add')
def test_parses_action_input(self):
steps = parse_react_trace('Action: add[2, 3]\nObservation: 5')
self.assertEqual(steps[0]['action_input'], '2, 3')
def test_observation_closes_step(self):
steps = parse_react_trace('Thought: a\nAction: x[1]\nObservation: ok')
self.assertEqual(steps[0]['observation'], 'ok')
def test_two_steps(self):
text = 'Thought: a\nAction: x[1]\nObservation: o1\nThought: b\nAction: y[2]\nObservation: o2'
self.assertEqual(len(parse_react_trace(text)), 2)
import re
_THOUGHT = re.compile(r'Thought:\s*(.+)')
_ACTION = re.compile(r'Action:\s*([A-Za-z0-9_\-]+)\s*\[(.*?)\]')
_OBS = re.compile(r'Observation:\s*(.+)')
def parse_react_trace(text):
steps = []
cur = {}
for line in text.splitlines():
line = line.strip()
if not line:
continue
m = _THOUGHT.match(line)
if m:
if cur.get('thought') or cur.get('action'):
steps.append(cur); cur = {}
cur['thought'] = m.group(1).strip(); continue
m = _ACTION.match(line)
if m:
cur['action'] = m.group(1).strip()
cur['action_input'] = m.group(2).strip(); continue
m = _OBS.match(line)
if m:
cur['observation'] = m.group(1).strip()
steps.append(cur); cur = {}
if cur.get('thought') or cur.get('action'):
steps.append(cur)
return steps