Repository navigation
Description
π― Affected Service(s)
App Service (Go ADK runtime β go/adk/pkg/models)
π¦ Impact/Severity
Blocker β the agent's entire system prompt is silently discarded.
π Bug Description
When a declarative Agent runs on the Go runtime (spec.declarative.runtime: go) with a Bedrock or Ollama model, the agent's system prompt (spec.declarative.systemMessage, rendered into config.json as instruction) is never sent to the model. The agent behaves as if it had no system prompt: instructions, grounding constraints, and output-format contracts are all lost.
The controller renders the prompt correctly (it appears verbatim as instruction in the pod's /config/config.json), and the Go ADK wires it into llmagent.Config.Instruction β but the Bedrock and Ollama model adapters drop it when building the provider request. The OpenAI, Anthropic, and SAP AI Core adapters are unaffected.
Root cause: the Google ADK delivers the agent instruction via req.Config.SystemInstruction, but bedrock.go and ollama_adk.go extract the system prompt only from a role-"system" message in req.Contents β a shape the ADK runtime never produces.
π Steps To Reproduce
- Create a
ModelConfigwithprovider: Bedrock(any model, e.g.anthropic.claude-3-haikuorqwen.qwen3-32b-v1:0). - Create a declarative
Agentwithruntime: gousing thatModelConfigand a distinctivesystemMessage, e.g.:spec: declarative: runtime: go modelConfig: my-bedrock-model systemMessage: "You are a test agent. Begin EVERY reply with the exact token ZEBRA9."
- Send any message to the agent (A2A
message/send, or the UI). - Observe the reply does not begin with
ZEBRA9. Confirmkubectl exec <pod> -- cat /config/config.jsonshows theinstructionfield is populated β i.e. the controller did its job; the model adapter dropped it. - Switch the same agent to
runtime: pythonβ the prompt is honored (_bedrock.py/_ollama.pyreadconfig.system_instruction).
π€ Expected Behavior
The Go-runtime Bedrock/Ollama adapters send the agent's systemMessage to the model (as the Converse system field for Bedrock, and the leading system message for Ollama), matching the Python runtime and the Go OpenAI/Anthropic/SAPAICore adapters.
π± Actual Behavior
The system prompt is silently discarded; the model is called with no system instruction. Grounding rules and output-format contracts are lost with no error.
π» Environment
- Application version: present in every 0.9.x release (verified
v0.9.9andv0.9.10); Go ADK depgoogle.golang.org/adk v1.4.0. - Affected runtime:
runtime: go. Affected providers: Bedrock, Ollama. Unaffected: OpenAI, Anthropic, SAP AI Core (all runtimes), and all providers onruntime: python.
π Additional Context β Root cause analysis
1. The ADK delivers the instruction via Config.SystemInstruction, not via Contents.
llmagent passes Instruction into the flow, and internal/llminternal/instruction_processor.go β internal/utils/utils.go#AppendInstructions writes it to req.Config.SystemInstruction (a *genai.Content). It is never appended to req.Contents as a role-"system" entry.
2. Bedrock reads the wrong place. go/adk/pkg/models/bedrock.go:
GenerateContentderives the system prompt solely fromconvertGenaiContentsToBedrockMessages(req.Contents, nameMap)βreq.Config(which holdsSystemInstruction) is not even passed in.- Inside that function the system text is only set when
content.Role == "system":if part.Text != "" { if content.Role == "system" { // <-- ADK never emits this role systemInstruction = part.Text continue } ... }
- Result:
systemInstruction == ""β the ConverseSystemfield is empty.
3. Ollama has the identical omission (go/adk/pkg/models/ollama_adk.go): convertGenaiContentsToOllamaMessages(req.Contents) only sets the system prompt from content.Role == "system", and req.Config.SystemInstruction is never read.
4. The working adapters show the correct pattern β they read config.SystemInstruction.Parts:
anthropic_adk.go(genaiContentsToAnthropicMessages(contents, config)),openai_adk.go,sapaicore_adk.go.
5. Why it survived multiple releases (no CI catch). go/adk/pkg/models/bedrock_test.go ("system instruction extracted") feeds the prompt as a {Role:"system"} entry in contents β the exact shape the live ADK flow never produces β and asserts it's extracted, so the test passes while production is broken. No Bedrock/Ollama test sets req.Config.SystemInstruction.
6. Origin. Introduced when the Bedrock and Ollama Go adapters were first added in commit 93471472 (PR #1650, "feat(go-adk): enhance model config and provider support") β both were written reading Contents[role==system], while the sibling anthropic_adk.go in the same tree already read config.SystemInstruction. So this has never worked on the Go runtime for these two providers; it is not a regression.
π οΈ Suggested Fix
Read req.Config.SystemInstruction in both adapters (mirroring anthropic_adk.go). Minimal, additive patches:
go/adk/pkg/models/bedrock.go β in GenerateContent, right after the convertGenaiContentsToBedrockMessages call (strings is already imported):
messages, systemInstruction := convertGenaiContentsToBedrockMessages(req.Contents, nameMap)
// The Google ADK delivers the agent Instruction via Config.SystemInstruction,
// not as a role-"system" message in Contents. Merge it in (cf. anthropic_adk.go).
if req.Config != nil && req.Config.SystemInstruction != nil {
var b strings.Builder
b.WriteString(systemInstruction)
for _, p := range req.Config.SystemInstruction.Parts {
if p != nil && p.Text != "" {
if b.Len() > 0 {
b.WriteByte('\n')
}
b.WriteString(p.Text)
}
}
systemInstruction = b.String()
}go/adk/pkg/models/ollama_adk.go β in GenerateContent, right after the convertGenaiContentsToOllamaMessages call:
messages, systemInstruction := convertGenaiContentsToOllamaMessages(req.Contents)
// Google ADK delivers the agent Instruction via Config.SystemInstruction, not a
// role-"system" Content. Merge it in (cf. anthropic_adk.go / openai_adk.go).
if req.Config != nil && req.Config.SystemInstruction != nil {
for _, p := range req.Config.SystemInstruction.Parts {
if p != nil && p.Text != "" {
if systemInstruction != "" {
systemInstruction += "\n"
}
systemInstruction += p.Text
}
}
}Regression test: add a case to bedrock_test.go / ollama_test.go that sets req.Config.SystemInstruction (instead of a role-"system" Content) and asserts the system prompt reaches the provider request β the current tests exercise a code path the runtime never hits.
π Are you willing to contribute?
Happy to open a PR with the two patches above plus the regression tests if that's welcome.
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsBacklog
Activity
fix(go-adk): extract system prompt from genai.GenerateContentConfig iβ¦