Source lives in
services/orchestrator/src/react_agent/. Code-reference pages exist for every module mentioned below; links are provided inline.1. Mental Model: A Framework Is Data, Not Code
Adding a framework is intentionally mostly declarative. The pipeline logic does not care whether it is translating EF Core or some new ORM — it reads framework-specific behaviour from:- Enums + lookup tables in
constants.py(what the framework is, what language it compiles to, which files describe it). - Context files in
context/snippets/andcontext/mappings/(the ground-truth config, harness skeletons, and DB mappings — see Context Engineering). - Few-shot examples + harness rules in
prompts.py.
2. Adding a New Framework — Step by Step
Suppose you are adding a new source framework. The same steps apply to a target (swapSourceFramework for TargetFramework, and add Java-side rather than .NET-side context).
Step 1 — Register the enum and lookup tables
Inreact_agent/constants.py:
Also add it to
DotnetFramework or JavaFramework so the validation router (prep_query_validation in graph.py) sends it to the correct sandbox.
Step 2 — Drop in the context files
Add toservices/orchestrator/src/context/snippets/:
- A project config (
linq2db-sandbox.csproj) pinning the exact dependency versions — this is injected into the prompt and used to compile the sandbox, so they can never drift. - A schema validation entrypoint (
LinqToDbSchemaValidationEntrypoint.cs) — a runnable program that loads the schema and fetches one row per entity. - A query validation entrypoint (
LinqToDbQueryEntrypoint.cs) — a runnable harness that executes the query and serialisescount/firstSample/lastSampleas JSON, matching the existing entrypoints’ output shape so the DeepDiff equivalence check compares like-for-like.
context/mappings/ and wire it into get_database_mapping_json() in utils.py.
Step 3 — Teach the prompts
Inreact_agent/prompts.py, add to the translation prompt:
- A few-shot example showing a representative source→target translation for the new framework.
- A harness rule describing the entrypoint signature and return type (mirror the existing “Source framework harness rules” / “Target framework harness rules” blocks — e.g. “For LINQ to DB: validation harness returns
IQueryable<T>. Entrypoint signature:Build(DataConnection db, bool ascending).”).
build_system_prompt() once Step 1 and Step 2 are done — you only hand-write the example and the rule.
Step 4 — New language? Add a sandbox + validator
If the framework compiles to a language UOM does not yet support (i.e. not C# or Java), you also need:- A new value in
LanguageTypeandSandboxType(constants.py) plus a Daytona sandbox image (see Sandbox Environment). - A new validator tool alongside
dotnet_validator.py/java_validator.py, and register it in theToolNodes ingraph.py.
validate_dotnet_code tool handles it.
Step 5 — Surface it in the frontend
Add the framework to the UI’s framework enums and, optionally, a new suggestion card. See the Frontend Components reference.Checklist
1
constants.py
Enum + every lookup dict + Source/Target/Dotnet/Java set.
2
context/snippets/
Config file + schema entrypoint + query entrypoint (matching JSON shape).
3
context/mappings/
New DB mapping (only if a new database).
4
prompts.py
Few-shot example + harness rule.
5
validator + sandbox
Only if a new compile language.
6
frontend
Enum + optional suggestion card.
3. Extending the LangGraph Backend
To add behaviour to the pipeline itself (a new node, tool, or routing rule):- New node — write an
async def my_node(state, config, runtime)ingraph.py, return a state-update dict or aCommand, thenbuilder.add_node(...)and wire edges withbuilder.add_edge/builder.add_conditional_edges. Follow the existing node docstring style. - New state field — add it to the appropriate dataclass in
state.py(InputState,OutputState, or internalState). Use thetranslation_messageschannel, notmessages, for noisy validation chatter — see State & Context. - New tool — add a
@tool-decorated function undercustom_tools/, register it in aToolNode, and (if the model should call it) inTOOLSintools.py. - New routing rule — write a function returning a
Literal[...]of node names and attach withadd_conditional_edges.
temperature=0 and keep retry budgets bounded (MAX_*_LOOPS) so the determinism guarantees described in Design Decisions still hold.
4. Local Development & Conventions
- Boot the stack and the LangGraph dev server per Getting Started. Use
make record_requeststo mock LLM calls while iterating. - Lint/format with the project’s configured Ruff setup (
maketargets inservices/orchestrator/Makefile). - Verify changes with the test suite under
services/orchestrator/tests/. - Confirm new traces look right in LangSmith / Logfire.
5. Related Reading
Architecture
The state machine you are extending.
Context Engineering
How the context files you add are used.
Prompt Engineering
How the prompt is assembled from those files.
Validators & Equivalence
Why your harness output shape must match.