Files
wehub-resource-sync 0418dc5cf9
Autopilot Pages / deploy (push) Waiting to run
CI / Python tests (3.10) (push) Waiting to run
CI / Python tests (3.11) (push) Waiting to run
CI / Python quality (push) Waiting to run
CI / Frontend typecheck (push) Waiting to run
chore: import upstream snapshot with attribution
2026-07-13 12:45:00 +08:00

194 lines
5.9 KiB
Python

from __future__ import annotations
from openharness.engine.messages import ConversationMessage, ImageBlock, TextBlock
from openharness.api.client import AnthropicApiClient, OAUTH_BETA_HEADER
def test_anthropic_client_adds_oauth_beta_header(monkeypatch):
captured: dict[str, object] = {}
class _FakeAsyncAnthropic:
def __init__(self, **kwargs):
captured.update(kwargs)
monkeypatch.setattr("openharness.api.client.AsyncAnthropic", _FakeAsyncAnthropic)
AnthropicApiClient(auth_token="oauth-token")
assert captured["auth_token"] == "oauth-token"
assert captured["default_headers"] == {"anthropic-beta": OAUTH_BETA_HEADER}
def test_anthropic_client_uses_api_key_without_oauth_beta(monkeypatch):
captured: dict[str, object] = {}
class _FakeAsyncAnthropic:
def __init__(self, **kwargs):
captured.update(kwargs)
monkeypatch.setattr("openharness.api.client.AsyncAnthropic", _FakeAsyncAnthropic)
AnthropicApiClient(api_key="api-key")
assert captured["api_key"] == "api-key"
assert "default_headers" not in captured
def test_anthropic_client_adds_claude_oauth_identity_headers(monkeypatch):
captured: dict[str, object] = {}
class _FakeAsyncAnthropic:
def __init__(self, **kwargs):
captured.update(kwargs)
monkeypatch.setattr("openharness.api.client.AsyncAnthropic", _FakeAsyncAnthropic)
monkeypatch.setattr(
"openharness.auth.external.get_claude_code_version",
lambda: "2.1.92",
)
monkeypatch.setattr(
"openharness.auth.external.get_claude_code_session_id",
lambda: "session-123",
)
monkeypatch.setattr(
"openharness.api.client.get_claude_code_session_id",
lambda: "session-123",
)
monkeypatch.setattr(
"openharness.api.client.claude_attribution_header",
lambda: "x-anthropic-billing-header: cc_version=2.1.92; cc_entrypoint=cli;",
)
AnthropicApiClient(auth_token="oauth-token", claude_oauth=True)
headers = captured["default_headers"]
assert captured["auth_token"] == "oauth-token"
assert headers["x-app"] == "cli"
assert headers["user-agent"] == "claude-cli/2.1.92 (external, cli)"
assert headers["X-Claude-Code-Session-Id"] == "session-123"
assert "oauth-2025-04-20" in headers["anthropic-beta"]
assert "claude-code-20250219" in headers["anthropic-beta"]
def test_conversation_message_serializes_image_block_for_anthropic():
message = ConversationMessage(
role="user",
content=[
TextBlock(text="Describe this."),
ImageBlock(media_type="image/png", data="YWJj", source_path="/tmp/example.png"),
],
)
assert message.to_api_param() == {
"role": "user",
"content": [
{"type": "text", "text": "Describe this."},
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": "YWJj",
},
},
],
}
def test_anthropic_client_refreshes_claude_token_on_request(monkeypatch):
captured_tokens: list[str] = []
class _FakeStream:
async def __aenter__(self):
return self
async def __aexit__(self, exc_type, exc, tb):
return False
async def __aiter__(self):
if False:
yield None
return
async def get_final_message(self):
class _Usage:
input_tokens = 1
output_tokens = 1
class _Message:
usage = _Usage()
stop_reason = "end_turn"
role = "assistant"
content = []
return _Message()
class _FakeMessages:
def __init__(self):
self.last_params = None
def stream(self, **params):
self.last_params = params
return _FakeStream()
class _FakeBeta:
def __init__(self):
self.messages = _FakeMessages()
class _FakeAsyncAnthropic:
def __init__(self, **kwargs):
captured_tokens.append(kwargs["auth_token"])
self.beta = _FakeBeta()
self.messages = _FakeMessages()
monkeypatch.setattr("openharness.api.client.AsyncAnthropic", _FakeAsyncAnthropic)
monkeypatch.setattr(
"openharness.auth.external.get_claude_code_session_id",
lambda: "session-123",
)
monkeypatch.setattr(
"openharness.api.client.get_claude_code_session_id",
lambda: "session-123",
)
monkeypatch.setattr(
"openharness.api.client.claude_attribution_header",
lambda: "x-anthropic-billing-header: cc_version=2.1.92; cc_entrypoint=cli;",
)
current_token = {"value": "initial-token"}
client = AnthropicApiClient(
auth_token="initial-token",
claude_oauth=True,
auth_token_resolver=lambda: current_token["value"],
)
current_token["value"] = "refreshed-token"
from openharness.api.client import ApiMessageRequest
async def _run():
events = []
async for event in client.stream_message(
ApiMessageRequest(
model="claude-sonnet-4-6",
messages=[],
system_prompt="system prompt",
)
):
events.append(event)
return events
import asyncio
events = asyncio.run(_run())
assert captured_tokens == ["initial-token", "refreshed-token"]
assert events
assert client._client.beta.messages.last_params["metadata"] == {
"user_id": '{"device_id":"openharness","session_id":"session-123","account_uuid":""}'
}
assert "oauth-2025-04-20" in client._client.beta.messages.last_params["betas"]
assert client._client.beta.messages.last_params["system"].startswith(
"x-anthropic-billing-header: cc_version=2.1.92; cc_entrypoint=cli;\n"
)