1+ import re
2+ import logging
3+ from typing import Tuple , Dict , Any , List
4+ import ast
5+ import traceback
6+
7+ logger = logging .getLogger (__name__ )
8+
9+ # Plugin identifier
10+ SLUG = "coc"
11+
12+ # Prompts
13+ CHAIN_OF_CODE_PROMPT = '''
14+ You are an AI assistant that uses Chain of Code (CoC) approach to solve problems. Follow these steps:
15+
16+ 1. Write Python code that breaks down the problem into clear steps
17+ 2. Each step should either be:
18+ - Executable Python code that performs computations
19+ - Pseudocode that you will simulate with natural language understanding
20+ 3. Track program state after each line execution
21+ 4. Return the final answer within the <output> tags
22+
23+ Format your response using:
24+ ```python
25+ [Your code here]
26+ ```
27+
28+ And track state after each line with:
29+ delta_state: {...}
30+
31+ Finally provide output as:
32+ <output>
33+ [Your final answer]
34+ </output>
35+ '''
36+
37+ STATE_SIMULATION_PROMPT = '''You are simulating the execution of Python code.
38+ Given the current program state and a line of code, return ONLY a Python dictionary representing the new state variables.
39+ Do not include any other text, code blocks, or formatting - just the Python dict.
40+
41+ For example:
42+ state = {'x': 5}
43+ code = "y = x + 3"
44+ You should return:
45+ {'y': 8}
46+ '''
47+
48+ def extract_code_blocks (text : str ) -> List [str ]:
49+ """Extract Python code blocks from text."""
50+ pattern = r'```python\s*(.*?)\s*```'
51+ matches = re .findall (pattern , text , re .DOTALL )
52+ return [m .strip () for m in matches ]
53+
54+ def extract_output (text : str ) -> str :
55+ """Extract content from output tags."""
56+ pattern = r'<output>(.*?)</output>'
57+ match = re .search (pattern , text , re .DOTALL )
58+ return match .group (1 ).strip () if match else text .strip ()
59+
60+ def extract_state_updates (text : str ) -> List [Dict [str , Any ]]:
61+ """Extract state updates from delta_state markers."""
62+ pattern = r'delta_state:\s*({.*?})'
63+ matches = re .findall (pattern , text , re .DOTALL )
64+ states = []
65+ for m in matches :
66+ try :
67+ # Clean up the state string before evaluation
68+ cleaned = re .sub (r'```python\s*|\s*```' , '' , m )
69+ state = ast .literal_eval (cleaned )
70+ states .append (state )
71+ except :
72+ logger .warning (f"Could not parse state update: { m } " )
73+ return states
74+
75+ def clean_state_response (response : str ) -> str :
76+ """Clean up LM state response to get just the dictionary."""
77+ # Remove any code blocks
78+ response = re .sub (r'```python\s*|\s*```' , '' , response )
79+ # Remove any natural language before or after the dict
80+ response = re .sub (r'^[^{]*' , '' , response )
81+ response = re .sub (r'[^}]*$' , '' , response )
82+ return response .strip ()
83+
84+ def execute_line (line : str , state : Dict [str , Any ], client , model : str ) -> Tuple [Any , Dict [str , Any ]]:
85+ """Execute a single line of code, either with Python or LM simulation."""
86+ try :
87+ # Try executing with Python
88+ # Create a copy of state for local execution
89+ local_state = state .copy ()
90+ exec (line , globals (), local_state )
91+ # Extract any new/modified variables
92+ new_state = {k :v for k ,v in local_state .items ()
93+ if k not in state or state [k ] != v }
94+ return None , new_state
95+ except Exception as e :
96+ # If Python execution fails, simulate with LM
97+ context = f"Current program state: { state } \n Execute line: { line } "
98+ response = client .chat .completions .create (
99+ model = model ,
100+ messages = [
101+ {"role" : "system" , "content" : STATE_SIMULATION_PROMPT },
102+ {"role" : "user" , "content" : context }
103+ ],
104+ temperature = 0.2
105+ )
106+ try :
107+ # Clean and parse LM response
108+ cleaned_response = clean_state_response (response .choices [0 ].message .content )
109+ new_state = ast .literal_eval (cleaned_response )
110+ return response .usage .completion_tokens , new_state
111+ except Exception as e :
112+ logger .error (f"Could not parse LM state response: { response .choices [0 ].message .content } " )
113+ logger .error (f"Error: { str (e )} " )
114+ logger .error (f"Cleaned response: { cleaned_response } " )
115+ return response .usage .completion_tokens , {}
116+
117+ def run (system_prompt : str , initial_query : str , client , model : str ) -> Tuple [str , int ]:
118+ """Main Chain of Code execution function."""
119+ # Generate initial code solution
120+ messages = [
121+ {"role" : "system" , "content" : system_prompt + "\n " + CHAIN_OF_CODE_PROMPT },
122+ {"role" : "user" , "content" : initial_query }
123+ ]
124+
125+ response = client .chat .completions .create (
126+ model = model ,
127+ messages = messages ,
128+ temperature = 0.7
129+ )
130+ initial_response = response .choices [0 ].message .content
131+ total_tokens = response .usage .completion_tokens
132+
133+ # Extract code blocks
134+ code_blocks = extract_code_blocks (initial_response )
135+ if not code_blocks :
136+ logger .warning ("No code blocks found in response" )
137+ return initial_response , total_tokens
138+
139+ # Execute code blocks line by line
140+ final_state = {}
141+ code = code_blocks [0 ] # Take first code block
142+
143+ # Split into lines and filter empty lines
144+ lines = [line .strip () for line in code .split ('\n ' ) if line .strip ()]
145+
146+ for line in lines :
147+ if not line or line .startswith ('#' ):
148+ continue
149+
150+ tokens , new_state = execute_line (line , final_state , client , model )
151+ if tokens :
152+ total_tokens += tokens
153+ final_state .update (new_state )
154+ logger .debug (f"Executed line: { line } " )
155+ logger .debug (f"New state: { new_state } " )
156+
157+ # Extract output tags from the initial response, or use answer from state
158+ final_answer = extract_output (initial_response )
159+ if not final_answer and 'answer' in final_state :
160+ final_answer = str (final_state ['answer' ])
161+
162+ return final_answer , total_tokens
0 commit comments