> ## Documentation Index
> Fetch the complete documentation index at: https://docs.gethaki.space/llms.txt
> Use this file to discover all available pages before exploring further.

# POST /v1/context · GET /v1/inspect

> Le ContextPacket et sa trace de décision complète

## Demander la mémoire

```http theme={null}
POST /v1/context
```

<ParamField body="project_id" type="string" required>1 à 128 caractères.</ParamField>
<ParamField body="subject_id" type="string" required>1 à 128 caractères.</ParamField>
<ParamField body="query" type="string" required>Non vide.</ParamField>

<ParamField body="purpose" type="string">
  Max 128 caractères. **Recommandé, pas obligatoire** en V1 : son absence
  ajoute un `warning` `missing_purpose` au packet (Policy Engine règle 3),
  jamais une erreur.
</ParamField>

<ParamField body="budget_tokens" type="integer" default="900">
  Doit être un entier positif — sinon `budget_exceeded` (422).
</ParamField>

### Réponse — `200 OK`

<ResponseField name="packet" type="ContextPacket" required>
  <Expandable title="ContextPacket">
    <ResponseField name="facts" type="PacketFact[]" required>
      <Expandable title="PacketFact">
        <ResponseField name="id" type="string" required />

        <ResponseField name="predicate" type="string" required />

        <ResponseField name="value" type="object" required />

        <ResponseField name="confidence" type="number | null" />

        <ResponseField name="valid_from" type="string | null" />

        <ResponseField name="source_event_ids" type="string[]" required />
      </Expandable>
    </ResponseField>

    <ResponseField name="episodes" type="PacketEpisode[]" default="[]">
      Mémoire épisodique (sprint 10) : événements sources les plus
      proches, sous le même budget.

      <Expandable title="PacketEpisode">
        <ResponseField name="event_id" type="string" required />

        <ResponseField name="kind" type="string" required />

        <ResponseField name="occurred_at" type="string | null" />

        <ResponseField name="excerpt" type="string" required>Tronqué à 300 caractères.</ResponseField>
      </Expandable>
    </ResponseField>

    <ResponseField name="warnings" type="string[]" required>
      Ex. `missing_purpose: ...`, `open_conflict: N fact(s) hidden pending conflict resolution`, `volatility_expired: N fact(s)...`.
    </ResponseField>

    <ResponseField name="status" type="&#x22;ok&#x22; | &#x22;degraded&#x22; | &#x22;failed&#x22;" default="ok" />

    <ResponseField name="empty_reason" type="&#x22;no_relevant_memory&#x22; | null" default="null">
      Posé par la porte de rappel (M3, désactivée par défaut — voir
      [Context Assembler](/fr/concepts/context-assembler#porte-de-rappel-m3-le-budget-est-un-plafond-pas-une-cible))
      quand des candidats existaient mais qu'aucun n'a franchi le
      plancher de pertinence. Délibérément **pas** un warning : `status`
      reste `"ok"`.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="token_count" type="integer" required>
  Total réel du packet (facts + episodes), estimé par `max(1, len(texte) // 4)`.
</ResponseField>

<ResponseField name="trace_id" type="uuid" required>
  Inspectable via `GET /v1/inspect/{trace_id}`.
</ResponseField>

<RequestExample>
  ```bash curl theme={null}
  curl -X POST http://localhost:8100/v1/context \
    -H "Content-Type: application/json" \
    -H "Authorization: Bearer hk_..." \
    -d '{
      "project_id": "prj_support", "subject_id": "usr_42",
      "query": "dans quelle langue envoyer la facture ?",
      "budget_tokens": 900
    }'
  ```

  ```python Python (SDK) theme={null}
  response = client.context(
      subject_id="usr_42",
      query="dans quelle langue envoyer la facture ?",
      project_id="prj_support",
      budget_tokens=900,
  )
  ```

  ```typescript TypeScript (SDK) theme={null}
  const { packet, trace_id } = await client.context({
    subjectId: "usr_42",
    query: "dans quelle langue envoyer la facture ?",
    projectId: "prj_support",
  });
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "packet": {
      "facts": [{
        "id": "f8a1c9de-...",
        "predicate": "invoice_language",
        "value": {"language": "fr"},
        "confidence": 0.9,
        "valid_from": "2026-08-01T10:00:00+00:00",
        "source_event_ids": ["7c21e4c2-..."]
      }],
      "episodes": [],
      "warnings": [],
      "status": "ok",
      "empty_reason": null
    },
    "token_count": 18,
    "trace_id": "0587fc4f-74a1-46af-a592-5789d1269072"
  }
  ```
</ResponseExample>

## Inspecter une trace

```http theme={null}
GET /v1/inspect/{trace_id}
```

Le scope est **obligatoire** en query et vérifié contre la trace : elle
ne fuit jamais hors de `(project_id, subject_id)`.

<ParamField path="trace_id" type="uuid" required />

<ParamField query="project_id" type="string" required />

<ParamField query="subject_id" type="string" required />

### Réponse — `200 OK`

<ResponseField name="decisions" type="TraceDecision[]" required>
  Une entrée **par fait ou épisode considéré**, y compris ceux jamais
  renvoyés dans le packet.

  <Expandable title="TraceDecision">
    <ResponseField name="fact_id" type="string | null" />

    <ResponseField name="episode_id" type="string | null" />

    <ResponseField name="action" type="string" required>
      `included` · `excluded` · `blocked`
    </ResponseField>

    <ResponseField name="reason_code" type="string" required>
      `top_score` · `over_budget` · `conflict_open` · `multi_hop_expansion` · `volatility_expired` · `below_relevance_floor`
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="packet" type="ContextPacket" required>Le packet exact qui a été servi.</ResponseField>

<ResponseField name="query" type="string" required />

<ResponseField name="purpose" type="string | null" />

<ResponseField name="token_count" type="integer" required />

<RequestExample>
  ```bash curl theme={null}
  curl "http://localhost:8100/v1/inspect/0587fc4f-74a1-46af-a592-5789d1269072?project_id=prj_support&subject_id=usr_42" \
    -H "Authorization: Bearer hk_..."
  ```
</RequestExample>

<ResponseExample>
  ```json 200 theme={null}
  {
    "trace_id": "0587fc4f-74a1-46af-a592-5789d1269072",
    "project_id": "prj_support",
    "subject_id": "usr_42",
    "query": "dans quelle langue envoyer la facture ?",
    "purpose": null,
    "packet": { "facts": [ /* ... */ ], "episodes": [], "warnings": [] },
    "decisions": [
      {"fact_id": "f8a1c9de-...", "episode_id": null, "action": "included", "reason_code": "top_score"}
    ],
    "token_count": 18
  }
  ```
</ResponseExample>

## Erreurs possibles

`missing_scope` (422 — `project_id`/`subject_id` absent sur `/v1/inspect`),
`budget_exceeded` (422 — `budget_tokens ≤ 0`), `trace_not_found` (404 —
trace inconnue ou hors scope), `forbidden_scope` (403).
