mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 11:10:45 +00:00
fix cron run binding route (#78373)
Co-authored-by: Alex Knight <15041791+amknight@users.noreply.github.com>
This commit is contained in:
@@ -124,6 +124,7 @@ Docs: https://docs.openclaw.ai
|
||||
- Providers/xAI: clamp the bundled xAI thinking profile to `off` so live Gateway runs cannot send unsupported reasoning levels to native Grok Responses models.
|
||||
- Matrix/approvals: retry approval delivery up to 3 times with a short backoff so transient Matrix send failures do not strand pending approval prompts. (#78179) Thanks @Patrick-Erichsen.
|
||||
- Discord/gateway: measure heartbeat ACK timeouts from the actual heartbeat send, preventing late initial heartbeats from triggering false reconnect loops while the channel is still awaiting readiness. Fixes #77668. (#78087) Thanks @bryce-d-greybeard and @NikolaFC.
|
||||
- Channels/cron: ignore stale runtime conversation bindings that point at completed isolated cron run sessions, so follow-up DMs fall back to their normal route instead of reusing a closed cron task prompt. Fixes #78074. Thanks @amknight.
|
||||
- Discord/guilds: route plain text control commands such as `/steer` through the normal authorization and mention gate instead of silently dropping them before an agent session can see them. Fixes #78080. Thanks @ramitrkar-hash.
|
||||
- Control UI/Sessions: make the compaction count a compact `N Checkpoint(s)` disclosure and show expanded session-level details with modern checkpoint history cards across responsive table layouts. Thanks @BunsDev.
|
||||
- Control UI/performance: keep chat and channel tabs responsive while history payloads and channel probes are slow, label partial channel status, and record slow chat/config render timings in the event log. Thanks @BunsDev.
|
||||
|
||||
@@ -1,11 +1,23 @@
|
||||
import type { OpenClawConfig } from "openclaw/plugin-sdk/config-types";
|
||||
import {
|
||||
__testing as conversationBindingTesting,
|
||||
registerSessionBindingAdapter,
|
||||
type SessionBindingAdapter,
|
||||
} from "openclaw/plugin-sdk/conversation-runtime";
|
||||
import { resolveThreadSessionKeys } from "openclaw/plugin-sdk/routing";
|
||||
import { describe, expect, it } from "vitest";
|
||||
import { resolveTelegramConversationBaseSessionKey } from "./conversation-route.js";
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
resolveTelegramConversationBaseSessionKey,
|
||||
resolveTelegramConversationRoute,
|
||||
} from "./conversation-route.js";
|
||||
|
||||
describe("resolveTelegramConversationBaseSessionKey", () => {
|
||||
const cfg: OpenClawConfig = {};
|
||||
|
||||
beforeEach(() => {
|
||||
conversationBindingTesting.resetSessionBindingAdaptersForTests();
|
||||
});
|
||||
|
||||
it("keeps default-account DMs on the route session key", () => {
|
||||
expect(
|
||||
resolveTelegramConversationBaseSessionKey({
|
||||
@@ -105,4 +117,47 @@ describe("resolveTelegramConversationBaseSessionKey", () => {
|
||||
}).sessionKey,
|
||||
).toBe("agent:main:telegram:personal:direct:12345:thread:12345:99");
|
||||
});
|
||||
|
||||
it("keeps inbound DMs on the main route when a stale runtime binding points at a cron run", () => {
|
||||
const touch = vi.fn<NonNullable<SessionBindingAdapter["touch"]>>();
|
||||
registerSessionBindingAdapter({
|
||||
channel: "telegram",
|
||||
accountId: "default",
|
||||
listBySession: () => [],
|
||||
resolveByConversation: () => ({
|
||||
bindingId: "binding-cron-run",
|
||||
targetSessionKey: "agent:youtube:cron:monthly-report:run:closed-run-1",
|
||||
targetKind: "session",
|
||||
conversation: {
|
||||
channel: "telegram",
|
||||
accountId: "default",
|
||||
conversationId: "12345",
|
||||
},
|
||||
status: "active",
|
||||
boundAt: 1,
|
||||
}),
|
||||
touch,
|
||||
});
|
||||
|
||||
const result = resolveTelegramConversationRoute({
|
||||
cfg: {
|
||||
session: {
|
||||
dmScope: "main",
|
||||
},
|
||||
},
|
||||
accountId: "default",
|
||||
chatId: 12345,
|
||||
isGroup: false,
|
||||
senderId: 12345,
|
||||
});
|
||||
|
||||
expect(touch).not.toHaveBeenCalled();
|
||||
expect(result.configuredBinding).toBeNull();
|
||||
expect(result.configuredBindingSessionKey).toBe("");
|
||||
expect(result.route).toMatchObject({
|
||||
agentId: "main",
|
||||
sessionKey: "agent:main:main",
|
||||
matchedBy: "default",
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -118,6 +118,28 @@ describe("runtime conversation binding route", () => {
|
||||
expect(result.boundSessionKey).toBeUndefined();
|
||||
expect(result.route).toBe(route);
|
||||
});
|
||||
|
||||
it("ignores runtime bindings that target isolated cron run sessions", () => {
|
||||
const route = createRoute();
|
||||
const binding = createBinding({
|
||||
targetSessionKey: "agent:youtube:cron:monthly-report:run:closed-run-1",
|
||||
});
|
||||
const { touch } = registerAdapter(binding);
|
||||
|
||||
const result = resolveRuntimeConversationBindingRoute({
|
||||
route,
|
||||
conversation: {
|
||||
channel: "demo",
|
||||
accountId: "default",
|
||||
conversationId: "room-1",
|
||||
},
|
||||
});
|
||||
|
||||
expect(touch).not.toHaveBeenCalled();
|
||||
expect(result.bindingRecord).toBeNull();
|
||||
expect(result.boundSessionKey).toBeUndefined();
|
||||
expect(result.route).toBe(route);
|
||||
});
|
||||
});
|
||||
|
||||
describe("ensureConfiguredBindingRouteReady", () => {
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
import type { ResolvedAgentRoute } from "../../routing/resolve-route.js";
|
||||
import { deriveLastRoutePolicy } from "../../routing/resolve-route.js";
|
||||
import { resolveAgentIdFromSessionKey } from "../../routing/session-key.js";
|
||||
import { isCronRunSessionKey } from "../../sessions/session-key-utils.js";
|
||||
import { resolveConfiguredBinding } from "./binding-registry.js";
|
||||
import { ensureConfiguredBindingTargetReady } from "./binding-targets.js";
|
||||
import type { ConfiguredBindingResolution } from "./binding-types.js";
|
||||
@@ -125,6 +126,16 @@ export function resolveRuntimeConversationBindingRoute(
|
||||
};
|
||||
}
|
||||
|
||||
if (isCronRunSessionKey(boundSessionKey)) {
|
||||
logVerbose(
|
||||
`ignored runtime conversation binding ${bindingRecord.bindingId} to isolated cron run session ${boundSessionKey}`,
|
||||
);
|
||||
return {
|
||||
bindingRecord: null,
|
||||
route: params.route,
|
||||
};
|
||||
}
|
||||
|
||||
getSessionBindingService().touch(bindingRecord.bindingId);
|
||||
if (isPluginOwnedRuntimeBindingRecord(bindingRecord)) {
|
||||
return {
|
||||
|
||||
Reference in New Issue
Block a user