feat: add AI provider chat routes#25413
Conversation
|
/coder-agents-review |
There was a problem hiding this comment.
First-pass review (Netero). These are mechanical findings from the first pass only; the full review panel has not yet reviewed this PR. The panel will review after these findings are addressed.
Severity count: 1 P1, 1 P2, 2 P3.
The CRUD surface is well-structured and consistent with the existing chat provider pattern. Route registration, authorization checks, and converter functions are clean. The naming follows established conventions throughout.
"675+ new lines of non-test Go code with 0 new handler tests. The only test changes are 3 lines adding Name: to existing dbcrypt tests." (Netero)
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
|
/coder-agents-review |
|
/coder-agents-review |
|
/coder-agents-review |
There was a problem hiding this comment.
Panel review (R2, 10 reviewers). All four R1 Netero findings addressed cleanly in e82b66f.
The CRUD surface is well-organized: consistent naming, correct RBAC checks, clean converters. The new test suite covers the main lifecycle and key validation paths.
Severity count: 7 P2, 4 P3, 2 Nit.
The findings cluster around three themes: (1) missing input validation that the legacy chat provider handlers already implement (key size cap, BaseURL normalization, whitespace trimming), (2) mutation handlers that lack transactions and row locks (updateAIProvider and deleteAIProvider), and (3) test gaps on error branches that guard the R1 fixes.
Ryosuke's structural observation: wrapping updateAIProvider and deleteAIProvider in InTx with GetForUpdate (the pattern deleteChatProvider already uses) resolves DEREM-7 and DEREM-8 simultaneously, and makes parent-existence checks structurally natural.
"675+ new lines of non-test Go code with 0 new handler tests" was the R1 finding. The author shipped 223 lines of tests covering all 11 handlers. Solid turnaround. (Netero R1 vs R2)
coderd/database/migrations/000498_ai_providers_schema_expand.up.sql:33
Nit [DEREM-18] idx_user_ai_provider_keys_user_id is redundant.
The UNIQUE (user_id, ai_provider_id) constraint implicitly creates a composite index with user_id as the leading column. PostgreSQL can use a composite index for prefix lookups, so queries filtering only on user_id (e.g., GetUserAIProviderKeysByUserID) are already served by the unique index. The standalone index adds write amplification with no query benefit. Consider dropping it and keeping only idx_user_ai_provider_keys_ai_provider_id for the non-leading column.
(Knuckle Nit)
🤖
🤖 This review was automatically generated with Coder Agents.
There was a problem hiding this comment.
Review blocked (R3). All 13 open findings from the panel review (R2) are unaddressed. No code changes to the affected files since R2. Further review is blocked until the author responds or pushes fixes.
Unaddressed P2 findings (7):
- DEREM-5:
upsertUserAIProviderKeyallows key attachment to disabled providers - DEREM-6: No API key size validation in
createAIProviderKey/upsertUserAIProviderKey - DEREM-7:
deleteAIProviderreturns 204 for non-existent or already-deleted providers - DEREM-8:
updateAIProviderread-then-update without transaction; lost updates and 500 on concurrent soft-delete - DEREM-9: BaseURL stored without validation; SSRF vector when consumed by bridge
- DEREM-10: All 11 handlers discard DB errors in 500 responses (no Detail, no logging)
- DEREM-11:
updateAIProvidervalidation error paths untested
Unaddressed P3 findings (4):
- DEREM-12:
listAIProviderKeysreturns 200 for non-existent provider IDs - DEREM-13: Cross-provider key deletion check untested
- DEREM-14:
listUserAIProviderKeyConfigsfiltering logic untested - DEREM-15:
BYOKDisabledRejectsUpsertAndAllowsDeletetests delete of non-existent key
Unaddressed Nit findings (2):
- DEREM-16: API key whitespace not trimmed before storage
- DEREM-18: Redundant index
idx_user_ai_provider_keys_user_id
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R4). 6 of 13 findings addressed in a735065 (DEREM-5, 6, 7, 8, 9, 16). Good progress on the P2 input validation and transaction fixes. 7 findings remain unaddressed with no author response.
Still silent P2 findings (2):
- DEREM-10: All 11 handlers discard DB errors in 500 responses (no
Detail, no logging) - DEREM-11:
updateAIProvidervalidation error paths untested (409 on duplicate name, 400 on invalid name via update)
Still silent P3 findings (4):
- DEREM-12:
listAIProviderKeysreturns 200 for non-existent provider IDs - DEREM-13: Cross-provider key deletion check untested
- DEREM-14:
listUserAIProviderKeyConfigsfiltering logic untested - DEREM-15:
BYOKDisabledRejectsUpsertAndAllowsDeletetests delete of non-existent key
Still silent Nit (1):
- DEREM-18: Redundant index
idx_user_ai_provider_keys_user_id
Further review is blocked until the author responds or pushes fixes for the remaining findings. Even a brief "intentional, will not fix" acknowledgment unblocks the review.
🤖 This review was automatically generated with Coder Agents.
There was a problem hiding this comment.
Review blocked (R5). Same 7 findings from R4 remain silent. Only docs changes since last round.
Silent P2 (2): DEREM-10 (500 responses discard errors), DEREM-11 (update validation untested).
Silent P3 (4): DEREM-12, 13, 14, 15.
Silent Nit (1): DEREM-18.
This is the third consecutive blocked round (R3, R4, R5). The review cannot proceed without author engagement on these findings. A brief reply (even "will not fix" or "deferred") unblocks the next round.
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R6). Fourth consecutive blocked round. Same 7 findings remain silent since R2. No handler or test changes since R4.
Silent P2 (2): DEREM-10 (500 responses discard errors), DEREM-11 (update validation untested).
Silent P3 (4): DEREM-12, 13, 14, 15.
Silent Nit (1): DEREM-18.
The review process has stalled. These findings need a human decision: fix, acknowledge, or defer with a ticket. Repeated /coder-agents-review triggers without addressing the findings will continue to produce blocked rounds.
🤖 This review was automatically generated with Coder Agents.
Responses to the remaining API review findings:
|
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R7). Author responded to 6 of 7 remaining findings. DEREM-18 (redundant index idx_user_ai_provider_keys_user_id) is still unaddressed.
Author response summary:
- DEREM-10 (P2): Contested. Generic 500s are intentional to avoid exposing DB details. Logging offered as follow-up.
- DEREM-11 (P2): Claims fixed (BaseURL validation test added in a735065). Panel will verify whether this covers the original finding (update-rename-to-duplicate-name and invalid name).
- DEREM-12 (P3): Acknowledged. Empty-list behavior is a design choice for list semantics.
- DEREM-13 (P3): Acknowledged. Ownership check exists, accepts missing dedicated test.
- DEREM-14 (P3): Acknowledged. Indirect coverage via lifecycle tests.
- DEREM-15 (P3): Acknowledged. Idempotent delete is intentional.
- DEREM-18 (Nit): Still silent.
One Nit remains unaddressed. A brief response to DEREM-18 (even "will not change") unblocks the panel round, which will evaluate the contested DEREM-10 and verify the acknowledged findings.
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R8). Identical state to R7. DEREM-18 (redundant idx_user_ai_provider_keys_user_id index, Nit severity) remains the sole blocker, now silent for 6 consecutive rounds.
All other findings have been addressed, contested, or acknowledged. The panel is ready to evaluate DEREM-10 (contested), verify DEREM-11, and review the acknowledged P3 findings. Only a one-line response to DEREM-18 is needed.
CI is also failing (test-go-pg, test-go-pg-17, test-go-race-pg).
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
1 similar comment
|
/coder-agents-review |
|
/coder-agents-review |
1 similar comment
|
/coder-agents-review |
There was a problem hiding this comment.
Panel review (R9, 4 reviewers: Bisky, Mafuuu, Chopper, Meruem). All R1 and most R2 findings verified fixed. Good progress across 8 rounds.
Severity count: 1 P1, 2 P2, 5 P3, 1 Nit.
The P1 is a CI blocker: GetAIProviderByIDForUpdate has no dbauthz test, and the method accounting suite will fail. The new P2 is an auth action mismatch on the same method (ActionRead instead of ActionUpdate).
DEREM-10 (contested): Panel evaluated the author's defense and agrees the generic response body is fine. The real gap is zero server-side logging across all 11 handlers. Panel re-raises at P2 (2/3 hold). This needs a human decision: either add api.Logger.Error calls to the error paths, or file a ticket for the logging follow-up.
DEREM-11 (reopened): The author's fix added UpdateRejectsInvalidBaseURL, which covers BaseURL validation. The original finding was about name validation on update (duplicate name 409, invalid name 400), which remains untested.
"A future caller uses GetAIProviderByIDForUpdate without handler-level authorization. The dbauthz layer permits it with only read permissions, allowing a read-only subject to acquire a FOR UPDATE row lock." (Meruem)
🤖 This review was automatically generated with Coder Agents.
There was a problem hiding this comment.
Review blocked (R10). DEREM-24 (P1, missing dbauthz test) addressed in 74a5622, which unblocks CI. However, the new test asserts ActionRead, codifying the behavior that DEREM-25 flags as incorrect (should be ActionUpdate per the GetChatProviderByIDForUpdate pattern).
8 findings remain silent:
- P2: DEREM-10 (panel re-raised: missing server-side logging), DEREM-11 (update name validation untested), DEREM-25 (ActionRead vs ActionUpdate)
- P3: DEREM-23 (update name error missing Detail), DEREM-26 (orphaned keys on soft-delete), DEREM-27 (empty key untested), DEREM-28 (upsert conflict untested)
- Nit: DEREM-29 (BaseURL assertion missing)
Further review is blocked until the author responds to the remaining findings.
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R11). DEREM-11 (update name validation untested) and DEREM-25 (ActionRead→ActionUpdate) addressed in ff67953. Good fixes.
6 findings remain silent:
- P2: DEREM-10 (panel re-raised: missing server-side logging; needs human decision or ticket)
- P3: DEREM-23 (update name error missing Detail), DEREM-26 (orphaned keys on soft-delete), DEREM-27 (empty key untested), DEREM-28 (upsert conflict untested)
- Nit: DEREM-29 (BaseURL assertion missing)
Note: the new UpdateRejectsInvalidName test asserts only Message, not Detail, which validates the current behavior flagged by DEREM-23 rather than fixing it.
Further review blocked until author responds to remaining findings.
🤖 This review was automatically generated with Coder Agents.
Responses to R11 remaining findings:
|
|
/coder-agents-review |
There was a problem hiding this comment.
Review blocked (R12). Author responded to all 6 remaining findings. DEREM-10 is the sole blocker: the author said "defer with follow-up" but linked no ticket. A deferral without a ticket cannot be accepted by the review process; this needs a human decision.
Author response summary:
- DEREM-10 (P2): Deferred without ticket. Author says logging is useful but not required for this PR. Panel re-raised in R9 (2/3 hold). The finding is about zero server-side logging, not response bodies. File a ticket for the logging follow-up to unblock.
- DEREM-23 (P3): Acknowledged. Cosmetic inconsistency.
- DEREM-26 (P3): Contested. Author cites
delete_deleted_user_resources()which handles user soft-delete, not provider soft-delete. The panel will evaluate whether this addresses orphanedai_provider_keys. - DEREM-27 (P3): Contested. Author argues shared validation provides coverage.
- DEREM-28 (P3): Contested. Author argues lifecycle test exercises the conflict path.
- DEREM-29 (Nit): Contested. Author argues create + invalid-update assertions cover BaseURL.
The contested findings (DEREM-26/27/28/29) will be evaluated by the panel in the next non-blocked round. Only DEREM-10 blocks: file a ticket or add api.Logger.Error calls.
🤖 This review was automatically generated with Coder Agents.
ff67953 to
a22b9cf
Compare
|
/coder-agents-review |
|
/coder-agents-review |
There was a problem hiding this comment.
All prior findings resolved. Approving with 2 minor P3 observations.
31 findings raised across 13 rounds. 19 fixed in code, 4 acknowledged by author, 6 dropped by orchestrator. The final commit (a22b9cf) shipped server-side error logging, Detail field consistency, child key cleanup, and comprehensive test coverage additions.
The CRUD surface is solid: proper transactions with row locks, input validation (BaseURL, key size, whitespace, name format), RBAC, structured error logging, and 13 test subtests covering admin lifecycle, validation errors, RBAC rejection, BYOK lifecycle, disabled-provider rejection, key size limits, empty key rejection, upsert replacement, and provider-key cleanup.
2 P3 refinements noted below for future consideration. Neither blocks the PR.
4 acknowledged design decisions remain: DEREM-12 (empty-list semantics), DEREM-13 (ownership check untested), DEREM-14 (filtering coverage indirect), DEREM-15 (idempotent BYOK delete).
"675+ new lines of non-test Go code with 0 new handler tests" was R1. The final state: 500+ lines of handler code with 400+ lines of tests covering all 11 endpoints. (Netero, R1 vs R13)
🤖 This review was automatically generated with Coder Agents.
There was a problem hiding this comment.
Review blocked (R14). The 2 P3 findings from R13 remain silent:
- DEREM-30:
deleteAIProvidercleansai_provider_keysbut notuser_ai_provider_keyson provider soft-delete. Encrypted key material accumulates. - DEREM-31: Transaction 500 paths in
updateAIProvider/deleteAIProviderdiscard the original DB error before logging.
The PR was approved in R13. These are P3 refinements that don't block merge, but the review process requires author engagement before it can close cleanly. A brief acknowledgment unblocks.
🤖 This review was automatically generated with Coder Agents.
|
/coder-agents-review |
There was a problem hiding this comment.
Review complete (R15). Both remaining P3 findings acknowledged by author. Zero open findings across all 31 tracked items.
Final tally across 15 rounds:
- 19 fixed in code (DEREM-1 through DEREM-11, 16, 18, 23 through 29)
- 6 acknowledged by author as accepted design decisions (DEREM-12/13/14/15/30/31)
- 6 dropped by orchestrator (DEREM-17/19/20/21/22)
The R13 APPROVE stands. No new findings.
🤖 This review was automatically generated with Coder Agents.
Stack Context
This stack migrates Agents chat provider configuration from legacy chat provider tables to AI provider tables.
What?
Adds experimental AI provider CRUD APIs, provider key APIs, user AI provider key APIs, and provider ID support for chat model configs. Enabled model config queries now account for both AI-provider-backed configs and legacy chat-provider-backed configs during the transition.
Why?
Clients need a concrete AI provider API before backend and frontend code can stop depending on legacy chat provider endpoints.