catalog.ts 2.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263
  1. /** Shared projection of the live LLM registry into the browser model catalog. */
  2. import type { Context } from '@deepseek-ai/cordis'
  3. import type {
  4. ModelCatalogFailure,
  5. ModelProviderGroup,
  6. ModelReasoning,
  7. } from './types.ts'
  8. /**
  9. * Build the browser model catalog without requiring a Session.
  10. * @param ctx - Host context carrying the live LLM registry.
  11. * @returns successful non-empty provider groups and isolated provider failures.
  12. */
  13. export async function buildModelCatalog(ctx: Context): Promise<{
  14. readonly groups: ModelProviderGroup[]
  15. readonly failures: ModelCatalogFailure[]
  16. }> {
  17. const catalog = await Promise.all(ctx.llm.listProviders().map(async (provider) => {
  18. try {
  19. const models = await ctx.llm.listModels(provider.id)
  20. const entries = await Promise.all(models.map(async (model) => {
  21. const resolved = await ctx.llm.resolveModelInfo(provider.id, model.id)
  22. const reasoning: ModelReasoning | undefined = resolved.reasoning === undefined
  23. ? undefined
  24. : {
  25. efforts: resolved.reasoning.efforts.map(effort => ({
  26. id: effort.id,
  27. name: effort.name,
  28. ...(effort.description === undefined ? {} : { description: effort.description }),
  29. })),
  30. ...(resolved.reasoning.defaultEffort === undefined
  31. ? {}
  32. : { defaultEffort: resolved.reasoning.defaultEffort }),
  33. }
  34. return {
  35. id: model.id,
  36. name: model.name,
  37. ...(model.description === undefined ? {} : { description: model.description }),
  38. ...(reasoning === undefined ? {} : { reasoning }),
  39. }
  40. }))
  41. return {
  42. kind: 'group' as const,
  43. group: { id: provider.id, name: provider.name, models: entries },
  44. }
  45. } catch (error) {
  46. return {
  47. kind: 'failure' as const,
  48. failure: {
  49. id: provider.id,
  50. name: provider.name,
  51. message: error instanceof Error ? error.message : String(error),
  52. },
  53. }
  54. }
  55. }))
  56. return {
  57. groups: catalog.flatMap(item => item.kind === 'group' ? [item.group] : [])
  58. .filter(group => group.models.length > 0),
  59. failures: catalog.flatMap(item => item.kind === 'failure' ? [item.failure] : []),
  60. }
  61. }