Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Add API call tool type #571

Merged
merged 20 commits into from
Oct 4, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
60 changes: 60 additions & 0 deletions agents-api/agents_api/activities/excecute_api_call.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
from typing import Annotated, Any, Optional, TypedDict, Union

import httpx
from beartype import beartype
from pydantic import Field
from temporalio import activity

from ..autogen.openapi_model import ApiCallDef

# from ..clients import integrations
from ..common.protocol.tasks import StepContext
from ..env import testing

# from ..models.tools import get_tool_args_from_metadata


class RequestArgs(TypedDict):
content: Optional[str]
data: Optional[dict[str, Any]]
json_: Optional[dict[str, Any]]
cookies: Optional[dict[str, str]]
params: Optional[Union[str, dict[str, Any]]]


@beartype
async def execute_api_call(
api_call: ApiCallDef,
request_args: RequestArgs,
) -> Any:
try:
async with httpx.AsyncClient() as client:
response = await client.request(
method=api_call.method,
url=str(api_call.url),
headers=api_call.headers,
follow_redirects=api_call.follow_redirects,
**request_args,
)

response_dict = {
"status_code": response.status_code,
"headers": dict(response.headers),
"content": response.content,
"json": response.json(),
}

return response_dict

except BaseException as e:
if activity.in_activity():
activity.logger.error(f"Error in execute_api_call: {e}")

raise


mock_execute_api_call = execute_api_call

execute_api_call = activity.defn(name="execute_api_call")(
execute_api_call if not testing else mock_execute_api_call
)
11 changes: 10 additions & 1 deletion agents-api/agents_api/activities/task_steps/base_evaluate.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@

@beartype
async def base_evaluate(
exprs: str | list[str] | dict[str, str],
exprs: str | list[str] | dict[str, str] | dict[str, dict[str, str]],
values: dict[str, Any] = {},
extra_lambda_strs: dict[str, str] | None = None,
) -> Any | list[Any] | dict[str, Any]:
Expand Down Expand Up @@ -53,9 +53,18 @@ async def base_evaluate(
case list():
return [evaluator.eval(expr) for expr in exprs]

case dict() as d if all(isinstance(v, dict) for v in d.values()):
return {
k: {ik: evaluator.eval(iv) for ik, iv in v.items()}
for k, v in d.items()
}

case dict():
return {k: evaluator.eval(v) for k, v in exprs.items()}

case _:
raise ValueError(f"Invalid expression: {exprs}")

except BaseException as e:
if activity.in_activity():
activity.logger.error(f"Error in base_evaluate: {e}")
Expand Down
2 changes: 1 addition & 1 deletion agents-api/agents_api/autogen/Tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -944,7 +944,7 @@ class ToolCallStep(BaseModel):
"""
The tool to run
"""
arguments: dict[str, str] | Literal["_"] = "_"
arguments: dict[str, dict[str, str] | str] | Literal["_"] = "_"
"""
The input parameters for the tool (defaults to last step output)
"""
Expand Down
181 changes: 164 additions & 17 deletions agents-api/agents_api/autogen/Tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,114 @@
from typing import Annotated, Any, Literal
from uuid import UUID

from pydantic import AwareDatetime, BaseModel, ConfigDict, Field
from pydantic import AnyUrl, AwareDatetime, BaseModel, ConfigDict, Field, StrictBool


class ApiCallDef(BaseModel):
"""
API call definition
"""

model_config = ConfigDict(
populate_by_name=True,
)
method: Literal[
"GET", "POST", "PUT", "DELETE", "PATCH", "HEAD", "OPTIONS", "CONNECT", "TRACE"
]
"""
The HTTP method to use
"""
url: AnyUrl
"""
The URL to call
"""
headers: dict[str, str] | None = None
"""
The headers to send with the request
"""
content: str | None = None
"""
The content as base64 to send with the request
"""
data: dict[str, str] | None = None
"""
The data to send as form data
"""
json_: Annotated[dict[str, Any] | None, Field(None, alias="json")]
"""
JSON body to send with the request
"""
cookies: dict[str, str] | None = None
"""
Cookies
"""
params: str | dict[str, Any] | None = None
"""
The parameters to send with the request
"""
follow_redirects: StrictBool | None = None
"""
Follow redirects
"""


class ApiCallDefUpdate(BaseModel):
"""
API call definition
"""

model_config = ConfigDict(
populate_by_name=True,
)
method: (
Literal[
"GET",
"POST",
"PUT",
"DELETE",
"PATCH",
"HEAD",
"OPTIONS",
"CONNECT",
"TRACE",
]
| None
) = None
"""
The HTTP method to use
"""
url: AnyUrl | None = None
"""
The URL to call
"""
headers: dict[str, str] | None = None
"""
The headers to send with the request
"""
content: str | None = None
"""
The content as base64 to send with the request
"""
data: dict[str, str] | None = None
"""
The data to send as form data
"""
json_: Annotated[dict[str, Any] | None, Field(None, alias="json")]
"""
JSON body to send with the request
"""
cookies: dict[str, str] | None = None
"""
Cookies
"""
params: str | dict[str, Any] | None = None
"""
The parameters to send with the request
"""
follow_redirects: StrictBool | None = None
"""
Follow redirects
"""


class ChosenToolCall(BaseModel):
Expand Down Expand Up @@ -37,12 +144,26 @@ class CreateToolRequest(BaseModel):
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
"""
description: str | None = None
"""
Description of the tool
"""
function: FunctionDef | None = None
"""
The function to call
"""
integration: IntegrationDef | None = None
"""
The integration to call
"""
system: SystemDef | None = None
"""
The system to call
"""
api_call: ApiCallDef | None = None
"""
The API call to make
"""


class FunctionCallOption(BaseModel):
Expand Down Expand Up @@ -104,10 +225,6 @@ class IntegrationDef(BaseModel):
"""
The specific method of the integration to call
"""
description: str | None = None
"""
Optional description of the integration
"""
setup: dict[str, Any] | None = None
"""
The setup parameters the integration accepts
Expand Down Expand Up @@ -146,10 +263,6 @@ class IntegrationDefUpdate(BaseModel):
"""
The specific method of the integration to call
"""
description: str | None = None
"""
Optional description of the integration
"""
setup: dict[str, Any] | None = None
"""
The setup parameters the integration accepts
Expand Down Expand Up @@ -179,12 +292,26 @@ class PatchToolRequest(BaseModel):
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
"""
description: str | None = None
"""
Description of the tool
"""
function: FunctionDef | None = None
"""
The function to call
"""
integration: IntegrationDefUpdate | None = None
"""
The integration to call
"""
system: SystemDefUpdate | None = None
"""
The system to call
"""
api_call: ApiCallDefUpdate | None = None
"""
The API call to make
"""


class SystemDef(BaseModel):
Expand All @@ -199,10 +326,6 @@ class SystemDef(BaseModel):
"""
The name of the system call
"""
description: str | None = None
"""
Optional description of the system call
"""
arguments: dict[str, Any] | None = None
"""
The arguments to pre-apply to the system call
Expand All @@ -221,10 +344,6 @@ class SystemDefUpdate(BaseModel):
"""
The name of the system call
"""
description: str | None = None
"""
Optional description of the system call
"""
arguments: dict[str, Any] | None = None
"""
The arguments to pre-apply to the system call
Expand All @@ -239,12 +358,26 @@ class Tool(BaseModel):
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
"""
description: str | None = None
"""
Description of the tool
"""
function: FunctionDef | None = None
"""
The function to call
"""
integration: IntegrationDef | None = None
"""
The integration to call
"""
system: SystemDef | None = None
"""
The system to call
"""
api_call: ApiCallDef | None = None
"""
The API call to make
"""
created_at: Annotated[AwareDatetime, Field(json_schema_extra={"readOnly": True})]
"""
When this resource was created as UTC date-time
Expand Down Expand Up @@ -279,12 +412,26 @@ class UpdateToolRequest(BaseModel):
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
"""
description: str | None = None
"""
Description of the tool
"""
function: FunctionDef | None = None
"""
The function to call
"""
integration: IntegrationDef | None = None
"""
The integration to call
"""
system: SystemDef | None = None
"""
The system to call
"""
api_call: ApiCallDef | None = None
"""
The API call to make
"""


class ChosenFunctionCall(ChosenToolCall):
Expand Down
3 changes: 2 additions & 1 deletion agents-api/agents_api/models/chat/prepare_chat_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -90,12 +90,13 @@ def prepare_chat_context(
participant_type: "agent",
},

*tools { agent_id, tool_id, name, type, spec, updated_at, created_at },
*tools { agent_id, tool_id, name, type, spec, description, updated_at, created_at },
tool = {
"id": tool_id,
"name": name,
"type": type,
"spec": spec,
"description": description,
"updated_at": updated_at,
"created_at": created_at,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,6 +149,7 @@ def prepare_execution_input(
"name",
"type",
"spec",
"description",
"created_at",
"updated_at",
)
Expand Down
4 changes: 3 additions & 1 deletion agents-api/agents_api/models/task/create_or_update_task.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,9 @@ def create_or_update_task(
data.metadata = data.metadata or {}
data.input_schema = data.input_schema or {}

task_data = task_to_spec(data).model_dump(exclude_none=True, exclude_unset=True)
task_data = task_to_spec(data).model_dump(
exclude_none=True, exclude_unset=True, mode="json"
)
task_data.pop("task_id", None)
task_data["created_at"] = utcnow().timestamp()

Expand Down
Loading
Loading