models-dev.ts 4.3 KB

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