pulse-coder-engine 0.0.1-alpha.10 → 0.0.1-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
- import { FlexibleSchema, ModelMessage, LanguageModel, Tool as Tool$1 } from 'ai';
2
1
  import { EventEmitter } from 'events';
2
+ import { ModelMessage, FlexibleSchema, LanguageModel } from 'ai';
3
3
 
4
4
  /**
5
5
  * Custom LLM provider factory - receives a model name and returns a LanguageModel.
@@ -77,6 +77,58 @@ interface ILogger {
77
77
  error(message: string, error?: Error, meta?: Record<string, unknown>): void;
78
78
  }
79
79
 
80
+ /** Convenience: a value that may be wrapped in a Promise. */
81
+ type Promisable<T> = T | Promise<T>;
82
+ interface BeforeRunInput {
83
+ context: Context;
84
+ systemPrompt?: SystemPromptOption;
85
+ tools: Record<string, any>;
86
+ }
87
+ interface BeforeRunResult {
88
+ systemPrompt?: SystemPromptOption;
89
+ tools?: Record<string, any>;
90
+ }
91
+ type BeforeLLMCallInput = BeforeRunInput;
92
+ type BeforeLLMCallResult = BeforeRunResult;
93
+ interface AfterRunInput {
94
+ context: Context;
95
+ result: string;
96
+ }
97
+ interface AfterLLMCallInput {
98
+ context: Context;
99
+ finishReason: string;
100
+ text: string;
101
+ }
102
+ interface BeforeToolCallInput {
103
+ name: string;
104
+ input: any;
105
+ }
106
+ interface BeforeToolCallResult {
107
+ input?: any;
108
+ }
109
+ interface AfterToolCallInput {
110
+ name: string;
111
+ input: any;
112
+ output: any;
113
+ }
114
+ interface AfterToolCallResult {
115
+ output?: any;
116
+ }
117
+ interface EngineHookMap {
118
+ /** Fires once at the start of Engine.run(), before entering the loop. */
119
+ beforeRun: (input: BeforeRunInput) => Promisable<BeforeRunResult | void>;
120
+ /** Fires once when Engine.run() finishes. Read-only. */
121
+ afterRun: (input: AfterRunInput) => Promisable<void>;
122
+ /** Fires before each LLM call inside the loop (including retries after tool-calls). */
123
+ beforeLLMCall: (input: BeforeLLMCallInput) => Promisable<BeforeLLMCallResult | void>;
124
+ /** Fires after each LLM call completes. Read-only. */
125
+ afterLLMCall: (input: AfterLLMCallInput) => Promisable<void>;
126
+ /** Fires before each individual tool execution. Can modify input or throw to abort. */
127
+ beforeToolCall: (input: BeforeToolCallInput) => Promisable<BeforeToolCallResult | void>;
128
+ /** Fires after each individual tool execution. Can modify output. */
129
+ afterToolCall: (input: AfterToolCallInput) => Promisable<AfterToolCallResult | void>;
130
+ }
131
+ type EngineHookName = keyof EngineHookMap;
80
132
  interface EnginePlugin {
81
133
  name: string;
82
134
  version: string;
@@ -86,28 +138,13 @@ interface EnginePlugin {
86
138
  afterInitialize?(context: EnginePluginContext): Promise<void>;
87
139
  destroy?(context: EnginePluginContext): Promise<void>;
88
140
  }
89
- interface EngineRunHookInput {
90
- context: Context;
91
- messages: ModelMessage[];
92
- tools: Record<string, Tool$1>;
93
- systemPrompt?: SystemPromptOption;
94
- hooks?: ToolHooks;
95
- }
96
- interface EngineRunHookResult {
97
- systemPrompt?: SystemPromptOption;
98
- hooks?: ToolHooks;
99
- }
100
- type EngineRunHook = (input: EngineRunHookInput) => Promise<EngineRunHookResult | void> | EngineRunHookResult | void;
101
141
  interface EnginePluginContext {
102
- registerTool(name: string, tool: Tool$1): void;
103
- registerTools(tools: Record<string, Tool$1>): void;
104
- getTool(name: string): Tool$1 | undefined;
142
+ registerTool(name: string, tool: any): void;
143
+ registerTools(tools: Record<string, any>): void;
144
+ getTool(name: string): any;
105
145
  /** Returns a snapshot of all tools registered by plugins so far. */
106
- getTools(): Record<string, Tool$1>;
107
- registerRunHook(name: string, hook: EngineRunHook): void;
108
- getRunHook(name: string): EngineRunHook | undefined;
109
- registerProtocol(name: string, handler: ProtocolHandler): void;
110
- getProtocol(name: string): ProtocolHandler | undefined;
146
+ getTools(): Record<string, any>;
147
+ registerHook<K extends EngineHookName>(hookName: K, handler: EngineHookMap[K]): void;
111
148
  registerService<T>(name: string, service: T): void;
112
149
  getService<T>(name: string): T | undefined;
113
150
  getConfig<T>(key: string): T | undefined;
@@ -120,10 +157,6 @@ interface EnginePluginContext {
120
157
  error(message: string, error?: Error, meta?: any): void;
121
158
  };
122
159
  }
123
- interface ProtocolHandler {
124
- name: string;
125
- handle(message: any): Promise<any>;
126
- }
127
160
  interface EnginePluginLoadOptions {
128
161
  plugins?: EnginePlugin[];
129
162
  dirs?: string[];
@@ -241,7 +274,6 @@ interface PlanModeService {
241
274
  getModePolicy(mode?: PlanMode): ModePolicy;
242
275
  getToolMetadata(toolNames: string[]): ToolMeta[];
243
276
  buildPromptAppend(toolNames: string[], transition?: PlanModeTransitionResult): string;
244
- applyHooks(baseHooks?: ToolHooks): ToolHooks;
245
277
  getEvents(limit?: number): PlanModeEvent[];
246
278
  }
247
279
  type LoggerLike = EnginePluginContext['logger'];
@@ -258,9 +290,8 @@ declare class BuiltInPlanModeService implements PlanModeService {
258
290
  getModePolicy(mode?: PlanMode): ModePolicy;
259
291
  getToolMetadata(toolNames: string[]): ToolMeta[];
260
292
  buildPromptAppend(toolNames: string[], transition?: PlanModeTransitionResult): string;
261
- applyHooks(baseHooks?: ToolHooks): ToolHooks;
262
293
  getEvents(limit?: number): PlanModeEvent[];
263
- private observePotentialPolicyViolation;
294
+ observePotentialPolicyViolation(toolName: string, input: unknown): void;
264
295
  private inferToolMeta;
265
296
  private getLatestUserText;
266
297
  private messageContentToText;
@@ -274,4 +305,4 @@ declare const builtInPlanModePlugin: EnginePlugin;
274
305
  */
275
306
  declare const builtInPlugins: (EnginePlugin | SubAgentPlugin)[];
276
307
 
277
- export { BuiltInPlanModeService as B, type ClarificationRequest as C, type EnginePluginLoadOptions as E, type ILogger as I, type LLMProviderFactory as L, type ModePolicy as M, type PlanMode as P, type SystemPromptOption as S, type Tool as T, type ToolHooks as a, type Context as b, type ToolExecutionContext as c, type EngineRunHook as d, BuiltInSkillRegistry as e, type EnginePlugin as f, type EnginePluginContext as g, type PlanIntentLabel as h, type PlanModeEvent as i, type PlanModeEventName as j, type PlanModeService as k, type PlanModeTransitionResult as l, type ToolCategory as m, type ToolMeta as n, type ToolRisk as o, builtInMCPPlugin as p, builtInPlanModePlugin as q, builtInPlugins as r, builtInSkillsPlugin as s, SubAgentPlugin as t };
308
+ export { type AfterLLMCallInput as A, type BeforeLLMCallInput as B, type ClarificationRequest as C, builtInPlanModePlugin as D, type EngineHookMap as E, builtInPlugins as F, builtInSkillsPlugin as G, SubAgentPlugin as H, type ILogger as I, type LLMProviderFactory as L, type ModePolicy as M, type PlanMode as P, type SystemPromptOption as S, type Tool as T, type Context as a, type ToolExecutionContext as b, type EnginePluginLoadOptions as c, type ToolHooks as d, type EngineHookName as e, type AfterRunInput as f, type AfterToolCallInput as g, type AfterToolCallResult as h, type BeforeLLMCallResult as i, type BeforeRunInput as j, type BeforeRunResult as k, type BeforeToolCallInput as l, type BeforeToolCallResult as m, BuiltInPlanModeService as n, BuiltInSkillRegistry as o, type EnginePlugin as p, type EnginePluginContext as q, type PlanIntentLabel as r, type PlanModeEvent as s, type PlanModeEventName as t, type PlanModeService as u, type PlanModeTransitionResult as v, type ToolCategory as w, type ToolMeta as x, type ToolRisk as y, builtInMCPPlugin as z };
@@ -1,5 +1,5 @@
1
- import { FlexibleSchema, ModelMessage, LanguageModel, Tool as Tool$1 } from 'ai';
2
1
  import { EventEmitter } from 'events';
2
+ import { ModelMessage, FlexibleSchema, LanguageModel } from 'ai';
3
3
 
4
4
  /**
5
5
  * Custom LLM provider factory - receives a model name and returns a LanguageModel.
@@ -77,6 +77,58 @@ interface ILogger {
77
77
  error(message: string, error?: Error, meta?: Record<string, unknown>): void;
78
78
  }
79
79
 
80
+ /** Convenience: a value that may be wrapped in a Promise. */
81
+ type Promisable<T> = T | Promise<T>;
82
+ interface BeforeRunInput {
83
+ context: Context;
84
+ systemPrompt?: SystemPromptOption;
85
+ tools: Record<string, any>;
86
+ }
87
+ interface BeforeRunResult {
88
+ systemPrompt?: SystemPromptOption;
89
+ tools?: Record<string, any>;
90
+ }
91
+ type BeforeLLMCallInput = BeforeRunInput;
92
+ type BeforeLLMCallResult = BeforeRunResult;
93
+ interface AfterRunInput {
94
+ context: Context;
95
+ result: string;
96
+ }
97
+ interface AfterLLMCallInput {
98
+ context: Context;
99
+ finishReason: string;
100
+ text: string;
101
+ }
102
+ interface BeforeToolCallInput {
103
+ name: string;
104
+ input: any;
105
+ }
106
+ interface BeforeToolCallResult {
107
+ input?: any;
108
+ }
109
+ interface AfterToolCallInput {
110
+ name: string;
111
+ input: any;
112
+ output: any;
113
+ }
114
+ interface AfterToolCallResult {
115
+ output?: any;
116
+ }
117
+ interface EngineHookMap {
118
+ /** Fires once at the start of Engine.run(), before entering the loop. */
119
+ beforeRun: (input: BeforeRunInput) => Promisable<BeforeRunResult | void>;
120
+ /** Fires once when Engine.run() finishes. Read-only. */
121
+ afterRun: (input: AfterRunInput) => Promisable<void>;
122
+ /** Fires before each LLM call inside the loop (including retries after tool-calls). */
123
+ beforeLLMCall: (input: BeforeLLMCallInput) => Promisable<BeforeLLMCallResult | void>;
124
+ /** Fires after each LLM call completes. Read-only. */
125
+ afterLLMCall: (input: AfterLLMCallInput) => Promisable<void>;
126
+ /** Fires before each individual tool execution. Can modify input or throw to abort. */
127
+ beforeToolCall: (input: BeforeToolCallInput) => Promisable<BeforeToolCallResult | void>;
128
+ /** Fires after each individual tool execution. Can modify output. */
129
+ afterToolCall: (input: AfterToolCallInput) => Promisable<AfterToolCallResult | void>;
130
+ }
131
+ type EngineHookName = keyof EngineHookMap;
80
132
  interface EnginePlugin {
81
133
  name: string;
82
134
  version: string;
@@ -86,28 +138,13 @@ interface EnginePlugin {
86
138
  afterInitialize?(context: EnginePluginContext): Promise<void>;
87
139
  destroy?(context: EnginePluginContext): Promise<void>;
88
140
  }
89
- interface EngineRunHookInput {
90
- context: Context;
91
- messages: ModelMessage[];
92
- tools: Record<string, Tool$1>;
93
- systemPrompt?: SystemPromptOption;
94
- hooks?: ToolHooks;
95
- }
96
- interface EngineRunHookResult {
97
- systemPrompt?: SystemPromptOption;
98
- hooks?: ToolHooks;
99
- }
100
- type EngineRunHook = (input: EngineRunHookInput) => Promise<EngineRunHookResult | void> | EngineRunHookResult | void;
101
141
  interface EnginePluginContext {
102
- registerTool(name: string, tool: Tool$1): void;
103
- registerTools(tools: Record<string, Tool$1>): void;
104
- getTool(name: string): Tool$1 | undefined;
142
+ registerTool(name: string, tool: any): void;
143
+ registerTools(tools: Record<string, any>): void;
144
+ getTool(name: string): any;
105
145
  /** Returns a snapshot of all tools registered by plugins so far. */
106
- getTools(): Record<string, Tool$1>;
107
- registerRunHook(name: string, hook: EngineRunHook): void;
108
- getRunHook(name: string): EngineRunHook | undefined;
109
- registerProtocol(name: string, handler: ProtocolHandler): void;
110
- getProtocol(name: string): ProtocolHandler | undefined;
146
+ getTools(): Record<string, any>;
147
+ registerHook<K extends EngineHookName>(hookName: K, handler: EngineHookMap[K]): void;
111
148
  registerService<T>(name: string, service: T): void;
112
149
  getService<T>(name: string): T | undefined;
113
150
  getConfig<T>(key: string): T | undefined;
@@ -120,10 +157,6 @@ interface EnginePluginContext {
120
157
  error(message: string, error?: Error, meta?: any): void;
121
158
  };
122
159
  }
123
- interface ProtocolHandler {
124
- name: string;
125
- handle(message: any): Promise<any>;
126
- }
127
160
  interface EnginePluginLoadOptions {
128
161
  plugins?: EnginePlugin[];
129
162
  dirs?: string[];
@@ -241,7 +274,6 @@ interface PlanModeService {
241
274
  getModePolicy(mode?: PlanMode): ModePolicy;
242
275
  getToolMetadata(toolNames: string[]): ToolMeta[];
243
276
  buildPromptAppend(toolNames: string[], transition?: PlanModeTransitionResult): string;
244
- applyHooks(baseHooks?: ToolHooks): ToolHooks;
245
277
  getEvents(limit?: number): PlanModeEvent[];
246
278
  }
247
279
  type LoggerLike = EnginePluginContext['logger'];
@@ -258,9 +290,8 @@ declare class BuiltInPlanModeService implements PlanModeService {
258
290
  getModePolicy(mode?: PlanMode): ModePolicy;
259
291
  getToolMetadata(toolNames: string[]): ToolMeta[];
260
292
  buildPromptAppend(toolNames: string[], transition?: PlanModeTransitionResult): string;
261
- applyHooks(baseHooks?: ToolHooks): ToolHooks;
262
293
  getEvents(limit?: number): PlanModeEvent[];
263
- private observePotentialPolicyViolation;
294
+ observePotentialPolicyViolation(toolName: string, input: unknown): void;
264
295
  private inferToolMeta;
265
296
  private getLatestUserText;
266
297
  private messageContentToText;
@@ -274,4 +305,4 @@ declare const builtInPlanModePlugin: EnginePlugin;
274
305
  */
275
306
  declare const builtInPlugins: (EnginePlugin | SubAgentPlugin)[];
276
307
 
277
- export { BuiltInPlanModeService as B, type ClarificationRequest as C, type EnginePluginLoadOptions as E, type ILogger as I, type LLMProviderFactory as L, type ModePolicy as M, type PlanMode as P, type SystemPromptOption as S, type Tool as T, type ToolHooks as a, type Context as b, type ToolExecutionContext as c, type EngineRunHook as d, BuiltInSkillRegistry as e, type EnginePlugin as f, type EnginePluginContext as g, type PlanIntentLabel as h, type PlanModeEvent as i, type PlanModeEventName as j, type PlanModeService as k, type PlanModeTransitionResult as l, type ToolCategory as m, type ToolMeta as n, type ToolRisk as o, builtInMCPPlugin as p, builtInPlanModePlugin as q, builtInPlugins as r, builtInSkillsPlugin as s, SubAgentPlugin as t };
308
+ export { type AfterLLMCallInput as A, type BeforeLLMCallInput as B, type ClarificationRequest as C, builtInPlanModePlugin as D, type EngineHookMap as E, builtInPlugins as F, builtInSkillsPlugin as G, SubAgentPlugin as H, type ILogger as I, type LLMProviderFactory as L, type ModePolicy as M, type PlanMode as P, type SystemPromptOption as S, type Tool as T, type Context as a, type ToolExecutionContext as b, type EnginePluginLoadOptions as c, type ToolHooks as d, type EngineHookName as e, type AfterRunInput as f, type AfterToolCallInput as g, type AfterToolCallResult as h, type BeforeLLMCallResult as i, type BeforeRunInput as j, type BeforeRunResult as k, type BeforeToolCallInput as l, type BeforeToolCallResult as m, BuiltInPlanModeService as n, BuiltInSkillRegistry as o, type EnginePlugin as p, type EnginePluginContext as q, type PlanIntentLabel as r, type PlanModeEvent as s, type PlanModeEventName as t, type PlanModeService as u, type PlanModeTransitionResult as v, type ToolCategory as w, type ToolMeta as x, type ToolRisk as y, builtInMCPPlugin as z };
package/dist/index.cjs CHANGED
@@ -415,15 +415,28 @@ var maybeCompactContext = async (context, options) => {
415
415
  };
416
416
 
417
417
  // src/core/loop.ts
418
- function applyToolHooks(tools, hooks) {
418
+ function wrapToolsWithHooks(tools, beforeHooks, afterHooks) {
419
419
  const wrapped = {};
420
420
  for (const [name, t] of Object.entries(tools)) {
421
421
  wrapped[name] = {
422
422
  ...t,
423
423
  execute: async (input, ctx) => {
424
- const finalInput = hooks.onBeforeToolCall ? await hooks.onBeforeToolCall(name, input) ?? input : input;
424
+ let finalInput = input;
425
+ for (const hook of beforeHooks) {
426
+ const result = await hook({ name, input: finalInput });
427
+ if (result && "input" in result) {
428
+ finalInput = result.input;
429
+ }
430
+ }
425
431
  const output = await t.execute(finalInput, ctx);
426
- return hooks.onAfterToolCall ? await hooks.onAfterToolCall(name, finalInput, output) ?? output : output;
432
+ let finalOutput = output;
433
+ for (const hook of afterHooks) {
434
+ const result = await hook({ name, input: finalInput, output: finalOutput });
435
+ if (result && "output" in result) {
436
+ finalOutput = result.output;
437
+ }
438
+ }
439
+ return finalOutput;
427
440
  }
428
441
  };
429
442
  }
@@ -433,6 +446,7 @@ async function loop(context, options) {
433
446
  let errorCount = 0;
434
447
  let totalSteps = 0;
435
448
  let compactionAttempts = 0;
449
+ const loopHooks = options?.hooks ?? {};
436
450
  while (true) {
437
451
  try {
438
452
  if (compactionAttempts < MAX_COMPACTION_ATTEMPTS) {
@@ -449,8 +463,24 @@ async function loop(context, options) {
449
463
  }
450
464
  }
451
465
  let tools = options?.tools || {};
452
- if (options?.hooks) {
453
- tools = applyToolHooks(tools, options.hooks);
466
+ let systemPrompt = options?.systemPrompt;
467
+ if (loopHooks.beforeLLMCall?.length) {
468
+ for (const hook of loopHooks.beforeLLMCall) {
469
+ const result2 = await hook({ context, systemPrompt, tools });
470
+ if (result2) {
471
+ if ("systemPrompt" in result2 && result2.systemPrompt !== void 0) {
472
+ systemPrompt = result2.systemPrompt;
473
+ }
474
+ if ("tools" in result2 && result2.tools !== void 0) {
475
+ tools = result2.tools;
476
+ }
477
+ }
478
+ }
479
+ }
480
+ const beforeToolHooks = loopHooks.beforeToolCall ?? [];
481
+ const afterToolHooks = loopHooks.afterToolCall ?? [];
482
+ if (beforeToolHooks.length || afterToolHooks.length) {
483
+ tools = wrapToolsWithHooks(tools, beforeToolHooks, afterToolHooks);
454
484
  }
455
485
  const toolExecutionContext = {
456
486
  onClarificationRequest: options?.onClarificationRequest,
@@ -461,7 +491,7 @@ async function loop(context, options) {
461
491
  toolExecutionContext,
462
492
  provider: options?.provider,
463
493
  model: options?.model,
464
- systemPrompt: options?.systemPrompt,
494
+ systemPrompt,
465
495
  onStepFinish: (step) => {
466
496
  options?.onStepFinish?.(step);
467
497
  },
@@ -489,6 +519,11 @@ async function loop(context, options) {
489
519
  options?.onResponse?.(messages);
490
520
  }
491
521
  }
522
+ if (loopHooks.afterLLMCall?.length) {
523
+ for (const hook of loopHooks.afterLLMCall) {
524
+ await hook({ context, finishReason, text });
525
+ }
526
+ }
492
527
  if (finishReason === "stop") {
493
528
  return text || "Task completed.";
494
529
  }
@@ -1066,9 +1101,15 @@ var PluginManager = class {
1066
1101
  enginePlugins = /* @__PURE__ */ new Map();
1067
1102
  userConfigPlugins = [];
1068
1103
  tools = /* @__PURE__ */ new Map();
1069
- runHooks = /* @__PURE__ */ new Map();
1104
+ hooks = {
1105
+ beforeRun: [],
1106
+ afterRun: [],
1107
+ beforeLLMCall: [],
1108
+ afterLLMCall: [],
1109
+ beforeToolCall: [],
1110
+ afterToolCall: []
1111
+ };
1070
1112
  services = /* @__PURE__ */ new Map();
1071
- protocols = /* @__PURE__ */ new Map();
1072
1113
  config = /* @__PURE__ */ new Map();
1073
1114
  events = new import_events.EventEmitter();
1074
1115
  logger;
@@ -1177,14 +1218,10 @@ var PluginManager = class {
1177
1218
  },
1178
1219
  getTool: (name) => this.tools.get(name),
1179
1220
  getTools: () => Object.fromEntries(this.tools),
1180
- registerRunHook: (name, hook) => {
1181
- this.runHooks.set(name, hook);
1182
- },
1183
- getRunHook: (name) => this.runHooks.get(name),
1184
- registerProtocol: (name, handler) => {
1185
- this.protocols.set(name, handler);
1221
+ registerHook: (hookName, handler) => {
1222
+ this.hooks[hookName].push(handler);
1223
+ this.logger.debug(`Plugin "${plugin.name}" registered hook: ${hookName}`);
1186
1224
  },
1187
- getProtocol: (name) => this.protocols.get(name),
1188
1225
  registerService: (name, service) => {
1189
1226
  this.services.set(name, service);
1190
1227
  },
@@ -1380,10 +1417,10 @@ var PluginManager = class {
1380
1417
  return Object.fromEntries(this.tools);
1381
1418
  }
1382
1419
  /**
1383
- * 运行时钩子获取
1420
+ * 获取指定类型的 hook 处理函数数组
1384
1421
  */
1385
- getRunHooks() {
1386
- return Array.from(this.runHooks.values());
1422
+ getHooks(hookName) {
1423
+ return [...this.hooks[hookName]];
1387
1424
  }
1388
1425
  /**
1389
1426
  * 服务获取
@@ -1391,12 +1428,6 @@ var PluginManager = class {
1391
1428
  getService(name) {
1392
1429
  return this.services.get(name);
1393
1430
  }
1394
- /**
1395
- * 协议获取
1396
- */
1397
- getProtocol(name) {
1398
- return this.protocols.get(name);
1399
- }
1400
1431
  /**
1401
1432
  * 获取插件状态
1402
1433
  */
@@ -1405,9 +1436,10 @@ var PluginManager = class {
1405
1436
  enginePlugins: Array.from(this.enginePlugins.keys()),
1406
1437
  userConfigPlugins: this.userConfigPlugins.map((c) => c.name || "unnamed"),
1407
1438
  tools: Array.from(this.tools.keys()),
1408
- runHooks: Array.from(this.runHooks.keys()),
1409
- services: Array.from(this.services.keys()),
1410
- protocols: Array.from(this.protocols.keys())
1439
+ hooks: Object.fromEntries(
1440
+ Object.entries(this.hooks).map(([k, v]) => [k, v.length])
1441
+ ),
1442
+ services: Array.from(this.services.keys())
1411
1443
  };
1412
1444
  }
1413
1445
  /**
@@ -1884,25 +1916,6 @@ var BuiltInPlanModeService = class {
1884
1916
  }
1885
1917
  return lines.join("\n");
1886
1918
  }
1887
- applyHooks(baseHooks) {
1888
- return {
1889
- onBeforeToolCall: async (name, input) => {
1890
- this.observePotentialPolicyViolation(name, input);
1891
- if (baseHooks?.onBeforeToolCall) {
1892
- const nextInput = await baseHooks.onBeforeToolCall(name, input);
1893
- return nextInput ?? input;
1894
- }
1895
- return input;
1896
- },
1897
- onAfterToolCall: async (name, input, output) => {
1898
- if (baseHooks?.onAfterToolCall) {
1899
- const nextOutput = await baseHooks.onAfterToolCall(name, input, output);
1900
- return nextOutput ?? output;
1901
- }
1902
- return output;
1903
- }
1904
- };
1905
- }
1906
1919
  getEvents(limit = 50) {
1907
1920
  return this.events.slice(-Math.max(0, limit));
1908
1921
  }
@@ -2039,21 +2052,18 @@ var builtInPlanModePlugin = {
2039
2052
  version: "1.0.0",
2040
2053
  async initialize(context) {
2041
2054
  const service = new BuiltInPlanModeService(context.logger, context.events, "executing");
2042
- context.registerRunHook("plan-mode", ({ context: runContext, tools, systemPrompt, hooks }) => {
2055
+ context.registerHook("beforeLLMCall", ({ context: runContext, tools, systemPrompt }) => {
2043
2056
  const mode = service.getMode();
2044
2057
  if (mode === "executing") {
2045
- return {
2046
- systemPrompt,
2047
- hooks
2048
- };
2058
+ return;
2049
2059
  }
2050
2060
  const transition = service.processContextMessages(runContext.messages);
2051
2061
  const append = service.buildPromptAppend(Object.keys(tools), transition);
2052
2062
  const finalSystemPrompt = appendSystemPrompt(systemPrompt, append);
2053
- return {
2054
- systemPrompt: finalSystemPrompt,
2055
- hooks: service.applyHooks(hooks)
2056
- };
2063
+ return { systemPrompt: finalSystemPrompt };
2064
+ });
2065
+ context.registerHook("beforeToolCall", ({ name, input }) => {
2066
+ service.observePotentialPolicyViolation(name, input);
2057
2067
  });
2058
2068
  context.registerService("planMode", service);
2059
2069
  context.registerService("planModeService", service);
@@ -2264,52 +2274,70 @@ var Engine = class {
2264
2274
  // 默认启用扫描
2265
2275
  };
2266
2276
  }
2267
- async applyRunHooks(context, systemPrompt, hooks) {
2268
- let nextSystemPrompt = systemPrompt;
2269
- let nextHooks = hooks;
2270
- for (const runHook of this.pluginManager.getRunHooks()) {
2271
- const result = await runHook({
2272
- context,
2273
- messages: context.messages,
2274
- tools: this.tools,
2275
- systemPrompt: nextSystemPrompt,
2276
- hooks: nextHooks
2277
+ /**
2278
+ * Collect all hooks for a given loop invocation.
2279
+ * Merges plugin hooks with the legacy EngineOptions.hooks (ToolHooks).
2280
+ */
2281
+ collectLoopHooks() {
2282
+ const loopHooks = {
2283
+ beforeLLMCall: this.pluginManager.getHooks("beforeLLMCall"),
2284
+ afterLLMCall: this.pluginManager.getHooks("afterLLMCall"),
2285
+ beforeToolCall: [...this.pluginManager.getHooks("beforeToolCall")],
2286
+ afterToolCall: [...this.pluginManager.getHooks("afterToolCall")]
2287
+ };
2288
+ const legacyHooks = this.options.hooks;
2289
+ if (legacyHooks?.onBeforeToolCall) {
2290
+ const legacyBefore = legacyHooks.onBeforeToolCall;
2291
+ loopHooks.beforeToolCall.push(async ({ name, input }) => {
2292
+ const modified = await legacyBefore(name, input);
2293
+ return modified !== void 0 ? { input: modified } : void 0;
2277
2294
  });
2278
- if (!result) {
2279
- continue;
2280
- }
2281
- if ("systemPrompt" in result) {
2282
- nextSystemPrompt = result.systemPrompt;
2283
- }
2284
- if ("hooks" in result) {
2285
- nextHooks = result.hooks;
2286
- }
2287
2295
  }
2288
- return {
2289
- systemPrompt: nextSystemPrompt,
2290
- hooks: nextHooks
2291
- };
2296
+ if (legacyHooks?.onAfterToolCall) {
2297
+ const legacyAfter = legacyHooks.onAfterToolCall;
2298
+ loopHooks.afterToolCall.push(async ({ name, input, output }) => {
2299
+ const modified = await legacyAfter(name, input, output);
2300
+ return modified !== void 0 ? { output: modified } : void 0;
2301
+ });
2302
+ }
2303
+ return loopHooks;
2292
2304
  }
2293
2305
  /**
2294
2306
  * 运行AI循环
2295
2307
  */
2296
2308
  async run(context, options) {
2297
- const baseSystemPrompt = options?.systemPrompt ?? this.options.systemPrompt;
2298
- const baseHooks = options?.hooks ?? this.options.hooks;
2299
- const { systemPrompt, hooks } = await this.applyRunHooks(context, baseSystemPrompt, baseHooks);
2300
- return loop(context, {
2309
+ let systemPrompt = options?.systemPrompt ?? this.options.systemPrompt;
2310
+ let tools = { ...this.tools };
2311
+ const beforeRunHooks = this.pluginManager.getHooks("beforeRun");
2312
+ for (const hook of beforeRunHooks) {
2313
+ const result = await hook({ context, systemPrompt, tools });
2314
+ if (result) {
2315
+ if ("systemPrompt" in result && result.systemPrompt !== void 0) {
2316
+ systemPrompt = result.systemPrompt;
2317
+ }
2318
+ if ("tools" in result && result.tools !== void 0) {
2319
+ tools = result.tools;
2320
+ }
2321
+ }
2322
+ }
2323
+ const loopHooks = this.collectLoopHooks();
2324
+ const resultText = await loop(context, {
2301
2325
  ...options,
2302
- tools: this.tools,
2303
- // Engine 级别选项作为默认值;调用方通过 options 传入可在单次调用中覆盖
2326
+ tools,
2304
2327
  provider: options?.provider ?? this.options.llmProvider,
2305
2328
  model: options?.model ?? this.options.model,
2306
2329
  systemPrompt,
2307
- hooks,
2330
+ hooks: loopHooks,
2308
2331
  onToolCall: (toolCall) => {
2309
2332
  options?.onToolCall?.(toolCall);
2310
2333
  },
2311
2334
  onClarificationRequest: options?.onClarificationRequest
2312
2335
  });
2336
+ const afterRunHooks = this.pluginManager.getHooks("afterRun");
2337
+ for (const hook of afterRunHooks) {
2338
+ await hook({ context, result: resultText });
2339
+ }
2340
+ return resultText;
2313
2341
  }
2314
2342
  /**
2315
2343
  * 获取插件状态