# 引用

引用は、アシスタントの応答内の該当箇所を、それを裏付けるソースにリンクします。 セッションを作成または再開するときにenableCitationsを有効にしてから、assistant.message イベントのcitations ペイロードを読み取り、脚注、ソース リスト、またはインライン リンクをレンダリングします。

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

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

> \[!WARNING]
> 引用文献は試験的です。 オプション名、イベント ペイロード、プロバイダー カバレッジは、将来のリリースで変更される可能性があります。

## 引用文献のしくみ

引用は、SDK ではなくモデル プロバイダーによって生成されます。 フローには、次の 3 つの部分があります。

1. アプリケーションは、ドキュメントの添付ファイルやソース コンテンツを含むツールの結果など、引用可能な資料を提供します。
2. ランタイムは、`enableCitations` がオンのとき、そのマテリアルをワイヤ上で引用可能としてマークします。 Anthropicモデルの場合、添付ファイルは引用文献が有効になっている`document`ブロックとして送信されます。
3. モデルは引用メタデータを返し、ランタイムは最終的な`assistant.message` イベントでプロバイダーに依存しない`citations` オブジェクトに正規化します。

プロバイダーのサポートは制限されています。 各ソースレコードの `provider` フィールドには、引用の出典元が記録されます:

| プロバイダーの値    | 意味                                |
| ----------- | --------------------------------- |
| `anthropic` | Anthropic (クロード) モデル応答によって生成された引用 |
| `openai`    | OpenAI モデル応答によって生成された引用           |
| `client`    | ツール出力からランタイムによって合成された引用           |

> \[!NOTE]
> `enableCitations`を有効にしても、応答に引用文献が含まれるとは限りません。 モデルは、応答が引用可能なソース マテリアルに接地されている場合にのみ、それらを出力します。 `citations` フィールドは常に省略可能として扱います。

## セッションで引用を有効にする

セッション作成のオプションを設定し、再起動後に引用を行う場合は、再開時にもう一度設定します。

<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>

## アシスタント メッセージから引用文献を読む

引用文献は、`assistant.message_delta`イベントではなく、最終的な`assistant.message`イベントに到着します。 ソース マーカーをレンダリングする前に、最後のメッセージを待ちます。

<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>

## 引用ペイロードリファレンス

`citations` オブジェクトは重複除去されたソースを参照するスパンから分離するため、5 回引用されたソースが`sources`に 1 回表示されます。

| タイプ                                                  | フィールド               | Description                                        |
| ---------------------------------------------------- | ------------------- | -------------------------------------------------- |
| `Citations`                                          | `sources`           | 引用スパンで参照される、重複が除去されたソースのセット                        |
| `Citations`                                          | `spans`             | 根拠ソースで注釈された生成テキストの範囲                               |
| `CitationSource`                                     | `id`                |                                                    |
| `CitationReference.sourceId` によって参照される安定したターンスコープ識別子 |                     |                                                    |
| `CitationSource`                                     | `provider`          | 引用文献を作成したシステム: `anthropic`、 `openai`、または `client`  |
| `CitationSource`                                     | `title?`            | ソースの人間が判読できるタイトル                                   |
| `CitationSource`                                     | `url?`              | ソースの URL (Web リソースの場合)                             |
| `CitationSource`                                     | `path?`             | ソースがファイルの場合、エージェント ワークスペース のルートを基準としたファイル パス       |
| `CitationSpan`                                       | `startIndex`        | 最終メッセージ コンテンツ内の開始オフセット (UTF-16 コード単位、ゼロベース、含む)     |
| `CitationSpan`                                       | `endIndex`          | 最終的なメッセージ コンテンツの終了オフセット (UTF-16 コード単位、0 から始まる、排他的) |
| `CitationSpan`                                       | `references`        | このスパンをサポートするソース                                    |
| `CitationReference`                                  | `sourceId`          | この参照が指す `CitationSource` の識別子                      |
| `CitationReference`                                  | `citedText?`        | スパンをサポートするソースからの正確なテキスト (モデルが提供する場合)               |
| `CitationReference`                                  | `location?`         | スパンをサポートするソース内の場所                                  |
| `CitationReference`                                  | `providerMetadata?` | プロバイダーネイティブの関連付けデータ(不透明に渡される)                      |

> \[!TIP]
> スパン オフセットは、最終的な `content` 文字列に対して UTF-16 コード単位で測定されます。 TypeScript、Java、および.NET文字列は既に UTF-16 であるため、直接スライスできます。 Python文字列は Unicode コード ポイントによってインデックスが作成され、Go 文字列と Rust 文字列は UTF-8 であるため、上記の例のように、スライスする前にコンテンツを UTF-16 コード 単位に変換します。

### 引用場所

`CitationReference.location` は、 `type`でキー指定された判別共用体です。

| 場所のタイプ                  | フィールド                   | 使用 |
| ----------------------- | ----------------------- | -- |
| `char`                  |                         |    |
| `startIndex`、`endIndex` | ソース テキスト内の文字範囲          |    |
| `page`                  |                         |    |
| `startPage`、`endPage`   | ページ分割されたドキュメント内のページ範囲   |    |
| `block`                 |                         |    |
| `startBlock`、`endBlock` | 構造化ドキュメント内のコンテンツ ブロック範囲 |    |

## 引用可能なソースを提供する

引用文献には、モデルが属性付けできるソース マテリアルが必要です。 これを提供するには、2 つの方法があります。

### メッセージにドキュメントを添付する

引用が有効になっていて、セッションでAnthropicプロバイダーが使用されている場合、添付ファイルは引用がオンになっている`document` ブロックとして送信されるため、モデルはそれらの一節を引用できます。

<!-- 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",
        },
    ],
});
```

`file` では、attachment API と `blob`および[](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/image-input) attachment shapes について説明しています。

### ツールから引用可能なソースを返す

ツールの結果には、実験的な `citableSources` 配列が含まれます。 各エントリは、モデルが引用できる `content` と、 `id` とオプションの `title`、 `url`、および `path`を提供します。 これらのソースはツールの結果と共に保持されるため、セッションの再開後も存続し、そこから構築された引用文献には `client` プロバイダーでタグ付けされます。

## Limitations

* 引用文献はすべての SDK で試験的であり、互換性の保証の対象ではありません。
* カバレッジはモデル プロバイダーによって異なります。 引用サポートなしでプロバイダー用に構成されたセッションは、 `citations` ペイロードを出力しません。
* 引用は最終的な `assistant.message` イベントにのみ存在するため、ストリーミング コンシューマーは中間応答をレンダリングできません。
* パブリックコードとIP重複に関する引用は、この領域の一部ではありません。

## 詳細については、次を参照してください。

* [ストリーミング セッション イベント](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/streaming-events): セッション イベントを購読し、イベントの種類を絞り込む
* [画像入力](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/image-input): ファイルとメモリ内 BLOB をメッセージにアタッチする
* [セッションの再開と永続化](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/features/session-persistence): セッションを再開し、セッション オプションを再適用する
* [SDK と CLI の互換性](/ja/enterprise-cloud@latest/copilot/how-tos/copilot-sdk/troubleshooting/compatibility): SDK と CLI の機能マトリックス