Compiles the system instruction for an LLM agent by combining:
- Global instruction (from agent or parent)
- Agent's own instruction (with template variable substitution from state)
- Identity/persona instruction
- Output schema instruction
- Transfer instructions (listing available sub-agents)
This mirrors Python ADK's BaseLlmFlow._compile_system_instruction().
InstructionProvider
Both the instruction and global_instruction fields on ADK.Agent.LlmAgent
support dynamic providers in addition to static strings:
String.t()— static instruction (existing behaviour, unchanged)(ADK.Context.t() -> String.t())— 1-arity anonymous function called at runtime{module, atom}— MFA with 1 arg (context appended):module.atom(ctx){module, atom, extra_args}— MFA with extra args (context prepended):module.atom(ctx, extra_args...)
The provider is called once per invocation, just before template-variable
substitution, so the returned string still supports {variable} interpolation.
If a provider returns a non-binary value, it is coerced via to_string/1.
If the provider raises, the error is logged and an empty string is used so
the agent can still respond.
Summary
Functions
Compile the full system instruction for an agent given the context.
Split compiled instructions into static and dynamic portions.
Resolve an instruction provider to a string.
Substitute template variables in an instruction string.
Functions
@spec compile(map(), ADK.Context.t()) :: String.t()
Compile the full system instruction for an agent given the context.
Returns a single string combining all instruction components.
@spec compile_split(map(), ADK.Context.t()) :: {String.t(), String.t()}
Split compiled instructions into static and dynamic portions.
- Static: Parts that don't change between requests — global instruction, identity, transfer instructions. Suitable for Gemini's context caching.
- Dynamic: Parts that change per request — agent instruction with state variable substitution, output schema instruction.
Returns {static_instruction, dynamic_instruction} where either may be an
empty string (but never nil).
@spec resolve_provider(term(), ADK.Context.t() | nil) :: String.t() | nil
Resolve an instruction provider to a string.
Handles:
String.t()— returned as-is(ctx -> String.t())— called with the context (may be nil for global){module, atom}— called asmodule.atom(ctx){module, atom, extra_args}— called asmodule.atom(ctx, extra_args...)
Non-binary return values are coerced via to_string/1. Errors are caught
and an empty string is returned (with a warning logged).
Substitute template variables in an instruction string.
Variables use the {key} syntax. Values are looked up from session state.
Examples
iex> ADK.InstructionCompiler.substitute_vars("Hello {name}!", %{"name" => "World"})
"Hello World!"
iex> ADK.InstructionCompiler.substitute_vars("No vars here", %{})
"No vars here"