10 KiB
Implementation Plan
-
1. Foundation: reproduce the empty-graph symptom on
maindefaults -
1.1 Reproduce the empty-graph failure mode on the pre-fix
mainconfiguration- Stand up a local Neo4j (per
docker compose up neo4jor an existing host instance) and an unmodified backend on the currentmainbranch with the documented default.env(LLM via Dashscope/Qwen, noEMBEDDING_*overrides). - Upload a small representative seed file, kick off a graph build, and observe the worker until it terminates.
- Capture (a) the resulting
Taskenvelope (status,error), (b) the underlyingmirofish.*logs (ERROR/WARNING lines fromgraphiti_adapterandgraph_builder), and (c) the result ofMATCH (n:Entity {group_id: $gid}) RETURN count(n)in Neo4j. - Observable completion: the captured failure-mode notes (Task envelope + log excerpt + node count) are appended under a new "Reproduction Log" section in
.kiro/specs/graph-build-empty-fix/research.md, identifying which call site surfaces the failure (or which call site silently swallows it). - Requirements: 1.1, 1.2, 1.3
- Stand up a local Neo4j (per
-
1.2 Reconcile reproduction findings with the design hypothesis
- Compare the Reproduction Log against the dim-mismatch / Dashscope-can't-serve-OpenAI-embeddings hypothesis recorded in
research.md. - If findings match, mark the hypothesis "confirmed" in
research.mdand proceed to Task 2. - If findings diverge (root cause is elsewhere — e.g., a different silent path in graphiti-core or
graphiti_adapter), append a one-paragraph design revision todesign.mdunder "Overview" and add or rescope tasks before proceeding to Task 2. - Observable completion:
research.mdhas an explicit "confirmed" or "diverged" verdict with one-line rationale; if diverged,design.mdhas the matching revision paragraph dated to the implementation run. - Requirements: 1.2, 1.4
- Compare the Reproduction Log against the dim-mismatch / Dashscope-can't-serve-OpenAI-embeddings hypothesis recorded in
-
2. Core: flip embedding defaults to local Ollama
-
2.1 (P) Update embedding defaults in backend configuration
- In
backend/app/config.py, change the threeEMBEDDING_*defaults so that, with no.envoverride, the embedder resolves to a local Ollama instance withmxbai-embed-large: modelmxbai-embed-large, base URLhttp://localhost:11434/v1, API keyollama. - Do not introduce a new env var, rename any existing one, or change
GRAPHITI_LLM_PROVIDER(which staysopenai). - Observable completion: importing
Configin a fresh Python shell with an empty.envreturns the three new default values; setting any of the three in.envcontinues to override them (override semantics unchanged). - Requirements: 2.1, 5.4
- Boundary: Config
- In
-
2.2 (P) Add
progress.emptyGraphFailurelocale key in English and Chinese- Add a new entry under the existing
progress.*namespace inlocales/en.jsonandlocales/zh.jsonwhose value names the failure (graph build produced 0 entities for the project'sgroup_id). - Wording must remain readable in both locale switches via
utils.locale.tandvue-i18nwithout templated arguments (no placeholders). - Observable completion:
t('progress.emptyGraphFailure')resolves to a non-empty, locale-appropriate string underset_locale('en')andset_locale('zh'). - Requirements: 4.4, 4.5
- Boundary: locales
- Add a new entry under the existing
-
3. Core: gate graph-build completion on a non-zero entity-node count
-
3.1 Insert non-zero-count gate into the graph-build worker
- In
backend/app/services/graph_builder.py, immediately after_get_graph_info(graph_id)returns and beforecomplete_task(...)is called inside_build_graph_worker, branch ongraph_info.node_count == 0. - On zero: log at ERROR level via
mirofish.graph_builder's existing logger naminggraph_id, then callTaskManager().fail_task(task_id, t('progress.emptyGraphFailure'))and return without invokingcomplete_task. - On non-zero: proceed with the existing
complete_taskpath unchanged. - Do not weaken or touch the existing
except Exceptionbranch in the worker — the gate is additional. - Observable completion: a graph build whose
add_batchreturned cleanly but produced 0(:Entity {group_id})rows in Neo4j surfaces in the UI as aFAILEDtask withTask.error == t('progress.emptyGraphFailure'), and the corresponding ERROR log line is present in the backend logs;Project.statusno longer rests inGRAPH_BUILDINGfor the affected project. - Requirements: 1.4, 3.3, 4.2, 4.4, 4.5
- Depends: 2.2
- In
-
4. Core: documentation updates for the new default
-
4.1 (P) Flip the README env block to Ollama-active, OpenAI/Gemini commented
- In
README.md, edit the env-block code fence (around the existing embedding section) so the three Ollama lines are uncommented and the OpenAI/Gemini examples become commented-out fallback blocks beneath, with one-line guidance on when to use each. - In the surrounding setup prose, list
ollama pull mxbai-embed-largeas a prerequisite alongside Neo4j; keep the existing one-linecurlsmoke test that confirmsembedding length == 1024. - Observable completion: a reader following the README's setup section in order ends up with
EMBEDDING_*configured for local Ollama (no manual uncomment step) and with theollama pullstep queued before the first graph build. - Requirements: 2.2, 6.2, 6.3, 6.4
- Boundary: README.md
- In
-
4.2 (P) Update CLAUDE.md to reflect Ollama as the default embedder
- In
CLAUDE.md"Required Environment Variables", state that the defaultEMBEDDING_MODELismxbai-embed-largevia Ollama athttp://localhost:11434/v1, demote OpenAI and Gemini to "Other supported configurations", and retain the 1024-dim invariant plus the explicit rejection of 768-dimnomic-embed-text. - Observable completion: the "Required Environment Variables" block names Ollama as the active default and CLAUDE.md no longer implies that
text-embedding-3-smallis the default. - Requirements: 3.2, 6.1
- Boundary: CLAUDE.md
- In
-
4.3 (P) Tighten docker-compose.yml comment to point at the active
.env.exampleblock- In
docker-compose.yml, update the comment at themirofishservice (around lines 31-33) so it documentshost.docker.internal:11434as the way the container reaches the host Ollama daemon, and references the.env.exampleOllama block as the active default rather than an optional override. - Do not change service definitions, networks, or env_file wiring.
- Observable completion:
docker-compose.ymlreads as documentation that aligns with the new defaults; runningdocker compose configstill produces a valid configuration (no syntax regression). - Requirements: 6.3
- Boundary: docker-compose.yml
- In
-
4.4 Coordinate the
.env.examplediff (hook-protected file)- The Claude harness cannot write
.env.exampledirectly. Produce the exact diff (Ollama block uncommented as active, OpenAI/Gemini blocks present but commented) and record it in.kiro/specs/graph-build-empty-fix/HANDOFF.mdso the developer can apply it manually before merge. - Confirm that the diff matches
Config's new defaults from Task 2.1 (model, base URL, key strings) so operator-visible defaults align withConfigdefaults. - Observable completion:
HANDOFF.mdcontains the literal block to paste into.env.example, with a one-line "apply manually before merging" note; the diff is internally consistent withConfig's defaults from Task 2.1. - Requirements: 2.2
- Depends: 2.1
- The Claude harness cannot write
-
5. Validation: end-to-end and backwards compatibility
-
5.1 End-to-end smoke: graph build → profile generation → report agent on the new defaults
- With a running local Neo4j and a running local Ollama (with
mxbai-embed-largepulled), runnpm run dev, create a new project, upload a representative seed file, and exercise the pipeline through Step 4 (Report). - Confirm: the graph build
Taskterminates withstatus=COMPLETEDand a non-zeronode_count; the env-setup step produces a non-empty list of OASIS profiles; the report agent'sSearchResult/InsightForge/Panorama/Interviewtool calls return non-empty results. - If a representative seed file is not available locally, document this explicitly (no silent skip) and stop after the graph-build verification.
- Observable completion: a short "Smoke Run" section is appended to
research.mdrecording the project'sgroup_id, the capturednode_count/edge_count, and a one-line confirmation per downstream step; the PR description summarises this run. - Requirements: 1.5, 2.3, 7.1, 7.2, 7.3, 7.4
- Depends: 3.1, 4.4
- With a running local Neo4j and a running local Ollama (with
-
5.2 Backwards-compatibility check for explicit OpenAI/Gemini overrides
- With
.envcontaining explicit OpenAI- or Gemini-compatibleEMBEDDING_*values, restart the backend and confirm that_build_llm_and_embedderconstructs the same embedder as the pre-change implementation (OpenAI branch when the operator sets OpenAI values; Gemini branch underGRAPHITI_LLM_PROVIDER=gemini). - Confirm the graph build completes against the override without engaging the new gate's failure path on the happy case.
- Observable completion: the captured
Task.result.graph_infoshows a non-zeronode_countunder the override; no change in observed behaviour vs. the pre-change implementation for these providers; record outcome in the sameresearch.md"Smoke Run" section under a "Backwards-compat" sub-heading. - Requirements: 5.1, 5.2, 5.3
- Depends: 3.1
- With
-
5.3 Negative-path check: empty-graph gate fires and surfaces in the UI
- Force the new gate to fire — either by pointing
EMBEDDING_*at an unreachable Ollama, or by stubbing_get_graph_infoto returnnode_count=0for one run — and confirm the resultingTaskenvelope. - Confirm:
Task.status == FAILED,Task.erroris the localisedprogress.emptyGraphFailurestring in the active locale, the backend ERROR log entry from Task 3.1 is present, and the surrounding project'sstatusmoves out ofGRAPH_BUILDING(not stuck). - Observable completion: the captured
Taskenvelope and log excerpt are recorded inresearch.md(or the PR description) as the gate's negative-path evidence. - Requirements: 2.4, 4.4, 4.5
- Depends: 3.1
- Force the new gate to fire — either by pointing