@hopgoldy/agent-bridge 0.3.1 → 0.3.4
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/README.md +2 -0
- package/dist/agent-bridge.js +203 -60
- package/dist/cli.js +203 -60
- package/dist/index.d.ts +16 -2
- package/package.json +2 -1
package/dist/cli.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
// src/cli.ts
|
|
4
4
|
import process2 from "process";
|
|
5
|
+
import { createRequire } from "module";
|
|
5
6
|
import { Command } from "commander";
|
|
6
7
|
|
|
7
8
|
// src/config/prompt.ts
|
|
@@ -106,6 +107,85 @@ import { mkdir as mkdir2, readFile as readFile2, writeFile as writeFile2 } from
|
|
|
106
107
|
import os2 from "os";
|
|
107
108
|
import path2 from "path";
|
|
108
109
|
|
|
110
|
+
// src/i18n/index.ts
|
|
111
|
+
import i18next from "i18next";
|
|
112
|
+
var DEFAULT_LOCALE = "en-US";
|
|
113
|
+
var resources = {
|
|
114
|
+
"en-US": {
|
|
115
|
+
translation: {
|
|
116
|
+
progress: {
|
|
117
|
+
noProgress: "No progress yet.",
|
|
118
|
+
collapsed: "Collapsed {{count}} earlier updates.",
|
|
119
|
+
running: "Running {{subject}}",
|
|
120
|
+
finished: "Finished {{subject}}",
|
|
121
|
+
failed: "Failed {{subject}}",
|
|
122
|
+
failedWithDetail: "Failed {{subject}}: {{detail}}",
|
|
123
|
+
compacting: "Compacting session",
|
|
124
|
+
compactingWithDetail: "Compacting session: {{detail}}"
|
|
125
|
+
},
|
|
126
|
+
client: {
|
|
127
|
+
processing: "Processing...",
|
|
128
|
+
helpMessage: "Available commands:\n\n- `/new` (`/n`) - Start a new agent session\n- `/compact` (`/c`) - Compact the current session context\n- `/stop` (`/s`) - Stop the active agent run\n- `/help` (`/h`) - Show this help message",
|
|
129
|
+
messageDeliveryFailedTitle: "[agent-bridge error] Message delivery failed",
|
|
130
|
+
weixinCooldown: "Weixin send is cooling down after rate limiting. Please try again shortly."
|
|
131
|
+
},
|
|
132
|
+
gateway: {
|
|
133
|
+
noActiveSessionToCompact: "No active agent session to compact.",
|
|
134
|
+
noActiveSessionToStop: "No active agent session to stop.",
|
|
135
|
+
sessionCannotBeStopped: "This agent session cannot be stopped right now.",
|
|
136
|
+
noActiveRunToStop: "No active agent run to stop.",
|
|
137
|
+
startedNewSession: "Started a new session."
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
},
|
|
141
|
+
"zh-CN": {
|
|
142
|
+
translation: {
|
|
143
|
+
progress: {
|
|
144
|
+
noProgress: "\u6682\u65E0\u8FDB\u5EA6\u3002",
|
|
145
|
+
collapsed: "\u5DF2\u6298\u53E0 {{count}} \u6761\u8F83\u65E9\u66F4\u65B0\u3002",
|
|
146
|
+
running: "\u6B63\u5728\u6267\u884C {{subject}}",
|
|
147
|
+
finished: "\u5DF2\u5B8C\u6210 {{subject}}",
|
|
148
|
+
failed: "{{subject}} \u6267\u884C\u5931\u8D25",
|
|
149
|
+
failedWithDetail: "{{subject}} \u6267\u884C\u5931\u8D25\uFF1A{{detail}}",
|
|
150
|
+
compacting: "\u6B63\u5728\u538B\u7F29\u4F1A\u8BDD",
|
|
151
|
+
compactingWithDetail: "\u6B63\u5728\u538B\u7F29\u4F1A\u8BDD: {{detail}}"
|
|
152
|
+
},
|
|
153
|
+
client: {
|
|
154
|
+
processing: "\u6B63\u5728\u5904\u7406\u4E2D...",
|
|
155
|
+
helpMessage: "\u53EF\u7528\u547D\u4EE4\uFF1A\n\n- `/new` (`/n`) - \u5F00\u59CB\u4E00\u4E2A\u65B0\u4F1A\u8BDD\n- `/compact` (`/c`) - \u538B\u7F29\u5F53\u524D\u4F1A\u8BDD\u4E0A\u4E0B\u6587\n- `/stop` (`/s`) - \u505C\u6B62\u5F53\u524D\u6B63\u5728\u8FD0\u884C\u7684\u4EFB\u52A1\n- `/help` (`/h`) - \u67E5\u770B\u8FD9\u6761\u5E2E\u52A9\u4FE1\u606F",
|
|
156
|
+
messageDeliveryFailedTitle: "[agent-bridge \u9519\u8BEF] \u6D88\u606F\u53D1\u9001\u5931\u8D25",
|
|
157
|
+
weixinCooldown: "\u5FAE\u4FE1\u53D1\u9001\u56E0\u9650\u6D41\u5DF2\u8FDB\u5165\u51B7\u5374\uFF0C\u8BF7\u7A0D\u540E\u518D\u8BD5\u3002"
|
|
158
|
+
},
|
|
159
|
+
gateway: {
|
|
160
|
+
noActiveSessionToCompact: "\u5F53\u524D\u6CA1\u6709\u53EF\u538B\u7F29\u7684\u667A\u80FD\u4F53\u4F1A\u8BDD\u3002",
|
|
161
|
+
noActiveSessionToStop: "\u5F53\u524D\u6CA1\u6709\u53EF\u505C\u6B62\u7684\u667A\u80FD\u4F53\u4F1A\u8BDD\u3002",
|
|
162
|
+
sessionCannotBeStopped: "\u5F53\u524D\u65E0\u6CD5\u505C\u6B62\u8FD9\u4E2A\u667A\u80FD\u4F53\u4F1A\u8BDD\u3002",
|
|
163
|
+
noActiveRunToStop: "\u5F53\u524D\u6CA1\u6709\u6B63\u5728\u8FD0\u884C\u7684\u667A\u80FD\u4F53\u4EFB\u52A1\u53EF\u505C\u6B62\u3002",
|
|
164
|
+
startedNewSession: "\u5DF2\u5F00\u59CB\u65B0\u4F1A\u8BDD\u3002"
|
|
165
|
+
}
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
var instance = i18next.createInstance();
|
|
170
|
+
void instance.init({
|
|
171
|
+
lng: DEFAULT_LOCALE,
|
|
172
|
+
fallbackLng: DEFAULT_LOCALE,
|
|
173
|
+
resources,
|
|
174
|
+
interpolation: { escapeValue: false },
|
|
175
|
+
initImmediate: false
|
|
176
|
+
});
|
|
177
|
+
function getTranslator(locale) {
|
|
178
|
+
return instance.getFixedT(locale);
|
|
179
|
+
}
|
|
180
|
+
function getTranslatorForCommon(common) {
|
|
181
|
+
return getTranslator(common?.language ?? DEFAULT_LOCALE);
|
|
182
|
+
}
|
|
183
|
+
function formatSendFailureNotice(t, detail) {
|
|
184
|
+
return `${t("client.messageDeliveryFailedTitle")}
|
|
185
|
+
|
|
186
|
+
${detail}`;
|
|
187
|
+
}
|
|
188
|
+
|
|
109
189
|
// src/config/defaults.ts
|
|
110
190
|
var DEFAULTS = {
|
|
111
191
|
agentIdleTimeoutMs: 10 * 60 * 1e3
|
|
@@ -114,11 +194,20 @@ var DEFAULTS = {
|
|
|
114
194
|
// src/config/store.ts
|
|
115
195
|
var CONFIG_DIR = path2.join(os2.homedir(), ".config", "agent-bridge");
|
|
116
196
|
var CONFIG_PATH = path2.join(CONFIG_DIR, "config.json");
|
|
197
|
+
function normalizeLanguage(language) {
|
|
198
|
+
return language === "en-US" || language === "zh-CN" ? language : DEFAULT_LOCALE;
|
|
199
|
+
}
|
|
117
200
|
function normalizeChannelConfig(channel) {
|
|
118
201
|
if (!channel.client || !channel.agent) {
|
|
119
202
|
throw new Error("Invalid channel config shape");
|
|
120
203
|
}
|
|
121
|
-
return
|
|
204
|
+
return {
|
|
205
|
+
common: {
|
|
206
|
+
language: normalizeLanguage(channel.common?.language)
|
|
207
|
+
},
|
|
208
|
+
client: channel.client,
|
|
209
|
+
agent: channel.agent
|
|
210
|
+
};
|
|
122
211
|
}
|
|
123
212
|
function mergeDefaults(config = {}) {
|
|
124
213
|
const channels = Object.fromEntries(
|
|
@@ -193,16 +282,20 @@ var GatewayCore = class {
|
|
|
193
282
|
#agentConfig;
|
|
194
283
|
#agentIdleTimeoutMs;
|
|
195
284
|
#bindingStore;
|
|
285
|
+
#common;
|
|
286
|
+
#t;
|
|
196
287
|
#logger = createLogger("core");
|
|
197
288
|
#clientToAgentSession = /* @__PURE__ */ new Map();
|
|
198
289
|
#agentRuntimes = /* @__PURE__ */ new Map();
|
|
199
290
|
#started = false;
|
|
200
|
-
constructor({ imAdapter, agentModule, agentConfig, agentIdleTimeoutMs, bindingStore }) {
|
|
291
|
+
constructor({ imAdapter, agentModule, agentConfig, agentIdleTimeoutMs, bindingStore, common }) {
|
|
201
292
|
this.#imAdapter = imAdapter;
|
|
202
293
|
this.#agentModule = agentModule;
|
|
203
294
|
this.#agentConfig = agentConfig;
|
|
204
295
|
this.#agentIdleTimeoutMs = agentIdleTimeoutMs;
|
|
205
296
|
this.#bindingStore = bindingStore;
|
|
297
|
+
this.#common = common;
|
|
298
|
+
this.#t = getTranslatorForCommon(common);
|
|
206
299
|
}
|
|
207
300
|
async start() {
|
|
208
301
|
if (this.#started) return;
|
|
@@ -258,7 +351,7 @@ var GatewayCore = class {
|
|
|
258
351
|
await this.#deliverClientInput({
|
|
259
352
|
type: "assistant.message",
|
|
260
353
|
clientSessionId,
|
|
261
|
-
text: "
|
|
354
|
+
text: this.#t("gateway.noActiveSessionToCompact")
|
|
262
355
|
});
|
|
263
356
|
return;
|
|
264
357
|
}
|
|
@@ -273,7 +366,7 @@ var GatewayCore = class {
|
|
|
273
366
|
await this.#deliverClientInput({
|
|
274
367
|
type: "assistant.message",
|
|
275
368
|
clientSessionId,
|
|
276
|
-
text: "
|
|
369
|
+
text: this.#t("gateway.noActiveSessionToStop")
|
|
277
370
|
});
|
|
278
371
|
return;
|
|
279
372
|
}
|
|
@@ -282,7 +375,7 @@ var GatewayCore = class {
|
|
|
282
375
|
await this.#deliverClientInput({
|
|
283
376
|
type: "assistant.message",
|
|
284
377
|
clientSessionId,
|
|
285
|
-
text: "
|
|
378
|
+
text: this.#t("gateway.sessionCannotBeStopped")
|
|
286
379
|
});
|
|
287
380
|
return;
|
|
288
381
|
}
|
|
@@ -290,7 +383,7 @@ var GatewayCore = class {
|
|
|
290
383
|
await this.#deliverClientInput({
|
|
291
384
|
type: "assistant.message",
|
|
292
385
|
clientSessionId,
|
|
293
|
-
text: "
|
|
386
|
+
text: this.#t("gateway.noActiveRunToStop")
|
|
294
387
|
});
|
|
295
388
|
return;
|
|
296
389
|
}
|
|
@@ -309,7 +402,7 @@ var GatewayCore = class {
|
|
|
309
402
|
await this.#deliverClientInput({
|
|
310
403
|
type: "assistant.message",
|
|
311
404
|
clientSessionId,
|
|
312
|
-
text: "
|
|
405
|
+
text: this.#t("gateway.startedNewSession")
|
|
313
406
|
});
|
|
314
407
|
}
|
|
315
408
|
async #deliverClientInput(event) {
|
|
@@ -344,6 +437,7 @@ var GatewayCore = class {
|
|
|
344
437
|
if (this.#agentModule.resumeAgentSession) {
|
|
345
438
|
const agentAdapter = await this.#agentModule.resumeAgentSession({
|
|
346
439
|
config: this.#agentConfig,
|
|
440
|
+
common: this.#common ?? { channelName: "", language: "en-US" },
|
|
347
441
|
agentSessionId
|
|
348
442
|
});
|
|
349
443
|
return this.#startRuntime(clientSessionId, agentSessionId, agentAdapter);
|
|
@@ -354,7 +448,8 @@ var GatewayCore = class {
|
|
|
354
448
|
}
|
|
355
449
|
async #createRuntimeForClient(clientSessionId) {
|
|
356
450
|
const { agentSessionId, agentAdapter } = await this.#agentModule.createAgentSession({
|
|
357
|
-
config: this.#agentConfig
|
|
451
|
+
config: this.#agentConfig,
|
|
452
|
+
common: this.#common ?? { channelName: "", language: "en-US" }
|
|
358
453
|
});
|
|
359
454
|
return this.#startRuntime(clientSessionId, agentSessionId, agentAdapter);
|
|
360
455
|
}
|
|
@@ -1127,7 +1222,7 @@ var PiCodingAgentAdapter = class {
|
|
|
1127
1222
|
toolInput,
|
|
1128
1223
|
toolLabel,
|
|
1129
1224
|
result: "result" in rpcEvent ? rpcEvent.result : void 0,
|
|
1130
|
-
text: isError ?
|
|
1225
|
+
text: isError ? void 0 : `Finished ${toolName}`
|
|
1131
1226
|
});
|
|
1132
1227
|
if (toolCallId) {
|
|
1133
1228
|
this.#toolLabelByCallId.delete(toolCallId);
|
|
@@ -1292,16 +1387,16 @@ function createPiCodingAgentConfigCollector() {
|
|
|
1292
1387
|
var piCodingAgentModule = {
|
|
1293
1388
|
type: "pi-coding-agent",
|
|
1294
1389
|
createConfigCollector: createPiCodingAgentConfigCollector,
|
|
1295
|
-
async createAgentSession({ config }) {
|
|
1390
|
+
async createAgentSession({ config, common }) {
|
|
1296
1391
|
const agentSessionId = `pi-coding-agent:${randomUUID()}`;
|
|
1297
|
-
logger.info(`creating agent session ${agentSessionId}`);
|
|
1392
|
+
logger.info(`creating agent session ${agentSessionId} for channel ${common.channelName}`);
|
|
1298
1393
|
return {
|
|
1299
1394
|
agentSessionId,
|
|
1300
1395
|
agentAdapter: buildAdapter(config, agentSessionId)
|
|
1301
1396
|
};
|
|
1302
1397
|
},
|
|
1303
|
-
async resumeAgentSession({ config, agentSessionId }) {
|
|
1304
|
-
logger.info(`resuming agent session ${agentSessionId}`);
|
|
1398
|
+
async resumeAgentSession({ config, common, agentSessionId }) {
|
|
1399
|
+
logger.info(`resuming agent session ${agentSessionId} for channel ${common.channelName}`);
|
|
1305
1400
|
return buildAdapter(config, agentSessionId);
|
|
1306
1401
|
}
|
|
1307
1402
|
};
|
|
@@ -1325,14 +1420,15 @@ function getTypedAgentModule(config) {
|
|
|
1325
1420
|
// src/modules/client/utils/progress-renderer.ts
|
|
1326
1421
|
var DEFAULT_COLLAPSE_THRESHOLD = 10;
|
|
1327
1422
|
var MAX_TOOL_LABEL_DISPLAY_LENGTH = 15;
|
|
1328
|
-
var NO_PROGRESS_MARKDOWN = "No progress yet.";
|
|
1329
1423
|
var ProgressRenderer = class {
|
|
1330
1424
|
#collapseThreshold;
|
|
1425
|
+
#t;
|
|
1331
1426
|
#entries = /* @__PURE__ */ new Map();
|
|
1332
1427
|
#order = [];
|
|
1333
1428
|
#status = "running";
|
|
1334
1429
|
constructor(options = {}) {
|
|
1335
1430
|
this.#collapseThreshold = options.collapseThreshold ?? DEFAULT_COLLAPSE_THRESHOLD;
|
|
1431
|
+
this.#t = options.t ?? getTranslator("en-US");
|
|
1336
1432
|
}
|
|
1337
1433
|
/** Whether `event` should be recorded as progress (excludes assistant messages and thinking). */
|
|
1338
1434
|
isProgressEvent(event) {
|
|
@@ -1354,20 +1450,21 @@ var ProgressRenderer = class {
|
|
|
1354
1450
|
return {
|
|
1355
1451
|
markdown: this.#renderMarkdown(collapsedCount),
|
|
1356
1452
|
status: this.#status,
|
|
1357
|
-
collapsedCount
|
|
1453
|
+
collapsedCount,
|
|
1454
|
+
isEmpty: this.#order.length === 0
|
|
1358
1455
|
};
|
|
1359
1456
|
}
|
|
1360
1457
|
#renderMarkdown(collapsedCount) {
|
|
1361
1458
|
const contentLines = [];
|
|
1362
1459
|
if (collapsedCount > 0) {
|
|
1363
|
-
contentLines.push(`-
|
|
1460
|
+
contentLines.push(`- ${this.#t("progress.collapsed", { count: collapsedCount })}`);
|
|
1364
1461
|
}
|
|
1365
1462
|
for (const id of this.#visibleOrder()) {
|
|
1366
1463
|
const entry = this.#entries.get(id);
|
|
1367
1464
|
if (!entry) continue;
|
|
1368
1465
|
contentLines.push(entry.kind === "line" ? entry.line : this.#formatToolEntry(entry));
|
|
1369
1466
|
}
|
|
1370
|
-
return contentLines.length > 0 ? contentLines.join("\n") :
|
|
1467
|
+
return contentLines.length > 0 ? contentLines.join("\n") : this.#t("progress.noProgress");
|
|
1371
1468
|
}
|
|
1372
1469
|
#visibleOrder() {
|
|
1373
1470
|
return this.#order.slice(-this.#collapseThreshold);
|
|
@@ -1399,9 +1496,9 @@ var ProgressRenderer = class {
|
|
|
1399
1496
|
const subject = this.#formatToolSubject(entry.toolName, entry.toolLabel);
|
|
1400
1497
|
switch (entry.status) {
|
|
1401
1498
|
case "running":
|
|
1402
|
-
return `-
|
|
1499
|
+
return `- ${this.#t("progress.running", { subject })}`;
|
|
1403
1500
|
case "done":
|
|
1404
|
-
return `-
|
|
1501
|
+
return `- ${this.#t("progress.finished", { subject })}`;
|
|
1405
1502
|
case "error":
|
|
1406
1503
|
return this.#formatToolErrorLine(subject, entry.text);
|
|
1407
1504
|
}
|
|
@@ -1409,12 +1506,12 @@ var ProgressRenderer = class {
|
|
|
1409
1506
|
#formatProgressLine(event) {
|
|
1410
1507
|
switch (event.type) {
|
|
1411
1508
|
case "session.compacting":
|
|
1412
|
-
return `-
|
|
1509
|
+
return `- ${event.text ? this.#t("progress.compactingWithDetail", { detail: event.text }) : this.#t("progress.compacting")}`;
|
|
1413
1510
|
case "assistant.tool.running":
|
|
1414
1511
|
case "assistant.tool.update":
|
|
1415
|
-
return `-
|
|
1512
|
+
return `- ${this.#t("progress.running", { subject: this.#formatToolSubject(event.toolName, event.toolLabel) })}`;
|
|
1416
1513
|
case "assistant.tool.done":
|
|
1417
|
-
return `-
|
|
1514
|
+
return `- ${this.#t("progress.finished", { subject: this.#formatToolSubject(event.toolName, event.toolLabel) })}`;
|
|
1418
1515
|
case "assistant.tool.error":
|
|
1419
1516
|
return this.#formatToolErrorLine(this.#formatToolSubject(event.toolName, event.toolLabel), event.text);
|
|
1420
1517
|
}
|
|
@@ -1436,13 +1533,13 @@ var ProgressRenderer = class {
|
|
|
1436
1533
|
}
|
|
1437
1534
|
const lowerText = normalizedText.toLowerCase();
|
|
1438
1535
|
const lowerToolName = toolName.toLowerCase();
|
|
1439
|
-
if (lowerText === lowerToolName || lowerText ===
|
|
1536
|
+
if (lowerText === lowerToolName || lowerText === this.#t("progress.failed", { subject: toolName }).toLowerCase() || lowerText === this.#t("progress.running", { subject: toolName }).toLowerCase() || lowerText === this.#t("progress.finished", { subject: toolName }).toLowerCase()) {
|
|
1440
1537
|
return `- ${this.#humanizeToolError(toolName)}`;
|
|
1441
1538
|
}
|
|
1442
|
-
return `- ${this.#
|
|
1539
|
+
return `- ${this.#t("progress.failedWithDetail", { subject: toolName, detail: normalizedText })}`;
|
|
1443
1540
|
}
|
|
1444
1541
|
#humanizeToolError(toolName) {
|
|
1445
|
-
return
|
|
1542
|
+
return this.#t("progress.failed", { subject: toolName });
|
|
1446
1543
|
}
|
|
1447
1544
|
#progressStatus(event) {
|
|
1448
1545
|
switch (event.type) {
|
|
@@ -1457,6 +1554,18 @@ var ProgressRenderer = class {
|
|
|
1457
1554
|
};
|
|
1458
1555
|
|
|
1459
1556
|
// src/modules/client/utils/slash-commands.ts
|
|
1557
|
+
function isHelpCommand(text2) {
|
|
1558
|
+
switch (text2.toLowerCase()) {
|
|
1559
|
+
case "/help":
|
|
1560
|
+
case "/h":
|
|
1561
|
+
return true;
|
|
1562
|
+
default:
|
|
1563
|
+
return false;
|
|
1564
|
+
}
|
|
1565
|
+
}
|
|
1566
|
+
function resolveHelpMarkdown(text2, t) {
|
|
1567
|
+
return isHelpCommand(text2) ? t("client.helpMessage") : null;
|
|
1568
|
+
}
|
|
1460
1569
|
function parseSlashCommand(text2, clientSessionId) {
|
|
1461
1570
|
switch (text2.toLowerCase()) {
|
|
1462
1571
|
case "/new":
|
|
@@ -1466,6 +1575,7 @@ function parseSlashCommand(text2, clientSessionId) {
|
|
|
1466
1575
|
case "/c":
|
|
1467
1576
|
return { type: "command.session.compact", clientSessionId };
|
|
1468
1577
|
case "/stop":
|
|
1578
|
+
case "/s":
|
|
1469
1579
|
return { type: "command.session.stop", clientSessionId };
|
|
1470
1580
|
default:
|
|
1471
1581
|
return null;
|
|
@@ -1818,6 +1928,7 @@ function chunkText(text2, maxLen) {
|
|
|
1818
1928
|
var FeishuIMAdapter = class _FeishuIMAdapter {
|
|
1819
1929
|
#config;
|
|
1820
1930
|
#logger;
|
|
1931
|
+
#t;
|
|
1821
1932
|
#onOutput = null;
|
|
1822
1933
|
#client = null;
|
|
1823
1934
|
#egressQueue = [];
|
|
@@ -1842,18 +1953,17 @@ var FeishuIMAdapter = class _FeishuIMAdapter {
|
|
|
1842
1953
|
return;
|
|
1843
1954
|
}
|
|
1844
1955
|
const message = error instanceof Error ? error.message : String(error);
|
|
1845
|
-
const text2 =
|
|
1846
|
-
|
|
1847
|
-
${message}`;
|
|
1956
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
1848
1957
|
try {
|
|
1849
1958
|
await this.#client.sendText(chatId, text2);
|
|
1850
1959
|
} catch (notifyError) {
|
|
1851
1960
|
this.#logger.error("failed to notify send failure:", notifyError);
|
|
1852
1961
|
}
|
|
1853
1962
|
}
|
|
1854
|
-
constructor(config, logger3 = createLogger("feishu")) {
|
|
1963
|
+
constructor(config, logger3 = createLogger("feishu"), common) {
|
|
1855
1964
|
this.#config = config;
|
|
1856
1965
|
this.#logger = logger3;
|
|
1966
|
+
this.#t = getTranslatorForCommon(common);
|
|
1857
1967
|
}
|
|
1858
1968
|
async start(onOutput) {
|
|
1859
1969
|
this.#onOutput = onOutput;
|
|
@@ -1870,16 +1980,22 @@ ${message}`;
|
|
|
1870
1980
|
);
|
|
1871
1981
|
return;
|
|
1872
1982
|
}
|
|
1873
|
-
this.#lastInboundMessageIdBySession.set(clientSessionId, messageId);
|
|
1874
|
-
this.#resetProgressState(clientSessionId);
|
|
1875
|
-
await this.#client?.startTyping(chatId, messageId);
|
|
1876
1983
|
const normalizedText = text2.trim();
|
|
1984
|
+
const helpMarkdown = resolveHelpMarkdown(normalizedText, this.#t);
|
|
1985
|
+
if (helpMarkdown) {
|
|
1986
|
+
this.#logger.info(`received local help command ${normalizedText} (session=${clientSessionId})`);
|
|
1987
|
+
await this.#client?.sendText(chatId, helpMarkdown, messageId);
|
|
1988
|
+
return;
|
|
1989
|
+
}
|
|
1877
1990
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
1878
1991
|
if (commandEvent) {
|
|
1879
1992
|
this.#logger.info(`received command ${normalizedText} (session=${clientSessionId})`);
|
|
1880
1993
|
await this.#onOutput(commandEvent);
|
|
1881
1994
|
return;
|
|
1882
1995
|
}
|
|
1996
|
+
this.#lastInboundMessageIdBySession.set(clientSessionId, messageId);
|
|
1997
|
+
this.#resetProgressState(clientSessionId);
|
|
1998
|
+
await this.#client?.startTyping(chatId, messageId);
|
|
1883
1999
|
this.#logger.info(`received user message (session=${clientSessionId}): ${normalizedText}`);
|
|
1884
2000
|
await this.#onOutput({
|
|
1885
2001
|
type: "user.message",
|
|
@@ -1966,7 +2082,7 @@ ${message}`;
|
|
|
1966
2082
|
return;
|
|
1967
2083
|
}
|
|
1968
2084
|
const state = this.#progressStateBySession.get(event.clientSessionId) ?? {
|
|
1969
|
-
renderer: new ProgressRenderer(),
|
|
2085
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
1970
2086
|
messageId: null,
|
|
1971
2087
|
creating: false
|
|
1972
2088
|
};
|
|
@@ -1996,7 +2112,7 @@ ${message}`;
|
|
|
1996
2112
|
}
|
|
1997
2113
|
#resetProgressState(clientSessionId) {
|
|
1998
2114
|
this.#progressStateBySession.set(clientSessionId, {
|
|
1999
|
-
renderer: new ProgressRenderer(),
|
|
2115
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2000
2116
|
messageId: null,
|
|
2001
2117
|
creating: false
|
|
2002
2118
|
});
|
|
@@ -2048,8 +2164,8 @@ function createFeishuConfigCollector() {
|
|
|
2048
2164
|
var feishuClientModule = {
|
|
2049
2165
|
type: "feishu",
|
|
2050
2166
|
createConfigCollector: createFeishuConfigCollector,
|
|
2051
|
-
createClientAdapter(config) {
|
|
2052
|
-
return new FeishuIMAdapter(config);
|
|
2167
|
+
createClientAdapter({ config, common }) {
|
|
2168
|
+
return new FeishuIMAdapter(config, void 0, common);
|
|
2053
2169
|
}
|
|
2054
2170
|
};
|
|
2055
2171
|
|
|
@@ -2519,7 +2635,6 @@ function parseWecomSessionId(clientSessionId) {
|
|
|
2519
2635
|
|
|
2520
2636
|
// src/modules/client/wecom/adapter/wecom-im-adapter.ts
|
|
2521
2637
|
var MAX_TEXT_CHUNK2 = 4e3;
|
|
2522
|
-
var STARTING_MESSAGE = "Processing...";
|
|
2523
2638
|
function chunkText2(text2, maxLen) {
|
|
2524
2639
|
if (text2.length <= maxLen) return [text2];
|
|
2525
2640
|
const chunks = [];
|
|
@@ -2546,6 +2661,7 @@ function chunkText2(text2, maxLen) {
|
|
|
2546
2661
|
var WecomIMAdapter = class {
|
|
2547
2662
|
#config;
|
|
2548
2663
|
#logger;
|
|
2664
|
+
#t;
|
|
2549
2665
|
#onOutput = null;
|
|
2550
2666
|
#client = null;
|
|
2551
2667
|
#egressQueue = [];
|
|
@@ -2561,18 +2677,17 @@ var WecomIMAdapter = class {
|
|
|
2561
2677
|
return;
|
|
2562
2678
|
}
|
|
2563
2679
|
const message = error instanceof Error ? error.message : String(error);
|
|
2564
|
-
const text2 =
|
|
2565
|
-
|
|
2566
|
-
${message}`;
|
|
2680
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
2567
2681
|
try {
|
|
2568
2682
|
await this.#client.sendText(chatId, text2);
|
|
2569
2683
|
} catch (notifyError) {
|
|
2570
2684
|
this.#logger.error("failed to notify send failure:", notifyError);
|
|
2571
2685
|
}
|
|
2572
2686
|
}
|
|
2573
|
-
constructor(config, logger3 = createLogger("wecom")) {
|
|
2687
|
+
constructor(config, logger3 = createLogger("wecom"), common) {
|
|
2574
2688
|
this.#config = config;
|
|
2575
2689
|
this.#logger = logger3;
|
|
2690
|
+
this.#t = getTranslatorForCommon(common);
|
|
2576
2691
|
}
|
|
2577
2692
|
async start(onOutput) {
|
|
2578
2693
|
this.#onOutput = onOutput;
|
|
@@ -2598,6 +2713,11 @@ ${message}`;
|
|
|
2598
2713
|
return;
|
|
2599
2714
|
}
|
|
2600
2715
|
const normalizedText = text2.trim();
|
|
2716
|
+
const helpMarkdown = resolveHelpMarkdown(normalizedText, this.#t);
|
|
2717
|
+
if (helpMarkdown) {
|
|
2718
|
+
await this.#client?.sendText(chatId, helpMarkdown, messageId);
|
|
2719
|
+
return;
|
|
2720
|
+
}
|
|
2601
2721
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
2602
2722
|
if (commandEvent) {
|
|
2603
2723
|
await this.#onOutput(commandEvent);
|
|
@@ -2688,7 +2808,7 @@ ${message}`;
|
|
|
2688
2808
|
if (!state || state.announced || !this.#client) {
|
|
2689
2809
|
return;
|
|
2690
2810
|
}
|
|
2691
|
-
await this.#client.sendStreamText(chatId,
|
|
2811
|
+
await this.#client.sendStreamText(chatId, this.#t("client.processing"), {
|
|
2692
2812
|
replyToMessageId: messageId,
|
|
2693
2813
|
finish: false
|
|
2694
2814
|
});
|
|
@@ -2699,7 +2819,7 @@ ${message}`;
|
|
|
2699
2819
|
return;
|
|
2700
2820
|
}
|
|
2701
2821
|
const state = this.#progressStateBySession.get(event.clientSessionId) ?? {
|
|
2702
|
-
renderer: new ProgressRenderer(),
|
|
2822
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2703
2823
|
announced: false
|
|
2704
2824
|
};
|
|
2705
2825
|
this.#progressStateBySession.set(event.clientSessionId, state);
|
|
@@ -2722,7 +2842,7 @@ ${message}`;
|
|
|
2722
2842
|
}
|
|
2723
2843
|
this.#progressStateBySession.delete(clientSessionId);
|
|
2724
2844
|
const progress = state.renderer.getCurrentProgress();
|
|
2725
|
-
const body = progress.
|
|
2845
|
+
const body = progress.isEmpty ? this.#t("client.processing") : progress.markdown;
|
|
2726
2846
|
try {
|
|
2727
2847
|
await this.#client.sendStreamText(chatId, body, { replyToMessageId, finish: true });
|
|
2728
2848
|
} catch (error) {
|
|
@@ -2731,7 +2851,7 @@ ${message}`;
|
|
|
2731
2851
|
}
|
|
2732
2852
|
#resetProgressState(clientSessionId) {
|
|
2733
2853
|
this.#progressStateBySession.set(clientSessionId, {
|
|
2734
|
-
renderer: new ProgressRenderer(),
|
|
2854
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2735
2855
|
announced: false
|
|
2736
2856
|
});
|
|
2737
2857
|
}
|
|
@@ -2778,8 +2898,8 @@ function createWecomConfigCollector() {
|
|
|
2778
2898
|
var wecomClientModule = {
|
|
2779
2899
|
type: "wecom",
|
|
2780
2900
|
createConfigCollector: createWecomConfigCollector,
|
|
2781
|
-
createClientAdapter(config) {
|
|
2782
|
-
return new WecomIMAdapter(config);
|
|
2901
|
+
createClientAdapter({ config, common }) {
|
|
2902
|
+
return new WecomIMAdapter(config, void 0, common);
|
|
2783
2903
|
}
|
|
2784
2904
|
};
|
|
2785
2905
|
|
|
@@ -3087,6 +3207,7 @@ function chunkText3(text2, maxLen) {
|
|
|
3087
3207
|
var WeixinIMAdapter = class {
|
|
3088
3208
|
#config;
|
|
3089
3209
|
#logger;
|
|
3210
|
+
#t;
|
|
3090
3211
|
#onOutput = null;
|
|
3091
3212
|
#client = null;
|
|
3092
3213
|
#egressQueue = [];
|
|
@@ -3097,9 +3218,10 @@ var WeixinIMAdapter = class {
|
|
|
3097
3218
|
#recentInboundContentKeys = /* @__PURE__ */ new Map();
|
|
3098
3219
|
#rateLimitEvents = [];
|
|
3099
3220
|
#rateLimitCircuitUntil = 0;
|
|
3100
|
-
constructor(config, logger3 = createLogger("weixin")) {
|
|
3221
|
+
constructor(config, logger3 = createLogger("weixin"), common) {
|
|
3101
3222
|
this.#config = config;
|
|
3102
3223
|
this.#logger = logger3;
|
|
3224
|
+
this.#t = getTranslatorForCommon(common);
|
|
3103
3225
|
}
|
|
3104
3226
|
async start(onOutput) {
|
|
3105
3227
|
this.#onOutput = onOutput;
|
|
@@ -3120,8 +3242,13 @@ var WeixinIMAdapter = class {
|
|
|
3120
3242
|
this.#logger.debug(`ignoring unsupported Weixin group message (session=${clientSessionId})`);
|
|
3121
3243
|
return;
|
|
3122
3244
|
}
|
|
3123
|
-
this.#resetProgressState(clientSessionId);
|
|
3124
3245
|
const normalizedText = text2.trim();
|
|
3246
|
+
const helpMarkdown = resolveHelpMarkdown(normalizedText, this.#t);
|
|
3247
|
+
if (helpMarkdown) {
|
|
3248
|
+
await this.#client?.sendText(chatId, helpMarkdown);
|
|
3249
|
+
return;
|
|
3250
|
+
}
|
|
3251
|
+
this.#resetProgressState(clientSessionId);
|
|
3125
3252
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
3126
3253
|
if (commandEvent) {
|
|
3127
3254
|
await this.#onOutput(commandEvent);
|
|
@@ -3241,9 +3368,7 @@ var WeixinIMAdapter = class {
|
|
|
3241
3368
|
return;
|
|
3242
3369
|
}
|
|
3243
3370
|
const message = error instanceof Error ? error.message : String(error);
|
|
3244
|
-
const text2 =
|
|
3245
|
-
|
|
3246
|
-
${message}`;
|
|
3371
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
3247
3372
|
try {
|
|
3248
3373
|
await this.#client.sendText(chatId, text2);
|
|
3249
3374
|
} catch (notifyError) {
|
|
@@ -3256,7 +3381,7 @@ ${message}`;
|
|
|
3256
3381
|
}
|
|
3257
3382
|
const now = Date.now();
|
|
3258
3383
|
if (this.#rateLimitCircuitUntil > now) {
|
|
3259
|
-
throw new Error("
|
|
3384
|
+
throw new Error(this.#t("client.weixinCooldown"));
|
|
3260
3385
|
}
|
|
3261
3386
|
if (this.#rateLimitCircuitUntil !== 0 && this.#rateLimitCircuitUntil <= now) {
|
|
3262
3387
|
this.#rateLimitCircuitUntil = 0;
|
|
@@ -3272,7 +3397,7 @@ ${message}`;
|
|
|
3272
3397
|
if (this.#isRateLimitError(error)) {
|
|
3273
3398
|
this.#recordRateLimitEvent(now);
|
|
3274
3399
|
if (this.#rateLimitCircuitUntil > now) {
|
|
3275
|
-
throw new Error("
|
|
3400
|
+
throw new Error(this.#t("client.weixinCooldown"));
|
|
3276
3401
|
}
|
|
3277
3402
|
}
|
|
3278
3403
|
throw error;
|
|
@@ -3301,7 +3426,7 @@ ${message}`;
|
|
|
3301
3426
|
}
|
|
3302
3427
|
#createProgressState() {
|
|
3303
3428
|
return {
|
|
3304
|
-
renderer: new ProgressRenderer(),
|
|
3429
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
3305
3430
|
dirty: false,
|
|
3306
3431
|
interval: null
|
|
3307
3432
|
};
|
|
@@ -3486,8 +3611,8 @@ function createWeixinConfigCollector() {
|
|
|
3486
3611
|
var weixinClientModule = {
|
|
3487
3612
|
type: "weixin",
|
|
3488
3613
|
createConfigCollector: createWeixinConfigCollector,
|
|
3489
|
-
createClientAdapter(config) {
|
|
3490
|
-
return new WeixinIMAdapter(config);
|
|
3614
|
+
createClientAdapter({ config, common }) {
|
|
3615
|
+
return new WeixinIMAdapter(config, void 0, common);
|
|
3491
3616
|
}
|
|
3492
3617
|
};
|
|
3493
3618
|
|
|
@@ -3516,14 +3641,19 @@ var logger2 = createLogger("runner");
|
|
|
3516
3641
|
async function runChannel({ channelName, channelConfig, defaults }) {
|
|
3517
3642
|
const clientModule = getTypedClientModule(channelConfig.client);
|
|
3518
3643
|
const agentModule = getTypedAgentModule(channelConfig.agent);
|
|
3519
|
-
const
|
|
3644
|
+
const common = {
|
|
3645
|
+
channelName,
|
|
3646
|
+
language: channelConfig.common.language
|
|
3647
|
+
};
|
|
3648
|
+
const imAdapter = clientModule.createClientAdapter({ config: channelConfig.client.config, common });
|
|
3520
3649
|
const bindingStore = createFileSessionBindingStore(getSessionBindingStorePath(channelName));
|
|
3521
3650
|
const core = new GatewayCore({
|
|
3522
3651
|
imAdapter,
|
|
3523
3652
|
agentModule,
|
|
3524
3653
|
agentConfig: channelConfig.agent.config,
|
|
3525
3654
|
agentIdleTimeoutMs: defaults.agentIdleTimeoutMs,
|
|
3526
|
-
bindingStore
|
|
3655
|
+
bindingStore,
|
|
3656
|
+
common
|
|
3527
3657
|
});
|
|
3528
3658
|
await core.start();
|
|
3529
3659
|
logger2.info(`channel ${channelName} started`);
|
|
@@ -3537,6 +3667,8 @@ async function runChannel({ channelName, channelConfig, defaults }) {
|
|
|
3537
3667
|
}
|
|
3538
3668
|
|
|
3539
3669
|
// src/cli.ts
|
|
3670
|
+
var require2 = createRequire(import.meta.url);
|
|
3671
|
+
var { version } = require2("../package.json");
|
|
3540
3672
|
async function selectModuleType(label, modules, ctx) {
|
|
3541
3673
|
if (modules.length === 0) {
|
|
3542
3674
|
throw new Error(`No modules available for ${label}`);
|
|
@@ -3558,6 +3690,15 @@ async function collectModuleConfig(module, ctx) {
|
|
|
3558
3690
|
await collector.validate(config);
|
|
3559
3691
|
return config;
|
|
3560
3692
|
}
|
|
3693
|
+
async function collectCommonChannelConfig(ctx) {
|
|
3694
|
+
const language = await ctx.select("Channel language", [
|
|
3695
|
+
{ label: "English (en-US)", value: "en-US" },
|
|
3696
|
+
{ label: "\u4E2D\u6587 (zh-CN)", value: "zh-CN" }
|
|
3697
|
+
]);
|
|
3698
|
+
return {
|
|
3699
|
+
language
|
|
3700
|
+
};
|
|
3701
|
+
}
|
|
3561
3702
|
async function addChannel(config) {
|
|
3562
3703
|
const ctx = createPromptContext();
|
|
3563
3704
|
try {
|
|
@@ -3569,6 +3710,7 @@ async function addChannel(config) {
|
|
|
3569
3710
|
return null;
|
|
3570
3711
|
}
|
|
3571
3712
|
});
|
|
3713
|
+
const commonConfig = await collectCommonChannelConfig(ctx);
|
|
3572
3714
|
const clientType = await selectModuleType("Select client module", listClientModules(), ctx);
|
|
3573
3715
|
const clientModule = getClientModule(clientType);
|
|
3574
3716
|
if (!clientModule) {
|
|
@@ -3582,6 +3724,7 @@ async function addChannel(config) {
|
|
|
3582
3724
|
}
|
|
3583
3725
|
const agentConfig = await collectModuleConfig(agentModule, ctx);
|
|
3584
3726
|
config.channels[name] = {
|
|
3727
|
+
common: commonConfig,
|
|
3585
3728
|
client: {
|
|
3586
3729
|
type: clientType,
|
|
3587
3730
|
config: clientConfig
|
|
@@ -3660,7 +3803,7 @@ async function startChannel(channelName) {
|
|
|
3660
3803
|
}
|
|
3661
3804
|
async function runCli(argv = process2.argv) {
|
|
3662
3805
|
const program = new Command();
|
|
3663
|
-
program.name("agent-bridge").description("IM to Agent bridge CLI").version(
|
|
3806
|
+
program.name("agent-bridge").description("IM to Agent bridge CLI").version(version);
|
|
3664
3807
|
program.command("add").description("Interactively add a channel").action(async () => {
|
|
3665
3808
|
const config = await loadConfig();
|
|
3666
3809
|
await addChannel(config);
|