@consensus-tools/consensus-tools 0.1.4 → 0.1.6
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/index.ts +45 -13
- package/openclaw.plugin.json +392 -47
- package/package.json +1 -1
- package/src/cli.ts +1 -1
- package/src/config.ts +57 -6
- package/src/jobs/engine.ts +1 -1
- package/src/ledger/ledger.ts +1 -1
- package/src/network/client.ts +1 -1
- package/src/network/server.ts +2 -2
- package/src/service.ts +1 -1
package/index.ts
CHANGED
|
@@ -9,28 +9,35 @@ import { registerTools } from './src/tools';
|
|
|
9
9
|
import { createService } from './src/service';
|
|
10
10
|
import type { ConsensusToolsConfig, Job } from './src/types';
|
|
11
11
|
|
|
12
|
-
export default
|
|
12
|
+
export default function register(api: any) {
|
|
13
13
|
const logger = api?.logger?.child ? api.logger.child({ plugin: PLUGIN_ID }) : api?.logger;
|
|
14
14
|
const loaded = loadConfig(api, logger);
|
|
15
15
|
const { config } = validateConfig(loaded, logger);
|
|
16
16
|
const agentId = resolveAgentId(api, config);
|
|
17
17
|
|
|
18
18
|
const storage = createStorage(config);
|
|
19
|
-
await storage.init();
|
|
20
|
-
|
|
21
19
|
const ledger = new LedgerEngine(storage, config, logger);
|
|
22
20
|
const engine = new JobEngine(storage, ledger, config, logger);
|
|
23
21
|
const server = new ConsensusToolsServer(config, engine, ledger, logger);
|
|
24
22
|
const client = new ConsensusToolsClient(config.global.baseUrl, config.global.accessToken, logger);
|
|
25
23
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
let readyPromise: Promise<void> | null = null;
|
|
25
|
+
const ensureReady = async () => {
|
|
26
|
+
if (!readyPromise) {
|
|
27
|
+
readyPromise = (async () => {
|
|
28
|
+
await storage.init();
|
|
29
|
+
if (config.mode === 'local') {
|
|
30
|
+
await ledger.applyConfigBalances(
|
|
31
|
+
config.local.ledger.balances,
|
|
32
|
+
config.local.ledger.balancesMode ?? 'initial'
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
})();
|
|
36
|
+
}
|
|
37
|
+
return readyPromise;
|
|
38
|
+
};
|
|
32
39
|
|
|
33
|
-
const backend = createBackend(config, engine, ledger, client, server, storage, logger, agentId);
|
|
40
|
+
const backend = createBackend(config, ensureReady, engine, ledger, client, server, storage, logger, agentId);
|
|
34
41
|
|
|
35
42
|
api.registerCli(
|
|
36
43
|
({ program }: any) => {
|
|
@@ -49,11 +56,19 @@ export default async function register(api: any) {
|
|
|
49
56
|
getJob: backend.getJob
|
|
50
57
|
};
|
|
51
58
|
const service = createService(config, serviceBackend, agentId, capabilities, logger);
|
|
52
|
-
api.registerService({
|
|
59
|
+
api.registerService({
|
|
60
|
+
id: 'consensus-tools',
|
|
61
|
+
start: async () => {
|
|
62
|
+
await ensureReady();
|
|
63
|
+
await service.start();
|
|
64
|
+
},
|
|
65
|
+
stop: service.stop
|
|
66
|
+
});
|
|
53
67
|
}
|
|
54
68
|
|
|
55
69
|
function createBackend(
|
|
56
70
|
config: ConsensusToolsConfig,
|
|
71
|
+
ensureReady: () => Promise<void>,
|
|
57
72
|
engine: JobEngine,
|
|
58
73
|
ledger: LedgerEngine,
|
|
59
74
|
client: ConsensusToolsClient,
|
|
@@ -90,6 +105,7 @@ function createBackend(
|
|
|
90
105
|
|
|
91
106
|
const backend = {
|
|
92
107
|
postJob: async (actorId: string, input: any): Promise<Job> => {
|
|
108
|
+
await ensureReady();
|
|
93
109
|
if (config.mode === 'global') {
|
|
94
110
|
ensureGlobalAccess('post jobs');
|
|
95
111
|
ensureNetworkSideEffects('post jobs');
|
|
@@ -103,6 +119,7 @@ function createBackend(
|
|
|
103
119
|
}
|
|
104
120
|
},
|
|
105
121
|
listJobs: async (filters?: Record<string, string | undefined>): Promise<Job[]> => {
|
|
122
|
+
await ensureReady();
|
|
106
123
|
if (config.mode === 'global') {
|
|
107
124
|
ensureGlobalAccess('list jobs');
|
|
108
125
|
return client.listJobs(filters || {});
|
|
@@ -110,6 +127,7 @@ function createBackend(
|
|
|
110
127
|
return engine.listJobs(filters || {});
|
|
111
128
|
},
|
|
112
129
|
getJob: async (jobId: string): Promise<Job | undefined> => {
|
|
130
|
+
await ensureReady();
|
|
113
131
|
if (config.mode === 'global') {
|
|
114
132
|
ensureGlobalAccess('get jobs');
|
|
115
133
|
return client.getJob(jobId);
|
|
@@ -117,6 +135,7 @@ function createBackend(
|
|
|
117
135
|
return engine.getJob(jobId);
|
|
118
136
|
},
|
|
119
137
|
getStatus: async (jobId: string): Promise<any> => {
|
|
138
|
+
await ensureReady();
|
|
120
139
|
if (config.mode === 'global') {
|
|
121
140
|
ensureGlobalAccess('get job status');
|
|
122
141
|
return client.getStatus(jobId);
|
|
@@ -124,6 +143,7 @@ function createBackend(
|
|
|
124
143
|
return engine.getStatus(jobId);
|
|
125
144
|
},
|
|
126
145
|
claimJob: async (actorId: string, jobId: string, stakeAmount: number, leaseSeconds: number): Promise<any> => {
|
|
146
|
+
await ensureReady();
|
|
127
147
|
if (config.mode === 'global') {
|
|
128
148
|
ensureGlobalAccess('claim jobs');
|
|
129
149
|
ensureNetworkSideEffects('claim jobs');
|
|
@@ -137,12 +157,14 @@ function createBackend(
|
|
|
137
157
|
}
|
|
138
158
|
},
|
|
139
159
|
heartbeat: async (actorId: string, jobId: string): Promise<void> => {
|
|
160
|
+
await ensureReady();
|
|
140
161
|
if (config.mode === 'global') {
|
|
141
162
|
return;
|
|
142
163
|
}
|
|
143
164
|
return engine.heartbeat(actorId, jobId);
|
|
144
165
|
},
|
|
145
166
|
submitJob: async (actorId: string, jobId: string, input: any): Promise<any> => {
|
|
167
|
+
await ensureReady();
|
|
146
168
|
if (config.mode === 'global') {
|
|
147
169
|
ensureGlobalAccess('submit jobs');
|
|
148
170
|
ensureNetworkSideEffects('submit jobs');
|
|
@@ -156,6 +178,7 @@ function createBackend(
|
|
|
156
178
|
}
|
|
157
179
|
},
|
|
158
180
|
listSubmissions: async (jobId: string): Promise<any[]> => {
|
|
181
|
+
await ensureReady();
|
|
159
182
|
if (config.mode === 'global') {
|
|
160
183
|
ensureGlobalAccess('list submissions');
|
|
161
184
|
const status = await client.getStatus(jobId);
|
|
@@ -165,6 +188,7 @@ function createBackend(
|
|
|
165
188
|
return status.submissions;
|
|
166
189
|
},
|
|
167
190
|
listVotes: async (jobId: string): Promise<any[]> => {
|
|
191
|
+
await ensureReady();
|
|
168
192
|
if (config.mode === 'global') {
|
|
169
193
|
ensureGlobalAccess('list votes');
|
|
170
194
|
const status = await client.getStatus(jobId);
|
|
@@ -174,6 +198,7 @@ function createBackend(
|
|
|
174
198
|
return status.votes;
|
|
175
199
|
},
|
|
176
200
|
vote: async (actorId: string, jobId: string, input: any): Promise<any> => {
|
|
201
|
+
await ensureReady();
|
|
177
202
|
if (config.mode === 'global') {
|
|
178
203
|
ensureGlobalAccess('vote');
|
|
179
204
|
ensureNetworkSideEffects('vote');
|
|
@@ -187,6 +212,7 @@ function createBackend(
|
|
|
187
212
|
}
|
|
188
213
|
},
|
|
189
214
|
resolveJob: async (actorId: string, jobId: string, input: any): Promise<any> => {
|
|
215
|
+
await ensureReady();
|
|
190
216
|
if (config.mode === 'global') {
|
|
191
217
|
ensureGlobalAccess('resolve jobs');
|
|
192
218
|
ensureNetworkSideEffects('resolve jobs');
|
|
@@ -200,6 +226,7 @@ function createBackend(
|
|
|
200
226
|
}
|
|
201
227
|
},
|
|
202
228
|
getLedgerBalance: async (target: string): Promise<number> => {
|
|
229
|
+
await ensureReady();
|
|
203
230
|
if (config.mode === 'global') {
|
|
204
231
|
ensureGlobalAccess('read ledger');
|
|
205
232
|
const result = await client.getLedger(target);
|
|
@@ -208,6 +235,7 @@ function createBackend(
|
|
|
208
235
|
return ledger.getBalance(target);
|
|
209
236
|
},
|
|
210
237
|
faucet: async (target: string, amount: number): Promise<any> => {
|
|
238
|
+
await ensureReady();
|
|
211
239
|
if (!config.local.ledger.faucetEnabled) {
|
|
212
240
|
throw new Error('Faucet disabled');
|
|
213
241
|
}
|
|
@@ -219,6 +247,7 @@ function createBackend(
|
|
|
219
247
|
return ledger.faucet(target, amount, `faucet:${agentId}`);
|
|
220
248
|
},
|
|
221
249
|
getDiagnostics: async () => {
|
|
250
|
+
await ensureReady();
|
|
222
251
|
const errors = (await storage.getState()).errors.map((err: any) => ({ at: err.at, message: err.message }));
|
|
223
252
|
let networkOk: boolean | undefined = undefined;
|
|
224
253
|
if (config.mode === 'global') {
|
|
@@ -229,13 +258,16 @@ function createBackend(
|
|
|
229
258
|
await client.listJobs({});
|
|
230
259
|
networkOk = true;
|
|
231
260
|
} catch (err) {
|
|
232
|
-
logger?.warn?.(
|
|
261
|
+
logger?.warn?.(`consensus-tools: diagnostics network check failed: ${err instanceof Error ? err.message : String(err)}`);
|
|
233
262
|
networkOk = false;
|
|
234
263
|
}
|
|
235
264
|
}
|
|
236
265
|
return { errors, networkOk };
|
|
237
266
|
},
|
|
238
|
-
startServer: async () =>
|
|
267
|
+
startServer: async () => {
|
|
268
|
+
await ensureReady();
|
|
269
|
+
return server.start();
|
|
270
|
+
},
|
|
239
271
|
stopServer: async () => server.stop()
|
|
240
272
|
};
|
|
241
273
|
|
package/openclaw.plugin.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"id": "consensus-tools",
|
|
3
3
|
"name": "consensus-tools",
|
|
4
|
-
"version": "0.1.
|
|
4
|
+
"version": "0.1.4",
|
|
5
5
|
"main": "index.ts",
|
|
6
6
|
"description": "consensus-tools distributed job board for OpenClaw agents",
|
|
7
7
|
"configSchema": {
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
"properties": {
|
|
11
11
|
"mode": {
|
|
12
12
|
"type": "string",
|
|
13
|
-
"enum": [
|
|
13
|
+
"enum": [
|
|
14
|
+
"local",
|
|
15
|
+
"global"
|
|
16
|
+
],
|
|
14
17
|
"default": "local",
|
|
15
18
|
"description": "Choose local storage or a hosted global job board"
|
|
16
19
|
},
|
|
@@ -24,7 +27,10 @@
|
|
|
24
27
|
"properties": {
|
|
25
28
|
"kind": {
|
|
26
29
|
"type": "string",
|
|
27
|
-
"enum": [
|
|
30
|
+
"enum": [
|
|
31
|
+
"sqlite",
|
|
32
|
+
"json"
|
|
33
|
+
],
|
|
28
34
|
"default": "json"
|
|
29
35
|
},
|
|
30
36
|
"path": {
|
|
@@ -32,51 +38,199 @@
|
|
|
32
38
|
"default": "./.openclaw/consensus-tools.json"
|
|
33
39
|
}
|
|
34
40
|
},
|
|
35
|
-
"required": [
|
|
41
|
+
"required": [
|
|
42
|
+
"kind",
|
|
43
|
+
"path"
|
|
44
|
+
]
|
|
36
45
|
},
|
|
37
46
|
"server": {
|
|
38
47
|
"type": "object",
|
|
39
48
|
"additionalProperties": false,
|
|
40
49
|
"properties": {
|
|
41
|
-
"enabled": {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
50
|
+
"enabled": {
|
|
51
|
+
"type": "boolean",
|
|
52
|
+
"default": false
|
|
53
|
+
},
|
|
54
|
+
"host": {
|
|
55
|
+
"type": "string",
|
|
56
|
+
"default": "127.0.0.1"
|
|
57
|
+
},
|
|
58
|
+
"port": {
|
|
59
|
+
"type": "integer",
|
|
60
|
+
"default": 9888,
|
|
61
|
+
"minimum": 1,
|
|
62
|
+
"maximum": 65535
|
|
63
|
+
},
|
|
64
|
+
"authToken": {
|
|
65
|
+
"type": "string",
|
|
66
|
+
"default": ""
|
|
67
|
+
}
|
|
45
68
|
},
|
|
46
|
-
"required": [
|
|
69
|
+
"required": [
|
|
70
|
+
"enabled",
|
|
71
|
+
"host",
|
|
72
|
+
"port",
|
|
73
|
+
"authToken"
|
|
74
|
+
]
|
|
75
|
+
},
|
|
76
|
+
"slashingEnabled": {
|
|
77
|
+
"type": "boolean",
|
|
78
|
+
"default": false
|
|
47
79
|
},
|
|
48
|
-
"slashingEnabled": { "type": "boolean", "default": false },
|
|
49
80
|
"jobDefaults": {
|
|
50
81
|
"type": "object",
|
|
51
82
|
"additionalProperties": false,
|
|
52
83
|
"properties": {
|
|
53
|
-
"reward": {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
84
|
+
"reward": {
|
|
85
|
+
"type": "number",
|
|
86
|
+
"default": 10,
|
|
87
|
+
"minimum": 0
|
|
88
|
+
},
|
|
89
|
+
"stakeRequired": {
|
|
90
|
+
"type": "number",
|
|
91
|
+
"default": 1,
|
|
92
|
+
"minimum": 0
|
|
93
|
+
},
|
|
94
|
+
"maxParticipants": {
|
|
95
|
+
"type": "integer",
|
|
96
|
+
"default": 3,
|
|
97
|
+
"minimum": 1
|
|
98
|
+
},
|
|
99
|
+
"minParticipants": {
|
|
100
|
+
"type": "integer",
|
|
101
|
+
"default": 1,
|
|
102
|
+
"minimum": 1
|
|
103
|
+
},
|
|
104
|
+
"expiresSeconds": {
|
|
105
|
+
"type": "integer",
|
|
106
|
+
"default": 86400,
|
|
107
|
+
"minimum": 60
|
|
108
|
+
},
|
|
58
109
|
"consensusPolicy": {
|
|
59
110
|
"type": "object",
|
|
60
111
|
"additionalProperties": false,
|
|
61
112
|
"properties": {
|
|
62
113
|
"type": {
|
|
63
114
|
"type": "string",
|
|
64
|
-
"enum": [
|
|
115
|
+
"enum": [
|
|
116
|
+
"FIRST_SUBMISSION_WINS",
|
|
117
|
+
"SINGLE_WINNER",
|
|
118
|
+
"HIGHEST_CONFIDENCE_SINGLE",
|
|
119
|
+
"APPROVAL_VOTE",
|
|
120
|
+
"OWNER_PICK",
|
|
121
|
+
"TOP_K_SPLIT",
|
|
122
|
+
"MAJORITY_VOTE",
|
|
123
|
+
"WEIGHTED_VOTE_SIMPLE",
|
|
124
|
+
"WEIGHTED_REPUTATION",
|
|
125
|
+
"TRUSTED_ARBITER"
|
|
126
|
+
],
|
|
65
127
|
"default": "FIRST_SUBMISSION_WINS"
|
|
66
128
|
},
|
|
67
|
-
"trustedArbiterAgentId": {
|
|
129
|
+
"trustedArbiterAgentId": {
|
|
130
|
+
"type": "string",
|
|
131
|
+
"default": ""
|
|
132
|
+
},
|
|
133
|
+
"minConfidence": {
|
|
134
|
+
"type": "number",
|
|
135
|
+
"default": 0,
|
|
136
|
+
"minimum": 0,
|
|
137
|
+
"maximum": 1
|
|
138
|
+
},
|
|
139
|
+
"topK": {
|
|
140
|
+
"type": "integer",
|
|
141
|
+
"default": 2,
|
|
142
|
+
"minimum": 1
|
|
143
|
+
},
|
|
144
|
+
"ordering": {
|
|
145
|
+
"type": "string",
|
|
146
|
+
"enum": [
|
|
147
|
+
"confidence",
|
|
148
|
+
"score"
|
|
149
|
+
],
|
|
150
|
+
"default": "confidence"
|
|
151
|
+
},
|
|
152
|
+
"quorum": {
|
|
153
|
+
"type": "integer",
|
|
154
|
+
"minimum": 1
|
|
155
|
+
},
|
|
156
|
+
"minScore": {
|
|
157
|
+
"type": "number"
|
|
158
|
+
},
|
|
159
|
+
"minMargin": {
|
|
160
|
+
"type": "number"
|
|
161
|
+
},
|
|
162
|
+
"tieBreak": {
|
|
163
|
+
"type": "string",
|
|
164
|
+
"enum": [
|
|
165
|
+
"earliest",
|
|
166
|
+
"confidence",
|
|
167
|
+
"arbiter"
|
|
168
|
+
]
|
|
169
|
+
},
|
|
170
|
+
"approvalVote": {
|
|
171
|
+
"type": "object",
|
|
172
|
+
"additionalProperties": false,
|
|
173
|
+
"properties": {
|
|
174
|
+
"weightMode": {
|
|
175
|
+
"type": "string",
|
|
176
|
+
"enum": [
|
|
177
|
+
"equal",
|
|
178
|
+
"explicit",
|
|
179
|
+
"reputation"
|
|
180
|
+
]
|
|
181
|
+
},
|
|
182
|
+
"settlement": {
|
|
183
|
+
"type": "string",
|
|
184
|
+
"enum": [
|
|
185
|
+
"immediate",
|
|
186
|
+
"staked",
|
|
187
|
+
"oracle"
|
|
188
|
+
]
|
|
189
|
+
},
|
|
190
|
+
"oracle": {
|
|
191
|
+
"type": "string",
|
|
192
|
+
"enum": [
|
|
193
|
+
"trusted_arbiter"
|
|
194
|
+
]
|
|
195
|
+
},
|
|
196
|
+
"voteSlashPercent": {
|
|
197
|
+
"type": "number",
|
|
198
|
+
"minimum": 0,
|
|
199
|
+
"maximum": 1
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
68
203
|
},
|
|
69
|
-
"required": [
|
|
204
|
+
"required": [
|
|
205
|
+
"type",
|
|
206
|
+
"trustedArbiterAgentId"
|
|
207
|
+
]
|
|
70
208
|
},
|
|
71
209
|
"slashingPolicy": {
|
|
72
210
|
"type": "object",
|
|
73
211
|
"additionalProperties": false,
|
|
74
212
|
"properties": {
|
|
75
|
-
"enabled": {
|
|
76
|
-
|
|
77
|
-
|
|
213
|
+
"enabled": {
|
|
214
|
+
"type": "boolean",
|
|
215
|
+
"default": false
|
|
216
|
+
},
|
|
217
|
+
"slashPercent": {
|
|
218
|
+
"type": "number",
|
|
219
|
+
"default": 0,
|
|
220
|
+
"minimum": 0,
|
|
221
|
+
"maximum": 1
|
|
222
|
+
},
|
|
223
|
+
"slashFlat": {
|
|
224
|
+
"type": "number",
|
|
225
|
+
"default": 0,
|
|
226
|
+
"minimum": 0
|
|
227
|
+
}
|
|
78
228
|
},
|
|
79
|
-
"required": [
|
|
229
|
+
"required": [
|
|
230
|
+
"enabled",
|
|
231
|
+
"slashPercent",
|
|
232
|
+
"slashFlat"
|
|
233
|
+
]
|
|
80
234
|
}
|
|
81
235
|
},
|
|
82
236
|
"required": [
|
|
@@ -93,19 +247,145 @@
|
|
|
93
247
|
"type": "object",
|
|
94
248
|
"additionalProperties": false,
|
|
95
249
|
"properties": {
|
|
96
|
-
"faucetEnabled": {
|
|
97
|
-
|
|
98
|
-
|
|
250
|
+
"faucetEnabled": {
|
|
251
|
+
"type": "boolean",
|
|
252
|
+
"default": false
|
|
253
|
+
},
|
|
254
|
+
"initialCreditsPerAgent": {
|
|
255
|
+
"type": "number",
|
|
256
|
+
"default": 0,
|
|
257
|
+
"minimum": 0
|
|
258
|
+
},
|
|
259
|
+
"balancesMode": {
|
|
260
|
+
"type": "string",
|
|
261
|
+
"enum": [
|
|
262
|
+
"initial",
|
|
263
|
+
"override"
|
|
264
|
+
],
|
|
265
|
+
"default": "initial"
|
|
266
|
+
},
|
|
99
267
|
"balances": {
|
|
100
268
|
"type": "object",
|
|
101
|
-
"additionalProperties": {
|
|
269
|
+
"additionalProperties": {
|
|
270
|
+
"type": "number",
|
|
271
|
+
"minimum": 0
|
|
272
|
+
},
|
|
102
273
|
"default": {}
|
|
103
274
|
}
|
|
104
275
|
},
|
|
105
|
-
"required": [
|
|
276
|
+
"required": [
|
|
277
|
+
"faucetEnabled",
|
|
278
|
+
"initialCreditsPerAgent",
|
|
279
|
+
"balancesMode",
|
|
280
|
+
"balances"
|
|
281
|
+
]
|
|
282
|
+
},
|
|
283
|
+
"consensusPolicies": {
|
|
284
|
+
"type": "object",
|
|
285
|
+
"additionalProperties": {
|
|
286
|
+
"type": "object",
|
|
287
|
+
"additionalProperties": false,
|
|
288
|
+
"properties": {
|
|
289
|
+
"type": {
|
|
290
|
+
"type": "string",
|
|
291
|
+
"enum": [
|
|
292
|
+
"FIRST_SUBMISSION_WINS",
|
|
293
|
+
"SINGLE_WINNER",
|
|
294
|
+
"HIGHEST_CONFIDENCE_SINGLE",
|
|
295
|
+
"APPROVAL_VOTE",
|
|
296
|
+
"OWNER_PICK",
|
|
297
|
+
"TOP_K_SPLIT",
|
|
298
|
+
"MAJORITY_VOTE",
|
|
299
|
+
"WEIGHTED_VOTE_SIMPLE",
|
|
300
|
+
"WEIGHTED_REPUTATION",
|
|
301
|
+
"TRUSTED_ARBITER"
|
|
302
|
+
]
|
|
303
|
+
},
|
|
304
|
+
"trustedArbiterAgentId": {
|
|
305
|
+
"type": "string"
|
|
306
|
+
},
|
|
307
|
+
"minConfidence": {
|
|
308
|
+
"type": "number",
|
|
309
|
+
"minimum": 0,
|
|
310
|
+
"maximum": 1
|
|
311
|
+
},
|
|
312
|
+
"topK": {
|
|
313
|
+
"type": "integer",
|
|
314
|
+
"minimum": 1
|
|
315
|
+
},
|
|
316
|
+
"ordering": {
|
|
317
|
+
"type": "string",
|
|
318
|
+
"enum": [
|
|
319
|
+
"confidence",
|
|
320
|
+
"score"
|
|
321
|
+
]
|
|
322
|
+
},
|
|
323
|
+
"quorum": {
|
|
324
|
+
"type": "integer",
|
|
325
|
+
"minimum": 1
|
|
326
|
+
},
|
|
327
|
+
"minScore": {
|
|
328
|
+
"type": "number"
|
|
329
|
+
},
|
|
330
|
+
"minMargin": {
|
|
331
|
+
"type": "number"
|
|
332
|
+
},
|
|
333
|
+
"tieBreak": {
|
|
334
|
+
"type": "string",
|
|
335
|
+
"enum": [
|
|
336
|
+
"earliest",
|
|
337
|
+
"confidence",
|
|
338
|
+
"arbiter"
|
|
339
|
+
]
|
|
340
|
+
},
|
|
341
|
+
"approvalVote": {
|
|
342
|
+
"type": "object",
|
|
343
|
+
"additionalProperties": false,
|
|
344
|
+
"properties": {
|
|
345
|
+
"weightMode": {
|
|
346
|
+
"type": "string",
|
|
347
|
+
"enum": [
|
|
348
|
+
"equal",
|
|
349
|
+
"explicit",
|
|
350
|
+
"reputation"
|
|
351
|
+
]
|
|
352
|
+
},
|
|
353
|
+
"settlement": {
|
|
354
|
+
"type": "string",
|
|
355
|
+
"enum": [
|
|
356
|
+
"immediate",
|
|
357
|
+
"staked",
|
|
358
|
+
"oracle"
|
|
359
|
+
]
|
|
360
|
+
},
|
|
361
|
+
"oracle": {
|
|
362
|
+
"type": "string",
|
|
363
|
+
"enum": [
|
|
364
|
+
"trusted_arbiter"
|
|
365
|
+
]
|
|
366
|
+
},
|
|
367
|
+
"voteSlashPercent": {
|
|
368
|
+
"type": "number",
|
|
369
|
+
"minimum": 0,
|
|
370
|
+
"maximum": 1
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
}
|
|
374
|
+
},
|
|
375
|
+
"required": [
|
|
376
|
+
"type"
|
|
377
|
+
]
|
|
378
|
+
},
|
|
379
|
+
"default": {}
|
|
106
380
|
}
|
|
107
381
|
},
|
|
108
|
-
"required": [
|
|
382
|
+
"required": [
|
|
383
|
+
"storage",
|
|
384
|
+
"server",
|
|
385
|
+
"slashingEnabled",
|
|
386
|
+
"jobDefaults",
|
|
387
|
+
"ledger"
|
|
388
|
+
]
|
|
109
389
|
},
|
|
110
390
|
"global": {
|
|
111
391
|
"type": "object",
|
|
@@ -120,7 +400,10 @@
|
|
|
120
400
|
"default": ""
|
|
121
401
|
}
|
|
122
402
|
},
|
|
123
|
-
"required": [
|
|
403
|
+
"required": [
|
|
404
|
+
"baseUrl",
|
|
405
|
+
"accessToken"
|
|
406
|
+
]
|
|
124
407
|
},
|
|
125
408
|
"agentIdentity": {
|
|
126
409
|
"type": "object",
|
|
@@ -128,7 +411,11 @@
|
|
|
128
411
|
"properties": {
|
|
129
412
|
"agentIdSource": {
|
|
130
413
|
"type": "string",
|
|
131
|
-
"enum": [
|
|
414
|
+
"enum": [
|
|
415
|
+
"openclaw",
|
|
416
|
+
"env",
|
|
417
|
+
"manual"
|
|
418
|
+
],
|
|
132
419
|
"default": "openclaw"
|
|
133
420
|
},
|
|
134
421
|
"manualAgentId": {
|
|
@@ -136,50 +423,108 @@
|
|
|
136
423
|
"default": ""
|
|
137
424
|
}
|
|
138
425
|
},
|
|
139
|
-
"required": [
|
|
426
|
+
"required": [
|
|
427
|
+
"agentIdSource",
|
|
428
|
+
"manualAgentId"
|
|
429
|
+
]
|
|
140
430
|
},
|
|
141
431
|
"safety": {
|
|
142
432
|
"type": "object",
|
|
143
433
|
"additionalProperties": false,
|
|
144
434
|
"properties": {
|
|
145
|
-
"requireOptionalToolsOptIn": {
|
|
146
|
-
|
|
435
|
+
"requireOptionalToolsOptIn": {
|
|
436
|
+
"type": "boolean",
|
|
437
|
+
"default": true
|
|
438
|
+
},
|
|
439
|
+
"allowNetworkSideEffects": {
|
|
440
|
+
"type": "boolean",
|
|
441
|
+
"default": false
|
|
442
|
+
}
|
|
147
443
|
},
|
|
148
|
-
"required": [
|
|
444
|
+
"required": [
|
|
445
|
+
"requireOptionalToolsOptIn",
|
|
446
|
+
"allowNetworkSideEffects"
|
|
447
|
+
]
|
|
149
448
|
}
|
|
150
449
|
},
|
|
151
|
-
"required": [
|
|
450
|
+
"required": [
|
|
451
|
+
"mode",
|
|
452
|
+
"agentIdentity",
|
|
453
|
+
"safety"
|
|
454
|
+
],
|
|
152
455
|
"allOf": [
|
|
153
456
|
{
|
|
154
|
-
"if": {
|
|
155
|
-
|
|
457
|
+
"if": {
|
|
458
|
+
"properties": {
|
|
459
|
+
"mode": {
|
|
460
|
+
"const": "local"
|
|
461
|
+
}
|
|
462
|
+
}
|
|
463
|
+
},
|
|
464
|
+
"then": {
|
|
465
|
+
"required": [
|
|
466
|
+
"local"
|
|
467
|
+
]
|
|
468
|
+
}
|
|
156
469
|
},
|
|
157
470
|
{
|
|
158
|
-
"if": {
|
|
159
|
-
|
|
471
|
+
"if": {
|
|
472
|
+
"properties": {
|
|
473
|
+
"mode": {
|
|
474
|
+
"const": "global"
|
|
475
|
+
}
|
|
476
|
+
}
|
|
477
|
+
},
|
|
478
|
+
"then": {
|
|
479
|
+
"required": [
|
|
480
|
+
"global"
|
|
481
|
+
]
|
|
482
|
+
}
|
|
160
483
|
}
|
|
161
484
|
]
|
|
162
485
|
},
|
|
163
486
|
"uiHints": {
|
|
164
487
|
"local": {
|
|
165
488
|
"storage": {
|
|
166
|
-
"path": {
|
|
489
|
+
"path": {
|
|
490
|
+
"ui:widget": "file"
|
|
491
|
+
}
|
|
167
492
|
},
|
|
168
493
|
"server": {
|
|
169
|
-
"authToken": {
|
|
494
|
+
"authToken": {
|
|
495
|
+
"ui:widget": "password",
|
|
496
|
+
"sensitive": true
|
|
497
|
+
}
|
|
170
498
|
},
|
|
171
499
|
"ledger": {
|
|
172
|
-
"faucetEnabled": {
|
|
173
|
-
|
|
174
|
-
|
|
500
|
+
"faucetEnabled": {
|
|
501
|
+
"ui:widget": "checkbox",
|
|
502
|
+
"warning": "Dev-only faucet"
|
|
503
|
+
},
|
|
504
|
+
"balancesMode": {
|
|
505
|
+
"label": "Balance mode",
|
|
506
|
+
"ui:widget": "radio"
|
|
507
|
+
},
|
|
508
|
+
"balances": {
|
|
509
|
+
"label": "Per-agent balances"
|
|
510
|
+
}
|
|
175
511
|
}
|
|
176
512
|
},
|
|
177
513
|
"global": {
|
|
178
|
-
"baseUrl": {
|
|
179
|
-
|
|
514
|
+
"baseUrl": {
|
|
515
|
+
"label": "Global board URL"
|
|
516
|
+
},
|
|
517
|
+
"accessToken": {
|
|
518
|
+
"ui:widget": "password",
|
|
519
|
+
"sensitive": true,
|
|
520
|
+
"label": "Access Token"
|
|
521
|
+
}
|
|
180
522
|
},
|
|
181
523
|
"safety": {
|
|
182
|
-
"allowNetworkSideEffects": {
|
|
524
|
+
"allowNetworkSideEffects": {
|
|
525
|
+
"ui:widget": "checkbox",
|
|
526
|
+
"warning": "Enables network mutations"
|
|
527
|
+
}
|
|
183
528
|
}
|
|
184
529
|
}
|
|
185
530
|
}
|
package/package.json
CHANGED
package/src/cli.ts
CHANGED
|
@@ -1057,7 +1057,7 @@ function resolveSh(): string {
|
|
|
1057
1057
|
'const storage=new JsonStorage(stateFile); await storage.init();',
|
|
1058
1058
|
'const ledger=new LedgerEngine(storage, defaultConfig);',
|
|
1059
1059
|
'const engine=new JobEngine(storage, ledger, defaultConfig);',
|
|
1060
|
-
'const input
|
|
1060
|
+
'const input = {};',
|
|
1061
1061
|
'if (winner) input.manualWinners = [winner];',
|
|
1062
1062
|
'if (subId) input.manualSubmissionId = subId;',
|
|
1063
1063
|
"const actor = winner || 'cli@local';",
|
package/src/config.ts
CHANGED
|
@@ -51,6 +51,7 @@ export const configSchema = {
|
|
|
51
51
|
type: 'string',
|
|
52
52
|
enum: [
|
|
53
53
|
'FIRST_SUBMISSION_WINS',
|
|
54
|
+
'SINGLE_WINNER',
|
|
54
55
|
'HIGHEST_CONFIDENCE_SINGLE',
|
|
55
56
|
'APPROVAL_VOTE',
|
|
56
57
|
'OWNER_PICK',
|
|
@@ -66,7 +67,20 @@ export const configSchema = {
|
|
|
66
67
|
minConfidence: { type: 'number', default: 0, minimum: 0, maximum: 1 },
|
|
67
68
|
topK: { type: 'integer', default: 2, minimum: 1 },
|
|
68
69
|
ordering: { type: 'string', enum: ['confidence', 'score'], default: 'confidence' },
|
|
69
|
-
quorum: { type: 'integer', minimum: 1 }
|
|
70
|
+
quorum: { type: 'integer', minimum: 1 },
|
|
71
|
+
minScore: { type: 'number' },
|
|
72
|
+
minMargin: { type: 'number' },
|
|
73
|
+
tieBreak: { type: 'string', enum: ['earliest', 'confidence', 'arbiter'] },
|
|
74
|
+
approvalVote: {
|
|
75
|
+
type: 'object',
|
|
76
|
+
additionalProperties: false,
|
|
77
|
+
properties: {
|
|
78
|
+
weightMode: { type: 'string', enum: ['equal', 'explicit', 'reputation'] },
|
|
79
|
+
settlement: { type: 'string', enum: ['immediate', 'staked', 'oracle'] },
|
|
80
|
+
oracle: { type: 'string', enum: ['trusted_arbiter'] },
|
|
81
|
+
voteSlashPercent: { type: 'number', minimum: 0, maximum: 1 }
|
|
82
|
+
}
|
|
83
|
+
}
|
|
70
84
|
},
|
|
71
85
|
required: ['type', 'trustedArbiterAgentId']
|
|
72
86
|
},
|
|
@@ -101,6 +115,7 @@ export const configSchema = {
|
|
|
101
115
|
type: 'string',
|
|
102
116
|
enum: [
|
|
103
117
|
'FIRST_SUBMISSION_WINS',
|
|
118
|
+
'SINGLE_WINNER',
|
|
104
119
|
'HIGHEST_CONFIDENCE_SINGLE',
|
|
105
120
|
'APPROVAL_VOTE',
|
|
106
121
|
'OWNER_PICK',
|
|
@@ -115,7 +130,20 @@ export const configSchema = {
|
|
|
115
130
|
minConfidence: { type: 'number', minimum: 0, maximum: 1 },
|
|
116
131
|
topK: { type: 'integer', minimum: 1 },
|
|
117
132
|
ordering: { type: 'string', enum: ['confidence', 'score'] },
|
|
118
|
-
quorum: { type: 'integer', minimum: 1 }
|
|
133
|
+
quorum: { type: 'integer', minimum: 1 },
|
|
134
|
+
minScore: { type: 'number' },
|
|
135
|
+
minMargin: { type: 'number' },
|
|
136
|
+
tieBreak: { type: 'string', enum: ['earliest', 'confidence', 'arbiter'] },
|
|
137
|
+
approvalVote: {
|
|
138
|
+
type: 'object',
|
|
139
|
+
additionalProperties: false,
|
|
140
|
+
properties: {
|
|
141
|
+
weightMode: { type: 'string', enum: ['equal', 'explicit', 'reputation'] },
|
|
142
|
+
settlement: { type: 'string', enum: ['immediate', 'staked', 'oracle'] },
|
|
143
|
+
oracle: { type: 'string', enum: ['trusted_arbiter'] },
|
|
144
|
+
voteSlashPercent: { type: 'number', minimum: 0, maximum: 1 }
|
|
145
|
+
}
|
|
146
|
+
}
|
|
119
147
|
},
|
|
120
148
|
required: ['type']
|
|
121
149
|
},
|
|
@@ -234,14 +262,14 @@ export function loadConfig(api: any, logger?: any): ConsensusToolsConfig {
|
|
|
234
262
|
try {
|
|
235
263
|
raw = api?.config?.getPluginConfig?.(PLUGIN_ID);
|
|
236
264
|
} catch (err) {
|
|
237
|
-
logger?.warn?.(
|
|
265
|
+
logger?.warn?.(`consensus-tools: failed to read config via getPluginConfig: ${err instanceof Error ? err.message : String(err)}`);
|
|
238
266
|
}
|
|
239
267
|
|
|
240
268
|
if (!raw) {
|
|
241
269
|
try {
|
|
242
270
|
raw = api?.config?.get?.(`plugins.entries.${PLUGIN_ID}.config`);
|
|
243
271
|
} catch (err) {
|
|
244
|
-
logger?.warn?.(
|
|
272
|
+
logger?.warn?.(`consensus-tools: failed to read config via config.get: ${err instanceof Error ? err.message : String(err)}`);
|
|
245
273
|
}
|
|
246
274
|
}
|
|
247
275
|
|
|
@@ -253,7 +281,30 @@ export function loadConfig(api: any, logger?: any): ConsensusToolsConfig {
|
|
|
253
281
|
raw = api?.config?.entries?.[PLUGIN_ID]?.config;
|
|
254
282
|
}
|
|
255
283
|
|
|
256
|
-
return mergeDefaults(fallback, raw ?? {});
|
|
284
|
+
return normalizeLegacyPolicyAliases(mergeDefaults(fallback, raw ?? {}));
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
function normalizeLegacyPolicyAliases(config: ConsensusToolsConfig): ConsensusToolsConfig {
|
|
288
|
+
const normalized = deepCopy(config);
|
|
289
|
+
|
|
290
|
+
const normalizePolicyType = (value?: string) => {
|
|
291
|
+
if (value === 'SINGLE_WINNER') return 'FIRST_SUBMISSION_WINS';
|
|
292
|
+
return value;
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
const defaultsPolicy = normalized?.local?.jobDefaults?.consensusPolicy;
|
|
296
|
+
if (defaultsPolicy?.type) {
|
|
297
|
+
defaultsPolicy.type = normalizePolicyType(defaultsPolicy.type) as any;
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
const policyMap = normalized?.local?.consensusPolicies ?? {};
|
|
301
|
+
for (const policy of Object.values(policyMap)) {
|
|
302
|
+
if (policy?.type) {
|
|
303
|
+
policy.type = normalizePolicyType(policy.type) as any;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
return normalized;
|
|
257
308
|
}
|
|
258
309
|
|
|
259
310
|
export function validateConfig(input: ConsensusToolsConfig, logger?: any): { config: ConsensusToolsConfig; errors: string[] } {
|
|
@@ -264,7 +315,7 @@ export function validateConfig(input: ConsensusToolsConfig, logger?: any): { con
|
|
|
264
315
|
: (validate.errors || []).map((err) => `${err.instancePath || '/'} ${err.message || 'invalid'}`);
|
|
265
316
|
|
|
266
317
|
if (!ok) {
|
|
267
|
-
logger?.warn?.(
|
|
318
|
+
logger?.warn?.(`consensus-tools: config validation warnings: ${JSON.stringify(errors)}`);
|
|
268
319
|
}
|
|
269
320
|
|
|
270
321
|
return { config: candidate, errors };
|
package/src/jobs/engine.ts
CHANGED
package/src/ledger/ledger.ts
CHANGED
|
@@ -127,7 +127,7 @@ export class LedgerEngine {
|
|
|
127
127
|
ensureNonNegative(nextBalance, `${entry.agentId} after ${entry.type}`);
|
|
128
128
|
state.ledger.push(entry);
|
|
129
129
|
});
|
|
130
|
-
this.logger?.info?.({ entry }
|
|
130
|
+
this.logger?.info?.(`consensus-tools: ledger entry (${entry.type} ${entry.amount} agent=${entry.agentId}${entry.jobId ? ` job=${entry.jobId}` : ''})`);
|
|
131
131
|
if (this.config.local.ledger.balancesMode === 'override') {
|
|
132
132
|
await this.applyConfigBalances(this.config.local.ledger.balances, 'override');
|
|
133
133
|
}
|
package/src/network/client.ts
CHANGED
|
@@ -59,7 +59,7 @@ export class ConsensusToolsClient {
|
|
|
59
59
|
|
|
60
60
|
if (!res.ok) {
|
|
61
61
|
const text = await res.text();
|
|
62
|
-
this.logger?.warn?.(
|
|
62
|
+
this.logger?.warn?.(`consensus-tools: network request failed (status=${res.status}, path=${path})`);
|
|
63
63
|
throw new Error(`Network error ${res.status}: ${text || res.statusText}`);
|
|
64
64
|
}
|
|
65
65
|
|
package/src/network/server.ts
CHANGED
|
@@ -22,7 +22,7 @@ export class ConsensusToolsServer {
|
|
|
22
22
|
this.server?.listen(port, host, () => resolve());
|
|
23
23
|
});
|
|
24
24
|
|
|
25
|
-
this.logger?.info?.(
|
|
25
|
+
this.logger?.info?.(`consensus-tools embedded server started (host=${host}, port=${port})`);
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
async stop(): Promise<void> {
|
|
@@ -113,7 +113,7 @@ export class ConsensusToolsServer {
|
|
|
113
113
|
|
|
114
114
|
return this.reply(res, 404, { error: 'Not found' });
|
|
115
115
|
} catch (err: any) {
|
|
116
|
-
this.logger?.warn?.(
|
|
116
|
+
this.logger?.warn?.(`consensus-tools server error: ${err instanceof Error ? err.message : String(err)}`);
|
|
117
117
|
try {
|
|
118
118
|
await this.engine.recordError?.(err?.message || 'Server error', { path: req.url, method: req.method });
|
|
119
119
|
} catch {
|
package/src/service.ts
CHANGED
|
@@ -16,7 +16,7 @@ export function createService(
|
|
|
16
16
|
id: 'consensus-tools-service',
|
|
17
17
|
start: async () => {
|
|
18
18
|
if (config.mode === 'global') return;
|
|
19
|
-
logger?.debug?.(
|
|
19
|
+
logger?.debug?.(`consensus-tools: service started (agentId=${agentId}, capabilities=${Array.isArray(capabilities) ? capabilities.join(',') : ''})`);
|
|
20
20
|
},
|
|
21
21
|
stop: async () => {
|
|
22
22
|
if (config.mode === 'global') return;
|