mirror of
https://github.com/n8n-io/n8n.git
synced 2026-10-19 16:55:02 +02:00
refactor(core): Move prompt assembly into runtime context
This commit is contained in:
parent
61e41f966b
commit
d8275daabb
|
|
@ -55,14 +55,8 @@ import { createFilteredLogger } from '../logger';
|
|||
import { MemoryOrchestrator } from '../memory/memory-orchestrator';
|
||||
import { generateThreadTitle } from '../memory/title-generation';
|
||||
import { AgentMessageList, type SerializedMessageList } from '../model/message-list';
|
||||
import { supportsSplitSystemMessages } from '../model/model-factory';
|
||||
import { createModelTokenCounter } from '../model/model-token-counter';
|
||||
import {
|
||||
applyRuntimeCacheBreakpoints,
|
||||
buildInstructionPromptCacheOptions,
|
||||
getEffectiveAnthropicCacheTtl,
|
||||
mergeProviderOptions,
|
||||
} from '../model/prompt-cache';
|
||||
import { getEffectiveAnthropicCacheTtl } from '../model/prompt-cache';
|
||||
import { ActiveSkills } from '../skills/active-skills';
|
||||
import { BackgroundTaskTracker } from '../state/background-task-tracker';
|
||||
import { AgentEventBus, type AgentAbortScope } from '../state/event-bus';
|
||||
|
|
@ -758,11 +752,7 @@ export class AgentRuntime {
|
|||
...options,
|
||||
persistence: options?.persistence,
|
||||
});
|
||||
// Explicit instruction options take precedence over cache defaults.
|
||||
const instructionProviderOptions = mergeProviderOptions(
|
||||
buildInstructionPromptCacheOptions(this.config.promptCaching, this.modelIdString),
|
||||
this.config.instructionProviderOptions,
|
||||
);
|
||||
const instructionProviderOptions = this.context.buildInstructionProviderOptions();
|
||||
const state: LoopState = {
|
||||
totalUsage: undefined,
|
||||
lastFinishReason: 'stop',
|
||||
|
|
@ -900,23 +890,20 @@ export class AgentRuntime {
|
|||
list,
|
||||
);
|
||||
const hostVolatileInstructions = await this.resolveVolatileInstructions(options?.persistence);
|
||||
const { system, messages } = this.buildModelPrompt(ctx, tools, hostVolatileInstructions);
|
||||
// Cache breakpoints apply to this call only. Do not change stored messages or tools.
|
||||
const cached = applyRuntimeCacheBreakpoints({
|
||||
system,
|
||||
messages: this.activeSkills?.modelMessages(messages, list) ?? messages,
|
||||
aiTools: tools.aiTools,
|
||||
promptCaching: this.config.promptCaching,
|
||||
modelId: this.modelIdString,
|
||||
staticToolCacheName: tools.staticToolCacheName,
|
||||
const prompt = this.context.buildModelPrompt({
|
||||
list,
|
||||
tools,
|
||||
instructionProviderOptions: ctx.instructionProviderOptions,
|
||||
hostVolatileInstructions,
|
||||
activeSkills: this.activeSkills,
|
||||
});
|
||||
const modelCallContext: ModelCallContext = {
|
||||
model: staticContext.model,
|
||||
system,
|
||||
messages: cached.messages,
|
||||
system: prompt.system,
|
||||
messages: prompt.messages,
|
||||
abortSignal: abortScope.signal,
|
||||
hasTools: tools.hasTools,
|
||||
aiTools: cached.aiTools,
|
||||
aiTools: prompt.aiTools,
|
||||
reasoning: staticContext.reasoning,
|
||||
providerOptions: staticContext.providerOptions,
|
||||
outputSpec: staticContext.outputSpec,
|
||||
|
|
@ -927,26 +914,6 @@ export class AgentRuntime {
|
|||
return { toolMap: tools.toolMap, modelCallContext };
|
||||
}
|
||||
|
||||
private buildModelPrompt(
|
||||
ctx: PreparedLoopContext,
|
||||
tools: ReturnType<RuntimeContextBuilder['buildToolLoopContext']>,
|
||||
hostVolatileInstructions: string | undefined,
|
||||
) {
|
||||
const combinedVolatileInstructions = [tools.volatileInstructions, hostVolatileInstructions]
|
||||
.map((value) => value?.trim())
|
||||
.filter((value): value is string => Boolean(value))
|
||||
.join('\n\n');
|
||||
return ctx.list.forLlm(
|
||||
// Skill content changes only on activation. Keep it cached when memory compacts.
|
||||
[tools.effectiveInstructions, this.activeSkills?.instructions()]
|
||||
.filter(Boolean)
|
||||
.join('\n\n'),
|
||||
ctx.instructionProviderOptions,
|
||||
combinedVolatileInstructions || undefined,
|
||||
supportsSplitSystemMessages(this.config.model),
|
||||
);
|
||||
}
|
||||
|
||||
private createInputRejectionHandler(
|
||||
ctx: PreparedLoopContext,
|
||||
iterationCount: number,
|
||||
|
|
|
|||
|
|
@ -23,13 +23,19 @@ import {
|
|||
} from '../memory/episodic-memory-capture';
|
||||
import { loadAi } from '../model/lazy-ai';
|
||||
import type { AgentMessageList } from '../model/message-list';
|
||||
import { createModel } from '../model/model-factory';
|
||||
import { buildCallPromptCacheOptions, mergeProviderOptions } from '../model/prompt-cache';
|
||||
import { createModel, supportsSplitSystemMessages } from '../model/model-factory';
|
||||
import {
|
||||
applyRuntimeCacheBreakpoints,
|
||||
buildCallPromptCacheOptions,
|
||||
buildInstructionPromptCacheOptions,
|
||||
mergeProviderOptions,
|
||||
} from '../model/prompt-cache';
|
||||
import {
|
||||
getProviderQuirks,
|
||||
PROVIDER_QUIRKS,
|
||||
resolveDefaultMaxOutputTokens,
|
||||
} from '../model/provider-quirks';
|
||||
import type { ActiveSkills } from '../skills/active-skills';
|
||||
import type { DeferredToolManager } from '../tools/deferred-tool-manager';
|
||||
import { buildToolMap, toAiSdkProviderTools, toAiSdkTools } from '../tools/tool-adapter';
|
||||
|
||||
|
|
@ -109,6 +115,14 @@ export class RuntimeContextBuilder {
|
|||
return Output.object({ schema });
|
||||
}
|
||||
|
||||
buildInstructionProviderOptions(): ProviderOptions | undefined {
|
||||
// Explicit instruction options take precedence over cache defaults.
|
||||
return mergeProviderOptions(
|
||||
buildInstructionPromptCacheOptions(this.config.promptCaching, this.modelId),
|
||||
this.config.instructionProviderOptions,
|
||||
);
|
||||
}
|
||||
|
||||
/** Build the current local tool view; deferred loads can change this between iterations. */
|
||||
buildToolLoopContext(
|
||||
aiProviderTools: ReturnType<typeof toAiSdkProviderTools>,
|
||||
|
|
@ -134,6 +148,44 @@ export class RuntimeContextBuilder {
|
|||
};
|
||||
}
|
||||
|
||||
buildModelPrompt({
|
||||
list,
|
||||
tools,
|
||||
instructionProviderOptions,
|
||||
hostVolatileInstructions,
|
||||
activeSkills,
|
||||
}: {
|
||||
list: AgentMessageList;
|
||||
tools: ReturnType<RuntimeContextBuilder['buildToolLoopContext']>;
|
||||
instructionProviderOptions: ProviderOptions | undefined;
|
||||
hostVolatileInstructions: string | undefined;
|
||||
activeSkills: ActiveSkills | undefined;
|
||||
}) {
|
||||
const combinedVolatileInstructions = [tools.volatileInstructions, hostVolatileInstructions]
|
||||
.map((value) => value?.trim())
|
||||
.filter((value): value is string => Boolean(value))
|
||||
.join('\n\n');
|
||||
const { system, messages } = list.forLlm(
|
||||
// Skill content changes only on activation. Keep it cached when memory compacts.
|
||||
[tools.effectiveInstructions, activeSkills?.instructions()]
|
||||
.filter(Boolean)
|
||||
.join('\n\n'),
|
||||
instructionProviderOptions,
|
||||
combinedVolatileInstructions || undefined,
|
||||
supportsSplitSystemMessages(this.config.model),
|
||||
);
|
||||
// Cache breakpoints apply to this call only. Do not change stored messages or tools.
|
||||
const cached = applyRuntimeCacheBreakpoints({
|
||||
system,
|
||||
messages: activeSkills?.modelMessages(messages, list) ?? messages,
|
||||
aiTools: tools.aiTools,
|
||||
promptCaching: this.config.promptCaching,
|
||||
modelId: this.modelId,
|
||||
staticToolCacheName: tools.staticToolCacheName,
|
||||
});
|
||||
return { system, ...cached };
|
||||
}
|
||||
|
||||
/**
|
||||
* Name of the tool eligible for an Anthropic tool-definitions cache
|
||||
* breakpoint, or `undefined` if the tool set isn't fully static. Deferred
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user