






















@@ -54,6 +54,10 @@ import {
5454createCodexDynamicToolBridge,
5555} from "./dynamic-tools.js";
5656import * as elicitationBridge from "./elicitation-bridge.js";
57+import {
58+CodexAppServerEventProjector,
59+type CodexAppServerToolTelemetry,
60+} from "./event-projector.js";
5761import {
5862buildCodexPluginAppCacheKey,
5963resolveCodexPluginAppCacheEndpoint,
@@ -669,6 +673,15 @@ function createRuntimeDynamicTool(name: string): RuntimeDynamicToolForTest {
669673};
670674}
671675676+function buildEmptyCodexToolTelemetry(): CodexAppServerToolTelemetry {
677+return {
678+didSendViaMessagingTool: false,
679+messagingToolSentTexts: [],
680+messagingToolSentMediaUrls: [],
681+messagingToolSentTargets: [],
682+};
683+}
684+672685function createPluginAppConfigPatch() {
673686return {
674687apps: {
@@ -2657,28 +2670,31 @@ describe("runCodexAppServerAttempt", () => {
26572670});
2658267126592672it("returns a run context report without deferred Codex dynamic tool schemas", async () => {
2660-testing.setOpenClawCodingToolsFactoryForTests(() => [
2661-createRuntimeDynamicTool("message"),
2662-createRuntimeDynamicTool("web_search"),
2663-]);
2664-const harness = createStartedThreadHarness();
26652673const params = createParams(
26662674path.join(tempDir, "session.jsonl"),
26672675path.join(tempDir, "workspace"),
26682676);
2669-params.disableTools = false;
2670-params.runtimePlan = createCodexRuntimePlanFixture();
2671-params.sourceReplyDeliveryMode = "message_tool_only";
2672-params.toolsAllow = ["message", "web_search"];
2673-2674-const run = runCodexAppServerAttempt(params, {
2675-pluginConfig: { appServer: { mode: "yolo" } },
2677+const toolBridge = createCodexDynamicToolBridge({
2678+tools: [createRuntimeDynamicTool("message"), createRuntimeDynamicTool("web_search")],
2679+signal: new AbortController().signal,
2680+directToolNames: ["message"],
26762681});
2677-await harness.waitForMethod("turn/start", 120_000);
2678-await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
2679-const result = await run;
268026822681-const report = result.systemPromptReport;
2683+const report = testing.buildCodexSystemPromptReport({
2684+attempt: params,
2685+sessionKey: params.sessionKey ?? "agent:main:session-1",
2686+workspaceDir: params.workspaceDir ?? tempDir,
2687+developerInstructions: "test developer instructions",
2688+workspaceBootstrapContext: {
2689+bootstrapFiles: [],
2690+contextFiles: [],
2691+promptContextFiles: [],
2692+developerInstructionFiles: [],
2693+heartbeatReferenceFiles: [],
2694+},
2695+skillsPrompt: "",
2696+tools: toolBridge.availableSpecs,
2697+});
26822698expect(report?.source).toBe("run");
26832699expect(report?.provider).toBe("codex");
26842700expect(report?.model).toBe("gpt-5.4-codex");
@@ -2692,46 +2708,24 @@ describe("runCodexAppServerAttempt", () => {
26922708});
2693270926942710it("keeps searchable Codex dynamic tools canonical in mirrored transcript snapshots", async () => {
2695-testing.setOpenClawCodingToolsFactoryForTests(() => [createRuntimeDynamicTool("wiki_status")]);
2696-const harness = createStartedThreadHarness();
26972711const params = createParams(
26982712path.join(tempDir, "session.jsonl"),
26992713path.join(tempDir, "workspace"),
27002714);
2701-params.disableTools = false;
2702-params.runtimePlan = createCodexRuntimePlanFixture();
2703-params.toolsAllow = ["wiki_status"];
2704-2705-const run = runCodexAppServerAttempt(params, {
2706-pluginConfig: {
2707-codexDynamicToolsLoading: "searchable",
2708-appServer: { mode: "yolo" },
2709-},
2715+const projector = new CodexAppServerEventProjector(params, "thread-1", "turn-1");
2716+projector.recordDynamicToolCall({
2717+callId: "call-wiki-status-1",
2718+tool: "wiki_status",
2719+arguments: { topic: "README.md" },
27102720});
2711-await harness.waitForMethod("turn/start", 120_000);
2712-2713-const toolResult = (await harness.handleServerRequest({
2714-id: "request-tool-wiki-status",
2715-method: "item/tool/call",
2716-params: {
2717-threadId: "thread-1",
2718-turnId: "turn-1",
2719-callId: "call-wiki-status-1",
2720-namespace: CODEX_OPENCLAW_DYNAMIC_TOOL_NAMESPACE,
2721-tool: "wiki_status",
2722-arguments: { topic: "README.md" },
2723-},
2724-})) as {
2725-contentItems?: Array<{ text?: string; type?: string }>;
2726-success?: boolean;
2727-};
2728-expect(toolResult).toEqual({
2721+projector.recordDynamicToolResult({
2722+callId: "call-wiki-status-1",
2723+tool: "wiki_status",
27292724success: true,
2725+terminalType: "completed",
27302726contentItems: [{ type: "inputText", text: "wiki_status done" }],
27312727});
2732-2733-await harness.completeTurn({ threadId: "thread-1", turnId: "turn-1" });
2734-const result = await run;
2728+const result = projector.buildResult(buildEmptyCodexToolTelemetry());
2735272927362730expect(result.messagesSnapshot.map((message) => message.role)).toEqual([
27372731"user",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。