@rubytech/create-realagent 1.0.819 → 1.0.821
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/package.json +1 -1
- package/payload/platform/plugins/admin/skills/onboarding/SKILL.md +8 -9
- package/payload/platform/plugins/cloudflare/PLUGIN.md +1 -1
- package/payload/platform/plugins/cloudflare/scripts/setup-tunnel.sh +70 -20
- package/payload/platform/plugins/docs/references/cloudflare.md +1 -1
- package/payload/platform/plugins/docs/references/graph.md +20 -0
- package/payload/platform/plugins/email/PLUGIN.md +2 -0
- package/payload/platform/plugins/memory/mcp/dist/index.js +8 -2
- package/payload/platform/plugins/memory/mcp/dist/index.js.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts +20 -0
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.d.ts.map +1 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js +40 -1
- package/payload/platform/plugins/memory/mcp/dist/tools/profile-update.js.map +1 -1
- package/payload/server/chunk-5OG7TUQL.js +315 -0
- package/payload/server/chunk-CZGOB575.js +593 -0
- package/payload/server/chunk-NUXYHO6N.js +10079 -0
- package/payload/server/chunk-SALVIGXH.js +1116 -0
- package/payload/server/chunk-ZT6LKDTP.js +2238 -0
- package/payload/server/client-pool-IQU6H43X.js +32 -0
- package/payload/server/cloudflare-task-tracker-Q4X5BYR7.js +17 -0
- package/payload/server/maxy-edge.js +4 -3
- package/payload/server/neo4j-migrations-CYIKMSEO.js +366 -0
- package/payload/server/public/assets/admin-okt0ygrZ.js +352 -0
- package/payload/server/public/assets/{graph-DeH6ulGh.js → graph-LLMJa4Ch.js} +1 -1
- package/payload/server/public/assets/{page-WIAWD2Oi.js → page-DoaF3DB0.js} +1 -1
- package/payload/server/public/graph.html +2 -2
- package/payload/server/public/index.html +2 -2
- package/payload/server/server.js +269 -488
- package/payload/server/public/assets/admin-CdVYoqKD.js +0 -352
|
@@ -16,7 +16,7 @@ const VALID_CATEGORIES = new Set([
|
|
|
16
16
|
]);
|
|
17
17
|
const VALID_MODES = new Set(["reinforce", "update", "contradict", "merge"]);
|
|
18
18
|
export async function profileUpdate(params) {
|
|
19
|
-
const { accountId, userId, category, key, value, source = "behavioural", mode = "reinforce", conversationId, profileFields, mergeSourceIds, } = params;
|
|
19
|
+
const { accountId, userId, category, key, value, source = "behavioural", mode = "reinforce", conversationId, profileFields, personFields, mergeSourceIds, } = params;
|
|
20
20
|
if (!VALID_CATEGORIES.has(category)) {
|
|
21
21
|
throw new Error(`Invalid category "${category}". Must be one of: ${[...VALID_CATEGORIES].join(", ")}`);
|
|
22
22
|
}
|
|
@@ -63,6 +63,45 @@ export async function profileUpdate(params) {
|
|
|
63
63
|
`, { accountId, userId, fields: safeFields, now });
|
|
64
64
|
}
|
|
65
65
|
}
|
|
66
|
+
// Task 886 §D — Person identity fields. Writes to the operator's
|
|
67
|
+
// personal-profile Person node bound to the AdminUser via OWNS (the
|
|
68
|
+
// edge the PIN-setup writeAdminUserAndPerson path created). The
|
|
69
|
+
// RETURN count guard is mandatory: a MATCH-SET against a missing
|
|
70
|
+
// Person silently no-ops and the agent would think the write
|
|
71
|
+
// succeeded (project_sprint_learnings: neo4j-match-set-no-op).
|
|
72
|
+
//
|
|
73
|
+
// Allow-list: only `email` and `telephone` reach the SET. Synonym
|
|
74
|
+
// rewriting (`phone` → `telephone`) is the writer's responsibility,
|
|
75
|
+
// not this tool's — callers that pass `phone` get rejected so grep
|
|
76
|
+
// stays aligned with schema-base.md doctrine.
|
|
77
|
+
if (personFields && (personFields.email !== undefined || personFields.telephone !== undefined)) {
|
|
78
|
+
const personSafeFields = {};
|
|
79
|
+
if (typeof personFields.email === "string" && personFields.email.length > 0) {
|
|
80
|
+
personSafeFields.email = personFields.email;
|
|
81
|
+
}
|
|
82
|
+
if (typeof personFields.telephone === "string" && personFields.telephone.length > 0) {
|
|
83
|
+
personSafeFields.telephone = personFields.telephone;
|
|
84
|
+
}
|
|
85
|
+
if (Object.keys(personSafeFields).length > 0) {
|
|
86
|
+
const personUpdate = await session.run(`
|
|
87
|
+
MATCH (au:AdminUser {userId: $userId})-[:OWNS]->(p:Person {accountId: $accountId})
|
|
88
|
+
SET p += $fields, p.updatedAt = $now
|
|
89
|
+
RETURN count(p) AS affected, collect(elementId(p))[0] AS personElementId
|
|
90
|
+
`, { accountId, userId, fields: personSafeFields, now });
|
|
91
|
+
const affected = personUpdate.records[0]?.get("affected");
|
|
92
|
+
const affectedN = typeof affected === "number" ? affected : (affected?.toNumber?.() ?? 0);
|
|
93
|
+
if (affectedN !== 1) {
|
|
94
|
+
throw new Error(`profile-update personFields: AdminUser-OWNS-Person not found for userId=${userId} accountId=${accountId.slice(0, 8)}… (affected=${affectedN}). Personal-profile Person is created at PIN setup; if this fires the OWNS edge is missing and the operator-identity capture path is broken.`);
|
|
95
|
+
}
|
|
96
|
+
// Identity-completion log — one line per identity field set in this
|
|
97
|
+
// call. Pre-Task-886 the agent had no observability of identity
|
|
98
|
+
// fields landing on Person; this gives operators a grep target
|
|
99
|
+
// matching the existing `[profile] sparse-state injected` pattern.
|
|
100
|
+
for (const fieldName of Object.keys(personSafeFields)) {
|
|
101
|
+
process.stderr.write(`[profile] identity-completed accountId=${accountId.slice(0, 8)}… field=${fieldName}\n`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
66
105
|
// Handle merge mode — combines multiple preferences into one
|
|
67
106
|
if (mode === "merge") {
|
|
68
107
|
return await executeMerge(session, accountId, userId, category, key, value, source, embedding, mergeSourceIds, now);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"profile-update.js","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,sBAAsB,CAAC;AAC7C,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,UAAU,EAAE,MAAM,8CAA8C,CAAC;AAE1E,kEAAkE;AAClE,MAAM,kBAAkB,GAAG,GAAG,CAAC;AAC/B,MAAM,uBAAuB,GAAG,IAAI,CAAC;AACrC,MAAM,uBAAuB,GAAG,GAAG,CAAC;AAEpC,MAAM,gBAAgB,GAAG,IAAI,GAAG,CAAC;IAC/B,eAAe;IACf,YAAY;IACZ,UAAU;IACV,UAAU;IACV,SAAS;IACT,aAAa;CACd,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,QAAQ,EAAE,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"profile-update.js","sourceRoot":"","sources":["../../src/tools/profile-update.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,315 @@
|
|
|
1
|
+
// app/lib/claude-agent/account.ts
|
|
2
|
+
import { resolve } from "path";
|
|
3
|
+
import { readFileSync as readFileSync2, readdirSync, existsSync as existsSync2, statSync } from "fs";
|
|
4
|
+
|
|
5
|
+
// ../lib/brand-templating/src/index.ts
|
|
6
|
+
import { join } from "path";
|
|
7
|
+
import { existsSync, readFileSync } from "fs";
|
|
8
|
+
var PLACEHOLDER = "{{productName}}";
|
|
9
|
+
var cachedProductName = null;
|
|
10
|
+
function brandJsonPath() {
|
|
11
|
+
const platformRoot = process.env.MAXY_PLATFORM_ROOT;
|
|
12
|
+
if (!platformRoot) {
|
|
13
|
+
throw new Error(
|
|
14
|
+
"[skill-loader] MAXY_PLATFORM_ROOT not set \u2014 cannot resolve brand.json"
|
|
15
|
+
);
|
|
16
|
+
}
|
|
17
|
+
return join(platformRoot, "config", "brand.json");
|
|
18
|
+
}
|
|
19
|
+
function getBrandProductName() {
|
|
20
|
+
if (cachedProductName !== null) return cachedProductName;
|
|
21
|
+
const path = brandJsonPath();
|
|
22
|
+
if (!existsSync(path)) {
|
|
23
|
+
throw new Error(`[skill-loader] brand.json missing at ${path}`);
|
|
24
|
+
}
|
|
25
|
+
let parsed;
|
|
26
|
+
try {
|
|
27
|
+
parsed = JSON.parse(readFileSync(path, "utf-8"));
|
|
28
|
+
} catch (err) {
|
|
29
|
+
throw new Error(
|
|
30
|
+
`[skill-loader] brand.json unreadable at ${path}: ${err instanceof Error ? err.message : String(err)}`
|
|
31
|
+
);
|
|
32
|
+
}
|
|
33
|
+
const value = parsed.productName;
|
|
34
|
+
if (typeof value !== "string" || value.trim() === "") {
|
|
35
|
+
throw new Error(
|
|
36
|
+
`[skill-loader] brand.json at ${path} has missing or empty productName`
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
cachedProductName = value;
|
|
40
|
+
return value;
|
|
41
|
+
}
|
|
42
|
+
function substituteBrandPlaceholders(content, sourcePath) {
|
|
43
|
+
if (!content.includes(PLACEHOLDER)) return content;
|
|
44
|
+
let productName;
|
|
45
|
+
try {
|
|
46
|
+
productName = getBrandProductName();
|
|
47
|
+
} catch (err) {
|
|
48
|
+
console.error(
|
|
49
|
+
`[skill-loader] ERROR: brand.json missing \u2014 cannot resolve productName for skill ${sourcePath}`
|
|
50
|
+
);
|
|
51
|
+
throw err;
|
|
52
|
+
}
|
|
53
|
+
const occurrences = content.split(PLACEHOLDER).length - 1;
|
|
54
|
+
const substituted = content.split(PLACEHOLDER).join(productName);
|
|
55
|
+
console.log(
|
|
56
|
+
`[skill-loader] brand-substituted productName=${productName} skill=${sourcePath} occurrences=${occurrences}`
|
|
57
|
+
);
|
|
58
|
+
return substituted;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// app/lib/claude-agent/account.ts
|
|
62
|
+
var PLATFORM_ROOT = process.env.MAXY_PLATFORM_ROOT ?? resolve(process.cwd(), "..");
|
|
63
|
+
var ACCOUNTS_DIR = resolve(PLATFORM_ROOT, "..", "data/accounts");
|
|
64
|
+
if (!existsSync2(PLATFORM_ROOT)) {
|
|
65
|
+
throw new Error(
|
|
66
|
+
`PLATFORM_ROOT does not exist: ${PLATFORM_ROOT}
|
|
67
|
+
Set the MAXY_PLATFORM_ROOT environment variable to the absolute path of the platform directory.`
|
|
68
|
+
);
|
|
69
|
+
}
|
|
70
|
+
function resolveAccount() {
|
|
71
|
+
if (!existsSync2(ACCOUNTS_DIR)) return null;
|
|
72
|
+
const usersFilePath = resolve(PLATFORM_ROOT, "config", "users.json");
|
|
73
|
+
let usersJsonUserId = null;
|
|
74
|
+
if (existsSync2(usersFilePath)) {
|
|
75
|
+
try {
|
|
76
|
+
const raw = readFileSync2(usersFilePath, "utf-8").trim();
|
|
77
|
+
if (raw) {
|
|
78
|
+
const users = JSON.parse(raw);
|
|
79
|
+
if (users.length > 0) {
|
|
80
|
+
usersJsonUserId = users[0].userId;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
} catch {
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
const entries = readdirSync(ACCOUNTS_DIR, { withFileTypes: true });
|
|
87
|
+
let fallback = null;
|
|
88
|
+
for (const entry of entries) {
|
|
89
|
+
if (!entry.isDirectory()) continue;
|
|
90
|
+
const configPath = resolve(ACCOUNTS_DIR, entry.name, "account.json");
|
|
91
|
+
if (!existsSync2(configPath)) continue;
|
|
92
|
+
const raw = readFileSync2(configPath, "utf-8");
|
|
93
|
+
let config;
|
|
94
|
+
try {
|
|
95
|
+
config = JSON.parse(raw);
|
|
96
|
+
} catch {
|
|
97
|
+
console.error(`[maxy] account.json is corrupt at ${configPath} \u2014 skipping`);
|
|
98
|
+
continue;
|
|
99
|
+
}
|
|
100
|
+
if (!config.adminModel || !config.publicModel) {
|
|
101
|
+
throw new Error(
|
|
102
|
+
`[maxy] account.json at ${configPath} is missing required model fields (adminModel / publicModel). Update account.json with valid model identifiers.`
|
|
103
|
+
);
|
|
104
|
+
}
|
|
105
|
+
const result = {
|
|
106
|
+
accountId: config.accountId,
|
|
107
|
+
accountDir: resolve(ACCOUNTS_DIR, entry.name),
|
|
108
|
+
config
|
|
109
|
+
};
|
|
110
|
+
if (usersJsonUserId && config.admins?.some((a) => a.userId === usersJsonUserId)) {
|
|
111
|
+
return result;
|
|
112
|
+
}
|
|
113
|
+
if (!fallback) {
|
|
114
|
+
fallback = result;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (usersJsonUserId && fallback) {
|
|
118
|
+
console.warn(
|
|
119
|
+
`[maxy] resolveAccount: no account matches users.json userId ${usersJsonUserId} \u2014 falling back to ${fallback.accountId}`
|
|
120
|
+
);
|
|
121
|
+
}
|
|
122
|
+
return fallback;
|
|
123
|
+
}
|
|
124
|
+
function readAgentFile(accountDir, agentName, filename) {
|
|
125
|
+
const filePath = resolve(accountDir, "agents", agentName, filename);
|
|
126
|
+
if (!existsSync2(filePath)) return null;
|
|
127
|
+
const raw = readFileSync2(filePath, "utf-8");
|
|
128
|
+
if (filename.endsWith(".md")) {
|
|
129
|
+
return substituteBrandPlaceholders(raw, filePath);
|
|
130
|
+
}
|
|
131
|
+
return raw;
|
|
132
|
+
}
|
|
133
|
+
function readIdentity(accountDir, agentName) {
|
|
134
|
+
return readAgentFile(accountDir, agentName, "IDENTITY.md");
|
|
135
|
+
}
|
|
136
|
+
var RESERVED_SLUGS = /* @__PURE__ */ new Set(["admin", "api", "assets", "brand", "bot", "privacy"]);
|
|
137
|
+
var SLUG_PATTERN = /^[a-z][a-z0-9-]{2,49}$/;
|
|
138
|
+
function validateAgentSlug(slug) {
|
|
139
|
+
if (!SLUG_PATTERN.test(slug)) return false;
|
|
140
|
+
if (RESERVED_SLUGS.has(slug)) return false;
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
function resolveDefaultAgentSlug(accountDir) {
|
|
144
|
+
const configPath = resolve(accountDir, "account.json");
|
|
145
|
+
if (!existsSync2(configPath)) {
|
|
146
|
+
console.error("[agent-resolve] account.json not found \u2014 cannot resolve defaultAgent");
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
let config;
|
|
150
|
+
try {
|
|
151
|
+
config = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
152
|
+
} catch (err) {
|
|
153
|
+
console.error("[agent-resolve] failed to read account.json:", err);
|
|
154
|
+
return null;
|
|
155
|
+
}
|
|
156
|
+
if (!config.defaultAgent) {
|
|
157
|
+
console.error("[agent-resolve] defaultAgent not configured in account.json \u2014 set it via the connect-whatsapp skill");
|
|
158
|
+
return null;
|
|
159
|
+
}
|
|
160
|
+
const agentConfigPath = resolve(accountDir, "agents", config.defaultAgent, "config.json");
|
|
161
|
+
if (!existsSync2(agentConfigPath)) {
|
|
162
|
+
console.error(`[agent-resolve] defaultAgent="${config.defaultAgent}" has no config.json at ${agentConfigPath}`);
|
|
163
|
+
return null;
|
|
164
|
+
}
|
|
165
|
+
return config.defaultAgent;
|
|
166
|
+
}
|
|
167
|
+
function estimateTokens(text) {
|
|
168
|
+
return Math.ceil(text.length / 4);
|
|
169
|
+
}
|
|
170
|
+
function resolveAgentConfig(accountDir, agentName) {
|
|
171
|
+
let model = null;
|
|
172
|
+
let plugins = null;
|
|
173
|
+
let status = null;
|
|
174
|
+
let displayName = null;
|
|
175
|
+
let image = null;
|
|
176
|
+
let imageShape = null;
|
|
177
|
+
let showAgentName = false;
|
|
178
|
+
let liveMemory = false;
|
|
179
|
+
let knowledgeKeywords = null;
|
|
180
|
+
let accessMode = "open";
|
|
181
|
+
const MAX_KNOWLEDGE_KEYWORDS = 5;
|
|
182
|
+
const configRaw = readAgentFile(accountDir, agentName, "config.json");
|
|
183
|
+
if (configRaw) {
|
|
184
|
+
let parsed;
|
|
185
|
+
try {
|
|
186
|
+
parsed = JSON.parse(configRaw);
|
|
187
|
+
} catch {
|
|
188
|
+
console.warn(`[agent-config] ${agentName}/config.json: invalid JSON \u2014 using defaults`);
|
|
189
|
+
parsed = {};
|
|
190
|
+
}
|
|
191
|
+
model = typeof parsed.model === "string" ? parsed.model : null;
|
|
192
|
+
plugins = Array.isArray(parsed.plugins) ? parsed.plugins : null;
|
|
193
|
+
status = typeof parsed.status === "string" ? parsed.status : null;
|
|
194
|
+
displayName = typeof parsed.displayName === "string" ? parsed.displayName : null;
|
|
195
|
+
image = typeof parsed.image === "string" ? parsed.image : null;
|
|
196
|
+
if (typeof parsed.imageShape === "string" && ["circle", "rounded"].includes(parsed.imageShape)) {
|
|
197
|
+
imageShape = parsed.imageShape;
|
|
198
|
+
}
|
|
199
|
+
if (parsed.showAgentName === true) {
|
|
200
|
+
showAgentName = true;
|
|
201
|
+
} else if (parsed.showAgentName === "none") {
|
|
202
|
+
showAgentName = "none";
|
|
203
|
+
}
|
|
204
|
+
if (image || imageShape || showAgentName) {
|
|
205
|
+
console.log(`[agent-config] ${agentName}: image=${image || "(none)"} imageShape=${imageShape || "(none)"} showAgentName=${showAgentName}`);
|
|
206
|
+
}
|
|
207
|
+
if (typeof parsed.accessMode === "string" && ["gated", "paid"].includes(parsed.accessMode)) {
|
|
208
|
+
accessMode = parsed.accessMode;
|
|
209
|
+
}
|
|
210
|
+
if (typeof parsed.liveMemory === "boolean") {
|
|
211
|
+
liveMemory = parsed.liveMemory;
|
|
212
|
+
} else if (typeof parsed.liveMemory === "string") {
|
|
213
|
+
const lower = parsed.liveMemory.toLowerCase();
|
|
214
|
+
if (lower === "true") {
|
|
215
|
+
liveMemory = true;
|
|
216
|
+
console.warn(`[agent-config] ${agentName}: liveMemory is string "true" \u2014 coercing to boolean. Fix the config to use a boolean value.`);
|
|
217
|
+
} else if (lower === "false") {
|
|
218
|
+
liveMemory = false;
|
|
219
|
+
console.warn(`[agent-config] ${agentName}: liveMemory is string "false" \u2014 coercing to boolean. Fix the config to use a boolean value.`);
|
|
220
|
+
} else {
|
|
221
|
+
throw new Error(`[agent-config] ${agentName}: liveMemory has invalid string value "${parsed.liveMemory}" \u2014 expected boolean or "true"/"false"`);
|
|
222
|
+
}
|
|
223
|
+
} else if (parsed.liveMemory !== void 0 && parsed.liveMemory !== null) {
|
|
224
|
+
throw new Error(`[agent-config] ${agentName}: liveMemory has invalid type ${typeof parsed.liveMemory} \u2014 expected boolean or "true"/"false"`);
|
|
225
|
+
}
|
|
226
|
+
if (Array.isArray(parsed.knowledgeKeywords) && parsed.knowledgeKeywords.length > 0) {
|
|
227
|
+
const filtered = parsed.knowledgeKeywords.filter((k) => typeof k === "string" && k.trim()).map((k) => k.replace(/,/g, "").trim().toLowerCase()).filter(Boolean);
|
|
228
|
+
if (filtered.length > MAX_KNOWLEDGE_KEYWORDS) {
|
|
229
|
+
console.warn(`[agent-config] ${agentName}: knowledgeKeywords has ${filtered.length} entries \u2014 capping at ${MAX_KNOWLEDGE_KEYWORDS}`);
|
|
230
|
+
}
|
|
231
|
+
knowledgeKeywords = filtered.length > 0 ? filtered.slice(0, MAX_KNOWLEDGE_KEYWORDS) : null;
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
let knowledge = null;
|
|
235
|
+
let knowledgeBaked = false;
|
|
236
|
+
const agentDir = resolve(accountDir, "agents", agentName);
|
|
237
|
+
const knowledgePath = resolve(agentDir, "KNOWLEDGE.md");
|
|
238
|
+
const summaryPath = resolve(agentDir, "KNOWLEDGE-SUMMARY.md");
|
|
239
|
+
const hasKnowledge = existsSync2(knowledgePath);
|
|
240
|
+
const hasSummary = existsSync2(summaryPath);
|
|
241
|
+
if (hasKnowledge && hasSummary) {
|
|
242
|
+
const knowledgeMtime = statSync(knowledgePath).mtimeMs;
|
|
243
|
+
const summaryMtime = statSync(summaryPath).mtimeMs;
|
|
244
|
+
if (summaryMtime >= knowledgeMtime) {
|
|
245
|
+
knowledge = readFileSync2(summaryPath, "utf-8");
|
|
246
|
+
} else {
|
|
247
|
+
console.warn(`[agent-config] ${agentName}: KNOWLEDGE-SUMMARY.md is stale (KNOWLEDGE.md is newer) \u2014 using full knowledge`);
|
|
248
|
+
knowledge = readFileSync2(knowledgePath, "utf-8");
|
|
249
|
+
}
|
|
250
|
+
knowledgeBaked = true;
|
|
251
|
+
} else if (hasKnowledge) {
|
|
252
|
+
knowledge = readFileSync2(knowledgePath, "utf-8");
|
|
253
|
+
knowledgeBaked = true;
|
|
254
|
+
}
|
|
255
|
+
let budget = null;
|
|
256
|
+
const identityRaw = readAgentFile(accountDir, agentName, "IDENTITY.md");
|
|
257
|
+
const soulRaw = readAgentFile(accountDir, agentName, "SOUL.md");
|
|
258
|
+
if (identityRaw || soulRaw || knowledge) {
|
|
259
|
+
const identityTokens = identityRaw ? estimateTokens(identityRaw) : 0;
|
|
260
|
+
const soulTokens = soulRaw ? estimateTokens(soulRaw) : 0;
|
|
261
|
+
const knowledgeTokens = knowledge ? estimateTokens(knowledge) : 0;
|
|
262
|
+
budget = {
|
|
263
|
+
identity: identityTokens,
|
|
264
|
+
soul: soulTokens,
|
|
265
|
+
knowledge: knowledgeTokens,
|
|
266
|
+
plugins: 0,
|
|
267
|
+
total: identityTokens + soulTokens + knowledgeTokens
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
return { model, plugins, status, displayName, image, imageShape, showAgentName, knowledge, knowledgeBaked, liveMemory, knowledgeKeywords, budget, accessMode };
|
|
271
|
+
}
|
|
272
|
+
function getDefaultAccountId() {
|
|
273
|
+
return resolveAccount()?.accountId ?? null;
|
|
274
|
+
}
|
|
275
|
+
function resolveUserAccounts(userId) {
|
|
276
|
+
if (!existsSync2(ACCOUNTS_DIR)) return [];
|
|
277
|
+
const results = [];
|
|
278
|
+
const entries = readdirSync(ACCOUNTS_DIR, { withFileTypes: true });
|
|
279
|
+
for (const entry of entries) {
|
|
280
|
+
if (!entry.isDirectory()) continue;
|
|
281
|
+
const configPath = resolve(ACCOUNTS_DIR, entry.name, "account.json");
|
|
282
|
+
if (!existsSync2(configPath)) continue;
|
|
283
|
+
let config;
|
|
284
|
+
try {
|
|
285
|
+
config = JSON.parse(readFileSync2(configPath, "utf-8"));
|
|
286
|
+
} catch {
|
|
287
|
+
console.error(`[session] account.json corrupt at ${configPath} \u2014 skipping`);
|
|
288
|
+
continue;
|
|
289
|
+
}
|
|
290
|
+
const adminEntry = config.admins?.find((a) => a.userId === userId);
|
|
291
|
+
if (adminEntry) {
|
|
292
|
+
results.push({
|
|
293
|
+
accountId: config.accountId,
|
|
294
|
+
accountDir: resolve(ACCOUNTS_DIR, entry.name),
|
|
295
|
+
config,
|
|
296
|
+
role: adminEntry.role
|
|
297
|
+
});
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
return results;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
export {
|
|
304
|
+
substituteBrandPlaceholders,
|
|
305
|
+
PLATFORM_ROOT,
|
|
306
|
+
ACCOUNTS_DIR,
|
|
307
|
+
resolveAccount,
|
|
308
|
+
readAgentFile,
|
|
309
|
+
readIdentity,
|
|
310
|
+
validateAgentSlug,
|
|
311
|
+
resolveDefaultAgentSlug,
|
|
312
|
+
resolveAgentConfig,
|
|
313
|
+
getDefaultAccountId,
|
|
314
|
+
resolveUserAccounts
|
|
315
|
+
};
|