> ## Documentation Index
> Fetch the complete documentation index at: https://composio-27-feat-docs-revamp.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# 🛠️ How to modify Actions?

> Learn how to modify Tools & Actions to refine schemas, inputs, and outputs for optimal results.

## Refining Tool Schemas, Inputs, & Outputs

In many scenarios, the schemas, inputs, or outputs of tools may benefit from additional processing. This refinement step can significantly improve the quality and usability of your data. Here are three key use cases:

* **Modifying Schema**: Modify the tool schema like the description of the parameters or the default values. For example, if you're manually providing certain values in input (like project\_id), you can mark these fields as "not required" in the schema so the LLM knows it doesn't need to ask for them.
* **Modifying Inputs**: Add values as inputs to avoid specifying them in the prompt. e.g., passing `project_id` & `team_id` to the `LINEAR_CREATE_LINEAR_ISSUE` action.
* **Modifying Outputs**: Modify outputs to get the desired data. e.g., extracting `execution_id` & `issue_id` from the response of `LINEAR_CREATE_LINEAR_ISSUE` action. Doing this can help keep the LLM context clean.

Composio empowers you with the ability to define **custom functions** as schema modifiers, input modifiers, or output modifiers.

These can be applied at two levels:

1. **App-level**: Affects all actions within a specific tool.
2. **Action-level**: Tailored processing for individual actions.

<Tabs>
  <Tab title="Python">
    <Steps>
      <Step title="Install required libraries">
        ```bash Python
        pip install langchain langchain-openai composio-langchain
        ```
      </Step>

      <Step title="Import required libraries">
        ```python Python
        from langchain.agents import create_openai_functions_agent, AgentExecutor
        from langchain import hub
        from langchain_openai import ChatOpenAI
        from composio_langchain import ComposioToolSet, Action, App
        ```
      </Step>

      <Step title="Import Prompt template & Initialize ChatOpenAI & composio toolset client">
        ```python Python
        prompt = hub.pull("hwchase17/openai-functions-agent")

        llm = ChatOpenAI()
        composio_toolset = ComposioToolSet()
        ```
      </Step>

      <Step title="Define a Custom Function to Modify Schema">
        This function will be used to modify the schema of the `LINEAR_CREATE_LINEAR_ISSUE` action, we get rid of the parameters `project_id` and `team_id`, later in the program we will pass these values as inputs to the action manually. The technical term for this is **Action-level Schema Processing**.

        ```python Python
        def linear_schema_processor(schema: dict) -> dict:
            # This way the agent doesn't expect a project and team ID to run the action
            del schema['project_id']
            del schema['team_id']
            return schema
        ```
      </Step>

      <Step title="Define a Custom Function to Modify Input">
        This function will be used to modify the input data for the `LINEAR_CREATE_LINEAR_ISSUE` action. Here we have added the values for `project_id` and `team_id` parameters to the input data. By doing this, we can avoid specifying these values in the prompt and be sure that the agent uses the correct values. The technical term for this is **Action-level Pre-Processing**.

        ```python Python
        def linear_pre_processor(input_data: dict) -> dict:
            input_data['project_id'] = 'e708162b-9b1a-4901-ab93-0f0149f9d805'  
            input_data['team_id'] = '249ee4cc-7bbb-4ff1-adbe-d3ef2f3df94e'
            return input_data
        ```
      </Step>

      <Step title="Define a Custom Function to Modify Output">
        This function will be used to modify the output data for the `LINEAR_CREATE_LINEAR_ISSUE` action. Here we are modifying the output to just return the action execution status `successful` & the `issue_id`, by doing this can keep the LLM context clean. The technical term for this is **Action-level Post-Processing**.

        ```python Python
        def linear_post_processor(output_data: dict) -> dict:
            output_data = {
                'success': output_data['successfull'],
                'issue_id': output_data['id'],
            }
            return output_data
        ```
      </Step>

      <Step title="Get Linear Action from Composio">
        When getting tools using the `get_tools()` method, we need to pass the `processors` parameter to specify the schema, pre-processing, and post-processing functions. In this example, we're setting up an Action-level preprocessor by mapping the `LINEAR_CREATE_LINEAR_ISSUE` action to our `linear_schema_processor`, `linear_pre_processor` and `linear_post_processor` functions defined above respectively in schema, pre, and post processors.

        ```python Python {2-12}
        tools = composio_toolset.get_tools(
            processors={
                "schema": {
                    Action.LINEAR_CREATE_LINEAR_ISSUE: linear_schema_processor,
                },
                "pre": {
                    Action.LINEAR_CREATE_LINEAR_ISSUE: linear_pre_processor,
                },
                "post": {
                    Action.LINEAR_CREATE_LINEAR_ISSUE: linear_post_processor,
                }
            },
            actions=[Action.LINEAR_CREATE_LINEAR_ISSUE]
        )
        ```
      </Step>

      <Step title="Invoke the agent">
        ```python Python
        task = "Create a Linear Issue to update the frontend"

        agent = create_openai_functions_agent(llm, tools, prompt)
        agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)

        agent_executor.invoke({"input": task})
        ```
      </Step>
    </Steps>
  </Tab>

  <Tab title="TypeScript">
    <Steps>
      <Step title="Install required libraries">
        ```bash TypeScript
        npm install composio-core @langchain/openai langchain @langchain/core
        ```
      </Step>

      <Step title="Import required libraries">
        ```typescript TypeScript
        import { ActionExecutionResDto, LangchainToolSet, RawActionData, TPostProcessor, TPreProcessor, TSchemaProcessor } from "composio-core";
        import { ChatOpenAI } from "@langchain/openai";
        import { createOpenAIFunctionsAgent, AgentExecutor } from "langchain/agents";
        import { pull } from "langchain/hub";
        import { ChatPromptTemplate } from "@langchain/core/prompts";
        ```
      </Step>

      <Step title="Initialize ChatOpenAI & LangChain toolset client">
        ```typescript TypeScript
        const llm = new ChatOpenAI({ apiKey: "<your-api-key>" });
        const toolset = new LangchainToolSet({ apiKey: "<your-api-key>" });
        ```
      </Step>

      <Step title="Schema Modifier">
        This will be used to modify the schema of the `LINEAR_CREATE_LINEAR_ISSUE` action, we remove the parameters `project_id` and `team_id` as required fields, later in the program we will pass these values as inputs to the action manually. The technical term for this is **Schema Processing**.

        ```typescript TypeScript
        const schemaProcessor: TSchemaProcessor = ({
          actionName,
          toolSchema,
        }: {
          actionName: string;
          toolSchema: RawActionData;
        }) => {
          const modifiedSchema = { ...toolSchema };
          modifiedSchema.parameters = {
            ...modifiedSchema.parameters,
            required: modifiedSchema.parameters?.required?.filter(
              field => !['project_id', 'team_id'].includes(field)
            ) || []
          };

          return modifiedSchema;
        };
        ```
      </Step>

      <Step title="Input Modifier">
        This will be used to modify the input data for the `LINEAR_CREATE_LINEAR_ISSUE` action. Here we have added the values for `project_id` and `team_id` parameters to the input data. By doing this, we can avoid specifying these values in the prompt and be sure that the agent uses the correct values. The technical term for this is **Pre-Processing**.

        ```typescript TypeScript
        const preProcessor: TPreProcessor = ({ params, actionName, appName }: {
          params: Record<string, unknown>;
          actionName: string;
          appName: string;
        }) => {
          const modifiedParams = { ...params };

          modifiedParams.project_id = "e708162b-9b1a-4901-ab93-0f0149f9d805";
          modifiedParams.team_id = "249ee4cc-7bbb-4ff1-adbe-d3ef2f3df94e";

          return modifiedParams;
        }
        ```
      </Step>

      <Step title="Output Modifier">
        This will be used to modify the output data for the `LINEAR_CREATE_LINEAR_ISSUE` action. Here we are modifying the output to just return the action execution status `successful` & the `issueId`, by doing this can keep the LLM context clean. The technical term for this is **Post-Processing**.

        ```typescript TypeScript
        const postProcessor: TPostProcessor = ({ actionName, appName, toolResponse }: {
          actionName: string;
          appName: string;
          toolResponse: ActionExecutionResDto;
        }) => {
          const issueId = toolResponse.data.id;
          return { data: { id: issueId }, successful: true };
        }
        ```
      </Step>

      <Step title="Add the Processors to Toolset & Execute the Agent">
        After creating the processors, we need to add them to the toolset using `addSchemaProcessor`, `addPreProcessor`, and `addPostProcessor` methods and then get the tools. Last we create the agent and execute it.

        ```typescript TypeScript {2-4}
        async function main() {
          toolset.addSchemaProcessor(schemaProcessor);
          toolset.addPreProcessor(preProcessor);
          toolset.addPostProcessor(postProcessor);

          const tools = await toolset.getTools({
            actions: ["LINEAR_CREATE_LINEAR_ISSUE"]
          });

          const prompt = (await pull(
            "hwchase17/openai-functions-agent"
          )) as ChatPromptTemplate;

          const agent = await createOpenAIFunctionsAgent({
            llm,
            tools,
            prompt,
          });

          const agentExecutor = new AgentExecutor({ agent, tools, verbose: true });

          const response = await agentExecutor.invoke({ input: "Create an issue on linear to update the frontend to with new design and description 'to update the frontend with new design', estimate is 5 (L) & return the issue id" });
          console.log(response);
        }

        main()
        ```
      </Step>
    </Steps>
  </Tab>
</Tabs>

### How to use processors at App-level?

Above we saw how to use processors at the Action-level, below is an example of how to use them at the App-level.

<CodeGroup>
  ```python Python {2-12}
  tools = composio_toolset.get_tools(
      processors={
          "pre": {
              App.<app_name>: processor_function,
          },
          "post": {
              App.<app_name>: processor_function,
          },
          "schema": {
              App.<app_name>: processor_function,
          },
      },
      apps=[App.<app_name>]
  )
  ```

  ```typescript TypeScript
  Coming Soon
  ```
</CodeGroup>

<Warning>
  Ensure that your schema processing, preprocessing, and postprocessing functions are efficient and don't introduce significant latency.
</Warning>
