You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
PraisonAI PR #1504 (link) merged 2026-04-22 adds three user-facing features that have no current documentation. This issue tracks the docs work needed.
Tool availability gating via @tool(availability=...) — hide tools from the LLM when they can't physically run (missing API key / dep / service).
Unknown-user pairing flow — bot unknown_user_policy + praisonai pairing CLI to securely onboard new bot users.
clarify tool — first-class tool agents call to ask a single clarifying question mid-task.
Each is opt-in and backward compatible.
Required Documentation Work
Two NEW pages + ONE UPDATE to an existing page.
Important
Per repo AGENTS.md: All new pages go under docs/features/. Do NOT add anything under docs/concepts/. Add entries to docs.json under the Features group, not Concepts.
✅ Task 1 — NEW page: docs/features/clarify-tool.mdx
Status in docs today: Does not exist (search confirms no matches in docs/ for clarify as a tool).
If choices present and reply is a valid digit, returns that choice
Returns "no answer provided" on empty reply
Bot auto-approve list now includes "clarify" (so the bot won't block the call on an approval prompt by default).
Required structure (per AGENTS.md template): frontmatter → one-sentence intro → hero Mermaid diagram → Quick Start <Steps> → How It Works (sequence diagram) → Configuration / Handler options → Common Patterns (CLI, bot, custom context handler) → Best Practices <AccordionGroup> → Related <CardGroup>.
Agent-centric Quick Start (the top example, per §1.1 rule 9):
frompraisonaiagentsimportAgentfrompraisonaiagents.tools.clarifyimportclarifyagent=Agent(
name="Writer",
instructions="Write code. If the requirement is genuinely ambiguous, call clarify once.",
tools=[clarify],
)
agent.start("Build me a web scraper")
# Agent may emit: clarify(question="Which language?", choices=["python", "rust"])
User-interaction flow to show (per §1.1 rule 10):
CLI: prompt appears in terminal, user types answer/number, agent resumes
Bot (Telegram/Discord/Slack): bot DMs the question with numbered choices, user replies, agent resumes
UI: interactive component (describe conceptually — SDK does not ship a UI component yet)
Mermaid hero diagram — use the standard color palette from AGENTS.md (§3.1). Show: Agent → clarify() → Channel (CLI/Bot/UI) → User → back to Agent.
Icon suggestion:messages-question or circle-question (Mintlify icon; verify availability).
docs.json: Add under Features group, after the existing tools entries.
✅ Task 2 — NEW page: docs/features/tool-availability.mdx
Status in docs today: Not documented. The @tool decorator itself has no dedicated page and no mention of availability. Search for check_availability / availability in docs/ returns zero hits related to this feature.
SDK source of truth (read these before writing):
src/praisonai-agents/praisonaiagents/tools/decorator.py (adds availability kwarg + check_availability() method on FunctionTool)
src/praisonai-agents/praisonaiagents/tools/protocols/tool_protocol.py (new ToolAvailabilityProtocol)
src/praisonai-agents/praisonaiagents/tools/registry.py (new list_available_tools() method + module-level function)
src/praisonai-agents/praisonaiagents/tools/__init__.py (exports the new registry function)
What it does: A tool author can provide a availability callable returning (is_available: bool, reason: str). At schema-build time, unavailable tools are filtered from the list sent to the LLM, so the model can't hallucinate a call to a tool whose env/API key/service isn't ready. Zero runtime cost for available tools — check only at schema build.
Signature: check_availability(self) -> tuple[bool, str]. Runtime-checkable. Called at schema-build time — must be fast, no I/O.
Registry / filtering (new):
frompraisonaiagents.toolsimportlist_available_tools, get_registry# Only tools that pass their checkavailable=list_available_tools()
# All registered tools, regardless of availabilityall_tools=get_registry().list_tools()
Behavior rules to document (from registry.py and decorator.py):
Tools withoutcheck_availability are treated as always-available.
If check_availability() raises, the tool is treated as unavailable and the exception message becomes the reason: f"Availability check failed: {e}" — a warning is logged.
Plain functions registered via register_function are always considered available (no protocol for them yet).
Agent-centric Quick Start (top of page):
importosfrompraisonaiagentsimportAgentfrompraisonaiagents.toolsimporttool@tool(availability=lambda: (bool(os.getenv("SERP_API_KEY")), "SERP_API_KEY not set"))defsearch_web(query: str) ->str:
"""Search the web."""
...
agent=Agent(
name="Researcher",
instructions="Research the topic the user asks about.",
tools=[search_web],
)
# If SERP_API_KEY is missing, the LLM will never see search_web.agent.start("Research quantum computing")
User-interaction flow to include:
Dev defines availability on a tool that needs an API key / Docker / DB.
Env var missing → tool hidden from LLM → agent doesn't hallucinate calls.
Env var set → tool appears → agent uses it normally.
Hero Mermaid diagram: Show Tool Registry → check_availability → [pass|fail] → LLM sees / doesn't see.
Icon suggestion:toggle-on or shield-check.
docs.json: Add under Features group. If a "Tools" sub-group exists, nest it there.
Current state of docs/best-practices/bot-security.mdx:
The page already describes pairing but is littered with <Warning> blocks saying the feature is conceptual / planned / may not exist. As of PR #1504, it is real and shipping. These disclaimers must be removed and APIs aligned to the new SDK.
Remove / replace the following three warning blocks (they are now factually wrong):
Around the "Gateway Pairing" section:
"The pairing system described below represents planned functionality. Current SDK implementation may differ. Verify against actual SDK documentation."
→ Delete. Replace with a pointer/link to the new dedicated docs/features/bot-pairing.mdx page.
Around "Doctor Security Check":
"The doctor command shown may not be available in current SDK version. Verify implementation status."
→ Verify against current SDK (praisonai/cli/features/doctor/checks/bot_checks.py exists in the synced tree). If available, drop the warning; if still gated, keep a scoped, accurate note.
In "Quick Start" — remove the comment lines:
# Note: Security features shown are conceptual # Actual implementation may vary # Security configuration would go here # when implemented in the SDK
→ Replace the Quick Start with a real, runnable example using the new unknown_user_policy field on BotConfig:
Also update the "Gateway Pairing" section to reflect the real flow:
PRAISONAI_GATEWAY_SECRET env var is no longer required — if unset, a per-install secret is auto-generated at <store_dir>/.gateway_secret with 0600 perms and reused across restarts. Env var still takes precedence when set. (gateway/pairing.py::_load_or_create_secret)
generate_code now accepts a channel_id — binding a code to a channel at generation time.
verify_and_pair accepts channel_id=None when the code was generated with a bound channel.
Task 3b — NEW page docs/features/bot-pairing.mdx:
Dedicated agent-centric page covering the end-to-end pairing flow. Bot-security page should link here.
Key content:
One-liner: "Let unknown users self-request access to your bot with a secure 8-char code that you approve from the CLI."
Hero Mermaid diagram:Unknown User → Bot DM → UnknownUserHandler → PairingStore.generate_code → Bot replies with code → Owner runs "praisonai pairing approve ..." → User now allowed.
Agent-centric Quick Start:
frompraisonaiagentsimportAgentfrompraisonaiagents.botsimportBotConfig# ... bot adapter wiring (Telegram in this PR)config=BotConfig(
allowed_users=["@owner"],
unknown_user_policy="pair", # new
)
CHANNEL_ID is optional when the code was generated with a bound channel_id (the bot does this).
Platforms shipped with handler wiring: telegram (only). Document discord/slack/whatsapp as valid platform strings for PairingStore but note adapter wiring is pending.
Codes are 8-char (from generate_code), HMAC-signed with per-install secret.
Codes have TTL (code_ttl, check PairingStore.__init__ default) — consumed on approve.
Per-install secret auto-persisted to <store_dir>/.gateway_secret mode 0600 when PRAISONAI_GATEWAY_SECRET is unset. A warning is logged if file perms drift from 0600.
Rate limiting on code generation: 600 s (10 min) window per channel_id (see UnknownUserHandler._rate_limit_window).
Codes and pairings both persist through restarts (atomic tempfile+rename write).
User-interaction flow (step-by-step, per §1.1 rule 10):
Hero Mermaid diagram with the standard palette (#8B0000, #189AB4, #10B981, #F59E0B, #6366F1, white text, #7C90A0 strokes)
Quick Start uses <Steps>; Best Practices uses <AccordionGroup>; Related uses <CardGroup>
Top example is agent-centric (starts from Agent(...), not from the low-level class)
Shortest-possible imports: from praisonaiagents.tools import tool, from praisonaiagents.tools.clarify import clarify, from praisonaiagents.bots import BotConfig
No forbidden phrases ("In this section...", "As you can see...", "It's important to note...", etc.)
Active voice, one-sentence section intros
Configuration options documented against SDK ground truth (no guessing, no invented params)
Include a user-interaction flow section for each feature (§1.1 rule 10)
Update docs.json under the Features group (not Concepts). Validate JSON after edit.
Context
PraisonAI PR #1504 (link) merged 2026-04-22 adds three user-facing features that have no current documentation. This issue tracks the docs work needed.
1810a26d3c0424fd1779d9dcfbef83ac540433b0Features shipped in PR #1504
@tool(availability=...)— hide tools from the LLM when they can't physically run (missing API key / dep / service).unknown_user_policy+praisonai pairingCLI to securely onboard new bot users.clarifytool — first-class tool agents call to ask a single clarifying question mid-task.Each is opt-in and backward compatible.
Required Documentation Work
Two NEW pages + ONE UPDATE to an existing page.
Important
Per repo
AGENTS.md: All new pages go underdocs/features/. Do NOT add anything underdocs/concepts/. Add entries todocs.jsonunder the Features group, not Concepts.✅ Task 1 — NEW page:
docs/features/clarify-tool.mdxStatus in docs today: Does not exist (search confirms no matches in
docs/forclarifyas a tool).SDK source of truth (read these before writing):
src/praisonai-agents/praisonaiagents/tools/clarify.py(198 lines, new)src/praisonai-agents/praisonaiagents/bots/config.py(adds"clarify"to bot default auto-approve list)src/praisonai-agents/tests/unit/tools/test_clarify_tool.py(247 lines — usage patterns)What it does: Lets the agent pause mid-run and ask the user a focused question with optional predefined choices, instead of guessing.
Public API (verbatim from SDK):
Tool metadata:
name = "clarify"description = "Ask the user a focused clarifying question when genuinely ambiguous. Use sparingly - only when you cannot proceed without their input."Tool signature (what the LLM calls):
clarify(question: str, choices: Optional[List[str]] = None) -> strHandler resolution order (inside
ClarifyTool.run):kwargs["ctx"]["clarify_handler"](either aClarifyHandleror a callable returning sync/asyncstr)self.handler(defaults toClarifyHandler()with no callback)"No interactive channel available. Please proceed with your best judgment for: {question}"CLI handler behavior (
create_cli_clarify_handler):🤔 {question}, then numbered choices if provided"skip"onKeyboardInterrupt/EOFBot handler behavior (
create_bot_clarify_handler(send_message_fn, wait_for_reply_fn)):choicespresent and reply is a valid digit, returns that choice"no answer provided"on empty replyBot auto-approve list now includes
"clarify"(so the bot won't block the call on an approval prompt by default).Required structure (per AGENTS.md template): frontmatter → one-sentence intro → hero Mermaid diagram → Quick Start
<Steps>→ How It Works (sequence diagram) → Configuration / Handler options → Common Patterns (CLI, bot, custom context handler) → Best Practices<AccordionGroup>→ Related<CardGroup>.Agent-centric Quick Start (the top example, per §1.1 rule 9):
User-interaction flow to show (per §1.1 rule 10):
Mermaid hero diagram — use the standard color palette from AGENTS.md (§3.1). Show: Agent → clarify() → Channel (CLI/Bot/UI) → User → back to Agent.
Icon suggestion:
messages-questionorcircle-question(Mintlify icon; verify availability).docs.json: Add under Features group, after the existing tools entries.
✅ Task 2 — NEW page:
docs/features/tool-availability.mdxStatus in docs today: Not documented. The
@tooldecorator itself has no dedicated page and no mention ofavailability. Search forcheck_availability/availabilityindocs/returns zero hits related to this feature.SDK source of truth (read these before writing):
src/praisonai-agents/praisonaiagents/tools/decorator.py(addsavailabilitykwarg +check_availability()method onFunctionTool)src/praisonai-agents/praisonaiagents/tools/protocols/tool_protocol.py(newToolAvailabilityProtocol)src/praisonai-agents/praisonaiagents/tools/registry.py(newlist_available_tools()method + module-level function)src/praisonai-agents/praisonaiagents/tools/__init__.py(exports the new registry function)src/praisonai-agents/tests/unit/tools/test_availability_gating.py(185 lines — usage patterns)What it does: A tool author can provide a
availabilitycallable returning(is_available: bool, reason: str). At schema-build time, unavailable tools are filtered from the list sent to the LLM, so the model can't hallucinate a call to a tool whose env/API key/service isn't ready. Zero runtime cost for available tools — check only at schema build.Public API (verbatim from SDK):
Decorator form:
Class form (for
BaseToolsubclasses) — implement the protocol:Protocol (new, exported from
praisonaiagents.tools.protocols):Signature:
check_availability(self) -> tuple[bool, str]. Runtime-checkable. Called at schema-build time — must be fast, no I/O.Registry / filtering (new):
Behavior rules to document (from
registry.pyanddecorator.py):check_availabilityare treated as always-available.check_availability()raises, the tool is treated as unavailable and the exception message becomes the reason:f"Availability check failed: {e}"— a warning is logged.register_functionare always considered available (no protocol for them yet).Agent-centric Quick Start (top of page):
User-interaction flow to include:
availabilityon a tool that needs an API key / Docker / DB.Hero Mermaid diagram: Show
Tool Registry → check_availability → [pass|fail] → LLM sees / doesn't see.Icon suggestion:
toggle-onorshield-check.docs.json: Add under Features group. If a "Tools" sub-group exists, nest it there.
✅ Task 3 — UPDATE existing page + NEW page: Bot pairing
Current state of
docs/best-practices/bot-security.mdx:The page already describes pairing but is littered with
<Warning>blocks saying the feature is conceptual / planned / may not exist. As of PR #1504, it is real and shipping. These disclaimers must be removed and APIs aligned to the new SDK.SDK source of truth (read these before writing):
src/praisonai-agents/praisonaiagents/bots/config.py— addsunknown_user_policy: Literal["deny", "allow", "pair"] = "deny"toBotConfigsrc/praisonai/praisonai/bots/_auth.py(140 lines, new) —UnknownUserHandlersrc/praisonai/praisonai/bots/telegram.py— wires handler into Telegram adapter (Discord/Slack/WhatsApp are NOT wired yet in this PR)src/praisonai/praisonai/cli/commands/pairing.py(169 lines, new) —praisonai pairingTyper appsrc/praisonai/praisonai/cli/app.py— registerspairingsubcommandsrc/praisonai/praisonai/gateway/pairing.py—PairingStoregains persistent per-install secret,generate_code(channel_id=...),verify_and_pair(channel_id=None, ...),list_pending(), persists pending codes to diskTask 3a — UPDATE
docs/best-practices/bot-security.mdx:Remove / replace the following three warning blocks (they are now factually wrong):
Around the "Gateway Pairing" section:
→ Delete. Replace with a pointer/link to the new dedicated
docs/features/bot-pairing.mdxpage.Around "Doctor Security Check":
→ Verify against current SDK (
praisonai/cli/features/doctor/checks/bot_checks.pyexists in the synced tree). If available, drop the warning; if still gated, keep a scoped, accurate note.In "Quick Start" — remove the comment lines:
→ Replace the Quick Start with a real, runnable example using the new
unknown_user_policyfield onBotConfig:Also update the "Gateway Pairing" section to reflect the real flow:
PRAISONAI_GATEWAY_SECRETenv var is no longer required — if unset, a per-install secret is auto-generated at<store_dir>/.gateway_secretwith0600perms and reused across restarts. Env var still takes precedence when set. (gateway/pairing.py::_load_or_create_secret)generate_codenow accepts achannel_id— binding a code to a channel at generation time.verify_and_pairacceptschannel_id=Nonewhen the code was generated with a bound channel.Task 3b — NEW page
docs/features/bot-pairing.mdx:Dedicated agent-centric page covering the end-to-end pairing flow. Bot-security page should link here.
Key content:
One-liner: "Let unknown users self-request access to your bot with a secure 8-char code that you approve from the CLI."
Hero Mermaid diagram:
Unknown User → Bot DM → UnknownUserHandler → PairingStore.generate_code → Bot replies with code → Owner runs "praisonai pairing approve ..." → User now allowed.Agent-centric Quick Start:
Then from the owner's terminal:
praisonai pairing list praisonai pairing approve telegram ABCD1234 --label "alice" praisonai pairing revoke telegram 987654321 praisonai pairing clear --confirmPolicy table (from
config.pycomments):denyallowallowed_users)pairCLI command reference — document every flag in
src/praisonai/praisonai/cli/commands/pairing.py:praisonai pairing list [--store-dir PATH]praisonai pairing approve PLATFORM CODE [CHANNEL_ID] [--label TEXT] [--store-dir PATH]CHANNEL_IDis optional when the code was generated with a boundchannel_id(the bot does this).discord/slack/whatsappas valid platform strings forPairingStorebut note adapter wiring is pending.praisonai pairing revoke PLATFORM CHANNEL_ID [--store-dir PATH]praisonai pairing clear [--confirm] [--store-dir PATH]Security model to surface:
generate_code), HMAC-signed with per-install secret.code_ttl, checkPairingStore.__init__default) — consumed on approve.<store_dir>/.gateway_secretmode0600whenPRAISONAI_GATEWAY_SECRETis unset. A warning is logged if file perms drift from0600.channel_id(seeUnknownUserHandler._rate_limit_window).User-interaction flow (step-by-step, per §1.1 rule 10):
UnknownUserHandlerchecksPairingStore.is_paired(channel_id, "telegram")— no.PairingStore.generate_code(channel_type="telegram", channel_id=<their chat id>)."Your pairing code: `ABCD1234`\nOwner: `praisonai pairing approve telegram ABCD1234`"Sequence Mermaid diagram of the above flow (per §3.4 template).
Best Practices accordion group:
unknown_user_policy='deny'in dev / allow-less environments".gateway_secretlike a secret — back it up, don't commit it"--labelon approve so you can tellpairing listrows apart"Icon suggestion:
handshakeoruser-plus.docs.json: Add under Features group near other bot-related entries (
bot-gateway,bot-routing,messaging-bots,bot-commands).Cross-Cutting Checklist for All Three Pages
Per
AGENTS.md(root of this repo):docs/features/— neverdocs/concepts/title,sidebarTitle,description,icon#8B0000,#189AB4,#10B981,#F59E0B,#6366F1, white text,#7C90A0strokes)<Steps>; Best Practices uses<AccordionGroup>; Related uses<CardGroup>Agent(...), not from the low-level class)from praisonaiagents.tools import tool,from praisonaiagents.tools.clarify import clarify,from praisonaiagents.bots import BotConfigdocs.jsonunder the Features group (not Concepts). Validate JSON after edit.@tooldecorator / tools overview; bot-pairing ↔ bot-security + messaging-bots.Deliverables
docs/features/clarify-tool.mdx(new)docs/features/tool-availability.mdx(new)docs/features/bot-pairing.mdx(new)docs/best-practices/bot-security.mdx(update — drop conceptual warnings, fix examples, link to bot-pairing)docs.jsonentries for the three new pages under Featuresmainwith the 4 content edits +docs.jsonOut of Scope
docs/js/anddocs/rust/parity pages — handled by the parity generator, not this issue.docs/concepts/— human-approved only.Created automatically in response to webhook
pull_request.closedon PraisonAI#1504.