revamp README - #1
phraakture wants to merge 1 commit into
Conversation
📝 WalkthroughWalkthroughREADME.md was reorganized to document installation, quickstart usage, the public API, memory processing, chat integration, and server operation with updated examples and configuration details. ChangesREADME documentation
Estimated code review effort: 1 (Trivial) | ~3 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 8be0e4722f
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| hits = memory.search(query=message, conversation_id=conv_id, limit=5) | ||
| memories = "\n".join(f"- [{h['type']}] {h['memory']}" for h in hits["results"]) |
There was a problem hiding this comment.
Make the chat helper await memory calls
In the chat example, Memory.search and Memory.add are async methods, but respond is synchronous and calls memory.search without await; when copied as a normal helper this makes hits a coroutine, so hits["results"] raises TypeError and the later memory.add call is never awaited or persisted. Make respond async and await both memory calls, or explicitly run them on an event loop.
Useful? React with 👍 / 👎.
| | `GET /health` | Health check | | ||
| | `POST /conversations` | Create conversation | | ||
| | `POST /memories` | Add memories from a turn | | ||
| | `GET /memories/search?q=&conv=` | Vector search | |
There was a problem hiding this comment.
Document the actual search query parameters
The documented URL uses q and conv, but the FastAPI handler requires query parameters named query and conversation_id; a user following this endpoint shape will get a validation error instead of search results. Update the example to /memories/search?query=...&conversation_id=... so it matches search_memories in src/eidetic/api/app.py.
Useful? React with 👍 / 👎.
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@README.md`:
- Line 82: Update the fenced diagram block in README.md by adding an appropriate
language identifier, such as text, to its opening fence while preserving the
diagram content.
- Around line 133-156: Update the README endpoint table’s GET /memories/search
example to use the actual FastAPI query parameters query and conversation_id
instead of q and conv. Keep the endpoint path and vector-search description
unchanged.
- Around line 99-131: Update the README Chat example’s respond function to be
asynchronous and await both memory.search() and memory.add(). Preserve the
existing search, LLM response, and persistence flow while ensuring hits contains
the resolved search result before accessing results.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| eidetic serve | ||
| ## How it works | ||
|
|
||
| ``` |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Specify a language for the fenced diagram block.
Add a language identifier such as text after the opening fence so markdownlint does not report MD040.
🧰 Tools
🪛 markdownlint-cli2 (0.23.0)
[warning] 82-82: Fenced code blocks should have a language specified
(MD040, fenced-code-language)
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` at line 82, Update the fenced diagram block in README.md by adding
an appropriate language identifier, such as text, to its opening fence while
preserving the diagram content.
Source: Linters/SAST tools
| ## Chat example | ||
|
|
||
| ### Docker | ||
| ```python | ||
| from openai import OpenAI | ||
| from eidetic import configure, Memory, create_table | ||
|
|
||
| ```bash | ||
| docker compose up --build | ||
| ``` | ||
| configure(openrouter_api_key="sk-or-v1-...", llm_provider="openrouter") | ||
| chat = OpenAI(api_key="sk-or-v1-...", base_url="https://openrouter.ai/api/v1") | ||
| await create_table() | ||
| memory = Memory() | ||
|
|
||
| Set API keys via environment variables (see `.env.example`). | ||
|
|
||
| ## CLI | ||
| def respond(message: str, conv_id: int = 1) -> str: | ||
| # 1. Retrieve relevant memories | ||
| hits = memory.search(query=message, conversation_id=conv_id, limit=5) | ||
| memories = "\n".join(f"- [{h['type']}] {h['memory']}" for h in hits["results"]) | ||
|
|
||
| ``` | ||
| eidetic create-conversation create a new conversation | ||
| eidetic add <conv_id> <user> <asst> add memories from one turn | ||
| eidetic search <conv_id> <query> search stored memories | ||
| eidetic expire-bubbles [conv_id] run bubble TTL expiry | ||
| # 2. Call LLM with memory context | ||
| reply = chat.chat.completions.create( | ||
| model="anthropic/claude-sonnet-4.5", | ||
| messages=[ | ||
| {"role": "system", "content": f"User memories:\n{memories or 'None yet.'}"}, | ||
| {"role": "user", "content": message}, | ||
| ], | ||
| ).choices[0].message.content | ||
|
|
||
| # 3. Store new facts from this exchange | ||
| memory.add( | ||
| messages=[{"role": "user", "content": message}, {"role": "assistant", "content": reply}], | ||
| conversation_id=conv_id, | ||
| ) | ||
| return reply | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Await the asynchronous memory APIs.
Memory.search() and Memory.add() are async, but respond() is synchronous and neither call is awaited. As written, hits["results"] operates on a coroutine and the new facts are never persisted.
Proposed fix
-def respond(message: str, conv_id: int = 1) -> str:
+async def respond(message: str, conv_id: int = 1) -> str:
# 1. Retrieve relevant memories
- hits = memory.search(query=message, conversation_id=conv_id, limit=5)
+ hits = await memory.search(query=message, conversation_id=conv_id, limit=5)
memories = "\n".join(f"- [{h['type']}] {h['memory']}" for h in hits["results"])
...
- memory.add(
+ await memory.add(
messages=[{"role": "user", "content": message}, {"role": "assistant", "content": reply}],
conversation_id=conv_id,
)📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Chat example | |
| ### Docker | |
| ```python | |
| from openai import OpenAI | |
| from eidetic import configure, Memory, create_table | |
| ```bash | |
| docker compose up --build | |
| ``` | |
| configure(openrouter_api_key="sk-or-v1-...", llm_provider="openrouter") | |
| chat = OpenAI(api_key="sk-or-v1-...", base_url="https://openrouter.ai/api/v1") | |
| await create_table() | |
| memory = Memory() | |
| Set API keys via environment variables (see `.env.example`). | |
| ## CLI | |
| def respond(message: str, conv_id: int = 1) -> str: | |
| # 1. Retrieve relevant memories | |
| hits = memory.search(query=message, conversation_id=conv_id, limit=5) | |
| memories = "\n".join(f"- [{h['type']}] {h['memory']}" for h in hits["results"]) | |
| ``` | |
| eidetic create-conversation create a new conversation | |
| eidetic add <conv_id> <user> <asst> add memories from one turn | |
| eidetic search <conv_id> <query> search stored memories | |
| eidetic expire-bubbles [conv_id] run bubble TTL expiry | |
| # 2. Call LLM with memory context | |
| reply = chat.chat.completions.create( | |
| model="anthropic/claude-sonnet-4.5", | |
| messages=[ | |
| {"role": "system", "content": f"User memories:\n{memories or 'None yet.'}"}, | |
| {"role": "user", "content": message}, | |
| ], | |
| ).choices[0].message.content | |
| # 3. Store new facts from this exchange | |
| memory.add( | |
| messages=[{"role": "user", "content": message}, {"role": "assistant", "content": reply}], | |
| conversation_id=conv_id, | |
| ) | |
| return reply | |
| ``` | |
| ## Chat example | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` around lines 99 - 131, Update the README Chat example’s respond
function to be asynchronous and await both memory.search() and memory.add().
Preserve the existing search, LLM response, and persistence flow while ensuring
hits contains the resolved search result before accessing results.
| ## Server | ||
|
|
||
| ``` | ||
| ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ | ||
| │ FastAPI │───▶│ MemoryService │───▶│ Extractor │ | ||
| │ (HTTP) │ │ (orchestr.) │ │ (LLM) │ | ||
| └─────────────┘ └──────┬───────┘ └──────────────┘ | ||
| │ | ||
| ┌────────────┼────────────┐ | ||
| ▼ ▼ ▼ | ||
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | ||
| │Classifier│ │ Bubble │ │ Summary │ | ||
| │ (LLM) │ │ Creator │ │ Service │ | ||
| └──────────┘ └──────────┘ └──────────┘ | ||
| │ | ||
| ┌────────────┼────────────┐ | ||
| ▼ ▼ ▼ | ||
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | ||
| │ FAISS │ │ SQLite │ │ LLM / │ | ||
| │ Index │ │ DB │ │ Embedding │ | ||
| └──────────┘ └──────────┘ └──────────┘ | ||
| ```bash | ||
| pip install 'eidetic-ai[server]' | ||
| eidetic serve # http://localhost:8000 | ||
| ``` | ||
|
|
||
| **Memory types:** | ||
| - **Semantic** — stable long-term facts about the user (name, preferences, skills). Deduplicated and updated via an LLM classifier (ADD / UPDATE / REPLACE / DELETE / NOOP). | ||
| - **Bubbles (episodic)** — time-bound significant moments. Linked bidirectionally to related memories via FAISS similarity. Automatically expired after a configurable TTL. | ||
| | Endpoint | Description | | ||
| |----------|-------------| | ||
| | `GET /health` | Health check | | ||
| | `POST /conversations` | Create conversation | | ||
| | `POST /memories` | Add memories from a turn | | ||
| | `GET /memories/search?q=&conv=` | Vector search | | ||
| | `PUT /memories/{id}` | Update memory text | | ||
| | `DELETE /memories/{id}` | Soft-delete | | ||
| | `POST /bubbles/expire` | Expire stale bubbles | | ||
|
|
||
| ## Config | ||
| Full OpenAPI docs at `/docs`. | ||
|
|
||
| All configuration via environment variables with prefix `EIDETIC_` or via the `configure()` function: | ||
| ### Docker | ||
|
|
||
| | Variable / kwarg | Default | Description | | ||
| |---|---|---| | ||
| | `EIDETIC_OPENAI_API_KEY` | — | OpenAI API key | | ||
| | `EIDETIC_OPENROUTER_API_KEY` | — | OpenRouter API key | | ||
| | `EIDETIC_LLM_PROVIDER` | `openai` | `openai` or `openrouter` | | ||
| | `EIDETIC_LLM_MODEL` | `gpt-4o-mini` | LLM model name | | ||
| | `EIDETIC_EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model name | | ||
| | `EIDETIC_DATABASE_URL` | `~/.eidetic/eidetic.db` | SQLAlchemy async DB URL | | ||
| | `EIDETIC_DEBUG` | `false` | Enable debug logging | | ||
| | `EIDETIC_BUBBLE_TTL_DAYS` | `30` | Bubble expiry in days (0 = never) | | ||
| | `EIDETIC_CONNECTION_THRESHOLD` | `0.6` | Min similarity for bubble links | | ||
| | `EIDETIC_MAX_CONNECTIONS_PER_BUBBLE` | `5` | Max bidirectional links per bubble | | ||
| ```bash | ||
| docker compose up --build | ||
| ``` |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
Document the actual search query parameters.
The FastAPI endpoint accepts query and conversation_id, but the README advertises q and conv; following this example results in a validation error.
-| `GET /memories/search?q=&conv=` | Vector search |
+| `GET /memories/search?query=&conversation_id=` | Vector search |📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| ## Server | |
| ``` | |
| ┌─────────────┐ ┌──────────────┐ ┌──────────────┐ | |
| │ FastAPI │───▶│ MemoryService │───▶│ Extractor │ | |
| │ (HTTP) │ │ (orchestr.) │ │ (LLM) │ | |
| └─────────────┘ └──────┬───────┘ └──────────────┘ | |
| │ | |
| ┌────────────┼────────────┐ | |
| ▼ ▼ ▼ | |
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | |
| │Classifier│ │ Bubble │ │ Summary │ | |
| │ (LLM) │ │ Creator │ │ Service │ | |
| └──────────┘ └──────────┘ └──────────┘ | |
| │ | |
| ┌────────────┼────────────┐ | |
| ▼ ▼ ▼ | |
| ┌──────────┐ ┌──────────┐ ┌──────────┐ | |
| │ FAISS │ │ SQLite │ │ LLM / │ | |
| │ Index │ │ DB │ │ Embedding │ | |
| └──────────┘ └──────────┘ └──────────┘ | |
| ```bash | |
| pip install 'eidetic-ai[server]' | |
| eidetic serve # http://localhost:8000 | |
| ``` | |
| **Memory types:** | |
| - **Semantic** — stable long-term facts about the user (name, preferences, skills). Deduplicated and updated via an LLM classifier (ADD / UPDATE / REPLACE / DELETE / NOOP). | |
| - **Bubbles (episodic)** — time-bound significant moments. Linked bidirectionally to related memories via FAISS similarity. Automatically expired after a configurable TTL. | |
| | Endpoint | Description | | |
| |----------|-------------| | |
| | `GET /health` | Health check | | |
| | `POST /conversations` | Create conversation | | |
| | `POST /memories` | Add memories from a turn | | |
| | `GET /memories/search?q=&conv=` | Vector search | | |
| | `PUT /memories/{id}` | Update memory text | | |
| | `DELETE /memories/{id}` | Soft-delete | | |
| | `POST /bubbles/expire` | Expire stale bubbles | | |
| ## Config | |
| Full OpenAPI docs at `/docs`. | |
| All configuration via environment variables with prefix `EIDETIC_` or via the `configure()` function: | |
| ### Docker | |
| | Variable / kwarg | Default | Description | | |
| |---|---|---| | |
| | `EIDETIC_OPENAI_API_KEY` | — | OpenAI API key | | |
| | `EIDETIC_OPENROUTER_API_KEY` | — | OpenRouter API key | | |
| | `EIDETIC_LLM_PROVIDER` | `openai` | `openai` or `openrouter` | | |
| | `EIDETIC_LLM_MODEL` | `gpt-4o-mini` | LLM model name | | |
| | `EIDETIC_EMBEDDING_MODEL` | `text-embedding-3-small` | Embedding model name | | |
| | `EIDETIC_DATABASE_URL` | `~/.eidetic/eidetic.db` | SQLAlchemy async DB URL | | |
| | `EIDETIC_DEBUG` | `false` | Enable debug logging | | |
| | `EIDETIC_BUBBLE_TTL_DAYS` | `30` | Bubble expiry in days (0 = never) | | |
| | `EIDETIC_CONNECTION_THRESHOLD` | `0.6` | Min similarity for bubble links | | |
| | `EIDETIC_MAX_CONNECTIONS_PER_BUBBLE` | `5` | Max bidirectional links per bubble | | |
| ```bash | |
| docker compose up --build | |
| ``` | |
| ## Server | |
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@README.md` around lines 133 - 156, Update the README endpoint table’s GET
/memories/search example to use the actual FastAPI query parameters query and
conversation_id instead of q and conv. Keep the endpoint path and vector-search
description unchanged.
Cleaner structure, badges, condensed API reference, simplified quickstart.
Summary by CodeRabbit