Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/agents/pi-embedded-runner/run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,9 @@ export async function runEmbeddedPiAgent(
streamParams: params.streamParams,
ownerNumbers: params.ownerNumbers,
enforceFinalTag: params.enforceFinalTag,
promptContextMode: params.promptContextMode,
promptContextReason: params.promptContextReason,
compactionCountBeforeRun: params.compactionCountBeforeRun,
});

const {
Expand Down
10 changes: 8 additions & 2 deletions src/agents/pi-embedded-runner/run/attempt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -434,6 +434,7 @@ export async function runEmbeddedAttempt(
});
const ttsHint = params.config ? buildTtsSystemPromptHint(params.config) : undefined;

const promptContextMode = params.promptContextMode ?? "full";
const appendPrompt = buildEmbeddedSystemPrompt({
workspaceDir: effectiveWorkspace,
defaultThinkLevel: params.thinkLevel,
Expand All @@ -458,7 +459,9 @@ export async function runEmbeddedAttempt(
userTimezone,
userTime,
userTimeFormat,
contextFiles,
contextFiles: promptContextMode === "full" ? contextFiles : [],
projectContextMode: promptContextMode,
contextFilePaths: contextFiles.map((file) => file.path),
memoryCitationsMode: params.config?.memory?.citations,
});
const systemPromptReport = buildSystemPromptReport({
Expand All @@ -480,9 +483,12 @@ export async function runEmbeddedAttempt(
})(),
systemPrompt: appendPrompt,
bootstrapFiles: hookAdjustedBootstrapFiles,
injectedFiles: contextFiles,
injectedFiles: promptContextMode === "full" ? contextFiles : [],
skillsPrompt,
tools,
contextInjectionMode: promptContextMode,
contextInjectionReason: params.promptContextReason,
compactionCountAtBuild: params.compactionCountBeforeRun,
});
const systemPromptOverride = createSystemPromptOverride(appendPrompt);
const systemPromptText = systemPromptOverride();
Expand Down
11 changes: 11 additions & 0 deletions src/agents/pi-embedded-runner/run/params.ts
Original file line number Diff line number Diff line change
Expand Up @@ -101,4 +101,15 @@ export type RunEmbeddedPiAgentParams = {
streamParams?: AgentStreamParams;
ownerNumbers?: string[];
enforceFinalTag?: boolean;
/** Controls whether full project-context files are reinjected this turn. */
promptContextMode?: "full" | "delta";
/** Why promptContextMode was selected. */
promptContextReason?:
| "session-start"
| "session-reset"
| "compaction"
| "model-handoff"
| "steady-state";
/** Compaction count observed before this run (from session entry). */
compactionCountBeforeRun?: number;
};
4 changes: 4 additions & 0 deletions src/agents/pi-embedded-runner/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ export function buildEmbeddedSystemPrompt(params: {
userTime?: string;
userTimeFormat?: ResolvedTimeFormat;
contextFiles?: EmbeddedContextFile[];
projectContextMode?: "full" | "delta";
contextFilePaths?: string[];
memoryCitationsMode?: MemoryCitationsMode;
}): string {
return buildAgentSystemPrompt({
Expand All @@ -73,6 +75,8 @@ export function buildEmbeddedSystemPrompt(params: {
userTime: params.userTime,
userTimeFormat: params.userTimeFormat,
contextFiles: params.contextFiles,
projectContextMode: params.projectContextMode,
contextFilePaths: params.contextFilePaths,
memoryCitationsMode: params.memoryCitationsMode,
});
}
Expand Down
8 changes: 8 additions & 0 deletions src/agents/system-prompt-report.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ export function buildSystemPromptReport(params: {
injectedFiles: EmbeddedContextFile[];
skillsPrompt: string;
tools: AgentTool[];
contextInjectionMode?: SessionSystemPromptReport["contextInjectionMode"];
contextInjectionReason?: SessionSystemPromptReport["contextInjectionReason"];
compactionCountAtBuild?: number;
}): SessionSystemPromptReport {
const systemPrompt = params.systemPrompt.trim();
const projectContext = extractBetween(
Expand Down Expand Up @@ -155,6 +158,11 @@ export function buildSystemPromptReport(params: {
projectContextChars,
nonProjectContextChars: Math.max(0, systemPrompt.length - projectContextChars),
},
contextInjectionMode: params.contextInjectionMode,
contextInjectionReason: params.contextInjectionReason,
compactionCountAtBuild: params.compactionCountAtBuild,
fullPromptCompactionCount:
params.contextInjectionMode === "full" ? params.compactionCountAtBuild : undefined,
injectedWorkspaceFiles: buildInjectedWorkspaceFiles({
bootstrapFiles: params.bootstrapFiles,
injectedFiles: params.injectedFiles,
Expand Down
21 changes: 20 additions & 1 deletion src/agents/system-prompt.ts
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,10 @@ export function buildAgentSystemPrompt(params: {
userTime?: string;
userTimeFormat?: ResolvedTimeFormat;
contextFiles?: EmbeddedContextFile[];
/** Inject full project context files or only a lightweight delta note. */
projectContextMode?: "full" | "delta";
/** Paths to context files for delta-mode reminders. */
contextFilePaths?: string[];
skillsPrompt?: string;
heartbeatPrompt?: string;
docsPath?: string;
Expand Down Expand Up @@ -577,10 +581,14 @@ export function buildAgentSystemPrompt(params: {
}

const contextFiles = params.contextFiles ?? [];
const projectContextMode = params.projectContextMode ?? "full";
const validContextFiles = contextFiles.filter(
(file) => typeof file.path === "string" && file.path.trim().length > 0,
);
if (validContextFiles.length > 0) {
const deltaContextPaths = (params.contextFilePaths ?? validContextFiles.map((file) => file.path))
.map((value) => value.trim())
.filter(Boolean);
if (projectContextMode === "full" && validContextFiles.length > 0) {
const hasSoulFile = validContextFiles.some((file) => {
const normalizedPath = file.path.trim().replace(/\\/g, "/");
const baseName = normalizedPath.split("/").pop() ?? normalizedPath;
Expand All @@ -597,6 +605,17 @@ export function buildAgentSystemPrompt(params: {
lines.push(`## ${file.path}`, "", file.content, "");
}
}
if (projectContextMode === "delta" && deltaContextPaths.length > 0) {
lines.push(
"# Project Context (delta)",
"",
"Full project-context file contents were already injected earlier in this session.",
"Reinject full context on session starts/resets, compaction boundaries, and model/session handoffs.",
"Known context files:",
...deltaContextPaths.map((path) => `- ${path}`),
"",
);
}

// Skip silent replies for subagent/none modes
if (!isMinimal) {
Expand Down
3 changes: 3 additions & 0 deletions src/auto-reply/reply/agent-runner-utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,9 @@ export function buildEmbeddedRunBaseParams(params: {
skillsSnapshot: params.run.skillsSnapshot,
ownerNumbers: params.run.ownerNumbers,
enforceFinalTag: resolveEnforceFinalTag(params.run, params.provider),
promptContextMode: params.run.promptContextMode,
promptContextReason: params.run.promptContextReason,
compactionCountBeforeRun: params.run.compactionCountBeforeRun,
provider: params.provider,
model: params.model,
...params.authProfile,
Expand Down
4 changes: 4 additions & 0 deletions src/auto-reply/reply/followup-runner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,9 @@ export function createFollowupRunner(params: {
extraSystemPrompt: queued.run.extraSystemPrompt,
ownerNumbers: queued.run.ownerNumbers,
enforceFinalTag: queued.run.enforceFinalTag,
promptContextMode: queued.run.promptContextMode,
promptContextReason: queued.run.promptContextReason,
compactionCountBeforeRun: queued.run.compactionCountBeforeRun,
provider,
model,
...authProfile,
Expand Down Expand Up @@ -212,6 +215,7 @@ export function createFollowupRunner(params: {
modelUsed,
providerUsed: fallbackProvider,
contextTokensUsed,
systemPromptReport: runResult.meta?.systemPromptReport,
logLabel: "followup",
});
}
Expand Down
42 changes: 42 additions & 0 deletions src/auto-reply/reply/get-reply-run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,45 @@ export async function runPreparedReply(
isNewSession,
});
const authProfileIdSource = sessionEntry?.authProfileOverrideSource;
const compactionCountBeforeRun = sessionEntry?.compactionCount ?? 0;
const lastPromptReport = sessionEntry?.systemPromptReport;
const lastFullPromptCompactionCount = lastPromptReport?.fullPromptCompactionCount;
const hasCompactedSinceLastFullPrompt =
typeof lastFullPromptCompactionCount === "number"
? compactionCountBeforeRun > lastFullPromptCompactionCount
: compactionCountBeforeRun > 0;
const normalizedModelForCompare = (() => {
const trimmed = model.trim();
if (!trimmed) {
return trimmed;
}
const slashIndex = trimmed.indexOf("/");
return slashIndex >= 0 ? trimmed.slice(slashIndex + 1) : trimmed;
})();
const modelHandoffDetected =
!isNewSession &&
Boolean(
(sessionEntry?.modelProvider && sessionEntry.modelProvider !== provider) ||
(sessionEntry?.model && sessionEntry.model !== normalizedModelForCompare),
);
const promptContextMode: "full" | "delta" =
isNewSession || resetTriggered || hasCompactedSinceLastFullPrompt || modelHandoffDetected
? "full"
: "delta";
const promptContextReason:
| "session-start"
| "session-reset"
| "compaction"
| "model-handoff"
| "steady-state" = isNewSession
? "session-start"
: resetTriggered
? "session-reset"
: hasCompactedSinceLastFullPrompt
? "compaction"
: modelHandoffDetected
? "model-handoff"
: "steady-state";
const followupRun = {
prompt: queuedBody,
messageId: sessionCtx.MessageSidFull ?? sessionCtx.MessageSid,
Expand Down Expand Up @@ -431,6 +470,9 @@ export async function runPreparedReply(
blockReplyBreak: resolvedBlockStreamingBreak,
ownerNumbers: command.ownerList.length > 0 ? command.ownerList : undefined,
extraSystemPrompt: extraSystemPrompt || undefined,
promptContextMode,
promptContextReason,
compactionCountBeforeRun,
...(isReasoningTagProvider(provider) ? { enforceFinalTag: true } : {}),
},
};
Expand Down
11 changes: 11 additions & 0 deletions src/auto-reply/reply/queue/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,17 @@ export type FollowupRun = {
ownerNumbers?: string[];
extraSystemPrompt?: string;
enforceFinalTag?: boolean;
/** Controls whether full project-context files are reinjected this turn. */
promptContextMode?: "full" | "delta";
/** Why promptContextMode was selected. */
promptContextReason?:
| "session-start"
| "session-reset"
| "compaction"
| "model-handoff"
| "steady-state";
/** Compaction count observed before this run (from session entry). */
compactionCountBeforeRun?: number;
};
};

Expand Down
13 changes: 13 additions & 0 deletions src/config/sessions/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,19 @@ export type SessionSystemPromptReport = {
projectContextChars: number;
nonProjectContextChars: number;
};
/** Whether this run injected full project context files or used lightweight delta context. */
contextInjectionMode?: "full" | "delta";
/** Reason selected for this run's context injection mode. */
contextInjectionReason?:
| "session-start"
| "session-reset"
| "compaction"
| "model-handoff"
| "steady-state";
/** Compaction count observed when this prompt was built. */
compactionCountAtBuild?: number;
/** Latest compaction count for which a full prompt was injected. */
fullPromptCompactionCount?: number;
injectedWorkspaceFiles: Array<{
name: string;
path: string;
Expand Down