wave-agent-sdk 0.8.4 → 0.9.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/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +5 -8
- package/dist/managers/aiManager.d.ts +6 -10
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +38 -13
- package/dist/managers/hookManager.d.ts.map +1 -1
- package/dist/managers/hookManager.js +15 -1
- package/dist/managers/messageManager.d.ts +1 -0
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +8 -2
- package/dist/managers/subagentManager.d.ts +2 -11
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +4 -53
- package/dist/prompts/autoMemory.d.ts +2 -0
- package/dist/prompts/autoMemory.d.ts.map +1 -0
- package/dist/prompts/autoMemory.js +33 -0
- package/dist/prompts/index.d.ts +4 -0
- package/dist/prompts/index.d.ts.map +1 -1
- package/dist/prompts/index.js +7 -0
- package/dist/services/aiService.js +6 -7
- package/dist/services/configurationService.d.ts +28 -16
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +87 -28
- package/dist/services/hook.js +2 -2
- package/dist/services/initializationService.d.ts.map +1 -1
- package/dist/services/initializationService.js +20 -9
- package/dist/services/memory.d.ts +22 -4
- package/dist/services/memory.d.ts.map +1 -1
- package/dist/services/memory.js +132 -73
- package/dist/types/configuration.d.ts +2 -0
- package/dist/types/configuration.d.ts.map +1 -1
- package/dist/types/history.d.ts +2 -0
- package/dist/types/history.d.ts.map +1 -1
- package/dist/types/hooks.d.ts +2 -0
- package/dist/types/hooks.d.ts.map +1 -1
- package/dist/types/hooks.js +17 -7
- package/dist/utils/containerSetup.d.ts +0 -5
- package/dist/utils/containerSetup.d.ts.map +1 -1
- package/dist/utils/containerSetup.js +11 -24
- package/dist/utils/fileSearch.d.ts +1 -6
- package/dist/utils/fileSearch.d.ts.map +1 -1
- package/dist/utils/fileSearch.js +104 -75
- package/dist/utils/gitUtils.d.ts +6 -0
- package/dist/utils/gitUtils.d.ts.map +1 -1
- package/dist/utils/gitUtils.js +18 -0
- package/dist/utils/promptHistory.d.ts +3 -3
- package/dist/utils/promptHistory.d.ts.map +1 -1
- package/dist/utils/promptHistory.js +12 -6
- package/package.json +2 -1
- package/src/agent.ts +7 -18
- package/src/managers/aiManager.ts +73 -28
- package/src/managers/hookManager.ts +22 -1
- package/src/managers/messageManager.ts +12 -2
- package/src/managers/subagentManager.ts +7 -69
- package/src/prompts/autoMemory.ts +33 -0
- package/src/prompts/index.ts +12 -0
- package/src/services/aiService.ts +8 -8
- package/src/services/configurationService.ts +100 -28
- package/src/services/hook.ts +2 -2
- package/src/services/initializationService.ts +24 -12
- package/src/services/memory.ts +144 -82
- package/src/types/configuration.ts +2 -0
- package/src/types/history.ts +2 -0
- package/src/types/hooks.ts +25 -9
- package/src/utils/containerSetup.ts +11 -33
- package/src/utils/fileSearch.ts +112 -80
- package/src/utils/gitUtils.ts +18 -0
- package/src/utils/promptHistory.ts +20 -6
package/dist/utils/gitUtils.d.ts
CHANGED
|
@@ -10,6 +10,12 @@ export declare function isGitRepository(dirPath: string): string;
|
|
|
10
10
|
* @returns Repository root path
|
|
11
11
|
*/
|
|
12
12
|
export declare function getGitRepoRoot(cwd: string): string;
|
|
13
|
+
/**
|
|
14
|
+
* Get the common directory of the git repository (handles worktrees)
|
|
15
|
+
* @param cwd Working directory
|
|
16
|
+
* @returns Repository common directory path
|
|
17
|
+
*/
|
|
18
|
+
export declare function getGitCommonDir(cwd: string): string;
|
|
13
19
|
/**
|
|
14
20
|
* Get the default remote branch (e.g., origin/main)
|
|
15
21
|
* @param cwd Working directory
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA2D1D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAYvE"}
|
|
1
|
+
{"version":3,"file":"gitUtils.d.ts","sourceRoot":"","sources":["../../src/utils/gitUtils.ts"],"names":[],"mappings":"AAIA;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,CAevD;AAED;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAUlD;AAED;;;;GAIG;AACH,wBAAgB,eAAe,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAWnD;AAED;;;;GAIG;AACH,wBAAgB,sBAAsB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CA2D1D;AAED;;;;GAIG;AACH,wBAAgB,qBAAqB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAW1D;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,GAAG,OAAO,CAYvE"}
|
package/dist/utils/gitUtils.js
CHANGED
|
@@ -40,6 +40,24 @@ export function getGitRepoRoot(cwd) {
|
|
|
40
40
|
return cwd;
|
|
41
41
|
}
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Get the common directory of the git repository (handles worktrees)
|
|
45
|
+
* @param cwd Working directory
|
|
46
|
+
* @returns Repository common directory path
|
|
47
|
+
*/
|
|
48
|
+
export function getGitCommonDir(cwd) {
|
|
49
|
+
try {
|
|
50
|
+
const commonDir = execSync("git rev-parse --git-common-dir", {
|
|
51
|
+
cwd,
|
|
52
|
+
encoding: "utf8",
|
|
53
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
54
|
+
}).trim();
|
|
55
|
+
return path.resolve(cwd, commonDir);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
return getGitRepoRoot(cwd);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
43
61
|
/**
|
|
44
62
|
* Get the default remote branch (e.g., origin/main)
|
|
45
63
|
* @param cwd Working directory
|
|
@@ -3,7 +3,7 @@ export declare class PromptHistoryManager {
|
|
|
3
3
|
/**
|
|
4
4
|
* Add a new prompt to history
|
|
5
5
|
*/
|
|
6
|
-
static addEntry(prompt: string): Promise<void>;
|
|
6
|
+
static addEntry(prompt: string, sessionId?: string, longTextMap?: Record<string, string>): Promise<void>;
|
|
7
7
|
/**
|
|
8
8
|
* Trim history file to MAX_HISTORY_ENTRIES
|
|
9
9
|
*/
|
|
@@ -11,10 +11,10 @@ export declare class PromptHistoryManager {
|
|
|
11
11
|
/**
|
|
12
12
|
* Get all history entries
|
|
13
13
|
*/
|
|
14
|
-
static getHistory(): Promise<PromptEntry[]>;
|
|
14
|
+
static getHistory(sessionId?: string): Promise<PromptEntry[]>;
|
|
15
15
|
/**
|
|
16
16
|
* Search history by query
|
|
17
17
|
*/
|
|
18
|
-
static searchHistory(query: string): Promise<PromptEntry[]>;
|
|
18
|
+
static searchHistory(query: string, sessionId?: string): Promise<PromptEntry[]>;
|
|
19
19
|
}
|
|
20
20
|
//# sourceMappingURL=promptHistory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"promptHistory.d.ts","sourceRoot":"","sources":["../../src/utils/promptHistory.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiBlD,qBAAa,oBAAoB;IAC/B;;OAEG;WACU,QAAQ,CAAC,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"promptHistory.d.ts","sourceRoot":"","sources":["../../src/utils/promptHistory.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAiBlD,qBAAa,oBAAoB;IAC/B;;OAEG;WACU,QAAQ,CACnB,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,MAAM,EAClB,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GACnC,OAAO,CAAC,IAAI,CAAC;IAyBhB;;OAEG;mBACkB,WAAW;IAoBhC;;OAEG;WACU,UAAU,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,WAAW,EAAE,CAAC;IA6CnE;;OAEG;WACU,aAAa,CACxB,KAAK,EAAE,MAAM,EACb,SAAS,CAAC,EAAE,MAAM,GACjB,OAAO,CAAC,WAAW,EAAE,CAAC;CAgB1B"}
|
|
@@ -19,7 +19,7 @@ export class PromptHistoryManager {
|
|
|
19
19
|
/**
|
|
20
20
|
* Add a new prompt to history
|
|
21
21
|
*/
|
|
22
|
-
static async addEntry(prompt) {
|
|
22
|
+
static async addEntry(prompt, sessionId, longTextMap) {
|
|
23
23
|
try {
|
|
24
24
|
if (!prompt.trim())
|
|
25
25
|
return;
|
|
@@ -27,6 +27,8 @@ export class PromptHistoryManager {
|
|
|
27
27
|
const entry = {
|
|
28
28
|
prompt,
|
|
29
29
|
timestamp: Date.now(),
|
|
30
|
+
sessionId,
|
|
31
|
+
longTextMap,
|
|
30
32
|
};
|
|
31
33
|
const line = JSON.stringify(entry) + "\n";
|
|
32
34
|
await fs.promises.appendFile(PROMPT_HISTORY_FILE, line, "utf-8");
|
|
@@ -61,7 +63,7 @@ export class PromptHistoryManager {
|
|
|
61
63
|
/**
|
|
62
64
|
* Get all history entries
|
|
63
65
|
*/
|
|
64
|
-
static async getHistory() {
|
|
66
|
+
static async getHistory(sessionId) {
|
|
65
67
|
try {
|
|
66
68
|
if (!fs.existsSync(PROMPT_HISTORY_FILE)) {
|
|
67
69
|
return [];
|
|
@@ -79,12 +81,16 @@ export class PromptHistoryManager {
|
|
|
79
81
|
}
|
|
80
82
|
})
|
|
81
83
|
.filter((entry) => entry !== null);
|
|
84
|
+
// Filter by sessionId if provided
|
|
85
|
+
const filteredEntries = sessionId
|
|
86
|
+
? entries.filter((entry) => entry.sessionId === sessionId)
|
|
87
|
+
: entries;
|
|
82
88
|
// Deduplicate by prompt, keeping the most recent one
|
|
83
89
|
const uniqueEntries = [];
|
|
84
90
|
const seenPrompts = new Set();
|
|
85
91
|
// Process from newest to oldest
|
|
86
|
-
for (let i =
|
|
87
|
-
const entry =
|
|
92
|
+
for (let i = filteredEntries.length - 1; i >= 0; i--) {
|
|
93
|
+
const entry = filteredEntries[i];
|
|
88
94
|
if (!seenPrompts.has(entry.prompt)) {
|
|
89
95
|
uniqueEntries.push(entry);
|
|
90
96
|
seenPrompts.add(entry.prompt);
|
|
@@ -100,9 +106,9 @@ export class PromptHistoryManager {
|
|
|
100
106
|
/**
|
|
101
107
|
* Search history by query
|
|
102
108
|
*/
|
|
103
|
-
static async searchHistory(query) {
|
|
109
|
+
static async searchHistory(query, sessionId) {
|
|
104
110
|
try {
|
|
105
|
-
const history = await this.getHistory();
|
|
111
|
+
const history = await this.getHistory(sessionId);
|
|
106
112
|
if (!query.trim()) {
|
|
107
113
|
return history;
|
|
108
114
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wave-agent-sdk",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.1",
|
|
4
4
|
"description": "SDK for building AI-powered development tools and agents",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -27,6 +27,7 @@
|
|
|
27
27
|
"@modelcontextprotocol/sdk": "^1.18.2",
|
|
28
28
|
"@vscode/ripgrep": "^1.15.14",
|
|
29
29
|
"chokidar": "^5.0.0",
|
|
30
|
+
"fuzzysort": "^3.1.0",
|
|
30
31
|
"glob": "^13.0.0",
|
|
31
32
|
"minimatch": "^10.0.3",
|
|
32
33
|
"openai": "^5.12.2"
|
package/src/agent.ts
CHANGED
|
@@ -77,32 +77,24 @@ export class Agent {
|
|
|
77
77
|
|
|
78
78
|
// Dynamic configuration getter methods
|
|
79
79
|
public getGatewayConfig(): GatewayConfig {
|
|
80
|
-
return this.configurationService.resolveGatewayConfig(
|
|
81
|
-
this.options.apiKey,
|
|
82
|
-
this.options.baseURL,
|
|
83
|
-
this.options.defaultHeaders,
|
|
84
|
-
this.options.fetchOptions,
|
|
85
|
-
this.options.fetch,
|
|
86
|
-
);
|
|
80
|
+
return this.configurationService.resolveGatewayConfig();
|
|
87
81
|
}
|
|
88
82
|
|
|
89
83
|
public getModelConfig(): ModelConfig {
|
|
90
84
|
return this.configurationService.resolveModelConfig(
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
85
|
+
undefined,
|
|
86
|
+
undefined,
|
|
87
|
+
undefined,
|
|
94
88
|
this.getPermissionMode(),
|
|
95
89
|
);
|
|
96
90
|
}
|
|
97
91
|
|
|
98
92
|
public getMaxInputTokens(): number {
|
|
99
|
-
return this.configurationService.resolveMaxInputTokens(
|
|
100
|
-
this.options.maxInputTokens,
|
|
101
|
-
);
|
|
93
|
+
return this.configurationService.resolveMaxInputTokens();
|
|
102
94
|
}
|
|
103
95
|
|
|
104
96
|
public getLanguage(): string | undefined {
|
|
105
|
-
return this.configurationService.resolveLanguage(
|
|
97
|
+
return this.configurationService.resolveLanguage();
|
|
106
98
|
}
|
|
107
99
|
|
|
108
100
|
/**
|
|
@@ -122,6 +114,7 @@ export class Agent {
|
|
|
122
114
|
|
|
123
115
|
// Initialize configuration service
|
|
124
116
|
this.configurationService = new ConfigurationService();
|
|
117
|
+
this.configurationService.setOptions(options);
|
|
125
118
|
|
|
126
119
|
this.logger = logger; // Save the passed logger
|
|
127
120
|
this.systemPrompt = systemPrompt; // Save custom system prompt
|
|
@@ -153,10 +146,6 @@ export class Agent {
|
|
|
153
146
|
},
|
|
154
147
|
addPermissionRule: (rule) => this.addPermissionRule(rule),
|
|
155
148
|
addUsage: (usage) => this.messageManager.addUsage(usage),
|
|
156
|
-
getGatewayConfig: () => this.getGatewayConfig(),
|
|
157
|
-
getModelConfig: () => this.getModelConfig(),
|
|
158
|
-
getMaxInputTokens: () => this.getMaxInputTokens(),
|
|
159
|
-
getLanguage: () => this.getLanguage(),
|
|
160
149
|
});
|
|
161
150
|
|
|
162
151
|
// Retrieve managers from container
|
|
@@ -3,7 +3,12 @@ import * as aiService from "../services/aiService.js";
|
|
|
3
3
|
import { convertMessagesForAPI } from "../utils/convertMessagesForAPI.js";
|
|
4
4
|
import { calculateComprehensiveTotalTokens } from "../utils/tokenCalculation.js";
|
|
5
5
|
import * as fs from "node:fs/promises";
|
|
6
|
-
import type {
|
|
6
|
+
import type {
|
|
7
|
+
GatewayConfig,
|
|
8
|
+
ModelConfig,
|
|
9
|
+
Usage,
|
|
10
|
+
PermissionMode,
|
|
11
|
+
} from "../types/index.js";
|
|
7
12
|
import type { ToolManager } from "./toolManager.js";
|
|
8
13
|
import type { ToolContext, ToolResult } from "../tools/types.js";
|
|
9
14
|
import type { MessageManager } from "./messageManager.js";
|
|
@@ -16,6 +21,7 @@ import type { SubagentManager } from "./subagentManager.js";
|
|
|
16
21
|
import type { SkillManager } from "./skillManager.js";
|
|
17
22
|
import { buildSystemPrompt } from "../prompts/index.js";
|
|
18
23
|
import { Container } from "../utils/container.js";
|
|
24
|
+
import { ConfigurationService } from "../services/configurationService.js";
|
|
19
25
|
|
|
20
26
|
import { logger } from "../utils/globalLogger.js";
|
|
21
27
|
|
|
@@ -31,12 +37,8 @@ export interface AIManagerOptions {
|
|
|
31
37
|
subagentType?: string; // Optional subagent type for hook context
|
|
32
38
|
/**Whether to use streaming mode for AI responses - defaults to true */
|
|
33
39
|
stream?: boolean;
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
getModelConfig: () => ModelConfig;
|
|
37
|
-
getMaxInputTokens: () => number;
|
|
38
|
-
getLanguage: () => string | undefined;
|
|
39
|
-
getEnvironmentVars?: () => Record<string, string>; // Get configuration environment variables for hooks
|
|
40
|
+
/**Optional model override (e.g. for subagents) */
|
|
41
|
+
modelOverride?: string;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
44
|
export class AIManager {
|
|
@@ -47,13 +49,7 @@ export class AIManager {
|
|
|
47
49
|
private systemPrompt?: string;
|
|
48
50
|
private subagentType?: string; // Store subagent type for hook context
|
|
49
51
|
private stream: boolean; // Streaming mode flag
|
|
50
|
-
|
|
51
|
-
// Configuration properties (replaced with getter function storage)
|
|
52
|
-
private getGatewayConfigFn: () => GatewayConfig;
|
|
53
|
-
private getModelConfigFn: () => ModelConfig;
|
|
54
|
-
private getMaxInputTokensFn: () => number;
|
|
55
|
-
private getLanguageFn: () => string | undefined;
|
|
56
|
-
private getEnvironmentVarsFn?: () => Record<string, string>;
|
|
52
|
+
private modelOverride?: string;
|
|
57
53
|
|
|
58
54
|
// Service overrides
|
|
59
55
|
constructor(
|
|
@@ -65,13 +61,7 @@ export class AIManager {
|
|
|
65
61
|
this.subagentType = options.subagentType; // Store subagent type
|
|
66
62
|
this.stream = options.stream ?? true; // Default to true if not specified
|
|
67
63
|
this.callbacks = options.callbacks ?? {};
|
|
68
|
-
|
|
69
|
-
// Store configuration getter functions for dynamic resolution
|
|
70
|
-
this.getGatewayConfigFn = options.getGatewayConfig;
|
|
71
|
-
this.getModelConfigFn = options.getModelConfig;
|
|
72
|
-
this.getMaxInputTokensFn = options.getMaxInputTokens;
|
|
73
|
-
this.getLanguageFn = options.getLanguage;
|
|
74
|
-
this.getEnvironmentVarsFn = options.getEnvironmentVars;
|
|
64
|
+
this.modelOverride = options.modelOverride;
|
|
75
65
|
}
|
|
76
66
|
|
|
77
67
|
private get toolManager(): ToolManager {
|
|
@@ -82,6 +72,12 @@ export class AIManager {
|
|
|
82
72
|
return this.container.get<MessageManager>("MessageManager")!;
|
|
83
73
|
}
|
|
84
74
|
|
|
75
|
+
private get memoryService(): import("../services/memory.js").MemoryService {
|
|
76
|
+
return this.container.get<import("../services/memory.js").MemoryService>(
|
|
77
|
+
"MemoryService",
|
|
78
|
+
)!;
|
|
79
|
+
}
|
|
80
|
+
|
|
85
81
|
private get taskManager(): import("../services/taskManager.js").TaskManager {
|
|
86
82
|
return this.container.get<import("../services/taskManager.js").TaskManager>(
|
|
87
83
|
"TaskManager",
|
|
@@ -108,21 +104,54 @@ export class AIManager {
|
|
|
108
104
|
return this.container.get<PermissionManager>("PermissionManager");
|
|
109
105
|
}
|
|
110
106
|
|
|
107
|
+
private get configurationService(): ConfigurationService {
|
|
108
|
+
return this.container.get<ConfigurationService>("ConfigurationService")!;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
111
|
// Getter methods for accessing dynamic configuration
|
|
112
112
|
public getGatewayConfig(): GatewayConfig {
|
|
113
|
-
return this.
|
|
113
|
+
return this.configurationService.resolveGatewayConfig();
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
public getModelConfig(): ModelConfig {
|
|
117
|
-
|
|
117
|
+
const permissionMode = this.container.has("PermissionMode")
|
|
118
|
+
? this.container.get<PermissionMode>("PermissionMode")
|
|
119
|
+
: undefined;
|
|
120
|
+
|
|
121
|
+
const parentModelConfig = this.configurationService.resolveModelConfig(
|
|
122
|
+
undefined,
|
|
123
|
+
undefined,
|
|
124
|
+
undefined,
|
|
125
|
+
permissionMode,
|
|
126
|
+
);
|
|
127
|
+
let modelToUse: string | undefined;
|
|
128
|
+
|
|
129
|
+
if (this.modelOverride) {
|
|
130
|
+
if (this.modelOverride === "fastModel") {
|
|
131
|
+
modelToUse = parentModelConfig.fastModel;
|
|
132
|
+
} else if (this.modelOverride !== "inherit") {
|
|
133
|
+
modelToUse = this.modelOverride;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
return this.configurationService.resolveModelConfig(
|
|
138
|
+
modelToUse,
|
|
139
|
+
undefined,
|
|
140
|
+
undefined,
|
|
141
|
+
permissionMode,
|
|
142
|
+
);
|
|
118
143
|
}
|
|
119
144
|
|
|
120
145
|
public getMaxInputTokens(): number {
|
|
121
|
-
return this.
|
|
146
|
+
return this.configurationService.resolveMaxInputTokens();
|
|
122
147
|
}
|
|
123
148
|
|
|
124
149
|
public getLanguage(): string | undefined {
|
|
125
|
-
return this.
|
|
150
|
+
return this.configurationService.resolveLanguage();
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public getAutoMemoryEnabled(): boolean {
|
|
154
|
+
return this.configurationService.resolveAutoMemoryEnabled();
|
|
126
155
|
}
|
|
127
156
|
|
|
128
157
|
private isCompressing: boolean = false;
|
|
@@ -272,6 +301,9 @@ export class AIManager {
|
|
|
272
301
|
);
|
|
273
302
|
} catch (compressError) {
|
|
274
303
|
logger?.error("Failed to compress messages:", compressError);
|
|
304
|
+
this.messageManager.addErrorBlock(
|
|
305
|
+
`Failed to compress conversation history: ${compressError instanceof Error ? compressError.message : String(compressError)}. You may encounter context limit issues.`,
|
|
306
|
+
);
|
|
275
307
|
} finally {
|
|
276
308
|
this.setIsCompressing(false);
|
|
277
309
|
}
|
|
@@ -393,6 +425,18 @@ export class AIManager {
|
|
|
393
425
|
}
|
|
394
426
|
}
|
|
395
427
|
|
|
428
|
+
let autoMemoryOptions: { directory: string; content: string } | undefined;
|
|
429
|
+
|
|
430
|
+
if (this.getAutoMemoryEnabled()) {
|
|
431
|
+
const directory = this.memoryService.getAutoMemoryDirectory(
|
|
432
|
+
this.workdir,
|
|
433
|
+
);
|
|
434
|
+
const content = await this.memoryService.getAutoMemoryContent(
|
|
435
|
+
this.workdir,
|
|
436
|
+
);
|
|
437
|
+
autoMemoryOptions = { directory, content };
|
|
438
|
+
}
|
|
439
|
+
|
|
396
440
|
// Call AI service with streaming callbacks if enabled
|
|
397
441
|
const callAgentOptions: CallAgentOptions = {
|
|
398
442
|
gatewayConfig: this.getGatewayConfig(),
|
|
@@ -412,6 +456,7 @@ export class AIManager {
|
|
|
412
456
|
language: this.getLanguage(),
|
|
413
457
|
isSubagent: !!this.subagentType,
|
|
414
458
|
planMode: planModeOptions,
|
|
459
|
+
autoMemory: autoMemoryOptions,
|
|
415
460
|
},
|
|
416
461
|
), // Pass custom system prompt
|
|
417
462
|
maxTokens: maxTokens, // Pass max tokens override
|
|
@@ -844,7 +889,7 @@ export class AIManager {
|
|
|
844
889
|
cwd: this.workdir,
|
|
845
890
|
subagentType: this.subagentType, // Include subagent type in hook context
|
|
846
891
|
// Stop hooks don't need toolName, toolInput, toolResponse, or userPrompt
|
|
847
|
-
env: this.
|
|
892
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
848
893
|
};
|
|
849
894
|
|
|
850
895
|
const results = await this.hookManager.executeHooks(hookName, context);
|
|
@@ -915,7 +960,7 @@ export class AIManager {
|
|
|
915
960
|
cwd: this.workdir,
|
|
916
961
|
toolInput,
|
|
917
962
|
subagentType: this.subagentType, // Include subagent type in hook context
|
|
918
|
-
env: this.
|
|
963
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
919
964
|
};
|
|
920
965
|
|
|
921
966
|
const results = await this.hookManager.executeHooks(
|
|
@@ -981,7 +1026,7 @@ export class AIManager {
|
|
|
981
1026
|
toolInput,
|
|
982
1027
|
toolResponse,
|
|
983
1028
|
subagentType: this.subagentType, // Include subagent type in hook context
|
|
984
|
-
env: this.
|
|
1029
|
+
env: this.configurationService.getEnvironmentVars(), // Include configuration environment variables
|
|
985
1030
|
};
|
|
986
1031
|
|
|
987
1032
|
const results = await this.hookManager.executeHooks(
|
|
@@ -162,10 +162,31 @@ export class HookManager {
|
|
|
162
162
|
const hookCommand = config.hooks[commandIndex];
|
|
163
163
|
|
|
164
164
|
try {
|
|
165
|
+
const options = hookCommand.timeout
|
|
166
|
+
? { timeout: hookCommand.timeout * 1000 }
|
|
167
|
+
: undefined;
|
|
168
|
+
|
|
169
|
+
if (hookCommand.async) {
|
|
170
|
+
// Execute async command without awaiting
|
|
171
|
+
executeCommand(hookCommand.command, context, options).catch(
|
|
172
|
+
(error) => {
|
|
173
|
+
const errorMessage =
|
|
174
|
+
error instanceof Error
|
|
175
|
+
? error.message
|
|
176
|
+
: "Unknown execution error";
|
|
177
|
+
logger?.error(
|
|
178
|
+
`[HookManager] Async hook command ${commandIndex + 1} failed: ${errorMessage}`,
|
|
179
|
+
);
|
|
180
|
+
},
|
|
181
|
+
);
|
|
182
|
+
// Async hooks are not included in results to prevent blocking
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
|
|
165
186
|
const result = await executeCommand(
|
|
166
187
|
hookCommand.command,
|
|
167
188
|
context,
|
|
168
|
-
|
|
189
|
+
options,
|
|
169
190
|
);
|
|
170
191
|
results.push(result);
|
|
171
192
|
|
|
@@ -22,6 +22,7 @@ import {
|
|
|
22
22
|
} from "../services/session.js";
|
|
23
23
|
import { ChatCompletionMessageFunctionToolCall } from "openai/resources.js";
|
|
24
24
|
import type { MemoryRuleManager } from "./MemoryRuleManager.js";
|
|
25
|
+
import type { MemoryService } from "../services/memory.js";
|
|
25
26
|
import { pathEncoder } from "../utils/pathEncoder.js";
|
|
26
27
|
|
|
27
28
|
import { Container } from "../utils/container.js";
|
|
@@ -113,6 +114,14 @@ export class MessageManager {
|
|
|
113
114
|
: undefined;
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
private get memoryService(): MemoryService {
|
|
118
|
+
const service = this.container.get<MemoryService>("MemoryService");
|
|
119
|
+
if (!service) {
|
|
120
|
+
throw new Error("MemoryService not found in container");
|
|
121
|
+
}
|
|
122
|
+
return service;
|
|
123
|
+
}
|
|
124
|
+
|
|
116
125
|
// Getter methods
|
|
117
126
|
public getSessionId(): string {
|
|
118
127
|
return this.sessionId;
|
|
@@ -161,8 +170,9 @@ export class MessageManager {
|
|
|
161
170
|
* Get combined memory content (project memory + user memory + modular rules)
|
|
162
171
|
*/
|
|
163
172
|
public async getCombinedMemory(): Promise<string> {
|
|
164
|
-
|
|
165
|
-
|
|
173
|
+
let combined = await this.memoryService.getCombinedMemoryContent(
|
|
174
|
+
this.workdir,
|
|
175
|
+
);
|
|
166
176
|
|
|
167
177
|
if (this.memoryRuleManager) {
|
|
168
178
|
const filesInContext = this.getFilesInContext();
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import { randomUUID } from "crypto";
|
|
2
2
|
import type { SubagentConfiguration } from "../utils/subagentParser.js";
|
|
3
|
-
import type {
|
|
4
|
-
Message,
|
|
5
|
-
GatewayConfig,
|
|
6
|
-
ModelConfig,
|
|
7
|
-
Usage,
|
|
8
|
-
} from "../types/index.js";
|
|
3
|
+
import type { Message, Usage } from "../types/index.js";
|
|
9
4
|
import { AIManager } from "./aiManager.js";
|
|
10
5
|
import { MessageManager } from "./messageManager.js";
|
|
11
6
|
import { ToolManager } from "./toolManager.js";
|
|
@@ -23,6 +18,7 @@ import {
|
|
|
23
18
|
|
|
24
19
|
import { Container } from "../utils/container.js";
|
|
25
20
|
import type { PermissionManager } from "./permissionManager.js";
|
|
21
|
+
import { ConfigurationService } from "../services/configurationService.js";
|
|
26
22
|
|
|
27
23
|
export interface SubagentManagerCallbacks {
|
|
28
24
|
// Granular subagent message callbacks (015-subagent-message-callbacks)
|
|
@@ -79,11 +75,6 @@ export interface SubagentInstance {
|
|
|
79
75
|
export interface SubagentManagerOptions {
|
|
80
76
|
workdir: string;
|
|
81
77
|
callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
|
|
82
|
-
getGatewayConfig: () => GatewayConfig;
|
|
83
|
-
getModelConfig: () => ModelConfig;
|
|
84
|
-
getMaxInputTokens: () => number;
|
|
85
|
-
getLanguage: () => string | undefined;
|
|
86
|
-
getEnvironmentVars?: () => Record<string, string>;
|
|
87
78
|
onUsageAdded?: (usage: Usage) => void;
|
|
88
79
|
}
|
|
89
80
|
|
|
@@ -93,11 +84,6 @@ export class SubagentManager {
|
|
|
93
84
|
|
|
94
85
|
private workdir: string;
|
|
95
86
|
private callbacks?: SubagentManagerCallbacks; // Use SubagentManagerCallbacks instead of parentCallbacks
|
|
96
|
-
private getGatewayConfig: () => GatewayConfig;
|
|
97
|
-
private getModelConfig: () => ModelConfig;
|
|
98
|
-
private getMaxInputTokens: () => number;
|
|
99
|
-
private getLanguage: () => string | undefined;
|
|
100
|
-
private getEnvironmentVars?: () => Record<string, string>;
|
|
101
87
|
private onUsageAdded?: (usage: Usage) => void;
|
|
102
88
|
private container: Container;
|
|
103
89
|
|
|
@@ -105,14 +91,13 @@ export class SubagentManager {
|
|
|
105
91
|
this.container = container;
|
|
106
92
|
this.workdir = options.workdir;
|
|
107
93
|
this.callbacks = options.callbacks; // Store SubagentManagerCallbacks
|
|
108
|
-
this.getGatewayConfig = options.getGatewayConfig;
|
|
109
|
-
this.getModelConfig = options.getModelConfig;
|
|
110
|
-
this.getMaxInputTokens = options.getMaxInputTokens;
|
|
111
|
-
this.getLanguage = options.getLanguage;
|
|
112
|
-
this.getEnvironmentVars = options.getEnvironmentVars;
|
|
113
94
|
this.onUsageAdded = options.onUsageAdded;
|
|
114
95
|
}
|
|
115
96
|
|
|
97
|
+
private get configurationService(): ConfigurationService {
|
|
98
|
+
return this.container.get<ConfigurationService>("ConfigurationService")!;
|
|
99
|
+
}
|
|
100
|
+
|
|
116
101
|
/**
|
|
117
102
|
* Initialize the SubagentManager by loading and caching configurations
|
|
118
103
|
*/
|
|
@@ -232,34 +217,7 @@ export class SubagentManager {
|
|
|
232
217
|
workdir: this.workdir,
|
|
233
218
|
systemPrompt: configuration.systemPrompt,
|
|
234
219
|
subagentType: parameters.subagent_type, // Pass subagent type for hook context
|
|
235
|
-
|
|
236
|
-
getModelConfig: () => {
|
|
237
|
-
// Determine model dynamically each time
|
|
238
|
-
const parentModelConfig = this.getModelConfig();
|
|
239
|
-
let modelToUse: string;
|
|
240
|
-
|
|
241
|
-
if (parameters.model) {
|
|
242
|
-
// Use model override from parameters if provided
|
|
243
|
-
modelToUse = parameters.model;
|
|
244
|
-
} else if (!configuration.model || configuration.model === "inherit") {
|
|
245
|
-
// Use parent's model for "inherit" or undefined
|
|
246
|
-
modelToUse = parentModelConfig.model;
|
|
247
|
-
} else if (configuration.model === "fastModel") {
|
|
248
|
-
// Use parent's fastModel for special "fastModel" value
|
|
249
|
-
modelToUse = parentModelConfig.fastModel;
|
|
250
|
-
} else {
|
|
251
|
-
// Use specific model name
|
|
252
|
-
modelToUse = configuration.model;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
return {
|
|
256
|
-
...parentModelConfig,
|
|
257
|
-
model: modelToUse,
|
|
258
|
-
};
|
|
259
|
-
},
|
|
260
|
-
getMaxInputTokens: this.getMaxInputTokens,
|
|
261
|
-
getLanguage: this.getLanguage,
|
|
262
|
-
getEnvironmentVars: this.getEnvironmentVars,
|
|
220
|
+
modelOverride: parameters.model || configuration.model, // Pass model override
|
|
263
221
|
callbacks: {
|
|
264
222
|
onUsageAdded: this.onUsageAdded,
|
|
265
223
|
},
|
|
@@ -449,28 +407,8 @@ export class SubagentManager {
|
|
|
449
407
|
|
|
450
408
|
// Execute the AI request with tool restrictions
|
|
451
409
|
// The AIManager will handle abort signals through its own abort controllers
|
|
452
|
-
// Resolve model name for sendAIMessage
|
|
453
|
-
let resolvedModel: string | undefined;
|
|
454
|
-
if (instance.model) {
|
|
455
|
-
resolvedModel = instance.model;
|
|
456
|
-
} else if (
|
|
457
|
-
instance.configuration.model &&
|
|
458
|
-
instance.configuration.model !== "inherit"
|
|
459
|
-
) {
|
|
460
|
-
if (instance.configuration.model === "fastModel") {
|
|
461
|
-
// Use parent's fastModel for special "fastModel" value
|
|
462
|
-
const parentModelConfig = this.getModelConfig();
|
|
463
|
-
resolvedModel = parentModelConfig.fastModel;
|
|
464
|
-
} else {
|
|
465
|
-
// Use specific model name
|
|
466
|
-
resolvedModel = instance.configuration.model;
|
|
467
|
-
}
|
|
468
|
-
}
|
|
469
|
-
// For "inherit" or undefined, resolvedModel remains undefined (uses AIManager default)
|
|
470
|
-
|
|
471
410
|
const executeAI = instance.aiManager.sendAIMessage({
|
|
472
411
|
tools: enabledTools,
|
|
473
|
-
model: resolvedModel,
|
|
474
412
|
});
|
|
475
413
|
|
|
476
414
|
// If we have an abort signal, race against it using utilities to prevent listener accumulation
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export function buildAutoMemoryPrompt(memoryDir: string): string {
|
|
2
|
+
return `
|
|
3
|
+
# auto memory
|
|
4
|
+
|
|
5
|
+
You have a persistent auto memory directory at \`${memoryDir}\`. Its contents persist across conversations.
|
|
6
|
+
|
|
7
|
+
As you work, consult your memory files to build on previous experience.
|
|
8
|
+
|
|
9
|
+
## How to save memories:
|
|
10
|
+
- Organize memory semantically by topic, not chronologically
|
|
11
|
+
- Use the Write and Edit tools to update your memory files
|
|
12
|
+
- \`MEMORY.md\` is always loaded into your conversation context — lines after 200 will be truncated, so keep it concise
|
|
13
|
+
- Create separate topic files (e.g., \`debugging.md\`, \`patterns.md\`) for detailed notes and link to them from MEMORY.md
|
|
14
|
+
- Update or remove memories that turn out to be wrong or outdated
|
|
15
|
+
- Do not write duplicate memories. First check if there is an existing memory you can update before writing a new one.
|
|
16
|
+
|
|
17
|
+
## What to save:
|
|
18
|
+
- Stable patterns and conventions confirmed across multiple interactions
|
|
19
|
+
- Key architectural decisions, important file paths, and project structure
|
|
20
|
+
- User preferences for workflow, tools, and communication style
|
|
21
|
+
- Solutions to recurring problems and debugging insights
|
|
22
|
+
|
|
23
|
+
## What NOT to save:
|
|
24
|
+
- Session-specific context (current task details, in-progress work, temporary state)
|
|
25
|
+
- Information that might be incomplete — verify against project docs before writing
|
|
26
|
+
- Anything that duplicates or contradicts existing AGENTS.md instructions
|
|
27
|
+
- Speculative or unverified conclusions from reading a single file
|
|
28
|
+
|
|
29
|
+
## Explicit user requests:
|
|
30
|
+
- When the user asks you to remember something across sessions (e.g., "always use bun", "never auto-commit"), save it — no need to wait for multiple interactions
|
|
31
|
+
- When the user asks to forget or stop remembering something, find and remove the relevant entries from your memory files
|
|
32
|
+
`;
|
|
33
|
+
}
|
package/src/prompts/index.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import * as os from "node:os";
|
|
2
2
|
import { ToolPlugin } from "../tools/types.js";
|
|
3
3
|
import { isGitRepository } from "../utils/gitUtils.js";
|
|
4
|
+
import { buildAutoMemoryPrompt } from "./autoMemory.js";
|
|
4
5
|
import {
|
|
5
6
|
EXPLORE_SUBAGENT_TYPE,
|
|
6
7
|
PLAN_SUBAGENT_TYPE,
|
|
@@ -301,6 +302,10 @@ export function buildSystemPrompt(
|
|
|
301
302
|
planFilePath: string;
|
|
302
303
|
planExists: boolean;
|
|
303
304
|
};
|
|
305
|
+
autoMemory?: {
|
|
306
|
+
directory: string;
|
|
307
|
+
content: string;
|
|
308
|
+
};
|
|
304
309
|
} = {},
|
|
305
310
|
): string {
|
|
306
311
|
let prompt = basePrompt || DEFAULT_SYSTEM_PROMPT;
|
|
@@ -335,6 +340,13 @@ Today's date: ${today}
|
|
|
335
340
|
`;
|
|
336
341
|
}
|
|
337
342
|
|
|
343
|
+
if (options.autoMemory) {
|
|
344
|
+
prompt += `\n\n${buildAutoMemoryPrompt(options.autoMemory.directory)}`;
|
|
345
|
+
if (options.autoMemory.content.trim()) {
|
|
346
|
+
prompt += `\n\n## MEMORY.md\n\n${options.autoMemory.content}`;
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
338
350
|
if (options.memory && options.memory.trim()) {
|
|
339
351
|
prompt += `\n## Memory Context\n\nThe following is important context and memory from previous interactions:\n\n${options.memory}`;
|
|
340
352
|
}
|