Skip to content

fix(amp): preserve tool calls in proxied streams - #2766

Closed
edlsh wants to merge 2 commits into
router-for-me:devfrom
edlsh:fix/amp-glob-tool-casing
Closed

edlsh wants to merge 2 commits into
router-for-me:devfrom
edlsh:fix/amp-glob-tool-casing

Conversation

@edlsh

@edlsh edlsh commented Apr 13, 2026 •

Copy link
Copy Markdown
Contributor

Summary

  • normalize known Amp tool names in rewritten responses
  • preserve the lowercase glob name that Amp expects instead of rewriting it to Glob
  • repair OpenAI Responses SSE completions whose final response.output is empty even though response.output_item.done already streamed tool-call items
  • preserve streamed function_call.name and arguments in repaired response.completed.response.output so Amp can normalize and execute the tool call
  • add regression coverage for both tool-name normalization and empty completed output repair

Root Cause

Amp deep GPT/Codex mode could receive a completed Responses stream where the tool call appeared in streamed response.output_item.done events, but the final response.completed.response.output was []. Amp then dropped the tool use during normalization because the completed output no longer carried the named call, making the CLI look stuck after the model responded.

Testing

  • go test ./sdk/api/handlers/openai
  • go build -o /tmp/cliproxyapi-amp-glob-fixed ./cmd/server
  • live localhost /v1/responses forced-tool smoke test returned a completed output containing function_call name shell and args {"cmd":"pwd"}

Notes

  • Local go test ./... still has unrelated existing failures in internal/api/modules/amp and internal/runtime/executor due local/global config state and Claude executor expectations.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces tool name normalization to ensure compatibility with Amp's case-sensitive tool whitelist. It adds a mapping of canonical tool names and a function to update tool names in both streaming and non-streaming API responses. Unit tests were added to verify the normalization logic. Feedback was provided regarding an optimization in the streaming logic to reduce redundant JSON parsing when accessing content_block fields.

Comment on lines +158 to +160
if gjson.GetBytes(data, "content_block.type").String() == "tool_use" {
name := gjson.GetBytes(data, "content_block.name").String()
if canonical, ok := ampCanonicalToolNames[strings.ToLower(name)]; ok && name != canonical {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The code performs redundant JSON parsing by calling gjson.GetBytes twice for the same content_block object. It is more efficient to retrieve the content_block once and then use Get on the resulting gjson.Result to access its fields. This is particularly relevant in streaming mode where this logic is executed for every chunk.

	// Streaming: content_block.name in content_block_start events
	contentBlock := gjson.GetBytes(data, "content_block")
	if contentBlock.Get("type").String() == "tool_use" {
		name := contentBlock.Get("name").String()

@luispater luispater left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Summary

This PR normalizes known Amp tool names in rewritten Anthropic-style responses, while explicitly preserving the lowercase glob tool name that Amp expects. It adds focused unit coverage for normalized and untouched tool names.

Key findings

  • Correctness: Normalization is applied to both non-streaming content[].name tool_use blocks and streaming content_block_start (content_block.name).
  • Compatibility: glob remains lowercase (and mixed/upper-case variants will normalize to glob).
  • Safety: Unknown tool names are left untouched.

Test plan

  • Not run locally (per review constraints; no PR checkout).
  • CI is green; PR description reports running:
    • go test ./internal/api/modules/amp
    • go test ./...
    • go build -o test-output ./cmd/server && rm test-output

Non-blocking suggestion

  • Add a unit test asserting Glob/GLOB becomes glob to lock in the key casing nuance.

This is an automated Codex review result and still requires manual verification by a human reviewer.

@edlsh edlsh changed the title fix(amp): preserve lowercase glob tool name fix(amp): preserve tool calls in proxied streams Apr 24, 2026
@edlsh

edlsh commented Apr 25, 2026

Copy link
Copy Markdown
Contributor Author

Consolidated into #2896 (which now contains both the glob lowercase tool casing fix and the openai responses deep-mode repair).

@edlsh edlsh closed this Apr 25, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants