@yuyuqueen/llm-context-kit 0.1.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.
@@ -0,0 +1,29 @@
1
+ import type { CompressionConfig, ContextCompressor } from "./types.js";
2
+ /**
3
+ * Create a context compressor that summarizes old conversation messages.
4
+ *
5
+ * Ported from OpenClaw's compact.ts core algorithm.
6
+ * Provider-agnostic: user provides their own LLM summarization callback.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * const compressor = createContextCompressor({
11
+ * summarize: async ({ messages, systemPrompt, signal }) => {
12
+ * const response = await anthropic.messages.create({
13
+ * model: "claude-haiku-4-5-20251001",
14
+ * max_tokens: 4096,
15
+ * system: systemPrompt,
16
+ * messages: messages.map(m => ({ role: m.role, content: m.content })),
17
+ * });
18
+ * return response.content[0].text;
19
+ * },
20
+ * });
21
+ *
22
+ * const result = await compressor.compress(messages);
23
+ * if (result.compressed) {
24
+ * messages = result.messages; // Use compressed messages
25
+ * }
26
+ * ```
27
+ */
28
+ export declare function createContextCompressor(config: CompressionConfig): ContextCompressor;
29
+ //# sourceMappingURL=compress-conversation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress-conversation.d.ts","sourceRoot":"","sources":["../src/compress-conversation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAEV,iBAAiB,EAEjB,iBAAiB,EAClB,MAAM,YAAY,CAAC;AAwHpB;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,uBAAuB,CACrC,MAAM,EAAE,iBAAiB,GACxB,iBAAiB,CA0GnB"}
@@ -0,0 +1,200 @@
1
+ import { DEFAULT_PRESERVE_RECENT_TURNS, DEFAULT_COMPRESSION_TIMEOUT_MS, DEFAULT_SUMMARY_SYSTEM_PROMPT, COMPRESSION_MARKER, } from "./defaults.js";
2
+ /**
3
+ * Check if a message contains image content blocks.
4
+ */
5
+ function hasImageContent(msg) {
6
+ if (!Array.isArray(msg.content))
7
+ return false;
8
+ return msg.content.some((block) => block &&
9
+ typeof block === "object" &&
10
+ (block.type === "image" || block.type === "image_url"));
11
+ }
12
+ /**
13
+ * Strip image blocks from a message, keeping only text.
14
+ * Returns null if the message has no text content after stripping.
15
+ */
16
+ function stripImages(msg) {
17
+ if (typeof msg.content === "string")
18
+ return msg;
19
+ if (!Array.isArray(msg.content))
20
+ return msg;
21
+ const textBlocks = msg.content.filter((block) => block &&
22
+ typeof block === "object" &&
23
+ block.type === "text");
24
+ if (textBlocks.length === 0)
25
+ return null;
26
+ return { ...msg, content: textBlocks };
27
+ }
28
+ /**
29
+ * Count conversation turns from the end.
30
+ * A turn is a user message + the following assistant message(s),
31
+ * including any tool_use/tool_result exchanges within that turn.
32
+ *
33
+ * Returns the index (exclusive) where the "recent" section begins.
34
+ */
35
+ function findRecentTurnBoundary(messages, preserveTurns) {
36
+ if (preserveTurns <= 0)
37
+ return messages.length;
38
+ let turnsFound = 0;
39
+ let i = messages.length - 1;
40
+ while (i >= 0 && turnsFound < preserveTurns) {
41
+ // Skip assistant messages and tool messages (they belong to the current turn)
42
+ while (i >= 0 && messages[i].role !== "user") {
43
+ i--;
44
+ }
45
+ if (i < 0)
46
+ break;
47
+ // Found a user message — this is the start of a turn
48
+ // But if this user message only contains tool_result blocks (Anthropic format),
49
+ // it's part of a tool exchange, not a real user turn
50
+ const msg = messages[i];
51
+ const isToolResultOnly = Array.isArray(msg.content) &&
52
+ msg.content.length > 0 &&
53
+ msg.content.every((block) => block && typeof block === "object" && block.type === "tool_result");
54
+ if (!isToolResultOnly) {
55
+ turnsFound++;
56
+ }
57
+ i--;
58
+ }
59
+ // i + 1 is where the recent section starts
60
+ return i + 1;
61
+ }
62
+ /**
63
+ * Ensure tool_use/tool_result pairs are not split.
64
+ * If the boundary falls in the middle of a tool exchange,
65
+ * move it backward to include the full exchange.
66
+ */
67
+ function adjustBoundaryForToolPairs(messages, boundary) {
68
+ // If boundary is at the start, nothing to adjust
69
+ if (boundary <= 0)
70
+ return 0;
71
+ // Check if the message at boundary is a tool_result (user msg with tool_result blocks)
72
+ // or a tool message — if so, we need to include the preceding assistant tool_use
73
+ let adjusted = boundary;
74
+ while (adjusted > 0) {
75
+ const msg = messages[adjusted];
76
+ const isToolRelated = msg.role === "tool" ||
77
+ (msg.role === "user" &&
78
+ Array.isArray(msg.content) &&
79
+ msg.content.some((block) => block && typeof block === "object" && block.type === "tool_result"));
80
+ if (!isToolRelated)
81
+ break;
82
+ adjusted--;
83
+ }
84
+ return adjusted;
85
+ }
86
+ /**
87
+ * Create a context compressor that summarizes old conversation messages.
88
+ *
89
+ * Ported from OpenClaw's compact.ts core algorithm.
90
+ * Provider-agnostic: user provides their own LLM summarization callback.
91
+ *
92
+ * @example
93
+ * ```typescript
94
+ * const compressor = createContextCompressor({
95
+ * summarize: async ({ messages, systemPrompt, signal }) => {
96
+ * const response = await anthropic.messages.create({
97
+ * model: "claude-haiku-4-5-20251001",
98
+ * max_tokens: 4096,
99
+ * system: systemPrompt,
100
+ * messages: messages.map(m => ({ role: m.role, content: m.content })),
101
+ * });
102
+ * return response.content[0].text;
103
+ * },
104
+ * });
105
+ *
106
+ * const result = await compressor.compress(messages);
107
+ * if (result.compressed) {
108
+ * messages = result.messages; // Use compressed messages
109
+ * }
110
+ * ```
111
+ */
112
+ export function createContextCompressor(config) {
113
+ const { summarize, preserveRecentTurns = DEFAULT_PRESERVE_RECENT_TURNS, timeoutMs = DEFAULT_COMPRESSION_TIMEOUT_MS, summarySystemPrompt = DEFAULT_SUMMARY_SYSTEM_PROMPT, logger, } = config;
114
+ return {
115
+ async compress(messages) {
116
+ // 1. Separate system messages
117
+ const systemMessages = [];
118
+ const conversation = [];
119
+ for (const msg of messages) {
120
+ if (msg.role === "system") {
121
+ systemMessages.push(msg);
122
+ }
123
+ else {
124
+ conversation.push(msg);
125
+ }
126
+ }
127
+ // 2. Find boundary between old (compressible) and recent (preserved)
128
+ let boundary = findRecentTurnBoundary(conversation, preserveRecentTurns);
129
+ boundary = adjustBoundaryForToolPairs(conversation, boundary);
130
+ const oldMessages = conversation.slice(0, boundary);
131
+ const recentMessages = conversation.slice(boundary);
132
+ // 3. Check if there's anything to compress
133
+ if (oldMessages.length === 0) {
134
+ return {
135
+ messages,
136
+ compressed: false,
137
+ removedCount: 0,
138
+ description: "No messages to compress — conversation is short enough",
139
+ };
140
+ }
141
+ // 4. Prepare messages for summarization (strip images)
142
+ const messagesToSummarize = oldMessages
143
+ .map(stripImages)
144
+ .filter((m) => m !== null);
145
+ if (messagesToSummarize.length === 0) {
146
+ return {
147
+ messages: [...systemMessages, ...recentMessages],
148
+ compressed: true,
149
+ removedCount: oldMessages.length,
150
+ description: "Old messages contained only images — removed without summary",
151
+ };
152
+ }
153
+ // 5. Call summarize with timeout
154
+ const controller = new AbortController();
155
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
156
+ let summary;
157
+ try {
158
+ summary = await summarize({
159
+ messages: messagesToSummarize,
160
+ systemPrompt: summarySystemPrompt,
161
+ signal: controller.signal,
162
+ });
163
+ }
164
+ catch (error) {
165
+ clearTimeout(timer);
166
+ const isTimeout = error instanceof Error && error.name === "AbortError";
167
+ const reason = isTimeout
168
+ ? "Compression timed out"
169
+ : `Compression failed: ${error instanceof Error ? error.message : String(error)}`;
170
+ logger?.warn?.(reason);
171
+ return {
172
+ messages,
173
+ compressed: false,
174
+ removedCount: 0,
175
+ description: reason,
176
+ };
177
+ }
178
+ clearTimeout(timer);
179
+ // 6. Build compressed message array
180
+ const summaryMessage = {
181
+ role: "user",
182
+ content: `${COMPRESSION_MARKER}\n\n${summary}`,
183
+ };
184
+ const compressedMessages = [
185
+ ...systemMessages,
186
+ summaryMessage,
187
+ ...recentMessages,
188
+ ];
189
+ logger?.info?.(`Compressed ${oldMessages.length} messages into summary (${summary.length} chars)`);
190
+ return {
191
+ messages: compressedMessages,
192
+ compressed: true,
193
+ summary,
194
+ removedCount: oldMessages.length,
195
+ description: `Compressed ${oldMessages.length} messages into summary`,
196
+ };
197
+ },
198
+ };
199
+ }
200
+ //# sourceMappingURL=compress-conversation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compress-conversation.js","sourceRoot":"","sources":["../src/compress-conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { Message, BudgetConfig, ContextBudget } from "./types.js";
2
+ /**
3
+ * Estimate token count for an array of messages.
4
+ * Uses a simple chars-per-token heuristic (default: 4 chars ≈ 1 token).
5
+ */
6
+ export declare function estimateMessageTokens(messages: Message[], charsPerToken?: number): number;
7
+ /**
8
+ * Create a context budget checker.
9
+ */
10
+ export declare function createContextBudget(config: BudgetConfig): ContextBudget;
11
+ //# sourceMappingURL=context-budget.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.d.ts","sourceRoot":"","sources":["../src/context-budget.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,YAAY,EAAgB,aAAa,EAAE,MAAM,YAAY,CAAC;AAiCrF;;;GAGG;AACH,wBAAgB,qBAAqB,CACnC,QAAQ,EAAE,OAAO,EAAE,EACnB,aAAa,GAAE,MAAgC,GAC9C,MAAM,CAMR;AAED;;GAEG;AACH,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,YAAY,GAAG,aAAa,CAuBvE"}
@@ -0,0 +1,68 @@
1
+ import { DEFAULT_RESERVE_OUTPUT_TOKENS, DEFAULT_CHARS_PER_TOKEN } from "./defaults.js";
2
+ /**
3
+ * Get total character count from a message's content.
4
+ */
5
+ function getMessageChars(msg) {
6
+ const { content } = msg;
7
+ if (typeof content === "string") {
8
+ return content.length;
9
+ }
10
+ if (!Array.isArray(content)) {
11
+ return 0;
12
+ }
13
+ let total = 0;
14
+ for (const block of content) {
15
+ if (!block || typeof block !== "object")
16
+ continue;
17
+ const b = block;
18
+ if (b.type === "text" && typeof b.text === "string") {
19
+ total += b.text.length;
20
+ }
21
+ else if (b.type === "tool_result" || b.type === "tool_use") {
22
+ // Count nested text content
23
+ const nested = b.content ?? b.input;
24
+ if (typeof nested === "string") {
25
+ total += nested.length;
26
+ }
27
+ else if (typeof nested === "object") {
28
+ total += JSON.stringify(nested).length;
29
+ }
30
+ }
31
+ }
32
+ return total;
33
+ }
34
+ /**
35
+ * Estimate token count for an array of messages.
36
+ * Uses a simple chars-per-token heuristic (default: 4 chars ≈ 1 token).
37
+ */
38
+ export function estimateMessageTokens(messages, charsPerToken = DEFAULT_CHARS_PER_TOKEN) {
39
+ let totalChars = 0;
40
+ for (const msg of messages) {
41
+ totalChars += getMessageChars(msg);
42
+ }
43
+ return Math.ceil(totalChars / charsPerToken);
44
+ }
45
+ /**
46
+ * Create a context budget checker.
47
+ */
48
+ export function createContextBudget(config) {
49
+ const { contextWindowTokens } = config;
50
+ const reserveOutput = config.reserveOutputTokens ?? DEFAULT_RESERVE_OUTPUT_TOKENS;
51
+ const charsPerToken = config.charsPerToken ?? DEFAULT_CHARS_PER_TOKEN;
52
+ const availableForInput = contextWindowTokens - reserveOutput;
53
+ return {
54
+ check(messages) {
55
+ const estimatedTokens = estimateMessageTokens(messages, charsPerToken);
56
+ const availableTokens = Math.max(0, availableForInput - estimatedTokens);
57
+ const withinBudget = estimatedTokens <= availableForInput;
58
+ const utilizationPercent = availableForInput > 0
59
+ ? Math.min(100, Math.round((estimatedTokens / availableForInput) * 100))
60
+ : 100;
61
+ return { estimatedTokens, availableTokens, withinBudget, utilizationPercent };
62
+ },
63
+ estimateTokens(messages) {
64
+ return estimateMessageTokens(messages, charsPerToken);
65
+ },
66
+ };
67
+ }
68
+ //# sourceMappingURL=context-budget.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-budget.js","sourceRoot":"","sources":["../src/context-budget.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ export declare const MAX_TOOL_RESULT_CONTEXT_SHARE = 0.3;
2
+ export declare const HARD_MAX_TOOL_RESULT_CHARS = 400000;
3
+ export declare const MIN_KEEP_CHARS = 2000;
4
+ export declare const DEFAULT_TRUNCATION_SUFFIX: string;
5
+ export declare const NEWLINE_CUT_THRESHOLD = 0.8;
6
+ export declare const DEFAULT_PRESERVE_RECENT_TURNS = 4;
7
+ export declare const DEFAULT_COMPRESSION_TIMEOUT_MS = 300000;
8
+ export declare const DEFAULT_SUMMARY_SYSTEM_PROMPT: string;
9
+ export declare const COMPRESSION_MARKER = "[Previous conversation compressed]";
10
+ export declare const DEFAULT_RESERVE_OUTPUT_TOKENS = 4096;
11
+ export declare const DEFAULT_CHARS_PER_TOKEN = 4;
12
+ //# sourceMappingURL=defaults.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.d.ts","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAEA,eAAO,MAAM,6BAA6B,MAAM,CAAC;AAEjD,eAAO,MAAM,0BAA0B,SAAU,CAAC;AAElD,eAAO,MAAM,cAAc,OAAQ,CAAC;AAEpC,eAAO,MAAM,yBAAyB,QAGc,CAAC;AAErD,eAAO,MAAM,qBAAqB,MAAM,CAAC;AAIzC,eAAO,MAAM,6BAA6B,IAAI,CAAC;AAE/C,eAAO,MAAM,8BAA8B,SAAU,CAAC;AAEtD,eAAO,MAAM,6BAA6B,QAOqB,CAAC;AAEhE,eAAO,MAAM,kBAAkB,uCAAuC,CAAC;AAIvE,eAAO,MAAM,6BAA6B,OAAQ,CAAC;AAEnD,eAAO,MAAM,uBAAuB,IAAI,CAAC"}
@@ -0,0 +1,23 @@
1
+ // ===== Tool Result Truncation =====
2
+ export const MAX_TOOL_RESULT_CONTEXT_SHARE = 0.3;
3
+ export const HARD_MAX_TOOL_RESULT_CHARS = 400_000;
4
+ export const MIN_KEEP_CHARS = 2_000;
5
+ export const DEFAULT_TRUNCATION_SUFFIX = "\n\n[Content truncated — original was too large for the model's context window. " +
6
+ "The content above is a partial view. If you need more, request specific sections or use " +
7
+ "offset/limit parameters to read smaller chunks.]";
8
+ export const NEWLINE_CUT_THRESHOLD = 0.8;
9
+ // ===== Conversation Compression =====
10
+ export const DEFAULT_PRESERVE_RECENT_TURNS = 4;
11
+ export const DEFAULT_COMPRESSION_TIMEOUT_MS = 300_000;
12
+ export const DEFAULT_SUMMARY_SYSTEM_PROMPT = "You are a conversation summarizer. Summarize the following conversation, preserving:\n" +
13
+ "- Key facts and decisions made\n" +
14
+ "- User preferences and requirements\n" +
15
+ "- Current task state and progress\n" +
16
+ "- Important file paths, code snippets, or technical details\n" +
17
+ "- Any errors encountered and their resolutions\n\n" +
18
+ "Be concise but comprehensive. Do not lose critical context.";
19
+ export const COMPRESSION_MARKER = "[Previous conversation compressed]";
20
+ // ===== Context Budget =====
21
+ export const DEFAULT_RESERVE_OUTPUT_TOKENS = 4_096;
22
+ export const DEFAULT_CHARS_PER_TOKEN = 4;
23
+ //# sourceMappingURL=defaults.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"defaults.js","sourceRoot":"","sources":["../src/defaults.ts"],"names":[],"mappings":"AAAA,qCAAqC;AAErC,MAAM,CAAC,MAAM,6BAA6B,GAAG,GAAG,CAAC;AAEjD,MAAM,CAAC,MAAM,0BAA0B,GAAG,OAAO,CAAC;AAElD,MAAM,CAAC,MAAM,cAAc,GAAG,KAAK,CAAC;AAEpC,MAAM,CAAC,MAAM,yBAAyB,GACpC,kFAAkF;IAClF,0FAA0F;IAC1F,kDAAkD,CAAC;AAErD,MAAM,CAAC,MAAM,qBAAqB,GAAG,GAAG,CAAC;AAEzC,uCAAuC;AAEvC,MAAM,CAAC,MAAM,6BAA6B,GAAG,CAAC,CAAC;AAE/C,MAAM,CAAC,MAAM,8BAA8B,GAAG,OAAO,CAAC;AAEtD,MAAM,CAAC,MAAM,6BAA6B,GACxC,wFAAwF;IACxF,kCAAkC;IAClC,uCAAuC;IACvC,qCAAqC;IACrC,+DAA+D;IAC/D,oDAAoD;IACpD,6DAA6D,CAAC;AAEhE,MAAM,CAAC,MAAM,kBAAkB,GAAG,oCAAoC,CAAC;AAEvE,6BAA6B;AAE7B,MAAM,CAAC,MAAM,6BAA6B,GAAG,KAAK,CAAC;AAEnD,MAAM,CAAC,MAAM,uBAAuB,GAAG,CAAC,CAAC"}
@@ -0,0 +1,7 @@
1
+ export { createToolResultTruncator } from "./truncate-tool-results.js";
2
+ export { createContextCompressor } from "./compress-conversation.js";
3
+ export { createContextBudget, estimateMessageTokens } from "./context-budget.js";
4
+ export { truncateText } from "./truncate-text.js";
5
+ export { MAX_TOOL_RESULT_CONTEXT_SHARE, HARD_MAX_TOOL_RESULT_CHARS, MIN_KEEP_CHARS, DEFAULT_COMPRESSION_TIMEOUT_MS, DEFAULT_PRESERVE_RECENT_TURNS, } from "./defaults.js";
6
+ export type { Message, TextBlock, ToolUseBlock, ToolResultBlock, ContentBlock, TruncateTextOptions, TruncationConfig, TruncationResult, ToolResultTruncator, SummaryFn, CompressionConfig, CompressionResult, ContextCompressor, BudgetConfig, BudgetStatus, ContextBudget, Logger, } from "./types.js";
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAGjF,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAGlD,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,cAAc,EACd,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,eAAe,CAAC;AAGvB,YAAY,EAEV,OAAO,EACP,SAAS,EACT,YAAY,EACZ,eAAe,EACf,YAAY,EAEZ,mBAAmB,EACnB,gBAAgB,EAChB,gBAAgB,EAChB,mBAAmB,EAEnB,SAAS,EACT,iBAAiB,EACjB,iBAAiB,EACjB,iBAAiB,EAEjB,YAAY,EACZ,YAAY,EACZ,aAAa,EAEb,MAAM,GACP,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,9 @@
1
+ // Factory functions
2
+ export { createToolResultTruncator } from "./truncate-tool-results.js";
3
+ export { createContextCompressor } from "./compress-conversation.js";
4
+ export { createContextBudget, estimateMessageTokens } from "./context-budget.js";
5
+ // Pure utility
6
+ export { truncateText } from "./truncate-text.js";
7
+ // Constants
8
+ export { MAX_TOOL_RESULT_CONTEXT_SHARE, HARD_MAX_TOOL_RESULT_CHARS, MIN_KEEP_CHARS, DEFAULT_COMPRESSION_TIMEOUT_MS, DEFAULT_PRESERVE_RECENT_TURNS, } from "./defaults.js";
9
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,oBAAoB;AACpB,OAAO,EAAE,yBAAyB,EAAE,MAAM,4BAA4B,CAAC;AACvE,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AACrE,OAAO,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAEjF,eAAe;AACf,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAElD,YAAY;AACZ,OAAO,EACL,6BAA6B,EAC7B,0BAA0B,EAC1B,cAAc,EACd,8BAA8B,EAC9B,6BAA6B,GAC9B,MAAM,eAAe,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { TruncateTextOptions } from "./types.js";
2
+ /**
3
+ * Truncate text to fit within maxChars, preserving the beginning.
4
+ * Uses newline-boundary optimization to avoid cutting mid-line.
5
+ *
6
+ * Ported from OpenClaw's truncateToolResultText.
7
+ */
8
+ export declare function truncateText(text: string, maxChars: number, options?: TruncateTextOptions): string;
9
+ //# sourceMappingURL=truncate-text.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-text.d.ts","sourceRoot":"","sources":["../src/truncate-text.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,YAAY,CAAC;AAOtD;;;;;GAKG;AACH,wBAAgB,YAAY,CAC1B,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,CAAC,EAAE,mBAAmB,GAC5B,MAAM,CAmBR"}
@@ -0,0 +1,24 @@
1
+ import { MIN_KEEP_CHARS, DEFAULT_TRUNCATION_SUFFIX, NEWLINE_CUT_THRESHOLD, } from "./defaults.js";
2
+ /**
3
+ * Truncate text to fit within maxChars, preserving the beginning.
4
+ * Uses newline-boundary optimization to avoid cutting mid-line.
5
+ *
6
+ * Ported from OpenClaw's truncateToolResultText.
7
+ */
8
+ export function truncateText(text, maxChars, options) {
9
+ if (text.length <= maxChars) {
10
+ return text;
11
+ }
12
+ const minKeep = options?.minKeepChars ?? MIN_KEEP_CHARS;
13
+ const suffix = options?.truncationSuffix ?? DEFAULT_TRUNCATION_SUFFIX;
14
+ const threshold = options?.newlineCutThreshold ?? NEWLINE_CUT_THRESHOLD;
15
+ const keepChars = Math.max(minKeep, maxChars - suffix.length);
16
+ // Try to break at a newline boundary to avoid cutting mid-line
17
+ let cutPoint = keepChars;
18
+ const lastNewline = text.lastIndexOf("\n", keepChars);
19
+ if (lastNewline > keepChars * threshold) {
20
+ cutPoint = lastNewline;
21
+ }
22
+ return text.slice(0, cutPoint) + suffix;
23
+ }
24
+ //# sourceMappingURL=truncate-text.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-text.js","sourceRoot":"","sources":["../src/truncate-text.ts"],"names":[],"mappings":"AACA,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,qBAAqB,GACtB,MAAM,eAAe,CAAC;AAEvB;;;;;GAKG;AACH,MAAM,UAAU,YAAY,CAC1B,IAAY,EACZ,QAAgB,EAChB,OAA6B;IAE7B,IAAI,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;QAC5B,OAAO,IAAI,CAAC;IACd,CAAC;IAED,MAAM,OAAO,GAAG,OAAO,EAAE,YAAY,IAAI,cAAc,CAAC;IACxD,MAAM,MAAM,GAAG,OAAO,EAAE,gBAAgB,IAAI,yBAAyB,CAAC;IACtE,MAAM,SAAS,GAAG,OAAO,EAAE,mBAAmB,IAAI,qBAAqB,CAAC;IAExE,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,QAAQ,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC;IAE9D,+DAA+D;IAC/D,IAAI,QAAQ,GAAG,SAAS,CAAC;IACzB,MAAM,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACtD,IAAI,WAAW,GAAG,SAAS,GAAG,SAAS,EAAE,CAAC;QACxC,QAAQ,GAAG,WAAW,CAAC;IACzB,CAAC;IAED,OAAO,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,GAAG,MAAM,CAAC;AAC1C,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { TruncationConfig, ToolResultTruncator } from "./types.js";
2
+ /**
3
+ * Create a tool result truncator.
4
+ *
5
+ * Ported from OpenClaw's tool-result-truncation.ts.
6
+ * Strips OpenClaw-specific session management; operates on message arrays.
7
+ */
8
+ export declare function createToolResultTruncator(config?: TruncationConfig): ToolResultTruncator;
9
+ //# sourceMappingURL=truncate-tool-results.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-tool-results.d.ts","sourceRoot":"","sources":["../src/truncate-tool-results.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAGV,gBAAgB,EAEhB,mBAAmB,EACpB,MAAM,YAAY,CAAC;AA+KpB;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,CAAC,EAAE,gBAAgB,GACxB,mBAAmB,CAgDrB"}
@@ -0,0 +1,173 @@
1
+ import { truncateText } from "./truncate-text.js";
2
+ import { MAX_TOOL_RESULT_CONTEXT_SHARE, HARD_MAX_TOOL_RESULT_CHARS, MIN_KEEP_CHARS, DEFAULT_TRUNCATION_SUFFIX, } from "./defaults.js";
3
+ /**
4
+ * Default tool result detection.
5
+ * Handles both Anthropic format (content blocks with type "tool_result")
6
+ * and OpenAI format (role "tool").
7
+ */
8
+ function defaultIsToolResult(msg) {
9
+ // OpenAI format
10
+ if (msg.role === "tool") {
11
+ return true;
12
+ }
13
+ // Anthropic format: user message containing tool_result blocks
14
+ if (msg.role === "user" && Array.isArray(msg.content)) {
15
+ return msg.content.some((block) => block && typeof block === "object" && block.type === "tool_result");
16
+ }
17
+ return false;
18
+ }
19
+ /**
20
+ * Get total text character count from content blocks.
21
+ * Handles both flat text blocks and nested tool_result blocks (Anthropic format).
22
+ */
23
+ function getBlocksTextLength(blocks) {
24
+ let total = 0;
25
+ for (const block of blocks) {
26
+ if (!block || typeof block !== "object")
27
+ continue;
28
+ const b = block;
29
+ if (b.type === "text" && typeof b.text === "string") {
30
+ total += b.text.length;
31
+ }
32
+ else if (b.type === "tool_result") {
33
+ // Anthropic format: tool_result has nested content
34
+ const nested = b.content;
35
+ if (typeof nested === "string") {
36
+ total += nested.length;
37
+ }
38
+ else if (Array.isArray(nested)) {
39
+ total += getBlocksTextLength(nested);
40
+ }
41
+ }
42
+ }
43
+ return total;
44
+ }
45
+ /**
46
+ * Get total text character count from a message's content.
47
+ */
48
+ function getMessageTextLength(msg) {
49
+ const { content } = msg;
50
+ if (typeof content === "string") {
51
+ return content.length;
52
+ }
53
+ if (!Array.isArray(content)) {
54
+ return 0;
55
+ }
56
+ return getBlocksTextLength(content);
57
+ }
58
+ /**
59
+ * Recursively truncate text blocks within a content block array.
60
+ * Handles both flat text blocks and nested tool_result content.
61
+ */
62
+ function truncateBlocks(blocks, totalTextChars, maxChars, minKeepChars, truncationSuffix) {
63
+ return blocks.map((block) => {
64
+ if (!block || typeof block !== "object")
65
+ return block;
66
+ const b = block;
67
+ if (b.type === "text" && typeof b.text === "string") {
68
+ const blockShare = b.text.length / totalTextChars;
69
+ const blockBudget = Math.max(minKeepChars, Math.floor(maxChars * blockShare));
70
+ return {
71
+ ...b,
72
+ text: truncateText(b.text, blockBudget, {
73
+ minKeepChars,
74
+ truncationSuffix,
75
+ }),
76
+ };
77
+ }
78
+ if (b.type === "tool_result") {
79
+ const nested = b.content;
80
+ if (typeof nested === "string" && nested.length > maxChars) {
81
+ return {
82
+ ...b,
83
+ content: truncateText(nested, maxChars, {
84
+ minKeepChars,
85
+ truncationSuffix,
86
+ }),
87
+ };
88
+ }
89
+ if (Array.isArray(nested)) {
90
+ return {
91
+ ...b,
92
+ content: truncateBlocks(nested, totalTextChars, maxChars, minKeepChars, truncationSuffix),
93
+ };
94
+ }
95
+ }
96
+ return block;
97
+ });
98
+ }
99
+ /**
100
+ * Truncate a single message's text content blocks to fit within maxChars.
101
+ * Returns a new message (does not mutate the original).
102
+ *
103
+ * Ported from OpenClaw's truncateToolResultMessage.
104
+ */
105
+ function truncateMessage(msg, maxChars, minKeepChars, truncationSuffix) {
106
+ const { content } = msg;
107
+ // String content
108
+ if (typeof content === "string") {
109
+ if (content.length <= maxChars) {
110
+ return msg;
111
+ }
112
+ return {
113
+ ...msg,
114
+ content: truncateText(content, maxChars, {
115
+ minKeepChars,
116
+ truncationSuffix,
117
+ }),
118
+ };
119
+ }
120
+ if (!Array.isArray(content)) {
121
+ return msg;
122
+ }
123
+ const totalTextChars = getMessageTextLength(msg);
124
+ if (totalTextChars <= maxChars) {
125
+ return msg;
126
+ }
127
+ // Distribute budget proportionally among text blocks (handles nesting)
128
+ const newContent = truncateBlocks(content, totalTextChars, maxChars, minKeepChars, truncationSuffix);
129
+ return { ...msg, content: newContent };
130
+ }
131
+ /**
132
+ * Create a tool result truncator.
133
+ *
134
+ * Ported from OpenClaw's tool-result-truncation.ts.
135
+ * Strips OpenClaw-specific session management; operates on message arrays.
136
+ */
137
+ export function createToolResultTruncator(config) {
138
+ const maxContextShare = config?.maxContextShare ?? MAX_TOOL_RESULT_CONTEXT_SHARE;
139
+ const hardMax = config?.hardMaxChars ?? HARD_MAX_TOOL_RESULT_CHARS;
140
+ const minKeep = config?.minKeepChars ?? MIN_KEEP_CHARS;
141
+ const suffix = config?.truncationSuffix ?? DEFAULT_TRUNCATION_SUFFIX;
142
+ const isToolResult = config?.isToolResult ?? defaultIsToolResult;
143
+ function calculateMaxChars(contextWindowTokens) {
144
+ const maxTokens = Math.floor(contextWindowTokens * maxContextShare);
145
+ const maxChars = maxTokens * 4;
146
+ return Math.min(maxChars, hardMax);
147
+ }
148
+ function isOversized(message, contextWindowTokens) {
149
+ if (!isToolResult(message)) {
150
+ return false;
151
+ }
152
+ const textLength = getMessageTextLength(message);
153
+ return textLength > calculateMaxChars(contextWindowTokens);
154
+ }
155
+ function truncate(messages, contextWindowTokens) {
156
+ const maxChars = calculateMaxChars(contextWindowTokens);
157
+ let truncatedCount = 0;
158
+ const newMessages = messages.map((msg) => {
159
+ if (!isToolResult(msg)) {
160
+ return msg;
161
+ }
162
+ const textLength = getMessageTextLength(msg);
163
+ if (textLength <= maxChars) {
164
+ return msg;
165
+ }
166
+ truncatedCount++;
167
+ return truncateMessage(msg, maxChars, minKeep, suffix);
168
+ });
169
+ return { messages: newMessages, truncatedCount };
170
+ }
171
+ return { truncate, isOversized, calculateMaxChars };
172
+ }
173
+ //# sourceMappingURL=truncate-tool-results.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"truncate-tool-results.js","sourceRoot":"","sources":["../src/truncate-tool-results.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,128 @@
1
+ export type TextBlock = {
2
+ type: "text";
3
+ text: string;
4
+ };
5
+ export type ToolUseBlock = {
6
+ type: "tool_use";
7
+ id: string;
8
+ name: string;
9
+ input: unknown;
10
+ };
11
+ export type ToolResultBlock = {
12
+ type: "tool_result";
13
+ tool_use_id: string;
14
+ content?: string | ContentBlock[];
15
+ };
16
+ export type ContentBlock = TextBlock | ToolUseBlock | ToolResultBlock | {
17
+ type: string;
18
+ [key: string]: unknown;
19
+ };
20
+ /**
21
+ * Provider-agnostic message format.
22
+ * Compatible with Anthropic and OpenAI message shapes.
23
+ */
24
+ export type Message = {
25
+ role: "user" | "assistant" | "system" | "tool" | (string & {});
26
+ content: string | ContentBlock[];
27
+ name?: string;
28
+ tool_use_id?: string;
29
+ [key: string]: unknown;
30
+ };
31
+ export type TruncateTextOptions = {
32
+ /** Minimum characters to keep (default: 2_000) */
33
+ minKeepChars?: number;
34
+ /** Suffix appended to truncated text */
35
+ truncationSuffix?: string;
36
+ /** Threshold for newline-boundary optimization (default: 0.8) */
37
+ newlineCutThreshold?: number;
38
+ };
39
+ export type TruncationConfig = {
40
+ /** Max share of context window for a single tool result (default: 0.3) */
41
+ maxContextShare?: number;
42
+ /** Hard character cap for any single tool result (default: 400_000) */
43
+ hardMaxChars?: number;
44
+ /** Minimum characters to keep when truncating (default: 2_000) */
45
+ minKeepChars?: number;
46
+ /** Custom suffix appended to truncated results */
47
+ truncationSuffix?: string;
48
+ /** Custom function to identify tool result messages */
49
+ isToolResult?: (msg: Message) => boolean;
50
+ };
51
+ export type TruncationResult = {
52
+ messages: Message[];
53
+ truncatedCount: number;
54
+ };
55
+ export type ToolResultTruncator = {
56
+ /** Truncate oversized tool results in a message array */
57
+ truncate: (messages: Message[], contextWindowTokens: number) => TruncationResult;
58
+ /** Check if a single message is an oversized tool result */
59
+ isOversized: (message: Message, contextWindowTokens: number) => boolean;
60
+ /** Calculate max chars allowed for a given context window */
61
+ calculateMaxChars: (contextWindowTokens: number) => number;
62
+ };
63
+ /**
64
+ * User-provided LLM callback for generating summaries.
65
+ * Provider-agnostic: user brings their own LLM client.
66
+ */
67
+ export type SummaryFn = (params: {
68
+ messages: Message[];
69
+ systemPrompt: string;
70
+ signal?: AbortSignal;
71
+ }) => Promise<string>;
72
+ export type CompressionConfig = {
73
+ /** User-provided LLM function for summarization */
74
+ summarize: SummaryFn;
75
+ /** Number of recent conversation turns to preserve (default: 4) */
76
+ preserveRecentTurns?: number;
77
+ /** Timeout in ms for summarization call (default: 300_000) */
78
+ timeoutMs?: number;
79
+ /** Custom system prompt for the summarization LLM call */
80
+ summarySystemPrompt?: string;
81
+ /** Logger */
82
+ logger?: Logger;
83
+ };
84
+ export type CompressionResult = {
85
+ messages: Message[];
86
+ compressed: boolean;
87
+ /** Summary text that replaced old messages */
88
+ summary?: string;
89
+ /** How many messages were removed */
90
+ removedCount: number;
91
+ /** Description of what happened */
92
+ description?: string;
93
+ };
94
+ export type ContextCompressor = {
95
+ /** Compress a conversation by summarizing old messages */
96
+ compress: (messages: Message[]) => Promise<CompressionResult>;
97
+ };
98
+ export type BudgetConfig = {
99
+ /** Total context window size in tokens */
100
+ contextWindowTokens: number;
101
+ /** Reserve tokens for output (default: 4_096) */
102
+ reserveOutputTokens?: number;
103
+ /** Chars-per-token ratio for estimation (default: 4) */
104
+ charsPerToken?: number;
105
+ };
106
+ export type BudgetStatus = {
107
+ /** Estimated total tokens used */
108
+ estimatedTokens: number;
109
+ /** Available tokens remaining */
110
+ availableTokens: number;
111
+ /** Whether messages fit within budget */
112
+ withinBudget: boolean;
113
+ /** Utilization percentage (0-100) */
114
+ utilizationPercent: number;
115
+ };
116
+ export type ContextBudget = {
117
+ /** Check if messages fit within the context window */
118
+ check: (messages: Message[]) => BudgetStatus;
119
+ /** Estimate token count for messages */
120
+ estimateTokens: (messages: Message[]) => number;
121
+ };
122
+ export type Logger = {
123
+ debug?: (message: string) => void;
124
+ info?: (message: string) => void;
125
+ warn?: (message: string) => void;
126
+ error?: (message: string) => void;
127
+ };
128
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,3 @@
1
+ // ===== Content Blocks =====
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,6BAA6B"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@yuyuqueen/llm-context-kit",
3
+ "version": "0.1.0",
4
+ "description": "Context window management for LLM applications. Tool result truncation, conversation compression, and context budget estimation.",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": [
15
+ "dist"
16
+ ],
17
+ "scripts": {
18
+ "build": "tsc",
19
+ "test": "vitest run",
20
+ "test:watch": "vitest",
21
+ "clean": "rm -rf dist"
22
+ },
23
+ "keywords": [
24
+ "llm",
25
+ "context-window",
26
+ "truncation",
27
+ "compression",
28
+ "token",
29
+ "anthropic",
30
+ "openai",
31
+ "ai"
32
+ ],
33
+ "license": "MIT",
34
+ "publishConfig": {
35
+ "registry": "https://registry.npmjs.org",
36
+ "access": "public"
37
+ },
38
+ "devDependencies": {
39
+ "typescript": "^5.7.0",
40
+ "vitest": "^3.0.0"
41
+ }
42
+ }