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.

Files changed (73) hide show
  1. solace_agent_mesh/agents/global/actions/plantuml_diagram.py +9 -2
  2. solace_agent_mesh/agents/global/actions/plotly_graph.py +70 -46
  3. solace_agent_mesh/agents/web_request/actions/do_web_request.py +34 -33
  4. solace_agent_mesh/cli/__init__.py +1 -1
  5. solace_agent_mesh/cli/commands/add/copy_from_plugin.py +8 -6
  6. solace_agent_mesh/cli/commands/add/gateway.py +162 -9
  7. solace_agent_mesh/cli/commands/build.py +15 -1
  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/create_config_file_step.py +8 -0
  11. solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +52 -1
  12. solace_agent_mesh/cli/commands/init/init.py +50 -37
  13. solace_agent_mesh/cli/commands/plugin/build.py +60 -9
  14. solace_agent_mesh/cli/commands/run.py +2 -2
  15. solace_agent_mesh/cli/config.py +4 -0
  16. solace_agent_mesh/cli/main.py +14 -8
  17. solace_agent_mesh/cli/utils.py +7 -2
  18. solace_agent_mesh/common/constants.py +10 -0
  19. solace_agent_mesh/common/prompt_templates.py +1 -3
  20. solace_agent_mesh/common/utils.py +104 -30
  21. solace_agent_mesh/config_portal/__init__.py +0 -0
  22. solace_agent_mesh/config_portal/backend/__init__.py +0 -0
  23. solace_agent_mesh/config_portal/backend/common.py +35 -0
  24. solace_agent_mesh/config_portal/backend/server.py +233 -0
  25. solace_agent_mesh/config_portal/frontend/static/client/assets/_index-DRPGOzHj.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-8147e469.js +1 -0
  30. solace_agent_mesh/config_portal/frontend/static/client/assets/root-DgMDqKDc.js +10 -0
  31. solace_agent_mesh/config_portal/frontend/static/client/assets/root-hhS5izs8.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/configs/service_embedding.yaml +1 -1
  36. solace_agent_mesh/configs/service_llm.yaml +1 -1
  37. solace_agent_mesh/gateway/components/gateway_base.py +7 -1
  38. solace_agent_mesh/gateway/components/gateway_input.py +8 -5
  39. solace_agent_mesh/gateway/components/gateway_output.py +12 -3
  40. solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +4 -0
  41. solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +43 -12
  42. solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +19 -5
  43. solace_agent_mesh/orchestrator/orchestrator_main.py +11 -5
  44. solace_agent_mesh/orchestrator/orchestrator_prompt.py +184 -60
  45. solace_agent_mesh/services/file_service/file_service.py +5 -0
  46. solace_agent_mesh/services/file_service/file_service_constants.py +1 -1
  47. solace_agent_mesh/services/file_service/file_transformations.py +11 -1
  48. solace_agent_mesh/services/file_service/file_utils.py +2 -0
  49. solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +21 -46
  50. solace_agent_mesh/services/history_service/history_providers/file_history_provider.py +74 -0
  51. solace_agent_mesh/services/history_service/history_providers/index.py +40 -0
  52. solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +19 -156
  53. solace_agent_mesh/services/history_service/history_providers/mongodb_history_provider.py +66 -0
  54. solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +40 -140
  55. solace_agent_mesh/services/history_service/history_providers/sql_history_provider.py +93 -0
  56. solace_agent_mesh/services/history_service/history_service.py +315 -41
  57. solace_agent_mesh/services/history_service/long_term_memory/__init__.py +0 -0
  58. solace_agent_mesh/services/history_service/long_term_memory/long_term_memory.py +399 -0
  59. solace_agent_mesh/services/llm_service/components/llm_request_component.py +19 -0
  60. solace_agent_mesh/templates/gateway-config-template.yaml +2 -1
  61. solace_agent_mesh/templates/gateway-default-config.yaml +3 -3
  62. solace_agent_mesh/templates/plugin-gateway-default-config.yaml +29 -0
  63. solace_agent_mesh/templates/rest-api-default-config.yaml +2 -1
  64. solace_agent_mesh/templates/slack-default-config.yaml +1 -1
  65. solace_agent_mesh/templates/solace-agent-mesh-default.yaml +9 -0
  66. solace_agent_mesh/templates/web-default-config.yaml +2 -1
  67. solace_agent_mesh-0.2.1.dist-info/METADATA +172 -0
  68. {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/RECORD +71 -52
  69. solace_agent_mesh/common/prompt_templates_unused_delete.py +0 -161
  70. solace_agent_mesh-0.1.3.dist-info/METADATA +0 -208
  71. {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/WHEEL +0 -0
  72. {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/entry_points.txt +0 -0
  73. {solace_agent_mesh-0.1.3.dist-info → solace_agent_mesh-0.2.1.dist-info}/licenses/LICENSE +0 -0
@@ -21,6 +21,14 @@ def create_config_file_step(options, default_options, none_interactive, abort):
21
21
  builtin_agents = options.get("built_in_agent", [])
22
22
  for agent in builtin_agents_ref:
23
23
  agent["enabled"] = agent["name"] in builtin_agents or agent["name"] == "global"
24
+
25
+ # Set up the built-in services
26
+ builtin_services_ref = (
27
+ sam_config.get("solace_agent_mesh", {}).get("built_in", {}).get("services", [])
28
+ )
29
+ for service in builtin_services_ref:
30
+ if service["name"] == "embedding":
31
+ service["enabled"] = options.get("embedding_service_enabled", False)
24
32
 
25
33
  # Set up the project structure
26
34
  sam_config.get("solace_agent_mesh", {})["config_directory"] = options.get("config_dir")
@@ -17,6 +17,57 @@ def add_pair_to_file_if_not_exists(file_path, pairs):
17
17
  f.write(f"{key}{value}\n")
18
18
 
19
19
 
20
+ def update_or_add_pairs_to_file(file_path, pairs):
21
+ """
22
+ Updates existing key-value pairs in a file or adds them if they don't exist.
23
+
24
+ Args:
25
+ file_path (str): The path to the file to update
26
+ pairs (list): A list of (key, value) tuples to update or add
27
+ """
28
+ # Check if file exists
29
+ if os.path.exists(file_path):
30
+ with open(file_path, "r", encoding="utf-8") as f:
31
+ lines = f.readlines()
32
+ else:
33
+ lines = []
34
+
35
+ # Create a dictionary of key-value pairs for quick lookup
36
+ pair_dict = {key: value for key, value in pairs}
37
+ updated_keys = set()
38
+
39
+ # Process each line
40
+ new_lines = []
41
+ for line in lines:
42
+ line = line.rstrip()
43
+ if not line or line.startswith("#"):
44
+ # Keep comments and empty lines
45
+ new_lines.append(line)
46
+ continue
47
+
48
+ # Check if line contains any of our keys
49
+ found_key = None
50
+ for key in pair_dict:
51
+ if line.startswith(key + "=") or line.startswith(key + " ="):
52
+ found_key = key
53
+ updated_keys.add(key)
54
+ new_lines.append(f"{key}{pair_dict[key]}")
55
+ break
56
+
57
+ if not found_key:
58
+ # Keep lines that don't match our keys
59
+ new_lines.append(line)
60
+
61
+ # Add any new variables that weren't found
62
+ for key, value in pairs:
63
+ if key not in updated_keys:
64
+ new_lines.append(f"{key}{value}")
65
+
66
+ # Write the updated content back to the file
67
+ with open(file_path, "w", encoding="utf-8") as f:
68
+ f.write("\n".join(new_lines) + "\n")
69
+
70
+
20
71
  def create_other_project_files_step(options, default_options, none_interactive, abort):
21
72
  """
22
73
  Creates the other project files. i.e. .gitignore, .env, requirements.txt, etc.
@@ -92,5 +143,5 @@ def create_other_project_files_step(options, default_options, none_interactive,
92
143
  required_env_variables.append((key, f"={value}"))
93
144
 
94
145
  create_if_not_exists(options["env_file"], "")
95
- add_pair_to_file_if_not_exists(options["env_file"], required_env_variables)
146
+ update_or_add_pairs_to_file(options["env_file"], required_env_variables)
96
147
  add_gateway_command(options["rest_api_gateway_name"],["rest-api"])
@@ -9,45 +9,16 @@ from .create_config_file_step import create_config_file_step
9
9
  from .file_service_step import file_service_step
10
10
  from .project_structure_step import project_structure_step
11
11
  from .create_other_project_files_step import create_other_project_files_step
12
-
12
+ from solace_agent_mesh.config_portal.backend.server import run_flask
13
+ import click
14
+ import multiprocessing
15
+ import sys
16
+ import time
13
17
  from cli.utils import (
14
18
  log_error,
19
+ ask_yes_no_question,
15
20
  )
16
-
17
- default_options = {
18
- "namespace": "",
19
- "config_dir": "configs",
20
- "module_dir": "modules",
21
- "env_file": ".env",
22
- "build_dir": "build",
23
- "broker_type": "container",
24
- "broker_url": "ws://localhost:8008",
25
- "broker_vpn": "default",
26
- "broker_username": "default",
27
- "broker_password": "default",
28
- "container_engine": "docker",
29
- "llm_model_name": "openai/gpt-4o",
30
- "llm_endpoint_url": "https://api.openai.com/v1",
31
- "llm_api_key": "",
32
- "embedding_model_name": "openai/text-embedding-ada-002",
33
- "embedding_endpoint_url": "https://api.openai.com/v1",
34
- "embedding_api_key": "",
35
- "built_in_agent": [],
36
- "file_service_provider": "volume",
37
- "file_service_config": ["volume=/tmp/solace-agent-mesh"],
38
- "env_var": [],
39
- "rest_api_enabled": True,
40
- "rest_api_server_input_port": "5050",
41
- "rest_api_server_host": "127.0.0.1",
42
- "rest_api_server_input_endpoint": "/api/v1/request",
43
- "rest_api_gateway_name": "rest-api",
44
- "webui_enabled": True,
45
- "webui_listen_port": "5001",
46
- "webui_host": "127.0.0.1"
47
- }
48
- """
49
- Default options for the init command.
50
- """
21
+ from solace_agent_mesh.config_portal.backend.common import default_options
51
22
 
52
23
 
53
24
  def abort(message: str):
@@ -61,7 +32,6 @@ def init_command(options={}):
61
32
  """
62
33
  Initialize the Solace Agent Mesh application.
63
34
  """
64
- click.echo(click.style("Initializing Solace Agent Mesh", bold=True, fg="blue"))
65
35
  skip = False
66
36
  if "skip" in options and options["skip"]:
67
37
  skip = True
@@ -77,6 +47,49 @@ def init_command(options={}):
77
47
  ("", create_config_file_step),
78
48
  ("Setting up project", create_other_project_files_step),
79
49
  ]
50
+
51
+ check_if_already_done(options, default_options, skip, abort)
52
+
53
+ click.echo(click.style("Initializing Solace Agent Mesh", bold=True, fg="blue"))
54
+ use_web_based_init = ask_yes_no_question("Would you like to configure your project through a web interface in your browser?", True)
55
+
56
+ if use_web_based_init and not skip:
57
+
58
+ with multiprocessing.Manager() as manager:
59
+ # Create a shared configuration dictionary
60
+ shared_config = manager.dict()
61
+
62
+ # Start the Flask server with the shared config
63
+ init_gui_process = multiprocessing.Process(
64
+ target=run_flask,
65
+ args=("127.0.0.1", 5002, shared_config)
66
+ )
67
+ init_gui_process.start()
68
+
69
+ click.echo(click.style("Web configuration portal is running at http://127.0.0.1:5002", fg="green"))
70
+ click.echo("Complete the configuration in your browser to continue...")
71
+
72
+ # Wait for the Flask server to finish
73
+ init_gui_process.join()
74
+
75
+ # Get the configuration from the shared dictionary
76
+ if shared_config:
77
+ # Convert from manager.dict to regular dict
78
+ config_from_portal = dict(shared_config)
79
+ options.update(config_from_portal)
80
+ click.echo(click.style("Configuration received from portal", fg="green"))
81
+
82
+ #if web configuration portal is used, skip the steps that are already done
83
+ steps_if_web_setup_used = [
84
+ ("", create_config_file_step),
85
+ ("", create_other_project_files_step),
86
+ ]
87
+ steps = steps_if_web_setup_used
88
+ else:
89
+ click.echo(click.style("Web configuration failed, please try again.", fg="red"))
90
+ return
91
+
92
+
80
93
  non_hidden_steps_count = len([step for step in steps if step[0]])
81
94
 
82
95
  step = 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
 
@@ -11,7 +16,7 @@ def build_command():
11
16
  subprocess.check_call(["python", "-m", "build"])
12
17
 
13
18
 
14
- def get_all_plugin_gateway_interfaces(config, abort):
19
+ def get_all_plugin_gateway_interfaces(config, abort, return_plugin_config=False):
15
20
  plugins = config.get("plugins", [])
16
21
  gateway_interfaces = {}
17
22
 
@@ -27,10 +32,21 @@ def get_all_plugin_gateway_interfaces(config, abort):
27
32
  if not os.path.exists(interface_path):
28
33
  continue
29
34
 
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
+ )
45
+ interface_gateway_config = None
30
46
  # Ensuring flow and default pair exist
31
47
  interface_pairs = {}
32
48
  for file in os.listdir(interface_path):
33
- if file.endswith("-flows.yaml") :
49
+ if file.endswith("-flows.yaml"):
34
50
  name = file.split("-flows.yaml")[0]
35
51
  if name not in interface_pairs:
36
52
  interface_pairs[name] = []
@@ -41,15 +57,35 @@ def get_all_plugin_gateway_interfaces(config, abort):
41
57
  if name not in interface_pairs:
42
58
  interface_pairs[name] = []
43
59
  interface_pairs[name].append(file)
44
-
60
+
45
61
  for name, files in interface_pairs.items():
46
62
  if len(files) == 2:
47
- gateway_interfaces[name] = interface_path
48
-
63
+ if return_plugin_config:
64
+ for (
65
+ interface_name,
66
+ interface_config,
67
+ ) in interface_gateway_configs.items():
68
+ if interface_name == name.replace("-", "_"):
69
+ interface_gateway_config = interface_config
70
+ break
71
+ gateway_interfaces[name] = (
72
+ interface_path,
73
+ interface_gateway_config,
74
+ )
75
+ else:
76
+ gateway_interfaces[name] = interface_path
77
+
49
78
  return gateway_interfaces
50
79
 
51
80
 
52
- 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
+ ):
53
89
  plugins = config.get("plugins", [])
54
90
  plugins_overwrite_dir = os.path.join(build_config_dir, "..", "overwrites")
55
91
 
@@ -61,7 +97,9 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
61
97
  name = plugin.get("name")
62
98
  load_unspecified_files = plugin.get("load_unspecified_files", True)
63
99
  load = plugin.get("load", {})
64
- 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
+ ]
65
103
  gateways_to_load = load.get("gateways") or []
66
104
  overwrites_to_load = load.get("overwrites") or []
67
105
 
@@ -121,6 +159,14 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
121
159
  agent_config_content = apply_document_parsers(
122
160
  agent_config_content, parsers, meta
123
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
+
124
170
  # Write agent configuration to build directory
125
171
  agent_build_path = os.path.join(
126
172
  build_config_dir, "agent_" + agent_config
@@ -156,7 +202,12 @@ def build_plugins(config, build_config_dir, abort, parsers, plugin_gateway_inter
156
202
  for gateway in gateway_subdirs:
157
203
  if load_unspecified_files or gateway in gateway_dirs:
158
204
  build_specific_gateway(
159
- 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,
160
211
  )
161
212
 
162
213
  ####################
@@ -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
 
@@ -79,3 +79,7 @@ class Config:
79
79
  if os.path.exists(path):
80
80
  with open(path, "r", encoding="utf-8") as f:
81
81
  return yaml.load(f)
82
+
83
+ @staticmethod
84
+ def get_yaml_parser():
85
+ return yaml.load
@@ -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
 
@@ -211,15 +211,21 @@ def visualize(port, find_unused_port, host, use_env):
211
211
  )
212
212
  @click.option(
213
213
  "--embedding-model-name",
214
- help="Embedding model name to use",
214
+ help="Embedding model name to use (only used if embedding service is enabled)",
215
215
  )
216
216
  @click.option(
217
217
  "--embedding-endpoint-url",
218
- help="Embedding endpoint URL",
218
+ help="Embedding endpoint URL (only used if embedding service is enabled)",
219
219
  )
220
220
  @click.option(
221
221
  "--embedding-api-key",
222
- help="Embedding API Key",
222
+ help="Embedding API Key (only used if embedding service is enabled)",
223
+ )
224
+ @click.option(
225
+ "--embedding-service-enabled",
226
+ is_flag=True,
227
+ default=None,
228
+ help="Enable/disable Embedding Service for vector embeddings",
223
229
  )
224
230
  @click.option(
225
231
  "--built-in-agent",
@@ -42,7 +42,7 @@ def literal_format_template(template, literals):
42
42
  return template
43
43
 
44
44
 
45
- def load_template(name, format_pair={}):
45
+ def load_template(name, format_pair={}, parser=None):
46
46
  """Load a template file and format it with the given key-value pairs."""
47
47
  # Construct the path to the template file using a relative path
48
48
  template_file = os.path.normpath(
@@ -53,7 +53,10 @@ def load_template(name, format_pair={}):
53
53
  return None
54
54
 
55
55
  with open(template_file, "r", encoding="utf-8") as f:
56
- file = f.read()
56
+ if parser:
57
+ file = parser(f)
58
+ else:
59
+ file = f.read()
57
60
 
58
61
  file = literal_format_template(file, format_pair)
59
62
 
@@ -75,6 +78,8 @@ def get_display_path(path):
75
78
  def log_error(message):
76
79
  click.echo(click.style(message, fg="red"), err=True)
77
80
 
81
+ def log_warning(message):
82
+ click.echo(click.style(message, fg="yellow"), err=False)
78
83
 
79
84
  def log_link(message):
80
85
  click.echo(click.style(message, fg="blue"), err=False)
@@ -3,3 +3,13 @@ SOLACE_AGENT_MESH_SYSTEM_SESSION_ID = "solace_agent_mesh_system_session_id"
3
3
  DEFAULT_IDENTITY_KEY_FIELD = "identity"
4
4
 
5
5
  ORCHESTRATOR_COMPONENT_NAME = "orchestrator"
6
+
7
+ HISTORY_MEMORY_ROLE = "history"
8
+
9
+ HISTORY_ACTION_ROLE = "tool_call"
10
+
11
+ HISTORY_USER_ROLE = "user"
12
+
13
+ HISTORY_SYSTEM_ROLE = "system"
14
+
15
+ HISTORY_ASSISTANT_ROLE = "assistant"
@@ -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}