@hopgoldy/agent-bridge 0.3.0 → 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 -63
- package/dist/cli.js +203 -63
- package/dist/index.d.ts +16 -2
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -78,6 +78,8 @@ agent-bridge remove <channel-name>
|
|
|
78
78
|
|
|
79
79
|
Config file: `~/.config/agent-bridge/config.json`
|
|
80
80
|
|
|
81
|
+
Architecture overview: [`docs/architecture-design.md`](./docs/architecture-design.md)
|
|
82
|
+
|
|
81
83
|
Command usage across IM adapters: [`docs/command-system.md`](./docs/command-system.md)
|
|
82
84
|
|
|
83
85
|
## Development
|
package/dist/agent-bridge.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);
|
|
@@ -1380,9 +1477,6 @@ var ProgressRenderer = class {
|
|
|
1380
1477
|
#upsertToolEntry(id, event) {
|
|
1381
1478
|
if (!this.#entries.has(id)) {
|
|
1382
1479
|
this.#order.push(id);
|
|
1383
|
-
} else {
|
|
1384
|
-
this.#order = this.#order.filter((entryId) => entryId !== id);
|
|
1385
|
-
this.#order.push(id);
|
|
1386
1480
|
}
|
|
1387
1481
|
this.#entries.set(id, {
|
|
1388
1482
|
kind: "tool",
|
|
@@ -1402,9 +1496,9 @@ var ProgressRenderer = class {
|
|
|
1402
1496
|
const subject = this.#formatToolSubject(entry.toolName, entry.toolLabel);
|
|
1403
1497
|
switch (entry.status) {
|
|
1404
1498
|
case "running":
|
|
1405
|
-
return `-
|
|
1499
|
+
return `- ${this.#t("progress.running", { subject })}`;
|
|
1406
1500
|
case "done":
|
|
1407
|
-
return `-
|
|
1501
|
+
return `- ${this.#t("progress.finished", { subject })}`;
|
|
1408
1502
|
case "error":
|
|
1409
1503
|
return this.#formatToolErrorLine(subject, entry.text);
|
|
1410
1504
|
}
|
|
@@ -1412,12 +1506,12 @@ var ProgressRenderer = class {
|
|
|
1412
1506
|
#formatProgressLine(event) {
|
|
1413
1507
|
switch (event.type) {
|
|
1414
1508
|
case "session.compacting":
|
|
1415
|
-
return `-
|
|
1509
|
+
return `- ${event.text ? this.#t("progress.compactingWithDetail", { detail: event.text }) : this.#t("progress.compacting")}`;
|
|
1416
1510
|
case "assistant.tool.running":
|
|
1417
1511
|
case "assistant.tool.update":
|
|
1418
|
-
return `-
|
|
1512
|
+
return `- ${this.#t("progress.running", { subject: this.#formatToolSubject(event.toolName, event.toolLabel) })}`;
|
|
1419
1513
|
case "assistant.tool.done":
|
|
1420
|
-
return `-
|
|
1514
|
+
return `- ${this.#t("progress.finished", { subject: this.#formatToolSubject(event.toolName, event.toolLabel) })}`;
|
|
1421
1515
|
case "assistant.tool.error":
|
|
1422
1516
|
return this.#formatToolErrorLine(this.#formatToolSubject(event.toolName, event.toolLabel), event.text);
|
|
1423
1517
|
}
|
|
@@ -1439,13 +1533,13 @@ var ProgressRenderer = class {
|
|
|
1439
1533
|
}
|
|
1440
1534
|
const lowerText = normalizedText.toLowerCase();
|
|
1441
1535
|
const lowerToolName = toolName.toLowerCase();
|
|
1442
|
-
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()) {
|
|
1443
1537
|
return `- ${this.#humanizeToolError(toolName)}`;
|
|
1444
1538
|
}
|
|
1445
|
-
return `- ${this.#
|
|
1539
|
+
return `- ${this.#t("progress.failedWithDetail", { subject: toolName, detail: normalizedText })}`;
|
|
1446
1540
|
}
|
|
1447
1541
|
#humanizeToolError(toolName) {
|
|
1448
|
-
return
|
|
1542
|
+
return this.#t("progress.failed", { subject: toolName });
|
|
1449
1543
|
}
|
|
1450
1544
|
#progressStatus(event) {
|
|
1451
1545
|
switch (event.type) {
|
|
@@ -1460,6 +1554,18 @@ var ProgressRenderer = class {
|
|
|
1460
1554
|
};
|
|
1461
1555
|
|
|
1462
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
|
+
}
|
|
1463
1569
|
function parseSlashCommand(text2, clientSessionId) {
|
|
1464
1570
|
switch (text2.toLowerCase()) {
|
|
1465
1571
|
case "/new":
|
|
@@ -1469,6 +1575,7 @@ function parseSlashCommand(text2, clientSessionId) {
|
|
|
1469
1575
|
case "/c":
|
|
1470
1576
|
return { type: "command.session.compact", clientSessionId };
|
|
1471
1577
|
case "/stop":
|
|
1578
|
+
case "/s":
|
|
1472
1579
|
return { type: "command.session.stop", clientSessionId };
|
|
1473
1580
|
default:
|
|
1474
1581
|
return null;
|
|
@@ -1821,6 +1928,7 @@ function chunkText(text2, maxLen) {
|
|
|
1821
1928
|
var FeishuIMAdapter = class _FeishuIMAdapter {
|
|
1822
1929
|
#config;
|
|
1823
1930
|
#logger;
|
|
1931
|
+
#t;
|
|
1824
1932
|
#onOutput = null;
|
|
1825
1933
|
#client = null;
|
|
1826
1934
|
#egressQueue = [];
|
|
@@ -1845,18 +1953,17 @@ var FeishuIMAdapter = class _FeishuIMAdapter {
|
|
|
1845
1953
|
return;
|
|
1846
1954
|
}
|
|
1847
1955
|
const message = error instanceof Error ? error.message : String(error);
|
|
1848
|
-
const text2 =
|
|
1849
|
-
|
|
1850
|
-
${message}`;
|
|
1956
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
1851
1957
|
try {
|
|
1852
1958
|
await this.#client.sendText(chatId, text2);
|
|
1853
1959
|
} catch (notifyError) {
|
|
1854
1960
|
this.#logger.error("failed to notify send failure:", notifyError);
|
|
1855
1961
|
}
|
|
1856
1962
|
}
|
|
1857
|
-
constructor(config, logger3 = createLogger("feishu")) {
|
|
1963
|
+
constructor(config, logger3 = createLogger("feishu"), common) {
|
|
1858
1964
|
this.#config = config;
|
|
1859
1965
|
this.#logger = logger3;
|
|
1966
|
+
this.#t = getTranslatorForCommon(common);
|
|
1860
1967
|
}
|
|
1861
1968
|
async start(onOutput) {
|
|
1862
1969
|
this.#onOutput = onOutput;
|
|
@@ -1873,16 +1980,22 @@ ${message}`;
|
|
|
1873
1980
|
);
|
|
1874
1981
|
return;
|
|
1875
1982
|
}
|
|
1876
|
-
this.#lastInboundMessageIdBySession.set(clientSessionId, messageId);
|
|
1877
|
-
this.#resetProgressState(clientSessionId);
|
|
1878
|
-
await this.#client?.startTyping(chatId, messageId);
|
|
1879
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
|
+
}
|
|
1880
1990
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
1881
1991
|
if (commandEvent) {
|
|
1882
1992
|
this.#logger.info(`received command ${normalizedText} (session=${clientSessionId})`);
|
|
1883
1993
|
await this.#onOutput(commandEvent);
|
|
1884
1994
|
return;
|
|
1885
1995
|
}
|
|
1996
|
+
this.#lastInboundMessageIdBySession.set(clientSessionId, messageId);
|
|
1997
|
+
this.#resetProgressState(clientSessionId);
|
|
1998
|
+
await this.#client?.startTyping(chatId, messageId);
|
|
1886
1999
|
this.#logger.info(`received user message (session=${clientSessionId}): ${normalizedText}`);
|
|
1887
2000
|
await this.#onOutput({
|
|
1888
2001
|
type: "user.message",
|
|
@@ -1969,7 +2082,7 @@ ${message}`;
|
|
|
1969
2082
|
return;
|
|
1970
2083
|
}
|
|
1971
2084
|
const state = this.#progressStateBySession.get(event.clientSessionId) ?? {
|
|
1972
|
-
renderer: new ProgressRenderer(),
|
|
2085
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
1973
2086
|
messageId: null,
|
|
1974
2087
|
creating: false
|
|
1975
2088
|
};
|
|
@@ -1999,7 +2112,7 @@ ${message}`;
|
|
|
1999
2112
|
}
|
|
2000
2113
|
#resetProgressState(clientSessionId) {
|
|
2001
2114
|
this.#progressStateBySession.set(clientSessionId, {
|
|
2002
|
-
renderer: new ProgressRenderer(),
|
|
2115
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2003
2116
|
messageId: null,
|
|
2004
2117
|
creating: false
|
|
2005
2118
|
});
|
|
@@ -2051,8 +2164,8 @@ function createFeishuConfigCollector() {
|
|
|
2051
2164
|
var feishuClientModule = {
|
|
2052
2165
|
type: "feishu",
|
|
2053
2166
|
createConfigCollector: createFeishuConfigCollector,
|
|
2054
|
-
createClientAdapter(config) {
|
|
2055
|
-
return new FeishuIMAdapter(config);
|
|
2167
|
+
createClientAdapter({ config, common }) {
|
|
2168
|
+
return new FeishuIMAdapter(config, void 0, common);
|
|
2056
2169
|
}
|
|
2057
2170
|
};
|
|
2058
2171
|
|
|
@@ -2522,7 +2635,6 @@ function parseWecomSessionId(clientSessionId) {
|
|
|
2522
2635
|
|
|
2523
2636
|
// src/modules/client/wecom/adapter/wecom-im-adapter.ts
|
|
2524
2637
|
var MAX_TEXT_CHUNK2 = 4e3;
|
|
2525
|
-
var STARTING_MESSAGE = "Processing...";
|
|
2526
2638
|
function chunkText2(text2, maxLen) {
|
|
2527
2639
|
if (text2.length <= maxLen) return [text2];
|
|
2528
2640
|
const chunks = [];
|
|
@@ -2549,6 +2661,7 @@ function chunkText2(text2, maxLen) {
|
|
|
2549
2661
|
var WecomIMAdapter = class {
|
|
2550
2662
|
#config;
|
|
2551
2663
|
#logger;
|
|
2664
|
+
#t;
|
|
2552
2665
|
#onOutput = null;
|
|
2553
2666
|
#client = null;
|
|
2554
2667
|
#egressQueue = [];
|
|
@@ -2564,18 +2677,17 @@ var WecomIMAdapter = class {
|
|
|
2564
2677
|
return;
|
|
2565
2678
|
}
|
|
2566
2679
|
const message = error instanceof Error ? error.message : String(error);
|
|
2567
|
-
const text2 =
|
|
2568
|
-
|
|
2569
|
-
${message}`;
|
|
2680
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
2570
2681
|
try {
|
|
2571
2682
|
await this.#client.sendText(chatId, text2);
|
|
2572
2683
|
} catch (notifyError) {
|
|
2573
2684
|
this.#logger.error("failed to notify send failure:", notifyError);
|
|
2574
2685
|
}
|
|
2575
2686
|
}
|
|
2576
|
-
constructor(config, logger3 = createLogger("wecom")) {
|
|
2687
|
+
constructor(config, logger3 = createLogger("wecom"), common) {
|
|
2577
2688
|
this.#config = config;
|
|
2578
2689
|
this.#logger = logger3;
|
|
2690
|
+
this.#t = getTranslatorForCommon(common);
|
|
2579
2691
|
}
|
|
2580
2692
|
async start(onOutput) {
|
|
2581
2693
|
this.#onOutput = onOutput;
|
|
@@ -2601,6 +2713,11 @@ ${message}`;
|
|
|
2601
2713
|
return;
|
|
2602
2714
|
}
|
|
2603
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
|
+
}
|
|
2604
2721
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
2605
2722
|
if (commandEvent) {
|
|
2606
2723
|
await this.#onOutput(commandEvent);
|
|
@@ -2691,7 +2808,7 @@ ${message}`;
|
|
|
2691
2808
|
if (!state || state.announced || !this.#client) {
|
|
2692
2809
|
return;
|
|
2693
2810
|
}
|
|
2694
|
-
await this.#client.sendStreamText(chatId,
|
|
2811
|
+
await this.#client.sendStreamText(chatId, this.#t("client.processing"), {
|
|
2695
2812
|
replyToMessageId: messageId,
|
|
2696
2813
|
finish: false
|
|
2697
2814
|
});
|
|
@@ -2702,7 +2819,7 @@ ${message}`;
|
|
|
2702
2819
|
return;
|
|
2703
2820
|
}
|
|
2704
2821
|
const state = this.#progressStateBySession.get(event.clientSessionId) ?? {
|
|
2705
|
-
renderer: new ProgressRenderer(),
|
|
2822
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2706
2823
|
announced: false
|
|
2707
2824
|
};
|
|
2708
2825
|
this.#progressStateBySession.set(event.clientSessionId, state);
|
|
@@ -2725,7 +2842,7 @@ ${message}`;
|
|
|
2725
2842
|
}
|
|
2726
2843
|
this.#progressStateBySession.delete(clientSessionId);
|
|
2727
2844
|
const progress = state.renderer.getCurrentProgress();
|
|
2728
|
-
const body = progress.
|
|
2845
|
+
const body = progress.isEmpty ? this.#t("client.processing") : progress.markdown;
|
|
2729
2846
|
try {
|
|
2730
2847
|
await this.#client.sendStreamText(chatId, body, { replyToMessageId, finish: true });
|
|
2731
2848
|
} catch (error) {
|
|
@@ -2734,7 +2851,7 @@ ${message}`;
|
|
|
2734
2851
|
}
|
|
2735
2852
|
#resetProgressState(clientSessionId) {
|
|
2736
2853
|
this.#progressStateBySession.set(clientSessionId, {
|
|
2737
|
-
renderer: new ProgressRenderer(),
|
|
2854
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
2738
2855
|
announced: false
|
|
2739
2856
|
});
|
|
2740
2857
|
}
|
|
@@ -2781,8 +2898,8 @@ function createWecomConfigCollector() {
|
|
|
2781
2898
|
var wecomClientModule = {
|
|
2782
2899
|
type: "wecom",
|
|
2783
2900
|
createConfigCollector: createWecomConfigCollector,
|
|
2784
|
-
createClientAdapter(config) {
|
|
2785
|
-
return new WecomIMAdapter(config);
|
|
2901
|
+
createClientAdapter({ config, common }) {
|
|
2902
|
+
return new WecomIMAdapter(config, void 0, common);
|
|
2786
2903
|
}
|
|
2787
2904
|
};
|
|
2788
2905
|
|
|
@@ -3090,6 +3207,7 @@ function chunkText3(text2, maxLen) {
|
|
|
3090
3207
|
var WeixinIMAdapter = class {
|
|
3091
3208
|
#config;
|
|
3092
3209
|
#logger;
|
|
3210
|
+
#t;
|
|
3093
3211
|
#onOutput = null;
|
|
3094
3212
|
#client = null;
|
|
3095
3213
|
#egressQueue = [];
|
|
@@ -3100,9 +3218,10 @@ var WeixinIMAdapter = class {
|
|
|
3100
3218
|
#recentInboundContentKeys = /* @__PURE__ */ new Map();
|
|
3101
3219
|
#rateLimitEvents = [];
|
|
3102
3220
|
#rateLimitCircuitUntil = 0;
|
|
3103
|
-
constructor(config, logger3 = createLogger("weixin")) {
|
|
3221
|
+
constructor(config, logger3 = createLogger("weixin"), common) {
|
|
3104
3222
|
this.#config = config;
|
|
3105
3223
|
this.#logger = logger3;
|
|
3224
|
+
this.#t = getTranslatorForCommon(common);
|
|
3106
3225
|
}
|
|
3107
3226
|
async start(onOutput) {
|
|
3108
3227
|
this.#onOutput = onOutput;
|
|
@@ -3123,8 +3242,13 @@ var WeixinIMAdapter = class {
|
|
|
3123
3242
|
this.#logger.debug(`ignoring unsupported Weixin group message (session=${clientSessionId})`);
|
|
3124
3243
|
return;
|
|
3125
3244
|
}
|
|
3126
|
-
this.#resetProgressState(clientSessionId);
|
|
3127
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);
|
|
3128
3252
|
const commandEvent = parseSlashCommand(normalizedText, clientSessionId);
|
|
3129
3253
|
if (commandEvent) {
|
|
3130
3254
|
await this.#onOutput(commandEvent);
|
|
@@ -3244,9 +3368,7 @@ var WeixinIMAdapter = class {
|
|
|
3244
3368
|
return;
|
|
3245
3369
|
}
|
|
3246
3370
|
const message = error instanceof Error ? error.message : String(error);
|
|
3247
|
-
const text2 =
|
|
3248
|
-
|
|
3249
|
-
${message}`;
|
|
3371
|
+
const text2 = formatSendFailureNotice(this.#t, message);
|
|
3250
3372
|
try {
|
|
3251
3373
|
await this.#client.sendText(chatId, text2);
|
|
3252
3374
|
} catch (notifyError) {
|
|
@@ -3259,7 +3381,7 @@ ${message}`;
|
|
|
3259
3381
|
}
|
|
3260
3382
|
const now = Date.now();
|
|
3261
3383
|
if (this.#rateLimitCircuitUntil > now) {
|
|
3262
|
-
throw new Error("
|
|
3384
|
+
throw new Error(this.#t("client.weixinCooldown"));
|
|
3263
3385
|
}
|
|
3264
3386
|
if (this.#rateLimitCircuitUntil !== 0 && this.#rateLimitCircuitUntil <= now) {
|
|
3265
3387
|
this.#rateLimitCircuitUntil = 0;
|
|
@@ -3275,7 +3397,7 @@ ${message}`;
|
|
|
3275
3397
|
if (this.#isRateLimitError(error)) {
|
|
3276
3398
|
this.#recordRateLimitEvent(now);
|
|
3277
3399
|
if (this.#rateLimitCircuitUntil > now) {
|
|
3278
|
-
throw new Error("
|
|
3400
|
+
throw new Error(this.#t("client.weixinCooldown"));
|
|
3279
3401
|
}
|
|
3280
3402
|
}
|
|
3281
3403
|
throw error;
|
|
@@ -3304,7 +3426,7 @@ ${message}`;
|
|
|
3304
3426
|
}
|
|
3305
3427
|
#createProgressState() {
|
|
3306
3428
|
return {
|
|
3307
|
-
renderer: new ProgressRenderer(),
|
|
3429
|
+
renderer: new ProgressRenderer({ t: this.#t }),
|
|
3308
3430
|
dirty: false,
|
|
3309
3431
|
interval: null
|
|
3310
3432
|
};
|
|
@@ -3489,8 +3611,8 @@ function createWeixinConfigCollector() {
|
|
|
3489
3611
|
var weixinClientModule = {
|
|
3490
3612
|
type: "weixin",
|
|
3491
3613
|
createConfigCollector: createWeixinConfigCollector,
|
|
3492
|
-
createClientAdapter(config) {
|
|
3493
|
-
return new WeixinIMAdapter(config);
|
|
3614
|
+
createClientAdapter({ config, common }) {
|
|
3615
|
+
return new WeixinIMAdapter(config, void 0, common);
|
|
3494
3616
|
}
|
|
3495
3617
|
};
|
|
3496
3618
|
|
|
@@ -3519,14 +3641,19 @@ var logger2 = createLogger("runner");
|
|
|
3519
3641
|
async function runChannel({ channelName, channelConfig, defaults }) {
|
|
3520
3642
|
const clientModule = getTypedClientModule(channelConfig.client);
|
|
3521
3643
|
const agentModule = getTypedAgentModule(channelConfig.agent);
|
|
3522
|
-
const
|
|
3644
|
+
const common = {
|
|
3645
|
+
channelName,
|
|
3646
|
+
language: channelConfig.common.language
|
|
3647
|
+
};
|
|
3648
|
+
const imAdapter = clientModule.createClientAdapter({ config: channelConfig.client.config, common });
|
|
3523
3649
|
const bindingStore = createFileSessionBindingStore(getSessionBindingStorePath(channelName));
|
|
3524
3650
|
const core = new GatewayCore({
|
|
3525
3651
|
imAdapter,
|
|
3526
3652
|
agentModule,
|
|
3527
3653
|
agentConfig: channelConfig.agent.config,
|
|
3528
3654
|
agentIdleTimeoutMs: defaults.agentIdleTimeoutMs,
|
|
3529
|
-
bindingStore
|
|
3655
|
+
bindingStore,
|
|
3656
|
+
common
|
|
3530
3657
|
});
|
|
3531
3658
|
await core.start();
|
|
3532
3659
|
logger2.info(`channel ${channelName} started`);
|
|
@@ -3540,6 +3667,8 @@ async function runChannel({ channelName, channelConfig, defaults }) {
|
|
|
3540
3667
|
}
|
|
3541
3668
|
|
|
3542
3669
|
// src/cli.ts
|
|
3670
|
+
var require2 = createRequire(import.meta.url);
|
|
3671
|
+
var { version } = require2("../package.json");
|
|
3543
3672
|
async function selectModuleType(label, modules, ctx) {
|
|
3544
3673
|
if (modules.length === 0) {
|
|
3545
3674
|
throw new Error(`No modules available for ${label}`);
|
|
@@ -3561,6 +3690,15 @@ async function collectModuleConfig(module, ctx) {
|
|
|
3561
3690
|
await collector.validate(config);
|
|
3562
3691
|
return config;
|
|
3563
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
|
+
}
|
|
3564
3702
|
async function addChannel(config) {
|
|
3565
3703
|
const ctx = createPromptContext();
|
|
3566
3704
|
try {
|
|
@@ -3572,6 +3710,7 @@ async function addChannel(config) {
|
|
|
3572
3710
|
return null;
|
|
3573
3711
|
}
|
|
3574
3712
|
});
|
|
3713
|
+
const commonConfig = await collectCommonChannelConfig(ctx);
|
|
3575
3714
|
const clientType = await selectModuleType("Select client module", listClientModules(), ctx);
|
|
3576
3715
|
const clientModule = getClientModule(clientType);
|
|
3577
3716
|
if (!clientModule) {
|
|
@@ -3585,6 +3724,7 @@ async function addChannel(config) {
|
|
|
3585
3724
|
}
|
|
3586
3725
|
const agentConfig = await collectModuleConfig(agentModule, ctx);
|
|
3587
3726
|
config.channels[name] = {
|
|
3727
|
+
common: commonConfig,
|
|
3588
3728
|
client: {
|
|
3589
3729
|
type: clientType,
|
|
3590
3730
|
config: clientConfig
|
|
@@ -3663,7 +3803,7 @@ async function startChannel(channelName) {
|
|
|
3663
3803
|
}
|
|
3664
3804
|
async function runCli(argv = process2.argv) {
|
|
3665
3805
|
const program = new Command();
|
|
3666
|
-
program.name("agent-bridge").description("IM to Agent bridge CLI").version(
|
|
3806
|
+
program.name("agent-bridge").description("IM to Agent bridge CLI").version(version);
|
|
3667
3807
|
program.command("add").description("Interactively add a channel").action(async () => {
|
|
3668
3808
|
const config = await loadConfig();
|
|
3669
3809
|
await addChannel(config);
|