index.ts 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. import { Anthropic } from "@anthropic-ai/sdk"
  2. import { BetaThinkingConfigParam } from "@anthropic-ai/sdk/resources/beta/messages/index.mjs"
  3. import { ApiConfiguration, ModelInfo, ApiHandlerOptions } from "../shared/api"
  4. import { ANTHROPIC_DEFAULT_MAX_TOKENS } from "./providers/constants"
  5. import { GlamaHandler } from "./providers/glama"
  6. import { AnthropicHandler } from "./providers/anthropic"
  7. import { AwsBedrockHandler } from "./providers/bedrock"
  8. import { OpenRouterHandler } from "./providers/openrouter"
  9. import { VertexHandler } from "./providers/vertex"
  10. import { AnthropicVertexHandler } from "./providers/anthropic-vertex"
  11. import { OpenAiHandler } from "./providers/openai"
  12. import { OllamaHandler } from "./providers/ollama"
  13. import { LmStudioHandler } from "./providers/lmstudio"
  14. import { GeminiHandler } from "./providers/gemini"
  15. import { OpenAiNativeHandler } from "./providers/openai-native"
  16. import { DeepSeekHandler } from "./providers/deepseek"
  17. import { MistralHandler } from "./providers/mistral"
  18. import { VsCodeLmHandler } from "./providers/vscode-lm"
  19. import { ApiStream } from "./transform/stream"
  20. import { UnboundHandler } from "./providers/unbound"
  21. import { RequestyHandler } from "./providers/requesty"
  22. import { HumanRelayHandler } from "./providers/human-relay"
  23. import { FakeAIHandler } from "./providers/fake-ai"
  24. import { XAIHandler } from "./providers/xai"
  25. export interface SingleCompletionHandler {
  26. completePrompt(prompt: string): Promise<string>
  27. }
  28. export interface ApiHandler {
  29. createMessage(systemPrompt: string, messages: Anthropic.Messages.MessageParam[], cacheKey?: string): ApiStream
  30. getModel(): { id: string; info: ModelInfo }
  31. /**
  32. * Counts tokens for content blocks
  33. * All providers extend BaseProvider which provides a default tiktoken implementation,
  34. * but they can override this to use their native token counting endpoints
  35. *
  36. * @param content The content to count tokens for
  37. * @returns A promise resolving to the token count
  38. */
  39. countTokens(content: Array<Anthropic.Messages.ContentBlockParam>): Promise<number>
  40. }
  41. export function buildApiHandler(configuration: ApiConfiguration): ApiHandler {
  42. const { apiProvider, ...options } = configuration
  43. switch (apiProvider) {
  44. case "anthropic":
  45. return new AnthropicHandler(options)
  46. case "glama":
  47. return new GlamaHandler(options)
  48. case "openrouter":
  49. return new OpenRouterHandler(options)
  50. case "bedrock":
  51. return new AwsBedrockHandler(options)
  52. case "vertex":
  53. if (options.apiModelId?.startsWith("claude")) {
  54. return new AnthropicVertexHandler(options)
  55. } else {
  56. return new VertexHandler(options)
  57. }
  58. case "openai":
  59. return new OpenAiHandler(options)
  60. case "ollama":
  61. return new OllamaHandler(options)
  62. case "lmstudio":
  63. return new LmStudioHandler(options)
  64. case "gemini":
  65. return new GeminiHandler(options)
  66. case "openai-native":
  67. return new OpenAiNativeHandler(options)
  68. case "deepseek":
  69. return new DeepSeekHandler(options)
  70. case "vscode-lm":
  71. return new VsCodeLmHandler(options)
  72. case "mistral":
  73. return new MistralHandler(options)
  74. case "unbound":
  75. return new UnboundHandler(options)
  76. case "requesty":
  77. return new RequestyHandler(options)
  78. case "human-relay":
  79. return new HumanRelayHandler()
  80. case "fake-ai":
  81. return new FakeAIHandler(options)
  82. case "xai":
  83. return new XAIHandler(options)
  84. default:
  85. return new AnthropicHandler(options)
  86. }
  87. }
  88. export function getModelParams({
  89. options,
  90. model,
  91. defaultMaxTokens,
  92. defaultTemperature = 0,
  93. defaultReasoningEffort,
  94. }: {
  95. options: ApiHandlerOptions
  96. model: ModelInfo
  97. defaultMaxTokens?: number
  98. defaultTemperature?: number
  99. defaultReasoningEffort?: "low" | "medium" | "high"
  100. }) {
  101. const {
  102. modelMaxTokens: customMaxTokens,
  103. modelMaxThinkingTokens: customMaxThinkingTokens,
  104. modelTemperature: customTemperature,
  105. reasoningEffort: customReasoningEffort,
  106. } = options
  107. let maxTokens = model.maxTokens ?? defaultMaxTokens
  108. let thinking: BetaThinkingConfigParam | undefined = undefined
  109. let temperature = customTemperature ?? defaultTemperature
  110. const reasoningEffort = customReasoningEffort ?? defaultReasoningEffort
  111. if (model.thinking) {
  112. // Only honor `customMaxTokens` for thinking models.
  113. maxTokens = customMaxTokens ?? maxTokens
  114. // Clamp the thinking budget to be at most 80% of max tokens and at
  115. // least 1024 tokens.
  116. const maxBudgetTokens = Math.floor((maxTokens || ANTHROPIC_DEFAULT_MAX_TOKENS) * 0.8)
  117. const budgetTokens = Math.max(Math.min(customMaxThinkingTokens ?? maxBudgetTokens, maxBudgetTokens), 1024)
  118. thinking = { type: "enabled", budget_tokens: budgetTokens }
  119. // Anthropic "Thinking" models require a temperature of 1.0.
  120. temperature = 1.0
  121. }
  122. return { maxTokens, thinking, temperature, reasoningEffort }
  123. }