-
Notifications
You must be signed in to change notification settings - Fork 12
feat(pdsl): route blocking EMIT_MENU gates through a harness's native question dialog #184
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e2039c0
8d071e9
617c4d3
fb7b6ae
a60766b
0ef03d9
a12e883
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -40,6 +40,51 @@ RULES: | |
| handles all unmatched input. | ||
| ALWAYS require every top-level `OPTIONS` entry to start with a decimal | ||
| number; aliases or patterns follow the number, not replace it. | ||
| ALWAYS treat every `EMIT_MENU` in this corpus as a blocking gate paired with | ||
| `WAIT`/`STOP_TURN` in the same `DO` block; the native-dialog routing below | ||
| applies to that pairing, not to text output that merely lists choices | ||
| without waiting on a reply. | ||
| ALWAYS, when executing `EMIT_MENU`, first check the menu is native-dialog | ||
|
ainetx marked this conversation as resolved.
|
||
| shape-compatible: at most 4 top-level `OPTIONS` entries, and no entry | ||
| documented as accepting free-text/arbitrary input (a path, a name, "or | ||
| describe your own", etc.) rather than choosing among the listed entries. | ||
|
Comment on lines
+47
to
+50
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 776 🏁 Script executed: #!/bin/bash
set -eu
file='skills/studio/modules/runtime/pdsl-execution-card.md'
printf '%s\n' '--- target excerpt ---'
sed -n '1,100p' "$file"
printf '%s\n' '--- related symbols and contracts ---'
rg -n -C 3 'EMIT_MENU|native-dialog|AskUserQuestion|option_count|OPTIONS' skills/studio .github README.md 2>/dev/null | head -n 240Repository: constructorfabric/studio Length of output: 22000 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- tracked files near runtime docs ---'
git ls-files 'skills/studio/modules/runtime/*' | sed -n '1,120p'
printf '%s\n' '--- exact target context ---'
sed -n '35,65p' skills/studio/modules/runtime/pdsl-execution-card.mdRepository: constructorfabric/studio Length of output: 3935 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- AskUserQuestion bindings and menu examples ---'
rg -n -C 5 'AskUserQuestion|ask_tool_name|ask_tool_description|questions.*options|options.*label' skills . 2>/dev/null | head -n 320
printf '%s\n' '--- one-option EMIT_MENU definitions ---'
python3 - <<'PY'
from pathlib import Path
import re
for p in Path('skills').rglob('*'):
if p.is_file():
try: s=p.read_text()
except UnicodeDecodeError: continue
for m in re.finditer(r'EMIT_MENU[^\n]*', s):
start=max(0,m.start()-300); end=min(len(s),m.start()+1400)
block=s[start:end]
opts=re.findall(r'^\s+\d+(?:\s+\S+)?\s*->', block, re.M)
if len(opts) <= 1 and opts:
print(f'{p}: {m.group(0)}; nearby option headers={opts}')
PYRepository: constructorfabric/studio Length of output: 50382 🌐 Web query:
💡 Result: The AskUserQuestion tool is a feature within the Claude Agent SDK designed to facilitate interaction when an agent requires clarification or direction from a user [1]. When an agent encounters a task with multiple valid approaches, it can call this tool to present the user with a structured set of questions [1]. In this context, the specification that options must be between 2 and 4 refers to the configuration requirements for the multiple-choice inputs [1]. Each AskUserQuestion call can support 1 to 4 distinct questions, and each of those questions must be configured with an options array containing exactly 2 to 4 choices [1]. Each choice in this array consists of a label and a description, and may optionally include a preview [1]. The implementation requires the developer to handle the tool call through the canUseTool callback, where the agent's question text and multiple-choice options are processed and presented to the user for selection [1]. Citations: 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- exact generated Claude prompt/tool documentation references ---'
rg -n -C 8 'AskUserQuestion|ask_tool_name|ask_tool_description' skills/studio --glob '*.md' --glob '*.py' --glob '*.json' --glob '*.toml' | head -n 260Repository: constructorfabric/studio Length of output: 27676 Require 2–4 options for Claude native routing. The 🤖 Prompt for AI Agents |
||
| ALWAYS treat an `ask_tool_name` context that was never established (no | ||
| generated shim or dispatch prompt set it at all) identically to `unset`; | ||
| the distinction between "explicitly no binding" and "never bound" carries | ||
| no different behavior. | ||
| ALWAYS, for a shape-compatible `EMIT_MENU` where the active `ask_tool_name` | ||
|
ainetx marked this conversation as resolved.
ainetx marked this conversation as resolved.
ainetx marked this conversation as resolved.
ainetx marked this conversation as resolved.
|
||
| context is a real tool name (not `unset` or never established), invoke | ||
| that tool instead of rendering the menu as prose, built from this fixed | ||
| abstract contract — not the tool's own literal field names, which vary by | ||
| harness: one prompt string (from `TITLE`); an ordered list of options, | ||
| each carrying a display label (the entry's short form), a display | ||
| description (its action clause), and a canonical, non-displayed identity | ||
| (the entry's number/alias) so the returned selection resumes the exact | ||
| numbered branch regardless of how the harness renders or truncates the | ||
| displayed label. For Claude's bound `AskUserQuestion`: one `questions` | ||
| entry, its `question`/`header` set to the prompt, `options[].label` and | ||
| `options[].description` set from each option's display label/description. | ||
|
Comment on lines
+61
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 448 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- target excerpt ---'
sed -n '1,140p' skills/studio/modules/runtime/pdsl-execution-card.md
printf '%s\n' '--- related references ---'
rg -n -C 3 'AskUserQuestion|canonical|identity|option|selection|alias|numbered branch' skills/studio/modules/runtime skills/studio 2>/dev/null | head -n 260
printf '%s\n' '--- tracked target status ---'
git status --short -- skills/studio/modules/runtime/pdsl-execution-card.mdRepository: constructorfabric/studio Length of output: 34392 🌐 Web query:
💡 Result: The AskUserQuestion tool is a component used by agents (specifically within the Claude Code/Agent SDK ecosystem) to solicit clarification or decision-making from a user when a task presents multiple valid approaches or requires additional requirements [1][2][3]. Input Structure When the agent invokes AskUserQuestion, the input payload typically contains an array of questions, where each object follows this structure [1][4]: - question (string): The full text of the question to display to the user [1]. - header (string): A short label for the question (maximum 12 characters) [1][4]. - options (array): A list of 2-4 choices, each containing a label (string) and a description (string) [1][4]. Optionally, TypeScript implementations may include a preview field [1]. - multiSelect (boolean): If set to true, allows the user to choose more than one option [1][4]. Output/Response Handling When the user responds, the system must return an answers object. This object maps the specific question text to the selected label(s) [1][4]: - answers (object): A record where keys are the original question text and values are the selected option labels (for multi-select, an array of labels or a comma-separated string) [1]. - questions (array): The original questions array must be passed back to ensure proper tool processing [1][4]. - response (string, optional): A free-form text reply if the user chooses to provide custom input instead of selecting structured options [1][4]. When integrated, this tool triggers a canUseTool callback, allowing the application to render the prompt via a web form, CLI dialog, or other UI interface [1][4]. By default, these questions remain open until answered, though a timeout (e.g., 60s, 5m, 10m) can be configured to allow the agent to proceed automatically if no user input is provided [2][5]. Citations:
Make the Claude selection mapping reversible. Claude’s 🤖 Prompt for AI Agents
Comment on lines
+65
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🔎 Supported by static analysis🤖 get_repo_knowledge executed:
Length of output: 439 🏁 Script executed: #!/bin/bash
set -eu
file='skills/studio/modules/runtime/pdsl-execution-card.md'
printf '%s\n' '--- target file ---'
sed -n '1,120p' "$file"
printf '%s\n' '--- related references ---'
rg -n -C 3 'AskUserQuestion|question|header|options|TITLE|execution.card|text fallback|native' skills/studio/modules/runtime skills/studio -g '*.md' | head -n 240Repository: constructorfabric/studio Length of output: 31074 🌐 Web query:
💡 Result: The AskUserQuestion tool, used in the Claude Agent SDK to prompt for user input, includes a header field specifically constrained to a maximum of 12 characters [1]. This header serves as a short label for the question presented to the user [1]. The tool's input structure also requires a question field for the full text and an options array containing 2 to 4 choices, each defined by a label and description [1]. Additionally, a multiSelect boolean field is used to indicate whether users are permitted to select multiple options [1]. Citations: Derive a valid Claude Claude limits 🤖 Prompt for AI Agents |
||
| That invocation is itself the turn's `WAIT`/`STOP_TURN` boundary — NEVER | ||
| additionally re-render the menu as text or execute a redundant | ||
| `STOP_TURN` after it. | ||
| ALWAYS treat a native-tool result that selects none of the numbered | ||
| `OPTIONS` — an out-of-band/free-text answer, a cancellation, a dismissal, | ||
| or a tool error — as unmatched input for the menu's own `INVALID` handler; | ||
| NEVER treat any such outcome as silently choosing a default option or | ||
| advancing past the gate. | ||
| ALWAYS, for a shape-compatible `EMIT_MENU` where `ask_tool_name` is `unset` | ||
| or never established, still surface the menu so a harness exposing an | ||
| equivalent affordance it recognizes by `ask_tool_description` can match | ||
| it: state the question, list the numbered options, and mark it explicitly | ||
| as a blocking question the assistant is waiting on — placed as the last | ||
| content in the turn. | ||
| ALWAYS, for a shape-incompatible `EMIT_MENU` (more than 4 options, or any | ||
| free-text-accepting entry), render as today's text menu regardless of | ||
| `ask_tool_name` — a native dialog's fixed-choice shape cannot represent it | ||
| faithfully — but still place it last in the turn and mark it blocking. | ||
| NEVER treat a harness with no matching native affordance as an error; | ||
| fall back to the same explicitly-marked, end-of-turn text rendering used | ||
| for shape-incompatible menus. | ||
| ALWAYS treat `ON_ERROR` as the named recovery path for matching failures. | ||
| ALWAYS treat `NOTES` as explanatory only; NOTES do not create executable | ||
| obligations unless an active rule references them. | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.