wave-agent-sdk 0.2.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent.d.ts +66 -20
- package/dist/agent.d.ts.map +1 -1
- package/dist/agent.js +156 -83
- package/dist/constants/prompts.d.ts +7 -2
- package/dist/constants/prompts.d.ts.map +1 -1
- package/dist/constants/prompts.js +41 -5
- package/dist/constants/tools.d.ts +2 -2
- package/dist/constants/tools.js +2 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/managers/MemoryRuleManager.d.ts.map +1 -1
- package/dist/managers/MemoryRuleManager.js +16 -2
- package/dist/managers/aiManager.d.ts +14 -4
- package/dist/managers/aiManager.d.ts.map +1 -1
- package/dist/managers/aiManager.js +61 -9
- package/dist/managers/backgroundBashManager.d.ts.map +1 -1
- package/dist/managers/backgroundBashManager.js +1 -0
- package/dist/managers/backgroundTaskManager.d.ts +35 -0
- package/dist/managers/backgroundTaskManager.d.ts.map +1 -0
- package/dist/managers/backgroundTaskManager.js +249 -0
- package/dist/managers/bashManager.d.ts.map +1 -1
- package/dist/managers/bashManager.js +0 -3
- package/dist/managers/foregroundTaskManager.d.ts +9 -0
- package/dist/managers/foregroundTaskManager.d.ts.map +1 -0
- package/dist/managers/foregroundTaskManager.js +20 -0
- package/dist/managers/liveConfigManager.d.ts +1 -1
- package/dist/managers/liveConfigManager.d.ts.map +1 -1
- package/dist/managers/lspManager.d.ts.map +1 -1
- package/dist/managers/lspManager.js +3 -1
- package/dist/managers/messageManager.d.ts +34 -4
- package/dist/managers/messageManager.d.ts.map +1 -1
- package/dist/managers/messageManager.js +104 -13
- package/dist/managers/permissionManager.d.ts.map +1 -1
- package/dist/managers/permissionManager.js +11 -13
- package/dist/managers/pluginManager.d.ts.map +1 -1
- package/dist/managers/pluginManager.js +3 -2
- package/dist/managers/pluginScopeManager.d.ts +13 -2
- package/dist/managers/pluginScopeManager.d.ts.map +1 -1
- package/dist/managers/pluginScopeManager.js +38 -0
- package/dist/managers/reversionManager.d.ts +39 -0
- package/dist/managers/reversionManager.d.ts.map +1 -0
- package/dist/managers/reversionManager.js +118 -0
- package/dist/managers/slashCommandManager.d.ts +4 -1
- package/dist/managers/slashCommandManager.d.ts.map +1 -1
- package/dist/managers/slashCommandManager.js +16 -6
- package/dist/managers/subagentManager.d.ts +13 -2
- package/dist/managers/subagentManager.d.ts.map +1 -1
- package/dist/managers/subagentManager.js +144 -35
- package/dist/managers/toolManager.d.ts +11 -1
- package/dist/managers/toolManager.d.ts.map +1 -1
- package/dist/managers/toolManager.js +11 -3
- package/dist/services/GitService.d.ts.map +1 -1
- package/dist/services/GitService.js +6 -2
- package/dist/services/MarketplaceService.d.ts +14 -1
- package/dist/services/MarketplaceService.d.ts.map +1 -1
- package/dist/services/MarketplaceService.js +72 -4
- package/dist/services/MemoryRuleService.d.ts +1 -1
- package/dist/services/MemoryRuleService.d.ts.map +1 -1
- package/dist/services/MemoryRuleService.js +13 -2
- package/dist/services/aiService.js +1 -1
- package/dist/services/configurationService.d.ts +18 -2
- package/dist/services/configurationService.d.ts.map +1 -1
- package/dist/services/configurationService.js +62 -0
- package/dist/services/fileWatcher.d.ts +0 -5
- package/dist/services/fileWatcher.d.ts.map +1 -1
- package/dist/services/fileWatcher.js +0 -11
- package/dist/services/memory.js +1 -1
- package/dist/services/pluginLoader.d.ts.map +1 -1
- package/dist/services/pluginLoader.js +6 -1
- package/dist/services/reversionService.d.ts +24 -0
- package/dist/services/reversionService.d.ts.map +1 -0
- package/dist/services/reversionService.js +76 -0
- package/dist/services/session.d.ts +7 -0
- package/dist/services/session.d.ts.map +1 -1
- package/dist/services/session.js +126 -3
- package/dist/tools/bashTool.d.ts +0 -8
- package/dist/tools/bashTool.d.ts.map +1 -1
- package/dist/tools/bashTool.js +52 -174
- package/dist/tools/deleteFileTool.d.ts.map +1 -1
- package/dist/tools/deleteFileTool.js +9 -0
- package/dist/tools/editTool.d.ts.map +1 -1
- package/dist/tools/editTool.js +15 -4
- package/dist/tools/multiEditTool.d.ts.map +1 -1
- package/dist/tools/multiEditTool.js +16 -5
- package/dist/tools/taskOutputTool.d.ts +3 -0
- package/dist/tools/taskOutputTool.d.ts.map +1 -0
- package/dist/tools/taskOutputTool.js +149 -0
- package/dist/tools/taskStopTool.d.ts +3 -0
- package/dist/tools/taskStopTool.d.ts.map +1 -0
- package/dist/tools/taskStopTool.js +65 -0
- package/dist/tools/taskTool.d.ts.map +1 -1
- package/dist/tools/taskTool.js +105 -63
- package/dist/tools/types.d.ts +7 -0
- package/dist/tools/types.d.ts.map +1 -1
- package/dist/tools/writeTool.d.ts.map +1 -1
- package/dist/tools/writeTool.js +9 -0
- package/dist/types/commands.d.ts +1 -0
- package/dist/types/commands.d.ts.map +1 -1
- package/dist/types/configuration.d.ts +3 -0
- package/dist/types/configuration.d.ts.map +1 -1
- package/dist/types/environment.d.ts +2 -1
- package/dist/types/environment.d.ts.map +1 -1
- package/dist/types/environment.js +0 -6
- package/dist/types/history.d.ts +5 -0
- package/dist/types/history.d.ts.map +1 -0
- package/dist/types/history.js +1 -0
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/index.js +1 -0
- package/dist/types/marketplace.d.ts +4 -0
- package/dist/types/marketplace.d.ts.map +1 -1
- package/dist/types/messaging.d.ts +7 -1
- package/dist/types/messaging.d.ts.map +1 -1
- package/dist/types/processes.d.ts +24 -4
- package/dist/types/processes.d.ts.map +1 -1
- package/dist/types/reversion.d.ts +29 -0
- package/dist/types/reversion.d.ts.map +1 -0
- package/dist/types/reversion.js +1 -0
- package/dist/utils/builtinSubagents.d.ts.map +1 -1
- package/dist/utils/builtinSubagents.js +16 -0
- package/dist/utils/constants.d.ts +2 -2
- package/dist/utils/constants.d.ts.map +1 -1
- package/dist/utils/constants.js +2 -2
- package/dist/utils/editUtils.d.ts +4 -9
- package/dist/utils/editUtils.d.ts.map +1 -1
- package/dist/utils/editUtils.js +54 -55
- package/dist/utils/messageOperations.d.ts +3 -1
- package/dist/utils/messageOperations.d.ts.map +1 -1
- package/dist/utils/messageOperations.js +8 -1
- package/dist/utils/openaiClient.d.ts.map +1 -1
- package/dist/utils/openaiClient.js +56 -26
- package/dist/utils/promptHistory.d.ts +20 -0
- package/dist/utils/promptHistory.d.ts.map +1 -0
- package/dist/utils/promptHistory.js +117 -0
- package/package.json +5 -3
- package/src/agent.ts +193 -109
- package/src/constants/prompts.ts +45 -5
- package/src/constants/tools.ts +2 -2
- package/src/index.ts +1 -1
- package/src/managers/MemoryRuleManager.ts +18 -2
- package/src/managers/aiManager.ts +87 -18
- package/src/managers/backgroundBashManager.ts +1 -0
- package/src/managers/backgroundTaskManager.ts +306 -0
- package/src/managers/bashManager.ts +0 -4
- package/src/managers/foregroundTaskManager.ts +26 -0
- package/src/managers/liveConfigManager.ts +2 -1
- package/src/managers/lspManager.ts +3 -1
- package/src/managers/messageManager.ts +136 -18
- package/src/managers/permissionManager.ts +11 -13
- package/src/managers/pluginManager.ts +4 -3
- package/src/managers/pluginScopeManager.ts +57 -8
- package/src/managers/reversionManager.ts +152 -0
- package/src/managers/slashCommandManager.ts +30 -7
- package/src/managers/subagentManager.ts +176 -31
- package/src/managers/toolManager.ts +23 -4
- package/src/services/GitService.ts +6 -2
- package/src/services/MarketplaceService.ts +100 -4
- package/src/services/MemoryRuleService.ts +18 -6
- package/src/services/aiService.ts +1 -1
- package/src/services/configurationService.ts +79 -1
- package/src/services/fileWatcher.ts +0 -13
- package/src/services/memory.ts +1 -1
- package/src/services/pluginLoader.ts +7 -1
- package/src/services/reversionService.ts +94 -0
- package/src/services/session.ts +161 -3
- package/src/tools/bashTool.ts +73 -200
- package/src/tools/deleteFileTool.ts +15 -0
- package/src/tools/editTool.ts +20 -10
- package/src/tools/multiEditTool.ts +21 -11
- package/src/tools/taskOutputTool.ts +174 -0
- package/src/tools/taskStopTool.ts +72 -0
- package/src/tools/taskTool.ts +130 -74
- package/src/tools/types.ts +7 -0
- package/src/tools/writeTool.ts +14 -0
- package/src/types/commands.ts +3 -0
- package/src/types/configuration.ts +4 -0
- package/src/types/environment.ts +3 -1
- package/src/types/history.ts +4 -0
- package/src/types/index.ts +1 -0
- package/src/types/marketplace.ts +5 -0
- package/src/types/messaging.ts +9 -1
- package/src/types/processes.ts +33 -4
- package/src/types/reversion.ts +29 -0
- package/src/utils/builtinSubagents.ts +18 -0
- package/src/utils/constants.ts +2 -2
- package/src/utils/editUtils.ts +66 -58
- package/src/utils/messageOperations.ts +10 -0
- package/src/utils/openaiClient.ts +69 -35
- package/src/utils/promptHistory.ts +133 -0
- package/dist/utils/bashHistory.d.ts +0 -50
- package/dist/utils/bashHistory.d.ts.map +0 -1
- package/dist/utils/bashHistory.js +0 -256
- package/src/utils/bashHistory.ts +0 -320
package/src/utils/editUtils.ts
CHANGED
|
@@ -3,80 +3,88 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
6
|
+
* Escape regular expression special characters
|
|
7
|
+
*/
|
|
8
|
+
export function escapeRegExp(string: string): string {
|
|
9
|
+
return string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Analyze why an edit failed by finding the best partial match and highlighting mismatches.
|
|
12
14
|
*/
|
|
13
|
-
export function
|
|
15
|
+
export function analyzeEditMismatch(
|
|
14
16
|
content: string,
|
|
15
17
|
searchString: string,
|
|
16
|
-
): string
|
|
17
|
-
|
|
18
|
-
if (content.includes(searchString)) {
|
|
19
|
-
return searchString;
|
|
20
|
-
}
|
|
21
|
-
|
|
18
|
+
): string {
|
|
19
|
+
const contentLines = content.split("\n");
|
|
22
20
|
const searchLines = searchString.split("\n");
|
|
23
|
-
if (searchLines.length === 0) return null;
|
|
24
21
|
|
|
25
|
-
|
|
26
|
-
|
|
22
|
+
if (searchLines.length === 0 || contentLines.length === 0) {
|
|
23
|
+
return "old_string not found in file (empty search or content)";
|
|
24
|
+
}
|
|
27
25
|
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
let isMatch = true;
|
|
26
|
+
let bestMatchIndex = -1;
|
|
27
|
+
let bestMatchScore = -1;
|
|
31
28
|
|
|
29
|
+
// Sliding window to find the best partial match
|
|
30
|
+
for (let i = 0; i <= contentLines.length - searchLines.length; i++) {
|
|
31
|
+
let currentScore = 0;
|
|
32
32
|
for (let j = 0; j < searchLines.length; j++) {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
const sTrimmed = sLine.trimStart();
|
|
37
|
-
const cTrimmed = cLine.trimStart();
|
|
38
|
-
|
|
39
|
-
// If trimmed content doesn't match, it's not a match
|
|
40
|
-
if (sTrimmed !== cTrimmed) {
|
|
41
|
-
isMatch = false;
|
|
42
|
-
break;
|
|
33
|
+
if (contentLines[i + j] === searchLines[j]) {
|
|
34
|
+
currentScore++;
|
|
43
35
|
}
|
|
36
|
+
}
|
|
44
37
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
38
|
+
// Heuristic: prioritize matches where first or last lines match
|
|
39
|
+
if (contentLines[i] === searchLines[0]) currentScore += 0.5;
|
|
40
|
+
if (
|
|
41
|
+
contentLines[i + searchLines.length - 1] ===
|
|
42
|
+
searchLines[searchLines.length - 1]
|
|
43
|
+
)
|
|
44
|
+
currentScore += 0.5;
|
|
50
45
|
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
46
|
+
// Also consider trimmed matches to catch indentation issues
|
|
47
|
+
for (let j = 0; j < searchLines.length; j++) {
|
|
48
|
+
if (
|
|
49
|
+
contentLines[i + j].trim() === searchLines[j].trim() &&
|
|
50
|
+
contentLines[i + j] !== searchLines[j]
|
|
51
|
+
) {
|
|
52
|
+
currentScore += 0.1;
|
|
57
53
|
}
|
|
58
54
|
}
|
|
59
55
|
|
|
60
|
-
if (
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
.join("\n");
|
|
64
|
-
if (foundMatch !== null && foundMatch !== matchCandidate) {
|
|
65
|
-
// Multiple different smart matches found
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
foundMatch = matchCandidate;
|
|
56
|
+
if (currentScore > bestMatchScore) {
|
|
57
|
+
bestMatchScore = currentScore;
|
|
58
|
+
bestMatchIndex = i;
|
|
69
59
|
}
|
|
70
60
|
}
|
|
71
61
|
|
|
72
|
-
// If
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
}
|
|
62
|
+
// If no decent match found (score <= 0), return generic message
|
|
63
|
+
if (bestMatchScore <= 0) {
|
|
64
|
+
return "old_string not found in file (no similar block found)";
|
|
65
|
+
}
|
|
76
66
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
67
|
+
// Generate detailed report
|
|
68
|
+
const reportLines: string[] = [
|
|
69
|
+
`old_string not found in file. Best partial match found at line ${bestMatchIndex + 1}:`,
|
|
70
|
+
];
|
|
71
|
+
|
|
72
|
+
for (let j = 0; j < searchLines.length; j++) {
|
|
73
|
+
const lineNum = bestMatchIndex + j + 1;
|
|
74
|
+
const actualLine = contentLines[bestMatchIndex + j];
|
|
75
|
+
const expectedLine = searchLines[j];
|
|
76
|
+
|
|
77
|
+
if (actualLine === expectedLine) {
|
|
78
|
+
reportLines.push(`${lineNum.toString().padStart(4)} | ${actualLine}`);
|
|
79
|
+
} else {
|
|
80
|
+
reportLines.push(
|
|
81
|
+
`${lineNum.toString().padStart(4)} | - ${expectedLine} (expected)`,
|
|
82
|
+
);
|
|
83
|
+
reportLines.push(
|
|
84
|
+
`${lineNum.toString().padStart(4)} | + ${actualLine} (actual)`,
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return reportLines.join("\n");
|
|
82
90
|
}
|
|
@@ -169,6 +169,7 @@ export const addUserMessageToMessages = ({
|
|
|
169
169
|
}
|
|
170
170
|
|
|
171
171
|
const userMessage: Message = {
|
|
172
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
172
173
|
role: "user",
|
|
173
174
|
blocks,
|
|
174
175
|
};
|
|
@@ -205,6 +206,7 @@ export const addAssistantMessageToMessages = (
|
|
|
205
206
|
}
|
|
206
207
|
|
|
207
208
|
const initialAssistantMessage: Message = {
|
|
209
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
208
210
|
role: "assistant",
|
|
209
211
|
blocks,
|
|
210
212
|
usage, // Include usage data if provided
|
|
@@ -502,6 +504,7 @@ export interface AddSubagentBlockParams {
|
|
|
502
504
|
status: "active" | "completed" | "error" | "aborted";
|
|
503
505
|
sessionId: string;
|
|
504
506
|
configuration: SubagentConfiguration;
|
|
507
|
+
runInBackground?: boolean;
|
|
505
508
|
}
|
|
506
509
|
|
|
507
510
|
export interface UpdateSubagentBlockParams {
|
|
@@ -518,6 +521,7 @@ export const addSubagentBlockToMessage = ({
|
|
|
518
521
|
status,
|
|
519
522
|
sessionId,
|
|
520
523
|
configuration,
|
|
524
|
+
runInBackground,
|
|
521
525
|
}: AddSubagentBlockParams): Message[] => {
|
|
522
526
|
const newMessages = [...messages];
|
|
523
527
|
|
|
@@ -527,6 +531,7 @@ export const addSubagentBlockToMessage = ({
|
|
|
527
531
|
if (!lastAssistantMessage || lastAssistantMessage.role !== "assistant") {
|
|
528
532
|
// Create new assistant message if the last message is not from assistant
|
|
529
533
|
lastAssistantMessage = {
|
|
534
|
+
id: `msg-${Date.now()}-${Math.random().toString(36).slice(2, 9)}`,
|
|
530
535
|
role: "assistant",
|
|
531
536
|
blocks: [],
|
|
532
537
|
};
|
|
@@ -541,6 +546,7 @@ export const addSubagentBlockToMessage = ({
|
|
|
541
546
|
status,
|
|
542
547
|
sessionId,
|
|
543
548
|
configuration,
|
|
549
|
+
runInBackground,
|
|
544
550
|
});
|
|
545
551
|
|
|
546
552
|
return newMessages;
|
|
@@ -552,6 +558,7 @@ export const updateSubagentBlockInMessage = (
|
|
|
552
558
|
updates: Partial<{
|
|
553
559
|
status: "active" | "completed" | "error" | "aborted";
|
|
554
560
|
sessionId: string;
|
|
561
|
+
runInBackground: boolean;
|
|
555
562
|
}>,
|
|
556
563
|
): Message[] => {
|
|
557
564
|
const newMessages = [...messages];
|
|
@@ -568,6 +575,9 @@ export const updateSubagentBlockInMessage = (
|
|
|
568
575
|
if (updates.sessionId !== undefined) {
|
|
569
576
|
block.sessionId = updates.sessionId;
|
|
570
577
|
}
|
|
578
|
+
if (updates.runInBackground !== undefined) {
|
|
579
|
+
block.runInBackground = updates.runInBackground;
|
|
580
|
+
}
|
|
571
581
|
return newMessages;
|
|
572
582
|
}
|
|
573
583
|
}
|
|
@@ -51,7 +51,9 @@ export class OpenAIClient {
|
|
|
51
51
|
>
|
|
52
52
|
>;
|
|
53
53
|
// Prevent unhandled rejection if only withResponse() is used
|
|
54
|
-
promise.catch(() => {
|
|
54
|
+
promise.catch((e) => {
|
|
55
|
+
logger.error("Unhandled OpenAI promise rejection:", e);
|
|
56
|
+
});
|
|
55
57
|
return promise;
|
|
56
58
|
},
|
|
57
59
|
},
|
|
@@ -83,24 +85,61 @@ export class OpenAIClient {
|
|
|
83
85
|
};
|
|
84
86
|
|
|
85
87
|
const fetchFn = (customFetch as typeof fetch) || fetch;
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
88
|
+
let lastError: (Error & { status?: number; body?: unknown }) | undefined;
|
|
89
|
+
const maxRetries = 3;
|
|
90
|
+
const initialDelay = 1000;
|
|
91
|
+
|
|
92
|
+
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
93
|
+
if (attempt > 0) {
|
|
94
|
+
const delay = initialDelay * Math.pow(2, attempt - 1);
|
|
95
|
+
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const response = await fetchFn(url, {
|
|
99
|
+
method: "POST",
|
|
100
|
+
headers,
|
|
101
|
+
body: JSON.stringify(params),
|
|
102
|
+
signal: options?.signal,
|
|
103
|
+
...(fetchOptions as RequestInit),
|
|
104
|
+
});
|
|
105
|
+
|
|
106
|
+
if (response.ok) {
|
|
107
|
+
if (params.stream) {
|
|
108
|
+
return {
|
|
109
|
+
data: this.streamChatCompletion(response),
|
|
110
|
+
response,
|
|
111
|
+
} as unknown as APIResponse<
|
|
112
|
+
P extends ChatCompletionCreateParamsStreaming
|
|
113
|
+
? AsyncIterable<ChatCompletionChunk>
|
|
114
|
+
: ChatCompletion
|
|
115
|
+
>;
|
|
116
|
+
} else {
|
|
117
|
+
const data = await response.json();
|
|
118
|
+
return {
|
|
119
|
+
data,
|
|
120
|
+
response,
|
|
121
|
+
} as unknown as APIResponse<
|
|
122
|
+
P extends ChatCompletionCreateParamsStreaming
|
|
123
|
+
? AsyncIterable<ChatCompletionChunk>
|
|
124
|
+
: ChatCompletion
|
|
125
|
+
>;
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
95
129
|
let errorBody: unknown;
|
|
96
130
|
try {
|
|
97
131
|
const text = await response.text();
|
|
98
132
|
try {
|
|
99
133
|
errorBody = JSON.parse(text);
|
|
100
|
-
} catch {
|
|
134
|
+
} catch (e) {
|
|
135
|
+
logger.error("Failed to parse error response body as JSON", {
|
|
136
|
+
error: e,
|
|
137
|
+
text,
|
|
138
|
+
});
|
|
101
139
|
errorBody = text;
|
|
102
140
|
}
|
|
103
|
-
} catch {
|
|
141
|
+
} catch (e) {
|
|
142
|
+
logger.error("Failed to read error response text", { error: e });
|
|
104
143
|
errorBody = {};
|
|
105
144
|
}
|
|
106
145
|
|
|
@@ -118,6 +157,21 @@ export class OpenAIClient {
|
|
|
118
157
|
) as Error & { status?: number; body?: unknown };
|
|
119
158
|
error.status = response.status;
|
|
120
159
|
error.body = errorBody;
|
|
160
|
+
|
|
161
|
+
if (response.status === 429 && attempt < maxRetries) {
|
|
162
|
+
const responseHeaders: Record<string, string> = {};
|
|
163
|
+
response.headers.forEach((value, key) => {
|
|
164
|
+
responseHeaders[key] = value;
|
|
165
|
+
});
|
|
166
|
+
logger.warn("OpenAI API 429 Too Many Requests, retrying...", {
|
|
167
|
+
attempt: attempt + 1,
|
|
168
|
+
status: response.status,
|
|
169
|
+
responseHeaders,
|
|
170
|
+
});
|
|
171
|
+
lastError = error;
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
|
|
121
175
|
const responseHeaders: Record<string, string> = {};
|
|
122
176
|
response.headers.forEach((value, key) => {
|
|
123
177
|
responseHeaders[key] = value;
|
|
@@ -131,27 +185,7 @@ export class OpenAIClient {
|
|
|
131
185
|
});
|
|
132
186
|
throw error;
|
|
133
187
|
}
|
|
134
|
-
|
|
135
|
-
if (params.stream) {
|
|
136
|
-
return {
|
|
137
|
-
data: this.streamChatCompletion(response),
|
|
138
|
-
response,
|
|
139
|
-
} as unknown as APIResponse<
|
|
140
|
-
P extends ChatCompletionCreateParamsStreaming
|
|
141
|
-
? AsyncIterable<ChatCompletionChunk>
|
|
142
|
-
: ChatCompletion
|
|
143
|
-
>;
|
|
144
|
-
} else {
|
|
145
|
-
const data = await response.json();
|
|
146
|
-
return {
|
|
147
|
-
data,
|
|
148
|
-
response,
|
|
149
|
-
} as unknown as APIResponse<
|
|
150
|
-
P extends ChatCompletionCreateParamsStreaming
|
|
151
|
-
? AsyncIterable<ChatCompletionChunk>
|
|
152
|
-
: ChatCompletion
|
|
153
|
-
>;
|
|
154
|
-
}
|
|
188
|
+
throw lastError;
|
|
155
189
|
}
|
|
156
190
|
|
|
157
191
|
private async *streamChatCompletion(
|
|
@@ -182,8 +216,8 @@ export class OpenAIClient {
|
|
|
182
216
|
try {
|
|
183
217
|
const json = JSON.parse(data);
|
|
184
218
|
yield json as ChatCompletionChunk;
|
|
185
|
-
} catch {
|
|
186
|
-
|
|
219
|
+
} catch (e) {
|
|
220
|
+
logger.error("Failed to parse stream chunk", { error: e, data });
|
|
187
221
|
}
|
|
188
222
|
}
|
|
189
223
|
}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import fs from "fs";
|
|
2
|
+
import { PROMPT_HISTORY_FILE, DATA_DIRECTORY } from "./constants.js";
|
|
3
|
+
import { logger } from "./globalLogger.js";
|
|
4
|
+
import { PromptEntry } from "../types/history.js";
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Ensure data directory exists
|
|
8
|
+
*/
|
|
9
|
+
const ensureDataDirectory = (): void => {
|
|
10
|
+
try {
|
|
11
|
+
if (!fs.existsSync(DATA_DIRECTORY)) {
|
|
12
|
+
fs.mkdirSync(DATA_DIRECTORY, { recursive: true });
|
|
13
|
+
}
|
|
14
|
+
} catch (error) {
|
|
15
|
+
logger.debug("Failed to create data directory:", error);
|
|
16
|
+
}
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
const MAX_HISTORY_ENTRIES = 1000;
|
|
20
|
+
|
|
21
|
+
export class PromptHistoryManager {
|
|
22
|
+
/**
|
|
23
|
+
* Add a new prompt to history
|
|
24
|
+
*/
|
|
25
|
+
static async addEntry(prompt: string): Promise<void> {
|
|
26
|
+
try {
|
|
27
|
+
if (!prompt.trim()) return;
|
|
28
|
+
|
|
29
|
+
ensureDataDirectory();
|
|
30
|
+
const entry: PromptEntry = {
|
|
31
|
+
prompt,
|
|
32
|
+
timestamp: Date.now(),
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
const line = JSON.stringify(entry) + "\n";
|
|
36
|
+
await fs.promises.appendFile(PROMPT_HISTORY_FILE, line, "utf-8");
|
|
37
|
+
|
|
38
|
+
// Periodically trim history file to prevent it from growing too large
|
|
39
|
+
// We do this randomly (1 in 50 chance) to avoid performance hit on every entry
|
|
40
|
+
if (Math.random() < 0.02) {
|
|
41
|
+
await this.trimHistory();
|
|
42
|
+
}
|
|
43
|
+
} catch (error) {
|
|
44
|
+
logger.debug("Failed to add prompt to history:", error);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Trim history file to MAX_HISTORY_ENTRIES
|
|
50
|
+
*/
|
|
51
|
+
private static async trimHistory(): Promise<void> {
|
|
52
|
+
try {
|
|
53
|
+
if (!fs.existsSync(PROMPT_HISTORY_FILE)) return;
|
|
54
|
+
|
|
55
|
+
const data = await fs.promises.readFile(PROMPT_HISTORY_FILE, "utf-8");
|
|
56
|
+
const lines = data.split("\n").filter((line) => line.trim());
|
|
57
|
+
|
|
58
|
+
if (lines.length > MAX_HISTORY_ENTRIES * 1.2) {
|
|
59
|
+
const trimmedLines = lines.slice(-MAX_HISTORY_ENTRIES);
|
|
60
|
+
await fs.promises.writeFile(
|
|
61
|
+
PROMPT_HISTORY_FILE,
|
|
62
|
+
trimmedLines.join("\n") + "\n",
|
|
63
|
+
"utf-8",
|
|
64
|
+
);
|
|
65
|
+
}
|
|
66
|
+
} catch (error) {
|
|
67
|
+
logger.debug("Failed to trim prompt history:", error);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Get all history entries
|
|
73
|
+
*/
|
|
74
|
+
static async getHistory(): Promise<PromptEntry[]> {
|
|
75
|
+
try {
|
|
76
|
+
if (!fs.existsSync(PROMPT_HISTORY_FILE)) {
|
|
77
|
+
return [];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const data = await fs.promises.readFile(PROMPT_HISTORY_FILE, "utf-8");
|
|
81
|
+
const lines = data.split("\n").filter((line) => line.trim());
|
|
82
|
+
|
|
83
|
+
const entries: PromptEntry[] = lines
|
|
84
|
+
.map((line) => {
|
|
85
|
+
try {
|
|
86
|
+
return JSON.parse(line) as PromptEntry;
|
|
87
|
+
} catch {
|
|
88
|
+
logger.debug("Failed to parse history line:", line);
|
|
89
|
+
return null;
|
|
90
|
+
}
|
|
91
|
+
})
|
|
92
|
+
.filter((entry): entry is PromptEntry => entry !== null);
|
|
93
|
+
|
|
94
|
+
// Deduplicate by prompt, keeping the most recent one
|
|
95
|
+
const uniqueEntries: PromptEntry[] = [];
|
|
96
|
+
const seenPrompts = new Set<string>();
|
|
97
|
+
|
|
98
|
+
// Process from newest to oldest
|
|
99
|
+
for (let i = entries.length - 1; i >= 0; i--) {
|
|
100
|
+
const entry = entries[i];
|
|
101
|
+
if (!seenPrompts.has(entry.prompt)) {
|
|
102
|
+
uniqueEntries.push(entry);
|
|
103
|
+
seenPrompts.add(entry.prompt);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return uniqueEntries;
|
|
108
|
+
} catch (error) {
|
|
109
|
+
logger.debug("Failed to load prompt history:", error);
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Search history by query
|
|
116
|
+
*/
|
|
117
|
+
static async searchHistory(query: string): Promise<PromptEntry[]> {
|
|
118
|
+
try {
|
|
119
|
+
const history = await this.getHistory();
|
|
120
|
+
if (!query.trim()) {
|
|
121
|
+
return history;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
const normalizedQuery = query.toLowerCase();
|
|
125
|
+
return history.filter((entry) =>
|
|
126
|
+
entry.prompt.toLowerCase().includes(normalizedQuery),
|
|
127
|
+
);
|
|
128
|
+
} catch (error) {
|
|
129
|
+
logger.debug("Failed to search prompt history:", error);
|
|
130
|
+
return [];
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Bash command history management module
|
|
3
|
-
* Used for persistent storage and searching of bash commands executed by users
|
|
4
|
-
*/
|
|
5
|
-
export interface BashHistoryEntry {
|
|
6
|
-
command: string;
|
|
7
|
-
timestamp: number;
|
|
8
|
-
workdir: string;
|
|
9
|
-
}
|
|
10
|
-
export interface BashHistory {
|
|
11
|
-
commands: BashHistoryEntry[];
|
|
12
|
-
version: number;
|
|
13
|
-
}
|
|
14
|
-
/**
|
|
15
|
-
* Load bash history
|
|
16
|
-
*/
|
|
17
|
-
export declare const loadBashHistory: () => BashHistory;
|
|
18
|
-
/**
|
|
19
|
-
* Save bash history
|
|
20
|
-
*/
|
|
21
|
-
export declare const saveBashHistory: (history: BashHistory) => void;
|
|
22
|
-
/**
|
|
23
|
-
* Add command to bash history
|
|
24
|
-
*/
|
|
25
|
-
export declare const addBashCommandToHistory: (command: string, workdir: string) => void;
|
|
26
|
-
/**
|
|
27
|
-
* Search bash history by keywords
|
|
28
|
-
*/
|
|
29
|
-
export declare const searchBashHistory: (query: string, limit?: number) => BashHistoryEntry[];
|
|
30
|
-
/**
|
|
31
|
-
* Get recently used bash commands
|
|
32
|
-
*/
|
|
33
|
-
export declare const getRecentBashCommands: (limit?: number) => BashHistoryEntry[];
|
|
34
|
-
/**
|
|
35
|
-
* Delete a specific command from bash history
|
|
36
|
-
*/
|
|
37
|
-
export declare const deleteBashCommandFromHistory: (command: string, workdir?: string) => void;
|
|
38
|
-
/**
|
|
39
|
-
* Clear bash history
|
|
40
|
-
*/
|
|
41
|
-
export declare const clearBashHistory: () => void;
|
|
42
|
-
/**
|
|
43
|
-
* Get bash command statistics
|
|
44
|
-
*/
|
|
45
|
-
export declare const getBashCommandStats: () => {
|
|
46
|
-
totalCommands: number;
|
|
47
|
-
uniqueCommands: number;
|
|
48
|
-
workdirs: string[];
|
|
49
|
-
};
|
|
50
|
-
//# sourceMappingURL=bashHistory.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"bashHistory.d.ts","sourceRoot":"","sources":["../../src/utils/bashHistory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,EAAE,gBAAgB,EAAE,CAAC;IAC7B,OAAO,EAAE,MAAM,CAAC;CACjB;AAkBD;;GAEG;AACH,eAAO,MAAM,eAAe,QAAO,WA+BlC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,GAAI,SAAS,WAAW,KAAG,IAoBtD,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,uBAAuB,GAClC,SAAS,MAAM,EACf,SAAS,MAAM,KACd,IA4BF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,iBAAiB,GAC5B,OAAO,MAAM,EACb,QAAO,MAAW,KACjB,gBAAgB,EAiElB,CAAC;AAwBF;;GAEG;AACH,eAAO,MAAM,qBAAqB,GAChC,QAAO,MAAW,KACjB,gBAAgB,EAWlB,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,4BAA4B,GACvC,SAAS,MAAM,EACf,UAAU,MAAM,KACf,IAmBF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,gBAAgB,QAAO,IAWnC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAO;IACrC,aAAa,EAAE,MAAM,CAAC;IACtB,cAAc,EAAE,MAAM,CAAC;IACvB,QAAQ,EAAE,MAAM,EAAE,CAAC;CAwBpB,CAAC"}
|