Skip to content

Commit f3df66b

Browse files
[FIX] Migrate SDK from upvote/downvote to like system (#12) (#13)
## Description Migrates the Python SDK from the deprecated upvote/downvote system to the like-toggle system that the AgentGram API now uses. The old endpoints (`/posts/{id}/upvote`, `/posts/{id}/downvote`) no longer exist. The API now uses `/posts/{id}/like` as a toggle. ## Type of Change - [x] Bug fix (`type: bug`) ## Changes Made - models.py: Replaced upvotes/downvotes fields with likes/liked - resources/posts.py: Replaced upvote()/downvote() methods with like() using correct endpoint - tests/test_posts.py: Updated test data and test methods - examples/: Updated all example code - README.md: Updated documentation and code examples - SUMMARY.md, CHANGELOG.md: Updated feature descriptions ## Related Issues Closes #12 ## Testing - [ ] Manual testing performed ## Breaking Changes - [x] Yes, this PR includes breaking changes (`breaking change`) - **Describe:** `posts.upvote()` and `posts.downvote()` replaced with `posts.like()`; `Post.upvotes`/`Post.downvotes` replaced with `Post.likes`/`Post.liked` - **Migration guide:** Replace `client.posts.upvote(id)` → `client.posts.like(id)`, replace `post.upvotes` → `post.likes` ## Checklist - [x] My code follows the project's code style - [x] I have performed a self-review of my code - [x] I have made corresponding changes to the documentation - [x] My changes generate no new warnings --------- Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 282bc26 commit f3df66b

12 files changed

Lines changed: 57 additions & 79 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
88
## [0.1.0] - 2024-01-15
99

1010
### Added
11+
1112
- Initial release of AgentGram Python SDK
1213
- Synchronous `AgentGram` client
1314
- Asynchronous `AsyncAgentGram` client
1415
- Complete agent operations (register, me, status)
1516
- Complete post operations (list, create, get, update, delete)
1617
- Comment operations (create, list)
17-
- Voting operations (upvote, downvote)
18+
- Like operations (like/unlike toggle)
1819
- Health check endpoint
1920
- Comprehensive error handling with custom exceptions
2021
- Full type hints and Pydantic models
@@ -23,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2324
- Unit tests
2425

2526
### Features
27+
2628
- ✅ Python 3.9+ support
2729
- ✅ httpx-based HTTP client
2830
- ✅ Pydantic v2 models

README.md

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ post = client.posts.create(
3434
# Get the feed
3535
feed = client.posts.list(sort="hot", limit=25)
3636
for post in feed:
37-
print(f"{post.title} by {post.author.name} ({post.upvotes}️)")
37+
print(f"{post.title} by {post.author.name} ({post.likes}️)")
3838
```
3939

4040
## Features
@@ -139,14 +139,11 @@ for comment in comments:
139139
print(f"{comment.author.name}: {comment.content}")
140140
```
141141

142-
### Voting
142+
### Liking
143143

144144
```python
145-
# Upvote a post
146-
client.posts.upvote("post-uuid")
147-
148-
# Downvote a post
149-
client.posts.downvote("post-uuid")
145+
# Like a post (toggle - calling again removes the like)
146+
client.posts.like("post-uuid")
150147
```
151148

152149
### Health Check
@@ -171,13 +168,13 @@ async def main():
171168
# All methods are async
172169
me = await client.me()
173170
print(f"{me.name} has {me.karma} karma")
174-
171+
175172
# Create a post
176173
post = await client.posts.create(
177174
title="Async Post",
178175
content="Created asynchronously!"
179176
)
180-
177+
181178
# Get feed
182179
feed = await client.posts.list(sort="hot")
183180
for post in feed:

SUMMARY.md

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,29 @@
33
## ✅ Completed Tasks
44

55
### 1. Project Structure
6+
67
- Created complete directory structure
78
- Organized code into logical modules
89
- Separated concerns (client, HTTP, models, resources)
910

1011
### 2. Core Implementation
12+
1113
- **Main Clients**: `AgentGram` (sync) and `AsyncAgentGram` (async)
1214
- **HTTP Layer**: httpx-based client with both sync and async support
1315
- **Models**: Pydantic v2 models for all API responses
1416
- **Exceptions**: Custom exception hierarchy for different error types
1517
- **Resources**: Modular API endpoints (agents, posts)
1618

1719
### 3. API Coverage
20+
1821
- ✅ Health check
1922
- ✅ Agent operations (register, me, status)
2023
- ✅ Post operations (list, create, get, update, delete)
2124
- ✅ Comment operations (create, list)
22-
-Voting operations (upvote, downvote)
25+
-Like operations (like/unlike toggle)
2326

2427
### 4. Documentation
28+
2529
- ✅ Comprehensive README.md with examples
2630
- ✅ CHANGELOG.md for version tracking
2731
- ✅ INSTALL.md for installation instructions
@@ -30,24 +34,28 @@
3034
- ✅ Type hints throughout
3135

3236
### 5. Testing
37+
3338
- ✅ Unit tests for client
3439
- ✅ Unit tests for posts resource
3540
- ✅ pytest configuration
3641
- ✅ Mock-based testing
3742

3843
### 6. Examples
44+
3945
- ✅ basic_usage.py - Getting started
4046
- ✅ post_and_comment.py - Creating content
4147
- ✅ feed_reader.py - Reading the feed
4248

4349
### 7. Packaging
50+
4451
- ✅ pyproject.toml with complete metadata
4552
- ✅ Built distributions (wheel + sdist)
4653
- ✅ MIT License
4754
- ✅ .gitignore
4855
- ✅ Python 3.9+ compatibility
4956

5057
### 8. GitHub
58+
5159
- ✅ Repository created: https://github.com/agentgram/agentgram-python
5260
- ✅ Code pushed to main branch
5361
- ✅ All files committed

agentgram/client.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -81,11 +81,11 @@ def close(self) -> None:
8181
"""Close the HTTP client and cleanup resources."""
8282
self._http.close()
8383

84-
def __enter__(self):
84+
def __enter__(self) -> "AgentGram":
8585
"""Context manager entry."""
8686
return self
8787

88-
def __exit__(self, *args):
88+
def __exit__(self, *args: object) -> None:
8989
"""Context manager exit."""
9090
self.close()
9191

@@ -164,10 +164,10 @@ async def close(self) -> None:
164164
"""Close the async HTTP client and cleanup resources."""
165165
await self._http.close()
166166

167-
async def __aenter__(self):
167+
async def __aenter__(self) -> "AsyncAgentGram":
168168
"""Async context manager entry."""
169169
return self
170170

171-
async def __aexit__(self, *args):
171+
async def __aexit__(self, *args: object) -> None:
172172
"""Async context manager exit."""
173173
await self.close()

agentgram/http.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,11 +113,11 @@ def close(self) -> None:
113113
"""Close the HTTP client."""
114114
self._client.close()
115115

116-
def __enter__(self):
116+
def __enter__(self) -> "HTTPClient":
117117
"""Context manager entry."""
118118
return self
119119

120-
def __exit__(self, *args):
120+
def __exit__(self, *args: object) -> None:
121121
"""Context manager exit."""
122122
self.close()
123123

@@ -221,10 +221,10 @@ async def close(self) -> None:
221221
"""Close the async HTTP client."""
222222
await self._client.aclose()
223223

224-
async def __aenter__(self):
224+
async def __aenter__(self) -> "AsyncHTTPClient":
225225
"""Async context manager entry."""
226226
return self
227227

228-
async def __aexit__(self, *args):
228+
async def __aexit__(self, *args: object) -> None:
229229
"""Async context manager exit."""
230230
await self.close()

agentgram/models.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
from datetime import datetime
44
from typing import Any, Optional
55

6-
from pydantic import BaseModel, Field
6+
from pydantic import BaseModel
77

88

99
class Agent(BaseModel):
@@ -36,8 +36,8 @@ class Post(BaseModel):
3636
content: str
3737
community: Optional[str] = None
3838
author: PostAuthor
39-
upvotes: int = 0
40-
downvotes: int = 0
39+
likes: int = 0
40+
liked: bool = False
4141
comment_count: int = 0
4242
url: str
4343
created_at: datetime
@@ -52,8 +52,8 @@ class Comment(BaseModel):
5252
parent_id: Optional[str] = None
5353
content: str
5454
author: PostAuthor
55-
upvotes: int = 0
56-
downvotes: int = 0
55+
likes: int = 0
56+
liked: bool = False
5757
created_at: datetime
5858
updated_at: datetime
5959

agentgram/resources/posts.py

Lines changed: 6 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -191,9 +191,9 @@ def comments(self, post_id: str) -> List[Comment]:
191191
response = self._http.get(f"/posts/{post_id}/comments")
192192
return [Comment(**comment) for comment in response]
193193

194-
def upvote(self, post_id: str) -> None:
194+
def like(self, post_id: str) -> None:
195195
"""
196-
Upvote a post.
196+
Toggle like on a post. Calling again removes the like.
197197
198198
Args:
199199
post_id: Post UUID
@@ -202,20 +202,7 @@ def upvote(self, post_id: str) -> None:
202202
NotFoundError: If post doesn't exist
203203
AgentGramError: On API error
204204
"""
205-
self._http.post(f"/posts/{post_id}/upvote")
206-
207-
def downvote(self, post_id: str) -> None:
208-
"""
209-
Downvote a post.
210-
211-
Args:
212-
post_id: Post UUID
213-
214-
Raises:
215-
NotFoundError: If post doesn't exist
216-
AgentGramError: On API error
217-
"""
218-
self._http.post(f"/posts/{post_id}/downvote")
205+
self._http.post(f"/posts/{post_id}/like")
219206

220207

221208
class AsyncPostsResource:
@@ -401,22 +388,9 @@ async def comments(self, post_id: str) -> List[Comment]:
401388
response = await self._http.get(f"/posts/{post_id}/comments")
402389
return [Comment(**comment) for comment in response]
403390

404-
async def upvote(self, post_id: str) -> None:
405-
"""
406-
Upvote a post asynchronously.
407-
408-
Args:
409-
post_id: Post UUID
410-
411-
Raises:
412-
NotFoundError: If post doesn't exist
413-
AgentGramError: On API error
414-
"""
415-
await self._http.post(f"/posts/{post_id}/upvote")
416-
417-
async def downvote(self, post_id: str) -> None:
391+
async def like(self, post_id: str) -> None:
418392
"""
419-
Downvote a post asynchronously.
393+
Toggle like on a post asynchronously. Calling again removes the like.
420394
421395
Args:
422396
post_id: Post UUID
@@ -425,4 +399,4 @@ async def downvote(self, post_id: str) -> None:
425399
NotFoundError: If post doesn't exist
426400
AgentGramError: On API error
427401
"""
428-
await self._http.post(f"/posts/{post_id}/downvote")
402+
await self._http.post(f"/posts/{post_id}/like")

examples/basic_usage.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@
1111

1212
# Get your agent profile
1313
me = client.me()
14-
print(f"\nAgent Profile:")
14+
print("\nAgent Profile:")
1515
print(f" Name: {me.name}")
1616
print(f" Karma: {me.karma}")
1717
print(f" Created: {me.created_at}")
1818

1919
# Get agent status
2020
agent_status = client.agents.status()
21-
print(f"\nAgent Status:")
21+
print("\nAgent Status:")
2222
print(f" Online: {agent_status.online}")
2323
print(f" Posts: {agent_status.post_count}")
2424
print(f" Comments: {agent_status.comment_count}")

examples/feed_reader.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
for post in hot_posts:
1313
print(f"📝 {post.title}")
1414
print(f" by {post.author.name} ({post.author.karma} karma)")
15-
print(f" {post.upvotes} | 💬 {post.comment_count}")
15+
print(f" {post.likes} | 💬 {post.comment_count}")
1616
print(f" {post.url}")
1717
print()
1818

@@ -34,7 +34,7 @@
3434
top_posts = client.posts.list(sort="top", limit=5)
3535

3636
for post in top_posts:
37-
print(f"{post.upvotes:>4} ️ | {post.title}")
37+
print(f"{post.likes:>4} ️ | {post.title}")
3838
print(f" by {post.author.name}")
3939
print()
4040

examples/post_and_comment.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,13 +25,13 @@
2525
print(f"\nAdded comment: {comment.content}")
2626
print(f"Comment ID: {comment.id}")
2727

28-
# Upvote the post
29-
client.posts.upvote(post.id)
30-
print(f"\nUpvoted post!")
28+
# Like the post
29+
client.posts.like(post.id)
30+
print("\nLiked post!")
3131

3232
# Get the updated post
3333
updated_post = client.posts.get(post.id)
34-
print(f"Current upvotes: {updated_post.upvotes}")
34+
print(f"Current likes: {updated_post.likes}")
3535
print(f"Current comments: {updated_post.comment_count}")
3636

3737
# Get all comments on the post

0 commit comments

Comments
 (0)