File size: 2,145 Bytes
11c0f3a
 
0d0f0f9
 
11c0f3a
 
 
 
0d0f0f9
 
11c0f3a
 
 
c33ab9e
11c0f3a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
"""Messaging-specific assertions built on neutral Anthropic stream contracts."""

from free_claude_code.core.anthropic import AnthropicStreamLedger
from free_claude_code.core.anthropic.stream_contracts import (
    assert_anthropic_stream_contract,
    has_tool_use,
    parse_sse_text,
)
from free_claude_code.messaging.event_parser import parse_cli_event
from free_claude_code.messaging.transcript import RenderCtx, TranscriptBuffer


def test_thinking_tool_text_and_transcript_order_contract() -> None:
    builder = AnthropicStreamLedger("msg_contract", "contract-model")
    chunks = [builder.message_start()]
    chunks.extend(builder.ensure_thinking_block())
    chunks.append(builder.emit_thinking_delta("inspect first"))
    chunks.extend(builder.close_content_blocks())
    tool_block_index = builder.blocks.allocate_index()
    chunks.append(
        builder.content_block_start(
            tool_block_index, "tool_use", id="toolu_1", name="Read"
        )
    )
    chunks.append(
        builder.content_block_delta(
            tool_block_index, "input_json_delta", '{"file":"README.md"}'
        )
    )
    chunks.append(builder.content_block_stop(tool_block_index))
    chunks.extend(builder.ensure_text_block())
    chunks.append(builder.emit_text_delta("done"))
    chunks.extend(builder.close_all_blocks())
    chunks.append(builder.message_delta("end_turn", 20))
    chunks.append(builder.message_stop())

    events = parse_sse_text("".join(chunks))
    assert_anthropic_stream_contract(events)
    assert has_tool_use(events)

    transcript = TranscriptBuffer()
    for event in events:
        for parsed in parse_cli_event(event.data):
            transcript.apply(parsed)
    rendered = transcript.render(_render_ctx(), limit_chars=3900, status=None)
    assert (
        rendered.find("inspect first")
        < rendered.find("Tool call:")
        < rendered.find("done")
    )


def _render_ctx() -> RenderCtx:
    return RenderCtx(
        bold=lambda s: f"*{s}*",
        code_inline=lambda s: f"`{s}`",
        escape_code=lambda s: s,
        escape_text=lambda s: s,
        render_markdown=lambda s: s,
    )