WreathBrowse
Reference

ChatOps#

ChatOps mounts verified provider ingress on a Wreath application. Commands share one declaration, identity, authorization, durable-work and audit model while each provider keeps its native protocol and outbound escape hatches.

The core has no provider SDK dependency. Slack signatures, Teams connector tokens, Discord signatures, manifests, acknowledgements and outbound wire shapes are owned by Wreath. A configured installation store supplies tenant credentials; a configured ExternalIdentityResolver turns only a verified provider identity into an existing Wreath principal. Profile names and email addresses never create an account link.

Commands that declare an authorization action refuse startup without an authorizer. Durable commands require the existing job owner and a transactional inbox. The default inline replay window is bounded and process-local; deployments with several workers must supply a shared inbox for cross-worker deduplication.

Configure PostgresWebhookInbox with the same transaction factory used by the job owner. Wreath then claims the provider delivery, inserts the job and records fenced completion in one commit. A crash cannot leave a remembered delivery with no job.

inbox = PostgresWebhookInbox(
    session_factory=inbox_transaction,
    lease_owner=replica_id,
    lease_seconds=30,
)

chat = ChatOps(
    app,
    name="operations",
    providers=(slack, teams, discord),
    jobs=jobs,
    inbox=inbox,
)

One command, three providers#

Add the provider objects to one ChatOps runtime, then declare the business action once. Provider adapters verify and normalize ingress before the runtime binds typed arguments, resolves an existing Wreath identity, applies second-factor and Cedar requirements, and invokes the handler.

chat = ChatOps(
    app,
    name="operations",
    providers=(slack, teams, discord),
    installations=installations,
    identity=identity_resolver,
    authorizer=authorizer,
    audit=audit,
)


@chat.command(
    "deploy",
    action="Release::deploy",
    resource="Release::environment",
    second_factor=300,
)
async def deploy(environment: Literal["staging", "production"]) -> ChatReply:
    return ChatReply.in_channel(f"Deploying {environment}")

Federation is deliberately lookup-only. Slack and Discord installation identities, and Teams Entra identities, may resolve to a principal already owned by Wreath's identity store. Provider profile fields do not provision or merge users. A missing, ambiguous or mismatched link refuses the identity-dependent command.

OrganizationFederation can then bind an installation to the same organization store SCIM provisions. It checks the linked Wreath identity's current membership on every resolution, so removing a member through SCIM also removes ChatOps access; it does not copy memberships into a chat-specific table.

identity_resolver = ExternalIdentityResolver(
    store=external_identities,
    federation=OrganizationFederation(organizations, installation_organizations),
)

The ordinary ConcurrencyPolicy and RateLimitPolicy can protect ChatOps after that identity and tenant have been resolved. The rate-limit key includes the tenant, Wreath identity (or provider actor when unlinked), and command name. Both policies keep their existing counters and stores.

chat = ChatOps(
    app,
    name="operations",
    admission=ConcurrencyPolicy(32),
    rate_limit=RateLimitPolicy(limit=20, window=60),
)

Durable agents#

A durable handler receives the original ChatContext, including an AgentRequest, the real job context and a provider emitter. context.job_context.fence is the owner for application effects that must occur once across retries. Provider emitters only perform their validated, idempotent replacement operation; arbitrary application effects remain the handler's responsibility.

@chat.command("investigate", execution="durable")
async def investigate(context: ChatContext) -> None:
    request = context.agent_request
    if request is None:
        raise RuntimeError("durable agent request is unavailable")
    async for event in agent.run(request):
        await context.emit(event)

Pass an existing Streams owner as streams= to retain the same fenced event sequence for reconnecting web clients. ChatOps keeps the provider delivery as the only producer: it joins that job's fence to the stream log instead of launching a second job. context.stream_key identifies the resulting resumable stream.

Every completed or failed dispatch also emits a structured ChatOps outcome through Wreath logging, which places it on the active Flight Recorder and OTLP pipeline without a separate audit transport. An optional application audit store is still appended for durable compliance records. wreath doctor preflight reports missing providers, jobs, transactional inboxes, authorizers, and stream owners before deployment.

Notification kinds can deliver through ChatOps with wreath.notifications.Chat. The channel resolves a tenant-bound destination and derives a deterministic idempotency key from the notification kind, recipient, tenant, and rendered content.

Provider-neutral tests#

TestClient.chat() drives the same compiled declarations without constructing a Slack, Teams, or Discord payload. Each ChatTurn retains the reply, emitted agent events, normalized context, and supplied arguments.

transcript = TestClient(app).chat(
    "operations",
    provider="slack",
    installation="T1",
    tenant="slack:T1",
    actor="U1",
    conversation="C1",
)
turn = await transcript.command("deploy", environment="staging")
assert turn.reply.content == "Deploying staging"

ChatOps.problem(error) uses Wreath's RFC 9457 ProblemDetail vocabulary for provider errors. Expected authorization and input failures retain their useful detail; unexpected failures become a generic 500 detail rather than leaking an exception message into chat.

Retained agent text is bounded before append: 40,000 characters for Slack, 28,000 for Teams and 2,000 for Discord. Slack delivery requires a validated response_url; Teams limits connector destinations to its supported service origin; Discord binds proactive destinations to the declared tenant. App-secret rotation invalidates already queued Teams envelopes, so drain or replace those jobs during rotation.

wreath.chat#

AgentBackend#

AgentBackend(*args, **kwargs)

run#

run(request: AgentRequest) -> AsyncIterator[AgentEvent]

AgentEvent#

AgentEvent(kind: "Literal['progress', 'text', 'completed']", content: 'str | None' = None, percent: 'int | None' = None, id: 'str | None' = None)

AgentEvent(kind: "Literal['progress', 'text', 'completed']", content: str | None = None, percent: int | None = None, id: str | None = None) -> None

completed (classmethod)#

completed() -> AgentEvent

progress (classmethod)#

progress(content: str, *, percent: int | None = None) -> AgentEvent

text (classmethod)#

text(content: str, *, id: str | None = None) -> AgentEvent

AgentRequest#

AgentRequest(tenant: 'str', actor: 'str', conversation: 'str', prompt: 'str', correlation: 'ChatCorrelation', native: 'Any' = None, principal: 'Any' = None)

AgentRequest(tenant: str, actor: str, conversation: str, prompt: str, correlation: ChatCorrelation, native: Any = None, principal: Any = None) -> None

ChatAuditEvent#

ChatAuditEvent(tenant: 'str', actor: 'str', action: 'str', correlation: 'ChatCorrelation')

ChatAuditEvent(tenant: str, actor: str, action: str, correlation: ChatCorrelation) -> None

ChatAdmissionError#

ChatAdmissionError(problem: ProblemDetail) -> None

ChatConfigurationError#

ChatContext#

ChatContext(provider: 'str', installation: 'str', tenant: 'str', actor: 'str', conversation: 'str', delivery_id: 'str', native: 'Any', raw: 'Any' = None, command: 'str | None' = None, action: 'str | None' = None, inputs: 'Mapping[str, Any]' = <factory>, response_url: 'str | None' = None, identity: 'Identity | None' = None, principal: 'Any' = None, external_identity: 'ExternalIdentityKey | None' = None, agent_request: 'AgentRequest | None' = None, emit: 'Callable[[AgentEvent], Awaitable[None]] | None' = None, job_context: 'Any' = None, stream_key: 'str | None' = None)

ChatContext(provider: str, installation: str, tenant: str, actor: str, conversation: str, delivery_id: str, native: Any, raw: Any = None, command: str | None = None, action: str | None = None, inputs: Mapping[str, Any] = <factory>, response_url: str | None = None, identity: Identity | None = None, principal: Any = None, external_identity: ExternalIdentityKey | None = None, agent_request: AgentRequest | None = None, emit: Callable[[AgentEvent], Awaitable[None]] | None = None, job_context: Any = None, stream_key: str | None = None) -> None

ChatCorrelation#

ChatCorrelation(interaction_id: 'str | None' = None, job_id: 'str | None' = None, trace_id: 'str | None' = None, provider_message_id: 'str | None' = None)

ChatCorrelation(interaction_id: str | None = None, job_id: str | None = None, trace_id: str | None = None, provider_message_id: str | None = None) -> None

ChatOps#

ChatOps(app: Any = None, *, name: str, providers: tuple[Any, ...] = (), path: str = '/_wreath/chat', installations: Any = None, identity: Any = None, jobs: Any = None, inbox: Any = None, outbox: Any = None, authorizer: Any = None, audit: Any = None, admission: Any = None, rate_limit: Any = None, progress: Any = None, conversation_store: Any = None, clock: Callable[[], float] = <built-in function time>) -> None

accept#

async accept(interaction: Any) -> Any

action#

action(name: str, *, description: str | None = None, prefix: bool = False) -> Callable[[Callable[..., Any]], Callable[..., Any]]

add#

add(provider: Any) -> Any

agent#

agent(name: str, backend: AgentBackend, *, action: str, description: str | None = None, resource: Any = 'conversation', second_factor: float | None = None, streams: Any = None) -> Callable[..., Any]

cancel#

async cancel(job_id: str, *, reason: str) -> bool

claim_action#

async claim_action(interaction: Any, *, store: Any) -> Any

command#

command(name: str, *, description: str | None = None, action: str | None = None, resource: Any = None, second_factor: float | None = None, execution: "Literal['inline', 'durable']" = 'inline', streams: Any = None, retries: int | None = None) -> Callable[[Callable[..., Any]], Callable[..., Any]]

event#

event(name: str, *, description: str | None = None) -> Callable[[Callable[..., Any]], Callable[..., Any]]

manifest#

manifest(provider: str, *, base_url: str) -> Any

problem#

problem(error: BaseException) -> ProblemDetail

replay_size (property)#

replay_size: int

require_tenant#

require_tenant(tenant: str, reference: ChatReference) -> ChatReference

send#

async send(*, tenant: str, destination: Any, content: str, idempotency_key: str) -> Any

ChatProgressCoalescer#

ChatProgressCoalescer(*, interval: float) -> None

flush#

flush(*, now: float) -> _ProgressDelivery

offer#

offer(event: AgentEvent, *, now: float) -> _ProgressDelivery | None

ChatReference#

ChatReference(tenant: 'str', id: 'str')

ChatReference(tenant: str, id: str) -> None

ChatReply#

ChatReply(content: 'str | None' = None, visibility: "Literal['default', 'ephemeral', 'in_channel']" = 'default', blocks: 'tuple[Mapping[str, Any], ...]' = (), native: 'Mapping[str, Any]' = <factory>, adaptive_card: 'Mapping[str, Any] | None' = None)

ChatReply(content: str | None = None, visibility: "Literal['default', 'ephemeral', 'in_channel']" = 'default', blocks: tuple[Mapping[str, Any], ...] = (), native: Mapping[str, Any] = <factory>, adaptive_card: Mapping[str, Any] | None = None) -> None

card (classmethod)#

card(value: Mapping[str, Any]) -> ChatReply

ephemeral (classmethod)#

ephemeral(content: str, *, blocks: list[Mapping[str, Any]] | tuple[Mapping[str, Any], ...] = (), native: Mapping[str, Any] | None = None) -> ChatReply

for_provider#

for_provider(provider: str) -> dict[str, Any]

in_channel (classmethod)#

in_channel(content: str, *, blocks: list[Mapping[str, Any]] | tuple[Mapping[str, Any], ...] = (), native: Mapping[str, Any] | None = None) -> ChatReply

text (classmethod)#

text(content: str) -> ChatReply

ChatTenantMismatch#

ExternalIdentityKey#

ExternalIdentityKey(*, subject: 'str', provider: 'str | None' = None, installation: 'str | None' = None, issuer: 'str | None' = None, tenant: 'str | None' = None) -> 'None'

ExternalIdentityKey(*, subject: str, provider: str | None = None, installation: str | None = None, issuer: str | None = None, tenant: str | None = None) -> None

ExternalIdentityResolver#

ExternalIdentityResolver(*, store: Any, federation: Any = None) -> None

resolve#

async resolve(key: ExternalIdentityKey) -> PrincipalBinding

IdentityLinkChallenge#

IdentityLinkChallenge(url: 'str', state: 'str')

IdentityLinkChallenge(url: str, state: str) -> None

IdentityResolutionError#

IdentityResolutionError(reason: str) -> None

InMemoryChatActionStore#

InMemoryChatActionStore(*, max_entries: int = 4096, ttl: float = 900.0, clock: Callable[[], float] = <built-in function monotonic>) -> None

claim#

async claim(custom_id: str, *, tenant: str, actor: str) -> _IssuedAction | None

issue#

async issue(*, workflow: str, decision: str, tenant: str, actor: str) -> _IssuedAction

size (property)#

size: int

PrincipalBinding#

PrincipalBinding(*, identity: 'Identity', external: 'ExternalIdentityKey | None' = None, key: 'ExternalIdentityKey | None' = None, principal: 'Any' = None, tenant: 'str | None' = None) -> 'None'

PrincipalBinding(*, identity: Identity, external: ExternalIdentityKey | None = None, key: ExternalIdentityKey | None = None, principal: Any = None, tenant: str | None = None) -> None

key (property)#

key: ExternalIdentityKey

StaleChatJobFence#

wreath.chat.slack#

Slack#

Slack(*, signing_secret: str, app_id: str | None = None, installations: SlackInstallationStore | None = None, http_client: Any = None, api_client: Any = None, response_client: Any = None, clock: Callable[[], float] = <built-in function time>, sleep: Callable[[float], Awaitable[None]] = <function sleep>, max_age: int = 300, max_retries: int = 3, replay_entries: int = 4096, event_scopes: Mapping[str, tuple[str, ...]] | None = None) -> None

call#

async call(installation: SlackInstallation, method: str, payload: Mapping[str, Any], *, idempotent: bool = False, idempotency_key: str | None = None) -> Mapping[str, Any]

manifest#

manifest(chat: Any, *, base_url: str) -> Mapping[str, Any]

respond#

async respond(target: SlackResponseURL, reply: Any) -> Any

response_url#

response_url(url: str, *, installation: str) -> SlackResponseURL

send#

async send(*, tenant: str, destination: SlackDestination, content: str, idempotency_key: str) -> Mapping[str, Any]

SlackDestination#

SlackDestination(channel_id: 'str', tenant: 'str', installation: 'SlackInstallation')

SlackDestination(channel_id: str, tenant: str, installation: SlackInstallation) -> None

SlackInstallation#

SlackInstallation(app_id: 'str', team_id: 'str | None', bot_token: 'str', bot_user_id: 'str', scopes: 'frozenset[str]', enterprise_id: 'str | None' = None, is_enterprise_install: 'bool' = False)

SlackInstallation(app_id: str, team_id: str | None, bot_token: str, bot_user_id: str, scopes: frozenset[str], enterprise_id: str | None = None, is_enterprise_install: bool = False) -> None

key (property)#

key: str

SlackInstallationStore#

SlackInstallationStore(*args, **kwargs)

fetch#

async fetch(*, enterprise_id: str | None, team_id: str | None, is_enterprise_install: bool) -> SlackInstallation | None

SlackRateLimited#

SlackRateLimited(retry_after: float) -> None

SlackResponseURL#

SlackResponseURL(url: 'str', installation: 'str')

SlackResponseURL(url: str, installation: str) -> None

wreath.chat.teams#

ConnectorRequest#

ConnectorRequest(method: 'str', url: 'str', headers: 'Mapping[str, str]', json: 'Mapping[str, Any]')

ConnectorRequest(method: str, url: str, headers: Mapping[str, str], json: Mapping[str, Any]) -> None

Teams#

Teams(*, config: TeamsBotConfig, verifier: Any = None, connector: Any = None, installations: Any = None, token_provider: Callable[[], str | Awaitable[str]] | None = None, clock: Callable[[], float] = <built-in function time>) -> None

external_identity#

external_identity(activity: TeamsActivity) -> Any

manifest#

manifest(chat: Any, *, base_url: str) -> Mapping[str, Any]

proactive#

async proactive(installation: TeamsInstallation, reply: Any, *, idempotency_key: str | None = None) -> Any

reply#

async reply(incoming: TeamsActivity, reply: Any, *, idempotency_key: str | None = None) -> Any

send#

async send(*, tenant: str, destination: Any, content: str, idempotency_key: str) -> Any

TeamsActivity#

TeamsActivity(id: 'str', kind: 'str', channel: 'str', service_url: 'str', tenant_id: 'str', aad_object_id: 'str | None', installation_key: 'tuple[str, str]', conversation_id: 'str', conversation_type: 'str', reply_to_id: 'str', sender_id: 'str', sender_name: 'str | None', recipient_id: 'str', recipient_name: 'str | None', text: 'str | None', name: 'str | None', action: 'str | None', value: 'Mapping[str, Any]', members_added: 'tuple[str, ...]', raw: 'Mapping[str, Any]', connector_verified: 'bool' = False)

TeamsActivity(id: str, kind: str, channel: str, service_url: str, tenant_id: str, aad_object_id: str | None, installation_key: tuple[str, str], conversation_id: str, conversation_type: str, reply_to_id: str, sender_id: str, sender_name: str | None, recipient_id: str, recipient_name: str | None, text: str | None, name: str | None, action: str | None, value: Mapping[str, Any], members_added: tuple[str, ...], raw: Mapping[str, Any], connector_verified: bool = False) -> None

parse (classmethod)#

parse(payload: Mapping[str, Any]) -> TeamsActivity

verified#

verified() -> TeamsActivity

TeamsBotConfig#

TeamsBotConfig(app_id: 'str', app_secret: 'str', messaging_endpoint: 'str', allowed_tenants: 'frozenset[str]', login_issuers: 'Mapping[str, str]' = <factory>, max_token_lifetime: 'int' = 3600)

TeamsBotConfig(app_id: str, app_secret: str, messaging_endpoint: str, allowed_tenants: frozenset[str], login_issuers: Mapping[str, str] = <factory>, max_token_lifetime: int = 3600) -> None

TeamsConnectorError#

TeamsConnectorError(*, status: int, retry_after: float | None = None) -> None

TeamsConnectorVerifier#

TeamsConnectorVerifier(config: TeamsBotConfig, *, fetch: Callable[[str], Awaitable[Mapping[str, Any]]] | None = None, clock: Callable[[], float] = <built-in function time>) -> None

startup#

async startup() -> int

verify#

async verify(authorization: str | None, activity: Mapping[str, Any]) -> None

TeamsContext#

TeamsContext(activity: 'TeamsActivity', external_identity: 'Any', tenant: 'str | None' = None, identity: 'Any' = None, principal: 'Any' = None, action: 'str | None' = None, inputs: 'dict[str, Any]' = <factory>, method: 'str' = 'POST', path: 'str' = '/_wreath/chat/teams', state: 'State' = <factory>, agent_request: 'Any' = None, emit: 'Any' = None, job_context: 'Any' = None)

TeamsContext(activity: TeamsActivity, external_identity: Any, tenant: str | None = None, identity: Any = None, principal: Any = None, action: str | None = None, inputs: dict[str, Any] = <factory>, method: str = 'POST', path: str = '/_wreath/chat/teams', state: State = <factory>, agent_request: Any = None, emit: Any = None, job_context: Any = None) -> None

actor (property)#

actor: str

channel_actor_id (property)#

channel_actor_id: str

command (property)#

command: str | None

conversation (property)#

conversation: str

delivery_id (property)#

delivery_id: str

installation (property)#

installation: str

native (property)#

native: Mapping[str, Any]

raw (property)#

raw: Mapping[str, Any]

TeamsInstallation#

TeamsInstallation(tenant_id: 'str', installation_id: 'str', service_url: 'str', conversation_id: 'str', bot_id: 'str')

TeamsInstallation(tenant_id: str, installation_id: str, service_url: str, conversation_id: str, bot_id: str) -> None

refreshed_from#

refreshed_from(activity: TeamsActivity, *, connector_verified: bool) -> TeamsInstallation

TeamsManifest#

TeamsManifest(package_id: 'str', app_id: 'str', version: 'str', name: 'str', short_description: 'str', long_description: 'str', developer_name: 'str', website_url: 'str', privacy_url: 'str', terms_url: 'str', scopes: 'tuple[str, ...]', commands: 'tuple[Mapping[str, str], ...]' = (), entra_resource: 'str | None' = None)

TeamsManifest(package_id: str, app_id: str, version: str, name: str, short_description: str, long_description: str, developer_name: str, website_url: str, privacy_url: str, terms_url: str, scopes: tuple[str, ...], commands: tuple[Mapping[str, str], ...] = (), entra_resource: str | None = None) -> None

package#

package(*, color_icon: bytes, outline_icon: bytes) -> bytes

render#

render() -> dict[str, Any]

TeamsRefusal#

TeamsRefusal(reason: str, message: str, *, status: int = 401) -> None

wreath.chat.discord#

Discord#

Discord(*, application_id: str, public_key: bytes | str | None, bot_token: str | None, client: Any = None, deliver: Callable[[Any], Any] | None = None, verify: Callable[[bytes, bytes, bytes], bool] = <function verify_ed25519>, clock: Callable[[], float] = <built-in function time>, signature_max_age: float = 300.0, rate_limiter: DiscordRateLimiter | None = None) -> None

accept#

async accept(chat: Any, interaction: DiscordInteraction, *, body: bytes | None = None, sent_at: float | None = None) -> _AcceptedInteraction

manifest#

manifest(chat: Any, *, base_url: str) -> DiscordManifest

send#

async send(*, tenant: str, destination: DiscordDestination, content: str, idempotency_key: str) -> Any

validate#

validate() -> None

DiscordCommand#

DiscordCommand(name: 'str', type: 'int' = 1, description: 'str' = '', options: 'tuple[DiscordOption, ...]' = (), integration_types: 'tuple[int, ...]' = (0,), contexts: 'tuple[int, ...]' = (0,), default_member_permissions: 'str | None' = None)

DiscordCommand(name: str, type: int = 1, description: str = '', options: tuple[DiscordOption, ...] = (), integration_types: tuple[int, ...] = (0,), contexts: tuple[int, ...] = (0,), default_member_permissions: str | None = None) -> None

as_discord#

as_discord() -> dict[str, Any]

DiscordComponent#

DiscordComponent(custom_id: 'str', component_type: 'int', message_id: 'str | None', values: 'tuple[Any, ...]' = ())

DiscordComponent(custom_id: str, component_type: int, message_id: str | None, values: tuple[Any, ...] = ()) -> None

DiscordConfigurationError#

DiscordDestination#

DiscordDestination(channel_id: 'str', tenant: 'str')

DiscordDestination(channel_id: str, tenant: str) -> None

DiscordInstallation#

DiscordInstallation(kind: "Literal['guild', 'user']", owner_id: 'str')

DiscordInstallation(kind: "Literal['guild', 'user']", owner_id: str) -> None

DiscordInteraction#

DiscordInteraction(id: 'str', application_id: 'str', token: 'str', kind: 'str', actor: 'DiscordActor', installation: 'DiscordInstallation', native: 'Mapping[str, Any]', command: 'DiscordInvokedCommand | None' = None, component: 'DiscordComponent | None' = None, modal: 'DiscordModal | None' = None)

DiscordInteraction(id: str, application_id: str, token: str, kind: str, actor: DiscordActor, installation: DiscordInstallation, native: Mapping[str, Any], command: DiscordInvokedCommand | None = None, component: DiscordComponent | None = None, modal: DiscordModal | None = None) -> None

custom_id (property)#

custom_id: str

parse (classmethod)#

parse(payload: Mapping[str, Any], *, allow_unknown: bool = False) -> DiscordInteraction

tenant (property)#

tenant: str

DiscordInteractionVerifier#

DiscordInteractionVerifier(public_key: bytes | str, *, verify: Callable[[bytes, bytes, bytes], bool] = <function verify_ed25519>, clock: Callable[[], float] = <built-in function time>, max_age: float | None = None) -> None

verify#

verify(*, signature: str, timestamp: str, body: bytes) -> None

DiscordManifest#

DiscordManifest(application_id: 'str', commands: 'tuple[DiscordCommand, ...]' = (), bot_token: 'str | None' = None, rate_limiter: 'DiscordRateLimiter | None' = None)

DiscordManifest(application_id: str, commands: tuple[DiscordCommand, ...] = (), bot_token: str | None = None, rate_limiter: DiscordRateLimiter | None = None) -> None

sync#

async sync(client: Any, *, scope: "Literal['global', 'guild']", guild_id: str | None = None) -> DiscordSyncResult

DiscordMessage#

DiscordMessage(content: 'str' = '', poll: 'Any' = None)

DiscordMessage(content: str = '', poll: Any = None) -> None

DiscordModal#

DiscordModal(custom_id: 'str', values: 'dict[str, Any]')

DiscordModal(custom_id: str, values: dict[str, Any]) -> None

DiscordNativeDelivery#

DiscordNativeDelivery(raw: 'Mapping[str, Any]')

DiscordNativeDelivery(raw: Mapping[str, Any]) -> None

DiscordOption#

DiscordOption(name: 'str', description: 'str', type: 'int', required: 'bool' = False, choices: 'tuple[Any, ...]' = (), options: 'tuple[DiscordOption, ...]' = (), min_value: 'int | float | None' = None, max_value: 'int | float | None' = None, min_length: 'int | None' = None, max_length: 'int | None' = None, autocomplete: 'bool' = False)

DiscordOption(name: str, description: str, type: int, required: bool = False, choices: tuple[Any, ...] = (), options: tuple[DiscordOption, ...] = (), min_value: int | float | None = None, max_value: int | float | None = None, min_length: int | None = None, max_length: int | None = None, autocomplete: bool = False) -> None

as_discord#

as_discord() -> dict[str, Any]

DiscordRateLimiter#

DiscordRateLimiter(*, clock: Callable[[], float] = <built-in function monotonic>, sleep: Callable[[float], Awaitable[None]] = <function sleep>, capacity: int = 4096) -> None

acquire#

async acquire(route: str, major: str | None) -> None

observe#

async observe(route: str, major: str | None, response: Any) -> None

DiscordResponder#

DiscordResponder(*, application_id: str, interaction_id: str, token: str, received_at: float, client: Any, clock: Callable[[], float] = <built-in function monotonic>, acknowledged: bool = False, component: bool = False, rate_limiter: DiscordRateLimiter | None = None) -> None

defer#

async defer(*, ephemeral: bool = False) -> dict[str, Any]

defer_update#

async defer_update() -> dict[str, Any]

edit_followup#

async edit_followup(message_id: str, **message: Any) -> Any

edit_original#

async edit_original(**message: Any) -> Any

followup#

async followup(*, ephemeral: bool = False, **message: Any) -> Any

for_component (classmethod)#

for_component(**options: Any) -> DiscordResponder

DiscordSyncError#

DiscordTenantKey#

from_installation (staticmethod)#

from_installation(installation: DiscordInstallation) -> str

from_interaction (classmethod)#

from_interaction(interaction: DiscordInteraction) -> str

InteractionAcknowledgementExpired#

InteractionAlreadyAcknowledged#

InteractionTokenExpired#

InvalidDiscordSignature#

UnsupportedDiscordField#

UnsupportedDiscordInteraction#

esc
↑↓ navigate↵ openesc close