Skip to content

Commit 847c408

Browse files
committed
refactor: migrate test inits from Promise to Effect; drop Promise variant
Converts ~60 Instance.provide({init: () => Promise}) call sites in amazon-bedrock and provider tests to Effect-typed inits via Effect.promise(...).pipe(Effect.asVoid). Tightens Instance.provide / Instance.load / Instance.reload signatures to only accept Effect.Effect<void> for init. liftLegacyInput still wraps the Effect with ALS bind via context.provide (through Effect.callback) so legacy code reachable through init that reads Instance.directory etc. continues to work. The wrap is now the single remaining bridge; once tests stop reading from ALS in init bodies, it can be deleted. Tests: bedrock + provider suites both pass. Pre-existing baseline failures in session.created.test.ts and project-init-git.test.ts are unrelated flakes (verified by running on dev's HEAD).
1 parent f33aec1 commit 847c408

3 files changed

Lines changed: 131 additions & 125 deletions

File tree

packages/opencode/src/project/instance.ts

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,29 @@ export type { LoadInput } from "./instance-store"
99

1010
type LegacyLoadInput = {
1111
directory: string
12-
init?: () => Promise<unknown>
12+
init?: Effect.Effect<void>
1313
project?: Project.Info
1414
worktree?: string
1515
}
1616

17-
// Promise-style legacy inits often read Instance.directory etc. from the ALS context.
18-
// The new Effect-typed init path doesn't bind ALS — it provides InstanceRef. To keep
19-
// legacy inits working without forcing every test to convert, bind ALS around the
20-
// Promise call here using the instance ctx that the store provides via InstanceRef.
17+
// Bind ALS around init so legacy code reachable through it (Instance.directory reads, etc.)
18+
// stays bound. The Effect-typed init also gets InstanceRef provided by the store.
2119
const liftLegacyInput = (input: LegacyLoadInput): InstanceStore.LoadInput => {
2220
const { init, ...rest } = input
2321
if (!init) return rest
2422
return {
2523
...rest,
2624
init: Effect.gen(function* () {
2725
const ctx = yield* InstanceRef
28-
yield* Effect.promise(() => (ctx ? context.provide(ctx, init) : init()))
26+
if (!ctx) return yield* init
27+
yield* Effect.callback<void>((resume) => {
28+
context.provide(ctx, () => {
29+
Effect.runPromise(init).then(
30+
() => resume(Effect.void),
31+
(err) => resume(Effect.die(err)),
32+
)
33+
})
34+
})
2935
}),
3036
}
3137
}
@@ -34,7 +40,7 @@ export const Instance = {
3440
load(input: LegacyLoadInput): Promise<InstanceContext> {
3541
return InstanceStore.runtime.runPromise((store) => store.load(liftLegacyInput(input)))
3642
},
37-
async provide<R>(input: { directory: string; init?: () => Promise<unknown>; fn: () => R }): Promise<R> {
43+
async provide<R>(input: { directory: string; init?: Effect.Effect<void>; fn: () => R }): Promise<R> {
3844
return context.provide(
3945
await Instance.load({ directory: input.directory, init: input.init }),
4046
async () => input.fn(),

packages/opencode/test/provider/amazon-bedrock.test.ts

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -45,10 +45,10 @@ test("Bedrock: config region takes precedence over AWS_REGION env var", async ()
4545
})
4646
await Instance.provide({
4747
directory: tmp.path,
48-
init: async () => {
48+
init: Effect.promise(async () => {
4949
set("AWS_REGION", "us-east-1")
5050
set("AWS_PROFILE", "default")
51-
},
51+
}).pipe(Effect.asVoid),
5252
fn: async () => {
5353
const providers = await list()
5454
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -70,10 +70,10 @@ test("Bedrock: falls back to AWS_REGION env var when no config region", async ()
7070
})
7171
await Instance.provide({
7272
directory: tmp.path,
73-
init: async () => {
73+
init: Effect.promise(async () => {
7474
set("AWS_REGION", "eu-west-1")
7575
set("AWS_PROFILE", "default")
76-
},
76+
}).pipe(Effect.asVoid),
7777
fn: async () => {
7878
const providers = await list()
7979
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -125,11 +125,11 @@ test("Bedrock: loads when bearer token from auth.json is present", async () => {
125125

126126
await Instance.provide({
127127
directory: tmp.path,
128-
init: async () => {
128+
init: Effect.promise(async () => {
129129
set("AWS_PROFILE", "")
130130
set("AWS_ACCESS_KEY_ID", "")
131131
set("AWS_BEARER_TOKEN_BEDROCK", "")
132-
},
132+
}).pipe(Effect.asVoid),
133133
fn: async () => {
134134
const providers = await list()
135135
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -171,10 +171,10 @@ test("Bedrock: config profile takes precedence over AWS_PROFILE env var", async
171171
})
172172
await Instance.provide({
173173
directory: tmp.path,
174-
init: async () => {
174+
init: Effect.promise(async () => {
175175
set("AWS_PROFILE", "default")
176176
set("AWS_ACCESS_KEY_ID", "test-key-id")
177-
},
177+
}).pipe(Effect.asVoid),
178178
fn: async () => {
179179
const providers = await list()
180180
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -203,9 +203,9 @@ test("Bedrock: includes custom endpoint in options when specified", async () =>
203203
})
204204
await Instance.provide({
205205
directory: tmp.path,
206-
init: async () => {
206+
init: Effect.promise(async () => {
207207
set("AWS_PROFILE", "default")
208-
},
208+
}).pipe(Effect.asVoid),
209209
fn: async () => {
210210
const providers = await list()
211211
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -236,12 +236,12 @@ test("Bedrock: autoloads when AWS_WEB_IDENTITY_TOKEN_FILE is present", async ()
236236
})
237237
await Instance.provide({
238238
directory: tmp.path,
239-
init: async () => {
239+
init: Effect.promise(async () => {
240240
set("AWS_WEB_IDENTITY_TOKEN_FILE", "/var/run/secrets/eks.amazonaws.com/serviceaccount/token")
241241
set("AWS_ROLE_ARN", "arn:aws:iam::123456789012:role/my-eks-role")
242242
set("AWS_PROFILE", "")
243243
set("AWS_ACCESS_KEY_ID", "")
244-
},
244+
}).pipe(Effect.asVoid),
245245
fn: async () => {
246246
const providers = await list()
247247
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -279,9 +279,9 @@ test("Bedrock: model with us. prefix should not be double-prefixed", async () =>
279279
})
280280
await Instance.provide({
281281
directory: tmp.path,
282-
init: async () => {
282+
init: Effect.promise(async () => {
283283
set("AWS_PROFILE", "default")
284-
},
284+
}).pipe(Effect.asVoid),
285285
fn: async () => {
286286
const providers = await list()
287287
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -316,9 +316,9 @@ test("Bedrock: model with global. prefix should not be prefixed", async () => {
316316
})
317317
await Instance.provide({
318318
directory: tmp.path,
319-
init: async () => {
319+
init: Effect.promise(async () => {
320320
set("AWS_PROFILE", "default")
321-
},
321+
}).pipe(Effect.asVoid),
322322
fn: async () => {
323323
const providers = await list()
324324
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -352,9 +352,9 @@ test("Bedrock: model with eu. prefix should not be double-prefixed", async () =>
352352
})
353353
await Instance.provide({
354354
directory: tmp.path,
355-
init: async () => {
355+
init: Effect.promise(async () => {
356356
set("AWS_PROFILE", "default")
357-
},
357+
}).pipe(Effect.asVoid),
358358
fn: async () => {
359359
const providers = await list()
360360
expect(providers[ProviderID.amazonBedrock]).toBeDefined()
@@ -388,9 +388,9 @@ test("Bedrock: model without prefix in US region should get us. prefix added", a
388388
})
389389
await Instance.provide({
390390
directory: tmp.path,
391-
init: async () => {
391+
init: Effect.promise(async () => {
392392
set("AWS_PROFILE", "default")
393-
},
393+
}).pipe(Effect.asVoid),
394394
fn: async () => {
395395
const providers = await list()
396396
expect(providers[ProviderID.amazonBedrock]).toBeDefined()

0 commit comments

Comments
 (0)