mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-19 21:56:00 +00:00
fix: stopHookContinuationUsed
This commit is contained in:
parent
9a6a722d14
commit
3381c44b16
3 changed files with 19 additions and 22 deletions
|
|
@ -77,6 +77,7 @@ export class AgentExternalHooksService extends Disposable implements IAgentExter
|
|||
declare readonly _serviceBrand: undefined;
|
||||
|
||||
private dynamicEngine: HookEngine | undefined;
|
||||
private stopHookContinuationUsed = false;
|
||||
|
||||
constructor(
|
||||
private readonly options: ExternalHooksServiceOptions = {},
|
||||
|
|
@ -203,6 +204,7 @@ export class AgentExternalHooksService extends Disposable implements IAgentExter
|
|||
loop.hooks.onWillStop.register('externalHooks', async (ctx, next) => {
|
||||
const reason = await this.runStop(ctx);
|
||||
if (reason !== undefined) {
|
||||
this.stopHookContinuationUsed = true;
|
||||
ctx.continuationPrompt = reason;
|
||||
return;
|
||||
}
|
||||
|
|
@ -314,6 +316,7 @@ export class AgentExternalHooksService extends Disposable implements IAgentExter
|
|||
}
|
||||
|
||||
private notifyTurnEnded(ctx: TurnEndedContext): void {
|
||||
this.stopHookContinuationUsed = false;
|
||||
if (ctx.result.reason === 'failed' && ctx.result.error !== undefined) {
|
||||
this.notifyStopFailure(ctx.result.error, ctx.turn.abortController.signal);
|
||||
}
|
||||
|
|
@ -343,9 +346,11 @@ export class AgentExternalHooksService extends Disposable implements IAgentExter
|
|||
|
||||
private async runStop(ctx: TurnWillStopContext): Promise<string | undefined> {
|
||||
ctx.signal.throwIfAborted();
|
||||
if (this.stopHookContinuationUsed) return undefined;
|
||||
|
||||
const block = await this.engine()?.triggerBlock('Stop', {
|
||||
signal: ctx.signal,
|
||||
inputData: { stopHookActive: ctx.stopHookActive },
|
||||
inputData: { stopHookActive: false },
|
||||
});
|
||||
ctx.signal.throwIfAborted();
|
||||
return block?.reason;
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import type { TurnResult } from './types';
|
|||
|
||||
export interface TurnBeforeStepContext {
|
||||
readonly turnId: number;
|
||||
readonly step: number;
|
||||
readonly signal: AbortSignal;
|
||||
}
|
||||
|
||||
|
|
@ -23,7 +24,6 @@ export interface TurnContextOverflowContext {
|
|||
|
||||
export interface TurnWillStopContext {
|
||||
readonly signal: AbortSignal;
|
||||
readonly stopHookActive: boolean;
|
||||
continuationPrompt?: string;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -71,7 +71,6 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
let stopReason: LoopTurnStopReason = 'completed';
|
||||
let activeStep: number | undefined;
|
||||
const maxSteps = this.config.get<LoopControl>(LOOP_CONTROL_SECTION)?.maxStepsPerTurn;
|
||||
let stopHookContinuationUsed = false;
|
||||
|
||||
try {
|
||||
while (true) {
|
||||
|
|
@ -96,19 +95,16 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
continue;
|
||||
}
|
||||
|
||||
if (!stopHookContinuationUsed) {
|
||||
const context: TurnWillStopContext = { signal, stopHookActive: false };
|
||||
await this.hooks.onWillStop.run(context);
|
||||
if (context.continuationPrompt !== undefined && hasStepBudgetRemaining(maxSteps, steps)) {
|
||||
stopHookContinuationUsed = true;
|
||||
this.append({
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: context.continuationPrompt }],
|
||||
toolCalls: [],
|
||||
origin: { kind: 'system_trigger', name: 'stop_hook' },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
const context: TurnWillStopContext = { signal };
|
||||
await this.hooks.onWillStop.run(context);
|
||||
if (context.continuationPrompt !== undefined) {
|
||||
this.append({
|
||||
role: 'user',
|
||||
content: [{ type: 'text', text: context.continuationPrompt }],
|
||||
toolCalls: [],
|
||||
origin: { kind: 'system_trigger', name: 'stop_hook' },
|
||||
});
|
||||
continue;
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
@ -150,7 +146,7 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
readonly stopReason: FinishReason;
|
||||
readonly continueTurn: boolean;
|
||||
}> {
|
||||
await this.hooks.beforeStep.run({ turnId, signal });
|
||||
await this.hooks.beforeStep.run({ turnId, step: currentStep, signal });
|
||||
signal.throwIfAborted();
|
||||
|
||||
const stepUuid = randomUUID();
|
||||
|
|
@ -228,7 +224,7 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
|
||||
this.emitStepCompleted(turnId, currentStep, stepUuid, usage, finishReason, response);
|
||||
|
||||
const afterStepContext = { turnId, signal, usage, continueTurn: false };
|
||||
const afterStepContext = { turnId, step: currentStep, signal, usage, continueTurn: false };
|
||||
try {
|
||||
await this.hooks.afterStep.run(afterStepContext);
|
||||
} catch {
|
||||
|
|
@ -383,10 +379,6 @@ function toolResultOutputForModel(result: ToolResult): string | ContentPart[] {
|
|||
return output;
|
||||
}
|
||||
|
||||
function hasStepBudgetRemaining(maxSteps: number | undefined, currentStep: number): boolean {
|
||||
return maxSteps === undefined || maxSteps <= 0 || currentStep < maxSteps;
|
||||
}
|
||||
|
||||
registerScopedService(
|
||||
LifecycleScope.Agent,
|
||||
IAgentLoopService,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue