model.ts 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. export * as Model from "./model.js"
  2. import { Schema } from "effect"
  3. import { optional, statics } from "./schema.js"
  4. import { Provider } from "./provider.js"
  5. import { Money } from "./money.js"
  6. export const ID = Schema.String.pipe(Schema.brand("Model.ID"))
  7. export type ID = typeof ID.Type
  8. export const VariantID = Schema.String.pipe(Schema.brand("Model.VariantID"))
  9. export type VariantID = typeof VariantID.Type
  10. export const Ref = Schema.Struct({
  11. id: ID,
  12. providerID: Provider.ID,
  13. variant: VariantID.pipe(optional),
  14. })
  15. .annotate({ identifier: "Model.Ref" })
  16. .pipe(
  17. statics((schema) => ({
  18. parse: (input: string) => {
  19. const providerEnd = input.indexOf("/")
  20. if (providerEnd <= 0) throw new Error(`Invalid model reference: ${input}`)
  21. const providerID = input.slice(0, providerEnd)
  22. const variantStart = input.indexOf("#", providerEnd + 1)
  23. const id = input.slice(providerEnd + 1, variantStart === -1 ? undefined : variantStart)
  24. const variant = variantStart === -1 ? undefined : input.slice(variantStart + 1)
  25. if (!id || providerID.includes("#") || (variant !== undefined && (!variant || variant.includes("#"))))
  26. throw new Error(`Invalid model reference: ${input}`)
  27. return schema.make({
  28. providerID: Provider.ID.make(providerID),
  29. id: ID.make(id),
  30. ...(variant ? { variant: VariantID.make(variant) } : {}),
  31. })
  32. },
  33. })),
  34. )
  35. export interface Ref extends Schema.Schema.Type<typeof Ref> {}
  36. export const Family = Schema.String.pipe(Schema.brand("Model.Family"))
  37. export type Family = typeof Family.Type
  38. export type ReasoningField = "reasoning" | "reasoning_content" | "reasoning_text" | (string & {})
  39. export const ReasoningField: Schema.Codec<ReasoningField> = Schema.Union([
  40. Schema.Literals(["reasoning", "reasoning_content", "reasoning_text"]),
  41. Schema.String,
  42. ]).annotate({ identifier: "Model.ReasoningField" })
  43. export const MaxTokensField = Schema.Literals(["max_completion_tokens", "max_tokens"]).annotate({
  44. identifier: "Model.MaxTokensField",
  45. })
  46. export type MaxTokensField = typeof MaxTokensField.Type
  47. export interface Compatibility extends Schema.Schema.Type<typeof Compatibility> {}
  48. export const Compatibility = Schema.Struct({
  49. reasoningField: ReasoningField.pipe(optional),
  50. maxTokensField: MaxTokensField.pipe(optional),
  51. requireFinishReason: Schema.Boolean.pipe(optional),
  52. }).annotate({ identifier: "Model.Compatibility" })
  53. export interface Capabilities extends Schema.Schema.Type<typeof Capabilities> {}
  54. export const Capabilities = Schema.Struct({
  55. tools: Schema.Boolean,
  56. input: Schema.Array(Schema.String),
  57. output: Schema.Array(Schema.String),
  58. }).annotate({ identifier: "Model.Capabilities" })
  59. export interface Cost extends Schema.Schema.Type<typeof Cost> {}
  60. export const Cost = Schema.Struct({
  61. tier: Schema.Struct({
  62. type: Schema.tag("context"),
  63. size: Schema.Int,
  64. }).pipe(optional),
  65. input: Money.USDPerMillionTokens,
  66. output: Money.USDPerMillionTokens,
  67. cache: Schema.Struct({
  68. read: Money.USDPerMillionTokens,
  69. write: Money.USDPerMillionTokens,
  70. }),
  71. }).annotate({ identifier: "Model.Cost" })
  72. export interface Variant extends Schema.Schema.Type<typeof Variant> {}
  73. export const Variant = Schema.Struct({
  74. id: VariantID,
  75. ...Provider.Overlays,
  76. }).annotate({ identifier: "Model.Variant" })
  77. export interface Info extends Schema.Schema.Type<typeof Info> {}
  78. export const Info = Schema.Struct({
  79. id: ID,
  80. modelID: ID,
  81. providerID: Provider.ID,
  82. family: Family.pipe(optional),
  83. name: Schema.String,
  84. compatibility: Compatibility.pipe(optional),
  85. package: Provider.Package.pipe(optional),
  86. ...Provider.Overlays,
  87. capabilities: Capabilities,
  88. variants: Schema.Array(Variant),
  89. time: Schema.Struct({
  90. released: Schema.Finite,
  91. }),
  92. cost: Schema.Array(Cost),
  93. status: Schema.Literals(["alpha", "beta", "deprecated", "active"]),
  94. enabled: Schema.Boolean,
  95. limit: Schema.Struct({
  96. context: Schema.Int,
  97. input: Schema.Int.pipe(optional),
  98. output: Schema.Int,
  99. }),
  100. })
  101. .annotate({ identifier: "Model.Info" })
  102. .pipe(
  103. statics(() => ({
  104. default: (providerID: Provider.ID, id: ID) =>
  105. ({
  106. id,
  107. modelID: id,
  108. providerID,
  109. name: id,
  110. capabilities: { tools: true, input: ["text", "image"], output: ["text"] },
  111. variants: [],
  112. time: { released: 0 },
  113. cost: [],
  114. status: "active",
  115. enabled: true,
  116. limit: { context: 0, output: 0 },
  117. }) satisfies Info,
  118. })),
  119. )