mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-07-26 09:34:47 +00:00
fix(agent-core-v2): restore UpdateGoal completion/blocked prompts and no-goal fallbacks
Align with v1: completing or blocking a goal now returns the dynamic summary/blocked-reason prompt (buildGoalCompletionSummaryPrompt / buildGoalBlockedReasonPrompt, already present in outcome-prompts.ts but unused) instead of the static "Goal marked complete/blocked." text, and all three statuses report the "no active/current goal" fallback when there is nothing to transition.
This commit is contained in:
parent
ff14e519c2
commit
d9e411f5e7
2 changed files with 58 additions and 4 deletions
|
|
@ -15,6 +15,10 @@ import type { BuiltinTool, ToolExecution } from '#/agent/tool/toolContract';
|
|||
import { registerTool } from '#/agent/toolRegistry/toolContribution';
|
||||
|
||||
import { IAgentGoalService } from '#/agent/goal/goal';
|
||||
import {
|
||||
buildGoalBlockedReasonPrompt,
|
||||
buildGoalCompletionSummaryPrompt,
|
||||
} from './outcome-prompts';
|
||||
import DESCRIPTION from './update-goal.md?raw';
|
||||
|
||||
export const UpdateGoalToolInputSchema = z
|
||||
|
|
@ -54,16 +58,25 @@ export class UpdateGoalTool implements BuiltinTool<UpdateGoalToolInput> {
|
|||
approvalRule: this.name,
|
||||
execute: async () => {
|
||||
if (status === 'active') {
|
||||
if (currentGoal === null) {
|
||||
return { output: 'Goal not resumed: no current goal.' };
|
||||
}
|
||||
await this.goal.resumeGoal({}, 'model');
|
||||
return { output: 'Goal resumed.' };
|
||||
}
|
||||
if (status === 'complete') {
|
||||
await this.goal.markComplete({}, 'model');
|
||||
return { output: 'Goal marked complete.', stopTurn: true };
|
||||
const completed = await this.goal.markComplete({}, 'model');
|
||||
if (completed === null) {
|
||||
return { output: 'Goal not completed: no active goal.' };
|
||||
}
|
||||
return { output: buildGoalCompletionSummaryPrompt(completed), stopTurn: true };
|
||||
}
|
||||
if (status === 'blocked') {
|
||||
await this.goal.markBlocked({}, 'model');
|
||||
return { output: 'Goal marked blocked.', stopTurn: true };
|
||||
const blocked = await this.goal.markBlocked({}, 'model');
|
||||
if (blocked === null) {
|
||||
return { output: 'Goal not blocked: no active goal.' };
|
||||
}
|
||||
return { output: buildGoalBlockedReasonPrompt(blocked), stopTurn: true };
|
||||
}
|
||||
return {
|
||||
isError: true,
|
||||
|
|
|
|||
|
|
@ -117,6 +117,47 @@ describe('goal tools', () => {
|
|||
expect(goals.getGoal().goal?.status).toBe('active');
|
||||
});
|
||||
|
||||
it('UpdateGoal complete returns the completion summary prompt and stops the turn', async () => {
|
||||
await goals.createGoal({ objective: 'ship it' });
|
||||
const execution = updateGoalTool.resolveExecution({ status: 'complete' });
|
||||
if (execution.isError === true) throw new Error('execution should not be an error');
|
||||
const result = await execution.execute({ turnId: 0, toolCallId: 'call_c', signal });
|
||||
|
||||
expect(result.stopTurn).toBe(true);
|
||||
expect(result.output).toContain('Goal completed successfully');
|
||||
expect(result.output).toContain('Worked');
|
||||
expect(result.output).toContain('Write a concise final message for the user');
|
||||
});
|
||||
|
||||
it('UpdateGoal blocked returns the blocked-reason prompt and stops the turn', async () => {
|
||||
await goals.createGoal({ objective: 'ship it' });
|
||||
const execution = updateGoalTool.resolveExecution({ status: 'blocked' });
|
||||
if (execution.isError === true) throw new Error('execution should not be an error');
|
||||
const result = await execution.execute({ turnId: 0, toolCallId: 'call_b', signal });
|
||||
|
||||
expect(result.stopTurn).toBe(true);
|
||||
expect(result.output).toContain('Goal blocked.');
|
||||
expect(result.output).toContain('Worked');
|
||||
expect(result.output).toContain('concrete blocker');
|
||||
});
|
||||
|
||||
it('UpdateGoal reports no active goal when completing/blocking/resuming without one', async () => {
|
||||
const done = updateGoalTool.resolveExecution({ status: 'complete' });
|
||||
if (done.isError === true) throw new Error('execution should not be an error');
|
||||
const doneResult = await done.execute({ turnId: 0, toolCallId: 'call_n1', signal });
|
||||
expect(doneResult.output).toBe('Goal not completed: no active goal.');
|
||||
|
||||
const blocked = updateGoalTool.resolveExecution({ status: 'blocked' });
|
||||
if (blocked.isError === true) throw new Error('execution should not be an error');
|
||||
const blockedResult = await blocked.execute({ turnId: 0, toolCallId: 'call_n2', signal });
|
||||
expect(blockedResult.output).toBe('Goal not blocked: no active goal.');
|
||||
|
||||
const resumed = updateGoalTool.resolveExecution({ status: 'active' });
|
||||
if (resumed.isError === true) throw new Error('execution should not be an error');
|
||||
const resumedResult = await resumed.execute({ turnId: 0, toolCallId: 'call_n3', signal });
|
||||
expect(resumedResult.output).toBe('Goal not resumed: no current goal.');
|
||||
});
|
||||
|
||||
async function countGoalTurn(turnId: number): Promise<void> {
|
||||
const abortController = new AbortController();
|
||||
eventBus.publish({ type: 'turn.started', turnId, origin: USER_PROMPT_ORIGIN });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue