@ycodium-ai/plugin-im 0.2.3102 → 0.2.3112
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 +423 -169
- package/locales/en.json +1 -0
- package/locales/zh-CN.json +1 -0
- package/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -126254,6 +126254,169 @@ var keepNewest = (record3, limit) => {
|
|
|
126254
126254
|
return entries.length <= limit ? record3 : Object.fromEntries(entries.slice(entries.length - limit));
|
|
126255
126255
|
};
|
|
126256
126256
|
|
|
126257
|
+
// src/boundedMap.ts
|
|
126258
|
+
var makeBoundedMap = (limit) => {
|
|
126259
|
+
const entries = /* @__PURE__ */ new Map();
|
|
126260
|
+
return {
|
|
126261
|
+
get: (key) => entries.get(key),
|
|
126262
|
+
set: (key, value2) => {
|
|
126263
|
+
entries.delete(key);
|
|
126264
|
+
entries.set(key, value2);
|
|
126265
|
+
if (entries.size > limit) {
|
|
126266
|
+
const oldest = entries.keys().next().value;
|
|
126267
|
+
if (oldest !== void 0) entries.delete(oldest);
|
|
126268
|
+
}
|
|
126269
|
+
},
|
|
126270
|
+
/** 忘掉键满足条件的那些。 */
|
|
126271
|
+
forget: (matches) => {
|
|
126272
|
+
for (const key of [...entries.keys()]) if (matches(key)) entries.delete(key);
|
|
126273
|
+
}
|
|
126274
|
+
};
|
|
126275
|
+
};
|
|
126276
|
+
|
|
126277
|
+
// src/replyAnchors.ts
|
|
126278
|
+
var THREAD_LIMIT = 256;
|
|
126279
|
+
var TURNS_PER_THREAD = 16;
|
|
126280
|
+
var anchorOfMessage = (adapter, message) => adapter?.quotesReplies === true ? { messageId: message.messageId, inThread: message.replyInThread === true } : void 0;
|
|
126281
|
+
var userMessageIdOfTurn = (execution, turnId) => {
|
|
126282
|
+
const intent = execution.turnIntents.find((candidate) => candidate.turn?.turnId === turnId);
|
|
126283
|
+
const latest = execution.latestTurn;
|
|
126284
|
+
return intent?.messageId ?? (latest?.turnId === turnId ? latest.userMessageId : void 0);
|
|
126285
|
+
};
|
|
126286
|
+
var makeReplyAnchors = (host) => {
|
|
126287
|
+
const byThread = makeBoundedMap(THREAD_LIMIT);
|
|
126288
|
+
const userMessageOfTurn = async (threadId, turnId) => {
|
|
126289
|
+
const execution = await host.projections.getThreadExecution(threadId).catch(() => null);
|
|
126290
|
+
if (execution === null) return void 0;
|
|
126291
|
+
const wanted = turnId ?? execution.session?.activeTurnId ?? execution.latestTurn?.turnId;
|
|
126292
|
+
return wanted == null ? void 0 : userMessageIdOfTurn(execution, wanted);
|
|
126293
|
+
};
|
|
126294
|
+
return {
|
|
126295
|
+
/**
|
|
126296
|
+
* 开轮时记一笔:`userMessageId` 是派给宿主的那条用户消息,`binding` 是收到聊天消息的那个
|
|
126297
|
+
* 聊天(带着它的锚点)。没有锚点(平台不引用)就不记。
|
|
126298
|
+
*/
|
|
126299
|
+
note: (threadId, userMessageId, binding) => {
|
|
126300
|
+
if (binding.reply === void 0) return;
|
|
126301
|
+
const turns = byThread.get(threadId) ?? makeBoundedMap(TURNS_PER_THREAD);
|
|
126302
|
+
byThread.set(threadId, turns);
|
|
126303
|
+
turns.set(userMessageId, { chatKey: chatKeyOf(binding), anchor: binding.reply });
|
|
126304
|
+
},
|
|
126305
|
+
/**
|
|
126306
|
+
* 给发往这条会话的聊天挂上 `turnId` 那一轮的锚点(null 的含义见上);取不到就原样返回。
|
|
126307
|
+
*
|
|
126308
|
+
* 锚点只配给它那条消息所在的聊天:会话可以被另一个聊天接走(`/resume`),而回复接口只按被
|
|
126309
|
+
* 回复的消息寻址,挂错了答复就发回原来的聊天。
|
|
126310
|
+
*/
|
|
126311
|
+
anchored: async (binding, threadId, turnId) => {
|
|
126312
|
+
const turns = byThread.get(threadId);
|
|
126313
|
+
if (turns === void 0) return binding;
|
|
126314
|
+
const asked = await userMessageOfTurn(threadId, turnId);
|
|
126315
|
+
const noted = asked === void 0 ? void 0 : turns.get(asked);
|
|
126316
|
+
return noted?.chatKey === chatKeyOf(binding) ? { ...binding, reply: noted.anchor } : binding;
|
|
126317
|
+
}
|
|
126318
|
+
};
|
|
126319
|
+
};
|
|
126320
|
+
|
|
126321
|
+
// src/conclusionLedger.ts
|
|
126322
|
+
var CONCLUSION_DEBT_LIMIT = 500;
|
|
126323
|
+
var keyOf = (threadId, userMessageId) => JSON.stringify([threadId, userMessageId]);
|
|
126324
|
+
var conclusionDebtsOf = (state) => state.conclusions ?? {};
|
|
126325
|
+
var foldConclusionEvent = (state, name, data) => {
|
|
126326
|
+
const threadId = data["threadId"];
|
|
126327
|
+
const userMessageId = data["userMessageId"];
|
|
126328
|
+
if (typeof threadId !== "string" || threadId === "" || typeof userMessageId !== "string" || userMessageId === "") {
|
|
126329
|
+
return state;
|
|
126330
|
+
}
|
|
126331
|
+
const key = keyOf(threadId, userMessageId);
|
|
126332
|
+
const pending = conclusionDebtsOf(state);
|
|
126333
|
+
if (name === "conclusion-delivered") {
|
|
126334
|
+
const { [key]: _delivered, ...rest } = pending;
|
|
126335
|
+
return { ...state, conclusions: rest };
|
|
126336
|
+
}
|
|
126337
|
+
const chatKey = data["chatKey"];
|
|
126338
|
+
const recordedAt = data["recordedAt"];
|
|
126339
|
+
if (typeof chatKey !== "string" || chatKey === "" || typeof recordedAt !== "string" || !Number.isFinite(Date.parse(recordedAt))) {
|
|
126340
|
+
return state;
|
|
126341
|
+
}
|
|
126342
|
+
return {
|
|
126343
|
+
...state,
|
|
126344
|
+
conclusions: keepNewest(
|
|
126345
|
+
{ ...pending, [key]: { chatKey, threadId, userMessageId, recordedAt } },
|
|
126346
|
+
CONCLUSION_DEBT_LIMIT
|
|
126347
|
+
)
|
|
126348
|
+
};
|
|
126349
|
+
};
|
|
126350
|
+
var makeConclusionLedger = (core) => {
|
|
126351
|
+
const inFlight = /* @__PURE__ */ new Set();
|
|
126352
|
+
const registering = /* @__PURE__ */ new Map();
|
|
126353
|
+
const delivered = makeBoundedMap(CONCLUSION_DEBT_LIMIT);
|
|
126354
|
+
let disposed = false;
|
|
126355
|
+
core.host.onDispose(() => {
|
|
126356
|
+
disposed = true;
|
|
126357
|
+
});
|
|
126358
|
+
const settle = (debt) => {
|
|
126359
|
+
delivered.set(keyOf(debt.threadId, debt.userMessageId), true);
|
|
126360
|
+
core.commit("conclusion-delivered", {
|
|
126361
|
+
threadId: debt.threadId,
|
|
126362
|
+
userMessageId: debt.userMessageId
|
|
126363
|
+
});
|
|
126364
|
+
};
|
|
126365
|
+
return {
|
|
126366
|
+
starting: (threadId) => {
|
|
126367
|
+
const gate = Promise.withResolvers();
|
|
126368
|
+
const pending = registering.get(threadId) ?? /* @__PURE__ */ new Set();
|
|
126369
|
+
registering.set(threadId, pending);
|
|
126370
|
+
pending.add(gate.promise);
|
|
126371
|
+
return () => {
|
|
126372
|
+
pending.delete(gate.promise);
|
|
126373
|
+
if (pending.size === 0) registering.delete(threadId);
|
|
126374
|
+
gate.resolve();
|
|
126375
|
+
};
|
|
126376
|
+
},
|
|
126377
|
+
owe: (debt) => {
|
|
126378
|
+
const pending = conclusionDebtsOf(core.state);
|
|
126379
|
+
if (Object.keys(pending).length >= CONCLUSION_DEBT_LIMIT && pending[keyOf(debt.threadId, debt.userMessageId)] === void 0) {
|
|
126380
|
+
core.host.log.warn("chat dropped its oldest conclusion debt at capacity", {
|
|
126381
|
+
oldest: Object.values(pending)[0],
|
|
126382
|
+
limit: CONCLUSION_DEBT_LIMIT
|
|
126383
|
+
});
|
|
126384
|
+
}
|
|
126385
|
+
core.commit("conclusion-owed", { ...debt });
|
|
126386
|
+
},
|
|
126387
|
+
forTurn: async (threadId, turnId = null) => {
|
|
126388
|
+
await Promise.all(registering.get(threadId) ?? []);
|
|
126389
|
+
const execution = await core.host.projections.getThreadExecution(threadId);
|
|
126390
|
+
const userMessageId = execution === null ? void 0 : turnId === null ? execution.latestTurn?.userMessageId : userMessageIdOfTurn(execution, turnId);
|
|
126391
|
+
const key = userMessageId === void 0 ? void 0 : keyOf(threadId, userMessageId);
|
|
126392
|
+
return {
|
|
126393
|
+
debt: key === void 0 ? void 0 : conclusionDebtsOf(core.state)[key],
|
|
126394
|
+
handled: key !== void 0 && (delivered.get(key) === true || inFlight.has(key)),
|
|
126395
|
+
execution
|
|
126396
|
+
};
|
|
126397
|
+
},
|
|
126398
|
+
deliver: async (debt, send) => {
|
|
126399
|
+
const key = keyOf(debt.threadId, debt.userMessageId);
|
|
126400
|
+
if (disposed || inFlight.has(key) || conclusionDebtsOf(core.state)[key] === void 0)
|
|
126401
|
+
return false;
|
|
126402
|
+
inFlight.add(key);
|
|
126403
|
+
try {
|
|
126404
|
+
const sent = await send();
|
|
126405
|
+
if (sent) settle(debt);
|
|
126406
|
+
return sent;
|
|
126407
|
+
} finally {
|
|
126408
|
+
inFlight.delete(key);
|
|
126409
|
+
}
|
|
126410
|
+
},
|
|
126411
|
+
discard: (debt) => {
|
|
126412
|
+
const key = keyOf(debt.threadId, debt.userMessageId);
|
|
126413
|
+
if (!disposed && !inFlight.has(key) && conclusionDebtsOf(core.state)[key] !== void 0) {
|
|
126414
|
+
settle(debt);
|
|
126415
|
+
}
|
|
126416
|
+
}
|
|
126417
|
+
};
|
|
126418
|
+
};
|
|
126419
|
+
|
|
126257
126420
|
// src/chatState.ts
|
|
126258
126421
|
var IM_STATE_KEY = "chats";
|
|
126259
126422
|
var IM_STATE_VERSION = 1;
|
|
@@ -126420,6 +126583,9 @@ var withChat = (state, chatKey, patch) => ({
|
|
|
126420
126583
|
var foldImEvent = (state, name, data) => {
|
|
126421
126584
|
if (!isRecord(data)) return state;
|
|
126422
126585
|
switch (name) {
|
|
126586
|
+
case "conclusion-owed":
|
|
126587
|
+
case "conclusion-delivered":
|
|
126588
|
+
return foldConclusionEvent(state, name, data);
|
|
126423
126589
|
case "chat-updated": {
|
|
126424
126590
|
const chatKey = nonEmpty3(data["chatKey"]);
|
|
126425
126591
|
if (chatKey === null) return state;
|
|
@@ -128177,11 +128343,15 @@ var makeImCore = (input) => {
|
|
|
128177
128343
|
};
|
|
128178
128344
|
const deliver = async (binding, text4, attachments = []) => {
|
|
128179
128345
|
await postImages(binding, attachments);
|
|
128180
|
-
if (text4.trim() === "") return;
|
|
128346
|
+
if (text4.trim() === "") return true;
|
|
128347
|
+
const adapter = adapterFor(binding.platform);
|
|
128348
|
+
if (adapter === void 0) return false;
|
|
128181
128349
|
try {
|
|
128182
|
-
await
|
|
128350
|
+
await adapter.sendText(binding, text4);
|
|
128351
|
+
return true;
|
|
128183
128352
|
} catch (error) {
|
|
128184
128353
|
host.log.warn("chat could not deliver", { error: describeError(error) });
|
|
128354
|
+
return false;
|
|
128185
128355
|
}
|
|
128186
128356
|
};
|
|
128187
128357
|
const bots = () => readBots(input.config(), adapterFor);
|
|
@@ -128209,6 +128379,93 @@ var makeImCore = (input) => {
|
|
|
128209
128379
|
};
|
|
128210
128380
|
};
|
|
128211
128381
|
|
|
128382
|
+
// src/conclusionDelivery.ts
|
|
128383
|
+
import { threadOrNull as threadOrNull3 } from "@ycodium-ai/plugin-api";
|
|
128384
|
+
|
|
128385
|
+
// src/threadMessages.ts
|
|
128386
|
+
import {
|
|
128387
|
+
isThreadNotFound,
|
|
128388
|
+
threadMessagesNewestFirst
|
|
128389
|
+
} from "@ycodium-ai/plugin-api";
|
|
128390
|
+
var PAGE_SIZE = 20;
|
|
128391
|
+
async function* newestFirst(threads, threadId) {
|
|
128392
|
+
try {
|
|
128393
|
+
yield* threadMessagesNewestFirst(threads, threadId, { pageSize: PAGE_SIZE });
|
|
128394
|
+
} catch (error) {
|
|
128395
|
+
if (!isThreadNotFound(error)) throw error;
|
|
128396
|
+
}
|
|
128397
|
+
}
|
|
128398
|
+
async function attachmentsOf(threads, threadId, message) {
|
|
128399
|
+
const collected = [...message.attachments ?? []];
|
|
128400
|
+
const total = message.attachmentsTotal ?? collected.length;
|
|
128401
|
+
while (collected.length < total) {
|
|
128402
|
+
let page;
|
|
128403
|
+
try {
|
|
128404
|
+
page = await threads.messages.list({
|
|
128405
|
+
threadId,
|
|
128406
|
+
messageId: message.id,
|
|
128407
|
+
attachmentOffset: collected.length,
|
|
128408
|
+
textLimit: 2
|
|
128409
|
+
});
|
|
128410
|
+
} catch (error) {
|
|
128411
|
+
if (isThreadNotFound(error)) break;
|
|
128412
|
+
throw error;
|
|
128413
|
+
}
|
|
128414
|
+
const more = page.items[0]?.attachments ?? [];
|
|
128415
|
+
if (more.length === 0) break;
|
|
128416
|
+
collected.push(...more);
|
|
128417
|
+
}
|
|
128418
|
+
return collected;
|
|
128419
|
+
}
|
|
128420
|
+
async function latestMessage(threads, threadId, accept) {
|
|
128421
|
+
for await (const message of newestFirst(threads, threadId)) {
|
|
128422
|
+
if (accept(message)) return message;
|
|
128423
|
+
}
|
|
128424
|
+
return void 0;
|
|
128425
|
+
}
|
|
128426
|
+
async function messagesAfterLastUser(threads, threadId) {
|
|
128427
|
+
const after = [];
|
|
128428
|
+
for await (const message of newestFirst(threads, threadId)) {
|
|
128429
|
+
if (message.role === "user") break;
|
|
128430
|
+
after.push(message);
|
|
128431
|
+
}
|
|
128432
|
+
return after.toReversed();
|
|
128433
|
+
}
|
|
128434
|
+
|
|
128435
|
+
// src/conclusionDelivery.ts
|
|
128436
|
+
var makeConclusionDelivery = (core, anchors) => {
|
|
128437
|
+
let disposed = false;
|
|
128438
|
+
core.host.onDispose(() => {
|
|
128439
|
+
disposed = true;
|
|
128440
|
+
});
|
|
128441
|
+
const marked = (text4, recovered) => recovered ? `${core.t("reply.conclusionRecovered")}
|
|
128442
|
+
${text4}` : text4;
|
|
128443
|
+
return {
|
|
128444
|
+
prepareConclusion: async (threadId, turnId = null) => {
|
|
128445
|
+
const thread = await threadOrNull3(core.host.threads, threadId);
|
|
128446
|
+
const final = thread === null ? void 0 : await latestMessage(
|
|
128447
|
+
core.host.threads,
|
|
128448
|
+
threadId,
|
|
128449
|
+
(message) => message.role === "assistant" && message.text.trim() !== ""
|
|
128450
|
+
);
|
|
128451
|
+
const attachments = final === void 0 ? [] : await attachmentsOf(core.host.threads, threadId, final);
|
|
128452
|
+
return async (binding, options) => {
|
|
128453
|
+
if (disposed || thread === null) return false;
|
|
128454
|
+
if (final === void 0) return options.streaming;
|
|
128455
|
+
const text4 = options.streaming ? "" : marked(`${thread.title}
|
|
128456
|
+
|
|
128457
|
+
${final.text}`, options.recovered);
|
|
128458
|
+
const anchored = await anchors.anchored(binding, threadId, turnId ?? final.turnId);
|
|
128459
|
+
return !disposed && core.deliver(anchored, text4, attachments);
|
|
128460
|
+
};
|
|
128461
|
+
},
|
|
128462
|
+
failure: async (binding, threadId, notice, recovered, turnId = null) => {
|
|
128463
|
+
const anchored = await anchors.anchored(binding, threadId, turnId);
|
|
128464
|
+
return !disposed && core.deliver(anchored, marked(notice, recovered));
|
|
128465
|
+
}
|
|
128466
|
+
};
|
|
128467
|
+
};
|
|
128468
|
+
|
|
128212
128469
|
// src/attachments.ts
|
|
128213
128470
|
var IMAGE_LIMIT_BYTES = 10 * 1024 * 1024;
|
|
128214
128471
|
var FILE_LIMIT_BYTES = 25 * 1024 * 1024;
|
|
@@ -128501,68 +128758,6 @@ var makeCooldown = (windowMs, now, maxKeys = Number.POSITIVE_INFINITY) => {
|
|
|
128501
128758
|
};
|
|
128502
128759
|
};
|
|
128503
128760
|
|
|
128504
|
-
// src/boundedMap.ts
|
|
128505
|
-
var makeBoundedMap = (limit) => {
|
|
128506
|
-
const entries = /* @__PURE__ */ new Map();
|
|
128507
|
-
return {
|
|
128508
|
-
get: (key) => entries.get(key),
|
|
128509
|
-
set: (key, value2) => {
|
|
128510
|
-
entries.delete(key);
|
|
128511
|
-
entries.set(key, value2);
|
|
128512
|
-
if (entries.size > limit) {
|
|
128513
|
-
const oldest = entries.keys().next().value;
|
|
128514
|
-
if (oldest !== void 0) entries.delete(oldest);
|
|
128515
|
-
}
|
|
128516
|
-
},
|
|
128517
|
-
/** 忘掉键满足条件的那些。 */
|
|
128518
|
-
forget: (matches) => {
|
|
128519
|
-
for (const key of [...entries.keys()]) if (matches(key)) entries.delete(key);
|
|
128520
|
-
}
|
|
128521
|
-
};
|
|
128522
|
-
};
|
|
128523
|
-
|
|
128524
|
-
// src/replyAnchors.ts
|
|
128525
|
-
var THREAD_LIMIT = 256;
|
|
128526
|
-
var TURNS_PER_THREAD = 16;
|
|
128527
|
-
var anchorOfMessage = (adapter, message) => adapter?.quotesReplies === true ? { messageId: message.messageId, inThread: message.replyInThread === true } : void 0;
|
|
128528
|
-
var makeReplyAnchors = (host) => {
|
|
128529
|
-
const byThread = makeBoundedMap(THREAD_LIMIT);
|
|
128530
|
-
const userMessageOfTurn = async (threadId, turnId) => {
|
|
128531
|
-
const execution = await host.projections.getThreadExecution(threadId).catch(() => null);
|
|
128532
|
-
if (execution === null) return void 0;
|
|
128533
|
-
const latest = execution.latestTurn;
|
|
128534
|
-
const wanted = turnId ?? execution.session?.activeTurnId ?? latest?.turnId;
|
|
128535
|
-
if (wanted == null) return void 0;
|
|
128536
|
-
const intent = execution.turnIntents.find((candidate) => candidate.turn?.turnId === wanted);
|
|
128537
|
-
return intent?.messageId ?? (latest?.turnId === wanted ? latest.userMessageId : void 0);
|
|
128538
|
-
};
|
|
128539
|
-
return {
|
|
128540
|
-
/**
|
|
128541
|
-
* 开轮时记一笔:`userMessageId` 是派给宿主的那条用户消息,`binding` 是收到聊天消息的那个
|
|
128542
|
-
* 聊天(带着它的锚点)。没有锚点(平台不引用)就不记。
|
|
128543
|
-
*/
|
|
128544
|
-
note: (threadId, userMessageId, binding) => {
|
|
128545
|
-
if (binding.reply === void 0) return;
|
|
128546
|
-
const turns = byThread.get(threadId) ?? makeBoundedMap(TURNS_PER_THREAD);
|
|
128547
|
-
byThread.set(threadId, turns);
|
|
128548
|
-
turns.set(userMessageId, { chatKey: chatKeyOf(binding), anchor: binding.reply });
|
|
128549
|
-
},
|
|
128550
|
-
/**
|
|
128551
|
-
* 给发往这条会话的聊天挂上 `turnId` 那一轮的锚点(null 的含义见上);取不到就原样返回。
|
|
128552
|
-
*
|
|
128553
|
-
* 锚点只配给它那条消息所在的聊天:会话可以被另一个聊天接走(`/resume`),而回复接口只按被
|
|
128554
|
-
* 回复的消息寻址,挂错了答复就发回原来的聊天。
|
|
128555
|
-
*/
|
|
128556
|
-
anchored: async (binding, threadId, turnId) => {
|
|
128557
|
-
const turns = byThread.get(threadId);
|
|
128558
|
-
if (turns === void 0) return binding;
|
|
128559
|
-
const asked = await userMessageOfTurn(threadId, turnId);
|
|
128560
|
-
const noted = asked === void 0 ? void 0 : turns.get(asked);
|
|
128561
|
-
return noted?.chatKey === chatKeyOf(binding) ? { ...binding, reply: noted.anchor } : binding;
|
|
128562
|
-
}
|
|
128563
|
-
};
|
|
128564
|
-
};
|
|
128565
|
-
|
|
128566
128761
|
// src/inbound.ts
|
|
128567
128762
|
var SEEN_MESSAGE_LIMIT = 256;
|
|
128568
128763
|
var ARCHIVED_REPLY_COOLDOWN_MS = 10 * 6e4;
|
|
@@ -128600,10 +128795,9 @@ var makeInbound = (core, deps) => {
|
|
|
128600
128795
|
});
|
|
128601
128796
|
if (sender === null) return;
|
|
128602
128797
|
if (!notAllowedReplyCooldown.tryAcquire(`${target2.rowId}:${sender}`)) return;
|
|
128603
|
-
enqueueForChat(
|
|
128604
|
-
|
|
128605
|
-
|
|
128606
|
-
);
|
|
128798
|
+
enqueueForChat(chatKeyOf(target2), async () => {
|
|
128799
|
+
await deliver(target2, t("reply.notAllowedYet", { id: sender }));
|
|
128800
|
+
});
|
|
128607
128801
|
};
|
|
128608
128802
|
const currentBot = (rowId) => bots().find((candidate) => candidate.rowId === rowId);
|
|
128609
128803
|
const inheritFromParent = (bot, chatId, parentChatId) => {
|
|
@@ -131703,10 +131897,11 @@ var makeCardStream = (deps) => {
|
|
|
131703
131897
|
const run = (async () => {
|
|
131704
131898
|
try {
|
|
131705
131899
|
while (pending !== null) {
|
|
131706
|
-
const next = pending
|
|
131900
|
+
const next = pending;
|
|
131707
131901
|
pending = null;
|
|
131708
131902
|
try {
|
|
131709
|
-
await deps.update(id, next);
|
|
131903
|
+
await deps.update(id, next.view);
|
|
131904
|
+
if (next.result !== void 0) next.result.sent = true;
|
|
131710
131905
|
} catch (error) {
|
|
131711
131906
|
deps.warn("could not update a card", error);
|
|
131712
131907
|
}
|
|
@@ -131731,12 +131926,14 @@ var makeCardStream = (deps) => {
|
|
|
131731
131926
|
}
|
|
131732
131927
|
},
|
|
131733
131928
|
finish: async (last) => {
|
|
131734
|
-
if (closed) return;
|
|
131929
|
+
if (closed) return false;
|
|
131735
131930
|
closed = true;
|
|
131736
131931
|
cancelTimer?.();
|
|
131737
131932
|
cancelTimer = null;
|
|
131738
|
-
|
|
131933
|
+
const result = { sent: false };
|
|
131934
|
+
pending = { view: last, result };
|
|
131739
131935
|
await drain();
|
|
131936
|
+
return result.sent;
|
|
131740
131937
|
},
|
|
131741
131938
|
abandon: () => {
|
|
131742
131939
|
closed = true;
|
|
@@ -138122,6 +138319,7 @@ var en_default = {
|
|
|
138122
138319
|
}
|
|
138123
138320
|
},
|
|
138124
138321
|
reply: {
|
|
138322
|
+
conclusionRecovered: "(Finished while restarting; delivered now)",
|
|
138125
138323
|
notAllowed: "You are not on this bot's allow list, so this tap had no effect.",
|
|
138126
138324
|
noDefaultModel: 'Project "{{title}}" has no agent selected yet, so a thread cannot be started. Send /model to pick one, or set a default in the project settings, then message again.',
|
|
138127
138325
|
projectArchived: 'Project "{{title}}" is archived. Restore it, or send /repo to pick another project, then message again.',
|
|
@@ -138791,6 +138989,7 @@ var zh_CN_default = {
|
|
|
138791
138989
|
}
|
|
138792
138990
|
},
|
|
138793
138991
|
reply: {
|
|
138992
|
+
conclusionRecovered: "\uFF08\u91CD\u542F\u671F\u95F4\u5B8C\u6210\uFF0C\u73B0\u5728\u8865\u53D1\uFF09",
|
|
138794
138993
|
notAllowed: "\u4F60\u4E0D\u5728\u8FD9\u4E2A\u673A\u5668\u4EBA\u7684\u5141\u8BB8\u540D\u5355\u91CC\uFF0C\u8FD9\u6B21\u70B9\u51FB\u6CA1\u6709\u751F\u6548\u3002",
|
|
138795
138994
|
noDefaultModel: "\u9879\u76EE\u300C{{title}}\u300D\u8FD8\u6CA1\u9009 agent\uFF0C\u5F00\u4E0D\u4E86\u4F1A\u8BDD\u3002\u53D1 /model \u9009\u4E00\u4E2A\uFF0C\u6216\u8005\u5230\u9879\u76EE\u8BBE\u7F6E\u91CC\u8BBE\u4E2A\u9ED8\u8BA4\uFF0C\u518D\u53D1\u4E00\u6B21\u6D88\u606F\u3002",
|
|
138796
138995
|
projectArchived: "\u9879\u76EE\u300C{{title}}\u300D\u5DF2\u5F52\u6863\u3002\u6062\u590D\u5B83\uFF0C\u6216\u53D1 /repo \u6362\u4E2A\u9879\u76EE\uFF0C\u518D\u53D1\u6D88\u606F\u3002",
|
|
@@ -139311,14 +139510,14 @@ var makeLiveTranslate = (initial) => {
|
|
|
139311
139510
|
};
|
|
139312
139511
|
|
|
139313
139512
|
// src/modelPlan.ts
|
|
139314
|
-
import { threadOrNull as
|
|
139513
|
+
import { threadOrNull as threadOrNull4 } from "@ycodium-ai/plugin-api";
|
|
139315
139514
|
var makeModelPlan = (core, deps) => {
|
|
139316
139515
|
const { host, t, commit, deliver } = core;
|
|
139317
139516
|
const { threadStillUsable } = deps;
|
|
139318
139517
|
const currentModelOf = async (binding) => {
|
|
139319
139518
|
const chat = chatOf(core.state, chatKeyOf(binding));
|
|
139320
139519
|
if (chat.threadId !== null) {
|
|
139321
|
-
const thread = await
|
|
139520
|
+
const thread = await threadOrNull4(host.threads, chat.threadId).catch(() => null);
|
|
139322
139521
|
if (thread !== null) {
|
|
139323
139522
|
return {
|
|
139324
139523
|
instanceId: thread.modelSelection.instanceId,
|
|
@@ -139387,7 +139586,62 @@ var makeModelPlan = (core, deps) => {
|
|
|
139387
139586
|
};
|
|
139388
139587
|
|
|
139389
139588
|
// src/notifications.ts
|
|
139390
|
-
import { readThreadFailed, threadOrNull as
|
|
139589
|
+
import { readThreadFailed, threadOrNull as threadOrNull5 } from "@ycodium-ai/plugin-api";
|
|
139590
|
+
|
|
139591
|
+
// src/conclusionRecovery.ts
|
|
139592
|
+
var MAX_AGE_MS = 7 * 24 * 60 * 60 * 1e3;
|
|
139593
|
+
var recoverConclusions = async (core, ledger, delivery, failures) => {
|
|
139594
|
+
let disposed = false;
|
|
139595
|
+
core.host.onDispose(() => {
|
|
139596
|
+
disposed = true;
|
|
139597
|
+
});
|
|
139598
|
+
await core.ready;
|
|
139599
|
+
for (const debt of Object.values(conclusionDebtsOf(core.state))) {
|
|
139600
|
+
if (disposed) return;
|
|
139601
|
+
try {
|
|
139602
|
+
const execution = await core.host.projections.getThreadExecution(debt.threadId);
|
|
139603
|
+
if (disposed) return;
|
|
139604
|
+
if (execution === null) {
|
|
139605
|
+
ledger.discard(debt);
|
|
139606
|
+
continue;
|
|
139607
|
+
}
|
|
139608
|
+
const latest = execution.latestTurn;
|
|
139609
|
+
if (latest?.userMessageId !== debt.userMessageId) {
|
|
139610
|
+
core.host.log.info("chat discarded a conclusion whose turn is no longer latest", {
|
|
139611
|
+
...debt
|
|
139612
|
+
});
|
|
139613
|
+
ledger.discard(debt);
|
|
139614
|
+
continue;
|
|
139615
|
+
}
|
|
139616
|
+
if (latest.state === "running" || execution.session?.activeTurnId != null) continue;
|
|
139617
|
+
if (latest.completedAt !== null && Date.parse(latest.completedAt) < Date.now() - MAX_AGE_MS) {
|
|
139618
|
+
core.host.log.info("chat discarded a conclusion older than seven days", { ...debt });
|
|
139619
|
+
ledger.discard(debt);
|
|
139620
|
+
continue;
|
|
139621
|
+
}
|
|
139622
|
+
const binding = core.bindingForChatKey(debt.chatKey);
|
|
139623
|
+
if (binding === void 0) continue;
|
|
139624
|
+
await ledger.deliver(debt, async () => {
|
|
139625
|
+
if (latest.state === "error") {
|
|
139626
|
+
return delivery.failure(
|
|
139627
|
+
binding,
|
|
139628
|
+
debt.threadId,
|
|
139629
|
+
failures.forFailure(debt.threadId, execution.session?.lastError),
|
|
139630
|
+
true,
|
|
139631
|
+
latest.turnId
|
|
139632
|
+
);
|
|
139633
|
+
}
|
|
139634
|
+
const send = await delivery.prepareConclusion(debt.threadId, latest.turnId);
|
|
139635
|
+
return send(binding, { recovered: true, streaming: false });
|
|
139636
|
+
});
|
|
139637
|
+
} catch (error) {
|
|
139638
|
+
core.host.log.warn("chat could not recover a conclusion", {
|
|
139639
|
+
...debt,
|
|
139640
|
+
error: describeError(error)
|
|
139641
|
+
});
|
|
139642
|
+
}
|
|
139643
|
+
}
|
|
139644
|
+
};
|
|
139391
139645
|
|
|
139392
139646
|
// src/notificationTargets.ts
|
|
139393
139647
|
var notificationChatKeys = (state, threadId, projectId) => {
|
|
@@ -139396,56 +139650,6 @@ var notificationChatKeys = (state, threadId, projectId) => {
|
|
|
139396
139650
|
return projectId === null ? [] : chatsOnProject(state, projectId);
|
|
139397
139651
|
};
|
|
139398
139652
|
|
|
139399
|
-
// src/threadMessages.ts
|
|
139400
|
-
import {
|
|
139401
|
-
isThreadNotFound,
|
|
139402
|
-
threadMessagesNewestFirst
|
|
139403
|
-
} from "@ycodium-ai/plugin-api";
|
|
139404
|
-
var PAGE_SIZE = 20;
|
|
139405
|
-
async function* newestFirst(threads, threadId) {
|
|
139406
|
-
try {
|
|
139407
|
-
yield* threadMessagesNewestFirst(threads, threadId, { pageSize: PAGE_SIZE });
|
|
139408
|
-
} catch (error) {
|
|
139409
|
-
if (!isThreadNotFound(error)) throw error;
|
|
139410
|
-
}
|
|
139411
|
-
}
|
|
139412
|
-
async function attachmentsOf(threads, threadId, message) {
|
|
139413
|
-
const collected = [...message.attachments ?? []];
|
|
139414
|
-
const total = message.attachmentsTotal ?? collected.length;
|
|
139415
|
-
while (collected.length < total) {
|
|
139416
|
-
let page;
|
|
139417
|
-
try {
|
|
139418
|
-
page = await threads.messages.list({
|
|
139419
|
-
threadId,
|
|
139420
|
-
messageId: message.id,
|
|
139421
|
-
attachmentOffset: collected.length,
|
|
139422
|
-
textLimit: 2
|
|
139423
|
-
});
|
|
139424
|
-
} catch (error) {
|
|
139425
|
-
if (isThreadNotFound(error)) break;
|
|
139426
|
-
throw error;
|
|
139427
|
-
}
|
|
139428
|
-
const more = page.items[0]?.attachments ?? [];
|
|
139429
|
-
if (more.length === 0) break;
|
|
139430
|
-
collected.push(...more);
|
|
139431
|
-
}
|
|
139432
|
-
return collected;
|
|
139433
|
-
}
|
|
139434
|
-
async function latestMessage(threads, threadId, accept) {
|
|
139435
|
-
for await (const message of newestFirst(threads, threadId)) {
|
|
139436
|
-
if (accept(message)) return message;
|
|
139437
|
-
}
|
|
139438
|
-
return void 0;
|
|
139439
|
-
}
|
|
139440
|
-
async function messagesAfterLastUser(threads, threadId) {
|
|
139441
|
-
const after = [];
|
|
139442
|
-
for await (const message of newestFirst(threads, threadId)) {
|
|
139443
|
-
if (message.role === "user") break;
|
|
139444
|
-
after.push(message);
|
|
139445
|
-
}
|
|
139446
|
-
return after.toReversed();
|
|
139447
|
-
}
|
|
139448
|
-
|
|
139449
139653
|
// src/turnOutcome.ts
|
|
139450
139654
|
var outcomeOfSession = (status) => {
|
|
139451
139655
|
if (status === "error") return "failed";
|
|
@@ -139456,15 +139660,16 @@ var outcomeOfSession = (status) => {
|
|
|
139456
139660
|
// src/notifications.ts
|
|
139457
139661
|
var THREAD_PROJECT_CACHE_LIMIT = 256;
|
|
139458
139662
|
var makeNotifications = (core, deps) => {
|
|
139459
|
-
const { host, adapterFor,
|
|
139663
|
+
const { host, adapterFor, bindingForChatKey, ready } = core;
|
|
139460
139664
|
const { clearWorking } = deps;
|
|
139461
139665
|
const { turnCards } = deps.replyCards;
|
|
139462
|
-
const { failures,
|
|
139666
|
+
const { failures, conclusions, delivery } = deps;
|
|
139667
|
+
void recoverConclusions(core, conclusions, delivery, failures);
|
|
139463
139668
|
const projectByThread = /* @__PURE__ */ new Map();
|
|
139464
139669
|
const projectOfThread = async (threadId) => {
|
|
139465
139670
|
const known = projectByThread.get(threadId);
|
|
139466
139671
|
if (known !== void 0) return known;
|
|
139467
|
-
const thread = await
|
|
139672
|
+
const thread = await threadOrNull5(host.threads, threadId);
|
|
139468
139673
|
if (thread === null) return null;
|
|
139469
139674
|
if (projectByThread.size >= THREAD_PROJECT_CACHE_LIMIT) {
|
|
139470
139675
|
const oldest = projectByThread.keys().next().value;
|
|
@@ -139501,26 +139706,28 @@ var makeNotifications = (core, deps) => {
|
|
|
139501
139706
|
const said = threadsWithSomethingToReport.delete(threadId);
|
|
139502
139707
|
await ready;
|
|
139503
139708
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
139504
|
-
const
|
|
139505
|
-
|
|
139506
|
-
|
|
139507
|
-
|
|
139508
|
-
|
|
139509
|
-
|
|
139510
|
-
|
|
139511
|
-
|
|
139512
|
-
|
|
139513
|
-
|
|
139514
|
-
|
|
139515
|
-
const text4 = streamsTo(binding, threadId) ? "" : `${thread.title}
|
|
139516
|
-
|
|
139517
|
-
${final.text}`;
|
|
139518
|
-
await deliver(
|
|
139519
|
-
owns(binding, threadId) ? await anchors.anchored(binding, threadId, final.turnId) : binding,
|
|
139520
|
-
text4,
|
|
139521
|
-
attachments
|
|
139709
|
+
const owes = Object.values(conclusionDebtsOf(core.state)).some(
|
|
139710
|
+
(debt2) => debt2.threadId === threadId
|
|
139711
|
+
);
|
|
139712
|
+
const { debt, handled, execution } = said || owes ? await conclusions.forTurn(threadId) : { debt: void 0, handled: false, execution: null };
|
|
139713
|
+
if (debt !== void 0) {
|
|
139714
|
+
const binding = bindingForChatKey(debt.chatKey);
|
|
139715
|
+
if (binding !== void 0 && !streamsTo(binding, threadId) && execution?.session?.activeTurnId == null && execution?.latestTurn?.state !== "running" && execution?.latestTurn?.state !== "error" && payload.session?.status !== "error") {
|
|
139716
|
+
await conclusions.deliver(debt, async () => {
|
|
139717
|
+
const send = await delivery.prepareConclusion(
|
|
139718
|
+
threadId,
|
|
139719
|
+
execution?.latestTurn?.turnId ?? null
|
|
139522
139720
|
);
|
|
139523
|
-
|
|
139721
|
+
return send(binding, { recovered: false, streaming: false });
|
|
139722
|
+
});
|
|
139723
|
+
}
|
|
139724
|
+
} else if (said && !handled) {
|
|
139725
|
+
const send = await delivery.prepareConclusion(threadId);
|
|
139726
|
+
for (const binding of targets) {
|
|
139727
|
+
await send(binding, {
|
|
139728
|
+
recovered: false,
|
|
139729
|
+
streaming: streamsTo(binding, threadId)
|
|
139730
|
+
});
|
|
139524
139731
|
}
|
|
139525
139732
|
}
|
|
139526
139733
|
const outcome = outcomeOfSession(payload.session?.status);
|
|
@@ -139533,7 +139740,10 @@ ${final.text}`;
|
|
|
139533
139740
|
threadsWithSomethingToReport.delete(threadId);
|
|
139534
139741
|
await ready;
|
|
139535
139742
|
const targets = targetsForProject(threadId, await projectOfThread(threadId));
|
|
139536
|
-
const
|
|
139743
|
+
const { debt, handled } = await conclusions.forTurn(threadId);
|
|
139744
|
+
const debtBinding = debt === void 0 ? void 0 : bindingForChatKey(debt.chatKey);
|
|
139745
|
+
const recipients = debt !== void 0 ? debtBinding === void 0 ? [] : [debtBinding] : targets;
|
|
139746
|
+
const textTargets = handled ? [] : recipients.filter(
|
|
139537
139747
|
(binding) => !(streamsTo(binding, threadId) && turnCards.covers(threadId))
|
|
139538
139748
|
);
|
|
139539
139749
|
const drawingTurn = turnCards.drawingTurn(threadId);
|
|
@@ -139542,7 +139752,13 @@ ${final.text}`;
|
|
|
139542
139752
|
failures.holdForCard(threadId, drawingTurn, notice);
|
|
139543
139753
|
for (const binding of targets) {
|
|
139544
139754
|
await clearWorking(binding, threadId, "failed");
|
|
139545
|
-
|
|
139755
|
+
}
|
|
139756
|
+
if (notice !== null) {
|
|
139757
|
+
for (const binding of textTargets) {
|
|
139758
|
+
const send = () => delivery.failure(binding, threadId, notice, false);
|
|
139759
|
+
if (debt !== void 0) await conclusions.deliver(debt, send);
|
|
139760
|
+
else await send();
|
|
139761
|
+
}
|
|
139546
139762
|
}
|
|
139547
139763
|
});
|
|
139548
139764
|
const rememberThreadProject = (threadId, projectId) => {
|
|
@@ -140135,7 +140351,7 @@ var makeFailureNotices = (core) => {
|
|
|
140135
140351
|
const heldForCard = /* @__PURE__ */ new Map();
|
|
140136
140352
|
const reasonOf2 = (detail) => detail?.trim() ?? "";
|
|
140137
140353
|
return {
|
|
140138
|
-
/**
|
|
140354
|
+
/** 一次失败通知的那句话(带新参考号,同号进日志):实时失败事件与重启补发各取一次。 */
|
|
140139
140355
|
forFailure: (threadId, detail) => {
|
|
140140
140356
|
const reference2 = diagnosticRef("msg");
|
|
140141
140357
|
core.host.log.warn("chat turn failed", { threadId, reference: reference2 });
|
|
@@ -140165,7 +140381,7 @@ var makeFailureNotices = (core) => {
|
|
|
140165
140381
|
// src/replyCards.ts
|
|
140166
140382
|
import {
|
|
140167
140383
|
readTurnProgress,
|
|
140168
|
-
threadOrNull as
|
|
140384
|
+
threadOrNull as threadOrNull6,
|
|
140169
140385
|
TURN_PROGRESS_TRIGGER_KIND
|
|
140170
140386
|
} from "@ycodium-ai/plugin-api";
|
|
140171
140387
|
|
|
@@ -140291,15 +140507,19 @@ var makeTurnCards = (deps) => {
|
|
|
140291
140507
|
const title = live?.title ?? await deps.titleOf(threadId);
|
|
140292
140508
|
const view = await finalView(title, progress, live, end);
|
|
140293
140509
|
if (live?.card != null) {
|
|
140294
|
-
|
|
140295
|
-
|
|
140296
|
-
|
|
140297
|
-
|
|
140298
|
-
|
|
140299
|
-
if (card === null) {
|
|
140300
|
-
await deps.fallback(threadId, turnId, target2.chatKey, view);
|
|
140510
|
+
const card = live.card;
|
|
140511
|
+
const sent = await card.finish(view);
|
|
140512
|
+
deps.onClosed(card.cardId);
|
|
140513
|
+
if (deps.finalize !== void 0)
|
|
140514
|
+
await deps.finalize(threadId, turnId, target2.chatKey, async () => sent);
|
|
140301
140515
|
return;
|
|
140302
140516
|
}
|
|
140517
|
+
const send = async () => {
|
|
140518
|
+
const card = await openCard(target2, view);
|
|
140519
|
+
return card !== null || await deps.fallback(threadId, turnId, target2.chatKey, view);
|
|
140520
|
+
};
|
|
140521
|
+
if (deps.finalize === void 0) await send();
|
|
140522
|
+
else await deps.finalize(threadId, turnId, target2.chatKey, send);
|
|
140303
140523
|
};
|
|
140304
140524
|
const handle = async (slot, threadId, item) => {
|
|
140305
140525
|
await deps.ready;
|
|
@@ -140444,7 +140664,7 @@ var makeTurnCards = (deps) => {
|
|
|
140444
140664
|
};
|
|
140445
140665
|
|
|
140446
140666
|
// src/replyCards.ts
|
|
140447
|
-
var makeReplyCards = (core, failures, anchors) => {
|
|
140667
|
+
var makeReplyCards = (core, failures, anchors, conclusions, delivery) => {
|
|
140448
140668
|
const { host, adapterFor, commit, deliver, bindingForChatKey, bindingOfThread, ready } = core;
|
|
140449
140669
|
const stopRequested = /* @__PURE__ */ new Set();
|
|
140450
140670
|
const turnCards = makeTurnCards({
|
|
@@ -140480,12 +140700,12 @@ var makeReplyCards = (core, failures, anchors) => {
|
|
|
140480
140700
|
(message) => message.role === "user" && message.text.trim() !== ""
|
|
140481
140701
|
).catch(() => void 0);
|
|
140482
140702
|
if (asked !== void 0) return turnTitleOf(asked.text);
|
|
140483
|
-
const thread = await
|
|
140703
|
+
const thread = await threadOrNull6(host.threads, threadId).catch(() => null);
|
|
140484
140704
|
return turnTitleOf(thread?.title ?? "");
|
|
140485
140705
|
},
|
|
140486
140706
|
endOf: async (threadId, turnId) => {
|
|
140487
140707
|
const stopped = stopRequested.delete(threadId);
|
|
140488
|
-
const thread = await
|
|
140708
|
+
const thread = await threadOrNull6(host.threads, threadId).catch(() => null);
|
|
140489
140709
|
const session = thread?.session;
|
|
140490
140710
|
const outcome = outcomeOfSession(session?.status);
|
|
140491
140711
|
const errorText2 = failures.forCard(
|
|
@@ -140502,11 +140722,24 @@ var makeReplyCards = (core, failures, anchors) => {
|
|
|
140502
140722
|
},
|
|
140503
140723
|
onOpened: (card) => commit("turn-card-opened", card),
|
|
140504
140724
|
onClosed: (cardId) => commit("turn-card-closed", { cardId }),
|
|
140505
|
-
|
|
140725
|
+
finalize: async (threadId, turnId, chatKey, send) => {
|
|
140726
|
+
const { debt, handled } = await conclusions.forTurn(threadId, turnId);
|
|
140727
|
+
if (handled) return;
|
|
140728
|
+
if (debt === void 0) {
|
|
140729
|
+
await send();
|
|
140730
|
+
return;
|
|
140731
|
+
}
|
|
140732
|
+
if (!await conclusions.deliver(debt, send)) return;
|
|
140506
140733
|
const binding = bindingForChatKey(chatKey);
|
|
140507
140734
|
if (binding === void 0) return;
|
|
140735
|
+
const sendConclusion = await delivery.prepareConclusion(threadId, turnId);
|
|
140736
|
+
await sendConclusion(binding, { recovered: false, streaming: true });
|
|
140737
|
+
},
|
|
140738
|
+
fallback: async (threadId, turnId, chatKey, view) => {
|
|
140739
|
+
const binding = bindingForChatKey(chatKey);
|
|
140740
|
+
if (binding === void 0) return false;
|
|
140508
140741
|
const text4 = [view.body, view.errorText ?? ""].filter((part) => part !== "").join("\n\n");
|
|
140509
|
-
|
|
140742
|
+
return deliver(await anchors.anchored(binding, threadId, turnId), text4);
|
|
140510
140743
|
},
|
|
140511
140744
|
schedule: (run, delayMs) => {
|
|
140512
140745
|
const timer = setTimeout(run, delayMs);
|
|
@@ -140724,7 +140957,7 @@ var makeSendFileTool = (deps) => ({
|
|
|
140724
140957
|
});
|
|
140725
140958
|
|
|
140726
140959
|
// src/sessions.ts
|
|
140727
|
-
import { threadOrNull as
|
|
140960
|
+
import { threadOrNull as threadOrNull7 } from "@ycodium-ai/plugin-api";
|
|
140728
140961
|
var WEB_LIST_PAGE = 100;
|
|
140729
140962
|
var shellOf = (thread) => ({
|
|
140730
140963
|
threadId: thread.id,
|
|
@@ -140784,7 +141017,7 @@ var makeSessions = (core) => {
|
|
|
140784
141017
|
});
|
|
140785
141018
|
};
|
|
140786
141019
|
const rowForThread = async (binding, chatKey, threadId) => {
|
|
140787
|
-
const thread = await
|
|
141020
|
+
const thread = await threadOrNull7(host.threads, threadId, { archived: "include" });
|
|
140788
141021
|
if (thread === null || thread.projectId !== binding.projectId) return null;
|
|
140789
141022
|
return rowFromThread(shellOf(thread), chatKey, originOf(threadId, binding.projectId));
|
|
140790
141023
|
};
|
|
@@ -141938,7 +142171,7 @@ ${line}`
|
|
|
141938
142171
|
};
|
|
141939
142172
|
|
|
141940
142173
|
// src/turns.ts
|
|
141941
|
-
import { projectOrNull as projectOrNull2, threadOrNull as
|
|
142174
|
+
import { projectOrNull as projectOrNull2, threadOrNull as threadOrNull8 } from "@ycodium-ai/plugin-api";
|
|
141942
142175
|
var TITLE_MAX_CHARS = 72;
|
|
141943
142176
|
var titleFrom = (text4) => text4.replace(/\s+/g, " ").slice(0, TITLE_MAX_CHARS) || "Chat thread";
|
|
141944
142177
|
var makeTurns = (core, deps) => {
|
|
@@ -141947,7 +142180,7 @@ var makeTurns = (core, deps) => {
|
|
|
141947
142180
|
const { pendingByChat, pendingFor, collectResources } = deps.attachments;
|
|
141948
142181
|
const threadStillUsable = async (binding, threadId) => {
|
|
141949
142182
|
try {
|
|
141950
|
-
const thread = await
|
|
142183
|
+
const thread = await threadOrNull8(host.threads, threadId, { archived: "include" });
|
|
141951
142184
|
return thread !== null && thread.archivedAt == null && thread.projectId === binding.projectId;
|
|
141952
142185
|
} catch {
|
|
141953
142186
|
return true;
|
|
@@ -142045,6 +142278,7 @@ var makeTurns = (core, deps) => {
|
|
|
142045
142278
|
} catch {
|
|
142046
142279
|
}
|
|
142047
142280
|
}
|
|
142281
|
+
const registered = deps.conclusions.starting(threadId);
|
|
142048
142282
|
try {
|
|
142049
142283
|
await host.threads.turns.start({
|
|
142050
142284
|
requestId: crypto.randomUUID(),
|
|
@@ -142062,9 +142296,19 @@ var makeTurns = (core, deps) => {
|
|
|
142062
142296
|
interactionMode: interactionModeOf(chatKey),
|
|
142063
142297
|
...intentAction !== void 0 ? { intentAction } : {}
|
|
142064
142298
|
});
|
|
142299
|
+
if (intentAction?.kind !== "steer") {
|
|
142300
|
+
deps.conclusions.owe({
|
|
142301
|
+
chatKey,
|
|
142302
|
+
threadId,
|
|
142303
|
+
userMessageId,
|
|
142304
|
+
recordedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
142305
|
+
});
|
|
142306
|
+
}
|
|
142065
142307
|
} catch (error) {
|
|
142066
142308
|
if (carried !== void 0) pendingByChat.set(chatKey, carried);
|
|
142067
142309
|
throw error;
|
|
142310
|
+
} finally {
|
|
142311
|
+
registered();
|
|
142068
142312
|
}
|
|
142069
142313
|
deps.noteInboundUserMessage?.(userMessageId);
|
|
142070
142314
|
host.log.info("chat started a turn from a message", {
|
|
@@ -144473,13 +144717,22 @@ var imPlugin = definePlugin({
|
|
|
144473
144717
|
const acknowledgements = makeAcknowledgements(core);
|
|
144474
144718
|
const failures = makeFailureNotices(core);
|
|
144475
144719
|
const replyAnchors = makeReplyAnchors(core.host);
|
|
144476
|
-
const
|
|
144720
|
+
const conclusions = makeConclusionLedger(core);
|
|
144721
|
+
const conclusionDelivery = makeConclusionDelivery(core, replyAnchors);
|
|
144722
|
+
const replyCards = makeReplyCards(
|
|
144723
|
+
core,
|
|
144724
|
+
failures,
|
|
144725
|
+
replyAnchors,
|
|
144726
|
+
conclusions,
|
|
144727
|
+
conclusionDelivery
|
|
144728
|
+
);
|
|
144477
144729
|
const teams = makeTeamGoals(core);
|
|
144478
144730
|
const notifications = makeNotifications(core, {
|
|
144479
144731
|
clearWorking: acknowledgements.clearWorking,
|
|
144480
144732
|
replyCards,
|
|
144481
144733
|
failures,
|
|
144482
|
-
|
|
144734
|
+
conclusions,
|
|
144735
|
+
delivery: conclusionDelivery
|
|
144483
144736
|
});
|
|
144484
144737
|
const webSync = makeWebSync(core);
|
|
144485
144738
|
const approvals = makeApprovals(core, replyAnchors);
|
|
@@ -144490,6 +144743,7 @@ var imPlugin = definePlugin({
|
|
|
144490
144743
|
});
|
|
144491
144744
|
const inboundAttachments = makeInboundAttachments(core);
|
|
144492
144745
|
const turns = makeTurns(core, {
|
|
144746
|
+
conclusions,
|
|
144493
144747
|
attachments: inboundAttachments,
|
|
144494
144748
|
queueFlow: interactions.queueFlow,
|
|
144495
144749
|
rememberThreadProject: notifications.rememberThreadProject,
|
package/locales/en.json
CHANGED
|
@@ -193,6 +193,7 @@
|
|
|
193
193
|
}
|
|
194
194
|
},
|
|
195
195
|
"reply": {
|
|
196
|
+
"conclusionRecovered": "(Finished while restarting; delivered now)",
|
|
196
197
|
"notAllowed": "You are not on this bot's allow list, so this tap had no effect.",
|
|
197
198
|
"noDefaultModel": "Project \"{{title}}\" has no agent selected yet, so a thread cannot be started. Send /model to pick one, or set a default in the project settings, then message again.",
|
|
198
199
|
"projectArchived": "Project \"{{title}}\" is archived. Restore it, or send /repo to pick another project, then message again.",
|
package/locales/zh-CN.json
CHANGED
|
@@ -193,6 +193,7 @@
|
|
|
193
193
|
}
|
|
194
194
|
},
|
|
195
195
|
"reply": {
|
|
196
|
+
"conclusionRecovered": "(重启期间完成,现在补发)",
|
|
196
197
|
"notAllowed": "你不在这个机器人的允许名单里,这次点击没有生效。",
|
|
197
198
|
"noDefaultModel": "项目「{{title}}」还没选 agent,开不了会话。发 /model 选一个,或者到项目设置里设个默认,再发一次消息。",
|
|
198
199
|
"projectArchived": "项目「{{title}}」已归档。恢复它,或发 /repo 换个项目,再发消息。",
|
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.3112",
|
|
4
4
|
"description": "Talk to your agents from Telegram, WeCom, Lark, or WeChat (experimental).",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"im",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"markdown-it": "^15.0.2",
|
|
33
33
|
"react": "19.2.6",
|
|
34
34
|
"vite-plus": "0.2.2",
|
|
35
|
-
"@ycodium-ai/plugin-api": "0.2.
|
|
35
|
+
"@ycodium-ai/plugin-api": "0.2.3112"
|
|
36
36
|
},
|
|
37
37
|
"ycodium": {
|
|
38
38
|
"plugin": "./dist/index.js",
|