ISNAD Scientific Platform

Documentation Center
V1 · Référence officielle

Architecture

Live AI Vocal Hadith Agent — contrat public minimal des tools

7 min de lectureMis à jour le 29 octobre 2026
Sur cette page

Principes communs#

  • Contrat indépendant de tout fournisseur d'IA.
  • Huit tools nommés, strictement READ ONLY ; aucun SQL, nom de table ou RPC libre n'est accepté depuis le LLM.
  • Les identifiants retournés sont les IDs canoniques ISNAD lorsqu'ils existent.
  • Toute liste est bornée. Un dépassement est refusé ou plafonné explicitement avec truncated: true.
  • Toute affirmation scientifique porte evidence_status: "fact" | "inference" | "insufficient_evidence" et une provenance. Ici, fact signifie « directement présent dans la source ou le dataset cité », pas « vérité historique absolue ».
  • Une relation probable, ambiguous, unresolved ou seulement possible conserve ce statut et ne devient jamais attested.
  • Les embeddings peuvent seulement découvrir des candidats. Ils ne constituent jamais une preuve et ne sont pas disponibles dans le contrat actuel.
  • Forme minimale commune de provenance :
{
  "source_type": "corpus|scholarly_work|commentary|dataset",
  "source_id": "string|null",
  "source_key": "string|null",
  "citation": "string|null",
  "locator": { "page": "string|null", "volume": "string|null" }
}

Conventions transversales communes (Task 2B)#

Ces conventions s'appliquent aux huit tools. Aucune n'exige de nouvel objet DB ni de migration.

A. Statut scientifique (evidence_status)#

Trois valeurs, et seulement trois :

valeursignification
factProposition directement soutenue par les données ISNAD retournées dans la même réponse (présente telle quelle dans la source ou le dataset cité).
inferenceConclusion dérivée explicitement des données retournées, par un raisonnement traçable jusqu'à ces données.
insufficient_evidenceLes données disponibles ne permettent pas d'établir la proposition.

Règle impérative : absence de résultat ≠ preuve du contraire. Un tool qui ne trouve rien retourne insufficient_evidence (ou une liste vide + capability_note), jamais une négation présentée comme un fact.

fact ne signifie pas « vérité historique absolue » mais « attesté dans la donnée citée ».

B. Provenance commune#

Toute affirmation portant un evidence_status porte au moins une entrée provenance. Structure minimale (tous les champs sont optionnels sauf object_id et object_type, et aucun ne nécessite de migration DB) :

{
  "object_id": "string|integer",
  "object_type": "hadith|chain|chain_node|narrator|narrator_entry|relation|commentary_passage|source|dataset",
  "source_id": "string|null",
  "source_title": "string|null",
  "edition_id": "string|null",
  "locator": "string|null"
}

locator est une chaîne libre (page, volume, offset, commit/hash…) quand la surface actuelle la fournit ; sinon null. Un champ inconnu vaut null, jamais une valeur reconstruite.

C. Erreurs communes#

Ensemble fermé de codes. Chaque erreur est un objet { "code": ..., "message": ... }. Le message est court, lisible, sans donnée sensible. Aucune stack trace, aucun nom de table, aucun SQL n'est jamais exposé.

codeusage
INVALID_ARGUMENTentrée malformée, type incorrect, valeur hors domaine.
NOT_FOUNDidentifiant valide mais aucun objet correspondant.
AMBIGUOUSl'entrée correspond à plusieurs objets canoniques et ne peut être résolue.
INSUFFICIENT_EVIDENCEla demande ne peut être satisfaite avec le niveau de preuve requis.
LIMIT_EXCEEDEDlimit demandé au-dessus du hard max.
UNAVAILABLEdépendance en amont indisponible ou capacité non déployée.
INTERNAL_ERRORdéfaut inattendu ; message générique uniquement.

Les codes historiques employés dans les sections par-tool (invalid_input, not_found, upstream_unavailable, …) sont des alias lisibles de cet ensemble et seront normalisés par le Gateway.

D. Limites#

  • Toute liste est bornée. Aucune requête non bornée n'est acceptée.
  • Default limit : 5 (sauf indication contraire d'une section par-tool, ex. get_narrator_profile = 10, get_narrator_hadiths = 10).
  • Hard max : 20 (exception publique explicite : get_narrator_hadiths = 50).
  • Un limit supérieur au hard max → LIMIT_EXCEEDED, jamais un silencieux plafonnement sans signal.
  • Un résultat plafonné porte truncated: true.
  • Le timeout est une responsabilité future du Gateway ; le contrat ne le spécifie pas ici.

E. Relations entre narrateurs#

possible ≠ attested. Le champ relation_status prend exactement :

valeursignification
attestedRelation de transmission enregistrée avec une evidence/provenance identifiable.
possibleRelation plausible (co-occurrence, indice partiel) mais non enregistrée comme attestée.
not_establishedAucune relation ne peut être établie à partir des données disponibles.

Une valeur attested doit être accompagnée d'au moins une entrée provenance pointant l'evidence. Sans provenance identifiable, le statut ne peut pas être attested. Aucun nouveau moteur scientifique n'est introduit ; les statuts existants (probable, ambiguous, unresolved) restent valides et se rangent sous possible / not_established lors de la normalisation Gateway.

F. Recherche sémantique#

vector / embedding similarity = candidate discovery only.

Un score vectoriel :

  • n'est pas une preuve ;
  • n'est pas une validation scientifique ;
  • reste distinct de evidence_status (il ne le fixe jamais à fact).

Un résultat issu d'une recherche vectorielle porte au mieux evidence_status: "inference" et son score dans un champ séparé (score), jamais confondu avec le niveau de preuve.

G. Indépendance fournisseur#

Le contrat ne dépend d'aucun fournisseur ni format propriétaire de function calling : ni OpenAI, ni Realtime API, ni Claude, ni Codex, ni Copilot. Les huit tools sont décrits en JSON neutre. Le futur Gateway adapte ce contrat au fournisseur effectivement utilisé (mapping des noms, des schémas et des codes d'erreur).

1. search_hadith#

  • Purpose: trouver des hadiths candidats par recherche lexicale arabe ou référence canonique.
  • Input JSON shape:
{ "query": "string", "query_language": "ar|fr|auto", "collection_id": "integer|null", "limit": "integer|null" }
  • Output JSON shape:
{
  "results": [{
    "hadith_id": "integer",
    "canonical_reference": "string",
    "text_ar": "string|null",
    "text_fr": "string|null",
    "match_method": "exact|fulltext|fuzzy|reference",
    "score": "number|null",
    "evidence_status": "inference",
    "provenance": [{}]
  }],
  "truncated": "boolean",
  "capability_note": "string|null"
}
  • Limit: défaut 5, maximum 20.
  • Principales erreurs: invalid_input, unsupported_language, limit_exceeded, upstream_unavailable.
  • Provenance minimale: source_key, collection et référence canonique de chaque hit.
  • Status actuel: PARTIAL — recherche arabe lexicale disponible ; recherche française et vectorielle absentes. Une requête française non couverte retourne honnêtement insufficient_evidence/capability_note, jamais des résultats inventés.

2. get_hadith#

  • Purpose: retourner un hadith canonique et sa référence de corpus.
  • Input JSON shape:
{ "hadith_id": "integer" }
  • Output JSON shape:
{
  "hadith_id": "integer",
  "canonical_reference": "string",
  "collection": { "id": "integer", "code": "string", "name": "string|null" },
  "book": { "id": "integer", "number": "string|null", "title": "string|null" },
  "chapter": { "id": "integer", "number": "string|null", "title": "string|null" },
  "text_ar": "string|null",
  "text_fr": "string|null",
  "evidence_status": "fact",
  "provenance": [{}]
}
  • Limit: non applicable ; exactement un hadith.
  • Principales erreurs: invalid_id, not_found, upstream_unavailable.
  • Provenance minimale: clé source, collection, livre, chapitre et métadonnées dataset/import disponibles.
  • Status actuel: READY.

3. get_hadith_chains#

  • Purpose: retourner les chaînes observées d'un hadith, ordonnées sans transformer leur résolution en certitude.
  • Input JSON shape:
{ "hadith_id": "integer", "limit": "integer|null" }
  • Output JSON shape:
{
  "hadith_id": "integer",
  "chains": [{
    "chain_id": "integer",
    "chain_number": "integer",
    "nodes": [{
      "position": "integer",
      "narrator_id": "integer|null",
      "mention_ar": "string|null",
      "transmission_term_ar": "string|null",
      "resolution_status": "confirmed|probable|ambiguous|unresolved",
      "confidence": "number|null"
    }],
    "evidence_status": "fact|insufficient_evidence",
    "provenance": [{}]
  }],
  "truncated": "boolean"
}
  • Limit: défaut 5 chaînes, maximum 20.
  • Principales erreurs: invalid_id, not_found, limit_exceeded, upstream_unavailable.
  • Provenance minimale: clé/source de chaîne et référence du hadith ; statuts de résolution conservés par nœud.
  • Status actuel: READY.

4. search_narrator#

  • Purpose: trouver des narrateurs canoniques candidats à partir d'un nom arabe ou translittéré.
  • Input JSON shape:
{
  "query": "string",
  "query_language": "ar|latin|auto",
  "filters": { "grade_tier": "string|null", "region": "string|null", "generation": "string|null" },
  "limit": "integer|null"
}
  • Output JSON shape:
{
  "results": [{
    "narrator_id": "integer",
    "name_ar": "string|null",
    "name_fr": "string|null",
    "canonical_display": "string|null",
    "match_tier": "exact|prefix|substring|fulltext|fuzzy",
    "score": "number|null",
    "evidence_status": "inference",
    "provenance": [{}]
  }],
  "truncated": "boolean"
}
  • Limit: défaut 5, maximum 20.
  • Principales erreurs: invalid_input, unsupported_language, limit_exceeded, upstream_unavailable.
  • Provenance minimale: ID canonique, forme de nom ayant contribué au match et statut du canon d'affichage lorsqu'il existe.
  • Status actuel: READY — les résultats sont des candidats classés, pas des identifications certaines.

5. get_narrator_profile#

  • Purpose: retourner un profil narrateur structuré sans mélanger identité, données legacy et assertions savantes.
  • Input JSON shape:
{ "narrator_id": "integer", "entry_limit": "integer|null" }
  • Output JSON shape:
{
  "narrator_id": "integer",
  "identity": { "name_ar": "string|null", "name_fr": "string|null", "canonical_display": "string|null", "variants": [] },
  "legacy_scholarly_data": [{ "field": "string", "value": "unknown", "evidence_status": "fact|insufficient_evidence", "provenance": [{}] }],
  "source_entries": [{ "entry_id": "string", "text": "string", "resolution_status": "LINKED|AMBIGUOUS|CONFLICTED", "evidence_status": "fact|insufficient_evidence", "provenance": [{}] }],
  "canonical_assertions": [{ "field": "string", "value": "unknown", "evidence_status": "fact", "provenance": [{}] }],
  "truncated": "boolean",
  "capability_note": "string|null"
}
  • Limit: entry_limit défaut 10, maximum 20.
  • Principales erreurs: invalid_id, not_found, limit_exceeded, upstream_unavailable.
  • Provenance minimale: source/édition/locator pour chaque notice ou affirmation scientifique quand disponible ; statut de revue/résolution conservé.
  • Status actuel: PARTIAL — la façade publique d'assertions omet confiance, locator et preuves détaillées. Leur absence produit insufficient_evidence, jamais une reconstruction.

6. get_narrator_hadiths#

  • Purpose: retourner les occurrences certaines d'un narrateur canonique dans les chaînes du corpus.
  • Input JSON shape:
{ "narrator_id": "integer", "page": "integer|null", "limit": "integer|null" }
  • Output JSON shape:
{
  "narrator_id": "integer",
  "occurrence_count": "integer",
  "distinct_hadith_count": "integer",
  "page": "integer",
  "items": [{
    "hadith_id": "integer",
    "canonical_reference": "string",
    "chain_id": "integer",
    "node_id": "integer",
    "position": "integer",
    "relation_type": "chain_occurrence",
    "evidence_status": "fact",
    "provenance": [{}]
  }],
  "truncated": "boolean"
}
  • Limit: défaut 10, maximum public 50.
  • Principales erreurs: invalid_id, not_found, invalid_page, limit_exceeded, upstream_unavailable.
  • Provenance minimale: référence du hadith, chaîne/nœud, dataset/import et source disponibles.
  • Status actuel: READY — une occurrence n'implique ni relation maître/élève ni authenticité.

7. get_transmission_relation#

  • Purpose: décrire les relations de transmission enregistrées entre deux narrateurs canoniques, séparément des observations de chaîne.
  • Input JSON shape:
{ "narrator_a_id": "integer", "narrator_b_id": "integer", "include_chain_observations": "boolean|null", "limit": "integer|null" }
  • Output JSON shape:
{
  "narrator_a_id": "integer",
  "narrator_b_id": "integer",
  "relations": [{
    "teacher_id": "integer",
    "student_id": "integer",
    "relation_status": "attested|probable|ambiguous|unresolved",
    "evidence_status": "fact|inference|insufficient_evidence",
    "provenance": [{}]
  }],
  "chain_observations": [],
  "evidence_status": "fact|insufficient_evidence",
  "truncated": "boolean",
  "capability_note": "string|null"
}
  • Limit: défaut 10 éléments de preuve, maximum 20.
  • Principales erreurs: invalid_id, same_narrator, limit_exceeded, upstream_unavailable.
  • Provenance minimale: source/collection et texte source quand la surface actuelle les fournit ; chaîne/nœud/hadith pour toute observation de chaîne.
  • Status actuel: PARTIAL — le RPC existant omet collection et texte source. Une relation absente ou seulement possible retourne insufficient_evidence ou son statut exact, jamais attested.

8. get_hadith_commentary#

  • Purpose: retourner les passages de commentaire publiables et validés associés à un hadith canonique.
  • Input JSON shape:
{ "hadith_id": "integer", "language": "fr|ar|null", "limit": "integer|null" }
  • Output JSON shape:
{
  "hadith_id": "integer",
  "passages": [{
    "passage_id": "string|integer",
    "passage_kind": "string",
    "source_text": "string|null",
    "translation": { "language": "fr", "text": "string", "status": "PUBLISHED" },
    "alignment_status": "string",
    "alignment_confidence": "number|null",
    "evidence_status": "fact|inference",
    "provenance": [{}]
  }],
  "truncated": "boolean"
}
  • Limit: défaut 5, maximum 20.
  • Principales erreurs: invalid_id, not_found, unsupported_language, limit_exceeded, upstream_unavailable.
  • Provenance minimale: œuvre/auteur, édition, volume/page/offset, document URL ou dépôt/commit/hash, droits/licence et statut d'alignement disponibles.
  • Status actuel: READY — uniquement la vue publique filtrée ; aucune table privée de commentaire n'entre dans le contrat.

État global#

  • READY: 5 — get_hadith, get_hadith_chains, search_narrator, get_narrator_hadiths, get_hadith_commentary.
  • PARTIAL: 3 — search_hadith, get_narrator_profile, get_transmission_relation.
  • Étape suivante: Task 2B peut préciser les invariants et exemples de réponses sans implémenter le gateway ni créer d'objet DB.