feat: add dedicated testing agents and enhanced parallel orchestration

Introduce a new testing agent architecture that runs regression tests
independently from coding agents, improving quality assurance in
parallel mode.

Key changes:

Testing Agent System:
- Add testing_prompt.template.md for dedicated testing agent role
- Add feature_mark_failing MCP tool for regression detection
- Add --agent-type flag to select initializer/coding/testing mode
- Remove regression testing from coding prompt (now handled by testing agents)

Parallel Orchestrator Enhancements:
- Add testing agent spawning with configurable ratio (--testing-agent-ratio)
- Add comprehensive debug logging system (DebugLog class)
- Improve database session management to prevent stale reads
- Add engine.dispose() calls to refresh connections after subprocess commits
- Fix f-string linting issues (remove unnecessary f-prefixes)

UI Improvements:
- Add testing agent mascot (Chip) to AgentAvatar
- Enhance AgentCard to display testing agent status
- Add testing agent ratio slider in SettingsModal
- Update WebSocket handling for testing agent updates
- Improve ActivityFeed to show testing agent activity

API & Server Updates:
- Add testing_agent_ratio to settings schema and endpoints
- Update process manager to support testing agent type
- Enhance WebSocket messages for agent_update events

Template Changes:
- Delete coding_prompt_yolo.template.md (consolidated into main prompt)
- Update initializer_prompt.template.md with improved structure
- Streamline coding_prompt.template.md workflow

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Auto
2026-01-18 13:49:50 +02:00
parent 5f786078fa
commit 13128361b0
27 changed files with 1885 additions and 536 deletions

View File

@@ -1,8 +1,8 @@
import { MessageCircle, ScrollText, X, Copy, Check } from 'lucide-react'
import { MessageCircle, ScrollText, X, Copy, Check, Code, FlaskConical } from 'lucide-react'
import { useState } from 'react'
import { createPortal } from 'react-dom'
import { AgentAvatar } from './AgentAvatar'
import type { ActiveAgent, AgentLogEntry } from '../lib/types'
import type { ActiveAgent, AgentLogEntry, AgentType } from '../lib/types'
interface AgentCardProps {
agent: ActiveAgent
@@ -50,9 +50,28 @@ function getStateColor(state: ActiveAgent['state']): string {
}
}
// Get agent type badge config
function getAgentTypeBadge(agentType: AgentType): { label: string; className: string; icon: typeof Code } {
if (agentType === 'testing') {
return {
label: 'TEST',
className: 'bg-purple-100 text-purple-700 border-purple-300',
icon: FlaskConical,
}
}
// Default to coding
return {
label: 'CODE',
className: 'bg-blue-100 text-blue-700 border-blue-300',
icon: Code,
}
}
export function AgentCard({ agent, onShowLogs }: AgentCardProps) {
const isActive = ['thinking', 'working', 'testing'].includes(agent.state)
const hasLogs = agent.logs && agent.logs.length > 0
const typeBadge = getAgentTypeBadge(agent.agentType || 'coding')
const TypeIcon = typeBadge.icon
return (
<div
@@ -62,6 +81,20 @@ export function AgentCard({ agent, onShowLogs }: AgentCardProps) {
transition-all duration-300
`}
>
{/* Agent type badge */}
<div className="flex justify-end mb-1">
<span
className={`
inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-bold
uppercase tracking-wide rounded border
${typeBadge.className}
`}
>
<TypeIcon size={10} />
{typeBadge.label}
</span>
</div>
{/* Header with avatar and name */}
<div className="flex items-center gap-2 mb-2">
<AgentAvatar name={agent.agentName} state={agent.state} size="sm" />
@@ -122,6 +155,8 @@ interface AgentLogModalProps {
export function AgentLogModal({ agent, logs, onClose }: AgentLogModalProps) {
const [copied, setCopied] = useState(false)
const typeBadge = getAgentTypeBadge(agent.agentType || 'coding')
const TypeIcon = typeBadge.icon
const handleCopy = async () => {
const logText = logs
@@ -159,9 +194,21 @@ export function AgentLogModal({ agent, logs, onClose }: AgentLogModalProps) {
<div className="flex items-center gap-3">
<AgentAvatar name={agent.agentName} state={agent.state} size="sm" />
<div>
<h2 className="font-display font-bold text-lg">
{agent.agentName} Logs
</h2>
<div className="flex items-center gap-2">
<h2 className="font-display font-bold text-lg">
{agent.agentName} Logs
</h2>
<span
className={`
inline-flex items-center gap-1 px-1.5 py-0.5 text-[10px] font-bold
uppercase tracking-wide rounded border
${typeBadge.className}
`}
>
<TypeIcon size={10} />
{typeBadge.label}
</span>
</div>
<p className="text-sm text-neo-text-secondary">
Feature #{agent.featureId}: {agent.featureName}
</p>