28389df805
* Python: Move session persistence into core Move SessionStore and durable msgspec-backed storage into core, restore sessions in Foundry Responses hosting with per-user isolation, and document the serialization design. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Address session persistence review feedback Harden scoped file paths and corruption recovery, preserve session serialization compatibility, clarify dependency placement, and add reproducible benchmark evidence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Preserve session snapshot compatibility Deep-copy in-memory session writes and retain existing Telegram session keys so stored conversations continue resolving. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Simplify Foundry session isolation Add experimental FoundrySessionStore backed by Agent Server request context, remove resolver plumbing, and centralize v2 user isolation for sessions, checkpoints, and approvals. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Reduce Foundry session helper layering Inline the single-use request user accessor while keeping separate context validation, fingerprint, and directory helpers for their distinct callers. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Clarify Foundry request context validation Separate fail-fast request validation from context retrieval so Responses no longer appears to discard a returned context. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Python: Share Foundry request context helpers Move protocol validation and user-scope derivation into a dedicated request-context module, leaving the session-store module focused on storage. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Restore Foundry checkpoint storage paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Simplify Foundry session storage paths Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Persist Foundry sessions under hosted home Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Make hosted path test platform independent Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Address session persistence review feedback Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Isolate Foundry session path handling Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Clarify Foundry session path terminology Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Align Foundry sessions with Responses continuity Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Finalize Foundry Responses session persistence Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Add session store feature usage telemetry Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c * Fix hosted per-call history persistence Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c --------- Copilot-Session: 3e5c81ad-75e8-4e92-a883-8bbd676c6c8c
4.1 KiB
4.1 KiB
agent-framework-hosting-telegram
Telegram Bot API-shaped helpers for app-owned Agent Framework hosting.
This is an alpha, helper-only package: it converts between Telegram's
Update JSON shape and Agent Framework run values in both directions. It
does not provide a bot client, a hosting/channel registry, or a
long-running service. Your app remains fully responsible for:
- Fetching updates -- long polling (
getUpdates) or registering a webhook -- and for verifying webhook authenticity (e.g. Telegram's secret token header, or an IP allowlist). - The Bot API client -- issuing the actual HTTP calls (
sendMessage,sendPhoto,editMessageText,answerCallbackQuery,getFile, ...) with whatever HTTP library you prefer. - Rate limits and retries -- Telegram enforces per-chat and global rate
limits; back off and retry on
429/5xxyourself. - Command dispatch --
telegram_command(...)only parses and normalizes a leading/command; your app decides what each command does. - Sessions/storage -- pair these helpers with
agent-framework-hosting'sAgentStateand core'sSessionStoreorFileSessionStoreto persistAgentSessions across turns.
Helpers
telegram_chat_id(update)-- the chat id an update belongs to.telegram_session_id(update, bot_id=...)-- a bot-scopedAgentStatesession id. Private chats usetelegram:<bot_id>:<user_id>; other chats usetelegram:<bot_id>:<chat_id>.telegram_command(update)-- a leading slash command, with/name@bot argsnormalized to/name args. ReturnsNoneif there is none.telegram_callback_query_id(update)-- a callback query's id, so you can callanswerCallbackQueryyourself.telegram_media_file_id(update_or_message)-- the(file_id, mime_type)of inbound media (largest photo size, document, voice, audio, or video).telegram_to_run(update, *, resolve_file_url=None, stream=False)-- convert amessage,edited_message, orcallback_queryupdate intoAgent.runarguments. Provideresolve_file_url(typically backed bygetFile) to turn inbound media into content; without it (or when it returnsNone), text/caption is preserved and media is otherwise dropped. Media-only input with no resolvable URL raisesValueError.telegram_from_run(result, *, chat_id, parse_mode=None)-- render a finished run as oneTelegramOperation(sendPhotowhen the response has an image, otherwisesendMessage, falling back to"(no response)").telegram_from_streaming_run(stream, *, chat_id, message_id, initial_text=None, parse_mode=None)-- render a streaming run aseditMessageTextoperations with the cumulative text so far, followed by any images in the final response assendPhotooperations. Pass the app-created placeholder text asinitial_textso an identical first edit is omitted. Image-only responses first emitdeleteMessagefor the placeholder.
TelegramOperation is a minimal TypedDict of {"method": str, "payload": dict}
-- your app is responsible for actually calling the Bot API with it.
from agent_framework_hosting import AgentState
from agent_framework_hosting_telegram import (
telegram_chat_id,
telegram_from_run,
telegram_session_id,
telegram_to_run,
)
state = AgentState(agent)
async def handle_update(update: dict) -> None:
chat_id = telegram_chat_id(update)
if chat_id is None:
return # Not a chat update this bot handles.
session_id = telegram_session_id(update, bot_id=bot.id)
session = await state.get_or_create_session(session_id)
run = await telegram_to_run(update, resolve_file_url=resolve_telegram_file_url)
result = await (await state.get_target()).run(run["messages"], session=session, options=run["options"])
await state.set_session(session_id, session) # type: ignore[arg-type]
operation = telegram_from_run(result, chat_id=chat_id)
await call_bot_api(operation["method"], operation["payload"]) # Your HTTP client.
The base execution-state helpers live in
agent-framework-hosting.