agentx-dev 2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,2 @@
1
+ graft agentx_dev
2
+ prune tests
@@ -0,0 +1,112 @@
1
+ Metadata-Version: 2.4
2
+ Name: agentx-dev
3
+ Version: 2.0
4
+ Summary: A lightweight LLM agent framework with standard and structured tool support use, prompt management, and support for OpenAI.
5
+ Author-email: Bruce-Arhin Shadrach <brucearhin098@gmail.com>
6
+ Project-URL: Homepage, https://github.com/shadrach098/Bruce_framework
7
+ Project-URL: Bug Tracker, https://github.com/shadrach098/Bruce_framework/issues
8
+ Project-URL: Source, https://github.com/shadrach098/Bruce_framework
9
+ Requires-Python: >=3.8
10
+ Description-Content-Type: text/markdown
11
+ Requires-Dist: openai>=1.0.0
12
+ Requires-Dist: pydantic>=2.0
13
+ Requires-Dist: google-generativeai
14
+ Requires-Dist: httpx
15
+ Requires-Dist: PyYAML>=5.3.1
16
+
17
+
18
+ # 🧠 Bruce Agent
19
+
20
+ **AgentX** is a lightweight, extensible agentic framework for building custom LLM agents with structured tool use, prompt templates, and integration with OpenAI and Gemini models.
21
+
22
+ ## 🚀 Features
23
+
24
+ - 🔁 Custom reasoning loop (`AgentRunner`)
25
+ - 🧩 Structured tool execution (Pydantic-based)
26
+ - 💬 Prompt templating and management
27
+ - 🔌 LLM-agnostic: supports **OpenAI function calling** and **Google Gemini**
28
+ - 🪄 Easy-to-use API for building agents
29
+
30
+ ## 📦 Installation
31
+
32
+ published to PyPI:
33
+
34
+ ```sh
35
+ pip install AgentX-Dev
36
+ ```
37
+
38
+ ## Example use
39
+
40
+ ```python
41
+ from AgentXL import AgentRunner, AgentType,ChatModel
42
+ from pydantic import BaseModel
43
+ from AgentXL.Tools import StructuredTool,StandardTool
44
+ # Define a sample Stuctured tool
45
+ class MultiplyTool(BaseModel):
46
+ a: int
47
+ b: int
48
+
49
+ def multiply(a: int, b: int) -> int:
50
+ return a * b
51
+
52
+ # Define a sample Standard tool
53
+ def Weather(weather:str):
54
+ return f"{weather} is currently at 28 degree with a high of 32 and a low of 18 "
55
+
56
+ # Create chat model and agent
57
+ ReAct=AgentType.ReAct
58
+ chat_model = ChatModel.GPT(model="gpt-4", temperature=0.7)
59
+ tools = [StructuredTool(name="MultiplyTool",
60
+ description="useful when you need to add two numbers",
61
+ func=multiply,
62
+ args_schema=MultiplyTool
63
+ ),
64
+ StandardTool(name="Weather",
65
+ description="when you need to check the weather of a location, input should be the str of the location",
66
+ func=Weather)]
67
+ # Create an AgentRunner instance
68
+ agent = AgentRunner(model=chat_model,Agent=ReAct, tools=tools)
69
+
70
+ # Initialize the agent with user input
71
+ response = agent.Initialize("What is 5 times 8?")
72
+
73
+ # Print the result
74
+ print(response.content)
75
+
76
+
77
+ # output the Agent completion
78
+ agent.Initialize("i need the weather in Barrie")
79
+
80
+
81
+ ```
82
+
83
+ ``` bruce_framework/
84
+ ├── src/
85
+ │ └── bruce_framework/
86
+ │ ├── __init__.py
87
+ │ ├── agent/
88
+ │ │ ├── __init__.py
89
+ │ │ └── agent.py
90
+ │ ├── runner/
91
+ │ │ ├── __init__.py
92
+ │ │ └── agent_run.py
93
+ │ └── chatmodel.py
94
+ ├── README.md
95
+ ├── LICENSE
96
+ └── pyproject.toml
97
+
98
+ ```
99
+
100
+ ## 📚 Documentation (Coming Soon)
101
+ ### More tutorials, tool examples, and structured prompting guides coming soon.
102
+
103
+ ## 🧑‍💻 Author
104
+ #### Bruce-Arhin Shadrach
105
+ #### 📧 brucearhin098@gmail.com
106
+ #### 🌐 GitHub
107
+
108
+ 📝 License
109
+ MIT License
110
+
111
+
112
+
@@ -0,0 +1,96 @@
1
+
2
+ # 🧠 Bruce Agent
3
+
4
+ **AgentX** is a lightweight, extensible agentic framework for building custom LLM agents with structured tool use, prompt templates, and integration with OpenAI and Gemini models.
5
+
6
+ ## 🚀 Features
7
+
8
+ - 🔁 Custom reasoning loop (`AgentRunner`)
9
+ - 🧩 Structured tool execution (Pydantic-based)
10
+ - 💬 Prompt templating and management
11
+ - 🔌 LLM-agnostic: supports **OpenAI function calling** and **Google Gemini**
12
+ - 🪄 Easy-to-use API for building agents
13
+
14
+ ## 📦 Installation
15
+
16
+ published to PyPI:
17
+
18
+ ```sh
19
+ pip install AgentX-Dev
20
+ ```
21
+
22
+ ## Example use
23
+
24
+ ```python
25
+ from AgentXL import AgentRunner, AgentType,ChatModel
26
+ from pydantic import BaseModel
27
+ from AgentXL.Tools import StructuredTool,StandardTool
28
+ # Define a sample Stuctured tool
29
+ class MultiplyTool(BaseModel):
30
+ a: int
31
+ b: int
32
+
33
+ def multiply(a: int, b: int) -> int:
34
+ return a * b
35
+
36
+ # Define a sample Standard tool
37
+ def Weather(weather:str):
38
+ return f"{weather} is currently at 28 degree with a high of 32 and a low of 18 "
39
+
40
+ # Create chat model and agent
41
+ ReAct=AgentType.ReAct
42
+ chat_model = ChatModel.GPT(model="gpt-4", temperature=0.7)
43
+ tools = [StructuredTool(name="MultiplyTool",
44
+ description="useful when you need to add two numbers",
45
+ func=multiply,
46
+ args_schema=MultiplyTool
47
+ ),
48
+ StandardTool(name="Weather",
49
+ description="when you need to check the weather of a location, input should be the str of the location",
50
+ func=Weather)]
51
+ # Create an AgentRunner instance
52
+ agent = AgentRunner(model=chat_model,Agent=ReAct, tools=tools)
53
+
54
+ # Initialize the agent with user input
55
+ response = agent.Initialize("What is 5 times 8?")
56
+
57
+ # Print the result
58
+ print(response.content)
59
+
60
+
61
+ # output the Agent completion
62
+ agent.Initialize("i need the weather in Barrie")
63
+
64
+
65
+ ```
66
+
67
+ ``` bruce_framework/
68
+ ├── src/
69
+ │ └── bruce_framework/
70
+ │ ├── __init__.py
71
+ │ ├── agent/
72
+ │ │ ├── __init__.py
73
+ │ │ └── agent.py
74
+ │ ├── runner/
75
+ │ │ ├── __init__.py
76
+ │ │ └── agent_run.py
77
+ │ └── chatmodel.py
78
+ ├── README.md
79
+ ├── LICENSE
80
+ └── pyproject.toml
81
+
82
+ ```
83
+
84
+ ## 📚 Documentation (Coming Soon)
85
+ ### More tutorials, tool examples, and structured prompting guides coming soon.
86
+
87
+ ## 🧑‍💻 Author
88
+ #### Bruce-Arhin Shadrach
89
+ #### 📧 brucearhin098@gmail.com
90
+ #### 🌐 GitHub
91
+
92
+ 📝 License
93
+ MIT License
94
+
95
+
96
+
@@ -0,0 +1,349 @@
1
+ """
2
+ This module contains classes and functions for working with agent prompts and JSON data.
3
+
4
+ It includes classes for different agent prompt templates, a function to convert strings to JSON,
5
+ and a container class for standard pre-defined agent prompt templates.
6
+ """
7
+
8
+ import yaml,logging,json,uuid,time,os
9
+ from pydantic import BaseModel, Field, ValidationError
10
+ from typing import Dict, Any,Type,Optional,List,Union
11
+ from rich.console import Console
12
+ console=Console()
13
+ # Set up logging
14
+ logging.basicConfig(level=logging.ERROR)
15
+ logger = logging.getLogger(__name__)
16
+
17
+ class StandardParser(BaseModel):
18
+ """
19
+ A Pydantic model representing the standard parser.
20
+
21
+ Attributes:
22
+ - action: str, the action to take.
23
+ - action_input: str or Dict, the input to the action.
24
+
25
+ Methods:
26
+ - from_json: Creates an instance from a JSON string.
27
+ """
28
+ action: str = Field("The action to take", alias='action')
29
+ action_input: str | Dict = Field("The input to the action", alias='action_input')
30
+
31
+ class Config:
32
+ populate_by_name = True
33
+
34
+ @classmethod
35
+ def from_json(cls, json_str: str):
36
+ try:
37
+ json_object = convert_to_json(json_str)
38
+ if isinstance(json_object,dict):
39
+ return cls(**json_object)
40
+ elif isinstance(json_object,str):
41
+ return json_object
42
+ except (ValueError, ValidationError) as e:
43
+ logger.error(f"Error creating StandardParser instance: {e}")
44
+ raise
45
+
46
+
47
+
48
+
49
+
50
+
51
+ def load_prompt_templates(file_path: str) -> Dict:
52
+ """
53
+ Loads prompt templates from a YAML file.
54
+
55
+ Args:
56
+ - file_path: str, the path to the YAML file containing the prompt templates.
57
+
58
+ Returns:
59
+ - Dict: A dictionary containing the loaded prompt templates.
60
+ """
61
+ if not os.path.exists(file_path):
62
+ raise FileNotFoundError(f"Can't find file {file_path}")
63
+ with open(file_path, 'r') as yaml_:
64
+
65
+ return yaml.safe_load(yaml_)
66
+
67
+ system = load_prompt_templates( r"..\promptTemplate.yaml")
68
+
69
+
70
+ def convert_to_json(json_str: str) -> Dict[str, Any]:
71
+ """
72
+ Converts a given string into a JSON object.
73
+
74
+ Args:
75
+ - json_str: str, the string to be converted into JSON.
76
+
77
+ Returns:
78
+ - Dict[str, Any]: A dictionary representing the JSON object.
79
+
80
+ Raises:
81
+ - json.JSONDecodeError: If the input string is not valid JSON.
82
+ """
83
+ try:
84
+ if json_str.startswith("```json") and json_str.endswith("```"):
85
+ return json.loads(json_str.split("```json")[-1].split("```")[0])
86
+ elif json_str.startswith('{') and json_str.endswith('}'):
87
+ return json.loads(json_str)
88
+ else :
89
+ return json_str
90
+ except json.JSONDecodeError as e:
91
+ logger.error(f"Failed to decode JSON: {e}")
92
+ return f"Failed to decode JSON: {e}" # or you can re-raise the exception, depending on your error handling strategy
93
+
94
+ # Consider adding a Config class to these models to allow population by field name
95
+ class Instruction_Tuned_(BaseModel):
96
+ """
97
+ A Pydantic model representing the Instruction-Tuned prompt template.
98
+
99
+ Attributes:
100
+ - action: str, the action to take or final answer.
101
+ - action_input: str or Dict, the input to the action.
102
+
103
+ Methods:
104
+ - from_json: Creates an instance from a JSON string.
105
+ """
106
+ action: str = Field("The action to take OR Final Answer", alias="action")
107
+ action_input: str | Dict = Field("The input to the action OR You should put what you want to return to use here and return to user immediately", alias="action_input")
108
+
109
+
110
+ @classmethod
111
+ def from_json(cls, json_str: str):
112
+ try:
113
+ json_object = convert_to_json(json_str)
114
+ if isinstance(json_object,dict):
115
+ return cls(**json_object)
116
+ elif isinstance(json_object,str):
117
+ return json_object
118
+ except (ValueError, ValidationError) as e:
119
+ # Handle the error, e.g., log it, raise a custom exception, or return a default value
120
+ error = f"Error creating Instruction_Tuned_ instance: {e}"
121
+ logger.error(error)
122
+ raise
123
+
124
+
125
+ class React_(BaseModel):
126
+ """
127
+ A Pydantic model representing the ReAct prompt template.
128
+
129
+ Attributes:
130
+ - Thought: str, the agent's thoughts.
131
+ - action: str, the action to take or final answer.
132
+ - action_input: str or Dict, the input to the action.
133
+
134
+ Methods:
135
+ - from_json: Creates an instance from a JSON string.
136
+ """
137
+ Thought: str = Field('The Agent Thoughts', alias='Thought')
138
+ action: str = Field("The action to take OR Final Answer", alias="action")
139
+ action_input: str | Dict = Field("The input to the action OR You should put what you want to return to use here and return to user immediately", alias="action_input")
140
+
141
+ @classmethod
142
+ def from_json(cls, json_str: str):
143
+ try:
144
+ json_object = convert_to_json(json_str)
145
+ if isinstance(json_object,dict):
146
+ console.print("[bold cyan]Thinking...[/bold cyan]")
147
+ print(f"\n{json_object['Thought']}")
148
+ return cls(**json_object)
149
+ elif isinstance(json_object,str):
150
+ return json_object
151
+ except (ValueError, ValidationError) as e:
152
+ # Handle the error, e.g., log it, raise a custom exception, or return a default value
153
+ error = f"Error creating React_ instance: {e}"
154
+ logger.error(error)
155
+ raise
156
+
157
+ class ChainOfThought(BaseModel):
158
+ """
159
+ A Pydantic model representing the Chain-of-Thought prompt template.
160
+
161
+ Attributes:
162
+ - Thought: str, the step-by-step reasoning.
163
+ - Action: str, the action to take or final answer.
164
+ - Action_Input: str or Dict, the input to the action.
165
+
166
+ Methods:
167
+ - from_json: Creates an instance from a JSON string.
168
+ """
169
+ Thought: str = Field('The step-by-step reasoning', alias='Thought')
170
+ Action: str = Field("The action to take or Final Answer", alias='Action')
171
+ Action_Input: str | Dict = Field("The input to the action", alias='Action Input')
172
+
173
+ @classmethod
174
+ def from_json(cls, json_str: str):
175
+ try:
176
+ json_object = convert_to_json(json_str)
177
+ if isinstance(json_object,dict):
178
+ console.print("[bold cyan]Thinking...[/bold cyan]")
179
+ print(f"\n{json_object['Thought']}")
180
+ return cls(**json_object)
181
+ elif isinstance(json_object,str):
182
+ return json_object
183
+ except (ValueError, ValidationError) as e:
184
+ logger.error(f"Error creating ChainOfThought instance: {e}")
185
+ raise
186
+
187
+ class ZeroShot(BaseModel):
188
+ """
189
+ A Pydantic model representing the Zero-Shot prompt template.
190
+
191
+ Attributes:
192
+ - action: str, the action to take.
193
+ - action_input: str or Dict, the input to the action.
194
+
195
+ Methods:
196
+ - from_json: Creates an instance from a JSON string.
197
+ """
198
+ action: str = Field("The action to take", alias='action')
199
+ action_input: str | Dict = Field("The input to the action", alias='action_input')
200
+
201
+ @classmethod
202
+ def from_json(cls, json_str: str):
203
+ try:
204
+ json_object = convert_to_json(json_str)
205
+ if isinstance(json_object,dict):
206
+ return cls(**json_object)
207
+ elif isinstance(json_object,str):
208
+ return json_object
209
+ except (ValueError, ValidationError) as e:
210
+ logger.error(f"Error creating ZeroShot instance: {e}")
211
+ raise
212
+
213
+ class FewShot(BaseModel):
214
+ """
215
+ A Pydantic model representing the Few-Shot prompt template.
216
+
217
+ Attributes:
218
+ - action: str, the action to take.
219
+ - action_input: str or Dict, the input to the action.
220
+
221
+ Methods:
222
+ - from_json: Creates an instance from a JSON string.
223
+ """
224
+ action: str = Field("The action to take", alias='action')
225
+ action_input: str | Dict = Field("The input to the action", alias='action_input')
226
+
227
+ @classmethod
228
+ def from_json(cls, json_str: str):
229
+ try:
230
+ json_object = convert_to_json(json_str)
231
+ if isinstance(json_object,dict):
232
+ return cls(**json_object)
233
+ elif isinstance(json_object,str):
234
+ return json_object
235
+ except (ValueError, ValidationError) as e:
236
+ logger.error(f"Error creating FewShot instance: {e}")
237
+ raise
238
+
239
+
240
+ class AgentFormattor(BaseModel):
241
+ prompt: str
242
+ Agent: Type[BaseModel]=Field(description="The agent that will under the prompt and extract what's needed")
243
+
244
+ @classmethod
245
+ def Formattor(cls,prompt:str,Agent:Type[BaseModel]):
246
+ return cls(prompt=prompt,Agent=Agent)
247
+
248
+
249
+ class AgentPrompt:
250
+ """
251
+ Manages and formats the prompt template for the agent, allowing for
252
+ flexible placeholder values.
253
+ """
254
+ def __init__(self, prompt: str):
255
+ """
256
+ Initializes the prompt with a template string.
257
+ """
258
+ self.prompt = prompt
259
+
260
+ def format(self, tools: List,user_hold, **kwargs: Any) -> str:
261
+ """
262
+ Formats the prompt template with dynamic values.
263
+
264
+ Args:
265
+ tools (List): A list of tool objects to populate {tools} and {tool_names}.
266
+ **kwargs (Any): Optional. Any other key-value pairs corresponding to
267
+ placeholders in the template (e.g., user_input="...").
268
+ Returns:
269
+ str: The fully formatted prompt.
270
+ """
271
+ # Build the dictionary of values that are always available.
272
+ format_values = {
273
+ 'tools': "\n".join([f"- {t.name}: {t.description}" for t in tools]),
274
+ 'tool_names': ", ".join([t.name for t in tools]),
275
+ 'user_input' : user_hold
276
+
277
+ }
278
+
279
+ # The update() method merges the optional kwargs.
280
+ # If kwargs is empty, this does nothing.
281
+ format_values.update(kwargs)
282
+
283
+ # format_map uses the combined dictionary to fill in the template.
284
+ return self.prompt.format_map(format_values)
285
+
286
+
287
+
288
+
289
+ class AgentType:
290
+ """
291
+ A container for standard, pre-defined agent prompt templates.
292
+
293
+ This class holds various prompt styles as class attributes, making them
294
+ easy to access and use to initialize an AgentPrompt.
295
+
296
+ Example:
297
+ react_prompt_template = AgentType.ReAct
298
+ agent_prompt = AgentPrompt(template=react_prompt_template)
299
+ """
300
+
301
+ ReAct = AgentFormattor.Formattor(prompt=system['ReAct'],Agent=React_)
302
+ Instruction_Tuned = AgentFormattor.Formattor(prompt=system['Instruction-Tuned'],Agent=Instruction_Tuned_)
303
+ Chain_of_Thought = AgentFormattor.Formattor(prompt=system['Chain-of-Thought'],Agent=ChainOfThought)
304
+ Zero_Shot = AgentFormattor.Formattor(prompt=system['Zero-Shot'],Agent=ZeroShot)
305
+ Few_Shot = AgentFormattor.Formattor(prompt=system['Few-Shot'],Agent=FewShot)
306
+
307
+
308
+
309
+
310
+ class ToolCall(BaseModel):
311
+ name: str
312
+ args: Dict[str, Any]
313
+ result: str
314
+
315
+
316
+ class ToolCall(BaseModel):
317
+ name: str
318
+ args: Dict[str, Any]
319
+ result: str
320
+
321
+ class AgentCompletion(BaseModel):
322
+ id: str
323
+ object: str = "agent.completion"
324
+ created: int
325
+ model: str
326
+ query: str
327
+ content: str
328
+ tool_calls: List[ToolCall] = Field(default_factory=list)
329
+ steps: List[str] = Field(default_factory=list)
330
+ history: Optional[List[Dict[str, str]]] = None
331
+
332
+
333
+ @classmethod
334
+ def from_agent(cls, *, model_name: str, query: str, content: Union[str, Dict[str, Any], List[Dict[str, Any]]], tool_calls: Optional[List[ToolCall]] = None, steps: Optional[List[str]] = None, history: List[Dict[str, str]]):
335
+ if isinstance(content, (dict, list)):
336
+ content_str = json.dumps(content, ensure_ascii=False)
337
+ else:
338
+ content_str = content
339
+ return cls(
340
+ id=str(uuid.uuid4()),
341
+ created=int(time.time()),
342
+ model=model_name,
343
+ query=query,
344
+ content=content_str,
345
+ tool_calls=tool_calls,
346
+ steps=steps,
347
+ history=history
348
+ )
349
+
@@ -0,0 +1,11 @@
1
+ from .Agent import AgentFormattor,AgentPrompt,AgentType,AgentCompletion,StandardParser,ToolCall
2
+
3
+
4
+ __all__ =[
5
+ 'AgentFormattor',
6
+ 'AgentCompletion',
7
+ 'AgentPrompt',
8
+ 'AgentType',
9
+ 'StandardParser',
10
+ 'ToolCall'
11
+ ]