mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-09 21:14:31 +00:00
Cron: route reminders by session namespace
This commit is contained in:
committed by
Peter Steinberger
parent
f452a7a60b
commit
f988abf202
@@ -259,6 +259,7 @@ function resolveHeartbeatSession(
|
||||
cfg: OpenClawConfig,
|
||||
agentId?: string,
|
||||
heartbeat?: HeartbeatConfig,
|
||||
forcedSessionKey?: string,
|
||||
) {
|
||||
const sessionCfg = cfg.session;
|
||||
const scope = sessionCfg?.scope ?? "per-sender";
|
||||
@@ -276,6 +277,31 @@ function resolveHeartbeatSession(
|
||||
return { sessionKey: mainSessionKey, storePath, store, entry: mainEntry };
|
||||
}
|
||||
|
||||
const forced = forcedSessionKey?.trim();
|
||||
if (forced) {
|
||||
const forcedCandidate = toAgentStoreSessionKey({
|
||||
agentId: resolvedAgentId,
|
||||
requestKey: forced,
|
||||
mainKey: cfg.session?.mainKey,
|
||||
});
|
||||
const forcedCanonical = canonicalizeMainSessionAlias({
|
||||
cfg,
|
||||
agentId: resolvedAgentId,
|
||||
sessionKey: forcedCandidate,
|
||||
});
|
||||
if (forcedCanonical !== "global") {
|
||||
const sessionAgentId = resolveAgentIdFromSessionKey(forcedCanonical);
|
||||
if (sessionAgentId === normalizeAgentId(resolvedAgentId)) {
|
||||
return {
|
||||
sessionKey: forcedCanonical,
|
||||
storePath,
|
||||
store,
|
||||
entry: store[forcedCanonical],
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const trimmed = heartbeat?.session?.trim() ?? "";
|
||||
if (!trimmed) {
|
||||
return { sessionKey: mainSessionKey, storePath, store, entry: mainEntry };
|
||||
@@ -437,6 +463,7 @@ function normalizeHeartbeatReply(
|
||||
export async function runHeartbeatOnce(opts: {
|
||||
cfg?: OpenClawConfig;
|
||||
agentId?: string;
|
||||
sessionKey?: string;
|
||||
heartbeat?: HeartbeatConfig;
|
||||
reason?: string;
|
||||
deps?: HeartbeatDeps;
|
||||
@@ -493,7 +520,12 @@ export async function runHeartbeatOnce(opts: {
|
||||
// The LLM prompt says "if it exists" so this is expected behavior.
|
||||
}
|
||||
|
||||
const { entry, sessionKey, storePath } = resolveHeartbeatSession(cfg, agentId, heartbeat);
|
||||
const { entry, sessionKey, storePath } = resolveHeartbeatSession(
|
||||
cfg,
|
||||
agentId,
|
||||
heartbeat,
|
||||
opts.sessionKey,
|
||||
);
|
||||
const previousUpdatedAt = entry?.updatedAt;
|
||||
const delivery = resolveHeartbeatDeliveryTarget({ cfg, entry, heartbeat });
|
||||
const heartbeatAccountId = heartbeat?.accountId?.trim();
|
||||
@@ -969,11 +1001,45 @@ export function startHeartbeatRunner(opts: {
|
||||
}
|
||||
|
||||
const reason = params?.reason;
|
||||
const requestedAgentId = params?.agentId ? normalizeAgentId(params.agentId) : undefined;
|
||||
const requestedSessionKey = params?.sessionKey?.trim() || undefined;
|
||||
const isInterval = reason === "interval";
|
||||
const startedAt = Date.now();
|
||||
const now = startedAt;
|
||||
let ran = false;
|
||||
|
||||
if (requestedSessionKey || requestedAgentId) {
|
||||
const targetAgentId = requestedAgentId ?? resolveAgentIdFromSessionKey(requestedSessionKey);
|
||||
const targetAgent = state.agents.get(targetAgentId);
|
||||
if (!targetAgent) {
|
||||
scheduleNext();
|
||||
return { status: "skipped", reason: "disabled" };
|
||||
}
|
||||
try {
|
||||
const res = await runOnce({
|
||||
cfg: state.cfg,
|
||||
agentId: targetAgent.agentId,
|
||||
heartbeat: targetAgent.heartbeat,
|
||||
reason,
|
||||
sessionKey: requestedSessionKey,
|
||||
deps: { runtime: state.runtime },
|
||||
});
|
||||
if (res.status !== "skipped" || res.reason !== "disabled") {
|
||||
advanceAgentSchedule(targetAgent, now);
|
||||
}
|
||||
scheduleNext();
|
||||
return res.status === "ran" ? { status: "ran", durationMs: Date.now() - startedAt } : res;
|
||||
} catch (err) {
|
||||
const errMsg = formatErrorMessage(err);
|
||||
log.error(`heartbeat runner: targeted runOnce threw unexpectedly: ${errMsg}`, {
|
||||
error: errMsg,
|
||||
});
|
||||
advanceAgentSchedule(targetAgent, now);
|
||||
scheduleNext();
|
||||
return { status: "failed", reason: errMsg };
|
||||
}
|
||||
}
|
||||
|
||||
for (const agent of state.agents.values()) {
|
||||
if (isInterval && now < agent.nextDueMs) {
|
||||
continue;
|
||||
@@ -1016,7 +1082,12 @@ export function startHeartbeatRunner(opts: {
|
||||
return { status: "skipped", reason: isInterval ? "not-due" : "disabled" };
|
||||
};
|
||||
|
||||
const wakeHandler: HeartbeatWakeHandler = async (params) => run({ reason: params.reason });
|
||||
const wakeHandler: HeartbeatWakeHandler = async (params) =>
|
||||
run({
|
||||
reason: params.reason,
|
||||
agentId: params.agentId,
|
||||
sessionKey: params.sessionKey,
|
||||
});
|
||||
const disposeWakeHandler = setHeartbeatWakeHandler(wakeHandler);
|
||||
updateConfig(state.cfg);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user