@ebowwa/glm-daemon 0.3.2 → 0.4.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/package.json +5 -5
- package/src/agent.js +166 -0
- package/src/builtin-tools.js +349 -0
- package/src/channels/base.js +509 -0
- package/src/channels/discord.js +374 -0
- package/src/channels/index.js +186 -0
- package/src/channels/telegram.js +395 -0
- package/src/daemon.js +593 -0
- package/src/daemon.ts +188 -1
- package/src/hooks.js +145 -0
- package/src/hooks.ts +3 -0
- package/src/index.js +123 -0
- package/src/memory.js +323 -0
- package/src/state.js +168 -0
- package/src/tools.js +192 -0
- package/src/types.js +21 -0
- package/src/types.ts +62 -0
- package/src/worktree.js +195 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Base Channel - Implements ChannelConnector from @ebowwa/channel-types
|
|
4
|
+
*
|
|
5
|
+
* Abstract base class for all communication channels (Telegram, Discord, etc.)
|
|
6
|
+
* Provides shared functionality for message routing, error handling, and conversation management.
|
|
7
|
+
*/
|
|
8
|
+
var __assign = (this && this.__assign) || function () {
|
|
9
|
+
__assign = Object.assign || function(t) {
|
|
10
|
+
for (var s, i = 1, n = arguments.length; i < n; i++) {
|
|
11
|
+
s = arguments[i];
|
|
12
|
+
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
|
|
13
|
+
t[p] = s[p];
|
|
14
|
+
}
|
|
15
|
+
return t;
|
|
16
|
+
};
|
|
17
|
+
return __assign.apply(this, arguments);
|
|
18
|
+
};
|
|
19
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
20
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
21
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
22
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
23
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
24
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
25
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
26
|
+
});
|
|
27
|
+
};
|
|
28
|
+
var __generator = (this && this.__generator) || function (thisArg, body) {
|
|
29
|
+
var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g = Object.create((typeof Iterator === "function" ? Iterator : Object).prototype);
|
|
30
|
+
return g.next = verb(0), g["throw"] = verb(1), g["return"] = verb(2), typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
|
|
31
|
+
function verb(n) { return function (v) { return step([n, v]); }; }
|
|
32
|
+
function step(op) {
|
|
33
|
+
if (f) throw new TypeError("Generator is already executing.");
|
|
34
|
+
while (g && (g = 0, op[0] && (_ = 0)), _) try {
|
|
35
|
+
if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
|
|
36
|
+
if (y = 0, t) op = [op[0] & 2, t.value];
|
|
37
|
+
switch (op[0]) {
|
|
38
|
+
case 0: case 1: t = op; break;
|
|
39
|
+
case 4: _.label++; return { value: op[1], done: false };
|
|
40
|
+
case 5: _.label++; y = op[1]; op = [0]; continue;
|
|
41
|
+
case 7: op = _.ops.pop(); _.trys.pop(); continue;
|
|
42
|
+
default:
|
|
43
|
+
if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
|
|
44
|
+
if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
|
|
45
|
+
if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
|
|
46
|
+
if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
|
|
47
|
+
if (t[2]) _.ops.pop();
|
|
48
|
+
_.trys.pop(); continue;
|
|
49
|
+
}
|
|
50
|
+
op = body.call(thisArg, _);
|
|
51
|
+
} catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
|
|
52
|
+
if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
var __spreadArray = (this && this.__spreadArray) || function (to, from, pack) {
|
|
56
|
+
if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) {
|
|
57
|
+
if (ar || !(i in from)) {
|
|
58
|
+
if (!ar) ar = Array.prototype.slice.call(from, 0, i);
|
|
59
|
+
ar[i] = from[i];
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return to.concat(ar || Array.prototype.slice.call(from));
|
|
63
|
+
};
|
|
64
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
65
|
+
exports.BaseChannel = void 0;
|
|
66
|
+
var channel_types_1 = require("@ebowwa/channel-types");
|
|
67
|
+
var ai_1 = require("@ebowwa/ai");
|
|
68
|
+
var glm_daemon_1 = require("@ebowwa/glm-daemon");
|
|
69
|
+
// ============================================================
|
|
70
|
+
// ABSTRACT BASE CHANNEL
|
|
71
|
+
// ============================================================
|
|
72
|
+
/**
|
|
73
|
+
* Abstract base class for communication channels.
|
|
74
|
+
* Implements ChannelConnector from @ebowwa/channel-types.
|
|
75
|
+
*/
|
|
76
|
+
var BaseChannel = /** @class */ (function () {
|
|
77
|
+
function BaseChannel(config) {
|
|
78
|
+
this.daemon = null;
|
|
79
|
+
this.activeDaemonTask = null;
|
|
80
|
+
this.conversationHistory = new Map();
|
|
81
|
+
this.connected = false;
|
|
82
|
+
this.config = config;
|
|
83
|
+
this.glmClient = new ai_1.GLMClient();
|
|
84
|
+
}
|
|
85
|
+
// ============================================================
|
|
86
|
+
// ChannelConnector Interface Implementation
|
|
87
|
+
// ============================================================
|
|
88
|
+
/**
|
|
89
|
+
* Start the channel
|
|
90
|
+
*/
|
|
91
|
+
BaseChannel.prototype.start = function () {
|
|
92
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
93
|
+
return __generator(this, function (_a) {
|
|
94
|
+
switch (_a.label) {
|
|
95
|
+
case 0: return [4 /*yield*/, this.startPlatform()];
|
|
96
|
+
case 1:
|
|
97
|
+
_a.sent();
|
|
98
|
+
this.connected = true;
|
|
99
|
+
return [2 /*return*/];
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
});
|
|
103
|
+
};
|
|
104
|
+
/**
|
|
105
|
+
* Stop the channel
|
|
106
|
+
*/
|
|
107
|
+
BaseChannel.prototype.stop = function () {
|
|
108
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
109
|
+
return __generator(this, function (_a) {
|
|
110
|
+
switch (_a.label) {
|
|
111
|
+
case 0: return [4 /*yield*/, this.stopPlatform()];
|
|
112
|
+
case 1:
|
|
113
|
+
_a.sent();
|
|
114
|
+
return [4 /*yield*/, this.cleanup()];
|
|
115
|
+
case 2:
|
|
116
|
+
_a.sent();
|
|
117
|
+
this.connected = false;
|
|
118
|
+
return [2 /*return*/];
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
};
|
|
123
|
+
/**
|
|
124
|
+
* Register message handler (from ChannelConnector interface)
|
|
125
|
+
*/
|
|
126
|
+
BaseChannel.prototype.onMessage = function (handler) {
|
|
127
|
+
this.messageHandler = handler;
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Check if connected
|
|
131
|
+
*/
|
|
132
|
+
BaseChannel.prototype.isConnected = function () {
|
|
133
|
+
return this.connected;
|
|
134
|
+
};
|
|
135
|
+
// ============================================================
|
|
136
|
+
// Message Routing (Core Logic)
|
|
137
|
+
// ============================================================
|
|
138
|
+
/**
|
|
139
|
+
* Route a ChannelMessage through the internal handler or use default routing.
|
|
140
|
+
* This bridges ChannelMessage (from channel-types) to the internal routing logic.
|
|
141
|
+
*/
|
|
142
|
+
BaseChannel.prototype.routeChannelMessage = function (message) {
|
|
143
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
144
|
+
var context, result;
|
|
145
|
+
return __generator(this, function (_a) {
|
|
146
|
+
switch (_a.label) {
|
|
147
|
+
case 0:
|
|
148
|
+
// If external handler is registered, use it
|
|
149
|
+
if (this.messageHandler) {
|
|
150
|
+
return [2 /*return*/, this.messageHandler(message)];
|
|
151
|
+
}
|
|
152
|
+
context = {
|
|
153
|
+
userId: message.sender.id,
|
|
154
|
+
userName: message.sender.displayName || message.sender.username,
|
|
155
|
+
channelId: message.context.groupName || message.channelId.accountId,
|
|
156
|
+
timestamp: message.timestamp,
|
|
157
|
+
};
|
|
158
|
+
return [4 /*yield*/, this.routeMessage(message.text, context)];
|
|
159
|
+
case 1:
|
|
160
|
+
result = _a.sent();
|
|
161
|
+
// Convert RouteResult to ChannelResponse
|
|
162
|
+
return [2 /*return*/, this.resultToResponse(result, message)];
|
|
163
|
+
}
|
|
164
|
+
});
|
|
165
|
+
});
|
|
166
|
+
};
|
|
167
|
+
/**
|
|
168
|
+
* Route a message to appropriate handler (internal routing logic)
|
|
169
|
+
*/
|
|
170
|
+
BaseChannel.prototype.routeMessage = function (content, context) {
|
|
171
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
172
|
+
var classification, _a;
|
|
173
|
+
return __generator(this, function (_b) {
|
|
174
|
+
switch (_b.label) {
|
|
175
|
+
case 0:
|
|
176
|
+
// Update conversation history
|
|
177
|
+
this.addToHistory(context.userId, { role: "user", content: content });
|
|
178
|
+
return [4 /*yield*/, this.classifyMessage(content)];
|
|
179
|
+
case 1:
|
|
180
|
+
classification = _b.sent();
|
|
181
|
+
console.log("[".concat(this.constructor.name, "] Message classified: ").concat(classification.type, " (").concat(classification.confidence, ")"));
|
|
182
|
+
_a = classification.type;
|
|
183
|
+
switch (_a) {
|
|
184
|
+
case "chat": return [3 /*break*/, 2];
|
|
185
|
+
case "task": return [3 /*break*/, 4];
|
|
186
|
+
case "status": return [3 /*break*/, 6];
|
|
187
|
+
}
|
|
188
|
+
return [3 /*break*/, 8];
|
|
189
|
+
case 2: return [4 /*yield*/, this.handleChat(content, context)];
|
|
190
|
+
case 3: return [2 /*return*/, _b.sent()];
|
|
191
|
+
case 4: return [4 /*yield*/, this.handleTask(content, context)];
|
|
192
|
+
case 5: return [2 /*return*/, _b.sent()];
|
|
193
|
+
case 6: return [4 /*yield*/, this.handleStatus()];
|
|
194
|
+
case 7: return [2 /*return*/, _b.sent()];
|
|
195
|
+
case 8: return [4 /*yield*/, this.handleUnknown(content)];
|
|
196
|
+
case 9: return [2 /*return*/, _b.sent()];
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
});
|
|
200
|
+
};
|
|
201
|
+
/**
|
|
202
|
+
* Convert internal RouteResult to ChannelResponse
|
|
203
|
+
*/
|
|
204
|
+
BaseChannel.prototype.resultToResponse = function (result, originalMessage) {
|
|
205
|
+
var replyTo = (0, channel_types_1.createMessageRef)(originalMessage.messageId, originalMessage.channelId);
|
|
206
|
+
var content = {
|
|
207
|
+
text: result.response,
|
|
208
|
+
replyToOriginal: true,
|
|
209
|
+
};
|
|
210
|
+
return {
|
|
211
|
+
content: content,
|
|
212
|
+
replyTo: replyTo,
|
|
213
|
+
isComplete: result.source !== "daemon" || !this.activeDaemonTask,
|
|
214
|
+
metadata: __assign({ source: result.source }, result.metadata),
|
|
215
|
+
};
|
|
216
|
+
};
|
|
217
|
+
// ============================================================
|
|
218
|
+
// Message Classification
|
|
219
|
+
// ============================================================
|
|
220
|
+
/**
|
|
221
|
+
* Classify incoming message
|
|
222
|
+
*/
|
|
223
|
+
BaseChannel.prototype.classifyMessage = function (content) {
|
|
224
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
225
|
+
var lower, taskKeywords, hasTaskKeyword, isComplex, chatKeywords, hasChatKeyword;
|
|
226
|
+
return __generator(this, function (_a) {
|
|
227
|
+
lower = content.toLowerCase();
|
|
228
|
+
// Status queries
|
|
229
|
+
if (lower.includes("status") ||
|
|
230
|
+
lower.includes("progress") ||
|
|
231
|
+
lower.includes("what are you doing")) {
|
|
232
|
+
return [2 /*return*/, { type: "status", confidence: 0.95, suggestedAction: "handle_locally" }];
|
|
233
|
+
}
|
|
234
|
+
taskKeywords = [
|
|
235
|
+
"implement",
|
|
236
|
+
"build",
|
|
237
|
+
"create",
|
|
238
|
+
"fix",
|
|
239
|
+
"add",
|
|
240
|
+
"remove",
|
|
241
|
+
"refactor",
|
|
242
|
+
"deploy",
|
|
243
|
+
"test",
|
|
244
|
+
"debug",
|
|
245
|
+
"optimize",
|
|
246
|
+
"write",
|
|
247
|
+
"generate code",
|
|
248
|
+
"make a",
|
|
249
|
+
"create a",
|
|
250
|
+
"build a",
|
|
251
|
+
"pr for",
|
|
252
|
+
"branch for",
|
|
253
|
+
];
|
|
254
|
+
hasTaskKeyword = taskKeywords.some(function (kw) { return lower.includes(kw); });
|
|
255
|
+
isComplex = content.length > 100 || content.split("\n").length > 2;
|
|
256
|
+
if (hasTaskKeyword && isComplex) {
|
|
257
|
+
return [2 /*return*/, { type: "task", confidence: 0.85, suggestedAction: "delegate_daemon" }];
|
|
258
|
+
}
|
|
259
|
+
chatKeywords = [
|
|
260
|
+
"hello",
|
|
261
|
+
"hi",
|
|
262
|
+
"hey",
|
|
263
|
+
"thanks",
|
|
264
|
+
"help",
|
|
265
|
+
"what can you",
|
|
266
|
+
"how are you",
|
|
267
|
+
"remember",
|
|
268
|
+
"tell me",
|
|
269
|
+
"explain",
|
|
270
|
+
"describe",
|
|
271
|
+
"list",
|
|
272
|
+
];
|
|
273
|
+
hasChatKeyword = chatKeywords.some(function (kw) { return lower.includes(kw); });
|
|
274
|
+
if (hasChatKeyword || !hasTaskKeyword) {
|
|
275
|
+
return [2 /*return*/, { type: "chat", confidence: 0.75, suggestedAction: "handle_locally" }];
|
|
276
|
+
}
|
|
277
|
+
return [2 /*return*/, { type: "unknown", confidence: 0.5, suggestedAction: "handle_locally" }];
|
|
278
|
+
});
|
|
279
|
+
});
|
|
280
|
+
};
|
|
281
|
+
// ============================================================
|
|
282
|
+
// Message Handlers
|
|
283
|
+
// ============================================================
|
|
284
|
+
/**
|
|
285
|
+
* Handle chat messages locally with GLM
|
|
286
|
+
*/
|
|
287
|
+
BaseChannel.prototype.handleChat = function (content, context) {
|
|
288
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
289
|
+
var start, history_1, systemPrompt, messages, response, responseText, error_1;
|
|
290
|
+
var _a, _b, _c;
|
|
291
|
+
return __generator(this, function (_d) {
|
|
292
|
+
switch (_d.label) {
|
|
293
|
+
case 0:
|
|
294
|
+
start = Date.now();
|
|
295
|
+
_d.label = 1;
|
|
296
|
+
case 1:
|
|
297
|
+
_d.trys.push([1, 3, , 4]);
|
|
298
|
+
history_1 = this.conversationHistory.get(context.userId) || [];
|
|
299
|
+
systemPrompt = "You are a helpful AI assistant. You have access to conversation history and user context.\n\nUser: ".concat(context.userName || context.userId, "\nTime: ").concat(context.timestamp.toISOString(), "\n\nBe concise, helpful, and friendly. If the user asks about your capabilities, explain that you can:\n- Answer questions and have conversations\n- Handle coding tasks by delegating to a specialized daemon\n- Check status of ongoing work\n\nFor complex coding tasks, suggest the user phrase it as a task request.");
|
|
300
|
+
messages = __spreadArray(__spreadArray([
|
|
301
|
+
{ role: "system", content: systemPrompt }
|
|
302
|
+
], history_1.slice(-10).map(function (msg) { return ({
|
|
303
|
+
role: msg.role,
|
|
304
|
+
content: msg.content
|
|
305
|
+
}); }), true), [
|
|
306
|
+
{ role: "user", content: content }
|
|
307
|
+
], false);
|
|
308
|
+
return [4 /*yield*/, this.glmClient.chatCompletion(messages, {
|
|
309
|
+
temperature: 0.7,
|
|
310
|
+
maxTokens: 4096
|
|
311
|
+
})];
|
|
312
|
+
case 2:
|
|
313
|
+
response = _d.sent();
|
|
314
|
+
responseText = ((_c = (_b = (_a = response.choices) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.message) === null || _c === void 0 ? void 0 : _c.content) || String(response);
|
|
315
|
+
this.addToHistory(context.userId, { role: "assistant", content: responseText });
|
|
316
|
+
return [2 /*return*/, {
|
|
317
|
+
source: "butler",
|
|
318
|
+
response: responseText,
|
|
319
|
+
metadata: { executionTime: Date.now() - start },
|
|
320
|
+
}];
|
|
321
|
+
case 3:
|
|
322
|
+
error_1 = _d.sent();
|
|
323
|
+
return [2 /*return*/, {
|
|
324
|
+
source: "error",
|
|
325
|
+
response: "Sorry, I encountered an error: ".concat(error_1 instanceof Error ? error_1.message : String(error_1)),
|
|
326
|
+
}];
|
|
327
|
+
case 4: return [2 /*return*/];
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
});
|
|
331
|
+
};
|
|
332
|
+
/**
|
|
333
|
+
* Handle task messages by delegating to GLMDaemon
|
|
334
|
+
*/
|
|
335
|
+
BaseChannel.prototype.handleTask = function (content, context) {
|
|
336
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
337
|
+
var start, status_1, daemonConfig, teamName, status_2, error_2;
|
|
338
|
+
return __generator(this, function (_a) {
|
|
339
|
+
switch (_a.label) {
|
|
340
|
+
case 0:
|
|
341
|
+
start = Date.now();
|
|
342
|
+
if (this.activeDaemonTask && this.daemon) {
|
|
343
|
+
status_1 = this.daemon.getStatus();
|
|
344
|
+
return [2 /*return*/, {
|
|
345
|
+
source: "daemon",
|
|
346
|
+
response: "I'm currently working on: \"".concat(this.activeDaemonTask, "\"\n\nStatus: ").concat((status_1 === null || status_1 === void 0 ? void 0 : status_1.phase) || "unknown", "\n\nPlease wait for this to complete, or use \"stop\" to cancel it."),
|
|
347
|
+
metadata: {
|
|
348
|
+
daemonId: status_1 === null || status_1 === void 0 ? void 0 : status_1.id,
|
|
349
|
+
phase: status_1 === null || status_1 === void 0 ? void 0 : status_1.phase,
|
|
350
|
+
},
|
|
351
|
+
}];
|
|
352
|
+
}
|
|
353
|
+
if (!(content.toLowerCase().includes("stop") && this.daemon)) return [3 /*break*/, 2];
|
|
354
|
+
return [4 /*yield*/, this.daemon.stop()];
|
|
355
|
+
case 1:
|
|
356
|
+
_a.sent();
|
|
357
|
+
this.daemon = null;
|
|
358
|
+
this.activeDaemonTask = null;
|
|
359
|
+
return [2 /*return*/, {
|
|
360
|
+
source: "daemon",
|
|
361
|
+
response: "Task stopped. Ready for new instructions.",
|
|
362
|
+
}];
|
|
363
|
+
case 2:
|
|
364
|
+
_a.trys.push([2, 4, , 5]);
|
|
365
|
+
daemonConfig = {
|
|
366
|
+
cwd: this.config.daemonWorkdir || process.cwd(),
|
|
367
|
+
teamName: "".concat(this.constructor.name.toLowerCase(), "-task-").concat(Date.now()),
|
|
368
|
+
model: "glm-4.7",
|
|
369
|
+
autoCommit: this.config.enableDaemonAutoCommit || false,
|
|
370
|
+
autoPR: this.config.enableDaemonAutoPR || false,
|
|
371
|
+
baseBranch: this.config.daemonBaseBranch || "dev",
|
|
372
|
+
enableWorktree: true,
|
|
373
|
+
completionPromise: "TASK_COMPLETE",
|
|
374
|
+
};
|
|
375
|
+
this.daemon = new glm_daemon_1.GLMDaemon(daemonConfig);
|
|
376
|
+
this.activeDaemonTask = content;
|
|
377
|
+
return [4 /*yield*/, this.daemon.start(content)];
|
|
378
|
+
case 3:
|
|
379
|
+
teamName = _a.sent();
|
|
380
|
+
status_2 = this.daemon.getStatus();
|
|
381
|
+
return [2 /*return*/, {
|
|
382
|
+
source: "daemon",
|
|
383
|
+
response: "Started working on: \"".concat(content, "\"\n\nTeam: ").concat(teamName, "\nPhase: ").concat(status_2.phase, "\n\nI'll work through this using SLAM (Planning \u2192 Executing \u2192 Reviewing \u2192 Fixing \u2192 Committing).\n\nCheck status anytime with \"status\" or \"progress\"."),
|
|
384
|
+
metadata: {
|
|
385
|
+
daemonId: status_2.id,
|
|
386
|
+
phase: status_2.phase,
|
|
387
|
+
executionTime: Date.now() - start,
|
|
388
|
+
},
|
|
389
|
+
}];
|
|
390
|
+
case 4:
|
|
391
|
+
error_2 = _a.sent();
|
|
392
|
+
this.daemon = null;
|
|
393
|
+
this.activeDaemonTask = null;
|
|
394
|
+
return [2 /*return*/, {
|
|
395
|
+
source: "error",
|
|
396
|
+
response: "Failed to start task: ".concat(error_2 instanceof Error ? error_2.message : String(error_2)),
|
|
397
|
+
}];
|
|
398
|
+
case 5: return [2 /*return*/];
|
|
399
|
+
}
|
|
400
|
+
});
|
|
401
|
+
});
|
|
402
|
+
};
|
|
403
|
+
/**
|
|
404
|
+
* Handle status queries
|
|
405
|
+
*/
|
|
406
|
+
BaseChannel.prototype.handleStatus = function () {
|
|
407
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
408
|
+
var parts, status_3;
|
|
409
|
+
return __generator(this, function (_a) {
|
|
410
|
+
parts = [];
|
|
411
|
+
parts.push("**Butler (Chat):** Ready");
|
|
412
|
+
parts.push("- Memory: Active");
|
|
413
|
+
parts.push("- Scheduled tasks: Running");
|
|
414
|
+
if (this.daemon && this.activeDaemonTask) {
|
|
415
|
+
status_3 = this.daemon.getStatus();
|
|
416
|
+
parts.push("\n**Daemon (Task):** Active");
|
|
417
|
+
parts.push("- Task: \"".concat(this.activeDaemonTask, "\""));
|
|
418
|
+
parts.push("- Phase: ".concat(status_3.phase));
|
|
419
|
+
parts.push("- Iteration: ".concat(status_3.iteration));
|
|
420
|
+
parts.push("- Team: ".concat(status_3.id));
|
|
421
|
+
if (status_3.totalSubtasks > 0) {
|
|
422
|
+
parts.push("- Progress: ".concat(status_3.completedSubtasks, "/").concat(status_3.totalSubtasks, " subtasks"));
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
parts.push("\n**Daemon (Task):** Idle");
|
|
427
|
+
}
|
|
428
|
+
parts.push("\n**System:**");
|
|
429
|
+
parts.push("- Active conversations: ".concat(this.conversationHistory.size));
|
|
430
|
+
parts.push("- Uptime: ".concat(process.uptime().toFixed(0), "s"));
|
|
431
|
+
return [2 /*return*/, {
|
|
432
|
+
source: "butler",
|
|
433
|
+
response: parts.join("\n"),
|
|
434
|
+
}];
|
|
435
|
+
});
|
|
436
|
+
});
|
|
437
|
+
};
|
|
438
|
+
/**
|
|
439
|
+
* Handle unknown messages - ask for clarification
|
|
440
|
+
*/
|
|
441
|
+
BaseChannel.prototype.handleUnknown = function (content) {
|
|
442
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
443
|
+
return __generator(this, function (_a) {
|
|
444
|
+
return [2 /*return*/, {
|
|
445
|
+
source: "butler",
|
|
446
|
+
response: "I'm not sure what you want me to do with: \"".concat(content, "\"\n\n**Quick guide:**\n- For questions, chat, or status \u2192 I handle directly\n- For coding tasks, bug fixes, or features \u2192 I'll use the daemon\n- Example: \"implement a new feature\" \u2192 Daemon\n- Example: \"what can you do?\" \u2192 Butler\n\nCould you clarify what you need?"),
|
|
447
|
+
}];
|
|
448
|
+
});
|
|
449
|
+
});
|
|
450
|
+
};
|
|
451
|
+
// ============================================================
|
|
452
|
+
// Utilities
|
|
453
|
+
// ============================================================
|
|
454
|
+
/**
|
|
455
|
+
* Add message to conversation history
|
|
456
|
+
*/
|
|
457
|
+
BaseChannel.prototype.addToHistory = function (userId, message) {
|
|
458
|
+
if (!this.conversationHistory.has(userId)) {
|
|
459
|
+
this.conversationHistory.set(userId, []);
|
|
460
|
+
}
|
|
461
|
+
var history = this.conversationHistory.get(userId);
|
|
462
|
+
history.push(message);
|
|
463
|
+
if (history.length > 20) {
|
|
464
|
+
history.splice(0, history.length - 20);
|
|
465
|
+
}
|
|
466
|
+
};
|
|
467
|
+
/**
|
|
468
|
+
* Get current status
|
|
469
|
+
*/
|
|
470
|
+
BaseChannel.prototype.getStatus = function () {
|
|
471
|
+
var _a, _b;
|
|
472
|
+
return {
|
|
473
|
+
hasActiveDaemon: this.daemon !== null,
|
|
474
|
+
activeTask: this.activeDaemonTask,
|
|
475
|
+
conversationCount: this.conversationHistory.size,
|
|
476
|
+
daemonPhase: ((_b = (_a = this.daemon) === null || _a === void 0 ? void 0 : _a.getStatus()) === null || _b === void 0 ? void 0 : _b.phase) || null,
|
|
477
|
+
};
|
|
478
|
+
};
|
|
479
|
+
/**
|
|
480
|
+
* Cleanup resources
|
|
481
|
+
*/
|
|
482
|
+
BaseChannel.prototype.cleanup = function () {
|
|
483
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
484
|
+
return __generator(this, function (_a) {
|
|
485
|
+
switch (_a.label) {
|
|
486
|
+
case 0:
|
|
487
|
+
if (!this.daemon) return [3 /*break*/, 2];
|
|
488
|
+
return [4 /*yield*/, this.daemon.stop()];
|
|
489
|
+
case 1:
|
|
490
|
+
_a.sent();
|
|
491
|
+
this.daemon = null;
|
|
492
|
+
_a.label = 2;
|
|
493
|
+
case 2:
|
|
494
|
+
this.conversationHistory.clear();
|
|
495
|
+
this.activeDaemonTask = null;
|
|
496
|
+
return [2 /*return*/];
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
});
|
|
500
|
+
};
|
|
501
|
+
/**
|
|
502
|
+
* Helper to create ChannelId for this channel
|
|
503
|
+
*/
|
|
504
|
+
BaseChannel.prototype.createId = function () {
|
|
505
|
+
return (0, channel_types_1.createChannelId)(this.config.platform, this.config.accountId, this.config.instanceId);
|
|
506
|
+
};
|
|
507
|
+
return BaseChannel;
|
|
508
|
+
}());
|
|
509
|
+
exports.BaseChannel = BaseChannel;
|