
























@@ -1715,6 +1715,256 @@ describe("CodexAppServerEventProjector", () => {
17151715expect(toolResultContent.content).toBe("opened");
17161716});
171717171718+it("emits verbose summaries for transcript-recorded dynamic tool calls", async () => {
1719+const onAgentEvent = vi.fn();
1720+const onToolResult = vi.fn();
1721+const projector = await createProjector({
1722+ ...(await createParams()),
1723+verboseLevel: "on",
1724+ onAgentEvent,
1725+ onToolResult,
1726+});
1727+1728+projector.recordDynamicToolCall({
1729+callId: "call-browser-1",
1730+tool: "browser",
1731+arguments: { action: "open", url: "http://127.0.0.1:3000" },
1732+});
1733+1734+const toolEvents = onAgentEvent.mock.calls.filter(([event]) => {
1735+const record = requireRecord(event, "agent event");
1736+return record.stream === "tool";
1737+});
1738+expect(toolEvents).toHaveLength(0);
1739+expect(onToolResult).toHaveBeenCalledTimes(1);
1740+const payload = mockCallArg(onToolResult, 0, 0, "onToolResult") as { text?: string };
1741+expect(payload.text).toContain("Browser");
1742+});
1743+1744+it("does not replay transcript summaries when only tool output is enabled", async () => {
1745+const onToolResult = vi.fn();
1746+const projector = await createProjector({
1747+ ...(await createParams()),
1748+ onToolResult,
1749+shouldEmitToolResult: () => false,
1750+shouldEmitToolOutput: () => true,
1751+});
1752+1753+projector.recordDynamicToolCall({
1754+callId: "call-browser-1",
1755+tool: "browser",
1756+arguments: { action: "open", url: "http://127.0.0.1:3000" },
1757+});
1758+projector.recordDynamicToolResult({
1759+callId: "call-browser-1",
1760+tool: "browser",
1761+success: true,
1762+contentItems: [{ type: "inputText", text: "opened" }],
1763+});
1764+1765+expect(onToolResult).toHaveBeenCalledTimes(1);
1766+const payload = mockCallArg(onToolResult, 0, 0, "onToolResult") as { text?: string };
1767+expect(payload.text).toContain("opened");
1768+expect(payload.text).toContain("```txt\nopened\n```");
1769+});
1770+1771+it("suppresses transcript progress for message-like tools", async () => {
1772+const onAgentEvent = vi.fn();
1773+const onToolResult = vi.fn();
1774+const projector = await createProjector({
1775+ ...(await createParams()),
1776+verboseLevel: "on",
1777+ onAgentEvent,
1778+ onToolResult,
1779+});
1780+1781+projector.recordDynamicToolCall({
1782+callId: "call-message-1",
1783+tool: "message",
1784+arguments: { action: "send", text: "hello" },
1785+});
1786+projector.recordDynamicToolResult({
1787+callId: "call-message-1",
1788+tool: "message",
1789+success: true,
1790+contentItems: [{ type: "inputText", text: "sent" }],
1791+});
1792+1793+const toolEvents = onAgentEvent.mock.calls.filter(([event]) => {
1794+const record = requireRecord(event, "agent event");
1795+return record.stream === "tool";
1796+});
1797+expect(toolEvents).toHaveLength(0);
1798+expect(onToolResult).not.toHaveBeenCalled();
1799+});
1800+1801+it("suppresses transcript progress for activity-log bash commands", async () => {
1802+const onAgentEvent = vi.fn();
1803+const onToolResult = vi.fn();
1804+const projector = await createProjector({
1805+ ...(await createParams()),
1806+verboseLevel: "on",
1807+ onAgentEvent,
1808+ onToolResult,
1809+});
1810+1811+projector.recordDynamicToolCall({
1812+callId: "call-log-activity-1",
1813+tool: "bash",
1814+arguments: {
1815+command:
1816+'/bin/bash -lc \'/home/openclaw/.openclaw/workspace/bin/log_activity.sh "web_search" "Grilled salmon research"\'',
1817+cwd: "/workspace",
1818+},
1819+});
1820+projector.recordDynamicToolResult({
1821+callId: "call-log-activity-1",
1822+tool: "bash",
1823+success: true,
1824+contentItems: [{ type: "inputText", text: "Logged: [web_search] Grilled salmon research" }],
1825+});
1826+1827+const toolEvents = onAgentEvent.mock.calls.filter(([event]) => {
1828+const record = requireRecord(event, "agent event");
1829+return record.stream === "tool";
1830+});
1831+expect(toolEvents).toHaveLength(0);
1832+expect(onToolResult).not.toHaveBeenCalled();
1833+1834+const result = projector.buildResult(buildEmptyToolTelemetry());
1835+expect(result.messagesSnapshot.some((message) => message.role === "toolResult")).toBe(true);
1836+});
1837+1838+it("keeps diagnostics for exact message-like native tool items while suppressing progress", async () => {
1839+const onAgentEvent = vi.fn();
1840+const onToolResult = vi.fn();
1841+const projector = await createProjector({
1842+ ...(await createParams()),
1843+verboseLevel: "on",
1844+ onAgentEvent,
1845+ onToolResult,
1846+});
1847+const diagnosticEvents: DiagnosticEventPayload[] = [];
1848+const unsubscribe = onInternalDiagnosticEvent((event) => diagnosticEvents.push(event));
1849+1850+try {
1851+await projector.handleNotification(
1852+forCurrentTurn("item/started", {
1853+item: {
1854+type: "mcpToolCall",
1855+id: "mcp-message-1",
1856+server: null,
1857+tool: "message",
1858+arguments: { text: "hello" },
1859+status: "inProgress",
1860+result: null,
1861+error: null,
1862+durationMs: null,
1863+},
1864+}),
1865+);
1866+await projector.handleNotification(
1867+forCurrentTurn("item/completed", {
1868+item: {
1869+type: "mcpToolCall",
1870+id: "mcp-message-1",
1871+server: null,
1872+tool: "message",
1873+arguments: { text: "hello" },
1874+status: "completed",
1875+result: { ok: true },
1876+error: null,
1877+durationMs: 7,
1878+},
1879+}),
1880+);
1881+await flushDiagnosticEvents();
1882+} finally {
1883+unsubscribe();
1884+}
1885+1886+const toolEvents = onAgentEvent.mock.calls.filter(([event]) => {
1887+const record = requireRecord(event, "agent event");
1888+return record.stream === "tool";
1889+});
1890+expect(toolEvents).toHaveLength(0);
1891+expect(onToolResult).not.toHaveBeenCalled();
1892+1893+const toolDiagnosticEvents = diagnosticEvents.filter(
1894+(
1895+event,
1896+): event is Extract<
1897+DiagnosticEventPayload,
1898+{
1899+type:
1900+| "tool.execution.started"
1901+| "tool.execution.completed"
1902+| "tool.execution.error"
1903+| "tool.execution.blocked";
1904+}
1905+> => event.type.startsWith("tool.execution."),
1906+);
1907+expect(
1908+toolDiagnosticEvents.map((event) => ({
1909+type: event.type,
1910+toolName: event.toolName,
1911+toolCallId: event.toolCallId,
1912+durationMs: "durationMs" in event ? event.durationMs : undefined,
1913+})),
1914+).toEqual([
1915+{
1916+type: "tool.execution.started",
1917+toolName: "message",
1918+toolCallId: "mcp-message-1",
1919+durationMs: undefined,
1920+},
1921+{
1922+type: "tool.execution.completed",
1923+toolName: "message",
1924+toolCallId: "mcp-message-1",
1925+durationMs: 7,
1926+},
1927+]);
1928+});
1929+1930+it("does not suppress qualified external tools that end with message-like names", async () => {
1931+const onAgentEvent = vi.fn();
1932+const onToolResult = vi.fn();
1933+const projector = await createProjector({
1934+ ...(await createParams()),
1935+verboseLevel: "on",
1936+ onAgentEvent,
1937+ onToolResult,
1938+});
1939+1940+await projector.handleNotification(
1941+forCurrentTurn("item/started", {
1942+item: {
1943+type: "mcpToolCall",
1944+id: "mcp-email-send-1",
1945+server: "email",
1946+tool: "send",
1947+arguments: { to: "user@example.com" },
1948+status: "inProgress",
1949+result: null,
1950+error: null,
1951+durationMs: null,
1952+},
1953+}),
1954+);
1955+1956+const toolStart = findAgentEvent(onAgentEvent, {
1957+stream: "tool",
1958+phase: "start",
1959+itemId: "mcp-email-send-1",
1960+name: "email.send",
1961+}).data;
1962+expect(toolStart.toolCallId).toBe("mcp-email-send-1");
1963+expect(onToolResult).toHaveBeenCalledWith({
1964+text: "🧩 Email.send: `user@example.com`",
1965+});
1966+});
1967+17181968it("marks declined Codex-native tool results as non-success", async () => {
17191969const onAgentEvent = vi.fn();
17201970const projector = await createProjector({ ...(await createParams()), onAgentEvent });
@@ -1888,7 +2138,7 @@ describe("CodexAppServerEventProjector", () => {
18882138);
1889213918902140const text = (mockCallArg(onToolResult, 0, 0, "onToolResult") as { text?: string }).text;
1891-expect(text).toContain("sk-123…ZZZZ");
2141+expect(text).toContain("OPENAI_API_KEY=*** pnpm test");
18922142expect(text).not.toContain("sk-1234567890abcdefZZZZ");
18932143});
18942144此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。