11import { dirname , resolve } from "node:path" ;
22import { fileURLToPath } from "node:url" ;
3- import { expect , it , vi } from "vitest" ;
3+ import { beforeEach , expect , it , vi } from "vitest" ;
44
55const mocks = vi . hoisted ( ( ) => {
66 const approveAll = vi . fn ( ) ;
@@ -13,17 +13,75 @@ const mocks = vi.hoisted(() => {
1313 copilotClientCtor ( options ) ;
1414 return { createSession, stop : stopClient } ;
1515 } ;
16- return { approveAll, createSession, stopClient, copilotClientCtor, defaultForUri, forUri, CopilotClient } ;
16+
17+ const anthropicConstructor = vi . fn ( ) ;
18+ const anthropicToolRunner = vi . fn ( ( ) => ( {
19+ async runUntilDone ( ) {
20+ return { content : [ { type : "text" , text : JSON . stringify ( "anthropic-mounted" ) } ] } ;
21+ } ,
22+ params : { messages : [ ] } ,
23+ } ) ) ;
24+ const Anthropic = function ( this : unknown , options : unknown ) {
25+ anthropicConstructor ( options ) ;
26+ return { beta : { messages : { toolRunner : anthropicToolRunner } } } ;
27+ } ;
28+ const betaTool = vi . fn ( ( tool ) => tool ) ;
29+
30+ const codexConstructor = vi . fn ( ) ;
31+ const codexRun = vi . fn ( async ( ) => ( { finalResponse : JSON . stringify ( "codex-mounted" ) } ) ) ;
32+ const codexStartThread = vi . fn ( ( ) => ( { run : codexRun } ) ) ;
33+ const Codex = function ( this : unknown , options : unknown ) {
34+ codexConstructor ( options ) ;
35+ return { startThread : codexStartThread } ;
36+ } ;
37+
38+ return {
39+ approveAll,
40+ createSession,
41+ stopClient,
42+ copilotClientCtor,
43+ defaultForUri,
44+ forUri,
45+ CopilotClient,
46+ anthropicConstructor,
47+ anthropicToolRunner,
48+ Anthropic,
49+ betaTool,
50+ codexConstructor,
51+ codexRun,
52+ codexStartThread,
53+ Codex,
54+ } ;
1755} ) ;
1856
1957vi . mock ( "@github/copilot-sdk" , ( ) => ( {
2058 approveAll : mocks . approveAll ,
2159 CopilotClient : mocks . CopilotClient ,
2260 RuntimeConnection : { forUri : mocks . forUri , forStdio : vi . fn ( ) } ,
2361} ) ) ;
62+ vi . mock ( "@anthropic-ai/sdk" , ( ) => ( { default : mocks . Anthropic } ) ) ;
63+ vi . mock ( "@anthropic-ai/sdk/helpers/beta/json-schema" , ( ) => ( { betaTool : mocks . betaTool } ) ) ;
64+ vi . mock ( "@openai/codex-sdk" , ( ) => ( { Codex : mocks . Codex } ) ) ;
2465
2566import { agent , launchRigProgram , s } from "rig" ;
2667
68+ beforeEach ( ( ) => {
69+ mocks . copilotClientCtor . mockClear ( ) ;
70+ mocks . createSession . mockReset ( ) ;
71+ mocks . anthropicConstructor . mockClear ( ) ;
72+ mocks . anthropicToolRunner . mockClear ( ) ;
73+ mocks . betaTool . mockClear ( ) ;
74+ mocks . codexConstructor . mockClear ( ) ;
75+ mocks . codexRun . mockClear ( ) ;
76+ mocks . codexStartThread . mockClear ( ) ;
77+ delete process . env [ "COPILOT_SDK_URI" ] ;
78+ delete process . env [ "RIG_ENGINE" ] ;
79+ delete process . env [ "ANTHROPIC_API_KEY" ] ;
80+ delete process . env [ "OPENAI_API_KEY" ] ;
81+ delete process . env [ "GEMINI_API_KEY" ] ;
82+ delete process . env [ "GOOGLE_API_KEY" ] ;
83+ } ) ;
84+
2785it ( "uses the launcher cwd when mounting the default copilot engine" , async ( ) => {
2886 const sendAndWait = vi . fn ( ) . mockResolvedValue ( JSON . stringify ( "default-mounted" ) ) ;
2987 mocks . createSession . mockResolvedValue ( { sendAndWait } ) ;
@@ -70,3 +128,63 @@ it("uses COPILOT_SDK_URI when mounting the default copilot engine", async () =>
70128 mocks . forUri . mockImplementation ( mocks . defaultForUri ) ;
71129 }
72130} ) ;
131+
132+ it ( "prefers COPILOT_SDK_URI over RIG_ENGINE when mounting the default engine" , async ( ) => {
133+ const sendAndWait = vi . fn ( ) . mockResolvedValue ( JSON . stringify ( "copilot-preferred" ) ) ;
134+ mocks . createSession . mockResolvedValue ( { sendAndWait } ) ;
135+ process . env [ "COPILOT_SDK_URI" ] = "http://127.0.0.1:4242" ;
136+ process . env [ "RIG_ENGINE" ] = "anthropic" ;
137+ process . env [ "ANTHROPIC_API_KEY" ] = "test-key" ;
138+ mocks . forUri . mockImplementation ( ( ( url : string ) => ( { kind : "uri" , url } ) ) as any ) ;
139+
140+ const fixturePath = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , "./launcher.fixture.ts" ) ;
141+
142+ try {
143+ await launchRigProgram ( fixturePath ) ;
144+
145+ const call = agent ( {
146+ name : "launcher-default-engine-copilot-preferred-test" ,
147+ input : s . object ( { } ) ,
148+ } ) ;
149+ const result = await call ( { } ) ;
150+ expect ( result ) . toBe ( "copilot-preferred" ) ;
151+ expect ( mocks . forUri ) . toHaveBeenCalledWith ( "http://127.0.0.1:4242" ) ;
152+ expect ( mocks . copilotClientCtor ) . toHaveBeenCalled ( ) ;
153+ expect ( mocks . anthropicConstructor ) . not . toHaveBeenCalled ( ) ;
154+ } finally {
155+ mocks . forUri . mockImplementation ( mocks . defaultForUri ) ;
156+ }
157+ } ) ;
158+
159+ it ( "automatically mounts anthropicEngine when ANTHROPIC_API_KEY is set" , async ( ) => {
160+ process . env [ "ANTHROPIC_API_KEY" ] = "test-key" ;
161+ const fixturePath = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , "./launcher.fixture.ts" ) ;
162+
163+ await launchRigProgram ( fixturePath ) ;
164+
165+ const call = agent ( {
166+ name : "launcher-default-engine-anthropic-test" ,
167+ input : s . object ( { } ) ,
168+ } ) ;
169+ const result = await call ( { } ) ;
170+ expect ( result ) . toBe ( "anthropic-mounted" ) ;
171+ expect ( mocks . anthropicConstructor ) . toHaveBeenCalledWith ( { } ) ;
172+ expect ( mocks . copilotClientCtor ) . not . toHaveBeenCalled ( ) ;
173+ } ) ;
174+
175+ it ( "automatically mounts codexEngine when OPENAI_API_KEY is set" , async ( ) => {
176+ process . env [ "OPENAI_API_KEY" ] = "test-key" ;
177+ const fixturePath = resolve ( dirname ( fileURLToPath ( import . meta. url ) ) , "./launcher.fixture.ts" ) ;
178+
179+ await launchRigProgram ( fixturePath ) ;
180+
181+ const call = agent ( {
182+ name : "launcher-default-engine-codex-test" ,
183+ input : s . object ( { } ) ,
184+ } ) ;
185+ const result = await call ( { } ) ;
186+ expect ( result ) . toBe ( "codex-mounted" ) ;
187+ expect ( mocks . codexConstructor ) . toHaveBeenCalledWith ( { } ) ;
188+ expect ( mocks . codexStartThread ) . toHaveBeenCalledWith ( expect . objectContaining ( { model : "small" } ) ) ;
189+ expect ( mocks . copilotClientCtor ) . not . toHaveBeenCalled ( ) ;
190+ } ) ;
0 commit comments