惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Apple Machine Learning Research
Apple Machine Learning Research
J
Java Code Geeks
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Last Week in AI
Last Week in AI
雷峰网
雷峰网
博客园_首页
小众软件
小众软件
美团技术团队
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
腾讯CDC
P
Proofpoint News Feed
MongoDB | Blog
MongoDB | Blog
Google DeepMind News
Google DeepMind News
MyScale Blog
MyScale Blog
U
Unit 42
The Cloudflare Blog
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
Microsoft Security Blog
Microsoft Security Blog
大猫的无限游戏
大猫的无限游戏
Engineering at Meta
Engineering at Meta
N
Netflix TechBlog - Medium
Microsoft Azure Blog
Microsoft Azure Blog
博客园 - 叶小钗

Recent Commits to openclaw:main

test: merge chat side-result checks · openclaw/openclaw@ddd2c2a test: merge cron history checks · openclaw/openclaw@f7eb746 test: merge responsive navigation shell checks · openclaw/openclaw@c2e4b47 docs(changelog): add codex oauth fixes · openclaw/openclaw@628e6cd test: merge navigation routing cases · openclaw/openclaw@5d8cecb Tests: mock channel registry bundled fallback · openclaw/openclaw@2b08233 Secrets: avoid broad web search discovery for single plugin config · openclaw/openclaw@a464f59 test: merge config view browser checks · openclaw/openclaw@20cf511 fix(status): align oauth health with runtime · openclaw/openclaw@eed7116 feat: add macOS screen snapshots for monitor preview (#67954) thanks … · openclaw/openclaw@f377db1 fix: report shared auth scopes in hello-ok (#67810) thanks @BunsDev · openclaw/openclaw@0b6c39b Auto-reply: avoid eager bundled route fallback · openclaw/openclaw@3ea1bf4 Tests: narrow session binding contract setup · openclaw/openclaw@54e4e16 fix(macOS): enable undo/redo in webchat composer text input (#34962) · openclaw/openclaw@00951dc Tests: speed up channel setup promotion · openclaw/openclaw@82b529a Docs: refresh agent instructions · openclaw/openclaw@5775fe2 fix(auth): serialize OAuth refresh across agents to fix #26322 (#67876) · openclaw/openclaw@8e79080 test: allow ollama public surface boundary test · openclaw/openclaw@7d4f1a6 Docs: add test performance guardrails · openclaw/openclaw@89706d3 Tests: restore context-engine usage proof · openclaw/openclaw@e4c4f95 Tests: slim context engine runtime coverage · openclaw/openclaw@74c198f ci: retry failed custom checkouts · openclaw/openclaw@0ee5baf test: trim duplicate provider auth onboarding cases · openclaw/openclaw@1ffc02e matrix: fix sessions_spawn --thread subagent session spawning (#67643) · openclaw/openclaw@1ce2596 test: reduce auth choice fixture churn · openclaw/openclaw@857b9cd test: mock health status config boundaries · openclaw/openclaw@9d5ab4a test: mock onboard config io boundary · openclaw/openclaw@299694d test: mock legacy state plugin boundaries · openclaw/openclaw@2713089 test: mock channel install boundaries · openclaw/openclaw@b945248 test: mock doctor preview channel boundaries · openclaw/openclaw@b1a3ad4
fix(gateway): default restart acknowledgement continuatio...
obviyus · 2026-04-23 · via Recent Commits to openclaw:main

@@ -0,0 +1,136 @@

1+

import { beforeEach, describe, expect, it, vi } from "vitest";

2+

import type { RestartSentinelPayload } from "../../infra/restart-sentinel.js";

3+

import type { HandleCommandsParams } from "./commands-types.js";

4+5+

const mocks = vi.hoisted(() => ({

6+

isRestartEnabled: vi.fn(() => true),

7+

extractDeliveryInfo: vi.fn(() => ({

8+

deliveryContext: {

9+

channel: "telegram",

10+

to: "telegram:123",

11+

accountId: "default",

12+

},

13+

threadId: "thread-1",

14+

})),

15+

formatDoctorNonInteractiveHint: vi.fn(() => "Run: openclaw doctor --non-interactive"),

16+

writeRestartSentinel: vi.fn(async (_payload: RestartSentinelPayload) => "/tmp/sentinel.json"),

17+

scheduleGatewaySigusr1Restart: vi.fn(() => ({ scheduled: true })),

18+

triggerOpenClawRestart: vi.fn(() => ({ ok: true, method: "launchctl" })),

19+

}));

20+21+

vi.mock("../../config/commands.flags.js", () => ({

22+

isRestartEnabled: mocks.isRestartEnabled,

23+

}));

24+25+

vi.mock("../../config/sessions.js", () => ({

26+

extractDeliveryInfo: mocks.extractDeliveryInfo,

27+

}));

28+29+

vi.mock("../../globals.js", () => ({

30+

logVerbose: vi.fn(),

31+

}));

32+33+

vi.mock("../../channels/plugins/index.js", () => ({

34+

getChannelPlugin: vi.fn(),

35+

normalizeChannelId: (value?: string | null) => value?.trim().toLowerCase() ?? null,

36+

}));

37+38+

vi.mock("../../channels/plugins/conversation-bindings.js", () => ({

39+

setChannelConversationBindingIdleTimeoutBySessionKey: vi.fn(),

40+

setChannelConversationBindingMaxAgeBySessionKey: vi.fn(),

41+

}));

42+43+

vi.mock("../../infra/outbound/session-binding-service.js", () => ({

44+

getSessionBindingService: vi.fn(),

45+

}));

46+47+

vi.mock("../../infra/restart-sentinel.js", async () => {

48+

const actual = await vi.importActual<typeof import("../../infra/restart-sentinel.js")>(

49+

"../../infra/restart-sentinel.js",

50+

);

51+

return {

52+

...actual,

53+

formatDoctorNonInteractiveHint: mocks.formatDoctorNonInteractiveHint,

54+

writeRestartSentinel: mocks.writeRestartSentinel,

55+

};

56+

});

57+58+

vi.mock("../../infra/restart.js", () => ({

59+

scheduleGatewaySigusr1Restart: mocks.scheduleGatewaySigusr1Restart,

60+

triggerOpenClawRestart: mocks.triggerOpenClawRestart,

61+

}));

62+63+

const { handleRestartCommand } = await import("./commands-session.js");

64+65+

function restartCommandParams(overrides?: Partial<HandleCommandsParams>): HandleCommandsParams {

66+

return {

67+

ctx: {},

68+

cfg: {},

69+

command: {

70+

surface: "telegram",

71+

channel: "telegram",

72+

ownerList: [],

73+

senderIsOwner: true,

74+

isAuthorizedSender: true,

75+

senderId: "user-1",

76+

rawBodyNormalized: "/restart",

77+

commandBodyNormalized: "/restart",

78+

from: "telegram:123",

79+

to: "bot",

80+

},

81+

directives: {},

82+

elevated: { enabled: true, allowed: true, failures: [] },

83+

sessionKey: "agent:main:telegram:direct:123:thread:thread-1",

84+

workspaceDir: "/tmp",

85+

defaultGroupActivation: () => "mention",

86+

resolvedVerboseLevel: "off",

87+

resolvedReasoningLevel: "off",

88+

resolveDefaultThinkingLevel: async () => undefined,

89+

provider: "openai",

90+

model: "gpt-5.4",

91+

contextTokens: 0,

92+

isGroup: false,

93+

...overrides,

94+

} as HandleCommandsParams;

95+

}

96+97+

describe("handleRestartCommand", () => {

98+

beforeEach(() => {

99+

mocks.isRestartEnabled.mockReset();

100+

mocks.isRestartEnabled.mockReturnValue(true);

101+

mocks.extractDeliveryInfo.mockClear();

102+

mocks.formatDoctorNonInteractiveHint.mockClear();

103+

mocks.writeRestartSentinel.mockClear();

104+

mocks.scheduleGatewaySigusr1Restart.mockClear();

105+

mocks.triggerOpenClawRestart.mockReset();

106+

mocks.triggerOpenClawRestart.mockReturnValue({ ok: true, method: "launchctl" });

107+

});

108+109+

it("writes a routed restart sentinel before restarting from chat", async () => {

110+

const { DEFAULT_RESTART_SUCCESS_CONTINUATION_MESSAGE } =

111+

await import("../../infra/restart-sentinel.js");

112+113+

const result = await handleRestartCommand(restartCommandParams(), true);

114+115+

expect(result?.shouldContinue).toBe(false);

116+

expect(mocks.writeRestartSentinel).toHaveBeenCalledWith(

117+

expect.objectContaining({

118+

kind: "restart",

119+

status: "ok",

120+

sessionKey: "agent:main:telegram:direct:123:thread:thread-1",

121+

deliveryContext: {

122+

channel: "telegram",

123+

to: "telegram:123",

124+

accountId: "default",

125+

},

126+

threadId: "thread-1",

127+

message: "/restart",

128+

continuation: {

129+

kind: "agentTurn",

130+

message: DEFAULT_RESTART_SUCCESS_CONTINUATION_MESSAGE,

131+

},

132+

}),

133+

);

134+

expect(mocks.triggerOpenClawRestart).toHaveBeenCalledTimes(1);

135+

});

136+

});