MCPcopy Create free account
hub / github.com/MoonshotAI/kimi-code / runStepLoop

Method runStepLoop

packages/agent-core/src/agent/turn/index.ts:670–846  ·  view source on GitHub ↗
(turnId: number, signal: AbortSignal)

Source from the content-addressed store, hash-verified

668 }
669
670 private async runStepLoop(turnId: number, signal: AbortSignal): Promise<LoopTurnStopReason> {
671 let stopHookContinuationUsed = false;
672 let goalOutcomeMessageContinuationUsed = false;
673 const deduper = new ToolCallDeduplicator({ telemetry: this.agent.telemetry });
674 await this.agent.mcp?.waitForInitialLoad(signal);
675 // Surface the active goal at the start of the turn (append-only; no-op when
676 // there is no active goal). Each goal continuation is its own turn, so this
677 // re-injects the reminder once per turn rather than per step, preserving prompt caching.
678 await this.agent.injection.injectGoal();
679 while (true) {
680 signal.throwIfAborted();
681 const model = this.agent.config.model;
682 const loopControl = this.agent.kimiConfig?.loopControl;
683 let stopForGoalBudget = false;
684 try {
685 const result = await runTurn({
686 turnId: String(turnId),
687 signal,
688 llm: this.agent.llm,
689 buildMessages: () => this.agent.context.messages,
690 buildMessagesStrict: () => this.agent.context.strictMessages,
691 dispatchEvent: this.buildDispatchEvent(turnId),
692 tools: this.agent.tools.loopTools,
693 log: this.agent.log,
694 maxSteps: loopControl?.maxStepsPerTurn,
695 maxRetryAttempts: loopControl?.maxRetriesPerStep,
696 recordStepUsage: async (usage) => {
697 try {
698 const snapshot = await this.agent.goal.recordTokenUsage(grandTotal(usage));
699 stopForGoalBudget = snapshot?.budget.overBudget === true;
700 } catch (error) {
701 this.agent.log.warn('goal token accounting failed', { error });
702 }
703 },
704 hooks: {
705 beforeStep: async ({ signal: stepSignal }) => {
706 this.agent.microCompaction.detect();
707 await this.agent.fullCompaction.beforeStep(stepSignal);
708 // Flush steered messages (background-task / cron notifications,
709 // user interrupts) AFTER compaction so they land in the
710 // post-compaction context instead of being dropped by it. The
711 // keep/drop decision lives in
712 // `compactionUserMessageDisposition()`; these origins are not
713 // re-injected later, so append them only after compaction runs.
714 this.flushSteerBuffer();
715 await this.agent.injection.inject();
716 deduper.beginStep();
717 return;
718 },
719 afterStep: async ({ usage }) => {
720 this.agent.usage.record(model, usage, 'turn');
721 await this.agent.fullCompaction.afterStep();
722 deduper.endStep();
723 return stopForGoalBudget ? { stopTurn: true } : undefined;
724 },
725 // oxlint-disable-next-line no-loop-func -- stop hook continuation state is scoped to this turn.
726 shouldContinueAfterStop: async (ctx) => {
727 const { signal } = ctx;

Callers 1

runOneTurnMethod · 0.95

Calls 15

buildDispatchEventMethod · 0.95
flushSteerBufferMethod · 0.95
beginStepMethod · 0.95
endStepMethod · 0.95
checkSameStepMethod · 0.95
finalizeResultMethod · 0.95
grandTotalFunction · 0.90
toKimiErrorPayloadFunction · 0.90
budgetToolResultForModelFunction · 0.90
isKimiErrorFunction · 0.90
isMaxStepsExceededErrorFunction · 0.90

Tested by

no test coverage detected