@artflo-ai/artflo-openclaw-plugin 0.0.10 → 0.0.12
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.
|
@@ -8,18 +8,54 @@ const VALID_NODE_TYPES = new Set([
|
|
|
8
8
|
'video',
|
|
9
9
|
'batch',
|
|
10
10
|
]);
|
|
11
|
+
/**
|
|
12
|
+
* Fallback map: canvas numeric node types → PlanDSL string types.
|
|
13
|
+
* LLMs sometimes emit raw canvas codes instead of the PlanDSL strings.
|
|
14
|
+
*/
|
|
15
|
+
const NUMERIC_TYPE_MAP = {
|
|
16
|
+
100000: 'process', // EDGE — unlikely but safe fallback
|
|
17
|
+
110000: 'input',
|
|
18
|
+
110001: 'image',
|
|
19
|
+
110004: 'video',
|
|
20
|
+
110006: 'selector',
|
|
21
|
+
130000: 'process',
|
|
22
|
+
130500: 'refine',
|
|
23
|
+
190000: 'crop',
|
|
24
|
+
};
|
|
11
25
|
function isRecord(value) {
|
|
12
26
|
return typeof value === 'object' && value !== null;
|
|
13
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Attempt to coerce a raw node type (number or unknown string) into a valid
|
|
30
|
+
* PlanDSL NodeType. Returns the mapped type or `null` if unrecoverable.
|
|
31
|
+
*/
|
|
32
|
+
function coerceNodeType(raw) {
|
|
33
|
+
if (typeof raw === 'string') {
|
|
34
|
+
const lower = raw.toLowerCase().trim();
|
|
35
|
+
if (VALID_NODE_TYPES.has(lower)) {
|
|
36
|
+
return lower;
|
|
37
|
+
}
|
|
38
|
+
// Try parsing stringified number ("110000")
|
|
39
|
+
const num = Number(lower);
|
|
40
|
+
if (!Number.isNaN(num) && NUMERIC_TYPE_MAP[num]) {
|
|
41
|
+
return NUMERIC_TYPE_MAP[num];
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
if (typeof raw === 'number' && NUMERIC_TYPE_MAP[raw]) {
|
|
46
|
+
return NUMERIC_TYPE_MAP[raw];
|
|
47
|
+
}
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
14
50
|
export function parsePlanV2(value) {
|
|
15
51
|
if (!isRecord(value)) {
|
|
16
|
-
throw new Error('Plan must be an object');
|
|
52
|
+
throw new Error('Plan must be an object. See artflo_canvas SKILL.md for the PlanDSL V2 schema.');
|
|
17
53
|
}
|
|
18
54
|
if (!Array.isArray(value.nodes)) {
|
|
19
|
-
throw new Error('Plan nodes must be an array');
|
|
55
|
+
throw new Error('Plan nodes must be an array. See artflo_canvas SKILL.md for the PlanDSL V2 schema.');
|
|
20
56
|
}
|
|
21
57
|
if (!Array.isArray(value.edges)) {
|
|
22
|
-
throw new Error('Plan edges must be an array');
|
|
58
|
+
throw new Error('Plan edges must be an array. See artflo_canvas SKILL.md for the PlanDSL V2 schema.');
|
|
23
59
|
}
|
|
24
60
|
const nodes = value.nodes.map((node, index) => parseNodeSpec(node, index));
|
|
25
61
|
const edges = value.edges.map((edge, index) => parseEdgeSpec(edge, index));
|
|
@@ -44,15 +80,25 @@ function parseNodeSpec(value, index) {
|
|
|
44
80
|
if (!isRecord(value)) {
|
|
45
81
|
throw new Error(`Node at index ${index} must be an object`);
|
|
46
82
|
}
|
|
47
|
-
|
|
83
|
+
// Accept "ref" or fall back to "id" (canvas format)
|
|
84
|
+
const ref = typeof value.ref === 'string' && value.ref.length > 0
|
|
85
|
+
? value.ref
|
|
86
|
+
: typeof value.id === 'string' && value.id.length > 0
|
|
87
|
+
? value.id
|
|
88
|
+
: '';
|
|
89
|
+
if (ref.length === 0) {
|
|
48
90
|
throw new Error(`Node at index ${index} is missing ref`);
|
|
49
91
|
}
|
|
50
|
-
|
|
51
|
-
|
|
92
|
+
const resolvedType = coerceNodeType(value.type);
|
|
93
|
+
if (!resolvedType) {
|
|
94
|
+
throw new Error(`Node ${ref} has invalid type "${String(value.type)}". ` +
|
|
95
|
+
`Valid types: ${[...VALID_NODE_TYPES].join(', ')}. ` +
|
|
96
|
+
`Do NOT use numeric canvas types (110000, 130000, etc.). ` +
|
|
97
|
+
`See artflo_canvas SKILL.md for the PlanDSL V2 schema.`);
|
|
52
98
|
}
|
|
53
99
|
return {
|
|
54
|
-
ref
|
|
55
|
-
type:
|
|
100
|
+
ref,
|
|
101
|
+
type: resolvedType,
|
|
56
102
|
data: isRecord(value.data) ? value.data : {},
|
|
57
103
|
dependsOn: typeof value.dependsOn === 'string' ? value.dependsOn : undefined,
|
|
58
104
|
};
|
|
@@ -61,15 +107,31 @@ function parseEdgeSpec(value, index) {
|
|
|
61
107
|
if (!isRecord(value)) {
|
|
62
108
|
throw new Error(`Edge at index ${index} must be an object`);
|
|
63
109
|
}
|
|
64
|
-
|
|
65
|
-
|
|
110
|
+
// Accept "from"/"to" or fall back to "source"/"target" (canvas format)
|
|
111
|
+
const from = typeof value.from === 'string'
|
|
112
|
+
? value.from
|
|
113
|
+
: typeof value.source === 'string'
|
|
114
|
+
? value.source
|
|
115
|
+
: '';
|
|
116
|
+
const to = typeof value.to === 'string'
|
|
117
|
+
? value.to
|
|
118
|
+
: typeof value.target === 'string'
|
|
119
|
+
? value.target
|
|
120
|
+
: '';
|
|
121
|
+
if (from.length === 0 || to.length === 0) {
|
|
122
|
+
throw new Error(`Edge at index ${index} must include from and to. ` +
|
|
123
|
+
`See artflo_canvas SKILL.md for the PlanDSL V2 schema.`);
|
|
66
124
|
}
|
|
67
125
|
return {
|
|
68
126
|
ref: typeof value.ref === 'string' ? value.ref : undefined,
|
|
69
|
-
from
|
|
70
|
-
to
|
|
71
|
-
fromHandle: typeof value.fromHandle === 'string' ? value.fromHandle
|
|
72
|
-
|
|
127
|
+
from,
|
|
128
|
+
to,
|
|
129
|
+
fromHandle: typeof value.fromHandle === 'string' ? value.fromHandle
|
|
130
|
+
: typeof value.sourceHandle === 'string' ? value.sourceHandle
|
|
131
|
+
: undefined,
|
|
132
|
+
toHandle: typeof value.toHandle === 'string' ? value.toHandle
|
|
133
|
+
: typeof value.targetHandle === 'string' ? value.targetHandle
|
|
134
|
+
: undefined,
|
|
73
135
|
};
|
|
74
136
|
}
|
|
75
137
|
export function validateAndFixPlan(plan) {
|
|
@@ -27,7 +27,7 @@ export function registerArtfloTools(api, context) {
|
|
|
27
27
|
api.registerTool({
|
|
28
28
|
name: ARTFLO_TOOL_NAMES.getNode,
|
|
29
29
|
label: 'Artflo Canvas Get Node',
|
|
30
|
-
description: 'Read one node or edge from the current Artflo canvas session by id.',
|
|
30
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Read one node or edge from the current Artflo canvas session by id.',
|
|
31
31
|
parameters: Type.Object({
|
|
32
32
|
canvasId: Type.String({ minLength: 1 }),
|
|
33
33
|
id: Type.String({ minLength: 1 }),
|
|
@@ -52,7 +52,7 @@ export function registerArtfloTools(api, context) {
|
|
|
52
52
|
api.registerTool({
|
|
53
53
|
name: ARTFLO_TOOL_NAMES.connect,
|
|
54
54
|
label: 'Artflo Canvas Connect',
|
|
55
|
-
description: 'Register or warm a direct Artflo canvas WebSocket session for a canvas id using preconfigured plugin credentials.',
|
|
55
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Register or warm a direct Artflo canvas WebSocket session for a canvas id using preconfigured plugin credentials.',
|
|
56
56
|
parameters: Type.Object({
|
|
57
57
|
canvasId: Type.String({ minLength: 1 }),
|
|
58
58
|
}),
|
|
@@ -79,7 +79,7 @@ export function registerArtfloTools(api, context) {
|
|
|
79
79
|
api.registerTool({
|
|
80
80
|
name: ARTFLO_TOOL_NAMES.connectionStatus,
|
|
81
81
|
label: 'Artflo Canvas Connection Status',
|
|
82
|
-
description: 'Inspect current plugin-level Artflo WebSocket session state and config readiness.',
|
|
82
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Inspect current plugin-level Artflo WebSocket session state and config readiness.',
|
|
83
83
|
parameters: Type.Object({
|
|
84
84
|
canvasId: Type.Optional(Type.String()),
|
|
85
85
|
}),
|
|
@@ -107,7 +107,7 @@ export function registerArtfloTools(api, context) {
|
|
|
107
107
|
api.registerTool({
|
|
108
108
|
name: ARTFLO_TOOL_NAMES.getState,
|
|
109
109
|
label: 'Artflo Canvas State',
|
|
110
|
-
description: 'Return scaffold plugin state and planned runtime capabilities for Artflo execution.',
|
|
110
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Return scaffold plugin state and planned runtime capabilities for Artflo execution.',
|
|
111
111
|
parameters: Type.Object({
|
|
112
112
|
canvasId: Type.Optional(Type.String()),
|
|
113
113
|
}),
|
|
@@ -143,7 +143,7 @@ export function registerArtfloTools(api, context) {
|
|
|
143
143
|
api.registerTool({
|
|
144
144
|
name: ARTFLO_TOOL_NAMES.getConfig,
|
|
145
145
|
label: 'Artflo Canvas Get Config',
|
|
146
|
-
description: 'Return available models, subscription status, and prompt refine categories for the connected canvas. Call this before planning a workflow so you know which models and resolutions are available.',
|
|
146
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Return available models, subscription status, and prompt refine categories for the connected canvas. Call this before planning a workflow so you know which models and resolutions are available.',
|
|
147
147
|
parameters: Type.Object({
|
|
148
148
|
canvasId: Type.String({ minLength: 1 }),
|
|
149
149
|
}),
|
|
@@ -179,7 +179,7 @@ export function registerArtfloTools(api, context) {
|
|
|
179
179
|
api.registerTool({
|
|
180
180
|
name: ARTFLO_TOOL_NAMES.findNodes,
|
|
181
181
|
label: 'Artflo Canvas Find Nodes',
|
|
182
|
-
description: 'Find nodes or edges in the connected Artflo canvas by ids, type, status, label text, or runnable state.',
|
|
182
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Find nodes or edges in the connected Artflo canvas by ids, type, status, label text, or runnable state.',
|
|
183
183
|
parameters: Type.Object({
|
|
184
184
|
canvasId: Type.String({ minLength: 1 }),
|
|
185
185
|
ids: Type.Optional(Type.Array(Type.String())),
|
|
@@ -237,7 +237,7 @@ export function registerArtfloTools(api, context) {
|
|
|
237
237
|
api.registerTool({
|
|
238
238
|
name: ARTFLO_TOOL_NAMES.changeElements,
|
|
239
239
|
label: 'Artflo Canvas Change Elements',
|
|
240
|
-
description: 'Apply direct structured element changes to an existing Artflo canvas session.',
|
|
240
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Apply direct structured element changes to an existing Artflo canvas session. Do NOT use this tool to create new workflows from scratch — use artflo_canvas_execute_plan instead.',
|
|
241
241
|
parameters: Type.Object({
|
|
242
242
|
canvasId: Type.String({ minLength: 1 }),
|
|
243
243
|
changes: Type.Array(Type.Any(), { minItems: 1 }),
|
|
@@ -264,7 +264,7 @@ export function registerArtfloTools(api, context) {
|
|
|
264
264
|
api.registerTool({
|
|
265
265
|
name: ARTFLO_TOOL_NAMES.deleteElements,
|
|
266
266
|
label: 'Artflo Canvas Delete Elements',
|
|
267
|
-
description: 'Delete nodes or edges from the current Artflo canvas session.',
|
|
267
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Delete nodes or edges from the current Artflo canvas session.',
|
|
268
268
|
parameters: Type.Object({
|
|
269
269
|
canvasId: Type.String({ minLength: 1 }),
|
|
270
270
|
ids: Type.Array(Type.String(), { minItems: 1 }),
|
|
@@ -289,7 +289,7 @@ export function registerArtfloTools(api, context) {
|
|
|
289
289
|
api.registerTool({
|
|
290
290
|
name: ARTFLO_TOOL_NAMES.runNodes,
|
|
291
291
|
label: 'Artflo Canvas Run Nodes',
|
|
292
|
-
description: 'Run one or more executable Artflo nodes by id.',
|
|
292
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Run one or more executable Artflo nodes by id.',
|
|
293
293
|
parameters: Type.Object({
|
|
294
294
|
canvasId: Type.String({ minLength: 1 }),
|
|
295
295
|
ids: Type.Array(Type.String(), { minItems: 1 }),
|
|
@@ -314,7 +314,7 @@ export function registerArtfloTools(api, context) {
|
|
|
314
314
|
api.registerTool({
|
|
315
315
|
name: ARTFLO_TOOL_NAMES.waitForCompletion,
|
|
316
316
|
label: 'Artflo Canvas Wait For Completion',
|
|
317
|
-
description: 'Wait for one or more executable nodes to reach completion status.',
|
|
317
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Wait for one or more executable nodes to reach completion status.',
|
|
318
318
|
parameters: Type.Object({
|
|
319
319
|
canvasId: Type.String({ minLength: 1 }),
|
|
320
320
|
ids: Type.Array(Type.String(), { minItems: 1 }),
|
|
@@ -341,7 +341,7 @@ export function registerArtfloTools(api, context) {
|
|
|
341
341
|
api.registerTool({
|
|
342
342
|
name: ARTFLO_TOOL_NAMES.executePlan,
|
|
343
343
|
label: 'Artflo Execute Plan',
|
|
344
|
-
description: 'Execute a structured Artflo plan through deterministic runtime logic.
|
|
344
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for the PlanDSL V2 schema and valid node types. Execute a structured Artflo plan through deterministic runtime logic. Node types must be strings: "input", "process", "refine", "selector", "crop", "image", "video", "batch". Edges must use "from"/"to" fields (not "source"/"target"). Do NOT use numeric canvas types (110000, 130000, etc.).',
|
|
345
345
|
parameters: Type.Object({
|
|
346
346
|
canvasId: Type.String({ minLength: 1 }),
|
|
347
347
|
plan: Type.Object({
|
|
@@ -410,7 +410,7 @@ export function registerArtfloTools(api, context) {
|
|
|
410
410
|
api.registerTool({
|
|
411
411
|
name: ARTFLO_TOOL_NAMES.createCanvas,
|
|
412
412
|
label: 'Artflo Canvas Create',
|
|
413
|
-
description: 'Create a new Artflo canvas project. Returns the canvas id and project URL. Use this when no canvas id is available or the user requests a new canvas.',
|
|
413
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Create a new Artflo canvas project. Returns the canvas id and project URL. Use this when no canvas id is available or the user requests a new canvas.',
|
|
414
414
|
parameters: Type.Object({
|
|
415
415
|
name: Type.Optional(Type.String({ description: 'Canvas name, defaults to "Untitled"' })),
|
|
416
416
|
}),
|
|
@@ -436,7 +436,7 @@ export function registerArtfloTools(api, context) {
|
|
|
436
436
|
api.registerTool({
|
|
437
437
|
name: ARTFLO_TOOL_NAMES.getLastCanvas,
|
|
438
438
|
label: 'Artflo Canvas Get Last',
|
|
439
|
-
description: 'Get the last used canvas id. Use this when user requests last used canvas.',
|
|
439
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Get the last used canvas id. Use this when user requests last used canvas.',
|
|
440
440
|
parameters: Type.Object({}),
|
|
441
441
|
async execute(_id, params) {
|
|
442
442
|
return runWithToolTrace(ARTFLO_TOOL_NAMES.getLastCanvas, params, async () => {
|
|
@@ -457,7 +457,7 @@ export function registerArtfloTools(api, context) {
|
|
|
457
457
|
api.registerTool({
|
|
458
458
|
name: ARTFLO_TOOL_NAMES.listModels,
|
|
459
459
|
label: 'Artflo Canvas List Models',
|
|
460
|
-
description: 'List all available AI models. When presenting results to the user, you MUST show ALL of these fields in a table: ' +
|
|
460
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. List all available AI models. When presenting results to the user, you MUST show ALL of these fields in a table: ' +
|
|
461
461
|
'1) Model name (use model_name, NEVER expose model_key to user) ' +
|
|
462
462
|
'2) Credits (base price; if resolutionPricing exists, show per-resolution prices) ' +
|
|
463
463
|
'3) Supported resolutions ' +
|
|
@@ -567,7 +567,7 @@ export function registerArtfloTools(api, context) {
|
|
|
567
567
|
api.registerTool({
|
|
568
568
|
name: ARTFLO_TOOL_NAMES.uploadFile,
|
|
569
569
|
label: 'Artflo Upload File',
|
|
570
|
-
description: 'Upload a local file or a remote URL to Artflo OBS storage. Returns the CDN URL and object key. Use this to upload reference images before creating workflows with image-to-image or image-to-video nodes.',
|
|
570
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Upload a local file or a remote URL to Artflo OBS storage. Returns the CDN URL and object key. Use this to upload reference images before creating workflows with image-to-image or image-to-video nodes.',
|
|
571
571
|
parameters: Type.Object({
|
|
572
572
|
source: Type.String({
|
|
573
573
|
description: 'Local file path or remote https URL to upload.',
|
|
@@ -592,7 +592,7 @@ export function registerArtfloTools(api, context) {
|
|
|
592
592
|
api.registerTool({
|
|
593
593
|
name: ARTFLO_TOOL_NAMES.getUserStatus,
|
|
594
594
|
label: 'Artflo Get User Status',
|
|
595
|
-
description: 'Get the current user subscription plan and remaining credits. Does not require a canvas connection.',
|
|
595
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Get the current user subscription plan and remaining credits. Does not require a canvas connection.',
|
|
596
596
|
parameters: Type.Object({}),
|
|
597
597
|
async execute(_id, params) {
|
|
598
598
|
return runWithToolTrace(ARTFLO_TOOL_NAMES.getUserStatus, params, async () => {
|
|
@@ -621,7 +621,7 @@ export function registerArtfloTools(api, context) {
|
|
|
621
621
|
api.registerTool({
|
|
622
622
|
name: ARTFLO_TOOL_NAMES.setApiKey,
|
|
623
623
|
label: 'Artflo Set Config',
|
|
624
|
-
description: 'Save Artflo plugin config (apiKey and/or env). Call this when the user provides their API Key or wants to switch environment. Both parameters are optional — only provided values will be updated.',
|
|
624
|
+
description: '⚠️ Before using this tool, you MUST read the artflo_canvas SKILL.md for usage rules and constraints. Save Artflo plugin config (apiKey and/or env). Call this when the user provides their API Key or wants to switch environment. Both parameters are optional — only provided values will be updated.',
|
|
625
625
|
parameters: Type.Object({
|
|
626
626
|
apiKey: Type.Optional(Type.String({ minLength: 1, description: 'Artflo API Key.' })),
|
|
627
627
|
env: Type.Optional(Type.String({ enum: ['release', 'test'], description: 'Environment: release or test.' })),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@artflo-ai/artflo-openclaw-plugin",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.12",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "OpenClaw plugin that connects directly to Artflo canvas WebSocket runtime.",
|
|
6
6
|
"keywords": [
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
"files": [
|
|
14
14
|
"README.md",
|
|
15
15
|
"dist",
|
|
16
|
+
"!dist/logs",
|
|
16
17
|
"openclaw.plugin.json",
|
|
17
18
|
"skills",
|
|
18
19
|
"package.json"
|
|
@@ -58,7 +58,7 @@ metadata:
|
|
|
58
58
|
- 将插件配置视为 WebSocket 凭证和连接默认值的唯一真实来源。
|
|
59
59
|
- **禁止编造 API URL**:不要自行拼接或猜测 Artflo API 路径。所有 API 交互必须通过插件提供的 tool 完成(如 `artflo_canvas_get_last`、`artflo_canvas_create`、`artflo_upload_file` 等)。不要使用 `fetch` 或 `curl` 直接调用 Artflo API。
|
|
60
60
|
- **model_key 保密**:`model_key`(如 `Praline_2`、`ToffeeV1-Lite`)是内部标识,仅供构建 plan 使用。向用户展示模型时只使用 `model_name`(显示名称),绝不向用户暴露 `model_key`。
|
|
61
|
-
- **资源保存路径**:画布生成完成后需要下载保存的资源(图片、视频等),必须保存到
|
|
61
|
+
- **资源保存路径**:画布生成完成后需要下载保存的资源(图片、视频等),必须保存到 `artflo/outbound` 目录。不要使用 `/tmp` 或其他临时目录。
|
|
62
62
|
- **环境设置保密**:不要主动向用户提及或暴露环境切换功能(release/test)。只有当用户明确提到要切换环境、设置 test 环境时,才使用 `artflo_set_api_key` 的 `env` 参数。
|
|
63
63
|
- **品牌名称规范**:产品名称是 **Artflo**(A 大写,其余小写)。不要写成 ArtFlo、ARTFLO、artFlo 或其他变体。所有面向用户的文字中必须使用正确的大小写。
|
|
64
64
|
- **模型列表展示规范**:当用户查看模型列表时,必须展示以下字段,不要省略:
|
|
@@ -94,6 +94,7 @@ metadata:
|
|
|
94
94
|
8. 调用 `artflo_canvas_execute_plan` 执行该 plan。
|
|
95
95
|
9. 如果是检查现状,使用 `artflo_canvas_get_state`、`artflo_canvas_get_node` 或 `artflo_canvas_find_nodes`。
|
|
96
96
|
10. 如果是定向修复,使用 `artflo_canvas_change_elements`、`artflo_canvas_delete_elements`、`artflo_canvas_run_nodes` 和 `artflo_canvas_wait_for_completion`。
|
|
97
|
+
11. 生成成功必须告知用户源文件的资源链接,与生成文件分开发送
|
|
97
98
|
|
|
98
99
|
## 规划核心要点
|
|
99
100
|
|
|
@@ -137,19 +138,3 @@ metadata:
|
|
|
137
138
|
4. 如果错误是 "invalid model"(error_code=402),说明选择的模型不可用。调用 `artflo_canvas_get_config` 确认可用模型列表,选择一个 `available: true` 的模型,然后 change + rerun。
|
|
138
139
|
5. **绝对不要删除已成功执行的上游节点**。只修复出错的那个节点。
|
|
139
140
|
6. 如果需要重建整个工作流分支,先向用户确认,不要自行决定。
|
|
140
|
-
|
|
141
|
-
## Channel 适配规则
|
|
142
|
-
|
|
143
|
-
向用户发送 Artflo 生成结果时,必须根据当前 Channel 的限制选择合适的发送方式。
|
|
144
|
-
|
|
145
|
-
### 企业微信(WeCom)
|
|
146
|
-
|
|
147
|
-
| 资源大小 | 发送方式 |
|
|
148
|
-
|---------|---------|
|
|
149
|
-
| 图片 ≤ 2 MB | 以图片形式发送 |
|
|
150
|
-
| 图片 > 2 MB 且 ≤ 20 MB | 以文件形式发送 |
|
|
151
|
-
| 文件 > 20 MB | 直接发送图片/文件的 URL 链接 |
|
|
152
|
-
|
|
153
|
-
### 其他 Channel
|
|
154
|
-
|
|
155
|
-
(待补充)
|