feat(discord-bridge): imagini si fisiere text din Discord ajung la Claude
Puntea trimitea doar `content`-ul mesajului; orice atasament disparea tacut, iar un mesaj fara text (doar poza) era respins ca "empty". Acum mesajul de utilizator se construieste ca blocuri, in formatul pe care CLI-ul il accepta pe `--input-format stream-json` (verificat pe CLI real: Claude descrie corect o imagine trimisa asa). - imagini png/jpeg/gif/webp -> blocuri `image` base64, max 4, max 3,5 MB brut (base64 umfla cu ~4/3, iar API-ul refuza peste ~5 MB codate) - fisiere text (mime `text/*`, `application/json`, sau extensie cunoscuta) -> continutul intra in prompt, max 4, trunchiat la 100 KB - restul (PDF, Office, arhive, svg, heic) -> doar numite, cu motivul Detalii care conteaza: - `image/jpg` si `image/png; charset=...` se normalizeaza; cand Discord nu trimite content_type cadem pe extensie - marimea se verifica de doua ori: cea declarata (ca sa nu descarcam degeaba) si cea reala dupa descarcare - nimic nu dispare tacut: ce n-a putut fi citit apare in prompt ca "Atasamente ignorate: ..."; o imagine stricata nu anuleaza restul mesajului - merge si mid-tur: o poza trimisa in timpul unui tur intra pe stdin ca steering 31 de teste noi in tests/test_attachments.py (normalizare tipuri, limite, trunchiere, erori de descarcare, integrare prin punte, steering). Suita: 426 pass. README: sectiune "Atasamente" + limitarea veche corectata (ramane doar vocea). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Q4uzvgm7AyJch5WH8QHRhY
This commit is contained in:
@@ -80,9 +80,10 @@ def build_cmd(
|
||||
return cmd
|
||||
|
||||
|
||||
def user_message(text: str) -> str:
|
||||
def user_message(content: str | list[dict]) -> str:
|
||||
blocks = [{"type": "text", "text": content}] if isinstance(content, str) else content
|
||||
return json.dumps(
|
||||
{"type": "user", "message": {"role": "user", "content": [{"type": "text", "text": text}]}},
|
||||
{"type": "user", "message": {"role": "user", "content": blocks}},
|
||||
ensure_ascii=False,
|
||||
)
|
||||
|
||||
@@ -199,11 +200,11 @@ class ClaudeProcess:
|
||||
await res
|
||||
|
||||
# ------------------------------------------------------------- mesaje
|
||||
async def send(self, text: str) -> None:
|
||||
async def send(self, content: str | list[dict]) -> None:
|
||||
"""Trimite un mesaj de utilizator pe stdin (si mid-tur: asta e steering-ul)."""
|
||||
if not self.alive or self.proc is None or self.proc.stdin is None:
|
||||
raise TurnFailed("procesul claude nu e viu")
|
||||
self.proc.stdin.write((user_message(text) + "\n").encode("utf-8"))
|
||||
self.proc.stdin.write((user_message(content) + "\n").encode("utf-8"))
|
||||
await self.proc.stdin.drain()
|
||||
self.last_active = time.monotonic()
|
||||
|
||||
@@ -222,7 +223,7 @@ class ClaudeProcess:
|
||||
|
||||
async def run_turn(
|
||||
self,
|
||||
prompt: str,
|
||||
prompt: str | list[dict],
|
||||
on_event: Callable[[Any], Awaitable[None]] | None = None,
|
||||
timeout: float | None = None,
|
||||
) -> TurnOutcome:
|
||||
|
||||
Reference in New Issue
Block a user