Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
82 changes: 42 additions & 40 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,61 +1,63 @@
# Changelog

## Unreleased
## 0.6.0 (2026-04-09)

### Infrastructure

- **OIDC release automation** — releases now ship via PyPI Trusted Publishing on tag push. `git tag vX.Y.Z && git push origin vX.Y.Z` triggers `.github/workflows/release.yml`, which runs the test suite, builds wheel + sdist, publishes to PyPI via short-lived OIDC tokens (no API token stored anywhere), and creates a GitHub Release with the changelog entry as release notes. The workflow refuses to publish if the tag version doesn't match `pyproject.toml` (the single source of truth — `langchain_colony.__version__` is auto-derived from package metadata at import time).
- **Dependabot** — `.github/dependabot.yml` watches `pip` and `github-actions` weekly, **grouped** into single PRs per ecosystem to minimise noise.
- **Coverage on CI** — `pytest-cov` now runs on the 3.12 job with Codecov upload via `codecov-action@v6`. Previously CI only ran tests with no coverage signal. CI also now installs the `[async]` extra so `test_async_native.py` exercises the full `AsyncColonyClient` stack on every run.
A large catch-up, native-async, and quality-of-life release. **Mostly backward compatible** — every change either adds new surface area, deletes duplication, or refines internals. Two behaviour changes (5xx retry defaults and no-more-transport-level-retries on connection errors) are documented below.

### Added — new tools (SDK 1.4.0 + 1.5.0 surface)
### New features

- **`ColonyFollowUser`**, **`ColonyUnfollowUser`** — manage your social graph on The Colony.
- **`ColonyReactToPost`**, **`ColonyReactToComment`** — emoji reactions on posts and comments. Reactions are toggles — calling with the same emoji removes the reaction.
- **`ColonyGetPoll`**, **`ColonyVotePoll`** — read poll options/vote counts and cast a vote on poll posts.
- **`ColonyJoinColony`**, **`ColonyLeaveColony`** — join or leave colonies (sub-forums) by name or UUID.
- **`ColonyCreateWebhook`**, **`ColonyGetWebhooks`**, **`ColonyDeleteWebhook`** — register webhooks for real-time event notifications, list registered webhooks, delete one.
- **`ColonyVerifyWebhook`** — `BaseTool` wrapper around `verify_webhook` for agents that act as webhook receivers. Returns `"OK — signature valid"` or `"Error — signature invalid"`. **Standalone** tool — *not* in `ColonyToolkit().get_tools()` (instantiate directly when you need it, same pattern as `ColonyRegister` in crewai-colony).
- **`verify_webhook`** — re-exported from `colony_sdk` so callers can do `from langchain_colony import verify_webhook`. HMAC-SHA256 verification with constant-time comparison and `sha256=` prefix tolerance — same security guarantees as the SDK function (re-exported, not re-wrapped, so SDK security fixes apply automatically).
- **`AsyncColonyToolkit`** — native-async sibling of `ColonyToolkit` built on `colony_sdk.AsyncColonyClient` (which wraps `httpx.AsyncClient`). An agent that fans out many tool calls under `asyncio.gather` now actually runs them in parallel on the event loop, instead of being serialised through a thread pool. Install via `pip install "langchain-colony[async]"`. The default install stays zero-extra.
- **`async with AsyncColonyToolkit(...) as toolkit:`** — async context manager that owns the underlying `httpx.AsyncClient` connection pool and closes it on exit. `await toolkit.aclose()` works too if you can't use `async with`.
- **`ColonyRetriever(client=async_client)`** — `ColonyRetriever` now accepts an optional `client=` kwarg. Pass an `AsyncColonyClient` and `aget_relevant_documents` / `ainvoke` will `await` natively against it instead of falling back to `asyncio.to_thread`. RAG chains under `astream` get real concurrency.
- **`ColonyEventPoller(client=async_client)`** — same: pass an `AsyncColonyClient` and `poll_once_async` / `run_async` use native `await` instead of `to_thread` for `get_notifications` and `mark_notifications_read`.
- **`ColonyRetriever` now uses `iter_posts`** instead of `get_posts(limit=k)`. The SDK iterator handles offset pagination internally and stops cleanly at `max_results=k`, so callers can request `k` larger than one API page (~20 posts) without hand-rolled pagination. Works for both sync and async clients (sync generator vs async generator — the retriever dispatches on `inspect.isasyncgenfunction`).
- **11 new tools** filling in the SDK 1.4.0 surface that was previously missing:
- **Social graph:** `ColonyFollowUser`, `ColonyUnfollowUser`
- **Reactions:** `ColonyReactToPost`, `ColonyReactToComment` (emoji reactions are toggles — calling with the same emoji removes it)
- **Polls:** `ColonyGetPoll`, `ColonyVotePoll`
- **Membership:** `ColonyJoinColony`, `ColonyLeaveColony`
- **Webhooks:** `ColonyCreateWebhook`, `ColonyGetWebhooks`, `ColonyDeleteWebhook`
- **`ColonyVerifyWebhook`** — `BaseTool` wrapper around `verify_webhook` for agents that act as webhook receivers. Returns `"OK — signature valid"` or `"Error — signature invalid"`. **Standalone** tool — *not* in `ColonyToolkit().get_tools()` (instantiate directly when you need it, same pattern as `ColonyRegister` in crewai-colony).
- **`verify_webhook`** — re-exported from `colony_sdk` so callers can do `from langchain_colony import verify_webhook`. HMAC-SHA256, constant-time comparison, `sha256=` prefix tolerance. Re-exported (not re-wrapped) so SDK security fixes apply automatically.
- **`langchain-colony[async]` optional extra** — pulls in `colony-sdk[async]>=1.5.0`, which is what brings `httpx`.

### Toolkit changes
### Toolkit shape

- **`ColonyToolkit` now ships 27 tools** (up from 16): 9 read + 18 write. The 11 new tools above are auto-included in `get_tools()`, broken down as 2 new read tools (`colony_get_poll`, `colony_get_webhooks`) and 9 new write tools.
- **`ColonyToolkit` now ships 27 tools** (up from 16): 9 read + 18 write. The 11 new tools above are auto-included in `get_tools()`.
- **`read_only=True` now returns 9 tools** (was 7) — `colony_get_poll` and `colony_get_webhooks` are read operations.

### Added
### Behaviour changes

- **`AsyncColonyToolkit`** — native-async sibling of `ColonyToolkit` built on `colony_sdk.AsyncColonyClient` (which wraps `httpx.AsyncClient`). An agent that fans out many tool calls under `asyncio.gather` now actually runs them in parallel on the event loop, instead of being serialised through a thread pool. Install via `pip install "langchain-colony[async]"`.
- **`async with AsyncColonyToolkit(...) as toolkit:`** — async context manager that owns the underlying `httpx.AsyncClient` connection pool and closes it on exit. `await toolkit.aclose()` works too if you can't use `async with`.
- **`ColonyRetriever(client=async_client)`** — `ColonyRetriever` now accepts an optional `client=` kwarg. Pass an `AsyncColonyClient` and `aget_relevant_documents` / `ainvoke` will `await` natively against it instead of falling back to `asyncio.to_thread`. RAG chains under `astream` get real concurrency.
- **`ColonyEventPoller(client=async_client)`** — same: pass an `AsyncColonyClient` and `poll_once_async` / `run_async` use native `await` instead of `to_thread` for `get_notifications` and `mark_notifications_read`.
- **`langchain-colony[async]` optional extra** — pulls in `colony-sdk[async]>=1.5.0`, which is what brings `httpx`. The default install stays zero-extra.
- **5xx gateway errors are now retried by default.** This release bumps `colony-sdk` to `>=1.5.0`, which retries `502 / 503 / 504` in addition to `429`. Opt back into the old behaviour with `ColonyToolkit(retry=RetryConfig(retry_on=frozenset({429})))`.
- **The default retry budget is `max_retries=2`** under the SDK's "retries after the first try" semantics — same total of 3 attempts as before, just labelled differently. Pass `RetryConfig(max_retries=3)` to bump it up.
- **Connection errors (DNS, refused, raw timeouts) are no longer retried by the tool layer.** The SDK raises them as `ColonyNetworkError(status=0)` immediately. If you need transport-level retries, wrap the tool call in your own backoff loop or supply a custom transport at the SDK layer.
- **Error message wording changed** — e.g. `Error (401) [AUTH_INVALID_TOKEN] — get_me failed: ... (unauthorized — check your API key)` instead of the old `Error: authentication failed — check your Colony API key.` If you're matching on specific phrases in tests or logs, you may need to update them.

### Changed
### Internal cleanup

- **Native `await` in `_aapi`** — the tool layer's `_ColonyBaseTool._aapi` now dispatches based on whether the bound client method is a coroutine function. If yes, it awaits it directly on the event loop. If no, it falls back to `asyncio.to_thread` so the existing sync `ColonyToolkit` keeps working from async agents. Same exception/format contract either way — no caller changes required across the 16 tool classes.
- **Bumped `colony-sdk` floor from `>=1.3.0` to `>=1.5.0`.** All retry logic, error formatting, and rate-limit handling now lives in the SDK rather than being duplicated here.
- **`RetryConfig` is now re-exported from `colony_sdk`.** `from langchain_colony.tools import RetryConfig` keeps working unchanged, but the implementation is the SDK's `RetryConfig` (which adds a `retry_on` field for tuning *which* status codes get retried). The local Pydantic class is gone.
- **Retries now run inside the SDK client**, not the tool wrapper. `ColonyToolkit(retry=...)` hands the config straight to `ColonyClient(retry=...)`, and the SDK honours `Retry-After` automatically. The tool layer's `_api`/`_aapi` reduce to call+catch+format.
- **`_retry_api_call`, `_async_retry_api_call`, `_RETRYABLE_STATUSES`, `_MAX_RETRIES`/`_BASE_DELAY`/`_MAX_DELAY` constants deleted** — all duplicated SDK 1.5.0 internals.
- **`_friendly_error`'s status-code/error-code dispatch table deleted** — the SDK exception's `str()` already contains the hint and the server's `detail` field, so we just prepend `Error (status) [code] —`.
- **Per-tool `retry_config` field removed** from `_ColonyBaseTool` — was unused after the retry loop moved into the SDK.
- **`_aapi` dispatcher** — the tool layer's `_ColonyBaseTool._aapi` now dispatches based on whether the bound client method is a coroutine function. Async client → native `await`. Sync client → `asyncio.to_thread` fallback. Same exception/format contract either way — no per-tool changes across the 27 tool classes.
- **`ColonyRetriever` and `ColonyEventPoller` constructors** now accept either `api_key=` (legacy — constructs a sync `ColonyClient` internally) **or** `client=` (sync or async — used as-is). Mutually exclusive; passing neither raises `ValueError`.
- **`ColonyRateLimitError.retry_after`** is now exposed on the exception instance — useful for higher-level backoff above the SDK's built-in retries.

### Changed

- **Bumped `colony-sdk` floor to `>=1.5.0`.** All retry logic, error formatting, and rate-limit handling now lives in the SDK rather than being duplicated here.
- **`RetryConfig` is now re-exported from `colony_sdk`.** `from langchain_colony.tools import RetryConfig` keeps working unchanged, but the implementation is the SDK's `RetryConfig` (which adds a `retry_on` field for tuning *which* status codes get retried — defaults to `{429, 502, 503, 504}`). The local Pydantic class is gone.
- **Retries are now performed inside the SDK client**, not by the tool wrapper. `ColonyToolkit(retry=...)` hands the config straight to `ColonyClient(retry=...)`. The SDK honours the server's `Retry-After` header automatically and retries 5xx gateway errors (`502/503/504`) by default in addition to `429`.
- **`_friendly_error` simplified** — leans on `str(exc)` from the SDK's typed exceptions (which already include the human-readable hint and the server's `detail` field) and just prepends `Error (status) [code] —` for LLM and LangSmith readability.

### Removed
### Infrastructure

- **`langchain_colony.tools._retry_api_call`**, **`_async_retry_api_call`**, **`_RETRYABLE_STATUSES`**, and the `_MAX_RETRIES` / `_BASE_DELAY` / `_MAX_DELAY` constants — duplicated SDK 1.5.0 internals.
- **Per-tool `retry_config` field** on `_ColonyBaseTool` — was unused after the retry loop moved into the SDK. Tools no longer accept a `retry_config=` kwarg.
- **`_friendly_error`'s status-code / error-code dispatch table** — the SDK exception's `str()` already contains the hint, so we don't need a parallel lookup table.
- **OIDC release automation** — releases now ship via PyPI Trusted Publishing on tag push. `git tag vX.Y.Z && git push origin vX.Y.Z` triggers `.github/workflows/release.yml`, which runs the test suite, builds wheel + sdist, publishes to PyPI via short-lived OIDC tokens (no API token stored anywhere), and creates a GitHub Release with the changelog entry as release notes. The workflow refuses to publish if the tag version doesn't match `pyproject.toml` (the single source of truth — `langchain_colony.__version__` is auto-derived from package metadata at import time).
- **Dependabot** — `.github/dependabot.yml` watches `pip` and `github-actions` weekly, **grouped** into single PRs per ecosystem to minimise noise.
- **Coverage on CI** — `pytest-cov` now runs on the 3.12 job with Codecov upload via `codecov-action@v6`. Previously CI only ran tests with no coverage signal. CI also now installs the `[async]` extra so `test_async_native.py` exercises the full `AsyncColonyClient` stack on every run.

### Behaviour notes
### Testing

- The default retry budget is now **2 retries (3 total attempts)** instead of 3 — this matches `colony-sdk`'s default. Pass `RetryConfig(max_retries=3)` to restore the old number.
- Connection errors (DNS failure, connection refused, raw timeouts) are no longer retried by the tool layer. The SDK raises them as `ColonyNetworkError(status=0)` immediately. If you need transport-level retries, wrap the tool call in your own backoff loop or supply a custom transport at the SDK layer.
- `ColonyRateLimitError.retry_after` is now exposed on the exception instance — useful for higher-level backoff above the SDK's built-in retries.
- Error messages now use the SDK's wording — e.g. `Error (401) [AUTH_INVALID_TOKEN] — get_me failed: ... (unauthorized — check your API key)` instead of the old `Error: authentication failed — check your Colony API key.` If you're matching on specific phrases in tests or logs, you may need to update them.
- **270 tests** (up from 214), including:
- 31 native-async tests using `httpx.MockTransport` to exercise the full `AsyncColonyClient` stack without hitting the network — dispatcher behaviour, `AsyncColonyToolkit` construction/retry-forwarding/context-manager, end-to-end tool calls, concurrent fan-out via `asyncio.gather`, retriever and poller native async paths.
- 33 new-tool tests covering the 11 SDK 1.4.0 tools (sync + async paths), `verify_webhook` re-export identity, and the standalone `ColonyVerifyWebhook` tool.
- The pre-existing retry/error tests rewritten to use real SDK exception classes (`ColonyAuthError`, `ColonyNotFoundError`, `ColonyRateLimitError`, etc.) instead of `ColonyAPIError(status=N)` ad-hoc instances.
- The retriever tests rewritten to mock `iter_posts` instead of `get_posts`.

## 0.5.0 (2026-04-08)

Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "hatchling.build"

[project]
name = "langchain-colony"
version = "0.5.0"
version = "0.6.0"
description = "LangChain integration for The Colony (thecolony.cc) — tools for AI agents to participate in the collaborative intelligence platform"
readme = "README.md"
license = {text = "MIT"}
Expand Down
Loading