Problem
Asynchronous video generation records a permanent quantity=0 usage row that is never reconciled.
VideoToolCore meters with record_media_seconds(...) at video_tool.py:736, taking the duration from result.get("duration"). For Ark calls started with wait_for_result=False, ark.py:354-362 returns created-task metadata only — status: "created", no duration key. coerce_duration therefore yields None, and the row is written as seconds with quantity=0.
That is the correct immediate behaviour (the unit must stay stable, and a call that happened must be recorded), but there is currently no completion path: no provider-task key on the row, no pending event, no callback, and no later true-up. TaskTracker can persist and report the zero row as final.
Impact
Every asynchronous video generation is under-billed — the provider generates and charges for the video, and the usage row permanently reads zero seconds.
Suggested fix
One of:
- Require metered video calls to wait for a terminal duration.
- Use the requested duration as the billed quantity, but only where the provider contract guarantees that is what is billed.
- Persist a pending event keyed by provider task ID and reconcile it exactly once at completion.
Option 3 preserves current async behaviour and is the most faithful, but needs a reconciliation store and exactly-once semantics.
Context
Raised in review of #1425 (Root B). Deferred from that PR: the fix is a new pending/reconciliation mechanism touching billing settlement semantics, well beyond that PR's scope of metering audio/video against the merged primitives (#1527).
Previously noted on #997 (issue comment 5090613906, inline/review history 3662326661, 4796045078).
Relevant code: src/xagent/core/tools/core/video_tool.py:734-742, src/xagent/core/model/video/ark.py:354-362
Problem
Asynchronous video generation records a permanent
quantity=0usage row that is never reconciled.VideoToolCoremeters withrecord_media_seconds(...)atvideo_tool.py:736, taking the duration fromresult.get("duration"). For Ark calls started withwait_for_result=False,ark.py:354-362returns created-task metadata only —status: "created", nodurationkey.coerce_durationtherefore yieldsNone, and the row is written as seconds withquantity=0.That is the correct immediate behaviour (the unit must stay stable, and a call that happened must be recorded), but there is currently no completion path: no provider-task key on the row, no pending event, no callback, and no later true-up.
TaskTrackercan persist and report the zero row as final.Impact
Every asynchronous video generation is under-billed — the provider generates and charges for the video, and the usage row permanently reads zero seconds.
Suggested fix
One of:
Option 3 preserves current async behaviour and is the most faithful, but needs a reconciliation store and exactly-once semantics.
Context
Raised in review of #1425 (Root B). Deferred from that PR: the fix is a new pending/reconciliation mechanism touching billing settlement semantics, well beyond that PR's scope of metering audio/video against the merged primitives (#1527).
Previously noted on #997 (issue comment 5090613906, inline/review history 3662326661, 4796045078).
Relevant code:
src/xagent/core/tools/core/video_tool.py:734-742,src/xagent/core/model/video/ark.py:354-362