solace-agent-mesh 0.0.1__py3-none-any.whl → 0.1.0__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/__init__.py +0 -3
- solace_agent_mesh/agents/__init__.py +0 -0
- solace_agent_mesh/agents/base_agent_component.py +224 -0
- solace_agent_mesh/agents/global/__init__.py +0 -0
- solace_agent_mesh/agents/global/actions/__init__.py +0 -0
- solace_agent_mesh/agents/global/actions/agent_state_change.py +54 -0
- solace_agent_mesh/agents/global/actions/clear_history.py +32 -0
- solace_agent_mesh/agents/global/actions/convert_file_to_markdown.py +160 -0
- solace_agent_mesh/agents/global/actions/create_file.py +70 -0
- solace_agent_mesh/agents/global/actions/error_action.py +45 -0
- solace_agent_mesh/agents/global/actions/plantuml_diagram.py +93 -0
- solace_agent_mesh/agents/global/actions/plotly_graph.py +117 -0
- solace_agent_mesh/agents/global/actions/retrieve_file.py +51 -0
- solace_agent_mesh/agents/global/global_agent_component.py +38 -0
- solace_agent_mesh/agents/image_processing/__init__.py +0 -0
- solace_agent_mesh/agents/image_processing/actions/__init__.py +0 -0
- solace_agent_mesh/agents/image_processing/actions/create_image.py +75 -0
- solace_agent_mesh/agents/image_processing/actions/describe_image.py +115 -0
- solace_agent_mesh/agents/image_processing/image_processing_agent_component.py +23 -0
- solace_agent_mesh/agents/slack/__init__.py +1 -0
- solace_agent_mesh/agents/slack/actions/__init__.py +1 -0
- solace_agent_mesh/agents/slack/actions/post_message.py +177 -0
- solace_agent_mesh/agents/slack/slack_agent_component.py +59 -0
- solace_agent_mesh/agents/web_request/__init__.py +0 -0
- solace_agent_mesh/agents/web_request/actions/__init__.py +0 -0
- solace_agent_mesh/agents/web_request/actions/do_image_search.py +84 -0
- solace_agent_mesh/agents/web_request/actions/do_news_search.py +47 -0
- solace_agent_mesh/agents/web_request/actions/do_suggestion_search.py +34 -0
- solace_agent_mesh/agents/web_request/actions/do_web_request.py +134 -0
- solace_agent_mesh/agents/web_request/actions/download_file.py +69 -0
- solace_agent_mesh/agents/web_request/web_request_agent_component.py +33 -0
- solace_agent_mesh/cli/__init__.py +1 -0
- solace_agent_mesh/cli/commands/__init__.py +0 -0
- solace_agent_mesh/cli/commands/add/__init__.py +3 -0
- solace_agent_mesh/cli/commands/add/add.py +88 -0
- solace_agent_mesh/cli/commands/add/agent.py +110 -0
- solace_agent_mesh/cli/commands/add/copy_from_plugin.py +90 -0
- solace_agent_mesh/cli/commands/add/gateway.py +221 -0
- solace_agent_mesh/cli/commands/build.py +631 -0
- solace_agent_mesh/cli/commands/chat/__init__.py +3 -0
- solace_agent_mesh/cli/commands/chat/chat.py +361 -0
- solace_agent_mesh/cli/commands/config.py +29 -0
- solace_agent_mesh/cli/commands/init/__init__.py +3 -0
- solace_agent_mesh/cli/commands/init/ai_provider_step.py +76 -0
- solace_agent_mesh/cli/commands/init/broker_step.py +102 -0
- solace_agent_mesh/cli/commands/init/builtin_agent_step.py +88 -0
- solace_agent_mesh/cli/commands/init/check_if_already_done.py +13 -0
- solace_agent_mesh/cli/commands/init/create_config_file_step.py +52 -0
- solace_agent_mesh/cli/commands/init/create_other_project_files_step.py +96 -0
- solace_agent_mesh/cli/commands/init/file_service_step.py +73 -0
- solace_agent_mesh/cli/commands/init/init.py +114 -0
- solace_agent_mesh/cli/commands/init/project_structure_step.py +45 -0
- solace_agent_mesh/cli/commands/init/rest_api_step.py +50 -0
- solace_agent_mesh/cli/commands/init/web_ui_step.py +40 -0
- solace_agent_mesh/cli/commands/plugin/__init__.py +3 -0
- solace_agent_mesh/cli/commands/plugin/add.py +98 -0
- solace_agent_mesh/cli/commands/plugin/build.py +217 -0
- solace_agent_mesh/cli/commands/plugin/create.py +117 -0
- solace_agent_mesh/cli/commands/plugin/plugin.py +109 -0
- solace_agent_mesh/cli/commands/plugin/remove.py +71 -0
- solace_agent_mesh/cli/commands/run.py +68 -0
- solace_agent_mesh/cli/commands/visualizer.py +138 -0
- solace_agent_mesh/cli/config.py +81 -0
- solace_agent_mesh/cli/main.py +306 -0
- solace_agent_mesh/cli/utils.py +246 -0
- solace_agent_mesh/common/__init__.py +0 -0
- solace_agent_mesh/common/action.py +91 -0
- solace_agent_mesh/common/action_list.py +37 -0
- solace_agent_mesh/common/action_response.py +327 -0
- solace_agent_mesh/common/constants.py +3 -0
- solace_agent_mesh/common/mysql_database.py +40 -0
- solace_agent_mesh/common/postgres_database.py +79 -0
- solace_agent_mesh/common/prompt_templates.py +30 -0
- solace_agent_mesh/common/prompt_templates_unused_delete.py +161 -0
- solace_agent_mesh/common/stimulus_utils.py +152 -0
- solace_agent_mesh/common/time.py +24 -0
- solace_agent_mesh/common/utils.py +638 -0
- solace_agent_mesh/configs/agent_global.yaml +74 -0
- solace_agent_mesh/configs/agent_image_processing.yaml +82 -0
- solace_agent_mesh/configs/agent_slack.yaml +64 -0
- solace_agent_mesh/configs/agent_web_request.yaml +75 -0
- solace_agent_mesh/configs/conversation_to_file.yaml +56 -0
- solace_agent_mesh/configs/error_catcher.yaml +56 -0
- solace_agent_mesh/configs/monitor.yaml +0 -0
- solace_agent_mesh/configs/monitor_stim_and_errors_to_slack.yaml +106 -0
- solace_agent_mesh/configs/monitor_user_feedback.yaml +58 -0
- solace_agent_mesh/configs/orchestrator.yaml +241 -0
- solace_agent_mesh/configs/service_embedding.yaml +81 -0
- solace_agent_mesh/configs/service_llm.yaml +265 -0
- solace_agent_mesh/configs/visualize_websocket.yaml +55 -0
- solace_agent_mesh/gateway/__init__.py +0 -0
- solace_agent_mesh/gateway/components/__init__.py +0 -0
- solace_agent_mesh/gateway/components/gateway_base.py +41 -0
- solace_agent_mesh/gateway/components/gateway_input.py +265 -0
- solace_agent_mesh/gateway/components/gateway_output.py +289 -0
- solace_agent_mesh/gateway/identity/bamboohr_identity.py +18 -0
- solace_agent_mesh/gateway/identity/identity_base.py +10 -0
- solace_agent_mesh/gateway/identity/identity_provider.py +60 -0
- solace_agent_mesh/gateway/identity/no_identity.py +9 -0
- solace_agent_mesh/gateway/identity/passthru_identity.py +9 -0
- solace_agent_mesh/monitors/base_monitor_component.py +26 -0
- solace_agent_mesh/monitors/feedback/user_feedback_monitor.py +75 -0
- solace_agent_mesh/monitors/stim_and_errors/stim_and_error_monitor.py +560 -0
- solace_agent_mesh/orchestrator/__init__.py +0 -0
- solace_agent_mesh/orchestrator/action_manager.py +225 -0
- solace_agent_mesh/orchestrator/components/__init__.py +0 -0
- solace_agent_mesh/orchestrator/components/orchestrator_action_manager_timeout_component.py +54 -0
- solace_agent_mesh/orchestrator/components/orchestrator_action_response_component.py +179 -0
- solace_agent_mesh/orchestrator/components/orchestrator_register_component.py +107 -0
- solace_agent_mesh/orchestrator/components/orchestrator_stimulus_processor_component.py +477 -0
- solace_agent_mesh/orchestrator/components/orchestrator_streaming_output_component.py +246 -0
- solace_agent_mesh/orchestrator/orchestrator_main.py +166 -0
- solace_agent_mesh/orchestrator/orchestrator_prompt.py +410 -0
- solace_agent_mesh/services/__init__.py +0 -0
- solace_agent_mesh/services/authorization/providers/base_authorization_provider.py +56 -0
- solace_agent_mesh/services/bamboo_hr_service/__init__.py +3 -0
- solace_agent_mesh/services/bamboo_hr_service/bamboo_hr.py +182 -0
- solace_agent_mesh/services/common/__init__.py +4 -0
- solace_agent_mesh/services/common/auto_expiry.py +45 -0
- solace_agent_mesh/services/common/singleton.py +18 -0
- solace_agent_mesh/services/file_service/__init__.py +14 -0
- solace_agent_mesh/services/file_service/file_manager/__init__.py +0 -0
- solace_agent_mesh/services/file_service/file_manager/bucket_file_manager.py +149 -0
- solace_agent_mesh/services/file_service/file_manager/file_manager_base.py +162 -0
- solace_agent_mesh/services/file_service/file_manager/memory_file_manager.py +64 -0
- solace_agent_mesh/services/file_service/file_manager/volume_file_manager.py +106 -0
- solace_agent_mesh/services/file_service/file_service.py +432 -0
- solace_agent_mesh/services/file_service/file_service_constants.py +54 -0
- solace_agent_mesh/services/file_service/file_transformations.py +131 -0
- solace_agent_mesh/services/file_service/file_utils.py +322 -0
- solace_agent_mesh/services/file_service/transformers/__init__.py +5 -0
- solace_agent_mesh/services/history_service/__init__.py +3 -0
- solace_agent_mesh/services/history_service/history_providers/__init__.py +0 -0
- solace_agent_mesh/services/history_service/history_providers/base_history_provider.py +78 -0
- solace_agent_mesh/services/history_service/history_providers/memory_history_provider.py +167 -0
- solace_agent_mesh/services/history_service/history_providers/redis_history_provider.py +163 -0
- solace_agent_mesh/services/history_service/history_service.py +139 -0
- solace_agent_mesh/services/llm_service/components/llm_request_component.py +293 -0
- solace_agent_mesh/services/llm_service/components/llm_service_component_base.py +152 -0
- solace_agent_mesh/services/middleware_service/__init__.py +0 -0
- solace_agent_mesh/services/middleware_service/middleware_service.py +20 -0
- solace_agent_mesh/templates/action.py +38 -0
- solace_agent_mesh/templates/agent.py +29 -0
- solace_agent_mesh/templates/agent.yaml +70 -0
- solace_agent_mesh/templates/gateway-config-template.yaml +6 -0
- solace_agent_mesh/templates/gateway-default-config.yaml +28 -0
- solace_agent_mesh/templates/gateway-flows.yaml +81 -0
- solace_agent_mesh/templates/gateway-header.yaml +16 -0
- solace_agent_mesh/templates/gateway_base.py +15 -0
- solace_agent_mesh/templates/gateway_input.py +98 -0
- solace_agent_mesh/templates/gateway_output.py +71 -0
- solace_agent_mesh/templates/plugin-pyproject.toml +30 -0
- solace_agent_mesh/templates/rest-api-default-config.yaml +23 -0
- solace_agent_mesh/templates/rest-api-flows.yaml +80 -0
- solace_agent_mesh/templates/slack-default-config.yaml +9 -0
- solace_agent_mesh/templates/slack-flows.yaml +90 -0
- solace_agent_mesh/templates/solace-agent-mesh-default.yaml +77 -0
- solace_agent_mesh/templates/solace-agent-mesh-plugin-default.yaml +8 -0
- solace_agent_mesh/templates/web-default-config.yaml +5 -0
- solace_agent_mesh/templates/web-flows.yaml +86 -0
- solace_agent_mesh/tools/__init__.py +0 -0
- solace_agent_mesh/tools/components/__init__.py +0 -0
- solace_agent_mesh/tools/components/conversation_formatter.py +111 -0
- solace_agent_mesh/tools/components/file_resolver_component.py +58 -0
- solace_agent_mesh/tools/config/runtime_config.py +26 -0
- solace_agent_mesh-0.1.0.dist-info/METADATA +179 -0
- solace_agent_mesh-0.1.0.dist-info/RECORD +170 -0
- solace_agent_mesh-0.1.0.dist-info/entry_points.txt +3 -0
- solace_agent_mesh-0.0.1.dist-info/licenses/LICENSE.txt → solace_agent_mesh-0.1.0.dist-info/licenses/LICENSE +1 -2
- solace_agent_mesh-0.0.1.dist-info/METADATA +0 -51
- solace_agent_mesh-0.0.1.dist-info/RECORD +0 -5
- {solace_agent_mesh-0.0.1.dist-info → solace_agent_mesh-0.1.0.dist-info}/WHEEL +0 -0
|
@@ -0,0 +1,246 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import re
|
|
3
|
+
import click
|
|
4
|
+
import importlib
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
def get_cli_root_dir():
|
|
8
|
+
"""Get the path to the CLI root directory."""
|
|
9
|
+
# Get the directory of the current script
|
|
10
|
+
current_dir = os.path.dirname(os.path.abspath(__file__))
|
|
11
|
+
# Construct the root directory
|
|
12
|
+
return os.path.normpath(os.path.join(current_dir, ".."))
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
def merge_dicts(dict1, dict2):
|
|
16
|
+
"""Merge two dictionaries recursively."""
|
|
17
|
+
for key, value in dict2.items():
|
|
18
|
+
if key in dict1 and isinstance(dict1[key], dict) and isinstance(value, dict):
|
|
19
|
+
merge_dicts(dict1[key], value)
|
|
20
|
+
elif key in dict1 and isinstance(dict1[key], list) and isinstance(value, list):
|
|
21
|
+
# set concat arrays
|
|
22
|
+
dict1[key] = list(dict1[key] + value)
|
|
23
|
+
else:
|
|
24
|
+
# dict2 takes precedence
|
|
25
|
+
dict1[key] = value
|
|
26
|
+
return dict1
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
def remove_duplicate(array, id_fn):
|
|
30
|
+
"""Remove duplicates from an array based on a key function. Keeps the last occurrence."""
|
|
31
|
+
seen = set()
|
|
32
|
+
reversed_array = array[::-1]
|
|
33
|
+
deduplicated_array = [
|
|
34
|
+
x for x in reversed_array if not (id_fn(x) in seen or seen.add(id_fn(x)))
|
|
35
|
+
]
|
|
36
|
+
return deduplicated_array[::-1]
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def literal_format_template(template, literals):
|
|
40
|
+
for key, value in literals.items():
|
|
41
|
+
template = template.replace("{{" + key + "}}", value)
|
|
42
|
+
return template
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def load_template(name, format_pair={}):
|
|
46
|
+
"""Load a template file and format it with the given key-value pairs."""
|
|
47
|
+
# Construct the path to the template file using a relative path
|
|
48
|
+
template_file = os.path.normpath(
|
|
49
|
+
os.path.join(get_cli_root_dir(), "templates", name)
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
if not os.path.exists(template_file):
|
|
53
|
+
return None
|
|
54
|
+
|
|
55
|
+
with open(template_file, "r", encoding="utf-8") as f:
|
|
56
|
+
file = f.read()
|
|
57
|
+
|
|
58
|
+
file = literal_format_template(file, format_pair)
|
|
59
|
+
|
|
60
|
+
return file
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def extract_yaml_env_variables(yaml_content):
|
|
64
|
+
"""Get environment variables from a yaml file.
|
|
65
|
+
Env variables are annotated with the ${VAR}
|
|
66
|
+
"""
|
|
67
|
+
return re.findall(r"\${(\w+)}", yaml_content)
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
def get_display_path(path):
|
|
71
|
+
"""Get the display path of a file path."""
|
|
72
|
+
return path if os.path.isabs(path) else f"./{path}"
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
def log_error(message):
|
|
76
|
+
click.echo(click.style(message, fg="red"), err=True)
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def log_link(message):
|
|
80
|
+
click.echo(click.style(message, fg="blue"), err=False)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def log_success(message):
|
|
84
|
+
click.echo(click.style(message, fg="green"), err=False)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
def ask_yes_no_question(question: str, default=False) -> bool:
|
|
88
|
+
"""Ask a yes/no question and return the answer."""
|
|
89
|
+
return click.confirm(question, default=default)
|
|
90
|
+
|
|
91
|
+
|
|
92
|
+
def ask_question(question: str, default=None) -> str:
|
|
93
|
+
"""Ask a question and return the answer."""
|
|
94
|
+
return click.prompt(question, default=default)
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
def ask_choice_question(question: str, choices: list, default=None) -> str:
|
|
98
|
+
"""Ask a choice question and return the answer."""
|
|
99
|
+
return click.prompt(question, type=click.Choice(choices), default=default)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def ask_password(question: str, default=None) -> str:
|
|
103
|
+
"""Ask a password question and return the answer."""
|
|
104
|
+
return click.prompt(question, default=default, hide_input=True)
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
def ask_if_not_provided(
|
|
108
|
+
options,
|
|
109
|
+
key,
|
|
110
|
+
question,
|
|
111
|
+
default=None,
|
|
112
|
+
none_interactive=False,
|
|
113
|
+
choices=None,
|
|
114
|
+
hide_input=False,
|
|
115
|
+
):
|
|
116
|
+
"""
|
|
117
|
+
Ask a question if the key is not in the options.
|
|
118
|
+
Updates the options dictionary with the answer.
|
|
119
|
+
Returns the answer.
|
|
120
|
+
"""
|
|
121
|
+
if key not in options or options[key] is None:
|
|
122
|
+
if none_interactive:
|
|
123
|
+
options[key] = default
|
|
124
|
+
elif choices:
|
|
125
|
+
options[key] = ask_choice_question(question, choices, default=default)
|
|
126
|
+
elif hide_input:
|
|
127
|
+
options[key] = ask_password(question, default=default)
|
|
128
|
+
elif isinstance(default, bool):
|
|
129
|
+
options[key] = ask_yes_no_question(question, default=default)
|
|
130
|
+
else:
|
|
131
|
+
options[key] = ask_question(question, default=default)
|
|
132
|
+
return options[key]
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
def apply_document_parsers(file_content, parsers, meta={}):
|
|
136
|
+
for parser in parsers:
|
|
137
|
+
file_content = parser(file_content, meta)
|
|
138
|
+
return file_content
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def load_plugin(name, return_path_only=False):
|
|
142
|
+
"""Load a plugin by name.
|
|
143
|
+
|
|
144
|
+
Args:
|
|
145
|
+
name (str): The name of the plugin to load.
|
|
146
|
+
return_path_only (bool, optional): Whether to return only the path to the module.
|
|
147
|
+
|
|
148
|
+
Returns:
|
|
149
|
+
module: The loaded module.
|
|
150
|
+
module_path: The path to the module. (Or only the path if return_path_only is True)
|
|
151
|
+
"""
|
|
152
|
+
# Construct the path to the plugin directory using a relative path
|
|
153
|
+
try:
|
|
154
|
+
# Attempt to import the module
|
|
155
|
+
module = importlib.import_module(name)
|
|
156
|
+
module_path = module.__path__[0]
|
|
157
|
+
except ImportError:
|
|
158
|
+
if return_path_only:
|
|
159
|
+
return None
|
|
160
|
+
return None, None
|
|
161
|
+
|
|
162
|
+
if return_path_only:
|
|
163
|
+
return module_path
|
|
164
|
+
|
|
165
|
+
return module, module_path
|
|
166
|
+
|
|
167
|
+
|
|
168
|
+
def get_formatted_names(name: str):
|
|
169
|
+
name = name.strip()
|
|
170
|
+
parts = re.split(r"[\s_-]", name)
|
|
171
|
+
return {
|
|
172
|
+
"KEBAB_CASE_NAME": "-".join([word.lower() for word in parts]),
|
|
173
|
+
"HYPHENED_NAME": name,
|
|
174
|
+
"CAMEL_CASE_NAME": "".join([word.capitalize() for word in parts]),
|
|
175
|
+
"SNAKE_CASE_NAME": "_".join([word.lower() for word in parts]),
|
|
176
|
+
"SPACED_NAME": " ".join(parts),
|
|
177
|
+
"SNAKE_UPPER_CASE_NAME": "_".join([word.upper() for word in parts]),
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def find_last_list_item_indent(yaml_content):
|
|
182
|
+
"""
|
|
183
|
+
Finds the indentation of the last list item
|
|
184
|
+
Returns the number of spaces before the dash (-)
|
|
185
|
+
"""
|
|
186
|
+
lines = yaml_content.splitlines()
|
|
187
|
+
|
|
188
|
+
# Look for the last line starting with '-' by iterating in reverse
|
|
189
|
+
for line in reversed(lines):
|
|
190
|
+
stripped_line = line.lstrip()
|
|
191
|
+
if stripped_line.startswith('-'):
|
|
192
|
+
return len(line) - len(stripped_line)
|
|
193
|
+
|
|
194
|
+
#default to 0
|
|
195
|
+
return 0
|
|
196
|
+
|
|
197
|
+
|
|
198
|
+
def normalize_and_reindent_yaml(reference_yaml, yaml_content):
|
|
199
|
+
"""Given YAML content, adjust the indentation to the given target_dash_indent,
|
|
200
|
+
while preserving the relative indentation of the content.
|
|
201
|
+
"""
|
|
202
|
+
target_dash_indent = find_last_list_item_indent(reference_yaml)
|
|
203
|
+
|
|
204
|
+
lines = yaml_content.splitlines()
|
|
205
|
+
if not lines:
|
|
206
|
+
return ""
|
|
207
|
+
|
|
208
|
+
# Find the current dash indentation in the content
|
|
209
|
+
current_dash_indent = None
|
|
210
|
+
for line in lines:
|
|
211
|
+
if line.lstrip().startswith('-'):
|
|
212
|
+
current_dash_indent = len(line) - len(line.lstrip())
|
|
213
|
+
break
|
|
214
|
+
|
|
215
|
+
if current_dash_indent is None:
|
|
216
|
+
current_dash_indent = 0
|
|
217
|
+
|
|
218
|
+
# Calculate the indentation difference
|
|
219
|
+
indent_difference = target_dash_indent - current_dash_indent
|
|
220
|
+
|
|
221
|
+
# Apply the indentation difference to all lines
|
|
222
|
+
reindented_lines = []
|
|
223
|
+
for line in lines:
|
|
224
|
+
if not line.strip():
|
|
225
|
+
# Preserve empty lines
|
|
226
|
+
reindented_lines.append(line)
|
|
227
|
+
else:
|
|
228
|
+
current_indent = len(line) - len(line.lstrip())
|
|
229
|
+
#prevent negative indent
|
|
230
|
+
new_indent = max(0, current_indent + indent_difference)
|
|
231
|
+
reindented_lines.append(' ' * new_indent + line.lstrip())
|
|
232
|
+
|
|
233
|
+
reindented_lines.append('\n')
|
|
234
|
+
|
|
235
|
+
return '\n'.join(reindented_lines)
|
|
236
|
+
|
|
237
|
+
def get_all_cases(name: str):
|
|
238
|
+
name = name.strip()
|
|
239
|
+
parts = re.split(r"[\s_-]", name)
|
|
240
|
+
return {
|
|
241
|
+
"KEBAB_CASE": "-".join([word.lower() for word in parts]),
|
|
242
|
+
"CAMEL_CASE": "".join([word.capitalize() for word in parts]),
|
|
243
|
+
"SNAKE_CASE": "_".join([word.lower() for word in parts]),
|
|
244
|
+
"SPACED": " ".join(parts),
|
|
245
|
+
"SNAKE_UPPER_CASE": "_".join([word.upper() for word in parts]),
|
|
246
|
+
}
|
|
File without changes
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
from abc import ABC, abstractmethod
|
|
2
|
+
|
|
3
|
+
from .action_response import ActionResponse
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Action(ABC):
|
|
7
|
+
|
|
8
|
+
def __init__(self, attributes, agent=None, config_fn=None, **kwargs):
|
|
9
|
+
self.validate_attributes(attributes)
|
|
10
|
+
self.long_description = attributes.get(
|
|
11
|
+
"long_description", attributes.get("prompt_directive", "<unspecified>")
|
|
12
|
+
)
|
|
13
|
+
self._prompt_directive = attributes.get("prompt_directive")
|
|
14
|
+
self._name = attributes.get("name")
|
|
15
|
+
self._params = attributes.get("params")
|
|
16
|
+
self._disabled = attributes.get("disabled", False)
|
|
17
|
+
self._examples = attributes.get("examples", [])
|
|
18
|
+
self._required_scopes = attributes.get("required_scopes", [])
|
|
19
|
+
self._config_fn = config_fn
|
|
20
|
+
self.agent = agent
|
|
21
|
+
self.kwargs = kwargs
|
|
22
|
+
|
|
23
|
+
@property
|
|
24
|
+
def name(self):
|
|
25
|
+
return self._name
|
|
26
|
+
|
|
27
|
+
@property
|
|
28
|
+
def disabled(self):
|
|
29
|
+
return self._disabled
|
|
30
|
+
|
|
31
|
+
@property
|
|
32
|
+
def examples(self):
|
|
33
|
+
return self._examples
|
|
34
|
+
|
|
35
|
+
@property
|
|
36
|
+
def required_scopes(self):
|
|
37
|
+
return self._required_scopes
|
|
38
|
+
|
|
39
|
+
def set_agent(self, agent):
|
|
40
|
+
self.agent = agent
|
|
41
|
+
|
|
42
|
+
def fix_scopes(self, search_value, replace_value):
|
|
43
|
+
self._required_scopes = [
|
|
44
|
+
scope.replace(search_value, replace_value)
|
|
45
|
+
for scope in self._required_scopes
|
|
46
|
+
]
|
|
47
|
+
|
|
48
|
+
def get_agent(self):
|
|
49
|
+
return self.agent
|
|
50
|
+
|
|
51
|
+
def set_config_fn(self, config_fn):
|
|
52
|
+
self._config_fn = config_fn
|
|
53
|
+
|
|
54
|
+
def get_config(self, key=None, default=None):
|
|
55
|
+
if self._config_fn:
|
|
56
|
+
return self._config_fn(key, default)
|
|
57
|
+
return default
|
|
58
|
+
|
|
59
|
+
def get_prompt_summary(self, prefix="") -> dict:
|
|
60
|
+
if self.disabled:
|
|
61
|
+
return None
|
|
62
|
+
summary = {}
|
|
63
|
+
action_name = self._name
|
|
64
|
+
summary[action_name] = {
|
|
65
|
+
"desc": self._prompt_directive,
|
|
66
|
+
"params": [f"{param['name']} ({param['desc']})" for param in self._params],
|
|
67
|
+
"examples": self._examples,
|
|
68
|
+
"required_scopes": self._required_scopes,
|
|
69
|
+
}
|
|
70
|
+
return summary
|
|
71
|
+
|
|
72
|
+
def validate_attributes(self, attributes):
|
|
73
|
+
if not attributes.get("name"):
|
|
74
|
+
raise ValueError("Actions must have a name")
|
|
75
|
+
if not attributes.get("prompt_directive"):
|
|
76
|
+
raise ValueError("Actions must have a prompt_directive")
|
|
77
|
+
if attributes.get("params"):
|
|
78
|
+
params = attributes.get("params")
|
|
79
|
+
for param in params:
|
|
80
|
+
if not param.get("name"):
|
|
81
|
+
raise ValueError(
|
|
82
|
+
"Action attributes params must have a descriptive name"
|
|
83
|
+
)
|
|
84
|
+
if not param.get("desc"):
|
|
85
|
+
raise ValueError("Action attributes params must have a description")
|
|
86
|
+
if not param.get("type"):
|
|
87
|
+
raise ValueError("Action attributes params must have a type")
|
|
88
|
+
|
|
89
|
+
@abstractmethod
|
|
90
|
+
def invoke(self, params, meta={}) -> ActionResponse:
|
|
91
|
+
raise NotImplementedError("Invoke method must be implemented in subclass")
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
from .action import Action
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ActionList:
|
|
5
|
+
|
|
6
|
+
def __init__(self, actions_classes, **kwargs):
|
|
7
|
+
self.actions: Action = []
|
|
8
|
+
self.actions_map = {}
|
|
9
|
+
for action_class in actions_classes:
|
|
10
|
+
action = action_class(**kwargs)
|
|
11
|
+
self.actions.append(action)
|
|
12
|
+
self.actions_map[action.name] = action
|
|
13
|
+
|
|
14
|
+
def add_action(self, action):
|
|
15
|
+
self.actions.append(action)
|
|
16
|
+
self.actions_map[action.name] = action
|
|
17
|
+
|
|
18
|
+
def set_agent(self, agent):
|
|
19
|
+
for action in self.actions:
|
|
20
|
+
action.set_agent(agent)
|
|
21
|
+
|
|
22
|
+
def fix_scopes(self, search_value, replace_value):
|
|
23
|
+
for action in self.actions:
|
|
24
|
+
action.fix_scopes(search_value, replace_value)
|
|
25
|
+
|
|
26
|
+
def set_config_fn(self, config_fn):
|
|
27
|
+
for action in self.actions:
|
|
28
|
+
action.set_config_fn(config_fn)
|
|
29
|
+
|
|
30
|
+
def get_prompt_summary(self, prefix="") -> dict:
|
|
31
|
+
summary = []
|
|
32
|
+
for action in self.actions:
|
|
33
|
+
summary.append(action.get_prompt_summary(prefix))
|
|
34
|
+
return summary
|
|
35
|
+
|
|
36
|
+
def get_action(self, name):
|
|
37
|
+
return self.actions_map.get(name)
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
"""This is the definition of responses for the actions of the system."""
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class RagMatch:
|
|
5
|
+
|
|
6
|
+
def __init__(self, text: str, link: str = None, heading: str = None):
|
|
7
|
+
self._text: str = text
|
|
8
|
+
self._link: str = link
|
|
9
|
+
self._heading: str = heading
|
|
10
|
+
|
|
11
|
+
@property
|
|
12
|
+
def text(self) -> str:
|
|
13
|
+
return self._text
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def link(self) -> str:
|
|
17
|
+
return self._link
|
|
18
|
+
|
|
19
|
+
@property
|
|
20
|
+
def heading(self) -> str:
|
|
21
|
+
return self._headings
|
|
22
|
+
|
|
23
|
+
def to_dict(self) -> dict:
|
|
24
|
+
return {
|
|
25
|
+
"text": self._text,
|
|
26
|
+
"link": self._link,
|
|
27
|
+
"heading": self._heading,
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
class InlineFile:
|
|
32
|
+
|
|
33
|
+
def __init__(self, content: str, name: str, **kwargs):
|
|
34
|
+
if type(content) != str:
|
|
35
|
+
raise ValueError("InlineFile content must be a string")
|
|
36
|
+
self._content: str = content
|
|
37
|
+
self._name: str = name
|
|
38
|
+
self._kwargs: dict = kwargs
|
|
39
|
+
|
|
40
|
+
@property
|
|
41
|
+
def content(self) -> str:
|
|
42
|
+
return self._content
|
|
43
|
+
|
|
44
|
+
@property
|
|
45
|
+
def name(self) -> str:
|
|
46
|
+
return self._name
|
|
47
|
+
|
|
48
|
+
@property
|
|
49
|
+
def kwargs(self) -> dict:
|
|
50
|
+
return self._kwargs
|
|
51
|
+
|
|
52
|
+
def to_dict(self) -> dict:
|
|
53
|
+
return {
|
|
54
|
+
"data": self._content,
|
|
55
|
+
"name": self._name,
|
|
56
|
+
"file_size": len(self._content.encode()),
|
|
57
|
+
"mime_type": "text/plain",
|
|
58
|
+
**self._kwargs,
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
class WithContextQuery:
|
|
63
|
+
|
|
64
|
+
def __init__(
|
|
65
|
+
self, query: str, context_type: str, context: str = None, since: str = None
|
|
66
|
+
):
|
|
67
|
+
self._query: str = query
|
|
68
|
+
self._context_type: str = context_type
|
|
69
|
+
self._context: str = context
|
|
70
|
+
self._since: str = since
|
|
71
|
+
|
|
72
|
+
@property
|
|
73
|
+
def query(self) -> str:
|
|
74
|
+
return self._query
|
|
75
|
+
|
|
76
|
+
@property
|
|
77
|
+
def context(self) -> str:
|
|
78
|
+
return self._context
|
|
79
|
+
|
|
80
|
+
@property
|
|
81
|
+
def context_type(self) -> str:
|
|
82
|
+
return self._context_type
|
|
83
|
+
|
|
84
|
+
@property
|
|
85
|
+
def since(self) -> dict:
|
|
86
|
+
return self._since
|
|
87
|
+
|
|
88
|
+
def to_dict(self) -> dict:
|
|
89
|
+
return {
|
|
90
|
+
"query": self._query,
|
|
91
|
+
"context_type": self._context_type,
|
|
92
|
+
"context": self._context,
|
|
93
|
+
"since": self._since,
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
|
|
97
|
+
class RagResponse:
|
|
98
|
+
|
|
99
|
+
def __init__(
|
|
100
|
+
self, data_source: str, matches: list[RagMatch], query: str, prompt: str = None
|
|
101
|
+
):
|
|
102
|
+
self._data_source: str = data_source
|
|
103
|
+
self._matches: list[RagMatch] = matches
|
|
104
|
+
self._query: str = query
|
|
105
|
+
self._prompt: str = prompt
|
|
106
|
+
|
|
107
|
+
@property
|
|
108
|
+
def data_source(self) -> str:
|
|
109
|
+
return self._data_source
|
|
110
|
+
|
|
111
|
+
@property
|
|
112
|
+
def matches(self) -> list[RagMatch]:
|
|
113
|
+
return self._matches
|
|
114
|
+
|
|
115
|
+
@property
|
|
116
|
+
def query(self) -> str:
|
|
117
|
+
return self._query
|
|
118
|
+
|
|
119
|
+
@property
|
|
120
|
+
def prompt(self) -> str:
|
|
121
|
+
return self._prompt
|
|
122
|
+
|
|
123
|
+
def to_dict(self) -> dict:
|
|
124
|
+
return {
|
|
125
|
+
"data_source": self._data_source,
|
|
126
|
+
"matches": [match.to_dict() for match in self._matches],
|
|
127
|
+
"query": self._query,
|
|
128
|
+
"prompt": self._prompt,
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
class AgentStateChange:
|
|
133
|
+
|
|
134
|
+
def __init__(self, agent_name: str, new_state: str):
|
|
135
|
+
self._agent_name: str = agent_name
|
|
136
|
+
self._new_state: str = new_state
|
|
137
|
+
|
|
138
|
+
@property
|
|
139
|
+
def agent_name(self) -> str:
|
|
140
|
+
return self._agent_name
|
|
141
|
+
|
|
142
|
+
@property
|
|
143
|
+
def new_state(self) -> str:
|
|
144
|
+
return self._new_state
|
|
145
|
+
|
|
146
|
+
def to_dict(self) -> dict:
|
|
147
|
+
return {"agent_name": self._agent_name, "new_state": self._new_state}
|
|
148
|
+
|
|
149
|
+
|
|
150
|
+
class ErrorInfo:
|
|
151
|
+
|
|
152
|
+
def __init__(self, error_message: str):
|
|
153
|
+
self._error_message: str = error_message
|
|
154
|
+
|
|
155
|
+
@property
|
|
156
|
+
def error_message(self) -> str:
|
|
157
|
+
return self._error_message
|
|
158
|
+
|
|
159
|
+
def __str__(self) -> str:
|
|
160
|
+
return self._error_message
|
|
161
|
+
|
|
162
|
+
def to_dict(self) -> dict:
|
|
163
|
+
return {"error_message": self._error_message}
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class ActionResponse:
|
|
167
|
+
|
|
168
|
+
def __init__(
|
|
169
|
+
self,
|
|
170
|
+
message: any = None,
|
|
171
|
+
files: list[str] = None,
|
|
172
|
+
inline_files: list[InlineFile] = None,
|
|
173
|
+
clear_history: bool = False,
|
|
174
|
+
history_depth_to_keep: int = None,
|
|
175
|
+
error_info: ErrorInfo = None,
|
|
176
|
+
agent_state_change: AgentStateChange = None,
|
|
177
|
+
invoke_model_again: bool = False,
|
|
178
|
+
context_query: WithContextQuery = None,
|
|
179
|
+
is_async: bool = False,
|
|
180
|
+
async_response_id: str = None,
|
|
181
|
+
):
|
|
182
|
+
# Message to return - this could be a string or a slack blocks message
|
|
183
|
+
self._message: str = message
|
|
184
|
+
# Files to return - this is a list of temporary files to return
|
|
185
|
+
self._files: list[str] = files
|
|
186
|
+
# Inline files to return - this is a list of inline files to return
|
|
187
|
+
self._inline_files: list[InlineFile] = inline_files
|
|
188
|
+
# Clear history - this is a flag to clear the chat history
|
|
189
|
+
self._clear_history: bool = clear_history
|
|
190
|
+
# Clear history but keep depth - this is a flag to clear the chat history but keep
|
|
191
|
+
# the last N messages
|
|
192
|
+
self._history_depth_to_keep: int = history_depth_to_keep
|
|
193
|
+
# Error info - this is a dictionary of error information (error_message)
|
|
194
|
+
self._error_info: ErrorInfo = error_info
|
|
195
|
+
# Agent state change - this is a dictionary of agent state change
|
|
196
|
+
# information (agent_name, new_state)
|
|
197
|
+
self._agent_state_change: AgentStateChange = agent_state_change
|
|
198
|
+
# Invoke model again - this is a flag to indicate if the model should be
|
|
199
|
+
# invoked again with the same input
|
|
200
|
+
self._invoke_model_again: bool = invoke_model_again
|
|
201
|
+
# Context query - this contains the query and context type to be used in the next action
|
|
202
|
+
self._context_query: WithContextQuery = context_query
|
|
203
|
+
# action_list_id - identifier of the action_list that this action response is associated with
|
|
204
|
+
self._action_list_id: str = None
|
|
205
|
+
# action_idx - index of the action in the action_list that this action response is associated with
|
|
206
|
+
self._action_idx: int = None
|
|
207
|
+
# action_name - name of the action that this action response is associated with
|
|
208
|
+
self._action_name: str = None
|
|
209
|
+
# action_params - parameters of the action that this action response is associated with
|
|
210
|
+
self._action_params: dict = None
|
|
211
|
+
# is_async - indicates if this is an async response that will be delivered later
|
|
212
|
+
self._is_async: bool = is_async
|
|
213
|
+
# async_response_id - unique identifier for correlating async responses
|
|
214
|
+
self._async_response_id: str = async_response_id
|
|
215
|
+
|
|
216
|
+
@property
|
|
217
|
+
def message(self) -> any:
|
|
218
|
+
return self._message
|
|
219
|
+
|
|
220
|
+
@message.setter
|
|
221
|
+
def message(self, message: any):
|
|
222
|
+
self._message = message
|
|
223
|
+
|
|
224
|
+
@property
|
|
225
|
+
def files(self) -> list[str]:
|
|
226
|
+
return self._files
|
|
227
|
+
|
|
228
|
+
@property
|
|
229
|
+
def inline_files(self) -> list[InlineFile]:
|
|
230
|
+
return self._inline_files
|
|
231
|
+
|
|
232
|
+
@property
|
|
233
|
+
def clear_history(self) -> bool:
|
|
234
|
+
return self._clear_history
|
|
235
|
+
|
|
236
|
+
@property
|
|
237
|
+
def history_depth_to_keep(self) -> int:
|
|
238
|
+
return self._history_depth_to_keep
|
|
239
|
+
|
|
240
|
+
@property
|
|
241
|
+
def error_info(self) -> dict:
|
|
242
|
+
return self._error_info
|
|
243
|
+
|
|
244
|
+
@property
|
|
245
|
+
def agent_state_change(self) -> AgentStateChange:
|
|
246
|
+
return self._agent_state_change
|
|
247
|
+
|
|
248
|
+
@property
|
|
249
|
+
def invoke_model_again(self) -> bool:
|
|
250
|
+
return self._invoke_model_again
|
|
251
|
+
|
|
252
|
+
@property
|
|
253
|
+
def context_query(self) -> WithContextQuery:
|
|
254
|
+
return self._context_query
|
|
255
|
+
|
|
256
|
+
@property
|
|
257
|
+
def action_list_id(self) -> str:
|
|
258
|
+
return self._action_list_id
|
|
259
|
+
|
|
260
|
+
@property
|
|
261
|
+
def action_idx(self) -> int:
|
|
262
|
+
return self._action_idx
|
|
263
|
+
|
|
264
|
+
@property
|
|
265
|
+
def action_name(self) -> str:
|
|
266
|
+
return self._action_name
|
|
267
|
+
|
|
268
|
+
@property
|
|
269
|
+
def action_params(self) -> dict:
|
|
270
|
+
return self._action_params
|
|
271
|
+
|
|
272
|
+
@action_list_id.setter
|
|
273
|
+
def action_list_id(self, action_list_id: str):
|
|
274
|
+
self._action_list_id = action_list_id
|
|
275
|
+
|
|
276
|
+
@action_idx.setter
|
|
277
|
+
def action_idx(self, action_idx: int):
|
|
278
|
+
self._action_idx = action_idx
|
|
279
|
+
|
|
280
|
+
@action_name.setter
|
|
281
|
+
def action_name(self, action_name: str):
|
|
282
|
+
self._action_name = action_name
|
|
283
|
+
|
|
284
|
+
@action_params.setter
|
|
285
|
+
def action_params(self, action_params: dict):
|
|
286
|
+
self._action_params = action_params
|
|
287
|
+
|
|
288
|
+
@property
|
|
289
|
+
def is_async(self) -> bool:
|
|
290
|
+
return self._is_async
|
|
291
|
+
|
|
292
|
+
@property
|
|
293
|
+
def async_response_id(self) -> str:
|
|
294
|
+
return self._async_response_id
|
|
295
|
+
|
|
296
|
+
def to_dict(self) -> dict:
|
|
297
|
+
response = {}
|
|
298
|
+
if self._message:
|
|
299
|
+
response["message"] = self._message
|
|
300
|
+
if self._is_async:
|
|
301
|
+
response["is_async"] = True
|
|
302
|
+
response["async_response_id"] = self._async_response_id
|
|
303
|
+
if self._files:
|
|
304
|
+
# Files are already dictionary
|
|
305
|
+
response["files"] = self._files
|
|
306
|
+
if self._inline_files:
|
|
307
|
+
# Add to the files list
|
|
308
|
+
response["files"] = response.get("files", []) + [
|
|
309
|
+
inline_file.to_dict() for inline_file in self._inline_files
|
|
310
|
+
]
|
|
311
|
+
if self._clear_history:
|
|
312
|
+
response["clear_history"] = self._clear_history
|
|
313
|
+
if self._history_depth_to_keep:
|
|
314
|
+
response["history_depth_to_keep"] = self._history_depth_to_keep
|
|
315
|
+
if self._error_info:
|
|
316
|
+
response["error_info"] = self._error_info.to_dict()
|
|
317
|
+
if self._agent_state_change:
|
|
318
|
+
response["agent_state_change"] = self._agent_state_change.to_dict()
|
|
319
|
+
if self._invoke_model_again:
|
|
320
|
+
response["invoke_model_again"] = self._invoke_model_again
|
|
321
|
+
if self._context_query:
|
|
322
|
+
response["context_query"] = self._context_query.to_dict()
|
|
323
|
+
response["action_list_id"] = self._action_list_id
|
|
324
|
+
response["action_idx"] = self._action_idx
|
|
325
|
+
response["action_name"] = self._action_name
|
|
326
|
+
response["action_params"] = self._action_params
|
|
327
|
+
return response
|