kagent-ts 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.
Files changed (143) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +395 -0
  3. package/dist/compression/interface.d.ts +26 -0
  4. package/dist/compression/interface.d.ts.map +1 -0
  5. package/dist/compression/interface.js +3 -0
  6. package/dist/compression/interface.js.map +1 -0
  7. package/dist/compression/sliding-window.d.ts +21 -0
  8. package/dist/compression/sliding-window.d.ts.map +1 -0
  9. package/dist/compression/sliding-window.js +55 -0
  10. package/dist/compression/sliding-window.js.map +1 -0
  11. package/dist/compression/types.d.ts +12 -0
  12. package/dist/compression/types.d.ts.map +1 -0
  13. package/dist/compression/types.js +3 -0
  14. package/dist/compression/types.js.map +1 -0
  15. package/dist/context/context-manager.d.ts +76 -0
  16. package/dist/context/context-manager.d.ts.map +1 -0
  17. package/dist/context/context-manager.js +132 -0
  18. package/dist/context/context-manager.js.map +1 -0
  19. package/dist/context/types.d.ts +35 -0
  20. package/dist/context/types.d.ts.map +1 -0
  21. package/dist/context/types.js +3 -0
  22. package/dist/context/types.js.map +1 -0
  23. package/dist/core/agent.d.ts +288 -0
  24. package/dist/core/agent.d.ts.map +1 -0
  25. package/dist/core/agent.js +398 -0
  26. package/dist/core/agent.js.map +1 -0
  27. package/dist/core/hooks.d.ts +34 -0
  28. package/dist/core/hooks.d.ts.map +1 -0
  29. package/dist/core/hooks.js +3 -0
  30. package/dist/core/hooks.js.map +1 -0
  31. package/dist/core/plan-solve-agent.d.ts +114 -0
  32. package/dist/core/plan-solve-agent.d.ts.map +1 -0
  33. package/dist/core/plan-solve-agent.js +450 -0
  34. package/dist/core/plan-solve-agent.js.map +1 -0
  35. package/dist/core/react-agent.d.ts +52 -0
  36. package/dist/core/react-agent.d.ts.map +1 -0
  37. package/dist/core/react-agent.js +266 -0
  38. package/dist/core/react-agent.js.map +1 -0
  39. package/dist/core/response-schema.d.ts +91 -0
  40. package/dist/core/response-schema.d.ts.map +1 -0
  41. package/dist/core/response-schema.js +292 -0
  42. package/dist/core/response-schema.js.map +1 -0
  43. package/dist/core/types.d.ts +6 -0
  44. package/dist/core/types.d.ts.map +1 -0
  45. package/dist/core/types.js +3 -0
  46. package/dist/core/types.js.map +1 -0
  47. package/dist/index.d.ts +39 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +67 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/llm/interface.d.ts +87 -0
  52. package/dist/llm/interface.d.ts.map +1 -0
  53. package/dist/llm/interface.js +3 -0
  54. package/dist/llm/interface.js.map +1 -0
  55. package/dist/llm/openai-provider.d.ts +92 -0
  56. package/dist/llm/openai-provider.d.ts.map +1 -0
  57. package/dist/llm/openai-provider.js +262 -0
  58. package/dist/llm/openai-provider.js.map +1 -0
  59. package/dist/messages/message.d.ts +50 -0
  60. package/dist/messages/message.d.ts.map +1 -0
  61. package/dist/messages/message.js +87 -0
  62. package/dist/messages/message.js.map +1 -0
  63. package/dist/messages/types.d.ts +31 -0
  64. package/dist/messages/types.d.ts.map +1 -0
  65. package/dist/messages/types.js +14 -0
  66. package/dist/messages/types.js.map +1 -0
  67. package/dist/preferences/preference-manager.d.ts +88 -0
  68. package/dist/preferences/preference-manager.d.ts.map +1 -0
  69. package/dist/preferences/preference-manager.js +196 -0
  70. package/dist/preferences/preference-manager.js.map +1 -0
  71. package/dist/preferences/types.d.ts +27 -0
  72. package/dist/preferences/types.d.ts.map +1 -0
  73. package/dist/preferences/types.js +3 -0
  74. package/dist/preferences/types.js.map +1 -0
  75. package/dist/session/session-manager.d.ts +56 -0
  76. package/dist/session/session-manager.d.ts.map +1 -0
  77. package/dist/session/session-manager.js +156 -0
  78. package/dist/session/session-manager.js.map +1 -0
  79. package/dist/session/session-types.d.ts +51 -0
  80. package/dist/session/session-types.d.ts.map +1 -0
  81. package/dist/session/session-types.js +3 -0
  82. package/dist/session/session-types.js.map +1 -0
  83. package/dist/skills/file-skill-loader.d.ts +88 -0
  84. package/dist/skills/file-skill-loader.d.ts.map +1 -0
  85. package/dist/skills/file-skill-loader.js +365 -0
  86. package/dist/skills/file-skill-loader.js.map +1 -0
  87. package/dist/skills/index.d.ts +4 -0
  88. package/dist/skills/index.d.ts.map +1 -0
  89. package/dist/skills/index.js +10 -0
  90. package/dist/skills/index.js.map +1 -0
  91. package/dist/skills/skill-manager.d.ts +133 -0
  92. package/dist/skills/skill-manager.d.ts.map +1 -0
  93. package/dist/skills/skill-manager.js +310 -0
  94. package/dist/skills/skill-manager.js.map +1 -0
  95. package/dist/skills/types.d.ts +42 -0
  96. package/dist/skills/types.d.ts.map +1 -0
  97. package/dist/skills/types.js +3 -0
  98. package/dist/skills/types.js.map +1 -0
  99. package/dist/tools/builtin/edit-file.d.ts +12 -0
  100. package/dist/tools/builtin/edit-file.d.ts.map +1 -0
  101. package/dist/tools/builtin/edit-file.js +123 -0
  102. package/dist/tools/builtin/edit-file.js.map +1 -0
  103. package/dist/tools/builtin/glob-search.d.ts +11 -0
  104. package/dist/tools/builtin/glob-search.d.ts.map +1 -0
  105. package/dist/tools/builtin/glob-search.js +264 -0
  106. package/dist/tools/builtin/glob-search.js.map +1 -0
  107. package/dist/tools/builtin/grep-search.d.ts +14 -0
  108. package/dist/tools/builtin/grep-search.d.ts.map +1 -0
  109. package/dist/tools/builtin/grep-search.js +264 -0
  110. package/dist/tools/builtin/grep-search.js.map +1 -0
  111. package/dist/tools/builtin/index.d.ts +21 -0
  112. package/dist/tools/builtin/index.d.ts.map +1 -0
  113. package/dist/tools/builtin/index.js +53 -0
  114. package/dist/tools/builtin/index.js.map +1 -0
  115. package/dist/tools/builtin/read-file.d.ts +11 -0
  116. package/dist/tools/builtin/read-file.d.ts.map +1 -0
  117. package/dist/tools/builtin/read-file.js +122 -0
  118. package/dist/tools/builtin/read-file.js.map +1 -0
  119. package/dist/tools/builtin/write-file.d.ts +10 -0
  120. package/dist/tools/builtin/write-file.d.ts.map +1 -0
  121. package/dist/tools/builtin/write-file.js +89 -0
  122. package/dist/tools/builtin/write-file.js.map +1 -0
  123. package/dist/tools/circuit-breaker.d.ts +77 -0
  124. package/dist/tools/circuit-breaker.d.ts.map +1 -0
  125. package/dist/tools/circuit-breaker.js +102 -0
  126. package/dist/tools/circuit-breaker.js.map +1 -0
  127. package/dist/tools/error-tracker.d.ts +116 -0
  128. package/dist/tools/error-tracker.d.ts.map +1 -0
  129. package/dist/tools/error-tracker.js +484 -0
  130. package/dist/tools/error-tracker.js.map +1 -0
  131. package/dist/tools/tool-registry.d.ts +87 -0
  132. package/dist/tools/tool-registry.d.ts.map +1 -0
  133. package/dist/tools/tool-registry.js +188 -0
  134. package/dist/tools/tool-registry.js.map +1 -0
  135. package/dist/tools/types.d.ts +95 -0
  136. package/dist/tools/types.d.ts.map +1 -0
  137. package/dist/tools/types.js +14 -0
  138. package/dist/tools/types.js.map +1 -0
  139. package/dist/utils/token-counter.d.ts +31 -0
  140. package/dist/utils/token-counter.d.ts.map +1 -0
  141. package/dist/utils/token-counter.js +105 -0
  142. package/dist/utils/token-counter.js.map +1 -0
  143. package/package.json +56 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 kagent-ts
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,395 @@
1
+ # KAgent-TS
2
+
3
+ A TypeScript agent framework for building LLM-powered applications with structured agent loops, tool management, session persistence, and user preference injection.
4
+
5
+ ## Features
6
+
7
+ - **Agent Loop Paradigms** — Base `Agent` + `ReActAgent` (Thought → Action → Observation → Final) + `PlanSolveAgent` (Plan → Resolve → Revise → Final)
8
+ - **LLM Integration** — OpenAI provider with automatic retry (exponential backoff + jitter) and network error classification
9
+ - **Tool System** — `ToolRegistry` with circuit breaker (automatic disable after threshold) and structured error tracking
10
+ - **Context Management** — Automatic token tracking, threshold-based compression with sliding window
11
+ - **Session Persistence** — Checkpoint-and-resume: auto-save on network error, graceful discard on abort (SIGINT)
12
+ - **User Preferences** — Plain-text Markdown file (`key: value`), injected into system prompt, auto-reloaded on file change
13
+ - **Skills** — Progressive disclosure: skills auto-detect from user input and load on demand
14
+ - **Built-in Tools** — Read file, write file, edit file, grep search, glob search
15
+
16
+ ## Installation
17
+
18
+ ```bash
19
+ npm install kagent-ts
20
+ ```
21
+
22
+ ## Quick Start
23
+
24
+ ```typescript
25
+ import { ReActAgent, OpenAIProvider, Tool } from "kagent-ts";
26
+
27
+ // 1. Create an LLM provider
28
+ const llm = new OpenAIProvider({
29
+ apiKey: process.env.OPENAI_API_KEY!,
30
+ model: "gpt-4o",
31
+ });
32
+
33
+ // 2. Define a tool
34
+ const calculator: Tool = {
35
+ name: "calculator",
36
+ description: "Perform a mathematical calculation",
37
+ parameters: {
38
+ type: "object",
39
+ properties: {
40
+ expression: {
41
+ type: "string",
42
+ description: "The mathematical expression to evaluate",
43
+ },
44
+ },
45
+ required: ["expression"],
46
+ },
47
+ async execute(args) {
48
+ const { expression } = args as { expression: string };
49
+ return String(eval(expression));
50
+ },
51
+ };
52
+
53
+ // 3. Create the agent
54
+ const agent = new ReActAgent({ llm, tools: [calculator] });
55
+
56
+ // 4. Run
57
+ const response = await agent.run("What is 25 * 4 + 10?");
58
+ console.log(response);
59
+ ```
60
+
61
+ ## Architecture
62
+
63
+ ```
64
+ src/
65
+ ├── core/ # Agent classes: Agent, ReActAgent, PlanSolveAgent
66
+ ├── llm/ # LLM provider interface + OpenAI implementation
67
+ ├── messages/ # Message types and builder class
68
+ ├── context/ # Context window management (token tracking)
69
+ ├── compression/ # Compression strategies (sliding window)
70
+ ├── session/ # Session checkpoint persistence & resume
71
+ ├── preferences/ # User preferences (Markdown file, auto-reload)
72
+ ├── skills/ # Progressive disclosure skill system
73
+ ├── tools/ # Tool registry, circuit breaker, error tracker
74
+ │ └── builtin/ # Built-in file tools (read, write, edit, grep, glob)
75
+ ├── utils/ # Token counting utilities
76
+ └── index.ts # Public API exports
77
+ ```
78
+
79
+ ## Agent Paradigms
80
+
81
+ ### ReActAgent
82
+
83
+ The classic Thought → Action → Observation loop with tool-call support:
84
+
85
+ ```typescript
86
+ import { ReActAgent } from "kagent-ts";
87
+
88
+ const agent = new ReActAgent({
89
+ llm,
90
+ tools: [myTool],
91
+ systemPrompt: "You are a helpful assistant.",
92
+ maxIterations: 10,
93
+ });
94
+ const response = await agent.run("Search for the latest news.");
95
+ ```
96
+
97
+ ### PlanSolveAgent
98
+
99
+ Plan → Resolve → Revise loop for complex multi-step tasks:
100
+
101
+ ```typescript
102
+ import { PlanSolveAgent } from "kagent-ts";
103
+
104
+ const agent = new PlanSolveAgent({
105
+ llm,
106
+ tools: [searchTool, calculatorTool],
107
+ maxIterations: 15,
108
+ maxPlanSteps: 12,
109
+ replanThreshold: 2, // auto-suggest replan after 2 consecutive failures
110
+ });
111
+ const response = await agent.run("Analyze Q3 financial data and generate a report.");
112
+ ```
113
+
114
+ The agent will:
115
+ 1. Create a detailed plan
116
+ 2. Execute each step with tools
117
+ 3. Revise the plan mid-execution if obstacles occur
118
+ 4. Deliver the final answer
119
+
120
+ ## LLM & Network Resilience
121
+
122
+ The OpenAI provider includes built-in retry logic:
123
+
124
+ ```typescript
125
+ const llm = new OpenAIProvider({
126
+ apiKey: process.env.OPENAI_API_KEY!,
127
+ model: "gpt-4o",
128
+ retry: {
129
+ maxRetries: 3,
130
+ baseDelayMs: 1000,
131
+ maxDelayMs: 30000,
132
+ },
133
+ });
134
+ ```
135
+
136
+ - **Retryable errors**: timeout, connection refused/reset, DNS failure, HTTP 429 (rate limit), HTTP 5xx (server error)
137
+ - **Permanent errors**: HTTP 401 (auth), HTTP 400 (bad request), abort signal — propagate immediately
138
+ - On retry exhaustion → throws `LLMNetworkError` with `cause` field for agent-level handling
139
+
140
+ ## Tool System
141
+
142
+ ### ToolRegistry + Circuit Breaker
143
+
144
+ Tools can be registered with automatic failure detection and circuit breaking:
145
+
146
+ ```typescript
147
+ import { ToolRegistry } from "kagent-ts";
148
+
149
+ const registry = new ToolRegistry({
150
+ breakerConfig: {
151
+ failureThreshold: 5, // disable after 5 consecutive failures
152
+ cooldownMs: 60000, // re-enable after 60s
153
+ halfOpenMaxRetries: 2,
154
+ },
155
+ });
156
+
157
+ registry.register(calculatorTool);
158
+ const result = await registry.execute("calculator", { expression: "2+2" });
159
+ ```
160
+
161
+ States: `CLOSED` (normal) → `OPEN` (disabled) → `HALF_OPEN` (probing) → `CLOSED` (recovered).
162
+
163
+ ### Error Tracking
164
+
165
+ Track full tool failure chains with LLM analysis:
166
+
167
+ ```typescript
168
+ const report = agent.generateErrorReport();
169
+ // Generates a structured markdown report of all tool failures,
170
+ // including LLM analysis of root cause and recovery steps.
171
+ ```
172
+
173
+ ### Built-in Tools
174
+
175
+ ```typescript
176
+ import { registerAllBuiltinTools, ReadFileTool, WriteFileTool } from "kagent-ts";
177
+
178
+ // Register individually
179
+ const agent = new ReActAgent({
180
+ llm,
181
+ tools: [...registerAllBuiltinTools()],
182
+ });
183
+
184
+ // Or add at runtime
185
+ agent.addTool(new ReadFileTool());
186
+ agent.addTool(new WriteFileTool());
187
+ ```
188
+
189
+ Available: `ReadFileTool`, `WriteFileTool`, `EditFileTool`, `GrepSearchTool`, `GlobSearchTool`.
190
+
191
+ ## Session Persistence & Network Recovery
192
+
193
+ The agent can checkpoint its state mid-run and resume after disconnection:
194
+
195
+ ```typescript
196
+ const agent = new ReActAgent({
197
+ llm,
198
+ tools: [myTool],
199
+ sessionId: "my-session",
200
+ enableCheckpointing: true,
201
+ });
202
+
203
+ // Normal execution — auto-saves after each LLM+tools cycle.
204
+ // On network error: saves "interrupted" checkpoint, returns resume instructions.
205
+ const result = await agent.run("Do something...");
206
+
207
+ // After network is restored:
208
+ const resumed = await agent.resume("my-session", "continue");
209
+ ```
210
+
211
+ When the user aborts (SIGINT / `agent.cancel()`), the checkpoint is discarded — no stale state persists.
212
+
213
+ ## User Preferences
214
+
215
+ Preferences are stored as a Markdown file (`.kagent/preferences.md` by default) and injected into the system prompt as a `=== User Preferences ===` section. File changes are auto-detected each loop iteration.
216
+
217
+ ```markdown
218
+ # User Preferences
219
+
220
+ codeStyle: Use TypeScript with functional style. Prefer interfaces.
221
+ language: Always respond in Chinese.
222
+ forbidden: Never use `any` type. Avoid mutating function parameters.
223
+ ```
224
+
225
+ ```typescript
226
+ // Via constructor
227
+ const agent = new ReActAgent({
228
+ llm,
229
+ tools: [myTool],
230
+ preferences: {
231
+ codeStyle: "Use TypeScript with functional style.",
232
+ language: "Always respond in Chinese.",
233
+ },
234
+ });
235
+
236
+ // With file persistence
237
+ import { PreferenceManager } from "kagent-ts";
238
+
239
+ const agent = new ReActAgent({
240
+ llm,
241
+ tools: [myTool],
242
+ preferenceManager: new PreferenceManager(),
243
+ });
244
+
245
+ // Runtime CRUD (auto-persists if PreferenceManager configured)
246
+ agent.setPreference("codeStyle", "Use TypeScript with functional style.");
247
+ agent.getPreference("language"); // "Always respond in Chinese."
248
+ agent.removePreference("forbidden");
249
+ agent.clearPreferences();
250
+
251
+ // The LLM sees this in every system prompt:
252
+ // === User Preferences ===
253
+ // - codeStyle: Use TypeScript with functional style.
254
+ // - language: Always respond in Chinese.
255
+ ```
256
+
257
+ ### File Format
258
+
259
+ `preferences.md` uses simple `key: value` lines. Lines starting with `#` are comments:
260
+
261
+ ```markdown
262
+ # User Preferences
263
+
264
+ codeStyle: Use TypeScript with functional style.
265
+ replyLanguage: Always respond in Chinese.
266
+ # This is a comment — ignored when loaded.
267
+ ```
268
+
269
+ Manually edit the file while the agent is running — changes are auto-detected before the next LLM call.
270
+
271
+ ## Skills (Progressive Disclosure)
272
+
273
+ Skills provide domain-specific knowledge and tools that load on demand. Skills are defined as file-based directories, making them easy to author and share.
274
+
275
+ ### Directory Structure
276
+
277
+ ```
278
+ skills/
279
+ ├── sql/
280
+ │ ├── SKILL.md # Frontmatter (metadata) + system prompt body
281
+ │ ├── reference/ # Reference docs loaded on activation
282
+ │ │ └── cheatsheet.md
283
+ │ └── scripts/ # Executable scripts registered as tools
284
+ │ └── format_sql.sh
285
+ ├── git/
286
+ │ ├── SKILL.md
287
+ │ └── scripts/
288
+ │ └── list_branches.sh
289
+ └── ...
290
+ ```
291
+
292
+ ### SKILL.md Format
293
+
294
+ ```markdown
295
+ ---
296
+ name: sql
297
+ description: SQL query writing and optimization
298
+ keywords: sql, query, database, select, join
299
+ ---
300
+
301
+ You are an expert in SQL. Write efficient queries, use appropriate indexes, and consider EXPLAIN plans.
302
+ ```
303
+
304
+ ### Usage
305
+
306
+ Point the agent to your `skills/` directory — skills are auto-discovered and lazily loaded:
307
+
308
+ ```typescript
309
+ import { ReActAgent, OpenAIProvider } from "kagent-ts";
310
+
311
+ const agent = new ReActAgent({
312
+ llm: provider,
313
+ tools: myTools,
314
+ skillsDir: "./skills", // Auto-discover file-based skills
315
+ });
316
+
317
+ // Manual activation
318
+ agent.activateSkill("sql");
319
+
320
+ // Or rely on auto-detection: when user input contains matching
321
+ // keywords (e.g., "write a SQL query"), the skill activates automatically.
322
+ const response = await agent.run("Write a query to find top 10 customers by revenue.");
323
+ ```
324
+
325
+ ### Skill Components
326
+
327
+ | Component | Location | Behavior |
328
+ |-----------|----------|----------|
329
+ | **Metadata** | SKILL.md frontmatter (`---`) | Registered on scan — name, description, keywords |
330
+ | **System Prompt** | SKILL.md body | Loaded on activation — injected into the agent's system prompt |
331
+ | **Reference Docs** | `reference/*.md`, `*.txt` | Appended to system prompt on activation, with `[Reference: filename]` headers |
332
+ | **Scripts** | `scripts/*.sh`, `.py`, `.js`, `.bat` | Registered as executable `Tool` objects on activation, named `{skillName}_{scriptName}` |
333
+
334
+ ### Supported Script Types
335
+
336
+ | Extension | Interpreter | Platform |
337
+ |-----------|-------------|----------|
338
+ | `.sh` | `bash` | Linux/macOS/WSL |
339
+ | `.bat` / `.cmd` | `cmd.exe /c` | Windows |
340
+ | `.ps1` | `powershell.exe -File` | Windows |
341
+ | `.js` | `node` | Cross-platform |
342
+ | `.py` | `python3` / `python` | Cross-platform |
343
+
344
+ Each script becomes a Tool that accepts a single `args: string` parameter, passed as CLI arguments to the script.
345
+
346
+ ## Context Management
347
+
348
+ Automatic token tracking with configurable thresholds:
349
+
350
+ ```typescript
351
+ import { ContextManager } from "kagent-ts";
352
+
353
+ const ctx = new ContextManager({
354
+ maxTokens: 128000,
355
+ compressionThresholdRatio: 0.75, // compress at 75% capacity
356
+ compressionRatio: 0.5, // remove 50% of messages on compress
357
+ });
358
+ ```
359
+
360
+ ## Compression
361
+
362
+ Sliding window strategy keeps the most recent messages:
363
+
364
+ ```typescript
365
+ import { SlidingWindowCompression } from "kagent-ts";
366
+
367
+ const compressor = new SlidingWindowCompression({
368
+ keepLastN: 20,
369
+ keepSystemMessages: true,
370
+ });
371
+
372
+ const result = compressor.compress(messages, systemPrompt);
373
+ // result.messages — compressed list
374
+ // result.removedCount — how many were removed
375
+ ```
376
+
377
+ ## Message API
378
+
379
+ ```typescript
380
+ import { Message } from "kagent-ts";
381
+
382
+ Message.user("Hello");
383
+ Message.system("You are a helpful assistant.");
384
+ Message.assistant("Hi there!");
385
+ Message.tool("Result", "call_123", "calculator");
386
+
387
+ msg.toDict(); // { role: "user", content: "Hello" }
388
+ msg.toJSON(); // JSON string
389
+ Message.fromJSON(json); // Deserialize
390
+ Message.fromJSONBulk(array); // Deserialize array
391
+ ```
392
+
393
+ ## License
394
+
395
+ MIT
@@ -0,0 +1,26 @@
1
+ import { MessageData } from "../messages/types";
2
+ /**
3
+ * Result of performing compression on a message list.
4
+ */
5
+ export interface CompressionResult {
6
+ /** The compressed/conserved messages. */
7
+ messages: MessageData[];
8
+ /** Number of messages that were removed. */
9
+ removedCount: number;
10
+ /** Whether compression was actually applied. */
11
+ applied: boolean;
12
+ }
13
+ /**
14
+ * Strategy interface for context compression.
15
+ * Implementations define how to reduce the message window when
16
+ * the token limit is exceeded.
17
+ */
18
+ export interface CompressionStrategy {
19
+ /**
20
+ * Compress the given messages to fit within the context window.
21
+ * @param messages The full list of messages.
22
+ * @param systemMessage An optional system message to preserve.
23
+ */
24
+ compress(messages: MessageData[], systemMessage?: MessageData): CompressionResult;
25
+ }
26
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/compression/interface.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,yCAAyC;IACzC,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,4CAA4C;IAC5C,YAAY,EAAE,MAAM,CAAC;IACrB,gDAAgD;IAChD,OAAO,EAAE,OAAO,CAAC;CAClB;AAED;;;;GAIG;AACH,MAAM,WAAW,mBAAmB;IAClC;;;;OAIG;IACH,QAAQ,CACN,QAAQ,EAAE,WAAW,EAAE,EACvB,aAAa,CAAC,EAAE,WAAW,GAC1B,iBAAiB,CAAC;CACtB"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/compression/interface.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { MessageData } from "../messages/types";
2
+ import { CompressionStrategy, CompressionResult } from "./interface";
3
+ import { CompressionConfig } from "./types";
4
+ /**
5
+ * Sliding window compression strategy.
6
+ *
7
+ * Preserves:
8
+ * 1. The system message (if present and configured to keep it)
9
+ * 2. The last N messages (most recent conversation turns)
10
+ *
11
+ * Everything in between is discarded.
12
+ */
13
+ export declare class SlidingWindowCompression implements CompressionStrategy {
14
+ private config;
15
+ /**
16
+ * Default config: keep the last 20 messages, preserve system messages.
17
+ */
18
+ constructor(config?: Partial<CompressionConfig>);
19
+ compress(messages: MessageData[], systemMessage?: MessageData): CompressionResult;
20
+ }
21
+ //# sourceMappingURL=sliding-window.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliding-window.d.ts","sourceRoot":"","sources":["../../src/compression/sliding-window.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,iBAAiB,EAAE,MAAM,SAAS,CAAC;AAE5C;;;;;;;;GAQG;AACH,qBAAa,wBAAyB,YAAW,mBAAmB;IAClE,OAAO,CAAC,MAAM,CAAoB;IAElC;;OAEG;gBACS,MAAM,CAAC,EAAE,OAAO,CAAC,iBAAiB,CAAC;IAQ/C,QAAQ,CACN,QAAQ,EAAE,WAAW,EAAE,EACvB,aAAa,CAAC,EAAE,WAAW,GAC1B,iBAAiB;CAoCrB"}
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SlidingWindowCompression = void 0;
4
+ /**
5
+ * Sliding window compression strategy.
6
+ *
7
+ * Preserves:
8
+ * 1. The system message (if present and configured to keep it)
9
+ * 2. The last N messages (most recent conversation turns)
10
+ *
11
+ * Everything in between is discarded.
12
+ */
13
+ class SlidingWindowCompression {
14
+ config;
15
+ /**
16
+ * Default config: keep the last 20 messages, preserve system messages.
17
+ */
18
+ constructor(config) {
19
+ this.config = {
20
+ strategy: "sliding_window",
21
+ keepLastN: config?.keepLastN ?? 20,
22
+ keepSystemMessages: config?.keepSystemMessages ?? true,
23
+ };
24
+ }
25
+ compress(messages, systemMessage) {
26
+ const originalLength = messages.length;
27
+ const preserved = [];
28
+ // 1. Preserve the explicit system message if provided
29
+ if (systemMessage && this.config.keepSystemMessages) {
30
+ preserved.push(systemMessage);
31
+ }
32
+ // 2. Take the last N messages
33
+ const recent = messages.slice(-this.config.keepLastN);
34
+ preserved.push(...recent);
35
+ // 3. De-duplicate system message if it appears both in messages and param
36
+ if (systemMessage && this.config.keepSystemMessages) {
37
+ // If the system message from the param also appeared in the recent slice,
38
+ // remove the duplicate from the recent slice
39
+ const systemIndex = preserved.findIndex((m, i) => i > 0 && m.role === "system" && m.content === systemMessage.content);
40
+ if (systemIndex > 0) {
41
+ // The system message from the param is at index 0.
42
+ // Remove the duplicate entry later in the list.
43
+ preserved.splice(systemIndex, 1);
44
+ }
45
+ }
46
+ const removed = originalLength + (systemMessage ? 1 : 0) - preserved.length;
47
+ return {
48
+ messages: preserved,
49
+ removedCount: Math.max(0, removed),
50
+ applied: removed > 0,
51
+ };
52
+ }
53
+ }
54
+ exports.SlidingWindowCompression = SlidingWindowCompression;
55
+ //# sourceMappingURL=sliding-window.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sliding-window.js","sourceRoot":"","sources":["../../src/compression/sliding-window.ts"],"names":[],"mappings":";;;AAIA;;;;;;;;GAQG;AACH,MAAa,wBAAwB;IAC3B,MAAM,CAAoB;IAElC;;OAEG;IACH,YAAY,MAAmC;QAC7C,IAAI,CAAC,MAAM,GAAG;YACZ,QAAQ,EAAE,gBAAgB;YAC1B,SAAS,EAAE,MAAM,EAAE,SAAS,IAAI,EAAE;YAClC,kBAAkB,EAAE,MAAM,EAAE,kBAAkB,IAAI,IAAI;SACvD,CAAC;IACJ,CAAC;IAED,QAAQ,CACN,QAAuB,EACvB,aAA2B;QAE3B,MAAM,cAAc,GAAG,QAAQ,CAAC,MAAM,CAAC;QACvC,MAAM,SAAS,GAAkB,EAAE,CAAC;QAEpC,sDAAsD;QACtD,IAAI,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;YACpD,SAAS,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC;QAChC,CAAC;QAED,8BAA8B;QAC9B,MAAM,MAAM,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;QACtD,SAAS,CAAC,IAAI,CAAC,GAAG,MAAM,CAAC,CAAC;QAE1B,0EAA0E;QAC1E,IAAI,aAAa,IAAI,IAAI,CAAC,MAAM,CAAC,kBAAkB,EAAE,CAAC;YACpD,0EAA0E;YAC1E,6CAA6C;YAC7C,MAAM,WAAW,GAAG,SAAS,CAAC,SAAS,CACrC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CACP,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,IAAI,KAAK,QAAQ,IAAI,CAAC,CAAC,OAAO,KAAK,aAAa,CAAC,OAAO,CACtE,CAAC;YACF,IAAI,WAAW,GAAG,CAAC,EAAE,CAAC;gBACpB,mDAAmD;gBACnD,gDAAgD;gBAChD,SAAS,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC;YACnC,CAAC;QACH,CAAC;QAED,MAAM,OAAO,GAAG,cAAc,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC,MAAM,CAAC;QAE5E,OAAO;YACL,QAAQ,EAAE,SAAS;YACnB,YAAY,EAAE,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,OAAO,CAAC;YAClC,OAAO,EAAE,OAAO,GAAG,CAAC;SACrB,CAAC;IACJ,CAAC;CACF;AArDD,4DAqDC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Configuration for the compression module.
3
+ */
4
+ export interface CompressionConfig {
5
+ /** The compression strategy to use. */
6
+ strategy: "sliding_window";
7
+ /** Number of messages to preserve when compression is triggered. */
8
+ keepLastN: number;
9
+ /** Whether to always keep system messages. */
10
+ keepSystemMessages: boolean;
11
+ }
12
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/compression/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,iBAAiB;IAChC,uCAAuC;IACvC,QAAQ,EAAE,gBAAgB,CAAC;IAE3B,oEAAoE;IACpE,SAAS,EAAE,MAAM,CAAC;IAElB,8CAA8C;IAC9C,kBAAkB,EAAE,OAAO,CAAC;CAC7B"}
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/compression/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,76 @@
1
+ import { MessageData } from "../messages/types";
2
+ import { ContextConfig, ContextState } from "./types";
3
+ /**
4
+ * ContextManager maintains the message window that will be sent to the LLM.
5
+ *
6
+ * Responsibilities:
7
+ * - Accept new messages and update the running token count.
8
+ * - Detect when the token threshold is crossed and trigger compression.
9
+ * - Provide the current message list to the caller (e.g., Agent).
10
+ */
11
+ export declare class ContextManager {
12
+ private config;
13
+ private messages;
14
+ private systemMessage;
15
+ private compressionStrategy;
16
+ private _isCompressed;
17
+ /** Optional model name for tiktoken-aware token counting. */
18
+ private modelName?;
19
+ constructor(config?: Partial<ContextConfig>);
20
+ /**
21
+ * Optionally set the model name so token counting uses tiktoken's
22
+ * model-specific encoding (e.g. "gpt-4o" → o200k_base).
23
+ */
24
+ setModelName(model: string): void;
25
+ /**
26
+ * Set or update the system message (always preserved in the window).
27
+ */
28
+ setSystemMessage(content: string): void;
29
+ /**
30
+ * Add a message to the context window.
31
+ */
32
+ addMessage(message: MessageData): void;
33
+ /**
34
+ * Check whether the context window has exceeded the compression threshold.
35
+ */
36
+ shouldCompress(): boolean;
37
+ /**
38
+ * The token count at which compression triggers.
39
+ */
40
+ private getCompressionThreshold;
41
+ /**
42
+ * Approximate token count of all messages in the window.
43
+ * When a model name has been set (via setModelName), uses tiktoken
44
+ * for model-specific encoding accuracy.
45
+ */
46
+ getCurrentTokens(): number;
47
+ /**
48
+ * Run the compression strategy to reduce the window size.
49
+ * Resets the message list to the compressed output.
50
+ */
51
+ compress(): {
52
+ removedCount: number;
53
+ };
54
+ /**
55
+ * Get the current context messages (ready to send to the LLM).
56
+ * Includes the system message as the first element if set.
57
+ */
58
+ getContextMessages(): MessageData[];
59
+ /**
60
+ * Get the raw messages (without system message prepended).
61
+ */
62
+ getMessages(): MessageData[];
63
+ /**
64
+ * Check if compression has been applied.
65
+ */
66
+ get isCompressed(): boolean;
67
+ /**
68
+ * Get the current state of the context window.
69
+ */
70
+ getState(): ContextState;
71
+ /**
72
+ * Clear all messages from the window (preserves system message).
73
+ */
74
+ clear(): void;
75
+ }
76
+ //# sourceMappingURL=context-manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context-manager.d.ts","sourceRoot":"","sources":["../../src/context/context-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAQ,MAAM,mBAAmB,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAKtD;;;;;;;GAOG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,QAAQ,CAAqB;IACrC,OAAO,CAAC,aAAa,CAA4B;IACjD,OAAO,CAAC,mBAAmB,CAAsB;IACjD,OAAO,CAAC,aAAa,CAAS;IAC9B,6DAA6D;IAC7D,OAAO,CAAC,SAAS,CAAC,CAAS;gBAEf,MAAM,CAAC,EAAE,OAAO,CAAC,aAAa,CAAC;IAW3C;;;OAGG;IACH,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,IAAI;IAIjC;;OAEG;IACH,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIvC;;OAEG;IACH,UAAU,CAAC,OAAO,EAAE,WAAW,GAAG,IAAI;IAItC;;OAEG;IACH,cAAc,IAAI,OAAO;IAIzB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAM/B;;;;OAIG;IACH,gBAAgB,IAAI,MAAM;IAc1B;;;OAGG;IACH,QAAQ,IAAI;QAAE,YAAY,EAAE,MAAM,CAAA;KAAE;IAUpC;;;OAGG;IACH,kBAAkB,IAAI,WAAW,EAAE;IAOnC;;OAEG;IACH,WAAW,IAAI,WAAW,EAAE;IAI5B;;OAEG;IACH,IAAI,YAAY,IAAI,OAAO,CAE1B;IAED;;OAEG;IACH,QAAQ,IAAI,YAAY;IASxB;;OAEG;IACH,KAAK,IAAI,IAAI;CAId"}