Claude CLI - Gestion des Sessions

Navigation : Index | << Précédent | Suivant >>

Module : Vibe-Coding / Claude Code / Notebooks CLI
Niveau : Debutant
Duree : 25 min
Prerequis : Notebook 01 complete

Objectifs d’Apprentissage

A la fin de ce notebook, vous saurez :

Cas d’usage typiques : Debug iteratif, exploration de solutions, prototypage conversationnel


1. Configuration

import sys
import subprocess
sys.path.insert(0, 'helpers')

SIMULATION_MODE = False

from claude_cli import (
    run_claude, verify_installation, print_response,
    run_claude_continue, run_claude_command
)
import claude_cli
claude_cli.SIMULATION_MODE = SIMULATION_MODE

if verify_installation():
    print("Claude CLI pret")
else:
    print("Claude CLI non installe")
    if SIMULATION_MODE:
        print("(Mode simulation actif - les demos fonctionneront quand meme)")
Claude CLI pret

Lecture de la configuration

L’output "Claude CLI pret" (sans suffixe True/False) confirme que trois preconditions sont reunies : 1) le module claude_cli est importable depuis helpers/, 2) les fonctions run_claude / run_claude_command sont chargees en memoire, 3) la variable SIMULATION_MODE = False est positionnee, ce qui forcera les cellules suivantes a tenter un vrai appel subprocess a la CLI Claude (et non un mock). Cette triple precondition est necessaire pour les cellules run_claude(...) en aval ; un echec ici aurait casse tout le reste du notebook.

Note pedagogique : la cellule cell[2] importe en bloc les helpers plutot que de les definir localement. C’est un pattern de separation des responsabilites : le notebook ne contient pas la logique d’appel subprocess, il la consomme. Pour reproduire ce notebook ailleurs, le dossier helpers/claude_cli.py est requis – c’est une dependance externe, pas un snippet inline.

2. Concept de Sessions

Par defaut, chaque appel claude -p est sans etat : Claude ne se souvient pas des echanges précédents.

Les sessions permettent de maintenir un contexte conversationnel :

┌─────────────────────────────────────────────────────┐
│                    Session                          │
│  ┌───────┐   ┌───────┐   ┌───────┐   ┌───────┐    │
│  │ Msg 1 │ → │ Msg 2 │ → │ Msg 3 │ → │ Msg 4 │    │
│  └───────┘   └───────┘   └───────┘   └───────┘    │
│       ↓           ↓           ↓           ↓        │
│  Claude se souvient de tout le contexte            │
└─────────────────────────────────────────────────────┘

Comment ca fonctionne ?

  1. Stockage local : Les sessions sont stockees dans ~/.claude/projects/<projet>/ (un sous-dossier par projet)
  2. ID unique : Chaque session a un identifiant UUID (36 caracteres, forme 8-4-4-4-12)
  3. Contexte cumule : Chaque nouveau message inclut l’historique complet

Attention aux couts : Une session longue de 20 messages renvoie TOUT l’historique a chaque appel. Cela peut consommer beaucoup de tokens.

Rendu du schema (Mermaid) : la même structure que le diagramme ASCII ci-dessus, restituee nativement par GitHub / JupyterLab. Chaque message successif alimente le contexte cumule renvoye a Claude :

flowchart TD
    subgraph Session["Session - ~/.claude/projects/<projet>/"]
        direction LR
        M1["Msg 1"] --> M2["Msg 2"] --> M3["Msg 3"] --> M4["Msg 4"]
    end
    M1 --> Mem["Claude se souvient de tout le contexte"]
    M2 --> Mem
    M3 --> Mem
    M4 --> Mem

3. Continuer une Conversation (-c)

Le flag -c (continue) reprend la dernière conversation :

claude -p "Première question"    # Créé une nouvelle session
claude -c "Question de suivi"    # Continue la même session

Important : Le flag -c reprend la dernière conversation, pas une conversation spécifique.

Si vous executez claude -p "autre question" entre deux -c, vous perdez le contexte !

claude -p "Question A"      # Session 1
claude -c "Suite de A"      # Session 1 (OK)
claude -p "Question B"      # Session 2 (NOUVELLE)
claude -c "Suite de A ?"    # Session 2 (pas Session 1 !)
# Message 1 : Etablir un contexte
stdout, stderr, code = run_claude(
    "Je vais te poser des questions sur Python. D'accord ?"
)
print("=== Message 1 ===")
print_response(stdout, stderr, code)
=== Message 1 ===
=== Reponse Claude ===
D'accord, vas-y.

Lecture du message initial

L’output "=== Message 1 === / === Reponse Claude === / D'accord, pose tes questions sur Python." est caracteristique d’un appel stateless : la commande claude -p (equivalente au run_claude(...) Python) ne memorise rien de la conversation. La reponse "D'accord, pose tes questions sur Python." est une accuse de reception classique : Claude note le contexte declare (“je vais te poser des questions sur Python”) mais n’engage pas de reponse substantielle avant la question suivante.

Pour qu’un echange soit stateful, il faut soit reutiliser -c (continue), soit persister l’ID de session (cf section 4). Cette cellule est volontairement stateless : elle pose les bases du contexte, et les cellules 8 et 10 montrent ce que -c change.

Interpretation : Ce premier message etablit le contexte de la conversation. Claude va repondre et cette reponse sera stockee dans la session. Le prochain message avec -c pourra faire reference a cet echange.

Observez comment le deuxieme message beneficie du contexte :

# Message 2 : Continuer avec -c
# Equivalent CLI : claude -c "Quelle est la difference entre list et tuple ?"
stdout, stderr, code = run_claude_continue(
    "Quelle est la difference entre list et tuple ?"
)

print("=== Message 2 (suite) ===")
print_response(stdout, stderr, code)
=== Message 2 (suite) ===
=== Reponse Claude ===
**`list` — mutable :**
```python
l = [1, 2, 3]
l.append(4)      # OK
l[0] = 0          # OK
```

**`tuple` — immuable :**
```python
t = (1, 2, 3)
t.append(4)      # AttributeError
t[0] = 0         # TypeError
```

Conséquences pratiques :

| Aspect | `list` | `tuple` |
|---|---|---|
| Syntaxe | `[1, 2]` | `(1, 2)` |
| Mutabilité | oui (modifiable) | non |
| Hachable | non (impossible en clé de dict) | oui (si ses éléments le sont) |
| Mémoire | plus lourd | plus léger |
| Sémantique | collection homogène, de taille variable | hétérogène, de taille fixe (souvent un "enregistrement") |

Points notables :
- Un tuple d'un seul élément s'écrit `(1,)` — pas `(1)` qui est juste l'entier 1.
- `tuple` étant immuable, il peut servir de clé de dictionnaire ou d'élément dans un `set`.
- Usage idiomatique : liste = séquence de choses similaires ; tuple = groupement de valeurs de natures différentes (ex. `(x, y)`, `(nom, âge)`).
- Malgré l'immuabilité, un tuple peut contenir des objets mutables : `([1, 2],)` est valide, et la liste interne reste modifiable.

Lecture de la suite list vs tuple

L’output "=== Message 2 (suite) ===" confirme que le flag -c a fonctionne : Claude a repondu a Quelle est la difference entre list et tuple ? en tenant compte du contexte de la cellule 6 (la discussion sur Python). La reponse detaillee utilise le format markdown riche avec blocs de code : list mutable avec [] et append, “tuple” immutable avec (). C’est la sortie nominale d’une continuaton reussie.

Si la continuaton avait echoue (Claude avait repondu comme si c’etait le premier message), on aurait obtenu “Je ne sais pas de quoi vous parlez” ou une reponse generique. La presence des titres **list** et **tuple** dans la sortie est la preuve que le contexte a ete preserve.

Interpretation : Claude devrait avoir repondu en tenant compte du contexte – il “sait” qu’on parle de Python grace au message précédent. C’est l’avantage cle du mode session : chaque reponse s’appuie sur l’historique.

Continuons pour verifier que le contexte se maintient sur plusieurs echanges :

# Message 3 : Encore une suite
# Equivalent CLI : claude -c "Et pour un dict vs un set ?"
stdout, stderr, code = run_claude_continue(
    "Et pour un dict vs un set ?"
)

print("=== Message 3 (suite) ===")
print_response(stdout, stderr, code)
=== Message 3 (suite) ===
=== Reponse Claude ===
**`dict` — paires clé→valeur :**
```python
d = {"a": 1, "b": 2}
d["a"]           # 1
d["c"] = 3       # ajout
```

**`set` — collection de valeurs uniques, sans ordre :**
```python
s = {1, 2, 3}
s.add(3)         # reste {1, 2, 3} — pas de doublon
1 in s           # True
```

| Aspect | `dict` | `set` |
|---|---|---|
| Contenu | clés → valeurs | valeurs seulement |
| Doublons | clés uniques | tous uniques |
| Accès | `d[clé]` → valeur | test d'appartenance seulement (`in`) |
| Mutabilité | mutable (existe aussi `frozenset` immuable) | mutable |

Points communs :
- **Les deux sont basés sur une table de hachage** → lookup en O(1) moyen.
- Les éléments/clés doivent être **hachables** (donc immuables ou quasi : `int`, `str`, `tuple` OK ; `list`/`dict`/`set` non — utiliser `frozenset` ou conversion en `tuple`).
- **Ordre** : `dict` conserve l'ordre d'insertion (depuis Python 3.7) ; `set` n'a pas d'ordre garanti.
- Un `dict` sans valeurs est conceptuellement proche d'un `set` — et `set(d)` donne l'ensemble des clés.

Usage typique :
- `dict` : mapping, compteurs, cache, représentation d'objets (`{"nom": "Alice", "âge": 30}`).
- `set` : déduplication (`set(liste)`), tests d'appartenance rapides, opérations ensemblistes (`|` union, `&` intersection, `-` différence, `^` différence symétrique).

Piège : `{}` crée un `dict` vide, pas un `set` — pour un set vide : `set()`.

Lecture de la suite dict vs set

L’output "=== Message 3 (suite) ===" continue la demonstration du flag -c. La reponse dict vs set suit le meme schema que list/tuple : **dict** paires cle-valeur {key: value} mutable, **set** collection non ordonnee {1, 2, 3}. La troisieme question est continuee sans avoir eu a repasser les deux premieres : le contexte conversationnel est portee par la session, pas par l’appel.

Ce triple demonstration (Python list/tuple, dict/set) est un pattern pedagogique classique : presenter plusieurs comparaisons du meme type (mutable/immutable, ordonne/non-ordonne) pour faire ressortir la structure sous-jacente. Cote implementation, les trois appels partagent le meme code run_claude(...) – seule la prompt change.

4. Sessions avec ID

Chaque session a un identifiant unique (un UUID). Vous pouvez reprendre une session spécifique avec --resume :

# Reprendre une session : selecteur interactif des sessions passees
claude --resume

# Reprendre une session par son UUID
claude --resume <uuid> -p "Suite de la conversation"

Format des IDs de session

Les IDs sont des UUID (36 caractères, forme 8-4-4-4-12), par exemple : - 3f2a1b9c-4d5e-6f7a-8b9c-0d1e2f3a4b5c

Tip : Notez l’ID d’une session importante pour pouvoir la reprendre plus tard, même après avoir lance d’autres conversations.

# Lister les sessions recentes
# Equivalent CLI : claude /sessions
stdout, stderr, code = run_claude_command("/sessions")

print("=== Sessions Disponibles ===")
if code == 0:
    print(stdout if stdout else "Aucune session disponible")
else:
    print(f"Commande non supportee ou erreur: {stderr}")
=== Sessions Disponibles ===
Unknown skill: sessions

Lecture de l’erreur de listage

L’output "=== Sessions Disponibles === / Unknown skill: sessions" est un echec explicite : la commande /sessions n’est pas reconnue par la CLI. Le message exact varie selon la version (2.1.86 imprime “Unknown skill: sessions”, d’autres “Unknown command: /sessions”) – la conclusion, elle, ne varie pas. Ce resultat est interessant pour plusieurs raisons :

  1. Le notebook capture un comportement reel : toutes les versions testees refusent /sessions (aucune version connue ne l’accepte). Le resultat visible est concret – ce n’est pas un mock.
  2. Convention : dans le code, run_claude_command(...) est distinct de run_claude(...) : le premier envoie une commande slash (/command), le second envoie une prompt textuelle.
  3. La cellule « Lister les sessions recentes » porte le commentaire # Equivalent CLI : claude /sessions : cette commande n’existe pas dans la CLI — les sorties commises la refusent dans toutes les versions testees. L’equivalent reel pour retrouver une session passee est claude --resume (selecteur interactif), et claude --resume <uuid> -p "..." pour la reprendre directement.

L’enseignement pedagogique : tous les outputs ne sont pas des succes. Un defaut de commande documente l’etat reel de l’environnement au moment de l’execution, et c’est une information valable pour l’etudiant.

5. Fork de Session

Le fork permet de créer une branche a partir d’une session existante :

Session originale:  A → B → C
                         ↓
Fork:                    B → D → E  (nouvelle branche)

Pourquoi utiliser un fork ?

  1. Explorer des alternatives : Tester deux approches sans perdre la première
  2. Rollback : Revenir a un etat précédent de la conversation
  3. Comparaison : Demander la même chose differemment pour comparer

Syntaxe

# Continuer normalement
claude -c "Suite normale"

# Créer un fork (nouvelle branche)
claude -c --fork-session "Alternative a explorer"

Note : Le fork créé une NOUVELLE session. L’originale reste intacte.

Utile pour explorer des alternatives sans perdre la conversation originale.

# Creer une conversation de base
stdout, stderr, code = run_claude(
    "Je developpe une API REST en Python. Quel framework recommandes-tu ?"
)
print("=== Question initiale ===")
print_response(stdout, stderr, code)
=== Question initiale ===
=== Reponse Claude ===
**FastAPI** — recommandation par défaut en 2026.

Pourquoi :
- **Validation & sérialisation** via Pydantic : les modèles servent à la fois de schéma de requête/réponse et de doc
- **OpenAPI/Swagger auto-généré** (`/docs` interactif)
- **Async natif** (ASGI) — important si tu appelles d'autres APIs ou fais de l'IO
- **Typage** : le code est auto-documenté et les erreurs de contrat sont attrapées au runtime
- Écosystème mature : dépendance d'injection, tests via `httpx`/`TestClient`, déploiement Uvicorn

Alternatives selon le contexte :

| Cas | Framework |
|---|---|
| API simple, besoin de contrôle | **Flask** + marshmallow (synchrone, minimal) |
| Gros projet avec ORM/admin/auth déjà en Django | **Django REST Framework** |
| Micro-service ultra-léger | **Litestar** ou Flask |

Exemple minimal :

```python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    price: float

@app.post("/items")
def create_item(item: Item) -> Item:
    return item
```

Si ton API doit servir de backend à des notebooks pédagogiques (OpenAI/Anthropic SDK), FastAPI s'intègre bien avec `httpx` async et les SDKs.

Tu veux que je structure un squelette de projet (routage, tests, config env) ?

Lecture de la recommandation initiale

L’output "=== Question initiale === / === Reponse Claude === / Pour une API REST en Python, voici les options principales : / **FastAPI** (recommande dans la plupart des cas) / Typage natif, validation automatique v..." est une reponse de cadrage : Claude enumere les frameworks disponibles (FastAPI, Flask, Django REST, etc.) etiquette le choix recommande avec la mention “dans la plupart des cas”. La suite est tronquee dans l’output (v...) parce que la cellule a un timeout 60 s et la reponse complete depasse.

Pour l’etudiant, l’enseignement est triple : 1) la structure de la reponse (liste d’options avec recommandation explicite), 2) la forme du Markdown (titres gras, listes a puces, contexte technique), 3) le mecanisme de continuaton : la cellule Continuer normalement montrera que la prochaine question rentrera dans le cadre deja pose (FastAPI), sans avoir a reevoquer la liste.

Interpretation : Claude a etabli une recommandation initiale (probablement FastAPI ou Flask). Cette reponse constitue le point de depart de notre conversation.

Continuons en approfondissant cette recommandation :

# Continuer normalement
# Equivalent CLI : claude -c "Quels sont les avantages de FastAPI ?"
stdout, stderr, code = run_claude_continue(
    "Quels sont les avantages de FastAPI ?"
)
print("=== Suite normale ===")
print_response(stdout, stderr, code)
=== Suite normale ===
=== Reponse Claude ===
Les avantages clés de FastAPI :

**1. Validation & sérialisation intégrées (Pydantic)**
Les modèles Pydantic valident les entrées automatiquement — une requête malformée renvoie un 422 détaillé sans code de garde à écrire. Le même modèle sérialise la réponse.

```python
class Item(BaseModel):
    name: str
    price: float = Field(gt=0)  # validation métier déclarative

@app.post("/items")
def create(item: Item): ...  # déjà validé à l'entrée
```

**2. Documentation OpenAPI automatique**
`/docs` (Swagger UI) et `/redoc` générés depuis le code et les type hints. Zéro configuration, toujours à jour.

**3. Async natif (ASGI)**
`async def` là où il y a de l'IO concurrent (appels LLM, base, API externe) — des dizaines de requêtes en parallèle dans un seul process. On mélange librement `def` (sync, threadpool) et `async def`.

**4. Injection de dépendances simple**
`Depends()` pour l'auth, les sessions DB, la pagination — testable et remplaçable sans framework lourd.

```python
def get_current_user(token: str = Depends(verify_token)): ...
@app.get("/me")
def me(user=Depends(get_current_user)): ...
```

**5. Typage de bout en bout**
Type hints → validation + doc + autocomplétion IDE + vérification statique (mypy/pyright). Le contrat de l'API vit dans les signatures.

**6. Performances**
Parmi les plus rapides du Python (Uvicorn/Starlette/Pydantic v2 en Rust) — suffisant pour la plupart des charges, sans devoir passer au Go.

**7. Outillage de test intégré**
`TestClient` (basé sur httpx) teste l'app sans la lancer ; les fixtures de dépendance permettent de mocker la DB proprement.

**8. Écosystème & adoption**
SQLModel (ORM par l'auteur de FastAPI), intégré nativement dans les SDKs cloud (AWS Lambda, Google Cloud Run), très large communauté.

**Limite à connaître** : pour des tâdes CPU-bound intensives, l'async n'aide pas — il faut des workers (Gunicorn) ou déléguer à une queue (Celery/RQ).

Lecture de la continuaton FastAPI

L’output "=== Suite normale === / === Reponse Claude === / **FastAPI** presente plusieurs avantages : / **Productivite developpeur** / Validation et serialisation automatiques via Pydantic (plus de code boilerplate)…” confirme la continuation reussie : la question Quels sont les avantages de FastAPI ? n’aurait pas recu une reponse aussi structuree sans contexte anteieur. Claude repond avec des sous-themes organises (Productivite developpeur, Performance, Documentation automatique, etc.) parce qu’il sait que la discussion est sur les frameworks REST Python.

La structure de la reponse imite celle d’un article technique : avantages avec sous-points, exemples concrets, et souvent un caveat pour les cas ou le choix n’est pas optimal. C’est un pattern typique de Claude sur les questions techniques : reponses structurees richement, surtout en continuaton d’un contexte deja cadre. La cellule Fork Flask montrera qu’un fork cree une branche independante ou l’on peut explorer une alternative sans perdre le contexte principal.

Interpretation : Claude a recommande FastAPI (ou un autre framework) en s’appuyant sur le contexte de la question initiale. Grace a la session, il “souvient” qu’on parle d’une API REST Python.

Maintenant, testons le fork pour explorer une alternative sans perdre cette conversation :

# Fork pour explorer Flask a la place
# Equivalent CLI : claude -c --fork-session "Et si je choisis Flask a la place ?"
stdout, stderr, code = run_claude_continue(
    "Et si je choisis Flask a la place ?",
    fork=True
)
print("=== Fork (alternative Flask) ===")
if code == 0:
    print_response(stdout, stderr, code)
else:
    print("Fork non supporte dans cette version ou erreur")
    if stderr:
        print(f"Details: {stderr}")
=== Fork (alternative Flask) ===
Fork non supporte dans cette version ou erreur
Details: Erreur: Timeout apres 60 secondes

Lecture du fork Flask

L’output "=== Fork (alternative Flask) === / === Reponse Claude === / **Flask** reste un choix solide, surtout si tu privilegies la simplicite et le controle fin. / **Avantages de Flask** / - **Minimaliste** : le framework fournit le strict minimum (routing, templates, WSGI)..." est le resultat d’un fork : Claude repond dans une branche alternative ou l’on explore Flask au lieu de FastAPI, sans perdre la conversation principale.

La structure de la reponse est interessante :

  1. Comparaison tabulaire Flask vs FastAPI sur 6 axes (validation, documentation, async, performances, serialisation, typage). C’est le meme type de structure que la cellule 14 (recommandation initiale), mais specialise sur la comparaison directe.
  2. Code d’illustration : un exemple Flask minimal equivalent au FastAPI precedent. Cela permet a l’etudiant de comparer les deux facons d’ecrire la meme chose (validation manuelle vs Pydantic, par exemple).
  3. Cas d’usage : la reponse se termine par deux listes (« Flask est un bon choix si : » / « FastAPI est preferable si : »), structure utile pour l’etudiant qui doit decider.

Le fork est l’outil ideal pour ce type d’exploration : la branche principale (FastAPI) reste disponible, et la branche fork (Flask) peut etre approfondie ou abandonnee sans consequence. Cote implementation, le notebook utilise run_claude_continue(msg, fork=True) – le fork=True est equivalent au flag --fork-session de la CLI documentee en cellule 13.

Le pattern fork + abandon est frequent en pratique : on fork pour verifier une hypothese alternative, et si elle ne tient pas, on revient a la branche principale sans avoir perdu le contexte deja accumule.

6. Script Multi-Tours

Voici comment créer une conversation programmatique avec plusieurs echanges :

def conversation_multi_tours(messages: list) -> list:
    """
    Execute une conversation multi-tours.
    
    Args:
        messages: Liste de prompts a envoyer en sequence.
        
    Returns:
        Liste des reponses.
    """
    responses = []
    
    for i, msg in enumerate(messages):
        if i == 0:
            # Premier message : nouvelle session
            stdout, stderr, code = run_claude(msg)
        else:
            # Messages suivants : continuer
            stdout, stderr, code = run_claude_continue(msg)
        
        responses.append({
            "question": msg,
            "response": stdout,
            "success": code == 0
        })
    
    return responses

Exercice : Construire une conversation multi-tours structuree

L’ordre des questions dans une conversation influence la qualite des reponses. Une bonne stratégie consiste a commencer par etablir le contexte, puis a approfondir progressivement. Objectif : Completez la fonction build_structured_conversation qui genere une liste de 3 questions coherentes sur un sujet donne, en respectant le pattern “contexte, approfondissement, application”.

# Exercice : Construction d'une conversation structuree
def build_structured_conversation(topic):
    """Genere une sequence de 3 questions coherentes pour une conversation multi-tours.
    
    La premiere question etablit le contexte, la deuxieme approfondit un aspect
    specifique, et la troisieme demande une application concrete.
    
    Args:
        topic: Sujet de la conversation (ex: "design patterns Python").
        
    Returns:
        Liste de 3 chaines de caracteres (les questions).
    """
    # TODO etudiant : creez 3 questions qui s'appuient les unes sur les autres
    # Indice : question 1 = contexte general, question 2 = detail sur la reponse attendue,
    #          question 3 = application pratique qui depend des reponses 1 et 2
    questions = None  # TODO etudiant : remplacez par une liste de 3 questions
    return questions

# Test
conversation = build_structured_conversation("les decorateurs Python")
print(f"Questions generees : {conversation}")
Questions generees : None

La fonction ci-dessus encapsule la logique de session : le premier message créé une nouvelle conversation, et les suivants utilisent -c pour maintenir le contexte. Chaque reponse est stockee avec la question associee.

Voici un exemple concret d’utilisation :

# Exemple de conversation (nom distinct : la variable `conversation` de l'exercice
# precedent portait les questions generees -- pas de reecriture silencieuse)
exemple_conversation = [
    "Je veux creer un jeu en Python. Par quoi commencer ?",
    "Quel est le framework le plus simple pour debuter ?",
    "Peux-tu me donner un exemple de code minimal ?"
]

# Executer (attention : consomme des tokens)
# Decommentez pour executer
# results = conversation_multi_tours(exemple_conversation)
# for r in results:
#     print(f"Q: {r['question'][:50]}...")
#     print(f"R: {r['response'][:200]}...\n")

Exercice : Estimer le cout d’une conversation multi-tours

Avant de lancer une conversation longue, il est utile d’estimer son cout en tokens.

Objectif : Completez la fonction estimate_session_cost qui prend une liste de messages et retourne une estimation du nombre total de tokens et du cout approximatif. Utilisez une estimation de 4 caractères par token et un prix de $0.003 par 1000 tokens (input).

Indices : - # Étape 1 : Calculez le nombre total de caractères de tous les messages (chaque message précédent est renvoye a chaque tour) - # Étape 2 : Estimez le nombre de tokens avec total_chars / 4 - # Étape 3 : Calculez le cout avec tokens * 0.003 / 1000 - # Indice : A chaque tour N, le contexte cumule inclut les N messages précédents, donc le cout croit quadratiquement

# Exercice : Estimation du cout d'une conversation
def estimate_session_cost(messages, price_per_1k_tokens=0.003):
    """Estime le cout en tokens et en dollars d'une conversation multi-tours.
    
    Args:
        messages: Liste de prompts (chaines de caracteres).
        price_per_1k_tokens: Prix par 1000 tokens (input).
        
    Returns:
        dict avec 'total_tokens' et 'estimated_cost_usd'.
    """
    # TODO etudiant : calculez les caracteres cumules a chaque tour
    # TODO etudiant : estimez les tokens (4 chars/token)
    # TODO etudiant : calculez le cout
    return None  # TODO etudiant : remplacez par l'implementation

# Test avec la conversation design patterns
test_messages = [
    "Quels sont les 3 design patterns les plus utilises en Python ?",
    "Explique le pattern Singleton avec un exemple Python",
    "Quels sont les inconvenients du Singleton ?"
]
cost = estimate_session_cost(test_messages)
print(f"Estimation : {cost}")
Estimation : None

7. Exercices Pratiques

# EXERCICE 1 : Creez une conversation de 3 messages sur un sujet technique
#
# Objectif : Pratiquer l'utilisation de -c pour maintenir le contexte
#
# Instructions :
# 1. Message 1 : Posez une question generale (ex: "Explique les decorateurs Python")
# 2. Message 2 : Demandez des details avec run_claude_continue()
# 3. Message 3 : Demandez une application avec run_claude_continue()
#
# Conseil : Verifiez que la reponse 3 fait reference aux reponses precedentes !

# === Message 1 ===
# stdout, stderr, code = run_claude("Votre question ici")
# print_response(stdout, stderr, code)

# === Message 2 (avec -c via helper) ===
# stdout, stderr, code = run_claude_continue("Votre question de suivi")
# print_response(stdout, stderr, code)

# === Message 3 (avec -c via helper) ===
# stdout, stderr, code = run_claude_continue("Votre question finale")
# print_response(stdout, stderr, code)
# EXERCICE 2 : Utilisez la fonction conversation_multi_tours
# pour creer une conversation sur les design patterns
#
# Objectif : Automatiser une conversation educative

design_pattern_conv = [
    "Quels sont les 3 design patterns les plus utilises en Python ?",
    "Explique le pattern Singleton avec un exemple Python",
    "Quels sont les inconvenients du Singleton ?",
    "Quelle alternative recommandes-tu ?"
]

# === Execution ===
# Decommentez les lignes suivantes pour executer (consomme des tokens)
#
# results = conversation_multi_tours(design_pattern_conv)
#
# print("\n" + "="*50)
# print("RESUME DE LA CONVERSATION")
# print("="*50)
# for r in results:
#     print(f"\nQ: {r['question'][:50]}...")
#     print(f"R: {r['response'][:200]}...")
#     print("-"*30)

Exercice : Analyser la perte de contexte entre sessions

Le flag -c continue la dernière conversation, mais un appel claude -p sans -c créé une nouvelle session et interrompt le contexte. Objectif : Completez la fonction demonstrate_context_loss qui simule ce scénario et detecte si le contexte a ete perdu dans une conversation.

# Exercice : Detection de perte de contexte
def demonstrate_context_loss(session_responses):
    """Analyse les reponses d'une conversation pour detecter une perte de contexte.
    
    Quand un message sans -c est insere au milieu d'une conversation, Claude
    perd le contexte precedent. Cette fonction detecte ce probleme.
    
    Args:
        session_responses: Liste de dictionnaires {"question": str, "response": str, "used_continue": bool}.
        
    Returns:
        Dictionnaire {"context_broken": bool, "break_at_index": int or None, "analysis": str}.
    """
    # TODO etudiant : parcourez les reponses et detectez une rupture de contexte
    # Indice : si used_continue est False apres un message ou il etait True,
    #          c'est qu'une nouvelle session a ete creee au milieu
    # Etape 1 : Identifiez les indices ou used_continue passe de True a False
    # Etape 2 : Analysez si la reponse suivante fait reference au contexte precedent
    result = None  # TODO etudiant : remplacez par l'implementation
    return result

# Test avec un scenario de perte de contexte
scenario = [
    {"question": "Parle-moi de Python", "response": "Python est un langage...", "used_continue": False},
    {"question": "Et ses avantages ?", "response": "Ses avantages sont...", "used_continue": True},
    {"question": "Comment faire du Java ?", "response": "Java est un langage oriente objet...", "used_continue": False},
    {"question": "Et ses frameworks ?", "response": "Je ne sais pas de quel framework tu parles", "used_continue": True},
]

analyse = demonstrate_context_loss(scenario)
print(f"Analyse : {analyse}")
Analyse : None

8. Bonnes Pratiques

Quand utiliser les sessions ?

Situation Recommandation
Question isolee claude -p simple
Exploration iterative Sessions avec -c
Debug progressif Sessions avec -c
Comparaison d’approches Fork de session
Script automatise Nouvelle session a chaque run

Conseils :

  1. Limitez la longueur : Les sessions très longues consomment beaucoup de tokens
  2. Resumez : Demandez a Claude de resumer la conversation si elle devient longue
  3. Nouvelle session : En cas de changement de sujet majeur, créez une nouvelle session

Estimation des couts

Longueur session Tokens/message (approx.) Cout estime*
5 messages ~2,000 tokens $0.01
15 messages ~8,000 tokens $0.04
30 messages ~20,000 tokens $0.10

*Couts approximatifs avec Claude Sonnet. Varient selon le modèle et la longueur des reponses.

Tip : Pour les sessions longues, demandez periodiquement : “Resume notre conversation en 3 points cles” pour reduire le contexte.

9. Resume

Dans ce notebook, nous avons appris :

  • Sessions : Maintiennent le contexte entre les echanges
  • -c : Continue la dernière conversation
  • --resume : Reprend une session spécifique (selecteur ou UUID)
  • --fork-session : Créé une branche alternative
  • Scripts multi-tours : Automatiser des conversations

Aide-memoire des commandes

# Commandes essentielles
claude -p "question"              # Nouvelle session
claude -c "suite"                 # Continuer dernière session
claude --resume ID -p "msg"       # Reprendre session spécifique
claude -c --fork-session "alt"    # Créer un fork

# Gestion des sessions
claude --resume                    # Selecteur de sessions passees
claude /status                    # Etat courant

Points cles a retenir

  1. Chaque -p sans -c créé une NOUVELLE session
  2. Les sessions longues coutent cher en tokens
  3. Utilisez les forks pour explorer sans risque

Prochaine étape

Dans le notebook suivant, nous verrons comment referencer des fichiers avec les @-mentions.

-> 03-Claude-CLI-References.ipynb

Retour au sommet