gencode-ai 0.2.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (150) hide show
  1. package/dist/agent/agent.d.ts +9 -2
  2. package/dist/agent/agent.d.ts.map +1 -1
  3. package/dist/agent/agent.js +37 -8
  4. package/dist/agent/agent.js.map +1 -1
  5. package/dist/agent/types.d.ts +5 -1
  6. package/dist/agent/types.d.ts.map +1 -1
  7. package/dist/cli/components/App.d.ts.map +1 -1
  8. package/dist/cli/components/App.js +15 -9
  9. package/dist/cli/components/App.js.map +1 -1
  10. package/dist/cli/components/Messages.js +1 -1
  11. package/dist/cli/components/Messages.js.map +1 -1
  12. package/dist/cli/components/ModelSelector.d.ts +4 -3
  13. package/dist/cli/components/ModelSelector.d.ts.map +1 -1
  14. package/dist/cli/components/ModelSelector.js +54 -37
  15. package/dist/cli/components/ModelSelector.js.map +1 -1
  16. package/dist/cli/components/ProviderManager.d.ts +2 -2
  17. package/dist/cli/components/ProviderManager.d.ts.map +1 -1
  18. package/dist/cli/components/ProviderManager.js +137 -156
  19. package/dist/cli/components/ProviderManager.js.map +1 -1
  20. package/dist/cli/index.js +30 -13
  21. package/dist/cli/index.js.map +1 -1
  22. package/dist/config/index.d.ts +2 -2
  23. package/dist/config/index.d.ts.map +1 -1
  24. package/dist/config/index.js +1 -1
  25. package/dist/config/index.js.map +1 -1
  26. package/dist/config/levels.d.ts +5 -5
  27. package/dist/config/levels.d.ts.map +1 -1
  28. package/dist/config/levels.js +20 -20
  29. package/dist/config/levels.js.map +1 -1
  30. package/dist/config/merger.js +1 -1
  31. package/dist/config/merger.js.map +1 -1
  32. package/dist/config/providers-config.d.ts +8 -5
  33. package/dist/config/providers-config.d.ts.map +1 -1
  34. package/dist/config/providers-config.js +19 -22
  35. package/dist/config/providers-config.js.map +1 -1
  36. package/dist/config/test-utils.d.ts +2 -2
  37. package/dist/config/test-utils.d.ts.map +1 -1
  38. package/dist/config/test-utils.js +4 -4
  39. package/dist/config/test-utils.js.map +1 -1
  40. package/dist/config/types.d.ts +23 -17
  41. package/dist/config/types.d.ts.map +1 -1
  42. package/dist/config/types.js +14 -14
  43. package/dist/config/types.js.map +1 -1
  44. package/dist/memory/memory-manager.d.ts +25 -12
  45. package/dist/memory/memory-manager.d.ts.map +1 -1
  46. package/dist/memory/memory-manager.js +241 -112
  47. package/dist/memory/memory-manager.js.map +1 -1
  48. package/dist/memory/test-utils.d.ts +1 -1
  49. package/dist/memory/test-utils.d.ts.map +1 -1
  50. package/dist/memory/test-utils.js +3 -3
  51. package/dist/memory/test-utils.js.map +1 -1
  52. package/dist/memory/types.d.ts +20 -10
  53. package/dist/memory/types.d.ts.map +1 -1
  54. package/dist/memory/types.js +13 -13
  55. package/dist/memory/types.js.map +1 -1
  56. package/dist/migration/migrate.d.ts +24 -0
  57. package/dist/migration/migrate.d.ts.map +1 -0
  58. package/dist/migration/migrate.js +164 -0
  59. package/dist/migration/migrate.js.map +1 -0
  60. package/dist/permissions/persistence.d.ts +2 -2
  61. package/dist/permissions/persistence.js +4 -4
  62. package/dist/permissions/persistence.js.map +1 -1
  63. package/dist/planning/plan-file.d.ts +1 -1
  64. package/dist/planning/plan-file.js +2 -2
  65. package/dist/planning/plan-file.js.map +1 -1
  66. package/dist/prompts/index.d.ts +5 -4
  67. package/dist/prompts/index.d.ts.map +1 -1
  68. package/dist/prompts/index.js +11 -8
  69. package/dist/prompts/index.js.map +1 -1
  70. package/dist/providers/anthropic.d.ts +2 -1
  71. package/dist/providers/anthropic.d.ts.map +1 -1
  72. package/dist/providers/anthropic.js +7 -0
  73. package/dist/providers/anthropic.js.map +1 -1
  74. package/dist/providers/gemini.d.ts +2 -1
  75. package/dist/providers/gemini.d.ts.map +1 -1
  76. package/dist/providers/gemini.js +7 -0
  77. package/dist/providers/gemini.js.map +1 -1
  78. package/dist/providers/index.d.ts +20 -10
  79. package/dist/providers/index.d.ts.map +1 -1
  80. package/dist/providers/index.js +48 -24
  81. package/dist/providers/index.js.map +1 -1
  82. package/dist/providers/openai.d.ts +2 -1
  83. package/dist/providers/openai.d.ts.map +1 -1
  84. package/dist/providers/openai.js +7 -0
  85. package/dist/providers/openai.js.map +1 -1
  86. package/dist/providers/registry.d.ts +48 -34
  87. package/dist/providers/registry.d.ts.map +1 -1
  88. package/dist/providers/registry.js +72 -88
  89. package/dist/providers/registry.js.map +1 -1
  90. package/dist/providers/store.d.ts +43 -17
  91. package/dist/providers/store.d.ts.map +1 -1
  92. package/dist/providers/store.js +112 -19
  93. package/dist/providers/store.js.map +1 -1
  94. package/dist/providers/types.d.ts +23 -0
  95. package/dist/providers/types.d.ts.map +1 -1
  96. package/dist/providers/vertex-ai.d.ts +15 -7
  97. package/dist/providers/vertex-ai.d.ts.map +1 -1
  98. package/dist/providers/vertex-ai.js +46 -13
  99. package/dist/providers/vertex-ai.js.map +1 -1
  100. package/dist/session/types.js +1 -1
  101. package/dist/session/types.js.map +1 -1
  102. package/docs/config-system-comparison.md +50 -50
  103. package/docs/cost-tracking-comparison.md +2 -2
  104. package/docs/memory-system.md +124 -31
  105. package/docs/permissions.md +2 -2
  106. package/docs/proposals/0006-memory-system.md +4 -4
  107. package/docs/proposals/0008-checkpointing.md +109 -2
  108. package/docs/proposals/0011-custom-commands.md +2 -1
  109. package/docs/proposals/0021-skills-system.md +2 -1
  110. package/docs/proposals/0023-permission-enhancements.md +2 -2
  111. package/docs/proposals/0033-enterprise-deployment.md +1 -1
  112. package/docs/proposals/0041-configuration-system.md +17 -19
  113. package/docs/proposals/0042-prompt-optimization.md +17 -9
  114. package/docs/proposals/README.md +5 -5
  115. package/docs/providers.md +94 -9
  116. package/package.json +3 -2
  117. package/scripts/migrate.ts +449 -0
  118. package/src/agent/agent.ts +51 -9
  119. package/src/agent/types.ts +5 -1
  120. package/src/cli/components/App.tsx +17 -8
  121. package/src/cli/components/Messages.tsx +1 -1
  122. package/src/cli/components/ModelSelector.tsx +62 -43
  123. package/src/cli/components/ProviderManager.tsx +278 -323
  124. package/src/cli/index.tsx +36 -17
  125. package/src/config/index.ts +5 -3
  126. package/src/config/levels.test.ts +22 -22
  127. package/src/config/levels.ts +22 -22
  128. package/src/config/loader.test.ts +14 -14
  129. package/src/config/manager.test.ts +19 -19
  130. package/src/config/merger.test.ts +23 -23
  131. package/src/config/merger.ts +1 -1
  132. package/src/config/providers-config.ts +23 -21
  133. package/src/config/test-utils.ts +6 -6
  134. package/src/config/types.ts +30 -20
  135. package/src/memory/memory-manager.test.ts +242 -24
  136. package/src/memory/memory-manager.ts +270 -141
  137. package/src/memory/test-utils.ts +4 -4
  138. package/src/memory/types.ts +28 -17
  139. package/src/permissions/persistence.ts +4 -4
  140. package/src/planning/plan-file.ts +2 -2
  141. package/src/prompts/index.ts +13 -9
  142. package/src/providers/anthropic.ts +9 -0
  143. package/src/providers/gemini.ts +9 -0
  144. package/src/providers/index.ts +76 -33
  145. package/src/providers/openai.ts +9 -0
  146. package/src/providers/registry.ts +116 -111
  147. package/src/providers/store.ts +130 -28
  148. package/src/providers/types.ts +33 -1
  149. package/src/providers/vertex-ai.ts +49 -13
  150. package/src/session/types.ts +1 -1
@@ -2,15 +2,15 @@
2
2
  * Memory System Types
3
3
  *
4
4
  * Hierarchical memory loading compatible with Claude Code:
5
- * At each level, both .gencode and .claude are loaded and merged (gencode has higher priority).
5
+ * At each level, both .gen and .claude are loaded and merged (gen has higher priority).
6
6
  *
7
7
  * Levels:
8
8
  * - Enterprise: System-wide managed memory (enforced)
9
- * - User: ~/.gencode/ + ~/.claude/ (both loaded, gencode content appears later)
10
- * - User Rules: ~/.gencode/rules/ + ~/.claude/rules/
11
- * - Extra: GENCODE_CONFIG_DIRS directories
12
- * - Project: ./AGENT.md, .gencode/, ./CLAUDE.md, .claude/ (recursive upward search)
13
- * - Project Rules: .gencode/rules/ + .claude/rules/
9
+ * - User: ~/.gen/ + ~/.claude/ (both loaded, gen content appears later)
10
+ * - User Rules: ~/.gen/rules/ + ~/.claude/rules/
11
+ * - Extra: GEN_CONFIG_DIRS directories
12
+ * - Project: ./GEN.md, .gen/, ./CLAUDE.md, .claude/ (recursive upward search)
13
+ * - Project Rules: .gen/rules/ + .claude/rules/
14
14
  * - Local: *.local.md files (gitignored)
15
15
  */
16
16
 
@@ -23,7 +23,16 @@ export type MemoryLevel =
23
23
  | 'project-rules'
24
24
  | 'local';
25
25
 
26
- export type MemoryNamespace = 'gencode' | 'claude' | 'extra';
26
+ export type MemoryNamespace = 'gen' | 'claude' | 'extra';
27
+
28
+ /**
29
+ * Memory merge strategy - how to combine CLAUDE.md and GEN.md at each level
30
+ * - fallback: Load GEN.md if exists, else CLAUDE.md (reduces context, default)
31
+ * - both: Load both CLAUDE.md and GEN.md (current behavior, max context)
32
+ * - gen-only: Only load .gen/GEN.md files
33
+ * - claude-only: Only load .claude/CLAUDE.md files
34
+ */
35
+ export type MemoryMergeStrategy = 'fallback' | 'both' | 'gen-only' | 'claude-only';
27
36
 
28
37
  export interface MemoryFile {
29
38
  path: string;
@@ -46,9 +55,9 @@ export interface MemoryRule {
46
55
 
47
56
  export interface MemoryConfig {
48
57
  // GenCode file names (higher priority)
49
- gencodeFilename: string;
50
- gencodeLocalFilename: string;
51
- gencodeDir: string;
58
+ genFilename: string;
59
+ genLocalFilename: string;
60
+ genDir: string;
52
61
 
53
62
  // Claude file names (lower priority, loaded first)
54
63
  claudeFilename: string;
@@ -64,9 +73,9 @@ export interface MemoryConfig {
64
73
 
65
74
  export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
66
75
  // GenCode
67
- gencodeFilename: 'AGENT.md',
68
- gencodeLocalFilename: 'AGENT.local.md',
69
- gencodeDir: '.gencode',
76
+ genFilename: 'GEN.md',
77
+ genLocalFilename: 'GEN.local.md',
78
+ genDir: '.gen',
70
79
 
71
80
  // Claude
72
81
  claudeFilename: 'CLAUDE.md',
@@ -82,13 +91,13 @@ export const DEFAULT_MEMORY_CONFIG: MemoryConfig = {
82
91
 
83
92
  // Legacy compatibility
84
93
  export const LEGACY_MEMORY_CONFIG = {
85
- primaryFilename: 'AGENT.md',
94
+ primaryFilename: 'GEN.md',
86
95
  fallbackFilename: 'CLAUDE.md',
87
- localFilename: 'AGENT.local.md',
96
+ localFilename: 'GEN.local.md',
88
97
  localFallbackFilename: 'CLAUDE.local.md',
89
- primaryUserDir: '.gencode',
98
+ primaryUserDir: '.gen',
90
99
  fallbackUserDir: '.claude',
91
- primaryLocalDir: '.gencode',
100
+ primaryLocalDir: '.gen',
92
101
  fallbackLocalDir: '.claude',
93
102
  rulesDir: 'rules',
94
103
  maxFileSize: 100 * 1024,
@@ -103,6 +112,7 @@ export interface LoadedMemory {
103
112
  context: string;
104
113
  errors: string[];
105
114
  sources: MemorySource[]; // For debugging
115
+ skippedFiles: string[]; // Files skipped due to merge strategy
106
116
  }
107
117
 
108
118
  export interface MemorySource {
@@ -116,4 +126,5 @@ export interface MemorySource {
116
126
  export interface MemoryLoadOptions {
117
127
  cwd: string;
118
128
  currentFile?: string; // For activating path-scoped rules
129
+ strategy?: MemoryMergeStrategy; // How to merge CLAUDE.md and AGENT.md (default: 'fallback')
119
130
  }
@@ -2,8 +2,8 @@
2
2
  * Permission Persistence - Store and load permission rules
3
3
  *
4
4
  * Handles persistent storage of permission rules at:
5
- * - Global: ~/.gencode/permissions.json
6
- * - Project: .gencode/permissions.json
5
+ * - Global: ~/.gen/permissions.json
6
+ * - Project: .gen/permissions.json
7
7
  */
8
8
 
9
9
  import * as fs from 'fs/promises';
@@ -21,7 +21,7 @@ import { parsePatternString } from './prompt-matcher.js';
21
21
 
22
22
  const PERMISSIONS_VERSION = 1;
23
23
  const PERMISSIONS_FILE = 'permissions.json';
24
- const GLOBAL_DIR = path.join(os.homedir(), '.gencode');
24
+ const GLOBAL_DIR = path.join(os.homedir(), '.gen');
25
25
 
26
26
  /**
27
27
  * Permission Persistence Manager
@@ -32,7 +32,7 @@ export class PermissionPersistence {
32
32
 
33
33
  constructor(projectPath?: string) {
34
34
  this.globalDir = GLOBAL_DIR;
35
- this.projectDir = projectPath ? path.join(projectPath, '.gencode') : null;
35
+ this.projectDir = projectPath ? path.join(projectPath, '.gen') : null;
36
36
  }
37
37
 
38
38
  /**
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Plan File Utilities
3
3
  *
4
- * Manages plan files stored in .gencode/plans/ directory.
4
+ * Manages plan files stored in .gen/plans/ directory.
5
5
  * Generates unique filenames with timestamps and slugs.
6
6
  */
7
7
 
@@ -14,7 +14,7 @@ import type { PlanFile } from './types.js';
14
14
  // Constants
15
15
  // ============================================================================
16
16
 
17
- const PLANS_DIR = '.gencode/plans';
17
+ const PLANS_DIR = '.gen/plans';
18
18
  const PLAN_FILE_EXTENSION = '.md';
19
19
 
20
20
  // Word lists for generating memorable names (like Claude Code)
@@ -14,7 +14,7 @@ import * as os from 'os';
14
14
  const __dirname = dirname(fileURLToPath(import.meta.url));
15
15
 
16
16
  // Path to providers.json config
17
- const PROVIDERS_CONFIG_PATH = join(homedir(), '.gencode', 'providers.json');
17
+ const PROVIDERS_CONFIG_PATH = join(homedir(), '.gen', 'providers.json');
18
18
 
19
19
  // Resolve prompts directory - check both src and dist locations
20
20
  function getPromptsDir(): string {
@@ -33,7 +33,7 @@ const promptsDir = getPromptsDir();
33
33
  export type ProviderType = 'anthropic' | 'openai' | 'gemini' | 'generic';
34
34
 
35
35
  /**
36
- * Providers config structure from ~/.gencode/providers.json
36
+ * Providers config structure from ~/.gen/providers.json
37
37
  */
38
38
  interface ProvidersConfig {
39
39
  connections: Record<string, unknown>;
@@ -41,7 +41,7 @@ interface ProvidersConfig {
41
41
  }
42
42
 
43
43
  /**
44
- * Load providers config from ~/.gencode/providers.json
44
+ * Load providers config from ~/.gen/providers.json
45
45
  */
46
46
  function loadProvidersConfig(): ProvidersConfig | null {
47
47
  try {
@@ -57,7 +57,7 @@ function loadProvidersConfig(): ProvidersConfig | null {
57
57
 
58
58
  /**
59
59
  * Look up which provider owns a given model ID
60
- * Searches through ~/.gencode/providers.json to find the provider
60
+ * Searches through ~/.gen/providers.json to find the provider
61
61
  *
62
62
  * @param model - The model ID (e.g., "claude-sonnet-4-5@20250929")
63
63
  * @returns The provider name (e.g., "anthropic") or null if not found
@@ -80,9 +80,13 @@ export function getProviderForModel(model: string): string | null {
80
80
  /**
81
81
  * Map provider names to prompt types
82
82
  * Falls back to 'generic' for unknown providers
83
+ * Handles both "provider" and "provider:authMethod" formats
83
84
  */
84
85
  export function mapProviderToPromptType(provider: string): ProviderType {
85
- switch (provider) {
86
+ // Extract provider prefix (e.g., "gemini:api_key" → "gemini")
87
+ const providerPrefix = provider.split(':')[0];
88
+
89
+ switch (providerPrefix) {
86
90
  case 'anthropic':
87
91
  return 'anthropic';
88
92
  case 'openai':
@@ -200,7 +204,7 @@ export function buildSystemPrompt(
200
204
 
201
205
  /**
202
206
  * Format memory context for injection into system prompt
203
- * Uses <claudeMd> tag for Claude Code compatibility
207
+ * Uses <claudeMd> tag for optimal compatibility with Claude models
204
208
  */
205
209
  export function formatMemoryContext(memoryContext: string): string {
206
210
  if (!memoryContext) {
@@ -240,7 +244,7 @@ export function buildSystemPromptWithMemory(
240
244
  * Flow: model → provider (from providers.json) → prompt
241
245
  *
242
246
  * This is the recommended way to build system prompts as it automatically
243
- * looks up the provider for the given model from ~/.gencode/providers.json
247
+ * looks up the provider for the given model from ~/.gen/providers.json
244
248
  *
245
249
  * @param model - The model ID (e.g., "claude-sonnet-4-5@20250929")
246
250
  * @param cwd - Current working directory
@@ -261,10 +265,10 @@ export function buildSystemPromptForModel(
261
265
 
262
266
  /**
263
267
  * Debug utility to verify prompt loading at runtime
264
- * Set GENCODE_DEBUG_PROMPTS=1 for summary, GENCODE_DEBUG_PROMPTS=2 for full content
268
+ * Set GEN_DEBUG_PROMPTS=1 for summary, GEN_DEBUG_PROMPTS=2 for full content
265
269
  */
266
270
  export function debugPromptLoading(model: string, fallbackProvider?: string): void {
267
- const debugLevel = process.env.GENCODE_DEBUG_PROMPTS;
271
+ const debugLevel = process.env.GEN_DEBUG_PROMPTS;
268
272
  if (!debugLevel || debugLevel === '0') {
269
273
  return;
270
274
  }
@@ -7,6 +7,7 @@ import Anthropic from '@anthropic-ai/sdk';
7
7
  import { calculateCost } from '../pricing/calculator.js';
8
8
  import type {
9
9
  LLMProvider,
10
+ ProviderClassMeta,
10
11
  CompletionOptions,
11
12
  CompletionResponse,
12
13
  StreamChunk,
@@ -23,6 +24,14 @@ type AnthropicTool = Anthropic.Tool;
23
24
  type AnthropicContent = Anthropic.ContentBlockParam;
24
25
 
25
26
  export class AnthropicProvider implements LLMProvider {
27
+ static readonly meta: ProviderClassMeta = {
28
+ provider: 'anthropic',
29
+ authMethod: 'api_key',
30
+ envVars: ['ANTHROPIC_API_KEY'],
31
+ displayName: 'Direct API',
32
+ description: 'Direct API access',
33
+ };
34
+
26
35
  readonly name = 'anthropic';
27
36
  private client: Anthropic;
28
37
 
@@ -8,6 +8,7 @@ import type { Content, Part, Tool, GenerateContentResult } from '@google/generat
8
8
  import { calculateCost } from '../pricing/calculator.js';
9
9
  import type {
10
10
  LLMProvider,
11
+ ProviderClassMeta,
11
12
  CompletionOptions,
12
13
  CompletionResponse,
13
14
  StreamChunk,
@@ -21,6 +22,14 @@ import type {
21
22
  } from './types.js';
22
23
 
23
24
  export class GeminiProvider implements LLMProvider {
25
+ static readonly meta: ProviderClassMeta = {
26
+ provider: 'gemini',
27
+ authMethod: 'api_key',
28
+ envVars: ['GOOGLE_API_KEY', 'GEMINI_API_KEY'],
29
+ displayName: 'Direct API',
30
+ description: 'Direct API access',
31
+ };
32
+
24
33
  readonly name = 'gemini';
25
34
  private client: GoogleGenerativeAI;
26
35
  private apiKey: string;
@@ -6,56 +6,80 @@ export * from './types.js';
6
6
  export { OpenAIProvider } from './openai.js';
7
7
  export { AnthropicProvider } from './anthropic.js';
8
8
  export { GeminiProvider } from './gemini.js';
9
- export { VertexAIProvider } from './vertex-ai.js';
9
+ export { AnthropicVertexProvider } from './vertex-ai.js';
10
10
 
11
- import type { LLMProvider, OpenAIConfig, AnthropicConfig, GeminiConfig, VertexAIConfig } from './types.js';
11
+ import type {
12
+ LLMProvider,
13
+ Provider,
14
+ AuthMethod,
15
+ OpenAIConfig,
16
+ AnthropicConfig,
17
+ GeminiConfig,
18
+ VertexAIConfig,
19
+ } from './types.js';
12
20
  import { OpenAIProvider } from './openai.js';
13
21
  import { AnthropicProvider } from './anthropic.js';
14
22
  import { GeminiProvider } from './gemini.js';
15
- import { VertexAIProvider } from './vertex-ai.js';
23
+ import { AnthropicVertexProvider } from './vertex-ai.js';
24
+
25
+ // Legacy type alias for backward compatibility
26
+ /** @deprecated Use Provider instead */
27
+ export type ProviderName = Provider;
16
28
 
17
- export type ProviderName = 'openai' | 'anthropic' | 'gemini' | 'vertex-ai';
18
29
  export type ProviderConfigMap = {
19
30
  openai: OpenAIConfig;
20
31
  anthropic: AnthropicConfig;
21
32
  gemini: GeminiConfig;
22
- 'vertex-ai': VertexAIConfig;
23
33
  };
24
34
 
25
- export interface CreateProviderOptions<T extends ProviderName = ProviderName> {
26
- provider: T;
27
- config?: ProviderConfigMap[T];
35
+ export interface CreateProviderOptions {
36
+ provider: Provider;
37
+ authMethod?: AuthMethod;
38
+ config?: OpenAIConfig | AnthropicConfig | GeminiConfig | VertexAIConfig;
28
39
  }
29
40
 
30
41
  /**
31
- * Create a provider instance by name
42
+ * Create a provider instance by provider and auth method
43
+ * If authMethod is not provided, defaults to 'api_key'
32
44
  */
33
45
  export function createProvider(options: CreateProviderOptions): LLMProvider {
34
- switch (options.provider) {
35
- case 'openai':
36
- return new OpenAIProvider(options.config as OpenAIConfig);
37
- case 'anthropic':
38
- return new AnthropicProvider(options.config as AnthropicConfig);
39
- case 'gemini':
40
- return new GeminiProvider(options.config as GeminiConfig);
41
- case 'vertex-ai':
42
- return new VertexAIProvider(options.config as VertexAIConfig);
43
- default:
44
- throw new Error(`Unknown provider: ${options.provider}`);
46
+ const { provider, authMethod = 'api_key', config } = options;
47
+
48
+ // Map provider + authMethod to the correct implementation
49
+ if (provider === 'anthropic') {
50
+ if (authMethod === 'vertex') {
51
+ return new AnthropicVertexProvider(config as VertexAIConfig);
52
+ } else if (authMethod === 'api_key') {
53
+ return new AnthropicProvider(config as AnthropicConfig);
54
+ }
55
+ throw new Error(`Unsupported auth method for anthropic: ${authMethod}`);
56
+ }
57
+
58
+ if (provider === 'openai') {
59
+ if (authMethod === 'api_key') {
60
+ return new OpenAIProvider(config as OpenAIConfig);
61
+ }
62
+ throw new Error(`Unsupported auth method for openai: ${authMethod}`);
63
+ }
64
+
65
+ if (provider === 'gemini') {
66
+ if (authMethod === 'api_key') {
67
+ return new GeminiProvider(config as GeminiConfig);
68
+ }
69
+ throw new Error(`Unsupported auth method for gemini: ${authMethod}`);
45
70
  }
71
+
72
+ throw new Error(`Unknown provider: ${provider}`);
46
73
  }
47
74
 
48
75
  /**
49
76
  * Infer provider from model name
77
+ * Note: This only returns the provider, not the auth method
78
+ * For Vertex AI models (claude-*@version), this returns 'anthropic'
50
79
  */
51
- export function inferProvider(model: string): ProviderName {
80
+ export function inferProvider(model: string): Provider {
52
81
  const modelLower = model.toLowerCase();
53
82
 
54
- // Vertex AI models (Claude models with @ version suffix like claude-sonnet-4-5@20250929)
55
- if (modelLower.includes('claude') && modelLower.includes('@')) {
56
- return 'vertex-ai';
57
- }
58
-
59
83
  // OpenAI models
60
84
  if (
61
85
  modelLower.includes('gpt') ||
@@ -68,7 +92,7 @@ export function inferProvider(model: string): ProviderName {
68
92
  return 'openai';
69
93
  }
70
94
 
71
- // Anthropic models
95
+ // Anthropic models (including Vertex AI format with @)
72
96
  if (modelLower.includes('claude')) {
73
97
  return 'anthropic';
74
98
  }
@@ -82,10 +106,29 @@ export function inferProvider(model: string): ProviderName {
82
106
  return 'openai';
83
107
  }
84
108
 
109
+ /**
110
+ * Infer auth method from model name
111
+ * Returns undefined if auth method cannot be inferred
112
+ */
113
+ export function inferAuthMethod(model: string): AuthMethod | undefined {
114
+ const modelLower = model.toLowerCase();
115
+
116
+ // Vertex AI models (Claude models with @ version suffix like claude-sonnet-4-5@20250929)
117
+ if (modelLower.includes('claude') && modelLower.includes('@')) {
118
+ return 'vertex';
119
+ }
120
+
121
+ // For other models, we can't reliably infer auth method
122
+ return undefined;
123
+ }
124
+
85
125
  /**
86
126
  * Common model aliases
87
127
  */
88
- export const ModelAliases: Record<string, { provider: ProviderName; model: string }> = {
128
+ export const ModelAliases: Record<
129
+ string,
130
+ { provider: Provider; authMethod?: AuthMethod; model: string }
131
+ > = {
89
132
  // OpenAI
90
133
  'gpt-4o': { provider: 'openai', model: 'gpt-4o' },
91
134
  'gpt-4o-mini': { provider: 'openai', model: 'gpt-4o-mini' },
@@ -94,7 +137,7 @@ export const ModelAliases: Record<string, { provider: ProviderName; model: strin
94
137
  'o1-mini': { provider: 'openai', model: 'o1-mini' },
95
138
  'o3-mini': { provider: 'openai', model: 'o3-mini' },
96
139
 
97
- // Anthropic
140
+ // Anthropic (Direct API)
98
141
  'claude-opus': { provider: 'anthropic', model: 'claude-opus-4-5-20251101' },
99
142
  'claude-sonnet': { provider: 'anthropic', model: 'claude-sonnet-4-20250514' },
100
143
  'claude-haiku': { provider: 'anthropic', model: 'claude-haiku-4-20250514' },
@@ -105,8 +148,8 @@ export const ModelAliases: Record<string, { provider: ProviderName; model: strin
105
148
  'gemini-1.5-pro': { provider: 'gemini', model: 'gemini-1.5-pro' },
106
149
  'gemini-1.5-flash': { provider: 'gemini', model: 'gemini-1.5-flash' },
107
150
 
108
- // Vertex AI (Claude on GCP)
109
- 'vertex-sonnet': { provider: 'vertex-ai', model: 'claude-sonnet-4-5@20250929' },
110
- 'vertex-haiku': { provider: 'vertex-ai', model: 'claude-haiku-4-5@20251001' },
111
- 'vertex-opus': { provider: 'vertex-ai', model: 'claude-opus-4-1@20250805' },
151
+ // Anthropic via Vertex AI
152
+ 'vertex-sonnet': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-sonnet-4-5@20250929' },
153
+ 'vertex-haiku': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-haiku-4-5@20251001' },
154
+ 'vertex-opus': { provider: 'anthropic', authMethod: 'vertex', model: 'claude-opus-4-1@20250805' },
112
155
  };
@@ -7,6 +7,7 @@ import OpenAI from 'openai';
7
7
  import { calculateCost } from '../pricing/calculator.js';
8
8
  import type {
9
9
  LLMProvider,
10
+ ProviderClassMeta,
10
11
  CompletionOptions,
11
12
  CompletionResponse,
12
13
  StreamChunk,
@@ -22,6 +23,14 @@ type OpenAIMessage = OpenAI.Chat.Completions.ChatCompletionMessageParam;
22
23
  type OpenAITool = OpenAI.Chat.Completions.ChatCompletionTool;
23
24
 
24
25
  export class OpenAIProvider implements LLMProvider {
26
+ static readonly meta: ProviderClassMeta = {
27
+ provider: 'openai',
28
+ authMethod: 'api_key',
29
+ envVars: ['OPENAI_API_KEY'],
30
+ displayName: 'Direct API',
31
+ description: 'Direct API access',
32
+ };
33
+
25
34
  readonly name = 'openai';
26
35
  private client: OpenAI;
27
36