Stabilize pro editing without heavy office runtime
The workspace now carries the pro editing flow, streaming completion path, and lighter Office preview state as one checkpoint so the remote has the current runnable project shape. Constraint: Preserve the current workspace as a single reviewable project commit while excluding local agent state and verification artifacts. Removed stale Univer runtime dependencies from the lockfile so installs match package.json. Rejected: Commit runtime screenshots, .omx state, and coverage files | they are local artifacts rather than source state. Confidence: medium Scope-risk: broad Directive: Keep package.json and package-lock.json synchronized when changing frontend dependencies. Tested: npm run build; C:\Users\ydy\.conda\envs\llmwebsite\python.exe -m pytest backend/tests/test_main_endpoints.py backend/tests/test_main_cancel.py backend/tests/test_llm.py backend/tests/test_llm_extended.py -v -o addopts= (44 passed). Not-tested: Full pytest with repository coverage addopts currently reports 0% coverage because pytest-cov watches backend.* module names while tests import top-level backend modules. Co-authored-by: OmX <omx@oh-my-codex.dev>
This commit is contained in:
@@ -85,46 +85,45 @@ def test_extract_message_empty_dict():
|
||||
def test_call_ollama_no_system_message(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
async def fake_chat(**kwargs):
|
||||
captured["messages"] = kwargs.get("messages", [])
|
||||
return {"message": {"content": "ok", "thinking": ""}}
|
||||
async def fake_generate(**kwargs):
|
||||
captured["kwargs"] = kwargs
|
||||
return {"response": "ok"}
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
result = asyncio.run(
|
||||
llm.call_ollama("user prompt body", system_prompt=None, tag="no-system", temperature=0.1)
|
||||
)
|
||||
assert result["content"] == "ok"
|
||||
assert len(captured["messages"]) == 1
|
||||
assert captured["messages"][0]["role"] == "user"
|
||||
assert captured["messages"][0]["content"] == "user prompt body"
|
||||
assert captured["kwargs"]["prompt"] == "user prompt body"
|
||||
assert captured["kwargs"]["raw"] is True
|
||||
|
||||
|
||||
def test_call_ollama_whitespace_system_message(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
async def fake_chat(**kwargs):
|
||||
captured["messages"] = kwargs.get("messages", [])
|
||||
return {"message": {"content": "ok", "thinking": ""}}
|
||||
async def fake_generate(**kwargs):
|
||||
captured["kwargs"] = kwargs
|
||||
return {"response": "ok"}
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
result = asyncio.run(
|
||||
llm.call_ollama("user prompt", system_prompt=" ", tag="whitespace-system", temperature=0.1)
|
||||
)
|
||||
assert result["content"] == "ok"
|
||||
assert len(captured["messages"]) == 1
|
||||
assert captured["messages"][0]["role"] == "user"
|
||||
assert captured["kwargs"]["prompt"] == "user prompt"
|
||||
assert captured["kwargs"]["raw"] is True
|
||||
|
||||
|
||||
def test_call_ollama_thinking_in_kwargs(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
async def fake_chat(**kwargs):
|
||||
async def fake_generate(**kwargs):
|
||||
captured.update(kwargs)
|
||||
return {"message": {"content": "ok", "thinking": "boom"}}
|
||||
return {"response": "ok", "message": {"thinking": "boom"}} # keep thinking for backward test though it might not be perfect
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
res = asyncio.run(
|
||||
llm.call_ollama("prompt", thinking="boom", tag="think-flag", temperature=0.7)
|
||||
@@ -134,10 +133,10 @@ def test_call_ollama_thinking_in_kwargs(monkeypatch):
|
||||
|
||||
|
||||
def test_call_ollama_cancelled_reraises(monkeypatch):
|
||||
async def fake_chat(**kwargs):
|
||||
async def fake_generate(**kwargs):
|
||||
raise asyncio.CancelledError
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
with pytest.raises(asyncio.CancelledError):
|
||||
asyncio.run(
|
||||
@@ -146,10 +145,10 @@ def test_call_ollama_cancelled_reraises(monkeypatch):
|
||||
|
||||
|
||||
def test_call_ollama_chat_raises_rethrows(monkeypatch):
|
||||
async def fake_chat(**kwargs):
|
||||
async def fake_generate(**kwargs):
|
||||
raise ValueError("boom")
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
asyncio.run(
|
||||
@@ -158,10 +157,10 @@ def test_call_ollama_chat_raises_rethrows(monkeypatch):
|
||||
|
||||
|
||||
def test_call_ollama_returns_content_and_think_from_response(monkeypatch):
|
||||
async def fake_chat(**kwargs):
|
||||
return {"message": {"content": "final", "thinking": "process"}}
|
||||
async def fake_generate(**kwargs):
|
||||
return {"response": "final", "message": {"thinking": "process"}}
|
||||
|
||||
monkeypatch.setattr(llm.client, "chat", fake_chat)
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
res = asyncio.run(
|
||||
llm.call_ollama("prompt", system_prompt=None, tag="return", temperature=0.7)
|
||||
@@ -169,6 +168,51 @@ def test_call_ollama_returns_content_and_think_from_response(monkeypatch):
|
||||
assert res["content"] == "final" and res["think"] == "process"
|
||||
|
||||
|
||||
def test_stream_ollama_uses_requested_model_and_yields_chunks(monkeypatch):
|
||||
captured = {}
|
||||
|
||||
class FakeStream:
|
||||
def __init__(self, chunks):
|
||||
self._chunks = iter(chunks)
|
||||
|
||||
def __aiter__(self):
|
||||
return self
|
||||
|
||||
async def __anext__(self):
|
||||
try:
|
||||
return next(self._chunks)
|
||||
except StopIteration:
|
||||
raise StopAsyncIteration
|
||||
|
||||
async def fake_generate(**kwargs):
|
||||
captured["kwargs"] = kwargs
|
||||
return FakeStream([
|
||||
{"response": "深度"},
|
||||
{"response": "回答"},
|
||||
])
|
||||
|
||||
monkeypatch.setattr(llm.client, "generate", fake_generate)
|
||||
|
||||
chunks = []
|
||||
|
||||
async def collect_stream():
|
||||
async for chunk in llm.stream_ollama(
|
||||
"prompt",
|
||||
system_prompt="system",
|
||||
tag="stream",
|
||||
temperature=0.8,
|
||||
model="pro-model",
|
||||
use_pro_model=True,
|
||||
):
|
||||
chunks.append(chunk)
|
||||
|
||||
asyncio.run(collect_stream())
|
||||
|
||||
assert "".join(chunks) == "深度回答"
|
||||
assert captured["kwargs"]["model"] == "pro-model"
|
||||
assert captured["kwargs"]["stream"] is True
|
||||
|
||||
|
||||
def test_call_vlm_ocr_passes_image_and_prompt(monkeypatch):
|
||||
image_bytes = b"image-bytes"
|
||||
called = {}
|
||||
|
||||
Reference in New Issue
Block a user