solace-agent-mesh 1.1.0__py3-none-any.whl → 1.3.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/agent/adk/runner.py +18 -12
- solace_agent_mesh/agent/adk/services.py +3 -3
- solace_agent_mesh/agent/protocol/event_handlers.py +27 -21
- solace_agent_mesh/agent/sac/app.py +1 -1
- solace_agent_mesh/agent/sac/component.py +0 -1
- solace_agent_mesh/assets/docs/404.html +2 -2
- solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js → main.08d30374.js} +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/architecture/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/cli/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/gateways/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/orchestrator/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/concepts/plugins/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/debugging/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/deploy/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/deployment/observability/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/component-overview/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/configurations/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/installation/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/introduction/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/getting-started/quick-start/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-gateway-upgrade-to-0.3.0/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/migration-guides/a2a-upgrade-to-0.3.0/a2a-technical-migration-map/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/bedrock-agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/custom-agent/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/event-mesh-gateway/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mcp-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/mongodb-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rag-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/rest-gateway/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/slack-integration/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/tutorials/sql-database/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/artifact-management/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/audio-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/data-analysis-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/embeds/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/builtin-tools/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-agents/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/create-gateways/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/creating-service-providers/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/solace-ai-connector/index.html +2 -2
- solace_agent_mesh/assets/docs/docs/documentation/user-guide/structure/index.html +2 -2
- solace_agent_mesh/assets/docs/lunr-index-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/lunr-index.json +1 -1
- solace_agent_mesh/assets/docs/search-doc-1757433031159.json +1 -0
- solace_agent_mesh/assets/docs/search-doc.json +1 -1
- solace_agent_mesh/cli/__init__.py +1 -1
- solace_agent_mesh/cli/commands/add_cmd/agent_cmd.py +125 -48
- solace_agent_mesh/cli/commands/eval_cmd.py +14 -0
- solace_agent_mesh/cli/commands/init_cmd/__init__.py +53 -31
- solace_agent_mesh/cli/commands/init_cmd/database_step.py +91 -0
- solace_agent_mesh/cli/commands/init_cmd/env_step.py +19 -8
- solace_agent_mesh/cli/commands/init_cmd/orchestrator_step.py +80 -25
- solace_agent_mesh/cli/commands/init_cmd/web_init_step.py +32 -10
- solace_agent_mesh/cli/commands/init_cmd/webui_gateway_step.py +74 -15
- solace_agent_mesh/cli/commands/plugin_cmd/create_cmd.py +0 -2
- solace_agent_mesh/cli/commands/run_cmd.py +5 -3
- solace_agent_mesh/cli/utils.py +68 -12
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-vY5eu2lI.js +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/client-BeBkzgWW.js +25 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-Bjys1KQs.js +339 -0
- solace_agent_mesh/client/webui/frontend/static/assets/main-C03yrETa.css +1 -0
- solace_agent_mesh/client/webui/frontend/static/assets/vendor-CE0AeXyK.js +395 -0
- solace_agent_mesh/client/webui/frontend/static/auth-callback.html +3 -2
- solace_agent_mesh/client/webui/frontend/static/index.html +4 -3
- solace_agent_mesh/common/utils/embeds/resolver.py +1 -0
- solace_agent_mesh/config_portal/backend/common.py +2 -2
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-bFMKlzKf.js +98 -0
- solace_agent_mesh/config_portal/frontend/static/client/assets/{manifest-d845808d.js → manifest-89db7c30.js} +1 -1
- solace_agent_mesh/config_portal/frontend/static/client/index.html +1 -1
- solace_agent_mesh/evaluation/message_organizer.py +35 -56
- solace_agent_mesh/evaluation/run.py +26 -5
- solace_agent_mesh/evaluation/subscriber.py +35 -10
- solace_agent_mesh/evaluation/summary_builder.py +27 -34
- solace_agent_mesh/gateway/http_sse/ARCHITECTURE_GUIDE.md +676 -0
- solace_agent_mesh/gateway/http_sse/alembic/env.py +85 -0
- solace_agent_mesh/gateway/http_sse/alembic/script.py.mako +28 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/b1c2d3e4f5g6_add_database_indexes.py +83 -0
- solace_agent_mesh/gateway/http_sse/alembic/versions/d5b3f8f2e9a0_create_initial_database.py +58 -0
- solace_agent_mesh/gateway/http_sse/alembic.ini +147 -0
- solace_agent_mesh/gateway/http_sse/api/__init__.py +11 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/session_controller.py +355 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/task_controller.py +279 -0
- solace_agent_mesh/gateway/http_sse/api/controllers/user_controller.py +35 -0
- solace_agent_mesh/gateway/http_sse/api/dto/__init__.py +10 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/__init__.py +37 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/session_requests.py +49 -0
- solace_agent_mesh/gateway/http_sse/api/dto/requests/task_requests.py +66 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/__init__.py +43 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/session_responses.py +68 -0
- solace_agent_mesh/gateway/http_sse/api/dto/responses/task_responses.py +74 -0
- solace_agent_mesh/gateway/http_sse/app.py +31 -1
- solace_agent_mesh/gateway/http_sse/application/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/application/services/session_service.py +135 -0
- solace_agent_mesh/gateway/http_sse/component.py +224 -62
- solace_agent_mesh/gateway/http_sse/dependencies.py +142 -39
- solace_agent_mesh/gateway/http_sse/domain/entities/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/entities/session.py +90 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/domain/repositories/session_repository.py +54 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/dependency_injection/container.py +123 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/__init__.py +4 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_persistence_service.py +16 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/database_service.py +119 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence/models.py +31 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/persistence_service.py +12 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/__init__.py +3 -0
- solace_agent_mesh/gateway/http_sse/infrastructure/repositories/session_repository.py +174 -0
- solace_agent_mesh/gateway/http_sse/main.py +289 -85
- solace_agent_mesh/gateway/http_sse/routers/artifacts.py +121 -54
- solace_agent_mesh/gateway/http_sse/routers/config.py +3 -1
- solace_agent_mesh/gateway/http_sse/routers/tasks.py +83 -2
- solace_agent_mesh/gateway/http_sse/routers/visualization.py +7 -7
- solace_agent_mesh/gateway/http_sse/session_manager.py +64 -30
- solace_agent_mesh/gateway/http_sse/shared/__init__.py +9 -0
- solace_agent_mesh/gateway/http_sse/shared/auth_utils.py +29 -0
- solace_agent_mesh/gateway/http_sse/shared/enums.py +45 -0
- solace_agent_mesh/gateway/http_sse/shared/types.py +45 -0
- solace_agent_mesh/templates/shared_config.yaml +4 -5
- solace_agent_mesh/templates/webui.yaml +8 -10
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/METADATA +5 -3
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/RECORD +130 -91
- solace_agent_mesh/assets/docs/lunr-index-1756992446316.json +0 -1
- solace_agent_mesh/assets/docs/search-doc-1756992446316.json +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/authCallback-BmF2l6vg.js +0 -1
- solace_agent_mesh/client/webui/frontend/static/assets/client-D881Dttc.js +0 -49
- solace_agent_mesh/client/webui/frontend/static/assets/main-C0jZjYa8.js +0 -699
- solace_agent_mesh/client/webui/frontend/static/assets/main-CCeG324-.css +0 -1
- solace_agent_mesh/config_portal/frontend/static/client/assets/_index-Bym6YkMd.js +0 -98
- solace_agent_mesh/gateway/http_sse/routers/sessions.py +0 -85
- solace_agent_mesh/gateway/http_sse/routers/users.py +0 -59
- /solace_agent_mesh/assets/docs/assets/js/{main.a75ecc0d.js.LICENSE.txt → main.08d30374.js.LICENSE.txt} +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/WHEEL +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/entry_points.txt +0 -0
- {solace_agent_mesh-1.1.0.dist-info → solace_agent_mesh-1.3.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -1,17 +1,21 @@
|
|
|
1
|
-
import
|
|
1
|
+
import re
|
|
2
2
|
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
import click
|
|
3
5
|
import yaml
|
|
4
|
-
|
|
5
|
-
from ...utils import ask_if_not_provided, load_template, get_formatted_names
|
|
6
|
+
|
|
6
7
|
from config_portal.backend.common import DEFAULT_COMMUNICATION_TIMEOUT
|
|
7
8
|
|
|
9
|
+
from ...utils import ask_if_not_provided, get_formatted_names, load_template
|
|
10
|
+
|
|
8
11
|
ORCHESTRATOR_DEFAULTS = {
|
|
9
12
|
"agent_name": "OrchestratorAgent",
|
|
10
13
|
"supports_streaming": True,
|
|
11
14
|
"artifact_handling_mode": "reference",
|
|
12
15
|
"enable_embed_resolution": True,
|
|
13
16
|
"enable_artifact_content_instruction": True,
|
|
14
|
-
"
|
|
17
|
+
"enable_builtin_artifact_tools": {"enabled": True},
|
|
18
|
+
"enable_builtin_data_tools": {"enabled": True},
|
|
15
19
|
"artifact_service": {
|
|
16
20
|
"type": "filesystem",
|
|
17
21
|
"base_path": "/tmp/samv2",
|
|
@@ -83,16 +87,16 @@ def create_orchestrator_config(
|
|
|
83
87
|
options,
|
|
84
88
|
"session_service_type",
|
|
85
89
|
"Enter session service type",
|
|
86
|
-
|
|
90
|
+
"memory",
|
|
87
91
|
skip_interactive,
|
|
88
|
-
choices=["memory", "vertex_rag"],
|
|
92
|
+
choices=["sql", "memory", "vertex_rag"],
|
|
89
93
|
)
|
|
90
94
|
|
|
91
95
|
session_behavior = ask_if_not_provided(
|
|
92
96
|
options,
|
|
93
97
|
"session_service_behavior",
|
|
94
98
|
"Enter session service behavior",
|
|
95
|
-
|
|
99
|
+
"PERSISTENT",
|
|
96
100
|
skip_interactive,
|
|
97
101
|
choices=["PERSISTENT", "RUN_BASED"],
|
|
98
102
|
)
|
|
@@ -110,7 +114,7 @@ def create_orchestrator_config(
|
|
|
110
114
|
s3_bucket_name = None
|
|
111
115
|
s3_endpoint_url = None
|
|
112
116
|
s3_region = None
|
|
113
|
-
|
|
117
|
+
|
|
114
118
|
if artifact_type == "filesystem":
|
|
115
119
|
artifact_base_path = ask_if_not_provided(
|
|
116
120
|
options,
|
|
@@ -127,7 +131,7 @@ def create_orchestrator_config(
|
|
|
127
131
|
options["s3_endpoint_url"] = options["artifact_service_endpoint_url"]
|
|
128
132
|
if options.get("artifact_service_region"):
|
|
129
133
|
options["s3_region"] = options["artifact_service_region"]
|
|
130
|
-
|
|
134
|
+
|
|
131
135
|
s3_bucket_name = ask_if_not_provided(
|
|
132
136
|
options,
|
|
133
137
|
"s3_bucket_name",
|
|
@@ -304,18 +308,13 @@ def create_orchestrator_config(
|
|
|
304
308
|
if artifact_type == "filesystem":
|
|
305
309
|
artifact_base_path_line = f'base_path: "{artifact_base_path}"'
|
|
306
310
|
elif artifact_type == "s3":
|
|
307
|
-
s3_config_lines = [
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
if s3_region:
|
|
311
|
-
s3_config_lines.append(f'region: "{s3_region}"')
|
|
311
|
+
s3_config_lines = ["bucket_name: ${S3_BUCKET_NAME}"]
|
|
312
|
+
s3_config_lines.append("endpoint_url: ${S3_ENDPOINT_URL:-}")
|
|
313
|
+
s3_config_lines.append("region: ${S3_REGION}")
|
|
312
314
|
artifact_base_path_line = "\n ".join(s3_config_lines)
|
|
313
315
|
|
|
314
316
|
shared_replacements = {
|
|
315
|
-
"__DEFAULT_SESSION_SERVICE_TYPE__": session_type,
|
|
316
|
-
"__DEFAULT_SESSION_SERVICE_BEHAVIOR__": session_behavior,
|
|
317
317
|
"__DEFAULT_ARTIFACT_SERVICE_TYPE__": artifact_type,
|
|
318
|
-
"__DEFAULT_ARTIFACT_SERVICE_BASE_PATH_LINE__": artifact_base_path_line,
|
|
319
318
|
"__DEFAULT_ARTIFACT_SERVICE_SCOPE__": artifact_scope,
|
|
320
319
|
}
|
|
321
320
|
|
|
@@ -325,6 +324,18 @@ def create_orchestrator_config(
|
|
|
325
324
|
placeholder, str(value)
|
|
326
325
|
)
|
|
327
326
|
|
|
327
|
+
if not artifact_base_path_line:
|
|
328
|
+
modified_shared_content = re.sub(
|
|
329
|
+
r"\s*# __DEFAULT_ARTIFACT_SERVICE_BASE_PATH_LINE__.*",
|
|
330
|
+
"",
|
|
331
|
+
modified_shared_content,
|
|
332
|
+
)
|
|
333
|
+
else:
|
|
334
|
+
modified_shared_content = modified_shared_content.replace(
|
|
335
|
+
" # __DEFAULT_ARTIFACT_SERVICE_BASE_PATH_LINE__",
|
|
336
|
+
f" {artifact_base_path_line}",
|
|
337
|
+
)
|
|
338
|
+
|
|
328
339
|
shared_config_dest_path.parent.mkdir(parents=True, exist_ok=True)
|
|
329
340
|
with open(shared_config_dest_path, "w", encoding="utf-8") as f:
|
|
330
341
|
f.write(modified_shared_content)
|
|
@@ -366,8 +377,8 @@ def create_orchestrator_config(
|
|
|
366
377
|
try:
|
|
367
378
|
orchestrator_template_content = load_template("main_orchestrator.yaml")
|
|
368
379
|
|
|
369
|
-
|
|
370
|
-
|
|
380
|
+
formatted_name = get_formatted_names(options["agent_name"])
|
|
381
|
+
kebab_case_name = formatted_name.get("KEBAB_CASE_NAME")
|
|
371
382
|
|
|
372
383
|
deny_list_line = ""
|
|
373
384
|
if deny_list:
|
|
@@ -376,7 +387,7 @@ def create_orchestrator_config(
|
|
|
376
387
|
.strip()
|
|
377
388
|
.replace("'", '"')
|
|
378
389
|
)
|
|
379
|
-
deny_list_line = f"deny_list: {deny_list_yaml}
|
|
390
|
+
deny_list_line = f"deny_list: {deny_list_yaml}"
|
|
380
391
|
|
|
381
392
|
default_instruction = """You are the Orchestrator Agent within an AI agentic system. Your primary responsibilities are to:
|
|
382
393
|
1. Process tasks received from external sources via the system Gateway.
|
|
@@ -390,8 +401,40 @@ def create_orchestrator_config(
|
|
|
390
401
|
- You must then review the list of artifacts and return the ones that are important for the user by using the `signal_artifact_for_return` tool.
|
|
391
402
|
- Provide regular progress updates using `status_update` embed directives, especially before initiating any tool call."""
|
|
392
403
|
|
|
393
|
-
|
|
394
|
-
|
|
404
|
+
if session_type == "sql":
|
|
405
|
+
session_service_lines = [
|
|
406
|
+
f'type: "{session_type}"',
|
|
407
|
+
'database_url: "${ORCHESTRATOR_DATABASE_URL}"',
|
|
408
|
+
f'default_behavior: "{session_behavior}"',
|
|
409
|
+
]
|
|
410
|
+
session_service_block = "\n" + "\n".join(
|
|
411
|
+
[f" {line}" for line in session_service_lines]
|
|
412
|
+
)
|
|
413
|
+
|
|
414
|
+
data_dir = project_root / "data"
|
|
415
|
+
data_dir.mkdir(exist_ok=True)
|
|
416
|
+
orchestrator_db_file = data_dir / "orchestrator.db"
|
|
417
|
+
orchestrator_database_url = f"sqlite:///{orchestrator_db_file.resolve()}"
|
|
418
|
+
|
|
419
|
+
try:
|
|
420
|
+
env_path = project_root / ".env"
|
|
421
|
+
with open(env_path, "a", encoding="utf-8") as f:
|
|
422
|
+
f.write(
|
|
423
|
+
f'\nORCHESTRATOR_DATABASE_URL="{orchestrator_database_url}"\n'
|
|
424
|
+
)
|
|
425
|
+
click.echo(
|
|
426
|
+
f" Added ORCHESTRATOR_DATABASE_URL to .env: {orchestrator_database_url}"
|
|
427
|
+
)
|
|
428
|
+
except Exception as e:
|
|
429
|
+
click.echo(
|
|
430
|
+
click.style(
|
|
431
|
+
f"Warning: Could not add ORCHESTRATOR_DATABASE_URL to .env: {e}",
|
|
432
|
+
fg="yellow",
|
|
433
|
+
),
|
|
434
|
+
err=True,
|
|
435
|
+
)
|
|
436
|
+
else:
|
|
437
|
+
session_service_block = "*default_session_service"
|
|
395
438
|
|
|
396
439
|
orchestrator_replacements = {
|
|
397
440
|
"__NAMESPACE__": "${NAMESPACE}",
|
|
@@ -400,8 +443,8 @@ def create_orchestrator_config(
|
|
|
400
443
|
"__AGENT_NAME__": options["agent_name"],
|
|
401
444
|
"__LOG_FILE_NAME__": f"{kebab_case_name}.log",
|
|
402
445
|
"__INSTRUCTION__": default_instruction,
|
|
403
|
-
"__SESSION_SERVICE__":
|
|
404
|
-
"__ARTIFACT_SERVICE__":
|
|
446
|
+
"__SESSION_SERVICE__": session_service_block,
|
|
447
|
+
"__ARTIFACT_SERVICE__": "*default_artifact_service",
|
|
405
448
|
"__ARTIFACT_HANDLING_MODE__": artifact_handling_mode,
|
|
406
449
|
"__ENABLE_EMBED_RESOLUTION__": str(enable_embed_resolution).lower(),
|
|
407
450
|
"__ENABLE_ARTIFACT_CONTENT_INSTRUCTION__": str(
|
|
@@ -425,7 +468,6 @@ def create_orchestrator_config(
|
|
|
425
468
|
)
|
|
426
469
|
.strip()
|
|
427
470
|
.replace("'", '"'),
|
|
428
|
-
"__INTER_AGENT_COMMUNICATION_DENY_LIST_LINE__": deny_list_line,
|
|
429
471
|
"__INTER_AGENT_COMMUNICATION_TIMEOUT__": str(
|
|
430
472
|
inter_agent_communication_timeout
|
|
431
473
|
),
|
|
@@ -437,6 +479,19 @@ def create_orchestrator_config(
|
|
|
437
479
|
placeholder, str(value)
|
|
438
480
|
)
|
|
439
481
|
|
|
482
|
+
if deny_list:
|
|
483
|
+
modified_orchestrator_content = modified_orchestrator_content.replace(
|
|
484
|
+
"__INTER_AGENT_COMMUNICATION_DENY_LIST_LINE__",
|
|
485
|
+
deny_list_line,
|
|
486
|
+
)
|
|
487
|
+
else:
|
|
488
|
+
modified_orchestrator_content = re.sub(
|
|
489
|
+
r"^\s*__INTER_AGENT_COMMUNICATION_DENY_LIST_LINE__\n?$",
|
|
490
|
+
"",
|
|
491
|
+
modified_orchestrator_content,
|
|
492
|
+
flags=re.MULTILINE,
|
|
493
|
+
)
|
|
494
|
+
|
|
440
495
|
main_orchestrator_path.parent.mkdir(parents=True, exist_ok=True)
|
|
441
496
|
with open(main_orchestrator_path, "w", encoding="utf-8") as f:
|
|
442
497
|
f.write(modified_orchestrator_content)
|
|
@@ -1,9 +1,10 @@
|
|
|
1
|
-
import click
|
|
2
1
|
import multiprocessing
|
|
3
2
|
import sys
|
|
4
3
|
import webbrowser
|
|
5
|
-
from ...utils import wait_for_server
|
|
6
4
|
|
|
5
|
+
import click
|
|
6
|
+
|
|
7
|
+
from ...utils import wait_for_server
|
|
7
8
|
|
|
8
9
|
try:
|
|
9
10
|
from config_portal.backend.server import run_flask
|
|
@@ -19,7 +20,6 @@ except ImportError as e:
|
|
|
19
20
|
sys.exit(1)
|
|
20
21
|
|
|
21
22
|
|
|
22
|
-
|
|
23
23
|
def perform_web_init(current_cli_params: dict) -> dict:
|
|
24
24
|
"""
|
|
25
25
|
Launches the web-based configuration portal and updates params.
|
|
@@ -55,7 +55,7 @@ def perform_web_init(current_cli_params: dict) -> dict:
|
|
|
55
55
|
else:
|
|
56
56
|
click.echo(
|
|
57
57
|
click.style(
|
|
58
|
-
|
|
58
|
+
"Server did not start in time. Please check for errors and try again.",
|
|
59
59
|
fg="red",
|
|
60
60
|
)
|
|
61
61
|
)
|
|
@@ -67,12 +67,34 @@ def perform_web_init(current_cli_params: dict) -> dict:
|
|
|
67
67
|
init_gui_process.join()
|
|
68
68
|
if shared_config_from_web:
|
|
69
69
|
config_from_portal = dict(shared_config_from_web)
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
"
|
|
75
|
-
|
|
70
|
+
|
|
71
|
+
# Map web portal keys to CLI expected keys for backwards compatibility
|
|
72
|
+
key_mappings = {
|
|
73
|
+
"llm_api_key": "llm_service_api_key",
|
|
74
|
+
"llm_endpoint_url": "llm_service_endpoint",
|
|
75
|
+
"llm_model_name": "llm_service_model_name",
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
for old_key, new_key in key_mappings.items():
|
|
79
|
+
if old_key in config_from_portal and new_key not in config_from_portal:
|
|
80
|
+
config_from_portal[new_key] = config_from_portal[old_key]
|
|
81
|
+
|
|
82
|
+
# Handle planning and general model names with fallback to single model name
|
|
83
|
+
config_from_portal["llm_service_planning_model_name"] = (
|
|
84
|
+
config_from_portal.get("llm_service_planning_model_name")
|
|
85
|
+
or config_from_portal.get("llm_planning_model_name")
|
|
86
|
+
or config_from_portal.get("llm_model_name")
|
|
87
|
+
)
|
|
88
|
+
|
|
89
|
+
config_from_portal["llm_service_general_model_name"] = (
|
|
90
|
+
config_from_portal.get("llm_service_general_model_name")
|
|
91
|
+
or config_from_portal.get("llm_general_model_name")
|
|
92
|
+
or config_from_portal.get("llm_model_name")
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
# Clean up deprecated keys if new keys are present
|
|
96
|
+
config_from_portal.pop("llm_planning_model_name", None)
|
|
97
|
+
config_from_portal.pop("llm_general_model_name", None)
|
|
76
98
|
|
|
77
99
|
click.echo(
|
|
78
100
|
click.style("Configuration received from web portal.", fg="green")
|
|
@@ -3,14 +3,15 @@ from pathlib import Path
|
|
|
3
3
|
|
|
4
4
|
from ...utils import ask_if_not_provided, ask_yes_no_question, load_template
|
|
5
5
|
|
|
6
|
+
|
|
6
7
|
WEBUI_GATEWAY_DEFAULTS = {
|
|
7
8
|
"webui_frontend_welcome_message": "",
|
|
8
9
|
"webui_frontend_bot_name": "Solace Agent Mesh",
|
|
9
10
|
"webui_frontend_collect_feedback": False,
|
|
10
11
|
"webui_session_secret_key": "please_change_me_in",
|
|
11
12
|
"webui_fastapi_host": "127.0.0.1",
|
|
12
|
-
"webui_fastapi_port": 8000,
|
|
13
|
-
"webui_fastapi_https_port": 8443,
|
|
13
|
+
"webui_fastapi_port": 8000,
|
|
14
|
+
"webui_fastapi_https_port": 8443,
|
|
14
15
|
"webui_ssl_keyfile": "",
|
|
15
16
|
"webui_ssl_certfile": "",
|
|
16
17
|
"webui_ssl_keyfile_password": "",
|
|
@@ -39,6 +40,10 @@ def create_webui_gateway_config(
|
|
|
39
40
|
|
|
40
41
|
options["add_webui_gateway"] = add_gateway
|
|
41
42
|
|
|
43
|
+
if not add_gateway:
|
|
44
|
+
click.echo(click.style(" Skipping Web UI Gateway file creation.", fg="yellow"))
|
|
45
|
+
return True
|
|
46
|
+
|
|
42
47
|
options["webui_session_secret_key"] = ask_if_not_provided(
|
|
43
48
|
options,
|
|
44
49
|
"webui_session_secret_key",
|
|
@@ -69,9 +74,11 @@ def create_webui_gateway_config(
|
|
|
69
74
|
none_interactive=skip_interactive,
|
|
70
75
|
)
|
|
71
76
|
options["webui_fastapi_https_port"] = ask_if_not_provided(
|
|
72
|
-
options,
|
|
77
|
+
options,
|
|
78
|
+
"webui_fastapi_https_port",
|
|
79
|
+
"Enter Web UI FastAPI HTTPS Port",
|
|
73
80
|
default=default_values.get("webui_fastapi_https_port", 8443),
|
|
74
|
-
none_interactive=skip_interactive
|
|
81
|
+
none_interactive=skip_interactive,
|
|
75
82
|
)
|
|
76
83
|
options["webui_enable_embed_resolution"] = ask_if_not_provided(
|
|
77
84
|
options,
|
|
@@ -85,19 +92,26 @@ def create_webui_gateway_config(
|
|
|
85
92
|
is_bool=True,
|
|
86
93
|
)
|
|
87
94
|
options["webui_ssl_keyfile"] = ask_if_not_provided(
|
|
88
|
-
options,
|
|
95
|
+
options,
|
|
96
|
+
"webui_ssl_keyfile",
|
|
97
|
+
"Enter SSL Key File Path",
|
|
89
98
|
default=default_values.get("webui_ssl_keyfile", ""),
|
|
90
|
-
none_interactive=skip_interactive
|
|
99
|
+
none_interactive=skip_interactive,
|
|
91
100
|
)
|
|
92
101
|
options["webui_ssl_certfile"] = ask_if_not_provided(
|
|
93
|
-
options,
|
|
102
|
+
options,
|
|
103
|
+
"webui_ssl_certfile",
|
|
104
|
+
"Enter SSL Certificate File Path",
|
|
94
105
|
default=default_values.get("webui_ssl_certfile", ""),
|
|
95
|
-
none_interactive=skip_interactive
|
|
106
|
+
none_interactive=skip_interactive,
|
|
96
107
|
)
|
|
97
108
|
options["webui_ssl_keyfile_password"] = ask_if_not_provided(
|
|
98
|
-
options,
|
|
109
|
+
options,
|
|
110
|
+
"webui_ssl_keyfile_password",
|
|
111
|
+
"Enter SSL Key File Passphrase",
|
|
99
112
|
default=default_values.get("webui_ssl_keyfile_password", ""),
|
|
100
|
-
none_interactive=skip_interactive,
|
|
113
|
+
none_interactive=skip_interactive,
|
|
114
|
+
hide_input=True,
|
|
101
115
|
)
|
|
102
116
|
|
|
103
117
|
options["webui_frontend_welcome_message"] = ask_if_not_provided(
|
|
@@ -131,15 +145,58 @@ def create_webui_gateway_config(
|
|
|
131
145
|
is_bool=True,
|
|
132
146
|
)
|
|
133
147
|
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
148
|
+
session_type = ask_if_not_provided(
|
|
149
|
+
options,
|
|
150
|
+
"webui_session_service_type",
|
|
151
|
+
"Enter WebUI session service type",
|
|
152
|
+
"sql",
|
|
153
|
+
skip_interactive,
|
|
154
|
+
choices=["sql", "memory"],
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
session_behavior = ask_if_not_provided(
|
|
158
|
+
options,
|
|
159
|
+
"webui_session_service_behavior",
|
|
160
|
+
"Enter WebUI session service behavior",
|
|
161
|
+
"PERSISTENT",
|
|
162
|
+
skip_interactive,
|
|
163
|
+
choices=["PERSISTENT", "RUN_BASED"],
|
|
164
|
+
)
|
|
137
165
|
|
|
138
166
|
click.echo("Creating Web UI Gateway configuration file...")
|
|
139
167
|
destination_path = project_root / "configs" / "gateways" / "webui.yaml"
|
|
140
168
|
|
|
141
169
|
try:
|
|
142
170
|
template_content = load_template("webui.yaml")
|
|
171
|
+
|
|
172
|
+
if session_type == "sql":
|
|
173
|
+
session_service_lines = [
|
|
174
|
+
f'type: "{session_type}"',
|
|
175
|
+
f'database_url: "${{WEB_UI_GATEWAY_DATABASE_URL}}"',
|
|
176
|
+
f'default_behavior: "{session_behavior}"',
|
|
177
|
+
]
|
|
178
|
+
session_service_block = "\n" + "\n".join(
|
|
179
|
+
[f" {line}" for line in session_service_lines]
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
data_dir = project_root / "data"
|
|
183
|
+
data_dir.mkdir(exist_ok=True)
|
|
184
|
+
webui_db_file = data_dir / "webui_gateway.db"
|
|
185
|
+
webui_database_url = f"sqlite:///{webui_db_file.resolve()}"
|
|
186
|
+
|
|
187
|
+
try:
|
|
188
|
+
env_path = project_root / ".env"
|
|
189
|
+
with open(env_path, "a", encoding="utf-8") as f:
|
|
190
|
+
f.write(f'\nWEB_UI_GATEWAY_DATABASE_URL="{webui_database_url}"\n')
|
|
191
|
+
click.echo(f" Added WEB_UI_GATEWAY_DATABASE_URL to .env: {webui_database_url}")
|
|
192
|
+
except Exception as e:
|
|
193
|
+
click.echo(
|
|
194
|
+
click.style(f"Warning: Could not add WEB_UI_GATEWAY_DATABASE_URL to .env: {e}", fg="yellow"),
|
|
195
|
+
err=True,
|
|
196
|
+
)
|
|
197
|
+
else:
|
|
198
|
+
session_service_block = "*default_session_service"
|
|
199
|
+
|
|
143
200
|
replacements = {
|
|
144
201
|
"__FRONTEND_WELCOME_MESSAGE__": str(
|
|
145
202
|
options.get("webui_frontend_welcome_message", "")
|
|
@@ -150,11 +207,13 @@ def create_webui_gateway_config(
|
|
|
150
207
|
"__FRONTEND_COLLECT_FEEDBACK__": str(
|
|
151
208
|
options.get("webui_frontend_collect_feedback", False)
|
|
152
209
|
).lower(),
|
|
210
|
+
"__SESSION_SERVICE__": session_service_block,
|
|
153
211
|
}
|
|
154
212
|
|
|
155
213
|
modified_content = template_content
|
|
156
214
|
for placeholder, value in replacements.items():
|
|
157
|
-
|
|
215
|
+
if value is not None:
|
|
216
|
+
modified_content = modified_content.replace(placeholder, str(value))
|
|
158
217
|
|
|
159
218
|
destination_path.parent.mkdir(parents=True, exist_ok=True)
|
|
160
219
|
with open(destination_path, "w", encoding="utf-8") as f:
|
|
@@ -164,7 +223,7 @@ def create_webui_gateway_config(
|
|
|
164
223
|
return True
|
|
165
224
|
|
|
166
225
|
except FileNotFoundError:
|
|
167
|
-
click.echo(click.style(
|
|
226
|
+
click.echo(click.style("Error: Template file not found.", fg="red"), err=True)
|
|
168
227
|
return False
|
|
169
228
|
except IOError as e:
|
|
170
229
|
click.echo(
|
|
@@ -18,12 +18,10 @@ DEFAULT_PLUGIN_VERSION = "0.1.0"
|
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def ensure_directory_exists(path: pathlib.Path):
|
|
21
|
-
"""Creates a directory if it doesn't exist."""
|
|
22
21
|
path.mkdir(parents=True, exist_ok=True)
|
|
23
22
|
|
|
24
23
|
|
|
25
24
|
def replace_placeholders(content: str, replacements: dict) -> str:
|
|
26
|
-
"""Replaces placeholders in a string."""
|
|
27
25
|
for placeholder, value in replacements.items():
|
|
28
26
|
content = content.replace(placeholder, str(value))
|
|
29
27
|
return content
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import click
|
|
2
1
|
import os
|
|
3
2
|
import sys
|
|
4
3
|
from pathlib import Path
|
|
5
|
-
|
|
4
|
+
|
|
5
|
+
import click
|
|
6
|
+
from dotenv import find_dotenv, load_dotenv
|
|
7
|
+
|
|
6
8
|
from cli.utils import error_exit
|
|
7
9
|
from solace_agent_mesh.common.utils.initializer import initialize
|
|
8
10
|
|
|
@@ -110,7 +112,7 @@ def run(files: tuple[str, ...], skip_files: tuple[str, ...], system_env: bool):
|
|
|
110
112
|
),
|
|
111
113
|
err=True,
|
|
112
114
|
)
|
|
113
|
-
|
|
115
|
+
sys.exit(1)
|
|
114
116
|
|
|
115
117
|
for filepath in configs_dir.rglob("*.yaml"):
|
|
116
118
|
if filepath.name.startswith("_") or filepath.name.startswith(
|
solace_agent_mesh/cli/utils.py
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
|
+
import importlib
|
|
1
2
|
import os
|
|
3
|
+
import re
|
|
2
4
|
from pathlib import Path
|
|
3
|
-
import
|
|
5
|
+
from time import sleep
|
|
6
|
+
|
|
4
7
|
import click
|
|
5
|
-
import re
|
|
6
8
|
import requests
|
|
7
|
-
from
|
|
9
|
+
from sqlalchemy import create_engine, event
|
|
8
10
|
|
|
9
11
|
|
|
10
12
|
def ask_yes_no_question(question: str, default=False) -> bool:
|
|
@@ -83,7 +85,7 @@ def load_template(name, parser=None, *args):
|
|
|
83
85
|
if not os.path.exists(template_file):
|
|
84
86
|
raise FileNotFoundError(f"Template file '{template_file}' does not exist.")
|
|
85
87
|
|
|
86
|
-
with open(template_file,
|
|
88
|
+
with open(template_file, encoding="utf-8") as f:
|
|
87
89
|
if parser:
|
|
88
90
|
file = parser(f.read(), *args)
|
|
89
91
|
else:
|
|
@@ -94,21 +96,23 @@ def load_template(name, parser=None, *args):
|
|
|
94
96
|
|
|
95
97
|
def get_formatted_names(name: str):
|
|
96
98
|
# Normalize separators
|
|
97
|
-
normalized = re.sub(r
|
|
99
|
+
normalized = re.sub(r"[\s\-_]+", "_", name.strip())
|
|
98
100
|
|
|
99
|
-
camel_case_split = re.sub(
|
|
100
|
-
|
|
101
|
+
camel_case_split = re.sub(
|
|
102
|
+
r"([a-z0-9])([A-Z])", r"\1_\2", normalized
|
|
103
|
+
) # fooBar -> foo_Bar
|
|
104
|
+
acronym_split = re.sub(
|
|
105
|
+
r"([A-Z]+)([A-Z][a-z])", r"\1_\2", camel_case_split
|
|
106
|
+
) # APIKey -> API_Key
|
|
101
107
|
|
|
102
|
-
raw_parts = [p for p in acronym_split.split(
|
|
108
|
+
raw_parts = [p for p in acronym_split.split("_") if p]
|
|
103
109
|
|
|
104
110
|
parts = [p.lower() for p in raw_parts]
|
|
105
111
|
|
|
106
112
|
# Spaced capitalized name:
|
|
107
113
|
# - If original was all caps, keep it all caps (API -> API)
|
|
108
114
|
# - Else capitalize normally
|
|
109
|
-
spaced_capitalized_parts = [
|
|
110
|
-
p if p.isupper() else p.capitalize() for p in raw_parts
|
|
111
|
-
]
|
|
115
|
+
spaced_capitalized_parts = [p if p.isupper() else p.capitalize() for p in raw_parts]
|
|
112
116
|
|
|
113
117
|
return {
|
|
114
118
|
"KEBAB_CASE_NAME": "-".join(parts),
|
|
@@ -192,6 +196,7 @@ def indent_multiline_string(
|
|
|
192
196
|
else:
|
|
193
197
|
return "\n".join(indentation + line for line in text.splitlines()).lstrip()
|
|
194
198
|
|
|
199
|
+
|
|
195
200
|
def wait_for_server(url, timeout=30):
|
|
196
201
|
start = 0
|
|
197
202
|
while start < timeout:
|
|
@@ -203,4 +208,55 @@ def wait_for_server(url, timeout=30):
|
|
|
203
208
|
pass
|
|
204
209
|
sleep(0.5)
|
|
205
210
|
start += 0.5
|
|
206
|
-
return False
|
|
211
|
+
return False
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def create_and_validate_database(database_url: str, db_name: str = "database") -> bool:
|
|
215
|
+
"""
|
|
216
|
+
Create and validate a database connection.
|
|
217
|
+
|
|
218
|
+
Args:
|
|
219
|
+
database_url (str): Database URL to validate
|
|
220
|
+
db_name (str): Descriptive name for logging purposes
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
bool: True if successful, raises exception if failed
|
|
224
|
+
"""
|
|
225
|
+
try:
|
|
226
|
+
# Handle SQLite file creation
|
|
227
|
+
if database_url.startswith("sqlite:///"):
|
|
228
|
+
db_file_path_str = database_url.replace("sqlite:///", "")
|
|
229
|
+
db_file_path = Path(db_file_path_str)
|
|
230
|
+
db_file_path.parent.mkdir(parents=True, exist_ok=True)
|
|
231
|
+
|
|
232
|
+
engine = create_engine(database_url)
|
|
233
|
+
|
|
234
|
+
@event.listens_for(engine, "connect")
|
|
235
|
+
def set_sqlite_pragma(dbapi_connection, connection_record):
|
|
236
|
+
cursor = dbapi_connection.cursor()
|
|
237
|
+
cursor.execute("PRAGMA foreign_keys=ON")
|
|
238
|
+
cursor.close()
|
|
239
|
+
elif database_url.startswith("postgresql"):
|
|
240
|
+
# Check if PostgreSQL driver is available
|
|
241
|
+
try:
|
|
242
|
+
import psycopg2
|
|
243
|
+
except ImportError:
|
|
244
|
+
raise ImportError(
|
|
245
|
+
"PostgreSQL support requires psycopg2. Install with: "
|
|
246
|
+
"pip install 'solace-agent-mesh[postgresql]'"
|
|
247
|
+
)
|
|
248
|
+
engine = create_engine(database_url)
|
|
249
|
+
else:
|
|
250
|
+
engine = create_engine(database_url)
|
|
251
|
+
|
|
252
|
+
with engine.connect() as connection:
|
|
253
|
+
pass
|
|
254
|
+
|
|
255
|
+
engine.dispose()
|
|
256
|
+
click.echo(click.style(f" {db_name} validation successful.", fg="green"))
|
|
257
|
+
return True
|
|
258
|
+
|
|
259
|
+
except Exception as e:
|
|
260
|
+
error_msg = f"Database connection failed for {db_name}: {e}"
|
|
261
|
+
click.echo(click.style(f" Error: {error_msg}", fg="red"), err=True)
|
|
262
|
+
raise ValueError(error_msg)
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{c as n}from"./client-BeBkzgWW.js";import{r as a,j as s}from"./vendor-CE0AeXyK.js";function c(){return a.useEffect(()=>{const r=window.location.hash.substring(1),e=new URLSearchParams(r),o=e.get("access_token"),t=e.get("refresh_token");o?(localStorage.setItem("access_token",o),t&&localStorage.setItem("refresh_token",t),window.location.href="/"):console.error("AuthCallback: No access token found in URL hash.")},[]),s.jsx("div",{children:"Loading..."})}n.createRoot(document.getElementById("root")).render(s.jsx(c,{}));
|