solace-agent-mesh 0.1.3__py3-none-any.whl → 0.2.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 solace-agent-mesh might be problematic. Click here for more details.
- solace_agent_mesh/agents/global/actions/plantuml_diagram.py +9 -2
- solace_agent_mesh/agents/global/actions/plotly_graph.py +70 -46
- solace_agent_mesh/agents/web_request/actions/do_web_request.py +34 -33
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add/copy_from_plugin.py +8 -6
- solace_agent_mesh/cli/commands/add/gateway.py +162 -9
- solace_agent_mesh/cli/commands/build.py +15 -1
- solace_agent_mesh/cli/commands/init/ai_provider_step.py +45 -28
- solace_agent_mesh/cli/commands/init/broker_step.py +1 -4
- solace_agent_mesh/cli/commands/init/create_config_file_step.py +8 -0
- solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +52 -1
- solace_agent_mesh/cli/commands/init/init.py +50 -37
- solace_agent_mesh/cli/commands/plugin/build.py +60 -9
- solace_agent_mesh/cli/commands/run.py +2 -2
- solace_agent_mesh/cli/config.py +4 -0
- solace_agent_mesh/cli/main.py +14 -8
- solace_agent_mesh/cli/utils.py +7 -2
- solace_agent_mesh/common/constants.py +10 -0
- solace_agent_mesh/common/prompt_templates.py +1 -3
- solace_agent_mesh/common/utils.py +104 -30
- solace_agent_mesh/config_portal/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/__init__.py +0 -0
- solace_agent_mesh/config_portal/backend/common.py +35 -0
- solace_agent_mesh/config_portal/backend/server.py +233 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DRPGOzHj.js +42 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/components-ZIfdTbrV.js +191 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/entry.client-DX1misIU.js +19 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/index-BJHAE5s4.js +17 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-8147e469.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DgMDqKDc.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-hhS5izs8.css +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/favicon.ico +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/index.html +7 -0
- solace_agent_mesh/configs/orchestrator.yaml +1 -1
- solace_agent_mesh/configs/service_embedding.yaml +1 -1
- solace_agent_mesh/configs/service_llm.yaml +1 -1
- solace_agent_mesh/gateway/components/gateway_base.py +7 -1
- solace_agent_mesh/gateway/components/gateway_input.py +8 -5
- solace_agent_mesh/gateway/components/gateway_output.py +12 -3
- solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +4 -0
- solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +43 -12
- solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +19 -5
- solace_agent_mesh/orchestrator/orchestrator_main.py +11 -5
- solace_agent_mesh/orchestrator/orchestrator_prompt.py +184 -60
- solace_agent_mesh/services/file_service/file_service.py +5 -0
- solace_agent_mesh/services/file_service/file_service_constants.py +1 -1
- solace_agent_mesh/services/file_service/file_transformations.py +11 -1
- solace_agent_mesh/services/file_service/file_utils.py +2 -0
- solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +21 -46
- solace_agent_mesh/services/history_service/history_providers/file_history_provider.py +74 -0
- solace_agent_mesh/services/history_service/history_providers/index.py +40 -0
- solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +19 -156
- solace_agent_mesh/services/history_service/history_providers/mongodb_history_provider.py +66 -0
- solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +40 -140
- solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +93 -0
- solace_agent_mesh/services/history_service/history_service.py +315 -41
- solace_agent_mesh/services/history_service/long_term_memory/__init__.py +0 -0
- solace_agent_mesh/services/history_service/long_term_memory/long_term_memory.py +399 -0
- solace_agent_mesh/services/llm_service/components/llm_request_component.py +19 -0
- solace_agent_mesh/templates/gateway-config-template.yaml +2 -1
- solace_agent_mesh/templates/gateway-default-config.yaml +3 -3
- solace_agent_mesh/templates/plugin-gateway-default-config.yaml +29 -0
- solace_agent_mesh/templates/rest-api-default-config.yaml +2 -1
- solace_agent_mesh/templates/slack-default-config.yaml +1 -1
- solace_agent_mesh/templates/solace-agent-mesh-default.yaml +9 -0
- solace_agent_mesh/templates/web-default-config.yaml +2 -1
- solace_agent_mesh-0.2.1.dist-info/METADATA +172 -0
- {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/RECORD +71 -52
- solace_agent_mesh/common/prompt_templates_unused_delete.py +0 -161
- solace_agent_mesh-0.1.3.dist-info/METADATA +0 -208
- {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/licenses/LICENSE +0 -0
|
@@ -54,8 +54,15 @@ class PlantUmlDiagram(Action):
|
|
|
54
54
|
{"role": "user", "content": description},
|
|
55
55
|
]
|
|
56
56
|
agent = self.get_agent()
|
|
57
|
-
|
|
58
|
-
|
|
57
|
+
try:
|
|
58
|
+
response = agent.do_llm_service_request(messages=messages)
|
|
59
|
+
expression = response.get("content")
|
|
60
|
+
except TimeoutError as e:
|
|
61
|
+
log.error("LLM request timed out: %s", str(e))
|
|
62
|
+
return ActionResponse(message="LLM request timed out")
|
|
63
|
+
except Exception as e:
|
|
64
|
+
log.error("Failed to process content with LLM: %s", str(e))
|
|
65
|
+
return ActionResponse(message="Failed to process content with LLM")
|
|
59
66
|
|
|
60
67
|
# Surround expression with @startuml and @enduml if missing
|
|
61
68
|
if not expression.startswith("@startuml"):
|
|
@@ -37,46 +37,44 @@ class PlotlyGraph(Action):
|
|
|
37
37
|
],
|
|
38
38
|
"required_scopes": ["global:plotly:read"],
|
|
39
39
|
"examples": [
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
</example>
|
|
79
|
-
"""
|
|
40
|
+
{
|
|
41
|
+
"docstring": "This is an example of a user asking for a bar graph. The plotly action from the global agent is invoked to generate the graph.",
|
|
42
|
+
"tag_prefix_placeholder": "{tp}",
|
|
43
|
+
"starting_id": "12",
|
|
44
|
+
"user_input": "Please generate a random bar graph for me",
|
|
45
|
+
"metadata": [
|
|
46
|
+
"local_time: 2024-09-04 15:59:02 EDT-0400 (Wednesday)"
|
|
47
|
+
],
|
|
48
|
+
"reasoning": [
|
|
49
|
+
"- user has requested a random bar graph",
|
|
50
|
+
"- invoke the plotly action from the global agent to generate a bar graph with random data",
|
|
51
|
+
],
|
|
52
|
+
"response_text": "Certainly! I'd be happy to generate a random bar graph for you.",
|
|
53
|
+
"status_update": "I'll use our plotting tool to create this for you right away.",
|
|
54
|
+
"action": {
|
|
55
|
+
"agent": "global",
|
|
56
|
+
"name": "plotly",
|
|
57
|
+
"parameter_name": "plotly_figure_config",
|
|
58
|
+
"parameters": {
|
|
59
|
+
"plotly_figure_config": [
|
|
60
|
+
"{",
|
|
61
|
+
' "data": [',
|
|
62
|
+
" {",
|
|
63
|
+
' "x": ["A", "B", "C", "D", "E"],',
|
|
64
|
+
' "y": [23, 45, 56, 78, 90],',
|
|
65
|
+
' "type": "bar"',
|
|
66
|
+
" }",
|
|
67
|
+
" ],",
|
|
68
|
+
' "layout": {',
|
|
69
|
+
' "title": "Random Bar Graph",',
|
|
70
|
+
' "xaxis": {"title": "Categories"},',
|
|
71
|
+
' "yaxis": {"title": "Values"}',
|
|
72
|
+
" }",
|
|
73
|
+
"}",
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
},
|
|
77
|
+
}
|
|
80
78
|
],
|
|
81
79
|
},
|
|
82
80
|
**kwargs,
|
|
@@ -84,15 +82,38 @@ class PlotlyGraph(Action):
|
|
|
84
82
|
|
|
85
83
|
def invoke(self, params, meta={}) -> ActionResponse:
|
|
86
84
|
if platform.system() == "Windows":
|
|
87
|
-
kaleido_version = version(
|
|
88
|
-
min_version = parse(
|
|
89
|
-
max_version = parse(
|
|
90
|
-
if
|
|
85
|
+
kaleido_version = version("kaleido")
|
|
86
|
+
min_version = parse("0.1.0.post1")
|
|
87
|
+
max_version = parse("0.2.0")
|
|
88
|
+
if (
|
|
89
|
+
parse(kaleido_version) < min_version
|
|
90
|
+
or parse(kaleido_version) >= max_version
|
|
91
|
+
):
|
|
91
92
|
return ActionResponse(
|
|
92
93
|
message="For Windows users, the plotting functionality requires a specific version of Kaleido. Please refer to the documentation."
|
|
93
94
|
)
|
|
94
95
|
obj = params["plotly_figure_config"]
|
|
95
96
|
if isinstance(obj, str):
|
|
97
|
+
# First remove any leading/trailing whitespace
|
|
98
|
+
obj = obj.strip()
|
|
99
|
+
|
|
100
|
+
# Next remove ```yaml or ```json
|
|
101
|
+
if obj.startswith("```yaml") or obj.startswith("```json"):
|
|
102
|
+
obj = obj[7:]
|
|
103
|
+
elif obj.startswith("```"):
|
|
104
|
+
obj = obj[3:]
|
|
105
|
+
# Remove any trailing ``` characters
|
|
106
|
+
if obj.endswith("```"):
|
|
107
|
+
obj = obj[:-3]
|
|
108
|
+
# Remove any leading/trailing whitespace again
|
|
109
|
+
obj = obj.strip()
|
|
110
|
+
|
|
111
|
+
# If the string starts with a quote and ends with that same quote, remove them
|
|
112
|
+
if obj.startswith("'") and obj.endswith("'"):
|
|
113
|
+
obj = obj[1:-1]
|
|
114
|
+
elif obj.startswith('"') and obj.endswith('"'):
|
|
115
|
+
obj = obj[1:-1]
|
|
116
|
+
|
|
96
117
|
# Remove any leading/trailing quote characters
|
|
97
118
|
obj = obj.strip("'\" ")
|
|
98
119
|
try:
|
|
@@ -112,7 +133,9 @@ class PlotlyGraph(Action):
|
|
|
112
133
|
pio.write_image(fig, byte_io)
|
|
113
134
|
byte_io.seek(0)
|
|
114
135
|
file_service = FileService()
|
|
115
|
-
image_name =
|
|
136
|
+
image_name = (
|
|
137
|
+
"generated_graph_" + str(random.randint(100000, 999999)) + ".png"
|
|
138
|
+
)
|
|
116
139
|
image_meta = file_service.upload_from_buffer(
|
|
117
140
|
byte_io.read(),
|
|
118
141
|
image_name,
|
|
@@ -122,7 +145,8 @@ class PlotlyGraph(Action):
|
|
|
122
145
|
files.append(image_meta)
|
|
123
146
|
except Exception as e:
|
|
124
147
|
return ActionResponse(
|
|
125
|
-
message="Could not create plotly graph. Please check the plotly figure configuration. plotly error: "
|
|
148
|
+
message="Could not create plotly graph. Please check the plotly figure configuration. plotly error: "
|
|
149
|
+
+ str(e),
|
|
126
150
|
)
|
|
127
151
|
|
|
128
152
|
return ActionResponse(files=files)
|
|
@@ -31,37 +31,31 @@ class DoWebRequest(Action):
|
|
|
31
31
|
],
|
|
32
32
|
"required_scopes": ["web_request:do_web_request:read"],
|
|
33
33
|
"examples": [
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
</{tp}invoke_action>
|
|
60
|
-
|
|
61
|
-
<{tp}status_update>Retrieving the latest weather data for Ottawa...</{tp}status_update>'
|
|
62
|
-
</example_response>
|
|
63
|
-
</example>
|
|
64
|
-
"""
|
|
34
|
+
{
|
|
35
|
+
"docstring": "This is an example of a user requesting to fetch information from the web. The web_request agent is open so invoke the do_web_request action to fetch the content from the url and process the information according to the llm_prompt.",
|
|
36
|
+
"tag_prefix_placeholder": "{tp}",
|
|
37
|
+
"starting_id": "10",
|
|
38
|
+
"user_input": "What is the weather in Ottawa?",
|
|
39
|
+
"metadata": [
|
|
40
|
+
"local_time: 2024-11-06 12:33:12 EST-0500 (Wednesday)"
|
|
41
|
+
],
|
|
42
|
+
"reasoning": [
|
|
43
|
+
"- User is asking for current weather information in Ottawa",
|
|
44
|
+
"- We need to fetch up-to-date weather data",
|
|
45
|
+
"- Use the web_request agent to get the latest weather information",
|
|
46
|
+
"- Plan to use the Environment Canada website for accurate local weather data"
|
|
47
|
+
],
|
|
48
|
+
"response_text": "Certainly! I'll fetch the current weather information for Ottawa for you right away.",
|
|
49
|
+
"status_update": "Retrieving the latest weather data for Ottawa...",
|
|
50
|
+
"action": {
|
|
51
|
+
"agent": "web_request",
|
|
52
|
+
"name": "do_web_request",
|
|
53
|
+
"parameters": {
|
|
54
|
+
"url": "https://weather.gc.ca/city/pages/on-118_metric_e.html",
|
|
55
|
+
"llm_prompt": "Extract the current temperature, weather conditions, and any important weather alerts or warnings for Ottawa from the webpage. Format the response as a bulleted list with emoji where appropriate."
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
}
|
|
65
59
|
],
|
|
66
60
|
},
|
|
67
61
|
**kwargs,
|
|
@@ -127,8 +121,15 @@ class DoWebRequest(Action):
|
|
|
127
121
|
]
|
|
128
122
|
|
|
129
123
|
agent = self.get_agent()
|
|
130
|
-
|
|
131
|
-
|
|
124
|
+
try:
|
|
125
|
+
response = agent.do_llm_service_request(messages=messages)
|
|
126
|
+
content = response.get("content")
|
|
127
|
+
except TimeoutError as e:
|
|
128
|
+
log.error("LLM request timed out: %s", str(e))
|
|
129
|
+
return ActionResponse(message="LLM request timed out")
|
|
130
|
+
except Exception as e:
|
|
131
|
+
log.error("Failed to process content with LLM: %s", str(e))
|
|
132
|
+
return ActionResponse(message="Failed to process content with LLM")
|
|
132
133
|
|
|
133
134
|
# Code to create the image using the provided content
|
|
134
135
|
return ActionResponse(message=content)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
__version__ = "0.1
|
|
1
|
+
__version__ = "0.2.1"
|
|
@@ -16,7 +16,7 @@ def copy_from_plugin(name, plugin_name, entity_type):
|
|
|
16
16
|
if entity_type not in ["agents", "gateways"]:
|
|
17
17
|
log_error("Invalid entity type.")
|
|
18
18
|
return 1
|
|
19
|
-
|
|
19
|
+
|
|
20
20
|
src_entity_name = name
|
|
21
21
|
if ":" in plugin_name:
|
|
22
22
|
plugin_name, src_entity_name = plugin_name.split(":")
|
|
@@ -33,11 +33,13 @@ def copy_from_plugin(name, plugin_name, entity_type):
|
|
|
33
33
|
item_name = f"{item_name}.yaml" if entity_type == "agents" else item_name
|
|
34
34
|
|
|
35
35
|
src_entity_name = src_entity_name.replace("-", "_")
|
|
36
|
-
src_entity_name =
|
|
36
|
+
src_entity_name = (
|
|
37
|
+
f"{src_entity_name}.yaml" if entity_type == "agents" else src_entity_name
|
|
38
|
+
)
|
|
37
39
|
template_path = os.path.join(plugin_path, "configs", entity_type, src_entity_name)
|
|
38
40
|
|
|
39
41
|
if not os.path.exists(template_path):
|
|
40
|
-
log_error(f"Could not find '{
|
|
42
|
+
log_error(f"Could not find '{src_entity_name}' in '{plugin_name}' plugin.")
|
|
41
43
|
return 1
|
|
42
44
|
|
|
43
45
|
config = click.get_current_context().obj
|
|
@@ -80,11 +82,11 @@ def copy_from_plugin(name, plugin_name, entity_type):
|
|
|
80
82
|
else:
|
|
81
83
|
log_error("Invalid entity type.")
|
|
82
84
|
return 1
|
|
83
|
-
|
|
85
|
+
|
|
84
86
|
temp_file = os.path.join(config_directory, "__TEMPLATES_WILL_BE_HERE__")
|
|
85
87
|
if os.path.exists(temp_file):
|
|
86
88
|
os.remove(temp_file)
|
|
87
|
-
|
|
89
|
+
|
|
88
90
|
click.echo(
|
|
89
91
|
f"Copied {entity_type[:-1]} '{name}' from plugin '{plugin_name}' at: {get_display_path(target_directory)}"
|
|
90
|
-
)
|
|
92
|
+
)
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import os
|
|
2
2
|
import sys
|
|
3
3
|
import click
|
|
4
|
+
import re
|
|
4
5
|
|
|
5
|
-
from cli.utils import get_display_path, load_template, log_error, get_formatted_names
|
|
6
|
+
from cli.utils import get_display_path, load_template, log_error, get_formatted_names, log_warning
|
|
6
7
|
from cli.commands.plugin.build import get_all_plugin_gateway_interfaces
|
|
7
8
|
from cli.config import Config
|
|
8
9
|
|
|
@@ -34,6 +35,126 @@ def _add_python_files(modules_directory, template_args, created_file_names):
|
|
|
34
35
|
f.write(gateway_template)
|
|
35
36
|
created_file_names.append(gateway_path)
|
|
36
37
|
|
|
38
|
+
def _update_gateway_yaml(yaml_string, interface_gateway_config):
|
|
39
|
+
# Update system_purpose
|
|
40
|
+
if "system_purpose" in interface_gateway_config:
|
|
41
|
+
yaml_string = re.sub(
|
|
42
|
+
r'(system_purpose: >\n\s+)(.*?)(?=\n\s{4}\S)',
|
|
43
|
+
lambda m: f'{m.group(1)}{interface_gateway_config["system_purpose"]}',
|
|
44
|
+
yaml_string,
|
|
45
|
+
flags=re.DOTALL
|
|
46
|
+
)
|
|
47
|
+
|
|
48
|
+
# Update interaction_type
|
|
49
|
+
if "interaction_type" in interface_gateway_config:
|
|
50
|
+
yaml_string = re.sub(
|
|
51
|
+
r'(interaction_type: )".*?"',
|
|
52
|
+
lambda m: f'{m.group(1)}"{interface_gateway_config["interaction_type"]}"',
|
|
53
|
+
yaml_string
|
|
54
|
+
)
|
|
55
|
+
|
|
56
|
+
# Update history settings
|
|
57
|
+
history_config = interface_gateway_config.get("history", {})
|
|
58
|
+
if not history_config.get("enabled", False):
|
|
59
|
+
yaml_string = re.sub(r'\n\s+history_config: \n\s+<<: \*default_history_policy', '', yaml_string)
|
|
60
|
+
yaml_string = re.sub(r'(retain_history: )true', r'\1false', yaml_string)
|
|
61
|
+
yaml_string = re.sub(
|
|
62
|
+
r'\n- history_policy:.*?(?=\n\n)',
|
|
63
|
+
'',
|
|
64
|
+
yaml_string,
|
|
65
|
+
flags=re.DOTALL
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
else:
|
|
69
|
+
if history_config.get("type") is not None:
|
|
70
|
+
yaml_string = re.sub(
|
|
71
|
+
r'(type: )".*?"',
|
|
72
|
+
lambda m: f'{m.group(1)}"{history_config.get("type")}"',
|
|
73
|
+
yaml_string,
|
|
74
|
+
count=1 # Update only the first occurrence
|
|
75
|
+
)
|
|
76
|
+
if history_config.get("time_to_live") is not None:
|
|
77
|
+
yaml_string = re.sub(
|
|
78
|
+
r'(time_to_live: )\d+',
|
|
79
|
+
lambda m: f'{m.group(1)}{history_config.get("time_to_live")}',
|
|
80
|
+
yaml_string
|
|
81
|
+
)
|
|
82
|
+
if history_config.get("expiration_check_interval") is not None:
|
|
83
|
+
yaml_string = re.sub(
|
|
84
|
+
r'(expiration_check_interval: )\d+',
|
|
85
|
+
lambda m: f'{m.group(1)}{history_config.get("expiration_check_interval")}',
|
|
86
|
+
yaml_string
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
if history_config.get("max_turns") is not None:
|
|
90
|
+
yaml_string = re.sub(
|
|
91
|
+
r'(max_turns: )\d+',
|
|
92
|
+
lambda m: f'{m.group(1)}{history_config.get("max_turns")}',
|
|
93
|
+
yaml_string
|
|
94
|
+
)
|
|
95
|
+
if history_config.get("max_characters") is not None:
|
|
96
|
+
yaml_string = re.sub(
|
|
97
|
+
r'(max_characters: )\d+',
|
|
98
|
+
lambda m: f'{m.group(1)}{history_config.get("max_characters")}',
|
|
99
|
+
yaml_string
|
|
100
|
+
)
|
|
101
|
+
if history_config.get("enforce_alternate_message_roles") is not None:
|
|
102
|
+
yaml_string = re.sub(
|
|
103
|
+
r'(enforce_alternate_message_roles: )\w+',
|
|
104
|
+
lambda m: f'{m.group(1)}{str(history_config.get("enforce_alternate_message_roles", True)).lower()}',
|
|
105
|
+
yaml_string
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# Inject long-term memory before history_policy
|
|
109
|
+
if history_config.get("long_term_memory", {}).get("enabled", False):
|
|
110
|
+
# Build llm_config string
|
|
111
|
+
llm_config_items = history_config['long_term_memory'].get('llm_config', {})
|
|
112
|
+
if llm_config_items:
|
|
113
|
+
llm_config_parts = []
|
|
114
|
+
for key, value in llm_config_items.items():
|
|
115
|
+
llm_config_parts.append(f"{key}: {value}")
|
|
116
|
+
llm_config = "\n " + "\n ".join(llm_config_parts) + "\n"
|
|
117
|
+
else:
|
|
118
|
+
llm_config = " {} \n"
|
|
119
|
+
|
|
120
|
+
# Build store_config string
|
|
121
|
+
store_config_items = history_config['long_term_memory'].get('store_config', {})
|
|
122
|
+
if store_config_items:
|
|
123
|
+
store_config_parts = []
|
|
124
|
+
for key, value in store_config_items.items():
|
|
125
|
+
store_config_parts.append(f"{key}: {value}")
|
|
126
|
+
store_config = "\n " + "\n ".join(store_config_parts) + "\n"
|
|
127
|
+
else:
|
|
128
|
+
store_config = " {} \n"
|
|
129
|
+
long_term_yaml = (
|
|
130
|
+
'long_term_memory: true\n'
|
|
131
|
+
' long_term_memory_config:\n'
|
|
132
|
+
f' llm_config:{llm_config}'
|
|
133
|
+
f' store_config:{store_config}'
|
|
134
|
+
' '
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
if "long_term_memory:" not in yaml_string:
|
|
138
|
+
yaml_string = re.sub(
|
|
139
|
+
r'(history_policy: # History provider configs.*?\n(\s+max_turns: \d+))',
|
|
140
|
+
lambda m: f'{long_term_yaml}{m.group(1)}',
|
|
141
|
+
yaml_string,
|
|
142
|
+
flags=re.DOTALL
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Inject type_config under history_policy
|
|
146
|
+
type_config = history_config.get("type_config", {})
|
|
147
|
+
if type_config:
|
|
148
|
+
type_config_yaml = '\n'.join([f' {key}: {value}' for key, value in type_config.items()])
|
|
149
|
+
yaml_string = re.sub(
|
|
150
|
+
r'(history_policy: # History provider configs.*?)\n',
|
|
151
|
+
lambda m: f'{m.group(1)}\n{type_config_yaml}\n',
|
|
152
|
+
yaml_string,
|
|
153
|
+
flags=re.DOTALL
|
|
154
|
+
)
|
|
155
|
+
|
|
156
|
+
return yaml_string
|
|
157
|
+
|
|
37
158
|
def add_gateway_command(name, interfaces):
|
|
38
159
|
"""
|
|
39
160
|
Creates a gateway configuration directory and files based on provided templates.
|
|
@@ -76,7 +197,7 @@ def add_gateway_command(name, interfaces):
|
|
|
76
197
|
def abort():
|
|
77
198
|
sys.exit(1)
|
|
78
199
|
|
|
79
|
-
plugin_gateway_interfaces = get_all_plugin_gateway_interfaces(config, abort)
|
|
200
|
+
plugin_gateway_interfaces = get_all_plugin_gateway_interfaces(config, abort, return_plugin_config=True)
|
|
80
201
|
|
|
81
202
|
# Check if the gateway directory already exists
|
|
82
203
|
if os.path.exists(gateway_directory):
|
|
@@ -91,12 +212,11 @@ def add_gateway_command(name, interfaces):
|
|
|
91
212
|
|
|
92
213
|
# Create the gateway config file from the template directory
|
|
93
214
|
# The file name is gateway-default-config.yaml but write it as gateway.yaml in the gateway_directory
|
|
94
|
-
gateway_config_template = load_template("gateway-default-config.yaml")
|
|
95
215
|
gateway_config_path = os.path.join(gateway_directory, "gateway.yaml")
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
216
|
+
gateway_config_default = load_template("gateway-default-config.yaml")
|
|
217
|
+
gateway_config = gateway_config_default
|
|
218
|
+
gateway_config_interface_default_name = None # the interface name that is used for the default gateway config
|
|
219
|
+
gateway_config_overwritten = False
|
|
100
220
|
|
|
101
221
|
# If the interface list is not empty, create the interface config files
|
|
102
222
|
if interfaces:
|
|
@@ -105,8 +225,17 @@ def add_gateway_command(name, interfaces):
|
|
|
105
225
|
# The name will be {interface}-default-config.yaml
|
|
106
226
|
# Write the file as {interface}.yaml in the gateway_directory
|
|
107
227
|
if interface in plugin_gateway_interfaces:
|
|
228
|
+
interface_gateway_config = plugin_gateway_interfaces[interface][1]
|
|
229
|
+
# Checking if the interface has default values for the gateway.yaml
|
|
230
|
+
if interface_gateway_config:
|
|
231
|
+
# Checking if another interface has already been used to create the gateway.yaml
|
|
232
|
+
if gateway_config_interface_default_name:
|
|
233
|
+
# Overwrite the default gateway config with the current interface config
|
|
234
|
+
gateway_config_overwritten = True
|
|
235
|
+
gateway_config_interface_default_name = interface
|
|
236
|
+
gateway_config = _update_gateway_yaml(gateway_config_default, interface_gateway_config)
|
|
108
237
|
interface_default_path = os.path.join(
|
|
109
|
-
plugin_gateway_interfaces[interface],
|
|
238
|
+
plugin_gateway_interfaces[interface][0],
|
|
110
239
|
f"{interface}-default-config.yaml",
|
|
111
240
|
)
|
|
112
241
|
if not os.path.exists(interface_default_path):
|
|
@@ -149,6 +278,17 @@ def add_gateway_command(name, interfaces):
|
|
|
149
278
|
log_error(f"Error creating gateway, gateway config was created: {e}")
|
|
150
279
|
return 1
|
|
151
280
|
|
|
281
|
+
with open(gateway_config_path, "w", encoding="utf-8") as f:
|
|
282
|
+
f.write(gateway_config)
|
|
283
|
+
|
|
284
|
+
if gateway_config_overwritten:
|
|
285
|
+
log_warning(("Multiple interface configurations found. "
|
|
286
|
+
"Overwriting default gateway configuration with "
|
|
287
|
+
f"{gateway_config_interface_default_name} interface configuration."
|
|
288
|
+
))
|
|
289
|
+
|
|
290
|
+
created_file_names.append(gateway_config_path)
|
|
291
|
+
|
|
152
292
|
temp_file = os.path.join(config_directory, "__TEMPLATES_WILL_BE_HERE__")
|
|
153
293
|
if os.path.exists(temp_file):
|
|
154
294
|
os.remove(temp_file)
|
|
@@ -169,7 +309,8 @@ def add_interface_command(name):
|
|
|
169
309
|
Creates a new gateway interface with the provided name.
|
|
170
310
|
"""
|
|
171
311
|
config = Config.get_plugin_config()
|
|
172
|
-
|
|
312
|
+
plugin_config = config.get("solace_agent_mesh_plugin", {})
|
|
313
|
+
plugin_name = plugin_config.get("name")
|
|
173
314
|
if not plugin_name or plugin_name == "solace-agent-mesh-plugin":
|
|
174
315
|
log_error("Could not find a valid plugin project")
|
|
175
316
|
return 1
|
|
@@ -210,6 +351,18 @@ def add_interface_command(name):
|
|
|
210
351
|
|
|
211
352
|
_add_python_files(modules_directory, template_args, created_file_names)
|
|
212
353
|
|
|
354
|
+
# Update the 'solace-agent-mesh-plugin' configuration file
|
|
355
|
+
plugin_config["includes_gateway_interface"] = True
|
|
356
|
+
plugin_gateway_config_template = load_template("plugin-gateway-default-config.yaml", parser=Config.get_yaml_parser())
|
|
357
|
+
if not plugin_gateway_config_template:
|
|
358
|
+
log_error("Error: Plugin gateway config template not found.")
|
|
359
|
+
else:
|
|
360
|
+
if "interface_gateway_configs" not in plugin_config:
|
|
361
|
+
plugin_config["interface_gateway_configs"] = {}
|
|
362
|
+
plugin_config["interface_gateway_configs"][template_args["HYPHENED_NAME"]] = plugin_gateway_config_template.get("plugin_gateway_default_config", {})
|
|
363
|
+
Config.write_config(config, Config.user_plugin_config_file)
|
|
364
|
+
click.echo(f"Updated {Config.user_plugin_config_file} with default gateway interface configuration for {template_args['HYPHENED_NAME']}")
|
|
365
|
+
|
|
213
366
|
except IOError as e:
|
|
214
367
|
log_error(f"Error creating gateway interface, {e}")
|
|
215
368
|
return 1
|
|
@@ -16,7 +16,6 @@ from cli.utils import (
|
|
|
16
16
|
get_display_path,
|
|
17
17
|
log_error,
|
|
18
18
|
apply_document_parsers,
|
|
19
|
-
find_last_list_item_indent,
|
|
20
19
|
normalize_and_reindent_yaml
|
|
21
20
|
)
|
|
22
21
|
|
|
@@ -379,7 +378,22 @@ def build_solace_agent_mesh(config, build_config_dir, abort, parsers):
|
|
|
379
378
|
if f.endswith(".yaml")
|
|
380
379
|
and not any(f.startswith(prefix) for prefix in skip_prefixes)
|
|
381
380
|
]
|
|
381
|
+
|
|
382
|
+
# Check if embedding service is enabled
|
|
383
|
+
embedding_enabled = True # Default to True for backward compatibility
|
|
384
|
+
built_in_services = config.get("built_in", {}).get("services", [])
|
|
385
|
+
if built_in_services: # Only check if services section exists
|
|
386
|
+
embedding_enabled = False
|
|
387
|
+
for service in built_in_services:
|
|
388
|
+
if service.get("name") == "embedding" and service.get("enabled"):
|
|
389
|
+
embedding_enabled = True
|
|
390
|
+
break
|
|
391
|
+
|
|
382
392
|
for config_file in config_files:
|
|
393
|
+
# Skip embedding service if not enabled
|
|
394
|
+
if config_file == "service_embedding.yaml" and not embedding_enabled:
|
|
395
|
+
click.echo(f"Skipping embedding service as it is disabled.")
|
|
396
|
+
continue
|
|
383
397
|
try:
|
|
384
398
|
# Read config file
|
|
385
399
|
config_file_path = os.path.join(configs_source_path, config_file)
|
|
@@ -39,38 +39,55 @@ def ai_provider_step(options, default_options, none_interactive, abort):
|
|
|
39
39
|
default_options["llm_model_name"],
|
|
40
40
|
none_interactive,
|
|
41
41
|
)
|
|
42
|
-
|
|
43
|
-
ask_if_not_provided(
|
|
42
|
+
# Ask if the user wants to enable the embedding service
|
|
43
|
+
embedding_enabled = ask_if_not_provided(
|
|
44
44
|
options,
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
default_options["
|
|
45
|
+
"embedding_service_enabled",
|
|
46
|
+
"Enable embedding service for vector embeddings?",
|
|
47
|
+
default_options["embedding_service_enabled"],
|
|
48
48
|
none_interactive,
|
|
49
49
|
)
|
|
50
50
|
|
|
51
|
-
|
|
52
|
-
options,
|
|
53
|
-
"embedding_api_key",
|
|
54
|
-
"Provide Embedding API Key",
|
|
55
|
-
default_options["embedding_api_key"],
|
|
56
|
-
none_interactive,
|
|
57
|
-
hide_input=True,
|
|
58
|
-
)
|
|
51
|
+
options["embedding_service_enabled"] = embedding_enabled
|
|
59
52
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
53
|
+
# Only ask for embedding configuration if the service is enabled
|
|
54
|
+
if embedding_enabled:
|
|
55
|
+
ask_if_not_provided(
|
|
56
|
+
options,
|
|
57
|
+
"embedding_endpoint_url",
|
|
58
|
+
"Provide Embedding endpoint URL",
|
|
59
|
+
default_options["embedding_endpoint_url"],
|
|
60
|
+
none_interactive,
|
|
67
61
|
)
|
|
68
|
-
)
|
|
69
62
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
63
|
+
ask_if_not_provided(
|
|
64
|
+
options,
|
|
65
|
+
"embedding_api_key",
|
|
66
|
+
"Provide Embedding API Key",
|
|
67
|
+
default_options["embedding_api_key"],
|
|
68
|
+
none_interactive,
|
|
69
|
+
hide_input=True,
|
|
70
|
+
)
|
|
71
|
+
|
|
72
|
+
click.echo(
|
|
73
|
+
click.style(
|
|
74
|
+
(
|
|
75
|
+
"The model name should follow the format `provider/model-name`."
|
|
76
|
+
"\n\t For example: openai/text-embedding-ada-002 or openai/my-model-that-follows-openai-api"
|
|
77
|
+
),
|
|
78
|
+
fg="yellow",
|
|
79
|
+
)
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
ask_if_not_provided(
|
|
83
|
+
options,
|
|
84
|
+
"embedding_model_name",
|
|
85
|
+
"Provide Embedding model name to use",
|
|
86
|
+
default_options["embedding_model_name"],
|
|
87
|
+
none_interactive,
|
|
88
|
+
)
|
|
89
|
+
else:
|
|
90
|
+
# Set empty values for embedding configuration if the service is disabled
|
|
91
|
+
options["embedding_endpoint_url"] = ""
|
|
92
|
+
options["embedding_api_key"] = ""
|
|
93
|
+
options["embedding_model_name"] = ""
|
|
@@ -3,10 +3,7 @@ import click
|
|
|
3
3
|
import os
|
|
4
4
|
|
|
5
5
|
from cli.utils import ask_if_not_provided
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
CONTAINER_RUN_COMMAND = " run -d -p 8080:8080 -p 55554:55555 -p 8008:8008 -p 1883:1883 -p 8000:8000 -p 5672:5672 -p 9000:9000 -p 2222:2222 --shm-size=2g --env username_admin_globalaccesslevel=admin --env username_admin_password=admin --name=solace solace/solace-pubsub-standard"
|
|
9
|
-
|
|
6
|
+
from solace_agent_mesh.config_portal.backend.common import CONTAINER_RUN_COMMAND
|
|
10
7
|
|
|
11
8
|
def broker_step(options, default_options, none_interactive, abort):
|
|
12
9
|
"""
|