Thanks to visit codestin.com
Credit goes to github.com

Skip to content

feat: fetch providers over DRPC - #26650

Merged
dannykopping merged 4 commits into
mainfrom
dk/provider-drpc
Jun 29, 2026
Merged

feat: fetch providers over DRPC#26650
dannykopping merged 4 commits into
mainfrom
dk/provider-drpc

Conversation

@dannykopping

@dannykopping dannykopping commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

Closes AIGOV-455.

Why

The AI Gateway (aibridged) is being split into a standalone process that must not touch the database. coderd stays the source of truth and seeds the ai_providers / ai_provider_keys tables from the environment. This PR adds a DRPC call so the gateway fetches provider config from coderd instead of reading the DB, for both the embedded and standalone daemons.

What

  • Proto: new ProviderConfigurator service with a unary GetAIProviders RPC, plus AIProvider / AIProviderBedrock messages. CurrentMinor bumped to 1 (additive).
  • Server (coderd/aibridgedserver): GetAIProviders runs a read-only InTx under LockIDAIProvidersEnvSeed so it never returns a mid-seed snapshot, reads providers (incl. disabled) plus keys for enabled ones, and maps to proto under dbauthz.AsAIBridged. Unmappable rows are skipped and logged; plaintext keys and Bedrock secrets are never logged.
  • Client: DRPCProviderConfiguratorClient wired into the client union, dialer.go, and CreateInMemoryAIBridgeServer.
  • cli: BuildProvidersFromProto maps the response through the existing DB-neutral buildProvider. A shared poolRPCReloader does the fetch/build/replace for both daemons: the embedded daemon reloads on every ai_providers change and fails startup if it cannot subscribe; the standalone gateway drives the same reloader once at startup, retrying until success and staying interruptible.
  • Dead code removed: BuildProvidersFromConfig, ProvidersFromConfig, AIProviderFromConfig, and the DB-read BuildProviders path.

@pawbana
pawbana force-pushed the pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command branch 3 times, most recently from 334315a to 9973338 Compare June 25, 2026 09:44
@pawbana
pawbana force-pushed the pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command branch from 9973338 to 06af6f1 Compare June 25, 2026 12:16
@pawbana
pawbana force-pushed the pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command branch from 06af6f1 to 83efd04 Compare June 25, 2026 12:22

dannykopping commented Jun 25, 2026

Copy link
Copy Markdown
Contributor Author

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

coder-agents-review Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Chat: Spend limit reached | View chat
Requested: 2026-06-26 09:25 UTC by @dannykopping
Spend: $139.52 / $100.00 (limit reached)

Review history
  • R1 (2026-06-25): 23 reviewers, 6 Nit, 2 P2, 3 P3, COMMENT. Review
  • R2 (2026-06-26), 6 Nit, 2 P2, 3 P3, COMMENT. Review
  • R3 (2026-06-26): 8 reviewers, 7 Nit, 2 P2, 5 P3, COMMENT. Review
  • R4 (2026-06-29): 3 reviewers, 7 Nit, 2 P2, 5 P3, COMMENT. Review

deep-review v0.9.0 | Round 4 | 4820cbf..8f1d264

Last posted: Round 4, 14 findings (2 P2, 5 P3, 7 Nit), COMMENT. Review

Finding inventory

Findings

# Sev Status Location Summary Round Reviewer Posted
CRF-1 P2 Author fixed (c3a38c2) cli/aibridged.go:83 Pool starts empty; subscription failure loses boot-time fallback, leaving AI bridge permanently broken R1 Mafuuu P2, Hisoka P3, Chopper P3, Meruem P3, Zoro P3, Pariston P3 Yes
CRF-2 P2 Author fixed (e769b460c917) coderd/aibridged/server.go:5 DRPCServer interface missing DRPCProviderConfiguratorServer; compile-time assertion incomplete R1 Ryosuke Yes
CRF-3 P3 Author fixed (c3a38c2) enterprise/cli/aigatewaystart.go:237 Standalone gateway discards provider outcomes; no reload metrics recorded R1 Hisoka P3, Kurapika P3, Meruem P4 Yes
CRF-4 P3 Author fixed (c3a38c2) coderd/aibridged/proto/aibridged.proto:184 Proto comment "only when type=bedrock" is inaccurate; bedrock field set whenever settings have Bedrock R1 Leorio Yes
CRF-5 P3 Author fixed (e769b460c917) coderd/aibridgedserver/providers_test.go:155 Negative assertion relies on 250ms timeout without verifying fetch goroutine reached lock R1 Komugi Yes
CRF-6 Nit Author fixed (c3a38c2) cli/aibridged.go:127 BuildProvidersFromProto doc comment describes system architecture the function does not own R1 Gon Yes
CRF-7 Nit Author fixed (c3a38c2) cli/aibridged.go:35 "only the data path changed" is changelog text in a production comment R1 Gon Yes
CRF-8 Nit Author fixed (c3a38c2) coderd/aibridged/proto/aibridged.proto:43 "synchronises" British English; codebase uses American R1 Leorio Yes
CRF-9 Nit Author fixed (c3a38c2) cli/aibridged.go:86 Warn log message missing verb (reads as intent, not outcome) R1 Leorio Yes
CRF-10 Nit Author fixed (c3a38c2) enterprise/coderd/aibridge_reload_test.go:99 defer on RecordReloadAttempt inverts production metric timing R1 Kite, Meruem Yes
CRF-11 Nit Author fixed (c3a38c2) coderd/aibridged/dialer.go:60 Stale docstrings omit ProviderConfigurator from DRPC service list R1 Kite, Razor Yes
CRF-12 Note Dropped by orchestrator (intentional tradeoff; server-side Error log is the correct signal) coderd/aibridgedserver/providers.go:86 Server-side row skip hides corrupt providers from gateway metrics R1 Hisoka, Mafuuu, Pen Botter No
CRF-13 Note Dropped by orchestrator (negligible at current call frequency; revisit for AIGOV-465) coderd/aibridgedserver/providers.go:46 Advisory lock exclusive where shared would suffice R1 Pariston, Kurapika, Ryosuke, Knov No
CRF-14 P3 Dropped by orchestrator (4 lines with different error handling; extraction premature) enterprise/cli/aigatewaystart.go:228 initStandaloneProviders duplicates core of poolRPCReloader.Reload R1 Robin No
CRF-15 P3 Dropped by orchestrator (50ms initial delay negligible on startup path) enterprise/cli/aigatewaystart.go:229 Retry loop sleeps before first attempt R1 Razor No
CRF-16 P3 Dropped by orchestrator (explicitly out of scope per AIGOV-465) enterprise/cli/aigatewaystart.go:114 Standalone gateway no staleness signal after initial load R1 Pen Botter No
CRF-17 P3 Author fixed (8f1d264) enterprise/coderd/aibridge_reload_test.go:95 testPoolReloader duplicates exported NewPoolRPCReloader R3 Netero Yes
CRF-18 Nit Author fixed (8f1d264) coderd/aibridgedserver/aibridgedserver.go:710 Nolint comment references deleted embedded DB-read path R3 Netero Yes
CRF-19 P3 Author fixed (8f1d264) enterprise/cli/aigatewaystart_internal_test.go:36 TestLoadProviders_Interruptible missing retry-then-succeed path R3 Bisky Yes

Round log

Round 1

Panel. 2 P2, 3 P3, 6 Nit. 5 dropped (3 Note, 1 scope, 1 negligible). Reviewed against 83efd044efc9..bb14ffbddc0f.

Round 2

BLOCKED. CRF-1, CRF-3, CRF-4, CRF-6, CRF-7, CRF-8, CRF-9, CRF-10, CRF-11 addressed. CRF-2 (P2) and CRF-5 (P3) silent. No review.

Round 3

Panel. CRF-2 and CRF-5 addressed. All R1 findings resolved. Netero found CRF-17 (P3) and CRF-18 (Nit). Panel found CRF-19 (P3). No regressions from R1 fixes. Reviewed against e01b0a6a7b5a..e769b460c917.

Round 4

All R3 findings addressed. CRF-17 replaced with production code. CRF-18 comment fixed. CRF-19 test moved to PR #26605. Netero clean (1 dead-code finding dropped: NewWebsocketDialer consumer in stacked PR #26605). Approved. Reviewed against 4820cbf..8f1d264.

About deep-review

CRF = Coder Review Finding (P0-P4, Nit, Note)

Reviewer Focus
Bisky tests
Chopper ops/errors
Churn-guard change verification
Ging language modernization
Gon naming
Hisoka edge cases
Killua perf
Kite change integrity
Knov contracts
Knuckle SQL
Komugi flake/determinism
Kurapika security
Law decomposition
Leorio docs
Luffy product
Mafu-san process
Mafuuu contracts
Melody dispatch/pairing
Meruem structural
Nami frontend
Netero mechanical checks
Pariston premise testing
Pen-botter product gaps
Razor verification
Robin duplication
Ryosuke Go arch
Takumi concurrency
Zoro shape

🤖 Managed by Coder Agents.

@dannykopping dannykopping changed the title feat(coderd/aibridged): fetch providers over DRPC (GetAIProviders) feat: fetch providers over DRPC (GetAIProviders) Jun 25, 2026
@dannykopping dannykopping changed the title feat: fetch providers over DRPC (GetAIProviders) feat: fetch providers over DRPC Jun 25, 2026

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clean, well-scoped refactor. The DB-to-DRPC migration is symmetric across embedded and standalone paths, the proto surface is minimal, dead code is cleanly removed, and the concurrency test against real Postgres advisory locks is solid. Test density is healthy at 44%.

As Knov put it: "Good perimeter: disabled providers withhold keys and settings at the server, not the client."

Severity breakdown: 2 P2, 3 P3, 6 Nit.

The two P2s: (1) the embedded daemon can now start serving with an empty provider pool if the pubsub subscription or initial reload fails, losing the old boot-time fallback that guaranteed providers were loaded before the daemon accepted requests; (2) the DRPCServer interface was not updated to include DRPCProviderConfiguratorServer, so the compile-time assertion and any future mock targeting that interface silently omits the new service.

Observations not posted as findings: the advisory lock uses pg_advisory_xact_lock (exclusive) where pg_advisory_xact_lock_shared would let concurrent reads proceed without serializing against each other. At current call rates this has no impact, but worth noting before AIGOV-465 adds refresh-on-reseed. Server-side row skipping for corrupt settings is an intentional tradeoff (one corrupt blob does not break the fleet); the observability gap (gateway metrics cannot see the skip) is acceptable since the server-side Error log is the correct signal.


coderd/aibridged/server.go:5

P2 [CRF-2] DRPCServer embeds DRPCRecorderServer, DRPCMCPConfiguratorServer, and DRPCAuthorizerServer, but not DRPCProviderConfiguratorServer. The client-side DRPCClient (client.go:17) was updated to embed DRPCProviderConfiguratorClient, but the server-side union was not.

"Every consumer that type-asserts against DRPCServer silently misses the new service. If a future mock or alternative implementation targets DRPCServer, it will silently omit GetAIProviders." (Ryosuke)

The compile-time assertion at aibridgedserver.go:58 (var _ aibridged.DRPCServer = &Server{}) does not verify ProviderConfigurator.

Fix: add proto.DRPCProviderConfiguratorServer to this interface.

🤖

🤖 This review was automatically generated with Coder Agents.

Comment thread cli/aibridged.go
Comment thread enterprise/cli/aigatewaystart.go Outdated
Comment thread coderd/aibridged/proto/aibridged.proto Outdated
Comment thread coderd/aibridgedserver/providers_test.go Outdated
Comment thread cli/aibridged.go Outdated
Comment thread cli/aibridged.go Outdated
Comment thread coderd/aibridged/proto/aibridged.proto Outdated
Comment thread cli/aibridged.go Outdated
Comment thread enterprise/coderd/aibridge_reload_test.go Outdated
Comment thread coderd/aibridged/dialer.go Outdated
@pawbana
pawbana changed the base branch from pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command to graphite-base/26650 June 25, 2026 15:37
@dannykopping
dannykopping force-pushed the graphite-base/26650 branch from 83efd04 to bf6d5b8 Compare June 26, 2026 08:02
@dannykopping
dannykopping changed the base branch from graphite-base/26650 to pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command June 26, 2026 08:02
@linear-code

linear-code Bot commented Jun 26, 2026

Copy link
Copy Markdown

AIGOV-455

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

9 of 11 findings from Round 1 were addressed in c3a38c2. Good progress.

Further review is blocked until the remaining 2 silent findings receive a response (fix, acknowledge, or contest):

CRF-2 (P2) coderd/aibridged/server.go:5: DRPCServer interface still embeds only 3 services; DRPCProviderConfiguratorServer is missing. The compile-time assertion at aibridgedserver.go:58 does not verify the new service, and any future mock targeting DRPCServer silently omits GetAIProviders. Fix: add proto.DRPCProviderConfiguratorServer to the interface.

CRF-5 (P3) coderd/aibridgedserver/providers_test.go:155: The negative assertion in TestGetAIProvidersBlocksOnSeedLock relies on time.After(testutil.IntervalMedium) without verifying the fetch goroutine reached AcquireLock. On a loaded CI runner the assertion can pass vacuously. Fix: verify the goroutine entered the blocking call (e.g., query pg_stat_activity) or acknowledge the known limitation.

🤖 This review was automatically generated with Coder Agents.

@dannykopping

Copy link
Copy Markdown
Contributor Author

CRF-2: Fixed in f5b7463309 — DRPCProviderConfiguratorServer is now embedded in the DRPCServer interface (coderd/aibridged/server.go), so the compile-time assertion var _ aibridged.DRPCServer = &Server{} covers GetAIProviders and any consumer type-asserting against DRPCServer sees the new service.

@pawbana
pawbana changed the base branch from pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command to graphite-base/26650 June 26, 2026 09:21
@dannykopping
dannykopping force-pushed the graphite-base/26650 branch from bf6d5b8 to e01b0a6 Compare June 26, 2026 09:23
@dannykopping
dannykopping changed the base branch from graphite-base/26650 to pawel/aigov-315-implement-basic-coder-aibridge-start-sub-command June 26, 2026 09:23

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@dannykopping
dannykopping changed the base branch from graphite-base/26650 to pawel/aigov-308-implement-apiv2aibridgeserve-endpoint-2 June 26, 2026 12:18
@dannykopping
dannykopping marked this pull request as ready for review June 26, 2026 12:21
@dannykopping
dannykopping requested a review from pawbana June 26, 2026 12:21
@pawbana
pawbana force-pushed the dk/provider-drpc branch from 4c9b451 to a1de112 Compare June 26, 2026 14:31
@pawbana
pawbana force-pushed the pawel/aigov-308-implement-apiv2aibridgeserve-endpoint-2 branch from 0241b7a to 1ff23e2 Compare June 26, 2026 14:31
@pawbana
pawbana changed the base branch from pawel/aigov-308-implement-apiv2aibridgeserve-endpoint-2 to graphite-base/26650 June 26, 2026 15:15
@dannykopping
dannykopping force-pushed the graphite-base/26650 branch from 1ff23e2 to c782cbc Compare June 29, 2026 08:38
@dannykopping
dannykopping changed the base branch from graphite-base/26650 to main June 29, 2026 08:38

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review coder-agents-review Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

All 14 findings from rounds 1 and 3 are resolved. The author addressed every finding with substantive fixes, not band-aids: subscription failure made fatal (CRF-1), DRPCServer interface aligned with DRPCClient (CRF-2), pg_locks polling replaced timing-based inference (CRF-5), test helper replaced with production code (CRF-17), retry-succeed test coverage added and moved to stacked PR #26605 (CRF-19).

The refactor is clean. coderd owns the database; the gateway fetches provider config over DRPC. Both embedded and standalone daemons share an identical data path through NewPoolRPCReloader. The advisory lock serializes reads against the env seed. Disabled providers withhold keys and credentials at the server. Dead code is fully removed. Test density is healthy at 39%.

NewWebsocketDialer has no in-tree callers in this PR; its consumer lives in the stacked PR #26605.

🤖 This review was automatically generated with Coder Agents.

Copy link
Copy Markdown
Contributor Author

/coder-agents-review

@coder-agents-review

Copy link
Copy Markdown
Contributor

@dannykopping ⛔ This review has reached its per-chat spend limit ($139.52 / $100.00). Further review rounds are paused.

To raise the limit and continue, comment:

/coder-agents-review set-spend-limit:150

This is a per-chat budget, separate from any account-level usage limit.

🤖 Managed by Coder Agents.

Comment thread coderd/aibridged/aibridged.go
Comment thread coderd/aibridgedserver/aibridgedserver_test.go
Add a DRPC ProviderConfigurator service (GetAIProviders) so the embedded and
standalone AI Gateway daemons build their provider pool from coderd over DRPC
instead of reading the database directly. Includes the shared poolRPCReloader,
pubsub-driven reloads (fatal on subscription failure), the WebSocket dialer for
standalone gateways, and the DRPCServer interface/proto plumbing.
cli.BuildProviders (the DB-based builder) was removed in favor of fetching
providers over the in-memory DRPC. Update StartTestAIBridgeDaemon to start with
an empty pool and populate it via cli.NewPoolRPCReloader + SubscribeProviderReload,
matching cli.newAIBridgeDaemon.
…t branch

NewWebsocketDialer is only used by the standalone "coder ai-gateway start"
command, which is added in pawel/aigov-315. It landed here via a stack reorder;
move it to the branch that consumes it so each PR is correctly scoped.
@dannykopping
dannykopping merged commit ce94d42 into main Jun 29, 2026
30 of 31 checks passed

Copy link
Copy Markdown
Contributor Author

Merge activity

@dannykopping
dannykopping deleted the dk/provider-drpc branch June 29, 2026 11:35
@github-actions github-actions Bot locked and limited conversation to collaborators Jun 29, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants