mirror of
https://github.com/leonvanzyl/autocoder.git
synced 2026-02-05 08:23:08 +00:00
Token reduction (~40% per session, ~2.3M fewer tokens per 200-feature project): - Agent-type-specific tool lists: coding 9, testing 5, init 5 (was 19 for all) - Right-sized max_turns: coding 300, testing 100 (was 1000 for all) - Trimmed coding prompt template (~150 lines removed) - Streamlined testing prompt with batch support - YOLO mode now strips browser testing instructions from prompt - Added Grep, WebFetch, WebSearch to expand project session Performance improvements: - Rate limit retries start at ~15s with jitter (was fixed 60s) - Post-spawn delay reduced to 0.5s (was 2s) - Orchestrator consolidated to 1 DB query per loop (was 5-7) - Testing agents batch 3 features per session (was 1) - Smart context compaction preserves critical state, discards noise Bug fixes: - Removed ghost feature_release_testing MCP tool (wasted tokens every test session) - Forward all 9 Vertex AI env vars to chat sessions (was missing 3) - Fix DetachedInstanceError risk in test batch ORM access - Prevent duplicate testing of same features in parallel mode Code deduplication: - _get_project_path(): 9 copies -> 1 shared utility (project_helpers.py) - validate_project_name(): 9 copies -> 2 variants in 1 file (validation.py) - ROOT_DIR: 10 copies -> 1 definition (chat_constants.py) - API_ENV_VARS: 4 copies -> 1 source of truth (env_constants.py) Security hardening: - Unified sensitive directory blocklist (14 dirs, was two divergent lists) - Cached get_blocked_paths() for O(1) directory listing checks - Terminal security warning when ALLOW_REMOTE=1 exposes WebSocket - 20 new security tests for EXTRA_READ_PATHS blocking - Extracted _validate_command_list() and _validate_pkill_processes() helpers Type safety: - 87 mypy errors -> 0 across 58 source files - Installed types-PyYAML for proper yaml stub types - Fixed SQLAlchemy Column[T] coercions across all routers Dead code removed: - 13 files deleted (~2,679 lines): unused UI components, debug logs, outdated docs - 7 unused npm packages removed (Radix UI components with 0 imports) - AgentAvatar.tsx reduced from 615 -> 119 lines (SVGs extracted to mascotData.tsx) New CLI options: - --testing-batch-size (1-5) for parallel mode test batching - --testing-feature-ids for direct multi-feature testing Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
119 lines
3.0 KiB
TypeScript
119 lines
3.0 KiB
TypeScript
import { type AgentMascot, type AgentState } from '../lib/types'
|
|
import {
|
|
AVATAR_COLORS,
|
|
UNKNOWN_COLORS,
|
|
MASCOT_SVGS,
|
|
UnknownMascotSVG,
|
|
} from './mascotData'
|
|
|
|
interface AgentAvatarProps {
|
|
name: AgentMascot | 'Unknown'
|
|
state: AgentState
|
|
size?: 'sm' | 'md' | 'lg'
|
|
showName?: boolean
|
|
}
|
|
|
|
const SIZES = {
|
|
sm: { svg: 32, font: 'text-xs' },
|
|
md: { svg: 48, font: 'text-sm' },
|
|
lg: { svg: 64, font: 'text-base' },
|
|
}
|
|
|
|
// Animation classes based on state
|
|
function getStateAnimation(state: AgentState): string {
|
|
switch (state) {
|
|
case 'idle':
|
|
return 'animate-bounce-gentle'
|
|
case 'thinking':
|
|
return 'animate-thinking'
|
|
case 'working':
|
|
return 'animate-working'
|
|
case 'testing':
|
|
return 'animate-testing'
|
|
case 'success':
|
|
return 'animate-celebrate'
|
|
case 'error':
|
|
case 'struggling':
|
|
return 'animate-shake-gentle'
|
|
default:
|
|
return ''
|
|
}
|
|
}
|
|
|
|
// Glow effect based on state
|
|
function getStateGlow(state: AgentState): string {
|
|
switch (state) {
|
|
case 'working':
|
|
return 'shadow-[0_0_12px_rgba(0,180,216,0.5)]'
|
|
case 'thinking':
|
|
return 'shadow-[0_0_8px_rgba(255,214,10,0.4)]'
|
|
case 'success':
|
|
return 'shadow-[0_0_16px_rgba(112,224,0,0.6)]'
|
|
case 'error':
|
|
case 'struggling':
|
|
return 'shadow-[0_0_12px_rgba(255,84,0,0.5)]'
|
|
default:
|
|
return ''
|
|
}
|
|
}
|
|
|
|
// Get human-readable state description for accessibility
|
|
function getStateDescription(state: AgentState): string {
|
|
switch (state) {
|
|
case 'idle':
|
|
return 'waiting'
|
|
case 'thinking':
|
|
return 'analyzing'
|
|
case 'working':
|
|
return 'coding'
|
|
case 'testing':
|
|
return 'running tests'
|
|
case 'success':
|
|
return 'completed successfully'
|
|
case 'error':
|
|
return 'encountered an error'
|
|
case 'struggling':
|
|
return 'having difficulty'
|
|
default:
|
|
return state
|
|
}
|
|
}
|
|
|
|
export function AgentAvatar({ name, state, size = 'md', showName = false }: AgentAvatarProps) {
|
|
// Handle 'Unknown' agents (synthetic completions from untracked agents)
|
|
const isUnknown = name === 'Unknown'
|
|
const colors = isUnknown ? UNKNOWN_COLORS : AVATAR_COLORS[name]
|
|
const { svg: svgSize, font } = SIZES[size]
|
|
const SvgComponent = isUnknown ? UnknownMascotSVG : MASCOT_SVGS[name]
|
|
const stateDesc = getStateDescription(state)
|
|
const ariaLabel = `Agent ${name} is ${stateDesc}`
|
|
|
|
return (
|
|
<div
|
|
className="flex flex-col items-center gap-1"
|
|
role="status"
|
|
aria-label={ariaLabel}
|
|
aria-live="polite"
|
|
>
|
|
<div
|
|
className={`
|
|
rounded-full p-1 transition-all duration-300
|
|
${getStateAnimation(state)}
|
|
${getStateGlow(state)}
|
|
`}
|
|
style={{ backgroundColor: colors.accent }}
|
|
title={ariaLabel}
|
|
role="img"
|
|
aria-hidden="true"
|
|
>
|
|
<SvgComponent colors={colors} size={svgSize} />
|
|
</div>
|
|
{showName && (
|
|
<span className={`${font} font-bold text-foreground`} style={{ color: colors.primary }}>
|
|
{name}
|
|
</span>
|
|
)}
|
|
</div>
|
|
)
|
|
}
|