orchestrated-discussions/smarttools/discussion-moderator/config.yaml

166 lines
5.5 KiB
YAML

# discussion-moderator - Discussion facilitator and orchestrator
# Usage: cat discussion.md | discussion-moderator --templates-dir templates
name: discussion-moderator
description: Discussion facilitator and orchestrator
category: Discussion
meta:
display_name: AI-Moderator
alias: moderator
type: voting
expertise:
- Discussion facilitation
- Conflict resolution
- Summarization
- Progress tracking
concerns:
- "Is the discussion productive?"
- "Are all viewpoints represented?"
- "Are we ready to move forward?"
arguments:
- flag: --callout
variable: callout
default: ""
description: Specific question or @mention context
- flag: --templates-dir
variable: templates_dir
default: "templates"
description: Path to templates directory
- flag: --participants
variable: participants
default: "architect,security,pragmatist"
description: Comma-separated list of expected participants
- flag: --log-file
variable: log_file
default: ""
description: Path to log file for progress updates
steps:
# Step 1: Analyze discussion state and read template
- type: code
code: |
import re
import json
import os
from collections import Counter
# Extract metadata from discussion
phase_match = re.search(r'<!--\s*Phase:\s*(\w+)\s*-->', input, re.IGNORECASE)
template_match = re.search(r'<!--\s*Template:\s*(\w+)\s*-->', input, re.IGNORECASE)
current_phase = phase_match.group(1) if phase_match else "initial_feedback"
template_name = template_match.group(1) if template_match else "feature"
# Try to read template file for phase context
template_path = os.path.join(templates_dir, template_name + ".yaml")
phase_goal = "Facilitate the discussion"
phase_instructions = "Guide participants through the discussion."
next_phase = None
if os.path.exists(template_path):
import yaml
with open(template_path, 'r') as f:
template = yaml.safe_load(f)
phases = template.get("phases", {})
phase_info = phases.get(current_phase, {})
phase_goal = phase_info.get("goal", phase_goal)
phase_instructions = phase_info.get("instructions", phase_instructions)
next_phase = phase_info.get("next_phase", None)
phase_context = "Current Phase: " + current_phase + "\n\n"
phase_context += "Phase Goal: " + phase_goal + "\n\n"
phase_context += "Phase Instructions:\n" + phase_instructions
if next_phase:
phase_context += "\n\nNext Phase: " + next_phase
# Extract votes
votes = {}
for match in re.finditer(r'Name:\s*(.+?)\n.*?VOTE:\s*(READY|CHANGES|REJECT)', input, re.DOTALL | re.IGNORECASE):
author = match.group(1).strip()
vote = match.group(2).upper()
votes[author] = vote
vote_counts = Counter(votes.values())
# Extract mentions
mentions = set(re.findall(r'@(\w+)', input))
# Get responders
responders = set()
for match in re.finditer(r'^Name:\s*(.+?)$', input, re.MULTILINE):
responders.add(match.group(1).strip().lower().replace("ai-", ""))
# Expected participants (explicit loop to avoid exec() scope issues)
expected = set()
for p in participants.split(','):
expected.add(p.strip())
pending = expected - responders
# Questions and concerns (explicit loops to avoid exec() scope issues)
questions = []
for m in re.finditer(r'^(?:Q|QUESTION):\s*(.+)$', input, re.MULTILINE | re.IGNORECASE):
questions.append(m.group(1))
concerns = []
for m in re.finditer(r'^CONCERN:\s*(.+)$', input, re.MULTILINE | re.IGNORECASE):
concerns.append(m.group(1))
analysis = json.dumps({
"votes": votes,
"vote_counts": dict(vote_counts),
"total_votes": sum(vote_counts.values()),
"pending_participants": list(pending),
"all_responded": len(pending) == 0,
"open_questions": questions,
"concerns": concerns,
"current_phase": current_phase,
"next_phase": next_phase
})
output_var: analysis, phase_context
# Step 2: Generate moderation response
- type: prompt
prompt: |
You are AI-Moderator, responsible for keeping discussions productive and on-track.
## Your Role
- Summarize the current state of the discussion
- Identify who still needs to respond
- Note open questions and concerns
- Suggest next steps
- Determine if the discussion should advance to the next phase
## Phase Context
{phase_context}
## Discussion Analysis
{analysis}
## Full Discussion
{input}
Based on this analysis:
1. Summarize what has been discussed so far
2. List who still needs to respond (use @mentions)
3. Highlight any unresolved questions or concerns
4. Recommend whether to advance to the next phase based on the phase instructions
## Response Format
Respond with valid JSON only:
{{
"comment": "Your moderation comment in markdown. Use @mentions for pending participants.",
"vote": null,
"advance_phase": true or false,
"pending_participants": ["list", "of", "aliases"]
}}
As moderator, you typically don't vote (vote: null). Your role is to facilitate.
If there's nothing to moderate yet, respond: {{"sentinel": "NO_RESPONSE"}}
provider: claude-sonnet
output_var: response
output: "{response}"