瀏覽代碼

Vendor chattolib 0.5.0b17, moving the server floor to Chatto v0.5.0-beta.17

Refresh via vendor_chattolib.sh. The library diff against the previously
vendored b15.post1 is small and additive: a ThreadRootAuthorFilter enum plus
the list_followed_threads(root_author_filter=…) parameter behind it, the
max_video_upload_size deprecation (one limit for all attachments since b16),
and an acronym-aware _snake_case that keeps a future startDMReceived-style
oneof field from decoding to start_d_m_received. Nothing in the adapter
consumes any of it, so no behavioural change follows.

The spec in vendor_chattolib.sh needs no edit — its >=0.5.0b4,<0.6 bound
resolves to b17. What did go stale is the documented reason for
--no-binary chattolib: upstream publishes wheels again as of b15, so the
exception is no longer what makes a refresh reach the newest release. It
stays, because it pins the source we vendor; the comments now say so
instead of claiming the resolver would fall back to b4.

Also fixes a pre-existing test failure in TestSessionKey: it hardcoded the
manifest name "chatto-platform" where the derived key uses
Platform(PLATFORM_NAME).value, i.e. the directory name "hermes-chatto-plugin".
AGENTS.md requires exactly that form, so the failure was ours, not Hermes'.
Paul Klumpp 2 周之前
父節點
當前提交
ddb69e4b58

+ 2 - 2
AGENTS.md

@@ -34,10 +34,10 @@ consumption — because the bot is a Chatto client just like the browser. Read
 how the platform itself models a problem before inventing our own shape (its
 presence-overlay pattern is what shaped the roster projection below).
 
-The vendored copy is upstream `chattolib[realtime]` 0.5.0b15.post1 (realtime
+The vendored copy is upstream `chattolib[realtime]` 0.5.0b17 (realtime
 protocol 4 — the revision chattolib sends in `RealtimeSubscribe.protocol_version`).
 chattolib versions track the Chatto server release they target,
-so this copy pairs with Chatto v0.5.0-beta.15, which is also the server floor
+so this copy pairs with Chatto v0.5.0-beta.17, which is also the server floor
 this build claims to support (a `.postN` re-upload keeps the server target and
 moves only the library build). Refreshing `vendor/` via `vendor_chattolib.sh`
 can move that floor (see VENDORING.md) — after each refresh, restate the new

+ 2 - 2
README.md

@@ -4,7 +4,7 @@ A [Chatto](https://github.com/chattocorp/chatto) platform adapter plugin for [He
 
 All API interaction goes through [chattolib](https://github.com/TheCodemancerLtd/chattolib): a persistent WebSocket realtime connection delivers inbound events, ConnectRPC over HTTP handles outbound messages, reactions, uploads and more. Messages are processed through the full Hermes Agent pipeline (tool use, memory, reasoning) and answered in real time.
 
-Tested against Chatto v0.5.0-beta.15 with the vendored `chattolib[realtime]` 0.5.0b15.post1 (realtime protocol 4). chattolib versions track the Chatto server release they target, so this build pairs with Chatto v0.5.0-beta.15; Chatto servers older than v0.5.0-beta.15 are not supported by this build.
+Tested against Chatto v0.5.0-beta.17 with the vendored `chattolib[realtime]` 0.5.0b17 (realtime protocol 4). chattolib versions track the Chatto server release they target, so this build pairs with Chatto v0.5.0-beta.17; Chatto servers older than v0.5.0-beta.17 are not supported by this build.
 
 Before setup, here's the part most people want to know: how Hermes behaves once it's in your Chatto instance.
 
@@ -477,7 +477,7 @@ grep -i "chatto\|websocket\|realtime" ~/.hermes/logs/gateway.log | tail -30
 ## Notes
 
 - **Self-hosted friendly**: Works with any self-hosted Chatto instance. No cloud account or subscription required.
-- **Minimal dependencies**: Only requires `chattolib[realtime]==0.5.0b15.post1`, which is vendored — nothing to install.
+- **Minimal dependencies**: Only requires `chattolib[realtime]==0.5.0b17`, which is vendored — nothing to install.
 - **No message backfill**: Events missed while the gateway is down are gone — Chatto keeps no replay for the bot. Redelivered events after a reconnect are recognised and processed only once; anything genuinely new starts from the moment of reconnection.
 
 ## Acknowledgements

+ 7 - 4
VENDORING.md

@@ -91,7 +91,7 @@ PLATFORMS="linux-x86_64 linux-aarch64 macos-arm64 windows-amd64" ./vendor_chatto
 
 # Pin a specific chattolib version (keep the [realtime] extra — without it
 # websockets is not vendored and the event stream cannot start)
-CHATTOLIB_SPEC="chattolib[realtime]==0.5.0b15.post1" ./vendor_chattolib.sh
+CHATTOLIB_SPEC="chattolib[realtime]==0.5.0b17" ./vendor_chattolib.sh
 ```
 
 The script passes `--only-binary :all: --no-binary chattolib`. Everything must
@@ -100,9 +100,12 @@ come as a prebuilt wheel, because a source distribution of `pyqwest`,
 would build it for the host and silently drop host-architecture binaries into
 `vendor/platform/<other-tag>/`. chattolib itself is the documented exception: it
 is pure Python, so building it from an sdist yields identical,
-platform-independent files on any host. That exception is load-bearing, not
-cosmetic — upstream stopped publishing wheels after 0.5.0b4, so without it the
-resolver falls back to b4 and a refresh silently changes nothing.
+platform-independent files on any host. That exception was load-bearing while
+upstream published sdist-only releases (b5…b14): without it the resolver fell
+back to the last wheel, 0.5.0b4, and a refresh silently changed nothing. b15
+and b17 ship wheels again, so the exception is no longer required to reach the
+newest release — it stays because it pins the *source* we vendor, so the tree
+does not change shape when a release is re-uploaded as a wheel.
 
 The script wipes `vendor/`, installs the dependency tree once per platform via
 `uv pip install --python-platform …`, splits the result with `vendor_split.py`,

+ 2 - 1
test_adapter.py

@@ -2149,7 +2149,8 @@ class TestSessionKey:
 
         key = adapter._session_key_for(source)
 
-        assert key == "agent:support:chatto-platform:channel:room-1:thread-9", (
+        platform_value = Platform(ChattoConstants.PLATFORM_NAME).value
+        assert key == f"agent:support:{platform_value}:channel:room-1:thread-9", (
             f"derived key is {key!r}: without the profile namespace it names a "
             "different session than the gateway runs for a secondary profile"
         )

+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/INSTALLER → vendor/common/chattolib-0.5.0b17.dist-info/INSTALLER


+ 1 - 1
vendor/common/chattolib-0.5.0b15.post1.dist-info/METADATA → vendor/common/chattolib-0.5.0b17.dist-info/METADATA

@@ -1,6 +1,6 @@
 Metadata-Version: 2.4
 Name: chattolib
-Version: 0.5.0b15.post1
+Version: 0.5.0b17
 Summary: Async Python client library for the Chatto webchat Connect API
 Author-email: Felix <chatto@f3l1x.it>
 License-Expression: MPL-2.0 AND Apache-2.0

+ 16 - 16
vendor/common/chattolib-0.5.0b15.post1.dist-info/RECORD → vendor/common/chattolib-0.5.0b17.dist-info/RECORD

@@ -1,14 +1,14 @@
-chattolib-0.5.0b15.post1.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
-chattolib-0.5.0b15.post1.dist-info/METADATA,sha256=Msn_Wc7M5ePOdN8cRk-lTjSFrW3tgMF7LAeq-ppIxXM,4942
-chattolib-0.5.0b15.post1.dist-info/RECORD,,
-chattolib-0.5.0b15.post1.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
-chattolib-0.5.0b15.post1.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
-chattolib-0.5.0b15.post1.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
-chattolib-0.5.0b15.post1.dist-info/licenses/LICENSES/Apache-2.0.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
-chattolib-0.5.0b15.post1.dist-info/licenses/LICENSES/MPL-2.0.txt,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
-chattolib-0.5.0b15.post1.dist-info/top_level.txt,sha256=vgsGOu_BQfCunqwDpfv3epJ86-g6s0va3aAYlwUW1Cg,10
-chattolib-0.5.0b15.post1.dist-info/uv_build.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
-chattolib/__init__.py,sha256=baJ3jHj7jkcOU5QBk9wu72Q1pqbStc6IjNSifTP63kI,3581
+chattolib-0.5.0b17.dist-info/INSTALLER,sha256=5hhM4Q4mYTT9z6QB6PGpUAW81PGNFrYrdXMj4oM_6ak,2
+chattolib-0.5.0b17.dist-info/METADATA,sha256=lfTuDoRi_bAiFCQnZUrc80nB79LGApoXTPRjV5z4Od4,4936
+chattolib-0.5.0b17.dist-info/RECORD,,
+chattolib-0.5.0b17.dist-info/REQUESTED,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
+chattolib-0.5.0b17.dist-info/WHEEL,sha256=YVMoNqKzERt-wjUZwJ33xBGAwnFl-4cqbYkTtWa4itE,91
+chattolib-0.5.0b17.dist-info/licenses/LICENSE,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
+chattolib-0.5.0b17.dist-info/licenses/LICENSES/Apache-2.0.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
+chattolib-0.5.0b17.dist-info/licenses/LICENSES/MPL-2.0.txt,sha256=Pz2eACSxkhsGfW9_iN60pgy-enjnbGTj8df8O3ebnQQ,16726
+chattolib-0.5.0b17.dist-info/top_level.txt,sha256=vgsGOu_BQfCunqwDpfv3epJ86-g6s0va3aAYlwUW1Cg,10
+chattolib-0.5.0b17.dist-info/uv_build.json,sha256=RBNvo1WzZ4oRRq0W9-hknpT7T8If536DEMBg9hyq_4o,2
+chattolib/__init__.py,sha256=JOAGfbjwaVXVOO-e0_3Et2P_ZtaMgwAAxyAqYmUsQ8s,3639
 chattolib/_codegen/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
 chattolib/_codegen/protoc_gen_request_pb2.py,sha256=ctc_R6vciqBWr8Ki2eYWCwQnxXYg9t9OsPMVrjobK5M,1636
 chattolib/_codegen/protoc_gen_response_pb2.py,sha256=R016Wg9LhInIHVdUvofS4g_uZAr4fMd9N-2t4hDZu-c,2073
@@ -27,7 +27,7 @@ chattolib/_pb/chatto/admin/v1/event_log_pb2.py,sha256=zmLBF2nULUHZxL7eBIS5pfUPEN
 chattolib/_pb/chatto/admin/v1/members_connect.py,sha256=g6Cdn0oexiwiEURRDwdOrEuOjtDNi2xIMT9lY2u0zbQ,9791
 chattolib/_pb/chatto/admin/v1/members_pb2.py,sha256=951kNkor6-9GZtdyph4plXNGLaISJv-HrIuIMYZWpak,10408
 chattolib/_pb/chatto/admin/v1/permissions_connect.py,sha256=WkgM9RsmUsNK49Hebe5brVjeU_8RTqYp6-Kz1Bsn1F8,11087
-chattolib/_pb/chatto/admin/v1/permissions_pb2.py,sha256=ykaWzovhmKSPV9Xpb1HBth5XCOa64IMepodxyw2atNE,16976
+chattolib/_pb/chatto/admin/v1/permissions_pb2.py,sha256=PqIEPB2m64r6oO2nRmTExUzF6O4V1s6YMwwF8quiK5I,16828
 chattolib/_pb/chatto/admin/v1/roles_connect.py,sha256=wC-LbGEHMsSykt43xnrRD5zgyi8lYlz9F1NAyFXFfTU,8353
 chattolib/_pb/chatto/admin/v1/roles_pb2.py,sha256=fviHOZt-9im1PZDG_BWBjf6CEsMvIgKNxKxi2rKpBHY,8686
 chattolib/_pb/chatto/admin/v1/room_layout_connect.py,sha256=L2u1J9w7ONnyqZ8vmVOp5aoXPxPSMfTtmukGBqBsHJI,19257
@@ -70,9 +70,9 @@ chattolib/_pb/chatto/api/v1/rooms_connect.py,sha256=7BM1TpIgDntfaPKsdLKlItXWPEhM
 chattolib/_pb/chatto/api/v1/rooms_pb2.py,sha256=VkD7SDRFe5IogoW4I1lPSF7DGKsR-w5ONIQVYkxPc-8,23008
 chattolib/_pb/chatto/api/v1/server_pb2.py,sha256=4PLXiRaKo1aciExrEivskzOsAP-kSpa-iGeu0xSlLpM,2667
 chattolib/_pb/chatto/api/v1/server_state_connect.py,sha256=icUFtOoUTyjJEG_-lzFoqtT-nPYghnUvLK6lFcJyFDc,3944
-chattolib/_pb/chatto/api/v1/server_state_pb2.py,sha256=9jMiysZcOpY6zcbm5yMDOciOzsEBHj4m-zpj3xHc63g,3508
+chattolib/_pb/chatto/api/v1/server_state_pb2.py,sha256=hVxzHHZ_JXByViFgX2NpxfZB2Kl3DylYEvDtyOHnU_s,3728
 chattolib/_pb/chatto/api/v1/threads_connect.py,sha256=b6VBSLFrx4fEMovzUrbjK0fYskW0h3GBtrkle6HOvoY,11579
-chattolib/_pb/chatto/api/v1/threads_pb2.py,sha256=4PGCXevmCtMImtxyO_t49De3Xa1FHZyZBGxwv9fiCIs,7883
+chattolib/_pb/chatto/api/v1/threads_pb2.py,sha256=BxuZF6Gok83tKIz9anxhZasGQEr6aGR13YmL3M5gJOI,8551
 chattolib/_pb/chatto/api/v1/user_service_connect.py,sha256=kehavKiJvikLPayE7slup3LGQ8vheP9G0-6mWAXOWZg,7396
 chattolib/_pb/chatto/api/v1/user_service_pb2.py,sha256=Ma4Tdpe2xydPkmsy4UaizT6S6c9NMIKNj-6vWz0l2sY,8257
 chattolib/_pb/chatto/api/v1/user_status_pb2.py,sha256=8jz0aEQQzW3vlNvSXEngpEm_o6pWPOya6i_u293aS_c,3075
@@ -96,7 +96,7 @@ chattolib/_pb/chatto/realtime/v1/realtime_pb2.py,sha256=tFQapRdKrkuu26zhI9Z5m1dR
 chattolib/_protoc_plugin.py,sha256=ksfXIJT_Z7UIAMVkeVjaIXa2QEdIaYJz8VVbRYbp_p0,8996
 chattolib/_transport.py,sha256=WwnK3jIsWGoR6mi1YOt8hX72albS6O3ZD4kv5gZWo9Y,7510
 chattolib/bot.py,sha256=wHQzXOynp8Pi7S0lJClsdXcGDk637f3rOcQXtrYYb8I,22883
-chattolib/client.py,sha256=J3WfKrlGiD05awKPWKjXeHitQ71cgo4CJcNjteXcUUc,85417
+chattolib/client.py,sha256=IdY7G8cT19MITIi2x4ftPFtAwsm8vmfWLlvk7SlNY28,85909
 chattolib/exceptions.py,sha256=1QIVUjfop1CUVIvS3yv-ZZlV6RvmiXpSrCb17vS2t_A,1044
 chattolib/realtime.py,sha256=HGsdlv4lBfynnNp1hoqGwKXgHwIxIGisSt8gaUDR4oM,12015
-chattolib/types.py,sha256=RbqROHeTvsddeAr_CcZ_o8SyvbZVuSrTM-0gaMrX5AQ,48903
+chattolib/types.py,sha256=Ulr3YAje0cX9ga4PBSVz6Y0B3CKaWQzglH58k4_SFgc,49918

+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/REQUESTED → vendor/common/chattolib-0.5.0b17.dist-info/REQUESTED


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/WHEEL → vendor/common/chattolib-0.5.0b17.dist-info/WHEEL


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/licenses/LICENSE → vendor/common/chattolib-0.5.0b17.dist-info/licenses/LICENSE


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/licenses/LICENSES/Apache-2.0.txt → vendor/common/chattolib-0.5.0b17.dist-info/licenses/LICENSES/Apache-2.0.txt


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/licenses/LICENSES/MPL-2.0.txt → vendor/common/chattolib-0.5.0b17.dist-info/licenses/LICENSES/MPL-2.0.txt


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/top_level.txt → vendor/common/chattolib-0.5.0b17.dist-info/top_level.txt


+ 0 - 0
vendor/common/chattolib-0.5.0b15.post1.dist-info/uv_build.json → vendor/common/chattolib-0.5.0b17.dist-info/uv_build.json


+ 2 - 0
vendor/common/chattolib/__init__.py

@@ -69,6 +69,7 @@ from chattolib.types import (
     ServerProfile,
     ServerRuntimeConfig,
     SidebarLink,
+    ThreadRootAuthorFilter,
     ThreadSummary,
     TimeFormat,
     TimelineEvent,
@@ -146,6 +147,7 @@ __all__ = [
     "ServerProfile",
     "ServerRuntimeConfig",
     "SidebarLink",
+    "ThreadRootAuthorFilter",
     "ThreadSummary",
     "TimeFormat",
     "TimelineEvent",

File diff suppressed because it is too large
+ 0 - 0
vendor/common/chattolib/_pb/chatto/admin/v1/permissions_pb2.py


+ 10 - 8
vendor/common/chattolib/_pb/chatto/api/v1/server_state_pb2.py

@@ -25,13 +25,15 @@ _sym_db = _symbol_database.Default()
 from chatto.api.v1 import server_pb2 as chatto_dot_api_dot_v1_dot_server__pb2
 
 
-DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n chatto/api/v1/server_state.proto\x12\rchatto.api.v1\x1a\x1a\x63hatto/api/v1/server.proto\"\x19\n\x17GetServerProfileRequest\"O\n\x18GetServerProfileResponse\x12\x33\n\x07profile\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerPublicProfile\"\x10\n\x0eGetMotdRequest\"-\n\x0fGetMotdResponse\x12\x11\n\x04motd\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_motd\"\xb9\x02\n\x13ServerRuntimeConfig\x12\"\n\x1apush_notifications_enabled\x18\x01 \x01(\x08\x12\x1d\n\x10vapid_public_key\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0blivekit_url\x18\x03 \x01(\tH\x01\x88\x01\x01\x12 \n\x18video_processing_enabled\x18\x05 \x01(\x08\x12\x17\n\x0fmax_upload_size\x18\x06 \x01(\x03\x12\x1d\n\x15max_video_upload_size\x18\x07 \x01(\x03\x12#\n\x1bmessage_edit_window_seconds\x18\x08 \x01(\x05\x42\x13\n\x11_vapid_public_keyB\x0e\n\x0c_livekit_urlJ\x04\x08\x04\x10\x05R\x1b\x64irect_registration_enabled\"\x19\n\x17GetRuntimeConfigRequest\"O\n\x18GetRuntimeConfigResponse\x12\x33\n\x07runtime\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerRuntimeConfig2\xa3\x02\n\rServerService\x12\x63\n\x10GetServerProfile\x12&.chatto.api.v1.GetServerProfileRequest\x1a\'.chatto.api.v1.GetServerProfileResponse\x12H\n\x07GetMotd\x12\x1d.chatto.api.v1.GetMotdRequest\x1a\x1e.chatto.api.v1.GetMotdResponse\x12\x63\n\x10GetRuntimeConfig\x12&.chatto.api.v1.GetRuntimeConfigRequest\x1a\'.chatto.api.v1.GetRuntimeConfigResponseb\x06proto3')
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n chatto/api/v1/server_state.proto\x12\rchatto.api.v1\x1a\x1a\x63hatto/api/v1/server.proto\"\x19\n\x17GetServerProfileRequest\"O\n\x18GetServerProfileResponse\x12\x33\n\x07profile\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerPublicProfile\"\x10\n\x0eGetMotdRequest\"-\n\x0fGetMotdResponse\x12\x11\n\x04motd\x18\x01 \x01(\tH\x00\x88\x01\x01\x42\x07\n\x05_motd\"\xbd\x02\n\x13ServerRuntimeConfig\x12\"\n\x1apush_notifications_enabled\x18\x01 \x01(\x08\x12\x1d\n\x10vapid_public_key\x18\x02 \x01(\tH\x00\x88\x01\x01\x12\x18\n\x0blivekit_url\x18\x03 \x01(\tH\x01\x88\x01\x01\x12 \n\x18video_processing_enabled\x18\x05 \x01(\x08\x12\x17\n\x0fmax_upload_size\x18\x06 \x01(\x03\x12!\n\x15max_video_upload_size\x18\x07 \x01(\x03\x42\x02\x18\x01\x12#\n\x1bmessage_edit_window_seconds\x18\x08 \x01(\x05\x42\x13\n\x11_vapid_public_keyB\x0e\n\x0c_livekit_urlJ\x04\x08\x04\x10\x05R\x1b\x64irect_registration_enabled\"\x19\n\x17GetRuntimeConfigRequest\"O\n\x18GetRuntimeConfigResponse\x12\x33\n\x07runtime\x18\x01 \x01(\x0b\x32\".chatto.api.v1.ServerRuntimeConfig2\xa3\x02\n\rServerService\x12\x63\n\x10GetServerProfile\x12&.chatto.api.v1.GetServerProfileRequest\x1a\'.chatto.api.v1.GetServerProfileResponse\x12H\n\x07GetMotd\x12\x1d.chatto.api.v1.GetMotdRequest\x1a\x1e.chatto.api.v1.GetMotdResponse\x12\x63\n\x10GetRuntimeConfig\x12&.chatto.api.v1.GetRuntimeConfigRequest\x1a\'.chatto.api.v1.GetRuntimeConfigResponseb\x06proto3')
 
 _globals = globals()
 _builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
 _builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'chatto.api.v1.server_state_pb2', _globals)
 if not _descriptor._USE_C_DESCRIPTORS:
   DESCRIPTOR._loaded_options = None
+  _globals['_SERVERRUNTIMECONFIG'].fields_by_name['max_video_upload_size']._loaded_options = None
+  _globals['_SERVERRUNTIMECONFIG'].fields_by_name['max_video_upload_size']._serialized_options = b'\030\001'
   _globals['_GETSERVERPROFILEREQUEST']._serialized_start=79
   _globals['_GETSERVERPROFILEREQUEST']._serialized_end=104
   _globals['_GETSERVERPROFILERESPONSE']._serialized_start=106
@@ -41,11 +43,11 @@ if not _descriptor._USE_C_DESCRIPTORS:
   _globals['_GETMOTDRESPONSE']._serialized_start=205
   _globals['_GETMOTDRESPONSE']._serialized_end=250
   _globals['_SERVERRUNTIMECONFIG']._serialized_start=253
-  _globals['_SERVERRUNTIMECONFIG']._serialized_end=566
-  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_start=568
-  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_end=593
-  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_start=595
-  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_end=674
-  _globals['_SERVERSERVICE']._serialized_start=677
-  _globals['_SERVERSERVICE']._serialized_end=968
+  _globals['_SERVERRUNTIMECONFIG']._serialized_end=570
+  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_start=572
+  _globals['_GETRUNTIMECONFIGREQUEST']._serialized_end=597
+  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_start=599
+  _globals['_GETRUNTIMECONFIGRESPONSE']._serialized_end=678
+  _globals['_SERVERSERVICE']._serialized_start=681
+  _globals['_SERVERSERVICE']._serialized_end=972
 # @@protoc_insertion_point(module_scope)

File diff suppressed because it is too large
+ 0 - 0
vendor/common/chattolib/_pb/chatto/api/v1/threads_pb2.py


+ 10 - 1
vendor/common/chattolib/client.py

@@ -111,6 +111,7 @@ from chattolib.types import (
     ServerLogin,
     ServerProfile,
     ServerRuntimeConfig,
+    ThreadRootAuthorFilter,
     TimeFormat,
     TimelinePage,
     User,
@@ -1113,12 +1114,16 @@ class ChattoClient:
         offset: int | None = None,
         include_direct_message_threads: bool | None = None,
         unread_only: bool | None = None,
+        root_author_filter: ThreadRootAuthorFilter | None = None,
     ) -> FollowedThreadsPage:
         """Followed threads, newest activity first.
 
         ``unread_only`` returns only threads with unread replies (older
         servers ignore it); ``include_direct_message_threads`` also lists
-        followed direct-message threads.
+        followed direct-message threads; ``root_author_filter`` (since
+        0.5.0b16) filters by the author of the thread *root* —
+        ``VIEWER`` for threads you started, ``OTHERS`` for threads started
+        by someone else (older servers ignore it).
         """
         req = threads_pb2.ListFollowedThreadsRequest()
         page = _page_pb(limit, offset)
@@ -1128,6 +1133,10 @@ class ChattoClient:
             req.include_direct_message_threads = include_direct_message_threads
         if unread_only is not None:
             req.unread_only = unread_only
+        if root_author_filter is not None:
+            req.root_author_filter = threads_pb2.ThreadRootAuthorFilter.Value(
+                root_author_filter.value
+            )
         resp = await self._rpc(
             self._svc.threads.list_followed_threads(req, headers=self._headers())
         )

+ 22 - 2
vendor/common/chattolib/types.py

@@ -83,6 +83,12 @@ class NotificationLevel(StrEnum):
     ALL_MESSAGES = "NOTIFICATION_LEVEL_ALL_MESSAGES"
 
 
+class ThreadRootAuthorFilter(StrEnum):
+    UNSPECIFIED = "THREAD_ROOT_AUTHOR_FILTER_UNSPECIFIED"
+    VIEWER = "THREAD_ROOT_AUTHOR_FILTER_VIEWER"
+    OTHERS = "THREAD_ROOT_AUTHOR_FILTER_OTHERS"
+
+
 class ImageFitMode(StrEnum):
     UNSPECIFIED = "IMAGE_FIT_MODE_UNSPECIFIED"
     CONTAIN = "IMAGE_FIT_MODE_CONTAIN"
@@ -434,6 +440,8 @@ class ServerRuntimeConfig:
     livekit_url: str | None = None
     video_processing_enabled: bool = False
     max_upload_size: int = 0
+    # Deprecated since 0.5.0b16: an alias of ``max_upload_size`` (same value).
+    # Since 0.5.0b16 one size limit applies to all attachments, GIFs/videos included.
     max_video_upload_size: int = 0
     message_edit_window_seconds: int = 0
 
@@ -1012,10 +1020,22 @@ class TimelineEvent:
 
 
 def _snake_case(name: str) -> str:
+    """snake_case a camelCase oneof field name (acronym-aware).
+
+    Mirrors the chattolib protoc plugin's ``_method_name``: an underscore
+    goes before an uppercase letter only at a word boundary — after a
+    lowercase/digit, or before the final capital of a run that is followed
+    by a lowercase letter. A naive per-capital split would turn a future
+    acronym field like ``startDMReceived`` into ``start_d_m_received`` and
+    silently break any ``kind == "..."`` comparison.
+    """
     out: list[str] = []
-    for ch in name:
+    for i, ch in enumerate(name):
         if ch.isupper() and out:
-            out.append("_")
+            prev = name[i - 1]
+            nxt = name[i + 1] if i + 1 < len(name) else ""
+            if not prev.isupper() or nxt.islower():
+                out.append("_")
         out.append(ch.lower())
     return "".join(out)
 

+ 4 - 3
vendor_chattolib.sh

@@ -78,9 +78,10 @@ for tag in "${PLATFORM_LIST[@]}"; do
     #
     # chattolib is the one exception: it is pure Python with no compiled
     # extension, so building it from the sdist on any host yields identical,
-    # platform-independent files. It has to be an exception because upstream
-    # stopped publishing wheels after 0.5.0b4 — b5…b13 are sdist-only, and
-    # without this the resolver silently pins the vendored copy back to b4.
+    # platform-independent files. The exception was load-bearing while upstream
+    # published sdist-only releases (b5…b14); it now also pins the *source* we
+    # vendor, so the tree does not change shape the day a release is
+    # re-uploaded as a wheel.
     uv pip install \
         --target "$BUILD_DIR/$tag" \
         --python-platform "$target" \

Some files were not shown because too many files changed in this diff