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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claw-subagent-service",
3
- "version": "0.0.109",
3
+ "version": "0.0.110",
4
4
  "description": "虾说智能助手",
5
5
  "main": "cli.js",
6
6
  "bin": {
@@ -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/chat/completions',
368
- 'http://127.0.0.1:18789/v1/responses'
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 chatCompletions 端点未启用。`);
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.chatCompletions.enabled = true`);
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
- return `data:${contentType};base64,${base64}`;
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 messages;
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 base64Image = await this._downloadImageAsBase64(imageUrl);
463
+ const imageData = await this._downloadImageAsBase64(imageUrl);
456
464
 
457
- messages = [{
458
- role: 'user',
459
- content: [
460
- { type: 'text', text: textContent || '描述这张图片' },
461
- { type: 'image_url', image_url: { url: base64Image } }
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
- messages = [{ role: 'user', content: message }];
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
- messages = [{ role: 'user', content: message }];
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 = '';