@@ -183,73 +183,120 @@ export class MessageBus extends EventEmitter {
183183 super();
184184 }
185185
186- // 发布消息
186+ // 发布消息(带完整错误处理)
187187 async publish(message: Message): Promise<void> {
188- if (!this.isValidMessage(message)) {
189- throw new Error(\`Invalid message structure\`);
190- }
191-
192- if (message.type === MessageBusType.TOOL_CONFIRMATION_REQUEST) {
193- // 工具确认请求:先经过 Policy 检查
194- const { decision } = await this.policyEngine.check(
195- message.toolCall,
196- message.serverName,
197- );
188+ try {
189+ if (!this.isValidMessage(message)) {
190+ throw new Error(\`Invalid message structure: \${safeJsonStringify(message)}\`);
191+ }
198192
199- switch (decision) {
200- case PolicyDecision.ALLOW:
201- this.emitMessage({
202- type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
203- correlationId: message.correlationId,
204- confirmed: true,
205- });
206- break;
193+ if (message.type === MessageBusType.TOOL_CONFIRMATION_REQUEST) {
194+ // 工具确认请求:先经过 Policy 检查
195+ const { decision } = await this.policyEngine.check(
196+ message.toolCall,
197+ message.serverName,
198+ );
199+
200+ switch (decision) {
201+ case PolicyDecision.ALLOW:
202+ this.emitMessage({
203+ type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
204+ correlationId: message.correlationId,
205+ confirmed: true,
206+ });
207+ break;
208+
209+ case PolicyDecision.DENY:
210+ this.emitMessage({
211+ type: MessageBusType.TOOL_POLICY_REJECTION,
212+ toolCall: message.toolCall,
213+ });
214+ this.emitMessage({
215+ type: MessageBusType.TOOL_CONFIRMATION_RESPONSE,
216+ correlationId: message.correlationId,
217+ confirmed: false,
218+ });
219+ break;
220+
221+ case PolicyDecision.ASK_USER:
222+ // 传递给 UI 层处理
223+ this.emitMessage(message);
224+ break;
225+
226+ default:
227+ throw new Error(\`Unknown policy decision: \${decision}\`);
228+ }
229+ } else if (message.type === MessageBusType.HOOK_EXECUTION_REQUEST) {
230+ // Hook 执行请求:经过 Hook 策略检查
231+ const decision = await this.policyEngine.checkHook(message);
232+
233+ // 发送策略决策事件(用于可观测性)
234+ this.emitMessage({
235+ type: MessageBusType.HOOK_POLICY_DECISION,
236+ eventName: message.eventName,
237+ hookSource: getHookSource(message.input),
238+ decision: decision === PolicyDecision.ALLOW ? 'allow' : 'deny',
239+ reason: decision !== PolicyDecision.ALLOW
240+ ? 'Hook execution denied by policy'
241+ : undefined,
242+ });
207243
208- case PolicyDecision.DENY:
209- this.emitMessage({
210- type: MessageBusType.TOOL_POLICY_REJECTION,
211- toolCall: message.toolCall,
212- });
244+ if (decision === PolicyDecision.ALLOW) {
245+ this.emitMessage(message);
246+ } else {
247+ // Hook 不支持交互式确认,直接返回错误
213248 this.emitMessage({
214- type: MessageBusType.TOOL_CONFIRMATION_RESPONSE ,
249+ type: MessageBusType.HOOK_EXECUTION_RESPONSE ,
215250 correlationId: message.correlationId,
216- confirmed: false,
251+ success: false,
252+ error: new Error('Hook execution denied by policy'),
217253 });
218- break;
219-
220- case PolicyDecision.ASK_USER:
221- // 传递给 UI 层处理
222- this.emitMessage(message);
223- break;
224- }
225- } else if (message.type === MessageBusType.HOOK_EXECUTION_REQUEST) {
226- // Hook 执行请求:经过 Hook 策略检查
227- const decision = await this.policyEngine.checkHook(message);
228-
229- this.emitMessage({
230- type: MessageBusType.HOOK_POLICY_DECISION,
231- eventName: message.eventName,
232- hookSource: getHookSource(message.input),
233- decision: decision === PolicyDecision.ALLOW ? 'allow' : 'deny',
234- });
235-
236- if (decision === PolicyDecision.ALLOW) {
237- this.emitMessage(message);
254+ }
238255 } else {
239- this.emitMessage({
240- type: MessageBusType.HOOK_EXECUTION_RESPONSE,
241- correlationId: message.correlationId,
242- success: false,
243- error: new Error('Hook execution denied by policy'),
244- });
256+ // 其他消息类型直接转发
257+ this.emitMessage(message);
245258 }
246- } else {
247- // 其他消息类型直接转发
248- this.emitMessage(message );
259+ } catch (error) {
260+ // 错误不抛出,而是通过 'error' 事件发送
261+ this.emit('error', error );
249262 }
250263 }
251264}` ;
252265
266+ // 错误处理机制代码
267+ const errorHandlingCode = `// 错误处理机制
268+
269+ // 1. 订阅错误事件
270+ messageBus.on('error', (error: Error) => {
271+ console.error('[MessageBus Error]', error.message);
272+ // 可以发送到日志系统或监控平台
273+ telemetry.recordError('message_bus', error);
274+ });
275+
276+ // 2. ToolExecutionFailure 接口
277+ export interface ToolExecutionFailure<E = Error> {
278+ type: MessageBusType.TOOL_EXECUTION_FAILURE;
279+ correlationId: string;
280+ error: E;
281+ }
282+
283+ // 3. HookExecutionResponse 可包含错误
284+ export interface HookExecutionResponse {
285+ type: MessageBusType.HOOK_EXECUTION_RESPONSE;
286+ correlationId: string;
287+ success: boolean;
288+ error?: Error; // 失败时包含错误信息
289+ }
290+
291+ // 4. 使用示例:处理工具执行失败
292+ messageBus.subscribe(
293+ MessageBusType.TOOL_EXECUTION_FAILURE,
294+ (message: ToolExecutionFailure) => {
295+ console.error(\`Tool execution failed: \${message.error.message}\`);
296+ // 可以触发重试逻辑或通知用户
297+ }
298+ );` ;
299+
253300 const subscribePatternCode = `// 订阅消息
254301subscribe<T extends Message>(
255302 type: T['type'],
@@ -556,7 +603,50 @@ if (response.confirmed) {
556603 </ div >
557604 </ Layer >
558605
559- { /* 7. 策略更新 */ }
606+ { /* 7. 错误处理机制 */ }
607+ < Layer title = "错误处理机制" icon = "⚠️" >
608+ < div className = "space-y-4" >
609+ < HighlightBox title = "错误不抛出,通过事件传递" variant = "red" >
610+ < div className = "text-sm space-y-2 text-gray-300" >
611+ < p >
612+ MessageBus 的 < code className = "bg-black/30 px-1 rounded" > publish()</ code > 方法将整个逻辑包裹在 try-catch 中,
613+ 错误不会抛出导致程序崩溃,而是通过 < code className = "bg-black/30 px-1 rounded" > 'error'</ code > 事件发送。
614+ </ p >
615+ < p className = "text-amber-400" >
616+ 这保证了消息总线的稳定性,即使某个消息处理失败,其他消息仍可正常处理。
617+ </ p >
618+ </ div >
619+ </ HighlightBox >
620+
621+ < CodeBlock code = { errorHandlingCode } language = "typescript" title = "错误处理示例" />
622+
623+ < div className = "grid grid-cols-1 md:grid-cols-2 gap-4" >
624+ < HighlightBox title = "错误类型" variant = "blue" >
625+ < div className = "text-sm space-y-2" >
626+ < ul className = "text-gray-400 space-y-1" >
627+ < li > • < code className = "text-red-300" > Invalid message structure</ code > : 消息格式错误</ li >
628+ < li > • < code className = "text-red-300" > Unknown policy decision</ code > : 未知策略决策</ li >
629+ < li > • < code className = "text-red-300" > Request timed out</ code > : 请求超时</ li >
630+ < li > • < code className = "text-red-300" > Hook execution denied</ code > : Hook 执行被拒绝</ li >
631+ </ ul >
632+ </ div >
633+ </ HighlightBox >
634+
635+ < HighlightBox title = "错误观测性" variant = "green" >
636+ < div className = "text-sm space-y-2" >
637+ < ul className = "text-gray-400 space-y-1" >
638+ < li > • 订阅 < code className = "text-cyan-300" > 'error'</ code > 事件监控错误</ li >
639+ < li > • 错误可发送到遥测系统</ li >
640+ < li > • 支持自定义错误处理逻辑</ li >
641+ < li > • 可结合日志系统记录</ li >
642+ </ ul >
643+ </ div >
644+ </ HighlightBox >
645+ </ div >
646+ </ div >
647+ </ Layer >
648+
649+ { /* 8. 策略更新 */ }
560650 < Layer title = "动态策略更新" icon = "🔄" >
561651 < div className = "space-y-4" >
562652 < CodeBlock
0 commit comments