Skip to content

Commit cfe1bad

Browse files
mdesmetclaudeanandgupta42
authored
fix: show Snowflake Cortex in provider list before authentication (#447)
Snowflake Cortex was invisible in the UI because it has no env var trigger (env: []) and is plugin-auth only — it only appeared after the user had already completed the auth flow, making it undiscoverable. - Add Provider.all() to expose the full internal provider database (including unauthenticated custom providers like Snowflake Cortex) - Inject custom providers into GET /provider so Snowflake Cortex appears in the UI before auth, letting users find and authenticate it - Add tests: Provider.all() unauthenticated, disabled_providers and enabled_providers config filtering for custom providers Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com> Co-authored-by: anandgupta42 <93243293+anandgupta42@users.noreply.github.com>
1 parent 3022614 commit cfe1bad

File tree

3 files changed

+128
-0
lines changed

3 files changed

+128
-0
lines changed

packages/opencode/src/provider/provider.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1247,6 +1247,9 @@ export namespace Provider {
12471247
return {
12481248
models: languages,
12491249
providers,
1250+
// altimate_change start — expose full provider database (including unauthenticated custom providers)
1251+
database,
1252+
// altimate_change end
12501253
sdk,
12511254
modelLoaders,
12521255
varsLoaders,
@@ -1257,6 +1260,12 @@ export namespace Provider {
12571260
return state().then((state) => state.providers)
12581261
}
12591262

1263+
// altimate_change start — expose full provider database (including unauthenticated custom providers)
1264+
export async function all() {
1265+
return state().then((state) => state.database)
1266+
}
1267+
// altimate_change end
1268+
12601269
async function getSDK(model: Model) {
12611270
try {
12621271
using _ = log.time("getSDK", {

packages/opencode/src/server/routes/provider.ts

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,8 +49,19 @@ export const ProviderRoutes = lazy(() =>
4949
}
5050

5151
const connected = await Provider.list()
52+
// altimate_change start — include custom providers (e.g. Snowflake Cortex) even when not yet authenticated
53+
const allDatabase = await Provider.all()
54+
const customProviders: Record<string, Provider.Info> = {}
55+
for (const [key, value] of Object.entries(allDatabase)) {
56+
if (key in filteredProviders || key in connected) continue
57+
if ((enabled ? enabled.has(key) : true) && !disabled.has(key)) {
58+
customProviders[key] = value
59+
}
60+
}
61+
// altimate_change end
5262
const providers = Object.assign(
5363
mapValues(filteredProviders, (x) => Provider.fromModelsDevProvider(x)),
64+
customProviders,
5465
connected,
5566
)
5667
return c.json({

packages/opencode/test/provider/snowflake.test.ts

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -606,3 +606,111 @@ describe("snowflake-cortex provider", () => {
606606
}
607607
})
608608
})
609+
610+
// ---------------------------------------------------------------------------
611+
// Provider.all() — unauthenticated discoverability
612+
// ---------------------------------------------------------------------------
613+
614+
describe("Provider.all() discoverability", () => {
615+
test("includes snowflake-cortex even without oauth auth", async () => {
616+
const savedAuth = await Auth.get("snowflake-cortex")
617+
if (savedAuth) await Auth.remove("snowflake-cortex")
618+
try {
619+
await using tmp = await tmpdir({
620+
init: async (dir) => {
621+
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://altimate.ai/config.json" }))
622+
},
623+
})
624+
await Instance.provide({
625+
directory: tmp.path,
626+
init: async () => {
627+
Env.remove("SNOWFLAKE_ACCOUNT")
628+
},
629+
fn: async () => {
630+
const allProviders = await Provider.all()
631+
expect(allProviders["snowflake-cortex"]).toBeDefined()
632+
expect(allProviders["snowflake-cortex"].name).toBe("Snowflake Cortex")
633+
// list() still returns nothing (not authenticated)
634+
const connected = await Provider.list()
635+
expect(connected["snowflake-cortex"]).toBeUndefined()
636+
},
637+
})
638+
} finally {
639+
if (savedAuth) await Auth.set("snowflake-cortex", savedAuth)
640+
}
641+
})
642+
643+
test("all() includes snowflake-cortex models", async () => {
644+
await using tmp = await tmpdir({
645+
init: async (dir) => {
646+
await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://altimate.ai/config.json" }))
647+
},
648+
})
649+
await Instance.provide({
650+
directory: tmp.path,
651+
fn: async () => {
652+
const allProviders = await Provider.all()
653+
const models = allProviders["snowflake-cortex"]?.models
654+
expect(models).toBeDefined()
655+
expect(models["claude-sonnet-4-6"]).toBeDefined()
656+
expect(models["deepseek-r1"]).toBeDefined()
657+
},
658+
})
659+
})
660+
661+
test("disabled_providers config suppresses snowflake-cortex from all()", async () => {
662+
await using tmp = await tmpdir({
663+
init: async (dir) => {
664+
await Bun.write(
665+
path.join(dir, "opencode.json"),
666+
JSON.stringify({ $schema: "https://altimate.ai/config.json", disabled_providers: ["snowflake-cortex"] }),
667+
)
668+
},
669+
})
670+
await Instance.provide({
671+
directory: tmp.path,
672+
fn: async () => {
673+
// Provider.all() returns raw database, config filtering happens at the route level.
674+
// Verify the route-level filtering logic: a disabled provider should not appear
675+
// in the merged provider list used by GET /provider.
676+
const allProviders = await Provider.all()
677+
const connected = await Provider.list()
678+
// Simulate the route filtering (same logic as routes/provider.ts)
679+
const disabled = new Set(["snowflake-cortex"])
680+
const customProviders: Record<string, (typeof allProviders)[string]> = {}
681+
for (const [key, value] of Object.entries(allProviders)) {
682+
if (key in connected) continue
683+
if (!disabled.has(key)) customProviders[key] = value
684+
}
685+
expect(customProviders["snowflake-cortex"]).toBeUndefined()
686+
},
687+
})
688+
})
689+
690+
test("enabled_providers config suppresses snowflake-cortex when not listed", async () => {
691+
await using tmp = await tmpdir({
692+
init: async (dir) => {
693+
await Bun.write(
694+
path.join(dir, "opencode.json"),
695+
JSON.stringify({ $schema: "https://altimate.ai/config.json", enabled_providers: ["anthropic"] }),
696+
)
697+
},
698+
})
699+
await Instance.provide({
700+
directory: tmp.path,
701+
fn: async () => {
702+
const allProviders = await Provider.all()
703+
const connected = await Provider.list()
704+
// Simulate route filtering with enabled_providers
705+
// (snowflake-cortex is not in the enabled list, so it should be excluded)
706+
const enabled = new Set(["anthropic"])
707+
const customProviders: Record<string, (typeof allProviders)[string]> = {}
708+
for (const [key, value] of Object.entries(allProviders)) {
709+
if (key in connected) continue
710+
if (enabled.has(key)) customProviders[key] = value
711+
}
712+
expect(customProviders["snowflake-cortex"]).toBeUndefined()
713+
},
714+
})
715+
})
716+
})

0 commit comments

Comments
 (0)