Skip to content

Python — core and decorators

import freshgram
from freshgram import aio # async versions

The constant freshgram.API_VERSION is the API level of this SDK (currently 5); freshgram.info() returns the API level of the running host (currently 7).

Function Description
info() API version, plugin id, granted permissions
time() server unix time in seconds
log(text) write to the plugin log (up to 4000 bytes, the tail is kept)
call(request) raw call: {"op": ..., "a": {...}}
spawn(coroutine) run a coroutine on the plugin’s loop; returns a Task (see Async)
unload() unload the plugin after the current event
run(handler=None) the event loop; call it as the last line. It returns quietly when the host closes the channel (EOF) or sends a broken frame (the second case is logged)

With run(handler) the decorators are bypassed and every message of the host goes to handler(kind, value): kind is "init" (value is the init info) or "event" (value is the event map). call.result events are consumed by the SDK for freshgram.aio and never reach it. The return value is the status reported to the host: 0 or None for success; an integer such as -1 for failure (an exception also gives -1 and is logged).

def handler(kind, value):
if kind == "event" and value["type"] == "command" and "chat" in value:
freshgram.messages.send(value["chat"], "hi")
return 0
freshgram.run(handler)

FreshgramError (attributes code, message; str(error) is "code: message", or just the code when the message is empty) → Denied, Invalid, NotFound, QuotaExceeded, LimitExceeded, Unavailable, Failed. The fixed messages are listed in Errors and limits.

Decorator Event Permissions
@on_init plugin start, receives info —
@on(pattern) any events by name; pattern* is a prefix by event
@on_command(name) command ui.command
@on_menu(menu_id, surface=None) menu.click ui.menu
@on_badge_click(badge_id=None) badge.click ui.badges
@on_plugin_message(sender=None) plugin.message, the function gets (sender, data) plugins.message
@on_setting(item_id=None) settings.* (except open and long_click) ui.settings_page
@on_settings_open settings.open ui.settings_page
@on_dialog(item_id=None) dialog.* ui.dialog
@on_window(window_id, item_id=None) window.* ui.dialog
@on_long_click(item_id=None, window=None) *.long_click ui.*
@on_timer(timer_id=None) timer —
@on_chat_opened chat.opened chats.active
@on_translate(markdown=False) translate.request translate.provide
@on_ai(markdown=False) ai.request ai.provide
@on_toast(action_id=None) toast.click ui.toast
@on_toast_close(action_id=None) toast.close ui.toast
@on_typing chat.typing chats.activity
@on_read chat.read chats.activity
@on_member chat.member chats.activity
@on_title_changed chat.title_changed chats.activity
@on_pinned message.pinned messages.read
@on_story story.new stories.read
@on_call call.* calls.activity
@on_user_status user.status users.presence
@on_app_focus / @on_app_blur app.focus / app.blur app.activity

Handlers may be asynchronous (async def).

@freshgram.on_translate
def translate(items, to):
# items is a list of up to 20 texts, to is a language code
return [my_translate(t, to) for t in items]
@freshgram.on_ai
async def rewrite(request):
# request: text and, on demand, translate_to, tone, prompt, proofread, emojify
return request["text"].upper()

markdown of both decorators accepts True or "markdown" (the answer uses **bold** and the like) and "html" (<b>bold</b>); False means plain text. They can also be used without parentheses (@on_translate). An exception in the handler becomes an error reply: str(error) cut to 200 characters (not bytes). The manifest needs contributes.translator / contributes.aiProvider and, if activation triggers are set, the values translate / ai.