behavior-wrapped 0.8.9 → 0.8.10
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/assets/index-CFnO0oEF.js +11 -0
- package/dist/assets/{index-RUb7reCR.css → index-Ctd7RCMR.css} +1 -1
- package/dist/index.html +2 -2
- package/package.json +1 -1
- package/server/analysis.mjs +9 -6
- package/server/privacy.mjs +4 -2
- package/server/public-report-schema.mjs +1 -1
- package/dist/assets/index-CD48EtI2.js +0 -11
package/dist/index.html
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
<meta name="theme-color" content="#0d0b1b" />
|
|
7
7
|
<meta name="description" content="A local-first behavior report for you and your AI agents." />
|
|
8
8
|
<title>Behavior Wrapped</title>
|
|
9
|
-
<script type="module" crossorigin src="/assets/index-
|
|
10
|
-
<link rel="stylesheet" crossorigin href="/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/assets/index-CFnO0oEF.js"></script>
|
|
10
|
+
<link rel="stylesheet" crossorigin href="/assets/index-Ctd7RCMR.css">
|
|
11
11
|
</head>
|
|
12
12
|
<body>
|
|
13
13
|
<div id="root"></div>
|
package/package.json
CHANGED
package/server/analysis.mjs
CHANGED
|
@@ -62,7 +62,7 @@ function proseText(value) {
|
|
|
62
62
|
.replace(/`[^`\n]+`/g, " ")
|
|
63
63
|
.replace(/^\s*>.*$/gm, " ")
|
|
64
64
|
.replace(/https?:\/\/\S+/g, " ")
|
|
65
|
-
.replace(
|
|
65
|
+
.replace(/(?:^|\s)(?:[A-Za-z]:)?[/.~][^\s]+/g, " ")
|
|
66
66
|
.replace(/<[^>]+>/g, " ")
|
|
67
67
|
.replace(/\s+/g, " ")
|
|
68
68
|
.trim();
|
|
@@ -106,7 +106,7 @@ function repeatedInstructions(sessionRecords) {
|
|
|
106
106
|
return [...instructions.values()]
|
|
107
107
|
.filter((item) => item.occurrences >= 2)
|
|
108
108
|
.sort((left, right) => right.sessions.size - left.sessions.size || right.occurrences - left.occurrences || left.instruction.localeCompare(right.instruction))
|
|
109
|
-
.slice(0,
|
|
109
|
+
.slice(0, 2)
|
|
110
110
|
.map((item) => ({ instruction: item.instruction, occurrences: item.occurrences, distinctSessions: item.sessions.size }));
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -453,6 +453,8 @@ export function analyzeSessions(sessionRecords) {
|
|
|
453
453
|
};
|
|
454
454
|
for (const [recordIndex, record] of records.entries()) {
|
|
455
455
|
const text = visibleText(record);
|
|
456
|
+
const userProse = record.type === "user" ? proseText(localOpeningPrompt(text)) : "";
|
|
457
|
+
const assistantResponseProse = record.type === "assistant" ? proseText(text) : "";
|
|
456
458
|
const declaredModel = record?.message?.model || record?.model;
|
|
457
459
|
if (typeof declaredModel === "string" && declaredModel) currentModel = declaredModel;
|
|
458
460
|
if (record.type === "system" && record.subtype === "turn_duration") {
|
|
@@ -462,10 +464,10 @@ export function analyzeSessions(sessionRecords) {
|
|
|
462
464
|
longestUninterruptedRun = { durationMs: Math.round(durationMs), agent, agentName: definition?.name || "Agent" };
|
|
463
465
|
}
|
|
464
466
|
}
|
|
465
|
-
if (record.type === "user" && !record.isMeta &&
|
|
467
|
+
if (record.type === "user" && !record.isMeta && userProse) {
|
|
466
468
|
finishResponse();
|
|
467
469
|
hasCurrentPrompt = true;
|
|
468
|
-
userInputWords += wordCount(
|
|
470
|
+
userInputWords += wordCount(userProse);
|
|
469
471
|
userInputCount++;
|
|
470
472
|
sessionTurns++;
|
|
471
473
|
if (isFrustratedMessage(text)) frustratedMessages++;
|
|
@@ -477,8 +479,8 @@ export function analyzeSessions(sessionRecords) {
|
|
|
477
479
|
location: { sessionId, recordIndex, timestamp: record.timestamp || null },
|
|
478
480
|
});
|
|
479
481
|
}
|
|
480
|
-
} else if (record.type === "assistant" && hasCurrentPrompt &&
|
|
481
|
-
currentResponseWords += wordCount(
|
|
482
|
+
} else if (record.type === "assistant" && hasCurrentPrompt && assistantResponseProse) {
|
|
483
|
+
currentResponseWords += wordCount(assistantResponseProse);
|
|
482
484
|
}
|
|
483
485
|
if (record.type === "assistant" && text) {
|
|
484
486
|
assistantProse.push(text);
|
|
@@ -554,6 +556,7 @@ export function analyzeSessions(sessionRecords) {
|
|
|
554
556
|
agentUserWordRatio: userInputWords ? Number((agentResponseWords / userInputWords).toFixed(2)) : null,
|
|
555
557
|
averageAgentResponseWords: agentResponseCount ? Math.round(agentResponseWords / agentResponseCount) : 0,
|
|
556
558
|
averageUserInputWords: userInputCount ? Math.round(userInputWords / userInputCount) : 0,
|
|
559
|
+
wordCountMethod: "Counts conversational prose only, excluding injected workspace instructions, code, URLs, paths, and markup.",
|
|
557
560
|
longestSessionTurns: Math.max(0, ...sessionTurnCounts),
|
|
558
561
|
sessionTurnCounts: [...sessionTurnCounts].sort((left, right) => left - right),
|
|
559
562
|
sessionTurnMethod: "Counts each visible, non-meta user message as one turn.",
|
package/server/privacy.mjs
CHANGED
|
@@ -108,7 +108,7 @@ export function redactText(input, manualTerms = [], { disabledKinds = [], disabl
|
|
|
108
108
|
if (!labeledCredentialValue(match)) return match;
|
|
109
109
|
const replacement = "[REDACTED CREDENTIAL]";
|
|
110
110
|
const enabled = isEnabled("credential", match);
|
|
111
|
-
detections.push(detectionDetails({ kind: "credential", label: "
|
|
111
|
+
detections.push(detectionDetails({ kind: "credential", label: "API keys and secrets", value: match, replacement, offset, source, enabled }));
|
|
112
112
|
return enabled ? replacement : protect(match);
|
|
113
113
|
});
|
|
114
114
|
for (const [pattern, replacement] of [...SECRET_PATTERNS, ...(includeHeuristicSecrets ? HEURISTIC_SECRET_PATTERNS : []), ...PII_PATTERNS]) {
|
|
@@ -117,7 +117,9 @@ export function redactText(input, manualTerms = [], { disabledKinds = [], disabl
|
|
|
117
117
|
const enabled = isEnabled(kind, match);
|
|
118
118
|
detections.push(detectionDetails({
|
|
119
119
|
kind,
|
|
120
|
-
label:
|
|
120
|
+
label: /(?:SECRET|KEY|TOKEN|CREDENTIAL|HIGH-ENTROPY)/.test(replacement)
|
|
121
|
+
? "API keys and secrets"
|
|
122
|
+
: replacement.slice(1, -1).toLowerCase().replace(/\b\w/g, (letter) => letter.toUpperCase()),
|
|
121
123
|
value: match,
|
|
122
124
|
replacement,
|
|
123
125
|
offset,
|
|
@@ -38,7 +38,7 @@ function safeStockPhrases(value) {
|
|
|
38
38
|
|
|
39
39
|
function safeRepeatedInstructions(value) {
|
|
40
40
|
if (!Array.isArray(value)) return [];
|
|
41
|
-
return value.slice(0,
|
|
41
|
+
return value.slice(0, 2).flatMap((item) => {
|
|
42
42
|
const instruction = safeText(item?.instruction, 160).trim();
|
|
43
43
|
const occurrences = Math.round(safeNumber(item?.occurrences, 1_000_000));
|
|
44
44
|
const distinctSessions = Math.round(safeNumber(item?.distinctSessions, 1_000_000));
|