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

fix(core): digest backwards compatibility #451

Merged
merged 10 commits into from
Jul 10, 2024
Merged
Show file tree
Hide file tree
Changes from 5 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
2 changes: 1 addition & 1 deletion python/pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "uagents"
version = "0.13.1"
version = "0.13.2"
Archento marked this conversation as resolved.
Show resolved Hide resolved
description = "Lightweight framework for rapid agent-based development"
authors = [
"Ed FitzGerald <[email protected]>",
Expand Down
2 changes: 1 addition & 1 deletion python/src/uagents/communication.py
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,6 @@ async def send_sync_message(
if isinstance(response, Envelope):
json_message = response.decode_payload()
if response_type:
return response_type.model_validate_json(json_message)
return response_type.model_validate(json_message)
return json_message
return response
2 changes: 1 addition & 1 deletion python/src/uagents/envelope.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class Envelope(BaseModel):
target (str): The target's address.
session (UUID4): The session UUID that persists for back-and-forth
dialogues between agents.
schema_digest (str): The schema digest for the enclosed message (alias for protocol).
schema_digest (str): The schema digest for the enclosed message.
protocol_digest (Optional[str]): The digest of the protocol associated with the message
(optional).
payload (Optional[str]): The encoded message payload of the envelope (optional).
Expand Down
25 changes: 16 additions & 9 deletions python/src/uagents/models.py
Original file line number Diff line number Diff line change
@@ -1,19 +1,26 @@
import hashlib
import json
from typing import Type, Union
from typing import Any, Type, Union

from pydantic import BaseModel
from pydantic.v1 import BaseModel


# reverting back to pydantic.v1 BaseModel for backwards compatibility
class Model(BaseModel):
@classmethod
def model_json_schema(cls) -> str:
return cls.schema_json(indent=None, sort_keys=True)

def model_dump_json(self) -> str:
return self.json(indent=None, sort_keys=True)

@classmethod
def model_validate(cls, obj: Any) -> "Model":
return cls.parse_obj(obj)

@staticmethod
def build_schema_digest(model: Union["Model", Type["Model"]]) -> str:
schema = model.model_json_schema()
digest = (
hashlib.sha256(json.dumps(schema, sort_keys=True).encode("utf8"))
.digest()
.hex()
)
schema = model.schema_json(indent=None, sort_keys=True)
qati marked this conversation as resolved.
Show resolved Hide resolved
digest = hashlib.sha256(schema.encode("utf8")).digest().hex()

return f"model:{digest}"

Expand Down
36 changes: 36 additions & 0 deletions python/tests/test_model.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import unittest
from enum import Enum
from typing import List, Literal, Optional

from uagents import Model

Expand All @@ -25,6 +27,40 @@ class SuperImportantCheck(Model):

self.assertEqual(result, target_digest, "Digest mismatch")

def test_calculate_nested_digest_backcompat(self):
Archento marked this conversation as resolved.
Show resolved Hide resolved
"""
Test the digest calculation of nested models.
"""

class UAgentResponseType(Enum):
FINAL = "final"
ERROR = "error"
VALIDATION_ERROR = "validation_error"
SELECT_FROM_OPTIONS = "select_from_options"
FINAL_OPTIONS = "final_options"

class KeyValue(Model):
key: str
value: str

class UAgentResponse(Model):
version: Literal["v1"] = "v1"
type: UAgentResponseType
request_id: Optional[str]
agent_address: Optional[str]
message: Optional[str]
options: Optional[List[KeyValue]]
verbose_message: Optional[str]
verbose_options: Optional[List[KeyValue]]

target_digest = (
"model:cf0d1367c5f9ed8a269de559b2fbca4b653693bb8315d47eda146946a168200e"
)

result = Model.build_schema_digest(UAgentResponse)

self.assertEqual(result, target_digest, "Digest mismatch")


if __name__ == "__main__":
unittest.main()
Loading