





























@@ -280,6 +280,7 @@ import {
280280import {
281281installContextEngineLoopHook,
282282installToolResultContextGuard,
283+markTranscriptPromptText,
283284} from "../tool-result-context-guard.js";
284285import {
285286resolveLiveToolResultMaxChars,
@@ -1025,6 +1026,136 @@ function installRuntimeContextMessageForPrompt(params: {
10251026};
10261027}
102710281029+function replaceLastUserTextPrompt(params: {
1030+messages: AgentMessage[];
1031+shouldCapture?: (message: AgentMessage) => boolean;
1032+transcriptText?: string;
1033+replace: (text: string) => string | undefined;
1034+}): AgentMessage[] {
1035+const userIndex = params.messages.findLastIndex((message) => message.role === "user");
1036+if (userIndex === -1) {
1037+return params.messages;
1038+}
1039+const message = params.messages[userIndex];
1040+if (!message || message.role !== "user") {
1041+return params.messages;
1042+}
1043+if (params.shouldCapture && !params.shouldCapture(message)) {
1044+return params.messages;
1045+}
1046+const content = (message as { content?: unknown }).content;
1047+if (typeof content === "string") {
1048+const replacement = params.replace(content);
1049+if (replacement === undefined) {
1050+return params.messages;
1051+}
1052+const next = params.messages.slice();
1053+next[userIndex] = { ...message, content: replacement } as AgentMessage;
1054+if (params.transcriptText !== undefined) {
1055+markTranscriptPromptText(next[userIndex], params.transcriptText);
1056+}
1057+return next;
1058+}
1059+if (!Array.isArray(content)) {
1060+return params.messages;
1061+}
1062+let replaced = false;
1063+const nextContent = content.map((block) => {
1064+if (replaced || !block || typeof block !== "object") {
1065+return block;
1066+}
1067+const textBlock = block as { type?: unknown; text?: unknown };
1068+if (textBlock.type !== "text" || typeof textBlock.text !== "string") {
1069+return block;
1070+}
1071+const replacement = params.replace(textBlock.text);
1072+if (replacement === undefined) {
1073+return block;
1074+}
1075+replaced = true;
1076+return Object.assign({}, block, { text: replacement });
1077+});
1078+if (!replaced) {
1079+return params.messages;
1080+}
1081+const next = params.messages.slice();
1082+next[userIndex] = { ...message, content: nextContent } as AgentMessage;
1083+if (params.transcriptText !== undefined) {
1084+markTranscriptPromptText(next[userIndex], params.transcriptText);
1085+}
1086+return next;
1087+}
1088+1089+function composeModelPromptContext(params: {
1090+prompt: string;
1091+prependContext?: string;
1092+appendContext?: string;
1093+}): string {
1094+return [params.prependContext, params.prompt, params.appendContext]
1095+.filter((value): value is string => Boolean(value?.trim()))
1096+.join("\n\n");
1097+}
1098+1099+function installModelPromptTransform(params: {
1100+session: AgentSession;
1101+transcriptPrompt: string;
1102+modelPrompt?: string;
1103+prependContext?: string;
1104+appendContext?: string;
1105+shouldCapturePrompt: () => boolean;
1106+}): () => void {
1107+const modelPrompt = params.modelPrompt;
1108+const hasPromptContext =
1109+Boolean(params.prependContext?.trim()) || Boolean(params.appendContext?.trim());
1110+if ((!modelPrompt?.trim() || modelPrompt === params.transcriptPrompt) && !hasPromptContext) {
1111+return () => undefined;
1112+}
1113+const agent = params.session.agent as {
1114+transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
1115+};
1116+const originalTransformContext = agent.transformContext;
1117+let targetPromptTimestamp: number | undefined;
1118+agent.transformContext = async (messages, signal) => {
1119+const promptMessages = replaceLastUserTextPrompt({
1120+ messages,
1121+transcriptText: params.transcriptPrompt,
1122+shouldCapture: (message) => {
1123+const timestamp = (message as { timestamp?: unknown }).timestamp;
1124+if (targetPromptTimestamp !== undefined) {
1125+return timestamp === targetPromptTimestamp;
1126+}
1127+if (!params.shouldCapturePrompt()) {
1128+return false;
1129+}
1130+if (typeof timestamp === "number") {
1131+targetPromptTimestamp = timestamp;
1132+}
1133+return true;
1134+},
1135+replace: (text) => {
1136+if (modelPrompt?.trim() && text === params.transcriptPrompt) {
1137+return modelPrompt;
1138+}
1139+if (!hasPromptContext) {
1140+return undefined;
1141+}
1142+const replacement = composeModelPromptContext({
1143+prompt: text,
1144+prependContext: params.prependContext,
1145+appendContext: params.appendContext,
1146+});
1147+return replacement === text ? undefined : replacement;
1148+},
1149+});
1150+return originalTransformContext
1151+ ? await originalTransformContext.call(agent, promptMessages, signal)
1152+ : promptMessages;
1153+};
1154+return () => {
1155+agent.transformContext = originalTransformContext;
1156+};
1157+}
1158+10281159function appendRuntimeContextMessageForPrompt(params: {
10291160message: RuntimeContextCustomMessage;
10301161messages: AgentMessage[];
@@ -3868,6 +3999,11 @@ export async function runEmbeddedAttempt(
38683999 hookRunner,
38694000beforeAgentStartResult: params.beforeAgentStartResult,
38704001});
4002+const promptBeforePromptBuildHooks = effectivePrompt;
4003+const promptBuildPrependContext = hookResult?.prependContext;
4004+const promptBuildAppendContext = hookResult?.appendContext;
4005+const hasPromptBuildContext =
4006+Boolean(promptBuildPrependContext?.trim()) || Boolean(promptBuildAppendContext?.trim());
38714007{
38724008if (hookResult?.prependContext) {
38734009effectivePrompt = `${hookResult.prependContext}\n\n${effectivePrompt}`;
@@ -3953,15 +4089,37 @@ export async function runEmbeddedAttempt(
39534089`embedded run prompt start: runId=${params.runId} sessionId=${params.sessionId} ` +
39544090routingSummary,
39554091);
4092+const effectiveTranscriptPrompt =
4093+params.transcriptPrompt === undefined ? undefined : params.transcriptPrompt;
4094+let transcriptPromptForRuntimeSplit = effectiveTranscriptPrompt;
4095+let promptForRuntimeContextSplit = promptBeforePromptBuildHooks;
39564096// Repair orphaned trailing user messages so new prompts don't violate role ordering.
39574097const leafEntry = isRawModelRun ? null : sessionManager.getLeafEntry();
39584098if (leafEntry?.type === "message" && leafEntry.message.role === "user") {
3959-const orphanPromptMerge = resolveMessageMergeStrategy().mergeOrphanedTrailingUserPrompt({
4099+const messageMergeStrategy = resolveMessageMergeStrategy();
4100+const orphanPromptMerge = messageMergeStrategy.mergeOrphanedTrailingUserPrompt({
39604101prompt: effectivePrompt,
39614102trigger: params.trigger,
39624103leafMessage: leafEntry.message,
39634104});
4105+const runtimePromptMerge = messageMergeStrategy.mergeOrphanedTrailingUserPrompt({
4106+prompt: promptForRuntimeContextSplit,
4107+trigger: params.trigger,
4108+leafMessage: leafEntry.message,
4109+});
4110+const transcriptPromptMerge =
4111+effectiveTranscriptPrompt === undefined
4112+ ? undefined
4113+ : messageMergeStrategy.mergeOrphanedTrailingUserPrompt({
4114+prompt: effectiveTranscriptPrompt,
4115+trigger: params.trigger,
4116+leafMessage: leafEntry.message,
4117+});
39644118effectivePrompt = orphanPromptMerge.prompt;
4119+promptForRuntimeContextSplit = runtimePromptMerge.prompt;
4120+if (transcriptPromptMerge) {
4121+transcriptPromptForRuntimeSplit = transcriptPromptMerge.prompt;
4122+}
39654123if (orphanPromptMerge.removeLeaf) {
39664124if (leafEntry.parentId) {
39674125sessionManager.branch(leafEntry.parentId);
@@ -3989,11 +4147,13 @@ export async function runEmbeddedAttempt(
39894147log.debug(orphanRepairMessage);
39904148}
39914149}
4150+const promptForModelBeforeRuntimeContextSplit = effectivePrompt;
39924151if (!isRawModelRun) {
3993-effectivePrompt = annotateInterSessionPromptText(effectivePrompt, params.inputProvenance);
4152+promptForRuntimeContextSplit = annotateInterSessionPromptText(
4153+promptForRuntimeContextSplit,
4154+params.inputProvenance,
4155+);
39944156}
3995-const effectiveTranscriptPrompt =
3996-params.transcriptPrompt === undefined ? undefined : params.transcriptPrompt;
39974157const transcriptLeafId =
39984158(sessionManager.getLeafEntry() as { id?: string } | null | undefined)?.id ?? null;
39994159const heartbeatSummary =
@@ -4013,16 +4173,23 @@ export async function runEmbeddedAttempt(
40134173prePromptMessageCount = activeSession.messages.length;
4014417440154175const promptSubmission = resolveRuntimeContextPromptParts({
4016- effectivePrompt,
4017-transcriptPrompt: effectiveTranscriptPrompt,
4176+effectivePrompt: promptForRuntimeContextSplit,
4177+transcriptPrompt: transcriptPromptForRuntimeSplit,
4178+modelPrompt: hasPromptBuildContext
4179+ ? promptForModelBeforeRuntimeContextSplit
4180+ : undefined,
40184181emptyTranscriptMode: params.suppressNextUserMessagePersistence
40194182 ? "model-prompt"
40204183 : "runtime-event",
40214184});
4022-const promptForModel = buildCurrentInboundPrompt({
4185+const promptForSession = buildCurrentInboundPrompt({
40234186context: params.currentInboundContext,
40244187prompt: promptSubmission.prompt,
40254188});
4189+const promptForModel = buildCurrentInboundPrompt({
4190+context: params.currentInboundContext,
4191+prompt: promptSubmission.modelPrompt ?? promptSubmission.prompt,
4192+});
40264193const runtimeSystemContext = promptSubmission.runtimeSystemContext?.trim();
40274194if (promptSubmission.runtimeOnly && runtimeSystemContext) {
40284195const runtimeSystemPrompt = composeSystemPromptWithHookContext({
@@ -4471,7 +4638,7 @@ export async function runEmbeddedAttempt(
44714638if (normalizedReplayMessages !== activeSession.messages) {
44724639activeSession.agent.state.messages = normalizedReplayMessages;
44734640}
4474-finalPromptText = promptForModel;
4641+finalPromptText = promptForSession;
44754642trajectoryRecorder?.recordEvent("prompt.submitted", {
44764643prompt: promptForModel,
44774644systemPrompt: systemPromptForHook,
@@ -4482,26 +4649,51 @@ export async function runEmbeddedAttempt(
44824649updateActiveEmbeddedRunSnapshot(params.sessionId, {
44834650 transcriptLeafId,
44844651messages: btwSnapshotMessages,
4485-inFlightPrompt: promptForModel,
4652+inFlightPrompt: promptForSession,
44864653});
4487-if (promptSubmission.runtimeOnly) {
4488-await promptActiveSession(promptForModel);
4489-} else {
4490-const cleanupRuntimeContextMessage = installRuntimeContextMessageForPrompt({
4491-session: activeSession,
4492-message: runtimeContextMessageForCurrentTurn,
4493-});
4494-try {
4495-// Only pass images option if there are actually images to pass
4496-// This avoids potential issues with models that don't expect the images parameter
4497-if (imageResult.images.length > 0) {
4498-await promptActiveSession(promptForModel, { images: imageResult.images });
4499-} else {
4500-await promptActiveSession(promptForModel);
4654+let captureCurrentPromptForModel = false;
4655+const cleanupModelPromptTransform = installModelPromptTransform({
4656+session: activeSession,
4657+transcriptPrompt: promptForSession,
4658+modelPrompt: promptForModel,
4659+prependContext: promptBuildPrependContext,
4660+appendContext: promptBuildAppendContext,
4661+shouldCapturePrompt: () => captureCurrentPromptForModel,
4662+});
4663+const armModelPromptTransform = (submitted: boolean) => {
4664+if (submitted) {
4665+captureCurrentPromptForModel = true;
4666+}
4667+};
4668+try {
4669+if (promptSubmission.runtimeOnly) {
4670+await promptActiveSession(promptForSession, {
4671+preflightResult: armModelPromptTransform,
4672+});
4673+} else {
4674+const cleanupRuntimeContextMessage = installRuntimeContextMessageForPrompt({
4675+session: activeSession,
4676+message: runtimeContextMessageForCurrentTurn,
4677+});
4678+try {
4679+// Only pass images option if there are actually images to pass
4680+// This avoids potential issues with models that don't expect the images parameter
4681+if (imageResult.images.length > 0) {
4682+await promptActiveSession(promptForSession, {
4683+images: imageResult.images,
4684+preflightResult: armModelPromptTransform,
4685+});
4686+} else {
4687+await promptActiveSession(promptForSession, {
4688+preflightResult: armModelPromptTransform,
4689+});
4690+}
4691+} finally {
4692+cleanupRuntimeContextMessage();
45014693}
4502-} finally {
4503-cleanupRuntimeContextMessage();
45044694}
4695+} finally {
4696+cleanupModelPromptTransform();
45054697}
45064698}
45074699} catch (err) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。