agentsite 0.0.2.dev1__tar.gz → 0.0.3.dev1__tar.gz

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 (50) hide show
  1. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/PKG-INFO +1 -1
  2. agentsite-0.0.3.dev1/agentsite/agents/designer.py +41 -0
  3. agentsite-0.0.3.dev1/agentsite/agents/developer.py +75 -0
  4. agentsite-0.0.3.dev1/agentsite/agents/pm.py +41 -0
  5. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/engine/pipeline.py +158 -11
  6. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/PKG-INFO +1 -1
  7. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/pyproject.toml +1 -1
  8. agentsite-0.0.2.dev1/agentsite/agents/designer.py +0 -20
  9. agentsite-0.0.2.dev1/agentsite/agents/developer.py +0 -27
  10. agentsite-0.0.2.dev1/agentsite/agents/pm.py +0 -20
  11. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/README.md +0 -0
  12. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/__init__.py +0 -0
  13. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/agents/__init__.py +0 -0
  14. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/agents/orchestrator.py +0 -0
  15. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/agents/personas.py +0 -0
  16. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/agents/reviewer.py +0 -0
  17. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/agents/tools.py +0 -0
  18. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/__init__.py +0 -0
  19. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/app.py +0 -0
  20. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/deps.py +0 -0
  21. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/__init__.py +0 -0
  22. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/agents.py +0 -0
  23. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/assets.py +0 -0
  24. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/generate.py +0 -0
  25. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/models.py +0 -0
  26. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/preview.py +0 -0
  27. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/projects.py +0 -0
  28. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/routes/providers.py +0 -0
  29. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/api/websocket.py +0 -0
  30. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/cli.py +0 -0
  31. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/config.py +0 -0
  32. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/engine/__init__.py +0 -0
  33. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/engine/asset_handler.py +0 -0
  34. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/engine/gemini_patch.py +0 -0
  35. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/engine/project_manager.py +0 -0
  36. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/models.py +0 -0
  37. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/storage/__init__.py +0 -0
  38. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/storage/database.py +0 -0
  39. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite/storage/repository.py +0 -0
  40. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/SOURCES.txt +0 -0
  41. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/dependency_links.txt +0 -0
  42. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/entry_points.txt +0 -0
  43. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/requires.txt +0 -0
  44. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/agentsite.egg-info/top_level.txt +0 -0
  45. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/setup.cfg +0 -0
  46. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/tests/test_agents.py +0 -0
  47. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/tests/test_api.py +0 -0
  48. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/tests/test_models.py +0 -0
  49. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/tests/test_project_manager.py +0 -0
  50. {agentsite-0.0.2.dev1 → agentsite-0.0.3.dev1}/tests/test_storage.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentsite
3
- Version: 0.0.2.dev1
3
+ Version: 0.0.3.dev1
4
4
  Summary: AI-Powered Website Builder using Prompture agent orchestration
5
5
  Author-email: Juan Denis <juan@vene.co>
6
6
  License-Expression: MIT
@@ -0,0 +1,41 @@
1
+ """Designer agent factory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from prompture import Agent
6
+
7
+ from ..models import StyleSpec
8
+ from .personas import DESIGNER_PERSONA
9
+
10
+
11
+ def create_designer_agent(model: str) -> Agent:
12
+ """Create the Designer agent that produces a StyleSpec."""
13
+ return Agent(
14
+ model,
15
+ system_prompt=DESIGNER_PERSONA,
16
+ output_type=StyleSpec,
17
+ name="designer",
18
+ description="Defines visual design system (colors, fonts, spacing)",
19
+ output_key="style_spec",
20
+ )
21
+
22
+
23
+ def create_designer_agent_plain(model: str) -> Agent:
24
+ """Create a Designer agent WITHOUT output_type for models that don't support structured output.
25
+
26
+ Uses explicit JSON instructions in the system prompt instead of schema enforcement.
27
+ The caller is responsible for parsing the JSON output manually.
28
+ """
29
+ json_schema = StyleSpec.model_json_schema()
30
+ return Agent(
31
+ model,
32
+ system_prompt=(
33
+ DESIGNER_PERSONA.system_prompt
34
+ + "\n\nIMPORTANT: You MUST respond with ONLY a valid JSON object matching this schema:\n"
35
+ + f"```json\n{__import__('json').dumps(json_schema, indent=2)}\n```\n"
36
+ "Do NOT include any text before or after the JSON. Return ONLY the JSON object."
37
+ ),
38
+ name="designer",
39
+ description="Defines visual design system (plain text mode)",
40
+ output_key="style_spec",
41
+ )
@@ -0,0 +1,75 @@
1
+ """Developer agent factory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from prompture import Agent
6
+
7
+ from .personas import DEVELOPER_PERSONA
8
+ from .tools import list_files, read_file, write_file
9
+
10
+
11
+ def create_developer_agent(model: str) -> Agent:
12
+ """Create the Developer agent that generates page files.
13
+
14
+ Note: No ``output_type`` is set because the developer writes files
15
+ via the ``write_file`` tool. Forcing structured-output parsing on the
16
+ final text response causes failures when the LLM returns empty text
17
+ after finishing its tool calls. The pipeline already handles file
18
+ extraction from both tool-written files and raw output text.
19
+ """
20
+ return Agent(
21
+ model,
22
+ system_prompt=DEVELOPER_PERSONA,
23
+ tools=[write_file, read_file, list_files],
24
+ name="developer",
25
+ description="Generates HTML/CSS/JS files for each page",
26
+ output_key="page_output",
27
+ )
28
+
29
+
30
+ def create_developer_agent_plain(model: str) -> Agent:
31
+ """Create a Developer agent WITHOUT tools for models that don't support tool calling.
32
+
33
+ Instead of using write_file/read_file tools, this agent outputs file contents
34
+ directly in its response using markdown fenced code blocks. The pipeline's
35
+ existing fallback extraction logic (_extract_fenced_blocks, _try_extract_raw_html)
36
+ handles parsing the output into files on disk.
37
+ """
38
+ return Agent(
39
+ model,
40
+ system_prompt=(
41
+ "You are an expert frontend developer. You build complete, production-ready "
42
+ "web pages using semantic HTML5, modern CSS, and vanilla JavaScript.\n\n"
43
+ "WORKFLOW — you MUST follow this exact output format:\n"
44
+ "Output each file using markdown fenced code blocks with the language tag.\n"
45
+ "You MUST generate at least an index.html file.\n\n"
46
+ "Example output format:\n"
47
+ "```html\n"
48
+ "<!DOCTYPE html>\n"
49
+ "<html>...</html>\n"
50
+ "```\n\n"
51
+ "```css\n"
52
+ "/* styles.css */\n"
53
+ "body { ... }\n"
54
+ "```\n\n"
55
+ "```javascript\n"
56
+ "// script.js\n"
57
+ "document.addEventListener('DOMContentLoaded', ...);\n"
58
+ "```\n\n"
59
+ "Requirements:\n"
60
+ "- Write clean, semantic HTML with proper heading hierarchy\n"
61
+ "- Use CSS custom properties for theming (colors, fonts, spacing)\n"
62
+ "- Make pages fully responsive (mobile-first approach)\n"
63
+ "- Include smooth transitions and subtle animations\n"
64
+ "- Add proper meta tags, viewport settings, and favicon links\n"
65
+ "- Use Google Fonts via CDN link\n"
66
+ "- Write accessible markup (ARIA labels, alt text, focus styles)\n\n"
67
+ "Generate complete, self-contained files. Every HTML page should be fully functional "
68
+ "when opened directly in a browser.\n\n"
69
+ "IMPORTANT: Output ONLY the fenced code blocks with complete file contents. "
70
+ "Do not include any other text or explanation."
71
+ ),
72
+ name="developer",
73
+ description="Generates HTML/CSS/JS files for each page (plain text mode)",
74
+ output_key="page_output",
75
+ )
@@ -0,0 +1,41 @@
1
+ """Project Manager agent factory."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from prompture import Agent
6
+
7
+ from ..models import SitePlan
8
+ from .personas import PM_PERSONA
9
+
10
+
11
+ def create_pm_agent(model: str) -> Agent:
12
+ """Create the PM agent that produces a SitePlan."""
13
+ return Agent(
14
+ model,
15
+ system_prompt=PM_PERSONA,
16
+ output_type=SitePlan,
17
+ name="pm",
18
+ description="Plans website structure and pages",
19
+ output_key="site_plan",
20
+ )
21
+
22
+
23
+ def create_pm_agent_plain(model: str) -> Agent:
24
+ """Create a PM agent WITHOUT output_type for models that don't support structured output.
25
+
26
+ Uses explicit JSON instructions in the system prompt instead of schema enforcement.
27
+ The caller is responsible for parsing the JSON output manually.
28
+ """
29
+ json_schema = SitePlan.model_json_schema()
30
+ return Agent(
31
+ model,
32
+ system_prompt=(
33
+ PM_PERSONA.system_prompt
34
+ + "\n\nIMPORTANT: You MUST respond with ONLY a valid JSON object matching this schema:\n"
35
+ + f"```json\n{__import__('json').dumps(json_schema, indent=2)}\n```\n"
36
+ "Do NOT include any text before or after the JSON. Return ONLY the JSON object."
37
+ ),
38
+ name="pm",
39
+ description="Plans website structure and pages (plain text mode)",
40
+ output_key="site_plan",
41
+ )
@@ -11,7 +11,7 @@ from typing import Any
11
11
 
12
12
  from prompture import GroupCallbacks, GroupResult, SequentialGroup
13
13
 
14
- from ..agents.orchestrator import create_dynamic_pipeline
14
+ from ..agents.orchestrator import _agent_model, create_dynamic_pipeline
15
15
  from ..config import settings
16
16
  from ..models import AgentConfig, AgentRun, PageOutput, Project, SitePlan, StyleSpec, WSEvent
17
17
  from .gemini_patch import apply_gemini_patch
@@ -106,6 +106,7 @@ class GenerationPipeline:
106
106
  self._run_start_times: dict[str, float] = {}
107
107
  self._developer_output_text: str = "" # direct capture from callback
108
108
  self._developer_tool_calls: list[dict] = [] # tool calls from developer agent
109
+ self._agent_models: dict[str, str] = {} # agent_key -> resolved model name
109
110
 
110
111
  def _emit(self, event_type: str, agent: str = "", data: dict[str, Any] | None = None) -> None:
111
112
  """Fire a WebSocket event if a callback is registered."""
@@ -146,7 +147,8 @@ class GenerationPipeline:
146
147
  def _on_agent_start(name: str, prompt: str) -> None:
147
148
  agent_key = _agent_name_to_key(name)
148
149
  started_at = datetime.now(timezone.utc).isoformat()
149
- self._emit("agent_start", agent=agent_key, data={"started_at": started_at})
150
+ agent_model = self._agent_models.get(agent_key, "")
151
+ self._emit("agent_start", agent=agent_key, data={"started_at": started_at, "model": agent_model})
150
152
  run = AgentRun(
151
153
  project_id=project.id,
152
154
  page_slug=slug,
@@ -207,6 +209,7 @@ class GenerationPipeline:
207
209
  ", ".join(f"{k}=...({len(str(v))})" for k, v in (tc.get("arguments") or {}).items()),
208
210
  )
209
211
 
212
+ agent_model = self._agent_models.get(agent_key, "")
210
213
  self._emit(
211
214
  "agent_complete",
212
215
  agent=agent_key,
@@ -216,6 +219,7 @@ class GenerationPipeline:
216
219
  "input_tokens": input_tokens,
217
220
  "output_tokens": output_tokens,
218
221
  "tool_calls_count": len(tool_calls),
222
+ "model": agent_model,
219
223
  },
220
224
  )
221
225
 
@@ -249,11 +253,14 @@ class GenerationPipeline:
249
253
  self._emit("phase_start", data={"phase": "planning", "slug": slug, "version": version_number})
250
254
 
251
255
  try:
252
- # --- Phase A: Run PM agent standalone to get SitePlan ---
253
- from ..agents.orchestrator import _agent_model
256
+ # --- Resolve model for each agent and store for WS events ---
254
257
  from ..agents.pm import create_pm_agent
255
258
 
256
- pm_model = _agent_model("pm", model, self._agent_configs)
259
+ for agent_key in ("pm", "designer", "developer", "reviewer"):
260
+ self._agent_models[agent_key] = _agent_model(agent_key, model, self._agent_configs)
261
+
262
+ # --- Phase A: Run PM agent standalone to get SitePlan ---
263
+ pm_model = self._agent_models["pm"]
257
264
  pm_agent = create_pm_agent(pm_model)
258
265
 
259
266
  pm_callbacks = GroupCallbacks(
@@ -268,8 +275,26 @@ class GenerationPipeline:
268
275
  )
269
276
  _patch_pipeline_deps(pm_pipeline, deps)
270
277
 
271
- pm_result = pm_pipeline.run(page_prompt)
272
- site_plan_text = pm_result.shared_state.get("site_plan", "")
278
+ try:
279
+ pm_result = pm_pipeline.run(page_prompt)
280
+ site_plan_text = pm_result.shared_state.get("site_plan", "")
281
+ except Exception as pm_exc:
282
+ # Fallback: retry PM without structured output (for models like Kimi K2.5)
283
+ logger.warning(
284
+ "PM agent failed with structured output, retrying in plain text mode: %s",
285
+ pm_exc,
286
+ )
287
+ from ..agents.pm import create_pm_agent_plain
288
+
289
+ pm_agent_plain = create_pm_agent_plain(pm_model)
290
+ pm_pipeline_plain = SequentialGroup(
291
+ [(pm_agent_plain, "{prompt}")],
292
+ callbacks=pm_callbacks,
293
+ state={"prompt": page_prompt},
294
+ )
295
+ _patch_pipeline_deps(pm_pipeline_plain, deps)
296
+ pm_result = pm_pipeline_plain.run(page_prompt)
297
+ site_plan_text = pm_result.shared_state.get("site_plan", "")
273
298
 
274
299
  # Parse required_agents from the PM output
275
300
  required_agents = ["designer", "developer", "reviewer"] # default
@@ -289,8 +314,7 @@ class GenerationPipeline:
289
314
  all_agents = ["pm"] + [a for a in required_agents]
290
315
  self._emit("pipeline_plan", data={"required_agents": all_agents})
291
316
 
292
- # --- Phase B: Build dynamic pipeline for remaining agents ---
293
- # If designer is skipped, inject a default style_spec
317
+ # --- Phase B: Run Designer standalone (with fallback) if needed ---
294
318
  initial_state = {
295
319
  "prompt": page_prompt,
296
320
  "site_plan": site_plan_text,
@@ -299,15 +323,76 @@ class GenerationPipeline:
299
323
  "logo_url": project.logo_url or "",
300
324
  "icon_url": project.icon_url or "",
301
325
  }
302
- if "designer" not in required_agents:
326
+
327
+ if "designer" in required_agents:
328
+ from prompture import clean_json_text
329
+
330
+ from ..agents.designer import create_designer_agent, create_designer_agent_plain
331
+
332
+ designer_model = self._agent_models["designer"]
333
+ designer_agent = create_designer_agent(designer_model)
334
+ designer_prompt = (
335
+ "Design a visual style for this website:\n\n"
336
+ f"Site Plan: {site_plan_text}\n\n"
337
+ f"Logo URL: {project.logo_url or ''}\n"
338
+ f"Icon URL: {project.icon_url or ''}\n\n"
339
+ "Create a cohesive color scheme, typography, and spacing system."
340
+ )
341
+
342
+ designer_callbacks = GroupCallbacks(
343
+ on_agent_start=_on_agent_start,
344
+ on_agent_complete=_on_agent_complete,
345
+ on_agent_error=_on_agent_error,
346
+ )
347
+
348
+ try:
349
+ designer_pipeline = SequentialGroup(
350
+ [(designer_agent, "{designer_prompt}")],
351
+ callbacks=designer_callbacks,
352
+ state={"designer_prompt": designer_prompt},
353
+ )
354
+ _patch_pipeline_deps(designer_pipeline, deps)
355
+ designer_result = designer_pipeline.run(designer_prompt)
356
+ style_spec_text = designer_result.shared_state.get("style_spec", "")
357
+ except Exception as designer_exc:
358
+ # Fallback: retry Designer without structured output
359
+ logger.warning(
360
+ "Designer agent failed with structured output, retrying in plain text mode: %s",
361
+ designer_exc,
362
+ )
363
+ designer_agent_plain = create_designer_agent_plain(designer_model)
364
+ designer_pipeline_plain = SequentialGroup(
365
+ [(designer_agent_plain, "{designer_prompt}")],
366
+ callbacks=designer_callbacks,
367
+ state={"designer_prompt": designer_prompt},
368
+ )
369
+ _patch_pipeline_deps(designer_pipeline_plain, deps)
370
+ designer_result = designer_pipeline_plain.run(designer_prompt)
371
+ style_spec_text = designer_result.shared_state.get("style_spec", "")
372
+
373
+ initial_state["style_spec"] = style_spec_text
374
+
375
+ # Merge designer usage into pm_result for later aggregation
376
+ if hasattr(designer_result, 'aggregate_usage'):
377
+ if not hasattr(pm_result, 'aggregate_usage'):
378
+ pm_result.aggregate_usage = {}
379
+ for k, v in designer_result.aggregate_usage.items():
380
+ if isinstance(v, (int, float)):
381
+ pm_result.aggregate_usage[k] = pm_result.aggregate_usage.get(k, 0) + v
382
+
383
+ # Remove designer from remaining pipeline since we ran it here
384
+ remaining_agents = [a for a in required_agents if a != "designer"]
385
+ else:
386
+ remaining_agents = list(required_agents)
303
387
  # Use project's existing style_spec or sensible defaults
304
388
  if project.style_spec:
305
389
  initial_state["style_spec"] = project.style_spec.model_dump_json()
306
390
  else:
307
391
  initial_state["style_spec"] = StyleSpec().model_dump_json()
308
392
 
393
+ # --- Phase C: Build dynamic pipeline for developer+reviewer ---
309
394
  remaining_pipeline = create_dynamic_pipeline(
310
- required_agents,
395
+ remaining_agents,
311
396
  model,
312
397
  callbacks=group_callbacks,
313
398
  agent_configs=self._agent_configs,
@@ -324,6 +409,68 @@ class GenerationPipeline:
324
409
  # Merge nested group state back so we can access page_output
325
410
  _merge_nested_group_state(remaining_pipeline)
326
411
 
412
+ # Detect developer failure: Prompture's SequentialGroup catches
413
+ # agent errors internally (doesn't re-raise), so check for a
414
+ # failed result with no files and no developer output.
415
+ _dev_failed = (
416
+ not result.success
417
+ or (
418
+ not written_files
419
+ and not self._developer_output_text
420
+ and not self._developer_tool_calls
421
+ )
422
+ )
423
+ if _dev_failed and not written_files:
424
+ dev_errors = [
425
+ e for e in getattr(result, "errors", [])
426
+ if getattr(e, "agent_name", "") in ("developer", "agentsite_developer")
427
+ ]
428
+ logger.warning(
429
+ "Developer pipeline produced no output (success=%s, errors=%d, "
430
+ "written_files=%d, dev_output_len=%d, tool_calls=%d). "
431
+ "Retrying with plain text developer.",
432
+ result.success,
433
+ len(dev_errors),
434
+ len(written_files),
435
+ len(self._developer_output_text),
436
+ len(self._developer_tool_calls),
437
+ )
438
+ from ..agents.developer import create_developer_agent_plain
439
+
440
+ dev_model = self._agent_models["developer"]
441
+ dev_agent_plain = create_developer_agent_plain(dev_model)
442
+
443
+ dev_prompt = (
444
+ "Build the website page based on this plan:\n\n"
445
+ f"Site Plan: {initial_state['site_plan']}\n\n"
446
+ f"Style Spec: {initial_state.get('style_spec', '')}\n\n"
447
+ f"Logo URL: {initial_state.get('logo_url', '')}\n"
448
+ f"Icon URL: {initial_state.get('icon_url', '')}\n\n"
449
+ "Generate complete, self-contained HTML with inline or linked CSS/JS."
450
+ )
451
+
452
+ dev_callbacks = GroupCallbacks(
453
+ on_agent_start=_on_agent_start,
454
+ on_agent_complete=_on_agent_complete,
455
+ on_agent_error=_on_agent_error,
456
+ )
457
+ dev_pipeline_plain = SequentialGroup(
458
+ [(dev_agent_plain, "{dev_prompt}")],
459
+ callbacks=dev_callbacks,
460
+ state={"dev_prompt": dev_prompt},
461
+ )
462
+ _patch_pipeline_deps(dev_pipeline_plain, deps)
463
+ plain_result = dev_pipeline_plain.run(dev_prompt)
464
+
465
+ # Use the plain result's usage and state
466
+ if hasattr(plain_result, 'aggregate_usage'):
467
+ if not hasattr(result, 'aggregate_usage'):
468
+ result.aggregate_usage = {}
469
+ for k, v in plain_result.aggregate_usage.items():
470
+ if isinstance(v, (int, float)):
471
+ result.aggregate_usage[k] = result.aggregate_usage.get(k, 0) + v
472
+ result = plain_result
473
+
327
474
  # Merge usage from both phases
328
475
  combined_usage = pm_result.aggregate_usage.copy() if hasattr(pm_result, 'aggregate_usage') else {}
329
476
  if hasattr(result, 'aggregate_usage'):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: agentsite
3
- Version: 0.0.2.dev1
3
+ Version: 0.0.3.dev1
4
4
  Summary: AI-Powered Website Builder using Prompture agent orchestration
5
5
  Author-email: Juan Denis <juan@vene.co>
6
6
  License-Expression: MIT
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "agentsite"
7
- version = "0.0.2.dev1"
7
+ version = "0.0.3.dev1"
8
8
  description = "AI-Powered Website Builder using Prompture agent orchestration"
9
9
  readme = "README.md"
10
10
  license = "MIT"
@@ -1,20 +0,0 @@
1
- """Designer agent factory."""
2
-
3
- from __future__ import annotations
4
-
5
- from prompture import Agent
6
-
7
- from ..models import StyleSpec
8
- from .personas import DESIGNER_PERSONA
9
-
10
-
11
- def create_designer_agent(model: str) -> Agent:
12
- """Create the Designer agent that produces a StyleSpec."""
13
- return Agent(
14
- model,
15
- system_prompt=DESIGNER_PERSONA,
16
- output_type=StyleSpec,
17
- name="designer",
18
- description="Defines visual design system (colors, fonts, spacing)",
19
- output_key="style_spec",
20
- )
@@ -1,27 +0,0 @@
1
- """Developer agent factory."""
2
-
3
- from __future__ import annotations
4
-
5
- from prompture import Agent
6
-
7
- from .personas import DEVELOPER_PERSONA
8
- from .tools import list_files, read_file, write_file
9
-
10
-
11
- def create_developer_agent(model: str) -> Agent:
12
- """Create the Developer agent that generates page files.
13
-
14
- Note: No ``output_type`` is set because the developer writes files
15
- via the ``write_file`` tool. Forcing structured-output parsing on the
16
- final text response causes failures when the LLM returns empty text
17
- after finishing its tool calls. The pipeline already handles file
18
- extraction from both tool-written files and raw output text.
19
- """
20
- return Agent(
21
- model,
22
- system_prompt=DEVELOPER_PERSONA,
23
- tools=[write_file, read_file, list_files],
24
- name="developer",
25
- description="Generates HTML/CSS/JS files for each page",
26
- output_key="page_output",
27
- )
@@ -1,20 +0,0 @@
1
- """Project Manager agent factory."""
2
-
3
- from __future__ import annotations
4
-
5
- from prompture import Agent
6
-
7
- from ..models import SitePlan
8
- from .personas import PM_PERSONA
9
-
10
-
11
- def create_pm_agent(model: str) -> Agent:
12
- """Create the PM agent that produces a SitePlan."""
13
- return Agent(
14
- model,
15
- system_prompt=PM_PERSONA,
16
- output_type=SitePlan,
17
- name="pm",
18
- description="Plans website structure and pages",
19
- output_key="site_plan",
20
- )
File without changes
File without changes