Flexibles KI Prompt System #48

Merged
Lars merged 56 commits from develop into main 2026-03-26 14:49:48 +01:00
3 changed files with 51 additions and 15 deletions
Showing only changes of commit 4a2bebe249 - Show all commits

View File

@ -50,17 +50,24 @@ def resolve_placeholders(template: str, variables: Dict[str, Any], debug_info: O
resolved_value = str(value) resolved_value = str(value)
# Apply modifiers # Apply modifiers
if 'd' in modifiers and catalog: if 'd' in modifiers:
# Add description from catalog if catalog:
description = None # Add description from catalog
for cat_items in catalog.values(): description = None
matching = [item for item in cat_items if item['key'] == key] for cat_items in catalog.values():
if matching: matching = [item for item in cat_items if item['key'] == key]
description = matching[0].get('description', '') if matching:
break description = matching[0].get('description', '')
break
if description: if description:
resolved_value = f"{resolved_value} ({description})" resolved_value = f"{resolved_value} ({description})"
else:
# Catalog not available - log warning in debug
if debug_info is not None:
if 'warnings' not in debug_info:
debug_info['warnings'] = []
debug_info['warnings'].append(f"Modifier |d used but catalog not available for {key}")
# Track resolution for debug # Track resolution for debug
if debug_info is not None: if debug_info is not None:
@ -407,9 +414,11 @@ async def execute_prompt_with_data(
# Load placeholder catalog for |d modifier support # Load placeholder catalog for |d modifier support
try: try:
catalog = get_placeholder_catalog(profile_id) catalog = get_placeholder_catalog(profile_id)
variables['_catalog'] = catalog # Will be popped in execute_prompt except Exception as e:
except Exception:
catalog = None catalog = None
print(f"Warning: Could not load placeholder catalog: {e}")
variables['_catalog'] = catalog # Will be popped in execute_prompt (can be None)
# Add PROCESSED placeholders (name, weight_trend, caliper_summary, etc.) # Add PROCESSED placeholders (name, weight_trend, caliper_summary, etc.)
# This makes old-style prompts work with the new executor # This makes old-style prompts work with the new executor

View File

@ -786,13 +786,14 @@ async def execute_unified_prompt(
} }
# Execute with prompt_executor # Execute with prompt_executor
# Always enable debug when saving to collect metadata for value table
result = await execute_prompt_with_data( result = await execute_prompt_with_data(
prompt_slug=prompt_slug, prompt_slug=prompt_slug,
profile_id=profile_id, profile_id=profile_id,
modules=modules, modules=modules,
timeframes=timeframes, timeframes=timeframes,
openrouter_call_func=call_openrouter, openrouter_call_func=call_openrouter,
enable_debug=debug enable_debug=debug or save # Enable debug if saving for metadata collection
) )
# Save to ai_insights if requested # Save to ai_insights if requested

View File

@ -41,6 +41,7 @@ export default function UnifiedPromptModal({ prompt, onSave, onClose }) {
const [pickerTarget, setPickerTarget] = useState(null) // 'base' or {stage, promptIdx} const [pickerTarget, setPickerTarget] = useState(null) // 'base' or {stage, promptIdx}
const [cursorPosition, setCursorPosition] = useState(null) // Track cursor position for insertion const [cursorPosition, setCursorPosition] = useState(null) // Track cursor position for insertion
const baseTemplateRef = useRef(null) const baseTemplateRef = useRef(null)
const stageTemplateRefs = useRef({}) // Map of stage_promptIdx -> ref
// Test functionality // Test functionality
const [testing, setTesting] = useState(false) const [testing, setTesting] = useState(false)
@ -657,9 +658,18 @@ export default function UnifiedPromptModal({ prompt, onSave, onClose }) {
) : ( ) : (
<div> <div>
<textarea <textarea
ref={el => stageTemplateRefs.current[`${stage.stage}_${pIdx}`] = el}
className="form-input" className="form-input"
value={p.template || ''} value={p.template || ''}
onChange={e => updateStagePrompt(stage.stage, pIdx, 'template', e.target.value)} onChange={e => updateStagePrompt(stage.stage, pIdx, 'template', e.target.value)}
onClick={e => {
setCursorPosition(e.target.selectionStart)
setPickerTarget({ stage: stage.stage, promptIdx: pIdx })
}}
onKeyUp={e => {
setCursorPosition(e.target.selectionStart)
setPickerTarget({ stage: stage.stage, promptIdx: pIdx })
}}
rows={3} rows={3}
placeholder="Inline-Template mit {{placeholders}}..." placeholder="Inline-Template mit {{placeholders}}..."
style={{ width: '100%', fontSize: 12, textAlign: 'left', resize: 'vertical', fontFamily: 'monospace' }} style={{ width: '100%', fontSize: 12, textAlign: 'left', resize: 'vertical', fontFamily: 'monospace' }}
@ -819,16 +829,32 @@ export default function UnifiedPromptModal({ prompt, onSave, onClose }) {
} }
}, 0) }, 0)
} else if (pickerTarget && typeof pickerTarget === 'object') { } else if (pickerTarget && typeof pickerTarget === 'object') {
// Insert into pipeline stage template (append at end for now) // Insert into pipeline stage template at cursor position
const { stage: stageNum, promptIdx } = pickerTarget const { stage: stageNum, promptIdx } = pickerTarget
setStages(stages.map(s => { setStages(stages.map(s => {
if (s.stage === stageNum) { if (s.stage === stageNum) {
const newPrompts = [...s.prompts] const newPrompts = [...s.prompts]
const currentTemplate = newPrompts[promptIdx].template || '' const currentTemplate = newPrompts[promptIdx].template || ''
const pos = cursorPosition ?? currentTemplate.length
const newTemplate = currentTemplate.slice(0, pos) + placeholder + currentTemplate.slice(pos)
newPrompts[promptIdx] = { newPrompts[promptIdx] = {
...newPrompts[promptIdx], ...newPrompts[promptIdx],
template: currentTemplate + placeholder template: newTemplate
} }
// Restore focus and cursor position
setTimeout(() => {
const refKey = `${stageNum}_${promptIdx}`
const textarea = stageTemplateRefs.current[refKey]
if (textarea) {
textarea.focus()
const newPos = pos + placeholder.length
textarea.setSelectionRange(newPos, newPos)
setCursorPosition(newPos)
}
}, 0)
return { ...s, prompts: newPrompts } return { ...s, prompts: newPrompts }
} }
return s return s