add uv install guide & pyproject.toml; unify error prefix to !!!Error:

This commit is contained in:
Liang Jiaqing
2026-04-24 10:00:15 +08:00
parent f334994ab6
commit 12c2fe1f79
3 changed files with 75 additions and 7 deletions

View File

@@ -148,7 +148,7 @@ def _parse_claude_sse(resp_lines):
elif evt_type == "error":
err = evt.get("error", {})
emsg = err.get("message", str(err)) if isinstance(err, dict) else str(err)
warn = f"\n\n[SSE Error: {emsg}]"; break
warn = f"\n\n!!!Error: SSE {emsg}"; break
if not warn:
if not got_message_stop and not stop_reason: warn = "\n\n[!!! 流异常中断,未收到完整响应 !!!]"
elif stop_reason == "max_tokens": warn = "\n\n[!!! Response truncated: max_tokens !!!]"
@@ -211,7 +211,7 @@ def _parse_openai_sse(resp_lines, api_mode="chat_completions"):
elif etype == "error":
err = evt.get("error", {})
emsg = err.get("message", str(err)) if isinstance(err, dict) else str(err)
if emsg: content_text += f"Error: {emsg}"; yield f"Error: {emsg}"
if emsg: content_text += f"!!!Error: {emsg}"; yield f"!!!Error: {emsg}"
break
elif etype == "response.completed":
usage = evt.get("response", {}).get("usage", {})
@@ -522,7 +522,7 @@ class BaseSession:
if block.get('type', '') == 'tool_use':
tu = {'name': block.get('name', ''), 'arguments': block.get('input', {})}
yield f'<tool_use>{json.dumps(tu, ensure_ascii=False)}</tool_use>'
if not content.startswith("Error:"): self.history.append({"role": "assistant", "content": [{"type": "text", "text": content}]})
if not content.startswith("!!!Error:"): self.history.append({"role": "assistant", "content": [{"type": "text", "text": content}]})
return _ask_gen() if stream else ''.join(list(_ask_gen()))
class ClaudeSession(BaseSession):
@@ -537,7 +537,7 @@ class ClaudeSession(BaseSession):
if r.status_code != 200: raise Exception(f"HTTP {r.status_code} {r.content.decode('utf-8', errors='replace')[:500]}")
return (yield from _parse_claude_sse(r.iter_lines())) or []
except Exception as e:
yield (err := f"Error: {e}")
yield (err := f"!!!Error: {e}")
return [{"type": "text", "text": err}]
def make_messages(self, raw_list):
msgs = [{"role": m['role'], "content": list(m['content'])} for m in raw_list]
@@ -621,7 +621,7 @@ class NativeClaudeSession(BaseSession):
elif b.get("type") == "thinking": yield ""
return content_blocks
except Exception as e:
yield (err := f"Error: {e}")
yield (err := f"!!!Error: {e}")
return [{"type": "text", "text": err}]
def ask(self, msg):
@@ -635,7 +635,7 @@ class NativeClaudeSession(BaseSession):
try:
while True: yield next(gen)
except StopIteration as e: content_blocks = e.value or []
if content_blocks and not (len(content_blocks) == 1 and content_blocks[0].get("text", "").startswith("Error:")):
if content_blocks and not (len(content_blocks) == 1 and content_blocks[0].get("text", "").startswith("!!!Error:")):
self.history.append({"role": "assistant", "content": content_blocks})
text_parts = [b["text"] for b in content_blocks if b.get("type") == "text"]
content = "\n".join(text_parts).strip()
@@ -891,7 +891,7 @@ class MixinSession:
return self._cur_idx
def _raw_ask(self, *args, **kwargs):
base, n = self._pick(), len(self._sessions)
test_error = lambda x: isinstance(x, str) and (x.startswith('Error:') or x.startswith('[Error:'))
test_error = lambda x: isinstance(x, str) and x.lstrip().startswith(('!!!Error:', '[Error:'))
for attempt in range(self._retries + 1):
idx = (base + attempt) % n
gen = self._orig_raw_asks[idx](*args, **kwargs)