modelstat 0.0.34 → 0.0.36
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/LICENSE +87 -0
- package/dist/cli.mjs +410 -33
- package/dist/cli.mjs.map +1 -1
- package/package.json +18 -19
- package/vendor/tray-mac/build-app.sh +0 -0
package/dist/cli.mjs
CHANGED
|
@@ -4500,6 +4500,11 @@ var init_schemas = __esm({
|
|
|
4500
4500
|
provider: external_exports.enum(PROVIDERS),
|
|
4501
4501
|
provider_account_id: external_exports.string().max(200),
|
|
4502
4502
|
provider_account_label: external_exports.string().max(200).nullable(),
|
|
4503
|
+
/** Human-facing labels — what the user recognises the account by.
|
|
4504
|
+
* Populated from the keychain blob / OAuth JWT where available. */
|
|
4505
|
+
account_email: external_exports.string().max(200).nullable().optional(),
|
|
4506
|
+
account_org: external_exports.string().max(200).nullable().optional(),
|
|
4507
|
+
display_name: external_exports.string().max(200).nullable().optional(),
|
|
4503
4508
|
owner_scope: external_exports.enum(IDENTITY_OWNER_SCOPES).default("unassigned"),
|
|
4504
4509
|
detection_source: external_exports.string().max(80)
|
|
4505
4510
|
});
|
|
@@ -7302,14 +7307,19 @@ async function probeIdentities(os2) {
|
|
|
7302
7307
|
{ timeout: 3e3 }
|
|
7303
7308
|
).toString();
|
|
7304
7309
|
const body = JSON.parse(out);
|
|
7305
|
-
const
|
|
7310
|
+
const oauth = body.claudeAiOauth;
|
|
7311
|
+
const tok = oauth?.accessToken;
|
|
7306
7312
|
if (tok) {
|
|
7307
|
-
const
|
|
7308
|
-
const
|
|
7313
|
+
const email = oauth?.account?.email_address ?? oauth?.account?.email ?? null;
|
|
7314
|
+
const orgName = oauth?.organization?.name ?? null;
|
|
7315
|
+
const stableId = oauth?.account?.uuid ?? oauth?.organization?.uuid ?? (oauth?.refreshToken ?? tok).slice(0, 48);
|
|
7309
7316
|
ids.push({
|
|
7310
7317
|
provider: "anthropic",
|
|
7311
|
-
provider_account_id:
|
|
7312
|
-
provider_account_label:
|
|
7318
|
+
provider_account_id: stableId,
|
|
7319
|
+
provider_account_label: email ?? orgName ?? oauth?.subscriptionType ?? "Claude account",
|
|
7320
|
+
account_email: email,
|
|
7321
|
+
account_org: orgName ?? oauth?.subscriptionType ?? null,
|
|
7322
|
+
display_name: null,
|
|
7313
7323
|
owner_scope: "unassigned",
|
|
7314
7324
|
detection_source: "claude_keychain"
|
|
7315
7325
|
});
|
|
@@ -7328,6 +7338,8 @@ async function probeIdentities(os2) {
|
|
|
7328
7338
|
const jwt = obj.tokens?.id_token;
|
|
7329
7339
|
let email = null;
|
|
7330
7340
|
let sub = null;
|
|
7341
|
+
let name = null;
|
|
7342
|
+
let org = null;
|
|
7331
7343
|
let provider = "openai";
|
|
7332
7344
|
if (jwt) {
|
|
7333
7345
|
const parts = jwt.split(".");
|
|
@@ -7339,17 +7351,23 @@ async function probeIdentities(os2) {
|
|
|
7339
7351
|
);
|
|
7340
7352
|
email = body.email ?? null;
|
|
7341
7353
|
sub = body.sub ?? null;
|
|
7354
|
+
name = body.name ?? null;
|
|
7355
|
+
const oai = body["https://api.openai.com/auth"];
|
|
7356
|
+
org = oai?.organization_id ?? oai?.chatgpt_plan_type ?? null;
|
|
7342
7357
|
if (body.auth_provider === "google") provider = "openai";
|
|
7343
7358
|
} catch {
|
|
7344
7359
|
}
|
|
7345
7360
|
}
|
|
7346
7361
|
}
|
|
7347
|
-
const pid =
|
|
7362
|
+
const pid = obj.tokens?.account_id ?? sub ?? email;
|
|
7348
7363
|
if (pid) {
|
|
7349
7364
|
ids.push({
|
|
7350
7365
|
provider,
|
|
7351
7366
|
provider_account_id: pid,
|
|
7352
7367
|
provider_account_label: email,
|
|
7368
|
+
account_email: email,
|
|
7369
|
+
account_org: org,
|
|
7370
|
+
display_name: name,
|
|
7353
7371
|
owner_scope: "unassigned",
|
|
7354
7372
|
detection_source: "codex_auth_json"
|
|
7355
7373
|
});
|
|
@@ -7371,6 +7389,7 @@ async function probeIdentities(os2) {
|
|
|
7371
7389
|
provider: "google",
|
|
7372
7390
|
provider_account_id: email,
|
|
7373
7391
|
provider_account_label: email,
|
|
7392
|
+
account_email: email,
|
|
7374
7393
|
owner_scope: "unassigned",
|
|
7375
7394
|
detection_source: "gemini_oauth_creds"
|
|
7376
7395
|
});
|
|
@@ -7395,6 +7414,7 @@ async function probeIdentities(os2) {
|
|
|
7395
7414
|
provider: "cursor",
|
|
7396
7415
|
provider_account_id: auth.sub ?? auth.email,
|
|
7397
7416
|
provider_account_label: auth.email ?? null,
|
|
7417
|
+
account_email: auth.email ?? null,
|
|
7398
7418
|
owner_scope: "unassigned",
|
|
7399
7419
|
detection_source: "cursor_global_storage"
|
|
7400
7420
|
});
|
|
@@ -42435,9 +42455,9 @@ var require_range = __commonJS({
|
|
|
42435
42455
|
parseRange(range) {
|
|
42436
42456
|
const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
|
|
42437
42457
|
const memoKey = memoOpts + ":" + range;
|
|
42438
|
-
const
|
|
42439
|
-
if (
|
|
42440
|
-
return
|
|
42458
|
+
const cached2 = cache.get(memoKey);
|
|
42459
|
+
if (cached2) {
|
|
42460
|
+
return cached2;
|
|
42441
42461
|
}
|
|
42442
42462
|
const loose = this.options.loose;
|
|
42443
42463
|
const hr = loose ? re[t.HYPHENRANGELOOSE] : re[t.HYPHENRANGE];
|
|
@@ -44254,17 +44274,99 @@ var init_queue = __esm({
|
|
|
44254
44274
|
});
|
|
44255
44275
|
|
|
44256
44276
|
// ../../packages/companion-core/src/pipeline/prompts.ts
|
|
44257
|
-
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS,
|
|
44277
|
+
var OLLAMA_CHAT_MODEL, OLLAMA_EMBED_MODEL, SUMMARISER_SYSTEM_PROMPT, SUMMARISER_MAX_TOKENS, SUMMARISER_TEMPERATURE, QWEN_CHARS_PER_TOKEN, ABSTRACT_OUTPUT_MAX_CHARS;
|
|
44258
44278
|
var init_prompts = __esm({
|
|
44259
44279
|
"../../packages/companion-core/src/pipeline/prompts.ts"() {
|
|
44260
44280
|
"use strict";
|
|
44261
|
-
OLLAMA_CHAT_MODEL = "qwen3
|
|
44281
|
+
OLLAMA_CHAT_MODEL = "qwen3:4b";
|
|
44262
44282
|
OLLAMA_EMBED_MODEL = "bge-small-en-v1.5";
|
|
44263
|
-
SUMMARISER_SYSTEM_PROMPT = "
|
|
44264
|
-
SUMMARISER_MAX_TOKENS =
|
|
44265
|
-
ABSTRACT_OUTPUT_MAX_CHARS = 400;
|
|
44283
|
+
SUMMARISER_SYSTEM_PROMPT = "You summarise an AI coding session in ONE sentence, \u2264 240 characters. If the user message includes sampled conversation excerpts, base your summary on what the developer was actually working on (the substance \u2014 what was being built, debugged, refactored, or designed). If only metadata is given, paraphrase the metadata. Never quote the excerpts verbatim. No PII, no code literals, no file paths, no API keys. Reply with only the sentence.";
|
|
44284
|
+
SUMMARISER_MAX_TOKENS = 120;
|
|
44266
44285
|
SUMMARISER_TEMPERATURE = 0.2;
|
|
44267
44286
|
QWEN_CHARS_PER_TOKEN = 3.3;
|
|
44287
|
+
ABSTRACT_OUTPUT_MAX_CHARS = 240;
|
|
44288
|
+
}
|
|
44289
|
+
});
|
|
44290
|
+
|
|
44291
|
+
// ../../packages/companion-core/src/pipeline/cognition.ts
|
|
44292
|
+
function buildCognitionUserPrompt(abstract) {
|
|
44293
|
+
return `Summary: "${abstract.replace(/\s+/g, " ").trim().slice(0, 480)}"
|
|
44294
|
+
|
|
44295
|
+
Output JSON only.`;
|
|
44296
|
+
}
|
|
44297
|
+
function parseCognitionReply(text) {
|
|
44298
|
+
const json = extractFirstJsonObject(text);
|
|
44299
|
+
if (!json) return null;
|
|
44300
|
+
let parsed;
|
|
44301
|
+
try {
|
|
44302
|
+
parsed = JSON.parse(json);
|
|
44303
|
+
} catch {
|
|
44304
|
+
return null;
|
|
44305
|
+
}
|
|
44306
|
+
if (!parsed || typeof parsed !== "object") return null;
|
|
44307
|
+
const obj = parsed;
|
|
44308
|
+
return {
|
|
44309
|
+
emotions: sanitiseTags(obj.emotions),
|
|
44310
|
+
meta: sanitiseTags(obj.meta)
|
|
44311
|
+
};
|
|
44312
|
+
}
|
|
44313
|
+
function sanitiseTags(raw) {
|
|
44314
|
+
if (!Array.isArray(raw)) return [];
|
|
44315
|
+
const seen = /* @__PURE__ */ new Set();
|
|
44316
|
+
const out = [];
|
|
44317
|
+
for (const t of raw) {
|
|
44318
|
+
if (typeof t !== "string") continue;
|
|
44319
|
+
const cleaned = t.toLowerCase().normalize("NFKD").replace(/[^a-z0-9-]/g, "").replace(/-+/g, "-").replace(/^-+|-+$/g, "").slice(0, MAX_COGNITION_TAG_CHARS);
|
|
44320
|
+
if (!cleaned) continue;
|
|
44321
|
+
if (seen.has(cleaned)) continue;
|
|
44322
|
+
seen.add(cleaned);
|
|
44323
|
+
out.push(cleaned);
|
|
44324
|
+
if (out.length >= MAX_COGNITION_TAGS_PER_FIELD) break;
|
|
44325
|
+
}
|
|
44326
|
+
return out;
|
|
44327
|
+
}
|
|
44328
|
+
function formatCognitionSuffix(c) {
|
|
44329
|
+
if (!c) return "";
|
|
44330
|
+
const parts = [];
|
|
44331
|
+
if (c.emotions.length > 0) parts.push(`[Mood: ${c.emotions.join(", ")}]`);
|
|
44332
|
+
if (c.meta.length > 0) parts.push(`[Mind: ${c.meta.join(", ")}]`);
|
|
44333
|
+
return parts.join(" ");
|
|
44334
|
+
}
|
|
44335
|
+
function extractFirstJsonObject(s) {
|
|
44336
|
+
const start = s.indexOf("{");
|
|
44337
|
+
if (start < 0) return null;
|
|
44338
|
+
let depth = 0;
|
|
44339
|
+
let inStr = false;
|
|
44340
|
+
let escape2 = false;
|
|
44341
|
+
for (let i = start; i < s.length; i++) {
|
|
44342
|
+
const ch = s[i];
|
|
44343
|
+
if (inStr) {
|
|
44344
|
+
if (escape2) escape2 = false;
|
|
44345
|
+
else if (ch === "\\") escape2 = true;
|
|
44346
|
+
else if (ch === '"') inStr = false;
|
|
44347
|
+
continue;
|
|
44348
|
+
}
|
|
44349
|
+
if (ch === '"') {
|
|
44350
|
+
inStr = true;
|
|
44351
|
+
continue;
|
|
44352
|
+
}
|
|
44353
|
+
if (ch === "{") depth++;
|
|
44354
|
+
else if (ch === "}") {
|
|
44355
|
+
depth--;
|
|
44356
|
+
if (depth === 0) return s.slice(start, i + 1);
|
|
44357
|
+
}
|
|
44358
|
+
}
|
|
44359
|
+
return null;
|
|
44360
|
+
}
|
|
44361
|
+
var COGNITION_SYSTEM_PROMPT, MAX_COGNITION_TAGS_PER_FIELD, MAX_COGNITION_TAG_CHARS, COGNITION_MAX_TOKENS, COGNITION_TEMPERATURE;
|
|
44362
|
+
var init_cognition = __esm({
|
|
44363
|
+
"../../packages/companion-core/src/pipeline/cognition.ts"() {
|
|
44364
|
+
"use strict";
|
|
44365
|
+
COGNITION_SYSTEM_PROMPT = 'You read a one-sentence summary of an AI-coding work session and identify the user\'s emotional state and meta-cognitive state. Output JSON only \u2014 first character of reply is `{`. Schema: {"emotions":[],"meta":[]}. emotions: \u2264 3 short lowercase mood tags such as frustrated, curious, excited, focused, calm, confused, anxious, satisfied, proud, bored, energised. meta: \u2264 3 short lowercase tags about cognitive mode, such as debugging, exploring, planning, designing, learning, deciding, reviewing, refactoring, investigating, documenting. Each tag \u2264 24 chars, single word or hyphenated, no punctuation. Only emit a tag if the summary gives clear evidence \u2014 return [] for either field when unsure. Do not invent emotions the user did not display. No prose, no markdown.';
|
|
44366
|
+
MAX_COGNITION_TAGS_PER_FIELD = 3;
|
|
44367
|
+
MAX_COGNITION_TAG_CHARS = 24;
|
|
44368
|
+
COGNITION_MAX_TOKENS = 80;
|
|
44369
|
+
COGNITION_TEMPERATURE = 0.2;
|
|
44268
44370
|
}
|
|
44269
44371
|
});
|
|
44270
44372
|
|
|
@@ -44428,6 +44530,15 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
44428
44530
|
}
|
|
44429
44531
|
}
|
|
44430
44532
|
const redacted = { text: abstractText, counts };
|
|
44533
|
+
let abstractWithCognition = redacted.text;
|
|
44534
|
+
if (adapters2.cognize) {
|
|
44535
|
+
try {
|
|
44536
|
+
const tags2 = await adapters2.cognize({ abstract: redacted.text });
|
|
44537
|
+
const suffix = formatCognitionSuffix(tags2);
|
|
44538
|
+
if (suffix) abstractWithCognition = `${redacted.text} ${suffix}`;
|
|
44539
|
+
} catch {
|
|
44540
|
+
}
|
|
44541
|
+
}
|
|
44431
44542
|
const tags = [
|
|
44432
44543
|
{ root_key: "tools", name: first.tool, confidence: 1 },
|
|
44433
44544
|
{ root_key: "providers", name: first.provider, confidence: 1 }
|
|
@@ -44469,7 +44580,7 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
44469
44580
|
// 400) — well below the 512 storage cap. Models occasionally
|
|
44470
44581
|
// overshoot the prompt's "≤N chars" instruction; the slice is the
|
|
44471
44582
|
// hard guarantee the dashboard relies on.
|
|
44472
|
-
abstract:
|
|
44583
|
+
abstract: abstractWithCognition.slice(0, ABSTRACT_OUTPUT_MAX_CHARS),
|
|
44473
44584
|
tokens,
|
|
44474
44585
|
tags,
|
|
44475
44586
|
// counts is `Record<string, number>` after the optional model
|
|
@@ -44540,8 +44651,10 @@ var init_pipeline = __esm({
|
|
|
44540
44651
|
init_redact();
|
|
44541
44652
|
init_ids();
|
|
44542
44653
|
init_prompts();
|
|
44654
|
+
init_cognition();
|
|
44543
44655
|
init_redact();
|
|
44544
44656
|
init_prompts();
|
|
44657
|
+
init_cognition();
|
|
44545
44658
|
SEGMENT_TIME_GAP_MS = 15 * 6e4;
|
|
44546
44659
|
SEGMENT_TOPIC_THRESHOLD = 0.35;
|
|
44547
44660
|
SEGMENT_MAX_TURNS = 100;
|
|
@@ -44743,10 +44856,46 @@ function ollamaSummarize(cfg = defaultOllamaConfig()) {
|
|
|
44743
44856
|
return (body.message?.content ?? "").trim().slice(0, 240);
|
|
44744
44857
|
};
|
|
44745
44858
|
}
|
|
44859
|
+
function ollamaCognize(cfg = defaultOllamaConfig()) {
|
|
44860
|
+
return async ({ abstract }) => {
|
|
44861
|
+
if (!abstract || abstract.trim().length < 12) return null;
|
|
44862
|
+
let res;
|
|
44863
|
+
try {
|
|
44864
|
+
res = await fetch(`${cfg.baseUrl.replace(/\/+$/, "")}/api/chat`, {
|
|
44865
|
+
method: "POST",
|
|
44866
|
+
headers: { "content-type": "application/json" },
|
|
44867
|
+
body: JSON.stringify({
|
|
44868
|
+
model: cfg.chatModel,
|
|
44869
|
+
stream: false,
|
|
44870
|
+
format: "json",
|
|
44871
|
+
options: {
|
|
44872
|
+
temperature: COGNITION_TEMPERATURE,
|
|
44873
|
+
num_predict: COGNITION_MAX_TOKENS
|
|
44874
|
+
},
|
|
44875
|
+
messages: [
|
|
44876
|
+
{ role: "system", content: COGNITION_SYSTEM_PROMPT },
|
|
44877
|
+
{ role: "user", content: buildCognitionUserPrompt(abstract) }
|
|
44878
|
+
]
|
|
44879
|
+
})
|
|
44880
|
+
});
|
|
44881
|
+
} catch {
|
|
44882
|
+
return null;
|
|
44883
|
+
}
|
|
44884
|
+
if (!res.ok) return null;
|
|
44885
|
+
let body;
|
|
44886
|
+
try {
|
|
44887
|
+
body = await res.json();
|
|
44888
|
+
} catch {
|
|
44889
|
+
return null;
|
|
44890
|
+
}
|
|
44891
|
+
return parseCognitionReply(body.message?.content ?? "");
|
|
44892
|
+
};
|
|
44893
|
+
}
|
|
44746
44894
|
var init_ollama = __esm({
|
|
44747
44895
|
"../../packages/companion-core/src/node/ollama.ts"() {
|
|
44748
44896
|
"use strict";
|
|
44749
44897
|
init_prompts();
|
|
44898
|
+
init_cognition();
|
|
44750
44899
|
}
|
|
44751
44900
|
});
|
|
44752
44901
|
|
|
@@ -44856,12 +45005,21 @@ async function loadOnce(cfg) {
|
|
|
44856
45005
|
const modelPath = await ensureLlamaModel(cfg);
|
|
44857
45006
|
const llama = await llamaMod.getLlama();
|
|
44858
45007
|
const model = await llama.loadModel({ modelPath });
|
|
44859
|
-
const
|
|
44860
|
-
|
|
44861
|
-
|
|
45008
|
+
const summariserContext = await model.createContext({
|
|
45009
|
+
contextSize: cfg.contextSize
|
|
45010
|
+
});
|
|
45011
|
+
const cognizerContext = await model.createContext({
|
|
45012
|
+
contextSize: Math.min(cfg.contextSize, 2048)
|
|
45013
|
+
});
|
|
45014
|
+
const summarizer = new llamaMod.LlamaChatSession({
|
|
45015
|
+
contextSequence: summariserContext.getSequence(),
|
|
44862
45016
|
systemPrompt: SUMMARISER_SYSTEM_PROMPT
|
|
44863
45017
|
});
|
|
44864
|
-
|
|
45018
|
+
const cognizer = new llamaMod.LlamaChatSession({
|
|
45019
|
+
contextSequence: cognizerContext.getSequence(),
|
|
45020
|
+
systemPrompt: COGNITION_SYSTEM_PROMPT
|
|
45021
|
+
});
|
|
45022
|
+
loaded = { summarizer, cognizer };
|
|
44865
45023
|
return loaded;
|
|
44866
45024
|
})();
|
|
44867
45025
|
try {
|
|
@@ -44873,11 +45031,11 @@ async function loadOnce(cfg) {
|
|
|
44873
45031
|
}
|
|
44874
45032
|
function llamaSummarize(cfg = defaultLlamaConfig()) {
|
|
44875
45033
|
return async ({ prompt, maxTokens }) => {
|
|
44876
|
-
const {
|
|
45034
|
+
const { summarizer } = await loadOnce(cfg);
|
|
44877
45035
|
const run = inflight.then(async () => {
|
|
44878
|
-
|
|
45036
|
+
summarizer.resetChatHistory();
|
|
44879
45037
|
void maxTokens;
|
|
44880
|
-
const raw = await
|
|
45038
|
+
const raw = await summarizer.prompt(prompt, {
|
|
44881
45039
|
temperature: SUMMARISER_TEMPERATURE,
|
|
44882
45040
|
maxTokens: LLAMA_MAX_TOKENS
|
|
44883
45041
|
});
|
|
@@ -44893,11 +45051,42 @@ function llamaSummarize(cfg = defaultLlamaConfig()) {
|
|
|
44893
45051
|
return run;
|
|
44894
45052
|
};
|
|
44895
45053
|
}
|
|
45054
|
+
function llamaCognize(cfg = defaultLlamaConfig()) {
|
|
45055
|
+
return async ({ abstract }) => {
|
|
45056
|
+
if (!abstract || abstract.trim().length < 12) return null;
|
|
45057
|
+
let loadedSessions;
|
|
45058
|
+
try {
|
|
45059
|
+
loadedSessions = await loadOnce(cfg);
|
|
45060
|
+
} catch {
|
|
45061
|
+
return null;
|
|
45062
|
+
}
|
|
45063
|
+
const { cognizer } = loadedSessions;
|
|
45064
|
+
const run = inflight.then(async () => {
|
|
45065
|
+
cognizer.resetChatHistory();
|
|
45066
|
+
const raw = await cognizer.prompt(buildCognitionUserPrompt(abstract), {
|
|
45067
|
+
temperature: COGNITION_TEMPERATURE,
|
|
45068
|
+
// Qwen3.5 likes to "think" before answering. Give it a small
|
|
45069
|
+
// budget — the JSON answer is ~30 tokens but the thinking can
|
|
45070
|
+
// run 200-400. The strip below removes the <think> block.
|
|
45071
|
+
maxTokens: COGNITION_MAX_TOKENS + 400
|
|
45072
|
+
});
|
|
45073
|
+
const stripped = stripThinking(raw ?? "");
|
|
45074
|
+
return parseCognitionReply(stripped);
|
|
45075
|
+
});
|
|
45076
|
+
inflight = run.catch(() => void 0);
|
|
45077
|
+
try {
|
|
45078
|
+
return await run;
|
|
45079
|
+
} catch {
|
|
45080
|
+
return null;
|
|
45081
|
+
}
|
|
45082
|
+
};
|
|
45083
|
+
}
|
|
44896
45084
|
var DEFAULT_LLAMA_MODEL_URL, LLAMA_MAX_TOKENS, loaded, loadPromise, inflight;
|
|
44897
45085
|
var init_llama = __esm({
|
|
44898
45086
|
"../../packages/companion-core/src/node/llama.ts"() {
|
|
44899
45087
|
"use strict";
|
|
44900
45088
|
init_prompts();
|
|
45089
|
+
init_cognition();
|
|
44901
45090
|
DEFAULT_LLAMA_MODEL_URL = "https://huggingface.co/lmstudio-community/Qwen3.5-4B-GGUF/resolve/main/Qwen3.5-4B-Q4_K_M.gguf";
|
|
44902
45091
|
LLAMA_MAX_TOKENS = 1024;
|
|
44903
45092
|
loaded = null;
|
|
@@ -44906,16 +45095,79 @@ var init_llama = __esm({
|
|
|
44906
45095
|
}
|
|
44907
45096
|
});
|
|
44908
45097
|
|
|
45098
|
+
// ../../packages/companion-core/src/node/transformersjs-embed.ts
|
|
45099
|
+
async function loadPipeline(model) {
|
|
45100
|
+
if (cached) return cached;
|
|
45101
|
+
if (loadFailedPermanently) return null;
|
|
45102
|
+
if (!loadPromise2) {
|
|
45103
|
+
loadPromise2 = (async () => {
|
|
45104
|
+
try {
|
|
45105
|
+
const moduleId = "@huggingface/transformers";
|
|
45106
|
+
const tjs = await import(
|
|
45107
|
+
/* @vite-ignore */
|
|
45108
|
+
moduleId
|
|
45109
|
+
);
|
|
45110
|
+
const p = await tjs.pipeline("feature-extraction", model, {
|
|
45111
|
+
device: "cpu",
|
|
45112
|
+
dtype: "fp32"
|
|
45113
|
+
});
|
|
45114
|
+
cached = p;
|
|
45115
|
+
return p;
|
|
45116
|
+
} catch (err) {
|
|
45117
|
+
const msg = err.message;
|
|
45118
|
+
if (/unsupported|architecture|not supported|onnx|cannot resolve/i.test(msg)) {
|
|
45119
|
+
loadFailedPermanently = true;
|
|
45120
|
+
}
|
|
45121
|
+
console.warn(
|
|
45122
|
+
`[modelstat] transformers.js embedder unavailable (segments will be re-embedded server-side): ${msg}`
|
|
45123
|
+
);
|
|
45124
|
+
loadPromise2 = null;
|
|
45125
|
+
return null;
|
|
45126
|
+
}
|
|
45127
|
+
})();
|
|
45128
|
+
}
|
|
45129
|
+
return loadPromise2;
|
|
45130
|
+
}
|
|
45131
|
+
function createTransformersJsEmbedder(model = DEFAULT_MODEL) {
|
|
45132
|
+
return async (text) => {
|
|
45133
|
+
if (!text || text.trim().length === 0) return [];
|
|
45134
|
+
const pipe = await loadPipeline(model);
|
|
45135
|
+
if (!pipe) return [];
|
|
45136
|
+
try {
|
|
45137
|
+
const out = await pipe(text, { pooling: "mean", normalize: true });
|
|
45138
|
+
return Array.from(out.data);
|
|
45139
|
+
} catch (err) {
|
|
45140
|
+
console.warn(
|
|
45141
|
+
`[modelstat] embed error (returning empty vector, server will re-embed): ${err.message}`
|
|
45142
|
+
);
|
|
45143
|
+
return [];
|
|
45144
|
+
}
|
|
45145
|
+
};
|
|
45146
|
+
}
|
|
45147
|
+
var cached, loadPromise2, loadFailedPermanently, DEFAULT_MODEL;
|
|
45148
|
+
var init_transformersjs_embed = __esm({
|
|
45149
|
+
"../../packages/companion-core/src/node/transformersjs-embed.ts"() {
|
|
45150
|
+
"use strict";
|
|
45151
|
+
cached = null;
|
|
45152
|
+
loadPromise2 = null;
|
|
45153
|
+
loadFailedPermanently = false;
|
|
45154
|
+
DEFAULT_MODEL = "Xenova/bge-small-en-v1.5";
|
|
45155
|
+
}
|
|
45156
|
+
});
|
|
45157
|
+
|
|
44909
45158
|
// ../../packages/companion-core/src/node/index.ts
|
|
44910
45159
|
var node_exports = {};
|
|
44911
45160
|
__export(node_exports, {
|
|
44912
45161
|
DEFAULT_LLAMA_MODEL_URL: () => DEFAULT_LLAMA_MODEL_URL,
|
|
44913
45162
|
FileQueueStore: () => FileQueueStore,
|
|
44914
45163
|
SqliteQueueStore: () => FileQueueStore,
|
|
45164
|
+
createTransformersJsEmbedder: () => createTransformersJsEmbedder,
|
|
44915
45165
|
defaultLlamaConfig: () => defaultLlamaConfig,
|
|
44916
45166
|
defaultOllamaConfig: () => defaultOllamaConfig,
|
|
44917
45167
|
ensureLlamaModel: () => ensureLlamaModel,
|
|
45168
|
+
llamaCognize: () => llamaCognize,
|
|
44918
45169
|
llamaSummarize: () => llamaSummarize,
|
|
45170
|
+
ollamaCognize: () => ollamaCognize,
|
|
44919
45171
|
ollamaEmbed: () => ollamaEmbed,
|
|
44920
45172
|
ollamaSummarize: () => ollamaSummarize,
|
|
44921
45173
|
ollamaTokenize: () => ollamaTokenize
|
|
@@ -44927,6 +45179,103 @@ var init_node2 = __esm({
|
|
|
44927
45179
|
init_file_queue_store();
|
|
44928
45180
|
init_ollama();
|
|
44929
45181
|
init_llama();
|
|
45182
|
+
init_transformersjs_embed();
|
|
45183
|
+
}
|
|
45184
|
+
});
|
|
45185
|
+
|
|
45186
|
+
// ../../packages/companion-core/src/redact/privacy-filter.ts
|
|
45187
|
+
async function createPrivacyFilterRedactor(opts = {}) {
|
|
45188
|
+
const isBrowser = typeof globalThis !== "undefined" && typeof globalThis.window !== "undefined";
|
|
45189
|
+
const device = opts.device ?? (isBrowser ? "webgpu" : "cpu");
|
|
45190
|
+
const dtype = opts.dtype ?? "q4";
|
|
45191
|
+
const modelId = opts.model ?? "openai/privacy-filter";
|
|
45192
|
+
let cached2 = null;
|
|
45193
|
+
let loadPromise3 = null;
|
|
45194
|
+
async function loadPipeline2() {
|
|
45195
|
+
if (cached2) return cached2;
|
|
45196
|
+
if (!loadPromise3) {
|
|
45197
|
+
loadPromise3 = (async () => {
|
|
45198
|
+
try {
|
|
45199
|
+
const moduleId = "@huggingface/transformers";
|
|
45200
|
+
const tjs = await import(
|
|
45201
|
+
/* @vite-ignore */
|
|
45202
|
+
moduleId
|
|
45203
|
+
);
|
|
45204
|
+
const p = await tjs.pipeline("token-classification", modelId, {
|
|
45205
|
+
device,
|
|
45206
|
+
dtype,
|
|
45207
|
+
...opts.onProgress ? { progress_callback: opts.onProgress } : {}
|
|
45208
|
+
});
|
|
45209
|
+
cached2 = p;
|
|
45210
|
+
return p;
|
|
45211
|
+
} catch (err) {
|
|
45212
|
+
loadPromise3 = null;
|
|
45213
|
+
console.warn(
|
|
45214
|
+
"[privacy-filter] adapter unavailable \u2014 install @huggingface/transformers in the consuming package to enable model-based redaction. Falling back to pass-through.",
|
|
45215
|
+
err.message
|
|
45216
|
+
);
|
|
45217
|
+
return null;
|
|
45218
|
+
}
|
|
45219
|
+
})();
|
|
45220
|
+
}
|
|
45221
|
+
return loadPromise3;
|
|
45222
|
+
}
|
|
45223
|
+
return async function redactWithPrivacyFilter(text) {
|
|
45224
|
+
const empty = {
|
|
45225
|
+
text,
|
|
45226
|
+
counts: {
|
|
45227
|
+
secrets_found: 0,
|
|
45228
|
+
emails_redacted: 0,
|
|
45229
|
+
paths_redacted_absolute: 0
|
|
45230
|
+
}
|
|
45231
|
+
};
|
|
45232
|
+
if (!text) return empty;
|
|
45233
|
+
const classify = await loadPipeline2();
|
|
45234
|
+
if (!classify) return empty;
|
|
45235
|
+
let tokens;
|
|
45236
|
+
try {
|
|
45237
|
+
tokens = await classify(text);
|
|
45238
|
+
} catch (err) {
|
|
45239
|
+
console.warn(
|
|
45240
|
+
"[privacy-filter] inference failed, returning input unchanged:",
|
|
45241
|
+
err.message
|
|
45242
|
+
);
|
|
45243
|
+
return empty;
|
|
45244
|
+
}
|
|
45245
|
+
const spans = [];
|
|
45246
|
+
for (const t of tokens) {
|
|
45247
|
+
const ent = t.entity ?? "";
|
|
45248
|
+
if (!ent || ent === "O" || ent === "0") continue;
|
|
45249
|
+
if (t.start == null || t.end == null || t.end <= t.start) continue;
|
|
45250
|
+
const type = ent.replace(/^[BILUE]-/, "").toUpperCase();
|
|
45251
|
+
const last = spans[spans.length - 1];
|
|
45252
|
+
if (last && last.type === type && t.start - last.end <= 2) {
|
|
45253
|
+
last.end = t.end;
|
|
45254
|
+
} else {
|
|
45255
|
+
spans.push({ type, start: t.start, end: t.end });
|
|
45256
|
+
}
|
|
45257
|
+
}
|
|
45258
|
+
spans.sort((a, b) => b.start - a.start);
|
|
45259
|
+
let out = text;
|
|
45260
|
+
const extra = {};
|
|
45261
|
+
for (const s of spans) {
|
|
45262
|
+
extra[`pf_${s.type.toLowerCase()}`] = (extra[`pf_${s.type.toLowerCase()}`] ?? 0) + 1;
|
|
45263
|
+
out = out.slice(0, s.start) + `[REDACTED:${s.type}]` + out.slice(s.end);
|
|
45264
|
+
}
|
|
45265
|
+
return {
|
|
45266
|
+
text: out,
|
|
45267
|
+
counts: {
|
|
45268
|
+
secrets_found: 0,
|
|
45269
|
+
emails_redacted: 0,
|
|
45270
|
+
paths_redacted_absolute: 0,
|
|
45271
|
+
...extra
|
|
45272
|
+
}
|
|
45273
|
+
};
|
|
45274
|
+
};
|
|
45275
|
+
}
|
|
45276
|
+
var init_privacy_filter = __esm({
|
|
45277
|
+
"../../packages/companion-core/src/redact/privacy-filter.ts"() {
|
|
45278
|
+
"use strict";
|
|
44930
45279
|
}
|
|
44931
45280
|
});
|
|
44932
45281
|
|
|
@@ -44950,11 +45299,26 @@ async function probeOllama(baseUrl) {
|
|
|
44950
45299
|
return false;
|
|
44951
45300
|
}
|
|
44952
45301
|
}
|
|
44953
|
-
function bundledAdapters() {
|
|
45302
|
+
async function bundledAdapters() {
|
|
45303
|
+
const llamaCfg = defaultLlamaConfig();
|
|
44954
45304
|
return {
|
|
44955
|
-
|
|
44956
|
-
|
|
44957
|
-
|
|
45305
|
+
// Same transformers.js BGE-small embedder as the Ollama path. The
|
|
45306
|
+
// bundled-llama path used to ship vector-less (empty arrays);
|
|
45307
|
+
// hooking embeddings here means even no-Ollama installs get
|
|
45308
|
+
// proper segment-vs-leaf cosine matching at classify time.
|
|
45309
|
+
embed: createTransformersJsEmbedder(),
|
|
45310
|
+
summarize: llamaSummarize(llamaCfg),
|
|
45311
|
+
tokenize: (text) => Math.max(1, Math.ceil(text.length / 4)),
|
|
45312
|
+
cognize: llamaCognize(llamaCfg),
|
|
45313
|
+
// Model-based PII redactor (OpenAI Privacy Filter via
|
|
45314
|
+
// transformers.js / ONNX). Runs locally on CPU after the regex
|
|
45315
|
+
// pass in packages/core/redact.ts. ~1 GB model downloaded on
|
|
45316
|
+
// first run; subsequent runs reuse the cached weights. The
|
|
45317
|
+
// factory is async because it dynamic-imports
|
|
45318
|
+
// @huggingface/transformers — if the optional peer dep isn't
|
|
45319
|
+
// installed it returns a pass-through redactor (regex pass is
|
|
45320
|
+
// still the last line of defence).
|
|
45321
|
+
redact: await createPrivacyFilterRedactor()
|
|
44958
45322
|
};
|
|
44959
45323
|
}
|
|
44960
45324
|
async function getAdapters() {
|
|
@@ -44967,9 +45331,21 @@ async function getAdapters() {
|
|
|
44967
45331
|
`[modelstat] ollama up at ${ollamaCfg.baseUrl} \u2014 using ${ollamaCfg.chatModel} for summarisation`
|
|
44968
45332
|
);
|
|
44969
45333
|
adapters = {
|
|
44970
|
-
|
|
45334
|
+
// BGE-small via transformers.js — same model the server uses
|
|
45335
|
+
// via fastembed, so segment vectors land in the same 384-dim
|
|
45336
|
+
// space as leaf-description vectors and cosine similarity is
|
|
45337
|
+
// directly meaningful. We do NOT use ollamaEmbed here because
|
|
45338
|
+
// Ollama's library doesn't host bge-small (404 on pull) and
|
|
45339
|
+
// shipping MiniLM-via-Ollama vs BGE-small-server would break
|
|
45340
|
+
// cross-source similarity.
|
|
45341
|
+
embed: createTransformersJsEmbedder(),
|
|
44971
45342
|
summarize: ollamaSummarize(ollamaCfg),
|
|
44972
|
-
tokenize: ollamaTokenize()
|
|
45343
|
+
tokenize: ollamaTokenize(),
|
|
45344
|
+
cognize: ollamaCognize(ollamaCfg),
|
|
45345
|
+
// Privacy filter — same OpenAI Privacy Filter model regardless
|
|
45346
|
+
// of which summariser/embedder runtime we ended up on. Factory
|
|
45347
|
+
// is async (dynamic-imports @huggingface/transformers).
|
|
45348
|
+
redact: await createPrivacyFilterRedactor()
|
|
44973
45349
|
};
|
|
44974
45350
|
return adapters;
|
|
44975
45351
|
}
|
|
@@ -44983,7 +45359,7 @@ async function getAdapters() {
|
|
|
44983
45359
|
console.log(
|
|
44984
45360
|
"[modelstat] using bundled local summariser (Qwen3.5-4B, runs on this machine)"
|
|
44985
45361
|
);
|
|
44986
|
-
adapters = bundledAdapters();
|
|
45362
|
+
adapters = await bundledAdapters();
|
|
44987
45363
|
return adapters;
|
|
44988
45364
|
}
|
|
44989
45365
|
async function buildSegments(events) {
|
|
@@ -45008,6 +45384,7 @@ var init_pipeline2 = __esm({
|
|
|
45008
45384
|
"use strict";
|
|
45009
45385
|
init_pipeline();
|
|
45010
45386
|
init_node2();
|
|
45387
|
+
init_privacy_filter();
|
|
45011
45388
|
adapters = null;
|
|
45012
45389
|
probed = false;
|
|
45013
45390
|
}
|
|
@@ -45129,7 +45506,7 @@ var init_scan = __esm({
|
|
|
45129
45506
|
init_pipeline2();
|
|
45130
45507
|
init_config2();
|
|
45131
45508
|
init_api();
|
|
45132
|
-
AGENT_VERSION = "agent-0.0.
|
|
45509
|
+
AGENT_VERSION = "agent-0.0.36";
|
|
45133
45510
|
BATCH_MAX_EVENTS = 2e3;
|
|
45134
45511
|
}
|
|
45135
45512
|
});
|
|
@@ -45272,7 +45649,7 @@ var PROCESSING_VERSION;
|
|
|
45272
45649
|
var init_processing_version = __esm({
|
|
45273
45650
|
"src/processing-version.ts"() {
|
|
45274
45651
|
"use strict";
|
|
45275
|
-
PROCESSING_VERSION =
|
|
45652
|
+
PROCESSING_VERSION = 3;
|
|
45276
45653
|
}
|
|
45277
45654
|
});
|
|
45278
45655
|
|
|
@@ -47221,7 +47598,7 @@ var init_daemon = __esm({
|
|
|
47221
47598
|
init_config2();
|
|
47222
47599
|
init_lock();
|
|
47223
47600
|
init_scan();
|
|
47224
|
-
AGENT_VERSION2 = "agent-0.0.
|
|
47601
|
+
AGENT_VERSION2 = "agent-0.0.36";
|
|
47225
47602
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
47226
47603
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
47227
47604
|
status = {
|
|
@@ -47646,7 +48023,7 @@ function tryOpenBrowser(url) {
|
|
|
47646
48023
|
return false;
|
|
47647
48024
|
}
|
|
47648
48025
|
}
|
|
47649
|
-
var AGENT_VERSION3 = "agent-0.0.
|
|
48026
|
+
var AGENT_VERSION3 = "agent-0.0.36";
|
|
47650
48027
|
function osFamily() {
|
|
47651
48028
|
const p = platform4();
|
|
47652
48029
|
if (p === "darwin") return "macos";
|