@openagents-org/agent-launcher 0.2.194 → 0.2.195
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 +1 -1
- package/src/adapters/base.js +22 -4
- package/src/adapters/claude.js +2 -2
- package/src/adapters/codex.js +3 -1
package/package.json
CHANGED
package/src/adapters/base.js
CHANGED
|
@@ -239,6 +239,7 @@ class BaseAdapter {
|
|
|
239
239
|
// "this turn started after the stop and is meant to run".
|
|
240
240
|
this._channelRunGeneration = {};
|
|
241
241
|
this._channelRequestContent = {};
|
|
242
|
+
this._channelTriggerId = {};
|
|
242
243
|
// Channels a user stopped whose next turn has not started yet. Everything
|
|
243
244
|
// the send* helpers would post there is dropped: output a killed run was
|
|
244
245
|
// still flushing lands after the stop notice otherwise, and the workspace
|
|
@@ -1428,6 +1429,7 @@ class BaseAdapter {
|
|
|
1428
1429
|
// instructions (v1.1 M4); the block is prepended to the message.
|
|
1429
1430
|
// Gated synchronously so messages it cannot apply to (agents,
|
|
1430
1431
|
// anonymous humans, system) add no extra tick before the stop check.
|
|
1432
|
+
this._applyThreadCollaboration(channel, current);
|
|
1431
1433
|
if (this._sharedContextCandidate(current)) await this._applySharedContext(channel, current);
|
|
1432
1434
|
// Checked after the round trips above, which a stop can land inside:
|
|
1433
1435
|
// a message from before the stop never reaches the CLI.
|
|
@@ -1439,6 +1441,7 @@ class BaseAdapter {
|
|
|
1439
1441
|
this._mutedChannels.delete(channel);
|
|
1440
1442
|
this._stopNoticeSent.delete(channel);
|
|
1441
1443
|
this._stoppingChannels.delete(channel);
|
|
1444
|
+
this._channelTriggerId[channel] = current.messageId || null;
|
|
1442
1445
|
await this._handleMessage(current);
|
|
1443
1446
|
}
|
|
1444
1447
|
} catch (e) {
|
|
@@ -1447,6 +1450,7 @@ class BaseAdapter {
|
|
|
1447
1450
|
}
|
|
1448
1451
|
delete this._channelRunGeneration[channel];
|
|
1449
1452
|
delete this._channelRequestContent[channel];
|
|
1453
|
+
delete this._channelTriggerId[channel];
|
|
1450
1454
|
first = false;
|
|
1451
1455
|
|
|
1452
1456
|
const queue = this._channelQueues[channel];
|
|
@@ -1498,8 +1502,13 @@ class BaseAdapter {
|
|
|
1498
1502
|
* the per-run MCP server. Never throws.
|
|
1499
1503
|
*/
|
|
1500
1504
|
_sharedContextEmail(msg) {
|
|
1501
|
-
if (!msg
|
|
1502
|
-
const
|
|
1505
|
+
if (!msg) return null;
|
|
1506
|
+
const continuation = msg.senderType === 'agent' && msg.metadata?.orchestration?.action === 'next';
|
|
1507
|
+
if (msg.senderType !== 'human' && !continuation) return null;
|
|
1508
|
+
// Continuations retain the authenticated original requester so the next
|
|
1509
|
+
// agent applies the same owner-reviewed shared context and tool identity.
|
|
1510
|
+
const raw = continuation ? (msg.metadata.requester_email || '')
|
|
1511
|
+
: (msg.senderEmail || (msg.metadata && msg.metadata.sender_email) || '');
|
|
1503
1512
|
const email = String(raw).trim().toLowerCase();
|
|
1504
1513
|
return email && email.includes('@') ? email : null;
|
|
1505
1514
|
}
|
|
@@ -1508,6 +1517,15 @@ class BaseAdapter {
|
|
|
1508
1517
|
return this._sharedContextEmail(msg) !== null;
|
|
1509
1518
|
}
|
|
1510
1519
|
|
|
1520
|
+
_applyThreadCollaboration(channel, msg) {
|
|
1521
|
+
if (msg._threadCollaborationApplied || !channel || channel.startsWith('dm:')) return;
|
|
1522
|
+
const instructions = msg.metadata?.thread_agent_instructions?.[this.agentName];
|
|
1523
|
+
if (typeof instructions !== 'string' || !instructions.trim()) return;
|
|
1524
|
+
if (msg.originalContent === undefined) msg.originalContent = msg.content;
|
|
1525
|
+
msg.content = `COLLABORATION INSTRUCTIONS FOR THIS THREAD ONLY (do not carry these into other threads; existing owner restrictions still apply):\n${instructions.slice(0, 10000)}\nEND THREAD INSTRUCTIONS\n\n${msg.content || ''}`;
|
|
1526
|
+
msg._threadCollaborationApplied = true;
|
|
1527
|
+
}
|
|
1528
|
+
|
|
1511
1529
|
async _applySharedContext(channel, msg) {
|
|
1512
1530
|
const email = this._sharedContextEmail(msg);
|
|
1513
1531
|
if (!email) return false;
|
|
@@ -1805,7 +1823,7 @@ class BaseAdapter {
|
|
|
1805
1823
|
* structured field: an earlier attempt matched the word "completed" in the
|
|
1806
1824
|
* message text and fired on every bash for-loop that ended in `done`.
|
|
1807
1825
|
*/
|
|
1808
|
-
async sendResponse(channel, content) {
|
|
1826
|
+
async sendResponse(channel, content, { statusKind = 'completed' } = {}) {
|
|
1809
1827
|
if (this._isMuted(channel)) return;
|
|
1810
1828
|
try {
|
|
1811
1829
|
let attachments = [];
|
|
@@ -1825,7 +1843,7 @@ class BaseAdapter {
|
|
|
1825
1843
|
attachments,
|
|
1826
1844
|
senderType: 'agent',
|
|
1827
1845
|
senderName: this.agentName,
|
|
1828
|
-
metadata: { status_kind:
|
|
1846
|
+
metadata: { status_kind: statusKind, ...(this._channelTriggerId?.[channel] ? { in_reply_to: this._channelTriggerId[channel] } : {}) },
|
|
1829
1847
|
sessionId: this._sessionId,
|
|
1830
1848
|
});
|
|
1831
1849
|
} catch (e) {
|
package/src/adapters/claude.js
CHANGED
|
@@ -1125,7 +1125,7 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
1125
1125
|
*/
|
|
1126
1126
|
async _postTurnOutcome(pp, msgChannel, finalResponse) {
|
|
1127
1127
|
if (finalResponse) {
|
|
1128
|
-
try { await this.sendResponse(msgChannel, finalResponse); } catch {}
|
|
1128
|
+
try { await this.sendResponse(msgChannel, finalResponse, { statusKind: pp.lastErrorText ? 'error' : 'completed' }); } catch {}
|
|
1129
1129
|
} else if (pp.lastErrorText) {
|
|
1130
1130
|
try { await this.sendError(msgChannel, this._formatClaudeError(pp.lastErrorText)); } catch {}
|
|
1131
1131
|
} else if (!pp.everPostedAnything) {
|
|
@@ -1477,7 +1477,7 @@ class ClaudeAdapter extends BaseAdapter {
|
|
|
1477
1477
|
if (detail) {
|
|
1478
1478
|
try { await this.sendError(msgChannel, this._formatClaudeError(detail)); } catch {}
|
|
1479
1479
|
} else {
|
|
1480
|
-
try { await this.
|
|
1480
|
+
try { await this.sendError(msgChannel, `No response generated (exit code ${result.code === undefined ? 'unknown' : result.code}). Please try again.`); } catch {}
|
|
1481
1481
|
}
|
|
1482
1482
|
}
|
|
1483
1483
|
break;
|
package/src/adapters/codex.js
CHANGED
|
@@ -376,7 +376,9 @@ class CodexAdapter extends BaseAdapter {
|
|
|
376
376
|
if (result.stopped) return;
|
|
377
377
|
|
|
378
378
|
if (result.responseText) {
|
|
379
|
-
await this.sendResponse(msgChannel, result.responseText
|
|
379
|
+
await this.sendResponse(msgChannel, result.responseText, {
|
|
380
|
+
statusKind: CodexAdapter._endedEarly(result) ? 'error' : 'completed',
|
|
381
|
+
});
|
|
380
382
|
// A run that said something and then died (turn.failed, non-zero
|
|
381
383
|
// exit) used to post only that opening line as the finished reply,
|
|
382
384
|
// so it read as "Codex says one sentence and stops" with the real
|