mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-01-30 22:32:06 +00:00
Adding features work
This commit is contained in:
@@ -49,8 +49,8 @@ app.add_middleware(
|
||||
allow_origins=[
|
||||
"http://localhost:5173", # Vite dev server
|
||||
"http://127.0.0.1:5173",
|
||||
"http://localhost:8000", # Production
|
||||
"http://127.0.0.1:8000",
|
||||
"http://localhost:8888", # Production
|
||||
"http://127.0.0.1:8888",
|
||||
],
|
||||
allow_credentials=True,
|
||||
allow_methods=["*"],
|
||||
@@ -167,6 +167,6 @@ if __name__ == "__main__":
|
||||
uvicorn.run(
|
||||
"server.main:app",
|
||||
host="127.0.0.1", # Localhost only for security
|
||||
port=8000,
|
||||
port=8888,
|
||||
reload=True,
|
||||
)
|
||||
|
||||
@@ -136,13 +136,27 @@ async def spec_chat_websocket(websocket: WebSocket, project_name: str):
|
||||
# Create and start a new session
|
||||
session = await create_session(project_name)
|
||||
|
||||
# Track spec completion state
|
||||
spec_complete_received = False
|
||||
spec_path = None
|
||||
|
||||
# Stream the initial greeting
|
||||
async for chunk in session.start():
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
# Check for completion
|
||||
# Track spec_complete but don't send complete yet
|
||||
if chunk.get("type") == "spec_complete":
|
||||
await websocket.send_json({"type": "complete"})
|
||||
spec_complete_received = True
|
||||
spec_path = chunk.get("path")
|
||||
await websocket.send_json(chunk)
|
||||
continue
|
||||
|
||||
# When response_done arrives, send complete if spec was done
|
||||
if chunk.get("type") == "response_done":
|
||||
await websocket.send_json(chunk)
|
||||
if spec_complete_received:
|
||||
await websocket.send_json({"type": "complete", "path": spec_path})
|
||||
continue
|
||||
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
elif msg_type == "message":
|
||||
# User sent a message
|
||||
@@ -163,13 +177,27 @@ async def spec_chat_websocket(websocket: WebSocket, project_name: str):
|
||||
})
|
||||
continue
|
||||
|
||||
# Track spec completion state
|
||||
spec_complete_received = False
|
||||
spec_path = None
|
||||
|
||||
# Stream Claude's response
|
||||
async for chunk in session.send_message(user_content):
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
# Check for completion
|
||||
# Track spec_complete but don't send complete yet
|
||||
if chunk.get("type") == "spec_complete":
|
||||
await websocket.send_json({"type": "complete"})
|
||||
spec_complete_received = True
|
||||
spec_path = chunk.get("path")
|
||||
await websocket.send_json(chunk)
|
||||
continue
|
||||
|
||||
# When response_done arrives, send complete if spec was done
|
||||
if chunk.get("type") == "response_done":
|
||||
await websocket.send_json(chunk)
|
||||
if spec_complete_received:
|
||||
await websocket.send_json({"type": "complete", "path": spec_path})
|
||||
continue
|
||||
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
elif msg_type == "answer":
|
||||
# User answered a structured question
|
||||
@@ -196,12 +224,27 @@ async def spec_chat_websocket(websocket: WebSocket, project_name: str):
|
||||
else:
|
||||
user_response = str(answers)
|
||||
|
||||
# Track spec completion state
|
||||
spec_complete_received = False
|
||||
spec_path = None
|
||||
|
||||
# Stream Claude's response
|
||||
async for chunk in session.send_message(user_response):
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
# Track spec_complete but don't send complete yet
|
||||
if chunk.get("type") == "spec_complete":
|
||||
await websocket.send_json({"type": "complete"})
|
||||
spec_complete_received = True
|
||||
spec_path = chunk.get("path")
|
||||
await websocket.send_json(chunk)
|
||||
continue
|
||||
|
||||
# When response_done arrives, send complete if spec was done
|
||||
if chunk.get("type") == "response_done":
|
||||
await websocket.send_json(chunk)
|
||||
if spec_complete_received:
|
||||
await websocket.send_json({"type": "complete", "path": spec_path})
|
||||
continue
|
||||
|
||||
await websocket.send_json(chunk)
|
||||
|
||||
else:
|
||||
await websocket.send_json({
|
||||
|
||||
@@ -8,6 +8,7 @@ Uses the create-spec.md skill to guide users through app spec creation.
|
||||
|
||||
import asyncio
|
||||
import logging
|
||||
import shutil
|
||||
import threading
|
||||
from datetime import datetime
|
||||
from pathlib import Path
|
||||
@@ -87,15 +88,19 @@ class SpecChatSession:
|
||||
system_prompt = skill_content.replace("$ARGUMENTS", project_path)
|
||||
|
||||
# Create Claude SDK client with limited tools for spec creation
|
||||
# Use Opus for best quality spec generation
|
||||
# Use system CLI to avoid bundled Bun runtime crash (exit code 3) on Windows
|
||||
system_cli = shutil.which("claude")
|
||||
try:
|
||||
self.client = ClaudeSDKClient(
|
||||
options=ClaudeAgentOptions(
|
||||
model="claude-sonnet-4-20250514",
|
||||
model="claude-opus-4-5-20251101",
|
||||
cli_path=system_cli,
|
||||
system_prompt=system_prompt,
|
||||
allowed_tools=[
|
||||
"Read",
|
||||
"Write",
|
||||
"AskUserQuestion",
|
||||
"Glob",
|
||||
],
|
||||
max_turns=100,
|
||||
cwd=str(ROOT_DIR.resolve()),
|
||||
@@ -169,7 +174,7 @@ class SpecChatSession:
|
||||
"""
|
||||
Internal method to query Claude and stream responses.
|
||||
|
||||
Handles tool calls (AskUserQuestion, Write) and text responses.
|
||||
Handles tool calls (Write) and text responses.
|
||||
"""
|
||||
if not self.client:
|
||||
return
|
||||
@@ -178,6 +183,7 @@ class SpecChatSession:
|
||||
await self.client.query(message)
|
||||
|
||||
current_text = ""
|
||||
pending_spec_write = None # Track if we're waiting for app_spec.txt write result
|
||||
|
||||
# Stream the response using receive_response
|
||||
async for msg in self.client.receive_response():
|
||||
@@ -207,27 +213,17 @@ class SpecChatSession:
|
||||
tool_input = getattr(block, "input", {})
|
||||
tool_id = getattr(block, "id", "")
|
||||
|
||||
if tool_name == "AskUserQuestion":
|
||||
# Convert AskUserQuestion to structured UI
|
||||
questions = tool_input.get("questions", [])
|
||||
yield {
|
||||
"type": "question",
|
||||
"questions": questions,
|
||||
"tool_id": tool_id
|
||||
}
|
||||
# The SDK handles tool results internally
|
||||
|
||||
elif tool_name == "Write":
|
||||
# File being written - the SDK handles this
|
||||
if tool_name == "Write":
|
||||
# File being written - track for verification
|
||||
file_path = tool_input.get("file_path", "")
|
||||
|
||||
# Check if this is the app_spec.txt file
|
||||
# Track if this is the app_spec.txt file
|
||||
if "app_spec.txt" in str(file_path):
|
||||
self.complete = True
|
||||
yield {
|
||||
"type": "spec_complete",
|
||||
"path": str(file_path)
|
||||
pending_spec_write = {
|
||||
"tool_id": tool_id,
|
||||
"path": file_path
|
||||
}
|
||||
logger.info(f"Write tool called for app_spec.txt: {file_path}")
|
||||
|
||||
elif "initializer_prompt.md" in str(file_path):
|
||||
yield {
|
||||
@@ -236,15 +232,36 @@ class SpecChatSession:
|
||||
}
|
||||
|
||||
elif msg_type == "UserMessage" and hasattr(msg, "content"):
|
||||
# Tool results - the SDK handles these automatically
|
||||
# We just watch for any errors
|
||||
# Tool results - check for write confirmations and errors
|
||||
for block in msg.content:
|
||||
block_type = type(block).__name__
|
||||
if block_type == "ToolResultBlock":
|
||||
is_error = getattr(block, "is_error", False)
|
||||
tool_use_id = getattr(block, "tool_use_id", "")
|
||||
|
||||
if is_error:
|
||||
content = getattr(block, "content", "Unknown error")
|
||||
logger.warning(f"Tool error: {content}")
|
||||
# If the spec write failed, clear the pending write
|
||||
if pending_spec_write and tool_use_id == pending_spec_write.get("tool_id"):
|
||||
logger.error(f"app_spec.txt write failed: {content}")
|
||||
pending_spec_write = None
|
||||
else:
|
||||
# Tool succeeded - check if it was the spec write
|
||||
if pending_spec_write and tool_use_id == pending_spec_write.get("tool_id"):
|
||||
spec_path = pending_spec_write["path"]
|
||||
# Verify the file actually exists
|
||||
full_path = ROOT_DIR / spec_path
|
||||
if full_path.exists():
|
||||
logger.info(f"app_spec.txt verified at: {full_path}")
|
||||
self.complete = True
|
||||
yield {
|
||||
"type": "spec_complete",
|
||||
"path": str(spec_path)
|
||||
}
|
||||
else:
|
||||
logger.error(f"app_spec.txt not found after write: {full_path}")
|
||||
pending_spec_write = None
|
||||
|
||||
def is_complete(self) -> bool:
|
||||
"""Check if spec creation is complete."""
|
||||
|
||||
Reference in New Issue
Block a user