mcmas.ctx
1""" 2mcmas.ctx. 3""" 4 5import inspect 6import typing 7 8import pydantic 9 10import mcmas 11from mcmas import util 12 13LOGGER = util.get_logger(__name__) 14 15 16def patch_pydantic(): 17 """ 18 Patches current and future pydantic_ai.Agent instances to 19 have an additional `specification` attribute, which resolves 20 to a `mcmas.ispl.Agent`. 21 """ 22 LOGGER.warning("patching pydantic agent") 23 pydantic_ai = get_pydantic_ai() 24 if pydantic_ai: 25 pydantic_ai.Agent.specification = property( 26 lambda self: mcmas.ispl.Agent(**agent_builder[self]) 27 ) 28 oinit = pydantic_ai.Agent.__init__ 29 otool = pydantic_ai.Agent.tool 30 31 def agent_data(obj): 32 return { 33 "actions": ["none"], 34 "metadata": {"file": inspect.getfile(obj.__class__)}, 35 } 36 37 def init(self, *args, **kwargs): 38 LOGGER.warning("running patched init") 39 oinit(self, *args, **kwargs) 40 agent_builder.add_tag(self, **agent_data(self)) 41 42 def tool(self, fxn, *args, **kwargs): 43 out = otool(self, fxn, *args, **kwargs) 44 agent_builder.add_tag( 45 self, 46 **{ 47 **agent_data(self), 48 **{ 49 "actions": agent_builder[self].get("actions", []) 50 + [f"{fxn.__name__}"], 51 }, 52 }, 53 ) 54 # raise Exception([args,kwargs]) 55 return out 56 57 LOGGER.warning(f"patching class: {pydantic_ai.Agent}") 58 pydantic_ai.Agent.__init__ = init 59 pydantic_ai.Agent.tool = tool 60 61 for obj in util.find_instances(pydantic_ai.Agent): 62 LOGGER.warning(f"patching {obj}") 63 obj.__init__ = init 64 obj.tool = tool 65 agent_builder.add_tag(obj) 66 agent_builder.add_tag( 67 obj, 68 **{ 69 **agent_data(obj), 70 **{ 71 "actions": agent_builder[obj].get("actions", []) 72 + list(obj._function_toolset.tools.keys()), 73 }, 74 }, 75 ) 76 77 78class ModelBuilder: 79 """ 80 81 """ 82 83 def __init__(self): 84 self.TAGS = {} 85 86 @property 87 def wrapping(self): 88 from mcmas.models import Agent 89 90 return Agent 91 92 def __call__(self, obj: typing.Any, **data) -> typing.Any: 93 """ 94 95 """ 96 LOGGER.warning(f"updating {obj} with {data}") 97 key = self.key_for(obj) 98 orig = self.TAGS.get(key, {}) 99 orig.update(**data) 100 self.TAGS[key] = orig 101 return self.wrapping(**orig) 102 103 @pydantic.validate_call 104 def key_for(self, obj: typing.Any) -> str: 105 """ 106 107 """ 108 skey = getattr(obj, "name", str(obj)) 109 key = f"{obj.__class__.__module__}.{obj.__class__.__name__}.{skey}" 110 return key 111 112 @pydantic.validate_call 113 def __getitem__(self, other) -> typing.Dict: 114 return self.TAGS.get(self.key_for(other), {}) 115 116 @pydantic.validate_call 117 def __setitem__(self, obj, val: typing.Dict) -> typing.Any: 118 return self.add_tag(self.key_for(obj), **val) 119 120 def add_tag(self, obj, **tags) -> typing.Any: 121 """ 122 123 """ 124 LOGGER.warning(f"tagging {obj}") 125 # skey = getattr(obj, 'name', str(obj)) 126 key = self.key_for(obj) 127 # f"{obj.__class__.__module__}.{obj.__class__.__name__}.{skey}" 128 _tags = self.TAGS.get(key, {}) 129 _tags.update(**tags) 130 self.TAGS[key] = _tags 131 # .setdefault(key, {}).update(**tag) 132 LOGGER.warning(f"tagged {obj} with {_tags}") 133 134 return obj 135 136 137agent_builder = ModelBuilder() 138 139 140def get_pydantic_ai(): 141 try: 142 import pydantic_ai 143 144 return pydantic_ai 145 except (ImportError,): 146 LOGGER.critical( 147 "`pydantic_ai` module not available. " 148 "pip install py-mcmas[ai] or pydantic-ai" 149 ) 150 return None
LOGGER =
<Logger mcmas.ctx (INFO)>
def
patch_pydantic():
17def patch_pydantic(): 18 """ 19 Patches current and future pydantic_ai.Agent instances to 20 have an additional `specification` attribute, which resolves 21 to a `mcmas.ispl.Agent`. 22 """ 23 LOGGER.warning("patching pydantic agent") 24 pydantic_ai = get_pydantic_ai() 25 if pydantic_ai: 26 pydantic_ai.Agent.specification = property( 27 lambda self: mcmas.ispl.Agent(**agent_builder[self]) 28 ) 29 oinit = pydantic_ai.Agent.__init__ 30 otool = pydantic_ai.Agent.tool 31 32 def agent_data(obj): 33 return { 34 "actions": ["none"], 35 "metadata": {"file": inspect.getfile(obj.__class__)}, 36 } 37 38 def init(self, *args, **kwargs): 39 LOGGER.warning("running patched init") 40 oinit(self, *args, **kwargs) 41 agent_builder.add_tag(self, **agent_data(self)) 42 43 def tool(self, fxn, *args, **kwargs): 44 out = otool(self, fxn, *args, **kwargs) 45 agent_builder.add_tag( 46 self, 47 **{ 48 **agent_data(self), 49 **{ 50 "actions": agent_builder[self].get("actions", []) 51 + [f"{fxn.__name__}"], 52 }, 53 }, 54 ) 55 # raise Exception([args,kwargs]) 56 return out 57 58 LOGGER.warning(f"patching class: {pydantic_ai.Agent}") 59 pydantic_ai.Agent.__init__ = init 60 pydantic_ai.Agent.tool = tool 61 62 for obj in util.find_instances(pydantic_ai.Agent): 63 LOGGER.warning(f"patching {obj}") 64 obj.__init__ = init 65 obj.tool = tool 66 agent_builder.add_tag(obj) 67 agent_builder.add_tag( 68 obj, 69 **{ 70 **agent_data(obj), 71 **{ 72 "actions": agent_builder[obj].get("actions", []) 73 + list(obj._function_toolset.tools.keys()), 74 }, 75 }, 76 )
Patches current and future pydantic_ai.Agent instances to
have an additional specification attribute, which resolves
to a mcmas.ispl.Agent.
class
ModelBuilder:
79class ModelBuilder: 80 """ 81 82 """ 83 84 def __init__(self): 85 self.TAGS = {} 86 87 @property 88 def wrapping(self): 89 from mcmas.models import Agent 90 91 return Agent 92 93 def __call__(self, obj: typing.Any, **data) -> typing.Any: 94 """ 95 96 """ 97 LOGGER.warning(f"updating {obj} with {data}") 98 key = self.key_for(obj) 99 orig = self.TAGS.get(key, {}) 100 orig.update(**data) 101 self.TAGS[key] = orig 102 return self.wrapping(**orig) 103 104 @pydantic.validate_call 105 def key_for(self, obj: typing.Any) -> str: 106 """ 107 108 """ 109 skey = getattr(obj, "name", str(obj)) 110 key = f"{obj.__class__.__module__}.{obj.__class__.__name__}.{skey}" 111 return key 112 113 @pydantic.validate_call 114 def __getitem__(self, other) -> typing.Dict: 115 return self.TAGS.get(self.key_for(other), {}) 116 117 @pydantic.validate_call 118 def __setitem__(self, obj, val: typing.Dict) -> typing.Any: 119 return self.add_tag(self.key_for(obj), **val) 120 121 def add_tag(self, obj, **tags) -> typing.Any: 122 """ 123 124 """ 125 LOGGER.warning(f"tagging {obj}") 126 # skey = getattr(obj, 'name', str(obj)) 127 key = self.key_for(obj) 128 # f"{obj.__class__.__module__}.{obj.__class__.__name__}.{skey}" 129 _tags = self.TAGS.get(key, {}) 130 _tags.update(**tags) 131 self.TAGS[key] = _tags 132 # .setdefault(key, {}).update(**tag) 133 LOGGER.warning(f"tagged {obj} with {_tags}") 134 135 return obj
def
add_tag(self, obj, **tags) -> Any:
121 def add_tag(self, obj, **tags) -> typing.Any: 122 """ 123 124 """ 125 LOGGER.warning(f"tagging {obj}") 126 # skey = getattr(obj, 'name', str(obj)) 127 key = self.key_for(obj) 128 # f"{obj.__class__.__module__}.{obj.__class__.__name__}.{skey}" 129 _tags = self.TAGS.get(key, {}) 130 _tags.update(**tags) 131 self.TAGS[key] = _tags 132 # .setdefault(key, {}).update(**tag) 133 LOGGER.warning(f"tagged {obj} with {_tags}") 134 135 return obj
agent_builder =
<ModelBuilder object>
def
get_pydantic_ai():