From 9c38da1a42c29da7218dac9696b1d67d9ced2538 Mon Sep 17 00:00:00 2001
From: Vivek Gurudutt K <127002789+VivekGuruduttK28@users.noreply.github.com>
Date: Fri, 4 Oct 2024 05:40:54 +0530
Subject: [PATCH 1/3] Enhanced the error messages (#575)
This PR is to fix the issue mentioned in #572
I have made the required changes in the files create_agent.py,
create_or_update_agent.py and delete_agent.py. I have added descriptions
to QueryException, ValidationError and TypeError.
----
> [!IMPORTANT]
> Enhanced error messages for exceptions in agent-related files to
provide detailed guidance on potential issues.
>
> - **Error Messages**:
> - Enhanced error messages for `QueryException`, `ValidationError`, and
`TypeError` in `create_agent.py`, `create_or_update_agent.py`, and
`delete_agent.py`.
> - `QueryException`: Now includes a detailed message about potential
causes related to database query failures.
> - `ValidationError`: Provides guidance on checking input data for
missing or incorrect fields.
> - `TypeError`: Describes type mismatch issues and suggests reviewing
input data types.
>
> This description was created by [
](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral)
for 049d7eea196b74158e4fc4d83049656c7e7fa12e. It will automatically
update as commits are pushed.
Co-authored-by: Diwank Singh Tomer
---
agents-api/agents_api/models/agent/create_agent.py | 6 +++---
.../agents_api/models/agent/create_or_update_agent.py | 6 +++---
agents-api/agents_api/models/agent/delete_agent.py | 6 +++---
3 files changed, 9 insertions(+), 9 deletions(-)
diff --git a/agents-api/agents_api/models/agent/create_agent.py b/agents-api/agents_api/models/agent/create_agent.py
index 73be4ec77..546d0d441 100644
--- a/agents-api/agents_api/models/agent/create_agent.py
+++ b/agents-api/agents_api/models/agent/create_agent.py
@@ -32,9 +32,9 @@
in str(e): lambda *_: HTTPException(
detail="developer not found", status_code=403
),
- QueryException: partialclass(HTTPException, status_code=400),
- ValidationError: partialclass(HTTPException, status_code=400),
- TypeError: partialclass(HTTPException, status_code=400),
+ QueryException: partialclass(HTTPException, status_code=400, detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."),
+ ValidationError: partialclass(HTTPException, status_code=400, detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."),
+ TypeError: partialclass(HTTPException, status_code=400, detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."),
}
)
@wrap_in_class(
diff --git a/agents-api/agents_api/models/agent/create_or_update_agent.py b/agents-api/agents_api/models/agent/create_or_update_agent.py
index 156c8ae61..17e01fccb 100644
--- a/agents-api/agents_api/models/agent/create_or_update_agent.py
+++ b/agents-api/agents_api/models/agent/create_or_update_agent.py
@@ -27,9 +27,9 @@
@rewrap_exceptions(
{
- QueryException: partialclass(HTTPException, status_code=400),
- ValidationError: partialclass(HTTPException, status_code=400),
- TypeError: partialclass(HTTPException, status_code=400),
+ QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."),
+ ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."),
+ TypeError: partialclass(HTTPException, status_code=400,detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."),
}
)
@wrap_in_class(
diff --git a/agents-api/agents_api/models/agent/delete_agent.py b/agents-api/agents_api/models/agent/delete_agent.py
index 926007bdf..cb6b16718 100644
--- a/agents-api/agents_api/models/agent/delete_agent.py
+++ b/agents-api/agents_api/models/agent/delete_agent.py
@@ -32,9 +32,9 @@
in e.resp["display"]: lambda *_: HTTPException(
detail="developer not found or doesnt own resource", status_code=404
),
- QueryException: partialclass(HTTPException, status_code=400),
- ValidationError: partialclass(HTTPException, status_code=400),
- TypeError: partialclass(HTTPException, status_code=400),
+ QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."),
+ ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."),
+ TypeError: partialclass(HTTPException, status_code=400,detail="A type mismatch occurred. This likely means the data provided is of an incorrect type (e.g., string instead of integer). Please review the input and try again."),
}
)
@wrap_in_class(
From 51f5e65cf7095c09219dbe60080898b530f36dac Mon Sep 17 00:00:00 2001
From: Diwank Singh Tomer
Date: Thu, 3 Oct 2024 20:11:31 -0400
Subject: [PATCH 2/3] fix(agents-api): Remove unnecessary 'type' property from
tool type definition (#574)
Signed-off-by: Diwank Singh Tomer
----
> [!IMPORTANT]
> Removed 'type' property from tool classes and added computed 'type'
property using a function in `Tools.py`, `openapi_model.py`, and
`tasks.py`.
>
> - **Behavior**:
> - Removed `type` property from `CreateToolRequest`, `NamedToolChoice`,
`PatchToolRequest`, `Tool`, and `UpdateToolRequest` in `Tools.py`.
> - Added computed `type` property to `TaskTool`, `Tool`,
`UpdateToolRequest`, and `PatchToolRequest` in `openapi_model.py`.
> - Updated `task_to_spec()` in `tasks.py` to use computed `type`
property.
> - **Misc**:
> - Removed `type` property from `Tool` and `NamedToolChoice` in
`models.tsp`.
>
> This description was created by [
](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral)
for 289e87eff9a220b2c4430959f989cca471e36cf9. It will automatically
update as commits are pushed.
Signed-off-by: Diwank Singh Tomer
---
agents-api/agents_api/autogen/Tools.py | 31 ------
.../agents_api/autogen/openapi_model.py | 97 +++++--------------
.../agents_api/common/protocol/tasks.py | 27 ++++--
typespec/tools/models.tsp | 14 ---
4 files changed, 40 insertions(+), 129 deletions(-)
diff --git a/agents-api/agents_api/autogen/Tools.py b/agents-api/agents_api/autogen/Tools.py
index c2d4199a2..8227e5759 100644
--- a/agents-api/agents_api/autogen/Tools.py
+++ b/agents-api/agents_api/autogen/Tools.py
@@ -33,10 +33,6 @@ class CreateToolRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
- type: Literal["function", "integration", "system", "api_call"] = "function"
- """
- Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now)
- """
name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")]
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
@@ -168,10 +164,6 @@ class NamedToolChoice(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
- type: Literal["function", "integration", "system", "api_call"]
- """
- Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now)
- """
function: FunctionCallOption | None = None
@@ -183,10 +175,6 @@ class PatchToolRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
- type: Literal["function", "integration", "system", "api_call"] = "function"
- """
- Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now)
- """
name: Annotated[str | None, Field(None, max_length=40, pattern="^[^\\W0-9]\\w*$")]
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
@@ -247,10 +235,6 @@ class Tool(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
- type: Literal["function", "integration", "system", "api_call"] = "function"
- """
- Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now)
- """
name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")]
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
@@ -291,10 +275,6 @@ class UpdateToolRequest(BaseModel):
model_config = ConfigDict(
populate_by_name=True,
)
- type: Literal["function", "integration", "system", "api_call"] = "function"
- """
- Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now)
- """
name: Annotated[str, Field(max_length=40, pattern="^[^\\W0-9]\\w*$")]
"""
Name of the tool (must be unique for this agent and a valid python identifier string )
@@ -316,14 +296,3 @@ class ChosenFunctionCall(ChosenToolCall):
"""
The function to call
"""
-
-
-class NamedFunctionChoice(NamedToolChoice):
- model_config = ConfigDict(
- populate_by_name=True,
- )
- type: Literal["function"] = "function"
- function: FunctionCallOption
- """
- The function to call
- """
diff --git a/agents-api/agents_api/autogen/openapi_model.py b/agents-api/agents_api/autogen/openapi_model.py
index bff2221eb..0d9390816 100644
--- a/agents-api/agents_api/autogen/openapi_model.py
+++ b/agents-api/agents_api/autogen/openapi_model.py
@@ -77,88 +77,35 @@ class InputChatMLMessage(Message):
pass
-# Custom types (not generated correctly)
-# --------------------------------------
-
-ChatMLContent = (
- list[ChatMLTextContentPart | ChatMLImageContentPart]
- | Tool
- | ChosenToolCall
- | str
- | ToolResponse
- | list[
- list[ChatMLTextContentPart | ChatMLImageContentPart]
- | Tool
- | ChosenToolCall
- | str
- | ToolResponse
- ]
-)
-
-# Extract ChatMLRole
-ChatMLRole = BaseEntry.model_fields["role"].annotation
-
-# Extract ChatMLSource
-ChatMLSource = BaseEntry.model_fields["source"].annotation
-
-# Extract ExecutionStatus
-ExecutionStatus = Execution.model_fields["status"].annotation
-
-# Extract TransitionType
-TransitionType = Transition.model_fields["type"].annotation
-
-# Assertions to ensure consistency (optional, but recommended for runtime checks)
-assert ChatMLRole == BaseEntry.model_fields["role"].annotation
-assert ChatMLSource == BaseEntry.model_fields["source"].annotation
-assert ExecutionStatus == Execution.model_fields["status"].annotation
-assert TransitionType == Transition.model_fields["type"].annotation
-
-
-# Create models
-# -------------
+# Patches
+# -------
-class CreateTransitionRequest(Transition):
- # The following fields are optional in this
+def type_property(self: BaseModel) -> str:
+ return (
+ "function"
+ if self.function
+ else "integration"
+ if self.integration
+ else "system"
+ if self.system
+ else "api_call"
+ if self.api_call
+ else None
+ )
- id: UUID | None = None
- execution_id: UUID | None = None
- created_at: AwareDatetime | None = None
- updated_at: AwareDatetime | None = None
- metadata: dict[str, Any] | None = None
- task_token: str | None = None
+# Patch original Tool class to add 'type' property
+TaskTool.type = computed_field(property(type_property))
-class CreateEntryRequest(BaseEntry):
- timestamp: Annotated[
- float, Field(ge=0.0, default_factory=lambda: utcnow().timestamp())
- ]
+# Patch original Tool class to add 'type' property
+Tool.type = computed_field(property(type_property))
- @classmethod
- def from_model_input(
- cls: Type[Self],
- model: str,
- *,
- role: ChatMLRole,
- content: ChatMLContent,
- name: str | None = None,
- source: ChatMLSource,
- **kwargs: dict,
- ) -> Self:
- tokenizer: dict = select_tokenizer(model=model)
- token_count = token_counter(
- model=model, messages=[{"role": role, "content": content, "name": name}]
- )
+# Patch original UpdateToolRequest class to add 'type' property
+UpdateToolRequest.type = computed_field(property(type_property))
- return cls(
- role=role,
- content=content,
- name=name,
- source=source,
- tokenizer=tokenizer["type"],
- token_count=token_count,
- **kwargs,
- )
+# Patch original PatchToolRequest class to add 'type' property
+PatchToolRequest.type = computed_field(property(type_property))
# Patch Task Workflow Steps
diff --git a/agents-api/agents_api/common/protocol/tasks.py b/agents-api/agents_api/common/protocol/tasks.py
index 6892d7098..bbb5c28d3 100644
--- a/agents-api/agents_api/common/protocol/tasks.py
+++ b/agents-api/agents_api/common/protocol/tasks.py
@@ -218,19 +218,28 @@ def task_to_spec(
task: Task | CreateTaskRequest | UpdateTaskRequest | PatchTaskRequest, **model_opts
) -> TaskSpecDef | PartialTaskSpecDef:
task_data = task.model_dump(**model_opts)
- main = task_data.pop("main")
- workflows = [Workflow(name="main", steps=main)]
+ if "tools" in task_data:
+ del task_data["tools"]
- for k in list(task_data.keys()):
- if k in TaskSpec.model_fields.keys():
- continue
+ tools = []
+ for tool in task.tools:
+ tool_spec = getattr(tool, tool.type)
- steps = task_data.pop(k)
- workflows.append(Workflow(name=k, steps=steps))
+ tools.append(
+ TaskToolDef(
+ type=tool.type,
+ spec=tool_spec.model_dump(),
+ **tool.model_dump(exclude={"type"}),
+ )
+ )
- tools = task_data.pop("tools", [])
- tools = [TaskToolDef(spec=tool.pop(tool["type"]), **tool) for tool in tools]
+ workflows = [Workflow(name="main", steps=task_data.pop("main"))]
+
+ for key, steps in list(task_data.items()):
+ if key not in TaskSpec.model_fields:
+ workflows.append(Workflow(name=key, steps=steps))
+ del task_data[key]
cls = PartialTaskSpecDef if isinstance(task, PatchTaskRequest) else TaskSpecDef
diff --git a/typespec/tools/models.tsp b/typespec/tools/models.tsp
index be0fb4f68..8a8cead44 100644
--- a/typespec/tools/models.tsp
+++ b/typespec/tools/models.tsp
@@ -74,9 +74,6 @@ model SystemDef {
// TODO: We should use this model for all tools, not just functions and discriminate on the type
model Tool {
- /** Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) */
- type: ToolType = ToolType.function;
-
/** Name of the tool (must be unique for this agent and a valid python identifier string )*/
name: validPythonIdentifier;
@@ -95,24 +92,13 @@ model FunctionCallOption {
name: string;
}
-@discriminator("type")
model NamedToolChoice {
- /** Whether this tool is a `function`, `api_call`, `system` etc. (Only `function` tool supported right now) */
- type: ToolType;
-
function?: FunctionCallOption;
integration?: never; // TODO: Implement
system?: never; // TODO: Implement
api_call?: never; // TODO: Implement
}
-model NamedFunctionChoice extends NamedToolChoice {
- type: ToolType.function;
-
- /** The function to call */
- function: FunctionCallOption;
-}
-
model ToolResponse {
@key id: uuid;
From 06813fbe4afde299420d6d285fc4ee3b4d9a6dbd Mon Sep 17 00:00:00 2001
From: JeevaRamanathan <64531160+JeevaRamanathan@users.noreply.github.com>
Date: Fri, 4 Oct 2024 05:42:58 +0530
Subject: [PATCH 3/3] Enhanced error message in create, delete agent (#572)
Related to #568
Enhanced HTTPException in `create_agent.py` and `delete_agent.py`.
As this issue states, we aim to improve error messages throughout the
agents-api. I believe this issue can accommodate multiple pull requests.
Your suggestions are highly appreciated.
----
> [!IMPORTANT]
> Enhanced error messages in `create_agent.py` and `delete_agent.py` for
better clarity in `HTTPException` details.
>
> - **Error Messages**:
> - In `create_agent.py`, updated `HTTPException` detail to "Developer
not found. Please ensure the provided auth token (which refers to your
developer_id) is valid and the developer has the necessary permissions
to create an agent."
> - In `delete_agent.py`, updated `HTTPException` detail to "The
specified developer does not own the requested resource. Please verify
the ownership or check if the developer ID is correct."
>
> This description was created by [
](https://www.ellipsis.dev?ref=julep-ai%2Fjulep&utm_source=github&utm_medium=referral)
for a085d4193ec0c36ba407f340c77e81834419dd69. It will automatically
update as commits are pushed.
Co-authored-by: Diwank Singh Tomer
---
agents-api/agents_api/models/agent/create_agent.py | 3 ++-
agents-api/agents_api/models/agent/delete_agent.py | 3 ++-
2 files changed, 4 insertions(+), 2 deletions(-)
diff --git a/agents-api/agents_api/models/agent/create_agent.py b/agents-api/agents_api/models/agent/create_agent.py
index 546d0d441..c1451bb30 100644
--- a/agents-api/agents_api/models/agent/create_agent.py
+++ b/agents-api/agents_api/models/agent/create_agent.py
@@ -30,7 +30,8 @@
lambda e: isinstance(e, QueryException)
and "asserted to return some results, but returned none"
in str(e): lambda *_: HTTPException(
- detail="developer not found", status_code=403
+ detail="Developer not found. Please ensure the provided auth token (which refers to your developer_id) is valid and the developer has the necessary permissions to create an agent.",
+ status_code=403
),
QueryException: partialclass(HTTPException, status_code=400, detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."),
ValidationError: partialclass(HTTPException, status_code=400, detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."),
diff --git a/agents-api/agents_api/models/agent/delete_agent.py b/agents-api/agents_api/models/agent/delete_agent.py
index cb6b16718..d8f710481 100644
--- a/agents-api/agents_api/models/agent/delete_agent.py
+++ b/agents-api/agents_api/models/agent/delete_agent.py
@@ -30,7 +30,8 @@
lambda e: isinstance(e, QueryException)
and "Developer does not own resource"
in e.resp["display"]: lambda *_: HTTPException(
- detail="developer not found or doesnt own resource", status_code=404
+ detail="The specified developer does not own the requested resource. Please verify the ownership or check if the developer ID is correct.",
+ status_code=404
),
QueryException: partialclass(HTTPException, status_code=400,detail="A database query failed to return the expected results. This might occur if the requested resource doesn't exist or your query parameters are incorrect."),
ValidationError: partialclass(HTTPException, status_code=400,detail="Input validation failed. Please check the provided data for missing or incorrect fields, and ensure it matches the required format."),