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;