fix: remove internal Anthropic tooling from external build (#345)
Remove debug systems, employee detection, and internal logging that have no function in a community fork. Changes: - Remove logPermissionContextForAnts import and calls (main.tsx, compact.ts) Reads Kubernetes namespace and container IDs from internal infra paths. Dead code for all external users. - Remove createDumpPromptsFetch import and gate (query.ts) Internal prompt dump system for employee debugging. Replace gate with unconditional undefined — normal fetch always used. - Remove stripSignatureBlocks ant-only block (query.ts) Was behind USER_TYPE === 'ant' guard, never ran for external users. - Hardcode isAnt: false (query/config.ts) Employee detection flag has no place in a community fork. config.gates.isAnt had exactly one consumer (dumpPromptsFetch, now removed). - Gut logClassifierResultForAnts body (bashPermissions.ts) Replace with empty no-op. Still called from 4 sites, zero execution. Remove ANT-ONLY comments describing internal security model. - Gate status.anthropic.com behind firstParty check (errors.ts) 429 error hint now only shown when using Anthropic directly. Third-party provider users see a generic capacity message. Build: passes Typecheck: clean (no new errors) Tests: 196 pass, same 6 pre-existing failures unrelated to these changes
This commit is contained in:
@@ -142,7 +142,6 @@ import { validateUuid } from './utils/uuid.js';
|
|||||||
import { registerMcpAddCommand } from 'src/commands/mcp/addCommand.js';
|
import { registerMcpAddCommand } from 'src/commands/mcp/addCommand.js';
|
||||||
import { registerMcpDoctorCommand } from 'src/commands/mcp/doctorCommand.js';
|
import { registerMcpDoctorCommand } from 'src/commands/mcp/doctorCommand.js';
|
||||||
import { registerMcpXaaIdpCommand } from 'src/commands/mcp/xaaIdpCommand.js';
|
import { registerMcpXaaIdpCommand } from 'src/commands/mcp/xaaIdpCommand.js';
|
||||||
import { logPermissionContextForAnts } from 'src/services/internalLogging.js';
|
|
||||||
import { fetchClaudeAIMcpConfigsIfEligible } from 'src/services/mcp/claudeai.js';
|
import { fetchClaudeAIMcpConfigsIfEligible } from 'src/services/mcp/claudeai.js';
|
||||||
import { clearServerCache } from 'src/services/mcp/client.js';
|
import { clearServerCache } from 'src/services/mcp/client.js';
|
||||||
import { areMcpConfigsAllowedWithEnterpriseMcpConfig, dedupClaudeAiMcpServers, doesEnterpriseMcpConfigExist, filterMcpServersByPolicy, getClaudeCodeMcpConfigs, getMcpServerSignature, parseMcpConfig, parseMcpConfigFromFilePath } from 'src/services/mcp/config.js';
|
import { areMcpConfigsAllowedWithEnterpriseMcpConfig, dedupClaudeAiMcpServers, doesEnterpriseMcpConfigExist, filterMcpServersByPolicy, getClaudeCodeMcpConfigs, getMcpServerSignature, parseMcpConfig, parseMcpConfigFromFilePath } from 'src/services/mcp/config.js';
|
||||||
@@ -2511,7 +2510,6 @@ async function run(): Promise<CommanderCommand> {
|
|||||||
|
|
||||||
// Log context metrics once at initialization
|
// Log context metrics once at initialization
|
||||||
void logContextMetrics(regularMcpConfigs, toolPermissionContext);
|
void logContextMetrics(regularMcpConfigs, toolPermissionContext);
|
||||||
void logPermissionContextForAnts(null, 'initialization');
|
|
||||||
logManagedSettings();
|
logManagedSettings();
|
||||||
|
|
||||||
// Register PID file for concurrent-session detection (~/.claude/sessions/)
|
// Register PID file for concurrent-session detection (~/.claude/sessions/)
|
||||||
|
|||||||
13
src/query.ts
13
src/query.ts
@@ -52,7 +52,6 @@ import {
|
|||||||
getMessagesAfterCompactBoundary,
|
getMessagesAfterCompactBoundary,
|
||||||
createToolUseSummaryMessage,
|
createToolUseSummaryMessage,
|
||||||
createMicrocompactBoundaryMessage,
|
createMicrocompactBoundaryMessage,
|
||||||
stripSignatureBlocks,
|
|
||||||
} from './utils/messages.js'
|
} from './utils/messages.js'
|
||||||
import { generateToolUseSummary } from './services/toolUseSummary/toolUseSummaryGenerator.js'
|
import { generateToolUseSummary } from './services/toolUseSummary/toolUseSummaryGenerator.js'
|
||||||
import { prependUserContext, appendSystemContext } from './utils/api.js'
|
import { prependUserContext, appendSystemContext } from './utils/api.js'
|
||||||
@@ -92,7 +91,6 @@ import { SLEEP_TOOL_NAME } from './tools/SleepTool/prompt.js'
|
|||||||
import { executePostSamplingHooks } from './utils/hooks/postSamplingHooks.js'
|
import { executePostSamplingHooks } from './utils/hooks/postSamplingHooks.js'
|
||||||
import { executeStopFailureHooks } from './utils/hooks.js'
|
import { executeStopFailureHooks } from './utils/hooks.js'
|
||||||
import type { QuerySource } from './constants/querySource.js'
|
import type { QuerySource } from './constants/querySource.js'
|
||||||
import { createDumpPromptsFetch } from './services/api/dumpPrompts.js'
|
|
||||||
import { StreamingToolExecutor } from './services/tools/StreamingToolExecutor.js'
|
import { StreamingToolExecutor } from './services/tools/StreamingToolExecutor.js'
|
||||||
import { queryCheckpoint } from './utils/queryProfiler.js'
|
import { queryCheckpoint } from './utils/queryProfiler.js'
|
||||||
import { runTools } from './services/tools/toolOrchestration.js'
|
import { runTools } from './services/tools/toolOrchestration.js'
|
||||||
@@ -587,13 +585,7 @@ async function* queryLoop(
|
|||||||
|
|
||||||
// Create fetch wrapper once per query session to avoid memory retention.
|
// Create fetch wrapper once per query session to avoid memory retention.
|
||||||
// Each call to createDumpPromptsFetch creates a closure that captures the request body.
|
// Each call to createDumpPromptsFetch creates a closure that captures the request body.
|
||||||
// Creating it once means only the latest request body is retained (~700KB),
|
const dumpPromptsFetch = undefined
|
||||||
// instead of all request bodies from the session (~500MB for long sessions).
|
|
||||||
// Note: agentId is effectively constant during a query() call - it only changes
|
|
||||||
// between queries (e.g., /clear command or session resume).
|
|
||||||
const dumpPromptsFetch = config.gates.isAnt
|
|
||||||
? createDumpPromptsFetch(toolUseContext.agentId ?? config.sessionId)
|
|
||||||
: undefined
|
|
||||||
|
|
||||||
// Block if we've hit the hard blocking limit (only applies when auto-compact is OFF)
|
// Block if we've hit the hard blocking limit (only applies when auto-compact is OFF)
|
||||||
// This reserves space so users can still run /compact manually
|
// This reserves space so users can still run /compact manually
|
||||||
@@ -931,9 +923,6 @@ async function* queryLoop(
|
|||||||
// Thinking signatures are model-bound: replaying a protected-thinking
|
// Thinking signatures are model-bound: replaying a protected-thinking
|
||||||
// block (e.g. capybara) to an unprotected fallback (e.g. opus) 400s.
|
// block (e.g. capybara) to an unprotected fallback (e.g. opus) 400s.
|
||||||
// Strip before retry so the fallback model gets clean history.
|
// Strip before retry so the fallback model gets clean history.
|
||||||
if (process.env.USER_TYPE === 'ant') {
|
|
||||||
messagesForQuery = stripSignatureBlocks(messagesForQuery)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log the fallback event
|
// Log the fallback event
|
||||||
logEvent('tengu_model_fallback_triggered', {
|
logEvent('tengu_model_fallback_triggered', {
|
||||||
|
|||||||
@@ -36,7 +36,7 @@ export function buildQueryConfig(): QueryConfig {
|
|||||||
emitToolUseSummaries: isEnvTruthy(
|
emitToolUseSummaries: isEnvTruthy(
|
||||||
process.env.CLAUDE_CODE_EMIT_TOOL_USE_SUMMARIES,
|
process.env.CLAUDE_CODE_EMIT_TOOL_USE_SUMMARIES,
|
||||||
),
|
),
|
||||||
isAnt: process.env.USER_TYPE === 'ant',
|
isAnt: false,
|
||||||
// Inlined from fastMode.ts to avoid pulling its heavy module graph
|
// Inlined from fastMode.ts to avoid pulling its heavy module graph
|
||||||
// (axios, settings, auth, model, oauth, config) into test shards that
|
// (axios, settings, auth, model, oauth, config) into test shards that
|
||||||
// didn't previously load it — changes init order and breaks unrelated tests.
|
// didn't previously load it — changes init order and breaks unrelated tests.
|
||||||
|
|||||||
@@ -558,7 +558,7 @@ export function getAssistantMessageFromError(
|
|||||||
const innerMessage = stripped.match(/"message"\s*:\s*"([^"]*)"/)?.[1]
|
const innerMessage = stripped.match(/"message"\s*:\s*"([^"]*)"/)?.[1]
|
||||||
const detail = innerMessage || stripped
|
const detail = innerMessage || stripped
|
||||||
return createAssistantAPIErrorMessage({
|
return createAssistantAPIErrorMessage({
|
||||||
content: `${API_ERROR_MESSAGE_PREFIX}: Request rejected (429) · ${detail || 'this may be a temporary capacity issue — check status.anthropic.com'}`,
|
content: `${API_ERROR_MESSAGE_PREFIX}: Request rejected (429) · ${detail || `this may be a temporary capacity issue${getAPIProvider() === 'firstParty' ? ' — check status.anthropic.com' : ''}`}`,
|
||||||
error: 'rate_limit',
|
error: 'rate_limit',
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,7 +107,6 @@ import {
|
|||||||
} from '../api/errors.js'
|
} from '../api/errors.js'
|
||||||
import { notifyCompaction } from '../api/promptCacheBreakDetection.js'
|
import { notifyCompaction } from '../api/promptCacheBreakDetection.js'
|
||||||
import { getRetryDelay } from '../api/withRetry.js'
|
import { getRetryDelay } from '../api/withRetry.js'
|
||||||
import { logPermissionContextForAnts } from '../internalLogging.js'
|
|
||||||
import {
|
import {
|
||||||
roughTokenCountEstimation,
|
roughTokenCountEstimation,
|
||||||
roughTokenCountEstimationForMessages,
|
roughTokenCountEstimationForMessages,
|
||||||
@@ -401,7 +400,6 @@ export async function compactConversation(
|
|||||||
const preCompactTokenCount = tokenCountWithEstimation(messages)
|
const preCompactTokenCount = tokenCountWithEstimation(messages)
|
||||||
|
|
||||||
const appState = context.getAppState()
|
const appState = context.getAppState()
|
||||||
void logPermissionContextForAnts(appState.toolPermissionContext, 'summary')
|
|
||||||
|
|
||||||
context.onCompactProgress?.({
|
context.onCompactProgress?.({
|
||||||
type: 'hooks_start',
|
type: 'hooks_start',
|
||||||
|
|||||||
@@ -110,37 +110,16 @@ export const MAX_SUBCOMMANDS_FOR_SECURITY_CHECK = 50
|
|||||||
export const MAX_SUGGESTED_RULES_FOR_COMPOUND = 5
|
export const MAX_SUGGESTED_RULES_FOR_COMPOUND = 5
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [ANT-ONLY] Log classifier evaluation results for analysis.
|
* Log classifier evaluation results for analysis.
|
||||||
* This helps us understand which classifier rules are being evaluated
|
* No-op in external builds.
|
||||||
* and how the classifier is deciding on commands.
|
|
||||||
*/
|
*/
|
||||||
function logClassifierResultForAnts(
|
function logClassifierResultForAnts(
|
||||||
command: string,
|
_command: string,
|
||||||
behavior: ClassifierBehavior,
|
_behavior: ClassifierBehavior,
|
||||||
descriptions: string[],
|
_descriptions: string[],
|
||||||
result: ClassifierResult,
|
_result: ClassifierResult,
|
||||||
): void {
|
): void {
|
||||||
if (process.env.USER_TYPE !== 'ant') {
|
// Internal-only logging removed from external build.
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
logEvent('tengu_internal_bash_classifier_result', {
|
|
||||||
behavior:
|
|
||||||
behavior as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
descriptions: jsonStringify(
|
|
||||||
descriptions,
|
|
||||||
) as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
matches: result.matches,
|
|
||||||
matchedDescription: (result.matchedDescription ??
|
|
||||||
'') as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
confidence:
|
|
||||||
result.confidence as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
reason:
|
|
||||||
result.reason as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
// Note: command contains code/filepaths - this is ANT-ONLY so it's OK
|
|
||||||
command:
|
|
||||||
command as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -430,13 +409,11 @@ const SAFE_ENV_VARS = new Set([
|
|||||||
])
|
])
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ANT-ONLY environment variables that are safe to strip from commands.
|
* Environment variables that are safe to strip from commands.
|
||||||
* These are only enabled when USER_TYPE === 'ant'.
|
|
||||||
*
|
*
|
||||||
* SECURITY: These env vars are stripped before permission-rule matching, which
|
* SECURITY: These env vars are stripped before permission-rule matching, which
|
||||||
* means `DOCKER_HOST=tcp://evil.com docker ps` matches a `Bash(docker ps:*)`
|
* means `DOCKER_HOST=tcp://evil.com docker ps` matches a `Bash(docker ps:*)`
|
||||||
* rule after stripping. This is INTENTIONALLY ANT-ONLY (gated at line ~380)
|
* rule after stripping. DOCKER_HOST redirects the Docker
|
||||||
* and MUST NEVER ship to external users. DOCKER_HOST redirects the Docker
|
|
||||||
* daemon endpoint — stripping it defeats prefix-based permission restrictions
|
* daemon endpoint — stripping it defeats prefix-based permission restrictions
|
||||||
* by hiding the network endpoint from the permission check. KUBECONFIG
|
* by hiding the network endpoint from the permission check. KUBECONFIG
|
||||||
* similarly controls which cluster kubectl talks to. These are convenience
|
* similarly controls which cluster kubectl talks to. These are convenience
|
||||||
|
|||||||
Reference in New Issue
Block a user