Skip to content

Commit

Permalink
fix: improve decorator validation and project generation
Browse files Browse the repository at this point in the history
  • Loading branch information
1 parent ba32b21 commit e90d1a3
Show file tree
Hide file tree
Showing 3 changed files with 60 additions and 25 deletions.
52 changes: 34 additions & 18 deletions agentstack/frameworks/agent_protocol.py
Original file line number Diff line number Diff line change
Expand Up @@ -60,24 +60,40 @@ def validate(self) -> None:
elif target.id == 'tools':
has_tools = True
elif isinstance(node, ast.FunctionDef):
if hasattr(node, 'decorator_list'):
for decorator in node.decorator_list:
# Handle both simple decorators and attribute decorators
if isinstance(decorator, ast.Name) and decorator.id == 'on_task':
has_task_handler = True
elif isinstance(decorator, ast.Attribute):
if (isinstance(decorator.value, ast.Name) and
decorator.value.id == 'agent_protocol' and
decorator.attr == 'on_task'):
has_task_handler = True
# Similar check for on_step decorator
elif isinstance(decorator, ast.Name) and decorator.id == 'on_step':
has_step_handler = True
elif isinstance(decorator, ast.Attribute):
if (isinstance(decorator.value, ast.Name) and
decorator.value.id == 'agent_protocol' and
decorator.attr == 'on_step'):
has_step_handler = True
for decorator in node.decorator_list:
# Handle all possible decorator patterns
decorator_str = ''
if isinstance(decorator, ast.Name):
decorator_str = decorator.id
elif isinstance(decorator, ast.Attribute):
# Build full decorator path (e.g., agent_protocol.on_task)
parts = []
current = decorator
while isinstance(current, ast.Attribute):
parts.append(current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.append(current.id)
decorator_str = '.'.join(reversed(parts))
elif isinstance(decorator, ast.Call):
# Handle decorator calls (e.g., @decorator())
if isinstance(decorator.func, ast.Attribute):
parts = []
current = decorator.func
while isinstance(current, ast.Attribute):
parts.append(current.attr)
current = current.value
if isinstance(current, ast.Name):
parts.append(current.id)
decorator_str = '.'.join(reversed(parts))
elif isinstance(decorator.func, ast.Name):
decorator_str = decorator.func.id

# Check for task and step handlers
if 'on_task' in decorator_str:
has_task_handler = True
elif 'on_step' in decorator_str:
has_step_handler = True

if not has_app:
raise ValidationError(f"FastAPI app not found in {self.path}")
Expand Down
31 changes: 25 additions & 6 deletions agentstack/generation/project_generation.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,18 +23,31 @@ def generate_project(project_dir: Path, framework: str, project_name: str, proje
project_name: Human-readable name of the project
project_slug: URL-friendly slug for the project
"""
template_dir = get_package_path() / 'templates' / framework
# Get absolute path to template directory using package path
package_path = get_package_path()
template_dir = package_path / 'templates' / framework

# Validate template directory and cookiecutter.json existence
if not template_dir.exists():
raise ValidationError(f"Template directory for framework '{framework}' not found")
raise ValidationError(
f"Template directory for framework '{framework}' not found at {template_dir}. "
f"Package path: {package_path}"
)

cookiecutter_json = template_dir / 'cookiecutter.json'
if not cookiecutter_json.exists():
raise ValidationError(
f"cookiecutter.json not found in template directory at {cookiecutter_json}. "
f"Directory contents: {list(template_dir.iterdir())}"
)

# Create project directory if it doesn't exist
os.makedirs(project_dir, exist_ok=True)

# Generate project using cookiecutter
# Generate project using cookiecutter with absolute path
cookiecutter(
str(template_dir),
output_dir=str(project_dir.parent),
str(template_dir.absolute()),
output_dir=str(project_dir.parent.absolute()),
no_input=True,
extra_context={
'project_metadata': {
Expand All @@ -48,5 +61,11 @@ def generate_project(project_dir: Path, framework: str, project_name: str, proje
nested_dir = project_dir.parent / project_slug
if nested_dir.exists() and nested_dir != project_dir:
for item in nested_dir.iterdir():
shutil.move(str(item), str(project_dir / item.name))
target_path = project_dir / item.name
if target_path.exists():
if target_path.is_dir():
shutil.rmtree(target_path)
else:
target_path.unlink()
shutil.move(str(item), str(target_path))
nested_dir.rmdir()
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[build-system]
requires = ["setuptools", "wheel"]
requires = ["setuptools>=61.0.0", "wheel"]
build-backend = "setuptools.build_meta"

[project]
Expand Down

0 comments on commit e90d1a3

Please sign in to comment.