fix(claude-hook): derive span durations from start timestamps
This commit is contained in:
@@ -331,6 +331,8 @@ async function handleToolStart(input) {
|
||||
if (spanKey) {
|
||||
activeSpans.set(spanKey, spanId);
|
||||
state.spans[spanKey] = spanId;
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId)
|
||||
state.runId = runId;
|
||||
if (sessionKey)
|
||||
@@ -358,7 +360,13 @@ async function handleToolEnd(input) {
|
||||
const spanId = spanKey ? activeSpans.get(spanKey) || state.spans[spanKey] : void 0;
|
||||
const result = isRecord(input.result) ? input.result : isRecord(input.output) ? input.output : {};
|
||||
const success = !result.error;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : void 0;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : void 0);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey)
|
||||
saveState(sessionKey, state);
|
||||
}
|
||||
enqueue(buildEnvelope("span.end", sessionKey, {
|
||||
runId,
|
||||
spanId,
|
||||
@@ -387,6 +395,8 @@ async function handleSubagentStart(input) {
|
||||
if (sessionKey) {
|
||||
activeSubagents.set(sessionKey, { name: agentName, spanId });
|
||||
state.subagent = { name: agentName, spanId };
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId)
|
||||
state.runId = runId;
|
||||
saveState(sessionKey, state);
|
||||
@@ -412,8 +422,14 @@ async function handleSubagentStop(input) {
|
||||
const subagent = sessionKey ? activeSubagents.get(sessionKey) || state.subagent : void 0;
|
||||
const spanId = subagent?.spanId;
|
||||
const agentName = subagent?.name || pickString(input.agent, input.agent_name) || "unknown";
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : void 0;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : void 0);
|
||||
const usage = getUsage(input);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey)
|
||||
saveState(sessionKey, state);
|
||||
}
|
||||
enqueue(buildEnvelope("span.end", sessionKey, {
|
||||
runId,
|
||||
spanId,
|
||||
@@ -439,6 +455,8 @@ async function handleCompactStart(input) {
|
||||
if (sessionKey) {
|
||||
activeSpans.set(sessionKey + ":compact", spanId);
|
||||
state.compactSpanId = spanId;
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId)
|
||||
state.runId = runId;
|
||||
saveState(sessionKey, state);
|
||||
@@ -459,8 +477,14 @@ async function handleCompactEnd(input) {
|
||||
const runId = sessionKey ? activeRuns.get(sessionKey) || state.runId : void 0;
|
||||
const spanKey = sessionKey ? sessionKey + ":compact" : void 0;
|
||||
const spanId = spanKey ? activeSpans.get(spanKey) || state.compactSpanId : void 0;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : void 0;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : void 0);
|
||||
const contextWindow = getContextWindow(input);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey)
|
||||
saveState(sessionKey, state);
|
||||
}
|
||||
enqueue(buildEnvelope("span.end", sessionKey, {
|
||||
runId,
|
||||
spanId,
|
||||
|
||||
@@ -17,6 +17,7 @@ interface Dict { [key: string]: any }
|
||||
interface SessionState {
|
||||
runId?: string;
|
||||
spans: { [key: string]: string }; // key = sessionKey:toolName, value = spanId
|
||||
spanStartTimes?: { [spanId: string]: number }; // spanId -> epoch ms
|
||||
subagent?: { name: string; spanId: string };
|
||||
compactSpanId?: string;
|
||||
}
|
||||
@@ -385,6 +386,8 @@ async function handleToolStart(input: Dict) {
|
||||
if (spanKey) {
|
||||
activeSpans.set(spanKey, spanId);
|
||||
state.spans[spanKey] = spanId;
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId) state.runId = runId;
|
||||
if (sessionKey) saveState(sessionKey, state);
|
||||
}
|
||||
@@ -413,7 +416,12 @@ async function handleToolEnd(input: Dict) {
|
||||
const spanId = spanKey ? (activeSpans.get(spanKey) || state.spans[spanKey]) : undefined;
|
||||
const result = isRecord(input.result) ? input.result : isRecord(input.output) ? input.output : {};
|
||||
const success = !result.error;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : undefined;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : undefined);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey) saveState(sessionKey, state);
|
||||
}
|
||||
|
||||
enqueue(buildEnvelope('span.end', sessionKey, {
|
||||
runId,
|
||||
@@ -448,6 +456,8 @@ async function handleSubagentStart(input: Dict) {
|
||||
if (sessionKey) {
|
||||
activeSubagents.set(sessionKey, { name: agentName, spanId });
|
||||
state.subagent = { name: agentName, spanId };
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId) state.runId = runId;
|
||||
saveState(sessionKey, state);
|
||||
}
|
||||
@@ -475,8 +485,13 @@ async function handleSubagentStop(input: Dict) {
|
||||
const subagent = sessionKey ? (activeSubagents.get(sessionKey) || state.subagent) : undefined;
|
||||
const spanId = subagent?.spanId;
|
||||
const agentName = subagent?.name || pickString(input.agent, input.agent_name) || 'unknown';
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : undefined;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : undefined);
|
||||
const usage = getUsage(input);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey) saveState(sessionKey, state);
|
||||
}
|
||||
|
||||
enqueue(buildEnvelope('span.end', sessionKey, {
|
||||
runId,
|
||||
@@ -507,6 +522,8 @@ async function handleCompactStart(input: Dict) {
|
||||
if (sessionKey) {
|
||||
activeSpans.set(sessionKey + ':compact', spanId);
|
||||
state.compactSpanId = spanId;
|
||||
state.spanStartTimes = state.spanStartTimes || {};
|
||||
state.spanStartTimes[spanId] = Date.now();
|
||||
if (runId) state.runId = runId;
|
||||
saveState(sessionKey, state);
|
||||
}
|
||||
@@ -529,8 +546,13 @@ async function handleCompactEnd(input: Dict) {
|
||||
const runId = sessionKey ? (activeRuns.get(sessionKey) || state.runId) : undefined;
|
||||
const spanKey = sessionKey ? sessionKey + ':compact' : undefined;
|
||||
const spanId = spanKey ? (activeSpans.get(spanKey) || state.compactSpanId) : undefined;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms);
|
||||
const startTime = spanId ? state.spanStartTimes?.[spanId] : undefined;
|
||||
const duration = pickNumber(input.duration_ms, input.elapsed_ms) ?? (startTime ? Date.now() - startTime : undefined);
|
||||
const contextWindow = getContextWindow(input);
|
||||
if (spanId && state.spanStartTimes) {
|
||||
delete state.spanStartTimes[spanId];
|
||||
if (sessionKey) saveState(sessionKey, state);
|
||||
}
|
||||
|
||||
enqueue(buildEnvelope('span.end', sessionKey, {
|
||||
runId,
|
||||
|
||||
Reference in New Issue
Block a user