Skip to content

[Bug] Bash / Read / Glob / Grep intermittently fail with Tool <name> not found (0 ms) on Windows — present in 0.15.9 and 0.15.10 #1225

Description

@bachhn25810320367

[Bug] Bash / Read / Glob / Grep intermittently fail with Tool <name> not found (0 ms) on Windows — present in 0.15.9 and 0.15.10

What happened? / 问题描述

The four filesystem/shell tools (bash, read, glob, grep) stop resolving. The model emits a tool call, the app receives it, and the tool immediately returns:

Tool bash not found
Tool read not found
Tool glob not found
Tool grep not found

The failure takes 0 ms, which means it never reaches the actual tool implementation — it is rejected at name-resolution time.

Two things make this hard to pin down, and both are the reason for this report:

1. It is intermittent, not a permanently dead registry. The same tool name, same app version, same session, alternates between working and failing:

2026-09-28T09:00:35Z  Bash  error    0ms
2026-09-28T09:02:24Z  Read  error    0ms
2026-09-28T09:02:28Z  Bash  error    0ms
2026-09-28T09:03:43Z  Bash  success 223ms     <-- works
2026-09-28T09:03:47Z  Bash  error    1ms
2026-09-28T09:04:13Z  Bash  error    0ms
2026-09-28T09:05:12Z  Bash  success 267ms     <-- works
2026-09-28T09:06:07Z  Bash  error    0ms
2026-09-28T09:07:08Z  Read  success 18ms      <-- works
2026-09-28T09:12:16Z  Glob  success           <-- last success ever recorded

2. It is not a 0.15.10 regression. The last recorded success is 2026-09-28T09:12:16Z. The updater installed 0.15.9 at 05:14:08Z and 0.15.10 at 15:52:10Z that same day. Between 09:16 and 15:52 — i.e. while 0.15.9 was running — there were 62 consecutive dead-tool calls, all errors, all 0–1 ms. So 0.15.9 is affected too, and downgrading is not a workaround.

As of 2026-09-29T09:55Z (this report) there have been zero successful executions of these four tools across 24 h, 2 sessions, and 2 full app restarts.

Steps to reproduce / 复现步骤

  1. Run PI-Desktop on Windows 10 with a long-lived session that uses the agent harness heavily.

  2. After roughly a day of use, the four tools begin failing.

  3. Restart the app fully and open a new session — the tools still fail immediately, so it is not per-session state.

  4. Check ~/.pi-desktop/logs/app/tool.log: every failure is tool.execution.failed with "durationMs":0 and a valid toolCallId, meaning the call is delivered to the app and fails inside the tool layer.

Expected behavior / 预期行为

A tool name that is present in the session's tool list resolves and executes.

Actual behavior / 实际行为

tools.find(o => o.name === call.name) returns undefined and the call is rejected with Tool <name> not found in 0 ms, with no diagnostic about which names were actually available.

Where the message comes from / 错误信息来源

I traced the string to the tool-dispatch helper in the bundled runtime (resources/agent-runtime/sidecar.js, 7.7 MB minified bundle). The three distinct not found formats in that bundle are distinguishable; the one that is actually emitted (unquoted, matching the observed text) is:

async function Aht(t, e, n, r, i) {
  let s = t.tools?.find(o => o.name === n.name);
  if (!s) return { kind: "immediate", result: i_(`Tool ${n.name} not found`), isError: !0 };
  ...
}

The lookup is a strict === with no case normalization and no fallback, and the immediate branch explains the 0 ms duration exactly.

The registered names are all lowercase / 注册名全为小写

Instantiating the real tool definitions from the standalone package @earendil-works/pi-coding-agent@0.87.1 (dist/core/tools/*.js) at runtime:

createReadToolDefinition             -> name: "read"
createBashToolDefinition             -> name: "bash"
createEditToolDefinition             -> name: "edit"
createWriteToolDefinition            -> name: "write"
createGrepToolDefinition             -> name: "grep"
createFindToolDefinition             -> name: "find"
createLsToolDefinition               -> name: "ls"
createPowerShellToolDefinition       -> name: "powershell"

Reproducing the dispatcher's lookup against that set:

tools.find(o => o.name === "read")  -> true
tools.find(o => o.name === "Read")  -> false
tools.find(o => o.name === "bash")  -> true
tools.find(o => o.name === "Bash")  -> false
tools.find(o => o.name === "glob")  -> false      <-- pi has no "glob" at all

Two observations:

  • The canonical names are lowercase. A capitalized name can never satisfy the ===.

  • pi core has no glob tool whatsoever — it has find and ls. So glob is not obtainable from pi core under any spelling, which suggests Glob is supplied by the desktop layer and is broken for a separate reason.

The bundled sidecar.js contains both spellings, which is consistent with an unfinished name migration (see #860):

  | capitalized | lowercase -- | -- | -- Bash / bash | 16 | 31 Read / read | 12 | 23 Edit / edit | 9 | 21 Grep / grep | 10 | 8 Glob / glob | 10 | 2

Write (312/312), Edit (156/168), Task (26/26), askTool (16/16) and plugin_pi_shellbridge_shell_run (416/449) were unaffected throughout — so the failure is specific to this group, not a general session failure.

App version / 应用版本

PI-Desktop 0.15.10 · win32 x64
resources/agent-runtime/sidecar.js  7,696,583 bytes  (2026-09-28 19:30 local)
pi-desktop-host-core.exe             15,870,464 bytes (2026-09-28 19:30 local)

Operating system / 操作系统

Windows 10 Pro, 10.0.19045 (MINGW64_NT-10.0-19045)
Electron 43.6.0 · Node v24.20.0

Extra environment / 其他环境信息

  • Affected on both 0.15.9 and 0.15.10.

  • The four tools have never recovered in 24 h / 2 sessions / 2 restarts.

  • Bash and Read calls reach the app (valid toolCallId in the log), so this is not a model↔app transport failure.

Logs / 日志

Representative failure entries from ~/.pi-desktop/logs/app/tool.log:

{"ts":"2026-09-29T09:53:51.427Z","level":"error","channel":"app","category":"tool","event":"tool.execution.failed","message":"tool execution failed","sessionId":"<this-session>","turnId":"<...>","toolCallId":"call_function_...","data":{"toolName":"read","outcome":"error","durationMs":0,...}}
{"ts":"2026-09-29T09:53:53.389Z","level":"error","channel":"app","category":"tool","event":"tool.execution.failed","message":"tool execution failed","sessionId":"<this-session>","turnId":"<...>","toolCallId":"call_function_...","data":{"toolName":"bash","outcome":"error","durationMs":0,...}}
{"ts":"2026-09-29T09:54:15.243Z","level":"error","channel":"app","category":"tool","event":"tool.execution.failed","message":"tool execution failed","sessionId":"<this-session>","turnId":"<...>","toolCallId":"call_function_...","data":{"toolName":"grep","outcome":"error","durationMs":0,...}}

For contrast, a working call from the same log:

{"ts":"2026-09-28T09:07:08Z","level":"info",...,"data":{"toolName":"Read","outcome":"success","durationMs":18,...}}

What would help most / 最需要的信息

The single missing piece is the actual contents of t.tools at the moment of a failure. A one-line diagnostic in the dispatcher would settle it immediately:

let s = t.tools?.find(o => o.name === n.name);
if (!s) { console.warn('[pi] tool lookup miss', { called: n.name, available: t.tools?.map(x => x.name) }); ... }

Without it, Tool <name> not found is indistinguishable between "name not registered", "name registered with different case", and "tool list rebuilt mid-session" — which is exactly why this has been hard to diagnose from the outside.

Two smaller questions:

  1. Is the tool list rebuilt per turn, per mode, or per compaction? A rebuild that drops the filesystem/shell group would explain the intermittency and the recovery.

  2. Should the dispatcher normalize case, or should the name migration in refactor(tool-names): one canonical lowercase tool name, one normalization boundary #860 be finished on the desktop side so it matches pi core's lowercase canonical names?

Related

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions