diff --git a/apps/agui/app/comms/page.tsx b/apps/agui/app/comms/page.tsx index 6fa843f..45bb632 100644 --- a/apps/agui/app/comms/page.tsx +++ b/apps/agui/app/comms/page.tsx @@ -10,6 +10,64 @@ import { useAgent } from '../../contexts/AgentContextHybrid'; import { NoAgentsPlaceholder } from '../../components/NoAgentsPlaceholder'; import { extractErrorMessage, getDiscordInvite } from '../../lib/utils/error-helpers'; import { ErrorModal } from '../../components/ErrorModal'; +import type { ConversationMessage, MessageType } from '../../lib/ciris-sdk/types'; + +// Helper to get effective message type (backward compatible with is_agent) +function getEffectiveMessageType(msg: ConversationMessage): MessageType { + if (msg.message_type) return msg.message_type; + return msg.is_agent ? 'agent' : 'user'; +} + +// Helper to get message styles based on type +function getMessageStyles(type: MessageType) { + switch (type) { + case 'user': + return { + container: 'justify-end', + bubble: 'bg-blue-600 text-white', + meta: 'text-blue-100', + icon: null, + }; + case 'agent': + return { + container: 'justify-start', + bubble: 'bg-white border border-gray-200', + meta: 'text-gray-500', + icon: null, + }; + case 'system': + return { + container: 'justify-center', + bubble: 'bg-blue-50 border border-blue-200 text-blue-700', + meta: 'text-blue-500', + icon: 'info', + }; + case 'error': + return { + container: 'justify-center', + bubble: 'bg-red-50 border border-red-200 text-red-700', + meta: 'text-red-500', + icon: 'warning', + }; + } +} + +// Icon components for system/error messages +function InfoIcon() { + return ( + + + + ); +} + +function WarningIcon() { + return ( + + + + ); +} export default function CommsPage() { const { user } = useAuth(); @@ -212,22 +270,33 @@ export default function CommsPage() { // Debug log to see message structure if (idx === 0) console.log('Message structure:', msg); + const msgType = getEffectiveMessageType(msg); + const styles = getMessageStyles(msgType); + + // Determine author display + const authorDisplay = msg.author || ( + msgType === 'user' ? 'You' : + msgType === 'agent' ? 'CIRIS' : + msgType === 'system' ? 'System' : + 'Error' + ); + return (
-
- {msg.author || (msg.is_agent ? 'CIRIS' : 'You')} • {new Date(msg.timestamp).toLocaleTimeString()} +
+ {authorDisplay} • {new Date(msg.timestamp).toLocaleTimeString()} +
+
+ {styles.icon === 'info' && } + {styles.icon === 'warning' && } + {msg.content}
-
{msg.content}
); diff --git a/apps/agui/app/page.tsx b/apps/agui/app/page.tsx index 30addb9..6ec6d89 100644 --- a/apps/agui/app/page.tsx +++ b/apps/agui/app/page.tsx @@ -261,7 +261,7 @@ export default function InteractPage() { sendMessageMutation.mutate(msgToSend); }; - const stageNames = ['thought_start', 'snapshot_and_context', 'dma_results', 'aspdma_result', 'conscience_result', 'action_result']; + const stageNames = ['thought_start', 'snapshot_and_context', 'dma_results', 'idma_result', 'tsaspdma_result', 'aspdma_result', 'conscience_result', 'action_result']; // Get stage number based on position const getStageNumber = (stageName: string): string => { @@ -499,6 +499,95 @@ export default function InteractPage() { return ; } + // Special rendering for idma_result (V1.9.3: Identity DMA) + if (stageName === 'idma_result') { + const isFragile = data.is_fragile ?? false; + const fragilityReason = data.fragility_reason ?? null; + const epistemicHumility = data.epistemic_humility ?? null; + const diversityScore = data.diversity_score ?? null; + const correlationFactors = data.correlation_factors ?? []; + + // Thresholds for identity stability + const epistemicOk = epistemicHumility !== null && epistemicHumility > 0.7; + const diversityOk = diversityScore !== null && diversityScore > 0.5; + + const otherFields = Object.keys(data).filter( + key => !['is_fragile', 'fragility_reason', 'epistemic_humility', 'diversity_score', 'correlation_factors'].includes(key) + ); + + return ( +
+ {/* Identity Status Header */} +
+
+
+ Identity Check: {isFragile ? 'FRAGILE' : 'STABLE'} +
+ {isFragile && fragilityReason && ( +
⚠️ {fragilityReason}
+ )} + {isFragile && !fragilityReason && ( +
⚠️ Fragility Warning Active
+ )} +
+
+ + {/* Identity Metrics */} +
+
Identity Coherence Metrics:
+
+ {/* Epistemic Humility */} +
+
Epistemic Humility
+
{epistemicHumility !== null ? (epistemicHumility * 100).toFixed(0) + '%' : 'N/A'}
+
{epistemicOk ? '✓ High confidence' : '⚠ Low confidence'}
+
+ + {/* Diversity Score */} +
+
DMA Diversity
+
{diversityScore !== null ? (diversityScore * 100).toFixed(0) + '%' : 'N/A'}
+
{diversityOk ? '✓ Good agreement' : '⚠ Low agreement'}
+
+
+
+ + {/* Correlation Factors */} + {correlationFactors.length > 0 && ( +
+
Correlation Factors:
+
+ {correlationFactors.map((factor: string, idx: number) => ( + + {factor} + + ))} +
+
+ )} + + {/* Other fields under "View details" */} + {otherFields.length > 0 && ( +
+ + 📋 View details ({otherFields.length} more fields) + +
+ {otherFields.map(field => ( +
+ {field}: + {renderExpandableData(data[field], 2)} +
+ ))} +
+
+ )} +
+ ); + } + // Special rendering for aspdma_result if (stageName === 'aspdma_result') { // Extract action name, removing "HandlerActionType." prefix if present @@ -549,6 +638,103 @@ export default function InteractPage() { ); } + // Special rendering for tsaspdma_result (V1.9.3: Tool-Specific ASPDMA) + if (stageName === 'tsaspdma_result') { + const originalToolName = data.original_tool_name || 'UNKNOWN'; + const finalAction = data.final_action || 'tool'; // "tool", "speak", or "ponder" + const finalToolName = data.final_tool_name || originalToolName; + const finalParameters = data.final_parameters || {}; + const rationale = data.tsaspdma_rationale || ''; + + // Derive status from final_action + const isApproved = finalAction === 'tool'; + const needsClarification = finalAction === 'speak'; + const isReconsidering = finalAction === 'ponder'; + + const otherFields = Object.keys(data).filter( + key => !['original_tool_name', 'final_action', 'final_tool_name', 'final_parameters', 'tsaspdma_rationale'].includes(key) + ); + + return ( +
+ {/* Tool Validation Header */} +
+
+
+ 🔧 Tool Validation +
+
+ Tool: {finalToolName} + {originalToolName !== finalToolName && ( + (was: {originalToolName}) + )} +
+
+ Status: {isApproved ? '✅ Approved' : needsClarification ? '⚠️ Needs Clarification' : isReconsidering ? '🔄 Reconsidering' : 'Unknown'} +
+
+
+ + {/* Final Parameters */} + {Object.keys(finalParameters).length > 0 && ( +
+
Final Parameters:
+
+ {Object.entries(finalParameters).map(([key, value]) => ( +
+ {key}: + {renderExpandableData(value, 2)} +
+ ))} +
+
+ )} + + {/* Reasoning */} + {rationale && ( +
+
Reasoning:
+
+ {rationale} +
+
+ )} + + {/* Other fields under "View details" */} + {otherFields.length > 0 && ( +
+ + 📋 View details ({otherFields.length} more fields) + +
+ {otherFields.map(field => ( +
+ {field}: + {renderExpandableData(data[field], 2)} +
+ ))} +
+
+ )} +
+ ); + } + // Special rendering for conscience_result if (stageName === 'conscience_result') { const consciencePassed = data.conscience_passed; @@ -1188,6 +1374,17 @@ export default function InteractPage() { >E )} + {/* Show IDMA indicator */} + {stageName === 'idma_result' && ( + + {stage.data?.is_fragile ? 'FRAGILE' : `${stage.data?.epistemic_humility ? (stage.data.epistemic_humility * 100).toFixed(0) + '%' : 'IDMA'}`} + {stage.data?.is_fragile && ⚠️} + + )} {/* Show action label for ASPDMA */} {stageName === 'aspdma_result' && stage.data.selected_action && ( @@ -1195,6 +1392,23 @@ export default function InteractPage() { {stage.data.is_recursive && 🔁} )} + {/* Show TSASPDMA tool indicator */} + {stageName === 'tsaspdma_result' && ( + + 🔧 {stage.data?.final_tool_name || stage.data?.original_tool_name || 'TOOL'} + {stage.data?.final_action === 'tool' && } + {stage.data?.final_action === 'speak' && } + {stage.data?.final_action === 'ponder' && 🔄} + + )} {/* Show conscience status */} {stageName === 'conscience_result' && ( E )} + {/* Show IDMA indicator */} + {stageName === 'idma_result' && ( + + {stage.data?.is_fragile ? 'FRAGILE' : `${stage.data?.epistemic_humility ? (stage.data.epistemic_humility * 100).toFixed(0) + '%' : 'IDMA'}`} + {stage.data?.is_fragile && ⚠️} + + )} {/* Show action label for ASPDMA */} {stageName === 'aspdma_result' && stage.data.selected_action && ( @@ -1449,6 +1674,23 @@ export default function InteractPage() { {stage.data.is_recursive && 🔁} )} + {/* Show TSASPDMA tool indicator */} + {stageName === 'tsaspdma_result' && ( + + 🔧 {stage.data?.final_tool_name || stage.data?.original_tool_name || 'TOOL'} + {stage.data?.final_action === 'tool' && } + {stage.data?.final_action === 'speak' && } + {stage.data?.final_action === 'ponder' && 🔄} + + )} {/* Show conscience status */} {stageName === 'conscience_result' && ( ; + reasoning: string; + approved: boolean; +} + export interface ConscienceResult { conscience_name: string; passed: boolean;