@chatpanel/events 0.91.0 → 0.91.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +1 -1
- package/package.json +1 -1
- package/team-record.js +29 -0
package/index.js
CHANGED
|
@@ -197,7 +197,7 @@ export { fixedPlan, parsePlan, plannerPrompt, waves, breakCycles, TEAM_PLAN_SCHE
|
|
|
197
197
|
export { createBoard, parseFindings, boardText, findingsInstruction, toBriefClaims, FINDINGS_SCHEMA, FINDING_KINDS, THREAD_KINDS, THREAD_STATUSES, POST_KINDS, POST_STATUSES, ASK_TYPES, emptyBoardState, foldBoard, findingsOf } from './team-board.js';
|
|
198
198
|
export { boardToolProvider, boardToolSpec, createAnswerBox, withBoardTool, BOARD_TOOL_NAME, DEFAULT_ASK_TIMEOUT_MS } from './board-tool.js';
|
|
199
199
|
export { createRunCache, withRunCache } from './team-cache.js';
|
|
200
|
-
export { emptyRun, foldRun, runFromEvents, checkpointFrom, isResumable, LIVE_RUN_STATUSES, RESUMABLE_RUN_STATUSES } from './team-record.js';
|
|
200
|
+
export { emptyRun, foldRun, runFromEvents, checkpointFrom, isResumable, LIVE_RUN_STATUSES, RESUMABLE_RUN_STATUSES , spendOf, describeSpend } from './team-record.js';
|
|
201
201
|
export { validateProject, normalizeProject, defineProject, canTransition as canProjectTransition, blankProject, projectFromForm, emptyProjectRecord, foldProject, projectProgress, ProjectError, PROJECT_STATUSES, PROJECT_ID_RE } from './project.js';
|
|
202
202
|
// Job POSTINGS (F8 §12) — `jobs.js` is the scheduler and keeps `defineJob`; a posting is a JobPost here.
|
|
203
203
|
export { validateJob as validateJobPost, normalizeJob as normalizeJobPost, defineJob as defineJobPost, canTransition as canJobPostTransition, applyAll, jobToRole, readyJobs, blankJob as blankJobPost, jobFromForm as jobPostFromForm, JobError as JobPostError, JOB_STATUSES as JOB_POST_STATUSES, JOB_ID_RE as JOB_POST_ID_RE } from './job.js';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@chatpanel/events",
|
|
3
|
-
"version": "0.91.
|
|
3
|
+
"version": "0.91.1",
|
|
4
4
|
"description": "The canonical ChatPanel event-log and capability contracts \u2014 typed durable facts, clock-free deterministic linearization, schema upcasting, and the invariants the replay harness asserts. Pure, dependency-free ESM shared by the ChatPanel extension, gateway and bridge.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.js",
|
package/team-record.js
CHANGED
|
@@ -122,3 +122,32 @@ export function isResumable(run) {
|
|
|
122
122
|
if (RESUMABLE_RUN_STATUSES.includes(run.status)) return true;
|
|
123
123
|
return !!run.stale && LIVE_RUN_STATUSES.includes(run.status); // its client went away mid-run
|
|
124
124
|
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* The run's spend against its cap, as a board shows it: the record's last `run.usage` (or
|
|
128
|
+
* nothing spent yet) with `ms` measured LIVE for a run still going — the stored figure is as
|
|
129
|
+
* of the last task's end, and a board read "0 s" through a ten-minute research task.
|
|
130
|
+
*/
|
|
131
|
+
export function spendOf(run, { now = Date.now() } = {}) {
|
|
132
|
+
const cap = run?.usage?.cap || run?.budget || null;
|
|
133
|
+
if (!cap || !Object.keys(cap).length) return null;
|
|
134
|
+
const spent = { tokens: 0, calls: 0, usd: 0, ms: 0, ...(run?.usage?.spent || {}) };
|
|
135
|
+
if (LIVE_RUN_STATUSES.includes(run?.status) && run?.startedAt) spent.ms = Math.max(spent.ms || 0, now - run.startedAt);
|
|
136
|
+
const pct = cap.tokens ? Math.min(100, Math.round(((spent.tokens || 0) / cap.tokens) * 100)) : cap.ms ? Math.min(100, Math.round(((spent.ms || 0) / cap.ms) * 100)) : null;
|
|
137
|
+
return { cap, spent, pct, exhausted: run?.usage?.exhausted || null };
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const secs = (ms) => { const s = Math.max(0, Math.round((Number(ms) || 0) / 1000)); return s >= 60 ? `${Math.floor(s / 60)}m${String(s % 60).padStart(2, '0')}s` : `${s}s`; };
|
|
141
|
+
const num = (n) => (Number(n) || 0).toLocaleString('en-US');
|
|
142
|
+
|
|
143
|
+
/** One line: `1,240 / 40,000 tokens · 3 / 20 calls · 2m10s / 15m00s`. Only the capped dimensions. */
|
|
144
|
+
export function describeSpend(spend) {
|
|
145
|
+
if (!spend?.cap) return '';
|
|
146
|
+
const { cap, spent } = spend;
|
|
147
|
+
return [
|
|
148
|
+
cap.tokens ? `${num(spent.tokens)} / ${num(cap.tokens)} tokens` : '',
|
|
149
|
+
cap.calls ? `${num(spent.calls)} / ${num(cap.calls)} calls` : '',
|
|
150
|
+
cap.usd ? `$${(Number(spent.usd) || 0).toFixed(2)} / $${Number(cap.usd).toFixed(2)}` : '',
|
|
151
|
+
cap.ms ? `${secs(spent.ms)} / ${secs(cap.ms)}` : '',
|
|
152
|
+
].filter(Boolean).join(' · ');
|
|
153
|
+
}
|