





























@@ -4,7 +4,9 @@ import os from "node:os";
44import path from "node:path";
55import {
66embeddedAgentLog,
7+isToolWrappedWithBeforeToolCallHook,
78type EmbeddedRunAttemptParams,
9+wrapToolWithBeforeToolCallHook,
810} from "openclaw/plugin-sdk/agent-harness-runtime";
911import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
1012import {
@@ -581,6 +583,46 @@ describe("Codex app-server dynamic tool build", () => {
581583});
582584});
583585586+it("forwards the tool outcome observer into Codex dynamic tools", async () => {
587+const sessionFile = path.join(tempDir, "session.jsonl");
588+const workspaceDir = path.join(tempDir, "workspace");
589+const params = createParams(sessionFile, workspaceDir);
590+const onToolOutcome = vi.fn();
591+params.disableTools = false;
592+params.onToolOutcome = onToolOutcome;
593+params.runtimePlan = createCodexRuntimePlanFixture();
594+const factoryOptions: unknown[] = [];
595+setOpenClawCodingToolsFactoryForTests((options) => {
596+factoryOptions.push(options);
597+return [];
598+});
599+600+await buildDynamicToolsForTest(params, workspaceDir, { sandbox: null as never });
601+602+expect(factoryOptions[0]).toMatchObject({ onToolOutcome });
603+});
604+605+it("preserves before-tool wrapping through Codex runtime normalization", async () => {
606+const sessionFile = path.join(tempDir, "session.jsonl");
607+const workspaceDir = path.join(tempDir, "workspace");
608+const params = createParams(sessionFile, workspaceDir);
609+params.disableTools = false;
610+const runtimePlan = createCodexRuntimePlanFixture();
611+runtimePlan.tools.normalize = (tools) => tools.map((tool) => ({ ...tool }));
612+params.runtimePlan = runtimePlan;
613+const wrappedTool = wrapToolWithBeforeToolCallHook(createRuntimeDynamicTool("web_fetch"), {
614+agentId: "main",
615+sessionId: params.sessionId,
616+});
617+setOpenClawCodingToolsFactoryForTests(() => [wrappedTool]);
618+619+const tools = await buildDynamicToolsForTest(params, workspaceDir, { sandbox: null as never });
620+621+expect(tools).toHaveLength(1);
622+expect(tools[0]).not.toBe(wrappedTool);
623+expect(isToolWrappedWithBeforeToolCallHook(tools[0])).toBe(true);
624+});
625+584626it("passes runtime config into Codex exec dynamic tool construction", async () => {
585627const sessionFile = path.join(tempDir, "session.jsonl");
586628const workspaceDir = path.join(tempDir, "workspace");
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。