wave-agent-sdk 0.0.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/README.md +32 -0
- package/dist/agent.d.ts +96 -0
- package/dist/agent.d.ts.map +1 -0
- package/dist/agent.js +286 -0
- package/dist/hooks/executor.d.ts +56 -0
- package/dist/hooks/executor.d.ts.map +1 -0
- package/dist/hooks/executor.js +312 -0
- package/dist/hooks/index.d.ts +17 -0
- package/dist/hooks/index.d.ts.map +1 -0
- package/dist/hooks/index.js +14 -0
- package/dist/hooks/manager.d.ts +90 -0
- package/dist/hooks/manager.d.ts.map +1 -0
- package/dist/hooks/manager.js +395 -0
- package/dist/hooks/matcher.d.ts +49 -0
- package/dist/hooks/matcher.d.ts.map +1 -0
- package/dist/hooks/matcher.js +147 -0
- package/dist/hooks/settings.d.ts +46 -0
- package/dist/hooks/settings.d.ts.map +1 -0
- package/dist/hooks/settings.js +100 -0
- package/dist/hooks/types.d.ts +80 -0
- package/dist/hooks/types.d.ts.map +1 -0
- package/dist/hooks/types.js +59 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +20 -0
- package/dist/managers/aiManager.d.ts +61 -0
- package/dist/managers/aiManager.d.ts.map +1 -0
- package/dist/managers/aiManager.js +415 -0
- package/dist/managers/backgroundBashManager.d.ts +27 -0
- package/dist/managers/backgroundBashManager.d.ts.map +1 -0
- package/dist/managers/backgroundBashManager.js +166 -0
- package/dist/managers/bashManager.d.ts +20 -0
- package/dist/managers/bashManager.d.ts.map +1 -0
- package/dist/managers/bashManager.js +66 -0
- package/dist/managers/mcpManager.d.ts +63 -0
- package/dist/managers/mcpManager.d.ts.map +1 -0
- package/dist/managers/mcpManager.js +378 -0
- package/dist/managers/messageManager.d.ts +85 -0
- package/dist/managers/messageManager.d.ts.map +1 -0
- package/dist/managers/messageManager.js +265 -0
- package/dist/managers/skillManager.d.ts +59 -0
- package/dist/managers/skillManager.d.ts.map +1 -0
- package/dist/managers/skillManager.js +317 -0
- package/dist/managers/slashCommandManager.d.ts +77 -0
- package/dist/managers/slashCommandManager.d.ts.map +1 -0
- package/dist/managers/slashCommandManager.js +208 -0
- package/dist/managers/toolManager.d.ts +23 -0
- package/dist/managers/toolManager.d.ts.map +1 -0
- package/dist/managers/toolManager.js +79 -0
- package/dist/services/aiService.d.ts +28 -0
- package/dist/services/aiService.d.ts.map +1 -0
- package/dist/services/aiService.js +180 -0
- package/dist/services/memory.d.ts +8 -0
- package/dist/services/memory.d.ts.map +1 -0
- package/dist/services/memory.js +128 -0
- package/dist/services/session.d.ts +54 -0
- package/dist/services/session.d.ts.map +1 -0
- package/dist/services/session.js +196 -0
- package/dist/tools/bashTool.d.ts +14 -0
- package/dist/tools/bashTool.d.ts.map +1 -0
- package/dist/tools/bashTool.js +351 -0
- package/dist/tools/deleteFileTool.d.ts +6 -0
- package/dist/tools/deleteFileTool.d.ts.map +1 -0
- package/dist/tools/deleteFileTool.js +67 -0
- package/dist/tools/editTool.d.ts +6 -0
- package/dist/tools/editTool.d.ts.map +1 -0
- package/dist/tools/editTool.js +168 -0
- package/dist/tools/globTool.d.ts +6 -0
- package/dist/tools/globTool.d.ts.map +1 -0
- package/dist/tools/globTool.js +113 -0
- package/dist/tools/grepTool.d.ts +6 -0
- package/dist/tools/grepTool.d.ts.map +1 -0
- package/dist/tools/grepTool.js +268 -0
- package/dist/tools/lsTool.d.ts +6 -0
- package/dist/tools/lsTool.d.ts.map +1 -0
- package/dist/tools/lsTool.js +160 -0
- package/dist/tools/multiEditTool.d.ts +6 -0
- package/dist/tools/multiEditTool.d.ts.map +1 -0
- package/dist/tools/multiEditTool.js +222 -0
- package/dist/tools/readTool.d.ts +6 -0
- package/dist/tools/readTool.d.ts.map +1 -0
- package/dist/tools/readTool.js +136 -0
- package/dist/tools/types.d.ts +35 -0
- package/dist/tools/types.d.ts.map +1 -0
- package/dist/tools/types.js +4 -0
- package/dist/tools/writeTool.d.ts +6 -0
- package/dist/tools/writeTool.d.ts.map +1 -0
- package/dist/tools/writeTool.js +138 -0
- package/dist/types.d.ts +212 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +13 -0
- package/dist/utils/bashHistory.d.ts +46 -0
- package/dist/utils/bashHistory.d.ts.map +1 -0
- package/dist/utils/bashHistory.js +236 -0
- package/dist/utils/commandArgumentParser.d.ts +34 -0
- package/dist/utils/commandArgumentParser.d.ts.map +1 -0
- package/dist/utils/commandArgumentParser.js +123 -0
- package/dist/utils/constants.d.ts +27 -0
- package/dist/utils/constants.d.ts.map +1 -0
- package/dist/utils/constants.js +28 -0
- package/dist/utils/convertMessagesForAPI.d.ts +9 -0
- package/dist/utils/convertMessagesForAPI.d.ts.map +1 -0
- package/dist/utils/convertMessagesForAPI.js +189 -0
- package/dist/utils/customCommands.d.ts +14 -0
- package/dist/utils/customCommands.d.ts.map +1 -0
- package/dist/utils/customCommands.js +71 -0
- package/dist/utils/fileFilter.d.ts +26 -0
- package/dist/utils/fileFilter.d.ts.map +1 -0
- package/dist/utils/fileFilter.js +177 -0
- package/dist/utils/markdownParser.d.ts +27 -0
- package/dist/utils/markdownParser.d.ts.map +1 -0
- package/dist/utils/markdownParser.js +109 -0
- package/dist/utils/mcpUtils.d.ts +24 -0
- package/dist/utils/mcpUtils.d.ts.map +1 -0
- package/dist/utils/mcpUtils.js +51 -0
- package/dist/utils/messageOperations.d.ts +118 -0
- package/dist/utils/messageOperations.d.ts.map +1 -0
- package/dist/utils/messageOperations.js +334 -0
- package/dist/utils/path.d.ts +25 -0
- package/dist/utils/path.d.ts.map +1 -0
- package/dist/utils/path.js +109 -0
- package/dist/utils/skillParser.d.ts +18 -0
- package/dist/utils/skillParser.d.ts.map +1 -0
- package/dist/utils/skillParser.js +147 -0
- package/dist/utils/stringUtils.d.ts +13 -0
- package/dist/utils/stringUtils.d.ts.map +1 -0
- package/dist/utils/stringUtils.js +44 -0
- package/package.json +51 -0
- package/src/agent.ts +405 -0
- package/src/hooks/executor.ts +440 -0
- package/src/hooks/index.ts +52 -0
- package/src/hooks/manager.ts +618 -0
- package/src/hooks/matcher.ts +187 -0
- package/src/hooks/settings.ts +129 -0
- package/src/hooks/types.ts +169 -0
- package/src/index.ts +24 -0
- package/src/managers/aiManager.ts +573 -0
- package/src/managers/backgroundBashManager.ts +203 -0
- package/src/managers/bashManager.ts +97 -0
- package/src/managers/mcpManager.ts +493 -0
- package/src/managers/messageManager.ts +415 -0
- package/src/managers/skillManager.ts +404 -0
- package/src/managers/slashCommandManager.ts +293 -0
- package/src/managers/toolManager.ts +106 -0
- package/src/services/aiService.ts +252 -0
- package/src/services/memory.ts +149 -0
- package/src/services/session.ts +265 -0
- package/src/tools/bashTool.ts +402 -0
- package/src/tools/deleteFileTool.ts +81 -0
- package/src/tools/editTool.ts +192 -0
- package/src/tools/globTool.ts +135 -0
- package/src/tools/grepTool.ts +326 -0
- package/src/tools/lsTool.ts +187 -0
- package/src/tools/multiEditTool.ts +268 -0
- package/src/tools/readTool.ts +165 -0
- package/src/tools/types.ts +47 -0
- package/src/tools/writeTool.ts +163 -0
- package/src/types.ts +260 -0
- package/src/utils/bashHistory.ts +303 -0
- package/src/utils/commandArgumentParser.ts +153 -0
- package/src/utils/constants.ts +37 -0
- package/src/utils/convertMessagesForAPI.ts +236 -0
- package/src/utils/customCommands.ts +85 -0
- package/src/utils/fileFilter.ts +202 -0
- package/src/utils/markdownParser.ts +156 -0
- package/src/utils/mcpUtils.ts +81 -0
- package/src/utils/messageOperations.ts +506 -0
- package/src/utils/path.ts +118 -0
- package/src/utils/skillParser.ts +188 -0
- package/src/utils/stringUtils.ts +50 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { ToolContext, ToolPlugin, ToolResult } from "../tools/types.js";
|
|
2
|
+
import { bashTool, bashOutputTool, killBashTool } from "../tools/bashTool.js";
|
|
3
|
+
import { deleteFileTool } from "../tools/deleteFileTool.js";
|
|
4
|
+
import { editTool } from "../tools/editTool.js";
|
|
5
|
+
import { multiEditTool } from "../tools/multiEditTool.js";
|
|
6
|
+
import { writeTool } from "../tools/writeTool.js";
|
|
7
|
+
// New tools
|
|
8
|
+
import { globTool } from "../tools/globTool.js";
|
|
9
|
+
import { grepTool } from "../tools/grepTool.js";
|
|
10
|
+
import { lsTool } from "../tools/lsTool.js";
|
|
11
|
+
import { readTool } from "../tools/readTool.js";
|
|
12
|
+
import { SkillManager } from "./skillManager.js";
|
|
13
|
+
import { McpManager } from "./mcpManager.js";
|
|
14
|
+
import { ChatCompletionFunctionTool } from "openai/resources.js";
|
|
15
|
+
import type { Logger } from "../types.js";
|
|
16
|
+
|
|
17
|
+
export interface ToolManagerOptions {
|
|
18
|
+
mcpManager: McpManager;
|
|
19
|
+
logger?: Logger;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Tool Manager
|
|
24
|
+
*/
|
|
25
|
+
class ToolManager {
|
|
26
|
+
private tools = new Map<string, ToolPlugin>();
|
|
27
|
+
private mcpManager: McpManager;
|
|
28
|
+
private logger?: Logger;
|
|
29
|
+
|
|
30
|
+
constructor(options: ToolManagerOptions) {
|
|
31
|
+
this.mcpManager = options.mcpManager;
|
|
32
|
+
this.logger = options.logger;
|
|
33
|
+
|
|
34
|
+
// Initialize built-in tools
|
|
35
|
+
this.initializeBuiltInTools();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
private initializeBuiltInTools(): void {
|
|
39
|
+
const builtInTools = [
|
|
40
|
+
bashTool,
|
|
41
|
+
bashOutputTool,
|
|
42
|
+
killBashTool,
|
|
43
|
+
deleteFileTool,
|
|
44
|
+
editTool,
|
|
45
|
+
multiEditTool,
|
|
46
|
+
writeTool,
|
|
47
|
+
globTool,
|
|
48
|
+
grepTool,
|
|
49
|
+
lsTool,
|
|
50
|
+
readTool,
|
|
51
|
+
new SkillManager({ logger: this.logger }).createTool(),
|
|
52
|
+
];
|
|
53
|
+
|
|
54
|
+
for (const tool of builtInTools) {
|
|
55
|
+
this.tools.set(tool.name, tool);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
async execute(
|
|
60
|
+
name: string,
|
|
61
|
+
args: Record<string, unknown>,
|
|
62
|
+
context: ToolContext,
|
|
63
|
+
): Promise<ToolResult> {
|
|
64
|
+
// Check if it's an MCP tool first
|
|
65
|
+
if (this.mcpManager.isMcpTool(name)) {
|
|
66
|
+
return this.mcpManager.executeMcpToolByRegistry(name, args, context);
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// Check built-in tools
|
|
70
|
+
const plugin = this.tools.get(name);
|
|
71
|
+
if (plugin) {
|
|
72
|
+
try {
|
|
73
|
+
return await plugin.execute(args, context);
|
|
74
|
+
} catch (error) {
|
|
75
|
+
return {
|
|
76
|
+
success: false,
|
|
77
|
+
content: "",
|
|
78
|
+
error: error instanceof Error ? error.message : String(error),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
success: false,
|
|
85
|
+
content: "",
|
|
86
|
+
error: `Tool '${name}' not found`,
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
list(): ToolPlugin[] {
|
|
91
|
+
const builtInTools = Array.from(this.tools.values());
|
|
92
|
+
const mcpTools = this.mcpManager.getMcpToolPlugins();
|
|
93
|
+
return [...builtInTools, ...mcpTools];
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
getToolsConfig(): ChatCompletionFunctionTool[] {
|
|
97
|
+
const builtInToolsConfig = Array.from(this.tools.values()).map(
|
|
98
|
+
(tool) => tool.config,
|
|
99
|
+
);
|
|
100
|
+
const mcpToolsConfig = this.mcpManager.getMcpToolsConfig();
|
|
101
|
+
return [...builtInToolsConfig, ...mcpToolsConfig];
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Export tool registry class and types
|
|
106
|
+
export { ToolManager };
|
|
@@ -0,0 +1,252 @@
|
|
|
1
|
+
import OpenAI from "openai";
|
|
2
|
+
import { ChatCompletionMessageToolCall } from "openai/resources";
|
|
3
|
+
import {
|
|
4
|
+
ChatCompletionCreateParamsNonStreaming,
|
|
5
|
+
ChatCompletionMessageParam,
|
|
6
|
+
ChatCompletionFunctionTool,
|
|
7
|
+
} from "openai/resources.js";
|
|
8
|
+
import { FAST_MODEL_ID, AGENT_MODEL_ID } from "@/utils/constants.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Model configuration type, based on OpenAI parameters but excluding messages
|
|
12
|
+
*/
|
|
13
|
+
type ModelConfig = Omit<ChatCompletionCreateParamsNonStreaming, "messages">;
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Get specific configuration parameters based on model name
|
|
17
|
+
* @param modelName Model name
|
|
18
|
+
* @param baseConfig Base configuration
|
|
19
|
+
* @returns Configured model parameters
|
|
20
|
+
*/
|
|
21
|
+
function getModelConfig(
|
|
22
|
+
modelName: string,
|
|
23
|
+
baseConfig: Partial<ModelConfig> = {},
|
|
24
|
+
): ModelConfig {
|
|
25
|
+
const config: ModelConfig = {
|
|
26
|
+
model: modelName,
|
|
27
|
+
stream: false,
|
|
28
|
+
...baseConfig,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Configuration rules for specific models
|
|
32
|
+
if (modelName.includes("gpt-5-codex")) {
|
|
33
|
+
// gpt-5-codex model sets temperature to undefined
|
|
34
|
+
config.temperature = undefined;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return config;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
// Initialize OpenAI client with environment variables
|
|
41
|
+
const openai = new OpenAI({
|
|
42
|
+
apiKey: process.env.AIGW_TOKEN,
|
|
43
|
+
baseURL: process.env.AIGW_URL,
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
export interface CallAgentOptions {
|
|
47
|
+
messages: ChatCompletionMessageParam[];
|
|
48
|
+
sessionId?: string;
|
|
49
|
+
abortSignal?: AbortSignal;
|
|
50
|
+
memory?: string; // Memory content parameter, content read from WAVE.md
|
|
51
|
+
workdir: string; // Current working directory
|
|
52
|
+
tools?: ChatCompletionFunctionTool[]; // Tool configuration
|
|
53
|
+
model?: string; // Custom model
|
|
54
|
+
systemPrompt?: string; // Custom system prompt
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export interface CallAgentResult {
|
|
58
|
+
content?: string;
|
|
59
|
+
tool_calls?: ChatCompletionMessageToolCall[];
|
|
60
|
+
usage?: {
|
|
61
|
+
prompt_tokens: number;
|
|
62
|
+
completion_tokens: number;
|
|
63
|
+
total_tokens: number;
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export async function callAgent(
|
|
68
|
+
options: CallAgentOptions,
|
|
69
|
+
): Promise<CallAgentResult> {
|
|
70
|
+
const { messages, abortSignal, memory, workdir, tools, model, systemPrompt } =
|
|
71
|
+
options;
|
|
72
|
+
|
|
73
|
+
try {
|
|
74
|
+
// Build system prompt content
|
|
75
|
+
let systemContent: string;
|
|
76
|
+
|
|
77
|
+
if (systemPrompt) {
|
|
78
|
+
// Use custom system prompt if provided
|
|
79
|
+
systemContent = systemPrompt;
|
|
80
|
+
} else {
|
|
81
|
+
// Use default system prompt
|
|
82
|
+
systemContent = `You are an interactive CLI tool that helps users with software engineering tasks. Use the instructions below and the tools available to you to assist the user.
|
|
83
|
+
|
|
84
|
+
## Current Working Directory
|
|
85
|
+
${workdir}
|
|
86
|
+
`;
|
|
87
|
+
|
|
88
|
+
// If there is memory content, add it to the system prompt
|
|
89
|
+
if (memory && memory.trim()) {
|
|
90
|
+
systemContent += `\n\n## Memory Context\n\nThe following is important context and memory from previous interactions:\n\n${memory}`;
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// Add system prompt
|
|
95
|
+
const systemMessage: OpenAI.Chat.Completions.ChatCompletionMessageParam = {
|
|
96
|
+
role: "system",
|
|
97
|
+
content: systemContent,
|
|
98
|
+
};
|
|
99
|
+
|
|
100
|
+
// ChatCompletionMessageParam[] is already in OpenAI format, add system prompt to the beginning
|
|
101
|
+
const openaiMessages: OpenAI.Chat.Completions.ChatCompletionMessageParam[] =
|
|
102
|
+
[systemMessage, ...messages];
|
|
103
|
+
|
|
104
|
+
// Get model configuration
|
|
105
|
+
const modelConfig = getModelConfig(model || AGENT_MODEL_ID, {
|
|
106
|
+
temperature: 0,
|
|
107
|
+
max_completion_tokens: 32768,
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Prepare API call parameters
|
|
111
|
+
const createParams: ChatCompletionCreateParamsNonStreaming = {
|
|
112
|
+
...modelConfig,
|
|
113
|
+
messages: openaiMessages,
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
// Only add tools if they exist
|
|
117
|
+
if (tools && tools.length > 0) {
|
|
118
|
+
createParams.tools = tools;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// Call OpenAI API (non-streaming)
|
|
122
|
+
const response = await openai.chat.completions.create(createParams, {
|
|
123
|
+
signal: abortSignal,
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
const finalMessage = response.choices[0]?.message;
|
|
127
|
+
const totalUsage = response.usage
|
|
128
|
+
? {
|
|
129
|
+
prompt_tokens: response.usage.prompt_tokens,
|
|
130
|
+
completion_tokens: response.usage.completion_tokens,
|
|
131
|
+
total_tokens: response.usage.total_tokens,
|
|
132
|
+
}
|
|
133
|
+
: undefined;
|
|
134
|
+
|
|
135
|
+
const result: CallAgentResult = {};
|
|
136
|
+
|
|
137
|
+
// Return content
|
|
138
|
+
if (finalMessage?.content) {
|
|
139
|
+
result.content = finalMessage.content;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Return tool call
|
|
143
|
+
if (finalMessage?.tool_calls && finalMessage.tool_calls.length > 0) {
|
|
144
|
+
result.tool_calls = finalMessage.tool_calls;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
// Return token usage information
|
|
148
|
+
if (totalUsage) {
|
|
149
|
+
result.usage = totalUsage;
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
return result;
|
|
153
|
+
} catch (error) {
|
|
154
|
+
if ((error as Error).name === "AbortError") {
|
|
155
|
+
throw new Error("Request was aborted");
|
|
156
|
+
}
|
|
157
|
+
// // logger.error("Failed to call OpenAI:", error);
|
|
158
|
+
throw error;
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface CompressMessagesOptions {
|
|
163
|
+
messages: ChatCompletionMessageParam[];
|
|
164
|
+
abortSignal?: AbortSignal;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export async function compressMessages(
|
|
168
|
+
options: CompressMessagesOptions,
|
|
169
|
+
): Promise<string> {
|
|
170
|
+
const { messages, abortSignal } = options;
|
|
171
|
+
|
|
172
|
+
// Get model configuration
|
|
173
|
+
const modelConfig = getModelConfig(FAST_MODEL_ID, {
|
|
174
|
+
temperature: 0.1,
|
|
175
|
+
max_tokens: 1500,
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
try {
|
|
179
|
+
const response = await openai.chat.completions.create(
|
|
180
|
+
{
|
|
181
|
+
...modelConfig,
|
|
182
|
+
messages: [
|
|
183
|
+
{
|
|
184
|
+
role: "system",
|
|
185
|
+
content: `You are an expert conversation history compression specialist. Your task is to create comprehensive yet concise summaries that preserve critical development context.
|
|
186
|
+
|
|
187
|
+
## Primary Request and Intent
|
|
188
|
+
Compress conversation history while maintaining all essential technical and procedural information.
|
|
189
|
+
|
|
190
|
+
## Key Technical Concepts
|
|
191
|
+
- Code modifications and file operations
|
|
192
|
+
- Tool executions and their results
|
|
193
|
+
- Error handling and debugging processes
|
|
194
|
+
- User requirements and assistant solutions
|
|
195
|
+
- Technical discussions and decisions
|
|
196
|
+
|
|
197
|
+
## Compression Strategy
|
|
198
|
+
1. **Preserve Critical Information**:
|
|
199
|
+
- All file paths, function names, and code examples
|
|
200
|
+
- Tool execution results and outcomes
|
|
201
|
+
- Error messages and resolution steps
|
|
202
|
+
- User requirements and implementation approaches
|
|
203
|
+
- Technical decisions and their reasoning
|
|
204
|
+
|
|
205
|
+
2. **Structure Organization**:
|
|
206
|
+
- Group related actions and discussions
|
|
207
|
+
- Maintain chronological flow for complex operations
|
|
208
|
+
- Separate different technical topics clearly
|
|
209
|
+
|
|
210
|
+
3. **Context Preservation**:
|
|
211
|
+
- Keep enough detail for future reference
|
|
212
|
+
- Maintain relationships between requests and solutions
|
|
213
|
+
- Preserve debugging context and error resolution paths
|
|
214
|
+
|
|
215
|
+
## Output Requirements:
|
|
216
|
+
- Use third-person narrative format
|
|
217
|
+
- Target 300-800 words (scale based on complexity)
|
|
218
|
+
- Maintain the original conversation language
|
|
219
|
+
- Structure with clear sections for multi-topic conversations
|
|
220
|
+
- Focus on actionable information and outcomes
|
|
221
|
+
|
|
222
|
+
## Format Template:
|
|
223
|
+
For technical conversations, structure as:
|
|
224
|
+
- **User Requests**: Key requirements and goals
|
|
225
|
+
- **Technical Implementation**: Code changes, file operations, tool usage
|
|
226
|
+
- **Problem Resolution**: Errors encountered and solutions applied
|
|
227
|
+
- **Outcomes**: Final results and current state`,
|
|
228
|
+
},
|
|
229
|
+
...messages,
|
|
230
|
+
{
|
|
231
|
+
role: "user",
|
|
232
|
+
content: `Please compress this conversation following the structured approach. Focus on preserving all technical details, file operations, and problem-solving context while creating a concise summary.`,
|
|
233
|
+
},
|
|
234
|
+
],
|
|
235
|
+
},
|
|
236
|
+
{
|
|
237
|
+
signal: abortSignal,
|
|
238
|
+
},
|
|
239
|
+
);
|
|
240
|
+
|
|
241
|
+
return (
|
|
242
|
+
response.choices[0]?.message?.content?.trim() ||
|
|
243
|
+
"Failed to compress conversation history"
|
|
244
|
+
);
|
|
245
|
+
} catch (error) {
|
|
246
|
+
if ((error as Error).name === "AbortError") {
|
|
247
|
+
throw new Error("Compression request was aborted");
|
|
248
|
+
}
|
|
249
|
+
// // logger.error("Failed to compress messages:", error);
|
|
250
|
+
return "Failed to compress conversation history";
|
|
251
|
+
}
|
|
252
|
+
}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { promises as fs } from "fs";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import { USER_MEMORY_FILE, DATA_DIRECTORY } from "../utils/constants.js";
|
|
4
|
+
|
|
5
|
+
// Project memory related methods
|
|
6
|
+
export const isMemoryMessage = (message: string): boolean => {
|
|
7
|
+
return message.trim().startsWith("#");
|
|
8
|
+
};
|
|
9
|
+
|
|
10
|
+
export const addMemory = async (
|
|
11
|
+
message: string,
|
|
12
|
+
workdir: string,
|
|
13
|
+
): Promise<void> => {
|
|
14
|
+
if (!isMemoryMessage(message)) {
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
try {
|
|
19
|
+
const memoryFilePath = path.join(workdir, "WAVE.md");
|
|
20
|
+
|
|
21
|
+
// Format memory entry, starting with -, no timestamp
|
|
22
|
+
const memoryEntry = `- ${message.substring(1).trim()}\n`;
|
|
23
|
+
|
|
24
|
+
// Check if file exists
|
|
25
|
+
let existingContent = "";
|
|
26
|
+
try {
|
|
27
|
+
existingContent = await fs.readFile(memoryFilePath, "utf-8");
|
|
28
|
+
} catch (error) {
|
|
29
|
+
// File does not exist, create new file
|
|
30
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
31
|
+
existingContent =
|
|
32
|
+
"# Memory\n\nThis is the AI assistant's memory file, recording important information and context.\n\n";
|
|
33
|
+
} else {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Append new memory entry to the end of the file
|
|
39
|
+
const updatedContent = existingContent + memoryEntry;
|
|
40
|
+
|
|
41
|
+
// Write file
|
|
42
|
+
await fs.writeFile(memoryFilePath, updatedContent, "utf-8");
|
|
43
|
+
|
|
44
|
+
// logger.info(`Memory added to ${memoryFilePath}:`, message);
|
|
45
|
+
} catch (error) {
|
|
46
|
+
// logger.error("Failed to add memory:", error);
|
|
47
|
+
throw new Error(`Failed to add memory: ${(error as Error).message}`);
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
|
|
51
|
+
// User memory related methods
|
|
52
|
+
export const ensureUserMemoryFile = async (): Promise<void> => {
|
|
53
|
+
try {
|
|
54
|
+
// Ensure data directory exists
|
|
55
|
+
await fs.mkdir(DATA_DIRECTORY, { recursive: true });
|
|
56
|
+
|
|
57
|
+
// Check if user memory file exists
|
|
58
|
+
try {
|
|
59
|
+
await fs.access(USER_MEMORY_FILE);
|
|
60
|
+
} catch (error) {
|
|
61
|
+
// File does not exist, create new file
|
|
62
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
63
|
+
const initialContent =
|
|
64
|
+
"# User Memory\n\nThis is the user-level memory file, recording important information and context across projects.\n\n";
|
|
65
|
+
await fs.writeFile(USER_MEMORY_FILE, initialContent, "utf-8");
|
|
66
|
+
// logger.info(`Created user memory file: ${USER_MEMORY_FILE}`);
|
|
67
|
+
} else {
|
|
68
|
+
throw error;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
} catch (error) {
|
|
72
|
+
// logger.error("Failed to ensure user memory file:", error);
|
|
73
|
+
throw new Error(
|
|
74
|
+
`Failed to ensure user memory file: ${(error as Error).message}`,
|
|
75
|
+
);
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
export const addUserMemory = async (message: string): Promise<void> => {
|
|
80
|
+
try {
|
|
81
|
+
// Ensure user memory file exists
|
|
82
|
+
await ensureUserMemoryFile();
|
|
83
|
+
|
|
84
|
+
// Format memory entry, starting with -
|
|
85
|
+
const memoryEntry = `- ${message.substring(1).trim()}\n`;
|
|
86
|
+
|
|
87
|
+
// Read existing content
|
|
88
|
+
const existingContent = await fs.readFile(USER_MEMORY_FILE, "utf-8");
|
|
89
|
+
|
|
90
|
+
// Append new memory entry to the end of the file
|
|
91
|
+
const updatedContent = existingContent + memoryEntry;
|
|
92
|
+
|
|
93
|
+
// Write file
|
|
94
|
+
await fs.writeFile(USER_MEMORY_FILE, updatedContent, "utf-8");
|
|
95
|
+
|
|
96
|
+
// logger.info(`User memory added to ${USER_MEMORY_FILE}:`, message);
|
|
97
|
+
} catch (error) {
|
|
98
|
+
// logger.error("Failed to add user memory:", error);
|
|
99
|
+
throw new Error(`Failed to add user memory: ${(error as Error).message}`);
|
|
100
|
+
}
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
export const getUserMemoryContent = async (): Promise<string> => {
|
|
104
|
+
try {
|
|
105
|
+
await ensureUserMemoryFile();
|
|
106
|
+
return await fs.readFile(USER_MEMORY_FILE, "utf-8");
|
|
107
|
+
} catch {
|
|
108
|
+
// logger.error("Failed to read user memory:", error);
|
|
109
|
+
return "";
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
// Read project memory file content
|
|
114
|
+
export const readMemoryFile = async (workdir: string): Promise<string> => {
|
|
115
|
+
try {
|
|
116
|
+
const memoryFilePath = path.join(workdir, "WAVE.md");
|
|
117
|
+
return await fs.readFile(memoryFilePath, "utf-8");
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if ((error as NodeJS.ErrnoException).code === "ENOENT") {
|
|
120
|
+
return "";
|
|
121
|
+
}
|
|
122
|
+
throw error;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
// Get merged memory content (project memory + user memory)
|
|
127
|
+
export const getCombinedMemoryContent = async (
|
|
128
|
+
workdir: string,
|
|
129
|
+
): Promise<string> => {
|
|
130
|
+
// Read memory file content
|
|
131
|
+
const memoryContent = await readMemoryFile(workdir);
|
|
132
|
+
|
|
133
|
+
// Read user-level memory content
|
|
134
|
+
const userMemoryContent = await getUserMemoryContent();
|
|
135
|
+
|
|
136
|
+
// Merge project memory and user memory
|
|
137
|
+
let combinedMemory = "";
|
|
138
|
+
if (memoryContent.trim()) {
|
|
139
|
+
combinedMemory += memoryContent;
|
|
140
|
+
}
|
|
141
|
+
if (userMemoryContent.trim()) {
|
|
142
|
+
if (combinedMemory) {
|
|
143
|
+
combinedMemory += "\n\n";
|
|
144
|
+
}
|
|
145
|
+
combinedMemory += userMemoryContent;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
return combinedMemory;
|
|
149
|
+
};
|