Blocked: this can only be started after #100 is done.
Summary
Add an "Ask AI" tab to IceGraph: a chat-style page, alongside Graph/Metadata/Timeline/FileTree, where a user can ask free-form questions about the currently-loaded table and get a full AI-generated answer back.
Confirmed requirements
There will be a custom prompt in the backend that will be on top of the user prompt.
- Backend adds the official
openai Python SDK. The AI endpoint, model, and API key are configured entirely through environment variables (backend/constants.py-style config, same pattern as SPARK_REMOTE). No provider picker, no endpoint/token field anywhere in the UI.
- Frontend gets a new page: an AI chat assistant.
- Each question automatically includes context about the currently-loaded table (schema, partition spec, node/file counts).
- As the user chats, the conversation has memory across turns, but what's persisted to
localStorage is a running summary, not the raw message list. Every request sends the question plus the current summary; every response returns both the answer and an updated summary, which overwrites what's in localStorage.
localStorage is scoped per table (keyed by table name + snapshot range, same key style as the existing graphData_<table>_<start>_<end> cache key).
- The relay reuses the existing async job/poll mechanism (
jobs dict + ThreadPoolExecutor + per-job token) that /api/v1/graph-data already uses. A synchronous call isn't acceptable because a slow AI response would block the whole app for every user.
- Responses are returned in full — no streaming.
Backend
New dependency: openai (official Python SDK). Its base_url override also covers Azure OpenAI and OpenAI-compatible self-hosted servers (Ollama, vLLM), so one client code path is enough. Add via uv add openai in backend/.
backend/constants.py — new env-configurable defaults, same pattern as MAX_SNAPSHOTS_TO_COMPUTE:
| Variable |
Default |
Purpose |
AI_API_BASE_URL |
"" |
Base URL passed to the openai client. Empty = feature disabled. |
AI_API_KEY |
"" |
API key passed to the openai client. Empty = feature disabled. |
AI_MODEL |
"gpt-4o-mini" |
Model name to request. |
AI_REQUEST_TIMEOUT_SECONDS |
60 |
Timeout passed to the openai client. |
No new token-header constant needed — reuse the existing JOB_TOKEN_FIELD (X-IceGraph-Job-Token) for ask-ai jobs too.
Frontend
- A new "Ask AI" tab, in the same nav position as Graph/Metadata/Timeline/FileTree, reachable by keyboard shortcut
5.
- A chat interface: the user types a question, submits it, sees a loading state, then the full AI answer appears in the conversation.
- Each question automatically carries the currently-loaded table's context (schema, partition spec, node/file counts) — the user never has to supply this themselves.
- Conversation memory persists per table (scoped by table + snapshot range) across page reloads, as a running summary rather than the raw message transcript.
- If the AI backend is unavailable or misconfigured, the tab shows an inline error without breaking the rest of the app.
- Visually and structurally consistent with the existing tabs (same nav/typography/error-state conventions already used elsewhere in the app).
Per CLAUDE.md's standing convention for this repo: DocsPage.jsx gets a section for the new tab, and claude-plugin/skills/icegraph/SKILL.md gets the new /table/ask-ai route.
Blocked: this can only be started after #100 is done.
Summary
Add an "Ask AI" tab to IceGraph: a chat-style page, alongside Graph/Metadata/Timeline/FileTree, where a user can ask free-form questions about the currently-loaded table and get a full AI-generated answer back.
Confirmed requirements
There will be a custom prompt in the backend that will be on top of the user prompt.
openaiPython SDK. The AI endpoint, model, and API key are configured entirely through environment variables (backend/constants.py-style config, same pattern asSPARK_REMOTE). No provider picker, no endpoint/token field anywhere in the UI.localStorageis a running summary, not the raw message list. Every request sends the question plus the current summary; every response returns both the answer and an updated summary, which overwrites what's inlocalStorage.localStorageis scoped per table (keyed by table name + snapshot range, same key style as the existinggraphData_<table>_<start>_<end>cache key).jobsdict +ThreadPoolExecutor+ per-job token) that/api/v1/graph-dataalready uses. A synchronous call isn't acceptable because a slow AI response would block the whole app for every user.Backend
New dependency:
openai(official Python SDK). Itsbase_urloverride also covers Azure OpenAI and OpenAI-compatible self-hosted servers (Ollama, vLLM), so one client code path is enough. Add viauv add openaiinbackend/.backend/constants.py— new env-configurable defaults, same pattern asMAX_SNAPSHOTS_TO_COMPUTE:AI_API_BASE_URL""openaiclient. Empty = feature disabled.AI_API_KEY""openaiclient. Empty = feature disabled.AI_MODEL"gpt-4o-mini"AI_REQUEST_TIMEOUT_SECONDS60openaiclient.No new token-header constant needed — reuse the existing
JOB_TOKEN_FIELD(X-IceGraph-Job-Token) for ask-ai jobs too.Frontend
5.Per CLAUDE.md's standing convention for this repo:
DocsPage.jsxgets a section for the new tab, andclaude-plugin/skills/icegraph/SKILL.mdgets the new/table/ask-airoute.