modelstat 0.0.42 → 0.0.43
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/dist/cli.mjs +166 -8
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -4421,7 +4421,15 @@ var init_schemas = __esm({
|
|
|
4421
4421
|
installation_id: external_exports.string(),
|
|
4422
4422
|
identity_id: external_exports.string().nullable()
|
|
4423
4423
|
})
|
|
4424
|
-
).optional()
|
|
4424
|
+
).optional(),
|
|
4425
|
+
/** Optional per-session titles — session_id → short redacted title
|
|
4426
|
+
* (≤120 chars) produced by the companion's local titler from the
|
|
4427
|
+
* session's segment abstracts. Server-side this is last-write-wins
|
|
4428
|
+
* per session; companions recompute it from the full session view on
|
|
4429
|
+
* every upload, so the latest batch always carries the freshest
|
|
4430
|
+
* title. Absent for runtimes without a titler (older agents, no-op
|
|
4431
|
+
* browser summariser) — the server keeps whatever it has. */
|
|
4432
|
+
session_titles: external_exports.record(external_exports.string(), external_exports.string().max(120)).optional()
|
|
4425
4433
|
});
|
|
4426
4434
|
HeartbeatPayload = external_exports.object({
|
|
4427
4435
|
device_id: external_exports.string(),
|
|
@@ -4743,7 +4751,9 @@ async function parseClaudeCodeJsonl(ctx) {
|
|
|
4743
4751
|
if (obj.type === "assistant") {
|
|
4744
4752
|
const a = obj;
|
|
4745
4753
|
const usage = a.message?.usage ?? {};
|
|
4746
|
-
|
|
4754
|
+
if (a.message?.model && a.message.model !== "<synthetic>") {
|
|
4755
|
+
lastModel = a.message.model;
|
|
4756
|
+
}
|
|
4747
4757
|
if (!a.uuid || !sessionId) {
|
|
4748
4758
|
skipped += 1;
|
|
4749
4759
|
continue;
|
|
@@ -44387,6 +44397,89 @@ var init_cognition = __esm({
|
|
|
44387
44397
|
}
|
|
44388
44398
|
});
|
|
44389
44399
|
|
|
44400
|
+
// ../../packages/companion-core/src/pipeline/title.ts
|
|
44401
|
+
function buildTitleUserPrompt(input) {
|
|
44402
|
+
const lines = input.abstracts.map(
|
|
44403
|
+
(a, i) => ` [part ${i + 1}] ${a.replace(/\s+/g, " ").trim().slice(0, TITLER_ABSTRACT_SLICE_CHARS)}`
|
|
44404
|
+
).join("\n");
|
|
44405
|
+
const facts = input.facts?.trim();
|
|
44406
|
+
return `${facts ? `Session context: ${facts}.
|
|
44407
|
+
|
|
44408
|
+
` : ""}Summaries of the session's parts (chronological):
|
|
44409
|
+
${lines}
|
|
44410
|
+
|
|
44411
|
+
Write the title.`;
|
|
44412
|
+
}
|
|
44413
|
+
function stripCognitionSuffix(abstract) {
|
|
44414
|
+
return abstract.replace(/\s*\[(?:Mood|Mind):[^\]]*\]/g, "").trim();
|
|
44415
|
+
}
|
|
44416
|
+
function sanitiseTitle(raw) {
|
|
44417
|
+
if (!raw) return "";
|
|
44418
|
+
const firstLine = raw.replace(/```[a-z]*\n?/gi, "").split(/[\n\r]/).map((l) => l.trim()).find((l) => l.length > 0) ?? "";
|
|
44419
|
+
let t = firstLine.replace(/\s+/g, " ").replace(/^["'`“”]+/, "").replace(/["'`“”]+$/, "").replace(/[.!]+$/, "").trim();
|
|
44420
|
+
if (!t) return "";
|
|
44421
|
+
t = redact(t).text;
|
|
44422
|
+
return t.slice(0, TITLE_MAX_CHARS).trim();
|
|
44423
|
+
}
|
|
44424
|
+
function fallbackTitle(abstracts) {
|
|
44425
|
+
const first = abstracts.find((a) => a.trim().length > 0);
|
|
44426
|
+
if (!first) return "";
|
|
44427
|
+
const sentence = first.split(/(?<=[.!?])\s/, 1)[0] ?? first;
|
|
44428
|
+
return sanitiseTitle(sentence);
|
|
44429
|
+
}
|
|
44430
|
+
function sampleAbstracts(abstracts, max = TITLER_MAX_ABSTRACTS) {
|
|
44431
|
+
if (abstracts.length <= max) return abstracts;
|
|
44432
|
+
const picks = /* @__PURE__ */ new Set([0, abstracts.length - 1]);
|
|
44433
|
+
for (let i = 1; picks.size < max; i++) {
|
|
44434
|
+
picks.add(Math.round(i * (abstracts.length - 1) / (max - 1)));
|
|
44435
|
+
}
|
|
44436
|
+
return [...picks].sort((a, b) => a - b).map((i) => abstracts[i]);
|
|
44437
|
+
}
|
|
44438
|
+
async function buildSessionTitles(segments, entitle) {
|
|
44439
|
+
const bySession = /* @__PURE__ */ new Map();
|
|
44440
|
+
for (const s of segments) {
|
|
44441
|
+
const arr = bySession.get(s.session_id) ?? [];
|
|
44442
|
+
arr.push(s);
|
|
44443
|
+
bySession.set(s.session_id, arr);
|
|
44444
|
+
}
|
|
44445
|
+
const out = {};
|
|
44446
|
+
for (const [sessionId, segs] of bySession) {
|
|
44447
|
+
const sorted = [...segs].sort((a, b) => a.started_at.localeCompare(b.started_at));
|
|
44448
|
+
const abstracts = sorted.map((s) => stripCognitionSuffix(s.abstract)).filter((a) => a.length > 0);
|
|
44449
|
+
if (abstracts.length === 0) continue;
|
|
44450
|
+
let title = "";
|
|
44451
|
+
if (entitle) {
|
|
44452
|
+
const first = sorted[0];
|
|
44453
|
+
const project = first.tags.find((t) => t.root_key === "projects")?.name;
|
|
44454
|
+
const facts = [
|
|
44455
|
+
project ? `repo ${project}` : null,
|
|
44456
|
+
`${sorted.length} part${sorted.length === 1 ? "" : "s"} on ${first.tool}`
|
|
44457
|
+
].filter(Boolean).join("; ");
|
|
44458
|
+
try {
|
|
44459
|
+
title = sanitiseTitle(await entitle({ abstracts: sampleAbstracts(abstracts), facts }));
|
|
44460
|
+
} catch {
|
|
44461
|
+
title = "";
|
|
44462
|
+
}
|
|
44463
|
+
}
|
|
44464
|
+
if (!title) title = fallbackTitle(abstracts);
|
|
44465
|
+
if (title) out[sessionId] = title;
|
|
44466
|
+
}
|
|
44467
|
+
return out;
|
|
44468
|
+
}
|
|
44469
|
+
var TITLER_SYSTEM_PROMPT, TITLE_MAX_CHARS, TITLER_MAX_TOKENS, TITLER_TEMPERATURE, TITLER_MAX_ABSTRACTS, TITLER_ABSTRACT_SLICE_CHARS;
|
|
44470
|
+
var init_title = __esm({
|
|
44471
|
+
"../../packages/companion-core/src/pipeline/title.ts"() {
|
|
44472
|
+
"use strict";
|
|
44473
|
+
init_redact();
|
|
44474
|
+
TITLER_SYSTEM_PROMPT = "You write a short TITLE for an AI coding session, given one-sentence summaries of its parts in chronological order. The title names what the session was about at a high level, in 3-8 words. If the session clearly spans more than one theme, name the top themes (at most 3) separated by ' \xB7 '. Use concrete domain keywords (features, components, subsystems). No narration, no filler words like 'session' or 'work on', no quotes, no trailing period, no PII, no code literals, no file paths. Reply with only the title.";
|
|
44475
|
+
TITLE_MAX_CHARS = 80;
|
|
44476
|
+
TITLER_MAX_TOKENS = 60;
|
|
44477
|
+
TITLER_TEMPERATURE = 0.2;
|
|
44478
|
+
TITLER_MAX_ABSTRACTS = 10;
|
|
44479
|
+
TITLER_ABSTRACT_SLICE_CHARS = 240;
|
|
44480
|
+
}
|
|
44481
|
+
});
|
|
44482
|
+
|
|
44390
44483
|
// ../../packages/companion-core/src/pipeline/index.ts
|
|
44391
44484
|
async function buildSegmentsForSession(events, adapters2, onProgress) {
|
|
44392
44485
|
if (events.length === 0) return [];
|
|
@@ -44682,6 +44775,7 @@ var init_pipeline = __esm({
|
|
|
44682
44775
|
init_redact();
|
|
44683
44776
|
init_prompts();
|
|
44684
44777
|
init_cognition();
|
|
44778
|
+
init_title();
|
|
44685
44779
|
SEGMENT_TIME_GAP_MS = 15 * 6e4;
|
|
44686
44780
|
SEGMENT_TOPIC_THRESHOLD = 0.35;
|
|
44687
44781
|
SEGMENT_MAX_TURNS = 100;
|
|
@@ -45050,6 +45144,9 @@ async function loadOnce(cfg) {
|
|
|
45050
45144
|
const cognizerContext = await model.createContext({
|
|
45051
45145
|
contextSize: Math.min(cfg.contextSize, 2048)
|
|
45052
45146
|
});
|
|
45147
|
+
const entitlerContext = await model.createContext({
|
|
45148
|
+
contextSize: cfg.contextSize
|
|
45149
|
+
});
|
|
45053
45150
|
const summarizer = new llamaMod.LlamaChatSession({
|
|
45054
45151
|
contextSequence: summariserContext.getSequence(),
|
|
45055
45152
|
systemPrompt: SUMMARISER_SYSTEM_PROMPT
|
|
@@ -45058,7 +45155,11 @@ async function loadOnce(cfg) {
|
|
|
45058
45155
|
contextSequence: cognizerContext.getSequence(),
|
|
45059
45156
|
systemPrompt: COGNITION_SYSTEM_PROMPT
|
|
45060
45157
|
});
|
|
45061
|
-
|
|
45158
|
+
const entitler = new llamaMod.LlamaChatSession({
|
|
45159
|
+
contextSequence: entitlerContext.getSequence(),
|
|
45160
|
+
systemPrompt: TITLER_SYSTEM_PROMPT
|
|
45161
|
+
});
|
|
45162
|
+
loaded = { summarizer, cognizer, entitler };
|
|
45062
45163
|
return loaded;
|
|
45063
45164
|
})();
|
|
45064
45165
|
try {
|
|
@@ -45120,12 +45221,41 @@ function llamaCognize(cfg = defaultLlamaConfig()) {
|
|
|
45120
45221
|
}
|
|
45121
45222
|
};
|
|
45122
45223
|
}
|
|
45224
|
+
function llamaEntitle(cfg = defaultLlamaConfig()) {
|
|
45225
|
+
return async (input) => {
|
|
45226
|
+
if (input.abstracts.length === 0) return null;
|
|
45227
|
+
let loadedSessions;
|
|
45228
|
+
try {
|
|
45229
|
+
loadedSessions = await loadOnce(cfg);
|
|
45230
|
+
} catch {
|
|
45231
|
+
return null;
|
|
45232
|
+
}
|
|
45233
|
+
const { entitler } = loadedSessions;
|
|
45234
|
+
const run = inflight.then(async () => {
|
|
45235
|
+
entitler.resetChatHistory();
|
|
45236
|
+
const raw = await entitler.prompt(buildTitleUserPrompt(input), {
|
|
45237
|
+
temperature: TITLER_TEMPERATURE,
|
|
45238
|
+
// Same thinking-budget rationale as the cognition pass: the
|
|
45239
|
+
// answer is tiny but Qwen3.5 reasons first.
|
|
45240
|
+
maxTokens: TITLER_MAX_TOKENS + 400
|
|
45241
|
+
});
|
|
45242
|
+
return stripThinking(raw ?? "") || null;
|
|
45243
|
+
});
|
|
45244
|
+
inflight = run.catch(() => void 0);
|
|
45245
|
+
try {
|
|
45246
|
+
return await run;
|
|
45247
|
+
} catch {
|
|
45248
|
+
return null;
|
|
45249
|
+
}
|
|
45250
|
+
};
|
|
45251
|
+
}
|
|
45123
45252
|
var DEFAULT_LLAMA_MODEL_URL, LLAMA_MAX_TOKENS, loaded, loadPromise, inflight;
|
|
45124
45253
|
var init_llama = __esm({
|
|
45125
45254
|
"../../packages/companion-core/src/node/llama.ts"() {
|
|
45126
45255
|
"use strict";
|
|
45127
45256
|
init_prompts();
|
|
45128
45257
|
init_cognition();
|
|
45258
|
+
init_title();
|
|
45129
45259
|
DEFAULT_LLAMA_MODEL_URL = "https://huggingface.co/lmstudio-community/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf";
|
|
45130
45260
|
LLAMA_MAX_TOKENS = 1024;
|
|
45131
45261
|
loaded = null;
|
|
@@ -45205,6 +45335,7 @@ __export(node_exports, {
|
|
|
45205
45335
|
defaultOllamaConfig: () => defaultOllamaConfig,
|
|
45206
45336
|
ensureLlamaModel: () => ensureLlamaModel,
|
|
45207
45337
|
llamaCognize: () => llamaCognize,
|
|
45338
|
+
llamaEntitle: () => llamaEntitle,
|
|
45208
45339
|
llamaSummarize: () => llamaSummarize,
|
|
45209
45340
|
ollamaCognize: () => ollamaCognize,
|
|
45210
45341
|
ollamaEmbed: () => ollamaEmbed,
|
|
@@ -45322,6 +45453,7 @@ var init_privacy_filter = __esm({
|
|
|
45322
45453
|
var pipeline_exports = {};
|
|
45323
45454
|
__export(pipeline_exports, {
|
|
45324
45455
|
buildSegments: () => buildSegments,
|
|
45456
|
+
buildSessionTitles: () => buildSessionTitles2,
|
|
45325
45457
|
preflightSummariser: () => preflightSummariser
|
|
45326
45458
|
});
|
|
45327
45459
|
async function bundledAdapters() {
|
|
@@ -45337,6 +45469,11 @@ async function bundledAdapters() {
|
|
|
45337
45469
|
summarize: llamaSummarize(llamaCfg),
|
|
45338
45470
|
tokenize: (text) => Math.max(1, Math.ceil(text.length / 4)),
|
|
45339
45471
|
cognize: llamaCognize(llamaCfg),
|
|
45472
|
+
// Session-title pass — same bundled model, third chat session with
|
|
45473
|
+
// TITLER_SYSTEM_PROMPT. One short call per session per upload (the
|
|
45474
|
+
// sessions-list title in the dashboard). Best-effort like cognize:
|
|
45475
|
+
// failures fall back to a deterministic title in buildSessionTitles.
|
|
45476
|
+
entitle: llamaEntitle(llamaCfg),
|
|
45340
45477
|
// Model-based PII redactor (OpenAI Privacy Filter via
|
|
45341
45478
|
// transformers.js / ONNX). Runs locally on CPU after the regex
|
|
45342
45479
|
// pass in packages/core/redact.ts. ~1 GB model downloaded on
|
|
@@ -45366,6 +45503,10 @@ async function getAdapters() {
|
|
|
45366
45503
|
async function buildSegments(events, onProgress) {
|
|
45367
45504
|
return buildSegmentsForSession(events, await getAdapters(), onProgress);
|
|
45368
45505
|
}
|
|
45506
|
+
async function buildSessionTitles2(segments) {
|
|
45507
|
+
const a = await getAdapters();
|
|
45508
|
+
return buildSessionTitles(segments, a.entitle);
|
|
45509
|
+
}
|
|
45369
45510
|
async function preflightSummariser() {
|
|
45370
45511
|
const a = await getAdapters();
|
|
45371
45512
|
const out = await a.summarize({
|
|
@@ -45457,16 +45598,33 @@ async function scanAll(cb = {}) {
|
|
|
45457
45598
|
let segmentsUploaded = 0;
|
|
45458
45599
|
let buffer = [];
|
|
45459
45600
|
let pendingCursors = [];
|
|
45601
|
+
const runSegmentsBySession = /* @__PURE__ */ new Map();
|
|
45460
45602
|
async function flushBatch() {
|
|
45461
45603
|
if (!buffer.length) return;
|
|
45462
45604
|
const events = buffer.map(withNonNullTokens);
|
|
45463
45605
|
const segments = await buildSegments(events, cb.onProgress);
|
|
45606
|
+
for (const seg of segments) {
|
|
45607
|
+
const arr = runSegmentsBySession.get(seg.session_id) ?? [];
|
|
45608
|
+
arr.push(seg);
|
|
45609
|
+
runSegmentsBySession.set(seg.session_id, arr);
|
|
45610
|
+
}
|
|
45611
|
+
const titleInput = [];
|
|
45612
|
+
for (const sessionId of new Set(segments.map((s) => s.session_id))) {
|
|
45613
|
+
titleInput.push(...runSegmentsBySession.get(sessionId) ?? []);
|
|
45614
|
+
}
|
|
45615
|
+
let sessionTitles = {};
|
|
45616
|
+
try {
|
|
45617
|
+
sessionTitles = await buildSessionTitles2(titleInput);
|
|
45618
|
+
} catch (e) {
|
|
45619
|
+
console.warn("session titling failed \u2014 shipping batch untitled:", e.message);
|
|
45620
|
+
}
|
|
45464
45621
|
const batch = {
|
|
45465
45622
|
batch_id: batchId(),
|
|
45466
45623
|
device_id: deviceId,
|
|
45467
45624
|
agent_version: AGENT_VERSION,
|
|
45468
45625
|
events,
|
|
45469
|
-
segments
|
|
45626
|
+
segments,
|
|
45627
|
+
...Object.keys(sessionTitles).length ? { session_titles: sessionTitles } : {}
|
|
45470
45628
|
};
|
|
45471
45629
|
cb.onUpload?.({ events: events.length, segments: segments.length });
|
|
45472
45630
|
const res = await uploadBatch(batch);
|
|
@@ -45513,7 +45671,7 @@ var init_scan = __esm({
|
|
|
45513
45671
|
init_pipeline2();
|
|
45514
45672
|
init_config2();
|
|
45515
45673
|
init_api();
|
|
45516
|
-
AGENT_VERSION = true ? "agent-0.0.
|
|
45674
|
+
AGENT_VERSION = true ? "agent-0.0.43" : "agent-dev";
|
|
45517
45675
|
BATCH_MAX_EVENTS = 2e3;
|
|
45518
45676
|
ZERO_TOKENS = {
|
|
45519
45677
|
input: 0,
|
|
@@ -45704,7 +45862,7 @@ var PROCESSING_VERSION;
|
|
|
45704
45862
|
var init_processing_version = __esm({
|
|
45705
45863
|
"src/processing-version.ts"() {
|
|
45706
45864
|
"use strict";
|
|
45707
|
-
PROCESSING_VERSION =
|
|
45865
|
+
PROCESSING_VERSION = 4;
|
|
45708
45866
|
}
|
|
45709
45867
|
});
|
|
45710
45868
|
|
|
@@ -47713,7 +47871,7 @@ var init_daemon = __esm({
|
|
|
47713
47871
|
init_lock();
|
|
47714
47872
|
init_scan();
|
|
47715
47873
|
init_single_flight();
|
|
47716
|
-
AGENT_VERSION2 = true ? "agent-0.0.
|
|
47874
|
+
AGENT_VERSION2 = true ? "agent-0.0.43" : "agent-dev";
|
|
47717
47875
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
47718
47876
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
47719
47877
|
DISCOVERY_INTERVAL_MS = 6e4;
|
|
@@ -48223,7 +48381,7 @@ function tryOpenBrowser(url) {
|
|
|
48223
48381
|
return false;
|
|
48224
48382
|
}
|
|
48225
48383
|
}
|
|
48226
|
-
var AGENT_VERSION3 = true ? "agent-0.0.
|
|
48384
|
+
var AGENT_VERSION3 = true ? "agent-0.0.43" : "agent-dev";
|
|
48227
48385
|
function osFamily() {
|
|
48228
48386
|
const p = platform4();
|
|
48229
48387
|
if (p === "darwin") return "macos";
|