Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
12 changes: 6 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

## Introduction

The Universal Tool Calling Protocol (UTCP) is a modern, flexible, and scalable standard for defining and interacting with tools across a wide variety of communication protocols. UTCP 1.0.0 introduces a modular core with a plugin-based architecture, making it more extensible, testable, and easier to package.
The Universal Tool Calling Protocol (UTCP) is a secure, scalable standard for defining and interacting with tools across a wide variety of communication protocols. UTCP 1.0.0 introduces a modular core with a plugin-based architecture, making it more extensible, testable, and easier to package.

In contrast to other protocols, UTCP places a strong emphasis on:

Expand Down Expand Up @@ -87,7 +87,7 @@ Version 1.0.0 introduces several breaking changes. Follow these steps to migrate
3. **Update Imports**: Change your imports to reflect the new modular structure. For example, `from utcp.client.transport_interfaces.http_transport import HttpProvider` becomes `from utcp_http.http_call_template import HttpCallTemplate`.
4. **Tool Search**: If you were using the default search, the new strategy is `TagAndDescriptionWordMatchStrategy`. This is the new default and requires no changes unless you were implementing a custom strategy.
5. **Tool Naming**: Tool names are now namespaced as `manual_name.tool_name`. The client handles this automatically.
6 **Variable Substitution Namespacing**: Variables that are subsituted in different `call_templates`, are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.
6. **Variable Substitution Namespacing**: Variables that are substituted in different `call_templates`, are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the extra comma after call_templates to fix the sentence grammar.

Prompt for AI agents
Address the following comment on README.md at line 90:

<comment>Remove the extra comma after `call_templates` to fix the sentence grammar.</comment>

<file context>
@@ -87,7 +87,7 @@ Version 1.0.0 introduces several breaking changes. Follow these steps to migrate
 3.  **Update Imports**: Change your imports to reflect the new modular structure. For example, `from utcp.client.transport_interfaces.http_transport import HttpProvider` becomes `from utcp_http.http_call_template import HttpCallTemplate`.
 4.  **Tool Search**: If you were using the default search, the new strategy is `TagAndDescriptionWordMatchStrategy`. This is the new default and requires no changes unless you were implementing a custom strategy.
 5.  **Tool Naming**: Tool names are now namespaced as `manual_name.tool_name`. The client handles this automatically.
-6   **Variable Substitution Namespacing**: Variables that are subsituted in different `call_templates`, are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.
+6.  **Variable Substitution Namespacing**: Variables that are substituted in different `call_templates`, are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.
 
 ## Usage Examples
</file context>
Suggested change
6. **Variable Substitution Namespacing**: Variables that are substituted in different `call_templates`, are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.
6. **Variable Substitution Namespacing**: Variables that are substituted in different `call_templates` are first namespaced with the name of the manual with the `_` duplicated. So a key in a tool call template called `API_KEY` from the manual `manual_1` would be converted to `manual__1_API_KEY`.


## Usage Examples

Expand Down Expand Up @@ -226,7 +226,7 @@ if __name__ == "__main__":

### 2. Providing a UTCP Manual

A `UTCPManual` describes the tools you offer. The key change is replacing `tool_provider` with `call_template`.
A `UTCPManual` describes the tools you offer. The key change is replacing `tool_provider` with `tool_call_template`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use consistent casing for the manual class/name: replace UTCPManual with UtcpManual for consistency across the docs.

Prompt for AI agents
Address the following comment on README.md at line 229:

<comment>Use consistent casing for the manual class/name: replace `UTCPManual` with `UtcpManual` for consistency across the docs.</comment>

<file context>
@@ -226,7 +226,7 @@ if __name__ == &quot;__main__&quot;:
 
 ### 2. Providing a UTCP Manual
 
-A `UTCPManual` describes the tools you offer. The key change is replacing `tool_provider` with `call_template`.
+A `UTCPManual` describes the tools you offer. The key change is replacing `tool_provider` with `tool_call_template`.
 
 **`server.py`**
</file context>
Suggested change
A `UTCPManual` describes the tools you offer. The key change is replacing `tool_provider` with `tool_call_template`.
A `UtcpManual` describes the tools you offer. The key change is replacing `tool_provider` with `tool_call_template`.


**`server.py`**

Expand Down Expand Up @@ -288,7 +288,7 @@ def utcp_discovery():
"conditions": {"type": "string"}
}
},
"call_template": {
"tool_call_template": {
"call_template_type": "http",
"url": "https://example.com/api/weather",
"http_method": "GET"
Expand All @@ -311,7 +311,7 @@ You can find full examples in the [examples repository](https://github.com/unive

### `UtcpManual` and `Tool` Models

The `tool_provider` object inside a `Tool` has been replaced by `call_template`.
The `tool_provider` object inside a `Tool` has been replaced by `tool_call_template`.

```json
{
Expand All @@ -324,7 +324,7 @@ The `tool_provider` object inside a `Tool` has been replaced by `call_template`.
"inputs": { ... },
"outputs": { ... },
"tags": ["string"],
"call_template": {
"tool_call_template": {
"call_template_type": "http",
"url": "https://...",
"http_method": "GET"
Expand Down
30 changes: 29 additions & 1 deletion core/src/utcp/data/auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,20 +11,48 @@
import traceback

class Auth(BaseModel, ABC):
"""Authentication details for a provider.
"""REQUIRED
Authentication details for a provider.

Attributes:
auth_type: The authentication type identifier.
"""
auth_type: str

class AuthSerializer(Serializer[Auth]):
"""REQUIRED
Serializer for authentication details.

Defines the contract for serializers that convert authentication details to and from
dictionaries for storage or transmission. Serializers are responsible for:
- Converting authentication details to dictionaries for storage or transmission
- Converting dictionaries back to authentication details
- Ensuring data consistency during serialization and deserialization
"""
auth_serializers: dict[str, Serializer[Auth]] = {}

def to_dict(self, obj: Auth) -> dict:
"""REQUIRED
Convert an Auth object to a dictionary.

Args:
obj: The Auth object to convert.

Returns:
The dictionary converted from the Auth object.
"""
return AuthSerializer.auth_serializers[obj.auth_type].to_dict(obj)

def validate_dict(self, obj: dict) -> Auth:
"""REQUIRED
Validate a dictionary and convert it to an Auth object.

Args:
obj: The dictionary to validate and convert.

Returns:
The Auth object converted from the dictionary.
"""
try:
return AuthSerializer.auth_serializers[obj["auth_type"]].validate_dict(obj)
except KeyError:
Expand Down
23 changes: 22 additions & 1 deletion core/src/utcp/data/auth_implementations/api_key_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from utcp.exceptions import UtcpSerializerValidationError

class ApiKeyAuth(Auth):
"""Authentication using an API key.
"""REQUIRED
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstring starts with placeholder 'REQUIRED' instead of a one-line summary; violates standard docstring conventions and may impact doc generation.

Prompt for AI agents
Address the following comment on core/src/utcp/data/auth_implementations/api_key_auth.py at line 8:

<comment>Docstring starts with placeholder &#39;REQUIRED&#39; instead of a one-line summary; violates standard docstring conventions and may impact doc generation.</comment>

<file context>
@@ -5,7 +5,8 @@
 from utcp.exceptions import UtcpSerializerValidationError
 
 class ApiKeyAuth(Auth):
-    &quot;&quot;&quot;Authentication using an API key.
+    &quot;&quot;&quot;REQUIRED
+    Authentication using an API key.
 
</file context>

Authentication using an API key.

The key can be provided directly or sourced from an environment variable.
Supports placement in headers, query parameters, or cookies.
Expand All @@ -30,10 +31,30 @@ class ApiKeyAuth(Auth):


class ApiKeyAuthSerializer(Serializer[ApiKeyAuth]):
"""REQUIRED
Serializer for ApiKeyAuth model."""
def to_dict(self, obj: ApiKeyAuth) -> dict:
"""REQUIRED
Convert an ApiKeyAuth object to a dictionary.

Args:
obj: The ApiKeyAuth object to convert.

Returns:
The dictionary converted from the ApiKeyAuth object.
"""
return obj.model_dump()

def validate_dict(self, obj: dict) -> ApiKeyAuth:
"""REQUIRED
Validate a dictionary and convert it to an ApiKeyAuth object.

Args:
obj: The dictionary to validate and convert.

Returns:
The ApiKeyAuth object converted from the dictionary.
"""
try:
return ApiKeyAuth.model_validate(obj)
except ValidationError as e:
Expand Down
23 changes: 22 additions & 1 deletion core/src/utcp/data/auth_implementations/basic_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@
from utcp.exceptions import UtcpSerializerValidationError

class BasicAuth(Auth):
"""Authentication using HTTP Basic Authentication.
"""REQUIRED
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove the 'REQUIRED' placeholder so the docstring begins with the actual summary.

Prompt for AI agents
Address the following comment on core/src/utcp/data/auth_implementations/basic_auth.py at line 8:

<comment>Remove the &#39;REQUIRED&#39; placeholder so the docstring begins with the actual summary.</comment>

<file context>
@@ -5,7 +5,8 @@
 from utcp.exceptions import UtcpSerializerValidationError
 
 class BasicAuth(Auth):
-    &quot;&quot;&quot;Authentication using HTTP Basic Authentication.
+    &quot;&quot;&quot;REQUIRED
+    Authentication using HTTP Basic Authentication.
 
</file context>
Suggested change
"""REQUIRED
"""

Authentication using HTTP Basic Authentication.

Uses the standard HTTP Basic Authentication scheme with username and password
encoded in the Authorization header.
Expand All @@ -22,10 +23,30 @@ class BasicAuth(Auth):


class BasicAuthSerializer(Serializer[BasicAuth]):
"""REQUIRED
Serializer for BasicAuth model."""
def to_dict(self, obj: BasicAuth) -> dict:
"""REQUIRED
Convert a BasicAuth object to a dictionary.

Args:
obj: The BasicAuth object to convert.

Returns:
The dictionary converted from the BasicAuth object.
"""
return obj.model_dump()

def validate_dict(self, obj: dict) -> BasicAuth:
"""REQUIRED
Validate a dictionary and convert it to a BasicAuth object.

Args:
obj: The dictionary to validate and convert.

Returns:
The BasicAuth object converted from the dictionary.
"""
try:
return BasicAuth.model_validate(obj)
except ValidationError as e:
Expand Down
23 changes: 22 additions & 1 deletion core/src/utcp/data/auth_implementations/oauth2_auth.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@


class OAuth2Auth(Auth):
"""Authentication using OAuth2 client credentials flow.
"""REQUIRED
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstrings begin with a 'REQUIRED' placeholder instead of a meaningful summary; replace the placeholder with an appropriate summary to improve documentation clarity.

Prompt for AI agents
Address the following comment on core/src/utcp/data/auth_implementations/oauth2_auth.py at line 9:

<comment>Docstrings begin with a &#39;REQUIRED&#39; placeholder instead of a meaningful summary; replace the placeholder with an appropriate summary to improve documentation clarity.</comment>

<file context>
@@ -6,7 +6,8 @@
 
 
 class OAuth2Auth(Auth):
-    &quot;&quot;&quot;Authentication using OAuth2 client credentials flow.
+    &quot;&quot;&quot;REQUIRED
+    Authentication using OAuth2 client credentials flow.
 
</file context>

Authentication using OAuth2 client credentials flow.

Implements the OAuth2 client credentials grant type for machine-to-machine
authentication. The client automatically handles token acquisition and refresh.
Expand All @@ -27,10 +28,30 @@ class OAuth2Auth(Auth):


class OAuth2AuthSerializer(Serializer[OAuth2Auth]):
"""REQUIRED
Serializer for OAuth2Auth model."""
def to_dict(self, obj: OAuth2Auth) -> dict:
"""REQUIRED
Convert an OAuth2Auth object to a dictionary.

Args:
obj: The OAuth2Auth object to convert.

Returns:
The dictionary converted from the OAuth2Auth object.
"""
return obj.model_dump()

def validate_dict(self, obj: dict) -> OAuth2Auth:
"""REQUIRED
Validate a dictionary and convert it to an OAuth2Auth object.

Args:
obj: The dictionary to validate and convert.

Returns:
The OAuth2Auth object converted from the dictionary.
"""
try:
return OAuth2Auth.model_validate(obj)
except ValidationError as e:
Expand Down
30 changes: 29 additions & 1 deletion core/src/utcp/data/call_template.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
from utcp.data.auth import Auth, AuthSerializer

class CallTemplate(BaseModel):
"""Base class for all UTCP tool providers.
"""REQUIRED
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Docstrings start with a "REQUIRED" label instead of a concise summary on the first line; use the summary as the first line to follow standard docstring conventions (PEP 257).

Prompt for AI agents
Address the following comment on core/src/utcp/data/call_template.py at line 32:

<comment>Docstrings start with a &quot;REQUIRED&quot; label instead of a concise summary on the first line; use the summary as the first line to follow standard docstring conventions (PEP 257).</comment>

<file context>
@@ -29,7 +29,8 @@
 from utcp.data.auth import Auth, AuthSerializer
 
 class CallTemplate(BaseModel):
-    &quot;&quot;&quot;Base class for all UTCP tool providers.
+    &quot;&quot;&quot;REQUIRED
+    Base class for all UTCP tool providers.
 
</file context>

Base class for all UTCP tool providers.

This is the abstract base class that all specific call template implementations
inherit from. It provides the common fields that every provider must have.
Expand Down Expand Up @@ -61,12 +62,39 @@ def validate_auth(cls, v: Optional[Union[Auth, dict]]):
return AuthSerializer().validate_dict(v)

class CallTemplateSerializer(Serializer[CallTemplate]):
"""REQUIRED
Serializer for call templates.

Defines the contract for serializers that convert call templates to and from
dictionaries for storage or transmission. Serializers are responsible for:
- Converting call templates to dictionaries for storage or transmission
- Converting dictionaries back to call templates
- Ensuring data consistency during serialization and deserialization
"""
call_template_serializers: dict[str, Serializer[CallTemplate]] = {}

def to_dict(self, obj: CallTemplate) -> dict:
"""REQUIRED
Convert a CallTemplate object to a dictionary.

Args:
obj: The CallTemplate object to convert.

Returns:
The dictionary converted from the CallTemplate object.
"""
return CallTemplateSerializer.call_template_serializers[obj.call_template_type].to_dict(obj)

def validate_dict(self, obj: dict) -> CallTemplate:
"""REQUIRED
Validate a dictionary and convert it to a CallTemplate object.

Args:
obj: The dictionary to validate and convert.

Returns:
The CallTemplate object converted from the dictionary.
"""
try:
return CallTemplateSerializer.call_template_serializers[obj["call_template_type"]].validate_dict(obj)
except KeyError:
Expand Down
9 changes: 9 additions & 0 deletions core/src/utcp/data/register_manual_response.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,15 @@
from typing import List

class RegisterManualResult(BaseModel):
"""REQUIRED
Result of a manual registration.

Attributes:
manual_call_template: The call template of the registered manual.
manual: The registered manual.
success: Whether the registration was successful.
errors: List of error messages if registration failed.
"""
manual_call_template: CallTemplate
manual: UtcpManual
success: bool
Expand Down
Loading
Loading