test: keep env runtime local to provider tests

This commit is contained in:
Kit Langton
2026-04-14 22:09:18 -04:00
parent d7c4d7f6ca
commit 203d974693
3 changed files with 83 additions and 81 deletions

View File

@@ -47,7 +47,6 @@ import { Pty } from "@/pty"
import { Installation } from "@/installation"
import { ShareNext } from "@/share/share-next"
import { SessionShare } from "@/share/session"
import { Env } from "@/env"
export const AppLayer = Layer.mergeAll(
Observability.layer,
@@ -96,7 +95,6 @@ export const AppLayer = Layer.mergeAll(
Installation.defaultLayer,
ShareNext.defaultLayer,
SessionShare.defaultLayer,
Env.defaultLayer,
)
const rt = ManagedRuntime.make(AppLayer, { memoMap })

View File

@@ -11,8 +11,10 @@ import { Global } from "../../src/global"
import { Filesystem } from "../../src/util/filesystem"
import { Effect } from "effect"
import { AppRuntime } from "../../src/effect/app-runtime"
import { makeRuntime } from "../../src/effect/run-service"
const set = (k: string, v: string) => AppRuntime.runPromise(Env.Service.use((svc) => svc.set(k, v)))
const env = makeRuntime(Env.Service, Env.defaultLayer)
const set = (k: string, v: string) => env.runSync((svc) => svc.set(k, v))
async function list() {
return AppRuntime.runPromise(
@@ -44,8 +46,8 @@ test("Bedrock: config region takes precedence over AWS_REGION env var", async ()
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_REGION", "us-east-1")
await set("AWS_PROFILE", "default")
set("AWS_REGION", "us-east-1")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -69,8 +71,8 @@ test("Bedrock: falls back to AWS_REGION env var when no config region", async ()
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_REGION", "eu-west-1")
await set("AWS_PROFILE", "default")
set("AWS_REGION", "eu-west-1")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -124,9 +126,9 @@ test("Bedrock: loads when bearer token from auth.json is present", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "")
await set("AWS_ACCESS_KEY_ID", "")
await set("AWS_BEARER_TOKEN_BEDROCK", "")
set("AWS_PROFILE", "")
set("AWS_ACCESS_KEY_ID", "")
set("AWS_BEARER_TOKEN_BEDROCK", "")
},
fn: async () => {
const providers = await list()
@@ -170,8 +172,8 @@ test("Bedrock: config profile takes precedence over AWS_PROFILE env var", async
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
await set("AWS_ACCESS_KEY_ID", "test-key-id")
set("AWS_PROFILE", "default")
set("AWS_ACCESS_KEY_ID", "test-key-id")
},
fn: async () => {
const providers = await list()
@@ -202,7 +204,7 @@ test("Bedrock: includes custom endpoint in options when specified", async () =>
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -235,10 +237,10 @@ test("Bedrock: autoloads when AWS_WEB_IDENTITY_TOKEN_FILE is present", async ()
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_WEB_IDENTITY_TOKEN_FILE", "/var/run/secrets/eks.amazonaws.com/serviceaccount/token")
await set("AWS_ROLE_ARN", "arn:aws:iam::123456789012:role/my-eks-role")
await set("AWS_PROFILE", "")
await set("AWS_ACCESS_KEY_ID", "")
set("AWS_WEB_IDENTITY_TOKEN_FILE", "/var/run/secrets/eks.amazonaws.com/serviceaccount/token")
set("AWS_ROLE_ARN", "arn:aws:iam::123456789012:role/my-eks-role")
set("AWS_PROFILE", "")
set("AWS_ACCESS_KEY_ID", "")
},
fn: async () => {
const providers = await list()
@@ -278,7 +280,7 @@ test("Bedrock: model with us. prefix should not be double-prefixed", async () =>
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -315,7 +317,7 @@ test("Bedrock: model with global. prefix should not be prefixed", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -351,7 +353,7 @@ test("Bedrock: model with eu. prefix should not be double-prefixed", async () =>
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()
@@ -387,7 +389,7 @@ test("Bedrock: model without prefix in US region should get us. prefix added", a
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("AWS_PROFILE", "default")
set("AWS_PROFILE", "default")
},
fn: async () => {
const providers = await list()

View File

@@ -13,8 +13,10 @@ import { Filesystem } from "../../src/util/filesystem"
import { Env } from "../../src/env"
import { Effect } from "effect"
import { AppRuntime } from "../../src/effect/app-runtime"
import { makeRuntime } from "../../src/effect/run-service"
const set = (k: string, v: string) => AppRuntime.runPromise(Env.Service.use((svc) => svc.set(k, v)))
const env = makeRuntime(Env.Service, Env.defaultLayer)
const set = (k: string, v: string) => env.runSync((svc) => svc.set(k, v))
async function run<A, E>(fn: (provider: Provider.Interface) => Effect.Effect<A, E, never>) {
return AppRuntime.runPromise(
@@ -73,7 +75,7 @@ test("provider loaded from env variable", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -128,7 +130,7 @@ test("disabled_providers excludes provider", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -152,8 +154,8 @@ test("enabled_providers restricts to only listed providers", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
await set("OPENAI_API_KEY", "test-openai-key")
set("ANTHROPIC_API_KEY", "test-api-key")
set("OPENAI_API_KEY", "test-openai-key")
},
fn: async () => {
const providers = await list()
@@ -182,7 +184,7 @@ test("model whitelist filters models for provider", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -213,7 +215,7 @@ test("model blacklist excludes specific models", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -248,7 +250,7 @@ test("custom model alias via config", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -324,7 +326,7 @@ test("env variable takes precedence, config merges options", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "env-api-key")
set("ANTHROPIC_API_KEY", "env-api-key")
},
fn: async () => {
const providers = await list()
@@ -350,7 +352,7 @@ test("getModel returns model for valid provider/model", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model = await getModel(ProviderID.anthropic, ModelID.make("claude-sonnet-4-20250514"))
@@ -377,7 +379,7 @@ test("getModel throws ModelNotFoundError for invalid model", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
expect(getModel(ProviderID.anthropic, ModelID.make("nonexistent-model"))).rejects.toThrow()
@@ -430,7 +432,7 @@ test("defaultModel returns first available model when no config set", async () =
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model = await defaultModel()
@@ -455,7 +457,7 @@ test("defaultModel respects config model setting", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model = await defaultModel()
@@ -570,7 +572,7 @@ test("model options are merged from existing model", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -599,7 +601,7 @@ test("provider removed when all models filtered out", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -622,7 +624,7 @@ test("closest finds model by partial match", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const result = await closest(ProviderID.anthropic, ["sonnet-4"])
@@ -677,7 +679,7 @@ test("getModel uses realIdByKey for aliased models", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -792,7 +794,7 @@ test("model inherits properties from existing database model", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -820,7 +822,7 @@ test("disabled_providers prevents loading even with env var", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("OPENAI_API_KEY", "test-openai-key")
set("OPENAI_API_KEY", "test-openai-key")
},
fn: async () => {
const providers = await list()
@@ -844,8 +846,8 @@ test("enabled_providers with empty array allows no providers", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
await set("OPENAI_API_KEY", "test-openai-key")
set("ANTHROPIC_API_KEY", "test-api-key")
set("OPENAI_API_KEY", "test-openai-key")
},
fn: async () => {
const providers = await list()
@@ -874,7 +876,7 @@ test("whitelist and blacklist can be combined", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -983,7 +985,7 @@ test("getSmallModel returns appropriate small model", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model = await getSmallModel(ProviderID.anthropic)
@@ -1008,7 +1010,7 @@ test("getSmallModel respects config small_model override", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model = await getSmallModel(ProviderID.anthropic)
@@ -1056,8 +1058,8 @@ test("multiple providers can be configured simultaneously", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-anthropic-key")
await set("OPENAI_API_KEY", "test-openai-key")
set("ANTHROPIC_API_KEY", "test-anthropic-key")
set("OPENAI_API_KEY", "test-openai-key")
},
fn: async () => {
const providers = await list()
@@ -1135,7 +1137,7 @@ test("model alias name defaults to alias key when id differs", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1175,7 +1177,7 @@ test("provider with multiple env var options only includes apiKey when single en
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("MULTI_ENV_KEY_1", "test-key")
set("MULTI_ENV_KEY_1", "test-key")
},
fn: async () => {
const providers = await list()
@@ -1217,7 +1219,7 @@ test("provider with single env var includes apiKey automatically", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("SINGLE_ENV_KEY", "my-api-key")
set("SINGLE_ENV_KEY", "my-api-key")
},
fn: async () => {
const providers = await list()
@@ -1254,7 +1256,7 @@ test("model cost overrides existing cost values", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1333,9 +1335,9 @@ test("disabled_providers and enabled_providers interaction", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-anthropic")
await set("OPENAI_API_KEY", "test-openai")
await set("GOOGLE_GENERATIVE_AI_API_KEY", "test-google")
set("ANTHROPIC_API_KEY", "test-anthropic")
set("OPENAI_API_KEY", "test-openai")
set("GOOGLE_GENERATIVE_AI_API_KEY", "test-google")
},
fn: async () => {
const providers = await list()
@@ -1492,7 +1494,7 @@ test("provider env fallback - second env var used if first missing", async () =>
directory: tmp.path,
init: async () => {
// Only set fallback, not primary
await set("FALLBACK_KEY", "fallback-api-key")
set("FALLBACK_KEY", "fallback-api-key")
},
fn: async () => {
const providers = await list()
@@ -1516,7 +1518,7 @@ test("getModel returns consistent results", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const model1 = await getModel(ProviderID.anthropic, ModelID.make("claude-sonnet-4-20250514"))
@@ -1577,7 +1579,7 @@ test("ModelNotFoundError includes suggestions for typos", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
try {
@@ -1605,7 +1607,7 @@ test("ModelNotFoundError for provider includes suggestions", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
try {
@@ -1653,7 +1655,7 @@ test("getProvider returns provider info", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const provider = await getProvider(ProviderID.anthropic)
@@ -1677,7 +1679,7 @@ test("closest returns undefined when no partial match found", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const result = await closest(ProviderID.anthropic, ["nonexistent-xyz-model"])
@@ -1700,7 +1702,7 @@ test("closest checks multiple query terms in order", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
// First term won't match, second will
@@ -1772,7 +1774,7 @@ test("provider options are deeply merged", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1810,7 +1812,7 @@ test("custom model inherits npm package from models.dev provider config", async
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("OPENAI_API_KEY", "test-api-key")
set("OPENAI_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1845,7 +1847,7 @@ test("custom model inherits api.url from models.dev provider", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("OPENROUTER_API_KEY", "test-api-key")
set("OPENROUTER_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1946,7 +1948,7 @@ test("model variants are generated for reasoning models", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -1984,7 +1986,7 @@ test("model variants can be disabled via config", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2027,7 +2029,7 @@ test("model variants can be customized via config", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2066,7 +2068,7 @@ test("disabled key is stripped from variant config", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2104,7 +2106,7 @@ test("all variants can be disabled via config", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2142,7 +2144,7 @@ test("variant config merges with generated variants", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-api-key")
set("ANTHROPIC_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2180,7 +2182,7 @@ test("variants filtered in second pass for database models", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("OPENAI_API_KEY", "test-api-key")
set("OPENAI_API_KEY", "test-api-key")
},
fn: async () => {
const providers = await list()
@@ -2284,7 +2286,7 @@ test("Google Vertex: retains baseURL for custom proxy", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("GOOGLE_APPLICATION_CREDENTIALS", "test-creds")
set("GOOGLE_APPLICATION_CREDENTIALS", "test-creds")
},
fn: async () => {
const providers = await list()
@@ -2329,7 +2331,7 @@ test("Google Vertex: supports OpenAI compatible models", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("GOOGLE_APPLICATION_CREDENTIALS", "test-creds")
set("GOOGLE_APPLICATION_CREDENTIALS", "test-creds")
},
fn: async () => {
const providers = await list()
@@ -2355,9 +2357,9 @@ test("cloudflare-ai-gateway loads with env variables", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("CLOUDFLARE_ACCOUNT_ID", "test-account")
await set("CLOUDFLARE_GATEWAY_ID", "test-gateway")
await set("CLOUDFLARE_API_TOKEN", "test-token")
set("CLOUDFLARE_ACCOUNT_ID", "test-account")
set("CLOUDFLARE_GATEWAY_ID", "test-gateway")
set("CLOUDFLARE_API_TOKEN", "test-token")
},
fn: async () => {
const providers = await list()
@@ -2387,9 +2389,9 @@ test("cloudflare-ai-gateway forwards config metadata options", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("CLOUDFLARE_ACCOUNT_ID", "test-account")
await set("CLOUDFLARE_GATEWAY_ID", "test-gateway")
await set("CLOUDFLARE_API_TOKEN", "test-token")
set("CLOUDFLARE_ACCOUNT_ID", "test-account")
set("CLOUDFLARE_GATEWAY_ID", "test-gateway")
set("CLOUDFLARE_API_TOKEN", "test-token")
},
fn: async () => {
const providers = await list()
@@ -2487,8 +2489,8 @@ test("plugin config enabled and disabled providers are honored", async () => {
await Instance.provide({
directory: tmp.path,
init: async () => {
await set("ANTHROPIC_API_KEY", "test-anthropic-key")
await set("OPENAI_API_KEY", "test-openai-key")
set("ANTHROPIC_API_KEY", "test-anthropic-key")
set("OPENAI_API_KEY", "test-openai-key")
},
fn: async () => {
const providers = await list()