From 6072142dbadb6cc8b721dcb988f77bbb2bbc478d Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Fri, 2 Jan 2026 12:11:00 -0600 Subject: [PATCH 1/3] feat: Add system/error message type handling to comms page MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add MessageType type alias ('user' | 'agent' | 'system' | 'error') - Add optional message_type field to ConversationMessage interface - Add getEffectiveMessageType() for backward compatibility with is_agent - Add getMessageStyles() helper for type-based styling - Add InfoIcon and WarningIcon components for system/error messages - Update message rendering: system (blue, centered), error (red, centered) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- apps/agui/app/comms/page.tsx | 87 ++++++++++++++++++++++++++++---- apps/agui/lib/ciris-sdk/types.ts | 3 ++ 2 files changed, 81 insertions(+), 9 deletions(-) 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/lib/ciris-sdk/types.ts b/apps/agui/lib/ciris-sdk/types.ts index 462e769..d33276e 100644 --- a/apps/agui/lib/ciris-sdk/types.ts +++ b/apps/agui/lib/ciris-sdk/types.ts @@ -163,6 +163,8 @@ export interface ResourceLimit { } // Conversation Types +export type MessageType = 'user' | 'agent' | 'system' | 'error'; + export interface ConversationMessage { id: string; content: string; @@ -171,6 +173,7 @@ export interface ConversationMessage { channel_id: string; timestamp: string; is_agent: boolean; + message_type?: MessageType; // Optional for backward compatibility } export interface ConversationHistory { From 179b4c4367bc5d5104fab77aa73f66a974185234 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 27 Jan 2026 22:08:13 -0600 Subject: [PATCH 2/3] feat: Add IDMA_RESULT and TSASPDMA_RESULT event handling (V1.9.3) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Types (types.ts): - Add IDMAResult interface (k_eff, correlation_risk, fragility_flag, phase) - Add TSASPDMAResult interface (tool_name, tool_parameters, reasoning, approved) Dashboard (page.tsx): - Add idma_result and tsaspdma_result to stageNames array - Add specialized rendering for IDMA with identity coherence metrics display - Add specialized rendering for TSASPDMA with tool info and approval status - Add stage indicators with defensive null checks for malformed events - Purple theme for IDMA, cyan theme for TSASPDMA, orange for fragility warnings 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- apps/agui/app/page.tsx | 203 ++++++++++++++++++++++++++++++- apps/agui/lib/ciris-sdk/types.ts | 16 +++ 2 files changed, 218 insertions(+), 1 deletion(-) diff --git a/apps/agui/app/page.tsx b/apps/agui/app/page.tsx index 30addb9..c0a80c2 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', 'aspdma_result', 'tsaspdma_result', 'conscience_result', 'action_result']; // Get stage number based on position const getStageNumber = (stageName: string): string => { @@ -499,6 +499,77 @@ export default function InteractPage() { return ; } + // Special rendering for idma_result (V1.9.3: Identity DMA) + if (stageName === 'idma_result') { + const kEff = data.k_eff ?? null; + const correlationRisk = data.correlation_risk ?? null; + const fragilityFlag = data.fragility_flag ?? false; + const phase = data.phase || 'unknown'; + + // Thresholds for identity stability + const kEffOk = kEff !== null && kEff > 0.7; + const correlationRiskOk = correlationRisk !== null && correlationRisk < 0.3; + + const otherFields = Object.keys(data).filter( + key => !['k_eff', 'correlation_risk', 'fragility_flag', 'phase'].includes(key) + ); + + return ( +
+ {/* Identity Status Header */} +
+
+
+ Identity Phase: {phase.toUpperCase()} +
+ {fragilityFlag && ( +
⚠️ Fragility Warning Active
+ )} +
+
+ + {/* Identity Metrics */} +
+
Identity Coherence Metrics:
+
+ {/* k_eff */} +
+
k_eff (Coherence)
+
{kEff !== null ? kEff.toFixed(3) : 'N/A'}
+
{kEffOk ? '✓ > 0.7' : '⚠ Should be > 0.7'}
+
+ + {/* Correlation Risk */} +
+
Correlation Risk
+
{correlationRisk !== null ? correlationRisk.toFixed(3) : 'N/A'}
+
{correlationRiskOk ? '✓ < 0.3' : '⚠ Should be < 0.3'}
+
+
+
+ + {/* 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 +620,86 @@ export default function InteractPage() { ); } + // Special rendering for tsaspdma_result (V1.9.3: Tool-Specific ASPDMA) + if (stageName === 'tsaspdma_result') { + const toolName = data.tool_name || 'UNKNOWN'; + const toolParameters = data.tool_parameters || {}; + const reasoning = data.reasoning || data.tsaspdma_reasoning || ''; + const approved = data.approved ?? data.tsaspdma_approved ?? null; + + const otherFields = Object.keys(data).filter( + key => !['tool_name', 'tool_parameters', 'reasoning', 'tsaspdma_reasoning', 'approved', 'tsaspdma_approved'].includes(key) + ); + + return ( +
+ {/* Tool Selection Header */} +
+
+
+ 🔧 {toolName} +
+ {approved !== null && ( +
+ {approved ? '✓ Approved for execution' : '✗ Not approved'} +
+ )} +
+
+ + {/* Tool Parameters */} + {Object.keys(toolParameters).length > 0 && ( +
+
Tool Parameters:
+
+ {Object.entries(toolParameters).map(([key, value]) => ( +
+ {key}: + {renderExpandableData(value, 2)} +
+ ))} +
+
+ )} + + {/* Reasoning */} + {reasoning && ( +
+
Reasoning:
+
+ {reasoning} +
+
+ )} + + {/* 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 +1339,17 @@ export default function InteractPage() { >E )} + {/* Show IDMA indicator */} + {stageName === 'idma_result' && ( + + {stage.data?.phase?.toUpperCase() || 'IDMA'} + {stage.data?.fragility_flag && ⚠️} + + )} {/* Show action label for ASPDMA */} {stageName === 'aspdma_result' && stage.data.selected_action && ( @@ -1195,6 +1357,20 @@ export default function InteractPage() { {stage.data.is_recursive && 🔁} )} + {/* Show TSASPDMA tool indicator */} + {stageName === 'tsaspdma_result' && ( + + 🔧 {stage.data?.tool_name || 'TOOL'} + {stage.data?.approved === true && } + {stage.data?.approved === false && } + + )} {/* Show conscience status */} {stageName === 'conscience_result' && ( E )} + {/* Show IDMA indicator */} + {stageName === 'idma_result' && ( + + {stage.data?.phase?.toUpperCase() || 'IDMA'} + {stage.data?.fragility_flag && ⚠️} + + )} {/* Show action label for ASPDMA */} {stageName === 'aspdma_result' && stage.data.selected_action && ( @@ -1449,6 +1636,20 @@ export default function InteractPage() { {stage.data.is_recursive && 🔁} )} + {/* Show TSASPDMA tool indicator */} + {stageName === 'tsaspdma_result' && ( + + 🔧 {stage.data?.tool_name || 'TOOL'} + {stage.data?.approved === true && } + {stage.data?.approved === false && } + + )} {/* Show conscience status */} {stageName === 'conscience_result' && ( ; + reasoning: string; + approved: boolean; +} + export interface ConscienceResult { conscience_name: string; passed: boolean; From 6f636c9a8fee0cfabe48d7ae100ec1c36db09045 Mon Sep 17 00:00:00 2001 From: Eric Moore Date: Tue, 27 Jan 2026 22:32:55 -0600 Subject: [PATCH 3/3] refactor: Update IDMA and TSASPDMA field names to V1.9.3 spec MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - IDMA: k_eff → epistemic_humility, correlation_risk → diversity_score, fragility_flag → is_fragile, added fragility_reason and correlation_factors - TSASPDMA: tool_name → original_tool_name/final_tool_name, tool_parameters → final_parameters, reasoning → tsaspdma_rationale, approved → final_action (tool/speak/ponder) - Updated stage order: TSASPDMA now comes before ASPDMA per spec 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- apps/agui/app/page.tsx | 177 +++++++++++++++++++++++++---------------- 1 file changed, 109 insertions(+), 68 deletions(-) diff --git a/apps/agui/app/page.tsx b/apps/agui/app/page.tsx index c0a80c2..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', 'idma_result', 'aspdma_result', 'tsaspdma_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 => { @@ -501,30 +501,34 @@ export default function InteractPage() { // Special rendering for idma_result (V1.9.3: Identity DMA) if (stageName === 'idma_result') { - const kEff = data.k_eff ?? null; - const correlationRisk = data.correlation_risk ?? null; - const fragilityFlag = data.fragility_flag ?? false; - const phase = data.phase || 'unknown'; + 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 kEffOk = kEff !== null && kEff > 0.7; - const correlationRiskOk = correlationRisk !== null && correlationRisk < 0.3; + const epistemicOk = epistemicHumility !== null && epistemicHumility > 0.7; + const diversityOk = diversityScore !== null && diversityScore > 0.5; const otherFields = Object.keys(data).filter( - key => !['k_eff', 'correlation_risk', 'fragility_flag', 'phase'].includes(key) + key => !['is_fragile', 'fragility_reason', 'epistemic_humility', 'diversity_score', 'correlation_factors'].includes(key) ); return (
{/* Identity Status Header */}
-
- Identity Phase: {phase.toUpperCase()} +
+ Identity Check: {isFragile ? 'FRAGILE' : 'STABLE'}
- {fragilityFlag && ( + {isFragile && fragilityReason && ( +
⚠️ {fragilityReason}
+ )} + {isFragile && !fragilityReason && (
⚠️ Fragility Warning Active
)}
@@ -534,22 +538,36 @@ export default function InteractPage() {
Identity Coherence Metrics:
- {/* k_eff */} -
-
k_eff (Coherence)
-
{kEff !== null ? kEff.toFixed(3) : 'N/A'}
-
{kEffOk ? '✓ > 0.7' : '⚠ Should be > 0.7'}
+ {/* Epistemic Humility */} +
+
Epistemic Humility
+
{epistemicHumility !== null ? (epistemicHumility * 100).toFixed(0) + '%' : 'N/A'}
+
{epistemicOk ? '✓ High confidence' : '⚠ Low confidence'}
- {/* Correlation Risk */} -
-
Correlation Risk
-
{correlationRisk !== null ? correlationRisk.toFixed(3) : 'N/A'}
-
{correlationRiskOk ? '✓ < 0.3' : '⚠ Should be < 0.3'}
+ {/* 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 && (
@@ -622,45 +640,62 @@ export default function InteractPage() { // Special rendering for tsaspdma_result (V1.9.3: Tool-Specific ASPDMA) if (stageName === 'tsaspdma_result') { - const toolName = data.tool_name || 'UNKNOWN'; - const toolParameters = data.tool_parameters || {}; - const reasoning = data.reasoning || data.tsaspdma_reasoning || ''; - const approved = data.approved ?? data.tsaspdma_approved ?? null; + 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 => !['tool_name', 'tool_parameters', 'reasoning', 'tsaspdma_reasoning', 'approved', 'tsaspdma_approved'].includes(key) + key => !['original_tool_name', 'final_action', 'final_tool_name', 'final_parameters', 'tsaspdma_rationale'].includes(key) ); return (
- {/* Tool Selection Header */} + {/* Tool Validation Header */}
- 🔧 {toolName} + 🔧 Tool Validation +
+
+ Tool: {finalToolName} + {originalToolName !== finalToolName && ( + (was: {originalToolName}) + )} +
+
+ Status: {isApproved ? '✅ Approved' : needsClarification ? '⚠️ Needs Clarification' : isReconsidering ? '🔄 Reconsidering' : 'Unknown'}
- {approved !== null && ( -
- {approved ? '✓ Approved for execution' : '✗ Not approved'} -
- )}
- {/* Tool Parameters */} - {Object.keys(toolParameters).length > 0 && ( + {/* Final Parameters */} + {Object.keys(finalParameters).length > 0 && (
-
Tool Parameters:
+
Final Parameters:
- {Object.entries(toolParameters).map(([key, value]) => ( + {Object.entries(finalParameters).map(([key, value]) => (
{key}: {renderExpandableData(value, 2)} @@ -671,11 +706,11 @@ export default function InteractPage() { )} {/* Reasoning */} - {reasoning && ( + {rationale && (
Reasoning:
- {reasoning} + {rationale}
)} @@ -1342,12 +1377,12 @@ export default function InteractPage() { {/* Show IDMA indicator */} {stageName === 'idma_result' && ( - {stage.data?.phase?.toUpperCase() || 'IDMA'} - {stage.data?.fragility_flag && ⚠️} + }`} title={`Confidence: ${stage.data?.epistemic_humility ? (stage.data.epistemic_humility * 100).toFixed(0) + '%' : 'N/A'}`}> + {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 */} @@ -1360,15 +1395,18 @@ export default function InteractPage() { {/* Show TSASPDMA tool indicator */} {stageName === 'tsaspdma_result' && ( - 🔧 {stage.data?.tool_name || 'TOOL'} - {stage.data?.approved === true && } - {stage.data?.approved === false && } + : stage.data?.final_action === 'speak' + ? 'bg-yellow-100 text-yellow-800' + : stage.data?.final_action === 'ponder' + ? 'bg-blue-100 text-blue-800' + : 'bg-cyan-100 text-cyan-800' + }`} title={`Tool: ${stage.data?.final_tool_name || stage.data?.original_tool_name || 'Unknown'}`}> + 🔧 {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 */} @@ -1621,12 +1659,12 @@ export default function InteractPage() { {/* Show IDMA indicator */} {stageName === 'idma_result' && ( - {stage.data?.phase?.toUpperCase() || 'IDMA'} - {stage.data?.fragility_flag && ⚠️} + }`} title={`Confidence: ${stage.data?.epistemic_humility ? (stage.data.epistemic_humility * 100).toFixed(0) + '%' : 'N/A'}`}> + {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 */} @@ -1639,15 +1677,18 @@ export default function InteractPage() { {/* Show TSASPDMA tool indicator */} {stageName === 'tsaspdma_result' && ( - 🔧 {stage.data?.tool_name || 'TOOL'} - {stage.data?.approved === true && } - {stage.data?.approved === false && } + : stage.data?.final_action === 'speak' + ? 'bg-yellow-100 text-yellow-800' + : stage.data?.final_action === 'ponder' + ? 'bg-blue-100 text-blue-800' + : 'bg-cyan-100 text-cyan-800' + }`} title={`Tool: ${stage.data?.final_tool_name || stage.data?.original_tool_name || 'Unknown'}`}> + 🔧 {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 */}