claw-subagent-service 0.0.109 → 0.0.110
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/package.json
CHANGED
|
@@ -363,9 +363,10 @@ class OpenClawClient {
|
|
|
363
363
|
const sessionId = `clawmessenger-${fromUser}`;
|
|
364
364
|
|
|
365
365
|
// 尝试多个可能的 SSE 端点,兼容不同版本 OpenClaw Gateway
|
|
366
|
+
// 注意:多模态图片必须使用 /v1/responses 端点
|
|
366
367
|
const endpoints = [
|
|
367
|
-
'http://127.0.0.1:18789/v1/
|
|
368
|
-
'http://127.0.0.1:18789/v1/
|
|
368
|
+
'http://127.0.0.1:18789/v1/responses',
|
|
369
|
+
'http://127.0.0.1:18789/v1/chat/completions'
|
|
369
370
|
];
|
|
370
371
|
|
|
371
372
|
for (let i = 0; i < endpoints.length; i++) {
|
|
@@ -383,9 +384,9 @@ class OpenClawClient {
|
|
|
383
384
|
}
|
|
384
385
|
|
|
385
386
|
if (is404 && isLast) {
|
|
386
|
-
this.log?.error(`[OpenClawClient] 所有 SSE 端点均返回 404。OpenClaw
|
|
387
|
+
this.log?.error(`[OpenClawClient] 所有 SSE 端点均返回 404。OpenClaw responses 端点未启用。`);
|
|
387
388
|
this.log?.error(`[OpenClawClient] 请检查 ~/.openclaw/openclaw.json 中是否包含:`);
|
|
388
|
-
this.log?.error(`[OpenClawClient] gateway.http.endpoints.
|
|
389
|
+
this.log?.error(`[OpenClawClient] gateway.http.endpoints.responses.enabled = true`);
|
|
389
390
|
this.log?.error(`[OpenClawClient] 修改后请重启 OpenClaw gateway: openclaw gateway`);
|
|
390
391
|
} else {
|
|
391
392
|
this.log?.error(`[OpenClawClient] SSE 请求失败: ${err.message}`);
|
|
@@ -425,7 +426,11 @@ class OpenClawClient {
|
|
|
425
426
|
const contentType = response.headers['content-type'] || 'image/jpeg';
|
|
426
427
|
this.log?.info(`[OpenClawClient] 图片下载完成: ${imageUrl}, size=${buffer.length}, type=${contentType}`);
|
|
427
428
|
|
|
428
|
-
|
|
429
|
+
// 返回对象,包含纯 base64 和 MIME 类型
|
|
430
|
+
return {
|
|
431
|
+
base64: base64,
|
|
432
|
+
mediaType: contentType
|
|
433
|
+
};
|
|
429
434
|
} catch (err) {
|
|
430
435
|
this.log?.error(`[OpenClawClient] 图片下载失败: ${imageUrl}, ${err.message}`);
|
|
431
436
|
throw err;
|
|
@@ -443,7 +448,10 @@ class OpenClawClient {
|
|
|
443
448
|
|
|
444
449
|
// 检测消息是否包含图片 URL
|
|
445
450
|
const imageUrlMatch = message.match(/\[图片\]\s*(https?:\/\/[^\s]+)/);
|
|
446
|
-
let
|
|
451
|
+
let payload;
|
|
452
|
+
|
|
453
|
+
// 判断使用哪个端点
|
|
454
|
+
const isResponsesEndpoint = apiUrl.includes('/v1/responses');
|
|
447
455
|
|
|
448
456
|
if (imageUrlMatch) {
|
|
449
457
|
// 多模态格式:图片 + 文本
|
|
@@ -452,32 +460,72 @@ class OpenClawClient {
|
|
|
452
460
|
|
|
453
461
|
try {
|
|
454
462
|
// 下载图片并转换为 base64
|
|
455
|
-
const
|
|
463
|
+
const imageData = await this._downloadImageAsBase64(imageUrl);
|
|
456
464
|
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
465
|
+
if (isResponsesEndpoint) {
|
|
466
|
+
// /v1/responses 端点格式(推荐,支持多模态)
|
|
467
|
+
payload = {
|
|
468
|
+
model: 'openclaw',
|
|
469
|
+
input: [
|
|
470
|
+
{ type: 'input_text', text: textContent || '描述这张图片' },
|
|
471
|
+
{
|
|
472
|
+
type: 'input_image',
|
|
473
|
+
source: {
|
|
474
|
+
type: 'base64',
|
|
475
|
+
media_type: imageData.mediaType,
|
|
476
|
+
data: imageData.base64 // 纯 base64,不带 data URI 前缀
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
],
|
|
480
|
+
stream: true,
|
|
481
|
+
max_tokens: 2048
|
|
482
|
+
};
|
|
483
|
+
} else {
|
|
484
|
+
// /v1/chat/completions 端点格式(兼容旧版)
|
|
485
|
+
payload = {
|
|
486
|
+
model: 'openclaw',
|
|
487
|
+
messages: [{
|
|
488
|
+
role: 'user',
|
|
489
|
+
content: [
|
|
490
|
+
{ type: 'text', text: textContent || '描述这张图片' },
|
|
491
|
+
{ type: 'image_url', image_url: { url: `data:${imageData.mediaType};base64,${imageData.base64}` } }
|
|
492
|
+
]
|
|
493
|
+
}],
|
|
494
|
+
stream: true,
|
|
495
|
+
max_tokens: 2048
|
|
496
|
+
};
|
|
497
|
+
}
|
|
464
498
|
} catch (err) {
|
|
465
499
|
this.log?.warn(`[OpenClawClient] 图片处理失败,回退到文本模式: ${err.message}`);
|
|
466
500
|
// 回退到纯文本模式
|
|
467
|
-
|
|
501
|
+
payload = {
|
|
502
|
+
model: 'openclaw',
|
|
503
|
+
messages: [{ role: 'user', content: message }],
|
|
504
|
+
stream: true,
|
|
505
|
+
max_tokens: 2048
|
|
506
|
+
};
|
|
468
507
|
}
|
|
469
508
|
} else {
|
|
470
509
|
// 纯文本格式
|
|
471
|
-
|
|
510
|
+
if (isResponsesEndpoint) {
|
|
511
|
+
payload = {
|
|
512
|
+
model: 'openclaw',
|
|
513
|
+
input: [
|
|
514
|
+
{ type: 'input_text', text: message }
|
|
515
|
+
],
|
|
516
|
+
stream: true,
|
|
517
|
+
max_tokens: 2048
|
|
518
|
+
};
|
|
519
|
+
} else {
|
|
520
|
+
payload = {
|
|
521
|
+
model: 'openclaw',
|
|
522
|
+
messages: [{ role: 'user', content: message }],
|
|
523
|
+
stream: true,
|
|
524
|
+
max_tokens: 2048
|
|
525
|
+
};
|
|
526
|
+
}
|
|
472
527
|
}
|
|
473
528
|
|
|
474
|
-
const payload = {
|
|
475
|
-
model: 'openclaw',
|
|
476
|
-
messages: messages,
|
|
477
|
-
stream: true,
|
|
478
|
-
max_tokens: 2048
|
|
479
|
-
};
|
|
480
|
-
|
|
481
529
|
this.log?.info(`[OpenClawClient] SSE 请求 payload: ${JSON.stringify(payload)}`);
|
|
482
530
|
|
|
483
531
|
let fullText = '';
|