xabot-cli 1.4.8 → 1.5.1

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.
Files changed (35) hide show
  1. package/dist/bridge/index.d.ts +2 -0
  2. package/dist/bridge/index.d.ts.map +1 -1
  3. package/dist/bridge/index.js +158 -182
  4. package/dist/bridge/index.js.map +1 -1
  5. package/dist/cli/chat.d.ts +2 -0
  6. package/dist/cli/chat.d.ts.map +1 -1
  7. package/dist/cli/chat.js +8 -3
  8. package/dist/cli/chat.js.map +1 -1
  9. package/dist/cli/feishu.d.ts.map +1 -1
  10. package/dist/cli/feishu.js +10 -1
  11. package/dist/cli/feishu.js.map +1 -1
  12. package/dist/cli/wechat.d.ts.map +1 -1
  13. package/dist/cli/wechat.js +6 -1
  14. package/dist/cli/wechat.js.map +1 -1
  15. package/dist/core/fs-utils.d.ts.map +1 -1
  16. package/dist/core/fs-utils.js +13 -3
  17. package/dist/core/fs-utils.js.map +1 -1
  18. package/dist/platforms/feishu/client.d.ts.map +1 -1
  19. package/dist/platforms/feishu/client.js +56 -61
  20. package/dist/platforms/feishu/client.js.map +1 -1
  21. package/dist/platforms/wechat/client.d.ts.map +1 -1
  22. package/dist/platforms/wechat/client.js +8 -0
  23. package/dist/platforms/wechat/client.js.map +1 -1
  24. package/dist/xacpp/capabilities.d.ts +8 -0
  25. package/dist/xacpp/capabilities.d.ts.map +1 -0
  26. package/dist/xacpp/capabilities.js +36 -0
  27. package/dist/xacpp/capabilities.js.map +1 -0
  28. package/dist/xacpp/initiator-session-handler.d.ts +1 -2
  29. package/dist/xacpp/initiator-session-handler.d.ts.map +1 -1
  30. package/dist/xacpp/initiator-session-handler.js +41 -37
  31. package/dist/xacpp/initiator-session-handler.js.map +1 -1
  32. package/dist/xacpp/session-handler.d.ts.map +1 -1
  33. package/dist/xacpp/session-handler.js +3 -2
  34. package/dist/xacpp/session-handler.js.map +1 -1
  35. package/package.json +2 -2
@@ -77,6 +77,8 @@ export declare class Bridge {
77
77
  private endThinking;
78
78
  /** Send a single ContentPart to the cloud platform. */
79
79
  private _sendContentPart;
80
+ /** Route interaction command to pending queue. Shared by handleCommand for action_request/question/sensitive_info_operation. */
81
+ private _handleInteractionCommand;
80
82
  /** Handle Command from downstream Agent (forwarded via XabotSessionHandler.onCommand). */
81
83
  handleCommand(command: XacppCommand): Promise<XacppResponse>;
82
84
  /** Handle Event from downstream Agent (forwarded via XabotSessionHandler.onEvent). */
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,5 @@
1
1
  import { StreamCapability } from '../core/types.js';
2
+ import { acknowledge, genericResponse, errorResponse, genericCommand, commandName } from 'xacpp';
2
3
  import { parseInput } from './input-parser.js';
3
4
  import { i18nResource } from '../i18n/index.js';
4
5
  import { createLogger } from '../core/logger.js';
@@ -105,8 +106,8 @@ export class Bridge {
105
106
  payload.arguments ? `参数:${payload.arguments}` : '',
106
107
  '───────────────',
107
108
  'a: 始终允许 | y: 单次允许',
108
- 'n [原因]: 本次拒绝(可附带拒绝原因)',
109
109
  'c: 取消执行',
110
+ '直接输入文本即拒绝(文本将作为拒绝原因)',
110
111
  ].filter(Boolean).join('\n');
111
112
  }
112
113
  /** Format question for cloud display. */
@@ -137,9 +138,9 @@ export class Bridge {
137
138
  return lines.join('\n');
138
139
  }
139
140
  /** Format TraceableEvent (info/warn/error) for cloud display. */
140
- formatTraceable(icon, event) {
141
- const title = i18nResource(event.title?.trim() || '');
142
- const content = i18nResource(event.content?.trim() || '');
141
+ formatTraceable(icon, data) {
142
+ const title = i18nResource(data.title?.trim() || '');
143
+ const content = i18nResource(data.content?.trim() || '');
143
144
  if (title && content)
144
145
  return `${icon} ${title}\n${content}`;
145
146
  return `${icon} ${title || content}`;
@@ -150,28 +151,24 @@ export class Bridge {
150
151
  switch (item.type) {
151
152
  case 'action_request': {
152
153
  if (input === 'a')
153
- return { kind: 'action', requestId: item.requestId, type: 'approve_always' };
154
+ return genericResponse("action", { requestId: item.requestId, type: 'approve_always' });
154
155
  if (input === 'y')
155
- return { kind: 'action', requestId: item.requestId, type: 'approve' };
156
- if (input === 'n' || input.startsWith('n ')) {
157
- const reason = text.trim().slice(1).trim() || '用户拒绝';
158
- return { kind: 'action', requestId: item.requestId, type: 'reject', reason };
159
- }
156
+ return genericResponse("action", { requestId: item.requestId, type: 'approve' });
160
157
  if (input === 'c')
161
- return { kind: 'action', requestId: item.requestId, type: 'reject', reason: '用户取消执行' };
162
- return null;
158
+ return genericResponse("action", { requestId: item.requestId, type: 'reject', reason: '用户取消执行' });
159
+ return genericResponse("action", { requestId: item.requestId, type: 'reject', reason: text.trim() });
163
160
  }
164
161
  case 'question': {
165
162
  const payload = item.eventPayload;
166
163
  if (input === 'c')
167
- return { kind: 'question', requestId: item.requestId, type: 'skip', reason: '用户取消执行' };
164
+ return genericResponse("question", { requestId: item.requestId, type: 'skip', reason: '用户取消执行' });
168
165
  if (payload.options.length > 0) {
169
166
  const num = parseInt(input, 10);
170
167
  if (!isNaN(num) && num >= 1 && num <= payload.options.length) {
171
- return { kind: 'question', requestId: item.requestId, type: 'answer', content: payload.options[num - 1] };
168
+ return genericResponse("question", { requestId: item.requestId, type: 'answer', content: payload.options[num - 1] });
172
169
  }
173
170
  }
174
- return { kind: 'question', requestId: item.requestId, type: 'answer', content: text.trim() };
171
+ return genericResponse("question", { requestId: item.requestId, type: 'answer', content: text.trim() });
175
172
  }
176
173
  case 'sensitive_info_operation': {
177
174
  const siPayload = item.eventPayload;
@@ -179,7 +176,7 @@ export class Bridge {
179
176
  const results = siPayload.operation.items.map((itm) => siPayload.operation.type === 'collect'
180
177
  ? { type: 'collect_skipped', key: itm.key, reason: '用户取消执行' }
181
178
  : { type: 'delete_rejected', id: itm.id ?? '', reason: '用户取消执行' });
182
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
179
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
183
180
  }
184
181
  const lines = text.trim().split('\n');
185
182
  const items = siPayload.operation.items;
@@ -190,10 +187,10 @@ export class Bridge {
190
187
  ? { type: 'provided', key: itm.key, value }
191
188
  : { type: 'collect_skipped', key: itm.key, reason: '未提供值' };
192
189
  });
193
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
190
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
194
191
  }
195
192
  const results = items.map((itm) => ({ type: 'deleted', id: itm.id ?? '' }));
196
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
193
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
197
194
  }
198
195
  }
199
196
  }
@@ -287,45 +284,102 @@ export class Bridge {
287
284
  }
288
285
  }
289
286
  }
287
+ /** Route interaction command to pending queue. Shared by handleCommand for action_request/question/sensitive_info_operation. */
288
+ async _handleInteractionCommand(type, payload) {
289
+ if (!this.cloud)
290
+ return acknowledge();
291
+ // Look up target from activity
292
+ const target = this.activityToTarget.get(payload.activity);
293
+ if (!target)
294
+ return acknowledge();
295
+ const { chatId, senderId } = target;
296
+ const key = this.targetKey(chatId, senderId);
297
+ const pq = this.ensureQueue(key);
298
+ const item = this.createPendingItem(chatId, senderId, type, payload);
299
+ const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
300
+ if (!pq.active) {
301
+ pq.active = item;
302
+ try {
303
+ let message;
304
+ switch (type) {
305
+ case 'action_request':
306
+ message = this.formatActionMessage(payload);
307
+ break;
308
+ case 'question':
309
+ message = this.formatQuestionMessage(payload);
310
+ break;
311
+ case 'sensitive_info_operation':
312
+ message = this.formatSensitiveInfoMessage(payload);
313
+ break;
314
+ }
315
+ await this.cloud.send(chatId, { type: 'text', text: message });
316
+ }
317
+ catch {
318
+ pq.active = null;
319
+ item.resolve(errorResponse('send_failed', `failed to forward ${type} to cloud`));
320
+ }
321
+ }
322
+ else {
323
+ pq.queue.push(item);
324
+ }
325
+ return pendingPromise;
326
+ }
290
327
  /** Handle Command from downstream Agent (forwarded via XabotSessionHandler.onCommand). */
291
328
  async handleCommand(command) {
292
329
  if (!this.cloud)
293
- return { kind: 'acknowledge' };
294
- if (typeof command === 'object' && 'message' in command) {
330
+ return acknowledge();
331
+ const name = commandName(command);
332
+ // Message command: agent sends content directly to the session's chatId
333
+ if (name === 'message' && typeof command === 'object' && 'generic' in command) {
295
334
  const chatId = this.sessionChatId;
296
335
  if (!chatId)
297
- return { kind: 'acknowledge' };
298
- for (const part of command.message.content) {
336
+ return acknowledge();
337
+ const args = command.generic.arguments;
338
+ for (const part of args.content) {
299
339
  await this._sendContentPart(chatId, '', '', part);
300
340
  }
301
- return { kind: 'acknowledge' };
341
+ return acknowledge();
342
+ }
343
+ // Interaction commands (moved from Event to Command in xacpp 0.7.x)
344
+ if (typeof command === 'object' && 'generic' in command) {
345
+ const args = command.generic.arguments;
346
+ switch (name) {
347
+ case 'action_request':
348
+ return this._handleInteractionCommand('action_request', args);
349
+ case 'question':
350
+ return this._handleInteractionCommand('question', args);
351
+ case 'sensitive_info_operation':
352
+ return this._handleInteractionCommand('sensitive_info_operation', args);
353
+ }
302
354
  }
303
- return { kind: 'acknowledge' };
355
+ return acknowledge();
304
356
  }
305
357
  /** Handle Event from downstream Agent (forwarded via XabotSessionHandler.onEvent). */
306
358
  async handleEvent(activityId, event) {
307
359
  if (!this.cloud)
308
- return { kind: 'acknowledge' };
360
+ return acknowledge();
309
361
  const target = this.activityToTarget.get(activityId);
310
362
  if (!target)
311
- return { kind: 'acknowledge' };
363
+ return acknowledge();
312
364
  const { chatId } = target;
365
+ const eventName = event.event.name;
366
+ const data = event.event.data;
313
367
  // Non-think events end the thinking phase
314
- if (event.event.type !== 'think') {
368
+ if (eventName !== 'think') {
315
369
  const state = this.activityStates.get(activityId);
316
370
  if (state?.thinkingStart) {
317
371
  await this.endThinking(chatId, activityId);
318
372
  }
319
373
  }
320
374
  // Non-content_delta events clear expressing phase
321
- if (event.event.type !== 'content_delta') {
375
+ if (eventName !== 'content_delta') {
322
376
  const state = this.activityStates.get(activityId);
323
377
  if (state?.expressingStart !== undefined) {
324
378
  delete state.expressingStart;
325
379
  }
326
380
  }
327
381
  // Handle typing indicator: refresh for non-complete, release for complete
328
- if (event.event.type === 'complete') {
382
+ if (eventName === 'complete') {
329
383
  const state = this.activityStates.get(activityId);
330
384
  if (state?.processingMessageId !== undefined) {
331
385
  await this.cloud.releaseTypingIndicator(chatId, target.senderId, state.processingMessageId);
@@ -340,10 +394,10 @@ export class Bridge {
340
394
  log.debug('refreshTypingIndicator failed: %s', err);
341
395
  }
342
396
  }
343
- switch (event.event.type) {
397
+ switch (eventName) {
344
398
  case 'think': {
345
399
  if (!chatId)
346
- return { kind: 'acknowledge' };
400
+ return acknowledge();
347
401
  let state = this.activityStates.get(activityId);
348
402
  if (!state) {
349
403
  state = {};
@@ -360,14 +414,14 @@ export class Bridge {
360
414
  }
361
415
  }
362
416
  }
363
- return { kind: 'acknowledge' };
417
+ return acknowledge();
364
418
  }
365
419
  case 'content_delta': {
366
420
  if (!chatId)
367
- return { kind: 'acknowledge' };
421
+ return acknowledge();
368
422
  // content_delta is only emitted in streaming mode — forward only on streaming platforms
369
423
  if (this.cloud.streamCapability() === StreamCapability.NonStreaming) {
370
- return { kind: 'acknowledge' };
424
+ return acknowledge();
371
425
  }
372
426
  let state = this.activityStates.get(activityId);
373
427
  if (!state) {
@@ -383,131 +437,63 @@ export class Bridge {
383
437
  log.debug('expressing indicator send failed: %s', err);
384
438
  }
385
439
  }
386
- const payload = event.event.payload;
440
+ const payload = data.payload;
387
441
  await this._sendContentPart(chatId, target.senderId, activityId, payload);
388
- return { kind: 'acknowledge' };
442
+ return acknowledge();
389
443
  }
390
444
  case 'content_part': {
391
445
  if (!chatId)
392
- return { kind: 'acknowledge' };
446
+ return acknowledge();
393
447
  // content_part is emitted in non-streaming mode — forward only if verbose
394
448
  if (this.verbose) {
395
- const payload = event.event.payload;
449
+ const payload = data.payload;
396
450
  await this._sendContentPart(chatId, target.senderId, activityId, payload);
397
451
  }
398
- return { kind: 'acknowledge' };
452
+ return acknowledge();
399
453
  }
400
454
  case 'tool_result': {
401
455
  if (!chatId)
402
- return { kind: 'acknowledge' };
403
- const payload = event.event;
404
- if (payload.toolName === 'send_file') {
405
- for (const part of payload.parts) {
456
+ return acknowledge();
457
+ if (data.toolName === 'send_file') {
458
+ for (const part of data.parts) {
406
459
  await this._sendContentPart(chatId, target.senderId, activityId, part);
407
460
  }
408
461
  }
409
- return { kind: 'acknowledge' };
462
+ return acknowledge();
410
463
  }
411
464
  case 'complete': {
412
- const payload = event.event;
413
- for (const part of payload.assistantReply) {
465
+ for (const part of data.assistantReply) {
414
466
  await this._sendContentPart(chatId, target.senderId, activityId, part);
415
467
  }
416
- return { kind: 'acknowledge' };
468
+ return acknowledge();
417
469
  }
418
470
  case 'notify': {
419
471
  if (!chatId)
420
- return { kind: 'acknowledge' };
421
- await this.cloud.send(chatId, { type: 'text', text: event.event.message });
422
- return { kind: 'acknowledge' };
423
- }
424
- case 'action_request': {
425
- if (!chatId)
426
- return { kind: 'acknowledge' };
427
- const key = this.targetKey(chatId, target.senderId);
428
- const pq = this.ensureQueue(key);
429
- const item = this.createPendingItem(chatId, target.senderId, 'action_request', event.event);
430
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
431
- if (!pq.active) {
432
- pq.active = item;
433
- try {
434
- await this.cloud.send(chatId, { type: 'text', text: this.formatActionMessage(event.event) });
435
- }
436
- catch {
437
- pq.active = null;
438
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward action_request to cloud' });
439
- }
440
- }
441
- else {
442
- pq.queue.push(item);
443
- }
444
- return pendingPromise;
445
- }
446
- case 'question': {
447
- if (!chatId)
448
- return { kind: 'acknowledge' };
449
- const key = this.targetKey(chatId, target.senderId);
450
- const pq = this.ensureQueue(key);
451
- const item = this.createPendingItem(chatId, target.senderId, 'question', event.event);
452
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
453
- if (!pq.active) {
454
- pq.active = item;
455
- try {
456
- await this.cloud.send(chatId, { type: 'text', text: this.formatQuestionMessage(event.event) });
457
- }
458
- catch {
459
- pq.active = null;
460
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward question to cloud' });
461
- }
462
- }
463
- else {
464
- pq.queue.push(item);
465
- }
466
- return pendingPromise;
467
- }
468
- case 'sensitive_info_operation': {
469
- if (!chatId)
470
- return { kind: 'acknowledge' };
471
- const key = this.targetKey(chatId, target.senderId);
472
- const pq = this.ensureQueue(key);
473
- const item = this.createPendingItem(chatId, target.senderId, 'sensitive_info_operation', event.event);
474
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
475
- if (!pq.active) {
476
- pq.active = item;
477
- try {
478
- await this.cloud.send(chatId, { type: 'text', text: this.formatSensitiveInfoMessage(event.event) });
479
- }
480
- catch {
481
- pq.active = null;
482
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward sensitive_info_operation to cloud' });
483
- }
484
- }
485
- else {
486
- pq.queue.push(item);
487
- }
488
- return pendingPromise;
472
+ return acknowledge();
473
+ await this.cloud.send(chatId, { type: 'text', text: data.message });
474
+ return acknowledge();
489
475
  }
490
476
  case 'info': {
491
477
  if (!chatId)
492
- return { kind: 'acknowledge' };
493
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️', event.event) });
494
- return { kind: 'acknowledge' };
478
+ return acknowledge();
479
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️', data) });
480
+ return acknowledge();
495
481
  }
496
482
  case 'warn': {
497
483
  if (!chatId)
498
- return { kind: 'acknowledge' };
499
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️', event.event) });
500
- return { kind: 'acknowledge' };
484
+ return acknowledge();
485
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️', data) });
486
+ return acknowledge();
501
487
  }
502
488
  case 'error': {
503
489
  if (!chatId)
504
- return { kind: 'acknowledge' };
505
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌', event.event) });
506
- return { kind: 'acknowledge' };
490
+ return acknowledge();
491
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌', data) });
492
+ return acknowledge();
507
493
  }
508
494
  case 'tool_use': {
509
495
  if (!chatId)
510
- return { kind: 'acknowledge' };
496
+ return acknowledge();
511
497
  let state = this.activityStates.get(activityId);
512
498
  if (!state) {
513
499
  state = {};
@@ -524,7 +510,7 @@ export class Bridge {
524
510
  }
525
511
  }
526
512
  }
527
- return { kind: 'acknowledge' };
513
+ return acknowledge();
528
514
  }
529
515
  case 'pair_complete': {
530
516
  if (this.verbose) {
@@ -534,10 +520,17 @@ export class Bridge {
534
520
  // Elapsed time available for future use: (Date.now() - start) / 1000
535
521
  }
536
522
  }
537
- return { kind: 'acknowledge' };
538
- }
523
+ return acknowledge();
524
+ }
525
+ case 'think_start':
526
+ case 'think_end':
527
+ case 'content_start':
528
+ case 'content_end':
529
+ case 'think_part':
530
+ case 'start':
531
+ return acknowledge();
539
532
  default: {
540
- return { kind: 'acknowledge' };
533
+ return acknowledge();
541
534
  }
542
535
  }
543
536
  }
@@ -569,7 +562,7 @@ export class Bridge {
569
562
  pq.active = next;
570
563
  this.sendNextPending(next).catch(() => {
571
564
  pq.active = null;
572
- next.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward queued event to cloud' });
565
+ next.resolve(errorResponse('send_failed', 'failed to forward queued event to cloud'));
573
566
  });
574
567
  }
575
568
  else {
@@ -617,14 +610,6 @@ export class Bridge {
617
610
  const { chatId, senderId } = msg;
618
611
  // ── Text messages: parse and dispatch by kind ─────────────────────
619
612
  if (msg.content.type === 'text' && msg.fallback) {
620
- const mediaKey = this.targetKey(chatId, senderId);
621
- let buffered = this.pendingMediaByTarget.get(mediaKey);
622
- if (!buffered) {
623
- buffered = [];
624
- this.pendingMediaByTarget.set(mediaKey, buffered);
625
- }
626
- buffered.push({ ...msg.content });
627
- log.debug('← cloud recv: fallback (chatId=%s, buffered=%d)', chatId, buffered.length);
628
613
  continue;
629
614
  }
630
615
  if (msg.content.type === 'text') {
@@ -632,30 +617,29 @@ export class Bridge {
632
617
  switch (parsed.kind) {
633
618
  case 'new': {
634
619
  this.unbindActivity(chatId, senderId);
635
- const createResponse = await this.session.requestCommand({
636
- new_activity: { title: '' },
637
- });
638
- if (createResponse.kind === 'activity_ready') {
639
- const newActivityId = createResponse.activity;
640
- this.bindActivity(chatId, senderId, newActivityId);
641
- if (parsed.prompt) {
642
- await this.session.requestCommand({
643
- invoke_activity: {
644
- activity: newActivityId,
645
- messages: [{ type: 'text', text: parsed.prompt }],
646
- },
647
- });
648
- await this.setTypingIndicatorIfNeeded(chatId, senderId, newActivityId, msg.id);
620
+ if (parsed.prompt) {
621
+ const createResponse = await this.session.requestCommand(genericCommand("new_activity", { title: '' }));
622
+ if (createResponse.kind === 'generic' && createResponse.name === 'activity_ready') {
623
+ const activityId = createResponse.data.activity;
624
+ this.bindActivity(chatId, senderId, activityId);
625
+ await this.session.requestCommand(genericCommand("invoke_activity", {
626
+ activity: activityId,
627
+ messages: [{ type: 'text', text: parsed.prompt }],
628
+ }));
629
+ await this.setTypingIndicatorIfNeeded(chatId, senderId, activityId, msg.id);
649
630
  }
650
631
  }
632
+ else {
633
+ await this.session.requestCommand(genericCommand("new_activity", { title: '' }));
634
+ }
651
635
  continue;
652
636
  }
653
637
  case 'compact': {
654
638
  let activityId = this.getActivityForUser(chatId, senderId);
655
639
  if (!activityId) {
656
- const lastResponse = await this.session.requestCommand('last_activity');
657
- if (lastResponse.kind === 'activity_ready') {
658
- activityId = lastResponse.activity;
640
+ const lastResponse = await this.session.requestCommand(genericCommand("last_activity", {}));
641
+ if (lastResponse.kind === 'generic' && lastResponse.name === 'activity_ready') {
642
+ activityId = lastResponse.data.activity;
659
643
  this.bindActivity(chatId, senderId, activityId);
660
644
  }
661
645
  else {
@@ -663,17 +647,15 @@ export class Bridge {
663
647
  continue;
664
648
  }
665
649
  }
666
- await this.session.requestCommand({
667
- compact_activity: { activity: activityId },
668
- });
650
+ await this.session.requestCommand(genericCommand("compact_activity", { activity: activityId }));
669
651
  continue;
670
652
  }
671
653
  case 'cancel': {
672
654
  let activityId = this.getActivityForUser(chatId, senderId);
673
655
  if (!activityId) {
674
- const lastResponse = await this.session.requestCommand('last_activity');
675
- if (lastResponse.kind === 'activity_ready') {
676
- activityId = lastResponse.activity;
656
+ const lastResponse = await this.session.requestCommand(genericCommand("last_activity", {}));
657
+ if (lastResponse.kind === 'generic' && lastResponse.name === 'activity_ready') {
658
+ activityId = lastResponse.data.activity;
677
659
  this.bindActivity(chatId, senderId, activityId);
678
660
  }
679
661
  else {
@@ -681,9 +663,7 @@ export class Bridge {
681
663
  continue;
682
664
  }
683
665
  }
684
- await this.session.requestCommand({
685
- cancel_activity: { activity: activityId },
686
- });
666
+ await this.session.requestCommand(genericCommand("cancel_activity", { activity: activityId }));
687
667
  continue;
688
668
  }
689
669
  case 'unknown_command': {
@@ -705,7 +685,7 @@ export class Bridge {
705
685
  if (parsed.text.trim().toLowerCase() === 'c') {
706
686
  const actId = this.getActivityForUser(chatId, senderId);
707
687
  if (actId) {
708
- await this.session.requestCommand({ cancel_activity: { activity: actId } });
688
+ await this.session.requestCommand(genericCommand("cancel_activity", { activity: actId }));
709
689
  await this.cloud.send(chatId, { type: 'text', text: '✅ 已终止当前任务,可下达新的指令' });
710
690
  }
711
691
  }
@@ -718,16 +698,14 @@ export class Bridge {
718
698
  // ── Original invoke logic ──
719
699
  let activityId = this.getActivityForUser(chatId, senderId);
720
700
  if (!activityId) {
721
- const lastResponse = await this.session.requestCommand('last_activity');
722
- if (lastResponse.kind === 'activity_ready') {
723
- activityId = lastResponse.activity;
701
+ const lastResponse = await this.session.requestCommand(genericCommand("last_activity", {}));
702
+ if (lastResponse.kind === 'generic' && lastResponse.name === 'activity_ready') {
703
+ activityId = lastResponse.data.activity;
724
704
  }
725
705
  else {
726
- const createResponse = await this.session.requestCommand({
727
- new_activity: { title: '' },
728
- });
729
- if (createResponse.kind === 'activity_ready') {
730
- activityId = createResponse.activity;
706
+ const createResponse = await this.session.requestCommand(genericCommand("new_activity", { title: '' }));
707
+ if (createResponse.kind === 'generic' && createResponse.name === 'activity_ready') {
708
+ activityId = createResponse.data.activity;
731
709
  }
732
710
  else {
733
711
  continue;
@@ -740,12 +718,10 @@ export class Bridge {
740
718
  if (bufferedMedia.length > 0) {
741
719
  this.pendingMediaByTarget.delete(invokeKey);
742
720
  }
743
- await this.session.requestCommand({
744
- invoke_activity: {
745
- activity: activityId,
746
- messages: [...bufferedMedia, { type: 'text', text: parsed.text }],
747
- },
748
- });
721
+ await this.session.requestCommand(genericCommand("invoke_activity", {
722
+ activity: activityId,
723
+ messages: [...bufferedMedia, { type: 'text', text: parsed.text }],
724
+ }));
749
725
  await this.setTypingIndicatorIfNeeded(chatId, senderId, activityId, msg.id);
750
726
  continue;
751
727
  }
@@ -788,10 +764,10 @@ export class Bridge {
788
764
  this.runPromise = null;
789
765
  for (const [, pq] of this.pendingQueues) {
790
766
  if (pq.active) {
791
- pq.active.resolve({ kind: 'error', code: 'cancelled', message: 'Bridge closing' });
767
+ pq.active.resolve(errorResponse('cancelled', 'Bridge closing'));
792
768
  }
793
769
  for (const item of pq.queue) {
794
- item.resolve({ kind: 'error', code: 'cancelled', message: 'Bridge closing' });
770
+ item.resolve(errorResponse('cancelled', 'Bridge closing'));
795
771
  }
796
772
  }
797
773
  this.pendingQueues.clear();