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.
- package/LICENSE +21 -0
- package/README.md +395 -0
- package/dist/compression/interface.d.ts +26 -0
- package/dist/compression/interface.d.ts.map +1 -0
- package/dist/compression/interface.js +3 -0
- package/dist/compression/interface.js.map +1 -0
- package/dist/compression/sliding-window.d.ts +21 -0
- package/dist/compression/sliding-window.d.ts.map +1 -0
- package/dist/compression/sliding-window.js +55 -0
- package/dist/compression/sliding-window.js.map +1 -0
- package/dist/compression/types.d.ts +12 -0
- package/dist/compression/types.d.ts.map +1 -0
- package/dist/compression/types.js +3 -0
- package/dist/compression/types.js.map +1 -0
- package/dist/context/context-manager.d.ts +76 -0
- package/dist/context/context-manager.d.ts.map +1 -0
- package/dist/context/context-manager.js +132 -0
- package/dist/context/context-manager.js.map +1 -0
- package/dist/context/types.d.ts +35 -0
- package/dist/context/types.d.ts.map +1 -0
- package/dist/context/types.js +3 -0
- package/dist/context/types.js.map +1 -0
- package/dist/core/agent.d.ts +288 -0
- package/dist/core/agent.d.ts.map +1 -0
- package/dist/core/agent.js +398 -0
- package/dist/core/agent.js.map +1 -0
- package/dist/core/hooks.d.ts +34 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +3 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/plan-solve-agent.d.ts +114 -0
- package/dist/core/plan-solve-agent.d.ts.map +1 -0
- package/dist/core/plan-solve-agent.js +450 -0
- package/dist/core/plan-solve-agent.js.map +1 -0
- package/dist/core/react-agent.d.ts +52 -0
- package/dist/core/react-agent.d.ts.map +1 -0
- package/dist/core/react-agent.js +266 -0
- package/dist/core/react-agent.js.map +1 -0
- package/dist/core/response-schema.d.ts +91 -0
- package/dist/core/response-schema.d.ts.map +1 -0
- package/dist/core/response-schema.js +292 -0
- package/dist/core/response-schema.js.map +1 -0
- package/dist/core/types.d.ts +6 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +3 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +39 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/llm/interface.d.ts +87 -0
- package/dist/llm/interface.d.ts.map +1 -0
- package/dist/llm/interface.js +3 -0
- package/dist/llm/interface.js.map +1 -0
- package/dist/llm/openai-provider.d.ts +92 -0
- package/dist/llm/openai-provider.d.ts.map +1 -0
- package/dist/llm/openai-provider.js +262 -0
- package/dist/llm/openai-provider.js.map +1 -0
- package/dist/messages/message.d.ts +50 -0
- package/dist/messages/message.d.ts.map +1 -0
- package/dist/messages/message.js +87 -0
- package/dist/messages/message.js.map +1 -0
- package/dist/messages/types.d.ts +31 -0
- package/dist/messages/types.d.ts.map +1 -0
- package/dist/messages/types.js +14 -0
- package/dist/messages/types.js.map +1 -0
- package/dist/preferences/preference-manager.d.ts +88 -0
- package/dist/preferences/preference-manager.d.ts.map +1 -0
- package/dist/preferences/preference-manager.js +196 -0
- package/dist/preferences/preference-manager.js.map +1 -0
- package/dist/preferences/types.d.ts +27 -0
- package/dist/preferences/types.d.ts.map +1 -0
- package/dist/preferences/types.js +3 -0
- package/dist/preferences/types.js.map +1 -0
- package/dist/session/session-manager.d.ts +56 -0
- package/dist/session/session-manager.d.ts.map +1 -0
- package/dist/session/session-manager.js +156 -0
- package/dist/session/session-manager.js.map +1 -0
- package/dist/session/session-types.d.ts +51 -0
- package/dist/session/session-types.d.ts.map +1 -0
- package/dist/session/session-types.js +3 -0
- package/dist/session/session-types.js.map +1 -0
- package/dist/skills/file-skill-loader.d.ts +88 -0
- package/dist/skills/file-skill-loader.d.ts.map +1 -0
- package/dist/skills/file-skill-loader.js +365 -0
- package/dist/skills/file-skill-loader.js.map +1 -0
- package/dist/skills/index.d.ts +4 -0
- package/dist/skills/index.d.ts.map +1 -0
- package/dist/skills/index.js +10 -0
- package/dist/skills/index.js.map +1 -0
- package/dist/skills/skill-manager.d.ts +133 -0
- package/dist/skills/skill-manager.d.ts.map +1 -0
- package/dist/skills/skill-manager.js +310 -0
- package/dist/skills/skill-manager.js.map +1 -0
- package/dist/skills/types.d.ts +42 -0
- package/dist/skills/types.d.ts.map +1 -0
- package/dist/skills/types.js +3 -0
- package/dist/skills/types.js.map +1 -0
- package/dist/tools/builtin/edit-file.d.ts +12 -0
- package/dist/tools/builtin/edit-file.d.ts.map +1 -0
- package/dist/tools/builtin/edit-file.js +123 -0
- package/dist/tools/builtin/edit-file.js.map +1 -0
- package/dist/tools/builtin/glob-search.d.ts +11 -0
- package/dist/tools/builtin/glob-search.d.ts.map +1 -0
- package/dist/tools/builtin/glob-search.js +264 -0
- package/dist/tools/builtin/glob-search.js.map +1 -0
- package/dist/tools/builtin/grep-search.d.ts +14 -0
- package/dist/tools/builtin/grep-search.d.ts.map +1 -0
- package/dist/tools/builtin/grep-search.js +264 -0
- package/dist/tools/builtin/grep-search.js.map +1 -0
- package/dist/tools/builtin/index.d.ts +21 -0
- package/dist/tools/builtin/index.d.ts.map +1 -0
- package/dist/tools/builtin/index.js +53 -0
- package/dist/tools/builtin/index.js.map +1 -0
- package/dist/tools/builtin/read-file.d.ts +11 -0
- package/dist/tools/builtin/read-file.d.ts.map +1 -0
- package/dist/tools/builtin/read-file.js +122 -0
- package/dist/tools/builtin/read-file.js.map +1 -0
- package/dist/tools/builtin/write-file.d.ts +10 -0
- package/dist/tools/builtin/write-file.d.ts.map +1 -0
- package/dist/tools/builtin/write-file.js +89 -0
- package/dist/tools/builtin/write-file.js.map +1 -0
- package/dist/tools/circuit-breaker.d.ts +77 -0
- package/dist/tools/circuit-breaker.d.ts.map +1 -0
- package/dist/tools/circuit-breaker.js +102 -0
- package/dist/tools/circuit-breaker.js.map +1 -0
- package/dist/tools/error-tracker.d.ts +116 -0
- package/dist/tools/error-tracker.d.ts.map +1 -0
- package/dist/tools/error-tracker.js +484 -0
- package/dist/tools/error-tracker.js.map +1 -0
- package/dist/tools/tool-registry.d.ts +87 -0
- package/dist/tools/tool-registry.d.ts.map +1 -0
- package/dist/tools/tool-registry.js +188 -0
- package/dist/tools/tool-registry.js.map +1 -0
- package/dist/tools/types.d.ts +95 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +14 -0
- package/dist/tools/types.js.map +1 -0
- package/dist/utils/token-counter.d.ts +31 -0
- package/dist/utils/token-counter.d.ts.map +1 -0
- package/dist/utils/token-counter.js +105 -0
- package/dist/utils/token-counter.js.map +1 -0
- 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 @@
|
|
|
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 @@
|
|
|
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"}
|