要約で長期メモリに移したメッセージをDBから物理削除していたため、
一度要約されると人間も内容を確認できなくなっていた。削除をやめ、
messages に archived_at(要約に取り込まれた時刻)と memory_id
(どの要約に取り込まれたか)を持たせる。
モデルからは従来どおり見えない:
- get_context_messages() がアーカイブ済みを除外する
- maybe_summarize() の閾値判定も現役メッセージだけを数える
(ここを除外し忘れると件数が減らず再要約が繰り返される)
- backfill_tags() もアーカイブ済みは対象外にする
人間からは確認できる:
- GET /chat/sessions/{id}/messages がアーカイブ済みも archived_at
付きで返す。export/import もアーカイブ状態を保持する
- チャット画面では半透明で表示し、最後のアーカイブ済みメッセージの
直後に「ここから先がモデルに渡る」区切り線を出す
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
230 lines
6.1 KiB
Markdown
230 lines
6.1 KiB
Markdown
# API リファレンス
|
||
|
||
ベースURL: `http://localhost:8000`
|
||
Swagger UI: `http://localhost:8000/docs`
|
||
|
||
---
|
||
|
||
## チャット
|
||
|
||
### POST /chat/stream
|
||
SSE でストリーミング応答を返す。
|
||
|
||
**リクエストボディ**
|
||
```json
|
||
{
|
||
"message": "こんにちは",
|
||
"session_id": "uuid(省略時は新規セッション作成)",
|
||
"model": "gpt-5.4(省略時は DEFAULT_MODEL)"
|
||
}
|
||
```
|
||
|
||
**SSE イベント**
|
||
| type | value | タイミング |
|
||
|---|---|---|
|
||
| `session_id` | セッション UUID | 新規セッション作成直後 |
|
||
| `chunk` | テキスト断片 | LLM トークン生成ごと |
|
||
| `notes_updated` | — | AI が共有ノートを書き換えた直後 |
|
||
| `done` | — | 正常完了 |
|
||
| `error` | エラーメッセージ | 例外発生時 |
|
||
|
||
---
|
||
|
||
### GET /chat/sessions
|
||
セッション一覧を `updated_at` 降順で返す。
|
||
|
||
**レスポンス**
|
||
```json
|
||
[
|
||
{
|
||
"id": "uuid",
|
||
"title": "セッションタイトル",
|
||
"model": "gpt-5.4",
|
||
"updated_at": "2026-06-01T12:00:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### GET /chat/sessions/{session_id}/messages
|
||
セッションのメッセージ一覧を `created_at` 昇順で返す。要約に取り込まれた(アーカイブ済みの)
|
||
メッセージも含めて返し、`archived_at` で区別する。アーカイブ済みのものは LLM に渡す
|
||
コンテキストには入らないが、履歴としては残っている。
|
||
|
||
**レスポンス**
|
||
```json
|
||
[
|
||
{ "id": 1, "role": "user", "content": "...", "created_at": "...", "archived_at": "2026-08-20T04:00:00+00:00", "tags": [] },
|
||
{ "id": 2, "role": "assistant", "content": "...", "created_at": "...", "archived_at": null, "tags": [] }
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### DELETE /chat/sessions/{session_id}
|
||
セッションと紐づくメッセージ・メモリをすべて削除。`204 No Content` を返す。
|
||
|
||
---
|
||
|
||
## メモリ
|
||
|
||
### GET /memory/{session_id}
|
||
セッションの長期メモリ(要約)一覧を `created_at` 昇順で返す。
|
||
|
||
**レスポンス**
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"session_id": "uuid",
|
||
"summary": "要約テキスト",
|
||
"created_at": "2026-06-01T12:00:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### DELETE /memory/{memory_id}
|
||
特定のメモリエントリを削除。`204 No Content` を返す。
|
||
|
||
---
|
||
|
||
## 共有ノート
|
||
|
||
ユーザーと AI が共同編集するノート。ページのタイトル一覧は毎回システムプロンプトに注入され、
|
||
本文は AI が `read_note` / `write_note` ツールで読み書きする。
|
||
`section` を設定すると、同じセクション名のページはタブバー上で常に連続してグループ表示される。
|
||
|
||
### GET /api/notes
|
||
全ページを `position` 昇順で返す。同じ `section` のページは常に連続する(隣接=同一グループとして扱われる)。
|
||
|
||
**レスポンス**
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"title": "買い物リスト",
|
||
"content": "- 牛乳
|
||
- 卵",
|
||
"position": 0,
|
||
"section": "生活",
|
||
"updated_at": "2026-08-19T12:00:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### POST /api/notes
|
||
ページを新規作成し、`201 Created` で作成したページを返す。
|
||
`section` を指定すると、作成直後にそのセクションの末尾へ配置される(他ページの `position` も再採番される)。
|
||
|
||
**リクエスト**
|
||
```json
|
||
{ "title": "新しいページ", "content": "", "section": null }
|
||
```
|
||
|
||
---
|
||
|
||
### PATCH /api/notes/{page_id}
|
||
ページのタイトル・本文・セクションを更新する。指定したフィールドだけが変更される。
|
||
タイトルを空文字にしようとした場合は `400`、ページが存在しない場合は `404` を返す。
|
||
|
||
`section` はリクエストボディに**キーとして含まれているかどうか**で判定する(`null` を明示的に送るとグループ解除)。
|
||
セクションを変更すると、そのページは新しいセクションの末尾(該当ページが無ければ末尾)へ移動し、
|
||
全ページの `position` が振り直される。
|
||
|
||
**リクエスト**
|
||
```json
|
||
{ "content": "更新後の本文", "section": "生活" }
|
||
```
|
||
|
||
---
|
||
|
||
### POST /api/notes/sections/rename
|
||
`old_name` セクションに属する全ページを `new_name` セクションへ一括で付け替える。
|
||
`new_name` を空文字/未指定にすると、そのセクションの全ページのグループを解除する。
|
||
ページの並び順(`position`)は変更しない。
|
||
|
||
**リクエスト**
|
||
```json
|
||
{ "old_name": "生活", "new_name": "生活雑貨" }
|
||
```
|
||
|
||
**レスポンス**
|
||
```json
|
||
{ "renamed": 2 }
|
||
```
|
||
|
||
---
|
||
|
||
### POST /api/notes/reorder
|
||
タブのドラッグ&ドロップによる並べ替えを反映する。`order` には**全ページID**をドラッグ後の
|
||
新しい順序で渡す(サーバー側では計算しない。フロントが `store.pages` から算出する)。
|
||
`page_id` のページには先に `section` を設定してから、`order` の順に `position` を振り直す。
|
||
別セクションのタブの前後にドロップした場合は、そのセクションへの移動も兼ねる。
|
||
|
||
`order` が現在の全ページIDの集合と一致しない場合は `400` を返す。
|
||
|
||
**リクエスト**
|
||
```json
|
||
{ "page_id": 3, "section": "生活", "order": [1, 3, 2, 4] }
|
||
```
|
||
|
||
**レスポンス**
|
||
```json
|
||
{ "reordered": 4 }
|
||
```
|
||
|
||
---
|
||
|
||
### DELETE /api/notes/{page_id}
|
||
ページを削除。`204 No Content` を返す。
|
||
|
||
---
|
||
|
||
## ログ
|
||
|
||
### GET /logs
|
||
LLM API 呼び出しログを `created_at` 降順で返す。
|
||
|
||
**クエリパラメーター**
|
||
| パラメーター | 型 | 説明 |
|
||
|---|---|---|
|
||
| `session_id` | string | セッションで絞り込み |
|
||
| `status` | `ok` / `error` | 成功・失敗で絞り込み |
|
||
| `limit` | int (≤500) | 最大件数(デフォルト 100) |
|
||
| `offset` | int | スキップ件数 |
|
||
|
||
**レスポンス**
|
||
```json
|
||
[
|
||
{
|
||
"id": 1,
|
||
"session_id": "uuid",
|
||
"model": "gpt-5.4",
|
||
"request_json": "[{\"role\":\"user\",\"content\":\"...\"}]",
|
||
"response_text": "...",
|
||
"error": null,
|
||
"latency_ms": 832.5,
|
||
"created_at": "2026-06-01T12:00:00"
|
||
}
|
||
]
|
||
```
|
||
|
||
---
|
||
|
||
### DELETE /logs/{log_id}
|
||
指定ログを削除。`204 No Content` を返す。
|
||
|
||
---
|
||
|
||
## ヘルスチェック
|
||
|
||
### GET /health
|
||
```json
|
||
{ "status": "ok" }
|
||
```
|