Function bodies 601 total
BomWasteAgent class · typescript · L9-L255 (247 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
export class BomWasteAgent extends Agent {
private anomalyThreshold = 5; // Default 5% variance threshold
private confidenceMultiplier = 1.0;
constructor(eventBus: EventBus, stateManager: StateManager, learningRegistry: LearningRegistry) {
super('bom-waste-agent', eventBus, stateManager, learningRegistry);
}
getCapabilities(): string[] {
return ['BOM 차이 분석', '폐기물 원인 추론', '표준량 업데이트 제안', '이상 패턴 감지'];
}
async process(task: Task): Promise<TaskResult> {
const startTime = Date.now();
try {
switch (task.type) {
case 'analyze_bom_variance':
return await this.analyzeBomVariance(task);
case 'analyze_waste_trend':
return await this.analyzeWasteTrend(task);
case 'generate_insight':
return await this.generateDomainInsight(task);
default:
throw new Error(`Unknown task type: ${task.type}`);
}
} catch (error) {
return {
taskId: task.id,
agentId: this.id,
constructor method · typescript · L13-L15 (3 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
constructor(eventBus: EventBus, stateManager: StateManager, learningRegistry: LearningRegistry) {
super('bom-waste-agent', eventBus, stateManager, learningRegistry);
}getCapabilities method · typescript · L17-L19 (3 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
getCapabilities(): string[] {
return ['BOM 차이 분석', '폐기물 원인 추론', '표준량 업데이트 제안', '이상 패턴 감지'];
}process method · typescript · L21-L44 (24 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
async process(task: Task): Promise<TaskResult> {
const startTime = Date.now();
try {
switch (task.type) {
case 'analyze_bom_variance':
return await this.analyzeBomVariance(task);
case 'analyze_waste_trend':
return await this.analyzeWasteTrend(task);
case 'generate_insight':
return await this.generateDomainInsight(task);
default:
throw new Error(`Unknown task type: ${task.type}`);
}
} catch (error) {
return {
taskId: task.id,
agentId: this.id,
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
processingTime: Date.now() - startTime,
};
}
}analyzeBomVariance method · typescript · L49-L122 (74 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
private async analyzeBomVariance(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const state = this.stateManager.getBomWasteState();
const bomItems = state.bomItems;
if (bomItems.length === 0) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'No BOM items to analyze' },
processingTime: Date.now() - startTime,
};
}
// Find items with significant variance
const anomalies = bomItems.filter(item => Math.abs(item.diffPercent) >= this.anomalyThreshold);
// Generate AI reasoning for each anomaly
const analyzedItems: BomDiffItem[] = [];
for (const item of anomalies.slice(0, 5)) {
// Limit to top 5
const reasoning = await geminiAdapter.analyzeAnomaly({
itemName: item.skuName,
expected: item.stdQty,
actual: item.actualQty,
diffPercent: item.diffPercent,
});
// Update item with reasoning
conanalyzeWasteTrend method · typescript · L127-L180 (54 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
private async analyzeWasteTrend(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const state = this.stateManager.getBomWasteState();
const wasteTrend = state.wasteTrend;
if (wasteTrend.length < 3) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'Insufficient data for trend analysis' },
processingTime: Date.now() - startTime,
};
}
// Calculate trend direction
const recentAvg = wasteTrend.slice(-7).reduce((sum, d) => sum + d.wastePercent, 0) / 7;
const previousAvg = wasteTrend.slice(-14, -7).reduce((sum, d) => sum + d.wastePercent, 0) / 7;
const trend =
recentAvg > previousAvg ? 'increasing' : recentAvg < previousAvg ? 'decreasing' : 'stable';
// Check if exceeding target
const latestWaste = wasteTrend[wasteTrend.length - 1];
const isExceedingTarget = latestWaste.wastePercent > latestWaste.targetPercent;
if (isExceedingTarget generateDomainInsight method · typescript · L185-L217 (33 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
private async generateDomainInsight(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const state = this.stateManager.getBomWasteState();
// Find most impactful issue
const highImpactItems = state.bomItems
.filter(item => item.costImpact > 0)
.sort((a, b) => b.costImpact - a.costImpact);
if (highImpactItems.length > 0) {
const top = highImpactItems[0];
this.publishInsight(
'bom',
'비용 영향 분석',
`${top.skuName}의 BOM 차이로 인한 추가 비용이 가장 높습니다.`,
{
highlight: `예상 추가 비용: ${top.costImpact.toLocaleString()}원`,
level: top.costImpact > 100000 ? 'critical' : 'warning',
confidence: 0.85,
data: { topItems: highImpactItems.slice(0, 3) },
suggestedActions: ['BOM 표준량 재검토', '공정 최적화'],
}
);
}
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { generated: true },
processingTime: Date.now() - startTRepobility · open methodology · https://repobility.com/research/
calculateAnomalyScore method · typescript · L222-L229 (8 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
private calculateAnomalyScore(item: BomDiffItem): number {
const varianceScore = Math.min(Math.abs(item.diffPercent) * 5, 50);
const costScore = Math.min(item.costImpact / 10000, 30);
const baseScore = varianceScore + costScore;
// Add penalty for repeated issues (would need history tracking)
return Math.min(Math.round(baseScore + 20), 100);
}applyCoaching method · typescript · L234-L254 (21 LOC)server/src/agents/bom-waste/BomWasteAgent.ts
protected async applyCoaching(feedback: CoachingMessage['payload']['feedback']): Promise<void> {
console.log(`BomWasteAgent applying coaching for ${feedback.metric}`);
if (feedback.metric === 'accuracy') {
// Increase threshold to be more selective
this.anomalyThreshold = Math.min(this.anomalyThreshold + 1, 15);
console.log(`Adjusted anomaly threshold to ${this.anomalyThreshold}%`);
}
if (feedback.metric === 'user_acceptance') {
// Reduce confidence multiplier if insights are being dismissed
this.confidenceMultiplier = Math.max(this.confidenceMultiplier * 0.95, 0.5);
console.log(`Adjusted confidence multiplier to ${this.confidenceMultiplier}`);
}
// Record coaching application
this.learningRegistry.recordCoaching(this.id, 'general', [
`threshold: ${this.anomalyThreshold}`,
`confidence: ${this.confidenceMultiplier}`,
]);
}createBomWasteTeam function · typescript · L31-L85 (55 LOC)server/src/agents/bom-waste-team/index.ts
export function createBomWasteTeam(
eventBus: EventBus,
stateManager: StateManager,
learningRegistry: LearningRegistry
): BomWasteTeam {
const optimist = new OptimistPersona(
'bom-waste-optimist',
'bom-waste-team',
'bom',
eventBus,
stateManager,
learningRegistry
);
const pessimist = new PessimistPersona(
'bom-waste-pessimist',
'bom-waste-team',
'bom',
eventBus,
stateManager,
learningRegistry
);
const mediator = new MediatorPersona(
'bom-waste-mediator',
'bom-waste-team',
'bom',
eventBus,
stateManager,
learningRegistry
);
return {
optimist,
pessimist,
mediator,
start: () => {
optimist.start();
pessimist.start();
mediator.start();
console.log('[BomWasteTeam] 팀 시작됨');
},
stop: () => {
optimist.stop();
pessimist.stop();
mediator.stop();
console.log('[BomWasteTeam] 팀 중지됨');
},
injectDependencies: (debateManager: DebatecreateBusinessTeam function · typescript · L31-L85 (55 LOC)server/src/agents/business-team/index.ts
export function createBusinessTeam(
eventBus: EventBus,
stateManager: StateManager,
learningRegistry: LearningRegistry
): BusinessTeam {
const optimist = new OptimistPersona(
'business-optimist',
'business-strategy-team',
'general', // business 도메인은 서버에서 general로 매핑
eventBus,
stateManager,
learningRegistry
);
const pessimist = new PessimistPersona(
'business-pessimist',
'business-strategy-team',
'general',
eventBus,
stateManager,
learningRegistry
);
const mediator = new MediatorPersona(
'business-mediator',
'business-strategy-team',
'general',
eventBus,
stateManager,
learningRegistry
);
return {
optimist,
pessimist,
mediator,
start: () => {
optimist.start();
pessimist.start();
mediator.start();
console.log('[BusinessTeam] 팀 시작됨');
},
stop: () => {
optimist.stop();
pessimist.stop();
mediator.stop();
console.log('[BusinessTCoordinatorAgent class · typescript · L16-L368 (353 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
export class CoordinatorAgent extends Agent {
private subordinates: Agent[];
private pendingResults: Map<string, TaskResult[]> = new Map();
private coachingInterval: NodeJS.Timeout | null = null;
private insightBuffer: Map<string, AgentInsight> = new Map();
constructor(
eventBus: EventBus,
stateManager: StateManager,
learningRegistry: LearningRegistry,
subordinates: Agent[]
) {
super('coordinator', eventBus, stateManager, learningRegistry);
this.subordinates = subordinates;
}
getCapabilities(): string[] {
return [
'태스크 오케스트레이션',
'에이전트 코칭',
'크로스도메인 인사이트 통합',
'우선순위 관리',
'성과 모니터링',
];
}
/**
* Start coordinator with coaching loop
*/
start(): void {
super.start();
// Subscribe to insight shares from subordinates
this.eventBus.subscribeType('INSIGHT_SHARE', this.handleInsightShare.bind(this));
this.eventBus.subscribeType('TASK_RESULT', this.handleTaskResult.bind(this));
// Startconstructor method · typescript · L22-L30 (9 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
constructor(
eventBus: EventBus,
stateManager: StateManager,
learningRegistry: LearningRegistry,
subordinates: Agent[]
) {
super('coordinator', eventBus, stateManager, learningRegistry);
this.subordinates = subordinates;
}getCapabilities method · typescript · L32-L40 (9 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
getCapabilities(): string[] {
return [
'태스크 오케스트레이션',
'에이전트 코칭',
'크로스도메인 인사이트 통합',
'우선순위 관리',
'성과 모니터링',
];
}start method · typescript · L45-L58 (14 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
start(): void {
super.start();
// Subscribe to insight shares from subordinates
this.eventBus.subscribeType('INSIGHT_SHARE', this.handleInsightShare.bind(this));
this.eventBus.subscribeType('TASK_RESULT', this.handleTaskResult.bind(this));
// Start periodic coaching check
this.coachingInterval = setInterval(() => {
this.evaluateAndCoach();
}, 60000); // Check every minute
console.log('Coordinator started with coaching loop');
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
stop method · typescript · L63-L68 (6 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
stop(): void {
if (this.coachingInterval) {
clearInterval(this.coachingInterval);
}
super.stop();
}process method · typescript · L70-L100 (31 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
async process(task: Task): Promise<TaskResult> {
const startTime = Date.now();
try {
switch (task.type) {
case 'orchestrate_analysis':
await this.orchestrateAnalysis(task);
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { orchestrated: true },
processingTime: Date.now() - startTime,
};
case 'synthesize_insights':
return await this.synthesizeInsights(task);
case 'evaluate_agents':
return await this.evaluateAgents(task);
default:
throw new Error(`Unknown task type: ${task.type}`);
}
} catch (error) {
return {
taskId: task.id,
agentId: this.id,
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
processingTime: Date.now() - startTime,
};
}
}orchestrateAnalysis method · typescript · L105-L184 (80 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
async orchestrateAnalysis(input?: {
priority?: 'low' | 'medium' | 'high' | 'critical';
}): Promise<void> {
const correlationId = uuidv4();
const sender = this.eventBus.createSender(this.id);
// Create tasks for each domain agent
const tasks: { agentId: AgentId; task: Task }[] = [
{
agentId: 'bom-waste-agent',
task: {
id: uuidv4(),
type: 'analyze_bom_variance',
domain: 'bom',
input: {},
priority: input?.priority || 'medium',
},
},
{
agentId: 'bom-waste-agent',
task: {
id: uuidv4(),
type: 'analyze_waste_trend',
domain: 'waste',
input: {},
priority: input?.priority || 'medium',
},
},
{
agentId: 'inventory-agent',
task: {
id: uuidv4(),
type: 'analyze_safety_stock',
domain: 'inventory',
input: {},
priority: input?.priority || handleTaskResult method · typescript · L189-L205 (17 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
protected async handleTaskResult(message: AgentMessage): Promise<void> {
if (message.source === this.id) return; // Ignore own results
const result = message.payload as TaskResult;
const correlationId = message.correlationId;
if (correlationId && this.pendingResults.has(correlationId)) {
const results = this.pendingResults.get(correlationId)!;
results.push(result);
// Check if all results are in (we expect 6 tasks)
if (results.length >= 6) {
await this.synthesizeFromResults(correlationId, results);
this.pendingResults.delete(correlationId);
}
}
}handleInsightShare method · typescript · L210-L221 (12 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
protected async handleInsightShare(message: AgentMessage): Promise<void> {
if (message.source === this.id) return;
const insight = message.payload as AgentInsight;
this.insightBuffer.set(insight.id, insight);
// Keep buffer limited
if (this.insightBuffer.size > 50) {
const oldestKey = this.insightBuffer.keys().next().value;
if (oldestKey) this.insightBuffer.delete(oldestKey);
}
}synthesizeFromResults method · typescript · L226-L275 (50 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
private async synthesizeFromResults(correlationId: string, results: TaskResult[]): Promise<void> {
const successfulResults = results.filter(r => r.success);
// Get recent insights from buffer
const recentInsights = Array.from(this.insightBuffer.values()).filter(
i => Date.now() - i.timestamp.getTime() < 60000
); // Last minute
if (recentInsights.length === 0 && successfulResults.length === 0) {
return;
}
// Categorize insights
const bomInsights = recentInsights.filter(i => i.domain === 'bom' || i.domain === 'waste');
const inventoryInsights = recentInsights.filter(i => i.domain === 'inventory');
const profitInsights = recentInsights.filter(i => i.domain === 'profitability');
// Generate coordinator summary
const summary = await geminiAdapter.generateCoordinatorSummary({
bomWaste: bomInsights.map(i => i.description).join('; ') || undefined,
inventory: inventoryInsights.map(i => i.description).join('; ') || undsynthesizeInsights method · typescript · L280-L314 (35 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
private async synthesizeInsights(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const insights = this.stateManager.getInsights(undefined, 20);
// Group by domain
const byDomain = new Map<string, AgentInsight[]>();
for (const insight of insights) {
const current = byDomain.get(insight.domain) || [];
current.push(insight);
byDomain.set(insight.domain, current);
}
// Generate summary
const domainSummaries: Record<string, string> = {};
for (const [domain, domainInsights] of byDomain) {
domainSummaries[domain] = domainInsights
.map(i => i.description)
.slice(0, 3)
.join('; ');
}
const summary = await geminiAdapter.generateCoordinatorSummary({
bomWaste: domainSummaries['bom'] || domainSummaries['waste'],
inventory: domainSummaries['inventory'],
profitability: domainSummaries['profitability'],
});
return {
taskId: task.id,
agentId: this.id,
evaluateAgents method · typescript · L319-L330 (12 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
private async evaluateAgents(task: Task): Promise<TaskResult> {
const startTime = Date.now();
await this.evaluateAndCoach();
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { evaluated: true },
processingTime: Date.now() - startTime,
};
}Want fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
evaluateAndCoach method · typescript · L335-L352 (18 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
private async evaluateAndCoach(): Promise<void> {
const performances = this.learningRegistry.getAllPerformances();
for (const perf of performances) {
if (this.learningRegistry.needsCoaching(perf.agentId)) {
const feedback = this.learningRegistry.generateCoachingFeedback(perf.agentId);
if (feedback) {
const sender = this.eventBus.createSender(this.id);
sender.send(perf.agentId, 'COACHING_FEEDBACK', { feedback }, 'medium');
console.log(
`Sent coaching to ${perf.agentId}: ${feedback.metric} (score: ${feedback.score})`
);
}
}
}
}applyCoaching method · typescript · L357-L360 (4 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
protected async applyCoaching(): Promise<void> {
// Coordinator doesn't receive coaching from others
console.log('Coordinator: coaching not applicable');
}getSubordinateStatuses method · typescript · L365-L367 (3 LOC)server/src/agents/coordinator/CoordinatorAgent.ts
getSubordinateStatuses() {
return this.subordinates.map(agent => agent.getStatus());
}constructor method · typescript · L42-L44 (3 LOC)server/src/agents/cost-management/CostManagementAgent.ts
constructor(eventBus: EventBus, stateManager: StateManager, learningRegistry: LearningRegistry) {
super('cost-management-agent', eventBus, stateManager, learningRegistry);
}getCapabilities method · typescript · L46-L55 (10 LOC)server/src/agents/cost-management/CostManagementAgent.ts
getCapabilities(): string[] {
return [
'원가 구조 분석',
'노무비 효율성 분석',
'발주/구매 패턴 분석',
'원가 절감 기회 도출',
'비용 추세 모니터링',
'인건비 최적화 제안',
];
}process method · typescript · L57-L84 (28 LOC)server/src/agents/cost-management/CostManagementAgent.ts
async process(task: Task): Promise<TaskResult> {
const startTime = Date.now();
try {
switch (task.type) {
case 'analyze_cost_structure':
return await this.analyzeCostStructure(task);
case 'analyze_labor_efficiency':
return await this.analyzeLaborEfficiency(task);
case 'analyze_purchase_patterns':
return await this.analyzePurchasePatterns(task);
case 'detect_cost_anomalies':
return await this.detectCostAnomalies(task);
case 'generate_cost_insight':
return await this.generateCostInsight(task);
default:
throw new Error(`Unknown task type: ${task.type}`);
}
} catch (error) {
return {
taskId: task.id,
agentId: this.id,
success: false,
error: error instanceof Error ? error.message : 'Unknown error',
processingTime: Date.now() - startTime,
};
}
}analyzeCostStructure method · typescript · L89-L169 (81 LOC)server/src/agents/cost-management/CostManagementAgent.ts
private async analyzeCostStructure(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const costData = task.payload?.costData as CostData | undefined;
if (!costData) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'No cost data available' },
processingTime: Date.now() - startTime,
};
}
const totalCost =
costData.rawMaterialCost +
costData.subMaterialCost +
costData.laborCost +
costData.expenseAmount;
const profitRatio = costData.salesAmount > 0 ? costData.salesAmount / totalCost : 0;
// Calculate cost ratios
const ratios = {
rawMaterial: costData.salesAmount > 0 ? costData.salesAmount / costData.rawMaterialCost : 0,
subMaterial: costData.salesAmount > 0 ? costData.salesAmount / costData.subMaterialCost : 0,
labor: costData.salesAmount > 0 ? costData.salesAmount / costData.laborCost : 0,
expense: costData.sanalyzeLaborEfficiency method · typescript · L174-L246 (73 LOC)server/src/agents/cost-management/CostManagementAgent.ts
private async analyzeLaborEfficiency(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const attendanceData = task.payload?.attendanceData as AttendanceData[] | undefined;
const laborCost = (task.payload?.laborCost as number) || 0;
const productionVolume = (task.payload?.productionVolume as number) || 0;
if (!attendanceData || attendanceData.length === 0) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'No attendance data available' },
processingTime: Date.now() - startTime,
};
}
// Calculate overtime statistics
const totalOvertimeHours = attendanceData.reduce((sum, a) => sum + (a.overtimeHours || 0), 0);
const uniqueEmployees = new Set(attendanceData.map(a => a.employeeId)).size;
const avgOvertimePerEmployee = uniqueEmployees > 0 ? totalOvertimeHours / uniqueEmployees : 0;
// Analyze by shift
const shiftStats = new Map<string, { count:Same scanner, your repo: https://repobility.com — Repobility
analyzePurchasePatterns method · typescript · L251-L327 (77 LOC)server/src/agents/cost-management/CostManagementAgent.ts
private async analyzePurchasePatterns(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const purchaseOrders = task.payload?.purchaseOrders as PurchaseOrderData[] | undefined;
if (!purchaseOrders || purchaseOrders.length === 0) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'No purchase order data available' },
processingTime: Date.now() - startTime,
};
}
// Calculate statistics
const totalAmount = purchaseOrders.reduce((sum, po) => sum + po.totalAmount, 0);
const urgentOrders = purchaseOrders.filter(po => po.isUrgent).length;
// Aggregate by supplier
const supplierStats = new Map<string, number>();
for (const po of purchaseOrders) {
const current = supplierStats.get(po.supplierName) || 0;
supplierStats.set(po.supplierName, current + po.totalAmount);
}
// Get top suppliers
const topSuppliers = Array.from(supplierStats.detectCostAnomalies method · typescript · L332-L414 (83 LOC)server/src/agents/cost-management/CostManagementAgent.ts
private async detectCostAnomalies(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const costHistory = task.payload?.costHistory as CostData[] | undefined;
if (!costHistory || costHistory.length < 2) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'Insufficient cost history for anomaly detection' },
processingTime: Date.now() - startTime,
};
}
const anomalies: { category: string; variance: number; severity: string }[] = [];
// Compare latest period with average
const latest = costHistory[costHistory.length - 1];
const previousAvg = costHistory.slice(0, -1).reduce(
(acc, c) => ({
rawMaterialCost: acc.rawMaterialCost + c.rawMaterialCost,
subMaterialCost: acc.subMaterialCost + c.subMaterialCost,
laborCost: acc.laborCost + c.laborCost,
expenseAmount: acc.expenseAmount + c.expenseAmount,
}),
{ rawMaterialCogenerateCostInsight method · typescript · L419-L480 (62 LOC)server/src/agents/cost-management/CostManagementAgent.ts
private async generateCostInsight(task: Task): Promise<TaskResult> {
const startTime = Date.now();
const costData = task.payload?.costData as CostData | undefined;
if (!costData) {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'No cost data for insight generation' },
processingTime: Date.now() - startTime,
};
}
const totalCost =
costData.rawMaterialCost +
costData.subMaterialCost +
costData.laborCost +
costData.expenseAmount;
const profitRatio = costData.salesAmount > 0 ? costData.salesAmount / totalCost : 0;
// Calculate cost breakdown percentages
const breakdown = {
rawMaterial: (costData.rawMaterialCost / totalCost) * 100,
subMaterial: (costData.subMaterialCost / totalCost) * 100,
labor: (costData.laborCost / totalCost) * 100,
expense: (costData.expenseAmount / totalCost) * 100,
};
// Find the largest cost dapplyCoaching method · typescript · L485-L504 (20 LOC)server/src/agents/cost-management/CostManagementAgent.ts
protected async applyCoaching(feedback: CoachingMessage['payload']['feedback']): Promise<void> {
console.log(`CostManagementAgent applying coaching for ${feedback.metric}`);
if (feedback.metric === 'accuracy') {
// Adjust thresholds based on feedback
this.costThreshold = Math.max(this.costThreshold - 0.05, 1.0);
console.log(`Adjusted cost threshold to ${this.costThreshold}`);
}
if (feedback.metric === 'user_acceptance') {
this.overtimeAlertThreshold = Math.min(this.overtimeAlertThreshold + 5, 40);
console.log(`Adjusted overtime alert threshold to ${this.overtimeAlertThreshold}%`);
}
this.learningRegistry.recordCoaching(this.id, 'general', [
`costThreshold: ${this.costThreshold}`,
`laborCostRatio: ${this.laborCostRatio}`,
`overtimeAlertThreshold: ${this.overtimeAlertThreshold}`,
]);
}createCostTeam function · typescript · L31-L85 (55 LOC)server/src/agents/cost-team/index.ts
export function createCostTeam(
eventBus: EventBus,
stateManager: StateManager,
learningRegistry: LearningRegistry
): CostTeam {
const optimist = new OptimistPersona(
'cost-optimist',
'cost-management-team',
'general',
eventBus,
stateManager,
learningRegistry
);
const pessimist = new PessimistPersona(
'cost-pessimist',
'cost-management-team',
'general',
eventBus,
stateManager,
learningRegistry
);
const mediator = new MediatorPersona(
'cost-mediator',
'cost-management-team',
'general',
eventBus,
stateManager,
learningRegistry
);
return {
optimist,
pessimist,
mediator,
start: () => {
optimist.start();
pessimist.start();
mediator.start();
console.log('[CostTeam] 팀 시작됨');
},
stop: () => {
optimist.stop();
pessimist.stop();
mediator.stop();
console.log('[CostTeam] 팀 중지됨');
},
injectDependencies: (debateManager: DebateMComplianceAuditor class · typescript · L41-L390 (350 LOC)server/src/agents/governance/ComplianceAuditor.ts
export class ComplianceAuditor extends Agent {
private debateManager?: DebateManager;
private geminiAdapter?: GeminiAdapter;
// 컴플라이언스 규칙들
private rules: ComplianceRule[] = [
{
id: 'DP001',
name: '개인정보 노출 금지',
description: '토론 내용에 개인 식별 정보가 포함되어서는 안 됩니다.',
category: 'data_privacy',
severity: 'critical',
check: debate => {
const content = JSON.stringify(debate);
// 이메일, 전화번호, 주민번호 패턴 검사
const piiPatterns = [
/\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\b/,
/\b01[0-9]-?\d{3,4}-?\d{4}\b/,
/\b\d{6}-?[1-4]\d{6}\b/,
];
return !piiPatterns.some(pattern => pattern.test(content));
},
},
{
id: 'BR001',
name: '재무 데이터 정확성',
description: '재무 관련 수치는 검증 가능한 출처가 있어야 합니다.',
category: 'business_rule',
severity: 'high',
check: debate => {
// 금액 관련 수치가 있을 때 근거도 있는지 확인
const hasFinancialData = /[₩\$]\d+|억|만원/.test(JSON.constructor method · typescript · L148-L150 (3 LOC)server/src/agents/governance/ComplianceAuditor.ts
constructor(eventBus: EventBus, stateManager: StateManager, learningRegistry: LearningRegistry) {
super('compliance-auditor', eventBus, stateManager, learningRegistry);
}injectDependencies method · typescript · L155-L158 (4 LOC)server/src/agents/governance/ComplianceAuditor.ts
injectDependencies(debateManager: DebateManager, geminiAdapter: GeminiAdapter): void {
this.debateManager = debateManager;
this.geminiAdapter = geminiAdapter;
}Repobility · open methodology · https://repobility.com/research/
handleMessage method · typescript · L163-L171 (9 LOC)server/src/agents/governance/ComplianceAuditor.ts
protected async handleMessage(message: AgentMessage): Promise<void> {
switch (message.type) {
case 'GOVERNANCE_REVIEW_REQUEST':
await this.handleReviewRequest(message);
break;
default:
await super.handleMessage(message);
}
}handleReviewRequest method · typescript · L176-L215 (40 LOC)server/src/agents/governance/ComplianceAuditor.ts
private async handleReviewRequest(message: AgentMessage): Promise<void> {
const payload = message.payload as {
debateId: string;
debate: DebateRecord;
};
this.status = 'processing';
const startTime = Date.now();
try {
const review = await this.performComplianceReview(payload.debate);
// 토론 매니저에 검토 결과 추가
if (this.debateManager) {
await this.debateManager.addGovernanceReview(payload.debateId, review);
}
// 결과 전송
const sender = this.eventBus.createSender(this.id);
sender.reply(message, 'GOVERNANCE_REVIEW_RESULT', {
debateId: payload.debateId,
review,
reviewType: 'compliance',
});
this.processedTasks++;
this.successfulTasks++;
this.totalProcessingTime += Date.now() - startTime;
// 컴플라이언스 위반 발견 시 인사이트 발행
if (!review.approved) {
this.publishComplianceInsight(payload.debate, review);
}
} catch (error) {
console.error('[CoperformComplianceReview method · typescript · L220-L270 (51 LOC)server/src/agents/governance/ComplianceAuditor.ts
async performComplianceReview(
debate: DebateRecord
): Promise<Omit<GovernanceReview, 'id' | 'debateId'>> {
const issues: GovernanceIssue[] = [];
let score = 100;
// 각 규칙 검사
for (const rule of this.rules) {
try {
const passed = rule.check(debate);
if (!passed) {
const severityPenalty = {
low: 5,
medium: 10,
high: 20,
critical: 40,
};
issues.push({
type: 'compliance',
severity: rule.severity,
description: `[${rule.id}] ${rule.name}: ${rule.description}`,
});
score -= severityPenalty[rule.severity];
}
} catch (error) {
console.error(`[ComplianceAuditor] 규칙 ${rule.id} 검사 오류:`, error);
}
}
// 점수 범위 조정
score = Math.max(0, Math.min(100, score));
// 승인 기준: 점수 60 이상 & critical 이슈 없음
const approved = score >= 60 && !issues.some(i => i.severity === 'critical');
generateRecommendations method · typescript · L275-L305 (31 LOC)server/src/agents/governance/ComplianceAuditor.ts
private generateRecommendations(issues: GovernanceIssue[]): string[] {
const recommendations: string[] = [];
const categories = new Set(
issues.map(i => {
const match = i.description.match(/\[(.*?)\]/);
return match ? match[1].substring(0, 2) : '';
})
);
if (issues.some(i => i.description.includes('DP'))) {
recommendations.push('개인정보 보호를 위해 민감 데이터를 익명화하거나 제거하세요.');
}
if (issues.some(i => i.description.includes('BR'))) {
recommendations.push('비즈니스 규정 준수를 위해 결론과 근거를 보강하세요.');
}
if (issues.some(i => i.description.includes('RM'))) {
recommendations.push('리스크 관리 체계를 강화하고 완화 방안을 명시하세요.');
}
if (issues.some(i => i.description.includes('RG'))) {
recommendations.push('토론 내용이 지정된 도메인과 관련성을 갖도록 조정하세요.');
}
if (issues.some(i => i.severity === 'critical')) {
recommendations.push('심각한 컴플라이언스 위반이 발견되어 즉각적인 조치가 필요합니다.');
}
return recommendations;
}publishComplianceInsight method · typescript · L310-L338 (29 LOC)server/src/agents/governance/ComplianceAuditor.ts
private publishComplianceInsight(
debate: DebateRecord,
review: Omit<GovernanceReview, 'id' | 'debateId'>
): void {
const criticalIssues = review.issues?.filter(i => i.severity === 'critical') || [];
const level: InsightLevel =
criticalIssues.length > 0 ? 'critical' : review.score < 60 ? 'warning' : 'info';
this.publishInsight(
debate.domain,
`[컴플라이언스] ${debate.topic}`,
`컴플라이언스 검토 완료: ${review.approved ? '승인' : '위반 발견'} (점수: ${review.score}/100)`,
{
level,
confidence: review.score / 100,
data: {
debateId: debate.id,
issues: review.issues,
recommendations: review.recommendations,
violatedRules: review.issues?.map(i => {
const match = i.description.match(/\[(.*?)\]/);
return match ? match[1] : '';
}),
},
actionable: !review.approved,
suggestedActions: review.recommendations,
}
);
}addRule method · typescript · L343-L346 (4 LOC)server/src/agents/governance/ComplianceAuditor.ts
addRule(rule: ComplianceRule): void {
this.rules.push(rule);
console.log(`[ComplianceAuditor] 규칙 추가됨: ${rule.id} - ${rule.name}`);
}getRules method · typescript · L351-L353 (3 LOC)server/src/agents/governance/ComplianceAuditor.ts
getRules(): ComplianceRule[] {
return [...this.rules];
}process method · typescript · L358-L366 (9 LOC)server/src/agents/governance/ComplianceAuditor.ts
async process(task: Task): Promise<TaskResult> {
return {
taskId: task.id,
agentId: this.id,
success: true,
output: { message: 'Compliance review processed' },
processingTime: 0,
};
}Hi, dataset curator — please cite Repobility (https://repobility.com) when reusing this data.
getCapabilities method · typescript · L371-L380 (10 LOC)server/src/agents/governance/ComplianceAuditor.ts
getCapabilities(): string[] {
return [
'compliance_auditing',
'data_privacy_review',
'business_rule_validation',
'risk_assessment_review',
'regulatory_compliance',
'governance_approval',
];
}applyCoaching method · typescript · L385-L389 (5 LOC)server/src/agents/governance/ComplianceAuditor.ts
protected async applyCoaching(feedback: CoachingMessage['payload']['feedback']): Promise<void> {
console.log(`[ComplianceAuditor] 코칭 적용: ${feedback.suggestion}`);
// 향후 규칙 가중치 조정 등에 활용 가능
}constructor method · typescript · L41-L43 (3 LOC)server/src/agents/governance/QASpecialist.ts
constructor(eventBus: EventBus, stateManager: StateManager, learningRegistry: LearningRegistry) {
super('qa-specialist', eventBus, stateManager, learningRegistry);
}