victordibia commited on
Commit
aad7124
Β·
1 Parent(s): 034c2ac

Deploy 2026-01-26 07:56:26

Browse files
Dockerfile CHANGED
@@ -19,8 +19,8 @@ RUN pip install --no-cache-dir uv
19
  # -------------------------------------------------------------------
20
  FROM base AS builder
21
 
22
- # Copy only dependency files first (better layer caching)
23
- COPY pyproject.toml uv.lock ./
24
 
25
  # Install dependencies to system (no venv needed in container)
26
  RUN uv pip install --system .
@@ -37,6 +37,9 @@ COPY --from=builder /usr/local/bin /usr/local/bin
37
  # Copy application source (includes pre-built frontend in src/flow/ui/ui/)
38
  COPY src/ ./src/
39
 
 
 
 
40
  # Install the app itself (editable, uses already-installed deps)
41
  RUN uv pip install --system --no-deps -e .
42
 
 
19
  # -------------------------------------------------------------------
20
  FROM base AS builder
21
 
22
+ # Copy files needed for build (hatchling requires README.md)
23
+ COPY pyproject.toml uv.lock README.md ./
24
 
25
  # Install dependencies to system (no venv needed in container)
26
  RUN uv pip install --system .
 
37
  # Copy application source (includes pre-built frontend in src/flow/ui/ui/)
38
  COPY src/ ./src/
39
 
40
+ # Copy files needed for package install
41
+ COPY pyproject.toml README.md ./
42
+
43
  # Install the app itself (editable, uses already-installed deps)
44
  RUN uv pip install --system --no-deps -e .
45
 
src/flow/ui/services/optimizer_service.py CHANGED
@@ -26,10 +26,14 @@ class OptimizerService:
26
 
27
  async def run_job(self, job_id: str | UUID) -> AsyncGenerator[JobProgress, None]:
28
  """Run an optimization job and yield progress updates."""
 
 
 
 
29
  async with async_session() as session:
30
  # Load job
31
  result = await session.execute(
32
- select(OptimizationJob).where(OptimizationJob.id == str(job_id))
33
  )
34
  job = result.scalar_one_or_none()
35
  if not job:
@@ -182,7 +186,7 @@ class OptimizerService:
182
  configs = []
183
  for config_id in config_ids:
184
  result = await session.execute(
185
- select(AgentConfig).where(AgentConfig.id == config_id)
186
  )
187
  db_config = result.scalar_one_or_none()
188
  if db_config:
@@ -207,7 +211,7 @@ class OptimizerService:
207
  tasks = []
208
  for task_id in task_ids:
209
  result = await session.execute(
210
- select(TaskModel).where(TaskModel.id == task_id)
211
  )
212
  db_task = result.scalar_one_or_none()
213
  if db_task:
 
26
 
27
  async def run_job(self, job_id: str | UUID) -> AsyncGenerator[JobProgress, None]:
28
  """Run an optimization job and yield progress updates."""
29
+ # Convert to UUID if string
30
+ if isinstance(job_id, str):
31
+ job_id = UUID(job_id)
32
+
33
  async with async_session() as session:
34
  # Load job
35
  result = await session.execute(
36
+ select(OptimizationJob).where(OptimizationJob.id == job_id)
37
  )
38
  job = result.scalar_one_or_none()
39
  if not job:
 
186
  configs = []
187
  for config_id in config_ids:
188
  result = await session.execute(
189
+ select(AgentConfig).where(AgentConfig.id == UUID(config_id))
190
  )
191
  db_config = result.scalar_one_or_none()
192
  if db_config:
 
211
  tasks = []
212
  for task_id in task_ids:
213
  result = await session.execute(
214
+ select(TaskModel).where(TaskModel.id == UUID(task_id))
215
  )
216
  db_task = result.scalar_one_or_none()
217
  if db_task:
src/flow/ui/tests/test_e2e_user_journey.py CHANGED
@@ -447,6 +447,84 @@ class TestAPIEndpoints:
447
  assert resp.status_code == 200
448
  assert resp.json() == []
449
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
450
 
451
  if __name__ == "__main__":
452
  # Run tests directly
 
447
  assert resp.status_code == 200
448
  assert resp.json() == []
449
 
450
+ @pytest.mark.asyncio
451
+ async def test_job_start_endpoint(self, client: httpx.AsyncClient):
452
+ """Test that job start endpoint works and updates job status.
453
+
454
+ Note: The actual optimization will likely fail in test environment due to
455
+ missing dependencies, but we verify the endpoint is accessible and
456
+ the job status transitions correctly.
457
+ """
458
+ print("\n[Job Start Endpoint Test]")
459
+
460
+ # Create config
461
+ config_resp = await client.post(
462
+ "/api/configs",
463
+ json={"name": "start-test-config"},
464
+ )
465
+ assert config_resp.status_code == 201
466
+ config = config_resp.json()
467
+ print(f" βœ“ Created config: {config['id'][:8]}...")
468
+
469
+ # Create task
470
+ task_resp = await client.post(
471
+ "/api/tasks",
472
+ json={"name": "start-test-task", "prompt": "Print hello world"},
473
+ )
474
+ assert task_resp.status_code == 201
475
+ task = task_resp.json()
476
+ print(f" βœ“ Created task: {task['id'][:8]}...")
477
+
478
+ try:
479
+ # Create job
480
+ job_resp = await client.post(
481
+ "/api/jobs",
482
+ json={
483
+ "name": "start-test-job",
484
+ "config_ids": [config["id"]],
485
+ "task_ids": [task["id"]],
486
+ "parallel": 1,
487
+ },
488
+ )
489
+ assert job_resp.status_code == 201
490
+ job = job_resp.json()
491
+ job_id = job["id"]
492
+ print(f" βœ“ Created job: {job_id[:8]}...")
493
+ assert job["status"] == "pending"
494
+ print(f" βœ“ Job status is 'pending'")
495
+
496
+ # Try to start job - this is a streaming endpoint
497
+ # We just verify it's accessible (200 OK) even if it errors during execution
498
+ print(f" βœ“ Attempting to start job...")
499
+ start_resp = await client.post(f"/api/jobs/{job_id}/start")
500
+ # The endpoint should return 200 OK for the SSE stream
501
+ assert start_resp.status_code == 200, f"Start endpoint failed: {start_resp.status_code}"
502
+ print(f" βœ“ Start endpoint responded with 200")
503
+
504
+ # Check job status after start attempt
505
+ # It should have transitioned from 'pending' (to 'running' or 'failed')
506
+ status_resp = await client.get(f"/api/jobs/{job_id}")
507
+ assert status_resp.status_code == 200
508
+ updated_job = status_resp.json()
509
+ print(f" βœ“ Job status after start: {updated_job['status']}")
510
+
511
+ # Job should no longer be pending
512
+ # It's either 'running', 'failed', or 'completed'
513
+ assert updated_job["status"] in ["running", "failed", "completed"], \
514
+ f"Unexpected status: {updated_job['status']}"
515
+ print(f" βœ“ Job transitioned from 'pending' to '{updated_job['status']}'")
516
+
517
+ # Cleanup
518
+ await client.delete(f"/api/jobs/{job_id}")
519
+ print(f" βœ“ Deleted job")
520
+
521
+ finally:
522
+ await client.delete(f"/api/tasks/{task['id']}")
523
+ await client.delete(f"/api/configs/{config['id']}")
524
+ print(f" βœ“ Cleaned up config and task")
525
+
526
+ print("\n Job start endpoint test passed!")
527
+
528
 
529
  if __name__ == "__main__":
530
  # Run tests directly