v2 Phase 4: add "generated" (output) tokens under the total on Session
The total is ~97% cache reads, which reads as implausibly large on its own.
Show the cache-inclusive total as the headline token number and the output
tokens ("what Claude actually generated", ~1.1M) as a small line beneath it —
impressive total, believable sub-number. Daemon sends a new `to` field; firmware
parses output_today and renders it. Re-spaced the Session layout for the 5th row.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -90,6 +90,7 @@ def compute_today_usage() -> dict:
|
|||||||
today = datetime.date.today()
|
today = datetime.date.today()
|
||||||
midnight = datetime.datetime.combine(today, datetime.time.min)
|
midnight = datetime.datetime.combine(today, datetime.time.min)
|
||||||
total_tokens = 0
|
total_tokens = 0
|
||||||
|
output_tokens = 0
|
||||||
cost = 0.0
|
cost = 0.0
|
||||||
messages = 0
|
messages = 0
|
||||||
try:
|
try:
|
||||||
@@ -133,13 +134,15 @@ def compute_today_usage() -> dict:
|
|||||||
cw = usage.get("cache_creation_input_tokens", 0) or 0
|
cw = usage.get("cache_creation_input_tokens", 0) or 0
|
||||||
cr = usage.get("cache_read_input_tokens", 0) or 0
|
cr = usage.get("cache_read_input_tokens", 0) or 0
|
||||||
total_tokens += inp + out + cw + cr
|
total_tokens += inp + out + cw + cr
|
||||||
|
output_tokens += out
|
||||||
messages += 1
|
messages += 1
|
||||||
p = _price_for(msg.get("model"))
|
p = _price_for(msg.get("model"))
|
||||||
cost += (inp * p["in"] + out * p["out"]
|
cost += (inp * p["in"] + out * p["out"]
|
||||||
+ cw * p["cache_w"] + cr * p["cache_r"]) / 1_000_000
|
+ cw * p["cache_w"] + cr * p["cache_r"]) / 1_000_000
|
||||||
except OSError:
|
except OSError:
|
||||||
continue
|
continue
|
||||||
return {"tk": int(total_tokens), "tc": int(round(cost * 100)), "tn": messages}
|
return {"tk": int(total_tokens), "tc": int(round(cost * 100)),
|
||||||
|
"tn": messages, "to": int(output_tokens)}
|
||||||
|
|
||||||
|
|
||||||
def _build_file_logger() -> logging.Logger | None:
|
def _build_file_logger() -> logging.Logger | None:
|
||||||
|
|||||||
+2
-1
@@ -13,6 +13,7 @@ struct UsageData {
|
|||||||
// Today's Claude Code usage (Phase 4 — computed by the daemon from local
|
// Today's Claude Code usage (Phase 4 — computed by the daemon from local
|
||||||
// transcripts). Tokens can exceed 2^31 on a heavy day, so use 64-bit.
|
// transcripts). Tokens can exceed 2^31 on a heavy day, so use 64-bit.
|
||||||
long long tokens_today; // total tokens today (input+output+cache)
|
long long tokens_today; // total tokens today (input+output+cache)
|
||||||
|
long long output_today; // output tokens today (what Claude generated)
|
||||||
int cost_cents_today; // equivalent API cost today, US cents
|
int cost_cents_today; // equivalent API cost today, US cents
|
||||||
int messages_today; // assistant messages today
|
int messages_today; // assistant requests (API turns) today
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -113,6 +113,7 @@ static bool parse_json(const char* json, UsageData* out) {
|
|||||||
strlcpy(out->status, doc["st"] | "unknown", sizeof(out->status));
|
strlcpy(out->status, doc["st"] | "unknown", sizeof(out->status));
|
||||||
out->ok = doc["ok"] | false;
|
out->ok = doc["ok"] | false;
|
||||||
out->tokens_today = doc["tk"] | (long long)0;
|
out->tokens_today = doc["tk"] | (long long)0;
|
||||||
|
out->output_today = doc["to"] | (long long)0;
|
||||||
out->cost_cents_today = doc["tc"] | 0;
|
out->cost_cents_today = doc["tc"] | 0;
|
||||||
out->messages_today = doc["tn"] | 0;
|
out->messages_today = doc["tn"] | 0;
|
||||||
out->valid = true;
|
out->valid = true;
|
||||||
|
|||||||
+13
-4
@@ -132,6 +132,7 @@ static lv_obj_t* bt_mac_lbl;
|
|||||||
static lv_obj_t* session_container; // today's tokens / cost
|
static lv_obj_t* session_container; // today's tokens / cost
|
||||||
static lv_obj_t* sess_cost_lbl;
|
static lv_obj_t* sess_cost_lbl;
|
||||||
static lv_obj_t* sess_tokens_lbl;
|
static lv_obj_t* sess_tokens_lbl;
|
||||||
|
static lv_obj_t* sess_gen_lbl;
|
||||||
static lv_obj_t* sess_msgs_lbl;
|
static lv_obj_t* sess_msgs_lbl;
|
||||||
|
|
||||||
// App registry — the launcher renders one tile per entry, so adding a screen is
|
// App registry — the launcher renders one tile per entry, so adding a screen is
|
||||||
@@ -704,25 +705,31 @@ static void init_session_screen(lv_obj_t* scr) {
|
|||||||
lv_label_set_text(sess_cost_lbl, "$0.00");
|
lv_label_set_text(sess_cost_lbl, "$0.00");
|
||||||
lv_obj_set_style_text_font(sess_cost_lbl, &font_tiempos_56, 0);
|
lv_obj_set_style_text_font(sess_cost_lbl, &font_tiempos_56, 0);
|
||||||
lv_obj_set_style_text_color(sess_cost_lbl, COL_TEXT, 0);
|
lv_obj_set_style_text_color(sess_cost_lbl, COL_TEXT, 0);
|
||||||
lv_obj_align(sess_cost_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 30);
|
lv_obj_align(sess_cost_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 25);
|
||||||
|
|
||||||
lv_obj_t* sub = lv_label_create(session_container);
|
lv_obj_t* sub = lv_label_create(session_container);
|
||||||
lv_label_set_text(sub, "spent today");
|
lv_label_set_text(sub, "spent today");
|
||||||
lv_obj_set_style_text_font(sub, &font_styrene_20, 0);
|
lv_obj_set_style_text_font(sub, &font_styrene_20, 0);
|
||||||
lv_obj_set_style_text_color(sub, COL_DIM, 0);
|
lv_obj_set_style_text_color(sub, COL_DIM, 0);
|
||||||
lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, L.content_y + 110);
|
lv_obj_align(sub, LV_ALIGN_TOP_MID, 0, L.content_y + 105);
|
||||||
|
|
||||||
sess_tokens_lbl = lv_label_create(session_container);
|
sess_tokens_lbl = lv_label_create(session_container);
|
||||||
lv_label_set_text(sess_tokens_lbl, "\xE2\x80\x94 tokens");
|
lv_label_set_text(sess_tokens_lbl, "\xE2\x80\x94 tokens");
|
||||||
lv_obj_set_style_text_font(sess_tokens_lbl, &font_styrene_28, 0);
|
lv_obj_set_style_text_font(sess_tokens_lbl, &font_styrene_28, 0);
|
||||||
lv_obj_set_style_text_color(sess_tokens_lbl, COL_ACCENT, 0);
|
lv_obj_set_style_text_color(sess_tokens_lbl, COL_ACCENT, 0);
|
||||||
lv_obj_align(sess_tokens_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 165);
|
lv_obj_align(sess_tokens_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 152);
|
||||||
|
|
||||||
|
sess_gen_lbl = lv_label_create(session_container);
|
||||||
|
lv_label_set_text(sess_gen_lbl, "\xE2\x80\x94 generated");
|
||||||
|
lv_obj_set_style_text_font(sess_gen_lbl, &font_styrene_16, 0);
|
||||||
|
lv_obj_set_style_text_color(sess_gen_lbl, COL_DIM, 0);
|
||||||
|
lv_obj_align(sess_gen_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 192);
|
||||||
|
|
||||||
sess_msgs_lbl = lv_label_create(session_container);
|
sess_msgs_lbl = lv_label_create(session_container);
|
||||||
lv_label_set_text(sess_msgs_lbl, "\xE2\x80\x94 requests");
|
lv_label_set_text(sess_msgs_lbl, "\xE2\x80\x94 requests");
|
||||||
lv_obj_set_style_text_font(sess_msgs_lbl, &font_styrene_20, 0);
|
lv_obj_set_style_text_font(sess_msgs_lbl, &font_styrene_20, 0);
|
||||||
lv_obj_set_style_text_color(sess_msgs_lbl, COL_DIM, 0);
|
lv_obj_set_style_text_color(sess_msgs_lbl, COL_DIM, 0);
|
||||||
lv_obj_align(sess_msgs_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 215);
|
lv_obj_align(sess_msgs_lbl, LV_ALIGN_TOP_MID, 0, L.content_y + 232);
|
||||||
|
|
||||||
lv_obj_add_flag(session_container, LV_OBJ_FLAG_HIDDEN);
|
lv_obj_add_flag(session_container, LV_OBJ_FLAG_HIDDEN);
|
||||||
}
|
}
|
||||||
@@ -805,6 +812,8 @@ void ui_update(const UsageData* data) {
|
|||||||
data->cost_cents_today / 100, data->cost_cents_today % 100);
|
data->cost_cents_today / 100, data->cost_cents_today % 100);
|
||||||
format_tokens(data->tokens_today, buf, sizeof(buf));
|
format_tokens(data->tokens_today, buf, sizeof(buf));
|
||||||
lv_label_set_text_fmt(sess_tokens_lbl, "%s tokens", buf);
|
lv_label_set_text_fmt(sess_tokens_lbl, "%s tokens", buf);
|
||||||
|
format_tokens(data->output_today, buf, sizeof(buf));
|
||||||
|
lv_label_set_text_fmt(sess_gen_lbl, "%s generated", buf);
|
||||||
lv_label_set_text_fmt(sess_msgs_lbl, "%d requests", data->messages_today);
|
lv_label_set_text_fmt(sess_msgs_lbl, "%d requests", data->messages_today);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user