dsh-agent-toolkit 0.2.2 → 0.2.3

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/lib/index.js CHANGED
@@ -2266,20 +2266,23 @@ const feishuChannel = {
2266
2266
  appSecret: bot.secret
2267
2267
  }));
2268
2268
  const dedup = new MessageDedup();
2269
- const dispatcher = new lark.EventDispatcher({}).register({ "im.message.receive_v1": async (data) => {
2270
- const parsed = parseMessageEvent(data);
2271
- if (parsed === null || !dedup.check(parsed.messageId)) return;
2272
- const reply = new FeishuReplyHandle(api, parsed.chatId, tunables, log);
2273
- io.onMessage({
2274
- botId: bot.record.id,
2275
- chatId: parsed.chatId,
2276
- userId: parsed.userId,
2277
- messageId: parsed.messageId,
2278
- text: parsed.text,
2279
- reply,
2280
- ackProcessing: makeAck(api, parsed.messageId, tunables.processingReactionEmoji)
2281
- });
2282
- } });
2269
+ const dispatcher = new lark.EventDispatcher({}).register({
2270
+ "im.message.message_read_v1": async () => void 0,
2271
+ "im.message.receive_v1": async (data) => {
2272
+ const parsed = parseMessageEvent(data);
2273
+ if (parsed === null || !dedup.check(parsed.messageId)) return;
2274
+ const reply = new FeishuReplyHandle(api, parsed.chatId, tunables, log);
2275
+ io.onMessage({
2276
+ botId: bot.record.id,
2277
+ chatId: parsed.chatId,
2278
+ userId: parsed.userId,
2279
+ messageId: parsed.messageId,
2280
+ text: parsed.text,
2281
+ reply,
2282
+ ackProcessing: makeAck(api, parsed.messageId, tunables.processingReactionEmoji)
2283
+ });
2284
+ }
2285
+ });
2283
2286
  const ws = new lark.WSClient({
2284
2287
  appId,
2285
2288
  appSecret: bot.secret,
@@ -2342,66 +2345,6 @@ const projectBotDomain = defineDomain({
2342
2345
  function bindingKey(botId, chatId) {
2343
2346
  return `${botId}:${chatId}`;
2344
2347
  }
2345
- //#endregion
2346
- //#region src/channels/inbound.ts
2347
- /** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → followup 投递。 */
2348
- var Inbound = class {
2349
- deps;
2350
- constructor(deps) {
2351
- this.deps = deps;
2352
- }
2353
- onMessage(msg) {
2354
- this.handle(msg).catch(async (error) => {
2355
- this.deps.onError(`[project-bot] 入站处理失败:${error instanceof Error ? error.message : String(error)}`);
2356
- await msg.reply.notice("处理失败,请稍后再试").catch(() => void 0);
2357
- });
2358
- }
2359
- async handle(msg) {
2360
- const bot = this.deps.bots.get(msg.botId);
2361
- if (bot === void 0) return;
2362
- const directive = parseDirective(msg.text);
2363
- if (directive === "new") {
2364
- await this.deps.router.reset(bot, msg.chatId, msg.reply);
2365
- await msg.reply.notice("已开启新会话");
2366
- return;
2367
- }
2368
- if (directive === "stop") {
2369
- const rt = this.deps.router.lookup(bot.id, msg.chatId);
2370
- if (rt?.inflight !== void 0) {
2371
- rt.agent.cancel();
2372
- await msg.reply.notice("已请求停止当前任务");
2373
- } else await msg.reply.notice("当前没有进行中的任务");
2374
- return;
2375
- }
2376
- if (directive === "status") {
2377
- const rt = this.deps.router.lookup(bot.id, msg.chatId);
2378
- await msg.reply.notice(rt === void 0 ? `项目:${bot.project}\n会话:未创建(发送消息即创建)` : `项目:${bot.project}\n会话:${rt.sessionId}\n状态:${rt.inflight !== void 0 ? "处理中" : "空闲"}`);
2379
- return;
2380
- }
2381
- const rt = await this.deps.router.ensure(bot, msg.chatId, msg.reply);
2382
- if (rt.inflight !== void 0) {
2383
- await msg.reply.notice("上一条还在处理中,请稍候(或发送 /stop 取消)");
2384
- return;
2385
- }
2386
- rt.inflight = { ack: void 0 };
2387
- rt.inflight.ack = await msg.ackProcessing().catch(() => void 0) ?? void 0;
2388
- const message = createUserMessage({
2389
- content: [{
2390
- type: "text",
2391
- text: msg.text
2392
- }],
2393
- source: { kind: "user" }
2394
- });
2395
- try {
2396
- rt.agent.followup(message);
2397
- } catch (error) {
2398
- const ack = rt.inflight.ack;
2399
- rt.inflight = void 0;
2400
- await ack?.();
2401
- throw error;
2402
- }
2403
- }
2404
- };
2405
2348
  /** 向段序列追加内容:与尾段同类则合并,异类开新段。 */
2406
2349
  function appendToSegments(segments, kind, text) {
2407
2350
  const tail = segments[segments.length - 1];
@@ -2519,6 +2462,67 @@ var Outbound = class {
2519
2462
  }
2520
2463
  };
2521
2464
  //#endregion
2465
+ //#region src/channels/inbound.ts
2466
+ /** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → followup 投递。 */
2467
+ var Inbound = class {
2468
+ deps;
2469
+ constructor(deps) {
2470
+ this.deps = deps;
2471
+ }
2472
+ onMessage(msg) {
2473
+ this.handle(msg).catch(async (error) => {
2474
+ const detail = truncateDetail(error instanceof Error ? error.message : String(error), this.deps.maxErrorDetailChars);
2475
+ this.deps.onError(`[project-bot] 入站处理失败:${detail}`);
2476
+ await msg.reply.notice(`处理失败:${detail}`).catch(() => void 0);
2477
+ });
2478
+ }
2479
+ async handle(msg) {
2480
+ const bot = this.deps.bots.get(msg.botId);
2481
+ if (bot === void 0) return;
2482
+ const directive = parseDirective(msg.text);
2483
+ if (directive === "new") {
2484
+ await this.deps.router.reset(bot, msg.chatId, msg.reply);
2485
+ await msg.reply.notice("已开启新会话");
2486
+ return;
2487
+ }
2488
+ if (directive === "stop") {
2489
+ const rt = this.deps.router.lookup(bot.id, msg.chatId);
2490
+ if (rt?.inflight !== void 0) {
2491
+ rt.agent.cancel();
2492
+ await msg.reply.notice("已请求停止当前任务");
2493
+ } else await msg.reply.notice("当前没有进行中的任务");
2494
+ return;
2495
+ }
2496
+ if (directive === "status") {
2497
+ const rt = this.deps.router.lookup(bot.id, msg.chatId);
2498
+ await msg.reply.notice(rt === void 0 ? `项目:${bot.project}\n会话:未创建(发送消息即创建)` : `项目:${bot.project}\n会话:${rt.sessionId}\n状态:${rt.inflight !== void 0 ? "处理中" : "空闲"}`);
2499
+ return;
2500
+ }
2501
+ const rt = await this.deps.router.ensure(bot, msg.chatId, msg.reply);
2502
+ if (rt.inflight !== void 0) {
2503
+ await msg.reply.notice("上一条还在处理中,请稍候(或发送 /stop 取消)");
2504
+ return;
2505
+ }
2506
+ rt.inflight = { ack: void 0 };
2507
+ rt.inflight.ack = await msg.ackProcessing().catch(() => void 0) ?? void 0;
2508
+ const message = createUserMessage({
2509
+ content: [{
2510
+ type: "text",
2511
+ text: msg.text
2512
+ }],
2513
+ source: { kind: "user" }
2514
+ });
2515
+ try {
2516
+ rt.agent.followup(message);
2517
+ } catch (error) {
2518
+ const ack = rt.inflight.ack;
2519
+ rt.inflight = void 0;
2520
+ await ack?.();
2521
+ throw error;
2522
+ }
2523
+ }
2524
+ };
2525
+ //#endregion
2522
2526
  //#region src/channels/ports.ts
2523
2527
  /** 从 bot 记录提取创作期注入(主 Agent 绑定形态)。 */
2524
2528
  function hooksOf(bot) {
@@ -2659,6 +2663,7 @@ var BotRuntime = class {
2659
2663
  this.inbound = new Inbound({
2660
2664
  router: this.router,
2661
2665
  bots: deps.bots,
2666
+ maxErrorDetailChars: deps.maxErrorDetailChars,
2662
2667
  onError: (m) => deps.log.warn(m)
2663
2668
  });
2664
2669
  this.outbound = new Outbound(this.sessions, (m) => deps.log.warn(m), deps.maxErrorDetailChars);
@@ -2993,6 +2998,18 @@ function createApiHandler(deps) {
2993
2998
  //#endregion
2994
2999
  //#region src/bots/register-app.ts
2995
3000
  /** 扫码一键创建飞书应用:lark.registerApp(OAuth 2.0 Device Authorization Grant)的状态机封装。 */
3001
+ /** 扫码创建应用时申请的权限/事件(流式卡片 + 收发消息 + 表情 + 通讯录基础信息)。
3002
+ * 故意不加 as const:readonly 元组不可赋值给 SDK AppAddons 的 mutable string[],
3003
+ * 否则 bots/index.ts 的 lark.registerApp(options) 透传会 typecheck 失败。 */
3004
+ const FEISHU_REGISTER_APP_ADDONS = {
3005
+ scopes: { tenant: [
3006
+ "im:message",
3007
+ "im:message:send_as_bot",
3008
+ "cardkit:card:write",
3009
+ "contact:user.base:readonly"
3010
+ ] },
3011
+ events: { items: { tenant: ["im.message.receive_v1"] } }
3012
+ };
2996
3013
  var RegisterAppService = class {
2997
3014
  deps;
2998
3015
  sessions = /* @__PURE__ */ new Map();
@@ -3013,6 +3030,7 @@ var RegisterAppService = class {
3013
3030
  this.sessions.set(id, entry);
3014
3031
  this.deps.registerApp({
3015
3032
  signal: controller.signal,
3033
+ addons: FEISHU_REGISTER_APP_ADDONS,
3016
3034
  onQRCodeReady: (info) => {
3017
3035
  entry.state = {
3018
3036
  status: "pending",