gitlab-duo.test.ts 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414
  1. export {}
  2. // TODO: UNCOMMENT WHEN GITLAB SUPPORT IS COMPLETED
  3. //
  4. //
  5. //
  6. // import { test, expect, describe } from "bun:test"
  7. // import path from "path"
  8. // import { ProviderID, ModelID } from "../../src/provider/schema"
  9. // import { tmpdir } from "../fixture/fixture"
  10. // import { Instance } from "../../src/project/instance"
  11. import { WithInstance } from "../../src/project/with-instance"
  12. // import { Provider } from "@/provider/provider"
  13. // import { Env } from "../../src/env"
  14. // import { Global } from "@opencode-ai/core/global"
  15. // import { GitLabWorkflowLanguageModel } from "gitlab-ai-provider"
  16. // test("GitLab Duo: loads provider with API key from environment", async () => {
  17. // await using tmp = await tmpdir({
  18. // init: async (dir) => {
  19. // await Bun.write(
  20. // path.join(dir, "opencode.json"),
  21. // JSON.stringify({
  22. // $schema: "https://opencode.ai/config.json",
  23. // }),
  24. // )
  25. // },
  26. // })
  27. // await WithInstance.provide({
  28. // directory: tmp.path,
  29. // init: async () => {
  30. // Env.set("GITLAB_TOKEN", "test-gitlab-token")
  31. // },
  32. // fn: async () => {
  33. // const providers = await list()
  34. // expect(providers[ProviderID.gitlab]).toBeDefined()
  35. // expect(providers[ProviderID.gitlab].key).toBe("test-gitlab-token")
  36. // },
  37. // })
  38. // })
  39. // test("GitLab Duo: config instanceUrl option sets baseURL", async () => {
  40. // await using tmp = await tmpdir({
  41. // init: async (dir) => {
  42. // await Bun.write(
  43. // path.join(dir, "opencode.json"),
  44. // JSON.stringify({
  45. // $schema: "https://opencode.ai/config.json",
  46. // provider: {
  47. // gitlab: {
  48. // options: {
  49. // instanceUrl: "https://gitlab.example.com",
  50. // },
  51. // },
  52. // },
  53. // }),
  54. // )
  55. // },
  56. // })
  57. // await WithInstance.provide({
  58. // directory: tmp.path,
  59. // init: async () => {
  60. // Env.set("GITLAB_TOKEN", "test-token")
  61. // Env.set("GITLAB_INSTANCE_URL", "https://gitlab.example.com")
  62. // },
  63. // fn: async () => {
  64. // const providers = await list()
  65. // expect(providers[ProviderID.gitlab]).toBeDefined()
  66. // expect(providers[ProviderID.gitlab].options?.instanceUrl).toBe("https://gitlab.example.com")
  67. // },
  68. // })
  69. // })
  70. // test("GitLab Duo: loads with OAuth token from auth.json", async () => {
  71. // await using tmp = await tmpdir({
  72. // init: async (dir) => {
  73. // await Bun.write(
  74. // path.join(dir, "opencode.json"),
  75. // JSON.stringify({
  76. // $schema: "https://opencode.ai/config.json",
  77. // }),
  78. // )
  79. // },
  80. // })
  81. // const authPath = path.join(Global.Path.data, "auth.json")
  82. // await Bun.write(
  83. // authPath,
  84. // JSON.stringify({
  85. // gitlab: {
  86. // type: "oauth",
  87. // access: "test-access-token",
  88. // refresh: "test-refresh-token",
  89. // expires: Date.now() + 3600000,
  90. // },
  91. // }),
  92. // )
  93. // await WithInstance.provide({
  94. // directory: tmp.path,
  95. // init: async () => {
  96. // Env.set("GITLAB_TOKEN", "")
  97. // },
  98. // fn: async () => {
  99. // const providers = await list()
  100. // expect(providers[ProviderID.gitlab]).toBeDefined()
  101. // },
  102. // })
  103. // })
  104. // test("GitLab Duo: loads with Personal Access Token from auth.json", async () => {
  105. // await using tmp = await tmpdir({
  106. // init: async (dir) => {
  107. // await Bun.write(
  108. // path.join(dir, "opencode.json"),
  109. // JSON.stringify({
  110. // $schema: "https://opencode.ai/config.json",
  111. // }),
  112. // )
  113. // },
  114. // })
  115. // const authPath2 = path.join(Global.Path.data, "auth.json")
  116. // await Bun.write(
  117. // authPath2,
  118. // JSON.stringify({
  119. // gitlab: {
  120. // type: "api",
  121. // key: "glpat-test-pat-token",
  122. // },
  123. // }),
  124. // )
  125. // await WithInstance.provide({
  126. // directory: tmp.path,
  127. // init: async () => {
  128. // Env.set("GITLAB_TOKEN", "")
  129. // },
  130. // fn: async () => {
  131. // const providers = await list()
  132. // expect(providers[ProviderID.gitlab]).toBeDefined()
  133. // expect(providers[ProviderID.gitlab].key).toBe("glpat-test-pat-token")
  134. // },
  135. // })
  136. // })
  137. // test("GitLab Duo: supports self-hosted instance configuration", async () => {
  138. // await using tmp = await tmpdir({
  139. // init: async (dir) => {
  140. // await Bun.write(
  141. // path.join(dir, "opencode.json"),
  142. // JSON.stringify({
  143. // $schema: "https://opencode.ai/config.json",
  144. // provider: {
  145. // gitlab: {
  146. // options: {
  147. // instanceUrl: "https://gitlab.company.internal",
  148. // apiKey: "glpat-internal-token",
  149. // },
  150. // },
  151. // },
  152. // }),
  153. // )
  154. // },
  155. // })
  156. // await WithInstance.provide({
  157. // directory: tmp.path,
  158. // init: async () => {
  159. // Env.set("GITLAB_INSTANCE_URL", "https://gitlab.company.internal")
  160. // },
  161. // fn: async () => {
  162. // const providers = await list()
  163. // expect(providers[ProviderID.gitlab]).toBeDefined()
  164. // expect(providers[ProviderID.gitlab].options?.instanceUrl).toBe("https://gitlab.company.internal")
  165. // },
  166. // })
  167. // })
  168. // test("GitLab Duo: config apiKey takes precedence over environment variable", async () => {
  169. // await using tmp = await tmpdir({
  170. // init: async (dir) => {
  171. // await Bun.write(
  172. // path.join(dir, "opencode.json"),
  173. // JSON.stringify({
  174. // $schema: "https://opencode.ai/config.json",
  175. // provider: {
  176. // gitlab: {
  177. // options: {
  178. // apiKey: "config-token",
  179. // },
  180. // },
  181. // },
  182. // }),
  183. // )
  184. // },
  185. // })
  186. // await WithInstance.provide({
  187. // directory: tmp.path,
  188. // init: async () => {
  189. // Env.set("GITLAB_TOKEN", "env-token")
  190. // },
  191. // fn: async () => {
  192. // const providers = await list()
  193. // expect(providers[ProviderID.gitlab]).toBeDefined()
  194. // },
  195. // })
  196. // })
  197. // test("GitLab Duo: includes context-1m beta header in aiGatewayHeaders", async () => {
  198. // await using tmp = await tmpdir({
  199. // init: async (dir) => {
  200. // await Bun.write(
  201. // path.join(dir, "opencode.json"),
  202. // JSON.stringify({
  203. // $schema: "https://opencode.ai/config.json",
  204. // }),
  205. // )
  206. // },
  207. // })
  208. // await WithInstance.provide({
  209. // directory: tmp.path,
  210. // init: async () => {
  211. // Env.set("GITLAB_TOKEN", "test-token")
  212. // },
  213. // fn: async () => {
  214. // const providers = await list()
  215. // expect(providers[ProviderID.gitlab]).toBeDefined()
  216. // expect(providers[ProviderID.gitlab].options?.aiGatewayHeaders?.["anthropic-beta"]).toContain(
  217. // "context-1m-2025-08-07",
  218. // )
  219. // },
  220. // })
  221. // })
  222. // test("GitLab Duo: supports feature flags configuration", async () => {
  223. // await using tmp = await tmpdir({
  224. // init: async (dir) => {
  225. // await Bun.write(
  226. // path.join(dir, "opencode.json"),
  227. // JSON.stringify({
  228. // $schema: "https://opencode.ai/config.json",
  229. // provider: {
  230. // gitlab: {
  231. // options: {
  232. // featureFlags: {
  233. // duo_agent_platform_agentic_chat: true,
  234. // duo_agent_platform: true,
  235. // },
  236. // },
  237. // },
  238. // },
  239. // }),
  240. // )
  241. // },
  242. // })
  243. // await WithInstance.provide({
  244. // directory: tmp.path,
  245. // init: async () => {
  246. // Env.set("GITLAB_TOKEN", "test-token")
  247. // },
  248. // fn: async () => {
  249. // const providers = await list()
  250. // expect(providers[ProviderID.gitlab]).toBeDefined()
  251. // expect(providers[ProviderID.gitlab].options?.featureFlags).toBeDefined()
  252. // expect(providers[ProviderID.gitlab].options?.featureFlags?.duo_agent_platform_agentic_chat).toBe(true)
  253. // },
  254. // })
  255. // })
  256. // test("GitLab Duo: has multiple agentic chat models available", async () => {
  257. // await using tmp = await tmpdir({
  258. // init: async (dir) => {
  259. // await Bun.write(
  260. // path.join(dir, "opencode.json"),
  261. // JSON.stringify({
  262. // $schema: "https://opencode.ai/config.json",
  263. // }),
  264. // )
  265. // },
  266. // })
  267. // await WithInstance.provide({
  268. // directory: tmp.path,
  269. // init: async () => {
  270. // Env.set("GITLAB_TOKEN", "test-token")
  271. // },
  272. // fn: async () => {
  273. // const providers = await list()
  274. // expect(providers[ProviderID.gitlab]).toBeDefined()
  275. // const models = Object.keys(providers[ProviderID.gitlab].models)
  276. // expect(models.length).toBeGreaterThan(0)
  277. // expect(models).toContain("duo-chat-haiku-4-5")
  278. // expect(models).toContain("duo-chat-sonnet-4-5")
  279. // expect(models).toContain("duo-chat-opus-4-5")
  280. // },
  281. // })
  282. // })
  283. // describe("GitLab Duo: workflow model routing", () => {
  284. // test("duo-workflow-* model routes through workflowChat", async () => {
  285. // await using tmp = await tmpdir({
  286. // init: async (dir) => {
  287. // await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" }))
  288. // },
  289. // })
  290. // await WithInstance.provide({
  291. // directory: tmp.path,
  292. // init: async () => {
  293. // Env.set("GITLAB_TOKEN", "test-token")
  294. // },
  295. // fn: async () => {
  296. // const providers = await list()
  297. // const gitlab = providers[ProviderID.gitlab]
  298. // expect(gitlab).toBeDefined()
  299. // gitlab.models["duo-workflow-sonnet-4-6"] = {
  300. // id: ModelID.make("duo-workflow-sonnet-4-6"),
  301. // providerID: ProviderID.make("gitlab"),
  302. // name: "Agent Platform (Claude Sonnet 4.6)",
  303. // family: "",
  304. // api: { id: "duo-workflow-sonnet-4-6", url: "https://gitlab.com", npm: "gitlab-ai-provider" },
  305. // status: "active",
  306. // headers: {},
  307. // options: { workflowRef: "claude_sonnet_4_6" },
  308. // cost: { input: 0, output: 0, cache: { read: 0, write: 0 } },
  309. // limit: { context: 200000, output: 64000 },
  310. // capabilities: {
  311. // temperature: false,
  312. // reasoning: true,
  313. // attachment: true,
  314. // toolcall: true,
  315. // input: { text: true, audio: false, image: true, video: false, pdf: true },
  316. // output: { text: true, audio: false, image: false, video: false, pdf: false },
  317. // interleaved: false,
  318. // },
  319. // release_date: "",
  320. // variants: {},
  321. // }
  322. // const model = await getModel(ProviderID.gitlab, ModelID.make("duo-workflow-sonnet-4-6"))
  323. // expect(model).toBeDefined()
  324. // expect(model.options?.workflowRef).toBe("claude_sonnet_4_6")
  325. // const language = await getLanguage(model)
  326. // expect(language).toBeDefined()
  327. // expect(language).toBeInstanceOf(GitLabWorkflowLanguageModel)
  328. // },
  329. // })
  330. // })
  331. // test("duo-chat-* model routes through agenticChat (not workflow)", async () => {
  332. // await using tmp = await tmpdir({
  333. // init: async (dir) => {
  334. // await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" }))
  335. // },
  336. // })
  337. // await WithInstance.provide({
  338. // directory: tmp.path,
  339. // init: async () => {
  340. // Env.set("GITLAB_TOKEN", "test-token")
  341. // },
  342. // fn: async () => {
  343. // const providers = await list()
  344. // expect(providers[ProviderID.gitlab]).toBeDefined()
  345. // const model = await getModel(ProviderID.gitlab, ModelID.make("duo-chat-sonnet-4-5"))
  346. // expect(model).toBeDefined()
  347. // const language = await getLanguage(model)
  348. // expect(language).toBeDefined()
  349. // expect(language).not.toBeInstanceOf(GitLabWorkflowLanguageModel)
  350. // },
  351. // })
  352. // })
  353. // test("model.options merged with provider.options in getLanguage", async () => {
  354. // await using tmp = await tmpdir({
  355. // init: async (dir) => {
  356. // await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" }))
  357. // },
  358. // })
  359. // await WithInstance.provide({
  360. // directory: tmp.path,
  361. // init: async () => {
  362. // Env.set("GITLAB_TOKEN", "test-token")
  363. // },
  364. // fn: async () => {
  365. // const providers = await list()
  366. // const gitlab = providers[ProviderID.gitlab]
  367. // expect(gitlab.options?.featureFlags).toBeDefined()
  368. // const model = await getModel(ProviderID.gitlab, ModelID.make("duo-chat-sonnet-4-5"))
  369. // expect(model).toBeDefined()
  370. // expect(model.options).toBeDefined()
  371. // },
  372. // })
  373. // })
  374. // })
  375. // describe("GitLab Duo: static models", () => {
  376. // test("static duo-chat models always present regardless of discovery", async () => {
  377. // await using tmp = await tmpdir({
  378. // init: async (dir) => {
  379. // await Bun.write(path.join(dir, "opencode.json"), JSON.stringify({ $schema: "https://opencode.ai/config.json" }))
  380. // },
  381. // })
  382. // await WithInstance.provide({
  383. // directory: tmp.path,
  384. // init: async () => {
  385. // Env.set("GITLAB_TOKEN", "test-token")
  386. // },
  387. // fn: async () => {
  388. // const providers = await list()
  389. // const models = Object.keys(providers[ProviderID.gitlab].models)
  390. // expect(models).toContain("duo-chat-haiku-4-5")
  391. // expect(models).toContain("duo-chat-sonnet-4-5")
  392. // expect(models).toContain("duo-chat-opus-4-5")
  393. // },
  394. // })
  395. // })
  396. // })