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.
- package/dist/bridge/index.d.ts +2 -0
- package/dist/bridge/index.d.ts.map +1 -1
- package/dist/bridge/index.js +157 -177
- 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/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":"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,EAAoG,MAAM,OAAO,CAAC;AAsB7M;;;;;;;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,gIAAgI;YAClH,yBAAyB;IAoCvC,0FAA0F;IACpF,aAAa,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC;IAgClE,sFAAsF;IAChF,WAAW,CAAC,UAAU,EAAE,MAAM,EAAE,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,aAAa,CAAC;IAqLxF,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;IAsKlB,+EAA+E;IAC/E,eAAe,IAAI,IAAI;IAQjB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAuC7B"}
|
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';
|
|
@@ -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,24 +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
|
+
return genericResponse("action", { requestId: item.requestId, type: 'approve' });
|
|
156
157
|
if (input === 'c')
|
|
157
|
-
return
|
|
158
|
-
return
|
|
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
|
|
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
|
|
168
|
+
return genericResponse("question", { requestId: item.requestId, type: 'answer', content: payload.options[num - 1] });
|
|
168
169
|
}
|
|
169
170
|
}
|
|
170
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
290
|
-
|
|
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
|
|
294
|
-
|
|
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
|
|
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
|
|
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
|
|
360
|
+
return acknowledge();
|
|
305
361
|
const target = this.activityToTarget.get(activityId);
|
|
306
362
|
if (!target)
|
|
307
|
-
return
|
|
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 (
|
|
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 (
|
|
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 (
|
|
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 (
|
|
397
|
+
switch (eventName) {
|
|
340
398
|
case 'think': {
|
|
341
399
|
if (!chatId)
|
|
342
|
-
return
|
|
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
|
|
417
|
+
return acknowledge();
|
|
360
418
|
}
|
|
361
419
|
case 'content_delta': {
|
|
362
420
|
if (!chatId)
|
|
363
|
-
return
|
|
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
|
|
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 =
|
|
440
|
+
const payload = data.payload;
|
|
383
441
|
await this._sendContentPart(chatId, target.senderId, activityId, payload);
|
|
384
|
-
return
|
|
442
|
+
return acknowledge();
|
|
385
443
|
}
|
|
386
444
|
case 'content_part': {
|
|
387
445
|
if (!chatId)
|
|
388
|
-
return
|
|
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 =
|
|
449
|
+
const payload = data.payload;
|
|
392
450
|
await this._sendContentPart(chatId, target.senderId, activityId, payload);
|
|
393
451
|
}
|
|
394
|
-
return
|
|
452
|
+
return acknowledge();
|
|
395
453
|
}
|
|
396
454
|
case 'tool_result': {
|
|
397
455
|
if (!chatId)
|
|
398
|
-
return
|
|
399
|
-
|
|
400
|
-
|
|
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
|
|
462
|
+
return acknowledge();
|
|
406
463
|
}
|
|
407
464
|
case 'complete': {
|
|
408
|
-
const
|
|
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
|
|
468
|
+
return acknowledge();
|
|
413
469
|
}
|
|
414
470
|
case 'notify': {
|
|
415
471
|
if (!chatId)
|
|
416
|
-
return
|
|
417
|
-
await this.cloud.send(chatId, { type: 'text', text:
|
|
418
|
-
return
|
|
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
|
|
489
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('ℹ️',
|
|
490
|
-
return
|
|
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
|
|
495
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('⚠️',
|
|
496
|
-
return
|
|
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
|
|
501
|
-
await this.cloud.send(chatId, { type: 'text', text: this.formatTraceable('❌',
|
|
502
|
-
return
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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(
|
|
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
|
-
|
|
632
|
-
new_activity
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
741
|
-
|
|
742
|
-
|
|
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(
|
|
767
|
+
pq.active.resolve(errorResponse('cancelled', 'Bridge closing'));
|
|
788
768
|
}
|
|
789
769
|
for (const item of pq.queue) {
|
|
790
|
-
item.resolve(
|
|
770
|
+
item.resolve(errorResponse('cancelled', 'Bridge closing'));
|
|
791
771
|
}
|
|
792
772
|
}
|
|
793
773
|
this.pendingQueues.clear();
|