mirror of
https://github.com/earendil-works/pi.git
synced 2026-10-02 00:35:27 +08:00
feat(coding-agent): support compaction routing sessions
This commit is contained in:
@@ -1873,6 +1873,7 @@ export class AgentSession {
|
||||
env,
|
||||
this.settingsManager.getRetrySettings(),
|
||||
this._summarizationRetryCallbacks({ source: "compaction", reason: "manual" }),
|
||||
undefined, // sessionId
|
||||
);
|
||||
summary = result.summary;
|
||||
firstKeptEntryId = result.firstKeptEntryId;
|
||||
@@ -2161,6 +2162,7 @@ export class AgentSession {
|
||||
env,
|
||||
this.settingsManager.getRetrySettings(),
|
||||
this._summarizationRetryCallbacks({ source: "compaction", reason }),
|
||||
undefined, // sessionId
|
||||
);
|
||||
summary = compactResult.summary;
|
||||
firstKeptEntryId = compactResult.firstKeptEntryId;
|
||||
|
||||
@@ -544,8 +544,9 @@ function createSummarizationOptions(
|
||||
env: Record<string, string> | undefined,
|
||||
signal: AbortSignal | undefined,
|
||||
thinkingLevel: ThinkingLevel | undefined,
|
||||
sessionId: string | undefined,
|
||||
): SimpleStreamOptions {
|
||||
const options: SimpleStreamOptions = { maxTokens, signal, apiKey, headers, env };
|
||||
const options: SimpleStreamOptions = { maxTokens, signal, apiKey, headers, env, sessionId };
|
||||
if (model.reasoning && thinkingLevel && thinkingLevel !== "off") {
|
||||
options.reasoning = thinkingLevel;
|
||||
}
|
||||
@@ -567,11 +568,12 @@ export async function completeSummarization(
|
||||
retry?: RetryPolicy,
|
||||
callbacks?: RetryCallbacks,
|
||||
): Promise<AssistantMessage> {
|
||||
// Summaries are standalone requests, so isolate routing and avoid cache writes that cannot be reused.
|
||||
// Avoid cache writes for one-off summaries. Reuse caller-supplied routing when available;
|
||||
// callers without a session ID, including branch summaries, receive a fresh routing ID.
|
||||
const requestOptions: SimpleStreamOptions = {
|
||||
...options,
|
||||
cacheRetention: "none",
|
||||
sessionId: uuidv7(),
|
||||
sessionId: options.sessionId ?? uuidv7(),
|
||||
};
|
||||
const produce = async (): Promise<AssistantMessage> =>
|
||||
streamFn
|
||||
@@ -598,6 +600,7 @@ export async function generateSummary(
|
||||
env?: Record<string, string>,
|
||||
retry?: RetryPolicy,
|
||||
callbacks?: RetryCallbacks,
|
||||
sessionId?: string,
|
||||
): Promise<string> {
|
||||
return (
|
||||
await generateSummaryWithUsage(
|
||||
@@ -614,6 +617,7 @@ export async function generateSummary(
|
||||
env,
|
||||
retry,
|
||||
callbacks,
|
||||
sessionId,
|
||||
)
|
||||
).text;
|
||||
}
|
||||
@@ -633,6 +637,7 @@ export async function generateSummaryWithUsage(
|
||||
env?: Record<string, string>,
|
||||
retry?: RetryPolicy,
|
||||
callbacks?: RetryCallbacks,
|
||||
sessionId?: string,
|
||||
): Promise<{ text: string; usage: Usage }> {
|
||||
const maxTokens = Math.min(
|
||||
Math.floor(0.8 * reserveTokens),
|
||||
@@ -665,7 +670,16 @@ export async function generateSummaryWithUsage(
|
||||
},
|
||||
];
|
||||
|
||||
const completionOptions = createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel);
|
||||
const completionOptions = createSummarizationOptions(
|
||||
model,
|
||||
maxTokens,
|
||||
apiKey,
|
||||
headers,
|
||||
env,
|
||||
signal,
|
||||
thinkingLevel,
|
||||
sessionId,
|
||||
);
|
||||
|
||||
const response = await completeSummarization(
|
||||
model,
|
||||
@@ -813,6 +827,7 @@ Be concise. Focus on what's needed to understand the kept suffix.`;
|
||||
*
|
||||
* @param preparation - Pre-calculated preparation from prepareCompaction()
|
||||
* @param customInstructions - Optional custom focus for the summary
|
||||
* @param sessionId - Optional routing session ID forwarded without enabling prompt caching
|
||||
*/
|
||||
export async function compact(
|
||||
preparation: CompactionPreparation,
|
||||
@@ -826,6 +841,7 @@ export async function compact(
|
||||
env?: Record<string, string>,
|
||||
retry?: RetryPolicy,
|
||||
callbacks?: RetryCallbacks,
|
||||
sessionId?: string,
|
||||
): Promise<CompactionResult> {
|
||||
const {
|
||||
firstKeptEntryId,
|
||||
@@ -860,6 +876,7 @@ export async function compact(
|
||||
env,
|
||||
retry,
|
||||
callbacks,
|
||||
sessionId,
|
||||
);
|
||||
historyText = historyResult.text;
|
||||
historyUsage = historyResult.usage;
|
||||
@@ -876,6 +893,7 @@ export async function compact(
|
||||
streamFn,
|
||||
retry,
|
||||
callbacks,
|
||||
sessionId,
|
||||
);
|
||||
// Merge into single summary
|
||||
summary = `${historyText}\n\n---\n\n**Turn Context (split turn):**\n\n${turnPrefixResult.text}`;
|
||||
@@ -896,6 +914,7 @@ export async function compact(
|
||||
env,
|
||||
retry,
|
||||
callbacks,
|
||||
sessionId,
|
||||
);
|
||||
summary = result.text;
|
||||
summaryUsage = result.usage;
|
||||
@@ -933,6 +952,7 @@ async function generateTurnPrefixSummary(
|
||||
streamFn?: StreamFn,
|
||||
retry?: RetryPolicy,
|
||||
callbacks?: RetryCallbacks,
|
||||
sessionId?: string,
|
||||
): Promise<{ text: string; usage: Usage }> {
|
||||
const maxTokens = Math.min(
|
||||
Math.floor(0.5 * reserveTokens),
|
||||
@@ -952,7 +972,7 @@ async function generateTurnPrefixSummary(
|
||||
const response = await completeSummarization(
|
||||
model,
|
||||
{ systemPrompt: SUMMARIZATION_SYSTEM_PROMPT, messages: summarizationMessages },
|
||||
createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel),
|
||||
createSummarizationOptions(model, maxTokens, apiKey, headers, env, signal, thinkingLevel, sessionId),
|
||||
streamFn,
|
||||
retry,
|
||||
callbacks,
|
||||
|
||||
@@ -4,6 +4,7 @@ import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import {
|
||||
type CompactionPreparation,
|
||||
compact,
|
||||
completeSummarization,
|
||||
generateSummary,
|
||||
generateSummaryWithUsage,
|
||||
} from "../src/core/compaction/index.ts";
|
||||
@@ -102,6 +103,19 @@ describe("generateSummary reasoning options", () => {
|
||||
expect(sessionIds[0]).not.toBe(sessionIds[1]);
|
||||
});
|
||||
|
||||
it("honors a caller-supplied routing session without prompt caching", async () => {
|
||||
await completeSummarization(
|
||||
createModel(false),
|
||||
{ systemPrompt: "Summarize", messages: [] },
|
||||
{ sessionId: "current-routing-session", cacheRetention: "long" },
|
||||
);
|
||||
|
||||
expect(completeSimpleMock.mock.calls[0][2]).toMatchObject({
|
||||
sessionId: "current-routing-session",
|
||||
cacheRetention: "none",
|
||||
});
|
||||
});
|
||||
|
||||
it("does not set reasoning when thinking is off", async () => {
|
||||
await generateSummary(
|
||||
messages,
|
||||
|
||||
Reference in New Issue
Block a user