Skip to content

Commit 7902c83

Browse files
santiago.gonzalezcarvajcenteneradavidfierro
andcommitted
feat(opencode): add Snowflake bearer OAuth support with refresh handling
Co-authored-by: David Fierro <14184197+davidfierro@users.noreply.github.com>
1 parent 936363e commit 7902c83

8 files changed

Lines changed: 935 additions & 88 deletions

File tree

packages/core/src/plugin/provider/snowflake-cortex.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,17 @@ export const SnowflakeCortexPlugin = PluginV2.define({
7070
return {
7171
"aisdk.sdk": Effect.fn(function* (evt) {
7272
if (evt.model.providerID !== ProviderV2.ID.make("snowflake-cortex")) return
73-
const pat =
74-
process.env.SNOWFLAKE_CORTEX_PAT ?? (typeof evt.options.apiKey === "string" ? evt.options.apiKey : undefined)
73+
const token =
74+
process.env.SNOWFLAKE_CORTEX_TOKEN ??
75+
process.env.SNOWFLAKE_CORTEX_PAT ??
76+
(typeof evt.options.token === "string" ? evt.options.token : undefined) ??
77+
(typeof evt.options.apiKey === "string" ? evt.options.apiKey : undefined)
7578
const upstream = typeof evt.options.fetch === "function" ? (evt.options.fetch as FetchLike) : undefined
7679
if (evt.options.includeUsage !== false) evt.options.includeUsage = true
7780
const mod = yield* Effect.promise(() => import("@ai-sdk/openai-compatible"))
7881
evt.sdk = mod.createOpenAICompatible({
7982
...evt.options,
80-
...(pat ? { apiKey: pat } : {}),
83+
...(token ? { apiKey: token } : {}),
8184
fetch: cortexFetch(upstream) as typeof fetch,
8285
} as any)
8386
}),

packages/core/test/plugin/provider-snowflake-cortex.test.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,48 @@ describe("SnowflakeCortexPlugin", () => {
7272
),
7373
)
7474

75+
it.effect("uses SNOWFLAKE_CORTEX_TOKEN env var", () =>
76+
withEnv({ SNOWFLAKE_CORTEX_TOKEN: "oauth-token", SNOWFLAKE_CORTEX_PAT: undefined }, () =>
77+
Effect.gen(function* () {
78+
const plugin = yield* PluginV2.Service
79+
yield* plugin.add(SnowflakeCortexPlugin)
80+
const result = yield* plugin.trigger(
81+
"aisdk.sdk",
82+
{
83+
model: model("snowflake-cortex", "claude-sonnet-4-6"),
84+
package: "@ai-sdk/openai-compatible",
85+
options: { name: "snowflake-cortex", baseURL: "https://test.snowflakecomputing.com/api/v2/cortex/v1" },
86+
},
87+
{},
88+
)
89+
expect(result.sdk).toBeDefined()
90+
}),
91+
),
92+
)
93+
94+
it.effect("falls back to options.token when no Snowflake env token is set", () =>
95+
withEnv({ SNOWFLAKE_CORTEX_TOKEN: undefined, SNOWFLAKE_CORTEX_PAT: undefined }, () =>
96+
Effect.gen(function* () {
97+
const plugin = yield* PluginV2.Service
98+
yield* plugin.add(SnowflakeCortexPlugin)
99+
const result = yield* plugin.trigger(
100+
"aisdk.sdk",
101+
{
102+
model: model("snowflake-cortex", "claude-sonnet-4-6"),
103+
package: "@ai-sdk/openai-compatible",
104+
options: {
105+
name: "snowflake-cortex",
106+
baseURL: "https://test.snowflakecomputing.com/api/v2/cortex/v1",
107+
token: "options-token",
108+
},
109+
},
110+
{},
111+
)
112+
expect(result.sdk).toBeDefined()
113+
}),
114+
),
115+
)
116+
75117
it.effect("sets includeUsage on the SDK options", () =>
76118
withEnv({ SNOWFLAKE_CORTEX_PAT: "test-pat" }, () =>
77119
Effect.gen(function* () {

packages/opencode/src/cli/cmd/providers.ts

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -477,25 +477,6 @@ export const ProvidersLoginCommand = effectCmd({
477477
)
478478
}
479479

480-
if (provider === "snowflake-cortex") {
481-
const account = yield* promptValue(
482-
yield* Prompt.text({
483-
message: "Snowflake Account Identifier",
484-
placeholder: "xy12345.us-east-1",
485-
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
486-
}),
487-
)
488-
const pat = yield* promptValue(
489-
yield* Prompt.password({
490-
message: "Programmatic Access Token (PAT)",
491-
validate: (x) => (x && x.length > 0 ? undefined : "Required"),
492-
}),
493-
)
494-
yield* Effect.orDie(authSvc.set(provider, { type: "api", key: pat, metadata: { account } }))
495-
yield* Prompt.outro("Done")
496-
return
497-
}
498-
499480
const key = yield* Prompt.password({
500481
message: "Enter your API key",
501482
validate: (x) => (x && x.length > 0 ? undefined : "Required"),

packages/opencode/src/plugin/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import { CloudflareAIGatewayAuthPlugin, CloudflareWorkersAuthPlugin } from "./cl
1919
import { AzureAuthPlugin } from "./azure"
2020
import { DigitalOceanAuthPlugin } from "./digitalocean"
2121
import { XaiAuthPlugin } from "./xai"
22+
import { SnowflakeCortexAuthPlugin } from "./snowflake-cortex"
2223
import { Effect, Layer, Context } from "effect"
2324
import { EffectBridge } from "@/effect/bridge"
2425
import { InstanceState } from "@/effect/instance-state"
@@ -75,6 +76,7 @@ function internalPlugins(flags: RuntimeFlags.Info): PluginInstance[] {
7576
CloudflareAIGatewayAuthPlugin,
7677
AzureAuthPlugin,
7778
DigitalOceanAuthPlugin,
79+
SnowflakeCortexAuthPlugin,
7880
XaiAuthPlugin,
7981
]
8082
}

0 commit comments

Comments
 (0)