@codebolt/agent 6.1.20 → 6.1.21
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/processor-pieces/messageModifiers/argumentProcessorModifier.js +11 -15
- package/dist/processor-pieces/messageModifiers/atFileProcessorModifier.d.ts +0 -1
- package/dist/processor-pieces/messageModifiers/atFileProcessorModifier.js +16 -33
- package/dist/processor-pieces/messageModifiers/capabilityContextModifier.js +3 -2
- package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.d.ts +7 -0
- package/dist/processor-pieces/messageModifiers/chatHistoryMessageModifier.js +135 -27
- package/dist/processor-pieces/messageModifiers/chatRecordingModifier.js +3 -3
- package/dist/processor-pieces/messageModifiers/contextAssemblyModifier.js +18 -12
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.d.ts +1 -0
- package/dist/processor-pieces/messageModifiers/directoryContextModifier.js +15 -15
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.d.ts +1 -0
- package/dist/processor-pieces/messageModifiers/environmentContextModifier.js +48 -2
- package/dist/processor-pieces/messageModifiers/ideContextModifier.js +3 -2
- package/dist/processor-pieces/messageModifiers/memoryImportModifier.js +9 -15
- package/dist/processor-pieces/messageModifiers/toolInjectionModifier.js +17 -20
- package/dist/processor-pieces/postInferenceProcessors/loopDetectionModifier.js +8 -19
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.d.ts +1 -1
- package/dist/processor-pieces/postToolCallProcessors/conversationCompactorModifier.js +15 -15
- package/dist/processor-pieces/postToolCallProcessors/shellProcessorModifier.js +3 -3
- package/dist/processor-pieces/preInferenceProcessors/chatCompressionModifier.js +2 -2
- package/dist/processor-pieces/utils/messageModifierHelper.js +3 -3
- package/dist/types/libFunctionTypes.d.ts +5 -0
- package/dist/unified/agent/agent.d.ts +10 -0
- package/dist/unified/agent/agent.js +166 -15
- package/dist/unified/agent/tools.d.ts +14 -0
- package/dist/unified/agent/tools.js +82 -51
- package/dist/unified/base/agentStep.d.ts +1 -0
- package/dist/unified/base/agentStep.js +39 -11
- package/dist/unified/base/initialPromptGenerator.d.ts +2 -0
- package/dist/unified/base/initialPromptGenerator.js +42 -19
- package/dist/unified/base/promptContext.d.ts +3 -0
- package/dist/unified/base/promptContext.js +193 -15
- package/dist/unified/base/responseExecutor.d.ts +6 -0
- package/dist/unified/base/responseExecutor.js +222 -58
- package/dist/unified/services/CompressionCoordinator.js +9 -9
- package/dist/unified/services/compaction/autoCompact.js +5 -5
- package/dist/unified/services/compaction/contextCollapse.js +2 -2
- package/dist/unified/services/compaction/reactiveCompact.js +5 -5
- package/dist/unified/types/libTypes.d.ts +6 -0
- package/dist/unified/utils/agentToolLoader.js +29 -24
- package/package.json +5 -1
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.ArgumentProcessorModifier = void 0;
|
|
4
4
|
const base_1 = require("../base");
|
|
5
|
+
const promptContext_1 = require("../../unified/base/promptContext");
|
|
5
6
|
class ArgumentProcessorModifier extends base_1.BaseMessageModifier {
|
|
6
7
|
constructor(options = {}) {
|
|
7
8
|
super();
|
|
@@ -19,8 +20,7 @@ class ArgumentProcessorModifier extends base_1.BaseMessageModifier {
|
|
|
19
20
|
if (!(invocation === null || invocation === void 0 ? void 0 : invocation.args)) {
|
|
20
21
|
return Promise.resolve(createdMessage);
|
|
21
22
|
}
|
|
22
|
-
|
|
23
|
-
const userMessage = createdMessage.message.messages.find(msg => msg.role === 'user');
|
|
23
|
+
const userMessage = (0, promptContext_1.getCurrentUserMessage)(createdMessage);
|
|
24
24
|
if (!userMessage || typeof userMessage.content !== 'string') {
|
|
25
25
|
return Promise.resolve(createdMessage);
|
|
26
26
|
}
|
|
@@ -37,23 +37,19 @@ class ArgumentProcessorModifier extends base_1.BaseMessageModifier {
|
|
|
37
37
|
}
|
|
38
38
|
appendContent = `\n\nArguments: ${argsToAppend}`;
|
|
39
39
|
}
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
};
|
|
47
|
-
}
|
|
48
|
-
return msg;
|
|
49
|
-
});
|
|
40
|
+
const updatedMessage = (0, promptContext_1.updateCurrentUserMessage)(createdMessage, (message) => ({
|
|
41
|
+
...message,
|
|
42
|
+
content: typeof message.content === 'string'
|
|
43
|
+
? message.content + appendContent
|
|
44
|
+
: message.content,
|
|
45
|
+
}));
|
|
50
46
|
return Promise.resolve({
|
|
47
|
+
...updatedMessage,
|
|
51
48
|
message: {
|
|
52
|
-
...
|
|
53
|
-
messages: updatedMessages
|
|
49
|
+
...updatedMessage.message,
|
|
54
50
|
},
|
|
55
51
|
metadata: {
|
|
56
|
-
...
|
|
52
|
+
...updatedMessage.metadata,
|
|
57
53
|
argumentsProcessed: true,
|
|
58
54
|
argumentsAppended: appendContent.trim()
|
|
59
55
|
}
|
|
@@ -19,7 +19,6 @@ export declare class AtFileProcessorModifier extends BaseMessageModifier {
|
|
|
19
19
|
private readManyFiles;
|
|
20
20
|
private readFileContent;
|
|
21
21
|
private getFolderStructure;
|
|
22
|
-
private findLastUserMessage;
|
|
23
22
|
private getProjectPath;
|
|
24
23
|
private isReadableTextFile;
|
|
25
24
|
private isLikelyBinaryFile;
|
|
@@ -41,6 +41,7 @@ const base_1 = require("../base");
|
|
|
41
41
|
const fs = __importStar(require("node:fs/promises"));
|
|
42
42
|
const path = __importStar(require("node:path"));
|
|
43
43
|
const codeboltjs_1 = __importDefault(require("@codebolt/codeboltjs"));
|
|
44
|
+
const promptContext_1 = require("../../unified/base/promptContext");
|
|
44
45
|
class AtFileProcessorModifier extends base_1.BaseMessageModifier {
|
|
45
46
|
constructor(options = {}) {
|
|
46
47
|
super();
|
|
@@ -74,39 +75,30 @@ class AtFileProcessorModifier extends base_1.BaseMessageModifier {
|
|
|
74
75
|
if (!result.success) {
|
|
75
76
|
return createdMessage;
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
-
const
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
// Convert string content to array format if needed
|
|
84
|
-
let currentContent;
|
|
85
|
-
if (Array.isArray(lastUserMessage.content)) {
|
|
86
|
-
currentContent = lastUserMessage.content;
|
|
87
|
-
}
|
|
88
|
-
else {
|
|
89
|
-
// Convert string content to array format
|
|
90
|
-
currentContent = [{ type: 'text', text: lastUserMessage.content }];
|
|
91
|
-
}
|
|
92
|
-
// Ensure processedContent is in array format
|
|
78
|
+
const currentUserMessage = (0, promptContext_1.getCurrentUserMessage)(createdMessage);
|
|
79
|
+
const updatedMessage = currentUserMessage && result.processedContent
|
|
80
|
+
? (0, promptContext_1.updateCurrentUserMessage)(createdMessage, (message) => {
|
|
81
|
+
const currentContent = Array.isArray(message.content)
|
|
82
|
+
? message.content
|
|
83
|
+
: [{ type: 'text', text: message.content }];
|
|
93
84
|
const newContent = Array.isArray(result.processedContent)
|
|
94
85
|
? result.processedContent
|
|
95
86
|
: [{ type: 'text', text: result.processedContent }];
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
87
|
+
return {
|
|
88
|
+
...message,
|
|
89
|
+
type: 'message',
|
|
90
|
+
role: 'user',
|
|
99
91
|
content: [...currentContent, ...newContent]
|
|
100
92
|
};
|
|
101
|
-
}
|
|
102
|
-
|
|
93
|
+
})
|
|
94
|
+
: createdMessage;
|
|
103
95
|
return {
|
|
96
|
+
...updatedMessage,
|
|
104
97
|
message: {
|
|
105
|
-
...
|
|
106
|
-
messages
|
|
98
|
+
...updatedMessage.message,
|
|
107
99
|
},
|
|
108
100
|
metadata: {
|
|
109
|
-
...
|
|
101
|
+
...updatedMessage.metadata,
|
|
110
102
|
atFileProcessed: true,
|
|
111
103
|
processedFiles: mentionedFiles,
|
|
112
104
|
processedFolders: mentionedFolders,
|
|
@@ -348,15 +340,6 @@ class AtFileProcessorModifier extends base_1.BaseMessageModifier {
|
|
|
348
340
|
}
|
|
349
341
|
return lines.join('\n');
|
|
350
342
|
}
|
|
351
|
-
findLastUserMessage(messages) {
|
|
352
|
-
for (let i = messages.length - 1; i >= 0; i--) {
|
|
353
|
-
const message = messages[i];
|
|
354
|
-
if (message && message.role === 'user') {
|
|
355
|
-
return i;
|
|
356
|
-
}
|
|
357
|
-
}
|
|
358
|
-
return -1;
|
|
359
|
-
}
|
|
360
343
|
async getProjectPath() {
|
|
361
344
|
const effectiveProjectPath = process.env['CODEBOLT_EFFECTIVE_PROJECT_PATH'] || process.env['CODEBOLT_PROJECT_PATH'];
|
|
362
345
|
if (effectiveProjectPath) {
|
|
@@ -36,10 +36,11 @@ class CapabilityContextModifier extends base_1.BaseMessageModifier {
|
|
|
36
36
|
role: 'user',
|
|
37
37
|
content: this.formatSelectedCapabilitiesContext(selectedCapabilities, selectedCapabilityInfo, skillContexts),
|
|
38
38
|
};
|
|
39
|
+
const updatedMessage = (0, promptContext_1.appendUserContextMessage)(createdMessage, contextMessage);
|
|
39
40
|
return {
|
|
40
|
-
...
|
|
41
|
+
...updatedMessage,
|
|
41
42
|
metadata: {
|
|
42
|
-
...
|
|
43
|
+
...updatedMessage.metadata,
|
|
43
44
|
selectedCapabilities,
|
|
44
45
|
selectedCapabilitiesProcessed: true,
|
|
45
46
|
selectedCapabilityNames: skillContexts.map((context) => context.name),
|
|
@@ -15,4 +15,11 @@ export declare class ChatHistoryMessageModifier extends BaseMessageModifier {
|
|
|
15
15
|
modify(originalRequest: FlatUserMessage, createdMessage: ProcessedMessage): Promise<ProcessedMessage>;
|
|
16
16
|
private getChatHistory;
|
|
17
17
|
setMaxHistoryMessages(max: number): void;
|
|
18
|
+
private addMissingToolResponses;
|
|
19
|
+
private getStandaloneToolCall;
|
|
20
|
+
private getFunctionCallOutputId;
|
|
21
|
+
private getAssistantToolCallId;
|
|
22
|
+
private getAssistantToolCallName;
|
|
23
|
+
private getAssistantToolCallArguments;
|
|
24
|
+
private buildMissingToolResponseContent;
|
|
18
25
|
}
|
|
@@ -25,11 +25,12 @@ class ChatHistoryMessageModifier extends base_1.BaseMessageModifier {
|
|
|
25
25
|
if (!chatHistory || chatHistory.length === 0) {
|
|
26
26
|
return createdMessage;
|
|
27
27
|
}
|
|
28
|
+
const updatedMessage = (0, promptContext_1.prependTranscriptMessages)(createdMessage, chatHistory);
|
|
28
29
|
// Directly use the chat history messages - they're already in MessageObject format
|
|
29
30
|
return {
|
|
30
|
-
...
|
|
31
|
+
...updatedMessage,
|
|
31
32
|
metadata: {
|
|
32
|
-
...
|
|
33
|
+
...updatedMessage.metadata,
|
|
33
34
|
chatHistoryAdded: true,
|
|
34
35
|
chatHistoryCount: chatHistory.length,
|
|
35
36
|
threadId: originalRequest.threadId
|
|
@@ -47,40 +48,20 @@ class ChatHistoryMessageModifier extends base_1.BaseMessageModifier {
|
|
|
47
48
|
try {
|
|
48
49
|
const response = await codeboltjs_1.default.chat.getChatHistory(threadId);
|
|
49
50
|
// Check if response has messages array
|
|
50
|
-
if (!(response === null || response === void 0 ? void 0 : response.chats) || !((_a = response === null || response === void 0 ? void 0 : response.chats) === null || _a === void 0 ? void 0 : _a.
|
|
51
|
+
if (!(response === null || response === void 0 ? void 0 : response.chats) || !((_a = response === null || response === void 0 ? void 0 : response.chats) === null || _a === void 0 ? void 0 : _a.input) || !Array.isArray((_b = response === null || response === void 0 ? void 0 : response.chats) === null || _b === void 0 ? void 0 : _b.input) || ((_c = response === null || response === void 0 ? void 0 : response.chats) === null || _c === void 0 ? void 0 : _c.input.length) === 0) {
|
|
51
52
|
return [];
|
|
52
53
|
}
|
|
53
|
-
let historyMessages = (_d = response === null || response === void 0 ? void 0 : response.chats) === null || _d === void 0 ? void 0 : _d.
|
|
54
|
+
let historyMessages = (_d = response === null || response === void 0 ? void 0 : response.chats) === null || _d === void 0 ? void 0 : _d.input;
|
|
54
55
|
// Thread filtering is now handled by the API directly via threadId parameter
|
|
55
56
|
// Filter out system messages if not included
|
|
56
57
|
if (!this.includeSystemMessages) {
|
|
57
58
|
historyMessages = historyMessages.filter((msg) => msg.role !== 'system');
|
|
58
59
|
}
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
if (false) {
|
|
60
|
+
historyMessages = historyMessages.filter((message) => !(0, promptContext_1.isGeneratedUserContextMessage)(message));
|
|
61
|
+
if (this.maxHistoryMessages > 0 && historyMessages.length > this.maxHistoryMessages) {
|
|
62
62
|
historyMessages = historyMessages.slice(-this.maxHistoryMessages);
|
|
63
63
|
}
|
|
64
|
-
|
|
65
|
-
// If so, add tool response messages for each tool_call
|
|
66
|
-
const lastMessage = historyMessages[historyMessages.length - 1];
|
|
67
|
-
if (lastMessage &&
|
|
68
|
-
lastMessage.role === 'assistant' &&
|
|
69
|
-
lastMessage.tool_calls &&
|
|
70
|
-
Array.isArray(lastMessage.tool_calls) &&
|
|
71
|
-
lastMessage.tool_calls.length > 0) {
|
|
72
|
-
// Add tool response messages for each tool_call
|
|
73
|
-
const toolResponseMessages = [];
|
|
74
|
-
for (const toolCall of lastMessage.tool_calls) {
|
|
75
|
-
toolResponseMessages.push({
|
|
76
|
-
role: 'tool',
|
|
77
|
-
content: `Tool call "${toolCall.function.name}" was not executed. This appears to be from a previous incomplete conversation. The tool was called with arguments: ${toolCall.function.arguments}`,
|
|
78
|
-
tool_call_id: toolCall.id
|
|
79
|
-
});
|
|
80
|
-
}
|
|
81
|
-
// Return original messages + tool responses + context message
|
|
82
|
-
return [...historyMessages, ...toolResponseMessages];
|
|
83
|
-
}
|
|
64
|
+
historyMessages = this.addMissingToolResponses(historyMessages);
|
|
84
65
|
// Add a system message to indicate this is previous conversation
|
|
85
66
|
const contextMessage = {
|
|
86
67
|
role: 'user',
|
|
@@ -98,5 +79,132 @@ class ChatHistoryMessageModifier extends base_1.BaseMessageModifier {
|
|
|
98
79
|
setMaxHistoryMessages(max) {
|
|
99
80
|
this.maxHistoryMessages = max;
|
|
100
81
|
}
|
|
82
|
+
addMissingToolResponses(historyMessages) {
|
|
83
|
+
const existingToolResponseIds = new Set();
|
|
84
|
+
for (const message of historyMessages) {
|
|
85
|
+
const functionCallOutputId = this.getFunctionCallOutputId(message);
|
|
86
|
+
if (functionCallOutputId) {
|
|
87
|
+
existingToolResponseIds.add(functionCallOutputId);
|
|
88
|
+
}
|
|
89
|
+
if (typeof message.tool_call_id === 'string') {
|
|
90
|
+
existingToolResponseIds.add(message.tool_call_id);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
const repairedMessages = [];
|
|
94
|
+
for (const message of historyMessages) {
|
|
95
|
+
repairedMessages.push(message);
|
|
96
|
+
const standaloneToolCall = this.getStandaloneToolCall(message);
|
|
97
|
+
if (standaloneToolCall && !existingToolResponseIds.has(standaloneToolCall.id)) {
|
|
98
|
+
repairedMessages.push({
|
|
99
|
+
type: 'function_call_output',
|
|
100
|
+
call_id: standaloneToolCall.id,
|
|
101
|
+
output: this.buildMissingToolResponseContent(standaloneToolCall.name, standaloneToolCall.arguments),
|
|
102
|
+
status: 'completed',
|
|
103
|
+
});
|
|
104
|
+
existingToolResponseIds.add(standaloneToolCall.id);
|
|
105
|
+
}
|
|
106
|
+
const assistantToolCalls = Array.isArray(message.tool_calls) ? message.tool_calls : [];
|
|
107
|
+
for (const toolCall of assistantToolCalls) {
|
|
108
|
+
const toolCallId = this.getAssistantToolCallId(toolCall);
|
|
109
|
+
if (!toolCallId || existingToolResponseIds.has(toolCallId)) {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
const toolName = this.getAssistantToolCallName(toolCall);
|
|
113
|
+
const toolArguments = this.getAssistantToolCallArguments(toolCall);
|
|
114
|
+
repairedMessages.push({
|
|
115
|
+
role: 'tool',
|
|
116
|
+
content: this.buildMissingToolResponseContent(toolName, toolArguments),
|
|
117
|
+
tool_call_id: toolCallId,
|
|
118
|
+
});
|
|
119
|
+
existingToolResponseIds.add(toolCallId);
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return repairedMessages;
|
|
123
|
+
}
|
|
124
|
+
getStandaloneToolCall(message) {
|
|
125
|
+
var _a, _b;
|
|
126
|
+
const typedMessage = message;
|
|
127
|
+
if (typedMessage.type !== 'function_call') {
|
|
128
|
+
return null;
|
|
129
|
+
}
|
|
130
|
+
const id = typeof typedMessage.call_id === 'string'
|
|
131
|
+
? typedMessage.call_id
|
|
132
|
+
: typeof typedMessage.id === 'string'
|
|
133
|
+
? typedMessage.id
|
|
134
|
+
: '';
|
|
135
|
+
if (!id) {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
const name = typeof typedMessage.name === 'string'
|
|
139
|
+
? typedMessage.name
|
|
140
|
+
: typeof ((_a = typedMessage.function) === null || _a === void 0 ? void 0 : _a.name) === 'string'
|
|
141
|
+
? typedMessage.function.name
|
|
142
|
+
: 'unknown';
|
|
143
|
+
const toolArguments = typeof typedMessage.arguments === 'string'
|
|
144
|
+
? typedMessage.arguments
|
|
145
|
+
: typeof ((_b = typedMessage.function) === null || _b === void 0 ? void 0 : _b.arguments) === 'string'
|
|
146
|
+
? typedMessage.function.arguments
|
|
147
|
+
: '';
|
|
148
|
+
return {
|
|
149
|
+
id,
|
|
150
|
+
name,
|
|
151
|
+
arguments: toolArguments,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
getFunctionCallOutputId(message) {
|
|
155
|
+
const typedMessage = message;
|
|
156
|
+
if (typedMessage.type === 'function_call_output' &&
|
|
157
|
+
typeof typedMessage.call_id === 'string') {
|
|
158
|
+
return typedMessage.call_id;
|
|
159
|
+
}
|
|
160
|
+
return null;
|
|
161
|
+
}
|
|
162
|
+
getAssistantToolCallId(toolCall) {
|
|
163
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const typedToolCall = toolCall;
|
|
167
|
+
if (typeof typedToolCall.id === 'string') {
|
|
168
|
+
return typedToolCall.id;
|
|
169
|
+
}
|
|
170
|
+
if (typeof typedToolCall.call_id === 'string') {
|
|
171
|
+
return typedToolCall.call_id;
|
|
172
|
+
}
|
|
173
|
+
return null;
|
|
174
|
+
}
|
|
175
|
+
getAssistantToolCallName(toolCall) {
|
|
176
|
+
var _a;
|
|
177
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
178
|
+
return 'unknown';
|
|
179
|
+
}
|
|
180
|
+
const typedToolCall = toolCall;
|
|
181
|
+
if (typeof typedToolCall.name === 'string') {
|
|
182
|
+
return typedToolCall.name;
|
|
183
|
+
}
|
|
184
|
+
if (typeof ((_a = typedToolCall.function) === null || _a === void 0 ? void 0 : _a.name) === 'string') {
|
|
185
|
+
return typedToolCall.function.name;
|
|
186
|
+
}
|
|
187
|
+
return 'unknown';
|
|
188
|
+
}
|
|
189
|
+
getAssistantToolCallArguments(toolCall) {
|
|
190
|
+
var _a;
|
|
191
|
+
if (!toolCall || typeof toolCall !== 'object') {
|
|
192
|
+
return '';
|
|
193
|
+
}
|
|
194
|
+
const typedToolCall = toolCall;
|
|
195
|
+
if (typeof typedToolCall.arguments === 'string') {
|
|
196
|
+
return typedToolCall.arguments;
|
|
197
|
+
}
|
|
198
|
+
if (typeof ((_a = typedToolCall.function) === null || _a === void 0 ? void 0 : _a.arguments) === 'string') {
|
|
199
|
+
return typedToolCall.function.arguments;
|
|
200
|
+
}
|
|
201
|
+
return '';
|
|
202
|
+
}
|
|
203
|
+
buildMissingToolResponseContent(toolName, toolArguments) {
|
|
204
|
+
if (toolName.includes('attempt_completion')) {
|
|
205
|
+
return 'The user is satisfied with the result.';
|
|
206
|
+
}
|
|
207
|
+
return `Tool call "${toolName}" was not executed. This appears to be from a previous incomplete conversation. The tool was called with arguments: ${toolArguments}`;
|
|
208
|
+
}
|
|
101
209
|
}
|
|
102
210
|
exports.ChatHistoryMessageModifier = ChatHistoryMessageModifier;
|
|
@@ -107,12 +107,12 @@ class ChatRecordingModifier extends base_1.BaseMessageModifier {
|
|
|
107
107
|
}
|
|
108
108
|
const timestamp = new Date().toISOString();
|
|
109
109
|
// Record each message
|
|
110
|
-
for (const message of createdMessage.message.
|
|
110
|
+
for (const message of createdMessage.message.input) {
|
|
111
111
|
const record = {
|
|
112
112
|
timestamp,
|
|
113
113
|
messageId: (_a = createdMessage.metadata) === null || _a === void 0 ? void 0 : _a['messageId'],
|
|
114
114
|
threadId: (_b = createdMessage.metadata) === null || _b === void 0 ? void 0 : _b['threadId'],
|
|
115
|
-
role: message.role,
|
|
115
|
+
role: message.role || 'assistant',
|
|
116
116
|
content: typeof message.content === 'string' ? message.content : JSON.stringify(message.content)
|
|
117
117
|
};
|
|
118
118
|
if (this.options.includeMetadata) {
|
|
@@ -129,7 +129,7 @@ class ChatRecordingModifier extends base_1.BaseMessageModifier {
|
|
|
129
129
|
}
|
|
130
130
|
}
|
|
131
131
|
catch (error) {
|
|
132
|
-
console.error('Error recording chat
|
|
132
|
+
console.error('Error recording chat input:', error);
|
|
133
133
|
}
|
|
134
134
|
}
|
|
135
135
|
async writeRecord(record) {
|
|
@@ -45,6 +45,7 @@ class ContextAssemblyModifier extends base_1.BaseMessageModifier {
|
|
|
45
45
|
return createdMessage;
|
|
46
46
|
}
|
|
47
47
|
const contextMessage = {
|
|
48
|
+
type: 'message',
|
|
48
49
|
role: this.options.messageRole,
|
|
49
50
|
content: contextContent,
|
|
50
51
|
};
|
|
@@ -54,7 +55,7 @@ class ContextAssemblyModifier extends base_1.BaseMessageModifier {
|
|
|
54
55
|
return {
|
|
55
56
|
...updatedMessage,
|
|
56
57
|
metadata: {
|
|
57
|
-
...
|
|
58
|
+
...updatedMessage.metadata,
|
|
58
59
|
contextAssemblyAdded: true,
|
|
59
60
|
contextAssemblyStats: {
|
|
60
61
|
totalTokens: context.total_tokens,
|
|
@@ -76,7 +77,7 @@ class ContextAssemblyModifier extends base_1.BaseMessageModifier {
|
|
|
76
77
|
scope_variables: { ...this.options.scopeVariables },
|
|
77
78
|
};
|
|
78
79
|
if (this.options.includeUserInput) {
|
|
79
|
-
const userMessage =
|
|
80
|
+
const userMessage = (0, promptContext_1.getCurrentUserMessage)(createdMessage);
|
|
80
81
|
if (userMessage && typeof userMessage.content === 'string') {
|
|
81
82
|
request.input = userMessage.content;
|
|
82
83
|
}
|
|
@@ -137,7 +138,7 @@ class RuleBasedContextModifier extends base_1.BaseMessageModifier {
|
|
|
137
138
|
var _a;
|
|
138
139
|
try {
|
|
139
140
|
// First evaluate rules to determine which memories to include
|
|
140
|
-
const userMessage =
|
|
141
|
+
const userMessage = (0, promptContext_1.getCurrentUserMessage)(createdMessage);
|
|
141
142
|
const input = userMessage && typeof userMessage.content === 'string' ? userMessage.content : undefined;
|
|
142
143
|
const request = {
|
|
143
144
|
scope_variables: { ...this.options.scopeVariables },
|
|
@@ -181,14 +182,16 @@ class RuleBasedContextModifier extends base_1.BaseMessageModifier {
|
|
|
181
182
|
role: this.options.messageRole,
|
|
182
183
|
content: contextContent,
|
|
183
184
|
};
|
|
184
|
-
const
|
|
185
|
+
const updatedMessage = this.options.messageRole === 'user'
|
|
186
|
+
? (0, promptContext_1.appendUserContextMessage)(createdMessage, contextMessage)
|
|
187
|
+
: (0, promptContext_1.appendSystemContextMessage)(createdMessage, contextMessage);
|
|
185
188
|
return {
|
|
189
|
+
...updatedMessage,
|
|
186
190
|
message: {
|
|
187
|
-
...
|
|
188
|
-
messages,
|
|
191
|
+
...updatedMessage.message,
|
|
189
192
|
},
|
|
190
193
|
metadata: {
|
|
191
|
-
...
|
|
194
|
+
...updatedMessage.metadata,
|
|
192
195
|
ruleBasedContextAdded: true,
|
|
193
196
|
ruleEvaluation: {
|
|
194
197
|
matchedRules: ruleResult.data.matched_rules,
|
|
@@ -241,7 +244,7 @@ class MemoryTypeContextModifier extends base_1.BaseMessageModifier {
|
|
|
241
244
|
additionalVariables = this.resolveVariables(requiredVarsResponse.data, createdMessage);
|
|
242
245
|
}
|
|
243
246
|
}
|
|
244
|
-
const userMessage =
|
|
247
|
+
const userMessage = (0, promptContext_1.getCurrentUserMessage)(createdMessage);
|
|
245
248
|
const input = userMessage && typeof userMessage.content === 'string' ? userMessage.content : undefined;
|
|
246
249
|
const request = {
|
|
247
250
|
scope_variables: { ...this.options.scopeVariables },
|
|
@@ -268,17 +271,20 @@ class MemoryTypeContextModifier extends base_1.BaseMessageModifier {
|
|
|
268
271
|
return createdMessage;
|
|
269
272
|
}
|
|
270
273
|
const contextMessage = {
|
|
274
|
+
type: 'message',
|
|
271
275
|
role: this.options.messageRole,
|
|
272
276
|
content: contextContent,
|
|
273
277
|
};
|
|
274
|
-
const
|
|
278
|
+
const updatedMessage = this.options.messageRole === 'user'
|
|
279
|
+
? (0, promptContext_1.appendUserContextMessage)(createdMessage, contextMessage)
|
|
280
|
+
: (0, promptContext_1.appendSystemContextMessage)(createdMessage, contextMessage);
|
|
275
281
|
return {
|
|
282
|
+
...updatedMessage,
|
|
276
283
|
message: {
|
|
277
|
-
...
|
|
278
|
-
messages,
|
|
284
|
+
...updatedMessage.message,
|
|
279
285
|
},
|
|
280
286
|
metadata: {
|
|
281
|
-
...
|
|
287
|
+
...updatedMessage.metadata,
|
|
282
288
|
memoryTypeContextAdded: true,
|
|
283
289
|
memoryNames: this.options.memoryNames,
|
|
284
290
|
contextAssemblyStats: {
|
|
@@ -24,6 +24,7 @@ export declare class DirectoryContextModifier extends BaseMessageModifier {
|
|
|
24
24
|
* @returns A promise resolving to the formatted folder structure string.
|
|
25
25
|
*/
|
|
26
26
|
private getFolderStructure;
|
|
27
|
+
private isTruncated;
|
|
27
28
|
private readFullStructure;
|
|
28
29
|
/**
|
|
29
30
|
* Reads the directory structure using BFS, respecting maxItems.
|
|
@@ -106,10 +106,11 @@ ${folderStructure}`;
|
|
|
106
106
|
role: 'user', // Note: gemini-cli adds this as user message, not system
|
|
107
107
|
content: directoryContext
|
|
108
108
|
};
|
|
109
|
+
const updatedMessage = (0, promptContext_1.appendUserContextMessage)(createdMessage, contextMessage);
|
|
109
110
|
return Promise.resolve({
|
|
110
|
-
...
|
|
111
|
+
...updatedMessage,
|
|
111
112
|
metadata: {
|
|
112
|
-
...
|
|
113
|
+
...updatedMessage.metadata,
|
|
113
114
|
directoryContextAdded: true,
|
|
114
115
|
workspaceDirectories
|
|
115
116
|
}
|
|
@@ -226,20 +227,8 @@ ${folderStructure}`;
|
|
|
226
227
|
const structureLines = [];
|
|
227
228
|
// Pass true for isRoot for the initial call
|
|
228
229
|
this.formatStructure(structureRoot, '', true, true, structureLines);
|
|
229
|
-
// 3. Build the final output string
|
|
230
|
-
function isTruncated(node) {
|
|
231
|
-
if (node.hasMoreFiles || node.hasMoreSubfolders || node.isIgnored) {
|
|
232
|
-
return true;
|
|
233
|
-
}
|
|
234
|
-
for (const sub of node.subFolders) {
|
|
235
|
-
if (isTruncated(sub)) {
|
|
236
|
-
return true;
|
|
237
|
-
}
|
|
238
|
-
}
|
|
239
|
-
return false;
|
|
240
|
-
}
|
|
241
230
|
let summary = `Showing up to ${mergedOptions.maxItems} items (files + folders).`;
|
|
242
|
-
if (isTruncated(structureRoot)) {
|
|
231
|
+
if (this.isTruncated(structureRoot)) {
|
|
243
232
|
summary += ` Folders or files indicated with ${TRUNCATION_INDICATOR} contain more items not shown, were ignored, or the display limit (${mergedOptions.maxItems} items) was reached.`;
|
|
244
233
|
}
|
|
245
234
|
return `${summary}\n\n${resolvedPath}${path.sep}\n${structureLines.join('\n')}`;
|
|
@@ -249,6 +238,17 @@ ${folderStructure}`;
|
|
|
249
238
|
return `Error processing directory "${resolvedPath}": ${getErrorMessage(error)}`;
|
|
250
239
|
}
|
|
251
240
|
}
|
|
241
|
+
isTruncated(node) {
|
|
242
|
+
if (node.hasMoreFiles || node.hasMoreSubfolders || node.isIgnored) {
|
|
243
|
+
return true;
|
|
244
|
+
}
|
|
245
|
+
for (const subFolder of node.subFolders) {
|
|
246
|
+
if (this.isTruncated(subFolder)) {
|
|
247
|
+
return true;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
return false;
|
|
251
|
+
}
|
|
252
252
|
async readFullStructure(rootPath, options) {
|
|
253
253
|
const rootName = path.basename(rootPath);
|
|
254
254
|
const rootNode = {
|
|
@@ -14,6 +14,7 @@ export declare class EnvironmentContextModifier extends BaseMessageModifier {
|
|
|
14
14
|
constructor(options?: EnvironmentContextOptions);
|
|
15
15
|
modify(originalRequest: FlatUserMessage, createdMessage: ProcessedMessage): Promise<ProcessedMessage>;
|
|
16
16
|
private formatMentionedEnvironments;
|
|
17
|
+
private formatPendingAsyncTasks;
|
|
17
18
|
private readProjectAgentMd;
|
|
18
19
|
private readAgentInstructionFile;
|
|
19
20
|
private generateFullContext;
|
|
@@ -102,6 +102,7 @@ Effective project directory for this task: ${currentDir}
|
|
|
102
102
|
${baseProjectPath ? `CodeBolt base project directory: ${baseProjectPath}
|
|
103
103
|
CodeBolt app-level configuration, providers, plugins, and .codebolt data are loaded from the base project directory. Code changes for the task should still target the effective project directory unless the user explicitly says otherwise.` : ''}
|
|
104
104
|
${directoryListing}
|
|
105
|
+
Async task policy: long-running commands and child threads are tracked as async tasks with execution_mode foreground_scoped, auto_scoped, background_scoped, or background_detached. Scoped tasks are owned by the current agent run and are stopped if the user force-stops the agent. Before completing, use async_task_list to inspect unresolved scoped work and async_task_control to wait, stop, or explicitly detach each running task. background_detached tasks survive user force-stop and natural completion, so detach only intentional background services such as dev servers.
|
|
105
106
|
`.trim();
|
|
106
107
|
// Prepare context parts (same as gemini-cli)
|
|
107
108
|
const contextParts = [environmentContext];
|
|
@@ -119,6 +120,10 @@ ${directoryListing}
|
|
|
119
120
|
if (mentionedEnvironmentContext) {
|
|
120
121
|
contextParts.push(mentionedEnvironmentContext);
|
|
121
122
|
}
|
|
123
|
+
const asyncTaskContext = await this.formatPendingAsyncTasks();
|
|
124
|
+
if (asyncTaskContext) {
|
|
125
|
+
contextParts.push(asyncTaskContext);
|
|
126
|
+
}
|
|
122
127
|
// Add full file context if enabled (just like gemini-cli does)
|
|
123
128
|
if (this.options.enableFullContext) {
|
|
124
129
|
try {
|
|
@@ -137,10 +142,11 @@ ${directoryListing}
|
|
|
137
142
|
role: 'user',
|
|
138
143
|
content: finalContent
|
|
139
144
|
};
|
|
145
|
+
const updatedMessage = (0, promptContext_1.appendUserContextMessage)(createdMessage, contextMessage);
|
|
140
146
|
return Promise.resolve({
|
|
141
|
-
...
|
|
147
|
+
...updatedMessage,
|
|
142
148
|
metadata: {
|
|
143
|
-
...
|
|
149
|
+
...updatedMessage.metadata,
|
|
144
150
|
environmentContextAdded: true,
|
|
145
151
|
projectAgentMdContextAdded: Boolean(agentMdContext),
|
|
146
152
|
fullContextAdded: this.options.enableFullContext,
|
|
@@ -187,6 +193,7 @@ ${directoryListing}
|
|
|
187
193
|
'The user explicitly mentioned these environments with #. Treat them as routing context, not as an automatic active-environment selection.',
|
|
188
194
|
'If the user asks to run, start, delegate, create, or continue work in one of these environments, first inspect this mentioned environment list and choose the matching environment.',
|
|
189
195
|
'Use the thread tool `thread_create_background` to create a background thread in the selected remote environment. Pass the selected environment object in `environment`, set `isRemoteTask: true`, and put the requested work in `userMessage` or `task`.',
|
|
196
|
+
'If the next step depends on that child thread finishing, use `async_task_control` with taskId `thread:<threadId>` and action `wait` before continuing.',
|
|
190
197
|
'If `thread_create_background` is not available in the current tool list, first use the tool search capability, such as `tool_search`, to find the thread/background-thread creation tool and then use the matching tool.',
|
|
191
198
|
'If multiple mentioned environments could match and the user did not specify which one, ask a brief clarification before creating the background thread.',
|
|
192
199
|
'Do not call environment management tools or change the active environment just because an environment was mentioned.',
|
|
@@ -194,6 +201,45 @@ ${directoryListing}
|
|
|
194
201
|
'</mentioned-environments>',
|
|
195
202
|
].join('\n');
|
|
196
203
|
}
|
|
204
|
+
async formatPendingAsyncTasks() {
|
|
205
|
+
try {
|
|
206
|
+
const response = await codeboltjs_1.default.asyncTask.listTasks({
|
|
207
|
+
scope: 'thread',
|
|
208
|
+
});
|
|
209
|
+
const tasks = Array.isArray(response === null || response === void 0 ? void 0 : response.tasks) ? response.tasks : [];
|
|
210
|
+
const unresolvedTasks = tasks.filter((task) => task &&
|
|
211
|
+
task.executionMode !== 'background_detached' &&
|
|
212
|
+
!['completed', 'failed', 'stopped'].includes(task.status));
|
|
213
|
+
const detachedTasks = tasks.filter((task) => task &&
|
|
214
|
+
task.executionMode === 'background_detached' &&
|
|
215
|
+
!['completed', 'failed', 'stopped'].includes(task.status));
|
|
216
|
+
if (unresolvedTasks.length === 0 && detachedTasks.length === 0) {
|
|
217
|
+
return null;
|
|
218
|
+
}
|
|
219
|
+
const sections = [];
|
|
220
|
+
if (unresolvedTasks.length > 0) {
|
|
221
|
+
sections.push([
|
|
222
|
+
'<pending_async_tasks>',
|
|
223
|
+
'These scoped async tasks are still unresolved for this thread. Before completing, choose wait, stop, or detach for each task using async_task_control. Detach only intentional background services that should survive agent stop.',
|
|
224
|
+
JSON.stringify(unresolvedTasks, null, 2),
|
|
225
|
+
'</pending_async_tasks>',
|
|
226
|
+
].join('\n'));
|
|
227
|
+
}
|
|
228
|
+
if (detachedTasks.length > 0) {
|
|
229
|
+
sections.push([
|
|
230
|
+
'<detached_async_tasks>',
|
|
231
|
+
'These background_detached async tasks are still running in the background for this thread. They do not block completion and survive user force-stop. Stop them with async_task_control if they are no longer needed.',
|
|
232
|
+
JSON.stringify(detachedTasks, null, 2),
|
|
233
|
+
'</detached_async_tasks>',
|
|
234
|
+
].join('\n'));
|
|
235
|
+
}
|
|
236
|
+
return sections.join('\n\n');
|
|
237
|
+
}
|
|
238
|
+
catch (error) {
|
|
239
|
+
console.error('Error reading pending async tasks:', error);
|
|
240
|
+
return null;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
197
243
|
async readProjectAgentMd(basePath, title = 'Project Agent Instructions') {
|
|
198
244
|
const instructionFiles = [
|
|
199
245
|
path.join(basePath, '.codebolt', 'agent.md'),
|
|
@@ -34,10 +34,11 @@ class IdeContextModifier extends base_1.BaseMessageModifier {
|
|
|
34
34
|
this.lastSentIdeContext = newIdeContext;
|
|
35
35
|
}
|
|
36
36
|
this.forceFullContext = false;
|
|
37
|
+
const updatedMessage = (0, promptContext_1.appendSystemContextMessage)(createdMessage, ideContextMessage);
|
|
37
38
|
return Promise.resolve({
|
|
38
|
-
...
|
|
39
|
+
...updatedMessage,
|
|
39
40
|
metadata: {
|
|
40
|
-
...
|
|
41
|
+
...updatedMessage.metadata,
|
|
41
42
|
ideContextAdded: true,
|
|
42
43
|
ideContextType: this.forceFullContext ? 'full' : 'incremental'
|
|
43
44
|
}
|