feat: prepare 2.2.0 with UI and execution fixes

Add dark theme, richer Markdown and readable plugin results.
Improve Android input evidence, response integrity and diagnostics.
Unify lifecycle, guidance receipts and evidence sources across clients.
Keep direct action dispatch without an added AI quota approval layer.
Align version metadata at 2.2.0 and bundle Helper 1.2.2.

Validation: 3063 backend tests before the version bump; 44 after.
Frontend: 317 tests and production build passed.
This commit is contained in:
chenmingxuan committed 2026-10-26 00:44:13 +08:00
1 parent 83bcfd54d5
commit fac4ccb760
146 files changed
+5689 -2033

No files matched your search

+75 -1
View File
@@ -18,6 +18,7 @@ from artemis.llm.diagnostics import (
)
from artemis.llm.router import ModelEndpoint
from artemis.services import llm
from artemis.runtime.cancellation import CancellationReason
class Engine:
@@ -121,6 +122,10 @@ async def test_headers_without_body_timeout_then_retry_keeps_evidence(monkeypatc
assert failed["usage"] is None and "first_output_at" not in failed
assert final["request_id"] == failed["request_id"]
assert final["attempt_id"] != failed["attempt_id"] and final["attempt"] == 2
assert final["previous_attempt_id"] == failed["attempt_id"]
retry = next(r["payload"] for r in engine.records if r["name"] == "llm_retry")
assert retry["request_id"] == failed["request_id"]
assert retry["attempt_id"] == failed["attempt_id"]
assert final["phase"] == "completed" and final["usage"]["total_tokens"] == 12
assert (
final["started_at"] <= final["headers_at"] <= final["first_output_at"] <= final["ended_at"]
@@ -226,6 +231,72 @@ async def test_concurrent_requests_do_not_mix_server_ids():
assert second["server_request_id"] == "two"
@pytest.mark.asyncio
async def test_diagnostic_ids_survive_streaming_and_structured_completion_without_header_bodies():
engine = Engine()
attempt = RequestAttempt(
engine, request_id="local", attempt=1, timeout=300, max_retries=1, metadata={}
)
token = ACTIVE_ATTEMPT.set(attempt)
traceparent = "00-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa-bbbbbbbbbbbbbbbb-01"
try:
request = httpx.Request(
"POST", "https://example.test/responses", headers={"x-client-request-id": "caller-id"}
)
await observe_request_headers(request)
await observe_response_headers(
httpx.Response(
200,
headers={
"x-request-id": "server-id",
"x-trace-id": "gateway-id",
"traceparent": traceparent,
"set-cookie": "private cookie",
"authorization": "private credential",
},
)
)
attempt.chunk(AIMessageChunk(content="hello", response_metadata={"id": "resp-first"}))
attempt.finish(
"completed",
response={
"raw": AIMessageChunk(
content="hello", response_metadata={"id": "resp-final", "status": "completed"}
),
"parsed": {"private": "business details"},
},
)
finally:
ACTIVE_ATTEMPT.reset(token)
assert request.headers["x-client-request-id"] == "caller-id"
assert attempt.data["client_request_id"] == "caller-id"
assert attempt.data["server_request_id"] == "server-id"
assert attempt.data["server_trace_id"] == "gateway-id"
assert attempt.data["traceparent"] == traceparent
assert attempt.data["response_id"] == "resp-final"
assert attempt.data["response_status"] == "completed"
assert "private" not in json.dumps(engine.records, default=str)
def test_invalid_or_overlong_correlation_headers_are_omitted():
attempt = RequestAttempt(
Engine(), request_id="local", attempt=1, timeout=300, max_retries=1, metadata={}
)
attempt.headers(
httpx.Response(
200,
headers={
"x-request-id": "x" * 257,
"x-trace-id": "not an id",
"traceparent": "not a trace",
},
)
)
assert attempt.data["server_request_id"] is None
assert attempt.data["server_trace_id"] is None
assert "traceparent" not in attempt.data
def test_error_redaction_and_image_headers():
import base64
import io
@@ -372,11 +443,14 @@ async def test_cancelling_retry_wait_does_not_leave_a_live_request(monkeypatch):
task = asyncio.create_task(llm._run_with_recovery(timeout, max_retries=1))
await asyncio.wait_for(waiting.wait(), 2)
task.cancel()
task.cancel(CancellationReason.GUIDANCE_REPLACED)
with pytest.raises(asyncio.CancelledError):
await task
assert engine.records[-1]["payload"]["phase"] == "cancelled"
assert "模型请求" in engine.records[-1]["payload"]["error"]
assert engine.records[-1]["payload"]["cancel_reason"] == "guidance_replaced"
assert engine.records[-1]["payload"]["cancel_phase"] == "retry_wait"
assert "timeout_scope" not in engine.records[-1]["payload"]
def test_diagnostic_api_limits_preview_but_downloads_complete_history(tmp_path, monkeypatch):