@primusclaw/personal-agent 0.5.0 → 0.7.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/index.js +536 -66
- package/dist/types/assistant/chat.d.ts +2 -0
- package/dist/types/assistant/choice-clicks.d.ts +35 -0
- package/dist/types/assistant/events.d.ts +17 -0
- package/dist/types/assistant/index.d.ts +1 -0
- package/dist/types/assistant/say.d.ts +12 -4
- package/dist/types/assistant/views.d.ts +22 -0
- package/dist/types/language/chosen.d.ts +24 -0
- package/dist/types/language/group.d.ts +18 -0
- package/dist/types/locales/assistant-cards.d.ts +15 -0
- package/dist/types/locales/group-language.d.ts +32 -0
- package/dist/types/locales/group.d.ts +1 -1
- package/dist/types/locales/terminal-approvals.d.ts +5 -0
- package/dist/types/ports/store/assistant.d.ts +27 -1
- package/dist/types/ports/store/group-language.d.ts +20 -0
- package/dist/types/ports/store/index.d.ts +3 -0
- package/dist/types/ports/surface.d.ts +6 -0
- package/dist/types/protocol/claw-api/assistant-events.d.ts +24 -2
- package/dist/types/remote-view/terminal-ask-view.d.ts +11 -1
- package/dist/types/routing/chat.d.ts +16 -2
- package/dist/types/routing/deps.d.ts +1 -1
- package/dist/types/routing/group-language.d.ts +25 -0
- package/dist/types/routing/group-router.d.ts +3 -1
- package/dist/types/routing/personal-text.d.ts +2 -1
- package/dist/types/routing/turn-runner.d.ts +6 -0
- package/dist/types/routing/turn-start.d.ts +7 -2
- package/dist/types/turn/engine/context.d.ts +4 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -4029,7 +4029,18 @@ var assistantCardText = defineCatalog({
|
|
|
4029
4029
|
minutesAgo: (p) => `${String(p.n)} min ago`,
|
|
4030
4030
|
hoursAgo: (p) => `${String(p.n)} h ago`,
|
|
4031
4031
|
daysAgo: (p) => `${String(p.n)} d ago`,
|
|
4032
|
-
askedTitle: (p) => `Asked of others \xB7 ${String(p.n)}
|
|
4032
|
+
askedTitle: (p) => `Asked of others \xB7 ${String(p.n)}`,
|
|
4033
|
+
choiceTitle: "Pick one",
|
|
4034
|
+
choiceTitleMany: "Pick any that apply",
|
|
4035
|
+
choiceSend: "Send",
|
|
4036
|
+
choiceTyped: "You can also just reply in the chat.",
|
|
4037
|
+
choiceNone: "Pick an option first, then press Send.",
|
|
4038
|
+
choiceSent: (p) => `You picked: ${p.answer}`,
|
|
4039
|
+
choiceGone: "This choice is no longer open. Reply in the chat instead.",
|
|
4040
|
+
choiceSending: (p) => `Sending: ${p.answer}. If nothing comes back, reply in the chat instead.`,
|
|
4041
|
+
choiceFailed: "That did not go through. Press Send again.",
|
|
4042
|
+
/** How the options picked are joined into the person's message. */
|
|
4043
|
+
choiceJoin: ", "
|
|
4033
4044
|
},
|
|
4034
4045
|
zh: {
|
|
4035
4046
|
...english2,
|
|
@@ -4066,7 +4077,17 @@ var assistantCardText = defineCatalog({
|
|
|
4066
4077
|
minutesAgo: (p) => `${String(p.n)} \u5206\u949F\u524D`,
|
|
4067
4078
|
hoursAgo: (p) => `${String(p.n)} \u5C0F\u65F6\u524D`,
|
|
4068
4079
|
daysAgo: (p) => `${String(p.n)} \u5929\u524D`,
|
|
4069
|
-
askedTitle: (p) => `\u8BF7\u522B\u4EBA\u505A\u7684\u4EE3\u5BA1 \xB7 ${String(p.n)}
|
|
4080
|
+
askedTitle: (p) => `\u8BF7\u522B\u4EBA\u505A\u7684\u4EE3\u5BA1 \xB7 ${String(p.n)}`,
|
|
4081
|
+
choiceTitle: "\u8BF7\u9009\u62E9\u4E00\u9879",
|
|
4082
|
+
choiceTitleMany: "\u53EF\u591A\u9009",
|
|
4083
|
+
choiceSend: "\u53D1\u9001",
|
|
4084
|
+
choiceTyped: "\u4E5F\u53EF\u4EE5\u76F4\u63A5\u5728\u804A\u5929\u91CC\u56DE\u590D\u3002",
|
|
4085
|
+
choiceNone: "\u8BF7\u5148\u9009\u4E00\u9879\uFF0C\u518D\u70B9\u53D1\u9001\u3002",
|
|
4086
|
+
choiceSent: (p) => `\u4F60\u9009\u4E86\uFF1A${p.answer}`,
|
|
4087
|
+
choiceGone: "\u8FD9\u4E2A\u9009\u62E9\u5DF2\u7ECF\u5931\u6548\uFF0C\u8BF7\u76F4\u63A5\u5728\u804A\u5929\u91CC\u56DE\u590D\u3002",
|
|
4088
|
+
choiceSending: (p) => `\u6B63\u5728\u53D1\u9001\uFF1A${p.answer}\u3002\u5982\u679C\u4E00\u76F4\u6CA1\u6709\u56DE\u5E94\uFF0C\u8BF7\u76F4\u63A5\u5728\u804A\u5929\u91CC\u56DE\u590D\u3002`,
|
|
4089
|
+
choiceFailed: "\u6CA1\u6709\u53D1\u51FA\u53BB\uFF0C\u8BF7\u518D\u70B9\u4E00\u6B21\u53D1\u9001\u3002",
|
|
4090
|
+
choiceJoin: "\u3001"
|
|
4070
4091
|
}
|
|
4071
4092
|
});
|
|
4072
4093
|
var ASKED_VERDICT = {
|
|
@@ -4969,6 +4990,7 @@ var ITEM_KINDS = ["task", "review", "remote"];
|
|
|
4969
4990
|
|
|
4970
4991
|
// ../claw/packages/protocol/src/claw-api/assistant-events.ts
|
|
4971
4992
|
var ASSISTANT_EVENT_TYPES = ["assistant.say", "work_item.needs_you", "assistant.action"];
|
|
4993
|
+
var TERMINAL_ASKS = ["after_card", "on_input"];
|
|
4972
4994
|
var REVIEW_HANDOFF_ACTION = "review_for_other";
|
|
4973
4995
|
|
|
4974
4996
|
// ../claw/packages/protocol/src/claw-api/notifications.ts
|
|
@@ -6076,6 +6098,19 @@ function deliveryLine(delivery, url) {
|
|
|
6076
6098
|
return turnEnglish.deliveryLine(plain(delivery.name), sizeText(delivery.size), caption, url);
|
|
6077
6099
|
}
|
|
6078
6100
|
|
|
6101
|
+
// packages/core/src/language/chosen.ts
|
|
6102
|
+
function chosenLang(prefs) {
|
|
6103
|
+
if (!prefs.langSet) return void 0;
|
|
6104
|
+
return prefs.lang === "zh" || prefs.lang === "en" ? prefs.lang : void 0;
|
|
6105
|
+
}
|
|
6106
|
+
function replyLanguageContext(prefs) {
|
|
6107
|
+
const lang = chosenLang(prefs);
|
|
6108
|
+
return lang === void 0 ? {} : { reply_language: lang };
|
|
6109
|
+
}
|
|
6110
|
+
function replyLanguageLine(lang) {
|
|
6111
|
+
return `[Reply language: ${lang === "zh" ? "Chinese" : "English"}]`;
|
|
6112
|
+
}
|
|
6113
|
+
|
|
6079
6114
|
// packages/core/src/language/detect.ts
|
|
6080
6115
|
var CJK2 = /[㐀-䶿一-鿿豈-]/u;
|
|
6081
6116
|
function hasCjk2(text8) {
|
|
@@ -6103,8 +6138,8 @@ function writtenLang(text8) {
|
|
|
6103
6138
|
const words3 = written3.map((w) => w.toLowerCase());
|
|
6104
6139
|
if (words3.length < 3) return void 0;
|
|
6105
6140
|
const first = words3[0] ?? "";
|
|
6106
|
-
const
|
|
6107
|
-
return
|
|
6141
|
+
const sentence3 = EN_VERBS.has(first) || words3.some((w) => EN_GLUE.has(w)) || written3.some((w) => EN_FORM.test(w));
|
|
6142
|
+
return sentence3 ? "en" : void 0;
|
|
6108
6143
|
}
|
|
6109
6144
|
function pickLang2(...texts4) {
|
|
6110
6145
|
for (const text8 of texts4) {
|
|
@@ -6209,9 +6244,13 @@ ${text8}` : quote || text8;
|
|
|
6209
6244
|
function messageOf(ctx) {
|
|
6210
6245
|
const said2 = withQuote(ctx.request.sent || ctx.request.text, ctx.request.quote ?? "");
|
|
6211
6246
|
const note = ctx.record.filesNote;
|
|
6212
|
-
|
|
6247
|
+
const message = said2 && note ? `${said2}
|
|
6213
6248
|
|
|
6214
6249
|
${note}` : said2 || note;
|
|
6250
|
+
const chosen = ctx.request.replyLang;
|
|
6251
|
+
return message && chosen !== void 0 ? `${message}
|
|
6252
|
+
|
|
6253
|
+
${replyLanguageLine(chosen)}` : message;
|
|
6215
6254
|
}
|
|
6216
6255
|
|
|
6217
6256
|
// packages/core/src/locales/claw.ts
|
|
@@ -8837,6 +8876,7 @@ var TurnEngine = class {
|
|
|
8837
8876
|
quote: run.quote,
|
|
8838
8877
|
sent: run.sent,
|
|
8839
8878
|
lang: run.lang,
|
|
8879
|
+
...run.replyLang === void 0 ? {} : { replyLang: run.replyLang },
|
|
8840
8880
|
files: run.files,
|
|
8841
8881
|
...review ? reviewRequest(review) : {}
|
|
8842
8882
|
};
|
|
@@ -9518,21 +9558,34 @@ function helpLang(store, userId, locale, asked3) {
|
|
|
9518
9558
|
const written3 = asked3 !== void 0 && !prefs.langSet ? writtenLang(asked3) : void 0;
|
|
9519
9559
|
return written3 ?? langOf2(store, userId, locale);
|
|
9520
9560
|
}
|
|
9561
|
+
function groupLangOf(store, conversationId, userId, locale, written3) {
|
|
9562
|
+
const chosen = groupChosenLang(store, conversationId);
|
|
9563
|
+
if (chosen !== void 0) return chosen;
|
|
9564
|
+
const prefs = userId ? store.prefs.getPrefs(userId) : void 0;
|
|
9565
|
+
return writtenLang(written3) ?? answerLang(prefs !== void 0 && !prefs.langSet ? prefs.lang : "", locale);
|
|
9566
|
+
}
|
|
9567
|
+
function groupChosenLang(store, conversationId) {
|
|
9568
|
+
const lang = conversationId ? store.groupLanguage?.groupLanguage(conversationId) : null;
|
|
9569
|
+
return lang === "zh" || lang === "en" ? lang : void 0;
|
|
9570
|
+
}
|
|
9521
9571
|
var Chat = class {
|
|
9522
|
-
constructor(store, sender, conversation, scope, locale) {
|
|
9572
|
+
constructor(store, sender, conversation, scope, locale, written3 = "") {
|
|
9523
9573
|
this.store = store;
|
|
9524
9574
|
this.sender = sender;
|
|
9525
9575
|
this.conversation = conversation;
|
|
9526
9576
|
this.scope = scope;
|
|
9527
9577
|
this.locale = locale;
|
|
9578
|
+
this.written = written3;
|
|
9528
9579
|
}
|
|
9529
9580
|
store;
|
|
9530
9581
|
sender;
|
|
9531
9582
|
conversation;
|
|
9532
9583
|
scope;
|
|
9533
9584
|
locale;
|
|
9585
|
+
written;
|
|
9586
|
+
/** In a 1:1 chat the person's language (`langOf`); in a group, the group's (`groupLangOf`). */
|
|
9534
9587
|
lang() {
|
|
9535
|
-
return langOf2(this.store, this.sender.id, this.locale);
|
|
9588
|
+
return this.scope ? groupLangOf(this.store, this.scope, this.sender.id, this.locale, this.written) : langOf2(this.store, this.sender.id, this.locale);
|
|
9536
9589
|
}
|
|
9537
9590
|
zh() {
|
|
9538
9591
|
return this.lang() === "zh";
|
|
@@ -10275,7 +10328,7 @@ var CHAT_ENTRIES = [
|
|
|
10275
10328
|
category: "chat",
|
|
10276
10329
|
zh: "\u8981\u4F60\u62CD\u677F\u65F6\u6211\u53D1\u5361\u7247\uFF1A\u70B9\u6309\u94AE\u56DE\u7B54\u3001\u6279\u51C6\u6216\u62D2\u7EDD",
|
|
10277
10330
|
en: "When I need you, I send a card: tap to answer, approve or deny",
|
|
10278
|
-
covers: ["card:decision", "card:answer", "card:assistant_action"],
|
|
10331
|
+
covers: ["card:decision", "card:answer", "card:assistant_action", "card:assistant_choice"],
|
|
10279
10332
|
where: "both"
|
|
10280
10333
|
}),
|
|
10281
10334
|
capability({
|
|
@@ -10978,7 +11031,12 @@ function renderHelp(language, options = {}) {
|
|
|
10978
11031
|
const oneToOne = chat.group ? oneToOneBlock(lang, chat, bot) : void 0;
|
|
10979
11032
|
if (oneToOne !== void 0) out.push(oneToOne);
|
|
10980
11033
|
out.push(authorityText(zh, chat.parts));
|
|
10981
|
-
if (chat.group)
|
|
11034
|
+
if (chat.group)
|
|
11035
|
+
out.push(
|
|
11036
|
+
zh ? `\u8BBE\u7F6E\u53EA\u80FD\u5728\u548C\u6211\u7684 1:1 \u804A\u5929\u91CC\u6539\u3002
|
|
11037
|
+
\u53EA\u6709\u8FD9\u4E2A\u7FA4\u7684\u56DE\u590D\u8BED\u8A00\u5728\u7FA4\u91CC\u8BBE\uFF1A@${bot} \u8BF4\u300C\u8FD9\u4E2A\u7FA4\u7528\u82F1\u6587\u300D\uFF08\u6216\u4E2D\u6587\u3001\u8DDF\u968F\u63D0\u95EE\u8005\uFF09\u3002` : `Settings are changed in a 1:1 chat with me.
|
|
11038
|
+
This group's language is set here: @${bot} "use English in this group" (or Chinese, or "follow the asker").`
|
|
11039
|
+
);
|
|
10982
11040
|
out.push(dataStatement(lang, !chat.group && chat.parts.has("remote"), options.groupContext));
|
|
10983
11041
|
out.push(
|
|
10984
11042
|
zh ? "\u968F\u65F6\u95EE\u6211\u300C\u4F60\u80FD\u505A\u4EC0\u4E48\u300D\u770B\u8FD9\u4EFD\u8BF4\u660E\u3002\u5E95\u90E8\u83DC\u5355\u91CC\u4E5F\u6709\u5E38\u7528\u7684\u6309\u94AE\u3002" : 'Ask "what can you do" any time to see this again. The menu by the compose box has the common ones too.'
|
|
@@ -11561,8 +11619,8 @@ var VALUED = [
|
|
|
11561
11619
|
function personal(text8, flat2, key) {
|
|
11562
11620
|
if (STOP_IT2.has(key)) return "/stop";
|
|
11563
11621
|
if (DETACH2.has(detachKey(key))) return "/agent detach";
|
|
11564
|
-
const
|
|
11565
|
-
if (
|
|
11622
|
+
const phrase2 = lookUp(key, PERSONAL_PHRASES);
|
|
11623
|
+
if (phrase2 !== null) return phrase2;
|
|
11566
11624
|
for (const read of VALUED) {
|
|
11567
11625
|
const command = read(flat2);
|
|
11568
11626
|
if (command !== null) return command;
|
|
@@ -12056,11 +12114,13 @@ var RouterContext = class {
|
|
|
12056
12114
|
/** The chat an event is answered in: its conversation, as the person who sent it. */
|
|
12057
12115
|
chatOf(event, scope) {
|
|
12058
12116
|
const conversation = this.deps.surface.conversation(event.conversation);
|
|
12059
|
-
|
|
12117
|
+
const written3 = event.type === "message" ? event.text : "";
|
|
12118
|
+
return new Chat(this.deps.store, event.sender, conversation, scope, event.locale, written3);
|
|
12060
12119
|
}
|
|
12061
12120
|
/** A chat in another conversation of the same person (their 1:1 chat, a group a request waited in). */
|
|
12062
12121
|
chatIn(chat, ref, scope = "") {
|
|
12063
|
-
|
|
12122
|
+
const written3 = scope ? chat.written : "";
|
|
12123
|
+
return new Chat(this.deps.store, chat.sender, this.deps.surface.conversation(ref), scope, chat.locale, written3);
|
|
12064
12124
|
}
|
|
12065
12125
|
/** A click as a feature handler is given it. */
|
|
12066
12126
|
clickRoute(action, chat) {
|
|
@@ -12113,8 +12173,8 @@ var groupText = defineCatalog({
|
|
|
12113
12173
|
stopMany: (p) => `#${String(p.number)}: more than one repository has it; write it as owner/repo#${String(p.number)}.`
|
|
12114
12174
|
},
|
|
12115
12175
|
zh: {
|
|
12116
|
-
githubOneToOne: "`/github`
|
|
12117
|
-
oneToOneOnly: (p) => `\`${p.word}\`
|
|
12176
|
+
githubOneToOne: "`/github` \u53EA\u80FD\u5728 1:1 \u804A\u5929\u91CC\u7528\uFF0C\u8BF7\u5728\u548C\u6211\u7684 1:1 \u804A\u5929\u91CC\u64CD\u4F5C\u3002",
|
|
12177
|
+
oneToOneOnly: (p) => `\`${p.word}\` \u53EA\u80FD\u5728 1:1 \u804A\u5929\u91CC\u7528\uFF0C\u8BF7\u5728\u548C\u6211\u7684 1:1 \u804A\u5929\u91CC\u64CD\u4F5C\u3002`,
|
|
12118
12178
|
agentInGroup: "`/agent` \u5728\u7FA4\u91CC\u53EA\u80FD\u7528 attach \u548C detach\uFF0C\u5176\u4F59\u8BF7\u5728 1:1 \u804A\u5929\u91CC\u7528\u3002",
|
|
12119
12179
|
whoami: (p) => `${p.name || "\u4F60"} \u5DF2\u8FDE\u63A5\u5230 SaFE \u7528\u6237 ${p.who}\u3002`,
|
|
12120
12180
|
whoamiUnknown: "\u4F60\u5DF2\u8FDE\u63A5\uFF0C\u4F46 SaFE \u6CA1\u544A\u8BC9\u6211\u662F\u8C01\u7684\u8D26\u53F7\u3002",
|
|
@@ -12280,7 +12340,8 @@ var Onboarding = class {
|
|
|
12280
12340
|
try {
|
|
12281
12341
|
const conversation = await this.openPersonal(chat);
|
|
12282
12342
|
if (conversation === void 0) throw new Error("no 1:1 conversation");
|
|
12283
|
-
|
|
12343
|
+
const dm = this.ctx.chatIn(chat, conversation.ref);
|
|
12344
|
+
await dm.say(groupText.in(dm.lang()).targeted({ bot: config.botName }));
|
|
12284
12345
|
} catch (error) {
|
|
12285
12346
|
logger.warn("group: the 1:1 line about a private message did not go out", { error: errorName(error) });
|
|
12286
12347
|
return;
|
|
@@ -13031,6 +13092,208 @@ var SettingsCommands = class {
|
|
|
13031
13092
|
}
|
|
13032
13093
|
};
|
|
13033
13094
|
|
|
13095
|
+
// packages/core/src/language/group.ts
|
|
13096
|
+
var WORDS = /* @__PURE__ */ new Map([
|
|
13097
|
+
["zh", "zh"],
|
|
13098
|
+
["cn", "zh"],
|
|
13099
|
+
["chinese", "zh"],
|
|
13100
|
+
["\u4E2D\u6587", "zh"],
|
|
13101
|
+
["\u6C49\u8BED", "zh"],
|
|
13102
|
+
["en", "en"],
|
|
13103
|
+
["english", "en"],
|
|
13104
|
+
["\u82F1\u6587", "en"],
|
|
13105
|
+
["\u82F1\u8BED", "en"],
|
|
13106
|
+
["auto", "auto"],
|
|
13107
|
+
["follow", "auto"],
|
|
13108
|
+
["\u81EA\u52A8", "auto"],
|
|
13109
|
+
["\u8DDF\u968F", "auto"],
|
|
13110
|
+
["\u8DDF\u968F\u63D0\u95EE\u8005", "auto"],
|
|
13111
|
+
["followtheasker", "auto"]
|
|
13112
|
+
]);
|
|
13113
|
+
var PUNCT2 = ` \r
|
|
13114
|
+
\u3002\uFF0E.\uFF01!\uFF1F?\uFF5E~\uFF0C,\u3001\uFF1B;\uFF1A:"'\u201C\u201D\u2018\u2019\uFF08\uFF09()`;
|
|
13115
|
+
var GROUP = "(?:\u8FD9\u4E2A\u7FA4\u804A|\u8FD9\u4E2A\u7FA4|\u672C\u7FA4|\u6B64\u7FA4|\u7FA4\u804A|\u7FA4)(?:\u91CC\u9762|\u91CC|\u5185|\u4E2D)?";
|
|
13116
|
+
var LANG_ZH = "(\u4E2D\u6587|\u6C49\u8BED|\u82F1\u6587|\u82F1\u8BED)";
|
|
13117
|
+
var ASKER = "(?:\u63D0\u95EE\u8005|\u63D0\u95EE\u4EBA|\u63D0\u95EE\u7684\u4EBA|\u95EE\u95EE\u9898\u7684\u4EBA|\u95EE\u7684\u4EBA|\u53D1\u95EE\u7684\u4EBA)";
|
|
13118
|
+
var ZH_SET = [
|
|
13119
|
+
new RegExp(
|
|
13120
|
+
`^(?:\u4EE5\u540E|\u4E4B\u540E|\u4ECA\u540E|\u4ECE\u73B0\u5728\u8D77|\u4ECE\u73B0\u5728\u5F00\u59CB)?(?:\u8BF7|\u9EBB\u70E6)?(?:\u5728)?${GROUP}(?:\u4EE5\u540E|\u4E4B\u540E|\u4ECA\u540E|\u4ECE\u73B0\u5728\u8D77|\u4ECE\u73B0\u5728\u5F00\u59CB)?(?:\u8BF7)?(?:\u90FD|\u4E00\u5F8B|\u7EDF\u4E00)?(?:\u7528|\u8BF4|\u4F7F\u7528)${LANG_ZH}(?:\u56DE\u590D|\u56DE\u7B54|\u4EA4\u6D41|\u8BF4\u8BDD|\u804A\u5929|\u804A)?(?:\u5427|\u597D\u5417|\u53EF\u4EE5\u5417)?$`,
|
|
13121
|
+
"u"
|
|
13122
|
+
),
|
|
13123
|
+
new RegExp(
|
|
13124
|
+
`^(?:\u628A)?${GROUP}(?:\u7684)?(?:\u56DE\u590D)?\u8BED\u8A00(?:\u8BBE\u4E3A|\u8BBE\u6210|\u6539\u6210|\u6539\u4E3A|\u8BBE\u7F6E\u4E3A|\u8BBE\u7F6E\u6210|\u5207\u6362\u5230|\u5207\u6362\u6210|\u6362\u6210)${LANG_ZH}$`,
|
|
13125
|
+
"u"
|
|
13126
|
+
)
|
|
13127
|
+
];
|
|
13128
|
+
var ZH_AUTO = [
|
|
13129
|
+
new RegExp(
|
|
13130
|
+
`^(?:\u4EE5\u540E|\u4E4B\u540E|\u4ECA\u540E)?(?:\u5728)?${GROUP}(?:\u4EE5\u540E|\u4E4B\u540E|\u4ECA\u540E)?(?:\u90FD)?(?:\u8DDF\u968F|\u8DDF\u7740|\u6309|\u6309\u7167|\u7528)${ASKER}(?:\u7684)?(?:\u8BED\u8A00)?(?:\u56DE\u590D|\u56DE\u7B54)?(?:\u5427)?$`,
|
|
13131
|
+
"u"
|
|
13132
|
+
),
|
|
13133
|
+
new RegExp(
|
|
13134
|
+
`^(?:\u628A)?${GROUP}(?:\u7684)?(?:\u56DE\u590D)?\u8BED\u8A00(?:\u8BBE\u4E3A|\u8BBE\u6210|\u6539\u6210|\u6539\u4E3A|\u8BBE\u7F6E\u4E3A|\u8BBE\u7F6E\u6210|\u5207\u6362\u5230|\u5207\u6362\u6210|\u6362\u6210)(?:\u81EA\u52A8|\u8DDF\u968F${ASKER})$`,
|
|
13135
|
+
"u"
|
|
13136
|
+
)
|
|
13137
|
+
];
|
|
13138
|
+
var LANG_EN = "(english|chinese)";
|
|
13139
|
+
var THIS_GROUP = "(?:this|the|our) (?:group chat|group|chat)";
|
|
13140
|
+
var ANSWER = "(?:use|speak|reply in|answer in|respond in|talk in|write in)";
|
|
13141
|
+
var EN_SET = [
|
|
13142
|
+
new RegExp(`^(?:please )?${ANSWER} ${LANG_EN} (?:in|for) ${THIS_GROUP}(?: from now on)?(?: please)?$`),
|
|
13143
|
+
new RegExp(`^(?:in|for) ${THIS_GROUP},? (?:please )?${ANSWER} ${LANG_EN}(?: from now on)?(?: please)?$`),
|
|
13144
|
+
new RegExp(`^${THIS_GROUP} (?:uses|speaks|is in) ${LANG_EN}$`),
|
|
13145
|
+
new RegExp(
|
|
13146
|
+
`^(?:please )?(?:set|change|switch) (?:the |this )?(?:group|chat)(?:'s)? language to ${LANG_EN}(?: please)?$`
|
|
13147
|
+
)
|
|
13148
|
+
];
|
|
13149
|
+
var EN_AUTO = [
|
|
13150
|
+
new RegExp(
|
|
13151
|
+
`^(?:please )?(?:follow the asker|use the asker'?s language|reply in the asker'?s language|answer in the language of each question)(?: (?:in|for) ${THIS_GROUP})?(?: please)?$`
|
|
13152
|
+
),
|
|
13153
|
+
new RegExp(
|
|
13154
|
+
`^(?:please )?(?:set|change|switch) (?:the |this )?(?:group|chat)(?:'s)? language to (?:auto|follow the asker)(?: please)?$`
|
|
13155
|
+
)
|
|
13156
|
+
];
|
|
13157
|
+
function phrase(text8) {
|
|
13158
|
+
return pySplit(pyLower(pyStrip(text8, PUNCT2))).join("");
|
|
13159
|
+
}
|
|
13160
|
+
function sentence(text8) {
|
|
13161
|
+
return pySplit(pyLower(pyStrip(text8, PUNCT2))).join(" ");
|
|
13162
|
+
}
|
|
13163
|
+
var MAX_SENTENCE_CHARS = 120;
|
|
13164
|
+
function sentenceCommand(text8) {
|
|
13165
|
+
if (text8.length > MAX_SENTENCE_CHARS) return void 0;
|
|
13166
|
+
const zh = phrase(text8);
|
|
13167
|
+
const en2 = sentence(text8);
|
|
13168
|
+
for (const pattern of ZH_SET) {
|
|
13169
|
+
const word2 = pattern.exec(zh)?.[1];
|
|
13170
|
+
const lang = word2 === void 0 ? void 0 : WORDS.get(word2);
|
|
13171
|
+
if (lang !== void 0) return { kind: "set", lang };
|
|
13172
|
+
}
|
|
13173
|
+
if (ZH_AUTO.some((p) => p.test(zh))) return { kind: "set", lang: "auto" };
|
|
13174
|
+
for (const pattern of EN_SET) {
|
|
13175
|
+
const word2 = pattern.exec(en2)?.[1];
|
|
13176
|
+
const lang = word2 === void 0 ? void 0 : WORDS.get(word2);
|
|
13177
|
+
if (lang !== void 0) return { kind: "set", lang };
|
|
13178
|
+
}
|
|
13179
|
+
if (EN_AUTO.some((p) => p.test(en2))) return { kind: "set", lang: "auto" };
|
|
13180
|
+
return void 0;
|
|
13181
|
+
}
|
|
13182
|
+
function parseGroupLang(text8) {
|
|
13183
|
+
const words3 = pySplit(text8);
|
|
13184
|
+
if (pyLower(words3[0] ?? "") !== "/lang") return sentenceCommand(pyStrip(text8));
|
|
13185
|
+
if (words3.length === 1) return { kind: "status" };
|
|
13186
|
+
const lang = WORDS.get(pyLower(words3.slice(1).join("")));
|
|
13187
|
+
return lang === void 0 ? { kind: "usage" } : { kind: "set", lang };
|
|
13188
|
+
}
|
|
13189
|
+
|
|
13190
|
+
// packages/core/src/locales/group-language.ts
|
|
13191
|
+
var NAMES2 = {
|
|
13192
|
+
zh: ["\u4E2D\u6587", "Chinese"],
|
|
13193
|
+
en: ["\u82F1\u6587", "English"],
|
|
13194
|
+
auto: ["\u8DDF\u968F\u63D0\u95EE\u8005\u7684\u8BED\u8A00", "the language each question is asked in"]
|
|
13195
|
+
};
|
|
13196
|
+
function groupLanguageSet(lang, name) {
|
|
13197
|
+
const [zh, en2] = NAMES2[lang];
|
|
13198
|
+
return `\u5DF2\u6539\u4E3A${zh}\u56DE\u590D\uFF0C\u7531 ${name || "\u7FA4\u6210\u5458"} \u8BBE\u7F6E\u3002
|
|
13199
|
+
I answer in ${en2} in this group from now on (set by ${name || "a member"}).`;
|
|
13200
|
+
}
|
|
13201
|
+
var GROUP_LANGUAGE_CARD = {
|
|
13202
|
+
title: "\u8FD9\u4E2A\u7FA4\u7528\u54EA\u79CD\u8BED\u8A00\u56DE\u590D\uFF1F/ Which language should I use in this group?",
|
|
13203
|
+
text: (p) => `\u7FA4\u91CC\u4EFB\u4F55\u4EBA\u90FD\u53EF\u4EE5\u9009\uFF0C\u4E4B\u540E\u4E5F\u80FD\u7528 @${p.bot} /lang zh | en | auto \u518D\u6539\u3002
|
|
13204
|
+
Anyone here may pick; @${p.bot} /lang zh | en | auto changes it later.`,
|
|
13205
|
+
buttons: { zh: "\u4E2D\u6587", en: "English", auto: "\u8DDF\u968F\u63D0\u95EE\u8005 (Follow the asker)" }
|
|
13206
|
+
};
|
|
13207
|
+
var groupLanguageText = defineCatalog({
|
|
13208
|
+
en: {
|
|
13209
|
+
isZh: (p) => `This group is answered in Chinese. @${p.bot} /lang en or /lang auto changes it.`,
|
|
13210
|
+
isEn: (p) => `This group is answered in English. @${p.bot} /lang zh or /lang auto changes it.`,
|
|
13211
|
+
isAuto: (p) => `This group is answered in the language each question is asked in. @${p.bot} /lang zh or /lang en sets one.`,
|
|
13212
|
+
isNone: (p) => `This group has no language set: each question is answered in the language it is asked in. @${p.bot} /lang zh, /lang en or /lang auto sets it.`,
|
|
13213
|
+
usage: (p) => `Usage: @${p.bot} /lang zh | en | auto (follow the asker).`
|
|
13214
|
+
},
|
|
13215
|
+
zh: {
|
|
13216
|
+
isZh: (p) => `\u8FD9\u4E2A\u7FA4\u7528\u4E2D\u6587\u56DE\u590D\u3002@${p.bot} /lang en \u6216 /lang auto \u53EF\u6539\u3002`,
|
|
13217
|
+
isEn: (p) => `\u8FD9\u4E2A\u7FA4\u7528\u82F1\u6587\u56DE\u590D\u3002@${p.bot} /lang zh \u6216 /lang auto \u53EF\u6539\u3002`,
|
|
13218
|
+
isAuto: (p) => `\u8FD9\u4E2A\u7FA4\u6309\u6BCF\u4E2A\u95EE\u9898\u6240\u7528\u7684\u8BED\u8A00\u56DE\u590D\u3002@${p.bot} /lang zh \u6216 /lang en \u53EF\u8BBE\u4E3A\u56FA\u5B9A\u8BED\u8A00\u3002`,
|
|
13219
|
+
isNone: (p) => `\u8FD9\u4E2A\u7FA4\u8FD8\u6CA1\u8BBE\u8BED\u8A00\uFF1A\u6BCF\u4E2A\u95EE\u9898\u6309\u5B83\u6240\u7528\u7684\u8BED\u8A00\u56DE\u590D\u3002@${p.bot} /lang zh\u3001/lang en \u6216 /lang auto \u53EF\u8BBE\u7F6E\u3002`,
|
|
13220
|
+
usage: (p) => `\u7528\u6CD5\uFF1A@${p.bot} /lang zh | en | auto\uFF08\u8DDF\u968F\u63D0\u95EE\u8005\uFF09\u3002`
|
|
13221
|
+
}
|
|
13222
|
+
});
|
|
13223
|
+
|
|
13224
|
+
// packages/core/src/routing/group-language.ts
|
|
13225
|
+
var GROUP_LANG_VERB = "group_lang";
|
|
13226
|
+
var LANGS2 = ["zh", "en", "auto"];
|
|
13227
|
+
function isGroupLanguage(value) {
|
|
13228
|
+
return typeof value === "string" && LANGS2.includes(value);
|
|
13229
|
+
}
|
|
13230
|
+
var GroupLanguages = class {
|
|
13231
|
+
constructor(ctx) {
|
|
13232
|
+
this.ctx = ctx;
|
|
13233
|
+
}
|
|
13234
|
+
ctx;
|
|
13235
|
+
/** `/lang …` or a sentence that sets the group's language: answered here; false when `text` is neither. */
|
|
13236
|
+
async command(chat, text8) {
|
|
13237
|
+
const command = parseGroupLang(text8);
|
|
13238
|
+
if (command === void 0) return false;
|
|
13239
|
+
const bot = this.ctx.deps.config.botName;
|
|
13240
|
+
if (command.kind === "set") {
|
|
13241
|
+
this.ctx.deps.store.groupLanguage.setGroupLanguage(chat.scope, command.lang);
|
|
13242
|
+
await chat.say(groupLanguageSet(command.lang, chat.sender.name));
|
|
13243
|
+
return true;
|
|
13244
|
+
}
|
|
13245
|
+
const said2 = groupLanguageText.in(chat.lang());
|
|
13246
|
+
if (command.kind === "usage") {
|
|
13247
|
+
await chat.say(said2.usage({ bot }));
|
|
13248
|
+
return true;
|
|
13249
|
+
}
|
|
13250
|
+
const lang = this.ctx.deps.store.groupLanguage.groupLanguage(chat.scope);
|
|
13251
|
+
const state = lang === "zh" ? said2.isZh : lang === "en" ? said2.isEn : lang === "auto" ? said2.isAuto : said2.isNone;
|
|
13252
|
+
await chat.say(state({ bot }));
|
|
13253
|
+
return true;
|
|
13254
|
+
}
|
|
13255
|
+
/**
|
|
13256
|
+
* The first @mention in a chat that has no language: the card that asks its members which, once (the chat is recorded as asked
|
|
13257
|
+
* before the card goes, so two mentions at once put one; a card that could not be posted is asked again next time).
|
|
13258
|
+
*/
|
|
13259
|
+
async askOnce(chat) {
|
|
13260
|
+
const { store, logger, config } = this.ctx.deps;
|
|
13261
|
+
if (!store.groupLanguage.markGroupLanguageAsked(chat.scope)) return;
|
|
13262
|
+
const buttons2 = LANGS2.map(
|
|
13263
|
+
(lang) => viewButtonOf({ title: GROUP_LANGUAGE_CARD.buttons[lang], verb: GROUP_LANG_VERB, data: { lang } })
|
|
13264
|
+
);
|
|
13265
|
+
try {
|
|
13266
|
+
await chat.send(
|
|
13267
|
+
noteMessage({
|
|
13268
|
+
title: GROUP_LANGUAGE_CARD.title,
|
|
13269
|
+
text: GROUP_LANGUAGE_CARD.text({ bot: config.botName }),
|
|
13270
|
+
tone: "accent",
|
|
13271
|
+
buttons: buttons2
|
|
13272
|
+
})
|
|
13273
|
+
);
|
|
13274
|
+
} catch (error) {
|
|
13275
|
+
store.groupLanguage.unmarkGroupLanguageAsked(chat.scope);
|
|
13276
|
+
logger.warn("group: the language card could not be posted; it is asked again next time", {
|
|
13277
|
+
error: errorName(error)
|
|
13278
|
+
});
|
|
13279
|
+
}
|
|
13280
|
+
}
|
|
13281
|
+
/** A pick on the language card, by anyone in the chat: the language is set, the card says so, and so does the chat. */
|
|
13282
|
+
async click(action, chat) {
|
|
13283
|
+
const lang = action.data["lang"];
|
|
13284
|
+
if (!isGroupLanguage(lang)) {
|
|
13285
|
+
await this.ctx.settle(
|
|
13286
|
+
action,
|
|
13287
|
+
chat,
|
|
13288
|
+
groupLanguageText.in(chat.lang()).usage({ bot: this.ctx.deps.config.botName })
|
|
13289
|
+
);
|
|
13290
|
+
return;
|
|
13291
|
+
}
|
|
13292
|
+
this.ctx.deps.store.groupLanguage.setGroupLanguage(chat.scope, lang);
|
|
13293
|
+
await this.ctx.settle(action, chat, groupLanguageSet(lang, chat.sender.name));
|
|
13294
|
+
}
|
|
13295
|
+
};
|
|
13296
|
+
|
|
13034
13297
|
// packages/core/src/routing/show-here.ts
|
|
13035
13298
|
var ShowHere = class {
|
|
13036
13299
|
constructor(ctx) {
|
|
@@ -13206,11 +13469,12 @@ var PersonalRouter = class {
|
|
|
13206
13469
|
const { assistant, remote } = this.ctx.deps;
|
|
13207
13470
|
const userId = chat.sender.id;
|
|
13208
13471
|
const understood = assistant.understands(userId);
|
|
13209
|
-
const
|
|
13210
|
-
const
|
|
13211
|
-
const
|
|
13472
|
+
const choice = message.choice === true;
|
|
13473
|
+
const switching = understood && !choice && remote.enabled && switchCommand(message.text) !== null;
|
|
13474
|
+
const forAssistant = understood && (choice || !exactCommand(message.text, { menuCommand, isKnownCommand })) && !switching;
|
|
13475
|
+
const text8 = understood && !choice ? menuCommand(message.text) : this.text.textOf(message);
|
|
13212
13476
|
learnLang(this.ctx.deps.store, userId, message.text);
|
|
13213
|
-
if (await this.beforeCredential(message, chat, text8, forAssistant)) return;
|
|
13477
|
+
if (!choice && await this.beforeCredential(message, chat, text8, forAssistant)) return;
|
|
13214
13478
|
const key = await this.ctx.credentials.credential(chat, true);
|
|
13215
13479
|
if (key === void 0) return;
|
|
13216
13480
|
if (forAssistant && !this.text.talksToAgent(message)) await this.text.understand(message, chat, key);
|
|
@@ -13306,7 +13570,7 @@ var GroupRemote = class {
|
|
|
13306
13570
|
const { remote } = this.ctx.deps;
|
|
13307
13571
|
const bound = this.chatOf(chat);
|
|
13308
13572
|
const attached = remote.attached(bound.id);
|
|
13309
|
-
const args = this.agentArgs(words3.text, attached);
|
|
13573
|
+
const args = message.choice === true ? null : this.agentArgs(words3.text, attached);
|
|
13310
13574
|
const provider = this.ctx.credentials.provider(chat.sender.id, key);
|
|
13311
13575
|
if (args !== null) {
|
|
13312
13576
|
const parsed = parseAgentCommand(args);
|
|
@@ -13327,11 +13591,12 @@ var GroupRemote = class {
|
|
|
13327
13591
|
const { remote } = this.ctx.deps;
|
|
13328
13592
|
const bound = this.chatOf(chat);
|
|
13329
13593
|
const provider = this.ctx.credentials.provider(chat.sender.id, key);
|
|
13330
|
-
|
|
13594
|
+
const choice = message.choice === true;
|
|
13595
|
+
if (!choice && (naturalCommand(words3.text) === "/stop" || parseCommand(words3.text) === "stop")) {
|
|
13331
13596
|
await remote.stop(bound, key, chat.conversation);
|
|
13332
13597
|
return true;
|
|
13333
13598
|
}
|
|
13334
|
-
if (parseCommand(words3.text) !== null) return false;
|
|
13599
|
+
if (!choice && parseCommand(words3.text) !== null) return false;
|
|
13335
13600
|
let quote = words3.quote;
|
|
13336
13601
|
if (remote.windowMode(bound.id) === "card") {
|
|
13337
13602
|
if (!remote.quotesWindow(bound.id, message)) return false;
|
|
@@ -13552,7 +13817,8 @@ async function answerWaitingQuestion(ctx, reply) {
|
|
|
13552
13817
|
questions: questions.length,
|
|
13553
13818
|
card: pending.cardId ? "edited" : "not editable"
|
|
13554
13819
|
});
|
|
13555
|
-
|
|
13820
|
+
const lang = answerLang(store.prefs.getPrefs(chat.sender.id).lang, chat.locale, questions[0]?.question, reply.text);
|
|
13821
|
+
await settleCard(ctx, chat, pending.cardId, [...answers.answers], lang);
|
|
13556
13822
|
return true;
|
|
13557
13823
|
}
|
|
13558
13824
|
function waitingQuestion(ctx, reply) {
|
|
@@ -13621,7 +13887,8 @@ var TurnStarter = class {
|
|
|
13621
13887
|
return Promise.all([...this.running]).then(() => void 0);
|
|
13622
13888
|
}
|
|
13623
13889
|
/** The turn that runs (its end is `done`), or undefined when none was started (the person was told why). */
|
|
13624
|
-
async start(
|
|
13890
|
+
async start(started) {
|
|
13891
|
+
const request = { ...started, ...this.replyLang(started) };
|
|
13625
13892
|
const { chat, review } = request;
|
|
13626
13893
|
if (await this.answersQuestion(request)) return void 0;
|
|
13627
13894
|
const key = review ? reviewTurnKey(chat.sender.id, chat.scope, review.itemId, review.pull) : chatTurnKey(chat.sender.id, chat.scope);
|
|
@@ -13778,11 +14045,22 @@ var TurnStarter = class {
|
|
|
13778
14045
|
sent: request.sent ?? "",
|
|
13779
14046
|
files: request.files ?? [],
|
|
13780
14047
|
lang: review?.lang ?? chat.lang(),
|
|
14048
|
+
...request.replyLang === void 0 ? {} : { replyLang: request.replyLang },
|
|
13781
14049
|
ownThumbs: this.ownThumbs(request),
|
|
13782
14050
|
notifies: this.ctx.deps.subscriptions !== void 0 && store.notifySubs.getNotifySub(chat.sender.id) !== null,
|
|
13783
14051
|
review: review?.fields
|
|
13784
14052
|
};
|
|
13785
14053
|
}
|
|
14054
|
+
/**
|
|
14055
|
+
* The language a chat turn is to be answered in, when one was chosen (a review's answer follows its request's language): in a
|
|
14056
|
+
* group the group's (`groupChosenLang`; the sender's own choice is not read there), in a 1:1 chat the person's.
|
|
14057
|
+
*/
|
|
14058
|
+
replyLang(request) {
|
|
14059
|
+
if (request.review !== void 0) return {};
|
|
14060
|
+
const { store } = this.ctx.deps;
|
|
14061
|
+
const lang = request.chat.scope ? groupChosenLang(store, request.chat.scope) : chosenLang(store.prefs.getPrefs(request.chat.sender.id));
|
|
14062
|
+
return lang === void 0 ? {} : { replyLang: lang };
|
|
14063
|
+
}
|
|
13786
14064
|
hooks(request, run, turn, turnId) {
|
|
13787
14065
|
const { review, chat } = request;
|
|
13788
14066
|
const store = this.ctx.deps.store;
|
|
@@ -13866,9 +14144,11 @@ var PersonalText = class {
|
|
|
13866
14144
|
starter;
|
|
13867
14145
|
/**
|
|
13868
14146
|
* What the person wrote, with a word of the commands menu read as its command and a sentence help teaches read as the
|
|
13869
|
-
* command it means; a sentence for what this chat cannot do right now stays words.
|
|
14147
|
+
* command it means; a sentence for what this chat cannot do right now stays words. A choice picked on the assistant's card
|
|
14148
|
+
* is the words picked, never a command.
|
|
13870
14149
|
*/
|
|
13871
14150
|
textOf(message, group = false) {
|
|
14151
|
+
if (message.choice === true) return message.text;
|
|
13872
14152
|
const { github, assistant, remote, config } = this.ctx.deps;
|
|
13873
14153
|
const userId = group ? void 0 : message.sender.id;
|
|
13874
14154
|
const on = (test) => userId !== void 0 && test(userId);
|
|
@@ -13894,6 +14174,10 @@ var PersonalText = class {
|
|
|
13894
14174
|
}
|
|
13895
14175
|
async onText(message, chat, key) {
|
|
13896
14176
|
const text8 = this.textOf(message);
|
|
14177
|
+
if (message.choice === true) {
|
|
14178
|
+
await this.sentOn(message, chat, key);
|
|
14179
|
+
return;
|
|
14180
|
+
}
|
|
13897
14181
|
if (parseCommand(text8) === "unlink" && !message.text.startsWith("/")) {
|
|
13898
14182
|
await chat.say(routingText.in(chat.lang()).unlinkAsk);
|
|
13899
14183
|
return;
|
|
@@ -13945,7 +14229,7 @@ var PersonalText = class {
|
|
|
13945
14229
|
const sent = messageText.withLinks(text8, message);
|
|
13946
14230
|
const prompt = messageText.withQuote(sent, quote);
|
|
13947
14231
|
const files = await this.attachments(message, chat, toAgent);
|
|
13948
|
-
const control = this.sessionControl(userId, prompt, toAgent, quote, files, text8);
|
|
14232
|
+
const control = message.choice !== true && this.sessionControl(userId, prompt, toAgent, quote, files, text8);
|
|
13949
14233
|
if (control && assistant.understands(userId)) {
|
|
13950
14234
|
await this.understand(message, chat, key);
|
|
13951
14235
|
} else if (prompt && toAgent && !control) {
|
|
@@ -14120,13 +14404,14 @@ var STOP_SAID = {
|
|
|
14120
14404
|
item_closed: ["\u5DF2\u7ECF\u7ED3\u675F\u4E86\u3002", "it had already ended."]
|
|
14121
14405
|
};
|
|
14122
14406
|
var GroupRouter = class {
|
|
14123
|
-
constructor(ctx, text8, sessions, onboarding, remote, starter) {
|
|
14407
|
+
constructor(ctx, text8, sessions, onboarding, remote, starter, languages) {
|
|
14124
14408
|
this.ctx = ctx;
|
|
14125
14409
|
this.text = text8;
|
|
14126
14410
|
this.sessions = sessions;
|
|
14127
14411
|
this.onboarding = onboarding;
|
|
14128
14412
|
this.remote = remote;
|
|
14129
14413
|
this.starter = starter;
|
|
14414
|
+
this.languages = languages;
|
|
14130
14415
|
}
|
|
14131
14416
|
ctx;
|
|
14132
14417
|
text;
|
|
@@ -14134,6 +14419,7 @@ var GroupRouter = class {
|
|
|
14134
14419
|
onboarding;
|
|
14135
14420
|
remote;
|
|
14136
14421
|
starter;
|
|
14422
|
+
languages;
|
|
14137
14423
|
async route(event, chat) {
|
|
14138
14424
|
if (!chat.scope) return;
|
|
14139
14425
|
if (event.type === "action") await this.click(event, chat);
|
|
@@ -14147,6 +14433,10 @@ var GroupRouter = class {
|
|
|
14147
14433
|
await this.onboarding.click(action, chat);
|
|
14148
14434
|
return;
|
|
14149
14435
|
}
|
|
14436
|
+
if (action.verb === GROUP_LANG_VERB) {
|
|
14437
|
+
await this.languages.click(action, chat);
|
|
14438
|
+
return;
|
|
14439
|
+
}
|
|
14150
14440
|
const handler = this.ctx.deps.handlers.clicks.find((h) => h.verbs.includes(action.verb));
|
|
14151
14441
|
if (handler?.inGroup !== void 0) await handler.inGroup(this.ctx.clickRoute(action, chat));
|
|
14152
14442
|
}
|
|
@@ -14158,7 +14448,11 @@ var GroupRouter = class {
|
|
|
14158
14448
|
async message(message, chat) {
|
|
14159
14449
|
const words3 = this.words(message);
|
|
14160
14450
|
learnLang(this.ctx.deps.store, chat.sender.id, message.text);
|
|
14161
|
-
|
|
14451
|
+
const choice = message.choice === true;
|
|
14452
|
+
const language = !choice && await this.languages.command(chat, words3.text);
|
|
14453
|
+
await this.languages.askOnce(chat);
|
|
14454
|
+
if (language) return;
|
|
14455
|
+
if (!choice && await this.groupOwn(message, chat, words3)) return;
|
|
14162
14456
|
const route = {
|
|
14163
14457
|
sender: chat.sender,
|
|
14164
14458
|
conversation: chat.conversation,
|
|
@@ -14167,10 +14461,13 @@ var GroupRouter = class {
|
|
|
14167
14461
|
message,
|
|
14168
14462
|
text: words3.text
|
|
14169
14463
|
};
|
|
14170
|
-
|
|
14464
|
+
if (!choice) {
|
|
14465
|
+
for (const interceptor of this.ctx.deps.handlers.groupInterceptors)
|
|
14466
|
+
if (await interceptor.intercept(route)) return;
|
|
14467
|
+
}
|
|
14171
14468
|
const key = await this.ctx.credentials.credential(chat, false);
|
|
14172
14469
|
if (key === void 0) {
|
|
14173
|
-
const keep = parseCommand(words3.text) === null;
|
|
14470
|
+
const keep = choice || parseCommand(words3.text) === null;
|
|
14174
14471
|
await this.onboarding.member(message, chat, { ...words3, keep, identity: false });
|
|
14175
14472
|
return;
|
|
14176
14473
|
}
|
|
@@ -14184,7 +14481,7 @@ var GroupRouter = class {
|
|
|
14184
14481
|
const [first = ""] = pySplit(words3.text);
|
|
14185
14482
|
const word2 = pyLower(first);
|
|
14186
14483
|
if (empty || word2 === "/help") {
|
|
14187
|
-
const lang =
|
|
14484
|
+
const lang = chat.lang();
|
|
14188
14485
|
const assistant = this.ctx.deps.assistant.on(chat.sender.id);
|
|
14189
14486
|
const groupContext = this.ctx.deps.groupHistory.kept(message.conversation.id);
|
|
14190
14487
|
await chat.say(
|
|
@@ -14199,11 +14496,11 @@ var GroupRouter = class {
|
|
|
14199
14496
|
return true;
|
|
14200
14497
|
}
|
|
14201
14498
|
if (github !== void 0 && word2 === "/github") {
|
|
14202
|
-
await chat.say(groupText.in(
|
|
14499
|
+
await chat.say(groupText.in(chat.lang()).githubOneToOne);
|
|
14203
14500
|
return true;
|
|
14204
14501
|
}
|
|
14205
14502
|
if (!this.oneToOneOnly(word2, words3.text, remote.enabled)) return false;
|
|
14206
|
-
await chat.say(groupText.in(
|
|
14503
|
+
await chat.say(groupText.in(chat.lang()).oneToOneOnly({ word: word2 }));
|
|
14207
14504
|
return true;
|
|
14208
14505
|
}
|
|
14209
14506
|
/** A command of a 1:1 chat (`/agent attach|detach` binds the group: it stays the group's). */
|
|
@@ -14213,7 +14510,7 @@ var GroupRouter = class {
|
|
|
14213
14510
|
return !(word2 === "/agent" && remoteOn && (verb === "attach" || verb === "detach"));
|
|
14214
14511
|
}
|
|
14215
14512
|
async withKey(message, chat, key, words3) {
|
|
14216
|
-
const command = parseCommand(words3.text);
|
|
14513
|
+
const command = message.choice === true ? null : parseCommand(words3.text);
|
|
14217
14514
|
if (command === "new") await this.sessions.new(chat, chat.scope);
|
|
14218
14515
|
else if (command === "stop") await this.sessions.stop(chat, key, chat.scope);
|
|
14219
14516
|
else if (command === "whoami") await this.whoami(chat, key);
|
|
@@ -14270,7 +14567,7 @@ ${quote}` : history || quote;
|
|
|
14270
14567
|
};
|
|
14271
14568
|
}
|
|
14272
14569
|
async stopReviews(chat, pulls, text8) {
|
|
14273
|
-
const zh = hasCjk2(text8);
|
|
14570
|
+
const zh = (groupChosenLang(this.ctx.deps.store, chat.scope) ?? (hasCjk2(text8) ? "zh" : "en")) === "zh";
|
|
14274
14571
|
const said2 = groupText.in(zh ? "zh" : "en");
|
|
14275
14572
|
const key = await this.ctx.credentials.credential(chat, false);
|
|
14276
14573
|
let items;
|
|
@@ -14440,7 +14737,8 @@ var Router = class _Router {
|
|
|
14440
14737
|
sessions,
|
|
14441
14738
|
this.onboarding,
|
|
14442
14739
|
new GroupRemote(this.ctx, this.text),
|
|
14443
|
-
this.starter
|
|
14740
|
+
this.starter,
|
|
14741
|
+
new GroupLanguages(this.ctx)
|
|
14444
14742
|
);
|
|
14445
14743
|
}
|
|
14446
14744
|
async handle(event) {
|
|
@@ -14517,7 +14815,7 @@ var Router = class _Router {
|
|
|
14517
14815
|
*/
|
|
14518
14816
|
async withinRate(message, chat) {
|
|
14519
14817
|
const group = message.conversation.kind === "group";
|
|
14520
|
-
if (group && !message.mentioned || _Router.isStop(message.text, group)) return true;
|
|
14818
|
+
if (group && !message.mentioned || message.choice !== true && _Router.isStop(message.text, group)) return true;
|
|
14521
14819
|
const { limits, securityEvent, metrics } = this.ctx.deps;
|
|
14522
14820
|
const verdict = limits.checkMessage(chat.sender.id);
|
|
14523
14821
|
if (verdict.allowed) return true;
|
|
@@ -14575,7 +14873,7 @@ var Router = class _Router {
|
|
|
14575
14873
|
};
|
|
14576
14874
|
|
|
14577
14875
|
// packages/core/src/approvals/sensitive.ts
|
|
14578
|
-
var
|
|
14876
|
+
var WORDS2 = /* @__PURE__ */ new Set([
|
|
14579
14877
|
"token",
|
|
14580
14878
|
"secret",
|
|
14581
14879
|
"secrets",
|
|
@@ -14680,7 +14978,7 @@ function isSensitiveName(name) {
|
|
|
14680
14978
|
const parts2 = nameWords(String(name));
|
|
14681
14979
|
if (parts2.length === 0 || COUNTERS.has(parts2.join(" "))) return false;
|
|
14682
14980
|
return parts2.some((word2, i) => {
|
|
14683
|
-
if (
|
|
14981
|
+
if (WORDS2.has(word2)) return true;
|
|
14684
14982
|
const next = parts2[i + 1];
|
|
14685
14983
|
if (next === void 0) return false;
|
|
14686
14984
|
const pair = `${word2} ${next}`;
|
|
@@ -15539,6 +15837,10 @@ var AssistantChat = class {
|
|
|
15539
15837
|
filesOnly(lang) {
|
|
15540
15838
|
return assistantChatText.in(lang).filesOnly;
|
|
15541
15839
|
}
|
|
15840
|
+
/** The language the person chose to be answered in, as the message's `channel_context` carries it (none: nothing is sent). */
|
|
15841
|
+
chosenLanguage(userId) {
|
|
15842
|
+
return replyLanguageContext(this.o.store.prefs.getPrefs(userId));
|
|
15843
|
+
}
|
|
15542
15844
|
langOf(userId, text8) {
|
|
15543
15845
|
return answerLang(this.o.store.prefs.getPrefs(userId).lang, this.o.clientLocale?.() ?? "", text8);
|
|
15544
15846
|
}
|
|
@@ -15558,10 +15860,11 @@ var AssistantChat = class {
|
|
|
15558
15860
|
const handing = { ...request };
|
|
15559
15861
|
const sent = await this.handTo(handing, async (sessionId, ready) => {
|
|
15560
15862
|
const folderId = typeof request.context["channel_message_id"] === "string" ? request.context["channel_message_id"] : "";
|
|
15561
|
-
const context2 =
|
|
15863
|
+
const context2 = {
|
|
15562
15864
|
...request.context,
|
|
15563
|
-
files: await this.handOverFiles(handing, sessionId, folderId || this.o.random.hexId(), request.files)
|
|
15564
|
-
|
|
15865
|
+
...request.files.length ? { files: await this.handOverFiles(handing, sessionId, folderId || this.o.random.hexId(), request.files) } : {},
|
|
15866
|
+
...this.chosenLanguage(request.userId)
|
|
15867
|
+
};
|
|
15565
15868
|
await ready();
|
|
15566
15869
|
return this.o.claw.assistant.send(request.credential, sessionId, request.prompt, {
|
|
15567
15870
|
...request.modelKey ? { modelKey: request.modelKey } : {},
|
|
@@ -15633,7 +15936,7 @@ var AssistantChat = class {
|
|
|
15633
15936
|
async (_sessionId, ready) => {
|
|
15634
15937
|
const files = request.files.length ? { files: await this.handOverFiles(handing, sessionId, this.o.random.hexId(), request.files) } : {};
|
|
15635
15938
|
const attached = request.attached === void 0 ? {} : { attached: attachedOf(request.attached) };
|
|
15636
|
-
const context2 = { ...files, ...attached };
|
|
15939
|
+
const context2 = { ...files, ...attached, ...this.chosenLanguage(request.userId) };
|
|
15637
15940
|
await ready();
|
|
15638
15941
|
return this.o.claw.assistant.send(request.credential, sessionId, request.prompt, {
|
|
15639
15942
|
...Object.keys(context2).length ? { context: context2 } : {},
|
|
@@ -16134,6 +16437,117 @@ var AssistantActions = class {
|
|
|
16134
16437
|
}
|
|
16135
16438
|
};
|
|
16136
16439
|
|
|
16440
|
+
// packages/core/src/assistant/choice-clicks.ts
|
|
16441
|
+
var CHOICE_VERB = "assistant_choice";
|
|
16442
|
+
var CHOICE_INPUT = "choice";
|
|
16443
|
+
function pickedOn(card, value) {
|
|
16444
|
+
const places = new Set(
|
|
16445
|
+
pyStr(value).split(",").map((p) => p.trim()).filter((p) => /^\d{1,2}$/.test(p)).map(Number)
|
|
16446
|
+
);
|
|
16447
|
+
return card.options.filter((_, i) => places.has(i));
|
|
16448
|
+
}
|
|
16449
|
+
function typedMessage(click, text8, id) {
|
|
16450
|
+
const { action } = click;
|
|
16451
|
+
return {
|
|
16452
|
+
type: "message",
|
|
16453
|
+
id,
|
|
16454
|
+
sender: click.sender,
|
|
16455
|
+
conversation: action.conversation,
|
|
16456
|
+
locale: action.locale,
|
|
16457
|
+
clientPlatform: action.clientPlatform,
|
|
16458
|
+
text: text8,
|
|
16459
|
+
mentioned: action.conversation.kind !== "personal",
|
|
16460
|
+
targeted: false,
|
|
16461
|
+
namesBotFirst: false,
|
|
16462
|
+
conversationName: "",
|
|
16463
|
+
mentions: [],
|
|
16464
|
+
links: [],
|
|
16465
|
+
quotes: [],
|
|
16466
|
+
files: [],
|
|
16467
|
+
unreadableFiles: [],
|
|
16468
|
+
provenance: "typed",
|
|
16469
|
+
choice: true
|
|
16470
|
+
// (an option that is a menu word or a help phrase is an answer, never that command)
|
|
16471
|
+
};
|
|
16472
|
+
}
|
|
16473
|
+
function langOf3(card, click) {
|
|
16474
|
+
if (card?.lang === "zh" || card?.lang === "en") return card.lang;
|
|
16475
|
+
return click.lang();
|
|
16476
|
+
}
|
|
16477
|
+
var AssistantChoiceClicks = class {
|
|
16478
|
+
constructor(deps) {
|
|
16479
|
+
this.deps = deps;
|
|
16480
|
+
}
|
|
16481
|
+
deps;
|
|
16482
|
+
verbs = [CHOICE_VERB];
|
|
16483
|
+
/** A 1:1 chat: answered with no Claw key (the message it sends is checked as any typed one is). */
|
|
16484
|
+
async beforeCredential(click) {
|
|
16485
|
+
await this.press(click);
|
|
16486
|
+
return true;
|
|
16487
|
+
}
|
|
16488
|
+
async inGroup(click) {
|
|
16489
|
+
await this.press(click);
|
|
16490
|
+
return true;
|
|
16491
|
+
}
|
|
16492
|
+
async press(click) {
|
|
16493
|
+
const buttons2 = this.deps.store.assistantButtons;
|
|
16494
|
+
const card = buttons2.getChoiceCard(pyStr(click.action.data["card"]));
|
|
16495
|
+
const lang = langOf3(card, click);
|
|
16496
|
+
const t4 = assistantCardText.in(lang);
|
|
16497
|
+
if (card === null || click.conversation.ref.kind === "personal" && card.userId !== click.sender.id) {
|
|
16498
|
+
await finish(click, t4.choiceGone);
|
|
16499
|
+
return;
|
|
16500
|
+
}
|
|
16501
|
+
if (card.state === "done") {
|
|
16502
|
+
await this.sent(click, card, card.chosen, lang, false);
|
|
16503
|
+
return;
|
|
16504
|
+
}
|
|
16505
|
+
if (card.state !== "open") {
|
|
16506
|
+
await click.settle(t4.choiceSending({ answer: card.chosen.join(t4.choiceJoin) }), { announce: false });
|
|
16507
|
+
return;
|
|
16508
|
+
}
|
|
16509
|
+
const chosen = pickedOn(card, click.action.data[CHOICE_INPUT]);
|
|
16510
|
+
if (!chosen.length || !card.multiple && chosen.length > 1) {
|
|
16511
|
+
await this.again(click, card, lang, t4.choiceNone);
|
|
16512
|
+
return;
|
|
16513
|
+
}
|
|
16514
|
+
if (!buttons2.claimChoiceCard(card.cardId, chosen)) {
|
|
16515
|
+
const now = buttons2.getChoiceCard(card.cardId) ?? card;
|
|
16516
|
+
if (now.state === "done") await this.sent(click, now, now.chosen, lang, false);
|
|
16517
|
+
else await click.settle(t4.choiceSending({ answer: now.chosen.join(t4.choiceJoin) }), { announce: false });
|
|
16518
|
+
return;
|
|
16519
|
+
}
|
|
16520
|
+
const text8 = chosen.join(t4.choiceJoin);
|
|
16521
|
+
try {
|
|
16522
|
+
await this.deps.deliver(typedMessage(click, text8, `${CHOICE_VERB}:${card.cardId}`));
|
|
16523
|
+
} catch (error) {
|
|
16524
|
+
buttons2.moveChoiceCard(card.cardId, "open", { onlyFrom: "busy" });
|
|
16525
|
+
this.deps.logger.warn("a choice could not be sent; its card is given back", { error: errorName(error) });
|
|
16526
|
+
await this.again(click, card, lang, t4.choiceFailed);
|
|
16527
|
+
return;
|
|
16528
|
+
}
|
|
16529
|
+
buttons2.moveChoiceCard(card.cardId, "done", { onlyFrom: "busy" });
|
|
16530
|
+
await this.sent(click, card, chosen, lang, true);
|
|
16531
|
+
}
|
|
16532
|
+
/** The card back, open, with `note` under its options. */
|
|
16533
|
+
async again(click, card, lang, note) {
|
|
16534
|
+
const model = { ...this.model(card, lang), note };
|
|
16535
|
+
await click.settle(viewMessage2({ name: "choiceCard", model }), { announce: false });
|
|
16536
|
+
}
|
|
16537
|
+
/** The card replaced by what was picked and sent (said as a line too when `announce`). */
|
|
16538
|
+
async sent(click, card, chosen, lang, announce) {
|
|
16539
|
+
const t4 = assistantCardText.in(lang);
|
|
16540
|
+
const view7 = viewMessage2({ name: "choiceChosen", model: { text: card.text, chosen, lang } });
|
|
16541
|
+
await click.settle(
|
|
16542
|
+
view7,
|
|
16543
|
+
announce ? { fallback: t4.choiceSent({ answer: chosen.join(t4.choiceJoin) }) } : { announce: false }
|
|
16544
|
+
);
|
|
16545
|
+
}
|
|
16546
|
+
model(card, lang) {
|
|
16547
|
+
return { text: card.text, cardId: card.cardId, options: card.options, multiple: card.multiple, note: "", lang };
|
|
16548
|
+
}
|
|
16549
|
+
};
|
|
16550
|
+
|
|
16137
16551
|
// packages/core/src/assistant/auto-reply.ts
|
|
16138
16552
|
function answersUnasked(watch) {
|
|
16139
16553
|
return watch["state"] === "active" && watch["reply_allowed"] === true;
|
|
@@ -17142,6 +17556,24 @@ function suggestedRepliesOf(event, text8, styleOn, lang) {
|
|
|
17142
17556
|
if (replies.length) return replies.slice(0, SUGGESTIONS_MAX);
|
|
17143
17557
|
return [...ASSISTANT_SUGGESTED_REPLIES[lang ?? pickLang2(text8)]];
|
|
17144
17558
|
}
|
|
17559
|
+
var CHOICE_OPTIONS_MIN = 2;
|
|
17560
|
+
var CHOICE_OPTIONS_MAX = 10;
|
|
17561
|
+
var CHOICE_OPTION_MAX = 80;
|
|
17562
|
+
function choiceOf(event) {
|
|
17563
|
+
const choice = record2(event["choices"]);
|
|
17564
|
+
if (event["type"] !== "assistant.say" || choice === void 0) return void 0;
|
|
17565
|
+
const raw = choice["options"];
|
|
17566
|
+
if (!Array.isArray(raw)) return void 0;
|
|
17567
|
+
const options = [];
|
|
17568
|
+
for (const entry of raw) {
|
|
17569
|
+
if (typeof entry !== "string" || /[\u0000-\u001f\u007f\u2028\u2029]/u.test(entry)) return void 0;
|
|
17570
|
+
const option = pySplit(entry).join(" ");
|
|
17571
|
+
if (!option || cpLength(option) > CHOICE_OPTION_MAX) return void 0;
|
|
17572
|
+
if (!options.includes(option)) options.push(option);
|
|
17573
|
+
}
|
|
17574
|
+
if (options.length < CHOICE_OPTIONS_MIN || options.length > CHOICE_OPTIONS_MAX) return void 0;
|
|
17575
|
+
return { options, multiple: choice["multiple"] === true };
|
|
17576
|
+
}
|
|
17145
17577
|
var REMOTE_KINDS = /* @__PURE__ */ new Set(["done", "needs_you", "error", "resolved"]);
|
|
17146
17578
|
function resolvedOf(remote) {
|
|
17147
17579
|
const resolved = record2(remote["resolved"]);
|
|
@@ -17278,14 +17710,19 @@ ${text8}`;
|
|
|
17278
17710
|
return all.length ? [...said2.slice(0, -1), { ...last, suggestions: toReplies(all.slice(0, SUGGESTIONS_MAX)) }] : said2;
|
|
17279
17711
|
}
|
|
17280
17712
|
/**
|
|
17281
|
-
* The card with buttons the event asks for, recorded first: a result that waits, a write Claw holds, or a
|
|
17282
|
-
* person; undefined for none. `holdsWords`: the card shows the words, which are then not said apart.
|
|
17713
|
+
* The card with buttons the event asks for, recorded first: a result that waits, a write Claw holds, a command or a choice put
|
|
17714
|
+
* to the person; undefined for none. `holdsWords`: the card shows the words, which are then not said apart.
|
|
17283
17715
|
*/
|
|
17284
17716
|
card(userId, event, item, said2) {
|
|
17285
17717
|
const inCard = said2.inCard ? said2.text : "";
|
|
17286
17718
|
if (item?.canAccept)
|
|
17287
17719
|
return { message: this.workCard(userId, item, said2.text, inCard, said2.lang), holdsWords: said2.inCard };
|
|
17288
|
-
|
|
17720
|
+
const asked3 = item === null ? this.askCard(userId, event, inCard, said2.lang) : void 0;
|
|
17721
|
+
if (asked3 !== void 0) return { message: asked3, holdsWords: said2.inCard };
|
|
17722
|
+
return this.choiceCard(userId, event, inCard, said2.lang, said2.inCard);
|
|
17723
|
+
}
|
|
17724
|
+
/** A write Claw holds for the person (Allow, Deny) or a command put to them (Run, Cancel), recorded first; undefined for none. */
|
|
17725
|
+
askCard(userId, event, inCard, lang) {
|
|
17289
17726
|
const held = confirmWriteOf(event);
|
|
17290
17727
|
if (held !== void 0) {
|
|
17291
17728
|
const cardId2 = this.deps.store.assistantButtons.addConfirmCard(
|
|
@@ -17294,8 +17731,8 @@ ${text8}`;
|
|
|
17294
17731
|
held.kind,
|
|
17295
17732
|
held.allowLabel
|
|
17296
17733
|
);
|
|
17297
|
-
const model = { text: inCard || held.allowLabel, cardId: cardId2, allowLabel: held.allowLabel, lang
|
|
17298
|
-
return
|
|
17734
|
+
const model = { text: inCard || held.allowLabel, cardId: cardId2, allowLabel: held.allowLabel, lang };
|
|
17735
|
+
return view3({ name: "confirmWrite", model });
|
|
17299
17736
|
}
|
|
17300
17737
|
const confirm = confirmActionOf(event, this.deps.exactCommand);
|
|
17301
17738
|
if (confirm === void 0) return void 0;
|
|
@@ -17306,10 +17743,19 @@ ${text8}`;
|
|
|
17306
17743
|
confirm.name,
|
|
17307
17744
|
confirm.args
|
|
17308
17745
|
);
|
|
17309
|
-
return {
|
|
17310
|
-
|
|
17311
|
-
|
|
17312
|
-
|
|
17746
|
+
return view3({ name: "actionCard", model: { text: inCard || command, cardId, command, lang } });
|
|
17747
|
+
}
|
|
17748
|
+
/**
|
|
17749
|
+
* A choice put to the person (`choices`): its options and Send, recorded first (what a press sends is read from the record).
|
|
17750
|
+
* Its Send sends what was picked as the person's own message.
|
|
17751
|
+
*/
|
|
17752
|
+
choiceCard(userId, event, inCard, lang, holdsWords) {
|
|
17753
|
+
const choice = choiceOf(event);
|
|
17754
|
+
if (choice === void 0) return void 0;
|
|
17755
|
+
const { options, multiple } = choice;
|
|
17756
|
+
const cardId = this.deps.store.assistantButtons.addChoiceCard(userId, { text: inCard, options, multiple, lang });
|
|
17757
|
+
const model = { text: inCard, cardId, options, multiple, note: "", lang };
|
|
17758
|
+
return { message: view3({ name: "choiceCard", model }, inCard), holdsWords };
|
|
17313
17759
|
}
|
|
17314
17760
|
/** What was said, as AI answers with thumbs, each with the citations its own words cite (when the whole text cites at all). */
|
|
17315
17761
|
said(event, text8, parts2) {
|
|
@@ -19311,7 +19757,11 @@ var terminalApprovalText = defineCatalog({
|
|
|
19311
19757
|
newText: "With:",
|
|
19312
19758
|
alwaysOption: (p) => `"Always allow (this session)" means: ${p.name}`,
|
|
19313
19759
|
firstAnswerWins: "The terminal is asking too: the first answer, here or there, counts.",
|
|
19760
|
+
afterCard: "The terminal asks only after this card is answered or its wait is over: decline it here, or hand it back to the terminal and approve it there.",
|
|
19761
|
+
onInput: "To answer at the terminal instead, type anything there: the question goes back to it and this card is withdrawn.",
|
|
19314
19762
|
tooLong: "Too long to show in full here: it can only be turned down from the phone; approve it at the terminal.",
|
|
19763
|
+
tooLongAfterCard: "Too long to show in full here: it can only be declined from the phone; the terminal asks once this card's wait is over.",
|
|
19764
|
+
tooLongOnInput: "Too long to show in full here: it can only be turned down from the phone; to approve it, type anything at the terminal and answer it there.",
|
|
19315
19765
|
questionOf: (p) => `Question ${String(p.n)} of ${String(p.of)}`,
|
|
19316
19766
|
optionYes: "Yes",
|
|
19317
19767
|
optionSession: "Always allow (this session)",
|
|
@@ -19319,6 +19769,7 @@ var terminalApprovalText = defineCatalog({
|
|
|
19319
19769
|
optionNoStop: "No, and stop",
|
|
19320
19770
|
optionPlanApprove: "Approve (ask before edits)",
|
|
19321
19771
|
optionPlanKeep: "Keep planning",
|
|
19772
|
+
optionToTerminal: "Ask me at the terminal",
|
|
19322
19773
|
answeredInTerminal: "Answered in the terminal",
|
|
19323
19774
|
noLongerWaiting: "No longer waiting for an answer",
|
|
19324
19775
|
answeredInTerminalLine: "This request was answered in the terminal.",
|
|
@@ -19342,7 +19793,11 @@ var terminalApprovalText = defineCatalog({
|
|
|
19342
19793
|
newText: "\u6539\u4E3A\uFF1A",
|
|
19343
19794
|
alwaysOption: (p) => `\u201C\u672C\u4F1A\u8BDD\u59CB\u7EC8\u5141\u8BB8\u201D\u5373\uFF1A${p.name}`,
|
|
19344
19795
|
firstAnswerWins: "\u7EC8\u7AEF\u91CC\u4E5F\u5728\u7B49\u4F60\u56DE\u7B54\uFF0C\u5148\u7B54\u7684\u7B97\u6570\u3002",
|
|
19796
|
+
afterCard: "\u7EC8\u7AEF\u8981\u7B49\u8FD9\u5F20\u5361\u7247\u7B54\u5B8C\u6216\u7B49\u5F85\u65F6\u95F4\u5230\u4E86\u624D\u4F1A\u95EE\uFF1A\u5728\u8FD9\u91CC\u62D2\u7EDD\uFF0C\u6216\u4EA4\u56DE\u7EC8\u7AEF\u3001\u5230\u7EC8\u7AEF\u91CC\u6279\u51C6\u3002",
|
|
19797
|
+
onInput: "\u60F3\u6539\u5728\u7EC8\u7AEF\u91CC\u56DE\u7B54\uFF0C\u5C31\u5728\u7EC8\u7AEF\u91CC\u968F\u4FBF\u8F93\u5165\u70B9\u4EC0\u4E48\uFF1A\u95EE\u9898\u56DE\u5230\u7EC8\u7AEF\uFF0C\u8FD9\u5F20\u5361\u7247\u968F\u4E4B\u64A4\u56DE\u3002",
|
|
19345
19798
|
tooLong: "\u5185\u5BB9\u8FC7\u957F\uFF0C\u8FD9\u91CC\u663E\u793A\u4E0D\u5168\uFF1A\u624B\u673A\u4E0A\u53EA\u80FD\u62D2\u7EDD\uFF0C\u8BF7\u5230\u7EC8\u7AEF\u6279\u51C6\u3002",
|
|
19799
|
+
tooLongAfterCard: "\u5185\u5BB9\u8FC7\u957F\uFF0C\u8FD9\u91CC\u663E\u793A\u4E0D\u5168\uFF1A\u624B\u673A\u4E0A\u53EA\u80FD\u62D2\u7EDD\uFF1B\u8FD9\u5F20\u5361\u7247\u7684\u7B49\u5F85\u65F6\u95F4\u4E00\u8FC7\uFF0C\u7EC8\u7AEF\u5C31\u4F1A\u95EE\u4F60\u3002",
|
|
19800
|
+
tooLongOnInput: "\u5185\u5BB9\u8FC7\u957F\uFF0C\u8FD9\u91CC\u663E\u793A\u4E0D\u5168\uFF1A\u624B\u673A\u4E0A\u53EA\u80FD\u62D2\u7EDD\uFF1B\u8981\u6279\u51C6\uFF0C\u5728\u7EC8\u7AEF\u91CC\u968F\u4FBF\u8F93\u5165\u70B9\u4EC0\u4E48\uFF0C\u5230\u7EC8\u7AEF\u91CC\u56DE\u7B54\u3002",
|
|
19346
19801
|
questionOf: (p) => `\u7B2C ${String(p.n)} \u9898\uFF0C\u5171 ${String(p.of)} \u9898`,
|
|
19347
19802
|
optionYes: "\u5141\u8BB8",
|
|
19348
19803
|
optionSession: "\u672C\u4F1A\u8BDD\u59CB\u7EC8\u5141\u8BB8",
|
|
@@ -19350,6 +19805,7 @@ var terminalApprovalText = defineCatalog({
|
|
|
19350
19805
|
optionNoStop: "\u62D2\u7EDD\u5E76\u505C\u6B62",
|
|
19351
19806
|
optionPlanApprove: "\u6279\u51C6\uFF08\u7F16\u8F91\u524D\u9010\u4E2A\u8BE2\u95EE\uFF09",
|
|
19352
19807
|
optionPlanKeep: "\u7EE7\u7EED\u89C4\u5212",
|
|
19808
|
+
optionToTerminal: "\u4EA4\u56DE\u7EC8\u7AEF",
|
|
19353
19809
|
answeredInTerminal: "\u5DF2\u5728\u7EC8\u7AEF\u91CC\u56DE\u7B54",
|
|
19354
19810
|
noLongerWaiting: "\u4E0D\u518D\u7B49\u5F85\u56DE\u7B54",
|
|
19355
19811
|
answeredInTerminalLine: "\u8FD9\u4E2A\u8BF7\u6C42\u5DF2\u5728\u7EC8\u7AEF\u91CC\u56DE\u7B54\u3002",
|
|
@@ -19481,6 +19937,9 @@ var TERMINAL_FALLBACK_BYTES = 4e3;
|
|
|
19481
19937
|
var LINE_MAX = 400;
|
|
19482
19938
|
var LABEL_MAX2 = 200;
|
|
19483
19939
|
var OPTION_NAME_MAX = 200;
|
|
19940
|
+
function terminalAsksOf(ask3) {
|
|
19941
|
+
return TERMINAL_ASKS.find((t4) => t4 === ask3["terminal_asks"]);
|
|
19942
|
+
}
|
|
19484
19943
|
function isTerminalAsk(ask3) {
|
|
19485
19944
|
return ask3 !== void 0 && ask3["origin"] === "terminal";
|
|
19486
19945
|
}
|
|
@@ -19503,7 +19962,8 @@ function optionTitle(option, lang) {
|
|
|
19503
19962
|
["deny", words3.optionNo],
|
|
19504
19963
|
["deny-stop", words3.optionNoStop],
|
|
19505
19964
|
["plan-approve", words3.optionPlanApprove],
|
|
19506
|
-
["plan-keep", words3.optionPlanKeep]
|
|
19965
|
+
["plan-keep", words3.optionPlanKeep],
|
|
19966
|
+
["terminal", words3.optionToTerminal]
|
|
19507
19967
|
]);
|
|
19508
19968
|
return titles.get(option.optionId);
|
|
19509
19969
|
}
|
|
@@ -19622,10 +20082,15 @@ function notesOf(ask3, complete, options, words3) {
|
|
|
19622
20082
|
const index = Number(ask3["question_index"]);
|
|
19623
20083
|
if (Number.isInteger(total) && total > 1 && Number.isInteger(index))
|
|
19624
20084
|
notes.push(words3.questionOf({ n: index + 1, of: total }));
|
|
19625
|
-
|
|
20085
|
+
const asks = terminalAsksOf(ask3);
|
|
20086
|
+
if (!complete)
|
|
20087
|
+
notes.push(
|
|
20088
|
+
asks === "after_card" ? words3.tooLongAfterCard : asks === "on_input" ? words3.tooLongOnInput : words3.tooLong
|
|
20089
|
+
);
|
|
19626
20090
|
for (const o of shownOptions(options))
|
|
19627
20091
|
if (o.kind === "allow_always") notes.push(words3.alwaysOption({ name: lit(o.name, OPTION_NAME_MAX) }));
|
|
19628
|
-
notes.push(words3.firstAnswerWins);
|
|
20092
|
+
if (asks === void 0) notes.push(words3.firstAnswerWins);
|
|
20093
|
+
else if (complete) notes.push(asks === "after_card" ? words3.afterCard : words3.onInput);
|
|
19629
20094
|
return notes;
|
|
19630
20095
|
}
|
|
19631
20096
|
function terminalAskView(input, lang = "en") {
|
|
@@ -22031,9 +22496,9 @@ var SUMMARY_CHARS = 1200;
|
|
|
22031
22496
|
var DM_SUMMARY_CHARS = 700;
|
|
22032
22497
|
var VERDICT = pyRegExp(String.raw`^\s*VERDICT:\s*(CLEAN|BLOCKING|NOT_REVIEWED)\s*$`, "i");
|
|
22033
22498
|
var CJK5 = /[一-鿿]/u;
|
|
22034
|
-
var
|
|
22499
|
+
var NAMES3 = Object.keys(PLAIN_WORDS).sort((a, b3) => b3.length - a.length).map((n) => n.replace(/[.*+?^${}()|[\]\\]/gu, "\\$&")).join("|");
|
|
22035
22500
|
var RAW_NAME = new RegExp(
|
|
22036
|
-
`\`(?<![A-Za-z0-9_])(${
|
|
22501
|
+
`\`(?<![A-Za-z0-9_])(${NAMES3})(?![A-Za-z0-9_])\`|(?<![A-Za-z0-9_])(${NAMES3})(?![A-Za-z0-9_])`,
|
|
22037
22502
|
"gu"
|
|
22038
22503
|
);
|
|
22039
22504
|
function plainWords(text8) {
|
|
@@ -26142,6 +26607,7 @@ __export(remote_view_exports, {
|
|
|
26142
26607
|
statusView: () => statusView,
|
|
26143
26608
|
takeoverView: () => takeoverView,
|
|
26144
26609
|
terminalAskView: () => terminalAskView,
|
|
26610
|
+
terminalAsksOf: () => terminalAsksOf,
|
|
26145
26611
|
windowView: () => windowView
|
|
26146
26612
|
});
|
|
26147
26613
|
|
|
@@ -28257,8 +28723,8 @@ var STATUS_REFUSALS = /* @__PURE__ */ new Map([
|
|
|
28257
28723
|
[403, "keyRejected"]
|
|
28258
28724
|
]);
|
|
28259
28725
|
var ERROR_CODE = /^[a-z][a-z0-9_]{0,59}$/u;
|
|
28260
|
-
function saidIn(lang,
|
|
28261
|
-
return remoteAgentText.in(lang)[
|
|
28726
|
+
function saidIn(lang, sentence3) {
|
|
28727
|
+
return remoteAgentText.in(lang)[sentence3];
|
|
28262
28728
|
}
|
|
28263
28729
|
function failureText2(err2, errors, now, lang = "en") {
|
|
28264
28730
|
if (err2 instanceof Reconnecting) return offlineText(err2.connector, now, lang);
|
|
@@ -28497,9 +28963,9 @@ var Targets = class {
|
|
|
28497
28963
|
*/
|
|
28498
28964
|
takeoverOf(chatKey, connector, agent, data, now, lang) {
|
|
28499
28965
|
const entry = resumableOf(agent).find((e) => e.ref === textOf6(data["resume"]));
|
|
28500
|
-
const no = (
|
|
28966
|
+
const no = (sentence3) => ({
|
|
28501
28967
|
entry: null,
|
|
28502
|
-
problem: saidIn(lang,
|
|
28968
|
+
problem: saidIn(lang, sentence3)
|
|
28503
28969
|
});
|
|
28504
28970
|
if (entry === void 0) return no("conversationGone");
|
|
28505
28971
|
if (entry.state === WATCH_STATE && data["takeover"]) {
|
|
@@ -28520,9 +28986,9 @@ var Targets = class {
|
|
|
28520
28986
|
* process kept when it was typed (the card carries only a token).
|
|
28521
28987
|
*/
|
|
28522
28988
|
folderOf(chatKey, agent, data, now, lang) {
|
|
28523
|
-
const no = (
|
|
28989
|
+
const no = (sentence3) => ({
|
|
28524
28990
|
path: "",
|
|
28525
|
-
problem: saidIn(lang,
|
|
28991
|
+
problem: saidIn(lang, sentence3)
|
|
28526
28992
|
});
|
|
28527
28993
|
if ("typed" in data) {
|
|
28528
28994
|
const path = this.chats.typedPath(chatKey, textOf6(data["typed"]), now);
|
|
@@ -29333,7 +29799,7 @@ function older(version, than) {
|
|
|
29333
29799
|
function isCode(reason) {
|
|
29334
29800
|
return CODE4.test(reason);
|
|
29335
29801
|
}
|
|
29336
|
-
function
|
|
29802
|
+
function sentence2(code3, lang, setup) {
|
|
29337
29803
|
const text8 = own(connectorReasonText.in(lang), code3) ?? "";
|
|
29338
29804
|
return code3 === "revoked" ? text8.replaceAll("{login}", setup.login()) : text8;
|
|
29339
29805
|
}
|
|
@@ -29357,7 +29823,7 @@ function explain(code3, version = null, setup = new Setup("", null)) {
|
|
|
29357
29823
|
if (!KNOWN.has(code3)) return both((lang) => connectorReasonHints.in(lang).unknown({ code: code3 }));
|
|
29358
29824
|
return both((lang) => {
|
|
29359
29825
|
const after = hintAfter(code3, lang, version);
|
|
29360
|
-
const own3 =
|
|
29826
|
+
const own3 = sentence2(code3, lang, setup);
|
|
29361
29827
|
return after ? `${own3}${after.sep}${after.hint}` : own3;
|
|
29362
29828
|
});
|
|
29363
29829
|
}
|
|
@@ -32756,6 +33222,7 @@ export {
|
|
|
32756
33222
|
AssistantActionClicks,
|
|
32757
33223
|
AssistantActions,
|
|
32758
33224
|
AssistantChat as AssistantChatService,
|
|
33225
|
+
AssistantChoiceClicks,
|
|
32759
33226
|
BOARD_CARDS,
|
|
32760
33227
|
BOARD_LINES,
|
|
32761
33228
|
BOARD_RETRY_MAX,
|
|
@@ -32989,6 +33456,7 @@ export {
|
|
|
32989
33456
|
TAG,
|
|
32990
33457
|
TARGET_LINES,
|
|
32991
33458
|
TARGET_MAX,
|
|
33459
|
+
TERMINAL_ASKS,
|
|
32992
33460
|
TERMINAL_HOOK_COMMANDS,
|
|
32993
33461
|
TERMINAL_SESSION_LIMITS,
|
|
32994
33462
|
THUMB_COMMENT_MAX,
|
|
@@ -33105,8 +33573,10 @@ export {
|
|
|
33105
33573
|
githubConfirmButtons,
|
|
33106
33574
|
githubConfirmMessage,
|
|
33107
33575
|
githubConnectMessage,
|
|
33576
|
+
groupChosenLang,
|
|
33108
33577
|
groupContextLines,
|
|
33109
33578
|
groupContextText,
|
|
33579
|
+
groupLangOf,
|
|
33110
33580
|
guardrailsText,
|
|
33111
33581
|
hasCjk2 as hasCjk,
|
|
33112
33582
|
hasControl,
|