fix: architect subagent tool dispatch failures on Anthropic/proxy providers#9
Open
ChicK00o wants to merge 4 commits into
Open
fix: architect subagent tool dispatch failures on Anthropic/proxy providers#9ChicK00o wants to merge 4 commits into
ChicK00o wants to merge 4 commits into
Conversation
## 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)
… 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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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, andfinishwere 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
CreateAgentSessionOptions.toolsexpectsstring[]for built-ins, notToolDefinition[]. Passing objects caused the SDK to silently drop all tools from the request.allowedToolNamesfilter was strippingagent_write,flow_write, andfinishbecause only built-in names were included. Custom tool names are now added to the allowlist.pi-anthropic-messagesadapter builds its inbound name→tool map from the main session'sgetAllTools(). 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.projectRootresolution:process.cwd()pointed to pi's install directory. A newresolveProjectRoot()walks up from cwd to find the nearest.git, falling back to~/.pioutside any repo.agent_write/flow_write: Paths are now resolved againstprojectRootbefore validation, so all response branches return the same absolute path. Bare names (e.g.my-agent) are auto-expanded to their staging path.finishas plain text: When the model hitsmax_tokensmid-turn,finishappears as a text<tool_call>block. Bothexecution.tsandflow-workspacenow recover from this.mcp__prefix in tool name comparisons: Switch statements and toolCall extractors inflow-workspaceandarchitect-widgetnow strip themcp__<ns>__prefix before comparing, and resolve extracted paths againstprojectRootfor correctexistsSync/readFileSyncbehaviour.@pi/anthropic-messagesfalls back to known on-disk paths including compileddist/layouts.find/lsmissing fromCORE_TOOL_NAMES: These built-ins were being incorrectly prefixed.