Cette étude de cas relie à AgentChat un SaaS d’histoires utilisant déjà l’IA, appelé StoryShelf. Un utilisateur crée une histoire par conversation ; l’agent écrit les enregistrements structurés de l’histoire et des chapitres via les API de StoryShelf, lance des tâches d’illustration, examine les URL d’images renvoyées et met à jour l’histoire. StoryShelf lit ensuite sa propre base de données et affiche le résultat dans sa bibliothèque et son éditeur habituels.
Le point important est qu’AgentChat ne devient pas la base de données des histoires et que StoryShelf ne transforme pas une longue réponse de l’assistant en enregistrements. L’agent effectue les mêmes opérations contrôlées que l’application StoryShelf comprend déjà.
Étape 1 : exposer le pack de capacités de StoryShelf
POST /v1/stories
GET /v1/stories/{story_id}
POST /v1/stories/{story_id}/chapters
PUT /v1/stories/{story_id}/chapters/{chapter_id}
POST /v1/image-jobs
GET /v1/image-jobs/{job_id}
PUT /v1/stories/{story_id}/cover Chaque réponse de création renvoie des identifiants stables. Les écritures d’histoires et de chapitres sont idempotentes grâce à client_request_id, de sorte qu’une nouvelle tentative ne crée pas de doublons. Les tâches d’image sont asynchrones et renvoient poll_after_seconds. La réponse d’une image terminée contient asset_id et image_url, jamais de données en base64.
Étape 2 : provisionner le document StoryShelf
POST /api/api-documents
Authorization: Bearer ac_live_AGENT_CHAT_KEY
Content-Type: application/json
{
"title": "StoryShelf Story and Illustration API",
"description": "Create stories and chapters, generate illustrations, and attach image assets.",
"content": "# StoryShelf API\nBase URL: https://stories.example.com/v1\n\nCreate the story record before chapters and preserve every returned ID. Write chapters one at a time.\n\nPOST /stories body: client_request_id, title, audience, style, premise, outline[]. Response: story_id, status.\n\nPOST /stories/{story_id}/chapters body: client_request_id, position, title, content. Response: chapter_id, revision.\n\nPOST /image-jobs body: client_request_id, story_id, chapter_id optional, prompt, aspect_ratio. Response: job_id, status, poll_after_seconds. Start the job in one turn; sleep and poll in a later turn.\n\nGET /image-jobs/{job_id} returns status and, when succeeded, asset_id and image_url. Call view_image when visual inspection is useful.\n\nPUT /stories/{story_id}/cover body: asset_id.\n\nNever publish a draft unless the user explicitly asks."
} Le document contient des règles de workflow qui ne peuvent pas être déduites de manière fiable d’une simple liste de chemins OpenAPI : préserver les identifiants, séparer les opérations asynchrones, inspecter les URL des images et ne pas publier implicitement.
Étape 3 : créer la session d’histoire de l’utilisateur
POST /api/agent/sessions
Authorization: Bearer ac_live_AGENT_CHAT_KEY
Content-Type: application/json
{
"title": "Story creator for user_88",
"llm_config_id": "creative_model_uuid",
"api_document_ids": ["story_api_document_uuid"],
"system_prompt": "Help the user plan and create stories. Save approved creative work through StoryShelf APIs. Keep the user informed when image jobs are running.",
"max_turns": 25,
"tool_timeout_seconds": 180,
"tool_result_max_chars": 12000,
"host_headers": [
{ "host": "stories.example.com", "header_key": "Authorization", "header_value": "Bearer short_lived_story_user_token" }
]
} StoryShelf crée cette session depuis son backend et stocke l’UUID de session renvoyé à côté de la conversation de l’utilisateur. L’en-tête à courte durée de vie limite toutes les lectures et écritures de l’API des histoires à user_88. Il est injecté au moment de la requête et n’est inclus ni dans le contexte du LLM ni dans les réponses de l’API AgentChat.
Étape 4 : permettre à l’utilisateur de créer via le chat
POST /api/agent/sessions/session_uuid/chat
Authorization: Bearer ac_live_AGENT_CHAT_KEY
Content-Type: application/json
{
"message": "Create a three-chapter story for ages 8-10 about a child who repairs a lighthouse for lost spaceships. Use a gentle watercolor style and make an illustrated cover."
} AgentChat stocke le message de l’utilisateur et renvoie l’état « processing ». L’interface StoryShelf commence immédiatement à interroger les messages au lieu de maintenir la requête de chat ouverte.
La séquence concrète des appels d’outils
- L’agent planifie le titre, le principe, le public, le style et un plan en trois parties.
- Il appelle POST /stories et reçoit story_id story_123.
- Il écrit les chapitres un, deux et trois via des appels distincts à l’API et conserve chaque chapter_id.
- Il crée un prompt d’image cohérent avec le style enregistré de l’histoire et appelle POST /image-jobs.
- Comme la tâche doit s’achever de manière asynchrone, le tour de modèle suivant appelle sleep en utilisant poll_after_seconds, puis une requête ultérieure interroge GET /image-jobs/job_7.
- Lorsque la réponse contient image_url, l’agent appelle view_image afin que l’illustration soit intégrée au contexte en tant qu’entrée multimodale native.
- Si l’image correspond à l’histoire, il appelle PUT /stories/story_123/cover avec asset_id. Dans le cas contraire, il soumet un prompt révisé comme nouvelle tâche.
- Il termine en fournissant l’identifiant de l’histoire enregistrée, le résumé du chapitre et l’état de la couverture.
Les résultats des outils sont persistés au fur et à mesure de leur exécution, mais la requête suivante adressée au modèle reçoit les résultats des outils exécutés simultanément dans l’ordre d’origine des appels d’outils. Le document de l’API devrait déconseiller les écritures dépendantes dans le même lot parallèle lorsqu’un appel a besoin d’un identifiant renvoyé par un autre.
Étape 5 : fusionner correctement les messages d’AgentChat
GET /api/agent/sessions/session_uuid/messages?after_id=msg_uuid&after_revision=6
Authorization: Bearer ac_live_AGENT_CHAT_KEY Le client StoryShelf ne remplace un message que lorsque sa révision augmente. Il peut afficher le texte de l’assistant, une activité compacte de tâche d’illustration et un aperçu final de l’image. Les messages partiels de l’assistant ayant échoué restent visibles, mais AgentChat les exclut du contexte futur du LLM.
Si la génération d’images utilise le budget de tours restant, AgentChat renvoie un état dont next_action est défini sur continue. StoryShelf affiche un bouton « Continuer » et appelle POST /api/agent/sessions/session_uuid/continue. La nouvelle exécution reçoit un nouveau budget de tours et reprend à partir des messages persistants.
Étape 6 : générer l’histoire à partir de la base de données StoryShelf
POST /stories, POST /chapters et PUT /cover ont déjà écrit des enregistrements validés dans StoryShelf. La page de la bibliothèque interroge les tables StoryShelf et affiche le nouveau titre et la nouvelle couverture. L’éditeur charge les chapitres à l’aide de story_id. La transcription du chat n’est pas analysée pour reconstruire l’histoire.
Cette conception rend sûre une finalisation partielle. Si la tâche de création de la couverture échoue, les trois chapitres existent toujours. L’utilisateur peut poursuivre la même session AgentChat et demander une nouvelle couverture sans générer à nouveau l’histoire.
Ce qui doit être testé avant le lancement
- Réessayer la création de l’histoire et des chapitres avec le même client_request_id et vérifier qu’aucun enregistrement en double n’apparaît.
- Retournez un échec de tâche d’image et vérifiez que l’agent préserve l’histoire et explique l’étape de récupération possible.
- Arrêtez-vous pendant l’interrogation des images, puis poursuivez la session et terminez la couverture.
- Essayez de lire l’identifiant de l’histoire d’un autre utilisateur avec le jeton injecté et vérifiez que StoryShelf renvoie 403 ou « introuvable ».
- Retournez une URL d’image invalide et vérifiez que l’agent signale l’erreur de l’outil au lieu de l’insérer comme texte.
- Actualisez la bibliothèque StoryShelf à partir de sa propre base de données après chaque mutation terminée.