feat: live-validated against Ollama Cloud; schema instruction fallback for cloud

Phase 8: all six live checks pass (tier aliases, thinking-tier chat, real
tool invocation, structured Generate[T], forced failover with bench+skip,
skill agent). Discovery: ollama.com ignores the format field — the
provider now also states the schema as a system instruction (constrained
decoding locally, instruction-guided JSON on cloud), with hermetic test.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
2026-06-10 13:22:54 +02:00
parent 97513141dc
commit 04b21fdad2
5 changed files with 299 additions and 1 deletions
+8
View File
@@ -235,6 +235,14 @@ func TestStructuredOutputFormat(t *testing.T) {
if resp.Text() != `{"name":"Ada"}` {
t.Errorf("text = %q", resp.Text())
}
// Ollama Cloud ignores "format", so the schema must also be stated as
// a system instruction.
msgs := cap.body["messages"].([]any)
sys := msgs[0].(map[string]any)
if sys["role"] != "system" || !strings.Contains(sys["content"].(string), `"name"`) ||
!strings.Contains(sys["content"].(string), "JSON Schema") {
t.Errorf("system fold must carry the schema instruction, got %v", sys)
}
}
func TestThinkMapping(t *testing.T) {
+8
View File
@@ -138,6 +138,14 @@ func (m *model) buildRequest(req llm.Request, stream bool) (*chatRequest, error)
}
}
}
if len(req.Schema) > 0 {
// Belt and braces: local Ollama enforces the "format" schema by
// constrained decoding, but Ollama Cloud ignores the field
// (verified live 2026-06-10) — so the schema is also stated as an
// explicit instruction. Harmless where format works, essential
// where it doesn't.
sys = append(sys, "Respond with a single JSON object that validates against this JSON Schema — no markdown, no code fences, no prose before or after the JSON:\n"+string(req.Schema))
}
if len(sys) > 0 {
out.Messages = append(out.Messages, chatMessage{
Role: "system", Content: strings.Join(sys, "\n\n"),