diff --git a/_AI_USAGE_LOG.md b/_AI_USAGE_LOG.md index 78aa5f5..ebdfad4 100644 --- a/_AI_USAGE_LOG.md +++ b/_AI_USAGE_LOG.md @@ -51,4 +51,5 @@ (End of file - total 50 lines) | 2026-08-09 10:50 | 反馈迭代 | 里程碑3.1 backlog 清理(retro 3 项):① chat_structured 增加 token 超限检测(渲染后估算超限→truncate_cb→重渲染,与 chat 流程一致)TDD RED→GREEN 新增 test_chat_structured_truncation_callback_triggered;② 清理 test_inference_engine.py 未用导入(pytest/json/ChatMessage);③ HttpLLMClient 增加上下文管理器(__enter__/__exit__ 退出时关闭底层 httpx.Client 释放连接)TDD 新增 test_client_context_manager_closes_transport;pytest 全量 119 passed 覆盖 100.00%,fail_under=99 达标;提交见 git log | src/genesis/inference/engine.py, src/genesis/inference/client.py, tests/test_inference_engine.py, tests/test_inference_client.py, _AI_USAGE_LOG.md | deepseek-v4-flash-free | -| 2026-08-09 11:20 | 反馈迭代 | Web UI 设计评审(v1.0→v1.1,7 项发现全修):以大赛手册+api-design 为权威基准审查 web-ui-design.md——F1 上传区补「概要设计做成说明书」独立 write_instruction file_type(api-design §2.2 连带扩展)+ 命名统一;F2 §4.1 任务队列 Redis 写死→抽象 TaskQueue(InMemory 默认/Redis/Valkey 可选);F3 新增设置页 §3.6;F4 预览路径改 ContentBlock→chapter_html+docx;F5 生成页新增规则冲突浮动卡片(WS conflict_pending→conflicts/{id}/resolve);F6 新增会话历史页 §3.7;F7 新增 §7 无障碍与设计规范。同步 design.md §8 简版镜像(上传区/预览/队列/导航历史/冲突卡片/设置历史简版//history 命令);产出评审报告 docs/web-ui-design-review-v1.1.md;docs/design.md、docs/api-design.md 连带修订 | docs/web-ui-design.md, docs/web-ui-design-review-v1.1.md, docs/api-design.md, docs/design.md, _AI_USAGE_LOG.md | deepseek-v4-flash-free | +| 2026-08-09 11:20 | 反馈迭代 | Web UI 设计评审(v1.0→v1.1,7 项发现全修):以大赛手册+api-design 为权威基准审查 web-ui-design.md——F1 上传区补「概要设计做成说明书」独立 write_instruction file_type(api-design §2.2 连带扩展)+ 命名统一;F2 §4.1 任务队列 Redis 写死→抽象 TaskQueue(InMemory 默认/Redis/Valkey 可选);F3 新增设置页 §3.6;F4 预览路径改 ContentBlock→chapter_html+docx;F5 生成页新增规则冲突卡片(WS conflict_pending→conflicts/{id}/resolve);F6 新增会话历史页 §3.7;F7 新增 §7 无障碍与设计规范。同步 design.md §8 镜像(上传区/设置/队列/会话/冲突卡片/历史简版//history 命令);产出评审报告 docs/web-ui-design-review-v1.1.md;docs/design.md、docs/api-design.md 连带修订 | docs/web-ui-design.md, docs/web-ui-design-review-v1.1.md, docs/api-design.md, docs/design.md, _AI_USAGE_LOG.md | deepseek-v4-flash-free | +| 2026-08-09 11:45 | Agent 实现 | LLM 错误码对齐 Task1:异常树 error_code 类属性(LLMError 基类 None + four 子类 four 码,对齐 api-design §7),沿用现有中文 docstring 未改动。TDD RED(AttributeError: type object 'LLMError' has no attribute 'error_code')→ GREEN(聚焦 4 passed,exceptions.py 100%);聚焦单文件运行触发全库 fail-under=99 coverage exit 1 为基线行为(总覆盖 9.95%),与本次改动无关;加入 _AI_USAGE_LOG.md 提交 | src/genesis/inference/exceptions.py, tests/test_inference_errors.py, _AI_USAGE_LOG.md | deepseek-v4-flash-free | diff --git a/src/genesis/inference/exceptions.py b/src/genesis/inference/exceptions.py index 8fed13d..4aca4c6 100644 --- a/src/genesis/inference/exceptions.py +++ b/src/genesis/inference/exceptions.py @@ -3,19 +3,24 @@ from __future__ import annotations class LLMError(Exception): """LLM 调用相关的异常基类(api-design §7 映射基底)""" + error_code: str | None = None # api §7 错误码(机器可读);新增子类必须覆写 class LLMNetworkError(LLMError): """网络失败 / 5xx 重试耗尽(可重试语义)""" + error_code = "LLM_NETWORK_ERROR" class LLMTimeoutError(LLMError): """LLM 调用超时(api-error: LLM_TIMEOUT 502)""" + error_code = "LLM_TIMEOUT" class LLMNotConfiguredError(LLMError): """Key / 模型缺失(api-error: LLM_NOT_CONFIGURED 503)""" + error_code = "LLM_NOT_CONFIGURED" class LLMResponseError(LLMError): - """响应结构损坏(JSON 解析失败等)""" \ No newline at end of file + """响应结构损坏(JSON 解析失败等)""" + error_code = "LLM_PARSE_ERROR" \ No newline at end of file diff --git a/tests/test_inference_errors.py b/tests/test_inference_errors.py index 7020f70..ea409bc 100644 --- a/tests/test_inference_errors.py +++ b/tests/test_inference_errors.py @@ -18,4 +18,18 @@ def test_error_hierarchy(): def test_error_message_roundtrip(): e = LLMTimeoutError("timeout!") - assert str(e) == "timeout!" \ No newline at end of file + assert str(e) == "timeout!" + + +def test_error_code_class_attributes(): + # error_code 与 api-design §7 错误码表一一对应(机器可读事实源) + assert LLMError.error_code is None + assert LLMTimeoutError.error_code == "LLM_TIMEOUT" + assert LLMNetworkError.error_code == "LLM_NETWORK_ERROR" + assert LLMNotConfiguredError.error_code == "LLM_NOT_CONFIGURED" + assert LLMResponseError.error_code == "LLM_PARSE_ERROR" + + +def test_error_code_inherited_by_instance(): + e = LLMNetworkError("network") + assert e.error_code == "LLM_NETWORK_ERROR" \ No newline at end of file