aiexecode 1.0.66 → 1.0.69

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.

Potentially problematic release.


This version of aiexecode might be problematic. Click here for more details.

Files changed (87) hide show
  1. package/config_template/settings.json +1 -3
  2. package/index.js +46 -71
  3. package/package.json +1 -12
  4. package/payload_viewer/out/404/index.html +1 -1
  5. package/payload_viewer/out/404.html +1 -1
  6. package/payload_viewer/out/index.html +1 -1
  7. package/payload_viewer/out/index.txt +1 -1
  8. package/payload_viewer/web_server.js +0 -163
  9. package/prompts/completion_judge.txt +11 -7
  10. package/src/ai_based/completion_judge.js +97 -6
  11. package/src/ai_based/orchestrator.js +71 -3
  12. package/src/ai_based/pip_package_installer.js +14 -12
  13. package/src/ai_based/pip_package_lookup.js +13 -10
  14. package/src/commands/apikey.js +8 -34
  15. package/src/commands/help.js +3 -4
  16. package/src/commands/model.js +17 -74
  17. package/src/commands/reasoning_effort.js +1 -1
  18. package/src/config/feature_flags.js +0 -12
  19. package/src/{ui → frontend}/App.js +23 -25
  20. package/src/frontend/README.md +81 -0
  21. package/src/{ui/components/SuggestionsDisplay.js → frontend/components/AutocompleteMenu.js} +3 -3
  22. package/src/{ui/components/HistoryItemDisplay.js → frontend/components/ConversationItem.js} +37 -89
  23. package/src/{ui → frontend}/components/CurrentModelView.js +3 -5
  24. package/src/{ui → frontend}/components/Footer.js +4 -6
  25. package/src/{ui → frontend}/components/Header.js +2 -5
  26. package/src/{ui/components/InputPrompt.js → frontend/components/Input.js} +16 -54
  27. package/src/frontend/components/ModelListView.js +106 -0
  28. package/src/{ui → frontend}/components/ModelUpdatedView.js +3 -5
  29. package/src/{ui → frontend}/components/SessionSpinner.js +3 -3
  30. package/src/{ui → frontend}/components/SetupWizard.js +8 -101
  31. package/src/{ui → frontend}/components/ToolApprovalPrompt.js +16 -14
  32. package/src/frontend/design/themeColors.js +42 -0
  33. package/src/{ui → frontend}/index.js +7 -7
  34. package/src/frontend/utils/inputBuffer.js +441 -0
  35. package/src/{ui/utils/markdownRenderer.js → frontend/utils/markdownParser.js} +3 -3
  36. package/src/{ui/utils/ConsolePatcher.js → frontend/utils/outputRedirector.js} +9 -9
  37. package/src/{ui/utils/codeColorizer.js → frontend/utils/syntaxHighlighter.js} +2 -3
  38. package/src/system/ai_request.js +145 -595
  39. package/src/system/code_executer.js +111 -16
  40. package/src/system/file_integrity.js +5 -7
  41. package/src/system/log.js +3 -3
  42. package/src/system/mcp_integration.js +15 -13
  43. package/src/system/output_helper.js +0 -20
  44. package/src/system/session.js +97 -23
  45. package/src/system/session_memory.js +2 -82
  46. package/src/system/system_info.js +1 -1
  47. package/src/system/ui_events.js +0 -43
  48. package/src/tools/code_editor.js +17 -2
  49. package/src/tools/file_reader.js +17 -2
  50. package/src/tools/glob.js +9 -1
  51. package/src/tools/response_message.js +0 -2
  52. package/src/tools/ripgrep.js +9 -1
  53. package/src/tools/web_downloader.js +9 -1
  54. package/src/util/config.js +3 -8
  55. package/src/util/debug_log.js +4 -11
  56. package/src/util/mcp_config_manager.js +3 -5
  57. package/src/util/output_formatter.js +0 -47
  58. package/src/util/prompt_loader.js +3 -4
  59. package/src/util/safe_fs.js +60 -0
  60. package/src/util/setup_wizard.js +1 -3
  61. package/src/util/text_formatter.js +0 -86
  62. package/src/config/claude_models.js +0 -195
  63. package/src/ui/README.md +0 -208
  64. package/src/ui/api.js +0 -167
  65. package/src/ui/components/AgenticProgressDisplay.js +0 -126
  66. package/src/ui/components/Composer.js +0 -55
  67. package/src/ui/components/LoadingIndicator.js +0 -54
  68. package/src/ui/components/ModelListView.js +0 -214
  69. package/src/ui/components/Notifications.js +0 -55
  70. package/src/ui/components/StreamingIndicator.js +0 -36
  71. package/src/ui/contexts/AppContext.js +0 -25
  72. package/src/ui/contexts/StreamingContext.js +0 -20
  73. package/src/ui/contexts/UIStateContext.js +0 -117
  74. package/src/ui/example-usage.js +0 -180
  75. package/src/ui/hooks/useTerminalResize.js +0 -39
  76. package/src/ui/themes/semantic-tokens.js +0 -73
  77. package/src/ui/utils/text-buffer.js +0 -975
  78. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_buildManifest.js +0 -0
  79. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_clientMiddlewareManifest.json +0 -0
  80. /package/payload_viewer/out/_next/static/{t0WTsjXST7ISD1Boa6ifx → 7FgHZugvVp3pn1XStUYUJ}/_ssgManifest.js +0 -0
  81. /package/src/{ui → frontend}/components/BlankLine.js +0 -0
  82. /package/src/{ui → frontend}/components/FileDiffViewer.js +0 -0
  83. /package/src/{ui → frontend}/components/HelpView.js +0 -0
  84. /package/src/{ui → frontend}/hooks/useCompletion.js +0 -0
  85. /package/src/{ui → frontend}/hooks/useKeypress.js +0 -0
  86. /package/src/{ui → frontend}/utils/diffUtils.js +0 -0
  87. /package/src/{ui → frontend}/utils/renderInkComponent.js +0 -0
@@ -3,7 +3,6 @@ import { homedir } from 'os';
3
3
  import { join, dirname } from 'path';
4
4
  import { safeReadFile, safeWriteFile, safeMkdir, safeReaddir, safeStat, safeCopyFile } from './safe_fs.js';
5
5
  import { fileURLToPath } from 'url';
6
- import { DEFAULT_CLAUDE_MODEL } from '../config/claude_models.js';
7
6
  import { DEFAULT_OPENAI_MODEL } from '../config/openai_models.js';
8
7
 
9
8
  // Get project root directory (this file is in src/util/, so go up 2 levels)
@@ -11,7 +10,6 @@ const __filename = fileURLToPath(import.meta.url);
11
10
  const __dirname = dirname(__filename);
12
11
  const PROJECT_ROOT = join(__dirname, '..', '..');
13
12
 
14
- function consolelog() { }
15
13
  /**
16
14
  * 홈 디렉토리 경로를 반환
17
15
  * @returns {string} 홈 디렉토리 경로
@@ -43,12 +41,9 @@ export const PAYLOAD_LOG_DIR = join(CONFIG_DIR, 'payload_log');
43
41
  export const DEBUG_LOG_DIR = join(CONFIG_DIR, 'debuglog');
44
42
  export const DEBUG_LOG_FILE = join(CONFIG_DIR, 'debug.txt'); // Deprecated: 호환성을 위해 유지
45
43
  const DEFAULT_SETTINGS = {
46
- AI_PROVIDER: 'openai', // 'openai' or 'anthropic'
47
44
  OPENAI_API_KEY: '',
48
45
  OPENAI_MODEL: DEFAULT_OPENAI_MODEL,
49
46
  OPENAI_REASONING_EFFORT: 'medium', // 'minimal', 'low', 'medium', 'high'
50
- ANTHROPIC_API_KEY: '',
51
- ANTHROPIC_MODEL: DEFAULT_CLAUDE_MODEL,
52
47
  // 도구 활성화 옵션
53
48
  TOOLS_ENABLED: {
54
49
  edit_file_range: false, // 기본적으로 비활성화 (edit_file_replace 사용 권장)
@@ -89,7 +84,7 @@ export async function ensureConfigDirectory() {
89
84
  })
90
85
  );
91
86
  } catch (error) {
92
- consolelog(`Failed to ensure config directory at ${CONFIG_DIR}:`, error);
87
+ // Failed to ensure config directory - silently ignore
93
88
  throw error;
94
89
  }
95
90
  }
@@ -112,7 +107,7 @@ export async function loadSettings() {
112
107
  await safeWriteFile(SETTINGS_FILE, JSON.stringify(DEFAULT_SETTINGS, null, 2), 'utf8');
113
108
  return { ...DEFAULT_SETTINGS };
114
109
  }
115
- consolelog(`Failed to load settings from ${SETTINGS_FILE}:`, error);
110
+ // Failed to load settings - silently ignore
116
111
  return { ...DEFAULT_SETTINGS };
117
112
  }
118
113
  }
@@ -127,7 +122,7 @@ export async function saveSettings(settings) {
127
122
  try {
128
123
  await safeWriteFile(SETTINGS_FILE, JSON.stringify(settings, null, 2), 'utf8');
129
124
  } catch (error) {
130
- consolelog(`Failed to save settings to ${SETTINGS_FILE}:`, error);
125
+ // Failed to save settings - silently ignore
131
126
  throw error;
132
127
  }
133
128
  }
@@ -5,7 +5,7 @@
5
5
 
6
6
  import { DEBUG_LOG_DIR } from './config.js';
7
7
  import { join, dirname } from 'path';
8
- import { safeMkdir, safeAppendFile } from './safe_fs.js';
8
+ import { safeMkdirSync, safeAppendFileSync } from './safe_fs.js';
9
9
 
10
10
  /**
11
11
  * 디버그 로그를 파일에 기록합니다.
@@ -24,16 +24,9 @@ export function debugLog(logFileName, context, message) {
24
24
  ? `[${timestamp}] [${context}] ${message}\n`
25
25
  : `[${timestamp}] ${message}\n`;
26
26
 
27
- // 디렉토리 생성 및 로그 쓰기를 비동기로 처리
28
- setImmediate(async () => {
29
- try {
30
- // 디렉토리가 없으면 생성 (recursive: true 이므로 이미 존재해도 에러 없음)
31
- await safeMkdir(logDir, { recursive: true });
32
- await safeAppendFile(LOG_FILE, logMessage);
33
- } catch (err) {
34
- // Ignore logging errors
35
- }
36
- });
27
+ // 디렉토리 생성 및 로그 쓰기를 동기로 처리
28
+ safeMkdirSync(logDir, { recursive: true });
29
+ safeAppendFileSync(LOG_FILE, logMessage);
37
30
  } catch (err) {
38
31
  // Ignore logging errors
39
32
  }
@@ -4,8 +4,6 @@ import { join } from 'path';
4
4
  import { createHash } from 'crypto';
5
5
  import { CONFIG_DIR } from './config.js';
6
6
 
7
- function consolelog() { }
8
-
9
7
  /**
10
8
  * MCP 설정 파일 경로 반환 (전역 사용자 설정)
11
9
  * @returns {string} 설정 파일 경로
@@ -25,14 +23,14 @@ export async function loadMergedMcpConfig() {
25
23
  const data = await safeReadFile(path, 'utf8');
26
24
  const config = JSON.parse(data);
27
25
 
28
- consolelog(`Loaded MCP config from ${path}`);
26
+ // Loaded MCP config - silently
29
27
  return config.mcpServers || {};
30
28
  } catch (error) {
31
29
  // 파일이 없으면 빈 객체 반환
32
30
  if (error.message && error.message.includes('Failed to read file')) {
33
31
  return {};
34
32
  }
35
- consolelog(`Warning: Failed to load MCP config: ${error.message}`);
33
+ // Failed to load MCP config - silently ignore
36
34
  return {};
37
35
  }
38
36
  }
@@ -83,7 +81,7 @@ export async function saveMcpConfig(servers) {
83
81
  };
84
82
 
85
83
  await safeWriteFile(path, JSON.stringify(config, null, 2), 'utf8');
86
- consolelog(`Saved MCP config to ${path}`);
84
+ // Saved MCP config - silently
87
85
  return path;
88
86
  }
89
87
 
@@ -20,15 +20,6 @@ export function clampOutput(text) {
20
20
  return text;
21
21
  }
22
22
 
23
- /**
24
- * 응답 메시지 포맷팅
25
- * @param {Object} result - 응답 메시지 결과
26
- * @returns {string} 포맷된 메시지
27
- */
28
- export function formatResponseMessageStdout(result) {
29
- return result.message || '';
30
- }
31
-
32
23
  /**
33
24
  * 파일 읽기 결과에 줄 번호 추가
34
25
  * @param {Object} result - 파일 읽기 실행 결과
@@ -44,38 +35,6 @@ export function formatReadFileStdout(result) {
44
35
  return stdout;
45
36
  }
46
37
 
47
- /**
48
- * 특정 줄 읽기 결과 포맷팅
49
- * @param {Object} result - 파일 줄 읽기 실행 결과
50
- * @returns {string} 줄 번호와 내용
51
- */
52
- export function formatReadFileLinesStdout(result) {
53
- let stdout = '';
54
- if (result.file_lines) {
55
- result.file_lines.map((line) => {
56
- stdout += `${line.line_number}|${line.line_content}\n`;
57
- });
58
- }
59
- return stdout;
60
- }
61
-
62
- /**
63
- * 디렉토리 목록을 DIR/FILE 형식으로 표시
64
- * @param {Object} result - 디렉토리 목록 실행 결과
65
- * @returns {string} 포맷된 디렉토리 목록
66
- */
67
- export function formatListDirectoryStdout(result) {
68
- let stdout = '';
69
- if (result.directory_contents) {
70
- result.directory_contents.forEach((item) => {
71
- const typeLabel = item.is_directory ? 'DIR' : 'FILE';
72
- const size = item.is_directory ? '' : ` (${item.size_bytes} bytes)`;
73
- stdout += `${typeLabel}: ${item.name}${size}\n`;
74
- });
75
- }
76
- return stdout;
77
- }
78
-
79
38
  /**
80
39
  * operation 타입별로 적절한 포맷터 선택
81
40
  * @param {string} operation - 도구 작업 타입
@@ -84,14 +43,8 @@ export function formatListDirectoryStdout(result) {
84
43
  */
85
44
  export function formatToolStdout(operation, result) {
86
45
  switch (operation) {
87
- case 'response_message':
88
- return formatResponseMessageStdout(result);
89
46
  case 'read_file':
90
47
  return formatReadFileStdout(result);
91
- case 'read_file_lines':
92
- return formatReadFileLinesStdout(result);
93
- case 'list_directory':
94
- return formatListDirectoryStdout(result);
95
48
  default:
96
49
  return JSON.stringify(result, null, 2);
97
50
  }
@@ -4,7 +4,6 @@ import { fileURLToPath } from "url";
4
4
 
5
5
  const moduleDirname = dirname(fileURLToPath(import.meta.url));
6
6
  const defaultProjectRoot = dirname(dirname(moduleDirname));
7
- function consolelog() { }
8
7
 
9
8
  /**
10
9
  * 프로젝트 루트 경로를 반환합니다.
@@ -24,7 +23,7 @@ async function loadSystemPrompt(promptPath) {
24
23
  const content = await safeReadFile(promptPath, "utf8");
25
24
  return content.trim();
26
25
  } catch (error) {
27
- consolelog(`Failed to load system prompt from ${promptPath}:`, error);
26
+ // Failed to load system prompt - return empty
28
27
  return '';
29
28
  }
30
29
  }
@@ -53,13 +52,13 @@ async function loadPromptFromPromptsDir(promptFileName) {
53
52
  // 우선순위 1: CWD/.aiexe/prompts/ (프로젝트별 커스텀 프롬프트)
54
53
  const cwdPromptPath = join(process.cwd(), ".aiexe", "prompts", promptFileName);
55
54
  if (await fileExists(cwdPromptPath)) {
56
- consolelog(`Loading prompt from project-specific path: ${cwdPromptPath}`);
55
+ // Loading prompt from project-specific path
57
56
  return await loadSystemPrompt(cwdPromptPath);
58
57
  }
59
58
 
60
59
  // 우선순위 2: 프로젝트루트/prompts/ (기본 프롬프트)
61
60
  const defaultPromptPath = join(getProjectRoot(), "prompts", promptFileName);
62
- consolelog(`Loading prompt from default path: ${defaultPromptPath}`);
61
+ // Loading prompt from default path
63
62
  return await loadSystemPrompt(defaultPromptPath);
64
63
  }
65
64
 
@@ -520,3 +520,63 @@ export async function safeAppendFile(filePath, data, encoding = 'utf8') {
520
520
  throw new Error(errorMsg);
521
521
  }
522
522
  }
523
+
524
+ // ============================================================
525
+ // 동기 작업 (Synchronous operations)
526
+ // ============================================================
527
+
528
+ import { mkdirSync, appendFileSync } from 'fs';
529
+
530
+ /**
531
+ * 디렉토리 생성 (동기)
532
+ * @param {string} dirPath - 생성할 디렉토리 경로
533
+ * @param {Object} options - 추가 옵션
534
+ * @param {boolean} options.recursive - 재귀적으로 생성 여부
535
+ * @returns {string|undefined}
536
+ */
537
+ export function safeMkdirSync(dirPath, options = {}) {
538
+ const absolutePath = toAbsolutePath(dirPath);
539
+
540
+ if (!validatePath(absolutePath)) {
541
+ throw new Error(`Invalid directory path: ${dirPath}`);
542
+ }
543
+
544
+ if (isProtectedPath(absolutePath)) {
545
+ throw new Error(`Protected path cannot be modified: ${absolutePath}`);
546
+ }
547
+
548
+ try {
549
+ return mkdirSync(absolutePath, options);
550
+ } catch (error) {
551
+ // recursive: true 일 때 이미 존재하는 디렉토리는 에러가 아님
552
+ if (error.code === 'EEXIST' && options.recursive) {
553
+ return;
554
+ }
555
+ throw new Error(`Failed to create directory ${absolutePath}: ${error.message}`);
556
+ }
557
+ }
558
+
559
+ /**
560
+ * 파일에 내용 추가 (동기)
561
+ * @param {string} filePath - 파일 경로
562
+ * @param {string|Buffer} data - 추가할 데이터
563
+ * @param {string} encoding - 인코딩 (기본값: 'utf8')
564
+ * @returns {void}
565
+ */
566
+ export function safeAppendFileSync(filePath, data, encoding = 'utf8') {
567
+ const absolutePath = toAbsolutePath(filePath);
568
+
569
+ if (!validatePath(absolutePath)) {
570
+ throw new Error(`Invalid file path: ${filePath}`);
571
+ }
572
+
573
+ if (isProtectedPath(absolutePath)) {
574
+ throw new Error(`Protected path cannot be modified: ${absolutePath}`);
575
+ }
576
+
577
+ try {
578
+ return appendFileSync(absolutePath, data, encoding);
579
+ } catch (error) {
580
+ throw new Error(`Failed to append to file ${absolutePath}: ${error.message}`);
581
+ }
582
+ }
@@ -1,7 +1,7 @@
1
1
  // 초기 설정 마법사 - 사용자에게 API 키 및 모델 설정을 안내합니다.
2
2
  import React from 'react';
3
3
  import { render } from 'ink';
4
- import { SetupWizard } from '../ui/components/SetupWizard.js';
4
+ import { SetupWizard } from '../frontend/components/SetupWizard.js';
5
5
  import { loadSettings, saveSettings, SETTINGS_FILE } from './config.js';
6
6
  import chalk from 'chalk';
7
7
 
@@ -61,8 +61,6 @@ export async function isConfigured() {
61
61
 
62
62
  if (settings.AI_PROVIDER === 'openai') {
63
63
  return Boolean(settings.OPENAI_API_KEY && settings.OPENAI_API_KEY.trim());
64
- } else if (settings.AI_PROVIDER === 'anthropic') {
65
- return Boolean(settings.ANTHROPIC_API_KEY && settings.ANTHROPIC_API_KEY.trim());
66
64
  }
67
65
 
68
66
  return false;
@@ -1,91 +1,5 @@
1
1
  // 문자열 및 텍스트 포맷팅 유틸리티
2
2
 
3
- /**
4
- * 텍스트 줄에 들여쓰기 추가
5
- * @param {string} content - 원본 내용
6
- * @param {number} indentLevel - 들여쓰기 레벨 (기본값: 0)
7
- * @returns {string} 들여쓰기가 적용된 내용
8
- */
9
- export function indentLines(content, indentLevel = 0) {
10
- return content.split('\n').map(line => ' '.repeat(indentLevel) + line).join('\n');
11
- }
12
-
13
- /**
14
- * JSON 객체를 XML 형식으로 변환
15
- * @param {Object|string} json - 변환할 JSON 객체
16
- * @param {number} indentLevel - 들여쓰기 레벨 (기본값: 0)
17
- * @returns {string} XML 형식 문자열
18
- */
19
- export function tagify(json, indentLevel = 0) {
20
- if (!json) return '';
21
-
22
- if (typeof json === 'string') {
23
- return indentLines(json, indentLevel);
24
- }
25
-
26
- if (json.tagname) {
27
- let openTag = `<${json.tagname}`;
28
-
29
- if (json.attr && typeof json.attr === 'object') {
30
- for (const [key, value] of Object.entries(json.attr)) {
31
- openTag += ` ${key}="${value}"`;
32
- }
33
- }
34
-
35
- openTag += '>';
36
- const closeTag = `</${json.tagname}>`;
37
-
38
- let result = indentLines(openTag, indentLevel) + '\n';
39
-
40
- if (json.children && Array.isArray(json.children)) {
41
- for (const child of json.children) {
42
- result += tagify(child, indentLevel + 1) + '\n';
43
- }
44
- }
45
-
46
- result += indentLines(closeTag, indentLevel);
47
- return result;
48
- }
49
-
50
- if (json.content) {
51
- return indentLines(json.content, indentLevel);
52
- }
53
-
54
- return '';
55
- }
56
-
57
- /**
58
- * 문자열을 안전한 펜스 코드 블록으로 감싸는 함수
59
- * @param {string} content - 감쌀 내용
60
- * @param {string} fencedName - 코드 블록 언어 이름
61
- * @returns {string} 펜스 코드 블록으로 감싼 문자열
62
- */
63
- export function wrapWithSafeFence(content, fencedName) {
64
- // 내용 내의 최대 연속 백틱 개수 찾기
65
- let maxConsecutiveTicks = 0;
66
- let currentTicks = 0;
67
-
68
- for (let i = 0; i < content.length; i++) {
69
- if (content[i] === '`') {
70
- currentTicks++;
71
- } else {
72
- if (currentTicks > maxConsecutiveTicks) {
73
- maxConsecutiveTicks = currentTicks;
74
- }
75
- currentTicks = 0;
76
- }
77
- }
78
- // 마지막 연속 백틱도 확인
79
- if (currentTicks > maxConsecutiveTicks) {
80
- maxConsecutiveTicks = currentTicks;
81
- }
82
-
83
- // 기존 최대값보다 1개 더 많은 백틱으로 감싸기 (최소 3개)
84
- const fenceLength = Math.max(3, maxConsecutiveTicks + 1);
85
- const fence = '`'.repeat(fenceLength);
86
- return `${fence}\n${fencedName}\n${indentLines(content, 1)}\n${fence}`;
87
- }
88
-
89
3
  /**
90
4
  * 긴 텍스트를 제한하고 생략 표시를 추가하는 함수
91
5
  * @param {string} text - 원본 텍스트
@@ -1,195 +0,0 @@
1
- /**
2
- * Anthropic Claude 모델 설정
3
- *
4
- * 모든 Claude 모델 정보를 중앙 집중식으로 관리합니다.
5
- * 새 모델 추가 시 이 파일만 수정하면 됩니다.
6
- *
7
- * 참고: https://docs.anthropic.com/en/docs/about-claude/models/overview
8
- */
9
-
10
- export const CLAUDE_MODELS = {
11
- // ========================================
12
- // Claude 4.x 시리즈 (최신)
13
- // ========================================
14
- 'claude-sonnet-4-5-20250929': {
15
- name: 'Claude Sonnet 4.5',
16
- description: 'Best model for complex agents and coding (recommended)',
17
- contextWindow: 200000, // 200K (베타: 1M)
18
- maxTokens: 64000, // 64K
19
- pricing: {
20
- input: 3, // $3 per million tokens
21
- output: 15 // $15 per million tokens
22
- },
23
- speed: 'fast',
24
- knowledgeCutoff: '2025-01',
25
- trainingDataCutoff: '2025-07'
26
- },
27
- 'claude-sonnet-4-20250514': {
28
- name: 'Claude Sonnet 4',
29
- description: 'High-performance model',
30
- contextWindow: 200000, // 200K (베타: 1M)
31
- maxTokens: 64000, // 64K
32
- pricing: {
33
- input: 3,
34
- output: 15
35
- },
36
- speed: 'fast',
37
- knowledgeCutoff: '2025-01',
38
- trainingDataCutoff: '2025-07'
39
- },
40
- 'claude-opus-4-1-20250805': {
41
- name: 'Claude Opus 4.1',
42
- description: 'Exceptional model for specialized complex tasks',
43
- contextWindow: 200000, // 200K
44
- maxTokens: 32000, // 32K
45
- pricing: {
46
- input: 15, // $15 per million tokens
47
- output: 75 // $75 per million tokens
48
- },
49
- speed: 'moderate',
50
- knowledgeCutoff: '2025-01',
51
- trainingDataCutoff: '2025-03'
52
- },
53
- 'claude-opus-4-20250514': {
54
- name: 'Claude Opus 4',
55
- description: 'Previous flagship model (very high intelligence)',
56
- contextWindow: 200000, // 200K
57
- maxTokens: 32000, // 32K
58
- pricing: {
59
- input: 15,
60
- output: 75
61
- },
62
- speed: 'moderate',
63
- knowledgeCutoff: '2025-01',
64
- trainingDataCutoff: '2025-03'
65
- },
66
- 'claude-haiku-4-5-20251001': {
67
- name: 'Claude Haiku 4.5',
68
- description: 'Fastest and most intelligent Haiku model (extended thinking support)',
69
- contextWindow: 200000, // 200K
70
- maxTokens: 64000, // 64K
71
- pricing: {
72
- input: 1, // $1 per million tokens
73
- output: 5 // $5 per million tokens
74
- },
75
- speed: 'fastest',
76
- knowledgeCutoff: '2025-02',
77
- trainingDataCutoff: '2025-07'
78
- },
79
-
80
- // ========================================
81
- // Claude 3.x 시리즈
82
- // ========================================
83
- 'claude-3-7-sonnet-20250219': {
84
- name: 'Claude Sonnet 3.7',
85
- description: 'High-performance model with extended thinking support',
86
- contextWindow: 200000, // 200K
87
- maxTokens: 64000, // 64K (베타: 128K)
88
- pricing: {
89
- input: 3,
90
- output: 15
91
- },
92
- speed: 'fast',
93
- knowledgeCutoff: '2025-01',
94
- trainingDataCutoff: '2025-07'
95
- },
96
- 'claude-3-5-sonnet-20241022': {
97
- name: 'Claude 3.5 Sonnet',
98
- description: 'Proven model with balanced performance',
99
- contextWindow: 200000, // 200K
100
- maxTokens: 8192, // 8K
101
- pricing: {
102
- input: 3,
103
- output: 15
104
- },
105
- speed: 'fast',
106
- knowledgeCutoff: '2024-04',
107
- trainingDataCutoff: '2024-04'
108
- },
109
- 'claude-3-5-haiku-20241022': {
110
- name: 'Claude 3.5 Haiku',
111
- description: 'Very fast response speed',
112
- contextWindow: 200000, // 200K
113
- maxTokens: 8192, // 8K
114
- pricing: {
115
- input: 1,
116
- output: 5
117
- },
118
- speed: 'fastest',
119
- knowledgeCutoff: '2024-07',
120
- trainingDataCutoff: '2024-07'
121
- },
122
- 'claude-3-haiku-20240307': {
123
- name: 'Claude 3 Haiku',
124
- description: 'Fast and concise responses',
125
- contextWindow: 200000, // 200K
126
- maxTokens: 4096, // 4K
127
- pricing: {
128
- input: 0.25,
129
- output: 1.25
130
- },
131
- speed: 'very-fast',
132
- knowledgeCutoff: '2023-08',
133
- trainingDataCutoff: '2023-08'
134
- }
135
- };
136
-
137
- /**
138
- * 모델 ID로 모델 정보 가져오기
139
- */
140
- export function getClaudeModelInfo(modelId) {
141
- return CLAUDE_MODELS[modelId] || null;
142
- }
143
-
144
- /**
145
- * 모델 ID로 max_tokens 가져오기
146
- */
147
- export function getClaudeMaxTokens(modelId) {
148
- const model = CLAUDE_MODELS[modelId];
149
- return model ? model.maxTokens : 8192; // 기본값 8K
150
- }
151
-
152
- /**
153
- * 모델 ID로 context window 크기 가져오기
154
- */
155
- export function getClaudeContextWindow(modelId) {
156
- const model = CLAUDE_MODELS[modelId];
157
- return model ? model.contextWindow : 200000; // 기본값 200K
158
- }
159
-
160
- /**
161
- * 모든 Claude 모델 ID 목록 가져오기
162
- */
163
- export function getAllClaudeModelIds() {
164
- return Object.keys(CLAUDE_MODELS);
165
- }
166
-
167
- /**
168
- * Claude 4.x 시리즈 모델 ID 목록
169
- */
170
- export function getClaude4Models() {
171
- return [
172
- 'claude-sonnet-4-5-20250929',
173
- 'claude-sonnet-4-20250514',
174
- 'claude-opus-4-1-20250805',
175
- 'claude-opus-4-20250514',
176
- 'claude-haiku-4-5-20251001'
177
- ];
178
- }
179
-
180
- /**
181
- * Claude 3.x 시리즈 모델 ID 목록
182
- */
183
- export function getClaude3Models() {
184
- return [
185
- 'claude-3-7-sonnet-20250219',
186
- 'claude-3-5-sonnet-20241022',
187
- 'claude-3-5-haiku-20241022',
188
- 'claude-3-haiku-20240307'
189
- ];
190
- }
191
-
192
- /**
193
- * 기본 권장 Claude 모델 ID
194
- */
195
- export const DEFAULT_CLAUDE_MODEL = 'claude-sonnet-4-5-20250929';