Pudu programming language
Menu
Package

@chrismichaelps / pudu-lang-mcp

Model Context Protocol server for Pudu language documentation and compiler tools

0.1.1Apache-2.01

InstallClose

Prompts.pudu

Pudu86 lines5.5 KB

GitHub ↗
1/** @Domain.Catalog.Prompts.Registry — prompt templates and their rendering */2module PuduLangMcp.Domain.Catalog.Prompts34import Std.Json as Json5import Std.List as List6import Std.Text as Text7import PuduLangMcp.Errors.RpcError as RpcError8import PuduLangMcp.Utils.JsonAccess as Access910/** @Domain.Catalog.Prompts.PromptArgument — one named prompt input */11export type PromptArgument = { name: Str, description: Str, required: Bool }1213/** @Domain.Catalog.Prompts.PromptSpec — one prompt described once */14export type PromptSpec = { name: Str, title: Str, description: Str, arguments: Array[PromptArgument] }1516/// Language rules and the verification workflow, appended to every prompt.17export const CONVENTIONS: Str = "Pudu rules that are easy to get wrong:\n- A brace inside a string literal starts interpolation: \"\{name\}\" inserts name. Write \\\{ and \\\} for literal braces.\n- Option and Result helpers are module functions: Option.unwrapOr(value, fallback), never value.unwrapOr(fallback).\n- items.get(i) answers the element and stops the program when i is out of range; List.get(&items, i) answers an Option.\n- Module scope holds only const. Lookup tables are const tables built with mapOf([...]) or setOf([...]).\n- scope, module, and where are keywords and cannot name bindings or fields.\n- Every import is qualified and aliased: import Std.Json as Json.\n\nBefore answering with Pudu code, check it with pudu_check, format it with pudu_format, and lint it with pudu_lint. Look up library functions with pudu_reference_search and pudu_module_reference rather than guessing their names."1819/// Every prompt, in listing order.20export fn all() -> Array[PromptSpec] {21  [22    PromptSpec{name: "pudu_write_code", title: "Write Pudu code", description: "Write Pudu code for a task, following the language's conventions and verifying it with the compiler.", arguments: [23        PromptArgument{name: "task", description: "What the code should do.", required: true}24      ] },25    PromptSpec{name: "pudu_fix_diagnostics", title: "Fix Pudu diagnostics", description: "Fix the compiler diagnostics in a piece of Pudu code.", arguments: [26        PromptArgument{name: "source", description: "The Pudu code.", required: true},27        PromptArgument{name: "diagnostics", description: "The diagnostics to fix; pudu_check answers them when omitted.", required: false}28      ] },29    PromptSpec{name: "pudu_review", title: "Review Pudu code", description: "Review Pudu code for correctness, idiom, and failure handling.", arguments: [30        PromptArgument{name: "source", description: "The Pudu code to review.", required: true}31      ] },32    PromptSpec{name: "pudu_explain", title: "Explain a Pudu topic", description: "Explain a Pudu language topic from its documentation, with an example that compiles.", arguments: [33        PromptArgument{name: "topic", description: "The topic, such as 'ownership' or 'traits'.", required: true}34      ] }35  ]36}3738/// A prompt as `prompts/list` describes it.39export fn toJson(spec: &PromptSpec) -> Json.Json {40  Json.object(&[41      ("name", Json.Text(spec.name)),42      ("title", Json.Text(spec.title)),43      ("description", Json.Text(spec.description)),44      ("arguments", Json.list(&spec.arguments.map(|held: PromptArgument| Json.object(&[45                ("name", Json.Text(held.name)),46                ("description", Json.Text(held.description)),47                ("required", Json.Boolean(held.required))48              ]))))49    ])50}5152/// A prompt's description and user message, or why its arguments are refused.53export fn render(name: Str, arguments: &Json.Json) -> Result[(Str, Str), RpcError.ProtocolError] {54  let spec = match List.find(&all(), |held: PromptSpec| held.name == name) {55    case Some(found) => found56    case None => { return Err(RpcError.InvalidParams("unknown prompt: " + name)) }57  }58  var values: Array[(Str, Str)] = []59  for held in spec.arguments {60    match Access.member(arguments, held.name) {61      case Some(Json.Text(text)) => {62        if held.required && Text.isBlank(text) { return Err(RpcError.InvalidParams("prompt argument '" + held.name + "' must not be empty")) }63        values = values.push((held.name, text))64      }65      case Some(_) => { return Err(RpcError.InvalidParams("prompt argument '" + held.name + "' must be a string")) }66      case None => {67        if held.required { return Err(RpcError.InvalidParams("missing prompt argument '" + held.name + "'")) }68        values = values.push((held.name, ""))69      }70    }71  }72  let value = |key: Str| match List.lookup(&values, key) { case Some(text) => text case None => "" }73  let body = if name == "pudu_write_code" {74    "Write Pudu code for this task:\n\n" + value("task") + "\n\nSearch the documentation with pudu_docs_search when a construct is unfamiliar."75  } else if name == "pudu_fix_diagnostics" {76    let given = value("diagnostics")77    let reported = if given.isEmpty() { "Run pudu_check on it to get the diagnostics." } else { "The diagnostics are:\n\n```\n" + given + "\n```" }78    "Fix this Pudu code so it compiles without diagnostics:\n\n```pudu\n" + value("source") + "\n```\n\n" + reported + "\n\nExplain each change in one sentence."79  } else if name == "pudu_review" {80    "Review this Pudu code. Report correctness problems first, then failure handling (Result and Option use), then idiom, each with the line and a concrete change:\n\n```pudu\n" + value("source") + "\n```"81  } else {82    "Explain the Pudu topic '" + value("topic") + "'. Read the relevant documentation with pudu_docs_search and pudu_docs_read first, and end with a short example checked with pudu_check."83  }84  Ok((spec.description, body + "\n\n" + CONVENTIONS))85}86