Feature/v2 langgraph core - #16
Merged
Merged
Conversation
…s to interfaces ResearchContext (query, documents, answer) is the LangGraph state per ADR-005 — a dataclass, not a Pydantic model, since LangGraph accepts TypedDict/dataclass/BaseModel equally and a dataclass skips re-validating on every node's partial update. RetrieveFn and AnswerFn move out of rag_service.py and telegram_bot.py into domain/interfaces.py: the new research_agent/nodes.py needs RetrieveFn too, and importing it from a service it has no other relation to would violate the dependency direction. They now live as contract vocabulary alongside the Protocols, per ADR-004.
make_retrieve_node and make_generate_node are (ResearchContext) -> dict functions with zero LangGraph imports, per ADR-005. A node can't take extra parameters, so RetrieveFn/LLMProvider are injected via a factory closure instead of module globals or stuffing them into the state — same pattern as AnswerFn, RetrieveFn and with_logging elsewhere in the project. Tested by passing a fabricated ResearchContext and asserting the returned partial-state dict, with no graph execution needed.
Documents T18 kickoff: the LangGraph node/state/factory reasoning behind today's implementation (ADR-005), plus the mypy stub-limitation finding in StateGraph.add_node discovered while wiring the graph.
answer_v2_graph invokes build_research_graph(...).ainvoke(ResearchContext), replacing answer_query as the function wired to TelegramBot. No changes to telegram_bot.py — the bot still only depends on AnswerFn. answer_v1_pipeline (the old function-call pipeline) stays in the script, unwired, so T24 can run it side by side with answer_v2_graph over the same queries. Closes the remaining T18 acceptance criteria: bot answers through the graph, telegram_bot.py untouched, and a new test invokes the compiled graph end to end with a mocked retriever and LLM.
run_telegram_bot.py and run_research_graph.py had the same embedder/Chroma/ BM25/LLM construction block duplicated. Yesterday it stayed duplicated on purpose — with a single consumer the abstraction was premature. With two, it's justified: build_dependencies() in scripts/_wiring.py now returns what both need. Also centralizes the pysqlite3 sys.modules patch, previously copied across four scripts (run_telegram_bot.py, run_research_graph.py, eval_retrieval.py, ingest_documents.py) — importing _wiring applies it. eval_retrieval.py and ingest_documents.py only pick up the patch, not build_dependencies(): their retriever wiring differs enough (per-strategy access, or no retrieval at all) that forcing them onto the shared factory wasn't worth it.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.