Skip to content
Merged
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
26 changes: 25 additions & 1 deletion backend/advanced_workflow_orchestrator.py
Original file line number Diff line number Diff line change
Expand Up @@ -1022,7 +1022,31 @@ async def execute_workflow(self, workflow_id: str, input_data: Dict[str, Any],
"""Execute a complex workflow"""

if workflow_id not in self.workflows:
raise ValueError(f"Workflow {workflow_id} not found")
# Lazy Load from Template Manager
if self.template_manager and self.template_manager.get_template(workflow_id):
logger.info(f"Lazy-loading template {workflow_id} into orchestrator...")
template = self.template_manager.get_template(workflow_id)
# Convert Template -> WorkflowDefinition
steps = []
for t_step in template.steps:
steps.append(WorkflowStep(
step_id=t_step.step_id,
step_type=WorkflowStepType(t_step.step_type) if hasattr(WorkflowStepType, t_step.step_type.upper()) else WorkflowStepType.API_CALL,
description=t_step.description,
parameters=t_step.parameters if isinstance(t_step.parameters, dict) else {}, # Handle list vs dict
next_steps=t_step.depends_on if hasattr(t_step, 'depends_on') else []
))

new_def = WorkflowDefinition(
workflow_id=template.template_id,
name=template.name,
description=template.description,
steps=steps,
start_step=steps[0].step_id if steps else "end"
)
self.workflows[workflow_id] = new_def
else:
raise ValueError(f"Workflow {workflow_id} not found in registry or templates")

workflow = self.workflows[workflow_id]
context = WorkflowContext(
Expand Down
56 changes: 55 additions & 1 deletion backend/api/workflow_template_routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,13 @@ class CreateTemplateRequest(BaseModel):
tags: List[str] = []
steps: List[Dict[str, Any]] = []

class UpdateTemplateRequest(BaseModel):
name: Optional[str] = None
description: Optional[str] = None
steps: Optional[List[Dict[str, Any]]] = None
inputs: Optional[List[Dict[str, Any]]] = None
tags: Optional[List[str]] = None

@router.post("/")
async def create_template(request: CreateTemplateRequest):
"""Create a new workflow template from the visual builder"""
Expand Down Expand Up @@ -89,7 +96,8 @@ async def list_templates(category: Optional[str] = None, limit: int = 50):
"tags": t.tags,
"usage_count": t.usage_count,
"rating": t.rating,
"is_featured": t.is_featured
"is_featured": t.is_featured,
"steps": [s.model_dump() if hasattr(s, 'model_dump') else s.__dict__ for s in t.steps]
}
for t in templates
]
Expand All @@ -108,6 +116,52 @@ async def get_template(template_id: str):

return template.dict()

@router.put("/{template_id}")
async def update_template_endpoint(template_id: str, request: UpdateTemplateRequest):
"""Update an existing workflow template"""
try:
manager = get_template_manager()

# Convert request model to dict, excluding None values
updates = {k: v for k, v in request.dict().items() if v is not None}

if not updates:
raise HTTPException(status_code=400, detail="No updates provided")

# Special handling for steps if provided (need to map format)
if "steps" in updates:
# We assume steps come in the same format as CreateRequest,
# so we might need to process them if the internal model expects differently.
# However, workflow_template_system.py expects Pydantic models or dicts matching schema.
# Let's clean up the steps just in case
processed_steps = []
for i, step in enumerate(updates["steps"]):
processed_steps.append({
"id": step.get("step_id", step.get("id", f"step_{i}")), # Map step_id -> id
"name": step.get("name", f"Step {i}"),
"description": step.get("description", ""),
"step_type": step.get("step_type", "action"),
"parameters": step.get("parameters", []),
"depends_on": step.get("depends_on", []),
"condition": step.get("condition"),
# Add other fields as needed
})
updates["steps"] = processed_steps

updated_template = manager.update_template(template_id, updates)

return {
"status": "success",
"message": f"Template {template_id} updated",
"template": updated_template.dict()
}

except ValueError as e:
raise HTTPException(status_code=404, detail=str(e))
except Exception as e:
logger.error(f"Failed to update template: {e}")
raise HTTPException(status_code=500, detail=str(e))

@router.post("/{template_id}/instantiate")
async def instantiate_template(template_id: str, request: InstantiateRequest):
"""Create a runnable workflow from a template"""
Expand Down
35 changes: 35 additions & 0 deletions backend/check_accounts_endpoint.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@

import requests

# 1. Login to get token
login_url = "http://localhost:8000/api/auth/login"
payload = {
"username": "admin@example.com",
"password": "securePass123"
}
print(f"Logging in...")
try:
login_res = requests.post(login_url, data=payload)
if login_res.status_code != 200:
print(f"Login failed: {login_res.text}")
exit(1)

token = login_res.json().get("access_token")
headers = {"Authorization": f"Bearer {token}"}
print("Login successful.")

# 2. Test Accounts Endpoint
accounts_url = "http://localhost:8000/api/auth/accounts"
print(f"Testing {accounts_url}...")

res = requests.get(accounts_url, headers=headers)
print(f"Status: {res.status_code}")
if res.status_code == 200:
print("Response JSON:")
print(res.json())
print("SUCCESS")
else:
print(f"FAILED: {res.text}")

except Exception as e:
print(f"Error: {e}")
5 changes: 5 additions & 0 deletions backend/check_bcrypt.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
try:
import bcrypt
print("BCRYPT_AVAILABLE = True")
except ImportError:
print("BCRYPT_AVAILABLE = False")
56 changes: 56 additions & 0 deletions backend/check_db_memory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@

import sys
import os
import logging
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from core.models import User, Base, UserStatus

# Setup Logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def test_memory_db():
print("Testing In-Memory DB (sqlite:///:memory:)")
engine = create_engine("sqlite:///:memory:", echo=True)
Session = sessionmaker(bind=engine)
session = Session()

try:
# Create Tables
print("Creating tables...")
Base.metadata.create_all(engine)

# Insert User
print("Inserting user...")
new_user = User(
email="test@example.com",
first_name="Test",
last_name="User",
status=UserStatus.ACTIVE
)
session.add(new_user)
session.commit()

# Query User
print("Querying user...")
user = session.query(User).filter(User.email == "test@example.com").first()
if user:
print(f"SUCCESS: User found: {user.email}, ID: {user.id}")
with open("db_success.txt", "w") as f:
f.write(f"SUCCESS: User found: {user.email}, ID: {user.id}")
else:
print("FAILURE: User NOT found")

except Exception as e:
print("CRITICAL ERROR:")
with open("db_error.log", "w") as f:
import traceback
traceback.print_exc(file=f)
import traceback
traceback.print_exc()
finally:
session.close()

if __name__ == "__main__":
test_memory_db()
39 changes: 39 additions & 0 deletions backend/check_db_standalone.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@

import sys
import os
import logging
# numpy mock removed for testing


from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker
from core.models import User
DATABASE_URL = "sqlite:///./atom_v2.db"
# from core.database import DATABASE_URL, Base

# Setup Logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)

def test_db():
print(f"Testing DB URL: {DATABASE_URL}")
engine = create_engine(DATABASE_URL)
Session = sessionmaker(bind=engine)
session = Session()

try:
print("Querying user...")
user = session.query(User).filter(User.email == "admin@example.com").first()
if user:
print(f"User found: {user.email}, ID: {user.id}")
else:
print("User NOT found")
except Exception as e:
print("Error querying DB:")
import traceback
traceback.print_exc()
finally:
session.close()

if __name__ == "__main__":
test_db()
16 changes: 16 additions & 0 deletions backend/check_endpoints.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import requests

def check(url):
try:
r = requests.get(url, allow_redirects=False)
print(f"GET {url} -> {r.status_code}")
if r.status_code in [301, 302, 307, 308]:
print(f" Location: {r.headers.get('Location')}")
except Exception as e:
print(f"GET {url} -> ERROR: {e}")

print("Checking backend directly...")
check("http://127.0.0.1:8000/api/agents")
check("http://127.0.0.1:8000/api/agents/")
check("http://localhost:8000/api/agents")
check("http://localhost:8000/api/agents/")
19 changes: 19 additions & 0 deletions backend/check_login_final.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@

import requests
try:
url = "http://localhost:8000/api/auth/login"
payload = {
"username": "admin@example.com",
"password": "securePass123"
}
print(f"Testing Login at {url}...")
response = requests.post(url, data=payload)

print(f"Status Code: {response.status_code}")
if response.status_code == 200:
print("LOGIN SUCCESS!")
print(f"Token: {response.json().get('access_token')[:10]}...")
else:
print(f"LOGIN FAILED: {response.text}")
except Exception as e:
print(f"Error: {e}")
26 changes: 26 additions & 0 deletions backend/check_user_status.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import sys
import os
from sqlalchemy import create_engine, text
from sqlalchemy.orm import sessionmaker

# Database setup
DATABASE_URL = os.getenv("DATABASE_URL", "sqlite:///./atom.db")
if "postgres" in DATABASE_URL:
DATABASE_URL = DATABASE_URL.replace("postgres://", "postgresql://")

try:
engine = create_engine(DATABASE_URL)
with engine.connect() as connection:
result = connection.execute(text("SELECT id, email, password_hash, status FROM users WHERE email = 'admin@example.com'"))
user = result.fetchone()

if user:
print(f"✅ User found: {user.email}")
print(f" ID: {user.id}")
print(f" Status: {user.status}")
print(f" Hash start: {user.password_hash[:10]}...")
else:
print("❌ User 'admin@example.com' NOT FOUND")

except Exception as e:
print(f"Error checking DB: {e}")
45 changes: 45 additions & 0 deletions backend/core/admin_bootstrap.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import logging
from sqlalchemy.orm import Session
from core.models import User, UserStatus
from core.auth import get_password_hash
from core.database import SessionLocal

logger = logging.getLogger("ATOM_BOOTSTRAP")

def ensure_admin_user():
"""
Ensures the admin@example.com user exists with the correct password.
This runs INSIDE the main application process to avoid DB locks.
"""
db = SessionLocal()
try:
email = "admin@example.com"
password = "securePass123"

user = db.query(User).filter(User.email == email).first()

if user:
logger.info(f"BOOTSTRAP: User {email} found. resetting password...")
user.password_hash = get_password_hash(password)
user.status = UserStatus.ACTIVE
db.commit()
logger.info(f"BOOTSTRAP: Password for {email} reset to '{password}'")
else:
logger.info(f"BOOTSTRAP: User {email} not found. Creating...")
new_user = User(
id="00000000-0000-0000-0000-000000000000", # Fixed ID for development stability
email=email,
password_hash=get_password_hash(password),
first_name="Admin",
last_name="User",
status=UserStatus.ACTIVE
)
db.add(new_user)
db.commit()
logger.info(f"BOOTSTRAP: Created {email} with password '{password}'")

except Exception as e:
logger.error(f"BOOTSTRAP FAILED: {e}")
db.rollback()
finally:
db.close()
Loading
Loading