models-dev.ts 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. import { DateTime, Effect, Scope, Stream } from "effect"
  2. import { Catalog } from "../catalog"
  3. import { Integration } from "../integration"
  4. import { EventV2 } from "../event"
  5. import { ModelV2 } from "../model"
  6. import { ModelRequest } from "../model-request"
  7. import { ModelsDev } from "../models-dev"
  8. import { PluginV2 } from "../plugin"
  9. import { ProviderV2 } from "../provider"
  10. function released(date: string) {
  11. const time = Date.parse(date)
  12. return DateTime.makeUnsafe(Number.isFinite(time) ? time : 0)
  13. }
  14. function cost(input: ModelsDev.Model["cost"]) {
  15. const base = {
  16. input: input?.input ?? 0,
  17. output: input?.output ?? 0,
  18. cache: {
  19. read: input?.cache_read ?? 0,
  20. write: input?.cache_write ?? 0,
  21. },
  22. }
  23. if (!input?.context_over_200k) return [base]
  24. return [
  25. base,
  26. {
  27. tier: {
  28. type: "context" as const,
  29. size: 200_000,
  30. },
  31. input: input.context_over_200k.input,
  32. output: input.context_over_200k.output,
  33. cache: {
  34. read: input.context_over_200k.cache_read ?? 0,
  35. write: input.context_over_200k.cache_write ?? 0,
  36. },
  37. },
  38. ]
  39. }
  40. function variants(model: ModelsDev.Model, packageName?: string) {
  41. return Object.entries(model.experimental?.modes ?? {}).map(([id, item]) => {
  42. const request = ModelRequest.normalizeAiSdkOptions(packageName, item.provider?.body ?? {})
  43. return {
  44. id: ModelV2.VariantID.make(id),
  45. headers: { ...(item.provider?.headers ?? {}) },
  46. ...request,
  47. }
  48. })
  49. }
  50. export const ModelsDevPlugin = PluginV2.define({
  51. id: PluginV2.ID.make("models-dev"),
  52. effect: Effect.gen(function* () {
  53. const catalog = yield* Catalog.Service
  54. const integrations = yield* Integration.Service
  55. const modelsDev = yield* ModelsDev.Service
  56. const events = yield* EventV2.Service
  57. const scope = yield* Scope.Scope
  58. const transform = yield* catalog.transform()
  59. const integrationTransform = yield* integrations.transform()
  60. const refresh = Effect.fn("ModelsDevPlugin.refresh")(function* () {
  61. const data = yield* modelsDev.get()
  62. yield* integrationTransform((integrations) => {
  63. for (const item of Object.values(data)) {
  64. if (item.env.length === 0) continue
  65. const integrationID = Integration.ID.make(item.id)
  66. integrations.update(integrationID, (integration) => (integration.name = item.name))
  67. integrations.method.update({
  68. integrationID,
  69. method: { type: "key" },
  70. })
  71. integrations.method.update({
  72. integrationID,
  73. method: { type: "env", names: [...item.env] },
  74. })
  75. }
  76. })
  77. yield* transform((catalog) => {
  78. for (const item of Object.values(data)) {
  79. const providerID = ProviderV2.ID.make(item.id)
  80. catalog.provider.update(providerID, (provider) => {
  81. provider.name = item.name
  82. provider.api = item.npm
  83. ? {
  84. type: "aisdk",
  85. package: item.npm,
  86. url: item.api,
  87. }
  88. : {
  89. type: "native",
  90. url: item.api,
  91. settings: {},
  92. }
  93. })
  94. for (const model of Object.values(item.models)) {
  95. const modelID = ModelV2.ID.make(model.id)
  96. catalog.model.update(providerID, modelID, (draft) => {
  97. draft.name = model.name
  98. draft.family = model.family ? ModelV2.Family.make(model.family) : undefined
  99. draft.api = model.provider?.npm
  100. ? {
  101. id: draft.api.id,
  102. type: "aisdk",
  103. package: model.provider?.npm,
  104. url: model.provider.api,
  105. }
  106. : {
  107. id: draft.api.id,
  108. type: "native",
  109. url: model.provider?.api,
  110. settings: {},
  111. }
  112. draft.capabilities = {
  113. tools: model.tool_call,
  114. input: [...(model.modalities?.input ?? [])],
  115. output: [...(model.modalities?.output ?? [])],
  116. }
  117. draft.variants = variants(model, model.provider?.npm ?? item.npm)
  118. draft.time.released = released(model.release_date)
  119. draft.cost = cost(model.cost)
  120. draft.status = model.status ?? "active"
  121. draft.enabled = true
  122. draft.limit = {
  123. context: model.limit.context,
  124. input: model.limit.input,
  125. output: model.limit.output,
  126. }
  127. })
  128. }
  129. }
  130. })
  131. })
  132. yield* refresh()
  133. yield* events.subscribe(ModelsDev.Event.Refreshed).pipe(
  134. Stream.runForEach(() => refresh()),
  135. Effect.forkScoped({ startImmediately: true }),
  136. )
  137. }),
  138. })