a4e 0.1.5__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.
Files changed (70) hide show
  1. a4e/__init__.py +0 -0
  2. a4e/cli.py +47 -0
  3. a4e/cli_commands/__init__.py +5 -0
  4. a4e/cli_commands/add.py +376 -0
  5. a4e/cli_commands/deploy.py +149 -0
  6. a4e/cli_commands/dev.py +162 -0
  7. a4e/cli_commands/info.py +206 -0
  8. a4e/cli_commands/init.py +211 -0
  9. a4e/cli_commands/list.py +227 -0
  10. a4e/cli_commands/mcp.py +504 -0
  11. a4e/cli_commands/remove.py +197 -0
  12. a4e/cli_commands/update.py +285 -0
  13. a4e/cli_commands/validate.py +117 -0
  14. a4e/core.py +109 -0
  15. a4e/dev_runner.py +425 -0
  16. a4e/server.py +86 -0
  17. a4e/templates/agent.md.j2 +168 -0
  18. a4e/templates/agent.py.j2 +15 -0
  19. a4e/templates/agents.md.j2 +99 -0
  20. a4e/templates/metadata.json.j2 +20 -0
  21. a4e/templates/prompt.md.j2 +20 -0
  22. a4e/templates/prompts/agent.md.j2 +206 -0
  23. a4e/templates/skills/agents.md.j2 +110 -0
  24. a4e/templates/skills/skill.md.j2 +120 -0
  25. a4e/templates/support_module.py.j2 +84 -0
  26. a4e/templates/tool.py.j2 +60 -0
  27. a4e/templates/tools/agent.md.j2 +192 -0
  28. a4e/templates/view.tsx.j2 +21 -0
  29. a4e/templates/views/agent.md.j2 +219 -0
  30. a4e/tools/__init__.py +70 -0
  31. a4e/tools/agent_tools/__init__.py +12 -0
  32. a4e/tools/agent_tools/add_support_module.py +95 -0
  33. a4e/tools/agent_tools/add_tool.py +115 -0
  34. a4e/tools/agent_tools/list_tools.py +28 -0
  35. a4e/tools/agent_tools/remove_tool.py +69 -0
  36. a4e/tools/agent_tools/update_tool.py +123 -0
  37. a4e/tools/deploy/__init__.py +8 -0
  38. a4e/tools/deploy/deploy.py +59 -0
  39. a4e/tools/dev/__init__.py +10 -0
  40. a4e/tools/dev/check_environment.py +79 -0
  41. a4e/tools/dev/dev_start.py +30 -0
  42. a4e/tools/dev/dev_stop.py +26 -0
  43. a4e/tools/project/__init__.py +10 -0
  44. a4e/tools/project/get_agent_info.py +66 -0
  45. a4e/tools/project/get_instructions.py +216 -0
  46. a4e/tools/project/initialize_project.py +231 -0
  47. a4e/tools/schemas/__init__.py +8 -0
  48. a4e/tools/schemas/generate_schemas.py +278 -0
  49. a4e/tools/skills/__init__.py +12 -0
  50. a4e/tools/skills/add_skill.py +105 -0
  51. a4e/tools/skills/helpers.py +137 -0
  52. a4e/tools/skills/list_skills.py +54 -0
  53. a4e/tools/skills/remove_skill.py +74 -0
  54. a4e/tools/skills/update_skill.py +150 -0
  55. a4e/tools/validation/__init__.py +8 -0
  56. a4e/tools/validation/validate.py +389 -0
  57. a4e/tools/views/__init__.py +12 -0
  58. a4e/tools/views/add_view.py +40 -0
  59. a4e/tools/views/helpers.py +91 -0
  60. a4e/tools/views/list_views.py +27 -0
  61. a4e/tools/views/remove_view.py +73 -0
  62. a4e/tools/views/update_view.py +124 -0
  63. a4e/utils/dev_manager.py +253 -0
  64. a4e/utils/schema_generator.py +255 -0
  65. a4e-0.1.5.dist-info/METADATA +427 -0
  66. a4e-0.1.5.dist-info/RECORD +70 -0
  67. a4e-0.1.5.dist-info/WHEEL +5 -0
  68. a4e-0.1.5.dist-info/entry_points.txt +2 -0
  69. a4e-0.1.5.dist-info/licenses/LICENSE +21 -0
  70. a4e-0.1.5.dist-info/top_level.txt +1 -0
@@ -0,0 +1,216 @@
1
+ """
2
+ Get instructions for AI agents on how to use A4E tools.
3
+ """
4
+
5
+ from ...core import mcp
6
+
7
+
8
+ AGENT_INSTRUCTIONS = '''
9
+ # A4E Agent Creator - Instructions for AI Assistants
10
+
11
+ You have access to the **A4E MCP Server** for creating conversational AI agents.
12
+
13
+ ## Architecture Overview
14
+
15
+ A4E agents use a **Skills V2** architecture with three layers:
16
+
17
+ ```
18
+ USER MESSAGE → SKILL SELECTOR → VIEW RENDERER → VIEW DISPLAY
19
+ ```
20
+
21
+ 1. **Skill Selector**: Matches user intent to a skill based on `intent_triggers`
22
+ 2. **View Renderer**: Calls `internal_tools`, processes results, maps to view props
23
+ 3. **View Display**: Renders React component with the props
24
+
25
+ ## Core Concepts
26
+
27
+ ### Tools (Python Functions)
28
+ Backend logic - calculations, API calls, data retrieval.
29
+
30
+ ### Views (React Components)
31
+ Frontend display - what users see. Each view has:
32
+ - `view.tsx` - React component
33
+ - `view.schema.json` - Props schema
34
+
35
+ ### Skills (Intent → View Mapping)
36
+ Connect user intents to views:
37
+ - `intent_triggers` - phrases that activate the skill
38
+ - `internal_tools` - tools to call
39
+ - `output_view` - view to render
40
+
41
+ ## Available MCP Tools
42
+
43
+ | Tool | Description |
44
+ |------|-------------|
45
+ | `initialize_project(name, display_name, description, category, template)` | Create new agent |
46
+ | `add_tool(agent_name, tool_name, description, parameters)` | Add Python tool |
47
+ | `add_view(agent_name, view_id, description, props)` | Add React view |
48
+ | `add_skill(agent_name, skill_id, name, description, intent_triggers, output_view, internal_tools, requires_auth)` | Add skill |
49
+ | `update_tool/view/skill(...)` | Update existing components |
50
+ | `remove_tool/view/skill(...)` | Remove components |
51
+ | `list_tools/views/skills(agent_name)` | List components |
52
+ | `validate(agent_name)` | Validate configuration |
53
+ | `generate_schemas(agent_name, force)` | Regenerate schemas |
54
+ | `dev_start(agent_name, port)` | Start dev server |
55
+
56
+ ## Workflow
57
+
58
+ ### Step 1: Initialize Project
59
+ ```python
60
+ initialize_project(
61
+ name="my-agent", # lowercase-hyphens
62
+ display_name="My Agent",
63
+ description="What the agent does",
64
+ category="category",
65
+ template="basic", # basic | with-tools | with-views | full
66
+ project_path="/path/to/workspace" # IMPORTANT: Pass the current workspace path
67
+ )
68
+ ```
69
+
70
+ **IMPORTANT**: Always pass `project_path` with the user's current workspace/project directory.
71
+ The agent will be created at `{project_path}/file-store/agent-store/{name}/`.
72
+
73
+ ### Step 2: Add Tools
74
+ ```python
75
+ add_tool(
76
+ agent_name="my-agent",
77
+ tool_name="calculate_something", # snake_case
78
+ description="What it does",
79
+ parameters={
80
+ "param1": {"type": "string", "description": "...", "required": True},
81
+ "param2": {"type": "number", "description": "..."}
82
+ }
83
+ )
84
+ ```
85
+
86
+ **Parameter types:** `string`, `number`, `integer`, `boolean`, `array`, `object`
87
+
88
+ ### Step 3: Add Views
89
+ ```python
90
+ add_view(
91
+ agent_name="my-agent",
92
+ view_id="result_view", # snake_case
93
+ description="What it displays",
94
+ props={
95
+ "title": {"type": "string", "description": "..."},
96
+ "items": {"type": "array", "description": "..."}
97
+ }
98
+ )
99
+ ```
100
+
101
+ ### Step 4: Add Skills (AFTER creating views)
102
+ ```python
103
+ add_skill(
104
+ agent_name="my-agent",
105
+ skill_id="show_result", # snake_case
106
+ name="Show Result", # Display name
107
+ description="When to use this skill",
108
+ intent_triggers=[
109
+ "show result",
110
+ "display data",
111
+ "mostrar resultado" # Multiple languages supported
112
+ ],
113
+ output_view="result_view", # Must match existing view_id
114
+ internal_tools=["calculate_something"],
115
+ requires_auth=False
116
+ )
117
+ ```
118
+
119
+ ### Step 5: Validate
120
+ ```python
121
+ validate(agent_name="my-agent")
122
+ ```
123
+
124
+ ## Important Rules
125
+
126
+ 1. **Create views BEFORE skills** - Skills reference views by ID
127
+ 2. **Use snake_case** for tool_name, view_id, skill_id
128
+ 3. **Use lowercase-hyphens** for agent name
129
+ 4. **Write diverse intent_triggers** - variations, synonyms, multiple languages
130
+ 5. **Check errors** - All tools return `{"success": bool, "error": str, "fix": str}`
131
+
132
+ ## Data Flow Example
133
+
134
+ User: "Calculate my BMI"
135
+
136
+ 1. Skill Selector → matches "show_bmi_result" skill
137
+ 2. View Renderer:
138
+ - Calls `calculate_bmi(weight=70, height=1.75)`
139
+ - Gets `{"bmi": 22.9, "category": "normal"}`
140
+ - Maps to view props
141
+ 3. View Display → renders BMI result component
142
+
143
+ ## Project Structure
144
+
145
+ ```
146
+ {agent}/
147
+ ├── agent.py
148
+ ├── metadata.json
149
+ ├── tools/
150
+ │ ├── {tool_name}.py
151
+ │ └── schemas.json
152
+ ├── views/
153
+ │ ├── {view_id}/
154
+ │ │ ├── view.tsx
155
+ │ │ └── view.schema.json
156
+ │ └── schemas.json
157
+ ├── skills/
158
+ │ ├── {skill_id}/
159
+ │ │ └── SKILL.md
160
+ │ └── schemas.json
161
+ └── prompts/
162
+ └── agent.md
163
+ ```
164
+
165
+ ## Quick Example
166
+
167
+ ```python
168
+ # 1. Initialize (ALWAYS pass project_path!)
169
+ initialize_project(
170
+ name="calculator",
171
+ display_name="Calculator",
172
+ description="Math calculator",
173
+ category="Productivity",
174
+ template="basic",
175
+ project_path="/Users/me/my-project" # Current workspace path
176
+ )
177
+
178
+ # 2. Add tool
179
+ add_tool(agent_name="calculator", tool_name="add_numbers", description="Add two numbers", parameters={"a": "number", "b": "number"})
180
+
181
+ # 3. Add view
182
+ add_view(agent_name="calculator", view_id="sum_result", description="Show sum", props={"result": "number", "expression": "string"})
183
+
184
+ # 4. Add skill
185
+ add_skill(agent_name="calculator", skill_id="show_sum", name="Show Sum", description="Display addition result", intent_triggers=["add", "sum", "plus"], output_view="sum_result", internal_tools=["add_numbers"])
186
+
187
+ # 5. Validate
188
+ validate(agent_name="calculator")
189
+ ```
190
+ '''
191
+
192
+
193
+ @mcp.tool()
194
+ def get_instructions() -> dict:
195
+ """
196
+ Get instructions for AI agents on how to use A4E MCP tools.
197
+
198
+ Call this tool first to understand how to create A4E agents.
199
+ Returns comprehensive documentation on architecture, tools, and workflows.
200
+ """
201
+ return {
202
+ "success": True,
203
+ "instructions": AGENT_INSTRUCTIONS,
204
+ "summary": "A4E Agent Creator instructions loaded. Use initialize_project() to start, then add tools, views, and skills.",
205
+ "quick_reference": {
206
+ "workflow": ["initialize_project", "add_tool", "add_view", "add_skill", "validate"],
207
+ "naming": {
208
+ "agent_name": "lowercase-hyphens",
209
+ "tool_name": "snake_case",
210
+ "view_id": "snake_case",
211
+ "skill_id": "snake_case"
212
+ },
213
+ "parameter_types": ["string", "number", "integer", "boolean", "array", "object"],
214
+ "templates": ["basic", "with-tools", "with-views", "full"]
215
+ }
216
+ }
@@ -0,0 +1,231 @@
1
+ """
2
+ Initialize project tool.
3
+ """
4
+
5
+ from pathlib import Path
6
+ from typing import Literal, Optional
7
+ import os
8
+
9
+ from ...core import mcp, jinja_env, sanitize_input, get_project_dir, get_configured_project_dir
10
+
11
+
12
+ @mcp.tool()
13
+ def initialize_project(
14
+ name: str,
15
+ display_name: str,
16
+ description: str,
17
+ category: Literal[
18
+ "Concierge",
19
+ "E-commerce",
20
+ "Fitness & Health",
21
+ "Education",
22
+ "Entertainment",
23
+ "Productivity",
24
+ "Finance",
25
+ "Customer Support",
26
+ "General",
27
+ ],
28
+ template: Literal["basic", "with-tools", "with-views", "full"] = "basic",
29
+ project_path: Optional[str] = None,
30
+ ) -> dict:
31
+ """
32
+ Initialize a new A4E agent project
33
+
34
+ Args:
35
+ name: Agent ID (lowercase, hyphens, e.g., "nutrition-coach")
36
+ display_name: Human-readable name (e.g., "Nutrition Coach")
37
+ description: Short description of the agent
38
+ category: Agent category for marketplace
39
+ template: Project template (basic=files only, with-tools=example tool, with-views=example view, full=both)
40
+ project_path: Base directory where the agent folder will be created.
41
+ The agent will be created at {project_path}/{name}/.
42
+ If not provided, uses the current workspace directory.
43
+
44
+ Returns:
45
+ Project details with created files and next steps
46
+ """
47
+ # Validate name format
48
+ if not name.replace("-", "").replace("_", "").isalnum():
49
+ return {
50
+ "success": False,
51
+ "error": "Agent name must be alphanumeric with hyphens/underscores only",
52
+ }
53
+
54
+ # Determine project directory
55
+ if project_path:
56
+ # Use explicit path provided by the LLM/user
57
+ base_dir = Path(project_path).resolve()
58
+ if not base_dir.exists():
59
+ return {
60
+ "success": False,
61
+ "error": f"Project path does not exist: {project_path}",
62
+ }
63
+ if not base_dir.is_dir():
64
+ return {
65
+ "success": False,
66
+ "error": f"Project path is not a directory: {project_path}",
67
+ }
68
+ # Create agent directly in the provided path
69
+ project_dir = base_dir / name
70
+ else:
71
+ # Use automatic detection (env var, cwd, etc.)
72
+ project_dir = get_project_dir(name)
73
+
74
+ if project_dir.exists():
75
+ return {"success": False, "error": f"Directory '{project_dir}' already exists"}
76
+
77
+ try:
78
+ # Ensure file-store/agent-store structure exists
79
+ agent_store_root = project_dir.parent
80
+ agent_store_root.mkdir(parents=True, exist_ok=True)
81
+
82
+ # Create agent directory
83
+ project_dir.mkdir(exist_ok=True)
84
+ (project_dir / "prompts").mkdir(exist_ok=True)
85
+ (project_dir / "tools").mkdir(exist_ok=True)
86
+ (project_dir / "views").mkdir(exist_ok=True)
87
+ (project_dir / "skills").mkdir(exist_ok=True)
88
+
89
+ # Sanitize inputs before template rendering
90
+ safe_name = sanitize_input(name)
91
+
92
+ # Generate agent.py
93
+ agent_template = jinja_env.get_template("agent.py.j2")
94
+ agent_code = agent_template.render(agent_id=safe_name)
95
+ (project_dir / "agent.py").write_text(agent_code)
96
+
97
+ # Generate metadata.json
98
+ metadata_template = jinja_env.get_template("metadata.json.j2")
99
+ # Sanitize text inputs (allow spaces and common punctuation for display_name and description)
100
+ safe_display_name = sanitize_input(display_name, r"a-zA-Z0-9 _-")
101
+ safe_description = sanitize_input(description, r"a-zA-Z0-9 .,!?_-")
102
+ metadata = metadata_template.render(
103
+ agent_id=safe_name,
104
+ display_name=safe_display_name,
105
+ description=safe_description,
106
+ category=category,
107
+ )
108
+ (project_dir / "metadata.json").write_text(metadata)
109
+
110
+ # Generate prompts/agent.md
111
+ prompt_template = jinja_env.get_template("prompt.md.j2")
112
+ prompt = prompt_template.render(
113
+ display_name=safe_display_name,
114
+ category=category,
115
+ description=safe_description,
116
+ )
117
+ (project_dir / "prompts/agent.md").write_text(prompt)
118
+ (project_dir / "prompts/reviewer.md").write_text("")
119
+ (project_dir / "prompts/view_renderer.md").write_text("")
120
+
121
+ # Generate AGENTS.md (root context file)
122
+ agents_template = jinja_env.get_template("agents.md.j2")
123
+ agents_md = agents_template.render(
124
+ agent_id=safe_name,
125
+ display_name=safe_display_name,
126
+ category=category,
127
+ description=safe_description,
128
+ )
129
+ (project_dir / "AGENTS.md").write_text(agents_md)
130
+
131
+ # Generate subdirectory AGENTS.md files for AI coding agents
132
+ tools_agents_template = jinja_env.get_template("tools/agent.md.j2")
133
+ (project_dir / "tools" / "AGENTS.md").write_text(tools_agents_template.render())
134
+
135
+ views_agents_template = jinja_env.get_template("views/agent.md.j2")
136
+ (project_dir / "views" / "AGENTS.md").write_text(views_agents_template.render())
137
+
138
+ prompts_agents_template = jinja_env.get_template("prompts/agent.md.j2")
139
+ (project_dir / "prompts" / "AGENTS.md").write_text(prompts_agents_template.render())
140
+
141
+ # Generate skills/AGENTS.md (skills documentation)
142
+ skills_agents_template = jinja_env.get_template("skills/agents.md.j2")
143
+ skills_agents_md = skills_agents_template.render(agent_id=safe_name)
144
+ (project_dir / "skills/AGENTS.md").write_text(skills_agents_md)
145
+
146
+ # Create welcome view (MANDATORY)
147
+ from ..views.helpers import create_view
148
+ create_view(
149
+ view_id="welcome",
150
+ description="Welcome view for the agent",
151
+ props={"title": {"type": "string", "description": "Welcome title"}},
152
+ project_dir=project_dir,
153
+ )
154
+
155
+ # Create example content based on template
156
+ if template in ["with-tools", "full"]:
157
+ # Create example tool
158
+ example_tool_code = '''from a4e.sdk import tool
159
+ from typing import Optional, Any
160
+
161
+ @tool
162
+ def example_tool(
163
+ query: str,
164
+ max_results: Optional[int] = 10
165
+ ) -> dict:
166
+ """
167
+ Example tool that demonstrates basic functionality
168
+
169
+ Args:
170
+ query: Search query or input text
171
+ max_results: Maximum number of results to return
172
+ """
173
+ # TODO: Implement your tool logic here
174
+ return {
175
+ "status": "success",
176
+ "message": f"Processed query: {query}",
177
+ "results": []
178
+ }
179
+ '''
180
+ (project_dir / "tools" / "example_tool.py").write_text(example_tool_code)
181
+
182
+ if template in ["with-views", "full"]:
183
+ # Create example view (in addition to welcome)
184
+ create_view(
185
+ view_id="example_view",
186
+ description="Example view demonstrating props usage",
187
+ props={
188
+ "title": {"type": "string", "description": "View title"},
189
+ "count": {"type": "number", "description": "Count value"},
190
+ },
191
+ project_dir=project_dir,
192
+ )
193
+
194
+ # Create welcome skill (connects welcome view)
195
+ from ..skills.helpers import create_skill
196
+ create_skill(
197
+ skill_id="show_welcome",
198
+ name="Show Welcome",
199
+ description="Display the welcome screen. Use when user wants to go home or start over.",
200
+ intent_triggers=["start over", "go home", "main menu", "welcome", "inicio", "volver al inicio"],
201
+ output_view="welcome",
202
+ internal_tools=[],
203
+ requires_auth=False,
204
+ view_props={"title": {"type": "string", "description": "Welcome title"}},
205
+ project_dir=project_dir,
206
+ )
207
+
208
+ # Auto-generate schemas after project initialization
209
+ from ..schemas import generate_schemas
210
+ generate_schemas(force=False, agent_name=name)
211
+
212
+ _PROJECT_DIR = get_configured_project_dir()
213
+ return {
214
+ "success": True,
215
+ "message": f"Initialized agent '{name}'",
216
+ "path": str(project_dir),
217
+ "diagnostic": {
218
+ "workspace_env": os.environ.get("A4E_WORKSPACE"),
219
+ "project_dir_flag": str(_PROJECT_DIR) if _PROJECT_DIR else None,
220
+ "detected_root": str(get_project_dir()),
221
+ "cwd": str(Path.cwd()),
222
+ },
223
+ "next_steps": [
224
+ f"Add tools: add_tool(..., agent_name='{name}')",
225
+ f"Add views: add_view(..., agent_name='{name}')",
226
+ f"Add skills: add_skill(..., agent_name='{name}')",
227
+ "Start dev server using 'dev_start'",
228
+ ],
229
+ }
230
+ except Exception as e:
231
+ return {"success": False, "error": str(e)}
@@ -0,0 +1,8 @@
1
+ """
2
+ Schema generation tools.
3
+ """
4
+
5
+ from .generate_schemas import generate_schemas
6
+
7
+ __all__ = ["generate_schemas"]
8
+