feat(cloudflare/ai): add AI.ProviderKey BYOK composition helper - #586
Conversation
eacd314 to
07189a4
Compare
07189a4 to
5909b1e
Compare
4354af0 to
8b62a28
Compare
|
@sam-goodwin rebased and tested with cf resources now |
…oviderConfig composition Replace the monolithic AiGatewayProviderKey Resource (PR alchemy-run#586) with a lightweight composition helper: an Effect.gen that provisions a Secrets Store Secret named {gatewayId}_{providerSlug}_{alias} scoped to ai_gateway, then declares an AiGatewayProviderConfig referencing that secret's id. No Provider registration needed — the helper composes two existing resources rather than managing its own lifecycle. Also fix process.env usage in ProviderConfig.ts JSDoc example to use Config.redacted() per the maintainer's review comment (sam-goodwin, line 154 on the original PR).
8b62a28 to
f2a8482
Compare
|
Reworked this onto current |
`Cloudflare.AI.ProviderKey` bundles the two low-level resources a Cloudflare
AI Gateway bring-your-own-key requires: a Secrets Store `Secret` and the
`GatewayProvider` config that references it. Cloudflare mandates the secret
live in the gateway's attached store, be scoped to `ai_gateway`, and be named
exactly `{gatewayId}_{providerSlug}_{alias}` — the helper owns that naming
contract so app stacks declare one resource instead of hand-wiring both.
Returns `{ secret, gatewayProvider }` so callers can still reference either
underlying resource. Also points the `GatewayProvider` manual-wiring example
at this helper and switches its secret example to `Config.redacted`.
672034a to
500bddc
Compare
|
Rebased onto current |
|
@sam-goodwin any feedback on this? would love to use it, or still reworking some internals a bit? |
Sorry for delay, trying my best to keep up. |
| export const ProviderKey = (id: string, props: ProviderKeyProps) => | ||
| Effect.gen(function* () { | ||
| const alias = props.alias ?? "default"; | ||
| const secret = yield* Secret(props.secretResourceId ?? `${id}-secret`, { |
There was a problem hiding this comment.
Instead of ${id}-secret, you could instead pipe the Effect.gen (ProviderKey effect) to Namespace.push(id) and then name these Secret("Secret") and GatewayProvider("Provider")and they will be namespaced under${id}`
There was a problem hiding this comment.
Applied in 55e4b0f — the ProviderKey effect is piped through Namespace.push(id) and the children are now Secret("Secret") and GatewayProvider("Provider") (dropped the secretResourceId escape hatch since the ${id}-secret default is gone). Also added a reconciliation test covering in-place value rotation and the alias-change replacement cascade. All 4 live tests pass.
….push
Per review: pipe the ProviderKey effect through Namespace.push(id) so the
backing resources are Secret("Secret") and GatewayProvider("Provider"),
namespaced under ${id}. Drops the secretResourceId escape hatch (the
${id}-secret default it existed for is gone).
Adds a reconciliation test covering in-place value rotation (stable
secretId + providerConfigId) and the alias-change replacement cascade
(secret renamed, provider config replaced and re-pointed, old secret
reclaimed).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Adds @resource/@product/@category + @section/@example blocks so docs:gen emits an API reference page (it skips untagged exports), documents the namespaced children and update/replacement semantics, and adds field docs on the returned { secret, gatewayProvider }. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…s signature Replace the Omit<GatewayProviderInputProps> intersection with an explicitly declared plain-typed interface; the constructor takes InputProps<ProviderKeyProps> so the engine's Input wrapping stays at the signature, not in the Props declaration. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Cloudflare.AI.ProviderKey— a composition helper that declares a Cloudflare AI Gateway bring-your-own-key (BYOK) provider key as a single resource.A BYOK key needs two coordinated resources:
Secretholding the provider API key — scoped toai_gatewayand named exactly{gatewayId}_{providerSlug}_{alias}, andGatewayProviderconfig that references that secret on the gateway.This helper owns that naming contract and wires both, so app stacks declare one resource instead of hand-coupling the two:
It returns
{ secret, gatewayProvider }so either underlying resource stays addressable.Notes
mainand re-ported onto theCloudflare/AiGateway/→Cloudflare/AI/restructure: the helper composesGatewayProvider(formerlyAiGatewayProviderConfig), lives atAI/ProviderKey.ts, and surfaces asCloudflare.AI.ProviderKey.Namespace.push(id), so the children are plainSecret("Secret")andGatewayProvider("Provider")namespaced under${id}(drops thesecretResourceIdescape hatch the old${id}-secretdefault needed).GatewayProvidermanual-wiring example to useConfig.redacted(per the earlier review note) and cross-links this helper.ProviderKeyis tagged@resourcewith@section/@exampleblocks, sodocs:genemits an API reference page for it (untagged exports are skipped).{gatewayId}_{providerSlug}_{alias}naming contract, explicit alias, redeploy idempotency, in-place value rotation (stablesecretId+providerConfigId), the alias-change replacement cascade (secret renamed, provider config replaced and re-pointed, old secret reclaimed), and a post-destroy check that the BYOK secret is reclaimed from the surviving (adopted) store.tsc -bis green. Thecheckjob's red isdocs:checkfailing on pre-existing broken links to unrelated Cloudflare provider pages (/providers/cloudflare/email/*,/providers/cloudflare/queue) — not introduced here (nowebsite/changes).🤖 Generated with Claude Code