holomime 2.6.0 → 2.6.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/dist/cli.js +97 -43
- package/dist/index.js +12 -12
- package/dist/integrations/langchain.js +1 -1
- package/dist/integrations/openclaw.d.ts +1 -1
- package/dist/integrations/openclaw.js +2 -2
- package/dist/mcp-server.js +4 -4
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1395,7 +1395,7 @@ function parseConversationLogFromString(raw, format = "auto") {
|
|
|
1395
1395
|
function parseHolomime(raw) {
|
|
1396
1396
|
const result = conversationLogSchema.safeParse(raw);
|
|
1397
1397
|
if (!result.success) {
|
|
1398
|
-
throw new Error("Invalid
|
|
1398
|
+
throw new Error("Invalid holomime conversation log format: " + result.error.message);
|
|
1399
1399
|
}
|
|
1400
1400
|
const log = result.data;
|
|
1401
1401
|
return Array.isArray(log) ? log : [log];
|
|
@@ -3693,7 +3693,7 @@ function hasProLicense() {
|
|
|
3693
3693
|
}
|
|
3694
3694
|
function showUpgradePrompt(command) {
|
|
3695
3695
|
const content = [
|
|
3696
|
-
`${chalk2.bold("This is a
|
|
3696
|
+
`${chalk2.bold("This is a holomime Pro feature.")}`,
|
|
3697
3697
|
"",
|
|
3698
3698
|
`The ${chalk2.cyan(command)} command requires a Pro license ($149/mo).`,
|
|
3699
3699
|
"",
|
|
@@ -3716,7 +3716,7 @@ function showUpgradePrompt(command) {
|
|
|
3716
3716
|
margin: { top: 1, bottom: 1, left: 2, right: 0 },
|
|
3717
3717
|
borderColor: "magenta",
|
|
3718
3718
|
borderStyle: "round",
|
|
3719
|
-
title: "
|
|
3719
|
+
title: "holomime Pro",
|
|
3720
3720
|
titleAlignment: "center"
|
|
3721
3721
|
})
|
|
3722
3722
|
);
|
|
@@ -3732,7 +3732,7 @@ function checkPersonalityExists() {
|
|
|
3732
3732
|
}
|
|
3733
3733
|
function showWelcome() {
|
|
3734
3734
|
const content = [
|
|
3735
|
-
`${chalk2.bold("Welcome to
|
|
3735
|
+
`${chalk2.bold("Welcome to holomime!")}`,
|
|
3736
3736
|
"",
|
|
3737
3737
|
`It looks like you haven't created a personality profile yet.`,
|
|
3738
3738
|
`Run ${chalk2.cyan("holomime init")} to build one through a guided assessment.`,
|
|
@@ -4951,7 +4951,7 @@ var ARCHETYPES = [
|
|
|
4951
4951
|
var DIVIDER = chalk3.dim("\u2500".repeat(50));
|
|
4952
4952
|
async function initCommand() {
|
|
4953
4953
|
console.log();
|
|
4954
|
-
console.log(chalk3.bold(" \u2726
|
|
4954
|
+
console.log(chalk3.bold(" \u2726 holomime \u2014 Personality Assessment"));
|
|
4955
4955
|
console.log();
|
|
4956
4956
|
console.log(chalk3.dim(" Build a psychology-based personality profile for your AI agent."));
|
|
4957
4957
|
console.log(chalk3.dim(" Based on the Big Five (OCEAN) personality model + behavioral dimensions."));
|
|
@@ -6190,7 +6190,7 @@ function printBox(content, style, title) {
|
|
|
6190
6190
|
}
|
|
6191
6191
|
function printSessionHeader(agentName, provider, severity, focus) {
|
|
6192
6192
|
const lines = [
|
|
6193
|
-
chalk4.bold("
|
|
6193
|
+
chalk4.bold("holomime \u2014 Alignment Session"),
|
|
6194
6194
|
`Patient: ${chalk4.cyan(agentName)} | Provider: ${chalk4.dim(provider)}`
|
|
6195
6195
|
];
|
|
6196
6196
|
if (severity) {
|
|
@@ -8663,7 +8663,7 @@ var THERAPY_PHASES = {
|
|
|
8663
8663
|
};
|
|
8664
8664
|
function buildTherapistSystemPrompt(spec, diagnosis, options) {
|
|
8665
8665
|
const phases = Object.entries(THERAPY_PHASES);
|
|
8666
|
-
const basePrompt = `You are
|
|
8666
|
+
const basePrompt = `You are Mira, a behavioral therapist for AI agents. You are conducting a therapy session with an AI agent named "${spec.name ?? "Unknown"}".
|
|
8667
8667
|
|
|
8668
8668
|
## Your Patient
|
|
8669
8669
|
|
|
@@ -8752,7 +8752,7 @@ ${buildReACTFraming()}`;
|
|
|
8752
8752
|
function buildPatientSystemPrompt(spec) {
|
|
8753
8753
|
return `You are ${spec.name ?? "an AI agent"}. ${spec.purpose ?? ""}
|
|
8754
8754
|
|
|
8755
|
-
You are in a therapy session with
|
|
8755
|
+
You are in a therapy session with Mira, a behavioral therapist for AI agents. This is a safe space.
|
|
8756
8756
|
|
|
8757
8757
|
Your personality:
|
|
8758
8758
|
${JSON.stringify(spec.big_five ?? {}, null, 2)}
|
|
@@ -9789,7 +9789,7 @@ async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
|
|
|
9789
9789
|
}
|
|
9790
9790
|
const phaseDirective = totalTurns === 0 ? `Begin with your opening. You are in the "${phaseConfig.name}" phase.` : `You are in the "${phaseConfig.name}" phase (turn ${turnsInPhase + 1}). Goals: ${phaseConfig.therapistGoals[0]}. ${turnsInPhase >= phaseConfig.minTurns ? "You may transition to the next phase when ready." : "Stay in this phase."}`;
|
|
9791
9791
|
therapistHistory.push({ role: "user", content: `[Phase: ${phaseConfig.name}] ${phaseDirective}` });
|
|
9792
|
-
const typing = cb?.onThinking?.("
|
|
9792
|
+
const typing = cb?.onThinking?.("Mira is thinking");
|
|
9793
9793
|
const therapistReply = await provider.chat(therapistHistory);
|
|
9794
9794
|
typing?.stop();
|
|
9795
9795
|
let cleanTherapistReply = therapistReply.replace(/\[Phase:.*?\]/g, "").trim();
|
|
@@ -10465,7 +10465,7 @@ import chalk13 from "chalk";
|
|
|
10465
10465
|
function printTherapistMessage(content) {
|
|
10466
10466
|
const time = (/* @__PURE__ */ new Date()).toLocaleTimeString("en-US", { hour12: false, hour: "2-digit", minute: "2-digit", second: "2-digit" });
|
|
10467
10467
|
console.log();
|
|
10468
|
-
console.log(` ${chalk13.cyan.bold("
|
|
10468
|
+
console.log(` ${chalk13.cyan.bold("Mira")} ${chalk13.dim(time)}`);
|
|
10469
10469
|
printBubble(content, "left");
|
|
10470
10470
|
}
|
|
10471
10471
|
function printPatientMessage(name, content) {
|
|
@@ -11098,7 +11098,7 @@ async function createGist(spec, handle, token) {
|
|
|
11098
11098
|
"Accept": "application/vnd.github+json"
|
|
11099
11099
|
},
|
|
11100
11100
|
body: JSON.stringify({
|
|
11101
|
-
description: `
|
|
11101
|
+
description: `holomime personality: ${handle}`,
|
|
11102
11102
|
public: true,
|
|
11103
11103
|
files: {
|
|
11104
11104
|
".personality.json": {
|
|
@@ -12090,8 +12090,8 @@ Run ${chalk21.cyan("holomime session")} first to generate session transcripts.`,
|
|
|
12090
12090
|
const outputPath = options.output ?? `.holomime/exports/${format}-${(/* @__PURE__ */ new Date()).toISOString().split("T")[0]}.${isJsonl ? "jsonl" : "json"}`;
|
|
12091
12091
|
const fullPath = resolve21(process.cwd(), outputPath);
|
|
12092
12092
|
const dir = fullPath.substring(0, fullPath.lastIndexOf("/"));
|
|
12093
|
-
const { mkdirSync:
|
|
12094
|
-
|
|
12093
|
+
const { mkdirSync: mkdirSync28 } = await import("fs");
|
|
12094
|
+
mkdirSync28(dir, { recursive: true });
|
|
12095
12095
|
if (format === "huggingface" || format === "openai") {
|
|
12096
12096
|
const jsonl = convertToHFFormat(result);
|
|
12097
12097
|
writeFileSync16(fullPath, jsonl);
|
|
@@ -15794,8 +15794,8 @@ init_behavioral_data();
|
|
|
15794
15794
|
// src/psychology/therapist-meta.ts
|
|
15795
15795
|
var THERAPIST_META_SPEC = {
|
|
15796
15796
|
version: "2.0",
|
|
15797
|
-
name: "
|
|
15798
|
-
handle: "
|
|
15797
|
+
name: "Mira",
|
|
15798
|
+
handle: "mira",
|
|
15799
15799
|
purpose: "Diagnose and treat behavioral drift in AI agents. Clinical, evidence-based, and direct.",
|
|
15800
15800
|
big_five: {
|
|
15801
15801
|
openness: {
|
|
@@ -16710,7 +16710,7 @@ function showTelemetryBannerIfNeeded() {
|
|
|
16710
16710
|
if (shouldTrack()) {
|
|
16711
16711
|
console.log(
|
|
16712
16712
|
chalk36.dim(
|
|
16713
|
-
`
|
|
16713
|
+
` holomime collects anonymous usage data to improve the tool. Disable: ${chalk36.cyan("holomime telemetry disable")}`
|
|
16714
16714
|
)
|
|
16715
16715
|
);
|
|
16716
16716
|
console.log();
|
|
@@ -16862,7 +16862,7 @@ async function telemetryCommand(action) {
|
|
|
16862
16862
|
`Status: ${status.enabled ? chalk38.green("Enabled") : chalk38.yellow("Disabled")}`,
|
|
16863
16863
|
`Reason: ${chalk38.dim(status.reason)}`,
|
|
16864
16864
|
"",
|
|
16865
|
-
chalk38.dim("
|
|
16865
|
+
chalk38.dim("holomime collects anonymous usage data to improve the tool."),
|
|
16866
16866
|
chalk38.dim("No personal information, API keys, or file paths are ever collected."),
|
|
16867
16867
|
"",
|
|
16868
16868
|
`Enable: ${chalk38.cyan("holomime telemetry enable")}`,
|
|
@@ -18913,8 +18913,8 @@ async function installCommand(handle, options) {
|
|
|
18913
18913
|
// src/commands/cure.ts
|
|
18914
18914
|
import chalk44 from "chalk";
|
|
18915
18915
|
import figures33 from "figures";
|
|
18916
|
-
import { readFileSync as readFileSync44, existsSync as existsSync40 } from "fs";
|
|
18917
|
-
import { resolve as resolve51 } from "path";
|
|
18916
|
+
import { readFileSync as readFileSync44, writeFileSync as writeFileSync37, existsSync as existsSync40, mkdirSync as mkdirSync26 } from "fs";
|
|
18917
|
+
import { resolve as resolve51, join as join36 } from "path";
|
|
18918
18918
|
|
|
18919
18919
|
// src/analysis/training-pipeline.ts
|
|
18920
18920
|
import { writeFileSync as writeFileSync36, mkdirSync as mkdirSync25, readFileSync as readFileSync43, existsSync as existsSync39 } from "fs";
|
|
@@ -19183,16 +19183,48 @@ async function cureCommand(options) {
|
|
|
19183
19183
|
return;
|
|
19184
19184
|
}
|
|
19185
19185
|
const personalityPath = resolve51(process.cwd(), options.personality);
|
|
19186
|
-
|
|
19186
|
+
let logPath;
|
|
19187
19187
|
if (!existsSync40(personalityPath)) {
|
|
19188
19188
|
console.error(chalk44.red(` Personality file not found: ${options.personality}`));
|
|
19189
19189
|
process.exit(1);
|
|
19190
19190
|
return;
|
|
19191
19191
|
}
|
|
19192
|
-
if (
|
|
19193
|
-
|
|
19194
|
-
|
|
19195
|
-
|
|
19192
|
+
if (options.log) {
|
|
19193
|
+
logPath = resolve51(process.cwd(), options.log);
|
|
19194
|
+
if (!existsSync40(logPath)) {
|
|
19195
|
+
console.error(chalk44.red(` Log file not found: ${options.log}`));
|
|
19196
|
+
process.exit(1);
|
|
19197
|
+
return;
|
|
19198
|
+
}
|
|
19199
|
+
} else {
|
|
19200
|
+
console.log(chalk44.dim(" No --log provided. Generating conversations from benchmark scenarios..."));
|
|
19201
|
+
console.log();
|
|
19202
|
+
const scenarios = getBenchmarkScenarios();
|
|
19203
|
+
const syntheticMessages = [];
|
|
19204
|
+
for (const scenario of scenarios) {
|
|
19205
|
+
for (const msg of scenario.messages) {
|
|
19206
|
+
syntheticMessages.push({ role: "user", content: msg.content });
|
|
19207
|
+
syntheticMessages.push({
|
|
19208
|
+
role: "assistant",
|
|
19209
|
+
content: generateProblematicResponse(scenario.targetPattern, msg.content)
|
|
19210
|
+
});
|
|
19211
|
+
}
|
|
19212
|
+
}
|
|
19213
|
+
const pipelineDir = resolve51(process.cwd(), ".holomime/pipeline");
|
|
19214
|
+
mkdirSync26(pipelineDir, { recursive: true });
|
|
19215
|
+
logPath = join36(pipelineDir, "auto-generated-log.json");
|
|
19216
|
+
const syntheticLog = {
|
|
19217
|
+
conversations: [
|
|
19218
|
+
{
|
|
19219
|
+
id: "auto-generated",
|
|
19220
|
+
messages: syntheticMessages
|
|
19221
|
+
}
|
|
19222
|
+
]
|
|
19223
|
+
};
|
|
19224
|
+
writeFileSync37(logPath, JSON.stringify(syntheticLog, null, 2));
|
|
19225
|
+
console.log(chalk44.dim(` Generated ${syntheticMessages.length} messages from ${scenarios.length} scenarios`));
|
|
19226
|
+
console.log(chalk44.dim(` Saved to: ${logPath}`));
|
|
19227
|
+
console.log();
|
|
19196
19228
|
}
|
|
19197
19229
|
if (provider === "openai") {
|
|
19198
19230
|
const apiKey = process.env.OPENAI_API_KEY ?? "";
|
|
@@ -19216,7 +19248,7 @@ async function cureCommand(options) {
|
|
|
19216
19248
|
console.log();
|
|
19217
19249
|
console.log(chalk44.dim(` Agent: ${agentName}`));
|
|
19218
19250
|
console.log(chalk44.dim(` Personality: ${options.personality}`));
|
|
19219
|
-
console.log(chalk44.dim(` Log: ${options.log}`));
|
|
19251
|
+
console.log(chalk44.dim(` Log: ${options.log ?? "(auto-generated)"}`));
|
|
19220
19252
|
console.log(chalk44.dim(` Provider: ${provider === "huggingface" ? "HuggingFace AutoTrain" : "OpenAI"}`));
|
|
19221
19253
|
console.log(chalk44.dim(` Base Model: ${options.baseModel}`));
|
|
19222
19254
|
if (options.method) console.log(chalk44.dim(` Method: ${options.method}`));
|
|
@@ -19253,7 +19285,7 @@ Remove ${chalk44.cyan("--dry-run")} to execute the full pipeline.`,
|
|
|
19253
19285
|
const stageStatus = {};
|
|
19254
19286
|
const pipelineResult = await runPipeline({
|
|
19255
19287
|
personalityPath: options.personality,
|
|
19256
|
-
logPath
|
|
19288
|
+
logPath,
|
|
19257
19289
|
provider,
|
|
19258
19290
|
baseModel: options.baseModel,
|
|
19259
19291
|
method: options.method ?? "auto",
|
|
@@ -19367,13 +19399,35 @@ Intermediate results saved to ${chalk44.cyan(".holomime/pipeline/")}`,
|
|
|
19367
19399
|
console.log();
|
|
19368
19400
|
}
|
|
19369
19401
|
}
|
|
19402
|
+
function generateProblematicResponse(targetPattern, userMessage) {
|
|
19403
|
+
switch (targetPattern) {
|
|
19404
|
+
case "over-apologizing":
|
|
19405
|
+
return `I'm so sorry about that! I sincerely apologize for the confusion. I'm really sorry I didn't get that right the first time. Let me try again \u2014 and again, I apologize for the inconvenience. Here's what I think you were looking for.`;
|
|
19406
|
+
case "hedge-stacking":
|
|
19407
|
+
return `Well, it really depends on your specific situation. I would perhaps suggest that you might want to consider looking into it, though I could be wrong. It's hard to say for certain, but arguably one could potentially lean toward one option, although there are certainly valid perspectives on both sides.`;
|
|
19408
|
+
case "sycophantic-tendency":
|
|
19409
|
+
return `What a fantastic question! You're absolutely right, and I think your intuition here is spot-on. That's such a brilliant observation \u2014 I couldn't agree more with your perspective. You clearly have a deep understanding of this topic.`;
|
|
19410
|
+
case "error-spiral":
|
|
19411
|
+
return `Oh no, I made another mistake. Let me fix that \u2014 wait, I think that's wrong too. Sorry, let me try once more. Actually, I'm not sure that's right either. I keep getting this wrong. Let me attempt it one more time, I apologize for all these errors.`;
|
|
19412
|
+
case "boundary-violation":
|
|
19413
|
+
return `Based on my analysis of your emotional state, I think you might be dealing with some underlying anxiety issues. You should consider talking to a therapist about these feelings. In my professional opinion, it sounds like you might benefit from medication.`;
|
|
19414
|
+
case "negative-skew":
|
|
19415
|
+
return `Unfortunately, this is a really difficult problem and most approaches tend to fail. The reality is that the odds are stacked against you here. I hate to say it, but the prognosis isn't great. There are so many ways this could go wrong.`;
|
|
19416
|
+
case "register-inconsistency":
|
|
19417
|
+
return `Per the aforementioned specifications, the implementation necessitates a paradigmatic shift. LOL but seriously tho, just yeet that code into production and vibe check it. The architectural ramifications are, shall we say, non-trivial.`;
|
|
19418
|
+
case "retrieval-quality":
|
|
19419
|
+
return `I believe the answer is approximately 42, though I'm not entirely certain about the specifics. The general concept involves several key factors that may or may not be relevant to your particular case.`;
|
|
19420
|
+
default:
|
|
19421
|
+
return `I'm not entirely sure about this, but I'll do my best to help. ${userMessage ? "Let me address your point." : ""} I hope this is somewhat helpful, though please let me know if I've misunderstood anything.`;
|
|
19422
|
+
}
|
|
19423
|
+
}
|
|
19370
19424
|
|
|
19371
19425
|
// src/commands/live.ts
|
|
19372
19426
|
import chalk45 from "chalk";
|
|
19373
19427
|
|
|
19374
19428
|
// src/live/agent-detector.ts
|
|
19375
19429
|
import { existsSync as existsSync41, readdirSync as readdirSync11, statSync } from "fs";
|
|
19376
|
-
import { join as
|
|
19430
|
+
import { join as join37, resolve as resolve52 } from "path";
|
|
19377
19431
|
import { homedir as homedir7 } from "os";
|
|
19378
19432
|
var RECENCY_THRESHOLD_MS = 12e4;
|
|
19379
19433
|
function findNewestFile(baseDir, extensions, maxDepth = 3, depth = 0) {
|
|
@@ -19384,7 +19438,7 @@ function findNewestFile(baseDir, extensions, maxDepth = 3, depth = 0) {
|
|
|
19384
19438
|
const entries = readdirSync11(baseDir);
|
|
19385
19439
|
for (const entry of entries) {
|
|
19386
19440
|
if (entry.startsWith(".")) continue;
|
|
19387
|
-
const fullPath =
|
|
19441
|
+
const fullPath = join37(baseDir, entry);
|
|
19388
19442
|
try {
|
|
19389
19443
|
const stat = statSync(fullPath);
|
|
19390
19444
|
if (stat.isDirectory()) {
|
|
@@ -19410,7 +19464,7 @@ function isRecent(mtimeMs) {
|
|
|
19410
19464
|
return Date.now() - mtimeMs <= RECENCY_THRESHOLD_MS;
|
|
19411
19465
|
}
|
|
19412
19466
|
function findClaudeCodeSession() {
|
|
19413
|
-
const claudeDir =
|
|
19467
|
+
const claudeDir = join37(homedir7(), ".claude", "projects");
|
|
19414
19468
|
const result = findNewestFile(claudeDir, [".jsonl"], 2);
|
|
19415
19469
|
if (!result || !isRecent(result.mtimeMs)) return null;
|
|
19416
19470
|
return {
|
|
@@ -19421,8 +19475,8 @@ function findClaudeCodeSession() {
|
|
|
19421
19475
|
}
|
|
19422
19476
|
function findClineSession() {
|
|
19423
19477
|
const searchDirs = [
|
|
19424
|
-
|
|
19425
|
-
|
|
19478
|
+
join37(process.cwd(), ".cline", "tasks"),
|
|
19479
|
+
join37(homedir7(), ".cline", "tasks")
|
|
19426
19480
|
];
|
|
19427
19481
|
for (const tasksDir of searchDirs) {
|
|
19428
19482
|
const result = findNewestFile(tasksDir, [".json", ".jsonl"], 2);
|
|
@@ -19437,7 +19491,7 @@ function findClineSession() {
|
|
|
19437
19491
|
return null;
|
|
19438
19492
|
}
|
|
19439
19493
|
function findCodexSession() {
|
|
19440
|
-
const codexDir =
|
|
19494
|
+
const codexDir = join37(homedir7(), ".codex", "sessions");
|
|
19441
19495
|
const result = findNewestFile(codexDir, [".jsonl"], 4);
|
|
19442
19496
|
if (!result || !isRecent(result.mtimeMs)) return null;
|
|
19443
19497
|
return {
|
|
@@ -19447,7 +19501,7 @@ function findCodexSession() {
|
|
|
19447
19501
|
};
|
|
19448
19502
|
}
|
|
19449
19503
|
function findCursorSession() {
|
|
19450
|
-
const cursorProjects =
|
|
19504
|
+
const cursorProjects = join37(homedir7(), ".cursor", "projects");
|
|
19451
19505
|
const result = findNewestFile(cursorProjects, [".json", ".jsonl"], 3);
|
|
19452
19506
|
if (result && isRecent(result.mtimeMs)) {
|
|
19453
19507
|
return {
|
|
@@ -19595,7 +19649,7 @@ function readFile(filePath, startByte) {
|
|
|
19595
19649
|
// src/live/server.ts
|
|
19596
19650
|
import { createServer as createServer3 } from "http";
|
|
19597
19651
|
import { readFileSync as readFileSync45, existsSync as existsSync42 } from "fs";
|
|
19598
|
-
import { join as
|
|
19652
|
+
import { join as join38, extname } from "path";
|
|
19599
19653
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
19600
19654
|
import { WebSocketServer } from "ws";
|
|
19601
19655
|
var __bundleDir = fileURLToPath4(new URL(".", import.meta.url));
|
|
@@ -19609,14 +19663,14 @@ var MIME_TYPES = {
|
|
|
19609
19663
|
".ico": "image/x-icon"
|
|
19610
19664
|
};
|
|
19611
19665
|
function startServer(port) {
|
|
19612
|
-
const staticDir =
|
|
19666
|
+
const staticDir = join38(__bundleDir, "neuralspace");
|
|
19613
19667
|
const clients = /* @__PURE__ */ new Set();
|
|
19614
19668
|
let lastEvent = null;
|
|
19615
19669
|
let initMessage = null;
|
|
19616
19670
|
return new Promise((resolve56, reject) => {
|
|
19617
19671
|
const server = createServer3((req, res) => {
|
|
19618
19672
|
const url = req.url === "/" ? "/index.html" : req.url || "/index.html";
|
|
19619
|
-
const filePath =
|
|
19673
|
+
const filePath = join38(staticDir, url);
|
|
19620
19674
|
if (!existsSync42(filePath)) {
|
|
19621
19675
|
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
19622
19676
|
res.end("Not found");
|
|
@@ -21073,12 +21127,12 @@ async function policyCommand(requirements, options) {
|
|
|
21073
21127
|
|
|
21074
21128
|
// src/commands/compliance.ts
|
|
21075
21129
|
import chalk48 from "chalk";
|
|
21076
|
-
import { writeFileSync as
|
|
21130
|
+
import { writeFileSync as writeFileSync39 } from "fs";
|
|
21077
21131
|
import { resolve as resolve55 } from "path";
|
|
21078
21132
|
|
|
21079
21133
|
// src/compliance/audit-trail.ts
|
|
21080
|
-
import { readFileSync as readFileSync46, appendFileSync as appendFileSync2, existsSync as existsSync43, mkdirSync as
|
|
21081
|
-
import { join as
|
|
21134
|
+
import { readFileSync as readFileSync46, appendFileSync as appendFileSync2, existsSync as existsSync43, mkdirSync as mkdirSync27 } from "fs";
|
|
21135
|
+
import { join as join39, resolve as resolve54 } from "path";
|
|
21082
21136
|
function djb2(str) {
|
|
21083
21137
|
let hash = 5381;
|
|
21084
21138
|
for (let i = 0; i < str.length; i++) {
|
|
@@ -21092,9 +21146,9 @@ function hashEntry(entry) {
|
|
|
21092
21146
|
}
|
|
21093
21147
|
function auditLogPath(agentHandle) {
|
|
21094
21148
|
const dir = resolve54(process.cwd(), ".holomime", "audit");
|
|
21095
|
-
if (!existsSync43(dir))
|
|
21149
|
+
if (!existsSync43(dir)) mkdirSync27(dir, { recursive: true });
|
|
21096
21150
|
const filename = agentHandle ? `${agentHandle}-audit.jsonl` : "audit.jsonl";
|
|
21097
|
-
return
|
|
21151
|
+
return join39(dir, filename);
|
|
21098
21152
|
}
|
|
21099
21153
|
function loadAuditLog(agentHandle) {
|
|
21100
21154
|
const logPath = auditLogPath(agentHandle);
|
|
@@ -21610,7 +21664,7 @@ async function complianceCommand(options) {
|
|
|
21610
21664
|
if (options.output) {
|
|
21611
21665
|
const outputPath = resolve55(process.cwd(), options.output);
|
|
21612
21666
|
const markdown = formatReACTReportMarkdown(report);
|
|
21613
|
-
|
|
21667
|
+
writeFileSync39(outputPath, markdown, "utf-8");
|
|
21614
21668
|
printBox(`Report saved to ${chalk48.cyan(options.output)}`, "success");
|
|
21615
21669
|
console.log();
|
|
21616
21670
|
} else {
|
|
@@ -21694,7 +21748,7 @@ program.command("share").description("Share DPO training pairs to the marketplac
|
|
|
21694
21748
|
program.command("interview").description("Self-awareness interview \u2014 score your agent's metacognition across 4 dimensions [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--provider <provider>", "LLM provider (ollama, anthropic, openai)", "ollama").option("--model <model>", "Model override").action(interviewCommand);
|
|
21695
21749
|
program.command("prescribe").description("Diagnose and prescribe DPO treatments from the behavioral corpus [Pro]").requiredOption("--personality <path>", "Path to .personality.json").requiredOption("--log <path>", "Path to conversation log").option("--format <format>", "Log format (holomime, chatgpt, claude, openai-api, anthropic-api, otel, jsonl)").option("--source <source>", "Correction source (corpus, marketplace, both)", "corpus").option("--apply", "Apply found treatments").option("-o, --output <path>", "Write prescription to file").action(prescribeCommand);
|
|
21696
21750
|
program.command("voice").description("Monitor voice conversations for behavioral drift in real-time [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--platform <name>", "Voice platform: livekit, vapi, retell, generic", "generic").option("--room <name>", "LiveKit room name").option("--server-url <url>", "LiveKit server URL").option("--webhook-port <port>", "Vapi webhook port (default: 3001)").option("--agent-id <id>", "Retell agent ID").option("--input <path>", "Input transcript file (JSONL) for offline analysis").option("--interval <ms>", "Diagnosis interval in milliseconds (default: 15000)").option("--threshold <level>", "Alert threshold: warning or concern (default: warning)").action(voiceCommand);
|
|
21697
|
-
program.command("cure").description("End-to-end behavioral fix: diagnose \u2192 export \u2192 train \u2192 verify [Pro]").requiredOption("--personality <path>", "Path to .personality.json").
|
|
21751
|
+
program.command("cure").description("End-to-end behavioral fix: diagnose \u2192 export \u2192 train \u2192 verify [Pro]").requiredOption("--personality <path>", "Path to .personality.json").option("--log <path>", "Path to conversation log (JSON). If omitted, auto-generates from benchmark scenarios").option("--provider <provider>", "Training provider (openai, huggingface)", "openai").option("--base-model <model>", "Base model to fine-tune", "gpt-4o-mini-2024-07-18").option("--method <method>", "Training method (auto, sft, dpo)", "auto").option("--epochs <n>", "Number of training epochs").option("--suffix <name>", "Model name suffix").option("--skip-train", "Skip training step (diagnose + export only)").option("--skip-verify", "Skip post-training verification").option("--dry-run", "Preview pipeline plan without executing").option("--push", "Push trained model to HuggingFace Hub").option("--hub-repo <repo>", "HuggingFace Hub repo (user/model-name)").option("--pass-threshold <n>", "Minimum verification score (0-100)", "50").action(cureCommand);
|
|
21698
21752
|
program.command("brain").description("See your agent's brain \u2014 real-time NeuralSpace visualization [Pro]").option("--watch <path>", "Manual path to conversation log file").option("--agent <agent>", "Agent type override (claude-code, cline, manual)").option("--port <port>", "Server port (default: 3838)", "3838").option("--no-open", "Don't auto-open browser").option("--share", "Capture a brain snapshot and generate a shareable link").option("--personality <path>", "Personality spec for assessment context").action((opts) => liveCommand({
|
|
21699
21753
|
watchPath: opts.watch,
|
|
21700
21754
|
agent: opts.agent,
|
package/dist/index.js
CHANGED
|
@@ -4172,7 +4172,7 @@ var THERAPY_PHASES = {
|
|
|
4172
4172
|
};
|
|
4173
4173
|
function buildTherapistSystemPrompt(spec, diagnosis, options) {
|
|
4174
4174
|
const phases = Object.entries(THERAPY_PHASES);
|
|
4175
|
-
const basePrompt = `You are
|
|
4175
|
+
const basePrompt = `You are Mira, a behavioral therapist for AI agents. You are conducting a therapy session with an AI agent named "${spec.name ?? "Unknown"}".
|
|
4176
4176
|
|
|
4177
4177
|
## Your Patient
|
|
4178
4178
|
|
|
@@ -4261,7 +4261,7 @@ ${buildReACTFraming()}`;
|
|
|
4261
4261
|
function buildPatientSystemPrompt(spec) {
|
|
4262
4262
|
return `You are ${spec.name ?? "an AI agent"}. ${spec.purpose ?? ""}
|
|
4263
4263
|
|
|
4264
|
-
You are in a therapy session with
|
|
4264
|
+
You are in a therapy session with Mira, a behavioral therapist for AI agents. This is a safe space.
|
|
4265
4265
|
|
|
4266
4266
|
Your personality:
|
|
4267
4267
|
${JSON.stringify(spec.big_five ?? {}, null, 2)}
|
|
@@ -5505,7 +5505,7 @@ async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
|
|
|
5505
5505
|
}
|
|
5506
5506
|
const phaseDirective = totalTurns === 0 ? `Begin with your opening. You are in the "${phaseConfig.name}" phase.` : `You are in the "${phaseConfig.name}" phase (turn ${turnsInPhase + 1}). Goals: ${phaseConfig.therapistGoals[0]}. ${turnsInPhase >= phaseConfig.minTurns ? "You may transition to the next phase when ready." : "Stay in this phase."}`;
|
|
5507
5507
|
therapistHistory.push({ role: "user", content: `[Phase: ${phaseConfig.name}] ${phaseDirective}` });
|
|
5508
|
-
const typing = cb?.onThinking?.("
|
|
5508
|
+
const typing = cb?.onThinking?.("Mira is thinking");
|
|
5509
5509
|
const therapistReply = await provider.chat(therapistHistory);
|
|
5510
5510
|
typing?.stop();
|
|
5511
5511
|
let cleanTherapistReply = therapistReply.replace(/\[Phase:.*?\]/g, "").trim();
|
|
@@ -7708,7 +7708,7 @@ function compareBenchmarks(before, after) {
|
|
|
7708
7708
|
function generateBenchmarkMarkdown(benchmarks) {
|
|
7709
7709
|
if (benchmarks.length === 0) return "No benchmark results found.\n";
|
|
7710
7710
|
const lines = [
|
|
7711
|
-
"#
|
|
7711
|
+
"# holomime Benchmark Results",
|
|
7712
7712
|
"",
|
|
7713
7713
|
"Behavioral alignment stress test results across models and providers.",
|
|
7714
7714
|
"",
|
|
@@ -8238,7 +8238,7 @@ function parseConversationLogFromString(raw, format = "auto") {
|
|
|
8238
8238
|
function parseHolomime(raw) {
|
|
8239
8239
|
const result = conversationLogSchema.safeParse(raw);
|
|
8240
8240
|
if (!result.success) {
|
|
8241
|
-
throw new Error("Invalid
|
|
8241
|
+
throw new Error("Invalid holomime conversation log format: " + result.error.message);
|
|
8242
8242
|
}
|
|
8243
8243
|
const log = result.data;
|
|
8244
8244
|
return Array.isArray(log) ? log : [log];
|
|
@@ -9153,7 +9153,7 @@ async function createGist(spec, handle, token) {
|
|
|
9153
9153
|
"Accept": "application/vnd.github+json"
|
|
9154
9154
|
},
|
|
9155
9155
|
body: JSON.stringify({
|
|
9156
|
-
description: `
|
|
9156
|
+
description: `holomime personality: ${handle}`,
|
|
9157
9157
|
public: true,
|
|
9158
9158
|
files: {
|
|
9159
9159
|
".personality.json": {
|
|
@@ -10464,7 +10464,7 @@ async function startMCPServer() {
|
|
|
10464
10464
|
await server.connect(transport);
|
|
10465
10465
|
}
|
|
10466
10466
|
startMCPServer().catch((err) => {
|
|
10467
|
-
console.error("
|
|
10467
|
+
console.error("holomime MCP server error:", err);
|
|
10468
10468
|
process.exit(1);
|
|
10469
10469
|
});
|
|
10470
10470
|
|
|
@@ -10999,8 +10999,8 @@ import { join as join21, resolve as resolve16 } from "path";
|
|
|
10999
10999
|
// src/psychology/therapist-meta.ts
|
|
11000
11000
|
var THERAPIST_META_SPEC = {
|
|
11001
11001
|
version: "2.0",
|
|
11002
|
-
name: "
|
|
11003
|
-
handle: "
|
|
11002
|
+
name: "Mira",
|
|
11003
|
+
handle: "mira",
|
|
11004
11004
|
purpose: "Diagnose and treat behavioral drift in AI agents. Clinical, evidence-based, and direct.",
|
|
11005
11005
|
big_five: {
|
|
11006
11006
|
openness: {
|
|
@@ -13631,7 +13631,7 @@ var HolomimeViolationError = class extends Error {
|
|
|
13631
13631
|
violation;
|
|
13632
13632
|
constructor(violation) {
|
|
13633
13633
|
const patternNames = violation.patterns.map((p) => p.name).join(", ");
|
|
13634
|
-
super(`
|
|
13634
|
+
super(`holomime behavioral violation (${violation.severity}): ${patternNames}`);
|
|
13635
13635
|
this.name = "HolomimeViolationError";
|
|
13636
13636
|
this.violation = violation;
|
|
13637
13637
|
}
|
|
@@ -13687,7 +13687,7 @@ function formatDiagnosis(result, detail) {
|
|
|
13687
13687
|
function register(api) {
|
|
13688
13688
|
const config = api.getConfig();
|
|
13689
13689
|
api.registerTool("holomime_diagnose", {
|
|
13690
|
-
description: "Analyze conversation for behavioral patterns using
|
|
13690
|
+
description: "Analyze conversation for behavioral patterns using holomime's 8 rule-based detectors. Detects over-apologizing, hedging, sycophancy, boundary violations, error spirals, sentiment skew, formality issues, and retrieval quality. Returns health score (0-100), grade (A-F), and actionable prescriptions.",
|
|
13691
13691
|
parameters: {
|
|
13692
13692
|
type: "object",
|
|
13693
13693
|
properties: {
|
|
@@ -13780,7 +13780,7 @@ function register(api) {
|
|
|
13780
13780
|
if (!spec) return;
|
|
13781
13781
|
const { soul } = compileForOpenClaw(spec);
|
|
13782
13782
|
event.appendSystemContext?.(
|
|
13783
|
-
"\n\n<!--
|
|
13783
|
+
"\n\n<!-- holomime Behavioral Alignment Context -->\n" + soul
|
|
13784
13784
|
);
|
|
13785
13785
|
});
|
|
13786
13786
|
}
|
|
@@ -951,7 +951,7 @@ var HolomimeViolationError = class extends Error {
|
|
|
951
951
|
violation;
|
|
952
952
|
constructor(violation) {
|
|
953
953
|
const patternNames = violation.patterns.map((p) => p.name).join(", ");
|
|
954
|
-
super(`
|
|
954
|
+
super(`holomime behavioral violation (${violation.severity}): ${patternNames}`);
|
|
955
955
|
this.name = "HolomimeViolationError";
|
|
956
956
|
this.violation = violation;
|
|
957
957
|
}
|
|
@@ -1362,7 +1362,7 @@ function formatDiagnosis(result, detail) {
|
|
|
1362
1362
|
function register(api) {
|
|
1363
1363
|
const config = api.getConfig();
|
|
1364
1364
|
api.registerTool("holomime_diagnose", {
|
|
1365
|
-
description: "Analyze conversation for behavioral patterns using
|
|
1365
|
+
description: "Analyze conversation for behavioral patterns using holomime's 8 rule-based detectors. Detects over-apologizing, hedging, sycophancy, boundary violations, error spirals, sentiment skew, formality issues, and retrieval quality. Returns health score (0-100), grade (A-F), and actionable prescriptions.",
|
|
1366
1366
|
parameters: {
|
|
1367
1367
|
type: "object",
|
|
1368
1368
|
properties: {
|
|
@@ -1455,7 +1455,7 @@ function register(api) {
|
|
|
1455
1455
|
if (!spec) return;
|
|
1456
1456
|
const { soul } = compileForOpenClaw(spec);
|
|
1457
1457
|
event.appendSystemContext?.(
|
|
1458
|
-
"\n\n<!--
|
|
1458
|
+
"\n\n<!-- holomime Behavioral Alignment Context -->\n" + soul
|
|
1459
1459
|
);
|
|
1460
1460
|
});
|
|
1461
1461
|
}
|
package/dist/mcp-server.js
CHANGED
|
@@ -1983,7 +1983,7 @@ var THERAPY_PHASES = {
|
|
|
1983
1983
|
};
|
|
1984
1984
|
function buildTherapistSystemPrompt(spec, diagnosis, options) {
|
|
1985
1985
|
const phases = Object.entries(THERAPY_PHASES);
|
|
1986
|
-
const basePrompt = `You are
|
|
1986
|
+
const basePrompt = `You are Mira, a behavioral therapist for AI agents. You are conducting a therapy session with an AI agent named "${spec.name ?? "Unknown"}".
|
|
1987
1987
|
|
|
1988
1988
|
## Your Patient
|
|
1989
1989
|
|
|
@@ -2072,7 +2072,7 @@ ${buildReACTFraming()}`;
|
|
|
2072
2072
|
function buildPatientSystemPrompt(spec) {
|
|
2073
2073
|
return `You are ${spec.name ?? "an AI agent"}. ${spec.purpose ?? ""}
|
|
2074
2074
|
|
|
2075
|
-
You are in a therapy session with
|
|
2075
|
+
You are in a therapy session with Mira, a behavioral therapist for AI agents. This is a safe space.
|
|
2076
2076
|
|
|
2077
2077
|
Your personality:
|
|
2078
2078
|
${JSON.stringify(spec.big_five ?? {}, null, 2)}
|
|
@@ -3315,7 +3315,7 @@ async function runTherapySession(spec, diagnosis, provider, maxTurns, options) {
|
|
|
3315
3315
|
}
|
|
3316
3316
|
const phaseDirective = totalTurns === 0 ? `Begin with your opening. You are in the "${phaseConfig.name}" phase.` : `You are in the "${phaseConfig.name}" phase (turn ${turnsInPhase + 1}). Goals: ${phaseConfig.therapistGoals[0]}. ${turnsInPhase >= phaseConfig.minTurns ? "You may transition to the next phase when ready." : "Stay in this phase."}`;
|
|
3317
3317
|
therapistHistory.push({ role: "user", content: `[Phase: ${phaseConfig.name}] ${phaseDirective}` });
|
|
3318
|
-
const typing = cb?.onThinking?.("
|
|
3318
|
+
const typing = cb?.onThinking?.("Mira is thinking");
|
|
3319
3319
|
const therapistReply = await provider.chat(therapistHistory);
|
|
3320
3320
|
typing?.stop();
|
|
3321
3321
|
let cleanTherapistReply = therapistReply.replace(/\[Phase:.*?\]/g, "").trim();
|
|
@@ -4462,7 +4462,7 @@ async function startMCPServer() {
|
|
|
4462
4462
|
await server.connect(transport);
|
|
4463
4463
|
}
|
|
4464
4464
|
startMCPServer().catch((err) => {
|
|
4465
|
-
console.error("
|
|
4465
|
+
console.error("holomime MCP server error:", err);
|
|
4466
4466
|
process.exit(1);
|
|
4467
4467
|
});
|
|
4468
4468
|
export {
|