ralphx 0.2.2__py3-none-any.whl → 0.3.4__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.
ralphx/__init__.py CHANGED
@@ -1,6 +1,6 @@
1
1
  """RalphX - Generic agent loop orchestration system."""
2
2
 
3
- __version__ = "0.1.0"
3
+ __version__ = "0.3.4"
4
4
  __author__ = "Jack"
5
5
 
6
6
  # Package metadata
ralphx/api/main.py CHANGED
@@ -27,7 +27,7 @@ from fastapi.responses import FileResponse, JSONResponse
27
27
  from fastapi.staticfiles import StaticFiles
28
28
 
29
29
  from ralphx import __version__
30
- from ralphx.api.routes import auth, config, files, filesystem, imports, items, logs, loops, planning, projects, resources, runs, stream, templates, workflows
30
+ from ralphx.api.routes import auth, config, export_import, files, filesystem, imports, items, logs, loops, planning, projects, resources, runs, stream, templates, workflows
31
31
  from ralphx.core.auth import restore_orphaned_backup
32
32
  from ralphx.core.workspace import ensure_workspace
33
33
 
@@ -123,10 +123,17 @@ async def _stale_run_cleanup_loop():
123
123
  async def lifespan(app: FastAPI):
124
124
  """Application lifespan events."""
125
125
  from ralphx.core.logger import system_log
126
+ from ralphx.core.sample_project import ensure_sample_project_created
126
127
 
127
128
  # Startup
128
129
  ensure_workspace()
129
130
 
131
+ # Create sample project on first run
132
+ try:
133
+ ensure_sample_project_created()
134
+ except Exception as e:
135
+ logger.warning(f"Sample project creation failed: {e}")
136
+
130
137
  # Restore any orphaned credential backups from previous crashes
131
138
  # This ensures user's main credentials are ALWAYS restored
132
139
  restore_orphaned_backup()
@@ -278,6 +285,7 @@ app.include_router(logs.router, prefix="/api", tags=["logs"])
278
285
  app.include_router(config.router, prefix="/api/projects", tags=["config"])
279
286
  app.include_router(workflows.router, prefix="/api/projects/{slug}", tags=["workflows"])
280
287
  app.include_router(planning.router, prefix="/api/projects/{slug}", tags=["planning"])
288
+ app.include_router(export_import.router, prefix="/api/projects/{slug}", tags=["export-import"])
281
289
 
282
290
 
283
291
  # Root endpoint
ralphx/api/routes/auth.py CHANGED
@@ -181,6 +181,62 @@ async def validate_credentials(
181
181
  }
182
182
 
183
183
 
184
+ @router.get("/usage")
185
+ async def get_usage(
186
+ project_path: Optional[str] = Query(
187
+ None, description="Project path for scoped credentials"
188
+ ),
189
+ ):
190
+ """Get Claude API usage statistics.
191
+
192
+ Returns 5-hour and 7-day utilization percentages.
193
+ """
194
+ import httpx
195
+
196
+ project_id = _get_project_id(project_path)
197
+ db = Database()
198
+ creds = db.get_credentials(project_id)
199
+
200
+ if not creds or not creds.get("access_token"):
201
+ return {
202
+ "success": False,
203
+ "error": "No credentials found",
204
+ }
205
+
206
+ try:
207
+ async with httpx.AsyncClient() as client:
208
+ response = await client.get(
209
+ "https://api.anthropic.com/api/oauth/usage",
210
+ headers={
211
+ "Authorization": f"Bearer {creds['access_token']}",
212
+ "anthropic-beta": "oauth-2025-04-20",
213
+ },
214
+ timeout=10.0,
215
+ )
216
+
217
+ if response.status_code != 200:
218
+ return {
219
+ "success": False,
220
+ "error": f"API error: {response.status_code}",
221
+ }
222
+
223
+ data = response.json()
224
+ five_hour = data.get("five_hour", {})
225
+ seven_day = data.get("seven_day", {})
226
+ return {
227
+ "success": True,
228
+ "five_hour_utilization": five_hour.get("utilization"),
229
+ "five_hour_resets_at": five_hour.get("resets_at"),
230
+ "seven_day_utilization": seven_day.get("utilization"),
231
+ "seven_day_resets_at": seven_day.get("resets_at"),
232
+ }
233
+ except Exception as e:
234
+ return {
235
+ "success": False,
236
+ "error": str(e),
237
+ }
238
+
239
+
184
240
  @router.get("/credentials/export")
185
241
  async def export_credentials(
186
242
  scope: Literal["project", "global"] = Query("global"),