agentweaver 0.1.16 → 0.1.18
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/README.md +148 -27
- package/dist/artifacts.js +114 -3
- package/dist/doctor/checks/executors.js +2 -2
- package/dist/flow-state.js +138 -1
- package/dist/index.js +421 -82
- package/dist/interactive/controller.js +305 -36
- package/dist/interactive/ink/index.js +24 -3
- package/dist/interactive/state.js +1 -0
- package/dist/interactive/tree.js +2 -2
- package/dist/interactive/web/index.js +179 -0
- package/dist/interactive/web/protocol.js +154 -0
- package/dist/interactive/web/server.js +575 -0
- package/dist/interactive/web/static/app.js +709 -0
- package/dist/interactive/web/static/index.html +77 -0
- package/dist/interactive/web/static/styles.css +2 -0
- package/dist/interactive/web/static/styles.input.css +469 -0
- package/dist/pipeline/auto-flow.js +9 -6
- package/dist/pipeline/context.js +6 -5
- package/dist/pipeline/declarative-flows.js +39 -20
- package/dist/pipeline/flow-catalog.js +40 -14
- package/dist/pipeline/flow-specs/auto-common-guided.json +313 -0
- package/dist/pipeline/flow-specs/auto-common.json +4 -1
- package/dist/pipeline/flow-specs/auto-golang.json +27 -1
- package/dist/pipeline/flow-specs/design-review/design-review-loop.json +15 -1
- package/dist/pipeline/flow-specs/design-review.json +2 -0
- package/dist/pipeline/flow-specs/implement.json +3 -1
- package/dist/pipeline/flow-specs/plan.json +8 -2
- package/dist/pipeline/flow-specs/playbook-init.json +199 -0
- package/dist/pipeline/flow-specs/review/review-fix.json +3 -1
- package/dist/pipeline/flow-specs/review/review-loop.json +4 -0
- package/dist/pipeline/flow-specs/review/review.json +2 -0
- package/dist/pipeline/launch-profile-config.js +30 -18
- package/dist/pipeline/node-contract.js +1 -0
- package/dist/pipeline/node-registry.js +119 -5
- package/dist/pipeline/nodes/flow-run-node.js +200 -173
- package/dist/pipeline/nodes/llm-prompt-node.js +15 -33
- package/dist/pipeline/nodes/playbook-ensure-node.js +115 -0
- package/dist/pipeline/nodes/playbook-inventory-node.js +51 -0
- package/dist/pipeline/nodes/playbook-questions-form-node.js +166 -0
- package/dist/pipeline/nodes/playbook-write-node.js +243 -0
- package/dist/pipeline/nodes/project-guidance-node.js +69 -0
- package/dist/pipeline/plugin-loader.js +389 -0
- package/dist/pipeline/plugin-types.js +1 -0
- package/dist/pipeline/prompt-registry.js +4 -1
- package/dist/pipeline/prompt-runtime.js +6 -2
- package/dist/pipeline/registry.js +71 -4
- package/dist/pipeline/spec-compiler.js +1 -0
- package/dist/pipeline/spec-loader.js +14 -0
- package/dist/pipeline/spec-types.js +19 -0
- package/dist/pipeline/spec-validator.js +6 -0
- package/dist/pipeline/value-resolver.js +41 -2
- package/dist/playbook/practice-candidates.js +12 -0
- package/dist/playbook/repo-inventory.js +208 -0
- package/dist/plugin-sdk.js +1 -0
- package/dist/prompts.js +31 -0
- package/dist/runtime/artifact-registry.js +3 -0
- package/dist/runtime/execution-routing.js +25 -19
- package/dist/runtime/interactive-execution-routing.js +66 -57
- package/dist/runtime/playbook.js +485 -0
- package/dist/runtime/project-guidance.js +339 -0
- package/dist/structured-artifact-schema-registry.js +8 -0
- package/dist/structured-artifact-schemas.json +235 -0
- package/dist/structured-artifacts.js +7 -1
- package/docs/declarative-workflows.md +565 -0
- package/docs/example/.flows/examples/claude-example.json +50 -0
- package/docs/example/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/example/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/examples/.flows/claude-example.json +50 -0
- package/docs/examples/.plugins/claude-example-plugin/index.js +149 -0
- package/docs/examples/.plugins/claude-example-plugin/plugin.json +8 -0
- package/docs/features.md +77 -0
- package/docs/playbook.md +327 -0
- package/docs/plugin-sdk.md +731 -0
- package/package.json +13 -4
|
@@ -0,0 +1,731 @@
|
|
|
1
|
+
# AgentWeaver Plugin SDK
|
|
2
|
+
|
|
3
|
+
This guide is for external plugin authors who want to add custom executors, custom nodes, and custom declarative flows without modifying AgentWeaver core.
|
|
4
|
+
|
|
5
|
+
Use only the public SDK import:
|
|
6
|
+
|
|
7
|
+
```ts
|
|
8
|
+
import type {
|
|
9
|
+
ExecutorDefinition,
|
|
10
|
+
JsonValue,
|
|
11
|
+
NodeContractMetadata,
|
|
12
|
+
PipelineNodeDefinition,
|
|
13
|
+
PluginEntryModuleExports,
|
|
14
|
+
PluginExecutorRegistration,
|
|
15
|
+
PluginManifest,
|
|
16
|
+
PluginNodeRegistration,
|
|
17
|
+
} from "agentweaver/plugin-sdk";
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Do not import from:
|
|
21
|
+
|
|
22
|
+
- `agentweaver`
|
|
23
|
+
- `agentweaver/dist/*`
|
|
24
|
+
- `agentweaver/src/*`
|
|
25
|
+
- repository-relative source paths
|
|
26
|
+
|
|
27
|
+
## Architecture Overview
|
|
28
|
+
|
|
29
|
+
AgentWeaver has four pieces that matter to plugin authors:
|
|
30
|
+
|
|
31
|
+
- An `executor` integrates with an external tool or runtime action. It is a typed function with `defaultConfig` and `execute`.
|
|
32
|
+
- A `node` is the runtime unit referenced from declarative flow JSON. A node can use executors, read flow context, and return outputs.
|
|
33
|
+
- A `flow` is declarative JSON loaded from built-in specs, global `~/.agentweaver/.flows/**/*.json`, or project-local `.agentweaver/.flows/**/*.json`.
|
|
34
|
+
- A `plugin manifest` tells AgentWeaver where a global or project-local plugin is installed and which ESM entrypoint to load.
|
|
35
|
+
|
|
36
|
+
The runtime merges built-in registries with global and project-local plugin registrations. Flow validation then runs against that merged registry. That means a custom flow can reference plugin-provided node kinds directly, and plugin node metadata can declare dependencies on built-in or plugin-provided executor ids.
|
|
37
|
+
|
|
38
|
+
## Installation Layout
|
|
39
|
+
|
|
40
|
+
Supported plugin locations are:
|
|
41
|
+
|
|
42
|
+
```text
|
|
43
|
+
~/.agentweaver/.plugins/<plugin-id>/plugin.json
|
|
44
|
+
.agentweaver/.plugins/<plugin-id>/plugin.json
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Rules enforced by the loader:
|
|
48
|
+
|
|
49
|
+
- AgentWeaver discovers plugin directories from `~/.agentweaver/.plugins/` and `.agentweaver/.plugins/`.
|
|
50
|
+
- Directories are loaded in lexicographic order.
|
|
51
|
+
- Each plugin directory must contain `plugin.json`.
|
|
52
|
+
- The directory name must match the manifest `id` exactly.
|
|
53
|
+
- Loading is fail-fast. An invalid plugin stops registry construction.
|
|
54
|
+
- Invalid plugins are not skipped partially.
|
|
55
|
+
- Duplicate built-in ids and duplicate plugin ids are rejected by registry creation.
|
|
56
|
+
|
|
57
|
+
Custom flows live under:
|
|
58
|
+
|
|
59
|
+
```text
|
|
60
|
+
~/.agentweaver/.flows/**/*.json
|
|
61
|
+
.agentweaver/.flows/**/*.json
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
Those flows use the same validator and runtime as built-in flows.
|
|
65
|
+
If the same flow id or plugin id is discovered from more than one source, AgentWeaver fails fast instead of silently overriding one source with another.
|
|
66
|
+
|
|
67
|
+
## Repository Examples
|
|
68
|
+
|
|
69
|
+
This repository keeps reference plugin examples under `docs/examples/`.
|
|
70
|
+
|
|
71
|
+
## Claude Example Plugin
|
|
72
|
+
|
|
73
|
+
Current Claude example files:
|
|
74
|
+
|
|
75
|
+
- plugin manifest: `docs/examples/.plugins/claude-example-plugin/plugin.json`
|
|
76
|
+
- plugin entrypoint: `docs/examples/.plugins/claude-example-plugin/index.js`
|
|
77
|
+
- example flow: `docs/examples/.flows/claude-example.json`
|
|
78
|
+
|
|
79
|
+
`docs/examples/` is documentation material, not an auto-loaded runtime location. To run an example, copy it into `~/.agentweaver/` or `.agentweaver/`.
|
|
80
|
+
|
|
81
|
+
The Claude example is intentionally an executor-only plugin. The flow uses the built-in `llm-prompt` node with `executor: "claude"`, so the example demonstrates the same integration surface used by built-in LLM executors such as Codex and OpenCode.
|
|
82
|
+
|
|
83
|
+
Important runtime behavior:
|
|
84
|
+
|
|
85
|
+
- the executor shells out to `claude -p <prompt> --output-format json`
|
|
86
|
+
- for artifact-producing `llm-prompt` steps it also grants Claude access to the current workspace via `--add-dir <cwd>` and configured non-interactive edit permissions
|
|
87
|
+
- it accepts `CLAUDE_BIN`, `CLAUDE_MODEL`, and `CLAUDE_MAX_TURNS`
|
|
88
|
+
- optional runtime controls can be driven through `CLAUDE_PERMISSION_MODE`, `CLAUDE_ALLOWED_TOOLS`, and `CLAUDE_DISALLOWED_TOOLS`
|
|
89
|
+
- it normalizes assistant text from `result`, `message.content[*].text`, or `content[*].text`
|
|
90
|
+
- when a flow declares `requiredArtifacts`, `llm-prompt` only verifies and publishes those paths; the Claude prompt itself must create files such as `artifacts/examples/claude-example-proof.json`
|
|
91
|
+
- authentication is expected to be checked with `claude auth status`
|
|
92
|
+
|
|
93
|
+
## Manifest Contract
|
|
94
|
+
|
|
95
|
+
`plugin.json` must be a JSON object with these required fields:
|
|
96
|
+
|
|
97
|
+
- `id`
|
|
98
|
+
- `sdk_version`
|
|
99
|
+
- `entrypoint`
|
|
100
|
+
|
|
101
|
+
Supported optional fields:
|
|
102
|
+
|
|
103
|
+
- `name`
|
|
104
|
+
- `version`
|
|
105
|
+
- `description`
|
|
106
|
+
|
|
107
|
+
Example:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"id": "sample-plugin",
|
|
112
|
+
"sdk_version": 1,
|
|
113
|
+
"entrypoint": "index.js",
|
|
114
|
+
"name": "Sample Plugin",
|
|
115
|
+
"version": "0.1.0",
|
|
116
|
+
"description": "Custom executor and node for a project-local flow."
|
|
117
|
+
}
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Validation rules:
|
|
121
|
+
|
|
122
|
+
- `id` must be a non-empty string.
|
|
123
|
+
- `sdk_version` must be a positive integer.
|
|
124
|
+
- `sdk_version` must match the current supported SDK major exactly. Today that value is `1`.
|
|
125
|
+
- `entrypoint` must be a non-empty string.
|
|
126
|
+
|
|
127
|
+
## Entrypoint Rules
|
|
128
|
+
|
|
129
|
+
The manifest `entrypoint` is resolved relative to the plugin root.
|
|
130
|
+
|
|
131
|
+
Supported module formats:
|
|
132
|
+
|
|
133
|
+
- ESM `.js`
|
|
134
|
+
- ESM `.mjs`
|
|
135
|
+
|
|
136
|
+
Unsupported patterns:
|
|
137
|
+
|
|
138
|
+
- `.cjs`
|
|
139
|
+
- files without `.js` or `.mjs`
|
|
140
|
+
- entrypoints outside the plugin root
|
|
141
|
+
- default exports
|
|
142
|
+
|
|
143
|
+
The plugin entry module may export:
|
|
144
|
+
|
|
145
|
+
- `executors`
|
|
146
|
+
- `nodes`
|
|
147
|
+
- both
|
|
148
|
+
|
|
149
|
+
At least one recognized non-empty registration array must exist.
|
|
150
|
+
|
|
151
|
+
This is valid:
|
|
152
|
+
|
|
153
|
+
```ts
|
|
154
|
+
export const executors = [/* ... */];
|
|
155
|
+
export const nodes = [/* ... */];
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
This is invalid:
|
|
159
|
+
|
|
160
|
+
```ts
|
|
161
|
+
export default {
|
|
162
|
+
executors: [],
|
|
163
|
+
};
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Executor Contract
|
|
167
|
+
|
|
168
|
+
Executors are registered as objects with `id` and `definition`.
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import type { ExecutorDefinition, JsonValue, PluginExecutorRegistration } from "agentweaver/plugin-sdk";
|
|
172
|
+
|
|
173
|
+
type EchoConfig = {
|
|
174
|
+
prefix: string;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
type EchoInput = {
|
|
178
|
+
message: string;
|
|
179
|
+
};
|
|
180
|
+
|
|
181
|
+
type EchoResult = {
|
|
182
|
+
echoed: string;
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
const echoExecutorDefinition: ExecutorDefinition<EchoConfig, EchoInput, EchoResult> = {
|
|
186
|
+
kind: "sample-echo-executor",
|
|
187
|
+
version: 1,
|
|
188
|
+
defaultConfig: {
|
|
189
|
+
prefix: "plugin:",
|
|
190
|
+
},
|
|
191
|
+
async execute(context, input, config) {
|
|
192
|
+
context.ui.writeStdout(`[sample-echo-executor] ${input.message}\n`);
|
|
193
|
+
return {
|
|
194
|
+
echoed: `${config.prefix}${input.message}`,
|
|
195
|
+
};
|
|
196
|
+
},
|
|
197
|
+
};
|
|
198
|
+
|
|
199
|
+
export const executors: PluginExecutorRegistration[] = [
|
|
200
|
+
{
|
|
201
|
+
id: "sample-echo-executor",
|
|
202
|
+
definition: echoExecutorDefinition,
|
|
203
|
+
},
|
|
204
|
+
];
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
Rules enforced by the loader:
|
|
208
|
+
|
|
209
|
+
- `definition.kind === id`
|
|
210
|
+
- `definition.version` must be a positive integer
|
|
211
|
+
- `definition.defaultConfig` must be JSON-serializable
|
|
212
|
+
- `definition.execute` must be a function
|
|
213
|
+
|
|
214
|
+
### Optional Routing Metadata
|
|
215
|
+
|
|
216
|
+
If your executor is intended to appear in the execution-routing modal and be used by `llm-prompt`, you may also export `routing`.
|
|
217
|
+
|
|
218
|
+
Example:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
export const executors: PluginExecutorRegistration[] = [
|
|
222
|
+
{
|
|
223
|
+
id: "claude",
|
|
224
|
+
definition: claudeExecutorDefinition,
|
|
225
|
+
routing: {
|
|
226
|
+
kind: "llm",
|
|
227
|
+
defaultModel: "sonnet",
|
|
228
|
+
models: ["sonnet", "opus", "haiku"],
|
|
229
|
+
},
|
|
230
|
+
},
|
|
231
|
+
];
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
Rules:
|
|
235
|
+
|
|
236
|
+
- `routing.kind` must currently be `llm`
|
|
237
|
+
- `routing.defaultModel` must be a non-empty string
|
|
238
|
+
- `routing.models` must be a non-empty string array
|
|
239
|
+
- `routing.defaultModel` must also appear inside `routing.models`
|
|
240
|
+
|
|
241
|
+
Executors without `routing` still work normally when referenced directly by plugin nodes, but they will not appear in the routing modal and cannot be selected through execution routing.
|
|
242
|
+
|
|
243
|
+
### Executor Runtime Context
|
|
244
|
+
|
|
245
|
+
`ExecutorContext` contains:
|
|
246
|
+
|
|
247
|
+
- `cwd`: current project working directory
|
|
248
|
+
- `env`: resolved process environment
|
|
249
|
+
- `ui`: terminal output adapter
|
|
250
|
+
- `dryRun`: whether the current execution is dry-run
|
|
251
|
+
- `verbose`: verbose execution flag
|
|
252
|
+
- `mdLang`: markdown language preference when available
|
|
253
|
+
- `runtime.resolveCmd(name, envVarName)`: resolve a tool path
|
|
254
|
+
- `runtime.runCommand(argv, options)`: run a subprocess
|
|
255
|
+
- `runtime.artifactRegistry`: publish artifacts through the runtime registry
|
|
256
|
+
|
|
257
|
+
Use these facade APIs instead of importing internal runtime modules from AgentWeaver source.
|
|
258
|
+
|
|
259
|
+
## Node Contract
|
|
260
|
+
|
|
261
|
+
Nodes are what flow JSON references through `step.node`.
|
|
262
|
+
|
|
263
|
+
Each node registration has three parts:
|
|
264
|
+
|
|
265
|
+
- `id`
|
|
266
|
+
- `definition`
|
|
267
|
+
- `metadata`
|
|
268
|
+
|
|
269
|
+
Example:
|
|
270
|
+
|
|
271
|
+
```ts
|
|
272
|
+
import type {
|
|
273
|
+
NodeContractMetadata,
|
|
274
|
+
PipelineNodeDefinition,
|
|
275
|
+
PluginNodeRegistration,
|
|
276
|
+
} from "agentweaver/plugin-sdk";
|
|
277
|
+
|
|
278
|
+
type SampleNodeParams = {
|
|
279
|
+
message: string;
|
|
280
|
+
};
|
|
281
|
+
|
|
282
|
+
type SampleNodeResult = {
|
|
283
|
+
echoed: string;
|
|
284
|
+
};
|
|
285
|
+
|
|
286
|
+
const sampleNodeDefinition: PipelineNodeDefinition<SampleNodeParams, SampleNodeResult> = {
|
|
287
|
+
kind: "sample-node",
|
|
288
|
+
version: 1,
|
|
289
|
+
async run(context, params) {
|
|
290
|
+
const executor = context.executors.get("sample-echo-executor");
|
|
291
|
+
const result = await executor.execute(context, { message: params.message }, executor.defaultConfig);
|
|
292
|
+
context.setSummary?.(`Echoed: ${result.echoed}`);
|
|
293
|
+
return {
|
|
294
|
+
value: {
|
|
295
|
+
echoed: result.echoed,
|
|
296
|
+
},
|
|
297
|
+
};
|
|
298
|
+
},
|
|
299
|
+
};
|
|
300
|
+
|
|
301
|
+
const sampleNodeMetadata: NodeContractMetadata = {
|
|
302
|
+
kind: "sample-node",
|
|
303
|
+
version: 1,
|
|
304
|
+
prompt: "forbidden",
|
|
305
|
+
requiredParams: ["message"],
|
|
306
|
+
executors: ["sample-echo-executor"],
|
|
307
|
+
};
|
|
308
|
+
|
|
309
|
+
export const nodes: PluginNodeRegistration[] = [
|
|
310
|
+
{
|
|
311
|
+
id: "sample-node",
|
|
312
|
+
definition: sampleNodeDefinition,
|
|
313
|
+
metadata: sampleNodeMetadata,
|
|
314
|
+
},
|
|
315
|
+
];
|
|
316
|
+
```
|
|
317
|
+
|
|
318
|
+
Rules enforced by the loader:
|
|
319
|
+
|
|
320
|
+
- `definition.kind === id`
|
|
321
|
+
- `metadata.kind === id`
|
|
322
|
+
- `definition.version` must be a positive integer
|
|
323
|
+
- `metadata.version` must be a positive integer
|
|
324
|
+
- `definition.version === metadata.version`
|
|
325
|
+
- `definition.run` must be a function
|
|
326
|
+
- `metadata.prompt` must be one of `required`, `allowed`, or `forbidden`
|
|
327
|
+
- `metadata.requiredParams`, when present, must be a non-empty `string[]`
|
|
328
|
+
- `metadata.executors`, when present, must be a non-empty `string[]`
|
|
329
|
+
- `metadata.nestedFlowParam`, when present, must be a non-empty string
|
|
330
|
+
|
|
331
|
+
After registries are merged, every executor id listed in `metadata.executors` must exist. This can point to built-in executors or plugin-provided executors.
|
|
332
|
+
|
|
333
|
+
### Node Runtime Context
|
|
334
|
+
|
|
335
|
+
`PipelineContext` contains everything from the executor-facing runtime plus pipeline-specific services:
|
|
336
|
+
|
|
337
|
+
- `issueKey`
|
|
338
|
+
- `jiraRef`
|
|
339
|
+
- `cwd`
|
|
340
|
+
- `env`
|
|
341
|
+
- `ui`
|
|
342
|
+
- `dryRun`
|
|
343
|
+
- `verbose`
|
|
344
|
+
- `mdLang`
|
|
345
|
+
- `runtime`
|
|
346
|
+
- `executors`
|
|
347
|
+
- `nodes`
|
|
348
|
+
- `registryContext`
|
|
349
|
+
- `setSummary(markdown)`
|
|
350
|
+
- `requestUserInput(...)` when the active node supports it
|
|
351
|
+
- `executionRouting`
|
|
352
|
+
- resume helpers such as `resumeStepValue` and `persistRunningStepValue`
|
|
353
|
+
|
|
354
|
+
Use the context object and the public SDK types as the stable integration surface. Do not couple plugin code to internal files under `src/` or `dist/`.
|
|
355
|
+
|
|
356
|
+
## Executors vs. Nodes
|
|
357
|
+
|
|
358
|
+
Use an executor when you need a reusable integration boundary:
|
|
359
|
+
|
|
360
|
+
- call an external CLI
|
|
361
|
+
- wrap a service client
|
|
362
|
+
- normalize I/O or configuration across nodes
|
|
363
|
+
|
|
364
|
+
Use a node when you need a flow-visible runtime unit:
|
|
365
|
+
|
|
366
|
+
- consume flow params
|
|
367
|
+
- enforce required params and prompt behavior through metadata
|
|
368
|
+
- combine one or more executors
|
|
369
|
+
- publish outputs or set summaries for the surrounding flow
|
|
370
|
+
|
|
371
|
+
A declarative flow never references an executor directly. It references node kinds. Nodes are the bridge between flow JSON and executor-backed behavior.
|
|
372
|
+
|
|
373
|
+
## Complete Plugin Entry Module
|
|
374
|
+
|
|
375
|
+
The following `index.js` is a minimal but complete plugin entrypoint that exports both a custom executor and a custom node:
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
/** @type {import("agentweaver/plugin-sdk").PluginExecutorRegistration[]} */
|
|
379
|
+
export const executors = [
|
|
380
|
+
{
|
|
381
|
+
id: "sample-echo-executor",
|
|
382
|
+
definition: {
|
|
383
|
+
kind: "sample-echo-executor",
|
|
384
|
+
version: 1,
|
|
385
|
+
defaultConfig: {
|
|
386
|
+
prefix: "plugin:",
|
|
387
|
+
},
|
|
388
|
+
async execute(context, input, config) {
|
|
389
|
+
context.ui.writeStdout(`[sample-echo-executor] ${String(input.message)}\n`);
|
|
390
|
+
return {
|
|
391
|
+
echoed: `${config.prefix}${String(input.message)}`,
|
|
392
|
+
};
|
|
393
|
+
},
|
|
394
|
+
},
|
|
395
|
+
},
|
|
396
|
+
];
|
|
397
|
+
|
|
398
|
+
/** @type {import("agentweaver/plugin-sdk").PluginNodeRegistration[]} */
|
|
399
|
+
export const nodes = [
|
|
400
|
+
{
|
|
401
|
+
id: "sample-node",
|
|
402
|
+
definition: {
|
|
403
|
+
kind: "sample-node",
|
|
404
|
+
version: 1,
|
|
405
|
+
async run(context, params) {
|
|
406
|
+
const executor = context.executors.get("sample-echo-executor");
|
|
407
|
+
const result = await executor.execute(
|
|
408
|
+
context,
|
|
409
|
+
{ message: String(params.message) },
|
|
410
|
+
executor.defaultConfig,
|
|
411
|
+
);
|
|
412
|
+
context.setSummary?.(`Sample node completed with ${result.echoed}`);
|
|
413
|
+
return {
|
|
414
|
+
value: result,
|
|
415
|
+
};
|
|
416
|
+
},
|
|
417
|
+
},
|
|
418
|
+
metadata: {
|
|
419
|
+
kind: "sample-node",
|
|
420
|
+
version: 1,
|
|
421
|
+
prompt: "forbidden",
|
|
422
|
+
requiredParams: ["message"],
|
|
423
|
+
executors: ["sample-echo-executor"],
|
|
424
|
+
},
|
|
425
|
+
},
|
|
426
|
+
];
|
|
427
|
+
```
|
|
428
|
+
|
|
429
|
+
## Wiring a Custom Flow
|
|
430
|
+
|
|
431
|
+
A custom flow can be discovered from `~/.agentweaver/.flows/**/*.json` or `.agentweaver/.flows/**/*.json`.
|
|
432
|
+
|
|
433
|
+
A flow can reference your plugin-provided node id directly:
|
|
434
|
+
|
|
435
|
+
```json
|
|
436
|
+
{
|
|
437
|
+
"kind": "sample-flow",
|
|
438
|
+
"version": 1,
|
|
439
|
+
"description": "Run the sample plugin node.",
|
|
440
|
+
"phases": [
|
|
441
|
+
{
|
|
442
|
+
"id": "run-sample",
|
|
443
|
+
"steps": [
|
|
444
|
+
{
|
|
445
|
+
"id": "echo",
|
|
446
|
+
"node": "sample-node",
|
|
447
|
+
"params": {
|
|
448
|
+
"message": {
|
|
449
|
+
"const": "hello from plugin"
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
]
|
|
454
|
+
}
|
|
455
|
+
]
|
|
456
|
+
}
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
Save that file as either:
|
|
460
|
+
|
|
461
|
+
```text
|
|
462
|
+
.agentweaver/.flows/sample-flow.json
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
or:
|
|
466
|
+
|
|
467
|
+
```text
|
|
468
|
+
~/.agentweaver/.flows/sample-flow.json
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
Once the plugin loads successfully, the flow validator treats `sample-node` like any built-in node kind.
|
|
472
|
+
|
|
473
|
+
### Nested Flow Resolution
|
|
474
|
+
|
|
475
|
+
If a node supports nested flow references through a metadata field such as `nestedFlowParam`, AgentWeaver resolves the nested flow by file name.
|
|
476
|
+
|
|
477
|
+
Resolution rules:
|
|
478
|
+
|
|
479
|
+
- project-local, global, and built-in flow file names must not collide for the same nested flow reference
|
|
480
|
+
- multiple project-local files with the same base file name are ambiguous
|
|
481
|
+
- multiple global files with the same base file name are ambiguous
|
|
482
|
+
- multiple built-in files with the same base file name are ambiguous
|
|
483
|
+
- an unknown file name fails validation
|
|
484
|
+
|
|
485
|
+
Keep nested flow file names unique when you rely on file-name-based resolution.
|
|
486
|
+
|
|
487
|
+
## End-to-End Walkthrough
|
|
488
|
+
|
|
489
|
+
This walkthrough is the acceptance path for the public docs. It creates a throwaway local plugin and runs a custom flow using only the documented contract.
|
|
490
|
+
|
|
491
|
+
### 1. Create the plugin directory
|
|
492
|
+
|
|
493
|
+
Use either project-local or global installation. Project-local example:
|
|
494
|
+
|
|
495
|
+
```bash
|
|
496
|
+
mkdir -p .agentweaver/.plugins/sample-plugin
|
|
497
|
+
```
|
|
498
|
+
|
|
499
|
+
Global example:
|
|
500
|
+
|
|
501
|
+
```bash
|
|
502
|
+
mkdir -p ~/.agentweaver/.plugins/sample-plugin
|
|
503
|
+
```
|
|
504
|
+
|
|
505
|
+
### 2. Write `plugin.json`
|
|
506
|
+
|
|
507
|
+
```json
|
|
508
|
+
{
|
|
509
|
+
"id": "sample-plugin",
|
|
510
|
+
"sdk_version": 1,
|
|
511
|
+
"entrypoint": "index.js",
|
|
512
|
+
"name": "Sample Plugin",
|
|
513
|
+
"version": "0.1.0",
|
|
514
|
+
"description": "Throwaway local plugin used to validate the public SDK guide."
|
|
515
|
+
}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
Write it to one of:
|
|
519
|
+
|
|
520
|
+
```text
|
|
521
|
+
.agentweaver/.plugins/sample-plugin/plugin.json
|
|
522
|
+
~/.agentweaver/.plugins/sample-plugin/plugin.json
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
### 3. Write the plugin entrypoint
|
|
526
|
+
|
|
527
|
+
Write the complete `index.js` example from the previous section to one of:
|
|
528
|
+
|
|
529
|
+
```text
|
|
530
|
+
.agentweaver/.plugins/sample-plugin/index.js
|
|
531
|
+
~/.agentweaver/.plugins/sample-plugin/index.js
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### 4. Create the custom flow
|
|
535
|
+
|
|
536
|
+
Project-local:
|
|
537
|
+
|
|
538
|
+
```bash
|
|
539
|
+
mkdir -p .agentweaver/.flows
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Global:
|
|
543
|
+
|
|
544
|
+
```bash
|
|
545
|
+
mkdir -p ~/.agentweaver/.flows
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
Create `sample-flow.json` in the matching flow directory with the flow JSON from the previous section.
|
|
549
|
+
|
|
550
|
+
### 5. Build AgentWeaver
|
|
551
|
+
|
|
552
|
+
From the AgentWeaver repository:
|
|
553
|
+
|
|
554
|
+
```bash
|
|
555
|
+
npm install
|
|
556
|
+
npm run build
|
|
557
|
+
```
|
|
558
|
+
|
|
559
|
+
### 6. Run the flow
|
|
560
|
+
|
|
561
|
+
Custom flows are discovered in the interactive catalog:
|
|
562
|
+
|
|
563
|
+
```bash
|
|
564
|
+
node dist/index.js
|
|
565
|
+
node dist/index.js --help
|
|
566
|
+
```
|
|
567
|
+
|
|
568
|
+
The flow should appear under either the `global` or `custom` catalog root with the id `sample-flow`. Select it from interactive mode and run it there.
|
|
569
|
+
|
|
570
|
+
### 7. Expected result
|
|
571
|
+
|
|
572
|
+
The registry should load the plugin, validate `sample-node`, and allow the custom flow to execute without reading AgentWeaver internals.
|
|
573
|
+
|
|
574
|
+
If execution fails, use the troubleshooting section below before inspecting any core source files.
|
|
575
|
+
|
|
576
|
+
## Compatibility and Versioning
|
|
577
|
+
|
|
578
|
+
Compatibility is strict:
|
|
579
|
+
|
|
580
|
+
- `sdk_version` must match the currently supported SDK major exactly
|
|
581
|
+
- the current public SDK major is `1`
|
|
582
|
+
- the supported public export is `agentweaver/plugin-sdk`
|
|
583
|
+
- built-in node and executor ids are protected and cannot be overridden
|
|
584
|
+
- plugin-provided ids must also be unique across all loaded plugins
|
|
585
|
+
|
|
586
|
+
Recommended upgrade workflow after updating AgentWeaver:
|
|
587
|
+
|
|
588
|
+
1. Check whether `AGENTWEAVER_PLUGIN_SDK_VERSION` changed.
|
|
589
|
+
2. Update `sdk_version` in each plugin manifest if the SDK major changed.
|
|
590
|
+
3. Rebuild AgentWeaver.
|
|
591
|
+
4. Run at least one local custom flow that exercises your plugin nodes.
|
|
592
|
+
5. Re-check packaging or deployment steps if you publish your plugin from a separate repository.
|
|
593
|
+
|
|
594
|
+
If the SDK major changes, review your plugin entrypoint, executor definitions, node metadata, routing metadata, and custom flow assumptions before trusting the plugin in production use.
|
|
595
|
+
|
|
596
|
+
## Testing Workflow for Plugin Authors
|
|
597
|
+
|
|
598
|
+
A practical minimum workflow:
|
|
599
|
+
|
|
600
|
+
1. Build AgentWeaver with `npm run build`.
|
|
601
|
+
2. Keep your plugin under `~/.agentweaver/.plugins/<plugin-id>/` or `.agentweaver/.plugins/<plugin-id>/`.
|
|
602
|
+
3. Keep one or more smoke-test flows under `~/.agentweaver/.flows/` or `.agentweaver/.flows/`.
|
|
603
|
+
4. Run a custom flow that touches every plugin node and executor dependency.
|
|
604
|
+
5. Re-run the flow after every AgentWeaver upgrade.
|
|
605
|
+
|
|
606
|
+
Useful checks:
|
|
607
|
+
|
|
608
|
+
- `npm run check`
|
|
609
|
+
- `npm run build`
|
|
610
|
+
- `node dist/index.js --help`
|
|
611
|
+
- interactive catalog inspection to confirm the custom flow is visible
|
|
612
|
+
|
|
613
|
+
## Troubleshooting
|
|
614
|
+
|
|
615
|
+
### Manifest parse error
|
|
616
|
+
|
|
617
|
+
Symptom: AgentWeaver reports that it failed to parse `plugin.json`.
|
|
618
|
+
|
|
619
|
+
Checks:
|
|
620
|
+
|
|
621
|
+
- ensure `plugin.json` is valid JSON
|
|
622
|
+
- ensure the top-level value is a JSON object
|
|
623
|
+
|
|
624
|
+
### Plugin directory does not match manifest id
|
|
625
|
+
|
|
626
|
+
Symptom: the loader reports that the manifest id does not match the installation directory.
|
|
627
|
+
|
|
628
|
+
Fix:
|
|
629
|
+
|
|
630
|
+
- rename the directory or change `plugin.json.id` so both values match exactly
|
|
631
|
+
|
|
632
|
+
### Unsupported `sdk_version`
|
|
633
|
+
|
|
634
|
+
Symptom: the loader reports that the plugin declares one SDK version but AgentWeaver supports another.
|
|
635
|
+
|
|
636
|
+
Fix:
|
|
637
|
+
|
|
638
|
+
- change `sdk_version` to the exact supported major
|
|
639
|
+
- review compatibility before trusting the plugin after the upgrade
|
|
640
|
+
|
|
641
|
+
### Invalid entrypoint path
|
|
642
|
+
|
|
643
|
+
Symptom: the loader reports that the entrypoint resolves outside the plugin root.
|
|
644
|
+
|
|
645
|
+
Fix:
|
|
646
|
+
|
|
647
|
+
- point `entrypoint` to a file inside `.agentweaver/.plugins/<plugin-id>/`
|
|
648
|
+
|
|
649
|
+
### Unsupported module format
|
|
650
|
+
|
|
651
|
+
Symptom: the loader rejects `.cjs` or another unsupported file extension.
|
|
652
|
+
|
|
653
|
+
Fix:
|
|
654
|
+
|
|
655
|
+
- use ESM `.js` or `.mjs`
|
|
656
|
+
|
|
657
|
+
### Default export misuse
|
|
658
|
+
|
|
659
|
+
Symptom: the loader reports that default exports are not supported.
|
|
660
|
+
|
|
661
|
+
Fix:
|
|
662
|
+
|
|
663
|
+
- export named `executors` and/or `nodes` arrays only
|
|
664
|
+
|
|
665
|
+
### Empty or missing registration arrays
|
|
666
|
+
|
|
667
|
+
Symptom: the loader reports that the plugin must export at least one non-empty recognized registration array.
|
|
668
|
+
|
|
669
|
+
Fix:
|
|
670
|
+
|
|
671
|
+
- export `executors`, `nodes`, or both
|
|
672
|
+
- make sure at least one of them contains a registration
|
|
673
|
+
|
|
674
|
+
### Invalid executor registration
|
|
675
|
+
|
|
676
|
+
Checks:
|
|
677
|
+
|
|
678
|
+
- `definition.kind` matches `id`
|
|
679
|
+
- `definition.version` is a positive integer
|
|
680
|
+
- `definition.defaultConfig` is JSON-serializable
|
|
681
|
+
- `definition.execute` is a function
|
|
682
|
+
|
|
683
|
+
### Invalid node registration
|
|
684
|
+
|
|
685
|
+
Checks:
|
|
686
|
+
|
|
687
|
+
- `definition.kind` matches `id`
|
|
688
|
+
- `metadata.kind` matches `id`
|
|
689
|
+
- `definition.version` matches `metadata.version`
|
|
690
|
+
- `metadata.prompt` is `required`, `allowed`, or `forbidden`
|
|
691
|
+
- `metadata.executors` references valid executor ids
|
|
692
|
+
|
|
693
|
+
### Duplicate ids
|
|
694
|
+
|
|
695
|
+
Symptom: registry creation fails because a node or executor id already exists.
|
|
696
|
+
|
|
697
|
+
Fix:
|
|
698
|
+
|
|
699
|
+
- rename the plugin-provided id
|
|
700
|
+
- avoid built-in ids and ids used by other local plugins
|
|
701
|
+
|
|
702
|
+
### Unresolved executor dependencies
|
|
703
|
+
|
|
704
|
+
Symptom: a node declares `metadata.executors` and registry creation reports an unknown executor.
|
|
705
|
+
|
|
706
|
+
Fix:
|
|
707
|
+
|
|
708
|
+
- export the executor from the same plugin or another loaded plugin
|
|
709
|
+
- confirm the executor id matches exactly
|
|
710
|
+
|
|
711
|
+
### Missing or ambiguous nested flow reference
|
|
712
|
+
|
|
713
|
+
Symptom: flow validation fails with an unknown or ambiguous nested flow name.
|
|
714
|
+
|
|
715
|
+
Fix:
|
|
716
|
+
|
|
717
|
+
- ensure the referenced file exists
|
|
718
|
+
- avoid duplicate base file names across global, project-local, and built-in flows
|
|
719
|
+
- keep global and project-local nested flow file names unique
|
|
720
|
+
|
|
721
|
+
## Supported Boundary Summary
|
|
722
|
+
|
|
723
|
+
Treat these as stable public assumptions for plugin authoring:
|
|
724
|
+
|
|
725
|
+
- import only from `agentweaver/plugin-sdk`
|
|
726
|
+
- install local plugins under `~/.agentweaver/.plugins/<plugin-id>/plugin.json` or `.agentweaver/.plugins/<plugin-id>/plugin.json`
|
|
727
|
+
- export named `executors` and/or `nodes` arrays from an ESM `.js` or `.mjs` entrypoint
|
|
728
|
+
- reference plugin node ids from `~/.agentweaver/.flows/**/*.json` or `.agentweaver/.flows/**/*.json`
|
|
729
|
+
- keep plugin ids, node ids, executor ids, and nested flow file names unambiguous
|
|
730
|
+
|
|
731
|
+
Everything else should be treated as internal implementation detail unless it is exposed through the public SDK subpath in a future release.
|