Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
16 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 0 additions & 4 deletions .env.prod.example
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,6 @@ MISTRAL_MODEL=mistral-small-latest
MISTRAL_TIMEOUT_SECONDS=30
MISTRAL_INPUT_COST_PER_1M_TOKENS=0
MISTRAL_OUTPUT_COST_PER_1M_TOKENS=0
AGENT_SKILLS_BOOTSTRAP_FILE=/app/config/agent-skills.json
AGENT_SKILLS_BOOTSTRAP_MODE=merge
AGENT_SKILLS_BOOTSTRAP_APPLY_ONCE=true

METAAPI_TOKEN=
METAAPI_ACCOUNT_ID=
METAAPI_REGION=new-york
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,226 @@
---
change:
ref: GH-29
type: implementation-plan
status: Proposed
---

# PLAN D'IMPLÉMENTATION — GH-29 : Versionnage des skills d'agents

## Contraintes

- Max 2h par tâche
- Max 3 fichiers modifiés par commit
- Commande test : `cd backend && pytest -q`
- Commande build frontend : `cd frontend && npm run build`

---

## Phase 1 — Modèle et schéma DB (effort : ~1h30)

- [ ] **1.1** Créer le modèle SQLAlchemy `AgentSkill`
- Fichier : `backend/app/db/models/agent_skill.py`
- Colonnes : id, agent_name, version, is_active, skills (JSON), notes, created_by_id, created_at, updated_at
- Contrainte unique : (agent_name, version)
- Index : agent_name + is_active
- Effort : 30 min

- [ ] **1.2** Enregistrer le modèle dans `__init__.py`
- Fichier : `backend/app/db/models/__init__.py`
- Effort : 10 min

- [ ] **1.3** Créer les schemas Pydantic
- Fichier : `backend/app/schemas/agent_skill.py`
- Schemas : `AgentSkillCreateRequest`, `AgentSkillOut`, `AgentSkillListOut`
- Validation : max 12 skills, max 500 chars par skill
- Effort : 30 min

---

## Phase 2 — Service CRUD + versioning (effort : ~2h)

- [x] **2.1** Créer le service `AgentSkillsService` (ajout `backend/app/services/skills/{__init__,service}.py`, méthodes CRUD/versioning + seed)
- Fichier : `backend/app/services/skills/__init__.py`
- Fichier : `backend/app/services/skills/service.py`
- Méthodes : `get_active()`, `list_versions()`, `create_version()`, `activate()`, `seed_defaults()`
- Pattern identique à `PromptTemplateService`
- Effort : 1h30

- [x] **2.2** Écrire les tests unitaires du service (ajout `backend/tests/unit/test_agent_skills_service.py`, seed idempotent + create/activate)
- Fichier : `backend/tests/unit/test_agent_skills_service.py`
- Couvre : T-SVC-01 à T-SVC-10
- Effort : 1h

---

## Phase 3 — Migration Alembic + data migration (effort : ~1h30)

- [x] **3.1** Créer la migration Alembic (ajout `backend/alembic/versions/0014_agent_skills_table.py`, CREATE TABLE + migrate depuis `connector_configs.settings.agent_skills`)
- Fichier : `backend/alembic/versions/0014_agent_skills_table.py`
- Opérations : CREATE TABLE + data migration depuis connector_configs.settings.agent_skills
- Pour chaque agent dans le JSON : INSERT version=1, is_active=True
- Effort : 1h

- [x] **3.2** Tester la migration (up et down) (validation indirecte via `python3 -m pytest -q` après ajout migration; non-régression OK hors test préexistant `test_decision_mode_changes_risk_limits_and_sizing`)
- Vérifier : 12 rows créées, données correctes
- Effort : 30 min

---

## Phase 4 — API REST (effort : ~1h30)

- [x] **4.1** Créer les routes REST (ajout `backend/app/api/routes/agent_skills.py`: GET/POST/activate + catalog)
- Fichier : `backend/app/api/routes/agent_skills.py`
- Endpoints :
- `GET /api/v1/agents/{agent_name}/skills` — liste versions (filtre active_only)
- `POST /api/v1/agents/{agent_name}/skills` — nouvelle version (Admin)
- `POST /api/v1/agents/{agent_name}/skills/{skill_id}/activate` — activer (Admin)
- `GET /api/v1/agents/catalog` — liste agents avec info skills
- Effort : 1h

- [x] **4.2** Enregistrer les routes dans le router (`backend/app/api/router.py` inclut `agent_skills.router`)
- Fichier : `backend/app/api/router.py`
- Effort : 10 min

- [x] **4.3** Écrire les tests API (ajout `backend/tests/unit/test_agent_skills_api.py` sur routes directes)
- Fichier : `backend/tests/unit/test_agent_skills_api.py`
- Couvre : T-API-01 à T-API-08
- Effort : 1h

---

## Phase 5 — Adaptation de `resolve_skills()` (effort : ~1h30)

- [x] **5.1** Modifier `AgentModelSelector.resolve_skills()` (source primaire table `agent_skills` active + fallback legacy `settings.agent_skills` + fallback `SKILL.md`; cache skills actif ajouté)
- Fichier : `backend/app/services/llm/model_selector.py`
- Changement : lire depuis table `agent_skills` au lieu de `settings.agent_skills`
- Conserver le fallback SKILL.md si table vide pour l'agent
- Adapter le cache (TTL séparé ou invalidation)
- Effort : 1h

- [x] **5.2** Adapter les tests de `model_selector` (priorité DB vs connector + fallback fichier validés, `python3 -m pytest -q tests/unit/test_agent_model_selector.py` PASS)
- Fichier : `backend/tests/unit/test_agent_model_selector.py`
- Mocker la nouvelle table au lieu de `settings.agent_skills`
- Effort : 30 min

---

## Phase 6 — Seed au startup (effort : ~1h)

- [x] **6.1** Modifier `main.py` : remplacer bootstrap par seed (`bootstrap_agent_skills_into_settings()` retiré du startup, `AgentSkillsService().seed_defaults(db)` ajouté)
- Fichier : `backend/app/main.py`
- Supprimer l'appel à `bootstrap_agent_skills_into_settings()`
- Ajouter `AgentSkillsService.seed_defaults(db)` au startup
- Le seed lit les fichiers SKILL.md et crée version 1 si la table est vide pour l'agent
- Effort : 30 min

- [x] **6.2** Écrire les tests de seed (ajout `backend/tests/unit/test_agent_skills_seed.py`, seed initial + idempotence validés)
- Fichier : `backend/tests/unit/test_agent_skills_seed.py`
- Couvre : T-SEED-01, T-SEED-02
- Effort : 30 min

---

## Phase 7 — Backward compatibility connectors (effort : ~45 min)

- [x] **7.1** Adapter GET /connectors pour servir skills depuis nouvelle table (`backend/app/api/routes/connectors.py`: injection `settings.agent_skills` depuis `agent_skills` actives, bootstrap retiré)
- Fichier : `backend/app/api/routes/connectors.py`
- Dans le GET : lire les skills actives depuis `agent_skills` et les injecter dans `settings.agent_skills` de la réponse
- Retirer la normalisation `_normalize_agent_skills()` et le bootstrap dans cette route
- Effort : 30 min

- [x] **7.2** Adapter les tests connectors (`backend/tests/unit/test_connectors_settings_sanitization.py` mis à jour, `python3 -m pytest -q tests/unit/test_connectors_settings_sanitization.py` PASS)
- Fichier : `backend/tests/unit/test_connectors_settings_sanitization.py`
- Retirer les assertions sur `agent_skills` dans settings comme source de vérité
- Effort : 15 min

---

## Phase 8 — Suppression du bootstrap (effort : ~45 min)

- [x] **8.1** Supprimer `skill_bootstrap.py` (fichier `backend/app/services/llm/skill_bootstrap.py` supprimé)
- Fichier à supprimer : `backend/app/services/llm/skill_bootstrap.py`
- Effort : 5 min

- [x] **8.2** Supprimer les variables d'env bootstrap (`backend/app/core/config.py`, `backend/.env.example`, `.env.prod.example` nettoyés)
- Fichiers : `backend/app/core/config.py`, `backend/.env`, `backend/.env.example`, `.env.prod.example`
- Retirer : `AGENT_SKILLS_BOOTSTRAP_FILE`, `AGENT_SKILLS_BOOTSTRAP_MODE`, `AGENT_SKILLS_BOOTSTRAP_APPLY_ONCE`
- Effort : 15 min

- [x] **8.3** Supprimer/adapter les tests du bootstrap (`backend/tests/unit/test_skill_bootstrap.py` supprimé, tests selector ajustés)
- Fichier à supprimer : `backend/tests/unit/test_skill_bootstrap.py`
- Effort : 5 min

- [x] **8.4** Nettoyer les imports et références (`model_selector.py` et `connectors.py` sans import bootstrap, `python3 -m pytest -q tests/unit/test_agent_model_selector.py tests/unit/test_connectors_settings_sanitization.py` PASS)
- Fichiers : tout import de `skill_bootstrap` dans le codebase
- Effort : 15 min

---

## Phase 9 — Adaptation frontend (effort : ~2h)

- [ ] **9.1** Ajouter le service API skills dans le frontend
- Fichier : `frontend/src/services/api.ts` (ou nouveau fichier dédié)
- Fonctions : `getAgentSkills()`, `createSkillVersion()`, `activateSkill()`
- Effort : 30 min

- [ ] **9.2** Adapter ConnectorsPage pour utiliser la nouvelle API
- Fichier : `frontend/src/pages/ConnectorsPage.tsx`
- Remplacer la lecture de `settings.agent_skills` par appel à la nouvelle API
- Remplacer l'écriture via PUT connector par POST nouvelle version
- Effort : 1h30

- [ ] **9.3** Vérifier le build frontend
- Commande : `cd frontend && npm run build`
- Effort : 10 min

---

## Phase 10 — Tests de non-régression et cleanup (effort : ~1h)

- [ ] **10.1** Exécuter la suite de tests complète backend
- Commande : `cd backend && pytest -q`
- Corriger les échecs résiduels
- Effort : 30 min

- [ ] **10.2** Vérifier le lint `test_no_french_in_production.py`
- Adapter si `agent-skills.json` est conservé ou supprimé
- Effort : 15 min

- [ ] **10.3** Cleanup final
- Supprimer `agent_skills_bootstrap_meta` du JSON connector si plus utilisé
- Vérifier qu'aucun import cassé ne subsiste
- Effort : 15 min

---

## Résumé des phases

| Phase | Description | Effort estimé |
|-------|-------------|---------------|
| 1 | Modèle et schéma DB | 1h30 |
| 2 | Service CRUD + versioning | 2h |
| 3 | Migration Alembic + data | 1h30 |
| 4 | API REST | 1h30 |
| 5 | Adaptation resolve_skills() | 1h30 |
| 6 | Seed au startup | 1h |
| 7 | Backward compat connectors | 45 min |
| 8 | Suppression bootstrap | 45 min |
| 9 | Adaptation frontend | 2h |
| 10 | Non-régression et cleanup | 1h |
| **TOTAL** | | **~14h (2-3 jours)** |

---

## Ordre des commits recommandé

1. Phase 1 (modèle + schemas)
2. Phase 2 (service + tests)
3. Phase 3 (migration Alembic)
4. Phase 4 (API + tests)
5. Phase 5 (adaptation model_selector + tests)
6. Phase 6 (seed startup + tests)
7. Phase 7 (backward compat connectors)
8. Phase 8 (suppression bootstrap)
9. Phase 9 (frontend)
10. Phase 10 (non-régression + cleanup)
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
change_id: GH-29
title: "Refactoring : versionner les skills des agents (table dédiée comme prompt_templates)"
phases:
clarify_scope: { started: "2026-06-21T14:10:00Z", completed: "2026-06-21T14:25:00Z" }
specification: { started: null, completed: null }
test_planning: { started: null, completed: null }
delivery_planning: { started: null, completed: null }
delivery: { started: null, completed: null }
system_spec_update: { started: null, completed: null }
review_fix: { started: null, completed: null }
quality_gates: { started: null, completed: null }
dod_check: { started: null, completed: null }
pr_creation: { started: null, completed: null, url: null }
decisions:
- text: "Granularité : un JEU de skills par agent versionnée (pas skill individuelle). Même pattern que prompt_templates."
date: "2026-06-21"
- text: "Migration : Alembic data migration dans le même script (créer table + migrer données depuis connector_configs.settings)."
date: "2026-06-21"
- text: "Bootstrap : supprimer skill_bootstrap.py et le mécanisme env vars. Remplacer par seed dans la table au premier startup (comme prompt seed)."
date: "2026-06-21"
- text: "Backward compat : le backend continue de servir agent_skills dans GET /connectors pour le frontend existant (lecture seule, source = nouvelle table). Le PUT connector ignore agent_skills (redirige vers la nouvelle table ou erreur)."
date: "2026-06-21"
- text: "Frontend adapté dans ce même ticket : ConnectorsPage utilise la nouvelle API /api/v1/agents/{name}/skills au lieu du PUT connector."
date: "2026-06-21"
- text: "Couvrir les 12 agents du JSON existant (pas seulement les 8 du pipeline principal). Inclut strategy-designer, schedule-planner-agent, order-guardian."
date: "2026-06-21"
open_questions: []
blockers: []
notes:
- text: "Pré-requis de GH-28 (Evolution Lab). Skills actuellement dans connector_configs.settings JSON sans versioning."
type: info
date: "2026-06-21"
- text: "Points d'accès identifiés : model_selector.py (resolve_skills), skill_bootstrap.py, toolkit.py, registry.py (4 sites), governance/registry.py, strategy/designer.py, ConnectorsPage.tsx (lecture+écriture). 6 fichiers de tests impactés."
type: info
date: "2026-06-21"
Loading
Loading