@ouro.bot/cli 0.1.0-alpha.977 → 0.1.0-alpha.978
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/changelog.json
CHANGED
|
@@ -1,6 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"_note": "This changelog is maintained as part of the PR/version-bump workflow. Agent-curated, not auto-generated. Agents read this file directly via read_file to understand what changed between versions.",
|
|
3
3
|
"versions": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.1.0-alpha.978",
|
|
6
|
+
"changes": [
|
|
7
|
+
"Psyche edits now take effect on the next turn for every agent. Each prompt build compares the content of the psyche and house files with the cached copy and rereads on any change, so an edit by the agent, its owner or a sync pull no longer waits for a restart. Content is compared rather than mtimes, which FUSE shares such as Unraid's do not always update."
|
|
8
|
+
]
|
|
9
|
+
},
|
|
4
10
|
{
|
|
5
11
|
"version": "0.1.0-alpha.977",
|
|
6
12
|
"changes": [
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
<?xml version="1.0"?>
|
|
2
2
|
<Container version="2">
|
|
3
3
|
<Name>ouro-butler</Name>
|
|
4
|
-
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.
|
|
4
|
+
<Repository>ghcr.io/ourostack/ouroboros-butler:0.1.0-alpha.978</Repository>
|
|
5
5
|
<Registry>https://github.com/ourostack/ouroboros/pkgs/container/ouroboros-butler</Registry>
|
|
6
6
|
<Network>host</Network>
|
|
7
7
|
<Shell>sh</Shell>
|
package/dist/mind/prompt.js
CHANGED
|
@@ -34,6 +34,7 @@ var __importStar = (this && this.__importStar) || (function () {
|
|
|
34
34
|
})();
|
|
35
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
36
|
exports.flattenSystemPrompt = flattenSystemPrompt;
|
|
37
|
+
exports.loadPsycheAt = loadPsycheAt;
|
|
37
38
|
exports.resetPsycheCache = resetPsycheCache;
|
|
38
39
|
exports.buildSessionSummary = buildSessionSummary;
|
|
39
40
|
exports.bodyMapSection = bodyMapSection;
|
|
@@ -62,6 +63,7 @@ exports.rhythmStatusSection = rhythmStatusSection;
|
|
|
62
63
|
exports.buildSystem = buildSystem;
|
|
63
64
|
const fs = __importStar(require("fs"));
|
|
64
65
|
const path = __importStar(require("path"));
|
|
66
|
+
const crypto_1 = require("crypto");
|
|
65
67
|
const core_1 = require("../heart/core");
|
|
66
68
|
const ouro_version_manager_1 = require("../heart/versioning/ouro-version-manager");
|
|
67
69
|
const tools_1 = require("../repertoire/tools");
|
|
@@ -94,9 +96,40 @@ function flattenSystemPrompt(sp) {
|
|
|
94
96
|
const parts = [sp.stable, sp.volatile].filter(Boolean);
|
|
95
97
|
return parts.join("\n\n");
|
|
96
98
|
}
|
|
97
|
-
//
|
|
98
|
-
//
|
|
99
|
-
|
|
99
|
+
// Psyche text cache, one entry per agent root (the daemon can host several agents). An entry is good only while
|
|
100
|
+
// the files it was read from are unchanged: every load hashes their content, so an edit by the agent, its owner or
|
|
101
|
+
// a sync pull takes effect on the very next prompt build. Content, not mtime or inode, because those are unreliable
|
|
102
|
+
// on FUSE shares such as Unraid's /mnt/user; the files are small, so hashing them is cheap.
|
|
103
|
+
const _psycheCache = new Map();
|
|
104
|
+
const PSYCHE_SOURCE_FILES = {
|
|
105
|
+
soul: ["psyche", "SOUL.md"],
|
|
106
|
+
identity: ["psyche", "IDENTITY.md"],
|
|
107
|
+
lore: ["psyche", "LORE.md"],
|
|
108
|
+
tacitKnowledge: ["psyche", "TACIT.md"],
|
|
109
|
+
aspirations: ["psyche", "ASPIRATIONS.md"],
|
|
110
|
+
house: ["house", "HOUSE.md"],
|
|
111
|
+
houseNames: ["house", "house.json"],
|
|
112
|
+
};
|
|
113
|
+
/** Every file the psyche is built from, read once; null when a file is absent or unreadable. */
|
|
114
|
+
function readPsycheSources(agentRoot) {
|
|
115
|
+
const sources = {};
|
|
116
|
+
for (const [key, parts] of Object.entries(PSYCHE_SOURCE_FILES)) {
|
|
117
|
+
try {
|
|
118
|
+
sources[key] = String(fs.readFileSync(path.join(agentRoot, ...parts), "utf-8"));
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
sources[key] = null;
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return sources;
|
|
125
|
+
}
|
|
126
|
+
/** A content hash of the sources; an absent file hashes differently from an empty one. */
|
|
127
|
+
function psycheFingerprint(sources) {
|
|
128
|
+
const hash = (0, crypto_1.createHash)("sha256");
|
|
129
|
+
for (const text of Object.values(sources))
|
|
130
|
+
hash.update(text === null ? "-" : `+${text.length}:${text}`);
|
|
131
|
+
return hash.digest("hex");
|
|
132
|
+
}
|
|
100
133
|
// A household install names its owner, its Butler and its home in house/house.json,
|
|
101
134
|
// a file the package never overwrites. The packaged psyche writes {{owner}}, {{butler}}
|
|
102
135
|
// and {{household}} where those names go, so one psyche serves every household.
|
|
@@ -105,59 +138,48 @@ const HOUSE_NAME_DEFAULTS = {
|
|
|
105
138
|
butler: "the Butler",
|
|
106
139
|
household: "the household",
|
|
107
140
|
};
|
|
108
|
-
function
|
|
141
|
+
function parseHouseNames(text) {
|
|
142
|
+
const names = { ...HOUSE_NAME_DEFAULTS };
|
|
109
143
|
try {
|
|
110
|
-
const parsed = JSON.parse(
|
|
111
|
-
const names = { ...HOUSE_NAME_DEFAULTS };
|
|
144
|
+
const parsed = JSON.parse(text ?? "");
|
|
112
145
|
for (const [key, field] of [["owner", "ownerName"], ["butler", "butlerName"], ["household", "householdName"]]) {
|
|
113
146
|
const value = parsed[field];
|
|
114
147
|
if (typeof value === "string" && value.trim())
|
|
115
148
|
names[key] = value.trim();
|
|
116
149
|
}
|
|
117
|
-
return names;
|
|
118
150
|
}
|
|
119
151
|
catch {
|
|
120
|
-
|
|
152
|
+
// no house.json, or not JSON: the defaults stand
|
|
121
153
|
}
|
|
154
|
+
return names;
|
|
122
155
|
}
|
|
123
156
|
function fillHouseNames(text, names) {
|
|
124
|
-
return text.replace(/\{\{(owner|butler|household)\}\}/gu, (_match, key) => names[key]);
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
return
|
|
133
|
-
|
|
134
|
-
}
|
|
135
|
-
function loadHouseFile(agentRoot, names) {
|
|
136
|
-
try {
|
|
137
|
-
return fillHouseNames(fs.readFileSync(path.join(agentRoot, "house", "HOUSE.md"), "utf-8").trim(), names);
|
|
138
|
-
}
|
|
139
|
-
catch {
|
|
140
|
-
return "";
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
function loadPsyche() {
|
|
144
|
-
const agentRoot = (0, identity_1.getAgentRoot)();
|
|
145
|
-
if (_psycheCache?.agentRoot === agentRoot)
|
|
146
|
-
return _psycheCache.psyche;
|
|
147
|
-
const names = loadHouseNames(agentRoot);
|
|
157
|
+
return (text ?? "").trim().replace(/\{\{(owner|butler|household)\}\}/gu, (_match, key) => names[key]);
|
|
158
|
+
}
|
|
159
|
+
/** The psyche for one agent root. Each call reads its files once and rebuilds only when their content changed. */
|
|
160
|
+
function loadPsycheAt(agentRoot) {
|
|
161
|
+
const sources = readPsycheSources(agentRoot);
|
|
162
|
+
const fingerprint = psycheFingerprint(sources);
|
|
163
|
+
const cached = _psycheCache.get(agentRoot);
|
|
164
|
+
if (cached?.fingerprint === fingerprint)
|
|
165
|
+
return cached.psyche;
|
|
166
|
+
const names = parseHouseNames(sources.houseNames);
|
|
148
167
|
const psyche = {
|
|
149
|
-
soul:
|
|
150
|
-
identity:
|
|
151
|
-
lore:
|
|
152
|
-
tacitKnowledge:
|
|
153
|
-
aspirations:
|
|
154
|
-
house:
|
|
168
|
+
soul: fillHouseNames(sources.soul, names),
|
|
169
|
+
identity: fillHouseNames(sources.identity, names),
|
|
170
|
+
lore: fillHouseNames(sources.lore, names),
|
|
171
|
+
tacitKnowledge: fillHouseNames(sources.tacitKnowledge, names),
|
|
172
|
+
aspirations: fillHouseNames(sources.aspirations, names),
|
|
173
|
+
house: fillHouseNames(sources.house, names),
|
|
155
174
|
};
|
|
156
|
-
_psycheCache
|
|
175
|
+
_psycheCache.set(agentRoot, { fingerprint, psyche });
|
|
157
176
|
return psyche;
|
|
158
177
|
}
|
|
178
|
+
function loadPsyche() {
|
|
179
|
+
return loadPsycheAt((0, identity_1.getAgentRoot)());
|
|
180
|
+
}
|
|
159
181
|
function resetPsycheCache() {
|
|
160
|
-
_psycheCache
|
|
182
|
+
_psycheCache.clear();
|
|
161
183
|
}
|
|
162
184
|
const DEFAULT_ACTIVE_THRESHOLD_MS = 24 * 60 * 60 * 1000; // 24 hours
|
|
163
185
|
function buildSessionSummary(options) {
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ouro.bot/cli",
|
|
3
|
-
"version": "0.1.0-alpha.
|
|
3
|
+
"version": "0.1.0-alpha.978",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@ouro.bot/cli",
|
|
9
|
-
"version": "0.1.0-alpha.
|
|
9
|
+
"version": "0.1.0-alpha.978",
|
|
10
10
|
"dependencies": {
|
|
11
11
|
"@anthropic-ai/sdk": "^0.78.0",
|
|
12
12
|
"@azure/identity": "^4.13.0",
|