speckl/examples/PromptOptimizer.speckdl
Scott Scoble 02a61f1d33 feat: add PromptOptimizer spec and functional runtime
PromptOptimizer.speckdl: state machine spec for prompt optimization pipeline
(Idle → Analyzing → Rewriting → Compressing → Validating → Done)
Compiles clean with tsc --noEmit.

PromptOptimizer-runtime.ts: functional TypeScript runtime that actually
optimizes LLM prompts:
- Token counting (approximate, GPT-4 style ~4 chars/token)
- Section extraction (role, instruction, constraint, format, context, example, tone)
- Redundancy detection (duplicate phrases/sentences)
- Vague instruction detection (hedging, filler words)
- Constraint counting and quality scoring
- 4 optimization strategies:
  - reorder: prioritize constraints and role before instructions
  - deduplicate: remove repeated sentences
  - concretize: replace vague phrases with specific alternatives
  - decompose: add numbered steps to imperative instructions
- Compression pipeline: deduplicate → filler removal → section pruning
- Validation: keyword preservation, structural integrity, token reduction
- Agent integration: can load and optimize SOUL.md/AGENTS.md files

Demo shows 8% reduction on SOUL.md, 5% on AGENTS.md (both already
well-structured). Higher gains on verbose prompts (13-30% reduction).
2026-05-13 21:14:55 -07:00

160 lines
No EOL
4.4 KiB
Text

// PromptOptimizer.speckdl — State machine spec for LLM prompt optimization
// Phases: Idle → Analyzing → Rewriting → Compressing → Validating → Done
// The runtime (PromptOptimizer-runtime.ts) implements the actual optimization logic.
speck PromptOptimizer {
version: "0.1.0"
author: "sscoble"
license: "MIT"
// ─── State ────────────────────────────────────────────────
state: {
phase: OptimizerPhase,
originalPrompt: String,
optimizedPrompt: String,
analysis: PromptAnalysis,
strategiesApplied: StringList,
rewriteCount: Nat,
originalTokens: Nat,
optimizedTokens: Nat,
tokenReduction: Nat,
confidence: Nat,
issues: StringList,
errors: StringList
}
init: {
phase := Idle,
originalPrompt := "",
optimizedPrompt := "",
analysis := null,
strategiesApplied := [],
rewriteCount := 0,
originalTokens := 0,
optimizedTokens := 0,
tokenReduction := 0,
confidence := 0,
issues := [],
errors := []
}
// ─── Events ───────────────────────────────────────────────
event PromptSubmitted {
prompt: String,
context: String,
model: String
}
event AnalysisComplete {
tokenCount: Nat,
redundancyScore: Nat,
structureScore: Nat,
constraintCount: Nat,
instructionCount: Nat,
issues: StringList
}
event RewriteApplied {
strategy: String,
beforeTokens: Nat,
afterTokens: Nat
}
event CompressionComplete {
originalTokens: Nat,
compressedTokens: Nat,
reduction: Nat
}
event ValidationComplete {
criteria: String,
confidence: Nat,
passed: Bool
}
event OptimizationFailed {
phase: OptimizerPhase,
message: String
}
// ─── Actions ──────────────────────────────────────────────
// Submit a prompt for optimization
action submit(prompt: String, context: String, model: String) {
require phase === Idle
require len(prompt) > 0
this.phase := Analyzing
this.originalPrompt := prompt
this.errors := []
emit PromptSubmitted { prompt: prompt, context: context, model: model }
}
// Apply a rewrite strategy
action rewrite(strategy: String) {
require phase === Analyzing || phase === Validating
this.phase := Rewriting
this.rewriteCount := rewriteCount + 1
emit RewriteApplied { strategy: strategy, beforeTokens: originalTokens, afterTokens: 0 }
}
// Compress the prompt
action compress(targetTokens: Nat) {
require phase === Rewriting
this.phase := Compressing
emit CompressionComplete { originalTokens: originalTokens, compressedTokens: 0, reduction: 0 }
}
// Validate the optimized prompt
action validate(criteria: String) {
require phase === Rewriting || phase === Compressing
this.phase := Validating
emit ValidationComplete { criteria: criteria, confidence: 0, passed: true }
}
// Accept the result
action complete() {
require phase === Validating
this.phase := Done
}
// Start over
action reset() {
this.phase := Idle
this.originalPrompt := ""
this.optimizedPrompt := ""
this.rewriteCount := 0
}
// ─── Interface ────────────────────────────────────────────
interface OptimizerPhase {
Idle
Analyzing
Rewriting
Compressing
Validating
Done
Failed
}
// ─── Constraints ───────────────────────────────────────────
constraint mustPreserveIntent: "Optimized prompt must preserve the original intent"
constraint mustReduceOrMaintain: "Optimized prompt must have equal or fewer tokens"
constraint noInfiniteRewrite: "Maximum 3 rewrite cycles before forcing Done"
// ─── Verification ──────────────────────────────────────────
verify eventuallyDone: "Every optimization request must eventually reach Done or Failed"
verify analyzingPrecedesRewriting: "Rewriting must be preceded by Analyzing"
}