astonish 0.1__py3-none-any.whl
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.
Potentially problematic release.
This version of astonish might be problematic. Click here for more details.
- astonish/__init__.py +0 -0
- astonish/agents/agents_creator.yaml +406 -0
- astonish/factory/__init__.py +0 -0
- astonish/factory/ai_provider_factory.py +27 -0
- astonish/globals.py +102 -0
- astonish/main.py +176 -0
- astonish/providers/__init__.py +0 -0
- astonish/providers/ai_provider_interface.py +18 -0
- astonish/providers/ollama_provider.py +107 -0
- astonish/providers/sap_ai_core_provider.py +114 -0
- astonish/tools/__init__.py +0 -0
- astonish/tools/internal_tools.py +45 -0
- astonish/tools/mcp_config_editor.py +60 -0
- astonish/tools/tavily_search.py +72 -0
- astonish/tools/tool_base.py +6 -0
- astonish-0.1.dist-info/METADATA +251 -0
- astonish-0.1.dist-info/RECORD +21 -0
- astonish-0.1.dist-info/WHEEL +5 -0
- astonish-0.1.dist-info/entry_points.txt +2 -0
- astonish-0.1.dist-info/licenses/LICENSE +21 -0
- astonish-0.1.dist-info/top_level.txt +1 -0
astonish/__init__.py
ADDED
|
File without changes
|
|
@@ -0,0 +1,406 @@
|
|
|
1
|
+
description: An agentic flow designed to assist users in creating a new agentic flows.
|
|
2
|
+
nodes:
|
|
3
|
+
- name: get_overall_idea
|
|
4
|
+
type: input
|
|
5
|
+
prompt: |
|
|
6
|
+
Welcome to the Agentic Flow Creator! I'm here to help you design a new agentic flow.
|
|
7
|
+
We are going to create the initial flow for your agentic flow, which you customize later.
|
|
8
|
+
Please provide an overall description of the flow you want to create. What's the main goal and what should it do?
|
|
9
|
+
|
|
10
|
+
output_model:
|
|
11
|
+
overall_idea: str
|
|
12
|
+
user_message:
|
|
13
|
+
- "Thank you for sharing your idea! Let's now check which tools you have currently available."
|
|
14
|
+
|
|
15
|
+
- name: fetch_available_tools
|
|
16
|
+
type: llm
|
|
17
|
+
tools: True
|
|
18
|
+
tools_selection:
|
|
19
|
+
- shell_command
|
|
20
|
+
system: |
|
|
21
|
+
You are a system assistant tasked with fetching the list of available tools.
|
|
22
|
+
prompt: |
|
|
23
|
+
Use the shell_command tool to run the following command:
|
|
24
|
+
astonish tools list
|
|
25
|
+
|
|
26
|
+
Parse the output and create a structured list of available tools with their descriptions.
|
|
27
|
+
output_model:
|
|
28
|
+
available_tools: list
|
|
29
|
+
user_message:
|
|
30
|
+
- "Available tools fetched successfully."
|
|
31
|
+
|
|
32
|
+
- name: process_idea
|
|
33
|
+
type: llm
|
|
34
|
+
system: |
|
|
35
|
+
You are an expert in designing agentic flows. Analyze the user's overall idea and create a base flow structure.
|
|
36
|
+
prompt: |
|
|
37
|
+
User's overall idea:
|
|
38
|
+
{overall_idea}
|
|
39
|
+
|
|
40
|
+
Available tools:
|
|
41
|
+
{available_tools}
|
|
42
|
+
|
|
43
|
+
Based on this idea and the available tools, please:
|
|
44
|
+
1. Create a base flow structure with necessary nodes and their purposes.
|
|
45
|
+
2. Identify which of the available tools might be required for this flow.
|
|
46
|
+
3. Highlight any potential challenges or areas that need further clarification.
|
|
47
|
+
4. If any required functionality is not available in the current tools, note it as a potential limitation.
|
|
48
|
+
5. Remember that input from the user can be collected directly from the application, so you don't need to require a tool for that.
|
|
49
|
+
|
|
50
|
+
Present this information in a clear, structured format.
|
|
51
|
+
Export the base_flow if line breaks between the items using \n
|
|
52
|
+
|
|
53
|
+
If the tools are not sufficient to implement the flow, please indicate that the user should provide the specific tools throug MCP servers to be able to create the agents.
|
|
54
|
+
|
|
55
|
+
add the the message for the user, detailing the base flow, required tools, challenges, and limitations, in the response message
|
|
56
|
+
Structure the message to the user as follows:
|
|
57
|
+
|
|
58
|
+
I've created a base flow structure based on your idea. Here it is, along with required tools, potential challenges, and limitations:
|
|
59
|
+
|
|
60
|
+
Base Flow:
|
|
61
|
+
{base_flow}
|
|
62
|
+
|
|
63
|
+
Required Tools:
|
|
64
|
+
{required_tools}
|
|
65
|
+
|
|
66
|
+
Potential Challenges:
|
|
67
|
+
{challenges}
|
|
68
|
+
|
|
69
|
+
Limitations:
|
|
70
|
+
{limitations}
|
|
71
|
+
|
|
72
|
+
For any item that has a list (eg.: ['item1','item2']), please break in multiple lines and put * before each item.
|
|
73
|
+
Do not use tools for analysis, format, or any other tasks that can be done by the LLM itself.
|
|
74
|
+
output_model:
|
|
75
|
+
base_flow: list
|
|
76
|
+
required_tools: list
|
|
77
|
+
challenges: str
|
|
78
|
+
limitations: str
|
|
79
|
+
have_tools: bool
|
|
80
|
+
response: str
|
|
81
|
+
user_message:
|
|
82
|
+
- response
|
|
83
|
+
print_state: False
|
|
84
|
+
|
|
85
|
+
- name: get_user_feedback
|
|
86
|
+
type: input
|
|
87
|
+
prompt: |
|
|
88
|
+
Do you have any feedback or changes you'd like to make? If you're satisfied, type 'CONTINUE'. Otherwise, provide your feedback:
|
|
89
|
+
output_model:
|
|
90
|
+
user_feedback: str
|
|
91
|
+
|
|
92
|
+
- name: refine_flow
|
|
93
|
+
type: llm
|
|
94
|
+
system: |
|
|
95
|
+
You are an agentic flow architect. Refine the flow based on user feedback.
|
|
96
|
+
prompt: |
|
|
97
|
+
Current base flow:
|
|
98
|
+
{base_flow}
|
|
99
|
+
|
|
100
|
+
User feedback:
|
|
101
|
+
{user_feedback}
|
|
102
|
+
|
|
103
|
+
Available tools:
|
|
104
|
+
{available_tools}
|
|
105
|
+
|
|
106
|
+
Please refine the flow, addressing the user's feedback. If the user typed asked to continue, keep the current flow as is.
|
|
107
|
+
Ensure that any changes still work within the constraints of the available tools.
|
|
108
|
+
output_model:
|
|
109
|
+
refined_flow: str
|
|
110
|
+
continue_flag: bool
|
|
111
|
+
|
|
112
|
+
- name: generate_yaml
|
|
113
|
+
type: llm
|
|
114
|
+
system: |
|
|
115
|
+
You are an expert in creating agentic flow YAML files. Follow the provided example and rules strictly.
|
|
116
|
+
prompt: |
|
|
117
|
+
Refined flow:
|
|
118
|
+
{refined_flow}
|
|
119
|
+
|
|
120
|
+
Available tools:
|
|
121
|
+
{available_tools}
|
|
122
|
+
|
|
123
|
+
Generate a complete YAML file for this agentic flow, following this specific format and rules:
|
|
124
|
+
|
|
125
|
+
Rules:
|
|
126
|
+
1. Node types can only be 'input' or 'llm'.
|
|
127
|
+
2. 'input' nodes have limited fields: name, type, prompt, and output_model.
|
|
128
|
+
3. 'llm' nodes can have all fields: name, type, system, prompt, output_model, user_message, tools, and tools_selection.
|
|
129
|
+
4. 'tools' field should be a boolean (True/False).
|
|
130
|
+
5. 'tools_selection' should only be included if 'tools' is True.
|
|
131
|
+
6. 'tools_selection' should only contain tools from the available_tools list and should only contain the tool name, not the description.
|
|
132
|
+
7. 'user_message' should only be included if we need to display something to the user, and should only contain fields defined in the output_model.
|
|
133
|
+
8. Ensure all node names are unique and descriptive.
|
|
134
|
+
9. The flow must cover all possible paths through the nodes, including conditional branches.
|
|
135
|
+
10. Conditions must be properly formatted as lambda functions.
|
|
136
|
+
11. Only use tools that are available in the {available_tools} list.
|
|
137
|
+
12. Ensure all variables used in prompts are defined in the output_model of a previous node.
|
|
138
|
+
13. Be careful with the content of the user_message, as it should only contain the fields defined in the output_model of the node.
|
|
139
|
+
14. When adding a variable to the user_message, we should ensure that we request in the prompt for the content to be displayed to be well-formatted.
|
|
140
|
+
15. Pay attention to not provided duplicate content to the user, as it can cause confusion.
|
|
141
|
+
16. Make sure all variables used in prompts are properly defined in the output_model of previous nodes.
|
|
142
|
+
17. Make sure variables in a node prompot are defined in the output_model of previous nodes.
|
|
143
|
+
18. Make sure the node use the required variables in the prompt
|
|
144
|
+
|
|
145
|
+
Example YAML structure (note: variables in this example are prefixed with 'example_' to distinguish them from actual state variables):
|
|
146
|
+
|
|
147
|
+
```yaml
|
|
148
|
+
nodes:
|
|
149
|
+
- name: get_user_input
|
|
150
|
+
type: input
|
|
151
|
+
prompt: |
|
|
152
|
+
Please enter your question or type 'exit' to quit:
|
|
153
|
+
output_model:
|
|
154
|
+
example_user_input: str
|
|
155
|
+
|
|
156
|
+
- name: analyze_input
|
|
157
|
+
type: llm
|
|
158
|
+
system: |
|
|
159
|
+
You are an AI assistant analyzing user input.
|
|
160
|
+
prompt: |
|
|
161
|
+
Analyze the following user input: {{example_user_input}}
|
|
162
|
+
Determine if it's a question or an exit command.
|
|
163
|
+
output_model:
|
|
164
|
+
example_is_question: bool
|
|
165
|
+
example_input_type: str
|
|
166
|
+
|
|
167
|
+
- name: process_question
|
|
168
|
+
type: llm
|
|
169
|
+
system: |
|
|
170
|
+
You are an AI assistant answering user questions.
|
|
171
|
+
prompt: |
|
|
172
|
+
User question: {{example_user_input}}
|
|
173
|
+
Please provide a detailed answer to the user's question.
|
|
174
|
+
output_model:
|
|
175
|
+
example_answer: str
|
|
176
|
+
user_message:
|
|
177
|
+
- example_answer
|
|
178
|
+
tools: True
|
|
179
|
+
tools_selection:
|
|
180
|
+
- web_search
|
|
181
|
+
- knowledge_base
|
|
182
|
+
|
|
183
|
+
- name: farewell
|
|
184
|
+
type: llm
|
|
185
|
+
system: |
|
|
186
|
+
You are a polite AI assistant saying goodbye.
|
|
187
|
+
prompt: |
|
|
188
|
+
Generate a polite farewell message for the user.
|
|
189
|
+
output_model:
|
|
190
|
+
example_farewell_message: str
|
|
191
|
+
user_message:
|
|
192
|
+
- example_farewell_message
|
|
193
|
+
|
|
194
|
+
flow:
|
|
195
|
+
- from: START
|
|
196
|
+
to: get_user_input
|
|
197
|
+
- from: get_user_input
|
|
198
|
+
to: analyze_input
|
|
199
|
+
- from: analyze_input
|
|
200
|
+
edges:
|
|
201
|
+
- to: process_question
|
|
202
|
+
condition: "lambda x: x['example_is_question']"
|
|
203
|
+
- to: farewell
|
|
204
|
+
condition: "lambda x: not x['example_is_question']"
|
|
205
|
+
- from: process_question
|
|
206
|
+
to: get_user_input
|
|
207
|
+
- from: farewell
|
|
208
|
+
to: END
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
Now, generate the complete YAML for the agentic flow based on the refined flow structure we've discussed, following the example and rules provided. Make sure to include appropriate conditional flows, only use user_message when necessary, and ensure all variables used in prompts are properly defined in previous nodes' output_models.
|
|
212
|
+
|
|
213
|
+
After generating the YAML, show the content to the user.
|
|
214
|
+
|
|
215
|
+
output_model:
|
|
216
|
+
flow_yaml: str
|
|
217
|
+
save_confirmation: str
|
|
218
|
+
user_message:
|
|
219
|
+
- flow_yaml
|
|
220
|
+
print_state: False
|
|
221
|
+
|
|
222
|
+
- name: get_user_feedback_yaml
|
|
223
|
+
type: input
|
|
224
|
+
prompt: |
|
|
225
|
+
Do you have any feedback or changes you'd like to make? If you're satisfied, type 'CONTINUE'. Otherwise, provide your feedback:
|
|
226
|
+
output_model:
|
|
227
|
+
user_feedback_yaml: str
|
|
228
|
+
|
|
229
|
+
- name: refine_yaml
|
|
230
|
+
type: llm
|
|
231
|
+
system: |
|
|
232
|
+
You are an agentic flow architect. Refine the yaml flow based on user feedback.
|
|
233
|
+
prompt: |
|
|
234
|
+
Current yaml flow:
|
|
235
|
+
{refined_flow}
|
|
236
|
+
|
|
237
|
+
User feedback:
|
|
238
|
+
{user_feedback_yaml}
|
|
239
|
+
|
|
240
|
+
Available tools:
|
|
241
|
+
{available_tools}
|
|
242
|
+
|
|
243
|
+
Please refine the flow, addressing the user's feedback. If the user asked to continue, keep the current yaml flow as is.
|
|
244
|
+
Ensure that any changes still work within the constraints of the available tools.
|
|
245
|
+
Only change what is necessary to address the user's feedback, nothing else
|
|
246
|
+
output_model:
|
|
247
|
+
refined_flow: str
|
|
248
|
+
continue_yaml_flag: bool
|
|
249
|
+
|
|
250
|
+
- name: save_yaml
|
|
251
|
+
type: llm
|
|
252
|
+
tools: True
|
|
253
|
+
tools_selection:
|
|
254
|
+
- write_file
|
|
255
|
+
- shell_command
|
|
256
|
+
system: |
|
|
257
|
+
You are an expert in creating and saving files to disk. Follow the provided example and rules strictly.
|
|
258
|
+
prompt: |
|
|
259
|
+
Run following command with the shell_command tool to get the path to the user config directory:
|
|
260
|
+
python -c "import appdirs; print(appdirs.user_config_dir('astonish'))"
|
|
261
|
+
|
|
262
|
+
flow_yaml:
|
|
263
|
+
{flow_yaml}
|
|
264
|
+
|
|
265
|
+
Save the content of the flow_yaml to disk using write_file tool in the config directory.
|
|
266
|
+
The file name should be at 'agents/new_flow.yaml' inside the config_dir.
|
|
267
|
+
|
|
268
|
+
Confirm once the file has been saved.
|
|
269
|
+
output_model:
|
|
270
|
+
config_dir: str
|
|
271
|
+
flow_yaml: str
|
|
272
|
+
save_confirmation: str
|
|
273
|
+
user_message:
|
|
274
|
+
- save_confirmation
|
|
275
|
+
print_state: False
|
|
276
|
+
|
|
277
|
+
- name: validate_flow
|
|
278
|
+
type: llm
|
|
279
|
+
tools: True
|
|
280
|
+
tools_selection:
|
|
281
|
+
- shell_command
|
|
282
|
+
system: |
|
|
283
|
+
You are a system tester for agentic flows. Run the validation command and interpret the results.
|
|
284
|
+
prompt: |
|
|
285
|
+
Refined flow:
|
|
286
|
+
{refined_flow}
|
|
287
|
+
|
|
288
|
+
The flow YAML has been saved to:
|
|
289
|
+
/home/schardosin/projects/astonish/astonish/agents/new_flow.yaml
|
|
290
|
+
|
|
291
|
+
Use the shell_command tool to run the following command:
|
|
292
|
+
astonish flow new_flow
|
|
293
|
+
|
|
294
|
+
Analyze the output and determine if there are any errors or warnings. If there are issues, summarize them clearly.
|
|
295
|
+
Format the content before displaying it to the user.
|
|
296
|
+
|
|
297
|
+
Verify that all the requirements in the Refined flow were met and that the flow is valid.
|
|
298
|
+
Store the shell command output in the shell_result variable.
|
|
299
|
+
output_model:
|
|
300
|
+
validation_result: str
|
|
301
|
+
has_errors: bool
|
|
302
|
+
shell_result: str
|
|
303
|
+
user_message:
|
|
304
|
+
- shell_result
|
|
305
|
+
- validation_result
|
|
306
|
+
|
|
307
|
+
- name: fix_errors
|
|
308
|
+
type: llm
|
|
309
|
+
tools: True
|
|
310
|
+
tools_selection:
|
|
311
|
+
- read_file
|
|
312
|
+
- write_file
|
|
313
|
+
system: |
|
|
314
|
+
You are an agentic flow debugger. Fix any errors found during validation.
|
|
315
|
+
prompt: |
|
|
316
|
+
Validation results:
|
|
317
|
+
{validation_result}
|
|
318
|
+
|
|
319
|
+
Available tools:
|
|
320
|
+
{available_tools}
|
|
321
|
+
|
|
322
|
+
Use the FileReadOrEdit tool to read the current flow YAML from:
|
|
323
|
+
/home/schardosin/projects/astonish/astonish/agents/new_flow.yaml
|
|
324
|
+
|
|
325
|
+
Please fix any errors found during validation. If no errors were found, return the current YAML unchanged.
|
|
326
|
+
Ensure that any fixes still use only the available tools.
|
|
327
|
+
|
|
328
|
+
After making any necessary changes, use the FileWriteOrEdit tool to save the updated YAML back to the same file.
|
|
329
|
+
output_model:
|
|
330
|
+
fixed_yaml: str
|
|
331
|
+
save_confirmation: str
|
|
332
|
+
user_message:
|
|
333
|
+
- save_confirmation
|
|
334
|
+
|
|
335
|
+
- name: show_final_flow
|
|
336
|
+
type: llm
|
|
337
|
+
system: |
|
|
338
|
+
You are a helpful assistant presenting the final agentic flow to the user.
|
|
339
|
+
prompt: |
|
|
340
|
+
Use the FileReadOrEdit tool to read the final flow YAML from:
|
|
341
|
+
/home/schardosin/projects/astonish/astonish/agents/new_flow.yaml
|
|
342
|
+
|
|
343
|
+
Please present a summary of the final flow to the user, highlighting its key components and functionality.
|
|
344
|
+
Also mention which of the available tools are used in this flow.
|
|
345
|
+
output_model:
|
|
346
|
+
flow_summary: str
|
|
347
|
+
user_message:
|
|
348
|
+
- flow_summary
|
|
349
|
+
|
|
350
|
+
- name: get_final_approval
|
|
351
|
+
type: input
|
|
352
|
+
prompt: |
|
|
353
|
+
This is the final version of your agentic flow. Do you approve saving this flow? (yes/no)
|
|
354
|
+
output_model:
|
|
355
|
+
final_approval: bool
|
|
356
|
+
|
|
357
|
+
flow:
|
|
358
|
+
- from: START
|
|
359
|
+
to: get_overall_idea
|
|
360
|
+
- from: get_overall_idea
|
|
361
|
+
to: fetch_available_tools
|
|
362
|
+
- from: fetch_available_tools
|
|
363
|
+
to: process_idea
|
|
364
|
+
- from: process_idea
|
|
365
|
+
edges:
|
|
366
|
+
- to: get_user_feedback
|
|
367
|
+
condition: "lambda x: x['have_tools']"
|
|
368
|
+
- to: END
|
|
369
|
+
condition: "lambda x: not x['have_tools']"
|
|
370
|
+
- from: get_user_feedback
|
|
371
|
+
to: refine_flow
|
|
372
|
+
- from: refine_flow
|
|
373
|
+
edges:
|
|
374
|
+
- to: get_user_feedback_yaml
|
|
375
|
+
condition: "lambda x: not x['continue_flag']"
|
|
376
|
+
- to: generate_yaml
|
|
377
|
+
condition: "lambda x: x['continue_flag']"
|
|
378
|
+
- from: generate_yaml
|
|
379
|
+
to: get_user_feedback_yaml
|
|
380
|
+
- from: get_user_feedback_yaml
|
|
381
|
+
to: refine_yaml
|
|
382
|
+
- from: refine_yaml
|
|
383
|
+
edges:
|
|
384
|
+
- to: generate_yaml
|
|
385
|
+
condition: "lambda x: not x['continue_yaml_flag']"
|
|
386
|
+
- to: save_yaml
|
|
387
|
+
condition: "lambda x: x['continue_yaml_flag']"
|
|
388
|
+
- from: validate_flow
|
|
389
|
+
edges:
|
|
390
|
+
- to: fix_errors
|
|
391
|
+
condition: "lambda x: x['has_errors']"
|
|
392
|
+
- to: show_final_flow
|
|
393
|
+
condition: "lambda x: not x['has_errors']"
|
|
394
|
+
|
|
395
|
+
- from: fix_errors
|
|
396
|
+
to: validate_flow
|
|
397
|
+
- from: show_final_flow
|
|
398
|
+
to: get_final_approval
|
|
399
|
+
- from: get_final_approval
|
|
400
|
+
edges:
|
|
401
|
+
- to: save_yaml
|
|
402
|
+
condition: "lambda x: x['final_approval']"
|
|
403
|
+
- to: get_user_feedback_yaml
|
|
404
|
+
condition: "lambda x: not x['final_approval']"
|
|
405
|
+
- from: save_yaml
|
|
406
|
+
to: END
|
|
File without changes
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
from astonish.providers.ai_provider_interface import AIProvider
|
|
2
|
+
from astonish.providers.sap_ai_core_provider import SAPAICoreProvider
|
|
3
|
+
from astonish.providers.ollama_provider import OllamaProvider
|
|
4
|
+
from typing import List, Tuple
|
|
5
|
+
|
|
6
|
+
class AIProviderFactory:
|
|
7
|
+
_providers = {}
|
|
8
|
+
|
|
9
|
+
@classmethod
|
|
10
|
+
def register_provider(cls, name: str, display_name: str, provider_class: type):
|
|
11
|
+
if not issubclass(provider_class, AIProvider):
|
|
12
|
+
raise TypeError("Provider must implement AIProvider interface")
|
|
13
|
+
cls._providers[name] = (display_name, provider_class)
|
|
14
|
+
|
|
15
|
+
@classmethod
|
|
16
|
+
def get_provider(cls, name: str) -> AIProvider:
|
|
17
|
+
provider_info = cls._providers.get(name)
|
|
18
|
+
if not provider_info:
|
|
19
|
+
raise ValueError(f"No provider registered with name: {name}")
|
|
20
|
+
return provider_info[1]()
|
|
21
|
+
|
|
22
|
+
@classmethod
|
|
23
|
+
def get_registered_providers(cls) -> List[Tuple[str, str]]:
|
|
24
|
+
return [(name, info[0]) for name, info in cls._providers.items()]
|
|
25
|
+
|
|
26
|
+
AIProviderFactory.register_provider("sap_ai_core", "SAP AI Core", SAPAICoreProvider)
|
|
27
|
+
AIProviderFactory.register_provider("ollama", "Ollama", OllamaProvider)
|
astonish/globals.py
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import configparser, os, appdirs
|
|
2
|
+
import logging
|
|
3
|
+
from logging.handlers import RotatingFileHandler
|
|
4
|
+
|
|
5
|
+
CONFIG_FILE = "config.ini"
|
|
6
|
+
LOG_FILE = "astonish.log"
|
|
7
|
+
MCP_CONFIG_FILE = "mcp_config.json"
|
|
8
|
+
|
|
9
|
+
config = configparser.ConfigParser()
|
|
10
|
+
config_dir = appdirs.user_config_dir("astonish")
|
|
11
|
+
os.makedirs(config_dir, exist_ok=True)
|
|
12
|
+
config_path = os.path.join(config_dir, CONFIG_FILE)
|
|
13
|
+
logger_path = os.path.join(config_dir, LOG_FILE)
|
|
14
|
+
mcp_config_path = os.path.join(config_dir, MCP_CONFIG_FILE)
|
|
15
|
+
mcp_config = None
|
|
16
|
+
|
|
17
|
+
# Configure the logger
|
|
18
|
+
logging.basicConfig(
|
|
19
|
+
level=logging.INFO, # Default log level
|
|
20
|
+
format="%(asctime)s - %(levelname)s - %(message)s",
|
|
21
|
+
handlers=[
|
|
22
|
+
RotatingFileHandler(logger_path, maxBytes=5 * 1024 * 1024, backupCount=3), # 5 MB files
|
|
23
|
+
],
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
logger = logging.getLogger("astonish")
|
|
27
|
+
|
|
28
|
+
def setup_logger(verbose=False):
|
|
29
|
+
logger.setLevel(logging.DEBUG if verbose else logging.INFO)
|
|
30
|
+
|
|
31
|
+
# File handler
|
|
32
|
+
file_handler = RotatingFileHandler(logger_path, maxBytes=5 * 1024 * 1024, backupCount=3)
|
|
33
|
+
file_handler.setFormatter(logging.Formatter("%(asctime)s - %(levelname)s - %(message)s"))
|
|
34
|
+
logger.addHandler(file_handler)
|
|
35
|
+
|
|
36
|
+
# Optional terminal handler for verbose mode
|
|
37
|
+
if verbose:
|
|
38
|
+
console_handler = logging.StreamHandler()
|
|
39
|
+
console_handler.setFormatter(logging.Formatter("%(levelname)s: %(message)s"))
|
|
40
|
+
logger.addHandler(console_handler)
|
|
41
|
+
|
|
42
|
+
return logger
|
|
43
|
+
|
|
44
|
+
def load_config():
|
|
45
|
+
# Load existing configuration if it exists
|
|
46
|
+
if os.path.exists(config_path):
|
|
47
|
+
config.read(config_path)
|
|
48
|
+
|
|
49
|
+
def load_mcp_config():
|
|
50
|
+
import json
|
|
51
|
+
|
|
52
|
+
global mcp_config
|
|
53
|
+
default_config = {
|
|
54
|
+
"mcpServers": {}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
# Load existing MCP configuration if it exists
|
|
58
|
+
if os.path.exists(mcp_config_path):
|
|
59
|
+
try:
|
|
60
|
+
with open(mcp_config_path, 'r') as mcp_config_file:
|
|
61
|
+
loaded_config = json.load(mcp_config_file)
|
|
62
|
+
|
|
63
|
+
# Check if 'mcpServers' key exists in the loaded config
|
|
64
|
+
if "mcpServers" not in loaded_config:
|
|
65
|
+
logger.warning(f"'mcpServers' key not found in {mcp_config_path}. Using default configuration.")
|
|
66
|
+
mcp_config = default_config
|
|
67
|
+
else:
|
|
68
|
+
mcp_config = loaded_config
|
|
69
|
+
except json.JSONDecodeError:
|
|
70
|
+
logger.warning(f"Error decoding JSON from {mcp_config_path}. Using default configuration.")
|
|
71
|
+
mcp_config = default_config
|
|
72
|
+
except Exception as e:
|
|
73
|
+
logger.warning(f"Error reading {mcp_config_path}: {str(e)}. Using default configuration.")
|
|
74
|
+
mcp_config = default_config
|
|
75
|
+
else:
|
|
76
|
+
logger.warning(f"MCP config file not found at {mcp_config_path}. Using default configuration.")
|
|
77
|
+
mcp_config = default_config
|
|
78
|
+
|
|
79
|
+
return mcp_config
|
|
80
|
+
|
|
81
|
+
async def initialize_mcp_tools():
|
|
82
|
+
from langchain_mcp_adapters.client import MultiServerMCPClient
|
|
83
|
+
|
|
84
|
+
global mcp_config
|
|
85
|
+
if mcp_config is None:
|
|
86
|
+
logger.error("MCP config is not loaded. Cannot initialize MCP tools.")
|
|
87
|
+
return None
|
|
88
|
+
|
|
89
|
+
logger.info("Initializing MCP client...")
|
|
90
|
+
mcp_client = MultiServerMCPClient(mcp_config['mcpServers'])
|
|
91
|
+
|
|
92
|
+
logger.info("Connecting to MCP servers...")
|
|
93
|
+
for server_name, server_config in mcp_config['mcpServers'].items():
|
|
94
|
+
try:
|
|
95
|
+
logger.info(f"Connecting to server: {server_name}")
|
|
96
|
+
await mcp_client.connect_to_server(server_name, server_config)
|
|
97
|
+
logger.info(f"Successfully connected to server: {server_name}")
|
|
98
|
+
except Exception as e:
|
|
99
|
+
logger.error(f"Failed to connect to server {server_name}: {str(e)}")
|
|
100
|
+
|
|
101
|
+
logger.info("MCP client initialization complete")
|
|
102
|
+
return mcp_client
|