@agentconnect.md/daemon 1.0.0-rc.58 → 1.0.0-rc.59
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/index.js +39 -13
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23639,7 +23639,7 @@ var LocalStore = class {
|
|
|
23639
23639
|
CREATE TABLE IF NOT EXISTS sessions (
|
|
23640
23640
|
key TEXT PRIMARY KEY, agentId TEXT, platform TEXT, channel TEXT, thread TEXT,
|
|
23641
23641
|
acpSessionId TEXT, state TEXT, lastDeliveredTs TEXT, updatedAt INTEGER,
|
|
23642
|
-
usage TEXT
|
|
23642
|
+
usage TEXT, muted INTEGER
|
|
23643
23643
|
);
|
|
23644
23644
|
CREATE TABLE IF NOT EXISTS transcript (
|
|
23645
23645
|
seq INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
@@ -23658,11 +23658,14 @@ var LocalStore = class {
|
|
|
23658
23658
|
`);
|
|
23659
23659
|
this.migrateSessionUsage();
|
|
23660
23660
|
}
|
|
23661
|
-
/** Add the `sessions.usage`
|
|
23662
|
-
* CREATE TABLE IF NOT EXISTS above adds
|
|
23663
|
-
* existing table, so upgrade in place.
|
|
23661
|
+
/** Add the `sessions.usage` (JSON token accounting) and `sessions.muted` (`!stop`
|
|
23662
|
+
* thread mute) columns to a pre-existing DB. CREATE TABLE IF NOT EXISTS above adds
|
|
23663
|
+
* them for fresh DBs but never alters an existing table, so upgrade in place.
|
|
23664
|
+
* No-op once the columns are present. */
|
|
23664
23665
|
migrateSessionUsage() {
|
|
23665
|
-
|
|
23666
|
+
const cols = this.db.prepare("PRAGMA table_info(sessions)").all();
|
|
23667
|
+
if (!cols.some((c) => c.name === "usage")) this.db.exec("ALTER TABLE sessions ADD COLUMN usage TEXT");
|
|
23668
|
+
if (!cols.some((c) => c.name === "muted")) this.db.exec("ALTER TABLE sessions ADD COLUMN muted INTEGER");
|
|
23666
23669
|
}
|
|
23667
23670
|
/**
|
|
23668
23671
|
* Pre-`kind` transcript tables keyed on (channel, thread, ts) hold only conversational
|
|
@@ -23734,6 +23737,15 @@ var LocalStore = class {
|
|
|
23734
23737
|
setSessionState(key, state, updatedAt) {
|
|
23735
23738
|
this.db.prepare("UPDATE sessions SET state = ?, updatedAt = ? WHERE key = ?").run(state, updatedAt, key);
|
|
23736
23739
|
}
|
|
23740
|
+
/** `!stop` thread mute: while set, the router must not auto-dispatch this session's
|
|
23741
|
+
* thread to the agent (thread affinity / keyword / auto); an explicit @mention
|
|
23742
|
+
* clears it. No-op on an unknown key. */
|
|
23743
|
+
setSessionMuted(key, muted) {
|
|
23744
|
+
this.db.prepare("UPDATE sessions SET muted = ? WHERE key = ?").run(muted ? 1 : 0, key);
|
|
23745
|
+
}
|
|
23746
|
+
isSessionMuted(key) {
|
|
23747
|
+
return this.db.prepare("SELECT muted FROM sessions WHERE key = ?").get(key)?.muted === 1;
|
|
23748
|
+
}
|
|
23737
23749
|
/** Current token accounting for a session (parsed from the `usage` JSON column),
|
|
23738
23750
|
* or `{}` if none has been recorded / the JSON is unreadable. */
|
|
23739
23751
|
getUsage(key) {
|
|
@@ -24449,9 +24461,10 @@ function kindMatches(r, msg) {
|
|
|
24449
24461
|
case "auto": return true;
|
|
24450
24462
|
}
|
|
24451
24463
|
}
|
|
24452
|
-
const pickRule = (r) => ({
|
|
24464
|
+
const pickRule = (r, via) => ({
|
|
24453
24465
|
agentId: r.agentId,
|
|
24454
|
-
integrationId: r.integrationId
|
|
24466
|
+
integrationId: r.integrationId,
|
|
24467
|
+
via
|
|
24455
24468
|
});
|
|
24456
24469
|
/**
|
|
24457
24470
|
* Arbitrate the merged (local ∪ CP) rule set for an inbound message (design §8.2/§8.3).
|
|
@@ -24466,19 +24479,19 @@ function routeRules(msg, rules, threadOwner) {
|
|
|
24466
24479
|
const scopeCandidates = rules.filter((r) => scopeMatches(r, msg) && authz(r));
|
|
24467
24480
|
const kindCandidates = scopeCandidates.filter((r) => kindMatches(r, msg));
|
|
24468
24481
|
const mention = kindCandidates.find((r) => r.match.kind === "mention");
|
|
24469
|
-
if (mention) return pickRule(mention);
|
|
24482
|
+
if (mention) return pickRule(mention, "mention");
|
|
24470
24483
|
if (msg.thread) {
|
|
24471
24484
|
const owner = threadOwner(msg.channel, msg.thread);
|
|
24472
24485
|
if (owner) {
|
|
24473
24486
|
const ownerRule = scopeCandidates.find((x) => x.agentId === owner);
|
|
24474
|
-
if (ownerRule) return pickRule(ownerRule);
|
|
24487
|
+
if (ownerRule) return pickRule(ownerRule, "thread");
|
|
24475
24488
|
}
|
|
24476
24489
|
}
|
|
24477
24490
|
const layer = kindCandidates.some((r) => r.source === "cp" && r.scope.channel === msg.channel && (r.scope.thread === void 0 || r.scope.thread === msg.thread)) ? kindCandidates.filter((r) => r.source === "cp") : kindCandidates;
|
|
24478
24491
|
for (const kind of KIND_ORDER) {
|
|
24479
24492
|
if (kind === "mention") continue;
|
|
24480
24493
|
const r = layer.find((x) => x.match.kind === kind);
|
|
24481
|
-
if (r) return pickRule(r);
|
|
24494
|
+
if (r) return pickRule(r, kind);
|
|
24482
24495
|
}
|
|
24483
24496
|
return null;
|
|
24484
24497
|
}
|
|
@@ -83114,6 +83127,16 @@ var Daemon = class Daemon {
|
|
|
83114
83127
|
this.log.debug(`routing: dropping ${msg.msgId} for agent "${result.agentId}" (draining)`);
|
|
83115
83128
|
return;
|
|
83116
83129
|
}
|
|
83130
|
+
const muteKey = sessionKey(msg.platform, msg.channel, msg.thread ?? msg.msgId, result.agentId);
|
|
83131
|
+
if (this.store.isSessionMuted(muteKey)) {
|
|
83132
|
+
if (result.via !== "mention") {
|
|
83133
|
+
this.recordUnrouted(msg);
|
|
83134
|
+
this.log.debug(`routing: dropping ${msg.msgId} for agent "${result.agentId}" (muted by !stop; awaiting @mention)`);
|
|
83135
|
+
return;
|
|
83136
|
+
}
|
|
83137
|
+
this.store.setSessionMuted(muteKey, false);
|
|
83138
|
+
this.log.info(`routing: agent "${result.agentId}" un-muted in ch=${msg.channel} (explicit @mention)`);
|
|
83139
|
+
}
|
|
83117
83140
|
this.log.info(`routing: ch=${msg.channel} → agent "${result.agentId}" (integration ${result.integrationId})`);
|
|
83118
83141
|
this.dispatch(result.agentId, msg, result.integrationId).catch((err) => this.log.error(`dispatch failed for agent "${result.agentId}": ${formatErr(err)}`));
|
|
83119
83142
|
}
|
|
@@ -83184,11 +83207,14 @@ var Daemon = class Daemon {
|
|
|
83184
83207
|
const conn = this.replyConnFor(target.agentId, target.integrationId);
|
|
83185
83208
|
const thread = msg.thread ?? msg.msgId;
|
|
83186
83209
|
const key = sessionKey(msg.platform, msg.channel, thread, target.agentId);
|
|
83187
|
-
const
|
|
83210
|
+
const rec = this.store.getSession(key);
|
|
83211
|
+
const acpSessionId = rec?.acpSessionId;
|
|
83188
83212
|
const inflight = !!(acpSessionId && this.pending.has(acpSessionId));
|
|
83189
83213
|
if (command.kind === "stop") {
|
|
83214
|
+
if (rec) this.store.setSessionMuted(key, true);
|
|
83215
|
+
const muteNote = "Muted in this thread — @mention me to resume.";
|
|
83190
83216
|
if (!inflight) {
|
|
83191
|
-
conn?.postMessage(msg.channel, "Nothing is running to stop.", thread);
|
|
83217
|
+
conn?.postMessage(msg.channel, rec ? `🔇 Nothing is running. ${muteNote}` : "Nothing is running to stop.", thread);
|
|
83192
83218
|
return;
|
|
83193
83219
|
}
|
|
83194
83220
|
this.queued.delete(acpSessionId);
|
|
@@ -83196,7 +83222,7 @@ var Daemon = class Daemon {
|
|
|
83196
83222
|
this.store.setSessionState(key, "cancelling", this.clock.now());
|
|
83197
83223
|
this.hosts.get(target.agentId)?.cancel(acpSessionId).catch((err) => this.log.error(`command stop: cancel failed: ${err.message}`));
|
|
83198
83224
|
this.armCancelBackstop(target.agentId, acpSessionId, key);
|
|
83199
|
-
conn?.postMessage(msg.channel,
|
|
83225
|
+
conn?.postMessage(msg.channel, `🛑 Stopped. ${muteNote}`, thread);
|
|
83200
83226
|
return;
|
|
83201
83227
|
}
|
|
83202
83228
|
if (!command.text) {
|