Files
claude-code/src/utils/systemPrompt.ts
claude-code-best 2fb1c9dcd8 feat: 工具层及 mcp 大重构 (#252)
* feat: 第一版大重构

* fix: 修复类型问题

* chore: 更新版本到 1.3.2

* Add brave as alternative WebSearchTool

* fix: 修正顺序

* fix: 修复对穷鬼模式的 auto dream 和 session memory 越过

* feat: 穷鬼模式去除 session-summary

* feat: 创建 builtin-tools 包,搬运所有工具实现

将 src/tools/ 下的全部 60 个工具目录迁移至 packages/builtin-tools/src/tools/,
内部导入路径已更新为 src/ alias 模式。

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 更新 src/ 中所有工具引用至 builtin-tools 包,删除 src/tools/

- src/tools.ts 及 178 个 src/ 文件的 import 路径从 ./tools/ 改为 builtin-tools/tools/
- 删除 src/tools/ 整个目录(已迁移至 packages/builtin-tools/)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* chore: 添加 builtin-tools 路径别名至 tsconfig,更新 bun.lock

- tsconfig.json 新增 builtin-tools/* 和 builtin-tools 路径映射
- 新增 packages/builtin-tools/src 至 include

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* refactor: 为 builtin-tools、mcp-client、agent-tools 添加 @claude-code-best 作用域前缀

所有包名及 import 路径统一添加 @claude-code-best/ 前缀:
- builtin-tools → @claude-code-best/builtin-tools
- mcp-client → @claude-code-best/mcp-client
- agent-tools → @claude-code-best/agent-tools

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>

* fix: 修复 node 环境没有 bun 的问题

---------

Co-authored-by: Eric-Guo <eric.guocz@gmail.com>
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-13 09:52:05 +08:00

124 lines
4.8 KiB
TypeScript

import { feature } from 'bun:bundle'
import {
type AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
logEvent,
} from '../services/analytics/index.js'
import type { ToolUseContext } from '../Tool.js'
import type { AgentDefinition } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
import { isBuiltInAgent } from '@claude-code-best/builtin-tools/tools/AgentTool/loadAgentsDir.js'
import { isEnvTruthy } from './envUtils.js'
import { asSystemPrompt, type SystemPrompt } from './systemPromptType.js'
export { asSystemPrompt, type SystemPrompt } from './systemPromptType.js'
// Dead code elimination: conditional import for proactive mode.
// Same pattern as prompts.ts — lazy require to avoid pulling the module
// into non-proactive builds.
/* eslint-disable @typescript-eslint/no-require-imports */
const proactiveModule =
feature('PROACTIVE') || feature('KAIROS')
? (require('../proactive/index.js') as typeof import('../proactive/index.js'))
: null
/* eslint-enable @typescript-eslint/no-require-imports */
function isProactiveActive_SAFE_TO_CALL_ANYWHERE(): boolean {
return proactiveModule?.isProactiveActive() ?? false
}
/**
* Builds the effective system prompt array based on priority:
* 0. Override system prompt (if set, e.g., via loop mode - REPLACES all other prompts)
* 1. Coordinator system prompt (if coordinator mode is active)
* 2. Agent system prompt (if mainThreadAgentDefinition is set)
* - In proactive mode: agent prompt is APPENDED to default (agent adds domain
* instructions on top of the autonomous agent prompt, like teammates do)
* - Otherwise: agent prompt REPLACES default
* 3. Custom system prompt (if specified via --system-prompt)
* 4. Default system prompt (the standard Claude Code prompt)
*
* Plus appendSystemPrompt is always added at the end if specified (except when override is set).
*/
export function buildEffectiveSystemPrompt({
mainThreadAgentDefinition,
toolUseContext,
customSystemPrompt,
defaultSystemPrompt,
appendSystemPrompt,
overrideSystemPrompt,
}: {
mainThreadAgentDefinition: AgentDefinition | undefined
toolUseContext: Pick<ToolUseContext, 'options'>
customSystemPrompt: string | undefined
defaultSystemPrompt: string[]
appendSystemPrompt: string | undefined
overrideSystemPrompt?: string | null
}): SystemPrompt {
if (overrideSystemPrompt) {
return asSystemPrompt([overrideSystemPrompt])
}
// Coordinator mode: use coordinator prompt instead of default
// Use inline env check instead of coordinatorModule to avoid circular
// dependency issues during test module loading.
if (
feature('COORDINATOR_MODE') &&
isEnvTruthy(process.env.CLAUDE_CODE_COORDINATOR_MODE) &&
!mainThreadAgentDefinition
) {
// Lazy require to avoid circular dependency at module load time
const { getCoordinatorSystemPrompt } =
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('../coordinator/coordinatorMode.js') as typeof import('../coordinator/coordinatorMode.js')
return asSystemPrompt([
getCoordinatorSystemPrompt(),
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}
const agentSystemPrompt = mainThreadAgentDefinition
? isBuiltInAgent(mainThreadAgentDefinition)
? mainThreadAgentDefinition.getSystemPrompt({
toolUseContext: { options: toolUseContext.options },
})
: mainThreadAgentDefinition.getSystemPrompt()
: undefined
// Log agent memory loaded event for main loop agents
if (mainThreadAgentDefinition?.memory) {
logEvent('tengu_agent_memory_loaded', {
...(process.env.USER_TYPE === 'ant' && {
agent_type:
mainThreadAgentDefinition.agentType as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
}),
scope:
mainThreadAgentDefinition.memory as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
source:
'main-thread' as AnalyticsMetadata_I_VERIFIED_THIS_IS_NOT_CODE_OR_FILEPATHS,
})
}
// In proactive mode, agent instructions are appended to the default prompt
// rather than replacing it. The proactive default prompt is already lean
// (autonomous agent identity + memory + env + proactive section), and agents
// add domain-specific behavior on top — same pattern as teammates.
if (
agentSystemPrompt &&
(feature('PROACTIVE') || feature('KAIROS')) &&
isProactiveActive_SAFE_TO_CALL_ANYWHERE()
) {
return asSystemPrompt([
...defaultSystemPrompt,
`\n# Custom Agent Instructions\n${agentSystemPrompt}`,
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}
return asSystemPrompt([
...(agentSystemPrompt
? [agentSystemPrompt]
: customSystemPrompt
? [customSystemPrompt]
: defaultSystemPrompt),
...(appendSystemPrompt ? [appendSystemPrompt] : []),
])
}