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.

Files changed (51) hide show
  1. solace_agent_mesh/agents/global/actions/plantuml_diagram.py +94 -36
  2. solace_agent_mesh/agents/global/actions/plotly_graph.py +48 -22
  3. solace_agent_mesh/cli/__init__.py +1 -1
  4. solace_agent_mesh/cli/commands/add/agent.py +1 -1
  5. solace_agent_mesh/cli/commands/add/copy_from_plugin.py +9 -7
  6. solace_agent_mesh/cli/commands/add/gateway.py +2 -2
  7. solace_agent_mesh/cli/commands/build.py +15 -0
  8. solace_agent_mesh/cli/commands/init/ai_provider_step.py +45 -28
  9. solace_agent_mesh/cli/commands/init/broker_step.py +1 -4
  10. solace_agent_mesh/cli/commands/init/check_if_already_done.py +1 -1
  11. solace_agent_mesh/cli/commands/init/create_config_file_step.py +8 -0
  12. solace_agent_mesh/cli/commands/init/init.py +20 -38
  13. solace_agent_mesh/cli/commands/init/web_init_step.py +32 -0
  14. solace_agent_mesh/cli/commands/plugin/build.py +52 -10
  15. solace_agent_mesh/cli/commands/plugin/create.py +3 -3
  16. solace_agent_mesh/cli/commands/run.py +2 -2
  17. solace_agent_mesh/cli/main.py +20 -8
  18. solace_agent_mesh/common/prompt_templates.py +1 -3
  19. solace_agent_mesh/common/utils.py +88 -19
  20. solace_agent_mesh/config_portal/__init__.py +0 -0
  21. solace_agent_mesh/config_portal/backend/__init__.py +0 -0
  22. solace_agent_mesh/config_portal/backend/common.py +35 -0
  23. solace_agent_mesh/config_portal/backend/server.py +233 -0
  24. solace_agent_mesh/config_portal/frontend/static/client/Solace_community_logo.png +0 -0
  25. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-b13CSm84.js +42 -0
  26. solace_agent_mesh/config_portal/frontend/static/client/assets/components-ZIfdTbrV.js +191 -0
  27. solace_agent_mesh/config_portal/frontend/static/client/assets/entry.client-DX1misIU.js +19 -0
  28. solace_agent_mesh/config_portal/frontend/static/client/assets/index-BJHAE5s4.js +17 -0
  29. solace_agent_mesh/config_portal/frontend/static/client/assets/manifest-c92a7808.js +1 -0
  30. solace_agent_mesh/config_portal/frontend/static/client/assets/root-BApq5dPK.js +10 -0
  31. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DX4gQ516.css +1 -0
  32. solace_agent_mesh/config_portal/frontend/static/client/favicon.ico +0 -0
  33. solace_agent_mesh/config_portal/frontend/static/client/index.html +7 -0
  34. solace_agent_mesh/configs/orchestrator.yaml +1 -1
  35. solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +4 -0
  36. solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +46 -16
  37. solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +19 -5
  38. solace_agent_mesh/orchestrator/orchestrator_main.py +11 -5
  39. solace_agent_mesh/orchestrator/orchestrator_prompt.py +78 -74
  40. solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +1 -1
  41. solace_agent_mesh/services/llm_service/components/llm_request_component.py +54 -31
  42. solace_agent_mesh/templates/rest-api-default-config.yaml +4 -2
  43. solace_agent_mesh/templates/solace-agent-mesh-default.yaml +9 -0
  44. solace_agent_mesh/templates/web-default-config.yaml +4 -2
  45. solace_agent_mesh-0.2.2.dist-info/METADATA +172 -0
  46. {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/RECORD +49 -35
  47. solace_agent_mesh/common/prompt_templates_unused_delete.py +0 -161
  48. solace_agent_mesh-0.2.0.dist-info/METADATA +0 -209
  49. {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/WHEEL +0 -0
  50. {solace_agent_mesh-0.2.0.dist-info → solace_agent_mesh-0.2.2.dist-info}/entry_points.txt +0 -0
  51. {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 log_error, apply_document_parsers, load_plugin
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 = (Config.load_config(os.path.join(plugin_path, Config.user_plugin_config_file)) or {}).get("solace_agent_mesh_plugin", {}).get("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 interface_name, interface_config in interface_gateway_configs.items():
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] = (interface_path, interface_gateway_config)
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(config, build_config_dir, abort, parsers, plugin_gateway_interfaces, build_specific_gateway):
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 = [agent.replace("-", "_") for agent in (load.get("agents") or [])]
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, abort, parsers, gateway_config_path, gateway, plugin_gateway_interfaces
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 = "THIS WILL IS ONLY HERE TO PREVENT GIT FROM IGNORING THIS DIRECTORY"
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", "__TEMPLATES_WILL_BE_HERE__"), "w", encoding="utf-8") as f:
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", "__INTERFACES_WILL_BE_HERE__"), "w", encoding="utf-8") as f:
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
- use_env, config_files, exclude_files, quick_build, ignore_build, force_build
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 use_env:
37
+ if not use_system_env:
38
38
  try:
39
39
  from dotenv import load_dotenv
40
40
 
@@ -66,11 +66,11 @@ def build(y, no_init):
66
66
 
67
67
  @cli.command()
68
68
  @click.option(
69
- "-e",
70
- "--use-env",
69
+ "-u",
70
+ "--use-system-env",
71
71
  default=False,
72
72
  is_flag=True,
73
- help="Loads the environment variables file defined in the config.",
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(use_env, files, skip, quick_build, ignore_build, force_build):
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
- use_env, list(files), list(skip), quick_build, ignore_build, force_build
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) -> HumanMessage:
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(response, last_chunk=False, tag_prefix=""):
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
- add_content_entry(parsed_data["content"], "file", current_file)
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
- add_content_entry(parsed_data["content"], "file", current_file)
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
- ).strip()
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
- current_action["parameters"][current_param_name] = "\n".join(
415
- current_param_value
416
- ).strip()
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).strip()
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
- current_action["parameters"][current_param_name] = "\n".join(
436
- current_param_value
437
- ).strip()
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.strip():
455
- current_param_value.append(content_before_close.strip())
456
- current_action["parameters"][current_param_name] = "\n".join(
457
- current_param_value
458
- ).strip()
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.strip())
481
+ current_param_value.append(line)
465
482
 
466
483
  else:
467
- current_text.append(line)
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 &gt;, &lt;, 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("&lt;", "<")
619
+ param_value = param_value.replace("&gt;", ">")
620
+ param_value = param_value.replace("&amp;", "&")
621
+ param_value = param_value.replace("&quot;", '"')
622
+ param_value = param_value.replace("&apos;", "'")
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"