Skip to content

fix: architect subagent tool dispatch failures on Anthropic/proxy providers#9

Open
ChicK00o wants to merge 4 commits into
BlackBeltTechnology:developfrom
ChicK00o:fix/architect-tool-dispatch
Open

fix: architect subagent tool dispatch failures on Anthropic/proxy providers#9
ChicK00o wants to merge 4 commits into
BlackBeltTechnology:developfrom
ChicK00o:fix/architect-tool-dispatch

Conversation

@ChicK00o

@ChicK00o ChicK00o commented May 1, 2026

Copy link
Copy Markdown

Problem

When using an Anthropic-messages provider (direct or proxied) as the model backend, the flow architect subagent received zero callable tools. agent_write, flow_write, and finish were missing from the outbound API request, so the model wrote raw <tool_call> XML as plain text and always failed with "Architect couldn't produce a flow".

Files were also written to pi's install directory instead of the user's project, and tool name comparisons silently broke when the MCP adapter applied its mcp__<ns>__ prefix.

What was fixed

  • Tool registration: CreateAgentSessionOptions.tools expects string[] for built-ins, not ToolDefinition[]. Passing objects caused the SDK to silently drop all tools from the request.
  • Custom tool allowlist: The SDK's allowedToolNames filter was stripping agent_write, flow_write, and finish because only built-in names were included. Custom tool names are now added to the allowlist.
  • Adapter reverse map: The pi-anthropic-messages adapter builds its inbound name→tool map from the main session's getAllTools(). Subagent-only tools were never registered there, so inbound translation failed. Name-only stubs are now registered on the main session for the adapter's benefit.
  • mcp__flows__ prefix conflict: pi-flows was pre-prefixing custom tools, which broke the adapter's inverse mapping. The prefix is removed — the adapter handles renaming end-to-end.
  • projectRoot resolution: process.cwd() pointed to pi's install directory. A new resolveProjectRoot() walks up from cwd to find the nearest .git, falling back to ~/.pi outside any repo.
  • Path consistency in agent_write/flow_write: Paths are now resolved against projectRoot before validation, so all response branches return the same absolute path. Bare names (e.g. my-agent) are auto-expanded to their staging path.
  • finish as plain text: When the model hits max_tokens mid-turn, finish appears as a text <tool_call> block. Both execution.ts and flow-workspace now recover from this.
  • mcp__ prefix in tool name comparisons: Switch statements and toolCall extractors in flow-workspace and architect-widget now strip the mcp__<ns>__ prefix before comparing, and resolve extracted paths against projectRoot for correct existsSync/readFileSync behaviour.
  • Adapter fallback paths: Dynamic import of @pi/anthropic-messages falls back to known on-disk paths including compiled dist/ layouts.
  • find/ls missing from CORE_TOOL_NAMES: These built-ins were being incorrectly prefixed.

ChicK00o added 3 commits May 1, 2026 14:57
## Problem

When using portkey-aws (or any anthropic-messages provider) as the
model backend for the flow architect, the architect subagent session
received zero callable tools — agent_write, flow_write, and finish
were all absent from the outbound API request. The model had no tools
to call, so it wrote <tool_call> XML blocks as plain text and the
architect always reported 'Architect couldn't produce a flow'.

## Root Causes & Fixes

### 1. Wrong type for `tools` parameter (execution.ts)
CreateAgentSessionOptions.tools expects string[] (tool names to enable
from the built-in set), not ToolDefinition[]. Passing objects caused
the SDK to silently ignore the array, sending requests with no tools.

Fix: pass builtinToolNames as string[], customTools as ToolDefinition[].

### 2. Custom tools excluded by allowedToolNames filter (execution.ts)
The SDK uses options.tools as an allowedToolNames allowlist. Only names
in that set pass isAllowedTool() and appear in getAllTools() and the
outbound payload. Passing only builtin names filtered out agent_write,
flow_write, and finish entirely.

Fix: include customTools names in the tools allowlist alongside builtins.

### 3. Adapter reverse map missing custom tool names (index.ts)
The pi-anthropic-messages adapter builds its inbound reverse map from
pi.getAllTools() on the MAIN session. Subagent custom tools
(agent_write, flow_write, finish) were never registered on the main
session, so the reverse map had no entry for mcp__pi__agent_write etc.,
and inbound translation failed (tool dispatch: not found).

Fix: also register name-only stubs on the main session so the adapter
can build correct reverse maps. The stubs are never called — subagents
get the real execute via extraCustomTools.

### 4. mcp__flows__ prefix broke adapter round-trip (execution.ts)
pi-flows was applying its own mcp__flows__ prefix to custom tools.
The adapter's DEFAULT_MCP_PREFIX inverse mapping skips names that
already start with mcp__, so mcp__flows__finish had no reverse map
entry and dispatch failed.

Fix: remove mcp__flows__ prefix entirely — let the adapter handle
outbound renaming (finish → mcp__pi__finish) and inbound translation.

### 5. projectRoot always process.cwd() (index.ts, flow-workspace/index.ts)
Files were written to pi's install directory instead of the user's
project directory.

Fix: resolveProjectRoot() walks up from process.cwd() looking for .git,
falls back to ~/.pi if no git repo found (new extensions/project-root.ts).

### 6. agent_write/flow_write used wrong path base (agent-write.ts, flow-write.ts)
Relative paths were resolved against pi's process.cwd(), not the project.

Fix: resolve all paths against projectRoot. Also accept 'name' as alias
for 'path' (model uses both) and auto-expand bare names to staging paths.

### 7. flowPath recovery when finish is text-embedded (flow-workspace/index.ts)
When the model exhausts output tokens mid-response, finish appears as a
text <tool_call> block rather than a real tool invocation.

Fix: recover finishParams from text-embedded <tool_call> JSON in
execution.ts; recover flowPath from finishParams.files in workspace.

### 8. mcp__ prefix stripping in tool name comparisons (flow-workspace, architect-widget)
Tool names in toolCalls and architect widget switch statements were
compared against bare names but could arrive with mcp__<ns>__ prefix.

Fix: strip mcp__[^_]+__ prefix before comparison in both places.

### 9. Adapter fallback path (anthropic-messages-adapter.ts)
Dynamic import of @pi/anthropic-messages by package name fails when
installed as a git package under ~/.pi/agent/git/.

Fix: fall back to known install paths under ~/.pi/agent/git/.

### 10. find/ls missing from CORE_TOOL_NAMES (tool-prefix.ts)
These are builtin tools that should not be prefixed.

Fix: add find and ls to CORE_TOOL_NAMES.
- agent-write/flow-write: resolve absPath before validation so all
  response branches (invalid, fs-error, success) return the same
  absolute path instead of the pre-resolution relative filePath
- flow-workspace: resolve finishParams.files paths against projectRoot
  in both handleNewFlow and handleEditFlow fallback blocks so file
  existence checks and preview reads work correctly
- execution: remove now-dead customTools prefix remap loop (toolPrefix
  is always empty; the adapter handles renaming)
- architect-widget: extractAgentName now checks input.name alias before
  falling back to content frontmatter, matching agent_write's new 'name'
  parameter support
- anthropic-messages-adapter: add dist/extensions/index.js and
  dist/index.js to CANDIDATE_PATHS to cover compiled install layouts
…ntName redundancy

- flow-workspace: tc.input paths (from both flow_write and agent_write)
  are now resolved against projectRoot in both handleNewFlow and
  handleEditFlow, so existsSync/readFileSync in the preview loop work
  correctly when process.cwd() differs from projectRoot; also handle
  the 'name' alias alongside 'path' in both tool call extractors
- architect-widget: remove dead second branch in extractAgentName
  (stripped.includes('.') guard was unreachable — subsequent 'if
  (stripped)' would catch it anyway)
@ChicK00o ChicK00o changed the title fix: architect flow creation failures on Anthropic/proxy providers fix: architect subagent tool dispatch failures on Anthropic/proxy providers May 6, 2026
… adapter

- execution: fix <tool_call> recovery regex — non-greedy {[\s\S]*?} stops
  at the first } so nested JSON (e.g. files:[{path:...}]) was truncated;
  capture full tag content and let JSON.parse consume exactly one value
- anthropic-messages-adapter: restructure so import errors fall through to
  path candidates but a successful import that throws in mod.default(pi)
  propagates instead of being silently swallowed
- flow-workspace: extract identical toolCalls+finishParams collector from
  handleEditFlow and handleNewFlow into shared collectCreatedFiles() helper
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant