Skip to content

Commit

Permalink
feat: add anthropic computer tools
Browse files Browse the repository at this point in the history
  • Loading branch information
angrybayblade committed Oct 24, 2024
1 parent a0740ac commit e0e1968
Show file tree
Hide file tree
Showing 8 changed files with 1,021 additions and 365 deletions.
731 changes: 663 additions & 68 deletions python/composio/client/enums/_action.py

Large diffs are not rendered by default.

10 changes: 10 additions & 0 deletions python/composio/client/enums/_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,28 @@
class App(_AnnotatedEnum[AppData], path=APPS_CACHE):
"""Class to represent `App` entity."""

AGENCYZOOM: "App"
AIRTABLE: "App"
ANTHROPIC: "App"
ASANA: "App"
ATTIO: "App"
BAMBOOHR: "App"
BLACKBOARD: "App"
BREVO: "App"
BROWSERBASE_TOOL: "App"
BROWSER_TOOL: "App"
CALENDLY: "App"
CLICKUP: "App"
CODEINTERPRETER: "App"
CODE_ANALYSIS_TOOL: "App"
CODE_FORMAT_TOOL: "App"
COMPOSIO: "App"
DISCORD: "App"
DISCORDBOT: "App"
DROPBOX: "App"
ELEVENLABS: "App"
EMBED_TOOL: "App"
ENTELLIGENCE: "App"
EXA: "App"
FIGMA: "App"
FILETOOL: "App"
Expand All @@ -54,6 +61,7 @@ class App(_AnnotatedEnum[AppData], path=APPS_CACHE):
JUNGLESCOUT: "App"
KLAVIYO: "App"
LINEAR: "App"
LINKEDIN: "App"
LISTENNOTES: "App"
MAILCHIMP: "App"
MATHEMATICAL: "App"
Expand All @@ -67,11 +75,13 @@ class App(_AnnotatedEnum[AppData], path=APPS_CACHE):
SALESFORCE: "App"
SERPAPI: "App"
SHELLTOOL: "App"
SHOPIFY: "App"
SLACK: "App"
SLACKBOT: "App"
SNOWFLAKE: "App"
SPIDERTOOL: "App"
SQLTOOL: "App"
SUPABASE: "App"
TAVILY: "App"
TRELLO: "App"
TWITTER: "App"
Expand Down
95 changes: 95 additions & 0 deletions python/composio/client/enums/_tag.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@
class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
"""Tag object."""

AGENCYZOOM_AUTHENTICATION: "Tag"
AGENCYZOOM_BUSINESS_CLASSIFICATIONS: "Tag"
AGENCYZOOM_CONFIGURATION_AND_SETTINGS: "Tag"
AGENCYZOOM_CONTACT_MANAGEMENT: "Tag"
AGENCYZOOM_CUSTOMER_MANAGEMENT: "Tag"
AGENCYZOOM_DEPARTMENT_AND_GROUPS: "Tag"
AGENCYZOOM_IMPORTANT: "Tag"
AGENCYZOOM_LEAD_MANAGEMENT: "Tag"
AGENCYZOOM_LIFE_AND_HEALTH_LEAD_MANAGEMENT: "Tag"
AGENCYZOOM_OPPORTUNITY_MANAGEMENT: "Tag"
AGENCYZOOM_PIPELINE: "Tag"
AGENCYZOOM_SERVICE_CENTER: "Tag"
AGENCYZOOM_TASK_MANAGEMENT: "Tag"
AGENCYZOOM_THREAD: "Tag"
AGENCYZOOM_USER_MANAGEMENT: "Tag"
AGENCYZOOM_V4SSO_AUTHENTICATION: "Tag"
AIRTABLE_IMPORTANT: "Tag"
ASANA_ALLOCATIONS: "Tag"
ASANA_ATTACHMENTS: "Tag"
ASANA_AUDIT_LOG_API: "Tag"
Expand Down Expand Up @@ -79,6 +96,56 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
BAMBOOHR_TIME_TRACKING___PRIVATE_BETA: "Tag"
BAMBOOHR_TRAINING: "Tag"
BAMBOOHR_WEBHOOKS: "Tag"
BLACKBOARD_ADAPTIVE_RELEASE: "Tag"
BLACKBOARD_ANNOUNCEMENTS: "Tag"
BLACKBOARD_ATTEMPT_RECEIPT: "Tag"
BLACKBOARD_ATTENDANCE: "Tag"
BLACKBOARD_CALENDAR: "Tag"
BLACKBOARD_CONTENT: "Tag"
BLACKBOARD_CONTENT_COLLECTION_RESOURCES: "Tag"
BLACKBOARD_CONTENT_FILE_ATTACHMENTS: "Tag"
BLACKBOARD_CONTENT_GROUP_ASSIGNMENTS: "Tag"
BLACKBOARD_CONTENT_RESOURCES: "Tag"
BLACKBOARD_CONTENT_REVIEW: "Tag"
BLACKBOARD_COURSES: "Tag"
BLACKBOARD_COURSE_ANNOUNCEMENTS: "Tag"
BLACKBOARD_COURSE_ASSESSMENTS: "Tag"
BLACKBOARD_COURSE_CATEGORIES: "Tag"
BLACKBOARD_COURSE_GRADEBOOK_CATEGORIES: "Tag"
BLACKBOARD_COURSE_GRADES: "Tag"
BLACKBOARD_COURSE_GRADE_ATTEMPTS: "Tag"
BLACKBOARD_COURSE_GRADE_NOTATIONS: "Tag"
BLACKBOARD_COURSE_GRADING_PERIODS: "Tag"
BLACKBOARD_COURSE_GROUPS: "Tag"
BLACKBOARD_COURSE_GROUP_USERS: "Tag"
BLACKBOARD_COURSE_MEMBERSHIPS: "Tag"
BLACKBOARD_COURSE_MESSAGES: "Tag"
BLACKBOARD_COURSE_TOC: "Tag"
BLACKBOARD_DATA_SOURCES: "Tag"
BLACKBOARD_DEPRECATED___COURSES: "Tag"
BLACKBOARD_DEPRECATED___COURSE_GRADES: "Tag"
BLACKBOARD_DEPRECATED___COURSE_GROUPS: "Tag"
BLACKBOARD_DEPRECATED___COURSE_GROUP_USERS: "Tag"
BLACKBOARD_DISCUSSIONS: "Tag"
BLACKBOARD_GOALS: "Tag"
BLACKBOARD_IMPORTANT: "Tag"
BLACKBOARD_INSTITUTIONAL_HIERARCHY: "Tag"
BLACKBOARD_INSTITUTIONAL_HIERARCHY_ADMINISTRATORS: "Tag"
BLACKBOARD_LTI: "Tag"
BLACKBOARD_OAUTH: "Tag"
BLACKBOARD_PERFORMANCE_DASHBOARD: "Tag"
BLACKBOARD_PROCTORING: "Tag"
BLACKBOARD_PRONOUNS: "Tag"
BLACKBOARD_ROLES: "Tag"
BLACKBOARD_RUBRICS: "Tag"
BLACKBOARD_RUBRIC_ASSOCIATIONS: "Tag"
BLACKBOARD_RUBRIC_EVALUATIONS: "Tag"
BLACKBOARD_SESSIONS: "Tag"
BLACKBOARD_SIS_LOGS: "Tag"
BLACKBOARD_SYSTEM: "Tag"
BLACKBOARD_TERMS: "Tag"
BLACKBOARD_UPLOADS: "Tag"
BLACKBOARD_USERS: "Tag"
BREVO_ACCOUNT: "Tag"
BREVO_COMPANIES: "Tag"
BREVO_CONTACTS: "Tag"
Expand Down Expand Up @@ -106,6 +173,20 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
BREVO_USER: "Tag"
BREVO_WEBHOOKS: "Tag"
BREVO_WHATSAPP_CAMPAIGNS: "Tag"
CALENDLY_ACTIVITY_LOG: "Tag"
CALENDLY_AVAILABILITY: "Tag"
CALENDLY_DATA_COMPLIANCE: "Tag"
CALENDLY_EVENT_TYPES: "Tag"
CALENDLY_GROUPS: "Tag"
CALENDLY_IMPORTANT: "Tag"
CALENDLY_ORGANIZATIONS: "Tag"
CALENDLY_OUTGOING_COMMUNICATIONS: "Tag"
CALENDLY_ROUTING_FORMS: "Tag"
CALENDLY_SCHEDULED_EVENTS: "Tag"
CALENDLY_SCHEDULING_LINKS: "Tag"
CALENDLY_SHARES: "Tag"
CALENDLY_USERS: "Tag"
CALENDLY_WEBHOOKS: "Tag"
CLICKUP_ATTACHMENTS: "Tag"
CLICKUP_AUTHORIZATION: "Tag"
CLICKUP_COMMENTS: "Tag"
Expand Down Expand Up @@ -464,6 +545,8 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
SALESFORCE_LEAD: "Tag"
SALESFORCE_NOTE: "Tag"
SALESFORCE_OPPORTUNITY: "Tag"
SHOPIFY_IMPORTANT: "Tag"
SHOPIFY_PRODUCT_IMAGE: "Tag"
SLACKBOT_ADMIN: "Tag"
SLACKBOT_ADMIN_APPS: "Tag"
SLACKBOT_ADMIN_APPS_APPROVED: "Tag"
Expand Down Expand Up @@ -578,6 +661,18 @@ class Tag(_AnnotatedEnum[TagData], path=TAGS_CACHE):
SLACK_USERS_PROFILE: "Tag"
SLACK_VIEWS: "Tag"
SLACK_WORKFLOWS: "Tag"
SUPABASE_AUTH: "Tag"
SUPABASE_DATABASE: "Tag"
SUPABASE_DOMAINS: "Tag"
SUPABASE_EDGE_FUNCTIONS: "Tag"
SUPABASE_ENVIRONMENTS: "Tag"
SUPABASE_IMPORTANT: "Tag"
SUPABASE_OAUTH: "Tag"
SUPABASE_ORGANIZATIONS: "Tag"
SUPABASE_PROJECTS: "Tag"
SUPABASE_REST: "Tag"
SUPABASE_SECRETS: "Tag"
SUPABASE_STORAGE: "Tag"
TRELLO_ACTION: "Tag"
TRELLO_BATCH: "Tag"
TRELLO_BOARD: "Tag"
Expand Down
5 changes: 2 additions & 3 deletions python/composio/tools/env/filemanager/file.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@
import subprocess
import sys
import typing as t
from collections import deque
from enum import Enum
from pathlib import Path
from collections import deque

import typing_extensions as te

Expand Down Expand Up @@ -57,7 +57,7 @@ class File(WithLogger):

_start: int
_end: int
_history: deque
_history: deque # TOFIX: Possible memory leak

def __init__(
self,
Expand Down Expand Up @@ -579,4 +579,3 @@ def undo(self) -> t.Optional[str]:
def __str__(self) -> str:
"""String representation."""
return f"File(name={self.path})"

107 changes: 16 additions & 91 deletions python/composio/tools/local/anthropic_computer_use/actions/bash.py
Original file line number Diff line number Diff line change
@@ -1,91 +1,29 @@
"""Tool for executing bash commands in a persistent session."""

import asyncio
import os
import typing as t

from pydantic import BaseModel, Field

from composio.tools.base.local import LocalAction
from composio.tools.base.exceptions import ExecutionFailed
from composio.tools.base.local import LocalAction
from composio.tools.env.constants import EXIT_CODE, STDERR, STDOUT


class BashSession:
"""A session of a bash shell."""

_process: asyncio.subprocess.Process
_output_delay: float = 0.2 # seconds
_timeout: float = 120.0 # seconds
_sentinel: str = "<<exit>>"

async def start(self):
self._process = await asyncio.create_subprocess_shell(
"/bin/bash",
preexec_fn=os.setsid,
shell=True,
bufsize=0,
stdin=asyncio.subprocess.PIPE,
stdout=asyncio.subprocess.PIPE,
stderr=asyncio.subprocess.PIPE,
)

def stop(self):
"""Terminate the bash shell."""
if self._process.returncode is None:
self._process.terminate()

async def run(self, command: str) -> t.Dict[str, t.Any]:
"""Execute a command in the bash shell."""
if self._process.returncode is not None:
raise ExecutionFailed(f"Bash session has exited with returncode {self._process.returncode}")

assert self._process.stdin
assert self._process.stdout
assert self._process.stderr

self._process.stdin.write(
command.encode() + f"; echo '{self._sentinel}'\n".encode()
)
await self._process.stdin.drain()

try:
async with asyncio.timeout(self._timeout):
while True:
await asyncio.sleep(self._output_delay)
output = self._process.stdout._buffer.decode()
if self._sentinel in output:
output = output[: output.index(self._sentinel)]
break
except asyncio.TimeoutError:
raise ExecutionFailed(f"Command timed out after {self._timeout} seconds")

error = self._process.stderr._buffer.decode()

self._process.stdout._buffer.clear()
self._process.stderr._buffer.clear()

return {
STDOUT: output.strip(),
STDERR: error.strip(),
EXIT_CODE: 0 if not error else 1,
}


class BashRequest(BaseModel):
"""Bash request abstraction."""

command: str = Field(
...,
description="Bash command to be executed.",
)
session_id: str = Field(
default="",
default=None,
description=(
"ID of the bash session where this command will be executed. "
"If not provided, a new session will be created."
"If not provided, the most recently used shell will be used to "
"execute the command."
),
)
command: str = Field(
...,
description="Bash command to be executed.",
)
restart: bool = Field(
False,
description="If True, restart the bash session before executing the command.",
Expand All @@ -107,16 +45,16 @@ class BashResponse(BaseModel):
...,
description="Exit code of the command",
)
session_id: str = Field(
...,
session_id: t.Optional[str] = Field(
None,
description="ID of the bash session used for this command",
)


class BashCommand(LocalAction[BashRequest, BashResponse]):
"""
Run bash commands in a persistent session.
This tool allows you to execute bash commands in a persistent session,
maintaining state between commands. You can also restart the session
if needed.
Expand All @@ -131,35 +69,22 @@ class BashCommand(LocalAction[BashRequest, BashResponse]):
"""

_tags = ["workspace", "bash"]
_sessions: t.Dict[str, BashSession] = {}

async def execute(self, request: BashRequest, metadata: t.Dict) -> BashResponse:
def execute(self, request: BashRequest, metadata: t.Dict) -> BashResponse:
"""Execute a bash command."""
session = self._sessions.get(request.session_id)

if request.restart or session is None:
if session:
session.stop()
session = BashSession()
await session.start()
session_id = f"bash_{len(self._sessions)}"
self._sessions[session_id] = session
else:
session_id = request.session_id

shell = self.shells.get(id=request.session_id)
try:
output = await session.run(request.command)
output = shell.exec(cmd=request.command)
return BashResponse(
stdout=output[STDOUT],
stderr=output[STDERR],
exit_code=output[EXIT_CODE],
session_id=session_id,
session_id=request.session_id,
)
except ExecutionFailed as e:
return BashResponse(
stdout="",
stderr=str(e),
exit_code=1,
session_id=session_id,
session_id=request.session_id,
)

Loading

0 comments on commit e0e1968

Please sign in to comment.