| 418 | reconsiderable_work.owner_type, |
| 419 | reconsiderable_work.owner_id, |
| 420 | reconsiderable_work.oldest_reconsiderable_at, |
| 421 | COALESCE(active_work.active_count, 0) AS active_count, |
| 422 | CASE |
| 423 | WHEN reconsiderable_work.owner_type = 'org' |
| 424 | THEN ${MAX_CONCURRENT_CODE_REVIEWS_PER_ORG}::bigint |
| 425 | WHEN COALESCE( |
| 426 | ${kilocode_users.total_microdollars_acquired}, |
| 427 | 0 |
| 428 | ) - COALESCE(${kilocode_users.microdollars_used}, 0) > ${FUNDED_CODE_REVIEW_BALANCE_THRESHOLD_MICRODOLLARS} |
| 429 | THEN ${MAX_CONCURRENT_CODE_REVIEWS_PER_FUNDED_USER}::bigint |
| 430 | ELSE ${MAX_CONCURRENT_CODE_REVIEWS_PER_DEFAULT_USER}::bigint |
| 431 | END AS capacity_limit |
| 432 | FROM reconsiderable_work |
| 433 | LEFT JOIN active_work |
| 434 | ON active_work.owner_type = reconsiderable_work.owner_type |
| 435 | AND active_work.owner_id = reconsiderable_work.owner_id |
| 436 | LEFT JOIN ${kilocode_users} |
| 437 | ON reconsiderable_work.owner_type = 'user' |
| 438 | AND ${kilocode_users.id} = reconsiderable_work.owner_id |
| 439 | ) |
| 440 | SELECT owner_type, owner_id |
| 441 | FROM capacity_candidates |
| 442 | WHERE active_count < capacity_limit |
| 443 | ORDER BY oldest_reconsiderable_at ASC, owner_type ASC, owner_id ASC |
| 444 | LIMIT ${limit + 1} |
| 445 | `); |
| 446 | |
| 447 | const hasMore = result.rows.length > limit; |
| 448 | const owners = result.rows.slice(0, limit).map(row => |
| 449 | row.owner_type === 'org' |
| 450 | ? ({ |
| 451 | type: 'org', |
| 452 | id: row.owner_id, |
| 453 | } satisfies DispatchableCodeReviewOwnerCandidate) |
| 454 | : ({ |
| 455 | type: 'user', |
| 456 | id: row.owner_id, |
| 457 | } satisfies DispatchableCodeReviewOwnerCandidate) |
| 458 | ); |
| 459 | |
| 460 | return { owners, hasMore }; |
| 461 | } catch (error) { |
| 462 | captureException(error, { |
| 463 | tags: { operation: 'listDispatchableCodeReviewOwnerCandidates' }, |
| 464 | extra: { limit }, |
| 465 | }); |
| 466 | throw error; |
| 467 | } |
| 468 | } |
| 469 | |
| 470 | export async function listCodeReviewAttempts( |
| 471 | codeReviewId: string |
| 472 | ): Promise<CloudAgentCodeReviewAttempt[]> { |
| 473 | try { |
| 474 | return await db |
| 475 | .select() |
| 476 | .from(cloud_agent_code_review_attempts) |
| 477 | .where(eq(cloud_agent_code_review_attempts.code_review_id, codeReviewId)) |