codeframe-ai 0.9.0__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.
- codeframe/__init__.py +11 -0
- codeframe/__main__.py +20 -0
- codeframe/adapters/__init__.py +5 -0
- codeframe/adapters/e2b/__init__.py +13 -0
- codeframe/adapters/e2b/adapter.py +342 -0
- codeframe/adapters/e2b/budget.py +71 -0
- codeframe/adapters/e2b/credential_scanner.py +134 -0
- codeframe/adapters/llm/__init__.py +92 -0
- codeframe/adapters/llm/anthropic.py +414 -0
- codeframe/adapters/llm/base.py +444 -0
- codeframe/adapters/llm/mock.py +281 -0
- codeframe/adapters/llm/openai.py +483 -0
- codeframe/agents/__init__.py +8 -0
- codeframe/agents/dependency_resolver.py +714 -0
- codeframe/auth/__init__.py +16 -0
- codeframe/auth/api_key_router.py +238 -0
- codeframe/auth/api_keys.py +156 -0
- codeframe/auth/dependencies.py +358 -0
- codeframe/auth/manager.py +178 -0
- codeframe/auth/models.py +30 -0
- codeframe/auth/router.py +93 -0
- codeframe/auth/schemas.py +15 -0
- codeframe/auth/scopes.py +53 -0
- codeframe/cli/__init__.py +12 -0
- codeframe/cli/__main__.py +20 -0
- codeframe/cli/api_client.py +275 -0
- codeframe/cli/app.py +5688 -0
- codeframe/cli/auth.py +122 -0
- codeframe/cli/auth_commands.py +958 -0
- codeframe/cli/commands/__init__.py +5 -0
- codeframe/cli/config_commands.py +79 -0
- codeframe/cli/dashboard_commands.py +67 -0
- codeframe/cli/engines_commands.py +205 -0
- codeframe/cli/env_commands.py +409 -0
- codeframe/cli/helpers.py +56 -0
- codeframe/cli/hooks_commands.py +208 -0
- codeframe/cli/import_commands.py +129 -0
- codeframe/cli/pr_commands.py +549 -0
- codeframe/cli/proof_commands.py +415 -0
- codeframe/cli/stats_commands.py +311 -0
- codeframe/cli/telemetry_runtime.py +153 -0
- codeframe/cli/validators.py +123 -0
- codeframe/config/rate_limits.py +165 -0
- codeframe/core/__init__.py +15 -0
- codeframe/core/adapters/__init__.py +43 -0
- codeframe/core/adapters/agent_adapter.py +114 -0
- codeframe/core/adapters/builtin.py +326 -0
- codeframe/core/adapters/claude_code.py +62 -0
- codeframe/core/adapters/codex.py +393 -0
- codeframe/core/adapters/git_utils.py +40 -0
- codeframe/core/adapters/kilocode.py +126 -0
- codeframe/core/adapters/opencode.py +48 -0
- codeframe/core/adapters/streaming_chat.py +483 -0
- codeframe/core/adapters/subprocess_adapter.py +213 -0
- codeframe/core/adapters/verification_wrapper.py +269 -0
- codeframe/core/agent.py +2183 -0
- codeframe/core/agents_config.py +569 -0
- codeframe/core/api_key_service.py +211 -0
- codeframe/core/artifacts.py +428 -0
- codeframe/core/blocker_detection.py +218 -0
- codeframe/core/blockers.py +433 -0
- codeframe/core/checkpoints.py +481 -0
- codeframe/core/conductor.py +2255 -0
- codeframe/core/config.py +827 -0
- codeframe/core/config_watcher.py +268 -0
- codeframe/core/context.py +542 -0
- codeframe/core/context_packager.py +234 -0
- codeframe/core/credentials.py +735 -0
- codeframe/core/dependency_analyzer.py +229 -0
- codeframe/core/dependency_graph.py +290 -0
- codeframe/core/diagnostic_agent.py +712 -0
- codeframe/core/diagnostics.py +616 -0
- codeframe/core/editor.py +556 -0
- codeframe/core/engine_registry.py +256 -0
- codeframe/core/engine_stats.py +231 -0
- codeframe/core/environment.py +697 -0
- codeframe/core/events.py +375 -0
- codeframe/core/executor.py +1005 -0
- codeframe/core/fix_tracker.py +480 -0
- codeframe/core/gates.py +1322 -0
- codeframe/core/git.py +477 -0
- codeframe/core/github_connect_service.py +178 -0
- codeframe/core/github_integration_config.py +118 -0
- codeframe/core/github_issues_service.py +449 -0
- codeframe/core/hooks.py +184 -0
- codeframe/core/importers/__init__.py +1 -0
- codeframe/core/importers/ralph.py +540 -0
- codeframe/core/installer.py +650 -0
- codeframe/core/models.py +1026 -0
- codeframe/core/notifications_config.py +183 -0
- codeframe/core/planner.py +437 -0
- codeframe/core/prd.py +670 -0
- codeframe/core/prd_discovery.py +1118 -0
- codeframe/core/prd_stress_test.py +499 -0
- codeframe/core/progress.py +126 -0
- codeframe/core/proof/__init__.py +34 -0
- codeframe/core/proof/capture.py +79 -0
- codeframe/core/proof/evidence.py +56 -0
- codeframe/core/proof/ledger.py +574 -0
- codeframe/core/proof/models.py +162 -0
- codeframe/core/proof/obligations.py +103 -0
- codeframe/core/proof/runner.py +233 -0
- codeframe/core/proof/scope.py +81 -0
- codeframe/core/proof/stubs.py +156 -0
- codeframe/core/quick_fixes.py +558 -0
- codeframe/core/react_agent.py +1650 -0
- codeframe/core/reconciliation.py +183 -0
- codeframe/core/replay.py +788 -0
- codeframe/core/review.py +285 -0
- codeframe/core/runtime.py +1134 -0
- codeframe/core/sandbox/__init__.py +27 -0
- codeframe/core/sandbox/context.py +98 -0
- codeframe/core/sandbox/worktree.py +20 -0
- codeframe/core/schedule.py +396 -0
- codeframe/core/stall_detector.py +71 -0
- codeframe/core/stall_monitor.py +134 -0
- codeframe/core/state_machine.py +121 -0
- codeframe/core/streaming.py +502 -0
- codeframe/core/task_tree.py +400 -0
- codeframe/core/tasks.py +1022 -0
- codeframe/core/telemetry.py +232 -0
- codeframe/core/templates.py +221 -0
- codeframe/core/tools.py +942 -0
- codeframe/core/workspace.py +887 -0
- codeframe/core/worktrees.py +276 -0
- codeframe/git/__init__.py +5 -0
- codeframe/git/github_integration.py +505 -0
- codeframe/lib/__init__.py +0 -0
- codeframe/lib/audit_logger.py +248 -0
- codeframe/lib/metrics_tracker.py +800 -0
- codeframe/lib/quality/__init__.py +7 -0
- codeframe/lib/quality/complexity_analyzer.py +316 -0
- codeframe/lib/quality/owasp_patterns.py +284 -0
- codeframe/lib/quality/security_scanner.py +250 -0
- codeframe/lib/rate_limiter.py +312 -0
- codeframe/notifications/__init__.py +0 -0
- codeframe/notifications/webhook.py +380 -0
- codeframe/planning/__init__.py +30 -0
- codeframe/planning/issue_generator.py +219 -0
- codeframe/planning/prd_template_functions.py +137 -0
- codeframe/planning/prd_templates.py +975 -0
- codeframe/planning/task_scheduler.py +511 -0
- codeframe/planning/task_templates.py +533 -0
- codeframe/platform_store/__init__.py +5 -0
- codeframe/platform_store/database.py +277 -0
- codeframe/platform_store/repositories/__init__.py +24 -0
- codeframe/platform_store/repositories/api_key_repository.py +245 -0
- codeframe/platform_store/repositories/audit_repository.py +67 -0
- codeframe/platform_store/repositories/base.py +295 -0
- codeframe/platform_store/repositories/interactive_sessions.py +165 -0
- codeframe/platform_store/repositories/token_repository.py +598 -0
- codeframe/platform_store/repositories/workspace_registry_repository.py +175 -0
- codeframe/platform_store/schema_manager.py +321 -0
- codeframe/templates/AGENTS.md.default +94 -0
- codeframe/tui/__init__.py +5 -0
- codeframe/tui/app.py +256 -0
- codeframe/tui/data_service.py +103 -0
- codeframe/ui/__init__.py +0 -0
- codeframe/ui/dependencies.py +103 -0
- codeframe/ui/models.py +999 -0
- codeframe/ui/response_models.py +201 -0
- codeframe/ui/routers/__init__.py +5 -0
- codeframe/ui/routers/_helpers.py +29 -0
- codeframe/ui/routers/batches_v2.py +315 -0
- codeframe/ui/routers/blockers_v2.py +320 -0
- codeframe/ui/routers/checkpoints_v2.py +310 -0
- codeframe/ui/routers/costs_v2.py +322 -0
- codeframe/ui/routers/diagnose_v2.py +225 -0
- codeframe/ui/routers/discovery_v2.py +417 -0
- codeframe/ui/routers/environment_v2.py +284 -0
- codeframe/ui/routers/events_v2.py +75 -0
- codeframe/ui/routers/gates_v2.py +166 -0
- codeframe/ui/routers/git_v2.py +284 -0
- codeframe/ui/routers/github_integrations_v2.py +532 -0
- codeframe/ui/routers/interactive_sessions_v2.py +238 -0
- codeframe/ui/routers/pr_v2.py +709 -0
- codeframe/ui/routers/prd_v2.py +695 -0
- codeframe/ui/routers/proof_v2.py +755 -0
- codeframe/ui/routers/review_v2.py +360 -0
- codeframe/ui/routers/schedule_v2.py +214 -0
- codeframe/ui/routers/session_chat_ws.py +354 -0
- codeframe/ui/routers/settings_v2.py +562 -0
- codeframe/ui/routers/streaming_v2.py +155 -0
- codeframe/ui/routers/tasks_v2.py +1098 -0
- codeframe/ui/routers/templates_v2.py +232 -0
- codeframe/ui/routers/terminal_ws.py +267 -0
- codeframe/ui/routers/workspace_v2.py +527 -0
- codeframe/ui/server.py +568 -0
- codeframe/ui/shared.py +241 -0
- codeframe/workspace/__init__.py +5 -0
- codeframe/workspace/manager.py +249 -0
- codeframe_ai-0.9.0.dist-info/METADATA +517 -0
- codeframe_ai-0.9.0.dist-info/RECORD +197 -0
- codeframe_ai-0.9.0.dist-info/WHEEL +5 -0
- codeframe_ai-0.9.0.dist-info/entry_points.txt +3 -0
- codeframe_ai-0.9.0.dist-info/licenses/LICENSE +661 -0
- codeframe_ai-0.9.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"""SSE streaming utilities for real-time task execution events.
|
|
2
|
+
|
|
3
|
+
This module provides shared SSE utilities (formatting, event generation,
|
|
4
|
+
publisher management) used by streaming consumers.
|
|
5
|
+
|
|
6
|
+
The actual SSE endpoint for tasks is in tasks_v2.py:
|
|
7
|
+
GET /api/v2/tasks/{task_id}/stream (requires workspace_path only)
|
|
8
|
+
"""
|
|
9
|
+
|
|
10
|
+
import asyncio
|
|
11
|
+
import logging
|
|
12
|
+
from typing import AsyncGenerator, Optional
|
|
13
|
+
|
|
14
|
+
from fastapi import APIRouter, Request
|
|
15
|
+
from fastapi.responses import StreamingResponse # noqa: F401 — re-exported
|
|
16
|
+
|
|
17
|
+
from codeframe.core.models import ExecutionEvent
|
|
18
|
+
from codeframe.core.streaming import EventPublisher
|
|
19
|
+
|
|
20
|
+
logger = logging.getLogger(__name__)
|
|
21
|
+
|
|
22
|
+
router = APIRouter(
|
|
23
|
+
prefix="/api/v2/tasks",
|
|
24
|
+
tags=["streaming"],
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
# Global event publisher instance
|
|
28
|
+
# In production, this should be dependency-injected
|
|
29
|
+
_event_publisher: Optional[EventPublisher] = None
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def get_event_publisher() -> EventPublisher:
|
|
33
|
+
"""Get or create the global EventPublisher instance.
|
|
34
|
+
|
|
35
|
+
Returns:
|
|
36
|
+
The EventPublisher singleton
|
|
37
|
+
"""
|
|
38
|
+
global _event_publisher
|
|
39
|
+
if _event_publisher is None:
|
|
40
|
+
_event_publisher = EventPublisher()
|
|
41
|
+
return _event_publisher
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def set_event_publisher(publisher: EventPublisher) -> None:
|
|
45
|
+
"""Set the global EventPublisher instance (for testing).
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
publisher: EventPublisher instance to use
|
|
49
|
+
"""
|
|
50
|
+
global _event_publisher
|
|
51
|
+
_event_publisher = publisher
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
def format_sse_event(event: ExecutionEvent) -> str:
|
|
55
|
+
"""Format an ExecutionEvent as an SSE data line.
|
|
56
|
+
|
|
57
|
+
SSE format:
|
|
58
|
+
data: {"event_type": "...", ...}\\n\\n
|
|
59
|
+
|
|
60
|
+
Args:
|
|
61
|
+
event: ExecutionEvent to format
|
|
62
|
+
|
|
63
|
+
Returns:
|
|
64
|
+
SSE-formatted string with data prefix and double newline
|
|
65
|
+
"""
|
|
66
|
+
return f"data: {event.model_dump_json()}\n\n"
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def format_sse_comment(message: str) -> str:
|
|
70
|
+
"""Format a comment line for SSE (used for heartbeats).
|
|
71
|
+
|
|
72
|
+
SSE comments start with ':' and are ignored by EventSource clients,
|
|
73
|
+
but keep the connection alive.
|
|
74
|
+
|
|
75
|
+
Args:
|
|
76
|
+
message: Comment message
|
|
77
|
+
|
|
78
|
+
Returns:
|
|
79
|
+
SSE comment string
|
|
80
|
+
"""
|
|
81
|
+
return f": {message}\n\n"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
async def event_stream_generator(
|
|
85
|
+
task_id: str,
|
|
86
|
+
publisher: EventPublisher,
|
|
87
|
+
request: Request,
|
|
88
|
+
heartbeat_interval: float = 15.0,
|
|
89
|
+
) -> AsyncGenerator[str, None]:
|
|
90
|
+
"""Generate SSE events for a task with heartbeat keep-alive.
|
|
91
|
+
|
|
92
|
+
Subscribes to the EventPublisher and yields SSE-formatted strings.
|
|
93
|
+
Emits SSE comments as heartbeats during idle periods to prevent
|
|
94
|
+
proxy/browser timeouts.
|
|
95
|
+
|
|
96
|
+
Args:
|
|
97
|
+
task_id: Task ID to stream events for
|
|
98
|
+
publisher: EventPublisher to subscribe to
|
|
99
|
+
request: FastAPI request (for disconnect detection)
|
|
100
|
+
heartbeat_interval: Seconds between heartbeat comments
|
|
101
|
+
|
|
102
|
+
Yields:
|
|
103
|
+
SSE-formatted event strings or comment heartbeats
|
|
104
|
+
"""
|
|
105
|
+
logger.info(f"Starting SSE stream for task {task_id}")
|
|
106
|
+
|
|
107
|
+
queue: asyncio.Queue = asyncio.Queue(maxsize=1000)
|
|
108
|
+
loop = asyncio.get_running_loop()
|
|
109
|
+
|
|
110
|
+
from codeframe.core.streaming import _Subscription
|
|
111
|
+
subscription = _Subscription(task_id, queue, loop)
|
|
112
|
+
|
|
113
|
+
async with publisher._lock:
|
|
114
|
+
publisher._subscribers[task_id].append(subscription)
|
|
115
|
+
|
|
116
|
+
try:
|
|
117
|
+
while True:
|
|
118
|
+
if await request.is_disconnected():
|
|
119
|
+
logger.info(f"Client disconnected from task {task_id} stream")
|
|
120
|
+
break
|
|
121
|
+
|
|
122
|
+
try:
|
|
123
|
+
item = await asyncio.wait_for(queue.get(), timeout=heartbeat_interval)
|
|
124
|
+
|
|
125
|
+
if item is _Subscription.END_OF_STREAM:
|
|
126
|
+
break
|
|
127
|
+
|
|
128
|
+
yield format_sse_event(item)
|
|
129
|
+
|
|
130
|
+
if item.event_type == "completion":
|
|
131
|
+
logger.info(f"Task {task_id} completed, closing stream")
|
|
132
|
+
break
|
|
133
|
+
except asyncio.TimeoutError:
|
|
134
|
+
yield format_sse_comment("heartbeat")
|
|
135
|
+
|
|
136
|
+
except asyncio.CancelledError:
|
|
137
|
+
logger.info(f"SSE stream cancelled for task {task_id}")
|
|
138
|
+
raise
|
|
139
|
+
except Exception as e:
|
|
140
|
+
logger.error(f"Error in SSE stream for task {task_id}: {e}")
|
|
141
|
+
raise
|
|
142
|
+
finally:
|
|
143
|
+
async with publisher._lock:
|
|
144
|
+
if subscription in publisher._subscribers[task_id]:
|
|
145
|
+
publisher._subscribers[task_id].remove(subscription)
|
|
146
|
+
if not publisher._subscribers[task_id]:
|
|
147
|
+
del publisher._subscribers[task_id]
|
|
148
|
+
logger.info(f"Closing SSE stream for task {task_id}")
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
# NOTE: The SSE stream endpoint for tasks is defined in tasks_v2.py
|
|
152
|
+
# (GET /api/v2/tasks/{task_id}/stream) which only requires workspace_path
|
|
153
|
+
# and is compatible with browser EventSource (no custom auth headers needed).
|
|
154
|
+
# This module retains the shared utilities (format_sse_event, format_sse_comment,
|
|
155
|
+
# event_stream_generator, get_event_publisher) used by other streaming consumers.
|