(self, system_prompt: list[str], messages: list[Message])
| 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() |
| 201 | streaming_text = False |
| 202 | events.append(ToolUseEvent( |
| 203 | id=event.content_block.id, |
| 204 | name=event.content_block.name, |
| 205 | input=json.dumps(event.content_block.input), |
| 206 | )) |
| 207 | |
| 208 | elif event.type == 'message_stop': |
| 209 | if self.emit_output and streaming_text: |
| 210 | _sys.stdout.write("\n") |
| 211 | _sys.stdout.flush() |
| 212 | streaming_text = False |
| 213 | events.append(MessageStopEvent()) |
| 214 | |
| 215 | return events |
nothing calls this directly
no test coverage detected