agent-zero/tests/test_anthropic_thoughts_prompt.py
Alessandro 60c940fd03
Some checks failed
Build And Publish Docker Images / plan (push) Has been cancelled
Build And Publish Docker Images / build (push) Has been cancelled
fix(model-config): detect Claude models across providers
The Anthropic thoughts-prompt hook previously activated only when the
provider or model name contained "anthropic". Claude models exposed by
third-party or OpenAI-compatible providers without that identifier
therefore missed the prompt adaptation.

Extend the existing detection with a case-insensitive "claude" match
in the effective main model name, regardless of provider. Preserve the
existing "anthropic" match in either the provider or model name.

Keep the public-action-summary substitutions and prompt scope unchanged.
Preserve shared prompt templates, the thoughts JSON field, saved history,
custom wording, and native protocol projection. Do not change transport
error handling or suppress provider content-policy errors.

Add regression coverage for Claude-only model names across OpenRouter,
OpenAI-compatible, Vertex AI, Bedrock, and generic providers, plus mixed
case and negative cases. Update the plugin contract and README.

Validation:
- Reproduced five failing Claude-only cases before the fix.
- Passed 99 targeted prompt, model-config, and onboarding tests using
  /opt/venv-a0/bin/python.
- Passed git diff --check.

Live A0 API/provider behavior was not retested; this fixes the detection
gap but does not establish that every provider refusal is resolved.
2026-09-30 19:03:54 +02:00

63 lines
2.6 KiB
Python

from pathlib import Path
from types import SimpleNamespace
import pytest
from helpers import files, responses_tools
from plugins._model_config.extensions.python._functions.agent.Agent.read_prompt.end import (
_20_anthropic_thoughts as thoughts,
)
@pytest.mark.parametrize("provider,model,adapted", [
("anthropic", "claude-opus-5-5", True),
("AnThRoPiC", "custom-model", True),
("openrouter", "Anthropic/claude-opus-5.5", True),
("other", "Anthropic/custom-model", True),
("bedrock", "us.anthropic.claude-opus", True),
("openrouter", "claude-opus-5.5", True),
("openai", "claude-opus-5-5", True),
("other", "ClAuDe-opus-5-5", True),
("vertex_ai", "claude-sonnet-4@20250514", True),
("bedrock", "claude-opus-5-5", True),
("openrouter", "openai/gpt-5", False),
("openai", "gpt-5", False),
("claude_gateway", "unrelated-model", False),
("other", "", False),
])
def test_scoped_prompt_rendering_preserves_templates_and_native_projection(
monkeypatch, provider, model, adapted,
):
root = Path(__file__).parents[1] / "prompts"
monkeypatch.setattr(thoughts, "get_chat_model_config", lambda agent: {
"provider": provider, "name": model,
})
agent = SimpleNamespace()
hook = thoughts.AnthropicThoughts(agent)
def read_prompt(name):
original = files.read_prompt_file(name, _directories=[str(root)]).rstrip("\n")
data = {"args": (agent,), "kwargs": {"file": name}, "result": original}
hook.execute(data)
assert (data["result"] != original) == (adapted and name != "agent.system.main.communication.native.md")
return data["result"]
agent.read_prompt = read_prompt
main = read_prompt("agent.system.main.md")
assert read_prompt("agent.system.main.communication.md") in main
assert read_prompt("agent.system.main.solving.md") in main
assert '"thoughts": [' in main
assert ("explain each step in thoughts" not in main) == adapted
loop = SimpleNamespace(params_temporary={})
responses_tools.register_prompt(agent, loop, "main", main)
native = responses_tools.project_system_prompt(
[{"role": "system", "content": files.remove_code_fences(main, language="json")}],
loop.params_temporary["responses_prompt_replacements"],
)[0]["content"]
assert "Use the provided native functions" in native
for name in ("agent.system.main.md", "fw.initial_message.md"):
custom = "Custom thoughts guidance."
data = {"args": (agent, name), "kwargs": {}, "result": custom}
hook.execute(data)
assert data["result"] == custom