chattice 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- chattice-0.1.0/.gitignore +24 -0
- chattice-0.1.0/.python-version +2 -0
- chattice-0.1.0/CHANGELOG.md +29 -0
- chattice-0.1.0/CODE_OF_CONDUCT.md +6 -0
- chattice-0.1.0/CONTRIBUTING.md +73 -0
- chattice-0.1.0/LICENSE +21 -0
- chattice-0.1.0/PKG-INFO +210 -0
- chattice-0.1.0/PUBLIC_API.md +28 -0
- chattice-0.1.0/README.md +173 -0
- chattice-0.1.0/SECURITY.md +29 -0
- chattice-0.1.0/THIRD_PARTY_NOTICES.md +64 -0
- chattice-0.1.0/docs/adr/ADR-001-event-domain-model.md +50 -0
- chattice-0.1.0/docs/adr/ADR-002-dispatcher-router.md +53 -0
- chattice-0.1.0/docs/adr/ADR-003-raw-google-models.md +46 -0
- chattice-0.1.0/docs/adr/ADR-004-transport-abstraction.md +42 -0
- chattice-0.1.0/docs/adr/ADR-005-authentication-abstraction.md +46 -0
- chattice-0.1.0/docs/adr/ADR-006-fsm-key-strategy.md +45 -0
- chattice-0.1.0/docs/adr/ADR-007-cards-builder.md +45 -0
- chattice-0.1.0/docs/adr/ADR-008-sync-async-responses.md +50 -0
- chattice-0.1.0/docs/adr/ADR-009-google-interaction-normalization.md +55 -0
- chattice-0.1.0/docs/adr/ADR-010-project-identity.md +22 -0
- chattice-0.1.0/docs/adr/ADR-011-versioning-policy.md +25 -0
- chattice-0.1.0/docs/adr/index.md +21 -0
- chattice-0.1.0/docs/adr/template.md +26 -0
- chattice-0.1.0/docs/aiogram-comparison.md +237 -0
- chattice-0.1.0/docs/api.md +71 -0
- chattice-0.1.0/docs/architecture/authentication.md +126 -0
- chattice-0.1.0/docs/architecture/bot-api-client.md +129 -0
- chattice-0.1.0/docs/architecture/capabilities.md +166 -0
- chattice-0.1.0/docs/architecture/cards.md +115 -0
- chattice-0.1.0/docs/architecture/dependency-injection.md +43 -0
- chattice-0.1.0/docs/architecture/dialogs-app-home.md +179 -0
- chattice-0.1.0/docs/architecture/dispatcher-router.md +77 -0
- chattice-0.1.0/docs/architecture/event-model.md +102 -0
- chattice-0.1.0/docs/architecture/forms-vs-fsm-vs-scenes.md +123 -0
- chattice-0.1.0/docs/architecture/fsm.md +191 -0
- chattice-0.1.0/docs/architecture/google-interaction-adapter.md +124 -0
- chattice-0.1.0/docs/architecture/http-transport.md +50 -0
- chattice-0.1.0/docs/architecture/middleware.md +62 -0
- chattice-0.1.0/docs/architecture/observability.md +143 -0
- chattice-0.1.0/docs/architecture/overview.md +102 -0
- chattice-0.1.0/docs/architecture/pubsub.md +85 -0
- chattice-0.1.0/docs/architecture/reliability.md +191 -0
- chattice-0.1.0/docs/architecture/security.md +165 -0
- chattice-0.1.0/docs/architecture/testing.md +184 -0
- chattice-0.1.0/docs/architecture/transports.md +70 -0
- chattice-0.1.0/docs/architecture/workspace-events.md +134 -0
- chattice-0.1.0/docs/assets/brand/chattice-logo.png +0 -0
- chattice-0.1.0/docs/assets/brand/chattice-mark-black.png +0 -0
- chattice-0.1.0/docs/assets/brand/chattice-mark-white.png +0 -0
- chattice-0.1.0/docs/assets/brand/chattice-mark.png +0 -0
- chattice-0.1.0/docs/assets/brand/favicon.png +0 -0
- chattice-0.1.0/docs/assets/brand/github-avatar.png +0 -0
- chattice-0.1.0/docs/common-mistakes.md +57 -0
- chattice-0.1.0/docs/concepts/mental-model.md +87 -0
- chattice-0.1.0/docs/cookbook/recipes.md +211 -0
- chattice-0.1.0/docs/examples.md +42 -0
- chattice-0.1.0/docs/getting-started/authentication.md +122 -0
- chattice-0.1.0/docs/getting-started/first-deployment.md +56 -0
- chattice-0.1.0/docs/getting-started/google-chat-setup.md +95 -0
- chattice-0.1.0/docs/getting-started/installation.md +48 -0
- chattice-0.1.0/docs/getting-started/project-structure.md +27 -0
- chattice-0.1.0/docs/getting-started/quickstart.md +161 -0
- chattice-0.1.0/docs/guides/advanced-apis.md +56 -0
- chattice-0.1.0/docs/guides/auth-capabilities.md +130 -0
- chattice-0.1.0/docs/guides/cards-forms-dialogs.md +190 -0
- chattice-0.1.0/docs/guides/commands.md +73 -0
- chattice-0.1.0/docs/guides/deployment.md +230 -0
- chattice-0.1.0/docs/guides/enterprise.md +83 -0
- chattice-0.1.0/docs/guides/files-media.md +444 -0
- chattice-0.1.0/docs/guides/memberships-spaces.md +118 -0
- chattice-0.1.0/docs/guides/messages.md +131 -0
- chattice-0.1.0/docs/guides/routing-state.md +153 -0
- chattice-0.1.0/docs/guides/transports.md +95 -0
- chattice-0.1.0/docs/guides/workspace-events.md +77 -0
- chattice-0.1.0/docs/index.md +59 -0
- chattice-0.1.0/docs/llms.txt +53 -0
- chattice-0.1.0/docs/public-api.md +409 -0
- chattice-0.1.0/docs/reference/compatibility.md +29 -0
- chattice-0.1.0/docs/reference/google-api-mapping.md +42 -0
- chattice-0.1.0/docs/release/sbom-chattice.spdx.json +1712 -0
- chattice-0.1.0/docs/stability.md +52 -0
- chattice-0.1.0/docs/troubleshooting.md +169 -0
- chattice-0.1.0/examples/README.md +34 -0
- chattice-0.1.0/examples/__init__.py +1 -0
- chattice-0.1.0/examples/bots/__init__.py +11 -0
- chattice-0.1.0/examples/bots/buttons_bot.py +87 -0
- chattice-0.1.0/examples/bots/command_bot.py +74 -0
- chattice-0.1.0/examples/bots/dialog_bot.py +78 -0
- chattice-0.1.0/examples/bots/echo_bot.py +38 -0
- chattice-0.1.0/examples/bots/fastapi_bot.py +48 -0
- chattice-0.1.0/examples/bots/form_bot.py +78 -0
- chattice-0.1.0/examples/bots/fsm_bot.py +85 -0
- chattice-0.1.0/examples/bots/http_echo_bot.py +52 -0
- chattice-0.1.0/examples/bots/pubsub_bot.py +60 -0
- chattice-0.1.0/examples/bots/pubsub_pull_echo_bot.py +54 -0
- chattice-0.1.0/examples/bots/workspace_events_bot.py +50 -0
- chattice-0.1.0/examples/docs/__init__.py +1 -0
- chattice-0.1.0/examples/docs/from_zero.py +310 -0
- chattice-0.1.0/examples/docs/quickstart_app.py +29 -0
- chattice-0.1.0/examples/production/crm_workflow/__init__.py +1 -0
- chattice-0.1.0/examples/production/crm_workflow/main.py +252 -0
- chattice-0.1.0/examples/production/multi_space_notification.py +75 -0
- chattice-0.1.0/examples/scenarios/__init__.py +5 -0
- chattice-0.1.0/examples/scenarios/apphome_dashboard.py +66 -0
- chattice-0.1.0/examples/scenarios/buttons_menu.py +96 -0
- chattice-0.1.0/examples/scenarios/dynamic_employee_picker.py +51 -0
- chattice-0.1.0/examples/scenarios/link_preview.py +58 -0
- chattice-0.1.0/examples/scenarios/private_dialog_to_public_card.py +107 -0
- chattice-0.1.0/examples/scenarios/registration_dialog.py +112 -0
- chattice-0.1.0/examples/scenarios/registration_fsm.py +116 -0
- chattice-0.1.0/examples/scenarios/request_form.py +103 -0
- chattice-0.1.0/examples/scenarios/request_form_plus_fsm.py +161 -0
- chattice-0.1.0/examples/scenarios/text_triggers.py +64 -0
- chattice-0.1.0/llms.txt +53 -0
- chattice-0.1.0/mkdocs.yml +73 -0
- chattice-0.1.0/pyproject.toml +134 -0
- chattice-0.1.0/scripts/gen_llms_txt.py +64 -0
- chattice-0.1.0/scripts/gen_sbom.py +85 -0
- chattice-0.1.0/scripts/serve_smoke.sh +36 -0
- chattice-0.1.0/scripts/verify_package.sh +71 -0
- chattice-0.1.0/src/chattice/__init__.py +8 -0
- chattice-0.1.0/src/chattice/_json_snapshot.py +35 -0
- chattice-0.1.0/src/chattice/actions.py +223 -0
- chattice-0.1.0/src/chattice/adapters/__init__.py +1 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/__init__.py +19 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/envelope.py +80 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/exceptions.py +25 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/inputs.py +107 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/interaction.py +20 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/models.py +97 -0
- chattice-0.1.0/src/chattice/adapters/google_chat/parser.py +369 -0
- chattice-0.1.0/src/chattice/assets.py +23 -0
- chattice-0.1.0/src/chattice/auth/__init__.py +21 -0
- chattice-0.1.0/src/chattice/auth/providers.py +190 -0
- chattice-0.1.0/src/chattice/capabilities/__init__.py +25 -0
- chattice-0.1.0/src/chattice/capabilities/matrix.py +460 -0
- chattice-0.1.0/src/chattice/cards/__init__.py +46 -0
- chattice-0.1.0/src/chattice/cards/_assets.py +130 -0
- chattice-0.1.0/src/chattice/cards/accessory.py +40 -0
- chattice-0.1.0/src/chattice/cards/actions.py +67 -0
- chattice-0.1.0/src/chattice/cards/card.py +387 -0
- chattice-0.1.0/src/chattice/cards/dialog.py +54 -0
- chattice-0.1.0/src/chattice/cards/raw.py +55 -0
- chattice-0.1.0/src/chattice/cards/serialization.py +26 -0
- chattice-0.1.0/src/chattice/cards/status.py +42 -0
- chattice-0.1.0/src/chattice/cards/validation.py +48 -0
- chattice-0.1.0/src/chattice/cards/widgets.py +453 -0
- chattice-0.1.0/src/chattice/client/__init__.py +28 -0
- chattice-0.1.0/src/chattice/client/bot.py +1163 -0
- chattice-0.1.0/src/chattice/client/credentials.py +8 -0
- chattice-0.1.0/src/chattice/client/errors.py +119 -0
- chattice-0.1.0/src/chattice/dispatcher/__init__.py +8 -0
- chattice-0.1.0/src/chattice/dispatcher/dependency.py +189 -0
- chattice-0.1.0/src/chattice/dispatcher/dispatcher.py +302 -0
- chattice-0.1.0/src/chattice/dispatcher/handler.py +28 -0
- chattice-0.1.0/src/chattice/dispatcher/lifespan.py +87 -0
- chattice-0.1.0/src/chattice/dispatcher/middleware.py +57 -0
- chattice-0.1.0/src/chattice/dispatcher/observer.py +83 -0
- chattice-0.1.0/src/chattice/dispatcher/router.py +92 -0
- chattice-0.1.0/src/chattice/events/__init__.py +52 -0
- chattice-0.1.0/src/chattice/events/action.py +48 -0
- chattice-0.1.0/src/chattice/events/app_home.py +33 -0
- chattice-0.1.0/src/chattice/events/base.py +24 -0
- chattice-0.1.0/src/chattice/events/command.py +65 -0
- chattice-0.1.0/src/chattice/events/common.py +33 -0
- chattice-0.1.0/src/chattice/events/error.py +16 -0
- chattice-0.1.0/src/chattice/events/form.py +82 -0
- chattice-0.1.0/src/chattice/events/message.py +170 -0
- chattice-0.1.0/src/chattice/events/references.py +204 -0
- chattice-0.1.0/src/chattice/events/space.py +24 -0
- chattice-0.1.0/src/chattice/events/unknown.py +15 -0
- chattice-0.1.0/src/chattice/events/widget.py +26 -0
- chattice-0.1.0/src/chattice/exceptions/__init__.py +72 -0
- chattice-0.1.0/src/chattice/experimental/__init__.py +5 -0
- chattice-0.1.0/src/chattice/experimental/ai/__init__.py +35 -0
- chattice-0.1.0/src/chattice/experimental/ai/google.py +248 -0
- chattice-0.1.0/src/chattice/experimental/ai/models.py +168 -0
- chattice-0.1.0/src/chattice/filters/__init__.py +14 -0
- chattice-0.1.0/src/chattice/filters/base.py +65 -0
- chattice-0.1.0/src/chattice/filters/magic.py +237 -0
- chattice-0.1.0/src/chattice/forms.py +164 -0
- chattice-0.1.0/src/chattice/fsm/__init__.py +50 -0
- chattice-0.1.0/src/chattice/fsm/context.py +55 -0
- chattice-0.1.0/src/chattice/fsm/filter.py +39 -0
- chattice-0.1.0/src/chattice/fsm/record.py +405 -0
- chattice-0.1.0/src/chattice/fsm/redis.py +134 -0
- chattice-0.1.0/src/chattice/fsm/states.py +60 -0
- chattice-0.1.0/src/chattice/fsm/storage.py +132 -0
- chattice-0.1.0/src/chattice/idempotency.py +318 -0
- chattice-0.1.0/src/chattice/integrations/__init__.py +1 -0
- chattice-0.1.0/src/chattice/integrations/fastapi/__init__.py +13 -0
- chattice-0.1.0/src/chattice/integrations/fastapi/router.py +567 -0
- chattice-0.1.0/src/chattice/integrations/gcs/__init__.py +126 -0
- chattice-0.1.0/src/chattice/media/__init__.py +380 -0
- chattice-0.1.0/src/chattice/media/_rest.py +130 -0
- chattice-0.1.0/src/chattice/middleware.py +40 -0
- chattice-0.1.0/src/chattice/observability.py +25 -0
- chattice-0.1.0/src/chattice/py.typed +1 -0
- chattice-0.1.0/src/chattice/testing/__init__.py +16 -0
- chattice-0.1.0/src/chattice/testing/assertions.py +46 -0
- chattice-0.1.0/src/chattice/testing/event_factory.py +203 -0
- chattice-0.1.0/src/chattice/testing/fake_transport.py +308 -0
- chattice-0.1.0/src/chattice/testing/fsm.py +13 -0
- chattice-0.1.0/src/chattice/testing/mock_bot.py +185 -0
- chattice-0.1.0/src/chattice/transports/__init__.py +1 -0
- chattice-0.1.0/src/chattice/transports/http/__init__.py +29 -0
- chattice-0.1.0/src/chattice/transports/http/adapter.py +51 -0
- chattice-0.1.0/src/chattice/transports/http/errors.py +18 -0
- chattice-0.1.0/src/chattice/transports/http/request.py +46 -0
- chattice-0.1.0/src/chattice/transports/http/response.py +83 -0
- chattice-0.1.0/src/chattice/transports/http/verifier.py +154 -0
- chattice-0.1.0/src/chattice/transports/pubsub.py +159 -0
- chattice-0.1.0/src/chattice/transports/pubsub_runner.py +479 -0
- chattice-0.1.0/src/chattice/workspace_events/__init__.py +20 -0
- chattice-0.1.0/src/chattice/workspace_events/envelope.py +35 -0
- chattice-0.1.0/src/chattice/workspace_events/parser.py +246 -0
- chattice-0.1.0/src/chattice/workspace_events/runtime.py +340 -0
- chattice-0.1.0/tests/__init__.py +0 -0
- chattice-0.1.0/tests/auth/__init__.py +0 -0
- chattice-0.1.0/tests/auth/test_bot_auth.py +161 -0
- chattice-0.1.0/tests/auth/test_experimental_namespace.py +30 -0
- chattice-0.1.0/tests/auth/test_providers.py +111 -0
- chattice-0.1.0/tests/capabilities/__init__.py +0 -0
- chattice-0.1.0/tests/capabilities/test_gate.py +52 -0
- chattice-0.1.0/tests/capabilities/test_matrix.py +143 -0
- chattice-0.1.0/tests/capabilities/test_scope_hardening.py +183 -0
- chattice-0.1.0/tests/cards/__init__.py +0 -0
- chattice-0.1.0/tests/cards/test_actions.py +30 -0
- chattice-0.1.0/tests/cards/test_asset_publishing.py +290 -0
- chattice-0.1.0/tests/cards/test_card.py +126 -0
- chattice-0.1.0/tests/cards/test_dialog.py +26 -0
- chattice-0.1.0/tests/cards/test_dialog_observers.py +90 -0
- chattice-0.1.0/tests/cards/test_form_roundtrip.py +65 -0
- chattice-0.1.0/tests/cards/test_form_widgets.py +68 -0
- chattice-0.1.0/tests/cards/test_gate.py +76 -0
- chattice-0.1.0/tests/cards/test_gate_apphome.py +66 -0
- chattice-0.1.0/tests/cards/test_gate_dialog.py +105 -0
- chattice-0.1.0/tests/cards/test_image.py +66 -0
- chattice-0.1.0/tests/cards/test_roundtrip.py +91 -0
- chattice-0.1.0/tests/cards/test_serialization.py +34 -0
- chattice-0.1.0/tests/cards/test_snapshots.py +56 -0
- chattice-0.1.0/tests/cards/test_status.py +27 -0
- chattice-0.1.0/tests/cards/test_validation.py +22 -0
- chattice-0.1.0/tests/cards/test_widgets.py +112 -0
- chattice-0.1.0/tests/client/__init__.py +0 -0
- chattice-0.1.0/tests/client/_fake_transport.py +5 -0
- chattice-0.1.0/tests/client/test_bot_close.py +121 -0
- chattice-0.1.0/tests/client/test_bot_crud.py +99 -0
- chattice-0.1.0/tests/client/test_bot_errors.py +67 -0
- chattice-0.1.0/tests/client/test_bot_lazy.py +57 -0
- chattice-0.1.0/tests/client/test_bot_lifecycle.py +158 -0
- chattice-0.1.0/tests/client/test_bot_memberships.py +254 -0
- chattice-0.1.0/tests/client/test_bot_privacy.py +167 -0
- chattice-0.1.0/tests/client/test_bot_send.py +123 -0
- chattice-0.1.0/tests/client/test_credentials.py +18 -0
- chattice-0.1.0/tests/client/test_errors.py +85 -0
- chattice-0.1.0/tests/client/test_fake_transport.py +49 -0
- chattice-0.1.0/tests/client/test_integration.py +74 -0
- chattice-0.1.0/tests/client/test_resource_names_f13.py +50 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/README.md +23 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/dm_card_click.json +29 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/private_card_button.json +30 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/private_card_form.json +37 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/private_command.json +21 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/shared_thread_card_click_user_a.json +30 -0
- chattice-0.1.0/tests/fixtures/google_chat/conformance/shared_thread_card_click_user_b.json +30 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/README.md +44 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/added_to_space.json +5 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/app_command.json +8 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/app_home.json +7 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/app_home_card_clicked.json +10 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked.json +16 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked_cancel_dialog.json +6 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked_form.json +14 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked_human_message.json +37 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked_request_dialog.json +6 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/card_clicked_submit_dialog.json +9 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/malformed_conflict.json +1 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/malformed_missing_type.json +1 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/malformed_timestamp.json +1 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/malformed_type.json +1 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/message.json +12 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/message_action.json +15 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/message_matched_url.json +21 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/removed_from_space.json +5 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/slash_command.json +22 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/submit_form.json +12 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/unknown_event.json +5 -0
- chattice-0.1.0/tests/fixtures/google_chat/interactions/widget_updated.json +8 -0
- chattice-0.1.0/tests/fsm/__init__.py +0 -0
- chattice-0.1.0/tests/fsm/test_context.py +52 -0
- chattice-0.1.0/tests/fsm/test_dispatcher_integration.py +84 -0
- chattice-0.1.0/tests/fsm/test_filter.py +54 -0
- chattice-0.1.0/tests/fsm/test_gate.py +91 -0
- chattice-0.1.0/tests/fsm/test_memory_storage.py +58 -0
- chattice-0.1.0/tests/fsm/test_record.py +256 -0
- chattice-0.1.0/tests/fsm/test_redis_storage.py +80 -0
- chattice-0.1.0/tests/fsm/test_states.py +36 -0
- chattice-0.1.0/tests/fsm/test_storage_key.py +63 -0
- chattice-0.1.0/tests/integration/__init__.py +0 -0
- chattice-0.1.0/tests/integration/live/README.md +79 -0
- chattice-0.1.0/tests/integration/live/__init__.py +0 -0
- chattice-0.1.0/tests/integration/live/test_smoke.py +165 -0
- chattice-0.1.0/tests/integration/test_personal_shared_conformance.py +466 -0
- chattice-0.1.0/tests/integrations/test_gcs_assets.py +223 -0
- chattice-0.1.0/tests/media/__init__.py +0 -0
- chattice-0.1.0/tests/media/test_attachment_identity.py +350 -0
- chattice-0.1.0/tests/media/test_attachment_ref.py +103 -0
- chattice-0.1.0/tests/media/test_bot_media.py +440 -0
- chattice-0.1.0/tests/media/test_inputfile.py +200 -0
- chattice-0.1.0/tests/media/test_media_rest.py +202 -0
- chattice-0.1.0/tests/media/test_message_attachment_refs.py +39 -0
- chattice-0.1.0/tests/reliability/__init__.py +0 -0
- chattice-0.1.0/tests/reliability/test_gate.py +206 -0
- chattice-0.1.0/tests/reliability/test_idempotency.py +134 -0
- chattice-0.1.0/tests/reliability/test_observability.py +79 -0
- chattice-0.1.0/tests/reliability/test_redaction.py +176 -0
- chattice-0.1.0/tests/reliability/test_redis_lifecycle_f09.py +119 -0
- chattice-0.1.0/tests/reliability/test_timeout_cancellation.py +64 -0
- chattice-0.1.0/tests/test_accessory_widgets.py +110 -0
- chattice-0.1.0/tests/test_actions.py +198 -0
- chattice-0.1.0/tests/test_ai.py +296 -0
- chattice-0.1.0/tests/test_ai_gemini_hardening.py +170 -0
- chattice-0.1.0/tests/test_apphome_integration.py +118 -0
- chattice-0.1.0/tests/test_architecture.py +236 -0
- chattice-0.1.0/tests/test_cards_integration.py +243 -0
- chattice-0.1.0/tests/test_codec_form_card_f11.py +154 -0
- chattice-0.1.0/tests/test_command_routing.py +122 -0
- chattice-0.1.0/tests/test_dependency.py +135 -0
- chattice-0.1.0/tests/test_dialog_envelope_truth_table.py +223 -0
- chattice-0.1.0/tests/test_dialog_integration.py +158 -0
- chattice-0.1.0/tests/test_dispatcher.py +192 -0
- chattice-0.1.0/tests/test_documentation_examples.py +45 -0
- chattice-0.1.0/tests/test_dx_enrichment.py +249 -0
- chattice-0.1.0/tests/test_events.py +55 -0
- chattice-0.1.0/tests/test_examples.py +121 -0
- chattice-0.1.0/tests/test_fastapi_integration.py +282 -0
- chattice-0.1.0/tests/test_filters.py +279 -0
- chattice-0.1.0/tests/test_forms.py +127 -0
- chattice-0.1.0/tests/test_gap_hardening.py +148 -0
- chattice-0.1.0/tests/test_google_interactions.py +445 -0
- chattice-0.1.0/tests/test_immutable_facades_f10.py +82 -0
- chattice-0.1.0/tests/test_lifespan.py +77 -0
- chattice-0.1.0/tests/test_log_redaction.py +140 -0
- chattice-0.1.0/tests/test_middleware.py +176 -0
- chattice-0.1.0/tests/test_persistent_actions.py +104 -0
- chattice-0.1.0/tests/test_pubsub_workspace_integration.py +423 -0
- chattice-0.1.0/tests/test_raw_and_validation.py +140 -0
- chattice-0.1.0/tests/test_regexp_filters.py +72 -0
- chattice-0.1.0/tests/test_router.py +198 -0
- chattice-0.1.0/tests/testing/__init__.py +0 -0
- chattice-0.1.0/tests/testing/test_assertions_fsm.py +56 -0
- chattice-0.1.0/tests/testing/test_event_factory.py +70 -0
- chattice-0.1.0/tests/testing/test_gate.py +23 -0
- chattice-0.1.0/tests/testing/test_mock_bot.py +75 -0
- chattice-0.1.0/tests/transports/__init__.py +0 -0
- chattice-0.1.0/tests/transports/http/__init__.py +0 -0
- chattice-0.1.0/tests/transports/http/_test_tokens.py +91 -0
- chattice-0.1.0/tests/transports/http/test_adapter.py +58 -0
- chattice-0.1.0/tests/transports/http/test_errors.py +22 -0
- chattice-0.1.0/tests/transports/http/test_pubsub.py +68 -0
- chattice-0.1.0/tests/transports/http/test_request.py +46 -0
- chattice-0.1.0/tests/transports/http/test_response.py +38 -0
- chattice-0.1.0/tests/transports/http/test_verifier.py +325 -0
- chattice-0.1.0/tests/transports/test_pubsub_runner.py +487 -0
- chattice-0.1.0/tests/transports/test_pubsub_verifier.py +97 -0
- chattice-0.1.0/tests/workspace_events/__init__.py +0 -0
- chattice-0.1.0/tests/workspace_events/test_gate.py +86 -0
- chattice-0.1.0/tests/workspace_events/test_observer.py +71 -0
- chattice-0.1.0/tests/workspace_events/test_parser.py +393 -0
- chattice-0.1.0/uv.lock +2458 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
.venv/
|
|
2
|
+
.coverage
|
|
3
|
+
.mypy_cache/
|
|
4
|
+
.pytest_cache/
|
|
5
|
+
.ruff_cache/
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.py[cod]
|
|
8
|
+
build/
|
|
9
|
+
dist/
|
|
10
|
+
site/
|
|
11
|
+
*.egg-info/
|
|
12
|
+
.DS_Store
|
|
13
|
+
|
|
14
|
+
.coverage*
|
|
15
|
+
|
|
16
|
+
.secrets/
|
|
17
|
+
token.json
|
|
18
|
+
oauth-client.json
|
|
19
|
+
service-account*.json
|
|
20
|
+
|
|
21
|
+
# macOS synchronization duplicates.
|
|
22
|
+
* [0-9]
|
|
23
|
+
* [0-9].*
|
|
24
|
+
.env
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes are documented here. The project follows Semantic
|
|
4
|
+
Versioning. Before 1.0, incompatible changes may be released in a minor
|
|
5
|
+
version and will include migration notes.
|
|
6
|
+
|
|
7
|
+
## [0.1.0] — Initial public release
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- Async dispatcher, routers, middleware, dependency injection, filters, and
|
|
12
|
+
typed Google Chat interaction events.
|
|
13
|
+
- HTTP, Pub/Sub, streaming-pull, and Google Workspace Events integrations.
|
|
14
|
+
- Async Google Chat API client with app and delegated-user authentication.
|
|
15
|
+
- Typed Cards v2 builders, dialogs, forms, App Home responses, card updates,
|
|
16
|
+
attachments, and optional Card image publishing.
|
|
17
|
+
- Finite-state storage, idempotency storage, Redis integrations, lifecycle
|
|
18
|
+
resources, and observability hooks.
|
|
19
|
+
- FastAPI integration, testing helpers, runnable examples, API reference, and
|
|
20
|
+
deployment guidance.
|
|
21
|
+
- Raw Google payload and client escape hatches for forward compatibility.
|
|
22
|
+
- Automated dependency, Google Chat schema, Cards SDK, and release-note
|
|
23
|
+
monitoring.
|
|
24
|
+
|
|
25
|
+
### Compatibility
|
|
26
|
+
|
|
27
|
+
- Python 3.11, 3.12, and 3.13.
|
|
28
|
+
- Google Chat API v1 and Cards v2.
|
|
29
|
+
- The package distribution and Python import are both named `chattice`.
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Contributing to Chattice
|
|
2
|
+
|
|
3
|
+
Chattice is an async Python framework for Google Chat apps. Contributions
|
|
4
|
+
that are naturally additive are the most welcome:
|
|
5
|
+
|
|
6
|
+
- new Google UI support (widgets, cards)
|
|
7
|
+
- Google API wrappers behind the raw escape hatch pattern
|
|
8
|
+
- tests, examples, docs, bug fixes
|
|
9
|
+
|
|
10
|
+
## Workflow
|
|
11
|
+
|
|
12
|
+
1. Open an issue describing the problem or idea (no PR-first for
|
|
13
|
+
architectural changes — see the RFC rule below).
|
|
14
|
+
2. Branch off `main`; implement with tests.
|
|
15
|
+
3. Run the full gate suite:
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
uv sync --all-groups
|
|
19
|
+
uv run pytest -q
|
|
20
|
+
uv run mypy src tests
|
|
21
|
+
uv run ruff check . && uv run ruff format --check .
|
|
22
|
+
uv run mkdocs build --strict
|
|
23
|
+
bash scripts/verify_package.sh
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
4. Open a PR. The description must state: the problem, public API
|
|
27
|
+
impact, compatibility impact, tests/docs added, risk level, and
|
|
28
|
+
whether core changed.
|
|
29
|
+
|
|
30
|
+
## Rules
|
|
31
|
+
|
|
32
|
+
- New examples must expose a `main()` executed from
|
|
33
|
+
`tests/test_examples.py` (docs can never drift).
|
|
34
|
+
- Fixtures must be official payload shapes with provenance recorded in
|
|
35
|
+
`tests/fixtures/google_chat/interactions/README.md`.
|
|
36
|
+
- Public API changes require the public-API rule (charter §7): typing,
|
|
37
|
+
tests, docs, deliberate export, compatibility review.
|
|
38
|
+
- Architectural changes (Dispatcher/Router/FSM contracts, new workflow
|
|
39
|
+
engines, package splits, breaking API) require a lightweight design
|
|
40
|
+
proposal first: Problem · Current behavior · Proposed API · Why the
|
|
41
|
+
current API is insufficient · Alternatives · Compatibility ·
|
|
42
|
+
Migration · Maintenance cost · Simpler solutions rejected.
|
|
43
|
+
|
|
44
|
+
## License
|
|
45
|
+
|
|
46
|
+
MIT. By contributing you agree your contributions are licensed
|
|
47
|
+
under it. No CLA required.
|
|
48
|
+
|
|
49
|
+
## Upstream Google changes
|
|
50
|
+
|
|
51
|
+
Google updates the wire layer (`google-apps-chat`, `google-apps-card`)
|
|
52
|
+
and ships Developer Preview features continuously. The documented public
|
|
53
|
+
surface changes deliberately, so every upstream change follows one protocol:
|
|
54
|
+
|
|
55
|
+
1. An update PR arrives from dependabot (weekly, `google-sdks` group)
|
|
56
|
+
or from the weekly `upstream-check` workflow's `upstream` issue.
|
|
57
|
+
2. CI runs the full suite, mypy/ruff, and the golden fixtures.
|
|
58
|
+
3. Wire analysis of the SDK diff:
|
|
59
|
+
- a new event FIELD → keep it lossless (`raw`), add a round-trip
|
|
60
|
+
test; no public API change;
|
|
61
|
+
- a new event TYPE → decide: typed support (adapter + capability)
|
|
62
|
+
or explicit `UnknownEvent`; update the Google API mapping and the
|
|
63
|
+
capabilities matrix;
|
|
64
|
+
- a breaking change → P0 issue, a Chattice semver decision (rare).
|
|
65
|
+
4. Update fixtures (reviewed), docs (mapping/capabilities), and the
|
|
66
|
+
compatibility revision.
|
|
67
|
+
5. Pre-release: run every example (the `examples/docs/from_zero.py`
|
|
68
|
+
journey plus the bots/scenarios).
|
|
69
|
+
|
|
70
|
+
Principles: Google updates are additive INSIDE the adapters; the public
|
|
71
|
+
Chattice surface changes only by Chattice's own semver decision. The
|
|
72
|
+
lossless paths (`UnknownEvent`, `RawWidget`, `Bot.raw_client`) absorb
|
|
73
|
+
new Google types — a new type must never crash existing bots.
|
chattice-0.1.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Chattice contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
chattice-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,210 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: chattice
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Async typed event framework for Google Chat apps
|
|
5
|
+
Project-URL: Documentation, https://whiteysage.github.io/chattice/
|
|
6
|
+
Project-URL: Source, https://github.com/WhiteySage/chattice
|
|
7
|
+
Project-URL: Issues, https://github.com/WhiteySage/chattice/issues
|
|
8
|
+
Project-URL: Changelog, https://github.com/WhiteySage/chattice/blob/main/CHANGELOG.md
|
|
9
|
+
Author: WhiteySage
|
|
10
|
+
License-Expression: MIT
|
|
11
|
+
License-File: LICENSE
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Framework :: AsyncIO
|
|
14
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
15
|
+
Classifier: Programming Language :: Python :: 3
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
19
|
+
Classifier: Typing :: Typed
|
|
20
|
+
Requires-Python: >=3.11
|
|
21
|
+
Requires-Dist: google-apps-chat<1.0.0,>=0.10.4
|
|
22
|
+
Requires-Dist: google-auth<3,>=2.30
|
|
23
|
+
Requires-Dist: pydantic<3.0,>=2.10
|
|
24
|
+
Provides-Extra: fastapi
|
|
25
|
+
Requires-Dist: fastapi<1,>=0.115; extra == 'fastapi'
|
|
26
|
+
Provides-Extra: gcs
|
|
27
|
+
Requires-Dist: google-cloud-storage<4,>=3; extra == 'gcs'
|
|
28
|
+
Provides-Extra: gemini
|
|
29
|
+
Requires-Dist: google-genai<3,>=1; extra == 'gemini'
|
|
30
|
+
Provides-Extra: media
|
|
31
|
+
Requires-Dist: google-api-python-client<3,>=2.198; extra == 'media'
|
|
32
|
+
Provides-Extra: pubsub
|
|
33
|
+
Requires-Dist: google-cloud-pubsub<3,>=2.21; extra == 'pubsub'
|
|
34
|
+
Provides-Extra: redis
|
|
35
|
+
Requires-Dist: redis<7,>=5; extra == 'redis'
|
|
36
|
+
Description-Content-Type: text/markdown
|
|
37
|
+
|
|
38
|
+
<img src="https://raw.githubusercontent.com/WhiteySage/chattice/main/docs/assets/brand/chattice-logo.png"
|
|
39
|
+
alt="Chattice" width="320" />
|
|
40
|
+
|
|
41
|
+
# Chattice
|
|
42
|
+
|
|
43
|
+
Async, typed event framework for Google Chat apps — aiogram-quality DX, Google-native semantics.
|
|
44
|
+
|
|
45
|
+
[](https://pypi.org/project/chattice/)
|
|
46
|
+
[](LICENSE)
|
|
47
|
+
[](#status)
|
|
48
|
+
[](https://github.com/WhiteySage/chattice/discussions)
|
|
49
|
+
|
|
50
|
+
```python
|
|
51
|
+
from chattice import Dispatcher, F, Router
|
|
52
|
+
from chattice.events import MessageEvent
|
|
53
|
+
|
|
54
|
+
router = Router()
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
@router.message(F.text == "ping")
|
|
58
|
+
async def ping(message: MessageEvent) -> str:
|
|
59
|
+
return "pong" # synchronous interaction response (no auth, 30 s deadline)
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
dispatcher = Dispatcher()
|
|
63
|
+
dispatcher.include_router(router)
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
## What this is
|
|
67
|
+
|
|
68
|
+
- **Google Chat-native.** Space, Thread, Message, Command, Action, Card,
|
|
69
|
+
Dialog, App Home, Workspace Events are first-class typed objects. No
|
|
70
|
+
Telegram concepts leak into the domain model.
|
|
71
|
+
- **aiogram ergonomics.** Routers, magic filters (`F`), middleware,
|
|
72
|
+
dependency injection, FSM — the DX you know, without Telegram
|
|
73
|
+
semantics.
|
|
74
|
+
- **Explicit response model.** A handler RETURN is the synchronous
|
|
75
|
+
interaction response (30 s deadline); outbound `Bot` calls are
|
|
76
|
+
separate authenticated operations. Contextual `message.reply()` /
|
|
77
|
+
`thread.send()` / `space.send()` methods are zero-fetch adapters over
|
|
78
|
+
that same Bot, never a hidden second channel.
|
|
79
|
+
- **Secure by default.** Incoming verification is fail-closed, push
|
|
80
|
+
endpoints require a verifier, outbound privacy gates (private
|
|
81
|
+
messages, notifications, preview features) fail closed before any
|
|
82
|
+
network call.
|
|
83
|
+
- **Core is small.** Core abstracts Google Chat platform primitives and
|
|
84
|
+
technical boilerplate ONLY. Business scenarios (polls, approvals,
|
|
85
|
+
tickets) are assembled from the primitives in your
|
|
86
|
+
application code — never added to core.
|
|
87
|
+
|
|
88
|
+
## What this is not
|
|
89
|
+
|
|
90
|
+
- **Not a Telegram framework.** No `chat_id`, no `CallbackQuery`, no
|
|
91
|
+
`Update` hierarchy, no Telegram-style long polling (see the
|
|
92
|
+
[aiogram comparison](https://whiteysage.github.io/chattice/aiogram-comparison/)).
|
|
93
|
+
- **Not a Google product.** Independent open-source project, not
|
|
94
|
+
endorsed by Google.
|
|
95
|
+
|
|
96
|
+
## Two ways to run
|
|
97
|
+
|
|
98
|
+
Chattice has two honest startup models (see the
|
|
99
|
+
[aiogram side-by-side](docs/aiogram-comparison.md)):
|
|
100
|
+
|
|
101
|
+
```python
|
|
102
|
+
# HTTP — Google calls your HTTPS endpoint; the handler RETURN is the
|
|
103
|
+
# synchronous response (Dialogs and App Home work here).
|
|
104
|
+
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience=...)))
|
|
105
|
+
# python -m uvicorn app:app
|
|
106
|
+
|
|
107
|
+
# Pub/Sub streaming pull — a persistent subscriber process, visually
|
|
108
|
+
# like aiogram's start_polling, but it is NOT Telegram polling.
|
|
109
|
+
# No domain/TLS needed; no Dialogs, no App Home — answers go outbound
|
|
110
|
+
# through the authenticated Bot.
|
|
111
|
+
await dispatcher.run_pubsub(subscription, bot=bot)
|
|
112
|
+
# python app.py
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
## Capabilities
|
|
116
|
+
|
|
117
|
+
| Area | Support |
|
|
118
|
+
| --- | --- |
|
|
119
|
+
| Events | MESSAGE, CARD_CLICKED, APP_COMMAND (slash/quick/message actions), ADDED/REMOVED_FROM_SPACE, APP_HOME, SUBMIT_FORM, WIDGET_UPDATED |
|
|
120
|
+
| Routing | Routers, observer-wide filters, magic filters, middleware, DI |
|
|
121
|
+
| Cards | Typed facades, public/non-sensitive PNG/JPEG publication through an optional AssetPublisher, sync updates |
|
|
122
|
+
| Memberships | APP-auth add/get/list/remove for internal human users; caller-member Space listing |
|
|
123
|
+
| Dialogs | OPEN_DIALOG, submit/cancel observers, action status; capability-gated per transport |
|
|
124
|
+
| FSM | State/StatesGroup, Memory + Redis record storage (compare-and-set) |
|
|
125
|
+
| Ingress | HTTP (verified), Pub/Sub push (verified), Pub/Sub streaming pull, Workspace Events CloudEvents |
|
|
126
|
+
| Media | Local-file attachments sent with USER auth end to end (`media.upload` → `messages.create`, sender = HUMAN); download USER/APP; metadata APP; 200 MB local preflight |
|
|
127
|
+
| Auth | App (service account), user (OAuth refresh), incoming verification |
|
|
128
|
+
| Testing | MockBot, EventFactory, assertions, fake transport |
|
|
129
|
+
|
|
130
|
+
## Install
|
|
131
|
+
|
|
132
|
+
Python 3.11+ (3.11–3.13 tested). MIT-licensed.
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
pip install "chattice[fastapi,pubsub,redis]" # core + all integrations
|
|
136
|
+
|
|
137
|
+
# or pick only what you need:
|
|
138
|
+
# pip install chattice core
|
|
139
|
+
# pip install "chattice[fastapi]" FastAPI integration
|
|
140
|
+
# pip install "chattice[redis]" Redis FSM/idempotency storage
|
|
141
|
+
# pip install "chattice[pubsub]" Pub/Sub push + streaming pull
|
|
142
|
+
# pip install "chattice[gcs]" Local Card image publication through GCS
|
|
143
|
+
|
|
144
|
+
# using uv
|
|
145
|
+
uv add "chattice[fastapi,pubsub,redis]"
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
## Quickstart
|
|
149
|
+
|
|
150
|
+
1. Parse a documented interaction payload:
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
from chattice.adapters.google_chat import parse_interaction
|
|
154
|
+
|
|
155
|
+
event = parse_interaction(payload)
|
|
156
|
+
result = await dispatcher.feed_update(event)
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
2. Serve HTTP interactions (FastAPI):
|
|
160
|
+
|
|
161
|
+
```python
|
|
162
|
+
from fastapi import FastAPI
|
|
163
|
+
from chattice.integrations.fastapi import create_chat_router
|
|
164
|
+
from chattice.transports.http import GoogleTokenVerifier
|
|
165
|
+
|
|
166
|
+
app = FastAPI()
|
|
167
|
+
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience="...")))
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
3. Send messages:
|
|
171
|
+
|
|
172
|
+
```python
|
|
173
|
+
from chattice.client import Bot
|
|
174
|
+
|
|
175
|
+
bot = Bot(credentials=...)
|
|
176
|
+
await bot.send_message("spaces/AAA", text="hello")
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
Inside an interaction handler, configure the same Bot once and use the known
|
|
180
|
+
Google context without extra fetches:
|
|
181
|
+
|
|
182
|
+
```python
|
|
183
|
+
dispatcher = Dispatcher(bot=bot)
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
@router.message()
|
|
187
|
+
async def reply(message: MessageEvent) -> None:
|
|
188
|
+
await message.reply("hello in this thread")
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Docs
|
|
192
|
+
|
|
193
|
+
Start with [Installation](https://whiteysage.github.io/chattice/getting-started/installation/), the
|
|
194
|
+
[5-minute Quickstart](https://whiteysage.github.io/chattice/getting-started/quickstart/), and the
|
|
195
|
+
[Space → Thread → Message mental model](https://whiteysage.github.io/chattice/concepts/mental-model/). The
|
|
196
|
+
[public API reference](https://whiteysage.github.io/chattice/public-api/), [Google mapping](https://whiteysage.github.io/chattice/reference/google-api-mapping/),
|
|
197
|
+
and [aiogram comparison](https://whiteysage.github.io/chattice/aiogram-comparison/) are linked from the docs site.
|
|
198
|
+
Runnable examples live in [`examples/`](https://github.com/WhiteySage/chattice/tree/main/examples); machine-readable documentation is available in
|
|
199
|
+
[`llms.txt`](https://whiteysage.github.io/chattice/llms.txt).
|
|
200
|
+
|
|
201
|
+
## Status
|
|
202
|
+
|
|
203
|
+
Pre-1.0 **public release** (current version 0.1.0) — see
|
|
204
|
+
[CHANGELOG](CHANGELOG.md). The documented public
|
|
205
|
+
surface is the compatibility baseline: pre-1.0 work may add APIs but does not incompatibly
|
|
206
|
+
rename, remove, or change existing contracts. `chattice.experimental`
|
|
207
|
+
has no compatibility promise. `Bot.raw_client` and raw event payloads
|
|
208
|
+
follow Google's SDK and wire schema rather than the stable facade
|
|
209
|
+
promise. **Not an official Google product** — independent open-source
|
|
210
|
+
software, not endorsed by Google. MIT License, see [LICENSE](https://github.com/WhiteySage/chattice/blob/main/LICENSE).
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# PUBLIC_API — machine-readable index
|
|
2
|
+
|
|
3
|
+
This file is the compact machine-readable index. The full
|
|
4
|
+
human reference: `docs/public-api.md`; rendered signatures:
|
|
5
|
+
`docs/api.md`. Architecture test `tests/test_architecture.py::test_every_public_export_is_importable` pins every package's `__all__`; the canonical entry-point rule lives in `docs/public-api.md`.
|
|
6
|
+
|
|
7
|
+
- chattice: Dispatcher · Router · F · __version__
|
|
8
|
+
- chattice.actions: ActionData (`function=` discriminator binding) · ActionDataDecodeError · ActionDataFilter
|
|
9
|
+
- chattice.assets: AssetPublisher
|
|
10
|
+
- chattice.auth: AuthMode · CredentialsProvider · ServiceAccountCredentialsProvider · UserCredentialsProvider · CHAT_BOT_SCOPE · CHAT_APP_MEMBERSHIPS_SCOPE
|
|
11
|
+
- chattice.capabilities: ResponseCapabilities · ResponseCapability · OutboundCapabilities · OutboundCapability · PreviewCapabilities · PreviewFeature · PREVIEW_APP_COMMAND_TYPES · CapabilityNotSupported
|
|
12
|
+
- chattice.cards: Card · CardHeader · Section · Button (string or ActionData binding) · ButtonList · TextParagraph · Divider · Image (`from_url`/`from_path`/`from_bytes`) · TextInput · SelectionInput · DateTimePicker · Action · OpenLink · Dialog · ActionStatus · ActionStatusCode · Validation · TextInputType · AccessoryWidget · RawWidget
|
|
13
|
+
- chattice.client: Bot (message/media/Card asset/membership/Space operations) · MessageReplyOption · ChatAPIError + wrapped error classes · wrap_api_error · CredentialsProvider (compat re-export)
|
|
14
|
+
- chattice.dispatcher: Dispatcher (`bot=` contextual binding) · Router · EventObserver · Lifespan · LifespanResource
|
|
15
|
+
- chattice.events: Event · MessageEvent (`reply`, lossless read metadata) · CommandEvent · CommandKind · ActionEvent · ActionSource · AddedToSpaceEvent · RemovedFromSpaceEvent · UnknownEvent · ErrorEvent · AppHomeEvent · FormSubmitEvent · WidgetUpdatedEvent · SpaceRef.send · ThreadRef.send · refs · form input values · DialogEventType · TimeZone
|
|
16
|
+
- chattice.filters: F · MagicExpression · MagicField · Filter · BaseFilter · FilterLike · FilterValue
|
|
17
|
+
- chattice.forms: FormModel · FormDecodeError · FormFilter
|
|
18
|
+
- chattice.fsm: State · StatesGroup · FSMContext · FSMStrategy · StorageKey · BaseStorage · MemoryStorage · RedisStorage (lazy) · StateFilter · FSMError · FSMRecord · FSMRecordConflict · FSMRecordStorage · MemoryFSMRecordStorage · RedisFSMRecordStorage (lazy) · BaseStorageFromRecord
|
|
19
|
+
- chattice.idempotency: IdempotencyStorage · MemoryIdempotencyStorage · RedisIdempotencyStorage · ClaimResult · new_owner
|
|
20
|
+
- chattice.integrations.fastapi: create_chat_router · create_pubsub_router · create_workspace_events_router
|
|
21
|
+
- chattice.integrations.gcs: GCSAssetPublisher
|
|
22
|
+
- chattice.middleware: Middleware · BaseMiddleware · MiddlewareLike · NextHandler
|
|
23
|
+
- chattice.observability: ObservabilityHooks
|
|
24
|
+
- chattice.testing: MockBot · EventFactory · FakeChatTransport · assert_card_has_button · assert_card_header · set_state_for
|
|
25
|
+
- chattice.transports.http: SYNC_RESPONSE_DEADLINE · HTTPInteractionAdapter · InteractionContext · IncomingRequest · IncomingRequestVerifier · GoogleTokenVerifier · MockVerifier · InteractionResponse · ResponseState · WidgetAutocomplete · RawInteractionResponse · VerificationError · DoubleResponseError
|
|
26
|
+
- chattice.transports.pubsub: PubSubPushAdapter · PubSubEnvelopeError · decode_message_data · PubSubPushVerifier · GooglePubSubVerifier · MockPubSubVerifier
|
|
27
|
+
- chattice.workspace_events: EventsDispatcher · EventsRouter · WorkspaceEvent · WorkspaceEventType · WorkspaceEventError · parse_workspace_event · parse_workspace_envelope
|
|
28
|
+
- chattice.experimental: marker has no direct exports; chattice.experimental.ai is distributed but explicitly unstable and outside the stable API
|
chattice-0.1.0/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
<img src="https://raw.githubusercontent.com/WhiteySage/chattice/main/docs/assets/brand/chattice-logo.png"
|
|
2
|
+
alt="Chattice" width="320" />
|
|
3
|
+
|
|
4
|
+
# Chattice
|
|
5
|
+
|
|
6
|
+
Async, typed event framework for Google Chat apps — aiogram-quality DX, Google-native semantics.
|
|
7
|
+
|
|
8
|
+
[](https://pypi.org/project/chattice/)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
[](#status)
|
|
11
|
+
[](https://github.com/WhiteySage/chattice/discussions)
|
|
12
|
+
|
|
13
|
+
```python
|
|
14
|
+
from chattice import Dispatcher, F, Router
|
|
15
|
+
from chattice.events import MessageEvent
|
|
16
|
+
|
|
17
|
+
router = Router()
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
@router.message(F.text == "ping")
|
|
21
|
+
async def ping(message: MessageEvent) -> str:
|
|
22
|
+
return "pong" # synchronous interaction response (no auth, 30 s deadline)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
dispatcher = Dispatcher()
|
|
26
|
+
dispatcher.include_router(router)
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## What this is
|
|
30
|
+
|
|
31
|
+
- **Google Chat-native.** Space, Thread, Message, Command, Action, Card,
|
|
32
|
+
Dialog, App Home, Workspace Events are first-class typed objects. No
|
|
33
|
+
Telegram concepts leak into the domain model.
|
|
34
|
+
- **aiogram ergonomics.** Routers, magic filters (`F`), middleware,
|
|
35
|
+
dependency injection, FSM — the DX you know, without Telegram
|
|
36
|
+
semantics.
|
|
37
|
+
- **Explicit response model.** A handler RETURN is the synchronous
|
|
38
|
+
interaction response (30 s deadline); outbound `Bot` calls are
|
|
39
|
+
separate authenticated operations. Contextual `message.reply()` /
|
|
40
|
+
`thread.send()` / `space.send()` methods are zero-fetch adapters over
|
|
41
|
+
that same Bot, never a hidden second channel.
|
|
42
|
+
- **Secure by default.** Incoming verification is fail-closed, push
|
|
43
|
+
endpoints require a verifier, outbound privacy gates (private
|
|
44
|
+
messages, notifications, preview features) fail closed before any
|
|
45
|
+
network call.
|
|
46
|
+
- **Core is small.** Core abstracts Google Chat platform primitives and
|
|
47
|
+
technical boilerplate ONLY. Business scenarios (polls, approvals,
|
|
48
|
+
tickets) are assembled from the primitives in your
|
|
49
|
+
application code — never added to core.
|
|
50
|
+
|
|
51
|
+
## What this is not
|
|
52
|
+
|
|
53
|
+
- **Not a Telegram framework.** No `chat_id`, no `CallbackQuery`, no
|
|
54
|
+
`Update` hierarchy, no Telegram-style long polling (see the
|
|
55
|
+
[aiogram comparison](https://whiteysage.github.io/chattice/aiogram-comparison/)).
|
|
56
|
+
- **Not a Google product.** Independent open-source project, not
|
|
57
|
+
endorsed by Google.
|
|
58
|
+
|
|
59
|
+
## Two ways to run
|
|
60
|
+
|
|
61
|
+
Chattice has two honest startup models (see the
|
|
62
|
+
[aiogram side-by-side](docs/aiogram-comparison.md)):
|
|
63
|
+
|
|
64
|
+
```python
|
|
65
|
+
# HTTP — Google calls your HTTPS endpoint; the handler RETURN is the
|
|
66
|
+
# synchronous response (Dialogs and App Home work here).
|
|
67
|
+
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience=...)))
|
|
68
|
+
# python -m uvicorn app:app
|
|
69
|
+
|
|
70
|
+
# Pub/Sub streaming pull — a persistent subscriber process, visually
|
|
71
|
+
# like aiogram's start_polling, but it is NOT Telegram polling.
|
|
72
|
+
# No domain/TLS needed; no Dialogs, no App Home — answers go outbound
|
|
73
|
+
# through the authenticated Bot.
|
|
74
|
+
await dispatcher.run_pubsub(subscription, bot=bot)
|
|
75
|
+
# python app.py
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Capabilities
|
|
79
|
+
|
|
80
|
+
| Area | Support |
|
|
81
|
+
| --- | --- |
|
|
82
|
+
| Events | MESSAGE, CARD_CLICKED, APP_COMMAND (slash/quick/message actions), ADDED/REMOVED_FROM_SPACE, APP_HOME, SUBMIT_FORM, WIDGET_UPDATED |
|
|
83
|
+
| Routing | Routers, observer-wide filters, magic filters, middleware, DI |
|
|
84
|
+
| Cards | Typed facades, public/non-sensitive PNG/JPEG publication through an optional AssetPublisher, sync updates |
|
|
85
|
+
| Memberships | APP-auth add/get/list/remove for internal human users; caller-member Space listing |
|
|
86
|
+
| Dialogs | OPEN_DIALOG, submit/cancel observers, action status; capability-gated per transport |
|
|
87
|
+
| FSM | State/StatesGroup, Memory + Redis record storage (compare-and-set) |
|
|
88
|
+
| Ingress | HTTP (verified), Pub/Sub push (verified), Pub/Sub streaming pull, Workspace Events CloudEvents |
|
|
89
|
+
| Media | Local-file attachments sent with USER auth end to end (`media.upload` → `messages.create`, sender = HUMAN); download USER/APP; metadata APP; 200 MB local preflight |
|
|
90
|
+
| Auth | App (service account), user (OAuth refresh), incoming verification |
|
|
91
|
+
| Testing | MockBot, EventFactory, assertions, fake transport |
|
|
92
|
+
|
|
93
|
+
## Install
|
|
94
|
+
|
|
95
|
+
Python 3.11+ (3.11–3.13 tested). MIT-licensed.
|
|
96
|
+
|
|
97
|
+
```bash
|
|
98
|
+
pip install "chattice[fastapi,pubsub,redis]" # core + all integrations
|
|
99
|
+
|
|
100
|
+
# or pick only what you need:
|
|
101
|
+
# pip install chattice core
|
|
102
|
+
# pip install "chattice[fastapi]" FastAPI integration
|
|
103
|
+
# pip install "chattice[redis]" Redis FSM/idempotency storage
|
|
104
|
+
# pip install "chattice[pubsub]" Pub/Sub push + streaming pull
|
|
105
|
+
# pip install "chattice[gcs]" Local Card image publication through GCS
|
|
106
|
+
|
|
107
|
+
# using uv
|
|
108
|
+
uv add "chattice[fastapi,pubsub,redis]"
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
## Quickstart
|
|
112
|
+
|
|
113
|
+
1. Parse a documented interaction payload:
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from chattice.adapters.google_chat import parse_interaction
|
|
117
|
+
|
|
118
|
+
event = parse_interaction(payload)
|
|
119
|
+
result = await dispatcher.feed_update(event)
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
2. Serve HTTP interactions (FastAPI):
|
|
123
|
+
|
|
124
|
+
```python
|
|
125
|
+
from fastapi import FastAPI
|
|
126
|
+
from chattice.integrations.fastapi import create_chat_router
|
|
127
|
+
from chattice.transports.http import GoogleTokenVerifier
|
|
128
|
+
|
|
129
|
+
app = FastAPI()
|
|
130
|
+
app.include_router(create_chat_router(dispatcher, GoogleTokenVerifier(audience="...")))
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
3. Send messages:
|
|
134
|
+
|
|
135
|
+
```python
|
|
136
|
+
from chattice.client import Bot
|
|
137
|
+
|
|
138
|
+
bot = Bot(credentials=...)
|
|
139
|
+
await bot.send_message("spaces/AAA", text="hello")
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
Inside an interaction handler, configure the same Bot once and use the known
|
|
143
|
+
Google context without extra fetches:
|
|
144
|
+
|
|
145
|
+
```python
|
|
146
|
+
dispatcher = Dispatcher(bot=bot)
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
@router.message()
|
|
150
|
+
async def reply(message: MessageEvent) -> None:
|
|
151
|
+
await message.reply("hello in this thread")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
## Docs
|
|
155
|
+
|
|
156
|
+
Start with [Installation](https://whiteysage.github.io/chattice/getting-started/installation/), the
|
|
157
|
+
[5-minute Quickstart](https://whiteysage.github.io/chattice/getting-started/quickstart/), and the
|
|
158
|
+
[Space → Thread → Message mental model](https://whiteysage.github.io/chattice/concepts/mental-model/). The
|
|
159
|
+
[public API reference](https://whiteysage.github.io/chattice/public-api/), [Google mapping](https://whiteysage.github.io/chattice/reference/google-api-mapping/),
|
|
160
|
+
and [aiogram comparison](https://whiteysage.github.io/chattice/aiogram-comparison/) are linked from the docs site.
|
|
161
|
+
Runnable examples live in [`examples/`](https://github.com/WhiteySage/chattice/tree/main/examples); machine-readable documentation is available in
|
|
162
|
+
[`llms.txt`](https://whiteysage.github.io/chattice/llms.txt).
|
|
163
|
+
|
|
164
|
+
## Status
|
|
165
|
+
|
|
166
|
+
Pre-1.0 **public release** (current version 0.1.0) — see
|
|
167
|
+
[CHANGELOG](CHANGELOG.md). The documented public
|
|
168
|
+
surface is the compatibility baseline: pre-1.0 work may add APIs but does not incompatibly
|
|
169
|
+
rename, remove, or change existing contracts. `chattice.experimental`
|
|
170
|
+
has no compatibility promise. `Bot.raw_client` and raw event payloads
|
|
171
|
+
follow Google's SDK and wire schema rather than the stable facade
|
|
172
|
+
promise. **Not an official Google product** — independent open-source
|
|
173
|
+
software, not endorsed by Google. MIT License, see [LICENSE](https://github.com/WhiteySage/chattice/blob/main/LICENSE).
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Security Policy
|
|
2
|
+
|
|
3
|
+
## Reporting
|
|
4
|
+
|
|
5
|
+
Report suspected security vulnerabilities through **GitHub private
|
|
6
|
+
vulnerability reporting** (Security Advisories) on the public
|
|
7
|
+
repository — enable the feature before the first public release.
|
|
8
|
+
Until the repository is public, contact the project owner directly.
|
|
9
|
+
Do not open a public issue for vulnerabilities.
|
|
10
|
+
|
|
11
|
+
## Supported versions
|
|
12
|
+
|
|
13
|
+
For pre-1.0 releases, only the latest release receives security fixes.
|
|
14
|
+
The policy will be expanded before 1.0.
|
|
15
|
+
|
|
16
|
+
## Security model
|
|
17
|
+
|
|
18
|
+
Chattice ships transport verification and capability guards:
|
|
19
|
+
|
|
20
|
+
- Incoming HTTP interactions: `GoogleTokenVerifier` (Google-issued
|
|
21
|
+
bearer tokens, audience + issuer checks) → 401 on failure.
|
|
22
|
+
- Pub/Sub push: `GooglePubSubVerifier` (signature, audience, REQUIRED
|
|
23
|
+
service-account email, email_verified) — secure by default; an
|
|
24
|
+
explicit `allow_unverified=True` opt-in exists for local use only.
|
|
25
|
+
- Push dedupe is an owner-safe state machine; handlers must stay
|
|
26
|
+
idempotent (push has no exactly-once guarantee).
|
|
27
|
+
- Secrets are never logged: the redaction source-scan test pins this.
|
|
28
|
+
|
|
29
|
+
If you find a bypass, please report it per the section above.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Third-party notices
|
|
2
|
+
|
|
3
|
+
Chattice is licensed under the MIT License. This file lists the direct
|
|
4
|
+
third-party dependencies of the project and their licenses, based on the
|
|
5
|
+
locked dependency inventory. It is an engineering compliance record, not legal
|
|
6
|
+
advice. Versions are the locked versions in `uv.lock`.
|
|
7
|
+
|
|
8
|
+
All declared direct dependencies carry permissive licenses compatible
|
|
9
|
+
with the MIT License (Apache-2.0, MIT, BSD-2/3-Clause, ISC). No
|
|
10
|
+
GPL/AGPL/SSPL dependency is declared.
|
|
11
|
+
|
|
12
|
+
## Runtime dependencies
|
|
13
|
+
|
|
14
|
+
| Package | Version | License |
|
|
15
|
+
| --- | --- | --- |
|
|
16
|
+
| [google-apps-chat](https://github.com/googleapis/google-cloud-python/tree/main/packages/google-apps-chat) | 0.10.4 | Apache-2.0 |
|
|
17
|
+
| [google-auth](https://github.com/googleapis/google-auth-library-python) | 2.56.3 | Apache-2.0 |
|
|
18
|
+
| [pydantic](https://github.com/pydantic/pydantic) | 2.13.4 | MIT |
|
|
19
|
+
|
|
20
|
+
## Optional extras
|
|
21
|
+
|
|
22
|
+
| Package | Version | License | Extra |
|
|
23
|
+
| --- | --- | --- | --- |
|
|
24
|
+
| [fastapi](https://github.com/fastapi/fastapi) | 0.141.1 | MIT | `fastapi` |
|
|
25
|
+
| [redis](https://github.com/redis/redis-py) | 6.4.0 | MIT | `redis` |
|
|
26
|
+
| [google-genai](https://github.com/googleapis/python-genai) | 2.18.1 | Apache-2.0 | `gemini` |
|
|
27
|
+
| [google-cloud-pubsub](https://github.com/googleapis/python-pubsub) | 2.39.1 | Apache-2.0 | `pubsub` |
|
|
28
|
+
|
|
29
|
+
## Development, documentation and build dependencies
|
|
30
|
+
|
|
31
|
+
| Package | Version | License |
|
|
32
|
+
| --- | --- | --- |
|
|
33
|
+
| [cryptography](https://github.com/pyca/cryptography) | 45.0.7 | Apache-2.0 OR BSD-3-Clause |
|
|
34
|
+
| [fakeredis](https://github.com/cunla/fakeredis-py) | 2.37.0 | BSD-3-Clause |
|
|
35
|
+
| [httpx](https://github.com/encode/httpx) | 0.28.1 | BSD-3-Clause |
|
|
36
|
+
| [mkdocs](https://github.com/mkdocs/mkdocs) | 1.6.1 | BSD-2-Clause |
|
|
37
|
+
| [mkdocs-material](https://github.com/squidfunk/mkdocs-material) | 9.7.7 | MIT |
|
|
38
|
+
| [mkdocstrings[python]](https://github.com/mkdocstrings/mkdocstrings) | 1.0.6 | ISC |
|
|
39
|
+
| [mypy](https://github.com/python/mypy) | 1.20.2 | MIT (with identified PSF-licensed portions) |
|
|
40
|
+
| [pyjwt](https://github.com/jpadilla/pyjwt) | 2.13.0 | MIT |
|
|
41
|
+
| [pytest](https://github.com/pytest-dev/pytest) | 8.4.2 | MIT |
|
|
42
|
+
| [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio) | 1.4.0 | Apache-2.0 |
|
|
43
|
+
| [pytest-cov](https://github.com/pytest-dev/pytest-cov) | 7.1.0 | MIT |
|
|
44
|
+
| [ruff](https://github.com/astral-sh/ruff) | 0.16.3 | MIT |
|
|
45
|
+
| [uvicorn](https://github.com/encode/uvicorn) | 0.52.3 | BSD-3-Clause |
|
|
46
|
+
| [hatchling](https://github.com/pypa/hatch) | >=1.27 (build backend) | MIT |
|
|
47
|
+
|
|
48
|
+
## What is and is not distributed
|
|
49
|
+
|
|
50
|
+
The wheel packages `src/chattice` and project licensing/typing
|
|
51
|
+
metadata; it does NOT embed dependency source trees. Declaring
|
|
52
|
+
dependencies in wheel metadata causes installers to fetch their
|
|
53
|
+
independently licensed distributions; it does not relicense or copy
|
|
54
|
+
them into Chattice.
|
|
55
|
+
|
|
56
|
+
An exact-artifact SBOM for the locked dependency set is generated from
|
|
57
|
+
`uv.lock` with `scripts/gen_sbom.py` (SPDX 2.3 JSON, written to
|
|
58
|
+
`docs/release/`). Run it after every lock change and commit the result.
|
|
59
|
+
|
|
60
|
+
## Chattice license
|
|
61
|
+
|
|
62
|
+
MIT License — see [LICENSE](LICENSE). This project is independent
|
|
63
|
+
open-source software: not official Google software and not endorsed by
|
|
64
|
+
Google.
|