@cfio/cohort-sync 0.2.0 → 0.2.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/index.js +119 -28
- package/dist/package.json +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -11748,6 +11748,19 @@ function saveAgentStatesToHot(states) {
|
|
|
11748
11748
|
function getAgentStatesFromHot() {
|
|
11749
11749
|
return getHotState()?.agentStates ?? null;
|
|
11750
11750
|
}
|
|
11751
|
+
function saveIntervalsToHot(heartbeat, activityFlush) {
|
|
11752
|
+
const hot = getHotState();
|
|
11753
|
+
if (hot) {
|
|
11754
|
+
hot.intervals = { heartbeat, activityFlush };
|
|
11755
|
+
}
|
|
11756
|
+
}
|
|
11757
|
+
function clearIntervalsFromHot() {
|
|
11758
|
+
const hot = getHotState();
|
|
11759
|
+
if (!hot?.intervals) return;
|
|
11760
|
+
if (hot.intervals.heartbeat) clearInterval(hot.intervals.heartbeat);
|
|
11761
|
+
if (hot.intervals.activityFlush) clearInterval(hot.intervals.activityFlush);
|
|
11762
|
+
hot.intervals = { heartbeat: null, activityFlush: null };
|
|
11763
|
+
}
|
|
11751
11764
|
|
|
11752
11765
|
// src/sync.ts
|
|
11753
11766
|
function extractJson(raw) {
|
|
@@ -12014,6 +12027,7 @@ function shouldPushTelemetry(current, lastPushed) {
|
|
|
12014
12027
|
if (!lastPushed) return true;
|
|
12015
12028
|
if (current.status !== lastPushed.status) return true;
|
|
12016
12029
|
if (current.compactions !== lastPushed.compactions) return true;
|
|
12030
|
+
if (current.activeSessions !== lastPushed.activeSessions) return true;
|
|
12017
12031
|
if (current.contextLimit > 0 && lastPushed.contextLimit > 0) {
|
|
12018
12032
|
const currentPct = current.contextTokens / current.contextLimit;
|
|
12019
12033
|
const lastPct = lastPushed.contextTokens / lastPushed.contextLimit;
|
|
@@ -12101,6 +12115,13 @@ function buildActivitySentence(agentName, event, context) {
|
|
|
12101
12115
|
var AgentStateTracker = class {
|
|
12102
12116
|
agents = /* @__PURE__ */ new Map();
|
|
12103
12117
|
activityBuffer = [];
|
|
12118
|
+
sessionKeyToAgent = /* @__PURE__ */ new Map();
|
|
12119
|
+
setSessionAgent(sessionKey, agentName) {
|
|
12120
|
+
this.sessionKeyToAgent.set(sessionKey, agentName);
|
|
12121
|
+
}
|
|
12122
|
+
getSessionAgent(sessionKey) {
|
|
12123
|
+
return this.sessionKeyToAgent.get(sessionKey) ?? null;
|
|
12124
|
+
}
|
|
12104
12125
|
getOrCreate(agentName) {
|
|
12105
12126
|
let state = this.agents.get(agentName);
|
|
12106
12127
|
if (!state) {
|
|
@@ -12142,6 +12163,25 @@ var AgentStateTracker = class {
|
|
|
12142
12163
|
state.sessions.delete(sessionKey);
|
|
12143
12164
|
}
|
|
12144
12165
|
}
|
|
12166
|
+
hasSession(agentName, sessionKey) {
|
|
12167
|
+
const state = this.agents.get(agentName);
|
|
12168
|
+
if (!state) return false;
|
|
12169
|
+
return state.sessions.has(sessionKey);
|
|
12170
|
+
}
|
|
12171
|
+
pruneStaleSessions(agentName, maxAgeMs) {
|
|
12172
|
+
const state = this.agents.get(agentName);
|
|
12173
|
+
if (!state) return [];
|
|
12174
|
+
const now = Date.now();
|
|
12175
|
+
const pruned = [];
|
|
12176
|
+
for (const [key, session] of state.sessions) {
|
|
12177
|
+
const lastMs = new Date(session.lastActivity).getTime();
|
|
12178
|
+
if (now - lastMs > maxAgeMs) {
|
|
12179
|
+
state.sessions.delete(key);
|
|
12180
|
+
pruned.push(key);
|
|
12181
|
+
}
|
|
12182
|
+
}
|
|
12183
|
+
return pruned;
|
|
12184
|
+
}
|
|
12145
12185
|
// --- Telemetry updates ---
|
|
12146
12186
|
updateStatus(agentName, status) {
|
|
12147
12187
|
this.getOrCreate(agentName).status = status;
|
|
@@ -12243,17 +12283,27 @@ var AgentStateTracker = class {
|
|
|
12243
12283
|
clear() {
|
|
12244
12284
|
this.agents.clear();
|
|
12245
12285
|
this.activityBuffer = [];
|
|
12286
|
+
this.sessionKeyToAgent.clear();
|
|
12246
12287
|
}
|
|
12247
12288
|
exportState() {
|
|
12248
|
-
return
|
|
12289
|
+
return {
|
|
12290
|
+
agents: new Map(this.agents),
|
|
12291
|
+
sessionKeyToAgent: new Map(this.sessionKeyToAgent)
|
|
12292
|
+
};
|
|
12249
12293
|
}
|
|
12250
12294
|
importState(states) {
|
|
12251
|
-
|
|
12295
|
+
const agentMap = states instanceof Map ? states : states.agents;
|
|
12296
|
+
for (const [name, state] of agentMap) {
|
|
12252
12297
|
if (!(state.sessions instanceof Map)) {
|
|
12253
12298
|
state.sessions = new Map(Object.entries(state.sessions));
|
|
12254
12299
|
}
|
|
12255
12300
|
this.agents.set(name, state);
|
|
12256
12301
|
}
|
|
12302
|
+
if (!(states instanceof Map) && states.sessionKeyToAgent) {
|
|
12303
|
+
for (const [key, agent] of states.sessionKeyToAgent) {
|
|
12304
|
+
this.sessionKeyToAgent.set(key, agent);
|
|
12305
|
+
}
|
|
12306
|
+
}
|
|
12257
12307
|
}
|
|
12258
12308
|
};
|
|
12259
12309
|
|
|
@@ -12315,6 +12365,30 @@ function registerHooks(api, cfg) {
|
|
|
12315
12365
|
function resolveAgentName(agentId) {
|
|
12316
12366
|
return (nameMap?.[agentId] ?? agentId).toLowerCase();
|
|
12317
12367
|
}
|
|
12368
|
+
function resolveAgentFromContext(ctx) {
|
|
12369
|
+
if (ctx.agentId && typeof ctx.agentId === "string") {
|
|
12370
|
+
return resolveAgentName(ctx.agentId);
|
|
12371
|
+
}
|
|
12372
|
+
const sessionKey = ctx.sessionKey ?? ctx.sessionId;
|
|
12373
|
+
if (sessionKey && typeof sessionKey === "string") {
|
|
12374
|
+
const mapped = tracker.getSessionAgent(sessionKey);
|
|
12375
|
+
if (mapped) return mapped;
|
|
12376
|
+
}
|
|
12377
|
+
return resolveAgentName("main");
|
|
12378
|
+
}
|
|
12379
|
+
clearIntervalsFromHot();
|
|
12380
|
+
heartbeatInterval = setInterval(() => {
|
|
12381
|
+
pushHeartbeat().catch((err) => {
|
|
12382
|
+
logger.warn(`cohort-sync: heartbeat tick failed: ${String(err)}`);
|
|
12383
|
+
});
|
|
12384
|
+
}, 12e4);
|
|
12385
|
+
activityFlushInterval = setInterval(() => {
|
|
12386
|
+
flushActivityBuffer().catch((err) => {
|
|
12387
|
+
logger.warn(`cohort-sync: activity flush tick failed: ${String(err)}`);
|
|
12388
|
+
});
|
|
12389
|
+
}, 1500);
|
|
12390
|
+
saveIntervalsToHot(heartbeatInterval, activityFlushInterval);
|
|
12391
|
+
logger.info("cohort-sync: intervals created (heartbeat=2m, activityFlush=1.5s)");
|
|
12318
12392
|
api.registerTool((toolCtx) => {
|
|
12319
12393
|
const agentId = toolCtx.agentId ?? "main";
|
|
12320
12394
|
const agentName = resolveAgentName(agentId);
|
|
@@ -12361,6 +12435,13 @@ function registerHooks(api, cfg) {
|
|
|
12361
12435
|
}
|
|
12362
12436
|
async function pushHeartbeat() {
|
|
12363
12437
|
const allAgentIds = ["main", ...(config?.agents?.list ?? []).map((a) => a.id)];
|
|
12438
|
+
for (const agentId of allAgentIds) {
|
|
12439
|
+
const agentName = resolveAgentName(agentId);
|
|
12440
|
+
const pruned = tracker.pruneStaleSessions(agentName, 6e5);
|
|
12441
|
+
if (pruned.length > 0) {
|
|
12442
|
+
logger.info(`cohort-sync: pruned ${pruned.length} stale sessions for ${agentName}`);
|
|
12443
|
+
}
|
|
12444
|
+
}
|
|
12364
12445
|
for (const agentId of allAgentIds) {
|
|
12365
12446
|
const agentName = resolveAgentName(agentId);
|
|
12366
12447
|
try {
|
|
@@ -12374,6 +12455,18 @@ function registerHooks(api, cfg) {
|
|
|
12374
12455
|
logger.warn(`cohort-sync: heartbeat push failed for ${agentName}: ${String(err)}`);
|
|
12375
12456
|
}
|
|
12376
12457
|
}
|
|
12458
|
+
for (const agentId of allAgentIds) {
|
|
12459
|
+
const agentName = resolveAgentName(agentId);
|
|
12460
|
+
try {
|
|
12461
|
+
if (tracker.shouldPushSessions(agentName)) {
|
|
12462
|
+
const sessSnapshot = tracker.getSessionsSnapshot(agentName);
|
|
12463
|
+
await pushSessions(cfg.apiKey, agentName, sessSnapshot);
|
|
12464
|
+
tracker.markSessionsPushed(agentName);
|
|
12465
|
+
}
|
|
12466
|
+
} catch (err) {
|
|
12467
|
+
logger.warn(`cohort-sync: heartbeat session push failed for ${agentName}: ${String(err)}`);
|
|
12468
|
+
}
|
|
12469
|
+
}
|
|
12377
12470
|
logger.info(`cohort-sync: heartbeat pushed for ${allAgentIds.length} agents`);
|
|
12378
12471
|
}
|
|
12379
12472
|
async function flushActivityBuffer() {
|
|
@@ -12425,18 +12518,6 @@ function registerHooks(api, cfg) {
|
|
|
12425
12518
|
}
|
|
12426
12519
|
}
|
|
12427
12520
|
logger.info(`cohort-sync: seeded telemetry for ${allAgentIds.length} agents`);
|
|
12428
|
-
heartbeatInterval = setInterval(() => {
|
|
12429
|
-
pushHeartbeat().catch((err) => {
|
|
12430
|
-
logger.warn(`cohort-sync: heartbeat tick failed: ${String(err)}`);
|
|
12431
|
-
});
|
|
12432
|
-
}, 12e4);
|
|
12433
|
-
logger.info("cohort-sync: heartbeat started (2m interval)");
|
|
12434
|
-
activityFlushInterval = setInterval(() => {
|
|
12435
|
-
flushActivityBuffer().catch((err) => {
|
|
12436
|
-
logger.warn(`cohort-sync: activity flush tick failed: ${String(err)}`);
|
|
12437
|
-
});
|
|
12438
|
-
}, 1500);
|
|
12439
|
-
logger.info("cohort-sync: activity flush started (1.5s interval)");
|
|
12440
12521
|
});
|
|
12441
12522
|
api.on("agent_end", async (_event, ctx) => {
|
|
12442
12523
|
const agentId = ctx.agentId ?? "main";
|
|
@@ -12469,6 +12550,13 @@ function registerHooks(api, cfg) {
|
|
|
12469
12550
|
contextTokens: ext.contextTokens ?? usage.total ?? 0,
|
|
12470
12551
|
contextLimit: ext.contextLimit ?? 0
|
|
12471
12552
|
});
|
|
12553
|
+
if (sessionKey && !tracker.hasSession(agentName, sessionKey)) {
|
|
12554
|
+
tracker.addSession(agentName, sessionKey);
|
|
12555
|
+
logger.info(`cohort-sync: inferred session for ${agentName} from llm_output (${sessionKey})`);
|
|
12556
|
+
}
|
|
12557
|
+
if (sessionKey) {
|
|
12558
|
+
tracker.setSessionAgent(sessionKey, agentName);
|
|
12559
|
+
}
|
|
12472
12560
|
if (tracker.shouldPushTelemetry(agentName)) {
|
|
12473
12561
|
const snapshot = tracker.getTelemetrySnapshot(agentName);
|
|
12474
12562
|
if (snapshot) {
|
|
@@ -12522,6 +12610,17 @@ function registerHooks(api, cfg) {
|
|
|
12522
12610
|
tracker.markTelemetryPushed(agentName);
|
|
12523
12611
|
}
|
|
12524
12612
|
}
|
|
12613
|
+
const sessionKey = ctx.sessionKey;
|
|
12614
|
+
if (sessionKey && !tracker.hasSession(agentName, sessionKey)) {
|
|
12615
|
+
tracker.addSession(agentName, sessionKey);
|
|
12616
|
+
tracker.setSessionAgent(sessionKey, agentName);
|
|
12617
|
+
logger.info(`cohort-sync: inferred session for ${agentName} (${sessionKey})`);
|
|
12618
|
+
if (tracker.shouldPushSessions(agentName)) {
|
|
12619
|
+
const sessSnapshot = tracker.getSessionsSnapshot(agentName);
|
|
12620
|
+
await pushSessions(cfg.apiKey, agentName, sessSnapshot);
|
|
12621
|
+
tracker.markSessionsPushed(agentName);
|
|
12622
|
+
}
|
|
12623
|
+
}
|
|
12525
12624
|
const entry = buildActivitySentence(agentName, "before_agent_start", {
|
|
12526
12625
|
channel: ctx.messageProvider ?? "unknown"
|
|
12527
12626
|
});
|
|
@@ -12568,8 +12667,7 @@ function registerHooks(api, cfg) {
|
|
|
12568
12667
|
}
|
|
12569
12668
|
});
|
|
12570
12669
|
api.on("before_tool_call", async (event, ctx) => {
|
|
12571
|
-
const
|
|
12572
|
-
const agentName = resolveAgentName(agentId);
|
|
12670
|
+
const agentName = resolveAgentFromContext(ctx);
|
|
12573
12671
|
try {
|
|
12574
12672
|
const entry = buildActivitySentence(agentName, "before_tool_call", {
|
|
12575
12673
|
toolName: event.toolName ?? event.name,
|
|
@@ -12581,8 +12679,7 @@ function registerHooks(api, cfg) {
|
|
|
12581
12679
|
}
|
|
12582
12680
|
});
|
|
12583
12681
|
api.on("message_received", async (_event, ctx) => {
|
|
12584
|
-
const
|
|
12585
|
-
const agentName = resolveAgentName(agentId);
|
|
12682
|
+
const agentName = resolveAgentFromContext(ctx);
|
|
12586
12683
|
try {
|
|
12587
12684
|
const entry = buildActivitySentence(agentName, "message_received", {
|
|
12588
12685
|
channel: ctx.messageProvider ?? "unknown"
|
|
@@ -12593,8 +12690,7 @@ function registerHooks(api, cfg) {
|
|
|
12593
12690
|
}
|
|
12594
12691
|
});
|
|
12595
12692
|
api.on("message_sent", async (_event, ctx) => {
|
|
12596
|
-
const
|
|
12597
|
-
const agentName = resolveAgentName(agentId);
|
|
12693
|
+
const agentName = resolveAgentFromContext(ctx);
|
|
12598
12694
|
try {
|
|
12599
12695
|
const entry = buildActivitySentence(agentName, "message_sent", {
|
|
12600
12696
|
channel: ctx.messageProvider ?? "unknown"
|
|
@@ -12605,14 +12701,9 @@ function registerHooks(api, cfg) {
|
|
|
12605
12701
|
}
|
|
12606
12702
|
});
|
|
12607
12703
|
api.on("gateway_stop", async () => {
|
|
12608
|
-
|
|
12609
|
-
|
|
12610
|
-
|
|
12611
|
-
}
|
|
12612
|
-
if (activityFlushInterval) {
|
|
12613
|
-
clearInterval(activityFlushInterval);
|
|
12614
|
-
activityFlushInterval = null;
|
|
12615
|
-
}
|
|
12704
|
+
clearIntervalsFromHot();
|
|
12705
|
+
heartbeatInterval = null;
|
|
12706
|
+
activityFlushInterval = null;
|
|
12616
12707
|
await flushActivityBuffer().catch((err) => {
|
|
12617
12708
|
logger.warn(`cohort-sync: final activity flush failed: ${String(err)}`);
|
|
12618
12709
|
});
|
package/dist/package.json
CHANGED