n8n-nodes-openclaw 1.0.0
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/LICENSE +28 -0
- package/README.md +164 -0
- package/dist/credentials/OpenClawApi.credentials.js +29 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +12 -0
- package/dist/nodes/OpenClaw/OpenClaw.node.js +284 -0
- package/dist/nodes/OpenClaw/openclaw.svg +22 -0
- package/dist/nodes/OpenClaw/toolSchemas.js +2334 -0
- package/package.json +138 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
BSD 3-Clause License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025, Jason Williscroft
|
|
4
|
+
|
|
5
|
+
Redistribution and use in source and binary forms, with or without
|
|
6
|
+
modification, are permitted provided that the following conditions are met:
|
|
7
|
+
|
|
8
|
+
1. Redistributions of source code must retain the above copyright notice, this
|
|
9
|
+
list of conditions and the following disclaimer.
|
|
10
|
+
|
|
11
|
+
2. Redistributions in binary form must reproduce the above copyright notice,
|
|
12
|
+
this list of conditions and the following disclaimer in the documentation
|
|
13
|
+
and/or other materials provided with the distribution.
|
|
14
|
+
|
|
15
|
+
3. Neither the name of the copyright holder nor the names of its
|
|
16
|
+
contributors may be used to endorse or promote products derived from
|
|
17
|
+
this software without specific prior written permission.
|
|
18
|
+
|
|
19
|
+
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
20
|
+
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
21
|
+
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|
22
|
+
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
|
|
23
|
+
FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
24
|
+
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
|
25
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
|
|
26
|
+
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
27
|
+
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
28
|
+
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
package/README.md
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
# n8n-nodes-openclaw
|
|
2
|
+
|
|
3
|
+
[n8n](https://n8n.io/) community nodes for the [OpenClaw](https://github.com/openclaw/openclaw) Gateway API.
|
|
4
|
+
|
|
5
|
+
Control your OpenClaw instance from n8n workflows — manage sessions, send messages, run cron jobs, search the web, execute commands, and more.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
[](https://www.npmjs.com/package/n8n-nodes-openclaw)
|
|
9
|
+
[](LICENSE)
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
### Community Nodes (recommended)
|
|
14
|
+
|
|
15
|
+
1. Open **Settings → Community Nodes** in your n8n instance
|
|
16
|
+
2. Click **Install a community node**
|
|
17
|
+
3. Enter `n8n-nodes-openclaw`
|
|
18
|
+
4. Click **Install**
|
|
19
|
+
|
|
20
|
+
### Manual Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
# In your n8n custom nodes directory
|
|
24
|
+
cd ~/.n8n/custom
|
|
25
|
+
npm install n8n-nodes-openclaw
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Or link from source:
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
git clone https://github.com/karmaniverous/n8n-nodes-openclaw.git
|
|
32
|
+
cd n8n-nodes-openclaw
|
|
33
|
+
npm install
|
|
34
|
+
npm run build
|
|
35
|
+
|
|
36
|
+
# Link into n8n
|
|
37
|
+
mkdir -p ~/.n8n/custom/node_modules
|
|
38
|
+
ln -s "$(pwd)" ~/.n8n/custom/node_modules/n8n-nodes-openclaw
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then restart n8n.
|
|
42
|
+
|
|
43
|
+
## Setup
|
|
44
|
+
|
|
45
|
+
1. In n8n, go to **Settings → Credentials → Add Credential**
|
|
46
|
+
2. Search for **OpenClaw API**
|
|
47
|
+
3. Enter your:
|
|
48
|
+
- **Gateway URL** — e.g. `http://127.0.0.1:18789`
|
|
49
|
+
- **Gateway Token** — found in your OpenClaw config file under `gateway.auth.token`
|
|
50
|
+
|
|
51
|
+
## Available Tools
|
|
52
|
+
|
|
53
|
+
The OpenClaw node exposes **20 tools** via a Resource dropdown, each with contextual parameters:
|
|
54
|
+
|
|
55
|
+
| Resource | Description |
|
|
56
|
+
|----------|-------------|
|
|
57
|
+
| **Agents List** | List available agent IDs for spawning sub-agents |
|
|
58
|
+
| **Browser** | Control a browser — open pages, screenshots, snapshots, click, fill forms |
|
|
59
|
+
| **Canvas** | Control canvas overlays on paired nodes |
|
|
60
|
+
| **Cron** | Manage scheduled jobs — list, add, update, remove, run, wake |
|
|
61
|
+
| **Execute Command** | Run shell commands on the host system |
|
|
62
|
+
| **Gateway** | Manage the gateway — restart, read/write config, trigger updates |
|
|
63
|
+
| **Image** | Analyze images with a vision model |
|
|
64
|
+
| **Memory Get** | Read snippets from agent memory files |
|
|
65
|
+
| **Memory Search** | Semantically search agent memory |
|
|
66
|
+
| **Message** | Send, read, edit, delete messages across channels (Slack, Discord, Telegram, etc.) |
|
|
67
|
+
| **Nodes** | Discover and control paired nodes — notifications, camera, location, commands |
|
|
68
|
+
| **Process Manager** | Manage running exec sessions — poll, log, write stdin, kill |
|
|
69
|
+
| **Session Status** | Get session status, usage stats, and set model overrides |
|
|
70
|
+
| **Sessions History** | Retrieve conversation history for a session |
|
|
71
|
+
| **Sessions List** | List active sessions with filters |
|
|
72
|
+
| **Sessions Send** | Send messages into other sessions (cross-session communication) |
|
|
73
|
+
| **Sessions Spawn** | Spawn background sub-agents in isolated sessions |
|
|
74
|
+
| **Text to Speech** | Convert text to speech audio |
|
|
75
|
+
| **Web Fetch** | Fetch and extract readable content from URLs (HTML → markdown) |
|
|
76
|
+
| **Web Search** | Search the web via Brave Search |
|
|
77
|
+
|
|
78
|
+
### Raw Mode
|
|
79
|
+
|
|
80
|
+
Every resource supports **Raw Mode** — toggle it on to send arbitrary JSON arguments instead of using the form fields. Useful for edge cases or new parameters not yet in the schema.
|
|
81
|
+
|
|
82
|
+
## CLI Commands Not in the API
|
|
83
|
+
|
|
84
|
+
The OpenClaw CLI (`openclaw`) has commands that are **not available** via the Gateway HTTP API — notably `openclaw gateway status`, `openclaw gateway start`, and `openclaw gateway stop`. These manage the local daemon and require OS-level access.
|
|
85
|
+
|
|
86
|
+
If you need these in a workflow, use n8n's built-in **Execute Command** node to run them directly:
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
openclaw gateway status
|
|
90
|
+
```
|
|
91
|
+
|
|
92
|
+
The CLI does not currently support JSON output, so you'll need to parse the human-readable text.
|
|
93
|
+
|
|
94
|
+
## Examples
|
|
95
|
+
|
|
96
|
+
See the [`examples/`](examples/) directory for ready-to-import n8n workflow files:
|
|
97
|
+
|
|
98
|
+
- **List Sessions** — basic workflow showing session listing
|
|
99
|
+
- **Send Slack Message** — send a message to a Slack channel
|
|
100
|
+
- **Cron Job Management** — list and run cron jobs
|
|
101
|
+
- **Web Search → Message** — search the web and post results to a channel
|
|
102
|
+
|
|
103
|
+
Import any example via **Workflows → Import from File** in n8n.
|
|
104
|
+
|
|
105
|
+
## How It Works
|
|
106
|
+
|
|
107
|
+
This node calls the OpenClaw Gateway's [`POST /tools/invoke`](https://docs.openclaw.ai) endpoint. Each resource/action combination maps to a tool invocation:
|
|
108
|
+
|
|
109
|
+
```json
|
|
110
|
+
{
|
|
111
|
+
"tool": "sessions_list",
|
|
112
|
+
"args": { "limit": 5, "kinds": ["main", "group"] }
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
The gateway enforces tool policies, authentication, and session context. See the [OpenClaw docs](https://docs.openclaw.ai) for full API details.
|
|
117
|
+
|
|
118
|
+
## Development
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
git clone https://github.com/karmaniverous/n8n-nodes-openclaw.git
|
|
122
|
+
cd n8n-nodes-openclaw
|
|
123
|
+
npm install
|
|
124
|
+
npm run build
|
|
125
|
+
npm test
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
### Project Structure
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
src/
|
|
132
|
+
credentials/ # OpenClaw API credential type
|
|
133
|
+
nodes/OpenClaw/ # Main node implementation
|
|
134
|
+
OpenClaw.node.ts # Node class with execute function
|
|
135
|
+
toolSchemas.ts # Static tool schema loader
|
|
136
|
+
openclaw.svg # Node icon
|
|
137
|
+
tool-schemas/ # JSON schema files for each tool (20 files)
|
|
138
|
+
examples/ # Example n8n workflows
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
### Running Tests
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
npm test # Unit tests
|
|
145
|
+
OPENCLAW_TOKEN=<token> npm test # + integration tests against live gateway
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
### Linting & Type Checking
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
npm run lint
|
|
152
|
+
npm run typecheck
|
|
153
|
+
npm run knip # Unused exports/dependencies check
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
## License
|
|
157
|
+
|
|
158
|
+
[BSD-3-Clause](LICENSE)
|
|
159
|
+
|
|
160
|
+
## Links
|
|
161
|
+
|
|
162
|
+
- [OpenClaw](https://github.com/openclaw/openclaw) — the AI agent framework
|
|
163
|
+
- [OpenClaw Docs](https://docs.openclaw.ai) — full documentation
|
|
164
|
+
- [n8n Community Nodes](https://docs.n8n.io/integrations/community-nodes/) — how community nodes work
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
class OpenClawApi {
|
|
4
|
+
name = 'openClawApi';
|
|
5
|
+
displayName = 'OpenClaw API';
|
|
6
|
+
documentationUrl = 'https://docs.openclaw.ai/gateway/tools-invoke-http-api';
|
|
7
|
+
properties = [
|
|
8
|
+
{
|
|
9
|
+
displayName: 'Gateway URL',
|
|
10
|
+
name: 'gatewayUrl',
|
|
11
|
+
type: 'string',
|
|
12
|
+
default: 'http://127.0.0.1:18789',
|
|
13
|
+
placeholder: 'http://127.0.0.1:18789',
|
|
14
|
+
description: 'The URL of your OpenClaw Gateway. Default port is 18789.',
|
|
15
|
+
required: true,
|
|
16
|
+
},
|
|
17
|
+
{
|
|
18
|
+
displayName: 'Gateway Token',
|
|
19
|
+
name: 'gatewayToken',
|
|
20
|
+
type: 'string',
|
|
21
|
+
typeOptions: { password: true },
|
|
22
|
+
default: '',
|
|
23
|
+
description: 'The authentication token for your OpenClaw Gateway. Found in your gateway config under gateway.auth.token.',
|
|
24
|
+
required: true,
|
|
25
|
+
},
|
|
26
|
+
];
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
exports.OpenClawApi = OpenClawApi;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { ICredentialType, INodeProperties, INodeType, INodeTypeDescription, IExecuteFunctions, INodeExecutionData } from 'n8n-workflow';
|
|
2
|
+
|
|
3
|
+
declare class OpenClawApi implements ICredentialType {
|
|
4
|
+
name: string;
|
|
5
|
+
displayName: string;
|
|
6
|
+
documentationUrl: string;
|
|
7
|
+
properties: INodeProperties[];
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
declare class OpenClaw implements INodeType {
|
|
11
|
+
description: INodeTypeDescription;
|
|
12
|
+
execute(this: IExecuteFunctions): Promise<INodeExecutionData[][]>;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Tool schema type definition.
|
|
17
|
+
*/
|
|
18
|
+
interface ToolParameterDef {
|
|
19
|
+
type: string;
|
|
20
|
+
required?: boolean;
|
|
21
|
+
enum?: string[];
|
|
22
|
+
description?: string;
|
|
23
|
+
default?: unknown;
|
|
24
|
+
placeholder?: string;
|
|
25
|
+
/** If true, the n8n field is a comma-separated string that should be split into an array before sending to the API. */
|
|
26
|
+
splitAsArray?: boolean;
|
|
27
|
+
displayOptions?: {
|
|
28
|
+
show?: {
|
|
29
|
+
action?: string[];
|
|
30
|
+
};
|
|
31
|
+
};
|
|
32
|
+
}
|
|
33
|
+
interface ToolSchema {
|
|
34
|
+
name: string;
|
|
35
|
+
label: string;
|
|
36
|
+
description: string;
|
|
37
|
+
actions?: string[];
|
|
38
|
+
parameters: Record<string, ToolParameterDef>;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* All tool schemas, sorted by label for UI display.
|
|
42
|
+
*/
|
|
43
|
+
declare const toolSchemas: ToolSchema[];
|
|
44
|
+
|
|
45
|
+
export { OpenClaw, OpenClawApi, toolSchemas };
|
|
46
|
+
export type { ToolParameterDef, ToolSchema };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var credentials_OpenClawApi_credentials = require('./credentials/OpenClawApi.credentials.js');
|
|
4
|
+
var nodes_OpenClaw_OpenClaw_node = require('./nodes/OpenClaw/OpenClaw.node.js');
|
|
5
|
+
var nodes_OpenClaw_toolSchemas = require('./nodes/OpenClaw/toolSchemas.js');
|
|
6
|
+
require('n8n-workflow');
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
exports.OpenClawApi = credentials_OpenClawApi_credentials.OpenClawApi;
|
|
11
|
+
exports.OpenClaw = nodes_OpenClaw_OpenClaw_node.OpenClaw;
|
|
12
|
+
exports.toolSchemas = nodes_OpenClaw_toolSchemas.toolSchemas;
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var n8nWorkflow = require('n8n-workflow');
|
|
4
|
+
var nodes_OpenClaw_toolSchemas = require('./toolSchemas.js');
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Build n8n node properties from tool schemas.
|
|
8
|
+
*/
|
|
9
|
+
function buildResourceOptions() {
|
|
10
|
+
return nodes_OpenClaw_toolSchemas.toolSchemas.map((schema) => ({
|
|
11
|
+
name: schema.label,
|
|
12
|
+
value: schema.name,
|
|
13
|
+
description: schema.description,
|
|
14
|
+
}));
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Build action (operation) options for a specific tool.
|
|
18
|
+
*/
|
|
19
|
+
function buildActionProperties() {
|
|
20
|
+
const properties = [];
|
|
21
|
+
for (const schema of nodes_OpenClaw_toolSchemas.toolSchemas) {
|
|
22
|
+
if (!schema.actions)
|
|
23
|
+
continue;
|
|
24
|
+
properties.push({
|
|
25
|
+
displayName: 'Action',
|
|
26
|
+
name: 'action',
|
|
27
|
+
type: 'options',
|
|
28
|
+
displayOptions: {
|
|
29
|
+
show: { resource: [schema.name] },
|
|
30
|
+
},
|
|
31
|
+
options: schema.actions.map((action) => ({
|
|
32
|
+
name: action.charAt(0).toUpperCase() + action.slice(1),
|
|
33
|
+
value: action,
|
|
34
|
+
})),
|
|
35
|
+
default: schema.actions[0],
|
|
36
|
+
noDataExpression: true,
|
|
37
|
+
required: true,
|
|
38
|
+
description: `The ${schema.label} operation to perform`,
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
return properties;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Build parameter fields for each tool, respecting displayOptions.
|
|
45
|
+
*/
|
|
46
|
+
function buildParameterProperties() {
|
|
47
|
+
const properties = [];
|
|
48
|
+
for (const schema of nodes_OpenClaw_toolSchemas.toolSchemas) {
|
|
49
|
+
const params = schema.parameters;
|
|
50
|
+
for (const [paramName, paramDef] of Object.entries(params)) {
|
|
51
|
+
// Skip 'action' — already handled above
|
|
52
|
+
if (paramName === 'action')
|
|
53
|
+
continue;
|
|
54
|
+
// Skip gateway override params — handled by credentials
|
|
55
|
+
if (paramName === 'gatewayUrl' || paramName === 'gatewayToken')
|
|
56
|
+
continue;
|
|
57
|
+
const displayOptions = {
|
|
58
|
+
show: { resource: [schema.name] },
|
|
59
|
+
};
|
|
60
|
+
// If the param has its own displayOptions.show.action, merge it
|
|
61
|
+
if (paramDef.displayOptions?.show?.action) {
|
|
62
|
+
displayOptions.show.action =
|
|
63
|
+
paramDef.displayOptions.show.action;
|
|
64
|
+
}
|
|
65
|
+
const n8nType = mapType(paramDef.type);
|
|
66
|
+
const prop = {
|
|
67
|
+
displayName: formatDisplayName(paramName),
|
|
68
|
+
name: paramName,
|
|
69
|
+
type: n8nType,
|
|
70
|
+
displayOptions,
|
|
71
|
+
default: paramDef.default ?? (n8nType === 'boolean' ? false : ''),
|
|
72
|
+
required: paramDef.required ?? false,
|
|
73
|
+
description: paramDef.description ?? '',
|
|
74
|
+
};
|
|
75
|
+
if (paramDef.enum && n8nType === 'options') {
|
|
76
|
+
prop.options = paramDef.enum.map((v) => ({
|
|
77
|
+
name: v.charAt(0).toUpperCase() + v.slice(1),
|
|
78
|
+
value: v,
|
|
79
|
+
}));
|
|
80
|
+
}
|
|
81
|
+
if (paramDef.placeholder) {
|
|
82
|
+
prop.placeholder = paramDef.placeholder;
|
|
83
|
+
}
|
|
84
|
+
// For object/json types, use the json type
|
|
85
|
+
if (paramDef.type === 'object') {
|
|
86
|
+
prop.type = 'json';
|
|
87
|
+
prop.default = '{}';
|
|
88
|
+
}
|
|
89
|
+
properties.push(prop);
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
return properties;
|
|
93
|
+
}
|
|
94
|
+
function mapType(schemaType) {
|
|
95
|
+
switch (schemaType) {
|
|
96
|
+
case 'string':
|
|
97
|
+
return 'string';
|
|
98
|
+
case 'number':
|
|
99
|
+
return 'number';
|
|
100
|
+
case 'boolean':
|
|
101
|
+
return 'boolean';
|
|
102
|
+
case 'object':
|
|
103
|
+
return 'json';
|
|
104
|
+
default:
|
|
105
|
+
return 'string';
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
function formatDisplayName(name) {
|
|
109
|
+
return name
|
|
110
|
+
.replace(/([A-Z])/g, ' $1')
|
|
111
|
+
.replace(/[_-]/g, ' ')
|
|
112
|
+
.replace(/\b\w/g, (c) => c.toUpperCase())
|
|
113
|
+
.trim();
|
|
114
|
+
}
|
|
115
|
+
class OpenClaw {
|
|
116
|
+
description = {
|
|
117
|
+
displayName: 'OpenClaw',
|
|
118
|
+
name: 'openClaw',
|
|
119
|
+
icon: 'file:openclaw.svg',
|
|
120
|
+
group: ['transform'],
|
|
121
|
+
version: 1,
|
|
122
|
+
subtitle: '={{$parameter["resource"] + ": " + ($parameter["action"] || "execute")}}',
|
|
123
|
+
description: 'Interact with the OpenClaw Gateway API',
|
|
124
|
+
defaults: {
|
|
125
|
+
name: 'OpenClaw',
|
|
126
|
+
},
|
|
127
|
+
inputs: ['main'],
|
|
128
|
+
outputs: ['main'],
|
|
129
|
+
credentials: [
|
|
130
|
+
{
|
|
131
|
+
name: 'openClawApi',
|
|
132
|
+
required: true,
|
|
133
|
+
},
|
|
134
|
+
],
|
|
135
|
+
properties: [
|
|
136
|
+
// Resource selector (tool)
|
|
137
|
+
{
|
|
138
|
+
displayName: 'Resource',
|
|
139
|
+
name: 'resource',
|
|
140
|
+
type: 'options',
|
|
141
|
+
noDataExpression: true,
|
|
142
|
+
options: buildResourceOptions(),
|
|
143
|
+
default: 'sessions_list',
|
|
144
|
+
required: true,
|
|
145
|
+
description: 'The OpenClaw tool to invoke',
|
|
146
|
+
},
|
|
147
|
+
// Raw mode option
|
|
148
|
+
{
|
|
149
|
+
displayName: 'Raw Mode',
|
|
150
|
+
name: 'rawMode',
|
|
151
|
+
type: 'boolean',
|
|
152
|
+
default: false,
|
|
153
|
+
description: 'Whether to send raw JSON arguments instead of using the form fields. Useful for tools not yet supported with typed fields.',
|
|
154
|
+
},
|
|
155
|
+
{
|
|
156
|
+
displayName: 'Raw Arguments (JSON)',
|
|
157
|
+
name: 'rawArgs',
|
|
158
|
+
type: 'json',
|
|
159
|
+
default: '{}',
|
|
160
|
+
displayOptions: {
|
|
161
|
+
show: { rawMode: [true] },
|
|
162
|
+
},
|
|
163
|
+
description: 'Raw JSON arguments to pass to the tool',
|
|
164
|
+
},
|
|
165
|
+
// Action selectors per resource
|
|
166
|
+
...buildActionProperties(),
|
|
167
|
+
// Parameter fields per resource
|
|
168
|
+
...buildParameterProperties(),
|
|
169
|
+
],
|
|
170
|
+
};
|
|
171
|
+
async execute() {
|
|
172
|
+
const items = this.getInputData();
|
|
173
|
+
const returnData = [];
|
|
174
|
+
const credentials = await this.getCredentials('openClawApi');
|
|
175
|
+
const gatewayUrl = credentials.gatewayUrl;
|
|
176
|
+
const gatewayToken = credentials.gatewayToken;
|
|
177
|
+
for (let i = 0; i < items.length; i++) {
|
|
178
|
+
try {
|
|
179
|
+
const resource = this.getNodeParameter('resource', i);
|
|
180
|
+
const rawMode = this.getNodeParameter('rawMode', i, false);
|
|
181
|
+
let args;
|
|
182
|
+
if (rawMode) {
|
|
183
|
+
const rawArgs = this.getNodeParameter('rawArgs', i, '{}');
|
|
184
|
+
args = JSON.parse(rawArgs);
|
|
185
|
+
}
|
|
186
|
+
else {
|
|
187
|
+
args = buildArgsFromParameters.call(this, resource, i);
|
|
188
|
+
}
|
|
189
|
+
const body = {
|
|
190
|
+
tool: resource,
|
|
191
|
+
args,
|
|
192
|
+
};
|
|
193
|
+
// If there's an action, also set it at the top level
|
|
194
|
+
if (args.action) {
|
|
195
|
+
body.action = args.action;
|
|
196
|
+
}
|
|
197
|
+
const options = {
|
|
198
|
+
method: 'POST',
|
|
199
|
+
url: `${gatewayUrl.replace(/\/$/, '')}/tools/invoke`,
|
|
200
|
+
body,
|
|
201
|
+
headers: {
|
|
202
|
+
'Content-Type': 'application/json',
|
|
203
|
+
Authorization: `Bearer ${gatewayToken}`,
|
|
204
|
+
},
|
|
205
|
+
json: true,
|
|
206
|
+
};
|
|
207
|
+
const response = (await this.helpers.httpRequest(options));
|
|
208
|
+
if (response.ok === false) {
|
|
209
|
+
throw new n8nWorkflow.NodeApiError(this.getNode(), response, {
|
|
210
|
+
message: response.error?.message ?? 'Unknown error',
|
|
211
|
+
});
|
|
212
|
+
}
|
|
213
|
+
returnData.push({
|
|
214
|
+
json: (response.result ?? response),
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
catch (error) {
|
|
218
|
+
if (this.continueOnFail()) {
|
|
219
|
+
returnData.push({
|
|
220
|
+
json: { error: error.message },
|
|
221
|
+
});
|
|
222
|
+
continue;
|
|
223
|
+
}
|
|
224
|
+
throw error;
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return [returnData];
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Build args object from n8n parameter values for a given resource.
|
|
232
|
+
*/
|
|
233
|
+
function buildArgsFromParameters(resource, itemIndex) {
|
|
234
|
+
const schema = nodes_OpenClaw_toolSchemas.toolSchemas.find((s) => s.name === resource);
|
|
235
|
+
if (!schema)
|
|
236
|
+
return {};
|
|
237
|
+
const args = {};
|
|
238
|
+
// Get action if this tool has actions
|
|
239
|
+
if (schema.actions && schema.actions.length > 0) {
|
|
240
|
+
try {
|
|
241
|
+
args.action = this.getNodeParameter('action', itemIndex);
|
|
242
|
+
}
|
|
243
|
+
catch {
|
|
244
|
+
// action not available for this resource
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
// Get each parameter
|
|
248
|
+
for (const [paramName, paramDef] of Object.entries(schema.parameters)) {
|
|
249
|
+
if (paramName === 'action')
|
|
250
|
+
continue;
|
|
251
|
+
if (paramName === 'gatewayUrl' || paramName === 'gatewayToken')
|
|
252
|
+
continue;
|
|
253
|
+
try {
|
|
254
|
+
const value = this.getNodeParameter(paramName, itemIndex, undefined);
|
|
255
|
+
if (value !== undefined && !(typeof value === 'string' && value === '')) {
|
|
256
|
+
if (paramDef.type === 'object' && typeof value === 'string') {
|
|
257
|
+
// Parse JSON strings for object types
|
|
258
|
+
try {
|
|
259
|
+
args[paramName] = JSON.parse(value);
|
|
260
|
+
}
|
|
261
|
+
catch {
|
|
262
|
+
args[paramName] = value;
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
else if (paramDef.splitAsArray && typeof value === 'string') {
|
|
266
|
+
// Split comma-separated strings into arrays
|
|
267
|
+
args[paramName] = value
|
|
268
|
+
.split(',')
|
|
269
|
+
.map((s) => s.trim())
|
|
270
|
+
.filter((s) => s.length > 0);
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
args[paramName] = value;
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
catch {
|
|
278
|
+
// Parameter not available (hidden by displayOptions)
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
return args;
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
exports.OpenClaw = OpenClaw;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
<svg viewBox="0 0 120 120" fill="none" xmlns="http://www.w3.org/2000/svg">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="lobster-gradient" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
+
<stop offset="0%" stop-color="#ff4d4d"/>
|
|
5
|
+
<stop offset="100%" stop-color="#991b1b"/>
|
|
6
|
+
</linearGradient>
|
|
7
|
+
</defs>
|
|
8
|
+
<!-- Body -->
|
|
9
|
+
<path d="M60 10 C30 10 15 35 15 55 C15 75 30 95 45 100 L45 110 L55 110 L55 100 C55 100 60 102 65 100 L65 110 L75 110 L75 100 C90 95 105 75 105 55 C105 35 90 10 60 10Z" fill="url(#lobster-gradient)"/>
|
|
10
|
+
<!-- Left Claw -->
|
|
11
|
+
<path d="M20 45 C5 40 0 50 5 60 C10 70 20 65 25 55 C28 48 25 45 20 45Z" fill="url(#lobster-gradient)"/>
|
|
12
|
+
<!-- Right Claw -->
|
|
13
|
+
<path d="M100 45 C115 40 120 50 115 60 C110 70 100 65 95 55 C92 48 95 45 100 45Z" fill="url(#lobster-gradient)"/>
|
|
14
|
+
<!-- Antenna -->
|
|
15
|
+
<path d="M45 15 Q35 5 30 8" stroke="#ff4d4d" stroke-width="3" stroke-linecap="round"/>
|
|
16
|
+
<path d="M75 15 Q85 5 90 8" stroke="#ff4d4d" stroke-width="3" stroke-linecap="round"/>
|
|
17
|
+
<!-- Eyes -->
|
|
18
|
+
<circle cx="45" cy="35" r="6" fill="#050810"/>
|
|
19
|
+
<circle cx="75" cy="35" r="6" fill="#050810"/>
|
|
20
|
+
<circle cx="46" cy="34" r="2.5" fill="#00e5cc"/>
|
|
21
|
+
<circle cx="76" cy="34" r="2.5" fill="#00e5cc"/>
|
|
22
|
+
</svg>
|