Skip to content

Commit e84f272

Browse files
authored
Merge pull request #85 from cBioPortal/feat/clear-tools
feat(agent): clear_color_by and clear_render_controls tools
2 parents 7581f0f + 9dda514 commit e84f272

7 files changed

Lines changed: 129 additions & 13 deletions

File tree

packages/cell-explorer-agent/schema/app_config.schema.json

Lines changed: 46 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,38 @@
1212
"type": "string"
1313
},
1414
"colorBy": {
15-
"type": "string",
16-
"enum": [
17-
"gene",
18-
"category"
15+
"anyOf": [
16+
{
17+
"type": "string",
18+
"enum": [
19+
"gene",
20+
"category"
21+
]
22+
},
23+
{
24+
"type": "null"
25+
}
1926
]
2027
},
2128
"gene": {
22-
"type": "string"
29+
"anyOf": [
30+
{
31+
"type": "string"
32+
},
33+
{
34+
"type": "null"
35+
}
36+
]
2337
},
2438
"category": {
25-
"type": "string"
39+
"anyOf": [
40+
{
41+
"type": "string"
42+
},
43+
{
44+
"type": "null"
45+
}
46+
]
2647
},
2748
"highlightedCategories": {
2849
"type": "array",
@@ -109,13 +130,27 @@
109130
"additionalProperties": false
110131
},
111132
"pointSize": {
112-
"type": "number",
113-
"exclusiveMinimum": 0
133+
"anyOf": [
134+
{
135+
"type": "number",
136+
"exclusiveMinimum": 0
137+
},
138+
{
139+
"type": "null"
140+
}
141+
]
114142
},
115143
"opacity": {
116-
"type": "number",
117-
"minimum": 0,
118-
"maximum": 1
144+
"anyOf": [
145+
{
146+
"type": "number",
147+
"minimum": 0,
148+
"maximum": 1
149+
},
150+
{
151+
"type": "null"
152+
}
153+
]
119154
},
120155
"summaryObsColumns": {
121156
"type": "array",

packages/cell-explorer-agent/src/cell_explorer_agent/prompt/system.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,11 @@ def build_system_prompt(ctx: DatasetContext) -> str:
6565
"like 'in context', 'don't hide the rest', 'fade the others'), call "
6666
"set_selection_display_mode('dim') after the filter."
6767
)
68+
lines.append(
69+
" - For 'stop coloring' / 'reset color' / 'undo my rendering changes' "
70+
"use clear_color_by or clear_render_controls. These reset to defaults "
71+
"without affecting filters."
72+
)
6873
lines.append(
6974
" - Do not pan/zoom (set_viewport) or change rendering (set_render_controls) "
7075
"unless the user explicitly asks. The user controls the camera and visual style; "

packages/cell-explorer-agent/src/cell_explorer_agent/tools/__init__.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
from cell_explorer_agent.tools.data.schema import get_dataset_schema_tool
1515
from cell_explorer_agent.tools.registry import Tool, ToolCatalog, ToolKind
1616
from cell_explorer_agent.tools.ui_action.color import (
17+
clear_color_by_tool,
1718
set_color_by_category_tool,
1819
set_color_by_gene_tool,
1920
)
@@ -26,7 +27,10 @@
2627
filter_by_gene_expression_tool,
2728
)
2829
from cell_explorer_agent.tools.ui_action.gene_label_column import set_gene_label_column_tool
29-
from cell_explorer_agent.tools.ui_action.render import set_render_controls_tool
30+
from cell_explorer_agent.tools.ui_action.render import (
31+
clear_render_controls_tool,
32+
set_render_controls_tool,
33+
)
3034
from cell_explorer_agent.tools.ui_action.selection_display_mode import (
3135
set_selection_display_mode_tool,
3236
)
@@ -56,6 +60,7 @@ def build_v1_catalog(z: ZarrAccess, *, config: AgentConfig) -> ToolCatalog:
5660
cat.register(set_embedding_tool(z))
5761
cat.register(set_color_by_gene_tool(z))
5862
cat.register(set_color_by_category_tool(z))
63+
cat.register(clear_color_by_tool())
5964
cat.register(filter_by_ids_tool(z, filter_ids_max=config.filter_ids_max))
6065
cat.register(filter_by_gene_expression_tool(z))
6166
cat.register(set_selection_display_mode_tool())
@@ -70,6 +75,7 @@ def build_v1_catalog(z: ZarrAccess, *, config: AgentConfig) -> ToolCatalog:
7075
cat.register(set_summary_context_tool())
7176
cat.register(set_gene_label_column_tool(z))
7277
cat.register(set_render_controls_tool())
78+
cat.register(clear_render_controls_tool())
7379

7480
return cat
7581

packages/cell-explorer-agent/src/cell_explorer_agent/tools/ui_action/color.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,31 @@ async def run(gene: str) -> dict[str, Any]:
3030
)
3131

3232

33+
def clear_color_by_tool() -> Tool:
34+
async def run() -> dict[str, Any]:
35+
# `colorBy: null` is the frontend's reset sentinel: applyConfig calls
36+
# clearGene + clearObsColumn, and the canvas falls back to default gray.
37+
payload: dict[str, Any] = {"colorBy": None}
38+
validate_partial(payload)
39+
return {"payload": payload}
40+
41+
return Tool(
42+
name="clear_color_by",
43+
kind="ui_action",
44+
description=(
45+
"Reset the embedding coloring to the default (gray points). Use "
46+
"when the user says 'stop coloring' / 'clear the color' / 'reset "
47+
"color'. Does not affect filters or rendering controls."
48+
),
49+
args_schema={
50+
"type": "object",
51+
"properties": {},
52+
"additionalProperties": False,
53+
},
54+
func=run,
55+
)
56+
57+
3358
def set_color_by_category_tool(z: ZarrAccess) -> Tool:
3459
async def run(
3560
category: str,

packages/cell-explorer-agent/src/cell_explorer_agent/tools/ui_action/render.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,31 @@
66
from cell_explorer_agent.tools.registry import Tool
77

88

9+
def clear_render_controls_tool() -> Tool:
10+
async def run() -> dict[str, Any]:
11+
# `null` is the frontend's reset sentinel: applyConfig restores the
12+
# store defaults (0.5 / 0.5).
13+
payload: dict[str, Any] = {"pointSize": None, "opacity": None}
14+
validate_partial(payload)
15+
return {"payload": payload}
16+
17+
return Tool(
18+
name="clear_render_controls",
19+
kind="ui_action",
20+
description=(
21+
"Reset point_size and opacity to the frontend defaults (0.5 each). "
22+
"Use when the user says 'reset rendering' / 'undo my point size and "
23+
"opacity changes' / 'go back to default'."
24+
),
25+
args_schema={
26+
"type": "object",
27+
"properties": {},
28+
"additionalProperties": False,
29+
},
30+
func=run,
31+
)
32+
33+
934
def set_render_controls_tool() -> Tool:
1035
async def run(
1136
point_size: float | None = None,

packages/cell-explorer-agent/tests/test_tool_catalog_v1.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ async def test_v1_catalog_includes_all_tools(fake_zarr):
1818
"set_embedding",
1919
"set_color_by_gene",
2020
"set_color_by_category",
21+
"clear_color_by",
2122
"filter_by_ids",
2223
"filter_by_gene_expression",
2324
"set_selection_display_mode",
@@ -29,6 +30,7 @@ async def test_v1_catalog_includes_all_tools(fake_zarr):
2930
"set_summary_context",
3031
"set_gene_label_column",
3132
"set_render_controls",
33+
"clear_render_controls",
3234
}
3335

3436

packages/cell-explorer-agent/tests/test_tools_ui_action.py

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
from cell_explorer_agent.tools.ui_action.embedding import set_embedding_tool
22
from cell_explorer_agent.tools.ui_action.color import (
3+
clear_color_by_tool,
34
set_color_by_gene_tool,
45
set_color_by_category_tool,
56
)
@@ -17,7 +18,10 @@
1718
from cell_explorer_agent.tools.ui_action.viewport import set_viewport_tool
1819
from cell_explorer_agent.tools.ui_action.summary_context import set_summary_context_tool
1920
from cell_explorer_agent.tools.ui_action.gene_label_column import set_gene_label_column_tool
20-
from cell_explorer_agent.tools.ui_action.render import set_render_controls_tool
21+
from cell_explorer_agent.tools.ui_action.render import (
22+
clear_render_controls_tool,
23+
set_render_controls_tool,
24+
)
2125
from cell_explorer_agent.tools.ui_action.selection_display_mode import (
2226
set_selection_display_mode_tool,
2327
)
@@ -291,3 +295,17 @@ async def test_set_selection_display_mode_invalid_value():
291295
tool = set_selection_display_mode_tool()
292296
r = await tool.func(value="other")
293297
assert "error" in r
298+
299+
300+
async def test_clear_color_by_emits_null():
301+
tool = clear_color_by_tool()
302+
r = await tool.func()
303+
assert r == {"payload": {"colorBy": None}}
304+
assert tool.kind == "ui_action"
305+
306+
307+
async def test_clear_render_controls_emits_nulls():
308+
tool = clear_render_controls_tool()
309+
r = await tool.func()
310+
assert r == {"payload": {"pointSize": None, "opacity": None}}
311+
assert tool.kind == "ui_action"

0 commit comments

Comments
 (0)