xabot-cli 1.4.10 → 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.
@@ -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":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAU,MAAM,kBAAkB,CAAC;AAE1D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,mBAAmB,CAAC;AACxD,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAA+E,MAAM,OAAO,CAAC;AAqBxL;;;;;;;GAOG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,KAAK,CAA+B;IAC5C,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAgB;IAC3C,OAAO,CAAC,iBAAiB,CAA6B;IAEtD,uCAAuC;IACvC,OAAO,CAAC,QAAQ,CAAC,kBAAkB,CAA6C;IAChF,wCAAwC;IACxC,OAAO,CAAC,QAAQ,CAAC,gBAAgB,CAA8D;IAE/F,uEAAuE;IACvE,OAAO,CAAC,OAAO,CAA6B;IAE5C,yEAAyE;IACzE,OAAO,CAAC,aAAa,CAA0B;IAE/C,wDAAwD;IACxD,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAmC;IAEjE,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,oBAAoB,CAAoC;IAEzE,OAAO,CAAC,SAAS,CAAyB;IAC1C,OAAO,CAAC,MAAM,CAAS;IACvB,OAAO,CAAC,UAAU,CAA8B;IAEhD,qDAAqD;IACrD,OAAO,CAAC,WAAW,CAAS;IAE5B,sFAAsF;IACtF,OAAO,CAAC,gBAAgB,CAAgF;IAExG,OAAO,CAAC,OAAO,CAAU;gBAEb,SAAS,EAAE,cAAc,EAAE,OAAO,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,cAAc,CAAC;QAAC,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE;IAa9F,0FAA0F;IAC1F,YAAY,CAAC,KAAK,EAAE,cAAc,GAAG,IAAI;IAQzC,iEAAiE;IACjE,UAAU,CAAC,OAAO,EAAE,YAAY,GAAG,IAAI;IAgBvC,6EAA6E;IAC7E,mBAAmB,CAAC,OAAO,EAAE;QAAE,eAAe,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI;IAInG,mDAAmD;IACnD,OAAO,CAAC,SAAS;IAIjB,gDAAgD;IAChD,OAAO,CAAC,WAAW;IASnB,0CAA0C;IAC1C,OAAO,CAAC,iBAAiB;IAQzB,+CAA+C;IAC/C,OAAO,CAAC,mBAAmB;IAa3B,yCAAyC;IACzC,OAAO,CAAC,qBAAqB;IAgB7B,yDAAyD;IACzD,OAAO,CAAC,0BAA0B;IAUlC,iEAAiE;IACjE,OAAO,CAAC,eAAe;IAOvB,wEAAwE;IACxE,OAAO,CAAC,uBAAuB;IAkD/B,8DAA8D;IAC9D,OAAO,CAAC,aAAa;IASrB,iDAAiD;IACjD,OAAO,CAAC,kBAAkB;IAI1B,4DAA4D;IAC5D,OAAO,CAAC,YAAY;IAKpB,gDAAgD;IAChD,OAAO,CAAC,cAAc;IAStB,gGAAgG;IAChG,OAAO,CAAC,QAAQ,CAAC,cAAc,CAK1B;YAES,0BAA0B;YAe1B,iCAAiC;YAajC,WAAW;IAOzB,uDAAuD;YACzC,gBAAgB;IAiB9B,0FAA0F;IACpF,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAalE,sFAAsF;IAChF,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAwOxF,kDAAkD;YACpC,eAAe;IAU7B,6DAA6D;IAC7D,cAAc,CAAC,SAAS,EAAE,MAAM,EAAE,QAAQ,EAAE,aAAa,GAAG,IAAI;IAqBhE,8DAA8D;IACxD,GAAG,IAAI,OAAO,CAAC,IAAI,CAAC;YAUZ,IAAI;IAwLlB,+EAA+E;IAC/E,eAAe,IAAI,IAAI;IAQjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAuC7B"}
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';
@@ -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,24 +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
+ return genericResponse("action", { requestId: item.requestId, type: 'approve' });
156
157
  if (input === 'c')
157
- return { kind: 'action', requestId: item.requestId, type: 'reject', reason: '用户取消执行' };
158
- return { kind: 'action', requestId: item.requestId, type: 'reject', reason: text.trim() };
158
+ return genericResponse("action", { requestId: item.requestId, type: 'reject', reason: '用户取消执行' });
159
+ return genericResponse("action", { requestId: item.requestId, type: 'reject', reason: text.trim() });
159
160
  }
160
161
  case 'question': {
161
162
  const payload = item.eventPayload;
162
163
  if (input === 'c')
163
- return { kind: 'question', requestId: item.requestId, type: 'skip', reason: '用户取消执行' };
164
+ return genericResponse("question", { requestId: item.requestId, type: 'skip', reason: '用户取消执行' });
164
165
  if (payload.options.length > 0) {
165
166
  const num = parseInt(input, 10);
166
167
  if (!isNaN(num) && num >= 1 && num <= payload.options.length) {
167
- 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] });
168
169
  }
169
170
  }
170
- return { kind: 'question', requestId: item.requestId, type: 'answer', content: text.trim() };
171
+ return genericResponse("question", { requestId: item.requestId, type: 'answer', content: text.trim() });
171
172
  }
172
173
  case 'sensitive_info_operation': {
173
174
  const siPayload = item.eventPayload;
@@ -175,7 +176,7 @@ export class Bridge {
175
176
  const results = siPayload.operation.items.map((itm) => siPayload.operation.type === 'collect'
176
177
  ? { type: 'collect_skipped', key: itm.key, reason: '用户取消执行' }
177
178
  : { type: 'delete_rejected', id: itm.id ?? '', reason: '用户取消执行' });
178
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
179
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
179
180
  }
180
181
  const lines = text.trim().split('\n');
181
182
  const items = siPayload.operation.items;
@@ -186,10 +187,10 @@ export class Bridge {
186
187
  ? { type: 'provided', key: itm.key, value }
187
188
  : { type: 'collect_skipped', key: itm.key, reason: '未提供值' };
188
189
  });
189
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
190
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
190
191
  }
191
192
  const results = items.map((itm) => ({ type: 'deleted', id: itm.id ?? '' }));
192
- return { kind: 'sensitive_info_operation', requestId: item.requestId, results };
193
+ return genericResponse("sensitive_info_operation", { requestId: item.requestId, results });
193
194
  }
194
195
  }
195
196
  }
@@ -283,45 +284,102 @@ export class Bridge {
283
284
  }
284
285
  }
285
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
+ }
286
327
  /** Handle Command from downstream Agent (forwarded via XabotSessionHandler.onCommand). */
287
328
  async handleCommand(command) {
288
329
  if (!this.cloud)
289
- return { kind: 'acknowledge' };
290
- 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) {
291
334
  const chatId = this.sessionChatId;
292
335
  if (!chatId)
293
- return { kind: 'acknowledge' };
294
- for (const part of command.message.content) {
336
+ return acknowledge();
337
+ const args = command.generic.arguments;
338
+ for (const part of args.content) {
295
339
  await this._sendContentPart(chatId, '', '', part);
296
340
  }
297
- 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
+ }
298
354
  }
299
- return { kind: 'acknowledge' };
355
+ return acknowledge();
300
356
  }
301
357
  /** Handle Event from downstream Agent (forwarded via XabotSessionHandler.onEvent). */
302
358
  async handleEvent(activityId, event) {
303
359
  if (!this.cloud)
304
- return { kind: 'acknowledge' };
360
+ return acknowledge();
305
361
  const target = this.activityToTarget.get(activityId);
306
362
  if (!target)
307
- return { kind: 'acknowledge' };
363
+ return acknowledge();
308
364
  const { chatId } = target;
365
+ const eventName = event.event.name;
366
+ const data = event.event.data;
309
367
  // Non-think events end the thinking phase
310
- if (event.event.type !== 'think') {
368
+ if (eventName !== 'think') {
311
369
  const state = this.activityStates.get(activityId);
312
370
  if (state?.thinkingStart) {
313
371
  await this.endThinking(chatId, activityId);
314
372
  }
315
373
  }
316
374
  // Non-content_delta events clear expressing phase
317
- if (event.event.type !== 'content_delta') {
375
+ if (eventName !== 'content_delta') {
318
376
  const state = this.activityStates.get(activityId);
319
377
  if (state?.expressingStart !== undefined) {
320
378
  delete state.expressingStart;
321
379
  }
322
380
  }
323
381
  // Handle typing indicator: refresh for non-complete, release for complete
324
- if (event.event.type === 'complete') {
382
+ if (eventName === 'complete') {
325
383
  const state = this.activityStates.get(activityId);
326
384
  if (state?.processingMessageId !== undefined) {
327
385
  await this.cloud.releaseTypingIndicator(chatId, target.senderId, state.processingMessageId);
@@ -336,10 +394,10 @@ export class Bridge {
336
394
  log.debug('refreshTypingIndicator failed: %s', err);
337
395
  }
338
396
  }
339
- switch (event.event.type) {
397
+ switch (eventName) {
340
398
  case 'think': {
341
399
  if (!chatId)
342
- return { kind: 'acknowledge' };
400
+ return acknowledge();
343
401
  let state = this.activityStates.get(activityId);
344
402
  if (!state) {
345
403
  state = {};
@@ -356,14 +414,14 @@ export class Bridge {
356
414
  }
357
415
  }
358
416
  }
359
- return { kind: 'acknowledge' };
417
+ return acknowledge();
360
418
  }
361
419
  case 'content_delta': {
362
420
  if (!chatId)
363
- return { kind: 'acknowledge' };
421
+ return acknowledge();
364
422
  // content_delta is only emitted in streaming mode — forward only on streaming platforms
365
423
  if (this.cloud.streamCapability() === StreamCapability.NonStreaming) {
366
- return { kind: 'acknowledge' };
424
+ return acknowledge();
367
425
  }
368
426
  let state = this.activityStates.get(activityId);
369
427
  if (!state) {
@@ -379,131 +437,63 @@ export class Bridge {
379
437
  log.debug('expressing indicator send failed: %s', err);
380
438
  }
381
439
  }
382
- const payload = event.event.payload;
440
+ const payload = data.payload;
383
441
  await this._sendContentPart(chatId, target.senderId, activityId, payload);
384
- return { kind: 'acknowledge' };
442
+ return acknowledge();
385
443
  }
386
444
  case 'content_part': {
387
445
  if (!chatId)
388
- return { kind: 'acknowledge' };
446
+ return acknowledge();
389
447
  // content_part is emitted in non-streaming mode — forward only if verbose
390
448
  if (this.verbose) {
391
- const payload = event.event.payload;
449
+ const payload = data.payload;
392
450
  await this._sendContentPart(chatId, target.senderId, activityId, payload);
393
451
  }
394
- return { kind: 'acknowledge' };
452
+ return acknowledge();
395
453
  }
396
454
  case 'tool_result': {
397
455
  if (!chatId)
398
- return { kind: 'acknowledge' };
399
- const payload = event.event;
400
- if (payload.toolName === 'send_file') {
401
- for (const part of payload.parts) {
456
+ return acknowledge();
457
+ if (data.toolName === 'send_file') {
458
+ for (const part of data.parts) {
402
459
  await this._sendContentPart(chatId, target.senderId, activityId, part);
403
460
  }
404
461
  }
405
- return { kind: 'acknowledge' };
462
+ return acknowledge();
406
463
  }
407
464
  case 'complete': {
408
- const payload = event.event;
409
- for (const part of payload.assistantReply) {
465
+ for (const part of data.assistantReply) {
410
466
  await this._sendContentPart(chatId, target.senderId, activityId, part);
411
467
  }
412
- return { kind: 'acknowledge' };
468
+ return acknowledge();
413
469
  }
414
470
  case 'notify': {
415
471
  if (!chatId)
416
- return { kind: 'acknowledge' };
417
- await this.cloud.send(chatId, { type: 'text', text: event.event.message });
418
- return { kind: 'acknowledge' };
419
- }
420
- case 'action_request': {
421
- if (!chatId)
422
- return { kind: 'acknowledge' };
423
- const key = this.targetKey(chatId, target.senderId);
424
- const pq = this.ensureQueue(key);
425
- const item = this.createPendingItem(chatId, target.senderId, 'action_request', event.event);
426
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
427
- if (!pq.active) {
428
- pq.active = item;
429
- try {
430
- await this.cloud.send(chatId, { type: 'text', text: this.formatActionMessage(event.event) });
431
- }
432
- catch {
433
- pq.active = null;
434
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward action_request to cloud' });
435
- }
436
- }
437
- else {
438
- pq.queue.push(item);
439
- }
440
- return pendingPromise;
441
- }
442
- case 'question': {
443
- if (!chatId)
444
- return { kind: 'acknowledge' };
445
- const key = this.targetKey(chatId, target.senderId);
446
- const pq = this.ensureQueue(key);
447
- const item = this.createPendingItem(chatId, target.senderId, 'question', event.event);
448
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
449
- if (!pq.active) {
450
- pq.active = item;
451
- try {
452
- await this.cloud.send(chatId, { type: 'text', text: this.formatQuestionMessage(event.event) });
453
- }
454
- catch {
455
- pq.active = null;
456
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward question to cloud' });
457
- }
458
- }
459
- else {
460
- pq.queue.push(item);
461
- }
462
- return pendingPromise;
463
- }
464
- case 'sensitive_info_operation': {
465
- if (!chatId)
466
- return { kind: 'acknowledge' };
467
- const key = this.targetKey(chatId, target.senderId);
468
- const pq = this.ensureQueue(key);
469
- const item = this.createPendingItem(chatId, target.senderId, 'sensitive_info_operation', event.event);
470
- const pendingPromise = new Promise((resolve) => { item.resolve = resolve; });
471
- if (!pq.active) {
472
- pq.active = item;
473
- try {
474
- await this.cloud.send(chatId, { type: 'text', text: this.formatSensitiveInfoMessage(event.event) });
475
- }
476
- catch {
477
- pq.active = null;
478
- item.resolve({ kind: 'error', code: 'send_failed', message: 'failed to forward sensitive_info_operation to cloud' });
479
- }
480
- }
481
- else {
482
- pq.queue.push(item);
483
- }
484
- return pendingPromise;
472
+ return acknowledge();
473
+ await this.cloud.send(chatId, { type: 'text', text: data.message });
474
+ return acknowledge();
485
475
  }
486
476
  case 'info': {
487
477
  if (!chatId)
488
- return { kind: 'acknowledge' };
489
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️', event.event) });
490
- return { kind: 'acknowledge' };
478
+ return acknowledge();
479
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️', data) });
480
+ return acknowledge();
491
481
  }
492
482
  case 'warn': {
493
483
  if (!chatId)
494
- return { kind: 'acknowledge' };
495
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️', event.event) });
496
- return { kind: 'acknowledge' };
484
+ return acknowledge();
485
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️', data) });
486
+ return acknowledge();
497
487
  }
498
488
  case 'error': {
499
489
  if (!chatId)
500
- return { kind: 'acknowledge' };
501
- await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌', event.event) });
502
- return { kind: 'acknowledge' };
490
+ return acknowledge();
491
+ await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌', data) });
492
+ return acknowledge();
503
493
  }
504
494
  case 'tool_use': {
505
495
  if (!chatId)
506
- return { kind: 'acknowledge' };
496
+ return acknowledge();
507
497
  let state = this.activityStates.get(activityId);
508
498
  if (!state) {
509
499
  state = {};
@@ -520,7 +510,7 @@ export class Bridge {
520
510
  }
521
511
  }
522
512
  }
523
- return { kind: 'acknowledge' };
513
+ return acknowledge();
524
514
  }
525
515
  case 'pair_complete': {
526
516
  if (this.verbose) {
@@ -530,10 +520,17 @@ export class Bridge {
530
520
  // Elapsed time available for future use: (Date.now() - start) / 1000
531
521
  }
532
522
  }
533
- return { kind: 'acknowledge' };
534
- }
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();
535
532
  default: {
536
- return { kind: 'acknowledge' };
533
+ return acknowledge();
537
534
  }
538
535
  }
539
536
  }
@@ -565,7 +562,7 @@ export class Bridge {
565
562
  pq.active = next;
566
563
  this.sendNextPending(next).catch(() => {
567
564
  pq.active = null;
568
- 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'));
569
566
  });
570
567
  }
571
568
  else {
@@ -613,14 +610,6 @@ export class Bridge {
613
610
  const { chatId, senderId } = msg;
614
611
  // ── Text messages: parse and dispatch by kind ─────────────────────
615
612
  if (msg.content.type === 'text' && msg.fallback) {
616
- const mediaKey = this.targetKey(chatId, senderId);
617
- let buffered = this.pendingMediaByTarget.get(mediaKey);
618
- if (!buffered) {
619
- buffered = [];
620
- this.pendingMediaByTarget.set(mediaKey, buffered);
621
- }
622
- buffered.push({ ...msg.content });
623
- log.debug('← cloud recv: fallback (chatId=%s, buffered=%d)', chatId, buffered.length);
624
613
  continue;
625
614
  }
626
615
  if (msg.content.type === 'text') {
@@ -628,30 +617,29 @@ export class Bridge {
628
617
  switch (parsed.kind) {
629
618
  case 'new': {
630
619
  this.unbindActivity(chatId, senderId);
631
- const createResponse = await this.session.requestCommand({
632
- new_activity: { title: '' },
633
- });
634
- if (createResponse.kind === 'activity_ready') {
635
- const newActivityId = createResponse.activity;
636
- this.bindActivity(chatId, senderId, newActivityId);
637
- if (parsed.prompt) {
638
- await this.session.requestCommand({
639
- invoke_activity: {
640
- activity: newActivityId,
641
- messages: [{ type: 'text', text: parsed.prompt }],
642
- },
643
- });
644
- 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);
645
630
  }
646
631
  }
632
+ else {
633
+ await this.session.requestCommand(genericCommand("new_activity", { title: '' }));
634
+ }
647
635
  continue;
648
636
  }
649
637
  case 'compact': {
650
638
  let activityId = this.getActivityForUser(chatId, senderId);
651
639
  if (!activityId) {
652
- const lastResponse = await this.session.requestCommand('last_activity');
653
- if (lastResponse.kind === 'activity_ready') {
654
- 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;
655
643
  this.bindActivity(chatId, senderId, activityId);
656
644
  }
657
645
  else {
@@ -659,17 +647,15 @@ export class Bridge {
659
647
  continue;
660
648
  }
661
649
  }
662
- await this.session.requestCommand({
663
- compact_activity: { activity: activityId },
664
- });
650
+ await this.session.requestCommand(genericCommand("compact_activity", { activity: activityId }));
665
651
  continue;
666
652
  }
667
653
  case 'cancel': {
668
654
  let activityId = this.getActivityForUser(chatId, senderId);
669
655
  if (!activityId) {
670
- const lastResponse = await this.session.requestCommand('last_activity');
671
- if (lastResponse.kind === 'activity_ready') {
672
- 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;
673
659
  this.bindActivity(chatId, senderId, activityId);
674
660
  }
675
661
  else {
@@ -677,9 +663,7 @@ export class Bridge {
677
663
  continue;
678
664
  }
679
665
  }
680
- await this.session.requestCommand({
681
- cancel_activity: { activity: activityId },
682
- });
666
+ await this.session.requestCommand(genericCommand("cancel_activity", { activity: activityId }));
683
667
  continue;
684
668
  }
685
669
  case 'unknown_command': {
@@ -701,7 +685,7 @@ export class Bridge {
701
685
  if (parsed.text.trim().toLowerCase() === 'c') {
702
686
  const actId = this.getActivityForUser(chatId, senderId);
703
687
  if (actId) {
704
- await this.session.requestCommand({ cancel_activity: { activity: actId } });
688
+ await this.session.requestCommand(genericCommand("cancel_activity", { activity: actId }));
705
689
  await this.cloud.send(chatId, { type: 'text', text: '✅ 已终止当前任务,可下达新的指令' });
706
690
  }
707
691
  }
@@ -714,16 +698,14 @@ export class Bridge {
714
698
  // ── Original invoke logic ──
715
699
  let activityId = this.getActivityForUser(chatId, senderId);
716
700
  if (!activityId) {
717
- const lastResponse = await this.session.requestCommand('last_activity');
718
- if (lastResponse.kind === 'activity_ready') {
719
- 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;
720
704
  }
721
705
  else {
722
- const createResponse = await this.session.requestCommand({
723
- new_activity: { title: '' },
724
- });
725
- if (createResponse.kind === 'activity_ready') {
726
- 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;
727
709
  }
728
710
  else {
729
711
  continue;
@@ -736,12 +718,10 @@ export class Bridge {
736
718
  if (bufferedMedia.length > 0) {
737
719
  this.pendingMediaByTarget.delete(invokeKey);
738
720
  }
739
- await this.session.requestCommand({
740
- invoke_activity: {
741
- activity: activityId,
742
- messages: [...bufferedMedia, { type: 'text', text: parsed.text }],
743
- },
744
- });
721
+ await this.session.requestCommand(genericCommand("invoke_activity", {
722
+ activity: activityId,
723
+ messages: [...bufferedMedia, { type: 'text', text: parsed.text }],
724
+ }));
745
725
  await this.setTypingIndicatorIfNeeded(chatId, senderId, activityId, msg.id);
746
726
  continue;
747
727
  }
@@ -784,10 +764,10 @@ export class Bridge {
784
764
  this.runPromise = null;
785
765
  for (const [, pq] of this.pendingQueues) {
786
766
  if (pq.active) {
787
- pq.active.resolve({ kind: 'error', code: 'cancelled', message: 'Bridge closing' });
767
+ pq.active.resolve(errorResponse('cancelled', 'Bridge closing'));
788
768
  }
789
769
  for (const item of pq.queue) {
790
- item.resolve({ kind: 'error', code: 'cancelled', message: 'Bridge closing' });
770
+ item.resolve(errorResponse('cancelled', 'Bridge closing'));
791
771
  }
792
772
  }
793
773
  this.pendingQueues.clear();