Modifiers: control what goes in and comes out
Modifiers are functions Composio applies around direct tool calls: before_execute changes arguments, after_execute changes results.
from composio import after_execute, before_execute
@before_execute(tools=["GITHUB_CREATE_AN_ISSUE"])
def label_agent_issues(tool, toolkit, params):
params["arguments"].setdefault("labels", []).append("created-by-agent")
return params
@after_execute(toolkits=["gmail"])
def keep_only_subjects(tool, toolkit, response):
messages = response["data"].get("messages", [])
response["data"] = {"subjects": [m.get("subject") for m in messages]}
return responseparams = {"arguments": {"title": "Refund failed for A-1002"}}
print(label_agent_issues.apply("github", "GITHUB_CREATE_AN_ISSUE", params, "before_execute"))
print(label_agent_issues.apply("slack", "SLACK_SEND_MESSAGE", {"arguments": {"text": "hi"}}, "before_execute"))The decorator returns a Modifier, and apply is the method the SDK calls around every direct execution, with the toolkit slug, the tool slug, the data and the modifier type. Listed tools or toolkits limit where it runs: the GitHub issue got a label, the Slack message came back unchanged.
response = {"successful": True, "error": None, "data": {"messages": [{"subject": "Invoice", "body": "card 4111 1111 1111 1111"}]}}
print(keep_only_subjects.apply("gmail", "GMAIL_FETCH_EMAILS", response, "after_execute"))
print(keep_only_subjects.apply("GMAIL", "GMAIL_FETCH_EMAILS", response, "after_execute") is response)after_execute runs on the result before your code, and so the model, sees it. This one keeps only subjects, so an email body with a card number never enters the prompt, the model's provider or your logs. The last line shows that matching is exact: "GMAIL" does not match "gmail", so the result came back untouched, the same object. Use slugs exactly as the SDK reports them, and print one real result before you rely on its shape; the messages and subject keys here are an example.
tools = composio.tools.get(user_id, tools=["GMAIL_FETCH_EMAILS"])
results = composio.provider.handle_tool_calls(user_id=user_id, response=response, modifiers=[keep_only_subjects])Why modifiers matter for a deployment
- Force values the model must not choose, such as a label, a repository or a sender.
- Remove data the model does not need before it reaches a third-party model provider.
- Change tool schemas the model sees with
schema_modifier, passed tocomposio.tools.get.
- Write a
before_executemodifier that refuses emails to addresses outside the customer's domain by raising. - Apply
keep_only_subjectswith the modifier typebefore_execute. - Read the argument types of
schema_modifierincomposio/core/models/_modifiers.py.
Little by little, you're building something great.