PtcRunner.SubAgent.SystemPrompt (PtcRunner v0.5.1)
View SourceSystem prompt generation for SubAgent LLM interactions.
Orchestrates prompt generation by combining sections from:
Namespacemodules - Compact Lisp-style format for tools and dataSystemPrompt.Output- Expected return format from signature
Prompt Caching Architecture
To enable efficient prompt caching (e.g., Anthropic's cache_control), the prompt is split into static and dynamic sections:
- Static (system prompt):
generate_system/2returns language reference and output format - these rarely change and benefit from caching across different questions. - Dynamic (user message):
generate_context/2returns data inventory, tool schemas, and expected output - these vary per agent configuration but not per question.
The mission is placed only in the user message (not duplicated in system prompt).
Customization
The system_prompt field on SubAgent accepts:
- Map -
:prefix,:suffix,:language_spec,:output_format - Function -
fn default_prompt -> modified_prompt end - String - Complete override
Language Spec
The :language_spec option can be:
- Atom - Resolved via
PtcRunner.Lisp.LanguageSpec.get!/1 - String - Used as-is
- Callback -
fn ctx -> "prompt" end
Default: :single_shot for max_turns: 1, :multi_turn otherwise.
Examples
iex> agent = PtcRunner.SubAgent.new(prompt: "Add {{x}} and {{y}}")
iex> context = %{x: 5, y: 3}
iex> prompt = PtcRunner.SubAgent.SystemPrompt.generate(agent, context: context)
iex> prompt =~ "## Role"
true
iex> prompt =~ "data/x"
true
Summary
Functions
Apply system prompt customization (string override, function, or map with prefix/suffix).
Generate a complete system prompt for a SubAgent.
Generate dynamic context sections (prepended to user message).
Generate error recovery prompt for parse failures.
Alias for generate_system/2 for semantic clarity.
Generate static system prompt sections (cacheable).
Resolve a language_spec value to a string.
Truncate prompt if it exceeds the configured character limit.
Functions
@spec apply_customization(String.t(), PtcRunner.SubAgent.system_prompt_opts() | nil) :: String.t()
Apply system prompt customization (string override, function, or map with prefix/suffix).
Examples
iex> PtcRunner.SubAgent.SystemPrompt.apply_customization("base", nil)
"base"
iex> PtcRunner.SubAgent.SystemPrompt.apply_customization("base", "override")
"override"
iex> PtcRunner.SubAgent.SystemPrompt.apply_customization("base", fn p -> "PREFIX\n" <> p end)
"PREFIX\nbase"
@spec generate( PtcRunner.SubAgent.t(), keyword() ) :: String.t()
Generate a complete system prompt for a SubAgent.
Options: context (map), error_context (map for recovery prompts).
Examples
iex> agent = PtcRunner.SubAgent.new(prompt: "Process data")
iex> prompt = PtcRunner.SubAgent.SystemPrompt.generate(agent, context: %{user: "Alice"})
iex> prompt =~ "## Role" and prompt =~ "thinking:"
true
@spec generate_context( PtcRunner.SubAgent.t(), keyword() ) :: String.t()
Generate dynamic context sections (prepended to user message).
Returns data inventory, tool schemas, and expected output - these sections vary per agent configuration but not per individual question.
Note: The mission is NOT included here - it's already in the user message.
Options
:context- Map of context variables for the data inventory:received_field_descriptions- Field descriptions from upstream agent
Examples
iex> agent = PtcRunner.SubAgent.new(prompt: "Test", tools: %{"search" => fn _ -> [] end})
iex> context_prompt = PtcRunner.SubAgent.SystemPrompt.generate_context(agent, context: %{x: 1})
iex> context_prompt =~ ";; === data/ ===" and context_prompt =~ ";; === tools ==="
true
iex> context_prompt =~ "# Mission"
false
Generate error recovery prompt for parse failures.
Examples
iex> error = %{type: :parse_error, message: "Unexpected token"}
iex> PtcRunner.SubAgent.SystemPrompt.generate_error_recovery_prompt(error) =~ "Previous Turn Error"
true
@spec generate_static( PtcRunner.SubAgent.t(), keyword() ) :: String.t()
Alias for generate_system/2 for semantic clarity.
See generate_system/2 for documentation.
@spec generate_system( PtcRunner.SubAgent.t(), keyword() ) :: String.t()
Generate static system prompt sections (cacheable).
Returns only the language reference and output format - these sections rarely change across different questions and benefit from prompt caching.
This function has an alias generate_static/2 for semantic clarity.
Options
:resolution_context- Map with turn/model/memory/messages for language_spec callbacks
Examples
iex> agent = PtcRunner.SubAgent.new(prompt: "Test")
iex> system = PtcRunner.SubAgent.SystemPrompt.generate_system(agent)
iex> system =~ "## Role" and system =~ "# Output Format"
true
iex> system =~ "# Data Inventory"
false
Resolve a language_spec value to a string.
Examples
iex> PtcRunner.SubAgent.SystemPrompt.resolve_language_spec("custom prompt", %{})
"custom prompt"
iex> spec = PtcRunner.SubAgent.SystemPrompt.resolve_language_spec(:single_shot, %{})
iex> is_binary(spec) and String.contains?(spec, "PTC-Lisp")
true
iex> callback = fn ctx -> if ctx.turn > 1, do: "multi", else: "single" end
iex> PtcRunner.SubAgent.SystemPrompt.resolve_language_spec(callback, %{turn: 1})
"single"
Truncate prompt if it exceeds the configured character limit.
Examples
iex> PtcRunner.SubAgent.SystemPrompt.truncate_if_needed("short", nil)
"short"
iex> result = PtcRunner.SubAgent.SystemPrompt.truncate_if_needed(String.duplicate("x", 1000), %{max_chars: 100})
iex> result =~ "truncated"
true