@ycodium-ai/plugin-im 0.2.3216 → 0.2.3220
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 +383 -191
- package/package.json +3 -2
package/dist/index.js
CHANGED
|
@@ -126258,67 +126258,96 @@ var keepNewest = (record4, limit) => {
|
|
|
126258
126258
|
return entries.length <= limit ? record4 : Object.fromEntries(entries.slice(entries.length - limit));
|
|
126259
126259
|
};
|
|
126260
126260
|
|
|
126261
|
-
// src/
|
|
126262
|
-
var
|
|
126263
|
-
const
|
|
126264
|
-
|
|
126265
|
-
|
|
126266
|
-
|
|
126267
|
-
|
|
126268
|
-
|
|
126269
|
-
|
|
126270
|
-
|
|
126271
|
-
if (oldest !== void 0) entries.delete(oldest);
|
|
126272
|
-
}
|
|
126273
|
-
},
|
|
126274
|
-
/** 忘掉键满足条件的那些。 */
|
|
126275
|
-
forget: (matches) => {
|
|
126276
|
-
for (const key of [...entries.keys()]) if (matches(key)) entries.delete(key);
|
|
126261
|
+
// src/executionTurn.ts
|
|
126262
|
+
var indexExecution = (execution) => {
|
|
126263
|
+
const intentsByMessageId = /* @__PURE__ */ new Map();
|
|
126264
|
+
const intentsById = /* @__PURE__ */ new Map();
|
|
126265
|
+
const turnsById = /* @__PURE__ */ new Map();
|
|
126266
|
+
for (const intent of execution.turnIntents) {
|
|
126267
|
+
if (!intentsByMessageId.has(intent.messageId)) intentsByMessageId.set(intent.messageId, intent);
|
|
126268
|
+
if (!intentsById.has(intent.intentId)) intentsById.set(intent.intentId, intent);
|
|
126269
|
+
if (intent.turn?.turnId != null && !turnsById.has(intent.turn.turnId)) {
|
|
126270
|
+
turnsById.set(intent.turn.turnId, intent.turn);
|
|
126277
126271
|
}
|
|
126278
|
-
}
|
|
126272
|
+
}
|
|
126273
|
+
if (execution.latestTurn != null && !turnsById.has(execution.latestTurn.turnId)) {
|
|
126274
|
+
turnsById.set(execution.latestTurn.turnId, execution.latestTurn);
|
|
126275
|
+
}
|
|
126276
|
+
return { execution, intentsByMessageId, intentsById, turnsById };
|
|
126279
126277
|
};
|
|
126278
|
+
var executionTurnFor = (snapshot, turnId) => snapshot.turnsById.get(turnId);
|
|
126280
126279
|
|
|
126281
|
-
// src/
|
|
126282
|
-
var
|
|
126283
|
-
|
|
126284
|
-
|
|
126285
|
-
var
|
|
126286
|
-
|
|
126287
|
-
const
|
|
126288
|
-
|
|
126280
|
+
// src/intentStatus.ts
|
|
126281
|
+
var isLiveIntentStatus = (status) => status === "queued" || status === "preparing" || status === "dispatching" || status === "running" || status === "reconciling" || status === "blocked";
|
|
126282
|
+
|
|
126283
|
+
// src/conclusionTurn.ts
|
|
126284
|
+
var conclusionOf = (turn) => turn.state === "completed" || turn.state === "interrupted" || turn.state === "error" ? { kind: "settled", ...turn, state: turn.state } : { kind: "pending" };
|
|
126285
|
+
var conclusionTurnFor = (snapshot, userMessageId) => {
|
|
126286
|
+
const { execution } = snapshot;
|
|
126287
|
+
const initial = snapshot.intentsByMessageId.get(userMessageId);
|
|
126288
|
+
if (initial === void 0) {
|
|
126289
|
+
const latest = execution.latestTurn;
|
|
126290
|
+
return latest?.userMessageId === userMessageId ? conclusionOf(latest) : { kind: "gone" };
|
|
126291
|
+
}
|
|
126292
|
+
let intent = initial;
|
|
126293
|
+
const visited = /* @__PURE__ */ new Set();
|
|
126294
|
+
while (intent.status === "cancelled" || intent.status === "abandoned") {
|
|
126295
|
+
if (visited.has(intent.intentId)) return { kind: "gone" };
|
|
126296
|
+
visited.add(intent.intentId);
|
|
126297
|
+
const replacementId = intent.replacementIntentId;
|
|
126298
|
+
const replacement = replacementId == null ? void 0 : snapshot.intentsById.get(replacementId);
|
|
126299
|
+
if (replacement === void 0) return { kind: "gone" };
|
|
126300
|
+
intent = replacement;
|
|
126301
|
+
}
|
|
126302
|
+
const action = intent.action;
|
|
126303
|
+
const turn = intent.turn;
|
|
126304
|
+
if (action?.kind === "steer" && intent.deliveredTurnId === action.turnId) {
|
|
126305
|
+
return {
|
|
126306
|
+
kind: "merged",
|
|
126307
|
+
turnId: action.turnId,
|
|
126308
|
+
turn: executionTurnFor(snapshot, action.turnId)
|
|
126309
|
+
};
|
|
126310
|
+
}
|
|
126311
|
+
if (turn !== null) return conclusionOf(turn);
|
|
126312
|
+
if (action?.kind === "steer") return { kind: "pending" };
|
|
126313
|
+
return { kind: isLiveIntentStatus(intent.status) ? "pending" : "gone" };
|
|
126289
126314
|
};
|
|
126290
|
-
var
|
|
126291
|
-
const
|
|
126292
|
-
|
|
126293
|
-
|
|
126294
|
-
|
|
126295
|
-
|
|
126296
|
-
|
|
126297
|
-
|
|
126315
|
+
var groupConclusionDebts = (snapshot, threadId, debts) => {
|
|
126316
|
+
const resolved = new Map(
|
|
126317
|
+
debts.filter((debt) => debt.threadId === threadId).map((debt) => [
|
|
126318
|
+
debt.userMessageId,
|
|
126319
|
+
{ debt, result: conclusionTurnFor(snapshot, debt.userMessageId) }
|
|
126320
|
+
])
|
|
126321
|
+
);
|
|
126322
|
+
const byTurn = /* @__PURE__ */ new Map();
|
|
126323
|
+
for (const { debt, result: result2 } of resolved.values()) {
|
|
126324
|
+
if (result2.kind !== "settled" && result2.kind !== "merged") continue;
|
|
126325
|
+
const group = byTurn.get(result2.turnId) ?? [];
|
|
126326
|
+
group.push(debt);
|
|
126327
|
+
byTurn.set(result2.turnId, group);
|
|
126328
|
+
}
|
|
126329
|
+
for (const [turnId, candidates] of byTurn) {
|
|
126330
|
+
const ownerId = turnId === null ? void 0 : executionTurnFor(snapshot, turnId)?.userMessageId;
|
|
126331
|
+
const owner = ownerId === void 0 ? void 0 : resolved.get(ownerId);
|
|
126332
|
+
if (owner !== void 0 && owner.result.kind !== "gone" && !candidates.includes(owner.debt))
|
|
126333
|
+
candidates.push(owner.debt);
|
|
126334
|
+
}
|
|
126335
|
+
return { resolved, byTurn };
|
|
126336
|
+
};
|
|
126337
|
+
var conclusionDebtForTurn = (snapshot, turnId, candidates, isDelivered) => {
|
|
126338
|
+
const turn = turnId === null ? void 0 : executionTurnFor(snapshot, turnId);
|
|
126339
|
+
const own = candidates.find((debt2) => debt2.userMessageId === turn?.userMessageId);
|
|
126340
|
+
const handled = turn?.userMessageId !== void 0 && isDelivered(turn.userMessageId) || candidates.length === 0 && snapshot.execution.turnIntents.some((intent) => {
|
|
126341
|
+
if (!isDelivered(intent.messageId)) return false;
|
|
126342
|
+
const result2 = conclusionTurnFor(snapshot, intent.messageId);
|
|
126343
|
+
return (result2.kind === "merged" || result2.kind === "settled") && result2.turnId === turnId;
|
|
126344
|
+
});
|
|
126345
|
+
const debt = handled ? void 0 : own ?? candidates[0];
|
|
126298
126346
|
return {
|
|
126299
|
-
|
|
126300
|
-
|
|
126301
|
-
|
|
126302
|
-
|
|
126303
|
-
note: (threadId, userMessageId, binding) => {
|
|
126304
|
-
if (binding.reply === void 0) return;
|
|
126305
|
-
const turns = byThread.get(threadId) ?? makeBoundedMap(TURNS_PER_THREAD);
|
|
126306
|
-
byThread.set(threadId, turns);
|
|
126307
|
-
turns.set(userMessageId, { chatKey: chatKeyOf(binding), anchor: binding.reply });
|
|
126308
|
-
},
|
|
126309
|
-
/**
|
|
126310
|
-
* 给发往这条会话的聊天挂上 `turnId` 那一轮的锚点(null 的含义见上);取不到就原样返回。
|
|
126311
|
-
*
|
|
126312
|
-
* 锚点只配给它那条消息所在的聊天:会话可以被另一个聊天接走(`/resume`),而回复接口只按被
|
|
126313
|
-
* 回复的消息寻址,挂错了答复就发回原来的聊天。
|
|
126314
|
-
*/
|
|
126315
|
-
anchored: async (binding, threadId, turnId) => {
|
|
126316
|
-
const turns = byThread.get(threadId);
|
|
126317
|
-
if (turns === void 0) return binding;
|
|
126318
|
-
const asked = await userMessageOfTurn(threadId, turnId);
|
|
126319
|
-
const noted = asked === void 0 ? void 0 : turns.get(asked);
|
|
126320
|
-
return noted?.chatKey === chatKeyOf(binding) ? { ...binding, reply: noted.anchor } : binding;
|
|
126321
|
-
}
|
|
126347
|
+
debt,
|
|
126348
|
+
handled,
|
|
126349
|
+
userMessageId: turn?.userMessageId,
|
|
126350
|
+
redundant: candidates.filter((candidate) => candidate !== debt)
|
|
126322
126351
|
};
|
|
126323
126352
|
};
|
|
126324
126353
|
|
|
@@ -126336,11 +126365,14 @@ var foldConclusionEvent = (state, name, data) => {
|
|
|
126336
126365
|
const pending = conclusionDebtsOf(state);
|
|
126337
126366
|
if (name === "conclusion-delivered") {
|
|
126338
126367
|
const { [key]: _delivered, ...rest } = pending;
|
|
126368
|
+
const turnUserMessageId = data["turnUserMessageId"];
|
|
126369
|
+
const turnKey2 = typeof turnUserMessageId === "string" && turnUserMessageId !== "" ? keyOf(threadId, turnUserMessageId) : key;
|
|
126370
|
+
const { [turnKey2]: _turnDelivered, ...remaining } = rest;
|
|
126339
126371
|
return {
|
|
126340
126372
|
...state,
|
|
126341
|
-
conclusions:
|
|
126373
|
+
conclusions: remaining,
|
|
126342
126374
|
deliveredConclusions: keepNewest(
|
|
126343
|
-
{ ...state.deliveredConclusions, [key]: true },
|
|
126375
|
+
{ ...state.deliveredConclusions, [key]: true, [turnKey2]: true },
|
|
126344
126376
|
CONCLUSION_DEBT_LIMIT
|
|
126345
126377
|
)
|
|
126346
126378
|
};
|
|
@@ -126368,13 +126400,35 @@ var makeConclusionLedger = (core) => {
|
|
|
126368
126400
|
core.host.onDispose(() => {
|
|
126369
126401
|
disposed = true;
|
|
126370
126402
|
});
|
|
126371
|
-
const settle = (debt) => {
|
|
126403
|
+
const settle = ({ debt, turnUserMessageId }) => {
|
|
126372
126404
|
core.commit("conclusion-delivered", {
|
|
126373
126405
|
threadId: debt.threadId,
|
|
126374
|
-
userMessageId: debt.userMessageId
|
|
126406
|
+
userMessageId: debt.userMessageId,
|
|
126407
|
+
...turnUserMessageId !== void 0 && turnUserMessageId !== debt.userMessageId ? { turnUserMessageId } : {}
|
|
126375
126408
|
});
|
|
126376
126409
|
};
|
|
126410
|
+
const forExecutionTurn = (snapshot, threadId, turnId, grouped) => {
|
|
126411
|
+
if (disposed) return { selection: void 0, handled: true };
|
|
126412
|
+
const pending = conclusionDebtsOf(core.state);
|
|
126413
|
+
const candidates = (grouped ?? groupConclusionDebts(snapshot, threadId, Object.values(pending))).byTurn.get(turnId);
|
|
126414
|
+
const currentCandidates = candidates?.filter(
|
|
126415
|
+
(debt) => pending[keyOf(threadId, debt.userMessageId)] !== void 0
|
|
126416
|
+
);
|
|
126417
|
+
if (currentCandidates?.length === 0) return { selection: void 0, handled: true };
|
|
126418
|
+
const selected = conclusionDebtForTurn(
|
|
126419
|
+
snapshot,
|
|
126420
|
+
turnId,
|
|
126421
|
+
currentCandidates ?? [],
|
|
126422
|
+
(messageId) => delivered(keyOf(threadId, messageId))
|
|
126423
|
+
);
|
|
126424
|
+
for (const debt of selected.redundant) settle({ debt, turnUserMessageId: void 0 });
|
|
126425
|
+
return {
|
|
126426
|
+
selection: selected.debt === void 0 ? void 0 : { debt: selected.debt, turnUserMessageId: selected.userMessageId },
|
|
126427
|
+
handled: selected.handled || selected.debt !== void 0 && inFlight.has(keyOf(threadId, selected.debt.userMessageId))
|
|
126428
|
+
};
|
|
126429
|
+
};
|
|
126377
126430
|
return {
|
|
126431
|
+
forExecutionTurn,
|
|
126378
126432
|
starting: (threadId) => {
|
|
126379
126433
|
const gate = Promise.withResolvers();
|
|
126380
126434
|
const pending = registering.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
@@ -126409,15 +126463,17 @@ var makeConclusionLedger = (core) => {
|
|
|
126409
126463
|
forTurn: async (threadId, turnId = null) => {
|
|
126410
126464
|
await Promise.all(registering.get(threadId) ?? []);
|
|
126411
126465
|
const execution = await core.host.projections.getThreadExecution(threadId);
|
|
126412
|
-
const userMessageId = execution === null ? void 0 : turnId === null ? execution.latestTurn?.userMessageId : userMessageIdOfTurn(execution, turnId);
|
|
126413
|
-
const key = userMessageId === void 0 ? void 0 : keyOf(threadId, userMessageId);
|
|
126414
126466
|
return {
|
|
126415
|
-
|
|
126416
|
-
|
|
126417
|
-
|
|
126467
|
+
execution,
|
|
126468
|
+
...execution === null ? { selection: void 0, handled: false } : forExecutionTurn(
|
|
126469
|
+
indexExecution(execution),
|
|
126470
|
+
threadId,
|
|
126471
|
+
turnId ?? execution.latestTurn?.turnId ?? null
|
|
126472
|
+
)
|
|
126418
126473
|
};
|
|
126419
126474
|
},
|
|
126420
|
-
deliver: async (
|
|
126475
|
+
deliver: async (selection, send) => {
|
|
126476
|
+
const { debt } = selection;
|
|
126421
126477
|
const key = keyOf(debt.threadId, debt.userMessageId);
|
|
126422
126478
|
if (disposed || delivered(key) || inFlight.has(key) || conclusionDebtsOf(core.state)[key] === void 0)
|
|
126423
126479
|
return false;
|
|
@@ -126426,16 +126482,17 @@ var makeConclusionLedger = (core) => {
|
|
|
126426
126482
|
const sent = await send(
|
|
126427
126483
|
() => !delivered(key) && conclusionDebtsOf(core.state)[key] !== void 0
|
|
126428
126484
|
);
|
|
126429
|
-
if (sent) settle(
|
|
126485
|
+
if (sent) settle(selection);
|
|
126430
126486
|
return sent;
|
|
126431
126487
|
} finally {
|
|
126432
126488
|
inFlight.delete(key);
|
|
126433
126489
|
}
|
|
126434
126490
|
},
|
|
126435
|
-
discard: (
|
|
126491
|
+
discard: (selection) => {
|
|
126492
|
+
const { debt } = selection;
|
|
126436
126493
|
const key = keyOf(debt.threadId, debt.userMessageId);
|
|
126437
126494
|
if (!disposed && !delivered(key) && !inFlight.has(key) && conclusionDebtsOf(core.state)[key] !== void 0) {
|
|
126438
|
-
settle(
|
|
126495
|
+
settle(selection);
|
|
126439
126496
|
}
|
|
126440
126497
|
}
|
|
126441
126498
|
};
|
|
@@ -127450,6 +127507,26 @@ var makeChatQueue = (core) => {
|
|
|
127450
127507
|
// src/chatSetup.ts
|
|
127451
127508
|
import { threadOrNull } from "@ycodium-ai/plugin-api";
|
|
127452
127509
|
|
|
127510
|
+
// src/boundedMap.ts
|
|
127511
|
+
var makeBoundedMap = (limit) => {
|
|
127512
|
+
const entries = /* @__PURE__ */ new Map();
|
|
127513
|
+
return {
|
|
127514
|
+
get: (key) => entries.get(key),
|
|
127515
|
+
set: (key, value2) => {
|
|
127516
|
+
entries.delete(key);
|
|
127517
|
+
entries.set(key, value2);
|
|
127518
|
+
if (entries.size > limit) {
|
|
127519
|
+
const oldest = entries.keys().next().value;
|
|
127520
|
+
if (oldest !== void 0) entries.delete(oldest);
|
|
127521
|
+
}
|
|
127522
|
+
},
|
|
127523
|
+
/** 忘掉键满足条件的那些。 */
|
|
127524
|
+
forget: (matches) => {
|
|
127525
|
+
for (const key of [...entries.keys()]) if (matches(key)) entries.delete(key);
|
|
127526
|
+
}
|
|
127527
|
+
};
|
|
127528
|
+
};
|
|
127529
|
+
|
|
127453
127530
|
// src/cooldown.ts
|
|
127454
127531
|
var makeCooldown = (windowMs, now, maxKeys = Number.POSITIVE_INFINITY) => {
|
|
127455
127532
|
const lastAt = /* @__PURE__ */ new Map();
|
|
@@ -133604,18 +133681,14 @@ var makeInboundStore = (input) => {
|
|
|
133604
133681
|
write(rowId, row);
|
|
133605
133682
|
return result2.promise;
|
|
133606
133683
|
};
|
|
133607
|
-
const
|
|
133684
|
+
const claimReceipt = (rowId, id, message, receivedAt = 0) => {
|
|
133608
133685
|
const row = rowOf(rowId);
|
|
133609
|
-
|
|
133610
|
-
try {
|
|
133611
|
-
assertReadable(row);
|
|
133612
|
-
} catch (error) {
|
|
133613
|
-
return Promise.reject(error);
|
|
133614
|
-
}
|
|
133686
|
+
assertReadable(row);
|
|
133615
133687
|
const pending = row.claims.get(id);
|
|
133616
|
-
if (pending !== void 0) return
|
|
133688
|
+
if (pending !== void 0) return { first: false, persisted: pending };
|
|
133617
133689
|
const seen = row.data.seenIds.includes(id);
|
|
133618
|
-
if (seen && (row.claimRevisions.get(id) ?? 0) <= row.persisted)
|
|
133690
|
+
if (seen && (row.claimRevisions.get(id) ?? 0) <= row.persisted)
|
|
133691
|
+
return { first: false, persisted: Promise.resolve() };
|
|
133619
133692
|
if (!seen) {
|
|
133620
133693
|
if (message !== void 0) {
|
|
133621
133694
|
const inbox = row.data.inbox ?? [];
|
|
@@ -133659,7 +133732,17 @@ var makeInboundStore = (input) => {
|
|
|
133659
133732
|
row.claims.delete(id);
|
|
133660
133733
|
};
|
|
133661
133734
|
void result2.then(forget, forget);
|
|
133662
|
-
return
|
|
133735
|
+
return { first: !seen, persisted: result2 };
|
|
133736
|
+
};
|
|
133737
|
+
const claim = (rowId, id, message, receivedAt = 0) => {
|
|
133738
|
+
const row = rowOf(rowId);
|
|
133739
|
+
if (!row.loaded) return load(rowId).then(() => claim(rowId, id, message, receivedAt));
|
|
133740
|
+
try {
|
|
133741
|
+
const receipt = claimReceipt(rowId, id, message, receivedAt);
|
|
133742
|
+
return receipt.persisted.then(() => receipt.first);
|
|
133743
|
+
} catch (error) {
|
|
133744
|
+
return Promise.reject(error);
|
|
133745
|
+
}
|
|
133663
133746
|
};
|
|
133664
133747
|
const removeEntry = (rowId, key, failure2) => {
|
|
133665
133748
|
const row = rowOf(rowId);
|
|
@@ -133785,6 +133868,7 @@ var makeInboundStore = (input) => {
|
|
|
133785
133868
|
return {
|
|
133786
133869
|
load,
|
|
133787
133870
|
claim,
|
|
133871
|
+
claimReceipt,
|
|
133788
133872
|
get: (rowId, key) => {
|
|
133789
133873
|
const row = rowOf(rowId);
|
|
133790
133874
|
assertReadable(row);
|
|
@@ -133822,6 +133906,8 @@ var makeInboundStore = (input) => {
|
|
|
133822
133906
|
assertReadable(row);
|
|
133823
133907
|
if (row.data.inbox !== void 0)
|
|
133824
133908
|
row.data.inbox = row.data.inbox.filter((e) => e.key !== key);
|
|
133909
|
+
row.data.seenIds = row.data.seenIds.filter((id) => id !== key);
|
|
133910
|
+
row.claimRevisions.delete(key);
|
|
133825
133911
|
row.revision++;
|
|
133826
133912
|
},
|
|
133827
133913
|
reset,
|
|
@@ -133962,7 +134048,9 @@ var startConnections = (core, inboundHandlersFor, inboundState, recovery) => {
|
|
|
133962
134048
|
...inbound,
|
|
133963
134049
|
// 停用先封接收,保持发送连接直到已接收工作 drain 完成。
|
|
133964
134050
|
onMessage: (message) => {
|
|
133965
|
-
if (
|
|
134051
|
+
if (closed || disposed)
|
|
134052
|
+
return Promise.reject(new Error("inbound connection is closed"));
|
|
134053
|
+
return inbound.onMessage(message);
|
|
133966
134054
|
},
|
|
133967
134055
|
onButton: (...args2) => closed || disposed ? null : inbound.onButton(...args2),
|
|
133968
134056
|
onPanelClick: (click) => closed || disposed ? null : inbound.onPanelClick?.(click) ?? null,
|
|
@@ -135109,6 +135197,45 @@ var makeGreetings = (core, enqueueForChat, now) => {
|
|
|
135109
135197
|
};
|
|
135110
135198
|
};
|
|
135111
135199
|
|
|
135200
|
+
// src/replyAnchors.ts
|
|
135201
|
+
var THREAD_LIMIT = 256;
|
|
135202
|
+
var TURNS_PER_THREAD = 16;
|
|
135203
|
+
var anchorOfMessage = (adapter, message) => adapter?.quotesReplies === true ? { messageId: message.messageId, inThread: message.replyInThread === true } : void 0;
|
|
135204
|
+
var makeReplyAnchors = (host) => {
|
|
135205
|
+
const byThread = makeBoundedMap(THREAD_LIMIT);
|
|
135206
|
+
const userMessageOfTurn = async (threadId, turnId) => {
|
|
135207
|
+
const execution = await host.projections.getThreadExecution(threadId).catch(() => null);
|
|
135208
|
+
if (execution === null) return void 0;
|
|
135209
|
+
const wanted = turnId ?? execution.session?.activeTurnId ?? execution.latestTurn?.turnId;
|
|
135210
|
+
return wanted == null ? void 0 : executionTurnFor(indexExecution(execution), wanted)?.userMessageId;
|
|
135211
|
+
};
|
|
135212
|
+
return {
|
|
135213
|
+
/**
|
|
135214
|
+
* 开轮时记一笔:`userMessageId` 是派给宿主的那条用户消息,`binding` 是收到聊天消息的那个
|
|
135215
|
+
* 聊天(带着它的锚点)。没有锚点(平台不引用)就不记。
|
|
135216
|
+
*/
|
|
135217
|
+
note: (threadId, userMessageId, binding) => {
|
|
135218
|
+
if (binding.reply === void 0) return;
|
|
135219
|
+
const turns = byThread.get(threadId) ?? makeBoundedMap(TURNS_PER_THREAD);
|
|
135220
|
+
byThread.set(threadId, turns);
|
|
135221
|
+
turns.set(userMessageId, { chatKey: chatKeyOf(binding), anchor: binding.reply });
|
|
135222
|
+
},
|
|
135223
|
+
/**
|
|
135224
|
+
* 给发往这条会话的聊天挂上 `turnId` 那一轮的锚点(null 的含义见上);取不到就原样返回。
|
|
135225
|
+
*
|
|
135226
|
+
* 锚点只配给它那条消息所在的聊天:会话可以被另一个聊天接走(`/resume`),而回复接口只按被
|
|
135227
|
+
* 回复的消息寻址,挂错了答复就发回原来的聊天。
|
|
135228
|
+
*/
|
|
135229
|
+
anchored: async (binding, threadId, turnId) => {
|
|
135230
|
+
const turns = byThread.get(threadId);
|
|
135231
|
+
if (turns === void 0) return binding;
|
|
135232
|
+
const asked = await userMessageOfTurn(threadId, turnId);
|
|
135233
|
+
const noted = asked === void 0 ? void 0 : turns.get(asked);
|
|
135234
|
+
return noted?.chatKey === chatKeyOf(binding) ? { ...binding, reply: noted.anchor } : binding;
|
|
135235
|
+
}
|
|
135236
|
+
};
|
|
135237
|
+
};
|
|
135238
|
+
|
|
135112
135239
|
// src/inbound.ts
|
|
135113
135240
|
var ARCHIVED_REPLY_COOLDOWN_MS = 10 * 6e4;
|
|
135114
135241
|
var UNSUPPORTED_REPLY_COOLDOWN_MS = 6e4;
|
|
@@ -135336,40 +135463,44 @@ var makeInbound = (core, deps) => {
|
|
|
135336
135463
|
noteChatAlias: (alias, chatId) => noteChatAlias(bot, alias, chatId),
|
|
135337
135464
|
knowsChatAlias: (alias) => chatAliasOf(core.state, bot.rowId, alias) !== void 0,
|
|
135338
135465
|
onGreeting: (chatId, senderId) => greet(bot.rowId, chatId, senderId),
|
|
135339
|
-
onMessage: (received) => {
|
|
135466
|
+
onMessage: async (received) => {
|
|
135340
135467
|
const current = currentBot(bot.rowId);
|
|
135341
|
-
if (!accepting || current === void 0)
|
|
135468
|
+
if (!accepting || current === void 0) throw new Error("inbound is not accepting messages");
|
|
135342
135469
|
const message = settleChat(current, received);
|
|
135343
135470
|
const work = workForMessage(message);
|
|
135344
|
-
|
|
135471
|
+
const adapter = adapterFor(current.platform);
|
|
135345
135472
|
let saved;
|
|
135346
135473
|
try {
|
|
135347
|
-
saved = persistInbound(
|
|
135474
|
+
saved = persistInbound(adapter, message);
|
|
135348
135475
|
} catch (error) {
|
|
135349
135476
|
host.log.warn("chat could not serialize inbound; processing without restart protection", {
|
|
135350
135477
|
rowId: current.rowId,
|
|
135351
135478
|
error: describeError(error)
|
|
135352
135479
|
});
|
|
135353
135480
|
}
|
|
135481
|
+
const claim = inboundState.claimReceipt(current.rowId, work.key, saved, now());
|
|
135482
|
+
if (!claim.first) return claim.persisted;
|
|
135483
|
+
const receipt = claim.persisted.catch((error) => {
|
|
135484
|
+
inboundState.abandon(current.rowId, work.key);
|
|
135485
|
+
host.log.warn(
|
|
135486
|
+
adapter?.redeliversUnacknowledged ? "chat could not save inbound state; waiting for platform redelivery" : "chat could not save inbound state; processing without restart protection",
|
|
135487
|
+
{ rowId: current.rowId, error: describeError(error) }
|
|
135488
|
+
);
|
|
135489
|
+
throw error;
|
|
135490
|
+
});
|
|
135491
|
+
const enqueue = () => {
|
|
135492
|
+
const arrived = bindingOf2(current, message.chatId);
|
|
135493
|
+
if (message.chatKind !== void 0 && chatOf(core.state, chatKeyOf(arrived)).chatKind !== message.chatKind) {
|
|
135494
|
+
commit("chat-updated", { chatKey: chatKeyOf(arrived), chatKind: message.chatKind });
|
|
135495
|
+
}
|
|
135496
|
+
enqueueForChat(chatKeyOf(arrived), () => resumeMessage(current, message, work));
|
|
135497
|
+
};
|
|
135354
135498
|
track(
|
|
135355
|
-
|
|
135356
|
-
()
|
|
135357
|
-
},
|
|
135358
|
-
(error) => {
|
|
135359
|
-
inboundState.abandon(current.rowId, work.key);
|
|
135360
|
-
host.log.warn(
|
|
135361
|
-
"chat could not save inbound state; processing without restart protection",
|
|
135362
|
-
{ rowId: current.rowId, error: describeError(error) }
|
|
135363
|
-
);
|
|
135364
|
-
}
|
|
135365
|
-
).then(() => {
|
|
135366
|
-
const arrived = bindingOf2(current, message.chatId);
|
|
135367
|
-
if (message.chatKind !== void 0 && chatOf(core.state, chatKeyOf(arrived)).chatKind !== message.chatKind) {
|
|
135368
|
-
commit("chat-updated", { chatKey: chatKeyOf(arrived), chatKind: message.chatKind });
|
|
135369
|
-
}
|
|
135370
|
-
enqueueForChat(chatKeyOf(arrived), () => resumeMessage(current, message, work));
|
|
135499
|
+
receipt.then(enqueue, () => {
|
|
135500
|
+
if (!adapter?.redeliversUnacknowledged) enqueue();
|
|
135371
135501
|
})
|
|
135372
135502
|
);
|
|
135503
|
+
return receipt;
|
|
135373
135504
|
}
|
|
135374
135505
|
});
|
|
135375
135506
|
const replay = makeInboxReplay(
|
|
@@ -135803,14 +135934,6 @@ var queueCardOf = (record4, view, note, t) => {
|
|
|
135803
135934
|
var queueViewKey = (view, note) => JSON.stringify([view, note]);
|
|
135804
135935
|
|
|
135805
135936
|
// src/queueFlow.ts
|
|
135806
|
-
var LIVE_STATUSES = /* @__PURE__ */ new Set([
|
|
135807
|
-
"queued",
|
|
135808
|
-
"preparing",
|
|
135809
|
-
"dispatching",
|
|
135810
|
-
"running",
|
|
135811
|
-
"reconciling",
|
|
135812
|
-
"blocked"
|
|
135813
|
-
]);
|
|
135814
135937
|
var makeQueueFlow = (host, deps) => {
|
|
135815
135938
|
const { t } = host;
|
|
135816
135939
|
const shown = /* @__PURE__ */ new Map();
|
|
@@ -135834,7 +135957,7 @@ var makeQueueFlow = (host, deps) => {
|
|
|
135834
135957
|
const intent = execution?.intents.find((entry) => entry.messageId === messageId);
|
|
135835
135958
|
if (execution === null || intent === void 0 || intent.status !== "queued") return;
|
|
135836
135959
|
const waiting = execution.activeTurnId !== null || execution.queuePaused || execution.intents.some(
|
|
135837
|
-
(other) => other.intentId !== intent.intentId &&
|
|
135960
|
+
(other) => other.intentId !== intent.intentId && isLiveIntentStatus(other.status) && other.sequence < intent.sequence
|
|
135838
135961
|
);
|
|
135839
135962
|
if (!waiting) return;
|
|
135840
135963
|
const cards = target2.adapter.choiceCards;
|
|
@@ -144071,7 +144194,7 @@ var cardActionOperator = (event) => {
|
|
|
144071
144194
|
};
|
|
144072
144195
|
var startLarkInbound = (input) => {
|
|
144073
144196
|
const dispatcher = new import_node_sdk.EventDispatcher({}).register({
|
|
144074
|
-
"im.message.receive_v1": (event) => {
|
|
144197
|
+
"im.message.receive_v1": async (event) => {
|
|
144075
144198
|
const mode = input.groupMention ?? "always";
|
|
144076
144199
|
const parse = (groupMention) => parseInboundMessage(
|
|
144077
144200
|
event,
|
|
@@ -144081,17 +144204,16 @@ var startLarkInbound = (input) => {
|
|
|
144081
144204
|
);
|
|
144082
144205
|
const parsed = parse(mode);
|
|
144083
144206
|
if (parsed !== null) {
|
|
144084
|
-
input.onMessage(parsed);
|
|
144207
|
+
await input.onMessage(parsed);
|
|
144085
144208
|
return {};
|
|
144086
144209
|
}
|
|
144087
144210
|
const chat = event.message;
|
|
144088
144211
|
if (mode === "always" && input.isSoloGroup !== void 0 && chat?.chat_type !== "p2p") {
|
|
144089
144212
|
const chatId = chat?.chat_id;
|
|
144090
144213
|
if (typeof chatId === "string") {
|
|
144091
|
-
|
|
144092
|
-
|
|
144093
|
-
|
|
144094
|
-
});
|
|
144214
|
+
const solo = await input.isSoloGroup(chatId).catch(() => false);
|
|
144215
|
+
const relaxed = solo ? parse("never") : null;
|
|
144216
|
+
if (relaxed !== null) await input.onMessage(relaxed);
|
|
144095
144217
|
}
|
|
144096
144218
|
}
|
|
144097
144219
|
return {};
|
|
@@ -144670,10 +144792,12 @@ var makeLarkAdapter = (deps) => {
|
|
|
144670
144792
|
};
|
|
144671
144793
|
const soloGroupFor = (context2) => async (chatId) => {
|
|
144672
144794
|
const info = await context2.chatInfo(chatId);
|
|
144673
|
-
|
|
144795
|
+
if (info?.userCount === void 0 || info.botCount === void 0) return false;
|
|
144796
|
+
return info.userCount <= 1 && info.botCount <= 1;
|
|
144674
144797
|
};
|
|
144675
144798
|
return {
|
|
144676
144799
|
platform: "lark",
|
|
144800
|
+
redeliversUnacknowledged: true,
|
|
144677
144801
|
...larkInboundPersistence((rowId) => messageContexts.get(rowId)?.context),
|
|
144678
144802
|
botIdentity: (bot) => larkCredentials(bot).appId,
|
|
144679
144803
|
icon: "lark",
|
|
@@ -144781,15 +144905,27 @@ var makeLarkAdapter = (deps) => {
|
|
|
144781
144905
|
const key = JSON.stringify([message.chatId, topic?.threadId]);
|
|
144782
144906
|
const earlier = pendingDeliveries.get(key);
|
|
144783
144907
|
if (earlier === void 0 && pending === null && reference2 === null && !(prepared instanceof Promise) && !(source instanceof Promise)) {
|
|
144784
|
-
deliver(prepared, source);
|
|
144908
|
+
return deliver(prepared, source);
|
|
144785
144909
|
} else {
|
|
144786
|
-
const completed = Promise.all([
|
|
144910
|
+
const completed = Promise.all([
|
|
144911
|
+
earlier?.catch(() => {
|
|
144912
|
+
}),
|
|
144913
|
+
pending,
|
|
144914
|
+
reference2,
|
|
144915
|
+
source,
|
|
144916
|
+
prepared
|
|
144917
|
+
]).then(([, , replyTo, names, ready]) => {
|
|
144787
144918
|
if (pendingDeliveries.get(key) === completed) pendingDeliveries.delete(key);
|
|
144788
|
-
if (open)
|
|
144789
|
-
|
|
144919
|
+
if (!open) throw new Error("lark inbound connection is closed");
|
|
144920
|
+
return deliver(ready, names, replyTo ?? void 0);
|
|
144921
|
+
}).catch((error) => {
|
|
144922
|
+
handlers.onError(describeError(error));
|
|
144923
|
+
throw error;
|
|
144924
|
+
}).finally(() => {
|
|
144790
144925
|
if (pendingDeliveries.get(key) === completed) pendingDeliveries.delete(key);
|
|
144791
144926
|
});
|
|
144792
144927
|
pendingDeliveries.set(key, completed);
|
|
144928
|
+
return completed;
|
|
144793
144929
|
}
|
|
144794
144930
|
}
|
|
144795
144931
|
});
|
|
@@ -146643,13 +146779,13 @@ var makeModelPlan = (core, deps) => {
|
|
|
146643
146779
|
import { readThreadFailed, threadOrNull as threadOrNull5 } from "@ycodium-ai/plugin-api";
|
|
146644
146780
|
|
|
146645
146781
|
// src/conclusionOutbox.ts
|
|
146646
|
-
var enqueueConclusion = (core, ledger, binding,
|
|
146782
|
+
var enqueueConclusion = (core, ledger, binding, selection, send) => core.outbound(
|
|
146647
146783
|
chatKeyOf(binding),
|
|
146648
146784
|
async () => {
|
|
146649
|
-
if (
|
|
146650
|
-
else await ledger.deliver(
|
|
146785
|
+
if (selection === void 0) await send();
|
|
146786
|
+
else await ledger.deliver(selection, send);
|
|
146651
146787
|
},
|
|
146652
|
-
{ droppable:
|
|
146788
|
+
{ droppable: selection !== void 0 }
|
|
146653
146789
|
);
|
|
146654
146790
|
|
|
146655
146791
|
// src/conclusionRecovery.ts
|
|
@@ -146665,60 +146801,100 @@ var makeConclusionRecovery = (core, ledger, delivery, failures) => {
|
|
|
146665
146801
|
error: describeError(error)
|
|
146666
146802
|
});
|
|
146667
146803
|
};
|
|
146668
|
-
const
|
|
146804
|
+
const recoverThread = async (threadId, debts, requestedMessageId) => {
|
|
146669
146805
|
await core.ready;
|
|
146670
146806
|
if (disposed) return;
|
|
146671
146807
|
try {
|
|
146672
|
-
const execution = await core.host.projections.getThreadExecution(
|
|
146808
|
+
const execution = await core.host.projections.getThreadExecution(threadId);
|
|
146673
146809
|
if (disposed) return;
|
|
146674
146810
|
if (execution === null) {
|
|
146675
|
-
|
|
146676
|
-
|
|
146677
|
-
|
|
146678
|
-
|
|
146679
|
-
if (latest?.userMessageId !== debt.userMessageId) {
|
|
146680
|
-
core.host.log.info("chat discarded a conclusion whose turn is no longer latest", {
|
|
146681
|
-
...debt
|
|
146682
|
-
});
|
|
146683
|
-
ledger.discard(debt);
|
|
146684
|
-
return;
|
|
146685
|
-
}
|
|
146686
|
-
if (latest.state === "running" || execution.session?.activeTurnId != null) return;
|
|
146687
|
-
if (latest.completedAt !== null && Date.parse(latest.completedAt) < Date.now() - MAX_AGE_MS) {
|
|
146688
|
-
core.host.log.info("chat discarded a conclusion older than seven days", { ...debt });
|
|
146689
|
-
ledger.discard(debt);
|
|
146811
|
+
for (const debt of debts) {
|
|
146812
|
+
if (requestedMessageId === void 0 || debt.userMessageId === requestedMessageId)
|
|
146813
|
+
ledger.discard({ debt, turnUserMessageId: void 0 });
|
|
146814
|
+
}
|
|
146690
146815
|
return;
|
|
146691
146816
|
}
|
|
146692
|
-
const
|
|
146693
|
-
|
|
146694
|
-
|
|
146695
|
-
|
|
146696
|
-
|
|
146697
|
-
|
|
146698
|
-
|
|
146699
|
-
debt
|
|
146700
|
-
|
|
146701
|
-
|
|
146702
|
-
latest.turnId,
|
|
146703
|
-
owed
|
|
146704
|
-
);
|
|
146817
|
+
const snapshot = indexExecution(execution);
|
|
146818
|
+
const grouped = groupConclusionDebts(snapshot, threadId, debts);
|
|
146819
|
+
const { resolved, byTurn } = grouped;
|
|
146820
|
+
for (const { debt, result: result2 } of resolved.values()) {
|
|
146821
|
+
if (result2.kind === "gone") {
|
|
146822
|
+
if (requestedMessageId === void 0 || debt.userMessageId === requestedMessageId) {
|
|
146823
|
+
core.host.log.info("chat discarded a conclusion whose message has no turn", {
|
|
146824
|
+
...debt
|
|
146825
|
+
});
|
|
146826
|
+
ledger.discard({ debt, turnUserMessageId: void 0 });
|
|
146705
146827
|
}
|
|
146706
|
-
const send = await delivery.prepareConclusion(debt.threadId, latest.turnId);
|
|
146707
|
-
return send(binding, { recovered: true, streaming: false, owed });
|
|
146708
|
-
} catch (error) {
|
|
146709
|
-
couldNotRecover(debt, error);
|
|
146710
|
-
return false;
|
|
146711
146828
|
}
|
|
146712
|
-
}
|
|
146829
|
+
}
|
|
146830
|
+
const requested = requestedMessageId === void 0 ? void 0 : resolved.get(requestedMessageId)?.result;
|
|
146831
|
+
for (const turnId of byTurn.keys()) {
|
|
146832
|
+
if (requestedMessageId !== void 0 && (requested?.kind !== "settled" && requested?.kind !== "merged" || requested.turnId !== turnId))
|
|
146833
|
+
continue;
|
|
146834
|
+
const { selection, handled } = ledger.forExecutionTurn(snapshot, threadId, turnId, grouped);
|
|
146835
|
+
if (handled || selection === void 0 || requestedMessageId !== void 0 && selection.debt.userMessageId !== requestedMessageId)
|
|
146836
|
+
continue;
|
|
146837
|
+
const result2 = resolved.get(selection.debt.userMessageId).result;
|
|
146838
|
+
if (result2.kind === "pending" || result2.kind === "gone") continue;
|
|
146839
|
+
recoverTurn(selection, result2.kind === "settled" ? result2 : result2.turn, execution);
|
|
146840
|
+
}
|
|
146713
146841
|
} catch (error) {
|
|
146714
|
-
couldNotRecover(debt, error);
|
|
146842
|
+
for (const debt of debts) couldNotRecover(debt, error);
|
|
146715
146843
|
}
|
|
146716
146844
|
};
|
|
146845
|
+
const recoverTurn = (selection, turn, execution) => {
|
|
146846
|
+
const { debt } = selection;
|
|
146847
|
+
if (turn === void 0 || turn.state === "pending" || turn.state === "running" || execution.session?.activeTurnId === turn.turnId)
|
|
146848
|
+
return;
|
|
146849
|
+
if (turn.completedAt !== null && Date.parse(turn.completedAt) < Date.now() - MAX_AGE_MS) {
|
|
146850
|
+
core.host.log.info("chat discarded a conclusion older than seven days", { ...debt });
|
|
146851
|
+
ledger.discard(selection);
|
|
146852
|
+
return;
|
|
146853
|
+
}
|
|
146854
|
+
const binding = core.bindingForChatKey(selection.debt.chatKey);
|
|
146855
|
+
if (binding === void 0) return;
|
|
146856
|
+
enqueueConclusion(core, ledger, binding, selection, async (owed) => {
|
|
146857
|
+
try {
|
|
146858
|
+
if (turn.state === "error") {
|
|
146859
|
+
const detail = execution.latestTurn?.state === "error" && execution.latestTurn.turnId === turn.turnId ? execution.session?.lastError : void 0;
|
|
146860
|
+
return delivery.sendText(
|
|
146861
|
+
binding,
|
|
146862
|
+
debt.threadId,
|
|
146863
|
+
failures.forFailure(debt.threadId, detail),
|
|
146864
|
+
true,
|
|
146865
|
+
turn.turnId,
|
|
146866
|
+
owed
|
|
146867
|
+
);
|
|
146868
|
+
}
|
|
146869
|
+
const send = await delivery.prepareConclusion(debt.threadId, turn.turnId);
|
|
146870
|
+
return send(binding, { recovered: true, streaming: false, owed });
|
|
146871
|
+
} catch (error) {
|
|
146872
|
+
couldNotRecover(debt, error);
|
|
146873
|
+
return false;
|
|
146874
|
+
}
|
|
146875
|
+
});
|
|
146876
|
+
};
|
|
146877
|
+
const recoverConclusion = async (debt) => {
|
|
146878
|
+
await core.ready;
|
|
146879
|
+
await recoverThread(
|
|
146880
|
+
debt.threadId,
|
|
146881
|
+
Object.values(conclusionDebtsOf(core.state)).filter(
|
|
146882
|
+
(candidate) => candidate.threadId === debt.threadId
|
|
146883
|
+
),
|
|
146884
|
+
debt.userMessageId
|
|
146885
|
+
);
|
|
146886
|
+
};
|
|
146717
146887
|
const recoverConclusions = async () => {
|
|
146718
146888
|
await core.ready;
|
|
146889
|
+
const byThread = /* @__PURE__ */ new Map();
|
|
146719
146890
|
for (const debt of Object.values(conclusionDebtsOf(core.state))) {
|
|
146891
|
+
const group = byThread.get(debt.threadId) ?? [];
|
|
146892
|
+
group.push(debt);
|
|
146893
|
+
byThread.set(debt.threadId, group);
|
|
146894
|
+
}
|
|
146895
|
+
for (const [threadId, debts] of byThread) {
|
|
146720
146896
|
if (disposed) return;
|
|
146721
|
-
await
|
|
146897
|
+
await recoverThread(threadId, debts);
|
|
146722
146898
|
}
|
|
146723
146899
|
};
|
|
146724
146900
|
return { recoverConclusion, recoverConclusions };
|
|
@@ -146799,14 +146975,14 @@ var makeNotifications = (core, deps) => {
|
|
|
146799
146975
|
await ready;
|
|
146800
146976
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
146801
146977
|
const owes = Object.values(conclusionDebtsOf(core.state)).some(
|
|
146802
|
-
(
|
|
146978
|
+
(debt) => debt.threadId === threadId
|
|
146803
146979
|
);
|
|
146804
|
-
const {
|
|
146805
|
-
if (
|
|
146806
|
-
const binding = bindingForChatKey(debt.chatKey);
|
|
146980
|
+
const { selection, handled, execution } = said || owes || targets.length > 0 ? await conclusions.forTurn(threadId) : { selection: void 0, handled: false, execution: null };
|
|
146981
|
+
if (selection !== void 0) {
|
|
146982
|
+
const binding = bindingForChatKey(selection.debt.chatKey);
|
|
146807
146983
|
if (binding !== void 0 && !streamsTo(binding, threadId) && execution?.session?.activeTurnId == null && execution?.latestTurn?.state !== "running" && execution?.latestTurn?.state !== "error" && payload.session?.status !== "error") {
|
|
146808
146984
|
const turnId = execution?.latestTurn?.turnId ?? null;
|
|
146809
|
-
enqueueConclusion(core, conclusions, binding,
|
|
146985
|
+
enqueueConclusion(core, conclusions, binding, selection, async (owed) => {
|
|
146810
146986
|
const send = await delivery.prepareConclusion(threadId, turnId);
|
|
146811
146987
|
return send(binding, { recovered: false, streaming: false, owed });
|
|
146812
146988
|
});
|
|
@@ -146841,9 +147017,9 @@ var makeNotifications = (core, deps) => {
|
|
|
146841
147017
|
threadsWithSomethingToReport.delete(threadId);
|
|
146842
147018
|
await ready;
|
|
146843
147019
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
146844
|
-
const {
|
|
146845
|
-
const debtBinding =
|
|
146846
|
-
const recipients =
|
|
147020
|
+
const { selection, handled, execution } = await conclusions.forTurn(threadId);
|
|
147021
|
+
const debtBinding = selection === void 0 ? void 0 : bindingForChatKey(selection.debt.chatKey);
|
|
147022
|
+
const recipients = selection !== void 0 ? debtBinding === void 0 ? [] : [debtBinding] : targets;
|
|
146847
147023
|
const textTargets = handled ? [] : recipients.filter(
|
|
146848
147024
|
(binding) => !(streamsTo(binding, threadId) && turnCards.covers(threadId))
|
|
146849
147025
|
);
|
|
@@ -146854,7 +147030,7 @@ var makeNotifications = (core, deps) => {
|
|
|
146854
147030
|
if (notice !== null) {
|
|
146855
147031
|
for (const binding of textTargets) {
|
|
146856
147032
|
const send = (owed) => delivery.sendText(binding, threadId, notice, false, null, owed);
|
|
146857
|
-
enqueueConclusion(core, conclusions, binding,
|
|
147033
|
+
enqueueConclusion(core, conclusions, binding, selection, send);
|
|
146858
147034
|
}
|
|
146859
147035
|
}
|
|
146860
147036
|
for (const binding of targets) {
|
|
@@ -147844,10 +148020,10 @@ var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
|
147844
148020
|
onOpened: (card) => commit("turn-card-opened", card),
|
|
147845
148021
|
onClosed: (cardId) => commit("turn-card-closed", { cardId }),
|
|
147846
148022
|
finalize: async (threadId, turnId, chatKey, send) => {
|
|
147847
|
-
const {
|
|
148023
|
+
const { selection, handled } = await conclusions.forTurn(threadId, turnId);
|
|
147848
148024
|
if (handled) return true;
|
|
147849
|
-
if (
|
|
147850
|
-
if (!await conclusions.deliver(
|
|
148025
|
+
if (selection === void 0) return send();
|
|
148026
|
+
if (!await conclusions.deliver(selection, send)) return false;
|
|
147851
148027
|
const binding = bindingForChatKey(chatKey);
|
|
147852
148028
|
if (binding === void 0) return true;
|
|
147853
148029
|
const sendConclusion = await delivery.prepareConclusion(threadId, turnId);
|
|
@@ -147855,7 +148031,7 @@ var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
|
147855
148031
|
return true;
|
|
147856
148032
|
},
|
|
147857
148033
|
fallback: async (threadId, turnId, chatKey, view) => {
|
|
147858
|
-
const {
|
|
148034
|
+
const { selection, handled } = await conclusions.forTurn(threadId, turnId);
|
|
147859
148035
|
if (handled) return;
|
|
147860
148036
|
const binding = bindingForChatKey(chatKey);
|
|
147861
148037
|
if (binding === void 0) return;
|
|
@@ -147864,7 +148040,7 @@ var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
|
147864
148040
|
core,
|
|
147865
148041
|
conclusions,
|
|
147866
148042
|
binding,
|
|
147867
|
-
|
|
148043
|
+
selection,
|
|
147868
148044
|
(owed) => delivery.sendText(binding, threadId, text4, false, turnId, owed)
|
|
147869
148045
|
);
|
|
147870
148046
|
},
|
|
@@ -148996,6 +149172,7 @@ var makeTelegramAdapter = (deps) => {
|
|
|
148996
149172
|
});
|
|
148997
149173
|
return {
|
|
148998
149174
|
platform: "telegram",
|
|
149175
|
+
redeliversUnacknowledged: true,
|
|
148999
149176
|
botIdentity: tokenFingerprint,
|
|
149000
149177
|
icon: "telegram",
|
|
149001
149178
|
label: "Telegram",
|
|
@@ -149107,14 +149284,16 @@ var makeTelegramAdapter = (deps) => {
|
|
|
149107
149284
|
}
|
|
149108
149285
|
}
|
|
149109
149286
|
if (!running) break;
|
|
149110
|
-
advanceOffset(update);
|
|
149111
149287
|
const senderId = message.from === void 0 ? null : String(message.from.id);
|
|
149112
149288
|
const senderName2 = telegramDisplayName(message.from);
|
|
149113
149289
|
const chatKind = message.chat.type === "private" ? "private" : "group";
|
|
149114
149290
|
if (message.voice !== void 0 || text4 === "" && resource === null) {
|
|
149115
149291
|
const unsupported = unsupportedTypeOf(message);
|
|
149116
|
-
if (unsupported === null)
|
|
149117
|
-
|
|
149292
|
+
if (unsupported === null) {
|
|
149293
|
+
advanceOffset(update);
|
|
149294
|
+
continue;
|
|
149295
|
+
}
|
|
149296
|
+
await handlers.onMessage({
|
|
149118
149297
|
messageId: String(message.message_id),
|
|
149119
149298
|
chatId: chatIdOf(message),
|
|
149120
149299
|
senderId,
|
|
@@ -149123,11 +149302,13 @@ var makeTelegramAdapter = (deps) => {
|
|
|
149123
149302
|
resources: [],
|
|
149124
149303
|
unsupportedType: unsupported
|
|
149125
149304
|
});
|
|
149305
|
+
if (!running) break;
|
|
149306
|
+
advanceOffset(update);
|
|
149126
149307
|
continue;
|
|
149127
149308
|
}
|
|
149128
149309
|
const parentChatId = parentChatIdOf(message);
|
|
149129
149310
|
const replyTo = telegramReplyReference(message, botUsername, botId);
|
|
149130
|
-
handlers.onMessage({
|
|
149311
|
+
await handlers.onMessage({
|
|
149131
149312
|
messageId: String(message.message_id),
|
|
149132
149313
|
chatId: chatIdOf(message),
|
|
149133
149314
|
...parentChatId === void 0 ? {} : { parentChatId },
|
|
@@ -149147,6 +149328,8 @@ var makeTelegramAdapter = (deps) => {
|
|
|
149147
149328
|
}
|
|
149148
149329
|
]
|
|
149149
149330
|
});
|
|
149331
|
+
if (!running) break;
|
|
149332
|
+
advanceOffset(update);
|
|
149150
149333
|
}
|
|
149151
149334
|
} catch (error) {
|
|
149152
149335
|
if (!running) return;
|
|
@@ -149727,12 +149910,10 @@ var makeTurns = (core, deps) => {
|
|
|
149727
149910
|
);
|
|
149728
149911
|
if (!dispatched) return null;
|
|
149729
149912
|
topicRoot?.confirmConsumed();
|
|
149730
|
-
|
|
149731
|
-
|
|
149732
|
-
|
|
149733
|
-
|
|
149734
|
-
);
|
|
149735
|
-
}
|
|
149913
|
+
await deps.conclusions.owe(
|
|
149914
|
+
{ chatKey, threadId, userMessageId, recordedAt: (/* @__PURE__ */ new Date()).toISOString() },
|
|
149915
|
+
replayed ? deps.recoverConclusion : void 0
|
|
149916
|
+
);
|
|
149736
149917
|
} finally {
|
|
149737
149918
|
registered();
|
|
149738
149919
|
}
|
|
@@ -151167,7 +151348,7 @@ ${kept}`;
|
|
|
151167
151348
|
if (message.chatType !== "single") return;
|
|
151168
151349
|
client.rememberRequest(message.chatId, message.requestId);
|
|
151169
151350
|
client.rememberConversation(message.chatId, message.conversation);
|
|
151170
|
-
handlers.onMessage({
|
|
151351
|
+
void handlers.onMessage({
|
|
151171
151352
|
// 不保存短效 req_id:重启后的回话走新连接的 aibot_send_msg 主动发送,
|
|
151172
151353
|
// 不冒充原消息的回答,也不复用旧连接的 rememberRequest / 流状态。
|
|
151173
151354
|
messageId: message.messageId,
|
|
@@ -151184,6 +151365,10 @@ ${kept}`;
|
|
|
151184
151365
|
mimeType: resource.mimeType,
|
|
151185
151366
|
kind: resource.kind
|
|
151186
151367
|
}))
|
|
151368
|
+
}).catch((error) => {
|
|
151369
|
+
deps.log.warn("wecom could not persist inbound message", {
|
|
151370
|
+
error: describeError(error)
|
|
151371
|
+
});
|
|
151187
151372
|
});
|
|
151188
151373
|
}
|
|
151189
151374
|
}
|
|
@@ -152279,12 +152464,19 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
152279
152464
|
}
|
|
152280
152465
|
const messageId = message.msgid ?? `${chatId}:${message.createTime ?? Date.now()}`;
|
|
152281
152466
|
const base2 = { messageId, chatId, senderId: chatId };
|
|
152467
|
+
const receive = (inbound) => {
|
|
152468
|
+
void handlers.onMessage(inbound).catch((error) => {
|
|
152469
|
+
deps.log.warn("wecom-app could not persist inbound message", {
|
|
152470
|
+
error: describeError(error)
|
|
152471
|
+
});
|
|
152472
|
+
});
|
|
152473
|
+
};
|
|
152282
152474
|
if (message.msgtype === "text") {
|
|
152283
|
-
|
|
152475
|
+
receive({ ...base2, text: message.text?.content?.trim() ?? "", resources: [] });
|
|
152284
152476
|
return;
|
|
152285
152477
|
}
|
|
152286
152478
|
if (message.msgtype === "image" && message.mediaId !== void 0 && message.mediaId !== "") {
|
|
152287
|
-
|
|
152479
|
+
receive({
|
|
152288
152480
|
...base2,
|
|
152289
152481
|
text: "",
|
|
152290
152482
|
resources: [
|
|
@@ -152293,7 +152485,7 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
152293
152485
|
});
|
|
152294
152486
|
return;
|
|
152295
152487
|
}
|
|
152296
|
-
|
|
152488
|
+
receive({
|
|
152297
152489
|
...base2,
|
|
152298
152490
|
text: "",
|
|
152299
152491
|
resources: [],
|
|
@@ -152503,7 +152695,7 @@ var makeWecomAppAdapter = (deps) => {
|
|
|
152503
152695
|
// src/index.ts
|
|
152504
152696
|
var definition = {
|
|
152505
152697
|
id: "im",
|
|
152506
|
-
apiVersion:
|
|
152698
|
+
apiVersion: 23,
|
|
152507
152699
|
// 第二个参数只给插件自己的测试夹具:换掉文件 IO 与派发重试的等待。宿主只传 ctx。
|
|
152508
152700
|
activate: async (ctx, testing = {}) => {
|
|
152509
152701
|
const { dispatchSleep } = testing;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ycodium-ai/plugin-im",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.3220",
|
|
4
4
|
"description": "Talk to your agents from Telegram, WeCom, Lark, or WeChat (experimental).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"im",
|
|
@@ -32,7 +32,8 @@
|
|
|
32
32
|
"markdown-it": "^15.0.2",
|
|
33
33
|
"react": "19.2.6",
|
|
34
34
|
"vite-plus": "0.2.2",
|
|
35
|
-
"
|
|
35
|
+
"ycodium-react-test-harness": "0.0.0",
|
|
36
|
+
"@ycodium-ai/plugin-api": "0.2.3220"
|
|
36
37
|
},
|
|
37
38
|
"ycodium": {
|
|
38
39
|
"plugin": "./dist/index.js",
|