- Export Command wrapper class from main package
- Update hello_python example to register /hello command in OnActivate
- Slash commands must be registered via api.register_command() to work
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update HTTPResponseWriter class to support streaming responses:
- Add flush() method for best-effort HTTP flush requests
- Track pending writes with flush markers for streaming mode
- Add get_pending_writes() and clear_pending_writes() methods
- Document streaming mode, header locking, and flush semantics
- Add MAX_CHUNK_SIZE constant (64KB, matching Go)
Update ServeHTTP servicer to stream responses:
- Send response chunks incrementally instead of buffering
- Include flush flag on each message when requested
- Check for cancellation between chunks
- Handle empty body case (init only)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add flush field to ServeHTTPResponse for best-effort HTTP flush support.
Update ServeHTTPResponse and ServeHTTPResponseInit with comprehensive
documentation of streaming invariants, message ordering, and status
code validation rules.
Changes:
- Add flush boolean field (field 4) to ServeHTTPResponse
- Document response streaming invariants (init-once, header locking)
- Document status code validation (100-999 range, 0 defaults to 200)
- Regenerate Go and Python protobuf code
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add tests for both Go and Python ServeHTTP implementations covering:
- Body chunking behavior (small, exact, multiple, large bodies)
- Context cancellation during body streaming
- Header conversion utilities
- HTTPRequest/HTTPResponseWriter helper classes
- Request body assembly from multiple chunks
- Error handling (500 for handler errors, 404 for missing handler)
Go tests:
- TestChunking_* for body chunking scenarios
- TestConvertHTTPHeaders for header conversion
- TestBuildRequestInit for request metadata building
- TestWriteResponseHeaders for response header writing
- TestContextCancellation_DuringBodyRead for cancellation
Python tests:
- TestHTTPRequest for request wrapper class
- TestHTTPResponseWriter for response writer class
- TestHeaderConversion for proto<->dict conversion
- TestServeHTTPServicer for gRPC servicer behavior
- TestChunkingBehavior for body assembly
- TestCancellation for request cancellation
Also:
- Fixed sendRequest to properly set body_complete flag on EOF
- Added ServeHTTP to HookName enum
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add ServeHTTP bidirectional streaming implementation to the Python
hook servicer with HTTPRequest and HTTPResponseWriter helper classes.
Key features:
- Async generator for bidirectional streaming
- HTTPRequest wrapper with method, url, headers, body
- HTTPResponseWriter mimicking Go's http.ResponseWriter pattern
- Context cancellation detection during body streaming
- Header conversion utilities for proto <-> dict
Handler pattern:
- Receives: (plugin_context, response_writer, request)
- Similar to Go's http.Handler(w, r) pattern
- Response writer collects headers/status/body
Current limitations (deferred to 08-02):
- Request body fully buffered before handler invocation
- Response body fully buffered before streaming back
- No true streaming for large bodies yet
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add bidirectional streaming RPC for ServeHTTP hook to support
efficient HTTP request/response transfer between Go and Python.
Key changes:
- New hooks_http.proto with ServeHTTPRequest/Response messages
- HTTPHeader message for multi-value header support
- ServeHTTPRequestInit with full request metadata
- ServeHTTPResponseInit for status and headers
- Body chunks with completion flag for streaming
- Updated hooks.proto with ServeHTTP streaming RPC
- Regenerated Go and Python code
Design decisions:
- 64KB default chunk size per gRPC best practices
- First message carries metadata, subsequent messages carry body
- body_complete flag signals end of stream
- Headers as repeated HTTPHeader for multi-value support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add test_hooks_grpc_integration.py with in-process gRPC tests:
- Test Implemented RPC returns correct hook list
- Test lifecycle hooks (OnActivate, OnDeactivate, OnConfigurationChange)
- Test MessageWillBePosted allow/reject/modify scenarios
- Test notification hooks (MessageHasBeenPosted)
- Test activation failure propagation via response.error
- Test async handlers work through gRPC
- Fix lifecycle hooks to encode errors in response, not gRPC status
- Remove context parameter from runner.invoke() for lifecycle hooks
- Ensures activation failures are returned as AppError, not gRPC error
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create server.py with PluginServer class for gRPC server lifecycle
- Register grpc.health.v1.Health service with plugin status SERVING
- Output go-plugin handshake line (1|1|tcp|127.0.0.1:PORT|grpc)
- Bind to ephemeral port on localhost for security
- Add serve_plugin() and run_plugin() entry points
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create runtime_config.py to load config from environment variables
- Support MATTERMOST_PLUGIN_ID, MATTERMOST_PLUGIN_API_TARGET
- Support MATTERMOST_PLUGIN_HOOK_TIMEOUT, MATTERMOST_PLUGIN_LOG_LEVEL
- Provide sensible defaults and configure_logging helper
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create hook_runner.py with run_hook_async function
- Support both sync and async handlers via asyncio.to_thread
- Enforce timeouts with asyncio.wait_for (default 30s)
- Convert exceptions to gRPC status codes
- Add HookRunner class for convenient invocation
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create plugin.py with Plugin base class for plugin authors
- Use __init_subclass__ for automatic hook discovery at class definition
- Implement implemented_hooks(), has_hook(), invoke_hook() methods
- Provide api, logger, config properties for plugin instances
- Enforce single handler per hook with clear duplicate error
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Create hooks.py with @hook decorator for registration
- Add HookName enum with all canonical hook names from hooks.proto
- Support multiple decorator forms: @hook(HookName.X), @hook("X"), @hook
- Preserve function metadata with functools.wraps
- Validate hook names and raise HookRegistrationError for invalid names
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Update PluginAPIClient to inherit from PostsMixin, FilesMixin,
and KVStoreMixin, providing 31 new typed methods for:
- Post CRUD, ephemeral posts, and reactions
- File metadata, content, and uploads
- Key-value store operations with atomic support
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add KVStoreMixin with 9 methods:
- kv_set, kv_get, kv_delete, kv_delete_all, kv_list
- kv_set_with_expiry
- kv_compare_and_set, kv_compare_and_delete, kv_set_with_options
Provides complete KV store functionality including atomic operations
and expiring keys for plugin data persistence.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add FilesMixin with 8 methods:
- get_file_info, get_file_infos, set_file_searchable_content
- get_file, get_file_link, read_file
- upload_file, copy_file_infos
Covers all file metadata, content retrieval, and upload operations
following the established mixin pattern.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add PostsMixin with 15 methods:
- create_post, get_post, update_post, delete_post
- send_ephemeral_post, update_ephemeral_post, delete_ephemeral_post
- get_post_thread, get_posts_since, get_posts_after, get_posts_before
- add_reaction, remove_reaction, get_reactions
All methods follow the established mixin pattern with proper error
handling and type annotations.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add dataclasses for:
- Post: Mattermost message with full field support
- Reaction: User emoji reaction to a post
- PostList: Ordered list of posts with pagination
- FileInfo: File metadata with all attributes
- UploadSession: Resumable upload session
- PluginKVSetOptions: Options for KV set operations
All wrappers include from_proto() and to_proto() methods for
protobuf serialization.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add mixin imports and inheritance to PluginAPIClient so that the
User/Team/Channel API methods are actually available on the client.
This was missing from the previous mixin implementation commit.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generate Python code from server/public/pluginapi/grpc/proto:
- Protocol buffer message definitions (*_pb2.py)
- gRPC service stubs (*_pb2_grpc.py)
- Type stubs for IDE completion (*_pb2.pyi, *_pb2_grpc.pyi)
- Imports fixed to use package-relative imports
Generated from 18 .proto files using grpcio-tools and mypy-protobuf.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Add client classes for Mattermost Plugin API:
- PluginAPIClient: sync client with context manager support
- AsyncPluginAPIClient: async client with grpc.aio support
- Both implement get_server_version() as smoke test RPC
- Proper error handling converts gRPC errors to SDK exceptions
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Create the foundational Python SDK package structure:
- pyproject.toml with project metadata and dependencies
- src/mattermost_plugin/ package with src layout
- Configured for Python >=3.9 with grpcio and protobuf deps
- Dev dependencies include grpcio-tools, mypy-protobuf, pytest
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>