1import * as AWS from "@/AWS";
2import { CodeInterpreter } from "@/AWS/BedrockAgentCore";
3import * as Test from "@/Test/Alchemy";
4import * as control from "@distilled.cloud/aws/bedrock-agentcore-control";
5import { expect } from "alchemy-test";
6import * as Effect from "effect/Effect";
7import * as Schedule from "effect/Schedule";
8
9const { test } = Test.make({ providers: AWS.providers() });
10
11// Ungated typed-error probe: prove the distilled error union carries the
12// not-found tag this provider's read/delete paths depend on.
13test.provider(
14 "getCodeInterpreter on a nonexistent id fails with ResourceNotFoundException",
15 () =>
16 Effect.gen(function* () {
17 const error = yield* Effect.flip(
18 control.getCodeInterpreter({
19 codeInterpreterId: "alchemy_nonexistent_probe-0000000000",
20 }),
21 );
22 expect(error._tag).toBe("ResourceNotFoundException");
23 }),
24 { tags: ["provider:aws", "provider:aws:bedrockagentcore", "live"] },
25);
26
27const assertInterpreterGone = (codeInterpreterId: string) =>
28 Effect.gen(function* () {
29 const status = yield* control
30 .getCodeInterpreter({ codeInterpreterId })
31 .pipe(
32 Effect.map((r) => r.status as string),
33 Effect.catchTag("ResourceNotFoundException", () =>
34 Effect.succeed("DELETED" as string),
35 ),
36 );
37 if (status !== "DELETED") {
38 return yield* Effect.fail(
39 new Error(`interpreter still live (status: ${status})`),
40 );
41 }
42 }).pipe(
43 Effect.retry({
44 schedule: Schedule.max([
45 Schedule.fixed("3 seconds"),
46 Schedule.recurs(10),
47 ]),
48 }),
49 );
50
51test.provider(
52 "create sandbox interpreter, verify, replace on network change, destroy",
53 (stack) =>
54 Effect.gen(function* () {
55 yield* stack.destroy();
56
57 // create (SANDBOX default)
58 const { interpreter } = yield* stack.deploy(
59 Effect.gen(function* () {
60 const interpreter = yield* CodeInterpreter("Sandbox", {
61 tags: { fixture: "agentcore-code-interpreter" },
62 });
63 return { interpreter };
64 }),
65 );
66
67 expect(interpreter.codeInterpreterId).toBeTruthy();
68 expect(interpreter.codeInterpreterArn).toContain(":code-interpreter");
69 expect(interpreter.status).toBe("READY");
70
71 // out-of-band verification via distilled
72 const observed = yield* control.getCodeInterpreter({
73 codeInterpreterId: interpreter.codeInterpreterId,
74 });
75 expect(observed.status).toBe("READY");
76 expect(observed.networkConfiguration.networkMode).toBe("SANDBOX");
77
78 // network mode is create-only — changing it must replace
79 const { interpreter: replaced } = yield* stack.deploy(
80 Effect.gen(function* () {
81 const interpreter = yield* CodeInterpreter("Sandbox", {
82 networkConfiguration: { networkMode: "PUBLIC" },
83 tags: { fixture: "agentcore-code-interpreter" },
84 });
85 return { interpreter };
86 }),
87 );
88 expect(replaced.codeInterpreterId).not.toBe(
89 interpreter.codeInterpreterId,
90 );
91 const observedReplaced = yield* control.getCodeInterpreter({
92 codeInterpreterId: replaced.codeInterpreterId,
93 });
94 expect(observedReplaced.networkConfiguration.networkMode).toBe("PUBLIC");
95
96 yield* stack.destroy();
97 yield* assertInterpreterGone(replaced.codeInterpreterId);
98 }),
99 {
100 tags: ["provider:aws", "provider:aws:bedrockagentcore", "live"],
101 timeout: 180_000,
102 },
103);