mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-10 07:22:44 +00:00
fix(hooks): propagate ephemeral sessionId through embedded tool contexts (#32273)
* fix(plugins): expose ephemeral sessionId in tool contexts for per-conversation isolation The plugin tool context (`OpenClawPluginToolContext`) and tool hook context (`PluginHookToolContext`) only provided `sessionKey`, which is a durable channel identifier that survives /new and /reset. Plugins like mem0 that need per-conversation isolation (e.g. mapping Mem0 `run_id`) had no way to distinguish between conversations, causing session-scoped memories to persist unbounded across resets. Add `sessionId` (ephemeral UUID regenerated on /new and /reset) to: - `OpenClawPluginToolContext` (factory context for plugin tools) - `PluginHookToolContext` (before_tool_call / after_tool_call hooks) - Internal `HookContext` for tool call wrappers Thread the value from the run attempt through createOpenClawCodingTools → createOpenClawTools → resolvePluginTools and through the tool hook wrapper. Closes #31253 Made-with: Cursor * fix(agents): propagate embedded sessionId through tool hook context * test(hooks): cover sessionId in embedded tool hook contexts * docs(changelog): add sessionId hook context follow-up note * test(hooks): avoid toolCallId collision in after_tool_call e2e --------- Co-authored-by: SidQin-cyber <sidqin0410@gmail.com>
This commit is contained in:
@@ -30,4 +30,21 @@ describe("createOpenClawTools plugin context", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("forwards ephemeral sessionId to plugin tool context", () => {
|
||||
createOpenClawTools({
|
||||
config: {} as never,
|
||||
agentSessionKey: "agent:main:telegram:direct:12345",
|
||||
sessionId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
});
|
||||
|
||||
expect(resolvePluginToolsMock).toHaveBeenCalledWith(
|
||||
expect.objectContaining({
|
||||
context: expect.objectContaining({
|
||||
sessionKey: "agent:main:telegram:direct:12345",
|
||||
sessionId: "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
|
||||
}),
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,6 +70,8 @@ export function createOpenClawTools(options?: {
|
||||
requesterSenderId?: string | null;
|
||||
/** Whether the requesting sender is an owner. */
|
||||
senderIsOwner?: boolean;
|
||||
/** Ephemeral session UUID — regenerated on /new and /reset. */
|
||||
sessionId?: string;
|
||||
}): AnyAgentTool[] {
|
||||
const workspaceDir = resolveWorkspaceRoot(options?.workspaceDir);
|
||||
const imageTool = options?.agentDir?.trim()
|
||||
@@ -199,6 +201,7 @@ export function createOpenClawTools(options?: {
|
||||
config: options?.config,
|
||||
}),
|
||||
sessionKey: options?.agentSessionKey,
|
||||
sessionId: options?.sessionId,
|
||||
messageChannel: options?.agentChannel,
|
||||
agentAccountId: options?.agentAccountId,
|
||||
requesterSenderId: options?.requesterSenderId ?? undefined,
|
||||
|
||||
@@ -370,6 +370,7 @@ export async function compactEmbeddedPiSessionDirect(
|
||||
messageProvider: params.messageChannel ?? params.messageProvider,
|
||||
agentAccountId: params.agentAccountId,
|
||||
sessionKey: sandboxSessionKey,
|
||||
sessionId: params.sessionId,
|
||||
groupId: params.groupId,
|
||||
groupChannel: params.groupChannel,
|
||||
groupSpace: params.groupSpace,
|
||||
|
||||
@@ -585,6 +585,7 @@ export async function runEmbeddedAttempt(
|
||||
senderE164: params.senderE164,
|
||||
senderIsOwner: params.senderIsOwner,
|
||||
sessionKey: sandboxSessionKey,
|
||||
sessionId: params.sessionId,
|
||||
agentDir,
|
||||
workspaceDir: effectiveWorkspace,
|
||||
config: params.config,
|
||||
@@ -858,7 +859,8 @@ export async function runEmbeddedAttempt(
|
||||
},
|
||||
{
|
||||
agentId: sessionAgentId,
|
||||
sessionKey: params.sessionKey,
|
||||
sessionKey: sandboxSessionKey,
|
||||
sessionId: params.sessionId,
|
||||
loopDetection: clientToolLoopDetection,
|
||||
},
|
||||
)
|
||||
@@ -1186,6 +1188,7 @@ export async function runEmbeddedAttempt(
|
||||
enforceFinalTag: params.enforceFinalTag,
|
||||
config: params.config,
|
||||
sessionKey: sandboxSessionKey,
|
||||
sessionId: params.sessionId,
|
||||
agentId: sessionAgentId,
|
||||
});
|
||||
|
||||
|
||||
@@ -433,6 +433,7 @@ export async function handleToolExecutionEnd(
|
||||
toolName,
|
||||
agentId: ctx.params.agentId,
|
||||
sessionKey: ctx.params.sessionKey,
|
||||
sessionId: ctx.params.sessionId,
|
||||
})
|
||||
.catch((err) => {
|
||||
ctx.log.warn(`after_tool_call hook failed: tool=${toolName} error=${String(err)}`);
|
||||
|
||||
@@ -132,7 +132,13 @@ export type EmbeddedPiSubscribeContext = {
|
||||
*/
|
||||
export type ToolHandlerParams = Pick<
|
||||
SubscribeEmbeddedPiSessionParams,
|
||||
"runId" | "onBlockReplyFlush" | "onAgentEvent" | "onToolResult" | "sessionKey" | "agentId"
|
||||
| "runId"
|
||||
| "onBlockReplyFlush"
|
||||
| "onAgentEvent"
|
||||
| "onToolResult"
|
||||
| "sessionKey"
|
||||
| "sessionId"
|
||||
| "agentId"
|
||||
>;
|
||||
|
||||
export type ToolHandlerState = Pick<
|
||||
|
||||
@@ -31,6 +31,8 @@ export type SubscribeEmbeddedPiSessionParams = {
|
||||
enforceFinalTag?: boolean;
|
||||
config?: OpenClawConfig;
|
||||
sessionKey?: string;
|
||||
/** Ephemeral session UUID — regenerated on /new and /reset. */
|
||||
sessionId?: string;
|
||||
/** Agent identity for hook context — resolved from session config in attempt.ts. */
|
||||
agentId?: string;
|
||||
};
|
||||
|
||||
@@ -122,6 +122,7 @@ describe("before_tool_call hook integration", () => {
|
||||
const tool = wrapToolWithBeforeToolCallHook({ name: "ReAd", execute } as any, {
|
||||
agentId: "main",
|
||||
sessionKey: "main",
|
||||
sessionId: "ephemeral-main",
|
||||
});
|
||||
const extensionContext = {} as Parameters<typeof tool.execute>[3];
|
||||
|
||||
@@ -136,6 +137,7 @@ describe("before_tool_call hook integration", () => {
|
||||
toolName: "read",
|
||||
agentId: "main",
|
||||
sessionKey: "main",
|
||||
sessionId: "ephemeral-main",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
@@ -9,6 +9,8 @@ import type { AnyAgentTool } from "./tools/common.js";
|
||||
export type HookContext = {
|
||||
agentId?: string;
|
||||
sessionKey?: string;
|
||||
/** Ephemeral session UUID — regenerated on /new and /reset. */
|
||||
sessionId?: string;
|
||||
loopDetection?: ToolLoopDetectionConfig;
|
||||
};
|
||||
|
||||
@@ -148,6 +150,7 @@ export async function runBeforeToolCallHook(args: {
|
||||
toolName,
|
||||
agentId: args.ctx?.agentId,
|
||||
sessionKey: args.ctx?.sessionKey,
|
||||
sessionId: args.ctx?.sessionId,
|
||||
},
|
||||
);
|
||||
|
||||
|
||||
@@ -188,6 +188,8 @@ export function createOpenClawCodingTools(options?: {
|
||||
messageThreadId?: string | number;
|
||||
sandbox?: SandboxContext | null;
|
||||
sessionKey?: string;
|
||||
/** Ephemeral session UUID — regenerated on /new and /reset. */
|
||||
sessionId?: string;
|
||||
agentDir?: string;
|
||||
workspaceDir?: string;
|
||||
config?: OpenClawConfig;
|
||||
@@ -493,6 +495,7 @@ export function createOpenClawCodingTools(options?: {
|
||||
requesterAgentIdOverride: agentId,
|
||||
requesterSenderId: options?.senderId,
|
||||
senderIsOwner: options?.senderIsOwner,
|
||||
sessionId: options?.sessionId,
|
||||
}),
|
||||
];
|
||||
const toolsForMessageProvider = applyMessageProviderToolPolicy(tools, options?.messageProvider);
|
||||
@@ -533,6 +536,7 @@ export function createOpenClawCodingTools(options?: {
|
||||
wrapToolWithBeforeToolCallHook(tool, {
|
||||
agentId,
|
||||
sessionKey: options?.sessionKey,
|
||||
sessionId: options?.sessionId,
|
||||
loopDetection: resolveToolLoopDetectionConfig({ cfg: options?.config, agentId }),
|
||||
}),
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user