chore: release api v1.0.0
- Event-based streaming for task agent - Retry logic when LLM responds without calling tools - Hardened prompts to enforce tool use - Working directory context in all agent prompts - Project paused: local LLMs not capable enough for agentic use Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -26,6 +26,41 @@ class PermissionMode(str, Enum):
|
||||
auto_accept = "auto_accept"
|
||||
|
||||
|
||||
class StreamEventType(str, Enum):
|
||||
"""Event types for structured agent streaming."""
|
||||
tool_start = "tool_start"
|
||||
tool_done = "tool_done"
|
||||
thinking = "thinking"
|
||||
response = "response"
|
||||
error = "error"
|
||||
done = "done"
|
||||
chunk = "chunk" # Legacy text chunk
|
||||
|
||||
|
||||
@dataclass
|
||||
class StreamEvent:
|
||||
"""
|
||||
Structured streaming event from agent execution.
|
||||
|
||||
Different event types carry different data:
|
||||
- tool_start: tool, args
|
||||
- tool_done: tool, result_summary
|
||||
- thinking: message
|
||||
- response: text
|
||||
- error: error_message
|
||||
- done: mode
|
||||
- chunk: text (legacy)
|
||||
"""
|
||||
event: StreamEventType
|
||||
tool: str | None = None
|
||||
args: dict | None = None
|
||||
result_summary: str | None = None
|
||||
message: str | None = None
|
||||
text: str | None = None
|
||||
error_message: str | None = None
|
||||
mode: str | None = None
|
||||
|
||||
|
||||
@dataclass
|
||||
class AgentResponse:
|
||||
"""Response from agent execution."""
|
||||
@@ -202,7 +237,7 @@ class WebberClient:
|
||||
prompt: str,
|
||||
working_dir: str = ".",
|
||||
mode: PermissionMode = PermissionMode.default,
|
||||
) -> AsyncIterator[str]:
|
||||
) -> AsyncIterator[StreamEvent]:
|
||||
"""
|
||||
Run an agent with streaming response.
|
||||
|
||||
@@ -213,7 +248,7 @@ class WebberClient:
|
||||
mode: Permission mode controlling tool access
|
||||
|
||||
Yields:
|
||||
Text chunks as they arrive
|
||||
StreamEvent objects as they arrive
|
||||
"""
|
||||
# Use a fresh client for streaming with longer timeout
|
||||
async with httpx.AsyncClient(
|
||||
@@ -235,13 +270,30 @@ class WebberClient:
|
||||
if line.startswith("data: "):
|
||||
try:
|
||||
data = json.loads(line[6:])
|
||||
event = data.get("event")
|
||||
if event == "chunk":
|
||||
yield data.get("data", "")
|
||||
elif event == "error":
|
||||
raise Exception(data.get("data", "Unknown error"))
|
||||
elif event == "done":
|
||||
event_type = data.get("event")
|
||||
|
||||
# Parse event type
|
||||
try:
|
||||
evt_type = StreamEventType(event_type)
|
||||
except ValueError:
|
||||
continue # Unknown event type
|
||||
|
||||
# Build StreamEvent from response data
|
||||
yield StreamEvent(
|
||||
event=evt_type,
|
||||
tool=data.get("tool"),
|
||||
args=data.get("args"),
|
||||
result_summary=data.get("result_summary"),
|
||||
message=data.get("message"),
|
||||
text=data.get("text") or data.get("data"), # 'data' for legacy chunk
|
||||
error_message=data.get("error_message") or data.get("data"),
|
||||
mode=data.get("mode"),
|
||||
)
|
||||
|
||||
# Stop on done or error
|
||||
if evt_type in (StreamEventType.done, StreamEventType.error):
|
||||
break
|
||||
|
||||
except json.JSONDecodeError:
|
||||
continue
|
||||
|
||||
|
||||
Reference in New Issue
Block a user