mirror of
https://github.com/claude-code-best/claude-code.git
synced 2026-06-22 08:15:53 +00:00
feat: Remote Control 条件工具注入 — PushNotification/SendUserFile/Brief 仅 bridge 启用时可用
- PushNotificationTool、SendUserFileTool 添加 isEnabled() 使用 isBridgeEnabled() - BriefTool 的 isEnabled() 从 isBriefEnabled() 改为 isBridgeEnabled() - ExecuteTool 添加 isEnabled() 兜底检查,不可用时返回友好错误 - useReplBridge bridge 首次连接时插入 system 消息通知模型新工具可用 - 移除 toolSearch 中 firstParty base URL 白名单检测,默认启用 tool search Co-Authored-By: glm-5.1[1m] <zai-org@claude-code-best.win>
This commit is contained in:
@@ -8,6 +8,7 @@ import { buildTool, type ToolDef } from 'src/Tool.js'
|
|||||||
import { isEnvTruthy } from 'src/utils/envUtils.js'
|
import { isEnvTruthy } from 'src/utils/envUtils.js'
|
||||||
import { lazySchema } from 'src/utils/lazySchema.js'
|
import { lazySchema } from 'src/utils/lazySchema.js'
|
||||||
import { plural } from 'src/utils/stringUtils.js'
|
import { plural } from 'src/utils/stringUtils.js'
|
||||||
|
import { isBridgeEnabled } from 'src/bridge/bridgeEnabled.js'
|
||||||
import { resolveAttachments, validateAttachmentPaths } from './attachments.js'
|
import { resolveAttachments, validateAttachmentPaths } from './attachments.js'
|
||||||
import {
|
import {
|
||||||
BRIEF_TOOL_NAME,
|
BRIEF_TOOL_NAME,
|
||||||
@@ -149,7 +150,7 @@ export const BriefTool = buildTool({
|
|||||||
return outputSchema()
|
return outputSchema()
|
||||||
},
|
},
|
||||||
isEnabled() {
|
isEnabled() {
|
||||||
return isBriefEnabled()
|
return isBridgeEnabled()
|
||||||
},
|
},
|
||||||
isConcurrencySafe() {
|
isConcurrencySafe() {
|
||||||
return true
|
return true
|
||||||
|
|||||||
@@ -74,6 +74,21 @@ export const ExecuteTool = buildTool({
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if the target tool is currently enabled
|
||||||
|
if (!targetTool.isEnabled()) {
|
||||||
|
return {
|
||||||
|
data: {
|
||||||
|
result: null,
|
||||||
|
tool_name: input.tool_name,
|
||||||
|
},
|
||||||
|
newMessages: [
|
||||||
|
createUserMessage({
|
||||||
|
content: `工具 "${input.tool_name}" 当前不可用:Remote Control 未连接。`,
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check permissions on the target tool
|
// Check permissions on the target tool
|
||||||
const permResult = await targetTool.checkPermissions?.(
|
const permResult = await targetTool.checkPermissions?.(
|
||||||
input.params as Record<string, unknown>,
|
input.params as Record<string, unknown>,
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import type { ToolResultBlockParam } from 'src/Tool.js'
|
|||||||
import { buildTool } from 'src/Tool.js'
|
import { buildTool } from 'src/Tool.js'
|
||||||
import { lazySchema } from 'src/utils/lazySchema.js'
|
import { lazySchema } from 'src/utils/lazySchema.js'
|
||||||
import { logForDebugging } from 'src/utils/debug.js'
|
import { logForDebugging } from 'src/utils/debug.js'
|
||||||
|
import { isBridgeEnabled } from 'src/bridge/bridgeEnabled.js'
|
||||||
|
|
||||||
const PUSH_NOTIFICATION_TOOL_NAME = 'PushNotification'
|
const PUSH_NOTIFICATION_TOOL_NAME = 'PushNotification'
|
||||||
|
|
||||||
@@ -48,6 +49,9 @@ Use this when:
|
|||||||
Requires Remote Control to be configured. Respects user notification settings (taskCompleteNotifEnabled, inputNeededNotifEnabled, agentPushNotifEnabled).`
|
Requires Remote Control to be configured. Respects user notification settings (taskCompleteNotifEnabled, inputNeededNotifEnabled, agentPushNotifEnabled).`
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isEnabled() {
|
||||||
|
return isBridgeEnabled()
|
||||||
|
},
|
||||||
isConcurrencySafe() {
|
isConcurrencySafe() {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ import type { ToolResultBlockParam } from 'src/Tool.js'
|
|||||||
import { buildTool } from 'src/Tool.js'
|
import { buildTool } from 'src/Tool.js'
|
||||||
import { lazySchema } from 'src/utils/lazySchema.js'
|
import { lazySchema } from 'src/utils/lazySchema.js'
|
||||||
import { SEND_USER_FILE_TOOL_NAME } from './prompt.js'
|
import { SEND_USER_FILE_TOOL_NAME } from './prompt.js'
|
||||||
|
import { isBridgeEnabled } from 'src/bridge/bridgeEnabled.js'
|
||||||
|
|
||||||
const inputSchema = lazySchema(() =>
|
const inputSchema = lazySchema(() =>
|
||||||
z.strictObject({
|
z.strictObject({
|
||||||
@@ -42,6 +43,9 @@ Guidelines:
|
|||||||
- Large files may take time to transfer`
|
- Large files may take time to transfer`
|
||||||
},
|
},
|
||||||
|
|
||||||
|
isEnabled() {
|
||||||
|
return isBridgeEnabled()
|
||||||
|
},
|
||||||
isConcurrencySafe() {
|
isConcurrencySafe() {
|
||||||
return true
|
return true
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -302,6 +302,7 @@ export function useReplBridge(
|
|||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case 'connected': {
|
case 'connected': {
|
||||||
|
const wasSessionActive = store.getState().replBridgeSessionActive;
|
||||||
setAppState(prev => {
|
setAppState(prev => {
|
||||||
if (prev.replBridgeSessionActive) return prev;
|
if (prev.replBridgeSessionActive) return prev;
|
||||||
return {
|
return {
|
||||||
@@ -312,6 +313,16 @@ export function useReplBridge(
|
|||||||
replBridgeError: undefined,
|
replBridgeError: undefined,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
// Notify model about newly available bridge-dependent tools
|
||||||
|
if (!wasSessionActive) {
|
||||||
|
setMessages(prev => [
|
||||||
|
...prev,
|
||||||
|
createSystemMessage(
|
||||||
|
'Remote Control 已连接。现在可以使用 PushNotification、SendUserFile、Brief 工具,请使用 ToolSearch 搜索发现。',
|
||||||
|
'info',
|
||||||
|
),
|
||||||
|
]);
|
||||||
|
}
|
||||||
// Send system/init so remote clients (web/iOS/Android) get
|
// Send system/init so remote clients (web/iOS/Android) get
|
||||||
// session metadata. REPL uses query() directly — never hits
|
// session metadata. REPL uses query() directly — never hits
|
||||||
// QueryEngine's SDKMessage layer — so this is the only path
|
// QueryEngine's SDKMessage layer — so this is the only path
|
||||||
|
|||||||
@@ -34,10 +34,6 @@ import { getMergedBetas } from './betas.js'
|
|||||||
import { getContextWindowForModel } from './context.js'
|
import { getContextWindowForModel } from './context.js'
|
||||||
import { logForDebugging } from './debug.js'
|
import { logForDebugging } from './debug.js'
|
||||||
import { isEnvDefinedFalsy, isEnvTruthy } from './envUtils.js'
|
import { isEnvDefinedFalsy, isEnvTruthy } from './envUtils.js'
|
||||||
import {
|
|
||||||
getAPIProvider,
|
|
||||||
isFirstPartyAnthropicBaseUrl,
|
|
||||||
} from './model/providers.js'
|
|
||||||
import { jsonStringify } from './slowOperations.js'
|
import { jsonStringify } from './slowOperations.js'
|
||||||
import { zodToJsonSchema } from './zodToJsonSchema.js'
|
import { zodToJsonSchema } from './zodToJsonSchema.js'
|
||||||
|
|
||||||
@@ -279,36 +275,10 @@ export function isToolSearchEnabledOptimistic(): boolean {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// tool_reference is a beta content type that third-party API gateways
|
// 此项目为逆向工程版本,用户均使用第三方代理(如 open.bigmodel.cn),
|
||||||
// (ANTHROPIC_BASE_URL proxies) typically don't support. When the provider
|
// 原版的 firstParty base URL 白名单检测会导致 tool search 默认禁用。
|
||||||
// is 'firstParty' but the base URL points elsewhere, the proxy will reject
|
// 移除该检测,默认启用 tool search。
|
||||||
// tool_reference blocks with a 400. Vertex/Bedrock/Foundry are unaffected —
|
// 用户仍可通过 ENABLE_TOOL_SEARCH=false 显式禁用。
|
||||||
// they have their own endpoints and beta headers.
|
|
||||||
// https://github.com/anthropics/claude-code/issues/30912
|
|
||||||
//
|
|
||||||
// HOWEVER: some proxies DO support tool_reference (LiteLLM passthrough,
|
|
||||||
// Cloudflare AI Gateway, corp gateways that forward beta headers). The
|
|
||||||
// blanket disable breaks defer_loading for those users — all MCP tools
|
|
||||||
// loaded into main context instead of on-demand (gh-31936 / CC-457,
|
|
||||||
// likely the real cause of CC-330 "v2.1.70 defer_loading regression").
|
|
||||||
// This gate only applies when ENABLE_TOOL_SEARCH is unset/empty (default
|
|
||||||
// behavior). Setting any non-empty value — 'true', 'auto', 'auto:N' —
|
|
||||||
// means the user is explicitly configuring tool search and asserts their
|
|
||||||
// setup supports it. The falsy check (rather than === undefined) aligns
|
|
||||||
// with getToolSearchMode(), which also treats "" as unset.
|
|
||||||
if (
|
|
||||||
!process.env.ENABLE_TOOL_SEARCH &&
|
|
||||||
getAPIProvider() === 'firstParty' &&
|
|
||||||
!isFirstPartyAnthropicBaseUrl()
|
|
||||||
) {
|
|
||||||
if (!loggedOptimistic) {
|
|
||||||
loggedOptimistic = true
|
|
||||||
logForDebugging(
|
|
||||||
`[ToolSearch:optimistic] disabled: ANTHROPIC_BASE_URL=${process.env.ANTHROPIC_BASE_URL} is not a first-party Anthropic host. Set ENABLE_TOOL_SEARCH=true (or auto / auto:N) if your proxy forwards tool_reference blocks.`,
|
|
||||||
)
|
|
||||||
}
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!loggedOptimistic) {
|
if (!loggedOptimistic) {
|
||||||
loggedOptimistic = true
|
loggedOptimistic = true
|
||||||
|
|||||||
Reference in New Issue
Block a user