fix: trigger agent response for webchat sessions after restart

Webchat sessions don't have channel/to in their delivery context, so
   the restart sentinel was falling back to enqueueSystemEvent() which
   queues the message but doesn't trigger an agent turn.

   This fix passes addChatRun and broadcast through to the sentinel,
   allowing it to register the run and call agentCommand() so responses
   stream to webchat clients.

   🤖 AI-assisted (Claude)
This commit is contained in:
Peter Dove 2026-01-28 18:18:00 +00:00
parent 109ac1c549
commit 1e0858ffe2
3 changed files with 49 additions and 2 deletions

View File

@ -14,7 +14,24 @@ import { defaultRuntime } from "../runtime.js";
import { deliveryContextFromSession, mergeDeliveryContext } from "../utils/delivery-context.js"; import { deliveryContextFromSession, mergeDeliveryContext } from "../utils/delivery-context.js";
import { loadSessionEntry } from "./session-utils.js"; import { loadSessionEntry } from "./session-utils.js";
export async function scheduleRestartSentinelWake(params: { deps: CliDeps }) { export type AddChatRunFn = (
runId: string,
entry: { sessionKey: string; clientRunId: string },
) => void;
export type BroadcastFn = (
event: string,
payload: unknown,
opts?: { dropIfSlow?: boolean },
) => void;
export interface RestartSentinelParams {
deps: CliDeps;
addChatRun?: AddChatRunFn;
broadcast?: BroadcastFn;
}
export async function scheduleRestartSentinelWake(params: RestartSentinelParams) {
const sentinel = await consumeRestartSentinel(); const sentinel = await consumeRestartSentinel();
if (!sentinel) return; if (!sentinel) return;
const payload = sentinel.payload; const payload = sentinel.payload;
@ -61,7 +78,27 @@ export async function scheduleRestartSentinelWake(params: { deps: CliDeps }) {
const channel = channelRaw ? normalizeChannelId(channelRaw) : null; const channel = channelRaw ? normalizeChannelId(channelRaw) : null;
const to = origin?.to; const to = origin?.to;
if (!channel || !to) { if (!channel || !to) {
// No outbound channel (e.g., webchat sessions use WebSocket, not channel delivery).
// For webchat: register the run with addChatRun so responses stream to the client.
enqueueSystemEvent(message, { sessionKey }); enqueueSystemEvent(message, { sessionKey });
if (params.addChatRun && params.broadcast) {
const runId = `restart-${Date.now()}`;
params.addChatRun(runId, { sessionKey, clientRunId: runId });
try {
await agentCommand(
{
message: `System: ${summary}`,
sessionKey,
runId,
deliver: false,
},
defaultRuntime,
params.deps,
);
} catch {
// Agent turn failed; system event already queued as fallback context
}
}
return; return;
} }

View File

@ -19,6 +19,8 @@ import type { loadMoltbotPlugins } from "../plugins/loader.js";
import { type PluginServicesHandle, startPluginServices } from "../plugins/services.js"; import { type PluginServicesHandle, startPluginServices } from "../plugins/services.js";
import { startBrowserControlServerIfEnabled } from "./server-browser.js"; import { startBrowserControlServerIfEnabled } from "./server-browser.js";
import { import {
type AddChatRunFn,
type BroadcastFn,
scheduleRestartSentinelWake, scheduleRestartSentinelWake,
shouldWakeFromRestartSentinel, shouldWakeFromRestartSentinel,
} from "./server-restart-sentinel.js"; } from "./server-restart-sentinel.js";
@ -37,6 +39,8 @@ export async function startGatewaySidecars(params: {
}; };
logChannels: { info: (msg: string) => void; error: (msg: string) => void }; logChannels: { info: (msg: string) => void; error: (msg: string) => void };
logBrowser: { error: (msg: string) => void }; logBrowser: { error: (msg: string) => void };
addChatRun?: AddChatRunFn;
broadcast?: BroadcastFn;
}) { }) {
// Start clawd browser control server (unless disabled via config). // Start clawd browser control server (unless disabled via config).
let browserControl: Awaited<ReturnType<typeof startBrowserControlServerIfEnabled>> = null; let browserControl: Awaited<ReturnType<typeof startBrowserControlServerIfEnabled>> = null;
@ -152,7 +156,11 @@ export async function startGatewaySidecars(params: {
if (shouldWakeFromRestartSentinel()) { if (shouldWakeFromRestartSentinel()) {
setTimeout(() => { setTimeout(() => {
void scheduleRestartSentinelWake({ deps: params.deps }); void scheduleRestartSentinelWake({
deps: params.deps,
addChatRun: params.addChatRun,
broadcast: params.broadcast,
});
}, 750); }, 750);
} }

View File

@ -503,6 +503,8 @@ export async function startGatewayServer(
logHooks, logHooks,
logChannels, logChannels,
logBrowser, logBrowser,
addChatRun,
broadcast,
})); }));
const { applyHotReload, requestGatewayRestart } = createGatewayReloadHandlers({ const { applyHotReload, requestGatewayRestart } = createGatewayReloadHandlers({