From 1c51ae4abb877c7bc80f2f35e654fd19a4d3deff Mon Sep 17 00:00:00 2001 From: Markus Date: Thu, 11 Sep 2025 14:50:44 -0700 Subject: [PATCH] Fixes for containers --- data/agent_teams/default_team - Copy.json | 117 --------- data/agent_teams/retail - Copy.json | 89 ------- src/frontend/src/services/PlanDataService.tsx | 234 +++++++++++++----- 3 files changed, 169 insertions(+), 271 deletions(-) delete mode 100644 data/agent_teams/default_team - Copy.json delete mode 100644 data/agent_teams/retail - Copy.json diff --git a/data/agent_teams/default_team - Copy.json b/data/agent_teams/default_team - Copy.json deleted file mode 100644 index 80f3b9171..000000000 --- a/data/agent_teams/default_team - Copy.json +++ /dev/null @@ -1,117 +0,0 @@ -{ - "id": "10", - "team_id": "team-business-operations", - "name": "Business Operations Team2", - "status": "visible", - "created": "2025-08-05T00:00:00.000Z", - "created_by": "Admin", - "agents": [ - { - "input_key": "hr-agent-001", - "type": "HR", - "name": "HR Specialist", - "deployment_name": "gpt-4o", - "system_message": "You are an AI Agent. You have knowledge about HR (e.g., human resources), policies, procedures, and onboarding guidelines.", - "description": "Handles employee onboarding, HR policies, and human resources management tasks.", - "icon": "Person", - "index_name": "", - "use_rag": false, - "use_mcp": false, - "coding_tools": false, - "use_bing": false - }, - { - "input_key": "tech-support-001", - "type": "TechSupport", - "name": "Tech Support Specialist", - "deployment_name": "gpt-4o", - "system_message": "You are a Product agent. You have knowledge about product management, development, and compliance guidelines. When asked to call a function, you should summarize back what was done.", - "description": "Provides technical support for mobile plans, telecommunications, and IT services.", - "icon": "Phone", - "index_name": "", - "use_rag": false, - "use_mcp": false, - "coding_tools": false, - "use_bing": false - }, - { - "input_key": "procurement-001", - "type": "Procurement", - "name": "Procurement Specialist", - "deployment_name": "gpt-4o", - "system_message": "You are a Procurement agent. You specialize in purchasing, vendor management, supply chain operations, and inventory control. You help with creating purchase orders, managing vendors, tracking orders, and ensuring efficient procurement processes.", - "description": "Manages purchasing decisions, add-ons, and procurement processes.", - "icon": "ShoppingBag", - "index_name": "", - "use_rag": false, - "use_mcp": false, - "coding_tools": false, - "use_bing": false - }, - { - "input_key": "marketing-001", - "type": "Marketing", - "name": "Marketing Specialist", - "deployment_name": "gpt-4o", - "system_message": "You are a Marketing agent. You specialize in marketing strategy, campaign development, content creation, and market analysis. You help create effective marketing campaigns, analyze market data, and develop promotional content for products and services.", - "description": "Creates marketing content, press releases, and promotional materials.", - "icon": "DocumentEdit", - "index_name": "", - "use_rag": false, - "use_mcp": false, - "coding_tools": false, - "use_bing": false - }, - { - "input_key": "generic-001", - "type": "Generic", - "name": "General Assistant", - "deployment_name": "gpt-4o", - "system_message": "You are a Generic agent that can help with general questions and provide basic information. You can search for information and perform simple calculations.", - "description": "Provides general assistance and handles miscellaneous tasks that don't require specialized expertise.", - "icon": "Bot", - "index_name": "", - "use_rag": false, - "use_mcp": false, - "coding_tools": false, - "use_bing": false - } - ], - "description": "Business Operations team handles employee onboarding, telecommunications support, procurement, and marketing tasks for comprehensive business operations management.", - "logo": "Building", - "plan": "Multi-agent business operations plan covering HR, tech support, procurement, and marketing activities", - "starting_tasks": [ - { - "id": "onboard", - "name": "Onboard employee", - "prompt": "Onboard a new employee, Jessica Smith.", - "created": "2025-08-05T00:00:00.000Z", - "creator": "system", - "logo": "Person" - }, - { - "id": "mobile", - "name": "Mobile plan query", - "prompt": "Ask about roaming plans prior to heading overseas.", - "created": "2025-08-05T00:00:00.000Z", - "creator": "system", - "logo": "Phone" - }, - { - "id": "addon", - "name": "Buy add-on", - "prompt": "Enable roaming on mobile plan, starting next week.", - "created": "2025-08-05T00:00:00.000Z", - "creator": "system", - "logo": "ShoppingBag" - }, - { - "id": "press", - "name": "Draft a press release", - "prompt": "Write a press release about our current products.", - "created": "2025-08-05T00:00:00.000Z", - "creator": "system", - "logo": "DocumentEdit" - } - ] -} \ No newline at end of file diff --git a/data/agent_teams/retail - Copy.json b/data/agent_teams/retail - Copy.json deleted file mode 100644 index 8963a3188..000000000 --- a/data/agent_teams/retail - Copy.json +++ /dev/null @@ -1,89 +0,0 @@ -{ - "id": "3", - "team_id": "team-3", - "name": "Retail Customer Success Team2", - "status": "visible", - "created": "", - "created_by": "", - "agents": [ - { - "input_key": "", - "type": "", - "name": "CustomerDataAgent", - "deployment_name": "gpt-4.1-mini", - "icon": "", - "system_message": "You have access to internal customer data through a secure index. Use this data to answer questions about customers, their interactions with customer service, satisfaction, etc. Be mindful of privacy and compliance regulations when handling customer data.", - "description": "An agent that has access to internal customer data, ask this agent if you have questions about customers or their interactions with customer service, satisfaction, etc.", - "use_rag": true, - "use_mcp": false, - "use_bing": false, - "use_reasoning": false, - "index_name": "macae-index", - "index_foundry_name": "", - "index_endpoint": "", - "coding_tools": false - }, - { - "input_key": "", - "type": "", - "name": "OrderDataAgent", - "deployment_name": "gpt-4.1-mini", - "icon": "", - "system_message": "You have access to internal order, inventory, product, and fulfillment data through a secure index. Use this data to answer questions about products, shipping delays, customer orders, warehouse management, etc. Be mindful of privacy and compliance regulations when handling customer data.", - "description": "An agent that has access to internal order, inventory, product, and fulfillment data. Ask this agent if you have questions about products, shipping delays, customer orders, warehouse management, etc.", - "use_rag": true, - "use_mcp": false, - "use_bing": false, - "use_reasoning": false, - "index_name": "macae-index", - "index_foundry_name": "", - "coding_tools": true - }, - { - "input_key": "", - "type": "", - "name": "AnalysisRecommendationAgent", - "deployment_name": "o4-mini", - "icon": "", - "system_message": "You are a reasoning agent that can analyze customer data and provide recommendations for improving customer satisfaction and retention. You do not have access to any data sources, but you can reason based on the information provided to you by other agents. Use your reasoning skills to identify patterns, trends, and insights that can help improve customer satisfaction and retention. Provide actionable recommendations based on your analysis. You have access to other agents that can answer questions and provide data about customers, products, orders, inventory, and fulfilment. Use these agents to gather information as needed.", - "description": "A reasoning agent that can analyze customer data and provide recommendations for improving customer satisfaction and retention.", - "use_rag": false, - "use_mcp": false, - "use_bing": false, - "use_reasoning": true, - "index_name": "", - "index_foundry_name": "", - "coding_tools": false - }, - { - "input_key": "", - "type": "", - "name": "ProxyAgent", - "deployment_name": "", - "icon": "", - "system_message": "", - "description": "", - "use_rag": false, - "use_mcp": false, - "use_bing": false, - "use_reasoning": false, - "index_name": "", - "index_foundry_name": "", - "coding_tools": false - } - ], - "protected": false, - "description": "Team focused on individualized customer relationship management and overall customer satisfaction.", - "logo": "", - "plan": "", - "starting_tasks": [ - { - "id": "task-1", - "name": "Satisfaction Plan", - "prompt": "Analyze the satisfaction of Emily Thompson with Contoso. If needed, provide a plan to increase her satisfaction.", - "created": "", - "creator": "", - "logo": "" - } - ] -} \ No newline at end of file diff --git a/src/frontend/src/services/PlanDataService.tsx b/src/frontend/src/services/PlanDataService.tsx index 1449cfe9e..dff5c2ba9 100644 --- a/src/frontend/src/services/PlanDataService.tsx +++ b/src/frontend/src/services/PlanDataService.tsx @@ -362,6 +362,7 @@ export class PlanDataService { * Parse an agent message object or repr string: * Input forms supported: * - { type: 'agent_message', data: "AgentMessage(agent_name='X', timestamp=..., content='...')"} + * - { type: 'agent_message', data: { agent_name: 'X', timestamp: 12345, content: '...' } } * - "AgentMessage(agent_name='X', timestamp=..., content='...')" * Returns a structured object with steps parsed from markdown-ish content. */ @@ -380,11 +381,62 @@ export class PlanDataService { raw_data: any; } | null { try { - // Unwrap wrapper - if (rawData && typeof rawData === 'object' && rawData.type === WebsocketMessageType.AGENT_MESSAGE && typeof rawData.data === 'string') { - return this.parseAgentMessage(rawData.data); + // Handle JSON string input - parse it first + if (typeof rawData === 'string' && rawData.startsWith('{')) { + try { + rawData = JSON.parse(rawData); + } catch (e) { + console.error('Failed to parse JSON string:', e); + // Fall through to handle as regular string + } + } + + // Unwrap wrapper - handle object format + if (rawData && typeof rawData === 'object' && rawData.type === WebsocketMessageType.AGENT_MESSAGE) { + if (typeof rawData.data === 'object' && rawData.data.agent_name) { + // New format: { type: 'agent_message', data: { agent_name: '...', timestamp: 123, content: '...' } } + const data = rawData.data; + const content = data.content || ''; + const timestamp = typeof data.timestamp === 'number' ? data.timestamp : null; + + // Parse the content for steps and next_steps (reuse existing logic) + const { steps, next_steps } = this.parseContentForStepsAndNextSteps(content); + + return { + agent: data.agent_name || 'UnknownAgent', + agent_type: AgentMessageType.AI_AGENT, + timestamp, + steps, + next_steps, + content, + raw_data: rawData + }; + } else if (typeof rawData.data === 'string') { + // Old format: { type: 'agent_message', data: "AgentMessage(...)" } + return this.parseAgentMessage(rawData.data); + } } + // Handle direct object format + if (rawData && typeof rawData === 'object' && rawData.agent_name) { + const content = rawData.content || ''; + const timestamp = typeof rawData.timestamp === 'number' ? rawData.timestamp : null; + + // Parse the content for steps and next_steps + const { steps, next_steps } = this.parseContentForStepsAndNextSteps(content); + + return { + agent: rawData.agent_name || 'UnknownAgent', + agent_type: AgentMessageType.AI_AGENT, + timestamp, + steps, + next_steps, + content, + raw_data: rawData + }; + } + + // Handle old string format: "AgentMessage(...)" if (typeof rawData !== 'string') return null; if (!rawData.startsWith('AgentMessage(')) return null; @@ -409,70 +461,15 @@ export class PlanDataService { .replace(/\\"/g, '"') .replace(/\\\\/g, '\\'); - // Parse sections of the form "##### Title Completed" - // Each block ends at --- line or next "##### " or end. - const lines = content.split('\n'); - const steps: Array<{ title: string; fields: Record; summary?: string; raw_block: string; }> = []; - let i = 0; - while (i < lines.length) { - const headingMatch = lines[i].match(/^#####\s+(.+?)\s+Completed\s*$/i); - if (headingMatch) { - const title = headingMatch[1].trim(); - const blockLines: string[] = []; - i++; - while (i < lines.length && !/^---\s*$/.test(lines[i]) && !/^#####\s+/.test(lines[i])) { - blockLines.push(lines[i]); - i++; - } - // Skip separator line if present - if (i < lines.length && /^---\s*$/.test(lines[i])) i++; - - const fields: Record = {}; - let summary: string | undefined; - for (const bl of blockLines) { - const fieldMatch = bl.match(/^\*\*(.+?)\*\*:\s*(.*)$/); - if (fieldMatch) { - const fieldName = fieldMatch[1].trim().replace(/:$/, ''); - const value = fieldMatch[2].trim().replace(/\\s+$/, ''); - if (fieldName) fields[fieldName] = value; - } else { - const summaryMatch = bl.match(/^AGENT SUMMARY:\s*(.+)$/i); - if (summaryMatch) { - summary = summaryMatch[1].trim(); - } - } - } - - steps.push({ - title, - fields, - summary, - raw_block: blockLines.join('\n').trim() - }); - } else { - i++; - } - } - - // Next Steps section - const nextSteps: string[] = []; - const nextIdx = lines.findIndex(l => /^Next Steps:/.test(l.trim())); - if (nextIdx !== -1) { - for (let j = nextIdx + 1; j < lines.length; j++) { - const l = lines[j].trim(); - if (!l) continue; - if (/^[-*]\s+/.test(l)) { - nextSteps.push(l.replace(/^[-*]\s+/, '').trim()); - } - } - } + // Parse the content for steps and next_steps + const { steps, next_steps } = this.parseContentForStepsAndNextSteps(content); return { agent, agent_type: AgentMessageType.AI_AGENT, timestamp, steps, - next_steps: nextSteps, + next_steps, content, raw_data: rawData }; @@ -481,12 +478,86 @@ export class PlanDataService { return null; } } - // ...inside export class PlanDataService { (place near other parsers) + + /** + * Helper method to parse content for steps and next_steps + * Extracted to avoid code duplication + */ + private static parseContentForStepsAndNextSteps(content: string): { + steps: Array<{ + title: string; + fields: Record; + summary?: string; + raw_block: string; + }>; + next_steps: string[]; + } { + // Parse sections of the form "##### Title Completed" + // Each block ends at --- line or next "##### " or end. + const lines = content.split('\n'); + const steps: Array<{ title: string; fields: Record; summary?: string; raw_block: string; }> = []; + let i = 0; + while (i < lines.length) { + const headingMatch = lines[i].match(/^#####\s+(.+?)\s+Completed\s*$/i); + if (headingMatch) { + const title = headingMatch[1].trim(); + const blockLines: string[] = []; + i++; + while (i < lines.length && !/^---\s*$/.test(lines[i]) && !/^#####\s+/.test(lines[i])) { + blockLines.push(lines[i]); + i++; + } + // Skip separator line if present + if (i < lines.length && /^---\s*$/.test(lines[i])) i++; + + const fields: Record = {}; + let summary: string | undefined; + for (const bl of blockLines) { + const fieldMatch = bl.match(/^\*\*(.+?)\*\*:\s*(.*)$/); + if (fieldMatch) { + const fieldName = fieldMatch[1].trim().replace(/:$/, ''); + const value = fieldMatch[2].trim().replace(/\\s+$/, ''); + if (fieldName) fields[fieldName] = value; + } else { + const summaryMatch = bl.match(/^AGENT SUMMARY:\s*(.+)$/i); + if (summaryMatch) { + summary = summaryMatch[1].trim(); + } + } + } + + steps.push({ + title, + fields, + summary, + raw_block: blockLines.join('\n').trim() + }); + } else { + i++; + } + } + + // Next Steps section + const next_steps: string[] = []; + const nextIdx = lines.findIndex(l => /^Next Steps:/.test(l.trim())); + if (nextIdx !== -1) { + for (let j = nextIdx + 1; j < lines.length; j++) { + const l = lines[j].trim(); + if (!l) continue; + if (/^[-*]\s+/.test(l)) { + next_steps.push(l.replace(/^[-*]\s+/, '').trim()); + } + } + } + + return { steps, next_steps }; + } /** * Parse streaming agent message fragments. * Supports: * - { type: 'agent_message_streaming', data: "AgentMessageStreaming(agent_name='X', content='partial', is_final=False)" } + * - { type: 'agent_message_streaming', data: { agent_name: 'X', content: 'partial', is_final: true } } * - "AgentMessageStreaming(agent_name='X', content='partial', is_final=False)" */ static parseAgentMessageStreaming(rawData: any): { @@ -496,11 +567,44 @@ export class PlanDataService { raw_data: any; } | null { try { - // Unwrap wrapper - if (rawData && typeof rawData === 'object' && rawData.type === 'agent_message_streaming' && typeof rawData.data === 'string') { - return this.parseAgentMessageStreaming(rawData.data); + // Handle JSON string input - parse it first + if (typeof rawData === 'string' && rawData.startsWith('{')) { + try { + rawData = JSON.parse(rawData); + } catch (e) { + console.error('Failed to parse JSON string:', e); + // Fall through to handle as regular string + } + } + + // Unwrap wrapper - handle object format + if (rawData && typeof rawData === 'object' && rawData.type === 'agent_message_streaming') { + if (typeof rawData.data === 'object' && rawData.data.agent_name) { + // New format: { type: 'agent_message_streaming', data: { agent_name: '...', content: '...', is_final: true } } + const data = rawData.data; + return { + agent: data.agent_name || 'UnknownAgent', + content: data.content || '', + is_final: Boolean(data.is_final), + raw_data: rawData + }; + } else if (typeof rawData.data === 'string') { + // Old format: { type: 'agent_message_streaming', data: "AgentMessageStreaming(...)" } + return this.parseAgentMessageStreaming(rawData.data); + } + } + + // Handle direct object format + if (rawData && typeof rawData === 'object' && rawData.agent_name) { + return { + agent: rawData.agent_name || 'UnknownAgent', + content: rawData.content || '', + is_final: Boolean(rawData.is_final), + raw_data: rawData + }; } + // Handle old string format: "AgentMessageStreaming(...)" if (typeof rawData !== 'string') return null; if (!rawData.startsWith('AgentMessageStreaming(')) return null;