github-copilot.ts 1.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344
  1. import { Effect } from "effect"
  2. import { ModelV2 } from "../../model"
  3. import { PluginV2 } from "../../plugin"
  4. import { ProviderV2 } from "../../provider"
  5. function shouldUseResponses(modelID: string) {
  6. // Copilot supports Responses for GPT-5 class models, except mini variants
  7. // which still need the chat-completions endpoint.
  8. const match = /^gpt-(\d+)/.exec(modelID)
  9. if (!match) return false
  10. return Number(match[1]) >= 5 && !modelID.startsWith("gpt-5-mini")
  11. }
  12. export const GithubCopilotPlugin = PluginV2.define({
  13. id: PluginV2.ID.make("github-copilot"),
  14. effect: Effect.gen(function* () {
  15. return {
  16. "provider.update": Effect.fn(function* (evt) {
  17. if (evt.provider.id !== ProviderV2.ID.githubCopilot) return
  18. }),
  19. "aisdk.sdk": Effect.fn(function* (evt) {
  20. if (evt.package !== "@ai-sdk/github-copilot") return
  21. const mod = yield* Effect.promise(() => import("../../github-copilot/copilot-provider"))
  22. evt.sdk = mod.createOpenaiCompatible(evt.options)
  23. }),
  24. "aisdk.language": Effect.fn(function* (evt) {
  25. if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return
  26. if (evt.sdk.responses === undefined && evt.sdk.chat === undefined) {
  27. evt.language = evt.sdk.languageModel(evt.model.apiID)
  28. return
  29. }
  30. evt.language = shouldUseResponses(evt.model.apiID)
  31. ? evt.sdk.responses(evt.model.apiID)
  32. : evt.sdk.chat(evt.model.apiID)
  33. }),
  34. "model.update": Effect.fn(function* (evt) {
  35. if (evt.model.providerID !== ProviderV2.ID.githubCopilot) return
  36. // This chat-only alias conflicts with the Copilot GPT-5 Responses route,
  37. // so hide it only for Copilot rather than for every provider catalog.
  38. if (evt.model.id === ModelV2.ID.make("gpt-5-chat-latest")) evt.cancel = true
  39. }),
  40. }
  41. }),
  42. })