@prometheus-ai/agent-core 0.5.4 → 0.5.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/types/agent-loop.d.ts +7 -0
- package/dist/types/agent.d.ts +41 -13
- package/dist/types/compaction/branch-summarization.d.ts +3 -3
- package/dist/types/compaction/compaction.d.ts +11 -9
- package/dist/types/compaction/messages.d.ts +14 -2
- package/dist/types/compaction/openai.d.ts +18 -3
- package/dist/types/compaction/pruning.d.ts +55 -0
- package/dist/types/compaction/shake.d.ts +3 -1
- package/dist/types/compaction/utils.d.ts +18 -2
- package/dist/types/proxy.d.ts +4 -3
- package/dist/types/telemetry.d.ts +59 -57
- package/dist/types/types.d.ts +60 -16
- package/package.json +6 -4
- package/src/agent-loop.ts +660 -181
- package/src/agent.ts +103 -30
- package/src/compaction/branch-summarization.ts +8 -7
- package/src/compaction/compaction.ts +69 -34
- package/src/compaction/messages.ts +78 -64
- package/src/compaction/openai.ts +88 -74
- package/src/compaction/prompts/branch-summary.md +1 -1
- package/src/compaction/prompts/compaction-summary-context.md +1 -1
- package/src/compaction/prompts/compaction-summary.md +2 -2
- package/src/compaction/prompts/compaction-update-summary.md +3 -3
- package/src/compaction/prompts/file-operations.md +3 -8
- package/src/compaction/prompts/summarization-system.md +1 -1
- package/src/compaction/pruning.ts +240 -8
- package/src/compaction/shake.ts +7 -3
- package/src/compaction/utils.ts +97 -19
- package/src/proxy.ts +13 -7
- package/src/telemetry.ts +126 -113
- package/src/types.ts +65 -16
package/src/agent.ts
CHANGED
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import { isPromise } from "node:util/types";
|
|
5
5
|
import {
|
|
6
|
+
type ApiKeyResolveContext,
|
|
6
7
|
type AssistantMessage,
|
|
7
8
|
type AssistantMessageEvent,
|
|
9
|
+
type Context,
|
|
8
10
|
type CursorExecHandlers,
|
|
9
11
|
type CursorToolResultHandler,
|
|
10
12
|
type Effort,
|
|
11
|
-
getBundledModel,
|
|
12
13
|
type ImageContent,
|
|
13
14
|
type Message,
|
|
14
15
|
type Model,
|
|
@@ -21,7 +22,9 @@ import {
|
|
|
21
22
|
type ToolChoice,
|
|
22
23
|
type ToolResultMessage,
|
|
23
24
|
} from "@prometheus-ai/ai";
|
|
24
|
-
import {
|
|
25
|
+
import { getBundledModel } from "@prometheus-ai/catalog/models";
|
|
26
|
+
import { logger } from "@prometheus-ai/utils";
|
|
27
|
+
import { abortReasonText, agentLoop, agentLoopContinue } from "./agent-loop";
|
|
25
28
|
import type { AppendOnlyContextManager } from "./append-only-context";
|
|
26
29
|
import type { HarmonyAuditEvent } from "./harmony-leak";
|
|
27
30
|
import type {
|
|
@@ -32,6 +35,7 @@ import type {
|
|
|
32
35
|
AgentState,
|
|
33
36
|
AgentTool,
|
|
34
37
|
AgentToolContext,
|
|
38
|
+
AsideMessage,
|
|
35
39
|
StreamFn,
|
|
36
40
|
ToolCallContext,
|
|
37
41
|
} from "./types";
|
|
@@ -91,6 +95,12 @@ export interface AgentOptions {
|
|
|
91
95
|
*/
|
|
92
96
|
transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
|
|
93
97
|
|
|
98
|
+
/**
|
|
99
|
+
* Optional transform applied after provider context assembly and before
|
|
100
|
+
* telemetry capture/provider send.
|
|
101
|
+
*/
|
|
102
|
+
transformProviderContext?: (context: Context, model: Model) => Context;
|
|
103
|
+
|
|
94
104
|
/**
|
|
95
105
|
* Steering mode: "all" = send all steering messages at once, "one-at-a-time" = one per turn
|
|
96
106
|
*/
|
|
@@ -108,12 +118,6 @@ export interface AgentOptions {
|
|
|
108
118
|
*/
|
|
109
119
|
interruptMode?: "immediate" | "wait";
|
|
110
120
|
|
|
111
|
-
/**
|
|
112
|
-
* Maximum completed tool calls to accept from one streamed assistant turn before
|
|
113
|
-
* executing the batch. Undefined disables batching.
|
|
114
|
-
*/
|
|
115
|
-
maxToolCallsPerTurn?: number;
|
|
116
|
-
|
|
117
121
|
/**
|
|
118
122
|
* API format for Kimi Code provider: "openai" or "anthropic" (default: "anthropic")
|
|
119
123
|
*/
|
|
@@ -132,6 +136,11 @@ export interface AgentOptions {
|
|
|
132
136
|
* Used by providers that support session-based caching (e.g., OpenAI Codex).
|
|
133
137
|
*/
|
|
134
138
|
sessionId?: string;
|
|
139
|
+
/**
|
|
140
|
+
* Optional prompt cache key forwarded to LLM providers.
|
|
141
|
+
* When omitted, providers may fall back to sessionId.
|
|
142
|
+
*/
|
|
143
|
+
promptCacheKey?: string;
|
|
135
144
|
/**
|
|
136
145
|
* Shared provider state map for session-scoped transport/session caches.
|
|
137
146
|
*/
|
|
@@ -141,7 +150,7 @@ export interface AgentOptions {
|
|
|
141
150
|
* Resolves an API key dynamically for each LLM call.
|
|
142
151
|
* Useful for expiring tokens (e.g., GitHub Copilot OAuth).
|
|
143
152
|
*/
|
|
144
|
-
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
153
|
+
getApiKey?: (provider: string, ctx?: ApiKeyResolveContext) => Promise<string | undefined> | string | undefined;
|
|
145
154
|
|
|
146
155
|
/**
|
|
147
156
|
* Inspect or replace provider payloads before they are sent.
|
|
@@ -264,6 +273,7 @@ export class Agent {
|
|
|
264
273
|
systemPrompt: [],
|
|
265
274
|
model: getBundledModel("google", "gemini-2.5-flash-lite-preview-06-17"),
|
|
266
275
|
thinkingLevel: undefined,
|
|
276
|
+
disableReasoning: false,
|
|
267
277
|
tools: [],
|
|
268
278
|
messages: [],
|
|
269
279
|
isStreaming: false,
|
|
@@ -276,13 +286,14 @@ export class Agent {
|
|
|
276
286
|
#abortController?: AbortController;
|
|
277
287
|
#convertToLlm: (messages: AgentMessage[]) => Message[] | Promise<Message[]>;
|
|
278
288
|
#transformContext?: (messages: AgentMessage[], signal?: AbortSignal) => Promise<AgentMessage[]>;
|
|
289
|
+
#transformProviderContext?: (context: Context, model: Model) => Context;
|
|
279
290
|
#steeringQueue: AgentMessage[] = [];
|
|
280
291
|
#followUpQueue: AgentMessage[] = [];
|
|
281
292
|
#steeringMode: "all" | "one-at-a-time";
|
|
282
293
|
#followUpMode: "all" | "one-at-a-time";
|
|
283
294
|
#interruptMode: "immediate" | "wait";
|
|
284
|
-
#maxToolCallsPerTurn?: number;
|
|
285
295
|
#sessionId?: string;
|
|
296
|
+
#promptCacheKey?: string;
|
|
286
297
|
#metadata?: Record<string, unknown>;
|
|
287
298
|
#metadataResolver?: (provider: string) => Record<string, unknown> | undefined;
|
|
288
299
|
#providerSessionState?: Map<string, ProviderSessionState>;
|
|
@@ -312,6 +323,7 @@ export class Agent {
|
|
|
312
323
|
#onAssistantMessageEvent?: (message: AssistantMessage, event: AssistantMessageEvent) => void;
|
|
313
324
|
#onHarmonyLeak?: (event: HarmonyAuditEvent) => void | Promise<void>;
|
|
314
325
|
#onBeforeYield?: () => Promise<void> | void;
|
|
326
|
+
#asideMessageProvider?: () => AsideMessage[] | Promise<AsideMessage[]>;
|
|
315
327
|
#telemetry?: AgentLoopConfig["telemetry"];
|
|
316
328
|
#appendOnlyContext?: AppendOnlyContextManager;
|
|
317
329
|
|
|
@@ -319,7 +331,7 @@ export class Agent {
|
|
|
319
331
|
#cursorToolResultBuffer: CursorToolResultEntry[] = [];
|
|
320
332
|
|
|
321
333
|
streamFn: StreamFn;
|
|
322
|
-
getApiKey?: (provider: string) => Promise<string | undefined> | string | undefined;
|
|
334
|
+
getApiKey?: (provider: string, ctx?: ApiKeyResolveContext) => Promise<string | undefined> | string | undefined;
|
|
323
335
|
/**
|
|
324
336
|
* Hook invoked after tool arguments are validated and before execution.
|
|
325
337
|
* Reassign at any time to swap the implementation (e.g. on extension reload).
|
|
@@ -341,9 +353,9 @@ export class Agent {
|
|
|
341
353
|
this.#steeringMode = opts.steeringMode || "one-at-a-time";
|
|
342
354
|
this.#followUpMode = opts.followUpMode || "one-at-a-time";
|
|
343
355
|
this.#interruptMode = opts.interruptMode || "immediate";
|
|
344
|
-
this.#maxToolCallsPerTurn = opts.maxToolCallsPerTurn;
|
|
345
356
|
this.streamFn = opts.streamFn || streamSimple;
|
|
346
357
|
this.#sessionId = opts.sessionId;
|
|
358
|
+
this.#promptCacheKey = opts.promptCacheKey;
|
|
347
359
|
this.#providerSessionState = opts.providerSessionState;
|
|
348
360
|
this.#thinkingBudgets = opts.thinkingBudgets;
|
|
349
361
|
this.#temperature = opts.temperature;
|
|
@@ -373,6 +385,7 @@ export class Agent {
|
|
|
373
385
|
this.afterToolCall = opts.afterToolCall;
|
|
374
386
|
this.#telemetry = opts.telemetry;
|
|
375
387
|
this.#appendOnlyContext = opts.appendOnlyContext;
|
|
388
|
+
this.#transformProviderContext = opts.transformProviderContext;
|
|
376
389
|
}
|
|
377
390
|
|
|
378
391
|
/**
|
|
@@ -390,6 +403,20 @@ export class Agent {
|
|
|
390
403
|
this.#sessionId = value;
|
|
391
404
|
}
|
|
392
405
|
|
|
406
|
+
/**
|
|
407
|
+
* Get the prompt cache key forwarded to providers.
|
|
408
|
+
*/
|
|
409
|
+
get promptCacheKey(): string | undefined {
|
|
410
|
+
return this.#promptCacheKey;
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
/**
|
|
414
|
+
* Set the prompt cache key forwarded to providers.
|
|
415
|
+
*/
|
|
416
|
+
set promptCacheKey(value: string | undefined) {
|
|
417
|
+
this.#promptCacheKey = value;
|
|
418
|
+
}
|
|
419
|
+
|
|
393
420
|
/**
|
|
394
421
|
* Static metadata forwarded to every API request when no resolver is installed
|
|
395
422
|
* (e.g. `metadata.user_id` for Anthropic session attribution). Setting this
|
|
@@ -564,14 +591,6 @@ export class Agent {
|
|
|
564
591
|
this.#maxRetryDelayMs = value;
|
|
565
592
|
}
|
|
566
593
|
|
|
567
|
-
get maxToolCallsPerTurn(): number | undefined {
|
|
568
|
-
return this.#maxToolCallsPerTurn;
|
|
569
|
-
}
|
|
570
|
-
|
|
571
|
-
set maxToolCallsPerTurn(value: number | undefined) {
|
|
572
|
-
this.#maxToolCallsPerTurn = value;
|
|
573
|
-
}
|
|
574
|
-
|
|
575
594
|
get state(): AgentState {
|
|
576
595
|
return this.#state;
|
|
577
596
|
}
|
|
@@ -607,6 +626,15 @@ export class Agent {
|
|
|
607
626
|
this.#onBeforeYield = fn;
|
|
608
627
|
}
|
|
609
628
|
|
|
629
|
+
/**
|
|
630
|
+
* Provide a source of non-interrupting "aside" messages (e.g. background-job
|
|
631
|
+
* completions, late LSP diagnostics) drained at each step boundary. Never
|
|
632
|
+
* aborts in-flight tools. See `AgentLoopConfig.getAsideMessages`.
|
|
633
|
+
*/
|
|
634
|
+
setAsideMessageProvider(fn: (() => AsideMessage[] | Promise<AsideMessage[]>) | undefined): void {
|
|
635
|
+
this.#asideMessageProvider = fn;
|
|
636
|
+
}
|
|
637
|
+
|
|
610
638
|
emitExternalEvent(event: AgentEvent) {
|
|
611
639
|
switch (event.type) {
|
|
612
640
|
case "message_start":
|
|
@@ -629,8 +657,8 @@ export class Agent {
|
|
|
629
657
|
}
|
|
630
658
|
|
|
631
659
|
// State mutators
|
|
632
|
-
setSystemPrompt(v: string[]) {
|
|
633
|
-
this.#state.systemPrompt = v;
|
|
660
|
+
setSystemPrompt(v: string[] | string) {
|
|
661
|
+
this.#state.systemPrompt = typeof v === "string" ? [v] : v;
|
|
634
662
|
}
|
|
635
663
|
|
|
636
664
|
setModel(m: Model) {
|
|
@@ -641,6 +669,10 @@ export class Agent {
|
|
|
641
669
|
this.#state.thinkingLevel = l;
|
|
642
670
|
}
|
|
643
671
|
|
|
672
|
+
setDisableReasoning(disabled: boolean) {
|
|
673
|
+
this.#state.disableReasoning = disabled;
|
|
674
|
+
}
|
|
675
|
+
|
|
644
676
|
setSteeringMode(mode: "all" | "one-at-a-time") {
|
|
645
677
|
this.#steeringMode = mode;
|
|
646
678
|
}
|
|
@@ -675,6 +707,11 @@ export class Agent {
|
|
|
675
707
|
this.#state.messages = ms.slice();
|
|
676
708
|
}
|
|
677
709
|
|
|
710
|
+
replaceQueues(steering: AgentMessage[], followUp: AgentMessage[]) {
|
|
711
|
+
this.#steeringQueue = steering.slice();
|
|
712
|
+
this.#followUpQueue = followUp.slice();
|
|
713
|
+
}
|
|
714
|
+
|
|
678
715
|
appendMessage(m: AgentMessage) {
|
|
679
716
|
this.#state.messages.push(m);
|
|
680
717
|
}
|
|
@@ -720,6 +757,24 @@ export class Agent {
|
|
|
720
757
|
return this.#steeringQueue.length > 0 || this.#followUpQueue.length > 0;
|
|
721
758
|
}
|
|
722
759
|
|
|
760
|
+
/** Non-consuming view of the pending steering queue (insertion order, newest
|
|
761
|
+
* last). The session layer derives its queued-message display/count from
|
|
762
|
+
* this live view instead of a mirror, so the agent-core queue stays the
|
|
763
|
+
* single source of truth. */
|
|
764
|
+
peekSteeringQueue(): readonly AgentMessage[] {
|
|
765
|
+
return this.#steeringQueue;
|
|
766
|
+
}
|
|
767
|
+
|
|
768
|
+
/** Non-consuming view of the pending follow-up queue. See
|
|
769
|
+
* {@link peekSteeringQueue}. */
|
|
770
|
+
peekFollowUpQueue(): readonly AgentMessage[] {
|
|
771
|
+
return this.#followUpQueue;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
get isAborting(): boolean {
|
|
775
|
+
return this.#abortController?.signal.aborted === true && this.#state.isStreaming;
|
|
776
|
+
}
|
|
777
|
+
|
|
723
778
|
#dequeueSteeringMessages(): AgentMessage[] {
|
|
724
779
|
if (this.#steeringMode === "one-at-a-time") {
|
|
725
780
|
if (this.#steeringQueue.length > 0) {
|
|
@@ -768,8 +823,8 @@ export class Agent {
|
|
|
768
823
|
this.#state.messages.length = 0;
|
|
769
824
|
}
|
|
770
825
|
|
|
771
|
-
abort() {
|
|
772
|
-
this.#abortController?.abort();
|
|
826
|
+
abort(reason?: unknown) {
|
|
827
|
+
this.#abortController?.abort(reason);
|
|
773
828
|
}
|
|
774
829
|
|
|
775
830
|
waitForIdle(): Promise<void> {
|
|
@@ -919,12 +974,18 @@ export class Agent {
|
|
|
919
974
|
}
|
|
920
975
|
: undefined;
|
|
921
976
|
|
|
922
|
-
const getToolChoice = () =>
|
|
923
|
-
this.#getToolChoice?.()
|
|
977
|
+
const getToolChoice = () => {
|
|
978
|
+
const queuedToolChoice = this.#getToolChoice?.();
|
|
979
|
+
if (queuedToolChoice !== undefined) {
|
|
980
|
+
return refreshToolChoiceForActiveTools(queuedToolChoice, this.#state.tools);
|
|
981
|
+
}
|
|
982
|
+
return refreshToolChoiceForActiveTools(options?.toolChoice, this.#state.tools);
|
|
983
|
+
};
|
|
924
984
|
|
|
925
985
|
const config: AgentLoopConfig = {
|
|
926
986
|
model,
|
|
927
987
|
reasoning,
|
|
988
|
+
disableReasoning: this.#state.disableReasoning,
|
|
928
989
|
temperature: this.#temperature,
|
|
929
990
|
topP: this.#topP,
|
|
930
991
|
topK: this.#topK,
|
|
@@ -934,8 +995,8 @@ export class Agent {
|
|
|
934
995
|
serviceTier: this.#serviceTier,
|
|
935
996
|
hideThinkingSummary: this.#hideThinkingSummary,
|
|
936
997
|
interruptMode: this.#interruptMode,
|
|
937
|
-
maxToolCallsPerTurn: this.#maxToolCallsPerTurn,
|
|
938
998
|
sessionId: this.#sessionId,
|
|
999
|
+
promptCacheKey: this.#promptCacheKey,
|
|
939
1000
|
metadata: this.#metadataResolver ? undefined : this.#metadata,
|
|
940
1001
|
metadataResolver: this.#metadataResolver,
|
|
941
1002
|
providerSessionState: this.#providerSessionState,
|
|
@@ -944,6 +1005,7 @@ export class Agent {
|
|
|
944
1005
|
kimiApiFormat: this.#kimiApiFormat,
|
|
945
1006
|
preferWebsockets: this.#preferWebsockets,
|
|
946
1007
|
convertToLlm: this.#convertToLlm,
|
|
1008
|
+
transformProviderContext: this.#transformProviderContext,
|
|
947
1009
|
transformContext: this.#transformContext,
|
|
948
1010
|
onPayload: this.#onPayload,
|
|
949
1011
|
onResponse: this.#onResponse,
|
|
@@ -968,6 +1030,7 @@ export class Agent {
|
|
|
968
1030
|
onHarmonyLeak: this.#onHarmonyLeak,
|
|
969
1031
|
getToolChoice,
|
|
970
1032
|
getReasoning: () => this.#state.thinkingLevel,
|
|
1033
|
+
getDisableReasoning: () => this.#state.disableReasoning,
|
|
971
1034
|
getSteeringMessages: async () => {
|
|
972
1035
|
if (skipInitialSteeringPoll) {
|
|
973
1036
|
skipInitialSteeringPoll = false;
|
|
@@ -975,7 +1038,9 @@ export class Agent {
|
|
|
975
1038
|
}
|
|
976
1039
|
return this.#dequeueSteeringMessages();
|
|
977
1040
|
},
|
|
1041
|
+
hasSteeringMessages: () => this.#steeringQueue.length > 0,
|
|
978
1042
|
getFollowUpMessages: async () => this.#dequeueFollowUpMessages(),
|
|
1043
|
+
getAsideMessages: async () => (await this.#asideMessageProvider?.()) ?? [],
|
|
979
1044
|
onBeforeYield: () => this.#onBeforeYield?.(),
|
|
980
1045
|
telemetry: this.#telemetry,
|
|
981
1046
|
};
|
|
@@ -1053,8 +1118,12 @@ export class Agent {
|
|
|
1053
1118
|
}
|
|
1054
1119
|
}
|
|
1055
1120
|
} catch (err) {
|
|
1056
|
-
const errorMessage = err instanceof Error ? err.message : String(err);
|
|
1057
1121
|
const stoppedForAbort = this.#abortController?.signal.aborted === true;
|
|
1122
|
+
const errorMessage = stoppedForAbort
|
|
1123
|
+
? abortReasonText(this.#abortController?.signal)
|
|
1124
|
+
: err instanceof Error
|
|
1125
|
+
? err.message
|
|
1126
|
+
: String(err);
|
|
1058
1127
|
const shouldEmitVisibleOutputBlockedError = !stoppedForAbort && isAnthropicOutputBlockedError(errorMessage);
|
|
1059
1128
|
const assistantPartial = partial?.role === "assistant" ? partial : undefined;
|
|
1060
1129
|
const hadAssistantStart = assistantPartial !== undefined;
|
|
@@ -1113,11 +1182,15 @@ export class Agent {
|
|
|
1113
1182
|
const result = listener(e) as unknown;
|
|
1114
1183
|
if (isPromise(result)) {
|
|
1115
1184
|
result.catch(err => {
|
|
1116
|
-
|
|
1185
|
+
logger.warn("Agent listener rejected", {
|
|
1186
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1187
|
+
});
|
|
1117
1188
|
});
|
|
1118
1189
|
}
|
|
1119
1190
|
} catch (err) {
|
|
1120
|
-
|
|
1191
|
+
logger.warn("Agent listener threw", {
|
|
1192
|
+
error: err instanceof Error ? err.message : String(err),
|
|
1193
|
+
});
|
|
1121
1194
|
}
|
|
1122
1195
|
}
|
|
1123
1196
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* a summary of the branch being left so context isn't lost.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type { Model } from "@prometheus-ai/ai";
|
|
8
|
+
import type { ApiKey, Model } from "@prometheus-ai/ai";
|
|
9
9
|
import { prompt } from "@prometheus-ai/utils";
|
|
10
10
|
import { type AgentTelemetry, instrumentedCompleteSimple } from "../telemetry";
|
|
11
11
|
import type { AgentMessage } from "../types";
|
|
@@ -13,10 +13,10 @@ import { estimateTokens } from "./compaction";
|
|
|
13
13
|
import type { ReadonlySessionManager, SessionEntry } from "./entries";
|
|
14
14
|
import {
|
|
15
15
|
type ConvertToLlm,
|
|
16
|
-
convertToLlm,
|
|
17
16
|
createBranchSummaryMessage,
|
|
18
17
|
createCompactionSummaryMessage,
|
|
19
18
|
createCustomMessage,
|
|
19
|
+
defaultConvertToLlm,
|
|
20
20
|
} from "./messages";
|
|
21
21
|
import branchSummaryPrompt from "./prompts/branch-summary.md" with { type: "text" };
|
|
22
22
|
import branchSummaryPreamble from "./prompts/branch-summary-preamble.md" with { type: "text" };
|
|
@@ -27,6 +27,7 @@ import {
|
|
|
27
27
|
type FileOperations,
|
|
28
28
|
SUMMARIZATION_SYSTEM_PROMPT,
|
|
29
29
|
serializeConversation,
|
|
30
|
+
stripReadSelector,
|
|
30
31
|
upsertFileOperations,
|
|
31
32
|
} from "./utils";
|
|
32
33
|
|
|
@@ -70,7 +71,7 @@ export interface GenerateBranchSummaryOptions {
|
|
|
70
71
|
/** Model to use for summarization */
|
|
71
72
|
model: Model;
|
|
72
73
|
/** API key for the model */
|
|
73
|
-
apiKey:
|
|
74
|
+
apiKey: ApiKey;
|
|
74
75
|
/** Abort signal for cancellation */
|
|
75
76
|
signal: AbortSignal;
|
|
76
77
|
/** Optional custom instructions for summarization */
|
|
@@ -83,7 +84,7 @@ export interface GenerateBranchSummaryOptions {
|
|
|
83
84
|
convertToLlm?: ConvertToLlm;
|
|
84
85
|
/**
|
|
85
86
|
* Optional telemetry handle. When provided, the branch summary LLM call is
|
|
86
|
-
* wrapped in an OTEL chat span tagged with `
|
|
87
|
+
* wrapped in an OTEL chat span tagged with `pi.gen_ai.oneshot.kind = "branch_summary"`.
|
|
87
88
|
*/
|
|
88
89
|
telemetry?: AgentTelemetry;
|
|
89
90
|
}
|
|
@@ -214,7 +215,7 @@ export function prepareBranchEntries(entries: SessionEntry[], tokenBudget: numbe
|
|
|
214
215
|
if (entry.type === "branch_summary" && !entry.fromExtension && entry.details) {
|
|
215
216
|
const details = entry.details as BranchSummaryDetails;
|
|
216
217
|
if (Array.isArray(details.readFiles)) {
|
|
217
|
-
for (const f of details.readFiles) fileOps.read.add(f);
|
|
218
|
+
for (const f of details.readFiles) fileOps.read.add(stripReadSelector(f));
|
|
218
219
|
}
|
|
219
220
|
if (Array.isArray(details.modifiedFiles)) {
|
|
220
221
|
// Modified files go into both edited and written for proper deduplication
|
|
@@ -288,7 +289,7 @@ export async function generateBranchSummary(
|
|
|
288
289
|
|
|
289
290
|
// Transform to LLM-compatible messages, then serialize to text
|
|
290
291
|
// Serialization prevents the model from treating it as a conversation to continue
|
|
291
|
-
const llmMessages = (options.convertToLlm ??
|
|
292
|
+
const llmMessages = (options.convertToLlm ?? defaultConvertToLlm)(messages);
|
|
292
293
|
const conversationText = serializeConversation(llmMessages);
|
|
293
294
|
|
|
294
295
|
// Build prompt
|
|
@@ -329,7 +330,7 @@ export async function generateBranchSummary(
|
|
|
329
330
|
|
|
330
331
|
// Compute file lists and append to summary
|
|
331
332
|
const { readFiles, modifiedFiles } = computeFileLists(fileOps);
|
|
332
|
-
summary = upsertFileOperations(summary, readFiles, modifiedFiles);
|
|
333
|
+
summary = upsertFileOperations(summary, readFiles, modifiedFiles, fileOps.read);
|
|
333
334
|
|
|
334
335
|
return {
|
|
335
336
|
summary: summary || "No summary generated",
|