genoma-evolution 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.brv/.obsidian/app.json +1 -0
- package/.brv/.obsidian/appearance.json +1 -0
- package/.brv/.obsidian/core-plugins.json +33 -0
- package/.brv/.obsidian/graph.json +22 -0
- package/.brv/.obsidian/workspace.json +195 -0
- package/.brv/Sin ti/314/201tulo 1.canvas" +1 -0
- package/.brv/Sin ti/314/201tulo 2.canvas" +1 -0
- package/.brv/Sin ti/314/201tulo.canvas" +1 -0
- package/.brv/_queue_status.json +1 -0
- package/.brv/config.json +5 -0
- package/.brv/context-tree/_index.md +60 -0
- package/.brv/context-tree/_manifest.json +165 -0
- package/.brv/context-tree/backend/_index.md +24 -0
- package/.brv/context-tree/backend/backend/_index.md +40 -0
- package/.brv/context-tree/backend/backend/init.abstract.md +0 -0
- package/.brv/context-tree/backend/backend/init.md +27 -0
- package/.brv/context-tree/backend/backend/init.overview.md +29 -0
- package/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
- package/.brv/context-tree/backend/backend/job_tracker.md +273 -0
- package/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
- package/.brv/context-tree/backend/backend/main.abstract.md +0 -0
- package/.brv/context-tree/backend/backend/main.md +1292 -0
- package/.brv/context-tree/backend/backend/main.overview.md +30 -0
- package/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
- package/.brv/context-tree/backend/backend/requirements.md +37 -0
- package/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
- package/.brv/context-tree/docs/_index.md +37 -0
- package/.brv/context-tree/docs/api/_index.md +54 -0
- package/.brv/context-tree/docs/api/context.md +11 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
- package/.brv/context-tree/frontend/_index.md +48 -0
- package/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
- package/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
- package/.brv/context-tree/frontend/src/_index.md +53 -0
- package/.brv/context-tree/frontend/src/components/_index.md +52 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
- package/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
- package/.brv/context-tree/frontend/src/context.md +10 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
- package/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
- package/.brv/context-tree/frontend/src/lib/_index.md +48 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
- package/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
- package/.brv/context-tree/frontend/src/page.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/page.md +103 -0
- package/.brv/context-tree/frontend/src/page.overview.md +7 -0
- package/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/settingspage.md +124 -0
- package/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
- package/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
- package/.brv/context-tree/frontend/src/sidebar.md +170 -0
- package/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
- package/.brv/context-tree/meta/_index.md +24 -0
- package/.brv/context-tree/meta/curation_context/_index.md +24 -0
- package/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
- package/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
- package/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
- package/.brv/dream-log/drm-1777341062653.json +33 -0
- package/.brv/dream-state.json +8 -0
- package/.brv/dream.lock +0 -0
- package/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/settings.local.json +7 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/app.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/appearance.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/core-plugins.json +33 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/graph.json +22 -0
- package/.claude/worktrees/phase-2-mcp/.brv/.obsidian/workspace.json +195 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 1.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo 2.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/Sin t/303/255tulo.canvas" +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/_queue_status.json +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/config.json +5 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_index.md +60 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/_manifest.json +165 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/_index.md +40 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.md +27 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/init.overview.md +29 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.md +273 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/job_tracker.overview.md +31 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.md +1292 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/main.overview.md +30 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.md +37 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/backend/backend/requirements.overview.md +28 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/_index.md +37 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/_index.md +54 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/context.md +11 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/docs/api/hermes_api_openapi_specification.overview.md +44 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/_index.md +48 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/_index.md +31 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.md +41 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/hermes_dashboard/architecture_overview.overview.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/_index.md +53 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/_index.md +52 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.md +161 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/components/sidebar_navigation_component.overview.md +32 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/context.md +10 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/functioncallingpage.overview.md +26 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/_index.md +48 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.abstract.md +1 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.md +403 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/lib/api_client_library.overview.md +69 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.md +103 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/page.overview.md +7 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.md +124 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/settingspage.overview.md +34 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.abstract.md +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.md +170 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/frontend/src/sidebar.overview.md +25 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/_index.md +24 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.abstract.md +4 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.md +35 -0
- package/.claude/worktrees/phase-2-mcp/.brv/context-tree/meta/curation_context/empty_context.overview.md +20 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream-log/drm-1777341062653.json +33 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream-state.json +8 -0
- package/.claude/worktrees/phase-2-mcp/.brv/dream.lock +0 -0
- package/.claude/worktrees/phase-2-mcp/.brv/review-backups/docs/api/hermes_api_openapi_specification.md +468 -0
- package/.claude/worktrees/phase-2-mcp/.claude/settings.local.json +13 -0
- package/.claude/worktrees/phase-2-mcp/.kilocode/package-lock.json +378 -0
- package/.claude/worktrees/phase-2-mcp/.kilocode/package.json +5 -0
- package/.claude/worktrees/phase-2-mcp/AGENTS.md +5 -0
- package/.claude/worktrees/phase-2-mcp/CLAUDE.md +29 -0
- package/.claude/worktrees/phase-2-mcp/QA_AUDIT_PLAN.md +156 -0
- package/.claude/worktrees/phase-2-mcp/README.md +316 -0
- package/.claude/worktrees/phase-2-mcp/agent-agnostic-evolution-dashboard.md +405 -0
- package/.claude/worktrees/phase-2-mcp/backend/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/claude_code_collector.py +277 -0
- package/.claude/worktrees/phase-2-mcp/backend/collectors/hermes_collector.py +68 -0
- package/.claude/worktrees/phase-2-mcp/backend/curator.py +512 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/__init__.py +19 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/engine.py +116 -0
- package/.claude/worktrees/phase-2-mcp/backend/eval/scorers.py +201 -0
- package/.claude/worktrees/phase-2-mcp/backend/generate_dataset.py +86 -0
- package/.claude/worktrees/phase-2-mcp/backend/job_tracker.py +232 -0
- package/.claude/worktrees/phase-2-mcp/backend/main.py +1746 -0
- package/.claude/worktrees/phase-2-mcp/backend/mcp_server.py +250 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/__init__.py +24 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/cycle_orchestrator.py +270 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/delta_validator.py +191 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/dspy_compiler.py +315 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/gepa_strategist.py +213 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/models.py +260 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/skill_deployer.py +195 -0
- package/.claude/worktrees/phase-2-mcp/backend/promethean/trace_ingestion.py +142 -0
- package/.claude/worktrees/phase-2-mcp/backend/requirements.txt +6 -0
- package/.claude/worktrees/phase-2-mcp/backend/sdd_evolve.py +459 -0
- package/.claude/worktrees/phase-2-mcp/backend/skill_detector.py +227 -0
- package/.claude/worktrees/phase-2-mcp/backend/skill_registry.py +289 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/__init__.py +5 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/run_store.py +393 -0
- package/.claude/worktrees/phase-2-mcp/backend/storage/schema.sql +99 -0
- package/.claude/worktrees/phase-2-mcp/backend/validate_evolution.py +267 -0
- package/.claude/worktrees/phase-2-mcp/components.json +28 -0
- package/.claude/worktrees/phase-2-mcp/docs/api/hermes-api.openapi.yaml +438 -0
- package/.claude/worktrees/phase-2-mcp/docs/hero.svg +148 -0
- package/.claude/worktrees/phase-2-mcp/eslint.config.mjs +18 -0
- package/.claude/worktrees/phase-2-mcp/install.sh +245 -0
- package/.claude/worktrees/phase-2-mcp/next-env.d.ts +6 -0
- package/.claude/worktrees/phase-2-mcp/next.config.ts +32 -0
- package/.claude/worktrees/phase-2-mcp/package-lock.json +11936 -0
- package/.claude/worktrees/phase-2-mcp/package.json +41 -0
- package/.claude/worktrees/phase-2-mcp/pnpm-workspace.yaml +4 -0
- package/.claude/worktrees/phase-2-mcp/postcss.config.mjs +7 -0
- package/.claude/worktrees/phase-2-mcp/public/file.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Bold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Medium.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Regular.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Bold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Medium.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Regular.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
- package/.claude/worktrees/phase-2-mcp/public/globe.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/next.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/theme-preview.html +257 -0
- package/.claude/worktrees/phase-2-mcp/public/vercel.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/public/window.svg +1 -0
- package/.claude/worktrees/phase-2-mcp/run.sh +26 -0
- package/.claude/worktrees/phase-2-mcp/skills-lock.json +10 -0
- package/.claude/worktrees/phase-2-mcp/specs/event-schema.md +223 -0
- package/.claude/worktrees/phase-2-mcp/specs/examples/run.jsonl +3 -0
- package/.claude/worktrees/phase-2-mcp/src/app/api/[...path]/route.ts +55 -0
- package/.claude/worktrees/phase-2-mcp/src/app/api/auth/token/route.ts +22 -0
- package/.claude/worktrees/phase-2-mcp/src/app/evolution/page.tsx +589 -0
- package/.claude/worktrees/phase-2-mcp/src/app/favicon.ico +0 -0
- package/.claude/worktrees/phase-2-mcp/src/app/globals.css +321 -0
- package/.claude/worktrees/phase-2-mcp/src/app/layout.tsx +63 -0
- package/.claude/worktrees/phase-2-mcp/src/app/page.tsx +70 -0
- package/.claude/worktrees/phase-2-mcp/src/app/skills/page.tsx +369 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ApiConfigCard.tsx +199 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.css +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.d.ts +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ColorBends.jsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/CoreLoopToggle.tsx +111 -0
- package/.claude/worktrees/phase-2-mcp/src/components/EnvironmentStatus.tsx +176 -0
- package/.claude/worktrees/phase-2-mcp/src/components/EvolutionBackground.tsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ReactQueryProvider.tsx +24 -0
- package/.claude/worktrees/phase-2-mcp/src/components/Sidebar.tsx +247 -0
- package/.claude/worktrees/phase-2-mcp/src/components/SkillDiffViewer.tsx +154 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ThemeAwareBackground.tsx +67 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ThemeToggle.tsx +54 -0
- package/.claude/worktrees/phase-2-mcp/src/components/WelcomeHero.tsx +77 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ClickSpark.tsx +116 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/CountUp.tsx +98 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/DarkSelect.tsx +95 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/DecryptedText.tsx +161 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ElectricBorder.tsx +184 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/GlitchText.tsx +34 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/ShinyText.tsx +55 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/SpotlightCard.tsx +42 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/TextType.tsx +95 -0
- package/.claude/worktrees/phase-2-mcp/src/components/bits/index.ts +9 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/CuratorPage.tsx +632 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/DatasetPage.tsx +271 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/EvolutionPage.tsx +676 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/FunctionCallingPage.tsx +1 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/LogsPage.tsx +272 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/MetricsPage.tsx +246 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/OverviewPage.tsx +420 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/SettingsPage.tsx +88 -0
- package/.claude/worktrees/phase-2-mcp/src/components/pages/SkillStudioPage.tsx +376 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/animated-theme-toggler.tsx +97 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/button.tsx +67 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/card.tsx +103 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/input.tsx +19 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/separator.tsx +28 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/sheet.tsx +147 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/sidebar.tsx +702 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/skeleton.tsx +13 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/theme-toggle.tsx +272 -0
- package/.claude/worktrees/phase-2-mcp/src/components/ui/tooltip.tsx +57 -0
- package/.claude/worktrees/phase-2-mcp/src/hooks/use-mobile.ts +19 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/api.ts +455 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/queryClient.ts +12 -0
- package/.claude/worktrees/phase-2-mcp/src/lib/utils.ts +6 -0
- package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
- package/.claude/worktrees/phase-2-mcp/stitch/agent_dashboard/prototype.html +676 -0
- package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/code.html +448 -0
- package/.claude/worktrees/phase-2-mcp/stitch/curator_workspace/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/datasets/code.html +479 -0
- package/.claude/worktrees/phase-2-mcp/stitch/datasets/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/code.html +461 -0
- package/.claude/worktrees/phase-2-mcp/stitch/evolution_history/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN.md +192 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/code.html +399 -0
- package/.claude/worktrees/phase-2-mcp/stitch/hermes_overview/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/live_logs/code.html +324 -0
- package/.claude/worktrees/phase-2-mcp/stitch/live_logs/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/code.html +596 -0
- package/.claude/worktrees/phase-2-mcp/stitch/skill_hub/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/code.html +527 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_metrics/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_settings/code.html +257 -0
- package/.claude/worktrees/phase-2-mcp/stitch/system_settings/screen.png +0 -0
- package/.claude/worktrees/phase-2-mcp/test_dashboard.py +201 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/fixtures/sample_session.jsonl +7 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/test_claude_code_collector.py +171 -0
- package/.claude/worktrees/phase-2-mcp/tests/collectors/test_hermes_collector.py +167 -0
- package/.claude/worktrees/phase-2-mcp/tests/eval/test_engine.py +234 -0
- package/.claude/worktrees/phase-2-mcp/tests/eval/test_scorers.py +249 -0
- package/.claude/worktrees/phase-2-mcp/tests/storage/__init__.py +0 -0
- package/.claude/worktrees/phase-2-mcp/tests/storage/test_run_store.py +359 -0
- package/.claude/worktrees/phase-2-mcp/tests/test_curator.py +559 -0
- package/.claude/worktrees/phase-2-mcp/tests/test_mcp_server.py +114 -0
- package/.claude/worktrees/phase-2-mcp/tsconfig.json +34 -0
- package/.env.example +72 -0
- package/.kilocode/package-lock.json +378 -0
- package/.kilocode/package.json +5 -0
- package/AGENTS.md +5 -0
- package/CLAUDE.md +29 -0
- package/QA_AUDIT_PLAN.md +156 -0
- package/README.md +355 -0
- package/agent-agnostic-evolution-dashboard.md +405 -0
- package/backend/__init__.py +0 -0
- package/backend/collectors/__init__.py +0 -0
- package/backend/collectors/claude_code_collector.py +277 -0
- package/backend/collectors/hermes_collector.py +68 -0
- package/backend/curator.py +512 -0
- package/backend/eval/__init__.py +19 -0
- package/backend/eval/engine.py +116 -0
- package/backend/eval/scorers.py +201 -0
- package/backend/generate_dataset.py +86 -0
- package/backend/job_tracker.py +232 -0
- package/backend/main.py +1746 -0
- package/backend/mcp_server.py +250 -0
- package/backend/promethean/__init__.py +24 -0
- package/backend/promethean/cycle_orchestrator.py +270 -0
- package/backend/promethean/delta_validator.py +191 -0
- package/backend/promethean/dspy_compiler.py +315 -0
- package/backend/promethean/gepa_strategist.py +213 -0
- package/backend/promethean/models.py +260 -0
- package/backend/promethean/skill_deployer.py +195 -0
- package/backend/promethean/trace_ingestion.py +142 -0
- package/backend/requirements.txt +6 -0
- package/backend/sdd_evolve.py +459 -0
- package/backend/skill_detector.py +227 -0
- package/backend/skill_registry.py +289 -0
- package/backend/storage/__init__.py +5 -0
- package/backend/storage/run_store.py +393 -0
- package/backend/storage/schema.sql +99 -0
- package/backend/validate_evolution.py +267 -0
- package/bin/genoma.js +250 -0
- package/components.json +28 -0
- package/docs/api/hermes-api.openapi.yaml +438 -0
- package/docs/hero.svg +148 -0
- package/eslint.config.mjs +18 -0
- package/install.sh +245 -0
- package/next-env.d.ts +6 -0
- package/next.config.ts +32 -0
- package/package.json +46 -0
- package/pnpm-workspace.yaml +4 -0
- package/postcss.config.mjs +7 -0
- package/public/file.svg +1 -0
- package/public/fonts/SF-Pro-Display-Bold.otf +0 -0
- package/public/fonts/SF-Pro-Display-Heavy.otf +0 -0
- package/public/fonts/SF-Pro-Display-Medium.otf +0 -0
- package/public/fonts/SF-Pro-Display-Regular.otf +0 -0
- package/public/fonts/SF-Pro-Display-Semibold.otf +0 -0
- package/public/fonts/SF-Pro-Text-Bold.otf +0 -0
- package/public/fonts/SF-Pro-Text-Heavy.otf +0 -0
- package/public/fonts/SF-Pro-Text-Medium.otf +0 -0
- package/public/fonts/SF-Pro-Text-Regular.otf +0 -0
- package/public/fonts/SF-Pro-Text-Semibold.otf +0 -0
- package/public/globe.svg +1 -0
- package/public/next.svg +1 -0
- package/public/theme-preview.html +257 -0
- package/public/vercel.svg +1 -0
- package/public/window.svg +1 -0
- package/run.sh +26 -0
- package/scripts/postinstall.js +50 -0
- package/skills-lock.json +10 -0
- package/specs/event-schema.md +223 -0
- package/specs/examples/run.jsonl +3 -0
- package/src/app/api/[...path]/route.ts +55 -0
- package/src/app/api/auth/token/route.ts +22 -0
- package/src/app/evolution/page.tsx +589 -0
- package/src/app/favicon.ico +0 -0
- package/src/app/globals.css +321 -0
- package/src/app/layout.tsx +63 -0
- package/src/app/page.tsx +70 -0
- package/src/app/skills/page.tsx +369 -0
- package/src/components/ApiConfigCard.tsx +199 -0
- package/src/components/ColorBends.css +1 -0
- package/src/components/ColorBends.d.ts +1 -0
- package/src/components/ColorBends.jsx +1 -0
- package/src/components/CoreLoopToggle.tsx +111 -0
- package/src/components/EnvironmentStatus.tsx +176 -0
- package/src/components/EvolutionBackground.tsx +1 -0
- package/src/components/ReactQueryProvider.tsx +24 -0
- package/src/components/Sidebar.tsx +247 -0
- package/src/components/SkillDiffViewer.tsx +154 -0
- package/src/components/ThemeAwareBackground.tsx +67 -0
- package/src/components/ThemeToggle.tsx +54 -0
- package/src/components/WelcomeHero.tsx +77 -0
- package/src/components/bits/ClickSpark.tsx +116 -0
- package/src/components/bits/CountUp.tsx +98 -0
- package/src/components/bits/DarkSelect.tsx +95 -0
- package/src/components/bits/DecryptedText.tsx +161 -0
- package/src/components/bits/ElectricBorder.tsx +184 -0
- package/src/components/bits/GlitchText.tsx +34 -0
- package/src/components/bits/ShinyText.tsx +55 -0
- package/src/components/bits/SpotlightCard.tsx +42 -0
- package/src/components/bits/TextType.tsx +95 -0
- package/src/components/bits/index.ts +9 -0
- package/src/components/pages/CuratorPage.tsx +632 -0
- package/src/components/pages/DatasetPage.tsx +271 -0
- package/src/components/pages/EvolutionPage.tsx +676 -0
- package/src/components/pages/FunctionCallingPage.tsx +1 -0
- package/src/components/pages/LogsPage.tsx +272 -0
- package/src/components/pages/MetricsPage.tsx +246 -0
- package/src/components/pages/OverviewPage.tsx +420 -0
- package/src/components/pages/SettingsPage.tsx +88 -0
- package/src/components/pages/SkillStudioPage.tsx +376 -0
- package/src/components/ui/animated-theme-toggler.tsx +97 -0
- package/src/components/ui/button.tsx +67 -0
- package/src/components/ui/card.tsx +103 -0
- package/src/components/ui/input.tsx +19 -0
- package/src/components/ui/separator.tsx +28 -0
- package/src/components/ui/sheet.tsx +147 -0
- package/src/components/ui/sidebar.tsx +702 -0
- package/src/components/ui/skeleton.tsx +13 -0
- package/src/components/ui/theme-toggle.tsx +272 -0
- package/src/components/ui/tooltip.tsx +57 -0
- package/src/hooks/use-mobile.ts +19 -0
- package/src/lib/api.ts +455 -0
- package/src/lib/queryClient.ts +12 -0
- package/src/lib/utils.ts +6 -0
- package/stitch/agent_dashboard/DESIGN_SPEC.md +521 -0
- package/stitch/agent_dashboard/prototype.html +676 -0
- package/stitch/curator_workspace/code.html +448 -0
- package/stitch/curator_workspace/screen.png +0 -0
- package/stitch/datasets/code.html +479 -0
- package/stitch/datasets/screen.png +0 -0
- package/stitch/evolution_history/code.html +461 -0
- package/stitch/evolution_history/screen.png +0 -0
- package/stitch/hermes_dashboard/DESIGN.md +192 -0
- package/stitch/hermes_dashboard/DESIGN_SPEC.md +455 -0
- package/stitch/hermes_overview/code.html +399 -0
- package/stitch/hermes_overview/screen.png +0 -0
- package/stitch/live_logs/code.html +324 -0
- package/stitch/live_logs/screen.png +0 -0
- package/stitch/skill_hub/code.html +596 -0
- package/stitch/skill_hub/screen.png +0 -0
- package/stitch/system_metrics/code.html +527 -0
- package/stitch/system_metrics/screen.png +0 -0
- package/stitch/system_settings/code.html +257 -0
- package/stitch/system_settings/screen.png +0 -0
- package/test_dashboard.py +201 -0
- package/tests/collectors/__init__.py +0 -0
- package/tests/collectors/fixtures/sample_session.jsonl +7 -0
- package/tests/collectors/test_claude_code_collector.py +171 -0
- package/tests/collectors/test_hermes_collector.py +167 -0
- package/tests/eval/test_engine.py +234 -0
- package/tests/eval/test_scorers.py +249 -0
- package/tests/storage/__init__.py +0 -0
- package/tests/storage/test_run_store.py +359 -0
- package/tests/test_curator.py +559 -0
- package/tests/test_e2e_npm.py +621 -0
- package/tests/test_mcp_server.py +114 -0
- package/tsconfig.json +34 -0
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
"""Evaluation engine orchestrating multiple scorers."""
|
|
2
|
+
|
|
3
|
+
from typing import Optional
|
|
4
|
+
|
|
5
|
+
from backend.eval.scorers import (
|
|
6
|
+
EvalScore,
|
|
7
|
+
OutcomeScorer,
|
|
8
|
+
ToolEfficiencyScorer,
|
|
9
|
+
TokenCostScorer,
|
|
10
|
+
ErrorRecoveryScorer,
|
|
11
|
+
DeltaScorer,
|
|
12
|
+
)
|
|
13
|
+
from backend.promethean.models import CanonicalRun
|
|
14
|
+
from backend.storage import RunStore
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class EvaluationEngine:
|
|
18
|
+
"""Evaluate canonical runs using composable scorers."""
|
|
19
|
+
|
|
20
|
+
DEFAULT_SCORERS = [
|
|
21
|
+
OutcomeScorer(),
|
|
22
|
+
ToolEfficiencyScorer(),
|
|
23
|
+
TokenCostScorer(),
|
|
24
|
+
ErrorRecoveryScorer(),
|
|
25
|
+
DeltaScorer(),
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
def __init__(self, store: Optional[RunStore] = None, scorers: Optional[list] = None):
|
|
29
|
+
self.store = store or RunStore()
|
|
30
|
+
self.scorers = scorers if scorers is not None else self.DEFAULT_SCORERS
|
|
31
|
+
|
|
32
|
+
def evaluate(self, run: CanonicalRun) -> list[EvalScore]:
|
|
33
|
+
"""Run applicable scorers on a run. Return list of scores."""
|
|
34
|
+
scores = []
|
|
35
|
+
for scorer in self.scorers:
|
|
36
|
+
if scorer.applies_to(run):
|
|
37
|
+
score = scorer.score(run)
|
|
38
|
+
if score: # DeltaScorer may return None
|
|
39
|
+
scores.append(score)
|
|
40
|
+
# Optionally save to storage
|
|
41
|
+
if self.store and hasattr(run, "run_id"):
|
|
42
|
+
try:
|
|
43
|
+
self._save_score(run.run_id, score)
|
|
44
|
+
except Exception:
|
|
45
|
+
pass
|
|
46
|
+
return scores
|
|
47
|
+
|
|
48
|
+
def evaluate_batch(self, runs: list[CanonicalRun]) -> dict:
|
|
49
|
+
"""Evaluate batch of runs. Return {total, evaluated, errors}."""
|
|
50
|
+
result = {"total": len(runs), "evaluated": 0, "errors": 0}
|
|
51
|
+
for run in runs:
|
|
52
|
+
try:
|
|
53
|
+
self.evaluate(run)
|
|
54
|
+
result["evaluated"] += 1
|
|
55
|
+
except Exception:
|
|
56
|
+
result["errors"] += 1
|
|
57
|
+
return result
|
|
58
|
+
|
|
59
|
+
def get_aggregate_score(self, run: CanonicalRun) -> float:
|
|
60
|
+
"""Weighted average of all applicable scores."""
|
|
61
|
+
scores = self.evaluate(run)
|
|
62
|
+
if not scores:
|
|
63
|
+
return 0.5 # Default if no scorers apply
|
|
64
|
+
|
|
65
|
+
# Equal weighting for now; can be customized per scorer
|
|
66
|
+
total = sum(s.score for s in scores)
|
|
67
|
+
return total / len(scores)
|
|
68
|
+
|
|
69
|
+
def detect_regression(
|
|
70
|
+
self, baseline_run_id: str, evolved_run_id: str, threshold: float = 0.05
|
|
71
|
+
) -> dict:
|
|
72
|
+
"""Compare baseline and evolved runs. Return {delta, regression, improvement, neutral}."""
|
|
73
|
+
baseline = self.store.get_run(baseline_run_id)
|
|
74
|
+
evolved = self.store.get_run(evolved_run_id)
|
|
75
|
+
|
|
76
|
+
if not baseline or not evolved:
|
|
77
|
+
return {
|
|
78
|
+
"error": "One or both runs not found",
|
|
79
|
+
"baseline_found": baseline is not None,
|
|
80
|
+
"evolved_found": evolved is not None,
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
baseline_score = self.get_aggregate_score(baseline)
|
|
84
|
+
evolved_score = self.get_aggregate_score(evolved)
|
|
85
|
+
delta = evolved_score - baseline_score
|
|
86
|
+
|
|
87
|
+
return {
|
|
88
|
+
"baseline_run_id": baseline_run_id,
|
|
89
|
+
"evolved_run_id": evolved_run_id,
|
|
90
|
+
"baseline_score": round(baseline_score, 3),
|
|
91
|
+
"evolved_score": round(evolved_score, 3),
|
|
92
|
+
"delta": round(delta, 3),
|
|
93
|
+
"threshold": threshold,
|
|
94
|
+
"regression": delta < -threshold,
|
|
95
|
+
"improvement": delta > threshold,
|
|
96
|
+
"neutral": abs(delta) <= threshold,
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
def _save_score(self, run_id: str, score: EvalScore):
|
|
100
|
+
"""Save evaluation score to storage (optional)."""
|
|
101
|
+
conn = self.store.connect()
|
|
102
|
+
try:
|
|
103
|
+
conn.execute(
|
|
104
|
+
"""INSERT INTO eval_scores (run_id, scorer, score, passed, details)
|
|
105
|
+
VALUES (?, ?, ?, ?, ?)""",
|
|
106
|
+
(
|
|
107
|
+
run_id,
|
|
108
|
+
score.scorer,
|
|
109
|
+
score.score,
|
|
110
|
+
1 if score.passed else 0,
|
|
111
|
+
str(score.details),
|
|
112
|
+
),
|
|
113
|
+
)
|
|
114
|
+
conn.commit()
|
|
115
|
+
finally:
|
|
116
|
+
self.store.close(conn)
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"""Evaluation scorers for CanonicalRun instances."""
|
|
2
|
+
|
|
3
|
+
from dataclasses import dataclass, field
|
|
4
|
+
from typing import Optional
|
|
5
|
+
|
|
6
|
+
from backend.promethean.models import CanonicalRun
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
@dataclass
|
|
10
|
+
class EvalScore:
|
|
11
|
+
"""Result of applying a scorer to a run."""
|
|
12
|
+
|
|
13
|
+
scorer: str
|
|
14
|
+
score: float # 0.0 to 1.0
|
|
15
|
+
passed: bool
|
|
16
|
+
details: dict = field(default_factory=dict)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class OutcomeScorer:
|
|
20
|
+
"""Score based on run outcome."""
|
|
21
|
+
|
|
22
|
+
name = "outcome"
|
|
23
|
+
|
|
24
|
+
def score(self, run: CanonicalRun) -> EvalScore:
|
|
25
|
+
"""Map outcome to score: success=1.0, partial=0.5, failure=0.0, unknown=0.3."""
|
|
26
|
+
outcome_map = {
|
|
27
|
+
"success": 1.0,
|
|
28
|
+
"partial": 0.5,
|
|
29
|
+
"failure": 0.0,
|
|
30
|
+
"unknown": 0.3,
|
|
31
|
+
}
|
|
32
|
+
score = outcome_map.get(run.outcome, 0.3)
|
|
33
|
+
return EvalScore(
|
|
34
|
+
scorer=self.name,
|
|
35
|
+
score=score,
|
|
36
|
+
passed=score > 0.5,
|
|
37
|
+
details={"outcome": run.outcome},
|
|
38
|
+
)
|
|
39
|
+
|
|
40
|
+
def applies_to(self, run: CanonicalRun) -> bool:
|
|
41
|
+
"""Applies to all runs."""
|
|
42
|
+
return True
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
class ToolEfficiencyScorer:
|
|
46
|
+
"""Score based on tool call efficiency (unique_tools / total_calls)."""
|
|
47
|
+
|
|
48
|
+
name = "tool_efficiency"
|
|
49
|
+
|
|
50
|
+
def score(self, run: CanonicalRun) -> EvalScore:
|
|
51
|
+
"""Calculate tool efficiency ratio. Pass if > 0.3."""
|
|
52
|
+
if not run.tool_calls:
|
|
53
|
+
return EvalScore(
|
|
54
|
+
scorer=self.name,
|
|
55
|
+
score=1.0,
|
|
56
|
+
passed=True,
|
|
57
|
+
details={"reason": "no_tools_used"},
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
total = len(run.tool_calls)
|
|
61
|
+
unique = len(set(tc.name for tc in run.tool_calls))
|
|
62
|
+
ratio = unique / total if total > 0 else 0.0
|
|
63
|
+
|
|
64
|
+
return EvalScore(
|
|
65
|
+
scorer=self.name,
|
|
66
|
+
score=ratio,
|
|
67
|
+
passed=ratio > 0.3,
|
|
68
|
+
details={
|
|
69
|
+
"unique_tools": unique,
|
|
70
|
+
"total_calls": total,
|
|
71
|
+
"efficiency_ratio": round(ratio, 2),
|
|
72
|
+
},
|
|
73
|
+
)
|
|
74
|
+
|
|
75
|
+
def applies_to(self, run: CanonicalRun) -> bool:
|
|
76
|
+
"""Applies to runs with tool calls."""
|
|
77
|
+
return len(run.tool_calls) > 0
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
class TokenCostScorer:
|
|
81
|
+
"""Score based on token usage: lower is better (up to 50k tokens)."""
|
|
82
|
+
|
|
83
|
+
name = "token_cost"
|
|
84
|
+
|
|
85
|
+
def score(self, run: CanonicalRun) -> EvalScore:
|
|
86
|
+
"""Score = max(0, 1 - tokens/50000). Pass if < 50k."""
|
|
87
|
+
if not run.metrics or not run.metrics.input_tokens:
|
|
88
|
+
return EvalScore(
|
|
89
|
+
scorer=self.name,
|
|
90
|
+
score=1.0,
|
|
91
|
+
passed=True,
|
|
92
|
+
details={"reason": "no_metrics"},
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
total_tokens = (run.metrics.input_tokens or 0) + (run.metrics.output_tokens or 0)
|
|
96
|
+
threshold = 50000
|
|
97
|
+
score = max(0.0, 1.0 - (total_tokens / threshold))
|
|
98
|
+
|
|
99
|
+
return EvalScore(
|
|
100
|
+
scorer=self.name,
|
|
101
|
+
score=score,
|
|
102
|
+
passed=total_tokens < threshold,
|
|
103
|
+
details={
|
|
104
|
+
"input_tokens": run.metrics.input_tokens,
|
|
105
|
+
"output_tokens": run.metrics.output_tokens,
|
|
106
|
+
"total_tokens": total_tokens,
|
|
107
|
+
"threshold": threshold,
|
|
108
|
+
},
|
|
109
|
+
)
|
|
110
|
+
|
|
111
|
+
def applies_to(self, run: CanonicalRun) -> bool:
|
|
112
|
+
"""Applies to runs with metrics."""
|
|
113
|
+
return run.metrics is not None
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
class ErrorRecoveryScorer:
|
|
117
|
+
"""Score based on error handling: success with no errors = 1.0, success with errors = 0.8, failure = 0.0."""
|
|
118
|
+
|
|
119
|
+
name = "error_recovery"
|
|
120
|
+
|
|
121
|
+
def score(self, run: CanonicalRun) -> EvalScore:
|
|
122
|
+
"""Score based on outcome and error presence."""
|
|
123
|
+
if run.outcome == "success":
|
|
124
|
+
if not run.errors:
|
|
125
|
+
score = 1.0
|
|
126
|
+
else:
|
|
127
|
+
score = 0.8
|
|
128
|
+
passed = True
|
|
129
|
+
elif run.outcome == "partial":
|
|
130
|
+
score = 0.5
|
|
131
|
+
passed = False
|
|
132
|
+
else: # failure or unknown
|
|
133
|
+
score = 0.0
|
|
134
|
+
passed = False
|
|
135
|
+
|
|
136
|
+
return EvalScore(
|
|
137
|
+
scorer=self.name,
|
|
138
|
+
score=score,
|
|
139
|
+
passed=passed,
|
|
140
|
+
details={
|
|
141
|
+
"outcome": run.outcome,
|
|
142
|
+
"error_count": len(run.errors),
|
|
143
|
+
"has_errors": len(run.errors) > 0,
|
|
144
|
+
},
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
def applies_to(self, run: CanonicalRun) -> bool:
|
|
148
|
+
"""Applies to all runs."""
|
|
149
|
+
return True
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
class DeltaScorer:
|
|
153
|
+
"""Score based on delta validation (Hermes-specific).
|
|
154
|
+
|
|
155
|
+
Only applies to Hermes runs with context.skill_name.
|
|
156
|
+
Integrates with existing DeltaValidator from promethean module.
|
|
157
|
+
"""
|
|
158
|
+
|
|
159
|
+
name = "delta"
|
|
160
|
+
|
|
161
|
+
def score(self, run: CanonicalRun) -> Optional[EvalScore]:
|
|
162
|
+
"""Run delta validation if applicable. Return None if not applicable."""
|
|
163
|
+
if not self.applies_to(run):
|
|
164
|
+
return None
|
|
165
|
+
|
|
166
|
+
# Try to import DeltaValidator
|
|
167
|
+
try:
|
|
168
|
+
from backend.promethean.delta_validator import get_validator
|
|
169
|
+
|
|
170
|
+
validator = get_validator()
|
|
171
|
+
skill_name = run.context.get("skill_name")
|
|
172
|
+
|
|
173
|
+
# Get baseline from context or infer
|
|
174
|
+
baseline = run.context.get("baseline_version")
|
|
175
|
+
if not baseline:
|
|
176
|
+
baseline = "unknown"
|
|
177
|
+
|
|
178
|
+
# Run validation
|
|
179
|
+
result = validator.validate(skill_name, baseline=baseline)
|
|
180
|
+
|
|
181
|
+
# Map validation result to score
|
|
182
|
+
passed = result.get("passed", False)
|
|
183
|
+
score = 1.0 if passed else 0.0
|
|
184
|
+
|
|
185
|
+
return EvalScore(
|
|
186
|
+
scorer=self.name,
|
|
187
|
+
score=score,
|
|
188
|
+
passed=passed,
|
|
189
|
+
details=result,
|
|
190
|
+
)
|
|
191
|
+
except Exception:
|
|
192
|
+
# DeltaValidator not available or error occurred
|
|
193
|
+
return None
|
|
194
|
+
|
|
195
|
+
def applies_to(self, run: CanonicalRun) -> bool:
|
|
196
|
+
"""Applies to Hermes runs with skill_name in context."""
|
|
197
|
+
return (
|
|
198
|
+
run.agent_name == "hermes"
|
|
199
|
+
and run.context
|
|
200
|
+
and "skill_name" in run.context
|
|
201
|
+
)
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Dataset Generator — Genera ejemplos de validación sintéticos para skills.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
python generate_dataset.py --skill code-review --count 10 --output ~/.hermes/datasets/code-review/train.jsonl
|
|
6
|
+
"""
|
|
7
|
+
import argparse
|
|
8
|
+
import json
|
|
9
|
+
import sys
|
|
10
|
+
from pathlib import Path
|
|
11
|
+
from openai import OpenAI
|
|
12
|
+
|
|
13
|
+
OLLAMA_BASE = "http://localhost:11434/v1"
|
|
14
|
+
OLLAMA_MODEL = "gemma4:31b-cloud"
|
|
15
|
+
|
|
16
|
+
client = OpenAI(base_url=OLLAMA_BASE, api_key="ollama")
|
|
17
|
+
|
|
18
|
+
SKILL_PROMPTS = {
|
|
19
|
+
"code-review": """Para la skill 'code-review', generá exactamente {count} ejemplos de revisión de código.
|
|
20
|
+
Cada ejemplo debe ser un objeto JSON con:
|
|
21
|
+
- "input": código con bugs/problemas (Python, TypeScript, o Go)
|
|
22
|
+
- "expected": la revisión esperada (bugs específicos que deberían detectarse)
|
|
23
|
+
|
|
24
|
+
Cubrí estos casos:
|
|
25
|
+
1. Python: SQL injection, type hints faltantes, async mal usado, raw dicts en vez de Pydantic
|
|
26
|
+
2. TypeScript/React: useEffect sin deps, componentes no memoizados, keys faltantes en maps
|
|
27
|
+
3. Go: error handling ignorado, goroutines sin sync, nil pointer dereference
|
|
28
|
+
4. General: dead code, secretos hardcodeados, logs con PII
|
|
29
|
+
|
|
30
|
+
IMPORTANTE: El expected NO debe ser el código corregido, sino una LISTA de bugs que deben detectarse.
|
|
31
|
+
|
|
32
|
+
OUTPUT: Array JSON de objetos {{"input": "...", "expected": "..."}}. Sin markdown fences.
|
|
33
|
+
Generá EXACTAMENTE {count} ejemplos. Comenzá YA:""",
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def generate_dataset(skill: str, count: int, output_path: str):
|
|
38
|
+
prompt = SKILL_PROMPTS.get(skill, SKILL_PROMPTS["code-review"]).format(count=count)
|
|
39
|
+
|
|
40
|
+
print(f"🎯 Generating {count} examples for '{skill}'...", flush=True)
|
|
41
|
+
|
|
42
|
+
resp = client.chat.completions.create(
|
|
43
|
+
model=OLLAMA_MODEL,
|
|
44
|
+
messages=[
|
|
45
|
+
{"role": "system", "content": "Sos un experto en code review. Generás datasets de validación en JSON. Output: solo JSON válido, sin explicaciones."},
|
|
46
|
+
{"role": "user", "content": prompt}
|
|
47
|
+
],
|
|
48
|
+
temperature=0.7,
|
|
49
|
+
max_tokens=4000,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
raw = resp.choices[0].message.content or ""
|
|
53
|
+
raw = raw.strip()
|
|
54
|
+
if raw.startswith("```"):
|
|
55
|
+
raw = raw.split("```")[1]
|
|
56
|
+
if raw.startswith("json"):
|
|
57
|
+
raw = raw[4:]
|
|
58
|
+
raw = raw.strip()
|
|
59
|
+
|
|
60
|
+
try:
|
|
61
|
+
examples = json.loads(raw)
|
|
62
|
+
except json.JSONDecodeError:
|
|
63
|
+
print(f"❌ Failed to parse JSON. Raw output:", file=sys.stderr)
|
|
64
|
+
print(raw[:500], file=sys.stderr)
|
|
65
|
+
sys.exit(1)
|
|
66
|
+
|
|
67
|
+
if not isinstance(examples, list):
|
|
68
|
+
examples = [examples]
|
|
69
|
+
|
|
70
|
+
# Write to file
|
|
71
|
+
out = Path(output_path)
|
|
72
|
+
out.parent.mkdir(parents=True, exist_ok=True)
|
|
73
|
+
with open(out, "w") as f:
|
|
74
|
+
for ex in examples:
|
|
75
|
+
f.write(json.dumps(ex, ensure_ascii=False) + "\n")
|
|
76
|
+
|
|
77
|
+
print(f"✅ Saved {len(examples)} examples to {out}")
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
if __name__ == "__main__":
|
|
81
|
+
parser = argparse.ArgumentParser(description="Generate synthetic validation dataset")
|
|
82
|
+
parser.add_argument("--skill", required=True, help="Skill name")
|
|
83
|
+
parser.add_argument("--count", type=int, default=10, help="Number of examples")
|
|
84
|
+
parser.add_argument("--output", required=True, help="Output .jsonl file")
|
|
85
|
+
args = parser.parse_args()
|
|
86
|
+
generate_dataset(args.skill, args.count, args.output)
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
"""Evolution job tracking — persistent state for active and completed jobs."""
|
|
2
|
+
|
|
3
|
+
import json
|
|
4
|
+
import re
|
|
5
|
+
import uuid
|
|
6
|
+
import asyncio
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
from dataclasses import dataclass, field, asdict
|
|
11
|
+
from typing import Optional
|
|
12
|
+
|
|
13
|
+
LOG_DIR = Path.home() / ".hermes" / "evolution-logs"
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
class JobStatus(str, Enum):
|
|
17
|
+
QUEUED = "queued"
|
|
18
|
+
LOADING_SKILL = "loading_skill"
|
|
19
|
+
BUILDING_DATASET = "building_dataset"
|
|
20
|
+
VALIDATING = "validating"
|
|
21
|
+
CONFIGURING = "configuring"
|
|
22
|
+
OPTIMIZING = "optimizing"
|
|
23
|
+
EVALUATING = "evaluating"
|
|
24
|
+
SAVING = "saving"
|
|
25
|
+
COMPLETED = "completed"
|
|
26
|
+
FAILED = "failed"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
# Phases in order (for progress calculation)
|
|
30
|
+
PHASE_ORDER = [
|
|
31
|
+
JobStatus.LOADING_SKILL,
|
|
32
|
+
JobStatus.BUILDING_DATASET,
|
|
33
|
+
JobStatus.VALIDATING,
|
|
34
|
+
JobStatus.CONFIGURING,
|
|
35
|
+
JobStatus.OPTIMIZING,
|
|
36
|
+
JobStatus.EVALUATING,
|
|
37
|
+
JobStatus.SAVING,
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
@dataclass
|
|
42
|
+
class EvolutionJob:
|
|
43
|
+
id: str
|
|
44
|
+
skill_name: str
|
|
45
|
+
status: JobStatus = JobStatus.QUEUED
|
|
46
|
+
iterations: int = 3
|
|
47
|
+
current_iteration: int = 0
|
|
48
|
+
pid: Optional[int] = None
|
|
49
|
+
started_at: str = ""
|
|
50
|
+
completed_at: str = ""
|
|
51
|
+
baseline_score: Optional[float] = None
|
|
52
|
+
current_best_score: Optional[float] = None
|
|
53
|
+
evolved_score: Optional[float] = None
|
|
54
|
+
improvement: Optional[float] = None
|
|
55
|
+
error: str = ""
|
|
56
|
+
logs: list[str] = field(default_factory=list)
|
|
57
|
+
|
|
58
|
+
def to_dict(self) -> dict:
|
|
59
|
+
d = asdict(self)
|
|
60
|
+
d["status"] = self.status.value
|
|
61
|
+
return d
|
|
62
|
+
|
|
63
|
+
@property
|
|
64
|
+
def progress(self) -> float:
|
|
65
|
+
"""0.0 to 1.0 progress estimate."""
|
|
66
|
+
if self.status == JobStatus.COMPLETED:
|
|
67
|
+
return 1.0
|
|
68
|
+
if self.status == JobStatus.FAILED:
|
|
69
|
+
return 0.0
|
|
70
|
+
if self.status == JobStatus.QUEUED:
|
|
71
|
+
return 0.0
|
|
72
|
+
|
|
73
|
+
# Phase-based progress
|
|
74
|
+
phase_idx = 0
|
|
75
|
+
try:
|
|
76
|
+
phase_idx = PHASE_ORDER.index(self.status)
|
|
77
|
+
except ValueError:
|
|
78
|
+
pass
|
|
79
|
+
|
|
80
|
+
phase_weight = 1.0 / len(PHASE_ORDER)
|
|
81
|
+
|
|
82
|
+
# Within OPTIMIZING phase, use iteration progress
|
|
83
|
+
if self.status == JobStatus.OPTIMIZING and self.iterations > 0:
|
|
84
|
+
iter_progress = self.current_iteration / self.iterations
|
|
85
|
+
base = phase_idx * phase_weight
|
|
86
|
+
return base + (iter_progress * phase_weight)
|
|
87
|
+
|
|
88
|
+
return phase_idx * phase_weight
|
|
89
|
+
|
|
90
|
+
def add_log(self, message: str):
|
|
91
|
+
timestamp = datetime.now().isoformat()[:19]
|
|
92
|
+
self.logs.append(f"[{timestamp}] {message}")
|
|
93
|
+
# Keep last 500 lines
|
|
94
|
+
if len(self.logs) > 500:
|
|
95
|
+
self.logs = self.logs[-500:]
|
|
96
|
+
|
|
97
|
+
def save_log(self):
|
|
98
|
+
LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
99
|
+
log_file = LOG_DIR / f"{self.id}.json"
|
|
100
|
+
log_file.write_text(json.dumps(self.to_dict(), indent=2))
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
class JobTracker:
|
|
104
|
+
def __init__(self):
|
|
105
|
+
self._jobs: dict[str, EvolutionJob] = {}
|
|
106
|
+
self._processes: dict[str, asyncio.subprocess.Process] = {}
|
|
107
|
+
LOG_DIR.mkdir(parents=True, exist_ok=True)
|
|
108
|
+
|
|
109
|
+
def create_job(self, skill_name: str, iterations: int) -> EvolutionJob:
|
|
110
|
+
job_id = f"{skill_name}_{datetime.now().strftime('%Y%m%d_%H%M%S')}_{uuid.uuid4().hex[:6]}"
|
|
111
|
+
job = EvolutionJob(
|
|
112
|
+
id=job_id,
|
|
113
|
+
skill_name=skill_name,
|
|
114
|
+
iterations=iterations,
|
|
115
|
+
started_at=datetime.now().isoformat(),
|
|
116
|
+
)
|
|
117
|
+
self._jobs[job_id] = job
|
|
118
|
+
return job
|
|
119
|
+
|
|
120
|
+
def get_job(self, job_id: str) -> Optional[EvolutionJob]:
|
|
121
|
+
return self._jobs.get(job_id)
|
|
122
|
+
|
|
123
|
+
def get_active_jobs(self) -> list[EvolutionJob]:
|
|
124
|
+
return [
|
|
125
|
+
j for j in self._jobs.values()
|
|
126
|
+
if j.status not in (JobStatus.COMPLETED, JobStatus.FAILED)
|
|
127
|
+
]
|
|
128
|
+
|
|
129
|
+
def get_all_jobs(self, limit: int = 50) -> list[EvolutionJob]:
|
|
130
|
+
sorted_jobs = sorted(
|
|
131
|
+
self._jobs.values(),
|
|
132
|
+
key=lambda j: j.started_at,
|
|
133
|
+
reverse=True,
|
|
134
|
+
)
|
|
135
|
+
return sorted_jobs[:limit]
|
|
136
|
+
|
|
137
|
+
def set_process(self, job_id: str, process: asyncio.subprocess.Process):
|
|
138
|
+
self._processes[job_id] = process
|
|
139
|
+
|
|
140
|
+
def get_process(self, job_id: str) -> Optional[asyncio.subprocess.Process]:
|
|
141
|
+
return self._processes.get(job_id)
|
|
142
|
+
|
|
143
|
+
def cleanup_process(self, job_id: str):
|
|
144
|
+
self._processes.pop(job_id, None)
|
|
145
|
+
|
|
146
|
+
# ── Log parsing ─────────────────────────────────────────────────
|
|
147
|
+
|
|
148
|
+
# Patterns to detect phase changes from Rich output
|
|
149
|
+
PHASE_PATTERNS = [
|
|
150
|
+
(r"Loaded:.*\.md", JobStatus.LOADING_SKILL),
|
|
151
|
+
(r"Building evaluation dataset", JobStatus.BUILDING_DATASET),
|
|
152
|
+
(r"Generated.*synthetic examples", JobStatus.BUILDING_DATASET),
|
|
153
|
+
(r"Mined.*examples from session", JobStatus.BUILDING_DATASET),
|
|
154
|
+
(r"Loaded golden dataset", JobStatus.BUILDING_DATASET),
|
|
155
|
+
(r"Validating baseline constraints", JobStatus.VALIDATING),
|
|
156
|
+
(r"Configuring optimizer", JobStatus.CONFIGURING),
|
|
157
|
+
(r"Running GEPA optimization", JobStatus.OPTIMIZING),
|
|
158
|
+
(r"Running MIPROv2", JobStatus.OPTIMIZING),
|
|
159
|
+
(r"Optimization completed", JobStatus.OPTIMIZING),
|
|
160
|
+
(r"Validating evolved skill", JobStatus.EVALUATING),
|
|
161
|
+
(r"Evaluating on holdout", JobStatus.EVALUATING),
|
|
162
|
+
(r"Evolution Results", JobStatus.SAVING),
|
|
163
|
+
(r"Saved.*to output", JobStatus.SAVING),
|
|
164
|
+
(r"✓ Skill evolved", JobStatus.COMPLETED),
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
# Pattern to extract scores
|
|
168
|
+
SCORE_PATTERN = re.compile(r"baseline[=_:\s]+(\d+\.?\d*)|evolved[=_:\s]+(\d+\.?\d*)|score[=_:\s]+(\d+\.?\d*)|improvement[=_:\s]+([+-]?\d+\.?\d*)", re.IGNORECASE)
|
|
169
|
+
|
|
170
|
+
# Pattern to extract iteration number
|
|
171
|
+
ITER_PATTERN = re.compile(r"iteration[=:\s]+(\d+)|eval[=:\s#]+(\d+)/(\d+)", re.IGNORECASE)
|
|
172
|
+
|
|
173
|
+
def parse_line(self, job: EvolutionJob, line: str):
|
|
174
|
+
"""Parse a log line and update job state."""
|
|
175
|
+
# Strip ANSI codes
|
|
176
|
+
clean = re.sub(r"\x1b\[[0-9;]*m", "", line).strip()
|
|
177
|
+
if not clean:
|
|
178
|
+
return
|
|
179
|
+
|
|
180
|
+
job.add_log(clean)
|
|
181
|
+
|
|
182
|
+
# Check phase transitions
|
|
183
|
+
for pattern, phase in self.PHASE_PATTERNS:
|
|
184
|
+
if re.search(pattern, clean, re.IGNORECASE):
|
|
185
|
+
if phase != job.status:
|
|
186
|
+
job.status = phase
|
|
187
|
+
|
|
188
|
+
# Check for optimization iteration progress
|
|
189
|
+
iter_match = self.ITER_PATTERN.search(clean)
|
|
190
|
+
if iter_match:
|
|
191
|
+
num = iter_match.group(1) or iter_match.group(2)
|
|
192
|
+
if num:
|
|
193
|
+
job.current_iteration = int(num)
|
|
194
|
+
total = iter_match.group(3)
|
|
195
|
+
if total:
|
|
196
|
+
job.iterations = int(total)
|
|
197
|
+
|
|
198
|
+
# Check for scores
|
|
199
|
+
score_match = self.SCORE_PATTERN.search(clean)
|
|
200
|
+
if score_match:
|
|
201
|
+
val = score_match.group(1) or score_match.group(2) or score_match.group(3) or score_match.group(4)
|
|
202
|
+
if val:
|
|
203
|
+
try:
|
|
204
|
+
score = float(val)
|
|
205
|
+
if "baseline" in clean.lower():
|
|
206
|
+
job.baseline_score = score
|
|
207
|
+
elif "evolved" in clean.lower() or "best" in clean.lower():
|
|
208
|
+
job.current_best_score = score
|
|
209
|
+
elif "improvement" in clean.lower():
|
|
210
|
+
job.improvement = score
|
|
211
|
+
except ValueError:
|
|
212
|
+
pass
|
|
213
|
+
|
|
214
|
+
# Check for completion
|
|
215
|
+
if "evolved_skill.md" in clean and "Saved" in clean:
|
|
216
|
+
job.status = JobStatus.COMPLETED
|
|
217
|
+
job.completed_at = datetime.now().isoformat()
|
|
218
|
+
|
|
219
|
+
# Check for failure
|
|
220
|
+
if "FAILED" in clean or "not found" in clean.lower():
|
|
221
|
+
if "✗" in clean or "Error" in clean or "error" in clean:
|
|
222
|
+
job.error = clean
|
|
223
|
+
job.status = JobStatus.FAILED
|
|
224
|
+
job.completed_at = datetime.now().isoformat()
|
|
225
|
+
|
|
226
|
+
# Persist periodically
|
|
227
|
+
if len(job.logs) % 10 == 0:
|
|
228
|
+
job.save_log()
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
# Global tracker instance
|
|
232
|
+
tracker = JobTracker()
|