Fix remaining code-review findings (15 bugs; #11 skipped as AID-compatible)
Backend: - provider: fall back to parsing a plain JSON body when a server ignores stream=true (was: silent empty turn); error if response has no text (#5) - memorybank: clamp cursors after undo/retry shrinks the action list, and translate summary_cursor (list position) to an Action.index boundary before comparing with Memory.source_end (#7) - memorybank: pinned memories now count toward the top_k budget (#8) - memorybank: cosine() returns 0.0 on dimension mismatch; changing the embedding model clears stored vectors so they re-embed (#9) - scripting: MAX_STORY_CARDS cap now counts cards inserted during the hook, so a script can't add unbounded cards in one turn (#10) - settings: /test tolerates non-dict JSON from /models (#13) - scenarios: import accepts worldInformation as a story-card source (#14) Frontend: - per-key debounce timers in PlotPanel and ScenarioEditor — editing two things within 600ms no longer drops the first save (#15, #16) - Continue button no longer discards typed input (#17) - failed retry resyncs actions from the server instead of leaving the removed action missing (#18) - Settings save/test surface errors instead of hanging on Testing… (#19) - InsightsPanel ignores stale responses from superseded requests (#20) - placeholder scan includes story-card trigger keys (#21) addStoryCard returning the 0-based index (falsy for the first card) matches real AI Dungeon per the scripting guidebook — kept, documented (#11). Statuses updated in CODE_REVIEW_FINDINGS.md; stale entries for previously fixed items (#1-4, #6, #12) corrected. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KFsGHju9szibJJa2YJcdbg
This commit is contained in:
co-authored by
Claude Fable 5
parent
3ee653a631
commit
253b533d3b
@@ -119,9 +119,16 @@ class OpenAICompatibleProvider(Provider):
|
||||
if resp.status_code != 200:
|
||||
detail = (await resp.aread()).decode(errors="replace")[:500]
|
||||
raise ProviderError(self._friendly_http_error(resp.status_code, detail))
|
||||
# Some servers ignore stream=true and return one plain JSON
|
||||
# body; buffer non-SSE lines so we can fall back to it.
|
||||
saw_sse = False
|
||||
raw_lines: list[str] = []
|
||||
async for line in resp.aiter_lines():
|
||||
if not line.startswith("data:"):
|
||||
if not saw_sse:
|
||||
raw_lines.append(line)
|
||||
continue
|
||||
saw_sse = True
|
||||
data = line[5:].strip()
|
||||
if data == "[DONE]":
|
||||
debuglog.finish_entry(log, response="".join(received))
|
||||
@@ -137,6 +144,27 @@ class OpenAICompatibleProvider(Provider):
|
||||
if chunk:
|
||||
received.append(chunk)
|
||||
yield "text", chunk
|
||||
if not saw_sse:
|
||||
body_text = "\n".join(raw_lines).strip()
|
||||
try:
|
||||
payload = json.loads(body_text)
|
||||
except ValueError:
|
||||
raise ProviderError(
|
||||
"AI endpoint returned neither an SSE stream nor JSON: "
|
||||
+ body_text[:200]
|
||||
)
|
||||
reasoning = self._extract_reasoning(payload)
|
||||
if reasoning:
|
||||
yield "reasoning", reasoning
|
||||
chunk = self._extract_chunk(payload)
|
||||
if chunk:
|
||||
received.append(chunk)
|
||||
yield "text", chunk
|
||||
if not received:
|
||||
raise ProviderError(
|
||||
"AI endpoint returned a response with no text: "
|
||||
+ body_text[:200]
|
||||
)
|
||||
debuglog.finish_entry(log, response="".join(received))
|
||||
except httpx.ConnectError as exc:
|
||||
error = f"Could not connect to {self.base_url} — is the AI server running?"
|
||||
|
||||
Reference in New Issue
Block a user