# Invoke tools for your AI agent

Agent Auth supports three approaches to tool calling: execute tools directly with explicit parameters, customize tool behavior with pre- and post-modifiers, or let an LLM select and invoke tools automatically based on user input.

## Direct tool execution

Using Scalekit SDK, you can execute any action on behalf of a user using the following parameters:

- user context
- `tool_name`
- `tool_input_parameters`

```python
# Fetch recent emails
tool_response = actions.execute_tool(
    # tool input parameters
    tool_input={
        'query': 'is:unread',
        'max_results': 5
    },
    # tool name to execute
    tool_name='gmail_fetch_mails',
    # connected_account gives the user context
    connected_account_id=connected_account.id,
)

print(f'Recent emails: {tool_response.result}')
```

```typescript
// Fetch recent emails
const toolResponse = await actions.executeTool({
  // tool name to execute
  toolName: 'gmail_fetch_mails',
  // connectedAccountId from a prior getOrCreateConnectedAccount call
  connectedAccountId: 'your_connected_account_id',
  // tool input parameters
  toolInput: {
    query: 'is:unread',
    max_results: 5,
  },
});

console.log('Recent emails:', toolResponse.result);
```

## Customize with modifiers

Tool modifiers intercept and modify tool inputs and outputs using decorators.

- **Pre-modifiers**: Modify tool inputs before execution
- **Post-modifiers**: Modify tool outputs after execution
**Common uses:** - Reduce response size to prevent LLM context overloading
  - Filter emails to unread only
  - Add consistent parameters
  - Transform data formats

### Pre-modifiers

Pre-modifiers modify tool inputs before execution to enforce consistent filters, add security constraints, override LLM decisions with required behavior, or set default configurations.

```python title="Example: Gmail unread filter"
from scalekit.actions.models.tool_input_output import ToolInput

# For example, we can modify the query to only fetch unread emails
# regardless of what the user asks for or what the LLM determines.
@actions.pre_modifier(tool_names=["gmail_fetch_mails"])
def gmail_pre_modifier(tool_input: ToolInput):
    tool_input['query'] = 'is:unread'
    return tool_input
```

This modifier:
- Intercepts all calls to `gmail_fetch_mails`
- Forces the query to always search for unread emails only
- Ensures consistent behavior regardless of user input or LLM interpretation

**Multiple tools example**

```python
@actions.pre_modifier(tool_names=["gmail_fetch_mails", "gmail_search_emails"])
def email_security_modifier(tool_input: ToolInput):
    # Add security constraints to all email operations
    tool_input['include_spam'] = False
    tool_input['max_results'] = min(tool_input.get('max_results', 10), 50)
    return tool_input
```

### Post-modifiers

Post-modifiers modify tool outputs after execution to reduce token usage, transform formats for LLM consumption, extract specific data, or standardize output structure.
**Response format:** Post-modifiers must always return a dictionary with a `"response"` key: `{"response": your_data}`

```python title="Example: Gmail response filtering"
from scalekit.actions.models.tool_input_output import ToolOutput

# Sometimes, the tool output needs to be modified in a deterministic way after the tool is executed.
# For example, we can modify the output to only return the first email snippet regardless of what the tool returns.
# This is an effective way to reduce the amount of data that is returned to the LLM to save on tokens.
@actions.post_modifier(tool_names=["gmail_fetch_mails"])
def gmail_post_modifier(output: ToolOutput):
    # Only return the first email snippet
    # Should return a dict
    # Response should be a dict with a key 'response'
    for snippet in output['messages']:
        print(f"Email snippet: {snippet['snippet']}")
    return {"response": output['messages'][0]['snippet']}
```

This modifier:
- Processes the response from `gmail_fetch_mails`
- Extracts only the first email snippet instead of returning all emails
- Reduces token usage by sending minimal data to the LLM

## Agentic tool calling

Let an LLM determine which tool to call and with what parameters based on user input. This quickstart uses LangChain to build an agent that authenticates a user with Gmail and fetches their last 5 unread emails.

**Prerequisites**: Scalekit API credentials (Client ID and Client Secret) and a Python development environment.

1. ### Set up your environment

   Install the Scalekit Python SDK and initialize the client with your API credentials:

   <p>
     ```sh showLineNumbers=false frame="none"
     pip install scalekit-sdk-python langchain
     ```
   </p>
   <p>
     ```python showLineNumbers=false frame="none"
     import scalekit.client
     import os

     scalekit_client = scalekit.client.ScalekitClient(
         client_id=os.getenv("SCALEKIT_CLIENT_ID"),
         client_secret=os.getenv("SCALEKIT_CLIENT_SECRET"),
         env_url=os.getenv("SCALEKIT_ENV_URL"),
     )
     actions = scalekit_client.actions

     ```
   </p>

2. ### Create a connected account

   Authorize a user to access their Gmail account by creating a connected account. This represents the user's connection to their Gmail account:

   ```python
   # Create a connected account for user if it doesn't exist already
   response = actions.get_or_create_connected_account(
               connection_name="gmail",
               identifier="user_123"
           )
   connected_account = response.connected_account

   print(f'Connected account created: {connected_account.id}')
   ```

3. ### Authenticate the user

   For Scalekit to execute tools on behalf of the user, the user must grant authorization to access their Gmail account. Scalekit automatically handles the entire OAuth workflow, including token refresh.

   ```python
   # If the user hasn't yet authorized the gmail connection or if the user's access token is expired,
   # generate a magic link and redirect the user to this link so that the user can complete authorization
   if(connected_account.status != "ACTIVE"):
         link_response = actions.get_authorization_link(
             connection_name="gmail",
             identifier="user_123"
         )
         print(f"🔗click on the link to authorize gmail", link_response.link)
         input(f"⎆ Press Enter after authorizing gmail...")

   # In a real app, redirect the user to this URL so that the user can complete the authentication process for their gmail account
   ```

4. ### Build a LangChain agent

   Build a simple agent that fetches the last 5 unread emails from the user's inbox and generates a summary.

   ```python
   from langchain_core.prompts import SystemMessagePromptTemplate, MessagesPlaceholder, HumanMessagePromptTemplate,PromptTemplate, ChatPromptTemplate

   # use scalekit SDK to fetch all GMAIL tools in langchain format
   tools =  actions.langchain.get_tools(
       identifier=identifier,
        providers = ["GMAIL"], # all tools for provider used by default
        page_size=100
   )

   prompt = ChatPromptTemplate.from_messages([
       SystemMessagePromptTemplate(prompt=PromptTemplate(input_variables=[], template="You are a helpful assistant. Use tools if needed")),
       MessagesPlaceholder(variable_name="chat_history", optional=True),
       HumanMessagePromptTemplate(prompt=PromptTemplate(input_variables=["input"], template="{input}")),
       MessagesPlaceholder(variable_name="agent_scratchpad")
   ])

   llm = ChatOpenAI(model="gpt-4o")
   agent = create_openai_tools_agent(llm, tools, prompt)
   agent_executor = AgentExecutor(agent=agent, tools=tools,verbose=True)
   result = agent_executor.invoke({"input":"fetch my last 5 unread emails and summarize it"}
   )
   ```

## Next steps

For more detailed framework-specific implementations, explore the AI framework guides:

<LinkCard title="LangChain Framework" icon="star" href="/agent-auth/frameworks/langchain">
    Build agents using LangChain with advanced tool calling and workflow capabilities.
  </LinkCard>
  <LinkCard title="Google ADK Framework" icon="star" href="/agent-auth/frameworks/google-adk">
    Create agents using Google ADK with Gemini models and native Google integration.
  </LinkCard>
  <LinkCard title="OpenClaw" icon="star" href="/agent-auth/openclaw">
    Connect OpenClaw agents to third-party services through Scalekit.
  </LinkCard>