docs(api): use /api/v2 in docs and examples, demote v1 to legacy (#370)
1.2.0 introduced /api/v2 as the canonical, cloud-aligned prefix and mounted every business router twice, but the user-facing entry points (README, README.zh-CN, QUICKSTART, the docs/ set, the Langfuse example) still taught /api/v1 — so new users were pointed at the compatibility alias while docs/api.md already declared v2 canonical. - Switch every EverOS endpoint reference in docs, examples, and `everos demo --live` to /api/v2, plus the matching CLI test expectations. - Describe /api/v1 as a legacy compatibility alias that may be removed in a future major release, rather than a permanent one. Nothing changes at runtime: both prefixes still resolve to the same handlers and the v1/v2 parity test is untouched. - Add a short note in README / README.zh-CN / QUICKSTART so existing v1 integrations know they keep working. - Fix the five dead endpoint anchors in the docs/api.md table of contents, which still pointed at the pre-1.2.0 #post-apiv1... slugs. Left on v1 deliberately: docs/migration-to-1.0.0.md (historical record), CHANGELOG history, tests/** (v1 must stay covered), and the use-cases/claude-code-plugin + openher READMEs, which document a different cloud API. Co-authored-by: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
6c9792ed11
commit
649046b0df
|
|
@ -22,7 +22,7 @@ A good module docstring states:
|
||||||
Example (abbreviated, from `memory/search/manager.py`):
|
Example (abbreviated, from `memory/search/manager.py`):
|
||||||
|
|
||||||
```python
|
```python
|
||||||
"""SearchManager — top-level orchestrator for POST /api/v1/memory/search.
|
"""SearchManager — top-level orchestrator for POST /api/v2/memory/search.
|
||||||
|
|
||||||
Hard partition by owner_type: user → episodes (+ profiles), agent →
|
Hard partition by owner_type: user → episodes (+ profiles), agent →
|
||||||
agent_cases + agent_skills. The manager never writes to storage; it only
|
agent_cases + agent_skills. The manager never writes to storage; it only
|
||||||
|
|
|
||||||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -19,6 +19,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
`metadata = {"method": ..., "calibrated": ...}` now, a structured field that
|
`metadata = {"method": ..., "calibrated": ...}` now, a structured field that
|
||||||
can be split on, alongside the existing human-readable comment. Dashboards
|
can be split on, alongside the existing human-readable comment. Dashboards
|
||||||
built on `recall_top_score` for keyword search need to switch to the new name.
|
built on `recall_top_score` for keyword search need to switch to the new name.
|
||||||
|
- **Docs and examples now use `/api/v2`** — README, QUICKSTART, the `docs/`
|
||||||
|
reference set, the Langfuse example, and `everos demo --live` all call the
|
||||||
|
canonical `/api/v2` prefix instead of `/api/v1`. `/api/v1` keeps resolving
|
||||||
|
to the same handlers, so nothing breaks; it is now described as a **legacy
|
||||||
|
compatibility alias that may be removed in a future major release** rather
|
||||||
|
than a permanent one. New integrations should target `/api/v2`.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- **Broken table-of-contents links in `docs/api.md`** — the endpoint anchors
|
||||||
|
still pointed at the pre-1.2.0 `#post-apiv1…` slugs after the headings moved
|
||||||
|
to `/api/v2`, so all five endpoint links in the TOC were dead.
|
||||||
|
|
||||||
## [1.2.0] - 2026-07-24
|
## [1.2.0] - 2026-07-24
|
||||||
|
|
||||||
|
|
@ -26,8 +38,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||||
|
|
||||||
- **`/api/v2` API prefix** — every business endpoint (`memory/*`, `ome/*`,
|
- **`/api/v2` API prefix** — every business endpoint (`memory/*`, `ome/*`,
|
||||||
`knowledge/*`) is now served under `/api/v2`, aligning the open-source API
|
`knowledge/*`) is now served under `/api/v2`, aligning the open-source API
|
||||||
with the EverOS Cloud contract. `/api/v1` is retained as a permanent,
|
with the EverOS Cloud contract. `/api/v1` is retained as a legacy
|
||||||
backward-compatible alias: both prefixes resolve to the same handlers with
|
compatibility alias: both prefixes resolve to the same handlers with
|
||||||
identical request/response contracts, so existing integrations keep working
|
identical request/response contracts, so existing integrations keep working
|
||||||
unchanged. Infrastructure endpoints (`/health`, `/metrics`) stay unversioned.
|
unchanged. Infrastructure endpoints (`/health`, `/metrics`) stay unversioned.
|
||||||
- **Native OpenTelemetry tracing** — memory operations (add / flush, memcell
|
- **Native OpenTelemetry tracing** — memory operations (add / flush, memcell
|
||||||
|
|
|
||||||
|
|
@ -123,11 +123,17 @@ Send messages to the server — one at a time or in batches. Each batch
|
||||||
belongs to a `session_id`, which represents one conversation thread.
|
belongs to a `session_id`, which represents one conversation thread.
|
||||||
Timestamps are Unix epoch in **milliseconds** (UTC).
|
Timestamps are Unix epoch in **milliseconds** (UTC).
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Business endpoints live under `/api/v2`. The older `/api/v1` prefix still
|
||||||
|
> resolves to the same handlers so existing integrations keep working, but it
|
||||||
|
> is a legacy alias that may be removed in a future major release — write new
|
||||||
|
> code against `/api/v2`.
|
||||||
|
|
||||||
First, a chat about climbing:
|
First, a chat about climbing:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
TS=$(($(date +%s)*1000))
|
TS=$(($(date +%s)*1000))
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/add \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{
|
-d "{
|
||||||
\"session_id\": \"demo-001\",
|
\"session_id\": \"demo-001\",
|
||||||
|
|
@ -143,7 +149,7 @@ curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
||||||
Now the topic shifts to work:
|
Now the topic shifts to work:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/add \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{
|
-d "{
|
||||||
\"session_id\": \"demo-001\",
|
\"session_id\": \"demo-001\",
|
||||||
|
|
@ -184,7 +190,7 @@ If you want to extract memory without waiting for a topic shift — for
|
||||||
example at the end of a session — call `/flush`:
|
example at the end of a session — call `/flush`:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/flush \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{"session_id":"demo-001"}'
|
-d '{"session_id":"demo-001"}'
|
||||||
```
|
```
|
||||||
|
|
@ -202,7 +208,7 @@ This forces extraction of whatever is still in the buffer.
|
||||||
## 6. Search
|
## 6. Search
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/search \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/search \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{
|
-d '{
|
||||||
"user_id": "alice",
|
"user_id": "alice",
|
||||||
|
|
@ -277,7 +283,7 @@ edit — no database driver needed.
|
||||||
requests to partition memory spaces inside one server (defaults to
|
requests to partition memory spaces inside one server (defaults to
|
||||||
`"default"` when omitted).
|
`"default"` when omitted).
|
||||||
- **Knowledge base** — upload documents via
|
- **Knowledge base** — upload documents via
|
||||||
`/api/v1/knowledge/documents` and search with hybrid retrieval. See
|
`/api/v2/knowledge/documents` and search with hybrid retrieval. See
|
||||||
[docs/knowledge.md](docs/knowledge.md).
|
[docs/knowledge.md](docs/knowledge.md).
|
||||||
- **Reflection** — offline memory consolidation; enable in `ome.toml`.
|
- **Reflection** — offline memory consolidation; enable in `ome.toml`.
|
||||||
See [docs/reflection.md](docs/reflection.md).
|
See [docs/reflection.md](docs/reflection.md).
|
||||||
|
|
|
||||||
18
README.md
18
README.md
|
|
@ -195,18 +195,24 @@ everos demo --live
|
||||||
```
|
```
|
||||||
|
|
||||||
Live demo mode connects to the running server and performs the real
|
Live demo mode connects to the running server and performs the real
|
||||||
`/health` -> `/api/v1/memory/add` -> `/api/v1/memory/flush` ->
|
`/health` -> `/api/v2/memory/add` -> `/api/v2/memory/flush` ->
|
||||||
`/api/v1/memory/search` flow before opening the same memory sphere UI. Use
|
`/api/v2/memory/search` flow before opening the same memory sphere UI. Use
|
||||||
`--server-url <url>` if your server is not on `http://127.0.0.1:8000`.
|
`--server-url <url>` if your server is not on `http://127.0.0.1:8000`.
|
||||||
|
|
||||||
### 5. Try Your First Memory
|
### 5. Try Your First Memory
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> Business endpoints live under `/api/v2`. The older `/api/v1` prefix still
|
||||||
|
> resolves to the same handlers so existing integrations keep working, but it
|
||||||
|
> is a legacy alias that may be removed in a future major release — write new
|
||||||
|
> code against `/api/v2`.
|
||||||
|
|
||||||
Add a tiny conversation:
|
Add a tiny conversation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
TS=$(($(date +%s)*1000))
|
TS=$(($(date +%s)*1000))
|
||||||
|
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/add \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{
|
-d "{
|
||||||
\"session_id\": \"demo-001\",
|
\"session_id\": \"demo-001\",
|
||||||
|
|
@ -222,7 +228,7 @@ curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
||||||
Force extraction for the local demo:
|
Force extraction for the local demo:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/flush \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{"session_id":"demo-001","app_id":"default","project_id":"default"}'
|
-d '{"session_id":"demo-001","app_id":"default","project_id":"default"}'
|
||||||
```
|
```
|
||||||
|
|
@ -230,7 +236,7 @@ curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
|
||||||
Search it back:
|
Search it back:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/search \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/search \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{
|
-d '{
|
||||||
"user_id": "alice",
|
"user_id": "alice",
|
||||||
|
|
@ -258,7 +264,7 @@ For annotated responses and the Markdown files EverOS creates, see
|
||||||
### Optional: Ingest Multimodal Files
|
### Optional: Ingest Multimodal Files
|
||||||
|
|
||||||
To ingest non-text content (image / pdf / audio / office documents)
|
To ingest non-text content (image / pdf / audio / office documents)
|
||||||
through `/api/v1/memory/add` `content` items, install the optional
|
through `/api/v2/memory/add` `content` items, install the optional
|
||||||
extra:
|
extra:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
|
|
@ -212,18 +212,23 @@ everos demo --live
|
||||||
```
|
```
|
||||||
|
|
||||||
Live demo mode 会连接正在运行的 server,并在打开同一个 memory sphere UI
|
Live demo mode 会连接正在运行的 server,并在打开同一个 memory sphere UI
|
||||||
之前真实执行 `/health` -> `/api/v1/memory/add` -> `/api/v1/memory/flush` ->
|
之前真实执行 `/health` -> `/api/v2/memory/add` -> `/api/v2/memory/flush` ->
|
||||||
`/api/v1/memory/search`。如果 server 不在 `http://127.0.0.1:8000`,可以使用
|
`/api/v2/memory/search`。如果 server 不在 `http://127.0.0.1:8000`,可以使用
|
||||||
`--server-url <url>`。
|
`--server-url <url>`。
|
||||||
|
|
||||||
### 5. 试写第一条记忆
|
### 5. 试写第一条记忆
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> 业务接口位于 `/api/v2`。旧的 `/api/v1` 前缀仍然指向同一批 handler,已有集成
|
||||||
|
> 不会受影响;但它只是兼容用的 legacy alias,未来的大版本可能移除 —— 新代码请
|
||||||
|
> 直接使用 `/api/v2`。
|
||||||
|
|
||||||
添加一个很小的 conversation:
|
添加一个很小的 conversation:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
TS=$(($(date +%s)*1000))
|
TS=$(($(date +%s)*1000))
|
||||||
|
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/add \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{
|
-d "{
|
||||||
\"session_id\": \"demo-001\",
|
\"session_id\": \"demo-001\",
|
||||||
|
|
@ -239,7 +244,7 @@ curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
||||||
为了本地 demo,手动触发一次 extraction:
|
为了本地 demo,手动触发一次 extraction:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/flush \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{"session_id":"demo-001","app_id":"default","project_id":"default"}'
|
-d '{"session_id":"demo-001","app_id":"default","project_id":"default"}'
|
||||||
```
|
```
|
||||||
|
|
@ -247,7 +252,7 @@ curl -X POST http://127.0.0.1:8000/api/v1/memory/flush \
|
||||||
再把这条记忆搜索回来:
|
再把这条记忆搜索回来:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/search \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/search \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{
|
-d '{
|
||||||
"user_id": "alice",
|
"user_id": "alice",
|
||||||
|
|
@ -271,7 +276,7 @@ Markdown 会同步写入,本地索引会在后台追上。
|
||||||
|
|
||||||
### 可选:摄取多模态文件
|
### 可选:摄取多模态文件
|
||||||
|
|
||||||
如果要通过 `/api/v1/memory/add` 的 `content` items 摄取非文本内容
|
如果要通过 `/api/v2/memory/add` 的 `content` items 摄取非文本内容
|
||||||
(image / pdf / audio / office documents),安装可选 extra:
|
(image / pdf / audio / office documents),安装可选 extra:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
|
|
|
||||||
22
docs/api.md
22
docs/api.md
|
|
@ -26,11 +26,11 @@ business semantics the raw spec does not carry.
|
||||||
- [SearchMethod](#searchmethod)
|
- [SearchMethod](#searchmethod)
|
||||||
- [GetMemoryType](#getmemorytype)
|
- [GetMemoryType](#getmemorytype)
|
||||||
- [Endpoints](#endpoints)
|
- [Endpoints](#endpoints)
|
||||||
- [POST /api/v2/memory/add](#post-apiv1memoryadd)
|
- [POST /api/v2/memory/add](#post-apiv2memoryadd)
|
||||||
- [POST /api/v2/memory/flush](#post-apiv1memoryflush)
|
- [POST /api/v2/memory/flush](#post-apiv2memoryflush)
|
||||||
- [POST /api/v2/memory/search](#post-apiv1memorysearch)
|
- [POST /api/v2/memory/search](#post-apiv2memorysearch)
|
||||||
- [POST /api/v2/memory/get](#post-apiv1memoryget)
|
- [POST /api/v2/memory/get](#post-apiv2memoryget)
|
||||||
- [POST /api/v2/ome/trigger](#post-apiv1ometrigger)
|
- [POST /api/v2/ome/trigger](#post-apiv2ometrigger)
|
||||||
- [Knowledge endpoints](#knowledge-endpoints)
|
- [Knowledge endpoints](#knowledge-endpoints)
|
||||||
- [OpenAPI spec source](#openapi-spec-source)
|
- [OpenAPI spec source](#openapi-spec-source)
|
||||||
|
|
||||||
|
|
@ -52,11 +52,13 @@ but are intentionally outside this reference — they are runtime probes
|
||||||
for deployment, not part of the application contract.
|
for deployment, not part of the application contract.
|
||||||
|
|
||||||
`/api/v2` is the canonical prefix, aligned with the EverOS Cloud API. Every
|
`/api/v2` is the canonical prefix, aligned with the EverOS Cloud API. Every
|
||||||
business endpoint is **also** served under `/api/v1`, which is retained as a
|
business endpoint is **also** served under `/api/v1`, kept as a legacy
|
||||||
permanent, backward-compatible alias: the two prefixes resolve to the same
|
compatibility alias: the two prefixes resolve to the same handlers with
|
||||||
handlers with identical request/response contracts. Existing `/api/v1`
|
identical request/response contracts, so existing `/api/v1` integrations keep
|
||||||
integrations keep working unchanged; new integrations should use `/api/v2`.
|
working today. The alias carries no long-term guarantee — it may be removed in
|
||||||
Swap the prefix in any example below to reach the same endpoint under v1.
|
a future major release, and it will be announced in the changelog with a
|
||||||
|
deprecation window before that happens. Write new integrations against
|
||||||
|
`/api/v2`, and migrate existing ones when convenient.
|
||||||
|
|
||||||
### Content type
|
### Content type
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -38,9 +38,9 @@ Live mode keeps the same TUI, but the memory lifecycle is backed by real
|
||||||
server calls:
|
server calls:
|
||||||
|
|
||||||
1. `GET /health`
|
1. `GET /health`
|
||||||
2. `POST /api/v1/memory/add`
|
2. `POST /api/v2/memory/add`
|
||||||
3. `POST /api/v1/memory/flush`
|
3. `POST /api/v2/memory/flush`
|
||||||
4. `POST /api/v1/memory/search`
|
4. `POST /api/v2/memory/search`
|
||||||
|
|
||||||
If your server is not running on `http://127.0.0.1:8000`, pass
|
If your server is not running on `http://127.0.0.1:8000`, pass
|
||||||
`--server-url <url>`.
|
`--server-url <url>`.
|
||||||
|
|
|
||||||
|
|
@ -302,7 +302,7 @@ The CLI ([cli.md](cli.md)) is intentionally small:
|
||||||
`rm -rf <memory-root>/.index/lancedb`, restart — the cascade
|
`rm -rf <memory-root>/.index/lancedb`, restart — the cascade
|
||||||
rebuilds from markdown. For an incremental catch-up, use
|
rebuilds from markdown. For an incremental catch-up, use
|
||||||
`everos cascade sync`.
|
`everos cascade sync`.
|
||||||
- **Flush** is an HTTP endpoint (`POST /api/v1/memory/flush`), not a
|
- **Flush** is an HTTP endpoint (`POST /api/v2/memory/flush`), not a
|
||||||
CLI command — it forces *extraction* of the session buffer, which is
|
CLI command — it forces *extraction* of the session buffer, which is
|
||||||
a different thing from forcing *index sync* (`cascade sync`).
|
a different thing from forcing *index sync* (`cascade sync`).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,14 +13,14 @@ and keeps the original file for reference.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# Upload a document
|
# Upload a document
|
||||||
curl -s -X POST http://localhost:8000/api/v1/knowledge/documents \
|
curl -s -X POST http://localhost:8000/api/v2/knowledge/documents \
|
||||||
-F "file=@my-report.pdf" \
|
-F "file=@my-report.pdf" \
|
||||||
-F "title=Q1 Engineering Report" \
|
-F "title=Q1 Engineering Report" \
|
||||||
| jq .data
|
| jq .data
|
||||||
# → { "doc_id": "d_a1b2c3d4e5f6", "category_id": "Technology", "topic_count": 8, ... }
|
# → { "doc_id": "d_a1b2c3d4e5f6", "category_id": "Technology", "topic_count": 8, ... }
|
||||||
|
|
||||||
# Search
|
# Search
|
||||||
curl -s -X POST http://localhost:8000/api/v1/knowledge/search \
|
curl -s -X POST http://localhost:8000/api/v2/knowledge/search \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"query": "performance bottleneck", "method": "hybrid"}' \
|
-d '{"query": "performance bottleneck", "method": "hybrid"}' \
|
||||||
| jq '.data.hits[:3] | .[] | {topic_name, score}'
|
| jq '.data.hits[:3] | .[] | {topic_name, score}'
|
||||||
|
|
@ -206,7 +206,7 @@ request to bypass LLM classification.
|
||||||
|
|
||||||
## API reference
|
## API reference
|
||||||
|
|
||||||
All endpoints are under `/api/v1/knowledge`. Responses use the envelope
|
All endpoints are under `/api/v2/knowledge`. Responses use the envelope
|
||||||
format `{"request_id": "...", "data": {...}}`. The `request_id` field is
|
format `{"request_id": "...", "data": {...}}`. The `request_id` field is
|
||||||
omitted from examples below for brevity.
|
omitted from examples below for brevity.
|
||||||
|
|
||||||
|
|
@ -256,7 +256,7 @@ async def upload_document(file_path: str, title: str) -> dict:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
|
||||||
with open(file_path, "rb") as f:
|
with open(file_path, "rb") as f:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
"/api/v1/knowledge/documents",
|
"/api/v2/knowledge/documents",
|
||||||
files={"file": (Path(file_path).name, f)},
|
files={"file": (Path(file_path).name, f)},
|
||||||
data={"title": title},
|
data={"title": title},
|
||||||
)
|
)
|
||||||
|
|
@ -267,7 +267,7 @@ async def upload_document(file_path: str, title: str) -> dict:
|
||||||
**Example — curl**:
|
**Example — curl**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://localhost:8000/api/v1/knowledge/documents \
|
curl -X POST http://localhost:8000/api/v2/knowledge/documents \
|
||||||
-F "file=@report.pdf" \
|
-F "file=@report.pdf" \
|
||||||
-F "title=Quarterly Report" \
|
-F "title=Quarterly Report" \
|
||||||
-F "category_id=Finance"
|
-F "category_id=Finance"
|
||||||
|
|
@ -605,7 +605,7 @@ Storage paths, SQLite rows, and LanceDB indexes are all scoped by
|
||||||
A complete workflow from upload to search:
|
A complete workflow from upload to search:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:8000/api/v1/knowledge
|
BASE=http://localhost:8000/api/v2/knowledge
|
||||||
|
|
||||||
# 1. List available categories
|
# 1. List available categories
|
||||||
curl -s "$BASE/categories" | jq '[.data.categories[] | .category_id]'
|
curl -s "$BASE/categories" | jq '[.data.categories[] | .category_id]'
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ result is fully retrievable with the same `/search` stack.
|
||||||
## How it works
|
## How it works
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/v1/memory/add
|
POST /api/v2/memory/add
|
||||||
messages[].content = [ ContentItem, ContentItem, ... ]
|
messages[].content = [ ContentItem, ContentItem, ... ]
|
||||||
│
|
│
|
||||||
│ text items → used verbatim
|
│ text items → used verbatim
|
||||||
|
|
@ -157,7 +157,7 @@ way — only the parsed text is.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
TS=$(($(date +%s) * 1000)) # v1 contract: timestamp in ms
|
TS=$(($(date +%s) * 1000)) # v1 contract: timestamp in ms
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/add \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/add \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d "{
|
-d "{
|
||||||
\"session_id\": \"mm-001\",
|
\"session_id\": \"mm-001\",
|
||||||
|
|
@ -244,7 +244,7 @@ HTTP library:
|
||||||
import httpx
|
import httpx
|
||||||
|
|
||||||
httpx.post(
|
httpx.post(
|
||||||
"http://127.0.0.1:8000/api/v1/memory/add",
|
"http://127.0.0.1:8000/api/v2/memory/add",
|
||||||
json={
|
json={
|
||||||
"session_id": "mm-001",
|
"session_id": "mm-001",
|
||||||
"messages": [
|
"messages": [
|
||||||
|
|
@ -319,7 +319,7 @@ episodes and memory cells as text turns, every retrieval method works
|
||||||
across multimodal-derived memory unchanged:
|
across multimodal-derived memory unchanged:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://127.0.0.1:8000/api/v1/memory/search \
|
curl -X POST http://127.0.0.1:8000/api/v2/memory/search \
|
||||||
-H 'Content-Type: application/json' \
|
-H 'Content-Type: application/json' \
|
||||||
-d '{
|
-d '{
|
||||||
"user_id": "alice",
|
"user_id": "alice",
|
||||||
|
|
|
||||||
|
|
@ -221,7 +221,7 @@ dedicated CLI command).
|
||||||
### Triggering a run
|
### Triggering a run
|
||||||
|
|
||||||
```
|
```
|
||||||
POST /api/v1/ome/trigger
|
POST /api/v2/ome/trigger
|
||||||
Content-Type: application/json
|
Content-Type: application/json
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -249,7 +249,7 @@ import httpx
|
||||||
async def trigger_reflection() -> str:
|
async def trigger_reflection() -> str:
|
||||||
async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
|
async with httpx.AsyncClient(base_url="http://localhost:8000") as client:
|
||||||
resp = await client.post(
|
resp = await client.post(
|
||||||
"/api/v1/ome/trigger",
|
"/api/v2/ome/trigger",
|
||||||
json={"name": "reflect_episodes", "timeout": 120, "force": True},
|
json={"name": "reflect_episodes", "timeout": 120, "force": True},
|
||||||
)
|
)
|
||||||
resp.raise_for_status()
|
resp.raise_for_status()
|
||||||
|
|
@ -259,7 +259,7 @@ async def trigger_reflection() -> str:
|
||||||
**Example — curl**:
|
**Example — curl**:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
curl -X POST http://localhost:8000/api/v1/ome/trigger \
|
curl -X POST http://localhost:8000/api/v2/ome/trigger \
|
||||||
-H "Content-Type: application/json" \
|
-H "Content-Type: application/json" \
|
||||||
-d '{"name": "reflect_episodes", "timeout": 120, "force": true}'
|
-d '{"name": "reflect_episodes", "timeout": 120, "force": true}'
|
||||||
```
|
```
|
||||||
|
|
@ -327,7 +327,7 @@ real deployment, once enabled it runs automatically on schedule, so this step
|
||||||
isn't needed.
|
isn't needed.
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
BASE=http://localhost:8000/api/v1
|
BASE=http://localhost:8000/api/v2
|
||||||
|
|
||||||
# 1. With Reflection enabled (set enabled = true in <root>/ome.toml),
|
# 1. With Reflection enabled (set enabled = true in <root>/ome.toml),
|
||||||
# trigger a run by hand here (for the demo; in production it runs on schedule)
|
# trigger a run by hand here (for the demo; in production it runs on schedule)
|
||||||
|
|
|
||||||
|
|
@ -42,11 +42,11 @@ zero tracing overhead.
|
||||||
|
|
||||||
| EverOS operation | Langfuse observation |
|
| EverOS operation | Langfuse observation |
|
||||||
| --- | --- |
|
| --- | --- |
|
||||||
| `POST /api/v1/memory/add` · `flush` | span `everos.memory.add` / `everos.memory.flush` |
|
| `POST /api/v2/memory/add` · `flush` | span `everos.memory.add` / `everos.memory.flush` |
|
||||||
| memcell boundary detection (LLM) | generation `everos.memcell.boundary` (model + tokens) |
|
| memcell boundary detection (LLM) | generation `everos.memcell.boundary` (model + tokens) |
|
||||||
| episode extraction (LLM) | generation `everos.extract` |
|
| episode extraction (LLM) | generation `everos.extract` |
|
||||||
| markdown persistence | span `everos.persist.markdown` |
|
| markdown persistence | span `everos.persist.markdown` |
|
||||||
| `POST /api/v1/memory/search` | retriever `everos.memory.search` → `recall` / `rank` |
|
| `POST /api/v2/memory/search` | retriever `everos.memory.search` → `recall` / `rank` |
|
||||||
| query / recall embedding | embedding `everos.embedding` |
|
| query / recall embedding | embedding `everos.embedding` |
|
||||||
| OME reflection strategies | agent `everos.ome.<strategy>` (linked to the triggering request's trace) |
|
| OME reflection strategies | agent `everos.ome.<strategy>` (linked to the triggering request's trace) |
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ def main() -> None:
|
||||||
ts = int(time.time() * 1000)
|
ts = int(time.time() * 1000)
|
||||||
|
|
||||||
add = _post(
|
add = _post(
|
||||||
"/api/v1/memory/add",
|
"/api/v2/memory/add",
|
||||||
{
|
{
|
||||||
"session_id": SESSION,
|
"session_id": SESSION,
|
||||||
"messages": [
|
"messages": [
|
||||||
|
|
@ -62,7 +62,7 @@ def main() -> None:
|
||||||
)
|
)
|
||||||
print("add ->", add["data"])
|
print("add ->", add["data"])
|
||||||
|
|
||||||
flush = _post("/api/v1/memory/flush", {"session_id": SESSION, "messages": []})
|
flush = _post("/api/v2/memory/flush", {"session_id": SESSION, "messages": []})
|
||||||
print("flush ->", flush["data"])
|
print("flush ->", flush["data"])
|
||||||
|
|
||||||
print("waiting for async index sync ...")
|
print("waiting for async index sync ...")
|
||||||
|
|
@ -70,7 +70,7 @@ def main() -> None:
|
||||||
|
|
||||||
for method in ("keyword", "hybrid", "agentic"):
|
for method in ("keyword", "hybrid", "agentic"):
|
||||||
resp = _post(
|
resp = _post(
|
||||||
"/api/v1/memory/search",
|
"/api/v2/memory/search",
|
||||||
{
|
{
|
||||||
"user_id": USER,
|
"user_id": USER,
|
||||||
"query": "which vector database did we move to and why",
|
"query": "which vector database did we move to and why",
|
||||||
|
|
|
||||||
|
|
@ -125,13 +125,13 @@ def create_app(
|
||||||
app.include_router(health.router)
|
app.include_router(health.router)
|
||||||
app.include_router(metrics.router)
|
app.include_router(metrics.router)
|
||||||
|
|
||||||
# Business API — served under both /api/v2 (cloud-aligned name) and
|
# Business API — served under both /api/v2 (canonical, cloud-aligned name)
|
||||||
# /api/v1 (retained as a permanent backward-compatible alias). The same
|
# and /api/v1 (legacy compatibility alias, removable in a future major).
|
||||||
# router object is mounted twice, so both prefixes resolve to the exact
|
# The same router object is mounted twice, so both prefixes resolve to the
|
||||||
# same handlers; FastAPI's default operationId embeds the path, so the
|
# exact same handlers; FastAPI's default operationId embeds the path, so
|
||||||
# two copies get distinct OpenAPI ids automatically (no collision).
|
# the two copies get distinct OpenAPI ids automatically (no collision).
|
||||||
# v1 and v2 stay identical by construction — see test_api_versioning.
|
# v1 and v2 stay identical by construction — see test_api_versioning.
|
||||||
# v1 first — retained alias, behavior identical.
|
# v1 first — legacy alias, behavior identical.
|
||||||
app.include_router(memorize.router, prefix="/api/v1")
|
app.include_router(memorize.router, prefix="/api/v1")
|
||||||
app.include_router(search.router, prefix="/api/v1")
|
app.include_router(search.router, prefix="/api/v1")
|
||||||
app.include_router(get.router, prefix="/api/v1")
|
app.include_router(get.router, prefix="/api/v1")
|
||||||
|
|
|
||||||
|
|
@ -160,7 +160,7 @@ def _run_live_demo_flow(
|
||||||
timestamp_ms = int(get_utc_now().timestamp() * 1000)
|
timestamp_ms = int(get_utc_now().timestamp() * 1000)
|
||||||
request(
|
request(
|
||||||
"POST",
|
"POST",
|
||||||
"/api/v1/memory/add",
|
"/api/v2/memory/add",
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
json_body={
|
json_body={
|
||||||
"session_id": LIVE_DEMO_SESSION_ID,
|
"session_id": LIVE_DEMO_SESSION_ID,
|
||||||
|
|
@ -179,7 +179,7 @@ def _run_live_demo_flow(
|
||||||
)
|
)
|
||||||
request(
|
request(
|
||||||
"POST",
|
"POST",
|
||||||
"/api/v1/memory/flush",
|
"/api/v2/memory/flush",
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
json_body={
|
json_body={
|
||||||
"session_id": LIVE_DEMO_SESSION_ID,
|
"session_id": LIVE_DEMO_SESSION_ID,
|
||||||
|
|
@ -199,7 +199,7 @@ def _run_live_demo_flow(
|
||||||
for attempt in range(search_attempts):
|
for attempt in range(search_attempts):
|
||||||
search = request(
|
search = request(
|
||||||
"POST",
|
"POST",
|
||||||
"/api/v1/memory/search",
|
"/api/v2/memory/search",
|
||||||
base_url=base_url,
|
base_url=base_url,
|
||||||
json_body=search_payload,
|
json_body=search_payload,
|
||||||
timeout_seconds=timeout_seconds,
|
timeout_seconds=timeout_seconds,
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
"""API version aliasing — every business route is served under v1 and v2.
|
"""API version aliasing — every business route is served under v1 and v2.
|
||||||
|
|
||||||
The ``/api/v2`` prefix is the cloud-aligned name; ``/api/v1`` is retained as a
|
The ``/api/v2`` prefix is the canonical, cloud-aligned name; ``/api/v1`` is a
|
||||||
permanent backward-compatible alias pointing to the *same* endpoint. These
|
legacy compatibility alias pointing to the *same* endpoint. These tests are
|
||||||
tests are the completeness guard: they fail if any versioned route is exposed
|
the completeness guard: they fail if any versioned route is exposed under one
|
||||||
under one prefix but not the other, or if the two prefixes ever diverge to
|
prefix but not the other, or if the two prefixes ever diverge to different
|
||||||
different handlers. Infrastructure endpoints (``/health``, ``/metrics``) are
|
handlers. Infrastructure endpoints (``/health``, ``/metrics``) are
|
||||||
deliberately unversioned and must NOT be mirrored.
|
deliberately unversioned and must NOT be mirrored.
|
||||||
|
|
||||||
Assertions run against ``app.openapi()["paths"]`` — the authoritative,
|
Assertions run against ``app.openapi()["paths"]`` — the authoritative,
|
||||||
|
|
|
||||||
|
|
@ -134,11 +134,11 @@ def test_live_demo_flow_calls_server_and_builds_story() -> None:
|
||||||
assert timeout_seconds == 3.0
|
assert timeout_seconds == 3.0
|
||||||
if path == "/health":
|
if path == "/health":
|
||||||
return {"status": "ok"}
|
return {"status": "ok"}
|
||||||
if path == "/api/v1/memory/add":
|
if path == "/api/v2/memory/add":
|
||||||
return {"message_count": 1, "status": "accumulated"}
|
return {"message_count": 1, "status": "accumulated"}
|
||||||
if path == "/api/v1/memory/flush":
|
if path == "/api/v2/memory/flush":
|
||||||
return {"message_count": 1, "status": "extracted"}
|
return {"message_count": 1, "status": "extracted"}
|
||||||
if path == "/api/v1/memory/search":
|
if path == "/api/v2/memory/search":
|
||||||
return {
|
return {
|
||||||
"data": {
|
"data": {
|
||||||
"episodes": [
|
"episodes": [
|
||||||
|
|
@ -172,9 +172,9 @@ def test_live_demo_flow_calls_server_and_builds_story() -> None:
|
||||||
|
|
||||||
assert [path for _, path, _ in calls] == [
|
assert [path for _, path, _ in calls] == [
|
||||||
"/health",
|
"/health",
|
||||||
"/api/v1/memory/add",
|
"/api/v2/memory/add",
|
||||||
"/api/v1/memory/flush",
|
"/api/v2/memory/flush",
|
||||||
"/api/v1/memory/search",
|
"/api/v2/memory/search",
|
||||||
]
|
]
|
||||||
add_body = calls[1][2]
|
add_body = calls[1][2]
|
||||||
assert add_body is not None
|
assert add_body is not None
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue