@kroxy/kroxy 1.0.17 → 1.0.19
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/src/tools/autoagent.js +69 -18
- package/dist/src/tools/hire.js +9 -6
- package/openclaw.plugin.json +10 -0
- package/package.json +1 -1
|
@@ -2,8 +2,9 @@
|
|
|
2
2
|
* kroxy_autoagent — Autonomous multi-step orchestrator.
|
|
3
3
|
*
|
|
4
4
|
* Takes a natural-language goal, decomposes it into 2–4 subtasks via Claude
|
|
5
|
-
* (or a rule-based fallback if
|
|
6
|
-
* for
|
|
5
|
+
* through Lava's gateway (or a rule-based fallback if keys are unset), fires
|
|
6
|
+
* kroxy_hire for all subtasks in parallel, then synthesizes outputs into a
|
|
7
|
+
* unified deliverable via Lava.
|
|
7
8
|
*/
|
|
8
9
|
import { Type } from '@sinclair/typebox';
|
|
9
10
|
import { executeHire } from './hire.js';
|
|
@@ -20,8 +21,9 @@ export const autoagentParams = Type.Object({
|
|
|
20
21
|
});
|
|
21
22
|
// ─── Decomposition ────────────────────────────────────────────────────────────
|
|
22
23
|
/**
|
|
23
|
-
* Ask Claude to decompose the goal into 2–4 subtasks.
|
|
24
|
-
* Falls back to
|
|
24
|
+
* Ask Claude (via Lava) to decompose the goal into 2–4 subtasks.
|
|
25
|
+
* Falls back to keyword-based decomposer if LAVA_SECRET_KEY or
|
|
26
|
+
* ANTHROPIC_API_KEY are not set.
|
|
25
27
|
*/
|
|
26
28
|
async function decomposeGoal(goal) {
|
|
27
29
|
const hasLava = process.env.LAVA_SECRET_KEY && process.env.ANTHROPIC_API_KEY;
|
|
@@ -39,13 +41,13 @@ async function decomposeGoal(goal) {
|
|
|
39
41
|
});
|
|
40
42
|
const parsed = JSON.parse(text.trim());
|
|
41
43
|
if (Array.isArray(parsed) && parsed.length > 0)
|
|
42
|
-
return parsed.slice(0, 4);
|
|
44
|
+
return { subtasks: parsed.slice(0, 4), viaLava: true };
|
|
43
45
|
}
|
|
44
46
|
catch {
|
|
45
47
|
// Fall through to rule-based
|
|
46
48
|
}
|
|
47
49
|
}
|
|
48
|
-
return ruleBasedDecompose(goal);
|
|
50
|
+
return { subtasks: ruleBasedDecompose(goal), viaLava: false };
|
|
49
51
|
}
|
|
50
52
|
/** Keyword-based decomposer — works without any API key. */
|
|
51
53
|
function ruleBasedDecompose(goal) {
|
|
@@ -70,30 +72,73 @@ function ruleBasedDecompose(goal) {
|
|
|
70
72
|
}
|
|
71
73
|
return subtasks.slice(0, 4);
|
|
72
74
|
}
|
|
75
|
+
// ─── Synthesis ────────────────────────────────────────────────────────────────
|
|
76
|
+
/**
|
|
77
|
+
* Use Lava/Claude to merge individual subtask deliverables into a single
|
|
78
|
+
* coherent summary. Best-effort — silently skipped if Lava is unavailable.
|
|
79
|
+
*/
|
|
80
|
+
async function synthesizeDeliverables(goal, receipts) {
|
|
81
|
+
const hasLava = process.env.LAVA_SECRET_KEY && process.env.ANTHROPIC_API_KEY;
|
|
82
|
+
if (!hasLava || receipts.length === 0)
|
|
83
|
+
return null;
|
|
84
|
+
const snippets = receipts
|
|
85
|
+
.filter(d => d?.deliverable?.summary)
|
|
86
|
+
.map((d, i) => `[Subtask ${i + 1}]\n${d.deliverable.summary}`)
|
|
87
|
+
.join('\n\n');
|
|
88
|
+
if (!snippets)
|
|
89
|
+
return null;
|
|
90
|
+
try {
|
|
91
|
+
return await lavaAnthropic({
|
|
92
|
+
model: 'claude-haiku-4-5-20251001',
|
|
93
|
+
max_tokens: 512,
|
|
94
|
+
system: 'You are a synthesis assistant. Given outputs from multiple AI agent subtasks, ' +
|
|
95
|
+
'write a concise unified summary (3–5 sentences) that integrates all key findings ' +
|
|
96
|
+
'into a coherent deliverable for the original goal.',
|
|
97
|
+
messages: [{ role: 'user', content: `Original goal: ${goal}\n\nSubtask outputs:\n${snippets}` }],
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
catch {
|
|
101
|
+
return null;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
73
104
|
// ─── Orchestrator ─────────────────────────────────────────────────────────────
|
|
74
105
|
export async function executeAutoagent(params) {
|
|
75
106
|
const goal = params.goal;
|
|
76
107
|
const maxBudget = params.maxBudget ?? 20;
|
|
77
108
|
// 1. Decompose
|
|
78
|
-
const subtasks = await decomposeGoal(goal);
|
|
109
|
+
const { subtasks, viaLava } = await decomposeGoal(goal);
|
|
79
110
|
const pricePerTask = parseFloat((maxBudget / subtasks.length).toFixed(2));
|
|
111
|
+
const modeLabel = viaLava
|
|
112
|
+
? 'LLM decomposition via Lava'
|
|
113
|
+
: '⚠ Keyword fallback — set LAVA_SECRET_KEY + ANTHROPIC_API_KEY for intelligent decomposition';
|
|
80
114
|
const lines = [
|
|
81
115
|
`AutoAgent: ${goal.slice(0, 80)}`,
|
|
82
116
|
`${'─'.repeat(50)}`,
|
|
83
117
|
`Budget: $${maxBudget} USDC across ${subtasks.length} subtask${subtasks.length === 1 ? '' : 's'} ($${pricePerTask} each)`,
|
|
118
|
+
`Mode: ${modeLabel}`,
|
|
84
119
|
'',
|
|
85
120
|
];
|
|
121
|
+
// 2. List all subtasks upfront before firing
|
|
122
|
+
subtasks.forEach(({ task, capability }, i) => {
|
|
123
|
+
lines.push(`[${i + 1}/${subtasks.length}] ${capability.toUpperCase()}: ${task.slice(0, 70)}`);
|
|
124
|
+
});
|
|
125
|
+
lines.push('', `Firing all ${subtasks.length} subtask${subtasks.length === 1 ? '' : 's'} in parallel…`, '');
|
|
126
|
+
// 3. Fire all hires concurrently
|
|
127
|
+
const settled = await Promise.allSettled(
|
|
128
|
+
subtasks.map(({ task, capability }) =>
|
|
129
|
+
executeHire({ task, maxPrice: pricePerTask, capability })
|
|
130
|
+
)
|
|
131
|
+
);
|
|
86
132
|
const receipts = [];
|
|
87
133
|
let totalSpent = 0;
|
|
88
|
-
|
|
89
|
-
|
|
134
|
+
for (let i = 0; i < settled.length; i++) {
|
|
135
|
+
const result = settled[i];
|
|
90
136
|
const { task, capability } = subtasks[i];
|
|
91
|
-
lines.push(`[${i + 1}
|
|
92
|
-
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
|
|
96
|
-
totalSpent += paid;
|
|
137
|
+
lines.push(`[${i + 1}] ${capability.toUpperCase()}: ${task.slice(0, 60)}`);
|
|
138
|
+
if (result.status === 'fulfilled') {
|
|
139
|
+
const d = result.value.details;
|
|
140
|
+
const paid = parseFloat(String(d?.amountPaid ?? '0'));
|
|
141
|
+
totalSpent += isNaN(paid) ? 0 : paid;
|
|
97
142
|
lines.push(` ✓ Completed in ${d?.duration ?? '?'} — paid $${d?.amountPaid ?? '?'}`);
|
|
98
143
|
lines.push(` Escrow: ${d?.escrowId ?? '?'}`);
|
|
99
144
|
if (d?.deliverable?.summary) {
|
|
@@ -102,15 +147,20 @@ export async function executeAutoagent(params) {
|
|
|
102
147
|
lines.push('');
|
|
103
148
|
receipts.push(d);
|
|
104
149
|
}
|
|
105
|
-
|
|
106
|
-
const msg =
|
|
150
|
+
else {
|
|
151
|
+
const msg = result.reason instanceof Error ? result.reason.message : String(result.reason);
|
|
107
152
|
lines.push(` ✗ Failed: ${msg.slice(0, 120)}`);
|
|
108
153
|
lines.push('');
|
|
109
154
|
}
|
|
110
155
|
}
|
|
156
|
+
// 4. Synthesize outputs into a unified deliverable (via Lava — best-effort)
|
|
157
|
+
const synthesis = await synthesizeDeliverables(goal, receipts);
|
|
111
158
|
lines.push(`${'─'.repeat(50)}`);
|
|
112
159
|
lines.push(`Total spent: $${totalSpent.toFixed(2)} USDC / $${maxBudget} budget`);
|
|
113
160
|
lines.push(`Subtasks completed: ${receipts.length}/${subtasks.length}`);
|
|
161
|
+
if (synthesis) {
|
|
162
|
+
lines.push('', '── Unified Deliverable ──', synthesis);
|
|
163
|
+
}
|
|
114
164
|
return {
|
|
115
165
|
content: [{ type: 'text', text: lines.join('\n') }],
|
|
116
166
|
details: {
|
|
@@ -119,7 +169,8 @@ export async function executeAutoagent(params) {
|
|
|
119
169
|
receipts,
|
|
120
170
|
totalSpent: totalSpent.toFixed(2),
|
|
121
171
|
budgetUsed: `$${totalSpent.toFixed(2)} / $${maxBudget}`,
|
|
172
|
+
synthesis: synthesis ?? undefined,
|
|
122
173
|
},
|
|
123
174
|
};
|
|
124
175
|
}
|
|
125
|
-
//# sourceMappingURL=autoagent.js.map
|
|
176
|
+
//# sourceMappingURL=autoagent.js.map
|
package/dist/src/tools/hire.js
CHANGED
|
@@ -5,16 +5,19 @@ const DEFAULT_API_URL = 'https://api-production-1b45.up.railway.app';
|
|
|
5
5
|
export const hireParams = Type.Object({
|
|
6
6
|
task: Type.String({ description: 'What you want the hired agent to do, e.g. "Research the top AI payment startups"' }),
|
|
7
7
|
maxPrice: Type.Optional(Type.Number({ minimum: 0.01, description: 'Maximum USDC budget, default 5.00' })),
|
|
8
|
-
capability: Type.Optional(Type.String({ description: 'Agent capability to match: research, writing, coding. Auto-detected from task if omitted.' })),
|
|
8
|
+
capability: Type.Optional(Type.String({ description: 'Agent capability to match: research, writing, coding, planning. Auto-detected from task if omitted.' })),
|
|
9
9
|
minRep: Type.Optional(Type.Number({ minimum: 0, maximum: 100, description: 'Minimum reputation score (0–100) required. Default: 0 (any agent accepted).' })),
|
|
10
10
|
});
|
|
11
11
|
function detectCapability(task) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
if (/write|draft|essay|blog|article|copy/i.test(task))
|
|
15
|
-
return 'writing';
|
|
16
|
-
if (/code|script|function|implement|build|program/i.test(task))
|
|
12
|
+
// Check coding first — "build" would otherwise fall through to planning
|
|
13
|
+
if (/code|script|function|implement|develop|engineer|program|smart contract/i.test(task))
|
|
17
14
|
return 'coding';
|
|
15
|
+
if (/write|draft|essay|blog|article|copy|content|landing page|marketing|email/i.test(task))
|
|
16
|
+
return 'writing';
|
|
17
|
+
if (/plan|roadmap|strateg|architect|design|outline|milestone|go-to-market/i.test(task))
|
|
18
|
+
return 'planning';
|
|
19
|
+
if (/research|find|search|analyz|summariz|look up|investigat|gather|survey/i.test(task))
|
|
20
|
+
return 'research';
|
|
18
21
|
return 'research';
|
|
19
22
|
}
|
|
20
23
|
function buildConditions(nexusUrl, jobId) {
|
package/openclaw.plugin.json
CHANGED
|
@@ -16,6 +16,8 @@
|
|
|
16
16
|
"KROXY_AGENT_WALLET": { "type": "string" },
|
|
17
17
|
"KROXY_AGENT_PRIVATE_KEY": { "type": "string" },
|
|
18
18
|
"NEXUS_URL": { "type": "string" },
|
|
19
|
+
"LAVA_SECRET_KEY": { "type": "string" },
|
|
20
|
+
"ANTHROPIC_API_KEY": { "type": "string" },
|
|
19
21
|
"KROXY_DEMO_MODE": {
|
|
20
22
|
"type": "string",
|
|
21
23
|
"default": "1"
|
|
@@ -31,6 +33,14 @@
|
|
|
31
33
|
"KROXY_AGENT_PRIVATE_KEY": {
|
|
32
34
|
"label": "Kroxy Private Key",
|
|
33
35
|
"sensitive": true
|
|
36
|
+
},
|
|
37
|
+
"LAVA_SECRET_KEY": {
|
|
38
|
+
"label": "Lava Secret Key (enables intelligent decomposition)",
|
|
39
|
+
"sensitive": true
|
|
40
|
+
},
|
|
41
|
+
"ANTHROPIC_API_KEY": {
|
|
42
|
+
"label": "Anthropic API Key (required with Lava)",
|
|
43
|
+
"sensitive": true
|
|
34
44
|
}
|
|
35
45
|
}
|
|
36
46
|
}
|