providers.ts 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247
  1. import { DEFAULT_AGENT_MCPS } from '../config/agent-mcps';
  2. import { RECOMMENDED_SKILLS } from './skills';
  3. import type { InstallConfig } from './types';
  4. // Model mappings by provider priority
  5. export const MODEL_MAPPINGS = {
  6. kimi: {
  7. orchestrator: { model: 'kimi-for-coding/k2p5' },
  8. oracle: { model: 'kimi-for-coding/k2p5', variant: 'high' },
  9. librarian: { model: 'kimi-for-coding/k2p5', variant: 'low' },
  10. explorer: { model: 'kimi-for-coding/k2p5', variant: 'low' },
  11. designer: { model: 'kimi-for-coding/k2p5', variant: 'medium' },
  12. fixer: { model: 'kimi-for-coding/k2p5', variant: 'low' },
  13. },
  14. openai: {
  15. orchestrator: { model: 'openai/gpt-5.2-codex' },
  16. oracle: { model: 'openai/gpt-5.2-codex', variant: 'high' },
  17. librarian: { model: 'openai/gpt-5.1-codex-mini', variant: 'low' },
  18. explorer: { model: 'openai/gpt-5.1-codex-mini', variant: 'low' },
  19. designer: { model: 'openai/gpt-5.1-codex-mini', variant: 'medium' },
  20. fixer: { model: 'openai/gpt-5.1-codex-mini', variant: 'low' },
  21. },
  22. antigravity: {
  23. orchestrator: { model: 'google/antigravity-gemini-3-flash' },
  24. oracle: { model: 'google/antigravity-gemini-3-pro' },
  25. librarian: {
  26. model: 'google/antigravity-gemini-3-flash',
  27. variant: 'low',
  28. },
  29. explorer: {
  30. model: 'google/antigravity-gemini-3-flash',
  31. variant: 'low',
  32. },
  33. designer: {
  34. model: 'google/antigravity-gemini-3-flash',
  35. variant: 'medium',
  36. },
  37. fixer: { model: 'google/antigravity-gemini-3-flash', variant: 'low' },
  38. },
  39. 'zen-free': {
  40. orchestrator: { model: 'opencode/big-pickle' },
  41. oracle: { model: 'opencode/big-pickle', variant: 'high' },
  42. librarian: { model: 'opencode/big-pickle', variant: 'low' },
  43. explorer: { model: 'opencode/big-pickle', variant: 'low' },
  44. designer: { model: 'opencode/big-pickle', variant: 'medium' },
  45. fixer: { model: 'opencode/big-pickle', variant: 'low' },
  46. },
  47. } as const;
  48. export function generateAntigravityMixedPreset(
  49. config: InstallConfig,
  50. existingPreset?: Record<string, unknown>,
  51. ): Record<string, unknown> {
  52. const result: Record<string, unknown> = existingPreset
  53. ? { ...existingPreset }
  54. : {};
  55. const createAgentConfig = (
  56. agentName: string,
  57. modelInfo: { model: string; variant?: string },
  58. ) => {
  59. const isOrchestrator = agentName === 'orchestrator';
  60. // Skills: orchestrator gets "*", others get recommended skills for their role
  61. const skills = isOrchestrator
  62. ? ['*']
  63. : RECOMMENDED_SKILLS.filter(
  64. (s) =>
  65. s.allowedAgents.includes('*') ||
  66. s.allowedAgents.includes(agentName),
  67. ).map((s) => s.skillName);
  68. // Special case for designer and agent-browser skill
  69. if (agentName === 'designer' && !skills.includes('agent-browser')) {
  70. skills.push('agent-browser');
  71. }
  72. return {
  73. model: modelInfo.model,
  74. variant: modelInfo.variant,
  75. skills,
  76. mcps:
  77. DEFAULT_AGENT_MCPS[agentName as keyof typeof DEFAULT_AGENT_MCPS] ?? [],
  78. };
  79. };
  80. const antigravityFlash = {
  81. model: 'google/antigravity-gemini-3-flash',
  82. };
  83. // Orchestrator: Kimi if hasKimi, else keep existing if exists, else antigravity
  84. if (config.hasKimi) {
  85. result.orchestrator = createAgentConfig(
  86. 'orchestrator',
  87. MODEL_MAPPINGS.kimi.orchestrator,
  88. );
  89. } else if (!result.orchestrator) {
  90. result.orchestrator = createAgentConfig(
  91. 'orchestrator',
  92. MODEL_MAPPINGS.antigravity.orchestrator,
  93. );
  94. }
  95. // Oracle: GPT if hasOpenAI, else keep existing if exists, else antigravity
  96. if (config.hasOpenAI) {
  97. result.oracle = createAgentConfig('oracle', MODEL_MAPPINGS.openai.oracle);
  98. } else if (!result.oracle) {
  99. result.oracle = createAgentConfig(
  100. 'oracle',
  101. MODEL_MAPPINGS.antigravity.oracle,
  102. );
  103. }
  104. // Explorer, Librarian, Designer, Fixer: Always use Antigravity Flash
  105. result.explorer = createAgentConfig('explorer', {
  106. ...antigravityFlash,
  107. variant: 'low',
  108. });
  109. result.librarian = createAgentConfig('librarian', {
  110. ...antigravityFlash,
  111. variant: 'low',
  112. });
  113. result.designer = createAgentConfig('designer', {
  114. ...antigravityFlash,
  115. variant: 'medium',
  116. });
  117. result.fixer = createAgentConfig('fixer', {
  118. ...antigravityFlash,
  119. variant: 'low',
  120. });
  121. return result;
  122. }
  123. export function generateLiteConfig(
  124. installConfig: InstallConfig,
  125. ): Record<string, unknown> {
  126. const config: Record<string, unknown> = {
  127. preset: 'zen-free',
  128. presets: {},
  129. };
  130. // Determine active preset name
  131. let activePreset:
  132. | 'kimi'
  133. | 'openai'
  134. | 'antigravity'
  135. | 'antigravity-mixed-both'
  136. | 'antigravity-mixed-kimi'
  137. | 'antigravity-mixed-openai'
  138. | 'zen-free' = 'zen-free';
  139. // Antigravity mixed presets have priority
  140. if (
  141. installConfig.hasAntigravity &&
  142. installConfig.hasKimi &&
  143. installConfig.hasOpenAI
  144. ) {
  145. activePreset = 'antigravity-mixed-both';
  146. } else if (installConfig.hasAntigravity && installConfig.hasKimi) {
  147. activePreset = 'antigravity-mixed-kimi';
  148. } else if (installConfig.hasAntigravity && installConfig.hasOpenAI) {
  149. activePreset = 'antigravity-mixed-openai';
  150. } else if (installConfig.hasAntigravity) {
  151. activePreset = 'antigravity';
  152. } else if (installConfig.hasKimi) {
  153. activePreset = 'kimi';
  154. } else if (installConfig.hasOpenAI) {
  155. activePreset = 'openai';
  156. }
  157. config.preset = activePreset;
  158. const createAgentConfig = (
  159. agentName: string,
  160. modelInfo: { model: string; variant?: string },
  161. ) => {
  162. const isOrchestrator = agentName === 'orchestrator';
  163. // Skills: orchestrator gets "*", others get recommended skills for their role
  164. const skills = isOrchestrator
  165. ? ['*']
  166. : RECOMMENDED_SKILLS.filter(
  167. (s) =>
  168. s.allowedAgents.includes('*') ||
  169. s.allowedAgents.includes(agentName),
  170. ).map((s) => s.skillName);
  171. // Special case for designer and agent-browser skill
  172. if (agentName === 'designer' && !skills.includes('agent-browser')) {
  173. skills.push('agent-browser');
  174. }
  175. return {
  176. model: modelInfo.model,
  177. variant: modelInfo.variant,
  178. skills,
  179. mcps:
  180. DEFAULT_AGENT_MCPS[agentName as keyof typeof DEFAULT_AGENT_MCPS] ?? [],
  181. };
  182. };
  183. const buildPreset = (mappingName: keyof typeof MODEL_MAPPINGS) => {
  184. const mapping = MODEL_MAPPINGS[mappingName];
  185. return Object.fromEntries(
  186. Object.entries(mapping).map(([agentName, modelInfo]) => {
  187. let activeModelInfo = { ...modelInfo };
  188. // Hybrid case: Kimi + OpenAI (use OpenAI for Oracle, Kimi for orchestrator/designer)
  189. if (
  190. activePreset === 'kimi' &&
  191. installConfig.hasOpenAI &&
  192. agentName === 'oracle'
  193. ) {
  194. activeModelInfo = { ...MODEL_MAPPINGS.openai.oracle };
  195. }
  196. return [agentName, createAgentConfig(agentName, activeModelInfo)];
  197. }),
  198. );
  199. };
  200. // Build preset based on type
  201. if (
  202. activePreset === 'antigravity-mixed-both' ||
  203. activePreset === 'antigravity-mixed-kimi' ||
  204. activePreset === 'antigravity-mixed-openai'
  205. ) {
  206. // Use dedicated mixed preset generator
  207. (config.presets as Record<string, unknown>)[activePreset] =
  208. generateAntigravityMixedPreset(installConfig);
  209. } else {
  210. // Use standard buildPreset for pure presets
  211. (config.presets as Record<string, unknown>)[activePreset] =
  212. buildPreset(activePreset);
  213. }
  214. if (installConfig.hasTmux) {
  215. config.tmux = {
  216. enabled: true,
  217. layout: 'main-vertical',
  218. main_pane_size: 60,
  219. };
  220. }
  221. return config;
  222. }