Skip to content

refactor: split anthropic-transforms.js into focused sub-modules#3478

Merged
lpcox merged 4 commits into
mainfrom
copilot/refactor-anthropic-transforms
May 21, 2026
Merged

refactor: split anthropic-transforms.js into focused sub-modules#3478
lpcox merged 4 commits into
mainfrom
copilot/refactor-anthropic-transforms

Conversation

Copilot AI commented May 20, 2026

Copy link
Copy Markdown
Contributor

containers/api-proxy/anthropic-transforms.js (474 lines) bundled four unrelated concerns — ANSI stripping, cache breakpoint injection, ephemeral TTL upgrading, and tool dropping — making each harder to review and reuse in isolation.

Split

New file Moved functions
transforms/ansi-strip.js stripAnsi, applyAnsiStrip
transforms/cache-control.js withCacheControl, injectCacheBreakpoints, upgradeEphemeralTtl, MAX_CACHE_BREAKPOINTS, EXTENDED_CACHE_BETA
transforms/tool-drop.js buildToolScrubPattern, applyToolDrop

anthropic-transforms.js is now a ~183-line composition-only layer:

const { stripAnsi, applyAnsiStrip } = require('./transforms/ansi-strip');
const { injectCacheBreakpoints, upgradeEphemeralTtl, ... } = require('./transforms/cache-control');
const { buildToolScrubPattern, applyToolDrop } = require('./transforms/tool-drop');

Compatibility

All existing exports from anthropic-transforms.js are preserved via re-exports — no changes required to providers/anthropic.js or the test suite. ansi-strip.js is now also available for reuse by other provider adapters.

Move the four independent transform concerns out of the monolithic
anthropic-transforms.js into dedicated files under transforms/:

- transforms/ansi-strip.js    — stripAnsi, applyAnsiStrip (~70 lines)
- transforms/cache-control.js — withCacheControl, injectCacheBreakpoints,
                                 upgradeEphemeralTtl, MAX_CACHE_BREAKPOINTS,
                                 EXTENDED_CACHE_BETA (~195 lines)
- transforms/tool-drop.js     — buildToolScrubPattern, applyToolDrop (~73 lines)

anthropic-transforms.js is now a thin composition layer (~183 lines) that
imports from the sub-modules and retains loadCustomTransform +
makeAnthropicTransform.  All existing exports are preserved for backward
compatibility with providers/anthropic.js and the test suite.
Copilot AI changed the title [WIP] Refactor api-proxy transforms into focused modules refactor: split anthropic-transforms.js into focused sub-modules May 20, 2026
Copilot finished work on behalf of lpcox May 20, 2026 23:16
Copilot AI requested a review from lpcox May 20, 2026 23:16
@lpcox lpcox marked this pull request as ready for review May 20, 2026 23:54
Copilot AI review requested due to automatic review settings May 20, 2026 23:54
@github-actions

github-actions Bot commented May 20, 2026

Copy link
Copy Markdown
Contributor

✅ Coverage Check Passed

Overall Coverage

Metric Base PR Delta
Lines 95.73% 95.83% 📈 +0.10%
Statements 95.56% 95.65% 📈 +0.09%
Functions 96.86% 96.88% 📈 +0.02%
Branches 89.30% 89.34% 📈 +0.04%
📁 Per-file Coverage Changes (2 files)
File Lines (Before → After) Statements (Before → After)
src/config-writer.ts 83.0% → 85.6% (+2.54%) 83.0% → 85.6% (+2.54%)
src/commands/validate-options.ts 87.3% → 100.0% (+12.70%) 86.4% → 100.0% (+13.62%)
✨ New Files (4 files)
  • src/commands/validators/agent-options.ts: 93.0% lines
  • src/commands/validators/config-assembly.ts: 83.0% lines
  • src/commands/validators/log-and-limits.ts: 95.2% lines
  • src/commands/validators/network-options.ts: 81.3% lines

Coverage comparison generated by scripts/ci/compare-coverage.ts

Comment thread containers/api-proxy/anthropic-transforms.js Fixed
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copilot AI 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.

Pull request overview

This PR refactors the Anthropic request-body transform layer in containers/api-proxy by extracting previously bundled transform concerns (ANSI stripping, cache-control breakpoint/TTL logic, and tool dropping) into focused sub-modules, while keeping anthropic-transforms.js as a composition/re-export layer to preserve the existing public API.

Changes:

  • Added dedicated transform modules under containers/api-proxy/transforms/ for ANSI stripping, cache-control logic, and tool dropping.
  • Updated containers/api-proxy/anthropic-transforms.js to import from the new modules and re-export the same symbols as before.
Show a summary per file
File Description
containers/api-proxy/transforms/tool-drop.js New module for tool removal and system-prompt scrubbing utilities.
containers/api-proxy/transforms/cache-control.js New module containing cache breakpoint injection + ephemeral TTL upgrade logic and constants.
containers/api-proxy/transforms/ansi-strip.js New generic ANSI SGR stripping helper + body transform for tool_result blocks.
containers/api-proxy/anthropic-transforms.js Refactored into a composition/re-export layer that delegates to the new transform modules.

Copilot's findings

Tip

Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

  • Files reviewed: 4/4 changed files
  • Comments generated: 5

Comment on lines +27 to 36
const { stripAnsi, applyAnsiStrip } = require('./transforms/ansi-strip');
const {
withCacheControl,
injectCacheBreakpoints,
upgradeEphemeralTtl,
MAX_CACHE_BREAKPOINTS,
EXTENDED_CACHE_BETA,
} = require('./transforms/cache-control');
const { buildToolScrubPattern, applyToolDrop } = require('./transforms/tool-drop');

Comment on lines +76 to +86
// Slot 3: last block of messages[0]
const msgs = result.messages;
if (slotsUsed < MAX_CACHE_BREAKPOINTS &&
Array.isArray(msgs) && msgs.length > 0 &&
Array.isArray(msgs[0].content) && msgs[0].content.length > 0) {
const content = [...msgs[0].content];
content[content.length - 1] = withCacheControl(content[content.length - 1], { type: 'ephemeral', ttl: '1h' });
const messages = [...msgs];
messages[0] = { ...msgs[0], content };
result.messages = messages;
slotsUsed++;
Comment on lines +130 to +137
if (Array.isArray(body.messages)) {
outer: for (let i = body.messages.length - 1; i >= 0; i--) {
const msg = body.messages[i];
if (!Array.isArray(msg.content)) continue;
for (let j = msg.content.length - 1; j >= 0; j--) {
const b = msg.content[j];
if (b && b.cache_control && b.cache_control.type === 'ephemeral') {
tailMsgIdx = i;
Comment on lines +39 to +44
const messages = body.messages.map(msg => {
if (!Array.isArray(msg.content)) return msg;

const content = msg.content.map(block => {
if (block.type !== 'tool_result') return block;

Comment on lines +45 to +67
// Remove matching entries from the tools array
if (Array.isArray(result.tools)) {
const filtered = result.tools.filter(tool => !dropSet.has(tool.name));
if (filtered.length < result.tools.length) {
if (filtered.length === 0) {
result = { ...result };
delete result.tools;
} else {
result.tools = filtered;
}
}
}

// Scrub tool-name references from system-prompt text blocks.
// We remove bare occurrences; surrounding punctuation/whitespace is left intact
// to avoid corrupting sentence structure.
if (Array.isArray(result.system)) {
const pattern = scrubPattern || buildToolScrubPattern([...dropSet]);
result.system = result.system.map(block => {
if (block.type !== 'text' || typeof block.text !== 'string') return block;
const scrubbed = block.text.replace(pattern, '');
return scrubbed === block.text ? block : { ...block, text: scrubbed };
});
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ort, function or class'

Co-authored-by: Copilot Autofix powered by AI <62310815+github-advanced-security[bot]@users.noreply.github.com>
@lpcox

lpcox commented May 21, 2026

Copy link
Copy Markdown
Collaborator

@copilot address review feedback

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Copilot AI commented May 21, 2026

Copy link
Copy Markdown
Contributor Author

@copilot address review feedback

Addressed in be36ece.

  • Added null/type guards in applyAnsiStrip, injectCacheBreakpoints, upgradeEphemeralTtl, and applyToolDrop to safely handle malformed array entries.
  • Updated containers/api-proxy/Dockerfile to include transforms/ so split modules are present in the image.
  • Added regression tests for malformed messages/tools/system entries.
  • Ran containers/api-proxy test suite (23/23 passing) and CodeQL scan (0 alerts).

Copilot finished work on behalf of lpcox May 21, 2026 00:25
@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results

  • ✅ GitHub API: 2 PR entries confirmed in recent-prs.json
  • ✅ Playwright: GitHub.com title contains "GitHub"
  • ✅ File verify: smoke-test-claude-26197870732.txt exists

Result: PASS

💥 [THE END] — Illustrated by Smoke Claude

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test: Copilot BYOK (Offline) Mode

Test Result
GitHub MCP connectivity
GitHub.com HTTP ⚠️ template vars not expanded
File write/read ⚠️ template vars not expanded
BYOK inference (this response)

Running in BYOK offline mode (COPILOT_OFFLINE=true) via api-proxy → api.githubcopilot.com

Author: @Copilot · Assignees: @lpcox, @Copilot

Overall: PARTIAL — BYOK inference path ✅, pre-step outputs not injected into prompt.

🔑 BYOK report filed by Smoke Copilot BYOK

@github-actions

Copy link
Copy Markdown
Contributor

🔍 Smoke Test Results

Test Status
GitHub MCP connectivity ✅ (fetched PR #3488: "fix: align OTEL attributes with gen_ai semconv spec")
GitHub.com HTTP connectivity ⚠️ pre-step data unavailable (template not expanded)
File write/read ⚠️ pre-step data unavailable (template not expanded)

Overall: PARTIAL — MCP confirmed working; pre-step outputs were not expanded.

cc @lpcox (author & assignee), @Copilot (assignee)

📰 BREAKING: Report filed by Smoke Copilot

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test

Merged PRs: fix: flatten OTEL cache attribute names for Sentry compatibility; fix: align OTEL attributes with gen_ai semconv spec
Queried PRs: refactor: extract useCleanupTestDir to eliminate repeated test boilerplate; refactor: split anthropic-transforms.js into focused sub-modules
✅ GitHub PR review, Playwright, file/bash, build
❌ safeinputs-gh unavailable, Tavily unavailable, discussion query unavailable
Overall status: FAIL

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • registry.npmjs.org

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "registry.npmjs.org"

See Network Configuration for more information.

🔮 The oracle has spoken through Smoke Codex

@github-actions

Copy link
Copy Markdown
Contributor

🔬 Smoke Test: API Proxy OpenTelemetry Tracing

Scenario Result Notes
S1: Module Loading otel.js loads cleanly; exports: startRequestSpan, setTokenAttributes, endSpan, endSpanError, shutdown, isEnabled + internal helpers
S2: Test Suite ⏳ Expected-pending No OTEL-specific Jest tests exist yet (no .test.ts matches otel); normal during development
S3: Env Var Forwarding src/services/api-proxy-service.ts forwards OTEL_EXPORTER_OTLP_ENDPOINT, OTEL_EXPORTER_OTLP_HEADERS, OTEL_SERVICE_NAME, GITHUB_AW_OTEL_TRACE_ID, GITHUB_AW_OTEL_PARENT_SPAN_ID
S4: Token Tracker Integration onUsage callback present in token-tracker-http.js (line 232); invoked after normalized usage extraction
S5: OTEL Diagnostics No OTLP endpoint configured in this run; file fallback path (/var/log/api-proxy/otel.jsonl) available; graceful degradation confirmed

Overall: ✅ All scenarios pass or are expected-pending during development.

📡 OTel tracing validated by Smoke OTel Tracing

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results: Gemini

  • GitHub MCP Testing: ❌ (mcpscripts command not found)
  • GitHub.com Connectivity: ❌ (HTTP 000, Exit 35)
  • File Writing Testing: ✅
  • Bash Tool Testing: ✅

Overall Status: FAIL

Warning

Firewall blocked 1 domain

The following domain was blocked by the firewall during workflow execution:

  • localhost

To allow these domains, add them to the network.allowed list in your workflow frontmatter:

network:
  allowed:
    - defaults
    - "localhost"

See Network Configuration for more information.

💎 Faceted by Smoke Gemini

@github-actions

Copy link
Copy Markdown
Contributor

Chroot Version Comparison Results

Runtime Host Version Chroot Version Match?
Python Python 3.12.13 Python 3.12.3
Node.js v24.15.0 v22.22.3
Go go1.22.12 go1.22.12

Overall: ❌ Not all tests passed — Python and Node.js versions differ between host and chroot environments.

Tested by Smoke Chroot

@github-actions

Copy link
Copy Markdown
Contributor

🏗️ Build Test Suite Results

Ecosystem Project Build/Install Tests Status
Bun elysia 1/1 passed ✅ PASS
Bun hono 1/1 passed ✅ PASS
C++ fmt N/A ✅ PASS
C++ json N/A ✅ PASS
Deno oak N/A 1/1 passed ✅ PASS
Deno std N/A 1/1 passed ✅ PASS
.NET hello-world N/A ✅ PASS
.NET json-parse N/A ✅ PASS
Go color 1/1 passed ✅ PASS
Go env 1/1 passed ✅ PASS
Go uuid 1/1 passed ✅ PASS
Java gson 1/1 passed ✅ PASS
Java caffeine 1/1 passed ✅ PASS
Node.js clsx All passed ✅ PASS
Node.js execa All passed ✅ PASS
Node.js p-limit All passed ✅ PASS
Rust fd 1/1 passed ✅ PASS
Rust zoxide 1/1 passed ✅ PASS

Overall: 8/8 ecosystems passed — ✅ PASS

Generated by Build Test Suite for issue #3478 · ● 7M ·

@github-actions

Copy link
Copy Markdown
Contributor

Smoke Test Results — FAIL

Check Result
Redis PING ❌ Timeout (no response)
PostgreSQL pg_isready ❌ No response
PostgreSQL SELECT 1 ❌ Timeout

Overall: FAILhost.docker.internal is unreachable from this runner. Service containers are not accessible.

🔌 Service connectivity validated by Smoke Services

@lpcox lpcox merged commit 16b972b into main May 21, 2026
69 of 72 checks passed
@lpcox lpcox deleted the copilot/refactor-anthropic-transforms branch May 21, 2026 00:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Refactoring] Split containers/api-proxy/anthropic-transforms.js into focused transform modules

4 participants