From 5602421db9141130104e1b0e95fdc06d947e98c0 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Tue, 2 Dec 2025 16:47:25 -0500 Subject: [PATCH 1/8] feat: add ability to push agent posts --- examples/add_agent_post_example.py | 40 ++++++++++++++++++++++++++++++ src/cvec/cvec.py | 31 +++++++++++++++++++++++ src/cvec/models/__init__.py | 8 ++++++ src/cvec/models/agent_post.py | 34 +++++++++++++++++++++++++ 4 files changed, 113 insertions(+) create mode 100644 examples/add_agent_post_example.py create mode 100644 src/cvec/models/agent_post.py diff --git a/examples/add_agent_post_example.py b/examples/add_agent_post_example.py new file mode 100644 index 0000000..c05e7bd --- /dev/null +++ b/examples/add_agent_post_example.py @@ -0,0 +1,40 @@ +import os +import uuid + +from cvec import CVec +from cvec.models.agent_post import AgentPostRecommendation, RecommendationType + + +def main() -> None: + # Initialize CVec client + cvec = CVec( + host=os.environ.get("CVEC_HOST", "https://your-subdomain.cvector.dev"), + api_key=os.environ.get("CVEC_API_KEY", "your-api-key"), + ) + + recommendations = [ + AgentPostRecommendation( + content="Critical recommendation", + recommendation_type=RecommendationType.CRITICAL, + ), + AgentPostRecommendation( + content="Warning recommendation", + recommendation_type=RecommendationType.WARNING, + ), + AgentPostRecommendation( + content="Info recommendation", + recommendation_type=RecommendationType.INFO, + ), + ] + + cvec.add_agent_post( + title="Test post", + author="Operational Agent", + image_id=str(uuid.uuid4()), # Replace with actual image UUID uploaded to S3 + content="SDK add post test.", + recommendations=recommendations, + ) + + +if __name__ == "__main__": + main() diff --git a/src/cvec/cvec.py b/src/cvec/cvec.py index eacb6a7..40d4da2 100644 --- a/src/cvec/cvec.py +++ b/src/cvec/cvec.py @@ -7,6 +7,7 @@ from urllib.parse import urlencode, urljoin from urllib.request import Request, urlopen +from cvec.models.agent_post import AgentPostRecommendation from cvec.models.metric import Metric, MetricDataPoint from cvec.models.span import Span from cvec.utils.arrow_converter import ( @@ -418,6 +419,36 @@ def get_modeling_metrics_data_arrow( assert isinstance(result, bytes) return result + def add_agent_post( + self, + title: str, + author: str, + image_id: Optional[str] = None, + content: Optional[str] = None, + recommendations: Optional[List[AgentPostRecommendation]] = None, + ) -> None: + """ + Add an agent post. + + Note: If image_id is provided, the image must be uploaded to S3 beforehand. + The image_id should be the UUID used as the filename (without .png extension) + in the S3 bucket at the tenant's path. + """ + + payload: Dict[str, Any] = { + "image_id": image_id, + "author": author, + "title": title, + "content": content, + } + + if recommendations: + payload["recommendations"] = [rec.model_dump(mode="json") for rec in recommendations] + + self._make_request( + "POST", "/api/agent_posts/add", json_data=payload + ) + def _login_with_supabase(self, email: str, password: str) -> None: """ Login to Supabase and get access/refresh tokens. diff --git a/src/cvec/models/__init__.py b/src/cvec/models/__init__.py index e3172fd..22365e9 100644 --- a/src/cvec/models/__init__.py +++ b/src/cvec/models/__init__.py @@ -1,8 +1,16 @@ +from .agent_post import ( + AgentPost, + AgentPostRecommendation, + RecommendationType, +) from .metric import Metric, MetricDataPoint from .span import Span __all__ = [ + "AgentPost", + "AgentPostRecommendation", "Metric", "MetricDataPoint", + "RecommendationType", "Span", ] diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py new file mode 100644 index 0000000..ee24447 --- /dev/null +++ b/src/cvec/models/agent_post.py @@ -0,0 +1,34 @@ +from datetime import datetime +from enum import Enum +from typing import List, Optional +from uuid import UUID + +from pydantic import BaseModel, ConfigDict, Field + + +class RecommendationType(str, Enum): + """Type of recommendation.""" + + CRITICAL = "critical" + WARNING = "warning" + INFO = "info" + + +class AgentPostRecommendation(BaseModel): + """ + Represents a recommendation for creating an agent post. + """ + + content: str = Field(..., min_length=1) + recommendation_type: RecommendationType + +class AgentPost(BaseModel): + """ + Represents an agent post with optional recommendations. + """ + + author: str + title: str + content: Optional[str] = None + image_id: Optional[UUID] = None + recommendations: Optional[List[AgentPostRecommendation]] = None From cf7f01b86cb6b9e1533b2b9bcc30f2d7134227fd Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 09:31:17 -0500 Subject: [PATCH 2/8] feat: add tags to request and rename recommendation type --- examples/add_agent_post_example.py | 20 ++++++++++++++++---- src/cvec/cvec.py | 6 +++++- src/cvec/models/__init__.py | 4 ++++ src/cvec/models/agent_post.py | 23 +++++++++++++++++++---- 4 files changed, 44 insertions(+), 9 deletions(-) diff --git a/examples/add_agent_post_example.py b/examples/add_agent_post_example.py index c05e7bd..186f87a 100644 --- a/examples/add_agent_post_example.py +++ b/examples/add_agent_post_example.py @@ -2,7 +2,7 @@ import uuid from cvec import CVec -from cvec.models.agent_post import AgentPostRecommendation, RecommendationType +from cvec.models.agent_post import AgentPostRecommendation, AgentPostTag, Severity def main() -> None: @@ -15,15 +15,26 @@ def main() -> None: recommendations = [ AgentPostRecommendation( content="Critical recommendation", - recommendation_type=RecommendationType.CRITICAL, + severity=Severity.CRITICAL, ), AgentPostRecommendation( content="Warning recommendation", - recommendation_type=RecommendationType.WARNING, + severity=Severity.WARNING, ), AgentPostRecommendation( content="Info recommendation", - recommendation_type=RecommendationType.INFO, + severity=Severity.INFO, + ), + ] + + tags = [ + AgentPostTag( + content="urgent", + severity=Severity.CRITICAL, + ), + AgentPostTag( + content="monitoring", + severity=Severity.INFO, ), ] @@ -33,6 +44,7 @@ def main() -> None: image_id=str(uuid.uuid4()), # Replace with actual image UUID uploaded to S3 content="SDK add post test.", recommendations=recommendations, + tags=tags, ) diff --git a/src/cvec/cvec.py b/src/cvec/cvec.py index 40d4da2..b9da0ae 100644 --- a/src/cvec/cvec.py +++ b/src/cvec/cvec.py @@ -7,7 +7,7 @@ from urllib.parse import urlencode, urljoin from urllib.request import Request, urlopen -from cvec.models.agent_post import AgentPostRecommendation +from cvec.models.agent_post import AgentPostRecommendation, AgentPostTag from cvec.models.metric import Metric, MetricDataPoint from cvec.models.span import Span from cvec.utils.arrow_converter import ( @@ -426,6 +426,7 @@ def add_agent_post( image_id: Optional[str] = None, content: Optional[str] = None, recommendations: Optional[List[AgentPostRecommendation]] = None, + tags: Optional[List[AgentPostTag]] = None, ) -> None: """ Add an agent post. @@ -445,6 +446,9 @@ def add_agent_post( if recommendations: payload["recommendations"] = [rec.model_dump(mode="json") for rec in recommendations] + if tags: + payload["tags"] = [tag.model_dump(mode="json") for tag in tags] + self._make_request( "POST", "/api/agent_posts/add", json_data=payload ) diff --git a/src/cvec/models/__init__.py b/src/cvec/models/__init__.py index 22365e9..69694a2 100644 --- a/src/cvec/models/__init__.py +++ b/src/cvec/models/__init__.py @@ -1,7 +1,9 @@ from .agent_post import ( AgentPost, AgentPostRecommendation, + AgentPostTag, RecommendationType, + Severity, ) from .metric import Metric, MetricDataPoint from .span import Span @@ -9,8 +11,10 @@ __all__ = [ "AgentPost", "AgentPostRecommendation", + "AgentPostTag", "Metric", "MetricDataPoint", "RecommendationType", + "Severity", "Span", ] diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index ee24447..8970c42 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -6,25 +6,39 @@ from pydantic import BaseModel, ConfigDict, Field -class RecommendationType(str, Enum): - """Type of recommendation.""" +class Severity(str, Enum): + """Severity level for recommendations and tags.""" CRITICAL = "critical" WARNING = "warning" INFO = "info" +# Deprecated: Use Severity instead +RecommendationType = Severity + + class AgentPostRecommendation(BaseModel): """ Represents a recommendation for creating an agent post. """ content: str = Field(..., min_length=1) - recommendation_type: RecommendationType + severity: Severity + + +class AgentPostTag(BaseModel): + """ + Represents a tag for creating an agent post. + """ + + content: str = Field(..., min_length=1) + severity: Severity + class AgentPost(BaseModel): """ - Represents an agent post with optional recommendations. + Represents an agent post with optional recommendations and tags. """ author: str @@ -32,3 +46,4 @@ class AgentPost(BaseModel): content: Optional[str] = None image_id: Optional[UUID] = None recommendations: Optional[List[AgentPostRecommendation]] = None + tags: Optional[List[AgentPostTag]] = None From 179d173dd156b357d20cb35238bffd66c8d12b76 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 17:51:30 -0500 Subject: [PATCH 3/8] chore: remove unused type definition --- src/cvec/models/agent_post.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index 8970c42..35e80d0 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -13,11 +13,6 @@ class Severity(str, Enum): WARNING = "warning" INFO = "info" - -# Deprecated: Use Severity instead -RecommendationType = Severity - - class AgentPostRecommendation(BaseModel): """ Represents a recommendation for creating an agent post. From 4595a0bdbc5dcc38c2d3a5efc6a4d8f5d0dc0b12 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 17:56:46 -0500 Subject: [PATCH 4/8] fix: lint fix --- src/cvec/models/agent_post.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index 35e80d0..0510f38 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -1,9 +1,8 @@ -from datetime import datetime from enum import Enum from typing import List, Optional from uuid import UUID -from pydantic import BaseModel, ConfigDict, Field +from pydantic import BaseModel, Field class Severity(str, Enum): From c92f35051fbe318edef1134dcac9dbb0abe05dd5 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 17:57:56 -0500 Subject: [PATCH 5/8] fix: fix type definitions Co-authored-by: gemini-code-assist[bot] <176961590+gemini-code-assist[bot]@users.noreply.github.com> --- src/cvec/models/agent_post.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index 0510f38..0a3ef4c 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -38,6 +38,6 @@ class AgentPost(BaseModel): author: str title: str content: Optional[str] = None - image_id: Optional[UUID] = None + image_id: Optional[str] = None recommendations: Optional[List[AgentPostRecommendation]] = None tags: Optional[List[AgentPostTag]] = None From 575b7334783f98eea78683f0ae0df17ff153b080 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 18:05:44 -0500 Subject: [PATCH 6/8] fix: remove old types + add pydantic model --- src/cvec/cvec.py | 23 ++++++++++------------- src/cvec/models/__init__.py | 2 -- 2 files changed, 10 insertions(+), 15 deletions(-) diff --git a/src/cvec/cvec.py b/src/cvec/cvec.py index 26422cc..5e55c0a 100644 --- a/src/cvec/cvec.py +++ b/src/cvec/cvec.py @@ -7,7 +7,7 @@ from urllib.parse import urlencode, urljoin from urllib.request import Request, urlopen -from cvec.models.agent_post import AgentPostRecommendation, AgentPostTag +from cvec.models.agent_post import AgentPost, AgentPostRecommendation, AgentPostTag from cvec.models.eav_column import EAVColumn from cvec.models.eav_filter import EAVFilter from cvec.models.eav_table import EAVTable @@ -444,18 +444,15 @@ def add_agent_post( in the S3 bucket at the tenant's path. """ - payload: Dict[str, Any] = { - "image_id": image_id, - "author": author, - "title": title, - "content": content, - } - - if recommendations: - payload["recommendations"] = [rec.model_dump(mode="json") for rec in recommendations] - - if tags: - payload["tags"] = [tag.model_dump(mode="json") for tag in tags] + post = AgentPost( + title=title, + author=author, + image_id=image_id, + content=content, + recommendations=recommendations, + tags=tags, + ) + payload = post.model_dump(mode="json", exclude_none=True) self._make_request( "POST", "/api/agent_posts/add", json_data=payload diff --git a/src/cvec/models/__init__.py b/src/cvec/models/__init__.py index 03e79b4..5986c12 100644 --- a/src/cvec/models/__init__.py +++ b/src/cvec/models/__init__.py @@ -2,7 +2,6 @@ AgentPost, AgentPostRecommendation, AgentPostTag, - RecommendationType, Severity, ) from .eav_column import EAVColumn @@ -20,7 +19,6 @@ "EAVTable", "Metric", "MetricDataPoint", - "RecommendationType", "Severity", "Span", ] From 578b01a1fdd03454cf672594e9801f504ac9ea9e Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 18:08:30 -0500 Subject: [PATCH 7/8] fix: lint fix --- src/cvec/models/agent_post.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index 0a3ef4c..465c635 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -1,6 +1,5 @@ from enum import Enum from typing import List, Optional -from uuid import UUID from pydantic import BaseModel, Field From fac44540cb5ff84b1f55944dea359dbc8ac0c9a4 Mon Sep 17 00:00:00 2001 From: Amy Ni Date: Wed, 3 Dec 2025 18:10:59 -0500 Subject: [PATCH 8/8] fix: ruff fix --- src/cvec/cvec.py | 4 +--- src/cvec/models/agent_post.py | 1 + 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cvec/cvec.py b/src/cvec/cvec.py index 5e55c0a..19a6ef4 100644 --- a/src/cvec/cvec.py +++ b/src/cvec/cvec.py @@ -454,9 +454,7 @@ def add_agent_post( ) payload = post.model_dump(mode="json", exclude_none=True) - self._make_request( - "POST", "/api/agent_posts/add", json_data=payload - ) + self._make_request("POST", "/api/agent_posts/add", json_data=payload) def _login_with_supabase(self, email: str, password: str) -> None: """ diff --git a/src/cvec/models/agent_post.py b/src/cvec/models/agent_post.py index 465c635..6d3eccc 100644 --- a/src/cvec/models/agent_post.py +++ b/src/cvec/models/agent_post.py @@ -11,6 +11,7 @@ class Severity(str, Enum): WARNING = "warning" INFO = "info" + class AgentPostRecommendation(BaseModel): """ Represents a recommendation for creating an agent post.