@sayknow-cli/agent-core 0.3.16 → 0.4.0

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.
@@ -1,298 +0,0 @@
1
- /**
2
- * Context compaction for long sessions.
3
- *
4
- * Pure functions for compaction logic. The session manager handles I/O,
5
- * and after compaction the session is reloaded.
6
- */
7
- import { type MessageAttribution, type Model, type ProviderSessionState, type Usage } from "@sayknow-cli/ai";
8
- import { type AgentTelemetry } from "../telemetry";
9
- import type { AgentMessage, AgentTool } from "../types";
10
- import type { SessionEntry } from "./entries";
11
- import { type ConvertToLlm } from "./messages";
12
- import { type FileOperations } from "./utils";
13
- /** Details stored in CompactionEntry.details for file tracking */
14
- export interface CompactionDetails {
15
- readFiles: string[];
16
- modifiedFiles: string[];
17
- }
18
- /** Result from compact() - SessionManager adds uuid/parentUuid when saving */
19
- export interface CompactionResult<T = unknown> {
20
- summary: string;
21
- /** Short PR-style summary for display purposes. */
22
- shortSummary?: string;
23
- firstKeptEntryId: string;
24
- tokensBefore: number;
25
- /** Hook-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
26
- details?: T;
27
- /** Hook-provided data to persist alongside compaction entry. */
28
- preserveData?: Record<string, unknown>;
29
- }
30
- export interface CompactionSettings {
31
- enabled: boolean;
32
- strategy?: "context-full" | "handoff" | "off";
33
- thresholdPercent?: number;
34
- thresholdTokens?: number;
35
- reserveTokens: number;
36
- keepRecentTokens: number;
37
- autoContinue?: boolean;
38
- remoteEnabled?: boolean;
39
- remoteEndpoint?: string;
40
- }
41
- export declare const DEFAULT_COMPACTION_SETTINGS: CompactionSettings;
42
- /**
43
- * Calculate total context tokens from usage.
44
- * Uses the native totalTokens field when available, falls back to computing from components.
45
- */
46
- export declare function calculateContextTokens(usage: Usage): number;
47
- export declare function calculatePromptTokens(usage: Usage): number;
48
- /**
49
- * Find the last non-aborted assistant message usage from session entries.
50
- */
51
- export declare function getLastAssistantUsage(entries: SessionEntry[]): Usage | undefined;
52
- /**
53
- * Effective reserve: the largest of 15% of the context window, the configured floor,
54
- * and the model's reserved completion budget (`maxOutputTokens`).
55
- *
56
- * Reserving `maxOutputTokens` keeps the safe input/prompt-packing budget below the
57
- * *total* context window for models whose completion reservation exceeds the 15%
58
- * floor (e.g. a 400K-context model with 128K max output reserves 128K, not 60K, so
59
- * input is capped near 272K instead of 340K).
60
- */
61
- export declare function effectiveReserveTokens(contextWindow: number, settings: CompactionSettings, maxOutputTokens?: number): number;
62
- /**
63
- * Check if compaction should trigger based on context usage.
64
- *
65
- * `maxOutputTokens` is the model's reserved completion budget; it is excluded from
66
- * the safe input budget so prompt + reserved output cannot exceed the total window.
67
- */
68
- export declare function shouldCompact(contextTokens: number, contextWindow: number, settings: CompactionSettings, maxOutputTokens?: number): boolean;
69
- /** Reason a compaction was triggered. `token` is the normal user-configurable path; the rest are emergency floors. */
70
- export type CompactionTriggerReason = "token" | "heap" | "retainedMemory" | "providerBytes" | "messageCount" | "imageBytes";
71
- /** A point-in-time resource sample. Supplied by an injectable sampler so tests never read real RSS. */
72
- export interface EmergencyCompactionSample {
73
- /** Resident heap bytes (e.g. process.memoryUsage().heapUsed). */
74
- heapUsedBytes: number;
75
- /** Approximate serialized provider-context bytes. */
76
- providerBytes: number;
77
- /** Provider-visible message count. */
78
- messageCount: number;
79
- /** Approximate inline image bytes in the provider context. */
80
- imageBytes: number;
81
- /** Bytes retained by session resident image sentinels; separate from provider-visible bytes. */
82
- sessionResidentImageBytes?: number;
83
- /** Bytes retained by non-provider materialized/session-local caches. */
84
- materializedResidentBytes?: number;
85
- /** Number of live TUI chat-container children. */
86
- tuiChatChildren?: number;
87
- /** Bytes retained by TUI render caches. */
88
- tuiCachedRenderBytes?: number;
89
- }
90
- export interface EmergencyCompactionLimits {
91
- heapUsedBytes: number;
92
- providerBytes: number;
93
- messageCount: number;
94
- imageBytes: number;
95
- retainedMemoryBytes?: number;
96
- retainedMemoryDiagnosticBytes?: number;
97
- tuiChatChildren?: number;
98
- tuiChatChildrenDiagnostic?: number;
99
- }
100
- export declare function resetEmergencyRetainedMemoryDiagnosticsForTests(): void;
101
- export declare function resolveEmergencyCompactionLimits(totalMemoryBytes?: number): EmergencyCompactionLimits;
102
- /**
103
- * Non-disableable emergency floors. These sit well above normal usage and exist so a
104
- * long session on weak hardware compacts before OOM even when token-based compaction is
105
- * disabled or its threshold is set too high. They are NOT user-tunable down to zero.
106
- */
107
- export declare const DEFAULT_EMERGENCY_COMPACTION_LIMITS: EmergencyCompactionLimits;
108
- /**
109
- * Returns the first emergency limit exceeded (heap > retainedMemory > providerBytes > imageBytes > messageCount),
110
- * or null when none is. Pure apart from retained-memory diagnostics; the caller routes the result through the
111
- * normal pair-safe `compact()` cut logic so a tool_use/tool_result pair is never split.
112
- */
113
- export declare function emergencyCompactionReason(sample: EmergencyCompactionSample, limits?: EmergencyCompactionLimits): CompactionTriggerReason | null;
114
- export declare function resolveThresholdTokens(contextWindow: number, settings: CompactionSettings, maxOutputTokens?: number): number;
115
- /**
116
- * Image content has no tokenizer representation; charge a fixed estimate
117
- * matching what providers typically bill for inline images.
118
- */
119
- export declare const IMAGE_TOKEN_ESTIMATE = 1200;
120
- /**
121
- * Native-free token estimate for a message. This is the only message
122
- * token estimator: provider usage (see {@link calculatePromptTokens}) anchors
123
- * the already-sent context, and this covers unsent/trailing deltas, per-entry
124
- * budgeting, and display surfaces. Callers add a conservative inflation factor
125
- * where compaction-threshold safety requires it.
126
- */
127
- export declare function estimateMessageTokensHeuristic(message: AgentMessage): number;
128
- /**
129
- * Script-aware native-free token estimate for plain string fragments.
130
- * Fragment-level counterpart of {@link estimateMessageTokensHeuristic}.
131
- */
132
- export declare function estimateTextTokensHeuristic(fragments: string | readonly string[]): number;
133
- export declare function estimateEntryTokens(entry: SessionEntry): number;
134
- export declare function estimateEntriesTokens(entries: SessionEntry[], startIndex: number, endIndex: number): number;
135
- /**
136
- * Find the user message (or bashExecution) that starts the turn containing the given entry index.
137
- * Returns -1 if no turn start found before the index.
138
- * BashExecutionMessage is treated like a user message for turn boundaries.
139
- */
140
- export declare function findTurnStartIndex(entries: SessionEntry[], entryIndex: number, startIndex: number): number;
141
- export interface CutPointResult {
142
- /** Index of first entry to keep */
143
- firstKeptEntryIndex: number;
144
- /** Index of user message that starts the turn being split, or -1 if not splitting */
145
- turnStartIndex: number;
146
- /** Whether this cut splits a turn (cut point is not a user message) */
147
- isSplitTurn: boolean;
148
- }
149
- /**
150
- * Find the cut point in session entries that keeps approximately `keepRecentTokens`.
151
- *
152
- * Algorithm: Walk backwards from newest, accumulating estimated message sizes.
153
- * Stop when we've accumulated >= keepRecentTokens. Cut at that point.
154
- *
155
- * Can cut at user OR assistant messages (never tool results). When cutting at an
156
- * assistant message with tool calls, its tool results come after and will be kept.
157
- *
158
- * Returns CutPointResult with:
159
- * - firstKeptEntryIndex: the entry index to start keeping from
160
- * - turnStartIndex: if cutting mid-turn, the user message that started that turn
161
- * - isSplitTurn: whether we're cutting in the middle of a turn
162
- *
163
- * Only considers entries between `startIndex` and `endIndex` (exclusive).
164
- */
165
- export declare function findCutPoint(entries: SessionEntry[], startIndex: number, endIndex: number, keepRecentTokens: number): CutPointResult;
166
- export declare const AUTO_HANDOFF_THRESHOLD_FOCUS: string;
167
- /**
168
- * Generate a summary of the conversation using the LLM.
169
- * If previousSummary is provided, uses the update prompt to merge.
170
- */
171
- export interface SummaryOptions {
172
- promptOverride?: string;
173
- extraContext?: string[];
174
- remoteEndpoint?: string;
175
- remoteInstructions?: string;
176
- initiatorOverride?: MessageAttribution;
177
- metadata?: Record<string, unknown>;
178
- convertToLlm?: ConvertToLlm;
179
- /**
180
- * Optional telemetry handle. When provided, every LLM call emitted during
181
- * compaction is wrapped in an OTEL chat span tagged with
182
- * `pi.gen_ai.oneshot.kind` (`compaction_summary`, `compaction_short_summary`,
183
- * or `compaction_turn_prefix`). `undefined` keeps the call paths zero-cost.
184
- */
185
- telemetry?: AgentTelemetry;
186
- authCredentialType?: "api_key" | "oauth";
187
- /**
188
- * Provider session affinity id forwarded to the maintenance LLM call so it
189
- * reuses the live turn's provider/WebSocket session (matches the
190
- * `providerSessionId ?? sessionId` the agent loop sends for normal turns).
191
- */
192
- sessionId?: string;
193
- /** Shared provider state map so maintenance calls reuse session-scoped transport/session caches. */
194
- providerSessionState?: Map<string, ProviderSessionState>;
195
- /** Hint that websocket transport should be preferred when supported by the provider implementation. */
196
- preferWebsockets?: boolean;
197
- }
198
- /**
199
- * Cap the serialized conversation fed to a summarization request so the request
200
- * itself fits inside the model's context window.
201
- *
202
- * Without this, summarizing a near-full context serializes (nearly) the entire
203
- * history back into a single summary request; on strict backends (e.g.
204
- * OpenAI-code/Codex `context_length_exceeded`) that request itself overflows and
205
- * throws, so context-overflow recovery cannot produce a summary and the agent
206
- * fails to compact-and-continue — a non-interactive `skc -p` run then terminates
207
- * on the very overflow the recovery was meant to absorb.
208
- *
209
- * The budget reserves the summary's own output tokens plus prompt/system/template
210
- * overhead, and applies a conservative safety factor for estimator error on
211
- * dense text (the reason the original overflow was missed).
212
- * Truncation keeps the head (origin/goals) and the tail (most recent state) and
213
- * elides the middle; it is a last resort that only triggers when the input would
214
- * otherwise not fit.
215
- */
216
- export declare function boundConversationTextForSummary(conversationText: string, model: Model, outputMaxTokens: number): string;
217
- export declare function generateSummary(currentMessages: AgentMessage[], model: Model, reserveTokens: number, apiKey: string, signal?: AbortSignal, customInstructions?: string, previousSummary?: string, options?: SummaryOptions): Promise<string>;
218
- export interface HandoffOptions {
219
- /** Live agent system prompt — passed verbatim so providers hit the cached prefix. */
220
- systemPrompt: string[];
221
- /** Live agent tool list — same purpose. Forced to `toolChoice: "none"`. */
222
- tools?: AgentTool<any>[];
223
- customInstructions?: string;
224
- convertToLlm?: ConvertToLlm;
225
- initiatorOverride?: MessageAttribution;
226
- metadata?: Record<string, unknown>;
227
- /**
228
- * Optional telemetry handle. When provided, the handoff LLM call is
229
- * wrapped in an OTEL chat span tagged with `pi.gen_ai.oneshot.kind = "handoff"`.
230
- */
231
- telemetry?: AgentTelemetry;
232
- authCredentialType?: "api_key" | "oauth";
233
- /**
234
- * Provider session affinity id forwarded to the handoff LLM call so it
235
- * reuses the live turn's provider/WebSocket session.
236
- */
237
- sessionId?: string;
238
- /** Shared provider state map so the handoff call reuses session-scoped transport/session caches. */
239
- providerSessionState?: Map<string, ProviderSessionState>;
240
- /** Hint that websocket transport should be preferred when supported by the provider implementation. */
241
- preferWebsockets?: boolean;
242
- }
243
- export declare function renderHandoffPrompt(customInstructions?: string): string;
244
- export declare function generateHandoff(messages: AgentMessage[], model: Model, apiKey: string, options: HandoffOptions, signal?: AbortSignal): Promise<string>;
245
- export interface CompactionPreparation {
246
- /** UUID of first entry to keep */
247
- firstKeptEntryId: string;
248
- /** Messages that will be summarized and discarded */
249
- messagesToSummarize: AgentMessage[];
250
- /** Messages that will be turned into turn prefix summary (if splitting) */
251
- turnPrefixMessages: AgentMessage[];
252
- /** Messages kept in full after compaction (recent history) */
253
- recentMessages: AgentMessage[];
254
- /** Whether this is a split turn (cut point in middle of turn) */
255
- isSplitTurn: boolean;
256
- tokensBefore: number;
257
- /** Summary from previous compaction, for iterative update */
258
- previousSummary?: string;
259
- /** Preserved opaque compaction payload from the previous compaction, if any. */
260
- previousPreserveData?: Record<string, unknown>;
261
- /** File operations extracted from messagesToSummarize */
262
- fileOps: FileOperations;
263
- /** Compaction settions from settings.jsonl */
264
- settings: CompactionSettings;
265
- /**
266
- * Diagnostics for the keep-window token correction (Finding 7). `ratio` is the
267
- * clamped heuristic→actual correction that was applied (1 when none supplied);
268
- * `keepRecentTokensCorrected` is the heuristic budget findCutPoint actually used.
269
- */
270
- tokenCorrection: {
271
- ratio: number;
272
- keepRecentTokensCorrected: number;
273
- };
274
- }
275
- /** Bounds for the keep-window token correction (Finding 7): never trust a ratio
276
- * beyond 2x in either direction so a bad estimate cannot balloon or collapse the
277
- * kept window. */
278
- export declare const TOKEN_CORRECTION_MIN_RATIO = 0.5;
279
- export declare const TOKEN_CORRECTION_MAX_RATIO = 2;
280
- export interface PrepareCompactionOptions {
281
- /**
282
- * Observed heuristic→actual token correction for the post-boundary keep window
283
- * (actualTokens / chars-4-heuristicTokens), supplied by the caller from per-turn
284
- * Usage deltas or a stable-prefix-subtracted comparison. Clamped to
285
- * [0.5, 2] and applied bidirectionally. When omitted, no correction is applied
286
- * (the confounded raw promptTokens/estimatedTokens quotient is never used).
287
- */
288
- tokenCorrectionRatio?: number;
289
- }
290
- export declare function prepareCompaction(pathEntries: SessionEntry[], settings: CompactionSettings, options?: PrepareCompactionOptions): CompactionPreparation | undefined;
291
- /**
292
- * Generate summaries for compaction using prepared data.
293
- * Returns CompactionResult - SessionManager adds id/parentId when saving.
294
- *
295
- * @param preparation - Pre-calculated preparation from prepareCompaction()
296
- * @param customInstructions - Optional custom focus for the summary
297
- */
298
- export declare function compact(preparation: CompactionPreparation, model: Model, apiKey: string, customInstructions?: string, signal?: AbortSignal, options?: SummaryOptions): Promise<CompactionResult>;
@@ -1,109 +0,0 @@
1
- import type { ImageContent, MessageAttribution, ServiceTier, TextContent } from "@sayknow-cli/ai";
2
- import type { AgentMessage } from "../types";
3
- export interface SessionEntryBase {
4
- type: string;
5
- id: string;
6
- parentId: string | null;
7
- timestamp: string;
8
- }
9
- export interface SessionMessageEntry extends SessionEntryBase {
10
- type: "message";
11
- message: AgentMessage;
12
- }
13
- export interface ThinkingLevelChangeEntry extends SessionEntryBase {
14
- type: "thinking_level_change";
15
- thinkingLevel?: string | null;
16
- }
17
- export interface ModelChangeEntry extends SessionEntryBase {
18
- type: "model_change";
19
- /** Model in "provider/modelId" format */
20
- model: string;
21
- /** Role: "default", "smol", "slow", etc. Undefined treated as "default" */
22
- role?: string;
23
- /** Requested model before a runtime substitution/fallback, in "provider/modelId" format. */
24
- previousModel?: string;
25
- /** Machine-readable reason for runtime model substitution/fallback. */
26
- reason?: string;
27
- /** Effective thinking level when the change was recorded. */
28
- thinkingLevel?: string | null;
29
- }
30
- export interface ServiceTierChangeEntry extends SessionEntryBase {
31
- type: "service_tier_change";
32
- serviceTier: ServiceTier | null;
33
- }
34
- export interface CompactionEntry<T = unknown> extends SessionEntryBase {
35
- type: "compaction";
36
- summary: string;
37
- shortSummary?: string;
38
- firstKeptEntryId: string;
39
- tokensBefore: number;
40
- /** Extension-specific data (e.g., ArtifactIndex, version markers for structured compaction) */
41
- details?: T;
42
- /** Hook-provided data to persist across compaction */
43
- preserveData?: Record<string, unknown>;
44
- /** True if generated by an extension, undefined/false if pi-generated (backward compatible) */
45
- fromExtension?: boolean;
46
- }
47
- export interface BranchSummaryEntry<T = unknown> extends SessionEntryBase {
48
- type: "branch_summary";
49
- fromId: string;
50
- summary: string;
51
- /** Extension-specific data (not sent to LLM) */
52
- details?: T;
53
- /** True if generated by an extension, false if pi-generated */
54
- fromExtension?: boolean;
55
- }
56
- export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
57
- type: "custom_message";
58
- customType: string;
59
- content: string | (TextContent | ImageContent)[];
60
- details?: T;
61
- display: boolean;
62
- /** Who initiated this message for billing/attribution semantics. */
63
- attribution?: MessageAttribution;
64
- }
65
- export interface CustomEntry<T = unknown> extends SessionEntryBase {
66
- type: "custom";
67
- customType: string;
68
- data?: T;
69
- }
70
- export interface LabelEntry extends SessionEntryBase {
71
- type: "label";
72
- targetId: string;
73
- label: string | undefined;
74
- }
75
- export interface TtsrInjectionEntry extends SessionEntryBase {
76
- type: "ttsr_injection";
77
- /** Names of rules that were injected */
78
- injectedRules: string[];
79
- }
80
- export interface MCPToolSelectionEntry extends SessionEntryBase {
81
- type: "mcp_tool_selection";
82
- /** MCP tool names selected for visibility in discovery mode. */
83
- selectedToolNames: string[];
84
- }
85
- export interface SessionInitEntry extends SessionEntryBase {
86
- type: "session_init";
87
- /** Full system prompt sent to the model */
88
- systemPrompt: string;
89
- /** Initial task/user message */
90
- task: string;
91
- /** Tools available to the agent */
92
- tools: string[];
93
- /** Output schema if structured output was requested */
94
- outputSchema?: unknown;
95
- }
96
- export interface ModeChangeEntry extends SessionEntryBase {
97
- type: "mode_change";
98
- /** Current mode name, or "none" when exiting a mode */
99
- mode: string;
100
- /** Optional mode-specific data (e.g. plan file path) */
101
- data?: Record<string, unknown>;
102
- }
103
- export interface CustomCompactionSessionEntries {
104
- }
105
- export type SessionEntry = SessionMessageEntry | ThinkingLevelChangeEntry | ModelChangeEntry | ServiceTierChangeEntry | CompactionEntry | BranchSummaryEntry | CustomEntry | CustomMessageEntry | LabelEntry | TtsrInjectionEntry | MCPToolSelectionEntry | SessionInitEntry | ModeChangeEntry | CustomCompactionSessionEntries[keyof CustomCompactionSessionEntries];
106
- export interface ReadonlySessionManager {
107
- getBranch(leafId?: string | null): SessionEntry[];
108
- getEntry(id: string): SessionEntry | undefined;
109
- }
@@ -1,26 +0,0 @@
1
- /**
2
- * Compaction error types.
3
- *
4
- * `CompactionCancelledError` is the canonical signal raised when a compaction
5
- * is explicitly aborted — operator Esc, extension hook returning `cancel`,
6
- * programmatic `session.abortCompaction()` call, or any other deliberate
7
- * abort source. Downstream callers (e.g. `executeCompaction`) discriminate
8
- * cancellation from other failures via `instanceof CompactionCancelledError`
9
- * rather than introspecting error messages or `name` fields — the typed
10
- * sentinel makes classification source-agnostic and refactor-stable.
11
- */
12
- export declare class CompactionCancelledError extends Error {
13
- readonly name: "CompactionCancelledError";
14
- constructor(message?: string);
15
- }
16
- /**
17
- * Outcome of a compaction attempt, surfaced by `CommandController.executeCompaction`
18
- * so callers (e.g. the plan-mode approval flow) can distinguish a deliberate abort
19
- * from an unrelated failure.
20
- *
21
- * "ok" — compaction completed; transcript was summarized.
22
- * "cancelled" — `CompactionCancelledError` was raised. Operator Esc, extension
23
- * hook, programmatic abort — all source-agnostic.
24
- * "failed" — any other rejection from `session.compact()`.
25
- */
26
- export type CompactionOutcome = "ok" | "cancelled" | "failed";
@@ -1,11 +0,0 @@
1
- /**
2
- * Compaction and summarization utilities.
3
- */
4
- export * from "./branch-summarization";
5
- export * from "./compaction";
6
- export * from "./entries";
7
- export * from "./errors";
8
- export * from "./messages";
9
- export * from "./openai";
10
- export * from "./pruning";
11
- export * from "./utils";
@@ -1,61 +0,0 @@
1
- import type { ImageContent, Message, MessageAttribution, ProviderPayload, TextContent } from "@sayknow-cli/ai";
2
- import type { AgentMessage } from "../types";
3
- export interface CustomMessage<T = unknown> {
4
- role: "custom";
5
- customType: string;
6
- content: string | (TextContent | ImageContent)[];
7
- display: boolean;
8
- details?: T;
9
- /** Who initiated this message for billing/attribution semantics. */
10
- attribution?: MessageAttribution;
11
- timestamp: number;
12
- }
13
- /** Legacy hook message type (pre-extensions). Kept for session migration. */
14
- export interface HookMessage<T = unknown> {
15
- role: "hookMessage";
16
- customType: string;
17
- content: string | (TextContent | ImageContent)[];
18
- display: boolean;
19
- details?: T;
20
- /** Who initiated this message for billing/attribution semantics. */
21
- attribution?: MessageAttribution;
22
- timestamp: number;
23
- }
24
- export interface BranchSummaryMessage {
25
- role: "branchSummary";
26
- summary: string;
27
- fromId: string;
28
- timestamp: number;
29
- }
30
- export interface CompactionSummaryMessage {
31
- role: "compactionSummary";
32
- summary: string;
33
- shortSummary?: string;
34
- tokensBefore: number;
35
- providerPayload?: ProviderPayload;
36
- timestamp: number;
37
- }
38
- export type CoreCompactionMessage = CustomMessage | HookMessage | BranchSummaryMessage | CompactionSummaryMessage;
39
- declare module "../types" {
40
- interface CustomAgentMessages {
41
- custom: CustomMessage;
42
- hookMessage: HookMessage;
43
- branchSummary: BranchSummaryMessage;
44
- compactionSummary: CompactionSummaryMessage;
45
- }
46
- }
47
- export type ConvertToLlm = (messages: AgentMessage[]) => Message[];
48
- export declare function renderBranchSummaryContext(summary: string): string;
49
- export declare function renderCompactionSummaryContext(summary: string): string;
50
- export declare function createBranchSummaryMessage(summary: string, fromId: string, timestamp: string): BranchSummaryMessage;
51
- export declare function createCompactionSummaryMessage(summary: string, tokensBefore: number, timestamp: string, shortSummary?: string, providerPayload?: ProviderPayload): CompactionSummaryMessage;
52
- export declare function createCustomMessage(customType: string, content: string | (TextContent | ImageContent)[], display: boolean, details: unknown | undefined, timestamp: string, attribution?: MessageAttribution): CustomMessage;
53
- /**
54
- * Default compaction-domain transformer.
55
- *
56
- * Embedders with their own app messages should pass a richer transformer through
57
- * `SummaryOptions.convertToLlm`; this default intentionally preserves only the
58
- * core LLM roles and the compaction messages owned by this package.
59
- */
60
- export declare function defaultConvertToLlm(messages: AgentMessage[]): Message[];
61
- export declare const convertToLlm: typeof defaultConvertToLlm;
@@ -1,63 +0,0 @@
1
- /**
2
- * Remote compaction utilities.
3
- *
4
- * Provider-side conversation summarization endpoints. Two flavors:
5
- *
6
- * - **OpenAI remote compaction** (`/responses/compact`): preserves encrypted
7
- * reasoning across compactions by submitting the full responses-API native
8
- * history and storing the returned `compaction` / `compaction_summary`
9
- * item in `preserveData` so future turns can replay the encrypted state.
10
- * - **Generic remote compaction**: a thin POST helper for self-hosted
11
- * summarization endpoints that accept `{ systemPrompt, prompt }` and reply
12
- * with `{ summary, shortSummary? }`.
13
- */
14
- import type { Message, Model } from "@sayknow-cli/ai/types";
15
- export declare const OPENAI_REMOTE_COMPACTION_PRESERVE_KEY = "openaiRemoteCompaction";
16
- export type OpenAiRemoteCompactionItem = {
17
- type: "compaction" | "compaction_summary";
18
- encrypted_content?: string;
19
- summary?: string;
20
- };
21
- export interface OpenAiRemoteCompactionPreserveData {
22
- provider?: string;
23
- replacementHistory: Array<Record<string, unknown>>;
24
- compactionItem: OpenAiRemoteCompactionItem;
25
- }
26
- export interface OpenAiRemoteCompactionRequest {
27
- model: string;
28
- input: Array<Record<string, unknown>>;
29
- instructions: string;
30
- }
31
- export interface OpenAiRemoteCompactionResponse extends OpenAiRemoteCompactionPreserveData {
32
- }
33
- export interface RemoteCompactionRequest {
34
- systemPrompt: string;
35
- prompt: string;
36
- }
37
- export interface RemoteCompactionResponse {
38
- summary: string;
39
- shortSummary?: string;
40
- }
41
- export declare function shouldUseOpenAiRemoteCompaction(model: Model): boolean;
42
- export declare function getPreservedOpenAiRemoteCompactionData(preserveData: Record<string, unknown> | undefined): OpenAiRemoteCompactionPreserveData | undefined;
43
- export declare function withOpenAiRemoteCompactionPreserveData(preserveData: Record<string, unknown> | undefined, remoteCompaction: OpenAiRemoteCompactionPreserveData | undefined): Record<string, unknown> | undefined;
44
- export declare function estimateOpenAiCompactInputTokens(input: Array<Record<string, unknown>>, instructions: string): number;
45
- export declare function trimOpenAiCompactInput(input: Array<Record<string, unknown>>, contextWindow: number, instructions: string): Array<Record<string, unknown>>;
46
- export declare function resolveOpenAiCompactInputBudget(contextWindow: number, maxOutputTokens?: number): number;
47
- /**
48
- * Build the OpenAI Responses-API native history array from LLM messages.
49
- *
50
- * Caller is responsible for converting any custom message types to
51
- * `Message[]` first (e.g. via the agent's `convertToLlm`); this function
52
- * operates purely on the LLM-domain shape.
53
- *
54
- * @param messages - LLM messages to encode.
55
- * @param model - Target model (used for provider gating + tool-call id rules).
56
- * @param previousReplacementHistory - History from a prior compaction whose
57
- * encrypted reasoning we want to preserve.
58
- */
59
- export declare function buildOpenAiNativeHistory(messages: Message[], model: Model, previousReplacementHistory?: Array<Record<string, unknown>>): Array<Record<string, unknown>>;
60
- export declare function requestOpenAiRemoteCompaction(model: Model, apiKey: string, compactInput: Array<Record<string, unknown>>, instructions: string, signal?: AbortSignal, options?: {
61
- authCredentialType?: "api_key" | "oauth";
62
- }): Promise<OpenAiRemoteCompactionResponse>;
63
- export declare function requestRemoteCompaction(endpoint: string, request: RemoteCompactionRequest, signal?: AbortSignal): Promise<RemoteCompactionResponse>;
@@ -1,69 +0,0 @@
1
- /**
2
- * Tool output pruning utilities for compaction.
3
- *
4
- * Candidate selection is staleness-aware: tool results that have been
5
- * superseded by a later result for the same target (same file read again,
6
- * same search re-run) or invalidated by a later successful edit/write to a
7
- * covered file are pruned in preference to merely-old results. Protect-window
8
- * and minimum-savings hysteresis semantics are unchanged.
9
- */
10
- import type { SessionEntry, SessionMessageEntry } from "./entries";
11
- export interface PruneConfig {
12
- /** Keep the most recent tool output tokens intact. */
13
- protectTokens: number;
14
- /** Only prune if total savings meets this threshold. */
15
- minimumSavings: number;
16
- /** Tool names that should never be pruned. */
17
- protectedTools: string[];
18
- /**
19
- * Tools in `protectedTools` whose protection is waived once the result is
20
- * superseded (a later result for the same target, or a later successful
21
- * edit/write to the covered file). The most recent result per target is
22
- * never considered superseded. Optional; defaults to none.
23
- */
24
- staleOverridableTools?: string[];
25
- }
26
- export declare const DEFAULT_PRUNE_CONFIG: PruneConfig;
27
- export interface PruneResult {
28
- prunedCount: number;
29
- tokensSaved: number;
30
- /**
31
- * The mutated message entries. Callers whose entry source returns
32
- * materialized copies (not live references) must write these back into
33
- * their canonical store by id.
34
- */
35
- prunedEntries: SessionMessageEntry[];
36
- }
37
- export interface AssistantArgumentPruneResult {
38
- argumentPrunedCount: number;
39
- argumentTokensSaved: number;
40
- /**
41
- * The mutated assistant message entries. Callers whose entry source returns
42
- * materialized copies must write these back into their canonical store by id.
43
- */
44
- prunedEntries: SessionMessageEntry[];
45
- }
46
- export declare function pruneAssistantToolArguments(entries: SessionEntry[], config?: PruneConfig): AssistantArgumentPruneResult;
47
- /**
48
- * Estimate the token savings {@link pruneToolOutputs} would achieve, without
49
- * mutating any entry. Returns 0 savings when below the configured minimum so the
50
- * caller sees the same gate the real prune enforces.
51
- */
52
- export declare function estimateToolOutputPruneSavings(entries: SessionEntry[], config?: PruneConfig): {
53
- prunableCount: number;
54
- tokensSaved: number;
55
- };
56
- /**
57
- * Evidence gate for below-threshold maintenance pruning (Finding 13). Pruning
58
- * forces a prompt-cache-epoch reset, so it only runs when opted in AND the
59
- * estimated stale savings clear a high minimum AND exceed the one-time reset
60
- * cost (so the reclaim pays the reset back). Default-off/blocked until live
61
- * evidence justifies enabling.
62
- */
63
- export declare function shouldRunMaintenancePrune(args: {
64
- enabled: boolean;
65
- estimatedSavings: number;
66
- minSavings: number;
67
- cacheEpochResetCost: number;
68
- }): boolean;
69
- export declare function pruneToolOutputs(entries: SessionEntry[], config?: PruneConfig): PruneResult;
@@ -1,32 +0,0 @@
1
- /**
2
- * Shared utilities for compaction and branch summarization.
3
- */
4
- import type { Message } from "@sayknow-cli/ai";
5
- import type { AgentMessage } from "../types";
6
- export interface FileOperations {
7
- read: Set<string>;
8
- written: Set<string>;
9
- edited: Set<string>;
10
- }
11
- export declare function createFileOps(): FileOperations;
12
- /**
13
- * Extract file operations from tool calls in an assistant message.
14
- */
15
- export declare function extractFileOpsFromMessage(message: AgentMessage, fileOps: FileOperations): void;
16
- /**
17
- * Compute final file lists from file operations.
18
- * Returns readFiles (files only read, not modified) and modifiedFiles.
19
- */
20
- export declare function computeFileLists(fileOps: FileOperations): {
21
- readFiles: string[];
22
- modifiedFiles: string[];
23
- };
24
- export declare function formatFileOperations(readFiles: string[], modifiedFiles: string[]): string;
25
- export declare function upsertFileOperations(summary: string, readFiles: string[], modifiedFiles: string[]): string;
26
- /**
27
- * Serialize LLM messages to text for summarization.
28
- * This prevents the model from treating it as a conversation to continue.
29
- * Call convertToLlm() first to handle custom message types.
30
- */
31
- export declare function serializeConversation(messages: Message[]): string;
32
- export declare const SUMMARIZATION_SYSTEM_PROMPT: string;