feat: 任务详情 LLM 请求数(cost_records 存 completions)
This commit is contained in:
1 parent
2ff8975f43
commit
ccb5a8638d
9 files changed
+215
-77
No files matched your search
@@ -140,7 +140,8 @@ class TestCostStore(unittest.TestCase):
|
||||
def test_record_computes_total_and_day(self):
|
||||
row_id = self.store.record(
|
||||
"t1", "p1", "gpt-6.1-sol", input_tokens=100, output_tokens=50,
|
||||
usd_micros=2000, source="actual", fallback_count=1)
|
||||
usd_micros=2000, source="actual", fallback_count=1,
|
||||
completions=7)
|
||||
self.assertIsInstance(row_id, int)
|
||||
report = self.store.report_by_task("t1")
|
||||
self.assertEqual(report["total_tokens"], 150)
|
||||
@@ -149,6 +150,16 @@ class TestCostStore(unittest.TestCase):
|
||||
self.assertEqual(report["fallback_count"], 1)
|
||||
self.assertEqual(report["actual_tokens"], 150)
|
||||
self.assertEqual(report["estimated_tokens"], 0)
|
||||
self.assertEqual(report["llm_requests"], 7)
|
||||
|
||||
def test_llm_requests_sums_completions_not_turns(self):
|
||||
self.store.record("t1", "p1", "m", input_tokens=10,
|
||||
output_tokens=0, source="actual", completions=3)
|
||||
self.store.record("t1", "p1", "m", input_tokens=20,
|
||||
output_tokens=0, source="actual", completions=5)
|
||||
report = self.store.report_by_task("t1")
|
||||
self.assertEqual(report["turns"], 2)
|
||||
self.assertEqual(report["llm_requests"], 8)
|
||||
|
||||
def test_invalid_source_rejected(self):
|
||||
with self.assertRaises(ValueError):
|
||||
@@ -196,6 +207,7 @@ class TestCostStore(unittest.TestCase):
|
||||
"estimated_tokens": 0,
|
||||
"cached_input_tokens": 0,
|
||||
"unpriced_actual_tokens": 0,
|
||||
"llm_requests": 0,
|
||||
})
|
||||
|
||||
|
||||
|
||||
@@ -359,5 +359,63 @@ class MCPTest(unittest.TestCase):
|
||||
self.assertIn(name, names)
|
||||
|
||||
|
||||
class LineReaderTest(unittest.TestCase):
|
||||
"""Pipelined stdin lines must all arrive (no select starvation).
|
||||
|
||||
Regression test for the live failure where the MCP answered
|
||||
initialize and then hung forever: the client wrote
|
||||
notifications/initialized + tools/call back-to-back, one
|
||||
readline() buffered both, and select() never saw the second
|
||||
line again because the fd was drained.
|
||||
"""
|
||||
|
||||
def test_pipelined_lines_all_delivered(self):
|
||||
import time
|
||||
from playwright_mcp import _LineReader
|
||||
rfd, wfd = os.pipe()
|
||||
try:
|
||||
reader = _LineReader(rfd)
|
||||
os.write(wfd, b"init\n")
|
||||
lines, drained = reader.poll()
|
||||
self.assertEqual(lines, ["init"])
|
||||
self.assertFalse(drained)
|
||||
# Second batch arrives as one write, like a real client
|
||||
# sending notification + next request back-to-back.
|
||||
os.write(wfd, b"notif\nnavigate\n")
|
||||
# Simulate the drain-loop delay: both lines sit in the
|
||||
# pipe before the next poll.
|
||||
time.sleep(0.2)
|
||||
got = []
|
||||
deadline = time.time() + 2
|
||||
while len(got) < 2 and time.time() < deadline:
|
||||
lines, drained = reader.poll()
|
||||
got.extend(lines)
|
||||
if not lines:
|
||||
time.sleep(0.02)
|
||||
self.assertEqual(got, ["notif", "navigate"])
|
||||
finally:
|
||||
os.close(wfd)
|
||||
os.close(rfd)
|
||||
|
||||
def test_partial_line_flushed_at_eof(self):
|
||||
from playwright_mcp import _LineReader
|
||||
rfd, wfd = os.pipe()
|
||||
try:
|
||||
reader = _LineReader(rfd)
|
||||
os.write(wfd, b"partial-no-newline")
|
||||
os.close(wfd)
|
||||
lines, drained = reader.poll()
|
||||
self.assertEqual(lines, [])
|
||||
self.assertFalse(drained)
|
||||
lines, drained = reader.poll()
|
||||
self.assertEqual(lines, ["partial-no-newline"])
|
||||
self.assertTrue(drained)
|
||||
finally:
|
||||
try:
|
||||
os.close(rfd)
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main()
|
||||
Reference in new issue
Block a user