modelstat 0.11.1 → 0.13.0
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 +106 -15
- package/dist/cli.mjs.map +1 -1
- package/package.json +3 -3
package/dist/cli.mjs
CHANGED
|
@@ -5141,7 +5141,24 @@ var init_schemas = __esm({
|
|
|
5141
5141
|
source_event_ids: external_exports.array(external_exports.string()).max(2e3),
|
|
5142
5142
|
/** Optional embedding of the abstract (BGE-small-en-v1.5, 384 dims).
|
|
5143
5143
|
* Present when the daemon has an Embedder adapter configured. */
|
|
5144
|
-
abstract_embedding: external_exports.array(external_exports.number()).length(384).optional()
|
|
5144
|
+
abstract_embedding: external_exports.array(external_exports.number()).length(384).optional(),
|
|
5145
|
+
/** Privacy-preserving on-device behavioral signal — COUNTS/RATIOS ONLY,
|
|
5146
|
+
* never raw text (mirrors RedactionReport). Powers server-side prompt-
|
|
5147
|
+
* friction detection. Optional so older daemons that omit it still validate. */
|
|
5148
|
+
behavior: external_exports.object({
|
|
5149
|
+
/** Developer messages in this segment. */
|
|
5150
|
+
user_turns: external_exports.number().int().nonnegative().default(0),
|
|
5151
|
+
/** User messages that land right after the assistant — a re-prompt /
|
|
5152
|
+
* correction proxy. */
|
|
5153
|
+
correction_count: external_exports.number().int().nonnegative().default(0),
|
|
5154
|
+
/** 0-1 frustration estimate (re-prompt density + negative mood tags). */
|
|
5155
|
+
frustration: external_exports.number().min(0).max(1).default(0)
|
|
5156
|
+
}).optional(),
|
|
5157
|
+
/** Distilled "what the developer asked for / how they directed the AI" — from
|
|
5158
|
+
* their MESSAGES ONLY (not the assistant's actions), redacted, ≤512. The
|
|
5159
|
+
* source Insights' rule + skill detectors mine, distinct from the outcome
|
|
5160
|
+
* `abstract`. Optional; absent from daemons that predate it. */
|
|
5161
|
+
user_intent: external_exports.string().max(512).optional()
|
|
5145
5162
|
});
|
|
5146
5163
|
ToolAction = external_exports.object({
|
|
5147
5164
|
/** Where it ran: `shell`, `mcp`, `builtin`, `browser`. (tier 0) */
|
|
@@ -35265,11 +35282,11 @@ var init_prompts = __esm({
|
|
|
35265
35282
|
"use strict";
|
|
35266
35283
|
OLLAMA_CHAT_MODEL = "qwen3:4b";
|
|
35267
35284
|
OLLAMA_EMBED_MODEL = "bge-small-en-v1.5";
|
|
35268
|
-
SUMMARISER_SYSTEM_PROMPT =
|
|
35269
|
-
SUMMARISER_MAX_TOKENS =
|
|
35285
|
+
SUMMARISER_SYSTEM_PROMPT = 'You summarise an AI coding session in 1-2 sentences, \u2264 400 characters. Name the CONCRETE work: the action taken, WHAT it acted on, and the specific target \u2014 the repository (e.g. erpc/erpc), branch, service, or component \u2014 whenever the session facts or excerpts identify it. Good: "Triggered a GitHub Actions release for erpc/erpc"; "Fixed a null dereference in the auth middleware of api-gateway". Lead with an outcome verb and pack in concrete domain keywords (frameworks, features, decisions). Base the substance on the excerpts when present, else the metadata. Never quote excerpts verbatim. No PII, no secrets, no API keys, no absolute file paths. Reply with only the summary.';
|
|
35286
|
+
SUMMARISER_MAX_TOKENS = 180;
|
|
35270
35287
|
SUMMARISER_TEMPERATURE = 0.2;
|
|
35271
35288
|
QWEN_CHARS_PER_TOKEN = 3.3;
|
|
35272
|
-
ABSTRACT_OUTPUT_MAX_CHARS =
|
|
35289
|
+
ABSTRACT_OUTPUT_MAX_CHARS = 400;
|
|
35273
35290
|
}
|
|
35274
35291
|
});
|
|
35275
35292
|
|
|
@@ -35782,7 +35799,7 @@ async function summariseSlice(sessionId, slice, adapters2) {
|
|
|
35782
35799
|
Sampled excerpts from the conversation (already redacted of PII and secrets):
|
|
35783
35800
|
${excerptBlock}
|
|
35784
35801
|
|
|
35785
|
-
Write
|
|
35802
|
+
Write a \u2264${ABSTRACT_OUTPUT_MAX_CHARS}-char summary (1-2 sentences) naming exactly what was achieved: the concrete action, what it acted on, and the specific target (repo/branch/service/component) when identifiable from the context above. Lead with an outcome verb and pack in concrete domain keywords (frameworks, features, decisions). Skip narration and filler.`;
|
|
35786
35803
|
const rawAbstract = await adapters2.summarize({
|
|
35787
35804
|
prompt,
|
|
35788
35805
|
maxTokens: SUMMARISER_MAX_TOKENS,
|
|
@@ -35810,15 +35827,16 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
35810
35827
|
}
|
|
35811
35828
|
}
|
|
35812
35829
|
const redacted = { text: abstractText, counts };
|
|
35813
|
-
let
|
|
35830
|
+
let cognition = null;
|
|
35814
35831
|
if (adapters2.cognize) {
|
|
35815
35832
|
try {
|
|
35816
|
-
|
|
35817
|
-
const suffix = formatCognitionSuffix(tags2);
|
|
35818
|
-
if (suffix) abstractWithCognition = `${redacted.text} ${suffix}`;
|
|
35833
|
+
cognition = await adapters2.cognize({ abstract: redacted.text });
|
|
35819
35834
|
} catch {
|
|
35820
35835
|
}
|
|
35821
35836
|
}
|
|
35837
|
+
const cognitionSuffix = cognition ? formatCognitionSuffix(cognition) : "";
|
|
35838
|
+
const abstractWithCognition = cognitionSuffix ? `${redacted.text} ${cognitionSuffix}` : redacted.text;
|
|
35839
|
+
const behavior = computeBehavior(slice, cognition);
|
|
35822
35840
|
const tags = [
|
|
35823
35841
|
{ root_key: "agents", name: first.agent, confidence: 1 },
|
|
35824
35842
|
{ root_key: "providers", name: first.provider, confidence: 1 }
|
|
@@ -35866,6 +35884,7 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
35866
35884
|
} catch {
|
|
35867
35885
|
segmentEmbedding = void 0;
|
|
35868
35886
|
}
|
|
35887
|
+
const userIntent = await summariseUserIntent(slice, adapters2);
|
|
35869
35888
|
const sourceEventIds = slice.map((e) => e.source_event_id);
|
|
35870
35889
|
const id = segmentId(sessionId, startedAtMs, endedAtMs, sourceEventIds);
|
|
35871
35890
|
return {
|
|
@@ -35887,7 +35906,66 @@ Write the SHORTEST keyword-dense paragraph (1-3 sentences, \u2264${ABSTRACT_OUTP
|
|
|
35887
35906
|
// number-valued catchall for pf_*.
|
|
35888
35907
|
redaction: redacted.counts,
|
|
35889
35908
|
source_event_ids: sourceEventIds,
|
|
35890
|
-
abstract_embedding: segmentEmbedding && segmentEmbedding.length === 384 ? segmentEmbedding : void 0
|
|
35909
|
+
abstract_embedding: segmentEmbedding && segmentEmbedding.length === 384 ? segmentEmbedding : void 0,
|
|
35910
|
+
behavior,
|
|
35911
|
+
user_intent: userIntent
|
|
35912
|
+
};
|
|
35913
|
+
}
|
|
35914
|
+
async function summariseUserIntent(slice, adapters2) {
|
|
35915
|
+
const userExcerpts = slice.filter((e) => e.kind === "user_message").map((e) => e.content_excerpt?.replace(/\s+/g, " ").trim()).filter((x) => !!x && x.length > 0);
|
|
35916
|
+
if (userExcerpts.length === 0) return void 0;
|
|
35917
|
+
const sample = userExcerpts.length <= 6 ? userExcerpts : [...userExcerpts.slice(0, 4), ...userExcerpts.slice(-2)];
|
|
35918
|
+
const block = sample.map((e, i) => ` [msg ${i + 1}] "${e.slice(0, 240)}"`).join("\n");
|
|
35919
|
+
try {
|
|
35920
|
+
const raw = await adapters2.summarize({
|
|
35921
|
+
prompt: `The developer's own messages to an AI coding assistant (already redacted of PII and secrets):
|
|
35922
|
+
${block}
|
|
35923
|
+
|
|
35924
|
+
In \u2264${USER_INTENT_MAX_CHARS} chars, summarise WHAT THE DEVELOPER ASKED FOR or DIRECTED \u2014 their goal or task in their own framing, AND any standing preferences / directives / conventions they expressed (e.g. "always be thorough", "ship fast", a naming or workflow convention). Focus on the DEVELOPER'S intent and voice, NOT what the assistant did. Reply with only the summary.`,
|
|
35925
|
+
maxTokens: USER_INTENT_MAX_TOKENS,
|
|
35926
|
+
excerpts: sample,
|
|
35927
|
+
facts: ""
|
|
35928
|
+
});
|
|
35929
|
+
if (!raw || !raw.trim()) return void 0;
|
|
35930
|
+
const regexPass = redact(raw);
|
|
35931
|
+
let text = regexPass.text;
|
|
35932
|
+
if (adapters2.redact) {
|
|
35933
|
+
try {
|
|
35934
|
+
text = (await adapters2.redact(regexPass.text)).text;
|
|
35935
|
+
} catch {
|
|
35936
|
+
}
|
|
35937
|
+
}
|
|
35938
|
+
const trimmed = text.trim().slice(0, USER_INTENT_MAX_CHARS);
|
|
35939
|
+
return trimmed.length > 0 ? trimmed : void 0;
|
|
35940
|
+
} catch {
|
|
35941
|
+
return void 0;
|
|
35942
|
+
}
|
|
35943
|
+
}
|
|
35944
|
+
function computeBehavior(slice, cognition) {
|
|
35945
|
+
let userTurns = 0;
|
|
35946
|
+
let correctionCount = 0;
|
|
35947
|
+
let prevWasAssistant = false;
|
|
35948
|
+
for (const ev of slice) {
|
|
35949
|
+
if (ev.kind === "user_message") {
|
|
35950
|
+
userTurns++;
|
|
35951
|
+
if (prevWasAssistant) correctionCount++;
|
|
35952
|
+
prevWasAssistant = false;
|
|
35953
|
+
} else if (ev.kind === "assistant_message") {
|
|
35954
|
+
prevWasAssistant = true;
|
|
35955
|
+
}
|
|
35956
|
+
}
|
|
35957
|
+
const frustratedMood = cognition?.emotions?.some((e) => {
|
|
35958
|
+
const lower = e.toLowerCase();
|
|
35959
|
+
return FRUSTRATION_MARKERS.some((m) => lower.includes(m));
|
|
35960
|
+
}) ?? false;
|
|
35961
|
+
const frustration = Math.min(
|
|
35962
|
+
1,
|
|
35963
|
+
Math.max(correctionCount / 4, frustratedMood ? 0.8 : 0)
|
|
35964
|
+
);
|
|
35965
|
+
return {
|
|
35966
|
+
user_turns: userTurns,
|
|
35967
|
+
correction_count: correctionCount,
|
|
35968
|
+
frustration: Math.round(frustration * 100) / 100
|
|
35891
35969
|
};
|
|
35892
35970
|
}
|
|
35893
35971
|
function sampleAndRedactExcerpts(slice) {
|
|
@@ -35942,7 +36020,7 @@ function inferEnvironment(branch) {
|
|
|
35942
36020
|
if (b === "dev" || b === "develop" || b.startsWith("dev/")) return "Dev";
|
|
35943
36021
|
return null;
|
|
35944
36022
|
}
|
|
35945
|
-
var SEGMENT_TIME_GAP_MS, SEGMENT_TOPIC_THRESHOLD, SEGMENT_MAX_TURNS, SEGMENT_MAX_DURATION_MS, SEGMENT_MAX_CONTENT_CHARS, ABSTRACT_MAX_CHARS;
|
|
36023
|
+
var SEGMENT_TIME_GAP_MS, SEGMENT_TOPIC_THRESHOLD, SEGMENT_MAX_TURNS, SEGMENT_MAX_DURATION_MS, SEGMENT_MAX_CONTENT_CHARS, ABSTRACT_MAX_CHARS, USER_INTENT_MAX_CHARS, USER_INTENT_MAX_TOKENS, FRUSTRATION_MARKERS;
|
|
35946
36024
|
var init_pipeline = __esm({
|
|
35947
36025
|
"../../packages/daemon-core/src/pipeline/index.ts"() {
|
|
35948
36026
|
"use strict";
|
|
@@ -35964,6 +36042,19 @@ var init_pipeline = __esm({
|
|
|
35964
36042
|
SEGMENT_MAX_DURATION_MS = 30 * 6e4;
|
|
35965
36043
|
SEGMENT_MAX_CONTENT_CHARS = 12e3;
|
|
35966
36044
|
ABSTRACT_MAX_CHARS = 512;
|
|
36045
|
+
USER_INTENT_MAX_CHARS = 240;
|
|
36046
|
+
USER_INTENT_MAX_TOKENS = 120;
|
|
36047
|
+
FRUSTRATION_MARKERS = [
|
|
36048
|
+
"frustrat",
|
|
36049
|
+
"annoy",
|
|
36050
|
+
"stuck",
|
|
36051
|
+
"confus",
|
|
36052
|
+
"irritat",
|
|
36053
|
+
"block",
|
|
36054
|
+
"stress",
|
|
36055
|
+
"angr",
|
|
36056
|
+
"overwhelm"
|
|
36057
|
+
];
|
|
35967
36058
|
}
|
|
35968
36059
|
});
|
|
35969
36060
|
|
|
@@ -37267,7 +37358,7 @@ var init_scan = __esm({
|
|
|
37267
37358
|
init_api();
|
|
37268
37359
|
init_config2();
|
|
37269
37360
|
init_pipeline2();
|
|
37270
|
-
DAEMON_VERSION = true ? "daemon-0.
|
|
37361
|
+
DAEMON_VERSION = true ? "daemon-0.13.0" : "daemon-dev";
|
|
37271
37362
|
BATCH_MAX_EVENTS = INGEST_BATCH_MAX_EVENTS;
|
|
37272
37363
|
BATCH_MAX_TOOL_CALLS = 2e4;
|
|
37273
37364
|
BATCH_BUFFER_HARD_CAP = BATCH_MAX_EVENTS * 2;
|
|
@@ -37834,7 +37925,7 @@ var PROCESSING_VERSION;
|
|
|
37834
37925
|
var init_processing_version = __esm({
|
|
37835
37926
|
"src/processing-version.ts"() {
|
|
37836
37927
|
"use strict";
|
|
37837
|
-
PROCESSING_VERSION =
|
|
37928
|
+
PROCESSING_VERSION = 11;
|
|
37838
37929
|
}
|
|
37839
37930
|
});
|
|
37840
37931
|
|
|
@@ -40214,7 +40305,7 @@ var init_daemon = __esm({
|
|
|
40214
40305
|
init_scan();
|
|
40215
40306
|
init_single_flight();
|
|
40216
40307
|
init_update();
|
|
40217
|
-
DAEMON_VERSION2 = true ? "daemon-0.
|
|
40308
|
+
DAEMON_VERSION2 = true ? "daemon-0.13.0" : "daemon-dev";
|
|
40218
40309
|
HEARTBEAT_INTERVAL_MS = 1e4;
|
|
40219
40310
|
SCAN_INTERVAL_MS = 5 * 60 * 1e3;
|
|
40220
40311
|
DISCOVERY_INTERVAL_MS = 6e4;
|
|
@@ -40846,7 +40937,7 @@ function tryOpenBrowser(url) {
|
|
|
40846
40937
|
return false;
|
|
40847
40938
|
}
|
|
40848
40939
|
}
|
|
40849
|
-
var DAEMON_VERSION3 = true ? "daemon-0.
|
|
40940
|
+
var DAEMON_VERSION3 = true ? "daemon-0.13.0" : "daemon-dev";
|
|
40850
40941
|
function osFamily() {
|
|
40851
40942
|
const p = platform6();
|
|
40852
40943
|
if (p === "darwin") return "macos";
|