# Références

Les citations relient des passages d’une réponse de l’assistant aux sources qui les étayent. Activez enableCitations lorsque vous créez ou reprenez une session, puis lisez la charge utile citations dans les événements assistant.message pour afficher des notes de bas de page, des listes de sources ou des liens intégrés.

<!-- markdownlint-disable GHD046 GHD005 -->

<!-- Suppressed: GHD046 (outdated release terminology), GHD005 (hardcoded data variable) -->

> \[!WARNING]
> Les citations sont expérimentales. Le nom de l’option, la charge utile d’événement et la couverture du fournisseur peuvent changer dans une version ultérieure.

## Fonctionnement des citations

Les citations sont produites par le fournisseur de modèles, et non par le Kit de développement logiciel (SDK). Le flux comporte trois parties :

1. Votre application fournit des documents citables, tels qu’une pièce jointe de document ou un résultat d’outil qui contient du contenu source.
2. L’environnement d’exécution marque ce contenu comme pouvant être cité sur le réseau lorsque `enableCitations` est activé. Pour les modèles Anthropic, les fichiers joints sont envoyés sous forme de blocs `document` avec les citations activées.
3. Le modèle renvoie des métadonnées de citation, et l’environnement d’exécution les normalise en un objet `citations` indépendant du fournisseur lors de l’événement final `assistant.message`.

La prise en charge du fournisseur est limitée. Champ `provider` sur chaque enregistrement source à partir duquel la citation provient :

| Valeur du fournisseur | Sens                                                                 |
| --------------------- | -------------------------------------------------------------------- |
| `anthropic`           | Citation produite par une réponse du modèle Anthropic (Claude)       |
| `openai`              | Citation produite par une réponse de modèle OpenAI                   |
| `client`              | Citation synthétisée par le runtime à partir de la sortie de l’outil |

> \[!NOTE]
> L’activation `enableCitations` ne garantit pas qu’une réponse contient des citations. Les modèles les émettent uniquement lorsque la réponse est ancrée dans le matériau source citable. Traitez toujours le `citations` champ comme facultatif.

## Activer les citations sur une session

Définissez l’option sur la création de session et définissez-la à nouveau sur reprise si vous souhaitez des citations après un redémarrage.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

<!-- docs-validate: skip -->

```typescript
const session = await client.createSession({
    onPermissionRequest: approveAll,
    enableCitations: true,
});

const resumed = await client.resumeSession(session.sessionId, {
    onPermissionRequest: approveAll,
    enableCitations: true,
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: skip -->

```python
session = await client.create_session(
    on_permission_request=PermissionHandler.approve_all,
    enable_citations=True,
)

resumed = await client.resume_session(
    session.session_id,
    on_permission_request=PermissionHandler.approve_all,
    enable_citations=True,
)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
session, err := client.CreateSession(ctx, &copilot.SessionConfig{
    OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
    EnableCitations:     copilot.Bool(true),
})

resumed, err := client.ResumeSession(ctx, session.SessionID, &copilot.ResumeSessionConfig{
    OnPermissionRequest: copilot.PermissionHandler.ApproveAll,
    EnableCitations:     copilot.Bool(true),
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

<!-- docs-validate: skip -->

```csharp
var session = await client.CreateSessionAsync(new SessionConfig
{
    OnPermissionRequest = PermissionHandler.ApproveAll,
    EnableCitations = true,
});

var resumed = await client.ResumeSessionAsync(session.SessionId, new ResumeSessionConfig
{
    OnPermissionRequest = PermissionHandler.ApproveAll,
    EnableCitations = true,
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
CopilotSession session = client
        .createSession(new SessionConfig()
                .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
                .setEnableCitations(true))
        .get();

CopilotSession resumed = client
        .resumeSession(session.getSessionId(), new ResumeSessionConfig()
                .setOnPermissionRequest(PermissionHandler.APPROVE_ALL)
                .setEnableCitations(true))
        .get();
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

<!-- docs-validate: skip -->

```rust
let session = client
    .create_session(
        SessionConfig::new()
            .approve_all_permissions()
            .with_enable_citations(true),
    )
    .await?;

let resumed = client
    .resume_session(
        ResumeSessionConfig::new(session.id().clone())
            .approve_all_permissions()
            .with_enable_citations(true),
    )
    .await?;
```

</div>

</div>

## Lire des citations à partir de messages d’assistant

Les citations arrivent lors de l’événement final `assistant.message`, et non lors des événements `assistant.message_delta`. Attendez le message final avant de restituer les marqueurs sources.

<div class="ghd-codetabs">
<div class="ghd-codetab" data-lang="typescript" data-label="TypeScript"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">TypeScript</div>

<!-- docs-validate: skip -->

```typescript
session.on((event) => {
    if (event.type !== "assistant.message" || !event.data.citations) {
        return;
    }

    const { sources, spans } = event.data.citations;
    const sourceById = new Map(sources.map((source) => [source.id, source]));

    for (const span of spans) {
        const quoted = event.data.content.slice(span.startIndex, span.endIndex);
        for (const reference of span.references) {
            const source = sourceById.get(reference.sourceId);
            const label = source?.title ?? source?.url ?? source?.path ?? source?.id;
            console.log(`"${quoted}" — ${label}`);
        }
    }
});
```

</div>

<div class="ghd-codetab" data-lang="python" data-label="Python"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Python</div>

<!-- docs-validate: skip -->

```python
from copilot.session_events import SessionEventType

def utf16_slice(text: str, start: int, end: int) -> str:
    """Slice by UTF-16 code units, which is how span offsets are measured."""
    units = text.encode("utf-16-le")
    return units[start * 2 : end * 2].decode("utf-16-le")

def handle(event):
    if event.type != SessionEventType.ASSISTANT_MESSAGE or not event.data.citations:
        return

    sources = {source.id: source for source in event.data.citations.sources}

    for span in event.data.citations.spans:
        quoted = utf16_slice(event.data.content, span.start_index, span.end_index)
        for reference in span.references:
            source = sources[reference.source_id]
            label = source.title or source.url or source.path or source.id
            print(f'"{quoted}" — {label}')

session.on(handle)
```

</div>

<div class="ghd-codetab" data-lang="go" data-label="Go"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Go</div>

<!-- docs-validate: skip -->

```golang
// import "unicode/utf16"

session.On(func(event copilot.SessionEvent) {
    d, ok := event.Data.(*copilot.AssistantMessageData)
    if !ok || d.Citations == nil {
        return
    }

    sources := map[string]copilot.CitationSource{}
    for _, source := range d.Citations.Sources {
        sources[source.ID] = source
    }

    // Span offsets are UTF-16 code units, so index the UTF-16 view of the content.
    units := utf16.Encode([]rune(d.Content))

    for _, span := range d.Citations.Spans {
        quoted := string(utf16.Decode(units[span.StartIndex:span.EndIndex]))
        for _, reference := range span.References {
            source := sources[reference.SourceID]
            label := source.ID
            switch {
            case source.Title != nil:
                label = *source.Title
            case source.URL != nil:
                label = *source.URL
            case source.Path != nil:
                label = *source.Path
            }
            fmt.Printf("%q — %s\n", quoted, label)
        }
    }
})
```

</div>

<div class="ghd-codetab" data-lang="dotnet" data-label=".NET"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">.NET</div>

<!-- docs-validate: skip -->

```csharp
session.On<SessionEvent>(evt =>
{
    if (evt is not AssistantMessageEvent message || message.Data.Citations is null)
    {
        return;
    }

    var sources = message.Data.Citations.Sources.ToDictionary(source => source.Id);

    foreach (var span in message.Data.Citations.Spans)
    {
        var quoted = message.Data.Content[(int)span.StartIndex..(int)span.EndIndex];
        foreach (var reference in span.References)
        {
            var source = sources[reference.SourceId];
            var label = source.Title ?? source.Url ?? source.Path ?? source.Id;
            Console.WriteLine($"\"{quoted}\" — {label}");
        }
    }
});
```

</div>

<div class="ghd-codetab" data-lang="java" data-label="Java"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Java</div>

<!-- docs-validate: skip -->

```java
session.on(AssistantMessageEvent.class, event -> {
    Citations citations = event.getData().citations();
    if (citations == null) {
        return;
    }

    Map<String, CitationSource> sources = citations.sources().stream()
            .collect(Collectors.toMap(CitationSource::id, source -> source));

    for (CitationSpan span : citations.spans()) {
        String quoted = event.getData().content()
                .substring(span.startIndex().intValue(), span.endIndex().intValue());
        for (CitationReference reference : span.references()) {
            CitationSource source = sources.get(reference.sourceId());
            String label = source.title() != null ? source.title()
                    : source.url() != null ? source.url()
                    : source.path() != null ? source.path()
                    : source.id();
            System.out.printf("\"%s\" — %s%n", quoted, label);
        }
    }
});
```

</div>

<div class="ghd-codetab" data-lang="rust" data-label="Rust"><div class="ghd-codetab-fallback-label" role="heading" aria-level="3">Rust</div>

<!-- docs-validate: skip -->

```rust
use github_copilot_sdk::session_events::AssistantMessageData;
use std::collections::HashMap;

let mut events = session.subscribe();

while let Ok(event) = events.recv().await {
    if event.event_type != "assistant.message" {
        continue;
    }

    let Some(data) = event.typed_data::<AssistantMessageData>() else {
        continue;
    };
    let Some(citations) = data.citations.as_ref() else {
        continue;
    };

    let sources: HashMap<&str, _> = citations
        .sources
        .iter()
        .map(|source| (source.id.as_str(), source))
        .collect();

    // Span offsets are UTF-16 code units, so index the UTF-16 view of the content.
    let units: Vec<u16> = data.content.encode_utf16().collect();

    for span in &citations.spans {
        let quoted = String::from_utf16_lossy(
            &units[span.start_index as usize..span.end_index as usize],
        );
        for reference in &span.references {
            let Some(source) = sources.get(reference.source_id.as_str()) else {
                continue;
            };
            let label = source
                .title
                .as_deref()
                .or(source.url.as_deref())
                .or(source.path.as_deref())
                .unwrap_or(source.id.as_str());
            println!("\"{quoted}\" — {label}");
        }
    }
}
```

</div>

</div>

## Informations de référence sur la charge utile de citation

L’objet `citations` sépare les sources dédupliquées des étendues qui les référencent. Par conséquent, une source citée cinq fois apparaît une fois dans `sources`.

| Type                | Champ               | Description                                                                                                               |
| ------------------- | ------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `Citations`         | `sources`           | Ensemble dédupliqué des sources référencées dans les segments de citation                                                 |
| `Citations`         | `spans`             | Segments de texte généré annotés avec leurs sources justificatives                                                        |
| `CitationSource`    | `id`                | Identificateur stable et délimité par tour référencé par `CitationReference.sourceId`                                     |
| `CitationSource`    | `provider`          | Système qui a produit la citation : `anthropic`, `openai`ou `client`                                                      |
| `CitationSource`    | `title?`            | Titre lisible par l’homme de la source                                                                                    |
| `CitationSource`    | `url?`              | URL de la source, lorsqu’il s’agit d’une ressource web                                                                    |
| `CitationSource`    | `path?`             | Chemin d’accès du fichier par rapport au répertoire racine de l’espace de travail de l’agent, si la source est un fichier |
| `CitationSpan`      | `startIndex`        | Décalage de début dans le contenu final du message (unités de code UTF-16, à base de zéro, inclusif)                      |
| `CitationSpan`      | `endIndex`          | Décalage de fin dans le contenu final du message (unités de code UTF-16, de base zéro, exclusives)                        |
| `CitationSpan`      | `references`        | Sources qui prennent en charge cette étendue                                                                              |
| `CitationReference` | `sourceId`          | Identificateur de `CitationSource` vers lequel pointe cette référence                                                     |
| `CitationReference` | `citedText?`        | Texte exact de la source qui prend en charge l’étendue, lorsque le modèle le fournit                                      |
| `CitationReference` | `location?`         | Emplacement dans le texte source qui justifie le segment                                                                  |
| `CitationReference` | `providerMetadata?` | Données de corrélation natives du fournisseur, transmises de manière opaque                                               |

> \[!TIP]
> Les décalages d’étendue sont mesurés en unités de code UTF-16 par rapport à la chaîne finale `content` . TypeScript, Java et chaînes .NET sont déjà UTF-16. Vous pouvez donc les découper directement. Les chaînes Python sont indexées selon les points de code Unicode, et les chaînes Go et Rust sont encodées en UTF-8 ; convertissez donc le contenu en unités de code UTF-16 avant de les découper, comme le montrent les exemples ci-dessus.

### Emplacements de citation

`CitationReference.location` est une union discriminée indexée par `type` :

| Type d’emplacement       | Fields                                               | Utilisation |
| ------------------------ | ---------------------------------------------------- | ----------- |
| `char`                   |                                                      |             |
| `startIndex`, `endIndex` | Plage de caractères dans le texte source             |             |
| `page`                   |                                                      |             |
| `startPage`, `endPage`   | Plage de pages dans un document paginé               |             |
| `block`                  |                                                      |             |
| `startBlock`, `endBlock` | Plage de blocs de contenu dans un document structuré |             |

## Fournir des sources citables

Les citations ont besoin d’un matériau source que le modèle peut attribuer. Il existe deux façons de le fournir.

### Joindre des documents à un message

Lorsque des citations sont activées et que la session utilise un fournisseur de Anthropic, les pièces jointes de fichiers sont envoyées sous forme `document` de blocs avec des citations activées, afin que le modèle puisse citer des passages à partir d’eux.

<!-- docs-validate: skip -->

```typescript
await session.sendAndWait({
    prompt: "Summarize the attached PDF and cite the passages you used.",
    attachments: [
        {
            type: "blob",
            data: pdfBase64,
            displayName: "quarterly-report.pdf",
            mimeType: "application/pdf",
        },
    ],
});
```

Consultez [Entrée d’image](/fr/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/image-input) pour l’API des pièces jointes ainsi que les formats de pièces jointes `file` et `blob`.

### Retourner des sources citables à partir d’un outil

Les résultats de l’outil incluent un tableau expérimental `citableSources`. Chaque entrée fournit `content` que le modèle peut citer, ainsi qu’un `id` et, éventuellement, `title`, `url` et `path`. Ces sources sont conservées avec le résultat de l’outil, de sorte qu’elles restent disponibles après la reprise de la session, et les citations générées à partir de celles-ci sont étiquetées avec le fournisseur `client`.

## Limitations

* Les citations sont expérimentales dans chaque Kit de développement logiciel (SDK) et ne sont pas couvertes par des garanties de compatibilité.
* La couverture dépend du fournisseur de modèles. Une session configurée pour un fournisseur sans prise en charge des citations n’émet aucun payload `citations`.
* Les citations ne sont présentes que dans le dernier événement `assistant.message`, de sorte que les clients en streaming ne peuvent pas les afficher en cours de réponse.
* Les citations de code public et de duplication IP ne font pas partie de cette surface.

## Lectures complémentaires

* [Événements de session de streaming](/fr/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/streaming-events) : s’abonner aux événements de session et aux types d’événements étroits
* [Entrée d’image](/fr/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/image-input) : attacher des fichiers et des objets blob en mémoire à un message
* [Reprise de session et persistance](/fr/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/session-persistence) : reprendre les sessions et réappliquer des options de session
* [Compatibilité du Kit de développement logiciel (SDK) et de l’interface](/fr/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/troubleshooting/compatibility) : Matrice de fonctionnalités du KIT DE développement logiciel (SDK) et de l’interface CLI