@ouro.bot/cli 0.1.0-alpha.726 → 0.1.0-alpha.728
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/README.md +14 -1
- package/assets/bluebubbles-host +264 -0
- package/changelog.json +18 -0
- package/dist/heart/config.js +1 -2
- package/dist/heart/core.js +181 -209
- package/dist/heart/daemon/bluebubbles-cli-integration.js +71 -0
- package/dist/heart/daemon/bluebubbles-host-protocol.js +433 -0
- package/dist/heart/daemon/bluebubbles-host.js +273 -0
- package/dist/heart/daemon/cli-defaults.js +8 -1
- package/dist/heart/daemon/cli-exec.js +239 -34
- package/dist/heart/daemon/cli-help.js +17 -6
- package/dist/heart/daemon/cli-parse.js +69 -1
- package/dist/heart/daemon/cli-render.js +7 -0
- package/dist/heart/daemon/daemon.js +79 -14
- package/dist/heart/daemon/doctor.js +21 -1
- package/dist/heart/daemon/mcp-canary.js +160 -29
- package/dist/heart/daemon/process-manager.js +100 -18
- package/dist/heart/daemon/socket-client.js +28 -19
- package/dist/heart/providers/anthropic.js +17 -12
- package/dist/heart/streaming.js +6 -6
- package/dist/heart/versioning/ouro-path-installer.js +30 -24
- package/dist/heart/versioning/ouro-recovery-launcher.js +76 -0
- package/dist/heart/versioning/version-intent.js +114 -0
- package/dist/mind/prompt-budget.js +104 -5
- package/dist/repertoire/tools.js +0 -10
- package/dist/senses/bluebubbles/client.js +43 -57
- package/dist/senses/bluebubbles/context-packet.js +104 -19
- package/dist/senses/bluebubbles/entry.js +14 -1
- package/dist/senses/bluebubbles/index.js +1398 -719
- package/dist/senses/bluebubbles/latest-turn.js +311 -0
- package/dist/senses/bluebubbles/outbound-state.js +4 -0
- package/dist/senses/bluebubbles/reaction-policy.js +4 -12
- package/dist/senses/bluebubbles/semantic-receipts.js +178 -10
- package/dist/senses/bluebubbles/webhook-registration.js +228 -0
- package/package.json +4 -2
package/dist/heart/streaming.js
CHANGED
|
@@ -496,14 +496,14 @@ function toResponsesUserContent(content) {
|
|
|
496
496
|
return parts.length > 0 ? parts : "";
|
|
497
497
|
}
|
|
498
498
|
function toResponsesInput(messages) {
|
|
499
|
-
|
|
499
|
+
const instructionParts = [];
|
|
500
500
|
const input = [];
|
|
501
501
|
for (const msg of messages) {
|
|
502
502
|
if (msg.role === "system") {
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
503
|
+
const sys = msg;
|
|
504
|
+
const content = (typeof sys.content === "string" ? sys.content : "").trim();
|
|
505
|
+
if (content)
|
|
506
|
+
instructionParts.push(content);
|
|
507
507
|
continue;
|
|
508
508
|
}
|
|
509
509
|
if (msg.role === "user") {
|
|
@@ -551,7 +551,7 @@ function toResponsesInput(messages) {
|
|
|
551
551
|
continue;
|
|
552
552
|
}
|
|
553
553
|
}
|
|
554
|
-
return { instructions, input };
|
|
554
|
+
return { instructions: instructionParts.join("\n\n"), input };
|
|
555
555
|
}
|
|
556
556
|
function toResponsesTools(ccTools) {
|
|
557
557
|
return ccTools.map((t) => ({
|
|
@@ -39,28 +39,20 @@ const fs = __importStar(require("fs"));
|
|
|
39
39
|
const os = __importStar(require("os"));
|
|
40
40
|
const path = __importStar(require("path"));
|
|
41
41
|
const runtime_1 = require("../../nerves/runtime");
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
if [ -f "$DEV_CONFIG" ] && [ "$1" != "up" ]; then
|
|
47
|
-
DEV_REPO=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$DEV_CONFIG','utf-8')).repoPath)}catch{}" 2>/dev/null)
|
|
48
|
-
DEV_ENTRY="$DEV_REPO/dist/heart/daemon/ouro-entry.js"
|
|
49
|
-
if [ -n "$DEV_REPO" ] && [ -e "$DEV_ENTRY" ]; then
|
|
50
|
-
exec node "$DEV_ENTRY" "$@"
|
|
51
|
-
fi
|
|
52
|
-
fi
|
|
53
|
-
# Fall back to installed version
|
|
54
|
-
ENTRY="$HOME/.ouro-cli/CurrentVersion/node_modules/@ouro.bot/cli/dist/heart/daemon/ouro-entry.js"
|
|
55
|
-
if [ ! -e "$ENTRY" ]; then
|
|
56
|
-
echo "ouro not installed. Run: npx ouro.bot@latest" >&2
|
|
57
|
-
exit 1
|
|
58
|
-
fi
|
|
59
|
-
exec node "$ENTRY" "$@"
|
|
60
|
-
`;
|
|
61
|
-
function writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync) {
|
|
42
|
+
const ouro_recovery_launcher_1 = require("./ouro-recovery-launcher");
|
|
43
|
+
const WRAPPER_SCRIPT = ouro_recovery_launcher_1.OURO_WRAPPER_SCRIPT;
|
|
44
|
+
function writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync, renameSync, existsSync, readFileSync) {
|
|
45
|
+
const assets = (0, ouro_recovery_launcher_1.resolveOuroRecoveryLauncherAssets)();
|
|
62
46
|
mkdirSync(path.dirname(scriptPath), { recursive: true });
|
|
63
|
-
|
|
47
|
+
const launcherPath = path.join(path.dirname(scriptPath), "ouro-launcher.js");
|
|
48
|
+
const launcherTempPath = `${launcherPath}.next-${process.pid}`;
|
|
49
|
+
writeFileSync(launcherTempPath, assets.launcherScript, { mode: 0o755 });
|
|
50
|
+
chmodSync(launcherTempPath, 0o755);
|
|
51
|
+
renameSync(launcherTempPath, launcherPath);
|
|
52
|
+
if (existsSync(launcherPath) && readFileSync(launcherPath, "utf8") !== assets.launcherScript) {
|
|
53
|
+
throw new Error("failed to verify installed Ouro recovery launcher");
|
|
54
|
+
}
|
|
55
|
+
writeFileSync(scriptPath, assets.wrapperScript, { mode: 0o755 });
|
|
64
56
|
chmodSync(scriptPath, 0o755);
|
|
65
57
|
}
|
|
66
58
|
function detectShellProfile(homeDir, shell, platform) {
|
|
@@ -106,6 +98,16 @@ function isWrapperCurrent(scriptPath, existsSync, readFileSync) {
|
|
|
106
98
|
return false;
|
|
107
99
|
}
|
|
108
100
|
}
|
|
101
|
+
function isRecoveryLauncherCurrent(scriptPath, existsSync, readFileSync) {
|
|
102
|
+
if (!existsSync(scriptPath))
|
|
103
|
+
return false;
|
|
104
|
+
try {
|
|
105
|
+
return readFileSync(scriptPath, "utf-8") === ouro_recovery_launcher_1.OURO_RECOVERY_LAUNCHER_SCRIPT;
|
|
106
|
+
}
|
|
107
|
+
catch {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
}
|
|
109
111
|
function isOwnedOuroLauncherPath(resolvedPath) {
|
|
110
112
|
const normalized = path.normalize(resolvedPath);
|
|
111
113
|
return (normalized.includes(`${path.sep}node_modules${path.sep}@ouro.bot${path.sep}cli${path.sep}`) ||
|
|
@@ -116,7 +118,8 @@ function isOwnedOuroLauncherContent(content) {
|
|
|
116
118
|
content.includes("ouro.bot@latest") ||
|
|
117
119
|
content.includes("ouro.bot@alpha") ||
|
|
118
120
|
content.includes('exec npx --yes ouro.bot "$@"') ||
|
|
119
|
-
content.includes("CurrentVersion/node_modules/@ouro.bot/cli")
|
|
121
|
+
content.includes("CurrentVersion/node_modules/@ouro.bot/cli") ||
|
|
122
|
+
content.includes(".ouro-cli/bin/ouro-launcher.js"));
|
|
120
123
|
}
|
|
121
124
|
function canRepairShadowedLauncher(shadowPath, existsSync, readFileSync, realpathSync) {
|
|
122
125
|
if (!existsSync(shadowPath))
|
|
@@ -236,6 +239,7 @@ function installOuroCommand(deps = {}) {
|
|
|
236
239
|
const realpathSync = deps.realpathSync ?? fs.realpathSync;
|
|
237
240
|
const lstatSync = deps.lstatSync ?? fs.lstatSync;
|
|
238
241
|
const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
|
|
242
|
+
const renameSync = deps.renameSync ?? fs.renameSync;
|
|
239
243
|
const envPath = deps.envPath ?? process.env.PATH ?? "";
|
|
240
244
|
const shell = deps.shell ?? process.env.SHELL;
|
|
241
245
|
/* v8 ignore stop */
|
|
@@ -254,9 +258,11 @@ function installOuroCommand(deps = {}) {
|
|
|
254
258
|
}
|
|
255
259
|
const binDir = path.join(homeDir, ".ouro-cli", "bin");
|
|
256
260
|
const scriptPath = path.join(binDir, "ouro");
|
|
261
|
+
const recoveryLauncherPath = path.join(binDir, "ouro-launcher.js");
|
|
257
262
|
const oldScriptPath = path.join(homeDir, ".local", "bin", "ouro");
|
|
258
263
|
const resolvePath = () => diagnoseOuroPath({ homeDir, envPath, existsSync, readFileSync });
|
|
259
|
-
const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync)
|
|
264
|
+
const modernCurrent = isWrapperCurrent(scriptPath, existsSync, readFileSync)
|
|
265
|
+
&& isRecoveryLauncherCurrent(recoveryLauncherPath, existsSync, readFileSync);
|
|
260
266
|
const oldExists = existsSync(oldScriptPath);
|
|
261
267
|
const oldCurrent = oldExists && isWrapperCurrent(oldScriptPath, existsSync, readFileSync);
|
|
262
268
|
// ── Repair old ~/.local/bin/ouro launcher ──
|
|
@@ -332,7 +338,7 @@ function installOuroCommand(deps = {}) {
|
|
|
332
338
|
});
|
|
333
339
|
try {
|
|
334
340
|
if (!modernCurrent) {
|
|
335
|
-
writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync);
|
|
341
|
+
writeWrapperScript(scriptPath, mkdirSync, writeFileSync, chmodSync, renameSync, existsSync, readFileSync);
|
|
336
342
|
}
|
|
337
343
|
}
|
|
338
344
|
catch (error) {
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.OURO_WRAPPER_SCRIPT = exports.OURO_RECOVERY_LAUNCHER_SCRIPT = void 0;
|
|
4
|
+
exports.resolveOuroRecoveryLauncherAssets = resolveOuroRecoveryLauncherAssets;
|
|
5
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
6
|
+
exports.OURO_RECOVERY_LAUNCHER_SCRIPT = `#!/usr/bin/env node
|
|
7
|
+
"use strict";
|
|
8
|
+
const fs = require("fs");
|
|
9
|
+
const os = require("os");
|
|
10
|
+
const path = require("path");
|
|
11
|
+
const cp = require("child_process");
|
|
12
|
+
const home = path.join(os.homedir(), ".ouro-cli");
|
|
13
|
+
const current = path.join(home, "CurrentVersion");
|
|
14
|
+
const intentPath = path.join(home, "version-intent.json");
|
|
15
|
+
const entryRel = "node_modules/@ouro.bot/cli/dist/heart/daemon/ouro-entry.js";
|
|
16
|
+
let intent = null;
|
|
17
|
+
try {
|
|
18
|
+
intent = JSON.parse(fs.readFileSync(intentPath, "utf8"));
|
|
19
|
+
if (intent.schemaVersion !== 1 || !["pinned", "latest"].includes(intent.mode) || !intent.targetVersion) throw new Error("invalid fields");
|
|
20
|
+
} catch (error) {
|
|
21
|
+
if (error && error.code !== "ENOENT") {
|
|
22
|
+
process.stderr.write("invalid Ouro version intent: " + error.message + "\\n");
|
|
23
|
+
process.exit(1);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
if (intent) {
|
|
27
|
+
const target = path.join(home, "versions", intent.targetVersion);
|
|
28
|
+
const targetEntry = path.join(target, entryRel);
|
|
29
|
+
if (!fs.existsSync(targetEntry)) {
|
|
30
|
+
process.stderr.write("Ouro version intent target is not installed: " + intent.targetVersion + "\\n");
|
|
31
|
+
process.exit(1);
|
|
32
|
+
}
|
|
33
|
+
let active = null;
|
|
34
|
+
try { active = path.basename(fs.readlinkSync(current)); } catch {}
|
|
35
|
+
if (active !== intent.targetVersion) {
|
|
36
|
+
const next = current + ".next-" + process.pid;
|
|
37
|
+
try { fs.unlinkSync(next); } catch {}
|
|
38
|
+
fs.symlinkSync(target, next);
|
|
39
|
+
fs.renameSync(next, current);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const entry = path.join(current, entryRel);
|
|
43
|
+
if (!fs.existsSync(entry)) {
|
|
44
|
+
process.stderr.write("ouro not installed. Run: npx ouro.bot@latest\\n");
|
|
45
|
+
process.exit(1);
|
|
46
|
+
}
|
|
47
|
+
const result = cp.spawnSync(process.execPath, [entry, ...process.argv.slice(2)], { stdio: "inherit" });
|
|
48
|
+
if (result.error) throw result.error;
|
|
49
|
+
if (result.signal) process.kill(process.pid, result.signal);
|
|
50
|
+
process.exit(result.status == null ? 1 : result.status);
|
|
51
|
+
`;
|
|
52
|
+
exports.OURO_WRAPPER_SCRIPT = `#!/bin/sh
|
|
53
|
+
# Check for dev mode — if dev-config.json exists, dispatch to the dev repo.
|
|
54
|
+
# Skip dev dispatch for "up" command (explicitly returns to production).
|
|
55
|
+
DEV_CONFIG="$HOME/.ouro-cli/dev-config.json"
|
|
56
|
+
if [ -f "$DEV_CONFIG" ] && [ "$1" != "up" ]; then
|
|
57
|
+
DEV_REPO=$(node -e "try{console.log(JSON.parse(require('fs').readFileSync('$DEV_CONFIG','utf-8')).repoPath)}catch{}" 2>/dev/null)
|
|
58
|
+
DEV_ENTRY="$DEV_REPO/dist/heart/daemon/ouro-entry.js"
|
|
59
|
+
if [ -n "$DEV_REPO" ] && [ -e "$DEV_ENTRY" ]; then
|
|
60
|
+
exec node "$DEV_ENTRY" "$@"
|
|
61
|
+
fi
|
|
62
|
+
fi
|
|
63
|
+
exec node "$HOME/.ouro-cli/bin/ouro-launcher.js" "$@"
|
|
64
|
+
`;
|
|
65
|
+
function resolveOuroRecoveryLauncherAssets() {
|
|
66
|
+
(0, runtime_1.emitNervesEvent)({
|
|
67
|
+
component: "daemon",
|
|
68
|
+
event: "daemon.ouro_recovery_launcher_assets_resolved",
|
|
69
|
+
message: "resolved stable CLI recovery launcher assets",
|
|
70
|
+
meta: { launcher: "ouro-launcher.js", wrapper: "ouro" },
|
|
71
|
+
});
|
|
72
|
+
return {
|
|
73
|
+
launcherScript: exports.OURO_RECOVERY_LAUNCHER_SCRIPT,
|
|
74
|
+
wrapperScript: exports.OURO_WRAPPER_SCRIPT,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.versionIntentPath = versionIntentPath;
|
|
37
|
+
exports.readVersionIntent = readVersionIntent;
|
|
38
|
+
exports.writeVersionIntent = writeVersionIntent;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const os = __importStar(require("os"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const runtime_1 = require("../../nerves/runtime");
|
|
43
|
+
function versionIntentPath(homeDir = os.homedir()) {
|
|
44
|
+
return path.join(homeDir, ".ouro-cli", "version-intent.json");
|
|
45
|
+
}
|
|
46
|
+
function parseVersionIntent(raw) {
|
|
47
|
+
let value;
|
|
48
|
+
try {
|
|
49
|
+
value = JSON.parse(raw);
|
|
50
|
+
}
|
|
51
|
+
catch {
|
|
52
|
+
throw new Error("invalid version intent: malformed JSON");
|
|
53
|
+
}
|
|
54
|
+
if (!value
|
|
55
|
+
|| typeof value !== "object"
|
|
56
|
+
|| value.schemaVersion !== 1
|
|
57
|
+
|| !["pinned", "latest"].includes(String(value.mode))
|
|
58
|
+
|| typeof value.targetVersion !== "string"
|
|
59
|
+
|| !value.targetVersion) {
|
|
60
|
+
throw new Error("invalid version intent: expected schemaVersion=1, mode, and targetVersion");
|
|
61
|
+
}
|
|
62
|
+
return value;
|
|
63
|
+
}
|
|
64
|
+
function readVersionIntent(deps = {}) {
|
|
65
|
+
const readFileSync = deps.readFileSync ?? fs.readFileSync;
|
|
66
|
+
try {
|
|
67
|
+
return parseVersionIntent(readFileSync(versionIntentPath(deps.homeDir), "utf8"));
|
|
68
|
+
}
|
|
69
|
+
catch (error) {
|
|
70
|
+
if (error.code === "ENOENT")
|
|
71
|
+
return null;
|
|
72
|
+
throw error;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
function writeVersionIntent(intent, deps = {}) {
|
|
76
|
+
const mkdirSync = deps.mkdirSync ?? fs.mkdirSync;
|
|
77
|
+
const writeFileSync = deps.writeFileSync ?? fs.writeFileSync;
|
|
78
|
+
const renameSync = deps.renameSync ?? fs.renameSync;
|
|
79
|
+
const unlinkSync = deps.unlinkSync ?? fs.unlinkSync;
|
|
80
|
+
const randomUUID = deps.randomUUID ?? (() => `${process.pid}-${Date.now()}`);
|
|
81
|
+
const destination = versionIntentPath(deps.homeDir);
|
|
82
|
+
const temporary = `${destination}.${randomUUID()}.tmp`;
|
|
83
|
+
(0, runtime_1.emitNervesEvent)({
|
|
84
|
+
component: "daemon",
|
|
85
|
+
event: "daemon.version_intent_write_start",
|
|
86
|
+
message: "writing CLI version intent",
|
|
87
|
+
meta: { mode: intent.mode, targetVersion: intent.targetVersion },
|
|
88
|
+
});
|
|
89
|
+
try {
|
|
90
|
+
mkdirSync(path.dirname(destination), { recursive: true });
|
|
91
|
+
writeFileSync(temporary, `${JSON.stringify(intent, null, 2)}\n`, { encoding: "utf8", mode: 0o600 });
|
|
92
|
+
renameSync(temporary, destination);
|
|
93
|
+
(0, runtime_1.emitNervesEvent)({
|
|
94
|
+
component: "daemon",
|
|
95
|
+
event: "daemon.version_intent_write_end",
|
|
96
|
+
message: "CLI version intent written",
|
|
97
|
+
meta: { mode: intent.mode, targetVersion: intent.targetVersion },
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch (error) {
|
|
101
|
+
try {
|
|
102
|
+
unlinkSync(temporary);
|
|
103
|
+
}
|
|
104
|
+
catch { /* best-effort temporary cleanup */ }
|
|
105
|
+
(0, runtime_1.emitNervesEvent)({
|
|
106
|
+
component: "daemon",
|
|
107
|
+
event: "daemon.version_intent_write_error",
|
|
108
|
+
level: "error",
|
|
109
|
+
message: "failed to write CLI version intent",
|
|
110
|
+
meta: { mode: intent.mode, targetVersion: intent.targetVersion, error: error instanceof Error ? error.message : String(error) },
|
|
111
|
+
});
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.PROMPT_BUDGET_FALLBACK_CONTEXT_WINDOW_TOKENS = exports.PROMPT_BUDGET_POLICY_VERSION = void 0;
|
|
4
4
|
exports.estimatePromptBudgetTokensForMessage = estimatePromptBudgetTokensForMessage;
|
|
5
5
|
exports.estimatePromptBudgetTokens = estimatePromptBudgetTokens;
|
|
6
|
+
exports.assessRequiredPromptEvidenceBudget = assessRequiredPromptEvidenceBudget;
|
|
6
7
|
exports.applyPromptBudget = applyPromptBudget;
|
|
7
8
|
const runtime_1 = require("../nerves/runtime");
|
|
8
9
|
exports.PROMPT_BUDGET_POLICY_VERSION = "prompt-budget/v1";
|
|
@@ -89,6 +90,42 @@ function itemTokens(item) {
|
|
|
89
90
|
function cloneMessage(message) {
|
|
90
91
|
return { ...message };
|
|
91
92
|
}
|
|
93
|
+
function requiredMessagesByIdentity(input) {
|
|
94
|
+
const evidence = input.requiredPromptEvidence;
|
|
95
|
+
if (!evidence)
|
|
96
|
+
return [];
|
|
97
|
+
const current = evidence.currentUserMessage;
|
|
98
|
+
if (current.role !== "user") {
|
|
99
|
+
throw new Error("required current user message must have role=user");
|
|
100
|
+
}
|
|
101
|
+
const currentMatches = input.messages.filter((message) => message === current);
|
|
102
|
+
if (currentMatches.length !== 1) {
|
|
103
|
+
throw new Error(currentMatches.length === 0
|
|
104
|
+
? "required current user message is not present by identity"
|
|
105
|
+
: "required current user message must appear exactly once by identity");
|
|
106
|
+
}
|
|
107
|
+
const predecessor = evidence.verifiedPredecessorMessage;
|
|
108
|
+
if (predecessor) {
|
|
109
|
+
if (predecessor === current)
|
|
110
|
+
throw new Error("required predecessor and current user message must be distinct objects");
|
|
111
|
+
if (predecessor.role !== "system") {
|
|
112
|
+
throw new Error("required verified predecessor message must have role=system");
|
|
113
|
+
}
|
|
114
|
+
const predecessorMatches = input.messages.filter((message) => message === predecessor);
|
|
115
|
+
if (predecessorMatches.length !== 1) {
|
|
116
|
+
throw new Error(predecessorMatches.length === 0
|
|
117
|
+
? "required verified predecessor message is not present by identity"
|
|
118
|
+
: "required verified predecessor message must appear exactly once by identity");
|
|
119
|
+
}
|
|
120
|
+
if (input.messages.indexOf(predecessor) !== input.messages.indexOf(current) - 1) {
|
|
121
|
+
throw new Error("required verified predecessor message must be immediately before the current user message");
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return input.messages.filter((message) => message === current || message === predecessor);
|
|
125
|
+
}
|
|
126
|
+
function cloneUnlessRequired(message, requiredMessages) {
|
|
127
|
+
return requiredMessages.has(message) ? message : cloneMessage(message);
|
|
128
|
+
}
|
|
92
129
|
function messageText(message) {
|
|
93
130
|
return typeof message.content === "string" ? message.content : "";
|
|
94
131
|
}
|
|
@@ -197,11 +234,35 @@ function nonSystemSourceFor(messages) {
|
|
|
197
234
|
return "diagnostics";
|
|
198
235
|
return "recent-session-tail";
|
|
199
236
|
}
|
|
200
|
-
function buildPromptBudgetItems(messages) {
|
|
237
|
+
function buildPromptBudgetItems(messages, requiredPromptEvidence) {
|
|
201
238
|
const rawItems = [];
|
|
202
239
|
let index = 0;
|
|
203
240
|
while (index < messages.length) {
|
|
204
241
|
const message = messages[index];
|
|
242
|
+
if (message === requiredPromptEvidence?.currentUserMessage) {
|
|
243
|
+
rawItems.push({
|
|
244
|
+
id: `required:${index}:current`,
|
|
245
|
+
priority: 1,
|
|
246
|
+
source: "current-user-message",
|
|
247
|
+
messages: [message],
|
|
248
|
+
originalMessageCount: 1,
|
|
249
|
+
required: "current-user",
|
|
250
|
+
});
|
|
251
|
+
index += 1;
|
|
252
|
+
continue;
|
|
253
|
+
}
|
|
254
|
+
if (message === requiredPromptEvidence?.verifiedPredecessorMessage) {
|
|
255
|
+
rawItems.push({
|
|
256
|
+
id: `required:${index}:predecessor`,
|
|
257
|
+
priority: 1,
|
|
258
|
+
source: "required-current-turn-state",
|
|
259
|
+
messages: [message],
|
|
260
|
+
originalMessageCount: 1,
|
|
261
|
+
required: "verified-predecessor",
|
|
262
|
+
});
|
|
263
|
+
index += 1;
|
|
264
|
+
continue;
|
|
265
|
+
}
|
|
205
266
|
if (message.role === "system") {
|
|
206
267
|
rawItems.push(...systemItems(message, index));
|
|
207
268
|
index += 1;
|
|
@@ -236,6 +297,8 @@ function buildPromptBudgetItems(messages) {
|
|
|
236
297
|
const lastUserItemIndex = rawItems.findLastIndex((item) => item.messages.some((message) => message.role === "user"));
|
|
237
298
|
const latestToolItemIndex = rawItems.findLastIndex((item) => item.messages.some((message) => message.role === "tool" || assistantHasToolCalls(message)));
|
|
238
299
|
return rawItems.map((item, itemIndex) => {
|
|
300
|
+
if (item.required)
|
|
301
|
+
return item;
|
|
239
302
|
if (itemIndex === lastUserItemIndex) {
|
|
240
303
|
return { ...item, priority: 1, source: "current-user-message" };
|
|
241
304
|
}
|
|
@@ -254,7 +317,7 @@ function buildPromptBudgetItems(messages) {
|
|
|
254
317
|
});
|
|
255
318
|
}
|
|
256
319
|
function flattenItems(items) {
|
|
257
|
-
return items.flatMap((item) => item.messages.map(cloneMessage));
|
|
320
|
+
return items.flatMap((item) => item.messages.map((message) => item.required ? message : cloneMessage(message)));
|
|
258
321
|
}
|
|
259
322
|
function budgetFor(input) {
|
|
260
323
|
const contextWindowTokens = typeof input.contextWindowTokens === "number" && Number.isFinite(input.contextWindowTokens) && input.contextWindowTokens > 0
|
|
@@ -273,6 +336,19 @@ function budgetFor(input) {
|
|
|
273
336
|
inputTokenLimit: Math.max(0, contextWindowTokens - outputReserveTokens - protocolReserveTokens),
|
|
274
337
|
};
|
|
275
338
|
}
|
|
339
|
+
function assessRequiredPromptEvidenceBudget(input) {
|
|
340
|
+
const budget = budgetFor(input);
|
|
341
|
+
const messages = requiredMessagesByIdentity(input);
|
|
342
|
+
const estimatedTokens = estimatePromptBudgetTokens(messages);
|
|
343
|
+
return {
|
|
344
|
+
status: messages.length > 0 && estimatedTokens > budget.inputTokenLimit
|
|
345
|
+
? "required_evidence_over_budget"
|
|
346
|
+
: "within_budget",
|
|
347
|
+
messages,
|
|
348
|
+
estimatedTokens,
|
|
349
|
+
budget,
|
|
350
|
+
};
|
|
351
|
+
}
|
|
276
352
|
function totalItemTokens(items) {
|
|
277
353
|
return estimatePromptBudgetTokens(flattenItems(items));
|
|
278
354
|
}
|
|
@@ -304,15 +380,38 @@ function emitPromptBudgetEvent(result) {
|
|
|
304
380
|
});
|
|
305
381
|
}
|
|
306
382
|
function applyPromptBudget(input) {
|
|
307
|
-
const
|
|
383
|
+
const requiredAssessment = assessRequiredPromptEvidenceBudget(input);
|
|
384
|
+
const budget = requiredAssessment.budget;
|
|
308
385
|
const estimatedBeforeTokens = estimatePromptBudgetTokens(input.messages);
|
|
309
386
|
const truncations = [];
|
|
387
|
+
const requiredMessages = requiredAssessment.messages;
|
|
388
|
+
const requiredMessageSet = new Set(requiredMessages);
|
|
310
389
|
let droppedMessages = 0;
|
|
390
|
+
const requiredTokens = requiredAssessment.estimatedTokens;
|
|
391
|
+
if (requiredAssessment.status === "required_evidence_over_budget") {
|
|
392
|
+
droppedMessages = input.messages.length - requiredMessages.length;
|
|
393
|
+
const result = {
|
|
394
|
+
policyVersion: exports.PROMPT_BUDGET_POLICY_VERSION,
|
|
395
|
+
status: "required_evidence_over_budget",
|
|
396
|
+
messages: requiredMessages,
|
|
397
|
+
budget,
|
|
398
|
+
stats: {
|
|
399
|
+
estimatedBeforeTokens,
|
|
400
|
+
estimatedAfterTokens: requiredTokens,
|
|
401
|
+
originalMessages: input.messages.length,
|
|
402
|
+
finalMessages: requiredMessages.length,
|
|
403
|
+
droppedMessages,
|
|
404
|
+
truncations,
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
emitPromptBudgetEvent(result);
|
|
408
|
+
return result;
|
|
409
|
+
}
|
|
311
410
|
if (estimatedBeforeTokens <= budget.inputTokenLimit) {
|
|
312
411
|
const result = {
|
|
313
412
|
policyVersion: exports.PROMPT_BUDGET_POLICY_VERSION,
|
|
314
413
|
status: "within_budget",
|
|
315
|
-
messages: input.messages.map(
|
|
414
|
+
messages: input.messages.map((message) => cloneUnlessRequired(message, requiredMessageSet)),
|
|
316
415
|
budget,
|
|
317
416
|
stats: {
|
|
318
417
|
estimatedBeforeTokens,
|
|
@@ -326,7 +425,7 @@ function applyPromptBudget(input) {
|
|
|
326
425
|
emitPromptBudgetEvent(result);
|
|
327
426
|
return result;
|
|
328
427
|
}
|
|
329
|
-
let items = buildPromptBudgetItems(input.messages);
|
|
428
|
+
let items = buildPromptBudgetItems(input.messages, input.requiredPromptEvidence);
|
|
330
429
|
for (const priority of [8, 7, 6, 5, 4, 3]) {
|
|
331
430
|
if (totalItemTokens(items) <= budget.inputTokenLimit)
|
|
332
431
|
break;
|
package/dist/repertoire/tools.js
CHANGED
|
@@ -3,7 +3,6 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.surfaceToolDef = exports.speakTool = exports.restTool = exports.ponderTool = exports.observeTool = exports.settleTool = exports.tools = void 0;
|
|
4
4
|
exports.resetMcpDefinitions = resetMcpDefinitions;
|
|
5
5
|
exports.getToolsForChannel = getToolsForChannel;
|
|
6
|
-
exports.getRestrictedReactionFeedbackTools = getRestrictedReactionFeedbackTools;
|
|
7
6
|
exports.resolveToolDefinition = resolveToolDefinition;
|
|
8
7
|
exports.shellRiskProfile = shellRiskProfile;
|
|
9
8
|
exports.riskProfileForTool = riskProfileForTool;
|
|
@@ -127,15 +126,6 @@ function getToolsForChannel(capabilities, toolPreferences, _context, providerCap
|
|
|
127
126
|
}
|
|
128
127
|
return filterByCapability(result, providerCapabilities);
|
|
129
128
|
}
|
|
130
|
-
/**
|
|
131
|
-
* The complete provider-facing tool surface for trusted reaction feedback.
|
|
132
|
-
* Keep these schemas sourced from the normal registry so restricted turns
|
|
133
|
-
* cannot drift onto lookalike definitions or inherit channel/MCP tools.
|
|
134
|
-
*/
|
|
135
|
-
function getRestrictedReactionFeedbackTools() {
|
|
136
|
-
const orientationGetTool = tools_base_1.baseToolDefinitions.find((definition) => definition.tool.function.name === "orientation_get").tool;
|
|
137
|
-
return [tools_base_1.settleTool, tools_base_1.observeTool, orientationGetTool];
|
|
138
|
-
}
|
|
139
129
|
// Look up a tool definition from the live combined registry (native + MCP).
|
|
140
130
|
// The base registry is intentionally consulted at call time so tests and
|
|
141
131
|
// runtime extensions cannot leave execution metadata behind a stale snapshot.
|