refactor: modularize plugin runtime and test hooks

This commit is contained in:
Peter Steinberger
2026-03-03 02:06:50 +00:00
parent f77f1d3800
commit 0fd77c9856
15 changed files with 812 additions and 619 deletions

View File

@@ -67,7 +67,8 @@ describe("session hook context wiring", () => {
await vi.waitFor(() => expect(hookRunnerMocks.runSessionStart).toHaveBeenCalledTimes(1));
const [event, context] = hookRunnerMocks.runSessionStart.mock.calls[0] ?? [];
expect(event).toMatchObject({ sessionKey });
expect(context).toMatchObject({ sessionKey });
expect(context).toMatchObject({ sessionKey, agentId: "main" });
expect(context).toMatchObject({ sessionId: event?.sessionId });
});
it("passes sessionKey to session_end hook context on reset", async () => {
@@ -88,8 +89,13 @@ describe("session hook context wiring", () => {
});
await vi.waitFor(() => expect(hookRunnerMocks.runSessionEnd).toHaveBeenCalledTimes(1));
await vi.waitFor(() => expect(hookRunnerMocks.runSessionStart).toHaveBeenCalledTimes(1));
const [event, context] = hookRunnerMocks.runSessionEnd.mock.calls[0] ?? [];
expect(event).toMatchObject({ sessionKey });
expect(context).toMatchObject({ sessionKey });
expect(context).toMatchObject({ sessionKey, agentId: "main" });
expect(context).toMatchObject({ sessionId: event?.sessionId });
const [startEvent] = hookRunnerMocks.runSessionStart.mock.calls[0] ?? [];
expect(startEvent).toMatchObject({ resumedFrom: "old-session" });
});
});

View File

@@ -146,6 +146,70 @@ type LegacyMainDeliveryRetirement = {
entry: SessionEntry;
};
type SessionHookContext = {
sessionId: string;
sessionKey: string;
agentId: string;
};
function buildSessionHookContext(params: {
sessionId: string;
sessionKey: string;
cfg: OpenClawConfig;
}): SessionHookContext {
return {
sessionId: params.sessionId,
sessionKey: params.sessionKey,
agentId: resolveSessionAgentId({ sessionKey: params.sessionKey, config: params.cfg }),
};
}
function buildSessionStartHookPayload(params: {
sessionId: string;
sessionKey: string;
cfg: OpenClawConfig;
resumedFrom?: string;
}): {
event: { sessionId: string; sessionKey: string; resumedFrom?: string };
context: SessionHookContext;
} {
return {
event: {
sessionId: params.sessionId,
sessionKey: params.sessionKey,
resumedFrom: params.resumedFrom,
},
context: buildSessionHookContext({
sessionId: params.sessionId,
sessionKey: params.sessionKey,
cfg: params.cfg,
}),
};
}
function buildSessionEndHookPayload(params: {
sessionId: string;
sessionKey: string;
cfg: OpenClawConfig;
messageCount?: number;
}): {
event: { sessionId: string; sessionKey: string; messageCount: number };
context: SessionHookContext;
} {
return {
event: {
sessionId: params.sessionId,
sessionKey: params.sessionKey,
messageCount: params.messageCount ?? 0,
},
context: buildSessionHookContext({
sessionId: params.sessionId,
sessionKey: params.sessionKey,
cfg: params.cfg,
}),
};
}
function resolveParentForkMaxTokens(cfg: OpenClawConfig): number {
const configured = cfg.session?.parentForkMaxTokens;
if (typeof configured === "number" && Number.isFinite(configured) && configured >= 0) {
@@ -643,39 +707,24 @@ export async function initSessionState(params: {
// If replacing an existing session, fire session_end for the old one
if (previousSessionEntry?.sessionId && previousSessionEntry.sessionId !== effectiveSessionId) {
if (hookRunner.hasHooks("session_end")) {
void hookRunner
.runSessionEnd(
{
sessionId: previousSessionEntry.sessionId,
sessionKey,
messageCount: 0,
},
{
sessionId: previousSessionEntry.sessionId,
sessionKey,
agentId: resolveSessionAgentId({ sessionKey, config: cfg }),
},
)
.catch(() => {});
const payload = buildSessionEndHookPayload({
sessionId: previousSessionEntry.sessionId,
sessionKey,
cfg,
});
void hookRunner.runSessionEnd(payload.event, payload.context).catch(() => {});
}
}
// Fire session_start for the new session
if (hookRunner.hasHooks("session_start")) {
void hookRunner
.runSessionStart(
{
sessionId: effectiveSessionId,
sessionKey,
resumedFrom: previousSessionEntry?.sessionId,
},
{
sessionId: effectiveSessionId,
sessionKey,
agentId: resolveSessionAgentId({ sessionKey, config: cfg }),
},
)
.catch(() => {});
const payload = buildSessionStartHookPayload({
sessionId: effectiveSessionId,
sessionKey,
cfg,
resumedFrom: previousSessionEntry?.sessionId,
});
void hookRunner.runSessionStart(payload.event, payload.context).catch(() => {});
}
}