mirror of
https://github.com/MoonshotAI/kimi-code.git
synced 2026-08-19 13:45:28 +00:00
refactor: minimize llmRequester.request
This commit is contained in:
parent
70f936acad
commit
3c62637b67
8 changed files with 79 additions and 67 deletions
|
|
@ -202,6 +202,7 @@ llmRequester --> usage #34495E
|
|||
llmRequester --> modelProvider #34495E
|
||||
llmRequester --> config #34495E
|
||||
toolExecutor --> toolRegistry #34495E
|
||||
toolExecutor --> record #34495E
|
||||
toolExecutor --> telemetry #34495E
|
||||
toolStore --> wireRecord #34495E
|
||||
toolDedup --> telemetry #34495E
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 258 KiB After Width: | Height: | Size: 243 KiB |
|
|
@ -1,7 +1,5 @@
|
|||
import { randomUUID } from 'node:crypto';
|
||||
|
||||
import type { AgentEvent } from '@moonshot-ai/protocol';
|
||||
|
||||
import { InstantiationType } from '#/_base/di/extensions';
|
||||
import { LifecycleScope, registerScopedService } from '#/_base/di/scope';
|
||||
import { IAgentLLMRequesterService, type LLMRequestFinish } from '#/agent/llmRequester';
|
||||
|
|
@ -151,11 +149,8 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
|
||||
const stepUuid = randomUUID();
|
||||
const turnStep = `${turnId}.${String(currentStep)}`;
|
||||
const emit = (event: AgentEvent): void => {
|
||||
this.record.signal(event);
|
||||
};
|
||||
|
||||
emit({ type: 'turn.step.started', turnId, step: currentStep, stepId: stepUuid });
|
||||
this.record.signal({ type: 'turn.step.started', turnId, step: currentStep, stepId: stepUuid });
|
||||
|
||||
const emitStreamPart = this.createStreamPartHandler(turnId);
|
||||
const response = await this.llmRequester.request(
|
||||
|
|
@ -164,7 +159,7 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
retry: {
|
||||
maxAttempts: this.config.get<LoopControl>(LOOP_CONTROL_SECTION)?.maxRetriesPerStep,
|
||||
onRetry: (retry) => {
|
||||
emit({
|
||||
this.record.signal({
|
||||
type: 'turn.step.retrying',
|
||||
turnId,
|
||||
step: currentStep,
|
||||
|
|
@ -201,7 +196,6 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
const toolResults = await this.toolExecutor.execute(response.message.toolCalls, {
|
||||
signal,
|
||||
turnId,
|
||||
dispatchProtocolEvent: emit,
|
||||
onToolResult: (toolCallId, result) => {
|
||||
this.append({
|
||||
...createToolMessage(toolCallId, toolResultOutputForModel(result)),
|
||||
|
|
@ -209,9 +203,6 @@ export class AgentLoopService implements IAgentLoopService {
|
|||
isError: result.isError,
|
||||
});
|
||||
},
|
||||
onProgress: (toolCallId, update) => {
|
||||
emit({ type: 'tool.progress', turnId, toolCallId, update });
|
||||
},
|
||||
});
|
||||
if (toolResults.some((r) => r.stopTurn === true)) {
|
||||
finishReason = 'completed';
|
||||
|
|
|
|||
|
|
@ -1,11 +1,9 @@
|
|||
import { createDecorator } from '#/_base/di';
|
||||
import type {
|
||||
ToolResult,
|
||||
ToolUpdate,
|
||||
ToolDidExecuteContext,
|
||||
ToolWillExecuteContext,
|
||||
} from '#/agent/tool';
|
||||
import type { AgentEvent } from '@moonshot-ai/protocol';
|
||||
import type { ToolCall } from '#/app/llmProtocol';
|
||||
import type { OrderedHookSlot } from '#/hooks';
|
||||
|
||||
|
|
@ -13,8 +11,6 @@ export interface ToolExecutorExecuteOptions {
|
|||
readonly signal: AbortSignal;
|
||||
readonly turnId: number;
|
||||
readonly onToolResult?: (toolCallId: string, result: ToolResult) => void | Promise<void>;
|
||||
readonly dispatchProtocolEvent?: (event: AgentEvent) => void;
|
||||
readonly onProgress?: (toolCallId: string, update: ToolUpdate) => void;
|
||||
}
|
||||
|
||||
export interface IAgentToolExecutorService {
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import {
|
|||
import { PathSecurityError } from '#/_base/tools/policies/path-access';
|
||||
import { isUserCancellation } from "#/_base/utils/abort";
|
||||
import { isAbortError } from '#/agent/loop/errors';
|
||||
import { IAgentRecordService } from '#/agent/record';
|
||||
import {
|
||||
ToolAccesses,
|
||||
type ExecutableTool,
|
||||
|
|
@ -20,6 +21,7 @@ import {
|
|||
type ToolDidExecuteContext,
|
||||
type ToolExecution,
|
||||
type ToolResult,
|
||||
type ToolUpdate,
|
||||
type ToolWillExecuteContext,
|
||||
} from '#/agent/tool';
|
||||
import { IAgentToolRegistryService } from '#/agent/toolRegistry';
|
||||
|
|
@ -58,6 +60,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
|
||||
constructor(
|
||||
@IAgentToolRegistryService private readonly toolRegistry: IAgentToolRegistryService,
|
||||
@IAgentRecordService private readonly record: IAgentRecordService,
|
||||
@ITelemetryService private readonly telemetry: ITelemetryService,
|
||||
@ILogService private readonly log?: ILogService,
|
||||
) {}
|
||||
|
|
@ -107,7 +110,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
const finalized = await this.finalizeToolResult(call, rawResult, options);
|
||||
results.push(finalized);
|
||||
|
||||
await dispatchToolResult(call, finalized, options);
|
||||
await this.dispatchToolResult(call, finalized, options);
|
||||
this.trackToolCall(call, finalized, timedResult.durationMs, options.turnId);
|
||||
}
|
||||
|
||||
|
|
@ -145,7 +148,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
output: string,
|
||||
displayFields?: ToolCallDisplayFields,
|
||||
): { task: ToolExecutionTask } => {
|
||||
dispatchToolCall(call, args, options, displayFields);
|
||||
this.dispatchToolCall(call, args, options, displayFields);
|
||||
return {
|
||||
task: makeResolvedTask(makeErrorToolResult(call, args, output)),
|
||||
};
|
||||
|
|
@ -160,7 +163,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
stopBatchAfterThis?: boolean;
|
||||
} => {
|
||||
const toolResult = this.normalizeAndMergeResult(result, call.toolName, undefined);
|
||||
dispatchToolCall(call, args, options, displayFields);
|
||||
this.dispatchToolCall(call, args, options, displayFields);
|
||||
return {
|
||||
task: makeResolvedTask({
|
||||
toolCall: call.toolCall,
|
||||
|
|
@ -223,7 +226,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
|
||||
const executionMetadata = decision?.executionMetadata;
|
||||
|
||||
dispatchToolCall(call, call.args, options, displayFields);
|
||||
this.dispatchToolCall(call, call.args, options, displayFields);
|
||||
|
||||
return {
|
||||
task: {
|
||||
|
|
@ -240,7 +243,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
options: ToolExecutorExecuteOptions,
|
||||
): ToolExecutionTask {
|
||||
const output = 'Tool skipped because a previous tool call stopped the turn.';
|
||||
dispatchToolCall(call, call.args, options);
|
||||
this.dispatchToolCall(call, call.args, options);
|
||||
return makeResolvedTask(makeErrorToolResult(call, call.args, output));
|
||||
}
|
||||
|
||||
|
|
@ -295,7 +298,7 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
signal,
|
||||
onUpdate: (update) => {
|
||||
if (signal.aborted) return;
|
||||
options.onProgress?.(call.toolCall.id, update);
|
||||
this.dispatchToolProgress(call, update, options);
|
||||
},
|
||||
});
|
||||
rawResult = await raceWithGraceTimeout(executePromise, signal, call.toolName);
|
||||
|
|
@ -326,6 +329,51 @@ export class AgentToolExecutorService implements IAgentToolExecutorService {
|
|||
};
|
||||
}
|
||||
|
||||
private dispatchToolCall(
|
||||
call: PreflightedToolCall,
|
||||
args: unknown,
|
||||
options: ToolExecutorExecuteOptions,
|
||||
displayFields?: ToolCallDisplayFields,
|
||||
): void {
|
||||
this.record.signal({
|
||||
type: 'tool.call.started',
|
||||
turnId: options.turnId,
|
||||
toolCallId: call.toolCall.id,
|
||||
name: call.toolName,
|
||||
args,
|
||||
description: displayFields?.description,
|
||||
display: displayFields?.display,
|
||||
});
|
||||
}
|
||||
|
||||
private async dispatchToolResult(
|
||||
call: PreflightedToolCall,
|
||||
result: ToolResult,
|
||||
options: ToolExecutorExecuteOptions,
|
||||
): Promise<void> {
|
||||
await options.onToolResult?.(call.toolCall.id, result);
|
||||
this.record.signal({
|
||||
type: 'tool.result',
|
||||
turnId: options.turnId,
|
||||
toolCallId: call.toolCall.id,
|
||||
output: result.output,
|
||||
isError: result.isError,
|
||||
});
|
||||
}
|
||||
|
||||
private dispatchToolProgress(
|
||||
call: RunnableToolCall,
|
||||
update: ToolUpdate,
|
||||
options: ToolExecutorExecuteOptions,
|
||||
): void {
|
||||
this.record.signal({
|
||||
type: 'tool.progress',
|
||||
turnId: options.turnId,
|
||||
toolCallId: call.toolCall.id,
|
||||
update,
|
||||
});
|
||||
}
|
||||
|
||||
private async finalizeToolResult(
|
||||
call: PreflightedToolCall,
|
||||
result: ToolResult,
|
||||
|
|
@ -504,38 +552,6 @@ function toolCallDisplayFieldsFromExecution(
|
|||
};
|
||||
}
|
||||
|
||||
function dispatchToolCall(
|
||||
call: PreflightedToolCall,
|
||||
args: unknown,
|
||||
options: ToolExecutorExecuteOptions,
|
||||
displayFields?: ToolCallDisplayFields,
|
||||
): void {
|
||||
options.dispatchProtocolEvent?.({
|
||||
type: 'tool.call.started',
|
||||
turnId: options.turnId,
|
||||
toolCallId: call.toolCall.id,
|
||||
name: call.toolName,
|
||||
args,
|
||||
description: displayFields?.description,
|
||||
display: displayFields?.display,
|
||||
});
|
||||
}
|
||||
|
||||
async function dispatchToolResult(
|
||||
call: PreflightedToolCall,
|
||||
result: ToolResult,
|
||||
options: ToolExecutorExecuteOptions,
|
||||
): Promise<void> {
|
||||
await options.onToolResult?.(call.toolCall.id, result);
|
||||
options.dispatchProtocolEvent?.({
|
||||
type: 'tool.result',
|
||||
turnId: options.turnId,
|
||||
toolCallId: call.toolCall.id,
|
||||
output: result.output,
|
||||
isError: result.isError,
|
||||
});
|
||||
}
|
||||
|
||||
function makeResolvedTask(result: PreparedToolResult): ToolExecutionTask {
|
||||
return {
|
||||
accesses: ToolAccesses.none(),
|
||||
|
|
|
|||
|
|
@ -16,8 +16,10 @@ import { IAgentToolRegistryService } from '#/agent/toolRegistry';
|
|||
import { AgentToolRegistryService } from '#/agent/toolRegistry/toolRegistryService';
|
||||
import { IAgentTurnService } from '#/agent/turn';
|
||||
import { IAgentProfileService } from '#/agent/profile';
|
||||
import { IAgentRecordService } from '#/agent/record';
|
||||
|
||||
import { createTestAgent, mcpServices, type TestAgentContext } from '../harness';
|
||||
import { stubRecord } from '../contextMemory/stubs';
|
||||
import { stubTurnWithHooks } from '../turn/stubs';
|
||||
import { discoverTools, executeTool, fakeMcpClient } from './stubs';
|
||||
|
||||
|
|
@ -139,6 +141,7 @@ describe('AgentMcpService', () => {
|
|||
on: () => toDisposable(() => {}),
|
||||
});
|
||||
ix.set(IAgentToolRegistryService, new SyncDescriptor(AgentToolRegistryService));
|
||||
ix.stub(IAgentRecordService, stubRecord());
|
||||
ix.set(IAgentToolExecutorService, new SyncDescriptor(AgentToolExecutorService));
|
||||
ix.stub(IAgentTurnService, stubTurnWithHooks());
|
||||
});
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ import { createServices } from '#/_base/di/test';
|
|||
import { ITelemetryService } from '#/app/telemetry';
|
||||
import type { ToolCall } from '#/app/llmProtocol';
|
||||
import { IAgentLoopService } from '#/agent/loop';
|
||||
import { IAgentRecordService } from '#/agent/record';
|
||||
import type { ExecutableTool, ExecutableToolContext, ToolExecution } from '#/agent/tool';
|
||||
import {
|
||||
IAgentToolDedupeService,
|
||||
|
|
@ -15,6 +16,7 @@ import type { ToolDedupResult } from '#/agent/toolDedupe';
|
|||
import { AgentToolExecutorService, IAgentToolExecutorService } from '#/agent/toolExecutor';
|
||||
import { AgentToolRegistryService, IAgentToolRegistryService } from '#/agent/toolRegistry';
|
||||
import { IAgentTurnService } from '#/agent/turn';
|
||||
import { stubRecord } from '../contextMemory/stubs';
|
||||
import { registerLogServices } from '../log/stubs';
|
||||
import { recordingTelemetry, type TelemetryRecord } from '../telemetry/stubs';
|
||||
import { stubLoopWithHooks, stubToolExecutor, stubTurnWithHooks } from '../turn/stubs';
|
||||
|
|
@ -159,6 +161,7 @@ describe('AgentToolDedupeService', () => {
|
|||
additionalServices: (reg) => {
|
||||
reg.defineInstance(ITelemetryService, recordingTelemetry(telemetryEvents));
|
||||
reg.defineInstance(IAgentLoopService, loop);
|
||||
reg.defineInstance(IAgentRecordService, stubRecord());
|
||||
reg.defineInstance(IAgentTurnService, stubTurnWithHooks());
|
||||
reg.define(IAgentToolRegistryService, AgentToolRegistryService);
|
||||
reg.define(IAgentToolExecutorService, AgentToolExecutorService);
|
||||
|
|
|
|||
|
|
@ -2,18 +2,21 @@ import type { ToolCall } from '#/app/llmProtocol/kosong';
|
|||
import type { AgentEvent, ToolInputDisplay } from '@moonshot-ai/protocol';
|
||||
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
||||
|
||||
import { SyncDescriptor } from '#/_base/di/descriptors';
|
||||
import { DisposableStore } from '#/_base/di/lifecycle';
|
||||
import { createServices, type TestInstantiationService } from '#/_base/di/test';
|
||||
import { AgentRecordService, IAgentRecordService } from '#/agent/record';
|
||||
import { ToolAccesses, type ExecutableTool, type ExecutableToolContext, type ExecutableToolResult, type ToolExecution, type ToolResult, type ToolUpdate } from '#/agent/tool';
|
||||
import { IAgentToolExecutorService, AgentToolExecutorService, parseToolCallArguments } from '#/agent/toolExecutor';
|
||||
import { IAgentToolRegistryService, AgentToolRegistryService } from '#/agent/toolRegistry';
|
||||
import { IAgentWireRecordService } from '#/agent/wireRecord';
|
||||
import { ITelemetryService } from '#/app/telemetry';
|
||||
import { stubWireRecord } from '../contextMemory/stubs';
|
||||
import { registerLogServices } from '../log/stubs';
|
||||
import { recordingTelemetry, type TelemetryRecord } from '../telemetry/stubs';
|
||||
|
||||
type ToolExecutorEvent =
|
||||
| { readonly type: 'tool.result'; readonly toolCallId: string; readonly result: ToolResult }
|
||||
| { readonly type: 'tool.progress'; readonly toolCallId: string; readonly update: ToolUpdate };
|
||||
| { readonly type: 'tool.result'; readonly toolCallId: string; readonly result: ToolResult };
|
||||
|
||||
let disposables: DisposableStore;
|
||||
let ix: TestInstantiationService;
|
||||
|
|
@ -32,11 +35,16 @@ beforeEach(() => {
|
|||
additionalServices: (reg) => {
|
||||
reg.define(IAgentToolRegistryService, AgentToolRegistryService);
|
||||
reg.define(IAgentToolExecutorService, AgentToolExecutorService);
|
||||
reg.defineInstance(IAgentWireRecordService, stubWireRecord());
|
||||
reg.defineInstance(ITelemetryService, recordingTelemetry(telemetryEvents));
|
||||
registerLogServices(reg);
|
||||
},
|
||||
strict: true,
|
||||
});
|
||||
ix.set(IAgentRecordService, new SyncDescriptor(AgentRecordService, [{}]));
|
||||
ix.get(IAgentRecordService).on((event) => {
|
||||
protocolEvents.push(event);
|
||||
});
|
||||
executor = ix.get(IAgentToolExecutorService);
|
||||
registry = ix.get(IAgentToolRegistryService);
|
||||
});
|
||||
|
|
@ -359,9 +367,9 @@ describe('AgentToolExecutorService', () => {
|
|||
|
||||
await execute([toolCall('call_progress', 'progress', {})]);
|
||||
|
||||
expect(events.filter((event) => event.type === 'tool.progress')).toEqual([
|
||||
{ type: 'tool.progress', toolCallId: 'call_progress', update: updates[0] },
|
||||
{ type: 'tool.progress', toolCallId: 'call_progress', update: updates[1] },
|
||||
expect(protocolEvents.filter((event) => event.type === 'tool.progress')).toEqual([
|
||||
{ type: 'tool.progress', turnId: 0, toolCallId: 'call_progress', update: updates[0] },
|
||||
{ type: 'tool.progress', turnId: 0, toolCallId: 'call_progress', update: updates[1] },
|
||||
]);
|
||||
});
|
||||
|
||||
|
|
@ -534,12 +542,6 @@ function execute(calls: ToolCall[], signal?: AbortSignal): Promise<ToolResult[]>
|
|||
onToolResult: (toolCallId, result) => {
|
||||
events.push({ type: 'tool.result', toolCallId, result });
|
||||
},
|
||||
dispatchProtocolEvent: (event) => {
|
||||
protocolEvents.push(event);
|
||||
},
|
||||
onProgress: (toolCallId, update) => {
|
||||
events.push({ type: 'tool.progress', toolCallId, update });
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
|
|
@ -568,9 +570,9 @@ function pairedToolCallIds(): { readonly calls: string[]; readonly results: stri
|
|||
event.type === 'tool.call.started',
|
||||
)
|
||||
.map((event) => event.toolCallId),
|
||||
results: events
|
||||
results: protocolEvents
|
||||
.filter(
|
||||
(event): event is Extract<ToolExecutorEvent, { type: 'tool.result' }> =>
|
||||
(event): event is Extract<AgentEvent, { type: 'tool.result' }> =>
|
||||
event.type === 'tool.result',
|
||||
)
|
||||
.map((event) => event.toolCallId),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue