gitlab-duo.test.ts 13 KB

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