generated from coulomb/repo-seed
Fixed and improved token tracking
This commit is contained in:
@@ -75,23 +75,47 @@ async def update_task(
|
||||
if task is None:
|
||||
raise HTTPException(status_code=404, detail="Task not found")
|
||||
|
||||
previous_status = task.status.value
|
||||
|
||||
# Separate token fields from task fields
|
||||
token_field_names = {"tokens_in", "tokens_out", "workplan_tokens_in", "workplan_tokens_out", "token_note", "model", "agent", "session_id"}
|
||||
token_field_names = {
|
||||
"tokens_in",
|
||||
"tokens_out",
|
||||
"workplan_tokens_in",
|
||||
"workplan_tokens_out",
|
||||
"token_note",
|
||||
"model",
|
||||
"agent",
|
||||
"session_id",
|
||||
"suppress_token_event",
|
||||
}
|
||||
update_data = body.model_dump(exclude_unset=True)
|
||||
token_data = {k: update_data.pop(k) for k in list(update_data.keys()) if k in token_field_names}
|
||||
suppress_token_event = bool(token_data.pop("suppress_token_event", False))
|
||||
|
||||
for field, value in update_data.items():
|
||||
setattr(task, field, value)
|
||||
await session.commit()
|
||||
await session.refresh(task)
|
||||
|
||||
# Token event — three-tier logic, only when marking done
|
||||
if update_data.get("status") == "done":
|
||||
# Token event — three-tier logic, only for an intentional transition to done.
|
||||
status_update = update_data.get("status")
|
||||
new_status = status_update.value if hasattr(status_update, "value") else status_update
|
||||
if (
|
||||
new_status == "done"
|
||||
and previous_status != "done"
|
||||
and not suppress_token_event
|
||||
):
|
||||
if "tokens_in" in token_data and "tokens_out" in token_data:
|
||||
# Tier 1: exact counts — default note "measured"; caller may override with token_note
|
||||
tin = token_data["tokens_in"]
|
||||
tout = token_data["tokens_out"]
|
||||
tnote = token_data.get("token_note") or "measured"
|
||||
measurement_kind = "measured"
|
||||
source_provider = "manual"
|
||||
confidence = 1.0
|
||||
source_id = f"task:{task_id}:manual"
|
||||
raw_metadata = {"input_source": "task_status_patch"}
|
||||
elif "workplan_tokens_in" in token_data and "workplan_tokens_out" in token_data:
|
||||
# Tier 2: prorate workplan total across task count
|
||||
count_result = await session.execute(
|
||||
@@ -101,9 +125,24 @@ async def update_task(
|
||||
tin = token_data["workplan_tokens_in"] // task_count
|
||||
tout = token_data["workplan_tokens_out"] // task_count
|
||||
tnote = "workplan"
|
||||
measurement_kind = "allocated"
|
||||
source_provider = "manual"
|
||||
confidence = 0.7
|
||||
source_id = f"task:{task_id}:workplan-allocation"
|
||||
raw_metadata = {
|
||||
"allocation_method": "workplan_prorated",
|
||||
"workplan_tokens_in": token_data["workplan_tokens_in"],
|
||||
"workplan_tokens_out": token_data["workplan_tokens_out"],
|
||||
"task_count": task_count,
|
||||
}
|
||||
else:
|
||||
# Tier 3: heuristic fallback
|
||||
tin, tout, tnote = 1000, 500, "heuristic"
|
||||
measurement_kind = "estimated"
|
||||
source_provider = "task_fallback"
|
||||
confidence = 0.35
|
||||
source_id = f"task:{task_id}:heuristic"
|
||||
raw_metadata = {"estimation_method": "fixed_task_done_fallback"}
|
||||
|
||||
# Resolve repo_id via workstream
|
||||
ws = await session.get(Workstream, task.workstream_id)
|
||||
@@ -121,6 +160,12 @@ async def update_task(
|
||||
ref_type="task",
|
||||
ref_id=str(task_id),
|
||||
note=tnote,
|
||||
measurement_kind=measurement_kind,
|
||||
source_provider=source_provider,
|
||||
source_id=source_id,
|
||||
confidence=confidence,
|
||||
raw_total_tokens=tin + tout,
|
||||
raw_metadata=raw_metadata,
|
||||
)
|
||||
session.add(event)
|
||||
await session.commit()
|
||||
|
||||
Reference in New Issue
Block a user