Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .env

This file was deleted.

31 changes: 31 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# ============================================================================
# LLM Provider Configuration (OpenAI-Compatible API)
# ============================================================================
# This project supports any OpenAI-compatible API provider.
# Configure BASE_URL, API_KEY, and MODEL_NAME based on your chosen provider.

# ----------------------------------------------------------------------------
# Option 1: OpenAI
# ----------------------------------------------------------------------------
BASE_URL=https://api.openai.com/v1
API_KEY=sk-your-openai-api-key-here
MODEL_NAME=gpt-4o

# ----------------------------------------------------------------------------
# Option 2: Other OpenAI-Compatible Providers
# ----------------------------------------------------------------------------
# Example for LM Studio

# BASE_URL=http://localhost:1234/v1
# API_KEY=lm-studio
# MODEL_NAME=local-model

# ============================================================================
# Optional: Web Search and Reading Tools
# ============================================================================

# SERPER_DEV_API_KEY=your-serper-api-key-here
# Get from: https://serper.dev

# JINA_API_KEY=your-jina-api-key-here
# Get from: https://jina.ai
39 changes: 25 additions & 14 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
*.pyc
.DS_Store
.idea
.vscode
# Python
__pycache__/
.env/
*.pyc

# Virtual environments
.venv/
env/
venv/
.idea
.venv
.uv-cache
logs
node_modules
frontend/.vscode
WareHouse/
env/

# uv
.uv-cache/

# IDEs
.idea/
.vscode/
frontend/.vscode/

# OS
.DS_Store

# Environment
.env

# Project Specific
logs/
node_modules/
data/
temp/
temp/
WareHouse/
15 changes: 15 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
.PHONY: server
server:
@uv run python server_main.py --port 6400 --reload

.PHONY: client
client:
@cd frontend && VITE_API_BASE_URL=http://localhost:6400 npm run dev

.PHONY: sync
sync:
@uv run python tools/sync_vuegraphs.py

.PHONY: validate-yamls
validate-yamls:
@uv run python tools/validate_all_yamls.py
42 changes: 37 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,34 @@ See our paper in [Multi-Agent Collaboration via Evolving Orchestration](https://
cd frontend && npm install
```

### 🔑 Configuration

* **Environment Variables**:
```bash
cp .env.example .env
```
* **Model Keys**: Set `API_KEY` and `BASE_URL` in `.env` for your LLM provider.
* **YAML placeholders**: Use `${VAR}`(e.g., `${API_KEY}`)in configuration files to reference these variables.

### ⚡️ Run the Application

1. **Start Backend** :

#### Using Makefile (Recommended)

1. **Start Backend**:
```bash
make server
```

2. **Start Frontend**:
```bash
make client
```
> Then access the Web Console at **[http://localhost:5173](http://localhost:5173)**.

#### Manual Commands

1. **Start Backend**:
```bash
# Run from the project root
uv run python server_main.py --port 6400 --reload
Expand All @@ -143,12 +168,19 @@ See our paper in [Multi-Agent Collaboration via Evolving Orchestration](https://
> * **Backend**: start with `--port 6401`
> * **Frontend**: set `VITE_API_BASE_URL=http://localhost:6401`

#### Utility Commands

### 🔑 Configuration
* **Sync YAML workflows to frontend**:
```bash
make sync
```
Uploads all workflow files from `yaml_instance/` to the frontend database.

* **Environment Variables**: Create a `.env` file in the project root.
* **Model Keys**: Set `API_KEY` and `BASE_URL` in `.env` for your LLM provider.
* **YAML placeholders**: Use `${VAR}`(e.g., `${API_KEY}`)in configuration files to reference these variables.
* **Validate all YAML workflows**:
```bash
make validate-yamls
```
Checks all YAML files for syntax and schema errors.

---

Expand Down
34 changes: 31 additions & 3 deletions check/check.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ class DesignError(RuntimeError):
"""Raised when a workflow design cannot be loaded or validated."""



def _allowed_node_types() -> set[str]:
names = set(iter_node_schemas().keys())
if not names:
Expand Down Expand Up @@ -73,7 +72,9 @@ def load_config(

data = prepare_design_mapping(raw_data, source=str(config_path))

schema_errors = validate_design(data, set_defaults=set_defaults, fn_module_ref=fn_module)
schema_errors = validate_design(
data, set_defaults=set_defaults, fn_module_ref=fn_module
)
if schema_errors:
formatted = "\n".join(f"- {err}" for err in schema_errors)
raise DesignError(f"Design validation failed for '{config_path}':\n{formatted}")
Expand All @@ -86,7 +87,9 @@ def load_config(
logic_errors = check_workflow_structure(data)
if logic_errors:
formatted = "\n".join(f"- {err}" for err in logic_errors)
raise DesignError(f"Workflow logical issues detected for '{config_path}':\n{formatted}")
raise DesignError(
f"Workflow logical issues detected for '{config_path}':\n{formatted}"
)
else:
print("Workflow OK.")

Expand Down Expand Up @@ -119,3 +122,28 @@ def check_config(yaml_content: Any) -> str:
return str(e)

return ""


def main():
import argparse
import sys

parser = argparse.ArgumentParser(description="Validate workflow design file.")
parser.add_argument(
"--path", type=Path, required=True, help="Path to the design file."
)
args = parser.parse_args()

try:
load_config(args.path)
print(f"Design '{args.path}' is valid.")
except DesignError as e:
print(f"Validation failed: {e}")
sys.exit(1)
except Exception as e:
print(f"An unexpected error occurred: {e}")
sys.exit(1)


if __name__ == "__main__":
main()
48 changes: 48 additions & 0 deletions tools/sync_vuegraphs.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import os
import glob
import requests
import yaml
from pathlib import Path

# Configuration
API_URL = "http://localhost:6400/api/vuegraphs/upload/content"
YAML_DIR = "yaml_instance"

def sync_yaml_to_vuegraphs():
"""Reads all YAML files and uploads them to the VueGraph database."""
print(f"Syncing YAML files from {YAML_DIR} to {API_URL}...")

yaml_files = glob.glob(os.path.join(YAML_DIR, "*.yaml"))

for file_path in yaml_files:
try:
filename = Path(file_path).stem # simulation_hospital_lmstudio

with open(file_path, "r") as f:
content = f.read()

# Basic validation to ensure it's a valid YAML
try:
yaml.safe_load(content)
except yaml.YAMLError as e:
print(f"Skipping {filename}: Invalid YAML - {e}")
continue

# Upload to VueGraph API
payload = {
"filename": filename,
"content": content
}

response = requests.post(API_URL, json=payload)

if response.status_code == 200:
print(f"Synced: {filename}")
else:
print(f"Failed: {filename} - {response.status_code} {response.text}")

except Exception as e:
print(f"Error processing {file_path}: {e}")

if __name__ == "__main__":
sync_yaml_to_vuegraphs()
77 changes: 77 additions & 0 deletions tools/validate_all_yamls.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import sys
import subprocess
from pathlib import Path


def validate_all():
base_dir = Path("yaml_instance")
if not base_dir.exists():
print(f"Directory {base_dir} not found.")
sys.exit(1)

# Recursive search for all .yaml files
files = sorted(list(base_dir.rglob("*.yaml")))

if not files:
print("No YAML files found.")
return

print(
f"Found {len(files)} YAML files. Running FULL validation via check.check...\n"
)

passed = 0
failed = 0
failed_files = []

for yaml_file in files:
# Use relative path for cleaner output
try:
rel_path = yaml_file.relative_to(Path.cwd())
except ValueError:
rel_path = yaml_file

# NOW we run check.check, which we just patched to have a main()
# This performs the stricter load_config() validation
cmd = [sys.executable, "-m", "check.check", "--path", str(yaml_file)]

try:
result = subprocess.run(cmd, capture_output=True, text=True)

if result.returncode == 0:
print(f"{rel_path}")
passed += 1
else:
print(f"{rel_path}")
# Indent error output
if result.stdout:
print(" stdout:", result.stdout.strip().replace("\n", "\n "))
# Validation errors usually print to stdout/stderr depending on impl
# Our new main prints to stdout for success/failure message
failed += 1
failed_files.append(str(rel_path))
except Exception as e:
print(f"{rel_path} (Execution Failed)")
print(f" Error: {e}")
failed += 1
failed_files.append(str(rel_path))

print("\n" + "=" * 40)
print(f"Validation Summary")
print("=" * 40)
print(f"Total Files: {len(files)}")
print(f"Passed: {passed}")
print(f"Failed: {failed}")

if failed > 0:
print("\nFailed Files:")
for f in failed_files:
print(f"- {f}")
sys.exit(1)
else:
print("\nAll files passed validation.")
sys.exit(0)


if __name__ == "__main__":
validate_all()
Loading