diff --git a/docs/changelog/compatibility-guide.mdx b/docs/changelog/compatibility-guide.mdx
index 33e01f7f..719ea184 100644
--- a/docs/changelog/compatibility-guide.mdx
+++ b/docs/changelog/compatibility-guide.mdx
@@ -4,27 +4,23 @@ description: "Compatibility guide for Honcho's SDKs and API"
icon: "shield-check"
---
-This guide helps you understand which versions of Honcho's API are compatible with which SDK versions.
+This guide helps you match the right SDK version to your Honcho API version. Newer SDK patch versions are always backward-compatible within the same major version — install the latest patch for your range.
-## Version Compatibility
-
-### Honcho API v3.0.2 (Current)
+## Current Versions
- **Compatible Version:** v2.0.0
+ **Latest:** v2.0.1
- Install with:
```bash
- npm install @honcho-ai/sdk@2.0.0
+ npm install @honcho-ai/sdk
```
- **Compatible Version:** v2.0.0
+ **Latest:** v2.0.1
- Install with:
```bash
- pip install honcho-ai==2.0.0
+ pip install honcho-ai
```
@@ -34,9 +30,9 @@ This guide helps you understand which versions of Honcho's API are compatible wi
| Honcho API Version | TypeScript SDK | Python SDK |
|-------------------|---------------|------------|
-| v3.0.2 (Current) | v2.0.0 | v2.0.0 |
-| v3.0.1 | v2.0.0 | v2.0.0 |
-| v3.0.0 | v2.0.0 | v2.0.0 |
+| v3.0.2 (Current) | v2.0.0+ | v2.0.0+ |
+| v3.0.1 | v2.0.0+ | v2.0.0+ |
+| v3.0.0 | v2.0.0+ | v2.0.0+ |
| v2.5.1 | v1.6.0 | v1.6.0 |
| v2.5.0 | v1.6.0 | v1.6.0 |
| v2.4.3 | v1.5.0 | v1.5.0 |
diff --git a/sdks/python/pyproject.toml b/sdks/python/pyproject.toml
index 20204d04..dd389d96 100644
--- a/sdks/python/pyproject.toml
+++ b/sdks/python/pyproject.toml
@@ -1,6 +1,6 @@
[project]
name = "honcho-ai"
-version = "2.0.0"
+version = "2.0.1"
description = "Official DX Optimized Python SDK for Honcho"
dynamic = ["readme"]
license = "Apache-2.0"
diff --git a/sdks/python/src/honcho/__init__.py b/sdks/python/src/honcho/__init__.py
index cf8d8bb5..35f42dce 100644
--- a/sdks/python/src/honcho/__init__.py
+++ b/sdks/python/src/honcho/__init__.py
@@ -66,7 +66,7 @@ from .types import (
DialecticStreamResponse,
)
-__version__ = "2.0.0"
+__version__ = "2.0.1"
__author__ = "Plastic Labs"
__email__ = "hello@plasticlabs.ai"
diff --git a/sdks/python/src/honcho/aio.py b/sdks/python/src/honcho/aio.py
index 1d72946a..2d02418e 100644
--- a/sdks/python/src/honcho/aio.py
+++ b/sdks/python/src/honcho/aio.py
@@ -604,6 +604,25 @@ class PeerAio(AsyncMetadataConfigMixin):
response = PeerCardResponse.model_validate(data)
return response.peer_card
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
+ async def set_card(
+ self,
+ peer_card: list[str],
+ target: str | PeerBase | None = None,
+ ) -> list[str] | None:
+ """Set the peer card asynchronously."""
+ await self._peer._honcho._ensure_workspace_async()
+ target_id = resolve_id(target)
+
+ query = {"target": target_id} if target_id else None
+ data = await self._peer._honcho._async_http_client.put(
+ routes.peer_card(self._peer.workspace_id, self._peer.id),
+ body={"peer_card": peer_card},
+ query=query,
+ )
+ response = PeerCardResponse.model_validate(data)
+ return response.peer_card
+
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
async def representation(
self,
diff --git a/sdks/python/src/honcho/peer.py b/sdks/python/src/honcho/peer.py
index ea71fc79..f53542c1 100644
--- a/sdks/python/src/honcho/peer.py
+++ b/sdks/python/src/honcho/peer.py
@@ -476,6 +476,38 @@ class Peer(PeerBase, MetadataConfigMixin):
return response.peer_card
+ @validate_call(config=ConfigDict(arbitrary_types_allowed=True))
+ def set_card(
+ self,
+ peer_card: list[str],
+ target: str | PeerBase | None = None,
+ ) -> list[str] | None:
+ """
+ Set the peer card for this peer.
+
+ Makes an API call to set the peer card. If a target is provided, sets this
+ peer's local card of the target peer.
+
+ Args:
+ peer_card: A list of strings to set as the peer card.
+ target: Optional target peer for local card. If provided, sets this
+ peer's card of the target peer. Can be a Peer object or peer ID string.
+
+ Returns:
+ A list of strings representing the updated peer card, or None if none is available
+ """
+ self._honcho._ensure_workspace()
+ target_id = resolve_id(target)
+
+ query = {"target": target_id} if target_id else None
+ data = self._honcho._http.put(
+ routes.peer_card(self.workspace_id, self.id),
+ body={"peer_card": peer_card},
+ query=query,
+ )
+ response = PeerCardResponse.model_validate(data)
+ return response.peer_card
+
@validate_call(config=ConfigDict(arbitrary_types_allowed=True))
def representation(
self,
diff --git a/sdks/typescript/__tests__/peer.test.ts b/sdks/typescript/__tests__/peer.test.ts
index 9a3b3b61..35f0b32e 100644
--- a/sdks/typescript/__tests__/peer.test.ts
+++ b/sdks/typescript/__tests__/peer.test.ts
@@ -430,6 +430,48 @@ describe('Peer', () => {
})
})
+ // ===========================================================================
+ // Set Peer Card (PUT /peers/:id/card)
+ // ===========================================================================
+
+ describe('PUT /peers/:id/card', () => {
+ test('setCard sets and returns peer card', async () => {
+ const peer = await client.peer('setcard-peer')
+
+ const cardData = ['fact one', 'fact two']
+ const result = await peer.setCard(cardData)
+
+ expect(result).toEqual(cardData)
+
+ // Verify with get
+ const card = await peer.card()
+ expect(card).toEqual(cardData)
+ })
+
+ test('setCard with target peer', async () => {
+ const observer = await client.peer('setcard-observer')
+ const observed = await client.peer('setcard-observed')
+
+ const cardData = ['target likes TypeScript', 'target is clever']
+ const result = await observer.setCard(cardData, observed)
+
+ expect(result).toEqual(cardData)
+
+ // Verify with get
+ const card = await observer.card(observed)
+ expect(card).toEqual(cardData)
+ })
+
+ test('setCard with target ID string', async () => {
+ const peer = await client.peer('setcard-string-peer')
+
+ const cardData = ['some fact']
+ const result = await peer.setCard(cardData, 'setcard-string-target')
+
+ expect(result).toEqual(cardData)
+ })
+ })
+
// ===========================================================================
// Peer Context (POST /peers/:id/context)
// ===========================================================================
diff --git a/sdks/typescript/package.json b/sdks/typescript/package.json
index 956066ed..618a0acf 100644
--- a/sdks/typescript/package.json
+++ b/sdks/typescript/package.json
@@ -1,6 +1,6 @@
{
"name": "@honcho-ai/sdk",
- "version": "2.0.0",
+ "version": "2.0.1",
"description": "Official DX Optimized TypeScript SDK for Honcho",
"author": "Plastic Labs ",
"license": "Apache-2.0",
diff --git a/sdks/typescript/src/peer.ts b/sdks/typescript/src/peer.ts
index 2ce07468..9d81453b 100644
--- a/sdks/typescript/src/peer.ts
+++ b/sdks/typescript/src/peer.ts
@@ -295,6 +295,18 @@ export class Peer {
)
}
+ private async _setCard(params: {
+ peer_card: string[]
+ target?: string
+ }): Promise {
+ await this._ensureWorkspace()
+ const { peer_card, ...query } = params
+ return this._http.put(
+ `/${API_VERSION}/workspaces/${this.workspaceId}/peers/${this.id}/card`,
+ { body: { peer_card }, query }
+ )
+ }
+
// ===========================================================================
// Public Methods
// ===========================================================================
@@ -662,6 +674,30 @@ export class Peer {
return response.peer_card
}
+ /**
+ * Set the peer card for this peer.
+ *
+ * Makes an API call to set the peer card. If a target is provided, sets this
+ * peer's local card of the target peer.
+ *
+ * @param peerCard - An array of strings to set as the peer card.
+ * @param target - Optional target peer for local card. If provided, sets this
+ * peer's card of the target peer. Can be a Peer object or peer ID string.
+ * @returns Promise resolving to an array of strings containing the updated peer card items,
+ * or null if no peer card exists
+ */
+ async setCard(
+ peerCard: string[],
+ target?: string | Peer
+ ): Promise {
+ const validatedTarget = CardTargetSchema.parse(target)
+ const response = await this._setCard({
+ peer_card: peerCard,
+ target: validatedTarget,
+ })
+ return response.peer_card
+ }
+
/**
* Get a subset of Honcho's Representation of a peer.
*
diff --git a/tests/routes/test_peers.py b/tests/routes/test_peers.py
index 84f23887..c8047f02 100644
--- a/tests/routes/test_peers.py
+++ b/tests/routes/test_peers.py
@@ -909,3 +909,52 @@ async def test_get_peer_card_with_data(
assert response.status_code == 200
data = response.json()
assert data["peer_card"] == target_card_content
+
+
+def test_set_peer_card(client: TestClient, sample_data: tuple[Workspace, Peer]):
+ """Test setting peer cards via the PUT endpoint."""
+ test_workspace, observer_peer = sample_data
+
+ # Create a target peer
+ target_peer_name = str(generate_nanoid())
+ response = client.post(
+ f"/v3/workspaces/{test_workspace.name}/peers",
+ json={"name": target_peer_name},
+ )
+ assert response.status_code in [200, 201]
+
+ # Set the observer's own card
+ self_card = ["I am a test peer", "I like writing tests"]
+ response = client.put(
+ f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
+ json={"peer_card": self_card},
+ )
+ assert response.status_code == 200
+ data = response.json()
+ assert data["peer_card"] == self_card
+
+ # Verify with GET
+ response = client.get(
+ f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card"
+ )
+ assert response.status_code == 200
+ assert response.json()["peer_card"] == self_card
+
+ # Set a card for the target peer
+ target_card = ["Target is helpful", "Target knows Python"]
+ response = client.put(
+ f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
+ params={"target": target_peer_name},
+ json={"peer_card": target_card},
+ )
+ assert response.status_code == 200
+ data = response.json()
+ assert data["peer_card"] == target_card
+
+ # Verify with GET
+ response = client.get(
+ f"/v3/workspaces/{test_workspace.name}/peers/{observer_peer.name}/card",
+ params={"target": target_peer_name},
+ )
+ assert response.status_code == 200
+ assert response.json()["peer_card"] == target_card
diff --git a/tests/sdk/sdk_integration_test.py b/tests/sdk/sdk_integration_test.py
index f5a14fe8..cffe6b1c 100644
--- a/tests/sdk/sdk_integration_test.py
+++ b/tests/sdk/sdk_integration_test.py
@@ -104,3 +104,37 @@ def test_message_and_chat_operations(honcho_test_client: Honcho):
# This is a mock response from the agent
_response = user.chat("What did I ask about?")
+
+
+def test_peer_card_operations(honcho_test_client: Honcho):
+ """
+ Tests setting and getting peer cards.
+ """
+ peer = honcho_test_client.peer(id="card-test-peer")
+ target = honcho_test_client.peer(id="card-test-target")
+
+ # Initially card should be None
+ card = peer.card()
+ assert card is None
+
+ # Set own card
+ own_card = ["I am a helpful assistant", "I enjoy learning"]
+ result = peer.set_card(own_card)
+ assert result == own_card
+
+ # Verify with get
+ card = peer.card()
+ assert card == own_card
+
+ # Set card for target
+ target_card = ["Target likes Python", "Target is friendly"]
+ result = peer.set_card(target_card, target=target)
+ assert result == target_card
+
+ # Verify with get
+ card = peer.card(target=target)
+ assert card == target_card
+
+ # Own card should still be unchanged
+ card = peer.card()
+ assert card == own_card
diff --git a/uv.lock b/uv.lock
index 634827d0..6af5c365 100644
--- a/uv.lock
+++ b/uv.lock
@@ -1136,7 +1136,7 @@ dev = [
[[package]]
name = "honcho-ai"
-version = "2.0.0"
+version = "2.0.1"
source = { editable = "sdks/python" }
dependencies = [
{ name = "httpx" },