11"""Custom MCP tool definitions for the agent SDK approach."""
22import json
33import logging
4+ import os
45import traceback
56from dataclasses import dataclass , field
67from typing import Any , Callable , Dict , List , Optional , Set
@@ -80,6 +81,7 @@ class ToolContext:
8081 iteration_history : List [Dict [str , Any ]] = field (default_factory = list )
8182 skill_factory_context : Dict [str , Any ] = field (default_factory = dict )
8283 proposals_disabled : bool = False # set True during test-time solving
84+ log_dir : Optional [str ] = None
8385
8486
8587def _text_result (text : str ) -> Dict [str , Any ]:
@@ -105,6 +107,23 @@ def create_mcp_tools(ctx: ToolContext,
105107 """
106108 from claude_agent_sdk import tool
107109
110+ _propose_count = [0 ] # mutable counter in closure
111+
112+ def _save_proposal_code (tool_name : str , code : str , names : List [str ],
113+ description : str ) -> None :
114+ if not ctx .log_dir :
115+ return
116+ _propose_count [0 ] += 1
117+ subdir = os .path .join (ctx .log_dir , "proposed_code" )
118+ os .makedirs (subdir , exist_ok = True )
119+ names_slug = "_" .join (names )[:80 ]
120+ filename = f"{ _propose_count [0 ]:03d} _{ tool_name } _{ names_slug } .py"
121+ filepath = os .path .join (subdir , filename )
122+ header = f'"""{ tool_name } : { description } """\n \n '
123+ with open (filepath , "w" ) as f :
124+ f .write (header + code )
125+ logging .info (f"Saved proposal code to { filepath } " )
126+
108127 # ===== INSPECTION TOOLS =====
109128
110129 @tool ("inspect_types" , "List all object types and their features" , {})
@@ -338,6 +357,8 @@ async def propose_types(args: Dict[str, Any]) -> Dict[str, Any]:
338357 ctx .iteration_proposals .proposed_types |= proposed
339358 names = [t .name for t in proposed ]
340359 logging .info (f"Agent proposed types: { names } " )
360+ _save_proposal_code ("propose_types" , code , names ,
361+ args .get ("description" , "" ))
341362 return _text_result (
342363 f"Successfully proposed { len (proposed )} types: { names } " )
343364
@@ -389,6 +410,8 @@ async def propose_predicates(args: Dict[str, Any]) -> Dict[str, Any]:
389410 ctx .iteration_proposals .proposed_predicates |= proposed
390411 names = [p .name for p in proposed ]
391412 logging .info (f"Agent proposed predicates: { names } " )
413+ _save_proposal_code ("propose_predicates" , code , names ,
414+ args .get ("description" , "" ))
392415
393416 msg = f"Successfully proposed { len (proposed )} predicates: { names } "
394417 if errors :
@@ -446,6 +469,8 @@ async def propose_object_augmentor(args: Dict[str, Any]) -> Dict[str, Any]:
446469 ctx .iteration_proposals .augment_task_fn = result
447470 ctx .iteration_proposals .augment_task_code = code
448471 logging .info (f"Agent proposed augmentor adding objects: { obj_names } " )
472+ _save_proposal_code ("propose_object_augmentor" , code , obj_names ,
473+ args .get ("description" , "" ))
449474 return _text_result (
450475 f"Successfully proposed augmentor. Test added objects: { obj_names } "
451476 )
@@ -488,6 +513,8 @@ async def propose_processes(args: Dict[str, Any]) -> Dict[str, Any]:
488513 ctx .iteration_proposals .proposed_processes |= proposed
489514 names = [p .name for p in proposed ]
490515 logging .info (f"Agent proposed processes: { names } " )
516+ _save_proposal_code ("propose_processes" , code , names ,
517+ args .get ("description" , "" ))
491518 return _text_result (
492519 f"Successfully proposed { len (proposed )} processes: { names } " )
493520
@@ -538,6 +565,8 @@ async def propose_options(args: Dict[str, Any]) -> Dict[str, Any]:
538565 ctx .options |= proposed
539566 names = [o .name for o in proposed ]
540567 logging .info (f"Agent proposed options: { names } " )
568+ _save_proposal_code ("propose_options" , code , names ,
569+ args .get ("description" , "" ))
541570 return _text_result (
542571 f"Successfully proposed { len (proposed )} options: { names } " )
543572
0 commit comments