Skip to content

Commit c2725af

Browse files
authored
Merge pull request AgentOps-AI#62 from AgentOps-AI/v0.2
v0.2
2 parents 91663f3 + 8570e1b commit c2725af

File tree

19 files changed

+599
-123
lines changed

19 files changed

+599
-123
lines changed

0.2-changes.md

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# 0.2 Roadmap
2+
3+
# Concepts
4+
- Support only CrewAI for now
5+
- Make the process of starting an agent project as easy as possible
6+
7+
# How do we get there
8+
- Understand current agent design
9+
- What are the use cases? How can they be categorized?
10+
11+
# CLI
12+
13+
## Template Types
14+
15+
### Chatbot
16+
- Conversational
17+
- Customer Support
18+
19+
### Research Agent
20+
- RAG
21+
- Search
22+
- Answers question
23+
24+
### Creative Agent
25+
- Coding Agent
26+
- Writer Agent
27+
- Image Gen
28+
29+
### Copilot
30+
- Understand a problem space
31+
- Support decision-making
32+
- Predict next steps
33+
34+
## Templates
35+
Are the templates part of cookiecutter, then structure is generated using the code-gen scripts?
36+
Or do we manage a collection of independent cookiecutter templates.
37+
38+
The options:
39+
40+
### Codegen
41+
This strategy involves using the existing and new codegen scripts to take the base project template and systematically
42+
build off of it.
43+
44+
This would require a templating structure that can handle complex agent designs.
45+
46+
Pros:
47+
- More easily extensible
48+
- Helps prevent some templates lagging behind in updates
49+
50+
Cons:
51+
- More complex design. Requires more work on codegen and is a more difficult pattern to understand
52+
- Contributions will be more challenging
53+
- There may be some templates that this design may not account for
54+
55+
### Cookiecutter
56+
With this strategy, every template would be its own Cookiecutter template.
57+
58+
Pros:
59+
- Much simpler to understand
60+
- No bounds on complexity or variation between templates
61+
62+
Cons:
63+
- Tech debt will easily grow
64+
- Every update will require a change to every single template
65+
- Requires robust processes for keeping every template updated
66+
67+
## Decision
68+
We'll move forward with the codegen method unless other information comes to light.
69+
70+
71+
### `agentstack i <project_name>`
72+
- Flags
73+
- `--in-place`
74+
- dont place into a subdirectory
75+
- `--template <template_name>`
76+
- generate the project according to a template
77+
- can also consume a url
78+
79+
### `agentstack tools`
80+
- Stays the same
81+
82+
### `agentstack generate`
83+
- `agent`
84+
- `--template <agent_name>`
85+
-

agentstack/cli/agentstack_data.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
from datetime import datetime
33
from typing import Optional, Literal
44

5-
from agentstack.utils import clean_input
5+
from agentstack.utils import clean_input, get_version
66
from agentstack.logger import log
77

88

@@ -14,7 +14,9 @@ def __init__(self,
1414
author_name: str = "",
1515
version: str = "",
1616
license: str = "",
17-
year: int = datetime.now().year
17+
year: int = datetime.now().year,
18+
template: str = "none",
19+
template_version: str = "0",
1820
):
1921
self.project_name = clean_input(project_name) if project_name else "myagent"
2022
self.project_slug = clean_input(project_slug) if project_slug else self.project_name
@@ -23,6 +25,10 @@ def __init__(self,
2325
self.version = version
2426
self.license = license
2527
self.year = year
28+
self.agentstack_version = get_version()
29+
self.template = template
30+
self.template_version = template_version
31+
2632
log.debug(f"ProjectMetadata: {self.to_dict()}")
2733

2834
def to_dict(self):
@@ -34,6 +40,9 @@ def to_dict(self):
3440
'version': self.version,
3541
'license': self.license,
3642
'year': self.year,
43+
'agentstack_version': self.agentstack_version,
44+
'template': self.template,
45+
'template_version': self.template_version,
3746
}
3847

3948
def to_json(self):

agentstack/cli/cli.py

Lines changed: 69 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
import json
22
import shutil
3+
import sys
34
import time
45
from datetime import datetime
56
from typing import Optional
7+
import requests
68
import itertools
79

810
from art import text2art
@@ -19,17 +21,64 @@
1921
from ..utils import open_json_file, term_color, is_snake_case
2022

2123

22-
def init_project_builder(slug_name: Optional[str] = None, skip_wizard: bool = False):
24+
def init_project_builder(slug_name: Optional[str] = None, template: Optional[str] = None, use_wizard: bool = False):
2325
if slug_name and not is_snake_case(slug_name):
2426
print(term_color("Project name must be snake case", 'red'))
2527
return
2628

27-
if skip_wizard:
29+
if template is not None and use_wizard:
30+
print(term_color("Template and wizard flags cannot be used together", 'red'))
31+
return
32+
33+
template_data = None
34+
if template is not None:
35+
url_start = "https://"
36+
if template[:len(url_start)] == url_start:
37+
# template is a url
38+
response = requests.get(template)
39+
if response.status_code == 200:
40+
template_data = response.json()
41+
else:
42+
print(term_color(f"Failed to fetch template data from {template}. Status code: {response.status_code}", 'red'))
43+
sys.exit(1)
44+
else:
45+
with importlib.resources.path('agentstack.templates.proj_templates', f'{template}.json') as template_path:
46+
if template_path is None:
47+
print(term_color(f"No such template {template} found", 'red'))
48+
sys.exit(1)
49+
template_data = open_json_file(template_path)
50+
51+
if template_data:
2852
project_details = {
29-
"name": slug_name or "new_agentstack_project",
30-
"version": "0.1.0",
53+
"name": slug_name or template_data['name'],
54+
"version": "0.0.1",
55+
"description": template_data['description'],
56+
"author": "Name <Email>",
57+
"license": "MIT"
58+
}
59+
framework = template_data['framework']
60+
design = {
61+
'agents': template_data['agents'],
62+
'tasks': template_data['tasks']
63+
}
64+
65+
tools = template_data['tools']
66+
67+
elif use_wizard:
68+
welcome_message()
69+
project_details = ask_project_details(slug_name)
70+
welcome_message()
71+
framework = ask_framework()
72+
design = ask_design()
73+
tools = ask_tools()
74+
75+
else:
76+
welcome_message()
77+
project_details = {
78+
"name": slug_name or "agentstack_project",
79+
"version": "0.0.1",
3180
"description": "New agentstack project",
32-
"author": "<NAME>",
81+
"author": "Name <Email>",
3382
"license": "MIT"
3483
}
3584

@@ -41,21 +90,15 @@ def init_project_builder(slug_name: Optional[str] = None, skip_wizard: bool = Fa
4190
}
4291

4392
tools = []
44-
else:
45-
welcome_message()
46-
project_details = ask_project_details(slug_name)
47-
welcome_message()
48-
framework = ask_framework()
49-
design = ask_design()
50-
tools = ask_tools()
5193

5294
log.debug(
5395
f"project_details: {project_details}"
5496
f"framework: {framework}"
5597
f"design: {design}"
5698
)
57-
insert_template(project_details, framework, design)
58-
add_tools(tools, project_details['name'])
99+
insert_template(project_details, framework, design, template_data)
100+
for tool_data in tools:
101+
generation.add_tool(tool_data['name'], agents=tool_data['agents'], path=project_details['name'])
59102

60103

61104
def welcome_message():
@@ -98,11 +141,9 @@ def ask_framework() -> str:
98141

99142

100143
def ask_design() -> dict:
101-
# use_wizard = inquirer.confirm(
102-
# message="Would you like to use the CLI wizard to set up agents and tasks?",
103-
# )
104-
105-
use_wizard = False
144+
use_wizard = inquirer.confirm(
145+
message="Would you like to use the CLI wizard to set up agents and tasks?",
146+
)
106147

107148
if not use_wizard:
108149
return {
@@ -202,11 +243,9 @@ def ask_design() -> dict:
202243

203244

204245
def ask_tools() -> list:
205-
# use_tools = inquirer.confirm(
206-
# message="Do you want to add agent tools now? (you can do this later with `agentstack tools add <tool_name>`)",
207-
# )
208-
209-
use_tools = False
246+
use_tools = inquirer.confirm(
247+
message="Do you want to add agent tools now? (you can do this later with `agentstack tools add <tool_name>`)",
248+
)
210249

211250
if not use_tools:
212251
return []
@@ -262,14 +301,16 @@ def ask_project_details(slug_name: Optional[str] = None) -> dict:
262301
return questions
263302

264303

265-
def insert_template(project_details: dict, framework_name: str, design: dict):
304+
def insert_template(project_details: dict, framework_name: str, design: dict, template_data: Optional[dict] = None):
266305
framework = FrameworkData(framework_name.lower())
267306
project_metadata = ProjectMetadata(project_name=project_details["name"],
268307
description=project_details["description"],
269308
author_name=project_details["author"],
270-
version=project_details["version"],
309+
version="0.0.1",
271310
license="MIT",
272-
year=datetime.now().year)
311+
year=datetime.now().year,
312+
template=template_data['name'] if template_data else None,
313+
template_version=template_data['template_version'] if template_data else None)
273314

274315
project_structure = ProjectStructure()
275316
project_structure.agents = design["agents"]
@@ -321,16 +362,11 @@ def insert_template(project_details: dict, framework_name: str, design: dict):
321362
)
322363

323364

324-
def add_tools(tools: list, project_name: str):
325-
for tool in tools:
326-
generation.add_tool(tool, project_name)
327-
328-
329365
def list_tools():
330366
# Display the tools
331367
tools = get_all_tools()
332368
curr_category = None
333-
369+
334370
print("\n\nAvailable AgentStack Tools:")
335371
for category, tools in itertools.groupby(tools, lambda x: x.category):
336372
if curr_category != category:

agentstack/generation/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
from .agent_generation import generate_agent
2-
from .task_generation import generate_task
1+
from .agent_generation import generate_agent, get_agent_names
2+
from .task_generation import generate_task, get_task_names
33
from .tool_generation import add_tool, remove_tool
44
from .files import ConfigFile, EnvFile, CONFIG_FILENAME

agentstack/generation/agent_generation.py

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
from typing import Optional
1+
from typing import Optional, List
22

3-
from .gen_utils import insert_code_after_tag
3+
from .gen_utils import insert_code_after_tag, get_crew_components, CrewComponent
44
from agentstack.utils import verify_agentstack_project, get_framework
55
import os
66
from ruamel.yaml import YAML
@@ -21,7 +21,7 @@ def generate_agent(
2121
if not backstory:
2222
backstory = 'Add your backstory here'
2323
if not llm:
24-
llm = 'Add your llm here with format provider/model'
24+
llm = 'openai/gpt-4o'
2525

2626
verify_agentstack_project()
2727

@@ -45,7 +45,7 @@ def generate_crew_agent(
4545
role: Optional[str] = 'Add your role here',
4646
goal: Optional[str] = 'Add your goal here',
4747
backstory: Optional[str] = 'Add your backstory here',
48-
llm: Optional[str] = 'Add your llm here with format provider/model'
48+
llm: Optional[str] = 'openai/gpt-4o'
4949
):
5050
config_path = os.path.join('src', 'config', 'agents.yaml')
5151

@@ -99,3 +99,8 @@ def generate_crew_agent(
9999
]
100100

101101
insert_code_after_tag(file_path, tag, code_to_insert)
102+
103+
104+
def get_agent_names(framework: str = 'crewai', path: str = '') -> List[str]:
105+
"""Get only agent names from the crew file"""
106+
return get_crew_components(framework, CrewComponent.AGENT, path)['agents']

0 commit comments

Comments
 (0)