From 8a5d20b10a17171ffb2a3d0d9b4fc32441ab54c1 Mon Sep 17 00:00:00 2001 From: Claude Date: Tue, 14 Jul 2026 09:25:07 +0000 Subject: [PATCH] Keep call arguments out of tool observation names Tool observations are now named by the tool alone (exec_command, local_shell, web_search, server.tool for MCP calls); the shell command and search query no longer appear in the name and live only in the observation input. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_019Cj5proPC8sHJmTP5DKmx8 --- README.md | 2 +- plugins/tracing/dist/index.mjs | 46 ++++-------------------------- plugins/tracing/src/trace.ts | 45 ++++------------------------- plugins/tracing/test/trace.test.ts | 13 ++++----- 4 files changed, 18 insertions(+), 88 deletions(-) diff --git a/README.md b/README.md index a27a88f..2074583 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ After each Codex turn, the plugin reads the session's rollout transcript and upl - **Turn** (`Codex Turn`, an [agent observation](https://langfuse.com/docs/observability/features/observation-types)) — one trace per turn, from your prompt to the final answer. - **Generations** — one per model response within the turn, named `LLM` (or `LLM Subagent` inside subagent threads), with the model recorded on the observation plus reasoning, assistant text, the tool calls it requested, and token usage. -- **Tool calls** — shell commands, `apply_patch`, `spawn_agent`, MCP tools, web searches, etc., each with its input, output, and error status. Observation names include what was called — the shell command (`exec_command: git status`), the search query (`web_search: …`), or the MCP server and tool (`server.tool`) — and failed commands are flagged as errors. +- **Tool calls** — shell commands, `apply_patch`, `spawn_agent`, MCP tools, web searches, etc., each with its input, output, and error status. MCP calls are named `server.tool`, and failed commands are flagged as errors. - **Subagents** — subagent threads are resolved from their own rollout files and nested under the spawning turn as `Codex Subagent Turn`. - **Sessions** — all turns from one Codex session are grouped via the Codex thread id, so you can replay the whole session in Langfuse's [Sessions](https://langfuse.com/docs/observability/features/sessions) view. diff --git a/plugins/tracing/dist/index.mjs b/plugins/tracing/dist/index.mjs index b894005..cdc80c5 100644 --- a/plugins/tracing/dist/index.mjs +++ b/plugins/tracing/dist/index.mjs @@ -47011,50 +47011,16 @@ function buildGenerationOutput(step, clip) { })); return Object.keys(output).length > 0 ? output : void 0; } -/** Tools that execute a shell command; the command makes a better span name. */ -const SHELL_TOOL_NAMES = new Set([ - "shell", - "exec_command", - "local_shell", - "container.exec" -]); -/** Collapse a value to a short single line usable inside a span name. */ -function previewText(value, max = 60) { - const oneLine = value.trim().replace(/\s+/g, " "); - return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine; -} -function extractCommandText(args) { - if (args == null || typeof args !== "object") return void 0; - const cmd = args.command ?? args.cmd; - if (typeof cmd === "string" && cmd.trim()) return cmd; - if (Array.isArray(cmd) && cmd.length > 0 && cmd.every((c) => typeof c === "string")) { - const parts = cmd; - if (parts.length === 3 && /^(ba|z|fi)?sh$/.test(parts[0]) && /^-l?c$/.test(parts[1])) return parts[2]; - return parts.join(" "); - } -} /** -* Observation name for a tool call: the tool name enriched with what it was -* called with (shell command, search query, MCP server/tool), so the trace -* tree shows *what* ran, not just which tool. +* Observation name for a tool call. MCP calls use the clean `server.tool` +* split from the mcp_tool_call_* events instead of the mangled function name; +* everything else uses the plain tool name. Call arguments (shell command, +* search query, …) stay out of the name — they belong to the observation +* input. */ function toolObservationName(tc) { if (tc.mcp) return `${tc.mcp.server}.${tc.mcp.tool}`; - const name = tc.name || "tool"; - if (SHELL_TOOL_NAMES.has(name)) { - const command = extractCommandText(tc.args); - if (command) return `${name}: ${previewText(command)}`; - } - if (name === "web_search" && tc.args != null && typeof tc.args === "object") { - const a = tc.args; - const detail = [ - a.query, - a.url, - a.pattern - ].find((v) => typeof v === "string" && v); - if (detail) return `${name}: ${previewText(detail)}`; - } - return name; + return tc.name || "tool"; } /** Emit a single turn (and its subagents) as a Langfuse observation tree. */ async function emitTurn(turn, sessionMeta, ctx) { diff --git a/plugins/tracing/src/trace.ts b/plugins/tracing/src/trace.ts index 6f965aa..3f5e2d0 100644 --- a/plugins/tracing/src/trace.ts +++ b/plugins/tracing/src/trace.ts @@ -155,49 +155,16 @@ function buildGenerationOutput(step: ModelStep, clip: Clip): Record 0 ? output : undefined; } -/** Tools that execute a shell command; the command makes a better span name. */ -const SHELL_TOOL_NAMES = new Set(["shell", "exec_command", "local_shell", "container.exec"]); - -/** Collapse a value to a short single line usable inside a span name. */ -function previewText(value: string, max = 60): string { - const oneLine = value.trim().replace(/\s+/g, " "); - return oneLine.length > max ? `${oneLine.slice(0, max - 1)}…` : oneLine; -} - -function extractCommandText(args: unknown): string | undefined { - if (args == null || typeof args !== "object") return undefined; - const cmd = - (args as { command?: unknown; cmd?: unknown }).command ?? (args as { cmd?: unknown }).cmd; - if (typeof cmd === "string" && cmd.trim()) return cmd; - if (Array.isArray(cmd) && cmd.length > 0 && cmd.every((c) => typeof c === "string")) { - const parts = cmd as string[]; - // Codex wraps most commands as ["bash", "-lc", "