koishi-plugin-dify-ai 0.1.7 → 0.1.9
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/config.d.ts +8 -5
- package/lib/index.js +132 -38
- package/lib/requester/variables.d.ts +5 -1
- package/lib/types.d.ts +5 -0
- package/package.json +1 -1
package/lib/config.d.ts
CHANGED
|
@@ -52,6 +52,9 @@ export type VariableEntry = {
|
|
|
52
52
|
source: 'constant';
|
|
53
53
|
field: string;
|
|
54
54
|
value: string;
|
|
55
|
+
} | {
|
|
56
|
+
source: 'json';
|
|
57
|
+
template: string;
|
|
55
58
|
};
|
|
56
59
|
/** 作用域的一行:维度 + 值 */
|
|
57
60
|
export interface ScopeRow {
|
|
@@ -111,8 +114,8 @@ export interface Config {
|
|
|
111
114
|
}
|
|
112
115
|
export declare const Config: Schema<Config>;
|
|
113
116
|
/**
|
|
114
|
-
*
|
|
115
|
-
* 数量与单文件大小 0 均为不限,大小仍与 Dify 各类型上限取较小值。
|
|
117
|
+
* 上传消息文件配置(含历史形态迁移:0.1.x 布尔、0.1.7 mode)。
|
|
118
|
+
* 数量与单文件大小 0 与 -1 均为不限,大小仍与 Dify 各类型上限取较小值。
|
|
116
119
|
*/
|
|
117
120
|
export declare function resolveUploadConfig(config: Config): {
|
|
118
121
|
enabled: boolean;
|
|
@@ -120,9 +123,9 @@ export declare function resolveUploadConfig(config: Config): {
|
|
|
120
123
|
maxMb: number;
|
|
121
124
|
};
|
|
122
125
|
/**
|
|
123
|
-
*
|
|
124
|
-
*
|
|
125
|
-
*
|
|
126
|
+
* 引用触发消息配置(含历史形态迁移:0.1.x 布尔与 quoteTrigger 透传、0.1.7 mode、布尔开关新形态)。
|
|
127
|
+
* 迁移判据沿用:旧布尔被透传保留且配置未被用户改动(默认形态)时以旧布尔为准。
|
|
128
|
+
* 阈值 -1 与 0 同为总是引用(比较 elapsed >= 阈值 自然兼容)。
|
|
126
129
|
*/
|
|
127
130
|
export declare function resolveQuoteConfig(config: Config): {
|
|
128
131
|
enabled: boolean;
|
package/lib/index.js
CHANGED
|
@@ -49,6 +49,15 @@ var en_US_default = {
|
|
|
49
49
|
|
|
50
50
|
// src/config.ts
|
|
51
51
|
var import_koishi = require("koishi");
|
|
52
|
+
|
|
53
|
+
// src/types.ts
|
|
54
|
+
function isMessageTrigger(type) {
|
|
55
|
+
return type !== "schedule" && type !== "density";
|
|
56
|
+
}
|
|
57
|
+
__name(isMessageTrigger, "isMessageTrigger");
|
|
58
|
+
var JSON_PLACEHOLDER = /\{\{\s*(\w+)(?::(\d+))?\s*\}\}/g;
|
|
59
|
+
|
|
60
|
+
// src/config.ts
|
|
52
61
|
var appTypeSchema = import_koishi.Schema.union([
|
|
53
62
|
import_koishi.Schema.const("auto").description("自动探测"),
|
|
54
63
|
import_koishi.Schema.const("chat").description("Chatbot"),
|
|
@@ -83,7 +92,7 @@ var conditionSchema = import_koishi.Schema.union([
|
|
|
83
92
|
import_koishi.Schema.object({
|
|
84
93
|
type: import_koishi.Schema.const("schedule").required(),
|
|
85
94
|
cron: import_koishi.Schema.string().default("").description("Cron 表达式"),
|
|
86
|
-
intervalMinutes: import_koishi.Schema.number().default(
|
|
95
|
+
intervalMinutes: import_koishi.Schema.number().default(-1).min(-1).description("间隔分钟")
|
|
87
96
|
}).default({ type: "schedule", cron: "", intervalMinutes: 0 }).description("定时"),
|
|
88
97
|
import_koishi.Schema.object({
|
|
89
98
|
type: import_koishi.Schema.const("density").required(),
|
|
@@ -121,7 +130,7 @@ var variableSchema = import_koishi.Schema.union([
|
|
|
121
130
|
import_koishi.Schema.object({
|
|
122
131
|
source: import_koishi.Schema.const("history").required(),
|
|
123
132
|
field: import_koishi.Schema.string().required().description("字段名"),
|
|
124
|
-
limit: import_koishi.Schema.
|
|
133
|
+
limit: import_koishi.Schema.number().default(-1).min(-1).max(100).description("条数,0 用全局")
|
|
125
134
|
}).default({ source: "history", field: "", limit: 0 }).description("历史消息"),
|
|
126
135
|
import_koishi.Schema.object({
|
|
127
136
|
source: import_koishi.Schema.const("meta").required(),
|
|
@@ -132,17 +141,32 @@ var variableSchema = import_koishi.Schema.union([
|
|
|
132
141
|
source: import_koishi.Schema.const("constant").required(),
|
|
133
142
|
field: import_koishi.Schema.string().required().description("字段名"),
|
|
134
143
|
value: import_koishi.Schema.string().role("textarea").required().description("固定文本")
|
|
135
|
-
}).default({ source: "constant", field: "", value: "" }).description("常量文本")
|
|
144
|
+
}).default({ source: "constant", field: "", value: "" }).description("常量文本"),
|
|
145
|
+
import_koishi.Schema.object({
|
|
146
|
+
source: import_koishi.Schema.const("json").required(),
|
|
147
|
+
template: import_koishi.Schema.string().role("textarea").required().description("JSON 对象")
|
|
148
|
+
}).default({ source: "json", template: "" }).description("JSON 对象")
|
|
136
149
|
]);
|
|
137
150
|
var quoteSchema = import_koishi.Schema.union([
|
|
138
|
-
import_koishi.Schema.
|
|
139
|
-
|
|
140
|
-
|
|
151
|
+
import_koishi.Schema.intersect([
|
|
152
|
+
import_koishi.Schema.object({
|
|
153
|
+
enabled: import_koishi.Schema.boolean().default(true).description("开启")
|
|
154
|
+
}),
|
|
155
|
+
import_koishi.Schema.union([
|
|
156
|
+
import_koishi.Schema.object({
|
|
157
|
+
enabled: import_koishi.Schema.const(true).required(),
|
|
158
|
+
minElapsedSeconds: import_koishi.Schema.number().min(-1).default(-1).description("回复耗时多少秒才引用,0 总是引用")
|
|
159
|
+
}),
|
|
160
|
+
import_koishi.Schema.object({})
|
|
161
|
+
])
|
|
162
|
+
]),
|
|
163
|
+
import_koishi.Schema.boolean(),
|
|
164
|
+
import_koishi.Schema.object({ mode: import_koishi.Schema.const("off").required() }),
|
|
141
165
|
import_koishi.Schema.object({
|
|
142
166
|
mode: import_koishi.Schema.const("on").required(),
|
|
143
|
-
minElapsedSeconds: import_koishi.Schema.
|
|
144
|
-
})
|
|
145
|
-
]);
|
|
167
|
+
minElapsedSeconds: import_koishi.Schema.number().min(-1).default(-1)
|
|
168
|
+
})
|
|
169
|
+
]).default({ enabled: true, minElapsedSeconds: -1 });
|
|
146
170
|
var cooldownSchema = import_koishi.Schema.union([
|
|
147
171
|
import_koishi.Schema.object({
|
|
148
172
|
mode: import_koishi.Schema.const("off").required()
|
|
@@ -158,16 +182,27 @@ var cooldownSchema = import_koishi.Schema.union([
|
|
|
158
182
|
}).default({ mode: "sliding", minSeconds: 30, maxSeconds: 120 }).description("滑动窗口")
|
|
159
183
|
]);
|
|
160
184
|
var uploadSchema = import_koishi.Schema.union([
|
|
161
|
-
import_koishi.Schema.
|
|
162
|
-
|
|
163
|
-
|
|
185
|
+
import_koishi.Schema.intersect([
|
|
186
|
+
import_koishi.Schema.object({
|
|
187
|
+
enabled: import_koishi.Schema.boolean().default(true).description("开启")
|
|
188
|
+
}),
|
|
189
|
+
import_koishi.Schema.union([
|
|
190
|
+
import_koishi.Schema.object({
|
|
191
|
+
enabled: import_koishi.Schema.const(true).required(),
|
|
192
|
+
maxCount: import_koishi.Schema.number().min(-1).default(-1).description("数量上限,0 不限"),
|
|
193
|
+
maxSizeMb: import_koishi.Schema.number().min(-1).default(-1).description("单文件大小上限 MB,0 不限")
|
|
194
|
+
}),
|
|
195
|
+
import_koishi.Schema.object({})
|
|
196
|
+
])
|
|
197
|
+
]),
|
|
198
|
+
import_koishi.Schema.boolean(),
|
|
199
|
+
import_koishi.Schema.object({ mode: import_koishi.Schema.const("off").required() }),
|
|
164
200
|
import_koishi.Schema.object({
|
|
165
201
|
mode: import_koishi.Schema.const("on").required(),
|
|
166
|
-
maxCount: import_koishi.Schema.
|
|
167
|
-
maxSizeMb: import_koishi.Schema.
|
|
168
|
-
})
|
|
169
|
-
|
|
170
|
-
]);
|
|
202
|
+
maxCount: import_koishi.Schema.number().min(-1).default(-1),
|
|
203
|
+
maxSizeMb: import_koishi.Schema.number().min(-1).default(-1)
|
|
204
|
+
})
|
|
205
|
+
]).default({ enabled: true, maxCount: -1, maxSizeMb: -1 });
|
|
171
206
|
var Config = import_koishi.Schema.intersect([
|
|
172
207
|
import_koishi.Schema.object({
|
|
173
208
|
apps: import_koishi.Schema.array(
|
|
@@ -185,7 +220,7 @@ var Config = import_koishi.Schema.intersect([
|
|
|
185
220
|
import_koishi.Schema.object({
|
|
186
221
|
name: import_koishi.Schema.string().required().description("规则名"),
|
|
187
222
|
enabled: import_koishi.Schema.boolean().default(true).description("启用"),
|
|
188
|
-
priority: import_koishi.Schema.number().default(
|
|
223
|
+
priority: import_koishi.Schema.number().default(-1).description("优先级,大者先匹配"),
|
|
189
224
|
app: import_koishi.Schema.string().required().description("应用名"),
|
|
190
225
|
conversationScope: import_koishi.Schema.union([
|
|
191
226
|
import_koishi.Schema.const("per-guild").description("按群聊"),
|
|
@@ -214,9 +249,9 @@ var Config = import_koishi.Schema.intersect([
|
|
|
214
249
|
}).description("触发规则"),
|
|
215
250
|
import_koishi.Schema.object({
|
|
216
251
|
parseElements: import_koishi.Schema.boolean().default(false).description("解析回复中的消息元素"),
|
|
217
|
-
quote: quoteSchema.
|
|
218
|
-
maxSegmentLength: import_koishi.Schema.
|
|
219
|
-
uploadFiles: uploadSchema.
|
|
252
|
+
quote: quoteSchema.description("引用触发消息"),
|
|
253
|
+
maxSegmentLength: import_koishi.Schema.number().min(-1).default(-1).description("分段长度,0 不分段"),
|
|
254
|
+
uploadFiles: uploadSchema.description("上传消息中的文件")
|
|
220
255
|
}).description("回复行为"),
|
|
221
256
|
import_koishi.Schema.object({
|
|
222
257
|
requestTimeout: import_koishi.Schema.natural().role("ms").default(3e5).description("请求超时"),
|
|
@@ -309,6 +344,17 @@ function toScope(rows) {
|
|
|
309
344
|
}
|
|
310
345
|
__name(toScope, "toScope");
|
|
311
346
|
function toVariable(entry) {
|
|
347
|
+
if (entry.source === "json") {
|
|
348
|
+
const template = entry.template ?? "";
|
|
349
|
+
if (!template.trim()) return null;
|
|
350
|
+
try {
|
|
351
|
+
const probe = JSON.parse(template.replace(JSON_PLACEHOLDER, "0"));
|
|
352
|
+
if (typeof probe !== "object" || probe === null || Array.isArray(probe)) return null;
|
|
353
|
+
} catch {
|
|
354
|
+
return null;
|
|
355
|
+
}
|
|
356
|
+
return { field: "", source: { type: "json", template } };
|
|
357
|
+
}
|
|
312
358
|
const field = entry.field?.trim();
|
|
313
359
|
if (!field) return null;
|
|
314
360
|
if (entry.source === "constant") {
|
|
@@ -328,25 +374,30 @@ function toVariable(entry) {
|
|
|
328
374
|
}
|
|
329
375
|
__name(toVariable, "toVariable");
|
|
330
376
|
function resolveUploadConfig(config) {
|
|
331
|
-
|
|
332
|
-
|
|
377
|
+
const upload = config.uploadFiles;
|
|
378
|
+
if (typeof upload === "boolean") {
|
|
379
|
+
return upload ? { enabled: true, maxCount: 0, maxMb: 0 } : { enabled: false, maxCount: 0, maxMb: 0 };
|
|
380
|
+
}
|
|
381
|
+
if (upload?.mode === "off" || upload?.enabled === false) {
|
|
382
|
+
return { enabled: false, maxCount: 0, maxMb: 0 };
|
|
333
383
|
}
|
|
334
|
-
if (config.uploadFiles?.mode === "off") return { enabled: false, maxCount: 0, maxMb: 0 };
|
|
335
384
|
return {
|
|
336
385
|
enabled: true,
|
|
337
|
-
maxCount: Number(
|
|
338
|
-
maxMb: Number(
|
|
386
|
+
maxCount: Number(upload?.maxCount) || 0,
|
|
387
|
+
maxMb: Number(upload?.maxSizeMb) || 0
|
|
339
388
|
};
|
|
340
389
|
}
|
|
341
390
|
__name(resolveUploadConfig, "resolveUploadConfig");
|
|
342
391
|
function resolveQuoteConfig(config) {
|
|
343
392
|
const quote = config.quote;
|
|
344
|
-
|
|
345
|
-
if (
|
|
393
|
+
if (typeof quote === "boolean") return { enabled: quote, minElapsedSeconds: 0 };
|
|
394
|
+
if (quote?.mode === "off") return { enabled: false, minElapsedSeconds: 0 };
|
|
395
|
+
const threshold = Number(quote?.minElapsedSeconds) || 0;
|
|
396
|
+
const untouched = !(threshold > 0) && quote?.enabled !== false;
|
|
397
|
+
if (typeof config.quoteTrigger === "boolean" && untouched) {
|
|
346
398
|
return { enabled: config.quoteTrigger, minElapsedSeconds: 0 };
|
|
347
399
|
}
|
|
348
|
-
|
|
349
|
-
return { enabled: true, minElapsedSeconds: Number(quote?.minElapsedSeconds) || 0 };
|
|
400
|
+
return { enabled: quote?.mode === "on" ? true : quote?.enabled !== false, minElapsedSeconds: threshold };
|
|
350
401
|
}
|
|
351
402
|
__name(resolveQuoteConfig, "resolveQuoteConfig");
|
|
352
403
|
function toCooldown(entry) {
|
|
@@ -1198,12 +1249,6 @@ var TriggerEngine = class {
|
|
|
1198
1249
|
}
|
|
1199
1250
|
};
|
|
1200
1251
|
|
|
1201
|
-
// src/types.ts
|
|
1202
|
-
function isMessageTrigger(type) {
|
|
1203
|
-
return type !== "schedule" && type !== "density";
|
|
1204
|
-
}
|
|
1205
|
-
__name(isMessageTrigger, "isMessageTrigger");
|
|
1206
|
-
|
|
1207
1252
|
// src/requester/files.ts
|
|
1208
1253
|
var import_promises = require("fs/promises");
|
|
1209
1254
|
var import_fs = require("fs");
|
|
@@ -1466,11 +1511,55 @@ function resolveSource(source, fireCtx, history, now) {
|
|
|
1466
1511
|
}
|
|
1467
1512
|
}
|
|
1468
1513
|
__name(resolveSource, "resolveSource");
|
|
1514
|
+
var META_PLACEHOLDERS = /* @__PURE__ */ new Set(["triggerType", "ruleName", "triggerTime"]);
|
|
1515
|
+
function resolvePlaceholderValue(name2, limit, fireCtx, history, now) {
|
|
1516
|
+
if (name2 === "history") {
|
|
1517
|
+
const channelKey = channelKeyOf(fireCtx.platform, fireCtx.channelId);
|
|
1518
|
+
return history.toVariable(history.get(channelKey, limit ?? history.limit));
|
|
1519
|
+
}
|
|
1520
|
+
if (name2 === "isDirect") {
|
|
1521
|
+
return fireCtx.session?.isDirect ?? fireCtx.isDirect ?? false;
|
|
1522
|
+
}
|
|
1523
|
+
if (META_PLACEHOLDERS.has(name2)) {
|
|
1524
|
+
return String(resolveMetaField(name2, fireCtx, now) ?? "");
|
|
1525
|
+
}
|
|
1526
|
+
const value = resolveSessionField(name2, fireCtx, now);
|
|
1527
|
+
return value === void 0 || value === null ? "" : String(value);
|
|
1528
|
+
}
|
|
1529
|
+
__name(resolvePlaceholderValue, "resolvePlaceholderValue");
|
|
1530
|
+
var BARE_PLACEHOLDER = /"\{\{\s*(\w+)(?::(\d+))?\s*\}\}"/g;
|
|
1531
|
+
var escapeJsonText = /* @__PURE__ */ __name((value) => JSON.stringify(value).slice(1, -1), "escapeJsonText");
|
|
1532
|
+
function interpolateTemplate(template, fireCtx, history, now) {
|
|
1533
|
+
const resolve = /* @__PURE__ */ __name((name2, limit) => resolvePlaceholderValue(name2, limit ? Number(limit) : void 0, fireCtx, history, now), "resolve");
|
|
1534
|
+
const native = template.replace(
|
|
1535
|
+
BARE_PLACEHOLDER,
|
|
1536
|
+
(_match, name2, limit) => JSON.stringify(resolve(name2, limit))
|
|
1537
|
+
);
|
|
1538
|
+
return native.replace(
|
|
1539
|
+
JSON_PLACEHOLDER,
|
|
1540
|
+
(_match, name2, limit) => escapeJsonText(String(resolve(name2, limit)))
|
|
1541
|
+
);
|
|
1542
|
+
}
|
|
1543
|
+
__name(interpolateTemplate, "interpolateTemplate");
|
|
1544
|
+
function resolveJsonObject(template, fireCtx, history, now) {
|
|
1545
|
+
try {
|
|
1546
|
+
const parsed = JSON.parse(interpolateTemplate(template, fireCtx, history, now));
|
|
1547
|
+
return typeof parsed === "object" && parsed !== null && !Array.isArray(parsed) ? parsed : null;
|
|
1548
|
+
} catch {
|
|
1549
|
+
return null;
|
|
1550
|
+
}
|
|
1551
|
+
}
|
|
1552
|
+
__name(resolveJsonObject, "resolveJsonObject");
|
|
1469
1553
|
function resolveVariables(rule, fireCtx, history) {
|
|
1470
1554
|
const inputs = {};
|
|
1471
1555
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
1472
1556
|
for (const binding of rule.variables) {
|
|
1473
|
-
if (
|
|
1557
|
+
if (binding?.source?.type !== "json") continue;
|
|
1558
|
+
const object = resolveJsonObject(binding.source.template, fireCtx, history, now);
|
|
1559
|
+
if (object) Object.assign(inputs, object);
|
|
1560
|
+
}
|
|
1561
|
+
for (const binding of rule.variables) {
|
|
1562
|
+
if (!binding?.field || binding.source?.type === "json") continue;
|
|
1474
1563
|
const value = resolveSource(binding.source, fireCtx, history, now);
|
|
1475
1564
|
if (value !== void 0) inputs[binding.field] = value;
|
|
1476
1565
|
}
|
|
@@ -1869,6 +1958,7 @@ var name = "dify-ai";
|
|
|
1869
1958
|
var inject = { required: ["database"] };
|
|
1870
1959
|
var PROBE_TIMEOUT_MS = 1e4;
|
|
1871
1960
|
function apply(ctx, config) {
|
|
1961
|
+
const startedAt = Date.now();
|
|
1872
1962
|
ctx.i18n.define("zh-CN", zh_CN_default);
|
|
1873
1963
|
ctx.i18n.define("en-US", en_US_default);
|
|
1874
1964
|
defineTables(ctx);
|
|
@@ -1880,7 +1970,11 @@ function apply(ctx, config) {
|
|
|
1880
1970
|
const engine = new TriggerEngine(ctx, runner, history, rules, cooldown);
|
|
1881
1971
|
ctx.on("ready", () => {
|
|
1882
1972
|
engine.start();
|
|
1883
|
-
|
|
1973
|
+
ctx.logger.info("插件装配完成,耗时 %dms", Date.now() - startedAt);
|
|
1974
|
+
const probeStart = Date.now();
|
|
1975
|
+
void probeAppTypes(ctx, apps, appTypes).then(() => {
|
|
1976
|
+
ctx.logger.info("应用类型探测完成,耗时 %dms", Date.now() - probeStart);
|
|
1977
|
+
});
|
|
1884
1978
|
});
|
|
1885
1979
|
const admin = ctx.command("dify", { authority: 3 });
|
|
1886
1980
|
registerMiscCommands(admin, conversationStore);
|
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { FireContext } from '../types';
|
|
2
2
|
import { MessageHistory } from '../history';
|
|
3
3
|
import { DifyRule } from '../types';
|
|
4
|
-
/**
|
|
4
|
+
/**
|
|
5
|
+
* 按规则的变量映射表构造 Dify inputs。
|
|
6
|
+
* JSON 对象条目先注入(顶层键展开合并进 inputs),单条映射后注入覆盖同名键——
|
|
7
|
+
* 现有单条配置行为不变,JSON 作为批量默认值。
|
|
8
|
+
*/
|
|
5
9
|
export declare function resolveVariables(rule: DifyRule, fireCtx: FireContext, history: MessageHistory): Record<string, any>;
|
package/lib/types.d.ts
CHANGED
|
@@ -68,7 +68,12 @@ export type VariableSource = {
|
|
|
68
68
|
} | {
|
|
69
69
|
type: 'constant';
|
|
70
70
|
value: string;
|
|
71
|
+
} | {
|
|
72
|
+
type: 'json';
|
|
73
|
+
template: string;
|
|
71
74
|
};
|
|
75
|
+
/** JSON 对象模板里的占位符:{{变量名}} 或 {{history:条数}}(加载校验与运行时插值共用) */
|
|
76
|
+
export declare const JSON_PLACEHOLDER: RegExp;
|
|
72
77
|
/** 一条变量映射:Dify inputs 字段名 ← 来源 */
|
|
73
78
|
export interface VariableBinding {
|
|
74
79
|
field: string;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "koishi-plugin-dify-ai",
|
|
3
3
|
"description": "Invoke Dify apps (chatflow / workflow / completion) in Koishi with triggers and conversation bindings",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.9",
|
|
5
5
|
"author": "PinkElysia",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"homepage": "https://github.com/PinkElysiaDev/dify-ai-plugin-for-Koishi#readme",
|