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.
- package/dist/bridge/index.d.ts +2 -0
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +158 -182
- package/dist/bridge/index.js.map +1 -1
- package/dist/cli/chat.d.ts +2 -0
- package/dist/cli/chat.d.ts.map +1 -1
- package/dist/cli/chat.js +8 -3
- package/dist/cli/chat.js.map +1 -1
- package/dist/cli/feishu.d.ts.map +1 -1
- package/dist/cli/feishu.js +10 -1
- package/dist/cli/feishu.js.map +1 -1
- package/dist/cli/wechat.d.ts.map +1 -1
- package/dist/cli/wechat.js +6 -1
- package/dist/cli/wechat.js.map +1 -1
- package/dist/core/fs-utils.d.ts.map +1 -1
- package/dist/core/fs-utils.js +13 -3
- package/dist/core/fs-utils.js.map +1 -1
- package/dist/platforms/feishu/client.d.ts.map +1 -1
- package/dist/platforms/feishu/client.js +56 -61
- package/dist/platforms/feishu/client.js.map +1 -1
- package/dist/platforms/wechat/client.d.ts.map +1 -1
- package/dist/platforms/wechat/client.js +8 -0
- package/dist/platforms/wechat/client.js.map +1 -1
- package/dist/xacpp/capabilities.d.ts +8 -0
- package/dist/xacpp/capabilities.d.ts.map +1 -0
- package/dist/xacpp/capabilities.js +36 -0
- package/dist/xacpp/capabilities.js.map +1 -0
- package/dist/xacpp/initiator-session-handler.d.ts +1 -2
- package/dist/xacpp/initiator-session-handler.d.ts.map +1 -1
- package/dist/xacpp/initiator-session-handler.js +41 -37
- package/dist/xacpp/initiator-session-handler.js.map +1 -1
- package/dist/xacpp/session-handler.d.ts.map +1 -1
- package/dist/xacpp/session-handler.js +3 -2
- package/dist/xacpp/session-handler.js.map +1 -1
- package/package.json +2 -2
package/dist/bridge/index.d.ts
CHANGED
|
@@ -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,
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bridge/index.ts"],"names":[],"mappings":"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"}
|
package/dist/bridge/index.js
CHANGED
|
@@ -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,
|
|
141
|
-
const title = i18nResource(
|
|
142
|
-
const content = i18nResource(
|
|
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
|
|
154
|
+
return genericResponse("action", { requestId: item.requestId, type: 'approve_always' });
|
|
154
155
|
if (input === 'y')
|
|
155
|
-
return
|
|
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
|
|
162
|
-
return
|
|
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
|
|
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
|
|
168
|
+
return genericResponse("question", { requestId: item.requestId, type: 'answer', content: payload.options[num - 1] });
|
|
172
169
|
}
|
|
173
170
|
}
|
|
174
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
294
|
-
|
|
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
|
|
298
|
-
|
|
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
|
|
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
|
|
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
|
|
360
|
+
return acknowledge();
|
|
309
361
|
const target = this.activityToTarget.get(activityId);
|
|
310
362
|
if (!target)
|
|
311
|
-
return
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
397
|
+
switch (eventName) {
|
|
344
398
|
case 'think': {
|
|
345
399
|
if (!chatId)
|
|
346
|
-
return
|
|
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
|
|
417
|
+
return acknowledge();
|
|
364
418
|
}
|
|
365
419
|
case 'content_delta': {
|
|
366
420
|
if (!chatId)
|
|
367
|
-
return
|
|
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
|
|
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 =
|
|
440
|
+
const payload = data.payload;
|
|
387
441
|
await this._sendContentPart(chatId, target.senderId, activityId, payload);
|
|
388
|
-
return
|
|
442
|
+
return acknowledge();
|
|
389
443
|
}
|
|
390
444
|
case 'content_part': {
|
|
391
445
|
if (!chatId)
|
|
392
|
-
return
|
|
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 =
|
|
449
|
+
const payload = data.payload;
|
|
396
450
|
await this._sendContentPart(chatId, target.senderId, activityId, payload);
|
|
397
451
|
}
|
|
398
|
-
return
|
|
452
|
+
return acknowledge();
|
|
399
453
|
}
|
|
400
454
|
case 'tool_result': {
|
|
401
455
|
if (!chatId)
|
|
402
|
-
return
|
|
403
|
-
|
|
404
|
-
|
|
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
|
|
462
|
+
return acknowledge();
|
|
410
463
|
}
|
|
411
464
|
case 'complete': {
|
|
412
|
-
const
|
|
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
|
|
468
|
+
return acknowledge();
|
|
417
469
|
}
|
|
418
470
|
case 'notify': {
|
|
419
471
|
if (!chatId)
|
|
420
|
-
return
|
|
421
|
-
await this.cloud.send(chatId, { type: 'text', text:
|
|
422
|
-
return
|
|
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
|
|
493
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️',
|
|
494
|
-
return
|
|
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
|
|
499
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️',
|
|
500
|
-
return
|
|
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
|
|
505
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌',
|
|
506
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
636
|
-
new_activity
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
745
|
-
|
|
746
|
-
|
|
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(
|
|
767
|
+
pq.active.resolve(errorResponse('cancelled', 'Bridge closing'));
|
|
792
768
|
}
|
|
793
769
|
for (const item of pq.queue) {
|
|
794
|
-
item.resolve(
|
|
770
|
+
item.resolve(errorResponse('cancelled', 'Bridge closing'));
|
|
795
771
|
}
|
|
796
772
|
}
|
|
797
773
|
this.pendingQueues.clear();
|