@ganglion/xacpx-relay 0.14.1 → 0.14.2-beta.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/dist/cli.js +227 -17
- package/dist/http/app.d.ts +3 -0
- package/dist/http/compact-history.d.ts +2 -0
- package/dist/relay-web/assets/DashboardView-C4uZxFJc.js +458 -0
- package/dist/relay-web/assets/{DashboardView-B2jBgxiL.css → DashboardView-CRYuoJ2T.css} +1 -1
- package/dist/relay-web/assets/{InviteView-CXCceyjs.js → InviteView-DJtV1g3a.js} +1 -1
- package/dist/relay-web/assets/{LoginView-s6HkroR1.js → LoginView-DrsAFowP.js} +1 -1
- package/dist/relay-web/assets/{SettingsView-a0OmqD6M.js → SettingsView-B-hRDWwa.js} +1 -1
- package/dist/relay-web/assets/{abnfDiagram-VRR7QNED-2JIaFFTg.js → abnfDiagram-VRR7QNED-DvXIiGiP.js} +1 -1
- package/dist/relay-web/assets/{arc-33J3JAHf.js → arc-lGeGPRGC.js} +1 -1
- package/dist/relay-web/assets/{architectureDiagram-ZJ3FMSHR-BchSqVyS.js → architectureDiagram-ZJ3FMSHR-BlfrbJZ7.js} +1 -1
- package/dist/relay-web/assets/{blockDiagram-677ZJIJ3-CNeeN8w_.js → blockDiagram-677ZJIJ3-D9CpR2tq.js} +1 -1
- package/dist/relay-web/assets/{c4Diagram-LMCZKHZV-DpHV_2Bl.js → c4Diagram-LMCZKHZV-D5gJNUFs.js} +1 -1
- package/dist/relay-web/assets/channel-BgqBTryA.js +1 -0
- package/dist/relay-web/assets/{chunk-2Q5K7J3B-CTZoYiXU.js → chunk-2Q5K7J3B-CEe3zyzr.js} +1 -1
- package/dist/relay-web/assets/{chunk-32BRIVSS-HaVMgCVO.js → chunk-32BRIVSS-DPfCCn5M.js} +1 -1
- package/dist/relay-web/assets/{chunk-5VM5RSS4-ojMow50b.js → chunk-5VM5RSS4-CFDfXqUR.js} +1 -1
- package/dist/relay-web/assets/{chunk-EX3LRPZG-BB9v3Fyx.js → chunk-EX3LRPZG-BJ8FZX61.js} +1 -1
- package/dist/relay-web/assets/{chunk-JWPE2WC7-DpPVEV0e.js → chunk-JWPE2WC7-R0jCcwG_.js} +1 -1
- package/dist/relay-web/assets/{chunk-MOJQB5TN-BVTnyTR0.js → chunk-MOJQB5TN-_QHvguKZ.js} +1 -1
- package/dist/relay-web/assets/{chunk-RYQCIY6F-CPUenDRh.js → chunk-RYQCIY6F-C2f2OGXu.js} +1 -1
- package/dist/relay-web/assets/{chunk-V7JOEXUC-D5wr2ziH.js → chunk-V7JOEXUC-CZ8cvGbJ.js} +1 -1
- package/dist/relay-web/assets/{chunk-VR4S4FIN-CM-9QhEh.js → chunk-VR4S4FIN-BdqWtJgq.js} +1 -1
- package/dist/relay-web/assets/{chunk-XXDRQBXY-DYTAeiTM.js → chunk-XXDRQBXY-Cw710t3a.js} +1 -1
- package/dist/relay-web/assets/classDiagram-OUVF2IWQ-DwhIEwUq.js +1 -0
- package/dist/relay-web/assets/classDiagram-v2-EOCWNBFH-DwhIEwUq.js +1 -0
- package/dist/relay-web/assets/{cose-bilkent-JH36ORCC-B5ht-Nkg.js → cose-bilkent-JH36ORCC-lVLW5WEW.js} +1 -1
- package/dist/relay-web/assets/{cynefin-VYW2F7L2-i7N2S7w1.js → cynefin-VYW2F7L2-DzXb1Qg3.js} +1 -1
- package/dist/relay-web/assets/{cynefinDiagram-TSTJHNR4-CFZRrysn.js → cynefinDiagram-TSTJHNR4-DorSrk5l.js} +1 -1
- package/dist/relay-web/assets/{dagre-VKFMJZFB-C00r7gwi.js → dagre-VKFMJZFB-C7KRVdBQ.js} +1 -1
- package/dist/relay-web/assets/{diagram-FQU43EPY-B3HmYhcj.js → diagram-FQU43EPY-DlpxPgGg.js} +1 -1
- package/dist/relay-web/assets/{diagram-G47NLZAW-DmRsVi1P.js → diagram-G47NLZAW-DpyBwPlZ.js} +1 -1
- package/dist/relay-web/assets/{diagram-NH7WQ7WH-CVzGQZCx.js → diagram-NH7WQ7WH-BtT1PHdr.js} +1 -1
- package/dist/relay-web/assets/{diagram-OA4YK3LP-BdVMJv3M.js → diagram-OA4YK3LP-Jw40hyJ4.js} +1 -1
- package/dist/relay-web/assets/{diagram-WEI45ONY-DUcNdB4v.js → diagram-WEI45ONY-BVHCnHzc.js} +1 -1
- package/dist/relay-web/assets/{ebnfDiagram-CCIWWBDH-CPz6Kmbm.js → ebnfDiagram-CCIWWBDH-B8tIY0DT.js} +1 -1
- package/dist/relay-web/assets/{erDiagram-Q63AITRT-VeMZYbaf.js → erDiagram-Q63AITRT-Bbb7pMuu.js} +1 -1
- package/dist/relay-web/assets/{flowDiagram-23GEKE2U-DHHV5pKm.js → flowDiagram-23GEKE2U-C6O-k1Lh.js} +1 -1
- package/dist/relay-web/assets/{ganttDiagram-NO4QXBWP-XuH2e6HD.js → ganttDiagram-NO4QXBWP-BvMFkuHz.js} +1 -1
- package/dist/relay-web/assets/{gitGraphDiagram-IHSO6WYX-ovsf1Fl5.js → gitGraphDiagram-IHSO6WYX-CPtPnpx1.js} +1 -1
- package/dist/relay-web/assets/{index-Kpr5-jgf.js → index-jjx4H84v.js} +2 -2
- package/dist/relay-web/assets/{infoDiagram-FWYZ7A6U-DScoKb0G.js → infoDiagram-FWYZ7A6U-DCj8dx4B.js} +1 -1
- package/dist/relay-web/assets/{ishikawaDiagram-FXEZZL3T-BBxwHVZf.js → ishikawaDiagram-FXEZZL3T-Dphi71w0.js} +1 -1
- package/dist/relay-web/assets/{journeyDiagram-5HDEW3XC-CxXhjgjC.js → journeyDiagram-5HDEW3XC-Dte5L42r.js} +1 -1
- package/dist/relay-web/assets/{kanban-definition-HUTT4EX6-DrNv9cZH.js → kanban-definition-HUTT4EX6-Vm5E-3-k.js} +1 -1
- package/dist/relay-web/assets/{linear-CkusLJGE.js → linear-BytQ8H5b.js} +1 -1
- package/dist/relay-web/assets/{mermaid.core-CZRtox5e.js → mermaid.core-DWa8K3k_.js} +4 -4
- package/dist/relay-web/assets/{mindmap-definition-LN4V7U3C-B1PXNCdk.js → mindmap-definition-LN4V7U3C-BcgOdq0O.js} +1 -1
- package/dist/relay-web/assets/{pegDiagram-2B236MQR-6XPhI4ao.js → pegDiagram-2B236MQR-6wFGkTj3.js} +1 -1
- package/dist/relay-web/assets/{pieDiagram-ENE6RG2P-CskGGVZw.js → pieDiagram-ENE6RG2P-DbeoojG3.js} +1 -1
- package/dist/relay-web/assets/{quadrantDiagram-ABIIQ3AL-DZRB7SqC.js → quadrantDiagram-ABIIQ3AL-L8lhatCO.js} +1 -1
- package/dist/relay-web/assets/{railroadDiagram-RFXS5EU6-CTAxd2yc.js → railroadDiagram-RFXS5EU6-CmNsEkKG.js} +1 -1
- package/dist/relay-web/assets/{requirementDiagram-TGXJPOKE-BF5gXh18.js → requirementDiagram-TGXJPOKE-CuDqGM8H.js} +1 -1
- package/dist/relay-web/assets/{sankeyDiagram-HTMAVEWB-CM8ZxfPM.js → sankeyDiagram-HTMAVEWB-Cpmd-8x3.js} +1 -1
- package/dist/relay-web/assets/{sequenceDiagram-DBY2YBRQ-QjI-fgd1.js → sequenceDiagram-DBY2YBRQ-ipwgpvyZ.js} +1 -1
- package/dist/relay-web/assets/{sizeCapture-X5ZJPWSS-05mn0JnJ.js → sizeCapture-X5ZJPWSS-ILRFTwii.js} +1 -1
- package/dist/relay-web/assets/{stateDiagram-2N3HPSRC-BNQ-XmgM.js → stateDiagram-2N3HPSRC-CHmuDF7F.js} +1 -1
- package/dist/relay-web/assets/stateDiagram-v2-6OUMAXLB-BMsDRO4U.js +1 -0
- package/dist/relay-web/assets/{swimlanes-5IMT3BWC-B0on9_MK.js → swimlanes-5IMT3BWC-DZhSWujN.js} +2 -2
- package/dist/relay-web/assets/swimlanesDiagram-G3AALYLV-C6GaSutc.js +8 -0
- package/dist/relay-web/assets/{theme-COCM1hBm.js → theme-DS8opD1d.js} +1 -1
- package/dist/relay-web/assets/{timeline-definition-FHXFAJF6-So8J-054.js → timeline-definition-FHXFAJF6-C2n1uG0w.js} +1 -1
- package/dist/relay-web/assets/{vennDiagram-L72KCM5P-B_senTb4.js → vennDiagram-L72KCM5P-Dotrpr6i.js} +1 -1
- package/dist/relay-web/assets/{wardleyDiagram-EHGQE667-ApGsv91F.js → wardleyDiagram-EHGQE667-B8ZSYG_L.js} +1 -1
- package/dist/relay-web/assets/{xychartDiagram-FW5EYKEG-BpdYYkKu.js → xychartDiagram-FW5EYKEG-BlayRcZO.js} +1 -1
- package/dist/relay-web/index.html +1 -1
- package/dist/relay-web/sw.js +1 -1
- package/dist/server.d.ts +2 -0
- package/dist/stores/messages.d.ts +3 -1
- package/dist/stores/turn-slot-anchors.d.ts +47 -0
- package/package.json +2 -2
- package/dist/relay-web/assets/DashboardView-CgzIgCQ5.js +0 -458
- package/dist/relay-web/assets/channel-CGmHIR5G.js +0 -1
- package/dist/relay-web/assets/classDiagram-OUVF2IWQ-BRju-dhQ.js +0 -1
- package/dist/relay-web/assets/classDiagram-v2-EOCWNBFH-BRju-dhQ.js +0 -1
- package/dist/relay-web/assets/stateDiagram-v2-6OUMAXLB-BSYqyg2P.js +0 -1
- package/dist/relay-web/assets/swimlanesDiagram-G3AALYLV-CZ6U0BMI.js +0 -8
package/dist/cli.js
CHANGED
|
@@ -7397,7 +7397,10 @@ function initSchema(db) {
|
|
|
7397
7397
|
queue_item_id TEXT,
|
|
7398
7398
|
queue_fallback INTEGER NOT NULL DEFAULT 0,
|
|
7399
7399
|
origin_queue_item_id TEXT,
|
|
7400
|
-
prompt_request_id TEXT
|
|
7400
|
+
prompt_request_id TEXT,
|
|
7401
|
+
started_at INTEGER,
|
|
7402
|
+
slot_after_id INTEGER,
|
|
7403
|
+
started_after_seq INTEGER
|
|
7401
7404
|
);
|
|
7402
7405
|
CREATE INDEX IF NOT EXISTS idx_messages_session ON messages (instance_id, session_alias, id);
|
|
7403
7406
|
CREATE TABLE IF NOT EXISTS recovery_receipts (
|
|
@@ -7406,6 +7409,16 @@ function initSchema(db) {
|
|
|
7406
7409
|
created_at TEXT NOT NULL,
|
|
7407
7410
|
PRIMARY KEY (instance_id, recovery_id)
|
|
7408
7411
|
);
|
|
7412
|
+
CREATE TABLE IF NOT EXISTS turn_slot_anchors (
|
|
7413
|
+
instance_id TEXT NOT NULL,
|
|
7414
|
+
session_alias TEXT NOT NULL,
|
|
7415
|
+
recovery_id TEXT NOT NULL DEFAULT '',
|
|
7416
|
+
slot_after_id INTEGER NOT NULL,
|
|
7417
|
+
started_at INTEGER,
|
|
7418
|
+
started_after_seq INTEGER,
|
|
7419
|
+
PRIMARY KEY (instance_id, recovery_id)
|
|
7420
|
+
);
|
|
7421
|
+
CREATE INDEX IF NOT EXISTS idx_turn_slot_anchors_session ON turn_slot_anchors (instance_id, session_alias);
|
|
7409
7422
|
CREATE TABLE IF NOT EXISTS pending_completion_routes (
|
|
7410
7423
|
request_message_id TEXT PRIMARY KEY,
|
|
7411
7424
|
account_id TEXT NOT NULL,
|
|
@@ -7449,6 +7462,15 @@ function initSchema(db) {
|
|
|
7449
7462
|
if (!messageCols.some((c) => c.name === "prompt_request_id")) {
|
|
7450
7463
|
db.exec("ALTER TABLE messages ADD COLUMN prompt_request_id TEXT");
|
|
7451
7464
|
}
|
|
7465
|
+
if (!messageCols.some((c) => c.name === "started_at")) {
|
|
7466
|
+
db.exec("ALTER TABLE messages ADD COLUMN started_at INTEGER");
|
|
7467
|
+
}
|
|
7468
|
+
if (!messageCols.some((c) => c.name === "slot_after_id")) {
|
|
7469
|
+
db.exec("ALTER TABLE messages ADD COLUMN slot_after_id INTEGER");
|
|
7470
|
+
}
|
|
7471
|
+
if (!messageCols.some((c) => c.name === "started_after_seq")) {
|
|
7472
|
+
db.exec("ALTER TABLE messages ADD COLUMN started_after_seq INTEGER");
|
|
7473
|
+
}
|
|
7452
7474
|
const instanceCols = db.all("PRAGMA table_info(instances)");
|
|
7453
7475
|
if (!instanceCols.some((c) => c.name === "capabilities_json")) {
|
|
7454
7476
|
db.exec("ALTER TABLE instances ADD COLUMN capabilities_json TEXT");
|
|
@@ -7597,6 +7619,7 @@ class AccountStore {
|
|
|
7597
7619
|
this.db.exec("BEGIN");
|
|
7598
7620
|
try {
|
|
7599
7621
|
this.db.run("DELETE FROM messages WHERE instance_id IN (SELECT id FROM instances WHERE account_id = ?)", [accountId]);
|
|
7622
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id IN (SELECT id FROM instances WHERE account_id = ?)", [accountId]);
|
|
7600
7623
|
this.db.run("DELETE FROM instances WHERE account_id = ?", [accountId]);
|
|
7601
7624
|
this.db.run("DELETE FROM pairing_tokens WHERE account_id = ?", [accountId]);
|
|
7602
7625
|
this.db.run("DELETE FROM web_sessions WHERE account_id = ?", [accountId]);
|
|
@@ -7761,6 +7784,7 @@ class InstanceStore {
|
|
|
7761
7784
|
remove(instanceId, accountId) {
|
|
7762
7785
|
if (!this.getOwned(instanceId, accountId))
|
|
7763
7786
|
return false;
|
|
7787
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id = ?", [instanceId]);
|
|
7764
7788
|
this.db.run("DELETE FROM instances WHERE id = ?", [instanceId]);
|
|
7765
7789
|
return true;
|
|
7766
7790
|
}
|
|
@@ -7809,6 +7833,9 @@ function toDto(r) {
|
|
|
7809
7833
|
text: r.text,
|
|
7810
7834
|
createdAt: r.created_at,
|
|
7811
7835
|
...r.queue_item_id ? { queueItemId: r.queue_item_id } : {},
|
|
7836
|
+
...typeof r.started_at === "number" ? { startedAt: r.started_at } : {},
|
|
7837
|
+
...typeof r.slot_after_id === "number" ? { slotAfterId: r.slot_after_id } : {},
|
|
7838
|
+
...typeof r.started_after_seq === "number" ? { startedAfterSeq: r.started_after_seq } : {},
|
|
7812
7839
|
...r.structured ? { structured: JSON.parse(r.structured) } : {},
|
|
7813
7840
|
...r.attachments ? { attachments: JSON.parse(r.attachments) } : {}
|
|
7814
7841
|
};
|
|
@@ -7821,8 +7848,8 @@ class MessageStore {
|
|
|
7821
7848
|
this.db = db;
|
|
7822
7849
|
this.now = now;
|
|
7823
7850
|
}
|
|
7824
|
-
append(instanceId, sessionAlias, direction, text, structured, attachments, promptRequestId, createdAt) {
|
|
7825
|
-
this.db.run("INSERT INTO messages (instance_id, session_alias, direction, text, created_at, structured, attachments, prompt_request_id) VALUES (
|
|
7851
|
+
append(instanceId, sessionAlias, direction, text, structured, attachments, promptRequestId, createdAt, startedAt, slotAfterId, startedAfterSeq) {
|
|
7852
|
+
this.db.run("INSERT INTO messages (instance_id, session_alias, direction, text, created_at, structured, attachments, prompt_request_id, started_at, slot_after_id, started_after_seq) VALUES (?,?,?,?,?,?,?,?,?,?,?)", [
|
|
7826
7853
|
instanceId,
|
|
7827
7854
|
sessionAlias,
|
|
7828
7855
|
direction,
|
|
@@ -7830,7 +7857,10 @@ class MessageStore {
|
|
|
7830
7857
|
createdAt ?? this.now().toISOString(),
|
|
7831
7858
|
structured ? JSON.stringify(structured) : null,
|
|
7832
7859
|
attachments && attachments.length > 0 ? JSON.stringify(attachments) : null,
|
|
7833
|
-
promptRequestId ?? null
|
|
7860
|
+
promptRequestId ?? null,
|
|
7861
|
+
startedAt ?? null,
|
|
7862
|
+
slotAfterId ?? null,
|
|
7863
|
+
startedAfterSeq ?? null
|
|
7834
7864
|
]);
|
|
7835
7865
|
return this.db.get("SELECT last_insert_rowid() AS id").id;
|
|
7836
7866
|
}
|
|
@@ -7938,7 +7968,7 @@ class MessageStore {
|
|
|
7938
7968
|
listBySession(accountId, instanceId, sessionAlias, opts = {}) {
|
|
7939
7969
|
const limit = opts.limit ?? 100;
|
|
7940
7970
|
const before = opts.before ?? null;
|
|
7941
|
-
const rows = this.db.all(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured, m.attachments, m.queue_item_id
|
|
7971
|
+
const rows = this.db.all(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured, m.attachments, m.queue_item_id, m.started_at, m.slot_after_id, m.started_after_seq
|
|
7942
7972
|
FROM messages m JOIN instances i ON i.id = m.instance_id
|
|
7943
7973
|
WHERE i.account_id = ? AND m.instance_id = ? AND m.session_alias = ?
|
|
7944
7974
|
AND (? IS NULL OR m.id < ?)
|
|
@@ -7951,11 +7981,14 @@ class MessageStore {
|
|
|
7951
7981
|
};
|
|
7952
7982
|
}
|
|
7953
7983
|
getById(accountId, instanceId, sessionAlias, id) {
|
|
7954
|
-
const row = this.db.get(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured, m.attachments, m.queue_item_id
|
|
7984
|
+
const row = this.db.get(`SELECT m.id, m.instance_id, m.session_alias, m.direction, m.text, m.created_at, m.structured, m.attachments, m.queue_item_id, m.started_at, m.slot_after_id, m.started_after_seq
|
|
7955
7985
|
FROM messages m JOIN instances i ON i.id = m.instance_id
|
|
7956
7986
|
WHERE i.account_id = ? AND m.instance_id = ? AND m.session_alias = ? AND m.id = ?`, [accountId, instanceId, sessionAlias, id]);
|
|
7957
7987
|
return row ? toDto(row) : null;
|
|
7958
7988
|
}
|
|
7989
|
+
lastId(instanceId, sessionAlias) {
|
|
7990
|
+
return this.db.get("SELECT id FROM messages WHERE instance_id = ? AND session_alias = ? ORDER BY id DESC LIMIT 1", [instanceId, sessionAlias])?.id;
|
|
7991
|
+
}
|
|
7959
7992
|
deleteBySession(instanceId, sessionAlias) {
|
|
7960
7993
|
const before = this.db.get("SELECT COUNT(*) AS n FROM messages WHERE instance_id = ? AND session_alias = ?", [instanceId, sessionAlias]);
|
|
7961
7994
|
this.db.run("DELETE FROM messages WHERE instance_id = ? AND session_alias = ?", [instanceId, sessionAlias]);
|
|
@@ -8065,6 +8098,75 @@ class RecoveryReceiptStore {
|
|
|
8065
8098
|
}
|
|
8066
8099
|
}
|
|
8067
8100
|
|
|
8101
|
+
// packages/relay/src/stores/turn-slot-anchors.ts
|
|
8102
|
+
var LEGACY_RECOVERY_ID_PREFIX = "\x00legacy:";
|
|
8103
|
+
function canonicalRecoveryId(sessionAlias, recoveryId) {
|
|
8104
|
+
return typeof recoveryId === "string" && recoveryId.length > 0 ? recoveryId : `${LEGACY_RECOVERY_ID_PREFIX}${sessionAlias}`;
|
|
8105
|
+
}
|
|
8106
|
+
|
|
8107
|
+
class TurnSlotAnchorStore {
|
|
8108
|
+
db;
|
|
8109
|
+
constructor(db) {
|
|
8110
|
+
this.db = db;
|
|
8111
|
+
}
|
|
8112
|
+
put(row) {
|
|
8113
|
+
this.db.run(`INSERT INTO turn_slot_anchors (
|
|
8114
|
+
instance_id, session_alias, recovery_id, slot_after_id, started_at, started_after_seq
|
|
8115
|
+
) VALUES (?,?,?,?,?,?)
|
|
8116
|
+
ON CONFLICT(instance_id, recovery_id) DO UPDATE SET
|
|
8117
|
+
session_alias = excluded.session_alias,
|
|
8118
|
+
slot_after_id = excluded.slot_after_id,
|
|
8119
|
+
started_at = excluded.started_at,
|
|
8120
|
+
started_after_seq = excluded.started_after_seq`, [
|
|
8121
|
+
row.instanceId,
|
|
8122
|
+
row.sessionAlias,
|
|
8123
|
+
row.recoveryId,
|
|
8124
|
+
row.slotAfterId,
|
|
8125
|
+
row.startedAt ?? null,
|
|
8126
|
+
row.startedAfterSeq ?? null
|
|
8127
|
+
]);
|
|
8128
|
+
}
|
|
8129
|
+
get(instanceId, recoveryId) {
|
|
8130
|
+
return this.toAnchor(this.db.get(`SELECT instance_id, session_alias, recovery_id, slot_after_id, started_at, started_after_seq
|
|
8131
|
+
FROM turn_slot_anchors WHERE instance_id = ? AND recovery_id = ?`, [instanceId, recoveryId]));
|
|
8132
|
+
}
|
|
8133
|
+
take(instanceId, sessionAlias, recoveryId) {
|
|
8134
|
+
const id = canonicalRecoveryId(sessionAlias, recoveryId);
|
|
8135
|
+
const row = this.get(instanceId, id);
|
|
8136
|
+
if (!row)
|
|
8137
|
+
return;
|
|
8138
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id = ? AND recovery_id = ?", [row.instanceId, row.recoveryId]);
|
|
8139
|
+
return row;
|
|
8140
|
+
}
|
|
8141
|
+
retain(instanceId, keepRecoveryIds) {
|
|
8142
|
+
if (keepRecoveryIds.size === 0) {
|
|
8143
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id = ?", [instanceId]);
|
|
8144
|
+
return;
|
|
8145
|
+
}
|
|
8146
|
+
const ids = [...keepRecoveryIds];
|
|
8147
|
+
const placeholders = ids.map(() => "?").join(",");
|
|
8148
|
+
this.db.run(`DELETE FROM turn_slot_anchors WHERE instance_id = ? AND recovery_id NOT IN (${placeholders})`, [instanceId, ...ids]);
|
|
8149
|
+
}
|
|
8150
|
+
deleteBySession(instanceId, sessionAlias) {
|
|
8151
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id = ? AND session_alias = ?", [instanceId, sessionAlias]);
|
|
8152
|
+
}
|
|
8153
|
+
deleteByInstance(instanceId) {
|
|
8154
|
+
this.db.run("DELETE FROM turn_slot_anchors WHERE instance_id = ?", [instanceId]);
|
|
8155
|
+
}
|
|
8156
|
+
toAnchor(row) {
|
|
8157
|
+
if (!row)
|
|
8158
|
+
return;
|
|
8159
|
+
return {
|
|
8160
|
+
instanceId: row.instance_id,
|
|
8161
|
+
sessionAlias: row.session_alias,
|
|
8162
|
+
recoveryId: row.recovery_id,
|
|
8163
|
+
slotAfterId: row.slot_after_id,
|
|
8164
|
+
...typeof row.started_at === "number" ? { startedAt: row.started_at } : {},
|
|
8165
|
+
...typeof row.started_after_seq === "number" ? { startedAfterSeq: row.started_after_seq } : {}
|
|
8166
|
+
};
|
|
8167
|
+
}
|
|
8168
|
+
}
|
|
8169
|
+
|
|
8068
8170
|
// packages/relay/src/gateway/instance-gateway.ts
|
|
8069
8171
|
import {
|
|
8070
8172
|
MSG,
|
|
@@ -10107,7 +10209,10 @@ function createApp(deps) {
|
|
|
10107
10209
|
});
|
|
10108
10210
|
app.delete("/api/instances/:id", (c) => {
|
|
10109
10211
|
const account = c.get("account");
|
|
10110
|
-
const
|
|
10212
|
+
const instanceId = c.req.param("id");
|
|
10213
|
+
const removed = deps.instances.remove(instanceId, account.id);
|
|
10214
|
+
if (removed)
|
|
10215
|
+
deps.turnSlotAnchors?.deleteByInstance(instanceId);
|
|
10111
10216
|
return removed ? c.json({ ok: true }) : c.json({ error: "not-found" }, 404);
|
|
10112
10217
|
});
|
|
10113
10218
|
app.get("/api/agent-directory", (c) => {
|
|
@@ -10286,6 +10391,7 @@ function createApp(deps) {
|
|
|
10286
10391
|
}
|
|
10287
10392
|
if (removeInput && !isErrorPayload2(result)) {
|
|
10288
10393
|
deps.messages.deleteBySession(instance.id, removeInput.alias);
|
|
10394
|
+
deps.turnSlotAnchors?.deleteBySession(instance.id, removeInput.alias);
|
|
10289
10395
|
}
|
|
10290
10396
|
if (body.type === MSG3.commandExecute) {
|
|
10291
10397
|
const p = payload;
|
|
@@ -10523,6 +10629,7 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10523
10629
|
}
|
|
10524
10630
|
};
|
|
10525
10631
|
const recoveryReceipts = new RecoveryReceiptStore(db);
|
|
10632
|
+
const slotAnchors = new TurnSlotAnchorStore(db);
|
|
10526
10633
|
const sessionUsage = new Map;
|
|
10527
10634
|
const listSessionUsage = (instanceId) => {
|
|
10528
10635
|
const prefix = `${instanceId}\x00`;
|
|
@@ -10556,7 +10663,8 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10556
10663
|
sessionAlias: k.slice(prefix.length),
|
|
10557
10664
|
parts: a.parts,
|
|
10558
10665
|
status: a.text ? "streaming" : "working",
|
|
10559
|
-
startedAt: a.startedAt
|
|
10666
|
+
startedAt: a.startedAt,
|
|
10667
|
+
...typeof a.slotAfterId === "number" ? { slotAfterId: a.slotAfterId } : {}
|
|
10560
10668
|
});
|
|
10561
10669
|
}
|
|
10562
10670
|
return out;
|
|
@@ -10668,6 +10776,48 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10668
10776
|
messages.append(instanceId, sessionAlias, "in", opts.prompt, opts.scheduled ? { scheduled: opts.scheduled } : undefined);
|
|
10669
10777
|
}
|
|
10670
10778
|
};
|
|
10779
|
+
const rememberAnchor = (sessionAlias, slot, recoveryId) => {
|
|
10780
|
+
slotAnchors.put({
|
|
10781
|
+
instanceId,
|
|
10782
|
+
sessionAlias,
|
|
10783
|
+
recoveryId: canonicalRecoveryId(sessionAlias, recoveryId),
|
|
10784
|
+
slotAfterId: slot.slotAfterId,
|
|
10785
|
+
...slot.startedAt !== undefined ? { startedAt: slot.startedAt } : {},
|
|
10786
|
+
...slot.startedAfterSeq !== undefined ? { startedAfterSeq: slot.startedAfterSeq } : {}
|
|
10787
|
+
});
|
|
10788
|
+
};
|
|
10789
|
+
const snapshotSlotAfterReconcile = (sessionAlias, extras = {}) => ({
|
|
10790
|
+
slotAfterId: messages.lastId(instanceId, sessionAlias) ?? 0,
|
|
10791
|
+
...extras.startedAt !== undefined ? { startedAt: extras.startedAt } : {},
|
|
10792
|
+
...extras.startedAfterSeq !== undefined ? { startedAfterSeq: extras.startedAfterSeq } : {}
|
|
10793
|
+
});
|
|
10794
|
+
const resolveFinishSlot = (sessionAlias, opts) => {
|
|
10795
|
+
const stored = slotAnchors.take(instanceId, sessionAlias, opts.recoveryId);
|
|
10796
|
+
if (stored) {
|
|
10797
|
+
return {
|
|
10798
|
+
slotAfterId: stored.slotAfterId,
|
|
10799
|
+
startedAt: stored.startedAt ?? opts.startedAt,
|
|
10800
|
+
startedAfterSeq: stored.startedAfterSeq ?? opts.startedAfterSeq
|
|
10801
|
+
};
|
|
10802
|
+
}
|
|
10803
|
+
return snapshotSlotAfterReconcile(sessionAlias, { startedAt: opts.startedAt, startedAfterSeq: opts.startedAfterSeq });
|
|
10804
|
+
};
|
|
10805
|
+
const restoreRunningSlot = (sessionAlias, turn) => {
|
|
10806
|
+
const stored = slotAnchors.get(instanceId, canonicalRecoveryId(sessionAlias, turn.recoveryId));
|
|
10807
|
+
if (stored) {
|
|
10808
|
+
return {
|
|
10809
|
+
slotAfterId: stored.slotAfterId,
|
|
10810
|
+
startedAt: stored.startedAt ?? turn.startedAt,
|
|
10811
|
+
startedAfterSeq: stored.startedAfterSeq ?? turn.startedAfterSeq
|
|
10812
|
+
};
|
|
10813
|
+
}
|
|
10814
|
+
const slot = snapshotSlotAfterReconcile(sessionAlias, { startedAt: turn.startedAt, startedAfterSeq: turn.startedAfterSeq });
|
|
10815
|
+
rememberAnchor(sessionAlias, slot, turn.recoveryId);
|
|
10816
|
+
return slot;
|
|
10817
|
+
};
|
|
10818
|
+
const appendAssistantOut = (sessionAlias, text, structured, slot) => {
|
|
10819
|
+
messages.append(instanceId, sessionAlias, "out", text, structured, undefined, undefined, undefined, slot.startedAt, slot.slotAfterId, slot.startedAfterSeq);
|
|
10820
|
+
};
|
|
10671
10821
|
try {
|
|
10672
10822
|
if (envelope.type === MSG4.instanceEvent) {
|
|
10673
10823
|
const raw = envelope.payload?.event;
|
|
@@ -10682,7 +10832,7 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10682
10832
|
const e = raw;
|
|
10683
10833
|
return e.type === "tool-event" ? { ...e, step: capToolStep(e.step) } : e;
|
|
10684
10834
|
})();
|
|
10685
|
-
|
|
10835
|
+
let outbound = event;
|
|
10686
10836
|
if (event.type === "turn-started") {
|
|
10687
10837
|
const k = key(instanceId, event.sessionAlias);
|
|
10688
10838
|
let notification;
|
|
@@ -10699,21 +10849,35 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10699
10849
|
}
|
|
10700
10850
|
}
|
|
10701
10851
|
try {
|
|
10702
|
-
|
|
10852
|
+
let slot;
|
|
10853
|
+
db.transaction(() => {
|
|
10854
|
+
reconcileInboundPrompt(event.sessionAlias, { prompt: event.prompt, queueItemId: event.queueItemId, scheduled: event.scheduled, promptRequestId: event.promptRequestId }, true);
|
|
10855
|
+
slot = snapshotSlotAfterReconcile(event.sessionAlias, {
|
|
10856
|
+
startedAt: nowMs(),
|
|
10857
|
+
startedAfterSeq: event.startedAfterSeq
|
|
10858
|
+
});
|
|
10859
|
+
rememberAnchor(event.sessionAlias, slot, event.recoveryId);
|
|
10860
|
+
});
|
|
10861
|
+
const startedAt = slot.startedAt ?? nowMs();
|
|
10703
10862
|
turnBuffers.set(k, {
|
|
10704
10863
|
text: "",
|
|
10705
10864
|
steps: new Map,
|
|
10706
10865
|
reasoning: "",
|
|
10707
10866
|
parts: [],
|
|
10708
|
-
startedAt
|
|
10867
|
+
startedAt,
|
|
10868
|
+
slotAfterId: slot.slotAfterId,
|
|
10869
|
+
...slot.startedAfterSeq !== undefined ? { startedAfterSeq: slot.startedAfterSeq } : {},
|
|
10709
10870
|
...notification ? { notification } : {}
|
|
10710
10871
|
});
|
|
10872
|
+
outbound = { ...event, slotAfterId: slot.slotAfterId };
|
|
10711
10873
|
} catch (err) {
|
|
10712
10874
|
turnBuffers.delete(k);
|
|
10713
10875
|
gateway.disconnect(instanceId);
|
|
10714
10876
|
throw err;
|
|
10715
10877
|
}
|
|
10716
|
-
}
|
|
10878
|
+
}
|
|
10879
|
+
webGateway.broadcast(accountId, { kind: "control-event", instanceId, event: outbound });
|
|
10880
|
+
if (event.type === "turn-output") {
|
|
10717
10881
|
const a = turnBuffers.get(key(instanceId, event.sessionAlias));
|
|
10718
10882
|
if (a) {
|
|
10719
10883
|
a.text += event.chunk;
|
|
@@ -10738,10 +10902,19 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10738
10902
|
const promptRequestId = a?.notification?.promptRequestId;
|
|
10739
10903
|
const flush = () => {
|
|
10740
10904
|
if (!a) {
|
|
10905
|
+
if (event.silent && (event.text === undefined || event.text === "")) {
|
|
10906
|
+
slotAnchors.take(instanceId, event.sessionAlias, event.recoveryId);
|
|
10907
|
+
return;
|
|
10908
|
+
}
|
|
10909
|
+
const slot = resolveFinishSlot(event.sessionAlias, {
|
|
10910
|
+
recoveryId: event.recoveryId,
|
|
10911
|
+
startedAfterSeq: event.startedAfterSeq,
|
|
10912
|
+
startedAt: event.startedAt
|
|
10913
|
+
});
|
|
10741
10914
|
if (event.text !== undefined) {
|
|
10742
|
-
|
|
10915
|
+
appendAssistantOut(event.sessionAlias, event.text, undefined, slot);
|
|
10743
10916
|
} else if (!event.ok && event.errorMessage !== undefined) {
|
|
10744
|
-
|
|
10917
|
+
appendAssistantOut(event.sessionAlias, event.errorMessage, undefined, slot);
|
|
10745
10918
|
} else {
|
|
10746
10919
|
logger.warn("relay.event.turn_finished_without_content", "turn finished with no buffered content", {
|
|
10747
10920
|
instanceId,
|
|
@@ -10754,9 +10927,20 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10754
10927
|
const hasReasoning = a.reasoning.trim().length > 0;
|
|
10755
10928
|
const hasStructured = steps.length > 0 || hasReasoning;
|
|
10756
10929
|
const text = a.text || (!event.ok && event.errorMessage !== undefined ? event.errorMessage : a.text);
|
|
10930
|
+
if (event.silent && !hasStructured && text === "") {
|
|
10931
|
+
slotAnchors.take(instanceId, event.sessionAlias, event.recoveryId);
|
|
10932
|
+
return;
|
|
10933
|
+
}
|
|
10757
10934
|
if (hasStructured || text !== "" || event.ok) {
|
|
10758
10935
|
const structured = hasStructured ? { toolSteps: steps, ...hasReasoning ? { reasoning: a.reasoning } : {}, ...a.parts.length ? { parts: a.parts } : {}, ...a.truncated ? { truncated: true } : {} } : a.truncated ? { truncated: true } : undefined;
|
|
10759
|
-
|
|
10936
|
+
slotAnchors.take(instanceId, event.sessionAlias, event.recoveryId);
|
|
10937
|
+
appendAssistantOut(event.sessionAlias, text, structured, {
|
|
10938
|
+
slotAfterId: a.slotAfterId,
|
|
10939
|
+
startedAt: a.startedAt,
|
|
10940
|
+
startedAfterSeq: a.startedAfterSeq
|
|
10941
|
+
});
|
|
10942
|
+
} else {
|
|
10943
|
+
slotAnchors.take(instanceId, event.sessionAlias, event.recoveryId);
|
|
10760
10944
|
}
|
|
10761
10945
|
};
|
|
10762
10946
|
const recoveryId = event.recoveryId;
|
|
@@ -10879,7 +11063,14 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10879
11063
|
}, false);
|
|
10880
11064
|
}
|
|
10881
11065
|
if (text !== undefined && !alreadyPersisted) {
|
|
10882
|
-
|
|
11066
|
+
const slot = resolveFinishSlot(finished.sessionAlias, {
|
|
11067
|
+
recoveryId: finished.recoveryId,
|
|
11068
|
+
startedAfterSeq: finished.startedAfterSeq,
|
|
11069
|
+
startedAt: finished.startedAt
|
|
11070
|
+
});
|
|
11071
|
+
appendAssistantOut(finished.sessionAlias, text, finished.truncated ? { truncated: true } : undefined, slot);
|
|
11072
|
+
} else {
|
|
11073
|
+
slotAnchors.take(instanceId, finished.sessionAlias, finished.recoveryId);
|
|
10883
11074
|
}
|
|
10884
11075
|
};
|
|
10885
11076
|
if (recoveryId) {
|
|
@@ -10963,6 +11154,17 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10963
11154
|
reasoning,
|
|
10964
11155
|
parts,
|
|
10965
11156
|
startedAt: turn.startedAt,
|
|
11157
|
+
...(() => {
|
|
11158
|
+
const slot = restoreRunningSlot(turn.sessionAlias, {
|
|
11159
|
+
recoveryId: turn.recoveryId,
|
|
11160
|
+
startedAfterSeq: turn.startedAfterSeq,
|
|
11161
|
+
startedAt: turn.startedAt
|
|
11162
|
+
});
|
|
11163
|
+
return {
|
|
11164
|
+
slotAfterId: slot.slotAfterId,
|
|
11165
|
+
...slot.startedAfterSeq !== undefined ? { startedAfterSeq: slot.startedAfterSeq } : {}
|
|
11166
|
+
};
|
|
11167
|
+
})(),
|
|
10966
11168
|
...turn.truncated ? { truncated: true } : {},
|
|
10967
11169
|
...notification ? { notification } : {}
|
|
10968
11170
|
});
|
|
@@ -10973,6 +11175,12 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
10973
11175
|
for (const entry of sync.commands) {
|
|
10974
11176
|
sessionCommands.set(key(instanceId, entry.sessionAlias), entry.commands);
|
|
10975
11177
|
}
|
|
11178
|
+
const keepAnchors = new Set;
|
|
11179
|
+
for (const turn of sync.turns)
|
|
11180
|
+
keepAnchors.add(canonicalRecoveryId(turn.sessionAlias, turn.recoveryId));
|
|
11181
|
+
for (const finished of sync.finishedOffline)
|
|
11182
|
+
keepAnchors.add(canonicalRecoveryId(finished.sessionAlias, finished.recoveryId));
|
|
11183
|
+
slotAnchors.retain(instanceId, keepAnchors);
|
|
10976
11184
|
webGateway.broadcast(accountId, { kind: "state-snapshot", instanceId, ...stateSnapshot(instanceId) });
|
|
10977
11185
|
} catch (err) {
|
|
10978
11186
|
gateway.disconnect(instanceId);
|
|
@@ -11022,7 +11230,8 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
11022
11230
|
},
|
|
11023
11231
|
onWebPromptSessionCleared: (instanceId, sessionAlias) => {
|
|
11024
11232
|
clearPendingForSession(instanceId, sessionAlias);
|
|
11025
|
-
}
|
|
11233
|
+
},
|
|
11234
|
+
turnSlotAnchors: slotAnchors
|
|
11026
11235
|
});
|
|
11027
11236
|
const completionRouteSweepTimer = setInterval(() => gateway.sweepExpiredCompletionRoutes(), 60 * 60000);
|
|
11028
11237
|
completionRouteSweepTimer.unref?.();
|
|
@@ -11032,6 +11241,7 @@ async function createRelayRuntime(dbPath, options = {}) {
|
|
|
11032
11241
|
instances,
|
|
11033
11242
|
messages,
|
|
11034
11243
|
recoveryReceipts,
|
|
11244
|
+
slotAnchors,
|
|
11035
11245
|
pushSubscriptions,
|
|
11036
11246
|
pushNotifier,
|
|
11037
11247
|
gateway,
|
package/dist/http/app.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { type LiveTurnSnapshotDto, type PublishedAgentEndpointDto, type SessionC
|
|
|
3
3
|
import type { AccountRow, AccountStore } from "../stores/accounts.js";
|
|
4
4
|
import type { InstanceStore } from "../stores/instances.js";
|
|
5
5
|
import type { MessageStore } from "../stores/messages.js";
|
|
6
|
+
import type { TurnSlotAnchorStore } from "../stores/turn-slot-anchors.js";
|
|
6
7
|
import type { PushSubscriptionStore } from "../stores/push-subscriptions.js";
|
|
7
8
|
import type { RelayLogger } from "../logging.js";
|
|
8
9
|
import { type UpdateCheck } from "../version.js";
|
|
@@ -17,6 +18,8 @@ export interface AppDeps {
|
|
|
17
18
|
instances: InstanceStore;
|
|
18
19
|
gateway: GatewayForApp;
|
|
19
20
|
messages: MessageStore;
|
|
21
|
+
/** Live-slot anchors; cleared when a session or instance is deleted. */
|
|
22
|
+
turnSlotAnchors?: TurnSlotAnchorStore;
|
|
20
23
|
/** Snapshot the in-flight turns for an instance (for the active-turns endpoint). */
|
|
21
24
|
activeTurns?: (instanceId: string) => LiveTurnSnapshotDto[];
|
|
22
25
|
/** Snapshot the latest per-session context-usage for an instance (for the active-turns endpoint). */
|
|
@@ -6,5 +6,7 @@ export declare const COMPACT_DETAIL_PREVIEW = 240;
|
|
|
6
6
|
* `parts` already carries them, and strip bulky tool bodies (diffs, command output,
|
|
7
7
|
* file previews). Collapsed cards keep titles/status plus a short subagent snippet.
|
|
8
8
|
* The full row is available from `GET .../messages/:id`.
|
|
9
|
+
* Top-level fields such as `startedAt`, `slotAfterId`, and `startedAfterSeq` are
|
|
10
|
+
* copied through unchanged — compact must not drop the durable slot anchor.
|
|
9
11
|
*/
|
|
10
12
|
export declare function compactHistoryMessage(row: MessageRecordDto): MessageRecordDto;
|