源码: main.rs:2384-2500 (AnthropicRuntimeClient) emit_output: 是否实时打印文本到终端。 CC 的做法: streaming 时同步渲染 markdown 到 stdout (main.rs:2436-2460)。 收到 TextDelta 时立刻 print,不等整个响应结束。
| 141 | # ============================================================ |
| 142 | |
| 143 | class ClaudeApiClient(ApiClient): |
| 144 | """源码: main.rs:2384-2500 (AnthropicRuntimeClient) |
| 145 | |
| 146 | emit_output: 是否实时打印文本到终端。 |
| 147 | CC 的做法: streaming 时同步渲染 markdown 到 stdout (main.rs:2436-2460)。 |
| 148 | 收到 TextDelta 时立刻 print,不等整个响应结束。 |
| 149 | """ |
| 150 | |
| 151 | def __init__( |
| 152 | self, |
| 153 | api_key: str, |
| 154 | model: str, |
| 155 | tools: list[dict] | None = None, |
| 156 | emit_output: bool = True, |
| 157 | ): |
| 158 | import anthropic |
| 159 | self.client = anthropic.Anthropic(api_key=api_key) |
| 160 | self.model = model |
| 161 | self.tools = tools or [] |
| 162 | self.emit_output = emit_output |
| 163 | |
| 164 | def stream(self, system_prompt: list[str], messages: list[Message]) -> list[AssistantEvent]: |
| 165 | import sys as _sys |
| 166 | |
| 167 | converted = _convert_messages(messages) |
| 168 | system_prompt_str = '\n'.join(system_prompt) |
| 169 | |
| 170 | kwargs: dict = { |
| 171 | "model": self.model, |
| 172 | "max_tokens": 8096, |
| 173 | "system": system_prompt_str, |
| 174 | "messages": converted, |
| 175 | } |
| 176 | if self.tools: |
| 177 | kwargs["tools"] = self.tools |
| 178 | |
| 179 | events: list[AssistantEvent] = [] |
| 180 | streaming_text = False # 追踪是否正在流式输出文本 |
| 181 | |
| 182 | with self.client.messages.stream(**kwargs) as s: |
| 183 | for event in s: |
| 184 | if event.type == 'content_block_delta': |
| 185 | if event.delta.type == 'text_delta': |
| 186 | events.append(TextDeltaEvent(text=event.delta.text)) |
| 187 | # 实时流式输出 — CC 的 emit_output |
| 188 | if self.emit_output: |
| 189 | if not streaming_text: |
| 190 | _sys.stdout.write("\n") |
| 191 | streaming_text = True |
| 192 | _sys.stdout.write(event.delta.text) |
| 193 | _sys.stdout.flush() |
| 194 | |
| 195 | elif event.type == 'content_block_stop': |
| 196 | if event.content_block.type == 'tool_use': |
| 197 | # 工具调用前换行 |
| 198 | if self.emit_output and streaming_text: |
| 199 | _sys.stdout.write("\n") |
| 200 | _sys.stdout.flush() |
no outgoing calls
no test coverage detected