Skip to content

Commit 32c2f40

Browse files
feat: create ToolGuidelines for better Agent orientation of when and how to use marimo tools, add guidelines to GetMarimoRules tool (#6793)
## 📝 Summary <!-- Provide a concise summary of what this pull request is addressing. If this PR fixes any issues, list them here by number (e.g., Fixes #123). --> This improves tool guidance for agents by adding structured guidelines that inform the agents not just what the tool is but when to and not to use it ++: <img width="954" height="290" alt="Screenshot 2025-10-15 at 3 55 22 PM" src="https://github.com/user-attachments/assets/4a08e443-0736-41aa-9b5a-c5d1369b4b78" /> this also improves the Agent consistently using the GetMarimoRules tool: <img width="332" height="538" alt="Screenshot 2025-10-15 at 4 23 28 PM" src="https://github.com/user-attachments/assets/1127999a-dbfc-4805-a7d0-7d3742c6f49c" /> ## 🔍 Description of Changes <!-- Detail the specific changes made in this pull request. Explain the problem addressed and how it was resolved. If applicable, provide before and after comparisons, screenshots, or any relevant details to help reviewers understand the changes easily. --> - Add `ToolGuidelines` to `types.py` - Integrate `ToolGuidelines` into `base.py` - Update `GetMarimoRules` class to improve usage ## 📋 Checklist - [x] I have read the [contributor guidelines](https://github.com/marimo-team/marimo/blob/main/CONTRIBUTING.md). - [ ] For large changes, or changes that affect the public API: this change was discussed or approved through an issue, on [Discord](https://marimo.io/discord?ref=pr), or the community [discussions](https://github.com/marimo-team/marimo/discussions) (Please provide a link if applicable). - [ ] I have added tests for the changes made. - [x] I have run the code and verified that it works as expected. --------- Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
1 parent f93081e commit 32c2f40

File tree

3 files changed

+60
-2
lines changed

3 files changed

+60
-2
lines changed

marimo/_ai/_tools/base.py

Lines changed: 39 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
)
1818

1919
from marimo import _loggers
20+
from marimo._ai._tools.types import ToolGuidelines
2021
from marimo._ai._tools.utils.exceptions import ToolExecutionError
2122
from marimo._config.config import CopilotMode
2223
from marimo._server.ai.tools.types import (
@@ -95,6 +96,7 @@ class ToolBase(Generic[ArgsT, OutT], ABC):
9596
# Override in subclass, or rely on fallbacks below
9697
name: str = ""
9798
description: str = ""
99+
guidelines: Optional[ToolGuidelines] = None
98100
Args: type[ArgsT]
99101
Output: type[OutT]
100102
context: ToolContext
@@ -127,7 +129,15 @@ def __init__(self, context: ToolContext) -> None:
127129

128130
# get description from class docstring
129131
if self.description == "":
130-
self.description = (self.__class__.__doc__ or "").strip()
132+
base_description = (self.__class__.__doc__ or "").strip()
133+
134+
# If guidelines exist, append them
135+
if self.guidelines is not None:
136+
self.description = self._format_with_guidelines(
137+
base_description, self.guidelines
138+
)
139+
else:
140+
self.description = base_description
131141

132142
async def __call__(self, args: ArgsT) -> OutT:
133143
"""
@@ -241,6 +251,34 @@ def _coerce_args(self, args: Any) -> ArgsT: # type: ignore[override]
241251
return args # type: ignore[return-value]
242252
return parse_raw(args, self.Args)
243253

254+
def _format_with_guidelines(
255+
self, description: str, guidelines: ToolGuidelines
256+
) -> str:
257+
"""Combine description with structured guidelines."""
258+
parts = [description] if description else []
259+
260+
if guidelines.when_to_use:
261+
parts.append("\n## When to use:")
262+
parts.extend(f"- {item}" for item in guidelines.when_to_use)
263+
264+
if guidelines.avoid_if:
265+
parts.append("\n## Avoid if:")
266+
parts.extend(f"- {item}" for item in guidelines.avoid_if)
267+
268+
if guidelines.prerequisites:
269+
parts.append("\n## Prerequisites:")
270+
parts.extend(f"- {item}" for item in guidelines.prerequisites)
271+
272+
if guidelines.side_effects:
273+
parts.append("\n## Side effects:")
274+
parts.extend(f"- {item}" for item in guidelines.side_effects)
275+
276+
if guidelines.additional_info:
277+
parts.append("\n## Additional info:")
278+
parts.append(guidelines.additional_info)
279+
280+
return "\n".join(parts)
281+
244282
# error defaults/hooks
245283
def _default_error_code(self) -> str:
246284
return "UNEXPECTED_ERROR"

marimo/_ai/_tools/tools/rules.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import marimo._utils.requests as requests
88
from marimo import _loggers
99
from marimo._ai._tools.base import ToolBase
10-
from marimo._ai._tools.types import EmptyArgs, SuccessResult
10+
from marimo._ai._tools.types import EmptyArgs, SuccessResult, ToolGuidelines
1111

1212
LOGGER = _loggers.marimo_logger()
1313

@@ -29,6 +29,15 @@ class GetMarimoRules(ToolBase[EmptyArgs, GetMarimoRulesOutput]):
2929
The content of the rules file.
3030
"""
3131

32+
guidelines = ToolGuidelines(
33+
when_to_use=[
34+
"Before using other marimo mcp tools, reading a marimo notebook, or writing to a notebook ALWAYS use this first to understand how marimo works",
35+
],
36+
avoid_if=[
37+
"The rules have already been retrieved recently, as they rarely change",
38+
],
39+
)
40+
3241
def handle(self, args: EmptyArgs) -> GetMarimoRulesOutput:
3342
del args
3443

marimo/_ai/_tools/types.py

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,14 @@ class SuccessResult:
2121
@dataclass
2222
class EmptyArgs:
2323
pass
24+
25+
26+
@dataclass
27+
class ToolGuidelines:
28+
"""Structured guidance for AI assistants on when and how to use a tool."""
29+
30+
when_to_use: Optional[list[str]] = None
31+
avoid_if: Optional[list[str]] = None
32+
prerequisites: Optional[list[str]] = None
33+
side_effects: Optional[list[str]] = None
34+
additional_info: Optional[str] = None

0 commit comments

Comments
 (0)