@cydm/happy-elves 0.1.0-beta.251 → 0.1.0-beta.258
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/apps/cli/package.json
CHANGED
package/apps/daemon/package.json
CHANGED
|
@@ -21,17 +21,47 @@ function primitiveSupport(value) {
|
|
|
21
21
|
function historyModel(value) {
|
|
22
22
|
return value === "append-only" || value === "authoritative-linear" ? value : undefined;
|
|
23
23
|
}
|
|
24
|
+
function stringField(value) {
|
|
25
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
26
|
+
}
|
|
27
|
+
function agentModelOptions(value) {
|
|
28
|
+
if (!Array.isArray(value))
|
|
29
|
+
return undefined;
|
|
30
|
+
const seen = new Set();
|
|
31
|
+
const models = value.flatMap((item) => {
|
|
32
|
+
if (!isRecord(item))
|
|
33
|
+
return [];
|
|
34
|
+
const id = stringField(item.id);
|
|
35
|
+
if (!id || seen.has(id))
|
|
36
|
+
return [];
|
|
37
|
+
seen.add(id);
|
|
38
|
+
const label = stringField(item.label);
|
|
39
|
+
const reason = stringField(item.reason);
|
|
40
|
+
return [{
|
|
41
|
+
id,
|
|
42
|
+
...(label ? { label } : {}),
|
|
43
|
+
...(item.unavailable === true ? { unavailable: true } : {}),
|
|
44
|
+
...(reason ? { reason } : {}),
|
|
45
|
+
}];
|
|
46
|
+
});
|
|
47
|
+
return models.length > 0 ? models : undefined;
|
|
48
|
+
}
|
|
24
49
|
export function normalizeMachineCapabilities(value) {
|
|
25
50
|
const record = isRecord(value) ? value : {};
|
|
26
51
|
const agents = Array.isArray(record.agents)
|
|
27
52
|
? record.agents.flatMap((agent) => {
|
|
28
53
|
if (!isRecord(agent) || typeof agent.id !== "string" || typeof agent.label !== "string")
|
|
29
54
|
return [];
|
|
55
|
+
const agentHistoryModel = historyModel(agent.historyModel);
|
|
56
|
+
const defaultModel = stringField(agent.defaultModel);
|
|
57
|
+
const models = agentModelOptions(agent.models);
|
|
30
58
|
return [{
|
|
31
59
|
id: agent.id,
|
|
32
60
|
label: agent.label,
|
|
33
61
|
...(typeof agent.command === "string" ? { command: agent.command } : {}),
|
|
34
|
-
...(
|
|
62
|
+
...(agentHistoryModel ? { historyModel: agentHistoryModel } : {}),
|
|
63
|
+
...(defaultModel ? { defaultModel } : {}),
|
|
64
|
+
...(models ? { models } : {}),
|
|
35
65
|
...(isRecord(agent.sessionPrimitives)
|
|
36
66
|
? {
|
|
37
67
|
sessionPrimitives: {
|
|
@@ -195,10 +195,54 @@ export function createRelayContext(options) {
|
|
|
195
195
|
};
|
|
196
196
|
}
|
|
197
197
|
function activeSessionClaim(accountId, sessionId) {
|
|
198
|
-
|
|
198
|
+
const claim = options.db
|
|
199
199
|
.prepare(`SELECT * FROM relay_session_claims
|
|
200
200
|
WHERE account_id = ? AND session_id = ? AND state = 'active'`)
|
|
201
201
|
.get(accountId, sessionId);
|
|
202
|
+
if (!claim)
|
|
203
|
+
return undefined;
|
|
204
|
+
if (isStaleSessionClaim(claim)) {
|
|
205
|
+
options.db
|
|
206
|
+
.prepare("DELETE FROM relay_session_claims WHERE account_id = ? AND session_id = ? AND request_id = ?")
|
|
207
|
+
.run(claim.account_id, claim.session_id, claim.request_id);
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
return claim;
|
|
211
|
+
}
|
|
212
|
+
function isStaleSessionClaim(claim) {
|
|
213
|
+
const admission = options.db
|
|
214
|
+
.prepare(`SELECT dispatch, finished_at, terminal_status
|
|
215
|
+
FROM relay_admissions
|
|
216
|
+
WHERE account_id = ? AND request_id = ?`)
|
|
217
|
+
.get(claim.account_id, claim.request_id);
|
|
218
|
+
if (admission && (admission.finished_at !== null || admission.terminal_status !== null))
|
|
219
|
+
return true;
|
|
220
|
+
const session = options.db
|
|
221
|
+
.prepare(`SELECT status, current_head, last_turn_id, updated_at
|
|
222
|
+
FROM sessions
|
|
223
|
+
WHERE account_id = ? AND id = ?`)
|
|
224
|
+
.get(claim.account_id, claim.session_id);
|
|
225
|
+
if (admission?.dispatch === "delivered" &&
|
|
226
|
+
session &&
|
|
227
|
+
!["new", "running", "offline"].includes(session.status) &&
|
|
228
|
+
session.updated_at > claim.created_at &&
|
|
229
|
+
session.current_head !== claim.turn_id &&
|
|
230
|
+
session.last_turn_id !== claim.turn_id) {
|
|
231
|
+
return true;
|
|
232
|
+
}
|
|
233
|
+
const newerTerminal = options.db
|
|
234
|
+
.prepare(`SELECT 1
|
|
235
|
+
FROM relay_admissions
|
|
236
|
+
WHERE account_id = ?
|
|
237
|
+
AND session_id = ?
|
|
238
|
+
AND kind = 'prompt'
|
|
239
|
+
AND request_id <> ?
|
|
240
|
+
AND finished_at IS NOT NULL
|
|
241
|
+
AND terminal_status IS NOT NULL
|
|
242
|
+
AND created_at > ?
|
|
243
|
+
LIMIT 1`)
|
|
244
|
+
.get(claim.account_id, claim.session_id, claim.request_id, claim.created_at);
|
|
245
|
+
return Boolean(newerTerminal);
|
|
202
246
|
}
|
|
203
247
|
function claimSessionTurn(params) {
|
|
204
248
|
const existing = activeSessionClaim(params.accountId, params.sessionId);
|
package/package.json
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
3
|
+
import os from "node:os";
|
|
2
4
|
import { readClaudeHistoricalEvents, readClaudeHistoricalSessionPage } from "./claude-history.js";
|
|
3
5
|
import { renameClaudeSession } from "./claude-rename.js";
|
|
4
6
|
import { forkAndTruncateClaudeSession, forkClaudeSession } from "./claude-session-store.js";
|
|
@@ -73,7 +75,7 @@ export function createCliRuntimeProvider(options) {
|
|
|
73
75
|
},
|
|
74
76
|
listAgents() {
|
|
75
77
|
return [
|
|
76
|
-
{ id: "codex", label: "Codex", ...
|
|
78
|
+
{ id: "codex", label: "Codex", ...codexAgentModels() },
|
|
77
79
|
{ id: "claude", label: "Claude Code", ...agentModelsFromEnv("HAPPY_ELVES_CLAUDE") },
|
|
78
80
|
];
|
|
79
81
|
},
|
|
@@ -331,6 +333,16 @@ function agentModelsFromEnv(prefix) {
|
|
|
331
333
|
...(models.length > 0 ? { models } : {}),
|
|
332
334
|
};
|
|
333
335
|
}
|
|
336
|
+
function codexAgentModels() {
|
|
337
|
+
const configured = agentModelsFromEnv("HAPPY_ELVES_CODEX");
|
|
338
|
+
if (configured.models && configured.models.length > 0)
|
|
339
|
+
return configured;
|
|
340
|
+
const cachedModels = modelOptionsFromCodexCache(process.env.CODEX_HOME);
|
|
341
|
+
return {
|
|
342
|
+
...(configured.defaultModel ? { defaultModel: configured.defaultModel } : {}),
|
|
343
|
+
...(cachedModels.length > 0 ? { models: cachedModels } : {}),
|
|
344
|
+
};
|
|
345
|
+
}
|
|
334
346
|
function modelOptionsFromEnv(value) {
|
|
335
347
|
const seen = new Set();
|
|
336
348
|
return (value ?? "")
|
|
@@ -347,4 +359,60 @@ function modelOptionsFromEnv(value) {
|
|
|
347
359
|
return [{ id, ...(label ? { label } : {}) }];
|
|
348
360
|
});
|
|
349
361
|
}
|
|
362
|
+
function modelOptionsFromCodexCache(codexHome) {
|
|
363
|
+
const cachePath = codexModelCachePaths(codexHome).find((candidate) => existsSync(candidate));
|
|
364
|
+
if (!cachePath)
|
|
365
|
+
return [];
|
|
366
|
+
try {
|
|
367
|
+
const parsed = JSON.parse(readFileSync(cachePath, "utf8"));
|
|
368
|
+
const models = Array.isArray(parsed)
|
|
369
|
+
? parsed
|
|
370
|
+
: isRecord(parsed) && Array.isArray(parsed.models)
|
|
371
|
+
? parsed.models
|
|
372
|
+
: [];
|
|
373
|
+
const seen = new Set();
|
|
374
|
+
return models.flatMap((item) => {
|
|
375
|
+
if (!isRecord(item))
|
|
376
|
+
return [];
|
|
377
|
+
if (typeof item.visibility === "string" && item.visibility !== "list")
|
|
378
|
+
return [];
|
|
379
|
+
const id = stringField(item, "slug") || stringField(item, "id") || stringField(item, "model") || stringField(item, "name");
|
|
380
|
+
if (!id || seen.has(id))
|
|
381
|
+
return [];
|
|
382
|
+
seen.add(id);
|
|
383
|
+
const label = stringField(item, "display_name") || stringField(item, "displayName") || stringField(item, "label");
|
|
384
|
+
return [{ id, ...(label ? { label } : {}) }];
|
|
385
|
+
});
|
|
386
|
+
}
|
|
387
|
+
catch {
|
|
388
|
+
return [];
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
function codexModelCachePaths(codexHome) {
|
|
392
|
+
const candidates = [
|
|
393
|
+
process.env.HAPPY_ELVES_CODEX_MODELS_CACHE,
|
|
394
|
+
codexHome?.trim() ? path.join(codexHome.trim(), "models_cache.json") : undefined,
|
|
395
|
+
process.env.APPDATA ? path.join(process.env.APPDATA, "Codex", "models_cache.json") : undefined,
|
|
396
|
+
process.env.APPDATA ? path.join(process.env.APPDATA, "codex", "models_cache.json") : undefined,
|
|
397
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, "Codex", "models_cache.json") : undefined,
|
|
398
|
+
process.env.LOCALAPPDATA ? path.join(process.env.LOCALAPPDATA, "codex", "models_cache.json") : undefined,
|
|
399
|
+
path.join(os.homedir(), ".codex", "models_cache.json"),
|
|
400
|
+
process.env.USERPROFILE ? path.join(process.env.USERPROFILE, ".codex", "models_cache.json") : undefined,
|
|
401
|
+
];
|
|
402
|
+
const seen = new Set();
|
|
403
|
+
return candidates.flatMap((candidate) => {
|
|
404
|
+
const normalized = candidate?.trim();
|
|
405
|
+
if (!normalized || seen.has(normalized))
|
|
406
|
+
return [];
|
|
407
|
+
seen.add(normalized);
|
|
408
|
+
return [normalized];
|
|
409
|
+
});
|
|
410
|
+
}
|
|
411
|
+
function isRecord(value) {
|
|
412
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
413
|
+
}
|
|
414
|
+
function stringField(record, key) {
|
|
415
|
+
const value = record[key];
|
|
416
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
417
|
+
}
|
|
350
418
|
//# sourceMappingURL=index.js.map
|