Skip to content

Commit

Permalink
Minor changes in Codeanalysis tools, Testing tool added. Support to c…
Browse files Browse the repository at this point in the history
…hange schema added (#578)

Co-authored-by: Viraj <35092918+angrybayblade@users.noreply.github.com>
  • Loading branch information
shreysingla11 and angrybayblade committed Sep 17, 2024
1 parent 55cbba0 commit 386e451
Show file tree
Hide file tree
Showing 17 changed files with 742 additions and 41 deletions.
552 changes: 536 additions & 16 deletions python/composio/client/enums/_action.py

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions python/composio/client/enums/_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ class App(_AnnotatedEnum[AppData], path=APPS_CACHE):
APIFY: "App"
ASANA: "App"
ATTIO: "App"
BAMBOOHR: "App"
BROWSERBASE_TOOL: "App"
BROWSER_TOOL: "App"
CLICKUP: "App"
Expand Down Expand Up @@ -64,6 +65,7 @@ class App(_AnnotatedEnum[AppData], path=APPS_CACHE):
NOTION: "App"
PERPLEXITYAI: "App"
PIPEDRIVE: "App"
POSTHOG: "App"
RAGTOOL: "App"
SALESFORCE: "App"
SCHEDULER: "App"
Expand Down
69 changes: 69 additions & 0 deletions python/composio/client/enums/_tag.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Tag enums.
"""

from composio.client.enums.base import TAGS_CACHE, TagData, _AnnotatedEnum, enum


Expand Down Expand Up @@ -58,6 +59,26 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
ATTIO_THREADS: "Tag"
ATTIO_WEBHOOKS: "Tag"
ATTIO_WORKSPACE_MEMBERS: "Tag"
BAMBOOHR_ACCOUNT_INFORMATION: "Tag"
BAMBOOHR_APPLICANT_TRACKING: "Tag"
BAMBOOHR_BENEFITS: "Tag"
BAMBOOHR_COMPANY_FILES: "Tag"
BAMBOOHR_EMPLOYEES: "Tag"
BAMBOOHR_EMPLOYEE_FILES: "Tag"
BAMBOOHR_GOALS: "Tag"
BAMBOOHR_HOURS: "Tag"
BAMBOOHR_IMPORTANT: "Tag"
BAMBOOHR_LAST_CHANGE_INFORMATION: "Tag"
BAMBOOHR_LOGIN: "Tag"
BAMBOOHR_PAYROLL: "Tag"
BAMBOOHR_PHOTOS: "Tag"
BAMBOOHR_REPORTS: "Tag"
BAMBOOHR_TABULAR_DATA: "Tag"
BAMBOOHR_TIME_OFF: "Tag"
BAMBOOHR_TIME_TRACKING: "Tag"
BAMBOOHR_TIME_TRACKING___PRIVATE_BETA: "Tag"
BAMBOOHR_TRAINING: "Tag"
BAMBOOHR_WEBHOOKS: "Tag"
CLICKUP_ATTACHMENTS: "Tag"
CLICKUP_AUTHORIZATION: "Tag"
CLICKUP_COMMENTS: "Tag"
Expand Down Expand Up @@ -361,6 +382,54 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
PIPEDRIVE_USERS: "Tag"
PIPEDRIVE_USERSETTINGS: "Tag"
PIPEDRIVE_WEBHOOKS: "Tag"
POSTHOG_ACTIONS: "Tag"
POSTHOG_ACTIVITY_LOG: "Tag"
POSTHOG_ANNOTATIONS: "Tag"
POSTHOG_APP_METRICS: "Tag"
POSTHOG_BATCH_EXPORTS: "Tag"
POSTHOG_COHORTS: "Tag"
POSTHOG_DASHBOARDS: "Tag"
POSTHOG_DASHBOARD_TEMPLATES: "Tag"
POSTHOG_DOMAINS: "Tag"
POSTHOG_EARLY_ACCESS_FEATURE: "Tag"
POSTHOG_EVENTS: "Tag"
POSTHOG_EVENT_DEFINITIONS: "Tag"
POSTHOG_EXPERIMENTS: "Tag"
POSTHOG_EXPLICIT_MEMBERS: "Tag"
POSTHOG_EXPORTS: "Tag"
POSTHOG_FEATURE_FLAGS: "Tag"
POSTHOG_FUNNEL: "Tag"
POSTHOG_GROUPS: "Tag"
POSTHOG_GROUPS_TYPES: "Tag"
POSTHOG_IMPORTANT: "Tag"
POSTHOG_INSIGHTS: "Tag"
POSTHOG_INVITES: "Tag"
POSTHOG_MEMBERS: "Tag"
POSTHOG_NOTEBOOKS: "Tag"
POSTHOG_ORGANIZATIONS: "Tag"
POSTHOG_PERSONS: "Tag"
POSTHOG_PIPELINE_DESTINATIONS: "Tag"
POSTHOG_PIPELINE_DESTINATION_CONFIGS: "Tag"
POSTHOG_PIPELINE_FRONTEND_APPS: "Tag"
POSTHOG_PIPELINE_FRONTEND_APPS_CONFIGS: "Tag"
POSTHOG_PIPELINE_IMPORT_APPS: "Tag"
POSTHOG_PIPELINE_IMPORT_APPS_CONFIGS: "Tag"
POSTHOG_PIPELINE_TRANSFORMATIONS: "Tag"
POSTHOG_PIPELINE_TRANSFORMATION_CONFIGS: "Tag"
POSTHOG_PLUGINS: "Tag"
POSTHOG_PLUGIN_CONFIGS: "Tag"
POSTHOG_PROJECTS: "Tag"
POSTHOG_PROPERTY_DEFINITIONS: "Tag"
POSTHOG_PROXY_RECORDS: "Tag"
POSTHOG_QUERY: "Tag"
POSTHOG_ROLES: "Tag"
POSTHOG_SESSIONS: "Tag"
POSTHOG_SESSION_RECORDINGS: "Tag"
POSTHOG_SESSION_RECORDING_PLAYLISTS: "Tag"
POSTHOG_SUBSCRIPTIONS: "Tag"
POSTHOG_SURVEYS: "Tag"
POSTHOG_TREND: "Tag"
POSTHOG_USERS: "Tag"
SALESFORCE_ACCOUNT: "Tag"
SALESFORCE_CAMPAIGN: "Tag"
SALESFORCE_CONTACT: "Tag"
Expand Down
1 change: 1 addition & 0 deletions python/composio/client/enums/_trigger.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
"""
Trigger enums.
"""

from composio.client.enums.base import TRIGGERS_CACHE, TriggerData, _AnnotatedEnum, enum


Expand Down
1 change: 0 additions & 1 deletion python/composio/tools/base/exceptions.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
"""Tool exceptions."""


from composio.exceptions import ComposioSDKError


Expand Down
3 changes: 3 additions & 0 deletions python/composio/tools/env/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,9 @@ def check_for_missing_dependencies(
},
timeout=600,
)
if request.status_code != 200:
raise ComposioSDKError(f"Error installing dependencies: {request.text}")

response = request.json()
if response["error"] is not None:
raise ComposioSDKError(
Expand Down
6 changes: 5 additions & 1 deletion python/composio/tools/env/factory.py
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,11 @@ def close(cls, id: str) -> None:
"""Teardown the workspace with given ID."""
if id not in cls._workspaces:
return
cls._workspaces[id].teardown()
workspace = cls._workspaces[id]
if workspace.persistent:
return

workspace.teardown()

@classmethod
def teardown(cls) -> None:
Expand Down
37 changes: 26 additions & 11 deletions python/composio/tools/local/codeanalysis/actions/base_action.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,21 +33,29 @@ def load_fqdn_cache(self, repo_name: str):
}

def get_matching_items(
self, query_name: Optional[str], item_type: str
self,
query_name: Optional[str],
item_type: str,
parent_fqdns: Optional[List[str]] = None,
) -> List[str]:
if not self.fqdn_index:
raise ValueError("FQDN index not loaded")

matching_fqdns = [
curr_fqdn
for curr_fqdn, curr_fqdn_elem in self.fqdn_index.items()
if curr_fqdn_elem["global_type"] == item_type
and (
def matches_query(curr_fqdn: str) -> bool:
return (
query_name is None
or query_name == curr_fqdn.split(".")[-1]
or query_name == curr_fqdn
)

matching_fqdns = [
curr_fqdn
for curr_fqdn, curr_fqdn_elem in self.fqdn_index.items()
if curr_fqdn_elem["global_type"] == item_type
and matches_query(curr_fqdn)
and (parent_fqdns is None or curr_fqdn_elem["parent_fqdn"] in parent_fqdns)
]

return matching_fqdns

def fetch_relevant_details(self, relevant_fqdn: str, repo_path: str) -> List[Dict]:
Expand Down Expand Up @@ -89,13 +97,20 @@ def execute(self, request, metadata):
def get_method_artefacts(
self, query_class_name: Optional[str], query_method_name: str, repo_path: str
) -> Dict:
matching_fqdns_func = self.get_matching_items(query_method_name, "function")
matching_fqdns_class = self.get_matching_items(query_class_name, "class")

if query_class_name is not None:
matching_fqdns_func = self.get_matching_items(
query_method_name, "function", matching_fqdns_class
)
else:
matching_fqdns_func = self.get_matching_items(query_method_name, "function")
func_results = self.get_item_results(matching_fqdns_func, repo_path)
filtered_func_results = self.filter_function_results(
func_results, query_class_name, matching_fqdns_class, repo_path
)
if query_class_name is not None:
filtered_func_results = self.filter_function_results(
func_results, query_class_name, matching_fqdns_class, repo_path
)
else:
filtered_func_results = func_results

return self.format_method_results(filtered_func_results)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ class GetRelevantCode(LocalAction[GetRelevantCodeRequest, GetRelevantCodeRespons
query: "database connection pooling"
The relevance of retrieved code snippets depends on the quality and specificity of the provided query.
Don't use this action if you are not sure about the query. And the results returned are not very relevant.
"""

display_name = "Get Relevant Code"
Expand Down
3 changes: 3 additions & 0 deletions python/composio/tools/local/filetool/actions/scroll.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ class Scroll(LocalAction[ScrollRequest, ScrollResponse]):
- A dictionary of line numbers and their content for the new view window.
- An error message if no file is open or if the file is not found.
Use SearchWord Action to search for a specific word in the file in case
the file is long, as scrolling is not efficient for large files.
Raises:
- FileNotFoundError: If the file is not found.
"""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,6 @@ def execute(self, request: GetPatchRequest, metadata: t.Dict) -> GetPatchRespons
cmd = ["git add -u"]
if len(request.new_file_path) > 0:
cmd = [f"git add {new_files}", "git add -u"]
cmd.append("git diff --cached")

output = self.shells.get(request.shell_id).exec(cmd=" && ".join(cmd))
return GetPatchResponse(
stdout=output[STDOUT],
Expand Down
49 changes: 49 additions & 0 deletions python/composio/tools/local/shelltool/shell_exec/actions/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
"""Tool for executing shell commands."""

import typing as t

from pydantic import BaseModel, Field

from composio.tools.base.local import LocalAction
from composio.tools.env.constants import STDERR, STDOUT
from composio.tools.local.shelltool.shell_exec.actions.exec import ShellRequest


class TestExecRequest(ShellRequest):
"""Test execution request."""


class TestExecResponse(BaseModel):
"""Shell execution response."""

test_response: str = Field(
...,
description="Response from the test command",
)
current_shell_pwd: str = Field(
default="",
description="Current shell's working directory",
)


class TestCommand(LocalAction[TestExecRequest, TestExecResponse]):
"""
Run the command for testing the patch.
"""

_tags = ["workspace", "shell"]

def execute(self, request: TestExecRequest, metadata: t.Dict) -> TestExecResponse:
"""Execute a shell command."""
shell = self.shells.get(id=request.shell_id)
project_path = metadata.get("project_path")
command = metadata.get("test_command")
self.logger.debug(f"Executing {command} @ {shell}")
shell.exec(cmd=f"cd {project_path}")
shell.exec(cmd="python -m pip install -e .")
output = shell.exec(cmd=f"{command}")
self.logger.debug(output)
return TestExecResponse(
test_response=output[STDERR],
current_shell_pwd=f"Currently in {shell.exec(cmd='pwd')[STDOUT].strip()}",
)
2 changes: 2 additions & 0 deletions python/composio/tools/local/shelltool/shell_exec/tool.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from composio.tools.local.shelltool.shell_exec.actions.exec import ExecCommand
from composio.tools.local.shelltool.shell_exec.actions.new import CreateShell
from composio.tools.local.shelltool.shell_exec.actions.spawn import SpawnProcess
from composio.tools.local.shelltool.shell_exec.actions.test import TestCommand


class Shelltool(LocalTool, autoload=True):
Expand All @@ -20,4 +21,5 @@ def actions(cls) -> t.List[t.Type[LocalAction]]:
ExecCommand,
CreateShell,
SpawnProcess,
TestCommand,
]
29 changes: 24 additions & 5 deletions python/composio/tools/toolset.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,9 @@ class ProcessorsType(te.TypedDict):
post: te.NotRequired[t.Dict[_KeyType, _ProcessorType]]
"""Response processors."""

schema: te.NotRequired[t.Dict[_KeyType, _ProcessorType]]
"""Schema processors"""


def _check_agentops() -> bool:
"""Check if AgentOps is installed and initialized."""
Expand Down Expand Up @@ -237,7 +240,9 @@ def _limit_file_search_response(response: t.Dict) -> t.Dict:
self.logger.debug("`api_key` is not set when initializing toolset.")

self._processors = (
processors if processors is not None else {"post": {}, "pre": {}}
processors
if processors is not None
else {"post": {}, "pre": {}, "schema": {}}
)
self._metadata = metadata or {}
self._workspace_id = workspace_id
Expand Down Expand Up @@ -496,7 +501,7 @@ def _add_metadata(self, action: Action, metadata: t.Optional[t.Dict]) -> t.Dict:
def _get_processor(
self,
key: _KeyType,
type_: te.Literal["post", "pre"],
type_: te.Literal["post", "pre", "schema"],
) -> t.Optional[_ProcessorType]:
"""Get processor for given app or action"""
processor = self._processors.get(type_, {}).get(key) # type: ignore
Expand All @@ -512,12 +517,12 @@ def _process(
self,
key: _KeyType,
data: t.Dict,
type_: te.Literal["pre", "post"],
type_: te.Literal["pre", "post", "schema"],
) -> t.Dict:
processor = self._get_processor(key=key, type_=type_)
if processor is not None:
self.logger.info(
f"Running {'request' if type_ == 'pre' else 'response'}"
f"Running {'request' if type_ == 'pre' else 'response' if type_ == 'post' else 'schema'}"
f" through: {processor.__name__}"
)
data = processor(data)
Expand Down Expand Up @@ -545,6 +550,17 @@ def _process_respone(self, action: Action, response: t.Dict) -> t.Dict:
type_="post",
)

def _process_schema_properties(self, action: Action, properties: t.Dict) -> t.Dict:
return self._process(
key=App(action.app),
data=self._process(
key=action,
data=properties,
type_="schema",
),
type_="schema",
)

@_record_action_if_available
def execute_action(
self,
Expand Down Expand Up @@ -723,7 +739,10 @@ def _process_schema(self, action_item: ActionModel) -> ActionModel:
action_item.description = action_item.description[
: self._description_char_limit
]

action_item.parameters.properties = self._process_schema_properties(
action=Action(action_item.name.upper()),
properties=action_item.parameters.properties,
)
return action_item

def create_trigger_listener(self, timeout: float = 15.0) -> TriggerSubscription:
Expand Down
Loading

0 comments on commit 386e451

Please sign in to comment.