Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
6ec6f56
feat: Add RSA prompts and RSAAggregationTask class
Apr 2, 2026
ff57eff
feat: Add RSA orchestration logic to ai_based_retrosynthesis
Apr 2, 2026
6d23afa
feat: Add RSA fields to FlaskRunSettings interface
Apr 2, 2026
85e1563
feat: Add RSA UI controls to App.tsx
Apr 2, 2026
2046f34
Fix AttributeError by initializing retro_synth_context in __init__
Apr 2, 2026
181203d
Update ChARGe submodule to restore OpenAIResponsesClient
Apr 2, 2026
0d1f6f6
Update ChARGe submodule with OpenAIResponsesClient parameter fix
Apr 2, 2026
287151a
Fix session reset between retries and add temperature=0.8 for RSA pro…
Apr 2, 2026
892cde1
Remove temperature parameter for gpt-5.2 compatibility
Apr 2, 2026
f7f9c2e
Add comprehensive RSA execution logging to capture prompts and outputs
Apr 2, 2026
276feeb
Fix RSA settings propagation to backend
Apr 2, 2026
b8809a4
Add intelligent routing for AI-based vs template-based retrosynthesis
Apr 2, 2026
58834b7
Make template-based retrosynthesis optional when config missing
Apr 2, 2026
dd360ca
Add dynamic WebSocket URL detection with HTTPS support
Apr 2, 2026
af1608f
Reduce RAG database queries from N(T+1) to 1 - Query once before prop…
Apr 2, 2026
0cd6ac8
Fix RAG mode to use user_prompt_with_rag in proposals
Apr 2, 2026
e901a0d
Filter query_reaction_database tool in RSA modes
Apr 2, 2026
eb00bb7
Add UI display for RAG database query results
Apr 2, 2026
1830ed1
Extract generic RSA algorithm into reusable helper function
Apr 3, 2026
5f9fcdd
Add parallel proposal generation and fix empty reactants validation
Apr 3, 2026
e97d7a1
Parallelize aggregation stages with proper RSA barriers
Apr 3, 2026
1381b77
Remove egg-info build artifacts and update gitignore
Apr 3, 2026
2a76705
Separate AI-based flag from RSA flag for explicit retrosynthesis appr…
Apr 3, 2026
0c2960b
Add comment about use_ai_based field inheritance in FlaskRunSettings
Apr 3, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,10 @@ vite.config.ts.timestamp-*
.venv/
venv/
__pycache__/
*.egg-info/
*.egg
dist/
build/

# Visual Studio Code
.vscode/
Expand Down
1 change: 1 addition & 0 deletions ChARGe
Submodule ChARGe added at 6bcfc1
1 change: 1 addition & 0 deletions charge_backend/backend_helper_funcs.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ def json(self):
@dataclass
class FlaskRunSettings(RunSettings):
molecule_name_format: MolNameFormat = Field(alias="moleculeName", default="brand")
# Inherit use_ai_based from RunSettings (defined in LC-Conductor)


@dataclass(frozen=True)
Expand Down
77 changes: 69 additions & 8 deletions charge_backend/backend_manager.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ def __init__(
self.websocket = task_manager.websocket
self.builtin_tool_definitions = builtin_tool_definitions or []
self.task_manager.available_builtin_tool_ids = None
self.retro_synth_context = None

def _selected_mcp_tools(self) -> list[str]:
if self.task_manager.available_tools is None:
Expand Down Expand Up @@ -225,14 +226,74 @@ async def _handle_optimization(

async def _handle_retrosynthesis(self, data: dict) -> None:
"""Handle retrosynthesis problem type."""
run_func = partial(
template_based_retrosynthesis,
data["smiles"],
self.args.config_file,
self.get_retro_synth_context(),
self.task_manager.websocket,
self.run_settings,
)
# Check if AI-based retrosynthesis is requested
# use_ai_based flag controls AI vs template approach
# If no config exists, fall back to AI-based
use_ai_based = self.run_settings.use_ai_based or not os.path.exists(self.args.config_file)

if use_ai_based:
# Use AI-based retrosynthesis (supports both standard and RSA modes)
# Create root node like template_based_retrosynthesis does
from backend_helper_funcs import Node
from charge_backend.moleculedb.molecule_naming import smiles_to_html
from charge_backend.moleculedb.purchasable import is_purchasable

context = self.get_retro_synth_context()
context.reset() # Clear context

start_smiles = data["smiles"]
mol_sources = is_purchasable(start_smiles)
if mol_sources:
purchasable_str = f"Yes (via {', '.join(mol_sources)})"
else:
purchasable_str = "No"

root = Node(
id="node_0",
smiles=start_smiles,
label=smiles_to_html(start_smiles, self.run_settings.molecule_name_format),
hoverInfo=f"""# Root molecule
**SMILES:** {start_smiles}

**Purchasable**? {purchasable_str}""",
level=0,
parentId=None,
cost=None,
bandgap=None,
yield_=None,
purchasable=(len(mol_sources) > 0),
highlight="yellow",
x=100,
y=100,
)

await context.add_node(root, websocket=self.task_manager.websocket)
root_node_id = root.id

run_func = partial(
ai_based_retrosynthesis,
root_node_id,
context,
data.get("query", None),
None, # Unconstrained
self.task_manager.websocket,
self.experiment,
self.args.config_file,
self.run_settings,
self._selected_mcp_tools(),
self._selected_builtin_tools(),
self.log_progress,
)
else:
# Use template-based retrosynthesis
run_func = partial(
template_based_retrosynthesis,
data["smiles"],
self.args.config_file,
self.get_retro_synth_context(),
self.task_manager.websocket,
self.run_settings,
)

await self.task_manager.run_task(run_func())

Expand Down
11 changes: 10 additions & 1 deletion charge_backend/charge_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -165,12 +165,21 @@ async def root(request: Request):
with open(os.path.join(DIST_PATH, "index.html"), "r") as fp:
html = fp.read()

# Use dynamic WebSocket URL based on request host
ws_server = os.getenv("WS_SERVER")
if not ws_server:
# Auto-detect from request host and protocol
host = request.headers.get("host", f"localhost:{args.port}")
# Use wss:// for HTTPS, ws:// for HTTP
scheme = "wss" if request.url.scheme == "https" else "ws"
ws_server = f"{scheme}://{host}/ws"

html = html.replace(
"<!-- APP CONFIG -->",
f"""
<script>
window.APP_CONFIG = {{
WS_SERVER: '{os.getenv("WS_SERVER", "ws://localhost:8001/ws")}',
WS_SERVER: '{ws_server}',
VERSION: '{os.getenv("SERVER_VERSION", "")}'
}};
</script>""",
Expand Down
Loading