Skip to content

Commit 84a0903

Browse files
authored
Merge pull request #11 from jhd3197/dev
Migrate Prompture integration to async API
2 parents a0f371c + b81019c commit 84a0903

13 files changed

Lines changed: 113 additions & 85 deletions

File tree

agentsite/agents/designer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from prompture import Agent
5+
from prompture import AsyncAgent as Agent
66

77
from ..engine.capabilities import supports_structured_output
88
from ..models import StyleSpec

agentsite/agents/developer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from prompture import Agent
5+
from prompture import AsyncAgent as Agent
66

77
from ..engine.capabilities import supports_tools
88
from .personas import DEVELOPER_PERSONA

agentsite/agents/orchestrator.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
from typing import Any
66

7-
from prompture import GroupCallbacks, LoopGroup, SequentialGroup
7+
from prompture import AsyncLoopGroup, AsyncSequentialGroup, GroupCallbacks
88

99
from ..config import settings
1010
from ..models import AgentConfig
@@ -21,7 +21,7 @@ def create_pipeline(
2121
max_review_iterations: int | None = None,
2222
review_threshold: int | None = None,
2323
agent_configs: dict[str, AgentConfig] | None = None,
24-
) -> SequentialGroup:
24+
) -> AsyncSequentialGroup:
2525
"""Build the full generation pipeline (static — all 4 agents).
2626
2727
Pipeline structure::
@@ -60,7 +60,7 @@ def _exit_condition(state: dict[str, Any], iteration: int) -> bool:
6060
lower = feedback_text.lower()
6161
return '"approved": true' in lower or '"approved":true' in lower
6262

63-
build_review_loop = LoopGroup(
63+
build_review_loop = AsyncLoopGroup(
6464
[
6565
(
6666
developer,
@@ -92,7 +92,7 @@ def _exit_condition(state: dict[str, Any], iteration: int) -> bool:
9292
)
9393

9494
# Full pipeline
95-
pipeline = SequentialGroup(
95+
pipeline = AsyncSequentialGroup(
9696
[
9797
(pm, "{prompt}"),
9898
(
@@ -120,7 +120,7 @@ def create_dynamic_pipeline(
120120
review_threshold: int | None = None,
121121
agent_configs: dict[str, AgentConfig] | None = None,
122122
error_policy: Any = None,
123-
) -> SequentialGroup:
123+
) -> AsyncSequentialGroup:
124124
"""Build a dynamic pipeline based on PM's required_agents output.
125125
126126
PM always runs before this. This builds the remaining pipeline steps
@@ -169,7 +169,7 @@ def _exit_condition(state: dict[str, Any], iteration: int) -> bool:
169169
return True
170170
return False
171171

172-
build_review_loop = LoopGroup(
172+
build_review_loop = AsyncLoopGroup(
173173
[
174174
(
175175
developer,
@@ -220,7 +220,7 @@ def _exit_condition(state: dict[str, Any], iteration: int) -> bool:
220220
kwargs: dict[str, Any] = {"callbacks": callbacks}
221221
if error_policy is not None:
222222
kwargs["error_policy"] = error_policy
223-
return SequentialGroup(steps, **kwargs)
223+
return AsyncSequentialGroup(steps, **kwargs)
224224

225225

226226
def _agent_model(

agentsite/agents/pm.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from __future__ import annotations
44

5-
from prompture import Agent
5+
from prompture import AsyncAgent as Agent
66

77
from ..engine.capabilities import supports_structured_output
88
from ..models import SitePlan

agentsite/agents/reviewer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import json
66

7-
from prompture import Agent
7+
from prompture import AsyncAgent as Agent
88

99
from ..engine.capabilities import supports_structured_output, supports_tools
1010
from ..models import ReviewFeedback

agentsite/api/routes/generate.py

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44

55
import asyncio
66
import logging
7-
from concurrent.futures import ThreadPoolExecutor
87
from datetime import datetime, timezone
98

109
from fastapi import APIRouter, Depends, HTTPException, WebSocket, WebSocketDisconnect
@@ -18,10 +17,6 @@
1817
logger = logging.getLogger("agentsite.api.generate")
1918
router = APIRouter(tags=["generate"])
2019

21-
# Thread pool for running sync Prompture pipelines
22-
_executor = ThreadPoolExecutor(max_workers=2, thread_name_prefix="agentsite-gen")
23-
24-
2520
class GenerateRequest(BaseModel):
2621
prompt: str = ""
2722
model: str = ""
@@ -82,9 +77,7 @@ async def start_generation(
8277
)
8378
await version_repo.create(version)
8479

85-
# Get event loop for WS bridge
86-
loop = asyncio.get_running_loop()
87-
on_event = ws_manager.make_callback(project_id, loop)
80+
on_event = ws_manager.make_callback(project_id)
8881

8982
# Load agent configs from DB for pipeline customization
9083
configs_list = await agent_config_repo.list_all()
@@ -93,17 +86,13 @@ async def start_generation(
9386
# Build pipeline
9487
pipeline = GenerationPipeline(pm, on_event=on_event, agent_configs=agent_configs)
9588

96-
# Run in thread pool (Prompture groups are synchronous)
9789
async def _run():
9890
try:
99-
result = await loop.run_in_executor(
100-
_executor,
101-
lambda: pipeline.generate(
102-
project,
103-
slug=slug,
104-
version_number=version_number,
105-
page_prompt=prompt,
106-
),
91+
result = await pipeline.generate(
92+
project,
93+
slug=slug,
94+
version_number=version_number,
95+
page_prompt=prompt,
10796
)
10897
# Read generated files from disk into version record
10998
file_list = pm.list_version_files(project.id, slug, version_number)

agentsite/api/websocket.py

Lines changed: 4 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,7 @@
22

33
from __future__ import annotations
44

5-
import asyncio
6-
import json
75
import logging
8-
from typing import Any
96

107
from fastapi import WebSocket
118

@@ -50,16 +47,11 @@ async def broadcast(self, project_id: str, event: WSEvent) -> None:
5047
for ws in dead:
5148
self.disconnect(project_id, ws)
5249

53-
def make_callback(self, project_id: str, loop: asyncio.AbstractEventLoop):
54-
"""Create a sync callback that bridges to async broadcast.
50+
def make_callback(self, project_id: str):
51+
"""Return an async callback for GenerationPipeline.on_event."""
5552

56-
Returns a callable suitable for GenerationPipeline.on_event.
57-
"""
58-
59-
def _on_event(event: WSEvent) -> None:
60-
asyncio.run_coroutine_threadsafe(
61-
self.broadcast(project_id, event), loop
62-
)
53+
async def _on_event(event: WSEvent) -> None:
54+
await self.broadcast(project_id, event)
6355

6456
return _on_event
6557

agentsite/cli.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
from __future__ import annotations
44

5+
import asyncio
56
import json
67
import sys
78

@@ -99,11 +100,13 @@ def _on_event(event):
99100
pipeline = GenerationPipeline(pm, on_event=_on_event)
100101

101102
try:
102-
result = pipeline.generate(
103-
project,
104-
slug=page,
105-
version_number=1,
106-
page_prompt=prompt,
103+
result = asyncio.run(
104+
pipeline.generate(
105+
project,
106+
slug=page,
107+
version_number=1,
108+
page_prompt=prompt,
109+
)
107110
)
108111
version_dir = pm.version_dir(project.id, page, 1)
109112

0 commit comments

Comments
 (0)