ガントで範囲外にはみ出すタスクの全体時間と往復数も範囲内に揃える
表示範囲を絞ったとき、作業時間だけが範囲内に切り詰められ、全体時間・往復数・ ツール呼び出し数はセッション全体の値のままだったので、1日表示に「全体 793時間」 のような数字が並んで読み違えやすかった。 範囲の左端で切れている行は全体時間を「表示範囲の開始→セッション終了」にし、 往復数とツール数も範囲内のターンだけを数える。切り詰めた行には clipped を立て、 ツールチップのラベルを「全体」→「表示範囲内」に変える。開始→終了の日時は 実際の値のままなので、範囲外へ続いていることはそこで分かる。 ガントの CSV にも clipped 列を追加した。 Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
+22
-5
@@ -606,6 +606,9 @@ class Store:
|
||||
"""ガント表示用。セッションを1本のバーとして、内側に応答中の区間を返す。
|
||||
|
||||
spans は各ターンの [発言時刻, 応答完了] を、隙間 1 秒以内なら繋げたもの。
|
||||
表示範囲より前から続いているセッションは、全体時間・往復数・ツール呼び出しも
|
||||
範囲内に切り詰めて返す(作業時間だけ切り詰めると数字が食い違うため)。
|
||||
clipped が真なら切り詰めたもの。
|
||||
"""
|
||||
paths = {p["id"]: p["path"] for p in self.projects()}
|
||||
if project_id:
|
||||
@@ -633,6 +636,8 @@ class Store:
|
||||
continue
|
||||
spans = []
|
||||
active = 0
|
||||
turn_count = 0
|
||||
tool_calls = 0
|
||||
for turn in session["turns"]:
|
||||
a = turn["ts"]
|
||||
if a is None:
|
||||
@@ -641,10 +646,20 @@ class Store:
|
||||
if t0 is not None and b < t0:
|
||||
continue
|
||||
active += turn["durMs"] or 0
|
||||
turn_count += 1
|
||||
tool_calls += turn["toolCalls"]
|
||||
if spans and a - spans[-1][1] <= 1:
|
||||
spans[-1][1] = max(spans[-1][1], b)
|
||||
else:
|
||||
spans.append([a, b])
|
||||
clipped = t0 is not None and start < t0
|
||||
if clipped:
|
||||
# バーが左端で切れているぶん、全体時間も見えている範囲だけにする
|
||||
wall = ms(end if end is not None else start, t0)
|
||||
else:
|
||||
wall = session["wallMs"]
|
||||
turn_count = session["turnCount"]
|
||||
tool_calls = session["toolCalls"]
|
||||
rows.append(
|
||||
{
|
||||
"id": session["id"],
|
||||
@@ -655,10 +670,11 @@ class Store:
|
||||
"end": session["end"],
|
||||
"startEpoch": round(start, 1),
|
||||
"endEpoch": round(end if end is not None else start, 1),
|
||||
"wallMs": session["wallMs"],
|
||||
"wallMs": wall,
|
||||
"activeMs": active,
|
||||
"turnCount": session["turnCount"],
|
||||
"toolCalls": session["toolCalls"],
|
||||
"turnCount": turn_count,
|
||||
"toolCalls": tool_calls,
|
||||
"clipped": clipped,
|
||||
"spans": [[round(a, 1), round(b, 1)] for a, b in spans],
|
||||
}
|
||||
)
|
||||
@@ -862,11 +878,12 @@ def turns_csv(session):
|
||||
def timeline_csv(data):
|
||||
buf = io.StringIO(newline="")
|
||||
writer = csv.writer(buf)
|
||||
writer.writerow(["project", "session_id", "title", "start", "end", "wall", "active", "turns", "tool_calls"])
|
||||
writer.writerow(["project", "session_id", "title", "start", "end", "wall", "active", "turns", "tool_calls", "clipped"])
|
||||
for s in data["sessions"]:
|
||||
writer.writerow(
|
||||
[s["projectPath"], s["id"], s["title"], s["start"] or "", s["end"] or "",
|
||||
fmt_dur(s["wallMs"]), fmt_dur(s["activeMs"]), s["turnCount"], s["toolCalls"]]
|
||||
fmt_dur(s["wallMs"]), fmt_dur(s["activeMs"]), s["turnCount"], s["toolCalls"],
|
||||
"1" if s["clipped"] else ""]
|
||||
)
|
||||
return buf.getvalue()
|
||||
|
||||
|
||||
Reference in New Issue
Block a user