dsh-agent-toolkit 0.2.5 → 0.2.6

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/lib/client.js CHANGED
@@ -68,14 +68,14 @@ window.__ModuleLoader__.load({
68
68
  }
69
69
  var delegate_card_module_css_default = {
70
70
  "summary": "_8wQUq_summary",
71
- "root": "_8wQUq_root",
72
- "body": "_8wQUq_body",
73
- "visuallyHidden": "_8wQUq_visuallyHidden",
71
+ "prompt": "_8wQUq_prompt",
74
72
  "row": "_8wQUq_row",
75
73
  "childLink": "_8wQUq_childLink",
76
- "prompt": "_8wQUq_prompt",
74
+ "root": "_8wQUq_root",
75
+ "result": "_8wQUq_result",
77
76
  "chip": "_8wQUq_chip",
78
- "result": "_8wQUq_result"
77
+ "visuallyHidden": "_8wQUq_visuallyHidden",
78
+ "body": "_8wQUq_body"
79
79
  };
80
80
  //#endregion
81
81
  //#region src/client/delegate/delegate-card.tsx
@@ -411,33 +411,33 @@ window.__ModuleLoader__.load({
411
411
  document.head.appendChild(tag);
412
412
  }
413
413
  var agents_module_css_default = {
414
- "toolGroupTitle": "KsfSLW_toolGroupTitle",
415
- "actions": "KsfSLW_actions",
416
- "createButton": "KsfSLW_createButton",
417
- "toolMode": "KsfSLW_toolMode",
418
414
  "hint": "KsfSLW_hint",
419
- "editorPane": "KsfSLW_editorPane",
420
- "error": "KsfSLW_error",
421
- "dangerButton": "KsfSLW_dangerButton",
422
415
  "listPane": "KsfSLW_listPane",
423
- "toolGroupSet": "KsfSLW_toolGroupSet",
424
- "select": "KsfSLW_select",
425
- "textarea": "KsfSLW_textarea",
426
416
  "agentRow": "KsfSLW_agentRow",
427
- "builtinBadge": "KsfSLW_builtinBadge",
428
- "field": "KsfSLW_field",
429
- "agentName": "KsfSLW_agentName",
430
- "agentDesc": "KsfSLW_agentDesc",
417
+ "agentRowActive": "KsfSLW_agentRowActive",
418
+ "createButton": "KsfSLW_createButton",
419
+ "editorPane": "KsfSLW_editorPane",
431
420
  "editor": "KsfSLW_editor",
432
- "block": "KsfSLW_block",
433
- "input": "KsfSLW_input",
434
- "readonlyId": "KsfSLW_readonlyId",
435
- "toolGrid": "KsfSLW_toolGrid",
436
421
  "blockTitle": "KsfSLW_blockTitle",
422
+ "toolGrid": "KsfSLW_toolGrid",
437
423
  "split": "KsfSLW_split",
424
+ "actions": "KsfSLW_actions",
425
+ "dangerButton": "KsfSLW_dangerButton",
426
+ "toolGroupTitle": "KsfSLW_toolGroupTitle",
438
427
  "toolCheck": "KsfSLW_toolCheck",
439
- "agentRowActive": "KsfSLW_agentRowActive",
440
- "dialog": "KsfSLW_dialog"
428
+ "readonlyId": "KsfSLW_readonlyId",
429
+ "select": "KsfSLW_select",
430
+ "toolMode": "KsfSLW_toolMode",
431
+ "field": "KsfSLW_field",
432
+ "toolGroupSet": "KsfSLW_toolGroupSet",
433
+ "error": "KsfSLW_error",
434
+ "agentDesc": "KsfSLW_agentDesc",
435
+ "agentName": "KsfSLW_agentName",
436
+ "builtinBadge": "KsfSLW_builtinBadge",
437
+ "textarea": "KsfSLW_textarea",
438
+ "dialog": "KsfSLW_dialog",
439
+ "block": "KsfSLW_block",
440
+ "input": "KsfSLW_input"
441
441
  };
442
442
  //#endregion
443
443
  //#region src/client/agents/AgentEditor.tsx
@@ -951,24 +951,24 @@ window.__ModuleLoader__.load({
951
951
  document.head.appendChild(tag);
952
952
  }
953
953
  var prompt_module_css_default = {
954
- "tabActive": "VZk1fa_tabActive",
954
+ "tab": "VZk1fa_tab",
955
+ "field": "VZk1fa_field",
956
+ "textarea": "VZk1fa_textarea",
957
+ "error": "VZk1fa_error",
958
+ "layerRowActive": "VZk1fa_layerRowActive",
959
+ "layerOrder": "VZk1fa_layerOrder",
955
960
  "listPane": "VZk1fa_listPane",
961
+ "dialog": "VZk1fa_dialog",
956
962
  "editorPane": "VZk1fa_editorPane",
957
- "layerName": "VZk1fa_layerName",
958
- "actions": "VZk1fa_actions",
959
- "hint": "VZk1fa_hint",
960
- "layerOrder": "VZk1fa_layerOrder",
961
- "readonlyTag": "VZk1fa_readonlyTag",
962
- "tab": "VZk1fa_tab",
963
+ "editor": "VZk1fa_editor",
963
964
  "split": "VZk1fa_split",
965
+ "actions": "VZk1fa_actions",
964
966
  "layerRow": "VZk1fa_layerRow",
965
- "textarea": "VZk1fa_textarea",
966
- "editor": "VZk1fa_editor",
967
- "dialog": "VZk1fa_dialog",
967
+ "readonlyTag": "VZk1fa_readonlyTag",
968
+ "tabActive": "VZk1fa_tabActive",
969
+ "layerName": "VZk1fa_layerName",
968
970
  "tabs": "VZk1fa_tabs",
969
- "error": "VZk1fa_error",
970
- "layerRowActive": "VZk1fa_layerRowActive",
971
- "field": "VZk1fa_field"
971
+ "hint": "VZk1fa_hint"
972
972
  };
973
973
  //#endregion
974
974
  //#region src/client/prompt/PromptLayersModal.tsx
@@ -1310,8 +1310,8 @@ window.__ModuleLoader__.load({
1310
1310
  document.head.appendChild(tag);
1311
1311
  }
1312
1312
  var entry_module_css_default = {
1313
- "rail": "QVHFVG_rail",
1314
- "trigger": "QVHFVG_trigger"
1313
+ "trigger": "QVHFVG_trigger",
1314
+ "rail": "QVHFVG_rail"
1315
1315
  };
1316
1316
  //#endregion
1317
1317
  //#region ../usage/src/client/shared/entry.tsx
@@ -1453,12 +1453,12 @@ window.__ModuleLoader__.load({
1453
1453
  }
1454
1454
  var chart_module_css_default = {
1455
1455
  "chartTheme": "_8LXSJW_chartTheme",
1456
- "swatchCached": "_8LXSJW_swatchCached",
1456
+ "tooltipTotal": "_8LXSJW_tooltipTotal",
1457
+ "legend": "_8LXSJW_legend",
1457
1458
  "tooltipTitle": "_8LXSJW_tooltipTitle",
1458
1459
  "swatchFresh": "_8LXSJW_swatchFresh",
1459
- "tooltip": "_8LXSJW_tooltip",
1460
- "tooltipTotal": "_8LXSJW_tooltipTotal",
1461
- "legend": "_8LXSJW_legend"
1460
+ "swatchCached": "_8LXSJW_swatchCached",
1461
+ "tooltip": "_8LXSJW_tooltip"
1462
1462
  };
1463
1463
  //#endregion
1464
1464
  //#region \0dsh-css:D:\work\github\dsh\dsh-agent-toolkit\packages\usage\src\client\usage\ActivityHeatmap.module.css.mjs
@@ -1472,14 +1472,14 @@ window.__ModuleLoader__.load({
1472
1472
  document.head.appendChild(tag);
1473
1473
  }
1474
1474
  var ActivityHeatmap_module_css_default = {
1475
- "grid": "hjrYrq_grid",
1476
1475
  "level3": "hjrYrq_level3",
1477
- "level4": "hjrYrq_level4",
1478
- "months": "hjrYrq_months",
1476
+ "level2": "hjrYrq_level2",
1479
1477
  "level0": "hjrYrq_level0",
1478
+ "grid": "hjrYrq_grid",
1479
+ "level4": "hjrYrq_level4",
1480
+ "level1": "hjrYrq_level1",
1480
1481
  "week": "hjrYrq_week",
1481
- "level2": "hjrYrq_level2",
1482
- "level1": "hjrYrq_level1"
1482
+ "months": "hjrYrq_months"
1483
1483
  };
1484
1484
  //#endregion
1485
1485
  //#region ../usage/src/client/usage/ActivityHeatmap.tsx
@@ -52516,19 +52516,19 @@ ${te.current.stack}
52516
52516
  document.head.appendChild(tag);
52517
52517
  }
52518
52518
  var UsageModal_module_css_default = {
52519
- "row": "MODeXa_row",
52519
+ "compaction": "MODeXa_compaction",
52520
+ "dateLabel": "MODeXa_dateLabel",
52521
+ "tab": "MODeXa_tab",
52522
+ "total": "MODeXa_total",
52523
+ "tabActive": "MODeXa_tabActive",
52524
+ "pagerButton": "MODeXa_pagerButton",
52525
+ "pager": "MODeXa_pager",
52520
52526
  "rowName": "MODeXa_rowName",
52521
- "rowCalls": "MODeXa_rowCalls",
52522
52527
  "dialog": "MODeXa_dialog",
52523
52528
  "sectionTitle": "MODeXa_sectionTitle",
52524
- "dateLabel": "MODeXa_dateLabel",
52525
- "pager": "MODeXa_pager",
52526
- "compaction": "MODeXa_compaction",
52527
- "pagerButton": "MODeXa_pagerButton",
52528
52529
  "tabs": "MODeXa_tabs",
52529
- "total": "MODeXa_total",
52530
- "tab": "MODeXa_tab",
52531
- "tabActive": "MODeXa_tabActive"
52530
+ "row": "MODeXa_row",
52531
+ "rowCalls": "MODeXa_rowCalls"
52532
52532
  };
52533
52533
  //#endregion
52534
52534
  //#region ../usage/src/client/usage/UsageModal.tsx
@@ -55153,29 +55153,29 @@ ${te.current.stack}
55153
55153
  document.head.appendChild(tag);
55154
55154
  }
55155
55155
  var bots_module_css_default = {
55156
- "botRow": "vTbXga_botRow",
55157
- "channelBadge": "vTbXga_channelBadge",
55158
- "field": "vTbXga_field",
55159
- "select": "vTbXga_select",
55160
- "status": "vTbXga_status",
55161
- "group": "vTbXga_group",
55162
- "botName": "vTbXga_botName",
55163
- "textarea": "vTbXga_textarea",
55164
- "dialog": "vTbXga_dialog",
55165
- "input": "vTbXga_input",
55156
+ "formActions": "vTbXga_formActions",
55166
55157
  "steps": "vTbXga_steps",
55167
- "createButton": "vTbXga_createButton",
55168
55158
  "tab": "vTbXga_tab",
55169
- "tabActive": "vTbXga_tabActive",
55170
- "hint": "vTbXga_hint",
55171
- "step": "vTbXga_step",
55172
- "stepSeparator": "vTbXga_stepSeparator",
55159
+ "error": "vTbXga_error",
55173
55160
  "tabs": "vTbXga_tabs",
55161
+ "dialog": "vTbXga_dialog",
55162
+ "step": "vTbXga_step",
55174
55163
  "scanSection": "vTbXga_scanSection",
55175
- "error": "vTbXga_error",
55164
+ "textarea": "vTbXga_textarea",
55165
+ "createButton": "vTbXga_createButton",
55166
+ "groupTitle": "vTbXga_groupTitle",
55167
+ "stepSeparator": "vTbXga_stepSeparator",
55168
+ "status": "vTbXga_status",
55169
+ "hint": "vTbXga_hint",
55170
+ "botRow": "vTbXga_botRow",
55171
+ "channelBadge": "vTbXga_channelBadge",
55172
+ "group": "vTbXga_group",
55173
+ "tabActive": "vTbXga_tabActive",
55176
55174
  "stepActive": "vTbXga_stepActive",
55177
- "formActions": "vTbXga_formActions",
55178
- "groupTitle": "vTbXga_groupTitle"
55175
+ "botName": "vTbXga_botName",
55176
+ "select": "vTbXga_select",
55177
+ "input": "vTbXga_input",
55178
+ "field": "vTbXga_field"
55179
55179
  };
55180
55180
  //#endregion
55181
55181
  //#region src/client/bots/BotForm.tsx
package/lib/index.js CHANGED
@@ -1698,6 +1698,22 @@ async function setupAgentScope(agentCtx, hooks, toolsScope) {
1698
1698
  }
1699
1699
  //#endregion
1700
1700
  //#region src/channels/feishu/api.ts
1701
+ /** 附件服务接受的图片媒体类型(与宿主 attachment v1 一致)。 */
1702
+ const IMAGE_MEDIA_TYPES = [
1703
+ "image/png",
1704
+ "image/jpeg",
1705
+ "image/webp",
1706
+ "image/gif"
1707
+ ];
1708
+ /** 按魔数判定图片媒体类型;未知字节时回退响应头 content-type(限接受集合),否则 undefined。 */
1709
+ function sniffImageMediaType(data, contentType) {
1710
+ if (data.length >= 4 && data[0] === 137 && data[1] === 80 && data[2] === 78 && data[3] === 71) return "image/png";
1711
+ if (data.length >= 3 && data[0] === 255 && data[1] === 216 && data[2] === 255) return "image/jpeg";
1712
+ if (data.length >= 4 && data[0] === 71 && data[1] === 73 && data[2] === 70 && data[3] === 56) return "image/gif";
1713
+ if (data.length >= 12 && data[0] === 82 && data[1] === 73 && data[2] === 70 && data[3] === 70 && data[8] === 87 && data[9] === 69 && data[10] === 66 && data[11] === 80) return "image/webp";
1714
+ const declared = typeof contentType === "string" ? contentType.split(";")[0].trim().toLowerCase() : "";
1715
+ return IMAGE_MEDIA_TYPES.includes(declared) ? declared : void 0;
1716
+ }
1701
1717
  /** SDK 薄封装:tenant_access_token 由 SDK 自动管理;错误带 code/msg 上下文。 */
1702
1718
  function createFeishuApi(client) {
1703
1719
  return {
@@ -1794,6 +1810,31 @@ function createFeishuApi(client) {
1794
1810
  message_id: messageId,
1795
1811
  reaction_id: reactionId
1796
1812
  } });
1813
+ },
1814
+ async downloadImage(messageId, fileKey) {
1815
+ const res = await client.im.messageResource.get({
1816
+ params: { type: "image" },
1817
+ path: {
1818
+ message_id: messageId,
1819
+ file_key: fileKey
1820
+ }
1821
+ });
1822
+ const chunks = [];
1823
+ await new Promise((resolve, reject) => {
1824
+ const stream = res.getReadableStream();
1825
+ stream.on("data", (chunk) => {
1826
+ chunks.push(chunk);
1827
+ });
1828
+ stream.on("end", () => resolve());
1829
+ stream.on("error", (error) => reject(error instanceof Error ? error : new Error(String(error))));
1830
+ });
1831
+ const data = new Uint8Array(Buffer.concat(chunks));
1832
+ const mediaType = sniffImageMediaType(data, res.headers?.["content-type"]);
1833
+ if (mediaType === void 0) throw new Error(`图片资源格式不受支持(file_key=${fileKey},content-type=${String(res.headers?.["content-type"] ?? "未知")})`);
1834
+ return {
1835
+ data,
1836
+ mediaType
1837
+ };
1797
1838
  }
1798
1839
  };
1799
1840
  }
@@ -1814,9 +1855,39 @@ function stripMentionPlaceholders(text) {
1814
1855
  //#endregion
1815
1856
  //#region src/channels/feishu/parse.ts
1816
1857
  /** im.message.receive_v1 事件解析:窄化为渠道无关的 ParsedMessage;message_id 去重。 */
1858
+ /** 从 post content(段落数组)抽取文本与图片 key;段落间以换行连接。 */
1859
+ function parsePostContent(content) {
1860
+ const imageKeys = [];
1861
+ const paragraphs = [];
1862
+ try {
1863
+ const parsed = JSON.parse(content);
1864
+ const list = Array.isArray(parsed.content) ? parsed.content : [];
1865
+ for (const paragraph of list) {
1866
+ if (!Array.isArray(paragraph)) continue;
1867
+ const parts = [];
1868
+ for (const node of paragraph) {
1869
+ if (node === null || typeof node !== "object") continue;
1870
+ if (node.tag === "img") {
1871
+ if (typeof node.image_key === "string" && node.image_key.length > 0) imageKeys.push(node.image_key);
1872
+ } else if ((node.tag === "text" || node.tag === "a") && typeof node.text === "string") parts.push(node.text);
1873
+ }
1874
+ paragraphs.push(parts.join(""));
1875
+ }
1876
+ } catch {
1877
+ return {
1878
+ text: "",
1879
+ imageKeys: []
1880
+ };
1881
+ }
1882
+ return {
1883
+ text: paragraphs.join("\n"),
1884
+ imageKeys
1885
+ };
1886
+ }
1817
1887
  /**
1818
1888
  * SDK handler 收到的 data 即事件体(README 示例 `data.message` 直接解构);
1819
- * 兼容包一层 { event } 的形态。过滤:机器人消息、非文本、群内未 @机器人、空文本。
1889
+ * 兼容包一层 { event } 的形态。过滤:机器人消息、非 text/post/image 类型、
1890
+ * 群内未 @机器人、无文本且无图片。
1820
1891
  */
1821
1892
  function parseMessageEvent(data) {
1822
1893
  const wrapped = data;
@@ -1825,25 +1896,38 @@ function parseMessageEvent(data) {
1825
1896
  const userId = event.sender.sender_id?.open_id;
1826
1897
  const msg = event.message;
1827
1898
  if (typeof userId !== "string" || msg === void 0) return null;
1828
- if (msg.message_type !== "text" || typeof msg.content !== "string") return null;
1899
+ if (msg.message_type !== "text" && msg.message_type !== "post" && msg.message_type !== "image") return null;
1900
+ if (typeof msg.content !== "string") return null;
1829
1901
  if (typeof msg.message_id !== "string" || typeof msg.chat_id !== "string") return null;
1830
1902
  if (msg.chat_type !== "p2p" && msg.chat_type !== "group") return null;
1831
1903
  if (msg.chat_type === "group" && !(msg.mentions ?? []).some((m) => m.mentioned_type === "bot")) return null;
1832
- let text;
1833
- try {
1904
+ let text = "";
1905
+ let imageKeys = [];
1906
+ if (msg.message_type === "text") try {
1834
1907
  const parsed = JSON.parse(msg.content);
1835
1908
  if (typeof parsed.text !== "string") return null;
1836
1909
  text = stripMentionPlaceholders(parsed.text);
1837
1910
  } catch {
1838
1911
  return null;
1839
1912
  }
1840
- if (text.length === 0) return null;
1913
+ else if (msg.message_type === "post") {
1914
+ const post = parsePostContent(msg.content);
1915
+ text = stripMentionPlaceholders(post.text);
1916
+ imageKeys = post.imageKeys;
1917
+ } else try {
1918
+ const parsed = JSON.parse(msg.content);
1919
+ if (typeof parsed.image_key === "string" && parsed.image_key.length > 0) imageKeys.push(parsed.image_key);
1920
+ } catch {
1921
+ return null;
1922
+ }
1923
+ if (text.length === 0 && imageKeys.length === 0) return null;
1841
1924
  return {
1842
1925
  messageId: msg.message_id,
1843
1926
  chatId: msg.chat_id,
1844
1927
  chatType: msg.chat_type,
1845
1928
  userId,
1846
- text
1929
+ text,
1930
+ imageKeys
1847
1931
  };
1848
1932
  }
1849
1933
  /** message_id 去重(飞书会重推);FIFO 容量淘汰。 */
@@ -2276,12 +2360,14 @@ const feishuChannel = {
2276
2360
  const parsed = parseMessageEvent(data);
2277
2361
  if (parsed === null || !dedup.check(parsed.messageId)) return;
2278
2362
  const reply = new FeishuReplyHandle(api, parsed.chatId, tunables, log);
2363
+ const loadImages = parsed.imageKeys.length > 0 ? async () => Promise.all(parsed.imageKeys.map(async (key) => api.downloadImage(parsed.messageId, key))) : void 0;
2279
2364
  io.onMessage({
2280
2365
  botId: bot.record.id,
2281
2366
  chatId: parsed.chatId,
2282
2367
  userId: parsed.userId,
2283
2368
  messageId: parsed.messageId,
2284
2369
  text: parsed.text,
2370
+ ...loadImages !== void 0 ? { loadImages } : {},
2285
2371
  reply,
2286
2372
  ackProcessing: makeAck(api, parsed.messageId, tunables.processingReactionEmoji)
2287
2373
  });
@@ -2467,7 +2553,7 @@ var Outbound = class {
2467
2553
  };
2468
2554
  //#endregion
2469
2555
  //#region src/channels/inbound.ts
2470
- /** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → followup 投递。 */
2556
+ /** 入站:指令分流 → 路由 → 单 in-flight 准入 → 表情回复 → 图片落附件库 → followup 投递。 */
2471
2557
  var Inbound = class {
2472
2558
  deps;
2473
2559
  constructor(deps) {
@@ -2509,11 +2595,23 @@ var Inbound = class {
2509
2595
  }
2510
2596
  rt.inflight = { ack: void 0 };
2511
2597
  rt.inflight.ack = await msg.ackProcessing().catch(() => void 0) ?? void 0;
2598
+ const imageRefs = [];
2599
+ if (msg.loadImages !== void 0) {
2600
+ const images = await msg.loadImages();
2601
+ if (images.length > 0) {
2602
+ const attachments = this.deps.attachments?.();
2603
+ if (attachments === void 0) await msg.reply.notice("当前环境暂不支持图片消息(附件服务不可用),已按文字部分处理");
2604
+ else imageRefs.push(...await attachments.saveImages(images));
2605
+ }
2606
+ }
2512
2607
  const message = createUserMessage({
2513
- content: [{
2608
+ content: [...msg.text.length > 0 ? [{
2514
2609
  type: "text",
2515
2610
  text: msg.text
2516
- }],
2611
+ }] : [], ...imageRefs.map((ref) => ({
2612
+ type: "image",
2613
+ attachment: ref
2614
+ }))],
2517
2615
  source: { kind: "user" }
2518
2616
  });
2519
2617
  try {
@@ -2668,6 +2766,7 @@ var BotRuntime = class {
2668
2766
  router: this.router,
2669
2767
  bots: deps.bots,
2670
2768
  maxErrorDetailChars: deps.maxErrorDetailChars,
2769
+ ...deps.attachments !== void 0 ? { attachments: deps.attachments } : {},
2671
2770
  onError: (m) => deps.log.warn(m)
2672
2771
  });
2673
2772
  this.outbound = new Outbound(this.sessions, (m) => deps.log.warn(m), deps.maxErrorDetailChars);
@@ -3175,6 +3274,18 @@ function setupBots(ctx, config, deps) {
3175
3274
  if (workspaceRegistry === void 0) throw new Error("workspaceRegistry 服务不可用");
3176
3275
  await (await workspaceRegistry.create(cwd)).attachSession(SessionId(sessionId));
3177
3276
  } };
3277
+ const attachmentsOf = () => {
3278
+ if (ctx.get("attachments", false) === void 0) return void 0;
3279
+ return { async saveImages(inputs) {
3280
+ const current = ctx.get("attachments", false);
3281
+ if (current === void 0) throw new Error("attachments 服务不可用");
3282
+ return current.saveImages(inputs.map(({ data, mediaType, name }) => ({
3283
+ data,
3284
+ mediaType,
3285
+ ...name !== void 0 ? { name } : {}
3286
+ })));
3287
+ } };
3288
+ };
3178
3289
  let botsTable;
3179
3290
  let bindingsTable;
3180
3291
  let runtime;
@@ -3209,6 +3320,7 @@ function setupBots(ctx, config, deps) {
3209
3320
  channels,
3210
3321
  tunables,
3211
3322
  maxErrorDetailChars: config.errorDetailMaxChars,
3323
+ attachments: attachmentsOf,
3212
3324
  resolveSecret: async (ref) => (await ctx.credentials.resolve(credentialRef(ref)))?.value,
3213
3325
  validateProject: (path) => existsSync(path),
3214
3326
  log