feat: 实现日历提醒完整功能(操作执行、通知服务重构、归档)
- 新增 ReminderActionExecutor 处理取消/稍后提醒操作 - 新增 ReminderOutboxStore 本地存储待处理操作 - 重构 LocalNotificationService 支持聚合提醒和交互操作 - 新增 event_color_resolver 工具类统一颜色解析 - 新增 CalendarService.archiveEvent 归档方法 - 增强 ModelTracking 支持缓存命中、推理token和成本追踪 - 添加 qwen3.5-35b-a3b 模型配置 - 更新 AndroidManifest 全屏intent权限 - 补充相关单元测试和文档
This commit is contained in:
@@ -0,0 +1,126 @@
|
||||
from __future__ import annotations
|
||||
|
||||
from typing import Any, cast
|
||||
|
||||
from core.agentscope.runtime.model_tracking import TrackingChatModel
|
||||
|
||||
|
||||
class _FakeMetadata:
|
||||
def model_dump(self) -> dict[str, object]:
|
||||
return {
|
||||
"prompt_tokens": 120,
|
||||
"completion_tokens": 30,
|
||||
"total_tokens": 150,
|
||||
"prompt_tokens_details": {
|
||||
"cached_tokens": 80,
|
||||
},
|
||||
"prompt_cache_hit_tokens": 80,
|
||||
"prompt_cache_miss_tokens": 40,
|
||||
"completion_tokens_details": {
|
||||
"reasoning_tokens": 5,
|
||||
},
|
||||
}
|
||||
|
||||
|
||||
class _FakeUsage:
|
||||
input_tokens = 120
|
||||
output_tokens = 30
|
||||
time = 1.234
|
||||
metadata = _FakeMetadata()
|
||||
|
||||
|
||||
class _FakeResponse:
|
||||
usage = _FakeUsage()
|
||||
|
||||
|
||||
class _FakeModel:
|
||||
stream = False
|
||||
|
||||
async def __call__(self, *args: object, **kwargs: object) -> _FakeResponse:
|
||||
return _FakeResponse()
|
||||
|
||||
|
||||
class _FakeUsageWithProviderCost:
|
||||
input_tokens = 50
|
||||
output_tokens = 10
|
||||
time = 0.5
|
||||
cost = 0.0123
|
||||
metadata = _FakeMetadata()
|
||||
|
||||
|
||||
class _FakeResponseWithProviderCost:
|
||||
usage = _FakeUsageWithProviderCost()
|
||||
|
||||
|
||||
class _FakeModelWithProviderCost:
|
||||
stream = False
|
||||
|
||||
async def __call__(
|
||||
self, *args: object, **kwargs: object
|
||||
) -> _FakeResponseWithProviderCost:
|
||||
return _FakeResponseWithProviderCost()
|
||||
|
||||
|
||||
class _FakeResponseWithoutUsage:
|
||||
usage = None
|
||||
|
||||
|
||||
class _FakeModelWithoutUsage:
|
||||
stream = False
|
||||
|
||||
async def __call__(
|
||||
self, *args: object, **kwargs: object
|
||||
) -> _FakeResponseWithoutUsage:
|
||||
return _FakeResponseWithoutUsage()
|
||||
|
||||
|
||||
async def test_tracking_chat_model_collects_primary_usage_fields() -> None:
|
||||
model = TrackingChatModel(cast(Any, _FakeModel()))
|
||||
|
||||
await model("prompt")
|
||||
|
||||
summary = model.usage_summary()
|
||||
assert summary["input_tokens"] == 120
|
||||
assert summary["output_tokens"] == 30
|
||||
assert summary["total_tokens"] == 150
|
||||
assert summary["latency_ms"] == 1234
|
||||
assert summary["cached_prompt_tokens"] == 80
|
||||
assert summary["prompt_cache_hit_tokens"] == 80
|
||||
assert summary["prompt_cache_miss_tokens"] == 40
|
||||
assert summary["reasoning_tokens"] == 5
|
||||
assert summary["direct_cost"] == 0.0
|
||||
assert summary["direct_cost_observed"] == 0
|
||||
assert summary["direct_cost_complete"] == 0
|
||||
assert summary["model_call_records"] == 1
|
||||
assert summary["usage_records"] == 1
|
||||
assert summary["direct_cost_records"] == 0
|
||||
assert summary["cost_source"] == "catalog_fallback"
|
||||
|
||||
|
||||
async def test_tracking_chat_model_prefers_provider_cost_when_available() -> None:
|
||||
model = TrackingChatModel(cast(Any, _FakeModelWithProviderCost()))
|
||||
|
||||
await model("prompt")
|
||||
|
||||
summary = model.usage_summary()
|
||||
assert summary["direct_cost"] == 0.0123
|
||||
assert summary["direct_cost_observed"] == 1
|
||||
assert summary["direct_cost_complete"] == 1
|
||||
assert summary["model_call_records"] == 1
|
||||
assert summary["usage_records"] == 1
|
||||
assert summary["direct_cost_records"] == 1
|
||||
assert summary["cost_source"] == "provider"
|
||||
|
||||
|
||||
async def test_tracking_chat_model_marks_direct_cost_incomplete_when_usage_missing() -> (
|
||||
None
|
||||
):
|
||||
model = TrackingChatModel(cast(Any, _FakeModelWithoutUsage()))
|
||||
|
||||
await model("prompt")
|
||||
|
||||
summary = model.usage_summary()
|
||||
assert summary["model_call_records"] == 1
|
||||
assert summary["usage_records"] == 0
|
||||
assert summary["direct_cost_records"] == 0
|
||||
assert summary["direct_cost_complete"] == 0
|
||||
Reference in New Issue
Block a user