👌 IMPROVE: discord fix

This commit is contained in:
kumarabhirup 2026-02-24 17:20:34 -05:00
parent 00baf45a2f
commit 9ca4263147
No known key found for this signature in database
GPG Key ID: DB7CA2289CAB0167
7 changed files with 46 additions and 9 deletions

View File

@ -17,7 +17,6 @@ import { join } from "node:path";
import { resolveOpenClawStateDir } from "@/lib/workspace";
export const runtime = "nodejs";
export const maxDuration = 600;
function deriveSubagentInfo(sessionKey: string): { parentSessionId: string; task: string } | null {
const registryPath = join(resolveOpenClawStateDir(), "subagents", "runs.json");

View File

@ -19,7 +19,6 @@ import { join } from "node:path";
import { resolveOpenClawStateDir } from "@/lib/workspace";
export const runtime = "nodejs";
export const maxDuration = 600;
function deriveSubagentInfo(sessionKey: string): { parentSessionId: string; task: string } | null {
const registryPath = join(resolveOpenClawStateDir(), "subagents", "runs.json");

View File

@ -1,6 +1,6 @@
import type { OpenClawConfig } from "../config/config.js";
const DEFAULT_AGENT_TIMEOUT_SECONDS = 1800;
const DEFAULT_AGENT_TIMEOUT_SECONDS = 0;
const MAX_SAFE_TIMEOUT_MS = 2_147_000_000;
const normalizeNumber = (value: unknown): number | undefined =>
@ -9,7 +9,8 @@ const normalizeNumber = (value: unknown): number | undefined =>
export function resolveAgentTimeoutSeconds(cfg?: OpenClawConfig): number {
const raw = normalizeNumber(cfg?.agents?.defaults?.timeoutSeconds);
const seconds = raw ?? DEFAULT_AGENT_TIMEOUT_SECONDS;
return Math.max(seconds, 1);
// 0 means "no timeout"; only clamp positive values to >= 1.
return seconds === 0 ? 0 : Math.max(seconds, 1);
}
export function resolveAgentTimeoutMs(opts: {
@ -21,9 +22,9 @@ export function resolveAgentTimeoutMs(opts: {
const minMs = Math.max(normalizeNumber(opts.minMs) ?? 1, 1);
const clampTimeoutMs = (valueMs: number) =>
Math.min(Math.max(valueMs, minMs), MAX_SAFE_TIMEOUT_MS);
const defaultMs = clampTimeoutMs(resolveAgentTimeoutSeconds(opts.cfg) * 1000);
// Use the maximum timer-safe timeout to represent "no timeout" when explicitly set to 0.
const NO_TIMEOUT_MS = MAX_SAFE_TIMEOUT_MS;
const defaultSeconds = resolveAgentTimeoutSeconds(opts.cfg);
const defaultMs = defaultSeconds === 0 ? NO_TIMEOUT_MS : clampTimeoutMs(defaultSeconds * 1000);
const overrideMs = normalizeNumber(opts.overrideMs);
if (overrideMs !== undefined) {
if (overrideMs === 0) {

View File

@ -74,7 +74,7 @@ function parseTimeoutSeconds(opts: { cfg: ReturnType<typeof loadConfig>; timeout
const raw =
opts.timeout !== undefined
? Number.parseInt(String(opts.timeout), 10)
: (opts.cfg.agents?.defaults?.timeoutSeconds ?? 600);
: (opts.cfg.agents?.defaults?.timeoutSeconds ?? 0);
if (Number.isNaN(raw) || raw < 0) {
throw new Error("--timeout must be a non-negative integer (seconds; 0 means no timeout)");
}
@ -226,7 +226,8 @@ async function agentViaGatewayStreamJson(opts: AgentCliOpts, _runtime: RuntimeEn
}
}
const timeoutSeconds = parseTimeoutSeconds({ cfg, timeout: opts.timeout });
const gatewayTimeoutMs = Math.max(10_000, (timeoutSeconds + 30) * 1000);
const gatewayTimeoutMs =
timeoutSeconds === 0 ? NO_GATEWAY_TIMEOUT_MS : Math.max(10_000, (timeoutSeconds + 30) * 1000);
const sessionKey = resolveSessionKeyForRequest({
cfg,

View File

@ -87,6 +87,33 @@ describe("resolveDiscordChannelAllowlist", () => {
expect(res[0]?.channelId).toBeUndefined();
});
it("resolves numeric guildId/channelId pair by ID", async () => {
const fetcher = withFetchPreconnect(async (input: RequestInfo | URL) => {
const url = urlToString(input);
if (url.endsWith("/users/@me/guilds")) {
return jsonResponse([{ id: "1468757251106934866", name: "Test Server" }]);
}
if (url.endsWith("/guilds/1468757251106934866/channels")) {
return jsonResponse([
{ id: "1475662965717078159", name: "bot-chat", guild_id: "1468757251106934866", type: 0 },
{ id: "9999", name: "general", guild_id: "1468757251106934866", type: 0 },
]);
}
return new Response("not found", { status: 404 });
});
const res = await resolveDiscordChannelAllowlist({
token: "test",
entries: ["1468757251106934866/1475662965717078159"],
fetcher,
});
expect(res[0]?.resolved).toBe(true);
expect(res[0]?.guildId).toBe("1468757251106934866");
expect(res[0]?.channelId).toBe("1475662965717078159");
expect(res[0]?.channelName).toBe("bot-chat");
});
it("bare numeric guild id is misrouted as channel id (regression)", async () => {
// Demonstrates why provider.ts must prefix guild-only entries with "guild:"
// In reality, Discord returns 404 when a guild ID is sent to /channels/<guildId>,

View File

@ -230,8 +230,11 @@ export async function resolveDiscordChannelAllowlist(params: {
continue;
}
const channels = await getChannels(guild.id);
const isIdQuery = /^\d+$/.test(channelQuery);
const matches = channels.filter(
(channel) => normalizeDiscordSlug(channel.name) === normalizeDiscordSlug(channelQuery),
(channel) =>
(isIdQuery && channel.id === channelQuery) ||
normalizeDiscordSlug(channel.name) === normalizeDiscordSlug(channelQuery),
);
const match = preferActiveMatch(matches);
if (match) {

View File

@ -16,6 +16,8 @@ export function isChatStopCommandText(text: string): boolean {
return trimmed.toLowerCase() === "/stop" || isAbortTrigger(trimmed);
}
const NO_EXPIRATION_THRESHOLD_MS = 2_000_000_000;
export function resolveChatRunExpiresAtMs(params: {
now: number;
timeoutMs: number;
@ -23,6 +25,11 @@ export function resolveChatRunExpiresAtMs(params: {
minMs?: number;
maxMs?: number;
}): number {
// "No timeout" runs (timeoutMs at or above the timer-safe max) never expire
// automatically; they can still be aborted via /stop or chat.abort.
if (params.timeoutMs >= NO_EXPIRATION_THRESHOLD_MS) {
return Number.MAX_SAFE_INTEGER;
}
const { now, timeoutMs, graceMs = 60_000, minMs = 2 * 60_000, maxMs = 24 * 60 * 60_000 } = params;
const boundedTimeoutMs = Math.max(0, timeoutMs);
const target = now + boundedTimeoutMs + graceMs;