@su-record/vibe 2.5.12 → 2.5.13
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.
- package/commands/vibe.analyze.md +3 -3
- package/commands/vibe.review.md +3 -3
- package/commands/vibe.run.md +75 -9
- package/commands/vibe.spec.md +7 -7
- package/commands/vibe.utils.md +62 -5
- package/dist/cli/setup/GlobalInstaller.d.ts +24 -0
- package/dist/cli/setup/GlobalInstaller.d.ts.map +1 -0
- package/dist/cli/setup/GlobalInstaller.js +130 -0
- package/dist/cli/setup/GlobalInstaller.js.map +1 -0
- package/dist/cli/setup/LanguageDetector.d.ts +16 -0
- package/dist/cli/setup/LanguageDetector.d.ts.map +1 -0
- package/dist/cli/setup/LanguageDetector.js +49 -0
- package/dist/cli/setup/LanguageDetector.js.map +1 -0
- package/dist/cli/setup/LegacyMigration.d.ts +25 -0
- package/dist/cli/setup/LegacyMigration.d.ts.map +1 -0
- package/dist/cli/setup/LegacyMigration.js +162 -0
- package/dist/cli/setup/LegacyMigration.js.map +1 -0
- package/dist/cli/setup/ProjectSetup.d.ts +30 -0
- package/dist/cli/setup/ProjectSetup.d.ts.map +1 -0
- package/dist/cli/setup/ProjectSetup.js +238 -0
- package/dist/cli/setup/ProjectSetup.js.map +1 -0
- package/dist/cli/setup/index.d.ts +14 -0
- package/dist/cli/setup/index.d.ts.map +1 -0
- package/dist/cli/setup/index.js +18 -0
- package/dist/cli/setup/index.js.map +1 -0
- package/dist/cli/setup.d.ts +10 -77
- package/dist/cli/setup.d.ts.map +1 -1
- package/dist/cli/setup.js +15 -592
- package/dist/cli/setup.js.map +1 -1
- package/dist/lib/llm/auth/ApiKeyManager.d.ts +21 -0
- package/dist/lib/llm/auth/ApiKeyManager.d.ts.map +1 -0
- package/dist/lib/llm/auth/ApiKeyManager.js +43 -0
- package/dist/lib/llm/auth/ApiKeyManager.js.map +1 -0
- package/dist/lib/llm/auth/ConfigManager.d.ts +29 -0
- package/dist/lib/llm/auth/ConfigManager.d.ts.map +1 -0
- package/dist/lib/llm/auth/ConfigManager.js +67 -0
- package/dist/lib/llm/auth/ConfigManager.js.map +1 -0
- package/dist/lib/llm/auth/index.d.ts +25 -0
- package/dist/lib/llm/auth/index.d.ts.map +1 -0
- package/dist/lib/llm/auth/index.js +83 -0
- package/dist/lib/llm/auth/index.js.map +1 -0
- package/dist/lib/llm/index.d.ts +10 -0
- package/dist/lib/llm/index.d.ts.map +1 -0
- package/dist/lib/llm/index.js +12 -0
- package/dist/lib/llm/index.js.map +1 -0
- package/dist/lib/llm/types.d.ts +96 -0
- package/dist/lib/llm/types.d.ts.map +1 -0
- package/dist/lib/llm/types.js +17 -0
- package/dist/lib/llm/types.js.map +1 -0
- package/dist/lib/llm/utils/index.d.ts +6 -0
- package/dist/lib/llm/utils/index.d.ts.map +1 -0
- package/dist/lib/llm/utils/index.js +6 -0
- package/dist/lib/llm/utils/index.js.map +1 -0
- package/dist/lib/llm/utils/retry.d.ts +25 -0
- package/dist/lib/llm/utils/retry.d.ts.map +1 -0
- package/dist/lib/llm/utils/retry.js +72 -0
- package/dist/lib/llm/utils/retry.js.map +1 -0
- package/dist/lib/llm/utils/stream.d.ts +13 -0
- package/dist/lib/llm/utils/stream.d.ts.map +1 -0
- package/dist/lib/llm/utils/stream.js +110 -0
- package/dist/lib/llm/utils/stream.js.map +1 -0
- package/dist/orchestrator/AgentExecutor.d.ts +23 -0
- package/dist/orchestrator/AgentExecutor.d.ts.map +1 -0
- package/dist/orchestrator/AgentExecutor.js +231 -0
- package/dist/orchestrator/AgentExecutor.js.map +1 -0
- package/dist/orchestrator/AgentManager.d.ts +73 -0
- package/dist/orchestrator/AgentManager.d.ts.map +1 -0
- package/dist/orchestrator/AgentManager.js +184 -0
- package/dist/orchestrator/AgentManager.js.map +1 -0
- package/dist/orchestrator/LLMCluster.d.ts +70 -0
- package/dist/orchestrator/LLMCluster.d.ts.map +1 -0
- package/dist/orchestrator/LLMCluster.js +91 -0
- package/dist/orchestrator/LLMCluster.js.map +1 -0
- package/dist/orchestrator/MultiLlmResearch.d.ts +27 -0
- package/dist/orchestrator/MultiLlmResearch.d.ts.map +1 -0
- package/dist/orchestrator/MultiLlmResearch.js +145 -0
- package/dist/orchestrator/MultiLlmResearch.js.map +1 -0
- package/dist/orchestrator/SessionStore.d.ts +41 -0
- package/dist/orchestrator/SessionStore.d.ts.map +1 -0
- package/dist/orchestrator/SessionStore.js +117 -0
- package/dist/orchestrator/SessionStore.js.map +1 -0
- package/dist/orchestrator/SmartRouter.d.ts +68 -0
- package/dist/orchestrator/SmartRouter.d.ts.map +1 -0
- package/dist/orchestrator/SmartRouter.js +256 -0
- package/dist/orchestrator/SmartRouter.js.map +1 -0
- package/dist/orchestrator/backgroundAgent.d.ts +10 -27
- package/dist/orchestrator/backgroundAgent.d.ts.map +1 -1
- package/dist/orchestrator/backgroundAgent.js +11 -345
- package/dist/orchestrator/backgroundAgent.js.map +1 -1
- package/dist/orchestrator/index.d.ts +3 -0
- package/dist/orchestrator/index.d.ts.map +1 -1
- package/dist/orchestrator/index.js +4 -0
- package/dist/orchestrator/index.js.map +1 -1
- package/dist/orchestrator/orchestrator.d.ts +19 -154
- package/dist/orchestrator/orchestrator.d.ts.map +1 -1
- package/dist/orchestrator/orchestrator.js +90 -514
- package/dist/orchestrator/orchestrator.js.map +1 -1
- package/dist/orchestrator/parallelResearch.d.ts +5 -12
- package/dist/orchestrator/parallelResearch.d.ts.map +1 -1
- package/dist/orchestrator/parallelResearch.js +10 -193
- package/dist/orchestrator/parallelResearch.js.map +1 -1
- package/hooks/scripts/generate-brand-assets.js +472 -0
- package/package.json +1 -1
- package/skills/brand-assets.md +141 -0
- package/skills/commerce-patterns.md +361 -0
- package/skills/e2e-commerce.md +304 -0
- package/skills/frontend-design.md +92 -0
- package/skills/seo-checklist.md +244 -0
|
@@ -0,0 +1,256 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* SmartRouter - LLM 스마트 라우팅 및 fallback 관리
|
|
3
|
+
* orchestrator.ts에서 추출된 라우팅 전용 모듈
|
|
4
|
+
*/
|
|
5
|
+
import { TASK_LLM_PRIORITY } from './types.js';
|
|
6
|
+
import * as gptApi from '../lib/gpt-api.js';
|
|
7
|
+
import * as geminiApi from '../lib/gemini-api.js';
|
|
8
|
+
import { debugLog } from '../lib/utils.js';
|
|
9
|
+
// LLM 가용성 캐시 (5분 TTL)
|
|
10
|
+
const LLM_CACHE_TTL = 5 * 60 * 1000;
|
|
11
|
+
/**
|
|
12
|
+
* SmartRouter - Task 유형별 최적 LLM 선택 + fallback chain
|
|
13
|
+
*/
|
|
14
|
+
export class SmartRouter {
|
|
15
|
+
cache;
|
|
16
|
+
verbose;
|
|
17
|
+
constructor(options = {}) {
|
|
18
|
+
this.verbose = options.verbose ?? false;
|
|
19
|
+
this.cache = {
|
|
20
|
+
gpt: { available: true, checkedAt: 0, errorCount: 0 },
|
|
21
|
+
gemini: { available: true, checkedAt: 0, errorCount: 0 }
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* 스마트 라우팅 - 작업 유형에 따라 최적의 LLM 선택 + fallback
|
|
26
|
+
*/
|
|
27
|
+
async route(request) {
|
|
28
|
+
const startTime = Date.now();
|
|
29
|
+
const { type, prompt, systemPrompt = 'You are a helpful assistant.', preferredLlm, maxRetries = 2 } = request;
|
|
30
|
+
// LLM 우선순위 결정
|
|
31
|
+
const providers = this.getProviderPriority(type, preferredLlm);
|
|
32
|
+
const attemptedProviders = [];
|
|
33
|
+
const errors = {};
|
|
34
|
+
// 각 LLM 순차 시도 (fallback chain)
|
|
35
|
+
for (const provider of providers) {
|
|
36
|
+
if (this.isUnavailable(provider)) {
|
|
37
|
+
if (this.verbose) {
|
|
38
|
+
debugLog(`[SmartRouter] Skipping ${provider} (recently failed)`);
|
|
39
|
+
}
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
attemptedProviders.push(provider);
|
|
43
|
+
// 재시도 로직
|
|
44
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
45
|
+
try {
|
|
46
|
+
const content = await this.callLlm(provider, prompt, systemPrompt);
|
|
47
|
+
this.markAvailable(provider);
|
|
48
|
+
return {
|
|
49
|
+
content,
|
|
50
|
+
provider,
|
|
51
|
+
success: true,
|
|
52
|
+
usedFallback: attemptedProviders.length > 1,
|
|
53
|
+
attemptedProviders,
|
|
54
|
+
duration: Date.now() - startTime
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
catch (error) {
|
|
58
|
+
const errorMsg = error instanceof Error ? error.message : String(error);
|
|
59
|
+
errors[provider] = errorMsg;
|
|
60
|
+
if (this.verbose) {
|
|
61
|
+
debugLog(`[SmartRouter] ${provider} attempt ${attempt + 1} failed: ${errorMsg}`);
|
|
62
|
+
}
|
|
63
|
+
if (this.shouldSkipRetry(errorMsg)) {
|
|
64
|
+
this.markUnavailable(provider);
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
if (attempt < maxRetries) {
|
|
68
|
+
await this.delay(1000 * (attempt + 1));
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
this.markUnavailable(provider);
|
|
73
|
+
}
|
|
74
|
+
// 모든 외부 LLM 실패 - Claude fallback
|
|
75
|
+
return {
|
|
76
|
+
content: this.buildFallbackMessage(type, prompt, errors),
|
|
77
|
+
provider: 'claude',
|
|
78
|
+
success: true,
|
|
79
|
+
usedFallback: true,
|
|
80
|
+
attemptedProviders,
|
|
81
|
+
errors: errors,
|
|
82
|
+
duration: Date.now() - startTime
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* LLM 우선순위 결정
|
|
87
|
+
*/
|
|
88
|
+
getProviderPriority(type, preferredLlm) {
|
|
89
|
+
if (preferredLlm) {
|
|
90
|
+
const others = TASK_LLM_PRIORITY[type].filter(p => p !== preferredLlm);
|
|
91
|
+
return [preferredLlm, ...others];
|
|
92
|
+
}
|
|
93
|
+
return [...TASK_LLM_PRIORITY[type]];
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* LLM 호출
|
|
97
|
+
*/
|
|
98
|
+
async callLlm(provider, prompt, systemPrompt) {
|
|
99
|
+
switch (provider) {
|
|
100
|
+
case 'gpt':
|
|
101
|
+
return gptApi.vibeGptOrchestrate(prompt, systemPrompt, { jsonMode: false });
|
|
102
|
+
case 'gemini':
|
|
103
|
+
return geminiApi.vibeGeminiOrchestrate(prompt, systemPrompt, { jsonMode: false });
|
|
104
|
+
case 'claude':
|
|
105
|
+
throw new Error('Claude fallback - handled by caller');
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* 재시도 없이 즉시 다음 LLM으로 넘어가야 하는 에러
|
|
112
|
+
*/
|
|
113
|
+
shouldSkipRetry(errorMsg) {
|
|
114
|
+
const skipPatterns = [
|
|
115
|
+
'rate limit', 'quota', 'exhausted', '429', 'usage limit', 'too many requests',
|
|
116
|
+
'no token', 'token not set', 'no api key', 'api key not set',
|
|
117
|
+
'missing token', 'missing api key', 'not authenticated',
|
|
118
|
+
'authentication failed', 'unauthorized', '401', 'auth'
|
|
119
|
+
];
|
|
120
|
+
const lowerMsg = errorMsg.toLowerCase();
|
|
121
|
+
return skipPatterns.some(pattern => lowerMsg.includes(pattern));
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* LLM 가용성 확인 (캐시 기반)
|
|
125
|
+
*/
|
|
126
|
+
isUnavailable(provider) {
|
|
127
|
+
if (provider === 'claude')
|
|
128
|
+
return false;
|
|
129
|
+
const cache = this.cache[provider];
|
|
130
|
+
const now = Date.now();
|
|
131
|
+
if (now - cache.checkedAt > LLM_CACHE_TTL) {
|
|
132
|
+
cache.available = true;
|
|
133
|
+
cache.errorCount = 0;
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
return !cache.available || cache.errorCount >= 3;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* LLM 가용 상태로 마킹
|
|
140
|
+
*/
|
|
141
|
+
markAvailable(provider) {
|
|
142
|
+
if (provider === 'claude')
|
|
143
|
+
return;
|
|
144
|
+
this.cache[provider] = {
|
|
145
|
+
available: true,
|
|
146
|
+
checkedAt: Date.now(),
|
|
147
|
+
errorCount: 0
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
/**
|
|
151
|
+
* LLM 불가용 상태로 마킹
|
|
152
|
+
*/
|
|
153
|
+
markUnavailable(provider) {
|
|
154
|
+
if (provider === 'claude')
|
|
155
|
+
return;
|
|
156
|
+
const cache = this.cache[provider];
|
|
157
|
+
cache.errorCount++;
|
|
158
|
+
cache.checkedAt = Date.now();
|
|
159
|
+
if (cache.errorCount >= 3) {
|
|
160
|
+
cache.available = false;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Fallback 메시지 생성
|
|
165
|
+
*/
|
|
166
|
+
buildFallbackMessage(type, prompt, errors) {
|
|
167
|
+
const errorSummary = Object.entries(errors)
|
|
168
|
+
.map(([provider, msg]) => `- ${provider}: ${msg}`)
|
|
169
|
+
.join('\n');
|
|
170
|
+
return `[External LLM Unavailable - Claude Direct Handling]
|
|
171
|
+
|
|
172
|
+
All external LLMs failed. Claude should handle this ${type} task directly.
|
|
173
|
+
|
|
174
|
+
**Original Request:**
|
|
175
|
+
${prompt}
|
|
176
|
+
|
|
177
|
+
**Failed Providers:**
|
|
178
|
+
${errorSummary}
|
|
179
|
+
|
|
180
|
+
**Action Required:**
|
|
181
|
+
Claude, please handle this task using your own capabilities. Do NOT retry external LLMs.`;
|
|
182
|
+
}
|
|
183
|
+
delay(ms) {
|
|
184
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
185
|
+
}
|
|
186
|
+
// ============================================
|
|
187
|
+
// Convenience Methods (Smart* shortcuts)
|
|
188
|
+
// ============================================
|
|
189
|
+
async webSearch(query) {
|
|
190
|
+
return this.route({
|
|
191
|
+
type: 'web-search',
|
|
192
|
+
prompt: query,
|
|
193
|
+
systemPrompt: 'Search the web and provide relevant information.'
|
|
194
|
+
});
|
|
195
|
+
}
|
|
196
|
+
async architectureReview(prompt) {
|
|
197
|
+
return this.route({
|
|
198
|
+
type: 'architecture',
|
|
199
|
+
prompt,
|
|
200
|
+
systemPrompt: 'You are a software architect. Analyze and review the architecture.'
|
|
201
|
+
});
|
|
202
|
+
}
|
|
203
|
+
async uiuxReview(prompt) {
|
|
204
|
+
return this.route({
|
|
205
|
+
type: 'uiux',
|
|
206
|
+
prompt,
|
|
207
|
+
systemPrompt: 'You are a UI/UX expert. Analyze and provide feedback.'
|
|
208
|
+
});
|
|
209
|
+
}
|
|
210
|
+
async codeAnalysis(prompt) {
|
|
211
|
+
return this.route({
|
|
212
|
+
type: 'code-analysis',
|
|
213
|
+
prompt,
|
|
214
|
+
systemPrompt: 'You are a code analysis expert. Review and analyze the code.'
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
async debugging(prompt) {
|
|
218
|
+
return this.route({
|
|
219
|
+
type: 'debugging',
|
|
220
|
+
prompt,
|
|
221
|
+
systemPrompt: 'You are a debugging expert. Find bugs and suggest fixes.'
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
async codeGen(description, context) {
|
|
225
|
+
const prompt = context ? `${description}\n\nContext:\n${context}` : description;
|
|
226
|
+
return this.route({
|
|
227
|
+
type: 'code-gen',
|
|
228
|
+
prompt,
|
|
229
|
+
systemPrompt: 'Generate clean, well-documented code.'
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* 캐시 상태 조회 (디버깅용)
|
|
234
|
+
*/
|
|
235
|
+
getCacheStatus() {
|
|
236
|
+
return { ...this.cache };
|
|
237
|
+
}
|
|
238
|
+
/**
|
|
239
|
+
* 캐시 초기화
|
|
240
|
+
*/
|
|
241
|
+
resetCache() {
|
|
242
|
+
this.cache = {
|
|
243
|
+
gpt: { available: true, checkedAt: 0, errorCount: 0 },
|
|
244
|
+
gemini: { available: true, checkedAt: 0, errorCount: 0 }
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
// 싱글톤 인스턴스
|
|
249
|
+
let defaultRouter = null;
|
|
250
|
+
export function getSmartRouter(options) {
|
|
251
|
+
if (!defaultRouter || options) {
|
|
252
|
+
defaultRouter = new SmartRouter(options);
|
|
253
|
+
}
|
|
254
|
+
return defaultRouter;
|
|
255
|
+
}
|
|
256
|
+
//# sourceMappingURL=SmartRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SmartRouter.js","sourceRoot":"","sources":["../../src/orchestrator/SmartRouter.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAML,iBAAiB,EAClB,MAAM,YAAY,CAAC;AACpB,OAAO,KAAK,MAAM,MAAM,mBAAmB,CAAC;AAC5C,OAAO,KAAK,SAAS,MAAM,sBAAsB,CAAC;AAClD,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAE3C,sBAAsB;AACtB,MAAM,aAAa,GAAG,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC;AASpC;;GAEG;AACH,MAAM,OAAO,WAAW;IACd,KAAK,CAAuB;IAC5B,OAAO,CAAU;IAEzB,YAAY,UAA8B,EAAE;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAC;QACxC,IAAI,CAAC,KAAK,GAAG;YACX,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YACrD,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;SACzD,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,KAAK,CAAC,KAAK,CAAC,OAA0B;QACpC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,EACJ,IAAI,EACJ,MAAM,EACN,YAAY,GAAG,8BAA8B,EAC7C,YAAY,EACZ,UAAU,GAAG,CAAC,EACf,GAAG,OAAO,CAAC;QAEZ,cAAc;QACd,MAAM,SAAS,GAAG,IAAI,CAAC,mBAAmB,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;QAC/D,MAAM,kBAAkB,GAAkB,EAAE,CAAC;QAC7C,MAAM,MAAM,GAA2B,EAAE,CAAC;QAE1C,+BAA+B;QAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;YACjC,IAAI,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,CAAC;gBACjC,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;oBACjB,QAAQ,CAAC,0BAA0B,QAAQ,oBAAoB,CAAC,CAAC;gBACnE,CAAC;gBACD,SAAS;YACX,CAAC;YAED,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;YAElC,SAAS;YACT,KAAK,IAAI,OAAO,GAAG,CAAC,EAAE,OAAO,IAAI,UAAU,EAAE,OAAO,EAAE,EAAE,CAAC;gBACvD,IAAI,CAAC;oBACH,MAAM,OAAO,GAAG,MAAM,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,MAAM,EAAE,YAAY,CAAC,CAAC;oBACnE,IAAI,CAAC,aAAa,CAAC,QAAQ,CAAC,CAAC;oBAE7B,OAAO;wBACL,OAAO;wBACP,QAAQ;wBACR,OAAO,EAAE,IAAI;wBACb,YAAY,EAAE,kBAAkB,CAAC,MAAM,GAAG,CAAC;wBAC3C,kBAAkB;wBAClB,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;qBACjC,CAAC;gBACJ,CAAC;gBAAC,OAAO,KAAK,EAAE,CAAC;oBACf,MAAM,QAAQ,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;oBACxE,MAAM,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAC;oBAE5B,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;wBACjB,QAAQ,CAAC,iBAAiB,QAAQ,YAAY,OAAO,GAAG,CAAC,YAAY,QAAQ,EAAE,CAAC,CAAC;oBACnF,CAAC;oBAED,IAAI,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,EAAE,CAAC;wBACnC,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;wBAC/B,MAAM;oBACR,CAAC;oBAED,IAAI,OAAO,GAAG,UAAU,EAAE,CAAC;wBACzB,MAAM,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,OAAO,GAAG,CAAC,CAAC,CAAC,CAAC;oBACzC,CAAC;gBACH,CAAC;YACH,CAAC;YAED,IAAI,CAAC,eAAe,CAAC,QAAQ,CAAC,CAAC;QACjC,CAAC;QAED,iCAAiC;QACjC,OAAO;YACL,OAAO,EAAE,IAAI,CAAC,oBAAoB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,CAAC;YACxD,QAAQ,EAAE,QAAQ;YAClB,OAAO,EAAE,IAAI;YACb,YAAY,EAAE,IAAI;YAClB,kBAAkB;YAClB,MAAM,EAAE,MAAqC;YAC7C,QAAQ,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS;SACjC,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,mBAAmB,CAAC,IAAc,EAAE,YAA0B;QACpE,IAAI,YAAY,EAAE,CAAC;YACjB,MAAM,MAAM,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,KAAK,YAAY,CAAC,CAAC;YACvE,OAAO,CAAC,YAAY,EAAE,GAAG,MAAM,CAAC,CAAC;QACnC,CAAC;QACD,OAAO,CAAC,GAAG,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC;IACtC,CAAC;IAED;;OAEG;IACK,KAAK,CAAC,OAAO,CACnB,QAAqB,EACrB,MAAc,EACd,YAAoB;QAEpB,QAAQ,QAAQ,EAAE,CAAC;YACjB,KAAK,KAAK;gBACR,OAAO,MAAM,CAAC,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YAC9E,KAAK,QAAQ;gBACX,OAAO,SAAS,CAAC,qBAAqB,CAAC,MAAM,EAAE,YAAY,EAAE,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAC;YACpF,KAAK,QAAQ;gBACX,MAAM,IAAI,KAAK,CAAC,qCAAqC,CAAC,CAAC;YACzD;gBACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,QAAQ,EAAE,CAAC,CAAC;QACrD,CAAC;IACH,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,QAAgB;QACtC,MAAM,YAAY,GAAG;YACnB,YAAY,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,EAAE,aAAa,EAAE,mBAAmB;YAC7E,UAAU,EAAE,eAAe,EAAE,YAAY,EAAE,iBAAiB;YAC5D,eAAe,EAAE,iBAAiB,EAAE,mBAAmB;YACvD,uBAAuB,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM;SACvD,CAAC;QACF,MAAM,QAAQ,GAAG,QAAQ,CAAC,WAAW,EAAE,CAAC;QACxC,OAAO,YAAY,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC;IAClE,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,QAAqB;QACzC,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO,KAAK,CAAC;QAExC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAEvB,IAAI,GAAG,GAAG,KAAK,CAAC,SAAS,GAAG,aAAa,EAAE,CAAC;YAC1C,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC;YACvB,KAAK,CAAC,UAAU,GAAG,CAAC,CAAC;YACrB,OAAO,KAAK,CAAC;QACf,CAAC;QAED,OAAO,CAAC,KAAK,CAAC,SAAS,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,CAAC;IACnD,CAAC;IAED;;OAEG;IACK,aAAa,CAAC,QAAqB;QACzC,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAElC,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,GAAG;YACrB,SAAS,EAAE,IAAI;YACf,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE;YACrB,UAAU,EAAE,CAAC;SACd,CAAC;IACJ,CAAC;IAED;;OAEG;IACK,eAAe,CAAC,QAAqB;QAC3C,IAAI,QAAQ,KAAK,QAAQ;YAAE,OAAO;QAElC,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QACnC,KAAK,CAAC,UAAU,EAAE,CAAC;QACnB,KAAK,CAAC,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAE7B,IAAI,KAAK,CAAC,UAAU,IAAI,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,SAAS,GAAG,KAAK,CAAC;QAC1B,CAAC;IACH,CAAC;IAED;;OAEG;IACK,oBAAoB,CAC1B,IAAc,EACd,MAAc,EACd,MAA8B;QAE9B,MAAM,YAAY,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;aACxC,GAAG,CAAC,CAAC,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,EAAE,CAAC,KAAK,QAAQ,KAAK,GAAG,EAAE,CAAC;aACjD,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,OAAO;;sDAE2C,IAAI;;;EAGxD,MAAM;;;EAGN,YAAY;;;yFAG2E,CAAC;IACxF,CAAC;IAEO,KAAK,CAAC,EAAU;QACtB,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,EAAE,CAAC,CAAC,CAAC;IACzD,CAAC;IAED,+CAA+C;IAC/C,yCAAyC;IACzC,+CAA+C;IAE/C,KAAK,CAAC,SAAS,CAAC,KAAa;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,YAAY;YAClB,MAAM,EAAE,KAAK;YACb,YAAY,EAAE,kDAAkD;SACjE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,kBAAkB,CAAC,MAAc;QACrC,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,cAAc;YACpB,MAAM;YACN,YAAY,EAAE,oEAAoE;SACnF,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,UAAU,CAAC,MAAc;QAC7B,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,MAAM;YACZ,MAAM;YACN,YAAY,EAAE,uDAAuD;SACtE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,YAAY,CAAC,MAAc;QAC/B,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,eAAe;YACrB,MAAM;YACN,YAAY,EAAE,8DAA8D;SAC7E,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,SAAS,CAAC,MAAc;QAC5B,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,WAAW;YACjB,MAAM;YACN,YAAY,EAAE,0DAA0D;SACzE,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,OAAO,CAAC,WAAmB,EAAE,OAAgB;QACjD,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC,GAAG,WAAW,iBAAiB,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC;QAChF,OAAO,IAAI,CAAC,KAAK,CAAC;YAChB,IAAI,EAAE,UAAU;YAChB,MAAM;YACN,YAAY,EAAE,uCAAuC;SACtD,CAAC,CAAC;IACL,CAAC;IAED;;OAEG;IACH,cAAc;QACZ,OAAO,EAAE,GAAG,IAAI,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED;;OAEG;IACH,UAAU;QACR,IAAI,CAAC,KAAK,GAAG;YACX,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;YACrD,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,EAAE,UAAU,EAAE,CAAC,EAAE;SACzD,CAAC;IACJ,CAAC;CACF;AAED,WAAW;AACX,IAAI,aAAa,GAAuB,IAAI,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,OAA4B;IACzD,IAAI,CAAC,aAAa,IAAI,OAAO,EAAE,CAAC;QAC9B,aAAa,GAAG,IAAI,WAAW,CAAC,OAAO,CAAC,CAAC;IAC3C,CAAC;IACD,OAAO,aAAa,CAAC;AACvB,CAAC"}
|
|
@@ -1,30 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Background Agent - 백그라운드 에이전트 관리
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
export declare function getBackgroundAgentResult(sessionId: string): Promise<ToolResult>;
|
|
14
|
-
/**
|
|
15
|
-
* 백그라운드 에이전트 취소
|
|
16
|
-
*/
|
|
17
|
-
export declare function cancelBackgroundAgent(sessionId: string): ToolResult;
|
|
18
|
-
/**
|
|
19
|
-
* 활성 세션 목록
|
|
20
|
-
*/
|
|
21
|
-
export declare function listActiveSessions(): ToolResult;
|
|
22
|
-
/**
|
|
23
|
-
* 세션 히스토리 조회
|
|
24
|
-
*/
|
|
25
|
-
export declare function getSessionHistory(limit?: number): ToolResult;
|
|
26
|
-
/**
|
|
27
|
-
* 여러 백그라운드 에이전트 동시 실행
|
|
28
|
-
*/
|
|
29
|
-
export declare function launchParallelAgents(agentConfigs: BackgroundAgentArgs[]): Promise<ToolResult>;
|
|
3
|
+
*
|
|
4
|
+
* v2.6.0: 기능이 2개 모듈로 분리됨
|
|
5
|
+
* - SessionStore: 세션 저장소, 정리, 히스토리 관리
|
|
6
|
+
* - AgentExecutor: 에이전트 실행 로직
|
|
7
|
+
*
|
|
8
|
+
* 이 파일은 하위 호환성을 위해 모든 함수를 re-export
|
|
9
|
+
*/
|
|
10
|
+
export { sessionStore, listActiveSessions, getSessionHistory } from './SessionStore.js';
|
|
11
|
+
export type { SessionData } from './SessionStore.js';
|
|
12
|
+
export { launchBackgroundAgent, getBackgroundAgentResult, cancelBackgroundAgent, launchParallelAgents } from './AgentExecutor.js';
|
|
30
13
|
//# sourceMappingURL=backgroundAgent.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"backgroundAgent.d.ts","sourceRoot":"","sources":["../../src/orchestrator/backgroundAgent.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"backgroundAgent.d.ts","sourceRoot":"","sources":["../../src/orchestrator/backgroundAgent.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAGH,OAAO,EACL,YAAY,EACZ,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,mBAAmB,CAAC;AAC3B,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,EACL,qBAAqB,EACrB,wBAAwB,EACxB,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,oBAAoB,CAAC"}
|
|
@@ -1,348 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Background Agent - 백그라운드 에이전트 관리
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
//
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
// 세션 정리 함수
|
|
15
|
-
function cleanupExpiredSessions() {
|
|
16
|
-
const now = Date.now();
|
|
17
|
-
// 활성 세션 정리 (TTL 초과 + running 상태인 경우 취소)
|
|
18
|
-
for (const [sessionId, session] of activeSessions.entries()) {
|
|
19
|
-
if (now - session.createdAt > SESSION_TTL) {
|
|
20
|
-
if (session.handle.status === 'running') {
|
|
21
|
-
session.cancelController.abort();
|
|
22
|
-
}
|
|
23
|
-
activeSessions.delete(sessionId);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
// 히스토리 정리 (24시간 초과)
|
|
27
|
-
const cutoff = now - SESSION_HISTORY_TTL;
|
|
28
|
-
while (sessionHistory.length > 0 && sessionHistory[0].startTime < cutoff) {
|
|
29
|
-
sessionHistory.shift();
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
// 정리 타이머 시작 (모듈 로드 시 자동 시작)
|
|
33
|
-
let cleanupTimer = null;
|
|
34
|
-
function startCleanupTimer() {
|
|
35
|
-
if (cleanupTimer)
|
|
36
|
-
return;
|
|
37
|
-
cleanupTimer = setInterval(cleanupExpiredSessions, CLEANUP_INTERVAL);
|
|
38
|
-
// unref로 프로세스 종료를 막지 않음
|
|
39
|
-
if (cleanupTimer.unref) {
|
|
40
|
-
cleanupTimer.unref();
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
// 모듈 로드 시 타이머 시작
|
|
44
|
-
startCleanupTimer();
|
|
45
|
-
/**
|
|
46
|
-
* 백그라운드 에이전트 시작
|
|
47
|
-
*/
|
|
48
|
-
export async function launchBackgroundAgent(args) {
|
|
49
|
-
const { prompt, agentName = `agent-${Date.now()}`, model = DEFAULT_MODELS.BACKGROUND, maxTurns = AGENT.MAX_TURNS, allowedTools = AGENT.DEFAULT_ALLOWED_TOOLS, projectPath = process.cwd(), onProgress } = args;
|
|
50
|
-
const query = await getAgentSdkQuery();
|
|
51
|
-
// Agent SDK가 없으면 시뮬레이션
|
|
52
|
-
if (!query) {
|
|
53
|
-
const handle = {
|
|
54
|
-
sessionId: `simulated-${Date.now()}`,
|
|
55
|
-
agentName,
|
|
56
|
-
status: 'completed',
|
|
57
|
-
startTime: Date.now(),
|
|
58
|
-
getResult: async () => ({
|
|
59
|
-
agentName,
|
|
60
|
-
sessionId: `simulated-${Date.now()}`,
|
|
61
|
-
result: `[Agent SDK not installed] Would execute: ${prompt.slice(0, 100)}...`,
|
|
62
|
-
success: true,
|
|
63
|
-
duration: 0
|
|
64
|
-
}),
|
|
65
|
-
cancel: () => { }
|
|
66
|
-
};
|
|
67
|
-
return {
|
|
68
|
-
content: [{
|
|
69
|
-
type: 'text',
|
|
70
|
-
text: `Background agent "${agentName}" started (simulated)\nSession ID: ${handle.sessionId}\n\nNote: Install @anthropic-ai/claude-agent-sdk for real execution.`
|
|
71
|
-
}],
|
|
72
|
-
handle
|
|
73
|
-
};
|
|
74
|
-
}
|
|
75
|
-
const startTime = Date.now();
|
|
76
|
-
const cancelController = new AbortController();
|
|
77
|
-
let sessionId = '';
|
|
78
|
-
let result = '';
|
|
79
|
-
let status = 'running';
|
|
80
|
-
// 결과 수집 Promise
|
|
81
|
-
const resultPromise = new Promise(async (resolve) => {
|
|
82
|
-
try {
|
|
83
|
-
const response = query({
|
|
84
|
-
prompt,
|
|
85
|
-
options: {
|
|
86
|
-
model,
|
|
87
|
-
maxTurns,
|
|
88
|
-
allowedTools,
|
|
89
|
-
cwd: projectPath
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
for await (const message of response) {
|
|
93
|
-
// 취소 체크
|
|
94
|
-
if (cancelController.signal.aborted) {
|
|
95
|
-
status = 'cancelled';
|
|
96
|
-
resolve({
|
|
97
|
-
agentName,
|
|
98
|
-
sessionId,
|
|
99
|
-
result: 'Cancelled by user',
|
|
100
|
-
success: false,
|
|
101
|
-
error: 'Cancelled',
|
|
102
|
-
duration: Date.now() - startTime
|
|
103
|
-
});
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
const msg = message;
|
|
107
|
-
// 세션 ID 캡처
|
|
108
|
-
if (msg.type === 'system' && msg.subtype === 'init' && msg.session_id) {
|
|
109
|
-
sessionId = msg.session_id;
|
|
110
|
-
}
|
|
111
|
-
// 진행 상황 콜백
|
|
112
|
-
if (msg.type === 'system' && msg.subtype === 'progress' && onProgress) {
|
|
113
|
-
onProgress(msg.content || 'Processing...');
|
|
114
|
-
}
|
|
115
|
-
// 결과 수집
|
|
116
|
-
if (msg.type === 'result' && msg.result) {
|
|
117
|
-
result = msg.result;
|
|
118
|
-
}
|
|
119
|
-
if (msg.type === 'assistant' && msg.message?.content) {
|
|
120
|
-
const textContent = msg.message.content
|
|
121
|
-
.filter(block => block.type === 'text' && block.text)
|
|
122
|
-
.map(block => block.text)
|
|
123
|
-
.join('\n');
|
|
124
|
-
if (textContent) {
|
|
125
|
-
result += textContent;
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
}
|
|
129
|
-
status = 'completed';
|
|
130
|
-
resolve({
|
|
131
|
-
agentName,
|
|
132
|
-
sessionId,
|
|
133
|
-
result: result || 'No result',
|
|
134
|
-
success: true,
|
|
135
|
-
duration: Date.now() - startTime
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
catch (error) {
|
|
139
|
-
status = 'failed';
|
|
140
|
-
resolve({
|
|
141
|
-
agentName,
|
|
142
|
-
sessionId,
|
|
143
|
-
result: '',
|
|
144
|
-
success: false,
|
|
145
|
-
error: error instanceof Error ? error.message : String(error),
|
|
146
|
-
duration: Date.now() - startTime
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
});
|
|
150
|
-
// 핸들 생성
|
|
151
|
-
const handle = {
|
|
152
|
-
sessionId: sessionId || `pending-${Date.now()}`,
|
|
153
|
-
agentName,
|
|
154
|
-
status,
|
|
155
|
-
startTime,
|
|
156
|
-
getResult: () => resultPromise,
|
|
157
|
-
cancel: () => {
|
|
158
|
-
cancelController.abort();
|
|
159
|
-
status = 'cancelled';
|
|
160
|
-
}
|
|
161
|
-
};
|
|
162
|
-
// 세션 등록
|
|
163
|
-
activeSessions.set(handle.sessionId, {
|
|
164
|
-
handle,
|
|
165
|
-
resultPromise,
|
|
166
|
-
cancelController,
|
|
167
|
-
createdAt: startTime
|
|
168
|
-
});
|
|
169
|
-
// 완료 시 히스토리에 추가
|
|
170
|
-
resultPromise.then((result) => {
|
|
171
|
-
sessionHistory.push({
|
|
172
|
-
sessionId: result.sessionId,
|
|
173
|
-
agentName: result.agentName,
|
|
174
|
-
status: result.success ? 'completed' : 'failed',
|
|
175
|
-
startTime,
|
|
176
|
-
endTime: Date.now(),
|
|
177
|
-
prompt
|
|
178
|
-
});
|
|
179
|
-
// 활성 세션에서 제거
|
|
180
|
-
activeSessions.delete(handle.sessionId);
|
|
181
|
-
});
|
|
182
|
-
return {
|
|
183
|
-
content: [{
|
|
184
|
-
type: 'text',
|
|
185
|
-
text: `Background agent "${agentName}" started\nSession ID: ${handle.sessionId}\nModel: ${model}\nMax Turns: ${maxTurns}\n\nUse getBackgroundAgentResult("${handle.sessionId}") to check status.`
|
|
186
|
-
}],
|
|
187
|
-
handle
|
|
188
|
-
};
|
|
189
|
-
}
|
|
190
|
-
/**
|
|
191
|
-
* 백그라운드 에이전트 결과 조회
|
|
192
|
-
*/
|
|
193
|
-
export async function getBackgroundAgentResult(sessionId) {
|
|
194
|
-
const session = activeSessions.get(sessionId);
|
|
195
|
-
if (!session) {
|
|
196
|
-
// 히스토리에서 찾기
|
|
197
|
-
const historical = sessionHistory.find(s => s.sessionId === sessionId);
|
|
198
|
-
if (historical) {
|
|
199
|
-
return {
|
|
200
|
-
content: [{
|
|
201
|
-
type: 'text',
|
|
202
|
-
text: `Session "${sessionId}" completed at ${new Date(historical.endTime).toISOString()}\nStatus: ${historical.status}`
|
|
203
|
-
}]
|
|
204
|
-
};
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
content: [{
|
|
208
|
-
type: 'text',
|
|
209
|
-
text: `Session "${sessionId}" not found`
|
|
210
|
-
}]
|
|
211
|
-
};
|
|
212
|
-
}
|
|
213
|
-
// 진행 중인 세션
|
|
214
|
-
if (session.handle.status === 'running') {
|
|
215
|
-
return {
|
|
216
|
-
content: [{
|
|
217
|
-
type: 'text',
|
|
218
|
-
text: `Session "${sessionId}" is still running\nAgent: ${session.handle.agentName}\nStarted: ${new Date(session.handle.startTime).toISOString()}`
|
|
219
|
-
}]
|
|
220
|
-
};
|
|
221
|
-
}
|
|
222
|
-
// 완료된 경우 결과 반환
|
|
223
|
-
const result = await session.resultPromise;
|
|
224
|
-
return {
|
|
225
|
-
content: [{
|
|
226
|
-
type: 'text',
|
|
227
|
-
text: `Session "${sessionId}" ${result.success ? 'completed' : 'failed'}\nDuration: ${(result.duration / 1000).toFixed(1)}s\n\nResult:\n${result.result}`
|
|
228
|
-
}],
|
|
229
|
-
result
|
|
230
|
-
};
|
|
231
|
-
}
|
|
232
|
-
/**
|
|
233
|
-
* 백그라운드 에이전트 취소
|
|
234
|
-
*/
|
|
235
|
-
export function cancelBackgroundAgent(sessionId) {
|
|
236
|
-
const session = activeSessions.get(sessionId);
|
|
237
|
-
if (!session) {
|
|
238
|
-
return {
|
|
239
|
-
content: [{
|
|
240
|
-
type: 'text',
|
|
241
|
-
text: `Session "${sessionId}" not found or already completed`
|
|
242
|
-
}]
|
|
243
|
-
};
|
|
244
|
-
}
|
|
245
|
-
session.handle.cancel();
|
|
246
|
-
return {
|
|
247
|
-
content: [{
|
|
248
|
-
type: 'text',
|
|
249
|
-
text: `Session "${sessionId}" cancelled`
|
|
250
|
-
}]
|
|
251
|
-
};
|
|
252
|
-
}
|
|
253
|
-
/**
|
|
254
|
-
* 활성 세션 목록
|
|
255
|
-
*/
|
|
256
|
-
export function listActiveSessions() {
|
|
257
|
-
const sessions = Array.from(activeSessions.values()).map(s => ({
|
|
258
|
-
sessionId: s.handle.sessionId,
|
|
259
|
-
agentName: s.handle.agentName,
|
|
260
|
-
status: s.handle.status,
|
|
261
|
-
startTime: new Date(s.handle.startTime).toISOString(),
|
|
262
|
-
runningFor: `${((Date.now() - s.handle.startTime) / 1000).toFixed(0)}s`
|
|
263
|
-
}));
|
|
264
|
-
if (sessions.length === 0) {
|
|
265
|
-
return {
|
|
266
|
-
content: [{
|
|
267
|
-
type: 'text',
|
|
268
|
-
text: 'No active background agents'
|
|
269
|
-
}]
|
|
270
|
-
};
|
|
271
|
-
}
|
|
272
|
-
let summary = `## Active Background Agents (${sessions.length})\n\n`;
|
|
273
|
-
for (const session of sessions) {
|
|
274
|
-
summary += `- **${session.agentName}** (${session.sessionId})\n`;
|
|
275
|
-
summary += ` Status: ${session.status} | Running: ${session.runningFor}\n`;
|
|
276
|
-
}
|
|
277
|
-
return {
|
|
278
|
-
content: [{ type: 'text', text: summary }],
|
|
279
|
-
sessions
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
/**
|
|
283
|
-
* 세션 히스토리 조회
|
|
284
|
-
*/
|
|
285
|
-
export function getSessionHistory(limit = 10) {
|
|
286
|
-
const recent = sessionHistory.slice(-limit).reverse();
|
|
287
|
-
if (recent.length === 0) {
|
|
288
|
-
return {
|
|
289
|
-
content: [{
|
|
290
|
-
type: 'text',
|
|
291
|
-
text: 'No session history'
|
|
292
|
-
}]
|
|
293
|
-
};
|
|
294
|
-
}
|
|
295
|
-
let summary = `## Session History (last ${recent.length})\n\n`;
|
|
296
|
-
for (const session of recent) {
|
|
297
|
-
const duration = session.endTime
|
|
298
|
-
? `${((session.endTime - session.startTime) / 1000).toFixed(1)}s`
|
|
299
|
-
: 'N/A';
|
|
300
|
-
summary += `- **${session.agentName}** (${session.sessionId})\n`;
|
|
301
|
-
summary += ` Status: ${session.status} | Duration: ${duration}\n`;
|
|
302
|
-
}
|
|
303
|
-
return {
|
|
304
|
-
content: [{ type: 'text', text: summary }],
|
|
305
|
-
history: recent
|
|
306
|
-
};
|
|
307
|
-
}
|
|
308
|
-
/**
|
|
309
|
-
* 여러 백그라운드 에이전트 동시 실행
|
|
310
|
-
*/
|
|
311
|
-
export async function launchParallelAgents(agentConfigs) {
|
|
312
|
-
const handles = [];
|
|
313
|
-
const errors = [];
|
|
314
|
-
// 병렬로 에이전트 시작
|
|
315
|
-
const results = await Promise.all(agentConfigs.map(async (config) => {
|
|
316
|
-
try {
|
|
317
|
-
const result = await launchBackgroundAgent(config);
|
|
318
|
-
if ('handle' in result) {
|
|
319
|
-
return result.handle;
|
|
320
|
-
}
|
|
321
|
-
return null;
|
|
322
|
-
}
|
|
323
|
-
catch (error) {
|
|
324
|
-
errors.push(`${config.agentName}: ${error instanceof Error ? error.message : String(error)}`);
|
|
325
|
-
return null;
|
|
326
|
-
}
|
|
327
|
-
}));
|
|
328
|
-
for (const result of results) {
|
|
329
|
-
if (result) {
|
|
330
|
-
handles.push(result);
|
|
331
|
-
}
|
|
332
|
-
}
|
|
333
|
-
let summary = `## Launched ${handles.length} Background Agents\n\n`;
|
|
334
|
-
for (const handle of handles) {
|
|
335
|
-
summary += `- ${handle.agentName}: ${handle.sessionId}\n`;
|
|
336
|
-
}
|
|
337
|
-
if (errors.length > 0) {
|
|
338
|
-
summary += `\n### Errors (${errors.length})\n`;
|
|
339
|
-
for (const error of errors) {
|
|
340
|
-
summary += `- ${error}\n`;
|
|
341
|
-
}
|
|
342
|
-
}
|
|
343
|
-
return {
|
|
344
|
-
content: [{ type: 'text', text: summary }],
|
|
345
|
-
handles
|
|
346
|
-
};
|
|
347
|
-
}
|
|
3
|
+
*
|
|
4
|
+
* v2.6.0: 기능이 2개 모듈로 분리됨
|
|
5
|
+
* - SessionStore: 세션 저장소, 정리, 히스토리 관리
|
|
6
|
+
* - AgentExecutor: 에이전트 실행 로직
|
|
7
|
+
*
|
|
8
|
+
* 이 파일은 하위 호환성을 위해 모든 함수를 re-export
|
|
9
|
+
*/
|
|
10
|
+
// SessionStore
|
|
11
|
+
export { sessionStore, listActiveSessions, getSessionHistory } from './SessionStore.js';
|
|
12
|
+
// AgentExecutor
|
|
13
|
+
export { launchBackgroundAgent, getBackgroundAgentResult, cancelBackgroundAgent, launchParallelAgents } from './AgentExecutor.js';
|
|
348
14
|
//# sourceMappingURL=backgroundAgent.js.map
|