solace-agent-mesh 0.2.0__py3-none-any.whl → 0.2.2__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 +94 -36
- solace_agent_mesh/agents/global/actions/plotly_graph.py +48 -22
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add/agent.py +1 -1
- solace_agent_mesh/cli/commands/add/copy_from_plugin.py +9 -7
- solace_agent_mesh/cli/commands/add/gateway.py +2 -2
- solace_agent_mesh/cli/commands/build.py +15 -0
- 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/check_if_already_done.py +1 -1
- solace_agent_mesh/cli/commands/init/create_config_file_step.py +8 -0
- solace_agent_mesh/cli/commands/init/init.py +20 -38
- solace_agent_mesh/cli/commands/init/web_init_step.py +32 -0
- solace_agent_mesh/cli/commands/plugin/build.py +52 -10
- solace_agent_mesh/cli/commands/plugin/create.py +3 -3
- solace_agent_mesh/cli/commands/run.py +2 -2
- solace_agent_mesh/cli/main.py +20 -8
- solace_agent_mesh/common/prompt_templates.py +1 -3
- solace_agent_mesh/common/utils.py +88 -19
- 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/Solace_community_logo.png +0 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-b13CSm84.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-c92a7808.js +1 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-BApq5dPK.js +10 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/root-DX4gQ516.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/orchestrator/components/orchestrator_action_manager_timeout_component.py +4 -0
- solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +46 -16
- 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 +78 -74
- solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +1 -1
- solace_agent_mesh/services/llm_service/components/llm_request_component.py +54 -31
- solace_agent_mesh/templates/rest-api-default-config.yaml +4 -2
- solace_agent_mesh/templates/solace-agent-mesh-default.yaml +9 -0
- solace_agent_mesh/templates/web-default-config.yaml +4 -2
- solace_agent_mesh-0.2.2.dist-info/METADATA +172 -0
- {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/RECORD +49 -35
- solace_agent_mesh/common/prompt_templates_unused_delete.py +0 -161
- solace_agent_mesh-0.2.0.dist-info/METADATA +0 -209
- {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/licenses/LICENSE +0 -0
|
@@ -2,7 +2,12 @@ import subprocess
|
|
|
2
2
|
import os
|
|
3
3
|
import click
|
|
4
4
|
|
|
5
|
-
from cli.utils import
|
|
5
|
+
from cli.utils import (
|
|
6
|
+
log_error,
|
|
7
|
+
apply_document_parsers,
|
|
8
|
+
load_plugin,
|
|
9
|
+
get_formatted_names,
|
|
10
|
+
)
|
|
6
11
|
from cli.config import Config
|
|
7
12
|
|
|
8
13
|
|
|
@@ -27,12 +32,21 @@ def get_all_plugin_gateway_interfaces(config, abort, return_plugin_config=False)
|
|
|
27
32
|
if not os.path.exists(interface_path):
|
|
28
33
|
continue
|
|
29
34
|
|
|
30
|
-
interface_gateway_configs = (
|
|
35
|
+
interface_gateway_configs = (
|
|
36
|
+
(
|
|
37
|
+
Config.load_config(
|
|
38
|
+
os.path.join(plugin_path, Config.user_plugin_config_file)
|
|
39
|
+
)
|
|
40
|
+
or {}
|
|
41
|
+
)
|
|
42
|
+
.get("solace_agent_mesh_plugin", {})
|
|
43
|
+
.get("interface_gateway_configs", {})
|
|
44
|
+
)
|
|
31
45
|
interface_gateway_config = None
|
|
32
46
|
# Ensuring flow and default pair exist
|
|
33
47
|
interface_pairs = {}
|
|
34
48
|
for file in os.listdir(interface_path):
|
|
35
|
-
if file.endswith("-flows.yaml")
|
|
49
|
+
if file.endswith("-flows.yaml"):
|
|
36
50
|
name = file.split("-flows.yaml")[0]
|
|
37
51
|
if name not in interface_pairs:
|
|
38
52
|
interface_pairs[name] = []
|
|
@@ -43,22 +57,35 @@ def get_all_plugin_gateway_interfaces(config, abort, return_plugin_config=False)
|
|
|
43
57
|
if name not in interface_pairs:
|
|
44
58
|
interface_pairs[name] = []
|
|
45
59
|
interface_pairs[name].append(file)
|
|
46
|
-
|
|
60
|
+
|
|
47
61
|
for name, files in interface_pairs.items():
|
|
48
62
|
if len(files) == 2:
|
|
49
63
|
if return_plugin_config:
|
|
50
|
-
for
|
|
64
|
+
for (
|
|
65
|
+
interface_name,
|
|
66
|
+
interface_config,
|
|
67
|
+
) in interface_gateway_configs.items():
|
|
51
68
|
if interface_name == name.replace("-", "_"):
|
|
52
69
|
interface_gateway_config = interface_config
|
|
53
70
|
break
|
|
54
|
-
gateway_interfaces[name] = (
|
|
71
|
+
gateway_interfaces[name] = (
|
|
72
|
+
interface_path,
|
|
73
|
+
interface_gateway_config,
|
|
74
|
+
)
|
|
55
75
|
else:
|
|
56
76
|
gateway_interfaces[name] = interface_path
|
|
57
|
-
|
|
77
|
+
|
|
58
78
|
return gateway_interfaces
|
|
59
79
|
|
|
60
80
|
|
|
61
|
-
def build_plugins(
|
|
81
|
+
def build_plugins(
|
|
82
|
+
config,
|
|
83
|
+
build_config_dir,
|
|
84
|
+
abort,
|
|
85
|
+
parsers,
|
|
86
|
+
plugin_gateway_interfaces,
|
|
87
|
+
build_specific_gateway,
|
|
88
|
+
):
|
|
62
89
|
plugins = config.get("plugins", [])
|
|
63
90
|
plugins_overwrite_dir = os.path.join(build_config_dir, "..", "overwrites")
|
|
64
91
|
|
|
@@ -70,7 +97,9 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
|
|
|
70
97
|
name = plugin.get("name")
|
|
71
98
|
load_unspecified_files = plugin.get("load_unspecified_files", True)
|
|
72
99
|
load = plugin.get("load", {})
|
|
73
|
-
agents_to_load = [
|
|
100
|
+
agents_to_load = [
|
|
101
|
+
agent.replace("-", "_") for agent in (load.get("agents") or [])
|
|
102
|
+
]
|
|
74
103
|
gateways_to_load = load.get("gateways") or []
|
|
75
104
|
overwrites_to_load = load.get("overwrites") or []
|
|
76
105
|
|
|
@@ -130,6 +159,14 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
|
|
|
130
159
|
agent_config_content = apply_document_parsers(
|
|
131
160
|
agent_config_content, parsers, meta
|
|
132
161
|
)
|
|
162
|
+
# Perform name substitutions
|
|
163
|
+
base_agent_name = agent_config[:-5] # Remove .yaml
|
|
164
|
+
name_cases = get_formatted_names(base_agent_name)
|
|
165
|
+
for case, val in name_cases.items():
|
|
166
|
+
agent_config_content = agent_config_content.replace(
|
|
167
|
+
f"{{{{{case}}}}}", val
|
|
168
|
+
)
|
|
169
|
+
|
|
133
170
|
# Write agent configuration to build directory
|
|
134
171
|
agent_build_path = os.path.join(
|
|
135
172
|
build_config_dir, "agent_" + agent_config
|
|
@@ -165,7 +202,12 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
|
|
|
165
202
|
for gateway in gateway_subdirs:
|
|
166
203
|
if load_unspecified_files or gateway in gateway_dirs:
|
|
167
204
|
build_specific_gateway(
|
|
168
|
-
build_config_dir,
|
|
205
|
+
build_config_dir,
|
|
206
|
+
abort,
|
|
207
|
+
parsers,
|
|
208
|
+
gateway_config_path,
|
|
209
|
+
gateway,
|
|
210
|
+
plugin_gateway_interfaces,
|
|
169
211
|
)
|
|
170
212
|
|
|
171
213
|
####################
|
|
@@ -8,7 +8,7 @@ from cli.utils import log_error, ask_question
|
|
|
8
8
|
|
|
9
9
|
DEFAULT_DESCRIPTION = "A solace-agent-mesh plugin project."
|
|
10
10
|
DEFAULT_AUTHOR = "Author Name"
|
|
11
|
-
EMPTY_FILE_MSG = "
|
|
11
|
+
EMPTY_FILE_MSG = ""
|
|
12
12
|
|
|
13
13
|
def create_command(
|
|
14
14
|
path: str, description: str = None, author: str = None, skip: bool = False
|
|
@@ -87,10 +87,10 @@ def create_command(
|
|
|
87
87
|
with open(os.path.join(py_path, "__init__.py"), "w", encoding="utf-8") as f:
|
|
88
88
|
f.write("")
|
|
89
89
|
|
|
90
|
-
with open(os.path.join("configs", "
|
|
90
|
+
with open(os.path.join("configs", ".gitkeep"), "w", encoding="utf-8") as f:
|
|
91
91
|
f.write(EMPTY_FILE_MSG)
|
|
92
92
|
|
|
93
|
-
with open(os.path.join("interfaces", "
|
|
93
|
+
with open(os.path.join("interfaces", ".gitkeep"), "w", encoding="utf-8") as f:
|
|
94
94
|
f.write(EMPTY_FILE_MSG)
|
|
95
95
|
|
|
96
96
|
with open(os.path.join("src", "__init__.py"), "w", encoding="utf-8") as f:
|
|
@@ -21,7 +21,7 @@ FILES_TO_EXCLUDE = []
|
|
|
21
21
|
|
|
22
22
|
|
|
23
23
|
def run_command(
|
|
24
|
-
|
|
24
|
+
use_system_env, config_files, exclude_files, quick_build, ignore_build, force_build
|
|
25
25
|
):
|
|
26
26
|
"""Run the Solace Agent Mesh application."""
|
|
27
27
|
|
|
@@ -34,7 +34,7 @@ def run_command(
|
|
|
34
34
|
|
|
35
35
|
click.echo("Running Solace Agent Mesh application")
|
|
36
36
|
|
|
37
|
-
if
|
|
37
|
+
if not use_system_env:
|
|
38
38
|
try:
|
|
39
39
|
from dotenv import load_dotenv
|
|
40
40
|
|
solace_agent_mesh/cli/main.py
CHANGED
|
@@ -66,11 +66,11 @@ def build(y, no_init):
|
|
|
66
66
|
|
|
67
67
|
@cli.command()
|
|
68
68
|
@click.option(
|
|
69
|
-
"-
|
|
70
|
-
"--use-env",
|
|
69
|
+
"-u",
|
|
70
|
+
"--use-system-env",
|
|
71
71
|
default=False,
|
|
72
72
|
is_flag=True,
|
|
73
|
-
help="
|
|
73
|
+
help="Use only system environment variables (ignore environment variables defined in the config).",
|
|
74
74
|
)
|
|
75
75
|
@click.option(
|
|
76
76
|
"-s",
|
|
@@ -100,13 +100,13 @@ def build(y, no_init):
|
|
|
100
100
|
is_flag=True,
|
|
101
101
|
help="Runs the build command first regardless of the build directory. Mutually exclusive with --ignore-build.",
|
|
102
102
|
)
|
|
103
|
-
def run(
|
|
103
|
+
def run(use_system_env, files, skip, quick_build, ignore_build, force_build):
|
|
104
104
|
"""Run the Solace Agent Mesh application.
|
|
105
105
|
|
|
106
106
|
FILES: Config files to run. Uses all the yaml files in the build directory if not provided.
|
|
107
107
|
"""
|
|
108
108
|
return run_command(
|
|
109
|
-
|
|
109
|
+
use_system_env, list(files), list(skip), quick_build, ignore_build, force_build
|
|
110
110
|
)
|
|
111
111
|
|
|
112
112
|
|
|
@@ -153,6 +153,12 @@ def visualize(port, find_unused_port, host, use_env):
|
|
|
153
153
|
default=False,
|
|
154
154
|
help="Non-interactive mode. Skip all the prompts, Uses provided options and default values.",
|
|
155
155
|
)
|
|
156
|
+
@click.option(
|
|
157
|
+
"--use-web-based-init",
|
|
158
|
+
is_flag=True,
|
|
159
|
+
default=False,
|
|
160
|
+
help="Launch the browser-based initialization interface directly, skipping the prompt.",
|
|
161
|
+
)
|
|
156
162
|
@click.option(
|
|
157
163
|
"--namespace",
|
|
158
164
|
help="project namespace",
|
|
@@ -211,15 +217,21 @@ def visualize(port, find_unused_port, host, use_env):
|
|
|
211
217
|
)
|
|
212
218
|
@click.option(
|
|
213
219
|
"--embedding-model-name",
|
|
214
|
-
help="Embedding model name to use",
|
|
220
|
+
help="Embedding model name to use (only used if embedding service is enabled)",
|
|
215
221
|
)
|
|
216
222
|
@click.option(
|
|
217
223
|
"--embedding-endpoint-url",
|
|
218
|
-
help="Embedding endpoint URL",
|
|
224
|
+
help="Embedding endpoint URL (only used if embedding service is enabled)",
|
|
219
225
|
)
|
|
220
226
|
@click.option(
|
|
221
227
|
"--embedding-api-key",
|
|
222
|
-
help="Embedding API Key",
|
|
228
|
+
help="Embedding API Key (only used if embedding service is enabled)",
|
|
229
|
+
)
|
|
230
|
+
@click.option(
|
|
231
|
+
"--embedding-service-enabled",
|
|
232
|
+
is_flag=True,
|
|
233
|
+
default=None,
|
|
234
|
+
help="Enable/disable Embedding Service for vector embeddings",
|
|
223
235
|
)
|
|
224
236
|
@click.option(
|
|
225
237
|
"--built-in-agent",
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
from typing import List
|
|
2
|
-
from langchain_core.messages import HumanMessage
|
|
3
|
-
|
|
4
2
|
import yaml
|
|
5
3
|
|
|
6
4
|
|
|
@@ -22,7 +20,7 @@ matching_locations:
|
|
|
22
20
|
"""
|
|
23
21
|
|
|
24
22
|
|
|
25
|
-
def FilterLocationsUserPrompt(location_filter: str) ->
|
|
23
|
+
def FilterLocationsUserPrompt(location_filter: str) -> str:
|
|
26
24
|
return f"""
|
|
27
25
|
<user-location-filter>
|
|
28
26
|
{location_filter}
|
|
@@ -140,6 +140,12 @@ def parse_file_content(file_xml: str) -> dict:
|
|
|
140
140
|
Parse the xml tags in the content and return a dictionary of the content.
|
|
141
141
|
"""
|
|
142
142
|
try:
|
|
143
|
+
# It is possible that the content of the file mistakenly has t###_ prefixes on the
|
|
144
|
+
# tags, so we need to strip them off. This is a bit of a hack to work around LLM errors
|
|
145
|
+
|
|
146
|
+
file_xml = re.sub(r"<t\d+_", "<", file_xml)
|
|
147
|
+
file_xml = re.sub(r"</t\d+_", "</", file_xml)
|
|
148
|
+
|
|
143
149
|
ignore_content_tags = ["data"]
|
|
144
150
|
file_dict = xml_to_dict(file_xml, ignore_content_tags)
|
|
145
151
|
dict_keys = list(file_dict.keys())
|
|
@@ -165,6 +171,7 @@ def parse_llm_output(llm_output: str) -> dict:
|
|
|
165
171
|
# We need to save all the strings that we replace so that we can put them back
|
|
166
172
|
# after we parse the yaml. Use a sequence number to create a unique placeholder
|
|
167
173
|
# for each string.
|
|
174
|
+
|
|
168
175
|
string_placeholders = {}
|
|
169
176
|
string_count = 0
|
|
170
177
|
sanity = 100
|
|
@@ -246,7 +253,9 @@ def parse_llm_output(llm_output: str) -> dict:
|
|
|
246
253
|
return obj
|
|
247
254
|
|
|
248
255
|
|
|
249
|
-
def parse_orchestrator_response(
|
|
256
|
+
def parse_orchestrator_response(
|
|
257
|
+
response, last_chunk=False, tag_prefix="", check_reasoning=True
|
|
258
|
+
):
|
|
250
259
|
tp = tag_prefix
|
|
251
260
|
parsed_data = {
|
|
252
261
|
"actions": [],
|
|
@@ -324,6 +333,7 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
324
333
|
current_param_value = []
|
|
325
334
|
open_tags = []
|
|
326
335
|
current_text = []
|
|
336
|
+
seen_invoke_action = False
|
|
327
337
|
|
|
328
338
|
for line in response.split("\n"):
|
|
329
339
|
|
|
@@ -350,7 +360,8 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
350
360
|
file_line = line[: file_end_index + len(f"</{tp}file>")]
|
|
351
361
|
file_content = [file_line]
|
|
352
362
|
current_file = parse_file_content("\n".join(file_content))
|
|
353
|
-
|
|
363
|
+
if not seen_invoke_action:
|
|
364
|
+
add_content_entry(parsed_data["content"], "file", current_file)
|
|
354
365
|
in_file = False
|
|
355
366
|
current_file = {}
|
|
356
367
|
file_content = []
|
|
@@ -368,7 +379,8 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
368
379
|
file_line = line[: file_end_index + len(f"</{tp}file>")]
|
|
369
380
|
file_content.append(file_line)
|
|
370
381
|
current_file = parse_file_content("\n".join(file_content))
|
|
371
|
-
|
|
382
|
+
if not seen_invoke_action:
|
|
383
|
+
add_content_entry(parsed_data["content"], "file", current_file)
|
|
372
384
|
in_file = False
|
|
373
385
|
current_file = {}
|
|
374
386
|
file_content = []
|
|
@@ -381,6 +393,7 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
381
393
|
if in_invoke_action:
|
|
382
394
|
parsed_data["errors"].append("Nested <invoke_action> tags")
|
|
383
395
|
in_invoke_action = True
|
|
396
|
+
seen_invoke_action = True
|
|
384
397
|
open_tags.append("invoke_action")
|
|
385
398
|
current_action = {
|
|
386
399
|
"agent": None,
|
|
@@ -403,7 +416,7 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
403
416
|
if current_param_name:
|
|
404
417
|
current_action["parameters"][current_param_name] = "\n".join(
|
|
405
418
|
current_param_value
|
|
406
|
-
)
|
|
419
|
+
)
|
|
407
420
|
parsed_data["actions"].append(current_action)
|
|
408
421
|
current_action = {}
|
|
409
422
|
current_param_name = None
|
|
@@ -411,9 +424,10 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
411
424
|
|
|
412
425
|
elif in_invoke_action and f"<{tp}parameter" in line:
|
|
413
426
|
if current_param_name:
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
427
|
+
param_value = "\n".join(current_param_value)
|
|
428
|
+
current_action["parameters"][current_param_name] = (
|
|
429
|
+
clean_parameter_value(param_value)
|
|
430
|
+
)
|
|
417
431
|
current_param_value = []
|
|
418
432
|
|
|
419
433
|
param_name_match = re.search(r'name\s*=\s*[\'"](\w+)[\'"]', line)
|
|
@@ -426,17 +440,19 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
426
440
|
r">(.*?)(?:</" + tp + "parameter>|$)", line
|
|
427
441
|
)
|
|
428
442
|
if content_after_open:
|
|
429
|
-
initial_content = content_after_open.group(1)
|
|
443
|
+
initial_content = content_after_open.group(1)
|
|
430
444
|
if initial_content:
|
|
431
445
|
current_param_value.append(initial_content)
|
|
432
446
|
|
|
433
447
|
# Check if parameter closes on same line
|
|
434
448
|
if f"</{tp}parameter>" in line:
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
449
|
+
param_value = "\n".join(current_param_value)
|
|
450
|
+
current_action["parameters"][current_param_name] = (
|
|
451
|
+
clean_parameter_value(param_value)
|
|
452
|
+
)
|
|
438
453
|
current_param_name = None
|
|
439
454
|
current_param_value = []
|
|
455
|
+
|
|
440
456
|
if "parameter" in open_tags:
|
|
441
457
|
open_tags.remove("parameter")
|
|
442
458
|
elif line.endswith("/>"):
|
|
@@ -451,25 +467,30 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
451
467
|
if f"</{tp}parameter>" in line:
|
|
452
468
|
# Handle content before closing tag on final line
|
|
453
469
|
content_before_close = re.sub(f"</{tp}parameter>.*", "", line)
|
|
454
|
-
if content_before_close
|
|
455
|
-
current_param_value.append(content_before_close
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
470
|
+
if content_before_close:
|
|
471
|
+
current_param_value.append(content_before_close)
|
|
472
|
+
param_value = "\n".join(current_param_value)
|
|
473
|
+
current_action["parameters"][current_param_name] = (
|
|
474
|
+
clean_parameter_value(param_value)
|
|
475
|
+
)
|
|
459
476
|
current_param_name = None
|
|
460
477
|
current_param_value = []
|
|
461
478
|
if "parameter" in open_tags:
|
|
462
479
|
open_tags.remove("parameter")
|
|
463
480
|
else:
|
|
464
|
-
current_param_value.append(line
|
|
481
|
+
current_param_value.append(line)
|
|
465
482
|
|
|
466
483
|
else:
|
|
467
|
-
|
|
484
|
+
# NOTE that we are intentionally ignoring all output text that occurs
|
|
485
|
+
# after any <invoke_action> tag. It has been told to never do this and
|
|
486
|
+
# if it does, then there is a good chance it is hallucinating responses
|
|
487
|
+
if not seen_invoke_action:
|
|
488
|
+
current_text.append(line)
|
|
468
489
|
|
|
469
490
|
if open_tags:
|
|
470
491
|
parsed_data["errors"].append(f"Unclosed tags: {', '.join(open_tags)}")
|
|
471
492
|
|
|
472
|
-
if in_file:
|
|
493
|
+
if in_file and not seen_invoke_action:
|
|
473
494
|
content = "\n".join(file_content)
|
|
474
495
|
# Add a status update for this
|
|
475
496
|
parsed_data["status_updates"].append(
|
|
@@ -481,9 +502,28 @@ def parse_orchestrator_response(response, last_chunk=False, tag_prefix=""):
|
|
|
481
502
|
if len(current_text) > 0:
|
|
482
503
|
add_content_entry(parsed_data["content"], "text", current_text)
|
|
483
504
|
|
|
505
|
+
# Final check - if there is no reasoning, then the LLM is not complying with the
|
|
506
|
+
# request and we should return an error
|
|
507
|
+
if check_reasoning and not parsed_data["reasoning"]:
|
|
508
|
+
parsed_data["errors"].append("No <t###_reasoning> tag found")
|
|
509
|
+
parsed_data["content"] = []
|
|
510
|
+
|
|
484
511
|
return parsed_data
|
|
485
512
|
|
|
486
513
|
|
|
514
|
+
def strip_text_after_invoke_action(text):
|
|
515
|
+
"""
|
|
516
|
+
Remove any text after the last </invoke_action> tag.
|
|
517
|
+
This is to prevent hallucinations from the LLM.
|
|
518
|
+
"""
|
|
519
|
+
# Find the last instance of </t\d+_invoke_action> regexp and remove everything after it.
|
|
520
|
+
matches = list(re.finditer(r"</t\d+_invoke_action>", text))
|
|
521
|
+
if matches:
|
|
522
|
+
last_match_end = matches[-1].end()
|
|
523
|
+
return text[:last_match_end]
|
|
524
|
+
return text
|
|
525
|
+
|
|
526
|
+
|
|
487
527
|
def remove_incomplete_tags_at_end(text):
|
|
488
528
|
"""If the end of the text is in the middle of a <tag> or </tag> then remove it."""
|
|
489
529
|
# remove any open tags at the end
|
|
@@ -555,6 +595,35 @@ def match_solace_topic(subscription: str, topic: str) -> bool:
|
|
|
555
595
|
)
|
|
556
596
|
|
|
557
597
|
|
|
598
|
+
def clean_parameter_value(param_value):
|
|
599
|
+
"""
|
|
600
|
+
Cleans a parameter value by:
|
|
601
|
+
1. Removing CDATA wrapper if present
|
|
602
|
+
2. Resolving XML entities like >, <, etc.
|
|
603
|
+
|
|
604
|
+
Parameters:
|
|
605
|
+
- param_value (str): The parameter value that might contain a CDATA wrapper
|
|
606
|
+
and/or XML entities
|
|
607
|
+
|
|
608
|
+
Returns:
|
|
609
|
+
- str: The cleaned parameter value
|
|
610
|
+
"""
|
|
611
|
+
if isinstance(param_value, str):
|
|
612
|
+
# Remove CDATA wrapper if present
|
|
613
|
+
cdata_match = re.match(r"\s*<!\[CDATA\[(.*?)\]\]>\s*$", param_value, re.DOTALL)
|
|
614
|
+
if cdata_match:
|
|
615
|
+
param_value = cdata_match.group(1)
|
|
616
|
+
|
|
617
|
+
# Resolve XML entities
|
|
618
|
+
param_value = param_value.replace("<", "<")
|
|
619
|
+
param_value = param_value.replace(">", ">")
|
|
620
|
+
param_value = param_value.replace("&", "&")
|
|
621
|
+
param_value = param_value.replace(""", '"')
|
|
622
|
+
param_value = param_value.replace("'", "'")
|
|
623
|
+
|
|
624
|
+
return param_value
|
|
625
|
+
|
|
626
|
+
|
|
558
627
|
def clean_text(text_array):
|
|
559
628
|
# Any leading blank lines are removed
|
|
560
629
|
while text_array and not text_array[0]:
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
default_options = {
|
|
2
|
+
"namespace": "",
|
|
3
|
+
"config_dir": "configs",
|
|
4
|
+
"module_dir": "modules",
|
|
5
|
+
"env_file": ".env",
|
|
6
|
+
"build_dir": "build",
|
|
7
|
+
"broker_type": "solace",
|
|
8
|
+
"broker_url": "ws://localhost:8008",
|
|
9
|
+
"broker_vpn": "default",
|
|
10
|
+
"broker_username": "default",
|
|
11
|
+
"broker_password": "default",
|
|
12
|
+
"container_engine": "docker",
|
|
13
|
+
"llm_model_name": "openai/gpt-4o",
|
|
14
|
+
"llm_endpoint_url": "https://api.openai.com/v1",
|
|
15
|
+
"llm_api_key": "",
|
|
16
|
+
"embedding_model_name": "openai/text-embedding-ada-002",
|
|
17
|
+
"embedding_endpoint_url": "https://api.openai.com/v1",
|
|
18
|
+
"embedding_api_key": "",
|
|
19
|
+
"embedding_service_enabled": False,
|
|
20
|
+
"built_in_agent": ["web_request"],
|
|
21
|
+
"file_service_provider": "volume",
|
|
22
|
+
"file_service_config": ["directory=/tmp/solace-agent-mesh"],
|
|
23
|
+
"env_var": [],
|
|
24
|
+
"rest_api_enabled": True,
|
|
25
|
+
"rest_api_server_input_port": "5050",
|
|
26
|
+
"rest_api_server_host": "127.0.0.1",
|
|
27
|
+
"rest_api_server_input_endpoint": "/api/v1/request",
|
|
28
|
+
"rest_api_gateway_name": "rest-api",
|
|
29
|
+
"webui_enabled": True,
|
|
30
|
+
"webui_listen_port": "5001",
|
|
31
|
+
"webui_host": "localhost",
|
|
32
|
+
"dev_mode": True,
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
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"
|