Skip to content

feat(graph-rag): implement full query runtime - #32

Merged
kl3inIT merged 1 commit into
light-ragfrom
kl3inIT/light-rag-pr07-query-runtime
Jul 24, 2026
Merged

feat(graph-rag): implement full query runtime#32
kl3inIT merged 1 commit into
light-ragfrom
kl3inIT/light-rag-pr07-query-runtime

Conversation

@kl3inIT

@kl3inIT kl3inIT commented Jul 24, 2026

Copy link
Copy Markdown
Owner

What changed

  • ports the complete LightRAG v1.5.4 query modes into the framework-neutral core: local, global, hybrid, naive, mix, and bypass
  • adds permission-scoped, snapshot-pinned entity/relation/chunk retrieval, expansion, related-chunk recovery, deterministic fusion, reranking fallback, token budgeting, references, and immutable trace output
  • adds Spring AI adapters for structured high/low keyword planning and complete/streaming answer generation
  • adds deterministic testkit projection and cross-tenant, mode, batching, rerank, output, heading, and streaming conformance tests
  • records the PR7/PR8 activation boundary: production mixed graph/chunk reads remain fail-closed until PR8 publishes graph in the shared snapshot

Why

PR7 owns executable query semantics while keeping provider and storage effects behind explicit ports. This preserves LightRAG behavior without allowing Spring AI, PostgreSQL, or an authorization adapter to leak into the algorithmic core.

Validation

  • git diff --check
  • mechanical Java package and zero-byte source checks
  • ./gradlew.bat --no-daemon compileJava
  • focused graph-rag core, testkit, and Spring AI tests
  • ./gradlew.bat --no-daemon test
  • isolated :apps:worker:test --rerun-tasks after a transient Gradle binary-results race

Merge target

This PR intentionally targets light-rag. It must not be merged directly into main.

Summary by CodeRabbit

  • New Features

    • Added end-to-end GraphRAG query execution with local, global, hybrid, naive, mixed, and bypass modes.
    • Added keyword planning, semantic retrieval, graph expansion, chunk ranking, optional reranking, context assembly, references, tracing, and streaming answers.
    • Added Spring AI integration for keyword planning and complete or streaming answer generation.
    • Added configurable output modes for context, prompts, or generated answers.
  • Tests

    • Added comprehensive coverage for retrieval modes, authorization filtering, reranking fallback, streaming, and output validation.

@coderabbitai

coderabbitai Bot commented Jul 24, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a framework-neutral LightRAG query runtime with validated contracts, keyword planning, authorized retrieval, chunk reranking, context assembly, structured results, in-memory conformance coverage, and Spring AI model adapters.

Changes

LightRAG query runtime

Layer / File(s) Summary
Query contracts and result models
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/*
Adds validated projection, request, answer, reranker, mode, output, and result contracts.
Keyword planning
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java, KeywordPlanningModel.java, LightRagKeywordPlanner.java, components/graph-rag-core/src/test/.../LightRagKeywordPlannerTests.java
Normalizes keyword plans, supports model and trusted sources, and applies short-query fallback behavior.
Query execution and rendering
components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java, components/graph-rag-core/src/test/.../LightRagWeightedPollingTests.java
Executes retrieval modes, graph expansion, chunk selection, reranking, token budgeting, context rendering, tracing, and answer generation.
Projection testkit and conformance
components/graph-rag-testkit/src/main/java/.../InMemoryAuthorizedQueryProjection.java, components/graph-rag-testkit/src/test/.../LightRagQueryRuntimeConformanceTests.java
Provides deterministic authorized projection behavior and tests retrieval branches, visibility, bypass, reranking, output modes, and request validation.
Spring AI adapters
integrations/graph-rag-spring-ai/src/main/java/..., integrations/graph-rag-spring-ai/src/test/...
Adds Spring AI keyword-planning and answer-generation adapters with structured parsing, streaming responses, error handling, and tests.

Estimated code review effort: 5 (Critical) | ~120 minutes

Sequence Diagram(s)

sequenceDiagram
  participant Client
  participant LightRagQueryEngine
  participant KeywordPlanningModel
  participant AuthorizedQueryProjection
  participant ChunkReranker
  participant QueryAnswerModel
  Client->>LightRagQueryEngine: execute(request)
  LightRagQueryEngine->>KeywordPlanningModel: complete(prompt)
  LightRagQueryEngine->>AuthorizedQueryProjection: retrieve authorized graph and chunks
  LightRagQueryEngine->>ChunkReranker: rerank(chunk candidates)
  LightRagQueryEngine->>QueryAnswerModel: answer(grounded request)
  QueryAnswerModel-->>LightRagQueryEngine: answer response
  LightRagQueryEngine-->>Client: LightRagQueryResult
Loading

Possibly related PRs

  • kl3inIT/OrgMemory#27: Introduces core authorization, snapshot, and vector types consumed by the new query contracts.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: implementing the full graph-RAG query runtime.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch kl3inIT/light-rag-pr07-query-runtime

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@kl3inIT
kl3inIT merged commit 6c899a2 into light-rag Jul 24, 2026
4 of 5 checks passed

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 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
`@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java`:
- Around line 488-499: Update the reranked stream in LightRagQueryEngine so
missing rerank scores do not receive top priority or bypass minimumRerankScore.
Exclude null-scored ChunkState entries before applying the chunkTopK limit,
while preserving the existing scored-item threshold, ordering, and tie-breakers.
- Around line 68-70: Update the empty-keyword guard in LightRagQueryEngine so it
returns no results only for pure graph modes; allow MIX and NAIVE modes to
continue into their chunk-seed or vectorChunks retrieval paths. Preserve the
existing noResults behavior when a graph-only mode has empty keywords.

In
`@components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java`:
- Around line 304-333: Update the visible(Chunk) overload to require
chunk.evidence().projectionGeneration() to equal snapshot.generation(),
alongside its existing scope and organization checks. Ensure searchChunks,
rankChunks, and loadChunks continue using this visibility predicate so all
exposed chunks are pinned to the requested projection snapshot.

In
`@components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java`:
- Around line 66-67: Add conformance fixtures in
LightRagQueryRuntimeConformanceTests using GENERATION - 1 alongside the existing
GENERATION data, covering stale entities/relations and chunks. For a snapshot
pinned to GENERATION, assert the stale fixture is absent from both returned
references and context, validating generation filtering across all projected
data types.

In
`@integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java`:
- Around line 43-46: Update the Prompt ChatOptions construction in
SpringAiKeywordPlanningModel.java (lines 43-46) and the comparable construction
in SpringAiQueryAnswerModel.java (lines 68-70) to derive from
chatModel.getOptions().mutate(), overriding only the intended model and
temperature values while preserving configured provider options such as apiKey,
baseUrl, and timeout.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 35533b62-a359-49ed-bd4f-118e30dcdd31

📥 Commits

Reviewing files that changed from the base of the PR and between cdc03ef and bb3f39e.

⛔ Files ignored due to path filters (3)
  • docs/increments/active/2026-07-23-full-lightrag-semantic-port/design.md is excluded by !docs/**
  • docs/increments/active/2026-07-23-full-lightrag-semantic-port/plan.md is excluded by !docs/**
  • docs/research/lightrag-v1.5.4-parity-manifest.md is excluded by !docs/**
📒 Files selected for processing (21)
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryResult.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryOutputMode.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagWeightedPollingTests.java
  • components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java
  • components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/GraphQueryModelException.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/StructuredKeywordPlanResponse.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModelTests.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModelTests.java
📜 Review details
⏰ Context from checks skipped due to timeout. (1)
  • GitHub Check: Backend · Java 25
🧰 Additional context used
📓 Path-based instructions (3)
**/*

📄 CodeRabbit inference engine (CLAUDE.md)

**/*: Before changing unfamiliar Spring Boot 4, Spring Modulith 2, Spring AI 2, Gradle, React, Vite, Tailwind, or TypeScript APIs, consult Context7/current official documentation and the project orgmemory-* verification skills.
Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work.
Never commit .env files, provider keys, tokens, or customer data.
Run the relevant gates from docs/guidelines/testing-harness.md; use a terminating clean test as the context gate, and do not treat bootRun as verification.
Current behavior belongs in architecture/specs only after it exists in code; intent belongs in vision, roadmap, or an active increment, and repository state must not be duplicated across documents.

Files:

  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryOutputMode.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/GraphQueryModelException.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/StructuredKeywordPlanResponse.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModelTests.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagWeightedPollingTests.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModelTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java
  • components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryResult.java
  • components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java
**/*.{java,sql}

📄 CodeRabbit inference engine (CLAUDE.md)

Pair JPA schema changes with a Flyway migration.

Files:

  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryOutputMode.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/GraphQueryModelException.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/StructuredKeywordPlanResponse.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModelTests.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagWeightedPollingTests.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModelTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java
  • components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryResult.java
  • components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java
**/*.java

📄 CodeRabbit inference engine (CLAUDE.md)

JetBrains IDE inspection is a Java-backend gate only.

Files:

  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryOutputMode.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/GraphQueryModelException.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/StructuredKeywordPlanResponse.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModelTests.java
  • components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagWeightedPollingTests.java
  • integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModelTests.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java
  • components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryResult.java
  • components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java
  • components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java
🔇 Additional comments (20)
integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/GraphQueryModelException.java (1)

1-12: LGTM!

integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/StructuredKeywordPlanResponse.java (1)

1-9: LGTM!

integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModelTests.java (1)

1-67: LGTM!

integrations/graph-rag-spring-ai/src/test/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModelTests.java (1)

1-104: LGTM!

components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java (2)

40-303: LGTM!


335-347: LGTM!

components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java (1)

1-263: LGTM!

Also applies to: 344-602

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java (1)

84-129: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java (1)

9-30: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java (1)

12-26: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java (1)

19-125: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryAnswerModel.java (1)

15-62: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryResult.java (1)

18-138: LGTM!

components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagWeightedPollingTests.java (1)

12-46: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/QueryOutputMode.java (1)

1-7: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlan.java (1)

1-67: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/KeywordPlanningModel.java (1)

1-11: LGTM!

components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagKeywordPlanner.java (2)

24-43: LGTM!


45-65: 🔒 Security & Privacy

Confirm agent-safety guidance was applied for this AI-integration surface.

prompt() interpolates raw, unescaped user query text directly into the LLM prompt sent via KeywordPlanningModel. This is new retrieval/AI-call surface; please confirm docs/guidelines/agent-safety.md guidance on handling untrusted input in prompts (e.g., injection resistance beyond the ---Constraints--- section) was consulted for this design.

As per coding guidelines, "Read docs/guidelines/agent-safety.md before retrieval, AI, MCP, permission, upload, graph, or export work."

Source: Coding guidelines

components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java (1)

1-77: LGTM!

Comment on lines +68 to +70
if (request.options().mode().usesGraph() && keywords.empty()) {
return noResults(request, keywords, List.of(), "keywords_empty");
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🌐 Web query:

LightRAG mix mode empty keywords fallback vector retrieval

💡 Result:

In LightRAG, the mix mode is a comprehensive retrieval strategy that integrates results from local graph retrieval, global graph retrieval, and naive (vector-based) retrieval [1][2][3]. Regarding keyword handling and fallback mechanisms: 1. Keyword Usage: Users can provide hl_keywords (high-level) and ll_keywords (low-level) to prioritize specific retrieval focuses [4][5]. Providing these lists acts as an manual override; when they are provided, LightRAG treats them as explicit instructions for the graph retrieval components, bypassing automatic keyword extraction [6]. 2. Empty Keywords Fallback: If these keyword lists are left empty (the default), LightRAG employs an internal process to automatically extract keywords from the user query before proceeding with graph retrieval [6]. 3. Vector Retrieval Behavior: While keywords primarily steer the knowledge graph traversal, the mix mode simultaneously performs a parallel vector similarity search using the raw query text (optionally augmented with conversation history) [7]. Importantly, direct chunk-vector retrieval in mix mode uses the raw query, ensuring that retrieval remains robust even if automatic keyword extraction processes are empty or suboptimal [6]. In specific implementations or forks (such as those managing local/global fallback logic), if automatic extraction yields no usable keywords, the system defaults to using the raw query to maintain retrieval continuity [6]. In summary, the mix mode does not "fail" if keywords are empty; instead, it either automatically generates them or relies on the parallel raw-query vector retrieval path to ensure retrieval coverage [6][7].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate file:"
fd -a 'LightRagQueryEngine.java' . || true

echo
echo "File outline:"
ast-grep outline components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java --view expanded || true

echo
echo "Relevant lines 1-140:"
sed -n '1,140p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java | nl -ba

echo
echo "Search mode definitions/usages:"
rg -n "enum Query[A-Za-z0-9_]*|MIX|usesGraph|usesChunkSeeds|LightRagQueryMode|QueryMode" components/graph-rag-core/src/main/java -S

Repository: kl3inIT/OrgMemory

Length of output: 2545


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant lines 1-140:"
sed -n '1,140p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java | cat -n

echo
echo "Search mode definitions/usages:"
rg -n "enum Query[A-Za-z0-9_]*|MIX|usesGraph|usesChunkSeeds|LightRagQueryMode|QueryMode" components/graph-rag-core/src/main/java -S

echo
echo "Search LightRagQueryMode files:"
fd -i 'LightRagQueryMode|QueryMode' components/graph-rag-core/src/main/java -e java

Repository: kl3inIT/OrgMemory

Length of output: 10572


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "LightRagQueryMode.java:"
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java

echo
echo "RetrievalStrategy.java:"
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/RetrievalStrategy.java

echo
echo "LightRagQueryRequest.java around options:"
sed -n '1,130p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryRequest.java | cat -n

echo
echo "Tests mentioning MIX, keywords_empty, usesChunkSeeds, or empty keyword plan:"
rg -n "MIX|keywords_empty|usesChunkSeeds|usesGraph|LightRagQueryMode|keyword" --glob '*.java' .

Repository: kl3inIT/OrgMemory

Length of output: 40451


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant line 99 and vectorChunks implementation:"
sed -n '90,115p;150,170p;448,495p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java | cat -n

echo
echo "LightRagQueryRuntimeConformanceTests relevant sections:"
sed -n '90,135p;170,225p;233,255p;335,385p' components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java | cat -n

echo
echo "KeywordPlan tests related to empty/high/low/source:"
sed -n '1,120p' components/graph-rag-core/src/test/java/com/orgmemory/graphrag/query/LightRagKeywordPlannerTests.java | cat -n

echo
echo "Read-only semantic probe for current mode predicates and proposed guard:"
python3 - <<'PY'
from pathlib import Path
text = Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java').read_text()
mode = Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryMode.java').read_text()
checks = {
    "line_68_usesGraph_shortcircuit": "request.options().mode().usesGraph() && keywords.empty()" in text,
    "line_99_mixed_usesChunkSeeds_vectorChunks": "request.options().mode().usesChunkSeeds()\n                ? vectorChunks(request, embeddingPlan.query())" in text,
    "mix_usesChunkSeeds_predicate": "public boolean usesChunkSeeds()\n        return this == NAIVE || this == MIX;" in mode,
    "mix_usesGraph_predicate": "public boolean usesGraph()\n        return this == LOCAL || this == GLOBAL || this == HYBRID || this == MIX;" in mode,
    "sec_mix_channels_chunk": "RetrievalStrategy.SECURE_MIX(List.of(\n            RetrievalChannel.ENTITY,\n            RetrievalChannel.RELATION,\n            RetrievalChannel.CHUNK));" in Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/RetrievalStrategy.java').read_text(),
}
for key, val in checks.items():
    print(f"{key}: {val}")
PY

Repository: kl3inIT/OrgMemory

Length of output: 17116


Keep MIX chunk-seed retrieval when keyword planning is empty.

MIX has chunk-seed retrieval, but the usesGraph() && keywords.empty() guard returns NO_RESULTS before the vectorChunks() path can run. Pure graph modes should still require keywords; bypass only this guard for MIX or NAIVE.

🐛 Proposed fix
-        if (request.options().mode().usesGraph() && keywords.empty()) {
+        if (request.options().mode().usesGraph()
+                && !request.options().mode().usesChunkSeeds()
+                && keywords.empty()) {
             return noResults(request, keywords, List.of(), "keywords_empty");
         }
📝 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.

Suggested change
if (request.options().mode().usesGraph() && keywords.empty()) {
return noResults(request, keywords, List.of(), "keywords_empty");
}
if (request.options().mode().usesGraph()
&& !request.options().mode().usesChunkSeeds()
&& keywords.empty()) {
return noResults(request, keywords, List.of(), "keywords_empty");
}
🤖 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
`@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java`
around lines 68 - 70, Update the empty-keyword guard in LightRagQueryEngine so
it returns no results only for pure graph modes; allow MIX and NAIVE modes to
continue into their chunk-seed or vectorChunks retrieval paths. Preserve the
existing noResults behavior when a graph-only mode has empty keywords.

Comment on lines +488 to +499
List<ChunkState> reranked = chunks.stream()
.map(item -> item.withRerank(byChunk.get(item.chunk().id())))
.filter(item -> item.rerankScore() == null
|| item.rerankScore() >= request.options().minimumRerankScore())
.sorted(Comparator
.comparingDouble((ChunkState item) ->
item.rerankScore() == null ? 1.0 : item.rerankScore())
.reversed()
.thenComparingInt(ChunkState::order)
.thenComparing(item -> item.chunk().id()))
.limit(request.options().chunkTopK())
.toList();

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Locate files:"
fd -a 'LightRagQueryEngine.java|ChunkReranker.java|ChunkState.java|ChunkRerankers.java' . || true

echo
echo "Git status/stat:"
git status --short
git diff --stat

echo
echo "Outline LightRagQueryEngine:"
ast-grep outline components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java --view compact || true

echo
echo "Relevant LightRagQueryEngine lines 450-530:"
sed -n '450,530p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java | nl -ba -v450

echo
echo "Search rerank symbols:"
rg -n "interface ChunkReranker|class .*ChunkReranker|record ChunkState|chunkTopK|minimumRerankScore|rerankScore|rerank\\(" components/graph-rag-core/src/main/java tests -S || true

echo
echo "Check dependency/docs for rerankers:"
rg -n "Rerank|rerank|chunkTopK|limit" docs components/graph-rag-core/src/main/java -S || true

Repository: kl3inIT/OrgMemory

Length of output: 674


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "Relevant ChunkReranker:"
sed -n '1,240p' components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/ChunkReranker.java

echo
echo "Relevant ChunkState/ChunkState-ish definitions:"
rg -n "record ChunkState|class ChunkState|rerankScore|withRerank" components/graph-rag-core/src/main/java -S

echo
echo "Relevant LightRagQueryEngine rerank section with line numbers:"
python3 - <<'PY'
from pathlib import Path
p = Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java')
lines = p.read_text().splitlines()
for i in range(450, 530):
    if i <= len(lines):
        print(f"{i}: {lines[i-1]}")
PY

echo
echo "Search rerank option usage:"
rg -n "chunkTopK|minimumRerankScore|rerank\\(|ChunkReranker|reranked|withRerank|rerankScore" components/graph-rag-core/src/main/java tests -S || true

Repository: kl3inIT/OrgMemory

Length of output: 13977


🌐 Web query:

Context7 current official documentation ChunkReranker.rerank limit return score for every candidate

💡 Result:

There is no "ChunkReranker" class or rerank method in the current Context7 official documentation [1][2][3]. Recent updates to Context7 have moved away from manual configuration of result limits, pagination, and reranking parameters [4]. The service now performs server-side, LLM-powered reranking automatically [4][3]. Developers describe their needs via a query string, and the system autonomously determines the relevant documentation to return [4]. Historically, older versions or different retrieval libraries (such as those for RedisVL or Elasticsearch) used classes like ChunkReranker or CohereReranker with explicit limit and return_score parameters [5][6][7][8]. However, these are not part of the Context7 API [1][4][3]. In the current Context7 framework, the API manages context token budgets and relevance scoring internally to optimize results without requiring manual tuning from the user [4][9].

Citations:


🌐 Web query:

OrgMemory graph rag ChunkReranker rerank limit documentation return Score list

💡 Result:

In the context of technical RAG (Retrieval-Augmented Generation) systems that employ a reranker (specifically referenced in the RAGFlow ecosystem which uses a "RERANK_LIMIT" parameter), the rerank limit is a backend constraint designed to prevent exceeding the input size capacity of reranking models [1][2]. Key aspects of the rerank limit and its relation to score lists include: 1. Function: The rerank limit defines the maximum number of documents or chunks that the system will pass to the reranker model for scoring in a single batch [3][4]. 2. Calculation and Constraints: - It is typically calculated based on pagination parameters (like page_size) and internal model API limits (e.g., 64) [3][5]. - Systems often enforce a logic such as min(calculated_limit, top_k, max_api_limit) to ensure user-defined Top-K settings are respected without violating provider-imposed API constraints (e.g., a 64-document limit) [1][2]. 3. Return Score List: After the reranker processes these candidates, it returns a list of results (the "score list") that has been re-ordered based on the model's relevance scores [3][4]. In most implementations, these scores are normalized or used to re-sort the initial retrieval pool before the final, paginated response is returned to the user [3][4]. 4. Pagination Issues: There is a known technical challenge in some implementations where the rerank limit must remain a multiple of the page_size to ensure that pagination math remains accurate [5]. Clamping the limit to satisfy API constraints (like the 64-doc limit) can inadvertently break this alignment, leading to dropped results or "short pages" during retrieval [5]. If you are encountering errors or unexpected behavior, it is likely due to the system's backend clamping the RERANK_LIMIT to meet API safety constraints, which may conflict with the page_size or top_k settings configured in your UI [1][5]. Patching the logic to strictly enforce min(RERANK_LIMIT, top_k) is a common developer-recommended workaround [1][2].

Citations:


Treat missing rerank scores as lowest priority instead of top priority.

ChunkReranker.rerank(..., limit) is a top-limit selection contract, so when there are more candidates than chunkTopK, omitted chunks get null scores. They currently pass minimumRerankScore unconditionally and sort first because null is mapped to 1.0, so the final limit(chunkTopK) can return mostly unscored chunks in original order. Drop them here, or sort them after scored chunks that meet the threshold.

🤖 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
`@components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/LightRagQueryEngine.java`
around lines 488 - 499, Update the reranked stream in LightRagQueryEngine so
missing rerank scores do not receive top priority or bypass minimumRerankScore.
Exclude null-scored ChunkState entries before applying the chunkTopK limit,
while preserving the existing scored-item threshold, ordering, and tie-breakers.

Comment on lines +304 to +333
private static boolean visible(
AuthorizedEvidenceScope scope,
ProjectionSnapshot snapshot,
EntityContribution contribution) {
return scope.includes(
contribution.provenance().organizationId(),
contribution.provenance().knowledgeAssetId())
&& contribution.provenance().projectionGeneration() == snapshot.generation();
}

private static boolean visible(
AuthorizedEvidenceScope scope,
ProjectionSnapshot snapshot,
RelationContribution contribution) {
return scope.includes(
contribution.provenance().organizationId(),
contribution.provenance().knowledgeAssetId())
&& contribution.provenance().projectionGeneration() == snapshot.generation();
}

private static boolean visible(
AuthorizedEvidenceScope scope,
ProjectionSnapshot snapshot,
Chunk chunk) {
return scope.includes(
chunk.evidence().organizationId(),
chunk.evidence().knowledgeAssetId())
&& snapshot.namespace().organizationId().equals(
chunk.evidence().organizationId());
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🟠 Major | 🏗️ Heavy lift

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -t f 'AuthorizedQueryProjection.java|EvidenceReference.java|EvidenceProvenance.java'
rg -n -A 15 'interface AuthorizedQueryProjection' --type=java
rg -n -A 12 'record Chunk' --type=java
rg -n -A 10 'record EvidenceReference' --type=java
rg -n -A 10 'record EvidenceProvenance' --type=java

Repository: kl3inIT/OrgMemory

Length of output: 553


🏁 Script executed:

#!/bin/bash
set -u

echo "== authorized projection file outline =="
ast-grep outline components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java --view expanded || true

echo "== relevant testkit file sections =="
cat -n components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java | sed -n '1,220p;300,355p'

echo "== core authorized projection sections =="
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/query/AuthorizedQueryProjection.java | sed -n '1,220p;300,360p'

echo "== evidence/model records =="
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/EvidenceReference.java
echo
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/EvidenceProvenance.java

Repository: kl3inIT/OrgMemory

Length of output: 24866


🏁 Script executed:

#!/bin/bash
set -u

echo "== locate conformance tests and generation constants =="
rg -n -C 4 'GENERATION|projectionGeneration|ProjectionSnapshot|InMemoryAuthorizedQueryProjection' components docs --type=java --glob '!**/graph-rag-testkit/**' || true

echo "== search for projection snapshot/generation model fields =="
rg -n -C 3 'record ProjectionSnapshot|class ProjectionSnapshot|ProjectionSnapshot' --type=java --type=sql || true

echo "== search for chunk projection generation persistence =="
rg -n -C 3 'projection_generation|projectionGeneration|Chunk|EvidenceReference|EvidenceProvenance' components --type=java | sed -n '1,260p' || true

echo "== deterministic behavior probe of visible methods from source text =="
python3 - <<'PY'
from pathlib import Path
s = Path('components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java').read_text()
checks = {
    "entity_visible_has_projectionGeneration": "contribution.provenance().projectionGeneration() == snapshot.generation()" in s,
    "relation_visible_has_projectionGeneration": "contribution.provenance().projectionGeneration() == snapshot.generation()" in s,
    "chunk_visible_has_projectionGeneration": "chunk.evidence().projectionGeneration()" in s or "projectionGeneration" in s[s.find("private static boolean visible("):s.find("private void begin", s.find("private static boolean visible(")))],
    "searchChunks_uses_chunksKeySet": "rankVisibleChunks(scope, snapshot, search, chunks.keySet())" in s,
    "chunk_has_aclGeneration": "long aclGeneration" in Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/EvidenceReference.java').read_text(),
    "chunk_has_projectionGeneration": "projectionGeneration" in Path('components/graph-rag-core/src/main/java/com/orgmemory/graphrag/model/EvidenceReference.java').read_text(),
}
for k,v in checks.items():
    print(f"{k}={v}")
PY

Repository: kl3inIT/OrgMemory

Length of output: 50373


🏁 Script executed:

#!/bin/bash
set -u

echo "== projection snapshot definitions =="
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/storage/ProjectionSnapshot.java

echo "== projection namespace definitions =="
cat -n components/graph-rag-core/src/main/java/com/orgmemory/graphrag/storage/ProjectionNamespace.java

echo "== production AuthorizedQueryProjection implementations =="
fd -t f '.*AuthorizedQueryProjection.*\.java' components --exec sh -c 'echo "--- $1"; cat -n "$1" | sed -n "1,260p"' sh {}

echo "== chunk generation accessors/usages =="
rg -n -C 3 'aclGeneration|projectionGeneration|evidence\(\)\.aclGeneration|snapshot\.generation\(\)' components --type=java | sed -n '1,260p'

echo "== conformance fixture generation references =="
rg -n -C 3 'InMemoryAuthorizedQueryProjection|new Chunk|EvidenceReference\(|GENERATION|projectionGeneration|projection generation' components/graph-rag-core components/graph-rag-testkit --type=java | sed -n '1,260p'

Repository: kl3inIT/OrgMemory

Length of output: 50373


Pin chunk visibility to the projection snapshot generation.

visible(EntityContribution) and visible(RelationContribution) filter by contribution.provenance().projectionGeneration() == snapshot.generation(), but visible(Chunk) only checks organization membership. Add and apply the same generation filter before exposing chunks from searchChunks, rankChunks, and loadChunks; otherwise chunks from a different published projection can be returned for a snapshot-pinned query.

🤖 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
`@components/graph-rag-testkit/src/main/java/com/orgmemory/graphrag/testkit/InMemoryAuthorizedQueryProjection.java`
around lines 304 - 333, Update the visible(Chunk) overload to require
chunk.evidence().projectionGeneration() to equal snapshot.generation(),
alongside its existing scope and organization checks. Ensure searchChunks,
rankChunks, and loadChunks continue using this visibility predicate so all
exposed chunks are pinned to the requested projection snapshot.

Comment on lines +66 to +67
private static final long GENERATION = 7;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🗄️ Data Integrity & Integration | 🔵 Trivial | ⚡ Quick win

No conformance coverage for stale/mismatched snapshot generation.

Every fixture is seeded under the same constant GENERATION (Line 66), so the suite never asserts that data from a different projection generation is excluded from results — for entities/relations (which the projection does filter by generation) or for chunks (which currently don't get filtered by generation at all; see companion comment on InMemoryAuthorizedQueryProjection.java). Adding a fixture seeded at GENERATION - 1 alongside the existing data, with an assertion that it never appears in references/context for a snapshot pinned to GENERATION, would directly validate the snapshot-pinning guarantee this PR is meant to provide.

Also applies to: 287-342

🤖 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
`@components/graph-rag-testkit/src/test/java/com/orgmemory/graphrag/testkit/LightRagQueryRuntimeConformanceTests.java`
around lines 66 - 67, Add conformance fixtures in
LightRagQueryRuntimeConformanceTests using GENERATION - 1 alongside the existing
GENERATION data, covering stale entities/relations and chunks. For a snapshot
pinned to GENERATION, assert the stale fixture is absent from both returned
references and context, validating generation filtering across all projected
data types.

Comment on lines +43 to +46
ChatOptions.builder()
.model(modelId)
.temperature(0.0)
.build()));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C2 'ChatOptions\.builder\(\)|getOptions\(\)\.mutate\(\)' \
  integrations/graph-rag-spring-ai/src

fd -HI 'libs.versions.toml|build.gradle|build.gradle.kts|settings.gradle|settings.gradle.kts' . \
  -x rg -n 'spring-ai|springAi' {}

Repository: kl3inIT/OrgMemory

Length of output: 5324


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Locate Spring AI provider model configuration files =="
rg -n -i "spring\.ai|chatmodel|model-|temperature|seed|max-tokens|frequency|presence|top|stop|tools" \
  -g 'application*.yml' -g 'application*.yaml' -g 'application*.properties' -g 'application*.conf' -g '*.java' .

echo
echo "== Inspect candidate Spring AI model interfaces/classes around getOptions and call =="
for f in \
  integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java \
  integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java \
  integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiDescriptionSummaryModel.java \
  integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiExtractionModel.java \
  integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiMultimodalAnalyzer.java
do
  echo "--- $f"
  sed -n '1,110p' "$f"
done

echo
echo "== Check dependency metadata for Spring AI 2.0.0 provider config classes =="
fd -HI 'pom.xml|build.gradle.kts|build.gradle|settings.gradle|libs.versions.toml|dependency-reduced-pom.xml' . | while read -r f; do
  echo "--- $f"
  rg -n 'spring-ai|gradle-plugin|java|plugins|org' "$f" | head -n 120
done

Repository: kl3inIT/OrgMemory

Length of output: 50374


🌐 Web query:

Spring AI 2.0.0 Prompt options model startup options override ChatOptions builder mutate getOptions documentation

💡 Result:

In Spring AI 2.0.0, ChatOptions are strictly immutable [1]. To modify existing options, you must use the mutate method, which returns a new builder initialized with the current values [2][3]. Key concepts and usage for Spring AI 2.0.0: 1. Mutating Options: Because options are immutable, the copy and fromOptions methods have been removed [1]. To create a modified version of an existing options instance, use the mutate method [2][1]: // Example of mutating options ChatOptions newOptions = originalOptions.mutate.temperature(0.7).model("gpt-4o").build; 2. ChatClient Options Configuration: The ChatClient's.options and.defaultOptions methods now require a ChatOptions.Builder (or a provider-specific subtype) rather than a fully built ChatOptions instance [1][4]. This builder is merged with the model's default options at request time, ensuring that only the fields you explicitly set will override the defaults [1][4]. 3. Merging Options: The ChatOptions.Builder provides a combineWith(ChatOptions.Builder other) method, which allows you to mutate a builder by taking non-null values from another builder while retaining existing values [5]. 4. Important Migration Note: Configuration property names for model options have changed; the.options prefix has been removed (e.g., spring.ai.openai.embedding.options.model is now spring.ai.openai.embedding.model) [4]. Additionally, default values for these options have been moved into the options constructors [4].

Citations:


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== Application Spring AI model configs =="
sed -n '35,95p' apps/worker/src/main/resources/application.yml
sed -n '65,95p' apps/api/src/main/resources/application.yml

echo
echo "== ChatModelPort definition =="
sed -n '1,80p' core/src/main/java/com/orgmemory/core/ai/ChatModelPort.java

echo
echo "== OpenAI model provider implementation =="
fd -HI 'OpenAiCompatibleChatModelProvider.java|Open*Chat*Model*.java' . -x sh -c 'echo "--- $1"; sed -n "1,220p" "$1"' sh {}

Repository: kl3inIT/OrgMemory

Length of output: 6972


🌐 Web query:

Spring AI 2.0.0 ChatModel defaultOptions Prompt options merge getOptions mutate non-null Prompt options override

💡 Result:

In Spring AI 2.0.0, the approach to handling ChatOptions depends on whether you are using the low-level ChatModel interface or the high-level ChatClient abstraction [1][2]. ChatModel Level Behavior: The ChatModel interface does not perform any merging of options [1][3]. The behavior is strictly as follows [2][3]: - If the ChatOptions provided in the Prompt is non-null, it is used exactly as-is, fully overriding the model's default options [1][3]. - If the ChatOptions provided in the Prompt is null, the model's own default options are used instead [1][3]. No partial merging or mutation occurs at the ChatModel level; you must provide a fully constructed instance of the concrete ChatOptions type required by the model (e.g., AnthropicChatOptions) if you wish to define custom settings [1][4]. ChatClient Level Behavior: In contrast, the ChatClient abstraction supports merging options [2][5]. When using ChatClient, you provide a ChatOptions.Builder (or a provider-specific subtype) via methods like.options [1][6][4]. This builder is merged with the model’s default options before the request is executed, allowing for an incremental, delta-based override where only the fields you explicitly set in the builder are applied [1][4]. Key Summary of Mechanisms: - Immutability: ChatOptions classes are strictly immutable [4]. - Mutation: The mutate method on a ChatOptions instance returns a new ChatOptions.Builder, which allows you to initialize a new builder based on existing values [7][8]. - Merging: Merging is a feature of the ChatClient and its builder system (e.g., via methods designed for incremental updates), not the ChatModel call [2][5]. - DefaultOptions: ChatModel.getDefaultOptions is deprecated in favor of ChatModel.getOptions, which retrieves the model's current configured defaults [1].

Citations:


Preserve provider options when overriding model options through Prompt.

With Spring AI 2.0.0 ChatModel, a non-null Prompt options value is used exactly as-is, replacing the model’s configured defaults rather than being merged. Since this path is constructed with OpenAI-specific defaults (apiKey, baseUrl, timeout, model), derive from chatModel.getOptions().mutate() and only override the fields that are intentionally supplied here.

Apply the same change to the comparable sites in SpringAiDescriptionSummaryModel.java, SpringAiExtractionModel.java, and SpringAiMultimodalAnalyzer.java.

Proposed direction
- ChatOptions.builder()
+ chatModel.getOptions().mutate()
📍 Affects 2 files
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java#L43-L46 (this comment)
  • integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiQueryAnswerModel.java#L68-L70
🤖 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
`@integrations/graph-rag-spring-ai/src/main/java/com/orgmemory/integrations/graphrag/springai/SpringAiKeywordPlanningModel.java`
around lines 43 - 46, Update the Prompt ChatOptions construction in
SpringAiKeywordPlanningModel.java (lines 43-46) and the comparable construction
in SpringAiQueryAnswerModel.java (lines 68-70) to derive from
chatModel.getOptions().mutate(), overriding only the intended model and
temperature values while preserving configured provider options such as apiKey,
baseUrl, and timeout.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant