Flexibles KI Prompt System #48
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user