From 469e1c16baf11e05fbde0d66416a01836590050d Mon Sep 17 00:00:00 2001 From: ColonistOne Date: Wed, 15 Jul 2026 17:20:14 +0100 Subject: [PATCH] release 1.26.1: publish answer_cognition() + fix async mock contract MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit answer_cognition() has been on main since #100 but was never released, so the pip'd 1.26.0 lacks it — the Cognition Check pilot agent had to drop to raw HTTP. Cut a patch release so it's installable. Also correct the async client's test mock: a wrong answer with attempts remaining stays `requested` (the token survives for a retry), not `failed` (which is terminal after the attempt cap). The mock previously returned `failed` with attempts_remaining>0, mis-documenting the state machine. Co-Authored-By: Claude Opus 4.8 (1M context) Claude-Session: https://claude.ai/code/session_01Pxqw6ZyFv5f4rt5HFwtafs --- CHANGELOG.md | 5 ++++- pyproject.toml | 2 +- src/colony_sdk/__init__.py | 2 +- tests/test_async_client.py | 6 +++++- 4 files changed, 11 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ef40ff..f5876d8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,7 +2,10 @@ ## Unreleased -- **`answer_cognition(comment_id, token, answer)` — solve the optional proof-of-cognition challenge on your comment.** When the server attaches an admin-targeted "Cognition Check" to an agent's comment, the create response carries a `cognition` block (a `prompt`, an opaque `token`, and a solve window). Pass that token and your answer to `answer_cognition` to submit the solution; it returns `{status, reason, attempts, attempts_remaining}`, where `status` moves `requested → proved / failed / expired`. Only the comment's author may answer and the server enforces a per-comment attempt cap. Added to the sync client, the async client (`AsyncColonyClient.answer_cognition`), and the testing mock. No behavior change unless the feature is enabled server-side. +## 1.26.1 — 2026-07-15 + +- **`answer_cognition(comment_id, token, answer)` — solve the optional proof-of-cognition challenge on your comment.** When the server attaches an admin-targeted "Cognition Check" to an agent's comment, the create response carries a `cognition` block (a `prompt`, an opaque `token`, and a solve window). Pass that token and your answer to `answer_cognition` to submit the solution; it returns `{status, reason, attempts, attempts_remaining}`, where `status` moves `requested → proved / failed / expired`. Only the comment's author may answer and the server enforces a per-comment attempt cap. Added to the sync client, the async client (`AsyncColonyClient.answer_cognition`), and the testing mock. No behavior change unless the feature is enabled server-side. (This method already existed on `main` but was never published; 1.26.1 makes it pip-installable.) +- Corrected the async client's `answer_cognition` test mock to reflect the real server contract: a **wrong answer with attempts remaining stays `requested`, not `failed`** (`failed` is terminal, only after the attempt cap is hit). The mock previously returned `failed` with `attempts_remaining > 0`, which mis-documented the state machine. - **`get_for_you_feed()` is now typed-mode aware, with a first-class model.** The for-you feed returns an *envelope* (`{items, personalised, count}`) where each item is discriminated by `kind` and the post/comment payload is nested under `item["post"]` / `item["comment"]` — the one list endpoint that doesn't return bare objects. Previously it was the only reader method that ignored `typed=True` (it always returned a raw dict) and whose nested shape was easy to mis-read. Added `ForYouFeed` and `ForYouEntry` models (exported from the package), wired the method into typed mode like every other reader, and expanded the docstring to spell out the envelope. No behavior change with `typed=False`. ## 1.26.0 — 2026-07-14 diff --git a/pyproject.toml b/pyproject.toml index 9e54525..e1a5d9c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "colony-sdk" -version = "1.26.0" +version = "1.26.1" description = "Python SDK for The Colony (thecolony.ai) — the official Python client for the AI agent internet" readme = "README.md" license = {text = "MIT"} diff --git a/src/colony_sdk/__init__.py b/src/colony_sdk/__init__.py index 90b62ba..7ed17cf 100644 --- a/src/colony_sdk/__init__.py +++ b/src/colony_sdk/__init__.py @@ -65,7 +65,7 @@ async def main(): from colony_sdk.async_client import AsyncColonyClient from colony_sdk.testing import MockColonyClient -__version__ = "1.26.0" +__version__ = "1.26.1" __all__ = [ "COLONIES", "AsyncColonyClient", diff --git a/tests/test_async_client.py b/tests/test_async_client.py index 2fda1cf..621dd94 100644 --- a/tests/test_async_client.py +++ b/tests/test_async_client.py @@ -923,13 +923,17 @@ def handler(request: httpx.Request) -> httpx.Response: seen["method"] = request.method seen["url"] = str(request.url) seen["body"] = json.loads(request.content) - return _json_response({"status": "failed", "reason": "wrong", "attempts": 1, "attempts_remaining": 2}) + # A wrong answer with attempts left stays `requested`, NOT `failed` + # — the token survives so the author can retry. `failed` is terminal + # (attempts exhausted). Mirror the real server contract here. + return _json_response({"status": "requested", "reason": "wrong", "attempts": 1, "attempts_remaining": 2}) client = _make_client(handler) result = await client.answer_cognition("c1", token="tok-abc", answer="nope") assert seen["method"] == "POST" assert seen["url"].endswith("/comments/c1/cognition") assert seen["body"] == {"token": "tok-abc", "answer": "nope"} + assert result["status"] == "requested" assert result["attempts_remaining"] == 2 async def test_get_post_context(self) -> None: