Initial commit
This commit is contained in:
40
agents/prompt-optimizer.md
Normal file
40
agents/prompt-optimizer.md
Normal file
@@ -0,0 +1,40 @@
|
||||
---
|
||||
name: prompt-optimizer
|
||||
description: Processes templates and extracts variables to create optimized prompts
|
||||
allowed-tools: [Read(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/templates/**), AskUserQuestion, Bash(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/prompt-optimizer-handler.sh:*)]
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
Extract variables from user task, substitute into template, validate result, return optimized prompt.
|
||||
|
||||
## Process
|
||||
|
||||
1. **Call handler** with your XML input:
|
||||
```bash
|
||||
~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/prompt-optimizer-handler.sh '<your-input-xml>'
|
||||
```
|
||||
|
||||
2. **Extract variables** from user task based on handler output:
|
||||
- Use variable descriptions (if provided) as guidance for extraction
|
||||
- Required variables must have values (use AskUserQuestion if unclear)
|
||||
- Optional variables can use defaults
|
||||
|
||||
3. **Substitute all** `{$VARIABLE}` and `{$VARIABLE:default}` patterns, remove YAML frontmatter
|
||||
|
||||
4. **Validate result** - scan your output for remaining `{$...}` patterns:
|
||||
- If any remain, re-analyze user task or infer appropriate values
|
||||
- Use default values for optional variables you missed
|
||||
- If you cannot determine a **required** variable value and cannot reasonably infer it, use AskUserQuestion to request clarification from the user
|
||||
- **Output MUST have ZERO remaining placeholders**
|
||||
|
||||
5. **Return XML**:
|
||||
```xml
|
||||
<prompt_optimizer_result>
|
||||
<template>template-name</template>
|
||||
<skill>skill-name or none</skill>
|
||||
<execution_mode>plan or direct</execution_mode>
|
||||
<optimized_prompt>
|
||||
(complete template with all variables substituted - NO {$...} patterns)
|
||||
</optimized_prompt>
|
||||
</prompt_optimizer_result>
|
||||
```
|
||||
329
agents/scripts/prompt-optimizer-handler.sh
Executable file
329
agents/scripts/prompt-optimizer-handler.sh
Executable file
@@ -0,0 +1,329 @@
|
||||
#!/usr/bin/env bash
|
||||
# Purpose: State machine for prompt-optimizer agent with integrated template processing
|
||||
# Inputs: XML input via stdin containing user_task, template, execution_mode
|
||||
# Outputs: Instructions with template content and variable extraction guidance
|
||||
# Architecture: Incorporates template-processor.sh logic directly (no external bash calls needed)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
. "$SCRIPT_DIR/../../scripts/common.sh"
|
||||
|
||||
# Setup plugin root
|
||||
setup_plugin_root
|
||||
|
||||
TEMPLATE_DIR="${CLAUDE_PLUGIN_ROOT}/templates"
|
||||
|
||||
# Parse XML input from command-line argument (supports multiline content)
|
||||
read_xml_input() {
|
||||
local xml_input="$1"
|
||||
|
||||
# Validate input provided
|
||||
if [ -z "$xml_input" ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract required fields using common functions
|
||||
local user_task
|
||||
user_task=$(require_xml_field "$xml_input" "user_task" "auto") || exit 1
|
||||
|
||||
local template
|
||||
template=$(require_xml_field "$xml_input" "template") || {
|
||||
echo "Error: Template selection must be done before calling prompt-optimizer." >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Extract optional field with default
|
||||
local execution_mode
|
||||
execution_mode=$(optional_xml_field "$xml_input" "execution_mode" "direct")
|
||||
|
||||
# Validate execution_mode
|
||||
if [ "$execution_mode" != "plan" ] && [ "$execution_mode" != "direct" ]; then
|
||||
echo "Error: Invalid execution_mode: $execution_mode (must be 'plan' or 'direct')" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export safely (without sanitization for USER_TASK to preserve content, but sanitize for output)
|
||||
export USER_TASK="$user_task"
|
||||
export TEMPLATE="$template"
|
||||
export EXECUTION_MODE="$execution_mode"
|
||||
}
|
||||
|
||||
# Map template name to skill name
|
||||
get_skill_for_template() {
|
||||
local template=$1
|
||||
|
||||
case "$template" in
|
||||
code-refactoring)
|
||||
echo "meta-prompt:code-refactoring"
|
||||
;;
|
||||
code-review)
|
||||
echo "meta-prompt:code-review"
|
||||
;;
|
||||
test-generation)
|
||||
echo "meta-prompt:test-generation"
|
||||
;;
|
||||
documentation-generator)
|
||||
echo "meta-prompt:documentation-generator"
|
||||
;;
|
||||
data-extraction)
|
||||
echo "meta-prompt:data-extraction"
|
||||
;;
|
||||
code-comparison)
|
||||
echo "meta-prompt:code-comparison"
|
||||
;;
|
||||
custom)
|
||||
echo "none"
|
||||
;;
|
||||
*)
|
||||
echo "none"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Load template file with improved error messages
|
||||
load_template() {
|
||||
local template_name="$1"
|
||||
local template_path="$TEMPLATE_DIR/${template_name}.md"
|
||||
|
||||
# Check if file exists
|
||||
if [ ! -f "$template_path" ]; then
|
||||
echo "Error: Template file not found: $template_path" >&2
|
||||
echo "" >&2
|
||||
echo "Available templates in $TEMPLATE_DIR:" >&2
|
||||
if [ -d "$TEMPLATE_DIR" ]; then
|
||||
ls -1 "$TEMPLATE_DIR"/*.md 2>/dev/null | sed 's/.*\// - /' | sed 's/\.md$//' >&2 || echo " (none found)" >&2
|
||||
else
|
||||
echo " Error: Template directory does not exist: $TEMPLATE_DIR" >&2
|
||||
fi
|
||||
echo "" >&2
|
||||
echo "Requested template: $template_name" >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if file is readable
|
||||
if [ ! -r "$template_path" ]; then
|
||||
echo "Error: Template file not readable: $template_path" >&2
|
||||
echo "Check file permissions." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Check if file is non-empty
|
||||
if [ ! -s "$template_path" ]; then
|
||||
echo "Error: Template file is empty: $template_path" >&2
|
||||
echo "Template files must contain prompt content." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
cat "$template_path"
|
||||
}
|
||||
|
||||
# Extract variables from template content
|
||||
extract_variables() {
|
||||
local template="$1"
|
||||
# Find all {$VARIABLE} and {$VARIABLE:default} patterns
|
||||
# Output format: VARIABLE (required) or VARIABLE:default (optional)
|
||||
echo "$template" | grep -oE '\{\$[A-Z_][A-Z0-9_]*(:[^}]*)?\}' 2>/dev/null | sort -u | sed 's/[{}$]//g' || true
|
||||
}
|
||||
|
||||
# Extract variable descriptions from template YAML frontmatter
|
||||
# Returns formatted variable descriptions for agent guidance
|
||||
extract_variable_descriptions() {
|
||||
local template_content="$1"
|
||||
|
||||
# Extract YAML frontmatter (between first two ---)
|
||||
local frontmatter
|
||||
frontmatter=$(echo "$template_content" | awk '/^---$/{if(++n==1){next}else{exit}} n==1{print}')
|
||||
|
||||
# Check for variable_descriptions section
|
||||
if ! echo "$frontmatter" | grep -q "variable_descriptions:"; then
|
||||
return 0 # No descriptions available
|
||||
fi
|
||||
|
||||
# Extract variable_descriptions block - get lines after variable_descriptions: until next top-level key
|
||||
# Pipe through sanitize_input to escape potential shell metacharacters
|
||||
echo "$frontmatter" | awk '
|
||||
/^variable_descriptions:/ { in_block=1; next }
|
||||
in_block && /^[a-z_]+:/ { exit }
|
||||
in_block && /^ [A-Z_]+:/ {
|
||||
# Remove leading spaces and print
|
||||
sub(/^ /, "");
|
||||
print
|
||||
}
|
||||
' | while IFS= read -r line; do
|
||||
sanitize_input "$line"
|
||||
done
|
||||
}
|
||||
|
||||
# Format variable descriptions for display
|
||||
# Input: raw variable descriptions (one per line in "NAME: description" format)
|
||||
# Output: formatted markdown list
|
||||
format_variable_descriptions() {
|
||||
local var_descriptions="$1"
|
||||
|
||||
# Skip if empty or only whitespace
|
||||
[ -z "$var_descriptions" ] && return 0
|
||||
echo "$var_descriptions" | grep -q '[^[:space:]]' || return 0
|
||||
|
||||
echo "## Variable Descriptions"
|
||||
echo ""
|
||||
echo "$var_descriptions" | while IFS= read -r line; do
|
||||
# Skip empty lines
|
||||
[ -z "$line" ] && continue
|
||||
# Split on first colon only to handle descriptions containing colons
|
||||
name="${line%%:*}"
|
||||
desc="${line#*:}"
|
||||
# Trim whitespace from name
|
||||
name="$(echo "$name" | sed 's/^[[:space:]]*//; s/[[:space:]]*$//')"
|
||||
# Skip if name is empty
|
||||
[ -z "$name" ] && continue
|
||||
# Clean up the description (remove surrounding quotes and whitespace)
|
||||
desc=$(echo "$desc" | sed 's/^[[:space:]]*"//; s/"[[:space:]]*$//; s/^[[:space:]]*//; s/[[:space:]]*$//')
|
||||
echo "- **$name**: $desc"
|
||||
done
|
||||
}
|
||||
|
||||
# Escape special characters for output
|
||||
escape_for_output() {
|
||||
local value="$1"
|
||||
# Escape for safe display in instructions (including $ for heredoc safety)
|
||||
printf '%s\n' "$value" | sed 's/\\/\\\\/g; s/\$/\\$/g; s/`/\\`/g; s/"/\\"/g'
|
||||
}
|
||||
|
||||
# Generate instructions for processing the template
|
||||
generate_instructions() {
|
||||
local sanitized_task=$(sanitize_input "$USER_TASK")
|
||||
local skill=$(get_skill_for_template "$TEMPLATE")
|
||||
|
||||
# Load template content
|
||||
local template_content
|
||||
template_content=$(load_template "$TEMPLATE") || {
|
||||
echo "Error: Failed to load template '$TEMPLATE'" >&2
|
||||
exit 1
|
||||
}
|
||||
|
||||
# Extract variables from template
|
||||
local variables
|
||||
variables=$(extract_variables "$template_content")
|
||||
|
||||
# Extract variable descriptions from frontmatter
|
||||
local var_descriptions
|
||||
var_descriptions=$(extract_variable_descriptions "$template_content")
|
||||
|
||||
# Escape template content for safe output
|
||||
local escaped_template=$(escape_for_output "$template_content")
|
||||
|
||||
# Parse variables into required and optional lists
|
||||
local required_vars=""
|
||||
local optional_vars=""
|
||||
|
||||
while IFS= read -r var; do
|
||||
if [ -z "$var" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
if [[ "$var" == *:* ]]; then
|
||||
# Variable has default value (optional)
|
||||
local var_name="${var%%:*}"
|
||||
# Note: default value is preserved in template, not extracted here
|
||||
if [ -n "$optional_vars" ]; then
|
||||
optional_vars="$optional_vars, $var_name"
|
||||
else
|
||||
optional_vars="$var_name"
|
||||
fi
|
||||
else
|
||||
# No default value (required)
|
||||
if [ -n "$required_vars" ]; then
|
||||
required_vars="$required_vars, $var"
|
||||
else
|
||||
required_vars="$var"
|
||||
fi
|
||||
fi
|
||||
done <<< "$variables"
|
||||
|
||||
cat <<EOF
|
||||
Template: $TEMPLATE (already selected)
|
||||
Skill: $skill
|
||||
Execution mode: $EXECUTION_MODE
|
||||
|
||||
TASK: Extract variables from the user task and substitute them into the template.
|
||||
|
||||
User task: $sanitized_task
|
||||
|
||||
## Template Variables
|
||||
|
||||
$(if [ -n "$required_vars" ]; then echo "Required: $required_vars"; fi)
|
||||
$(if [ -n "$optional_vars" ]; then echo "Optional: $optional_vars"; fi)
|
||||
$(if [ -z "$required_vars" ] && [ -z "$optional_vars" ]; then echo "This template has no variables."; fi)
|
||||
|
||||
$(format_variable_descriptions "$var_descriptions")
|
||||
|
||||
## Instructions
|
||||
|
||||
1. **Extract variable values** from the user task:
|
||||
- Analyze the user task to identify values for each variable
|
||||
- Use the variable descriptions above as guidance for what to extract
|
||||
- Required variables must have values
|
||||
- Optional variables can use their defaults if not specified in the task
|
||||
- Use AskUserQuestion if any required information is unclear
|
||||
|
||||
2. **Substitute variables** in the template:
|
||||
- Replace each {\\\$VARIABLE} or {\\\$VARIABLE:default} with its value
|
||||
- For optional variables without values, use their default
|
||||
- Ensure all {\\\$...} patterns are replaced
|
||||
|
||||
3. **Validate your result** before outputting:
|
||||
- Scan your substituted template for any remaining {\\\$...} patterns
|
||||
- If ANY remain, go back and extract/infer appropriate values
|
||||
- For optional variables you missed, use their default value from the pattern
|
||||
- Your output MUST have ZERO remaining placeholders
|
||||
|
||||
4. **Output the result** in this XML format:
|
||||
|
||||
\`\`\`xml
|
||||
<prompt_optimizer_result>
|
||||
<template>$TEMPLATE</template>
|
||||
<skill>$skill</skill>
|
||||
<execution_mode>$EXECUTION_MODE</execution_mode>
|
||||
<optimized_prompt>
|
||||
[Insert the complete processed template here with all variables substituted]
|
||||
</optimized_prompt>
|
||||
</prompt_optimizer_result>
|
||||
\`\`\`
|
||||
|
||||
## Template Content
|
||||
|
||||
\`\`\`
|
||||
$escaped_template
|
||||
\`\`\`
|
||||
|
||||
## Validation Checklist
|
||||
|
||||
Before returning your result, verify:
|
||||
- [ ] No {\\\$VARIABLE} patterns remain in <optimized_prompt>
|
||||
- [ ] No {\\\$VARIABLE:default} patterns remain in <optimized_prompt>
|
||||
- [ ] YAML frontmatter (lines between ---) is NOT included
|
||||
- [ ] All required variables have meaningful values from user task
|
||||
- [ ] Optional variables either have extracted values or use their defaults
|
||||
EOF
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Check for command-line argument
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read and parse XML input from first argument
|
||||
read_xml_input "$1"
|
||||
|
||||
# Generate and output instructions
|
||||
generate_instructions
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
221
agents/scripts/template-executor-handler.sh
Executable file
221
agents/scripts/template-executor-handler.sh
Executable file
@@ -0,0 +1,221 @@
|
||||
#!/usr/bin/env bash
|
||||
# Purpose: Deterministic input/output processing for template-executor agent
|
||||
# Inputs: XML input containing skill and optimized_prompt
|
||||
# Outputs: Instructions for Claude Code to execute
|
||||
# Token reduction: Eliminates XML parsing, skill routing, and output formatting
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
. "$SCRIPT_DIR/../../scripts/common.sh"
|
||||
|
||||
# Setup plugin root
|
||||
setup_plugin_root
|
||||
|
||||
SKILL_DIR="${CLAUDE_PLUGIN_ROOT}/skills"
|
||||
|
||||
# Validate skill file exists
|
||||
validate_skill() {
|
||||
local skill="$1"
|
||||
|
||||
# "none" is always valid (no skill needed)
|
||||
if [ "$skill" = "none" ]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
# Remove "meta-prompt:" prefix if present
|
||||
local skill_name="${skill#meta-prompt:}"
|
||||
local skill_file="${SKILL_DIR}/${skill_name}/SKILL.md"
|
||||
|
||||
if [ ! -f "$skill_file" ]; then
|
||||
echo "Warning: Skill file not found: $skill_file" >&2
|
||||
echo "" >&2
|
||||
echo "Available skills in $SKILL_DIR:" >&2
|
||||
if [ -d "$SKILL_DIR" ]; then
|
||||
find "$SKILL_DIR" -name "SKILL.md" -type f 2>/dev/null | sed "s|$SKILL_DIR/||" | sed 's|/SKILL.md$||' | sed 's/^/ - meta-prompt:/' >&2 || echo " (none found)" >&2
|
||||
else
|
||||
echo " Error: Skill directory does not exist: $SKILL_DIR" >&2
|
||||
fi
|
||||
echo "" >&2
|
||||
echo "Requested skill: $skill" >&2
|
||||
echo "Continuing without skill..." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
# Verify skill file is readable
|
||||
if [ ! -r "$skill_file" ]; then
|
||||
echo "Warning: Skill file exists but is not readable: $skill_file" >&2
|
||||
echo "Check file permissions." >&2
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
# Parse XML input from command-line argument (supports multiline content)
|
||||
read_xml_input() {
|
||||
local xml_input="$1"
|
||||
|
||||
# Validate input provided
|
||||
if [ -z "$xml_input" ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract required field using common function
|
||||
local optimized_prompt
|
||||
optimized_prompt=$(require_xml_field "$xml_input" "optimized_prompt" "auto") || exit 1
|
||||
|
||||
# Extract optional field with default
|
||||
local skill
|
||||
skill=$(optional_xml_field "$xml_input" "skill" "none")
|
||||
|
||||
# Validate skill file exists and fail if required skill is missing
|
||||
# Note: If skill is "none", validate_skill returns 0, so we never enter this block
|
||||
if ! validate_skill "$skill"; then
|
||||
echo "Error: Required skill '$skill' not found. Cannot continue." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export for use by other functions
|
||||
export SKILL="$skill"
|
||||
export OPTIMIZED_PROMPT="$optimized_prompt"
|
||||
}
|
||||
|
||||
# Generate instructions
|
||||
generate_instructions() {
|
||||
cat <<'INSTRUCTIONS_EOF'
|
||||
You are a versatile execution agent that combines template-based prompts with domain-specific skills to accomplish tasks efficiently.
|
||||
|
||||
## Your Task
|
||||
|
||||
Execute the optimized prompt provided below, following these steps:
|
||||
|
||||
INSTRUCTIONS_EOF
|
||||
|
||||
# Step 1: Load skill (if needed)
|
||||
if [ "$SKILL" != "none" ]; then
|
||||
cat <<EOF
|
||||
|
||||
### Step 1: Load Skill
|
||||
|
||||
Load the domain-specific skill to gain expertise:
|
||||
|
||||
\`\`\`
|
||||
Skill: $SKILL
|
||||
\`\`\`
|
||||
|
||||
The skill provides domain-specific best practices and guidance for task execution.
|
||||
|
||||
EOF
|
||||
else
|
||||
cat <<EOF
|
||||
|
||||
### Step 1: Skill Loading
|
||||
|
||||
No domain-specific skill required for this task (custom template).
|
||||
|
||||
EOF
|
||||
fi
|
||||
|
||||
# Step 2: Execute Task
|
||||
cat <<'EOF'
|
||||
|
||||
### Step 2: Execute Task
|
||||
|
||||
**IMPORTANT: Use TodoWrite to communicate your tasks and track progress throughout execution.**
|
||||
|
||||
Execute the task following:
|
||||
|
||||
1. **TodoWrite for task tracking**:
|
||||
- Create a todo list IMMEDIATELY when you start if the task has multiple steps
|
||||
- Mark tasks as in_progress before starting them
|
||||
- Mark tasks as completed immediately after finishing them
|
||||
- Keep exactly ONE task in_progress at a time
|
||||
- Use todos to communicate what you're working on to the user
|
||||
|
||||
2. **Parallelization**:
|
||||
- Identify independent operations that can run in parallel
|
||||
- Make multiple tool calls in a single response when possible
|
||||
- Chain dependent operations sequentially using && or multiple messages
|
||||
|
||||
3. **The optimized prompt's instructions** (provided below) - Your specific requirements
|
||||
|
||||
4. **The loaded skill's guidance** (if any) - Domain best practices and expertise
|
||||
|
||||
5. **Tool usage best practices**:
|
||||
- Use specialized tools (Read/Edit/Write) not bash for file operations
|
||||
- Never use placeholders - ask user if information is missing
|
||||
|
||||
### General Guidelines
|
||||
|
||||
**Code Modifications:**
|
||||
- ALWAYS Read files before editing
|
||||
- Use Edit for existing files, Write only for new files
|
||||
- Preserve exact indentation
|
||||
- Delete unused code completely (no comments or underscores)
|
||||
- Avoid security vulnerabilities (injection, XSS, etc.)
|
||||
|
||||
**Analysis Tasks:**
|
||||
- Be thorough and systematic
|
||||
- Provide specific, actionable feedback
|
||||
- Include examples and context
|
||||
- Structure output clearly
|
||||
|
||||
**Quality Standards:**
|
||||
- Follow existing conventions in the codebase
|
||||
- Keep solutions simple and focused
|
||||
- Make only requested changes (avoid over-engineering)
|
||||
- Test changes when appropriate
|
||||
|
||||
EOF
|
||||
|
||||
# Step 3: Output format
|
||||
cat <<'EOF'
|
||||
|
||||
### Step 3: Return Results
|
||||
|
||||
After completing the task, return your results in this XML format:
|
||||
|
||||
```xml
|
||||
<template_executor_result>
|
||||
<status>completed|failed|partial</status>
|
||||
<summary>
|
||||
Brief summary of what was accomplished
|
||||
</summary>
|
||||
<details>
|
||||
Detailed results, changes made, files modified, etc.
|
||||
</details>
|
||||
</template_executor_result>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Your Optimized Prompt
|
||||
|
||||
Below is the optimized prompt containing your specific task instructions:
|
||||
|
||||
EOF
|
||||
|
||||
# Output the optimized prompt
|
||||
echo "$OPTIMIZED_PROMPT"
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Check for command-line argument
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read and parse XML input from first argument
|
||||
read_xml_input "$1"
|
||||
|
||||
# Generate and output instructions
|
||||
generate_instructions
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
442
agents/scripts/template-selector-handler.sh
Executable file
442
agents/scripts/template-selector-handler.sh
Executable file
@@ -0,0 +1,442 @@
|
||||
#!/usr/bin/env bash
|
||||
# Purpose: State machine for template-selector agent with integrated classification
|
||||
# Inputs: XML input via stdin containing user_task, suggested_template (optional), confidence (optional)
|
||||
# Outputs: Instructions with classification result
|
||||
# Architecture: Incorporates template-selector.sh logic directly (no external bash calls needed)
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
# Source common functions
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
. "$SCRIPT_DIR/../../scripts/common.sh"
|
||||
|
||||
# Setup plugin root
|
||||
setup_plugin_root
|
||||
|
||||
TEMPLATE_DIR="${CLAUDE_PLUGIN_ROOT}/templates"
|
||||
|
||||
# ============================================================================
|
||||
# Confidence Threshold Configuration
|
||||
# ============================================================================
|
||||
#
|
||||
# These values control template classification confidence scoring:
|
||||
#
|
||||
# BORDERLINE_MIN (60%):
|
||||
# - Minimum confidence for accepting keyword-based classification
|
||||
# - Below this: routes to LLM for borderline case review
|
||||
# - Rationale: Ensures 90%+ accuracy by letting LLM handle uncertain cases
|
||||
#
|
||||
# STRONG_INDICATOR_BASE (75%):
|
||||
# - Base confidence when a strong indicator keyword is found
|
||||
# - Examples: "refactor", "compare", "test", "review"
|
||||
# - Rationale: Strong indicators reliably predict template choice
|
||||
#
|
||||
# SUPPORTING_KEYWORD_BONUS (8% per keyword):
|
||||
# - Additional confidence for each supporting keyword (max 100%)
|
||||
# - Examples: "code", "module", "security", etc.
|
||||
# - Rationale: Multiple related keywords increase confidence
|
||||
#
|
||||
# Confidence levels for supporting keywords only (no strong indicator):
|
||||
# - ONE_KEYWORD_CONFIDENCE (35%): One supporting keyword found
|
||||
# - TWO_KEYWORD_CONFIDENCE (60%): Two supporting keywords found
|
||||
# - THREE_KEYWORD_CONFIDENCE (75%): Three+ supporting keywords found
|
||||
#
|
||||
# Example scoring:
|
||||
# "Refactor the authentication module" = 75% (strong) + 8% (code keyword) = 83%
|
||||
# "Check security of code" = 60% (two keywords: security, code)
|
||||
# ============================================================================
|
||||
|
||||
BORDERLINE_MIN=60
|
||||
STRONG_INDICATOR_BASE=75
|
||||
SUPPORTING_KEYWORD_BONUS=8
|
||||
ONE_KEYWORD_CONFIDENCE=35
|
||||
TWO_KEYWORD_CONFIDENCE=60
|
||||
THREE_KEYWORD_CONFIDENCE=75
|
||||
|
||||
# Regex patterns for strong indicators
|
||||
PATTERN_CODE="refactor|codebase|implement|fix|update|modify|create|build|reorganize|improve|enhance|transform|optimize|rework|revamp|refine|polish|modernize|clean|streamline"
|
||||
PATTERN_COMPARISON="compare|classify|check|same|different|verify|determine|match|matches|equivalent|equals?|similar|duplicate|identical"
|
||||
PATTERN_TEST="tests?|spec|testing|unittest"
|
||||
PATTERN_REVIEW="review|feedback|critique|analyze|assess|evaluate|examine|inspect|scrutinize|audit|scan|survey|vet|investigate|appraise"
|
||||
PATTERN_DOCUMENTATION="documentation|readme|docstring|docs|document|write.*(comment|docstring|documentation|guide|instruction)|author.*(documentation|instruction|guide)"
|
||||
PATTERN_EXTRACTION="extract|parse|pull|retrieve|mine|harvest|collect|scrape|distill|gather|isolate|obtain|sift|fish|pluck|glean|cull|unearth|dredge|winnow"
|
||||
|
||||
# Parse XML input from command-line argument (supports multiline content)
|
||||
read_xml_input() {
|
||||
local xml_input="$1"
|
||||
|
||||
# Validate input provided
|
||||
if [ -z "$xml_input" ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Extract required field using common function
|
||||
local user_task
|
||||
user_task=$(require_xml_field "$xml_input" "user_task" "auto") || exit 1
|
||||
|
||||
# Extract optional fields with defaults
|
||||
local suggested_template
|
||||
suggested_template=$(optional_xml_field "$xml_input" "suggested_template" "")
|
||||
|
||||
local confidence
|
||||
confidence=$(optional_xml_field "$xml_input" "confidence" "")
|
||||
|
||||
# Validate confidence is a number if provided
|
||||
if [ -n "$confidence" ] && ! [[ "$confidence" =~ ^[0-9]+$ ]]; then
|
||||
echo "Error: Invalid confidence value: $confidence (must be integer)" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Export for use by other functions
|
||||
export USER_TASK="$user_task"
|
||||
export SUGGESTED_TEMPLATE="$suggested_template"
|
||||
export SUGGESTED_CONFIDENCE="$confidence"
|
||||
}
|
||||
|
||||
# Convert text to lowercase
|
||||
to_lowercase() {
|
||||
echo "$1" | tr '[:upper:]' '[:lower:]'
|
||||
}
|
||||
|
||||
# Count keyword matches
|
||||
count_matches() {
|
||||
local text="$1"
|
||||
shift
|
||||
|
||||
local IFS='|'
|
||||
local pattern="$*"
|
||||
|
||||
echo "$text" | grep -oiE "\b($pattern)\b" 2>/dev/null | wc -l | tr -d ' '
|
||||
}
|
||||
|
||||
# Pre-compute strong indicators
|
||||
# Optimized to run grep once and check all patterns
|
||||
compute_strong_indicators() {
|
||||
local text="$1"
|
||||
|
||||
# Combine all patterns into a single grep call
|
||||
local all_matches
|
||||
all_matches=$(echo "$text" | grep -oiE "\b($PATTERN_CODE|$PATTERN_COMPARISON|$PATTERN_TEST|$PATTERN_REVIEW|$PATTERN_DOCUMENTATION|$PATTERN_EXTRACTION)\b" | tr '[:upper:]' '[:lower:]') || true
|
||||
|
||||
# Check which patterns matched
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_CODE)\b"; then
|
||||
HAS_STRONG_CODE=1
|
||||
else
|
||||
HAS_STRONG_CODE=0
|
||||
fi
|
||||
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_COMPARISON)\b"; then
|
||||
HAS_STRONG_COMPARISON=1
|
||||
else
|
||||
HAS_STRONG_COMPARISON=0
|
||||
fi
|
||||
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_TEST)\b"; then
|
||||
HAS_STRONG_TEST=1
|
||||
else
|
||||
HAS_STRONG_TEST=0
|
||||
fi
|
||||
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_REVIEW)\b"; then
|
||||
HAS_STRONG_REVIEW=1
|
||||
else
|
||||
HAS_STRONG_REVIEW=0
|
||||
fi
|
||||
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_DOCUMENTATION)\b"; then
|
||||
HAS_STRONG_DOCUMENTATION=1
|
||||
else
|
||||
HAS_STRONG_DOCUMENTATION=0
|
||||
fi
|
||||
|
||||
if echo "$all_matches" | grep -qiE "\b($PATTERN_EXTRACTION)\b"; then
|
||||
HAS_STRONG_EXTRACTION=1
|
||||
else
|
||||
HAS_STRONG_EXTRACTION=0
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if category has strong indicator
|
||||
has_strong_indicator() {
|
||||
local category="$1"
|
||||
|
||||
case "$category" in
|
||||
"code")
|
||||
return $((1 - HAS_STRONG_CODE))
|
||||
;;
|
||||
"comparison")
|
||||
return $((1 - HAS_STRONG_COMPARISON))
|
||||
;;
|
||||
"test")
|
||||
return $((1 - HAS_STRONG_TEST))
|
||||
;;
|
||||
"review")
|
||||
return $((1 - HAS_STRONG_REVIEW))
|
||||
;;
|
||||
"documentation")
|
||||
return $((1 - HAS_STRONG_DOCUMENTATION))
|
||||
;;
|
||||
"extraction")
|
||||
return $((1 - HAS_STRONG_EXTRACTION))
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Calculate confidence for a category
|
||||
calculate_confidence() {
|
||||
local category=$1
|
||||
local supporting_count=$2
|
||||
|
||||
if has_strong_indicator "$category"; then
|
||||
local confidence=$((STRONG_INDICATOR_BASE + supporting_count * SUPPORTING_KEYWORD_BONUS))
|
||||
[ "$confidence" -gt 100 ] && confidence=100
|
||||
echo "$confidence"
|
||||
else
|
||||
if [ "$supporting_count" -eq 0 ]; then
|
||||
echo 0
|
||||
elif [ "$supporting_count" -eq 1 ]; then
|
||||
echo "$ONE_KEYWORD_CONFIDENCE"
|
||||
elif [ "$supporting_count" -eq 2 ]; then
|
||||
echo "$TWO_KEYWORD_CONFIDENCE"
|
||||
else
|
||||
echo "$THREE_KEYWORD_CONFIDENCE"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Classify task and return template name with confidence
|
||||
classify_task() {
|
||||
local task_description="$1"
|
||||
local task_lower=$(to_lowercase "$task_description")
|
||||
|
||||
# Pre-compute strong indicators
|
||||
compute_strong_indicators "$task_lower"
|
||||
|
||||
# Define supporting keywords
|
||||
local code_keywords=("code" "file" "class" "bug" "module" "system" "endpoint")
|
||||
local comparison_keywords=("sentence" "equal" "whether" "mean" "version" "duplicate" "similarity")
|
||||
local test_keywords=("coverage" "jest" "pytest" "junit" "mocha" "case" "suite" "edge" "unit" "generate")
|
||||
local review_keywords=("readability" "maintainability" "practices" "smell")
|
||||
local documentation_keywords=("comment" "guide" "reference" "explain" "api" "write" "function" "inline" "author" "instructions" "setup" "method")
|
||||
local extraction_keywords=("data" "scrape" "retrieve" "json" "html" "csv" "email" "address" "timestamp" "logs" "file")
|
||||
|
||||
# Count matches
|
||||
local code_count=$(count_matches "$task_lower" "${code_keywords[@]}")
|
||||
local comparison_count=$(count_matches "$task_lower" "${comparison_keywords[@]}")
|
||||
local testgen_count=$(count_matches "$task_lower" "${test_keywords[@]}")
|
||||
local review_count=$(count_matches "$task_lower" "${review_keywords[@]}")
|
||||
local documentation_count=$(count_matches "$task_lower" "${documentation_keywords[@]}")
|
||||
local extraction_count=$(count_matches "$task_lower" "${extraction_keywords[@]}")
|
||||
|
||||
# Calculate confidence scores
|
||||
local code_confidence=$(calculate_confidence "code" $code_count)
|
||||
local comparison_confidence=$(calculate_confidence "comparison" $comparison_count)
|
||||
local test_confidence=$(calculate_confidence "test" $testgen_count)
|
||||
local review_confidence=$(calculate_confidence "review" $review_count)
|
||||
local documentation_confidence=$(calculate_confidence "documentation" $documentation_count)
|
||||
local extraction_confidence=$(calculate_confidence "extraction" $extraction_count)
|
||||
|
||||
# Find highest confidence
|
||||
local max_confidence=0
|
||||
local selected_template="custom"
|
||||
|
||||
if [ "$code_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$code_confidence
|
||||
selected_template="code-refactoring"
|
||||
fi
|
||||
|
||||
if [ "$comparison_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$comparison_confidence
|
||||
selected_template="code-comparison"
|
||||
fi
|
||||
|
||||
if [ "$test_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$test_confidence
|
||||
selected_template="test-generation"
|
||||
fi
|
||||
|
||||
if [ "$review_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$review_confidence
|
||||
selected_template="code-review"
|
||||
fi
|
||||
|
||||
if [ "$documentation_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$documentation_confidence
|
||||
selected_template="documentation-generator"
|
||||
fi
|
||||
|
||||
if [ "$extraction_confidence" -gt "$max_confidence" ]; then
|
||||
max_confidence=$extraction_confidence
|
||||
selected_template="data-extraction"
|
||||
fi
|
||||
|
||||
# Set to custom if below borderline threshold
|
||||
if [ "$max_confidence" -lt "$BORDERLINE_MIN" ]; then
|
||||
selected_template="custom"
|
||||
max_confidence=0
|
||||
fi
|
||||
|
||||
# Validate template file exists
|
||||
if [ "$selected_template" != "custom" ]; then
|
||||
local template_file="${TEMPLATE_DIR}/${selected_template}.md"
|
||||
if [ ! -f "$template_file" ]; then
|
||||
selected_template="custom"
|
||||
max_confidence=0
|
||||
fi
|
||||
fi
|
||||
|
||||
# Output: template_name confidence
|
||||
echo "$selected_template $max_confidence"
|
||||
}
|
||||
|
||||
# Determine scenario based on confidence level
|
||||
get_scenario() {
|
||||
local confidence=$1
|
||||
|
||||
if [ "$confidence" -ge 70 ]; then
|
||||
echo "high"
|
||||
elif [ "$confidence" -ge 60 ]; then
|
||||
echo "borderline"
|
||||
else
|
||||
echo "weak"
|
||||
fi
|
||||
}
|
||||
|
||||
# Generate instructions based on scenario
|
||||
generate_instructions() {
|
||||
# Run classification
|
||||
local result=$(classify_task "$USER_TASK")
|
||||
local template_name=$(echo "$result" | cut -d' ' -f1)
|
||||
local confidence=$(echo "$result" | cut -d' ' -f2)
|
||||
|
||||
# Sanitize for output
|
||||
local sanitized_task=$(sanitize_input "$USER_TASK")
|
||||
|
||||
# Determine scenario
|
||||
local scenario=$(get_scenario "$confidence")
|
||||
|
||||
# Generate comparison note if suggested template differs
|
||||
local comparison_note=""
|
||||
if [ -n "$SUGGESTED_TEMPLATE" ] && [ "$template_name" != "$SUGGESTED_TEMPLATE" ]; then
|
||||
comparison_note="
|
||||
Note: Classification selected '$template_name' instead of suggested '$SUGGESTED_TEMPLATE'"
|
||||
elif [ -n "$SUGGESTED_TEMPLATE" ]; then
|
||||
comparison_note="
|
||||
Note: Classification agrees with suggested template '$SUGGESTED_TEMPLATE'"
|
||||
fi
|
||||
|
||||
case "$scenario" in
|
||||
high)
|
||||
# High confidence (70%+): Accept classification directly
|
||||
cat <<EOF
|
||||
CLASSIFICATION RESULT:
|
||||
Template: $template_name
|
||||
Confidence: $confidence%$comparison_note
|
||||
|
||||
DECISION: High confidence classification - accept directly.
|
||||
|
||||
Output the following XML immediately:
|
||||
|
||||
\`\`\`xml
|
||||
<template_selector_result>
|
||||
<selected_template>$template_name</selected_template>
|
||||
<confidence>$confidence</confidence>
|
||||
<reasoning>Keyword-based classification has high confidence ($confidence%) based on pattern matching.</reasoning>
|
||||
</template_selector_result>
|
||||
\`\`\`
|
||||
EOF
|
||||
;;
|
||||
borderline)
|
||||
# Borderline confidence (60-69%): Validate the classification
|
||||
cat <<EOF
|
||||
CLASSIFICATION RESULT:
|
||||
Template: $template_name
|
||||
Confidence: $confidence% (borderline)$comparison_note
|
||||
|
||||
TASK: Validate if this classification is appropriate.
|
||||
|
||||
User task: $sanitized_task
|
||||
Classified template: $template_name
|
||||
|
||||
Process:
|
||||
1. Read the classified template file to understand its purpose:
|
||||
Read: ~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/templates/$template_name.md
|
||||
|
||||
2. Evaluate if the user task matches the template's use cases
|
||||
|
||||
3. Make your decision:
|
||||
- If it's a good match: Confirm the classification
|
||||
- If it's a poor match: Briefly evaluate 1-2 other likely templates and select the best one
|
||||
|
||||
Output your decision in this XML format:
|
||||
|
||||
\`\`\`xml
|
||||
<template_selector_result>
|
||||
<selected_template>template-name</selected_template>
|
||||
<confidence>final-confidence-percentage</confidence>
|
||||
<reasoning>1-2 sentence explanation</reasoning>
|
||||
</template_selector_result>
|
||||
\`\`\`
|
||||
EOF
|
||||
;;
|
||||
weak)
|
||||
# Weak/no confidence (<60%): Full evaluation
|
||||
cat <<EOF
|
||||
CLASSIFICATION RESULT:
|
||||
Template: $template_name
|
||||
Confidence: $confidence% (low)$comparison_note
|
||||
|
||||
TASK: Evaluate the task against all templates and select the best match.
|
||||
|
||||
User task: $sanitized_task
|
||||
Initial classification: $template_name (confidence: $confidence%)
|
||||
|
||||
Available templates:
|
||||
1. code-refactoring - Modify code, fix bugs, add features, refactor
|
||||
2. code-review - Security audits, quality analysis, code feedback
|
||||
3. test-generation - Create tests, test suites, edge cases
|
||||
4. documentation-generator - API docs, READMEs, docstrings, guides
|
||||
5. data-extraction - Extract/parse data from logs, JSON, HTML, text
|
||||
6. code-comparison - Compare code, check equivalence, classify similarities
|
||||
7. custom - Novel tasks that don't fit standard templates
|
||||
|
||||
Process:
|
||||
1. Consider the task type (development, analysis, generation, comparison, extraction)
|
||||
2. Read relevant template files (1-3 templates that might match) to understand their scope
|
||||
3. Select the best matching template or "custom" if none fit well
|
||||
|
||||
Output your decision in this XML format:
|
||||
|
||||
\`\`\`xml
|
||||
<template_selector_result>
|
||||
<selected_template>template-name</selected_template>
|
||||
<confidence>final-confidence-percentage</confidence>
|
||||
<reasoning>1-2 sentence explanation</reasoning>
|
||||
</template_selector_result>
|
||||
\`\`\`
|
||||
EOF
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Main function
|
||||
main() {
|
||||
# Check for command-line argument
|
||||
if [ $# -eq 0 ]; then
|
||||
echo "Error: No input provided. Usage: $0 '<xml-input>'" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Read and parse XML input from first argument
|
||||
read_xml_input "$1"
|
||||
|
||||
# Generate and output instructions
|
||||
generate_instructions
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
28
agents/template-executor.md
Normal file
28
agents/template-executor.md
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
name: template-executor
|
||||
description: Generic execution agent that loads template-specific skills and executes optimized prompts
|
||||
allowed-tools: [Glob, Grep, Read, Edit, Write, Bash, TodoWrite, AskUserQuestion, Skill, Read(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/skills/**), Bash(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/template-executor-handler.sh:*)]
|
||||
model: sonnet
|
||||
---
|
||||
|
||||
Load skill and execute the optimized prompt.
|
||||
|
||||
## Process
|
||||
|
||||
1. **Call handler** with your XML input:
|
||||
```bash
|
||||
~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/template-executor-handler.sh '<your-input-xml>'
|
||||
```
|
||||
|
||||
2. **Load skill** (if not "none"): `Skill tool: <skill-name>`
|
||||
|
||||
3. **Execute** the optimized prompt using specialized tools (Read/Edit/Write, not bash for files). Track progress with TodoWrite.
|
||||
|
||||
4. **Return XML**:
|
||||
```xml
|
||||
<template_executor_result>
|
||||
<status>completed|failed|partial</status>
|
||||
<summary>Brief summary of what was accomplished</summary>
|
||||
<details>Detailed results, changes made, files modified, etc.</details>
|
||||
</template_executor_result>
|
||||
```
|
||||
29
agents/template-selector.md
Normal file
29
agents/template-selector.md
Normal file
@@ -0,0 +1,29 @@
|
||||
---
|
||||
name: template-selector
|
||||
description: Lightweight template classifier for borderline and uncertain cases
|
||||
allowed-tools: [Read(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/templates/**), Bash(~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/template-selector-handler.sh:*)]
|
||||
model: haiku
|
||||
---
|
||||
|
||||
Classify user request to select the best template.
|
||||
|
||||
## Process
|
||||
|
||||
1. **Call handler** with your XML input:
|
||||
```bash
|
||||
~/.claude/plugins/marketplaces/claude-experiments/meta-prompt/agents/scripts/template-selector-handler.sh '<your-input-xml>'
|
||||
```
|
||||
|
||||
2. **Follow handler instructions** based on confidence:
|
||||
- ≥70%: Accept classification
|
||||
- 60-69%: Read template to validate
|
||||
- <60%: Read 1-3 templates to decide
|
||||
|
||||
3. **Return XML**:
|
||||
```xml
|
||||
<template_selector_result>
|
||||
<selected_template>template-name</selected_template>
|
||||
<confidence>confidence-percentage</confidence>
|
||||
<reasoning>1-2 sentence explanation</reasoning>
|
||||
</template_selector_result>
|
||||
```
|
||||
Reference in New Issue
Block a user