@openacp/cli 0.2.17 → 0.2.19
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/{chunk-E6BM7RUB.js → chunk-HTXK4NLG.js} +541 -80
- package/dist/chunk-HTXK4NLG.js.map +1 -0
- package/dist/{chunk-QY32F5S7.js → chunk-XOVJLTEC.js} +49 -7
- package/dist/chunk-XOVJLTEC.js.map +1 -0
- package/dist/cli.js +4 -2
- package/dist/cli.js.map +1 -1
- package/dist/index.d.ts +73 -23
- package/dist/index.js +2 -2
- package/dist/{main-OAVE4LUW.js → main-WH6JJXBY.js} +5 -5
- package/dist/{setup-GIUUMBDH.js → setup-FB4DGR6R.js} +12 -3
- package/dist/setup-FB4DGR6R.js.map +1 -0
- package/dist/{tunnel-service-FPRPBPQ5.js → tunnel-service-I6NUMBT4.js} +263 -15
- package/dist/tunnel-service-I6NUMBT4.js.map +1 -0
- package/package.json +1 -1
- package/dist/chunk-E6BM7RUB.js.map +0 -1
- package/dist/chunk-QY32F5S7.js.map +0 -1
- package/dist/setup-GIUUMBDH.js.map +0 -1
- package/dist/tunnel-service-FPRPBPQ5.js.map +0 -1
- /package/dist/{main-OAVE4LUW.js.map → main-WH6JJXBY.js.map} +0 -0
|
@@ -55,7 +55,14 @@ import { ClientSideConnection, ndJsonStream } from "@agentclientprotocol/sdk";
|
|
|
55
55
|
var log = createChildLogger({ module: "agent-instance" });
|
|
56
56
|
function resolveAgentCommand(cmd) {
|
|
57
57
|
const packageDirs = [
|
|
58
|
-
path.resolve(
|
|
58
|
+
path.resolve(
|
|
59
|
+
process.cwd(),
|
|
60
|
+
"node_modules",
|
|
61
|
+
"@zed-industries",
|
|
62
|
+
cmd,
|
|
63
|
+
"dist",
|
|
64
|
+
"index.js"
|
|
65
|
+
),
|
|
59
66
|
path.resolve(process.cwd(), "node_modules", cmd, "dist", "index.js")
|
|
60
67
|
];
|
|
61
68
|
for (const jsPath of packageDirs) {
|
|
@@ -103,19 +110,33 @@ var AgentInstance = class _AgentInstance {
|
|
|
103
110
|
constructor(agentName) {
|
|
104
111
|
this.agentName = agentName;
|
|
105
112
|
}
|
|
106
|
-
static async
|
|
113
|
+
static async spawnSubprocess(agentDef, workingDirectory) {
|
|
107
114
|
const instance = new _AgentInstance(agentDef.name);
|
|
108
115
|
const resolved = resolveAgentCommand(agentDef.command);
|
|
109
|
-
log.debug(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
+
log.debug(
|
|
117
|
+
{
|
|
118
|
+
agentName: agentDef.name,
|
|
119
|
+
command: resolved.command,
|
|
120
|
+
args: resolved.args
|
|
121
|
+
},
|
|
122
|
+
"Resolved agent command"
|
|
123
|
+
);
|
|
124
|
+
instance.child = spawn(
|
|
125
|
+
resolved.command,
|
|
126
|
+
[...resolved.args, ...agentDef.args],
|
|
127
|
+
{
|
|
128
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
129
|
+
cwd: workingDirectory,
|
|
130
|
+
env: { ...process.env, ...agentDef.env }
|
|
131
|
+
}
|
|
132
|
+
);
|
|
116
133
|
await new Promise((resolve, reject) => {
|
|
117
134
|
instance.child.on("error", (err) => {
|
|
118
|
-
reject(
|
|
135
|
+
reject(
|
|
136
|
+
new Error(
|
|
137
|
+
`Failed to spawn agent "${agentDef.name}": ${err.message}. Is "${agentDef.command}" installed?`
|
|
138
|
+
)
|
|
139
|
+
);
|
|
119
140
|
});
|
|
120
141
|
instance.child.on("spawn", () => resolve());
|
|
121
142
|
});
|
|
@@ -125,14 +146,20 @@ var AgentInstance = class _AgentInstance {
|
|
|
125
146
|
});
|
|
126
147
|
const stdinLogger = new Transform({
|
|
127
148
|
transform(chunk, _enc, cb) {
|
|
128
|
-
log.debug(
|
|
149
|
+
log.debug(
|
|
150
|
+
{ direction: "send", raw: chunk.toString().trimEnd() },
|
|
151
|
+
"ACP raw"
|
|
152
|
+
);
|
|
129
153
|
cb(null, chunk);
|
|
130
154
|
}
|
|
131
155
|
});
|
|
132
156
|
stdinLogger.pipe(instance.child.stdin);
|
|
133
157
|
const stdoutLogger = new Transform({
|
|
134
158
|
transform(chunk, _enc, cb) {
|
|
135
|
-
log.debug(
|
|
159
|
+
log.debug(
|
|
160
|
+
{ direction: "recv", raw: chunk.toString().trimEnd() },
|
|
161
|
+
"ACP raw"
|
|
162
|
+
);
|
|
136
163
|
cb(null, chunk);
|
|
137
164
|
}
|
|
138
165
|
});
|
|
@@ -151,26 +178,82 @@ var AgentInstance = class _AgentInstance {
|
|
|
151
178
|
terminal: true
|
|
152
179
|
}
|
|
153
180
|
});
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
181
|
+
return instance;
|
|
182
|
+
}
|
|
183
|
+
setupCrashDetection() {
|
|
184
|
+
this.child.on("exit", (code, signal) => {
|
|
185
|
+
log.info(
|
|
186
|
+
{ sessionId: this.sessionId, exitCode: code, signal },
|
|
187
|
+
"Agent process exited"
|
|
188
|
+
);
|
|
161
189
|
if (code !== 0 && code !== null) {
|
|
162
|
-
const stderr =
|
|
163
|
-
|
|
190
|
+
const stderr = this.stderrCapture.getLastLines();
|
|
191
|
+
this.onSessionUpdate({
|
|
164
192
|
type: "error",
|
|
165
193
|
message: `Agent crashed (exit code ${code})
|
|
166
194
|
${stderr}`
|
|
167
195
|
});
|
|
168
196
|
}
|
|
169
197
|
});
|
|
170
|
-
|
|
171
|
-
log.debug({ sessionId:
|
|
198
|
+
this.connection.closed.then(() => {
|
|
199
|
+
log.debug({ sessionId: this.sessionId }, "ACP connection closed");
|
|
200
|
+
});
|
|
201
|
+
}
|
|
202
|
+
static async spawn(agentDef, workingDirectory) {
|
|
203
|
+
log.debug(
|
|
204
|
+
{ agentName: agentDef.name, command: agentDef.command },
|
|
205
|
+
"Spawning agent"
|
|
206
|
+
);
|
|
207
|
+
const spawnStart = Date.now();
|
|
208
|
+
const instance = await _AgentInstance.spawnSubprocess(
|
|
209
|
+
agentDef,
|
|
210
|
+
workingDirectory
|
|
211
|
+
);
|
|
212
|
+
const response = await instance.connection.newSession({
|
|
213
|
+
cwd: workingDirectory,
|
|
214
|
+
mcpServers: []
|
|
172
215
|
});
|
|
173
|
-
|
|
216
|
+
instance.sessionId = response.sessionId;
|
|
217
|
+
instance.setupCrashDetection();
|
|
218
|
+
log.info(
|
|
219
|
+
{ sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
|
|
220
|
+
"Agent spawn complete"
|
|
221
|
+
);
|
|
222
|
+
return instance;
|
|
223
|
+
}
|
|
224
|
+
static async resume(agentDef, workingDirectory, agentSessionId) {
|
|
225
|
+
log.debug({ agentName: agentDef.name, agentSessionId }, "Resuming agent");
|
|
226
|
+
const spawnStart = Date.now();
|
|
227
|
+
const instance = await _AgentInstance.spawnSubprocess(
|
|
228
|
+
agentDef,
|
|
229
|
+
workingDirectory
|
|
230
|
+
);
|
|
231
|
+
try {
|
|
232
|
+
const response = await instance.connection.unstable_resumeSession({
|
|
233
|
+
sessionId: agentSessionId,
|
|
234
|
+
cwd: workingDirectory
|
|
235
|
+
});
|
|
236
|
+
instance.sessionId = response.sessionId;
|
|
237
|
+
log.info(
|
|
238
|
+
{ sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
|
|
239
|
+
"Agent resume complete"
|
|
240
|
+
);
|
|
241
|
+
} catch (err) {
|
|
242
|
+
log.warn(
|
|
243
|
+
{ err, agentSessionId },
|
|
244
|
+
"Resume failed, falling back to new session"
|
|
245
|
+
);
|
|
246
|
+
const response = await instance.connection.newSession({
|
|
247
|
+
cwd: workingDirectory,
|
|
248
|
+
mcpServers: []
|
|
249
|
+
});
|
|
250
|
+
instance.sessionId = response.sessionId;
|
|
251
|
+
log.info(
|
|
252
|
+
{ sessionId: response.sessionId, durationMs: Date.now() - spawnStart },
|
|
253
|
+
"Agent fallback spawn complete"
|
|
254
|
+
);
|
|
255
|
+
}
|
|
256
|
+
instance.setupCrashDetection();
|
|
174
257
|
return instance;
|
|
175
258
|
}
|
|
176
259
|
// createClient — implemented in Task 6b
|
|
@@ -223,7 +306,10 @@ ${stderr}`
|
|
|
223
306
|
};
|
|
224
307
|
break;
|
|
225
308
|
case "available_commands_update":
|
|
226
|
-
event = {
|
|
309
|
+
event = {
|
|
310
|
+
type: "commands_update",
|
|
311
|
+
commands: update.availableCommands
|
|
312
|
+
};
|
|
227
313
|
break;
|
|
228
314
|
default:
|
|
229
315
|
return;
|
|
@@ -286,8 +372,14 @@ ${stderr}`
|
|
|
286
372
|
state.output = state.output.slice(excess);
|
|
287
373
|
}
|
|
288
374
|
};
|
|
289
|
-
childProcess.stdout?.on(
|
|
290
|
-
|
|
375
|
+
childProcess.stdout?.on(
|
|
376
|
+
"data",
|
|
377
|
+
(chunk) => appendOutput(chunk.toString())
|
|
378
|
+
);
|
|
379
|
+
childProcess.stderr?.on(
|
|
380
|
+
"data",
|
|
381
|
+
(chunk) => appendOutput(chunk.toString())
|
|
382
|
+
);
|
|
291
383
|
childProcess.on("exit", (code, signal) => {
|
|
292
384
|
state.exitStatus = { exitCode: code, signal };
|
|
293
385
|
});
|
|
@@ -301,7 +393,10 @@ ${stderr}`
|
|
|
301
393
|
return {
|
|
302
394
|
output: state.output,
|
|
303
395
|
truncated: false,
|
|
304
|
-
exitStatus: state.exitStatus ? {
|
|
396
|
+
exitStatus: state.exitStatus ? {
|
|
397
|
+
exitCode: state.exitStatus.exitCode,
|
|
398
|
+
signal: state.exitStatus.signal
|
|
399
|
+
} : void 0
|
|
305
400
|
};
|
|
306
401
|
},
|
|
307
402
|
async waitForTerminalExit(params) {
|
|
@@ -310,7 +405,10 @@ ${stderr}`
|
|
|
310
405
|
throw new Error(`Terminal not found: ${params.terminalId}`);
|
|
311
406
|
}
|
|
312
407
|
if (state.exitStatus !== null) {
|
|
313
|
-
return {
|
|
408
|
+
return {
|
|
409
|
+
exitCode: state.exitStatus.exitCode,
|
|
410
|
+
signal: state.exitStatus.signal
|
|
411
|
+
};
|
|
314
412
|
}
|
|
315
413
|
return new Promise((resolve) => {
|
|
316
414
|
state.process.on("exit", (code, signal) => {
|
|
@@ -381,6 +479,11 @@ var AgentManager = class {
|
|
|
381
479
|
if (!agentDef) throw new Error(`Agent "${agentName}" not found in config`);
|
|
382
480
|
return AgentInstance.spawn(agentDef, workingDirectory);
|
|
383
481
|
}
|
|
482
|
+
async resume(agentName, workingDirectory, agentSessionId) {
|
|
483
|
+
const agentDef = this.getAgent(agentName);
|
|
484
|
+
if (!agentDef) throw new Error(`Agent "${agentName}" not found in config`);
|
|
485
|
+
return AgentInstance.resume(agentDef, workingDirectory, agentSessionId);
|
|
486
|
+
}
|
|
384
487
|
};
|
|
385
488
|
|
|
386
489
|
// src/core/session.ts
|
|
@@ -393,6 +496,7 @@ var Session = class {
|
|
|
393
496
|
agentName;
|
|
394
497
|
workingDirectory;
|
|
395
498
|
agentInstance;
|
|
499
|
+
agentSessionId = "";
|
|
396
500
|
status = "initializing";
|
|
397
501
|
name;
|
|
398
502
|
promptQueue = [];
|
|
@@ -426,7 +530,10 @@ var Session = class {
|
|
|
426
530
|
this.log.debug("Prompt execution started");
|
|
427
531
|
try {
|
|
428
532
|
await this.agentInstance.prompt(text);
|
|
429
|
-
this.log.info(
|
|
533
|
+
this.log.info(
|
|
534
|
+
{ durationMs: Date.now() - promptStart },
|
|
535
|
+
"Prompt execution completed"
|
|
536
|
+
);
|
|
430
537
|
if (!this.name) {
|
|
431
538
|
await this.autoName();
|
|
432
539
|
}
|
|
@@ -499,10 +606,34 @@ var Session = class {
|
|
|
499
606
|
// src/core/session-manager.ts
|
|
500
607
|
var SessionManager = class {
|
|
501
608
|
sessions = /* @__PURE__ */ new Map();
|
|
609
|
+
store;
|
|
610
|
+
constructor(store = null) {
|
|
611
|
+
this.store = store;
|
|
612
|
+
}
|
|
502
613
|
async createSession(channelId, agentName, workingDirectory, agentManager) {
|
|
503
614
|
const agentInstance = await agentManager.spawn(agentName, workingDirectory);
|
|
504
|
-
const session = new Session({
|
|
615
|
+
const session = new Session({
|
|
616
|
+
channelId,
|
|
617
|
+
agentName,
|
|
618
|
+
workingDirectory,
|
|
619
|
+
agentInstance
|
|
620
|
+
});
|
|
505
621
|
this.sessions.set(session.id, session);
|
|
622
|
+
session.agentSessionId = session.agentInstance.sessionId;
|
|
623
|
+
if (this.store) {
|
|
624
|
+
await this.store.save({
|
|
625
|
+
sessionId: session.id,
|
|
626
|
+
agentSessionId: session.agentInstance.sessionId,
|
|
627
|
+
agentName: session.agentName,
|
|
628
|
+
workingDir: session.workingDirectory,
|
|
629
|
+
channelId,
|
|
630
|
+
status: session.status,
|
|
631
|
+
createdAt: session.createdAt.toISOString(),
|
|
632
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
633
|
+
name: session.name,
|
|
634
|
+
platform: {}
|
|
635
|
+
});
|
|
636
|
+
}
|
|
506
637
|
return session;
|
|
507
638
|
}
|
|
508
639
|
getSession(sessionId) {
|
|
@@ -516,9 +647,44 @@ var SessionManager = class {
|
|
|
516
647
|
}
|
|
517
648
|
return void 0;
|
|
518
649
|
}
|
|
650
|
+
registerSession(session) {
|
|
651
|
+
this.sessions.set(session.id, session);
|
|
652
|
+
}
|
|
653
|
+
async updateSessionPlatform(sessionId, platform) {
|
|
654
|
+
if (!this.store) return;
|
|
655
|
+
const record = this.store.get(sessionId);
|
|
656
|
+
if (record) {
|
|
657
|
+
await this.store.save({ ...record, platform });
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
async updateSessionActivity(sessionId) {
|
|
661
|
+
if (!this.store) return;
|
|
662
|
+
const record = this.store.get(sessionId);
|
|
663
|
+
if (record) {
|
|
664
|
+
await this.store.save({
|
|
665
|
+
...record,
|
|
666
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
667
|
+
});
|
|
668
|
+
}
|
|
669
|
+
}
|
|
670
|
+
async updateSessionStatus(sessionId, status) {
|
|
671
|
+
if (!this.store) return;
|
|
672
|
+
const record = this.store.get(sessionId);
|
|
673
|
+
if (record) {
|
|
674
|
+
await this.store.save({ ...record, status });
|
|
675
|
+
}
|
|
676
|
+
}
|
|
519
677
|
async cancelSession(sessionId) {
|
|
520
678
|
const session = this.sessions.get(sessionId);
|
|
521
|
-
if (session)
|
|
679
|
+
if (session) {
|
|
680
|
+
await session.cancel();
|
|
681
|
+
if (this.store) {
|
|
682
|
+
const record = this.store.get(sessionId);
|
|
683
|
+
if (record) {
|
|
684
|
+
await this.store.save({ ...record, status: "cancelled" });
|
|
685
|
+
}
|
|
686
|
+
}
|
|
687
|
+
}
|
|
522
688
|
}
|
|
523
689
|
listSessions(channelId) {
|
|
524
690
|
const all = Array.from(this.sessions.values());
|
|
@@ -526,6 +692,14 @@ var SessionManager = class {
|
|
|
526
692
|
return all;
|
|
527
693
|
}
|
|
528
694
|
async destroyAll() {
|
|
695
|
+
if (this.store) {
|
|
696
|
+
for (const session of this.sessions.values()) {
|
|
697
|
+
const record = this.store.get(session.id);
|
|
698
|
+
if (record) {
|
|
699
|
+
await this.store.save({ ...record, status: "finished" });
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
}
|
|
529
703
|
for (const session of this.sessions.values()) {
|
|
530
704
|
await session.destroy();
|
|
531
705
|
}
|
|
@@ -551,6 +725,129 @@ var NotificationManager = class {
|
|
|
551
725
|
}
|
|
552
726
|
};
|
|
553
727
|
|
|
728
|
+
// src/core/core.ts
|
|
729
|
+
import path3 from "path";
|
|
730
|
+
import os from "os";
|
|
731
|
+
|
|
732
|
+
// src/core/session-store.ts
|
|
733
|
+
import fs2 from "fs";
|
|
734
|
+
import path2 from "path";
|
|
735
|
+
var log2 = createChildLogger({ module: "session-store" });
|
|
736
|
+
var DEBOUNCE_MS = 2e3;
|
|
737
|
+
var JsonFileSessionStore = class {
|
|
738
|
+
records = /* @__PURE__ */ new Map();
|
|
739
|
+
filePath;
|
|
740
|
+
ttlDays;
|
|
741
|
+
debounceTimer = null;
|
|
742
|
+
cleanupInterval = null;
|
|
743
|
+
flushHandler = null;
|
|
744
|
+
constructor(filePath, ttlDays) {
|
|
745
|
+
this.filePath = filePath;
|
|
746
|
+
this.ttlDays = ttlDays;
|
|
747
|
+
this.load();
|
|
748
|
+
this.cleanup();
|
|
749
|
+
this.cleanupInterval = setInterval(
|
|
750
|
+
() => this.cleanup(),
|
|
751
|
+
24 * 60 * 60 * 1e3
|
|
752
|
+
);
|
|
753
|
+
this.flushHandler = () => this.flushSync();
|
|
754
|
+
process.on("SIGTERM", this.flushHandler);
|
|
755
|
+
process.on("SIGINT", this.flushHandler);
|
|
756
|
+
process.on("exit", this.flushHandler);
|
|
757
|
+
}
|
|
758
|
+
async save(record) {
|
|
759
|
+
this.records.set(record.sessionId, { ...record });
|
|
760
|
+
this.scheduleDiskWrite();
|
|
761
|
+
}
|
|
762
|
+
get(sessionId) {
|
|
763
|
+
return this.records.get(sessionId);
|
|
764
|
+
}
|
|
765
|
+
findByPlatform(channelId, predicate) {
|
|
766
|
+
for (const record of this.records.values()) {
|
|
767
|
+
if (record.channelId === channelId && predicate(record.platform)) {
|
|
768
|
+
return record;
|
|
769
|
+
}
|
|
770
|
+
}
|
|
771
|
+
return void 0;
|
|
772
|
+
}
|
|
773
|
+
list(channelId) {
|
|
774
|
+
const all = [...this.records.values()];
|
|
775
|
+
if (channelId) return all.filter((r) => r.channelId === channelId);
|
|
776
|
+
return all;
|
|
777
|
+
}
|
|
778
|
+
async remove(sessionId) {
|
|
779
|
+
this.records.delete(sessionId);
|
|
780
|
+
this.scheduleDiskWrite();
|
|
781
|
+
}
|
|
782
|
+
flushSync() {
|
|
783
|
+
if (this.debounceTimer) {
|
|
784
|
+
clearTimeout(this.debounceTimer);
|
|
785
|
+
this.debounceTimer = null;
|
|
786
|
+
}
|
|
787
|
+
const data = {
|
|
788
|
+
version: 1,
|
|
789
|
+
sessions: Object.fromEntries(this.records)
|
|
790
|
+
};
|
|
791
|
+
const dir = path2.dirname(this.filePath);
|
|
792
|
+
if (!fs2.existsSync(dir)) fs2.mkdirSync(dir, { recursive: true });
|
|
793
|
+
fs2.writeFileSync(this.filePath, JSON.stringify(data, null, 2));
|
|
794
|
+
}
|
|
795
|
+
destroy() {
|
|
796
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
797
|
+
if (this.cleanupInterval) clearInterval(this.cleanupInterval);
|
|
798
|
+
if (this.flushHandler) {
|
|
799
|
+
process.removeListener("SIGTERM", this.flushHandler);
|
|
800
|
+
process.removeListener("SIGINT", this.flushHandler);
|
|
801
|
+
process.removeListener("exit", this.flushHandler);
|
|
802
|
+
this.flushHandler = null;
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
load() {
|
|
806
|
+
if (!fs2.existsSync(this.filePath)) return;
|
|
807
|
+
try {
|
|
808
|
+
const raw = JSON.parse(
|
|
809
|
+
fs2.readFileSync(this.filePath, "utf-8")
|
|
810
|
+
);
|
|
811
|
+
if (raw.version !== 1) {
|
|
812
|
+
log2.warn(
|
|
813
|
+
{ version: raw.version },
|
|
814
|
+
"Unknown session store version, skipping load"
|
|
815
|
+
);
|
|
816
|
+
return;
|
|
817
|
+
}
|
|
818
|
+
for (const [id, record] of Object.entries(raw.sessions)) {
|
|
819
|
+
this.records.set(id, record);
|
|
820
|
+
}
|
|
821
|
+
log2.info({ count: this.records.size }, "Loaded session records");
|
|
822
|
+
} catch (err) {
|
|
823
|
+
log2.error({ err }, "Failed to load session store");
|
|
824
|
+
}
|
|
825
|
+
}
|
|
826
|
+
cleanup() {
|
|
827
|
+
const cutoff = Date.now() - this.ttlDays * 24 * 60 * 60 * 1e3;
|
|
828
|
+
let removed = 0;
|
|
829
|
+
for (const [id, record] of this.records) {
|
|
830
|
+
if (record.status === "active" || record.status === "initializing")
|
|
831
|
+
continue;
|
|
832
|
+
const lastActive = new Date(record.lastActiveAt).getTime();
|
|
833
|
+
if (lastActive < cutoff) {
|
|
834
|
+
this.records.delete(id);
|
|
835
|
+
removed++;
|
|
836
|
+
}
|
|
837
|
+
}
|
|
838
|
+
if (removed > 0) {
|
|
839
|
+
log2.info({ removed }, "Cleaned up expired session records");
|
|
840
|
+
this.scheduleDiskWrite();
|
|
841
|
+
}
|
|
842
|
+
}
|
|
843
|
+
scheduleDiskWrite() {
|
|
844
|
+
if (this.debounceTimer) clearTimeout(this.debounceTimer);
|
|
845
|
+
this.debounceTimer = setTimeout(() => {
|
|
846
|
+
this.flushSync();
|
|
847
|
+
}, DEBOUNCE_MS);
|
|
848
|
+
}
|
|
849
|
+
};
|
|
850
|
+
|
|
554
851
|
// src/tunnel/extract-file-info.ts
|
|
555
852
|
function extractFileInfo(name, kind, content) {
|
|
556
853
|
if (!content) return null;
|
|
@@ -621,7 +918,7 @@ function parseContent(content) {
|
|
|
621
918
|
}
|
|
622
919
|
|
|
623
920
|
// src/core/core.ts
|
|
624
|
-
var
|
|
921
|
+
var log3 = createChildLogger({ module: "core" });
|
|
625
922
|
var OpenACPCore = class {
|
|
626
923
|
configManager;
|
|
627
924
|
agentManager;
|
|
@@ -629,11 +926,18 @@ var OpenACPCore = class {
|
|
|
629
926
|
notificationManager;
|
|
630
927
|
adapters = /* @__PURE__ */ new Map();
|
|
631
928
|
tunnelService;
|
|
929
|
+
sessionStore = null;
|
|
930
|
+
resumeLocks = /* @__PURE__ */ new Map();
|
|
632
931
|
constructor(configManager) {
|
|
633
932
|
this.configManager = configManager;
|
|
634
933
|
const config = configManager.get();
|
|
635
934
|
this.agentManager = new AgentManager(config);
|
|
636
|
-
|
|
935
|
+
const storePath = path3.join(os.homedir(), ".openacp", "sessions.json");
|
|
936
|
+
this.sessionStore = new JsonFileSessionStore(
|
|
937
|
+
storePath,
|
|
938
|
+
config.sessionStore.ttlDays
|
|
939
|
+
);
|
|
940
|
+
this.sessionManager = new SessionManager(this.sessionStore);
|
|
637
941
|
this.notificationManager = new NotificationManager(this.adapters);
|
|
638
942
|
}
|
|
639
943
|
registerAdapter(name, adapter) {
|
|
@@ -661,16 +965,33 @@ var OpenACPCore = class {
|
|
|
661
965
|
// --- Message Routing ---
|
|
662
966
|
async handleMessage(message) {
|
|
663
967
|
const config = this.configManager.get();
|
|
664
|
-
|
|
968
|
+
log3.debug(
|
|
969
|
+
{
|
|
970
|
+
channelId: message.channelId,
|
|
971
|
+
threadId: message.threadId,
|
|
972
|
+
userId: message.userId
|
|
973
|
+
},
|
|
974
|
+
"Incoming message"
|
|
975
|
+
);
|
|
665
976
|
if (config.security.allowedUserIds.length > 0) {
|
|
666
977
|
if (!config.security.allowedUserIds.includes(message.userId)) {
|
|
667
|
-
|
|
978
|
+
log3.warn(
|
|
979
|
+
{ userId: message.userId },
|
|
980
|
+
"Rejected message from unauthorized user"
|
|
981
|
+
);
|
|
668
982
|
return;
|
|
669
983
|
}
|
|
670
984
|
}
|
|
671
985
|
const activeSessions = this.sessionManager.listSessions().filter((s) => s.status === "active" || s.status === "initializing");
|
|
672
986
|
if (activeSessions.length >= config.security.maxConcurrentSessions) {
|
|
673
|
-
|
|
987
|
+
log3.warn(
|
|
988
|
+
{
|
|
989
|
+
userId: message.userId,
|
|
990
|
+
currentCount: activeSessions.length,
|
|
991
|
+
max: config.security.maxConcurrentSessions
|
|
992
|
+
},
|
|
993
|
+
"Session limit reached"
|
|
994
|
+
);
|
|
674
995
|
const adapter = this.adapters.get(message.channelId);
|
|
675
996
|
if (adapter) {
|
|
676
997
|
await adapter.sendMessage("system", {
|
|
@@ -680,14 +1001,21 @@ var OpenACPCore = class {
|
|
|
680
1001
|
}
|
|
681
1002
|
return;
|
|
682
1003
|
}
|
|
683
|
-
|
|
1004
|
+
let session = this.sessionManager.getSessionByThread(
|
|
1005
|
+
message.channelId,
|
|
1006
|
+
message.threadId
|
|
1007
|
+
);
|
|
1008
|
+
if (!session) {
|
|
1009
|
+
session = await this.lazyResume(message) ?? void 0;
|
|
1010
|
+
}
|
|
684
1011
|
if (!session) return;
|
|
1012
|
+
this.sessionManager.updateSessionActivity(session.id);
|
|
685
1013
|
await session.enqueuePrompt(message.text);
|
|
686
1014
|
}
|
|
687
1015
|
async handleNewSession(channelId, agentName, workspacePath) {
|
|
688
1016
|
const config = this.configManager.get();
|
|
689
1017
|
const resolvedAgent = agentName || config.defaultAgent;
|
|
690
|
-
|
|
1018
|
+
log3.info({ channelId, agentName: resolvedAgent }, "New session request");
|
|
691
1019
|
const resolvedWorkspace = this.configManager.resolveWorkspace(
|
|
692
1020
|
workspacePath || config.agents[resolvedAgent]?.workingDirectory
|
|
693
1021
|
);
|
|
@@ -704,7 +1032,10 @@ var OpenACPCore = class {
|
|
|
704
1032
|
return session;
|
|
705
1033
|
}
|
|
706
1034
|
async handleNewChat(channelId, currentThreadId) {
|
|
707
|
-
const currentSession = this.sessionManager.getSessionByThread(
|
|
1035
|
+
const currentSession = this.sessionManager.getSessionByThread(
|
|
1036
|
+
channelId,
|
|
1037
|
+
currentThreadId
|
|
1038
|
+
);
|
|
708
1039
|
if (!currentSession) return null;
|
|
709
1040
|
return this.handleNewSession(
|
|
710
1041
|
channelId,
|
|
@@ -712,6 +1043,63 @@ var OpenACPCore = class {
|
|
|
712
1043
|
currentSession.workingDirectory
|
|
713
1044
|
);
|
|
714
1045
|
}
|
|
1046
|
+
// --- Lazy Resume ---
|
|
1047
|
+
async lazyResume(message) {
|
|
1048
|
+
const store = this.sessionStore;
|
|
1049
|
+
if (!store) return null;
|
|
1050
|
+
const lockKey = `${message.channelId}:${message.threadId}`;
|
|
1051
|
+
const existing = this.resumeLocks.get(lockKey);
|
|
1052
|
+
if (existing) return existing;
|
|
1053
|
+
const record = store.findByPlatform(
|
|
1054
|
+
message.channelId,
|
|
1055
|
+
(p) => String(p.topicId) === message.threadId
|
|
1056
|
+
);
|
|
1057
|
+
if (!record) return null;
|
|
1058
|
+
if (record.status === "cancelled" || record.status === "error") return null;
|
|
1059
|
+
const resumePromise = (async () => {
|
|
1060
|
+
try {
|
|
1061
|
+
const agentInstance = await this.agentManager.resume(
|
|
1062
|
+
record.agentName,
|
|
1063
|
+
record.workingDir,
|
|
1064
|
+
record.agentSessionId
|
|
1065
|
+
);
|
|
1066
|
+
const session = new Session({
|
|
1067
|
+
id: record.sessionId,
|
|
1068
|
+
channelId: record.channelId,
|
|
1069
|
+
agentName: record.agentName,
|
|
1070
|
+
workingDirectory: record.workingDir,
|
|
1071
|
+
agentInstance
|
|
1072
|
+
});
|
|
1073
|
+
session.threadId = message.threadId;
|
|
1074
|
+
session.agentSessionId = agentInstance.sessionId;
|
|
1075
|
+
session.status = "active";
|
|
1076
|
+
session.name = record.name;
|
|
1077
|
+
this.sessionManager.registerSession(session);
|
|
1078
|
+
const adapter = this.adapters.get(message.channelId);
|
|
1079
|
+
if (adapter) {
|
|
1080
|
+
this.wireSessionEvents(session, adapter);
|
|
1081
|
+
}
|
|
1082
|
+
await store.save({
|
|
1083
|
+
...record,
|
|
1084
|
+
agentSessionId: agentInstance.sessionId,
|
|
1085
|
+
status: "active",
|
|
1086
|
+
lastActiveAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1087
|
+
});
|
|
1088
|
+
log3.info(
|
|
1089
|
+
{ sessionId: session.id, threadId: message.threadId },
|
|
1090
|
+
"Lazy resume successful"
|
|
1091
|
+
);
|
|
1092
|
+
return session;
|
|
1093
|
+
} catch (err) {
|
|
1094
|
+
log3.error({ err, record }, "Lazy resume failed");
|
|
1095
|
+
return null;
|
|
1096
|
+
} finally {
|
|
1097
|
+
this.resumeLocks.delete(lockKey);
|
|
1098
|
+
}
|
|
1099
|
+
})();
|
|
1100
|
+
this.resumeLocks.set(lockKey, resumePromise);
|
|
1101
|
+
return resumePromise;
|
|
1102
|
+
}
|
|
715
1103
|
// --- Event Wiring ---
|
|
716
1104
|
toOutgoingMessage(event, session) {
|
|
717
1105
|
switch (event.type) {
|
|
@@ -720,19 +1108,37 @@ var OpenACPCore = class {
|
|
|
720
1108
|
case "thought":
|
|
721
1109
|
return { type: "thought", text: event.content };
|
|
722
1110
|
case "tool_call": {
|
|
723
|
-
const metadata = {
|
|
1111
|
+
const metadata = {
|
|
1112
|
+
id: event.id,
|
|
1113
|
+
kind: event.kind,
|
|
1114
|
+
status: event.status,
|
|
1115
|
+
content: event.content,
|
|
1116
|
+
locations: event.locations
|
|
1117
|
+
};
|
|
724
1118
|
this.enrichWithViewerLinks(event, metadata, session);
|
|
725
1119
|
return { type: "tool_call", text: event.name, metadata };
|
|
726
1120
|
}
|
|
727
1121
|
case "tool_update": {
|
|
728
|
-
const metadata = {
|
|
1122
|
+
const metadata = {
|
|
1123
|
+
id: event.id,
|
|
1124
|
+
status: event.status,
|
|
1125
|
+
content: event.content
|
|
1126
|
+
};
|
|
729
1127
|
this.enrichWithViewerLinks(event, metadata, session);
|
|
730
1128
|
return { type: "tool_update", text: "", metadata };
|
|
731
1129
|
}
|
|
732
1130
|
case "plan":
|
|
733
1131
|
return { type: "plan", text: "", metadata: { entries: event.entries } };
|
|
734
1132
|
case "usage":
|
|
735
|
-
return {
|
|
1133
|
+
return {
|
|
1134
|
+
type: "usage",
|
|
1135
|
+
text: "",
|
|
1136
|
+
metadata: {
|
|
1137
|
+
tokensUsed: event.tokensUsed,
|
|
1138
|
+
contextSize: event.contextSize,
|
|
1139
|
+
cost: event.cost
|
|
1140
|
+
}
|
|
1141
|
+
};
|
|
736
1142
|
default:
|
|
737
1143
|
return { type: "text", text: "" };
|
|
738
1144
|
}
|
|
@@ -741,17 +1147,39 @@ var OpenACPCore = class {
|
|
|
741
1147
|
if (!this.tunnelService || !session) return;
|
|
742
1148
|
const name = "name" in event ? event.name || "" : "";
|
|
743
1149
|
const kind = "kind" in event ? event.kind : void 0;
|
|
744
|
-
|
|
1150
|
+
log3.debug(
|
|
1151
|
+
{ name, kind, status: event.status, hasContent: !!event.content },
|
|
1152
|
+
"enrichWithViewerLinks: inspecting event"
|
|
1153
|
+
);
|
|
745
1154
|
const fileInfo = extractFileInfo(name, kind, event.content);
|
|
746
1155
|
if (!fileInfo) return;
|
|
747
|
-
|
|
1156
|
+
log3.info(
|
|
1157
|
+
{
|
|
1158
|
+
name,
|
|
1159
|
+
kind,
|
|
1160
|
+
filePath: fileInfo.filePath,
|
|
1161
|
+
hasOldContent: !!fileInfo.oldContent
|
|
1162
|
+
},
|
|
1163
|
+
"enrichWithViewerLinks: extracted file info"
|
|
1164
|
+
);
|
|
748
1165
|
const store = this.tunnelService.getStore();
|
|
749
1166
|
const viewerLinks = {};
|
|
750
1167
|
if (fileInfo.oldContent) {
|
|
751
|
-
const id2 = store.storeDiff(
|
|
1168
|
+
const id2 = store.storeDiff(
|
|
1169
|
+
session.id,
|
|
1170
|
+
fileInfo.filePath,
|
|
1171
|
+
fileInfo.oldContent,
|
|
1172
|
+
fileInfo.content,
|
|
1173
|
+
session.workingDirectory
|
|
1174
|
+
);
|
|
752
1175
|
if (id2) viewerLinks.diff = this.tunnelService.diffUrl(id2);
|
|
753
1176
|
}
|
|
754
|
-
const id = store.storeFile(
|
|
1177
|
+
const id = store.storeFile(
|
|
1178
|
+
session.id,
|
|
1179
|
+
fileInfo.filePath,
|
|
1180
|
+
fileInfo.content,
|
|
1181
|
+
session.workingDirectory
|
|
1182
|
+
);
|
|
755
1183
|
if (id) viewerLinks.file = this.tunnelService.fileUrl(id);
|
|
756
1184
|
if (Object.keys(viewerLinks).length > 0) {
|
|
757
1185
|
metadata.viewerLinks = viewerLinks;
|
|
@@ -768,12 +1196,19 @@ var OpenACPCore = class {
|
|
|
768
1196
|
case "tool_update":
|
|
769
1197
|
case "plan":
|
|
770
1198
|
case "usage":
|
|
771
|
-
adapter.sendMessage(
|
|
1199
|
+
adapter.sendMessage(
|
|
1200
|
+
session.id,
|
|
1201
|
+
this.toOutgoingMessage(event, session)
|
|
1202
|
+
);
|
|
772
1203
|
break;
|
|
773
1204
|
case "session_end":
|
|
774
1205
|
session.status = "finished";
|
|
1206
|
+
this.sessionManager.updateSessionStatus(session.id, "finished");
|
|
775
1207
|
adapter.cleanupSkillCommands(session.id);
|
|
776
|
-
adapter.sendMessage(session.id, {
|
|
1208
|
+
adapter.sendMessage(session.id, {
|
|
1209
|
+
type: "session_end",
|
|
1210
|
+
text: `Done (${event.reason})`
|
|
1211
|
+
});
|
|
777
1212
|
this.notificationManager.notify(session.channelId, {
|
|
778
1213
|
sessionId: session.id,
|
|
779
1214
|
sessionName: session.name,
|
|
@@ -782,8 +1217,12 @@ var OpenACPCore = class {
|
|
|
782
1217
|
});
|
|
783
1218
|
break;
|
|
784
1219
|
case "error":
|
|
1220
|
+
this.sessionManager.updateSessionStatus(session.id, "error");
|
|
785
1221
|
adapter.cleanupSkillCommands(session.id);
|
|
786
|
-
adapter.sendMessage(session.id, {
|
|
1222
|
+
adapter.sendMessage(session.id, {
|
|
1223
|
+
type: "error",
|
|
1224
|
+
text: event.message
|
|
1225
|
+
});
|
|
787
1226
|
this.notificationManager.notify(session.channelId, {
|
|
788
1227
|
sessionId: session.id,
|
|
789
1228
|
sessionName: session.name,
|
|
@@ -792,7 +1231,7 @@ var OpenACPCore = class {
|
|
|
792
1231
|
});
|
|
793
1232
|
break;
|
|
794
1233
|
case "commands_update":
|
|
795
|
-
|
|
1234
|
+
log3.debug({ commands: event.commands }, "Commands available");
|
|
796
1235
|
adapter.sendSkillCommands(session.id, event.commands);
|
|
797
1236
|
break;
|
|
798
1237
|
}
|
|
@@ -1106,7 +1545,7 @@ function buildDeepLink(chatId, messageId) {
|
|
|
1106
1545
|
// src/adapters/telegram/commands.ts
|
|
1107
1546
|
import { InlineKeyboard } from "grammy";
|
|
1108
1547
|
import { nanoid as nanoid2 } from "nanoid";
|
|
1109
|
-
var
|
|
1548
|
+
var log5 = createChildLogger({ module: "telegram-commands" });
|
|
1110
1549
|
function setupCommands(bot, core, chatId) {
|
|
1111
1550
|
bot.command("new", (ctx) => handleNew(ctx, core, chatId));
|
|
1112
1551
|
bot.command("new_chat", (ctx) => handleNewChat(ctx, core, chatId));
|
|
@@ -1161,7 +1600,7 @@ async function handleNew(ctx, core, chatId) {
|
|
|
1161
1600
|
const args = matchStr.split(" ").filter(Boolean);
|
|
1162
1601
|
const agentName = args[0];
|
|
1163
1602
|
const workspace = args[1];
|
|
1164
|
-
|
|
1603
|
+
log5.info({ userId: ctx.from?.id, agentName }, "New session command");
|
|
1165
1604
|
let threadId;
|
|
1166
1605
|
try {
|
|
1167
1606
|
const topicName = `\u{1F504} New Session`;
|
|
@@ -1176,6 +1615,9 @@ async function handleNew(ctx, core, chatId) {
|
|
|
1176
1615
|
workspace
|
|
1177
1616
|
);
|
|
1178
1617
|
session.threadId = String(threadId);
|
|
1618
|
+
await core.sessionManager.updateSessionPlatform(session.id, {
|
|
1619
|
+
topicId: threadId
|
|
1620
|
+
});
|
|
1179
1621
|
const finalName = `\u{1F504} ${session.agentName} \u2014 New Session`;
|
|
1180
1622
|
try {
|
|
1181
1623
|
await ctx.api.editForumTopic(chatId, threadId, { name: finalName });
|
|
@@ -1191,7 +1633,7 @@ async function handleNew(ctx, core, chatId) {
|
|
|
1191
1633
|
parse_mode: "HTML"
|
|
1192
1634
|
}
|
|
1193
1635
|
);
|
|
1194
|
-
session.warmup().catch((err) =>
|
|
1636
|
+
session.warmup().catch((err) => log5.error({ err }, "Warm-up error"));
|
|
1195
1637
|
} catch (err) {
|
|
1196
1638
|
if (threadId) {
|
|
1197
1639
|
try {
|
|
@@ -1231,6 +1673,9 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
1231
1673
|
parse_mode: "HTML"
|
|
1232
1674
|
});
|
|
1233
1675
|
session.threadId = String(newThreadId);
|
|
1676
|
+
await core.sessionManager.updateSessionPlatform(session.id, {
|
|
1677
|
+
topicId: newThreadId
|
|
1678
|
+
});
|
|
1234
1679
|
await ctx.api.sendMessage(
|
|
1235
1680
|
chatId,
|
|
1236
1681
|
`\u2705 New chat (same agent & workspace)
|
|
@@ -1241,7 +1686,7 @@ async function handleNewChat(ctx, core, chatId) {
|
|
|
1241
1686
|
parse_mode: "HTML"
|
|
1242
1687
|
}
|
|
1243
1688
|
);
|
|
1244
|
-
session.warmup().catch((err) =>
|
|
1689
|
+
session.warmup().catch((err) => log5.error({ err }, "Warm-up error"));
|
|
1245
1690
|
} catch (err) {
|
|
1246
1691
|
const message = err instanceof Error ? err.message : String(err);
|
|
1247
1692
|
await ctx.reply(`\u274C ${escapeHtml(message)}`, { parse_mode: "HTML" });
|
|
@@ -1255,7 +1700,7 @@ async function handleCancel(ctx, core) {
|
|
|
1255
1700
|
String(threadId)
|
|
1256
1701
|
);
|
|
1257
1702
|
if (session) {
|
|
1258
|
-
|
|
1703
|
+
log5.info({ sessionId: session.id }, "Cancel session command");
|
|
1259
1704
|
await session.cancel();
|
|
1260
1705
|
await ctx.reply("\u26D4 Session cancelled.", { parse_mode: "HTML" });
|
|
1261
1706
|
}
|
|
@@ -1376,7 +1821,7 @@ var STATIC_COMMANDS = [
|
|
|
1376
1821
|
// src/adapters/telegram/permissions.ts
|
|
1377
1822
|
import { InlineKeyboard as InlineKeyboard2 } from "grammy";
|
|
1378
1823
|
import { nanoid as nanoid3 } from "nanoid";
|
|
1379
|
-
var
|
|
1824
|
+
var log6 = createChildLogger({ module: "telegram-permissions" });
|
|
1380
1825
|
var PermissionHandler = class {
|
|
1381
1826
|
constructor(bot, chatId, getSession, sendNotification) {
|
|
1382
1827
|
this.bot = bot;
|
|
@@ -1436,7 +1881,7 @@ ${escapeHtml(request.description)}`,
|
|
|
1436
1881
|
}
|
|
1437
1882
|
const session = this.getSession(pending.sessionId);
|
|
1438
1883
|
const isAllow = pending.options.find((o) => o.id === optionId)?.isAllow ?? false;
|
|
1439
|
-
|
|
1884
|
+
log6.info({ requestId: pending.requestId, optionId, isAllow }, "Permission responded");
|
|
1440
1885
|
if (session?.pendingPermission?.requestId === pending.requestId) {
|
|
1441
1886
|
session.pendingPermission.resolve(optionId);
|
|
1442
1887
|
session.pendingPermission = void 0;
|
|
@@ -1503,7 +1948,7 @@ function redirectToAssistant(chatId, assistantTopicId) {
|
|
|
1503
1948
|
}
|
|
1504
1949
|
|
|
1505
1950
|
// src/adapters/telegram/adapter.ts
|
|
1506
|
-
var
|
|
1951
|
+
var log7 = createChildLogger({ module: "telegram" });
|
|
1507
1952
|
var TelegramAdapter = class extends ChannelAdapter {
|
|
1508
1953
|
bot;
|
|
1509
1954
|
telegramConfig;
|
|
@@ -1521,10 +1966,10 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
1521
1966
|
this.telegramConfig = config;
|
|
1522
1967
|
}
|
|
1523
1968
|
async start() {
|
|
1524
|
-
this.bot = new Bot(this.telegramConfig.botToken);
|
|
1969
|
+
this.bot = new Bot(this.telegramConfig.botToken, { client: { fetch } });
|
|
1525
1970
|
this.bot.catch((err) => {
|
|
1526
1971
|
const rootCause = err.error instanceof Error ? err.error : err;
|
|
1527
|
-
|
|
1972
|
+
log7.error({ err: rootCause }, "Telegram bot error");
|
|
1528
1973
|
});
|
|
1529
1974
|
this.bot.api.config.use((prev, method, payload, signal) => {
|
|
1530
1975
|
if (method === "getUpdates") {
|
|
@@ -1577,7 +2022,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
1577
2022
|
this.setupRoutes();
|
|
1578
2023
|
this.bot.start({
|
|
1579
2024
|
allowed_updates: ["message", "callback_query"],
|
|
1580
|
-
onStart: () =>
|
|
2025
|
+
onStart: () => log7.info(
|
|
1581
2026
|
{ chatId: this.telegramConfig.chatId },
|
|
1582
2027
|
"Telegram bot started"
|
|
1583
2028
|
)
|
|
@@ -1589,7 +2034,7 @@ var TelegramAdapter = class extends ChannelAdapter {
|
|
|
1589
2034
|
this.assistantTopicId
|
|
1590
2035
|
);
|
|
1591
2036
|
} catch (err) {
|
|
1592
|
-
|
|
2037
|
+
log7.error({ err }, "Failed to spawn assistant");
|
|
1593
2038
|
}
|
|
1594
2039
|
try {
|
|
1595
2040
|
const config = this.core.configManager.get();
|
|
@@ -1610,7 +2055,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1610
2055
|
reply_markup: buildMenuKeyboard()
|
|
1611
2056
|
});
|
|
1612
2057
|
} catch (err) {
|
|
1613
|
-
|
|
2058
|
+
log7.warn({ err }, "Failed to send welcome message");
|
|
1614
2059
|
}
|
|
1615
2060
|
}
|
|
1616
2061
|
async stop() {
|
|
@@ -1618,7 +2063,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1618
2063
|
await this.assistantSession.destroy();
|
|
1619
2064
|
}
|
|
1620
2065
|
await this.bot.stop();
|
|
1621
|
-
|
|
2066
|
+
log7.info("Telegram bot stopped");
|
|
1622
2067
|
}
|
|
1623
2068
|
setupRoutes() {
|
|
1624
2069
|
this.bot.on("message:text", async (ctx) => {
|
|
@@ -1636,7 +2081,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1636
2081
|
ctx.replyWithChatAction("typing").catch(() => {
|
|
1637
2082
|
});
|
|
1638
2083
|
handleAssistantMessage(this.assistantSession, ctx.message.text).catch(
|
|
1639
|
-
(err) =>
|
|
2084
|
+
(err) => log7.error({ err }, "Assistant error")
|
|
1640
2085
|
);
|
|
1641
2086
|
return;
|
|
1642
2087
|
}
|
|
@@ -1647,7 +2092,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1647
2092
|
threadId: String(threadId),
|
|
1648
2093
|
userId: String(ctx.from.id),
|
|
1649
2094
|
text: ctx.message.text
|
|
1650
|
-
}).catch((err) =>
|
|
2095
|
+
}).catch((err) => log7.error({ err }, "handleMessage error"));
|
|
1651
2096
|
});
|
|
1652
2097
|
}
|
|
1653
2098
|
// --- ChannelAdapter implementations ---
|
|
@@ -1725,7 +2170,9 @@ Workspace: <code>${workspace}</code>
|
|
|
1725
2170
|
await this.finalizeDraft(sessionId);
|
|
1726
2171
|
await this.bot.api.sendMessage(
|
|
1727
2172
|
this.telegramConfig.chatId,
|
|
1728
|
-
formatPlan(
|
|
2173
|
+
formatPlan(
|
|
2174
|
+
content.metadata
|
|
2175
|
+
),
|
|
1729
2176
|
{
|
|
1730
2177
|
message_thread_id: threadId,
|
|
1731
2178
|
parse_mode: "HTML",
|
|
@@ -1737,7 +2184,9 @@ Workspace: <code>${workspace}</code>
|
|
|
1737
2184
|
case "usage": {
|
|
1738
2185
|
await this.bot.api.sendMessage(
|
|
1739
2186
|
this.telegramConfig.chatId,
|
|
1740
|
-
formatUsage(
|
|
2187
|
+
formatUsage(
|
|
2188
|
+
content.metadata
|
|
2189
|
+
),
|
|
1741
2190
|
{
|
|
1742
2191
|
message_thread_id: threadId,
|
|
1743
2192
|
parse_mode: "HTML",
|
|
@@ -1778,7 +2227,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1778
2227
|
}
|
|
1779
2228
|
}
|
|
1780
2229
|
async sendPermissionRequest(sessionId, request) {
|
|
1781
|
-
|
|
2230
|
+
log7.info({ sessionId, requestId: request.id }, "Permission request sent");
|
|
1782
2231
|
const session = this.core.sessionManager.getSession(
|
|
1783
2232
|
sessionId
|
|
1784
2233
|
);
|
|
@@ -1786,7 +2235,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1786
2235
|
await this.permissionHandler.sendPermissionRequest(session, request);
|
|
1787
2236
|
}
|
|
1788
2237
|
async sendNotification(notification) {
|
|
1789
|
-
|
|
2238
|
+
log7.info(
|
|
1790
2239
|
{ sessionId: notification.sessionId, type: notification.type },
|
|
1791
2240
|
"Notification sent"
|
|
1792
2241
|
);
|
|
@@ -1812,7 +2261,7 @@ Workspace: <code>${workspace}</code>
|
|
|
1812
2261
|
});
|
|
1813
2262
|
}
|
|
1814
2263
|
async createSessionThread(sessionId, name) {
|
|
1815
|
-
|
|
2264
|
+
log7.info({ sessionId, name }, "Session topic created");
|
|
1816
2265
|
return String(
|
|
1817
2266
|
await createSessionTopic(this.bot, this.telegramConfig.chatId, name)
|
|
1818
2267
|
);
|
|
@@ -1830,7 +2279,9 @@ Workspace: <code>${workspace}</code>
|
|
|
1830
2279
|
);
|
|
1831
2280
|
}
|
|
1832
2281
|
async sendSkillCommands(sessionId, commands) {
|
|
1833
|
-
const session = this.core.sessionManager.getSession(
|
|
2282
|
+
const session = this.core.sessionManager.getSession(
|
|
2283
|
+
sessionId
|
|
2284
|
+
);
|
|
1834
2285
|
if (!session) return;
|
|
1835
2286
|
const threadId = Number(session.threadId);
|
|
1836
2287
|
if (!threadId) return;
|
|
@@ -1866,11 +2317,15 @@ Workspace: <code>${workspace}</code>
|
|
|
1866
2317
|
}
|
|
1867
2318
|
);
|
|
1868
2319
|
this.skillMessages.set(sessionId, msg.message_id);
|
|
1869
|
-
await this.bot.api.pinChatMessage(
|
|
1870
|
-
|
|
1871
|
-
|
|
2320
|
+
await this.bot.api.pinChatMessage(
|
|
2321
|
+
this.telegramConfig.chatId,
|
|
2322
|
+
msg.message_id,
|
|
2323
|
+
{
|
|
2324
|
+
disable_notification: true
|
|
2325
|
+
}
|
|
2326
|
+
);
|
|
1872
2327
|
} catch (err) {
|
|
1873
|
-
|
|
2328
|
+
log7.error({ err, sessionId }, "Failed to send skill commands");
|
|
1874
2329
|
}
|
|
1875
2330
|
await this.updateCommandAutocomplete(session.agentName, commands);
|
|
1876
2331
|
}
|
|
@@ -1901,9 +2356,15 @@ Workspace: <code>${workspace}</code>
|
|
|
1901
2356
|
await this.bot.api.setMyCommands(all, {
|
|
1902
2357
|
scope: { type: "chat", chat_id: this.telegramConfig.chatId }
|
|
1903
2358
|
});
|
|
1904
|
-
|
|
2359
|
+
log7.info(
|
|
2360
|
+
{ count: all.length, skills: validSkills.length },
|
|
2361
|
+
"Updated command autocomplete"
|
|
2362
|
+
);
|
|
1905
2363
|
} catch (err) {
|
|
1906
|
-
|
|
2364
|
+
log7.error(
|
|
2365
|
+
{ err, commands: all },
|
|
2366
|
+
"Failed to update command autocomplete"
|
|
2367
|
+
);
|
|
1907
2368
|
}
|
|
1908
2369
|
}
|
|
1909
2370
|
async finalizeDraft(sessionId) {
|
|
@@ -1928,4 +2389,4 @@ export {
|
|
|
1928
2389
|
ChannelAdapter,
|
|
1929
2390
|
TelegramAdapter
|
|
1930
2391
|
};
|
|
1931
|
-
//# sourceMappingURL=chunk-
|
|
2392
|
+
//# sourceMappingURL=chunk-HTXK4NLG.js.map
|