thatgfsj-code 0.2.1
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/.patches/0001-fix-repl-replace-readline-with-inquirer-input-for-ke.patch +279 -0
- package/.patches/0002-fix-repl-stream-AI-output-directly-to-stdout-so-term.patch +564 -0
- package/.patches/0003-fix-session-break-the-hallucination-loop-in-assistan.patch +194 -0
- package/.patches/0004-chore-release-bump-version-to-0.2.1.patch +24 -0
- package/LICENSE +21 -0
- package/README.md +100 -0
- package/ROADMAP.md +107 -0
- package/dist/agent/core.d.ts +56 -0
- package/dist/agent/core.d.ts.map +1 -0
- package/dist/agent/core.js +142 -0
- package/dist/agent/core.js.map +1 -0
- package/dist/agent/index.d.ts +8 -0
- package/dist/agent/index.d.ts.map +1 -0
- package/dist/agent/index.js +8 -0
- package/dist/agent/index.js.map +1 -0
- package/dist/agent/intent.d.ts +36 -0
- package/dist/agent/intent.d.ts.map +1 -0
- package/dist/agent/intent.js +146 -0
- package/dist/agent/intent.js.map +1 -0
- package/dist/agent/streaming.d.ts +50 -0
- package/dist/agent/streaming.d.ts.map +1 -0
- package/dist/agent/streaming.js +110 -0
- package/dist/agent/streaming.js.map +1 -0
- package/dist/core/ai-engine.d.ts +59 -0
- package/dist/core/ai-engine.d.ts.map +1 -0
- package/dist/core/ai-engine.js +378 -0
- package/dist/core/ai-engine.js.map +1 -0
- package/dist/core/cli.d.ts +21 -0
- package/dist/core/cli.d.ts.map +1 -0
- package/dist/core/cli.js +143 -0
- package/dist/core/cli.js.map +1 -0
- package/dist/core/config.d.ts +38 -0
- package/dist/core/config.d.ts.map +1 -0
- package/dist/core/config.js +129 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/context-compactor.d.ts +54 -0
- package/dist/core/context-compactor.d.ts.map +1 -0
- package/dist/core/context-compactor.js +197 -0
- package/dist/core/context-compactor.js.map +1 -0
- package/dist/core/hooks.d.ts +75 -0
- package/dist/core/hooks.d.ts.map +1 -0
- package/dist/core/hooks.js +146 -0
- package/dist/core/hooks.js.map +1 -0
- package/dist/core/permissions.d.ts +52 -0
- package/dist/core/permissions.d.ts.map +1 -0
- package/dist/core/permissions.js +237 -0
- package/dist/core/permissions.js.map +1 -0
- package/dist/core/session.d.ts +54 -0
- package/dist/core/session.d.ts.map +1 -0
- package/dist/core/session.js +147 -0
- package/dist/core/session.js.map +1 -0
- package/dist/core/skills.d.ts +60 -0
- package/dist/core/skills.d.ts.map +1 -0
- package/dist/core/skills.js +175 -0
- package/dist/core/skills.js.map +1 -0
- package/dist/core/state.d.ts +60 -0
- package/dist/core/state.d.ts.map +1 -0
- package/dist/core/state.js +106 -0
- package/dist/core/state.js.map +1 -0
- package/dist/core/subagent.d.ts +68 -0
- package/dist/core/subagent.d.ts.map +1 -0
- package/dist/core/subagent.js +142 -0
- package/dist/core/subagent.js.map +1 -0
- package/dist/core/system-prompt.d.ts +40 -0
- package/dist/core/system-prompt.d.ts.map +1 -0
- package/dist/core/system-prompt.js +138 -0
- package/dist/core/system-prompt.js.map +1 -0
- package/dist/core/tool-registry.d.ts +53 -0
- package/dist/core/tool-registry.d.ts.map +1 -0
- package/dist/core/tool-registry.js +138 -0
- package/dist/core/tool-registry.js.map +1 -0
- package/dist/core/types.d.ts +206 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +127 -0
- package/dist/core/types.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +481 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/client.d.ts +83 -0
- package/dist/mcp/client.d.ts.map +1 -0
- package/dist/mcp/client.js +267 -0
- package/dist/mcp/client.js.map +1 -0
- package/dist/repl/index.d.ts +8 -0
- package/dist/repl/index.d.ts.map +1 -0
- package/dist/repl/index.js +8 -0
- package/dist/repl/index.js.map +1 -0
- package/dist/repl/input.d.ts +61 -0
- package/dist/repl/input.d.ts.map +1 -0
- package/dist/repl/input.js +127 -0
- package/dist/repl/input.js.map +1 -0
- package/dist/repl/loop.d.ts +53 -0
- package/dist/repl/loop.d.ts.map +1 -0
- package/dist/repl/loop.js +241 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/output.d.ts +105 -0
- package/dist/repl/output.d.ts.map +1 -0
- package/dist/repl/output.js +197 -0
- package/dist/repl/output.js.map +1 -0
- package/dist/repl/welcome.d.ts +68 -0
- package/dist/repl/welcome.d.ts.map +1 -0
- package/dist/repl/welcome.js +249 -0
- package/dist/repl/welcome.js.map +1 -0
- package/dist/tools/file.d.ts +46 -0
- package/dist/tools/file.d.ts.map +1 -0
- package/dist/tools/file.js +100 -0
- package/dist/tools/file.js.map +1 -0
- package/dist/tools/git.d.ts +52 -0
- package/dist/tools/git.d.ts.map +1 -0
- package/dist/tools/git.js +112 -0
- package/dist/tools/git.js.map +1 -0
- package/dist/tools/index.d.ts +22 -0
- package/dist/tools/index.d.ts.map +1 -0
- package/dist/tools/index.js +43 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/tools/search.d.ts +36 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +223 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/shell.d.ts +57 -0
- package/dist/tools/shell.d.ts.map +1 -0
- package/dist/tools/shell.js +153 -0
- package/dist/tools/shell.js.map +1 -0
- package/dist/utils/diff-preview.d.ts +42 -0
- package/dist/utils/diff-preview.d.ts.map +1 -0
- package/dist/utils/diff-preview.js +174 -0
- package/dist/utils/diff-preview.js.map +1 -0
- package/dist/utils/index.d.ts +8 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +8 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/memory.d.ts +81 -0
- package/dist/utils/memory.d.ts.map +1 -0
- package/dist/utils/memory.js +186 -0
- package/dist/utils/memory.js.map +1 -0
- package/dist/utils/project-context.d.ts +62 -0
- package/dist/utils/project-context.d.ts.map +1 -0
- package/dist/utils/project-context.js +197 -0
- package/dist/utils/project-context.js.map +1 -0
- package/docs/API_KEY_GUIDE.md +236 -0
- package/docs/FAQ.md +182 -0
- package/install.bat +63 -0
- package/install.ps1 +238 -0
- package/install.sh +113 -0
- package/package.json +36 -0
- package/src/agent/core.ts +179 -0
- package/src/agent/index.ts +8 -0
- package/src/agent/intent.ts +181 -0
- package/src/agent/streaming.ts +132 -0
- package/src/core/ai-engine.ts +437 -0
- package/src/core/cli.ts +171 -0
- package/src/core/config.ts +147 -0
- package/src/core/context-compactor.ts +245 -0
- package/src/core/hooks.ts +196 -0
- package/src/core/permissions.ts +308 -0
- package/src/core/session.ts +165 -0
- package/src/core/skills.ts +208 -0
- package/src/core/state.ts +120 -0
- package/src/core/subagent.ts +195 -0
- package/src/core/system-prompt.ts +163 -0
- package/src/core/tool-registry.ts +157 -0
- package/src/core/types.ts +280 -0
- package/src/index.ts +544 -0
- package/src/mcp/client.ts +330 -0
- package/src/repl/index.ts +8 -0
- package/src/repl/input.ts +139 -0
- package/src/repl/loop.ts +280 -0
- package/src/repl/output.ts +222 -0
- package/src/repl/welcome.ts +296 -0
- package/src/tools/file.ts +117 -0
- package/src/tools/git.ts +132 -0
- package/src/tools/index.ts +48 -0
- package/src/tools/search.ts +263 -0
- package/src/tools/shell.ts +181 -0
- package/src/utils/diff-preview.ts +202 -0
- package/src/utils/index.ts +8 -0
- package/src/utils/memory.ts +223 -0
- package/src/utils/project-context.ts +207 -0
- package/tsconfig.json +19 -0
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Config Manager - Handles configuration loading and saving
|
|
3
|
+
* Supports multiple AI providers: MiniMax, SiliconFlow, OpenAI, Anthropic
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync, writeFileSync, existsSync, mkdirSync } from 'fs';
|
|
6
|
+
import { join, dirname } from 'path';
|
|
7
|
+
import { homedir } from 'os';
|
|
8
|
+
import { PROVIDERS } from './types.js';
|
|
9
|
+
const DEFAULT_CONFIG = {
|
|
10
|
+
model: 'Qwen/Qwen2.5-7B-Instruct',
|
|
11
|
+
apiKey: '',
|
|
12
|
+
temperature: 0.7,
|
|
13
|
+
maxTokens: 4096,
|
|
14
|
+
provider: 'siliconflow',
|
|
15
|
+
baseUrl: 'https://api.siliconflow.cn/v1'
|
|
16
|
+
};
|
|
17
|
+
export class ConfigManager {
|
|
18
|
+
configPath;
|
|
19
|
+
constructor() {
|
|
20
|
+
const homeDir = homedir();
|
|
21
|
+
const configDir = join(homeDir, '.thatgfsj');
|
|
22
|
+
this.configPath = join(configDir, 'config.json');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Load configuration with environment variable support
|
|
26
|
+
*/
|
|
27
|
+
static async load() {
|
|
28
|
+
const manager = new ConfigManager();
|
|
29
|
+
return manager.loadConfig();
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Load config from file and merge with environment variables
|
|
33
|
+
*/
|
|
34
|
+
loadConfig() {
|
|
35
|
+
let config = { ...DEFAULT_CONFIG };
|
|
36
|
+
try {
|
|
37
|
+
if (existsSync(this.configPath)) {
|
|
38
|
+
const data = readFileSync(this.configPath, 'utf-8');
|
|
39
|
+
const loaded = JSON.parse(data);
|
|
40
|
+
config = { ...config, ...loaded };
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
console.warn('Failed to load config, using defaults:', error);
|
|
45
|
+
}
|
|
46
|
+
// Resolve provider and get API key from environment
|
|
47
|
+
config = this.resolveProvider(config);
|
|
48
|
+
return config;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve provider and API key from config or environment
|
|
52
|
+
*/
|
|
53
|
+
resolveProvider(config) {
|
|
54
|
+
const provider = config.provider || 'siliconflow';
|
|
55
|
+
const providerConfig = (provider !== 'custom' && provider !== undefined) ? PROVIDERS[provider] : null;
|
|
56
|
+
if (!providerConfig) {
|
|
57
|
+
console.warn(`Unknown provider: ${provider}, falling back to siliconflow`);
|
|
58
|
+
return { ...config, provider: 'siliconflow', baseUrl: PROVIDERS.siliconflow.baseUrl };
|
|
59
|
+
}
|
|
60
|
+
// MODEL environment variable has highest priority
|
|
61
|
+
let model = process.env.MODEL || config.model || providerConfig.defaultModel;
|
|
62
|
+
// Handle Ollama (local, no API key needed)
|
|
63
|
+
let apiKey = config.apiKey;
|
|
64
|
+
let baseUrl = config.baseUrl || providerConfig.baseUrl;
|
|
65
|
+
if (provider === 'ollama') {
|
|
66
|
+
// Ollama doesn't need an API key
|
|
67
|
+
apiKey = '';
|
|
68
|
+
// Allow custom base URL via environment
|
|
69
|
+
baseUrl = process.env.OLLAMA_BASE_URL || baseUrl;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
// Try to get API key from environment
|
|
73
|
+
for (const envKey of providerConfig.envKeys) {
|
|
74
|
+
if (process.env[envKey]) {
|
|
75
|
+
apiKey = process.env[envKey];
|
|
76
|
+
break;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
return {
|
|
81
|
+
...config,
|
|
82
|
+
provider,
|
|
83
|
+
baseUrl,
|
|
84
|
+
model,
|
|
85
|
+
apiKey: apiKey || ''
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Get AIConfig for AIEngine
|
|
90
|
+
*/
|
|
91
|
+
static async getAIConfig() {
|
|
92
|
+
const config = await ConfigManager.load();
|
|
93
|
+
return {
|
|
94
|
+
model: config.model,
|
|
95
|
+
apiKey: config.apiKey,
|
|
96
|
+
temperature: config.temperature,
|
|
97
|
+
maxTokens: config.maxTokens,
|
|
98
|
+
baseUrl: config.baseUrl,
|
|
99
|
+
provider: config.provider
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Save configuration
|
|
104
|
+
*/
|
|
105
|
+
async save(config) {
|
|
106
|
+
const current = this.loadConfig();
|
|
107
|
+
const merged = { ...current, ...config };
|
|
108
|
+
const dir = dirname(this.configPath);
|
|
109
|
+
if (!existsSync(dir)) {
|
|
110
|
+
mkdirSync(dir, { recursive: true });
|
|
111
|
+
}
|
|
112
|
+
writeFileSync(this.configPath, JSON.stringify(merged, null, 2));
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Get config path
|
|
116
|
+
*/
|
|
117
|
+
getPath() {
|
|
118
|
+
return this.configPath;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* List available providers
|
|
122
|
+
*/
|
|
123
|
+
static listProviders() {
|
|
124
|
+
return Object.entries(PROVIDERS)
|
|
125
|
+
.map(([key, val]) => ` ${key}: ${val.name}`)
|
|
126
|
+
.join('\n');
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S05: Context Compactor - 3-tier progressive compression strategy
|
|
3
|
+
*
|
|
4
|
+
* Tier 1: Truncation - Remove oldest messages beyond hard limit
|
|
5
|
+
* Tier 2: Summarize - Replace old message ranges with summary
|
|
6
|
+
* Tier 3: Selective - Keep only recent N turns around tool executions
|
|
7
|
+
*
|
|
8
|
+
* Core insight: Context window is finite. Three-tier strategy enables "infinite" work.
|
|
9
|
+
*/
|
|
10
|
+
import { ChatMessage } from './types.js';
|
|
11
|
+
export interface CompactorConfig {
|
|
12
|
+
/** Hard limit: messages beyond this get removed first */
|
|
13
|
+
hardLimit?: number;
|
|
14
|
+
/** Soft limit: messages beyond this get summarized */
|
|
15
|
+
softLimit?: number;
|
|
16
|
+
/** How many recent turns to always preserve */
|
|
17
|
+
preserveRecent?: number;
|
|
18
|
+
/** Enable summarization (requires AI API) */
|
|
19
|
+
enableSummarize?: boolean;
|
|
20
|
+
}
|
|
21
|
+
export interface CompressionResult {
|
|
22
|
+
originalCount: number;
|
|
23
|
+
compactedCount: number;
|
|
24
|
+
removedCount: number;
|
|
25
|
+
method: 'none' | 'truncation' | 'summarize' | 'selective';
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* S05: Context Compactor
|
|
29
|
+
*/
|
|
30
|
+
export declare class ContextCompactor {
|
|
31
|
+
private config;
|
|
32
|
+
private totalTokensUsed;
|
|
33
|
+
constructor(config?: CompactorConfig);
|
|
34
|
+
/**
|
|
35
|
+
* S05: Compact messages using 3-tier strategy
|
|
36
|
+
* Called at the end of each agent turn
|
|
37
|
+
*/
|
|
38
|
+
compact(messages: ChatMessage[]): {
|
|
39
|
+
compacted: ChatMessage[];
|
|
40
|
+
result: CompressionResult;
|
|
41
|
+
};
|
|
42
|
+
private truncate;
|
|
43
|
+
private summarizeStrategy;
|
|
44
|
+
private summarizeTopic;
|
|
45
|
+
private selectiveStrategy;
|
|
46
|
+
isNearLimit(messages: ChatMessage[], limit?: number): boolean;
|
|
47
|
+
estimateTokens(messages: ChatMessage[]): number;
|
|
48
|
+
autoCompact(messages: ChatMessage[]): {
|
|
49
|
+
compacted: ChatMessage[];
|
|
50
|
+
result: CompressionResult;
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
export declare function integrateWithSessionManager(SessionManagerClass: any): void;
|
|
54
|
+
//# sourceMappingURL=context-compactor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-compactor.d.ts","sourceRoot":"","sources":["../../src/core/context-compactor.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,MAAM,WAAW,eAAe;IAC9B,yDAAyD;IACzD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sDAAsD;IACtD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,+CAA+C;IAC/C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,6CAA6C;IAC7C,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,iBAAiB;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,EAAE,MAAM,CAAC;IACrB,MAAM,EAAE,MAAM,GAAG,YAAY,GAAG,WAAW,GAAG,WAAW,CAAC;CAC3D;AAED;;GAEG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAkB;IAChC,OAAO,CAAC,eAAe,CAAK;gBAEhB,MAAM,GAAE,eAAoB;IAUxC;;;OAGG;IACH,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG;QAAE,SAAS,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,iBAAiB,CAAA;KAAE;IAqBzF,OAAO,CAAC,QAAQ;IAehB,OAAO,CAAC,iBAAiB;IAuCzB,OAAO,CAAC,cAAc;IAWtB,OAAO,CAAC,iBAAiB;IAiEzB,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,EAAE,KAAK,GAAE,MAAe,GAAG,OAAO;IAOrE,cAAc,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG,MAAM;IAQ/C,WAAW,CAAC,QAAQ,EAAE,WAAW,EAAE,GAAG;QAAE,SAAS,EAAE,WAAW,EAAE,CAAC;QAAC,MAAM,EAAE,iBAAiB,CAAA;KAAE;CAS9F;AAID,wBAAgB,2BAA2B,CAAC,mBAAmB,EAAE,GAAG,QAcnE"}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S05: Context Compactor - 3-tier progressive compression strategy
|
|
3
|
+
*
|
|
4
|
+
* Tier 1: Truncation - Remove oldest messages beyond hard limit
|
|
5
|
+
* Tier 2: Summarize - Replace old message ranges with summary
|
|
6
|
+
* Tier 3: Selective - Keep only recent N turns around tool executions
|
|
7
|
+
*
|
|
8
|
+
* Core insight: Context window is finite. Three-tier strategy enables "infinite" work.
|
|
9
|
+
*/
|
|
10
|
+
/**
|
|
11
|
+
* S05: Context Compactor
|
|
12
|
+
*/
|
|
13
|
+
export class ContextCompactor {
|
|
14
|
+
config;
|
|
15
|
+
totalTokensUsed = 0;
|
|
16
|
+
constructor(config = {}) {
|
|
17
|
+
this.config = {
|
|
18
|
+
hardLimit: 50,
|
|
19
|
+
softLimit: 30,
|
|
20
|
+
preserveRecent: 10,
|
|
21
|
+
enableSummarize: false,
|
|
22
|
+
...config
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* S05: Compact messages using 3-tier strategy
|
|
27
|
+
* Called at the end of each agent turn
|
|
28
|
+
*/
|
|
29
|
+
compact(messages) {
|
|
30
|
+
const count = messages.length;
|
|
31
|
+
// Tier 1: Within hard limit — no compression
|
|
32
|
+
if (count <= (this.config.hardLimit || 50)) {
|
|
33
|
+
return {
|
|
34
|
+
compacted: messages,
|
|
35
|
+
result: { originalCount: count, compactedCount: count, removedCount: 0, method: 'none' }
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
// Tier 2: Beyond soft limit — summarize middle messages
|
|
39
|
+
if (count > (this.config.softLimit || 30)) {
|
|
40
|
+
return this.summarizeStrategy(messages);
|
|
41
|
+
}
|
|
42
|
+
// Tier 3: Between soft and hard — selective preservation
|
|
43
|
+
return this.selectiveStrategy(messages);
|
|
44
|
+
}
|
|
45
|
+
// Tier 1: Simple truncation
|
|
46
|
+
truncate(messages, maxMessages) {
|
|
47
|
+
const systemMsg = messages.find(m => m.role === 'system');
|
|
48
|
+
const others = messages.filter(m => m.role !== 'system');
|
|
49
|
+
const toRemove = others.length - maxMessages;
|
|
50
|
+
if (toRemove <= 0 || others.length === 0) {
|
|
51
|
+
return messages;
|
|
52
|
+
}
|
|
53
|
+
// Remove oldest non-system messages
|
|
54
|
+
const keptOthers = others.slice(toRemove);
|
|
55
|
+
return systemMsg ? [systemMsg, ...keptOthers] : keptOthers;
|
|
56
|
+
}
|
|
57
|
+
// Tier 2: Summarize middle messages (stub — needs AI for real summarization)
|
|
58
|
+
summarizeStrategy(messages) {
|
|
59
|
+
const preserved = this.config.preserveRecent || 10;
|
|
60
|
+
const systemMsg = messages.find(m => m.role === 'system');
|
|
61
|
+
const others = messages.filter(m => m.role !== 'system');
|
|
62
|
+
if (others.length <= preserved) {
|
|
63
|
+
return {
|
|
64
|
+
compacted: messages,
|
|
65
|
+
result: { originalCount: messages.length, compactedCount: messages.length, removedCount: 0, method: 'none' }
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Keep recent N turns
|
|
69
|
+
const recent = others.slice(-preserved);
|
|
70
|
+
// Summarize the middle (this is a placeholder — real impl would call AI)
|
|
71
|
+
const summaryMsg = {
|
|
72
|
+
role: 'system',
|
|
73
|
+
content: '[S05: ' + (others.length - preserved) + ' earlier messages summarized — ' +
|
|
74
|
+
'conversation had ' + (others.length - preserved) + ' exchanges covering ' +
|
|
75
|
+
this.summarizeTopic(others.slice(0, -preserved)) + ']'
|
|
76
|
+
};
|
|
77
|
+
const compacted = systemMsg
|
|
78
|
+
? [systemMsg, summaryMsg, ...recent]
|
|
79
|
+
: [summaryMsg, ...recent];
|
|
80
|
+
return {
|
|
81
|
+
compacted,
|
|
82
|
+
result: {
|
|
83
|
+
originalCount: messages.length,
|
|
84
|
+
compactedCount: compacted.length,
|
|
85
|
+
removedCount: messages.length - compacted.length,
|
|
86
|
+
method: 'summarize'
|
|
87
|
+
}
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
// Extract simple topic from message content
|
|
91
|
+
summarizeTopic(msgs) {
|
|
92
|
+
const texts = msgs
|
|
93
|
+
.filter(m => m.role === 'user')
|
|
94
|
+
.map(m => m.content)
|
|
95
|
+
.slice(0, 3)
|
|
96
|
+
.join(' ')
|
|
97
|
+
.substring(0, 50);
|
|
98
|
+
return texts || 'various topics';
|
|
99
|
+
}
|
|
100
|
+
// Tier 3: Selective — keep turns around tool executions
|
|
101
|
+
selectiveStrategy(messages) {
|
|
102
|
+
const systemMsg = messages.find(m => m.role === 'system');
|
|
103
|
+
const others = messages.filter(m => m.role !== 'system');
|
|
104
|
+
const max = this.config.softLimit || 30;
|
|
105
|
+
if (others.length <= max) {
|
|
106
|
+
return {
|
|
107
|
+
compacted: messages,
|
|
108
|
+
result: { originalCount: messages.length, compactedCount: messages.length, removedCount: 0, method: 'none' }
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
// Find indices of tool-related messages
|
|
112
|
+
const toolIndices = new Set();
|
|
113
|
+
others.forEach((m, i) => {
|
|
114
|
+
if (m.tool_calls || m.role === 'tool' || m.role === 'assistant') {
|
|
115
|
+
toolIndices.add(i);
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
// Also add indices around tool messages
|
|
119
|
+
for (const idx of toolIndices) {
|
|
120
|
+
for (let offset = -2; offset <= 2; offset++) {
|
|
121
|
+
toolIndices.add(idx + offset);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
// Keep system message + messages near tool executions + recent messages
|
|
125
|
+
const recentCount = Math.floor(max * 0.3); // 30% recent
|
|
126
|
+
const toolCount = max - recentCount;
|
|
127
|
+
const recent = others.slice(-recentCount);
|
|
128
|
+
const toolMsgs = [];
|
|
129
|
+
for (const idx of [...toolIndices].sort((a, b) => a - b)) {
|
|
130
|
+
if (toolMsgs.length >= toolCount)
|
|
131
|
+
break;
|
|
132
|
+
if (idx >= 0 && idx < others.length - recentCount) {
|
|
133
|
+
toolMsgs.push(others[idx]);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
const compacted = systemMsg
|
|
137
|
+
? [systemMsg, ...toolMsgs, ...recent]
|
|
138
|
+
: [...toolMsgs, ...recent];
|
|
139
|
+
// Deduplicate while preserving order
|
|
140
|
+
const seen = new Set();
|
|
141
|
+
const deduped = compacted.filter(m => {
|
|
142
|
+
const key = m.role + m.content.substring(0, 30);
|
|
143
|
+
if (seen.has(key))
|
|
144
|
+
return false;
|
|
145
|
+
seen.add(key);
|
|
146
|
+
return true;
|
|
147
|
+
});
|
|
148
|
+
return {
|
|
149
|
+
compacted: deduped,
|
|
150
|
+
result: {
|
|
151
|
+
originalCount: messages.length,
|
|
152
|
+
compactedCount: deduped.length,
|
|
153
|
+
removedCount: messages.length - deduped.length,
|
|
154
|
+
method: 'selective'
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
}
|
|
158
|
+
// S05: Check if context is approaching limit
|
|
159
|
+
isNearLimit(messages, limit = 150000) {
|
|
160
|
+
// Rough estimate: 1 message ~= 200 tokens on average
|
|
161
|
+
const estimatedTokens = messages.length * 200;
|
|
162
|
+
return estimatedTokens > limit * 0.8; // 80% of limit
|
|
163
|
+
}
|
|
164
|
+
// S05: Get estimated token count
|
|
165
|
+
estimateTokens(messages) {
|
|
166
|
+
return messages.reduce((sum, m) => {
|
|
167
|
+
// Rough: content chars / 4 tokens
|
|
168
|
+
return sum + Math.ceil(m.content.length / 4) + 10; // +10 for role/overhead
|
|
169
|
+
}, 0);
|
|
170
|
+
}
|
|
171
|
+
// S05: Auto-compact if needed (called from AIEngine or SessionManager)
|
|
172
|
+
autoCompact(messages) {
|
|
173
|
+
if (this.isNearLimit(messages)) {
|
|
174
|
+
return this.compact(messages);
|
|
175
|
+
}
|
|
176
|
+
return {
|
|
177
|
+
compacted: messages,
|
|
178
|
+
result: { originalCount: messages.length, compactedCount: messages.length, removedCount: 0, method: 'none' }
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
// ==================== SessionManager Integration ====================
|
|
183
|
+
export function integrateWithSessionManager(SessionManagerClass) {
|
|
184
|
+
const originalTruncate = SessionManagerClass.prototype.truncate;
|
|
185
|
+
SessionManagerClass.prototype.truncate = function (maxMessages, forceCompact = false) {
|
|
186
|
+
if (forceCompact) {
|
|
187
|
+
const compactor = new ContextCompactor({ hardLimit: maxMessages });
|
|
188
|
+
const { compacted, result } = compactor.autoCompact(this.messages);
|
|
189
|
+
if (result.method !== 'none') {
|
|
190
|
+
this.messages = compacted;
|
|
191
|
+
return result;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
return originalTruncate.call(this, maxMessages);
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
//# sourceMappingURL=context-compactor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-compactor.js","sourceRoot":"","sources":["../../src/core/context-compactor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S08: Hooks System
|
|
3
|
+
* Inject custom logic at key event points without modifying agent source code
|
|
4
|
+
*
|
|
5
|
+
* Hook points: before/after tool calls, before/after agent loop, onError, etc.
|
|
6
|
+
* Users can register hooks for: audit logging, auto-formatting, security filtering, notifications
|
|
7
|
+
*/
|
|
8
|
+
import { ChatMessage } from './types.js';
|
|
9
|
+
export type HookName = 'beforeToolCall' | 'afterToolCall' | 'beforeAgentLoop' | 'afterAgentLoop' | 'onError' | 'beforeMessage' | 'afterMessage' | 'onCompact';
|
|
10
|
+
export interface HookContext {
|
|
11
|
+
toolName?: string;
|
|
12
|
+
toolParams?: Record<string, any>;
|
|
13
|
+
toolResult?: any;
|
|
14
|
+
messages?: ChatMessage[];
|
|
15
|
+
error?: Error;
|
|
16
|
+
iteration?: number;
|
|
17
|
+
[key: string]: any;
|
|
18
|
+
}
|
|
19
|
+
export type HookFn = (ctx: HookContext) => void | Promise<void>;
|
|
20
|
+
export interface HookRegistration {
|
|
21
|
+
name: HookName;
|
|
22
|
+
fn: HookFn;
|
|
23
|
+
priority?: number;
|
|
24
|
+
once?: boolean;
|
|
25
|
+
}
|
|
26
|
+
export declare class HookManager {
|
|
27
|
+
private hooks;
|
|
28
|
+
constructor();
|
|
29
|
+
/**
|
|
30
|
+
* S08: Register a hook
|
|
31
|
+
* @param name Hook point name
|
|
32
|
+
* @param fn Function to run
|
|
33
|
+
* @param priority Higher priority runs first
|
|
34
|
+
* @param once If true, auto-removed after first run
|
|
35
|
+
*/
|
|
36
|
+
register(name: HookName, fn: HookFn, priority?: number, once?: boolean): void;
|
|
37
|
+
/**
|
|
38
|
+
* S08: Unregister a hook by function reference
|
|
39
|
+
*/
|
|
40
|
+
unregister(name: HookName, fn: HookFn): void;
|
|
41
|
+
/**
|
|
42
|
+
* S08: Clear all hooks for a given name (or all)
|
|
43
|
+
*/
|
|
44
|
+
clear(name?: HookName): void;
|
|
45
|
+
/**
|
|
46
|
+
* S08: Emit a hook — call all registered functions at that point
|
|
47
|
+
* Returns after all sync hooks complete, awaits async ones
|
|
48
|
+
*/
|
|
49
|
+
emit(name: HookName, ctx: HookContext): Promise<void>;
|
|
50
|
+
/**
|
|
51
|
+
* S08: Check if any hooks are registered for a given name
|
|
52
|
+
*/
|
|
53
|
+
hasHooks(name: HookName): boolean;
|
|
54
|
+
/**
|
|
55
|
+
* S08: Get hook count
|
|
56
|
+
*/
|
|
57
|
+
getHookCount(name?: HookName): number;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* S08: Audit logging hook — logs all tool calls
|
|
61
|
+
*/
|
|
62
|
+
export declare function auditLogHook(ctx: HookContext): void;
|
|
63
|
+
/**
|
|
64
|
+
* S08: Prettier auto-format hook — run prettier after file writes
|
|
65
|
+
*/
|
|
66
|
+
export declare function prettierFormatHook(ctx: HookContext): Promise<void>;
|
|
67
|
+
/**
|
|
68
|
+
* S08: Security filter hook — block suspicious patterns
|
|
69
|
+
*/
|
|
70
|
+
export declare function securityFilterHook(ctx: HookContext): {
|
|
71
|
+
blocked: boolean;
|
|
72
|
+
reason: string;
|
|
73
|
+
};
|
|
74
|
+
export declare function getHookManager(): HookManager;
|
|
75
|
+
//# sourceMappingURL=hooks.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.d.ts","sourceRoot":"","sources":["../../src/core/hooks.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,WAAW,EAAY,MAAM,YAAY,CAAC;AAInD,MAAM,MAAM,QAAQ,GAChB,gBAAgB,GAChB,eAAe,GACf,iBAAiB,GACjB,gBAAgB,GAChB,SAAS,GACT,eAAe,GACf,cAAc,GACd,WAAW,CAAC;AAEhB,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IACjC,UAAU,CAAC,EAAE,GAAG,CAAC;IACjB,QAAQ,CAAC,EAAE,WAAW,EAAE,CAAC;IACzB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACpB;AAED,MAAM,MAAM,MAAM,GAAG,CAAC,GAAG,EAAE,WAAW,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;AAEhE,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,QAAQ,CAAC;IACf,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAID,qBAAa,WAAW;IACtB,OAAO,CAAC,KAAK,CAAgD;;IAa7D;;;;;;OAMG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,QAAQ,SAAI,EAAE,IAAI,UAAQ,GAAG,IAAI;IAOtE;;OAEG;IACH,UAAU,CAAC,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,GAAG,IAAI;IAK5C;;OAEG;IACH,KAAK,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,IAAI;IAU5B;;;OAGG;IACG,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC;IAiB3D;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,QAAQ,GAAG,OAAO;IAIjC;;OAEG;IACH,YAAY,CAAC,IAAI,CAAC,EAAE,QAAQ,GAAG,MAAM;CAUtC;AAID;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,WAAW,GAAG,IAAI,CAMnD;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAWxE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,GAAG,EAAE,WAAW,GAAG;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAiBzF;AAMD,wBAAgB,cAAc,IAAI,WAAW,CAK5C"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* S08: Hooks System
|
|
3
|
+
* Inject custom logic at key event points without modifying agent source code
|
|
4
|
+
*
|
|
5
|
+
* Hook points: before/after tool calls, before/after agent loop, onError, etc.
|
|
6
|
+
* Users can register hooks for: audit logging, auto-formatting, security filtering, notifications
|
|
7
|
+
*/
|
|
8
|
+
// ==================== Hook Manager ====================
|
|
9
|
+
export class HookManager {
|
|
10
|
+
hooks = new Map();
|
|
11
|
+
constructor() {
|
|
12
|
+
// Initialize all hook types
|
|
13
|
+
const allHooks = [
|
|
14
|
+
'beforeToolCall', 'afterToolCall', 'beforeAgentLoop', 'afterAgentLoop',
|
|
15
|
+
'onError', 'beforeMessage', 'afterMessage', 'onCompact'
|
|
16
|
+
];
|
|
17
|
+
for (const h of allHooks) {
|
|
18
|
+
this.hooks.set(h, []);
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* S08: Register a hook
|
|
23
|
+
* @param name Hook point name
|
|
24
|
+
* @param fn Function to run
|
|
25
|
+
* @param priority Higher priority runs first
|
|
26
|
+
* @param once If true, auto-removed after first run
|
|
27
|
+
*/
|
|
28
|
+
register(name, fn, priority = 0, once = false) {
|
|
29
|
+
const regs = this.hooks.get(name) || [];
|
|
30
|
+
regs.push({ name, fn, priority, once });
|
|
31
|
+
regs.sort((a, b) => (b.priority || 0) - (a.priority || 0));
|
|
32
|
+
this.hooks.set(name, regs);
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* S08: Unregister a hook by function reference
|
|
36
|
+
*/
|
|
37
|
+
unregister(name, fn) {
|
|
38
|
+
const regs = this.hooks.get(name) || [];
|
|
39
|
+
this.hooks.set(name, regs.filter(r => r.fn !== fn));
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* S08: Clear all hooks for a given name (or all)
|
|
43
|
+
*/
|
|
44
|
+
clear(name) {
|
|
45
|
+
if (name) {
|
|
46
|
+
this.hooks.set(name, []);
|
|
47
|
+
}
|
|
48
|
+
else {
|
|
49
|
+
for (const [, regs] of this.hooks) {
|
|
50
|
+
regs.length = 0;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* S08: Emit a hook — call all registered functions at that point
|
|
56
|
+
* Returns after all sync hooks complete, awaits async ones
|
|
57
|
+
*/
|
|
58
|
+
async emit(name, ctx) {
|
|
59
|
+
const regs = this.hooks.get(name) || [];
|
|
60
|
+
for (const reg of regs) {
|
|
61
|
+
try {
|
|
62
|
+
await Promise.resolve(reg.fn(ctx));
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
console.error(`[Hook ${name}] error:`, error.message);
|
|
66
|
+
}
|
|
67
|
+
// Remove if one-time hook
|
|
68
|
+
if (reg.once) {
|
|
69
|
+
this.unregister(name, reg.fn);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* S08: Check if any hooks are registered for a given name
|
|
75
|
+
*/
|
|
76
|
+
hasHooks(name) {
|
|
77
|
+
return (this.hooks.get(name)?.length || 0) > 0;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* S08: Get hook count
|
|
81
|
+
*/
|
|
82
|
+
getHookCount(name) {
|
|
83
|
+
if (name) {
|
|
84
|
+
return this.hooks.get(name)?.length || 0;
|
|
85
|
+
}
|
|
86
|
+
let total = 0;
|
|
87
|
+
for (const regs of this.hooks.values()) {
|
|
88
|
+
total += regs.length;
|
|
89
|
+
}
|
|
90
|
+
return total;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
// ==================== Built-in Hooks ====================
|
|
94
|
+
/**
|
|
95
|
+
* S08: Audit logging hook — logs all tool calls
|
|
96
|
+
*/
|
|
97
|
+
export function auditLogHook(ctx) {
|
|
98
|
+
if (ctx.toolName) {
|
|
99
|
+
const ts = new Date().toISOString().split('T')[1].split('.')[0];
|
|
100
|
+
const status = ctx.toolResult?.success ? 'OK' : 'FAIL';
|
|
101
|
+
console.log(`[AUDIT ${ts}] ${status} | tool=${ctx.toolName} | params=${JSON.stringify(ctx.toolParams || {})} | result=${ctx.toolResult?.success ? 'OK' : ctx.toolResult?.error}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* S08: Prettier auto-format hook — run prettier after file writes
|
|
106
|
+
*/
|
|
107
|
+
export async function prettierFormatHook(ctx) {
|
|
108
|
+
if (ctx.toolName === 'file' && ctx.toolParams?.action === 'write') {
|
|
109
|
+
const path = ctx.toolParams.path;
|
|
110
|
+
const ext = path.split('.').pop()?.toLowerCase();
|
|
111
|
+
const formattable = ['js', 'ts', 'jsx', 'tsx', 'json', 'md', 'css', 'html'];
|
|
112
|
+
if (formattable.includes(ext || '')) {
|
|
113
|
+
console.log(`[Hook] Auto-format skipped (prettier not installed) for ${path}`);
|
|
114
|
+
// In real impl: spawn prettier on the file
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* S08: Security filter hook — block suspicious patterns
|
|
120
|
+
*/
|
|
121
|
+
export function securityFilterHook(ctx) {
|
|
122
|
+
if (ctx.toolName === 'shell' && ctx.toolParams?.command) {
|
|
123
|
+
const cmd = ctx.toolParams.command;
|
|
124
|
+
const suspicious = [
|
|
125
|
+
/curl\s+.*\|.*sh/i,
|
|
126
|
+
/wget\s+.*\|.*sh/i,
|
|
127
|
+
/base64\s+-d/i,
|
|
128
|
+
/\.\/[^/]+\s+&&.*rm/i
|
|
129
|
+
];
|
|
130
|
+
for (const pattern of suspicious) {
|
|
131
|
+
if (pattern.test(cmd)) {
|
|
132
|
+
return { blocked: true, reason: `Suspicious pattern detected: ${pattern}` };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return { blocked: false, reason: '' };
|
|
137
|
+
}
|
|
138
|
+
// ==================== Singleton ====================
|
|
139
|
+
let globalHookManager = null;
|
|
140
|
+
export function getHookManager() {
|
|
141
|
+
if (!globalHookManager) {
|
|
142
|
+
globalHookManager = new HookManager();
|
|
143
|
+
}
|
|
144
|
+
return globalHookManager;
|
|
145
|
+
}
|
|
146
|
+
//# sourceMappingURL=hooks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hooks.js","sourceRoot":"","sources":["../../src/core/hooks.ts"],"names":[],"mappings":"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"}
|