feat: v2.8.0 — Artifacts uploads and plugin links, console tab combos, account avatars
- Artifacts hub: upload a file from the computer; make a skill by uploading a Markdown file, files, a folder or a .zip/.skill, or by writing it in the dialog; add plugins by picking from the list a marketplace link answers (POST /api/artifacts/plugin/inspect); Settings → AI tools → Artifacts Hub. - Console tabs are combos of up to four split panes (ConsoleTabs, PaneGrid). - Accounts: an own avatar (PUT/DELETE /api/me/avatar, raster only, ≤ 1 MB, <data dir>/avatars/), shown with name and role at the sidebar's foot and on the workspace owner groups (GET /api/users/:id/avatar, owner_avatar_at). - Users page: per-user storage (GET /api/users/storage, measured in a worker) and account-pool spend/tokens per account (server/lib/pool-usage.js). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -287,9 +287,32 @@ const BUCKET_COLS = ["model", "speed", "inference_geo", "service_tier"];
|
||||
* its session's `tool`, for the per-tool split.
|
||||
*/
|
||||
function dailyTokenRows(tzModifier, whereClause, params) {
|
||||
return bookedTokenRows(
|
||||
{ total: "DATE(s.started_at, ?)", hour: "DATE(h.hour || ':00:00', ?)", args: [tzModifier] },
|
||||
whereClause,
|
||||
params
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* The same booking per UTC hour (`YYYY-MM-DDTHH` in `date`) and per session
|
||||
* (`session_id`): what the account pool sums over a run's own hours. The rest
|
||||
* of a total goes to the session's start hour.
|
||||
*/
|
||||
function hourlyTokenRows(whereClause, params) {
|
||||
return bookedTokenRows(
|
||||
{ total: "substr(s.started_at, 1, 13)", hour: "h.hour", args: [] },
|
||||
whereClause,
|
||||
params,
|
||||
{ bySession: true }
|
||||
);
|
||||
}
|
||||
|
||||
/** `slot.total`/`slot.hour` name the period of a total and of an hourly row (`slot.args` bound once each). */
|
||||
function bookedTokenRows(slot, whereClause, params, { bySession = false } = {}) {
|
||||
const totals = db
|
||||
.prepare(
|
||||
`SELECT tu.session_id, DATE(s.started_at, ?) as date, s.tool,
|
||||
`SELECT tu.session_id, ${slot.total} as date, s.tool,
|
||||
${BUCKET_COLS.map((c) => `tu.${c}`).join(", ")},
|
||||
tu.input_tokens + tu.baseline_input as input_tokens,
|
||||
tu.output_tokens + tu.baseline_output as output_tokens,
|
||||
@@ -304,10 +327,10 @@ function dailyTokenRows(tzModifier, whereClause, params) {
|
||||
JOIN sessions s ON s.id = tu.session_id
|
||||
${whereClause}`
|
||||
)
|
||||
.all(tzModifier, ...params);
|
||||
.all(...slot.args, ...params);
|
||||
const hourly = db
|
||||
.prepare(
|
||||
`SELECT h.session_id, DATE(h.hour || ':00:00', ?) as date,
|
||||
`SELECT h.session_id, ${slot.hour} as date,
|
||||
${BUCKET_COLS.map((c) => `h.${c}`).join(", ")},
|
||||
${USAGE_COLS.map((c) => `SUM(h.${c}) as ${c}`).join(", ")}
|
||||
FROM token_usage_hourly h
|
||||
@@ -315,7 +338,7 @@ function dailyTokenRows(tzModifier, whereClause, params) {
|
||||
${whereClause}
|
||||
GROUP BY h.session_id, 2, ${BUCKET_COLS.map((c) => `h.${c}`).join(", ")}`
|
||||
)
|
||||
.all(tzModifier, ...params);
|
||||
.all(...slot.args, ...params);
|
||||
|
||||
const keyOf = (r) => [r.session_id, ...BUCKET_COLS.map((c) => r[c])].join("\u0001");
|
||||
const hoursByBucket = new Map();
|
||||
@@ -327,12 +350,18 @@ function dailyTokenRows(tzModifier, whereClause, params) {
|
||||
|
||||
const out = new Map();
|
||||
const add = (date, bucket, values) => {
|
||||
const k = [date, bucket.tool, ...BUCKET_COLS.map((c) => bucket[c])].join("\u0001");
|
||||
const k = [
|
||||
date,
|
||||
bucket.tool,
|
||||
...(bySession ? [bucket.session_id] : []),
|
||||
...BUCKET_COLS.map((c) => bucket[c]),
|
||||
].join("\u0001");
|
||||
let row = out.get(k);
|
||||
if (!row) {
|
||||
row = {
|
||||
date,
|
||||
tool: bucket.tool,
|
||||
...(bySession ? { session_id: bucket.session_id } : {}),
|
||||
...Object.fromEntries(BUCKET_COLS.map((c) => [c, bucket[c]])),
|
||||
};
|
||||
for (const c of USAGE_COLS) row[c] = 0;
|
||||
@@ -697,6 +726,7 @@ function attachAgentCosts(agents) {
|
||||
module.exports = router;
|
||||
module.exports.calculateCost = calculateCost;
|
||||
module.exports.dailyTokenRows = dailyTokenRows;
|
||||
module.exports.hourlyTokenRows = hourlyTokenRows;
|
||||
module.exports.costWhere = costWhere;
|
||||
module.exports.computeCost = computeCost;
|
||||
module.exports.agentOwnCost = agentOwnCost;
|
||||
|
||||
Reference in New Issue
Block a user