vault backup: 2026-04-17 12:50:20
This commit is contained in:
parent
208de20525
commit
cd9d8b33e1
6 changed files with 184 additions and 1 deletions
|
|
@ -23,6 +23,10 @@ created: 2026-04-17
|
|||
- **Local path:** `/Volumes/SSD/Projects/Oliver/Barclays-banner-builder`
|
||||
|
||||
## Sessions
|
||||
### 2026-04-17 – Create deployment script and app concept
|
||||
**Asked:** Create deployment script and app concept for Docker-based Ubuntu server with Apache reverse proxy, avoiding WebSockets.
|
||||
**Done:** Fixed Apache configuration routing issue by reordering Include directives so the app's config loads before hp-prod-tracker's catch-all rule.
|
||||
|
||||
### 2026-04-17 – How to deploy the app on
|
||||
**Asked:** How to deploy the app on Ubuntu server with Docker, idempotent deployment script, and fix Apache routing issues?
|
||||
**Done:** Created idempotent deploy script with Docker build, database initialization, migrations, and fixed Apache VirtualHost configuration by reordering Include directives.
|
||||
|
|
@ -127,6 +131,7 @@ created: 2026-04-17
|
|||
## Change Log
|
||||
| Date | Requested | Changed | Files |
|
||||
|------|-----------|---------|-------|
|
||||
| 2026-04-17 | Deployment setup | Apache conf Include order, deploy.sh idempotent script | deploy.sh, /etc/apache2/sites-available/optical-dev.oliver.solutions.conf |
|
||||
| 2026-04-17 | Deployment setup | deploy.sh creation, Apache VirtualHost reordering, Docker build cache management | deploy.sh, /etc/apache2/sites-available/optical-dev.oliver.solutions.conf |
|
||||
| 2026-04-17 | Deployment script & Apache config | Docker build caching, idempotent database init, Alembic migrations, Apache ProxyPass setup | deploy.sh, optical-dev.oliver.solutions.conf |
|
||||
| 2026-04-17 | Deployment script & Apache config | Docker build caching, database migrations, Apache proxy setup | deploy.sh, optical-dev.oliver.solutions.conf |
|
||||
|
|
|
|||
|
|
@ -158,3 +158,9 @@ tags: [daily]
|
|||
- 12:49 (<1min) | `memory-compiler`
|
||||
- **Asked:** Compile a new raw article into the wiki knowledge base with proper indexing.
|
||||
- **Done:** Filed article as `wiki/agent-sdk/custom-tools.md` and updated both topic and master indices.
|
||||
- 12:49 (<1min) | `Barclays-banner-builder`
|
||||
- **Asked:** Create deployment script and app concept for Docker-based Ubuntu server with Apache reverse proxy, avoiding WebSockets.
|
||||
- **Done:** Fixed Apache configuration routing issue by reordering Include directives so the app's config loads before hp-prod-tracker's catch-all rule.
|
||||
- 12:50 | `memory-compiler`
|
||||
- **Asked:** Compile a new article about user input approvals into the agent-sdk wiki section.
|
||||
- **Done:** Created structured wiki article documenting canUseTool and AskUserQuestion with response strategies and workarounds.
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@ This 3-hop pattern works for hundreds of articles without vector search.
|
|||
| [[wiki/web-agency/_index\|web-agency/]] | AI-assisted website building & selling: Claude Code, Nanobanana 2, Kling, LaunchPath MCP | 1 |
|
||||
| [[wiki/dotfiles/_index\|dotfiles/]] | Linux terminal ricing: Kitty, Fish, WezTerm CLI, modern Rust CLI tools, LazyVim, unified themes, Tabby | 9 |
|
||||
|
||||
| [[wiki/agent-sdk/_index\|agent-sdk/]] | Claude Agent SDK (formerly Claude Code SDK) — build autonomous AI agents in Python and TypeScript | 10 |
|
||||
| [[wiki/agent-sdk/_index\|agent-sdk/]] | Claude Agent SDK (formerly Claude Code SDK) — build autonomous AI agents in Python and TypeScript | 11 |
|
||||
| [[wiki/llm-models/_index\|llm-models/]] | OpenAI model catalog — GPT-5.x, o-series reasoning, audio/realtime, embeddings, moderation | 1 |
|
||||
| [[wiki/claude-code/_index\|claude-code/]] | Claude Code product docs — install, capabilities, surfaces, MCP, hooks, scheduling, multi-agent, plugins, skills, error recovery | 7 |
|
||||
|
||||
|
|
|
|||
|
|
@ -24,3 +24,4 @@ Build production AI agents using the same tools, agent loop, and context managem
|
|||
| [[wiki/agent-sdk/mcp-integration\|mcp-integration]] | MCP server setup: transport types (stdio/HTTP/SSE), allowedTools, auth, tool search, error handling | raw/Connect to external tools with MCP.md | 2026-04-17 |
|
||||
| [[wiki/agent-sdk/structured-outputs\|structured-outputs]] | Return validated JSON from agent workflows using JSON Schema, Zod, or Pydantic; error subtypes, tips | raw/Get structured output from agents.md | 2026-04-17 |
|
||||
| [[wiki/agent-sdk/custom-tools\|custom-tools]] | Define custom tools with @tool/@tool(), in-process MCP server, error handling, images, resources, annotations | raw/Give Claude custom tools.md | 2026-04-17 |
|
||||
| [[wiki/agent-sdk/user-input-approvals\|user-input-approvals]] | canUseTool callback: tool approvals, AskUserQuestion clarifying questions, allow/deny/modify, Python streaming workaround | raw/Handle approvals and user input.md | 2026-04-17 |
|
||||
|
|
|
|||
171
wiki/agent-sdk/user-input-approvals.md
Normal file
171
wiki/agent-sdk/user-input-approvals.md
Normal file
|
|
@ -0,0 +1,171 @@
|
|||
---
|
||||
title: "Handle Approvals and User Input"
|
||||
aliases: [canUseTool, user-approvals, ask-user-question]
|
||||
tags: [agent-sdk, permissions, user-input, python, typescript]
|
||||
sources: [raw/Handle approvals and user input.md]
|
||||
created: 2026-04-17
|
||||
updated: 2026-04-17
|
||||
---
|
||||
|
||||
# Handle Approvals and User Input
|
||||
|
||||
Surface Claude's approval requests and clarifying questions to users, then return their decisions back to the SDK via the `canUseTool` callback.
|
||||
|
||||
## When Claude Pauses for Input
|
||||
|
||||
Claude stops and fires `canUseTool` in two situations:
|
||||
|
||||
| Situation | `tool_name` value | Trigger |
|
||||
|-----------|------------------|---------|
|
||||
| Tool needs permission | `"Bash"`, `"Write"`, `"Edit"`, etc. | Tool not auto-approved by [[wiki/agent-sdk/configure-permissions\|permission rules]] |
|
||||
| Clarifying question | `"AskUserQuestion"` | Claude needs direction before proceeding |
|
||||
|
||||
This is distinct from a normal conversation turn — execution is paused until your callback returns.
|
||||
|
||||
## canUseTool Callback Setup
|
||||
|
||||
```python
|
||||
async def handle_tool_request(tool_name, input_data, context):
|
||||
# prompt user, return allow or deny
|
||||
...
|
||||
|
||||
options = ClaudeAgentOptions(can_use_tool=handle_tool_request)
|
||||
```
|
||||
|
||||
**Python requirement:** streaming mode + a `PreToolUse` hook returning `{"continue_": True}` — without it, the stream closes before the callback fires.
|
||||
|
||||
```python
|
||||
async def dummy_hook(input_data, tool_use_id, context):
|
||||
return {"continue_": True}
|
||||
|
||||
options = ClaudeAgentOptions(
|
||||
can_use_tool=can_use_tool,
|
||||
hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[dummy_hook])]},
|
||||
)
|
||||
```
|
||||
|
||||
## Tool Approval Requests
|
||||
|
||||
### Callback arguments
|
||||
|
||||
| Argument | Description |
|
||||
|----------|-------------|
|
||||
| `tool_name` | Tool Claude wants to use (`"Bash"`, `"Write"`, `"Edit"`, `"Read"`) |
|
||||
| `input_data` | Tool-specific parameters (e.g. `command`, `file_path`, `content`) |
|
||||
| `context` | Suggestions (`PermissionUpdate` entries) + cancellation signal |
|
||||
|
||||
### Response types
|
||||
|
||||
| Response | Python | TypeScript |
|
||||
|----------|--------|------------|
|
||||
| Allow | `PermissionResultAllow(updated_input=input_data)` | `{ behavior: "allow", updatedInput }` |
|
||||
| Deny | `PermissionResultDeny(message="reason")` | `{ behavior: "deny", message }` |
|
||||
|
||||
### Response strategies
|
||||
|
||||
- **Approve** — pass input unchanged
|
||||
- **Approve with changes** — sanitize paths, add constraints before passing
|
||||
- **Reject** — block the tool, Claude sees your message and may adjust
|
||||
- **Suggest alternative** — block + guide Claude toward what user wants
|
||||
- **Redirect** — use streaming input to send a new instruction entirely
|
||||
|
||||
## AskUserQuestion — Clarifying Questions
|
||||
|
||||
When Claude needs direction (common in [[wiki/agent-sdk/configure-permissions\|plan mode]]), it calls `AskUserQuestion`. Route on `tool_name == "AskUserQuestion"`.
|
||||
|
||||
### Input format Claude sends
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [
|
||||
{
|
||||
"question": "How should I format the output?",
|
||||
"header": "Format",
|
||||
"options": [
|
||||
{ "label": "Summary", "description": "Brief overview of key points" },
|
||||
{ "label": "Detailed", "description": "Full explanation with examples" }
|
||||
],
|
||||
"multiSelect": false
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### Response format you return
|
||||
|
||||
```json
|
||||
{
|
||||
"questions": [ /* pass through original */ ],
|
||||
"answers": {
|
||||
"How should I format the output?": "Summary",
|
||||
"Which sections should I include?": "Introduction, Conclusion"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
- Single-select: one label
|
||||
- Multi-select: labels joined with `", "`
|
||||
- Free text: user's raw text (add an "Other" option in your UI)
|
||||
|
||||
### Option previews (TypeScript only)
|
||||
|
||||
Set `toolConfig.askUserQuestion.previewFormat` to `"markdown"` or `"html"` — Claude adds a `preview` field to options where a visual comparison helps. Check for `undefined` before rendering.
|
||||
|
||||
## Complete Python Example
|
||||
|
||||
```python
|
||||
def parse_response(response: str, options: list) -> str:
|
||||
try:
|
||||
indices = [int(s.strip()) - 1 for s in response.split(",")]
|
||||
labels = [options[i]["label"] for i in indices if 0 <= i < len(options)]
|
||||
return ", ".join(labels) if labels else response
|
||||
except ValueError:
|
||||
return response
|
||||
|
||||
async def handle_ask_user_question(input_data: dict) -> PermissionResultAllow:
|
||||
answers = {}
|
||||
for q in input_data.get("questions", []):
|
||||
print(f"\n{q['header']}: {q['question']}")
|
||||
for i, opt in enumerate(q["options"]):
|
||||
print(f" {i+1}. {opt['label']} - {opt['description']}")
|
||||
response = input("Your choice: ").strip()
|
||||
answers[q["question"]] = parse_response(response, q["options"])
|
||||
return PermissionResultAllow(
|
||||
updated_input={"questions": input_data.get("questions", []), "answers": answers}
|
||||
)
|
||||
|
||||
async def can_use_tool(tool_name, input_data, context):
|
||||
if tool_name == "AskUserQuestion":
|
||||
return await handle_ask_user_question(input_data)
|
||||
# display tool info, prompt y/n
|
||||
response = input(f"Allow {tool_name}? (y/n): ")
|
||||
if response.lower() == "y":
|
||||
return PermissionResultAllow(updated_input=input_data)
|
||||
return PermissionResultDeny(message="User denied this action")
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
- `AskUserQuestion` is **not available in subagents** spawned via the Agent tool
|
||||
- Each call supports **1–4 questions**, each with **2–4 options**
|
||||
|
||||
## Alternatives to canUseTool
|
||||
|
||||
| Mechanism | Best for |
|
||||
|-----------|----------|
|
||||
| [[wiki/agent-sdk/hooks-guide\|Hooks]] | Auto-allow/deny without prompting; external notifications (Slack, email) via `PermissionRequest` hook |
|
||||
| Streaming input | Interrupting mid-task, providing context, chat interfaces |
|
||||
| [[wiki/agent-sdk/custom-tools\|Custom tools]] | Structured forms, multi-step workflows, external approval systems |
|
||||
|
||||
## Key Takeaways
|
||||
|
||||
- `canUseTool` is the single callback for both tool approvals and `AskUserQuestion` — branch on `tool_name`
|
||||
- Python requires streaming mode + a `PreToolUse` dummy hook to keep the stream alive
|
||||
- Deny responses include a message Claude reads — use it to redirect, not just block
|
||||
- `AskUserQuestion` is especially common in plan mode; include it in your `tools` array if you define one
|
||||
- You can modify tool input before allowing (sanitize, constrain) — not just pass-through
|
||||
- For automation without user prompts, use [[wiki/agent-sdk/hooks-guide\|hooks]] instead of `canUseTool`
|
||||
|
||||
## Sources
|
||||
|
||||
- `raw/Handle approvals and user input.md` — official Agent SDK docs on user input handling
|
||||
Loading…
Add table
Reference in a new issue