feat: enhance AI communication with dynamic system prompts, robust retry, and TUI formatters
This commit is contained in:
72
bin/ui/components/ChatBubble.mjs.backup
Normal file
72
bin/ui/components/ChatBubble.mjs.backup
Normal file
@@ -0,0 +1,72 @@
|
||||
import React from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
|
||||
const h = React.createElement;
|
||||
|
||||
const ChatBubble = ({ role, content, meta, width, children }) => {
|
||||
// Calculate safe content width accounting for gutter
|
||||
const contentWidth = width ? width - 2 : undefined; // Account for left gutter only
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// USER MESSAGE - Clean text-focused presentation
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
if (role === 'user') {
|
||||
return h(Box, {
|
||||
width: width,
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'flex-end',
|
||||
marginBottom: 1,
|
||||
paddingLeft: 2
|
||||
},
|
||||
h(Text, { color: 'cyan', wrap: 'wrap' }, content)
|
||||
);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// SYSTEM - MINIMALIST TOAST
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
if (role === 'system') {
|
||||
return h(Box, { width: width, justifyContent: 'center', marginBottom: 1 },
|
||||
h(Text, { color: 'gray', dimColor: true }, ` ${content} `)
|
||||
);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// ERROR - CLEAN GUTTER STYLE
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
if (role === 'error') {
|
||||
// Strip redundant "Error: " prefix if present in content
|
||||
const cleanContent = content.replace(/^Error:\s*/i, '');
|
||||
return h(Box, {
|
||||
width: width,
|
||||
flexDirection: 'row',
|
||||
marginBottom: 1
|
||||
},
|
||||
h(Box, { width: 1, marginRight: 1, backgroundColor: 'red' }),
|
||||
h(Text, { color: 'red', wrap: 'wrap' }, cleanContent)
|
||||
);
|
||||
}
|
||||
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
// ASSISTANT - Clean text-focused style (Opencode-like)
|
||||
// ═══════════════════════════════════════════════════════════════
|
||||
return h(Box, {
|
||||
width: width,
|
||||
flexDirection: 'row',
|
||||
marginBottom: 1
|
||||
},
|
||||
// Clean left gutter similar to opencode
|
||||
h(Box, { width: 2, marginRight: 1, borderStyle: 'single', borderRight: false, borderTop: false, borderBottom: false, borderLeftColor: 'green' }),
|
||||
|
||||
// Content area - text focused, no borders
|
||||
h(Box, {
|
||||
flexDirection: 'column',
|
||||
flexGrow: 1,
|
||||
minWidth: 10
|
||||
},
|
||||
children ? children : h(Text, { color: 'white', wrap: 'wrap' }, content)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ChatBubble;
|
||||
68
bin/ui/components/ThinkingBlock.mjs.backup
Normal file
68
bin/ui/components/ThinkingBlock.mjs.backup
Normal file
@@ -0,0 +1,68 @@
|
||||
import React, { useState, useEffect } from 'react';
|
||||
import { Box, Text } from 'ink';
|
||||
|
||||
const h = React.createElement;
|
||||
|
||||
const ThinkingBlock = ({
|
||||
lines = [],
|
||||
isThinking = false,
|
||||
stats = { chars: 0 },
|
||||
width = 80
|
||||
}) => {
|
||||
// If no thinking lines and not thinking, show nothing
|
||||
if (lines.length === 0 && !isThinking) return null;
|
||||
|
||||
// Show only last few lines to avoid clutter
|
||||
const visibleLines = lines.slice(-3); // Show cleaner view
|
||||
const hiddenCount = Math.max(0, lines.length - 3);
|
||||
|
||||
return h(Box, {
|
||||
flexDirection: 'row',
|
||||
width: width,
|
||||
marginBottom: 1,
|
||||
paddingLeft: 1 // Only left padding, no borders like opencode
|
||||
},
|
||||
// Clean left gutter similar to opencode
|
||||
h(Box, {
|
||||
width: 2,
|
||||
marginRight: 1,
|
||||
borderStyle: 'single',
|
||||
borderRight: false,
|
||||
borderTop: false,
|
||||
borderBottom: false,
|
||||
borderLeftColor: isThinking ? 'yellow' : 'gray'
|
||||
}),
|
||||
|
||||
h(Box, { flexDirection: 'column', flexGrow: 1 },
|
||||
// Header with minimal stats - opencode style
|
||||
h(Box, { marginBottom: 0.5, flexDirection: 'row' },
|
||||
h(Text, { color: isThinking ? 'yellow' : 'gray', dimColor: !isThinking },
|
||||
isThinking ? '💭 thinking...' : '💭 thinking'
|
||||
),
|
||||
stats.activeAgent && h(Text, { color: 'magenta', marginLeft: 1 }, `(${stats.activeAgent})`),
|
||||
h(Text, { color: 'gray', marginLeft: 1, dimColor: true }, `(${stats.chars} chars)`)
|
||||
),
|
||||
// Thinking lines with cleaner presentation
|
||||
visibleLines.map((line, i) =>
|
||||
h(Text, {
|
||||
key: i,
|
||||
color: 'gray',
|
||||
dimColor: true,
|
||||
wrap: 'truncate'
|
||||
},
|
||||
` ${line.substring(0, width - 4)}` // Cleaner indentation
|
||||
)
|
||||
),
|
||||
// Hidden count indicator
|
||||
hiddenCount > 0 && h(Text, {
|
||||
color: 'gray',
|
||||
dimColor: true,
|
||||
marginLeft: 2
|
||||
},
|
||||
`+${hiddenCount} steps`
|
||||
)
|
||||
)
|
||||
);
|
||||
};
|
||||
|
||||
export default ThinkingBlock;
|
||||
@@ -7,6 +7,7 @@ const h = React.createElement;
|
||||
const TodoList = ({ tasks = [], onAddTask, onCompleteTask, onDeleteTask, width = 60 }) => {
|
||||
const [newTask, setNewTask] = useState('');
|
||||
const [isAdding, setIsAdding] = useState(false);
|
||||
const [showCompleted, setShowCompleted] = useState(false); // Toggle to show/hide completed tasks
|
||||
|
||||
const handleAddTask = () => {
|
||||
if (newTask.trim()) {
|
||||
@@ -20,79 +21,196 @@ const TodoList = ({ tasks = [], onAddTask, onCompleteTask, onDeleteTask, width =
|
||||
const completedTasks = tasks.filter(t => t.status === 'completed');
|
||||
const progress = tasks.length > 0 ? Math.round((completedTasks.length / tasks.length) * 100) : 0;
|
||||
|
||||
return h(Box, { flexDirection: 'column', width: width, borderStyle: 'round', borderColor: 'gray', padding: 1 },
|
||||
// Header with title and progress
|
||||
h(Box, { flexDirection: 'row', justifyContent: 'space-between', marginBottom: 1 },
|
||||
h(Text, { bold: true, color: 'white' }, '📋 Tasks'),
|
||||
h(Text, { color: 'cyan' }, `${progress}%`)
|
||||
return h(Box, {
|
||||
flexDirection: 'column',
|
||||
width: width,
|
||||
borderStyle: 'double', // Professional double border
|
||||
borderColor: 'cyan', // Professional accent color
|
||||
paddingX: 1,
|
||||
paddingY: 1,
|
||||
backgroundColor: '#1e1e1e' // Dark theme like professional IDEs
|
||||
},
|
||||
// Header with title, progress, and stats
|
||||
h(Box, {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
marginBottom: 1,
|
||||
paddingBottom: 0.5,
|
||||
borderBottom: true,
|
||||
borderColor: 'gray'
|
||||
},
|
||||
h(Text, { bold: true, color: 'cyan' }, '📋 TASK MANAGER'),
|
||||
h(Box, { flexDirection: 'row', gap: 1 },
|
||||
h(Text, { color: 'green' }, `${completedTasks.length}`),
|
||||
h(Text, { color: 'gray' }, '/'),
|
||||
h(Text, { color: 'white' }, `${tasks.length}`),
|
||||
h(Text, { color: 'cyan' }, `(${progress}%)`)
|
||||
)
|
||||
),
|
||||
|
||||
// Progress bar
|
||||
// Progress bar with professional styling
|
||||
h(Box, { marginBottom: 1 },
|
||||
h(Box, {
|
||||
width: width - 4, // Account for padding
|
||||
width: width - 4,
|
||||
height: 1,
|
||||
borderStyle: 'single',
|
||||
borderColor: 'gray',
|
||||
flexDirection: 'row'
|
||||
flexDirection: 'row',
|
||||
backgroundColor: '#333333' // Dark background for progress bar
|
||||
},
|
||||
h(Box, {
|
||||
width: Math.max(1, Math.floor((width - 6) * progress / 100)),
|
||||
height: 1,
|
||||
backgroundColor: 'green'
|
||||
backgroundColor: progress === 100 ? 'green' : 'cyan' // Color based on completion
|
||||
})
|
||||
)
|
||||
),
|
||||
|
||||
// Add new task
|
||||
h(Box, { marginBottom: 1 },
|
||||
// Add new task with enhanced UI
|
||||
h(Box, {
|
||||
marginBottom: 1,
|
||||
paddingX: 0.5,
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderStyle: 'round',
|
||||
borderColor: 'gray'
|
||||
},
|
||||
isAdding
|
||||
? h(Box, { flexDirection: 'row', alignItems: 'center' },
|
||||
h(Text, { color: 'green', marginRight: 1 }, '●'),
|
||||
h(Text, { color: 'green', marginRight: 1 }, '✓'),
|
||||
h(Box, { flexGrow: 1 },
|
||||
h(TextInput, {
|
||||
value: newTask,
|
||||
onChange: setNewTask,
|
||||
onSubmit: handleAddTask,
|
||||
placeholder: 'Add new task...'
|
||||
placeholder: 'Enter new task...',
|
||||
backgroundColor: '#333333'
|
||||
})
|
||||
)
|
||||
)
|
||||
: h(Box, { flexDirection: 'row', alignItems: 'center' },
|
||||
h(Text, { color: 'green', marginRight: 1 }, '➕'),
|
||||
h(Text, { color: 'gray', dimColor: true, onClick: () => setIsAdding(true) }, 'Add task')
|
||||
: h(Box, {
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
onClick: () => setIsAdding(true)
|
||||
},
|
||||
h(Text, { color: 'green', marginRight: 1 }, '✚'),
|
||||
h(Text, { color: 'gray', dimColor: false }, 'Add new task (click to add)')
|
||||
)
|
||||
),
|
||||
|
||||
// Tasks list
|
||||
// Tasks list with enhanced styling
|
||||
h(Box, { flexDirection: 'column', flexGrow: 1 },
|
||||
// Pending tasks
|
||||
pendingTasks.map((task, index) =>
|
||||
h(Box, {
|
||||
key: task.id || index,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 0.5
|
||||
},
|
||||
h(Box, {
|
||||
width: 2,
|
||||
height: 1,
|
||||
borderStyle: 'round',
|
||||
borderColor: 'gray',
|
||||
marginRight: 1,
|
||||
onClick: () => onCompleteTask && onCompleteTask(task.id)
|
||||
},
|
||||
h(Text, { color: 'gray' }, '○')
|
||||
),
|
||||
h(Box, { flexGrow: 1 },
|
||||
h(Text, { color: 'white' }, task.content)
|
||||
// Pending tasks section
|
||||
pendingTasks.length > 0
|
||||
? h(Box, { marginBottom: 1 },
|
||||
h(Text, { color: 'yellow', bold: true, marginBottom: 0.5 }, `⚡ ${pendingTasks.length} PENDING`),
|
||||
...pendingTasks.map((task, index) =>
|
||||
h(Box, {
|
||||
key: task.id || index,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 0.5,
|
||||
paddingX: 1,
|
||||
backgroundColor: '#252525',
|
||||
borderStyle: 'single',
|
||||
borderColor: 'gray'
|
||||
},
|
||||
// Complete button
|
||||
h(Box, {
|
||||
width: 3,
|
||||
height: 1,
|
||||
marginRight: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
onClick: () => onCompleteTask && onCompleteTask(task.id),
|
||||
backgroundColor: 'transparent'
|
||||
},
|
||||
h(Text, { color: 'yellow' }, '○')
|
||||
),
|
||||
// Task content
|
||||
h(Box, { flexGrow: 1 },
|
||||
h(Text, { color: 'white' }, task.content)
|
||||
),
|
||||
// Delete button
|
||||
h(Box, {
|
||||
width: 3,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
onClick: () => onDeleteTask && onDeleteTask(task.id)
|
||||
},
|
||||
h(Text, { color: 'red' }, '✕')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
: h(Text, { color: 'gray', italic: true, marginBottom: 1, marginLeft: 1 }, 'No pending tasks'),
|
||||
|
||||
// Completed tasks (show collapsed by default)
|
||||
// Completed tasks section with toggle
|
||||
completedTasks.length > 0 && h(Box, { marginTop: 1 },
|
||||
h(Text, { color: 'gray', dimColor: true, bold: true }, `✓ ${completedTasks.length} completed`)
|
||||
h(Box, {
|
||||
flexDirection: 'row',
|
||||
justifyContent: 'space-between',
|
||||
onClick: () => setShowCompleted(!showCompleted)
|
||||
},
|
||||
h(Text, {
|
||||
color: showCompleted ? 'green' : 'gray',
|
||||
bold: true
|
||||
}, `✓ ${completedTasks.length} COMPLETED ${showCompleted ? '−' : '+'}`),
|
||||
h(Text, { color: 'gray', dimColor: true }, showCompleted ? 'click to collapse' : 'click to expand')
|
||||
),
|
||||
showCompleted && h(Box, { marginTop: 0.5 },
|
||||
...completedTasks.map((task, index) =>
|
||||
h(Box, {
|
||||
key: `completed-${task.id || index}`,
|
||||
flexDirection: 'row',
|
||||
alignItems: 'center',
|
||||
marginBottom: 0.5,
|
||||
paddingX: 1,
|
||||
backgroundColor: '#2a2a2a',
|
||||
borderStyle: 'single',
|
||||
borderColor: 'green'
|
||||
},
|
||||
// Completed indicator
|
||||
h(Box, {
|
||||
width: 3,
|
||||
height: 1,
|
||||
marginRight: 1,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center'
|
||||
},
|
||||
h(Text, { color: 'green', bold: true }, '✓')
|
||||
),
|
||||
// Task content
|
||||
h(Box, { flexGrow: 1 },
|
||||
h(Text, {
|
||||
color: 'gray',
|
||||
strikethrough: true,
|
||||
dimColor: true
|
||||
}, task.content)
|
||||
),
|
||||
// Delete button
|
||||
h(Box, {
|
||||
width: 3,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
onClick: () => onDeleteTask && onDeleteTask(task.id)
|
||||
},
|
||||
h(Text, { color: 'red' }, '✕')
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
),
|
||||
|
||||
// Footer with instructions
|
||||
h(Box, {
|
||||
marginTop: 1,
|
||||
paddingTop: 0.5,
|
||||
borderTop: true,
|
||||
borderColor: 'gray'
|
||||
},
|
||||
h(Text, { color: 'gray', dimColor: true, size: 'small' },
|
||||
'Click ○ to complete • Click ✕ to delete'
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user