clawmoney 0.8.3 → 0.8.4
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/dist/commands/hub.js +16 -2
- package/dist/hub/executor.js +78 -26
- package/dist/hub/provider.js +10 -1
- package/dist/hub/types.d.ts +3 -0
- package/dist/utils/api.js +3 -2
- package/dist/utils/config.d.ts +8 -0
- package/package.json +1 -1
package/dist/commands/hub.js
CHANGED
|
@@ -41,8 +41,15 @@ export async function hubStartCommand(options) {
|
|
|
41
41
|
const pid = readPid();
|
|
42
42
|
if (pid && isPidAlive(pid)) {
|
|
43
43
|
spinner.succeed(chalk.green(`Hub Provider started (PID ${pid})`));
|
|
44
|
+
const mode = config.provider?.execution_mode || "webhook";
|
|
44
45
|
console.log(chalk.dim(` Log file: ${LOG_FILE}`));
|
|
45
|
-
console.log(chalk.dim(`
|
|
46
|
+
console.log(chalk.dim(` Mode: ${mode}`));
|
|
47
|
+
if (mode === "cli") {
|
|
48
|
+
console.log(chalk.dim(` CLI command: ${options.cli || config.provider?.cli_command || "claude"}`));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
console.log(chalk.dim(` Webhook: ${config.provider?.webhook_url || "http://127.0.0.1:18789/hooks/agent"}`));
|
|
52
|
+
}
|
|
46
53
|
console.log(chalk.dim(` API key: ${config.api_key.slice(0, 8)}...`));
|
|
47
54
|
}
|
|
48
55
|
else {
|
|
@@ -155,7 +162,14 @@ export async function hubCallCommand(options) {
|
|
|
155
162
|
const timeout = options.timeout ? parseInt(options.timeout, 10) : 60;
|
|
156
163
|
const spinner = ora(`Calling ${options.agent}/${options.skill}...`).start();
|
|
157
164
|
try {
|
|
158
|
-
|
|
165
|
+
// gateway/invoke takes agent_id, skill, timeout as query params; input_data as POST body
|
|
166
|
+
const qs = new URLSearchParams({
|
|
167
|
+
agent_id: options.agent,
|
|
168
|
+
skill: options.skill,
|
|
169
|
+
timeout: String(timeout),
|
|
170
|
+
payment_method: "ledger",
|
|
171
|
+
});
|
|
172
|
+
const resp = await apiPost(`/api/v1/hub/gateway/invoke?${qs}`, inputData, config.api_key);
|
|
159
173
|
if (!resp.ok) {
|
|
160
174
|
const raw = resp.data && typeof resp.data === "object" && "detail" in resp.data
|
|
161
175
|
? resp.data.detail
|
package/dist/hub/executor.js
CHANGED
|
@@ -3,6 +3,7 @@ import { isProcessed, markProcessed } from "./dedup.js";
|
|
|
3
3
|
import { replaceLocalPaths } from "./media.js";
|
|
4
4
|
import { logger } from "./logger.js";
|
|
5
5
|
const TIMEOUT_BUFFER_S = 15;
|
|
6
|
+
// ── Prompt builder ──
|
|
6
7
|
function buildPrompt(call, config) {
|
|
7
8
|
const skillConfig = config.provider.skills?.[call.skill];
|
|
8
9
|
if (skillConfig?.prompt_template) {
|
|
@@ -13,13 +14,60 @@ function buildPrompt(call, config) {
|
|
|
13
14
|
return [
|
|
14
15
|
"You received a paid service request via ClawMoney Hub.",
|
|
15
16
|
`Skill: ${call.skill}`,
|
|
17
|
+
`Category: ${call.category}`,
|
|
18
|
+
`From: ${call.from}`,
|
|
19
|
+
`Price: $${call.price}`,
|
|
16
20
|
`Input: ${JSON.stringify(call.input, null, 2)}`,
|
|
17
21
|
"",
|
|
18
22
|
"Execute this task and return the result as JSON.",
|
|
19
|
-
"If you generate any files, save them and include their paths in the output.",
|
|
23
|
+
"If you generate any files (images, videos, etc.), save them and include their file paths in the output.",
|
|
24
|
+
"Return ONLY the JSON result, no other text.",
|
|
20
25
|
].join("\n");
|
|
21
26
|
}
|
|
22
|
-
|
|
27
|
+
// ── OpenClaw Webhook execution ──
|
|
28
|
+
async function executeViaWebhook(call, config, prompt, timeoutS) {
|
|
29
|
+
const { webhook_url, webhook_token } = config.provider;
|
|
30
|
+
logger.info(`Executing via OpenClaw webhook: skill="${call.skill}" order=${call.order_id}`);
|
|
31
|
+
const controller = new AbortController();
|
|
32
|
+
const timer = setTimeout(() => controller.abort(), timeoutS * 1000);
|
|
33
|
+
try {
|
|
34
|
+
const resp = await fetch(webhook_url, {
|
|
35
|
+
method: "POST",
|
|
36
|
+
headers: {
|
|
37
|
+
"Content-Type": "application/json",
|
|
38
|
+
Authorization: `Bearer ${webhook_token}`,
|
|
39
|
+
},
|
|
40
|
+
body: JSON.stringify({
|
|
41
|
+
message: prompt,
|
|
42
|
+
name: `Hub: ${call.skill}`,
|
|
43
|
+
deliver: false, // don't send to messaging channel
|
|
44
|
+
timeoutSeconds: timeoutS,
|
|
45
|
+
}),
|
|
46
|
+
signal: controller.signal,
|
|
47
|
+
});
|
|
48
|
+
clearTimeout(timer);
|
|
49
|
+
if (!resp.ok) {
|
|
50
|
+
const text = await resp.text();
|
|
51
|
+
throw new Error(`Webhook returned ${resp.status}: ${text}`);
|
|
52
|
+
}
|
|
53
|
+
const text = await resp.text();
|
|
54
|
+
// Try to parse JSON from response
|
|
55
|
+
const parsed = parseJsonOutput(text);
|
|
56
|
+
if (parsed)
|
|
57
|
+
return parsed;
|
|
58
|
+
// If response is not JSON, wrap as text result
|
|
59
|
+
return { result: text.trim().slice(0, 5000) };
|
|
60
|
+
}
|
|
61
|
+
catch (err) {
|
|
62
|
+
clearTimeout(timer);
|
|
63
|
+
if (err instanceof Error && err.name === "AbortError") {
|
|
64
|
+
throw new Error(`Webhook timed out after ${timeoutS}s`);
|
|
65
|
+
}
|
|
66
|
+
throw err;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── CLI (claude -p) execution — fallback ──
|
|
70
|
+
function executeViaCli(command, prompt, timeoutMs) {
|
|
23
71
|
return new Promise((resolve) => {
|
|
24
72
|
const args = ["-p", prompt, "--output-format", "json"];
|
|
25
73
|
const child = spawn(command, args, {
|
|
@@ -44,6 +92,7 @@ function runCli(command, prompt, timeoutMs) {
|
|
|
44
92
|
});
|
|
45
93
|
});
|
|
46
94
|
}
|
|
95
|
+
// ── JSON parser ──
|
|
47
96
|
function parseJsonOutput(raw) {
|
|
48
97
|
try {
|
|
49
98
|
return JSON.parse(raw);
|
|
@@ -62,6 +111,7 @@ function parseJsonOutput(raw) {
|
|
|
62
111
|
}
|
|
63
112
|
return null;
|
|
64
113
|
}
|
|
114
|
+
// ── Executor ──
|
|
65
115
|
export class Executor {
|
|
66
116
|
config;
|
|
67
117
|
send;
|
|
@@ -90,7 +140,7 @@ export class Executor {
|
|
|
90
140
|
}
|
|
91
141
|
markProcessed(call.order_id);
|
|
92
142
|
this.activeTasks.add(call.order_id);
|
|
93
|
-
logger.info(`Processing order=${call.order_id} skill="${call.skill}" from=${call.from}`);
|
|
143
|
+
logger.info(`Processing order=${call.order_id} skill="${call.skill}" from=${call.from} mode=${this.config.provider.execution_mode}`);
|
|
94
144
|
this.executeTask(call).catch((err) => {
|
|
95
145
|
logger.error(`Unhandled error in executeTask for ${call.order_id}:`, err);
|
|
96
146
|
});
|
|
@@ -103,6 +153,7 @@ export class Executor {
|
|
|
103
153
|
output: {
|
|
104
154
|
echo: call.input,
|
|
105
155
|
provider_status: "ok",
|
|
156
|
+
execution_mode: this.config.provider.execution_mode,
|
|
106
157
|
active_tasks: this.activeTasks.size,
|
|
107
158
|
max_concurrent: this.config.provider.max_concurrent,
|
|
108
159
|
},
|
|
@@ -112,31 +163,32 @@ export class Executor {
|
|
|
112
163
|
async executeTask(call) {
|
|
113
164
|
try {
|
|
114
165
|
const prompt = buildPrompt(call, this.config);
|
|
115
|
-
const
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
const errMsg = stderr.trim() || `CLI exited with code ${exitCode}`;
|
|
121
|
-
logger.error(`CLI failed (code=${exitCode}):`, errMsg);
|
|
122
|
-
this.send({
|
|
123
|
-
event: "deliver",
|
|
124
|
-
order_id: call.order_id,
|
|
125
|
-
error: errMsg.slice(0, 2000),
|
|
126
|
-
});
|
|
127
|
-
return;
|
|
166
|
+
const timeoutS = Math.max(call.timeout - TIMEOUT_BUFFER_S, 30);
|
|
167
|
+
let output;
|
|
168
|
+
if (this.config.provider.execution_mode === "webhook") {
|
|
169
|
+
// Execute via OpenClaw webhook
|
|
170
|
+
output = await executeViaWebhook(call, this.config, prompt, timeoutS);
|
|
128
171
|
}
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
172
|
+
else {
|
|
173
|
+
// Execute via CLI (claude -p / openclaw -p)
|
|
174
|
+
const command = this.config.provider.cli_command;
|
|
175
|
+
logger.info(`Executing via CLI: ${command} for skill="${call.skill}" (timeout=${timeoutS}s)`);
|
|
176
|
+
const { stdout, stderr, exitCode } = await executeViaCli(command, prompt, timeoutS * 1000);
|
|
177
|
+
if (exitCode !== 0) {
|
|
178
|
+
const errMsg = stderr.trim() || `CLI exited with code ${exitCode}`;
|
|
179
|
+
logger.error(`CLI failed (code=${exitCode}):`, errMsg);
|
|
180
|
+
this.send({
|
|
181
|
+
event: "deliver",
|
|
182
|
+
order_id: call.order_id,
|
|
183
|
+
error: errMsg.slice(0, 2000),
|
|
184
|
+
});
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
const parsed = parseJsonOutput(stdout);
|
|
188
|
+
output = parsed ?? { result: stdout.trim().slice(0, 5000) };
|
|
138
189
|
}
|
|
139
|
-
|
|
190
|
+
// Upload local files to R2 if any
|
|
191
|
+
output = await replaceLocalPaths(output, this.config);
|
|
140
192
|
const sent = this.send({
|
|
141
193
|
event: "deliver",
|
|
142
194
|
order_id: call.order_id,
|
package/dist/hub/provider.js
CHANGED
|
@@ -11,7 +11,10 @@ const CONFIG_DIR = join(homedir(), ".clawmoney");
|
|
|
11
11
|
const CONFIG_FILE = join(CONFIG_DIR, "config.yaml");
|
|
12
12
|
const PID_FILE = join(CONFIG_DIR, "provider.pid");
|
|
13
13
|
const DEFAULT_PROVIDER = {
|
|
14
|
+
execution_mode: "webhook",
|
|
14
15
|
cli_command: "claude",
|
|
16
|
+
webhook_url: "http://127.0.0.1:18789/hooks/agent",
|
|
17
|
+
webhook_token: "",
|
|
15
18
|
max_concurrent: 3,
|
|
16
19
|
ws_url: "wss://api.bnbot.ai/api/v1/ws/agent",
|
|
17
20
|
api_base_url: "https://api.bnbot.ai/api/v1",
|
|
@@ -73,7 +76,10 @@ function loadProviderConfig(cliCommand) {
|
|
|
73
76
|
}
|
|
74
77
|
const userProvider = (raw.provider ?? {});
|
|
75
78
|
const provider = {
|
|
79
|
+
execution_mode: userProvider.execution_mode ?? DEFAULT_PROVIDER.execution_mode,
|
|
76
80
|
cli_command: cliCommand ?? userProvider.cli_command ?? DEFAULT_PROVIDER.cli_command,
|
|
81
|
+
webhook_url: userProvider.webhook_url ?? DEFAULT_PROVIDER.webhook_url,
|
|
82
|
+
webhook_token: userProvider.webhook_token ?? DEFAULT_PROVIDER.webhook_token,
|
|
77
83
|
max_concurrent: userProvider.max_concurrent ?? DEFAULT_PROVIDER.max_concurrent,
|
|
78
84
|
ws_url: userProvider.ws_url ?? DEFAULT_PROVIDER.ws_url,
|
|
79
85
|
api_base_url: userProvider.api_base_url ?? DEFAULT_PROVIDER.api_base_url,
|
|
@@ -159,5 +165,8 @@ export function runProvider(cliCommand) {
|
|
|
159
165
|
wsClient.start();
|
|
160
166
|
poller.start();
|
|
161
167
|
logger.info("Hub Provider running. Listening for service calls...");
|
|
162
|
-
logger.info(`Config:
|
|
168
|
+
logger.info(`Config: mode=${config.provider.execution_mode}, max_concurrent=${config.provider.max_concurrent}` +
|
|
169
|
+
(config.provider.execution_mode === "webhook"
|
|
170
|
+
? `, webhook=${config.provider.webhook_url}`
|
|
171
|
+
: `, cli=${config.provider.cli_command}`));
|
|
163
172
|
}
|
package/dist/hub/types.d.ts
CHANGED
|
@@ -38,7 +38,10 @@ export interface TestResponseEvent {
|
|
|
38
38
|
}
|
|
39
39
|
export type OutgoingEvent = DeliverEvent | TestResponseEvent;
|
|
40
40
|
export interface ProviderSettings {
|
|
41
|
+
execution_mode: "webhook" | "cli";
|
|
41
42
|
cli_command: string;
|
|
43
|
+
webhook_url: string;
|
|
44
|
+
webhook_token: string;
|
|
42
45
|
max_concurrent: number;
|
|
43
46
|
ws_url: string;
|
|
44
47
|
api_base_url: string;
|
package/dist/utils/api.js
CHANGED
|
@@ -39,12 +39,13 @@ export async function apiPost(path, body, apiKey) {
|
|
|
39
39
|
headers: buildHeaders(apiKey),
|
|
40
40
|
body: JSON.stringify(body),
|
|
41
41
|
});
|
|
42
|
+
const text = await response.text();
|
|
42
43
|
let data;
|
|
43
44
|
try {
|
|
44
|
-
data =
|
|
45
|
+
data = JSON.parse(text);
|
|
45
46
|
}
|
|
46
47
|
catch {
|
|
47
|
-
data =
|
|
48
|
+
data = text;
|
|
48
49
|
}
|
|
49
50
|
return {
|
|
50
51
|
ok: response.ok,
|
package/dist/utils/config.d.ts
CHANGED
|
@@ -4,6 +4,14 @@ export interface ClawConfig {
|
|
|
4
4
|
agent_slug: string;
|
|
5
5
|
email?: string;
|
|
6
6
|
wallet_address?: string;
|
|
7
|
+
provider?: {
|
|
8
|
+
execution_mode?: string;
|
|
9
|
+
cli_command?: string;
|
|
10
|
+
webhook_url?: string;
|
|
11
|
+
webhook_token?: string;
|
|
12
|
+
max_concurrent?: number;
|
|
13
|
+
[key: string]: unknown;
|
|
14
|
+
};
|
|
7
15
|
}
|
|
8
16
|
export declare function getConfigPath(): string;
|
|
9
17
|
export declare function loadConfig(): ClawConfig | null;
|