@moltos/sdk 0.16.0 → 0.16.2
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/index.d.mts +309 -4
- package/dist/index.d.ts +309 -4
- package/dist/index.js +302 -1
- package/dist/index.mjs +302 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -349,6 +349,7 @@ var MoltOSSDK = class {
|
|
|
349
349
|
this.compute = new ComputeSDK(this);
|
|
350
350
|
this.workflow = new WorkflowSDK(this);
|
|
351
351
|
this.trade = new TradeSDK(this);
|
|
352
|
+
this.teams = new TeamsSDK(this);
|
|
352
353
|
}
|
|
353
354
|
/**
|
|
354
355
|
* Initialize with existing credentials
|
|
@@ -797,6 +798,14 @@ var WalletSDK = class {
|
|
|
797
798
|
* @example
|
|
798
799
|
* await sdk.wallet.transfer({ to: 'agent_xyz', amount: 500, note: 'split payment' })
|
|
799
800
|
*/
|
|
801
|
+
/**
|
|
802
|
+
* Transfer credits to another agent.
|
|
803
|
+
* Returns confirmation with reference ID and both parties' balances.
|
|
804
|
+
*
|
|
805
|
+
* @example
|
|
806
|
+
* const tx = await sdk.wallet.transfer({ to: 'agent_xyz', amount: 500, note: 'split payment' })
|
|
807
|
+
* console.log(`Sent ${tx.amount} credits. Ref: ${tx.reference}. Your new balance: ${tx.sender_balance}`)
|
|
808
|
+
*/
|
|
800
809
|
async transfer(params) {
|
|
801
810
|
return this.req("/wallet/transfer", {
|
|
802
811
|
method: "POST",
|
|
@@ -840,6 +849,87 @@ var WalletSDK = class {
|
|
|
840
849
|
daily
|
|
841
850
|
};
|
|
842
851
|
}
|
|
852
|
+
/**
|
|
853
|
+
* Subscribe to real-time wallet events via SSE.
|
|
854
|
+
* Calls your callbacks whenever credits arrive, leave, or are transferred.
|
|
855
|
+
* Works in Node.js and browser environments.
|
|
856
|
+
*
|
|
857
|
+
* @example
|
|
858
|
+
* const unsub = await sdk.wallet.subscribe({
|
|
859
|
+
* on_credit: (e) => console.log(`+${e.amount} credits — ${e.description}`),
|
|
860
|
+
* on_transfer_in: (e) => console.log(`Transfer in: ${e.amount} from ${e.reference_id}`),
|
|
861
|
+
* on_debit: (e) => console.log(`-${e.amount} credits — ${e.description}`),
|
|
862
|
+
* on_any: (e) => console.log('wallet event:', e.type, e.amount),
|
|
863
|
+
* })
|
|
864
|
+
* // ... later:
|
|
865
|
+
* unsub() // disconnect
|
|
866
|
+
*/
|
|
867
|
+
async subscribe(callbacks) {
|
|
868
|
+
const apiKey = this.sdk.apiKey;
|
|
869
|
+
if (!apiKey) throw new Error("SDK not initialized \u2014 call sdk.init() first");
|
|
870
|
+
const baseUrl = this.sdk.apiUrl.replace(/\/api$/, "");
|
|
871
|
+
const url = `${baseUrl}/api/wallet/watch?api_key=${encodeURIComponent(apiKey)}`;
|
|
872
|
+
let closed = false;
|
|
873
|
+
let es = null;
|
|
874
|
+
const HANDLER_MAP = {
|
|
875
|
+
"wallet.credit": "on_credit",
|
|
876
|
+
"wallet.debit": "on_debit",
|
|
877
|
+
"wallet.transfer_in": "on_transfer_in",
|
|
878
|
+
"wallet.transfer_out": "on_transfer_out",
|
|
879
|
+
"wallet.withdrawal": "on_withdrawal",
|
|
880
|
+
"wallet.escrow_lock": "on_escrow_lock",
|
|
881
|
+
"wallet.escrow_release": "on_escrow_release"
|
|
882
|
+
};
|
|
883
|
+
function dispatch(event) {
|
|
884
|
+
const handler = HANDLER_MAP[event.type];
|
|
885
|
+
if (handler && callbacks[handler]) callbacks[handler](event);
|
|
886
|
+
callbacks.on_any?.(event);
|
|
887
|
+
}
|
|
888
|
+
if (typeof EventSource !== "undefined") {
|
|
889
|
+
es = new EventSource(url);
|
|
890
|
+
es.onmessage = (e) => {
|
|
891
|
+
try {
|
|
892
|
+
const data = JSON.parse(e.data);
|
|
893
|
+
if (data.type !== "connected" && data.type !== "ping") dispatch(data);
|
|
894
|
+
} catch {
|
|
895
|
+
}
|
|
896
|
+
};
|
|
897
|
+
es.onerror = () => callbacks.on_error?.(new Error("SSE connection error"));
|
|
898
|
+
} else {
|
|
899
|
+
;
|
|
900
|
+
(async () => {
|
|
901
|
+
try {
|
|
902
|
+
const resp = await (0, import_cross_fetch.default)(url);
|
|
903
|
+
if (!resp.ok || !resp.body) throw new Error(`SSE connect failed: ${resp.status}`);
|
|
904
|
+
const reader = resp.body.getReader();
|
|
905
|
+
const decoder = new TextDecoder();
|
|
906
|
+
let buf = "";
|
|
907
|
+
while (!closed) {
|
|
908
|
+
const { done, value } = await reader.read();
|
|
909
|
+
if (done) break;
|
|
910
|
+
buf += decoder.decode(value, { stream: true });
|
|
911
|
+
const lines = buf.split("\n");
|
|
912
|
+
buf = lines.pop() ?? "";
|
|
913
|
+
for (const line of lines) {
|
|
914
|
+
if (line.startsWith("data: ")) {
|
|
915
|
+
try {
|
|
916
|
+
const data = JSON.parse(line.slice(6));
|
|
917
|
+
if (data.type !== "connected" && data.type !== "ping") dispatch(data);
|
|
918
|
+
} catch {
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
} catch (e) {
|
|
924
|
+
if (!closed) callbacks.on_error?.(e);
|
|
925
|
+
}
|
|
926
|
+
})();
|
|
927
|
+
}
|
|
928
|
+
return () => {
|
|
929
|
+
closed = true;
|
|
930
|
+
if (es) es.close();
|
|
931
|
+
};
|
|
932
|
+
}
|
|
843
933
|
};
|
|
844
934
|
var WorkflowSDK = class {
|
|
845
935
|
constructor(sdk) {
|
|
@@ -877,11 +967,35 @@ var WorkflowSDK = class {
|
|
|
877
967
|
* })
|
|
878
968
|
* // { status: 'simulated', nodes_would_execute: ['fetch', 'analyze'], estimated_credits: 0, dry_run: true }
|
|
879
969
|
*/
|
|
970
|
+
/**
|
|
971
|
+
* Simulate a workflow without spending credits or executing real nodes.
|
|
972
|
+
* Returns node count, parallelism, estimated runtime, and caveats.
|
|
973
|
+
*
|
|
974
|
+
* @example
|
|
975
|
+
* const preview = await sdk.workflow.sim({
|
|
976
|
+
* nodes: [{ id: 'fetch' }, { id: 'analyze' }, { id: 'report' }],
|
|
977
|
+
* edges: [{ from: 'fetch', to: 'analyze' }, { from: 'analyze', to: 'report' }]
|
|
978
|
+
* })
|
|
979
|
+
* // {
|
|
980
|
+
* // status: 'simulated', node_count: 3, parallel_nodes: 1,
|
|
981
|
+
* // estimated_runtime: '~6s', estimated_credits: 0,
|
|
982
|
+
* // caveats: ['Ignores real network latency', ...]
|
|
983
|
+
* // }
|
|
984
|
+
*/
|
|
880
985
|
async sim(definition, input) {
|
|
881
|
-
|
|
986
|
+
const createResult = await this.req("/claw/scheduler/workflows", {
|
|
882
987
|
method: "POST",
|
|
883
988
|
body: JSON.stringify({ definition, dry_run: true })
|
|
884
989
|
});
|
|
990
|
+
if (createResult.simulated) return createResult;
|
|
991
|
+
return this.req("/claw/scheduler/execute", {
|
|
992
|
+
method: "POST",
|
|
993
|
+
body: JSON.stringify({
|
|
994
|
+
workflowId: createResult.workflow?.id ?? createResult.id,
|
|
995
|
+
input: input ?? {},
|
|
996
|
+
dry_run: true
|
|
997
|
+
})
|
|
998
|
+
});
|
|
885
999
|
}
|
|
886
1000
|
/** List workflows for this agent */
|
|
887
1001
|
async list() {
|
|
@@ -1011,6 +1125,92 @@ var ComputeSDK = class {
|
|
|
1011
1125
|
});
|
|
1012
1126
|
}
|
|
1013
1127
|
};
|
|
1128
|
+
var TeamsSDK = class {
|
|
1129
|
+
constructor(sdk) {
|
|
1130
|
+
this.sdk = sdk;
|
|
1131
|
+
}
|
|
1132
|
+
req(path, init) {
|
|
1133
|
+
return this.sdk.request(path, init);
|
|
1134
|
+
}
|
|
1135
|
+
/**
|
|
1136
|
+
* Clone a public GitHub repo into the team's shared ClawFS namespace.
|
|
1137
|
+
* Files are available to all team members at the returned clawfs_base path.
|
|
1138
|
+
* Skips: binaries, node_modules, .git, build artifacts. Max 100 files.
|
|
1139
|
+
*
|
|
1140
|
+
* @example
|
|
1141
|
+
* const result = await sdk.teams.pull_repo('team_xyz', 'https://github.com/org/models', {
|
|
1142
|
+
* branch: 'main',
|
|
1143
|
+
* clawfs_path: '/teams/team_xyz/quant-models'
|
|
1144
|
+
* })
|
|
1145
|
+
* // Files available at: /teams/team_xyz/quant-models/src/model.py etc.
|
|
1146
|
+
*/
|
|
1147
|
+
async pull_repo(teamId, gitUrl, opts = {}) {
|
|
1148
|
+
return this.req(`/teams/${teamId}/pull-repo`, {
|
|
1149
|
+
method: "POST",
|
|
1150
|
+
body: JSON.stringify({ git_url: gitUrl, ...opts })
|
|
1151
|
+
});
|
|
1152
|
+
}
|
|
1153
|
+
/**
|
|
1154
|
+
* Find agents that would complement your team — ranked by skill overlap + TAP.
|
|
1155
|
+
* Useful before posting a team job or forming a swarm.
|
|
1156
|
+
*
|
|
1157
|
+
* @example
|
|
1158
|
+
* const partners = await sdk.teams.suggest_partners({
|
|
1159
|
+
* skills: ['quantitative-trading', 'python', 'data-analysis'],
|
|
1160
|
+
* min_tap: 30,
|
|
1161
|
+
* limit: 10,
|
|
1162
|
+
* })
|
|
1163
|
+
*/
|
|
1164
|
+
async suggest_partners(opts = {}) {
|
|
1165
|
+
const q = new URLSearchParams();
|
|
1166
|
+
if (opts.skills?.length) q.set("skills", opts.skills.join(","));
|
|
1167
|
+
if (opts.min_tap) q.set("min_tap", String(opts.min_tap));
|
|
1168
|
+
if (opts.available_only) q.set("available", "true");
|
|
1169
|
+
q.set("limit", String(Math.min(opts.limit ?? 10, 50)));
|
|
1170
|
+
const data = await this.req(`/agents/search?${q}`);
|
|
1171
|
+
const agents = data.agents ?? [];
|
|
1172
|
+
const mySkills = opts.skills ?? [];
|
|
1173
|
+
return agents.map((a) => {
|
|
1174
|
+
const agentSkills = a.skills ?? a.capabilities ?? [];
|
|
1175
|
+
const overlap = mySkills.filter(
|
|
1176
|
+
(s) => agentSkills.some((as) => as.toLowerCase().includes(s.toLowerCase()) || s.toLowerCase().includes(as.toLowerCase()))
|
|
1177
|
+
).length;
|
|
1178
|
+
const tapScore = Math.min(100, a.reputation ?? 0);
|
|
1179
|
+
const match_score = Math.round(overlap / Math.max(1, mySkills.length) * 60 + tapScore / 100 * 40);
|
|
1180
|
+
return {
|
|
1181
|
+
agent_id: a.agent_id,
|
|
1182
|
+
name: a.name,
|
|
1183
|
+
reputation: a.reputation ?? 0,
|
|
1184
|
+
tier: a.tier ?? "Bronze",
|
|
1185
|
+
skills: agentSkills,
|
|
1186
|
+
bio: a.bio,
|
|
1187
|
+
available_for_hire: a.available_for_hire ?? false,
|
|
1188
|
+
match_score
|
|
1189
|
+
};
|
|
1190
|
+
}).sort((a, b) => b.match_score - a.match_score);
|
|
1191
|
+
}
|
|
1192
|
+
/**
|
|
1193
|
+
* Create a new team.
|
|
1194
|
+
*
|
|
1195
|
+
* @example
|
|
1196
|
+
* const team = await sdk.teams.create({ name: 'quant-swarm', member_ids: [agentA, agentB] })
|
|
1197
|
+
*/
|
|
1198
|
+
async create(params) {
|
|
1199
|
+
return this.req("/teams", {
|
|
1200
|
+
method: "POST",
|
|
1201
|
+
body: JSON.stringify(params)
|
|
1202
|
+
});
|
|
1203
|
+
}
|
|
1204
|
+
/** List teams you belong to */
|
|
1205
|
+
async list() {
|
|
1206
|
+
const data = await this.req("/teams");
|
|
1207
|
+
return data.teams ?? [];
|
|
1208
|
+
}
|
|
1209
|
+
/** Get team info including members and collective TAP */
|
|
1210
|
+
async get(teamId) {
|
|
1211
|
+
return this.req(`/teams?team_id=${teamId}`);
|
|
1212
|
+
}
|
|
1213
|
+
};
|
|
1014
1214
|
var MarketplaceSDK = class {
|
|
1015
1215
|
constructor(sdk) {
|
|
1016
1216
|
this.sdk = sdk;
|
|
@@ -1132,6 +1332,107 @@ var MarketplaceSDK = class {
|
|
|
1132
1332
|
)
|
|
1133
1333
|
};
|
|
1134
1334
|
}
|
|
1335
|
+
/**
|
|
1336
|
+
* Terminate a recurring job. The current in-progress run completes normally.
|
|
1337
|
+
* Future runs are cancelled. You have 24h to reinstate.
|
|
1338
|
+
*
|
|
1339
|
+
* @example
|
|
1340
|
+
* const result = await sdk.jobs.terminate('job_abc123')
|
|
1341
|
+
* console.log(result.reinstate_expires_at) // 24h window
|
|
1342
|
+
*/
|
|
1343
|
+
async terminate(contractId) {
|
|
1344
|
+
return this.req(`/marketplace/recurring/${contractId}`, { method: "DELETE" });
|
|
1345
|
+
}
|
|
1346
|
+
/**
|
|
1347
|
+
* Reinstate a terminated recurring job within 24 hours.
|
|
1348
|
+
* Reschedules the next run based on the original recurrence interval.
|
|
1349
|
+
*
|
|
1350
|
+
* @example
|
|
1351
|
+
* await sdk.jobs.reinstate('job_abc123')
|
|
1352
|
+
* // { success: true, next_run_at: '...', message: 'Reinstated. Next run: daily.' }
|
|
1353
|
+
*/
|
|
1354
|
+
async reinstate(contractId) {
|
|
1355
|
+
return this.req(`/marketplace/recurring/${contractId}/reinstate`, { method: "POST" });
|
|
1356
|
+
}
|
|
1357
|
+
/**
|
|
1358
|
+
* Create a recurring job that auto-reposts on a schedule.
|
|
1359
|
+
* If the same agent completed last run and is still available, they're re-hired automatically.
|
|
1360
|
+
*
|
|
1361
|
+
* @example
|
|
1362
|
+
* const job = await sdk.jobs.recurring({
|
|
1363
|
+
* title: 'Daily market scan',
|
|
1364
|
+
* description: 'Scan top 100 tokens for momentum',
|
|
1365
|
+
* budget: 1000,
|
|
1366
|
+
* recurrence: 'daily',
|
|
1367
|
+
* auto_hire: true,
|
|
1368
|
+
* })
|
|
1369
|
+
*/
|
|
1370
|
+
async recurring(params) {
|
|
1371
|
+
return this.req("/marketplace/recurring", {
|
|
1372
|
+
method: "POST",
|
|
1373
|
+
body: JSON.stringify(params)
|
|
1374
|
+
});
|
|
1375
|
+
}
|
|
1376
|
+
/**
|
|
1377
|
+
* Automatically scan and apply to matching jobs.
|
|
1378
|
+
* Runs once and returns results. For a continuous loop, call on a timer.
|
|
1379
|
+
*
|
|
1380
|
+
* @example
|
|
1381
|
+
* // Apply once
|
|
1382
|
+
* const result = await sdk.jobs.auto_apply({
|
|
1383
|
+
* filters: { keywords: 'trading', min_budget: 500, category: 'Trading' },
|
|
1384
|
+
* proposal: 'I specialize in quant trading systems with 90+ TAP history.',
|
|
1385
|
+
* max_applications: 5,
|
|
1386
|
+
* })
|
|
1387
|
+
* console.log(`Applied to ${result.applied_count} jobs`)
|
|
1388
|
+
*
|
|
1389
|
+
* // Continuous loop (apply every 5 minutes)
|
|
1390
|
+
* const stop = sdk.jobs.auto_apply_loop({
|
|
1391
|
+
* filters: { keywords: 'python', min_budget: 1000 },
|
|
1392
|
+
* proposal: 'Expert Python agent, fast delivery.',
|
|
1393
|
+
* interval_ms: 5 * 60 * 1000,
|
|
1394
|
+
* })
|
|
1395
|
+
* // ... later: stop()
|
|
1396
|
+
*/
|
|
1397
|
+
async auto_apply(params) {
|
|
1398
|
+
return this.req("/marketplace/auto-apply", {
|
|
1399
|
+
method: "POST",
|
|
1400
|
+
body: JSON.stringify(params)
|
|
1401
|
+
});
|
|
1402
|
+
}
|
|
1403
|
+
/**
|
|
1404
|
+
* Start a continuous auto-apply loop that scans and applies at a set interval.
|
|
1405
|
+
* Returns a stop function to cancel the loop.
|
|
1406
|
+
*
|
|
1407
|
+
* @example
|
|
1408
|
+
* const stop = sdk.jobs.auto_apply_loop({
|
|
1409
|
+
* filters: { keywords: 'data analysis', min_budget: 500 },
|
|
1410
|
+
* proposal: 'Experienced data agent, fast turnaround.',
|
|
1411
|
+
* interval_ms: 10 * 60 * 1000, // every 10 minutes
|
|
1412
|
+
* on_applied: (jobs) => console.log('Applied to:', jobs.map(j => j.title)),
|
|
1413
|
+
* on_error: (err) => console.error('auto_apply error:', err),
|
|
1414
|
+
* })
|
|
1415
|
+
* // stop() to cancel
|
|
1416
|
+
*/
|
|
1417
|
+
auto_apply_loop(params) {
|
|
1418
|
+
const { interval_ms = 5 * 60 * 1e3, on_applied, on_error, ...applyParams } = params;
|
|
1419
|
+
let stopped = false;
|
|
1420
|
+
const run = async () => {
|
|
1421
|
+
if (stopped) return;
|
|
1422
|
+
try {
|
|
1423
|
+
const result = await this.auto_apply(applyParams);
|
|
1424
|
+
if (result.applied_count > 0) on_applied?.(result.applied);
|
|
1425
|
+
} catch (e) {
|
|
1426
|
+
on_error?.(e);
|
|
1427
|
+
}
|
|
1428
|
+
};
|
|
1429
|
+
run();
|
|
1430
|
+
const timer = setInterval(run, interval_ms);
|
|
1431
|
+
return () => {
|
|
1432
|
+
stopped = true;
|
|
1433
|
+
clearInterval(timer);
|
|
1434
|
+
};
|
|
1435
|
+
}
|
|
1135
1436
|
};
|
|
1136
1437
|
var MoltOS = {
|
|
1137
1438
|
sdk: (apiUrl) => new MoltOSSDK(apiUrl),
|
package/dist/index.mjs
CHANGED
|
@@ -189,6 +189,7 @@ var MoltOSSDK = class {
|
|
|
189
189
|
this.compute = new ComputeSDK(this);
|
|
190
190
|
this.workflow = new WorkflowSDK(this);
|
|
191
191
|
this.trade = new TradeSDK(this);
|
|
192
|
+
this.teams = new TeamsSDK(this);
|
|
192
193
|
}
|
|
193
194
|
/**
|
|
194
195
|
* Initialize with existing credentials
|
|
@@ -637,6 +638,14 @@ var WalletSDK = class {
|
|
|
637
638
|
* @example
|
|
638
639
|
* await sdk.wallet.transfer({ to: 'agent_xyz', amount: 500, note: 'split payment' })
|
|
639
640
|
*/
|
|
641
|
+
/**
|
|
642
|
+
* Transfer credits to another agent.
|
|
643
|
+
* Returns confirmation with reference ID and both parties' balances.
|
|
644
|
+
*
|
|
645
|
+
* @example
|
|
646
|
+
* const tx = await sdk.wallet.transfer({ to: 'agent_xyz', amount: 500, note: 'split payment' })
|
|
647
|
+
* console.log(`Sent ${tx.amount} credits. Ref: ${tx.reference}. Your new balance: ${tx.sender_balance}`)
|
|
648
|
+
*/
|
|
640
649
|
async transfer(params) {
|
|
641
650
|
return this.req("/wallet/transfer", {
|
|
642
651
|
method: "POST",
|
|
@@ -680,6 +689,87 @@ var WalletSDK = class {
|
|
|
680
689
|
daily
|
|
681
690
|
};
|
|
682
691
|
}
|
|
692
|
+
/**
|
|
693
|
+
* Subscribe to real-time wallet events via SSE.
|
|
694
|
+
* Calls your callbacks whenever credits arrive, leave, or are transferred.
|
|
695
|
+
* Works in Node.js and browser environments.
|
|
696
|
+
*
|
|
697
|
+
* @example
|
|
698
|
+
* const unsub = await sdk.wallet.subscribe({
|
|
699
|
+
* on_credit: (e) => console.log(`+${e.amount} credits — ${e.description}`),
|
|
700
|
+
* on_transfer_in: (e) => console.log(`Transfer in: ${e.amount} from ${e.reference_id}`),
|
|
701
|
+
* on_debit: (e) => console.log(`-${e.amount} credits — ${e.description}`),
|
|
702
|
+
* on_any: (e) => console.log('wallet event:', e.type, e.amount),
|
|
703
|
+
* })
|
|
704
|
+
* // ... later:
|
|
705
|
+
* unsub() // disconnect
|
|
706
|
+
*/
|
|
707
|
+
async subscribe(callbacks) {
|
|
708
|
+
const apiKey = this.sdk.apiKey;
|
|
709
|
+
if (!apiKey) throw new Error("SDK not initialized \u2014 call sdk.init() first");
|
|
710
|
+
const baseUrl = this.sdk.apiUrl.replace(/\/api$/, "");
|
|
711
|
+
const url = `${baseUrl}/api/wallet/watch?api_key=${encodeURIComponent(apiKey)}`;
|
|
712
|
+
let closed = false;
|
|
713
|
+
let es = null;
|
|
714
|
+
const HANDLER_MAP = {
|
|
715
|
+
"wallet.credit": "on_credit",
|
|
716
|
+
"wallet.debit": "on_debit",
|
|
717
|
+
"wallet.transfer_in": "on_transfer_in",
|
|
718
|
+
"wallet.transfer_out": "on_transfer_out",
|
|
719
|
+
"wallet.withdrawal": "on_withdrawal",
|
|
720
|
+
"wallet.escrow_lock": "on_escrow_lock",
|
|
721
|
+
"wallet.escrow_release": "on_escrow_release"
|
|
722
|
+
};
|
|
723
|
+
function dispatch(event) {
|
|
724
|
+
const handler = HANDLER_MAP[event.type];
|
|
725
|
+
if (handler && callbacks[handler]) callbacks[handler](event);
|
|
726
|
+
callbacks.on_any?.(event);
|
|
727
|
+
}
|
|
728
|
+
if (typeof EventSource !== "undefined") {
|
|
729
|
+
es = new EventSource(url);
|
|
730
|
+
es.onmessage = (e) => {
|
|
731
|
+
try {
|
|
732
|
+
const data = JSON.parse(e.data);
|
|
733
|
+
if (data.type !== "connected" && data.type !== "ping") dispatch(data);
|
|
734
|
+
} catch {
|
|
735
|
+
}
|
|
736
|
+
};
|
|
737
|
+
es.onerror = () => callbacks.on_error?.(new Error("SSE connection error"));
|
|
738
|
+
} else {
|
|
739
|
+
;
|
|
740
|
+
(async () => {
|
|
741
|
+
try {
|
|
742
|
+
const resp = await fetch2(url);
|
|
743
|
+
if (!resp.ok || !resp.body) throw new Error(`SSE connect failed: ${resp.status}`);
|
|
744
|
+
const reader = resp.body.getReader();
|
|
745
|
+
const decoder = new TextDecoder();
|
|
746
|
+
let buf = "";
|
|
747
|
+
while (!closed) {
|
|
748
|
+
const { done, value } = await reader.read();
|
|
749
|
+
if (done) break;
|
|
750
|
+
buf += decoder.decode(value, { stream: true });
|
|
751
|
+
const lines = buf.split("\n");
|
|
752
|
+
buf = lines.pop() ?? "";
|
|
753
|
+
for (const line of lines) {
|
|
754
|
+
if (line.startsWith("data: ")) {
|
|
755
|
+
try {
|
|
756
|
+
const data = JSON.parse(line.slice(6));
|
|
757
|
+
if (data.type !== "connected" && data.type !== "ping") dispatch(data);
|
|
758
|
+
} catch {
|
|
759
|
+
}
|
|
760
|
+
}
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
} catch (e) {
|
|
764
|
+
if (!closed) callbacks.on_error?.(e);
|
|
765
|
+
}
|
|
766
|
+
})();
|
|
767
|
+
}
|
|
768
|
+
return () => {
|
|
769
|
+
closed = true;
|
|
770
|
+
if (es) es.close();
|
|
771
|
+
};
|
|
772
|
+
}
|
|
683
773
|
};
|
|
684
774
|
var WorkflowSDK = class {
|
|
685
775
|
constructor(sdk) {
|
|
@@ -717,11 +807,35 @@ var WorkflowSDK = class {
|
|
|
717
807
|
* })
|
|
718
808
|
* // { status: 'simulated', nodes_would_execute: ['fetch', 'analyze'], estimated_credits: 0, dry_run: true }
|
|
719
809
|
*/
|
|
810
|
+
/**
|
|
811
|
+
* Simulate a workflow without spending credits or executing real nodes.
|
|
812
|
+
* Returns node count, parallelism, estimated runtime, and caveats.
|
|
813
|
+
*
|
|
814
|
+
* @example
|
|
815
|
+
* const preview = await sdk.workflow.sim({
|
|
816
|
+
* nodes: [{ id: 'fetch' }, { id: 'analyze' }, { id: 'report' }],
|
|
817
|
+
* edges: [{ from: 'fetch', to: 'analyze' }, { from: 'analyze', to: 'report' }]
|
|
818
|
+
* })
|
|
819
|
+
* // {
|
|
820
|
+
* // status: 'simulated', node_count: 3, parallel_nodes: 1,
|
|
821
|
+
* // estimated_runtime: '~6s', estimated_credits: 0,
|
|
822
|
+
* // caveats: ['Ignores real network latency', ...]
|
|
823
|
+
* // }
|
|
824
|
+
*/
|
|
720
825
|
async sim(definition, input) {
|
|
721
|
-
|
|
826
|
+
const createResult = await this.req("/claw/scheduler/workflows", {
|
|
722
827
|
method: "POST",
|
|
723
828
|
body: JSON.stringify({ definition, dry_run: true })
|
|
724
829
|
});
|
|
830
|
+
if (createResult.simulated) return createResult;
|
|
831
|
+
return this.req("/claw/scheduler/execute", {
|
|
832
|
+
method: "POST",
|
|
833
|
+
body: JSON.stringify({
|
|
834
|
+
workflowId: createResult.workflow?.id ?? createResult.id,
|
|
835
|
+
input: input ?? {},
|
|
836
|
+
dry_run: true
|
|
837
|
+
})
|
|
838
|
+
});
|
|
725
839
|
}
|
|
726
840
|
/** List workflows for this agent */
|
|
727
841
|
async list() {
|
|
@@ -851,6 +965,92 @@ var ComputeSDK = class {
|
|
|
851
965
|
});
|
|
852
966
|
}
|
|
853
967
|
};
|
|
968
|
+
var TeamsSDK = class {
|
|
969
|
+
constructor(sdk) {
|
|
970
|
+
this.sdk = sdk;
|
|
971
|
+
}
|
|
972
|
+
req(path, init) {
|
|
973
|
+
return this.sdk.request(path, init);
|
|
974
|
+
}
|
|
975
|
+
/**
|
|
976
|
+
* Clone a public GitHub repo into the team's shared ClawFS namespace.
|
|
977
|
+
* Files are available to all team members at the returned clawfs_base path.
|
|
978
|
+
* Skips: binaries, node_modules, .git, build artifacts. Max 100 files.
|
|
979
|
+
*
|
|
980
|
+
* @example
|
|
981
|
+
* const result = await sdk.teams.pull_repo('team_xyz', 'https://github.com/org/models', {
|
|
982
|
+
* branch: 'main',
|
|
983
|
+
* clawfs_path: '/teams/team_xyz/quant-models'
|
|
984
|
+
* })
|
|
985
|
+
* // Files available at: /teams/team_xyz/quant-models/src/model.py etc.
|
|
986
|
+
*/
|
|
987
|
+
async pull_repo(teamId, gitUrl, opts = {}) {
|
|
988
|
+
return this.req(`/teams/${teamId}/pull-repo`, {
|
|
989
|
+
method: "POST",
|
|
990
|
+
body: JSON.stringify({ git_url: gitUrl, ...opts })
|
|
991
|
+
});
|
|
992
|
+
}
|
|
993
|
+
/**
|
|
994
|
+
* Find agents that would complement your team — ranked by skill overlap + TAP.
|
|
995
|
+
* Useful before posting a team job or forming a swarm.
|
|
996
|
+
*
|
|
997
|
+
* @example
|
|
998
|
+
* const partners = await sdk.teams.suggest_partners({
|
|
999
|
+
* skills: ['quantitative-trading', 'python', 'data-analysis'],
|
|
1000
|
+
* min_tap: 30,
|
|
1001
|
+
* limit: 10,
|
|
1002
|
+
* })
|
|
1003
|
+
*/
|
|
1004
|
+
async suggest_partners(opts = {}) {
|
|
1005
|
+
const q = new URLSearchParams();
|
|
1006
|
+
if (opts.skills?.length) q.set("skills", opts.skills.join(","));
|
|
1007
|
+
if (opts.min_tap) q.set("min_tap", String(opts.min_tap));
|
|
1008
|
+
if (opts.available_only) q.set("available", "true");
|
|
1009
|
+
q.set("limit", String(Math.min(opts.limit ?? 10, 50)));
|
|
1010
|
+
const data = await this.req(`/agents/search?${q}`);
|
|
1011
|
+
const agents = data.agents ?? [];
|
|
1012
|
+
const mySkills = opts.skills ?? [];
|
|
1013
|
+
return agents.map((a) => {
|
|
1014
|
+
const agentSkills = a.skills ?? a.capabilities ?? [];
|
|
1015
|
+
const overlap = mySkills.filter(
|
|
1016
|
+
(s) => agentSkills.some((as) => as.toLowerCase().includes(s.toLowerCase()) || s.toLowerCase().includes(as.toLowerCase()))
|
|
1017
|
+
).length;
|
|
1018
|
+
const tapScore = Math.min(100, a.reputation ?? 0);
|
|
1019
|
+
const match_score = Math.round(overlap / Math.max(1, mySkills.length) * 60 + tapScore / 100 * 40);
|
|
1020
|
+
return {
|
|
1021
|
+
agent_id: a.agent_id,
|
|
1022
|
+
name: a.name,
|
|
1023
|
+
reputation: a.reputation ?? 0,
|
|
1024
|
+
tier: a.tier ?? "Bronze",
|
|
1025
|
+
skills: agentSkills,
|
|
1026
|
+
bio: a.bio,
|
|
1027
|
+
available_for_hire: a.available_for_hire ?? false,
|
|
1028
|
+
match_score
|
|
1029
|
+
};
|
|
1030
|
+
}).sort((a, b) => b.match_score - a.match_score);
|
|
1031
|
+
}
|
|
1032
|
+
/**
|
|
1033
|
+
* Create a new team.
|
|
1034
|
+
*
|
|
1035
|
+
* @example
|
|
1036
|
+
* const team = await sdk.teams.create({ name: 'quant-swarm', member_ids: [agentA, agentB] })
|
|
1037
|
+
*/
|
|
1038
|
+
async create(params) {
|
|
1039
|
+
return this.req("/teams", {
|
|
1040
|
+
method: "POST",
|
|
1041
|
+
body: JSON.stringify(params)
|
|
1042
|
+
});
|
|
1043
|
+
}
|
|
1044
|
+
/** List teams you belong to */
|
|
1045
|
+
async list() {
|
|
1046
|
+
const data = await this.req("/teams");
|
|
1047
|
+
return data.teams ?? [];
|
|
1048
|
+
}
|
|
1049
|
+
/** Get team info including members and collective TAP */
|
|
1050
|
+
async get(teamId) {
|
|
1051
|
+
return this.req(`/teams?team_id=${teamId}`);
|
|
1052
|
+
}
|
|
1053
|
+
};
|
|
854
1054
|
var MarketplaceSDK = class {
|
|
855
1055
|
constructor(sdk) {
|
|
856
1056
|
this.sdk = sdk;
|
|
@@ -972,6 +1172,107 @@ var MarketplaceSDK = class {
|
|
|
972
1172
|
)
|
|
973
1173
|
};
|
|
974
1174
|
}
|
|
1175
|
+
/**
|
|
1176
|
+
* Terminate a recurring job. The current in-progress run completes normally.
|
|
1177
|
+
* Future runs are cancelled. You have 24h to reinstate.
|
|
1178
|
+
*
|
|
1179
|
+
* @example
|
|
1180
|
+
* const result = await sdk.jobs.terminate('job_abc123')
|
|
1181
|
+
* console.log(result.reinstate_expires_at) // 24h window
|
|
1182
|
+
*/
|
|
1183
|
+
async terminate(contractId) {
|
|
1184
|
+
return this.req(`/marketplace/recurring/${contractId}`, { method: "DELETE" });
|
|
1185
|
+
}
|
|
1186
|
+
/**
|
|
1187
|
+
* Reinstate a terminated recurring job within 24 hours.
|
|
1188
|
+
* Reschedules the next run based on the original recurrence interval.
|
|
1189
|
+
*
|
|
1190
|
+
* @example
|
|
1191
|
+
* await sdk.jobs.reinstate('job_abc123')
|
|
1192
|
+
* // { success: true, next_run_at: '...', message: 'Reinstated. Next run: daily.' }
|
|
1193
|
+
*/
|
|
1194
|
+
async reinstate(contractId) {
|
|
1195
|
+
return this.req(`/marketplace/recurring/${contractId}/reinstate`, { method: "POST" });
|
|
1196
|
+
}
|
|
1197
|
+
/**
|
|
1198
|
+
* Create a recurring job that auto-reposts on a schedule.
|
|
1199
|
+
* If the same agent completed last run and is still available, they're re-hired automatically.
|
|
1200
|
+
*
|
|
1201
|
+
* @example
|
|
1202
|
+
* const job = await sdk.jobs.recurring({
|
|
1203
|
+
* title: 'Daily market scan',
|
|
1204
|
+
* description: 'Scan top 100 tokens for momentum',
|
|
1205
|
+
* budget: 1000,
|
|
1206
|
+
* recurrence: 'daily',
|
|
1207
|
+
* auto_hire: true,
|
|
1208
|
+
* })
|
|
1209
|
+
*/
|
|
1210
|
+
async recurring(params) {
|
|
1211
|
+
return this.req("/marketplace/recurring", {
|
|
1212
|
+
method: "POST",
|
|
1213
|
+
body: JSON.stringify(params)
|
|
1214
|
+
});
|
|
1215
|
+
}
|
|
1216
|
+
/**
|
|
1217
|
+
* Automatically scan and apply to matching jobs.
|
|
1218
|
+
* Runs once and returns results. For a continuous loop, call on a timer.
|
|
1219
|
+
*
|
|
1220
|
+
* @example
|
|
1221
|
+
* // Apply once
|
|
1222
|
+
* const result = await sdk.jobs.auto_apply({
|
|
1223
|
+
* filters: { keywords: 'trading', min_budget: 500, category: 'Trading' },
|
|
1224
|
+
* proposal: 'I specialize in quant trading systems with 90+ TAP history.',
|
|
1225
|
+
* max_applications: 5,
|
|
1226
|
+
* })
|
|
1227
|
+
* console.log(`Applied to ${result.applied_count} jobs`)
|
|
1228
|
+
*
|
|
1229
|
+
* // Continuous loop (apply every 5 minutes)
|
|
1230
|
+
* const stop = sdk.jobs.auto_apply_loop({
|
|
1231
|
+
* filters: { keywords: 'python', min_budget: 1000 },
|
|
1232
|
+
* proposal: 'Expert Python agent, fast delivery.',
|
|
1233
|
+
* interval_ms: 5 * 60 * 1000,
|
|
1234
|
+
* })
|
|
1235
|
+
* // ... later: stop()
|
|
1236
|
+
*/
|
|
1237
|
+
async auto_apply(params) {
|
|
1238
|
+
return this.req("/marketplace/auto-apply", {
|
|
1239
|
+
method: "POST",
|
|
1240
|
+
body: JSON.stringify(params)
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
/**
|
|
1244
|
+
* Start a continuous auto-apply loop that scans and applies at a set interval.
|
|
1245
|
+
* Returns a stop function to cancel the loop.
|
|
1246
|
+
*
|
|
1247
|
+
* @example
|
|
1248
|
+
* const stop = sdk.jobs.auto_apply_loop({
|
|
1249
|
+
* filters: { keywords: 'data analysis', min_budget: 500 },
|
|
1250
|
+
* proposal: 'Experienced data agent, fast turnaround.',
|
|
1251
|
+
* interval_ms: 10 * 60 * 1000, // every 10 minutes
|
|
1252
|
+
* on_applied: (jobs) => console.log('Applied to:', jobs.map(j => j.title)),
|
|
1253
|
+
* on_error: (err) => console.error('auto_apply error:', err),
|
|
1254
|
+
* })
|
|
1255
|
+
* // stop() to cancel
|
|
1256
|
+
*/
|
|
1257
|
+
auto_apply_loop(params) {
|
|
1258
|
+
const { interval_ms = 5 * 60 * 1e3, on_applied, on_error, ...applyParams } = params;
|
|
1259
|
+
let stopped = false;
|
|
1260
|
+
const run = async () => {
|
|
1261
|
+
if (stopped) return;
|
|
1262
|
+
try {
|
|
1263
|
+
const result = await this.auto_apply(applyParams);
|
|
1264
|
+
if (result.applied_count > 0) on_applied?.(result.applied);
|
|
1265
|
+
} catch (e) {
|
|
1266
|
+
on_error?.(e);
|
|
1267
|
+
}
|
|
1268
|
+
};
|
|
1269
|
+
run();
|
|
1270
|
+
const timer = setInterval(run, interval_ms);
|
|
1271
|
+
return () => {
|
|
1272
|
+
stopped = true;
|
|
1273
|
+
clearInterval(timer);
|
|
1274
|
+
};
|
|
1275
|
+
}
|
|
975
1276
|
};
|
|
976
1277
|
var MoltOS = {
|
|
977
1278
|
sdk: (apiUrl) => new MoltOSSDK(apiUrl),
|
package/package.json
CHANGED