agentp 0.8.0 → 0.9.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/AGENTS.md +31 -9
- package/README.md +44 -9
- package/bin/agentp +142 -28
- package/bin/ocmux +24 -6
- package/bin/tgagentp +219 -68
- package/debugging_tg_integration.md +5594 -0
- package/lib/opencode.js +45 -9
- package/package.json +1 -1
- package/tgagentp.log +2156 -0
package/lib/opencode.js
CHANGED
|
@@ -11,7 +11,7 @@ function getAuthHeaders() {
|
|
|
11
11
|
return { 'Authorization': `Basic ${encoded}` };
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
function makeRequest(options, data) {
|
|
14
|
+
function makeRequest(options, data, cancelRef) {
|
|
15
15
|
return new Promise((resolve, reject) => {
|
|
16
16
|
const req = http.request(options, (res) => {
|
|
17
17
|
let body = '';
|
|
@@ -25,6 +25,7 @@ function makeRequest(options, data) {
|
|
|
25
25
|
});
|
|
26
26
|
});
|
|
27
27
|
req.on('error', reject);
|
|
28
|
+
if (cancelRef) cancelRef.current = req;
|
|
28
29
|
if (data) req.write(data);
|
|
29
30
|
req.end();
|
|
30
31
|
});
|
|
@@ -181,15 +182,16 @@ async function listSessions(server, directory) {
|
|
|
181
182
|
return JSON.parse(body);
|
|
182
183
|
}
|
|
183
184
|
|
|
184
|
-
// Send a message directly to a specific session via the session API.
|
|
185
|
+
// Send a message directly to a specific session via the synchronous session API.
|
|
185
186
|
// Returns the collected text from all text parts in the response.
|
|
186
187
|
// Optionally specify an agent to handle the message.
|
|
187
|
-
|
|
188
|
+
// Optional cancelRef allows aborting the HTTP request (for /cancel support).
|
|
189
|
+
async function sendToSession(server, sessionId, text, agent, cancelRef) {
|
|
188
190
|
const url = `${server}/session/${encodeURIComponent(sessionId)}/message`;
|
|
189
191
|
const bodyObj = { parts: [{ type: 'text', text }] };
|
|
190
192
|
if (agent) bodyObj.agent = agent;
|
|
191
193
|
const body = JSON.stringify(bodyObj);
|
|
192
|
-
const { status, body: responseBody } = await makeRequest(buildJsonRequest(url, 'POST', body), body);
|
|
194
|
+
const { status, body: responseBody } = await makeRequest(buildJsonRequest(url, 'POST', body), body, cancelRef);
|
|
193
195
|
if (status !== 200) throw new Error(`Failed to send to session: ${status}`);
|
|
194
196
|
const result = JSON.parse(responseBody);
|
|
195
197
|
const texts = (result.parts || [])
|
|
@@ -209,9 +211,12 @@ async function createSession(server, title) {
|
|
|
209
211
|
}
|
|
210
212
|
|
|
211
213
|
// Update a session's properties (e.g. title).
|
|
212
|
-
async function updateSession(server, sessionId, title) {
|
|
214
|
+
async function updateSession(server, sessionId, title, agent) {
|
|
215
|
+
const bodyObj = {};
|
|
216
|
+
if (title != null) bodyObj.title = title;
|
|
217
|
+
if (agent != null) bodyObj.agent = agent;
|
|
213
218
|
const url = `${server}/session/${encodeURIComponent(sessionId)}`;
|
|
214
|
-
const body = JSON.stringify(
|
|
219
|
+
const body = JSON.stringify(bodyObj);
|
|
215
220
|
const { status, body: responseBody } = await makeRequest(buildJsonRequest(url, 'PATCH', body), body);
|
|
216
221
|
if (status !== 200) throw new Error(`Failed to update session: ${status}`);
|
|
217
222
|
return JSON.parse(responseBody);
|
|
@@ -276,7 +281,7 @@ async function respondToPermission(server, sessionId, permissionId, response, re
|
|
|
276
281
|
|
|
277
282
|
// Listen for session events via SSE, collecting assistant text parts and detecting
|
|
278
283
|
// permission requests. Resolves with the full collected text when the session goes idle.
|
|
279
|
-
// callbacks: { onText(chunk), onPermission(permission) }
|
|
284
|
+
// callbacks: { onText(chunk), onPermission(permission), onThinking(chunk), onConnected() }
|
|
280
285
|
// cancelRef — allows aborting the SSE stream via req.destroy()
|
|
281
286
|
function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
282
287
|
process.stderr.write(` [SSE] connecting to ${server}/event for session ${sessionId}\n`);
|
|
@@ -297,9 +302,22 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
297
302
|
return;
|
|
298
303
|
}
|
|
299
304
|
process.stderr.write(` [SSE] connected for session ${sessionId}\n`);
|
|
305
|
+
if (callbacks.onConnected) callbacks.onConnected();
|
|
300
306
|
let buffer = '';
|
|
301
307
|
const userMessageIDs = new Set();
|
|
302
308
|
let collected = '';
|
|
309
|
+
let resolved = false;
|
|
310
|
+
|
|
311
|
+
// Safety timeout: resolve with whatever we have after 90s
|
|
312
|
+
const safetyTimer = setTimeout(() => {
|
|
313
|
+
if (resolved) return;
|
|
314
|
+
resolved = true;
|
|
315
|
+
process.stderr.write(` [SSE] safety timeout (90s) for session ${sessionId}, collected ${collected.length} chars\n`);
|
|
316
|
+
cleanup();
|
|
317
|
+
req.destroy();
|
|
318
|
+
res.destroy();
|
|
319
|
+
resolve(collected);
|
|
320
|
+
}, 90000);
|
|
303
321
|
|
|
304
322
|
res.on('data', (chunk) => {
|
|
305
323
|
buffer += chunk.toString();
|
|
@@ -325,8 +343,8 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
325
343
|
process.stderr.write(` [SSE] event type=${event.type} sessionID=${props.sessionID} waitSession=${sessionId}\n`);
|
|
326
344
|
}
|
|
327
345
|
|
|
328
|
-
// Filter by sessionID when the event carries one
|
|
329
|
-
if (props.sessionID && props.sessionID !== sessionId) continue;
|
|
346
|
+
// Filter by sessionID when the event carries one (string-compare to handle type mismatches)
|
|
347
|
+
if (props.sessionID && String(props.sessionID) !== String(sessionId)) continue;
|
|
330
348
|
|
|
331
349
|
if (event.type === 'message.updated' && props.info?.role === 'user') {
|
|
332
350
|
userMessageIDs.add(props.info.id);
|
|
@@ -355,6 +373,9 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
355
373
|
|
|
356
374
|
// Completion signals
|
|
357
375
|
if (event.type === 'session.idle') {
|
|
376
|
+
clearTimeout(safetyTimer);
|
|
377
|
+
if (resolved) return;
|
|
378
|
+
resolved = true;
|
|
358
379
|
cleanup();
|
|
359
380
|
req.destroy();
|
|
360
381
|
res.destroy();
|
|
@@ -362,6 +383,9 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
362
383
|
return;
|
|
363
384
|
}
|
|
364
385
|
if (event.type === 'session.status' && props.status?.type === 'idle') {
|
|
386
|
+
clearTimeout(safetyTimer);
|
|
387
|
+
if (resolved) return;
|
|
388
|
+
resolved = true;
|
|
365
389
|
cleanup();
|
|
366
390
|
req.destroy();
|
|
367
391
|
res.destroy();
|
|
@@ -390,9 +414,21 @@ function listenForSessionEvents(server, sessionId, callbacks, cancelRef) {
|
|
|
390
414
|
});
|
|
391
415
|
|
|
392
416
|
res.on('end', () => {
|
|
417
|
+
clearTimeout(safetyTimer);
|
|
418
|
+
if (resolved) return;
|
|
419
|
+
resolved = true;
|
|
393
420
|
cleanup();
|
|
394
421
|
resolve(collected);
|
|
395
422
|
});
|
|
423
|
+
|
|
424
|
+
res.on('error', (err) => {
|
|
425
|
+
clearTimeout(safetyTimer);
|
|
426
|
+
if (resolved) return;
|
|
427
|
+
resolved = true;
|
|
428
|
+
cleanup();
|
|
429
|
+
process.stderr.write(` [SSE] response stream error for session ${sessionId}: ${err.message}\n`);
|
|
430
|
+
resolve(collected); // resolve with what we have
|
|
431
|
+
});
|
|
396
432
|
});
|
|
397
433
|
|
|
398
434
|
const cleanup = () => {
|