mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 13:20:43 +00:00
fix: keep codex tool result context config-free
This commit is contained in:
@@ -414,6 +414,92 @@ describe("createCodexDynamicToolBridge", () => {
|
||||
expect(result).toEqual(expectInputText("legacy compacted"));
|
||||
});
|
||||
|
||||
it("keeps config out of Codex tool-result contexts", async () => {
|
||||
const config = { session: { store: "/tmp/openclaw-session-store.json" } };
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const middlewareContexts: Record<string, unknown>[] = [];
|
||||
const legacyContexts: Record<string, unknown>[] = [];
|
||||
const middleware = vi.fn(async (_event: unknown, ctx: Record<string, unknown>) => {
|
||||
middlewareContexts.push(ctx);
|
||||
return undefined;
|
||||
});
|
||||
const factory = async (codex: {
|
||||
on: (
|
||||
event: "tool_result",
|
||||
handler: (
|
||||
event: unknown,
|
||||
ctx: Record<string, unknown>,
|
||||
) => Promise<{ result: AgentToolResult<unknown> } | void>,
|
||||
) => void;
|
||||
}) => {
|
||||
codex.on("tool_result", async (_event, ctx) => {
|
||||
legacyContexts.push(ctx);
|
||||
});
|
||||
};
|
||||
registry.agentToolResultMiddlewares.push({
|
||||
pluginId: "tokenjuice",
|
||||
pluginName: "Tokenjuice",
|
||||
rawHandler: middleware,
|
||||
handler: middleware,
|
||||
runtimes: ["codex"],
|
||||
source: "test",
|
||||
});
|
||||
registry.codexAppServerExtensionFactories.push({
|
||||
pluginId: "legacy",
|
||||
pluginName: "Legacy",
|
||||
rawFactory: factory,
|
||||
factory,
|
||||
source: "test",
|
||||
});
|
||||
setActivePluginRegistry(registry);
|
||||
|
||||
const execute = vi.fn(async () => textToolResult("done"));
|
||||
const bridge = createCodexDynamicToolBridge({
|
||||
tools: [createTool({ name: "exec", execute })],
|
||||
signal: new AbortController().signal,
|
||||
hookContext: {
|
||||
agentId: "agent-1",
|
||||
config: config as never,
|
||||
sessionId: "session-1",
|
||||
sessionKey: "agent:agent-1:session-1",
|
||||
runId: "run-1",
|
||||
},
|
||||
});
|
||||
|
||||
await bridge.handleToolCall({
|
||||
threadId: "thread-1",
|
||||
turnId: "turn-1",
|
||||
callId: "call-1",
|
||||
namespace: null,
|
||||
tool: "exec",
|
||||
arguments: { command: "pwd" },
|
||||
});
|
||||
|
||||
expect(execute).toHaveBeenCalledWith(
|
||||
"call-1",
|
||||
{ command: "pwd" },
|
||||
expect.any(AbortSignal),
|
||||
undefined,
|
||||
);
|
||||
expect(middlewareContexts).toHaveLength(1);
|
||||
expect(middlewareContexts[0]).toMatchObject({
|
||||
runtime: "codex",
|
||||
agentId: "agent-1",
|
||||
sessionId: "session-1",
|
||||
sessionKey: "agent:agent-1:session-1",
|
||||
runId: "run-1",
|
||||
});
|
||||
expect(middlewareContexts[0]).not.toHaveProperty("config");
|
||||
expect(legacyContexts).toHaveLength(1);
|
||||
expect(legacyContexts[0]).toMatchObject({
|
||||
agentId: "agent-1",
|
||||
sessionId: "session-1",
|
||||
sessionKey: "agent:agent-1:session-1",
|
||||
runId: "run-1",
|
||||
});
|
||||
expect(legacyContexts[0]).not.toHaveProperty("config");
|
||||
});
|
||||
|
||||
it("fires after_tool_call for successful codex tool executions", async () => {
|
||||
const afterToolCall = vi.fn();
|
||||
initializeGlobalHookRunner(
|
||||
|
||||
@@ -25,6 +25,16 @@ import {
|
||||
type JsonValue,
|
||||
} from "./protocol.js";
|
||||
|
||||
type CodexDynamicToolHookContext = {
|
||||
agentId?: string;
|
||||
config?: EmbeddedRunAttemptParams["config"];
|
||||
sessionId?: string;
|
||||
sessionKey?: string;
|
||||
runId?: string;
|
||||
};
|
||||
|
||||
type CodexToolResultHookContext = Omit<CodexDynamicToolHookContext, "config">;
|
||||
|
||||
export type CodexDynamicToolBridge = {
|
||||
specs: CodexDynamicToolSpec[];
|
||||
handleToolCall: (
|
||||
@@ -46,14 +56,9 @@ export type CodexDynamicToolBridge = {
|
||||
export function createCodexDynamicToolBridge(params: {
|
||||
tools: AnyAgentTool[];
|
||||
signal: AbortSignal;
|
||||
hookContext?: {
|
||||
agentId?: string;
|
||||
config?: EmbeddedRunAttemptParams["config"];
|
||||
sessionId?: string;
|
||||
sessionKey?: string;
|
||||
runId?: string;
|
||||
};
|
||||
hookContext?: CodexDynamicToolHookContext;
|
||||
}): CodexDynamicToolBridge {
|
||||
const toolResultHookContext = toToolResultHookContext(params.hookContext);
|
||||
const tools = params.tools.map((tool) =>
|
||||
isToolWrappedWithBeforeToolCallHook(tool)
|
||||
? tool
|
||||
@@ -70,11 +75,10 @@ export function createCodexDynamicToolBridge(params: {
|
||||
};
|
||||
const middlewareRunner = createAgentToolResultMiddlewareRunner({
|
||||
runtime: "codex",
|
||||
...params.hookContext,
|
||||
...toolResultHookContext,
|
||||
});
|
||||
const legacyExtensionRunner = createCodexAppServerToolResultExtensionRunner(
|
||||
params.hookContext ?? {},
|
||||
);
|
||||
const legacyExtensionRunner =
|
||||
createCodexAppServerToolResultExtensionRunner(toolResultHookContext);
|
||||
|
||||
return {
|
||||
specs: tools.map((tool) => ({
|
||||
@@ -126,10 +130,10 @@ export function createCodexDynamicToolBridge(params: {
|
||||
void runAgentHarnessAfterToolCallHook({
|
||||
toolName: tool.name,
|
||||
toolCallId: call.callId,
|
||||
runId: params.hookContext?.runId,
|
||||
agentId: params.hookContext?.agentId,
|
||||
sessionId: params.hookContext?.sessionId,
|
||||
sessionKey: params.hookContext?.sessionKey,
|
||||
runId: toolResultHookContext.runId,
|
||||
agentId: toolResultHookContext.agentId,
|
||||
sessionId: toolResultHookContext.sessionId,
|
||||
sessionKey: toolResultHookContext.sessionKey,
|
||||
startArgs: args,
|
||||
result,
|
||||
startedAt,
|
||||
@@ -149,10 +153,10 @@ export function createCodexDynamicToolBridge(params: {
|
||||
void runAgentHarnessAfterToolCallHook({
|
||||
toolName: tool.name,
|
||||
toolCallId: call.callId,
|
||||
runId: params.hookContext?.runId,
|
||||
agentId: params.hookContext?.agentId,
|
||||
sessionId: params.hookContext?.sessionId,
|
||||
sessionKey: params.hookContext?.sessionKey,
|
||||
runId: toolResultHookContext.runId,
|
||||
agentId: toolResultHookContext.agentId,
|
||||
sessionId: toolResultHookContext.sessionId,
|
||||
sessionKey: toolResultHookContext.sessionKey,
|
||||
startArgs: args,
|
||||
error: error instanceof Error ? error.message : String(error),
|
||||
startedAt,
|
||||
@@ -171,6 +175,18 @@ export function createCodexDynamicToolBridge(params: {
|
||||
};
|
||||
}
|
||||
|
||||
function toToolResultHookContext(
|
||||
ctx: CodexDynamicToolHookContext | undefined,
|
||||
): CodexToolResultHookContext {
|
||||
const { agentId, sessionId, sessionKey, runId } = ctx ?? {};
|
||||
return {
|
||||
...(agentId && { agentId }),
|
||||
...(sessionId && { sessionId }),
|
||||
...(sessionKey && { sessionKey }),
|
||||
...(runId && { runId }),
|
||||
};
|
||||
}
|
||||
|
||||
function composeAbortSignals(...signals: Array<AbortSignal | undefined>): AbortSignal {
|
||||
const activeSignals = signals.filter((signal): signal is AbortSignal => Boolean(signal));
|
||||
if (activeSignals.length === 0) {
|
||||
|
||||
Reference in New Issue
Block a user