npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@tylerho/pi-ask-user

v0.1.0

Published

A multiple-choice question tool that lets the model ask the user to pick an option or answer freely.

Readme

@tylerho/pi-ask-user

A multiple-choice question tool that lets the model ask the user to pick an option or answer freely.

Install

pi install npm:@tylerho/pi-ask-user


Ask User

A single multiple-choice question tool for the model: ask_user shows the user a question with 2–5 model-provided options in a TUI popup, always appends a free-form "Write my own answer…" fallback, and reports the outcome (selection, custom answer, or dismissal) back to the model. It exists so the model can enumerate likely answers instead of asking in plain text — and so the user can decline or answer freely without the model guessing.

Key concepts

  • Single-shot, stateless. One question per call; no state is kept between calls. The tool is meant for branching decisions mid-task (proceed? which option? how much?), not surveys.
  • Model builds the options; UI does the rest. The model supplies question + 2–5 options (label + optional one-line description). The extension appends a Write my own answer… option automatically — the model must never include one itself (enforced via prompt text, not validation).
  • Three outcomes. The user picks an option, writes a custom answer (inline editor), or dismisses (Esc). Dismissal is reported explicitly so the model does not invent an answer.
  • TUI-only. Outside TUI mode the tool does not block — it returns a message telling the model to ask in plain text instead.
  • Validation before UI. Option count is checked (2–5) and throws a descriptive error before any UI is shown, so the model can retry with corrected parameters.
  • Custom overlay with self-drawn chrome. The popup is rendered via ctx.ui.custom with its own full-width title bar and bottom rule; every line is truncated to the overlay width (truncateToWidth), and rendering is cached between inputs.
  • Keyboard model. / cycle options, number keys 1N jump straight to an option, Enter confirms, Esc on the options dismisses; inside the custom-answer editor Enter submits and Esc returns to the options.
  • Abort handling. The UI subscribes to the tool-call abort signal; aborts and Effect interrupts both resolve to a "Cancelled" result rather than hanging or throwing.

API

Tool

ask_user — "Ask User". Registered via pi.registerTool with promptSnippet and promptGuidelines so the model learns when to use it.

Parameters (TypeBox AskUserParams):

| Name | Type | Constraints | Description | |---|---|---|---| | question | string | — | The question to ask the user | | options | array of { label: string, description?: string } | 2–5 items | Answer options; label = "Short display label for this option", description = "Optional one-line description shown below the label" |

Return shape: content: [{ type: "text", text }] plus a details object (AskUserDetails): { question: string, options: string[], answer: string | null, wasCustom: boolean, cancelled: boolean } (cancelled: true iff answer === null).

Result text by outcome (from buildAskUserResultMessage):

  • no-ui (non-TUI mode): "No interactive UI is available, so the question could not be shown. Ask the user in plain text instead."
  • cancelled (abort/interrupt): "Cancelled"
  • dismissed (user pressed Esc): "User dismissed the question without answering. Do not assume an answer; proceed accordingly or ask differently."
  • custom: "User wrote their own answer: <answer>"
  • selected: "User selected option <N>: <answer>"

Error: throws ask_user requires between 2 and 5 options (got <n>). Retry with a valid number of options. when the option count is out of range.

Example call:

{
  "question": "Two tests are failing after the refactor. Fix them now or defer?",
  "options": [
    { "label": "Fix both now", "description": "Keep working until green" },
    { "label": "Defer", "description": "Record as known failures, move on" },
    { "label": "Only investigate", "description": "Diagnose but don't change code" }
  ]
}

Other exported surface

  • prompt.ts exports (constants the tool registers with, and the result-message builder):
    • ASK_USER_PARAMETER_DESCRIPTIONS — the per-parameter descriptions used in the schema.
    • ASK_USER_TOOL_DESCRIPTION — tool description ("Ask the user a single multiple-choice question (2-5 options)…").
    • ASK_USER_PROMPT_SNIPPET — one-line capability snippet for the available-tools prompt.
    • ASK_USER_PROMPT_GUIDELINES — two rules: use ask_user when likely answers are enumerable; one question per call.
    • buildAskUserResultMessage(outcome) — maps an outcome variant (no-ui | cancelled | dismissed | custom | selected) to the model-facing result text.
  • index.ts exports the AskUserInput type (Static<typeof AskUserParams>) and the default askUser(pi: ExtensionAPI) installer.

UI rendering hooks

  • renderCall — renders the call in the transcript: bold ask_user tool title, the question in muted, and the numbered option labels on a dim second line.
  • renderResult — renders the outcome from details: warning-colored ✗ dismissed, success ✓ (wrote) <answer> for custom answers, ✓ N. <answer> for selections (option number derived by looking up the answer in details.options).

No commands, events (pi.on), shortcuts, or config files — the extension is a single tool.

Examples

  1. Branching decision mid-task — after a check fails, ask whether to fix or defer (call above). A selection returns content: "User selected option 1: Fix both now" and details.answer = "Fix both now", so the model acts on the chosen branch.
  2. Custom answer — the user ignores the options and writes their own text in the editor. Result: "User wrote their own answer: …", details.wasCustom: true; the model must honor that text as the answer.
  3. Dismissal — the user hits Esc on the options. Result: "User dismissed the question without answering. Do not assume an answer; proceed accordingly or ask differently." The model should pick a safe default or re-ask differently — never assume the dismissed question was answered.
  4. Non-TUI fallback — in a non-interactive context the tool returns immediately with "No interactive UI is available…"; the model asks in plain text instead of blocking on a UI that can't render.