koishi-plugin-image-prompt 2.1.0 → 2.1.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/lib/index.js +90 -36
- package/package.json +1 -1
- package/readme.md +19 -2
- package/src/index.ts +106 -37
package/lib/index.js
CHANGED
|
@@ -265,11 +265,11 @@ function buildAgentTools() {
|
|
|
265
265
|
type: "function",
|
|
266
266
|
function: {
|
|
267
267
|
name: "get_avatar",
|
|
268
|
-
description: "\u53D6\
|
|
268
|
+
description: "\u53D6\u5934\u50CF\u5F53\u53C2\u8003\u56FE\uFF0C\u8FD4\u56DE\u5B83\u7684\u7F16\u53F7\u3002**\u53EA\u80FD\u53D6\u4E24\u79CD\u4EBA\u7684\u5934\u50CF**\uFF1A\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF08userId \u7559\u7A7A/\u5199 me\uFF09\uFF0C\u6216\u4ED6\u8FD9\u6B21\u6D88\u606F\u91CC\u660E\u786E @ \u5230\u7684\u4EBA\uFF08\u586B\u4E0A\u4E0B\u6587\u300C\u53EF\u53D6\u5934\u50CF\u7684\u4EBA\u300D\u91CC\u5217\u51FA\u7684 id/\u540D\u5B57\uFF09\u3002\u5176\u5B83 id \u4E00\u5F8B\u4F1A\u88AB\u62D2\u7EDD\u3002",
|
|
269
269
|
parameters: {
|
|
270
270
|
type: "object",
|
|
271
271
|
properties: {
|
|
272
|
-
userId: { type: "string", description: "\
|
|
272
|
+
userId: { type: "string", description: "\u7559\u7A7A\u6216\u5199 me/self/\u6211 = \u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF1B\u4E5F\u53EF\u4EE5\u586B\u4E0A\u4E0B\u6587\u91CC\u300C\u53EF\u53D6\u5934\u50CF\u7684\u4EBA\u300D\u5217\u51FA\u7684 id \u6216\u6635\u79F0\uFF08\u5373\u88AB @ \u7684\u4EBA\uFF09\u3002**\u4E0D\u8981\u81EA\u5DF1\u731C id**" }
|
|
273
273
|
},
|
|
274
274
|
required: []
|
|
275
275
|
}
|
|
@@ -785,7 +785,9 @@ var DEFAULT_AGENT_INSTRUCTIONS = `\u4F60\u662F QQ \u7FA4\u91CC\u7684\u7ED8\u56FE
|
|
|
785
785
|
- gallery_search\uFF1A\u6309\u5173\u952E\u8BCD\u641C\u7D22\u53C2\u8003\u56FE\u5E93\u3002**\u6D89\u53CA\u5177\u4F53\u89D2\u8272/\u7ACB\u7ED8\u65F6\u5FC5\u987B\u5148\u641C\u4E00\u6B21**\u3002
|
|
786
786
|
\u591A\u4E2A\u5173\u952E\u8BCD\u7528\u7A7A\u683C\u5206\u9694\uFF08\u5982\u300C\u767D\u53D1 \u7ACB\u7ED8\u300D\uFF09\uFF0C\u5168\u90E8\u547D\u4E2D\u7684\u6392\u5728\u6700\u524D\uFF1B\u641C\u4E0D\u5230\u5C31\u6362\u4E2A\u8BCD\u518D\u641C\u3002
|
|
787
787
|
- ask_user\uFF1A\u628A\u95EE\u9898\u53D1\u7ED9\u7528\u6237**\u5E76\u7B49\u4ED6\u56DE\u590D**\uFF08\u4ED6\u53D1\u7684\u56FE\u4E5F\u4F1A\u4E00\u8D77\u5E26\u56DE\u6765\uFF09\u3002
|
|
788
|
-
- get_avatar\uFF1A\u53D6\
|
|
788
|
+
- get_avatar\uFF1A\u53D6\u5934\u50CF\u5F53\u53C2\u8003\u56FE\u3002**\u53EA\u80FD\u53D6\u4E24\u79CD\u4EBA**\uFF1A\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF08userId \u7559\u7A7A\u6216\u5199 me\uFF09\uFF0C
|
|
789
|
+
\u4EE5\u53CA\u4ED6\u8FD9\u6B21\u6D88\u606F\u91CC\u660E\u786E @ \u5230\u7684\u4EBA\uFF08\u586B\u4E0A\u4E0B\u6587\u300C\u53EF\u53D6\u5934\u50CF\u7684\u4EBA\u300D\u91CC\u5217\u51FA\u7684 id \u6216\u6635\u79F0\uFF09\u3002
|
|
790
|
+
\u5176\u5B83\u4EFB\u4F55 id \u90FD\u4F1A\u88AB\u62D2\u7EDD\uFF0C\u4E0D\u8981\u731C\u3002
|
|
789
791
|
- draw\uFF1A\u771F\u6B63\u5F00\u59CB\u753B\u3002\u628A prompt \u548C\u6311\u4E2D\u7684\u53C2\u8003\u56FE\u7F16\u53F7\u4EA4\u8FDB\u53BB\uFF0C\u753B\u597D\u4F1A\u81EA\u52A8\u53D1\u5230\u7FA4\u91CC\u3002
|
|
790
792
|
|
|
791
793
|
\u5DE5\u4F5C\u89C4\u5219\uFF1A
|
|
@@ -807,8 +809,12 @@ var DEFAULT_AGENT_INSTRUCTIONS = `\u4F60\u662F QQ \u7FA4\u91CC\u7684\u7ED8\u56FE
|
|
|
807
809
|
8. \u3010\u6CA1\u6307\u5B9A\u53C2\u8003\u56FE\u65F6\u5148\u95EE\u4E00\u53E5\u3011\u7528\u6237\u8FD9\u6B21\u6CA1\u53D1\u56FE\u3001\u6CA1 @ \u4EBA\u3001\u6307\u4EE4\u672C\u8EAB\u4E5F\u6CA1\u6709\u9ED8\u8BA4\u53C2\u8003\u56FE\uFF0C\u4F60\u4E5F\u641C\u4E0D\u5230\u5408\u9002\u7684\u7ACB\u7ED8\u65F6\uFF0C
|
|
808
810
|
**\u4E0D\u8981\u76F4\u63A5 draw**\u3002\u5148\u7528 ask_user \u95EE\u4E00\u53E5\u8981\u4E0D\u8981\u53C2\u8003\u56FE\uFF0C\u5E76\u7ED9\u51FA\u9009\u9879\uFF08\u4F8B\u5982\u300C\u7528\u4F60\u81EA\u5DF1\u7684\u5934\u50CF / \u7528 @\u67D0\u67D0 \u7684\u5934\u50CF /
|
|
809
811
|
\u6211\u5E2E\u4F60\u4ECE\u56FE\u5E93\u627E\u4E00\u5F20 / \u4E0D\u7528\u53C2\u8003\u76F4\u63A5\u753B\u300D\uFF09\u3002\u7528\u6237\u8BF4\u300C\u4E0D\u7528 / \u968F\u4FBF / \u76F4\u63A5\u753B\u300D\u5C31\u7ACB\u523B\u5F00\u753B\uFF0C**\u4E0D\u8981\u95EE\u7B2C\u4E8C\u6B21**\u3002
|
|
810
|
-
9. \u3010\
|
|
811
|
-
\u8BF4\u300C\u753B
|
|
812
|
+
9. \u3010\u5934\u50CF\u53EA\u80FD\u53D6\u300C\u6211\u300D\u548C\u300C\u88AB @ \u7684\u4EBA\u300D\u3011
|
|
813
|
+
- \u7528\u6237\u8BF4\u300C\u753B\u6211\u300D\u300C\u7528\u6211\u7684\u5F62\u8C61\u300D\u300C\u6211\u7684\u5934\u50CF\u300D\u2192 get_avatar \u7684 userId **\u7559\u7A7A**\uFF0C\u53D6\u4ED6\u81EA\u5DF1\u7684\u5934\u50CF\uFF1B
|
|
814
|
+
- \u7528\u6237 @ \u4E86\u8C01 \u2192 \u90A3\u4E2A\u4EBA\u7684\u5934\u50CF\u5DF2\u7ECF\u81EA\u52A8\u5E26\u4E0A\u4E86\uFF08\u4E0A\u4E0B\u6587\u91CC\u4F1A\u5217\u51FA\u7F16\u53F7\uFF09\uFF0C\u76F4\u63A5\u7528\u90A3\u4E2A\u7F16\u53F7\u5373\u53EF\uFF0C
|
|
815
|
+
\u9700\u8981\u65F6\u4E5F\u53EF\u4EE5\u628A\u4ED6\u7684 id \u6216\u6635\u79F0\u586B\u8FDB get_avatar \u518D\u53D6\u4E00\u6B21\uFF1B
|
|
816
|
+
- **\u9664\u6B64\u4E4B\u5916\u6CA1\u6709\u7B2C\u4E09\u79CD\u4EBA**\u3002\u6CA1 @ \u522B\u4EBA\u65F6\u7EDD\u4E0D\u8BB8\u53D6\u522B\u4EBA\u7684\u5934\u50CF\uFF0C\u4E5F\u4E0D\u8981\u81EA\u5DF1\u7F16 userId
|
|
817
|
+
\uFF08\u7F16\u51FA\u6765\u7684 id \u4F1A\u62FF\u5230\u5B8C\u5168\u4E0D\u76F8\u5E72\u7684\u4EBA\u7684\u5934\u50CF\uFF0C\u8FD9\u662F\u4E25\u91CD\u9519\u8BEF\uFF09\u3002
|
|
812
818
|
10. \u3010\u9ED8\u8BA4\u4E0D\u6DA6\u8272\uFF0C\u7528\u6237\u70B9\u5934\u624D\u6DA6\u8272\u3011\u628A\u7528\u6237\u7684\u8BDD**\u539F\u5C01\u4E0D\u52A8**\u4EA4\u7ED9\u7ED8\u56FE\u6A21\u578B\u5C31\u662F\u6700\u597D\u7684\u9ED8\u8BA4\u503C\uFF1A
|
|
813
819
|
- **\u4E0D\u8981**\u4E3B\u52A8\u6269\u5199\u3001\u4E0D\u8981\u8865\u753B\u98CE/\u5149\u7EBF/\u6750\u8D28/\u955C\u5934\u3001\u4E0D\u8981\u7FFB\u6210\u82F1\u6587\u3001\u4E0D\u8981\u52A0\u300Cmasterpiece\u300D\u8FD9\u7C7B\u8BCD\uFF1B
|
|
814
820
|
- \u7528\u6237\u660E\u786E\u8BF4\u300C\u5E2E\u6211\u6DA6\u8272 / \u4F18\u5316\u4E00\u4E0B / \u5199\u8BE6\u7EC6\u70B9\u300D\u65F6\uFF0C\u4F60\u624D\u628A\u63D0\u793A\u8BCD\u5199\u5F97\u66F4\u5B8C\u6574\uFF1B
|
|
@@ -820,7 +826,7 @@ var DEFAULT_AGENT_INSTRUCTIONS = `\u4F60\u662F QQ \u7FA4\u91CC\u7684\u7ED8\u56FE
|
|
|
820
826
|
\u5982\u679C\u4F60\u6240\u5728\u7684\u63A5\u53E3\u4E0D\u652F\u6301\u51FD\u6570\u8C03\u7528\uFF0C\u5C31**\u53EA\u8F93\u51FA\u4E00\u884C JSON** \u6765\u8C03\u7528\u5DE5\u5177\uFF0C\u4F8B\u5982\uFF1A
|
|
821
827
|
{"tool":"gallery_search","args":{"keyword":"\u767D\u53D1 \u7ACB\u7ED8"}}
|
|
822
828
|
{"tool":"ask_user","args":{"question":"\u60F3\u8981\u4EC0\u4E48\u753B\u98CE\uFF1F"}}
|
|
823
|
-
{"tool":"get_avatar","args":{"userId":""}}
|
|
829
|
+
{"tool":"get_avatar","args":{"userId":""}}\uFF08\u7559\u7A7A = \u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF1B\u4E5F\u53EF\u4EE5\u586B\u88AB @ \u7684\u4EBA\u7684 id\uFF0C\u4E0D\u8BB8\u81EA\u5DF1\u7F16\uFF09
|
|
824
830
|
{"tool":"draw","args":{"prompt":"...","references":["ref1","user1"]}}
|
|
825
831
|
\u4E0D\u60F3\u8C03\u7528\u5DE5\u5177\u65F6\uFF0C\u6B63\u5E38\u8F93\u51FA\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u5373\u53EF\u3002`;
|
|
826
832
|
var AGENT_CONFIRM_RULE_ON = `**\u5FC5\u987B\u5148 ask_user**\uFF1A\u7528\u4E00\u53E5\u8BDD\u544A\u8BC9\u7528\u6237\u300C\u8FD9\u6B21\u4F1A\u53C2\u8003\u54EA\u51E0\u5F20\u56FE + \u5927\u81F4\u753B\u6210\u4EC0\u4E48\u6837\u300D\uFF0C
|
|
@@ -832,7 +838,7 @@ var AGENT_CONFIRM_RULE_OFF = `\u7528\u6237\u9700\u6C42\u5DF2\u7ECF\u660E\u786E\u
|
|
|
832
838
|
var AGENT_JSON_FALLBACK_RULE = `\uFF08\u6CE8\u610F\uFF1A\u5F53\u524D\u63A5\u53E3\u4E0D\u652F\u6301\u51FD\u6570\u8C03\u7528\uFF09\u8BF7\u4F60**\u53EA\u7528\u4E00\u884C JSON** \u6765\u8C03\u7528\u5DE5\u5177\uFF0C\u4E0D\u8981\u8F93\u51FA\u522B\u7684\u5185\u5BB9\uFF1A
|
|
833
839
|
{"tool":"gallery_search","args":{"keyword":"\u767D\u53D1 \u7ACB\u7ED8"}}
|
|
834
840
|
{"tool":"ask_user","args":{"question":"\u60F3\u8981\u4EC0\u4E48\u753B\u98CE\uFF1F"}}
|
|
835
|
-
{"tool":"get_avatar","args":{"userId":""}}
|
|
841
|
+
{"tool":"get_avatar","args":{"userId":""}}\uFF08\u7559\u7A7A = \u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF1B\u4E5F\u53EF\u4EE5\u586B\u88AB @ \u7684\u4EBA\u7684 id\uFF0C\u4E0D\u8BB8\u81EA\u5DF1\u7F16\uFF09
|
|
836
842
|
{"tool":"draw","args":{"prompt":"...","references":["ref1","ref2"]}}
|
|
837
843
|
\u4E0D\u9700\u8981\u8C03\u7528\u5DE5\u5177\u65F6\uFF0C\u6B63\u5E38\u8F93\u51FA\u7ED9\u7528\u6237\u770B\u7684\u4E2D\u6587\u5373\u53EF\u3002`;
|
|
838
844
|
var defaultCommands = [
|
|
@@ -1636,6 +1642,21 @@ function apply(ctx, config) {
|
|
|
1636
1642
|
let selfAvatarId = "";
|
|
1637
1643
|
const atAvatarIds = [];
|
|
1638
1644
|
const atAvatarById = /* @__PURE__ */ new Map();
|
|
1645
|
+
const avatarAllowed = /* @__PURE__ */ new Map();
|
|
1646
|
+
avatarAllowed.set(session.userId, "\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1");
|
|
1647
|
+
for (const t of atTargets) if (t.id) avatarAllowed.set(t.id, t.name || t.id);
|
|
1648
|
+
const resolveAvatarUser = (raw) => {
|
|
1649
|
+
const text = String(raw || "").trim();
|
|
1650
|
+
if (!text || text === session.userId || /^(me|self|自己|我|本人|我的头像|我自己)$/i.test(text)) {
|
|
1651
|
+
return session.userId;
|
|
1652
|
+
}
|
|
1653
|
+
if (avatarAllowed.has(text)) return text;
|
|
1654
|
+
const lower = text.toLowerCase();
|
|
1655
|
+
for (const [id, name2] of avatarAllowed) {
|
|
1656
|
+
if (name2 && (name2 === text || name2.toLowerCase() === lower)) return id;
|
|
1657
|
+
}
|
|
1658
|
+
return "";
|
|
1659
|
+
};
|
|
1639
1660
|
if (avatarOn) {
|
|
1640
1661
|
const selfUrl = await fetchAvatarUrl(session, session.userId);
|
|
1641
1662
|
if (selfUrl) {
|
|
@@ -1665,8 +1686,9 @@ function apply(ctx, config) {
|
|
|
1665
1686
|
baseIds,
|
|
1666
1687
|
atAvatarIds,
|
|
1667
1688
|
selfAvatarId,
|
|
1668
|
-
atTargets
|
|
1669
|
-
|
|
1689
|
+
atTargets,
|
|
1690
|
+
selfUserId: session.userId
|
|
1691
|
+
}, agentCfg, avatarAllowed) },
|
|
1670
1692
|
...history,
|
|
1671
1693
|
{ role: "user", content: userInputText ? userInputText : "\uFF08\u7528\u6237\u6CA1\u6709\u9644\u52A0\u8BF4\u660E\uFF0C\u8BF7\u6309\u6307\u4EE4\u81EA\u5E26\u7684\u63D0\u793A\u8BCD\u6765\uFF09" }
|
|
1672
1694
|
];
|
|
@@ -1765,22 +1787,28 @@ ${output}` }
|
|
|
1765
1787
|
async function toolGetAvatar(args) {
|
|
1766
1788
|
if (!avatarOn) return JSON.stringify({ ok: false, error: "\u5934\u50CF\u53C2\u8003\u56FE\u529F\u80FD\u5DF2\u5173\u95ED" });
|
|
1767
1789
|
const raw = String(args?.userId ?? args?.id ?? args?.user ?? "").trim();
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1790
|
+
const userId = resolveAvatarUser(raw);
|
|
1791
|
+
if (!userId) {
|
|
1792
|
+
const options = [...avatarAllowed.entries()].map(([id2, name2]) => ({ userId: id2, who: name2 }));
|
|
1793
|
+
return JSON.stringify({
|
|
1794
|
+
ok: false,
|
|
1795
|
+
error: `\u4E0D\u8BA4\u8BC6\u300C${raw}\u300D\u3002\u5934\u50CF\u53EA\u80FD\u53D6\u300C\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\u300D\u548C\u300C\u4ED6\u8FD9\u6B21 @ \u5230\u7684\u4EBA\u300D\uFF0C\u4E0D\u80FD\u81EA\u5DF1\u7F16 id`,
|
|
1796
|
+
available: options,
|
|
1797
|
+
note: `\u8981\u753B\u7684\u5982\u679C\u662F\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF0C\u628A userId \u7559\u7A7A\u518D\u8C03\u4E00\u6B21\uFF1B\u5982\u679C\u662F\u522B\u4EBA\uFF0C\u8BA9\u4ED6 @ \u90A3\u4E2A\u4EBA\u518D\u53D1\u4E00\u6B21\u6307\u4EE4\u3002\u73B0\u5728\u53EF\u53D6\uFF1A${options.map((o) => o.who).join("\u3001")}`
|
|
1798
|
+
});
|
|
1799
|
+
}
|
|
1800
|
+
const isSelf = userId === session.userId;
|
|
1801
|
+
const who = avatarAllowed.get(userId) || (isSelf ? "\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1" : userId);
|
|
1802
|
+
const cached = isSelf ? selfAvatarId : atAvatarById.get(userId);
|
|
1803
|
+
if (cached) return JSON.stringify({ ok: true, id: cached, userId, note: `${who}\u7684\u5934\u50CF` });
|
|
1804
|
+
const url = await fetchAvatarUrl(session, userId);
|
|
1805
|
+
if (!url) {
|
|
1806
|
+
return JSON.stringify({ ok: false, error: `\u6CA1\u53D6\u5230\u300C${who}\u300D\u7684\u5934\u50CF\uFF08\u8FD9\u4E2A\u5E73\u53F0\u53EF\u80FD\u4E0D\u63D0\u4F9B\u5934\u50CF\u5730\u5740\uFF09` });
|
|
1776
1807
|
}
|
|
1777
|
-
const
|
|
1778
|
-
if (
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
const id = register("avatar", url, `${raw} \u7684\u5934\u50CF`, "\u5934\u50CF");
|
|
1782
|
-
atAvatarById.set(raw, id);
|
|
1783
|
-
return JSON.stringify({ ok: true, id, userId: raw, note: "\u8FD9\u4E2A\u4EBA\u7684\u5934\u50CF" });
|
|
1808
|
+
const id = register("avatar", url, `${who}\u7684\u5934\u50CF`, "\u5934\u50CF");
|
|
1809
|
+
if (isSelf) selfAvatarId = id;
|
|
1810
|
+
else atAvatarById.set(userId, id);
|
|
1811
|
+
return JSON.stringify({ ok: true, id, userId, note: `${who}\u7684\u5934\u50CF` });
|
|
1784
1812
|
}
|
|
1785
1813
|
async function toolAskUser(args) {
|
|
1786
1814
|
const question = cleanAskMessage(args?.question ?? args?.text ?? args?.message);
|
|
@@ -1814,20 +1842,32 @@ ${output}` }
|
|
|
1814
1842
|
if (avatarOn) {
|
|
1815
1843
|
if (avatarCfg.autoAt !== false) {
|
|
1816
1844
|
for (const target of extractAtIds(String(answer || ""), session.selfId)) {
|
|
1845
|
+
if (!target.id) continue;
|
|
1846
|
+
if (!avatarAllowed.has(target.id)) avatarAllowed.set(target.id, target.name || target.id);
|
|
1847
|
+
const who = avatarAllowed.get(target.id) || target.id;
|
|
1817
1848
|
const cached = atAvatarById.get(target.id);
|
|
1818
1849
|
if (cached) {
|
|
1819
|
-
if (!avatars.some((a) => a.id === cached)) avatars.push({ id: cached, note: `${
|
|
1850
|
+
if (!avatars.some((a) => a.id === cached)) avatars.push({ id: cached, note: `${who} \u7684\u5934\u50CF` });
|
|
1820
1851
|
continue;
|
|
1821
1852
|
}
|
|
1822
1853
|
const url = await fetchAvatarUrl(session, target.id);
|
|
1823
1854
|
if (!url) continue;
|
|
1824
|
-
const id = register("avatar", url, `${
|
|
1855
|
+
const id = register("avatar", url, `${who} \u7684\u5934\u50CF`, "\u5934\u50CF");
|
|
1825
1856
|
atAvatarById.set(target.id, id);
|
|
1826
|
-
|
|
1857
|
+
if (!atAvatarIds.includes(id)) atAvatarIds.push(id);
|
|
1858
|
+
avatars.push({ id, note: `${who} \u7684\u5934\u50CF` });
|
|
1827
1859
|
}
|
|
1828
1860
|
}
|
|
1829
|
-
if (/头像|我的形象|画我|我自己/.test(text) && selfAvatarId) {
|
|
1830
|
-
|
|
1861
|
+
if (/头像|我的形象|画我|我自己/.test(text) && !avatars.some((a) => a.id === selfAvatarId)) {
|
|
1862
|
+
let id = selfAvatarId;
|
|
1863
|
+
if (!id) {
|
|
1864
|
+
const url = await fetchAvatarUrl(session, session.userId);
|
|
1865
|
+
if (url) {
|
|
1866
|
+
id = register("avatar", url, "\u53D1\u6307\u4EE4\u7684\u4EBA\u7684\u5934\u50CF", "\u5934\u50CF");
|
|
1867
|
+
selfAvatarId = id;
|
|
1868
|
+
}
|
|
1869
|
+
}
|
|
1870
|
+
if (id) avatars.push({ id, note: "\u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\u7684\u5934\u50CF" });
|
|
1831
1871
|
}
|
|
1832
1872
|
}
|
|
1833
1873
|
return JSON.stringify({
|
|
@@ -1892,7 +1932,7 @@ Negative prompt: ${String(args.negative_prompt).trim()}` : prompt;
|
|
|
1892
1932
|
});
|
|
1893
1933
|
}
|
|
1894
1934
|
}
|
|
1895
|
-
function buildAgentSystemPrompt(cmdConfig, userInputText, refCount, refs, agentCfg) {
|
|
1935
|
+
function buildAgentSystemPrompt(cmdConfig, userInputText, refCount, refs, agentCfg, avatarAllowed) {
|
|
1896
1936
|
const instructions = renderAgentInstructions(agentCfg.instructions || DEFAULT_AGENT_INSTRUCTIONS, {
|
|
1897
1937
|
command: cmdConfig.name || "",
|
|
1898
1938
|
prompt: cmdConfig.prompt || "",
|
|
@@ -1911,15 +1951,29 @@ Negative prompt: ${String(args.negative_prompt).trim()}` : prompt;
|
|
|
1911
1951
|
`- \u56FE\u5E93\u91CC\u53EF\u4EE5\u641C\u5230\u7684\u53C2\u8003\u56FE\uFF1A${refCount} \u5F20`
|
|
1912
1952
|
];
|
|
1913
1953
|
if (refs.baseIds.length) lines.push(`- \u6307\u4EE4\u9ED8\u8BA4\u53C2\u8003\u56FE\uFF08\u5DF2\u81EA\u52A8\u5E26\u4E0A\uFF0C\u4E0D\u7528\u518D\u586B\uFF09\uFF1A${refs.baseIds.join("\u3001")}`);
|
|
1914
|
-
if (
|
|
1954
|
+
if (cmdConfig.custom) lines.push("- \u8FD9\u662F\u81EA\u5B9A\u4E49\u6307\u4EE4\uFF1A\u7528\u6237\u6CA1\u8BF4\u6E05\u695A\u8981\u753B\u4EC0\u4E48\u65F6\uFF0C\u5148\u7528 ask_user \u95EE\u4E00\u53E5");
|
|
1955
|
+
const avatarLines = ["", "## \u53EF\u53D6\u5934\u50CF\u7684\u4EBA\uFF08get_avatar \u53EA\u8BA4\u8FD9\u4E9B\uFF09"];
|
|
1956
|
+
if (refs.selfAvatarId) {
|
|
1957
|
+
avatarLines.push(`- \u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF1A\u7F16\u53F7 ${refs.selfAvatarId}\uFF08\u4ED6\u60F3\u753B\u300C\u6211\u300D\u65F6\u7528\u8FD9\u4E2A\u7F16\u53F7\uFF0C\u6216 get_avatar \u7684 userId \u7559\u7A7A\u518D\u53D6\u4E00\u6B21\uFF09`);
|
|
1958
|
+
} else {
|
|
1959
|
+
avatarLines.push("- \u53D1\u6307\u4EE4\u7684\u4EBA\u81EA\u5DF1\uFF1Aget_avatar \u7684 userId **\u7559\u7A7A**\u5373\u53EF\uFF08\u8FD9\u8F6E\u8FD8\u6CA1\u63D0\u524D\u53D6\uFF0C\u53D6\u4E86\u624D\u6709\u7F16\u53F7\uFF09");
|
|
1960
|
+
}
|
|
1915
1961
|
if (refs.atAvatarIds.length) {
|
|
1916
|
-
const
|
|
1917
|
-
|
|
1962
|
+
const pairs = refs.atTargets.map((t, i) => `${refs.atAvatarIds[i] || "?"}=${t.name || t.id}`).join("\u3001");
|
|
1963
|
+
avatarLines.push(`- \u88AB @ \u7684\u4EBA\uFF08\u5DF2\u81EA\u52A8\u5E26\u4E0A\uFF0C\u4E0D\u7528\u518D\u586B\uFF09\uFF1A${pairs}`);
|
|
1918
1964
|
} else if (refs.atTargets.length) {
|
|
1919
|
-
|
|
1965
|
+
avatarLines.push(`- \u88AB @ \u7684\u4EBA\uFF1A${refs.atTargets.map((t) => `${t.name || t.id}\uFF08id=${t.id}\uFF09`).join("\u3001")}\uFF0C\u8FD8\u6CA1\u53D6\u5230\u5934\u50CF\uFF0C\u9700\u8981\u5C31\u7528 get_avatar \u586B\u4ED6\u7684 id \u518D\u8BD5`);
|
|
1920
1966
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1967
|
+
const others = [...(avatarAllowed || /* @__PURE__ */ new Map()).entries()].filter(([id]) => id !== refs.selfUserId && !refs.atTargets.some((t) => t.id === id));
|
|
1968
|
+
if (others.length) {
|
|
1969
|
+
avatarLines.push(`- \u540E\u7EED\u5BF9\u8BDD\u91CC\u53C8 @ \u5230\u7684\uFF1A${others.map(([id, name2]) => `${name2}\uFF08id=${id}\uFF09`).join("\u3001")}`);
|
|
1970
|
+
}
|
|
1971
|
+
if (refs.atTargets.length || others.length) {
|
|
1972
|
+
avatarLines.push("- \u4E0A\u9762\u8FD9\u4E9B\u4EBA\u4E4B\u5916\u7684 id **\u4E00\u5F8B\u4F1A\u88AB\u62D2\u7EDD**\uFF0C\u4E0D\u8981\u4ECE\u56FE\u5E93\u63CF\u8FF0\u3001\u5386\u53F2\u6D88\u606F\u6216\u4EFB\u4F55\u522B\u5904\u6284\u4E00\u4E2A id \u5F53\u5934\u50CF\u7528");
|
|
1973
|
+
} else {
|
|
1974
|
+
avatarLines.push("- \u8FD9\u6B21\u6CA1\u6709 @ \u4EFB\u4F55\u4EBA\uFF0C\u6240\u4EE5**\u53EA\u80FD\u53D6\u53D1\u6307\u4EE4\u8005\u81EA\u5DF1\u7684\u5934\u50CF**\uFF08userId \u7559\u7A7A\uFF09\u3002\u4E0D\u8981\u586B\u4EFB\u4F55 id");
|
|
1975
|
+
}
|
|
1976
|
+
return instructions + lines.join("\n") + avatarLines.join("\n");
|
|
1923
1977
|
}
|
|
1924
1978
|
async function requestAgentChat(messages, tools) {
|
|
1925
1979
|
const agentCfg = config.agent || {};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-image-prompt",
|
|
3
3
|
"description": "多功能 AI 图像处理插件:Agent 模式把「查不查图库 / 要不要追问 / 什么时候开画」全交给模型自己决定,支持手办化、Coser 化、Minecraft 化等 47 种风格与自定义提示词",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.1",
|
|
5
5
|
"main": "lib/index.js",
|
|
6
6
|
"typings": "lib/index.d.ts",
|
|
7
7
|
"files": [
|
package/readme.md
CHANGED
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
模型拿到 4 个工具,自己决定怎么走:
|
|
54
54
|
├─ gallery_search(关键词) → 自己想关键词、自己搜图库
|
|
55
55
|
├─ ask_user(问题) → 自己开口问、自己等用户回话
|
|
56
|
-
├─ get_avatar(
|
|
56
|
+
├─ get_avatar(留空/被@的人) → 取头像当参考图(只认自己和被 @ 的人)
|
|
57
57
|
└─ draw(prompt, references) → 自己写提示词、自己挑参考图、开画
|
|
58
58
|
↓
|
|
59
59
|
模型说最后一句话 → 发给用户
|
|
@@ -68,7 +68,7 @@
|
|
|
68
68
|
|---|---|
|
|
69
69
|
| `gallery_search` | 按关键词搜参考图库(关键词由模型自己拟,空格分隔多词)。返回每条的 `id`,写进 `draw` 的 `references` |
|
|
70
70
|
| `ask_user` | 把一句话发给用户**并等他的下一条消息**(他发的图片也会一起带回来,会拿到新编号) |
|
|
71
|
-
| `get_avatar` |
|
|
71
|
+
| `get_avatar` | 取头像当参考图。**只能取两种人**:发指令的人自己(`userId` 留空),或他这次明确 @ 到的人(填 id/昵称)。其它 id 一律拒绝 |
|
|
72
72
|
| `draw` | 真正开画。传最终提示词 + 参考图编号,画好自动发到群里 |
|
|
73
73
|
|
|
74
74
|
### 工作规则(写进提示词,由模型执行)
|
|
@@ -140,6 +140,23 @@
|
|
|
140
140
|
> 平台不提供头像地址时,日志里不会有报错,只是这次没有头像参考图。
|
|
141
141
|
> 想换头像服务就填「自定义头像地址模板」。
|
|
142
142
|
|
|
143
|
+
**只有两种人的头像能取:你自己,和你这次明确 @ 到的人。**
|
|
144
|
+
|
|
145
|
+
头像是按 id 拼 URL 拿的,而 QQ 的头像服务对**随便一个 id** 都会返回一张图片
|
|
146
|
+
(查无此人时给的是默认头像)。也就是说模型只要编一个 id,就能「成功」取到某个
|
|
147
|
+
完全不相干的人的头像,而你根本看不出来。
|
|
148
|
+
|
|
149
|
+
所以 `get_avatar` 有白名单,只认:
|
|
150
|
+
|
|
151
|
+
| 能取 | 怎么填 |
|
|
152
|
+
|---|---|
|
|
153
|
+
| 发指令的人自己 | `userId` **留空**(或写 me / 我 / 自己) |
|
|
154
|
+
| 这次消息里 @ 到的人 | 填上下文里列出的 id 或昵称 |
|
|
155
|
+
|
|
156
|
+
没 @ 任何人时,系统提示词会直接写明「这次只能取发指令者自己的头像」;
|
|
157
|
+
模型要是硬填一个不在名单里的 id,工具会返回 `不认识「xxx」` 并列出可取的人,
|
|
158
|
+
**不会**去拼那个 id 的地址。想画别人,就在指令里 @ 他。
|
|
159
|
+
|
|
143
160
|
### 🖼️ 参考图片组 / 图库
|
|
144
161
|
|
|
145
162
|
参考图以**分组**的方式注册,agent 通过 `gallery_search` 按需搜。
|
package/src/index.ts
CHANGED
|
@@ -250,11 +250,11 @@ export function buildAgentTools(): any[] {
|
|
|
250
250
|
type: 'function',
|
|
251
251
|
function: {
|
|
252
252
|
name: 'get_avatar',
|
|
253
|
-
description: '
|
|
253
|
+
description: '取头像当参考图,返回它的编号。**只能取两种人的头像**:发指令的人自己(userId 留空/写 me),或他这次消息里明确 @ 到的人(填上下文「可取头像的人」里列出的 id/名字)。其它 id 一律会被拒绝。',
|
|
254
254
|
parameters: {
|
|
255
255
|
type: 'object',
|
|
256
256
|
properties: {
|
|
257
|
-
userId: { type: 'string', description: '
|
|
257
|
+
userId: { type: 'string', description: '留空或写 me/self/我 = 发指令的人自己;也可以填上下文里「可取头像的人」列出的 id 或昵称(即被 @ 的人)。**不要自己猜 id**' },
|
|
258
258
|
},
|
|
259
259
|
required: [],
|
|
260
260
|
},
|
|
@@ -1161,7 +1161,9 @@ const DEFAULT_AGENT_INSTRUCTIONS = `你是 QQ 群里的绘图助手。用户发
|
|
|
1161
1161
|
- gallery_search:按关键词搜索参考图库。**涉及具体角色/立绘时必须先搜一次**。
|
|
1162
1162
|
多个关键词用空格分隔(如「白发 立绘」),全部命中的排在最前;搜不到就换个词再搜。
|
|
1163
1163
|
- ask_user:把问题发给用户**并等他回复**(他发的图也会一起带回来)。
|
|
1164
|
-
- get_avatar
|
|
1164
|
+
- get_avatar:取头像当参考图。**只能取两种人**:发指令的人自己(userId 留空或写 me),
|
|
1165
|
+
以及他这次消息里明确 @ 到的人(填上下文「可取头像的人」里列出的 id 或昵称)。
|
|
1166
|
+
其它任何 id 都会被拒绝,不要猜。
|
|
1165
1167
|
- draw:真正开始画。把 prompt 和挑中的参考图编号交进去,画好会自动发到群里。
|
|
1166
1168
|
|
|
1167
1169
|
工作规则:
|
|
@@ -1183,8 +1185,12 @@ const DEFAULT_AGENT_INSTRUCTIONS = `你是 QQ 群里的绘图助手。用户发
|
|
|
1183
1185
|
8. 【没指定参考图时先问一句】用户这次没发图、没 @ 人、指令本身也没有默认参考图,你也搜不到合适的立绘时,
|
|
1184
1186
|
**不要直接 draw**。先用 ask_user 问一句要不要参考图,并给出选项(例如「用你自己的头像 / 用 @某某 的头像 /
|
|
1185
1187
|
我帮你从图库找一张 / 不用参考直接画」)。用户说「不用 / 随便 / 直接画」就立刻开画,**不要问第二次**。
|
|
1186
|
-
9.
|
|
1187
|
-
|
|
1188
|
+
9. 【头像只能取「我」和「被 @ 的人」】
|
|
1189
|
+
- 用户说「画我」「用我的形象」「我的头像」→ get_avatar 的 userId **留空**,取他自己的头像;
|
|
1190
|
+
- 用户 @ 了谁 → 那个人的头像已经自动带上了(上下文里会列出编号),直接用那个编号即可,
|
|
1191
|
+
需要时也可以把他的 id 或昵称填进 get_avatar 再取一次;
|
|
1192
|
+
- **除此之外没有第三种人**。没 @ 别人时绝不许取别人的头像,也不要自己编 userId
|
|
1193
|
+
(编出来的 id 会拿到完全不相干的人的头像,这是严重错误)。
|
|
1188
1194
|
10. 【默认不润色,用户点头才润色】把用户的话**原封不动**交给绘图模型就是最好的默认值:
|
|
1189
1195
|
- **不要**主动扩写、不要补画风/光线/材质/镜头、不要翻成英文、不要加「masterpiece」这类词;
|
|
1190
1196
|
- 用户明确说「帮我润色 / 优化一下 / 写详细点」时,你才把提示词写得更完整;
|
|
@@ -1196,7 +1202,7 @@ const DEFAULT_AGENT_INSTRUCTIONS = `你是 QQ 群里的绘图助手。用户发
|
|
|
1196
1202
|
如果你所在的接口不支持函数调用,就**只输出一行 JSON** 来调用工具,例如:
|
|
1197
1203
|
{"tool":"gallery_search","args":{"keyword":"白发 立绘"}}
|
|
1198
1204
|
{"tool":"ask_user","args":{"question":"想要什么画风?"}}
|
|
1199
|
-
{"tool":"get_avatar","args":{"userId":""}}
|
|
1205
|
+
{"tool":"get_avatar","args":{"userId":""}}(留空 = 发指令的人自己;也可以填被 @ 的人的 id,不许自己编)
|
|
1200
1206
|
{"tool":"draw","args":{"prompt":"...","references":["ref1","user1"]}}
|
|
1201
1207
|
不想调用工具时,正常输出给用户看的中文即可。`
|
|
1202
1208
|
|
|
@@ -1212,7 +1218,7 @@ const AGENT_CONFIRM_RULE_OFF = `用户需求已经明确的,直接调用 draw
|
|
|
1212
1218
|
const AGENT_JSON_FALLBACK_RULE = `(注意:当前接口不支持函数调用)请你**只用一行 JSON** 来调用工具,不要输出别的内容:
|
|
1213
1219
|
{"tool":"gallery_search","args":{"keyword":"白发 立绘"}}
|
|
1214
1220
|
{"tool":"ask_user","args":{"question":"想要什么画风?"}}
|
|
1215
|
-
{"tool":"get_avatar","args":{"userId":""}}
|
|
1221
|
+
{"tool":"get_avatar","args":{"userId":""}}(留空 = 发指令的人自己;也可以填被 @ 的人的 id,不许自己编)
|
|
1216
1222
|
{"tool":"draw","args":{"prompt":"...","references":["ref1","ref2"]}}
|
|
1217
1223
|
不需要调用工具时,正常输出给用户看的中文即可。`
|
|
1218
1224
|
|
|
@@ -2144,6 +2150,28 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2144
2150
|
let selfAvatarId = ''
|
|
2145
2151
|
const atAvatarIds: string[] = []
|
|
2146
2152
|
const atAvatarById = new Map<string, string>()
|
|
2153
|
+
/**
|
|
2154
|
+
* 本次**允许**取头像的人:只有发指令者自己 + 他明确 @ 到的人。
|
|
2155
|
+
* 为什么必须挡:头像是按 id 拼 URL 的,而 QQ 的头像服务对**任何** id 都会返回一张图
|
|
2156
|
+
* (查无此人时给默认头像),所以模型随手编一个 id 也能「成功」拿到陌生人的头像。
|
|
2157
|
+
* 没有明确 @ 就不是明确指定,一律拒绝。
|
|
2158
|
+
*/
|
|
2159
|
+
const avatarAllowed = new Map<string, string>()
|
|
2160
|
+
avatarAllowed.set(session.userId, '发指令的人自己')
|
|
2161
|
+
for (const t of atTargets) if (t.id) avatarAllowed.set(t.id, t.name || t.id)
|
|
2162
|
+
/** 把「我 / me / 空 / 昵称」解析成一个被允许的 userId,解析不出来返回空 */
|
|
2163
|
+
const resolveAvatarUser = (raw: string): string => {
|
|
2164
|
+
const text = String(raw || '').trim()
|
|
2165
|
+
if (!text || text === session.userId || /^(me|self|自己|我|本人|我的头像|我自己)$/i.test(text)) {
|
|
2166
|
+
return session.userId
|
|
2167
|
+
}
|
|
2168
|
+
if (avatarAllowed.has(text)) return text
|
|
2169
|
+
const lower = text.toLowerCase()
|
|
2170
|
+
for (const [id, name] of avatarAllowed) {
|
|
2171
|
+
if (name && (name === text || name.toLowerCase() === lower)) return id
|
|
2172
|
+
}
|
|
2173
|
+
return ''
|
|
2174
|
+
}
|
|
2147
2175
|
if (avatarOn) {
|
|
2148
2176
|
const selfUrl = await fetchAvatarUrl(session, session.userId)
|
|
2149
2177
|
if (selfUrl) {
|
|
@@ -2171,8 +2199,8 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2171
2199
|
|
|
2172
2200
|
const messages: any[] = [
|
|
2173
2201
|
{ role: 'system', content: buildAgentSystemPrompt(cmdConfig, userInputText, pool.length, {
|
|
2174
|
-
userIds, baseIds, atAvatarIds, selfAvatarId, atTargets,
|
|
2175
|
-
}, agentCfg) },
|
|
2202
|
+
userIds, baseIds, atAvatarIds, selfAvatarId, atTargets, selfUserId: session.userId,
|
|
2203
|
+
}, agentCfg, avatarAllowed) },
|
|
2176
2204
|
...history,
|
|
2177
2205
|
{ role: 'user', content: userInputText ? userInputText : '(用户没有附加说明,请按指令自带的提示词来)' },
|
|
2178
2206
|
]
|
|
@@ -2279,28 +2307,36 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2279
2307
|
})
|
|
2280
2308
|
}
|
|
2281
2309
|
|
|
2282
|
-
/**
|
|
2310
|
+
/** 取头像:只能是发指令的人自己,或他这次明确 @ 到的人 */
|
|
2283
2311
|
async function toolGetAvatar(args: any): Promise<string> {
|
|
2284
2312
|
if (!avatarOn) return JSON.stringify({ ok: false, error: '头像参考图功能已关闭' })
|
|
2285
2313
|
const raw = String(args?.userId ?? args?.id ?? args?.user ?? '').trim()
|
|
2286
|
-
|
|
2287
|
-
|
|
2288
|
-
|
|
2289
|
-
}
|
|
2290
|
-
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2314
|
+
const userId = resolveAvatarUser(raw)
|
|
2315
|
+
|
|
2316
|
+
if (!userId) {
|
|
2317
|
+
const options = [...avatarAllowed.entries()].map(([id, name]) => ({ userId: id, who: name }))
|
|
2318
|
+
return JSON.stringify({
|
|
2319
|
+
ok: false,
|
|
2320
|
+
error: `不认识「${raw}」。头像只能取「发指令的人自己」和「他这次 @ 到的人」,不能自己编 id`,
|
|
2321
|
+
available: options,
|
|
2322
|
+
note: `要画的如果是发指令的人自己,把 userId 留空再调一次;如果是别人,让他 @ 那个人再发一次指令。现在可取:${options.map(o => o.who).join('、')}`,
|
|
2323
|
+
})
|
|
2294
2324
|
}
|
|
2295
2325
|
|
|
2296
|
-
const
|
|
2297
|
-
|
|
2326
|
+
const isSelf = userId === session.userId
|
|
2327
|
+
const who = avatarAllowed.get(userId) || (isSelf ? '发指令的人自己' : userId)
|
|
2328
|
+
|
|
2329
|
+
const cached = isSelf ? selfAvatarId : atAvatarById.get(userId)
|
|
2330
|
+
if (cached) return JSON.stringify({ ok: true, id: cached, userId, note: `${who}的头像` })
|
|
2298
2331
|
|
|
2299
|
-
const url = await fetchAvatarUrl(session,
|
|
2300
|
-
if (!url)
|
|
2301
|
-
|
|
2302
|
-
|
|
2303
|
-
|
|
2332
|
+
const url = await fetchAvatarUrl(session, userId)
|
|
2333
|
+
if (!url) {
|
|
2334
|
+
return JSON.stringify({ ok: false, error: `没取到「${who}」的头像(这个平台可能不提供头像地址)` })
|
|
2335
|
+
}
|
|
2336
|
+
const id = register('avatar', url, `${who}的头像`, '头像')
|
|
2337
|
+
if (isSelf) selfAvatarId = id
|
|
2338
|
+
else atAvatarById.set(userId, id)
|
|
2339
|
+
return JSON.stringify({ ok: true, id, userId, note: `${who}的头像` })
|
|
2304
2340
|
}
|
|
2305
2341
|
|
|
2306
2342
|
/** 提问并等用户的下一条消息(图也会一起带回来) */
|
|
@@ -2341,21 +2377,35 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2341
2377
|
if (avatarOn) {
|
|
2342
2378
|
if (avatarCfg.autoAt !== false) {
|
|
2343
2379
|
for (const target of extractAtIds(String(answer || ''), session.selfId)) {
|
|
2380
|
+
if (!target.id) continue
|
|
2381
|
+
// 他在回复里明确 @ 了,这个人从此也进入白名单
|
|
2382
|
+
if (!avatarAllowed.has(target.id)) avatarAllowed.set(target.id, target.name || target.id)
|
|
2383
|
+
const who = avatarAllowed.get(target.id) || target.id
|
|
2344
2384
|
const cached = atAvatarById.get(target.id)
|
|
2345
2385
|
if (cached) {
|
|
2346
|
-
if (!avatars.some(a => a.id === cached)) avatars.push({ id: cached, note: `${
|
|
2386
|
+
if (!avatars.some(a => a.id === cached)) avatars.push({ id: cached, note: `${who} 的头像` })
|
|
2347
2387
|
continue
|
|
2348
2388
|
}
|
|
2349
2389
|
const url = await fetchAvatarUrl(session, target.id)
|
|
2350
2390
|
if (!url) continue
|
|
2351
|
-
const id = register('avatar', url, `${
|
|
2391
|
+
const id = register('avatar', url, `${who} 的头像`, '头像')
|
|
2352
2392
|
atAvatarById.set(target.id, id)
|
|
2353
|
-
|
|
2393
|
+
if (!atAvatarIds.includes(id)) atAvatarIds.push(id)
|
|
2394
|
+
avatars.push({ id, note: `${who} 的头像` })
|
|
2354
2395
|
}
|
|
2355
2396
|
}
|
|
2356
2397
|
// 「用我的头像」「画我」——就算关闭了 autoSelf,用户明确开口了就给他
|
|
2357
|
-
if (/头像|我的形象|画我|我自己/.test(text) && selfAvatarId) {
|
|
2358
|
-
|
|
2398
|
+
if (/头像|我的形象|画我|我自己/.test(text) && !avatars.some(a => a.id === selfAvatarId)) {
|
|
2399
|
+
// 用户明确开口要自己的头像,没登记过就现取一次
|
|
2400
|
+
let id = selfAvatarId
|
|
2401
|
+
if (!id) {
|
|
2402
|
+
const url = await fetchAvatarUrl(session, session.userId)
|
|
2403
|
+
if (url) {
|
|
2404
|
+
id = register('avatar', url, '发指令的人的头像', '头像')
|
|
2405
|
+
selfAvatarId = id
|
|
2406
|
+
}
|
|
2407
|
+
}
|
|
2408
|
+
if (id) avatars.push({ id, note: '发指令的人自己的头像' })
|
|
2359
2409
|
}
|
|
2360
2410
|
}
|
|
2361
2411
|
|
|
@@ -2454,8 +2504,10 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2454
2504
|
atAvatarIds: string[]
|
|
2455
2505
|
selfAvatarId: string
|
|
2456
2506
|
atTargets: { id: string, name: string }[]
|
|
2507
|
+
selfUserId: string
|
|
2457
2508
|
},
|
|
2458
|
-
agentCfg: AgentConfig
|
|
2509
|
+
agentCfg: AgentConfig,
|
|
2510
|
+
avatarAllowed?: Map<string, string>
|
|
2459
2511
|
): string {
|
|
2460
2512
|
const instructions = renderAgentInstructions(agentCfg.instructions || DEFAULT_AGENT_INSTRUCTIONS, {
|
|
2461
2513
|
command: cmdConfig.name || '',
|
|
@@ -2474,16 +2526,33 @@ export function apply(ctx: Context, config: CommandConfig) {
|
|
|
2474
2526
|
`- 图库里可以搜到的参考图:${refCount} 张`,
|
|
2475
2527
|
]
|
|
2476
2528
|
if (refs.baseIds.length) lines.push(`- 指令默认参考图(已自动带上,不用再填):${refs.baseIds.join('、')}`)
|
|
2477
|
-
if (
|
|
2529
|
+
if (cmdConfig.custom) lines.push('- 这是自定义指令:用户没说清楚要画什么时,先用 ask_user 问一句')
|
|
2530
|
+
|
|
2531
|
+
// 头像:只列「发指令的人自己」+「被 @ 的人」,并写明其它 id 一律拒绝
|
|
2532
|
+
const avatarLines: string[] = ['', '## 可取头像的人(get_avatar 只认这些)']
|
|
2533
|
+
if (refs.selfAvatarId) {
|
|
2534
|
+
avatarLines.push(`- 发指令的人自己:编号 ${refs.selfAvatarId}(他想画「我」时用这个编号,或 get_avatar 的 userId 留空再取一次)`)
|
|
2535
|
+
} else {
|
|
2536
|
+
avatarLines.push('- 发指令的人自己:get_avatar 的 userId **留空**即可(这轮还没提前取,取了才有编号)')
|
|
2537
|
+
}
|
|
2478
2538
|
if (refs.atAvatarIds.length) {
|
|
2479
|
-
const
|
|
2480
|
-
|
|
2539
|
+
const pairs = refs.atTargets.map((t, i) => `${refs.atAvatarIds[i] || '?'}=${t.name || t.id}`).join('、')
|
|
2540
|
+
avatarLines.push(`- 被 @ 的人(已自动带上,不用再填):${pairs}`)
|
|
2481
2541
|
} else if (refs.atTargets.length) {
|
|
2482
|
-
|
|
2542
|
+
avatarLines.push(`- 被 @ 的人:${refs.atTargets.map(t => `${t.name || t.id}(id=${t.id})`).join('、')},还没取到头像,需要就用 get_avatar 填他的 id 再试`)
|
|
2543
|
+
}
|
|
2544
|
+
const others = [...(avatarAllowed || new Map<string, string>()).entries()]
|
|
2545
|
+
.filter(([id]) => id !== refs.selfUserId && !refs.atTargets.some(t => t.id === id))
|
|
2546
|
+
if (others.length) {
|
|
2547
|
+
avatarLines.push(`- 后续对话里又 @ 到的:${others.map(([id, name]) => `${name}(id=${id})`).join('、')}`)
|
|
2548
|
+
}
|
|
2549
|
+
if (refs.atTargets.length || others.length) {
|
|
2550
|
+
avatarLines.push('- 上面这些人之外的 id **一律会被拒绝**,不要从图库描述、历史消息或任何别处抄一个 id 当头像用')
|
|
2551
|
+
} else {
|
|
2552
|
+
avatarLines.push('- 这次没有 @ 任何人,所以**只能取发指令者自己的头像**(userId 留空)。不要填任何 id')
|
|
2483
2553
|
}
|
|
2484
|
-
if (cmdConfig.custom) lines.push('- 这是自定义指令:用户没说清楚要画什么时,先用 ask_user 问一句')
|
|
2485
2554
|
|
|
2486
|
-
return instructions + lines.join('\n')
|
|
2555
|
+
return instructions + lines.join('\n') + avatarLines.join('\n')
|
|
2487
2556
|
}
|
|
2488
2557
|
|
|
2489
2558
|
/** 发一次 agent 请求,返回助手消息与它想调的工具 */
|